one test to go

pull/17150/head
Rich Harris 4 days ago
parent ae12901b05
commit 27c2908bec

@ -93,20 +93,24 @@ function pause_effects(state, to_destroy, controlled_anchor) {
); );
clear_text_content(parent_node); clear_text_content(parent_node);
parent_node.append(/** @type {Element} */ (controlled_anchor)); parent_node.append(/** @type {Element} */ (controlled_anchor));
state.onscreen.clear(); state.items.clear();
} }
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var item = to_destroy[i]; var item = to_destroy[i];
if (!is_controlled) { if (!is_controlled) {
state.onscreen.delete(item.k); state.items.delete(item.k);
} }
destroy_effect(item.e, !is_controlled); destroy_effect(item.e, !is_controlled);
} }
});
link(state, to_destroy[0].prev, to_destroy[length - 1].next); link(state, to_destroy[0].prev, to_destroy[length - 1].next);
if (state.first === to_destroy[0]) {
state.first = to_destroy[0].prev;
}
});
} }
/** /**
@ -123,7 +127,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
var anchor = node; var anchor = node;
/** @type {EachState} */ /** @type {EachState} */
var state = { flags, onscreen: new Map(), offscreen: new Map(), first: null }; var state = { flags, items: new Map(), first: null, last: null };
var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
@ -221,7 +225,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
var value = array[i]; var value = array[i];
var key = get_key(value, i); var key = get_key(value, i);
var item = first_run ? null : state.onscreen.get(key) ?? state.offscreen.get(key); var item = first_run ? null : state.items.get(key);
if (item) { if (item) {
// update before reconciliation, to trigger any async updates // update before reconciliation, to trigger any async updates
@ -243,6 +247,8 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
); );
if (first_run) { if (first_run) {
item.o = true;
if (prev === null) { if (prev === null) {
state.first = item; state.first = item;
} else { } else {
@ -250,10 +256,9 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
} }
prev = item; prev = item;
state.onscreen.set(key, item);
} else {
state.offscreen.set(key, item);
} }
state.items.set(key, item);
} }
keys.add(key); keys.add(key);
@ -282,7 +287,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
set_hydrate_node(skip_nodes()); set_hydrate_node(skip_nodes());
} }
for (const [key, item] of state.onscreen) { for (const [key, item] of state.items) {
if (!keys.has(key)) { if (!keys.has(key)) {
batch.skipped_effects.add(item.e); batch.skipped_effects.add(item.e);
} }
@ -335,8 +340,7 @@ function reconcile(each_effect, array, state, anchor, flags, get_key) {
var is_animated = (flags & EACH_IS_ANIMATED) !== 0; var is_animated = (flags & EACH_IS_ANIMATED) !== 0;
var length = array.length; var length = array.length;
var onscreen = state.onscreen; var items = state.items;
var offscreen = state.offscreen;
var current = state.first; var current = state.first;
/** @type {undefined | Set<EachItem>} */ /** @type {undefined | Set<EachItem>} */
@ -370,7 +374,7 @@ function reconcile(each_effect, array, state, anchor, flags, get_key) {
for (i = 0; i < length; i += 1) { for (i = 0; i < length; i += 1) {
value = array[i]; value = array[i];
key = get_key(value, i); key = get_key(value, i);
item = /** @type {EachItem} */ (onscreen.get(key)); item = /** @type {EachItem} */ (items.get(key));
item.a?.measure(); item.a?.measure();
(to_animate ??= new Set()).add(item); (to_animate ??= new Set()).add(item);
@ -381,12 +385,12 @@ function reconcile(each_effect, array, state, anchor, flags, get_key) {
value = array[i]; value = array[i];
key = get_key(value, i); key = get_key(value, i);
item = onscreen.get(key); item = /** @type {EachItem} */ (items.get(key));
if (item === undefined) { state.first ??= item;
item = /** @type {EachItem} */ (offscreen.get(key));
offscreen.delete(key); if (!item.o) {
item.o = true;
var next = prev ? prev.next : current; var next = prev ? prev.next : current;
@ -396,8 +400,6 @@ function reconcile(each_effect, array, state, anchor, flags, get_key) {
move(item, next, anchor); move(item, next, anchor);
prev = item; prev = item;
onscreen.set(key, prev);
matched = []; matched = [];
stashed = []; stashed = [];
@ -531,12 +533,6 @@ function reconcile(each_effect, array, state, anchor, flags, get_key) {
// to the first offscreen item, etc // to the first offscreen item, etc
prev.e.next = null; prev.e.next = null;
} }
for (var unused of offscreen.values()) {
destroy_effect(unused.e);
}
offscreen.clear();
} }
/** /**
@ -596,6 +592,7 @@ function create_item(anchor, prev, value, key, index, render_fn, flags, get_coll
a: null, a: null,
// @ts-expect-error // @ts-expect-error
e: null, e: null,
o: false,
prev, prev,
next: null next: null
}; };

@ -64,14 +64,10 @@ export type TemplateNode = Text | Element | Comment;
export type Dom = TemplateNode | TemplateNode[]; export type Dom = TemplateNode | TemplateNode[];
export type EachState = { export type EachState = {
/** flags */
flags: number; flags: number;
/** items that are currently onscreen */ items: Map<any, EachItem>;
onscreen: Map<any, EachItem>;
/** items that are currently offscreen */
offscreen: Map<any, EachItem>;
/** head of the linked list of items */
first: EachItem | null; first: EachItem | null;
last: EachItem | null;
}; };
export type EachItem = { export type EachItem = {
@ -85,6 +81,8 @@ export type EachItem = {
i: number | Source<number>; i: number | Source<number>;
/** key */ /** key */
k: unknown; k: unknown;
/** true if onscreen */
o: boolean;
prev: EachItem | null; prev: EachItem | null;
next: EachItem | null; next: EachItem | null;
}; };

Loading…
Cancel
Save