Skip to content

Commit

Permalink
support $$props and $$restProps for custom elements (#5608)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanhauhau authored Oct 28, 2020
1 parent 0ca36a1 commit 6fa3e91
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/compile/render_dom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,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 }, ${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}
Expand Down
8 changes: 8 additions & 0 deletions src/runtime/internal/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
21 changes: 21 additions & 0 deletions test/custom-elements/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]+</g, '><')
.trim();
return node.innerHTML.replace(/<\/?noscript\/?>/g, '');
} catch (err) {
throw new Error(`Failed to normalize HTML:\n${html}`);
}
}
10 changes: 10 additions & 0 deletions test/custom-elements/samples/$$props/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<svelte:options tag="custom-element"/>

<script>
export let name;
</script>

<p>name: {name}</p>
<p>$$props: {JSON.stringify($$props)}</p>
<p>$$restProps: {JSON.stringify($$restProps)}</p>

13 changes: 13 additions & 0 deletions test/custom-elements/samples/$$props/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as assert from 'assert';
import './main.svelte';

export default function (target) {
target.innerHTML = '<custom-element name="world" answer="42" test="svelte"></custom-element>';
const el = target.querySelector('custom-element');

assert.htmlEqual(el.shadowRoot.innerHTML, `
<p>name: world</p>
<p>$$props: {"name":"world","answer":"42","test":"svelte"}</p>
<p>$$restProps: {"answer":"42","test":"svelte"}</p>
`);
}
14 changes: 13 additions & 1 deletion test/js/samples/css-shadow-dom-keyframes/expected.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteElement,
attribute_to_object,
detach,
element,
init,
Expand Down Expand Up @@ -34,7 +35,18 @@ class Component extends SvelteElement {
constructor(options) {
super();
this.shadowRoot.innerHTML = `<style>div{animation:foo 1s}@keyframes foo{0%{opacity:0}100%{opacity:1}}</style>`;
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) {
Expand Down

0 comments on commit 6fa3e91

Please sign in to comment.