pull/10798/head
Rich Harris 2 years ago
parent 6a72a4fcb0
commit 6f8ccb9b56

@ -16,7 +16,6 @@ export const IF_BLOCK = 1;
export const EACH_BLOCK = 2;
export const EACH_ITEM_BLOCK = 3;
export const AWAIT_BLOCK = 4;
export const KEY_BLOCK = 5;
export const HEAD_BLOCK = 6;
export const DYNAMIC_COMPONENT_BLOCK = 7;
export const DYNAMIC_ELEMENT_BLOCK = 8;

@ -1,140 +1,70 @@
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 {() => 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_node, get_key, render_fn) {
const block = {};
/** @type {null | import('../../types.js').Render} */
let current_render = null;
hydrate_block_anchor(anchor_node);
/** @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;
/** @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_node);
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;
}

@ -4,7 +4,6 @@ import {
EACH_ITEM_BLOCK,
IF_BLOCK,
AWAIT_BLOCK,
KEY_BLOCK,
HEAD_BLOCK,
DYNAMIC_COMPONENT_BLOCK,
DYNAMIC_ELEMENT_BLOCK,
@ -65,7 +64,6 @@ export type BlockType =
| typeof EACH_ITEM_BLOCK
| typeof IF_BLOCK
| typeof AWAIT_BLOCK
| typeof KEY_BLOCK
| typeof SNIPPET_BLOCK
| typeof HEAD_BLOCK
| typeof DYNAMIC_COMPONENT_BLOCK
@ -125,19 +123,6 @@ export type IfBlock = {
t: typeof IF_BLOCK;
};
export type KeyBlock = {
/** dom */
d: null | TemplateNode | Array<TemplateNode>;
/** effect */
e: null | Effect;
/** parent */
p: Block;
/** transition */
r: null | ((transition: Transition) => void);
/** type */
t: typeof KEY_BLOCK;
};
export type HeadBlock = {
/** dom */
d: null | TemplateNode | Array<TemplateNode>;
@ -256,7 +241,6 @@ export type Block =
| DynamicElementBlock
| DynamicComponentBlock
| HeadBlock
| KeyBlock
| EachBlock
| EachItemBlock
| SnippetBlock;

Loading…
Cancel
Save