fix: style and class special case

pull/18058/head
paoloricciuti 5 months ago
parent 37bd61d3f1
commit 6830052254

@ -38,7 +38,10 @@ import { TEMPLATE_FRAGMENT } from '../../../../../constants.js';
* @param {ComponentContext} context * @param {ComponentContext} context
*/ */
export function RegularElement(node, context) { export function RegularElement(node, context) {
const is_html = context.state.metadata.namespace === 'html' && node.name !== 'svg'; const is_html =
context.state.metadata.namespace === 'html' &&
node.name !== 'svg' &&
!context.state.options.customRenderer;
const name = is_html ? node.name.toLowerCase() : node.name; const name = is_html ? node.name.toLowerCase() : node.name;
context.state.template.push_element(name, node.start, is_html); context.state.template.push_element(name, node.start, is_html);

@ -1,5 +1,11 @@
import { to_class } from '../../../shared/attributes.js'; import { to_class } from '../../../shared/attributes.js';
import { hydrating } from '../hydration.js'; import { hydrating } from '../hydration.js';
import {
class_list_toggle,
get_attribute,
remove_attribute,
set_attribute
} from '../operations.js';
/** /**
* @param {Element} dom * @param {Element} dom
@ -21,17 +27,17 @@ export function set_class(dom, is_html, value, hash, prev_classes, next_classes)
) { ) {
var next_class_name = to_class(value, hash, next_classes); var next_class_name = to_class(value, hash, next_classes);
if (!hydrating || next_class_name !== dom.getAttribute('class')) { if (!hydrating || next_class_name !== get_attribute(dom, 'class')) {
// Removing the attribute when the value is only an empty string causes // Removing the attribute when the value is only an empty string causes
// performance issues vs simply making the className an empty string. So // performance issues vs simply making the className an empty string. So
// we should only remove the class if the value is nullish // we should only remove the class if the value is nullish
// and there no hash/directives : // and there no hash/directives :
if (next_class_name == null) { if (next_class_name == null) {
dom.removeAttribute('class'); remove_attribute(dom, 'class');
} else if (is_html) { } else if (is_html) {
dom.className = next_class_name; dom.className = next_class_name;
} else { } else {
dom.setAttribute('class', next_class_name); set_attribute(dom, 'class', next_class_name);
} }
} }
@ -42,7 +48,7 @@ export function set_class(dom, is_html, value, hash, prev_classes, next_classes)
var is_present = !!next_classes[key]; var is_present = !!next_classes[key];
if (prev_classes == null || is_present !== !!prev_classes[key]) { if (prev_classes == null || is_present !== !!prev_classes[key]) {
dom.classList.toggle(key, is_present); class_list_toggle(/** @type {HTMLElement} */ (dom), key, is_present);
} }
} }
} }

@ -1,5 +1,12 @@
import { to_style } from '../../../shared/attributes.js'; import { to_style } from '../../../shared/attributes.js';
import { hydrating } from '../hydration.js'; import { hydrating } from '../hydration.js';
import {
style_remove_property,
style_set_property,
get_attribute,
remove_attribute,
set_css_text
} from '../operations.js';
/** /**
* @param {Element & ElementCSSInlineStyle} dom * @param {Element & ElementCSSInlineStyle} dom
@ -13,9 +20,9 @@ function update_styles(dom, prev = {}, next, priority) {
if (prev[key] !== value) { if (prev[key] !== value) {
if (next[key] == null) { if (next[key] == null) {
dom.style.removeProperty(key); style_remove_property(/** @type {HTMLElement} */ (dom), key);
} else { } else {
dom.style.setProperty(key, value, priority); style_set_property(/** @type {HTMLElement} */ (dom), key, value, priority);
} }
} }
} }
@ -34,11 +41,11 @@ export function set_style(dom, value, prev_styles, next_styles) {
if (hydrating || prev !== value) { if (hydrating || prev !== value) {
var next_style_attr = to_style(value, next_styles); var next_style_attr = to_style(value, next_styles);
if (!hydrating || next_style_attr !== dom.getAttribute('style')) { if (!hydrating || next_style_attr !== get_attribute(dom, 'style')) {
if (next_style_attr == null) { if (next_style_attr == null) {
dom.removeAttribute('style'); remove_attribute(dom, 'style');
} else { } else {
dom.style.cssText = next_style_attr; set_css_text(/** @type {HTMLElement} */ (dom), next_style_attr);
} }
} }

@ -20,6 +20,8 @@ export default test({
// Input 1: value="hello" // Input 1: value="hello"
const input_value = inputs[0]; const input_value = inputs[0];
assert.equal(input_value.attributes['value'], 'hello'); assert.equal(input_value.attributes['value'], 'hello');
assert.equal(input_value.attributes['class'], 'hello');
assert.equal(input_value.attributes['style'], 'color: blue');
// Input 2: type="checkbox" checked="" // Input 2: type="checkbox" checked=""
const input_checked = inputs[1]; const input_checked = inputs[1];
@ -40,6 +42,8 @@ export default test({
// Input 5: spread attributes // Input 5: spread attributes
const input_spread = inputs[4]; const input_spread = inputs[4];
assert.equal(input_spread.attributes['value'], 'hello'); assert.equal(input_spread.attributes['value'], 'hello');
assert.equal(input_spread.attributes['class'], 'hello');
assert.equal(input_spread.attributes['style'], 'color: blue');
// Click the button to update all values // Click the button to update all values
dispatch_event(button, 'click'); dispatch_event(button, 'click');
@ -48,7 +52,8 @@ export default test({
// After update: // After update:
// Input 1: value="world" // Input 1: value="world"
assert.equal(input_value.attributes['value'], 'world'); assert.equal(input_value.attributes['value'], 'world');
assert.equal(input_value.attributes['class'], 'world');
assert.equal(input_value.attributes['style'], 'color: red');
// Input 2: checked should be removed // Input 2: checked should be removed
assert.equal(input_checked.attributes['checked'], undefined); assert.equal(input_checked.attributes['checked'], undefined);
@ -61,5 +66,7 @@ export default test({
// Input 5: spread attributes should update value to "world" // Input 5: spread attributes should update value to "world"
assert.equal(input_spread.attributes['value'], 'world'); assert.equal(input_spread.attributes['value'], 'world');
assert.equal(input_spread.attributes['class'], 'world');
assert.equal(input_spread.attributes['style'], 'color: red');
} }
}); });

@ -1,12 +1,14 @@
<script> <script>
let value = $state("hello"); let value = $state("hello");
let class_name = $state("hello");
let style = $state("color: blue");
let checked = $state(true); let checked = $state(true);
let default_value = $state("default_val"); let default_value = $state("default_val");
let default_checked = $state(true); let default_checked = $state(true);
let spread = $derived({value}); let spread = $derived({value, class: class_name, style});
</script> </script>
<input value={value} /> <input {value} class={class_name} {style} />
<input type="checkbox" checked={checked} /> <input type="checkbox" checked={checked} />
<input value="fixed" defaultValue={default_value} /> <input value="fixed" defaultValue={default_value} />
<input type="checkbox" checked defaultChecked={default_checked} /> <input type="checkbox" checked defaultChecked={default_checked} />
@ -14,6 +16,8 @@
<button onclick={() => { <button onclick={() => {
value = "world"; value = "world";
class_name = "world";
style = "color: red";
checked = false; checked = false;
default_value = "new_default"; default_value = "new_default";
default_checked = false; default_checked = false;
Loading…
Cancel
Save