diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index f94d4f0ee8..538e410855 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -105,6 +105,16 @@ export function RegularElement(node, context) { break; case 'Attribute': + // `is` attributes need to be part of the template, otherwise they break + if (attribute.name === 'is' && context.state.metadata.namespace === 'html') { + const { value } = build_attribute_value(attribute.value, context); + + if (value.type === 'Literal' && typeof value.value === 'string') { + context.state.template.push(` is="${escape_html(value.value, true)}"`); + continue; + } + } + attributes.push(attribute); lookup.set(attribute.name, attribute); break; @@ -243,7 +253,7 @@ export function RegularElement(node, context) { attribute.name !== 'autofocus' && (attribute.value === true || is_text_attribute(attribute)) ) { - const name = get_attribute_name(node, attribute, context); + const name = get_attribute_name(node, attribute); const value = is_text_attribute(attribute) ? attribute.value[0].data : true; if (name !== 'class' || value) { @@ -479,15 +489,6 @@ function build_element_spread_attributes(attributes, context, element, element_i if (attribute.type === 'Attribute') { const { value } = build_attribute_value(attribute.value, context); - if ( - attribute.name === 'is' && - value.type === 'Literal' && - context.state.metadata.namespace === 'html' - ) { - context.state.template.push(` is="${escape_html(value.value, true)}"`); - continue; - } - if ( is_event_attribute(attribute) && (get_attribute_expression(attribute).type === 'ArrowFunctionExpression' || @@ -568,7 +569,7 @@ function build_element_spread_attributes(attributes, context, element, element_i */ function build_element_attribute_update_assignment(element, node_id, attribute, context) { const state = context.state; - const name = get_attribute_name(element, attribute, context); + const name = get_attribute_name(element, attribute); const is_svg = context.state.metadata.namespace === 'svg' || element.name === 'svg'; const is_mathml = context.state.metadata.namespace === 'mathml'; let { has_call, value } = build_attribute_value(attribute.value, context); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js index b46392bf11..dc14fc80ab 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/element.js @@ -101,6 +101,7 @@ export function build_class_directives( /** * @param {AST.Attribute['value']} value * @param {ComponentContext} context + * @returns {{ value: Expression, has_state: boolean, has_call: boolean }} */ export function build_attribute_value(value, context) { if (value === true) { @@ -127,9 +128,8 @@ export function build_attribute_value(value, context) { /** * @param {AST.RegularElement | AST.SvelteElement} element * @param {AST.Attribute} attribute - * @param {{ state: { metadata: { namespace: Namespace }}}} context */ -export function get_attribute_name(element, attribute, context) { +export function get_attribute_name(element, attribute) { if (!element.metadata.svg && !element.metadata.mathml) { return normalize_attribute(attribute.name); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js index 7d2c5d78a1..21b902d5c2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js @@ -36,6 +36,7 @@ export function get_states_and_calls(values) { * @param {Array} values * @param {(node: SvelteNode, state: any) => any} visit * @param {ComponentClientTransformState} state + * @returns {{ value: Expression, has_state: boolean, has_call: boolean }} */ export function build_template_literal(values, visit, state) { /** @type {Expression[]} */ diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js index a968d646ad..c386c4f7c0 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/element.js @@ -217,7 +217,7 @@ export function build_element_attributes(node, context) { } else { for (const attribute of /** @type {AST.Attribute[]} */ (attributes)) { if (attribute.value === true || is_text_attribute(attribute)) { - const name = get_attribute_name(node, attribute, context); + const name = get_attribute_name(node, attribute); const literal_value = /** @type {Literal} */ ( build_attribute_value( attribute.value, @@ -239,7 +239,7 @@ export function build_element_attributes(node, context) { continue; } - const name = get_attribute_name(node, attribute, context); + const name = get_attribute_name(node, attribute); const value = build_attribute_value( attribute.value, context, @@ -264,9 +264,8 @@ export function build_element_attributes(node, context) { /** * @param {AST.RegularElement | AST.SvelteElement} element * @param {AST.Attribute} attribute - * @param {{ state: { namespace: Namespace }}} context */ -function get_attribute_name(element, attribute, context) { +function get_attribute_name(element, attribute) { let name = attribute.name; if (!element.metadata.svg && !element.metadata.mathml) { name = name.toLowerCase(); @@ -334,7 +333,7 @@ function build_element_spread_attributes( const object = b.object( attributes.map((attribute) => { if (attribute.type === 'Attribute') { - const name = get_attribute_name(element, attribute, context); + const name = get_attribute_name(element, attribute); const value = build_attribute_value( attribute.value, context,