diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 9618a0d854..543d6b0066 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -138,11 +138,15 @@ export default class Renderer { .reduce((lhs, rhs) => x`${lhs}, ${rhs}}`); } - changed(names, needs_update = false) { - const bitmask = names.reduce((bits, name) => { + get_bitmask(names) { + return names.reduce((bits, name) => { const bit = 1 << this.context_lookup.get(name); return bits | bit; }, 0); + } + + changed(names, needs_update = false) { + const bitmask = this.get_bitmask(names); return needs_update ? x`(#changed = $$self.$$.dirty) & ${bitmask}` diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index b4a2d13d53..155612e878 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -16,10 +16,41 @@ import is_dynamic from '../shared/is_dynamic'; import bind_this from '../shared/bind_this'; import { Node, Identifier, ObjectExpression } from 'estree'; import EventHandler from '../Element/EventHandler'; +import Let from '../../../nodes/Let'; + +function get_changes_merger(renderer: Renderer, lets: Let[]) { + if (lets.length === 0) return null; + + const input = { + type: 'ObjectPattern', + properties: lets.map(l => ({ + type: 'Property', + kind: 'init', + key: l.name, + value: l.value || l.name + })) + }; + + const names: Set = new Set(); + lets.forEach(l => { + l.names.forEach(name => { + names.add(name); + }); + }); + + const expressions = Array.from(names).map(name => { + const i = renderer.context_lookup.get(name); + return x`${name} ? ${1 << i} : 0`; + }); + + const output = expressions.reduce((lhs, rhs) => x`${lhs} | ${rhs}`); + + return x`(${input}) => (${output})`; +} export default class InlineComponentWrapper extends Wrapper { var: Identifier; - slots: Map = new Map(); + slots: Map = new Map(); node: InlineComponent; fragment: FragmentWrapper; @@ -74,7 +105,7 @@ export default class InlineComponentWrapper extends Wrapper { if (this.node.children.length) { this.node.lets.forEach(l => { - renderer.add_to_context(l.value.name, true); + renderer.add_to_context((l.value || l.name).name, true); }); const default_slot = block.child({ @@ -85,12 +116,11 @@ export default class InlineComponentWrapper extends Wrapper { this.renderer.blocks.push(default_slot); - const fn = get_context_merger(this.renderer, this.node.lets); - this.slots.set('default', { block: default_slot, scope: this.node.scope, - fn + get_context: get_context_merger(this.renderer, this.node.lets), + get_changes: get_changes_merger(this.renderer, this.node.lets) }); this.fragment = new FragmentWrapper(renderer, default_slot, node.children, this, strip_whitespace, next_sibling); @@ -133,7 +163,7 @@ export default class InlineComponentWrapper extends Wrapper { ? [ p`$$slots: { ${Array.from(this.slots).map(([name, slot]) => { - return p`${name}: [${slot.block.name}, ${slot.fn || null}]`; + return p`${name}: [${slot.block.name}, ${slot.get_context || null}, ${slot.get_changes || null}]`; })} }`, p`$$scope: { diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 044eb04583..123b6776e8 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -90,16 +90,13 @@ export default class SlotWrapper extends Wrapper { }); if (dynamic_dependencies.length > 0) { - const expression = dynamic_dependencies - .map(name => ({ type: 'Identifier', name } as any)) - .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); - - changes.properties.push(p`${attribute.name}: ${expression}`); + const bitmask = renderer.get_bitmask(dynamic_dependencies); + changes.properties.push(p`${attribute.name}: #changes & ${bitmask}`); } }); renderer.blocks.push(b` - const ${get_slot_changes_fn} = #changes => #changes; + const ${get_slot_changes_fn} = #changes => ${changes}; const ${get_slot_context_fn} = #ctx => ${get_slot_data(block, this.node.values)}; `); } else { diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index fab44f80db..97b83f360f 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -77,8 +77,8 @@ export function get_slot_context(definition, ctx, $$scope, fn) { } export function get_slot_changes(definition, $$scope, changed, fn) { - return definition[1] && fn - ? $$scope.changed | definition[1](fn(changed)) + return definition[2] && fn + ? $$scope.changed | definition[2](fn(changed)) : $$scope.changed; }