#2324, svelte:element implementation

pull/3928/head
erzr 6 years ago
parent 004faf67f4
commit 6921485b49

@ -106,10 +106,11 @@ export default class Element extends Node {
children: INode[];
namespace: string;
needs_manual_style_scoping: boolean;
dynamic_tag: boolean;
constructor(component, parent, scope, info: any) {
super(component, parent, scope, info);
this.name = info.name;
this.name = this.get_element_name(info);
this.namespace = get_namespace(parent, this, component.namespace);
@ -223,6 +224,26 @@ export default class Element extends Node {
component.stylesheet.apply(this);
}
get_element_name(info: any) {
let elementName = info.name;
if (elementName === 'svelte:element') {
const tag_attribute = info.attributes.find(node => node.name === 'tag');
if (tag_attribute) {
const tagValue = tag_attribute.value[0];
if (tagValue.data) {
elementName = tagValue.data;
} else {
this.dynamic_tag = tagValue.expression.name;
}
}
}
return elementName;
}
validate() {
if (a11y_distracting_elements.has(this.name)) {
// no-distracting-elements

@ -393,7 +393,7 @@ export default class ElementWrapper extends Wrapper {
}
get_render_statement() {
const { name, namespace } = this.node;
const { name, namespace, dynamic_tag } = this.node;
if (namespace === 'http://www.w3.org/2000/svg') {
return x`@svg_element("${name}")`;
@ -408,6 +408,10 @@ export default class ElementWrapper extends Wrapper {
return x`@element_is("${name}", ${is.render_chunks().reduce((lhs, rhs) => x`${lhs} + ${rhs}`)});`;
}
if (dynamic_tag) {
return x`@element(#ctx.${dynamic_tag} || ${dynamic_tag})`;
}
return x`@element("${name}")`;
}

@ -18,7 +18,7 @@ const meta_tags = new Map([
['svelte:body', 'Body']
]);
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component');
const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:element');
const specials = new Map([
[
@ -39,6 +39,7 @@ const specials = new Map([
const SELF = /^svelte:self(?=[\s/>])/;
const COMPONENT = /^svelte:component(?=[\s/>])/;
const ELEMENT = /^svelte:element(?=[\s/>])/;
function parent_is_head(stack) {
let i = stack.length;
@ -182,6 +183,24 @@ export default function tag(parser: Parser) {
element.expression = definition.value[0].expression;
}
if (name === 'svelte:element') {
const index = element.attributes.findIndex(attr => attr.type === 'Attribute' && attr.name === 'tag');
if (!~index) {
parser.error({
code: `missing-component-definition`,
message: `<svelte:element> must have a 'tag' attribute`
}, start);
}
const definition = element.attributes[index];
if (definition.value === true || definition.value.length !== 1 || (definition.value[0].type !== 'Text' && definition.value[0].type !== 'MustacheTag')) {
parser.error({
code: `invalid-tag-definition`,
message: `invalid tag definition`
}, definition.start);
}
}
// special cases top-level <script> and <style>
if (specials.has(name) && parser.stack.length === 1) {
const special = specials.get(name);
@ -259,6 +278,8 @@ function read_tag_name(parser: Parser) {
if (parser.read(COMPONENT)) return 'svelte:component';
if (parser.read(ELEMENT)) return 'svelte:element';
const name = parser.read_until(/(\s|\/|>)/);
if (meta_tags.has(name)) return name;

Loading…
Cancel
Save