Об этом проекте

Pretext — это чистая библиотека JavaScript/TypeScript для измерения многострочного текста и вычисления разметки строк. Она избегает DOM-API измерения, таких как `getBoundingClientRect` и `offsetHeight`, которые вызывают принудительный reflow, и вместо этого выполняет собственное измерение, используя браузерный canvas `measureText` как эталон. Это делает её полезной для виртуализации, пользовательских движков разметки, рендеринга в canvas/SVG и проверок переполнения во время разработки. ## Установка ```sh npm install @chenglou/pretext ``` ## Основные сценарии использования ### 1. Измерение высоты абзаца без обращения к DOM ```ts import { prepare, layout } from '@chenglou/pretext' const prepared = prepare('AGI 春天到了. بدأت الرحلة 🚀', '16px Inter') const { height, lineCount } = layout(prepared, 320, 20) ``` `prepare()` выполняет однократную работу: нормализацию пробелов, сегментацию текста, применение правил склейки и измерение на основе canvas. Затем `layout()` — это дешёвая чисто арифметическая операция над кэшированными ширинами, поэтому её можно повторно запускать при изменении размера без повторной подготовки. Опции для `prepare()` включают `whiteSpace: 'pre-wrap'` для поведения, похожего на textarea, `wordBreak: 'keep-all'` для CSS-подобного `word-break: keep-all` и `letterSpacing` для CSS `letter-spacing`. ### 2. Ручная разметка строк `prepareWithSegments()` возвращает более богатую структуру для пользовательской разметки. Доступны следующие API: - `layoutWithLines()` — возвращает все строки при фиксированной максимальной ширине, включая текст и измеренные ширины. - `walkLineRanges()` — вызывает callback для каждой строки с шириной и начальным/конечным курсорами, без построения строк. - `measureLineStats()` — возвращает количество строк и ширину самой широкой строки без аллокаций. - `measureNaturalWidth()` — возвращает ширину самой широкой принудительной строки, когда ширина не является причиной переноса. - `layoutNextLine()` / `layoutNextLineRange()` — API в стиле итератора для разметки строк по одной с потенциально разными ширинами, полезные для обтекания текстом плавающих элементов или динамических контейнеров. - `materializeLineRange()` — преобразует диапазон разметки обратно в полную строку. Это позволяет выполнять рендеринг в Canvas, SVG, WebGL и в перспективе в серверных средах. Демо включены в репозиторий и доступны на chenglou.me/pretext. ## Помощник для rich inline Отдельный помощник в `@chenglou/pretext/rich-inline` поддерживает базовый inline-поток rich-text со смешанными шрифтами, атомарными элементами (например, чипами и упоминаниями) и дополнительной шириной, задаваемой вызывающей стороной, для оформления pill-элементов. Он намеренно узкий: только inline, только `white-space: normal`, и это не универсальный движок форматирования CSS inline. ## Основные пункты глоссария API - `PreparedText` — непрозрачный быстрый дескриптор; `PreparedTextWithSegments` — более богатый дескриптор для ручной разметки. - `LayoutCursor` использует индексы сегментов/графем, а не смещения в исходной строке. - `layout()` для пустой строки возвращает `{ lineCount: 0, height: 0 }`; браузеры задают пустым блокам размер в один `line-height`, поэтому вызывающей стороне может потребоваться ограничение. - Мягкие переносы поддерживаются: они действуют как необязательные точки переноса и материализуются как завершающий `-`, когда выбираются. - `clearCache()` очищает общие внутренние кэши; `setLocale()` задаёт локаль для будущих вызовов подготовки. - Более богатый дескриптор включает приблизительные `segLevels` для пользовательского bidi-осведомлённого рендеринга, но Pretext не реализует полный Unicode Bidirectional Algorithm. ## Ограничения Pretext не является полноценным движком рендеринга шрифтов. Он нацелен на распространённые конфигурации CSS-текста: - `white-space: normal` и `pre-wrap` - `word-break: normal` и `keep-all` - `overflow-wrap: break-word` - `line-break: auto` - `letter-spacing` как числовое значение в пикселях - Табы следуют значению по умолчанию `tab-size: 8` Заметные ограничения: - `system-ui` и `-apple-system` небезопасны на macOS для точности `layout()`; рекомендуется именованный шрифт. - Эмодзи рядом с пунктуацией могут переноситься иначе, чем в браузере. - Некоторые шрифты, например Shantell Sans, могут давать другие переносы строк в длинных словах. - Во время выполнения требуются `Intl.Segmenter`, измерение текста через Canvas 2D и Unicode property escapes. - Возможности CSS-шрифтов за пределами сокращённой записи `font` для canvas не моделируются отдельно. В целом Pretext позиционируется как специализированная библиотека для измерения многострочного текста, дающая веб-разработчикам быструю и детерминированную альтернативу запросам к разметке браузера.