Skip to content

Commit 13b391b

Browse files
committed
fix: make snippet effects transparent for transitions
1 parent 30fa876 commit 13b391b

File tree

9 files changed

+65
-9
lines changed

9 files changed

+65
-9
lines changed

.changeset/lazy-knives-happen.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: make snippet effects transparent for transitions

packages/svelte/src/internal/client/constants.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ export const DIRTY = 1 << 9;
1010
export const MAYBE_DIRTY = 1 << 10;
1111
export const INERT = 1 << 11;
1212
export const DESTROYED = 1 << 12;
13-
export const IS_ELSEIF = 1 << 13;
14-
export const EFFECT_RAN = 1 << 14;
13+
export const EFFECT_RAN = 1 << 13;
14+
15+
/** 'Transparent' effects do not create a transition boundary */
16+
export const EFFECT_TRANSPARENT = 1 << 14;
1517

1618
export const STATE_SYMBOL = Symbol('$state');

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IS_ELSEIF } from '../../constants.js';
1+
import { EFFECT_TRANSPARENT } from '../../constants.js';
22
import { hydrate_nodes, hydrating, set_hydrating } from '../hydration.js';
33
import { remove } from '../reconciler.js';
44
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
@@ -79,6 +79,6 @@ export function if_block(
7979
});
8080

8181
if (elseif) {
82-
effect.f |= IS_ELSEIF;
82+
effect.f |= EFFECT_TRANSPARENT;
8383
}
8484
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EFFECT_TRANSPARENT } from '../../constants.js';
12
import { branch, render_effect } from '../../reactivity/effects.js';
23

34
/**
@@ -11,11 +12,13 @@ export function snippet(get_snippet, node, ...args) {
1112
/** @type {SnippetFn | null | undefined} */
1213
var snippet;
1314

14-
render_effect(() => {
15+
var effect = render_effect(() => {
1516
if (snippet === (snippet = get_snippet())) return;
1617

1718
if (snippet) {
1819
branch(() => /** @type {SnippetFn} */ (snippet)(node, ...args));
1920
}
2021
});
22+
23+
effect.f |= EFFECT_TRANSPARENT;
2124
}

packages/svelte/src/internal/client/dom/elements/transitions.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { should_intro } from '../../render.js';
77
import { is_function } from '../../utils.js';
88
import { current_each_item } from '../blocks/each.js';
99
import { TRANSITION_GLOBAL, TRANSITION_IN, TRANSITION_OUT } from '../../../../constants.js';
10-
import { EFFECT_RAN } from '../../constants.js';
10+
import { BLOCK_EFFECT, EFFECT_RAN } from '../../constants.js';
1111

1212
/**
1313
* @template T
@@ -212,6 +212,11 @@ export function transition(flags, element, get_fn, get_params) {
212212
if (is_intro && should_intro) {
213213
var parent = /** @type {import('#client').Effect} */ (e.parent);
214214

215+
// e.g snippets are implemented as render effects — keep going until we find the parent block
216+
while ((parent.f & BLOCK_EFFECT) === 0 && parent.parent) {
217+
parent = parent.parent;
218+
}
219+
215220
if (is_global || (parent.f & EFFECT_RAN) !== 0) {
216221
effect(() => {
217222
untrack(() => transition.in());

packages/svelte/src/internal/client/reactivity/effects.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
EFFECT_RAN,
2525
BLOCK_EFFECT,
2626
ROOT_EFFECT,
27-
IS_ELSEIF
27+
EFFECT_TRANSPARENT
2828
} from '../constants.js';
2929
import { set } from './sources.js';
3030
import { remove } from '../dom/reconciler.js';
@@ -345,7 +345,7 @@ export function pause_children(effect, transitions, local) {
345345

346346
while (child !== null) {
347347
var sibling = child.next;
348-
var transparent = (child.f & IS_ELSEIF) !== 0 || (child.f & BRANCH_EFFECT) !== 0;
348+
var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0;
349349
// TODO we don't need to call pause_children recursively with a linked list in place
350350
// it's slightly more involved though as we have to account for `transparent` changing
351351
// through the tree.
@@ -381,7 +381,7 @@ function resume_children(effect, local) {
381381

382382
while (child !== null) {
383383
var sibling = child.next;
384-
var transparent = (child.f & IS_ELSEIF) !== 0 || (child.f & BRANCH_EFFECT) !== 0;
384+
var transparent = (child.f & EFFECT_TRANSPARENT) !== 0 || (child.f & BRANCH_EFFECT) !== 0;
385385
// TODO we don't need to call resume_children recursively with a linked list in place
386386
// it's slightly more involved though as we have to account for `transparent` changing
387387
// through the tree.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
/** @type {{ children: import('svelte').Snippet }} */
3+
let { children } = $props();
4+
5+
let visible = $state(false);
6+
</script>
7+
8+
<button onclick={() => visible = !visible}>toggle</button>
9+
10+
{#if visible}
11+
{@render children()}
12+
{/if}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { flushSync } from 'svelte';
2+
import { ok, test } from '../../test';
3+
4+
export default test({
5+
test({ assert, target, raf }) {
6+
const button = target.querySelector('button');
7+
ok(button);
8+
9+
flushSync(() => button.click());
10+
raf.tick(50);
11+
assert.htmlEqual(target.innerHTML, '<button>toggle</button><p style="opacity: 0.5;">hello</p>');
12+
13+
flushSync(() => button.click());
14+
raf.tick(75);
15+
assert.htmlEqual(
16+
target.innerHTML,
17+
'<button>toggle</button><p style="opacity: 0.25;">hello</p>'
18+
);
19+
}
20+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import { fade } from 'svelte/transition';
3+
import { linear } from 'svelte/easing';
4+
import Container from './Container.svelte';
5+
</script>
6+
7+
<Container>
8+
<p style="opacity: 1" transition:fade={{ duration: 100, easing: linear }}>hello</p>
9+
</Container>

0 commit comments

Comments
 (0)