schedgrid/core
createGrid, the engine. No platform dependencies.
import { createGrid } from 'schedgrid/core';createGrid holds the state, rebuilds the expensive pieces only when their
own inputs change and the cheap frame whenever anything does. Nothing in
this module touches a platform API. It compiles without the DOM lib.
createGrid(options)
Prop
Type
rows and columns each describe one axis:
Prop
Type
A size is a SizeSpec: either a constant number of pixels or a function of
the index, which is how a header row gets a different height from the body
rows:
type SizeSpec = number | ((index: number) => number);
rows: { count: 201, size: (i) => (i === 0 ? 32 : 40), pinned: 1 }lanes is 'rows', 'columns' or false. See
Concepts.
Items
Prop
Type
The grid
The object createGrid returns. Every setter replaces one slice of state
and notifies subscribers once; wrap several in batch to notify once for
all of them.
Prop
Type
rows and columns expose read-only queries on each axis, all in content
space:
Prop
Type
The frame
Everything a renderer needs to draw one frame. Plain numbers only.
Prop
Type
Prop
Type
Prop
Type
frame.cells() builds the cross product of the frame's rows and columns on
first call and caches it. Use it when every cell needs a DOM node or a
canvas fill; skip it when only lines and items are drawn.
Prop
Type
frame.range is the scrollable index range the frame covers, pinned entries
excluded — the rows and columns a data source would need to fetch:
Prop
Type
total, viewport and scroll are the two shapes every measurement in the
library uses:
Prop
Type
Prop
Type
State
getState() returns the resolved options — the same shape you passed to
createGrid, with the defaults filled in:
Prop
Type
Utilities
The module also exports the pieces the engine is built from, for anyone who wants to lay out items without a grid.
assignLanes(items, mode)
function assignLanes(items: readonly Item[], mode: LaneMode): Lane[];One Lane per item, in the order the items were given. Greedy interval
colouring generalised to rectangles: items are swept along one axis in start
order and each takes the lowest lane not used by an overlapping item already
placed. Overlapping items are unioned into a cluster and every member reports
the cluster's lane count, so a renderer can give each item 1 / lanes of the
shared extent.
It runs over every item, not just the visible ones — an off-screen item can
still push a visible one into a higher lane, and lanes must not shift as the
user scrolls. The grid memoises the result on items identity, so passing
the same array back costs nothing.
Prop
Type
mode is the same LaneMode the grid takes, and picks which dimension is
divided when items overlap. See Concepts.
type LaneMode = 'rows' | 'columns' | false;itemsIntersect(a, b) and rangesIntersect(a, b)
function rangesIntersect(
a: readonly [number, number],
b: readonly [number, number],
): boolean;
function itemsIntersect(a: Item, b: Item): boolean;Overlap of half-open ranges: touching ranges do not intersect, so [0, 3]
and [3, 5] are apart. itemsIntersect is rangesIntersect on both axes.
createStore(initial)
function createStore<T extends object>(initial: T): Store<T>;The subscribable store behind getState, subscribe and batch: the
smallest one useSyncExternalStore is happy with. Snapshots are immutable —
a new object per change — and set skips the notification entirely when
every patched key is Object.is-equal to the current value, which is why a
scroll handler reporting the same offset twice costs nothing downstream.
Prop
Type