|
|
|
@ -42,6 +42,7 @@ import { active_effect, get } from '../../runtime.js';
|
|
|
|
import { DEV } from 'esm-env';
|
|
|
|
import { DEV } from 'esm-env';
|
|
|
|
import { derived_safe_equal } from '../../reactivity/deriveds.js';
|
|
|
|
import { derived_safe_equal } from '../../reactivity/deriveds.js';
|
|
|
|
import { current_batch } from '../../reactivity/batch.js';
|
|
|
|
import { current_batch } from '../../reactivity/batch.js';
|
|
|
|
|
|
|
|
import { log_effect_tree, root } from '../../dev/debug.js';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* The row of a keyed each block that is currently updating. We track this
|
|
|
|
* The row of a keyed each block that is currently updating. We track this
|
|
|
|
@ -151,9 +152,6 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
|
/** @type {V[]} */
|
|
|
|
/** @type {V[]} */
|
|
|
|
var array;
|
|
|
|
var array;
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {Effect} */
|
|
|
|
|
|
|
|
var each_effect;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function commit() {
|
|
|
|
function commit() {
|
|
|
|
reconcile(each_effect, array, state, anchor, render_fn, flags, get_key, get_collection);
|
|
|
|
reconcile(each_effect, array, state, anchor, render_fn, flags, get_key, get_collection);
|
|
|
|
|
|
|
|
|
|
|
|
@ -172,10 +170,9 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
block(() => {
|
|
|
|
var first_run = true;
|
|
|
|
// store a reference to the effect so that we can update the start/end nodes in reconciliation
|
|
|
|
|
|
|
|
each_effect ??= /** @type {Effect} */ (active_effect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var each_effect = block(() => {
|
|
|
|
array = /** @type {V[]} */ (get(each_array));
|
|
|
|
array = /** @type {V[]} */ (get(each_array));
|
|
|
|
var length = array.length;
|
|
|
|
var length = array.length;
|
|
|
|
|
|
|
|
|
|
|
|
@ -202,31 +199,41 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// this is separate to the previous block because `hydrating` might change
|
|
|
|
var keys = new Set();
|
|
|
|
if (hydrating) {
|
|
|
|
var batch = /** @type {Batch} */ (current_batch);
|
|
|
|
/** @type {EachItem | null} */
|
|
|
|
var prev = null;
|
|
|
|
var prev = null;
|
|
|
|
var defer = should_defer_append();
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {EachItem} */
|
|
|
|
for (var i = 0; i < length; i += 1) {
|
|
|
|
var item;
|
|
|
|
if (
|
|
|
|
|
|
|
|
hydrating &&
|
|
|
|
for (var i = 0; i < length; i++) {
|
|
|
|
hydrate_node.nodeType === COMMENT_NODE &&
|
|
|
|
if (
|
|
|
|
/** @type {Comment} */ (hydrate_node).data === HYDRATION_END
|
|
|
|
hydrate_node.nodeType === COMMENT_NODE &&
|
|
|
|
) {
|
|
|
|
/** @type {Comment} */ (hydrate_node).data === HYDRATION_END
|
|
|
|
// The server rendered fewer items than expected,
|
|
|
|
) {
|
|
|
|
// so break out and continue appending non-hydrated items
|
|
|
|
// The server rendered fewer items than expected,
|
|
|
|
anchor = /** @type {Comment} */ (hydrate_node);
|
|
|
|
// so break out and continue appending non-hydrated items
|
|
|
|
mismatch = true;
|
|
|
|
anchor = /** @type {Comment} */ (hydrate_node);
|
|
|
|
set_hydrating(false);
|
|
|
|
mismatch = true;
|
|
|
|
break;
|
|
|
|
set_hydrating(false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
var value = array[i];
|
|
|
|
|
|
|
|
var key = get_key(value, i);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var item = first_run ? null : state.onscreen.get(key) ?? state.offscreen.get(key);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (item) {
|
|
|
|
|
|
|
|
// update before reconciliation, to trigger any async updates
|
|
|
|
|
|
|
|
if ((flags & (EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE)) !== 0) {
|
|
|
|
|
|
|
|
update_item(item, value, i, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var value = array[i];
|
|
|
|
batch.skipped_effects.delete(item.e);
|
|
|
|
var key = get_key(value, i);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
console.log('creating', key);
|
|
|
|
item = create_item(
|
|
|
|
item = create_item(
|
|
|
|
hydrate_node,
|
|
|
|
first_run ? (hydrating ? hydrate_node : anchor) : null,
|
|
|
|
state,
|
|
|
|
state,
|
|
|
|
prev,
|
|
|
|
prev,
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
@ -235,66 +242,40 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
|
i,
|
|
|
|
i,
|
|
|
|
render_fn,
|
|
|
|
render_fn,
|
|
|
|
flags,
|
|
|
|
flags,
|
|
|
|
get_collection
|
|
|
|
get_collection,
|
|
|
|
|
|
|
|
defer
|
|
|
|
);
|
|
|
|
);
|
|
|
|
state.onscreen.set(key, item);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prev = item;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// remove excess nodes
|
|
|
|
|
|
|
|
if (length > 0) {
|
|
|
|
|
|
|
|
set_hydrate_node(skip_nodes());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hydrating) {
|
|
|
|
if (first_run) {
|
|
|
|
if (length === 0 && fallback_fn) {
|
|
|
|
if (prev === null) {
|
|
|
|
fallback = branch(() => fallback_fn(anchor));
|
|
|
|
state.first = item;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
if (should_defer_append()) {
|
|
|
|
|
|
|
|
var keys = new Set();
|
|
|
|
|
|
|
|
var batch = /** @type {Batch} */ (current_batch);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i += 1) {
|
|
|
|
|
|
|
|
value = array[i];
|
|
|
|
|
|
|
|
key = get_key(value, i);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var existing = state.onscreen.get(key) ?? state.offscreen.get(key);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (existing) {
|
|
|
|
|
|
|
|
// update before reconciliation, to trigger any async updates
|
|
|
|
|
|
|
|
if ((flags & (EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE)) !== 0) {
|
|
|
|
|
|
|
|
update_item(existing, value, i, flags);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
item = create_item(
|
|
|
|
prev.next = item;
|
|
|
|
null,
|
|
|
|
|
|
|
|
state,
|
|
|
|
|
|
|
|
null,
|
|
|
|
|
|
|
|
null,
|
|
|
|
|
|
|
|
value,
|
|
|
|
|
|
|
|
key,
|
|
|
|
|
|
|
|
i,
|
|
|
|
|
|
|
|
render_fn,
|
|
|
|
|
|
|
|
flags,
|
|
|
|
|
|
|
|
get_collection,
|
|
|
|
|
|
|
|
true
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state.offscreen.set(key, item);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
keys.add(key);
|
|
|
|
prev = item;
|
|
|
|
|
|
|
|
state.onscreen.set(key, item);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
state.offscreen.set(key, item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const [key, item] of state.onscreen) {
|
|
|
|
keys.add(key);
|
|
|
|
if (!keys.has(key)) {
|
|
|
|
}
|
|
|
|
batch.skipped_effects.add(item.e);
|
|
|
|
|
|
|
|
}
|
|
|
|
// remove excess nodes
|
|
|
|
}
|
|
|
|
if (hydrating && length > 0) {
|
|
|
|
|
|
|
|
set_hydrate_node(skip_nodes());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const [key, item] of state.onscreen) {
|
|
|
|
|
|
|
|
if (!keys.has(key)) {
|
|
|
|
|
|
|
|
batch.skipped_effects.add(item.e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!first_run) {
|
|
|
|
|
|
|
|
if (defer) {
|
|
|
|
batch.oncommit(commit);
|
|
|
|
batch.oncommit(commit);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
commit();
|
|
|
|
commit();
|
|
|
|
@ -315,6 +296,8 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
|
get(each_array);
|
|
|
|
get(each_array);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
first_run = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (hydrating) {
|
|
|
|
if (hydrating) {
|
|
|
|
anchor = hydrate_node;
|
|
|
|
anchor = hydrate_node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -338,7 +321,7 @@ function reconcile(each_effect, array, state, anchor, render_fn, flags, get_key,
|
|
|
|
var should_update = (flags & (EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE)) !== 0;
|
|
|
|
var should_update = (flags & (EACH_ITEM_REACTIVE | EACH_INDEX_REACTIVE)) !== 0;
|
|
|
|
|
|
|
|
|
|
|
|
var length = array.length;
|
|
|
|
var length = array.length;
|
|
|
|
var items = state.onscreen;
|
|
|
|
var onscreen = state.onscreen;
|
|
|
|
var first = state.first;
|
|
|
|
var first = state.first;
|
|
|
|
var current = first;
|
|
|
|
var current = first;
|
|
|
|
|
|
|
|
|
|
|
|
@ -373,7 +356,7 @@ function reconcile(each_effect, array, state, anchor, render_fn, 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 = items.get(key);
|
|
|
|
item = onscreen.get(key);
|
|
|
|
|
|
|
|
|
|
|
|
if (item !== undefined) {
|
|
|
|
if (item !== undefined) {
|
|
|
|
item.a?.measure();
|
|
|
|
item.a?.measure();
|
|
|
|
@ -386,14 +369,14 @@ function reconcile(each_effect, array, state, anchor, render_fn, flags, get_key,
|
|
|
|
value = array[i];
|
|
|
|
value = array[i];
|
|
|
|
key = get_key(value, i);
|
|
|
|
key = get_key(value, i);
|
|
|
|
|
|
|
|
|
|
|
|
item = items.get(key);
|
|
|
|
item = onscreen.get(key);
|
|
|
|
|
|
|
|
|
|
|
|
if (item === undefined) {
|
|
|
|
if (item === undefined) {
|
|
|
|
var pending = state.offscreen.get(key);
|
|
|
|
var pending = state.offscreen.get(key);
|
|
|
|
|
|
|
|
|
|
|
|
if (pending !== undefined) {
|
|
|
|
if (pending !== undefined) {
|
|
|
|
state.offscreen.delete(key);
|
|
|
|
state.offscreen.delete(key);
|
|
|
|
items.set(key, pending);
|
|
|
|
onscreen.set(key, pending);
|
|
|
|
|
|
|
|
|
|
|
|
var next = prev ? prev.next : current;
|
|
|
|
var next = prev ? prev.next : current;
|
|
|
|
|
|
|
|
|
|
|
|
@ -419,7 +402,7 @@ function reconcile(each_effect, array, state, anchor, render_fn, flags, get_key,
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
items.set(key, prev);
|
|
|
|
onscreen.set(key, prev);
|
|
|
|
|
|
|
|
|
|
|
|
matched = [];
|
|
|
|
matched = [];
|
|
|
|
stashed = [];
|
|
|
|
stashed = [];
|
|
|
|
@ -643,13 +626,14 @@ function create_item(
|
|
|
|
fragment.append((anchor = create_text()));
|
|
|
|
fragment.append((anchor = create_text()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
item.e = branch(() => render_fn(/** @type {Node} */ (anchor), v, i, get_collection), hydrating);
|
|
|
|
item.e = branch(() => render_fn(/** @type {Node} */ (anchor), v, i, get_collection));
|
|
|
|
|
|
|
|
|
|
|
|
item.e.prev = prev && prev.e;
|
|
|
|
item.e.prev = prev && prev.e;
|
|
|
|
item.e.next = next && next.e;
|
|
|
|
item.e.next = next && next.e;
|
|
|
|
|
|
|
|
|
|
|
|
if (prev === null) {
|
|
|
|
if (prev === null) {
|
|
|
|
if (!deferred) {
|
|
|
|
if (!deferred) {
|
|
|
|
|
|
|
|
// TODO move this into block effect?
|
|
|
|
state.first = item;
|
|
|
|
state.first = item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|