import type { GridPlugin, PluginContext, RenderWindow } from '../plugin.types'; import type { RowNode } from '../../types/row.types'; import { type Timeline } from './time/timeline-engine'; import { type SchedulerConfig } from './scheduler.config'; import { type SchedulerRuntime } from './scheduler-runtime'; import { SchedulerApi } from './api/scheduler-api'; /** * Timeline scheduler for Photon Grid. * * Resources are ordinary grid rows — so sorting, filtering, grouping, pinning * and row virtualization all come from the grid for free — and the timeline is a * plugin-owned layer mounted beside them. Events live in their own index rather * than inside row data, because an event is not a property of a resource: one * resource has an unbounded, independently-mutating set of them, and nesting * would make every event change re-run the grid's row pipeline. * * ## Why time slots are not columns * * The obvious design is one `ColumnDef` per time slot. It does not survive * contact with the numbers: ten years at daily granularity is ~3,650 columns, * and the grid's column path writes one CSS rule per column into a single * stylesheet, builds the entire centre header un-virtualized, and runs three * separate O(N) passes per frame. So the timeline owns its own axis and its own * horizontal virtualization, which is also what lets it reach minute * granularity over a decade — 5.26 million slots, at zero allocation. * * ## How it stays in step with the grid * * The layer is mounted with `followRowOrigin` and `followScrollX`, which apply * the same transforms the grid's own panels use. Bars are positioned in * *rebased* row space (`row.top - rowOriginY`) and *absolute* content-x, so a * pure scroll moves them via the layer transform and writes no styles at all. * That is the design's central claim and the reason it holds at 100k resources. * * @example * ```ts * import { SchedulerPlugin } from 'photon-grid-core/plugins/scheduler'; * * new GridCore(el, { * columns: [{ field: 'name', header: 'Employee', pinned: 'left', width: 200 }], * data: resources, * plugins: [new SchedulerPlugin({ resources, events, view: 'month' })], * }); * ``` */ export declare class SchedulerPlugin implements GridPlugin { private readonly raw; readonly id: string; readonly name = "Photon Scheduler"; private readonly config; private readonly index; private readonly selection; private readonly resourceById; private readonly eventById; /** Every subsystem, torn down in one loop rather than a hand-maintained list. */ private readonly modules; private runtime; private timeline; private ctx; private backdrop; private barRenderer; private header; private selectionService; /** The plugin public API. Available after `init`. */ private api; private bodyLayerEl; private headerHostEl; /** Last window received, so an out-of-band refresh can repaint without waiting for a scroll. */ private lastWindow; constructor(raw?: SchedulerConfig, id?: string); init(ctx: PluginContext): void; /** * Constructs every subsystem and records it for teardown. * * Order matters in one place only: the keyboard service needs the selection * service, so selection is built first. Everything else is independent — * services talk to each other through the runtime and through the narrow * ports declared at their own boundaries, never by importing one another. */ private buildModules; /** * Resolves the resource under a viewport Y coordinate, for cross-resource drags. * * Owned by the plugin rather than the drag service because it is the only * piece that knows both the render window (which rows are on screen and where) * and the grid's rebasing — the service would otherwise need both, and would * be untestable without a DOM. */ private resourceAtY; /** Scrolls the grid so a resource's row is visible. */ private scrollToResource; /** * Per-frame entry point. * * Everything downstream reads its geometry from this window rather than * measuring, so the scheduler never forces a layout during a scroll. */ onRenderWindow(window: RenderWindow): void; destroy(): void; /** * Sizes the header and body regions to the grid's centre area. * * The plugin layer spans the whole body, so both regions are inset by the * pinned panel widths the render window reports. Written every frame but * guarded by a value check, because panel widths only change on a resize or a * pin, not on a scroll. */ private layoutRegions; /** Builds the timeline from whichever config form the host supplied. */ private buildTimeline; private createRuntime; /** Maps a grid row to a resource id, honouring the host's override. */ resourceIdOfRow: (row: RowNode) => string | null; /** The resolved runtime, for the API and for tests. */ getRuntime(): SchedulerRuntime; /** The most recent render window, so an out-of-band refresh can repaint. */ getLastWindow(): RenderWindow | null; /** * The scheduler public API: events, selection, view, navigation, refresh. * * Only valid after the grid has initialized the plugin, which happens before * `GridEventType.READY` -- so a host reading it from `onReady` is safe. */ getApi(): SchedulerApi; /** Replaces the timeline, rebuilds the header and repaints. */ setTimeline(next: Timeline): void; } //# sourceMappingURL=scheduler-plugin.d.ts.map