[fix] slot data for cancelled transition (#6314)

pull/6577/head
Tan Li Hau 3 years ago committed by GitHub
parent 588b37f810
commit d75ed6a003
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -107,7 +107,7 @@ export default class SlotWrapper extends Wrapper {
if (spread_dynamic_dependencies.size) { if (spread_dynamic_dependencies.size) {
get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`); get_slot_spread_changes_fn = renderer.component.get_unique_name(`get_${sanitize(slot_name)}_slot_spread_changes`);
renderer.blocks.push(b` 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 { } else {
@ -168,27 +168,41 @@ export default class SlotWrapper extends Wrapper {
if (block.has_outros) { if (block.has_outros) {
condition = x`!#current || ${condition}`; condition = x`!#current || ${condition}`;
} }
let dirty = x`#dirty`;
if (block.has_outros) { // conditions to treat everything as dirty
dirty = x`!#current ? ${renderer.get_initial_dirty()} : ${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_condition = renderer.dirty(fallback_dynamic_dependencies);
let fallback_dirty = x`#dirty`;
if (block.has_outros) { if (block.has_outros) {
fallback_condition = x`!#current || ${fallback_condition}`; 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` const fallback_update = has_fallback && fallback_dynamic_dependencies.length > 0 && b`
if (${slot_or_fallback} && ${slot_or_fallback}.p && ${fallback_condition}) { if (${slot_or_fallback} && ${slot_or_fallback}.p && ${fallback_condition}) {
${slot_or_fallback}.p(#ctx, ${dirty}); ${slot_or_fallback}.p(#ctx, ${fallback_dirty});
} }
`; `;

@ -119,20 +119,28 @@ export function get_slot_changes(definition, $$scope, dirty, fn) {
return $$scope.dirty; return $$scope.dirty;
} }
export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_changes_fn, get_slot_context_fn) { export function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {
const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
if (slot_changes) { if (slot_changes) {
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
slot.p(slot_context, slot_changes); 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) { export function update_slot(slot, slot_definition, ctx, $$scope, dirty, get_slot_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); const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn);
if (slot_changes) { update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn);
const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); }
slot.p(slot_context, slot_changes);
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) { export function exclude_internal_props(props) {

@ -1,3 +1,4 @@
// cancelled the transition halfway
export default { export default {
html: ` html: `
<div>Foo</div> <div>Foo</div>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {slotProps}></slot>
</div>
{/if}

@ -0,0 +1,35 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
`,
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, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,22 @@
<script>
import Nested from './Nested.svelte';
let visible = true;
let state = 'Foo';
let slotProps = 'Foo';
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = 'Bar';
}
</script>
<div>outside {state} {props} {slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// + spreaded props + overflow context
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
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, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
0
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
0
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,27 @@
<script>
import Nested from './Nested.svelte';
export let a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0,a10=0,a11=0, a12=0,a13=0,a14=0,a15=0,a16=0,a17=0,a18=0,a19=0,a20=0,a21=0, a22=0,a23=0,a24=0,a25=0,a26=0,a27=0,a28=0,a29=0,a30=0,a31=0,a32=0,a33=0;
let visible = true;
let state = 'Foo';
let slotProps = 'Foo';
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = 'Bar';
}
</script>
<div>outside {state} {props} {slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
{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}

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,19 @@
<script>
export let visible;
let slotProps = { slotProps: 'XXX' };
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// with spreaded props
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
<div>inside Foo Foo XXX</div>
`,
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, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
<div>inside Foo Foo XXX</div>
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
<div>inside Bar Bar XXX</div>
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,26 @@
<script>
import Nested from './Nested.svelte';
import Nested2 from './Nested2.svelte';
let visible = true;
let state = 'Foo';
let slotProps = { slotProps: 'Foo' };
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = { slotProps: 'Bar' };
}
</script>
<div>outside {state} {props} {slotProps.slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
<Nested2 {visible} let:slotProps>
inside {state} {props} {slotProps}
</Nested2>

@ -0,0 +1,19 @@
<script>
export let visible;
export let slotProps;
function fade(node) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
</script>
{#if visible}
<div transition:fade>
<slot {...slotProps}></slot>
</div>
{/if}

@ -0,0 +1,40 @@
// updated props in the middle of transitions
// and cancelled the transition halfway
// + spreaded props + overflow context
export default {
html: `
<div>outside Foo Foo Foo</div>
<div>inside Foo Foo Foo</div>
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, `
<div>outside Bar Bar Bar</div>
<div>inside Foo Foo Foo</div>
0
`);
await component.show();
assert.htmlEqual(target.innerHTML, `
<div>outside Bar Bar Bar</div>
<div>inside Bar Bar Bar</div>
0
`);
raf.tick(100);
assert.equal(div.foo, 1);
}
};

@ -0,0 +1,27 @@
<script>
import Nested from './Nested.svelte';
export let a1=0,a2=0,a3=0,a4=0,a5=0,a6=0,a7=0,a8=0,a9=0,a10=0,a11=0, a12=0,a13=0,a14=0,a15=0,a16=0,a17=0,a18=0,a19=0,a20=0,a21=0, a22=0,a23=0,a24=0,a25=0,a26=0,a27=0,a28=0,a29=0,a30=0,a31=0,a32=0,a33=0;
let visible = true;
let state = 'Foo';
let slotProps = { slotProps: 'Foo' };
export let props;
export function show() {
visible = true;
}
export function hide() {
visible = false;
state = 'Bar';
slotProps = { slotProps: 'Bar' };
}
</script>
<div>outside {state} {props} {slotProps.slotProps}</div>
<Nested {visible} {slotProps} let:slotProps>
inside {state} {props} {slotProps}
</Nested>
{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}
Loading…
Cancel
Save