File size: 1,654 Bytes
064bfd6 | 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 | import type { DOMElement } from './dom.js'
import type { Rectangle } from './layout/geometry.js'
/**
* Cached layout bounds for each rendered node (used for blit + clearing).
* `top` is the yoga-local getComputedTop() — stored so ScrollBox viewport
* culling can skip yoga reads for clean children whose position hasn't
* shifted (O(dirty) instead of O(mounted) first-pass).
*/
export type CachedLayout = {
x: number
y: number
width: number
height: number
top?: number
}
export const nodeCache = new WeakMap<DOMElement, CachedLayout>()
/** Rects of removed children that need clearing on next render */
export const pendingClears = new WeakMap<DOMElement, Rectangle[]>()
/**
* Set when a pendingClear is added for an absolute-positioned node.
* Signals renderer to disable blit for the next frame: the removed node
* may have painted over non-siblings (e.g. an overlay over a ScrollBox
* earlier in tree order), so their blits from prevScreen would restore
* the overlay's pixels. Normal-flow removals are already handled by
* hasRemovedChild at the parent level; only absolute positioning paints
* cross-subtree. Reset at the start of each render.
*/
let absoluteNodeRemoved = false
export function addPendingClear(
parent: DOMElement,
rect: Rectangle,
isAbsolute: boolean,
): void {
const existing = pendingClears.get(parent)
if (existing) {
existing.push(rect)
} else {
pendingClears.set(parent, [rect])
}
if (isAbsolute) {
absoluteNodeRemoved = true
}
}
export function consumeAbsoluteRemovedFlag(): boolean {
const had = absoluteNodeRemoved
absoluteNodeRemoved = false
return had
}
|