diff --git a/.changeset/few-rocks-remain.md b/.changeset/few-rocks-remain.md new file mode 100644 index 000000000000..452c3b8a087e --- /dev/null +++ b/.changeset/few-rocks-remain.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure $effect.tracking returns false inside transition functions diff --git a/packages/svelte/src/internal/client/dom/elements/transitions.js b/packages/svelte/src/internal/client/dom/elements/transitions.js index b473d0029d36..5ae1357786ea 100644 --- a/packages/svelte/src/internal/client/dom/elements/transitions.js +++ b/packages/svelte/src/internal/client/dom/elements/transitions.js @@ -1,7 +1,13 @@ /** @import { AnimateFn, Animation, AnimationConfig, EachItem, Effect, TransitionFn, TransitionManager } from '#client' */ import { noop, is_function } from '../../../shared/utils.js'; import { effect } from '../../reactivity/effects.js'; -import { active_effect, untrack } from '../../runtime.js'; +import { + active_effect, + active_reaction, + set_active_effect, + set_active_reaction, + untrack +} from '../../runtime.js'; import { loop } from '../../loop.js'; import { should_intro } from '../../render.js'; import { current_each_item } from '../blocks/each.js'; @@ -185,12 +191,21 @@ export function transition(flags, element, get_fn, get_params) { var outro; function get_options() { - // If a transition is still ongoing, we use the existing options rather than generating - // new ones. This ensures that reversible transitions reverse smoothly, rather than - // jumping to a new spot because (for example) a different `duration` was used - return (current_options ??= get_fn()(element, get_params?.() ?? /** @type {P} */ ({}), { - direction - })); + var previous_reaction = active_reaction; + var previous_effect = active_effect; + set_active_reaction(null); + set_active_effect(null); + try { + // If a transition is still ongoing, we use the existing options rather than generating + // new ones. This ensures that reversible transitions reverse smoothly, rather than + // jumping to a new spot because (for example) a different `duration` was used + return (current_options ??= get_fn()(element, get_params?.() ?? /** @type {P} */ ({}), { + direction + })); + } finally { + set_active_reaction(previous_reaction); + set_active_effect(previous_effect); + } } /** @type {TransitionManager} */ diff --git a/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/_config.js new file mode 100644 index 000000000000..72474cee7507 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const b1 = target.querySelector('button'); + + b1?.click(); + flushSync(); + assert.deepEqual(logs, [false]); + + b1?.click(); + flushSync(); + assert.deepEqual(logs, [false, false]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/main.svelte new file mode 100644 index 000000000000..a2a9d1f939a4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-tracking-transition/main.svelte @@ -0,0 +1,13 @@ + + + + +{#if visible} +