diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index 070dc46687..769c6c0bf1 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -474,6 +474,7 @@ The following modifiers are available: * `capture` — fires the handler during the *capture* phase instead of the *bubbling* phase * `once` — remove the handler after the first time it runs * `self` — only trigger handler if event.target is the element itself +* `detail` — calls the handler with the event.detail value, instead of the event object. Modifiers can be chained together, e.g. `on:click|once|capture={...}`. diff --git a/src/compiler/compile/nodes/Element.ts b/src/compiler/compile/nodes/Element.ts index 7a70e603a7..ff5e291cc0 100644 --- a/src/compiler/compile/nodes/Element.ts +++ b/src/compiler/compile/nodes/Element.ts @@ -69,7 +69,8 @@ const valid_modifiers = new Set([ 'capture', 'once', 'passive', - 'self' + 'self', + 'detail' ]); const passive_events = new Set([ diff --git a/src/compiler/compile/nodes/InlineComponent.ts b/src/compiler/compile/nodes/InlineComponent.ts index 0bd1c9a6a7..b90ae635cb 100644 --- a/src/compiler/compile/nodes/InlineComponent.ts +++ b/src/compiler/compile/nodes/InlineComponent.ts @@ -102,10 +102,10 @@ export default class InlineComponent extends Node { this.handlers.forEach(handler => { handler.modifiers.forEach(modifier => { - if (modifier !== 'once') { + if (['once', 'detail'].indexOf(modifier) === -1) { component.error(handler, { code: 'invalid-event-modifier', - message: `Event modifiers other than 'once' can only be used on DOM elements` + message: `Event modifiers other than 'once' and 'detail' can only be used on DOM elements` }); } }); diff --git a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts index 157e186ea6..90d16b2424 100644 --- a/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts +++ b/src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts @@ -42,6 +42,7 @@ export default class EventHandlerWrapper { if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`; if (this.node.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`; if (this.node.modifiers.has('self')) snippet = x`@self(${snippet})`; + if (this.node.modifiers.has('detail')) snippet = x`@detail(${snippet})`; const args = []; diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 271b3de1e1..0dbff646a4 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -391,6 +391,7 @@ export default class InlineComponentWrapper extends Wrapper { const event_handler = new EventHandler(handler, this); let snippet = event_handler.get_snippet(block); if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`; + if (handler.modifiers.has('detail')) snippet = x`@detail(${snippet})`; return b`${name}.$on("${handler.name}", ${snippet});`; }); diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 0cd670fcb9..64343442da 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -85,6 +85,13 @@ export function self(fn) { }; } +export function detail(fn) { + return function(event) { + // @ts-ignore + fn.call(this, event.detail); + }; +} + export function attr(node: Element, attribute: string, value?: string) { if (value == null) node.removeAttribute(attribute); else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value); diff --git a/test/runtime/samples/component-event-handler-modifier-detail/Row.svelte b/test/runtime/samples/component-event-handler-modifier-detail/Row.svelte new file mode 100644 index 0000000000..d95c28838a --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-detail/Row.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-event-handler-modifier-detail/_config.js b/test/runtime/samples/component-event-handler-modifier-detail/_config.js new file mode 100644 index 0000000000..1289979c6c --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-detail/_config.js @@ -0,0 +1,13 @@ +export default { + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + await button.dispatchEvent(event); + assert.equal(component.selected, "apple"); + } +}; diff --git a/test/runtime/samples/component-event-handler-modifier-detail/main.svelte b/test/runtime/samples/component-event-handler-modifier-detail/main.svelte new file mode 100644 index 0000000000..e36a7ef920 --- /dev/null +++ b/test/runtime/samples/component-event-handler-modifier-detail/main.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/event-handler-modifier-detail/_config.js b/test/runtime/samples/event-handler-modifier-detail/_config.js new file mode 100644 index 0000000000..3c15cb6ee4 --- /dev/null +++ b/test/runtime/samples/event-handler-modifier-detail/_config.js @@ -0,0 +1,14 @@ +export default { + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.CustomEvent('click', { detail: 1 }); + + await button.dispatchEvent(event); + + assert.ok(component.button === 1); + } +}; diff --git a/test/runtime/samples/event-handler-modifier-detail/main.svelte b/test/runtime/samples/event-handler-modifier-detail/main.svelte new file mode 100644 index 0000000000..3f1e991f94 --- /dev/null +++ b/test/runtime/samples/event-handler-modifier-detail/main.svelte @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/test/validator/samples/component-event-modifiers-invalid/errors.json b/test/validator/samples/component-event-modifiers-invalid/errors.json index da608063fe..baaf612092 100644 --- a/test/validator/samples/component-event-modifiers-invalid/errors.json +++ b/test/validator/samples/component-event-modifiers-invalid/errors.json @@ -1,5 +1,5 @@ [{ - "message": "Event modifiers other than 'once' can only be used on DOM elements", + "message": "Event modifiers other than 'once' and 'detail' can only be used on DOM elements", "code": "invalid-event-modifier", "start": { "line": 6, diff --git a/test/validator/samples/event-modifiers-invalid/errors.json b/test/validator/samples/event-modifiers-invalid/errors.json index 8be2ca7348..6fb389ec65 100644 --- a/test/validator/samples/event-modifiers-invalid/errors.json +++ b/test/validator/samples/event-modifiers-invalid/errors.json @@ -1,5 +1,5 @@ [{ - "message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive or self", + "message": "Valid event modifiers are preventDefault, stopPropagation, capture, once, passive, self or detail", "code": "invalid-event-modifier", "start": { "line": 1,