Skip to content

Text Measurement

The text module provides a pipeline for measuring text dimensions using the Canvas API. This is useful for components that need to know text size before rendering (e.g., auto-sizing containers, virtual lists, chart labels).

prepare(text, font)

Measure a text string with a given CSS font and return a PreparedText handle:

tsx
import { prepare } from "@hedystia/view";

const measured = prepare("Hello, world!", "16px sans-serif");

The PreparedText object stores the text, font, and measured dimensions internally.

layout(prepared, maxWidth, lineHeight)

Compute line-wrapping layout for prepared text at a given width:

tsx
import { prepare, layout } from "@hedystia/view";

const text = prepare("A long paragraph of text...", "14px Arial");
const result = layout(text, 300, 20);

console.log(result.lineCount); // number of wrapped lines
console.log(result.height);    // total height in pixels

LayoutResult

tsx
interface LayoutResult {
  lineCount: number;
  height: number;
}

reactiveLayout(source, getPrepared, maxWidth, lineHeight)

Create a reactive memo that recomputes layout when the source changes:

tsx
import { sig, val, set, reactiveLayout, prepare, mount } from "@hedystia/view";

interface TextItem {
  content: string;
  font: string;
}

function TextPreview() {
  const [item, setItem] = sig<TextItem>({ content: "Hello, world!", font: "16px sans-serif" });
  const [width, setWidth] = sig(300);

  const result = reactiveLayout(
    item,
    (i) => prepare(i.content, i.font),
    width(),
    20,
  );

  return (
    <div>
      <input
        type="range"
        min="100"
        max="600"
        value={width}
        onInput={(e) => setWidth(Number((e.target as HTMLInputElement).value))}
      />
      <p>Width: {width}px</p>
      <p>Lines: {() => result().lineCount}</p>
      <p>Height: {() => result().height}px</p>
      <div
        style={() => ({
          width: `${width()}px`,
          border: "1px solid #ccc",
          padding: "8px",
          font: item().font,
        })}
      >
        {() => item().content}
      </div>
    </div>
  );
}

mount(TextPreview, document.getElementById("root")!);