UNPKG

inline-style-editor

Version:

Update CSS rules or add inline style to elements visualy

2,048 lines (1,736 loc) 178 kB
var DEV = false; // 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 index_of = Array.prototype.indexOf; var array_from = Array.from; var define_property = Object.defineProperty; var get_descriptor = Object.getOwnPropertyDescriptor; var get_descriptors = Object.getOwnPropertyDescriptors; var object_prototype = Object.prototype; var array_prototype = Array.prototype; var get_prototype_of = Object.getPrototypeOf; var is_extensible = Object.isExtensible; /** @param {Array<() => void>} arr */ function run_all(arr) { for (var i = 0; i < arr.length; i++) { arr[i](); } } /** * When encountering a situation like `let [a, b, c] = $derived(blah())`, * we need to stash an intermediate value that `a`, `b`, and `c` derive * from, in case it's an iterable * @template T * @param {ArrayLike<T> | Iterable<T>} value * @param {number} [n] * @returns {Array<T>} */ function to_array(value, n) { // return arrays unchanged if (Array.isArray(value)) { return value; } // if value is not iterable, or `n` is unspecified (indicates a rest // element, which means we're not concerned about unbounded iterables) // convert to an array with `Array.from` if (!(Symbol.iterator in value)) { return Array.from(value); } // otherwise, populate an array with `n` values /** @type {T[]} */ const array = []; for (const element of value) { array.push(element); if (array.length === n) break; } return array; } 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 BOUNDARY_EFFECT = 1 << 7; const UNOWNED = 1 << 8; const DISCONNECTED = 1 << 9; const CLEAN = 1 << 10; const DIRTY = 1 << 11; const MAYBE_DIRTY = 1 << 12; const INERT = 1 << 13; const DESTROYED = 1 << 14; const EFFECT_RAN = 1 << 15; /** 'Transparent' effects do not create a transition boundary */ const EFFECT_TRANSPARENT = 1 << 16; const HEAD_EFFECT = 1 << 19; const EFFECT_HAS_DERIVED = 1 << 20; const EFFECT_IS_UPDATING = 1 << 21; const STATE_SYMBOL = Symbol('$state'); const LEGACY_PROPS = Symbol('legacy props'); const LOADING_ATTR_SYMBOL = Symbol(''); /** @import { Equals } from '#client' */ /** @type {Equals} */ function equals(value) { return value === this.v; } /** * @param {unknown} a * @param {unknown} b * @returns {boolean} */ function safe_not_equal(a, b) { return a != a ? b == b : a !== b || (a !== null && typeof a === 'object') || typeof a === 'function'; } /** @type {Equals} */ function safe_equals(value) { return !safe_not_equal(value, this.v); } /* This file is generated by scripts/process-messages/index.js. Do not edit! */ /** * `%rune%` cannot be used inside an effect cleanup function * @param {string} rune * @returns {never} */ function effect_in_teardown(rune) { { throw new Error(`https://svelte.dev/e/effect_in_teardown`); } } /** * Effect cannot be created inside a `$derived` value that was not itself created inside an effect * @returns {never} */ function effect_in_unowned_derived() { { throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`); } } /** * `%rune%` can only be used inside an effect (e.g. during component initialisation) * @param {string} rune * @returns {never} */ function effect_orphan(rune) { { throw new Error(`https://svelte.dev/e/effect_orphan`); } } /** * 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() { { throw new Error(`https://svelte.dev/e/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) { { throw new Error(`https://svelte.dev/e/props_invalid_value`); } } /** * Property descriptors defined on `$state` objects must contain `value` and always be `enumerable`, `configurable` and `writable`. * @returns {never} */ function state_descriptors_fixed() { { throw new Error(`https://svelte.dev/e/state_descriptors_fixed`); } } /** * Cannot set prototype of `$state` object * @returns {never} */ function state_prototype_fixed() { { throw new Error(`https://svelte.dev/e/state_prototype_fixed`); } } /** * 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() { { throw new Error(`https://svelte.dev/e/state_unsafe_mutation`); } } let tracing_mode_flag = false; const EACH_ITEM_REACTIVE = 1; const EACH_INDEX_REACTIVE = 1 << 1; /** See EachBlock interface metadata.is_controlled for an explanation what this is */ const EACH_IS_CONTROLLED = 1 << 2; const EACH_IS_ANIMATED = 1 << 3; const EACH_ITEM_IMMUTABLE = 1 << 4; const PROPS_IS_IMMUTABLE = 1; const PROPS_IS_UPDATED = 1 << 2; const PROPS_IS_BINDABLE = 1 << 3; const PROPS_IS_LAZY_INITIAL = 1 << 4; const TEMPLATE_FRAGMENT = 1; const TEMPLATE_USE_IMPORT_NODE = 1 << 1; const UNINITIALIZED = Symbol(); const NAMESPACE_HTML = 'http://www.w3.org/1999/xhtml'; /* This file is generated by scripts/process-messages/index.js. Do not edit! */ /** * `%name%(...)` can only be used during component initialisation * @param {string} name * @returns {never} */ function lifecycle_outside_component(name) { { throw new Error(`https://svelte.dev/e/lifecycle_outside_component`); } } /** @import { ComponentContext } from '#client' */ /** @type {ComponentContext | null} */ let component_context = null; /** @param {ComponentContext | null} context */ function set_component_context(context) { component_context = context; } /** * @param {Record<string, unknown>} props * @param {any} runes * @param {Function} [fn] * @returns {void} */ function push(props, runes = false, fn) { var ctx = (component_context = { p: component_context, c: null, d: false, e: null, m: false, s: props, x: null, l: null }); teardown(() => { /** @type {ComponentContext} */ (ctx).d = true; }); } /** * @template {Record<string, any>} T * @param {T} [component] * @returns {T} */ function pop(component) { const context_stack_item = component_context; if (context_stack_item !== null) { if (component !== undefined) { context_stack_item.x = component; } const component_effects = context_stack_item.e; if (component_effects !== null) { var previous_effect = active_effect; var previous_reaction = active_reaction; context_stack_item.e = null; try { for (var i = 0; i < component_effects.length; i++) { var component_effect = component_effects[i]; set_active_effect(component_effect.effect); set_active_reaction(component_effect.reaction); effect(component_effect.fn); } } finally { set_active_effect(previous_effect); set_active_reaction(previous_reaction); } } component_context = context_stack_item.p; context_stack_item.m = true; } // Micro-optimization: Don't set .a above to the empty object // so it can be garbage-collected when the return here is unused return component || /** @type {T} */ ({}); } /** @returns {boolean} */ function is_runes() { return true; } /** @import { Source } from '#client' */ /** * @template T * @param {T} value * @returns {T} */ function proxy(value) { // if non-proxyable, or is already a proxy, return `value` if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { return value; } const prototype = get_prototype_of(value); if (prototype !== object_prototype && prototype !== array_prototype) { return value; } /** @type {Map<any, Source<any>>} */ var sources = new Map(); var is_proxied_array = is_array(value); var version = state(0); var reaction = active_reaction; /** * @template T * @param {() => T} fn */ var with_parent = (fn) => { var previous_reaction = active_reaction; set_active_reaction(reaction); /** @type {T} */ var result = fn(); set_active_reaction(previous_reaction); return result; }; if (is_proxied_array) { // We need to create the length source eagerly to ensure that // mutations to the array are properly synced with our proxy sources.set('length', state(/** @type {any[]} */ (value).length)); } return new Proxy(/** @type {any} */ (value), { defineProperty(_, prop, descriptor) { if ( !('value' in descriptor) || descriptor.configurable === false || descriptor.enumerable === false || descriptor.writable === false ) { // we disallow non-basic descriptors, because unless they are applied to the // target object — which we avoid, so that state can be forked — we will run // afoul of the various invariants // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/getOwnPropertyDescriptor#invariants state_descriptors_fixed(); } var s = sources.get(prop); if (s === undefined) { s = with_parent(() => state(descriptor.value)); sources.set(prop, s); } else { set( s, with_parent(() => proxy(descriptor.value)) ); } return true; }, deleteProperty(target, prop) { var s = sources.get(prop); if (s === undefined) { if (prop in target) { sources.set( prop, with_parent(() => state(UNINITIALIZED)) ); update_version(version); } } else { // When working with arrays, we need to also ensure we update the length when removing // an indexed property if (is_proxied_array && typeof prop === 'string') { var ls = /** @type {Source<number>} */ (sources.get('length')); var n = Number(prop); if (Number.isInteger(n) && n < ls.v) { set(ls, n); } } set(s, UNINITIALIZED); update_version(version); } return true; }, get(target, prop, receiver) { if (prop === STATE_SYMBOL) { return value; } var s = sources.get(prop); var exists = prop in target; // create a source, but only if it's an own property and not a prototype property if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) { s = with_parent(() => state(proxy(exists ? target[prop] : UNINITIALIZED))); sources.set(prop, s); } if (s !== undefined) { var v = get(s); return v === UNINITIALIZED ? undefined : v; } return Reflect.get(target, prop, receiver); }, getOwnPropertyDescriptor(target, prop) { var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); if (descriptor && 'value' in descriptor) { var s = sources.get(prop); if (s) descriptor.value = get(s); } else if (descriptor === undefined) { var source = sources.get(prop); var value = source?.v; if (source !== undefined && value !== UNINITIALIZED) { return { enumerable: true, configurable: true, value, writable: true }; } } return descriptor; }, has(target, prop) { if (prop === STATE_SYMBOL) { return true; } var s = sources.get(prop); var has = (s !== undefined && s.v !== UNINITIALIZED) || Reflect.has(target, prop); if ( s !== undefined || (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { s = with_parent(() => state(has ? proxy(target[prop]) : UNINITIALIZED)); sources.set(prop, s); } var value = get(s); if (value === UNINITIALIZED) { return false; } } return has; }, set(target, prop, value, receiver) { var s = sources.get(prop); var has = prop in target; // variable.length = value -> clear all signals with index >= value if (is_proxied_array && prop === 'length') { for (var i = value; i < /** @type {Source<number>} */ (s).v; i += 1) { var other_s = sources.get(i + ''); if (other_s !== undefined) { set(other_s, UNINITIALIZED); } else if (i in target) { // If the item exists in the original, we need to create a uninitialized source, // else a later read of the property would result in a source being created with // the value of the original item at that index. other_s = with_parent(() => state(UNINITIALIZED)); sources.set(i + '', other_s); } } } // If we haven't yet created a source for this property, we need to ensure // we do so otherwise if we read it later, then the write won't be tracked and // the heuristics of effects will be different vs if we had read the proxied // object property before writing to that property. if (s === undefined) { if (!has || get_descriptor(target, prop)?.writable) { s = with_parent(() => state(undefined)); set( s, with_parent(() => proxy(value)) ); sources.set(prop, s); } } else { has = s.v !== UNINITIALIZED; set( s, with_parent(() => proxy(value)) ); } var descriptor = Reflect.getOwnPropertyDescriptor(target, prop); // Set the new value before updating any signals so that any listeners get the new value if (descriptor?.set) { descriptor.set.call(receiver, value); } if (!has) { // If we have mutated an array directly, we might need to // signal that length has also changed. Do it before updating metadata // to ensure that iterating over the array as a result of a metadata update // will not cause the length to be out of sync. if (is_proxied_array && typeof prop === 'string') { var ls = /** @type {Source<number>} */ (sources.get('length')); var n = Number(prop); if (Number.isInteger(n) && n >= ls.v) { set(ls, n + 1); } } update_version(version); } return true; }, ownKeys(target) { get(version); var own_keys = Reflect.ownKeys(target).filter((key) => { var source = sources.get(key); return source === undefined || source.v !== UNINITIALIZED; }); for (var [key, source] of sources) { if (source.v !== UNINITIALIZED && !(key in target)) { own_keys.push(key); } } return own_keys; }, setPrototypeOf() { state_prototype_fixed(); } }); } /** * @param {Source<number>} signal * @param {1 | -1} [d] */ function update_version(signal, d = 1) { set(signal, signal.v + d); } /** @import { Derived, Effect } from '#client' */ /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function derived(fn) { var flags = DERIVED | DIRTY; var parent_derived = active_reaction !== null && (active_reaction.f & DERIVED) !== 0 ? /** @type {Derived} */ (active_reaction) : null; if (active_effect === null || (parent_derived !== null && (parent_derived.f & UNOWNED) !== 0)) { 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; } /** @type {Derived<V>} */ const signal = { ctx: component_context, deps: null, effects: null, equals, f: flags, fn, reactions: null, rv: 0, v: /** @type {V} */ (null), wv: 0, parent: parent_derived ?? active_effect }; return signal; } /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function user_derived(fn) { const d = derived(fn); push_reaction_value(d); return d; } /** * @template V * @param {() => V} fn * @returns {Derived<V>} */ /*#__NO_SIDE_EFFECTS__*/ function derived_safe_equal(fn) { const signal = derived(fn); signal.equals = safe_equals; return signal; } /** * @param {Derived} derived * @returns {void} */ function destroy_derived_effects(derived) { var effects = derived.effects; if (effects !== null) { derived.effects = null; for (var i = 0; i < effects.length; i += 1) { destroy_effect(/** @type {Effect} */ (effects[i])); } } } /** * @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)); { try { destroy_derived_effects(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); if (!derived.equals(value)) { derived.v = value; derived.wv = increment_write_version(); } // don't mark derived clean if we're reading it inside a // cleanup function, or it will cache a stale value if (is_destroying_effect) return; var status = (skip_reaction || (derived.f & UNOWNED) !== 0) && derived.deps !== null ? MAYBE_DIRTY : CLEAN; set_signal_status(derived, status); } /** @import { Derived, Effect, Source, Value } from '#client' */ const old_values = new Map(); /** * @template V * @param {V} v * @param {Error | null} [stack] * @returns {Source<V>} */ // TODO rename this to `state` throughout the codebase function source(v, stack) { /** @type {Value} */ var signal = { f: 0, // TODO ideally we could skip this altogether, but it causes type errors v, reactions: null, equals, rv: 0, wv: 0 }; return signal; } /** * @template V * @param {V} v * @param {Error | null} [stack] */ /*#__NO_SIDE_EFFECTS__*/ function state(v, stack) { const s = source(v); push_reaction_value(s); return s; } /** * @template V * @param {V} initial_value * @param {boolean} [immutable] * @returns {Source<V>} */ /*#__NO_SIDE_EFFECTS__*/ function mutable_source(initial_value, immutable = false) { const s = source(initial_value); if (!immutable) { s.equals = safe_equals; } return s; } /** * @template V * @param {Source<V>} source * @param {V} value * @param {boolean} [should_proxy] * @returns {V} */ function set(source, value, should_proxy = false) { if ( active_reaction !== null && !untracking && is_runes() && (active_reaction.f & (DERIVED | BLOCK_EFFECT)) !== 0 && !reaction_sources?.includes(source) ) { state_unsafe_mutation(); } let new_value = should_proxy ? proxy(value) : value; return internal_set(source, new_value); } /** * @template V * @param {Source<V>} source * @param {V} value * @returns {V} */ function internal_set(source, value) { if (!source.equals(value)) { var old_value = source.v; if (is_destroying_effect) { old_values.set(source, value); } else { old_values.set(source, old_value); } source.v = value; if ((source.f & DERIVED) !== 0) { // if we are assigning to a dirty derived we set it to clean/maybe dirty but we also eagerly execute it to track the dependencies if ((source.f & DIRTY) !== 0) { execute_derived(/** @type {Derived} */ (source)); } set_signal_status(source, (source.f & UNOWNED) === 0 ? CLEAN : MAYBE_DIRTY); } source.wv = increment_write_version(); mark_reactions(source, DIRTY); // It's possible that the current reaction might not have up-to-date dependencies // whilst it's actively running. 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 | ROOT_EFFECT)) === 0 ) { if (untracked_writes === null) { set_untracked_writes([source]); } else { untracked_writes.push(source); } } } 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; 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 { TemplateNode } from '#client' */ /** * Use this variable to guard everything related to hydration code so it can be treeshaken out * if the user doesn't use the `hydrate` method and these code paths are therefore not needed. */ let hydrating = false; /** @import { TemplateNode } from '#client' */ // export these for reference in the compiled code, making global name deduplication unnecessary /** @type {Window} */ var $window; /** @type {boolean} */ var is_firefox; /** @type {() => Node | null} */ var first_child_getter; /** @type {() => Node | null} */ var next_sibling_getter; /** * Initialize these lazily to avoid issues when using the runtime in a server context * where these globals are not available while avoiding a separate server entry point */ function init_operations() { if ($window !== undefined) { return; } $window = window; is_firefox = /Firefox/.test(navigator.userAgent); var element_prototype = Element.prototype; var node_prototype = Node.prototype; var text_prototype = Text.prototype; // @ts-ignore first_child_getter = get_descriptor(node_prototype, 'firstChild').get; // @ts-ignore next_sibling_getter = get_descriptor(node_prototype, 'nextSibling').get; if (is_extensible(element_prototype)) { // the following assignments improve perf of lookups on DOM nodes // @ts-expect-error element_prototype.__click = undefined; // @ts-expect-error element_prototype.__className = undefined; // @ts-expect-error element_prototype.__attributes = null; // @ts-expect-error element_prototype.__style = undefined; // @ts-expect-error element_prototype.__e = undefined; } if (is_extensible(text_prototype)) { // @ts-expect-error text_prototype.__t = undefined; } } /** * @param {string} value * @returns {Text} */ function create_text(value = '') { return document.createTextNode(value); } /** * @template {Node} N * @param {N} node * @returns {Node | null} */ /*@__NO_SIDE_EFFECTS__*/ function get_first_child(node) { return first_child_getter.call(node); } /** * @template {Node} N * @param {N} node * @returns {Node | null} */ /*@__NO_SIDE_EFFECTS__*/ function get_next_sibling(node) { return next_sibling_getter.call(node); } /** * Don't mark this as side-effect-free, hydration needs to walk all nodes * @template {Node} N * @param {N} node * @param {boolean} is_text * @returns {Node | null} */ function child(node, is_text) { { return get_first_child(node); } } /** * Don't mark this as side-effect-free, hydration needs to walk all nodes * @param {DocumentFragment | TemplateNode[]} fragment * @param {boolean} is_text * @returns {Node | null} */ function first_child(fragment, is_text) { { // when not hydrating, `fragment` is a `DocumentFragment` (the result of calling `open_frag`) var first = /** @type {DocumentFragment} */ (get_first_child(/** @type {Node} */ (fragment))); // TODO prevent user comments with the empty string when preserveComments is true if (first instanceof Comment && first.data === '') return get_next_sibling(first); return first; } } /** * Don't mark this as side-effect-free, hydration needs to walk all nodes * @param {TemplateNode} node * @param {number} count * @param {boolean} is_text * @returns {Node | null} */ function sibling(node, count = 1, is_text = false) { let next_sibling = node; while (count--) { next_sibling = /** @type {TemplateNode} */ (get_next_sibling(next_sibling)); } { return next_sibling; } } /** * @template {Node} N * @param {N} node * @returns {void} */ function clear_text_content(node) { node.textContent = ''; } /** @import { ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */ /** * @param {'$effect' | '$effect.pre' | '$inspect'} rune */ function validate_effect(rune) { if (active_effect === null && active_reaction === null) { effect_orphan(); } if (active_reaction !== null && (active_reaction.f & UNOWNED) !== 0 && active_effect === null) { effect_in_unowned_derived(); } if (is_destroying_effect) { effect_in_teardown(); } } /** * @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 parent = active_effect; /** @type {Effect} */ var effect = { ctx: component_context, deps: null, nodes_start: null, nodes_end: null, f: type | DIRTY, first: null, fn, last: null, next: null, parent, prev: null, teardown: null, transitions: null, wv: 0 }; if (sync) { try { update_effect(effect); effect.f |= EFFECT_RAN; } catch (e) { destroy_effect(effect); throw e; } } 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 | BOUNDARY_EFFECT)) === 0; if (!inert && push) { if (parent !== null) { push_effect(effect, parent); } // 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.effects ??= []).push(effect); } } return effect; } /** * @param {() => void} fn */ function teardown(fn) { const effect = create_effect(RENDER_EFFECT, null, false); set_signal_status(effect, CLEAN); effect.teardown = fn; return effect; } /** * Internal representation of `$effect(...)` * @param {() => void | (() => void)} fn */ function user_effect(fn) { validate_effect(); // Non-nested `$effect(...)` in a component should be deferred // until the component is mounted var defer = active_effect !== null && (active_effect.f & BRANCH_EFFECT) !== 0 && component_context !== null && !component_context.m; if (defer) { var context = /** @type {ComponentContext} */ (component_context); (context.e ??= []).push({ fn, effect: active_effect, reaction: active_reaction }); } else { var signal = effect(fn); return signal; } } /** * An effect root whose children can transition out * @param {() => void} fn * @returns {(options?: { outro?: boolean }) => Promise<void>} */ 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} */ function effect(fn) { return create_effect(EFFECT, fn, false); } /** * @param {() => void | (() => void)} fn * @returns {Effect} */ function render_effect(fn) { return create_effect(RENDER_EFFECT, fn, true); } /** * @param {(...expressions: any) => void | (() => void)} fn * @param {Array<() => any>} thunks * @returns {Effect} */ function template_effect(fn, thunks = [], d = derived) { const deriveds = thunks.map(d); const effect = () => fn(...deriveds.map(get)); return block(effect); } /** * @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 previously_destroying_effect = is_destroying_effect; const previous_reaction = active_reaction; set_is_destroying_effect(true); set_active_reaction(null); try { teardown.call(null); } finally { set_is_destroying_effect(previously_destroying_effect); set_active_reaction(previous_reaction); } } } /** * @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; if ((effect.f & ROOT_EFFECT) !== 0) { // this is now an independent root effect.parent = null; } else { 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) { remove_effect_dom(effect.nodes_start, /** @type {TemplateNode} */ (effect.nodes_end)); removed = true; } destroy_effect_children(effect, remove_dom && !removed); 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); } // `first` and `child` are nulled out in destroy_effect_children // we don't null out `parent` so that error propagation can work correctly effect.next = effect.prev = effect.teardown = effect.ctx = effect.deps = effect.fn = effect.nodes_start = effect.nodes_end = null; } /** * * @param {TemplateNode | null} node * @param {TemplateNode} end */ function remove_effect_dom(node, end) { while (node !== null) { /** @type {TemplateNode | null} */ var next = node === end ? null : /** @type {TemplateNode} */ (get_next_sibling(node)); node.remove(); node = next; } } /** * 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; effect.f ^= INERT; // Ensure the effect is marked as clean again so that any dirty child // effects can schedule themselves for execution if ((effect.f & CLEAN) === 0) { effect.f ^= CLEAN; } // If a dependency of this effect changed while it was paused, // schedule the effect to update if (check_dirtiness(effect)) { set_signal_status(effect, DIRTY); schedule_effect(effect); } 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(); } } } } /** @type {Array<() => void>} */ let micro_tasks = []; /** @type {Array<() => void>} */ let idle_tasks = []; function run_micro_tasks() { var tasks = micro_tasks; micro_tasks = []; run_all(tasks); } function run_idle_tasks() { var tasks = idle_tasks; idle_tasks = []; run_all(tasks); } /** * @param {() => void} fn */ function queue_micro_task(fn) { if (micro_tasks.length === 0) { queueMicrotask(run_micro_tasks); } micro_tasks.push(fn); } /** * Synchronously run any queued tasks. */ function flush_tasks() { if (micro_tasks.length > 0) { run_micro_tasks(); } if (idle_tasks.length > 0) { run_idle_tasks(); } } /** @import { ComponentContext, Derived, Effect, Reaction, Signal, Source, Value } from '#client' */ let is_throwing_error = false; let is_flushing = false; /** @type {Effect | null} */ let last_scheduled_effect = null; let is_updating_effect = false; let is_destroying_effect = false; /** @param {boolean} value */ function set_is_destroying_effect(value) { is_destroying_effect = value; } // Handle effect queues /** @type {Effect[]} */ let queued_root_effects = []; /** @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; let untracking = false; /** @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 reaction, reading and writing * them should not cause a re-run * @type {null | Source[]} */ let reaction_sources = null; /** @param {Value} value */ function push_reaction_value(value) { if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) { if (reaction_sources === null) { reaction_sources = [value]; } else { reaction_sources.push(value); } } } /** * 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. * Version starts from 1 so that unowned deriveds differentiate between a created effect and a run one for tracing **/ let write_version = 1; /** @type {number} Used to version each read of a source of derived to avoid duplicating depedencies inside a reaction */ let read_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; function increment_write_version() { return ++write_version; } /** * 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; var dependency; var is_disconnected = (flags & DISCONNECTED) !== 0; var is_unowned_connected = is_unowned && active_effect !== null && !skip_reaction; var length = dependencies.length; // If we are working with a disconnected or an unowned signal that is now connected (due to an active effect) // then we need to re-connect the reaction to the dependency if (is_disconnected || is_unowned_connected) { var derived = /** @type {Derived} */ (reaction); var parent = derived.parent; for (i = 0; i < length; i++) { dependency = dependencies[i]; // We always re-add all reactions (even duplicates) if the derived was // previously disconnected, however we don't if it was unowned as we // de-duplicate dependencies in that case if (is_disconnected || !dependency?.reactions?.includes(derived)) { (dependency.reactions ??= []).push(derived); } } if (is_disconnected) { derived.f ^= DISCONNECTED; } // If the unowned derived is now fully connected to the graph again (it's unowned and reconnected, has a parent // and the parent is not unowned), then we can mark it as connected again, removing the need for the unowned // flag if (is_unowned_connected && parent !== null && (parent.f & UNOWNED) === 0) { derived.f ^= UNOWNED; } } for (i = 0; i < length; i++) { dependency = dependencies[i]; if (check_dirtiness(/** @type {Derived} */ (dependency))) { update_derived(/** @type {Derived} */ (dependency)); } if (dependency.wv > reaction.wv) { return true; } } } // Unowned signals should never be marked as clean unless they // are used within an active_effect without skip_reaction if (!is_unowned || (active_effect !== null && !skip_reaction)) { set_signal_status(reaction, CLEAN); } } return false; } /** * @param {unknown} error * @param {Effect} effect */ function propagate_error(error, effect) { /** @type {Effect | null} */ var current = effect; while (current !== null) { if ((current.f & BOUNDARY_EFFECT) !== 0) { try { // @ts-expect-error current.fn(error); return; } catch { // Remove boundary flag from effect current.f ^= BOUNDARY_EFFECT; } } current = current.parent; } is_throwing_error = false; throw error; } /** * @param {Effect} effect */ function should_rethrow_error(effect) { return ( (effect.f & DESTROYED) === 0 && (effect.parent === null || (effect.parent.f & BOUNDARY_EFFECT) === 0) ); } /** * @param {unknown} error * @param {Effect} effect * @param {Effect | null} previous_effect * @param {ComponentContext | null} component_context */ function handle_error(error, effect, previous_effect, component_context) { if (is_throwing_error) { if (previous_effect === null) { is_throwing_error = false; } if (should_rethrow_error(effect)) { throw error; } return; } if (previous_effect !== null) { is_throwing_error = true; } propagate_error(error, effect); if (should_rethrow_error(effect)) { throw error; } } /** * @param {Value} signal * @param {Effect} effect * @param {boolean} [root] */ function schedule_possible_effect_self_invalidation(signal, effect, root = true) { var reactions = signal.reactions; if (reactions === null) return; for (var i = 0; i < reactions.length; i++) { var reaction = reactions[i]; if (reaction_sources?.includes(signal)) continue; if ((reaction.f & DERIVED) !== 0) { schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false); } else if (effect === reaction) { if (root) { set_signal_status(reaction, DIRTY); } else if ((reaction.f & CLEAN) !== 0) { set_signal_status(reaction, MAYBE_DIRTY); } schedule_effect(/** @type {Effect} */ (reaction)); } } } /** * @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 previous_reaction_sources = reaction_sources; var previous_component_context = component_context; var previous_untracking = untracking; var flags = reaction.f; new_deps = /** @type {null | Value[]} */ (null); skipped_deps = 0; untracked_writes = null; skip_reaction = (flags & UNOWNED) !== 0 && (untracking || !is_updating_effect || active_reaction === null); active_reaction = (flags & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null; reaction_sources = null; set_component_context(reaction.ctx); untracking = false; read_version++; reaction.f |= EFFECT_IS_UPDATING; 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; } // If we're inside an effect and we have untracked writes, then we need to // ensure that if any of those untracked writes result in re-invalidation // of the current effect, then that happens accordingly if ( is_runes() && untracked_writes !== null && !untracking && deps !== null && (reaction.f & (DERIVED | MAYBE_DIRTY | DIRTY)) === 0 ) { for (i = 0; i < /** @type {Source[]} */ (untracked_writes).length; i++) { schedule_possible_effect_self_invalidation( untracked_writes[i], /** @type {Effect} */ (reaction) ); } } // If we are returning to an previous reaction then // we need to increment the read version to ensure that // any dependencies in this reaction aren't marked with // the same version if (previous_reaction !== null && previous_reaction !== reaction) { read_version++; if (untracked_writes !== null) { if (previous_untracked_writes === null) { previous_untracked_writes = untracked_writes; } else { previous_untracked_writes.push(.../** @type {Source[]} */ (untracked_writes)); } } } 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; reaction_sources = previous_reaction_sources; set_component_context(previous_component_context); untracking = previous_untracking; reaction.f ^= EFFECT_IS_UPDATING; } } /** * @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 = index_of.call(reactions, 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; } // Disconnect any reactions owned by this reaction destroy_derived_effects(/** @type {Derived} **/ (dependency)); 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; var was_updating_effect = is_updating_effect; active_effect = effect; is_updating_effect = true; try { if ((flags & BLOCK_EFFECT) !== 0) { destroy_block_effect_children(effect); } else { destroy_effect_children(effect); } execute_effect_teardown(effect); var teardown = update_reaction(effect); effect.teardown = typeof teardown === 'function' ? teardown : null; effect.wv = write_version; var deps = effect.deps; // In DEV, we need to handle a case where $inspect.trace() might // incorrectly state a source dependency has not changed when it has. // That's beacuse that source was changed by the same effect, causing // the versions to match. We can avoid this by incrementing the version var dep; if (DEV && tracing_mode_flag && (effect.f & DIRTY) !== 0 && deps !== null) ; if (DEV) ; } catch (error) { handle_error(error, effect, previous_effect, previous_component_context || effect.ctx); } finally { is_updating_effect = was_updating_effect; active_effect = previous_effect; } } function infinite_loop_guard() { try { effect_update_depth_exceeded(); } catch (error) { // Try and handle the error so it can be caught at a boundary, that's // if there's an effect available from when it was last scheduled if (last_scheduled_effect !== null) { { handle_error(error, last_scheduled_effect, null); } } else { throw error; } } } function flush_queued_root_effects() { var was_updating_effect = is_updating_effect; try { var flush_count = 0; is_updating_effect = true; while (queued_root_effects.length > 0) { if (flush_count++ > 1000) { infinite_loop_guard(); } var root_effects = queued_root_effects; var length = root_effects.length; queued_root_effects = []; for (var i = 0; i < length; i++)