From cf90e2326d5abdb3955d931a74067a718ff07175 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 31 Oct 2020 00:28:56 +0800 Subject: [PATCH] support $$slots in custom elements --- src/compiler/compile/render_dom/index.ts | 8 ++++- src/runtime/internal/dom.ts | 10 +++++- .../samples/$$slot/main.svelte | 31 +++++++++++++++++++ test/custom-elements/samples/$$slot/test.js | 28 +++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 test/custom-elements/samples/$$slot/main.svelte create mode 100644 test/custom-elements/samples/$$slot/test.js diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 024aafde14a0..2f86202a34c2 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -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 = \`\`;`} - @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} diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index ad06d6ff0829..c8edf2674f62 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -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; +} \ No newline at end of file diff --git a/test/custom-elements/samples/$$slot/main.svelte b/test/custom-elements/samples/$$slot/main.svelte new file mode 100644 index 000000000000..05e1ac328443 --- /dev/null +++ b/test/custom-elements/samples/$$slot/main.svelte @@ -0,0 +1,31 @@ + + + + + + +

$$slots: {toString($$slots)}

+{#if $$slots.b} +
+ +
+{:else} +

Slot b is not available

+{/if} \ No newline at end of file diff --git a/test/custom-elements/samples/$$slot/test.js b/test/custom-elements/samples/$$slot/test.js new file mode 100644 index 000000000000..567e93f509e9 --- /dev/null +++ b/test/custom-elements/samples/$$slot/test.js @@ -0,0 +1,28 @@ +import * as assert from 'assert'; +import './main.svelte'; + +export default function (target) { + target.innerHTML = ` + hello worldbyeworld + hello worldhello worldbye world + `; + + const [a, b] = target.querySelectorAll('custom-element'); + + assert.htmlEqual(a.shadowRoot.innerHTML, ` + + +

$$slots: {"a":true,"default":true}

+

Slot b is not available

+ `); + + assert.htmlEqual(b.shadowRoot.innerHTML, ` + + +

$$slots: {"a":true,"b":true,"default":true}

+
+ `); + + assert.equal(a.getData(), ''); + assert.equal(b.getData(), 'foo'); +}