mirror of https://github.com/sveltejs/svelte
parent
391455c58e
commit
7e65579817
@ -0,0 +1,41 @@
|
||||
import { noop, insert, detach, FragmentMinimal, SvelteSlotOptions, SvelteComponentOptionsPrivate } from 'svelte/internal';
|
||||
import { SvelteComponent } from '..';
|
||||
|
||||
function create_root_slot_fn(elements: Node[]) {
|
||||
return function (): FragmentMinimal {
|
||||
return {
|
||||
c: noop,
|
||||
|
||||
m: function mount(target, anchor) {
|
||||
elements.forEach(element => {
|
||||
insert(target, element, anchor);
|
||||
});
|
||||
},
|
||||
|
||||
d: function destroy(detaching) {
|
||||
if (detaching) {
|
||||
elements.forEach(detach);
|
||||
}
|
||||
},
|
||||
|
||||
l: noop
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function createSlot(input: Record<string, Node | Node[]>) {
|
||||
const slots: Record<string, Array<ReturnType<typeof create_root_slot_fn>>> = {};
|
||||
for (const key in input) {
|
||||
const nodeOrNodeList = input[key];
|
||||
const nodeList = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
||||
slots[key] = [create_root_slot_fn(nodeList)];
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
export function slot(componentClass: typeof SvelteComponent, options: SvelteSlotOptions): Element[] {
|
||||
const wrapper = document.createElement('div');
|
||||
new componentClass({...options, target: wrapper} as SvelteComponentOptionsPrivate) as any;
|
||||
// @TODO this is a workaround until src/compiler/compile/render_dom/Block.ts is extended to expose created HTML element
|
||||
return Array.from(wrapper.children);
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/* generated by Svelte vX.Y.Z */
|
||||
import {
|
||||
SvelteComponent,
|
||||
append,
|
||||
create_slot,
|
||||
detach,
|
||||
element,
|
||||
init,
|
||||
insert,
|
||||
safe_not_equal,
|
||||
space,
|
||||
transition_in,
|
||||
transition_out,
|
||||
update_slot
|
||||
} from "svelte/internal";
|
||||
|
||||
const get_slot1_slot_changes = dirty => ({});
|
||||
const get_slot1_slot_context = ctx => ({});
|
||||
|
||||
function create_fragment(ctx) {
|
||||
let div;
|
||||
let t;
|
||||
let current;
|
||||
const default_slot_template = /*#slots*/ ctx[1].default;
|
||||
const default_slot = create_slot(default_slot_template, ctx, /*$$scope*/ ctx[0], null);
|
||||
const slot1_slot_template = /*#slots*/ ctx[1].slot1;
|
||||
const slot1_slot = create_slot(slot1_slot_template, ctx, /*$$scope*/ ctx[0], get_slot1_slot_context);
|
||||
|
||||
return {
|
||||
c() {
|
||||
div = element("div");
|
||||
if (default_slot) default_slot.c();
|
||||
t = space();
|
||||
if (slot1_slot) slot1_slot.c();
|
||||
},
|
||||
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(ctx, [dirty]) {
|
||||
if (default_slot) {
|
||||
if (default_slot.p && dirty & /*$$scope*/ 1) {
|
||||
update_slot(default_slot, default_slot_template, ctx, /*$$scope*/ ctx[0], dirty, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (slot1_slot) {
|
||||
if (slot1_slot.p && dirty & /*$$scope*/ 1) {
|
||||
update_slot(slot1_slot, slot1_slot_template, ctx, /*$$scope*/ ctx[0], dirty, get_slot1_slot_changes, get_slot1_slot_context);
|
||||
}
|
||||
}
|
||||
},
|
||||
i(local) {
|
||||
if (current) return;
|
||||
transition_in(default_slot, local);
|
||||
transition_in(slot1_slot, local);
|
||||
current = true;
|
||||
},
|
||||
o(local) {
|
||||
transition_out(default_slot, local);
|
||||
transition_out(slot1_slot, 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: slots = {}, $$scope } = $$props;
|
||||
|
||||
$$self.$$set = $$props => {
|
||||
if ("$$scope" in $$props) $$invalidate(0, $$scope = $$props.$$scope);
|
||||
};
|
||||
|
||||
return [$$scope, slots];
|
||||
}
|
||||
|
||||
class Component extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
init(this, options, instance, create_fragment, safe_not_equal, {});
|
||||
}
|
||||
}
|
||||
|
||||
export default Component;
|
@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<slot />
|
||||
<slot name="slot1" />
|
||||
</div>
|
@ -0,0 +1,52 @@
|
||||
import { createSlot, slot } from 'svelte';
|
||||
|
||||
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';
|
||||
const Nested = require('./nested.svelte').default;
|
||||
return {
|
||||
slots: createSlot({
|
||||
default: default_el,
|
||||
'my-slot': my_slot_els,
|
||||
'another-slot-with-content': another_slot_el,
|
||||
'conditional-slot': conditional_slot_el,
|
||||
'slot-with-content-from-nested': slot(Nested)
|
||||
})
|
||||
};
|
||||
},
|
||||
|
||||
test({ assert, component, target }) {
|
||||
const expectedHtmlWhenSlotIsVisible = `
|
||||
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
|
||||
slot with content from nested: <div>this div is in nested.svelte</div><span>this span is in nested.svelte</span>
|
||||
conditional slot: <div>conditional slot</div>
|
||||
conditional slot with content: default content`;
|
||||
|
||||
assert.htmlEqual(target.innerHTML, expectedHtmlWhenSlotIsVisible);
|
||||
|
||||
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
|
||||
slot with content from nested: <div>this div is in nested.svelte</div><span>this span is in nested.svelte</span>`);
|
||||
|
||||
component.is_slot_visible = true;
|
||||
assert.htmlEqual(target.innerHTML, expectedHtmlWhenSlotIsVisible);
|
||||
// @TODO once src/compiler/compile/render_dom/Block.ts is extended to expose created HTML elements
|
||||
// and nested component can be referenced directly, test mutating nested child props
|
||||
}
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
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>
|
||||
slot with content from nested: <slot name="slot-with-content-from-nested">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>
|
@ -0,0 +1,2 @@
|
||||
<div>this div is in nested.svelte</div>
|
||||
<span>this span is in nested.svelte</span>
|
Loading…
Reference in new issue