UNPKG

tailwind-screen-size

Version:

A framework-agnostic screen size indicator optimized for TailwindCSS but customizable for any CSS framework. Features real-time dimensions, breakpoints, themes, and development tools.

1,916 lines (1,634 loc) 157 kB
'use strict'; var svelte = require('svelte'); // generated during release, do not modify const PUBLIC_VERSION = '5'; if (typeof window !== 'undefined') // @ts-ignore (window.__svelte ||= { v: new Set() }).v.add(PUBLIC_VERSION); const PROPS_IS_BINDABLE = 1 << 3; const TEMPLATE_FRAGMENT = 1; const TEMPLATE_USE_IMPORT_NODE = 1 << 1; const UNINITIALIZED = Symbol(); // Dev-time component properties const FILENAME = Symbol('filename'); const node_env = globalThis.process?.env?.NODE_ENV; if (!node_env) { console.warn('If bundling, conditions should include development or production. If not bundling, conditions or NODE_ENV should include development or production. See https://www.npmjs.com/package/esm-env for tips on setting conditions in popular bundlers and runtimes.'); } var DEV = node_env && !node_env.toLowerCase().includes('prod'); /* This file is generated by scripts/process-messages/index.js. Do not edit! */ var bold = 'font-weight: bold'; var normal = 'font-weight: normal'; /** * %component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead * @param {string | undefined | null} [component] * @param {string | undefined | null} [owner] */ function ownership_invalid_mutation(component, owner) { if (DEV) { console.warn(`%c[svelte] ownership_invalid_mutation\n%c${component ? `${component} mutated a value owned by ${owner}. This is strongly discouraged. Consider passing values to child components with \`bind:\`, or use a callback instead` : "Mutating a value outside the component that created it is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead"}`, bold, normal); } else { // TODO print a link to the documentation console.warn("ownership_invalid_mutation"); } } /** * Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results * @param {string} operator */ function state_proxy_equality_mismatch(operator) { if (DEV) { console.warn(`%c[svelte] state_proxy_equality_mismatch\n%cReactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results`, bold, normal); } else { // TODO print a link to the documentation console.warn("state_proxy_equality_mismatch"); } } // Store the references to globals in case someone tries to monkey patch these, causing the below // to de-opt (this occurs often when using popular extensions). var is_array = Array.isArray; var define_property = Object.defineProperty; var get_descriptor = Object.getOwnPropertyDescriptor; var object_prototype = Object.prototype; var array_prototype = Array.prototype; var get_prototype_of = Object.getPrototypeOf; const DERIVED = 1 << 1; const EFFECT = 1 << 2; const RENDER_EFFECT = 1 << 3; const BLOCK_EFFECT = 1 << 4; const BRANCH_EFFECT = 1 << 5; const ROOT_EFFECT = 1 << 6; const UNOWNED = 1 << 7; const DISCONNECTED = 1 << 8; const CLEAN = 1 << 9; const DIRTY = 1 << 10; const MAYBE_DIRTY = 1 << 11; const INERT = 1 << 12; const DESTROYED = 1 << 13; const EFFECT_RAN = 1 << 14; /** 'Transparent' effects do not create a transition boundary */ const EFFECT_TRANSPARENT = 1 << 15; const INSPECT_EFFECT = 1 << 17; const HEAD_EFFECT = 1 << 18; const EFFECT_HAS_DERIVED = 1 << 19; const STATE_SYMBOL = Symbol('$state'); const STATE_SYMBOL_METADATA = Symbol('$state metadata'); const LEGACY_PROPS = Symbol('legacy props'); /** @import { Equals } from '#client' */ /** @type {Equals} */ function equals(value) { return value === this.v; } /* This file is generated by scripts/process-messages/index.js. Do not edit! */ /** * Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`) * @param {string} component * @param {string} key * @param {string} name * @returns {never} */ function bind_invalid_export(component, key, name) { if (DEV) { const error = new Error(`bind_invalid_export\nComponent ${component} has an export named \`${key}\` that a consumer component is trying to access using \`bind:${key}\`, which is disallowed. Instead, use \`bind:this\` (e.g. \`<${name} bind:this={component} />\`) and then access the property on the bound component instance (e.g. \`component.${key}\`)`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("bind_invalid_export"); } } /** * A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()` * @param {string} key * @param {string} component * @param {string} name * @returns {never} */ function bind_not_bindable(key, component, name) { if (DEV) { const error = new Error(`bind_not_bindable\nA component is attempting to bind to a non-bindable property \`${key}\` belonging to ${component} (i.e. \`<${name} bind:${key}={...}>\`). To mark a property as bindable: \`let { ${key} = $bindable() } = $props()\``); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("bind_not_bindable"); } } /** * %parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information * @param {string} parent * @param {string} method * @param {string} component * @returns {never} */ function component_api_changed(parent, method, component) { if (DEV) { const error = new Error(`component_api_changed\n${parent} called \`${method}\` on an instance of ${component}, which is no longer valid in Svelte 5. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("component_api_changed"); } } /** * Attempted to instantiate %component% with `new %name%`, which is no longer valid in Svelte 5. If this component is not under your control, set the `compatibility.componentApi` compiler option to `4` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information * @param {string} component * @param {string} name * @returns {never} */ function component_api_invalid_new(component, name) { if (DEV) { const error = new Error(`component_api_invalid_new\nAttempted to instantiate ${component} with \`new ${name}\`, which is no longer valid in Svelte 5. If this component is not under your control, set the \`compatibility.componentApi\` compiler option to \`4\` to keep it working. See https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes for more information`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("component_api_invalid_new"); } } /** * A derived value cannot reference itself recursively * @returns {never} */ function derived_references_self() { if (DEV) { const error = new Error(`derived_references_self\nA derived value cannot reference itself recursively`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("derived_references_self"); } } /** * Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops * @returns {never} */ function effect_update_depth_exceeded() { if (DEV) { const error = new Error(`effect_update_depth_exceeded\nMaximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("effect_update_depth_exceeded"); } } /** * Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value * @param {string} key * @returns {never} */ function props_invalid_value(key) { if (DEV) { const error = new Error(`props_invalid_value\nCannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("props_invalid_value"); } } /** * The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files * @param {string} rune * @returns {never} */ function rune_outside_svelte(rune) { if (DEV) { const error = new Error(`rune_outside_svelte\nThe \`${rune}\` rune is only available inside \`.svelte\` and \`.svelte.js/ts\` files`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("rune_outside_svelte"); } } /** * Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`. * @returns {never} */ function state_descriptors_fixed() { if (DEV) { const error = new Error(`state_descriptors_fixed\nProperty descriptors defined on \`$state\` objects must contain \`value\` and always be \`enumerable\`, \`configurable\` and \`writable\`.`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("state_descriptors_fixed"); } } /** * Cannot set prototype of `$state` object * @returns {never} */ function state_prototype_fixed() { if (DEV) { const error = new Error(`state_prototype_fixed\nCannot set prototype of \`$state\` object`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("state_prototype_fixed"); } } /** * Reading state that was created inside the same derived is forbidden. Consider using `untrack` to read locally created state * @returns {never} */ function state_unsafe_local_read() { if (DEV) { const error = new Error(`state_unsafe_local_read\nReading state that was created inside the same derived is forbidden. Consider using \`untrack\` to read locally created state`); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("state_unsafe_local_read"); } } /** * Updating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without `$state` * @returns {never} */ function state_unsafe_mutation() { if (DEV) { const error = new Error(`state_unsafe_mutation\nUpdating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without \`$state\``); error.name = 'Svelte error'; throw error; } else { // TODO print a link to the documentation throw new Error("state_unsafe_mutation"); } } let legacy_mode_flag = false; /** @import { Derived, Effect, Reaction, Source, Value } from '#client' */ let inspect_effects = new Set(); /** * @param {Set<any>} v */ function set_inspect_effects(v) { inspect_effects = v; } /** * @template V * @param {V} v * @returns {Source<V>} */ function source(v) { return { f: 0, // TODO ideally we could skip this altogether, but it causes type errors v, reactions: null, equals, version: 0 }; } /** * @template V * @param {V} v */ function state(v) { return push_derived_source(source(v)); } /** * @template V * @param {Source<V>} source */ /*#__NO_SIDE_EFFECTS__*/ function push_derived_source(source) { if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0) { if (derived_sources === null) { set_derived_sources([source]); } else { derived_sources.push(source); } } return source; } /** * @template V * @param {Source<V>} source * @param {V} value * @returns {V} */ function set(source, value) { if ( active_reaction !== null && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT)) !== 0 && // If the source was created locally within the current derived, then // we allow the mutation. (derived_sources === null || !derived_sources.includes(source)) ) { state_unsafe_mutation(); } return internal_set(source, value); } /** * @template V * @param {Source<V>} source * @param {V} value * @returns {V} */ function internal_set(source, value) { if (!source.equals(value)) { source.v = value; source.version = increment_version(); mark_reactions(source, DIRTY); // If the current signal is running for the first time, it won't have any // reactions as we only allocate and assign the reactions after the signal // has fully executed. So in the case of ensuring it registers the reaction // properly for itself, we need to ensure the current effect actually gets // scheduled. i.e: `$effect(() => x++)` if ( active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & BRANCH_EFFECT) === 0 ) { if (new_deps !== null && new_deps.includes(source)) { set_signal_status(active_effect, DIRTY); schedule_effect(active_effect); } else { if (untracked_writes === null) { set_untracked_writes([source]); } else { untracked_writes.push(source); } } } if (DEV && inspect_effects.size > 0) { const inspects = Array.from(inspect_effects); var previously_flushing_effect = is_flushing_effect; set_is_flushing_effect(true); try { for (const effect of inspects) { // Mark clean inspect-effects as maybe dirty and then check their dirtiness // instead of just updating the effects - this way we avoid overfiring. if ((effect.f & CLEAN) !== 0) { set_signal_status(effect, MAYBE_DIRTY); } if (check_dirtiness(effect)) { update_effect(effect); } } } finally { set_is_flushing_effect(previously_flushing_effect); } inspect_effects.clear(); } } return value; } /** * @param {Value} signal * @param {number} status should be DIRTY or MAYBE_DIRTY * @returns {void} */ function mark_reactions(signal, status) { var reactions = signal.reactions; if (reactions === null) return; var length = reactions.length; for (var i = 0; i < length; i++) { var reaction = reactions[i]; var flags = reaction.f; // Skip any effects that are already dirty if ((flags & DIRTY) !== 0) continue; // Inspect effects need to run immediately, so that the stack trace makes sense if (DEV && (flags & INSPECT_EFFECT) !== 0) { inspect_effects.add(reaction); continue; } set_signal_status(reaction, status); // If the signal a) was previously clean or b) is an unowned derived, then mark it if ((flags & (CLEAN | UNOWNED)) !== 0) { if ((flags & DERIVED) !== 0) { mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY); } else { schedule_effect(/** @type {Effect} */ (reaction)); } } } } /** @import { Derived, Effect } from '#client' */ /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function derived(fn) { var flags = DERIVED | DIRTY; if (active_effect === null) { flags |= UNOWNED; } else { // Since deriveds are evaluated lazily, any effects created inside them are // created too late to ensure that the parent effect is added to the tree active_effect.f |= EFFECT_HAS_DERIVED; } var parent_derived = active_reaction !== null && (active_reaction.f & DERIVED) !== 0 ? /** @type {Derived} */ (active_reaction) : null; /** @type {Derived<V>} */ const signal = { children: null, ctx: component_context, deps: null, equals, f: flags, fn, reactions: null, v: /** @type {V} */ (null), version: 0, parent: parent_derived ?? active_effect }; if (parent_derived !== null) { (parent_derived.children ??= []).push(signal); } return signal; } /** * @param {Derived} derived * @returns {void} */ function destroy_derived_children(derived) { var children = derived.children; if (children !== null) { derived.children = null; for (var i = 0; i < children.length; i += 1) { var child = children[i]; if ((child.f & DERIVED) !== 0) { destroy_derived(/** @type {Derived} */ (child)); } else { destroy_effect(/** @type {Effect} */ (child)); } } } } /** * The currently updating deriveds, used to detect infinite recursion * in dev mode and provide a nicer error than 'too much recursion' * @type {Derived[]} */ let stack = []; /** * @param {Derived} derived * @returns {Effect | null} */ function get_derived_parent_effect(derived) { var parent = derived.parent; while (parent !== null) { if ((parent.f & DERIVED) === 0) { return /** @type {Effect} */ (parent); } parent = parent.parent; } return null; } /** * @template T * @param {Derived} derived * @returns {T} */ function execute_derived(derived) { var value; var prev_active_effect = active_effect; set_active_effect(get_derived_parent_effect(derived)); if (DEV) { let prev_inspect_effects = inspect_effects; set_inspect_effects(new Set()); try { if (stack.includes(derived)) { derived_references_self(); } stack.push(derived); destroy_derived_children(derived); value = update_reaction(derived); } finally { set_active_effect(prev_active_effect); set_inspect_effects(prev_inspect_effects); stack.pop(); } } else { try { destroy_derived_children(derived); value = update_reaction(derived); } finally { set_active_effect(prev_active_effect); } } return value; } /** * @param {Derived} derived * @returns {void} */ function update_derived(derived) { var value = execute_derived(derived); var status = (skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN; set_signal_status(derived, status); if (!derived.equals(value)) { derived.v = value; derived.version = increment_version(); } } /** * @param {Derived} derived * @returns {void} */ function destroy_derived(derived) { destroy_derived_children(derived); remove_reactions(derived, 0); set_signal_status(derived, DESTROYED); derived.v = derived.children = derived.deps = derived.ctx = derived.reactions = null; } /** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, Reaction, TemplateNode, TransitionManager } from '#client' */ /** * @param {Effect} effect * @param {Effect} parent_effect */ function push_effect(effect, parent_effect) { var parent_last = parent_effect.last; if (parent_last === null) { parent_effect.last = parent_effect.first = effect; } else { parent_last.next = effect; effect.prev = parent_last; parent_effect.last = effect; } } /** * @param {number} type * @param {null | (() => void | (() => void))} fn * @param {boolean} sync * @param {boolean} push * @returns {Effect} */ function create_effect(type, fn, sync, push = true) { var is_root = (type & ROOT_EFFECT) !== 0; var parent_effect = active_effect; if (DEV) { // Ensure the parent is never an inspect effect while (parent_effect !== null && (parent_effect.f & INSPECT_EFFECT) !== 0) { parent_effect = parent_effect.parent; } } /** @type {Effect} */ var effect = { ctx: component_context, deps: null, deriveds: null, nodes_start: null, nodes_end: null, f: type | DIRTY, first: null, fn, last: null, next: null, parent: is_root ? null : parent_effect, prev: null, teardown: null, transitions: null, version: 0 }; if (DEV) { effect.component_function = dev_current_component_function; } if (sync) { var previously_flushing_effect = is_flushing_effect; try { set_is_flushing_effect(true); update_effect(effect); effect.f |= EFFECT_RAN; } catch (e) { destroy_effect(effect); throw e; } finally { set_is_flushing_effect(previously_flushing_effect); } } else if (fn !== null) { schedule_effect(effect); } // if an effect has no dependencies, no DOM and no teardown function, // don't bother adding it to the effect tree var inert = sync && effect.deps === null && effect.first === null && effect.nodes_start === null && effect.teardown === null && (effect.f & EFFECT_HAS_DERIVED) === 0; if (!inert && !is_root && push) { if (parent_effect !== null) { push_effect(effect, parent_effect); } // if we're in a derived, add the effect there too if (active_reaction !== null && (active_reaction.f & DERIVED) !== 0) { var derived = /** @type {Derived} */ (active_reaction); (derived.children ??= []).push(effect); } } return effect; } /** * @param {() => void | (() => void)} fn * @returns {Effect} */ function effect(fn) { return create_effect(EFFECT, fn, false); } /** * @param {() => void | (() => void)} fn * @returns {Effect} */ function template_effect(fn) { if (DEV) { define_property(fn, 'name', { value: '{expression}' }); } return block(fn); } /** * @param {(() => void)} fn * @param {number} flags */ function block(fn, flags = 0) { return create_effect(RENDER_EFFECT | BLOCK_EFFECT | flags, fn, true); } /** * @param {(() => void)} fn * @param {boolean} [push] */ function branch(fn, push = true) { return create_effect(RENDER_EFFECT | BRANCH_EFFECT, fn, true, push); } /** * @param {Effect} effect */ function execute_effect_teardown(effect) { var teardown = effect.teardown; if (teardown !== null) { const previous_reaction = active_reaction; set_active_reaction(null); try { teardown.call(null); } finally { set_active_reaction(previous_reaction); } } } /** * @param {Effect} signal * @returns {void} */ function destroy_effect_deriveds(signal) { var deriveds = signal.deriveds; if (deriveds !== null) { signal.deriveds = null; for (var i = 0; i < deriveds.length; i += 1) { destroy_derived(deriveds[i]); } } } /** * @param {Effect} signal * @param {boolean} remove_dom * @returns {void} */ function destroy_effect_children(signal, remove_dom = false) { var effect = signal.first; signal.first = signal.last = null; while (effect !== null) { var next = effect.next; destroy_effect(effect, remove_dom); effect = next; } } /** * @param {Effect} signal * @returns {void} */ function destroy_block_effect_children(signal) { var effect = signal.first; while (effect !== null) { var next = effect.next; if ((effect.f & BRANCH_EFFECT) === 0) { destroy_effect(effect); } effect = next; } } /** * @param {Effect} effect * @param {boolean} [remove_dom] * @returns {void} */ function destroy_effect(effect, remove_dom = true) { var removed = false; if ((remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes_start !== null) { /** @type {TemplateNode | null} */ var node = effect.nodes_start; var end = effect.nodes_end; while (node !== null) { /** @type {TemplateNode | null} */ var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node)); node.remove(); node = next; } removed = true; } destroy_effect_children(effect, remove_dom && !removed); destroy_effect_deriveds(effect); remove_reactions(effect, 0); set_signal_status(effect, DESTROYED); var transitions = effect.transitions; if (transitions !== null) { for (const transition of transitions) { transition.stop(); } } execute_effect_teardown(effect); var parent = effect.parent; // If the parent doesn't have any children, then skip this work altogether if (parent !== null && parent.first !== null) { unlink_effect(effect); } if (DEV) { effect.component_function = null; } // `first` and `child` are nulled out in destroy_effect_children effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.parent = effect.fn = effect.nodes_start = effect.nodes_end = null; } /** * Detach an effect from the effect tree, freeing up memory and * reducing the amount of work that happens on subsequent traversals * @param {Effect} effect */ function unlink_effect(effect) { var parent = effect.parent; var prev = effect.prev; var next = effect.next; if (prev !== null) prev.next = next; if (next !== null) next.prev = prev; if (parent !== null) { if (parent.first === effect) parent.first = next; if (parent.last === effect) parent.last = prev; } } /** * When a block effect is removed, we don't immediately destroy it or yank it * out of the DOM, because it might have transitions. Instead, we 'pause' it. * It stays around (in memory, and in the DOM) until outro transitions have * completed, and if the state change is reversed then we _resume_ it. * A paused effect does not update, and the DOM subtree becomes inert. * @param {Effect} effect * @param {() => void} [callback] */ function pause_effect(effect, callback) { /** @type {TransitionManager[]} */ var transitions = []; pause_children(effect, transitions, true); run_out_transitions(transitions, () => { destroy_effect(effect); if (callback) callback(); }); } /** * @param {TransitionManager[]} transitions * @param {() => void} fn */ function run_out_transitions(transitions, fn) { var remaining = transitions.length; if (remaining > 0) { var check = () => --remaining || fn(); for (var transition of transitions) { transition.out(check); } } else { fn(); } } /** * @param {Effect} effect * @param {TransitionManager[]} transitions * @param {boolean} local */ function pause_children(effect, transitions, local) { if ((effect.f & INERT) !== 0) return; effect.f ^= INERT; if (effect.transitions !== null) { for (const transition of effect.transitions) { if (transition.is_global || local) { transitions.push(transition); } } } var child = effect.first; while (child !== null) { var sibling = child.next; var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; // TODO we don't need to call pause_children recursively with a linked list in place // it's slightly more involved though as we have to account for `transparent` changing // through the tree. pause_children(child, transitions, transparent ? local : false); child = sibling; } } /** * The opposite of `pause_effect`. We call this if (for example) * `x` becomes falsy then truthy: `{#if x}...{/if}` * @param {Effect} effect */ function resume_effect(effect) { resume_children(effect, true); } /** * @param {Effect} effect * @param {boolean} local */ function resume_children(effect, local) { if ((effect.f & INERT) === 0) return; // If a dependency of this effect changed while it was paused, // apply the change now if (check_dirtiness(effect)) { update_effect(effect); } // Ensure we toggle the flag after possibly updating the effect so that // each block logic can correctly operate on inert items effect.f ^= INERT; var child = effect.first; while (child !== null) { var sibling = child.next; var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; // TODO we don't need to call resume_children recursively with a linked list in place // it's slightly more involved though as we have to account for `transparent` changing // through the tree. resume_children(child, transparent ? local : false); child = sibling; } if (effect.transitions !== null) { for (const transition of effect.transitions) { if (transition.is_global || local) { transition.in(); } } } } /** @import { ProxyMetadata } from '#client' */ /** @typedef {{ file: string, line: number, column: number }} Location */ /** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */ const boundaries = {}; const chrome_pattern = /at (?:.+ \()?(.+):(\d+):(\d+)\)?$/; const firefox_pattern = /@(.+):(\d+):(\d+)$/; function get_stack() { const stack = new Error().stack; if (!stack) return null; const entries = []; for (const line of stack.split('\n')) { let match = chrome_pattern.exec(line) ?? firefox_pattern.exec(line); if (match) { entries.push({ file: match[1], line: +match[2], column: +match[3] }); } } return entries; } /** * Determines which `.svelte` component is responsible for a given state change * @returns {Function | null} */ function get_component() { // first 4 lines are svelte internals; adjust this number if we change the internal call stack const stack = get_stack()?.slice(4); if (!stack) return null; for (let i = 0; i < stack.length; i++) { const entry = stack[i]; const modules = boundaries[entry.file]; if (!modules) { // If the first entry is not a component, that means the modification very likely happened // within a .svelte.js file, possibly triggered by a component. Since these files are not part // of the bondaries/component context heuristic, we need to bail in this case, else we would // have false positives when the .svelte.ts file provides a state creator function, encapsulating // the state and its mutations, and is being called from a component other than the one who // called the state creator function. if (i === 0) return null; continue; } for (const module of modules) { if (module.end == null) { return null; } if (module.start.line < entry.line && module.end.line > entry.line) { return module.component; } } } return null; } /** * Together with `mark_module_end`, this function establishes the boundaries of a `.svelte` file, * such that subsequent calls to `get_component` can tell us which component is responsible * for a given state change */ function mark_module_start() { const start = get_stack()?.[2]; if (start) { (boundaries[start.file] ??= []).push({ start, // @ts-expect-error end: null, // @ts-expect-error we add the component at the end, since HMR will overwrite the function component: null }); } } /** * @param {Function} component */ function mark_module_end(component) { const end = get_stack()?.[2]; if (end) { const boundaries_file = boundaries[end.file]; const boundary = boundaries_file[boundaries_file.length - 1]; boundary.end = end; boundary.component = component; } } /** * @param {ProxyMetadata | null} from * @param {ProxyMetadata} to */ function widen_ownership(from, to) { if (to.owners === null) { return; } while (from) { if (from.owners === null) { to.owners = null; break; } for (const owner of from.owners) { to.owners.add(owner); } from = from.parent; } } /** * @param {ProxyMetadata} metadata * @param {Function} component * @returns {boolean} */ function has_owner(metadata, component) { if (metadata.owners === null) { return true; } return ( metadata.owners.has(component) || (metadata.parent !== null && has_owner(metadata.parent, component)) ); } /** * @param {ProxyMetadata} metadata * @returns {any} */ function get_owner(metadata) { return ( metadata?.owners?.values().next().value ?? get_owner(/** @type {ProxyMetadata} */ (metadata.parent)) ); } /** * @param {ProxyMetadata} metadata */ function check_ownership(metadata) { const component = get_component(); if (component && !has_owner(metadata, component)) { let original = get_owner(metadata); // @ts-expect-error if (original[FILENAME] !== component[FILENAME]) { // @ts-expect-error ownership_invalid_mutation(component[FILENAME], original[FILENAME]); } else { ownership_invalid_mutation(); } } } /** @import { ComponentContext, Derived, Effect, Reaction, Signal, Source, Value } from '#client' */ // Used for DEV time error handling /** @param {WeakSet<Error>} value */ const handled_errors = new WeakSet(); // Used for handling scheduling let is_micro_task_queued = false; let is_flushing_effect = false; /** @param {boolean} value */ function set_is_flushing_effect(value) { is_flushing_effect = value; } // Handle effect queues /** @type {Effect[]} */ let queued_root_effects = []; let flush_count = 0; /** @type {Effect[]} Stack of effects, dev only */ let dev_effect_stack = []; // Handle signal reactivity tree dependencies and reactions /** @type {null | Reaction} */ let active_reaction = null; /** @param {null | Reaction} reaction */ function set_active_reaction(reaction) { active_reaction = reaction; } /** @type {null | Effect} */ let active_effect = null; /** @param {null | Effect} effect */ function set_active_effect(effect) { active_effect = effect; } /** * When sources are created within a derived, we record them so that we can safely allow * local mutations to these sources without the side-effect error being invoked unnecessarily. * @type {null | Source[]} */ let derived_sources = null; /** * @param {Source[] | null} sources */ function set_derived_sources(sources) { derived_sources = sources; } /** * The dependencies of the reaction that is currently being executed. In many cases, * the dependencies are unchanged between runs, and so this will be `null` unless * and until a new dependency is accessed — we track this via `skipped_deps` * @type {null | Value[]} */ let new_deps = null; let skipped_deps = 0; /** * Tracks writes that the effect it's executed in doesn't listen to yet, * so that the dependency can be added to the effect later on if it then reads it * @type {null | Source[]} */ let untracked_writes = null; /** @param {null | Source[]} value */ function set_untracked_writes(value) { untracked_writes = value; } /** @type {number} Used by sources and deriveds for handling updates to unowned deriveds */ let current_version = 0; // If we are working with a get() chain that has no active container, // to prevent memory leaks, we skip adding the reaction. let skip_reaction = false; // Handling runtime component context /** @type {ComponentContext | null} */ let component_context = null; /** * The current component function. Different from current component context: * ```html * <!-- App.svelte --> * <Foo> * <Bar /> <!-- context == Foo.svelte, function == App.svelte --> * </Foo> * ``` * @type {ComponentContext['function']} */ let dev_current_component_function = null; function increment_version() { return ++current_version; } /** @returns {boolean} */ function is_runes() { return !legacy_mode_flag; } /** * Determines whether a derived or effect is dirty. * If it is MAYBE_DIRTY, will set the status to CLEAN * @param {Reaction} reaction * @returns {boolean} */ function check_dirtiness(reaction) { var flags = reaction.f; if ((flags & DIRTY) !== 0) { return true; } if ((flags & MAYBE_DIRTY) !== 0) { var dependencies = reaction.deps; var is_unowned = (flags & UNOWNED) !== 0; if (dependencies !== null) { var i; if ((flags & DISCONNECTED) !== 0) { for (i = 0; i < dependencies.length; i++) { (dependencies[i].reactions ??= []).push(reaction); } reaction.f ^= DISCONNECTED; } for (i = 0; i < dependencies.length; i++) { var dependency = dependencies[i]; if (check_dirtiness(/** @type {Derived} */ (dependency))) { update_derived(/** @type {Derived} */ (dependency)); } // If we are working with an unowned signal as part of an effect (due to !skip_reaction) // and the version hasn't changed, we still need to check that this reaction // is linked to the dependency source – otherwise future updates will not be caught. if ( is_unowned && active_effect !== null && !skip_reaction && !dependency?.reactions?.includes(reaction) ) { (dependency.reactions ??= []).push(reaction); } if (dependency.version > reaction.version) { return true; } } } // Unowned signals should never be marked as clean. if (!is_unowned) { set_signal_status(reaction, CLEAN); } } return false; } /** * @param {Error} error * @param {Effect} effect * @param {ComponentContext | null} component_context */ function handle_error(error, effect, component_context) { // Given we don't yet have error boundaries, we will just always throw. if (!DEV || handled_errors.has(error) || component_context === null) { throw error; } const component_stack = []; const effect_name = effect.fn?.name; if (effect_name) { component_stack.push(effect_name); } /** @type {ComponentContext | null} */ let current_context = component_context; while (current_context !== null) { if (DEV) { /** @type {string} */ var filename = current_context.function?.[FILENAME]; if (filename) { const file = filename.split('/').pop(); component_stack.push(file); } } current_context = current_context.p; } const indent = /Firefox/.test(navigator.userAgent) ? ' ' : '\t'; define_property(error, 'message', { value: error.message + `\n${component_stack.map((name) => `\n${indent}in ${name}`).join('')}\n` }); const stack = error.stack; // Filter out internal files from callstack if (stack) { const lines = stack.split('\n'); const new_lines = []; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.includes('svelte/src/internal')) { continue; } new_lines.push(line); } define_property(error, 'stack', { value: error.stack + new_lines.join('\n') }); } handled_errors.add(error); throw error; } /** * @template V * @param {Reaction} reaction * @returns {V} */ function update_reaction(reaction) { var previous_deps = new_deps; var previous_skipped_deps = skipped_deps; var previous_untracked_writes = untracked_writes; var previous_reaction = active_reaction; var previous_skip_reaction = skip_reaction; var prev_derived_sources = derived_sources; var previous_component_context = component_context; var flags = reaction.f; new_deps = /** @type {null | Value[]} */ (null); skipped_deps = 0; untracked_writes = null; active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; skip_reaction = !is_flushing_effect && (flags & UNOWNED) !== 0; derived_sources = null; component_context = reaction.ctx; try { var result = /** @type {Function} */ (0, reaction.fn)(); var deps = reaction.deps; if (new_deps !== null) { var i; remove_reactions(reaction, skipped_deps); if (deps !== null && skipped_deps > 0) { deps.length = skipped_deps + new_deps.length; for (i = 0; i < new_deps.length; i++) { deps[skipped_deps + i] = new_deps[i]; } } else { reaction.deps = deps = new_deps; } if (!skip_reaction) { for (i = skipped_deps; i < deps.length; i++) { (deps[i].reactions ??= []).push(reaction); } } } else if (deps !== null && skipped_deps < deps.length) { remove_reactions(reaction, skipped_deps); deps.length = skipped_deps; } return result; } finally { new_deps = previous_deps; skipped_deps = previous_skipped_deps; untracked_writes = previous_untracked_writes; active_reaction = previous_reaction; skip_reaction = previous_skip_reaction; derived_sources = prev_derived_sources; component_context = previous_component_context; } } /** * @template V * @param {Reaction} signal * @param {Value<V>} dependency * @returns {void} */ function remove_reaction(signal, dependency) { let reactions = dependency.reactions; if (reactions !== null) { var index = reactions.indexOf(signal); if (index !== -1) { var new_length = reactions.length - 1; if (new_length === 0) { reactions = dependency.reactions = null; } else { // Swap with last element and then remove. reactions[index] = reactions[new_length]; reactions.pop(); } } } // If the derived has no reactions, then we can disconnect it from the graph, // allowing it to either reconnect in the future, or be GC'd by the VM. if ( reactions === null && (dependency.f & DERIVED) !== 0 && // Destroying a child effect while updating a parent effect can cause a dependency to appear // to be unused, when in fact it is used by the currently-updating parent. Checking `new_deps` // allows us to skip the expensive work of disconnecting and immediately reconnecting it (new_deps === null || !new_deps.includes(dependency)) ) { set_signal_status(dependency, MAYBE_DIRTY); // If we are working with a derived that is owned by an effect, then mark it as being // disconnected. if ((dependency.f & (UNOWNED | DISCONNECTED)) === 0) { dependency.f ^= DISCONNECTED; } remove_reactions(/** @type {Derived} **/ (dependency), 0); } } /** * @param {Reaction} signal * @param {number} start_index * @returns {void} */ function remove_reactions(signal, start_index) { var dependencies = signal.deps; if (dependencies === null) return; for (var i = start_index; i < dependencies.length; i++) { remove_reaction(signal, dependencies[i]); } } /** * @param {Effect} effect * @returns {void} */ function update_effect(effect) { var flags = effect.f; if ((flags & DESTROYED) !== 0) { return; } set_signal_status(effect, CLEAN); var previous_effect = active_effect; var previous_component_context = component_context; active_effect = effect; if (DEV) { var previous_component_fn = dev_current_component_function; dev_current_component_function = effect.component_function; } try { if ((flags & BLOCK_EFFECT) !== 0) { destroy_block_effect_children(effect); } else { destroy_effect_children(effect); } destroy_effect_deriveds(effect); execute_effect_teardown(effect); var teardown = update_reaction(effect); effect.teardown = typeof teardown === 'function' ? teardown : null; effect.version = current_version; if (DEV) { dev_effect_stack.push(effect); } } catch (error) { handle_error(/** @type {Error} */ (error), effect, previous_component_context); } finally { active_effect = previous_effect; if (DEV) { dev_current_component_function = previous_component_fn; } } } function infinite_loop_guard() { if (flush_count > 1000) { flush_count = 0; if (DEV) { try { effect_update_depth_exceeded(); } catch (error) { // stack is garbage, ignore. Instead add a console.error message. define_property(error, 'stack', { value: '' }); // eslint-disable-next-line no-console console.error( 'Last ten effects were: ', dev_effect_stack.slice(-10).map((d) => d.fn) ); dev_effect_stack = []; throw error; } } else { effect_update_depth_exceeded(); } } flush_count++; } /** * @param {Array<Effect>} root_effects * @returns {void} */ function flush_queued_root_effects(root_effects) { var length = root_effects.length; if (length === 0) { return; } infinite_loop_guard(); var previously_flushing_effect = is_flushing_effect; is_flushing_effect = true; try { for (var i = 0; i < length; i++) { var effect = root_effects[i]; if ((effect.f & CLEAN) === 0) { effect.f ^= CLEAN; } /** @type {Effect[]} */ var collected_effects = []; process_effects(effect, collected_effects); flush_queued_effects(collected_effects); } } finally { is_flushing_effect = previously_flushing_effect; } } /** * @param {Array<Effect>} effects * @returns {void} */ function flush_queued_effects(effects) { var length = effects.length; if (length === 0) return; for (var i = 0; i < length; i++) { var effect = effects[i]; if ((effect.f & (DESTROYED | INERT)) === 0 && check_dirtiness(effect)) { update_effect(effect); // Effects with no dependencies or teardown do not get added to the effect tree. // Deferred effects (e.g. `$effect(...)`) _are_ added to the tree because we // don't know if we need to keep them until they are executed. Doing the check // here (rather than in `update_effect`) allows us to skip the work for // immediate effects. if (effect.deps === null && effect.first === null && effect.nodes_start === null) { if (effect.teardown === null) { // remove this effect from the graph unlink_effect(effect); } else { // keep the effect in the graph, but free up some memory effect.fn = null; } } } } } function process_deferred() { is_micro_task_queued = false; if (flush_count > 1001) { return; } const previous_queued_root_effects = queued_root_effects; queued_root_effects = []; flush_queued_root_effects(previous_queued_root_effects); if (!is_micro_task_queued) { flush_count = 0; if (DEV) { dev_effect_stack = []; } } } /** * @param {Effect} signal * @returns {void} */ function schedule_effect(signal) { { if (!is_micro_task_queued) { is_micro_task_queued = true; queueMicrotask(process_deferred); } } var effect = signal; while (effect.parent !== null) { effect = effect.parent; var flags = effect.f; if ((flags & (ROOT_EFFECT | BRANCH_EFFECT)) !== 0) { if ((flags & CLEAN) === 0) return; effect.f ^= CLEAN; } } queued_root_effects.push(effect); } /** * * This function both runs render effects and collects user effects in topological order * from the starting effect passed in. Effects will be collected when they match the filtered * bitwise flag passed in only. The collected effects array will be populated with all the user * effects to be flushed. * * @param {Effect} effect * @param {Effect[]} collected_effects * @returns {void} */ function process_effects(effect, collected_effects) { var current_effect = effect.first; var effects = []; main_loop: while (current_effect !== null) { var flags = current_effect.f; var is_branch = (flags & BRANCH_EFFECT) !== 0; var is_skippable_branch = is_branch && (flags & CLEAN) !== 0; if (!is_skippable_branch && (flags & INERT) === 0) { if ((flags & RENDER_EFFECT) !== 0) { if (is_branch) { current_effect.f ^= CLEAN; } else if (check_dirtiness(current_effect)) { update_effect(current_effect); } var child = current_effect.first; if (child !== null) { current_effect = child; continue; } } else if ((flags & EFFECT) !== 0) { effects.push(current_effect); } } var sibling = current_effect.next; if (sibling === null) { let parent = current_effect.parent; while (parent !== null) { if (effect === parent) { break main_loop; } var parent_sibling = parent.next; if (parent_sibling !== null) { current_effect = parent_sibling; continue main_loop; } parent = parent.parent; } } current_effect = sibling; } // We might be dealing with many effects here, far more than can be spread into // an array push call (callstack overflow). So let's deal with each effect in a loop. for (var i = 0; i < effects.length; i++) { child = effects[i]; collected_effects.push(child); process_effects(child, collected_effects); } } /** * @template V * @param {Value<V>} signal * @returns {V} */ function get(signal) { var flags = signal.f; var is_derived = (flags & DERIVED) !== 0; // If the derived is destroyed, just execute it again without retaining // its memoisation properties as the derived is stale if (is_derived && (flags & DESTROYED) !== 0) { var value = execute_derived(/** @type {Derived} */ (signal)); // Ensure the derived remains destroyed destroy_derived(/** @type {Derived} */ (signal)); return value; } // Register the dependency on the current reaction signal. if (active_reaction !== null) { if (derived_sources !== null && derived_sources.includes(signal)) { state_unsafe_local_read(); } var deps = active_reaction.deps; // If the signal is accessing the same dependencies in the same // order as it did last time, increment `skipped_deps` // rather than updating `new_deps`, which creates GC cost if (new_deps === null && deps !== null && deps[skipped_deps] === signal) { skipped_deps++; } else if (new_deps === null) { new_deps = [signal]; } else { new_deps.push(signal); } if ( untracked_writes !== null && active_effect !== null && (active_effect.f & CLEAN) !== 0 && (active_effect.f & BRANCH_EFFECT) === 0 && untracked_writes.includes(signal) ) { set_signal_status(active_effect, DIRTY); schedule_effect(active_effect); } } else if (is_derived && /** @type {Derived} */ (signal).deps === null) { var derived = /** @type {Derived} */ (signal); var parent = derived.parent; var target = derived; while (parent !== null) { // Attach the derived to the nearest parent effect, if there are deriveds // in between then we also need to attach them too if ((parent.f & DERIVED) !== 0) { var parent_derived = /** @type {Derived} */ (parent); target = parent_derived; parent = parent_derived.parent; } else { var parent_effect = /** @type {Effect} */ (parent); if (!parent_effect.deriveds?.includes(target)) { (parent_effect.deriveds ??= []).push(target); } break; } } } if (is_derived) { derived = /** @type {Derived} */ (signal); if (check_dirtiness(derived)) { update_derived(derived); } } return signal.v; } const STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN); /** * @param {Signal} signal * @param {number} status * @returns {void} */ function set_signal_status(signal, status) { signal.f = (signal.f & STATUS_MASK) | status; } /** * @param {Record<string, unknown>} props * @param {any} runes * @param {Function} [fn] * @returns {void} */ function push(props, runes = false, fn) { component_context = { p: component_context, c: null, e: null, m: false, s: props, x: null, l: