modern-text 0.2.41 → 0.2.43
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/README.md +6 -25
- package/dist/index.cjs +98 -75
- package/dist/index.d.cts +63 -91
- package/dist/index.d.mts +63 -91
- package/dist/index.d.ts +63 -91
- package/dist/index.js +4 -4
- package/dist/index.mjs +97 -76
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -122,6 +122,14 @@ const set2 = /* @__PURE__ */ new Set([
|
|
|
122
122
|
"\u2019",
|
|
123
123
|
"\u02DC"
|
|
124
124
|
]);
|
|
125
|
+
const fsSelectionMap = {
|
|
126
|
+
1: "italic",
|
|
127
|
+
32: "bold"
|
|
128
|
+
};
|
|
129
|
+
const macStyleMap = {
|
|
130
|
+
1: "italic",
|
|
131
|
+
2: "bold"
|
|
132
|
+
};
|
|
125
133
|
const fontWeightMap = {
|
|
126
134
|
100: -0.2,
|
|
127
135
|
200: -0.1,
|
|
@@ -201,17 +209,19 @@ class Character {
|
|
|
201
209
|
if (!font) {
|
|
202
210
|
return this;
|
|
203
211
|
}
|
|
212
|
+
this.updateGlyph(font);
|
|
204
213
|
const {
|
|
205
214
|
isVertical,
|
|
206
215
|
content,
|
|
207
|
-
computedStyle,
|
|
216
|
+
computedStyle: style,
|
|
208
217
|
baseline,
|
|
209
218
|
inlineBox
|
|
210
|
-
} = this
|
|
211
|
-
const { os2, ascender, descender } = font;
|
|
219
|
+
} = this;
|
|
220
|
+
const { os2, head, ascender, descender } = font;
|
|
212
221
|
const typoAscender = os2.sTypoAscender;
|
|
222
|
+
const fontStyle = fsSelectionMap[os2.fsSelection] ?? macStyleMap[head.macStyle];
|
|
213
223
|
const { left, top } = inlineBox;
|
|
214
|
-
const
|
|
224
|
+
const needsItalic = style.fontStyle === "italic" && fontStyle !== "italic";
|
|
215
225
|
let x = left;
|
|
216
226
|
let y = top + baseline;
|
|
217
227
|
let glyphIndex;
|
|
@@ -225,13 +235,13 @@ class Character {
|
|
|
225
235
|
}
|
|
226
236
|
if (isVertical && !set1.has(content) && (content.codePointAt(0) <= 256 || set2.has(content))) {
|
|
227
237
|
path.addCommands(
|
|
228
|
-
font.getPathCommands(content, x, top + baseline - (inlineBox.height - inlineBox.width) / 2, fontSize) ?? []
|
|
238
|
+
font.getPathCommands(content, x, top + baseline - (inlineBox.height - inlineBox.width) / 2, style.fontSize) ?? []
|
|
229
239
|
);
|
|
230
240
|
const point = {
|
|
231
241
|
y: top - (inlineBox.height - inlineBox.width) / 2 + inlineBox.height / 2,
|
|
232
242
|
x: x + inlineBox.width / 2
|
|
233
243
|
};
|
|
234
|
-
if (
|
|
244
|
+
if (needsItalic) {
|
|
235
245
|
this._italic(
|
|
236
246
|
path,
|
|
237
247
|
isVertical ? {
|
|
@@ -244,9 +254,9 @@ class Character {
|
|
|
244
254
|
} else {
|
|
245
255
|
if (glyphIndex !== void 0) {
|
|
246
256
|
path.addCommands(
|
|
247
|
-
font.glyphs.get(glyphIndex).getPathCommands(x, y, fontSize)
|
|
257
|
+
font.glyphs.get(glyphIndex).getPathCommands(x, y, style.fontSize)
|
|
248
258
|
);
|
|
249
|
-
if (
|
|
259
|
+
if (needsItalic) {
|
|
250
260
|
this._italic(
|
|
251
261
|
path,
|
|
252
262
|
isVertical ? {
|
|
@@ -257,9 +267,9 @@ class Character {
|
|
|
257
267
|
}
|
|
258
268
|
} else {
|
|
259
269
|
path.addCommands(
|
|
260
|
-
font.getPathCommands(content, x, y, fontSize) ?? []
|
|
270
|
+
font.getPathCommands(content, x, y, style.fontSize) ?? []
|
|
261
271
|
);
|
|
262
|
-
if (
|
|
272
|
+
if (needsItalic) {
|
|
263
273
|
this._italic(
|
|
264
274
|
path,
|
|
265
275
|
isVertical ? { x: x + inlineBox.height / 2, y } : void 0
|
|
@@ -268,14 +278,14 @@ class Character {
|
|
|
268
278
|
}
|
|
269
279
|
}
|
|
270
280
|
path.addCommands(this._decoration());
|
|
271
|
-
const fontWeight =
|
|
272
|
-
if (fontWeight in fontWeightMap) {
|
|
273
|
-
path.bold(fontWeightMap[fontWeight] * fontSize * 0.05);
|
|
281
|
+
const fontWeight = style.fontWeight ?? 400;
|
|
282
|
+
if (fontWeight in fontWeightMap && ((fontWeight === 700 || fontWeight === "bold") && fontStyle !== "bold")) {
|
|
283
|
+
path.bold(fontWeightMap[fontWeight] * style.fontSize * 0.05);
|
|
274
284
|
}
|
|
275
285
|
path.style = {
|
|
276
|
-
fill:
|
|
277
|
-
stroke:
|
|
278
|
-
strokeWidth:
|
|
286
|
+
fill: style.color,
|
|
287
|
+
stroke: style.textStrokeWidth ? style.textStrokeColor : "none",
|
|
288
|
+
strokeWidth: style.textStrokeWidth ? style.textStrokeWidth * style.fontSize * 0.03 : 0
|
|
279
289
|
};
|
|
280
290
|
this.path = path;
|
|
281
291
|
this.glyphBox = this.getGlyphBoundingBox();
|
|
@@ -453,6 +463,7 @@ class Measurer {
|
|
|
453
463
|
"fontSize",
|
|
454
464
|
"letterSpacing",
|
|
455
465
|
"textStrokeWidth",
|
|
466
|
+
"textIndent",
|
|
456
467
|
"shadowOffsetX",
|
|
457
468
|
"shadowOffsetY",
|
|
458
469
|
"shadowBlur"
|
|
@@ -880,56 +891,50 @@ function listStyle() {
|
|
|
880
891
|
paths,
|
|
881
892
|
update: (text) => {
|
|
882
893
|
paths.length = 0;
|
|
883
|
-
const { paragraphs,
|
|
884
|
-
|
|
885
|
-
paragraphs.forEach((
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
const r = fontSize * 0.38 / 2;
|
|
898
|
-
listStyleSize = listStyleSize === "cover" ? r * 2 : listStyleSize;
|
|
899
|
-
switch (style.listStyleType) {
|
|
900
|
-
case "disc":
|
|
901
|
-
image = `<svg width="${r * 2}" height="${r * 2}" xmlns="http://www.w3.org/2000/svg">
|
|
894
|
+
const { paragraphs, isVertical, fontSize } = text;
|
|
895
|
+
const padding = fontSize * 0.45;
|
|
896
|
+
paragraphs.forEach((paragraph) => {
|
|
897
|
+
const { computedStyle: style } = paragraph;
|
|
898
|
+
let listStyleSize = style.listStyleSize;
|
|
899
|
+
let image;
|
|
900
|
+
if (!isNone(style.listStyleImage)) {
|
|
901
|
+
image = style.listStyleImage;
|
|
902
|
+
} else if (!isNone(style.listStyleType)) {
|
|
903
|
+
const r = fontSize * 0.38 / 2;
|
|
904
|
+
listStyleSize = listStyleSize === "cover" ? r * 2 : listStyleSize;
|
|
905
|
+
switch (style.listStyleType) {
|
|
906
|
+
case "disc":
|
|
907
|
+
image = `<svg width="${r * 2}" height="${r * 2}" xmlns="http://www.w3.org/2000/svg">
|
|
902
908
|
<circle cx="${r}" cy="${r}" r="${r}" fill="${style.color}" />
|
|
903
909
|
</svg>`;
|
|
904
|
-
|
|
910
|
+
break;
|
|
911
|
+
}
|
|
905
912
|
}
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
const imagePaths = parseSvg(image);
|
|
912
|
-
const imageBox = getPathsBoundingBox(imagePaths);
|
|
913
|
-
paragraphs.forEach((paragraph) => {
|
|
913
|
+
if (!image) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const imagePaths = parseSvg(image);
|
|
917
|
+
const imageBox = getPathsBoundingBox(imagePaths);
|
|
914
918
|
const box = paragraph.lineBox;
|
|
915
|
-
|
|
919
|
+
const fBox = paragraph.fragments[0].inlineBox;
|
|
920
|
+
if (fBox) {
|
|
916
921
|
const m = new Matrix3();
|
|
917
922
|
if (isVertical) {
|
|
918
|
-
const scale = parseScale(listStyleSize,
|
|
923
|
+
const scale = parseScale(listStyleSize, fontSize, fontSize);
|
|
919
924
|
const reScale = fontSize / imageBox.height * scale;
|
|
920
925
|
m.translate(-imageBox.left, -imageBox.top);
|
|
921
926
|
m.rotate(Math.PI / 2);
|
|
922
927
|
m.scale(reScale, reScale);
|
|
923
928
|
m.translate(fontSize / 2 - imageBox.height * reScale / 2, 0);
|
|
924
|
-
m.translate(box.left + (box.width - fontSize) / 2,
|
|
929
|
+
m.translate(box.left + (box.width - fontSize) / 2, fBox.top - padding);
|
|
925
930
|
} else {
|
|
926
|
-
const scale = parseScale(listStyleSize,
|
|
931
|
+
const scale = parseScale(listStyleSize, fontSize, fontSize);
|
|
927
932
|
const reScale = fontSize / imageBox.height * scale;
|
|
928
933
|
m.translate(-imageBox.left, -imageBox.top);
|
|
929
934
|
m.translate(-imageBox.width, 0);
|
|
930
935
|
m.scale(reScale, reScale);
|
|
931
936
|
m.translate(0, fontSize / 2 - imageBox.height * reScale / 2);
|
|
932
|
-
m.translate(
|
|
937
|
+
m.translate(fBox.left - padding, box.top + (box.height - fontSize) / 2);
|
|
933
938
|
}
|
|
934
939
|
paths.push(...imagePaths.map((p) => p.clone().matrix(m)));
|
|
935
940
|
}
|
|
@@ -1019,8 +1024,8 @@ function render() {
|
|
|
1019
1024
|
}
|
|
1020
1025
|
function getTransform2D(text, style) {
|
|
1021
1026
|
const { fontSize, renderBoundingBox } = text;
|
|
1022
|
-
const
|
|
1023
|
-
const
|
|
1027
|
+
const translateX = (style.translateX ?? 0) * fontSize;
|
|
1028
|
+
const translateY = (style.translateY ?? 0) * fontSize;
|
|
1024
1029
|
const PI_2 = Math.PI * 2;
|
|
1025
1030
|
const skewX = (style.skewX ?? 0) / 360 * PI_2;
|
|
1026
1031
|
const skewY = (style.skewY ?? 0) / 360 * PI_2;
|
|
@@ -1028,7 +1033,7 @@ function getTransform2D(text, style) {
|
|
|
1028
1033
|
const centerX = left + width / 2;
|
|
1029
1034
|
const centerY = top + height / 2;
|
|
1030
1035
|
tempM1.identity();
|
|
1031
|
-
tempM2.makeTranslation(
|
|
1036
|
+
tempM2.makeTranslation(translateX, translateY);
|
|
1032
1037
|
tempM1.multiply(tempM2);
|
|
1033
1038
|
tempM2.makeTranslation(centerX, centerY);
|
|
1034
1039
|
tempM1.multiply(tempM2);
|
|
@@ -1048,7 +1053,7 @@ var __publicField = (obj, key, value) => {
|
|
|
1048
1053
|
const defaultTextStyles = {
|
|
1049
1054
|
writingMode: "horizontal-tb",
|
|
1050
1055
|
verticalAlign: "baseline",
|
|
1051
|
-
lineHeight: 1,
|
|
1056
|
+
lineHeight: 1.2,
|
|
1052
1057
|
letterSpacing: 0,
|
|
1053
1058
|
// font
|
|
1054
1059
|
fontSize: 14,
|
|
@@ -1059,21 +1064,16 @@ const defaultTextStyles = {
|
|
|
1059
1064
|
// text
|
|
1060
1065
|
textWrap: "wrap",
|
|
1061
1066
|
textAlign: "start",
|
|
1067
|
+
textIndent: 0,
|
|
1062
1068
|
textTransform: "none",
|
|
1063
1069
|
textOrientation: "mixed",
|
|
1064
|
-
// color
|
|
1065
|
-
color: "#000",
|
|
1066
|
-
backgroundColor: "rgba(0, 0, 0, 0)",
|
|
1067
|
-
// text
|
|
1068
1070
|
textDecoration: "none",
|
|
1069
1071
|
// textStroke
|
|
1070
1072
|
textStrokeWidth: 0,
|
|
1071
1073
|
textStrokeColor: "#000",
|
|
1072
|
-
//
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
shadowOffsetY: 0,
|
|
1076
|
-
shadowBlur: 0,
|
|
1074
|
+
// color
|
|
1075
|
+
color: "#000",
|
|
1076
|
+
backgroundColor: "rgba(0, 0, 0, 0)",
|
|
1077
1077
|
// listStyle
|
|
1078
1078
|
listStyleType: "none",
|
|
1079
1079
|
listStyleImage: "none",
|
|
@@ -1084,7 +1084,16 @@ const defaultTextStyles = {
|
|
|
1084
1084
|
highlightImage: "none",
|
|
1085
1085
|
highlightSize: "cover",
|
|
1086
1086
|
highlightStrokeWidth: "100%",
|
|
1087
|
-
highlightOverflow: "none"
|
|
1087
|
+
highlightOverflow: "none",
|
|
1088
|
+
// shadow
|
|
1089
|
+
shadowColor: "rgba(0, 0, 0, 0)",
|
|
1090
|
+
shadowOffsetX: 0,
|
|
1091
|
+
shadowOffsetY: 0,
|
|
1092
|
+
shadowBlur: 0,
|
|
1093
|
+
translateX: 0,
|
|
1094
|
+
translateY: 0,
|
|
1095
|
+
skewX: 0,
|
|
1096
|
+
skewY: 0
|
|
1088
1097
|
};
|
|
1089
1098
|
class Text {
|
|
1090
1099
|
constructor(options = {}) {
|
|
@@ -1122,20 +1131,10 @@ class Text {
|
|
|
1122
1131
|
}
|
|
1123
1132
|
measure(dom = this.measureDom) {
|
|
1124
1133
|
this.computedStyle = { ...defaultTextStyles, ...this.style };
|
|
1125
|
-
const
|
|
1134
|
+
const oldParagraphs = this.paragraphs;
|
|
1135
|
+
const oldRenderBoundingBox = this.renderBoundingBox;
|
|
1126
1136
|
this.paragraphs = this.parser.parse();
|
|
1127
1137
|
const result = this.measurer.measure(dom);
|
|
1128
|
-
this.paragraphs = old;
|
|
1129
|
-
return result;
|
|
1130
|
-
}
|
|
1131
|
-
requestUpdate() {
|
|
1132
|
-
this.needsUpdate = true;
|
|
1133
|
-
return this;
|
|
1134
|
-
}
|
|
1135
|
-
update() {
|
|
1136
|
-
const { paragraphs, boundingBox } = this.measure();
|
|
1137
|
-
this.paragraphs = paragraphs;
|
|
1138
|
-
this.boundingBox = boundingBox;
|
|
1139
1138
|
const characters = this.characters;
|
|
1140
1139
|
characters.forEach((c) => c.update());
|
|
1141
1140
|
const plugins = [...this.plugins.values()];
|
|
@@ -1163,6 +1162,20 @@ class Text {
|
|
|
1163
1162
|
return getPathsBoundingBox(plugin.paths ?? []);
|
|
1164
1163
|
}).filter(Boolean)
|
|
1165
1164
|
);
|
|
1165
|
+
result.renderBoundingBox = this.renderBoundingBox;
|
|
1166
|
+
this.paragraphs = oldParagraphs;
|
|
1167
|
+
this.renderBoundingBox = oldRenderBoundingBox;
|
|
1168
|
+
return result;
|
|
1169
|
+
}
|
|
1170
|
+
requestUpdate() {
|
|
1171
|
+
this.needsUpdate = true;
|
|
1172
|
+
return this;
|
|
1173
|
+
}
|
|
1174
|
+
update() {
|
|
1175
|
+
const { paragraphs, boundingBox, renderBoundingBox } = this.measure();
|
|
1176
|
+
this.paragraphs = paragraphs;
|
|
1177
|
+
this.boundingBox = boundingBox;
|
|
1178
|
+
this.renderBoundingBox = renderBoundingBox;
|
|
1166
1179
|
return this;
|
|
1167
1180
|
}
|
|
1168
1181
|
render(options) {
|
|
@@ -1194,4 +1207,12 @@ class Text {
|
|
|
1194
1207
|
}
|
|
1195
1208
|
}
|
|
1196
1209
|
|
|
1197
|
-
|
|
1210
|
+
function measureText(options) {
|
|
1211
|
+
return new Text(options).measure();
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
function renderText(options) {
|
|
1215
|
+
return new Text(options).render(options);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
export { Character, Fragment, Measurer, Paragraph, Parser, Text, defaultTextStyles, definePlugin, drawPath, filterEmpty, getTransform2D, highlight, isNone, listStyle, measureText, parseColor, render, renderText, setupView, uploadColor, uploadColors };
|