pull/14714/head
Simon Holthausen 2 years ago
parent 45fa678242
commit 48d2e83b15

@ -142,6 +142,7 @@
"acorn-typescript": "^1.4.13",
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"clsx": "^2.1.1",
"esm-env": "^1.0.0",
"esrap": "^1.2.2",
"is-reference": "^3.0.2",

@ -739,6 +739,8 @@ export function analyze_component(root, source, options) {
if (attribute.type !== 'Attribute') continue;
if (attribute.name.toLowerCase() !== 'class') continue;
// The dynamic class method appends the hash to the end of the class attribute on its own
if (attribute.metadata.is_dynamic_class) continue outer;
class_attribute = attribute;
}

@ -24,6 +24,12 @@ export function Attribute(node, context) {
}
}
// class={[...]} or class={{...}} or `class={x}` need clsx to resolve the classes
if (node.name === 'class' && !Array.isArray(node.value) && node.value !== true) {
mark_subtree_dynamic(context.path);
node.metadata.is_dynamic_class = true;
}
if (node.value !== true) {
for (const chunk of get_attribute_chunks(node.value)) {
if (chunk.type !== 'ExpressionTag') continue;

@ -544,6 +544,10 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
let update;
if (name === 'class') {
if (attribute.metadata.is_dynamic_class) {
value = b.call('$.clsx', value);
}
if (attribute.metadata.expression.has_state && has_call) {
// ensure we're not creating a separate template effect for this so that
// potential class directives are added to the same effect and therefore always apply
@ -552,11 +556,13 @@ function build_element_attribute_update_assignment(element, node_id, attribute,
value = b.call('$.get', id);
has_call = false;
}
update = b.stmt(
b.call(
is_svg ? '$.set_svg_class' : is_mathml ? '$.set_mathml_class' : '$.set_class',
node_id,
value
value,
attribute.metadata.is_dynamic_class ? b.literal(context.state.analysis.css.hash) : undefined
)
);
} else if (name === 'value') {

@ -85,10 +85,25 @@ export function build_element_attributes(node, context) {
} else {
if (attribute.name === 'class') {
class_index = attributes.length;
} else if (attribute.name === 'style') {
style_index = attributes.length;
if (attribute.metadata.is_dynamic_class) {
attributes.push({
...attribute,
value: {
.../** @type {AST.ExpressionTag} */ (attribute.value),
expression: b.call(
'$.clsx',
/** @type {AST.ExpressionTag} */ (attribute.value).expression,
b.literal(context.state.analysis.css.hash)
)
}
});
}
} else {
if (attribute.name === 'style') {
style_index = attributes.length;
}
attributes.push(attribute);
}
attributes.push(attribute);
}
} else if (attribute.type === 'BindDirective') {
if (attribute.name === 'value' && node.name === 'select') continue;

@ -46,7 +46,8 @@ export function create_attribute(name, start, end, value) {
parent: null,
metadata: {
expression: create_expression_metadata(),
delegated: null
delegated: null,
is_dynamic_class: false
}
};
}

@ -452,6 +452,8 @@ export namespace AST {
expression: ExpressionMetadata;
/** May be set if this is an event attribute */
delegated: null | DelegatedEvent;
/** May be `true` if this is a `class` attribute that needs `clsx` */
is_dynamic_class: boolean;
};
}

@ -61,12 +61,13 @@ export function set_mathml_class(dom, value) {
/**
* @param {HTMLElement} dom
* @param {string} value
* @param {string} [hash]
* @returns {void}
*/
export function set_class(dom, value) {
export function set_class(dom, value, hash) {
// @ts-expect-error need to add __className to patched prototype
var prev_class_name = dom.__className;
var next_class_name = to_class(value);
var next_class_name = to_class(value) + (hash != null ? ' ' + hash : '');
if (hydrating && dom.className === next_class_name) {
// In case of hydration don't reset the class as it's already correct.

@ -1,3 +1,4 @@
export { clsx } from 'clsx';
export { FILENAME, HMR, NAMESPACE_SVG } from '../../constants.js';
export { cleanup_styles } from './dev/css.js';
export { add_locations } from './dev/elements.js';

@ -1,6 +1,7 @@
/** @import { ComponentType, SvelteComponent } from 'svelte' */
/** @import { Component, Payload, RenderOutput } from '#server' */
/** @import { Store } from '#shared' */
export { clsx } from 'clsx';
export { FILENAME, HMR } from '../../constants.js';
import { is_promise, noop } from '../shared/utils.js';
import { subscribe_to_store } from '../../store/utils.js';

@ -80,6 +80,9 @@ importers:
axobject-query:
specifier: ^4.1.0
version: 4.1.0
clsx:
specifier: ^2.1.1
version: 2.1.1
esm-env:
specifier: ^1.0.0
version: 1.0.0
@ -1211,6 +1214,10 @@ packages:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'}
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
codemirror@6.0.1:
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
@ -3950,6 +3957,8 @@ snapshots:
ci-info@3.9.0: {}
clsx@2.1.1: {}
codemirror@6.0.1(@lezer/common@1.2.1):
dependencies:
'@codemirror/autocomplete': 6.18.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.33.0)(@lezer/common@1.2.1)

Loading…
Cancel
Save