import type { RenderWindow } from '../../plugin.types'; import type { RowNode } from '../../../types/row.types'; import type { SlotAxis } from '../time/slot-axis'; import type { EventIndex } from '../data/event-index'; import { type LaneInput } from './lane-layout'; /** Placement of one event bar, in the layer's coordinate space. */ export interface BarPlacement { /** Stable key for DOM recycling: `resourceId \0 eventId`. */ readonly key: string; /** Pool handle, for resolving the event. */ readonly handle: number; readonly resourceId: string; /** Absolute content-space x. The layer's own translate handles panning. */ readonly left: number; /** Rebased y — see {@link RenderWindow.rowOriginY}. */ readonly top: number; readonly width: number; readonly height: number; readonly lane: number; readonly laneCount: number; } /** Tuning for {@link computeBarLayout}. */ export interface BarLayoutOptions { /** Vertical inset at the top and bottom of a row. @default 2 */ readonly rowPaddingY?: number; /** Gap between stacked lanes. @default 2 */ readonly laneGap?: number; /** * Floor on rendered bar width. * * Without it a one-minute event in a year view computes to a fraction of a * pixel and disappears — worse than being slightly wrong, because the user * has no way to find or fix data they cannot see. * @default 3 */ readonly minWidth?: number; /** * Ceiling on bars produced in one frame. * * Past this the bars are narrower than their own text and the view is not * communicating anything; the renderer is expected to fall back to a per-row * summary. A hard cap also stops one pathological resource from stalling a * frame. * @default 800 */ readonly maxBars?: number; } /** Reusable scratch, so a steady-state frame allocates nothing. */ export interface BarLayoutScratch { handles: number[]; lanes: LaneInput[]; } /** Creates the scratch buffers {@link computeBarLayout} reuses across frames. */ export declare function createBarLayoutScratch(): BarLayoutScratch; /** Result of one layout pass. */ export interface BarLayoutResult { readonly bars: BarPlacement[]; /** `true` when {@link BarLayoutOptions.maxBars} clipped the output. */ readonly truncated: boolean; } /** * Computes every event bar for one frame. * * **Pure**: it reads no DOM and measures nothing, which is what makes the whole * positioning story unit-testable in the `node` environment — the package has no * jsdom, and its DOM stub returns zeros from `getBoundingClientRect`. The * renderer that consumes this is a thin loop that writes `transform`. * * ## The rebasing contract * * `RowNode.top` is absolute content-space, but the grid writes * `top - rowOriginY` into its row stylesheet and translates the panels by * `--pg-row-offset-y`. Bars must live in that same rebased space or they drift * from their resource rows on every scrolled frame. Hence `top` here is always * `row.top - window.rowOriginY`, and a layer mounted with `followRowOrigin` * needs no vertical repositioning on scroll at all. * * Horizontally the mirror image: `left` is absolute content-space and a layer * mounted with `followScrollX` tracks panning through its own transform. So in * the steady state a pure scroll changes **no** bar's geometry — the layout is * recomputed but produces identical numbers, and the renderer's diff writes * nothing. * * @param window - The grid's render window for this frame. * @param axis - Time-to-pixel projection. * @param index - Event index to query. * @param resourceIdOf - Maps a grid row to a resource id; return `null` for * rows that are not resources (group headers, detail rows, summaries). * @param scratch - Reused buffers from {@link createBarLayoutScratch}. */ export declare function computeBarLayout(window: RenderWindow, axis: SlotAxis, index: EventIndex, resourceIdOf: (row: RowNode) => string | null, scratch: BarLayoutScratch, options?: BarLayoutOptions): BarLayoutResult; //# sourceMappingURL=bar-layout.d.ts.map