Skip to content

Commit

Permalink
allow <slot> to be part of a slot
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau committed Jan 21, 2020
1 parent b39282a commit e2eae53
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import ElementWrapper from './index';
import SlotWrapper from '../Slot';
import Block from '../../Block';
import { sanitize } from '../../../../utils/names';
import InlineComponentWrapper from '../InlineComponent';
import create_debugging_comment from '../shared/create_debugging_comment';
import { get_slot_definition } from '../shared/get_slot_definition';

export default function create_slot_block(attribute, element: ElementWrapper | SlotWrapper, block: Block) {
const owner = find_slot_owner(element.parent);

if (owner && owner.node.type === 'InlineComponent') {
const name = attribute.get_static_value() as string;

if (!((owner as unknown) as InlineComponentWrapper).slots.has(name)) {
const child_block = block.child({
comment: create_debugging_comment(element.node, element.renderer.component),
name: element.renderer.component.get_unique_name(
`create_${sanitize(name)}_slot`
),
type: 'slot',
});

const { scope, lets } = element.node;
const seen = new Set(lets.map(l => l.name.name));

((owner as unknown) as InlineComponentWrapper).node.lets.forEach(l => {
if (!seen.has(l.name.name)) lets.push(l);
});

((owner as unknown) as InlineComponentWrapper).slots.set(
name,
get_slot_definition(child_block, scope, lets)
);
element.renderer.blocks.push(child_block);
}

element.slot_block = ((owner as unknown) as InlineComponentWrapper).slots.get(
name
).block;

return element.slot_block;
}

return block;
}

function find_slot_owner(owner) {
while (owner) {
if (owner.node.type === 'InlineComponent') {
break;
}

if (owner.node.type === 'Element' && /-/.test(owner.node.name)) {
break;
}

owner = owner.parent;
}
return owner;
}
48 changes: 3 additions & 45 deletions src/compiler/compile/render_dom/wrappers/Element/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Renderer from '../../Renderer';
import Element from '../../../nodes/Element';
import Wrapper from '../shared/Wrapper';
import Block from '../../Block';
import { is_void, sanitize } from '../../../../utils/names';
import { is_void } from '../../../../utils/names';
import FragmentWrapper from '../Fragment';
import { escape_html, string_literal } from '../../../utils/stringify';
import TextWrapper from '../Text';
Expand All @@ -14,18 +14,16 @@ import AttributeWrapper from './Attribute';
import StyleAttributeWrapper from './StyleAttribute';
import { dimensions } from '../../../../utils/patterns';
import Binding from './Binding';
import InlineComponentWrapper from '../InlineComponent';
import add_to_set from '../../../utils/add_to_set';
import { add_event_handler } from '../shared/add_event_handlers';
import { add_action } from '../shared/add_actions';
import create_debugging_comment from '../shared/create_debugging_comment';
import { get_slot_definition } from '../shared/get_slot_definition';
import bind_this from '../shared/bind_this';
import { is_head } from '../shared/is_head';
import { Identifier } from 'estree';
import EventHandler from './EventHandler';
import { extract_names } from 'periscopic';
import Action from '../../../nodes/Action';
import create_slot_block from './create_slot_block';

const events = [
{
Expand Down Expand Up @@ -170,47 +168,7 @@ export default class ElementWrapper extends Wrapper {

this.attributes = this.node.attributes.map(attribute => {
if (attribute.name === 'slot') {
// TODO make separate subclass for this?
let owner = this.parent;
while (owner) {
if (owner.node.type === 'InlineComponent') {
break;
}

if (owner.node.type === 'Element' && /-/.test(owner.node.name)) {
break;
}

owner = owner.parent;
}

if (owner && owner.node.type === 'InlineComponent') {
const name = attribute.get_static_value() as string;

if (!(owner as unknown as InlineComponentWrapper).slots.has(name)) {
const child_block = block.child({
comment: create_debugging_comment(node, this.renderer.component),
name: this.renderer.component.get_unique_name(`create_${sanitize(name)}_slot`),
type: 'slot'
});

const { scope, lets } = this.node;
const seen = new Set(lets.map(l => l.name.name));

(owner as unknown as InlineComponentWrapper).node.lets.forEach(l => {
if (!seen.has(l.name.name)) lets.push(l);
});

(owner as unknown as InlineComponentWrapper).slots.set(
name,
get_slot_definition(child_block, scope, lets)
);
this.renderer.blocks.push(child_block);
}

this.slot_block = (owner as unknown as InlineComponentWrapper).slots.get(name).block;
block = this.slot_block;
}
block = create_slot_block(attribute, this, block);
}
if (attribute.name === 'style') {
return new StyleAttributeWrapper(this, block, attribute);
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/compile/render_dom/wrappers/Slot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import get_slot_data from '../../utils/get_slot_data';
import Expression from '../../nodes/shared/Expression';
import is_dynamic from './shared/is_dynamic';
import { Identifier, ObjectExpression } from 'estree';
import create_slot_block from './Element/create_slot_block';

export default class SlotWrapper extends Wrapper {
node: Slot;
fragment: FragmentWrapper;
slot_block: Block;

var: Identifier = { type: 'Identifier', name: 'slot' };
dependencies: Set<string> = new Set(['$$scope']);
Expand All @@ -30,6 +32,10 @@ export default class SlotWrapper extends Wrapper {
this.cannot_use_innerhtml();
this.not_static_content();

if (this.node.values.has('slot')) {
block = create_slot_block(this.node.values.get('slot'), this, block);
}

this.fragment = new FragmentWrapper(
renderer,
block,
Expand Down Expand Up @@ -59,6 +65,10 @@ export default class SlotWrapper extends Wrapper {

const { slot_name } = this.node;

if (this.slot_block) {
block = this.slot_block;
}

let get_slot_changes_fn;
let get_slot_context_fn;

Expand Down
24 changes: 23 additions & 1 deletion src/compiler/compile/render_ssr/handlers/Slot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ 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_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 & {
slot_scopes: Map<any, any>;
}) {
const slot_data = get_slot_data(node.values);
const slot = node.get_static_attribute_value('slot');
const nearest_inline_component = node.find_nearest(/InlineComponent/);

if (slot && nearest_inline_component) {
renderer.push();
}

renderer.push();
renderer.render(node.children, options);
Expand All @@ -15,4 +24,17 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions)
? $$slots.${node.slot_name}(${slot_data})
: ${result}
`);

if (slot && nearest_inline_component) {
const lets = node.lets;
const seen = new Set(lets.map(l => l.name.name));

nearest_inline_component.lets.forEach(l => {
if (!seen.has(l.name.name)) lets.push(l);
});
options.slot_scopes.set(slot, {
input: get_slot_scope(node.lets),
output: renderer.pop()
});
}
}
8 changes: 8 additions & 0 deletions test/runtime/samples/component-slot-nested-in-slot/One.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import Two from './Two.svelte';
export let a, b;
</script>

<Two {b} let:two>
<slot name="one" slot="two" one={a} two={two}></slot>
</Two>
4 changes: 4 additions & 0 deletions test/runtime/samples/component-slot-nested-in-slot/Two.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script>
export let b;
</script>
<slot name="two" two={b}></slot>
18 changes: 18 additions & 0 deletions test/runtime/samples/component-slot-nested-in-slot/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default {
html: `
<p slot='one'>one: 1 two: 2</p>
`,
test({ assert, component, target }) {
component.a = 3;
component.b = 4;
assert.htmlEqual(target.innerHTML, `
<p slot='one'>one: 3 two: 4</p>
`);

component.a = 5;
component.b = 6;
assert.htmlEqual(target.innerHTML, `
<p slot='one'>one: 5 two: 6</p>
`);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import One from './One.svelte';
export let a = 1;
export let b = 2;
</script>

<One {a} {b}>
<p slot='one' let:one let:two>one: {one} two: {two}</p>
</One>

0 comments on commit e2eae53

Please sign in to comment.