this repo has no description
at main 183 lines 6.1 kB view raw
1import { custom_event } from './dom.js'; 2 3export let current_component; 4 5/** @returns {void} */ 6export function set_current_component(component) { 7 current_component = component; 8} 9 10export function get_current_component() { 11 if (!current_component) throw new Error('Function called outside component initialization'); 12 return current_component; 13} 14 15/** 16 * Schedules a callback to run immediately before the component is updated after any state change. 17 * 18 * The first time the callback runs will be before the initial `onMount` 19 * 20 * https://svelte.dev/docs/svelte#beforeupdate 21 * @param {() => any} fn 22 * @returns {void} 23 */ 24export function beforeUpdate(fn) { 25 get_current_component().$$.before_update.push(fn); 26} 27 28/** 29 * The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM. 30 * It must be called during the component's initialisation (but doesn't need to live *inside* the component; 31 * it can be called from an external module). 32 * 33 * If a function is returned _synchronously_ from `onMount`, it will be called when the component is unmounted. 34 * 35 * `onMount` does not run inside a [server-side component](https://svelte.dev/docs#run-time-server-side-component-api). 36 * 37 * https://svelte.dev/docs/svelte#onmount 38 * @template T 39 * @param {() => import('./private.js').NotFunction<T> | Promise<import('./private.js').NotFunction<T>> | (() => any)} fn 40 * @returns {void} 41 */ 42export function onMount(fn) { 43 get_current_component().$$.on_mount.push(fn); 44} 45 46/** 47 * Schedules a callback to run immediately after the component has been updated. 48 * 49 * The first time the callback runs will be after the initial `onMount` 50 * 51 * https://svelte.dev/docs/svelte#afterupdate 52 * @param {() => any} fn 53 * @returns {void} 54 */ 55export function afterUpdate(fn) { 56 get_current_component().$$.after_update.push(fn); 57} 58 59/** 60 * Schedules a callback to run immediately before the component is unmounted. 61 * 62 * Out of `onMount`, `beforeUpdate`, `afterUpdate` and `onDestroy`, this is the 63 * only one that runs inside a server-side component. 64 * 65 * https://svelte.dev/docs/svelte#ondestroy 66 * @param {() => any} fn 67 * @returns {void} 68 */ 69export function onDestroy(fn) { 70 get_current_component().$$.on_destroy.push(fn); 71} 72 73/** 74 * Creates an event dispatcher that can be used to dispatch [component events](https://svelte.dev/docs#template-syntax-component-directives-on-eventname). 75 * Event dispatchers are functions that can take two arguments: `name` and `detail`. 76 * 77 * Component events created with `createEventDispatcher` create a 78 * [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). 79 * These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture). 80 * The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) 81 * property and can contain any type of data. 82 * 83 * The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument: 84 * ```ts 85 * const dispatch = createEventDispatcher<{ 86 * loaded: never; // does not take a detail argument 87 * change: string; // takes a detail argument of type string, which is required 88 * optional: number | null; // takes an optional detail argument of type number 89 * }>(); 90 * ``` 91 * 92 * https://svelte.dev/docs/svelte#createeventdispatcher 93 * @template {Record<string, any>} [EventMap=any] 94 * @returns {import('./public.js').EventDispatcher<EventMap>} 95 */ 96export function createEventDispatcher() { 97 const component = get_current_component(); 98 return (type, detail, { cancelable = false } = {}) => { 99 const callbacks = component.$$.callbacks[type]; 100 if (callbacks) { 101 // TODO are there situations where events could be dispatched 102 // in a server (non-DOM) environment? 103 const event = custom_event(/** @type {string} */ (type), detail, { cancelable }); 104 callbacks.slice().forEach((fn) => { 105 fn.call(component, event); 106 }); 107 return !event.defaultPrevented; 108 } 109 return true; 110 }; 111} 112 113/** 114 * Associates an arbitrary `context` object with the current component and the specified `key` 115 * and returns that object. The context is then available to children of the component 116 * (including slotted content) with `getContext`. 117 * 118 * Like lifecycle functions, this must be called during component initialisation. 119 * 120 * https://svelte.dev/docs/svelte#setcontext 121 * @template T 122 * @param {any} key 123 * @param {T} context 124 * @returns {T} 125 */ 126export function setContext(key, context) { 127 get_current_component().$$.context.set(key, context); 128 return context; 129} 130 131/** 132 * Retrieves the context that belongs to the closest parent component with the specified `key`. 133 * Must be called during component initialisation. 134 * 135 * https://svelte.dev/docs/svelte#getcontext 136 * @template T 137 * @param {any} key 138 * @returns {T} 139 */ 140export function getContext(key) { 141 return get_current_component().$$.context.get(key); 142} 143 144/** 145 * Retrieves the whole context map that belongs to the closest parent component. 146 * Must be called during component initialisation. Useful, for example, if you 147 * programmatically create a component and want to pass the existing context to it. 148 * 149 * https://svelte.dev/docs/svelte#getallcontexts 150 * @template {Map<any, any>} [T=Map<any, any>] 151 * @returns {T} 152 */ 153export function getAllContexts() { 154 return get_current_component().$$.context; 155} 156 157/** 158 * Checks whether a given `key` has been set in the context of a parent component. 159 * Must be called during component initialisation. 160 * 161 * https://svelte.dev/docs/svelte#hascontext 162 * @param {any} key 163 * @returns {boolean} 164 */ 165export function hasContext(key) { 166 return get_current_component().$$.context.has(key); 167} 168 169// TODO figure out if we still want to support 170// shorthand events, or if we want to implement 171// a real bubbling mechanism 172/** 173 * @param component 174 * @param event 175 * @returns {void} 176 */ 177export function bubble(component, event) { 178 const callbacks = component.$$.callbacks[event.type]; 179 if (callbacks) { 180 // @ts-ignore 181 callbacks.slice().forEach((fn) => fn.call(this, event)); 182 } 183}