mirror of https://github.com/sveltejs/svelte
parent
4abd99fa9d
commit
6785a53587
@ -1,140 +1,32 @@
|
|||||||
import { UNINITIALIZED, KEY_BLOCK } from '../../constants.js';
|
import { UNINITIALIZED, BRANCH_EFFECT } from '../../constants.js';
|
||||||
import { hydrate_block_anchor } from '../../hydration.js';
|
import { hydrate_block_anchor } from '../../hydration.js';
|
||||||
import { remove } from '../../reconciler.js';
|
import { pause_effect, render_effect } from '../../reactivity/computations.js';
|
||||||
import { current_block, destroy_signal, execute_effect, push_destroy_fn } from '../../runtime.js';
|
import { noop } from '../../../common.js';
|
||||||
import { render_effect } from '../../reactivity/computations.js';
|
|
||||||
import { trigger_transitions } from '../../transitions.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
|
* @template V
|
||||||
* @param {Comment} anchor_node
|
* @param {Comment} anchor_node
|
||||||
* @param {() => V} key
|
* @param {() => V} get_key
|
||||||
* @param {(anchor: Node) => void} render_fn
|
* @param {(anchor: Node) => void} render_fn
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function key_block(anchor_node, key, render_fn) {
|
export function key_block(anchor_node, get_key, render_fn) {
|
||||||
const block = create_key_block();
|
|
||||||
|
|
||||||
/** @type {null | import('../../types.js').Render} */
|
|
||||||
let current_render = null;
|
|
||||||
hydrate_block_anchor(anchor_node);
|
hydrate_block_anchor(anchor_node);
|
||||||
|
|
||||||
/** @type {V | typeof UNINITIALIZED} */
|
/** @type {V | typeof UNINITIALIZED} */
|
||||||
let key_value = UNINITIALIZED;
|
let key = UNINITIALIZED;
|
||||||
let mounted = false;
|
|
||||||
block.r =
|
/** @type {import('../../types.js').EffectSignal | null} */
|
||||||
/**
|
let effect;
|
||||||
* @param {import('../../types.js').Transition} transition
|
|
||||||
* @returns {void}
|
render_effect(() => {
|
||||||
*/
|
if (key === (key = get_key())) return; // TODO do we need safe_not_equal in non-runes mode?
|
||||||
(transition) => {
|
|
||||||
const render = /** @type {import('../../types.js').Render} */ (current_render);
|
if (effect) {
|
||||||
const transitions = render.s;
|
const e = effect;
|
||||||
transitions.add(transition);
|
pause_effect(e, noop);
|
||||||
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_signal(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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
block,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
// To ensure topological ordering of the key effect to the render effect,
|
|
||||||
// we trigger the effect after.
|
|
||||||
render();
|
|
||||||
mounted = true;
|
|
||||||
push_destroy_fn(key_effect, () => {
|
|
||||||
let render = current_render;
|
|
||||||
while (render !== null) {
|
|
||||||
const dom = render.d;
|
|
||||||
if (dom !== null) {
|
|
||||||
remove(dom);
|
|
||||||
}
|
|
||||||
const effect = render.e;
|
|
||||||
if (effect !== null) {
|
|
||||||
destroy_signal(effect);
|
|
||||||
}
|
|
||||||
render = render.p;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
block.e = key_effect;
|
effect = render_effect(() => render_fn(anchor_node), {}, true);
|
||||||
|
}).f |= BRANCH_EFFECT;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue