mirror of https://github.com/sveltejs/svelte
chore: simplify transitions (#10798)
* replace transition code * get rid of some stuff * simplify * remove some junk * not sure how we solved this before, but i guess this makes sense * oh hey i don't think we need this * make elseif transparent for transition purposes * oops * edge case * fix * do not want * rename * transition out ecah blocks when emptying * baby steps * hydration fix * tidy up * tidy up * tidy up * fallbacks * man i love deleting code * tidy up * note to self * why was this an effect * tidy up * tidy up * key blocks * temporary * fix * WIP * fix * simplify * emit events * delete delete delete * destroy child effects * simplify helper * simplify helper * fix * remove commented out code * fix wonky test * fix test * fix test * fix test * dynamic components * fix test * await * tidy up * fix * fix * fix test * tidy up * we dont need to reconcile during hydration * simplify * tidy up * fix * reduce indentation * simplify * remove some junk * remove some junk * simplify * tidy up * prefer while over do-while (this appears to have the same behaviour) * group fast paths * rename * unused import * unused exports * try this * simplify * simplify * simplify * simplify * tidy up * simplify * simplify * tidy up * simplify * simplify * more compact names * simplify * better comments * simplify * tidy up * we don't actually gain anything from this * fix binding group order bug (revealed by previous commit, but exists separately from it) * tidy up * simplify * tidy up * remove some junk * simplify * note to self * tidy up * revert this bit * tidy up * simplify * simplify * simplify * symmetry * tidy up * var * rename some stuff * tidy up * simplify * keyed each transitions * make elements inert * deferred transitions * fix * fix test * fix some tests * simplify * fix * fix test * fix * eh that'll do for now * fix * revert all these random changes * fix * fix * simplify * tidy up * simplify * simplify * tidy up * tidy up * tidy up * WIP * WIP * working * tidy up * fix * tidy up * tidy up * lerp * tidy up * rename * rename * almost everything working * tidy up * ALL TESTS PASSING * fix treeshaking * Apply suggestions from code review Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> * comment * explain elseif locality * explain flushSync * comments * this is accounted for * add some comments * remove outdated comment * add comment * add comments * rename * a few naming tweaks * explain each_item_block stuff * remove unused arg * optimise * add some comments * fix test post-optimisation * explicit comparisons * some docs * fix intro events * move effect.ran into the bitmask * docs * rename run_transitions to should_intro, add explanatory jsdoc * add some more docs * remove animation before measuring * only animate blocks that persist * note to self --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>pull/10870/head
parent
f6eca83b7c
commit
e8ce41815a
File diff suppressed because it is too large
Load Diff
@ -1,140 +1,76 @@
|
||||
import { UNINITIALIZED, KEY_BLOCK } from '../../constants.js';
|
||||
import { UNINITIALIZED } from '../../constants.js';
|
||||
import { hydrate_block_anchor } from '../hydration.js';
|
||||
import { remove } from '../reconciler.js';
|
||||
import { current_block, execute_effect } from '../../runtime.js';
|
||||
import { destroy_effect, render_effect } from '../../reactivity/effects.js';
|
||||
import { trigger_transitions } from '../elements/transitions.js';
|
||||
import { pause_effect, render_effect } from '../../reactivity/effects.js';
|
||||
import { safe_not_equal } from '../../reactivity/equality.js';
|
||||
|
||||
/** @returns {import('../../types.js').KeyBlock} */
|
||||
function create_key_block() {
|
||||
return {
|
||||
// dom
|
||||
d: null,
|
||||
// effect
|
||||
e: null,
|
||||
// parent
|
||||
p: /** @type {import('../../types.js').Block} */ (current_block),
|
||||
// transition
|
||||
r: null,
|
||||
// type
|
||||
t: KEY_BLOCK
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template V
|
||||
* @param {Comment} anchor_node
|
||||
* @param {() => V} key
|
||||
* @param {Comment} anchor
|
||||
* @param {() => V} get_key
|
||||
* @param {(anchor: Node) => void} render_fn
|
||||
* @returns {void}
|
||||
*/
|
||||
export function key_block(anchor_node, key, render_fn) {
|
||||
const block = create_key_block();
|
||||
export function key_block(anchor, get_key, render_fn) {
|
||||
const block = {};
|
||||
|
||||
/** @type {null | import('../../types.js').Render} */
|
||||
let current_render = null;
|
||||
hydrate_block_anchor(anchor_node);
|
||||
hydrate_block_anchor(anchor);
|
||||
|
||||
/** @type {V | typeof UNINITIALIZED} */
|
||||
let key_value = UNINITIALIZED;
|
||||
let mounted = false;
|
||||
block.r =
|
||||
/**
|
||||
* @param {import('../../types.js').Transition} transition
|
||||
* @returns {void}
|
||||
*/
|
||||
(transition) => {
|
||||
const render = /** @type {import('../../types.js').Render} */ (current_render);
|
||||
const transitions = render.s;
|
||||
transitions.add(transition);
|
||||
transition.f(() => {
|
||||
transitions.delete(transition);
|
||||
if (transitions.size === 0) {
|
||||
// If the current render has changed since, then we can remove the old render
|
||||
// effect as it's stale.
|
||||
if (current_render !== render && render.e !== null) {
|
||||
if (render.d !== null) {
|
||||
remove(render.d);
|
||||
render.d = null;
|
||||
}
|
||||
destroy_effect(render.e);
|
||||
render.e = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const create_render_effect = () => {
|
||||
/** @type {import('../../types.js').Render} */
|
||||
const render = {
|
||||
d: null,
|
||||
e: null,
|
||||
s: new Set(),
|
||||
p: current_render
|
||||
};
|
||||
const effect = render_effect(
|
||||
() => {
|
||||
render_fn(anchor_node);
|
||||
render.d = block.d;
|
||||
block.d = null;
|
||||
},
|
||||
block,
|
||||
true,
|
||||
true
|
||||
);
|
||||
render.e = effect;
|
||||
current_render = render;
|
||||
};
|
||||
const render = () => {
|
||||
const render = current_render;
|
||||
if (render === null) {
|
||||
create_render_effect();
|
||||
return;
|
||||
}
|
||||
const transitions = render.s;
|
||||
if (transitions.size === 0) {
|
||||
if (render.d !== null) {
|
||||
remove(render.d);
|
||||
render.d = null;
|
||||
}
|
||||
if (render.e) {
|
||||
execute_effect(render.e);
|
||||
} else {
|
||||
create_render_effect();
|
||||
}
|
||||
} else {
|
||||
trigger_transitions(transitions, 'out');
|
||||
create_render_effect();
|
||||
}
|
||||
};
|
||||
let key = UNINITIALIZED;
|
||||
|
||||
/** @type {import('#client').Effect} */
|
||||
let effect;
|
||||
|
||||
/**
|
||||
* Every time `key` changes, we create a new effect. Old effects are
|
||||
* removed from this set when they have fully transitioned out
|
||||
* @type {Set<import('#client').Effect>}
|
||||
*/
|
||||
let effects = new Set();
|
||||
|
||||
const key_effect = render_effect(
|
||||
() => {
|
||||
const prev_key_value = key_value;
|
||||
key_value = key();
|
||||
if (mounted && safe_not_equal(prev_key_value, key_value)) {
|
||||
render();
|
||||
if (safe_not_equal(key, (key = get_key()))) {
|
||||
if (effect) {
|
||||
var e = effect;
|
||||
pause_effect(e, () => {
|
||||
effects.delete(e);
|
||||
});
|
||||
}
|
||||
|
||||
effect = render_effect(
|
||||
() => {
|
||||
render_fn(anchor);
|
||||
|
||||
// @ts-expect-error TODO this should be unnecessary
|
||||
const dom = block.d;
|
||||
|
||||
return () => {
|
||||
if (dom !== null) {
|
||||
remove(dom);
|
||||
}
|
||||
};
|
||||
},
|
||||
block,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
// @ts-expect-error TODO tidy up
|
||||
effect.d = block.d;
|
||||
|
||||
effects.add(effect);
|
||||
}
|
||||
},
|
||||
block,
|
||||
false
|
||||
);
|
||||
// To ensure topological ordering of the key effect to the render effect,
|
||||
// we trigger the effect after.
|
||||
render();
|
||||
mounted = true;
|
||||
|
||||
key_effect.ondestroy = () => {
|
||||
let render = current_render;
|
||||
while (render !== null) {
|
||||
const dom = render.d;
|
||||
if (dom !== null) {
|
||||
remove(dom);
|
||||
}
|
||||
const effect = render.e;
|
||||
if (effect !== null) {
|
||||
destroy_effect(effect);
|
||||
}
|
||||
render = render.p;
|
||||
for (const e of effects) {
|
||||
// @ts-expect-error TODO tidy up. ondestroy should be totally unnecessary
|
||||
if (e.d) remove(e.d);
|
||||
}
|
||||
};
|
||||
block.e = key_effect;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue