UNPKG

modern-text

Version:

Measure and render text in a way that describes the DOM.

244 lines (226 loc) 11 kB
import { P as Plugin, T as TextMeasurer, a as Paragraph, M as MeasurerResult, C as Character, O as Options, b as MeasureResult, R as RenderOptions, c as Text } from './shared/modern-text.DzKfafj6.mjs'; export { d as Canvas2DRenderer, D as DrawShapePathsOptions, F as Fragment, e as TextEvents, t as textDefaultStyle } from './shared/modern-text.DzKfafj6.mjs'; import { Fonts } from 'modern-font'; import { FullStyle, NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc'; import { BoundingBox, Vector2, Path2DSet, Transform2D } from 'modern-path2d'; import { D as DeformationPreset } from './shared/modern-text.C2l8Y0PX.mjs'; export { B as BendContext, a as BendPreset, C as CurvePreset, b as DeformationCharInfo, c as DeformationCurve, F as FfdContext, d as FfdPreset, O as OffsetPreset, V as VerbatimContext } from './shared/modern-text.C2l8Y0PX.mjs'; declare function definePlugin(options: Plugin): Plugin; /** * The pure-JS, DOM-free text measurer (the only built-in backend). * * It computes the four-level boxes (`character.inlineBox`/`lineBox`, `fragment.inlineBox`, * `paragraph.lineBox`) directly from `modern-font` glyph advances + kerning — no DOM, so it * runs in Node/SSR/Worker and measures the *exact* font that is rendered (advances come from * the same SFNT the glyph paths do, so layout and rendering are pixel-consistent by construction). * * ## Scope * - `horizontal-tb` (LTR) and `vertical-rl` (columns right-to-left, glyphs top↓) * - line breaking: `word-break: break-all` (greedy, break anywhere) + explicit `\n` * - per-line `text-align` (start/left/center/end/right), `text-indent` (first line) * - box model: root + paragraph `padding`/`margin` (horizontal), `letter-spacing`, * `line-height`; block `vertical-align` (top/middle/bottom) at fixed height * - pair kerning (GPOS `kern` feature / legacy `kern` table) folded into break + positioning * * ## Not yet implemented (TODO) * - UAX#14 `word-break: normal` + 避头尾/kinsoku (`line-break`) * - BiDi, per-fragment inline `vertical-align`, borders * - vertical: per-paragraph margin/padding and block alignment * - ligatures (GSUB) — fine for CJK and most UI Latin * * Coordinates are relative to the root border-box top-left. */ declare class Measurer implements TextMeasurer { measure(paragraphs: Paragraph[], rootStyle: FullStyle, _dom?: HTMLElement, fonts?: Fonts): MeasurerResult; protected _rootPadding(rootStyle: FullStyle): { top: number; right: number; bottom: number; left: number; }; protected _measureHorizontal(paragraphs: Paragraph[], rootStyle: FullStyle): MeasurerResult; /** * Vertical writing-mode (`vertical-rl`): columns stack right-to-left, glyphs * flow top→bottom. It is the horizontal layout with the inline and block axes * swapped — the inline (down-column) advance is `advanceWidth` (CJK upright = em; * Latin is rotated, so its advance ≈ its width), the cross-axis content box is * `advanceHeight`, and the column thickness is `fontHeight`. The lineBox stays * accurate even though inlineBox carries the content-box rounding residual. * * v1: `vertical-rl` only; no per-paragraph margin/padding or block alignment. */ protected _measureVertical(paragraphs: Paragraph[], rootStyle: FullStyle): MeasurerResult; /** Advance step including CSS letter-spacing (px). */ protected _advance(character: Character): number; /** * Break a paragraph's characters into visual lines. * v1: `word-break: break-all` (break before any character that would overflow) * plus explicit `\n`/`\r` hard breaks. The newline itself occupies no line box. */ protected _breakLines(paragraph: Paragraph, avail: number): Character[][]; protected _applyKerning(paragraphs: Paragraph[]): void; protected _unionInto(target: BoundingBox, boxes: BoundingBox[]): void; protected _shiftAll(paragraphs: Paragraph[], dy: number): void; dispose(): void; } declare function measureText(options: Options, load: true): Promise<MeasureResult>; declare function measureText(options: Options): MeasureResult; type RenderTextOptions = Options & RenderOptions; declare function renderText(options: RenderTextOptions, load: true): Promise<void>; declare function renderText(options: RenderTextOptions): void; declare function backgroundPlugin(): Plugin; /** * 这些曲线类用于「逐字(-by-word)」沿形状排布文字。 * * 旧版变形代码针对 `modern-path2d@0.2.5` 编写,该版本内置了 * `CircleCurve` / `EllipseCurve` / `HeartCurve` / `PolygonCurve` / `RectangularCurve`, * 当前版本(1.6.x)已不再导出。这里从 0.2.5 原样移植其实现, * 仅做 Vector2 API 适配(`copy`→`copyFrom`、`new Vector2().lerpVectors`→`Vector2.lerp`), * 以保证逐字排布效果与原版一致。 * * 仅保留 deformer 实际用到的方法:getPoint / getPointAt / getTangent / getNormal。 */ declare abstract class ShapeCurve { arcLengthDivisions: number; protected _cacheArcLengths?: number[]; protected _needsUpdate: boolean; abstract getPoint(t: number, output?: Vector2): Vector2; getPointAt(u: number, output?: Vector2): Vector2; getLength(): number; getLengths(divisions?: number): number[]; getUToTMapping(u: number, distance?: number): number; getTangent(t: number, output?: Vector2): Vector2; getNormal(t: number, output?: Vector2): Vector2; } /** * 分段曲线基类:由若干子曲线拼成,`getCurve(t)` 选中子曲线并把 `curveT` 设为其局部参数, * 其余取点/切线/法线统一委托给选中的子曲线。 */ declare abstract class SegmentedCurve extends ShapeCurve { protected curveT: number; abstract getCurve(t: number): ShapeCurve; getPoint(t: number, output?: Vector2): Vector2; getPointAt(u: number, output?: Vector2): Vector2; getTangent(t: number, output?: Vector2): Vector2; getNormal(t: number, output?: Vector2): Vector2; } declare class LineShapeCurve extends ShapeCurve { start: Vector2; end: Vector2; constructor(start: Vector2, end: Vector2); getPoint(t: number, output?: Vector2): Vector2; getPointAt(u: number, output?: Vector2): Vector2; getTangent(_t: number, output?: Vector2): Vector2; } declare class CircleCurve extends ShapeCurve { center: Vector2; radius: number; start: number; end: number; constructor(center: Vector2, radius: number, start?: number, end?: number); getPoint(t: number, output?: Vector2): Vector2; getTangent(t: number, output?: Vector2): Vector2; getNormal(t: number, output?: Vector2): Vector2; } declare class EllipseCurve extends ShapeCurve { center: Vector2; radiusX: number; radiusY: number; rotation: number; startAngle: number; endAngle: number; clockwise: boolean; constructor(center?: Vector2, radiusX?: number, radiusY?: number, rotation?: number, startAngle?: number, endAngle?: number, clockwise?: boolean); getPoint(t: number, output?: Vector2): Vector2; } declare class HeartCurve extends SegmentedCurve { center: Vector2; size: number; start: number; end: number; protected curves: ShapeCurve[]; constructor(center: Vector2, size: number, start?: number, end?: number); update(): this; getCurve(t: number): ShapeCurve; } declare class PolygonCurve extends SegmentedCurve { center: Vector2; radius: number; number: number; start: number; end: number; protected curves: LineShapeCurve[]; protected points: Vector2[]; constructor(center: Vector2, radius?: number, number?: number, start?: number, end?: number); update(): this; getCurve(t: number): LineShapeCurve; } declare class RectangularCurve extends SegmentedCurve { center: Vector2; rx: number; aspectRatio: number; start: number; end: number; protected curves: LineShapeCurve[]; constructor(center: Vector2, rx: number, aspectRatio?: number, start?: number, end?: number); update(): this; getCurve(t: number): LineShapeCurve; } /** * 注册一个变形预设(库外部定义,运行时透传)。 * 官方预设包见子入口 `modern-text/deformations`。 */ declare function defineDeformation(name: string, preset: DeformationPreset): void; /** 取消注册某个预设 */ declare function removeDeformation(name: string): void; /** 当前已注册的预设名列表 */ declare function getDeformationNames(): string[]; /** * 文字变形插件(纯引擎)。 * * 通过 `text.deformation` 指定**已注册**的预设名: * ```ts * import { registerDeformations } from 'modern-text/deformations' * registerDeformations() * new Text({ content: 'abc', deformation: { type: 'bend', intensities: [50] } }) * ``` */ declare function deformationPlugin(): Plugin; declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight; declare function highlightPlugin(): Plugin; declare function listStylePlugin(): Plugin; declare function outlinePlugin(): Plugin; declare function renderPlugin(): Plugin; declare function textDecorationPlugin(): Plugin; interface SvgLoader { loaded: Map<string, string>; needsLoad: (source: string) => boolean; load: (svg: string) => Promise<void>; } declare function createSvgLoader(): SvgLoader; interface SvgParser { parsed: Map<string, { dom: SVGElement; pathSet: Path2DSet; }>; parse: (svg: string) => { dom: SVGElement; pathSet: Path2DSet; }; } declare function createSvgParser(loader: SvgLoader): SvgParser; declare function getEffectTransform2D(text: Text, effect: NormalizedEffect): Transform2D; declare function parseTransformOrigin(origin: string, left: number, top: number, width: number, height: number): { x: number; y: number; }; interface ValueContext { total: number; fontSize: number; } declare function parseValueNumber(value: string | number, ctx: ValueContext): number; declare function parseColormap(colormap: 'none' | Record<string, string>): Record<string, string>; declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean; declare function isEqualValue(val1: any, val2: any): boolean; export { Character, CircleCurve, DeformationPreset, EllipseCurve, HeartCurve, MeasureResult, Measurer, MeasurerResult, Options, Paragraph, Plugin, PolygonCurve, RectangularCurve, RenderOptions, Text, TextMeasurer, backgroundPlugin, createSvgLoader, createSvgParser, defineDeformation, definePlugin, deformationPlugin, getDeformationNames, getEffectTransform2D, getHighlightStyle, highlightPlugin, isEqualObject, isEqualValue, listStylePlugin, measureText, outlinePlugin, parseColormap, parseTransformOrigin, parseValueNumber, removeDeformation, renderPlugin, renderText, textDecorationPlugin }; export type { RenderTextOptions, SvgLoader, SvgParser };