diff --git a/src/compile/render-dom/Renderer.ts b/src/compile/render-dom/Renderer.ts index ae986315a9..f899d16fcb 100644 --- a/src/compile/render-dom/Renderer.ts +++ b/src/compile/render-dom/Renderer.ts @@ -3,16 +3,17 @@ import { CompileOptions } from '../../interfaces'; import Component from '../Component'; import FragmentWrapper from './wrappers/Fragment'; import CodeBuilder from '../utils/CodeBuilder'; +import SlotWrapper from './wrappers/Slot'; export default class Renderer { component: Component; // TODO Maybe Renderer shouldn't know about Component? options: CompileOptions; - blocks: (Block | string)[]; - readonly: Set; - slots: Set; - meta_bindings: CodeBuilder; - binding_groups: string[]; + blocks: (Block | string)[] = []; + readonly: Set = new Set(); + slots: Map = new Map(); + meta_bindings: CodeBuilder = new CodeBuilder(); // initial values for e.g. window.innerWidth, if there's a meta tag + binding_groups: string[] = []; block: Block; fragment: FragmentWrapper; @@ -24,16 +25,8 @@ export default class Renderer { this.options = options; this.locate = component.locate; // TODO messy - this.readonly = new Set(); - this.slots = new Set(); - this.file_var = options.dev && this.component.get_unique_name('file'); - // initial values for e.g. window.innerWidth, if there's a meta tag - this.meta_bindings = new CodeBuilder(); - - this.binding_groups = []; - // main block this.block = new Block({ renderer: this, @@ -46,7 +39,6 @@ export default class Renderer { }); this.block.has_update_method = true; - this.blocks = []; this.fragment = new FragmentWrapper( this, diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index 80a8308b93..50752c021b 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -220,10 +220,6 @@ export default class ElementWrapper extends Wrapper { render(block: Block, parent_node: string, parent_nodes: string) { const { renderer } = this; - if (this.node.name === 'slot') { - renderer.slots.add((this.node as Slot).slot_name); - } - if (this.node.name === 'noscript') return; if (this.slot_block) { diff --git a/src/compile/render-dom/wrappers/Slot.ts b/src/compile/render-dom/wrappers/Slot.ts index 89a575910f..c4a8a83bb4 100644 --- a/src/compile/render-dom/wrappers/Slot.ts +++ b/src/compile/render-dom/wrappers/Slot.ts @@ -9,10 +9,12 @@ import add_to_set from '../../utils/add_to_set'; import get_slot_data from '../../utils/get_slot_data'; import { stringify_props } from '../../utils/stringify_props'; import Expression from '../../nodes/shared/Expression'; +import Attribute from '../../nodes/Attribute'; export default class SlotWrapper extends Wrapper { node: Slot; fragment: FragmentWrapper; + slot_values: Map = new Map(); var = 'slot'; dependencies: Set = new Set(['$$scope']); @@ -38,14 +40,44 @@ export default class SlotWrapper extends Wrapper { ); this.node.attributes.forEach(attribute => { - add_to_set(this.dependencies, attribute.dependencies); + if (attribute.name !== 'name') this.slot_values.set(attribute.name, attribute); }); - block.add_dependencies(this.dependencies); + if (this.node.slot_name === 'default') { + // if this is the default slot, add our dependencies to any + // other slots (which inherit our slot values) that were + // previously encountered + renderer.slots.forEach(({ slot, block }) => { + this.slot_values.forEach((attribute, name) => { + if (!slot.slot_values.has(name)) { + slot.slot_values.set(name, attribute); + + add_to_set(slot.dependencies, attribute.dependencies); + block.add_dependencies(attribute.dependencies); + } + }); + }); + } else if (renderer.slots.has('default')) { + // otherwise, go the other way — inherit values from + // a previously encountered default slot + const { slot: default_slot } = renderer.slots.get('default'); + default_slot.slot_values.forEach((attribute, name) => { + if (!this.slot_values.has(name)) { + this.slot_values.set(name, attribute); + } + }); + } + + this.slot_values.forEach(attribute => { + add_to_set(this.dependencies, attribute.dependencies); + block.add_dependencies(attribute.dependencies); + }); // we have to do this, just in case block.add_intro(); block.add_outro(); + + renderer.slots.set(this.node.slot_name, { slot: this, block }); } render( @@ -56,14 +88,13 @@ export default class SlotWrapper extends Wrapper { const { renderer } = this; const { slot_name } = this.node; - renderer.slots.add(slot_name); let get_slot_changes; let get_slot_context; - const attributes = this.node.attributes.filter(attribute => attribute.name !== 'name'); + if (this.slot_values.size > 0) { + const attributes = Array.from(this.slot_values.values()); - if (attributes.length > 0) { get_slot_changes = renderer.component.get_unique_name(`get_${slot_name}_slot_changes`); get_slot_context = renderer.component.get_unique_name(`get_${slot_name}_slot_context`);