From be0785e6a2c6a51b23d1b469505875aba730cea4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 2 Dec 2025 20:05:26 -0500 Subject: [PATCH] WIP --- .../svelte/src/internal/client/constants.js | 1 + .../src/internal/client/dom/blocks/each.js | 39 +++++++++---------- .../svelte/src/internal/client/types.d.ts | 8 ++-- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/packages/svelte/src/internal/client/constants.js b/packages/svelte/src/internal/client/constants.js index a121e6674a..a1bdb8a985 100644 --- a/packages/svelte/src/internal/client/constants.js +++ b/packages/svelte/src/internal/client/constants.js @@ -40,6 +40,7 @@ export const EAGER_EFFECT = 1 << 17; export const HEAD_EFFECT = 1 << 18; export const EFFECT_PRESERVED = 1 << 19; export const USER_EFFECT = 1 << 20; +export const EFFECT_OFFSCREEN = 1 << 25; // Flags exclusive to deriveds /** diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index d86378079b..50ac3836a3 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -34,7 +34,7 @@ import { } from '../../reactivity/effects.js'; import { source, mutable_source, internal_set } from '../../reactivity/sources.js'; import { array_from, is_array } from '../../../shared/utils.js'; -import { COMMENT_NODE, INERT } from '#client/constants'; +import { COMMENT_NODE, EFFECT_OFFSCREEN, INERT } from '#client/constants'; import { queue_micro_task } from '../task.js'; import { get } from '../../runtime.js'; import { DEV } from 'esm-env'; @@ -131,7 +131,7 @@ function pause_effects(state, to_destroy, controlled_anchor) { */ function destroy_items(state, to_destroy) { // TODO only destroy effects if no pending batch needs them. otherwise, - // just set `item.o` back to `false` + // just re-add the `EFFECT_OFFSCREEN` flag for (var i = 0; i < to_destroy.length; i++) { var effect = to_destroy[i]; @@ -282,8 +282,8 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f get_collection ); - if (first_run) { - item.o = true; + if (!first_run) { + item.e.f |= EFFECT_OFFSCREEN; } items.set(key, item); @@ -394,9 +394,6 @@ function reconcile(state, array, anchor, flags, get_key) { /** @type {any} */ var key; - /** @type {EachItem | undefined} */ - var item; - /** @type {Effect | undefined} */ var effect; @@ -407,13 +404,13 @@ function reconcile(state, array, anchor, flags, get_key) { for (i = 0; i < length; i += 1) { value = array[i]; key = get_key(value, i); - item = /** @type {EachItem} */ (items.get(key)); + effect = /** @type {EachItem} */ (items.get(key)).e; // offscreen == coming in now, no animation in that case, // else this would happen https://github.com/sveltejs/svelte/issues/17181 - if (item.o) { - item.e.nodes?.a?.measure(); - (to_animate ??= new Set()).add(item.e); + if ((effect.f & EFFECT_OFFSCREEN) === 0) { + effect.nodes?.a?.measure(); + (to_animate ??= new Set()).add(effect); } } } @@ -422,8 +419,7 @@ function reconcile(state, array, anchor, flags, get_key) { value = array[i]; key = get_key(value, i); - item = /** @type {EachItem} */ (items.get(key)); - effect = item.e; + effect = /** @type {EachItem} */ (items.get(key)).e; if (state.outrogroups !== null) { for (const group of state.outrogroups) { @@ -434,8 +430,8 @@ function reconcile(state, array, anchor, flags, get_key) { } } - if (!item.o) { - item.o = true; + if ((effect.f & EFFECT_OFFSCREEN) !== 0) { + effect.f ^= EFFECT_OFFSCREEN; if (effect === current) { move(effect, null, anchor); @@ -586,10 +582,12 @@ function reconcile(state, array, anchor, flags, get_key) { // Append offscreen items at the end if (has_offscreen_items) { - for (const item of items.values()) { - if (!item.o) { - link(state, prev, item.e); - prev = item.e; + for (var item of items.values()) { + effect = item.e; + + if ((effect.f & EFFECT_OFFSCREEN) !== 0) { + link(state, prev, effect); + prev = effect; } } } @@ -676,9 +674,8 @@ function create_item(items, anchor, value, key, index, render_fn, flags, get_col } return { - i, v, - o: false, + i, e: branch(() => { render_fn(/** @type {Node} */ (anchor), v, i, get_collection); diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index 475dd120f7..2b0de5a039 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -89,14 +89,12 @@ export type EachState = { }; export type EachItem = { - /** effect */ - e: Effect; - /** item */ + /** value */ v: any | Source; /** index */ i: number | Source; - /** true if onscreen */ - o: boolean; + /** effect */ + e: Effect; }; export interface TransitionManager {