Skip to content

Commit

Permalink
fix: apply clsx logic to custom element class attributes
Browse files Browse the repository at this point in the history
Fixes #14902
  • Loading branch information
dummdidumm committed Jan 6, 2025
1 parent ed26c3f commit 2c46292
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/happy-candles-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: apply `clsx` logic to custom element `class` attributes
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,9 @@ function build_element_attribute_update_assignment(
is_svg ? '$.set_svg_class' : is_mathml ? '$.set_mathml_class' : '$.set_class',
node_id,
value,
attribute.metadata.needs_clsx ? b.literal(context.state.analysis.css.hash) : undefined
attribute.metadata.needs_clsx && context.state.analysis.css.hash
? b.literal(context.state.analysis.css.hash)
: undefined
)
);
} else if (name === 'value') {
Expand Down Expand Up @@ -648,6 +650,14 @@ function build_custom_element_attribute_update_assignment(node_id, attribute, co
const name = attribute.name; // don't lowercase, as we set the element's property, which might be case sensitive
let { has_call, value } = build_attribute_value(attribute.value, context);

// We assume that noone's going to redefine the semantics of the class attribute on custom elements, i.e. it's still used for CSS classes
if (name === 'class' && attribute.metadata.needs_clsx) {
if (context.state.analysis.css.hash) {
value = b.array([value, b.literal(context.state.analysis.css.hash)]);
}
value = b.call('$.clsx', value);
}

const update = b.stmt(b.call('$.set_custom_element_data', node_id, b.literal(name), value));

if (attribute.metadata.expression.has_state) {
Expand Down
14 changes: 10 additions & 4 deletions packages/svelte/tests/runtime-runes/samples/clsx/_config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { flushSync } from 'svelte';
import { test } from '../../test';

export default test({
Expand All @@ -14,27 +15,32 @@ export default test({
<div class="foo">child</div>
<div class="foo">child</div>
<applied-to-custom-element class="foo svelte-owbekl"></applied-to-custom-element>
<button>update</button>
`,
test({ assert, target }) {
const button = target.querySelector('button');

button?.click();
flushSync();

assert.htmlEqual(
target.innerHTML,
`
<div class="foo svelte-owbekl"></div>
<div class="foo svelte-owbekl"></div>
<div class="foo svelte-owbekl"></div>
<div class="foo svelte-owbekl"></div>
<div class="bar svelte-owbekl"></div>
<div class="bar svelte-owbekl"></div>
<div class="foo svelte-owbekl"></div>
<div class="foo">child</div>
<div class="foo">child</div>
<div class="bar">child</div>
<div class="bar">child</div>
<div class="foo">child</div>
<div class="foo">child</div>
<div class="foo">child</div>
<applied-to-custom-element class="bar svelte-owbekl"></applied-to-custom-element>
<button>update</button>
`
Expand Down
2 changes: 2 additions & 0 deletions packages/svelte/tests/runtime-runes/samples/clsx/main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
<Child class={[ foo, bar ]} />
<Child {...spread} />

<applied-to-custom-element class={{ foo, bar }}></applied-to-custom-element>

<button onclick={() => {
foo = null;
bar = 'bar';
Expand Down

0 comments on commit 2c46292

Please sign in to comment.