diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts
index 3b5001d483..5b4b47895e 100644
--- a/src/compiler/compile/render_dom/index.ts
+++ b/src/compiler/compile/render_dom/index.ts
@@ -90,8 +90,8 @@ export default function dom(
${uses_rest && !uses_props && x`$$props = @assign(@assign({}, $$props), @exclude_internal_props($$new_props))`}
${uses_rest && renderer.invalidate('$$restProps', x`$$restProps = ${compute_rest}`)}
${writable_props.map(prop =>
- b`if ('${prop.export_name}' in ${$$props}) ${renderer.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.export_name}`)};`
- )}
+ b`if ('${prop.export_name}' in ${$$props}) ${renderer.invalidate(prop.name, x`${prop.name} = ${$$props}.${prop.export_name}`)};`
+ )}
${component.slots.size > 0 &&
b`if ('$$scope' in ${$$props}) ${renderer.invalidate('$$scope', x`$$scope = ${$$props}.$$scope`)};`}
}
@@ -190,8 +190,8 @@ export default function dom(
${$$props} => {
${uses_props && renderer.invalidate('$$props', x`$$props = @assign(@assign({}, $$props), $$new_props)`)}
${injectable_vars.map(
- v => b`if ('${v.name}' in $$props) ${renderer.invalidate(v.name, x`${v.name} = ${$$props}.${v.name}`)};`
- )}
+ v => b`if ('${v.name}' in $$props) ${renderer.invalidate(v.name, x`${v.name} = ${$$props}.${v.name}`)};`
+ )}
}
`;
@@ -462,10 +462,15 @@ export default function dom(
class ${name} extends @SvelteElement {
constructor(options) {
super();
-
+ if (options) {
+ this.$$runSetup(options);
+ }
+ }
+ $$setup(options) {
+ console.log("$$setup");
${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, { props: options ? options.props : null, target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
${dev_props_check}
diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts
index c0f6facdd2..f1334c791d 100644
--- a/src/runtime/internal/Component.ts
+++ b/src/runtime/internal/Component.ts
@@ -171,7 +171,32 @@ if (typeof HTMLElement === 'function') {
this.attachShadow({ mode: 'open' });
}
+ $$initialProps: Record | null = {};
+ $$options: Record | null = {};
+ $$setup(_options) {
+ // overridden by instance
+ }
+
+ $$runSetup(options?: Record) {
+ console.log("$$runSetup");
+ const {$$initialProps} = this;
+ if ($$initialProps) {
+ const opts = (options || this.$$options);
+ this.$$initialProps = null;
+ this.$$options = null;
+ this.$$setup({
+ ...opts,
+ props: {
+ ...opts.props,
+ ...$$initialProps
+ }
+ });
+ }
+ }
+
connectedCallback() {
+ console.log("connectedCallback");
+ this.$$runSetup();
// @ts-ignore todo: improve typings
for (const key in this.$$.slotted) {
// @ts-ignore todo: improve typings
@@ -179,7 +204,12 @@ if (typeof HTMLElement === 'function') {
}
}
+ // initial implementation of method, will be overridden on setup
attributeChangedCallback(attr, _oldValue, newValue) {
+ console.log(`attributeChangedCallback: ${attr}, ${newValue}`);
+ if (this.$$initialProps) {
+ this.$$initialProps[attr] = newValue;
+ }
this[attr] = newValue;
}
@@ -199,7 +229,12 @@ if (typeof HTMLElement === 'function') {
};
}
- $set() {
+ $set(obj) {
+ if (this.$$initialProps && obj) {
+ for (const attr of Object.getOwnPropertyNames(obj)) {
+ this.$$initialProps[attr] = obj[attr];
+ }
+ }
// overridden by instance, if it has props
}
};
diff --git a/test/custom-elements/samples/props-after-create/main.svelte b/test/custom-elements/samples/props-after-create/main.svelte
new file mode 100644
index 0000000000..22c91751d0
--- /dev/null
+++ b/test/custom-elements/samples/props-after-create/main.svelte
@@ -0,0 +1,8 @@
+
+
+
+
+{items.length} items
+{items.join(', ')}
diff --git a/test/custom-elements/samples/props-after-create/test.js b/test/custom-elements/samples/props-after-create/test.js
new file mode 100644
index 0000000000..a9e08c168e
--- /dev/null
+++ b/test/custom-elements/samples/props-after-create/test.js
@@ -0,0 +1,23 @@
+import * as assert from 'assert';
+import CustomElement from './main.svelte';
+
+export default async function (target) {
+ const el = new CustomElement();
+
+ assert.equal(el.outerHTML, '');
+
+ // const el = target.querySelector('custom-element');
+
+ assert.equal(el.shadowRoot, undefined);
+
+ el.items = ['a', 'b', 'c'];
+ const [p1, p2] = el.shadowRoot.querySelectorAll('p');
+
+ assert.equal(p1.textContent, '3 items');
+ assert.equal(p2.textContent, 'a, b, c');
+
+ el.items = ['d', 'e', 'f', 'g', 'h'];
+
+ assert.equal(p1.textContent, '5 items');
+ assert.equal(p2.textContent, 'd, e, f, g, h');
+}
diff --git a/test/custom-elements/samples/props/test.js b/test/custom-elements/samples/props/test.js
index 9c7e44c3a3..f5e12e0a55 100644
--- a/test/custom-elements/samples/props/test.js
+++ b/test/custom-elements/samples/props/test.js
@@ -1,7 +1,7 @@
import * as assert from 'assert';
import CustomElement from './main.svelte';
-export default function (target) {
+export default async function (target) {
new CustomElement({
target
});
@@ -9,8 +9,15 @@ export default function (target) {
assert.equal(target.innerHTML, '');
const el = target.querySelector('custom-element');
+
+ // await new Promise((resolve) => setTimeout(resolve, 100));
+ // await new Promise((resolve) => setTimeout(resolve, 100));
const widget = el.shadowRoot.querySelector('my-widget');
+ console.log(widget);
+
+ // await new Promise((resolve) => setTimeout(resolve, 100));
+
const [p1, p2] = widget.shadowRoot.querySelectorAll('p');
assert.equal(p1.textContent, '3 items');
@@ -20,4 +27,4 @@ export default function (target) {
assert.equal(p1.textContent, '5 items');
assert.equal(p2.textContent, 'd, e, f, g, h');
-}
\ No newline at end of file
+}