diff --git a/documentation/docs/04-compiler-and-api/02-client-side-component-api.md b/documentation/docs/04-compiler-and-api/02-client-side-component-api.md index f14fbe3e6622..3b59e4362d52 100644 --- a/documentation/docs/04-compiler-and-api/02-client-side-component-api.md +++ b/documentation/docs/04-compiler-and-api/02-client-side-component-api.md @@ -178,17 +178,20 @@ import { SvelteComponent, ComponentConstructorOptions } from 'svelte'; declare global { class Component extends SvelteComponent {} var component: Component; + var options: { runOutro: boolean } | undefined; } export {} // @filename: index.ts // ---cut--- -component.$destroy(); +component.$destroy(options); ``` Removes a component from the DOM and triggers any `onDestroy` handlers. +`options` may contain the property `runOutro` which indicates whether to play any outro transitions before the component is destroyed. + ## Component props ```js diff --git a/packages/svelte/src/runtime/internal/Component.js b/packages/svelte/src/runtime/internal/Component.js index bc5b117c2ff0..dd66ad31b92a 100644 --- a/packages/svelte/src/runtime/internal/Component.js +++ b/packages/svelte/src/runtime/internal/Component.js @@ -17,7 +17,7 @@ import { element, attr } from './dom.js'; -import { transition_in } from './transitions.js'; +import { check_outros, group_outros, transition_in, transition_out } from './transitions.js'; /** @returns {void} */ export function bind(component, name, callback) { @@ -455,10 +455,22 @@ export class SvelteComponent { */ $$set = undefined; - /** @returns {void} */ - $destroy() { - destroy_component(this, 1); - this.$destroy = noop; + /** + * @param {import('./private.js').ComponentDestroyOptions} [options] + * @returns {void} + */ + $destroy(options) { + if (options?.runOutro && this.$$.fragment && this.$$.fragment.o) { + group_outros(); + transition_out(this.$$.fragment, 0, 0, () => { + destroy_component(this, 1); + this.$destroy = noop; + }); + check_outros(); + } else { + destroy_component(this, 1); + this.$destroy = noop; + } } /** diff --git a/packages/svelte/src/runtime/internal/dev.js b/packages/svelte/src/runtime/internal/dev.js index b1d89add3341..d06397c556ef 100644 --- a/packages/svelte/src/runtime/internal/dev.js +++ b/packages/svelte/src/runtime/internal/dev.js @@ -331,9 +331,12 @@ export class SvelteComponentDev extends SvelteComponent { super(); } - /** @returns {void} */ - $destroy() { - super.$destroy(); + /** + * @param {import('./private.js').ComponentDestroyOptions} [options] + * @returns {void} + */ + $destroy(options) { + super.$destroy(options); this.$destroy = () => { console.warn('Component was already destroyed'); // eslint-disable-line no-console }; diff --git a/packages/svelte/src/runtime/internal/private.d.ts b/packages/svelte/src/runtime/internal/private.d.ts index ef2245256ef7..64aea23de09a 100644 --- a/packages/svelte/src/runtime/internal/private.d.ts +++ b/packages/svelte/src/runtime/internal/private.d.ts @@ -75,6 +75,10 @@ export interface StyleInformation { rules: Record; } +export interface ComponentDestroyOptions { + runOutro?: boolean; +} + export type TaskCallback = (now: number) => boolean | void; export type TaskEntry = { c: TaskCallback; f: () => void }; diff --git a/packages/svelte/test/runtime/samples/transition-js-destroy/_config.js b/packages/svelte/test/runtime/samples/transition-js-destroy/_config.js new file mode 100644 index 000000000000..ddcea983a735 --- /dev/null +++ b/packages/svelte/test/runtime/samples/transition-js-destroy/_config.js @@ -0,0 +1,15 @@ +export default { + skip_if_ssr: true, + skip_if_hydrate: true, + skip_if_hydrate_from_ssr: true, + test({ assert, component, target, raf }) { + component.$destroy({ runOutro: true }); + + return Promise.resolve().then(() => { + const div = target.querySelector('div'); + + raf.tick(50); + assert.equal(div.transitioned, 0.5); + }); + } +}; diff --git a/packages/svelte/test/runtime/samples/transition-js-destroy/main.svelte b/packages/svelte/test/runtime/samples/transition-js-destroy/main.svelte new file mode 100644 index 000000000000..3d3eb655b40a --- /dev/null +++ b/packages/svelte/test/runtime/samples/transition-js-destroy/main.svelte @@ -0,0 +1,14 @@ + + +