Implement dynamic slot attribute

pull/8535/head
Nguyen Tran 3 years ago
parent 2f32f948ee
commit ae02d4720a

@ -529,10 +529,6 @@ export default class Element extends Node {
}
if (name === 'slot') {
if (!attribute.is_static) {
return component.error(attribute, compiler_errors.invalid_slot_attribute);
}
if (component.slot_outlets.has(name)) {
return component.error(attribute, compiler_errors.duplicate_slot_attribute(name));

@ -16,6 +16,7 @@ export default class SlotTemplate extends Node {
const_tags: ConstTag[];
slot_attribute: Attribute;
slot_template_name: string = 'default';
is_static: boolean = true;
constructor(
component: Component,
@ -44,14 +45,17 @@ export default class SlotTemplate extends Node {
case 'Attribute': {
if (node.name === 'slot') {
this.slot_attribute = new Attribute(component, this, scope, node);
if (!this.slot_attribute.is_static) {
return component.error(node, compiler_errors.invalid_slot_attribute);
}
if (this.slot_attribute.is_static) {
const value = this.slot_attribute.get_static_value();
if (typeof value === 'boolean') {
return component.error(node, compiler_errors.invalid_slot_attribute_value_missing);
}
this.slot_template_name = value as string;
this.is_static = true;
} else {
this.slot_template_name = component.get_unique_name('dynamic_slot_template').name;
this.is_static = false;
}
break;
}
throw new Error(`Invalid attribute '${node.name}' in <svelte:fragment>`);

@ -29,7 +29,8 @@ const regex_invalid_variable_identifier_characters = /[^a-zA-Z_$]/g;
export default class InlineComponentWrapper extends Wrapper {
var: Identifier;
slots: Map<string, SlotDefinition> = new Map();
slots: Map<SlotTemplate, SlotDefinition> = new Map();
staic_slot_names: Set<string> = new Set();
node: InlineComponent;
fragment: FragmentWrapper;
children: Array<Wrapper | FragmentWrapper> = [];
@ -95,14 +96,20 @@ export default class InlineComponentWrapper extends Wrapper {
block.add_outro();
}
set_slot(name: string, slot_definition: SlotDefinition) {
if (this.slots.has(name)) {
set_slot(slot: SlotTemplate, slot_definition: SlotDefinition) {
if (slot.is_static) {
const name = slot.slot_template_name;
if (this.staic_slot_names.has(name)) {
if (name === 'default') {
throw new Error('Found elements without slot attribute when using slot="default"');
}
throw new Error(`Duplicate slot name "${name}" in <${this.node.name}>`);
} else {
this.staic_slot_names.add(name);
}
}
this.slots.set(name, slot_definition);
this.slots.set(slot, slot_definition);
}
warn_if_reactive() {
@ -167,8 +174,10 @@ export default class InlineComponentWrapper extends Wrapper {
const initial_props = this.slots.size > 0
? [
p`$$slots: {
${Array.from(this.slots).map(([name, slot]) => {
return p`${name}: [${slot.block.name}, ${slot.get_context || null}, ${slot.get_changes || null}]`;
${Array.from(this.slots).map(([slot_template, slot]) => {
const { is_static, slot_template_name, slot_attribute } = slot_template;
const slot_expression = is_static ? { type: 'Literal', value: slot_template_name } : slot_attribute.get_value(block);
return p`[${slot_expression}]: [${slot.block.name}, ${slot.get_context || null}, ${slot.get_changes || null}]`;
})}
}`,
p`$$scope: {

@ -52,10 +52,7 @@ export default class SlotTemplateWrapper extends Wrapper {
if (!seen.has(l.name.name)) lets.push(l);
});
this.parent.set_slot(
slot_template_name,
get_slot_definition(this.block, scope, lets)
);
this.parent.set_slot(this.node, get_slot_definition(this.block, scope, lets));
this.fragment = new FragmentWrapper(
renderer,

@ -77,9 +77,9 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
slot_scopes
}));
slot_scopes.forEach(({ input, output, statements }, name) => {
slot_scopes.forEach(({ input, output, statements }, slot_exp) => {
slot_fns.push(
p`${name}: (${input}) => { ${statements}; return ${output}; }`
p`[${slot_exp}]: (${input}) => { ${statements}; return ${output}; }`
);
});
}

@ -9,7 +9,7 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions &
slot_scopes: Map<any, any>;
}) {
const slot_data = get_slot_data(node.values);
const slot = node.get_static_attribute_value('slot');
const slot = node.values.get('slot')?.get_value(null);
const nearest_inline_component = node.find_nearest(/InlineComponent/);
if (slot && nearest_inline_component) {

@ -29,7 +29,8 @@ export default function(node: SlotTemplate, renderer: Renderer, options: RenderO
throw new Error(`Duplicate slot name "${node.slot_template_name}" in <${parent_inline_component.name}>`);
}
options.slot_scopes.set(node.slot_template_name, {
const slot_expression = node.is_static ? { type: 'Literal', value: node.slot_template_name } : node.slot_attribute.get_value(null);
options.slot_scopes.set(slot_expression, {
input: get_slot_scope(node.lets),
output: slot_fragment_content,
statements: get_const_tags(node.const_tags)

Loading…
Cancel
Save