monowind 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["#shadow","#decorations","#resizeObserver","#scheduleLayout","#mutationObserver","#suppressMutations","#isOwnedMutation","#cellMetrics","#onFontsLoaded","#layoutPending","#performLayout"],"sources":["../src/metrics.ts","../src/wrap.ts","../src/layout.ts","../src/borders.ts","../src/render.ts","../src/style.ts","../src/types.ts","../src/tree.ts","../src/element.ts","../src/ascii.ts"],"sourcesContent":["import type { CellMetrics } from \"./types.ts\";\n\n/** Round to nearest integer, ties away from zero (per specs/cell-model.md). */\nexport function roundHalfAwayFromZero(value: number): number {\n const rounded = value >= 0 ? Math.floor(value + 0.5) : -Math.floor(-value + 0.5);\n return rounded || 0; // normalize -0 → 0\n}\n\n/** Convert a computed px value to cells using the spacing scale (1 cell = 0.25rem). */\nexport function pxToCells(px: number, rootFontSizePx: number): number {\n if (rootFontSizePx <= 0) return 0;\n return roundHalfAwayFromZero(px / (0.25 * rootFontSizePx));\n}\n\n/** Convert a percentage of an integer container to whole cells, ties away from zero. */\nexport function percentToCells(percent: number, containerCells: number): number {\n return roundHalfAwayFromZero((containerCells * percent) / 100);\n}\n\n/** Measure the width of a monospace character and the line-box height. */\nexport function measureCellMetrics(host: HTMLElement): CellMetrics {\n const probe = document.createElement(\"span\");\n probe.setAttribute(\"aria-hidden\", \"true\");\n // `!important` overrides the companion stylesheet's `mono-wind *` rules\n // (white-space, overflow-wrap) that would otherwise wrap the probe to the\n // host's width and give us a bogus per-cell measurement.\n probe.style.cssText =\n \"position:absolute!important;visibility:hidden!important;pointer-events:none!important;\" +\n \"white-space:pre!important;overflow-wrap:normal!important;\" +\n \"top:0!important;left:0!important;padding:0!important;margin:0!important;border:0!important;\";\n probe.textContent = \"M\".repeat(100);\n host.appendChild(probe);\n const rect = probe.getBoundingClientRect();\n host.removeChild(probe);\n return { width: rect.width / 100, height: rect.height };\n}\n\nexport function getRootFontSizePx(): number {\n return parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\n}\n","/**\n * Greedy word-wrap for monospace text.\n *\n * Words are runs of non-whitespace; whitespace runs collapse to single spaces\n * between fitting words. Browsers also treat a hyphen inside a word as a\n * break opportunity (break after `-`, no hyphen added) — except before a\n * digit, per UAX #14 (`2026-08` doesn't break) — so words are further split\n * into breakable segments. A segment longer than `width` breaks at cell\n * boundaries. `\\n` in the input is a HARD line break — the wrap restarts on\n * a new line (the source of these is `<br>` elements, converted to `\\n` by\n * the tree builder). A blank hard line still occupies one row.\n *\n * Matches how a browser wraps `white-space: normal; overflow-wrap: anywhere`\n * text in a fixed-width monospace container — we set that in styles.css so\n * the two agree.\n */\nexport function wrapLines(text: string, width: number): string[] {\n if (text.trim() === \"\") return [];\n return text.split(\"\\n\").flatMap((hardLine) => wrapHardLine(hardLine, width));\n}\n\n/** Number of rows `text` occupies at `width` (see wrapLines). */\nexport function wrapLineCount(text: string, width: number): number {\n return wrapLines(text, width).length;\n}\n\n/**\n * Split a word at its internal break opportunities: after each hyphen run,\n * unless the next character is a digit (UAX #14: no break between a hyphen\n * and a following number). `\"mx-auto\"` → `[\"mx-\", \"auto\"]`;\n * `\"2026-08\"` → `[\"2026-08\"]`. Also the unit of min-content width.\n */\nexport function breakableSegments(word: string): string[] {\n const segments: string[] = [];\n let start = 0;\n const hyphenRun = /-+/g;\n let match: RegExpExecArray | null;\n while ((match = hyphenRun.exec(word)) !== null) {\n const end = match.index + match[0].length;\n if (end < word.length && !/[0-9]/.test(word[end]!)) {\n segments.push(word.slice(start, end));\n start = end;\n }\n }\n segments.push(word.slice(start));\n return segments;\n}\n\nfunction wrapHardLine(text: string, width: number): string[] {\n // CSS \"document white space\" only: space, tab, CR, LF, FF. Notably NOT\n // NBSP (U+00A0) — JS `\\s` would match it, but the browser neither\n // collapses nor breaks at it, so it must stay inside its word.\n const words = text.split(/[ \\t\\r\\n\\f]+/).filter(Boolean);\n if (words.length === 0) return [\"\"];\n if (width <= 0) return [words.join(\" \")];\n\n const lines: string[] = [];\n let current = \"\";\n\n for (const word of words) {\n let joinsPrevious = false; // segments after the first attach with no space\n for (let segment of breakableSegments(word)) {\n const separator = !joinsPrevious && current !== \"\" ? 1 : 0;\n if (current !== \"\" && current.length + separator + segment.length <= width) {\n current += separator ? ` ${segment}` : segment;\n } else {\n if (current !== \"\") lines.push(current);\n // Break a too-long segment at cell boundaries; a chunk of exactly\n // `width` stays as the current line (matching browser overflow-wrap).\n while (segment.length > width) {\n lines.push(segment.slice(0, width));\n segment = segment.slice(width);\n }\n current = segment;\n }\n joinsPrevious = true;\n }\n }\n lines.push(current);\n return lines;\n}\n","import { percentToCells } from \"./metrics.ts\";\nimport { breakableSegments, wrapLineCount } from \"./wrap.ts\";\nimport type {\n CellLength,\n CellStyle,\n Insets,\n LayoutNode,\n NullableInsets,\n PerSide,\n Size,\n} from \"./types.ts\";\n\n/**\n * Layout entry point: mutates localRect on the root and each descendant.\n * Coordinates are parent-relative (root's rect is at 0,0).\n */\nexport function layoutRoot(root: LayoutNode, availableWidth: number): { height: number } {\n const cache: IntrinsicCache = { maxContent: new WeakMap(), minContent: new WeakMap() };\n layoutNode(root, availableWidth, undefined, 0, 0, \"fill\", cache);\n return { height: root.localRect.height };\n}\n\ntype SizingMode = \"fill\" | \"shrink\";\ninterface IntrinsicCache {\n maxContent: WeakMap<LayoutNode, number>;\n minContent: WeakMap<LayoutNode, number>;\n}\n\n/**\n * `forced` carries flex-assigned (\"used\") sizes from a parent flex pass —\n * they are authoritative and skip resolution/clamping entirely (the flex\n * loop already applied min/max). With sizes forced, `availableWidth` stays\n * the CONTAINING BLOCK's content width, which percent padding, margins,\n * and min/max resolve against — never the assigned size itself.\n */\nfunction layoutNode(\n node: LayoutNode,\n availableWidth: number,\n availableHeight: number | undefined,\n parentX: number,\n parentY: number,\n widthMode: SizingMode,\n cache: IntrinsicCache,\n forced?: { width?: number | undefined; height?: number | undefined },\n): void {\n const style = node.style;\n const forcedHeight = forced?.height;\n\n // Width is clamped to min/max BEFORE laying out content — wrapping and\n // child sizing must see the constrained width, not the raw resolved one.\n // (Height differs: max-height clamps the final rect after layout, since\n // content height is an output, and overflow handles the spill.)\n // Percent min/max (`max-w-full`) resolve against the available size; a\n // percent height limit with indefinite available height is ignored, per CSS.\n const minWidth = resolveLimit(style.minWidth, availableWidth) ?? 0;\n const maxWidth = resolveLimit(style.maxWidth, availableWidth);\n const minHeight = resolveLimit(style.minHeight, availableHeight) ?? 0;\n const maxHeight = resolveLimit(style.maxHeight, availableHeight);\n // Percent padding resolves against the containing block's width (CSS: all\n // four sides use the inline size) — `availableWidth` is that width here.\n // Stored on the node because the renderers need the resolved cells too.\n const padding: Insets = {\n top: resolveLength(style.padding.top, availableWidth),\n right: resolveLength(style.padding.right, availableWidth),\n bottom: resolveLength(style.padding.bottom, availableWidth),\n left: resolveLength(style.padding.left, availableWidth),\n };\n node.resolvedPadding = padding;\n const outerWidth =\n forced?.width ??\n clampSize(resolveWidth(style, availableWidth, widthMode, node, cache), minWidth, maxWidth);\n const outerHeightExplicit = resolveHeight(style, availableHeight);\n // A `forcedHeight` (set by a parent flex-column when grow/shrink assigned a\n // main-axis size) overrides both explicit `height` and `min-height` — the\n // flex algorithm's \"used main size\" is authoritative. Otherwise, `min-height`\n // is a lower bound so items-center / items-end see the enforced size, not\n // just the natural content size.\n const outerHeightFloor =\n forcedHeight ?? outerHeightExplicit ?? (minHeight > 0 ? minHeight : undefined);\n\n const inner = shrinkSize(\n outerWidth,\n outerHeightFloor ?? Number.POSITIVE_INFINITY,\n style.border,\n padding,\n );\n\n let contentHeight: number;\n if (node.children.length === 0) {\n // `white-space: nowrap` text never soft-wraps: its height is the\n // hard-line (`<br>`) count, regardless of width.\n contentHeight = node.text\n ? style.whiteSpace === \"nowrap\"\n ? node.text.split(\"\\n\").length\n : wrapLineCount(node.text, inner.width)\n : node.intrinsicHeight;\n } else if (style.display === \"flex\" && style.flexDirection === \"row\") {\n contentHeight = layoutFlexRow(node, inner.width, inner.height, style.border, padding, cache);\n } else if (style.display === \"flex\" && style.flexDirection === \"column\") {\n // Whether the main-axis (height) size is definite (explicit `height` or a\n // parent-assigned flex size) or only a `min-height` floor. A floor adds\n // distributable space for flex-grow but must never trigger flex-shrink —\n // min-height can only make the container taller, not compress content.\n const heightIsDefinite = forcedHeight !== undefined || outerHeightExplicit !== undefined;\n contentHeight = layoutFlexColumn(\n node,\n inner.width,\n inner.height,\n heightIsDefinite,\n style.border,\n padding,\n cache,\n );\n } else {\n contentHeight = layoutBlock(node, inner.width, style.border, padding, cache);\n }\n\n const naturalHeight =\n contentHeight + style.border.top + style.border.bottom + padding.top + padding.bottom;\n // Order matters: min-* is a floor, max-* is a ceiling; when both apply,\n // max wins per CSS (min-width < max-width is required, but if the author\n // sets an inconsistent pair CSS clamps to `max(min, min(max, value))`).\n // The pre-clamp height is the column flex algorithm's base size (CSS\n // distributes from UNclamped bases; min/max apply via its freeze loop).\n const unclampedHeight = forcedHeight ?? outerHeightExplicit ?? naturalHeight;\n node.unclampedHeight = unclampedHeight;\n const finalHeight = clampSize(unclampedHeight, minHeight, maxHeight);\n\n node.localRect = { x: parentX, y: parentY, width: outerWidth, height: finalHeight };\n}\n\nfunction clampSize(value: number, min: number, max: number | undefined): number {\n const clamped = max !== undefined ? Math.min(value, max) : value;\n return Math.max(min, clamped);\n}\n\n/** Resolve a spacing length to cells against its containing-block basis.\n * An indefinite basis (percent gap in an unbounded axis) resolves to 0. */\nfunction resolveLength(length: CellLength, basis: number | undefined): number {\n if (typeof length === \"number\") return length;\n return basis === undefined || !Number.isFinite(basis) ? 0 : percentToCells(length.percent, basis);\n}\n\n/** Resolve all four margin sides (preserving `auto` as null) against the\n * parent's content width — the CSS basis for every side. */\nfunction resolveMargin(margin: PerSide<CellLength | null>, basis: number): NullableInsets {\n const side = (v: CellLength | null) => (v === null ? null : resolveLength(v, basis));\n return {\n top: side(margin.top),\n right: side(margin.right),\n bottom: side(margin.bottom),\n left: side(margin.left),\n };\n}\n\n/** The cells of a CellLength for intrinsic sizing: percentages count as 0,\n * per CSS intrinsic-size contribution rules. */\nfunction intrinsicCells(length: CellLength): number {\n return typeof length === \"number\" ? length : 0;\n}\n\n/** Resolve a CellLength to cells: percent needs a definite available size.\n * `\"auto\"` resolves to none here (0 in block flow) — flex main-axis code\n * substitutes the item's content-based automatic minimum itself. */\nfunction resolveLimit(\n limit: CellLength | \"auto\" | undefined,\n available: number | undefined,\n): number | undefined {\n if (limit === undefined || limit === \"auto\") return undefined;\n if (typeof limit === \"number\") return limit;\n return available === undefined ? undefined : percentToCells(limit.percent, available);\n}\n\n/**\n * Lay out children in vertical block flow. Returns content height (rows used).\n *\n * - Vertical (main-axis) margins on adjacent siblings **collapse** — the\n * effective gap is `max(prev.bottom, curr.top)` for two positives, `min`\n * for two negatives, and the sum for mixed signs (standard CSS rule).\n * Parent–child collapsing is intentionally NOT implemented (see the cell-\n * model spec's Deviations section).\n * - Horizontal (cross-axis) margins position the child; `auto` on either\n * side centers or end-aligns as CSS does.\n */\nfunction layoutBlock(\n node: LayoutNode,\n innerWidth: number,\n border: Insets,\n padding: Insets,\n cache: IntrinsicCache,\n): number {\n const originX = border.left + padding.left;\n const startY = border.top + padding.top;\n let y = startY;\n let previousMarginBottom: number | null = null;\n for (const child of node.children) {\n const childMargin = resolveMargin(child.style.margin, innerWidth);\n const marginTop = childMargin.top ?? 0;\n const marginBottom = childMargin.bottom ?? 0;\n const marginLeft = childMargin.left ?? 0;\n const marginRight = childMargin.right ?? 0;\n layoutNode(\n child,\n Math.max(0, innerWidth - marginLeft - marginRight),\n undefined,\n 0,\n 0,\n \"fill\",\n cache,\n );\n const crossAvailable = innerWidth - child.localRect.width;\n const bothAutoX = childMargin.left === null && childMargin.right === null;\n const oneAutoLeft = childMargin.left === null && childMargin.right !== null;\n const oneAutoRight = childMargin.right === null && childMargin.left !== null;\n let crossOffset: number;\n if (bothAutoX) crossOffset = Math.floor(crossAvailable / 2);\n else if (oneAutoLeft) crossOffset = crossAvailable - marginRight;\n else if (oneAutoRight) crossOffset = marginLeft;\n else crossOffset = marginLeft;\n\n // `y` tracks the position where the next child's top edge goes. Margins\n // are added JUST BEFORE placing each child, then only the child's height\n // afterwards — the child's own bottom margin waits until the next\n // sibling (or the end-of-container) so we can collapse them properly.\n y +=\n previousMarginBottom === null ? marginTop : collapseMargins(previousMarginBottom, marginTop);\n child.localRect = { ...child.localRect, x: originX + crossOffset, y };\n y += child.localRect.height;\n previousMarginBottom = marginBottom;\n }\n if (previousMarginBottom !== null) y += previousMarginBottom;\n return y - startY;\n}\n\n/**\n * CSS margin-collapsing rule for two adjacent block-flow margins:\n * - both positive → the larger absorbs the smaller.\n * - both negative → the more negative absorbs the less negative.\n * - mixed → they sum (positive shrunk by the negative).\n */\nfunction collapseMargins(a: number, b: number): number {\n if (a >= 0 && b >= 0) return Math.max(a, b);\n if (a <= 0 && b <= 0) return Math.min(a, b);\n return a + b;\n}\n\nfunction layoutFlexRow(\n node: LayoutNode,\n innerWidth: number,\n innerHeight: number,\n border: Insets,\n padding: Insets,\n cache: IntrinsicCache,\n): number {\n const gapX = resolveLength(node.style.gapX, innerWidth);\n const gapY = resolveLength(node.style.gapY, innerHeight);\n const items = flexOrderedChildren(node).map((child) => {\n const margin = resolveMargin(child.style.margin, innerWidth);\n return {\n node: child,\n intrinsic: flexBaseOuterWidth(child, innerWidth, cache),\n grow: child.style.flexGrow,\n shrink: child.style.flexShrink,\n min: flexItemMinWidth(child, innerWidth, cache),\n max: resolveLimit(child.style.maxWidth, innerWidth),\n margin,\n marginLeft: margin.left,\n marginRight: margin.right,\n };\n });\n\n // Break into rows greedily. With gap, an item breaks when `used + gap +\n // fixedMargins + intrinsic` exceeds innerWidth. The first item on a row is\n // always placed even if it alone overflows, matching CSS.\n const rows: (typeof items)[] = [];\n if (node.style.flexWrap === \"wrap\") {\n let current: typeof items = [];\n let used = 0;\n for (const item of items) {\n // Placement uses the hypothetical size (base clamped by min/max).\n const hypothetical = Math.max(0, clampSize(item.intrinsic, item.min, item.max));\n const itemWidth = hypothetical + (item.marginLeft ?? 0) + (item.marginRight ?? 0);\n const next = current.length === 0 ? itemWidth : used + gapX + itemWidth;\n if (current.length > 0 && next > innerWidth) {\n rows.push(current);\n current = [];\n used = 0;\n }\n current.push(item);\n used = current.length === 1 ? itemWidth : used + gapX + itemWidth;\n }\n if (current.length > 0) rows.push(current);\n // wrap-reverse stacks the lines from the cross-end (bottom-up); items\n // within each line keep their main-axis order.\n if (node.style.wrapReverse) rows.reverse();\n } else {\n rows.push(items);\n }\n\n const originX = border.left + padding.left;\n const originY = border.top + padding.top;\n let y = 0;\n let totalRowHeight = 0;\n\n for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n const row = rows[rowIndex]!;\n const totalGap = gapX * Math.max(0, row.length - 1);\n const fixedMarginTotal = row.reduce(\n (sum, item) => sum + (item.marginLeft ?? 0) + (item.marginRight ?? 0),\n 0,\n );\n const availableForItems = Math.max(0, innerWidth - totalGap - fixedMarginTotal);\n // Per CSS: if there's positive free space and any main-axis auto margin,\n // auto margins absorb the leftover BEFORE flex-grow. Detect that case and\n // keep items at their intrinsic size — the auto-margin loop below will\n // then distribute the leftover space itself.\n const rowHasAutoMainMargin = row.some(\n (item) => item.marginLeft === null || item.marginRight === null,\n );\n const totalRowIntrinsic = row.reduce((s, i) => s + i.intrinsic, 0);\n const skipGrowForAutoMargins = rowHasAutoMainMargin && totalRowIntrinsic <= availableForItems;\n const widths = skipGrowForAutoMargins\n ? row.map((i) => i.intrinsic)\n : resolveFlexMainAxis(row, availableForItems);\n for (let i = 0; i < row.length; i++) {\n layoutNode(row[i]!.node, innerWidth, undefined, 0, 0, \"fill\", cache, {\n width: widths[i]!,\n });\n }\n const maxChildHeight = row.reduce((h, item) => Math.max(h, item.node.localRect.height), 0);\n // For a nowrap single row, the row can stretch to the container's inner\n // height (from min-h or explicit height) so items-center / items-end\n // have the enforced size to align against. With wrap, each row's height\n // is just its tallest child.\n const rowHeight =\n rows.length === 1 && Number.isFinite(innerHeight)\n ? Math.max(innerHeight, maxChildHeight)\n : maxChildHeight;\n\n // Stretch phase: any item whose effective cross alignment is `stretch`\n // (no explicit height, no auto cross-axis margins) grows to fill the\n // row. Re-run layoutNode with `forcedHeight` so nested content that\n // depends on the parent's height sees the final size.\n for (let i = 0; i < row.length; i++) {\n const child = row[i]!.node;\n const effectiveAlign =\n child.style.alignSelf === \"auto\" ? node.style.alignItems : child.style.alignSelf;\n const itemMargin = row[i]!.margin;\n const hasCrossAutoMargin = itemMargin.top === null || itemMargin.bottom === null;\n // Treat `{kind: \"auto\"}` as no explicit height (Typed OM returns this\n // for elements that don't set a height; only `cells`/`percent` counts\n // as an author-set size that stretch should respect).\n const hasExplicitHeight =\n child.style.height !== undefined && child.style.height.kind !== \"auto\";\n if (\n effectiveAlign === \"stretch\" &&\n !hasCrossAutoMargin &&\n !hasExplicitHeight &&\n rowHeight > child.localRect.height\n ) {\n const marginTop = itemMargin.top ?? 0;\n const marginBottom = itemMargin.bottom ?? 0;\n // Per CSS, a stretched cross size is still clamped by the item's own\n // min/max-height (percent resolved against the container's inner\n // height when definite).\n const crossBasis = Number.isFinite(innerHeight) ? innerHeight : undefined;\n const stretchedHeight = clampSize(\n Math.max(0, rowHeight - marginTop - marginBottom),\n resolveLimit(child.style.minHeight, crossBasis) ?? 0,\n resolveLimit(child.style.maxHeight, crossBasis),\n );\n if (stretchedHeight === child.localRect.height) continue;\n layoutNode(child, innerWidth, undefined, 0, 0, \"fill\", cache, {\n width: widths[i]!,\n height: stretchedHeight,\n });\n }\n }\n const totalUsed = widths.reduce((s, w) => s + w, 0);\n const leftover = Math.max(0, availableForItems - totalUsed);\n\n // Auto margins on the main axis absorb leftover space (each gets an\n // equal share). If any exist, they override justify-content.\n const autoCount = row.reduce(\n (n, item) => n + (item.marginLeft === null ? 1 : 0) + (item.marginRight === null ? 1 : 0),\n 0,\n );\n const autoMarginBefore: number[] = Array.from({ length: row.length }, () => 0);\n const autoMarginAfter: number[] = Array.from({ length: row.length }, () => 0);\n let offsets: number[];\n if (autoCount > 0 && leftover > 0) {\n const shares = distributeInteger(\n Array.from({ length: autoCount }, () => 1),\n leftover,\n );\n let shareIndex = 0;\n for (let i = 0; i < row.length; i++) {\n if (row[i]!.marginLeft === null) autoMarginBefore[i] = shares[shareIndex++]!;\n if (row[i]!.marginRight === null) autoMarginAfter[i] = shares[shareIndex++]!;\n }\n offsets = mainAxisOffsets(\"start\", widths, 0);\n } else {\n offsets = mainAxisOffsets(effectiveJustify(node.style), widths, leftover);\n }\n\n let cumulativeExtraOffset = 0;\n for (let i = 0; i < row.length; i++) {\n const item = row[i]!;\n const child = item.node;\n const fixedLeft = item.marginLeft ?? 0;\n const fixedRight = item.marginRight ?? 0;\n cumulativeExtraOffset += autoMarginBefore[i]! + fixedLeft;\n child.localRect = {\n ...child.localRect,\n x: originX + offsets[i]! + i * gapX + cumulativeExtraOffset,\n y: originY + y + crossAxisOffset(child, node.style.alignItems, rowHeight, item.margin),\n };\n cumulativeExtraOffset += autoMarginAfter[i]! + fixedRight;\n }\n const rowSpacing = rowIndex < rows.length - 1 ? gapY : 0;\n y += rowHeight + rowSpacing;\n totalRowHeight += rowHeight + rowSpacing;\n }\n\n return Number.isFinite(innerHeight) ? Math.max(innerHeight, totalRowHeight) : totalRowHeight;\n}\n\nfunction layoutFlexColumn(\n node: LayoutNode,\n innerWidth: number,\n innerHeight: number,\n heightIsDefinite: boolean,\n border: Insets,\n padding: Insets,\n cache: IntrinsicCache,\n): number {\n const gapY = resolveLength(node.style.gapY, innerHeight);\n\n const items = flexOrderedChildren(node).map((child) => {\n const margin = resolveMargin(child.style.margin, innerWidth);\n const marginLeft = margin.left ?? 0;\n const marginRight = margin.right ?? 0;\n const availableChildWidth = Math.max(0, innerWidth - marginLeft - marginRight);\n // Per-item cross-axis (width) stretch decision: parent's alignItems is\n // the default, but a child's own alignSelf wins if set. So an item with\n // `self-start` inside a stretch parent shrinks to intrinsic, not fills.\n const effectiveAlign =\n child.style.alignSelf === \"auto\" ? node.style.alignItems : child.style.alignSelf;\n const childStretch = effectiveAlign === \"stretch\";\n // First pass at intrinsic height along the main axis.\n layoutNode(\n child,\n availableChildWidth,\n undefined,\n 0,\n 0,\n childStretch ? \"fill\" : \"shrink\",\n cache,\n );\n const limitBasis = Number.isFinite(innerHeight) ? innerHeight : undefined;\n // Base main size per CSS flex-basis: an explicit basis (cells, or\n // percent against a definite container height) wins; otherwise the\n // first-pass height BEFORE min/max clamping — distribution starts from\n // raw bases, the freeze loop enforces the limits.\n const basis = child.style.flexBasis;\n const base =\n basis === undefined || basis.kind === \"auto\"\n ? child.unclampedHeight\n : basis.kind === \"cells\"\n ? basis.value\n : basis.kind === \"percent\" && limitBasis !== undefined\n ? percentToCells(basis.value, limitBasis)\n : child.unclampedHeight;\n // `min-height: auto` on a column item is the automatic minimum: its\n // content height (the first-pass laid-out height), unless overflow is\n // non-visible. Same rule as the row's min-content width.\n const autoMin =\n child.style.minHeight === \"auto\"\n ? child.style.overflow === \"visible\"\n ? child.localRect.height\n : 0\n : undefined;\n return {\n node: child,\n intrinsic: base,\n grow: child.style.flexGrow,\n shrink: child.style.flexShrink,\n min: autoMin ?? resolveLimit(child.style.minHeight, limitBasis) ?? 0,\n max: resolveLimit(child.style.maxHeight, limitBasis),\n margin,\n marginTop: margin.top,\n marginBottom: margin.bottom,\n marginLeft,\n marginRight,\n };\n });\n\n const totalGap = gapY * Math.max(0, items.length - 1);\n const fixedMarginTotal = items.reduce(\n (sum, item) => sum + (item.marginTop ?? 0) + (item.marginBottom ?? 0),\n 0,\n );\n const finiteInner = Number.isFinite(innerHeight);\n const totalIntrinsicHeight = items.reduce((s, i) => s + i.intrinsic, 0);\n const definiteAvailable = finiteInner\n ? Math.max(0, innerHeight - totalGap - fixedMarginTotal)\n : totalIntrinsicHeight;\n // A min-height-only container size is a floor, not a cap: it can hand\n // extra space to flex-grow, but content larger than the floor keeps its\n // intrinsic size (no flex-shrink) and the container grows to fit.\n const availableForItems = heightIsDefinite\n ? definiteAvailable\n : Math.max(definiteAvailable, totalIntrinsicHeight);\n\n // Same CSS rule as flex-row: auto margins on the main axis absorb positive\n // leftover before flex-grow gets to it.\n const columnHasAutoMainMargin = items.some(\n (item) => item.marginTop === null || item.marginBottom === null,\n );\n const skipGrowForAutoMargins =\n finiteInner && columnHasAutoMainMargin && totalIntrinsicHeight <= availableForItems;\n const finalHeights =\n finiteInner && !skipGrowForAutoMargins\n ? resolveFlexMainAxis(items, availableForItems)\n : items.map((i) => i.intrinsic);\n // If a child's main-axis size changed, re-run its layout with the new\n // height forced so any nested content that depends on the parent's height\n // (items-center/end in a nested flex, percent heights) sees the final size.\n for (let i = 0; i < items.length; i++) {\n if (finalHeights[i] !== items[i]!.intrinsic) {\n const item = items[i]!;\n const availableChildWidth = Math.max(0, innerWidth - item.marginLeft - item.marginRight);\n const effectiveAlign =\n item.node.style.alignSelf === \"auto\" ? node.style.alignItems : item.node.style.alignSelf;\n const childStretch = effectiveAlign === \"stretch\";\n layoutNode(\n item.node,\n availableChildWidth,\n finalHeights[i]!,\n 0,\n 0,\n childStretch ? \"fill\" : \"shrink\",\n cache,\n { height: finalHeights[i]! },\n );\n }\n }\n\n const totalUsed = finalHeights.reduce((s, h) => s + h, 0);\n const leftover = Math.max(0, availableForItems - totalUsed);\n\n const autoCount = items.reduce(\n (n, item) => n + (item.marginTop === null ? 1 : 0) + (item.marginBottom === null ? 1 : 0),\n 0,\n );\n const autoMarginBefore: number[] = Array.from({ length: items.length }, () => 0);\n const autoMarginAfter: number[] = Array.from({ length: items.length }, () => 0);\n let offsets: number[];\n if (autoCount > 0 && leftover > 0) {\n const shares = distributeInteger(\n Array.from({ length: autoCount }, () => 1),\n leftover,\n );\n let shareIndex = 0;\n for (let i = 0; i < items.length; i++) {\n if (items[i]!.marginTop === null) autoMarginBefore[i] = shares[shareIndex++]!;\n if (items[i]!.marginBottom === null) autoMarginAfter[i] = shares[shareIndex++]!;\n }\n offsets = mainAxisOffsets(\"start\", finalHeights, 0);\n } else {\n offsets = mainAxisOffsets(effectiveJustify(node.style), finalHeights, leftover);\n }\n\n const originX = border.left + padding.left;\n const originY = border.top + padding.top;\n let cumulativeExtraOffset = 0;\n for (let i = 0; i < items.length; i++) {\n const item = items[i]!;\n const child = item.node;\n const fixedTop = item.marginTop ?? 0;\n const fixedBottom = item.marginBottom ?? 0;\n cumulativeExtraOffset += autoMarginBefore[i]! + fixedTop;\n child.localRect = {\n ...child.localRect,\n x: originX + crossAxisOffsetX(child, node.style.alignItems, innerWidth, item.margin),\n y: originY + offsets[i]! + i * gapY + cumulativeExtraOffset,\n };\n cumulativeExtraOffset += autoMarginAfter[i]! + fixedBottom;\n }\n\n const totalOccupied = totalUsed + totalGap + fixedMarginTotal;\n return finiteInner ? Math.max(innerHeight, totalOccupied) : totalOccupied;\n}\n\n/**\n * Compute a child's cross-axis (vertical) offset inside a flex row, honoring\n * align-self override, cross-axis auto margins, and fixed cross-axis margins.\n */\nfunction crossAxisOffset(\n child: LayoutNode,\n parentAlign: CellStyle[\"alignItems\"],\n rowHeight: number,\n m: NullableInsets,\n): number {\n const align = child.style.alignSelf === \"auto\" ? parentAlign : child.style.alignSelf;\n const marginTop = m.top ?? 0;\n const marginBottom = m.bottom ?? 0;\n const crossAvailable = rowHeight - child.localRect.height;\n const bothAuto = m.top === null && m.bottom === null;\n const oneAutoTop = m.top === null && m.bottom !== null;\n const oneAutoBottom = m.bottom === null && m.top !== null;\n if (bothAuto) return Math.floor(crossAvailable / 2);\n if (oneAutoTop) return crossAvailable - marginBottom;\n if (oneAutoBottom) return marginTop;\n return marginTop + alignCrossOffset(align, rowHeight, child.localRect.height);\n}\n\n/**\n * Symmetric helper for flex-column: cross axis is horizontal, so auto/fixed\n * margins on `left`/`right` participate.\n */\nfunction crossAxisOffsetX(\n child: LayoutNode,\n parentAlign: CellStyle[\"alignItems\"],\n containerWidth: number,\n m: NullableInsets,\n): number {\n const align = child.style.alignSelf === \"auto\" ? parentAlign : child.style.alignSelf;\n const marginLeft = m.left ?? 0;\n const marginRight = m.right ?? 0;\n const crossAvailable = containerWidth - child.localRect.width;\n const bothAuto = m.left === null && m.right === null;\n const oneAutoLeft = m.left === null && m.right !== null;\n const oneAutoRight = m.right === null && m.left !== null;\n if (bothAuto) return Math.floor(crossAvailable / 2);\n if (oneAutoLeft) return crossAvailable - marginRight;\n if (oneAutoRight) return marginLeft;\n return marginLeft + alignCrossOffset(align, containerWidth, child.localRect.width);\n}\n\n/**\n * Position each item along the main axis given its size and leftover space.\n * Returns the offset from container inner origin for each item.\n */\nfunction mainAxisOffsets(\n justify: CellStyle[\"justifyContent\"],\n sizes: number[],\n leftover: number,\n): number[] {\n const count = sizes.length;\n if (count === 0) return [];\n\n const offsets: number[] = [];\n let cursor = 0;\n\n if (justify === \"space-between\" && count > 1) {\n const gapBase = Math.floor(leftover / (count - 1));\n const extra = leftover - gapBase * (count - 1);\n for (let i = 0; i < count; i++) {\n offsets.push(cursor);\n cursor += sizes[i]! + gapBase + (i < extra ? 1 : 0);\n }\n return offsets;\n }\n\n // space-around: every item gets equal space on both sides, so the edge\n // gaps are half the inner ones (weights 1,2,…,2,1 over the n+1 gap\n // slots). space-evenly: all n+1 gaps equal. Integer-distributed with the\n // shared remainder rule, so the result is deterministic.\n if ((justify === \"space-around\" || justify === \"space-evenly\") && leftover > 0) {\n const weights = Array.from({ length: count + 1 }, (_, i) =>\n justify === \"space-evenly\" || i === 0 || i === count ? 1 : 2,\n );\n const gaps = distributeInteger(weights, leftover);\n for (let i = 0; i < count; i++) {\n cursor += gaps[i]!;\n offsets.push(cursor);\n cursor += sizes[i]!;\n }\n return offsets;\n }\n\n if (justify === \"center\") cursor = Math.floor(leftover / 2);\n else if (justify === \"end\") cursor = leftover;\n\n for (let i = 0; i < count; i++) {\n offsets.push(cursor);\n cursor += sizes[i]!;\n }\n return offsets;\n}\n\n/**\n * Resolve flex main-axis sizes per CSS Flexbox §9.7 (\"Resolving Flexible\n * Lengths\"), adapted to integers: distribute free space proportionally to\n * grow factors (or shrink weights = base × shrink), clamp each result to the\n * item's own min/max, FREEZE the items whose clamp fired, and redistribute\n * among the rest — repeating until nothing new violates. Without the\n * redistribution rounds, an item clamped up to `min-w-*` would keep space\n * its neighbors were already told they could use, and boxes would overlap.\n *\n * `min`/`max` are outer main sizes in cells, already resolved from percent.\n * When clamps bind, the returned sizes may sum to less or more than\n * `available` — that's CSS (`justify-content` sees the underfill; overflow\n * handles the excess).\n */\nexport function resolveFlexMainAxis(\n items: ReadonlyArray<{\n intrinsic: number;\n grow: number;\n shrink: number;\n min?: number | undefined;\n max?: number | undefined;\n }>,\n available: number,\n): number[] {\n const count = items.length;\n const clamp = (value: number, index: number) =>\n Math.max(0, clampSize(value, items[index]!.min ?? 0, items[index]!.max));\n const base = items.map((i) => i.intrinsic);\n // Grow vs shrink is decided from the HYPOTHETICAL sizes (clamped bases),\n // per CSS; distribution then starts from the raw bases.\n const hypotheticalTotal = base.reduce((s, b, i) => s + clamp(b, i), 0);\n const growing = available >= hypotheticalTotal;\n\n const sizes: number[] = Array.from({ length: count }, () => 0);\n const frozen: boolean[] = Array.from({ length: count }, () => false);\n // Pre-freeze inflexible items, and items whose base already violates in\n // the flex direction (max-violation when growing, min-violation when\n // shrinking), at their hypothetical size. A base merely BELOW its min\n // while growing stays flexible — it grows from the raw base and the\n // violation loop enforces the min afterwards.\n for (let i = 0; i < count; i++) {\n const hypothetical = clamp(base[i]!, i);\n const flexFactor = growing ? items[i]!.grow : items[i]!.shrink;\n if (\n flexFactor === 0 ||\n (growing && base[i]! > hypothetical) ||\n (!growing && base[i]! < hypothetical)\n ) {\n sizes[i] = hypothetical;\n frozen[i] = true;\n }\n }\n\n // Each round freezes at least one item, so this terminates within `count`\n // iterations.\n for (;;) {\n const unfrozen: number[] = [];\n for (let i = 0; i < count; i++) if (!frozen[i]) unfrozen.push(i);\n if (unfrozen.length === 0) break;\n\n const frozenTotal = sizes.reduce((s, v, i) => (frozen[i] ? s + v : s), 0);\n const unfrozenBaseTotal = unfrozen.reduce((s, i) => s + base[i]!, 0);\n const freeSpace = available - frozenTotal - unfrozenBaseTotal;\n const amount = growing ? Math.max(0, freeSpace) : Math.max(0, -freeSpace);\n\n const weights = unfrozen.map((i) => (growing ? items[i]!.grow : base[i]! * items[i]!.shrink));\n const shares = distributeInteger(weights, amount);\n const tentative = unfrozen.map((i, k) => base[i]! + (growing ? shares[k]! : -shares[k]!));\n const clamped = unfrozen.map((i, k) => clamp(tentative[k]!, i));\n const totalViolation = clamped.reduce((s, v, k) => s + (v - tentative[k]!), 0);\n\n if (totalViolation === 0) {\n for (let k = 0; k < unfrozen.length; k++) sizes[unfrozen[k]!] = clamped[k]!;\n break;\n }\n // Freeze only the violators on the dominant side (min violations when\n // the total is positive, max violations when negative) and go again.\n for (let k = 0; k < unfrozen.length; k++) {\n const violation = clamped[k]! - tentative[k]!;\n if (totalViolation > 0 ? violation > 0 : violation < 0) {\n sizes[unfrozen[k]!] = clamped[k]!;\n frozen[unfrozen[k]!] = true;\n }\n }\n }\n return sizes;\n}\n\n/**\n * Distribute `total` integer units across N slots proportionally to `weights`,\n * with the remainder (from flooring) given to the slots with the largest\n * fractional part — deterministic, document order for ties.\n */\nexport function distributeInteger(weights: number[], total: number): number[] {\n const sum = weights.reduce((s, w) => s + w, 0);\n if (sum === 0 || total <= 0) return weights.map(() => 0);\n const raw = weights.map((w) => (w / sum) * total);\n const floored = raw.map(Math.floor);\n let deficit = total - floored.reduce((s, v) => s + v, 0);\n if (deficit > 0) {\n const order = raw\n .map((v, i) => [i, v - Math.floor(v)] as const)\n .sort((a, b) => (b[1] === a[1] ? a[0] - b[0] : b[1] - a[1]));\n for (const [i] of order) {\n if (deficit <= 0) break;\n floored[i]! += 1;\n deficit -= 1;\n }\n }\n return floored;\n}\n\nfunction alignCrossOffset(\n align: CellStyle[\"alignItems\"],\n container: number,\n child: number,\n): number {\n if (align === \"center\") return Math.max(0, Math.floor((container - child) / 2));\n if (align === \"end\") return Math.max(0, container - child);\n return 0;\n}\n\nfunction resolveWidth(\n style: CellStyle,\n available: number,\n mode: SizingMode,\n node: LayoutNode,\n cache: IntrinsicCache,\n): number {\n const width = style.width;\n if (width !== undefined && width.kind !== \"auto\")\n return resolveSizeAgainst(width, available, node, cache);\n return mode === \"shrink\" ? Math.min(available, intrinsicOuterWidth(node, cache)) : available;\n}\n\nfunction resolveHeight(style: CellStyle, available: number | undefined): number | undefined {\n if (style.height?.kind === \"cells\") return style.height.value;\n if (style.height?.kind === \"percent\" && available != null)\n return percentToCells(style.height.value, available);\n return undefined;\n}\n\n/**\n * A flex-row item's base main size, per CSS `flex-basis`: an explicit basis\n * if set, else the item's explicit width (cells, percent, or an intrinsic\n * keyword), else its max-content size. Percentages resolve against the\n * container's content box (`innerWidth`). NOT clamped by min/max —\n * distribution starts from the raw base per CSS §9.7 (clamping happens via\n * the freeze/violation loop); pre-clamping would e.g. leave `flex-1`\n * columns unequal at their content minimums.\n */\nfunction flexBaseOuterWidth(child: LayoutNode, innerWidth: number, cache: IntrinsicCache): number {\n const basis = child.style.flexBasis;\n const width = child.style.width;\n if (basis !== undefined && basis.kind !== \"auto\") {\n return resolveSizeAgainst(basis, innerWidth, child, cache);\n }\n if (width !== undefined && width.kind !== \"auto\") {\n return resolveSizeAgainst(width, innerWidth, child, cache);\n }\n return intrinsicOuterWidth(child, cache);\n}\n\n/** Resolve a definite Size against an available extent (`auto` falls back\n * to max-content — callers handle the auto/fill distinction themselves). */\nfunction resolveSizeAgainst(\n size: Size,\n available: number,\n node: LayoutNode,\n cache: IntrinsicCache,\n): number {\n switch (size.kind) {\n case \"cells\":\n return size.value;\n case \"percent\":\n return percentToCells(size.value, available);\n case \"min-content\":\n return minContentOuterWidth(node, cache);\n case \"max-content\":\n return intrinsicOuterWidth(node, cache);\n case \"fit-content\":\n return Math.min(\n intrinsicOuterWidth(node, cache),\n Math.max(minContentOuterWidth(node, cache), available),\n );\n case \"auto\":\n return intrinsicOuterWidth(node, cache);\n }\n}\n\n/**\n * Flex item order: stable sort by CSS `order` (document order breaks\n * ties), then reversed for `row-reverse` / `column-reverse` — the main\n * axis runs backwards, so laying reversed children in a normal row with\n * flipped justify start/end is equivalent.\n */\nfunction flexOrderedChildren(node: LayoutNode): LayoutNode[] {\n const children = [...node.children].sort((a, b) => a.style.order - b.style.order);\n if (node.style.flexReverse) children.reverse();\n return children;\n}\n\nfunction effectiveJustify(style: CellStyle): CellStyle[\"justifyContent\"] {\n if (!style.flexReverse) return style.justifyContent;\n if (style.justifyContent === \"start\") return \"end\";\n if (style.justifyContent === \"end\") return \"start\";\n return style.justifyContent;\n}\n\n/**\n * A flex-row item's used minimum width. `min-width: auto` (the CSS default)\n * is the automatic minimum: the item's min-content size — which is why text\n * in a flex row stops shrinking at its longest segment instead of\n * disappearing. It only applies while overflow is visible: `overflow` set\n * to anything else (e.g. via `truncate`) or an explicit `min-w-*` opts out.\n */\nfunction flexItemMinWidth(child: LayoutNode, innerWidth: number, cache: IntrinsicCache): number {\n if (child.style.minWidth === \"auto\") {\n return child.style.overflow === \"visible\" ? minContentOuterWidth(child, cache) : 0;\n }\n return resolveLimit(child.style.minWidth, innerWidth) ?? 0;\n}\n\n/** Max-content intrinsic outer width (border + padding + unwrapped content). */\nfunction intrinsicOuterWidth(node: LayoutNode, cache: IntrinsicCache): number {\n const cached = cache.maxContent.get(node);\n if (cached !== undefined) return cached;\n const style = node.style;\n const inner = intrinsicInnerWidth(node, cache);\n const result =\n inner +\n style.border.left +\n style.border.right +\n intrinsicCells(style.padding.left) +\n intrinsicCells(style.padding.right);\n cache.maxContent.set(node, result);\n return result;\n}\n\nfunction intrinsicInnerWidth(node: LayoutNode, cache: IntrinsicCache): number {\n if (node.children.length === 0) return node.intrinsicWidth;\n if (node.style.display === \"flex\" && node.style.flexDirection === \"row\") {\n const gap = intrinsicCells(node.style.gapX) * Math.max(0, node.children.length - 1);\n return node.children.reduce((sum, c) => sum + intrinsicOuterWidth(c, cache), 0) + gap;\n }\n return node.children.reduce((max, c) => Math.max(max, intrinsicOuterWidth(c, cache)), 0);\n}\n\n/**\n * Min-content intrinsic outer width: the narrowest the box can get without\n * overflow. For a text leaf that's the longest unbreakable unit — a word\n * under normal wrapping, a whole hard line under `nowrap`. A nowrap flex\n * row sums its items (they sit side by side no matter what); wrapping rows\n * and block/column containers take the widest child.\n */\nfunction minContentOuterWidth(node: LayoutNode, cache: IntrinsicCache): number {\n const cached = cache.minContent.get(node);\n if (cached !== undefined) return cached;\n const style = node.style;\n const inner = minContentInnerWidth(node, cache);\n const result =\n inner +\n style.border.left +\n style.border.right +\n intrinsicCells(style.padding.left) +\n intrinsicCells(style.padding.right);\n cache.minContent.set(node, result);\n return result;\n}\n\nfunction minContentInnerWidth(node: LayoutNode, cache: IntrinsicCache): number {\n if (node.children.length === 0) {\n if (!node.text) return node.intrinsicWidth;\n if (node.style.whiteSpace === \"nowrap\") return node.intrinsicWidth;\n let longest = 0;\n for (const word of node.text.split(/[ \\t\\r\\n\\f]+/)) {\n for (const segment of breakableSegments(word)) {\n if (segment.length > longest) longest = segment.length;\n }\n }\n return longest;\n }\n if (\n node.style.display === \"flex\" &&\n node.style.flexDirection === \"row\" &&\n node.style.flexWrap === \"nowrap\"\n ) {\n const gap = intrinsicCells(node.style.gapX) * Math.max(0, node.children.length - 1);\n return node.children.reduce((sum, c) => sum + minContentOuterWidth(c, cache), 0) + gap;\n }\n return node.children.reduce((max, c) => Math.max(max, minContentOuterWidth(c, cache)), 0);\n}\n\nfunction shrinkSize(\n width: number,\n height: number,\n border: Insets,\n padding: Insets,\n): { width: number; height: number } {\n return {\n width: Math.max(0, width - border.left - border.right - padding.left - padding.right),\n height: Math.max(0, height - border.top - border.bottom - padding.top - padding.bottom),\n };\n}\n","import type { BorderStyle, CellStyle, PerSide, Rect } from \"./types.ts\";\n\n/** One run of identical border glyphs, in absolute cell coordinates. */\nexport interface BorderRun {\n glyph: string;\n x: number;\n y: number;\n length: number;\n color: string | undefined;\n}\n\ninterface Glyphs {\n h: string;\n v: string;\n tl: string;\n tr: string;\n bl: string;\n br: string;\n}\n\ninterface RingSides {\n top: boolean;\n right: boolean;\n bottom: boolean;\n left: boolean;\n}\n\n/**\n * Emit runs of border glyphs for the box's engine-allocated border cells.\n *\n * For multi-cell borders (`border-2`, `border-3`, …) the engine allocates N\n * cells per edge; we render them as N concentric rings. Styles and colors\n * are per-side (see paintRing); every ring repeats them.\n *\n * A single-cell-thin box (width < 2 or height < 2) has no interior; we draw\n * only vertical/horizontal runs and skip corners that would overlap.\n */\nexport function collectBorderRuns(style: CellStyle, box: Rect, out: BorderRun[]): void {\n const border = style.border;\n if (border.top === 0 && border.right === 0 && border.bottom === 0 && border.left === 0) return;\n const rings = Math.max(border.top, border.right, border.bottom, border.left);\n for (let ring = 0; ring < rings; ring++) {\n const sides = {\n top: ring < border.top,\n right: ring < border.right,\n bottom: ring < border.bottom,\n left: ring < border.left,\n };\n const ringRect = {\n x: box.x + (sides.left ? ring : 0),\n y: box.y + (sides.top ? ring : 0),\n width: box.width - (sides.left ? ring : 0) - (sides.right ? ring : 0),\n height: box.height - (sides.top ? ring : 0) - (sides.bottom ? ring : 0),\n };\n if (ringRect.width <= 0 || ringRect.height <= 0) continue;\n paintRing(out, style.borderStyle, style.borderColor, ringRect, sides);\n }\n}\n\n/**\n * Paint one ring, honoring per-side styles and colors. Each edge uses its\n * own style's glyphs. A corner where both adjacent edges share a style uses\n * that style's corner glyph; mixed-style corners fall back to the light\n * corners (Unicode has no mixed junction glyphs for most pairs — same\n * convention as dashed/dotted). Corner color comes from the horizontal\n * (top/bottom) edge.\n */\nfunction paintRing(\n out: BorderRun[],\n styles: PerSide<BorderStyle>,\n colors: PerSide<string | undefined>,\n rect: Rect,\n sides: RingSides,\n): void {\n const top = borderGlyphs(styles.top);\n const right = borderGlyphs(styles.right);\n const bottom = borderGlyphs(styles.bottom);\n const left = borderGlyphs(styles.left);\n const corner = (a: BorderStyle, b: BorderStyle, pick: (g: Glyphs) => string): string =>\n a === b ? pick(borderGlyphs(a)) : pick(borderGlyphs(\"solid\"));\n const { x, y, width, height } = rect;\n const hasCorners = width >= 2 && height >= 2;\n const interiorStartX = x + (sides.left ? 1 : 0);\n const interiorEndX = x + width - (sides.right ? 1 : 0);\n const interiorStartY = y + (sides.top ? 1 : 0);\n const interiorEndY = y + height - (sides.bottom ? 1 : 0);\n\n // Horizontal edges\n if (sides.top && interiorEndX > interiorStartX) {\n out.push({\n glyph: top.h,\n x: interiorStartX,\n y,\n length: interiorEndX - interiorStartX,\n color: colors.top,\n });\n }\n if (sides.bottom && height > (sides.top ? 1 : 0) && interiorEndX > interiorStartX) {\n out.push({\n glyph: bottom.h,\n x: interiorStartX,\n y: y + height - 1,\n length: interiorEndX - interiorStartX,\n color: colors.bottom,\n });\n }\n // Vertical edges\n if (sides.left) {\n for (let vy = interiorStartY; vy < interiorEndY; vy++)\n out.push({ glyph: left.v, x, y: vy, length: 1, color: colors.left });\n }\n if (sides.right && width > (sides.left ? 1 : 0)) {\n for (let vy = interiorStartY; vy < interiorEndY; vy++)\n out.push({ glyph: right.v, x: x + width - 1, y: vy, length: 1, color: colors.right });\n }\n // Corners (only when we have interior room to distinguish them)\n if (hasCorners) {\n if (sides.top && sides.left)\n out.push({\n glyph: corner(styles.top, styles.left, (g) => g.tl),\n x,\n y,\n length: 1,\n color: colors.top,\n });\n if (sides.top && sides.right)\n out.push({\n glyph: corner(styles.top, styles.right, (g) => g.tr),\n x: x + width - 1,\n y,\n length: 1,\n color: colors.top,\n });\n if (sides.bottom && sides.left)\n out.push({\n glyph: corner(styles.bottom, styles.left, (g) => g.bl),\n x,\n y: y + height - 1,\n length: 1,\n color: colors.bottom,\n });\n if (sides.bottom && sides.right)\n out.push({\n glyph: corner(styles.bottom, styles.right, (g) => g.br),\n x: x + width - 1,\n y: y + height - 1,\n length: 1,\n color: colors.bottom,\n });\n }\n}\n\nfunction borderGlyphs(style: BorderStyle): Glyphs {\n switch (style) {\n case \"double\":\n return { h: \"═\", v: \"║\", tl: \"╔\", tr: \"╗\", bl: \"╚\", br: \"╝\" };\n // Light double dash pair: two dashes per cell, cleaner than the triple\n // dash `┄`/`┆` which reads as dots in many fonts.\n case \"dashed\":\n return { h: \"╌\", v: \"╎\", tl: \"┌\", tr: \"┐\", bl: \"└\", br: \"┘\" };\n case \"dotted\":\n return { h: \"┄\", v: \"┊\", tl: \"┌\", tr: \"┐\", bl: \"└\", br: \"┘\" };\n default:\n return { h: \"─\", v: \"│\", tl: \"┌\", tr: \"┐\", bl: \"└\", br: \"┘\" };\n }\n}\n","import { collectBorderRuns } from \"./borders.ts\";\nimport type { BorderRun } from \"./borders.ts\";\nimport type { Insets, LayoutNode, Rect } from \"./types.ts\";\n\n/**\n * Write geometry custom properties on each source element and (re)paint the\n * decoration layer. Coordinates on LayoutNode are parent-relative; borders\n * are painted in absolute coordinates so we accumulate the parent origin as\n * we walk.\n */\nexport function render(root: LayoutNode, decorationLayer: HTMLElement): void {\n const borderRuns: BorderRun[] = [];\n walk(root, 0, 0, borderRuns, true);\n paintDecorations(decorationLayer, borderRuns);\n}\n\nfunction walk(\n node: LayoutNode,\n parentAbsX: number,\n parentAbsY: number,\n borderRuns: BorderRun[],\n isRoot: boolean,\n): void {\n const absX = parentAbsX + node.localRect.x;\n const absY = parentAbsY + node.localRect.y;\n\n if (!isRoot) {\n positionElement(\n node.source as HTMLElement,\n node.localRect,\n node.resolvedPadding,\n node.style.border,\n node.style.textAlignBlocked,\n node.style.overflow,\n node.style.whiteSpace,\n );\n }\n\n collectBorderRuns(\n node.style,\n { x: absX, y: absY, width: node.localRect.width, height: node.localRect.height },\n borderRuns,\n );\n\n for (const child of node.children) {\n walk(child, absX, absY, borderRuns, false);\n }\n}\n\nfunction positionElement(\n el: HTMLElement,\n rect: Rect,\n padding: Insets,\n border: Insets,\n textAlignBlocked: boolean,\n overflow: \"visible\" | \"clip\",\n whiteSpace: \"normal\" | \"nowrap\",\n): void {\n el.setAttribute(\"data-mw-laid-out\", \"\");\n if (whiteSpace === \"nowrap\") el.setAttribute(\"data-mw-nowrap\", \"\");\n else el.removeAttribute(\"data-mw-nowrap\");\n el.style.setProperty(\"--mw-x\", String(rect.x));\n el.style.setProperty(\"--mw-y\", String(rect.y));\n el.style.setProperty(\"--mw-w\", String(rect.width));\n el.style.setProperty(\"--mw-h\", String(rect.height));\n if (overflow === \"clip\") el.setAttribute(\"data-mw-clip\", \"\");\n else el.removeAttribute(\"data-mw-clip\");\n // The browser insets content by border + padding; the engine has already\n // allocated cells for both. We expose them separately so the companion CSS\n // reads naturally, and the CSS sums them into the actual `padding` (since\n // engine border is painted as glyphs, native border-width stays 0).\n el.style.setProperty(\"--mw-pt\", String(padding.top));\n el.style.setProperty(\"--mw-pr\", String(padding.right));\n el.style.setProperty(\"--mw-pb\", String(padding.bottom));\n el.style.setProperty(\"--mw-pl\", String(padding.left));\n el.style.setProperty(\"--mw-bt\", String(border.top));\n el.style.setProperty(\"--mw-br\", String(border.right));\n el.style.setProperty(\"--mw-bb\", String(border.bottom));\n el.style.setProperty(\"--mw-bl\", String(border.left));\n if (textAlignBlocked) el.setAttribute(\"data-mw-text-align-blocked\", \"\");\n else el.removeAttribute(\"data-mw-text-align-blocked\");\n}\n\nfunction paintDecorations(layer: HTMLElement, runs: BorderRun[]): void {\n layer.replaceChildren();\n for (const run of runs) {\n // One span PER CELL, not per run: box-drawing glyphs may come from a\n // fallback font with a different advance width than the measured cell\n // (e.g. Google Fonts subsets that omit box-drawing characters), so a\n // multi-glyph run would drift off the grid. Positioning every glyph\n // from the grid keeps borders aligned regardless of which font supplies\n // the glyph. Revisit as a perf optimization once we can detect that the\n // active font covers the glyphs (or when painting to canvas).\n for (let i = 0; i < run.length; i++) {\n const span = document.createElement(\"span\");\n span.setAttribute(\"aria-hidden\", \"true\");\n span.style.position = \"absolute\";\n span.style.left = `calc(${run.x + i} * var(--mw-cw))`;\n span.style.top = `calc(${run.y} * var(--mw-ch))`;\n span.style.font = \"inherit\";\n span.style.lineHeight = \"inherit\";\n span.style.whiteSpace = \"pre\";\n span.style.pointerEvents = \"none\";\n span.style.userSelect = \"none\";\n if (run.color) span.style.color = run.color;\n span.textContent = run.glyph;\n layer.appendChild(span);\n }\n }\n}\n","import { pxToCells, roundHalfAwayFromZero } from \"./metrics.ts\";\nimport type {\n AlignItems,\n BorderStyle,\n CellLength,\n CellStyle,\n Display,\n Insets,\n JustifyContent,\n PerSide,\n Size,\n} from \"./types.ts\";\n\n/**\n * Read the interpreted CellStyle for an element from its computed CSS.\n *\n * The host must have the `measuring` attribute set while this runs so the\n * engine's own geometry rules (from styles.css) don't feed their outputs back\n * into what we read.\n */\nexport function readCellStyle(el: Element, rootFontSizePx: number): CellStyle {\n const cs = getComputedStyle(el);\n const csm = supportsTypedOM(el) ? el.computedStyleMap() : null;\n const classAttr = el.getAttribute(\"class\") ?? \"\";\n const inlineStyle = (el as HTMLElement).style;\n\n const rawDisplay = cs.display;\n const display: Display =\n rawDisplay === \"flex\"\n ? \"flex\"\n : rawDisplay === \"grid\"\n ? \"grid\"\n : rawDisplay === \"none\"\n ? \"none\"\n : rawDisplay.startsWith(\"inline\")\n ? \"block\"\n : \"block\";\n\n return {\n display,\n flexDirection: cs.flexDirection.startsWith(\"column\") ? \"column\" : \"row\",\n flexReverse: cs.flexDirection.endsWith(\"-reverse\"),\n flexWrap: cs.flexWrap.startsWith(\"wrap\") ? \"wrap\" : \"nowrap\",\n wrapReverse: cs.flexWrap === \"wrap-reverse\",\n flexGrow: Number(cs.flexGrow) || 0,\n flexShrink: cs.flexShrink === \"\" ? 1 : Number(cs.flexShrink) || 0,\n // flex-basis keeps its computed form (percentages stay symbolic), so\n // plain getComputedStyle is reliable here — `flex-1` reads as \"0%\".\n flexBasis: readFlexBasis(cs.flexBasis, rootFontSizePx),\n order: Number(cs.order) || 0,\n justifyContent: mapJustify(cs.justifyContent),\n alignItems: mapAlign(cs.alignItems),\n alignSelf: mapAlignSelf(cs.alignSelf),\n width: readSize(csm, cs.width, \"width\", rootFontSizePx, classAttr, inlineStyle),\n height: readSize(csm, cs.height, \"height\", rootFontSizePx, classAttr, inlineStyle),\n minWidth: readLimit(cs.minWidth, rootFontSizePx) ?? \"auto\",\n minHeight: readLimit(cs.minHeight, rootFontSizePx) ?? \"auto\",\n maxWidth: readLimit(cs.maxWidth, rootFontSizePx),\n maxHeight: readLimit(cs.maxHeight, rootFontSizePx),\n padding: readPadding(cs, rootFontSizePx),\n margin: readMargin(cs, csm, classAttr, rootFontSizePx),\n gapX: readSpacing(cs.columnGap === \"normal\" ? \"0px\" : cs.columnGap, rootFontSizePx),\n gapY: readSpacing(cs.rowGap === \"normal\" ? \"0px\" : cs.rowGap, rootFontSizePx),\n border: readBorderInsets(cs),\n borderStyle: {\n top: mapBorderStyle(cs.borderTopStyle),\n right: mapBorderStyle(cs.borderRightStyle),\n bottom: mapBorderStyle(cs.borderBottomStyle),\n left: mapBorderStyle(cs.borderLeftStyle),\n },\n // Treat `hidden` and `clip` the same — both keep content inside the\n // box. Normalized to `clip` internally since that's the more precise\n // semantic for what we do (no scroll container, cheaper). Longhands\n // (`overflow-x`/`overflow-y`) are honored: setting just one axis to\n // hidden or clip still marks the element as clipping. `auto` and\n // `scroll` are left as \"visible\" here — real scrolling is deferred to\n // the scrolling milestone.\n overflow:\n isClipping(cs.overflow) || isClipping(cs.overflowX) || isClipping(cs.overflowY)\n ? \"clip\"\n : \"visible\",\n // `nowrap` and `pre` disable soft wrapping; `pre`'s whitespace\n // preservation is NOT honored (documented deviation — the tree builder\n // collapses whitespace). Readable via getComputedStyle because the\n // companion stylesheet's white-space lock is gated on `:not([measuring])`.\n whiteSpace: cs.whiteSpace === \"nowrap\" || cs.whiteSpace === \"pre\" ? \"nowrap\" : \"normal\",\n textOverflow: cs.textOverflow === \"ellipsis\" ? \"ellipsis\" : \"clip\",\n color: cs.color,\n backgroundColor: cs.backgroundColor === \"rgba(0, 0, 0, 0)\" ? undefined : cs.backgroundColor,\n borderColor: {\n top: cs.borderTopColor,\n right: cs.borderRightColor,\n bottom: cs.borderBottomColor,\n left: cs.borderLeftColor,\n },\n // Detect authored text-align via class + inline style rather than\n // getComputedStyle, since our own override would otherwise be echoed\n // back and cause oscillation. Inheritance is handled by CSS: forcing\n // `text-align: start` on the element that authors center/justify\n // cascades to its descendants automatically.\n textAlignBlocked: authoredTextAlignBlocked(classAttr, inlineStyle),\n };\n}\n\nfunction isClipping(value: string): boolean {\n return value === \"hidden\" || value === \"clip\";\n}\n\nfunction authoredTextAlignBlocked(classAttr: string, inlineStyle: CSSStyleDeclaration): boolean {\n if (/(?:^|[\\s:.[!])text-(?:center|justify)/.test(classAttr)) return true;\n const inline = inlineStyle.textAlign;\n return inline === \"center\" || inline === \"justify\";\n}\n\nfunction supportsTypedOM(\n el: Element,\n): el is Element & { computedStyleMap(): StylePropertyMapReadOnly } {\n return typeof (el as { computedStyleMap?: unknown }).computedStyleMap === \"function\";\n}\n\nfunction mapJustify(value: string): JustifyContent {\n switch (value) {\n case \"center\":\n return \"center\";\n case \"flex-end\":\n case \"end\":\n case \"right\":\n return \"end\";\n case \"space-between\":\n return \"space-between\";\n case \"space-around\":\n return \"space-around\";\n case \"space-evenly\":\n return \"space-evenly\";\n default:\n return \"start\";\n }\n}\n\nfunction mapAlign(value: string): AlignItems {\n switch (value) {\n case \"center\":\n return \"center\";\n case \"flex-end\":\n case \"end\":\n return \"end\";\n case \"stretch\":\n // CSS default for align-items on a flex container is \"normal\", which\n // behaves as \"stretch\" in flex/grid contexts.\n case \"normal\":\n case \"\":\n return \"stretch\";\n default:\n return \"start\";\n }\n}\n\nfunction mapAlignSelf(value: string): \"auto\" | AlignItems {\n if (value === \"auto\" || value === \"\" || value === \"normal\") return \"auto\";\n return mapAlign(value);\n}\n\n/**\n * Read margins, preserving `auto` as `null`.\n *\n * `getComputedStyle` returns *used* values for margins on flex items, which\n * means an authored `auto` has already been resolved to a pixel length by\n * the browser's own flex pass — we can't tell \"auto\" from a fixed number\n * anymore. Typed OM returns *computed* values, so \"auto\" survives; we use it\n * as the source of truth when available.\n *\n * On engines without Typed OM (Firefox pre-157), fall back to scanning the\n * class attribute for Tailwind auto-margin utilities. LTR only for now.\n */\nfunction readMargin(\n cs: CSSStyleDeclaration,\n csm: StylePropertyMapReadOnly | null,\n classAttr: string,\n rootFontSizePx: number,\n): PerSide<CellLength | null> {\n const readSide = (\n physical: string,\n logical: string,\n autoClassPattern: RegExp,\n ): CellLength | null => {\n if (csm) {\n const physicalValue = csm.get(physical)?.toString().trim();\n if (physicalValue === \"auto\") return null;\n const logicalValue = csm.get(logical)?.toString().trim();\n if (logicalValue === \"auto\") return null;\n // Percent margins must stay symbolic (getComputedStyle would hand\n // back a used px value resolved against the pre-grid natural layout).\n if (physicalValue?.endsWith(\"%\")) {\n const percent = parseFloat(physicalValue);\n if (Number.isFinite(percent) && percent !== 0) return { percent };\n }\n } else if (autoClassPattern.test(classAttr)) {\n return null;\n }\n const physicalValue = cs.getPropertyValue(physical);\n if (physicalValue === \"auto\") return null;\n const physicalCells = readSpacing(physicalValue, rootFontSizePx);\n if (physicalCells !== 0) return physicalCells;\n const logicalValue = cs.getPropertyValue(logical);\n if (logicalValue === \"auto\") return null;\n return readSpacing(logicalValue, rootFontSizePx);\n };\n return {\n top: readSide(\"margin-top\", \"margin-block-start\", /(?:^|[\\s:.[!])(?:m|my|mt)-auto\\b/),\n right: readSide(\"margin-right\", \"margin-inline-end\", /(?:^|[\\s:.[!])(?:m|mx|mr|me)-auto\\b/),\n bottom: readSide(\"margin-bottom\", \"margin-block-end\", /(?:^|[\\s:.[!])(?:m|my|mb)-auto\\b/),\n left: readSide(\"margin-left\", \"margin-inline-start\", /(?:^|[\\s:.[!])(?:m|mx|ml|ms)-auto\\b/),\n };\n}\n\nfunction mapBorderStyle(value: string): BorderStyle {\n switch (value) {\n case \"double\":\n return \"double\";\n case \"dashed\":\n return \"dashed\";\n case \"dotted\":\n return \"dotted\";\n default:\n return \"solid\";\n }\n}\n\n/**\n * Read a min/max constraint. Percentages must be kept symbolic (they resolve\n * against the parent's content box during layout) — naive px parsing would\n * read `\"100%\"` as 100px and produce a nonsense cell count.\n */\nfunction readLimit(value: string, rootFontSizePx: number): CellLength | undefined {\n if (!value || value === \"none\" || value === \"auto\") return undefined;\n if (value.endsWith(\"%\")) {\n const percent = parseFloat(value);\n return Number.isFinite(percent) ? { percent } : undefined;\n }\n const px = parseFloat(value);\n return Number.isFinite(px) ? pxToCells(px, rootFontSizePx) : undefined;\n}\n\n/**\n * Read a spacing length. Percentages stay symbolic — they resolve against\n * the containing block's width during layout (getComputedStyle would give\n * a used px value based on the pre-grid natural layout, which is wrong).\n */\nfunction readSpacing(value: string, rootFontSizePx: number): CellLength {\n if (!value || value === \"auto\" || value === \"none\") return 0;\n if (value.endsWith(\"%\")) {\n const percent = parseFloat(value);\n return Number.isFinite(percent) && percent !== 0 ? { percent } : 0;\n }\n const px = parseFloat(value);\n return Number.isFinite(px) ? pxToCells(px, rootFontSizePx) : 0;\n}\n\nfunction readSize(\n csm: StylePropertyMapReadOnly | null,\n fallback: string,\n key: \"width\" | \"height\",\n rootFontSizePx: number,\n classAttr: string,\n inlineStyle: CSSStyleDeclaration,\n): Size | undefined {\n if (csm) {\n const value = csm.get(key);\n if (value == null) return undefined;\n const s = value.toString().trim();\n if (s === \"auto\") return { kind: \"auto\" };\n const intrinsic = intrinsicSizeKeyword(s);\n if (intrinsic) return intrinsic;\n if (s.endsWith(\"%\")) return { kind: \"percent\", value: parseFloat(s) };\n if (s.endsWith(\"px\")) return { kind: \"cells\", value: pxToCells(parseFloat(s), rootFontSizePx) };\n if (s.endsWith(\"rem\"))\n return { kind: \"cells\", value: roundHalfAwayFromZero(parseFloat(s) / 0.25) };\n }\n // Fallback path (Firefox pre-157: no Typed OM). getComputedStyle returns\n // *used* values (always px) for box properties, so we can't distinguish\n // \"authored w-N\" from \"natural content width\". Look at what was authored:\n // inline styles first, then any Tailwind sizing utility in the class list.\n // If neither is present, treat as auto so intrinsic sizing kicks in.\n const inline = key === \"width\" ? inlineStyle.width : inlineStyle.height;\n if (inline) {\n if (inline === \"auto\") return { kind: \"auto\" };\n const intrinsic = intrinsicSizeKeyword(inline);\n if (intrinsic) return intrinsic;\n if (inline.endsWith(\"%\")) return { kind: \"percent\", value: parseFloat(inline) };\n const px = parseFloat(inline);\n if (Number.isFinite(px)) return { kind: \"cells\", value: pxToCells(px, rootFontSizePx) };\n }\n // Intrinsic-keyword utilities (`w-min`…) must be caught by class scan here:\n // getComputedStyle would hand back the browser's *used* px width, which is\n // measured content px — NOT on the spacing scale — and would convert to a\n // nonsense cell count.\n const axis = key === \"width\" ? \"w\" : \"h\";\n if (new RegExp(`(?:^|[\\\\s:.[!])${axis}-min\\\\b`).test(classAttr)) return { kind: \"min-content\" };\n if (new RegExp(`(?:^|[\\\\s:.[!])${axis}-max\\\\b`).test(classAttr)) return { kind: \"max-content\" };\n if (new RegExp(`(?:^|[\\\\s:.[!])${axis}-fit\\\\b`).test(classAttr)) return { kind: \"fit-content\" };\n if (!hasSizingUtility(classAttr, axis)) return { kind: \"auto\" };\n if (fallback === \"auto\") return { kind: \"auto\" };\n if (fallback.endsWith(\"%\")) return { kind: \"percent\", value: parseFloat(fallback) };\n const px = parseFloat(fallback);\n if (Number.isFinite(px)) return { kind: \"cells\", value: pxToCells(px, rootFontSizePx) };\n return undefined;\n}\n\n/**\n * CSS `flex-basis`. `auto` (and the unsupported `content`) → undefined, so\n * the layout falls back to the width-or-intrinsic base. `0%` (Tailwind\n * `flex-1`) must survive as an actual zero base.\n */\nfunction readFlexBasis(value: string, rootFontSizePx: number): Size | undefined {\n if (!value || value === \"auto\" || value === \"content\") return undefined;\n const keyword = intrinsicSizeKeyword(value);\n if (keyword) return keyword;\n if (value.endsWith(\"%\")) {\n const percent = parseFloat(value);\n return Number.isFinite(percent) ? { kind: \"percent\", value: percent } : undefined;\n }\n const px = parseFloat(value);\n return Number.isFinite(px) ? { kind: \"cells\", value: pxToCells(px, rootFontSizePx) } : undefined;\n}\n\nfunction intrinsicSizeKeyword(value: string): Size | undefined {\n if (value === \"min-content\") return { kind: \"min-content\" };\n if (value === \"max-content\") return { kind: \"max-content\" };\n if (value === \"fit-content\") return { kind: \"fit-content\" };\n return undefined;\n}\n\n/**\n * Detect whether an element has an authored `width` / `height` utility (not\n * `min-*` or `max-*`, which set separate properties). Handles variants\n * (`md:w-full`, `hover:w-0`) and arbitrary variant selectors (`[&_span]:w-2`).\n * Used only when Typed OM is unavailable.\n */\nfunction hasSizingUtility(classAttr: string, axis: \"w\" | \"h\"): boolean {\n const pattern = axis === \"w\" ? /(?:^|[\\s:.[!])w-/ : /(?:^|[\\s:.[!])h-/;\n return pattern.test(classAttr);\n}\n\nfunction readPadding(cs: CSSStyleDeclaration, rootFontSizePx: number): PerSide<CellLength> {\n return {\n top: readSpacing(cs.getPropertyValue(\"padding-top\"), rootFontSizePx),\n right: readSpacing(cs.getPropertyValue(\"padding-right\"), rootFontSizePx),\n bottom: readSpacing(cs.getPropertyValue(\"padding-bottom\"), rootFontSizePx),\n left: readSpacing(cs.getPropertyValue(\"padding-left\"), rootFontSizePx),\n };\n}\n\n/** Border widths use the 1px = 1 cell scale (not the spacing scale). */\nfunction readBorderInsets(cs: CSSStyleDeclaration): Insets {\n const readSide = (side: string, style: string) => {\n if (cs.getPropertyValue(style) === \"none\") return 0;\n return roundHalfAwayFromZero(parseFloat(cs.getPropertyValue(side)) || 0);\n };\n return {\n top: readSide(\"border-top-width\", \"border-top-style\"),\n right: readSide(\"border-right-width\", \"border-right-style\"),\n bottom: readSide(\"border-bottom-width\", \"border-bottom-style\"),\n left: readSide(\"border-left-width\", \"border-left-style\"),\n };\n}\n","export interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface Insets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\n/** Insets where any side can be `null` to signal `auto` (used for margins). */\nexport interface NullableInsets {\n top: number | null;\n right: number | null;\n bottom: number | null;\n left: number | null;\n}\n\nexport type Size =\n | { kind: \"cells\"; value: number }\n | { kind: \"percent\"; value: number }\n | { kind: \"auto\" }\n /** Intrinsic sizing keywords (`w-min` / `w-max` / `w-fit`). Resolved\n * against content: min-content = longest unbreakable unit, max-content =\n * unwrapped size, fit-content = shrink-to-fit within the available space.\n * Only honored for `width`; on `height` they behave as `auto` (content\n * height already is the intrinsic height). */\n | { kind: \"min-content\" }\n | { kind: \"max-content\" }\n | { kind: \"fit-content\" };\n\nexport type Display = \"block\" | \"flex\" | \"grid\" | \"none\";\nexport type FlexDirection = \"row\" | \"column\";\nexport type FlexWrap = \"nowrap\" | \"wrap\";\nexport type JustifyContent =\n | \"start\"\n | \"center\"\n | \"end\"\n | \"space-between\"\n | \"space-around\"\n | \"space-evenly\";\nexport type AlignItems = \"start\" | \"center\" | \"end\" | \"stretch\";\nexport type AlignSelf = \"auto\" | \"start\" | \"center\" | \"end\" | \"stretch\";\nexport type BorderStyle = \"solid\" | \"double\" | \"dashed\" | \"dotted\";\nexport type Overflow = \"visible\" | \"clip\";\nexport type WhiteSpace = \"normal\" | \"nowrap\";\n\n/** A length in whole cells, or a percentage kept symbolic until layout.\n * Percentages resolve against the CSS-appropriate basis at layout time:\n * the available extent for min/max (`max-w-full` = 100%), the containing\n * block's WIDTH for padding and margins (all four sides, per CSS), and the\n * container's own content box in the gap's axis for gaps. */\nexport type CellLength = number | { percent: number };\nexport type TextOverflow = \"clip\" | \"ellipsis\";\n\n/** One value per box edge (border style, border color, …). */\nexport interface PerSide<T> {\n top: T;\n right: T;\n bottom: T;\n left: T;\n}\n\nexport interface CellStyle {\n display: Display;\n flexDirection: FlexDirection;\n /** True for `row-reverse` / `column-reverse`: the main axis runs\n * backwards — items lay out in reverse order and `justify-content`\n * start/end swap meaning. */\n flexReverse: boolean;\n flexWrap: FlexWrap;\n /** True for `wrap-reverse`: lines stack from the cross-end (bottom-up). */\n wrapReverse: boolean;\n flexGrow: number;\n flexShrink: number;\n /** CSS `flex-basis`: the flex base size when not `auto`/undefined —\n * notably `0%` from Tailwind's `flex-1`, which makes grow distribute ALL\n * the space (equal columns) instead of just the extra. */\n flexBasis: Size | undefined;\n /** CSS `order` — flex items sort by it (stable, document order ties). */\n order: number;\n justifyContent: JustifyContent;\n alignItems: AlignItems;\n alignSelf: AlignSelf;\n width: Size | undefined;\n height: Size | undefined;\n /** `\"auto\"` is CSS `min-width/height: auto`: 0 in block flow, but a flex\n * item's automatic minimum (its min-content size, when overflow is\n * visible) on the flex main axis — the reason text in a flex row stops\n * shrinking instead of vanishing, and why `min-w-0` exists. */\n minWidth: CellLength | \"auto\";\n minHeight: CellLength | \"auto\";\n maxWidth: CellLength | undefined;\n maxHeight: CellLength | undefined;\n padding: PerSide<CellLength>;\n /** `null` = `auto`. Percentages resolve against the parent's content\n * width where the margin is consumed. */\n margin: PerSide<CellLength | null>;\n gapX: CellLength;\n gapY: CellLength;\n border: Insets;\n borderStyle: PerSide<BorderStyle>;\n borderColor: PerSide<string | undefined>;\n overflow: Overflow;\n /** `nowrap` disables soft wrapping (hard `<br>` breaks still apply). */\n whiteSpace: WhiteSpace;\n /** Paint-only: with `nowrap` + clipping, the browser draws the ellipsis.\n * The engine only needs it for the ASCII renderer's mirror of that. */\n textOverflow: TextOverflow;\n /**\n * Paint-only colors, reserved for the visual-system milestone. `color` will\n * feed decoration glyphs that visually belong to the text (control framing\n * like `[ Save ]`, cursors, selection carets); `backgroundColor` will feed\n * cell-level highlights (selection ranges, decoration backgrounds). Read\n * from the source element now so the future work has the data available.\n */\n color: string | undefined;\n backgroundColor: string | undefined;\n /** True when text-align is center/justify — forced back to `start` since\n * per-line centering can't be snapped to whole cells. See cell-model spec. */\n textAlignBlocked: boolean;\n}\n\nexport interface LayoutNode {\n source: Element;\n style: CellStyle;\n children: LayoutNode[];\n /** Raw text content of the element's direct text nodes (leaves only). Empty\n * for pure containers. May coexist with child element nodes when the\n * element has mixed text+element children. */\n text: string;\n intrinsicWidth: number;\n intrinsicHeight: number;\n localRect: Rect;\n /** Outer height before min/max clamping — written by layoutNode; the\n * column flex algorithm's base main size (CSS distributes from unclamped\n * bases; limits apply via its freeze loop). */\n unclampedHeight: number;\n /** Padding with percentages resolved to cells — written by layoutNode\n * (percent resolves against the containing block width, which only\n * layout knows); the renderers read this, never `style.padding`. */\n resolvedPadding: Insets;\n}\n\nexport interface CellMetrics {\n width: number;\n height: number;\n}\n\nexport function defaultCellStyle(): CellStyle {\n return {\n display: \"block\",\n flexDirection: \"row\",\n flexReverse: false,\n flexWrap: \"nowrap\",\n wrapReverse: false,\n flexGrow: 0,\n flexShrink: 0,\n flexBasis: undefined,\n order: 0,\n justifyContent: \"start\",\n alignItems: \"start\",\n alignSelf: \"auto\",\n width: undefined,\n height: undefined,\n minWidth: \"auto\",\n minHeight: \"auto\",\n maxWidth: undefined,\n maxHeight: undefined,\n padding: zeroInsets(),\n margin: { top: 0, right: 0, bottom: 0, left: 0 },\n gapX: 0,\n gapY: 0,\n border: zeroInsets(),\n borderStyle: { top: \"solid\", right: \"solid\", bottom: \"solid\", left: \"solid\" },\n overflow: \"visible\",\n whiteSpace: \"normal\",\n textOverflow: \"clip\",\n color: undefined,\n backgroundColor: undefined,\n borderColor: { top: undefined, right: undefined, bottom: undefined, left: undefined },\n textAlignBlocked: false,\n };\n}\n\nexport function zeroInsets(): Insets {\n return { top: 0, right: 0, bottom: 0, left: 0 };\n}\n","import { readCellStyle } from \"./style.ts\";\nimport { zeroInsets } from \"./types.ts\";\nimport type { LayoutNode } from \"./types.ts\";\n\n/**\n * Build a LayoutNode tree from an element subtree.\n *\n * Rules:\n * - Elements with computed `display: none` are skipped entirely.\n * - An element becomes a **leaf** if it has no element children, or if all\n * its element children have computed `display: inline`/`inline-*`/`contents`\n * (they're part of the inline text flow, not laid out separately). The\n * leaf's `text` is the element's combined `textContent`, so text nodes\n * interleaved with inline elements (`<div>hello <span>world</span></div>`)\n * participate in the wrap calculation and render correctly.\n * - Elements with at least one block-level element child become **containers**\n * and recurse. Direct text nodes on containers (uncommon in utility-first\n * markup) are not laid out — CSS creates anonymous inline boxes for them,\n * but our absolutely-positioned children escape that flow. This is\n * documented as a deviation in specs/cell-model.md.\n */\nexport function buildTree(root: Element, rootFontSizePx: number): LayoutNode | null {\n const style = readCellStyle(root, rootFontSizePx);\n if (style.display === \"none\") return null;\n\n const elementChildren = Array.from(root.children);\n const isInlineOnly = elementChildren.every(hasInlineDisplay);\n\n if (isInlineOnly) {\n // Per-hard-line trim: whitespace around a `<br>` is source formatting\n // (the browser collapses and strips it at line edges), not content.\n const text = extractLeafText(root)\n .split(\"\\n\")\n .map((line) => line.trim())\n .join(\"\\n\")\n .trim();\n const intrinsicWidth = longestLine(text);\n const intrinsicHeight = text.length > 0 ? countHardLines(text) : 0;\n return {\n source: root,\n style,\n children: [],\n text,\n intrinsicWidth,\n intrinsicHeight,\n localRect: { x: 0, y: 0, width: intrinsicWidth, height: intrinsicHeight },\n unclampedHeight: 0,\n resolvedPadding: zeroInsets(),\n };\n }\n\n const children: LayoutNode[] = [];\n for (const child of elementChildren) {\n const node = buildTree(child, rootFontSizePx);\n if (node) children.push(node);\n }\n return {\n source: root,\n style,\n children,\n text: \"\",\n intrinsicWidth: 0,\n intrinsicHeight: 0,\n localRect: { x: 0, y: 0, width: 0, height: 0 },\n unclampedHeight: 0,\n resolvedPadding: zeroInsets(),\n };\n}\n\n/**\n * HTML tags whose default display is inline. Checked BEFORE computed display\n * because a flex/grid parent \"blockifies\" its direct children (per CSS), so\n * `<br>`/`<span>`/etc. inside a `display: flex` element compute to \"block\".\n * For our purposes those are still semantically inline text-flow markers\n * and shouldn't force their parent into container mode.\n */\nconst INLINE_BY_DEFAULT_TAGS = new Set([\n \"A\",\n \"ABBR\",\n \"B\",\n \"BDI\",\n \"BDO\",\n \"BR\",\n \"CITE\",\n \"CODE\",\n \"DATA\",\n \"DFN\",\n \"EM\",\n \"I\",\n \"KBD\",\n \"MARK\",\n \"Q\",\n \"S\",\n \"SAMP\",\n \"SMALL\",\n \"SPAN\",\n \"STRONG\",\n \"SUB\",\n \"SUP\",\n \"TIME\",\n \"U\",\n \"VAR\",\n \"WBR\",\n]);\n\nfunction hasInlineDisplay(el: Element): boolean {\n if (INLINE_BY_DEFAULT_TAGS.has(el.tagName)) return true;\n const display = getComputedStyle(el).display;\n return display.startsWith(\"inline\") || display === \"contents\";\n}\n\n/**\n * Walk childNodes and produce the leaf's text — with `<br>` emitted as `\\n`\n * so the wrap calculation counts the line break the browser will honor.\n * Recurses into inline elements (`<span>`, `<a>`, `<b>`, …).\n *\n * Whitespace inside text nodes (including literal newlines from source\n * formatting) collapses to single spaces, exactly like the browser under\n * `white-space: normal` — ONLY `<br>` produces a hard `\\n`. Without this,\n * markup indentation would masquerade as hard line breaks and the engine\n * would allocate rows the browser never renders.\n */\nfunction extractLeafText(el: Element): string {\n const parts: string[] = [];\n for (const node of Array.from(el.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n // CSS collapsible white space only (space/tab/CR/LF/FF) — NOT `\\s`,\n // which would also eat NBSP (U+00A0); the browser preserves NBSP and\n // never breaks at it.\n parts.push((node.textContent ?? \"\").replace(/[ \\t\\r\\n\\f]+/g, \" \"));\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n const child = node as Element;\n if (child.tagName === \"BR\") parts.push(\"\\n\");\n else parts.push(extractLeafText(child));\n }\n }\n return parts.join(\"\");\n}\n\nfunction longestLine(text: string): number {\n let max = 0;\n for (const line of text.split(\"\\n\")) if (line.length > max) max = line.length;\n return max;\n}\n\nfunction countHardLines(text: string): number {\n return text.split(\"\\n\").length;\n}\n","import { getRootFontSizePx, measureCellMetrics } from \"./metrics.ts\";\nimport { layoutRoot } from \"./layout.ts\";\nimport { render } from \"./render.ts\";\nimport { buildTree } from \"./tree.ts\";\nimport { defaultCellStyle } from \"./types.ts\";\nimport type { CellMetrics, LayoutNode } from \"./types.ts\";\n\nconst SHADOW_TEMPLATE = `\n<style>\n :host { display: block; position: relative; contain: layout style; }\n #viewport { position: relative; width: 100%; height: 100%; }\n #decorations { position: absolute; inset: 0; pointer-events: none; user-select: none; white-space: pre; }\n</style>\n<div id=\"viewport\">\n <div id=\"decorations\" aria-hidden=\"true\"></div>\n <slot></slot>\n</div>\n`;\n\nexport class MonoWindElement extends HTMLElement {\n #shadow: ShadowRoot;\n #decorations: HTMLElement;\n #resizeObserver: ResizeObserver | null = null;\n #mutationObserver: MutationObserver | null = null;\n #layoutPending = false;\n #suppressMutations = 0;\n #cellMetrics: CellMetrics | null = null;\n\n constructor() {\n super();\n this.#shadow = this.attachShadow({ mode: \"open\" });\n this.#shadow.innerHTML = SHADOW_TEMPLATE;\n this.#decorations = this.#shadow.getElementById(\"decorations\") as HTMLElement;\n }\n\n connectedCallback(): void {\n this.#resizeObserver = new ResizeObserver(() => this.#scheduleLayout());\n this.#resizeObserver.observe(this);\n\n this.#mutationObserver = new MutationObserver((records) => {\n if (this.#suppressMutations > 0) return;\n if (records.every(this.#isOwnedMutation)) return;\n // A class or style change on the host itself can shift font metrics\n // (font-size, font-family, letter-spacing). Invalidate the cache so\n // the next layout re-measures.\n if (records.some((r) => r.target === this && r.type === \"attributes\")) {\n this.#cellMetrics = null;\n }\n this.#scheduleLayout();\n });\n this.#mutationObserver.observe(this, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n attributeFilter: [\"class\", \"style\"],\n });\n\n // Fonts can finish loading after our first layout (the first layout then\n // used fallback-font metrics), which would leave decorations positioned\n // with stale cell metrics. Two signals, both needed:\n // - `fonts.ready` — resolves when the initial font loads settle. WebKit\n // fires this reliably; keep it for the common first-load case.\n // - `loadingdone` — fires on every later font-load batch (lazily\n // triggered @font-face, dynamically added styles).\n // Re-measuring is cheap and layout runs at most once per frame.\n document.fonts?.ready.then(this.#onFontsLoaded).catch((err: unknown) => {\n console.warn(\"[monowind] document.fonts.ready failed:\", err);\n });\n document.fonts?.addEventListener(\"loadingdone\", this.#onFontsLoaded);\n\n this.#scheduleLayout();\n }\n\n disconnectedCallback(): void {\n this.#resizeObserver?.disconnect();\n this.#mutationObserver?.disconnect();\n this.#resizeObserver = null;\n this.#mutationObserver = null;\n document.fonts?.removeEventListener(\"loadingdone\", this.#onFontsLoaded);\n // Invalidate metrics — if the element is re-connected somewhere else,\n // the surrounding font/size may differ.\n this.#cellMetrics = null;\n }\n\n #onFontsLoaded = (): void => {\n this.#cellMetrics = null; // font may have changed dimensions\n this.#scheduleLayout();\n };\n\n #isOwnedMutation = (record: MutationRecord): boolean => {\n if (record.type !== \"attributes\") return false;\n const name = record.attributeName;\n if (name === \"data-mw-laid-out\") return true;\n if (name === \"data-mw-ready\") return true;\n if (name === \"data-mw-text-align-blocked\") return true;\n if (name === \"data-mw-clip\") return true;\n if (name === \"data-mw-nowrap\") return true;\n // Style attribute mutations are hard to filter precisely from the record\n // alone (we can't tell which property was set). Rely on the counter that\n // brackets our write phase — if we're inside it, treat as owned.\n if (name === \"style\") return this.#suppressMutations > 0;\n return false;\n };\n\n #scheduleLayout(): void {\n if (this.#layoutPending) return;\n this.#layoutPending = true;\n requestAnimationFrame(() => {\n this.#layoutPending = false;\n try {\n this.#performLayout();\n } catch (err) {\n console.error(\"[monowind] layout failed:\", err);\n }\n });\n }\n\n #performLayout(): void {\n // The write phase is bracketed by (a) incrementing #suppressMutations\n // and (b) setting the `measuring` attribute. Anything the engine writes\n // to the light DOM during this phase — geometry vars, data-mw-*\n // attributes, decoration DOM — is either filtered by the counter or\n // drained via takeRecords() at the end. The counter can slightly\n // over-filter (a third-party script mutating in the same task would\n // also be swallowed); that's an accepted trade-off for MVP.\n this.#suppressMutations++;\n this.setAttribute(\"measuring\", \"\");\n try {\n // (1) Cell metrics — cached; invalidated by disconnected callback\n // (implicit) and by document.fonts.ready.\n if (!this.#cellMetrics) {\n this.#cellMetrics = measureCellMetrics(this);\n this.style.setProperty(\"--mw-cw\", `${this.#cellMetrics.width}px`);\n this.style.setProperty(\"--mw-ch\", `${this.#cellMetrics.height}px`);\n }\n const metrics = this.#cellMetrics;\n\n // (2) Available cells from host's padding-box (clientWidth, not\n // getBoundingClientRect().width — the former excludes any user-set\n // border/padding on the host itself).\n const availableCols = Math.max(0, Math.floor(this.clientWidth / metrics.width));\n if (availableCols === 0) return;\n\n // (3) Build a tree from the light DOM. Root is a virtual container\n // over the light-DOM children so we can lay them out as a block.\n const rootFontSizePx = getRootFontSizePx();\n const childNodes: LayoutNode[] = [];\n for (const child of Array.from(this.children)) {\n const node = buildTree(child, rootFontSizePx);\n if (node) childNodes.push(node);\n }\n if (childNodes.length === 0) {\n this.#decorations.replaceChildren();\n this.setAttribute(\"data-mw-ready\", \"\");\n return;\n }\n const virtualRoot: LayoutNode = {\n source: this,\n style: defaultCellStyle(),\n children: childNodes,\n text: \"\",\n intrinsicWidth: 0,\n intrinsicHeight: 0,\n localRect: { x: 0, y: 0, width: 0, height: 0 },\n unclampedHeight: 0,\n resolvedPadding: { top: 0, right: 0, bottom: 0, left: 0 },\n };\n\n // (4) Compute integer layout.\n const { height } = layoutRoot(virtualRoot, availableCols);\n\n // (5) Write geometry + paint decorations. Do this before clearing the\n // measuring attribute so the browser only paints the final state.\n render(virtualRoot, this.#decorations);\n\n // (6) Size the host to match content rows (content-driven height).\n this.style.height = `${height * metrics.height}px`;\n\n // (7) Reveal the host now that layout is done — kills the FOUC where\n // the browser paints raw flex/block layout before the engine runs.\n this.setAttribute(\"data-mw-ready\", \"\");\n } finally {\n this.removeAttribute(\"measuring\");\n // Flush pending mutation records that our own writes caused before\n // re-enabling observation. Microtask ordering isn't strictly\n // guaranteed here (see note at top of #performLayout).\n queueMicrotask(() => {\n this.#mutationObserver?.takeRecords();\n this.#suppressMutations--;\n });\n }\n }\n}\n\n/** Register the <mono-wind> element (idempotent). */\nexport function defineMonoWind(): void {\n if (customElements.get(\"mono-wind\")) return;\n customElements.define(\"mono-wind\", MonoWindElement);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"mono-wind\": MonoWindElement;\n }\n}\n","import { collectBorderRuns } from \"./borders.ts\";\nimport type { BorderRun } from \"./borders.ts\";\nimport { wrapLines } from \"./wrap.ts\";\nimport type { LayoutNode } from \"./types.ts\";\n\n/**\n * Render a laid-out tree as plain-text ASCII art: borders as box-drawing\n * glyphs, leaf text word-wrapped inside its content box, everything else as\n * spaces.\n *\n * This is the engine's \"screenshot without a browser\": deterministic,\n * font-independent, and diffable — used for golden regression tests and as\n * a debugging/agent-inspection tool. It intentionally renders geometry the\n * way the browser would paint it (same border-run and word-wrap code), minus\n * colors and fonts.\n *\n * Content that overflows the root box is clipped at the grid edges.\n */\nexport function renderAscii(root: LayoutNode): string {\n const width = root.localRect.width;\n const height = root.localRect.height;\n if (width <= 0 || height <= 0) return \"\";\n\n const grid: string[][] = Array.from({ length: height }, () =>\n Array.from({ length: width }, () => \" \"),\n );\n const put = (x: number, y: number, glyph: string) => {\n if (x >= 0 && x < width && y >= 0 && y < height) grid[y]![x] = glyph;\n };\n\n walk(root, 0, 0, put);\n\n return grid.map((row) => row.join(\"\").trimEnd()).join(\"\\n\");\n}\n\ntype PutGlyph = (x: number, y: number, glyph: string) => void;\n\nfunction walk(node: LayoutNode, parentAbsX: number, parentAbsY: number, put: PutGlyph): void {\n const absX = parentAbsX + node.localRect.x;\n const absY = parentAbsY + node.localRect.y;\n const style = node.style;\n\n const borderRuns: BorderRun[] = [];\n collectBorderRuns(\n style,\n { x: absX, y: absY, width: node.localRect.width, height: node.localRect.height },\n borderRuns,\n );\n for (const run of borderRuns) {\n for (let i = 0; i < run.length; i++) put(run.x + i, run.y, run.glyph);\n }\n\n if (node.children.length === 0 && node.text) {\n const padding = node.resolvedPadding;\n const contentX = absX + style.border.left + padding.left;\n const contentY = absY + style.border.top + padding.top;\n const contentWidth =\n node.localRect.width - style.border.left - style.border.right - padding.left - padding.right;\n const lines =\n style.whiteSpace === \"nowrap\"\n ? node.text.split(\"\\n\").map((line) => truncateLine(line, contentWidth, style))\n : wrapLines(node.text, contentWidth);\n for (let row = 0; row < lines.length; row++) {\n const line = lines[row]!;\n for (let col = 0; col < line.length; col++) {\n put(contentX + col, contentY + row, line[col]!);\n }\n }\n }\n\n for (const child of node.children) {\n walk(child, absX, absY, put);\n }\n}\n\n/**\n * Mirror of what the browser paints for a nowrap line: a clipping box cuts\n * it at the content width, with `…` in the last visible cell when\n * `text-overflow: ellipsis` is set. A non-clipping nowrap line is left\n * intact — like the browser, it overflows (the grid edge clips it).\n */\nfunction truncateLine(line: string, contentWidth: number, style: LayoutNode[\"style\"]): string {\n if (style.overflow !== \"clip\" || line.length <= contentWidth) return line;\n if (contentWidth <= 0) return \"\";\n if (style.textOverflow === \"ellipsis\") return `${line.slice(0, contentWidth - 1)}…`;\n return line.slice(0, contentWidth);\n}\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { LayoutNode } from "./types.ts";
2
+ /**
3
+ * Layout entry point: mutates localRect on the root and each descendant.
4
+ * Coordinates are parent-relative (root's rect is at 0,0).
5
+ */
6
+ export declare function layoutRoot(root: LayoutNode, availableWidth: number): {
7
+ height: number;
8
+ };
9
+ /**
10
+ * Resolve flex main-axis sizes per CSS Flexbox §9.7 ("Resolving Flexible
11
+ * Lengths"), adapted to integers: distribute free space proportionally to
12
+ * grow factors (or shrink weights = base × shrink), clamp each result to the
13
+ * item's own min/max, FREEZE the items whose clamp fired, and redistribute
14
+ * among the rest — repeating until nothing new violates. Without the
15
+ * redistribution rounds, an item clamped up to `min-w-*` would keep space
16
+ * its neighbors were already told they could use, and boxes would overlap.
17
+ *
18
+ * `min`/`max` are outer main sizes in cells, already resolved from percent.
19
+ * When clamps bind, the returned sizes may sum to less or more than
20
+ * `available` — that's CSS (`justify-content` sees the underfill; overflow
21
+ * handles the excess).
22
+ */
23
+ export declare function resolveFlexMainAxis(items: ReadonlyArray<{
24
+ intrinsic: number;
25
+ grow: number;
26
+ shrink: number;
27
+ min?: number | undefined;
28
+ max?: number | undefined;
29
+ }>, available: number): number[];
30
+ /**
31
+ * Distribute `total` integer units across N slots proportionally to `weights`,
32
+ * with the remainder (from flooring) given to the slots with the largest
33
+ * fractional part — deterministic, document order for ties.
34
+ */
35
+ export declare function distributeInteger(weights: number[], total: number): number[];
36
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,UAAU,EAIX,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIvF;AAgqBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B,CAAC,EACF,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CA+DV;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB5E"}
@@ -0,0 +1,11 @@
1
+ import type { CellMetrics } from "./types.ts";
2
+ /** Round to nearest integer, ties away from zero (per specs/cell-model.md). */
3
+ export declare function roundHalfAwayFromZero(value: number): number;
4
+ /** Convert a computed px value to cells using the spacing scale (1 cell = 0.25rem). */
5
+ export declare function pxToCells(px: number, rootFontSizePx: number): number;
6
+ /** Convert a percentage of an integer container to whole cells, ties away from zero. */
7
+ export declare function percentToCells(percent: number, containerCells: number): number;
8
+ /** Measure the width of a monospace character and the line-box height. */
9
+ export declare function measureCellMetrics(host: HTMLElement): CellMetrics;
10
+ export declare function getRootFontSizePx(): number;
11
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAejE;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -0,0 +1,9 @@
1
+ import type { LayoutNode } from "./types.ts";
2
+ /**
3
+ * Write geometry custom properties on each source element and (re)paint the
4
+ * decoration layer. Coordinates on LayoutNode are parent-relative; borders
5
+ * are painted in absolute coordinates so we accumulate the parent origin as
6
+ * we walk.
7
+ */
8
+ export declare function render(root: LayoutNode, decorationLayer: HTMLElement): void;
9
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAU,UAAU,EAAQ,MAAM,YAAY,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,GAAG,IAAI,CAI3E"}
@@ -0,0 +1,10 @@
1
+ import type { CellStyle } from "./types.ts";
2
+ /**
3
+ * Read the interpreted CellStyle for an element from its computed CSS.
4
+ *
5
+ * The host must have the `measuring` attribute set while this runs so the
6
+ * engine's own geometry rules (from styles.css) don't feed their outputs back
7
+ * into what we read.
8
+ */
9
+ export declare function readCellStyle(el: Element, rootFontSizePx: number): CellStyle;
10
+ //# sourceMappingURL=style.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../src/style.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,SAAS,EAMV,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,SAAS,CAkF5E"}
package/dist/tree.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { LayoutNode } from "./types.ts";
2
+ /**
3
+ * Build a LayoutNode tree from an element subtree.
4
+ *
5
+ * Rules:
6
+ * - Elements with computed `display: none` are skipped entirely.
7
+ * - An element becomes a **leaf** if it has no element children, or if all
8
+ * its element children have computed `display: inline`/`inline-*`/`contents`
9
+ * (they're part of the inline text flow, not laid out separately). The
10
+ * leaf's `text` is the element's combined `textContent`, so text nodes
11
+ * interleaved with inline elements (`<div>hello <span>world</span></div>`)
12
+ * participate in the wrap calculation and render correctly.
13
+ * - Elements with at least one block-level element child become **containers**
14
+ * and recurse. Direct text nodes on containers (uncommon in utility-first
15
+ * markup) are not laid out — CSS creates anonymous inline boxes for them,
16
+ * but our absolutely-positioned children escape that flow. This is
17
+ * documented as a deviation in specs/cell-model.md.
18
+ */
19
+ export declare function buildTree(root: Element, rootFontSizePx: number): LayoutNode | null;
20
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA8ClF"}
@@ -0,0 +1,151 @@
1
+ export interface Rect {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface Insets {
8
+ top: number;
9
+ right: number;
10
+ bottom: number;
11
+ left: number;
12
+ }
13
+ /** Insets where any side can be `null` to signal `auto` (used for margins). */
14
+ export interface NullableInsets {
15
+ top: number | null;
16
+ right: number | null;
17
+ bottom: number | null;
18
+ left: number | null;
19
+ }
20
+ export type Size = {
21
+ kind: "cells";
22
+ value: number;
23
+ } | {
24
+ kind: "percent";
25
+ value: number;
26
+ } | {
27
+ kind: "auto";
28
+ }
29
+ /** Intrinsic sizing keywords (`w-min` / `w-max` / `w-fit`). Resolved
30
+ * against content: min-content = longest unbreakable unit, max-content =
31
+ * unwrapped size, fit-content = shrink-to-fit within the available space.
32
+ * Only honored for `width`; on `height` they behave as `auto` (content
33
+ * height already is the intrinsic height). */
34
+ | {
35
+ kind: "min-content";
36
+ } | {
37
+ kind: "max-content";
38
+ } | {
39
+ kind: "fit-content";
40
+ };
41
+ export type Display = "block" | "flex" | "grid" | "none";
42
+ export type FlexDirection = "row" | "column";
43
+ export type FlexWrap = "nowrap" | "wrap";
44
+ export type JustifyContent = "start" | "center" | "end" | "space-between" | "space-around" | "space-evenly";
45
+ export type AlignItems = "start" | "center" | "end" | "stretch";
46
+ export type AlignSelf = "auto" | "start" | "center" | "end" | "stretch";
47
+ export type BorderStyle = "solid" | "double" | "dashed" | "dotted";
48
+ export type Overflow = "visible" | "clip";
49
+ export type WhiteSpace = "normal" | "nowrap";
50
+ /** A length in whole cells, or a percentage kept symbolic until layout.
51
+ * Percentages resolve against the CSS-appropriate basis at layout time:
52
+ * the available extent for min/max (`max-w-full` = 100%), the containing
53
+ * block's WIDTH for padding and margins (all four sides, per CSS), and the
54
+ * container's own content box in the gap's axis for gaps. */
55
+ export type CellLength = number | {
56
+ percent: number;
57
+ };
58
+ export type TextOverflow = "clip" | "ellipsis";
59
+ /** One value per box edge (border style, border color, …). */
60
+ export interface PerSide<T> {
61
+ top: T;
62
+ right: T;
63
+ bottom: T;
64
+ left: T;
65
+ }
66
+ export interface CellStyle {
67
+ display: Display;
68
+ flexDirection: FlexDirection;
69
+ /** True for `row-reverse` / `column-reverse`: the main axis runs
70
+ * backwards — items lay out in reverse order and `justify-content`
71
+ * start/end swap meaning. */
72
+ flexReverse: boolean;
73
+ flexWrap: FlexWrap;
74
+ /** True for `wrap-reverse`: lines stack from the cross-end (bottom-up). */
75
+ wrapReverse: boolean;
76
+ flexGrow: number;
77
+ flexShrink: number;
78
+ /** CSS `flex-basis`: the flex base size when not `auto`/undefined —
79
+ * notably `0%` from Tailwind's `flex-1`, which makes grow distribute ALL
80
+ * the space (equal columns) instead of just the extra. */
81
+ flexBasis: Size | undefined;
82
+ /** CSS `order` — flex items sort by it (stable, document order ties). */
83
+ order: number;
84
+ justifyContent: JustifyContent;
85
+ alignItems: AlignItems;
86
+ alignSelf: AlignSelf;
87
+ width: Size | undefined;
88
+ height: Size | undefined;
89
+ /** `"auto"` is CSS `min-width/height: auto`: 0 in block flow, but a flex
90
+ * item's automatic minimum (its min-content size, when overflow is
91
+ * visible) on the flex main axis — the reason text in a flex row stops
92
+ * shrinking instead of vanishing, and why `min-w-0` exists. */
93
+ minWidth: CellLength | "auto";
94
+ minHeight: CellLength | "auto";
95
+ maxWidth: CellLength | undefined;
96
+ maxHeight: CellLength | undefined;
97
+ padding: PerSide<CellLength>;
98
+ /** `null` = `auto`. Percentages resolve against the parent's content
99
+ * width where the margin is consumed. */
100
+ margin: PerSide<CellLength | null>;
101
+ gapX: CellLength;
102
+ gapY: CellLength;
103
+ border: Insets;
104
+ borderStyle: PerSide<BorderStyle>;
105
+ borderColor: PerSide<string | undefined>;
106
+ overflow: Overflow;
107
+ /** `nowrap` disables soft wrapping (hard `<br>` breaks still apply). */
108
+ whiteSpace: WhiteSpace;
109
+ /** Paint-only: with `nowrap` + clipping, the browser draws the ellipsis.
110
+ * The engine only needs it for the ASCII renderer's mirror of that. */
111
+ textOverflow: TextOverflow;
112
+ /**
113
+ * Paint-only colors, reserved for the visual-system milestone. `color` will
114
+ * feed decoration glyphs that visually belong to the text (control framing
115
+ * like `[ Save ]`, cursors, selection carets); `backgroundColor` will feed
116
+ * cell-level highlights (selection ranges, decoration backgrounds). Read
117
+ * from the source element now so the future work has the data available.
118
+ */
119
+ color: string | undefined;
120
+ backgroundColor: string | undefined;
121
+ /** True when text-align is center/justify — forced back to `start` since
122
+ * per-line centering can't be snapped to whole cells. See cell-model spec. */
123
+ textAlignBlocked: boolean;
124
+ }
125
+ export interface LayoutNode {
126
+ source: Element;
127
+ style: CellStyle;
128
+ children: LayoutNode[];
129
+ /** Raw text content of the element's direct text nodes (leaves only). Empty
130
+ * for pure containers. May coexist with child element nodes when the
131
+ * element has mixed text+element children. */
132
+ text: string;
133
+ intrinsicWidth: number;
134
+ intrinsicHeight: number;
135
+ localRect: Rect;
136
+ /** Outer height before min/max clamping — written by layoutNode; the
137
+ * column flex algorithm's base main size (CSS distributes from unclamped
138
+ * bases; limits apply via its freeze loop). */
139
+ unclampedHeight: number;
140
+ /** Padding with percentages resolved to cells — written by layoutNode
141
+ * (percent resolves against the containing block width, which only
142
+ * layout knows); the renderers read this, never `style.padding`. */
143
+ resolvedPadding: Insets;
144
+ }
145
+ export interface CellMetrics {
146
+ width: number;
147
+ height: number;
148
+ }
149
+ export declare function defaultCellStyle(): CellStyle;
150
+ export declare function zeroInsets(): Insets;
151
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}