Skip to content

Commit

Permalink
sveltejs#2324, svelte:element implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
erzr committed Nov 15, 2019
1 parent 004faf6 commit 6921485
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
23 changes: 22 additions & 1 deletion src/compiler/compile/nodes/Element.ts
Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/compile/render_dom/wrappers/Element/index.ts
Expand Up @@ -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}")`;
Expand All @@ -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}")`;
}

Expand Down
23 changes: 22 additions & 1 deletion src/compiler/parse/state/tag.ts
Expand Up @@ -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([
[
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 6921485

Please sign in to comment.