expose which slots are present in $$slots (#4602)

pull/5295/head
Tan Li Hau 4 years ago committed by GitHub
parent dccdb9f130
commit 0ac341d2c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,6 +2,7 @@
## Unreleased ## Unreleased
* Expose object of which slots have received content in `$$slots` ([#2106](https://github.com/sveltejs/svelte/issues/2106))
* Add types to `createEventDispatcher` ([#5211](https://github.com/sveltejs/svelte/issues/5211)) * Add types to `createEventDispatcher` ([#5211](https://github.com/sveltejs/svelte/issues/5211))
* In SSR mode, do not automatically declare variables for reactive assignments to member expressions ([#5247](https://github.com/sveltejs/svelte/issues/5247)) * In SSR mode, do not automatically declare variables for reactive assignments to member expressions ([#5247](https://github.com/sveltejs/svelte/issues/5247))
* Include selector in message of `unused-css-selector` warning ([#5252](https://github.com/sveltejs/svelte/issues/5252)) * Include selector in message of `unused-css-selector` warning ([#5252](https://github.com/sveltejs/svelte/issues/5252))

@ -60,7 +60,7 @@ export default class Renderer {
if (component.slots.size > 0) { if (component.slots.size > 0) {
this.add_to_context('$$scope'); this.add_to_context('$$scope');
this.add_to_context('$$slots'); this.add_to_context('#slots');
} }
if (this.binding_groups.size > 0) { 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_props = component.var_lookup.has('$$props');
const uses_rest = component.var_lookup.has('$$restProps'); const uses_rest = component.var_lookup.has('$$restProps');
const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`; const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`;
@ -409,13 +418,14 @@ export default function dom(
${resubscribable_reactive_store_unsubscribers} ${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} ${instance_javascript}
${unknown_props_check} ${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`[]`)}];`} ${renderer.binding_groups.size > 0 && b`const $$binding_groups = [${[...renderer.binding_groups.keys()].map(_ => x`[]`)}];`}
${component.partly_hoisted} ${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; const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot;
block.chunks.init.push(b` 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}); 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} ${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(); const result = renderer.pop();
renderer.add_expression(x` renderer.add_expression(x`
$$slots.${node.slot_name} #slots.${node.slot_name}
? $$slots.${node.slot_name}(${slot_data}) ? #slots.${node.slot_name}(${slot_data})
: ${result} : ${result}
`); `);
} }

@ -34,6 +34,9 @@ export default function ssr(
const props = component.vars.filter(variable => !variable.module && variable.export_name); 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 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_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$');
const reactive_store_values = reactive_stores const reactive_store_values = reactive_stores
.map(({ name }) => { .map(({ name }) => {
@ -118,6 +121,7 @@ export default function ssr(
const blocks = [ const blocks = [
rest, rest,
slots,
...reactive_stores.map(({ name }) => { ...reactive_stores.map(({ name }) => {
const store_name = name.slice(1); const store_name = name.slice(1);
const store = component.var_lookup.get(store_name); const store = component.var_lookup.get(store_name);
@ -144,7 +148,7 @@ export default function ssr(
${component.fully_hoisted} ${component.fully_hoisted}
const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => { const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => {
${blocks} ${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) { export function is_reserved_keyword(name) {
return reserved_keywords.has(name); return reserved_keywords.has(name);

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

@ -103,6 +103,8 @@ function instance($$self, $$props, $$invalidate) {
$$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(2, $prop = $$value)), prop); $$subscribe_prop = () => ($$unsubscribe_prop(), $$unsubscribe_prop = subscribe(prop, $$value => $$invalidate(2, $prop = $$value)), prop);
$$self.$$.on_destroy.push(() => $$unsubscribe_prop()); $$self.$$.on_destroy.push(() => $$unsubscribe_prop());
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let { prop } = $$props; let { prop } = $$props;
validate_store(prop, "prop"); validate_store(prop, "prop");
$$subscribe_prop(); $$subscribe_prop();
@ -115,9 +117,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop)); if ("prop" in $$props) $$subscribe_prop($$invalidate(0, prop = $$props.prop));
if ("alias" in $$props) $$invalidate(1, realName = $$props.alias); if ("alias" in $$props) $$invalidate(1, realName = $$props.alias);

@ -69,6 +69,8 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let { name } = $$props; let { name } = $$props;
const writable_props = ["name"]; const writable_props = ["name"];
@ -76,9 +78,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ("name" in $$props) $$invalidate(0, name = $$props.name); if ("name" in $$props) $$invalidate(0, name = $$props.name);
}; };

@ -170,6 +170,8 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let { things } = $$props; let { things } = $$props;
let { foo } = $$props; let { foo } = $$props;
let { bar } = $$props; let { bar } = $$props;
@ -180,9 +182,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("things" in $$props) $$invalidate(0, things = $$props.things);
if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo);

@ -164,6 +164,8 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let { things } = $$props; let { things } = $$props;
let { foo } = $$props; let { foo } = $$props;
const writable_props = ["things", "foo"]; const writable_props = ["things", "foo"];
@ -172,9 +174,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ("things" in $$props) $$invalidate(0, things = $$props.things); if ("things" in $$props) $$invalidate(0, things = $$props.things);
if ("foo" in $$props) $$invalidate(1, foo = $$props.foo); if ("foo" in $$props) $$invalidate(1, foo = $$props.foo);

@ -49,6 +49,8 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let obj = { x: 5 }; let obj = { x: 5 };
let kobzol = 5; let kobzol = 5;
const writable_props = []; const writable_props = [];
@ -57,8 +59,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$capture_state = () => ({ obj, kobzol }); $$self.$capture_state = () => ({ obj, kobzol });
$$self.$inject_state = $$props => { $$self.$inject_state = $$props => {

@ -136,14 +136,14 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props) { function instance($$self, $$props) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
const writable_props = []; const writable_props = [];
Object.keys($$props).forEach(key => { Object.keys($$props).forEach(key => {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
return []; return [];
} }

@ -1,7 +1,7 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { create_ssr_component, debug, each, escape } from "svelte/internal"; import { create_ssr_component, debug, each, escape } from "svelte/internal";
const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { const Component = create_ssr_component(($$result, $$props, $$bindings, slots) => {
let { things } = $$props; let { things } = $$props;
let { foo } = $$props; let { foo } = $$props;
if ($$props.things === void 0 && $$bindings.things && things !== void 0) $$bindings.things(things); if ($$props.things === void 0 && $$bindings.things && things !== void 0) $$bindings.things(things);

@ -65,6 +65,8 @@ function create_fragment(ctx) {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let { foo } = $$props; let { foo } = $$props;
let bar; let bar;
const writable_props = ["foo"]; const writable_props = ["foo"];
@ -73,9 +75,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
$$self.$$set = $$props => { $$self.$$set = $$props => {
if ("foo" in $$props) $$invalidate(0, foo = $$props.foo); if ("foo" in $$props) $$invalidate(0, foo = $$props.foo);
}; };

@ -67,6 +67,8 @@ function foo() {
} }
function instance($$self, $$props, $$invalidate) { function instance($$self, $$props, $$invalidate) {
let { $$slots: slots = {}, $$scope } = $$props;
validate_slots("Component", slots, []);
let node; let node;
{ {
@ -111,9 +113,6 @@ function instance($$self, $$props, $$invalidate) {
if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console_1.warn(`<Component> was created with unknown prop '${key}'`); if (!~writable_props.indexOf(key) && key.slice(0, 2) !== "$$") console_1.warn(`<Component> was created with unknown prop '${key}'`);
}); });
let { $$slots = {}, $$scope } = $$props;
validate_slots("Component", $$slots, []);
function div_binding($$value) { function div_binding($$value) {
binding_callbacks[$$value ? "unshift" : "push"](() => { binding_callbacks[$$value ? "unshift" : "push"](() => {
node = $$value; node = $$value;

@ -15,7 +15,7 @@ function swipe(node, callback) {
} // TODO implement } // TODO implement
const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { const Component = create_ssr_component(($$result, $$props, $$bindings, slots) => {
onMount(() => { onMount(() => {
console.log("onMount"); console.log("onMount");
}); });

@ -1,7 +1,7 @@
/* generated by Svelte vX.Y.Z */ /* generated by Svelte vX.Y.Z */
import { create_ssr_component } from "svelte/internal"; import { create_ssr_component } from "svelte/internal";
const Component = create_ssr_component(($$result, $$props, $$bindings, $$slots) => { const Component = create_ssr_component(($$result, $$props, $$bindings, slots) => {
return `<div>content</div> return `<div>content</div>
<div>more content</div>`; <div>more content</div>`;

@ -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