/** * Which projected lines a content block materializes for a given visible band. * * Extracted as a **shared module** rather than onto a collaborator because both * sides of the grid cut need it. `Scene.syncContentProjection` calls * {@link projectionLineWindow} for the plain carrier branch and stays on the * facade; {@link ContentGridProjector} calls {@link projectionGridLineWindow} for * the grid branch and has moved. Duplicating the scan would let the two branches * disagree about which lines are present, and a window that disagrees with the * carriers it drives serves stale geometry to selection and find-in-page. * * This is the `content-caret` precedent from `DEC-0022`: a stateless helper that * outlived the class it was private to. * * Every symbol here was module-private in `Scene.ts` and stays module-private to * the package. The core barrel re-exports everything from `./tree/Scene`, so * re-exporting from there would silently widen the public API (`DEC-0019` rule 3). * * Stateless by design — no `Scene`, no entities, no DOM. */ import type { PreparedContentGrid } from '@vectojs/text'; import type { ContentProjection } from '../Entity'; /** Half-open range of projected line indices to materialize. */ export interface ProjectionLineWindow { start: number; /** Exclusive. */ end: number; /** False when the whole document is being projected. */ gated: boolean; } /** * The contiguous run of lines overlapping `band`, in entity-local y. * * **Contiguous on purpose.** A gap would break selection: the DOM order of * carriers is what the browser walks when extending a selection or serialising * a copy, so materializing lines 0-9 and 90-99 with nothing between them would * let a drag from line 5 to line 95 silently splice out 80 lines of text. A * single window can only lose text at its *edges*, where the user cannot reach * without scrolling, and scrolling rebuilds the window. * * Falls back to the whole document whenever the answer is not clearly better: * a null band, a document that fits, or a window that would cover everything * anyway. Emitting nothing is never correct — projected text is what serves * find-in-page, copy and, for static text, the screen reader. */ export declare function projectionLineWindow(lines: ReadonlyArray<{ y: number; lineHeight?: number; }>, band: { minY: number; maxY: number; } | null, fallbackLineHeight: number): ProjectionLineWindow; /** * {@link projectionLineWindow} for a prepared grid. * * A grid line's y comes from the parallel `projection.lines` entry when present * and otherwise from `lineIndex * grid.lineHeight`, which is the same fallback * the materialization loop uses for positioning — so the window and the carriers * always agree on where a line is. */ export declare function projectionGridLineWindow(grid: PreparedContentGrid, projectionLines: ContentProjection['lines'], band: { minY: number; maxY: number; } | null): ProjectionLineWindow;