Skip to content

Commit 0762a66

Browse files
committed
feat provide $$slots
1 parent aa3dcc0 commit 0762a66

File tree

10 files changed

+103
-9
lines changed

10 files changed

+103
-9
lines changed

src/compiler/compile/render_dom/Renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export default class Renderer {
5959

6060
if (component.slots.size > 0) {
6161
this.add_to_context('$$scope');
62-
this.add_to_context('$$slots');
62+
this.add_to_context('#slots');
6363
}
6464

6565
if (this.binding_groups.length > 0) {

src/compiler/compile/render_dom/index.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ export default function dom(
7070
);
7171
}
7272

73+
const uses_slots = component.var_lookup.has('$$slots');
74+
let compute_slots;
75+
if (uses_slots) {
76+
compute_slots = b`
77+
const $$slots = @compute_slots(#slots);
78+
`;
79+
}
80+
81+
7382
const uses_props = component.var_lookup.has('$$props');
7483
const uses_rest = component.var_lookup.has('$$restProps');
7584
const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`;
@@ -420,13 +429,14 @@ export default function dom(
420429
421430
${resubscribable_reactive_store_unsubscribers}
422431
432+
${component.slots.size || component.compile_options.dev || uses_slots ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null}
433+
${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`}
434+
${compute_slots}
435+
423436
${instance_javascript}
424437
425438
${unknown_props_check}
426439
427-
${component.slots.size || component.compile_options.dev ? b`let { $$slots = {}, $$scope } = $$props;` : null}
428-
${component.compile_options.dev && b`@validate_slots('${component.tag}', $$slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`}
429-
430440
${renderer.binding_groups.length > 0 && b`const $$binding_groups = [${renderer.binding_groups.map(_ => x`[]`)}];`}
431441
432442
${component.partly_hoisted}

src/compiler/compile/render_dom/wrappers/Slot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ export default class SlotWrapper extends Wrapper {
128128
const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot;
129129

130130
block.chunks.init.push(b`
131-
const ${slot_definition} = ${renderer.reference('$$slots')}.${slot_name};
131+
const ${slot_definition} = ${renderer.reference('#slots')}.${slot_name};
132132
const ${slot} = @create_slot(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn});
133133
${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null}
134134
`);

src/compiler/compile/render_ssr/handlers/Slot.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions)
1111
const result = renderer.pop();
1212

1313
renderer.add_expression(x`
14-
$$slots.${node.slot_name}
15-
? $$slots.${node.slot_name}(${slot_data})
14+
#slots.${node.slot_name}
15+
? #slots.${node.slot_name}(${slot_data})
1616
: ${result}
1717
`);
1818
}

src/compiler/compile/render_ssr/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ export default function ssr(
3535
const props = component.vars.filter(variable => !variable.module && variable.export_name);
3636
const rest = uses_rest ? b`let $$restProps = @compute_rest_props($$props, [${props.map(prop => `"${prop.export_name}"`).join(',')}]);` : null;
3737

38+
const uses_slots = component.var_lookup.has('$$slots');
39+
const slots = uses_slots ? b`let $$slots = @compute_slots(#slots);` : null;
40+
3841
const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
3942
const reactive_store_values = reactive_stores
4043
.map(({ name }) => {
@@ -135,6 +138,7 @@ export default function ssr(
135138

136139
const blocks = [
137140
rest,
141+
slots,
138142
...reactive_stores.map(({ name }) => {
139143
const store_name = name.slice(1);
140144
const store = component.var_lookup.get(store_name);
@@ -161,7 +165,7 @@ export default function ssr(
161165
162166
${component.fully_hoisted}
163167
164-
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => {
168+
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => {
165169
${blocks}
166170
});
167171
`;

src/compiler/compile/utils/reserved_keywords.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const reserved_keywords = new Set(["$$props", "$$restProps"]);
1+
export const reserved_keywords = new Set(["$$props", "$$restProps", "$$slots"]);
22

33
export function is_reserved_keyword(name) {
44
return reserved_keywords.has(name);

src/runtime/internal/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ export function compute_rest_props(props, keys) {
116116
return rest;
117117
}
118118

119+
export function compute_slots(slots) {
120+
const result = {};
121+
for (const key in slots) {
122+
result[key] = true;
123+
}
124+
return result;
125+
}
126+
119127
export function once(fn) {
120128
let ran = false;
121129
return function(this: any, ...args) {

test/runtime/samples/$$slot/A.svelte

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script>
2+
let data = '';
3+
4+
if ($$slots.b) {
5+
data = 'foo';
6+
}
7+
8+
export function getData() {
9+
return data;
10+
}
11+
12+
function toString(data) {
13+
const result = {};
14+
const sortedKeys = Object.keys(data).sort();
15+
sortedKeys.forEach(key => result[key] = data[key]);
16+
return JSON.stringify(result);
17+
}
18+
</script>
19+
20+
<slot></slot>
21+
<slot name="a"></slot>
22+
23+
$$slots: {toString($$slots)}
24+
25+
{#if $$slots.b}
26+
<div>
27+
<slot name="b"></slot>
28+
</div>
29+
{:else}
30+
Slot b is not available
31+
{/if}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
export default {
2+
html: `
3+
<span>bye</span><span>world</span>
4+
<span slot="a">hello world</span>
5+
$$slots: {"a":true,"default":true}
6+
Slot b is not available
7+
8+
<span>bye world</span>
9+
<span slot="a">hello world</span>
10+
$$slots: {"a":true,"b":true,"default":true}
11+
<div><span slot="b">hello world</span></div>
12+
`,
13+
14+
async test({ assert, target, component }) {
15+
assert.equal(component.getA(), '');
16+
assert.equal(component.getB(), 'foo');
17+
}
18+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script>
2+
import A from "./A.svelte";
3+
let a, b;
4+
5+
export function getA() {
6+
return a.getData();
7+
}
8+
export function getB() {
9+
return b.getData();
10+
}
11+
</script>
12+
13+
<A bind:this={a}>
14+
<span slot="a">hello world</span>
15+
<span>bye</span>
16+
<span>world</span>
17+
</A>
18+
19+
<A bind:this={b}>
20+
<span slot="a">hello world</span>
21+
<span slot="b">hello world</span>
22+
<span>bye world</span>
23+
</A>

0 commit comments

Comments
 (0)