diff --git a/.changeset/lemon-cougars-buy.md b/.changeset/lemon-cougars-buy.md new file mode 100644 index 000000000000..382b3cdeb299 --- /dev/null +++ b/.changeset/lemon-cougars-buy.md @@ -0,0 +1,6 @@ +--- +'svelte': patch +--- + +fix: class:directive not working with $$restProps #15386 +fix: spread add an useless cssHash on non-scoped element diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js index fc5fd2cc4c53..81a4b45288eb 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js @@ -88,7 +88,9 @@ export function build_set_attributes( element_id, is_dynamic ? attributes_id : b.literal(null), b.object(values), - context.state.analysis.css.hash !== '' && b.literal(context.state.analysis.css.hash), + element.metadata.scoped && + context.state.analysis.css.hash !== '' && + b.literal(context.state.analysis.css.hash), preserve_attribute_case, is_custom_element, is_ignored(element, 'hydration_attribute_changed') && b.true diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js index 57101af4b823..281d8f061768 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js @@ -368,9 +368,10 @@ function build_element_spread_attributes( }) ); - const css_hash = context.state.analysis.css.hash - ? b.literal(context.state.analysis.css.hash) - : b.null; + const css_hash = + element.metadata.scoped && context.state.analysis.css.hash + ? b.literal(context.state.analysis.css.hash) + : b.null; const args = [object, css_hash, classes, styles, flags ? b.literal(flags) : undefined]; context.state.template.push(b.call('$.spread_attributes', ...args)); diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 151024e85c2e..dd408dcf8715 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -326,8 +326,16 @@ export function set_attributes( continue; } + if (key === 'class') { + var is_html = element.namespaceURI === 'http://www.w3.org/1999/xhtml'; + set_class(element, is_html, value, css_hash, prev?.[CLASS], next[CLASS]); + current[key] = value; + current[CLASS] = next[CLASS]; + continue; + } + var prev_value = current[key]; - if (value === prev_value && key !== 'class') continue; + if (value === prev_value) continue; current[key] = value; @@ -377,9 +385,6 @@ export function set_attributes( // @ts-ignore element[`__${event_name}`] = undefined; } - } else if (key === 'class') { - var is_html = element.namespaceURI === 'http://www.w3.org/1999/xhtml'; - set_class(element, is_html, value, css_hash, prev?.[CLASS], next[CLASS]); } else if (key === 'style' && value != null) { element.style.cssText = value + ''; } else if (key === 'autofocus') { diff --git a/packages/svelte/src/internal/client/dom/elements/class.js b/packages/svelte/src/internal/client/dom/elements/class.js index 3308709a247f..7027c84f6260 100644 --- a/packages/svelte/src/internal/client/dom/elements/class.js +++ b/packages/svelte/src/internal/client/dom/elements/class.js @@ -6,8 +6,8 @@ import { hydrating } from '../hydration.js'; * @param {boolean | number} is_html * @param {string | null} value * @param {string} [hash] - * @param {Record} [prev_classes] - * @param {Record} [next_classes] + * @param {Record} [prev_classes] + * @param {Record} [next_classes] * @returns {Record | undefined} */ export function set_class(dom, is_html, value, hash, prev_classes, next_classes) { @@ -34,12 +34,10 @@ export function set_class(dom, is_html, value, hash, prev_classes, next_classes) // @ts-expect-error need to add __className to patched prototype dom.__className = value; } else if (next_classes) { - prev_classes ??= {}; - for (var key in next_classes) { var is_present = !!next_classes[key]; - if (is_present !== !!prev_classes[key]) { + if (prev_classes == null || is_present !== !!prev_classes[key]) { dom.classList.toggle(key, is_present); } } diff --git a/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/_config.js b/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/_config.js index dd1bc6ac1a79..076efee994ec 100644 --- a/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/_config.js @@ -1,4 +1,4 @@ -import { flushSync } from 'svelte'; +import { flushSync, tick } from 'svelte'; import { test } from '../../test'; // This test counts mutations on hydration @@ -16,7 +16,12 @@ export default test({ html: `
-
+
+ + + + +
@@ -25,19 +30,97 @@ export default test({ ssrHtml: `
-
+
+ + + + +
`, - async test({ assert, component, instance }) { + async test({ target, assert, component, instance }) { flushSync(); + tick(); assert.deepEqual(instance.get_and_clear_mutations(), ['MAIN']); component.foo = false; flushSync(); - assert.deepEqual(instance.get_and_clear_mutations(), ['DIV', 'SPAN', 'B', 'I']); + tick(); + assert.deepEqual( + instance.get_and_clear_mutations(), + ['DIV', 'SPAN', 'B', 'I', 'DIV', 'SPAN', 'B', 'I'], + 'first mutation' + ); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + +
+ + + +
+ ` + ); + + component.foo = true; + flushSync(); + assert.deepEqual( + instance.get_and_clear_mutations(), + ['DIV', 'SPAN', 'B', 'I', 'DIV', 'SPAN', 'B', 'I'], + 'second mutation' + ); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + +
+ + + +
+ ` + ); + + component.classname = 'another'; + flushSync(); + assert.deepEqual( + instance.get_and_clear_mutations(), + ['DIV', 'B', 'DIV', 'B'], + 'class mutation' + ); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + + +
+ + + +
+ ` + ); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/main.svelte index 825362dcaf82..d748988e2190 100644 --- a/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/class-directive-mutations/main.svelte @@ -33,10 +33,15 @@
-
+
+ +
+ + +