Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 9x 9x 16x 16x 20x 20x 20x 5x 5x 15x 15x 15x 16x 24x 4x 4x 4x 2x 2x 2x 2x | /**
* @packageDocumentation
*
* Handle lifecycle reconciler for the scrollable canvas.
*
* Owns the `Map<string, RenderHandle>` and drives creation, update,
* and disposal of render handles based on successive `RenderObject[]`
* snapshots. DOM (or test) concerns are injected via `ReconcileCallbacks`.
*/
import type { RenderHandle, RenderObject } from "./index";
export interface ReconcileCallbacks {
onAdd(key: string, handle: RenderHandle, obj: RenderObject): void;
onUpdate(key: string, handle: RenderHandle, obj: RenderObject): void;
onRemove(key: string, handle: RenderHandle): void;
}
/**
* Reconciles a stream of `RenderObject` snapshots against an internal
* `Map<string, RenderHandle>`.
*
* - New keys → `renderer()` → `onAdd`
* - Existing keys → `handle.update()` → `onUpdate`
* - Stale keys → `handle[Symbol.dispose]()` → `onRemove`
*/
export class RenderObjectReconciler {
private handles = new Map<string, RenderHandle>();
private callbacks: ReconcileCallbacks;
constructor(callbacks: ReconcileCallbacks) {
this.callbacks = callbacks;
}
reconcile(objects: RenderObject[]): void {
const activeKeys = new Set<string>();
for (const obj of objects) {
activeKeys.add(obj.key);
const existing = this.handles.get(obj.key);
if (existing) {
existing.update(obj.data);
this.callbacks.onUpdate(obj.key, existing, obj);
} else {
const handle = obj.renderer(obj.data);
this.handles.set(obj.key, handle);
this.callbacks.onAdd(obj.key, handle, obj);
}
}
for (const [key, handle] of this.handles) {
if (!activeKeys.has(key)) {
handle[Symbol.dispose]?.();
this.callbacks.onRemove(key, handle);
this.handles.delete(key);
}
}
}
disposeAll(): void {
for (const [key, handle] of this.handles) {
handle[Symbol.dispose]?.();
this.callbacks.onRemove(key, handle);
}
this.handles.clear();
}
}
|