diff --git a/CHANGELOG.md b/CHANGELOG.md index 947173fd4d3..0b2bb5d7fb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Return the context object in `setContext` [#7427](https://github.com/sveltejs/svelte/issues/7427) * Fix `{@const}` tag not working inside Component when there's no `let:` [#7189](https://github.com/sveltejs/svelte/issues/7189) * Ignore comments in `{#each}` blocks when containing elements with `animate:` ([#3999](https://github.com/sveltejs/svelte/issues/3999)) +* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function when called will also return a boolean depending on whether the event is cancelled ([#7064](https://github.com/sveltejs/svelte/pull/7064)) ## 3.47.0 diff --git a/site/content/docs/03-run-time.md b/site/content/docs/03-run-time.md index a0d3f4148cf..c6423f408c7 100644 --- a/site/content/docs/03-run-time.md +++ b/site/content/docs/03-run-time.md @@ -221,14 +221,14 @@ Retrieves the whole context map that belongs to the closest parent component. Mu #### `createEventDispatcher` ```js -dispatch: ((name: string, detail?: any) => void) = createEventDispatcher(); +dispatch: ((name: string, detail?: any, options?: DispatchOptions) => boolean) = createEventDispatcher(); ``` --- Creates an event dispatcher that can be used to dispatch [component events](/docs#template-syntax-component-directives-on-eventname). Event dispatchers are functions that can take two arguments: `name` and `detail`. -Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data. +Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data. ```sv +``` + ### `svelte/store` The `svelte/store` module exports functions for creating [readable](/docs#run-time-svelte-store-readable), [writable](/docs#run-time-svelte-store-writable) and [derived](/docs#run-time-svelte-store-derived) stores. diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts index 4501771c0ac..0ba47f7e867 100644 --- a/src/runtime/internal/dev.ts +++ b/src/runtime/internal/dev.ts @@ -2,7 +2,7 @@ import { custom_event, append, append_hydration, insert, insert_hydration, detac import { SvelteComponent } from './Component'; export function dispatch_dev(type: string, detail?: T) { - document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }, true)); + document.dispatchEvent(custom_event(type, { version: '__VERSION__', ...detail }, { bubbles: true })); } export function append_dev(target: Node, node: Node) { diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 287c16b5fc5..e2a74202360 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -634,9 +634,9 @@ export function toggle_class(element, name, toggle) { element.classList[toggle ? 'add' : 'remove'](name); } -export function custom_event(type: string, detail?: T, bubbles: boolean = false) { +export function custom_event(type: string, detail?: T, { bubbles = false, cancelable = false } = {}): CustomEvent { const e: CustomEvent = document.createEvent('CustomEvent'); - e.initCustomEvent(type, bubbles, false, detail); + e.initCustomEvent(type, bubbles, cancelable, detail); return e; } diff --git a/src/runtime/internal/lifecycle.ts b/src/runtime/internal/lifecycle.ts index 3b3c2f5f71e..fbbeca9a67c 100644 --- a/src/runtime/internal/lifecycle.ts +++ b/src/runtime/internal/lifecycle.ts @@ -27,22 +27,33 @@ export function onDestroy(fn: () => any) { get_current_component().$$.on_destroy.push(fn); } -export function createEventDispatcher< - EventMap extends {} = any ->(): >(type: EventKey, detail?: EventMap[EventKey]) => void { +export interface DispatchOptions { + cancelable?: boolean; +} + +export function createEventDispatcher(): < + EventKey extends Extract +>( + type: EventKey, + detail?: EventMap[EventKey], + options?: DispatchOptions +) => boolean { const component = get_current_component(); - return (type: string, detail?: any) => { + return (type: string, detail?: any, { cancelable = false } = {}): boolean => { const callbacks = component.$$.callbacks[type]; if (callbacks) { // TODO are there situations where events could be dispatched // in a server (non-DOM) environment? - const event = custom_event(type, detail); + const event = custom_event(type, detail, { cancelable }); callbacks.slice().forEach(fn => { fn.call(component, event); }); + return !event.defaultPrevented; } + + return true; }; }