diff --git a/.changeset/fair-hands-relate.md b/.changeset/fair-hands-relate.md new file mode 100644 index 0000000000..fd7b3585ad --- /dev/null +++ b/.changeset/fair-hands-relate.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: resume inert effects when they come from offscreen diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index b248ce5544..93c1e2f155 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -500,6 +500,14 @@ function reconcile(state, array, anchor, flags, get_key) { move(effect, next, anchor); prev = effect; + if ((effect.f & INERT) !== 0) { + resume_effect(effect); + if (is_animated) { + effect.nodes?.a?.unfix(); + (to_animate ??= new Set()).delete(effect); + } + } + matched = []; stashed = []; diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-await-stale-rows/_config.js b/packages/svelte/tests/runtime-runes/samples/async-each-await-stale-rows/_config.js new file mode 100644 index 0000000000..7025e4000e --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-each-await-stale-rows/_config.js @@ -0,0 +1,32 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const spam = /** @type {HTMLButtonElement} */ (target.querySelector('button.spam')); + const resolve = /** @type {HTMLButtonElement} */ (target.querySelector('button.resolve')); + + resolve.click(); + await tick(); + + for (let i = 0; i < 5; i += 1) { + spam.click(); + await tick(); + } + + for (let i = 0; i < 5; i += 1) { + resolve.click(); + await tick(); + } + + assert.equal(target.querySelectorAll('div').length, 1); + assert.htmlEqual( + target.innerHTML, + ` + + +
pending
+ {/snippet} +