Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 48bfd81

Browse filesBrowse files
committed
fix: properly hydrate dynamic css props components and remove element removal
1 parent 26e3286 commit 48bfd81
Copy full SHA for 48bfd81

File tree

Expand file treeCollapse file tree

8 files changed

+66
-30
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+66
-30
lines changed

‎.changeset/twelve-foxes-smell.md

Copy file name to clipboard
+5Lines 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: properly hydrate dynamic css props components and remove element removal
+8-21Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,19 @@
1-
/** @import { Expression } from 'estree' */
21
/** @import { AST } from '#compiler' */
32
/** @import { ComponentContext } from '../types' */
4-
import * as b from '#compiler/builders';
3+
import { regex_is_valid_identifier } from '../../../patterns.js';
54
import { build_component } from './shared/component.js';
65

76
/**
87
* @param {AST.Component} node
98
* @param {ComponentContext} context
109
*/
1110
export function Component(node, context) {
12-
if (node.metadata.dynamic) {
13-
// Handle dynamic references to what seems like static inline components
14-
const component = build_component(node, '$$component', context, b.id('$$anchor'));
15-
context.state.init.push(
16-
b.stmt(
17-
b.call(
18-
'$.component',
19-
context.state.node,
20-
// TODO use untrack here to not update when binding changes?
21-
// Would align with Svelte 4 behavior, but it's arguably nicer/expected to update this
22-
b.thunk(/** @type {Expression} */ (context.visit(b.member_id(node.name)))),
23-
b.arrow([b.id('$$anchor'), b.id('$$component')], b.block([component]))
24-
)
25-
)
26-
);
27-
return;
28-
}
29-
30-
const component = build_component(node, node.name, context);
11+
const component = build_component(
12+
node,
13+
// if it's not dynamic we will just use the node name, if it is dynamic we will use the node name
14+
// only if it's a valid identifier, otherwise we will use a default name
15+
!node.metadata.dynamic || regex_is_valid_identifier.test(node.name) ? node.name : '$$component',
16+
context
17+
);
3118
context.state.init.push(component);
3219
}

‎packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js

Copy file name to clipboardExpand all lines: packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js
+12-5Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ import { determine_slot } from '../../../../../utils/slot.js';
1313
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
1414
* @param {string} component_name
1515
* @param {ComponentContext} context
16-
* @param {Expression} anchor
1716
* @returns {Statement}
1817
*/
19-
export function build_component(node, component_name, context, anchor = context.state.node) {
18+
export function build_component(node, component_name, context) {
19+
/**
20+
* @type {Expression}
21+
*/
22+
const anchor = context.state.node;
2023
/** @type {Array<Property[] | Expression>} */
2124
const props_and_spreads = [];
2225
/** @type {Array<() => void>} */
@@ -411,7 +414,7 @@ export function build_component(node, component_name, context, anchor = context.
411414
// TODO We can remove this ternary once we remove legacy mode, since in runes mode dynamic components
412415
// will be handled separately through the `$.component` function, and then the component name will
413416
// always be referenced through just the identifier here.
414-
node.type === 'SvelteComponent'
417+
node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)
415418
? component_name
416419
: /** @type {Expression} */ (context.visit(b.member_id(component_name))),
417420
node_id,
@@ -429,14 +432,18 @@ export function build_component(node, component_name, context, anchor = context.
429432

430433
const statements = [...snippet_declarations];
431434

432-
if (node.type === 'SvelteComponent') {
435+
if (node.type === 'SvelteComponent' || (node.type === 'Component' && node.metadata.dynamic)) {
433436
const prev = fn;
434437

435438
fn = (node_id) => {
436439
return b.call(
437440
'$.component',
438441
node_id,
439-
b.thunk(/** @type {Expression} */ (context.visit(node.expression))),
442+
b.thunk(
443+
/** @type {Expression} */ (
444+
context.visit(node.type === 'Component' ? b.member_id(node.name) : node.expression)
445+
)
446+
),
440447
b.arrow(
441448
[b.id('$$anchor'), b.id(component_name)],
442449
b.block([...binding_initializers, b.stmt(prev(b.id('$$anchor')))])

‎packages/svelte/src/internal/client/dom/blocks/css-props.js

Copy file name to clipboardExpand all lines: packages/svelte/src/internal/client/dom/blocks/css-props.js
-4Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,4 @@ export function css_props(element, get_styles) {
2626
}
2727
}
2828
});
29-
30-
teardown(() => {
31-
element.remove();
32-
});
3329
}
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div>a</div>
2+
3+
<style>
4+
div{
5+
color: var(--prop);
6+
}
7+
</style>
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div>b</div>
2+
3+
<style>
4+
div{
5+
color: var(--prop);
6+
}
7+
</style>
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { test } from '../../assert';
2+
import { flushSync } from 'svelte';
3+
4+
export default test({
5+
warnings: [],
6+
async test({ assert, target }) {
7+
const btn = target.querySelector('button');
8+
let div = /** @type {HTMLElement} */ (target.querySelector('div'));
9+
assert.equal(getComputedStyle(div).color, 'rgb(255, 0, 0)');
10+
flushSync(() => {
11+
btn?.click();
12+
});
13+
div = /** @type {HTMLElement} */ (target.querySelector('div'));
14+
assert.equal(getComputedStyle(div).color, 'rgb(255, 0, 0)');
15+
}
16+
});
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
import A from "./B.svelte";
3+
import B from "./A.svelte";
4+
let value = $state(0);
5+
6+
let Comp = $derived(value % 2 === 0 ? A : B);
7+
</script>
8+
9+
<button onclick={()=>value++}>click</button>
10+
11+
<Comp --prop="red"/>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.