Skip to content

Commit

Permalink
Fear: Add support for classlist
Browse files Browse the repository at this point in the history
  • Loading branch information
RaiVaibhav committed Apr 23, 2024
1 parent 05ac8f4 commit 1d81ca4
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 3 deletions.
Expand Up @@ -491,7 +491,11 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu
let update;

if (name === 'class') {
update = b.stmt(b.call(is_svg ? '$.set_svg_class' : '$.set_class', node_id, value));
if (value.type === 'ObjectExpression') {
update = b.stmt(b.call('$.set_class_list', node_id, value));
} else {
update = b.stmt(b.call(is_svg ? '$.set_svg_class' : '$.set_class', node_id, value));
}
} else if (DOMProperties.includes(name)) {
update = b.stmt(b.assignment('=', b.member(node_id, b.id(name)), value));
} else {
Expand Down
Expand Up @@ -2019,8 +2019,24 @@ function serialize_element_attributes(node, context) {
WhitespaceInsensitiveAttributes.includes(name)
);

//Any other tidy way to rewrite
const is_class_list =
name === 'class' &&
attribute &&
attribute.value &&
attribute.value[0] &&
attribute.value[0].type === 'ExpressionTag' &&
attribute.value[0].expression.type === 'ObjectExpression';

context.state.template.push(
t_expression(b.call('$.attr', b.literal(name), value, b.literal(is_boolean)))
t_expression(
b.call(
is_class_list ? '$.attr_class_list' : '$.attr',
b.literal(name),
value,
b.literal(is_boolean)
)
)
);
}
}
Expand Down
36 changes: 36 additions & 0 deletions packages/svelte/src/internal/client/dom/elements/class.js
Expand Up @@ -62,6 +62,42 @@ export function set_class(dom, value) {
}
}

/**
* @param {HTMLElement} dom
* @param {{[s: string]: any}} value
* @returns {void}
*/
export function set_class_list(dom, value) {

// with the toggle, and force option, as per
// the entry value, class can be added or removed
if (value) {
var entries = Object.entries(value)
for (let [key, entry] of entries) {
dom.classList.toggle(key, !!entry)
}
}

var next_class_name = dom.className;

// for performance reason remove this
if (!next_class_name) {
dom.removeAttribute('class');
}
// Set the updated className
// @ts-expect-error need to add __className to patched prototype
dom.__className = next_class_name;
// always remove the attribute

// Does classlist, need the check of
// dom.className === next_class_name ? in case of
// hydration, if the value
// or say next_class_name differs from the
// className, isn't this should simply update the
// token list and set the _className
}


/**
* @template V
* @param {V} value
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/index.js
Expand Up @@ -20,7 +20,7 @@ export {
set_dynamic_element_attributes,
set_xlink_attribute
} from './dom/elements/attributes.js';
export { set_class, set_svg_class, toggle_class } from './dom/elements/class.js';
export { set_class, set_svg_class, toggle_class, set_class_list } from './dom/elements/class.js';
export { event, delegate } from './dom/elements/events.js';
export { autofocus, remove_textarea_child } from './dom/elements/misc.js';
export { set_style } from './dom/elements/style.js';
Expand Down
21 changes: 21 additions & 0 deletions packages/svelte/src/internal/server/index.js
Expand Up @@ -263,6 +263,27 @@ export function attr(name, value, boolean) {
return ` ${name}${assignment}`;
}

// Separating the classlist for
// readability?

/**
* @template V
* @param {string} name
* @param {{[s: string]: any}} value
* @returns {string}
*/
export function attr_class_list(name, value) {
const entries = Object.entries(value).reduce((prev, [key, val], idx) => {
if (val) {
return idx === 0 ? key : prev + ' ' + key;
}
return prev;
}, '');

const assignment = `="${escape(entries, true)}"`;
return ` ${name}${assignment}`;
}

/**
* @param {Payload} payload
* @param {boolean} is_html
Expand Down

0 comments on commit 1d81ca4

Please sign in to comment.