svelte 5.45.4 → 5.45.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/index.js +1 -1
- package/package.json +1 -1
- package/src/internal/client/constants.js +1 -0
- package/src/internal/client/dom/blocks/css-props.js +2 -3
- package/src/internal/client/dom/blocks/each.js +212 -202
- package/src/internal/client/dom/blocks/html.js +4 -2
- package/src/internal/client/dom/blocks/svelte-element.js +3 -3
- package/src/internal/client/dom/blocks/svelte-head.js +2 -2
- package/src/internal/client/dom/hydration.js +2 -2
- package/src/internal/client/dom/operations.js +10 -13
- package/src/internal/client/dom/template.js +3 -3
- package/src/internal/client/reactivity/effects.js +5 -11
- package/src/internal/client/render.js +3 -2
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import { EachItem, EachState, Effect, EffectNodes, MaybeSource, Source, TemplateNode, TransitionManager, Value } from '#client' */
|
|
1
|
+
/** @import { EachItem, EachOutroGroup, EachState, Effect, EffectNodes, MaybeSource, Source, TemplateNode, TransitionManager, Value } from '#client' */
|
|
2
2
|
/** @import { Batch } from '../../reactivity/batch.js'; */
|
|
3
3
|
import {
|
|
4
4
|
EACH_INDEX_REACTIVE,
|
|
@@ -29,20 +29,22 @@ import {
|
|
|
29
29
|
block,
|
|
30
30
|
branch,
|
|
31
31
|
destroy_effect,
|
|
32
|
-
run_out_transitions,
|
|
33
|
-
pause_children,
|
|
34
32
|
pause_effect,
|
|
35
33
|
resume_effect
|
|
36
34
|
} from '../../reactivity/effects.js';
|
|
37
35
|
import { source, mutable_source, internal_set } from '../../reactivity/sources.js';
|
|
38
36
|
import { array_from, is_array } from '../../../shared/utils.js';
|
|
39
|
-
import { COMMENT_NODE, INERT } from '#client/constants';
|
|
37
|
+
import { COMMENT_NODE, EFFECT_OFFSCREEN, INERT } from '#client/constants';
|
|
40
38
|
import { queue_micro_task } from '../task.js';
|
|
41
39
|
import { get } from '../../runtime.js';
|
|
42
40
|
import { DEV } from 'esm-env';
|
|
43
41
|
import { derived_safe_equal } from '../../reactivity/deriveds.js';
|
|
44
42
|
import { current_batch } from '../../reactivity/batch.js';
|
|
45
43
|
|
|
44
|
+
// When making substantive changes to this file, validate them with the each block stress test:
|
|
45
|
+
// https://svelte.dev/playground/1972b2cf46564476ad8c8c6405b23b7b
|
|
46
|
+
// This test also exists in this repo, as `packages/svelte/tests/manual/each-stress-test`
|
|
47
|
+
|
|
46
48
|
/**
|
|
47
49
|
* @param {any} _
|
|
48
50
|
* @param {number} i
|
|
@@ -55,7 +57,7 @@ export function index(_, i) {
|
|
|
55
57
|
* Pause multiple effects simultaneously, and coordinate their
|
|
56
58
|
* subsequent destruction. Used in each blocks
|
|
57
59
|
* @param {EachState} state
|
|
58
|
-
* @param {
|
|
60
|
+
* @param {Effect[]} to_destroy
|
|
59
61
|
* @param {null | Node} controlled_anchor
|
|
60
62
|
*/
|
|
61
63
|
function pause_effects(state, to_destroy, controlled_anchor) {
|
|
@@ -63,19 +65,44 @@ function pause_effects(state, to_destroy, controlled_anchor) {
|
|
|
63
65
|
var transitions = [];
|
|
64
66
|
var length = to_destroy.length;
|
|
65
67
|
|
|
68
|
+
/** @type {EachOutroGroup} */
|
|
69
|
+
var group;
|
|
70
|
+
var remaining = to_destroy.length;
|
|
71
|
+
|
|
66
72
|
for (var i = 0; i < length; i++) {
|
|
67
|
-
|
|
73
|
+
let effect = to_destroy[i];
|
|
74
|
+
|
|
75
|
+
pause_effect(
|
|
76
|
+
effect,
|
|
77
|
+
() => {
|
|
78
|
+
if (group) {
|
|
79
|
+
group.pending.delete(effect);
|
|
80
|
+
group.done.add(effect);
|
|
81
|
+
|
|
82
|
+
if (group.pending.size === 0) {
|
|
83
|
+
var groups = /** @type {Set<EachOutroGroup>} */ (state.outrogroups);
|
|
84
|
+
|
|
85
|
+
destroy_effects(array_from(group.done));
|
|
86
|
+
groups.delete(group);
|
|
87
|
+
|
|
88
|
+
if (groups.size === 0) {
|
|
89
|
+
state.outrogroups = null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
remaining -= 1;
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
false
|
|
97
|
+
);
|
|
68
98
|
}
|
|
69
99
|
|
|
70
|
-
|
|
100
|
+
if (remaining === 0) {
|
|
71
101
|
// If we're in a controlled each block (i.e. the block is the only child of an
|
|
72
102
|
// element), and we are removing all items, _and_ there are no out transitions,
|
|
73
103
|
// we can use the fast path — emptying the element and replacing the anchor
|
|
74
104
|
var fast_path = transitions.length === 0 && controlled_anchor !== null;
|
|
75
105
|
|
|
76
|
-
// TODO only destroy effects if no pending batch needs them. otherwise,
|
|
77
|
-
// just set `item.o` back to `false`
|
|
78
|
-
|
|
79
106
|
if (fast_path) {
|
|
80
107
|
var anchor = /** @type {Element} */ (controlled_anchor);
|
|
81
108
|
var parent_node = /** @type {Element} */ (anchor.parentNode);
|
|
@@ -84,26 +111,34 @@ function pause_effects(state, to_destroy, controlled_anchor) {
|
|
|
84
111
|
parent_node.append(anchor);
|
|
85
112
|
|
|
86
113
|
state.items.clear();
|
|
87
|
-
link(state, to_destroy[0].prev, to_destroy[length - 1].next);
|
|
88
114
|
}
|
|
89
115
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
116
|
+
destroy_effects(to_destroy, !fast_path);
|
|
117
|
+
} else {
|
|
118
|
+
group = {
|
|
119
|
+
pending: new Set(to_destroy),
|
|
120
|
+
done: new Set()
|
|
121
|
+
};
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
(state.outrogroups ??= new Set()).add(group);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
100
126
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
127
|
+
/**
|
|
128
|
+
* @param {Effect[]} to_destroy
|
|
129
|
+
* @param {boolean} remove_dom
|
|
130
|
+
*/
|
|
131
|
+
function destroy_effects(to_destroy, remove_dom = true) {
|
|
132
|
+
// TODO only destroy effects if no pending batch needs them. otherwise,
|
|
133
|
+
// just re-add the `EFFECT_OFFSCREEN` flag
|
|
134
|
+
for (var i = 0; i < to_destroy.length; i++) {
|
|
135
|
+
destroy_effect(to_destroy[i], remove_dom);
|
|
136
|
+
}
|
|
105
137
|
}
|
|
106
138
|
|
|
139
|
+
/** @type {TemplateNode} */
|
|
140
|
+
var offscreen_anchor;
|
|
141
|
+
|
|
107
142
|
/**
|
|
108
143
|
* @template V
|
|
109
144
|
* @param {Element | Comment} node The next sibling node, or the parent node if this is a 'controlled' block
|
|
@@ -120,18 +155,13 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
120
155
|
/** @type {Map<any, EachItem>} */
|
|
121
156
|
var items = new Map();
|
|
122
157
|
|
|
123
|
-
/** @type {EachItem | null} */
|
|
124
|
-
var first = null;
|
|
125
|
-
|
|
126
158
|
var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
|
|
127
|
-
var is_reactive_value = (flags & EACH_ITEM_REACTIVE) !== 0;
|
|
128
|
-
var is_reactive_index = (flags & EACH_INDEX_REACTIVE) !== 0;
|
|
129
159
|
|
|
130
160
|
if (is_controlled) {
|
|
131
161
|
var parent_node = /** @type {Element} */ (node);
|
|
132
162
|
|
|
133
163
|
anchor = hydrating
|
|
134
|
-
? set_hydrate_node(
|
|
164
|
+
? set_hydrate_node(get_first_child(parent_node))
|
|
135
165
|
: parent_node.appendChild(create_text());
|
|
136
166
|
}
|
|
137
167
|
|
|
@@ -139,7 +169,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
139
169
|
hydrate_next();
|
|
140
170
|
}
|
|
141
171
|
|
|
142
|
-
/** @type {
|
|
172
|
+
/** @type {Effect | null} */
|
|
143
173
|
var fallback = null;
|
|
144
174
|
|
|
145
175
|
// TODO: ideally we could use derived for runes mode but because of the ability
|
|
@@ -157,20 +187,19 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
157
187
|
var first_run = true;
|
|
158
188
|
|
|
159
189
|
function commit() {
|
|
190
|
+
state.fallback = fallback;
|
|
160
191
|
reconcile(state, array, anchor, flags, get_key);
|
|
161
192
|
|
|
162
193
|
if (fallback !== null) {
|
|
163
194
|
if (array.length === 0) {
|
|
164
|
-
if (fallback.
|
|
165
|
-
|
|
166
|
-
fallback.fragment = null;
|
|
195
|
+
if ((fallback.f & EFFECT_OFFSCREEN) === 0) {
|
|
196
|
+
resume_effect(fallback);
|
|
167
197
|
} else {
|
|
168
|
-
|
|
198
|
+
fallback.f ^= EFFECT_OFFSCREEN;
|
|
199
|
+
move(fallback, null, anchor);
|
|
169
200
|
}
|
|
170
|
-
|
|
171
|
-
effect.first = fallback.effect;
|
|
172
201
|
} else {
|
|
173
|
-
pause_effect(fallback
|
|
202
|
+
pause_effect(fallback, () => {
|
|
174
203
|
// TODO only null out if no pending batch needs it,
|
|
175
204
|
// otherwise re-add `fallback.fragment` and move the
|
|
176
205
|
// effect into it
|
|
@@ -202,10 +231,9 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
202
231
|
|
|
203
232
|
var keys = new Set();
|
|
204
233
|
var batch = /** @type {Batch} */ (current_batch);
|
|
205
|
-
var prev = null;
|
|
206
234
|
var defer = should_defer_append();
|
|
207
235
|
|
|
208
|
-
for (var
|
|
236
|
+
for (var index = 0; index < length; index += 1) {
|
|
209
237
|
if (
|
|
210
238
|
hydrating &&
|
|
211
239
|
hydrate_node.nodeType === COMMENT_NODE &&
|
|
@@ -218,46 +246,33 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
218
246
|
set_hydrating(false);
|
|
219
247
|
}
|
|
220
248
|
|
|
221
|
-
var value = array[
|
|
222
|
-
var key = get_key(value,
|
|
249
|
+
var value = array[index];
|
|
250
|
+
var key = get_key(value, index);
|
|
223
251
|
|
|
224
252
|
var item = first_run ? null : items.get(key);
|
|
225
253
|
|
|
226
254
|
if (item) {
|
|
227
255
|
// update before reconciliation, to trigger any async updates
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (is_reactive_index) {
|
|
233
|
-
internal_set(/** @type {Value<number>} */ (item.i), i);
|
|
234
|
-
}
|
|
256
|
+
if (item.v) internal_set(item.v, value);
|
|
257
|
+
if (item.i) internal_set(item.i, index);
|
|
235
258
|
|
|
236
259
|
if (defer) {
|
|
237
260
|
batch.skipped_effects.delete(item.e);
|
|
238
261
|
}
|
|
239
262
|
} else {
|
|
240
263
|
item = create_item(
|
|
241
|
-
|
|
242
|
-
|
|
264
|
+
items,
|
|
265
|
+
first_run ? anchor : (offscreen_anchor ??= create_text()),
|
|
243
266
|
value,
|
|
244
267
|
key,
|
|
245
|
-
|
|
268
|
+
index,
|
|
246
269
|
render_fn,
|
|
247
270
|
flags,
|
|
248
271
|
get_collection
|
|
249
272
|
);
|
|
250
273
|
|
|
251
|
-
if (first_run) {
|
|
252
|
-
item.
|
|
253
|
-
|
|
254
|
-
if (prev === null) {
|
|
255
|
-
first = item;
|
|
256
|
-
} else {
|
|
257
|
-
prev.next = item;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
prev = item;
|
|
274
|
+
if (!first_run) {
|
|
275
|
+
item.e.f |= EFFECT_OFFSCREEN;
|
|
261
276
|
}
|
|
262
277
|
|
|
263
278
|
items.set(key, item);
|
|
@@ -268,19 +283,10 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
268
283
|
|
|
269
284
|
if (length === 0 && fallback_fn && !fallback) {
|
|
270
285
|
if (first_run) {
|
|
271
|
-
fallback =
|
|
272
|
-
fragment: null,
|
|
273
|
-
effect: branch(() => fallback_fn(anchor))
|
|
274
|
-
};
|
|
286
|
+
fallback = branch(() => fallback_fn(anchor));
|
|
275
287
|
} else {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
fragment.append(target);
|
|
279
|
-
|
|
280
|
-
fallback = {
|
|
281
|
-
fragment,
|
|
282
|
-
effect: branch(() => fallback_fn(target))
|
|
283
|
-
};
|
|
288
|
+
fallback = branch(() => fallback_fn((offscreen_anchor ??= create_text())));
|
|
289
|
+
fallback.f |= EFFECT_OFFSCREEN;
|
|
284
290
|
}
|
|
285
291
|
}
|
|
286
292
|
|
|
@@ -321,7 +327,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
|
|
|
321
327
|
});
|
|
322
328
|
|
|
323
329
|
/** @type {EachState} */
|
|
324
|
-
var state = { effect, flags, items,
|
|
330
|
+
var state = { effect, flags, items, outrogroups: null, fallback };
|
|
325
331
|
|
|
326
332
|
first_run = false;
|
|
327
333
|
|
|
@@ -345,21 +351,21 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
345
351
|
|
|
346
352
|
var length = array.length;
|
|
347
353
|
var items = state.items;
|
|
348
|
-
var current = state.first;
|
|
354
|
+
var current = state.effect.first;
|
|
349
355
|
|
|
350
|
-
/** @type {undefined | Set<
|
|
356
|
+
/** @type {undefined | Set<Effect>} */
|
|
351
357
|
var seen;
|
|
352
358
|
|
|
353
|
-
/** @type {
|
|
359
|
+
/** @type {Effect | null} */
|
|
354
360
|
var prev = null;
|
|
355
361
|
|
|
356
|
-
/** @type {undefined | Set<
|
|
362
|
+
/** @type {undefined | Set<Effect>} */
|
|
357
363
|
var to_animate;
|
|
358
364
|
|
|
359
|
-
/** @type {
|
|
365
|
+
/** @type {Effect[]} */
|
|
360
366
|
var matched = [];
|
|
361
367
|
|
|
362
|
-
/** @type {
|
|
368
|
+
/** @type {Effect[]} */
|
|
363
369
|
var stashed = [];
|
|
364
370
|
|
|
365
371
|
/** @type {V} */
|
|
@@ -368,8 +374,8 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
368
374
|
/** @type {any} */
|
|
369
375
|
var key;
|
|
370
376
|
|
|
371
|
-
/** @type {
|
|
372
|
-
var
|
|
377
|
+
/** @type {Effect | undefined} */
|
|
378
|
+
var effect;
|
|
373
379
|
|
|
374
380
|
/** @type {number} */
|
|
375
381
|
var i;
|
|
@@ -378,13 +384,13 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
378
384
|
for (i = 0; i < length; i += 1) {
|
|
379
385
|
value = array[i];
|
|
380
386
|
key = get_key(value, i);
|
|
381
|
-
|
|
387
|
+
effect = /** @type {EachItem} */ (items.get(key)).e;
|
|
382
388
|
|
|
383
389
|
// offscreen == coming in now, no animation in that case,
|
|
384
390
|
// else this would happen https://github.com/sveltejs/svelte/issues/17181
|
|
385
|
-
if (
|
|
386
|
-
|
|
387
|
-
(to_animate ??= new Set()).add(
|
|
391
|
+
if ((effect.f & EFFECT_OFFSCREEN) === 0) {
|
|
392
|
+
effect.nodes?.a?.measure();
|
|
393
|
+
(to_animate ??= new Set()).add(effect);
|
|
388
394
|
}
|
|
389
395
|
}
|
|
390
396
|
}
|
|
@@ -393,38 +399,53 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
393
399
|
value = array[i];
|
|
394
400
|
key = get_key(value, i);
|
|
395
401
|
|
|
396
|
-
|
|
402
|
+
effect = /** @type {EachItem} */ (items.get(key)).e;
|
|
397
403
|
|
|
398
|
-
state.
|
|
404
|
+
if (state.outrogroups !== null) {
|
|
405
|
+
for (const group of state.outrogroups) {
|
|
406
|
+
group.pending.delete(effect);
|
|
407
|
+
group.done.delete(effect);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
399
410
|
|
|
400
|
-
if (
|
|
401
|
-
|
|
411
|
+
if ((effect.f & EFFECT_OFFSCREEN) !== 0) {
|
|
412
|
+
effect.f ^= EFFECT_OFFSCREEN;
|
|
402
413
|
|
|
403
|
-
|
|
414
|
+
if (effect === current) {
|
|
415
|
+
move(effect, null, anchor);
|
|
416
|
+
} else {
|
|
417
|
+
var next = prev ? prev.next : current;
|
|
404
418
|
|
|
405
|
-
|
|
406
|
-
|
|
419
|
+
if (effect === state.effect.last) {
|
|
420
|
+
state.effect.last = effect.prev;
|
|
421
|
+
}
|
|
407
422
|
|
|
408
|
-
|
|
409
|
-
|
|
423
|
+
if (effect.prev) effect.prev.next = effect.next;
|
|
424
|
+
if (effect.next) effect.next.prev = effect.prev;
|
|
425
|
+
link(state, prev, effect);
|
|
426
|
+
link(state, effect, next);
|
|
410
427
|
|
|
411
|
-
|
|
412
|
-
|
|
428
|
+
move(effect, next, anchor);
|
|
429
|
+
prev = effect;
|
|
430
|
+
|
|
431
|
+
matched = [];
|
|
432
|
+
stashed = [];
|
|
413
433
|
|
|
414
|
-
|
|
415
|
-
|
|
434
|
+
current = prev.next;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
416
437
|
}
|
|
417
438
|
|
|
418
|
-
if ((
|
|
419
|
-
resume_effect(
|
|
439
|
+
if ((effect.f & INERT) !== 0) {
|
|
440
|
+
resume_effect(effect);
|
|
420
441
|
if (is_animated) {
|
|
421
|
-
|
|
422
|
-
(to_animate ??= new Set()).delete(
|
|
442
|
+
effect.nodes?.a?.unfix();
|
|
443
|
+
(to_animate ??= new Set()).delete(effect);
|
|
423
444
|
}
|
|
424
445
|
}
|
|
425
446
|
|
|
426
|
-
if (
|
|
427
|
-
if (seen !== undefined && seen.has(
|
|
447
|
+
if (effect !== current) {
|
|
448
|
+
if (seen !== undefined && seen.has(effect)) {
|
|
428
449
|
if (matched.length < stashed.length) {
|
|
429
450
|
// more efficient to move later items to the front
|
|
430
451
|
var start = stashed[0];
|
|
@@ -455,14 +476,14 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
455
476
|
stashed = [];
|
|
456
477
|
} else {
|
|
457
478
|
// more efficient to move earlier items to the back
|
|
458
|
-
seen.delete(
|
|
459
|
-
move(
|
|
479
|
+
seen.delete(effect);
|
|
480
|
+
move(effect, current, anchor);
|
|
460
481
|
|
|
461
|
-
link(state,
|
|
462
|
-
link(state,
|
|
463
|
-
link(state, prev,
|
|
482
|
+
link(state, effect.prev, effect.next);
|
|
483
|
+
link(state, effect, prev === null ? state.effect.first : prev.next);
|
|
484
|
+
link(state, prev, effect);
|
|
464
485
|
|
|
465
|
-
prev =
|
|
486
|
+
prev = effect;
|
|
466
487
|
}
|
|
467
488
|
|
|
468
489
|
continue;
|
|
@@ -471,12 +492,8 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
471
492
|
matched = [];
|
|
472
493
|
stashed = [];
|
|
473
494
|
|
|
474
|
-
while (current !== null && current !==
|
|
475
|
-
|
|
476
|
-
// skip over adding it to our seen Set as the item is already being handled
|
|
477
|
-
if ((current.e.f & INERT) === 0) {
|
|
478
|
-
(seen ??= new Set()).add(current);
|
|
479
|
-
}
|
|
495
|
+
while (current !== null && current !== effect) {
|
|
496
|
+
(seen ??= new Set()).add(current);
|
|
480
497
|
stashed.push(current);
|
|
481
498
|
current = current.next;
|
|
482
499
|
}
|
|
@@ -484,42 +501,62 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
484
501
|
if (current === null) {
|
|
485
502
|
continue;
|
|
486
503
|
}
|
|
504
|
+
}
|
|
487
505
|
|
|
488
|
-
|
|
506
|
+
if ((effect.f & EFFECT_OFFSCREEN) === 0) {
|
|
507
|
+
matched.push(effect);
|
|
489
508
|
}
|
|
490
509
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
current = item.next;
|
|
510
|
+
prev = effect;
|
|
511
|
+
current = effect.next;
|
|
494
512
|
}
|
|
495
513
|
|
|
496
|
-
|
|
514
|
+
if (state.outrogroups !== null) {
|
|
515
|
+
for (const group of state.outrogroups) {
|
|
516
|
+
if (group.pending.size === 0) {
|
|
517
|
+
destroy_effects(array_from(group.done));
|
|
518
|
+
state.outrogroups?.delete(group);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (state.outrogroups.size === 0) {
|
|
523
|
+
state.outrogroups = null;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
497
526
|
|
|
498
527
|
if (current !== null || seen !== undefined) {
|
|
499
|
-
|
|
528
|
+
/** @type {Effect[]} */
|
|
529
|
+
var to_destroy = [];
|
|
530
|
+
|
|
531
|
+
if (seen !== undefined) {
|
|
532
|
+
for (effect of seen) {
|
|
533
|
+
if ((effect.f & INERT) === 0) {
|
|
534
|
+
to_destroy.push(effect);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
500
538
|
|
|
501
539
|
while (current !== null) {
|
|
502
540
|
// If the each block isn't inert, then inert effects are currently outroing and will be removed once the transition is finished
|
|
503
|
-
if ((current.
|
|
541
|
+
if ((current.f & INERT) === 0 && current !== state.fallback) {
|
|
504
542
|
to_destroy.push(current);
|
|
505
543
|
}
|
|
544
|
+
|
|
506
545
|
current = current.next;
|
|
507
546
|
}
|
|
508
547
|
|
|
509
548
|
var destroy_length = to_destroy.length;
|
|
510
549
|
|
|
511
|
-
has_offscreen_items = items.size - destroy_length > length;
|
|
512
|
-
|
|
513
550
|
if (destroy_length > 0) {
|
|
514
551
|
var controlled_anchor = (flags & EACH_IS_CONTROLLED) !== 0 && length === 0 ? anchor : null;
|
|
515
552
|
|
|
516
553
|
if (is_animated) {
|
|
517
554
|
for (i = 0; i < destroy_length; i += 1) {
|
|
518
|
-
to_destroy[i].
|
|
555
|
+
to_destroy[i].nodes?.a?.measure();
|
|
519
556
|
}
|
|
520
557
|
|
|
521
558
|
for (i = 0; i < destroy_length; i += 1) {
|
|
522
|
-
to_destroy[i].
|
|
559
|
+
to_destroy[i].nodes?.a?.fix();
|
|
523
560
|
}
|
|
524
561
|
}
|
|
525
562
|
|
|
@@ -527,23 +564,11 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
527
564
|
}
|
|
528
565
|
}
|
|
529
566
|
|
|
530
|
-
// Append offscreen items at the end
|
|
531
|
-
if (has_offscreen_items) {
|
|
532
|
-
for (const item of items.values()) {
|
|
533
|
-
if (!item.o) {
|
|
534
|
-
link(state, prev, item);
|
|
535
|
-
prev = item;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
state.effect.last = prev && prev.e;
|
|
541
|
-
|
|
542
567
|
if (is_animated) {
|
|
543
568
|
queue_micro_task(() => {
|
|
544
569
|
if (to_animate === undefined) return;
|
|
545
|
-
for (
|
|
546
|
-
|
|
570
|
+
for (effect of to_animate) {
|
|
571
|
+
effect.nodes?.a?.apply();
|
|
547
572
|
}
|
|
548
573
|
});
|
|
549
574
|
}
|
|
@@ -551,8 +576,8 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
551
576
|
|
|
552
577
|
/**
|
|
553
578
|
* @template V
|
|
554
|
-
* @param {
|
|
555
|
-
* @param {
|
|
579
|
+
* @param {Map<any, EachItem>} items
|
|
580
|
+
* @param {Node} anchor
|
|
556
581
|
* @param {V} value
|
|
557
582
|
* @param {unknown} key
|
|
558
583
|
* @param {number} index
|
|
@@ -561,96 +586,81 @@ function reconcile(state, array, anchor, flags, get_key) {
|
|
|
561
586
|
* @param {() => V[]} get_collection
|
|
562
587
|
* @returns {EachItem}
|
|
563
588
|
*/
|
|
564
|
-
function create_item(
|
|
565
|
-
var
|
|
566
|
-
|
|
589
|
+
function create_item(items, anchor, value, key, index, render_fn, flags, get_collection) {
|
|
590
|
+
var v =
|
|
591
|
+
(flags & EACH_ITEM_REACTIVE) !== 0
|
|
592
|
+
? (flags & EACH_ITEM_IMMUTABLE) === 0
|
|
593
|
+
? mutable_source(value, false, false)
|
|
594
|
+
: source(value)
|
|
595
|
+
: null;
|
|
567
596
|
|
|
568
|
-
var
|
|
569
|
-
var i = (flags & EACH_INDEX_REACTIVE) === 0 ? index : source(index);
|
|
597
|
+
var i = (flags & EACH_INDEX_REACTIVE) !== 0 ? source(index) : null;
|
|
570
598
|
|
|
571
|
-
if (DEV &&
|
|
599
|
+
if (DEV && v) {
|
|
572
600
|
// For tracing purposes, we need to link the source signal we create with the
|
|
573
601
|
// collection + index so that tracing works as intended
|
|
574
|
-
|
|
575
|
-
var collection_index = typeof i === 'number' ? index : i.v;
|
|
602
|
+
v.trace = () => {
|
|
576
603
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
577
|
-
get_collection()[
|
|
604
|
+
get_collection()[i?.v ?? index];
|
|
578
605
|
};
|
|
579
606
|
}
|
|
580
607
|
|
|
581
|
-
|
|
582
|
-
var item = {
|
|
583
|
-
i,
|
|
608
|
+
return {
|
|
584
609
|
v,
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
o: false,
|
|
589
|
-
prev,
|
|
590
|
-
next: null
|
|
591
|
-
};
|
|
592
|
-
|
|
593
|
-
if (anchor === null) {
|
|
594
|
-
var fragment = document.createDocumentFragment();
|
|
595
|
-
fragment.append((anchor = create_text()));
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
item.e = branch(() => render_fn(/** @type {Node} */ (anchor), v, i, get_collection));
|
|
599
|
-
|
|
600
|
-
if (prev !== null) {
|
|
601
|
-
// we only need to set `prev.next = item`, because
|
|
602
|
-
// `item.prev = prev` was set on initialization.
|
|
603
|
-
// the effects themselves are already linked
|
|
604
|
-
prev.next = item;
|
|
605
|
-
}
|
|
610
|
+
i,
|
|
611
|
+
e: branch(() => {
|
|
612
|
+
render_fn(anchor, v ?? value, i ?? index, get_collection);
|
|
606
613
|
|
|
607
|
-
|
|
614
|
+
return () => {
|
|
615
|
+
items.delete(key);
|
|
616
|
+
};
|
|
617
|
+
})
|
|
618
|
+
};
|
|
608
619
|
}
|
|
609
620
|
|
|
610
621
|
/**
|
|
611
|
-
* @param {
|
|
612
|
-
* @param {
|
|
622
|
+
* @param {Effect} effect
|
|
623
|
+
* @param {Effect | null} next
|
|
613
624
|
* @param {Text | Element | Comment} anchor
|
|
614
625
|
*/
|
|
615
|
-
function move(
|
|
616
|
-
if (!
|
|
626
|
+
function move(effect, next, anchor) {
|
|
627
|
+
if (!effect.nodes) return;
|
|
617
628
|
|
|
618
|
-
var
|
|
629
|
+
var node = effect.nodes.start;
|
|
630
|
+
var end = effect.nodes.end;
|
|
619
631
|
|
|
620
|
-
var dest =
|
|
621
|
-
|
|
632
|
+
var dest =
|
|
633
|
+
next && (next.f & EFFECT_OFFSCREEN) === 0
|
|
634
|
+
? /** @type {EffectNodes} */ (next.nodes).start
|
|
635
|
+
: anchor;
|
|
622
636
|
|
|
623
|
-
while (node !== null
|
|
637
|
+
while (node !== null) {
|
|
624
638
|
var next_node = /** @type {TemplateNode} */ (get_next_sibling(node));
|
|
625
639
|
dest.before(node);
|
|
640
|
+
|
|
641
|
+
if (node === end) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
626
645
|
node = next_node;
|
|
627
646
|
}
|
|
628
647
|
}
|
|
629
648
|
|
|
630
649
|
/**
|
|
631
650
|
* @param {EachState} state
|
|
632
|
-
* @param {
|
|
633
|
-
* @param {
|
|
651
|
+
* @param {Effect | null} prev
|
|
652
|
+
* @param {Effect | null} next
|
|
634
653
|
*/
|
|
635
654
|
function link(state, prev, next) {
|
|
636
655
|
if (prev === null) {
|
|
637
|
-
state.first = next;
|
|
638
|
-
state.effect.first = next && next.e;
|
|
656
|
+
state.effect.first = next;
|
|
639
657
|
} else {
|
|
640
|
-
if (prev.e.next) {
|
|
641
|
-
prev.e.next.prev = null;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
658
|
prev.next = next;
|
|
645
|
-
prev.e.next = next && next.e;
|
|
646
659
|
}
|
|
647
660
|
|
|
648
|
-
if (next
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
|
|
661
|
+
if (next === null) {
|
|
662
|
+
state.effect.last = prev;
|
|
663
|
+
} else {
|
|
653
664
|
next.prev = prev;
|
|
654
|
-
next.e.prev = prev && prev.e;
|
|
655
665
|
}
|
|
656
666
|
}
|