Something went wrong

Thank you for being patient! We're working hard on resolving the issue

Layout Math - Lona Docs Log in

Layout Math

@tento-lona/sheets carries the pure layout pipeline — no DOM, no canvas. It computes:

  • Layout shape — per row type, the abstract structural shape (e.g. "single header column + N content columns")
  • Layout heights — per row type, the static pixel heights (DOM consults this; CLI ignores)
  • Render plan — per row, the re-render strategy (full-rebuild / content / style-only / none) plus mode + timeState + spanMode + stacking
  • Cell layout — per cell, the on-screen position derived from the row's CellLayout + the column/sheet context

Layout shape

import { resolveLayoutShape, DEFAULT_LAYOUT_SHAPE } from "@tento-lona/sheets";

const shape = resolveLayoutShape(rowType);
// Returns the per-type RowLayoutShape (header columns, content columns, …)

Non-DOM platforms (CLI, tests, terminal) consume this directly without dragging pixel heights through the pure path.

Layout heights

import { resolveLayoutHeights, DEFAULT_LAYOUT_HEIGHTS } from "@tento-lona/sheets";

const heights = resolveLayoutHeights(rowType);
// → RowLayoutHeights — header height, body height per row mode, etc.

DOM consults this for the type's static heights, then composes per-row heightPx overrides + plugin-runtime adjustments via composeLayoutSpec.

Timescale + RowRenderMode

import {
  TimeScale, RowRenderMode,
  calculateStackSize, getConservativeSpanCount,
  shouldStackCells, shouldSpanColumns,
  getOwnedRowPeriod, getTimescaleOrder, isOwnerColumn,
} from "@tento-lona/sheets";

const mode = RowRenderMode.compute(row, scale);   // "normal" | "stacked" | "spanned" | "span-stacked"

Mirrors yuzu-ui's timescale.ts — both copies co-exist until yuzu-ui's sheet-layout code re-routes through this barrel.

LayoutEngine

Pure cell-positioning synthesizer. Given a row's CellLayout + its column context, produces a Map<ColumnKey, CellPlacement>:

import { LayoutEngine } from "@tento-lona/sheets";

const placements = LayoutEngine.compute({
  row,
  cellLayout: row.cellLayout(),
  columns: visibleColumns,
  scale,
  mode,
});

RenderPlan

Per-row reconciliation strategy:

import { RenderPlan } from "@tento-lona/sheets";

const plan = RenderPlan.for(row, prevPlan, invalidationContext);

switch (plan.strategy) {
  case "full-rebuild": rebuildRow(row); break;
  case "content":      updateContent(row); break;
  case "style-only":   restyle(row); break;
  case "none":         /* skip */ break;
}

A full plan covers strategy + mode + timeState + spanMode + stacking — five orthogonal axes a renderer needs to know which update path is cheapest for this frame.

Subcolumn cache

import { defaultSubcolumnCache } from "@tento-lona/sheets";

const cache = defaultSubcolumnCache();
// Threaded through buildScene + plugin data providers for
// consistent subcolumn enumeration across re-renders.

See also

  • Scene & DiffbuildScene consumes RenderPlan + LayoutEngine outputs
  • Per-Type Plugins — plugins consult layout math via the binding resolvers