From 6c3c3bbf2a101eb9facf705589bf0f7f73da5001 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 18 Nov 2019 14:47:12 -0500 Subject: [PATCH] component bindings etc --- .../compile/nodes/shared/Expression.ts | 2 +- src/compiler/compile/render_dom/Renderer.ts | 2 +- src/compiler/compile/render_dom/index.ts | 10 +++---- .../wrappers/InlineComponent/index.ts | 30 +++++++++---------- .../compile/render_dom/wrappers/Window.ts | 12 +++++--- .../render_dom/wrappers/shared/bind_this.ts | 6 ++-- .../compile/render_ssr/handlers/Element.ts | 2 +- src/runtime/internal/Component.ts | 6 ++-- 8 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts index 0b4e9624f0..3890146550 100644 --- a/src/compiler/compile/nodes/shared/Expression.ts +++ b/src/compiler/compile/nodes/shared/Expression.ts @@ -332,7 +332,7 @@ export default class Expression { } }); - this.replace(invalidate(block.renderer, scope, node, traced, false)); + this.replace(invalidate(block.renderer, scope, node, traced)); } } }); diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 76500bef1d..a50e78662f 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -138,7 +138,7 @@ export default class Renderer { .reduce((lhs, rhs) => x`${lhs}, ${rhs}}`); } - changed(names, needs_update) { + changed(names, needs_update = false) { const bitmask = names.reduce((bits, name) => { const bit = 1 << this.context_lookup.get(name); return bits | bit; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 9f67eb2504..54303fd334 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -160,7 +160,7 @@ export default function dom( const { ctx: #ctx } = this.$$; const props = ${options.customElement ? x`this.attributes` : x`options.props || {}`}; ${expected.map(prop => b` - if (#ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) { + if (${renderer.reference(prop.name)} === undefined && !('${prop.export_name}' in props)) { @_console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'"); }`)} `; @@ -405,8 +405,8 @@ export default function dom( `); } - const prop_names = x`{ - ${props.map(v => p`${v.export_name}: ${v.export_name === v.name ? 0 : x`"${v.name}"`}}`)} + const prop_indexes = x`{ + ${props.map(v => p`${v.export_name}: ${renderer.context_lookup.get(v.name)}`)} }` as ObjectExpression; if (options.customElement) { @@ -417,7 +417,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_names}); + @init(this, { target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}); ${dev_props_check} @@ -469,7 +469,7 @@ export default function dom( constructor(options) { super(${options.dev && `options`}); ${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`} - @init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_names}); + @init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}); ${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name.name}", options, id: create_fragment.name });`} ${dev_props_check} diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 69cb0f8d5a..023f258dd2 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -315,24 +315,24 @@ export default class InlineComponentWrapper extends Wrapper { } const value = block.get_unique_name('value'); - const args: any[] = [value]; + const params: any[] = [value]; if (contextual_dependencies.length > 0) { - args.push({ - type: 'ObjectPattern', - properties: contextual_dependencies.map(name => { - const id = { type: 'Identifier', name }; - return { - type: 'Property', - kind: 'init', - key: id, - value: id - }; - }) + const args = []; + + contextual_dependencies.forEach(name => { + params.push({ + type: 'Identifier', + name + }); + + renderer.add_to_context(name, true); + args.push(renderer.reference(name)); }); + block.chunks.init.push(b` function ${id}(${value}) { - #ctx[${i}].call(null, ${value}, #ctx); + #ctx[${i}].call(null, ${value}, ${args}); } `); @@ -346,7 +346,7 @@ export default class InlineComponentWrapper extends Wrapper { } const body = b` - function ${id}(${args}) { + function ${id}(${params}) { ${lhs} = ${value}; ${renderer.invalidate(dependencies[0])}; } @@ -354,7 +354,7 @@ export default class InlineComponentWrapper extends Wrapper { component.partly_hoisted.push(body); - return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${renderer.context_lookup.get(binding.name)}, ${id}));`; + return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`; }); const munged_handlers = this.node.handlers.map(handler => { diff --git a/src/compiler/compile/render_dom/wrappers/Window.ts b/src/compiler/compile/render_dom/wrappers/Window.ts index d34af65829..26042fa84a 100644 --- a/src/compiler/compile/render_dom/wrappers/Window.ts +++ b/src/compiler/compile/render_dom/wrappers/Window.ts @@ -80,6 +80,9 @@ export default class WindowWrapper extends Wrapper { const id = block.get_unique_name(`onwindow${event}`); const props = events[event]; + renderer.add_to_context(id.name); + const fn = renderer.reference(id.name); + if (event === 'scroll') { // TODO other bidirectional bindings... block.add_variable(scrolling, x`false`); @@ -106,7 +109,7 @@ export default class WindowWrapper extends Wrapper { ${scrolling} = true; @_clearTimeout(${scrolling_timeout}); ${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100); - #ctx.${id}(); + ${fn}(); }) `); } else { @@ -117,7 +120,7 @@ export default class WindowWrapper extends Wrapper { }); block.event_listeners.push(x` - @listen(@_window, "${event}", #ctx.${id}) + @listen(@_window, "${event}", ${fn}) `); } @@ -139,8 +142,9 @@ export default class WindowWrapper extends Wrapper { // special case... might need to abstract this out if we add more special cases if (bindings.scrollX || bindings.scrollY) { const condition = renderer.changed([bindings.scrollX, bindings.scrollY].filter(Boolean)); - const scrollX = bindings.scrollX ? x`#ctx.${bindings.scrollX}` : x`@_window.pageXOffset`; - const scrollY = bindings.scrollY ? x`#ctx.${bindings.scrollY}` : x`@_window.pageYOffset`; + + const scrollX = bindings.scrollX ? renderer.reference(bindings.scrollX) : x`@_window.pageXOffset`; + const scrollY = bindings.scrollY ? renderer.reference(bindings.scrollY) : x`@_window.pageYOffset`; block.chunks.update.push(b` if (${condition} && !${scrolling}) { diff --git a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts index 6462522590..46cb561ef4 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -53,7 +53,7 @@ export default function bind_this(component: Component, block: Block, binding: B const args = []; for (const id of contextual_dependencies) { args.push(id); - block.add_variable(id, x`#ctx.${id}`); + block.add_variable(id, block.renderer.reference(id)); } const assign = block.get_unique_name(`assign_${variable.name}`); @@ -65,7 +65,7 @@ export default function bind_this(component: Component, block: Block, binding: B `); const condition = Array.from(contextual_dependencies) - .map(name => x`${name} !== #ctx.${name}`) // TODO figure out contextual deps + .map(name => x`${name} !== ${block.renderer.reference(name)}`) // TODO figure out contextual deps .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); // we push unassign and unshift assign so that references are @@ -74,7 +74,7 @@ export default function bind_this(component: Component, block: Block, binding: B block.chunks.update.push(b` if (${condition}) { ${unassign}(); - ${args.map(a => b`${a} = #ctx.${a}`)}; + ${args.map(a => b`${a} = ${block.renderer.reference(a)}`)}; ${assign}(); }` ); diff --git a/src/compiler/compile/render_ssr/handlers/Element.ts b/src/compiler/compile/render_ssr/handlers/Element.ts index c77a44990c..81b8801686 100644 --- a/src/compiler/compile/render_ssr/handlers/Element.ts +++ b/src/compiler/compile/render_ssr/handlers/Element.ts @@ -30,7 +30,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption const class_expression_list = node.classes.map(class_directive => { const { expression, name } = class_directive; - const snippet = expression ? expression.node : x`#ctx.${name}`; + const snippet = expression ? expression.node : x`#ctx.${name}`; // TODO is this right? return x`${snippet} ? "${name}" : ""`; }); if (node.needs_manual_style_scoping) { diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 18d40356ee..778428439f 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -36,9 +36,9 @@ interface T$$ { on_destroy: any[]; } -export function bind(component, name, index, callback) { - if (has_prop(component.$$.props, name)) { - name = component.$$.props[name] || name; +export function bind(component, name, callback) { + const index = component.$$.props[name]; + if (index !== undefined) { component.$$.bound[index] = callback; callback(component.$$.ctx[index]); }