feat: add outro option to unmount ()

* feat: add outro option to unmount

* unused

* regenerate

* revert

* changeset

* create separate component_root effect

* docs

* return a promise

* remove from map immediately
pull/14710/head
Rich Harris 4 months ago committed by GitHub
parent f0af633263
commit b0e3c5b438
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: add `outro` option to `unmount`

@ -33,19 +33,22 @@ Note that unlike calling `new App(...)` in Svelte 4, things like effects (includ
## `unmount`
Unmounts a component created with [`mount`](#mount) or [`hydrate`](#hydrate):
Unmounts a component that was previously created with [`mount`](#mount) or [`hydrate`](#hydrate).
If `options.outro` is `true`, [transitions](transition) will play before the component is removed from the DOM:
```js
// @errors: 1109
import { mount, unmount } from 'svelte';
import App from './App.svelte';
const app = mount(App, {...});
const app = mount(App, { target: document.body });
// later
unmount(app);
unmount(app, { outro: true });
```
Returns a `Promise` that resolves after transitions have completed if `options.outro` is true, or immediately otherwise.
## `render`
Only available on the server and when compiling with the `server` option. Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app:

@ -248,11 +248,35 @@ export function inspect_effect(fn) {
*/
export function effect_root(fn) {
const effect = create_effect(ROOT_EFFECT, fn, true);
return () => {
destroy_effect(effect);
};
}
/**
* An effect root whose children can transition out
* @param {() => void} fn
* @returns {(options?: { outro?: boolean }) => Promise<void>}
*/
export function component_root(fn) {
const effect = create_effect(ROOT_EFFECT, fn, true);
return (options = {}) => {
return new Promise((fulfil) => {
if (options.outro) {
pause_effect(effect, () => {
destroy_effect(effect);
fulfil(undefined);
});
} else {
destroy_effect(effect);
fulfil(undefined);
}
});
};
}
/**
* @param {() => void | (() => void)} fn
* @returns {Effect}

@ -10,7 +10,7 @@ import {
} from './dom/operations.js';
import { HYDRATION_END, HYDRATION_ERROR, HYDRATION_START } from '../../constants.js';
import { push, pop, component_context, active_effect } from './runtime.js';
import { effect_root, branch } from './reactivity/effects.js';
import { component_root, branch } from './reactivity/effects.js';
import {
hydrate_next,
hydrate_node,
@ -204,7 +204,7 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro
// @ts-expect-error will be defined because the render effect runs synchronously
var component = undefined;
var unmount = effect_root(() => {
var unmount = component_root(() => {
var anchor_node = anchor ?? target.appendChild(create_text());
branch(() => {
@ -252,7 +252,7 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro
}
root_event_handles.delete(event_handle);
mounted_components.delete(component);
if (anchor_node !== anchor) {
anchor_node.parentNode?.removeChild(anchor_node);
}
@ -271,14 +271,35 @@ let mounted_components = new WeakMap();
/**
* Unmounts a component that was previously mounted using `mount` or `hydrate`.
*
* If `options.outro` is `true`, [transitions](https://svelte.dev/docs/svelte/transition) will play before the component is removed from the DOM.
*
* Returns a `Promise` that resolves after transitions have completed if `options.outro` is true, or immediately otherwise.
*
* ```js
* import { mount, unmount } from 'svelte';
* import App from './App.svelte';
*
* const app = mount(App, { target: document.body });
*
* // later...
* unmount(app, { outro: true });
* ```
* @param {Record<string, any>} component
* @param {{ outro?: boolean }} [options]
* @returns {Promise<void>}
*/
export function unmount(component) {
export function unmount(component, options) {
const fn = mounted_components.get(component);
if (fn) {
fn();
} else if (DEV) {
mounted_components.delete(component);
return fn(options);
}
if (DEV) {
w.lifecycle_double_unmount();
}
return Promise.resolve();
}

@ -448,8 +448,24 @@ declare module 'svelte' {
}): Exports;
/**
* Unmounts a component that was previously mounted using `mount` or `hydrate`.
*
* If `options.outro` is `true`, [transitions](https://svelte.dev/docs/svelte/transition) will play before the component is removed from the DOM.
*
* Returns a `Promise` that resolves after transitions have completed if `options.outro` is true, or immediately otherwise.
*
* ```js
* import { mount, unmount } from 'svelte';
* import App from './App.svelte';
*
* const app = mount(App, { target: document.body });
*
* // later...
* unmount(app, { outro: true });
* ```
* */
export function unmount(component: Record<string, any>): void;
export function unmount(component: Record<string, any>, options?: {
outro?: boolean;
} | undefined): Promise<void>;
/**
* Returns a promise that resolves once any pending state changes have been applied.
* */

Loading…
Cancel
Save