|
|
|
@ -12,6 +12,7 @@ import { determine_namespace_for_children } from '../../utils.js';
|
|
|
|
|
import {
|
|
|
|
|
build_attribute_value,
|
|
|
|
|
build_class_directives,
|
|
|
|
|
build_set_attributes,
|
|
|
|
|
build_style_directives
|
|
|
|
|
} from './shared/element.js';
|
|
|
|
|
import { build_render_statement, build_update } from './shared/utils.js';
|
|
|
|
@ -94,10 +95,10 @@ export function SvelteElement(node, context) {
|
|
|
|
|
|
|
|
|
|
// Always use spread because we don't know whether the element is a custom element or not,
|
|
|
|
|
// therefore we need to do the "how to set an attribute" logic at runtime.
|
|
|
|
|
is_attributes_reactive = build_dynamic_element_attributes(
|
|
|
|
|
node,
|
|
|
|
|
is_attributes_reactive = build_set_attributes(
|
|
|
|
|
attributes,
|
|
|
|
|
inner_context,
|
|
|
|
|
node,
|
|
|
|
|
element_id,
|
|
|
|
|
attributes_id,
|
|
|
|
|
b.binary('!==', b.member(element_id, 'namespaceURI'), b.id('$.NAMESPACE_SVG')),
|
|
|
|
@ -152,87 +153,3 @@ export function SvelteElement(node, context) {
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Serializes dynamic element attribute assignments.
|
|
|
|
|
* Returns the `true` if spread is deemed reactive.
|
|
|
|
|
* @param {AST.SvelteElement} element
|
|
|
|
|
* @param {Array<AST.Attribute | AST.SpreadAttribute>} attributes
|
|
|
|
|
* @param {ComponentContext} context
|
|
|
|
|
* @param {Identifier} element_id
|
|
|
|
|
* @param {Identifier} attributes_id
|
|
|
|
|
* @param {false | Expression} preserve_attribute_case
|
|
|
|
|
* @param {false | Expression} is_custom_element
|
|
|
|
|
* @returns {boolean}
|
|
|
|
|
*/
|
|
|
|
|
function build_dynamic_element_attributes(
|
|
|
|
|
element,
|
|
|
|
|
attributes,
|
|
|
|
|
context,
|
|
|
|
|
element_id,
|
|
|
|
|
attributes_id,
|
|
|
|
|
preserve_attribute_case,
|
|
|
|
|
is_custom_element
|
|
|
|
|
) {
|
|
|
|
|
let needs_isolation = false;
|
|
|
|
|
let is_reactive = false;
|
|
|
|
|
|
|
|
|
|
/** @type {ObjectExpression['properties']} */
|
|
|
|
|
const values = [];
|
|
|
|
|
|
|
|
|
|
for (const attribute of attributes) {
|
|
|
|
|
if (attribute.type === 'Attribute') {
|
|
|
|
|
const { value } = build_attribute_value(attribute.value, context);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
is_event_attribute(attribute) &&
|
|
|
|
|
(get_attribute_expression(attribute).type === 'ArrowFunctionExpression' ||
|
|
|
|
|
get_attribute_expression(attribute).type === 'FunctionExpression')
|
|
|
|
|
) {
|
|
|
|
|
// Give the event handler a stable ID so it isn't removed and readded on every update
|
|
|
|
|
const id = context.state.scope.generate('event_handler');
|
|
|
|
|
context.state.init.push(b.var(id, value));
|
|
|
|
|
values.push(b.init(attribute.name, b.id(id)));
|
|
|
|
|
} else {
|
|
|
|
|
values.push(b.init(attribute.name, value));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
values.push(b.spread(/** @type {Expression} */ (context.visit(attribute))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
is_reactive ||=
|
|
|
|
|
attribute.metadata.expression.has_state ||
|
|
|
|
|
// objects could contain reactive getters -> play it safe and always assume spread attributes are reactive
|
|
|
|
|
attribute.type === 'SpreadAttribute';
|
|
|
|
|
needs_isolation ||=
|
|
|
|
|
attribute.type === 'SpreadAttribute' && attribute.metadata.expression.has_call;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const call = b.call(
|
|
|
|
|
'$.set_attributes',
|
|
|
|
|
element_id,
|
|
|
|
|
is_reactive ? attributes_id : b.literal(null),
|
|
|
|
|
b.object(values),
|
|
|
|
|
context.state.analysis.css.hash !== '' && b.literal(context.state.analysis.css.hash),
|
|
|
|
|
preserve_attribute_case,
|
|
|
|
|
is_custom_element,
|
|
|
|
|
is_ignored(element, 'hydration_attribute_changed') && b.true
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (is_reactive) {
|
|
|
|
|
context.state.init.push(b.let(attributes_id));
|
|
|
|
|
|
|
|
|
|
const update = b.stmt(b.assignment('=', attributes_id, call));
|
|
|
|
|
|
|
|
|
|
if (needs_isolation) {
|
|
|
|
|
context.state.init.push(build_update(update));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context.state.update.push(update);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
context.state.init.push(b.stmt(call));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|