pull/15961/head
Rich Harris 4 months ago
parent d5d9593940
commit 673151adce

@ -27,17 +27,21 @@ export function build_set_attributes(
element_id,
attributes_id
) {
let is_dynamic = false;
/** @type {ObjectExpression['properties']} */
const values = [];
/** @type {Expression[]} */
const expressions = [];
/** @param {Expression} value */
function memoize(value) {
return b.id(`$${expressions.push(value) - 1}`);
}
for (const attribute of attributes) {
if (attribute.type === 'Attribute') {
const { value, has_state } = build_attribute_value(
attribute.value,
context,
(value, metadata) => (metadata.has_call ? get_expression_id(context.state, value) : value)
const { value } = build_attribute_value(attribute.value, context, (value, metadata) =>
metadata.has_call ? memoize(value) : value
);
if (
@ -51,16 +55,11 @@ export function build_set_attributes(
} else {
values.push(b.init(attribute.name, value));
}
is_dynamic ||= has_state;
} else {
// objects could contain reactive getters -> play it safe and always assume spread attributes are reactive
is_dynamic = true;
let value = /** @type {Expression} */ (context.visit(attribute));
if (attribute.metadata.expression.has_call) {
value = get_expression_id(context.state, value);
value = memoize(value);
}
values.push(b.spread(value));
@ -75,9 +74,6 @@ export function build_set_attributes(
build_class_directives_object(class_directives, context)
)
);
is_dynamic ||=
class_directives.find((directive) => directive.metadata.expression.has_state) !== null;
}
if (style_directives.length) {
@ -88,29 +84,25 @@ export function build_set_attributes(
build_style_directives_object(style_directives, context)
)
);
is_dynamic ||= style_directives.some((directive) => directive.metadata.expression.has_state);
}
const call = b.call(
'$.set_attributes',
context.state.init.push(
b.stmt(
b.call(
'$.set_attribute_effect',
element_id,
is_dynamic ? attributes_id : b.null,
b.object(values),
b.arrow(
expressions.map((_, i) => b.id(`$${i}`)),
b.object(values)
),
expressions.length > 0 && b.array(expressions.map((expression) => b.thunk(expression))),
element.metadata.scoped &&
context.state.analysis.css.hash !== '' &&
b.literal(context.state.analysis.css.hash),
is_ignored(element, 'hydration_attribute_changed') && b.true
)
)
);
if (is_dynamic) {
context.state.init.push(
b.let(attributes_id),
b.stmt(b.call('$.set_attribute_effect', element_id, b.thunk(b.object(values))))
);
} else {
context.state.init.push(b.stmt(call));
}
}
/**

@ -10,6 +10,7 @@ import { is_capture_event, is_delegated, normalize_attribute } from '../../../..
import {
active_effect,
active_reaction,
get,
set_active_effect,
set_active_reaction
} from '../../runtime.js';
@ -19,6 +20,7 @@ import { set_class } from './class.js';
import { set_style } from './style.js';
import { ATTACHMENT_KEY, NAMESPACE_HTML } from '../../../../constants.js';
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
import { derived } from '../../reactivity/deriveds.js';
export const CLASS = Symbol('class');
export const STYLE = Symbol('style');
@ -448,22 +450,32 @@ export function set_attributes(element, prev, next, css_hash, skip_warning = fal
set_hydrating(true);
}
for (let symbol of Object.getOwnPropertySymbols(next)) {
if (symbol.description === ATTACHMENT_KEY) {
attach(element, () => next[symbol]);
}
}
// for (let symbol of Object.getOwnPropertySymbols(next)) {
// if (symbol.description === ATTACHMENT_KEY) {
// attach(element, () => next[symbol]);
// }
// }
return current;
}
/**
* @param {Element & ElementCSSInlineStyle} element
* @param {() => Record<string | symbol, any>} fn
* @param {(...expressions: any) => Record<string | symbol, any>} fn
* @param {Array<() => any>} thunks
* @param {string} [css_hash]
* @param {boolean} [skip_warning]
*/
export function set_attribute_effect(element, fn, css_hash, skip_warning = false) {
export function set_attribute_effect(
element,
fn,
thunks = [],
css_hash,
skip_warning = false,
d = derived
) {
const deriveds = thunks.map(d);
/** @type {Record<string | symbol, any>} */
var prev = {};
@ -471,24 +483,9 @@ export function set_attribute_effect(element, fn, css_hash, skip_warning = false
var effects = {};
block(() => {
var next = fn();
var next = fn(...deriveds.map(get));
for (const key in prev) {
if (!next[key]) {
element.removeAttribute(key);
}
}
for (let symbol of Object.getOwnPropertySymbols(prev)) {
if (!next[symbol]) {
destroy_effect(effects[symbol]);
delete effects[symbol];
}
}
for (const key in next) {
set_attribute(element, key, next[key], skip_warning);
}
set_attributes(element, prev, next, css_hash, skip_warning);
for (let symbol of Object.getOwnPropertySymbols(next)) {
if (symbol.description === ATTACHMENT_KEY && next[symbol] !== prev[symbol]) {

Loading…
Cancel
Save