modern-text 0.4.2 → 0.4.4

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,
@@ -676,7 +652,7 @@ function parseStrokeWidthScale(strokeWidth, fontSize, total) {
676
652
  return strokeWidth / total;
677
653
  }
678
654
  }
679
- function getTransformMatrix(a, b, c, isVertical) {
655
+ function getTransformMatrix(a, b, c, isVertical, type) {
680
656
  let scale;
681
657
  if (!isVertical) {
682
658
  scale = {
@@ -691,10 +667,18 @@ function getTransformMatrix(a, b, c, isVertical) {
691
667
  }
692
668
  const offset = c.center.add(
693
669
  a.center.sub(b.center).scale(scale.x, scale.y)
694
- ).sub({
695
- x: a.width / 2 * scale.x,
696
- y: a.height / 2 * scale.y
697
- });
670
+ );
671
+ if (type === "line") {
672
+ offset.sub({
673
+ x: a.width / 2 * scale.x,
674
+ y: a.height * scale.y
675
+ });
676
+ } else {
677
+ offset.sub({
678
+ x: a.width / 2 * scale.x,
679
+ y: a.height / 2 * scale.y
680
+ });
681
+ }
698
682
  const m = new modernPath2d.Matrix3();
699
683
  m.translate(-a.left, -a.top);
700
684
  if (isVertical) {
@@ -723,14 +707,13 @@ function highlight() {
723
707
  paths,
724
708
  update: (text) => {
725
709
  paths.length = 0;
726
- const { characters } = text;
727
- let group;
728
710
  const groups = [];
711
+ let group;
729
712
  let prevStyle;
730
- characters.forEach((character) => {
731
- const { isVertical, computedStyle: style } = character;
713
+ text.forEachCharacter((character) => {
714
+ const { isVertical, computedStyle: style, inlineBox, fontSize } = character;
732
715
  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) {
716
+ 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
717
  group.push(character);
735
718
  } else {
736
719
  group = [];
@@ -740,15 +723,15 @@ function highlight() {
740
723
  }
741
724
  prevStyle = style;
742
725
  });
743
- groups.filter((characters2) => characters2.length).map((characters2) => {
744
- const char = characters2[0];
726
+ groups.filter((characters) => characters.length).map((characters) => {
727
+ const char = characters[0];
745
728
  return {
746
- style: char.computedStyle,
747
- baseline: char.baseline,
748
- box: modernPath2d.BoundingBox.from(...characters2.map((c) => c.glyphBox))
729
+ char,
730
+ groupBox: modernPath2d.BoundingBox.from(...characters.map((c) => c.glyphBox))
749
731
  };
750
732
  }).forEach((group2) => {
751
- const { style, box: groupBox, baseline } = group2;
733
+ const { char, groupBox } = group2;
734
+ const style = char.computedStyle;
752
735
  const { fontSize, writingMode } = style;
753
736
  const isVertical = writingMode.includes("vertical");
754
737
  const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
@@ -759,12 +742,21 @@ function highlight() {
759
742
  const box = modernPath2d.getPathsBoundingBox(svgPaths, true);
760
743
  const refBox = modernPath2d.getPathsBoundingBox(refPaths, false);
761
744
  const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : isVertical ? groupBox.height : groupBox.width;
762
- const unitHeight = baseline * 0.8;
745
+ let unitHeight;
746
+ let type;
747
+ if (box.height / refBox.height > 0.8) {
748
+ type = "block";
749
+ unitHeight = groupBox.height;
750
+ } else {
751
+ type = "line";
752
+ unitHeight = char.inlineBox.top - groupBox.top + char.underlinePosition;
753
+ }
763
754
  const transform = getTransformMatrix(
764
755
  box,
765
756
  refBox,
766
757
  new modernPath2d.BoundingBox(groupBox.left, groupBox.top, isVertical ? unitHeight : unitWidth, isVertical ? unitWidth : unitHeight),
767
- isVertical
758
+ isVertical,
759
+ type
768
760
  );
769
761
  const styleScale = fontSize / box.width * 2;
770
762
  const total = Math.ceil(groupBox.width / unitWidth);
@@ -921,7 +913,7 @@ function render() {
921
913
  return boxes.length ? modernPath2d.BoundingBox.from(...boxes) : void 0;
922
914
  },
923
915
  render: (ctx, text) => {
924
- const { characters, paragraphs, glyphBox, effects, style } = text;
916
+ const { paragraphs, glyphBox, effects, style } = text;
925
917
  function fillBackground(color, box) {
926
918
  ctx.fillStyle = color;
927
919
  ctx.fillRect(box.left, box.top, box.width, box.height);
@@ -940,7 +932,7 @@ function render() {
940
932
  ctx.save();
941
933
  const [a, c, e, b, d, f] = getTransform2D(text, style2).transpose().elements;
942
934
  ctx.transform(a, b, c, d, e, f);
943
- characters.forEach((character) => {
935
+ text.forEachCharacter((character) => {
944
936
  if (character.parent.style?.backgroundColor) {
945
937
  fillBackground(character.parent.style.backgroundColor, character.inlineBox);
946
938
  }
@@ -985,6 +977,112 @@ function getTransform2D(text, style) {
985
977
  return tempM1.clone();
986
978
  }
987
979
 
980
+ function textDecoration() {
981
+ const paths = [];
982
+ return definePlugin({
983
+ name: "textDecoration",
984
+ paths,
985
+ update: (text) => {
986
+ paths.length = 0;
987
+ const groups = [];
988
+ let group;
989
+ let prevStyle;
990
+ text.forEachCharacter((character) => {
991
+ const { computedStyle: style, isVertical, inlineBox, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = character;
992
+ if (!isNone(style.textDecoration)) {
993
+ let flag = false;
994
+ if (prevStyle?.textDecoration === style.textDecoration && prevStyle?.writingMode === style.writingMode && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top)) {
995
+ switch (style.textDecoration) {
996
+ case "underline":
997
+ if (group[0].underlinePosition === underlinePosition && group[0].underlineThickness === underlineThickness) {
998
+ flag = true;
999
+ }
1000
+ break;
1001
+ case "line-through":
1002
+ if (group[0].strikeoutPosition === strikeoutPosition && group[0].strikeoutSize === strikeoutSize) {
1003
+ flag = true;
1004
+ }
1005
+ break;
1006
+ }
1007
+ }
1008
+ if (flag) {
1009
+ group.push(character);
1010
+ } else {
1011
+ group = [];
1012
+ group.push(character);
1013
+ groups.push(group);
1014
+ }
1015
+ prevStyle = style;
1016
+ } else {
1017
+ prevStyle = void 0;
1018
+ }
1019
+ });
1020
+ groups.forEach((group2) => {
1021
+ const { computedStyle: style, isVertical, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = group2[0];
1022
+ const { textDecoration: textDecoration2 } = style;
1023
+ const { left, top, width, height } = modernPath2d.BoundingBox.from(...group2.map((c) => c.inlineBox));
1024
+ let strokePosition = isVertical ? left : top;
1025
+ let strokeWidth = 0;
1026
+ switch (textDecoration2) {
1027
+ case "underline":
1028
+ strokePosition += underlinePosition;
1029
+ strokeWidth = underlineThickness * 2;
1030
+ break;
1031
+ case "line-through":
1032
+ strokePosition += strikeoutPosition;
1033
+ strokeWidth = strikeoutSize * 2;
1034
+ break;
1035
+ }
1036
+ strokePosition -= strokeWidth;
1037
+ if (isVertical) {
1038
+ paths.push(new modernPath2d.Path2D([
1039
+ { type: "M", x: strokePosition, y: top },
1040
+ { type: "L", x: strokePosition, y: top + height },
1041
+ { type: "L", x: strokePosition + strokeWidth, y: top + height },
1042
+ { type: "L", x: strokePosition + strokeWidth, y: top },
1043
+ { type: "Z" }
1044
+ ]));
1045
+ } else {
1046
+ paths.push(new modernPath2d.Path2D([
1047
+ { type: "M", x: left, y: strokePosition },
1048
+ { type: "L", x: left + width, y: strokePosition },
1049
+ { type: "L", x: left + width, y: strokePosition + strokeWidth },
1050
+ { type: "L", x: left, y: strokePosition + strokeWidth },
1051
+ { type: "Z" }
1052
+ ]));
1053
+ }
1054
+ });
1055
+ },
1056
+ render: (ctx, text) => {
1057
+ const { effects, fontSize } = text;
1058
+ if (effects) {
1059
+ effects.forEach((style) => {
1060
+ ctx.save();
1061
+ const [a, c, e, b, d, f] = getTransform2D(text, style).transpose().elements;
1062
+ ctx.transform(a, b, c, d, e, f);
1063
+ paths.forEach((path) => {
1064
+ drawPath({
1065
+ ctx,
1066
+ path,
1067
+ fontSize,
1068
+ ...style
1069
+ });
1070
+ });
1071
+ ctx.restore();
1072
+ });
1073
+ } else {
1074
+ paths.forEach((path) => {
1075
+ drawPath({
1076
+ ctx,
1077
+ path,
1078
+ fontSize
1079
+ });
1080
+ });
1081
+ }
1082
+ }
1083
+ });
1084
+ }
1085
+
988
1086
  var __defProp = Object.defineProperty;
989
1087
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
990
1088
  var __publicField = (obj, key, value) => {
@@ -1059,7 +1157,7 @@ class Text {
1059
1157
  this.measureDom = measureDom;
1060
1158
  this.effects = effects;
1061
1159
  this.fonts = fonts;
1062
- this.use(render()).use(highlight()).use(listStyle());
1160
+ this.use(listStyle()).use(textDecoration()).use(highlight()).use(render());
1063
1161
  }
1064
1162
  get fontSize() {
1065
1163
  return this.computedStyle.fontSize;
@@ -1074,6 +1172,16 @@ class Text {
1074
1172
  this.plugins.set(plugin.name, plugin);
1075
1173
  return this;
1076
1174
  }
1175
+ forEachCharacter(handle) {
1176
+ this.paragraphs.forEach((p, paragraphIndex) => {
1177
+ p.fragments.forEach((f, fragmentIndex) => {
1178
+ f.characters.forEach((c, characterIndex) => {
1179
+ handle(c, { paragraphIndex, fragmentIndex, characterIndex });
1180
+ });
1181
+ });
1182
+ });
1183
+ return this;
1184
+ }
1077
1185
  updateParagraphs() {
1078
1186
  this.computedStyle = { ...defaultTextStyles, ...this.style };
1079
1187
  let { content, computedStyle: style } = this;
@@ -1263,5 +1371,6 @@ exports.parseColor = parseColor;
1263
1371
  exports.render = render;
1264
1372
  exports.renderText = renderText;
1265
1373
  exports.setupView = setupView;
1374
+ exports.textDecoration = textDecoration;
1266
1375
  exports.uploadColor = uploadColor;
1267
1376
  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 };