diff --git a/.changeset/kind-deers-lay.md b/.changeset/kind-deers-lay.md new file mode 100644 index 0000000000..fad265dd44 --- /dev/null +++ b/.changeset/kind-deers-lay.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: more transition code-golfing diff --git a/packages/svelte/src/internal/client/block.js b/packages/svelte/src/internal/client/block.js index 9eff638034..8f70b0fcf1 100644 --- a/packages/svelte/src/internal/client/block.js +++ b/packages/svelte/src/internal/client/block.js @@ -35,8 +35,14 @@ export function create_root_block(intro) { /** @returns {import('./types.js').IfBlock} */ export function create_if_block() { return { - // current - c: false, + // alternate transitions + a: null, + // alternate effect + ae: null, + // consequent transitions + c: null, + // consequent effect + ce: null, // dom d: null, // effect @@ -46,7 +52,9 @@ export function create_if_block() { // transition r: null, // type - t: IF_BLOCK + t: IF_BLOCK, + // value + v: false }; } diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index a67ee2a0be..8e85e43886 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -70,7 +70,7 @@ import { } from './hydration.js'; import { array_from, define_property, get_descriptor, get_descriptors, is_array } from './utils.js'; import { is_promise } from '../common.js'; -import { bind_transition, remove_in_transitions, trigger_transitions } from './transitions.js'; +import { bind_transition, trigger_transitions } from './transitions.js'; /** @type {Set} */ const all_registerd_events = new Set(); @@ -1355,8 +1355,6 @@ export function slot(anchor_node, slot_fn, slot_props, fallback_fn) { function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { const block = create_if_block(); hydrate_block_anchor(anchor_node); - const consequent_transitions = new Set(); - const alternate_transitions = new Set(); const previous_hydration_fragment = current_hydration_fragment; /** @type {null | import('./types.js').TemplateNode | Array} */ @@ -1366,59 +1364,32 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { let has_mounted = false; let has_mounted_branch = false; - block.r = - /** - * @param {import('./types.js').Transition} transition - * @returns {void} - */ - (transition) => { - // block.current - if (block.c) { - consequent_transitions.add(transition); - transition.f(() => { - consequent_transitions.delete(transition); - remove_in_transitions(consequent_transitions); - if (consequent_transitions.size === 0) { - execute_effect(consequent_effect); - } - }); - } else { - alternate_transitions.add(transition); - transition.f(() => { - alternate_transitions.delete(transition); - remove_in_transitions(alternate_transitions); - if (alternate_transitions.size === 0) { - execute_effect(alternate_effect); - } - }); - } - }; const if_effect = render_effect( () => { const result = !!condition_fn(); - if (block.c !== result || !has_mounted) { - block.c = result; + if (block.v !== result || !has_mounted) { + block.v = result; if (has_mounted) { + const consequent_transitions = block.c; + const alternate_transitions = block.a; if (result) { - remove_in_transitions(alternate_transitions); - if (alternate_transitions.size === 0) { + if (alternate_transitions === null || alternate_transitions.size === 0) { execute_effect(alternate_effect); } else { trigger_transitions(alternate_transitions, 'out'); } - if (consequent_transitions.size === 0) { + if (consequent_transitions === null || consequent_transitions.size === 0) { execute_effect(consequent_effect); } else { trigger_transitions(consequent_transitions, 'in'); } } else { - remove_in_transitions(consequent_transitions); - if (consequent_transitions.size === 0) { + if (consequent_transitions === null || consequent_transitions.size === 0) { execute_effect(consequent_effect); } else { trigger_transitions(consequent_transitions, 'out'); } - if (alternate_transitions.size === 0) { + if (alternate_transitions === null || alternate_transitions.size === 0) { execute_effect(alternate_effect); } else { trigger_transitions(alternate_transitions, 'in'); @@ -1455,7 +1426,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { remove(consequent_dom); consequent_dom = null; } - if (block.c) { + if (block.v) { consequent_fn(anchor_node); if (!has_mounted_branch) { // Restore previous fragment so that Svelte continues to operate in hydration mode @@ -1469,6 +1440,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { block, true ); + block.ce = consequent_effect; // Managed effect const alternate_effect = render_effect( () => { @@ -1476,7 +1448,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { remove(alternate_dom); alternate_dom = null; } - if (!block.c) { + if (!block.v) { if (alternate_fn !== null) { alternate_fn(anchor_node); } @@ -1492,6 +1464,7 @@ function if_block(anchor_node, condition_fn, consequent_fn, alternate_fn) { block, true ); + block.ae = alternate_effect; push_destroy_fn(if_effect, () => { if (consequent_dom !== null) { remove(consequent_dom); @@ -1676,7 +1649,6 @@ export function component(anchor_node, component_fn, render_fn) { transitions.add(transition); transition.f(() => { transitions.delete(transition); - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.e !== null) { if (render.d !== null) { @@ -1724,7 +1696,6 @@ export function component(anchor_node, component_fn, render_fn) { return; } const transitions = render.s; - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.d !== null) { remove(render.d); @@ -1804,7 +1775,6 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) { transitions.add(transition); transition.f(() => { transitions.delete(transition); - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.e !== null) { if (render.d !== null) { @@ -1861,7 +1831,6 @@ function await_block(anchor_node, input, pending_fn, then_fn, catch_fn) { return; } const transitions = render.s; - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.d !== null) { remove(render.d); @@ -1966,7 +1935,6 @@ export function key(anchor_node, key, render_fn) { transitions.add(transition); transition.f(() => { transitions.delete(transition); - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.e !== null) { if (render.d !== null) { @@ -2007,7 +1975,6 @@ export function key(anchor_node, key, render_fn) { return; } const transitions = render.s; - remove_in_transitions(transitions); if (transitions.size === 0) { if (render.d !== null) { remove(render.d); @@ -2195,7 +2162,6 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re transitions.add(transition); transition.f(() => { transitions.delete(transition); - remove_in_transitions(transitions); if (transitions.size === 0) { if (fallback.e !== null) { if (fallback.d !== null) { diff --git a/packages/svelte/src/internal/client/transitions.js b/packages/svelte/src/internal/client/transitions.js index 64e587f10a..cfad871279 100644 --- a/packages/svelte/src/internal/client/transitions.js +++ b/packages/svelte/src/internal/client/transitions.js @@ -15,6 +15,7 @@ import { current_effect, destroy_signal, effect, + execute_effect, managed_effect, managed_pre_effect, mark_subtree_inert, @@ -418,7 +419,8 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) const block = current_block; const props = props_fn === null ? {} : props_fn(); - let skip_intro = true; + let can_show_intro_on_mount = true; + let can_apply_lazy_transitions = false; /** @type {import('./types.js').Block | null} */ let transition_block = block; @@ -429,19 +431,22 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) transition_block.r = each_item_transition; transition_block = transition_block.p; } else if (transition_block.t === AWAIT_BLOCK && transition_block.n /* pending */) { - skip_intro = false; + can_show_intro_on_mount = false; + } else if (transition_block.t === IF_BLOCK) { + transition_block.r = if_block_transition; } - if (skip_intro) { - skip_intro = transition_block.e === null; + if (!can_apply_lazy_transitions && can_show_intro_on_mount) { + can_show_intro_on_mount = transition_block.e === null; } - if (!skip_intro || !global) { - break; + if (!can_show_intro_on_mount || !global) { + can_apply_lazy_transitions = true; } } else if ( + !can_apply_lazy_transitions && transition_block.t === ROOT_BLOCK && (transition_block.e !== null || transition_block.i) ) { - skip_intro = false; + can_show_intro_on_mount = false; } transition_block = transition_block.p; } @@ -467,7 +472,7 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) transition = create_transition(dom, init, direction, transition_effect); const is_intro = direction === 'in'; - const show_intro = !skip_intro && (is_intro || direction === 'both'); + const show_intro = !can_show_intro_on_mount && (is_intro || direction === 'both'); if (show_intro) { transition.p = transition.i(); @@ -483,7 +488,7 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) /** @type {import('./types.js').Block | null} */ let transition_block = block; - while (transition_block !== null) { + while (!is_intro && transition_block !== null) { const parent = transition_block.p; if (is_transition_block(transition_block)) { if (transition_block.r !== null) { @@ -491,7 +496,7 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) } if ( parent === null || - (!global && (transition_block.t !== IF_BLOCK || parent.t !== IF_BLOCK || parent.c)) + (!global && (transition_block.t !== IF_BLOCK || parent.t !== IF_BLOCK || parent.v)) ) { break; } @@ -510,18 +515,6 @@ export function bind_transition(dom, transition_fn, props_fn, direction, global) } } -/** - * @param {Set} transitions - */ -export function remove_in_transitions(transitions) { - for (let transition of transitions) { - const direction = transition.r; - if (direction === 'in') { - transitions.delete(transition); - } - } -} - /** * @param {Set} transitions * @param {'in' | 'out' | 'key'} target_direction @@ -567,6 +560,43 @@ export function trigger_transitions(transitions, target_direction, from) { } } +/** + * @this {import('./types.js').IfBlock} + * @param {import('./types.js').Transition} transition + * @returns {void} + */ +function if_block_transition(transition) { + const block = this; + // block.value === true + if (block.v) { + let consequent_transitions = block.c; + if (consequent_transitions === null) { + consequent_transitions = block.c = new Set(); + } + consequent_transitions.add(transition); + transition.f(() => { + const c = /** @type {Set} */ (consequent_transitions); + c.delete(transition); + if (c.size === 0) { + execute_effect(/** @type {import('./types.js').EffectSignal} */ (block.ce)); + } + }); + } else { + let alternate_transitions = block.a; + if (alternate_transitions === null) { + alternate_transitions = block.a = new Set(); + } + alternate_transitions.add(transition); + transition.f(() => { + const a = /** @type {Set} */ (alternate_transitions); + a.delete(transition); + if (a.size === 0) { + execute_effect(/** @type {import('./types.js').EffectSignal} */ (block.ae)); + } + }); + } +} + /** * @this {import('./types.js').EachItemBlock} * @param {import('./types.js').Transition} transition diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index a87b08907f..1b41f6e0a4 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -165,16 +165,24 @@ export type RootBlock = { }; export type IfBlock = { - /** current */ - c: boolean; + /** value */ + v: boolean; /** dom */ d: null | TemplateNode | Array; /** effect */ - e: null | ComputationSignal; + e: null | EffectSignal; /** parent */ p: Block; /** transition */ r: null | ((transition: Transition) => void); + /** consequent transitions */ + c: null | Set; + /** alternate transitions */ + a: null | Set; + /** effect */ + ce: null | EffectSignal; + /** effect */ + ae: null | EffectSignal; /** type */ t: typeof IF_BLOCK; }; @@ -183,7 +191,7 @@ export type KeyBlock = { /** dom */ d: null | TemplateNode | Array; /** effect */ - e: null | ComputationSignal; + e: null | EffectSignal; /** parent */ p: Block; /** transition */