@abmaelsouza/pretext-styled-renderer
v1.0.2-build.2437134747
Published
Headless text layout engine for TypeScript and JavaScript. Supports text measurement, line breaking, hyphenation, and rich text rendering without relying on the DOM.
Maintainers
Readme
@abmaelsouza/pretext-styled-renderer
A high-performance, framework-agnostic rich-text rendering engine for TypeScript. It performs layout calculations entirely outside the DOM, making it compatible with any environment that provides a DOM (React, Vue, Svelte, Angular, or Vanilla JS). It provides pixel-perfect text wrapping, rich styling support, and a comprehensive Query API for inspecting layout metrics without relying on getBoundingClientRect.
Features
- 🚀 Zero-DOM Layout: Calculates line breaks and fragment positions using a canvas-like measurement engine.
- 🎨 Rich Styling per Span: Apply unique fonts, weights, colors, and backgrounds to any text fragment.
- 📏 Programmatic Metrics: Query bounding boxes for the total block, individual lines, or text fragments.
- ⌨️ Hit-Testing: Determine which line or fragment exists at a specific coordinate.
- 🔠 Smart Hyphenation: Built-in syllable-aware hyphenation logic.
- ⚡ Performance: Highly optimized for dynamic layouts and frequent resizing.
Installation
npm install @abmaelsouza/pretext-styled-rendererQuick Start
1. Initialize the Engine
import { PretextStyledEngine, type StyledSpan } from '@abmaelsouza/pretext-styled-renderer';
const engine = new PretextStyledEngine({
outerPaddingPx: 20,
defaultStyle: {
fontSize: 18,
fontFamily: 'system-ui, sans-serif',
lineHeight: 1.4,
color: '#1e293b'
}
});2. Define Styled Spans
const spans: StyledSpan[] = [
{ text: 'Hello ', style: { fontWeight: 'bold', color: 'blue' } },
{ text: 'World!', style: { fontStyle: 'italic', backgroundColor: '#f0f0f0' } }
];3. Calculate Layout & Sync to DOM
// Perform the layout calculation (no DOM used here)
engine.layout(spans, 400); // 400px width
// Sync the results to a container element
const container = document.getElementById('text-container');
engine.syncDom(container);Responsive Layout (Handling Resizes)
The engine calculates layout based on a fixed width. To make the text responsive, you must recalibrate the layout and call syncDom whenever the container size changes.
Using ResizeObserver (Recommended)
This is the most efficient way to detect when the actual container element changes size.
const container = document.getElementById('text-container');
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const newWidth = entry.contentRect.width;
// Recalculate and update the DOM
engine.layout(spans, newWidth);
engine.syncDom(container);
}
});
observer.observe(container);Using Window Resize
For simpler layouts, you can listen to the window's resize event.
window.addEventListener('resize', () => {
const newWidth = container.clientWidth;
engine.layout(spans, newWidth);
engine.syncDom(container);
});The Query API (Layout Metrics)
The engine provides a set of methods to inspect the rendered content programmatically. This is useful for drawing overlays, implementing custom selections, or hit-testing.
| Method | Description |
| :--- | :--- |
| getTotalRect() | Returns the {x, y, width, height} of the entire text block. |
| getLineRect(row) | Returns the bounding box of a specific line index. |
| getFragmentRects(row) | Returns an array of bounding boxes for every styled fragment in a line. |
| getLineAtHeight(y) | Returns the index of the line located at a specific vertical offset. |
| getLineWidths() | Returns an array of widths for every rendered line. |
| getLineText(row) | Returns the raw string content of a specific line. |
| getFullText() | Returns the entire concatenated text content. |
Styling Options (TextStyle)
Every StyledSpan can be customized with the following properties:
fontSize: Number (px) or String (e.g.,'18px')fontFamily: Font family stack (e.g.,'Inter, sans-serif')fontWeight:'normal','bold', or numeric values like600.fontStyle:'normal','italic', or'oblique'.lineHeight: Multiplier (e.g.,1.5) or pixel value.color: CSS color string.backgroundColor: CSS background-color string.letterSpacing: CSS-like letter-spacing (e.g.,'0.5px').textAlign:'left','center','right'.textDecoration:'none','underline','line-through'.opacity: Number between0and1.
License
MIT
