modern-text 0.5.13 → 0.6.1

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
+ createParagraphDom(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
  });
@@ -598,12 +597,41 @@ class Measurer {
598
597
  destory: () => dom.parentNode?.removeChild(dom)
599
598
  };
600
599
  }
601
- _measureDom(dom) {
600
+ measureDomText(text) {
601
+ const range = document.createRange();
602
+ range.selectNodeContents(text);
603
+ const data = text.data ?? "";
604
+ let offset = 0;
605
+ return Array.from(data).map((char) => {
606
+ const start = offset += data.substring(offset).indexOf(char);
607
+ const end = start + char.length;
608
+ offset += char.length;
609
+ range.setStart(text, Math.max(start, 0));
610
+ range.setEnd(text, end);
611
+ const rects = range.getClientRects?.() ?? [range.getBoundingClientRect()];
612
+ let rect = rects[rects.length - 1];
613
+ if (rects.length > 1 && rect.width < 2) {
614
+ rect = rects[rects.length - 2];
615
+ }
616
+ const content = range.toString();
617
+ if (content !== "" && rect && rect.width + rect.height !== 0) {
618
+ return {
619
+ content,
620
+ top: rect.top,
621
+ left: rect.left,
622
+ height: rect.height,
623
+ width: rect.width
624
+ };
625
+ }
626
+ return void 0;
627
+ }).filter(Boolean);
628
+ }
629
+ measureDom(dom) {
602
630
  const paragraphs = [];
603
631
  const fragments = [];
604
632
  const characters = [];
605
- dom.querySelectorAll("li").forEach((li, paragraphIndex) => {
606
- const pBox = li.getBoundingClientRect();
633
+ dom.querySelectorAll("li").forEach((pDom, paragraphIndex) => {
634
+ const pBox = pDom.getBoundingClientRect();
607
635
  paragraphs.push({
608
636
  paragraphIndex,
609
637
  left: pBox.left,
@@ -611,8 +639,8 @@ class Measurer {
611
639
  width: pBox.width,
612
640
  height: pBox.height
613
641
  });
614
- li.querySelectorAll("span").forEach((span, fragmentIndex) => {
615
- const fBox = span.getBoundingClientRect();
642
+ pDom.querySelectorAll(":scope > *").forEach((fDom, fragmentIndex) => {
643
+ const fBox = fDom.getBoundingClientRect();
616
644
  fragments.push({
617
645
  paragraphIndex,
618
646
  fragmentIndex,
@@ -621,37 +649,32 @@ class Measurer {
621
649
  width: fBox.width,
622
650
  height: fBox.height
623
651
  });
624
- const text = span.firstChild;
625
- if (text instanceof window.Text) {
626
- const range = document.createRange();
627
- range.selectNodeContents(text);
628
- const data = text.data ?? "";
629
- let offset = 0;
630
- Array.from(data).forEach((char, index) => {
631
- const start = offset += data.substring(offset).indexOf(char);
632
- const end = start + char.length;
633
- offset += char.length;
634
- range.setStart(text, Math.max(start, 0));
635
- range.setEnd(text, end);
636
- const rects = range.getClientRects?.() ?? [range.getBoundingClientRect()];
637
- let rect = rects[rects.length - 1];
638
- if (rects.length > 1 && rect.width < 2) {
639
- rect = rects[rects.length - 2];
640
- }
641
- const content = range.toString();
642
- if (content !== "" && rect && rect.width + rect.height !== 0) {
643
- characters.push({
644
- content,
645
- newParagraphIndex: -1,
646
- paragraphIndex,
647
- fragmentIndex,
648
- characterIndex: index,
649
- top: rect.top,
650
- left: rect.left,
651
- height: rect.height,
652
- width: rect.width,
653
- textWidth: -1,
654
- textHeight: -1
652
+ let characterIndex = 0;
653
+ if (fDom.firstChild instanceof window.Text) {
654
+ this.measureDomText(fDom.firstChild).forEach((char) => {
655
+ characters.push({
656
+ ...char,
657
+ newParagraphIndex: -1,
658
+ paragraphIndex,
659
+ fragmentIndex,
660
+ characterIndex: characterIndex++,
661
+ textWidth: -1,
662
+ textHeight: -1
663
+ });
664
+ });
665
+ } else {
666
+ fDom.querySelectorAll(":scope > *").forEach((cDom) => {
667
+ if (cDom.firstChild instanceof window.Text) {
668
+ this.measureDomText(cDom.firstChild).forEach((char) => {
669
+ characters.push({
670
+ ...char,
671
+ newParagraphIndex: -1,
672
+ paragraphIndex,
673
+ fragmentIndex,
674
+ characterIndex: characterIndex++,
675
+ textWidth: -1,
676
+ textHeight: -1
677
+ });
655
678
  });
656
679
  }
657
680
  });
@@ -664,10 +687,9 @@ class Measurer {
664
687
  characters
665
688
  };
666
689
  }
667
- measureDom(dom) {
668
- const { paragraphs } = this._text;
690
+ measureParagraphDom(paragraphs, dom) {
669
691
  const rect = dom.getBoundingClientRect();
670
- const measured = this._measureDom(dom);
692
+ const measured = this.measureDom(dom);
671
693
  measured.paragraphs.forEach((p) => {
672
694
  const _p = paragraphs[p.paragraphIndex];
673
695
  _p.lineBox.left = p.left - rect.left;
@@ -717,12 +739,12 @@ class Measurer {
717
739
  boundingBox: new modernPath2d.BoundingBox(0, 0, rect.width, rect.height)
718
740
  };
719
741
  }
720
- measure(dom) {
742
+ measure(paragraphs, rootStyle, dom) {
721
743
  let destory;
722
744
  if (!dom) {
723
- ({ dom, destory } = this.createDom());
745
+ ({ dom, destory } = this.createParagraphDom(paragraphs, rootStyle));
724
746
  }
725
- const result = this.measureDom(dom);
747
+ const result = this.measureParagraphDom(paragraphs, dom);
726
748
  destory?.();
727
749
  return result;
728
750
  }
@@ -825,33 +847,74 @@ class EventEmitter {
825
847
  function highlight() {
826
848
  const paths = [];
827
849
  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());
850
+ const loaded = /* @__PURE__ */ new Map();
851
+ const parsed = /* @__PURE__ */ new Map();
852
+ async function loadSvg(svg) {
853
+ if (!loaded.has(svg)) {
854
+ loaded.set(svg, svg);
855
+ try {
856
+ loaded.set(svg, await fetch(svg).then((rep) => rep.text()));
857
+ } catch (err) {
858
+ console.warn(err);
859
+ loaded.delete(svg);
834
860
  }
835
- const dom = modernPath2d.parseSvgToDom(svg);
861
+ }
862
+ }
863
+ function getPaths(svg) {
864
+ let result = parsed.get(svg);
865
+ if (!result) {
866
+ const dom = modernPath2d.parseSvgToDom(
867
+ needsFetch(svg) ? loaded.get(svg) ?? svg : svg
868
+ );
836
869
  const paths2 = modernPath2d.parseSvg(dom);
837
870
  result = { dom, paths: paths2 };
838
- svgStringToSvgPaths.set(svg, result);
871
+ parsed.set(svg, result);
839
872
  }
840
873
  return result;
841
874
  }
842
875
  return definePlugin({
843
876
  name: "highlight",
844
877
  paths,
845
- update: async (text) => {
878
+ load: async (text) => {
879
+ const promises = [];
880
+ text.forEachCharacter((character) => {
881
+ const { computedStyle: style } = character;
882
+ const { highlightImage, highlightReferImage } = style;
883
+ if (needsFetch(highlightImage)) {
884
+ promises.push(loadSvg(highlightImage));
885
+ }
886
+ if (needsFetch(highlightReferImage)) {
887
+ promises.push(loadSvg(highlightReferImage));
888
+ }
889
+ });
890
+ await Promise.all(promises);
891
+ },
892
+ update: (text) => {
846
893
  clipRects.length = 0;
847
894
  paths.length = 0;
848
895
  let groups = [];
849
896
  let group;
850
897
  let prevStyle;
851
898
  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) {
899
+ const {
900
+ computedStyle: style
901
+ } = character;
902
+ const {
903
+ highlightImage
904
+ } = style;
905
+ if (!isNone(highlightImage)) {
906
+ const {
907
+ inlineBox,
908
+ isVertical
909
+ } = character;
910
+ const {
911
+ fontSize,
912
+ highlightColormap,
913
+ highlightLine,
914
+ highlightSize,
915
+ highlightThickness
916
+ } = style;
917
+ 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
918
  group.push(character);
856
919
  } else {
857
920
  group = [];
@@ -870,8 +933,12 @@ function highlight() {
870
933
  for (let i = 0; i < groups.length; i++) {
871
934
  const characters = groups[i];
872
935
  const char = characters[0];
873
- const groupBox = modernPath2d.BoundingBox.from(...characters.map((c) => c.glyphBox));
874
- const { computedStyle: style } = char;
936
+ const groupBox = modernPath2d.BoundingBox.from(
937
+ ...characters.filter((c) => c.glyphBox).map((c) => c.glyphBox)
938
+ );
939
+ const {
940
+ computedStyle: style
941
+ } = char;
875
942
  const {
876
943
  fontSize,
877
944
  writingMode,
@@ -885,7 +952,7 @@ function highlight() {
885
952
  const isVertical = writingMode.includes("vertical");
886
953
  const thickness = parseValueNumber(highlightThickness, { fontSize, total: groupBox.width }) / groupBox.width;
887
954
  const colormap = parseColormap(highlightColormap);
888
- const { paths: svgPaths, dom: svgDom } = await getPaths(highlightImage);
955
+ const { paths: svgPaths, dom: svgDom } = getPaths(highlightImage);
889
956
  const aBox = modernPath2d.getPathsBoundingBox(svgPaths, true);
890
957
  const styleScale = fontSize / aBox.width * 2;
891
958
  const cBox = new modernPath2d.BoundingBox().copy(groupBox);
@@ -901,7 +968,7 @@ function highlight() {
901
968
  cBox.width = userWidth;
902
969
  }
903
970
  if (!isNone(highlightReferImage) && isNone(highlightLine)) {
904
- const bBox = modernPath2d.getPathsBoundingBox((await getPaths(highlightReferImage)).paths, true);
971
+ const bBox = modernPath2d.getPathsBoundingBox(getPaths(highlightReferImage).paths, true);
905
972
  aBox.copy(bBox);
906
973
  } else {
907
974
  let line;
@@ -1052,8 +1119,16 @@ function listStyle() {
1052
1119
  const { paragraphs, isVertical, fontSize } = text;
1053
1120
  const padding = fontSize * 0.45;
1054
1121
  paragraphs.forEach((paragraph) => {
1055
- const { computedStyle: style } = paragraph;
1056
- const { listStyleImage, listStyleColormap, listStyleSize, listStyleType, color } = style;
1122
+ const {
1123
+ computedStyle: style
1124
+ } = paragraph;
1125
+ const {
1126
+ color,
1127
+ listStyleImage,
1128
+ listStyleColormap,
1129
+ listStyleSize,
1130
+ listStyleType
1131
+ } = style;
1057
1132
  const colormap = parseColormap(listStyleColormap);
1058
1133
  let size = listStyleSize;
1059
1134
  let image;
@@ -1082,18 +1157,10 @@ function listStyle() {
1082
1157
  const m = new modernPath2d.Matrix3();
1083
1158
  if (isVertical) {
1084
1159
  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);
1160
+ 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
1161
  } else {
1091
1162
  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);
1163
+ 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
1164
  }
1098
1165
  paths.push(...imagePaths.map((p) => {
1099
1166
  const path = p.clone();
@@ -1229,11 +1296,24 @@ function textDecoration() {
1229
1296
  let group;
1230
1297
  let prevStyle;
1231
1298
  text.forEachCharacter((character) => {
1232
- const { computedStyle: style, isVertical, inlineBox, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = character;
1233
- if (!isNone(style.textDecoration)) {
1299
+ const {
1300
+ computedStyle: style,
1301
+ isVertical,
1302
+ inlineBox,
1303
+ underlinePosition,
1304
+ underlineThickness,
1305
+ strikeoutPosition,
1306
+ strikeoutSize
1307
+ } = character;
1308
+ const {
1309
+ color,
1310
+ textDecoration: textDecoration2,
1311
+ writingMode
1312
+ } = style;
1313
+ if (!isNone(textDecoration2)) {
1234
1314
  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) {
1315
+ if (prevStyle?.textDecoration === textDecoration2 && prevStyle?.writingMode === writingMode && prevStyle?.color === color && (isVertical ? group[0].inlineBox.left === inlineBox.left : group[0].inlineBox.top === inlineBox.top)) {
1316
+ switch (textDecoration2) {
1237
1317
  case "underline":
1238
1318
  if (group[0].underlinePosition === underlinePosition && group[0].underlineThickness === underlineThickness) {
1239
1319
  flag = true;
@@ -1259,8 +1339,18 @@ function textDecoration() {
1259
1339
  }
1260
1340
  });
1261
1341
  groups.forEach((group2) => {
1262
- const { computedStyle: style, isVertical, underlinePosition, underlineThickness, strikeoutPosition, strikeoutSize } = group2[0];
1263
- const { textDecoration: textDecoration2, color } = style;
1342
+ const {
1343
+ computedStyle: style,
1344
+ isVertical,
1345
+ underlinePosition,
1346
+ underlineThickness,
1347
+ strikeoutPosition,
1348
+ strikeoutSize
1349
+ } = group2[0];
1350
+ const {
1351
+ color,
1352
+ textDecoration: textDecoration2
1353
+ } = style;
1264
1354
  const { left, top, width, height } = modernPath2d.BoundingBox.from(...group2.map((c) => c.inlineBox));
1265
1355
  let position = isVertical ? left + width : top;
1266
1356
  const direction = isVertical ? -1 : 1;
@@ -1403,7 +1493,7 @@ class Text extends EventEmitter {
1403
1493
  __publicField(this, "glyphBox", new modernPath2d.BoundingBox());
1404
1494
  __publicField(this, "pathBox", new modernPath2d.BoundingBox());
1405
1495
  __publicField(this, "boundingBox", new modernPath2d.BoundingBox());
1406
- __publicField(this, "measurer", new Measurer(this));
1496
+ __publicField(this, "measurer", new Measurer());
1407
1497
  __publicField(this, "plugins", /* @__PURE__ */ new Map());
1408
1498
  __publicField(this, "fonts");
1409
1499
  this.debug = options.debug ?? false;
@@ -1437,6 +1527,9 @@ class Text extends EventEmitter {
1437
1527
  });
1438
1528
  return this;
1439
1529
  }
1530
+ async load() {
1531
+ await Promise.all(Array.from(this.plugins.values()).map((p) => p.load?.(this)));
1532
+ }
1440
1533
  updateParagraphs() {
1441
1534
  this.computedStyle = { ...defaultTextStyles, ...this.style };
1442
1535
  let { content, computedStyle: style } = this;
@@ -1488,7 +1581,7 @@ class Text extends EventEmitter {
1488
1581
  this.paragraphs = paragraphs;
1489
1582
  return this;
1490
1583
  }
1491
- async measure(dom = this.measureDom) {
1584
+ measure(dom = this.measureDom) {
1492
1585
  const old = {
1493
1586
  paragraphs: this.paragraphs,
1494
1587
  lineBox: this.lineBox,
@@ -1498,18 +1591,16 @@ class Text extends EventEmitter {
1498
1591
  boundingBox: this.boundingBox
1499
1592
  };
1500
1593
  this.updateParagraphs();
1501
- const result = this.measurer.measure(dom);
1594
+ const result = this.measurer.measure(this.paragraphs, this.computedStyle, dom);
1502
1595
  this.paragraphs = result.paragraphs;
1503
1596
  this.lineBox = result.boundingBox;
1504
1597
  this.characters.forEach((c) => {
1505
1598
  c.update(this.fonts);
1506
1599
  });
1507
1600
  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
- }
1601
+ Array.from(this.plugins.values()).sort((a, b) => (a.updateOrder ?? 0) - (b.updateOrder ?? 0)).forEach((plugin) => {
1602
+ plugin.update?.(this);
1603
+ });
1513
1604
  this.glyphBox = this.getGlyphBox();
1514
1605
  this.updatePathBox().updateBoundingBox();
1515
1606
  for (const key in old) {
@@ -1565,30 +1656,28 @@ class Text extends EventEmitter {
1565
1656
  this.needsUpdate = true;
1566
1657
  return this;
1567
1658
  }
1568
- async update() {
1569
- const result = await this.measure();
1659
+ update() {
1660
+ const result = this.measure();
1570
1661
  for (const key in result) {
1571
1662
  this[key] = result[key];
1572
1663
  }
1573
1664
  this.emit("update", { text: this });
1665
+ return this;
1574
1666
  }
1575
- async render(options) {
1667
+ render(options) {
1576
1668
  const { view, pixelRatio = 2 } = options;
1577
1669
  const ctx = view.getContext("2d");
1578
1670
  if (!ctx) {
1579
1671
  return;
1580
1672
  }
1581
1673
  if (this.needsUpdate) {
1582
- await this.update();
1674
+ this.update();
1583
1675
  }
1584
1676
  setupView(ctx, pixelRatio, this.boundingBox);
1585
1677
  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];
1678
+ Array.from(this.plugins.values()).sort((a, b) => (a.renderOrder ?? 0) - (b.renderOrder ?? 0)).forEach((plugin) => {
1590
1679
  if (plugin.render) {
1591
- await plugin.render?.(ctx, this);
1680
+ plugin.render?.(ctx, this);
1592
1681
  } else if (plugin.paths) {
1593
1682
  const style = this.computedStyle;
1594
1683
  plugin.paths.forEach((path) => {
@@ -1599,17 +1688,21 @@ class Text extends EventEmitter {
1599
1688
  });
1600
1689
  });
1601
1690
  }
1602
- }
1691
+ });
1603
1692
  this.emit("render", { text: this, view, pixelRatio });
1604
1693
  }
1605
1694
  }
1606
1695
 
1607
- function measureText(options) {
1608
- return new Text(options).measure();
1696
+ async function measureText(options) {
1697
+ const text = new Text(options);
1698
+ await text.load();
1699
+ return text.measure();
1609
1700
  }
1610
1701
 
1611
- function renderText(options) {
1612
- return new Text(options).render(options);
1702
+ async function renderText(options) {
1703
+ const text = new Text(options);
1704
+ await text.load();
1705
+ text.render(options);
1613
1706
  }
1614
1707
 
1615
1708
  exports.Character = Character;
@@ -1629,6 +1722,7 @@ exports.isEqualValue = isEqualValue;
1629
1722
  exports.isNone = isNone;
1630
1723
  exports.listStyle = listStyle;
1631
1724
  exports.measureText = measureText;
1725
+ exports.needsFetch = needsFetch;
1632
1726
  exports.parseColor = parseColor;
1633
1727
  exports.parseColormap = parseColormap;
1634
1728
  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,17 +132,24 @@ declare class Measurer {
134
132
  * </ul>
135
133
  * </section>
136
134
  */
137
- createDom(): {
135
+ createParagraphDom(paragraphs: Paragraph[], rootStyle: TextStyle): {
138
136
  dom: HTMLElement;
139
137
  destory: () => void;
140
138
  };
141
- protected _measureDom(dom: HTMLElement): {
139
+ measureDomText(text: Text): {
140
+ content: string;
141
+ top: number;
142
+ left: number;
143
+ width: number;
144
+ height: number;
145
+ }[];
146
+ measureDom(dom: HTMLElement): {
142
147
  paragraphs: MeasuredParagraph[];
143
148
  fragments: MeasuredFragment[];
144
149
  characters: MeasuredCharacter[];
145
150
  };
146
- measureDom(dom: HTMLElement): MeasureDomResult;
147
- measure(dom?: HTMLElement): MeasureDomResult;
151
+ measureParagraphDom(paragraphs: Paragraph[], dom: HTMLElement): MeasureDomResult;
152
+ measure(paragraphs: Paragraph[], rootStyle: TextStyle, dom?: HTMLElement): MeasureDomResult;
148
153
  }
149
154
 
150
155
  interface TextRenderOptions {
@@ -162,19 +167,19 @@ interface MeasureResult {
162
167
  declare const defaultTextStyles: TextStyle;
163
168
  interface TextEventMap {
164
169
  update: {
165
- text: Text;
170
+ text: Text$1;
166
171
  };
167
172
  measure: {
168
- text: Text;
173
+ text: Text$1;
169
174
  result: MeasureResult;
170
175
  };
171
176
  render: {
172
- text: Text;
177
+ text: Text$1;
173
178
  view: HTMLCanvasElement;
174
179
  pixelRatio: number;
175
180
  };
176
181
  }
177
- declare class Text extends EventEmitter<TextEventMap> {
182
+ declare class Text$1 extends EventEmitter<TextEventMap> {
178
183
  debug: boolean;
179
184
  content: TextContent;
180
185
  style: Partial<TextStyle>;
@@ -201,14 +206,15 @@ declare class Text extends EventEmitter<TextEventMap> {
201
206
  fragmentIndex: number;
202
207
  characterIndex: number;
203
208
  }) => void): this;
209
+ load(): Promise<void>;
204
210
  updateParagraphs(): this;
205
- measure(dom?: HTMLElement | undefined): Promise<MeasureResult>;
211
+ measure(dom?: HTMLElement | undefined): MeasureResult;
206
212
  getGlyphBox(): BoundingBox;
207
213
  updatePathBox(): this;
208
214
  updateBoundingBox(): this;
209
215
  requestUpdate(): this;
210
- update(): Promise<void>;
211
- render(options: TextRenderOptions): Promise<void>;
216
+ update(): this;
217
+ render(options: TextRenderOptions): void;
212
218
  }
213
219
 
214
220
  type Sizeable = `${number}%` | `${number}rem` | number;
@@ -286,15 +292,15 @@ interface ParagraphContent extends Partial<TextStyle> {
286
292
  fragments: FragmentContent[];
287
293
  }
288
294
  type TextContent = string | FragmentContent | ParagraphContent | (string | FragmentContent | ParagraphContent | (string | FragmentContent)[])[];
289
- type PromiseLike<T> = T | Promise<T>;
290
295
  interface TextPlugin {
291
296
  name: string;
292
297
  paths?: Path2D[];
293
- getBoundingBox?: (text: Text) => BoundingBox | undefined;
298
+ getBoundingBox?: (text: Text$1) => BoundingBox | undefined;
299
+ update?: (text: Text$1) => void;
294
300
  updateOrder?: number;
295
- update?: (text: Text) => PromiseLike<void>;
301
+ render?: (ctx: CanvasRenderingContext2D, text: Text$1) => void;
296
302
  renderOrder?: number;
297
- render?: (ctx: CanvasRenderingContext2D, text: Text) => PromiseLike<void>;
303
+ load?: (text: Text$1) => Promise<void>;
298
304
  }
299
305
  interface TextOptions {
300
306
  debug?: boolean;
@@ -328,23 +334,23 @@ declare function drawPath(options: DrawShapePathsOptions): void;
328
334
 
329
335
  declare function setupView(ctx: CanvasRenderingContext2D, pixelRatio: number, boundingBox: BoundingBox): void;
330
336
 
331
- declare function uploadColors(ctx: CanvasRenderingContext2D, text: Text): void;
337
+ declare function uploadColors(ctx: CanvasRenderingContext2D, text: Text$1): void;
332
338
 
333
339
  declare function definePlugin(options: TextPlugin): TextPlugin;
334
340
 
335
341
  declare function measureText(options: TextOptions): Promise<MeasureResult>;
336
342
 
343
+ declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
344
+
337
345
  declare function highlight(): TextPlugin;
338
346
 
339
347
  declare function listStyle(): TextPlugin;
340
348
 
341
349
  declare function render(): TextPlugin;
342
- declare function getTransform2D(text: Text, style: Partial<TextStyle>): Matrix3;
350
+ declare function getTransform2D(text: Text$1, style: Partial<TextStyle>): Matrix3;
343
351
 
344
352
  declare function textDecoration(): TextPlugin;
345
353
 
346
- declare function renderText(options: TextOptions & TextRenderOptions): Promise<void>;
347
-
348
354
  interface ValueContext {
349
355
  total: number;
350
356
  fontSize: number;
@@ -356,5 +362,6 @@ declare function isEqualObject(obj1: Record<string, any>, obj2: Record<string, a
356
362
  declare function isEqualValue(val1: any, val2: any): boolean;
357
363
  declare function hexToRgb(hex: string): string | null;
358
364
  declare function filterEmpty(val: Record<string, any> | undefined): Record<string, any> | undefined;
365
+ declare function needsFetch(source: string): boolean;
359
366
 
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 };
367
+ 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$1 as 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 };