From 23ac6b5d0a3bfa649fb4b9eb4ed811bdb9027bd8 Mon Sep 17 00:00:00 2001 From: adiguba Date: Mon, 17 Feb 2025 19:15:56 +0100 Subject: [PATCH 1/8] style must be set via set_attribute --- .../src/internal/client/dom/elements/attributes.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 2dba2d797a4a..2dc482739b87 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -224,15 +224,17 @@ export function set_custom_element_data(node, prop, value) { set_active_effect(null); try { if ( + // style need set_attribute() + prop !== 'style' && // Don't compute setters for custom elements while they aren't registered yet, // because during their upgrade/instantiation they might add more setters. // Instead, fall back to a simple "an object, then set as property" heuristic. - setters_cache.has(node.nodeName) || + (setters_cache.has(node.nodeName) || // customElements may not be available in browser extension contexts !customElements || customElements.get(node.tagName.toLowerCase()) ? get_setters(node).includes(prop) - : value && typeof value === 'object' + : value && typeof value === 'object') ) { // @ts-expect-error node[prop] = value; @@ -375,8 +377,8 @@ export function set_attributes( // @ts-ignore element[`__${event_name}`] = undefined; } - } else if (key === 'style' && value != null) { - element.style.cssText = value + ''; + } else if (key === 'style') { + set_attribute(element, key, value); } else if (key === 'autofocus') { autofocus(/** @type {HTMLElement} */ (element), Boolean(value)); } else if (!is_custom_element && (key === '__value' || (key === 'value' && value != null))) { From 8d40eda28e0d11c3cc633fe1d0076d210f7e2c40 Mon Sep 17 00:00:00 2001 From: adiguba Date: Mon, 17 Feb 2025 19:16:50 +0100 Subject: [PATCH 2/8] test --- .../samples/style-update/_config.js | 36 +++++++++++++++++++ .../samples/style-update/main.svelte | 9 +++++ 2 files changed, 45 insertions(+) create mode 100644 packages/svelte/tests/runtime-runes/samples/style-update/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/style-update/main.svelte diff --git a/packages/svelte/tests/runtime-runes/samples/style-update/_config.js b/packages/svelte/tests/runtime-runes/samples/style-update/_config.js new file mode 100644 index 000000000000..ae6b2a1c4031 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/style-update/_config.js @@ -0,0 +1,36 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +const style_1 = 'invalid-key:0; margin:4px;;color: green ;color:blue '; +const style_2 = ' other-key : 0 ; padding:2px; COLOR:green; color: blue'; + +// https://github.com/sveltejs/svelte/issues/15309 +export default test({ + props: { + style: style_1 + }, + + html: ` +
+
+ + + + `, + + async test({ assert, target, component }) { + component.style = style_2; + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/style-update/main.svelte b/packages/svelte/tests/runtime-runes/samples/style-update/main.svelte new file mode 100644 index 000000000000..d29590d67035 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/style-update/main.svelte @@ -0,0 +1,9 @@ + + +
+
+ + + From e174c0ddfaf367cf54c26fb0597211b33b705322 Mon Sep 17 00:00:00 2001 From: adiguba Date: Mon, 17 Feb 2025 19:21:53 +0100 Subject: [PATCH 3/8] changeset --- .changeset/real-cameras-attack.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/real-cameras-attack.md diff --git a/.changeset/real-cameras-attack.md b/.changeset/real-cameras-attack.md new file mode 100644 index 000000000000..3b4ad7cce32b --- /dev/null +++ b/.changeset/real-cameras-attack.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: spreading style is not consistent with attribute From e52b5349388bf84ad39df89d90d7542d6754d1ca Mon Sep 17 00:00:00 2001 From: adiguba Date: Mon, 17 Feb 2025 19:38:32 +0100 Subject: [PATCH 4/8] add empty string and null in test --- .../samples/style-update/_config.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/svelte/tests/runtime-runes/samples/style-update/_config.js b/packages/svelte/tests/runtime-runes/samples/style-update/_config.js index ae6b2a1c4031..f0b7f2648e6d 100644 --- a/packages/svelte/tests/runtime-runes/samples/style-update/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/style-update/_config.js @@ -32,5 +32,33 @@ export default test({ ` ); + + component.style = ''; + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + ` + ); + + component.style = null; + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + ` + ); } }); From 6d408788521026a79bcaf19a137b80dddd1f4ce1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 14:10:13 -0500 Subject: [PATCH 5/8] explanatory comment --- packages/svelte/src/internal/client/dom/elements/attributes.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 2dc482739b87..1b799a6b0cb3 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -378,6 +378,7 @@ export function set_attributes( element[`__${event_name}`] = undefined; } } else if (key === 'style') { + // avoid using the setter set_attribute(element, key, value); } else if (key === 'autofocus') { autofocus(/** @type {HTMLElement} */ (element), Boolean(value)); From 174629d2bde7ce86bd8b2a2385fc91bbc963dee8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 14:10:29 -0500 Subject: [PATCH 6/8] this is now redundant, set_attribute takes care of it --- .../svelte/src/internal/client/dom/elements/attributes.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 1b799a6b0cb3..745eab262d57 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -428,10 +428,6 @@ export function set_attributes( set_attribute(element, name, value); } } - if (key === 'style' && '__styles' in element) { - // reset styles to force style: directive to update - element.__styles = {}; - } } if (is_hydrating_custom_element) { From ece16add810b3d066fd5827cc4e7740e91443ad1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 14:12:52 -0500 Subject: [PATCH 7/8] drive-by --- .../svelte/src/internal/client/dom/elements/attributes.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 745eab262d57..48548acbbe6e 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -213,6 +213,7 @@ export function set_custom_element_data(node, prop, value) { // or effect var previous_reaction = active_reaction; var previous_effect = active_effect; + // If we're hydrating but the custom element is from Svelte, and it already scaffolded, // then it might run block logic in hydration mode, which we have to prevent. let was_hydrating = hydrating; @@ -222,9 +223,10 @@ export function set_custom_element_data(node, prop, value) { set_active_reaction(null); set_active_effect(null); + try { if ( - // style need set_attribute() + // `style` should use `set_attribute` rather than the setter prop !== 'style' && // Don't compute setters for custom elements while they aren't registered yet, // because during their upgrade/instantiation they might add more setters. From c3934d6e99d5b46282c6c1eaaf9aa43f167e6b63 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 14:13:38 -0500 Subject: [PATCH 8/8] tweak changeset --- .changeset/real-cameras-attack.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/real-cameras-attack.md b/.changeset/real-cameras-attack.md index 3b4ad7cce32b..35e276478508 100644 --- a/.changeset/real-cameras-attack.md +++ b/.changeset/real-cameras-attack.md @@ -2,4 +2,4 @@ 'svelte': patch --- -fix: spreading style is not consistent with attribute +fix: always use `setAttribute` when setting `style`