From 92cef6e6da824c5b399002d4d11c1fc34338508d Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 24 Oct 2025 00:14:22 +0200 Subject: [PATCH] fix: take into account static blocks when determining transition locality The "is this a transparent effect we can ignore" logic for determining whether or not to play a local transition didn't account for pruned block effects. This fix marks the child branch as transparent if the block effect was, and during traversal then checks if the branch is the child of a block - if not that means it's the child of a pruned block effect. fixes #16826 --- .changeset/easy-paths-take.md | 5 +++++ .../svelte/src/internal/client/constants.js | 5 ++++- .../src/internal/client/reactivity/effects.js | 10 ++++++++- .../transition-if-nested-static/_config.js | 22 +++++++++++++++++++ .../transition-if-nested-static/main.svelte | 18 +++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 .changeset/easy-paths-take.md create mode 100644 packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte diff --git a/.changeset/easy-paths-take.md b/.changeset/easy-paths-take.md new file mode 100644 index 000000000000..1378322abe5b --- /dev/null +++ b/.changeset/easy-paths-take.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: take into account static blocks when determining transition locality diff --git a/packages/svelte/src/internal/client/constants.js b/packages/svelte/src/internal/client/constants.js index 1f35add2a88a..6818fd9d3039 100644 --- a/packages/svelte/src/internal/client/constants.js +++ b/packages/svelte/src/internal/client/constants.js @@ -14,7 +14,10 @@ export const DESTROYED = 1 << 14; // Flags exclusive to effects export const EFFECT_RAN = 1 << 15; -/** 'Transparent' effects do not create a transition boundary */ +/** + * 'Transparent' effects do not create a transition boundary. + * This is on a block effect 99% of the time but may also be on a branch effect if its parent block effect was pruned + */ export const EFFECT_TRANSPARENT = 1 << 16; export const INSPECT_EFFECT = 1 << 17; export const HEAD_EFFECT = 1 << 18; diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index bfbb95a8db7c..9b54598f9e2b 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -149,6 +149,9 @@ function create_effect(type, fn, sync, push = true) { (e.f & EFFECT_PRESERVED) === 0 ) { e = e.first; + if ((type & BLOCK_EFFECT) !== 0 && (type & EFFECT_TRANSPARENT) !== 0 && e !== null) { + e.f |= EFFECT_TRANSPARENT; + } } if (e !== null) { @@ -604,7 +607,12 @@ export function pause_children(effect, transitions, local) { while (child !== null) { var sibling = child.next; - var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0; + var transparent = + (child.f & EFFECT_TRANSPARENT) !== 0 || + // If this is a branch effect without a block effect parent, + // it means the parent block effect was pruned. In that case, + // transparency information was transferred to the branch effect. + ((child.f & BRANCH_EFFECT) !== 0 && (effect.f & BLOCK_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. diff --git a/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js new file mode 100644 index 000000000000..900d6daff8a1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const btn = target.querySelector('button'); + + btn?.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +
Should not transition out
+ ` + ); + + btn?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte new file mode 100644 index 000000000000..84f6ee77afe6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/transition-if-nested-static/main.svelte @@ -0,0 +1,18 @@ + + + + + +{#if showText} + {#if show} +
+ Should not transition out +
+ {/if} +{/if}