add slots option to component constructor options object

pull/2684/head
Anton Samoylov 6 years ago
parent 1d0da9d022
commit b9ad989265

2
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.1.0",
"version": "3.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

@ -617,6 +617,7 @@ The following initialisation options can be provided:
| `props` | `{}` | An object of properties to supply to the component
| `hydrate` | `false` | See below
| `intro` | `false` | If `true`, will play transitions on initial render, rather than waiting for subsequent state changes
| `slots` | `{}` | An object with keys - slot names, values - element or array of elements
Existing children of `target` are left where they are.

@ -468,11 +468,21 @@ export default function dom(
} else {
const superclass = options.dev ? 'SvelteComponentDev' : 'SvelteComponent';
let slots_block = '';
if (component.slots.size > 0) {
slots_block = '\n' + deindent`
if (options.slots) {
options.props = options.props || {};
options.props.$$scope = {};
options.props.$$slots = @create_root_component_slots(options.slots);
}`;
}
builder.add_block(deindent`
class ${name} extends @${superclass} {
constructor(options) {
super(${options.dev && `options`});
${should_add_css && `if (!document.getElementById("${component.stylesheet.id}-style")) @add_css();`}
${should_add_css && `if (!document.getElementById("${component.stylesheet.id}-style")) @add_css();`}${slots_block}
@init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names});
${dev_props_check}

@ -1,3 +1,5 @@
import { insert, detach } from './dom';
export function noop() {}
export const identity = x => x;
@ -79,3 +81,37 @@ export function exclude_internal_props(props) {
for (const k in props) if (k[0] !== '$') result[k] = props[k];
return result;
}
function create_root_component_slot_fn(elements) {
return function create_root_component_slot() {
return {
c: noop,
m: function mount(target, anchor) {
elements.forEach(element => {
insert(target, element, anchor);
});
},
d: function destroy(detaching) {
if (detaching) {
elements.forEach(element => detach(element));
}
},
l: noop,
};
};
}
export function create_root_component_slots(slots) {
const root_component_slots = {};
for (const slot_name in slots) {
let elements = slots[slot_name];
if (!Array.isArray(elements)) {
elements = [elements];
}
root_component_slots[slot_name] = [create_root_component_slot_fn(elements)];
}
return root_component_slots;
}

@ -0,0 +1,118 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
append,
create_root_component_slots,
create_slot,
detach,
element,
get_slot_changes,
get_slot_context,
init,
insert,
safe_not_equal,
space
} from "svelte/internal";
const get_slot1_slot_changes = ({}) => ({});
const get_slot1_slot_context = ({}) => ({});
function create_fragment(ctx) {
var div, t, current;
const default_slot_1 = ctx.$$slots.default;
const default_slot = create_slot(default_slot_1, ctx, null);
const slot1_slot_1 = ctx.$$slots.slot1;
const slot1_slot = create_slot(slot1_slot_1, ctx, get_slot1_slot_context);
return {
c() {
div = element("div");
if (default_slot) default_slot.c();
t = space();
if (slot1_slot) slot1_slot.c();
},
l(nodes) {
if (default_slot) default_slot.l(div_nodes);
if (slot1_slot) slot1_slot.l(div_nodes);
},
m(target, anchor) {
insert(target, div, anchor);
if (default_slot) {
default_slot.m(div, null);
}
append(div, t);
if (slot1_slot) {
slot1_slot.m(div, null);
}
current = true;
},
p(changed, ctx) {
if (default_slot && default_slot.p && changed.$$scope) {
default_slot.p(get_slot_changes(default_slot_1, ctx, changed,), get_slot_context(default_slot_1, ctx, null));
}
if (slot1_slot && slot1_slot.p && changed.$$scope) {
slot1_slot.p(get_slot_changes(slot1_slot_1, ctx, changed, get_slot1_slot_changes), get_slot_context(slot1_slot_1, ctx, get_slot1_slot_context));
}
},
i(local) {
if (current) return;
if (default_slot && default_slot.i) default_slot.i(local);
if (slot1_slot && slot1_slot.i) slot1_slot.i(local);
current = true;
},
o(local) {
if (default_slot && default_slot.o) default_slot.o(local);
if (slot1_slot && slot1_slot.o) slot1_slot.o(local);
current = false;
},
d(detaching) {
if (detaching) {
detach(div);
}
if (default_slot) default_slot.d(detaching);
if (slot1_slot) slot1_slot.d(detaching);
}
};
}
function instance($$self, $$props, $$invalidate) {
let { $$slots = {}, $$scope } = $$props;
$$self.$set = $$props => {
if ('$$scope' in $$props) $$invalidate('$$scope', $$scope = $$props.$$scope);
};
return { $$slots, $$scope };
}
class Component extends SvelteComponent {
constructor(options) {
super();
if (options.slots) {
options.props = options.props || {};
options.props.$$scope = {};
options.props.$$slots = create_root_component_slots(options.slots);
}
init(this, options, instance, create_fragment, safe_not_equal, []);
}
}
export default Component;

@ -0,0 +1,4 @@
<div>
<slot />
<slot name="slot1" />
</div>

@ -134,12 +134,13 @@ describe("runtime", () => {
warnings.push(warning);
};
const configOptions = typeof config.options === 'function' ? config.options(window) : config.options;
const options = Object.assign({}, {
target,
hydrate,
props: config.props,
intro: config.intro
}, config.options || {});
}, configOptions || {});
const component = new SvelteComponent(options);

@ -0,0 +1,48 @@
export default {
options(window) {
const default_el = window.document.createElement('div');
default_el.innerHTML = 'default slot custom content';
const my_slot_el1 = window.document.createElement('div');
my_slot_el1.innerHTML = 'first my slot element';
const my_slot_el2 = window.document.createElement('div');
my_slot_el2.innerHTML = 'second my slot element';
const my_slot_els = [my_slot_el1, my_slot_el2];
const another_slot_el = window.document.createTextNode('another slot');
const conditional_slot_el = window.document.createElement('div');
conditional_slot_el.innerHTML = 'conditional slot';
return {
slots: {
default: default_el,
'my-slot': my_slot_els,
'another-slot-with-content': another_slot_el,
'conditional-slot': conditional_slot_el,
},
};
},
test({ assert, component, target }) {
assert.htmlEqual(target.innerHTML, `
default slot: <div>default slot custom content</div>
named slot: <div>first my slot element</div><div>second my slot element</div>
slot with default content: default content
another slot with content: another slot
conditional slot: <div>conditional slot</div>
conditional slot with content: default content`);
component.is_slot_visible = false;
assert.htmlEqual(target.innerHTML, `
default slot: <div>default slot custom content</div>
named slot: <div>first my slot element</div><div>second my slot element</div>
slot with default content: default content
another slot with content: another slot`);
component.is_slot_visible = true;
assert.htmlEqual(target.innerHTML, `
default slot: <div>default slot custom content</div>
named slot: <div>first my slot element</div><div>second my slot element</div>
slot with default content: default content
another slot with content: another slot
conditional slot: <div>conditional slot</div>
conditional slot with content: default content`);
}
};

@ -0,0 +1,11 @@
default slot: <slot />
named slot: <slot name="my-slot" />
slot with default content: <slot name="slot-with-content">default content</slot>
another slot with content: <slot name="another-slot-with-content">default content</slot>
{#if is_slot_visible}
conditional slot: <slot name="conditional-slot" />
conditional slot with content: <slot name="conditional-slot-with-content">default content</slot>
{/if}
<script>
export let is_slot_visible = true;
</script>
Loading…
Cancel
Save