modern-text 0.4.2 → 0.4.3

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.
package/dist/index.cjs CHANGED
@@ -148,16 +148,26 @@ class Character {
148
148
  this.content = content;
149
149
  this.index = index;
150
150
  this.parent = parent;
151
+ __publicField$3(this, "path", new modernPath2d.Path2D());
151
152
  __publicField$3(this, "lineBox", new modernPath2d.BoundingBox());
152
153
  __publicField$3(this, "inlineBox", new modernPath2d.BoundingBox());
153
154
  __publicField$3(this, "glyphBox");
154
155
  __publicField$3(this, "underlinePosition", 0);
155
156
  __publicField$3(this, "underlineThickness", 0);
156
- __publicField$3(this, "yStrikeoutPosition", 0);
157
- __publicField$3(this, "yStrikeoutSize", 0);
157
+ __publicField$3(this, "strikeoutPosition", 0);
158
+ __publicField$3(this, "strikeoutSize", 0);
159
+ __publicField$3(this, "ascender", 0);
160
+ __publicField$3(this, "descender", 0);
161
+ __publicField$3(this, "typoAscender", 0);
162
+ __publicField$3(this, "typoDescender", 0);
163
+ __publicField$3(this, "typoLineGap", 0);
164
+ __publicField$3(this, "winAscent", 0);
165
+ __publicField$3(this, "winDescent", 0);
166
+ __publicField$3(this, "xHeight", 0);
167
+ __publicField$3(this, "capHeight", 0);
158
168
  __publicField$3(this, "baseline", 0);
159
169
  __publicField$3(this, "centerDiviation", 0);
160
- __publicField$3(this, "path", new modernPath2d.Path2D());
170
+ __publicField$3(this, "fontStyle");
161
171
  }
162
172
  get center() {
163
173
  return this.glyphBox?.center;
@@ -184,25 +194,34 @@ class Character {
184
194
  if (!sfnt) {
185
195
  return this;
186
196
  }
187
- const { unitsPerEm, ascender, descender, os2, post } = sfnt;
197
+ const { hhea, os2, post, head } = sfnt;
198
+ const unitsPerEm = head.unitsPerEm;
199
+ const ascender = hhea.ascent;
200
+ const descender = hhea.descent;
188
201
  const { content, computedStyle } = this;
189
202
  const { fontSize } = computedStyle;
190
203
  const rate = unitsPerEm / fontSize;
191
204
  const advanceWidth = sfnt.getAdvanceWidth(content, fontSize);
192
205
  const advanceHeight = (ascender + Math.abs(descender)) / rate;
193
206
  const baseline = ascender / rate;
194
- const yStrikeoutPosition = (ascender - os2.yStrikeoutPosition) / rate;
195
- const yStrikeoutSize = os2.yStrikeoutSize / rate;
196
- const underlinePosition = (ascender - post.underlinePosition) / rate;
197
- const underlineThickness = post.underlineThickness / rate;
198
207
  this.inlineBox.width = advanceWidth;
199
208
  this.inlineBox.height = advanceHeight;
200
- this.underlinePosition = underlinePosition;
201
- this.underlineThickness = underlineThickness;
202
- this.yStrikeoutPosition = yStrikeoutPosition;
203
- this.yStrikeoutSize = yStrikeoutSize;
209
+ this.underlinePosition = (ascender - post.underlinePosition) / rate;
210
+ this.underlineThickness = post.underlineThickness / rate;
211
+ this.strikeoutPosition = (ascender - os2.yStrikeoutPosition) / rate;
212
+ this.strikeoutSize = os2.yStrikeoutSize / rate;
213
+ this.ascender = ascender / rate;
214
+ this.descender = descender / rate;
215
+ this.typoAscender = os2.sTypoAscender / rate;
216
+ this.typoDescender = os2.sTypoDescender / rate;
217
+ this.typoLineGap = os2.sTypoLineGap / rate;
218
+ this.winAscent = os2.usWinAscent / rate;
219
+ this.winDescent = os2.usWinDescent / rate;
220
+ this.xHeight = os2.sxHeight / rate;
221
+ this.capHeight = os2.sCapHeight / rate;
204
222
  this.baseline = baseline;
205
223
  this.centerDiviation = advanceHeight / 2 - baseline;
224
+ this.fontStyle = fsSelectionMap[os2.fsSelection] ?? macStyleMap[head.macStyle];
206
225
  return this;
207
226
  }
208
227
  update(fonts) {
@@ -216,11 +235,12 @@ class Character {
216
235
  content,
217
236
  computedStyle: style,
218
237
  baseline,
219
- inlineBox
238
+ inlineBox,
239
+ ascender,
240
+ descender,
241
+ typoAscender,
242
+ fontStyle
220
243
  } = this;
221
- const { os2, head, ascender, descender } = sfnt;
222
- const typoAscender = os2.sTypoAscender;
223
- const fontStyle = fsSelectionMap[os2.fsSelection] ?? macStyleMap[head.macStyle];
224
244
  const { left, top } = inlineBox;
225
245
  const needsItalic = style.fontStyle === "italic" && fontStyle !== "italic";
226
246
  let x = left;
@@ -278,7 +298,6 @@ class Character {
278
298
  }
279
299
  }
280
300
  }
281
- path.addCommands(this._decoration());
282
301
  const fontWeight = style.fontWeight ?? 400;
283
302
  if (fontWeight in fontWeightMap && ((fontWeight === 700 || fontWeight === "bold") && fontStyle !== "bold")) {
284
303
  path.bold(fontWeightMap[fontWeight] * style.fontSize * 0.05);
@@ -292,49 +311,6 @@ class Character {
292
311
  this.glyphBox = this.getGlyphBoundingBox();
293
312
  return this;
294
313
  }
295
- _decoration() {
296
- const { isVertical, underlinePosition, yStrikeoutPosition } = this;
297
- const { textDecoration, fontSize } = this.computedStyle;
298
- const { left, top, width, height } = this.inlineBox;
299
- const lineWidth = 0.1 * fontSize;
300
- let start;
301
- switch (textDecoration) {
302
- case "underline":
303
- if (isVertical) {
304
- start = left;
305
- } else {
306
- start = top + underlinePosition;
307
- }
308
- break;
309
- case "line-through":
310
- if (isVertical) {
311
- start = left + width / 2;
312
- } else {
313
- start = top + yStrikeoutPosition;
314
- }
315
- break;
316
- case "none":
317
- default:
318
- return [];
319
- }
320
- if (isVertical) {
321
- return [
322
- { type: "M", x: start, y: top },
323
- { type: "L", x: start, y: top + height },
324
- { type: "L", x: start + lineWidth, y: top + height },
325
- { type: "L", x: start + lineWidth, y: top },
326
- { type: "Z" }
327
- ];
328
- } else {
329
- return [
330
- { type: "M", x: left, y: start },
331
- { type: "L", x: left + width, y: start },
332
- { type: "L", x: left + width, y: start + lineWidth },
333
- { type: "L", x: left, y: start + lineWidth },
334
- { type: "Z" }
335
- ];
336
- }
337
- }
338
314
  _italic(path, startPoint) {
339
315
  path.skew(-0.24, 0, startPoint || {
340
316
  y: this.inlineBox.top + this.baseline,
@@ -723,14 +699,13 @@ function highlight() {
723
699
  paths,
724
700
  update: (text) => {
725
701
  paths.length = 0;
726
- const { characters } = text;
727
- let group;
728
702
  const groups = [];
703
+ let group;
729
704
  let prevStyle;
730
- characters.forEach((character) => {
731
- const { isVertical, computedStyle: style } = character;
705
+ text.forEachCharacter((character) => {
706
+ const { isVertical, computedStyle: style, inlineBox, fontSize } = character;
732
707
  if (!isNone(style.highlightImage) && character.glyphBox) {
733
- if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group?.length && (isVertical ? group[0].inlineBox.left === character.inlineBox.left : group[0].inlineBox.top === character.inlineBox.top) && group[0].fontSize === character.fontSize) {
708
+ if (style.highlightSize !== "1rem" && prevStyle?.highlightImage === style.highlightImage && prevStyle?.highlightSize === style.highlightSize && prevStyle?.highlightStrokeWidth === style.highlightStrokeWidth && prevStyle?.highlightOverflow === style.highlightOverflow && group?.length && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top) && group[0].fontSize === fontSize) {
734
709
  group.push(character);
735
710
  } else {
736
711
  group = [];
@@ -740,15 +715,15 @@ function highlight() {
740
715
  }
741
716
  prevStyle = style;
742
717
  });
743
- groups.filter((characters2) => characters2.length).map((characters2) => {
744
- const char = characters2[0];
718
+ groups.filter((characters) => characters.length).map((characters) => {
719
+ const char = characters[0];
745
720
  return {
746
721
  style: char.computedStyle,
747
- baseline: char.baseline,
748
- box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox))
722
+ unitHeight: char.typoAscender + char.typoDescender,
723
+ box: modernPath2d.BoundingBox.from(...characters.map((c) => c.glyphBox))
749
724
  };
750
725
  }).forEach((group2) => {
751
- const { style, box: groupBox, baseline } = group2;
726
+ const { style, box: groupBox, unitHeight } = group2;
752
727
  const { fontSize, writingMode } = style;
753
728
  const isVertical = writingMode.includes("vertical");
754
729
  const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
@@ -759,7 +734,6 @@ function highlight() {
759
734
  const box = modernPath2d.getPathsBoundingBox(svgPaths, true);
760
735
  const refBox = modernPath2d.getPathsBoundingBox(refPaths, false);
761
736
  const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : isVertical ? groupBox.height : groupBox.width;
762
- const unitHeight = baseline * 0.8;
763
737
  const transform = getTransformMatrix(
764
738
  box,
765
739
  refBox,
@@ -921,7 +895,7 @@ function render() {
921
895
  return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
922
896
  },
923
897
  render: (ctx, text) => {
924
- const { characters, paragraphs, glyphBox, effects, style } = text;
898
+ const { paragraphs, glyphBox, effects, style } = text;
925
899
  function fillBackground(color, box) {
926
900
  ctx.fillStyle = color;
927
901
  ctx.fillRect(box.left, box.top, box.width, box.height);
@@ -940,7 +914,7 @@ function render() {
940
914
  ctx.save();
941
915
  const [a, c, e, b, d, f] = getTransform2D(text, style2).transpose().elements;
942
916
  ctx.transform(a, b, c, d, e, f);
943
- characters.forEach((character) => {
917
+ text.forEachCharacter((character) => {
944
918
  if (character.parent.style?.backgroundColor) {
945
919
  fillBackground(character.parent.style.backgroundColor, character.inlineBox);
946
920
  }
@@ -985,6 +959,112 @@ function getTransform2D(text, style) {
985
959
  return tempM1.clone();
986
960
  }
987
961
 
962
+ function textDecoration() {
963
+ const paths = [];
964
+ return definePlugin({
965
+ name: "textDecoration",
966
+ paths,
967
+ update: (text) => {
968
+ paths.length = 0;
969
+ const groups = [];
970
+ let group;
971
+ let prevStyle;
972
+ text.forEachCharacter((character) => {
973
+ const { computedStyle: style, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = character;
974
+ if (!isNone(style.textDecoration)) {
975
+ let flag = false;
976
+ if (prevStyle?.textDecoration === style.textDecoration && prevStyle?.writingMode === style.writingMode) {
977
+ switch (style.textDecoration) {
978
+ case "underline":
979
+ if (group[0].underlinePosition === underlinePosition && group[0].underlineThickness === underlineThickness) {
980
+ flag = true;
981
+ }
982
+ break;
983
+ case "line-through":
984
+ if (group[0].strikeoutPosition === strikeoutPosition && group[0].strikeoutSize === strikeoutSize) {
985
+ flag = true;
986
+ }
987
+ break;
988
+ }
989
+ }
990
+ if (flag) {
991
+ group.push(character);
992
+ } else {
993
+ group = [];
994
+ group.push(character);
995
+ groups.push(group);
996
+ }
997
+ prevStyle = style;
998
+ } else {
999
+ prevStyle = void 0;
1000
+ }
1001
+ });
1002
+ groups.forEach((group2) => {
1003
+ const { computedStyle: style, isVertical, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = group2[0];
1004
+ const { textDecoration: textDecoration2 } = style;
1005
+ const { left, top, width, height } = modernPath2d.BoundingBox.from(...group2.map((c) => c.inlineBox));
1006
+ let strokePosition = isVertical ? left : top;
1007
+ let strokeWidth = 0;
1008
+ switch (textDecoration2) {
1009
+ case "underline":
1010
+ strokePosition += underlinePosition;
1011
+ strokeWidth = underlineThickness * 2;
1012
+ break;
1013
+ case "line-through":
1014
+ strokePosition += strikeoutPosition;
1015
+ strokeWidth = strikeoutSize * 2;
1016
+ break;
1017
+ }
1018
+ strokePosition -= strokeWidth;
1019
+ if (isVertical) {
1020
+ paths.push(new modernPath2d.Path2D([
1021
+ { type: "M", x: strokePosition, y: top },
1022
+ { type: "L", x: strokePosition, y: top + height },
1023
+ { type: "L", x: strokePosition + strokeWidth, y: top + height },
1024
+ { type: "L", x: strokePosition + strokeWidth, y: top },
1025
+ { type: "Z" }
1026
+ ]));
1027
+ } else {
1028
+ paths.push(new modernPath2d.Path2D([
1029
+ { type: "M", x: left, y: strokePosition },
1030
+ { type: "L", x: left + width, y: strokePosition },
1031
+ { type: "L", x: left + width, y: strokePosition + strokeWidth },
1032
+ { type: "L", x: left, y: strokePosition + strokeWidth },
1033
+ { type: "Z" }
1034
+ ]));
1035
+ }
1036
+ });
1037
+ },
1038
+ render: (ctx, text) => {
1039
+ const { effects, fontSize } = text;
1040
+ if (effects) {
1041
+ effects.forEach((style) => {
1042
+ ctx.save();
1043
+ const [a, c, e, b, d, f] = getTransform2D(text, style).transpose().elements;
1044
+ ctx.transform(a, b, c, d, e, f);
1045
+ paths.forEach((path) => {
1046
+ drawPath({
1047
+ ctx,
1048
+ path,
1049
+ fontSize,
1050
+ ...style
1051
+ });
1052
+ });
1053
+ ctx.restore();
1054
+ });
1055
+ } else {
1056
+ paths.forEach((path) => {
1057
+ drawPath({
1058
+ ctx,
1059
+ path,
1060
+ fontSize
1061
+ });
1062
+ });
1063
+ }
1064
+ }
1065
+ });
1066
+ }
1067
+
988
1068
  var __defProp = Object.defineProperty;
989
1069
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
990
1070
  var __publicField = (obj, key, value) => {
@@ -1059,7 +1139,7 @@ class Text {
1059
1139
  this.measureDom = measureDom;
1060
1140
  this.effects = effects;
1061
1141
  this.fonts = fonts;
1062
- this.use(render()).use(highlight()).use(listStyle());
1142
+ this.use(listStyle()).use(textDecoration()).use(highlight()).use(render());
1063
1143
  }
1064
1144
  get fontSize() {
1065
1145
  return this.computedStyle.fontSize;
@@ -1074,6 +1154,16 @@ class Text {
1074
1154
  this.plugins.set(plugin.name, plugin);
1075
1155
  return this;
1076
1156
  }
1157
+ forEachCharacter(handle) {
1158
+ this.paragraphs.forEach((p, paragraphIndex) => {
1159
+ p.fragments.forEach((f, fragmentIndex) => {
1160
+ f.characters.forEach((c, characterIndex) => {
1161
+ handle(c, { paragraphIndex, fragmentIndex, characterIndex });
1162
+ });
1163
+ });
1164
+ });
1165
+ return this;
1166
+ }
1077
1167
  updateParagraphs() {
1078
1168
  this.computedStyle = { ...defaultTextStyles, ...this.style };
1079
1169
  let { content, computedStyle: style } = this;
@@ -1263,5 +1353,6 @@ exports.parseColor = parseColor;
1263
1353
  exports.render = render;
1264
1354
  exports.renderText = renderText;
1265
1355
  exports.setupView = setupView;
1356
+ exports.textDecoration = textDecoration;
1266
1357
  exports.uploadColor = uploadColor;
1267
1358
  exports.uploadColors = uploadColors;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BoundingBox, Path2D, Vector2, VectorLike, Matrix3 } from 'modern-path2d';
2
- import { Fonts, Sfnt, GlyphPathCommand } from 'modern-font';
2
+ import { Fonts, Sfnt } from 'modern-font';
3
3
 
4
4
  declare class Fragment {
5
5
  content: string;
@@ -18,16 +18,26 @@ declare class Character {
18
18
  content: string;
19
19
  index: number;
20
20
  parent: Fragment;
21
+ path: Path2D;
21
22
  lineBox: BoundingBox;
22
23
  inlineBox: BoundingBox;
23
24
  glyphBox: BoundingBox | undefined;
24
25
  underlinePosition: number;
25
26
  underlineThickness: number;
26
- yStrikeoutPosition: number;
27
- yStrikeoutSize: number;
27
+ strikeoutPosition: number;
28
+ strikeoutSize: number;
29
+ ascender: number;
30
+ descender: number;
31
+ typoAscender: number;
32
+ typoDescender: number;
33
+ typoLineGap: number;
34
+ winAscent: number;
35
+ winDescent: number;
36
+ xHeight: number;
37
+ capHeight: number;
28
38
  baseline: number;
29
39
  centerDiviation: number;
30
- path: Path2D;
40
+ fontStyle?: 'bold' | 'italic';
31
41
  get center(): Vector2 | undefined;
32
42
  get computedStyle(): TextStyle;
33
43
  get isVertical(): boolean;
@@ -37,7 +47,6 @@ declare class Character {
37
47
  protected _getFontSfnt(fonts?: Fonts): Sfnt | undefined;
38
48
  updateGlyph(sfnt?: Sfnt | undefined): this;
39
49
  update(fonts?: Fonts): this;
40
- protected _decoration(): GlyphPathCommand[];
41
50
  protected _italic(path: Path2D, startPoint?: VectorLike): void;
42
51
  getGlyphMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
43
52
  min: Vector2;
@@ -158,6 +167,11 @@ declare class Text {
158
167
  get characters(): Character[];
159
168
  constructor(options?: TextOptions);
160
169
  use(plugin: TextPlugin): this;
170
+ forEachCharacter(handle: (character: Character, ctx: {
171
+ paragraphIndex: number;
172
+ fragmentIndex: number;
173
+ characterIndex: number;
174
+ }) => void): this;
161
175
  updateParagraphs(): this;
162
176
  measure(dom?: HTMLElement | undefined): MeasureResult;
163
177
  getGlyphBox(): BoundingBox;
@@ -285,9 +299,11 @@ declare function listStyle(): TextPlugin;
285
299
  declare function render(): TextPlugin;
286
300
  declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
287
301
 
302
+ declare function textDecoration(): TextPlugin;
303
+
288
304
  declare function renderText(options: TextOptions & TextRenderOptions): Text;
289
305
 
290
306
  declare function isNone(val: string | undefined): boolean;
291
307
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
292
308
 
293
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, uploadColor, uploadColors };
309
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BoundingBox, Path2D, Vector2, VectorLike, Matrix3 } from 'modern-path2d';
2
- import { Fonts, Sfnt, GlyphPathCommand } from 'modern-font';
2
+ import { Fonts, Sfnt } from 'modern-font';
3
3
 
4
4
  declare class Fragment {
5
5
  content: string;
@@ -18,16 +18,26 @@ declare class Character {
18
18
  content: string;
19
19
  index: number;
20
20
  parent: Fragment;
21
+ path: Path2D;
21
22
  lineBox: BoundingBox;
22
23
  inlineBox: BoundingBox;
23
24
  glyphBox: BoundingBox | undefined;
24
25
  underlinePosition: number;
25
26
  underlineThickness: number;
26
- yStrikeoutPosition: number;
27
- yStrikeoutSize: number;
27
+ strikeoutPosition: number;
28
+ strikeoutSize: number;
29
+ ascender: number;
30
+ descender: number;
31
+ typoAscender: number;
32
+ typoDescender: number;
33
+ typoLineGap: number;
34
+ winAscent: number;
35
+ winDescent: number;
36
+ xHeight: number;
37
+ capHeight: number;
28
38
  baseline: number;
29
39
  centerDiviation: number;
30
- path: Path2D;
40
+ fontStyle?: 'bold' | 'italic';
31
41
  get center(): Vector2 | undefined;
32
42
  get computedStyle(): TextStyle;
33
43
  get isVertical(): boolean;
@@ -37,7 +47,6 @@ declare class Character {
37
47
  protected _getFontSfnt(fonts?: Fonts): Sfnt | undefined;
38
48
  updateGlyph(sfnt?: Sfnt | undefined): this;
39
49
  update(fonts?: Fonts): this;
40
- protected _decoration(): GlyphPathCommand[];
41
50
  protected _italic(path: Path2D, startPoint?: VectorLike): void;
42
51
  getGlyphMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
43
52
  min: Vector2;
@@ -158,6 +167,11 @@ declare class Text {
158
167
  get characters(): Character[];
159
168
  constructor(options?: TextOptions);
160
169
  use(plugin: TextPlugin): this;
170
+ forEachCharacter(handle: (character: Character, ctx: {
171
+ paragraphIndex: number;
172
+ fragmentIndex: number;
173
+ characterIndex: number;
174
+ }) => void): this;
161
175
  updateParagraphs(): this;
162
176
  measure(dom?: HTMLElement | undefined): MeasureResult;
163
177
  getGlyphBox(): BoundingBox;
@@ -285,9 +299,11 @@ declare function listStyle(): TextPlugin;
285
299
  declare function render(): TextPlugin;
286
300
  declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
287
301
 
302
+ declare function textDecoration(): TextPlugin;
303
+
288
304
  declare function renderText(options: TextOptions & TextRenderOptions): Text;
289
305
 
290
306
  declare function isNone(val: string | undefined): boolean;
291
307
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
292
308
 
293
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, uploadColor, uploadColors };
309
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BoundingBox, Path2D, Vector2, VectorLike, Matrix3 } from 'modern-path2d';
2
- import { Fonts, Sfnt, GlyphPathCommand } from 'modern-font';
2
+ import { Fonts, Sfnt } from 'modern-font';
3
3
 
4
4
  declare class Fragment {
5
5
  content: string;
@@ -18,16 +18,26 @@ declare class Character {
18
18
  content: string;
19
19
  index: number;
20
20
  parent: Fragment;
21
+ path: Path2D;
21
22
  lineBox: BoundingBox;
22
23
  inlineBox: BoundingBox;
23
24
  glyphBox: BoundingBox | undefined;
24
25
  underlinePosition: number;
25
26
  underlineThickness: number;
26
- yStrikeoutPosition: number;
27
- yStrikeoutSize: number;
27
+ strikeoutPosition: number;
28
+ strikeoutSize: number;
29
+ ascender: number;
30
+ descender: number;
31
+ typoAscender: number;
32
+ typoDescender: number;
33
+ typoLineGap: number;
34
+ winAscent: number;
35
+ winDescent: number;
36
+ xHeight: number;
37
+ capHeight: number;
28
38
  baseline: number;
29
39
  centerDiviation: number;
30
- path: Path2D;
40
+ fontStyle?: 'bold' | 'italic';
31
41
  get center(): Vector2 | undefined;
32
42
  get computedStyle(): TextStyle;
33
43
  get isVertical(): boolean;
@@ -37,7 +47,6 @@ declare class Character {
37
47
  protected _getFontSfnt(fonts?: Fonts): Sfnt | undefined;
38
48
  updateGlyph(sfnt?: Sfnt | undefined): this;
39
49
  update(fonts?: Fonts): this;
40
- protected _decoration(): GlyphPathCommand[];
41
50
  protected _italic(path: Path2D, startPoint?: VectorLike): void;
42
51
  getGlyphMinMax(min?: Vector2, max?: Vector2, withStyle?: boolean): {
43
52
  min: Vector2;
@@ -158,6 +167,11 @@ declare class Text {
158
167
  get characters(): Character[];
159
168
  constructor(options?: TextOptions);
160
169
  use(plugin: TextPlugin): this;
170
+ forEachCharacter(handle: (character: Character, ctx: {
171
+ paragraphIndex: number;
172
+ fragmentIndex: number;
173
+ characterIndex: number;
174
+ }) => void): this;
161
175
  updateParagraphs(): this;
162
176
  measure(dom?: HTMLElement | undefined): MeasureResult;
163
177
  getGlyphBox(): BoundingBox;
@@ -285,9 +299,11 @@ declare function listStyle(): TextPlugin;
285
299
  declare function render(): TextPlugin;
286
300
  declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
287
301
 
302
+ declare function textDecoration(): TextPlugin;
303
+
288
304
  declare function renderText(options: TextOptions & TextRenderOptions): Text;
289
305
 
290
306
  declare function isNone(val: string | undefined): boolean;
291
307
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
292
308
 
293
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, uploadColor, uploadColors };
309
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightImage, type HighlightOverflow, type HighlightSize, type HighlightStrokeWidth, type LinearGradient, type ListStyleImage, type ListStylePosition, type ListStyleSize, type ListStyleType, type MeasureDomResult, type MeasureResult, type MeasuredCharacter, type MeasuredFragment, type MeasuredParagraph, Measurer, Paragraph, type ParagraphContent, type Sizeable, Text, type TextAlign, type TextContent, type TextDecoration, type TextDrawStyle, type TextInlineStyle, type TextLineStyle, type TextOptions, type TextOrientation, type TextPlugin, type TextRenderOptions, type TextStyle, type TextTransform, type TextWrap, type VerticalAlign, type WritingMode, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, textDecoration, uploadColor, uploadColors };