modern-text 0.5.13 → 0.6.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.
package/dist/index.cjs CHANGED
@@ -456,6 +456,9 @@ function filterEmpty(val) {
456
456
  }
457
457
  return res;
458
458
  }
459
+ function needsFetch(source) {
460
+ return source.startsWith("http://") || source.startsWith("https://") || source.startsWith("blob://");
461
+ }
459
462
 
460
463
  var __defProp$3 = Object.defineProperty;
461
464
  var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -526,9 +529,6 @@ function definePlugin(options) {
526
529
  }
527
530
 
528
531
  class Measurer {
529
- constructor(_text) {
530
- this._text = _text;
531
- }
532
532
  _styleToDomStyle(style) {
533
533
  const _style = { ...style };
534
534
  for (const key in style) {
@@ -560,8 +560,7 @@ class Measurer {
560
560
  * </ul>
561
561
  * </section>
562
562
  */
563
- createDom() {
564
- const { paragraphs, computedStyle } = this._text;
563
+ createDom(paragraphs, rootStyle) {
565
564
  const documentFragment = document.createDocumentFragment();
566
565
  const dom = document.createElement("section");
567
566
  Object.assign(dom.style, {
@@ -569,7 +568,7 @@ class Measurer {
569
568
  height: "max-content",
570
569
  whiteSpace: "pre-wrap",
571
570
  wordBreak: "break-all",
572
- ...this._styleToDomStyle(computedStyle),
571
+ ...this._styleToDomStyle(rootStyle),
573
572
  position: "fixed",
574
573
  visibility: "hidden"
575
574
  });
@@ -664,8 +663,7 @@ class Measurer {
664
663
  characters
665
664
  };
666
665
  }
667
- measureDom(dom) {
668
- const { paragraphs } = this._text;
666
+ measureDom(paragraphs, dom) {
669
667
  const rect = dom.getBoundingClientRect();
670
668
  const measured = this._measureDom(dom);
671
669
  measured.paragraphs.forEach((p) => {
@@ -717,12 +715,12 @@ class Measurer {
717
715
  boundingBox: new modernPath2d.BoundingBox(0, 0, rect.width, rect.height)
718
716
  };
719
717
  }
720
- measure(dom) {
718
+ measure(paragraphs, rootStyle, dom) {
721
719
  let destory;
722
720
  if (!dom) {
723
- ({ dom, destory } = this.createDom());
721
+ ({ dom, destory } = this.createDom(paragraphs, rootStyle));
724
722
  }
725
- const result = this.measureDom(dom);
723
+ const result = this.measureDom(paragraphs, dom);
726
724
  destory?.();
727
725
  return result;
728
726
  }
@@ -825,33 +823,74 @@ class EventEmitter {
825
823
  function highlight() {
826
824
  const paths = [];
827
825
  const clipRects = [];
828
- const svgStringToSvgPaths = /* @__PURE__ */ new Map();
829
- async function getPaths(svg) {
830
- let result = svgStringToSvgPaths.get(svg);
831
- if (!result) {
832
- if (svg.startsWith("http")) {
833
- svg = await fetch(svg).then((rep) => rep.text());
826
+ const loaded = /* @__PURE__ */ new Map();
827
+ const parsed = /* @__PURE__ */ new Map();
828
+ async function loadSvg(svg) {
829
+ if (!loaded.has(svg)) {
830
+ loaded.set(svg, svg);
831
+ try {
832
+ loaded.set(svg, await fetch(svg).then((rep) => rep.text()));
833
+ } catch (err) {
834
+ console.warn(err);
835
+ loaded.delete(svg);
834
836
  }
835
- const dom = modernPath2d.parseSvgToDom(svg);
837
+ }
838
+ }
839
+ function getPaths(svg) {
840
+ let result = parsed.get(svg);
841
+ if (!result) {
842
+ const dom = modernPath2d.parseSvgToDom(
843
+ needsFetch(svg) ? loaded.get(svg) ?? svg : svg
844
+ );
836
845
  const paths2 = modernPath2d.parseSvg(dom);
837
846
  result = { dom, paths: paths2 };
838
- svgStringToSvgPaths.set(svg, result);
847
+ parsed.set(svg, result);
839
848
  }
840
849
  return result;
841
850
  }
842
851
  return definePlugin({
843
852
  name: "highlight",
844
853
  paths,
845
- update: async (text) => {
854
+ load: async (text) => {
855
+ const promises = [];
856
+ text.forEachCharacter((character) => {
857
+ const { computedStyle: style } = character;
858
+ const { highlightImage, highlightReferImage } = style;
859
+ if (needsFetch(highlightImage)) {
860
+ promises.push(loadSvg(highlightImage));
861
+ }
862
+ if (needsFetch(highlightReferImage)) {
863
+ promises.push(loadSvg(highlightReferImage));
864
+ }
865
+ });
866
+ await Promise.all(promises);
867
+ },
868
+ update: (text) => {
846
869
  clipRects.length = 0;
847
870
  paths.length = 0;
848
871
  let groups = [];
849
872
  let group;
850
873
  let prevStyle;
851
874
  text.forEachCharacter((character) => {
852
- const { isVertical, computedStyle: style, inlineBox } = character;
853
- if (!isNone(style.highlightImage) && character.glyphBox) {
854
- if ((!prevStyle || isEqualValue(prevStyle.highlightImage, style.highlightImage) && isEqualValue(prevStyle.highlightColormap, style.highlightColormap) && isEqualValue(prevStyle.highlightLine, style.highlightLine) && isEqualValue(prevStyle.highlightSize, style.highlightSize) && isEqualValue(prevStyle.highlightThickness, style.highlightThickness)) && group?.length && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top) && group[0].fontSize === style.fontSize) {
875
+ const {
876
+ computedStyle: style
877
+ } = character;
878
+ const {
879
+ highlightImage
880
+ } = style;
881
+ if (!isNone(highlightImage)) {
882
+ const {
883
+ inlineBox,
884
+ isVertical
885
+ } = character;
886
+ const {
887
+ fontSize,
888
+ highlightColormap,
889
+ highlightLine,
890
+ highlightSize,
891
+ highlightThickness
892
+ } = style;
893
+ if ((!prevStyle || isEqualValue(prevStyle.highlightImage, highlightImage) && isEqualValue(prevStyle.highlightColormap, highlightColormap) && isEqualValue(prevStyle.highlightLine, highlightLine) && isEqualValue(prevStyle.highlightSize, highlightSize) && isEqualValue(prevStyle.highlightThickness, highlightThickness)) && group?.length && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top) && group[0].fontSize === fontSize) {
855
894
  group.push(character);
856
895
  } else {
857
896
  group = [];
@@ -870,8 +909,12 @@ function highlight() {
870
909
  for (let i = 0; i < groups.length; i++) {
871
910
  const characters = groups[i];
872
911
  const char = characters[0];
873
- const groupBox = modernPath2d.BoundingBox.from(...characters.map((c) => c.glyphBox));
874
- const { computedStyle: style } = char;
912
+ const groupBox = modernPath2d.BoundingBox.from(
913
+ ...characters.filter((c) => c.glyphBox).map((c) => c.glyphBox)
914
+ );
915
+ const {
916
+ computedStyle: style
917
+ } = char;
875
918
  const {
876
919
  fontSize,
877
920
  writingMode,
@@ -885,7 +928,7 @@ function highlight() {
885
928
  const isVertical = writingMode.includes("vertical");
886
929
  const thickness = parseValueNumber(highlightThickness, { fontSize, total: groupBox.width }) / groupBox.width;
887
930
  const colormap = parseColormap(highlightColormap);
888
- const { paths: svgPaths, dom: svgDom } = await getPaths(highlightImage);
931
+ const { paths: svgPaths, dom: svgDom } = getPaths(highlightImage);
889
932
  const aBox = modernPath2d.getPathsBoundingBox(svgPaths, true);
890
933
  const styleScale = fontSize / aBox.width * 2;
891
934
  const cBox = new modernPath2d.BoundingBox().copy(groupBox);
@@ -901,7 +944,7 @@ function highlight() {
901
944
  cBox.width = userWidth;
902
945
  }
903
946
  if (!isNone(highlightReferImage) && isNone(highlightLine)) {
904
- const bBox = modernPath2d.getPathsBoundingBox((await getPaths(highlightReferImage)).paths, true);
947
+ const bBox = modernPath2d.getPathsBoundingBox(getPaths(highlightReferImage).paths, true);
905
948
  aBox.copy(bBox);
906
949
  } else {
907
950
  let line;
@@ -1052,8 +1095,16 @@ function listStyle() {
1052
1095
  const { paragraphs, isVertical, fontSize } = text;
1053
1096
  const padding = fontSize * 0.45;
1054
1097
  paragraphs.forEach((paragraph) => {
1055
- const { computedStyle: style } = paragraph;
1056
- const { listStyleImage, listStyleColormap, listStyleSize, listStyleType, color } = style;
1098
+ const {
1099
+ computedStyle: style
1100
+ } = paragraph;
1101
+ const {
1102
+ color,
1103
+ listStyleImage,
1104
+ listStyleColormap,
1105
+ listStyleSize,
1106
+ listStyleType
1107
+ } = style;
1057
1108
  const colormap = parseColormap(listStyleColormap);
1058
1109
  let size = listStyleSize;
1059
1110
  let image;
@@ -1082,18 +1133,10 @@ function listStyle() {
1082
1133
  const m = new modernPath2d.Matrix3();
1083
1134
  if (isVertical) {
1084
1135
  const reScale = fontSize / imageBox.height * scale;
1085
- m.translate(-imageBox.left, -imageBox.top);
1086
- m.rotate(Math.PI / 2);
1087
- m.scale(reScale, reScale);
1088
- m.translate(fontSize / 2 - imageBox.height * reScale / 2, 0);
1089
- m.translate(box.left + (box.width - fontSize) / 2, fBox.top - padding);
1136
+ m.translate(-imageBox.left, -imageBox.top).rotate(Math.PI / 2).scale(reScale, reScale).translate(fontSize / 2 - imageBox.height * reScale / 2, 0).translate(box.left + (box.width - fontSize) / 2, fBox.top - padding);
1090
1137
  } else {
1091
1138
  const reScale = fontSize / imageBox.height * scale;
1092
- m.translate(-imageBox.left, -imageBox.top);
1093
- m.translate(-imageBox.width, 0);
1094
- m.scale(reScale, reScale);
1095
- m.translate(0, fontSize / 2 - imageBox.height * reScale / 2);
1096
- m.translate(fBox.left - padding, box.top + (box.height - fontSize) / 2);
1139
+ m.translate(-imageBox.left, -imageBox.top).translate(-imageBox.width, 0).scale(reScale, reScale).translate(0, fontSize / 2 - imageBox.height * reScale / 2).translate(fBox.left - padding, box.top + (box.height - fontSize) / 2);
1097
1140
  }
1098
1141
  paths.push(...imagePaths.map((p) => {
1099
1142
  const path = p.clone();
@@ -1229,11 +1272,24 @@ function textDecoration() {
1229
1272
  let group;
1230
1273
  let prevStyle;
1231
1274
  text.forEachCharacter((character) => {
1232
- const { computedStyle: style, isVertical, inlineBox, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = character;
1233
- if (!isNone(style.textDecoration)) {
1275
+ const {
1276
+ computedStyle: style,
1277
+ isVertical,
1278
+ inlineBox,
1279
+ underlinePosition,
1280
+ underlineThickness,
1281
+ strikeoutPosition,
1282
+ strikeoutSize
1283
+ } = character;
1284
+ const {
1285
+ color,
1286
+ textDecoration: textDecoration2,
1287
+ writingMode
1288
+ } = style;
1289
+ if (!isNone(textDecoration2)) {
1234
1290
  let flag = false;
1235
- if (prevStyle?.textDecoration === style.textDecoration && prevStyle?.writingMode === style.writingMode && prevStyle?.color === style.color && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top)) {
1236
- switch (style.textDecoration) {
1291
+ if (prevStyle?.textDecoration === textDecoration2 && prevStyle?.writingMode === writingMode && prevStyle?.color === color && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top)) {
1292
+ switch (textDecoration2) {
1237
1293
  case "underline":
1238
1294
  if (group[0].underlinePosition === underlinePosition && group[0].underlineThickness === underlineThickness) {
1239
1295
  flag = true;
@@ -1259,8 +1315,18 @@ function textDecoration() {
1259
1315
  }
1260
1316
  });
1261
1317
  groups.forEach((group2) => {
1262
- const { computedStyle: style, isVertical, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = group2[0];
1263
- const { textDecoration: textDecoration2, color } = style;
1318
+ const {
1319
+ computedStyle: style,
1320
+ isVertical,
1321
+ underlinePosition,
1322
+ underlineThickness,
1323
+ strikeoutPosition,
1324
+ strikeoutSize
1325
+ } = group2[0];
1326
+ const {
1327
+ color,
1328
+ textDecoration: textDecoration2
1329
+ } = style;
1264
1330
  const { left, top, width, height } = modernPath2d.BoundingBox.from(...group2.map((c) => c.inlineBox));
1265
1331
  let position = isVertical ? left + width : top;
1266
1332
  const direction = isVertical ? -1 : 1;
@@ -1403,7 +1469,7 @@ class Text extends EventEmitter {
1403
1469
  __publicField(this, "glyphBox", new modernPath2d.BoundingBox());
1404
1470
  __publicField(this, "pathBox", new modernPath2d.BoundingBox());
1405
1471
  __publicField(this, "boundingBox", new modernPath2d.BoundingBox());
1406
- __publicField(this, "measurer", new Measurer(this));
1472
+ __publicField(this, "measurer", new Measurer());
1407
1473
  __publicField(this, "plugins", /* @__PURE__ */ new Map());
1408
1474
  __publicField(this, "fonts");
1409
1475
  this.debug = options.debug ?? false;
@@ -1437,6 +1503,9 @@ class Text extends EventEmitter {
1437
1503
  });
1438
1504
  return this;
1439
1505
  }
1506
+ async load() {
1507
+ await Promise.all(Array.from(this.plugins.values()).map((p) => p.load?.(this)));
1508
+ }
1440
1509
  updateParagraphs() {
1441
1510
  this.computedStyle = { ...defaultTextStyles, ...this.style };
1442
1511
  let { content, computedStyle: style } = this;
@@ -1488,7 +1557,7 @@ class Text extends EventEmitter {
1488
1557
  this.paragraphs = paragraphs;
1489
1558
  return this;
1490
1559
  }
1491
- async measure(dom = this.measureDom) {
1560
+ measure(dom = this.measureDom) {
1492
1561
  const old = {
1493
1562
  paragraphs: this.paragraphs,
1494
1563
  lineBox: this.lineBox,
@@ -1498,18 +1567,16 @@ class Text extends EventEmitter {
1498
1567
  boundingBox: this.boundingBox
1499
1568
  };
1500
1569
  this.updateParagraphs();
1501
- const result = this.measurer.measure(dom);
1570
+ const result = this.measurer.measure(this.paragraphs, this.computedStyle, dom);
1502
1571
  this.paragraphs = result.paragraphs;
1503
1572
  this.lineBox = result.boundingBox;
1504
1573
  this.characters.forEach((c) => {
1505
1574
  c.update(this.fonts);
1506
1575
  });
1507
1576
  this.rawGlyphBox = this.getGlyphBox();
1508
- const plugins = Array.from(this.plugins.values());
1509
- plugins.sort((a, b) => (a.updateOrder ?? 0) - (b.updateOrder ?? 0));
1510
- for (let i = 0; i < plugins.length; i++) {
1511
- await plugins[i].update?.(this);
1512
- }
1577
+ Array.from(this.plugins.values()).sort((a, b) => (a.updateOrder ?? 0) - (b.updateOrder ?? 0)).forEach((plugin) => {
1578
+ plugin.update?.(this);
1579
+ });
1513
1580
  this.glyphBox = this.getGlyphBox();
1514
1581
  this.updatePathBox().updateBoundingBox();
1515
1582
  for (const key in old) {
@@ -1565,30 +1632,28 @@ class Text extends EventEmitter {
1565
1632
  this.needsUpdate = true;
1566
1633
  return this;
1567
1634
  }
1568
- async update() {
1569
- const result = await this.measure();
1635
+ update() {
1636
+ const result = this.measure();
1570
1637
  for (const key in result) {
1571
1638
  this[key] = result[key];
1572
1639
  }
1573
1640
  this.emit("update", { text: this });
1641
+ return this;
1574
1642
  }
1575
- async render(options) {
1643
+ render(options) {
1576
1644
  const { view, pixelRatio = 2 } = options;
1577
1645
  const ctx = view.getContext("2d");
1578
1646
  if (!ctx) {
1579
1647
  return;
1580
1648
  }
1581
1649
  if (this.needsUpdate) {
1582
- await this.update();
1650
+ this.update();
1583
1651
  }
1584
1652
  setupView(ctx, pixelRatio, this.boundingBox);
1585
1653
  uploadColors(ctx, this);
1586
- const plugins = Array.from(this.plugins.values());
1587
- plugins.sort((a, b) => (a.renderOrder ?? 0) - (b.renderOrder ?? 0));
1588
- for (let i = 0; i < plugins.length; i++) {
1589
- const plugin = plugins[i];
1654
+ Array.from(this.plugins.values()).sort((a, b) => (a.renderOrder ?? 0) - (b.renderOrder ?? 0)).forEach((plugin) => {
1590
1655
  if (plugin.render) {
1591
- await plugin.render?.(ctx, this);
1656
+ plugin.render?.(ctx, this);
1592
1657
  } else if (plugin.paths) {
1593
1658
  const style = this.computedStyle;
1594
1659
  plugin.paths.forEach((path) => {
@@ -1599,17 +1664,21 @@ class Text extends EventEmitter {
1599
1664
  });
1600
1665
  });
1601
1666
  }
1602
- }
1667
+ });
1603
1668
  this.emit("render", { text: this, view, pixelRatio });
1604
1669
  }
1605
1670
  }
1606
1671
 
1607
- function measureText(options) {
1608
- return new Text(options).measure();
1672
+ async function measureText(options) {
1673
+ const text = new Text(options);
1674
+ await text.load();
1675
+ return text.measure();
1609
1676
  }
1610
1677
 
1611
- function renderText(options) {
1612
- return new Text(options).render(options);
1678
+ async function renderText(options) {
1679
+ const text = new Text(options);
1680
+ await text.load();
1681
+ text.render(options);
1613
1682
  }
1614
1683
 
1615
1684
  exports.Character = Character;
@@ -1629,6 +1698,7 @@ exports.isEqualValue = isEqualValue;
1629
1698
  exports.isNone = isNone;
1630
1699
  exports.listStyle = listStyle;
1631
1700
  exports.measureText = measureText;
1701
+ exports.needsFetch = needsFetch;
1632
1702
  exports.parseColor = parseColor;
1633
1703
  exports.parseColormap = parseColormap;
1634
1704
  exports.parseValueNumber = parseValueNumber;
package/dist/index.d.cts CHANGED
@@ -121,8 +121,6 @@ interface MeasureDomResult {
121
121
  boundingBox: BoundingBox;
122
122
  }
123
123
  declare class Measurer {
124
- protected _text: Text;
125
- constructor(_text: Text);
126
124
  protected _styleToDomStyle(style: Partial<TextStyle>): Record<string, any>;
127
125
  /**
128
126
  * <section style="...">
@@ -134,7 +132,7 @@ declare class Measurer {
134
132
  * </ul>
135
133
  * </section>
136
134
  */
137
- createDom(): {
135
+ createDom(paragraphs: Paragraph[], rootStyle: TextStyle): {
138
136
  dom: HTMLElement;
139
137
  destory: () => void;
140
138
  };
@@ -143,8 +141,8 @@ declare class Measurer {
143
141
  fragments: MeasuredFragment[];
144
142
  characters: MeasuredCharacter[];
145
143
  };
146
- measureDom(dom: HTMLElement): MeasureDomResult;
147
- measure(dom?: HTMLElement): MeasureDomResult;
144
+ measureDom(paragraphs: Paragraph[], dom: HTMLElement): MeasureDomResult;
145
+ measure(paragraphs: Paragraph[], rootStyle: TextStyle, dom?: HTMLElement): MeasureDomResult;
148
146
  }
149
147
 
150
148
  interface TextRenderOptions {
@@ -201,14 +199,15 @@ declare class Text extends EventEmitter<TextEventMap> {
201
199
  fragmentIndex: number;
202
200
  characterIndex: number;
203
201
  }) => void): this;
202
+ load(): Promise<void>;
204
203
  updateParagraphs(): this;
205
- measure(dom?: HTMLElement | undefined): Promise<MeasureResult>;
204
+ measure(dom?: HTMLElement | undefined): MeasureResult;
206
205
  getGlyphBox(): BoundingBox;
207
206
  updatePathBox(): this;
208
207
  updateBoundingBox(): this;
209
208
  requestUpdate(): this;
210
- update(): Promise<void>;
211
- render(options: TextRenderOptions): Promise<void>;
209
+ update(): this;
210
+ render(options: TextRenderOptions): void;
212
211
  }
213
212
 
214
213
  type Sizeable = `${number}%` | `${number}rem` | number;
@@ -286,15 +285,15 @@ interface ParagraphContent extends Partial<TextStyle> {
286
285
  fragments: FragmentContent[];
287
286
  }
288
287
  type TextContent = string | FragmentContent | ParagraphContent | (string | FragmentContent | ParagraphContent | (string | FragmentContent)[])[];
289
- type PromiseLike<T> = T | Promise<T>;
290
288
  interface TextPlugin {
291
289
  name: string;
292
290
  paths?: Path2D[];
293
291
  getBoundingBox?: (text: Text) => BoundingBox | undefined;
292
+ update?: (text: Text) => void;
294
293
  updateOrder?: number;
295
- update?: (text: Text) => PromiseLike<void>;
294
+ render?: (ctx: CanvasRenderingContext2D, text: Text) => void;
296
295
  renderOrder?: number;
297
- render?: (ctx: CanvasRenderingContext2D, text: Text) => PromiseLike<void>;
296
+ load?: (text: Text) => Promise<void>;
298
297
  }
299
298
  interface TextOptions {
300
299
  debug?: boolean;
@@ -334,6 +333,8 @@ declare function definePlugin(options: TextPlugin): TextPlugin;
334
333
 
335
334
  declare function measureText(options: TextOptions): Promise<MeasureResult>;
336
335
 
336
+ declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
337
+
337
338
  declare function highlight(): TextPlugin;
338
339
 
339
340
  declare function listStyle(): TextPlugin;
@@ -343,8 +344,6 @@ declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
343
344
 
344
345
  declare function textDecoration(): TextPlugin;
345
346
 
346
- declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
347
-
348
347
  interface ValueContext {
349
348
  total: number;
350
349
  fontSize: number;
@@ -356,5 +355,6 @@ declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, a
356
355
  declare function isEqualValue(val1: any, val2: any): boolean;
357
356
  declare function hexToRgb(hex: string): string | null;
358
357
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
358
+ declare function needsFetch(source: string): boolean;
359
359
 
360
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
360
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, needsFetch, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
package/dist/index.d.mts CHANGED
@@ -121,8 +121,6 @@ interface MeasureDomResult {
121
121
  boundingBox: BoundingBox;
122
122
  }
123
123
  declare class Measurer {
124
- protected _text: Text;
125
- constructor(_text: Text);
126
124
  protected _styleToDomStyle(style: Partial<TextStyle>): Record<string, any>;
127
125
  /**
128
126
  * <section style="...">
@@ -134,7 +132,7 @@ declare class Measurer {
134
132
  * </ul>
135
133
  * </section>
136
134
  */
137
- createDom(): {
135
+ createDom(paragraphs: Paragraph[], rootStyle: TextStyle): {
138
136
  dom: HTMLElement;
139
137
  destory: () => void;
140
138
  };
@@ -143,8 +141,8 @@ declare class Measurer {
143
141
  fragments: MeasuredFragment[];
144
142
  characters: MeasuredCharacter[];
145
143
  };
146
- measureDom(dom: HTMLElement): MeasureDomResult;
147
- measure(dom?: HTMLElement): MeasureDomResult;
144
+ measureDom(paragraphs: Paragraph[], dom: HTMLElement): MeasureDomResult;
145
+ measure(paragraphs: Paragraph[], rootStyle: TextStyle, dom?: HTMLElement): MeasureDomResult;
148
146
  }
149
147
 
150
148
  interface TextRenderOptions {
@@ -201,14 +199,15 @@ declare class Text extends EventEmitter<TextEventMap> {
201
199
  fragmentIndex: number;
202
200
  characterIndex: number;
203
201
  }) => void): this;
202
+ load(): Promise<void>;
204
203
  updateParagraphs(): this;
205
- measure(dom?: HTMLElement | undefined): Promise<MeasureResult>;
204
+ measure(dom?: HTMLElement | undefined): MeasureResult;
206
205
  getGlyphBox(): BoundingBox;
207
206
  updatePathBox(): this;
208
207
  updateBoundingBox(): this;
209
208
  requestUpdate(): this;
210
- update(): Promise<void>;
211
- render(options: TextRenderOptions): Promise<void>;
209
+ update(): this;
210
+ render(options: TextRenderOptions): void;
212
211
  }
213
212
 
214
213
  type Sizeable = `${number}%` | `${number}rem` | number;
@@ -286,15 +285,15 @@ interface ParagraphContent extends Partial<TextStyle> {
286
285
  fragments: FragmentContent[];
287
286
  }
288
287
  type TextContent = string | FragmentContent | ParagraphContent | (string | FragmentContent | ParagraphContent | (string | FragmentContent)[])[];
289
- type PromiseLike<T> = T | Promise<T>;
290
288
  interface TextPlugin {
291
289
  name: string;
292
290
  paths?: Path2D[];
293
291
  getBoundingBox?: (text: Text) => BoundingBox | undefined;
292
+ update?: (text: Text) => void;
294
293
  updateOrder?: number;
295
- update?: (text: Text) => PromiseLike<void>;
294
+ render?: (ctx: CanvasRenderingContext2D, text: Text) => void;
296
295
  renderOrder?: number;
297
- render?: (ctx: CanvasRenderingContext2D, text: Text) => PromiseLike<void>;
296
+ load?: (text: Text) => Promise<void>;
298
297
  }
299
298
  interface TextOptions {
300
299
  debug?: boolean;
@@ -334,6 +333,8 @@ declare function definePlugin(options: TextPlugin): TextPlugin;
334
333
 
335
334
  declare function measureText(options: TextOptions): Promise<MeasureResult>;
336
335
 
336
+ declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
337
+
337
338
  declare function highlight(): TextPlugin;
338
339
 
339
340
  declare function listStyle(): TextPlugin;
@@ -343,8 +344,6 @@ declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
343
344
 
344
345
  declare function textDecoration(): TextPlugin;
345
346
 
346
- declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
347
-
348
347
  interface ValueContext {
349
348
  total: number;
350
349
  fontSize: number;
@@ -356,5 +355,6 @@ declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, a
356
355
  declare function isEqualValue(val1: any, val2: any): boolean;
357
356
  declare function hexToRgb(hex: string): string | null;
358
357
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
358
+ declare function needsFetch(source: string): boolean;
359
359
 
360
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
360
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, needsFetch, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
package/dist/index.d.ts CHANGED
@@ -121,8 +121,6 @@ interface MeasureDomResult {
121
121
  boundingBox: BoundingBox;
122
122
  }
123
123
  declare class Measurer {
124
- protected _text: Text;
125
- constructor(_text: Text);
126
124
  protected _styleToDomStyle(style: Partial<TextStyle>): Record<string, any>;
127
125
  /**
128
126
  * <section style="...">
@@ -134,7 +132,7 @@ declare class Measurer {
134
132
  * </ul>
135
133
  * </section>
136
134
  */
137
- createDom(): {
135
+ createDom(paragraphs: Paragraph[], rootStyle: TextStyle): {
138
136
  dom: HTMLElement;
139
137
  destory: () => void;
140
138
  };
@@ -143,8 +141,8 @@ declare class Measurer {
143
141
  fragments: MeasuredFragment[];
144
142
  characters: MeasuredCharacter[];
145
143
  };
146
- measureDom(dom: HTMLElement): MeasureDomResult;
147
- measure(dom?: HTMLElement): MeasureDomResult;
144
+ measureDom(paragraphs: Paragraph[], dom: HTMLElement): MeasureDomResult;
145
+ measure(paragraphs: Paragraph[], rootStyle: TextStyle, dom?: HTMLElement): MeasureDomResult;
148
146
  }
149
147
 
150
148
  interface TextRenderOptions {
@@ -201,14 +199,15 @@ declare class Text extends EventEmitter<TextEventMap> {
201
199
  fragmentIndex: number;
202
200
  characterIndex: number;
203
201
  }) => void): this;
202
+ load(): Promise<void>;
204
203
  updateParagraphs(): this;
205
- measure(dom?: HTMLElement | undefined): Promise<MeasureResult>;
204
+ measure(dom?: HTMLElement | undefined): MeasureResult;
206
205
  getGlyphBox(): BoundingBox;
207
206
  updatePathBox(): this;
208
207
  updateBoundingBox(): this;
209
208
  requestUpdate(): this;
210
- update(): Promise<void>;
211
- render(options: TextRenderOptions): Promise<void>;
209
+ update(): this;
210
+ render(options: TextRenderOptions): void;
212
211
  }
213
212
 
214
213
  type Sizeable = `${number}%` | `${number}rem` | number;
@@ -286,15 +285,15 @@ interface ParagraphContent extends Partial<TextStyle> {
286
285
  fragments: FragmentContent[];
287
286
  }
288
287
  type TextContent = string | FragmentContent | ParagraphContent | (string | FragmentContent | ParagraphContent | (string | FragmentContent)[])[];
289
- type PromiseLike<T> = T | Promise<T>;
290
288
  interface TextPlugin {
291
289
  name: string;
292
290
  paths?: Path2D[];
293
291
  getBoundingBox?: (text: Text) => BoundingBox | undefined;
292
+ update?: (text: Text) => void;
294
293
  updateOrder?: number;
295
- update?: (text: Text) => PromiseLike<void>;
294
+ render?: (ctx: CanvasRenderingContext2D, text: Text) => void;
296
295
  renderOrder?: number;
297
- render?: (ctx: CanvasRenderingContext2D, text: Text) => PromiseLike<void>;
296
+ load?: (text: Text) => Promise<void>;
298
297
  }
299
298
  interface TextOptions {
300
299
  debug?: boolean;
@@ -334,6 +333,8 @@ declare function definePlugin(options: TextPlugin): TextPlugin;
334
333
 
335
334
  declare function measureText(options: TextOptions): Promise<MeasureResult>;
336
335
 
336
+ declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
337
+
337
338
  declare function highlight(): TextPlugin;
338
339
 
339
340
  declare function listStyle(): TextPlugin;
@@ -343,8 +344,6 @@ declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
343
344
 
344
345
  declare function textDecoration(): TextPlugin;
345
346
 
346
- declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
347
-
348
347
  interface ValueContext {
349
348
  total: number;
350
349
  fontSize: number;
@@ -356,5 +355,6 @@ declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, a
356
355
  declare function isEqualValue(val1: any, val2: any): boolean;
357
356
  declare function hexToRgb(hex: string): string | null;
358
357
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
358
+ declare function needsFetch(source: string): boolean;
359
359
 
360
- export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };
360
+ export { Character, type DrawShapePathsOptions, type FontKerning, type FontStyle, type FontWeight, Fragment, type FragmentContent, type HighlightColormap, type HighlightImage, type HighlightLine, type HighlightReferImage, type HighlightSize, type HighlightThickness, type LinearGradient, type ListStyleColormap, 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 TextDecorationLine, type TextDrawStyle, type TextEventMap, 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, hexToRgb, highlight, isEqualObject, isEqualValue, isNone, listStyle, measureText, needsFetch, parseColor, parseColormap, parseValueNumber, render, renderText, setupView, textDecoration, uploadColor, uploadColors };