modern-text 0.2.35 → 0.2.37

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { BoundingBox, Path2D, Vector2, Matrix3, parseSvg, parseSvgToDom, getPathsBoundingBox } from 'modern-path2d';
1
+ import { BoundingBox, Path2D, Vector2, Matrix3, getPathsBoundingBox, parseSvg } from 'modern-path2d';
2
2
  export * from 'modern-path2d';
3
3
  import { fonts, Woff, Ttf } from 'modern-font';
4
4
  export * from 'modern-font';
@@ -298,7 +298,10 @@ class Character {
298
298
  }
299
299
  }
300
300
  path.addCommands(this._decoration());
301
- path.bold(fontWeightMap[computedStyle.fontWeight ?? 400] * fontSize * 0.05);
301
+ const fontWeight = computedStyle.fontWeight ?? 400;
302
+ if (fontWeight in fontWeightMap) {
303
+ path.bold(fontWeightMap[fontWeight] * fontSize * 0.05);
304
+ }
302
305
  path.style = {
303
306
  fill: computedStyle.color,
304
307
  stroke: computedStyle.textStrokeWidth ? computedStyle.textStrokeColor : "none",
@@ -819,9 +822,7 @@ function getTransform2D(text, style) {
819
822
  return tempM1.clone();
820
823
  }
821
824
 
822
- const defaultOptions = {
823
- referImage: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4="
824
- };
825
+ const defaultReferImage = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3MiIgaGVpZ2h0PSI3MiIgdmlld0JveD0iMCAwIDcyIDcyIiBmaWxsPSJub25lIj48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTMyLjQwMjkgMjhIMzUuMTU5NFYzMy4xNzcxQzM1Ljk4MjEgMzIuMzExNSAzNi45NzEgMzEuODczNyAzOC4wOTQ4IDMxLjg3MzdDMzkuNjY3NiAzMS44NzM3IDQwLjkxNjYgMzIuNDI5NSA0MS44MzkgMzMuNTQzN0w0MS44NDAzIDMzLjU0NTNDNDIuNjcxNyAzNC41NzA1IDQzLjA5MTUgMzUuODU1OSA0My4wOTE1IDM3LjM4NzdDNDMuMDkxNSAzOC45NzYxIDQyLjY3MjkgNDAuMzAyOCA0MS44MTgzIDQxLjMzMDRMNDEuODE3MSA0MS4zMzE4QzQwLjg3MzEgNDIuNDQ2MSAzOS41ODMyIDQzIDM3Ljk3MjEgNDNDMzYuNzQ3NyA0MyAzNS43NDg4IDQyLjY1OTkgMzQuOTk1OCA0MS45NjkzVjQyLjcyNDdIMzIuNDAyOVYyOFpNMzcuNTQyOCAzNC4wOTI0QzM2Ljg1NDkgMzQuMDkyNCAzNi4zMDE0IDM0LjM1NjEgMzUuODQ4NyAzNC45MDA0TDM1Ljg0NTIgMzQuOTA0NkMzNS4zMzU4IDM1LjQ4NTMgMzUuMDc3NiAzNi4yOTc2IDM1LjA3NzYgMzcuMzQ4NFYzNy41MDU3QzM1LjA3NzYgMzguNDY0IDM1LjI3NzIgMzkuMjQ0MyAzNS42OTQzIDM5LjgyNzlDMzYuMTQ0MSA0MC40NTg3IDM2Ljc3MjYgNDAuNzgxMyAzNy42MjQ1IDQwLjc4MTNDMzguNTg3NCA0MC43ODEzIDM5LjI3MDcgNDAuNDUyNyAzOS43MTUyIDM5LjgxMjdDNDAuMDcyOCAzOS4yNjg0IDQwLjI3MzcgMzguNDY3MyA0MC4yNzM3IDM3LjM4NzdDNDAuMjczNyAzNi4zMTA1IDQwLjA1MzMgMzUuNTMxMyAzOS42NzgzIDM1LjAwNzdDMzkuMjM3MSAzNC40MDcxIDM4LjUzNDIgMzQuMDkyNCAzNy41NDI4IDM0LjA5MjRaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZD0iTTQ5Ljg2MTQgMzEuODczN0M0OC4xNTM1IDMxLjg3MzcgNDYuODAxNiAzMi40MjM5IDQ1LjgzNDggMzMuNTM5MkM0NC45MzcgMzQuNTQ3MiA0NC40OTY2IDM1Ljg1NiA0NC40OTY2IDM3LjQyN0M0NC40OTY2IDM5LjAzNjggNDQuOTM2NyA0MC4zNjU5IDQ1Ljg1NTkgNDEuMzk0M0M0Ni44MDMxIDQyLjQ3MDYgNDguMTM0OCA0MyA0OS44MjA1IDQzQzUxLjIyNiA0MyA1Mi4zODI2IDQyLjY1NjMgNTMuMjQ3OSA0MS45Njk3QzU0LjEzNTkgNDEuMjYxNCA1NC43MDYxIDQwLjE4ODcgNTQuOTU3MyAzOC43NzkxTDU1IDM4LjUzOTdINTIuMjQ4NEw1Mi4yMjU5IDM4LjcyMDFDNTIuMTM3OSAzOS40MjUxIDUxLjg5MjUgMzkuOTI3OCA1MS41MTA5IDQwLjI1NThDNTEuMTI5NSA0MC41ODM1IDUwLjU4MzEgNDAuNzYxNiA0OS44NDA5IDQwLjc2MTZDNDkuMDAwMSA0MC43NjE2IDQ4LjM5NDkgNDAuNDcxNSA0Ny45OTA3IDM5LjkyMzdMNDcuOTg3NCAzOS45MTk0QzQ3LjUzNTYgMzkuMzQwMSA0Ny4zMTQ0IDM4LjUwNjIgNDcuMzE0NCAzNy40MDc0QzQ3LjMxNDQgMzYuMzMyMiA0Ny41NTQ0IDM1LjUxNzcgNDguMDA1OCAzNC45NTY4TDQ4LjAwNzggMzQuOTU0M0M0OC40NTM3IDM0LjM4MjUgNDkuMDYxOCAzNC4xMTIxIDQ5Ljg2MTQgMzQuMTEyMUM1MC41MjMgMzQuMTEyMSA1MS4wNDUxIDM0LjI2MTUgNTEuNDI3MiAzNC41NDA3QzUxLjc4ODQgMzQuODE5NCA1Mi4wNTMgMzUuMjQ0NyA1Mi4xODgxIDM1Ljg1NzFMNTIuMjIzOSAzNi4wMTk0SDU0Ljk1NDhMNTQuOTE3IDM1Ljc4MzVDNTQuNzA2MyAzNC40NjYgNTQuMTUzNiAzMy40NzAxIDUzLjI2MzQgMzIuODAxOUw1My4yNjAyIDMyLjc5OTVDNTIuMzk1MSAzMi4xNzU1IDUxLjI2MjEgMzEuODczNyA0OS44NjE0IDMxLjg3MzdaIiBmaWxsPSIjMjIyNTI5Ii8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yNS43NTYxIDI4LjI3NTNIMjIuNzQ0TDE3IDQyLjcyNDdIMjAuMDE0MUwyMS4zNDI5IDM5LjIwNDlIMjcuMTU3MkwyOC40ODYgNDIuNzI0N0gzMS41MDAxTDI1Ljc1NjEgMjguMjc1M1pNMjIuMjEyNSAzNi45MDc2TDI0LjI1OTYgMzEuNDUzOUwyNi4yODg1IDM2LjkwNzZIMjIuMjEyNVoiIGZpbGw9IiMyMjI1MjkiLz48L3N2Zz4=";
825
826
  function parseCharsPerRepeat(size, fontSize, total) {
826
827
  if (size === "cover") {
827
828
  return 0;
@@ -852,11 +853,48 @@ function parseStrokeWidthScale(strokeWidth, fontSize, total) {
852
853
  return strokeWidth / total;
853
854
  }
854
855
  }
855
- function highlight(options = {}) {
856
- const config = { ...defaultOptions, ...options };
857
- const referPaths = parseSvg(config.referImage);
856
+ function getTransformMatrix(a, b, c, isVertical) {
857
+ let scale;
858
+ if (isVertical) {
859
+ scale = {
860
+ x: c.width / b.height,
861
+ y: c.height / b.width
862
+ };
863
+ } else {
864
+ scale = {
865
+ x: c.width / b.width,
866
+ y: c.height / b.height
867
+ };
868
+ }
869
+ const offset = c.getCenterPoint().add(
870
+ a.getCenterPoint().sub(b.getCenterPoint()).scale(scale.x, scale.y)
871
+ ).sub({
872
+ x: a.width * scale.x / 2,
873
+ y: a.height * scale.y / 2
874
+ });
875
+ const m = new Matrix3();
876
+ m.translate(-a.left, -a.top);
877
+ if (isVertical) {
878
+ m.translate(-a.width / 2, -a.height / 2);
879
+ m.rotate(Math.PI / 2);
880
+ m.translate(a.width / 2, a.height / 2);
881
+ }
882
+ m.scale(scale.x, scale.y);
883
+ m.translate(offset.x, offset.y);
884
+ return m;
885
+ }
886
+ function highlight() {
858
887
  const paths = [];
859
888
  const clipRects = [];
889
+ const svgStringToSvgPaths = /* @__PURE__ */ new Map();
890
+ function getPaths(svg) {
891
+ let paths2 = svgStringToSvgPaths.get(svg);
892
+ if (!paths2) {
893
+ paths2 = parseSvg(svg);
894
+ svgStringToSvgPaths.set(svg, paths2);
895
+ }
896
+ return paths2;
897
+ }
860
898
  return definePlugin({
861
899
  name: "highlight",
862
900
  paths,
@@ -886,24 +924,24 @@ function highlight(options = {}) {
886
924
  };
887
925
  }).forEach((group2) => {
888
926
  const { style, box: groupBox } = group2;
889
- const { fontSize } = style;
927
+ const { fontSize, writingMode } = style;
928
+ const isVertical = writingMode.includes("vertical");
890
929
  const strokeWidthScale = parseStrokeWidthScale(style.highlightStrokeWidth, fontSize, groupBox.width);
891
930
  const charsPerRepeat = parseCharsPerRepeat(style.highlightSize, fontSize, groupBox.width);
892
931
  const highlightOverflow = isNone(style.highlightOverflow) ? charsPerRepeat ? "hidden" : "visible" : style.highlightOverflow;
893
- const svg = parseSvgToDom(style.highlightImage);
894
- const svgPaths = parseSvg(svg);
895
- const box = getPathsBoundingBox(svgPaths, false);
896
- const refBox = getPathsBoundingBox(referPaths, false);
897
- const scaleWidth = charsPerRepeat ? fontSize * charsPerRepeat : groupBox.width;
898
- const scaleX = scaleWidth / refBox.width;
899
- const scaleY = groupBox.height / refBox.height;
932
+ const refPaths = getPaths(isNone(style.highlightReferImage) ? defaultReferImage : style.highlightReferImage);
933
+ const svgPaths = getPaths(style.highlightImage);
934
+ const box = getPathsBoundingBox(svgPaths, true);
935
+ const refBox = getPathsBoundingBox(refPaths, false);
936
+ const unitWidth = charsPerRepeat ? fontSize * charsPerRepeat : groupBox.width;
937
+ const transform = getTransformMatrix(
938
+ box,
939
+ refBox,
940
+ new BoundingBox(groupBox.left, groupBox.top, unitWidth, groupBox.height),
941
+ isVertical
942
+ );
900
943
  const styleScale = fontSize / box.width * 2;
901
- const unitWidth = box.width * scaleX;
902
944
  const total = Math.ceil(groupBox.width / unitWidth);
903
- const transform = new Matrix3().translate(-box.left, -box.top).scale(scaleX, scaleY).translate(groupBox.left, groupBox.top).translate(
904
- (box.left - refBox.left) * scaleX,
905
- (box.top - refBox.top) * scaleY
906
- );
907
945
  for (let i = 0; i < total; i++) {
908
946
  const _transform = transform.clone().translate(i * unitWidth, 0);
909
947
  svgPaths.forEach((original) => {
@@ -1059,6 +1097,7 @@ const defaultTextStyles = {
1059
1097
  listStyleSize: "cover",
1060
1098
  listStylePosition: "outside",
1061
1099
  // highlight
1100
+ highlightReferImage: "none",
1062
1101
  highlightImage: "none",
1063
1102
  highlightSize: "cover",
1064
1103
  highlightStrokeWidth: "100%",
@@ -1083,7 +1122,7 @@ class Text {
1083
1122
  this.style = style;
1084
1123
  this.measureDom = measureDom;
1085
1124
  this.effects = effects;
1086
- this.use(effect()).use(highlight(options.highlight)).use(listStyle());
1125
+ this.use(effect()).use(highlight()).use(listStyle());
1087
1126
  }
1088
1127
  get fontSize() {
1089
1128
  return this.computedStyle.fontSize;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modern-text",
3
3
  "type": "module",
4
- "version": "0.2.35",
4
+ "version": "0.2.37",
5
5
  "packageManager": "pnpm@9.9.0",
6
6
  "description": "Measure and render text in a way that describes the DOM.",
7
7
  "author": "wxm",
@@ -58,7 +58,7 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "modern-font": "^0.2.1",
61
- "modern-path2d": "^0.2.2"
61
+ "modern-path2d": "^0.2.4"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@antfu/eslint-config": "^3.7.3",