From 6787855c527ce4ea8a8bf6a69c00a9c2216903b1 Mon Sep 17 00:00:00 2001 From: Nguyen Tran Date: Sat, 15 Apr 2023 23:29:59 -0400 Subject: [PATCH] Implemented dynamic slot name --- src/compiler/compile/nodes/Slot.ts | 29 ++++++++++++++----- .../compile/render_dom/wrappers/Slot.ts | 5 ++-- .../compile/render_ssr/handlers/Slot.ts | 6 ++-- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/compiler/compile/nodes/Slot.ts b/src/compiler/compile/nodes/Slot.ts index c21a48f5d6..362a9276db 100644 --- a/src/compiler/compile/nodes/Slot.ts +++ b/src/compiler/compile/nodes/Slot.ts @@ -3,7 +3,7 @@ import Attribute from './Attribute'; import Component from '../Component'; import TemplateScope from './shared/TemplateScope'; import { INode } from './interfaces'; -import { TemplateNode } from '../../interfaces'; +import { TemplateNode, Attribute as AttributeNode } from '../../interfaces'; import compiler_errors from '../compiler_errors'; export default class Slot extends Element { @@ -11,31 +11,44 @@ export default class Slot extends Element { name: string; children: INode[]; slot_name: string; + name_attribute: Attribute; values: Map = new Map(); constructor(component: Component, parent: INode, scope: TemplateScope, info: TemplateNode) { super(component, parent, scope, info); - info.attributes.forEach(attr => { + info.attributes.forEach((attr: AttributeNode) => { if (attr.type !== 'Attribute' && attr.type !== 'Spread') { return component.error(attr, compiler_errors.invalid_slot_directive); } - + + const new_attribute = new Attribute(component, this, scope, attr); if (attr.name === 'name') { - if (attr.value.length !== 1 || attr.value[0].type !== 'Text') { - return component.error(attr, compiler_errors.dynamic_slot_name); + if (attr.value.length === 1 && attr.value[0].type === 'Text') { + 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') { 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 is the default slot, add our dependencies to any diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 0a589e3394..040909c73d 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -69,7 +69,7 @@ export default class SlotWrapper extends Wrapper { ) { const { renderer } = this; - const { slot_name } = this.node; + const { slot_name, name_attribute } = this.node; if (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_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` - 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}); ${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null} `); diff --git a/src/compiler/compile/render_ssr/handlers/Slot.ts b/src/compiler/compile/render_ssr/handlers/Slot.ts index f89b619c46..137d9c8e6e 100644 --- a/src/compiler/compile/render_ssr/handlers/Slot.ts +++ b/src/compiler/compile/render_ssr/handlers/Slot.ts @@ -2,6 +2,7 @@ import Renderer, { RenderOptions } from '../Renderer'; import Slot from '../../nodes/Slot'; import { x } from 'code-red'; 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'; 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); const result = renderer.pop(); + const slot_expression = get_attribute_value(node.name_attribute); renderer.add_expression(x` - #slots.${node.slot_name} - ? #slots.${node.slot_name}(${slot_data}) + #slots[${slot_expression}] + ? #slots[${slot_expression}](${slot_data}) : ${result} `);