From 7949d8efac308123c5b2e770456d36a680ce9bba Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 9 Nov 2020 23:11:37 +0800 Subject: [PATCH] support $$slots in custom elements (#5619) --- CHANGELOG.md | 1 + 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 +++++++++++++++++ 5 files changed, 76 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/CHANGELOG.md b/CHANGELOG.md index b93a6a7fd..b36b4357d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Fix function calls in `` 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 diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 024aafde1..2f86202a3 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 ad06d6ff0..91e575ebf 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; +} diff --git a/test/custom-elements/samples/$$slot/main.svelte b/test/custom-elements/samples/$$slot/main.svelte new file mode 100644 index 000000000..05e1ac328 --- /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 000000000..567e93f50 --- /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'); +}