Implemented dynamic slot name

pull/8535/head
Nguyen Tran 3 years ago
parent 9425f18e52
commit 6787855c52

@ -3,7 +3,7 @@ import Attribute from './Attribute';
import Component from '../Component'; import Component from '../Component';
import TemplateScope from './shared/TemplateScope'; import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces'; import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces'; import { TemplateNode, Attribute as AttributeNode } from '../../interfaces';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
export default class Slot extends Element { export default class Slot extends Element {
@ -11,31 +11,44 @@ export default class Slot extends Element {
name: string; name: string;
children: INode[]; children: INode[];
slot_name: string; slot_name: string;
name_attribute: Attribute;
values: Map<string, Attribute> = new Map(); values: Map<string, Attribute> = new Map();
constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) { constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info); super(component, parent, scope, info);
info.attributes.forEach(attr => { info.attributes.forEach((attr: AttributeNode) => {
if (attr.type !== 'Attribute' && attr.type !== 'Spread') { if (attr.type !== 'Attribute' && attr.type !== 'Spread') {
return component.error(attr, compiler_errors.invalid_slot_directive); return component.error(attr, compiler_errors.invalid_slot_directive);
} }
const new_attribute = new Attribute(component, this, scope, attr);
if (attr.name === 'name') { if (attr.name === 'name') {
if (attr.value.length !== 1 || attr.value[0].type !== 'Text') { if (attr.value.length === 1 && attr.value[0].type === 'Text') {
return component.error(attr, compiler_errors.dynamic_slot_name); this.slot_name = attr.value[0].data;
} else {
this.slot_name = component.get_unique_name('dynamic_slot_name').name;
} }
this.slot_name = attr.value[0].data;
if (this.slot_name === 'default') { if (this.slot_name === 'default') {
return component.error(attr, compiler_errors.invalid_slot_name); return component.error(attr, compiler_errors.invalid_slot_name);
} }
this.name_attribute = new_attribute;
} }
this.values.set(attr.name, new Attribute(component, this, scope, attr)); this.values.set(attr.name, new_attribute);
}); });
if (!this.slot_name) this.slot_name = 'default'; if (!this.slot_name) {
// If there is no name attribute, pretend we do have a name attribute with value 'default'
this.slot_name = 'default';
this.name_attribute = new Attribute(component, this, scope, {
type: 'Attribute',
name: 'name',
value: [ { type: 'Text', data: 'default' } ]
} as AttributeNode);
}
if (this.slot_name === 'default') { if (this.slot_name === 'default') {
// if this is the default slot, add our dependencies to any // if this is the default slot, add our dependencies to any

@ -69,7 +69,7 @@ export default class SlotWrapper extends Wrapper {
) { ) {
const { renderer } = this; const { renderer } = this;
const { slot_name } = this.node; const { slot_name, name_attribute } = this.node;
if (this.slot_block) { if (this.slot_block) {
block = this.slot_block; block = this.slot_block;
@ -128,8 +128,9 @@ export default class SlotWrapper extends Wrapper {
const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`); const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`);
const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot; const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot;
const slot_expression = name_attribute.get_value(block);
block.chunks.init.push(b` block.chunks.init.push(b`
const ${slot_definition} = ${renderer.reference('#slots')}.${slot_name}; const ${slot_definition} = ${renderer.reference('#slots')}[${slot_expression}];
const ${slot} = @create_slot(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn}); const ${slot} = @create_slot(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn});
${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null} ${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null}
`); `);

@ -2,6 +2,7 @@ import Renderer, { RenderOptions } from '../Renderer';
import Slot from '../../nodes/Slot'; import Slot from '../../nodes/Slot';
import { x } from 'code-red'; import { x } from 'code-red';
import get_slot_data from '../../utils/get_slot_data'; import get_slot_data from '../../utils/get_slot_data';
import { get_attribute_value } from './shared/get_attribute_value';
import { get_slot_scope } from './shared/get_slot_scope'; import { get_slot_scope } from './shared/get_slot_scope';
export default function(node: Slot, renderer: Renderer, options: RenderOptions & { export default function(node: Slot, renderer: Renderer, options: RenderOptions & {
@ -19,9 +20,10 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions &
renderer.render(node.children, options); renderer.render(node.children, options);
const result = renderer.pop(); const result = renderer.pop();
const slot_expression = get_attribute_value(node.name_attribute);
renderer.add_expression(x` renderer.add_expression(x`
#slots.${node.slot_name} #slots[${slot_expression}]
? #slots.${node.slot_name}(${slot_data}) ? #slots[${slot_expression}](${slot_data})
: ${result} : ${result}
`); `);

Loading…
Cancel
Save