feat provide $$slots

pull/4602/head
Tan Li Hau 6 years ago
parent dccdb9f130
commit e36c0b000c

@ -60,7 +60,7 @@ export default class Renderer {
if (component.slots.size > 0) {
this.add_to_context('$$scope');
this.add_to_context('$$slots');
this.add_to_context('#slots');
}
if (this.binding_groups.size > 0) {

@ -70,6 +70,15 @@ export default function dom(
);
}
const uses_slots = component.var_lookup.has('$$slots');
let compute_slots;
if (uses_slots) {
compute_slots = b`
const $$slots = @compute_slots(#slots);
`;
}
const uses_props = component.var_lookup.has('$$props');
const uses_rest = component.var_lookup.has('$$restProps');
const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`;
@ -409,13 +418,14 @@ export default function dom(
${resubscribable_reactive_store_unsubscribers}
${component.slots.size || component.compile_options.dev || uses_slots ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null}
${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`}
${compute_slots}
${instance_javascript}
${unknown_props_check}
${component.slots.size || component.compile_options.dev ? b`let { $$slots = {}, $$scope } = $$props;` : null}
${component.compile_options.dev && b`@validate_slots('${component.tag}', $$slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`}
${renderer.binding_groups.size > 0 && b`const $$binding_groups = [${[...renderer.binding_groups.keys()].map(_ => x`[]`)}];`}
${component.partly_hoisted}

@ -125,7 +125,7 @@ export default class SlotWrapper extends Wrapper {
const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot;
block.chunks.init.push(b`
const ${slot_definition} = ${renderer.reference('$$slots')}.${slot_name};
const ${slot_definition} = ${renderer.reference('#slots')}.${slot_name};
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}
`);

@ -11,8 +11,8 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions)
const result = renderer.pop();
renderer.add_expression(x`
$$slots.${node.slot_name}
? $$slots.${node.slot_name}(${slot_data})
#slots.${node.slot_name}
? #slots.${node.slot_name}(${slot_data})
: ${result}
`);
}

@ -34,6 +34,9 @@ export default function ssr(
const props = component.vars.filter(variable => !variable.module && variable.export_name);
const rest = uses_rest ? b`let $$restProps = @compute_rest_props($$props, [${props.map(prop => `"${prop.export_name}"`).join(',')}]);` : null;
const uses_slots = component.var_lookup.has('$$slots');
const slots = uses_slots ? b`let $$slots = @compute_slots(#slots);` : null;
const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
const reactive_store_values = reactive_stores
.map(({ name }) => {
@ -118,6 +121,7 @@ export default function ssr(
const blocks = [
rest,
slots,
...reactive_stores.map(({ name }) => {
const store_name = name.slice(1);
const store = component.var_lookup.get(store_name);
@ -144,7 +148,7 @@ export default function ssr(
${component.fully_hoisted}
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => {
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => {
${blocks}
});
`;

@ -1,4 +1,4 @@
export const reserved_keywords = new Set(["$$props", "$$restProps"]);
export const reserved_keywords = new Set(["$$props", "$$restProps", "$$slots"]);
export function is_reserved_keyword(name) {
return reserved_keywords.has(name);

@ -128,6 +128,14 @@ export function compute_rest_props(props, keys) {
return rest;
}
export function compute_slots(slots) {
const result = {};
for (const key in slots) {
result[key] = true;
}
return result;
}
export function once(fn) {
let ran = false;
return function(this: any, ...args) {

@ -0,0 +1,31 @@
<script>
let data = '';
if ($$slots.b) {
data = 'foo';
}
export function getData() {
return data;
}
function toString(data) {
const result = {};
const sortedKeys = Object.keys(data).sort();
sortedKeys.forEach(key => result[key] = data[key]);
return JSON.stringify(result);
}
</script>
<slot></slot>
<slot name="a"></slot>
$$slots: {toString($$slots)}
{#if $$slots.b}
<div>
<slot name="b"></slot>
</div>
{:else}
Slot b is not available
{/if}

@ -0,0 +1,18 @@
export default {
html: `
<span>bye</span><span>world</span>
<span slot="a">hello world</span>
$$slots: {"a":true,"default":true}
Slot b is not available
<span>bye world</span>
<span slot="a">hello world</span>
$$slots: {"a":true,"b":true,"default":true}
<div><span slot="b">hello world</span></div>
`,
async test({ assert, target, component }) {
assert.equal(component.getA(), '');
assert.equal(component.getB(), 'foo');
}
};

@ -0,0 +1,23 @@
<script>
import A from "./A.svelte";
let a, b;
export function getA() {
return a.getData();
}
export function getB() {
return b.getData();
}
</script>
<A bind:this={a}>
<span slot="a">hello world</span>
<span>bye</span>
<span>world</span>
</A>
<A bind:this={b}>
<span slot="a">hello world</span>
<span slot="b">hello world</span>
<span>bye world</span>
</A>
Loading…
Cancel
Save