diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 2af546dd4d..a934c426c6 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -54,8 +54,6 @@ export default class Component { event_handlers: Array<{ name: string, body: string }>; props: string[]; - refCallees: Node[]; - code: MagicString; indirectDependencies: Map>; @@ -97,7 +95,6 @@ export default class Component { this.event_handlers = []; this.refs = new Set(); - this.refCallees = []; this.indirectDependencies = new Map(); diff --git a/src/compile/render-dom/index.ts b/src/compile/render-dom/index.ts index 85728c014f..3d303bf306 100644 --- a/src/compile/render-dom/index.ts +++ b/src/compile/render-dom/index.ts @@ -12,10 +12,7 @@ export default function dom( ) { const format = options.format || 'es'; - const { - name, - templateProperties - } = component; + const { name } = component; const renderer = new Renderer(component, options); diff --git a/src/compile/render-dom/wrappers/InlineComponent/index.ts b/src/compile/render-dom/wrappers/InlineComponent/index.ts index cbed70b03c..447e9c5c42 100644 --- a/src/compile/render-dom/wrappers/InlineComponent/index.ts +++ b/src/compile/render-dom/wrappers/InlineComponent/index.ts @@ -192,63 +192,7 @@ export default class InlineComponentWrapper extends Wrapper { name_updating = block.alias(`${name}_updating`); block.addVariable(name_updating, '{}'); - let hasLocalBindings = false; - let hasStoreBindings = false; - - const builder = new CodeBuilder(); - this.node.bindings.forEach((binding: Binding) => { - let { name: key } = getObject(binding.expression.node); - - let setFromChild; - - if (binding.isContextual) { - const computed = isComputed(binding.expression.node); - const tail = binding.expression.node.type === 'MemberExpression' ? getTailSnippet(binding.expression.node) : ''; - - const { object, property, snippet } = block.bindings.get(key)(); - - const lhs = binding.expression.node.type === 'MemberExpression' - ? binding.expression.snippet - : `${snippet} = childState${quotePropIfNecessary(binding.name)}`; - - setFromChild = deindent` - ${lhs} = childState${quotePropIfNecessary(binding.name)}; - - ${[...binding.expression.dependencies] - .map((name: string) => { - const isStoreProp = name[0] === '$'; - const prop = isStoreProp ? name.slice(1) : name; - const newState = isStoreProp ? 'newStoreState' : 'newState'; - - if (isStoreProp) hasStoreBindings = true; - else hasLocalBindings = true; - - return `${newState}${quotePropIfNecessary(prop)} = ctx${quotePropIfNecessary(name)};`; - })} - `; - } - - else { - const isStoreProp = key[0] === '$'; - const prop = isStoreProp ? key.slice(1) : key; - const newState = isStoreProp ? 'newStoreState' : 'newState'; - - if (isStoreProp) hasStoreBindings = true; - else hasLocalBindings = true; - - if (binding.expression.node.type === 'MemberExpression') { - setFromChild = deindent` - ${binding.expression.snippet} = childState${quotePropIfNecessary(binding.name)}; - ${newState}${quotePropIfNecessary(prop)} = ctx${quotePropIfNecessary(key)}; - `; - } - - else { - setFromChild = `${newState}${quotePropIfNecessary(prop)} = childState${quotePropIfNecessary(binding.name)};`; - } - } - statements.push(deindent` if (${binding.expression.snippet} !== void 0) { ${name_initial_data}${quotePropIfNecessary(binding.name)} = ${binding.expression.snippet}; @@ -256,11 +200,6 @@ export default class InlineComponentWrapper extends Wrapper { }` ); - builder.addConditional( - `!${name_updating}${quotePropIfNecessary(binding.name)} && changed${quotePropIfNecessary(binding.name)}`, - setFromChild - ); - updates.push(deindent` if (!${name_updating}${quotePropIfNecessary(binding.name)} && ${[...binding.expression.dependencies].map((dependency: string) => `changed.${dependency}`).join(' || ')}) { ${name_changes}${quotePropIfNecessary(binding.name)} = ${binding.expression.snippet}; @@ -270,27 +209,6 @@ export default class InlineComponentWrapper extends Wrapper { }); block.maintainContext = true; // TODO put this somewhere more logical - - const initialisers = [ - hasLocalBindings && 'newState = {}', - hasStoreBindings && 'newStoreState = {}', - ].filter(Boolean).join(', '); - - // TODO use component.$on('state', ...) instead of _bind - componentInitProperties.push(deindent` - _bind(changed, childState) { - var ${initialisers}; - ${builder} - ${hasLocalBindings && `#component.$set(newState);`} - ${name_updating} = {}; - } - `); - - beforecreate = deindent` - #component.$$root._beforecreate.push(() => { - ${name}._bind({ ${this.node.bindings.map(b => `${quoteNameIfNecessary(b.name)}: 1`).join(', ')} }, ${name}.get()); - }); - `; } this.node.handlers.forEach(handler => { @@ -495,6 +413,31 @@ export default class InlineComponentWrapper extends Wrapper { `); } + this.node.bindings.forEach(binding => { + const binding_name = component.getUniqueName(`${this.var}_${binding.name}_binding`); + + if (binding.expression.contextual_dependencies.size > 0) { + throw new Error(`TODO bindings with contextual dependencies`); + } else { + const lhs = component.source.slice(binding.expression.node.start, binding.expression.node.end); + const deps = Array.from(binding.expression.dependencies); + + component.event_handlers.push({ + name: binding_name, + body: deindent` + function ${binding_name}(value) { + ${lhs} = value; + ${deps.map(dep => `$$make_dirty('${dep}');`)} + } + ` + }); + + block.builders.init.addBlock(deindent` + ${this.var}.$$bind('${binding.name}', ctx.${binding_name}); + `); + } + }); + if (component.options.nestedTransitions) { block.builders.outro.addLine( `if (${name}) ${name}.$$fragment.o(#outrocallback);` diff --git a/src/internal/SvelteComponent.js b/src/internal/SvelteComponent.js index 5bd57d3c86..63f739eb69 100644 --- a/src/internal/SvelteComponent.js +++ b/src/internal/SvelteComponent.js @@ -10,12 +10,16 @@ export class SvelteComponent { this.$$onupdate = []; this.$$ondestroy = []; + this.$$bindings = blankObject(); this.$$callbacks = blankObject(); this.$$slotted = options.slots; set_current_component(this); const [get_state, inject_props, inject_refs] = this.$$init( - key => this.$$make_dirty(key) + key => { + this.$$make_dirty(key); + if (this.$$bindings[key]) this.$$bindings[key](get_state()[key]); + } ); this.$$ = { get_state, inject_props, inject_refs }; @@ -39,6 +43,10 @@ export class SvelteComponent { } } + $destroy() { + this.$$destroy(true); + } + $on(type, callback) { const callbacks = (this.$$callbacks[type] || (this.$$callbacks[type] = [])); callbacks.push(callback); @@ -49,8 +57,28 @@ export class SvelteComponent { }; } - $destroy() { - this.$$destroy(true); + $set(values) { + if (this.$$) { + this.$$.inject_props(values); + run_all(this.$$onprops); + + for (const key in values) this.$$make_dirty(key); + } + } + + $$bind(name, callback) { + this.$$bindings[name] = callback; + callback(this.$$.get_state()[name]); + } + + $$destroy(detach) { + if (this.$$) { + this.$$fragment.d(detach); + run_all(this.$$ondestroy); + + // TODO null out other refs + this.$$ondestroy = this.$$fragment = this.$$ = null; + } } $$make_dirty(key) { @@ -71,29 +99,10 @@ export class SvelteComponent { this.$$onmount = []; } - $set(values) { - if (this.$$) { - this.$$.inject_props(values); - run_all(this.$$onprops); - - for (const key in values) this.$$make_dirty(key); - } - } - $$update() { this.$$fragment.p(this.$$dirty, this.$$.get_state()); this.$$.inject_refs(this.$$refs); run_all(this.$$onupdate); this.$$dirty = null; } - - $$destroy(detach) { - if (this.$$) { - this.$$fragment.d(detach); - run_all(this.$$ondestroy); - - // TODO null out other refs - this.$$ondestroy = this.$$fragment = this.$$ = null; - } - } } \ No newline at end of file diff --git a/test/runtime/index.js b/test/runtime/index.js index 39778e0f04..29ea434e92 100644 --- a/test/runtime/index.js +++ b/test/runtime/index.js @@ -118,7 +118,7 @@ describe.only("runtime", () => { try { SvelteComponent = require(`./samples/${dir}/main.html`); } catch (err) { - showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile); // eslint-disable-line no-console + showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, svelte.compile); // eslint-disable-line no-console throw err; } @@ -187,7 +187,7 @@ describe.only("runtime", () => { skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions, dev: compileOptions.dev - }, compile); // eslint-disable-line no-console + }, svelte.compile); // eslint-disable-line no-console throw err; } }) @@ -199,7 +199,7 @@ describe.only("runtime", () => { hydratable: hydrate, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions - }, compile); + }, svelte.compile); } flush(); diff --git a/test/runtime/samples/component-binding/_config.js b/test/runtime/samples/component-binding/_config.js index e773226ba9..d16976e8bc 100644 --- a/test/runtime/samples/component-binding/_config.js +++ b/test/runtime/samples/component-binding/_config.js @@ -6,11 +6,11 @@ export default {

count: 0

`, - test(assert, component, target, window) { + async test(assert, component, target, window) { const click = new window.MouseEvent('click'); const button = target.querySelector('button'); - button.dispatchEvent(click); + await button.dispatchEvent(click); assert.equal(component.x, 1); assert.htmlEqual(target.innerHTML, ` @@ -18,7 +18,7 @@ export default {

count: 1

`); - button.dispatchEvent(click); + await button.dispatchEvent(click); assert.equal(component.x, 2); assert.htmlEqual(target.innerHTML, `