UNPKG

svelte

Version:

Cybernetically enhanced web apps

115 lines (97 loc) 3.26 kB
/** @import { Snippet } from 'svelte' */ /** @import { Effect, TemplateNode } from '#client' */ /** @import { Getters } from '#shared' */ import { EFFECT_TRANSPARENT } from '../../constants.js'; import { branch, block, destroy_effect, teardown } from '../../reactivity/effects.js'; import { dev_current_component_function, set_dev_current_component_function } from '../../context.js'; import { hydrate_next, hydrate_node, hydrating } from '../hydration.js'; import { create_fragment_from_html } from '../reconciler.js'; import { assign_nodes } from '../template.js'; import * as w from '../../warnings.js'; import * as e from '../../errors.js'; import { DEV } from 'esm-env'; import { get_first_child, get_next_sibling } from '../operations.js'; import { noop } from '../../../shared/utils.js'; /** * @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn * @param {TemplateNode} node * @param {() => SnippetFn | null | undefined} get_snippet * @param {(() => any)[]} args * @returns {void} */ export function snippet(node, get_snippet, ...args) { var anchor = node; /** @type {SnippetFn | null | undefined} */ // @ts-ignore var snippet = noop; /** @type {Effect | null} */ var snippet_effect; block(() => { if (snippet === (snippet = get_snippet())) return; if (snippet_effect) { destroy_effect(snippet_effect); snippet_effect = null; } if (DEV && snippet == null) { e.invalid_snippet(); } snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(anchor, ...args)); }, EFFECT_TRANSPARENT); if (hydrating) { anchor = hydrate_node; } } /** * In development, wrap the snippet function so that it passes validation, and so that the * correct component context is set for ownership checks * @param {any} component * @param {(node: TemplateNode, ...args: any[]) => void} fn */ export function wrap_snippet(component, fn) { return (/** @type {TemplateNode} */ node, /** @type {any[]} */ ...args) => { var previous_component_function = dev_current_component_function; set_dev_current_component_function(component); try { return fn(node, ...args); } finally { set_dev_current_component_function(previous_component_function); } }; } /** * Create a snippet programmatically * @template {unknown[]} Params * @param {(...params: Getters<Params>) => { * render: () => string * setup?: (element: Element) => void | (() => void) * }} fn * @returns {Snippet<Params>} */ export function createRawSnippet(fn) { // @ts-expect-error the types are a lie return (/** @type {TemplateNode} */ anchor, /** @type {Getters<Params>} */ ...params) => { var snippet = fn(...params); /** @type {Element} */ var element; if (hydrating) { element = /** @type {Element} */ (hydrate_node); hydrate_next(); } else { var html = snippet.render().trim(); var fragment = create_fragment_from_html(html); element = /** @type {Element} */ (get_first_child(fragment)); if (DEV && (get_next_sibling(element) !== null || element.nodeType !== 1)) { w.invalid_raw_snippet_render(); } anchor.before(element); } const result = snippet.setup?.(element); assign_nodes(element, element); if (typeof result === 'function') { teardown(result); } }; }