Skip to content

Commit f081a6c

Browse files
authored
fix: resume inert effects when they come from offscreen (#17942)
The offscreen branch was missing the "resume inert effects" logic that was just below; it never reached that because of the early continue. Fixes #17851
1 parent 1cd0645 commit f081a6c

4 files changed

Lines changed: 73 additions & 8 deletions

File tree

.changeset/fair-hands-relate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: resume inert effects when they come from offscreen

packages/svelte/src/internal/client/dom/blocks/each.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,14 @@ function reconcile(state, array, anchor, flags, get_key) {
480480
}
481481
}
482482

483+
if ((effect.f & INERT) !== 0) {
484+
resume_effect(effect);
485+
if (is_animated) {
486+
effect.nodes?.a?.unfix();
487+
(to_animate ??= new Set()).delete(effect);
488+
}
489+
}
490+
483491
if ((effect.f & EFFECT_OFFSCREEN) !== 0) {
484492
effect.f ^= EFFECT_OFFSCREEN;
485493

@@ -508,14 +516,6 @@ function reconcile(state, array, anchor, flags, get_key) {
508516
}
509517
}
510518

511-
if ((effect.f & INERT) !== 0) {
512-
resume_effect(effect);
513-
if (is_animated) {
514-
effect.nodes?.a?.unfix();
515-
(to_animate ??= new Set()).delete(effect);
516-
}
517-
}
518-
519519
if (effect !== current) {
520520
if (seen !== undefined && seen.has(effect)) {
521521
if (matched.length < stashed.length) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { tick } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
const spam = /** @type {HTMLButtonElement} */ (target.querySelector('button.spam'));
7+
const resolve = /** @type {HTMLButtonElement} */ (target.querySelector('button.resolve'));
8+
9+
resolve.click();
10+
await tick();
11+
12+
for (let i = 0; i < 5; i += 1) {
13+
spam.click();
14+
await tick();
15+
}
16+
17+
for (let i = 0; i < 5; i += 1) {
18+
resolve.click();
19+
await tick();
20+
}
21+
22+
assert.equal(target.querySelectorAll('div').length, 1);
23+
assert.htmlEqual(
24+
target.innerHTML,
25+
`
26+
<button class="spam">Spam</button>
27+
<button class="resolve">Resolve</button>
28+
<div>5</div>
29+
`
30+
);
31+
}
32+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script>
2+
let value = $state({ id: '0' });
3+
const resolvers = [];
4+
5+
function wait() {
6+
const promise = Promise.withResolvers();
7+
resolvers.push(promise.resolve);
8+
return promise.promise;
9+
}
10+
11+
function spam() {
12+
value.id = `${Number(value.id) + 1}`;
13+
}
14+
</script>
15+
16+
<button class="spam" onclick={spam}>Spam</button>
17+
<button class="resolve" onclick={() => resolvers.shift()?.()}>Resolve</button>
18+
19+
<svelte:boundary>
20+
{#each [value.id] as s (s)}
21+
{await wait()}
22+
<div>{s}</div>
23+
{/each}
24+
25+
{#snippet pending()}
26+
<p>pending</p>
27+
{/snippet}
28+
</svelte:boundary>

0 commit comments

Comments
 (0)