Iterate over line geometry without building line text strings. Ideal for shrinkwrap layouts.
walkLineRanges() iterates over lines at a fixed max width, calling onLine once per line with the line’s width and start/end cursors — but without materializing the line text strings. Use it for geometry-only work such as shrinkwrap, balanced text, or binary-search over widths.
import { prepareWithSegments, walkLineRanges, layoutWithLines } from '@chenglou/pretext'const prepared = prepareWithSegments(text, '16px Inter')// Find the tightest container width that still fits the text (shrinkwrap)let maxW = 0walkLineRanges(prepared, 320, line => { if (line.width > maxW) maxW = line.width})// maxW is now the widest line — the minimum container width for this text
Maximum line width in pixels. All lines use this same width. Call walkLineRanges() repeatedly with different widths to probe geometry before committing.
Find the minimum container width that still fits all lines:
let maxW = 0walkLineRanges(prepared, 320, line => { if (line.width > maxW) maxW = line.width})// maxW is now the widest line — the tightest container width that still fits the text
This enables multiline shrink-wrap that has historically been missing from the web platform.
Probe multiple candidate widths cheaply, then call layoutWithLines() once with the final width:
let lo = 0let hi = maxWidth// Binary search for smallest width where the text fits in 3 lines or fewerwhile (hi - lo > 1) { const mid = Math.floor((lo + hi) / 2) const lineCount = walkLineRanges(prepared, mid, () => {}) if (lineCount <= 3) hi = mid else lo = mid}// Now materialize lines at the chosen widthconst { lines } = layoutWithLines(prepared, hi, lineHeight)
Call walkLineRanges() repeatedly to probe widths, then call layoutWithLines() once with the final width to get the actual line text. This avoids string materialization during the search.