mirror of https://github.com/sveltejs/svelte
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
6.6 KiB
198 lines
6.6 KiB
/** @import { ComponentContext, ComponentContextLegacy } from '#client' */
|
|
/** @import { EventDispatcher } from './index.js' */
|
|
/** @import { NotFunction } from './internal/types.js' */
|
|
import { current_component_context, flush_sync, untrack } from './internal/client/runtime.js';
|
|
import { is_array } from './internal/shared/utils.js';
|
|
import { user_effect } from './internal/client/index.js';
|
|
import * as e from './internal/client/errors.js';
|
|
import { lifecycle_outside_component } from './internal/shared/errors.js';
|
|
|
|
/**
|
|
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
|
|
* It must be called during the component's initialisation (but doesn't need to live *inside* the component;
|
|
* it can be called from an external module).
|
|
*
|
|
* If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted.
|
|
*
|
|
* `onMount` does not run inside a [server-side component](https://svelte.dev/docs#run-time-server-side-component-api).
|
|
*
|
|
* https://svelte.dev/docs/svelte#onmount
|
|
* @template T
|
|
* @param {() => NotFunction<T> | Promise<NotFunction<T>> | (() => any)} fn
|
|
* @returns {void}
|
|
*/
|
|
export function onMount(fn) {
|
|
if (current_component_context === null) {
|
|
lifecycle_outside_component('onMount');
|
|
}
|
|
|
|
if (current_component_context.l !== null) {
|
|
init_update_callbacks(current_component_context).m.push(fn);
|
|
} else {
|
|
user_effect(() => {
|
|
const cleanup = untrack(fn);
|
|
if (typeof cleanup === 'function') return /** @type {() => void} */ (cleanup);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Schedules a callback to run immediately before the component is unmounted.
|
|
*
|
|
* Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the
|
|
* only one that runs inside a server-side component.
|
|
*
|
|
* https://svelte.dev/docs/svelte#ondestroy
|
|
* @param {() => any} fn
|
|
* @returns {void}
|
|
*/
|
|
export function onDestroy(fn) {
|
|
if (current_component_context === null) {
|
|
lifecycle_outside_component('onDestroy');
|
|
}
|
|
|
|
onMount(() => () => untrack(fn));
|
|
}
|
|
|
|
/**
|
|
* @template [T=any]
|
|
* @param {string} type
|
|
* @param {T} [detail]
|
|
* @param {any}params_0
|
|
* @returns {CustomEvent<T>}
|
|
*/
|
|
function create_custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
|
|
return new CustomEvent(type, { detail, bubbles, cancelable });
|
|
}
|
|
|
|
/**
|
|
* Creates an event dispatcher that can be used to dispatch [component events](https://svelte.dev/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).
|
|
* 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.
|
|
*
|
|
* The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument:
|
|
* ```ts
|
|
* const dispatch = createEventDispatcher<{
|
|
* loaded: never; // does not take a detail argument
|
|
* change: string; // takes a detail argument of type string, which is required
|
|
* optional: number | null; // takes an optional detail argument of type number
|
|
* }>();
|
|
* ```
|
|
*
|
|
* https://svelte.dev/docs/svelte#createeventdispatcher
|
|
* @deprecated Use callback props and/or the `$host()` rune instead — see https://svelte-5-preview.vercel.app/docs/deprecations#createeventdispatcher
|
|
* @template {Record<string, any>} [EventMap = any]
|
|
* @returns {EventDispatcher<EventMap>}
|
|
*/
|
|
export function createEventDispatcher() {
|
|
const component_context = current_component_context;
|
|
if (component_context === null) {
|
|
lifecycle_outside_component('createEventDispatcher');
|
|
}
|
|
|
|
return (type, detail, options) => {
|
|
const events = /** @type {Record<string, Function | Function[]>} */ (
|
|
component_context.s.$$events
|
|
)?.[/** @type {any} */ (type)];
|
|
|
|
if (events) {
|
|
const callbacks = is_array(events) ? events.slice() : [events];
|
|
// TODO are there situations where events could be dispatched
|
|
// in a server (non-DOM) environment?
|
|
const event = create_custom_event(/** @type {string} */ (type), detail, options);
|
|
for (const fn of callbacks) {
|
|
fn.call(component_context.x, event);
|
|
}
|
|
return !event.defaultPrevented;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
}
|
|
|
|
// TODO mark beforeUpdate and afterUpdate as deprecated in Svelte 6
|
|
|
|
/**
|
|
* Schedules a callback to run immediately before the component is updated after any state change.
|
|
*
|
|
* The first time the callback runs will be before the initial `onMount`.
|
|
*
|
|
* In runes mode use `$effect.pre` instead.
|
|
*
|
|
* https://svelte.dev/docs/svelte#beforeupdate
|
|
* @deprecated Use `$effect.pre` instead — see https://svelte-5-preview.vercel.app/docs/deprecations#beforeupdate-and-afterupdate
|
|
* @param {() => void} fn
|
|
* @returns {void}
|
|
*/
|
|
export function beforeUpdate(fn) {
|
|
if (current_component_context === null) {
|
|
lifecycle_outside_component('beforeUpdate');
|
|
}
|
|
|
|
if (current_component_context.l === null) {
|
|
e.lifecycle_legacy_only('beforeUpdate');
|
|
}
|
|
|
|
init_update_callbacks(current_component_context).b.push(fn);
|
|
}
|
|
|
|
/**
|
|
* Schedules a callback to run immediately after the component has been updated.
|
|
*
|
|
* The first time the callback runs will be after the initial `onMount`.
|
|
*
|
|
* In runes mode use `$effect` instead.
|
|
*
|
|
* https://svelte.dev/docs/svelte#afterupdate
|
|
* @deprecated Use `$effect` instead — see https://svelte-5-preview.vercel.app/docs/deprecations#beforeupdate-and-afterupdate
|
|
* @param {() => void} fn
|
|
* @returns {void}
|
|
*/
|
|
export function afterUpdate(fn) {
|
|
if (current_component_context === null) {
|
|
lifecycle_outside_component('afterUpdate');
|
|
}
|
|
|
|
if (current_component_context.l === null) {
|
|
e.lifecycle_legacy_only('afterUpdate');
|
|
}
|
|
|
|
init_update_callbacks(current_component_context).a.push(fn);
|
|
}
|
|
|
|
/**
|
|
* Legacy-mode: Init callbacks object for onMount/beforeUpdate/afterUpdate
|
|
* @param {ComponentContext} context
|
|
*/
|
|
function init_update_callbacks(context) {
|
|
var l = /** @type {ComponentContextLegacy} */ (context).l;
|
|
return (l.u ??= { a: [], b: [], m: [] });
|
|
}
|
|
|
|
/**
|
|
* Synchronously flushes any pending state changes and those that result from it.
|
|
* @param {() => void} [fn]
|
|
* @returns {void}
|
|
*/
|
|
export function flushSync(fn) {
|
|
flush_sync(fn);
|
|
}
|
|
|
|
export { hydrate, mount, unmount } from './internal/client/render.js';
|
|
|
|
export {
|
|
getContext,
|
|
getAllContexts,
|
|
hasContext,
|
|
setContext,
|
|
tick,
|
|
untrack
|
|
} from './internal/client/runtime.js';
|
|
|
|
export { createRawSnippet } from './internal/client/dom/blocks/snippet.js';
|