diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 6f956a230d..265b09591c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -1282,6 +1282,12 @@ function create_block(parent, name, nodes, context) { // It's important that close is the last statement in the block, as any previous statements // could contain element insertions into the template, which the close statement needs to // know of when constructing the list of current inner elements. + + if (context.path.length > 0) { + // this is a block — return DOM so it can be attached directly to the effect + close = b.return(close.expression); + } + body.push(close); } diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index d6820c058f..5dcf52d914 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -2,7 +2,6 @@ import { is_promise } from '../../../common.js'; import { hydrate_block_anchor } from '../hydration.js'; import { remove } from '../reconciler.js'; import { - current_block, current_component_context, flushSync, set_current_component_context, @@ -11,20 +10,7 @@ import { } from '../../runtime.js'; import { destroy_effect, pause_effect, render_effect } from '../../reactivity/effects.js'; import { DESTROYED, INERT } from '../../constants.js'; - -/** @returns {import('../../types.js').AwaitBlock} */ -export function create_await_block() { - return { - // dom - d: null, - // effect - e: null, - // parent - p: /** @type {import('../../types.js').Block} */ (current_block), - // pending - n: true - }; -} +import { create_block } from './utils.js'; /** * @template V @@ -36,7 +22,7 @@ export function create_await_block() { * @returns {void} */ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { - const block = create_await_block(); + const block = create_block(); const component_context = current_component_context; diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index b815fdc8b0..bc0f035378 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -15,7 +15,7 @@ import { } from '../hydration.js'; import { empty } from '../operations.js'; import { insert, remove } from '../reconciler.js'; -import { current_block, untrack } from '../../runtime.js'; +import { untrack } from '../../runtime.js'; import { destroy_effect, pause_effect, @@ -26,6 +26,7 @@ import { import { source, mutable_source, set } from '../../reactivity/sources.js'; import { is_array, is_frozen, map_get, map_set } from '../../utils.js'; import { STATE_SYMBOL } from '../../constants.js'; +import { create_block } from './utils.js'; var NEW_BLOCK = -1; var LIS_BLOCK = -2; @@ -33,11 +34,11 @@ var LIS_BLOCK = -2; /** * The row of a keyed each block that is currently updating. We track this * so that `animate:` directives have something to attach themselves to - * @type {import('#client').EachItemBlock | null} + * @type {import('#client').EachItem | null} */ export let current_each_item_block = null; -/** @param {import('#client').EachItemBlock | null} block */ +/** @param {import('#client').EachItem | null} block */ export function set_current_each_item_block(block) { current_each_item_block = block; } @@ -54,18 +55,10 @@ export function set_current_each_item_block(block) { * @returns {void} */ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, reconcile_fn) { - /** @type {import('#client').EachBlock} */ - var block = { - // dom - d: null, - // flags - f: flags, - // items - v: [], - // effect - e: null, - p: /** @type {import('#client').Block} */ (current_block) - }; + var block = create_block(); + + /** @type {import('#client').EachState} */ + var state = { flags, items: [] }; var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; hydrate_block_anchor(is_controlled ? /** @type {Node} */ (anchor.firstChild) : anchor); @@ -94,7 +87,7 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re // If we are working with an array that isn't proxied or frozen, then remove strict equality and ensure the items // are treated as reactive, so they get wrapped in a signal. - var flags = block.f; + var flags = state.flags; if ((flags & EACH_IS_STRICT_EQUALS) !== 0 && !is_frozen(array) && !(STATE_SYMBOL in array)) { flags ^= EACH_IS_STRICT_EQUALS; @@ -142,7 +135,7 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re break; } - b_blocks[i] = create_block(array[i], keys?.[i], i, render_fn, flags); + b_blocks[i] = create_item(array[i], keys?.[i], i, render_fn, flags); // TODO helperise this hydrating_node = /** @type {import('#client').TemplateNode} */ ( @@ -154,12 +147,12 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re remove_excess_hydration_nodes(hydration_list, hydrating_node); - block.v = b_blocks; + state.items = b_blocks; } if (!hydrating) { // TODO add 'empty controlled block' optimisation here - reconcile_fn(array, block, anchor, render_fn, flags, keys); + reconcile_fn(array, state, anchor, render_fn, flags, keys); } if (fallback_fn !== null) { @@ -200,17 +193,15 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re ); effect.ondestroy = () => { - for (var b of block.v) { - if (b.d !== null) { - destroy_effect(b.e); - remove(b.d); + for (var item of state.items) { + if (item.d !== null) { + destroy_effect(item.e); + remove(item.d); } } if (fallback) destroy_effect(fallback); }; - - block.e = effect; } /** @@ -243,55 +234,55 @@ export function each_indexed(anchor, get_collection, flags, render_fn, fallback_ /** * @template V * @param {Array} array - * @param {import('#client').EachBlock} each_block + * @param {import('#client').EachState} state * @param {Element | Comment | Text} anchor * @param {(anchor: null, item: V, index: number | import('#client').Source) => void} render_fn * @param {number} flags * @returns {void} */ -function reconcile_indexed_array(array, each_block, anchor, render_fn, flags) { - var a_blocks = each_block.v; +function reconcile_indexed_array(array, state, anchor, render_fn, flags) { + var a_items = state.items; - var a = a_blocks.length; + var a = a_items.length; var b = array.length; var min = Math.min(a, b); - /** @type {typeof a_blocks} */ - var b_blocks = Array(b); + /** @type {typeof a_items} */ + var b_items = Array(b); - var block; var item; + var value; // update items for (var i = 0; i < min; i += 1) { - item = array[i]; - block = a_blocks[i]; - b_blocks[i] = block; - update_block(block, item, i, flags); - resume_effect(block.e); + value = array[i]; + item = a_items[i]; + b_items[i] = item; + update_item(item, value, i, flags); + resume_effect(item.e); } if (b > a) { // add items for (; i < b; i += 1) { - item = array[i]; - block = create_block(item, null, i, render_fn, flags); - b_blocks[i] = block; - insert_block(block, anchor); + value = array[i]; + item = create_item(value, null, i, render_fn, flags); + b_items[i] = item; + insert_item(item, anchor); } - each_block.v = b_blocks; + state.items = b_items; } else if (a > b) { // remove items var remaining = a - b; var clear = () => { for (var i = b; i < a; i += 1) { - var block = a_blocks[i]; + var block = a_items[i]; if (block.d) remove(block.d); } - each_block.v = each_block.v.slice(0, b); + state.items.length = b; }; var check = () => { @@ -301,7 +292,7 @@ function reconcile_indexed_array(array, each_block, anchor, render_fn, flags) { }; for (; i < a; i += 1) { - pause_effect(a_blocks[i].e, check); + pause_effect(a_items[i].e, check); } } } @@ -312,20 +303,20 @@ function reconcile_indexed_array(array, each_block, anchor, render_fn, flags) { * https://github.com/localvoid/ivi/blob/9f1bd0918f487da5b131941228604763c5d8ef56/packages/ivi/src/client/core.ts#L968 * @template V * @param {Array} array - * @param {import('#client').EachBlock} each_block + * @param {import('#client').EachState} state * @param {Element | Comment | Text} anchor * @param {(anchor: null, item: V, index: number | import('#client').Source) => void} render_fn * @param {number} flags * @param {any[]} keys * @returns {void} */ -function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, keys) { - var a_blocks = each_block.v; +function reconcile_tracked_array(array, state, anchor, render_fn, flags, keys) { + var a_blocks = state.items; var a = a_blocks.length; var b = array.length; - /** @type {Array} */ + /** @type {Array} */ var b_blocks = Array(b); var is_animated = (flags & EACH_IS_ANIMATED) !== 0; @@ -333,7 +324,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke var start = 0; var block; - /** @type {Array} */ + /** @type {Array} */ var to_destroy = []; // Step 1 — trim common suffix @@ -344,7 +335,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke resume_effect(block.e); if (should_update) { - update_block(block, array[b], b, flags); + update_item(block, array[b], b, flags); } } @@ -355,7 +346,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke resume_effect(block.e); if (should_update) { - update_block(block, array[start], start, flags); + update_item(block, array[start], start, flags); } start += 1; @@ -365,9 +356,9 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke if (start === a) { // add only while (start < b) { - block = create_block(array[start], keys[start], start, render_fn, flags); + block = create_item(array[start], keys[start], start, render_fn, flags); b_blocks[start++] = block; - insert_block(block, anchor); + insert_item(block, anchor); } } else if (start === b) { // remove only @@ -390,7 +381,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke map_set(indexes, keys[i], i); } - /** @type {Array} */ + /** @type {Array} */ var to_animate = []; if (is_animated) { // for all blocks that were in both the old and the new list, @@ -439,17 +430,17 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke var insert = index === NEW_BLOCK; if (insert) { - block = create_block(array[b], keys[b], b, render_fn, flags); + block = create_item(array[b], keys[b], b, render_fn, flags); } else { block = b_blocks[b]; if (should_update) { - update_block(block, array[b], b, flags); + update_item(block, array[b], b, flags); } } if (insert || (moved && index !== LIS_BLOCK)) { last_sibling = last_block === undefined ? anchor : get_first_child(last_block); - anchor = insert_block(block, last_sibling); + anchor = insert_item(block, last_sibling); } last_block = b_blocks[b] = block; @@ -477,7 +468,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke if (block.d) remove(block.d); } - each_block.v = b_blocks; + state.items = b_blocks; }; var check = () => { @@ -490,7 +481,7 @@ function reconcile_tracked_array(array, each_block, anchor, render_fn, flags, ke pause_effect(block.e, check); } } else { - each_block.v = b_blocks; + state.items = b_blocks; } } @@ -582,17 +573,17 @@ function mark_lis(a) { } /** - * @param {import('#client').Block} block + * @param {import('#client').EachItem} block * @param {Text | Element | Comment} sibling * @returns {Text | Element | Comment} */ -function insert_block(block, sibling) { +function insert_item(block, sibling) { var current = /** @type {import('#client').TemplateNode} */ (block.d); return insert(current, sibling); } /** - * @param {import('#client').Block} block + * @param {import('#client').EachItem} block * @returns {Text | Element | Comment} */ function get_first_child(block) { @@ -606,13 +597,13 @@ function get_first_child(block) { } /** - * @param {import('#client').EachItemBlock} block + * @param {import('#client').EachItem} block * @param {any} item * @param {number} index * @param {number} type * @returns {void} */ -function update_block(block, item, index, type) { +function update_item(block, item, index, type) { if ((type & EACH_ITEM_REACTIVE) !== 0) { set(block.v, item); } @@ -631,9 +622,9 @@ function update_block(block, item, index, type) { * @param {number} index * @param {(anchor: null, item: V, index: number | import('#client').Value) => void} render_fn * @param {number} flags - * @returns {import('#client').EachItemBlock} + * @returns {import('#client').EachItem} */ -function create_block(item, key, index, render_fn, flags) { +function create_item(item, key, index, render_fn, flags) { var each_item_not_reactive = (flags & EACH_ITEM_REACTIVE) === 0; var item_value = each_item_not_reactive @@ -642,7 +633,7 @@ function create_block(item, key, index, render_fn, flags) { ? source(item) : mutable_source(item); - /** @type {import('#client').EachItemBlock} */ + /** @type {import('#client').EachItem} */ var block = { a: null, // dom diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index 729fc862d2..e03c4dc5af 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -6,46 +6,32 @@ import { set_current_hydration_fragment } from '../hydration.js'; import { remove } from '../reconciler.js'; -import { current_block } from '../../runtime.js'; import { destroy_effect, pause_effect, render_effect, resume_effect } from '../../reactivity/effects.js'; - -/** @returns {import('#client').IfBlock} */ -function create_if_block() { - return { - // dom - d: null, - // effect - e: null, - // parent - p: /** @type {import('#client').Block} */ (current_block), - // value - v: false - }; -} +import { create_block } from './utils.js'; /** * @param {Comment} anchor * @param {() => boolean} get_condition - * @param {(anchor: Node) => void} consequent_fn - * @param {null | ((anchor: Node) => void)} alternate_fn + * @param {(anchor: Node) => import('#client').TemplateNode | import('#client').TemplateNode[]} consequent_fn + * @param {null | ((anchor: Node) => import('#client').TemplateNode | import('#client').TemplateNode[])} alternate_fn * @param {boolean} [elseif] True if this is an `{:else if ...}` block rather than an `{#if ...}`, as that affects which transitions are considered 'local' * @returns {void} */ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, elseif = false) { - const block = create_if_block(); + const block = create_block(); hydrate_block_anchor(anchor); - /** @type {null | import('#client').TemplateNode | Array} */ - let consequent_dom = null; + /** @type {undefined | import('#client').TemplateNode | Array} */ + let consequent_dom; - /** @type {null | import('#client').TemplateNode | Array} */ - let alternate_dom = null; + /** @type {undefined | import('#client').TemplateNode | Array} */ + let alternate_dom; /** @type {import('#client').Effect | null} */ let consequent_effect = null; @@ -87,15 +73,14 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els } else { consequent_effect = render_effect( () => { - consequent_fn(anchor); - consequent_dom = block.d; + consequent_dom = consequent_fn(anchor); return () => { // TODO make this unnecessary by linking the dom to the effect, // and removing automatically on teardown - if (consequent_dom !== null) { + if (consequent_dom !== undefined) { remove(consequent_dom); - consequent_dom = null; + consequent_dom = undefined; } }; }, @@ -116,15 +101,14 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els } else if (alternate_fn) { alternate_effect = render_effect( () => { - alternate_fn(anchor); - alternate_dom = block.d; + alternate_dom = alternate_fn(anchor); return () => { // TODO make this unnecessary by linking the dom to the effect, // and removing automatically on teardown - if (alternate_dom !== null) { + if (alternate_dom !== undefined) { remove(alternate_dom); - alternate_dom = null; + alternate_dom = undefined; } }; }, @@ -154,21 +138,20 @@ export function if_block(anchor, get_condition, consequent_fn, alternate_fn, els if_effect.ondestroy = () => { // TODO make this unnecessary by linking the dom to the effect, // and removing automatically on teardown - if (consequent_dom !== null) { + if (consequent_dom !== undefined) { remove(consequent_dom); } - if (alternate_dom !== null) { + if (alternate_dom !== undefined) { remove(alternate_dom); } if (consequent_effect) { destroy_effect(consequent_effect); } + if (alternate_effect) { destroy_effect(alternate_effect); } }; - - block.e = if_effect; } diff --git a/packages/svelte/src/internal/client/dom/blocks/key.js b/packages/svelte/src/internal/client/dom/blocks/key.js index 7410c5b640..f7cb9c6dee 100644 --- a/packages/svelte/src/internal/client/dom/blocks/key.js +++ b/packages/svelte/src/internal/client/dom/blocks/key.js @@ -3,6 +3,7 @@ import { hydrate_block_anchor } from '../hydration.js'; import { remove } from '../reconciler.js'; import { pause_effect, render_effect } from '../../reactivity/effects.js'; import { safe_not_equal } from '../../reactivity/equality.js'; +import { create_block } from './utils.js'; /** * @template V @@ -12,7 +13,7 @@ import { safe_not_equal } from '../../reactivity/equality.js'; * @returns {void} */ export function key_block(anchor, get_key, render_fn) { - const block = {}; + const block = create_block(); hydrate_block_anchor(anchor); @@ -43,7 +44,6 @@ export function key_block(anchor, get_key, render_fn) { () => { render_fn(anchor); - // @ts-expect-error TODO this should be unnecessary const dom = block.d; return () => { diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index 27d3011668..ac45cb6981 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -1,6 +1,7 @@ import { render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; -import { current_block, untrack } from '../../runtime.js'; +import { untrack } from '../../runtime.js'; +import { create_block } from './utils.js'; /** * @param {() => Function | null | undefined} get_snippet @@ -9,15 +10,7 @@ import { current_block, untrack } from '../../runtime.js'; * @returns {void} */ export function snippet(get_snippet, node, ...args) { - /** @type {import('#client').SnippetBlock} */ - const block = { - // dom - d: null, - // parent - p: /** @type {import('#client').Block} */ (current_block), - // effect - e: null - }; + const block = create_block(); render_effect(() => { // Only rerender when the snippet function itself changes, diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js index a99eb4ce43..86fc548f04 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-component.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-component.js @@ -1,6 +1,7 @@ import { hydrate_block_anchor } from '../hydration.js'; import { pause_effect, render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; +import { create_block } from './utils.js'; // TODO this is very similar to `key`, can we deduplicate? @@ -13,7 +14,7 @@ import { remove } from '../reconciler.js'; * @returns {void} */ export function component(anchor, get_component, render_fn) { - const block = {}; + const block = create_block(); hydrate_block_anchor(anchor); @@ -46,7 +47,6 @@ export function component(anchor, get_component, render_fn) { () => { render_fn(component); - // @ts-expect-error TODO this should be unnecessary const dom = block.d; return () => { diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index 8e63fcc61b..bfaa47e844 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -8,10 +8,11 @@ import { resume_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; -import { current_block } from '../../runtime.js'; import { is_array } from '../../utils.js'; import { set_should_intro } from '../../render.js'; import { current_each_item_block, set_current_each_item_block } from './each.js'; +import { create_block } from './utils.js'; +import { current_block } from '../../runtime.js'; /** * @param {import('#client').Block} block @@ -41,15 +42,8 @@ function swap_block_dom(block, from, to) { * @returns {void} */ export function element(anchor, get_tag, is_svg, render_fn) { - /** @type {import('#client').DynamicElementBlock} */ - const block = { - // dom - d: null, - // effect - e: null, - // parent - p: /** @type {import('#client').Block} */ (current_block) - }; + const parent_block = /** @type {import('#client').Block} */ (current_block); + const block = create_block(); hydrate_block_anchor(anchor); @@ -134,7 +128,7 @@ export function element(anchor, get_tag, is_svg, render_fn) { anchor.before(element); if (prev_element) { - swap_block_dom(block.p, prev_element, element); + swap_block_dom(parent_block, prev_element, element); prev_element.remove(); } }, @@ -161,6 +155,4 @@ export function element(anchor, get_tag, is_svg, render_fn) { destroy_effect(effect); } }; - - block.e = wrapper; } diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js index c0916e7a29..bf70cd3e98 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js @@ -7,22 +7,14 @@ import { import { empty } from '../operations.js'; import { render_effect } from '../../reactivity/effects.js'; import { remove } from '../reconciler.js'; -import { current_block } from '../../runtime.js'; +import { create_block } from './utils.js'; /** * @param {(anchor: Node | null) => void} render_fn * @returns {void} */ export function head(render_fn) { - /** @type {import('#client').HeadBlock} */ - const block = { - // dom - d: null, - // effect - e: null, - // parent - p: /** @type {import('#client').Block} */ (current_block) - }; + const block = create_block(); // The head function may be called after the first hydration pass and ssr comment nodes may still be present, // therefore we need to skip that when we detect that we're not in hydration mode. @@ -61,8 +53,6 @@ export function head(render_fn) { remove(current); } }; - - block.e = head_effect; } finally { if (is_hydrating) { set_current_hydration_fragment(previous_hydration_fragment); diff --git a/packages/svelte/src/internal/client/dom/blocks/utils.js b/packages/svelte/src/internal/client/dom/blocks/utils.js new file mode 100644 index 0000000000..f1214ab68c --- /dev/null +++ b/packages/svelte/src/internal/client/dom/blocks/utils.js @@ -0,0 +1,7 @@ +/** @returns {import('#client').Block} */ +export function create_block() { + return { + // dom + d: null + }; +} diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index 387089f262..8461122a69 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -77,7 +77,7 @@ const linear = (t) => t; * @param {(() => P) | null} get_params */ export function animation(element, get_fn, get_params) { - var block = /** @type {import('#client').EachItemBlock} */ (current_each_item_block); + var block = /** @type {import('#client').EachItem} */ (current_each_item_block); /** @type {DOMRect} */ var from; diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index 24a0ebb6e0..97a8652c7a 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -178,7 +178,7 @@ export function comment(anchor) { * @param {Element | Text} dom * @param {boolean} is_fragment * @param {null | Text | Comment | Element} anchor - * @returns {void} + * @returns {import('#client').TemplateNode | import('#client').TemplateNode[]} */ function close_template(dom, is_fragment, anchor) { /** @type {import('#client').TemplateNode | Array} */ @@ -193,22 +193,22 @@ function close_template(dom, is_fragment, anchor) { } /** @type {import('#client').Block} */ (current_block).d = current; + + return current; } /** * @param {null | Text | Comment | Element} anchor * @param {Element | Text} dom - * @returns {void} */ export function close(anchor, dom) { - close_template(dom, false, anchor); + return close_template(dom, false, anchor); } /** * @param {null | Text | Comment | Element} anchor * @param {Element | Text} dom - * @returns {void} */ export function close_frag(anchor, dom) { - close_template(dom, true, anchor); + return close_template(dom, true, anchor); } diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index c6d20d4be7..7b7f939154 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -211,16 +211,10 @@ function _mount(Component, options) { should_intro = options.intro ?? false; - /** @type {import('#client').RootBlock} */ + /** @type {import('#client').Block} */ const block = { // dom - d: null, - // effect - e: null, - // intro - i: options.intro || false, - // parent - p: null + d: null }; /** @type {Exports} */ @@ -251,7 +245,7 @@ function _mount(Component, options) { block, true ); - block.e = effect; + const bound_event_listener = handle_event_propagation.bind(null, container); const bound_document_event_listener = handle_event_propagation.bind(null, document); @@ -301,7 +295,7 @@ function _mount(Component, options) { if (dom !== null) { remove(dom); } - destroy_effect(/** @type {import('./types.js').Effect} */ (block.e)); + destroy_effect(effect); }); return component; diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index 489f786b23..68025ce99a 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -49,80 +49,19 @@ export type Equals = (this: Value, value: unknown) => boolean; export type TemplateNode = Text | Element | Comment; -export type RootBlock = { +export interface Block { /** dom */ d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** intro */ - i: boolean; - /** parent */ - p: null; -}; - -export type IfBlock = { - /** value */ - v: boolean; - /** dom */ - d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** parent */ - p: Block; -}; - -export type HeadBlock = { - /** dom */ - d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** parent */ - p: Block; -}; - -export type DynamicElementBlock = { - /** dom */ - d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** parent */ - p: Block; -}; - -export type DynamicComponentBlock = { - /** dom */ - d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** parent */ - p: Block; -}; - -export type AwaitBlock = { - /** dom */ - d: null | TemplateNode | Array; - /** effect */ - e: null | Effect; - /** parent */ - p: Block; - /** pending */ - n: boolean; -}; +} -export type EachBlock = { +export type EachState = { /** flags */ - f: number; - /** dom */ - d: null | TemplateNode | Array; + flags: number; /** items */ - v: EachItemBlock[]; - /** effewct */ - e: null | Effect; - /** parent */ - p: Block; + items: EachItem[]; }; -export type EachItemBlock = { +export type EachItem = { /** animation manager */ a: AnimationManager | null; /** dom */ @@ -137,26 +76,6 @@ export type EachItemBlock = { k: unknown; }; -export type SnippetBlock = { - /** dom */ - d: null | TemplateNode | Array; - /** parent */ - p: Block; - /** effect */ - e: null | Effect; -}; - -export type Block = - | RootBlock - | IfBlock - | AwaitBlock - | DynamicElementBlock - | DynamicComponentBlock - | HeadBlock - | EachBlock - | EachItemBlock - | SnippetBlock; - export interface TransitionManager { /** Whether the `global` modifier was used (i.e. `transition:fade|global`) */ is_global: boolean; diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js index effa734e1d..3a88121a38 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -21,11 +21,11 @@ export default function Each_string_template($$anchor, $$props) { /* Update */ $.text_effect(text, () => `${$.stringify($.unwrap(thing))}, `); - $.close($$anchor, text); + return $.close($$anchor, text); }, null ); $.close_frag($$anchor, fragment); $.pop(); -} \ No newline at end of file +} diff --git a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js index f34a4933a3..cbe02d18ad 100644 --- a/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js @@ -27,10 +27,10 @@ export default function Function_prop_no_getter($$anchor, $$props) { /* Update */ $.text_effect(text, () => `clicks: ${$.stringify($.get(count))}`); - $.close($$anchor, text); + return $.close($$anchor, text); } }); $.close_frag($$anchor, fragment); $.pop(); -} \ No newline at end of file +}