@pdfme/schemas 6.0.6-dev.9 → 6.1.0-dev.2
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/builtins-CWHhKSVA.js +1389 -0
- package/dist/builtins-CWHhKSVA.js.map +1 -0
- package/dist/builtins.js +1 -1
- package/dist/{dynamicTemplate-DxHU9waC.js → dynamicTemplate-DmuRoTw4.js} +17 -345
- package/dist/dynamicTemplate-DmuRoTw4.js.map +1 -0
- package/dist/helper-M_MmV_d5.js +357 -0
- package/dist/helper-M_MmV_d5.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +958 -177
- package/dist/index.js.map +1 -1
- package/dist/list/constants.d.ts +10 -0
- package/dist/list/dynamicTemplate.d.ts +2 -0
- package/dist/list/helper.d.ts +15 -0
- package/dist/list/index.d.ts +4 -0
- package/dist/list/pdfRender.d.ts +3 -0
- package/dist/list/propPanel.d.ts +3 -0
- package/dist/list/types.d.ts +36 -0
- package/dist/list/uiRender.d.ts +3 -0
- package/dist/lists-B6dmgpkS.js +117 -0
- package/dist/lists-B6dmgpkS.js.map +1 -0
- package/dist/lists.d.ts +3 -0
- package/dist/lists.js +2 -0
- package/dist/multiVariableText/helper.d.ts +2 -1
- package/dist/tables/dynamicTemplate.d.ts +2 -1
- package/dist/tables.d.ts +1 -1
- package/dist/tables.js +2 -2
- package/dist/text/constants.d.ts +13 -0
- package/dist/text/inlineMarkdown.d.ts +4 -0
- package/dist/text/richText.d.ts +46 -0
- package/dist/text/richTextPdfRender.d.ts +34 -0
- package/dist/text/types.d.ts +18 -0
- package/dist/text/uiRender.d.ts +1 -1
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +7 -2
- package/dist/builtins-KUsYW25j.js +0 -613
- package/dist/builtins-KUsYW25j.js.map +0 -1
- package/dist/dynamicTemplate-DxHU9waC.js.map +0 -1
|
@@ -0,0 +1,1389 @@
|
|
|
1
|
+
import { A as TEXT_FORMAT_INLINE_MARKDOWN, C as FONT_SIZE_ADJUSTMENT, D as PLACEHOLDER_FONT_COLOR, E as FONT_VARIANT_FALLBACK_SYNTHETIC, M as VERTICAL_ALIGN_BOTTOM, N as VERTICAL_ALIGN_MIDDLE, O as SYNTHETIC_BOLD_CSS_TEXT_SHADOW, S as DYNAMIC_FIT_VERTICAL, T as FONT_VARIANT_FALLBACK_PLAIN, _ as DEFAULT_DYNAMIC_FIT, a as getFontKitFont, b as DEFAULT_TEXT_FORMAT, c as splitTextToSize, d as ALIGN_JUSTIFY, g as DEFAULT_ALIGNMENT, h as CODE_HORIZONTAL_PADDING, i as getFontDescentInPt, j as TEXT_FORMAT_PLAIN, k as SYNTHETIC_BOLD_OFFSET_RATIO, l as widthOfTextAtSize, m as CODE_BACKGROUND_COLOR, n as fetchRemoteFontData, o as heightOfFontAtSize, p as ALIGN_RIGHT, r as getBrowserVerticalFontAdjustments, s as isFirefox, t as calculateDynamicFontSize, u as ALIGN_CENTER, v as DEFAULT_FONT_COLOR, w as FONT_VARIANT_FALLBACK_ERROR, x as DYNAMIC_FIT_HORIZONTAL, y as DEFAULT_FONT_VARIANT_FALLBACK } from "./helper-M_MmV_d5.js";
|
|
2
|
+
import { c as HEX_COLOR_PATTERN } from "./dynamicTemplate-DmuRoTw4.js";
|
|
3
|
+
import { convertForPdfLayoutProps, createSvgStr, hex2PrintingColor, isEditable, rotatePoint } from "./utils.js";
|
|
4
|
+
import { DEFAULT_FONT_NAME, getDefaultFont, getFallbackFontName, mm2pt, pt2mm } from "@pdfme/common";
|
|
5
|
+
import { AlignCenter, AlignJustify, AlignLeft, AlignRight, ArrowDownToLine, ArrowUpToLine, Strikethrough, TextCursorInput, Underline } from "lucide";
|
|
6
|
+
//#region src/text/inlineMarkdown.ts
|
|
7
|
+
var MARKDOWN_ESCAPABLE_CHARS = new Set([
|
|
8
|
+
"\\",
|
|
9
|
+
"*",
|
|
10
|
+
"~",
|
|
11
|
+
"`"
|
|
12
|
+
]);
|
|
13
|
+
var MARKDOWN_ESCAPE_PATTERN = /[\\*~`]/g;
|
|
14
|
+
var MARKDOWN_UNESCAPE_PATTERN = /\\([\\*~`])/g;
|
|
15
|
+
var sameStyle = (a, b) => Boolean(a.bold) === Boolean(b.bold) && Boolean(a.italic) === Boolean(b.italic) && Boolean(a.strikethrough) === Boolean(b.strikethrough) && Boolean(a.code) === Boolean(b.code);
|
|
16
|
+
var appendRun = (runs, text, style) => {
|
|
17
|
+
if (!text) return;
|
|
18
|
+
const lastRun = runs.at(-1);
|
|
19
|
+
if (lastRun && sameStyle(lastRun, style)) {
|
|
20
|
+
lastRun.text += text;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
runs.push({
|
|
24
|
+
text,
|
|
25
|
+
...style.bold ? { bold: true } : {},
|
|
26
|
+
...style.italic ? { italic: true } : {},
|
|
27
|
+
...style.strikethrough ? { strikethrough: true } : {},
|
|
28
|
+
...style.code ? { code: true } : {}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
var findClosingDelimiter = (value, delimiter, from) => {
|
|
32
|
+
for (let i = from; i < value.length; i++) {
|
|
33
|
+
if (value[i] === "\\") {
|
|
34
|
+
i += 1;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (delimiter !== "`" && value[i] === "`") {
|
|
38
|
+
const codeEnd = findClosingDelimiter(value, "`", i + 1);
|
|
39
|
+
if (codeEnd === -1) continue;
|
|
40
|
+
i = codeEnd;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (value.startsWith(delimiter, i)) return i;
|
|
44
|
+
}
|
|
45
|
+
return -1;
|
|
46
|
+
};
|
|
47
|
+
var getDelimiter = (value, index) => {
|
|
48
|
+
if (value[index] === "`") return "`";
|
|
49
|
+
if (value.startsWith("***", index)) return "***";
|
|
50
|
+
if (value.startsWith("**", index)) return "**";
|
|
51
|
+
if (value.startsWith("~~", index)) return "~~";
|
|
52
|
+
if (value[index] === "*") return "*";
|
|
53
|
+
return "";
|
|
54
|
+
};
|
|
55
|
+
var mergeStyle = (style, delimiter) => {
|
|
56
|
+
if (delimiter === "***") return {
|
|
57
|
+
...style,
|
|
58
|
+
bold: true,
|
|
59
|
+
italic: true
|
|
60
|
+
};
|
|
61
|
+
if (delimiter === "**") return {
|
|
62
|
+
...style,
|
|
63
|
+
bold: true
|
|
64
|
+
};
|
|
65
|
+
if (delimiter === "*") return {
|
|
66
|
+
...style,
|
|
67
|
+
italic: true
|
|
68
|
+
};
|
|
69
|
+
if (delimiter === "~~") return {
|
|
70
|
+
...style,
|
|
71
|
+
strikethrough: true
|
|
72
|
+
};
|
|
73
|
+
return style;
|
|
74
|
+
};
|
|
75
|
+
var parseRange = (value, from, to, style) => {
|
|
76
|
+
const runs = [];
|
|
77
|
+
let buffer = "";
|
|
78
|
+
const flush = () => {
|
|
79
|
+
appendRun(runs, buffer, style);
|
|
80
|
+
buffer = "";
|
|
81
|
+
};
|
|
82
|
+
for (let index = from; index < to; index++) {
|
|
83
|
+
const char = value[index];
|
|
84
|
+
if (char === "\\" && index + 1 < to && MARKDOWN_ESCAPABLE_CHARS.has(value[index + 1])) {
|
|
85
|
+
buffer += value[index + 1];
|
|
86
|
+
index += 1;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const delimiter = getDelimiter(value, index);
|
|
90
|
+
if (!delimiter) {
|
|
91
|
+
buffer += char;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const closingIndex = findClosingDelimiter(value, delimiter, index + delimiter.length);
|
|
95
|
+
if (closingIndex === -1 || closingIndex + delimiter.length > to) {
|
|
96
|
+
buffer += char;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
flush();
|
|
100
|
+
if (delimiter === "`") appendRun(runs, value.slice(index + 1, closingIndex).replace(MARKDOWN_UNESCAPE_PATTERN, "$1"), {
|
|
101
|
+
...style,
|
|
102
|
+
code: true
|
|
103
|
+
});
|
|
104
|
+
else parseRange(value, index + delimiter.length, closingIndex, mergeStyle(style, delimiter)).forEach((run) => appendRun(runs, run.text, run));
|
|
105
|
+
index = closingIndex + delimiter.length - 1;
|
|
106
|
+
}
|
|
107
|
+
flush();
|
|
108
|
+
return runs;
|
|
109
|
+
};
|
|
110
|
+
var parseInlineMarkdown = (value) => {
|
|
111
|
+
if (!value) return [];
|
|
112
|
+
return parseRange(value, 0, value.length, {});
|
|
113
|
+
};
|
|
114
|
+
var escapeInlineMarkdown = (value) => value.replace(MARKDOWN_ESCAPE_PATTERN, (char) => `\\${char}`);
|
|
115
|
+
var stripInlineMarkdown = (value) => parseInlineMarkdown(value).map((run) => run.text).join("");
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/text/richText.ts
|
|
118
|
+
var richTextWordSegmenter = new Intl.Segmenter(void 0, { granularity: "word" });
|
|
119
|
+
var richTextGraphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
120
|
+
var getBaseFontName = (schema, font) => schema.fontName && font[schema.fontName] ? schema.fontName : getFallbackFontName(font);
|
|
121
|
+
var getLoadedFontName = (font, fontName) => fontName && font[fontName] ? fontName : void 0;
|
|
122
|
+
var isInlineMarkdownTextSchema = (schema) => schema.textFormat === "inline-markdown" && !(schema.type === "text" && schema.readOnly !== true);
|
|
123
|
+
var resolveFontVariant = (run, schema, font) => {
|
|
124
|
+
const baseFontName = getBaseFontName(schema, font);
|
|
125
|
+
const variants = schema.fontVariants ?? {};
|
|
126
|
+
const fallback = schema.fontVariantFallback ?? "synthetic";
|
|
127
|
+
let fontName = baseFontName;
|
|
128
|
+
let needsBold = Boolean(run.bold);
|
|
129
|
+
let needsItalic = Boolean(run.italic);
|
|
130
|
+
if (run.code) fontName = getLoadedFontName(font, variants.code) ?? baseFontName;
|
|
131
|
+
else if (run.bold && run.italic) {
|
|
132
|
+
const boldItalic = getLoadedFontName(font, variants.boldItalic);
|
|
133
|
+
const italic = getLoadedFontName(font, variants.italic);
|
|
134
|
+
const bold = getLoadedFontName(font, variants.bold);
|
|
135
|
+
if (boldItalic) {
|
|
136
|
+
fontName = boldItalic;
|
|
137
|
+
needsBold = false;
|
|
138
|
+
needsItalic = false;
|
|
139
|
+
} else if (italic) {
|
|
140
|
+
fontName = italic;
|
|
141
|
+
needsItalic = false;
|
|
142
|
+
} else if (bold) {
|
|
143
|
+
fontName = bold;
|
|
144
|
+
needsBold = false;
|
|
145
|
+
}
|
|
146
|
+
} else if (run.bold) {
|
|
147
|
+
const bold = getLoadedFontName(font, variants.bold);
|
|
148
|
+
if (bold) {
|
|
149
|
+
fontName = bold;
|
|
150
|
+
needsBold = false;
|
|
151
|
+
}
|
|
152
|
+
} else if (run.italic) {
|
|
153
|
+
const italic = getLoadedFontName(font, variants.italic);
|
|
154
|
+
if (italic) {
|
|
155
|
+
fontName = italic;
|
|
156
|
+
needsItalic = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if ((needsBold || needsItalic || run.code && !getLoadedFontName(font, variants.code)) && fallback === "error") throw new Error(`[@pdfme/schemas] Missing font variant for markdown text in field "${schema.name}".`);
|
|
160
|
+
return {
|
|
161
|
+
fontName,
|
|
162
|
+
syntheticBold: fallback !== "plain" && needsBold,
|
|
163
|
+
syntheticItalic: fallback !== "plain" && needsItalic
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
var resolveRichTextRuns = async (arg) => {
|
|
167
|
+
const { runs, schema, font, _cache } = arg;
|
|
168
|
+
const fontKitCache = /* @__PURE__ */ new Map();
|
|
169
|
+
const getResolvedFontKitFont = async (fontName) => {
|
|
170
|
+
const cached = fontKitCache.get(fontName);
|
|
171
|
+
if (cached) return cached;
|
|
172
|
+
const fontKitFont = await getFontKitFont(fontName, font, _cache);
|
|
173
|
+
fontKitCache.set(fontName, fontKitFont);
|
|
174
|
+
return fontKitFont;
|
|
175
|
+
};
|
|
176
|
+
return Promise.all(runs.map(async (run) => {
|
|
177
|
+
const resolution = resolveFontVariant(run, schema, font);
|
|
178
|
+
return {
|
|
179
|
+
...run,
|
|
180
|
+
...resolution,
|
|
181
|
+
fontKitFont: await getResolvedFontKitFont(resolution.fontName)
|
|
182
|
+
};
|
|
183
|
+
}));
|
|
184
|
+
};
|
|
185
|
+
var measureRunText = (run, text, fontSize, characterSpacing) => {
|
|
186
|
+
const syntheticBoldWidth = run.syntheticBold ? fontSize * SYNTHETIC_BOLD_OFFSET_RATIO * 2 : 0;
|
|
187
|
+
const syntheticItalicWidth = run.syntheticItalic ? heightOfFontAtSize(run.fontKitFont, fontSize) * Math.tan(12 * Math.PI / 180) : 0;
|
|
188
|
+
return widthOfTextAtSize(text, run.fontKitFont, fontSize, characterSpacing) + syntheticBoldWidth + syntheticItalicWidth;
|
|
189
|
+
};
|
|
190
|
+
var createLine = () => ({
|
|
191
|
+
runs: [],
|
|
192
|
+
width: 0,
|
|
193
|
+
hardBreak: false
|
|
194
|
+
});
|
|
195
|
+
var pushRunToLine = (line, run, text, fontSize, characterSpacing) => {
|
|
196
|
+
if (!text) return;
|
|
197
|
+
const width = measureRunText(run, text, fontSize, characterSpacing);
|
|
198
|
+
if (line.runs.length > 0) line.width += characterSpacing;
|
|
199
|
+
line.runs.push({
|
|
200
|
+
...run,
|
|
201
|
+
text,
|
|
202
|
+
width
|
|
203
|
+
});
|
|
204
|
+
line.width += width;
|
|
205
|
+
};
|
|
206
|
+
var measurePiecesWidth = (pieces, fontSize, characterSpacing) => {
|
|
207
|
+
let width = 0;
|
|
208
|
+
let hasText = false;
|
|
209
|
+
pieces.forEach((piece) => {
|
|
210
|
+
if (!piece.text) return;
|
|
211
|
+
if (hasText) width += characterSpacing;
|
|
212
|
+
width += measureRunText(piece.run, piece.text, fontSize, characterSpacing);
|
|
213
|
+
hasText = true;
|
|
214
|
+
});
|
|
215
|
+
return width;
|
|
216
|
+
};
|
|
217
|
+
var sliceRunPieces = (pieces, startIndex, endIndex) => {
|
|
218
|
+
const result = [];
|
|
219
|
+
let offset = 0;
|
|
220
|
+
pieces.forEach((piece) => {
|
|
221
|
+
const pieceStart = offset;
|
|
222
|
+
const pieceEnd = pieceStart + piece.text.length;
|
|
223
|
+
const sliceStart = Math.max(startIndex, pieceStart);
|
|
224
|
+
const sliceEnd = Math.min(endIndex, pieceEnd);
|
|
225
|
+
if (sliceStart < sliceEnd) result.push({
|
|
226
|
+
run: piece.run,
|
|
227
|
+
text: piece.text.slice(sliceStart - pieceStart, sliceEnd - pieceStart)
|
|
228
|
+
});
|
|
229
|
+
offset = pieceEnd;
|
|
230
|
+
});
|
|
231
|
+
return result;
|
|
232
|
+
};
|
|
233
|
+
var segmentRunPiecesByWord = (runs, onSegment, onHardBreak) => {
|
|
234
|
+
let paragraphPieces = [];
|
|
235
|
+
const flushParagraph = () => {
|
|
236
|
+
if (paragraphPieces.length === 0) return;
|
|
237
|
+
const paragraphText = paragraphPieces.map((piece) => piece.text).join("");
|
|
238
|
+
Array.from(richTextWordSegmenter.segment(paragraphText), ({ segment, index }) => {
|
|
239
|
+
const pieces = sliceRunPieces(paragraphPieces, index, index + segment.length);
|
|
240
|
+
if (pieces.length > 0) onSegment(pieces);
|
|
241
|
+
});
|
|
242
|
+
paragraphPieces = [];
|
|
243
|
+
};
|
|
244
|
+
runs.forEach((run) => {
|
|
245
|
+
run.text.split(/(\r\n|\r|\n)/).forEach((part) => {
|
|
246
|
+
if (part === "\r\n" || part === "\r" || part === "\n") {
|
|
247
|
+
flushParagraph();
|
|
248
|
+
onHardBreak();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
if (part) paragraphPieces.push({
|
|
252
|
+
run,
|
|
253
|
+
text: part
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
flushParagraph();
|
|
258
|
+
};
|
|
259
|
+
var splitIntoGraphemes = (value) => Array.from(richTextGraphemeSegmenter.segment(value), ({ segment }) => segment);
|
|
260
|
+
var countRichTextLineGraphemes = (line) => splitIntoGraphemes(line.runs.map((run) => run.text).join("")).length;
|
|
261
|
+
var layoutRichTextLines = (arg) => {
|
|
262
|
+
const { runs, fontSize, characterSpacing, boxWidthInPt } = arg;
|
|
263
|
+
const lines = [];
|
|
264
|
+
let currentLine = createLine();
|
|
265
|
+
const pushCurrentLine = (hardBreak) => {
|
|
266
|
+
currentLine.hardBreak = hardBreak;
|
|
267
|
+
lines.push(currentLine);
|
|
268
|
+
currentLine = createLine();
|
|
269
|
+
};
|
|
270
|
+
const pushPiecesToLine = (pieces) => {
|
|
271
|
+
pieces.forEach((piece) => {
|
|
272
|
+
pushRunToLine(currentLine, piece.run, piece.text, fontSize, characterSpacing);
|
|
273
|
+
});
|
|
274
|
+
};
|
|
275
|
+
const pushOversizedText = (run, text) => {
|
|
276
|
+
let remainingText = text;
|
|
277
|
+
while (remainingText.length > 0) {
|
|
278
|
+
const pendingSpacing = currentLine.runs.length > 0 ? characterSpacing : 0;
|
|
279
|
+
const remainingWidth = Math.max(boxWidthInPt - currentLine.width - pendingSpacing, 0);
|
|
280
|
+
const remainingTextWidth = measureRunText(run, remainingText, fontSize, characterSpacing);
|
|
281
|
+
if (remainingTextWidth <= remainingWidth || currentLine.runs.length === 0 && remainingTextWidth <= boxWidthInPt) {
|
|
282
|
+
pushRunToLine(currentLine, run, remainingText, fontSize, characterSpacing);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (currentLine.runs.length > 0 && remainingTextWidth <= boxWidthInPt) {
|
|
286
|
+
pushCurrentLine(false);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const graphemes = splitIntoGraphemes(remainingText);
|
|
290
|
+
let fittingText = "";
|
|
291
|
+
let fittingLength = 0;
|
|
292
|
+
for (const grapheme of graphemes) {
|
|
293
|
+
const candidate = fittingText + grapheme;
|
|
294
|
+
const candidateWidth = measureRunText(run, candidate, fontSize, characterSpacing);
|
|
295
|
+
const maxWidth = currentLine.runs.length === 0 ? boxWidthInPt : remainingWidth;
|
|
296
|
+
if (candidateWidth > maxWidth) {
|
|
297
|
+
if (fittingText) break;
|
|
298
|
+
if (currentLine.runs.length > 0) break;
|
|
299
|
+
}
|
|
300
|
+
fittingText = candidate;
|
|
301
|
+
fittingLength += grapheme.length;
|
|
302
|
+
if (candidateWidth > maxWidth) break;
|
|
303
|
+
}
|
|
304
|
+
if (!fittingText) {
|
|
305
|
+
pushCurrentLine(false);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
pushRunToLine(currentLine, run, fittingText, fontSize, characterSpacing);
|
|
309
|
+
remainingText = remainingText.slice(fittingLength);
|
|
310
|
+
if (remainingText.length > 0) pushCurrentLine(false);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const pushSegment = (pieces) => {
|
|
314
|
+
const segmentWidth = measurePiecesWidth(pieces, fontSize, characterSpacing);
|
|
315
|
+
const pendingSpacing = currentLine.runs.length > 0 ? characterSpacing : 0;
|
|
316
|
+
if (segmentWidth <= Math.max(boxWidthInPt - currentLine.width - pendingSpacing, 0) || currentLine.runs.length === 0 && segmentWidth <= boxWidthInPt) {
|
|
317
|
+
pushPiecesToLine(pieces);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (currentLine.runs.length > 0) {
|
|
321
|
+
pushCurrentLine(false);
|
|
322
|
+
if (segmentWidth <= boxWidthInPt) {
|
|
323
|
+
pushPiecesToLine(pieces);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
pieces.forEach((piece) => pushOversizedText(piece.run, piece.text));
|
|
328
|
+
};
|
|
329
|
+
segmentRunPiecesByWord(runs, pushSegment, () => pushCurrentLine(true));
|
|
330
|
+
if (currentLine.runs.length > 0 || lines.length === 0) pushCurrentLine(false);
|
|
331
|
+
return lines;
|
|
332
|
+
};
|
|
333
|
+
var measureParagraphWidths = (runs, fontSize, characterSpacing) => {
|
|
334
|
+
const widths = [];
|
|
335
|
+
let paragraphPieces = [];
|
|
336
|
+
const pushWidth = () => {
|
|
337
|
+
widths.push(measurePiecesWidth(paragraphPieces, fontSize, characterSpacing));
|
|
338
|
+
paragraphPieces = [];
|
|
339
|
+
};
|
|
340
|
+
runs.forEach((run) => {
|
|
341
|
+
run.text.split(/(\r\n|\r|\n)/).forEach((part) => {
|
|
342
|
+
if (part === "\r\n" || part === "\r" || part === "\n") {
|
|
343
|
+
pushWidth();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (part) paragraphPieces.push({
|
|
347
|
+
run,
|
|
348
|
+
text: part
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
pushWidth();
|
|
353
|
+
return widths;
|
|
354
|
+
};
|
|
355
|
+
var getLineHeightAtSize = (line, fontSize) => {
|
|
356
|
+
if (line.runs.length === 0) return fontSize;
|
|
357
|
+
return Math.max(...line.runs.map((run) => heightOfFontAtSize(run.fontKitFont, fontSize)));
|
|
358
|
+
};
|
|
359
|
+
var calculateDynamicRichTextFontSize = async (arg) => {
|
|
360
|
+
const { value, schema, font, _cache, startingFontSize } = arg;
|
|
361
|
+
const { fontSize: schemaFontSize, dynamicFontSize: dynamicFontSizeSetting, characterSpacing: schemaCharacterSpacing, width: boxWidth, height: boxHeight, lineHeight = 1 } = schema;
|
|
362
|
+
const fontSize = startingFontSize || schemaFontSize || 13;
|
|
363
|
+
if (!dynamicFontSizeSetting) return fontSize;
|
|
364
|
+
if (dynamicFontSizeSetting.max < dynamicFontSizeSetting.min) return fontSize;
|
|
365
|
+
const resolvedRuns = await resolveRichTextRuns({
|
|
366
|
+
runs: parseInlineMarkdown(value),
|
|
367
|
+
schema,
|
|
368
|
+
font,
|
|
369
|
+
_cache
|
|
370
|
+
});
|
|
371
|
+
const characterSpacing = schemaCharacterSpacing ?? 0;
|
|
372
|
+
const dynamicFontFit = dynamicFontSizeSetting.fit ?? "vertical";
|
|
373
|
+
const boxWidthInPt = mm2pt(boxWidth);
|
|
374
|
+
let dynamicFontSize = fontSize;
|
|
375
|
+
if (dynamicFontSize < dynamicFontSizeSetting.min) dynamicFontSize = dynamicFontSizeSetting.min;
|
|
376
|
+
else if (dynamicFontSize > dynamicFontSizeSetting.max) dynamicFontSize = dynamicFontSizeSetting.max;
|
|
377
|
+
const calculateConstraints = (size) => {
|
|
378
|
+
let totalWidthInMm = 0;
|
|
379
|
+
let totalHeightInMm = 0;
|
|
380
|
+
layoutRichTextLines({
|
|
381
|
+
runs: resolvedRuns,
|
|
382
|
+
fontSize: size,
|
|
383
|
+
characterSpacing,
|
|
384
|
+
boxWidthInPt
|
|
385
|
+
}).forEach((line, lineIndex) => {
|
|
386
|
+
if (dynamicFontFit === "vertical") totalWidthInMm = Math.max(totalWidthInMm, pt2mm(line.width));
|
|
387
|
+
if (lineIndex === 0) totalHeightInMm += pt2mm(getLineHeightAtSize(line, size) * lineHeight);
|
|
388
|
+
else totalHeightInMm += pt2mm(size * lineHeight);
|
|
389
|
+
});
|
|
390
|
+
if (dynamicFontFit === "horizontal") measureParagraphWidths(resolvedRuns, size, characterSpacing).forEach((paragraphWidth) => {
|
|
391
|
+
totalWidthInMm = Math.max(totalWidthInMm, pt2mm(paragraphWidth));
|
|
392
|
+
});
|
|
393
|
+
return {
|
|
394
|
+
totalWidthInMm,
|
|
395
|
+
totalHeightInMm
|
|
396
|
+
};
|
|
397
|
+
};
|
|
398
|
+
const shouldFontGrowToFit = (totalWidthInMm, totalHeightInMm) => {
|
|
399
|
+
if (dynamicFontSize >= dynamicFontSizeSetting.max) return false;
|
|
400
|
+
if (dynamicFontFit === "horizontal") return totalWidthInMm < boxWidth;
|
|
401
|
+
return totalHeightInMm < boxHeight;
|
|
402
|
+
};
|
|
403
|
+
const shouldFontShrinkToFit = (totalWidthInMm, totalHeightInMm) => {
|
|
404
|
+
if (dynamicFontSize <= dynamicFontSizeSetting.min || dynamicFontSize <= 0) return false;
|
|
405
|
+
return totalWidthInMm > boxWidth || totalHeightInMm > boxHeight;
|
|
406
|
+
};
|
|
407
|
+
let { totalWidthInMm, totalHeightInMm } = calculateConstraints(dynamicFontSize);
|
|
408
|
+
while (shouldFontGrowToFit(totalWidthInMm, totalHeightInMm)) {
|
|
409
|
+
dynamicFontSize += FONT_SIZE_ADJUSTMENT;
|
|
410
|
+
const { totalWidthInMm: newWidth, totalHeightInMm: newHeight } = calculateConstraints(dynamicFontSize);
|
|
411
|
+
if (newHeight < boxHeight) {
|
|
412
|
+
totalWidthInMm = newWidth;
|
|
413
|
+
totalHeightInMm = newHeight;
|
|
414
|
+
} else {
|
|
415
|
+
dynamicFontSize -= FONT_SIZE_ADJUSTMENT;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
while (shouldFontShrinkToFit(totalWidthInMm, totalHeightInMm)) {
|
|
420
|
+
dynamicFontSize -= FONT_SIZE_ADJUSTMENT;
|
|
421
|
+
({totalWidthInMm, totalHeightInMm} = calculateConstraints(dynamicFontSize));
|
|
422
|
+
}
|
|
423
|
+
return dynamicFontSize;
|
|
424
|
+
};
|
|
425
|
+
//#endregion
|
|
426
|
+
//#region src/text/richTextPdfRender.ts
|
|
427
|
+
var getSyntheticBoldWidth = (run, fontSize) => run.syntheticBold ? fontSize * SYNTHETIC_BOLD_OFFSET_RATIO * 2 : 0;
|
|
428
|
+
var getSyntheticItalicWidth = (run, fontSize) => run.syntheticItalic ? heightOfFontAtSize(run.fontKitFont, fontSize) * Math.tan(12 * Math.PI / 180) : 0;
|
|
429
|
+
var getRunWidth = (run, fontSize, characterSpacing) => widthOfTextAtSize(run.text, run.fontKitFont, fontSize, characterSpacing) + getSyntheticBoldWidth(run, fontSize) + getSyntheticItalicWidth(run, fontSize);
|
|
430
|
+
var getPdfFont = (run, pdfFontObj) => {
|
|
431
|
+
const pdfFont = pdfFontObj[run.fontName];
|
|
432
|
+
if (!pdfFont) throw new Error(`[@pdfme/schemas] Missing embedded font "${run.fontName}".`);
|
|
433
|
+
return pdfFont;
|
|
434
|
+
};
|
|
435
|
+
var drawDecorationLine = (arg) => {
|
|
436
|
+
const { page, x, y, width, rotate, pivotPoint, fontSize, color, opacity } = arg;
|
|
437
|
+
if (width <= 0) return;
|
|
438
|
+
page.drawLine({
|
|
439
|
+
start: rotatePoint({
|
|
440
|
+
x,
|
|
441
|
+
y
|
|
442
|
+
}, pivotPoint, rotate.angle),
|
|
443
|
+
end: rotatePoint({
|
|
444
|
+
x: x + width,
|
|
445
|
+
y
|
|
446
|
+
}, pivotPoint, rotate.angle),
|
|
447
|
+
thickness: 1 / 12 * fontSize,
|
|
448
|
+
color,
|
|
449
|
+
opacity
|
|
450
|
+
});
|
|
451
|
+
};
|
|
452
|
+
var drawRun = (arg) => {
|
|
453
|
+
const { page, pdfLib, run, pdfFont, x, y, rotate, pivotPoint, fontSize, lineHeight, color, opacity, colorType, characterSpacing, strikethrough } = arg;
|
|
454
|
+
const runWidth = getRunWidth(run, fontSize, characterSpacing);
|
|
455
|
+
const textHeight = heightOfFontAtSize(run.fontKitFont, fontSize);
|
|
456
|
+
if (run.code) {
|
|
457
|
+
const padding = CODE_HORIZONTAL_PADDING;
|
|
458
|
+
const bgX = x - padding;
|
|
459
|
+
const bgY = y - textHeight * .2;
|
|
460
|
+
const bgPoint = rotate.angle === 0 ? {
|
|
461
|
+
x: bgX,
|
|
462
|
+
y: bgY
|
|
463
|
+
} : rotatePoint({
|
|
464
|
+
x: bgX,
|
|
465
|
+
y: bgY
|
|
466
|
+
}, pivotPoint, rotate.angle);
|
|
467
|
+
page.drawRectangle({
|
|
468
|
+
x: bgPoint.x,
|
|
469
|
+
y: bgPoint.y,
|
|
470
|
+
width: runWidth + padding * 2,
|
|
471
|
+
height: textHeight * 1.2,
|
|
472
|
+
rotate,
|
|
473
|
+
color: hex2PrintingColor(CODE_BACKGROUND_COLOR, colorType),
|
|
474
|
+
opacity
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (strikethrough && runWidth > 0) drawDecorationLine({
|
|
478
|
+
page,
|
|
479
|
+
x,
|
|
480
|
+
y: y + textHeight / 3,
|
|
481
|
+
width: runWidth,
|
|
482
|
+
rotate,
|
|
483
|
+
pivotPoint,
|
|
484
|
+
fontSize,
|
|
485
|
+
color,
|
|
486
|
+
opacity
|
|
487
|
+
});
|
|
488
|
+
const drawAt = (drawX) => {
|
|
489
|
+
const point = rotate.angle === 0 ? {
|
|
490
|
+
x: drawX,
|
|
491
|
+
y
|
|
492
|
+
} : rotatePoint({
|
|
493
|
+
x: drawX,
|
|
494
|
+
y
|
|
495
|
+
}, pivotPoint, rotate.angle);
|
|
496
|
+
page.drawText(run.text, {
|
|
497
|
+
x: point.x,
|
|
498
|
+
y: point.y,
|
|
499
|
+
rotate,
|
|
500
|
+
size: fontSize,
|
|
501
|
+
color,
|
|
502
|
+
lineHeight: lineHeight * fontSize,
|
|
503
|
+
font: pdfFont,
|
|
504
|
+
opacity,
|
|
505
|
+
...run.syntheticItalic ? { ySkew: pdfLib.degrees(12) } : {}
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
drawAt(x);
|
|
509
|
+
if (run.syntheticBold) {
|
|
510
|
+
const offset = fontSize * SYNTHETIC_BOLD_OFFSET_RATIO;
|
|
511
|
+
for (let i = 1; i <= 2; i++) drawAt(x + offset * i);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
var renderInlineMarkdownText = async (arg) => {
|
|
515
|
+
const { value, schema, font, pdfFontObj, fontKitFont, page, pdfLib, _cache, colorType, fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing, x, width, height, pageHeight, pivotPoint, rotate, opacity } = arg;
|
|
516
|
+
const lines = layoutRichTextLines({
|
|
517
|
+
runs: await resolveRichTextRuns({
|
|
518
|
+
runs: parseInlineMarkdown(value),
|
|
519
|
+
schema,
|
|
520
|
+
font,
|
|
521
|
+
_cache
|
|
522
|
+
}),
|
|
523
|
+
fontSize,
|
|
524
|
+
characterSpacing,
|
|
525
|
+
boxWidthInPt: width
|
|
526
|
+
});
|
|
527
|
+
const firstLineTextHeight = heightOfFontAtSize(fontKitFont, fontSize);
|
|
528
|
+
const descent = getFontDescentInPt(fontKitFont, fontSize);
|
|
529
|
+
const halfLineHeightAdjustment = lineHeight === 0 ? 0 : (lineHeight - 1) * fontSize / 2;
|
|
530
|
+
let yOffset = 0;
|
|
531
|
+
if (verticalAlignment === "top") yOffset = firstLineTextHeight + halfLineHeightAdjustment;
|
|
532
|
+
else {
|
|
533
|
+
const otherLinesHeight = lineHeight * fontSize * (lines.length - 1);
|
|
534
|
+
if (verticalAlignment === "bottom") yOffset = height - otherLinesHeight + descent - halfLineHeightAdjustment;
|
|
535
|
+
else if (verticalAlignment === "middle") yOffset = (height - otherLinesHeight - firstLineTextHeight + descent) / 2 + firstLineTextHeight;
|
|
536
|
+
}
|
|
537
|
+
lines.forEach((line, rowIndex) => {
|
|
538
|
+
if (line.runs.length === 0) return;
|
|
539
|
+
let textWidth = line.width;
|
|
540
|
+
let spacing = characterSpacing;
|
|
541
|
+
if (alignment === "justify" && !line.hardBreak && rowIndex < lines.length - 1) {
|
|
542
|
+
const graphemeCount = countRichTextLineGraphemes(line);
|
|
543
|
+
if (graphemeCount > 0) {
|
|
544
|
+
spacing += (width - textWidth) / graphemeCount;
|
|
545
|
+
textWidth = width;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
let xLine = x;
|
|
549
|
+
if (alignment === "center") xLine += (width - textWidth) / 2;
|
|
550
|
+
else if (alignment === "right") xLine += width - textWidth;
|
|
551
|
+
const yLine = pageHeight - mm2pt(schema.position.y) - yOffset - lineHeight * fontSize * rowIndex;
|
|
552
|
+
page.pushOperators(pdfLib.setCharacterSpacing(spacing));
|
|
553
|
+
if (schema.strikethrough || schema.underline) {
|
|
554
|
+
const textHeight = Math.max(...line.runs.map((run) => heightOfFontAtSize(run.fontKitFont, fontSize)));
|
|
555
|
+
if (schema.strikethrough) drawDecorationLine({
|
|
556
|
+
page,
|
|
557
|
+
x: xLine,
|
|
558
|
+
y: yLine + textHeight / 3,
|
|
559
|
+
width: textWidth,
|
|
560
|
+
rotate,
|
|
561
|
+
pivotPoint,
|
|
562
|
+
fontSize,
|
|
563
|
+
color,
|
|
564
|
+
opacity
|
|
565
|
+
});
|
|
566
|
+
if (schema.underline) drawDecorationLine({
|
|
567
|
+
page,
|
|
568
|
+
x: xLine,
|
|
569
|
+
y: yLine - textHeight / 12,
|
|
570
|
+
width: textWidth,
|
|
571
|
+
rotate,
|
|
572
|
+
pivotPoint,
|
|
573
|
+
fontSize,
|
|
574
|
+
color,
|
|
575
|
+
opacity
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
line.runs.reduce((currentX, run, runIndex) => {
|
|
579
|
+
const runWidth = getRunWidth(run, fontSize, spacing);
|
|
580
|
+
drawRun({
|
|
581
|
+
page,
|
|
582
|
+
pdfLib,
|
|
583
|
+
run,
|
|
584
|
+
pdfFont: getPdfFont(run, pdfFontObj),
|
|
585
|
+
x: currentX,
|
|
586
|
+
y: yLine,
|
|
587
|
+
rotate,
|
|
588
|
+
pivotPoint,
|
|
589
|
+
fontSize,
|
|
590
|
+
lineHeight,
|
|
591
|
+
color,
|
|
592
|
+
opacity,
|
|
593
|
+
colorType,
|
|
594
|
+
characterSpacing: spacing,
|
|
595
|
+
strikethrough: Boolean(run.strikethrough)
|
|
596
|
+
});
|
|
597
|
+
return currentX + runWidth + (runIndex === line.runs.length - 1 ? 0 : spacing);
|
|
598
|
+
}, xLine);
|
|
599
|
+
});
|
|
600
|
+
};
|
|
601
|
+
//#endregion
|
|
602
|
+
//#region src/text/pdfRender.ts
|
|
603
|
+
var embedAndGetFontObj = async (arg) => {
|
|
604
|
+
const { pdfDoc, font, _cache } = arg;
|
|
605
|
+
if (_cache.has(pdfDoc)) return _cache.get(pdfDoc);
|
|
606
|
+
const fontValues = await Promise.all(Object.values(font).map(async (v) => {
|
|
607
|
+
let fontData = v.data;
|
|
608
|
+
if (typeof fontData === "string" && fontData.startsWith("http")) fontData = await fetchRemoteFontData(fontData);
|
|
609
|
+
return pdfDoc.embedFont(fontData, { subset: typeof v.subset === "undefined" ? true : v.subset });
|
|
610
|
+
}));
|
|
611
|
+
const fontObj = Object.keys(font).reduce((acc, cur, i) => Object.assign(acc, { [cur]: fontValues[i] }), {});
|
|
612
|
+
_cache.set(pdfDoc, fontObj);
|
|
613
|
+
return fontObj;
|
|
614
|
+
};
|
|
615
|
+
var getFontProp = ({ value, fontKitFont, schema, colorType, fontSize: resolvedFontSize }) => {
|
|
616
|
+
const fontSize = resolvedFontSize ?? (schema.dynamicFontSize ? calculateDynamicFontSize({
|
|
617
|
+
textSchema: schema,
|
|
618
|
+
fontKitFont,
|
|
619
|
+
value
|
|
620
|
+
}) : schema.fontSize ?? 13);
|
|
621
|
+
const color = hex2PrintingColor(schema.fontColor || "#000000", colorType);
|
|
622
|
+
return {
|
|
623
|
+
alignment: schema.alignment ?? "left",
|
|
624
|
+
verticalAlignment: schema.verticalAlignment ?? "top",
|
|
625
|
+
lineHeight: schema.lineHeight ?? 1,
|
|
626
|
+
characterSpacing: schema.characterSpacing ?? 0,
|
|
627
|
+
fontSize,
|
|
628
|
+
color
|
|
629
|
+
};
|
|
630
|
+
};
|
|
631
|
+
var pdfRender = async (arg) => {
|
|
632
|
+
const { value, pdfDoc, pdfLib, page, options, schema, _cache } = arg;
|
|
633
|
+
if (!value) return;
|
|
634
|
+
const { font = getDefaultFont(), colorType } = options;
|
|
635
|
+
const [pdfFontObj, fontKitFont] = await Promise.all([embedAndGetFontObj({
|
|
636
|
+
pdfDoc,
|
|
637
|
+
font,
|
|
638
|
+
_cache
|
|
639
|
+
}), getFontKitFont(schema.fontName, font, _cache)]);
|
|
640
|
+
const enableInlineMarkdown = isInlineMarkdownTextSchema(schema);
|
|
641
|
+
const { fontSize, color, alignment, verticalAlignment, lineHeight, characterSpacing } = getFontProp({
|
|
642
|
+
value: enableInlineMarkdown ? stripInlineMarkdown(value) : value,
|
|
643
|
+
fontKitFont,
|
|
644
|
+
schema,
|
|
645
|
+
colorType,
|
|
646
|
+
fontSize: enableInlineMarkdown && schema.dynamicFontSize ? await calculateDynamicRichTextFontSize({
|
|
647
|
+
value,
|
|
648
|
+
schema,
|
|
649
|
+
font,
|
|
650
|
+
_cache
|
|
651
|
+
}) : void 0
|
|
652
|
+
});
|
|
653
|
+
const fontName = schema.fontName ? schema.fontName : getFallbackFontName(font);
|
|
654
|
+
const pdfFontValue = pdfFontObj && pdfFontObj[fontName];
|
|
655
|
+
const pageHeight = page.getHeight();
|
|
656
|
+
const { width, height, rotate, position: { x, y }, opacity } = convertForPdfLayoutProps({
|
|
657
|
+
schema,
|
|
658
|
+
pageHeight,
|
|
659
|
+
applyRotateTranslate: false
|
|
660
|
+
});
|
|
661
|
+
const pivotPoint = {
|
|
662
|
+
x: x + width / 2,
|
|
663
|
+
y: pageHeight - mm2pt(schema.position.y) - height / 2
|
|
664
|
+
};
|
|
665
|
+
if (schema.backgroundColor) {
|
|
666
|
+
const color = hex2PrintingColor(schema.backgroundColor, colorType);
|
|
667
|
+
if (rotate.angle !== 0) {
|
|
668
|
+
const rotatedPoint = rotatePoint({
|
|
669
|
+
x,
|
|
670
|
+
y
|
|
671
|
+
}, pivotPoint, rotate.angle);
|
|
672
|
+
page.drawRectangle({
|
|
673
|
+
x: rotatedPoint.x,
|
|
674
|
+
y: rotatedPoint.y,
|
|
675
|
+
width,
|
|
676
|
+
height,
|
|
677
|
+
rotate,
|
|
678
|
+
color
|
|
679
|
+
});
|
|
680
|
+
} else page.drawRectangle({
|
|
681
|
+
x,
|
|
682
|
+
y,
|
|
683
|
+
width,
|
|
684
|
+
height,
|
|
685
|
+
rotate,
|
|
686
|
+
color
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
if (enableInlineMarkdown) {
|
|
690
|
+
await renderInlineMarkdownText({
|
|
691
|
+
value,
|
|
692
|
+
schema,
|
|
693
|
+
font,
|
|
694
|
+
pdfFontObj,
|
|
695
|
+
fontKitFont,
|
|
696
|
+
page,
|
|
697
|
+
pdfLib,
|
|
698
|
+
_cache,
|
|
699
|
+
colorType,
|
|
700
|
+
fontSize,
|
|
701
|
+
color,
|
|
702
|
+
alignment,
|
|
703
|
+
verticalAlignment,
|
|
704
|
+
lineHeight,
|
|
705
|
+
characterSpacing,
|
|
706
|
+
x,
|
|
707
|
+
width,
|
|
708
|
+
height,
|
|
709
|
+
pageHeight,
|
|
710
|
+
pivotPoint,
|
|
711
|
+
rotate,
|
|
712
|
+
opacity
|
|
713
|
+
});
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const firstLineTextHeight = heightOfFontAtSize(fontKitFont, fontSize);
|
|
717
|
+
const descent = getFontDescentInPt(fontKitFont, fontSize);
|
|
718
|
+
const halfLineHeightAdjustment = lineHeight === 0 ? 0 : (lineHeight - 1) * fontSize / 2;
|
|
719
|
+
const lines = splitTextToSize({
|
|
720
|
+
value,
|
|
721
|
+
characterSpacing,
|
|
722
|
+
fontSize,
|
|
723
|
+
fontKitFont,
|
|
724
|
+
boxWidthInPt: width
|
|
725
|
+
});
|
|
726
|
+
let yOffset = 0;
|
|
727
|
+
if (verticalAlignment === "top") yOffset = firstLineTextHeight + halfLineHeightAdjustment;
|
|
728
|
+
else {
|
|
729
|
+
const otherLinesHeight = lineHeight * fontSize * (lines.length - 1);
|
|
730
|
+
if (verticalAlignment === "bottom") yOffset = height - otherLinesHeight + descent - halfLineHeightAdjustment;
|
|
731
|
+
else if (verticalAlignment === "middle") yOffset = (height - otherLinesHeight - firstLineTextHeight + descent) / 2 + firstLineTextHeight;
|
|
732
|
+
}
|
|
733
|
+
const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
734
|
+
lines.forEach((line, rowIndex) => {
|
|
735
|
+
const trimmed = line.replace("\n", "");
|
|
736
|
+
const textWidth = widthOfTextAtSize(trimmed, fontKitFont, fontSize, characterSpacing);
|
|
737
|
+
const textHeight = heightOfFontAtSize(fontKitFont, fontSize);
|
|
738
|
+
const rowYOffset = lineHeight * fontSize * rowIndex;
|
|
739
|
+
if (line === "") line = "\r\n";
|
|
740
|
+
let xLine = x;
|
|
741
|
+
if (alignment === "center") xLine += (width - textWidth) / 2;
|
|
742
|
+
else if (alignment === "right") xLine += width - textWidth;
|
|
743
|
+
let yLine = pageHeight - mm2pt(schema.position.y) - yOffset - rowYOffset;
|
|
744
|
+
if (schema.strikethrough && textWidth > 0) {
|
|
745
|
+
const _x = xLine + textWidth + 1;
|
|
746
|
+
const _y = yLine + textHeight / 3;
|
|
747
|
+
page.drawLine({
|
|
748
|
+
start: rotatePoint({
|
|
749
|
+
x: xLine,
|
|
750
|
+
y: _y
|
|
751
|
+
}, pivotPoint, rotate.angle),
|
|
752
|
+
end: rotatePoint({
|
|
753
|
+
x: _x,
|
|
754
|
+
y: _y
|
|
755
|
+
}, pivotPoint, rotate.angle),
|
|
756
|
+
thickness: 1 / 12 * fontSize,
|
|
757
|
+
color,
|
|
758
|
+
opacity
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
if (schema.underline && textWidth > 0) {
|
|
762
|
+
const _x = xLine + textWidth + 1;
|
|
763
|
+
const _y = yLine - textHeight / 12;
|
|
764
|
+
page.drawLine({
|
|
765
|
+
start: rotatePoint({
|
|
766
|
+
x: xLine,
|
|
767
|
+
y: _y
|
|
768
|
+
}, pivotPoint, rotate.angle),
|
|
769
|
+
end: rotatePoint({
|
|
770
|
+
x: _x,
|
|
771
|
+
y: _y
|
|
772
|
+
}, pivotPoint, rotate.angle),
|
|
773
|
+
thickness: 1 / 12 * fontSize,
|
|
774
|
+
color,
|
|
775
|
+
opacity
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
if (rotate.angle !== 0) {
|
|
779
|
+
const rotatedPoint = rotatePoint({
|
|
780
|
+
x: xLine,
|
|
781
|
+
y: yLine
|
|
782
|
+
}, pivotPoint, rotate.angle);
|
|
783
|
+
xLine = rotatedPoint.x;
|
|
784
|
+
yLine = rotatedPoint.y;
|
|
785
|
+
}
|
|
786
|
+
let spacing = characterSpacing;
|
|
787
|
+
if (alignment === "justify" && line.slice(-1) !== "\n") {
|
|
788
|
+
const iterator = segmenter.segment(trimmed)[Symbol.iterator]();
|
|
789
|
+
const len = Array.from(iterator).length;
|
|
790
|
+
spacing += (width - textWidth) / len;
|
|
791
|
+
}
|
|
792
|
+
page.pushOperators(pdfLib.setCharacterSpacing(spacing));
|
|
793
|
+
page.drawText(trimmed, {
|
|
794
|
+
x: xLine,
|
|
795
|
+
y: yLine,
|
|
796
|
+
rotate,
|
|
797
|
+
size: fontSize,
|
|
798
|
+
color,
|
|
799
|
+
lineHeight: lineHeight * fontSize,
|
|
800
|
+
font: pdfFontValue,
|
|
801
|
+
opacity
|
|
802
|
+
});
|
|
803
|
+
});
|
|
804
|
+
};
|
|
805
|
+
//#endregion
|
|
806
|
+
//#region src/text/icons/index.ts
|
|
807
|
+
var TextStrikethroughIcon = createSvgStr(Strikethrough);
|
|
808
|
+
var TextUnderlineIcon = createSvgStr(Underline);
|
|
809
|
+
var TextAlignLeftIcon = createSvgStr(AlignLeft);
|
|
810
|
+
var TextAlignCenterIcon = createSvgStr(AlignCenter);
|
|
811
|
+
var TextAlignRightIcon = createSvgStr(AlignRight);
|
|
812
|
+
var TextAlignJustifyIcon = createSvgStr(AlignJustify);
|
|
813
|
+
var TextVerticalAlignTopIcon = createSvgStr(ArrowUpToLine);
|
|
814
|
+
var TextVerticalAlignMiddleIcon = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24"><path d="M8 19h3v4h2v-4h3l-4-4l-4 4zm8-14h-3V1h-2v4H8l4 4l4-4zM4 11v2h16v-2H4z" fill="currentColor"></path></svg>`;
|
|
815
|
+
var TextVerticalAlignBottomIcon = createSvgStr(ArrowDownToLine);
|
|
816
|
+
//#endregion
|
|
817
|
+
//#region src/text/extraFormatter.ts
|
|
818
|
+
var Formatter = /* @__PURE__ */ function(Formatter) {
|
|
819
|
+
Formatter["STRIKETHROUGH"] = "strikethrough";
|
|
820
|
+
Formatter["UNDERLINE"] = "underline";
|
|
821
|
+
Formatter["ALIGNMENT"] = "alignment";
|
|
822
|
+
Formatter["VERTICAL_ALIGNMENT"] = "verticalAlignment";
|
|
823
|
+
return Formatter;
|
|
824
|
+
}({});
|
|
825
|
+
function getExtraFormatterSchema(i18n) {
|
|
826
|
+
const buttons = [
|
|
827
|
+
{
|
|
828
|
+
key: Formatter.STRIKETHROUGH,
|
|
829
|
+
icon: TextStrikethroughIcon,
|
|
830
|
+
type: "boolean"
|
|
831
|
+
},
|
|
832
|
+
{
|
|
833
|
+
key: Formatter.UNDERLINE,
|
|
834
|
+
icon: TextUnderlineIcon,
|
|
835
|
+
type: "boolean"
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
key: Formatter.ALIGNMENT,
|
|
839
|
+
icon: TextAlignLeftIcon,
|
|
840
|
+
type: "select",
|
|
841
|
+
value: DEFAULT_ALIGNMENT
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
key: Formatter.ALIGNMENT,
|
|
845
|
+
icon: TextAlignCenterIcon,
|
|
846
|
+
type: "select",
|
|
847
|
+
value: ALIGN_CENTER
|
|
848
|
+
},
|
|
849
|
+
{
|
|
850
|
+
key: Formatter.ALIGNMENT,
|
|
851
|
+
icon: TextAlignRightIcon,
|
|
852
|
+
type: "select",
|
|
853
|
+
value: ALIGN_RIGHT
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
key: Formatter.ALIGNMENT,
|
|
857
|
+
icon: TextAlignJustifyIcon,
|
|
858
|
+
type: "select",
|
|
859
|
+
value: ALIGN_JUSTIFY
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
key: Formatter.VERTICAL_ALIGNMENT,
|
|
863
|
+
icon: TextVerticalAlignTopIcon,
|
|
864
|
+
type: "select",
|
|
865
|
+
value: "top"
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
key: Formatter.VERTICAL_ALIGNMENT,
|
|
869
|
+
icon: TextVerticalAlignMiddleIcon,
|
|
870
|
+
type: "select",
|
|
871
|
+
value: VERTICAL_ALIGN_MIDDLE
|
|
872
|
+
},
|
|
873
|
+
{
|
|
874
|
+
key: Formatter.VERTICAL_ALIGNMENT,
|
|
875
|
+
icon: TextVerticalAlignBottomIcon,
|
|
876
|
+
type: "select",
|
|
877
|
+
value: VERTICAL_ALIGN_BOTTOM
|
|
878
|
+
}
|
|
879
|
+
];
|
|
880
|
+
return {
|
|
881
|
+
title: i18n("schemas.text.format"),
|
|
882
|
+
widget: "ButtonGroup",
|
|
883
|
+
buttons,
|
|
884
|
+
span: 24
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
//#endregion
|
|
888
|
+
//#region src/text/propPanel.ts
|
|
889
|
+
var UseDynamicFontSize = (props) => {
|
|
890
|
+
const { rootElement, changeSchemas, activeSchema, i18n } = props;
|
|
891
|
+
const checkbox = document.createElement("input");
|
|
892
|
+
checkbox.type = "checkbox";
|
|
893
|
+
checkbox.checked = Boolean(activeSchema?.dynamicFontSize);
|
|
894
|
+
checkbox.onchange = (e) => {
|
|
895
|
+
changeSchemas([{
|
|
896
|
+
key: "dynamicFontSize",
|
|
897
|
+
value: e.target.checked ? {
|
|
898
|
+
min: 4,
|
|
899
|
+
max: 72,
|
|
900
|
+
fit: DEFAULT_DYNAMIC_FIT
|
|
901
|
+
} : void 0,
|
|
902
|
+
schemaId: activeSchema.id
|
|
903
|
+
}]);
|
|
904
|
+
};
|
|
905
|
+
const label = document.createElement("label");
|
|
906
|
+
const span = document.createElement("span");
|
|
907
|
+
span.innerText = i18n("schemas.text.dynamicFontSize") || "";
|
|
908
|
+
span.style.cssText = "margin-left: 0.5rem";
|
|
909
|
+
label.style.cssText = "display: flex; width: 100%;";
|
|
910
|
+
label.appendChild(checkbox);
|
|
911
|
+
label.appendChild(span);
|
|
912
|
+
rootElement.appendChild(label);
|
|
913
|
+
};
|
|
914
|
+
var UseInlineMarkdown = (props) => {
|
|
915
|
+
const { rootElement, changeSchemas, activeSchema, i18n } = props;
|
|
916
|
+
const checkbox = document.createElement("input");
|
|
917
|
+
checkbox.type = "checkbox";
|
|
918
|
+
checkbox.checked = activeSchema?.textFormat === TEXT_FORMAT_INLINE_MARKDOWN;
|
|
919
|
+
checkbox.onchange = (e) => {
|
|
920
|
+
changeSchemas([{
|
|
921
|
+
key: "textFormat",
|
|
922
|
+
value: e.target.checked ? TEXT_FORMAT_INLINE_MARKDOWN : TEXT_FORMAT_PLAIN,
|
|
923
|
+
schemaId: activeSchema.id
|
|
924
|
+
}]);
|
|
925
|
+
};
|
|
926
|
+
const label = document.createElement("label");
|
|
927
|
+
const span = document.createElement("span");
|
|
928
|
+
span.innerText = i18n("schemas.text.inlineMarkdown") || "";
|
|
929
|
+
span.style.cssText = "margin-left: 0.5rem";
|
|
930
|
+
label.style.cssText = "display: flex; width: 100%;";
|
|
931
|
+
label.appendChild(checkbox);
|
|
932
|
+
label.appendChild(span);
|
|
933
|
+
rootElement.appendChild(label);
|
|
934
|
+
};
|
|
935
|
+
var propPanel = {
|
|
936
|
+
schema: ({ options, activeSchema, i18n }) => {
|
|
937
|
+
const font = options.font || { [DEFAULT_FONT_NAME]: {
|
|
938
|
+
data: "",
|
|
939
|
+
fallback: true
|
|
940
|
+
} };
|
|
941
|
+
const fontNames = Object.keys(font);
|
|
942
|
+
const fallbackFontName = getFallbackFontName(font);
|
|
943
|
+
const enableDynamicFont = Boolean(activeSchema?.dynamicFontSize);
|
|
944
|
+
const activeTextSchema = activeSchema;
|
|
945
|
+
const hideTextFormat = activeTextSchema.type === "text" && activeTextSchema.readOnly !== true;
|
|
946
|
+
const enableInlineMarkdown = activeTextSchema.textFormat === "inline-markdown" && !hideTextFormat;
|
|
947
|
+
const baseFontName = activeTextSchema.fontName && font[activeTextSchema.fontName] ? activeTextSchema.fontName : fallbackFontName;
|
|
948
|
+
const optionalFontNames = [{
|
|
949
|
+
label: baseFontName,
|
|
950
|
+
value: ""
|
|
951
|
+
}, ...fontNames.filter((name) => name !== baseFontName).map((name) => ({
|
|
952
|
+
label: name,
|
|
953
|
+
value: name
|
|
954
|
+
}))];
|
|
955
|
+
return {
|
|
956
|
+
fontName: {
|
|
957
|
+
title: i18n("schemas.text.fontName"),
|
|
958
|
+
type: "string",
|
|
959
|
+
widget: "select",
|
|
960
|
+
default: fallbackFontName,
|
|
961
|
+
placeholder: fallbackFontName,
|
|
962
|
+
props: { options: fontNames.map((name) => ({
|
|
963
|
+
label: name,
|
|
964
|
+
value: name
|
|
965
|
+
})) },
|
|
966
|
+
span: 12
|
|
967
|
+
},
|
|
968
|
+
fontSize: {
|
|
969
|
+
title: i18n("schemas.text.size"),
|
|
970
|
+
type: "number",
|
|
971
|
+
widget: "inputNumber",
|
|
972
|
+
span: 6,
|
|
973
|
+
disabled: enableDynamicFont,
|
|
974
|
+
props: { min: 0 }
|
|
975
|
+
},
|
|
976
|
+
characterSpacing: {
|
|
977
|
+
title: i18n("schemas.text.spacing"),
|
|
978
|
+
type: "number",
|
|
979
|
+
widget: "inputNumber",
|
|
980
|
+
span: 6,
|
|
981
|
+
props: { min: 0 }
|
|
982
|
+
},
|
|
983
|
+
formatter: getExtraFormatterSchema(i18n),
|
|
984
|
+
lineHeight: {
|
|
985
|
+
title: i18n("schemas.text.lineHeight"),
|
|
986
|
+
type: "number",
|
|
987
|
+
widget: "inputNumber",
|
|
988
|
+
props: {
|
|
989
|
+
step: .1,
|
|
990
|
+
min: 0
|
|
991
|
+
},
|
|
992
|
+
span: 8
|
|
993
|
+
},
|
|
994
|
+
useDynamicFontSize: {
|
|
995
|
+
type: "boolean",
|
|
996
|
+
widget: "UseDynamicFontSize",
|
|
997
|
+
bind: false,
|
|
998
|
+
span: 16
|
|
999
|
+
},
|
|
1000
|
+
dynamicFontSize: {
|
|
1001
|
+
type: "object",
|
|
1002
|
+
widget: "card",
|
|
1003
|
+
column: 3,
|
|
1004
|
+
properties: {
|
|
1005
|
+
min: {
|
|
1006
|
+
title: i18n("schemas.text.min"),
|
|
1007
|
+
type: "number",
|
|
1008
|
+
widget: "inputNumber",
|
|
1009
|
+
hidden: !enableDynamicFont,
|
|
1010
|
+
props: { min: 0 }
|
|
1011
|
+
},
|
|
1012
|
+
max: {
|
|
1013
|
+
title: i18n("schemas.text.max"),
|
|
1014
|
+
type: "number",
|
|
1015
|
+
widget: "inputNumber",
|
|
1016
|
+
hidden: !enableDynamicFont,
|
|
1017
|
+
props: { min: 0 }
|
|
1018
|
+
},
|
|
1019
|
+
fit: {
|
|
1020
|
+
title: i18n("schemas.text.fit"),
|
|
1021
|
+
type: "string",
|
|
1022
|
+
widget: "select",
|
|
1023
|
+
hidden: !enableDynamicFont,
|
|
1024
|
+
props: { options: [{
|
|
1025
|
+
label: i18n("schemas.horizontal"),
|
|
1026
|
+
value: DYNAMIC_FIT_HORIZONTAL
|
|
1027
|
+
}, {
|
|
1028
|
+
label: i18n("schemas.vertical"),
|
|
1029
|
+
value: DYNAMIC_FIT_VERTICAL
|
|
1030
|
+
}] }
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
fontColor: {
|
|
1035
|
+
title: i18n("schemas.textColor"),
|
|
1036
|
+
type: "string",
|
|
1037
|
+
widget: "color",
|
|
1038
|
+
props: { disabledAlpha: true },
|
|
1039
|
+
rules: [{
|
|
1040
|
+
pattern: HEX_COLOR_PATTERN,
|
|
1041
|
+
message: i18n("validation.hexColor")
|
|
1042
|
+
}]
|
|
1043
|
+
},
|
|
1044
|
+
backgroundColor: {
|
|
1045
|
+
title: i18n("schemas.bgColor"),
|
|
1046
|
+
type: "string",
|
|
1047
|
+
widget: "color",
|
|
1048
|
+
props: { disabledAlpha: true },
|
|
1049
|
+
rules: [{
|
|
1050
|
+
pattern: HEX_COLOR_PATTERN,
|
|
1051
|
+
message: i18n("validation.hexColor")
|
|
1052
|
+
}]
|
|
1053
|
+
},
|
|
1054
|
+
useInlineMarkdown: {
|
|
1055
|
+
type: "boolean",
|
|
1056
|
+
widget: "UseInlineMarkdown",
|
|
1057
|
+
bind: false,
|
|
1058
|
+
hidden: hideTextFormat,
|
|
1059
|
+
span: enableInlineMarkdown ? 12 : 24
|
|
1060
|
+
},
|
|
1061
|
+
fontVariantFallback: {
|
|
1062
|
+
title: i18n("schemas.text.variantFallback"),
|
|
1063
|
+
type: "string",
|
|
1064
|
+
widget: "select",
|
|
1065
|
+
default: DEFAULT_FONT_VARIANT_FALLBACK,
|
|
1066
|
+
hidden: !enableInlineMarkdown,
|
|
1067
|
+
props: { options: [
|
|
1068
|
+
{
|
|
1069
|
+
label: i18n("schemas.text.synthetic"),
|
|
1070
|
+
value: FONT_VARIANT_FALLBACK_SYNTHETIC
|
|
1071
|
+
},
|
|
1072
|
+
{
|
|
1073
|
+
label: i18n("schemas.text.plain"),
|
|
1074
|
+
value: FONT_VARIANT_FALLBACK_PLAIN
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
label: i18n("schemas.text.error"),
|
|
1078
|
+
value: FONT_VARIANT_FALLBACK_ERROR
|
|
1079
|
+
}
|
|
1080
|
+
] },
|
|
1081
|
+
span: 12
|
|
1082
|
+
},
|
|
1083
|
+
fontVariants: {
|
|
1084
|
+
title: i18n("schemas.text.markdownFonts"),
|
|
1085
|
+
type: "object",
|
|
1086
|
+
widget: "card",
|
|
1087
|
+
column: 2,
|
|
1088
|
+
hidden: !enableInlineMarkdown,
|
|
1089
|
+
properties: {
|
|
1090
|
+
bold: {
|
|
1091
|
+
title: i18n("schemas.text.boldFont"),
|
|
1092
|
+
type: "string",
|
|
1093
|
+
widget: "select",
|
|
1094
|
+
props: { options: optionalFontNames }
|
|
1095
|
+
},
|
|
1096
|
+
italic: {
|
|
1097
|
+
title: i18n("schemas.text.italicFont"),
|
|
1098
|
+
type: "string",
|
|
1099
|
+
widget: "select",
|
|
1100
|
+
props: { options: optionalFontNames }
|
|
1101
|
+
},
|
|
1102
|
+
boldItalic: {
|
|
1103
|
+
title: i18n("schemas.text.boldItalicFont"),
|
|
1104
|
+
type: "string",
|
|
1105
|
+
widget: "select",
|
|
1106
|
+
props: { options: optionalFontNames }
|
|
1107
|
+
},
|
|
1108
|
+
code: {
|
|
1109
|
+
title: i18n("schemas.text.codeFont"),
|
|
1110
|
+
type: "string",
|
|
1111
|
+
widget: "select",
|
|
1112
|
+
props: { options: optionalFontNames }
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
},
|
|
1118
|
+
widgets: {
|
|
1119
|
+
UseDynamicFontSize,
|
|
1120
|
+
UseInlineMarkdown
|
|
1121
|
+
},
|
|
1122
|
+
defaultSchema: {
|
|
1123
|
+
name: "",
|
|
1124
|
+
type: "text",
|
|
1125
|
+
content: "Type Something...",
|
|
1126
|
+
position: {
|
|
1127
|
+
x: 0,
|
|
1128
|
+
y: 0
|
|
1129
|
+
},
|
|
1130
|
+
width: 45,
|
|
1131
|
+
height: 10,
|
|
1132
|
+
rotate: 0,
|
|
1133
|
+
alignment: DEFAULT_ALIGNMENT,
|
|
1134
|
+
verticalAlignment: "top",
|
|
1135
|
+
fontSize: 13,
|
|
1136
|
+
textFormat: DEFAULT_TEXT_FORMAT,
|
|
1137
|
+
fontVariantFallback: DEFAULT_FONT_VARIANT_FALLBACK,
|
|
1138
|
+
lineHeight: 1,
|
|
1139
|
+
characterSpacing: 0,
|
|
1140
|
+
dynamicFontSize: void 0,
|
|
1141
|
+
fontColor: DEFAULT_FONT_COLOR,
|
|
1142
|
+
fontName: void 0,
|
|
1143
|
+
backgroundColor: "",
|
|
1144
|
+
opacity: 1,
|
|
1145
|
+
strikethrough: false,
|
|
1146
|
+
underline: false
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
//#endregion
|
|
1150
|
+
//#region src/text/uiRender.ts
|
|
1151
|
+
var replaceUnsupportedChars = (text, fontKitFont) => {
|
|
1152
|
+
const charSupportCache = {};
|
|
1153
|
+
const isCharSupported = (char) => {
|
|
1154
|
+
if (char in charSupportCache) return charSupportCache[char];
|
|
1155
|
+
const isSupported = fontKitFont.hasGlyphForCodePoint(char.codePointAt(0) || 0);
|
|
1156
|
+
charSupportCache[char] = isSupported;
|
|
1157
|
+
return isSupported;
|
|
1158
|
+
};
|
|
1159
|
+
return text.split(/(\r\n|\n|\r)/).map((segment) => {
|
|
1160
|
+
if (/\r\n|\n|\r/.test(segment)) return segment;
|
|
1161
|
+
return Array.from(segment).map((char) => {
|
|
1162
|
+
if (/\s/.test(char) || char.charCodeAt(0) < 32) return char;
|
|
1163
|
+
return isCharSupported(char) ? char : "〿";
|
|
1164
|
+
}).join("");
|
|
1165
|
+
}).join("");
|
|
1166
|
+
};
|
|
1167
|
+
var uiRender = async (arg) => {
|
|
1168
|
+
const { value, schema, mode, onChange, stopEditing, tabIndex, placeholder, options, _cache } = arg;
|
|
1169
|
+
const usePlaceholder = isEditable(mode, schema) && placeholder && !value;
|
|
1170
|
+
const getText = (element) => {
|
|
1171
|
+
let text = element.innerText;
|
|
1172
|
+
if (text.endsWith("\n")) text = text.slice(0, -1);
|
|
1173
|
+
return text;
|
|
1174
|
+
};
|
|
1175
|
+
const font = options?.font || getDefaultFont();
|
|
1176
|
+
const fontKitFont = await getFontKitFont(schema.fontName, font, _cache);
|
|
1177
|
+
const enableInlineMarkdown = isInlineMarkdownTextSchema(schema);
|
|
1178
|
+
const displayValue = enableInlineMarkdown ? stripInlineMarkdown(value) : value;
|
|
1179
|
+
const dynamicRichTextFontSize = enableInlineMarkdown && schema.dynamicFontSize ? await calculateDynamicRichTextFontSize({
|
|
1180
|
+
value: usePlaceholder ? placeholder : value,
|
|
1181
|
+
schema,
|
|
1182
|
+
font,
|
|
1183
|
+
_cache
|
|
1184
|
+
}) : void 0;
|
|
1185
|
+
const textBlock = buildStyledTextContainer(arg, fontKitFont, usePlaceholder ? placeholder : displayValue, dynamicRichTextFontSize);
|
|
1186
|
+
const processedText = replaceUnsupportedChars(value, fontKitFont);
|
|
1187
|
+
if (!isEditable(mode, schema)) {
|
|
1188
|
+
if (enableInlineMarkdown) {
|
|
1189
|
+
await renderInlineMarkdownReadOnly({
|
|
1190
|
+
textBlock,
|
|
1191
|
+
value,
|
|
1192
|
+
schema,
|
|
1193
|
+
font,
|
|
1194
|
+
_cache
|
|
1195
|
+
});
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
textBlock.innerHTML = processedText.split("").map((l, i) => {
|
|
1199
|
+
const escaped = l.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1200
|
+
return `<span style="letter-spacing:${String(value).length === i + 1 ? 0 : "inherit"};">${escaped}</span>`;
|
|
1201
|
+
}).join("");
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
makeElementPlainTextContentEditable(textBlock);
|
|
1205
|
+
textBlock.tabIndex = tabIndex || 0;
|
|
1206
|
+
textBlock.innerText = mode === "designer" ? value : processedText;
|
|
1207
|
+
textBlock.addEventListener("blur", (e) => {
|
|
1208
|
+
if (onChange) onChange({
|
|
1209
|
+
key: "content",
|
|
1210
|
+
value: getText(e.target)
|
|
1211
|
+
});
|
|
1212
|
+
if (stopEditing) stopEditing();
|
|
1213
|
+
});
|
|
1214
|
+
if (schema.dynamicFontSize) {
|
|
1215
|
+
let dynamicFontSize = void 0;
|
|
1216
|
+
textBlock.addEventListener("keyup", () => {
|
|
1217
|
+
setTimeout(() => {
|
|
1218
|
+
(() => {
|
|
1219
|
+
if (!textBlock.textContent) return;
|
|
1220
|
+
dynamicFontSize = calculateDynamicFontSize({
|
|
1221
|
+
textSchema: schema,
|
|
1222
|
+
fontKitFont,
|
|
1223
|
+
value: isInlineMarkdownTextSchema(schema) ? stripInlineMarkdown(getText(textBlock)) : getText(textBlock),
|
|
1224
|
+
startingFontSize: dynamicFontSize
|
|
1225
|
+
});
|
|
1226
|
+
textBlock.style.fontSize = `${dynamicFontSize}pt`;
|
|
1227
|
+
const { topAdj: newTopAdj, bottomAdj: newBottomAdj } = getBrowserVerticalFontAdjustments(fontKitFont, dynamicFontSize ?? schema.fontSize ?? 13, schema.lineHeight ?? 1, schema.verticalAlignment ?? "top");
|
|
1228
|
+
textBlock.style.paddingTop = `${newTopAdj}px`;
|
|
1229
|
+
textBlock.style.marginBottom = `${newBottomAdj}px`;
|
|
1230
|
+
})();
|
|
1231
|
+
}, 0);
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
if (usePlaceholder) {
|
|
1235
|
+
textBlock.style.color = PLACEHOLDER_FONT_COLOR;
|
|
1236
|
+
textBlock.addEventListener("focus", () => {
|
|
1237
|
+
if (textBlock.innerText === placeholder) {
|
|
1238
|
+
textBlock.innerText = "";
|
|
1239
|
+
textBlock.style.color = schema.fontColor ?? "#000000";
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
if (mode === "designer") setTimeout(() => {
|
|
1244
|
+
textBlock.focus();
|
|
1245
|
+
const selection = window.getSelection();
|
|
1246
|
+
const range = document.createRange();
|
|
1247
|
+
if (selection && range) {
|
|
1248
|
+
range.selectNodeContents(textBlock);
|
|
1249
|
+
range.collapse(false);
|
|
1250
|
+
selection?.removeAllRanges();
|
|
1251
|
+
selection?.addRange(range);
|
|
1252
|
+
}
|
|
1253
|
+
});
|
|
1254
|
+
};
|
|
1255
|
+
var renderInlineMarkdownReadOnly = async (arg) => {
|
|
1256
|
+
const { textBlock, value, schema, font, _cache } = arg;
|
|
1257
|
+
const runs = await resolveRichTextRuns({
|
|
1258
|
+
runs: parseInlineMarkdown(value),
|
|
1259
|
+
schema,
|
|
1260
|
+
font,
|
|
1261
|
+
_cache
|
|
1262
|
+
});
|
|
1263
|
+
textBlock.innerHTML = "";
|
|
1264
|
+
runs.forEach((run) => {
|
|
1265
|
+
const span = document.createElement("span");
|
|
1266
|
+
span.textContent = replaceUnsupportedChars(run.text, run.fontKitFont);
|
|
1267
|
+
if (run.fontName) span.style.fontFamily = `'${run.fontName}'`;
|
|
1268
|
+
if (run.syntheticBold) {
|
|
1269
|
+
span.style.fontWeight = "800";
|
|
1270
|
+
span.style.textShadow = SYNTHETIC_BOLD_CSS_TEXT_SHADOW;
|
|
1271
|
+
}
|
|
1272
|
+
if (run.syntheticItalic) span.style.fontStyle = "italic";
|
|
1273
|
+
if (run.strikethrough) span.style.textDecoration = "line-through";
|
|
1274
|
+
if (run.code) {
|
|
1275
|
+
span.style.backgroundColor = CODE_BACKGROUND_COLOR;
|
|
1276
|
+
span.style.borderRadius = "2px";
|
|
1277
|
+
span.style.padding = "0 0.15em";
|
|
1278
|
+
if (!schema.fontVariants?.code || !font[schema.fontVariants.code]) span.style.fontFamily = run.fontName ? `'${run.fontName}', monospace` : "monospace";
|
|
1279
|
+
}
|
|
1280
|
+
textBlock.appendChild(span);
|
|
1281
|
+
});
|
|
1282
|
+
};
|
|
1283
|
+
var buildStyledTextContainer = (arg, fontKitFont, value, resolvedDynamicFontSize) => {
|
|
1284
|
+
const { schema, rootElement, mode } = arg;
|
|
1285
|
+
let dynamicFontSize = resolvedDynamicFontSize;
|
|
1286
|
+
if (dynamicFontSize === void 0 && schema.dynamicFontSize && value) dynamicFontSize = calculateDynamicFontSize({
|
|
1287
|
+
textSchema: schema,
|
|
1288
|
+
fontKitFont,
|
|
1289
|
+
value,
|
|
1290
|
+
startingFontSize: dynamicFontSize
|
|
1291
|
+
});
|
|
1292
|
+
const { topAdj, bottomAdj } = getBrowserVerticalFontAdjustments(fontKitFont, dynamicFontSize ?? schema.fontSize ?? 13, schema.lineHeight ?? 1, schema.verticalAlignment ?? "top");
|
|
1293
|
+
const topAdjustment = topAdj.toString();
|
|
1294
|
+
const bottomAdjustment = bottomAdj.toString();
|
|
1295
|
+
const container = document.createElement("div");
|
|
1296
|
+
const containerStyle = {
|
|
1297
|
+
padding: 0,
|
|
1298
|
+
resize: "none",
|
|
1299
|
+
backgroundColor: getBackgroundColor(value, schema),
|
|
1300
|
+
border: "none",
|
|
1301
|
+
display: "flex",
|
|
1302
|
+
flexDirection: "column",
|
|
1303
|
+
justifyContent: mapVerticalAlignToFlex(schema.verticalAlignment),
|
|
1304
|
+
width: "100%",
|
|
1305
|
+
height: "100%",
|
|
1306
|
+
cursor: isEditable(mode, schema) ? "text" : "default"
|
|
1307
|
+
};
|
|
1308
|
+
Object.assign(container.style, containerStyle);
|
|
1309
|
+
rootElement.innerHTML = "";
|
|
1310
|
+
rootElement.appendChild(container);
|
|
1311
|
+
const textDecorations = [];
|
|
1312
|
+
if (schema.strikethrough) textDecorations.push("line-through");
|
|
1313
|
+
if (schema.underline) textDecorations.push("underline");
|
|
1314
|
+
const textBlockStyle = {
|
|
1315
|
+
fontFamily: schema.fontName ? `'${schema.fontName}'` : "inherit",
|
|
1316
|
+
color: schema.fontColor ? schema.fontColor : DEFAULT_FONT_COLOR,
|
|
1317
|
+
fontSize: `${dynamicFontSize ?? schema.fontSize ?? 13}pt`,
|
|
1318
|
+
letterSpacing: `${schema.characterSpacing ?? 0}pt`,
|
|
1319
|
+
lineHeight: `${schema.lineHeight ?? 1}em`,
|
|
1320
|
+
textAlign: schema.alignment ?? "left",
|
|
1321
|
+
whiteSpace: "pre-wrap",
|
|
1322
|
+
wordBreak: "break-word",
|
|
1323
|
+
resize: "none",
|
|
1324
|
+
border: "none",
|
|
1325
|
+
outline: "none",
|
|
1326
|
+
marginBottom: `${bottomAdjustment}px`,
|
|
1327
|
+
paddingTop: `${topAdjustment}px`,
|
|
1328
|
+
backgroundColor: "transparent",
|
|
1329
|
+
textDecoration: textDecorations.join(" ")
|
|
1330
|
+
};
|
|
1331
|
+
const textBlock = document.createElement("div");
|
|
1332
|
+
textBlock.id = "text-" + String(schema.id);
|
|
1333
|
+
Object.assign(textBlock.style, textBlockStyle);
|
|
1334
|
+
container.appendChild(textBlock);
|
|
1335
|
+
return textBlock;
|
|
1336
|
+
};
|
|
1337
|
+
/**
|
|
1338
|
+
* Firefox doesn't support 'plaintext-only' contentEditable mode, which we want to avoid mark-up.
|
|
1339
|
+
* This function adds a workaround for Firefox to make the contentEditable element behave like 'plaintext-only'.
|
|
1340
|
+
*/
|
|
1341
|
+
var makeElementPlainTextContentEditable = (element) => {
|
|
1342
|
+
if (!isFirefox()) {
|
|
1343
|
+
element.contentEditable = "plaintext-only";
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
element.contentEditable = "true";
|
|
1347
|
+
element.addEventListener("keydown", (e) => {
|
|
1348
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
1349
|
+
e.preventDefault();
|
|
1350
|
+
document.execCommand("insertLineBreak", false, void 0);
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
element.addEventListener("paste", (e) => {
|
|
1354
|
+
e.preventDefault();
|
|
1355
|
+
const paste = e.clipboardData?.getData("text");
|
|
1356
|
+
const selection = window.getSelection();
|
|
1357
|
+
if (!selection?.rangeCount) return;
|
|
1358
|
+
selection.deleteFromDocument();
|
|
1359
|
+
selection.getRangeAt(0).insertNode(document.createTextNode(paste || ""));
|
|
1360
|
+
selection.collapseToEnd();
|
|
1361
|
+
});
|
|
1362
|
+
};
|
|
1363
|
+
var mapVerticalAlignToFlex = (verticalAlignmentValue) => {
|
|
1364
|
+
switch (verticalAlignmentValue) {
|
|
1365
|
+
case "top": return "flex-start";
|
|
1366
|
+
case VERTICAL_ALIGN_MIDDLE: return "center";
|
|
1367
|
+
case VERTICAL_ALIGN_BOTTOM: return "flex-end";
|
|
1368
|
+
}
|
|
1369
|
+
return "flex-start";
|
|
1370
|
+
};
|
|
1371
|
+
var getBackgroundColor = (value, schema) => {
|
|
1372
|
+
if (!value || !schema.backgroundColor) return "transparent";
|
|
1373
|
+
return schema.backgroundColor;
|
|
1374
|
+
};
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/text/index.ts
|
|
1377
|
+
var textSchema = {
|
|
1378
|
+
pdf: pdfRender,
|
|
1379
|
+
ui: uiRender,
|
|
1380
|
+
propPanel,
|
|
1381
|
+
icon: createSvgStr(TextCursorInput)
|
|
1382
|
+
};
|
|
1383
|
+
//#endregion
|
|
1384
|
+
//#region src/builtins.ts
|
|
1385
|
+
var builtInPlugins = { Text: textSchema };
|
|
1386
|
+
//#endregion
|
|
1387
|
+
export { mapVerticalAlignToFlex as a, Formatter as c, isInlineMarkdownTextSchema as d, resolveFontVariant as f, makeElementPlainTextContentEditable as i, getExtraFormatterSchema as l, parseInlineMarkdown as m, textSchema as n, uiRender as o, escapeInlineMarkdown as p, buildStyledTextContainer as r, propPanel as s, builtInPlugins as t, pdfRender as u };
|
|
1388
|
+
|
|
1389
|
+
//# sourceMappingURL=builtins-CWHhKSVA.js.map
|