From 4db8dd48032873ac038f279e88852eade387f112 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Thu, 29 Oct 2020 00:59:02 +0800 Subject: [PATCH 1/3] support $$props and $$restProps for custom elements --- src/compiler/compile/render_dom/index.ts | 2 +- src/runtime/internal/dom.ts | 8 +++++++ test/custom-elements/assert.js | 21 +++++++++++++++++++ .../samples/$$props/main.svelte | 10 +++++++++ test/custom-elements/samples/$$props/test.js | 13 ++++++++++++ .../css-shadow-dom-keyframes/expected.js | 14 ++++++++++++- 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 test/custom-elements/samples/$$props/main.svelte create mode 100644 test/custom-elements/samples/$$props/test.js diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 6380843b8712..024aafde14a0 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -474,7 +474,7 @@ export default function dom( ${css.code && b`this.shadowRoot.innerHTML = \`\`;`} - @init(this, { target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty}); + @init(this, { target: this.shadowRoot, props: @attribute_to_object(this.attributes) }, ${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 5380443fbc0a..830bc6abd186 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -360,3 +360,11 @@ export class HtmlTag { this.n.forEach(detach); } } + +export function attribute_to_object(attributes) { + const result = {}; + for (const attribute of attributes) { + result[attribute.name] = attribute.value; + } + return result; +} \ No newline at end of file diff --git a/test/custom-elements/assert.js b/test/custom-elements/assert.js index b8add0dadc22..474c314da983 100644 --- a/test/custom-elements/assert.js +++ b/test/custom-elements/assert.js @@ -31,3 +31,24 @@ export function equal(a, b, message) { export function ok(condition, message) { if (!condition) throw new Error(message || `Expected ${condition} to be truthy`); } + +export function htmlEqual(actual, expected, message) { + return deepEqual( + normalizeHtml(window, actual), + normalizeHtml(window, expected), + message + ); +} + +function normalizeHtml(window, html) { + try { + const node = window.document.createElement('div'); + node.innerHTML = html + .replace(//g, '') + .replace(/>[\s\r\n]+<') + .trim(); + return node.innerHTML.replace(/<\/?noscript\/?>/g, ''); + } catch (err) { + throw new Error(`Failed to normalize HTML:\n${html}`); + } +} \ No newline at end of file diff --git a/test/custom-elements/samples/$$props/main.svelte b/test/custom-elements/samples/$$props/main.svelte new file mode 100644 index 000000000000..68931e22db79 --- /dev/null +++ b/test/custom-elements/samples/$$props/main.svelte @@ -0,0 +1,10 @@ + + + + +

name: {name}

+

$$props: {JSON.stringify($$props)}

+

$$restProps: {JSON.stringify($$restProps)}

+ diff --git a/test/custom-elements/samples/$$props/test.js b/test/custom-elements/samples/$$props/test.js new file mode 100644 index 000000000000..94cad865778c --- /dev/null +++ b/test/custom-elements/samples/$$props/test.js @@ -0,0 +1,13 @@ +import * as assert from 'assert'; +import './main.svelte'; + +export default function (target) { + target.innerHTML = ''; + const el = target.querySelector('custom-element'); + + assert.htmlEqual(el.shadowRoot.innerHTML, ` +

name: world

+

$$props: {"name":"world","answer":"42","test":"svelte"}

+

$$restProps: {"answer":"42","test":"svelte"}

+ `); +} diff --git a/test/js/samples/css-shadow-dom-keyframes/expected.js b/test/js/samples/css-shadow-dom-keyframes/expected.js index a0a0ebe0211b..82a39e5924ff 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteElement, + attribute_to_object, detach, element, init, @@ -34,7 +35,18 @@ class Component extends SvelteElement { constructor(options) { super(); this.shadowRoot.innerHTML = ``; - init(this, { target: this.shadowRoot }, null, create_fragment, safe_not_equal, {}); + + init( + this, + { + target: this.shadowRoot, + props: attribute_to_object(this.attributes) + }, + null, + create_fragment, + safe_not_equal, + {} + ); if (options) { if (options.target) { From fd437f7ee58e14c12799e3942b75e4b3d63428de Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 28 Oct 2020 15:15:43 -0400 Subject: [PATCH 2/3] lint --- src/runtime/internal/dom.ts | 2 +- test/custom-elements/assert.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/internal/dom.ts b/src/runtime/internal/dom.ts index 830bc6abd186..ad06d6ff0829 100644 --- a/src/runtime/internal/dom.ts +++ b/src/runtime/internal/dom.ts @@ -367,4 +367,4 @@ export function attribute_to_object(attributes) { result[attribute.name] = attribute.value; } return result; -} \ No newline at end of file +} diff --git a/test/custom-elements/assert.js b/test/custom-elements/assert.js index 474c314da983..4ee8d9dda034 100644 --- a/test/custom-elements/assert.js +++ b/test/custom-elements/assert.js @@ -51,4 +51,4 @@ function normalizeHtml(window, html) { } catch (err) { throw new Error(`Failed to normalize HTML:\n${html}`); } -} \ No newline at end of file +} From b31c6526fda9a869220ab8374f1d6918e74028e4 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Wed, 28 Oct 2020 15:16:45 -0400 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9239ed8ca55b..cfff198368ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +* Fix `$$props` and `$$restProps` when compiling to a custom element ([#5482](https://github.com/sveltejs/svelte/issues/5482)) * Add `Element` and `Node` to known globals ([#5586](https://github.com/sveltejs/svelte/issues/5586)) ## 3.29.4