# Functions

Import these from `@grafloria/element`.

## Functions

### `bindDashboardGrid`

```ts
function bindDashboardGrid(
  api: DashboardGridApi,
  group: GroupModel,
  options: DashboardGridOptions = {}
): DashboardGridHandle
```

### `boardHeightFor`

The board frame height the mode implies for `rows` rows.

```ts
function boardHeightFor(g: DashboardGridGeometry, rows: number): number
```

### `buildCommitCommands`

```ts
function buildCommitCommands(deltas: TileDelta[]): Command[]
```

### `captionBandHeight`

The band's height for a section of `sectionH` px: the authored height (or
the tier), CLAMPED so the children always keep `CAPTION_MIN_CONTENT` px. A
one-row section used to hand its whole 34 px to a 22 px band and paint a
12 px sliver of a child.

```ts
function captionBandHeight(c: SectionCaptionOptions, sectionH: number): number
```

### `captionReserve`

Pixels the nested board's frame gives up at the top: the band plus its
vertical margins. A TAB reserves too — it is a narrower band, not a header
hanging over whatever the parent board put above the section (the stress
page had one lying across a chart's legend, and one clipped off the top of
the canvas). Only `show: 'hover'` reserves nothing: it is an overlay by
definition, and it paints opaque so the content beneath stays readable.

```ts
function captionReserve(c: SectionCaptionOptions | null, ctx: { static: boolean; sectionH: number }): number
```

### `cellFromGridItem`

GridItemConfig → engine cells, or null when the config carries no usable
placement (absent, or 'auto' lines). `fallback` fills spans a partial
config omits — the first-adoption path uses metadata `columnSpan` there.

```ts
function cellFromGridItem(
  gi: GridItemConfig | undefined,
  fallback?: { w?: number; h?: number }
): CellRect | null
```

### `cellToRect`

Project integer cells into a world rectangle inside `frame`.

RTL mirrors about the board's vertical centre line: the distance from the
board's RIGHT padding edge to the tile's RIGHT edge equals what the LTR
distance from the left padding edge to the tile's LEFT edge would be. Only
the x term changes — rows, heights and spans are direction-agnostic.

```ts
function cellToRect(
  cell: CellRect,
  frame: WorldRect,
  g: DashboardGridGeometry,
  rows: number
): WorldRect
```

### `columnUnitFor`

Width of one column cell for a board `width` px wide.

```ts
function columnUnitFor(g: DashboardGridGeometry, width: number): number
```

### `dashboard`

```ts
function dashboard(options: DashboardOptions): DashboardSpec
```

### `ensureDashboardKitStyles`

Idempotently inject the kit stylesheet (safe to call per binder).

```ts
function ensureDashboardKitStyles(doc?: Document): void
```

### `gridItemFromCell`

Engine cells → the GridItemConfig that persists them.

```ts
function gridItemFromCell(cell: CellRect): GridItemConfig
```

### `normalizeCaption`

The caption as options, or null when there is none. `title` fills the text.

```ts
function normalizeCaption(c: SectionCaption | undefined, title?: string): SectionCaptionOptions | null
```

### `paintCaptionBand`

Paint the band: geometry (inline, so the reserve and the pixels agree),
classes for alignment and mode, CSS variables for typography and box, and
the default content — icon, text, subtitle, ⓘ, actions. With `render` the
content is yours: the band is handed over empty and keeps its press rules.

```ts
function paintCaptionBand(
  band: HTMLElement,
  c: SectionCaptionOptions,
  ctx: { rtl: boolean; static: boolean; sectionH: number; render?: (host: HTMLElement) => void; onAction?: (actionId: string) => void }
): void
```

### `paintTabStrip`

```ts
function paintTabStrip(
  strip: HTMLElement,
  pages: TabPage[],
  activeId: string,
  o: TabsOptions | undefined,
  rtl: boolean,
  onPick: (id: string) => void,
  onSelectContainer?: (e: PointerEvent) => void,
  /**
   * The tab is the PAGE's drag handle, as it is in VS Code: press one and
   * travel, and the whole page leaves — not the widget under the pointer,
   * which used to be the only way to drag anything out and left the tab
   * behind pointing at an empty page.
   */
  onDrag?: (pageId: string, ev: PointerEvent) => boolean
): void
```

### `pointToCell`

The cell whose slot a tile TOP-LEFT at world (x, y) is closest to — the
prototype's margin-adjusted midpoint rounding (`round(L / cellPitch)`). Clamping to the board is the ENGINE's job (moveCheck clamps), not ours.

`spanW` is the tile's COLUMN SPAN and is used only when `g.rtl`: mirrored,
the cell is decided by the tile's RIGHT edge (its leading edge), so the
span is what converts the given left edge into it. LTR ignores it entirely,
which is why every existing call site keeps its exact behaviour. Getting
this wrong is the classic RTL drag bug — the tile lands a span away from
the placeholder — so the e2e battery asserts drop-on-placeholder in RTL.

```ts
function pointToCell(
  x: number,
  y: number,
  frame: WorldRect,
  g: DashboardGridGeometry,
  rows: number,
  spanW = 1
): { x: number; y: number }
```

### `rowHeightFor`

Row height for a board currently `rows` rows tall (both modes).

```ts
function rowHeightFor(g: DashboardGridGeometry, rows: number): number
```

### `sizeToSpan`

The integer span a fluid pixel size rounds to — the prototype's
`round((W + margin) / cellPitch)`, floored at 1×1.

```ts
function sizeToSpan(
  widthPx: number,
  heightPx: number,
  frame: WorldRect,
  g: DashboardGridGeometry,
  rows: number
): { w: number; h: number }
```

### `tabStripKey`

Paint the strip. Repainted only when its identity changes (the pages, the
active one, the options, RTL) so a page switch is a class toggle, not a
rebuild — and so a `click` listener survives between switches.

```ts
function tabStripKey(pages: TabPage[], activeId: string, o: TabsOptions | undefined, rtl: boolean): string
```

### `tabStripReserve`

Pixels the pages give up at the top of the container: nothing for a hidden strip, never under 18 for a visible one.

```ts
function tabStripReserve(o: TabsOptions | undefined, pageCount: number): number
```
