/** * Main Thread native `` recycler support. * * Lynx's `` is NOT a plain scrolling container — it's a managed recycler. * Native pulls each visible cell by calling `componentAtIndex(cellIndex)` and * recycles offscreen cells via `enqueueComponent(sign)`. If its * `update-list-info` metadata is never set, native crashes during layout * (`UIList.onLayoutCompleted` NPE — issue #120). * * Two kinds of cells coexist (#620): * * - **Eager per-element cells** (the pre-snapshot path, still used by * library dists and non-compiled subtrees): the Background Thread builds * the whole `` subtree through element ops; `componentAtIndex` * just returns the prebuilt element's sign, and `enqueueComponent` is a * no-op (each row owns its dedicated subtree). * * - **Snapshot-template cells** (compiled `` subtrees): rows stay * cheap STAGED instance records — `order[]` of instance ids IS the row * manifest — and `componentAtIndex` materializes the pulled cell * synchronously (`ensureElements()` + append + flush), so a fling can * never observe a blank cell. `enqueueComponent` is REAL here: the cell's * elements move into a pool keyed by `templateId|reuse-identifier`, and a * later pull for a same-shaped row ADOPTS a pooled tree and re-patches its * dynamic holes instead of constructing. * * A compiled `` itself is a template whose `create()` calls * `snapshotCreateList` (→ `createListElementForSnapshot` here), and whose * ListSlotV2 slot id is registered as an ALIAS of the list state * (`registerListSlotAlias`) so ordinary INSERT/REMOVE ops of item instances * route through `listInsertChild`/`listRemoveChild` unchanged. * * What this module owns: * - Creating `` via `__CreateList` (so the callbacks are registered). * - Tracking each list's ordered children (BG insertion order) and their * per-item platform info (item-key etc.) — for staged snapshot cells the * info is read from the instance's platform-info hole (`__values[0]`, * shape-validated; the transform pins it there) at flush time. * - Emitting `update-list-info` diffs (insert/remove actions) at the end of * each ops batch. Like the eager path, per-item info is carried at * insert time only (`updateAction` stays empty). * - The recycle pools and sign → row bookkeeping for template cells. * * `` children are intercepted here instead of being appended to the * list element directly (the recycler owns attachment via `componentAtIndex`). */ import { type MTSnapshotInstance } from './snapshot-mt.js'; /** True when `internalId` is a `` element (or alias) managed here. */ export declare function isListElement(internalId: number): boolean; /** True when `internalId` is a direct `` child of some ``. */ export declare function isListChild(internalId: number): boolean; /** Create a `` element and register its recycler callbacks. */ export declare function createListElement(internalId: number): MainThreadElement; /** * `snapshotCreateList` target (compiled `` create bodies, routed via * snapshot-mt's createList hook). The template instance's BG id keys the * state, so REMOVE of the instance tears the list down through the same * `destroyListElement` path as op-built lists. */ export declare function createListElementForSnapshot(inst: MTSnapshotInstance): MainThreadElement; /** * Register a bound ListSlotV2 slot id as an alias of its list's state, so * INSERT/REMOVE ops naming the slot as parent route through * `listInsertChild`/`listRemoveChild` (the BG inserts item instances into * the slot element — see nodeOps' bind replay). */ export declare function registerListSlotAlias(listInternalId: number, aliasId: number): void; /** * Record a `` inserted into a ``. We do NOT append it to the * list element here — the recycler attaches it on demand via * `componentAtIndex`. `anchorInternalId` is the real sibling to insert before, * or -1 to append. * * An insert of a child that is already in the list is a MOVE: the BG shadow * tree detaches implicitly on insertBefore and emits no REMOVE op (keyed * reorders arrive as bare inserts), so drop the old occurrence first — * before the anchor lookup, so the anchor index isn't stale. */ export declare function listInsertChild(listInternalId: number, childInternalId: number, anchorInternalId: number): void; /** * Record a `` removed from a ``. * * A cell native currently BINDS (it was pulled via `componentAtIndex` and not * yet enqueued) must be left COMPLETELY intact here — attached, registered, * sign-mapped: native discovers the removal only from the next * `update-list-info` diff, and reconciling it touches the outgoing cell * (RecycleRemovedItemHolders → OnEnqueueElement → SendExposureEvent). * Both destroying the cell AND merely detaching it at REMOVE-op time crash * native during that reconciliation (SIGSEGV typing in a list-filtering * search box; core#275 — detach-early refaults at the same frames with a * null-pointer call). Such cells become ZOMBIES: gone from `order` (so the * diff reports them removed and no pull can serve them) but fully wired * until native releases the holder via `enqueueComponent`, which then * detaches, pools the tree, and destroys the instance. This mirrors the * reference runtime, whose list-holder removeChild never detaches or drops * elements — teardown waits for the recycler. */ export declare function listRemoveChild(listInternalId: number, childInternalId: number): void; /** Tear down a `` element (detach callbacks, drop all state). */ export declare function destroyListElement(internalId: number): void; /** * Record a platform-info prop on a ``. Returns true if `key` is a * recognised platform-info key (the caller still sets it as a normal element * attribute regardless). Safe to call before the item's insert op arrives — * the info is stashed by child id and read at flush time. */ export declare function noteListItemProp(childInternalId: number, key: string, value: unknown): void; /** * Emit `update-list-info` diffs for every list whose children changed during * the current ops batch. Called once per batch, before the final * `__FlushElementTree`. * * The wire format is insert/remove only, so a MOVE (keyed reorder) is encoded * as remove + re-insert. Kept items whose relative order is unchanged — the * longest increasing subsequence of old indices taken in new order — stay put; * every other item is removed and re-inserted at its new position, so applying * the diff reproduces `state.order` exactly on native. `removeAction` carries * ascending OLD indices; `insertAction` carries ascending NEW positions, each * with the item's type and platform info. This matches the order the * host/native recycler applies them (remove first, then insert). */ export declare function flushDirtyLists(): void; /** Reset all list state — for testing and hot reload. */ export declare function resetListState(): void;