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
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..ad06d6ff0829 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;
+}
diff --git a/test/custom-elements/assert.js b/test/custom-elements/assert.js
index b8add0dadc22..4ee8d9dda034 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}`);
+ }
+}
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 = '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) {