modern-text 1.11.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +283 -22
  2. package/dist/deformations/index.cjs +566 -0
  3. package/dist/deformations/index.d.cts +11 -0
  4. package/dist/deformations/index.d.mts +11 -0
  5. package/dist/deformations/index.d.ts +11 -0
  6. package/dist/deformations/index.mjs +563 -0
  7. package/dist/index.cjs +15 -3
  8. package/dist/index.d.cts +186 -6
  9. package/dist/index.d.mts +186 -6
  10. package/dist/index.d.ts +186 -6
  11. package/dist/index.js +6 -5
  12. package/dist/index.mjs +4 -2
  13. package/dist/shared/modern-text.B2xfrqDc.cjs +556 -0
  14. package/dist/shared/modern-text.BD7PBYt7.d.cts +100 -0
  15. package/dist/shared/modern-text.BxijkspX.d.ts +100 -0
  16. package/dist/shared/{modern-text.BKZQdmgG.cjs → modern-text.CBgc-cQ1.cjs} +288 -18
  17. package/dist/shared/modern-text.CYa4lfoG.d.mts +100 -0
  18. package/dist/shared/{modern-text.Dqw5Z6MV.mjs → modern-text.ChzjFjsk.mjs} +283 -13
  19. package/dist/shared/{modern-text.Db7Uoht6.d.cts → modern-text.D4WopQCu.d.cts} +56 -22
  20. package/dist/shared/{modern-text.Db7Uoht6.d.mts → modern-text.D4WopQCu.d.mts} +56 -22
  21. package/dist/shared/{modern-text.Db7Uoht6.d.ts → modern-text.D4WopQCu.d.ts} +56 -22
  22. package/dist/shared/modern-text.JF1ny7A-.mjs +550 -0
  23. package/dist/shared/modern-text.MC5bIC9E.cjs +316 -0
  24. package/dist/shared/modern-text.fT17R5HY.mjs +310 -0
  25. package/dist/web-components/index.cjs +2 -1
  26. package/dist/web-components/index.d.cts +1 -1
  27. package/dist/web-components/index.d.mts +1 -1
  28. package/dist/web-components/index.d.ts +1 -1
  29. package/dist/web-components/index.mjs +2 -1
  30. package/package.json +12 -7
package/dist/index.d.cts CHANGED
@@ -1,11 +1,72 @@
1
- import { h as Plugin, O as Options, b as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.Db7Uoht6.cjs';
2
- export { C as Canvas2DRenderer, a as Character, D as DrawShapePathsOptions, F as Fragment, M as MeasureDomResult, c as MeasuredCharacter, d as MeasuredCharacterRect, e as MeasuredFragment, f as MeasuredParagraph, g as Measurer, P as Paragraph, i as TextEvents, t as textDefaultStyle } from './shared/modern-text.Db7Uoht6.cjs';
3
- import { NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
4
- import { Path2DSet, Transform2D } from 'modern-path2d';
5
- import 'modern-font';
1
+ import { i as Plugin, k as TextMeasurer, P as Paragraph, M as MeasureDomResult, a as Character, O as Options, c as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.D4WopQCu.cjs';
2
+ export { C as Canvas2DRenderer, D as DomMeasurer, b as DrawShapePathsOptions, F as Fragment, d as MeasuredCharacter, e as MeasuredCharacterRect, f as MeasuredFragment, g as MeasuredParagraph, h as MeasurerKind, j as TextEvents, t as textDefaultStyle } from './shared/modern-text.D4WopQCu.cjs';
3
+ import { Fonts } from 'modern-font';
4
+ import { FullStyle, NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
5
+ import { BoundingBox, Vector2, Path2DSet, Transform2D } from 'modern-path2d';
6
+ import { c as DeformationPreset } from './shared/modern-text.BD7PBYt7.cjs';
7
+ export { B as BendContext, a as BendPreset, C as CurvePreset, D as DeformationCharInfo, b as DeformationCurve, F as FfdContext, d as FfdPreset, O as OffsetPreset, V as VerbatimContext } from './shared/modern-text.BD7PBYt7.cjs';
6
8
 
7
9
  declare function definePlugin(options: Plugin): Plugin;
8
10
 
11
+ /**
12
+ * Pure-JS, DOM-free text measurer — a drop-in alternative to {@link DomMeasurer}.
13
+ *
14
+ * Instead of mounting a `<section>/<ul>/<li>/<span>` tree and reading
15
+ * `getBoundingClientRect()`, it computes the same four-level boxes
16
+ * (`character.inlineBox`/`lineBox`, `fragment.inlineBox`, `paragraph.lineBox`)
17
+ * from `modern-font` glyph advances, so the downstream
18
+ * measure → glyph → plugin pipeline is unchanged and it runs in Node/SSR/Worker.
19
+ *
20
+ * ## Scope
21
+ * - `horizontal-tb` (LTR) and `vertical-rl` (columns right-to-left, glyphs top↓)
22
+ * - line breaking: `word-break: break-all` (greedy, break anywhere) + explicit `\n`
23
+ * - per-line `text-align` (start/left/center/end/right), `text-indent` (first line)
24
+ * - box model: root + paragraph `padding`/`margin` (horizontal), `letter-spacing`,
25
+ * `line-height`; block `vertical-align` (top/middle/bottom) at fixed height
26
+ *
27
+ * ## Not yet implemented (TODO)
28
+ * - UAX#14 `word-break: normal` + 避头尾/kinsoku (`line-break`)
29
+ * - BiDi, per-fragment inline `vertical-align`, borders
30
+ * - vertical: per-paragraph margin/padding and block alignment
31
+ * - kerning/ligatures (GSUB/GPOS) — fine for CJK, diverges for proportional Latin
32
+ *
33
+ * Coordinates are relative to the root border-box top-left (matching the DOM
34
+ * measurer, whose rects are taken relative to `section.getBoundingClientRect()`).
35
+ */
36
+ declare class FontMeasurer implements TextMeasurer {
37
+ measure(paragraphs: Paragraph[], rootStyle: FullStyle, _dom?: HTMLElement, fonts?: Fonts): MeasureDomResult;
38
+ protected _rootPadding(rootStyle: FullStyle): {
39
+ top: number;
40
+ right: number;
41
+ bottom: number;
42
+ left: number;
43
+ };
44
+ protected _measureHorizontal(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
45
+ /**
46
+ * Vertical writing-mode (`vertical-rl`): columns stack right-to-left, glyphs
47
+ * flow top→bottom. It is the horizontal layout with the inline and block axes
48
+ * swapped — the inline (down-column) advance is `advanceWidth` (CJK upright = em;
49
+ * Latin is rotated, so its advance ≈ its width), the cross-axis content box is
50
+ * `advanceHeight`, and the column thickness is `fontHeight`. The lineBox is
51
+ * derived exactly as DomMeasurer.measureParagraphDom's vertical branch, so it
52
+ * stays accurate even though inlineBox carries the content-box rounding residual.
53
+ *
54
+ * v1: `vertical-rl` only; no per-paragraph margin/padding or block alignment.
55
+ */
56
+ protected _measureVertical(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
57
+ /** Advance step including CSS letter-spacing (px). */
58
+ protected _advance(character: Character): number;
59
+ /**
60
+ * Break a paragraph's characters into visual lines.
61
+ * v1: `word-break: break-all` (break before any character that would overflow)
62
+ * plus explicit `\n`/`\r` hard breaks. The newline itself occupies no line box.
63
+ */
64
+ protected _breakLines(paragraph: Paragraph, avail: number): Character[][];
65
+ protected _unionInto(target: BoundingBox, boxes: BoundingBox[]): void;
66
+ protected _shiftAll(paragraphs: Paragraph[], dy: number): void;
67
+ dispose(): void;
68
+ }
69
+
9
70
  declare function measureText(options: Options, load: true): Promise<MeasureResult>;
10
71
  declare function measureText(options: Options): MeasureResult;
11
72
 
@@ -15,6 +76,125 @@ declare function renderText(options: RenderTextOptions): void;
15
76
 
16
77
  declare function backgroundPlugin(): Plugin;
17
78
 
79
+ /**
80
+ * 这些曲线类用于「逐字(-by-word)」沿形状排布文字。
81
+ *
82
+ * 旧版变形代码针对 `modern-path2d@0.2.5` 编写,该版本内置了
83
+ * `CircleCurve` / `EllipseCurve` / `HeartCurve` / `PolygonCurve` / `RectangularCurve`,
84
+ * 当前版本(1.6.x)已不再导出。这里从 0.2.5 原样移植其实现,
85
+ * 仅做 Vector2 API 适配(`copy`→`copyFrom`、`new Vector2().lerpVectors`→`Vector2.lerp`),
86
+ * 以保证逐字排布效果与原版一致。
87
+ *
88
+ * 仅保留 deformer 实际用到的方法:getPoint / getPointAt / getTangent / getNormal。
89
+ */
90
+ declare abstract class ShapeCurve {
91
+ arcLengthDivisions: number;
92
+ protected _cacheArcLengths?: number[];
93
+ protected _needsUpdate: boolean;
94
+ abstract getPoint(t: number, output?: Vector2): Vector2;
95
+ getPointAt(u: number, output?: Vector2): Vector2;
96
+ getLength(): number;
97
+ getLengths(divisions?: number): number[];
98
+ getUToTMapping(u: number, distance?: number): number;
99
+ getTangent(t: number, output?: Vector2): Vector2;
100
+ getNormal(t: number, output?: Vector2): Vector2;
101
+ }
102
+ /**
103
+ * 分段曲线基类:由若干子曲线拼成,`getCurve(t)` 选中子曲线并把 `curveT` 设为其局部参数,
104
+ * 其余取点/切线/法线统一委托给选中的子曲线。
105
+ */
106
+ declare abstract class SegmentedCurve extends ShapeCurve {
107
+ protected curveT: number;
108
+ abstract getCurve(t: number): ShapeCurve;
109
+ getPoint(t: number, output?: Vector2): Vector2;
110
+ getPointAt(u: number, output?: Vector2): Vector2;
111
+ getTangent(t: number, output?: Vector2): Vector2;
112
+ getNormal(t: number, output?: Vector2): Vector2;
113
+ }
114
+ declare class LineShapeCurve extends ShapeCurve {
115
+ start: Vector2;
116
+ end: Vector2;
117
+ constructor(start: Vector2, end: Vector2);
118
+ getPoint(t: number, output?: Vector2): Vector2;
119
+ getPointAt(u: number, output?: Vector2): Vector2;
120
+ getTangent(_t: number, output?: Vector2): Vector2;
121
+ }
122
+ declare class CircleCurve extends ShapeCurve {
123
+ center: Vector2;
124
+ radius: number;
125
+ start: number;
126
+ end: number;
127
+ constructor(center: Vector2, radius: number, start?: number, end?: number);
128
+ getPoint(t: number, output?: Vector2): Vector2;
129
+ getTangent(t: number, output?: Vector2): Vector2;
130
+ getNormal(t: number, output?: Vector2): Vector2;
131
+ }
132
+ declare class EllipseCurve extends ShapeCurve {
133
+ center: Vector2;
134
+ radiusX: number;
135
+ radiusY: number;
136
+ rotation: number;
137
+ startAngle: number;
138
+ endAngle: number;
139
+ clockwise: boolean;
140
+ constructor(center?: Vector2, radiusX?: number, radiusY?: number, rotation?: number, startAngle?: number, endAngle?: number, clockwise?: boolean);
141
+ getPoint(t: number, output?: Vector2): Vector2;
142
+ }
143
+ declare class HeartCurve extends SegmentedCurve {
144
+ center: Vector2;
145
+ size: number;
146
+ start: number;
147
+ end: number;
148
+ protected curves: ShapeCurve[];
149
+ constructor(center: Vector2, size: number, start?: number, end?: number);
150
+ update(): this;
151
+ getCurve(t: number): ShapeCurve;
152
+ }
153
+ declare class PolygonCurve extends SegmentedCurve {
154
+ center: Vector2;
155
+ radius: number;
156
+ number: number;
157
+ start: number;
158
+ end: number;
159
+ protected curves: LineShapeCurve[];
160
+ protected points: Vector2[];
161
+ constructor(center: Vector2, radius?: number, number?: number, start?: number, end?: number);
162
+ update(): this;
163
+ getCurve(t: number): LineShapeCurve;
164
+ }
165
+ declare class RectangularCurve extends SegmentedCurve {
166
+ center: Vector2;
167
+ rx: number;
168
+ aspectRatio: number;
169
+ start: number;
170
+ end: number;
171
+ protected curves: LineShapeCurve[];
172
+ constructor(center: Vector2, rx: number, aspectRatio?: number, start?: number, end?: number);
173
+ update(): this;
174
+ getCurve(t: number): LineShapeCurve;
175
+ }
176
+
177
+ /**
178
+ * 注册一个变形预设(库外部定义,运行时透传)。
179
+ * 官方预设包见子入口 `modern-text/deformations`。
180
+ */
181
+ declare function defineDeformation(name: string, preset: DeformationPreset): void;
182
+ /** 取消注册某个预设 */
183
+ declare function removeDeformation(name: string): void;
184
+ /** 当前已注册的预设名列表 */
185
+ declare function getDeformationNames(): string[];
186
+ /**
187
+ * 文字变形插件(纯引擎)。
188
+ *
189
+ * 通过 `text.deformation` 指定**已注册**的预设名:
190
+ * ```ts
191
+ * import { registerDeformations } from 'modern-text/deformations'
192
+ * registerDeformations()
193
+ * new Text({ content: 'abc', deformation: { type: 'bend', intensities: [50] } })
194
+ * ```
195
+ */
196
+ declare function deformationPlugin(): Plugin;
197
+
18
198
  declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight;
19
199
  declare function highlightPlugin(): Plugin;
20
200
 
@@ -60,5 +240,5 @@ declare function parseColormap(colormap: 'none' | Record<string, string>): Recor
60
240
  declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean;
61
241
  declare function isEqualValue(val1: any, val2: any): boolean;
62
242
 
63
- export { MeasureResult, Options, Plugin, RenderOptions, Text, backgroundPlugin, createSvgLoader, createSvgParser, definePlugin, getEffectTransform2D, getHighlightStyle, highlightPlugin, isEqualObject, isEqualValue, listStylePlugin, measureText, outlinePlugin, parseColormap, parseTransformOrigin, parseValueNumber, renderPlugin, renderText, textDecorationPlugin };
243
+ export { Character, CircleCurve, DeformationPreset, EllipseCurve, FontMeasurer, HeartCurve, MeasureDomResult, MeasureResult, 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 };
64
244
  export type { RenderTextOptions, SvgLoader, SvgParser };
package/dist/index.d.mts CHANGED
@@ -1,11 +1,72 @@
1
- import { h as Plugin, O as Options, b as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.Db7Uoht6.mjs';
2
- export { C as Canvas2DRenderer, a as Character, D as DrawShapePathsOptions, F as Fragment, M as MeasureDomResult, c as MeasuredCharacter, d as MeasuredCharacterRect, e as MeasuredFragment, f as MeasuredParagraph, g as Measurer, P as Paragraph, i as TextEvents, t as textDefaultStyle } from './shared/modern-text.Db7Uoht6.mjs';
3
- import { NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
4
- import { Path2DSet, Transform2D } from 'modern-path2d';
5
- import 'modern-font';
1
+ import { i as Plugin, k as TextMeasurer, P as Paragraph, M as MeasureDomResult, a as Character, O as Options, c as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.D4WopQCu.mjs';
2
+ export { C as Canvas2DRenderer, D as DomMeasurer, b as DrawShapePathsOptions, F as Fragment, d as MeasuredCharacter, e as MeasuredCharacterRect, f as MeasuredFragment, g as MeasuredParagraph, h as MeasurerKind, j as TextEvents, t as textDefaultStyle } from './shared/modern-text.D4WopQCu.mjs';
3
+ import { Fonts } from 'modern-font';
4
+ import { FullStyle, NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
5
+ import { BoundingBox, Vector2, Path2DSet, Transform2D } from 'modern-path2d';
6
+ import { c as DeformationPreset } from './shared/modern-text.CYa4lfoG.mjs';
7
+ export { B as BendContext, a as BendPreset, C as CurvePreset, D as DeformationCharInfo, b as DeformationCurve, F as FfdContext, d as FfdPreset, O as OffsetPreset, V as VerbatimContext } from './shared/modern-text.CYa4lfoG.mjs';
6
8
 
7
9
  declare function definePlugin(options: Plugin): Plugin;
8
10
 
11
+ /**
12
+ * Pure-JS, DOM-free text measurer — a drop-in alternative to {@link DomMeasurer}.
13
+ *
14
+ * Instead of mounting a `<section>/<ul>/<li>/<span>` tree and reading
15
+ * `getBoundingClientRect()`, it computes the same four-level boxes
16
+ * (`character.inlineBox`/`lineBox`, `fragment.inlineBox`, `paragraph.lineBox`)
17
+ * from `modern-font` glyph advances, so the downstream
18
+ * measure → glyph → plugin pipeline is unchanged and it runs in Node/SSR/Worker.
19
+ *
20
+ * ## Scope
21
+ * - `horizontal-tb` (LTR) and `vertical-rl` (columns right-to-left, glyphs top↓)
22
+ * - line breaking: `word-break: break-all` (greedy, break anywhere) + explicit `\n`
23
+ * - per-line `text-align` (start/left/center/end/right), `text-indent` (first line)
24
+ * - box model: root + paragraph `padding`/`margin` (horizontal), `letter-spacing`,
25
+ * `line-height`; block `vertical-align` (top/middle/bottom) at fixed height
26
+ *
27
+ * ## Not yet implemented (TODO)
28
+ * - UAX#14 `word-break: normal` + 避头尾/kinsoku (`line-break`)
29
+ * - BiDi, per-fragment inline `vertical-align`, borders
30
+ * - vertical: per-paragraph margin/padding and block alignment
31
+ * - kerning/ligatures (GSUB/GPOS) — fine for CJK, diverges for proportional Latin
32
+ *
33
+ * Coordinates are relative to the root border-box top-left (matching the DOM
34
+ * measurer, whose rects are taken relative to `section.getBoundingClientRect()`).
35
+ */
36
+ declare class FontMeasurer implements TextMeasurer {
37
+ measure(paragraphs: Paragraph[], rootStyle: FullStyle, _dom?: HTMLElement, fonts?: Fonts): MeasureDomResult;
38
+ protected _rootPadding(rootStyle: FullStyle): {
39
+ top: number;
40
+ right: number;
41
+ bottom: number;
42
+ left: number;
43
+ };
44
+ protected _measureHorizontal(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
45
+ /**
46
+ * Vertical writing-mode (`vertical-rl`): columns stack right-to-left, glyphs
47
+ * flow top→bottom. It is the horizontal layout with the inline and block axes
48
+ * swapped — the inline (down-column) advance is `advanceWidth` (CJK upright = em;
49
+ * Latin is rotated, so its advance ≈ its width), the cross-axis content box is
50
+ * `advanceHeight`, and the column thickness is `fontHeight`. The lineBox is
51
+ * derived exactly as DomMeasurer.measureParagraphDom's vertical branch, so it
52
+ * stays accurate even though inlineBox carries the content-box rounding residual.
53
+ *
54
+ * v1: `vertical-rl` only; no per-paragraph margin/padding or block alignment.
55
+ */
56
+ protected _measureVertical(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
57
+ /** Advance step including CSS letter-spacing (px). */
58
+ protected _advance(character: Character): number;
59
+ /**
60
+ * Break a paragraph's characters into visual lines.
61
+ * v1: `word-break: break-all` (break before any character that would overflow)
62
+ * plus explicit `\n`/`\r` hard breaks. The newline itself occupies no line box.
63
+ */
64
+ protected _breakLines(paragraph: Paragraph, avail: number): Character[][];
65
+ protected _unionInto(target: BoundingBox, boxes: BoundingBox[]): void;
66
+ protected _shiftAll(paragraphs: Paragraph[], dy: number): void;
67
+ dispose(): void;
68
+ }
69
+
9
70
  declare function measureText(options: Options, load: true): Promise<MeasureResult>;
10
71
  declare function measureText(options: Options): MeasureResult;
11
72
 
@@ -15,6 +76,125 @@ declare function renderText(options: RenderTextOptions): void;
15
76
 
16
77
  declare function backgroundPlugin(): Plugin;
17
78
 
79
+ /**
80
+ * 这些曲线类用于「逐字(-by-word)」沿形状排布文字。
81
+ *
82
+ * 旧版变形代码针对 `modern-path2d@0.2.5` 编写,该版本内置了
83
+ * `CircleCurve` / `EllipseCurve` / `HeartCurve` / `PolygonCurve` / `RectangularCurve`,
84
+ * 当前版本(1.6.x)已不再导出。这里从 0.2.5 原样移植其实现,
85
+ * 仅做 Vector2 API 适配(`copy`→`copyFrom`、`new Vector2().lerpVectors`→`Vector2.lerp`),
86
+ * 以保证逐字排布效果与原版一致。
87
+ *
88
+ * 仅保留 deformer 实际用到的方法:getPoint / getPointAt / getTangent / getNormal。
89
+ */
90
+ declare abstract class ShapeCurve {
91
+ arcLengthDivisions: number;
92
+ protected _cacheArcLengths?: number[];
93
+ protected _needsUpdate: boolean;
94
+ abstract getPoint(t: number, output?: Vector2): Vector2;
95
+ getPointAt(u: number, output?: Vector2): Vector2;
96
+ getLength(): number;
97
+ getLengths(divisions?: number): number[];
98
+ getUToTMapping(u: number, distance?: number): number;
99
+ getTangent(t: number, output?: Vector2): Vector2;
100
+ getNormal(t: number, output?: Vector2): Vector2;
101
+ }
102
+ /**
103
+ * 分段曲线基类:由若干子曲线拼成,`getCurve(t)` 选中子曲线并把 `curveT` 设为其局部参数,
104
+ * 其余取点/切线/法线统一委托给选中的子曲线。
105
+ */
106
+ declare abstract class SegmentedCurve extends ShapeCurve {
107
+ protected curveT: number;
108
+ abstract getCurve(t: number): ShapeCurve;
109
+ getPoint(t: number, output?: Vector2): Vector2;
110
+ getPointAt(u: number, output?: Vector2): Vector2;
111
+ getTangent(t: number, output?: Vector2): Vector2;
112
+ getNormal(t: number, output?: Vector2): Vector2;
113
+ }
114
+ declare class LineShapeCurve extends ShapeCurve {
115
+ start: Vector2;
116
+ end: Vector2;
117
+ constructor(start: Vector2, end: Vector2);
118
+ getPoint(t: number, output?: Vector2): Vector2;
119
+ getPointAt(u: number, output?: Vector2): Vector2;
120
+ getTangent(_t: number, output?: Vector2): Vector2;
121
+ }
122
+ declare class CircleCurve extends ShapeCurve {
123
+ center: Vector2;
124
+ radius: number;
125
+ start: number;
126
+ end: number;
127
+ constructor(center: Vector2, radius: number, start?: number, end?: number);
128
+ getPoint(t: number, output?: Vector2): Vector2;
129
+ getTangent(t: number, output?: Vector2): Vector2;
130
+ getNormal(t: number, output?: Vector2): Vector2;
131
+ }
132
+ declare class EllipseCurve extends ShapeCurve {
133
+ center: Vector2;
134
+ radiusX: number;
135
+ radiusY: number;
136
+ rotation: number;
137
+ startAngle: number;
138
+ endAngle: number;
139
+ clockwise: boolean;
140
+ constructor(center?: Vector2, radiusX?: number, radiusY?: number, rotation?: number, startAngle?: number, endAngle?: number, clockwise?: boolean);
141
+ getPoint(t: number, output?: Vector2): Vector2;
142
+ }
143
+ declare class HeartCurve extends SegmentedCurve {
144
+ center: Vector2;
145
+ size: number;
146
+ start: number;
147
+ end: number;
148
+ protected curves: ShapeCurve[];
149
+ constructor(center: Vector2, size: number, start?: number, end?: number);
150
+ update(): this;
151
+ getCurve(t: number): ShapeCurve;
152
+ }
153
+ declare class PolygonCurve extends SegmentedCurve {
154
+ center: Vector2;
155
+ radius: number;
156
+ number: number;
157
+ start: number;
158
+ end: number;
159
+ protected curves: LineShapeCurve[];
160
+ protected points: Vector2[];
161
+ constructor(center: Vector2, radius?: number, number?: number, start?: number, end?: number);
162
+ update(): this;
163
+ getCurve(t: number): LineShapeCurve;
164
+ }
165
+ declare class RectangularCurve extends SegmentedCurve {
166
+ center: Vector2;
167
+ rx: number;
168
+ aspectRatio: number;
169
+ start: number;
170
+ end: number;
171
+ protected curves: LineShapeCurve[];
172
+ constructor(center: Vector2, rx: number, aspectRatio?: number, start?: number, end?: number);
173
+ update(): this;
174
+ getCurve(t: number): LineShapeCurve;
175
+ }
176
+
177
+ /**
178
+ * 注册一个变形预设(库外部定义,运行时透传)。
179
+ * 官方预设包见子入口 `modern-text/deformations`。
180
+ */
181
+ declare function defineDeformation(name: string, preset: DeformationPreset): void;
182
+ /** 取消注册某个预设 */
183
+ declare function removeDeformation(name: string): void;
184
+ /** 当前已注册的预设名列表 */
185
+ declare function getDeformationNames(): string[];
186
+ /**
187
+ * 文字变形插件(纯引擎)。
188
+ *
189
+ * 通过 `text.deformation` 指定**已注册**的预设名:
190
+ * ```ts
191
+ * import { registerDeformations } from 'modern-text/deformations'
192
+ * registerDeformations()
193
+ * new Text({ content: 'abc', deformation: { type: 'bend', intensities: [50] } })
194
+ * ```
195
+ */
196
+ declare function deformationPlugin(): Plugin;
197
+
18
198
  declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight;
19
199
  declare function highlightPlugin(): Plugin;
20
200
 
@@ -60,5 +240,5 @@ declare function parseColormap(colormap: 'none' | Record<string, string>): Recor
60
240
  declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean;
61
241
  declare function isEqualValue(val1: any, val2: any): boolean;
62
242
 
63
- export { MeasureResult, Options, Plugin, RenderOptions, Text, backgroundPlugin, createSvgLoader, createSvgParser, definePlugin, getEffectTransform2D, getHighlightStyle, highlightPlugin, isEqualObject, isEqualValue, listStylePlugin, measureText, outlinePlugin, parseColormap, parseTransformOrigin, parseValueNumber, renderPlugin, renderText, textDecorationPlugin };
243
+ export { Character, CircleCurve, DeformationPreset, EllipseCurve, FontMeasurer, HeartCurve, MeasureDomResult, MeasureResult, 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 };
64
244
  export type { RenderTextOptions, SvgLoader, SvgParser };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,72 @@
1
- import { h as Plugin, O as Options, b as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.Db7Uoht6.js';
2
- export { C as Canvas2DRenderer, a as Character, D as DrawShapePathsOptions, F as Fragment, M as MeasureDomResult, c as MeasuredCharacter, d as MeasuredCharacterRect, e as MeasuredFragment, f as MeasuredParagraph, g as Measurer, P as Paragraph, i as TextEvents, t as textDefaultStyle } from './shared/modern-text.Db7Uoht6.js';
3
- import { NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
4
- import { Path2DSet, Transform2D } from 'modern-path2d';
5
- import 'modern-font';
1
+ import { i as Plugin, k as TextMeasurer, P as Paragraph, M as MeasureDomResult, a as Character, O as Options, c as MeasureResult, R as RenderOptions, T as Text } from './shared/modern-text.D4WopQCu.js';
2
+ export { C as Canvas2DRenderer, D as DomMeasurer, b as DrawShapePathsOptions, F as Fragment, d as MeasuredCharacter, e as MeasuredCharacterRect, f as MeasuredFragment, g as MeasuredParagraph, h as MeasurerKind, j as TextEvents, t as textDefaultStyle } from './shared/modern-text.D4WopQCu.js';
3
+ import { Fonts } from 'modern-font';
4
+ import { FullStyle, NormalizedStyle, NormalizedHighlight, NormalizedEffect } from 'modern-idoc';
5
+ import { BoundingBox, Vector2, Path2DSet, Transform2D } from 'modern-path2d';
6
+ import { c as DeformationPreset } from './shared/modern-text.BxijkspX.js';
7
+ export { B as BendContext, a as BendPreset, C as CurvePreset, D as DeformationCharInfo, b as DeformationCurve, F as FfdContext, d as FfdPreset, O as OffsetPreset, V as VerbatimContext } from './shared/modern-text.BxijkspX.js';
6
8
 
7
9
  declare function definePlugin(options: Plugin): Plugin;
8
10
 
11
+ /**
12
+ * Pure-JS, DOM-free text measurer — a drop-in alternative to {@link DomMeasurer}.
13
+ *
14
+ * Instead of mounting a `<section>/<ul>/<li>/<span>` tree and reading
15
+ * `getBoundingClientRect()`, it computes the same four-level boxes
16
+ * (`character.inlineBox`/`lineBox`, `fragment.inlineBox`, `paragraph.lineBox`)
17
+ * from `modern-font` glyph advances, so the downstream
18
+ * measure → glyph → plugin pipeline is unchanged and it runs in Node/SSR/Worker.
19
+ *
20
+ * ## Scope
21
+ * - `horizontal-tb` (LTR) and `vertical-rl` (columns right-to-left, glyphs top↓)
22
+ * - line breaking: `word-break: break-all` (greedy, break anywhere) + explicit `\n`
23
+ * - per-line `text-align` (start/left/center/end/right), `text-indent` (first line)
24
+ * - box model: root + paragraph `padding`/`margin` (horizontal), `letter-spacing`,
25
+ * `line-height`; block `vertical-align` (top/middle/bottom) at fixed height
26
+ *
27
+ * ## Not yet implemented (TODO)
28
+ * - UAX#14 `word-break: normal` + 避头尾/kinsoku (`line-break`)
29
+ * - BiDi, per-fragment inline `vertical-align`, borders
30
+ * - vertical: per-paragraph margin/padding and block alignment
31
+ * - kerning/ligatures (GSUB/GPOS) — fine for CJK, diverges for proportional Latin
32
+ *
33
+ * Coordinates are relative to the root border-box top-left (matching the DOM
34
+ * measurer, whose rects are taken relative to `section.getBoundingClientRect()`).
35
+ */
36
+ declare class FontMeasurer implements TextMeasurer {
37
+ measure(paragraphs: Paragraph[], rootStyle: FullStyle, _dom?: HTMLElement, fonts?: Fonts): MeasureDomResult;
38
+ protected _rootPadding(rootStyle: FullStyle): {
39
+ top: number;
40
+ right: number;
41
+ bottom: number;
42
+ left: number;
43
+ };
44
+ protected _measureHorizontal(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
45
+ /**
46
+ * Vertical writing-mode (`vertical-rl`): columns stack right-to-left, glyphs
47
+ * flow top→bottom. It is the horizontal layout with the inline and block axes
48
+ * swapped — the inline (down-column) advance is `advanceWidth` (CJK upright = em;
49
+ * Latin is rotated, so its advance ≈ its width), the cross-axis content box is
50
+ * `advanceHeight`, and the column thickness is `fontHeight`. The lineBox is
51
+ * derived exactly as DomMeasurer.measureParagraphDom's vertical branch, so it
52
+ * stays accurate even though inlineBox carries the content-box rounding residual.
53
+ *
54
+ * v1: `vertical-rl` only; no per-paragraph margin/padding or block alignment.
55
+ */
56
+ protected _measureVertical(paragraphs: Paragraph[], rootStyle: FullStyle): MeasureDomResult;
57
+ /** Advance step including CSS letter-spacing (px). */
58
+ protected _advance(character: Character): number;
59
+ /**
60
+ * Break a paragraph's characters into visual lines.
61
+ * v1: `word-break: break-all` (break before any character that would overflow)
62
+ * plus explicit `\n`/`\r` hard breaks. The newline itself occupies no line box.
63
+ */
64
+ protected _breakLines(paragraph: Paragraph, avail: number): Character[][];
65
+ protected _unionInto(target: BoundingBox, boxes: BoundingBox[]): void;
66
+ protected _shiftAll(paragraphs: Paragraph[], dy: number): void;
67
+ dispose(): void;
68
+ }
69
+
9
70
  declare function measureText(options: Options, load: true): Promise<MeasureResult>;
10
71
  declare function measureText(options: Options): MeasureResult;
11
72
 
@@ -15,6 +76,125 @@ declare function renderText(options: RenderTextOptions): void;
15
76
 
16
77
  declare function backgroundPlugin(): Plugin;
17
78
 
79
+ /**
80
+ * 这些曲线类用于「逐字(-by-word)」沿形状排布文字。
81
+ *
82
+ * 旧版变形代码针对 `modern-path2d@0.2.5` 编写,该版本内置了
83
+ * `CircleCurve` / `EllipseCurve` / `HeartCurve` / `PolygonCurve` / `RectangularCurve`,
84
+ * 当前版本(1.6.x)已不再导出。这里从 0.2.5 原样移植其实现,
85
+ * 仅做 Vector2 API 适配(`copy`→`copyFrom`、`new Vector2().lerpVectors`→`Vector2.lerp`),
86
+ * 以保证逐字排布效果与原版一致。
87
+ *
88
+ * 仅保留 deformer 实际用到的方法:getPoint / getPointAt / getTangent / getNormal。
89
+ */
90
+ declare abstract class ShapeCurve {
91
+ arcLengthDivisions: number;
92
+ protected _cacheArcLengths?: number[];
93
+ protected _needsUpdate: boolean;
94
+ abstract getPoint(t: number, output?: Vector2): Vector2;
95
+ getPointAt(u: number, output?: Vector2): Vector2;
96
+ getLength(): number;
97
+ getLengths(divisions?: number): number[];
98
+ getUToTMapping(u: number, distance?: number): number;
99
+ getTangent(t: number, output?: Vector2): Vector2;
100
+ getNormal(t: number, output?: Vector2): Vector2;
101
+ }
102
+ /**
103
+ * 分段曲线基类:由若干子曲线拼成,`getCurve(t)` 选中子曲线并把 `curveT` 设为其局部参数,
104
+ * 其余取点/切线/法线统一委托给选中的子曲线。
105
+ */
106
+ declare abstract class SegmentedCurve extends ShapeCurve {
107
+ protected curveT: number;
108
+ abstract getCurve(t: number): ShapeCurve;
109
+ getPoint(t: number, output?: Vector2): Vector2;
110
+ getPointAt(u: number, output?: Vector2): Vector2;
111
+ getTangent(t: number, output?: Vector2): Vector2;
112
+ getNormal(t: number, output?: Vector2): Vector2;
113
+ }
114
+ declare class LineShapeCurve extends ShapeCurve {
115
+ start: Vector2;
116
+ end: Vector2;
117
+ constructor(start: Vector2, end: Vector2);
118
+ getPoint(t: number, output?: Vector2): Vector2;
119
+ getPointAt(u: number, output?: Vector2): Vector2;
120
+ getTangent(_t: number, output?: Vector2): Vector2;
121
+ }
122
+ declare class CircleCurve extends ShapeCurve {
123
+ center: Vector2;
124
+ radius: number;
125
+ start: number;
126
+ end: number;
127
+ constructor(center: Vector2, radius: number, start?: number, end?: number);
128
+ getPoint(t: number, output?: Vector2): Vector2;
129
+ getTangent(t: number, output?: Vector2): Vector2;
130
+ getNormal(t: number, output?: Vector2): Vector2;
131
+ }
132
+ declare class EllipseCurve extends ShapeCurve {
133
+ center: Vector2;
134
+ radiusX: number;
135
+ radiusY: number;
136
+ rotation: number;
137
+ startAngle: number;
138
+ endAngle: number;
139
+ clockwise: boolean;
140
+ constructor(center?: Vector2, radiusX?: number, radiusY?: number, rotation?: number, startAngle?: number, endAngle?: number, clockwise?: boolean);
141
+ getPoint(t: number, output?: Vector2): Vector2;
142
+ }
143
+ declare class HeartCurve extends SegmentedCurve {
144
+ center: Vector2;
145
+ size: number;
146
+ start: number;
147
+ end: number;
148
+ protected curves: ShapeCurve[];
149
+ constructor(center: Vector2, size: number, start?: number, end?: number);
150
+ update(): this;
151
+ getCurve(t: number): ShapeCurve;
152
+ }
153
+ declare class PolygonCurve extends SegmentedCurve {
154
+ center: Vector2;
155
+ radius: number;
156
+ number: number;
157
+ start: number;
158
+ end: number;
159
+ protected curves: LineShapeCurve[];
160
+ protected points: Vector2[];
161
+ constructor(center: Vector2, radius?: number, number?: number, start?: number, end?: number);
162
+ update(): this;
163
+ getCurve(t: number): LineShapeCurve;
164
+ }
165
+ declare class RectangularCurve extends SegmentedCurve {
166
+ center: Vector2;
167
+ rx: number;
168
+ aspectRatio: number;
169
+ start: number;
170
+ end: number;
171
+ protected curves: LineShapeCurve[];
172
+ constructor(center: Vector2, rx: number, aspectRatio?: number, start?: number, end?: number);
173
+ update(): this;
174
+ getCurve(t: number): LineShapeCurve;
175
+ }
176
+
177
+ /**
178
+ * 注册一个变形预设(库外部定义,运行时透传)。
179
+ * 官方预设包见子入口 `modern-text/deformations`。
180
+ */
181
+ declare function defineDeformation(name: string, preset: DeformationPreset): void;
182
+ /** 取消注册某个预设 */
183
+ declare function removeDeformation(name: string): void;
184
+ /** 当前已注册的预设名列表 */
185
+ declare function getDeformationNames(): string[];
186
+ /**
187
+ * 文字变形插件(纯引擎)。
188
+ *
189
+ * 通过 `text.deformation` 指定**已注册**的预设名:
190
+ * ```ts
191
+ * import { registerDeformations } from 'modern-text/deformations'
192
+ * registerDeformations()
193
+ * new Text({ content: 'abc', deformation: { type: 'bend', intensities: [50] } })
194
+ * ```
195
+ */
196
+ declare function deformationPlugin(): Plugin;
197
+
18
198
  declare function getHighlightStyle(style: NormalizedStyle): NormalizedHighlight;
19
199
  declare function highlightPlugin(): Plugin;
20
200
 
@@ -60,5 +240,5 @@ declare function parseColormap(colormap: 'none' | Record<string, string>): Recor
60
240
  declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, any>): boolean;
61
241
  declare function isEqualValue(val1: any, val2: any): boolean;
62
242
 
63
- export { MeasureResult, Options, Plugin, RenderOptions, Text, backgroundPlugin, createSvgLoader, createSvgParser, definePlugin, getEffectTransform2D, getHighlightStyle, highlightPlugin, isEqualObject, isEqualValue, listStylePlugin, measureText, outlinePlugin, parseColormap, parseTransformOrigin, parseValueNumber, renderPlugin, renderText, textDecorationPlugin };
243
+ export { Character, CircleCurve, DeformationPreset, EllipseCurve, FontMeasurer, HeartCurve, MeasureDomResult, MeasureResult, 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 };
64
244
  export type { RenderTextOptions, SvgLoader, SvgParser };