import { type TimeRange, type TimeUnit, type WeekStart } from './calendar'; import { type SlotAxis } from './slot-axis'; /** * How slot widths relate to slot durations. * * `'equal'` gives every slot the same width regardless of duration — a February * column is as wide as a January one. Reads as a *resource planner*. * `'proportional'` scales width with duration, so February is visibly shorter. * Reads as a *Gantt chart*. Neither is more correct; they answer different * questions. */ export type SlotWidthMode = 'equal' | 'proportional'; /** One row of the timeline header, above the slot row. */ export interface HeaderBand { readonly unit: TimeUnit; readonly step: number; } /** * Everything that defines a timeline. * * Note there is no `view` field. A "month view" is not a mode with its own code * path — it is this config with `unit: 'day'` and a month header band. That is * the whole reason a single engine can serve every view: the views differ in * data, not in behaviour. */ export interface TimelineConfig { /** Granularity of one slot. */ readonly unit: TimeUnit; /** Units per slot. `{ unit: 'minute', step: 15 }` gives quarter-hour slots. */ readonly step: number; /** The span the timeline covers. */ readonly range: TimeRange; /** Width of one slot in pixels (the *typical* width in proportional mode). */ readonly slotWidth: number; /** @default 'equal' */ readonly slotWidthMode?: SlotWidthMode; /** Header rows above the slot row, outermost first. */ readonly headerBands?: readonly HeaderBand[]; /** @default 1 (Monday) */ readonly weekStartsOn?: WeekStart; } /** A single header cell: one span of a header band. */ export interface HeaderCell { readonly startMs: number; readonly endMs: number; /** Pixel offset of the cell's left edge. */ readonly offsetPx: number; /** Pixel width of the cell. */ readonly widthPx: number; } /** One resolved header band, with its cells. */ export interface ResolvedHeaderBand { readonly unit: TimeUnit; readonly step: number; readonly cells: readonly HeaderCell[]; } /** * Named view presets. * * Each is nothing but a `{ unit, step, headerBands }` triple — which is the * point. Adding a view is adding a table entry, not a code path, and a host that * needs something unusual (six-hour slots over a fortnight) passes a raw * {@link TimelineConfig} instead of picking a name. * * Kept in its own const so it tree-shakes away for a host that only ever uses * explicit configs. */ export declare const TIMELINE_PRESETS: { /** Hours across one day. */ readonly day: { readonly unit: "hour"; readonly step: 1; readonly headerBands: [{ readonly unit: "day"; readonly step: 1; }]; }; /** Days across one week. */ readonly week: { readonly unit: "day"; readonly step: 1; readonly headerBands: [{ readonly unit: "week"; readonly step: 1; }]; }; /** Days across one month — the classic vacation planner. */ readonly month: { readonly unit: "day"; readonly step: 1; readonly headerBands: [{ readonly unit: "month"; readonly step: 1; }]; }; /** Weeks across a quarter. */ readonly quarter: { readonly unit: "week"; readonly step: 1; readonly headerBands: [{ readonly unit: "month"; readonly step: 1; }]; }; /** Months across a year. */ readonly year: { readonly unit: "month"; readonly step: 1; readonly headerBands: [{ readonly unit: "quarter"; readonly step: 1; }]; }; }; /** Name of a built-in view preset. */ export type TimelineViewName = keyof typeof TIMELINE_PRESETS; /** * The resolved timeline: an axis, header bands, and the config that produced * them. * * Immutable. Changing the view or range builds a new one rather than mutating, * so "did the timeline change?" is a reference comparison — which is what lets * the renderer skip work on a pure scroll. */ export interface Timeline { readonly config: TimelineConfig; readonly axis: SlotAxis; readonly bands: readonly ResolvedHeaderBand[]; /** Fence posts of the slot row. `count + 1` entries. */ readonly ticks: readonly number[]; } /** * Builds a {@link Timeline} from a config. * * The one interesting decision here is which axis implementation to use, and it * is made on two questions: * * 1. Are slot *widths* equal? (`slotWidthMode !== 'proportional'`) * 2. Are slot *durations* equal? * * Minute and hour are fixed-duration by definition. Day and week are equal * *unless* a DST transition falls in range — detected by probing month * boundaries, which is ~120 cheap probes for a decade rather than materialising * millions of edges. Month, quarter and year are never equal. * * Both answers yes ⇒ {@link UniformAxis} and no allocation. Otherwise a * {@link PrefixAxis}, whose cost is bounded because the units that force it are * exactly the coarse ones with few slots. */ export declare function buildTimeline(config: TimelineConfig): Timeline; /** Builds a timeline from a named preset over a range. */ export declare function buildTimelineFromView(view: TimelineViewName, range: TimeRange, slotWidth: number, overrides?: Partial): Timeline; //# sourceMappingURL=timeline-engine.d.ts.map