pull/10006/head
Simon Holthausen 3 years ago
parent 6a4b302abd
commit 348328fe9e

@ -1109,10 +1109,30 @@ const common_visitors = {
if (attribute.type === 'Attribute') {
if (attribute.name === 'xmlns' && is_text_attribute(attribute)) {
node.metadata.svg = attribute.value[0].data === namespace_svg;
break;
return;
}
}
}
for (let i = context.path.length - 1; i >= 0; i--) {
const ancestor = context.path[i];
if (
ancestor.type === 'Component' ||
ancestor.type === 'SvelteComponent' ||
ancestor.type === 'SvelteFragment' ||
ancestor.type === 'SnippetBlock'
) {
// Inside a slot or a snippet -> this resets the namespace, so we can't determine it
return;
}
if (ancestor.type === 'SvelteElement' || ancestor.type === 'RegularElement') {
node.metadata.svg =
ancestor.type === 'RegularElement' && ancestor.name === 'foreignObject'
? false
: ancestor.metadata.svg;
return;
}
}
}
};

@ -9,7 +9,7 @@ import {
import { binding_properties } from '../../../bindings.js';
import {
clean_nodes,
determine_element_namespace,
determine_namespace_for_children,
escape_html,
infer_namespace
} from '../../utils.js';
@ -1683,6 +1683,7 @@ export const template_visitors = {
context.state.template.push(`<!--${node.data}-->`);
},
HtmlTag(node, context) {
console.log('html tag');
context.state.template.push('<!>');
// push into init, so that bindings run afterwards, which might trigger another run and override hydration
@ -1851,7 +1852,7 @@ export const template_visitors = {
const metadata = context.state.metadata;
const child_metadata = {
...context.state.metadata,
namespace: determine_element_namespace(node, context.state.metadata.namespace, context.path)
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
};
context.state.template.push(`<${node.name}`);
@ -2076,11 +2077,7 @@ export const template_visitors = {
/** @type {import('estree').ExpressionStatement[]} */
const lets = [];
const namespace = determine_element_namespace(
node,
context.state.metadata.namespace,
context.path
);
const namespace = determine_namespace_for_children(node, context.state.metadata.namespace);
// Create a temporary context which picks up the init/update statements.
// They'll then be added to the function parameter of $.element

@ -15,7 +15,7 @@ import {
} from '../../constants.js';
import {
clean_nodes,
determine_element_namespace,
determine_namespace_for_children,
escape_html,
infer_namespace,
transform_inspect_rune
@ -1142,7 +1142,7 @@ const template_visitors = {
RegularElement(node, context) {
const metadata = {
...context.state.metadata,
namespace: determine_element_namespace(node, context.state.metadata.namespace, context.path)
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
};
context.state.template.push(t_string(`<${node.name}`));
@ -1234,7 +1234,7 @@ const template_visitors = {
const metadata = {
...context.state.metadata,
namespace: determine_element_namespace(node, context.state.metadata.namespace, context.path)
namespace: determine_namespace_for_children(node, context.state.metadata.namespace)
};
/** @type {import('./types').ComponentContext} */
const inner_context = {

@ -188,7 +188,7 @@ export function clean_nodes(
}
/**
* Infers the new namespace for the children of a node.
* Infers the namespace for the children of a node that should be used when creating the `$.template(...)`.
* @param {import('#compiler').Namespace} namespace
* @param {import('#compiler').SvelteNode} parent
* @param {import('#compiler').SvelteNode[]} nodes
@ -201,19 +201,28 @@ export function infer_namespace(namespace, parent, nodes, path) {
path.at(-1)
: parent;
if (
namespace !== 'foreign' &&
if (namespace !== 'foreign') {
if (parent_node?.type === 'RegularElement' && parent_node.name === 'foreignObject') {
return 'html';
}
if (parent_node?.type === 'RegularElement' || parent_node?.type === 'SvelteElement') {
return parent_node.metadata.svg ? 'svg' : 'html';
}
// Re-evaluate the namespace inside slot nodes that reset the namespace
(parent_node === undefined ||
if (
parent_node === undefined ||
parent_node.type === 'Root' ||
parent_node.type === 'Component' ||
parent_node.type === 'SvelteComponent' ||
parent_node.type === 'SvelteFragment' ||
parent_node.type === 'SnippetBlock')
) {
const new_namespace = check_nodes_for_namespace(nodes, 'keep');
if (new_namespace !== 'keep' && new_namespace !== 'maybe_html') {
namespace = new_namespace;
parent_node.type === 'SnippetBlock'
) {
const new_namespace = check_nodes_for_namespace(nodes, 'keep');
if (new_namespace !== 'keep' && new_namespace !== 'maybe_html') {
return new_namespace;
}
}
}
@ -279,48 +288,21 @@ function check_nodes_for_namespace(nodes, namespace) {
}
/**
* Determines the namespace the children of this node are in.
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} node
* @param {import('#compiler').Namespace} namespace
* @param {import('#compiler').SvelteNode[]} path
* @returns {import('#compiler').Namespace}
*/
export function determine_element_namespace(node, namespace, path) {
if (namespace !== 'foreign') {
let parent;
for (let i = path.length - 1; i >= 0; i--) {
parent = path[i];
if (parent.type === 'Fragment') {
parent = path[i - 1];
i--;
}
if (
parent?.type !== 'EachBlock' &&
parent?.type !== 'IfBlock' &&
parent?.type !== 'KeyBlock' &&
parent?.type !== 'AwaitBlock'
) {
break;
}
}
export function determine_namespace_for_children(node, namespace) {
if (namespace === 'foreign') {
return namespace;
}
if (parent?.type === 'RegularElement' && parent.name === 'foreignObject') {
return 'html';
} else if (
namespace !== 'svg' ||
parent?.type === 'Component' ||
parent?.type === 'SvelteComponent' ||
parent?.type === 'SvelteFragment' ||
parent?.type === 'SnippetBlock'
) {
if (node.metadata.svg) {
return 'svg';
} else {
return 'html';
}
}
if (node.name === 'foreignObject') {
return 'html';
}
return namespace;
return node.metadata.svg ? 'svg' : 'html';
}
/**

@ -309,7 +309,10 @@ export interface SvelteElement extends BaseElement {
name: 'svelte:element';
tag: Expression;
metadata: {
/** `true` if this is an svg element */
/**
* `true` if this is definitely an svg element.
* `false` could still mean that it is one, but we can't know statically.
*/
svg: boolean;
};
}

@ -1636,7 +1636,7 @@ export function element(anchor_node, tag_fn, namespace, render_fn) {
namespace ??
(tag === 'svg'
? namespace_svg
: anchor_node.parentElement?.tagName === 'FOREIGNOBJECT'
: anchor_node.parentElement?.tagName === 'foreignObject'
? null
: anchor_node.parentElement?.namespaceURI ?? null);
const next_element = tag

Loading…
Cancel
Save