diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index 937a75b0aa..09366dcaaf 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -107,7 +107,7 @@ export default class SlotWrapper extends Wrapper { if (spread_dynamic_dependencies.size) { get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`); renderer.blocks.push(b` - const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))} > 0 ? -1 : 0; + const ${get_slot_spread_changes_fn} = #dirty => ${renderer.dirty(Array.from(spread_dynamic_dependencies))}; `); } } else { @@ -168,27 +168,41 @@ export default class SlotWrapper extends Wrapper { if (block.has_outros) { condition = x`!#current || ${condition}`; } - let dirty = x`#dirty`; - if (block.has_outros) { - dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${dirty}`; + + // conditions to treat everything as dirty + const all_dirty_conditions = [ + get_slot_spread_changes_fn ? x`${get_slot_spread_changes_fn}(#dirty)` : null, + block.has_outros ? x`!#current` : null + ].filter(Boolean); + const all_dirty_condition = all_dirty_conditions.length ? all_dirty_conditions.reduce((condition1, condition2) => x`${condition1} || ${condition2}`): null; + + let slot_update; + if (all_dirty_condition) { + const dirty = x`${all_dirty_condition} ? @get_all_dirty_from_scope(${renderer.reference('$$scope')}) : @get_slot_changes(${slot_definition}, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn})`; + + slot_update = b` + if (${slot}.p && ${condition}) { + @update_slot_base(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_context_fn}); + } + `; + } else { + slot_update = b` + if (${slot}.p && ${condition}) { + @update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, #dirty, ${get_slot_changes_fn}, ${get_slot_context_fn}); + } + `; } - const slot_update = get_slot_spread_changes_fn ? b` - if (${slot}.p && ${condition}) { - @update_slot_spread(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_spread_changes_fn}, ${get_slot_context_fn}); - } - ` : b` - if (${slot}.p && ${condition}) { - @update_slot(${slot}, ${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${dirty}, ${get_slot_changes_fn}, ${get_slot_context_fn}); - } - `; let fallback_condition = renderer.dirty(fallback_dynamic_dependencies); + let fallback_dirty = x`#dirty`; if (block.has_outros) { fallback_condition = x`!#current || ${fallback_condition}`; + fallback_dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${fallback_dirty}`; } + const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b` if (${slot_or_fallback} && ${slot_or_fallback}.p && ${fallback_condition}) { - ${slot_or_fallback}.p(#ctx, ${dirty}); + ${slot_or_fallback}.p(#ctx, ${fallback_dirty}); } `; diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 646851d0a5..8868e38ee2 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -119,20 +119,28 @@ export function get_slot_changes(definition, $$scope, dirty, fn) { return $$scope.dirty; } -export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { - const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); +export function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) { if (slot_changes) { const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); slot.p(slot_context, slot_changes); } } -export function update_slot_spread(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_spread_changes_fn, get_slot_context_fn) { - const slot_changes = get_slot_spread_changes_fn(dirty) | get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); - if (slot_changes) { - const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); - slot.p(slot_context, slot_changes); +export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { + const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); + update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn); +} + +export function get_all_dirty_from_scope($$scope) { + if ($$scope.ctx.length > 32) { + const dirty = []; + const length = $$scope.ctx.length / 32; + for (let i = 0; i < length; i++) { + dirty[i] = -1; + } + return dirty; } + return -1; } export function exclude_internal_props(props) { diff --git a/test/runtime/samples/transition-js-slot-2/_config.js b/test/runtime/samples/transition-js-slot-2/_config.js index 67cc0b46d2..0f0cad5e41 100644 --- a/test/runtime/samples/transition-js-slot-2/_config.js +++ b/test/runtime/samples/transition-js-slot-2/_config.js @@ -1,3 +1,4 @@ +// cancelled the transition halfway export default { html: `
Foo
diff --git a/test/runtime/samples/transition-js-slot-4-cancelled/Nested.svelte b/test/runtime/samples/transition-js-slot-4-cancelled/Nested.svelte new file mode 100644 index 0000000000..04eea750fd --- /dev/null +++ b/test/runtime/samples/transition-js-slot-4-cancelled/Nested.svelte @@ -0,0 +1,19 @@ + + +{#if visible} +
+ +
+{/if} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-slot-4-cancelled/_config.js b/test/runtime/samples/transition-js-slot-4-cancelled/_config.js new file mode 100644 index 0000000000..d6b7c31132 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-4-cancelled/_config.js @@ -0,0 +1,35 @@ +// updated props in the middle of transitions +// and cancelled the transition halfway +export default { + html: ` +
outside Foo Foo Foo
+
inside Foo Foo Foo
+ `, + props: { + props: 'Foo' + }, + + async test({ assert, component, target, window, raf }) { + await component.hide(); + const [, div] = target.querySelectorAll('div'); + + raf.tick(50); + assert.equal(div.foo, 0.5); + + component.props = 'Bar'; + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Foo Foo Foo
+ `); + + await component.show(); + + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Bar Bar Bar
+ `); + + raf.tick(100); + assert.equal(div.foo, 1); + } +}; diff --git a/test/runtime/samples/transition-js-slot-4-cancelled/main.svelte b/test/runtime/samples/transition-js-slot-4-cancelled/main.svelte new file mode 100644 index 0000000000..1003419244 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-4-cancelled/main.svelte @@ -0,0 +1,22 @@ + + +
outside {state} {props} {slotProps}
+ + inside {state} {props} {slotProps} + diff --git a/test/runtime/samples/transition-js-slot-5-cancelled-overflow/Nested.svelte b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/Nested.svelte new file mode 100644 index 0000000000..10050b6a10 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/Nested.svelte @@ -0,0 +1,19 @@ + + +{#if visible} +
+ +
+{/if} diff --git a/test/runtime/samples/transition-js-slot-5-cancelled-overflow/_config.js b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/_config.js new file mode 100644 index 0000000000..aedc87f0b6 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/_config.js @@ -0,0 +1,40 @@ +// updated props in the middle of transitions +// and cancelled the transition halfway +// + spreaded props + overflow context + +export default { + html: ` +
outside Foo Foo Foo
+
inside Foo Foo Foo
+ 0 + `, + props: { + props: 'Foo' + }, + + async test({ assert, component, target, window, raf }) { + await component.hide(); + const [, div] = target.querySelectorAll('div'); + + raf.tick(50); + assert.equal(div.foo, 0.5); + + component.props = 'Bar'; + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Foo Foo Foo
+ 0 + `); + + await component.show(); + + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Bar Bar Bar
+ 0 + `); + + raf.tick(100); + assert.equal(div.foo, 1); + } +}; diff --git a/test/runtime/samples/transition-js-slot-5-cancelled-overflow/main.svelte b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/main.svelte new file mode 100644 index 0000000000..9c46fd0521 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-5-cancelled-overflow/main.svelte @@ -0,0 +1,27 @@ + + +
outside {state} {props} {slotProps}
+ + + inside {state} {props} {slotProps} + + +{a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+a16+a17+a18+a19+a20+a21+a22+a23+a24+a25+a26+a27+a28+a29+a30+a31+a32+a33} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested.svelte b/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested.svelte new file mode 100644 index 0000000000..b1853993d3 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested.svelte @@ -0,0 +1,19 @@ + + +{#if visible} +
+ +
+{/if} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested2.svelte b/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested2.svelte new file mode 100644 index 0000000000..52f89858a0 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-6-spread-cancelled/Nested2.svelte @@ -0,0 +1,19 @@ + + +{#if visible} +
+ +
+{/if} \ No newline at end of file diff --git a/test/runtime/samples/transition-js-slot-6-spread-cancelled/_config.js b/test/runtime/samples/transition-js-slot-6-spread-cancelled/_config.js new file mode 100644 index 0000000000..1d42c9cf71 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-6-spread-cancelled/_config.js @@ -0,0 +1,40 @@ +// updated props in the middle of transitions +// and cancelled the transition halfway +// with spreaded props + +export default { + html: ` +
outside Foo Foo Foo
+
inside Foo Foo Foo
+
inside Foo Foo XXX
+ `, + props: { + props: 'Foo' + }, + + async test({ assert, component, target, window, raf }) { + await component.hide(); + const [, div] = target.querySelectorAll('div'); + + raf.tick(50); + assert.equal(div.foo, 0.5); + + component.props = 'Bar'; + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Foo Foo Foo
+
inside Foo Foo XXX
+ `); + + await component.show(); + + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Bar Bar Bar
+
inside Bar Bar XXX
+ `); + + raf.tick(100); + assert.equal(div.foo, 1); + } +}; diff --git a/test/runtime/samples/transition-js-slot-6-spread-cancelled/main.svelte b/test/runtime/samples/transition-js-slot-6-spread-cancelled/main.svelte new file mode 100644 index 0000000000..5dd8ce348e --- /dev/null +++ b/test/runtime/samples/transition-js-slot-6-spread-cancelled/main.svelte @@ -0,0 +1,26 @@ + + +
outside {state} {props} {slotProps.slotProps}
+ + inside {state} {props} {slotProps} + + + inside {state} {props} {slotProps} + diff --git a/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/Nested.svelte b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/Nested.svelte new file mode 100644 index 0000000000..b01200fd9f --- /dev/null +++ b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/Nested.svelte @@ -0,0 +1,19 @@ + + +{#if visible} +
+ +
+{/if} diff --git a/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/_config.js b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/_config.js new file mode 100644 index 0000000000..aedc87f0b6 --- /dev/null +++ b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/_config.js @@ -0,0 +1,40 @@ +// updated props in the middle of transitions +// and cancelled the transition halfway +// + spreaded props + overflow context + +export default { + html: ` +
outside Foo Foo Foo
+
inside Foo Foo Foo
+ 0 + `, + props: { + props: 'Foo' + }, + + async test({ assert, component, target, window, raf }) { + await component.hide(); + const [, div] = target.querySelectorAll('div'); + + raf.tick(50); + assert.equal(div.foo, 0.5); + + component.props = 'Bar'; + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Foo Foo Foo
+ 0 + `); + + await component.show(); + + assert.htmlEqual(target.innerHTML, ` +
outside Bar Bar Bar
+
inside Bar Bar Bar
+ 0 + `); + + raf.tick(100); + assert.equal(div.foo, 1); + } +}; diff --git a/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/main.svelte b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/main.svelte new file mode 100644 index 0000000000..000b29ee7f --- /dev/null +++ b/test/runtime/samples/transition-js-slot-7-spread-cancelled-overflow/main.svelte @@ -0,0 +1,27 @@ + + +
outside {state} {props} {slotProps.slotProps}
+ + + inside {state} {props} {slotProps} + + +{a1+a2+a3+a4+a5+a6+a7+a8+a9+a10+a11+a12+a13+a14+a15+a16+a17+a18+a19+a20+a21+a22+a23+a24+a25+a26+a27+a28+a29+a30+a31+a32+a33} \ No newline at end of file