support $$slots in custom elements (#5619)

pull/5660/head
Tan Li Hau 4 years ago committed by GitHub
parent f7bddb23d3
commit 7949d8efac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,6 +6,7 @@
* Fix function calls in `<slot>` props that use contextual values ([#5565](https://github.com/sveltejs/svelte/issues/5565))
* Fix handling aborted transitions in `{:else}` blocks ([#5573](https://github.com/sveltejs/svelte/issues/5573))
* Add `Element` and `Node` to known globals ([#5586](https://github.com/sveltejs/svelte/issues/5586))
* Fix `$$slots` when compiling to custom elements ([#5594](https://github.com/sveltejs/svelte/issues/5594))
* Fix internal `import`s so that we're exposing a valid ES module ([#5617](https://github.com/sveltejs/svelte/issues/5617))
## 3.29.4

@ -467,6 +467,12 @@ export default function dom(
}
if (options.customElement) {
let init_props = x`@attribute_to_object(this.attributes)`;
if (uses_slots) {
init_props = x`{ ...${init_props}, $$slots: @get_custom_elements_slots(this) }`;
}
const declaration = b`
class ${name} extends @SvelteElement {
constructor(options) {
@ -474,7 +480,7 @@ export default function dom(
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}
@init(this, { target: this.shadowRoot, props: @attribute_to_object(this.attributes) }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
@init(this, { target: this.shadowRoot, props: ${init_props} }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
${dev_props_check}

@ -361,10 +361,18 @@ export class HtmlTag {
}
}
export function attribute_to_object(attributes) {
export function attribute_to_object(attributes: NamedNodeMap) {
const result = {};
for (const attribute of attributes) {
result[attribute.name] = attribute.value;
}
return result;
}
export function get_custom_elements_slots(element: HTMLElement) {
const result = {};
element.childNodes.forEach((node: Element) => {
result[node.slot || 'default'] = true;
});
return result;
}

@ -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>
<svelte:options tag="custom-element"/>
<slot></slot>
<slot name="a"></slot>
<p>$$slots: {toString($$slots)}</p>
{#if $$slots.b}
<div>
<slot name="b"></slot>
</div>
{:else}
<p>Slot b is not available</p>
{/if}

@ -0,0 +1,28 @@
import * as assert from 'assert';
import './main.svelte';
export default function (target) {
target.innerHTML = `
<custom-element><span slot="a">hello world</span><span>bye</span><span>world</span></custom-element>
<custom-element><span slot="a">hello world</span><span slot="b">hello world</span><span>bye world</span></custom-element>
`;
const [a, b] = target.querySelectorAll('custom-element');
assert.htmlEqual(a.shadowRoot.innerHTML, `
<slot></slot>
<slot name="a"></slot>
<p>$$slots: {"a":true,"default":true}</p>
<p>Slot b is not available</p>
`);
assert.htmlEqual(b.shadowRoot.innerHTML, `
<slot></slot>
<slot name="a"></slot>
<p>$$slots: {"a":true,"b":true,"default":true}</p>
<div><slot name="b"></slot></div>
`);
assert.equal(a.getData(), '');
assert.equal(b.getData(), 'foo');
}
Loading…
Cancel
Save