outroing each blocks

pull/1451/head
Rich Harris 6 years ago
parent 0a230d1c9d
commit 64fa48e699

@ -272,7 +272,7 @@ export default class Block {
${outroing} = true;
${hasIntros && `${introing} = false;`}
${this.outros > 1 && `var #outros = ${this.outros};`}
${this.outros > 1 && `#outrocallback = @callAfter(#outrocallback, ${this.outros});`}
${this.builders.outro}
},

@ -118,6 +118,10 @@ export default class EachBlock extends Node {
);
this.else.block.hasUpdateMethod = this.else.block.dependencies.size > 0;
}
if (this.block.hasOutroMethod || (this.else && this.else.block.hasOutroMethod)) {
block.addOutro();
}
}
build(
@ -313,9 +317,24 @@ export default class EachBlock extends Node {
block.builders.update.addBlock(deindent`
var ${this.each_block_value} = ${snippet};
${this.block.hasOutroMethod && `@transitionManager.groupOutros();`}
${blocks} = @updateKeyedEach(${blocks}, #component, changed, ${get_key}, ${dynamic ? '1' : '0'}, ctx, ${this.each_block_value}, ${lookup}, ${updateMountNode}, ${String(this.block.hasOutroMethod)}, ${create_each_block}, "${mountOrIntro}", ${anchor}, ${this.get_each_context});
`);
block.builders.outro.addBlock(deindent`
const keys = Object.keys(${lookup}).filter(key => ${lookup}[key]);
#outrocallback = @callAfter(#outrocallback, keys.length);
function outro(key) {
${lookup}[key].o(() => {
${lookup}[key] = null;
#outrocallback();
});
}
for (let #i = 0; #i < keys.length; #i += 1) outro(keys[#i]);
`)
block.builders.destroy.addBlock(deindent`
for (#i = 0; #i < ${blocks}.length; #i += 1) ${blocks}[#i].d(${parentNode ? '' : 'detach'});
`);
@ -372,6 +391,21 @@ export default class EachBlock extends Node {
allDependencies.add(dependency);
});
const outro = this.block.hasOutroMethod && block.getUniqueName('outro')
if (outro) {
block.builders.init.addBlock(deindent`
function ${outro}(i, detach, fn) {
if (${iterations}[i]) {
${iterations}[i].o(() => {
${iterations}[i].d(detach);
if (detach) ${iterations}[i] = null;
if (fn) fn();
});
}
}
`);
}
// TODO do this for keyed blocks as well
const condition = Array.from(allDependencies)
.map(dependency => `changed.${dependency}`)
@ -406,27 +440,21 @@ export default class EachBlock extends Node {
const start = this.block.hasUpdateMethod ? '0' : `${iterations}.length`;
const outro = block.getUniqueName('outro');
const destroy = this.block.hasOutroMethod
? deindent`
function ${outro}(i) {
if (${iterations}[i]) {
${iterations}[i].o(function() {
${iterations}[i].d(1);
${iterations}[i] = null;
});
}
}
let destroy;
if (this.block.hasOutroMethod) {
destroy = deindent`
@transitionManager.groupOutros();
for (; #i < ${iterations}.length; #i += 1) ${outro}(#i);
`
: deindent`
for (; #i < ${iterations}.length; #i += 1) ${outro}(#i, 1);
`;
} else {
destroy = deindent`
for (; #i < ${iterations}.length; #i += 1) {
${iterations}[#i].d(1);
}
${iterations}.length = ${this.each_block_value}.${length};
`;
}
block.builders.update.addBlock(deindent`
if (${condition}) {
@ -443,6 +471,13 @@ export default class EachBlock extends Node {
`);
}
if (outro) {
block.builders.outro.addBlock(deindent`
#outrocallback = @callAfter(#outrocallback, #i);
for (let #i = 0; #i < ${iterations}.length; #i += 1) ${outro}(#i, 0, #outrocallback);`
);
}
block.builders.destroy.addBlock(`@destroyEach(${iterations}, detach);`);
}

@ -712,7 +712,7 @@ export default class Element extends Node {
block.builders.outro.addBlock(deindent`
${name}.run(0, () => {
${block.outros > 1 ? `if (--#outros === 0) #outrocallback();` : `#outrocallback();`}
#outrocallback();
${name} = null;
});
`);
@ -759,9 +759,7 @@ export default class Element extends Node {
// group) prior to their removal from the DOM
block.builders.outro.addBlock(deindent`
${outroName} = @wrapTransition(#component, ${this.var}, ${fn}, ${snippet}, false);
${outroName}.run(0, () => {
${block.outros > 1 ? `if (--#outros === 0) #outrocallback();` : `#outrocallback();`}
});
${outroName}.run(0, #outrocallback);
`);
}
}

@ -1,5 +1,3 @@
import { transitionManager } from './transitions.js';
export function destroyBlock(block, lookup) {
block.d(1);
lookup[block.key] = null;
@ -45,7 +43,6 @@ export function updateKeyedEach(old_blocks, component, changed, get_key, dynamic
var did_move = {};
var destroy = has_outro ? outroAndDestroyBlock : destroyBlock;
if (has_outro) transitionManager.groupOutros();
function insert(block) {
block[intro_method](node, next);

@ -12,4 +12,10 @@ export function assignTrue(tar, src) {
export function isPromise(value) {
return value && typeof value.then === 'function';
}
export function callAfter(fn, i) {
return () => {
if (!--i) fn();
};
}

@ -0,0 +1,28 @@
export default {
skipIntroByDefault: true,
nestedTransitions: true,
data: {
x: false,
things: ['a']
},
test(assert, component, target, window, raf) {
component.set({ x: true });
const div = target.querySelector('div');
assert.equal(div.foo, 0);
raf.tick(100);
assert.equal(div.foo, 1);
component.set({ x: false });
assert.htmlEqual(target.innerHTML, '<div></div>');
raf.tick(150);
assert.equal(div.foo, 0.5);
raf.tick(200);
assert.htmlEqual(target.innerHTML, '');
},
};

@ -0,0 +1,20 @@
{#if x}
{#each things as thing (thing)}
<div transition:foo></div>
{/each}
{/if}
<script>
export default {
transitions: {
foo(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
}
};
</script>

@ -0,0 +1,28 @@
export default {
skipIntroByDefault: true,
nestedTransitions: true,
data: {
x: false,
things: ['a']
},
test(assert, component, target, window, raf) {
component.set({ x: true });
const div = target.querySelector('div');
assert.equal(div.foo, 0);
raf.tick(100);
assert.equal(div.foo, 1);
component.set({ x: false });
assert.htmlEqual(target.innerHTML, '<div></div>');
raf.tick(150);
assert.equal(div.foo, 0.5);
raf.tick(200);
assert.htmlEqual(target.innerHTML, '');
},
};

@ -0,0 +1,20 @@
{#if x}
{#each things as thing}
<div transition:foo></div>
{/each}
{/if}
<script>
export default {
transitions: {
foo(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t;
}
};
}
}
};
</script>
Loading…
Cancel
Save