@pdfme/jsx 6.1.1-dev.8 → 6.1.2-dev.3
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 +82 -6
- package/dist/components.d.ts +12 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +580 -59
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +78 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import { a as isPdfJsxElement, n as cloneElementWithChildren, o as isPdfJsxFragment, r as createElementNode } from "./node-BeNL0xMl.js";
|
|
2
|
-
import { getDefaultFont, pt2mm, resolvePageSize } from "@pdfme/common";
|
|
3
|
-
import { measureTextHeight } from "@pdfme/schemas/utils";
|
|
2
|
+
import { getDefaultFont, isBlankPdf, pt2mm, resolvePageSize } from "@pdfme/common";
|
|
3
|
+
import { escapeInlineMarkdown, getVariableNames, measureTextHeight, visitVariables } from "@pdfme/schemas/utils";
|
|
4
4
|
//#region src/components.ts
|
|
5
5
|
var makeBuiltin = (kind) => (props) => createElementNode(kind, props);
|
|
6
6
|
var Page = makeBuiltin("page");
|
|
7
|
+
var Static = makeBuiltin("static");
|
|
8
|
+
var Header = (props) => createElementNode("static", {
|
|
9
|
+
...props,
|
|
10
|
+
placement: "top"
|
|
11
|
+
});
|
|
12
|
+
var Footer = (props) => createElementNode("static", {
|
|
13
|
+
...props,
|
|
14
|
+
placement: "bottom"
|
|
15
|
+
});
|
|
16
|
+
var Absolute = makeBuiltin("absolute");
|
|
7
17
|
var Stack = makeBuiltin("stack");
|
|
8
18
|
var Row = makeBuiltin("row");
|
|
9
19
|
var Box = makeBuiltin("box");
|
|
10
20
|
var Spacer = makeBuiltin("spacer");
|
|
11
21
|
var Text = makeBuiltin("text");
|
|
22
|
+
var MultiVariableText = makeBuiltin("multiVariableText");
|
|
23
|
+
var Image = makeBuiltin("image");
|
|
24
|
+
var Svg = makeBuiltin("svg");
|
|
25
|
+
var Rectangle = makeBuiltin("rectangle");
|
|
26
|
+
var Ellipse = makeBuiltin("ellipse");
|
|
27
|
+
var Line = makeBuiltin("line");
|
|
12
28
|
var List = makeBuiltin("list");
|
|
13
29
|
var Table = makeBuiltin("table");
|
|
14
30
|
var PageBreak = (props) => createElementNode("pagebreak", props);
|
|
@@ -18,6 +34,10 @@ var DEFAULT_FONT_SIZE = 10;
|
|
|
18
34
|
var DEFAULT_LINE_HEIGHT = 1;
|
|
19
35
|
var DEFAULT_CHARACTER_SPACING = 0;
|
|
20
36
|
var DEFAULT_FONT_COLOR = "#000000";
|
|
37
|
+
var DEFAULT_VISUAL_HEIGHT = 40;
|
|
38
|
+
var DEFAULT_LINE_THICKNESS = .5;
|
|
39
|
+
var DEFAULT_LINE_COLOR = "#000000";
|
|
40
|
+
var DEFAULT_SHAPE_BORDER_COLOR = "#000000";
|
|
21
41
|
var DEFAULT_DYNAMIC_FONT_SIZE = {
|
|
22
42
|
min: 4,
|
|
23
43
|
max: 72,
|
|
@@ -25,19 +45,43 @@ var DEFAULT_DYNAMIC_FONT_SIZE = {
|
|
|
25
45
|
};
|
|
26
46
|
var renderToTemplate = async (node, options = {}) => {
|
|
27
47
|
validatePageBreakPlacement(node);
|
|
28
|
-
const
|
|
48
|
+
const expanded = expandPageBreaks(node);
|
|
49
|
+
validateAbsolutePlacement(expanded);
|
|
50
|
+
validateNoTopLevelStatic(expanded);
|
|
51
|
+
const pages = flattenChildren(expanded).filter((child) => isPdfJsxElement(child) && child.kind === "page");
|
|
29
52
|
if (pages.length === 0) throw new Error("@pdfme/jsx: renderToTemplate root must contain at least one <Page>.");
|
|
30
53
|
const firstPageProps = pages[0]?.props;
|
|
31
54
|
const firstMargin = resolveBoxSides(firstPageProps.margin);
|
|
32
55
|
const pageSize = resolvePageSize(firstPageProps.size, firstPageProps.orientation);
|
|
33
56
|
validateConsistentPageProps(pages, pageSize, firstMargin);
|
|
57
|
+
validateStaticPlacement(pages);
|
|
58
|
+
const { pages: bodyPages, blocks: staticBlocks } = extractStaticChildren(pages);
|
|
34
59
|
const inputs = {};
|
|
35
60
|
const usedNames = /* @__PURE__ */ new Set();
|
|
36
61
|
const nameCounters = {};
|
|
37
62
|
const font = options.font ?? getDefaultFont();
|
|
38
63
|
const _cache = /* @__PURE__ */ new Map();
|
|
39
64
|
const pageSchemas = [];
|
|
40
|
-
|
|
65
|
+
const staticSchemas = [];
|
|
66
|
+
const hasStaticChildren = hasStaticBlocks(staticBlocks);
|
|
67
|
+
if (hasStaticChildren && options.basePdf != null && !isBlankPdf(options.basePdf)) throw new Error("@pdfme/jsx: <Static> is supported only with a blank basePdf.");
|
|
68
|
+
if (hasStaticChildren) await layoutStaticBlocks({
|
|
69
|
+
blocks: staticBlocks,
|
|
70
|
+
frame: {
|
|
71
|
+
x: 0,
|
|
72
|
+
y: 0,
|
|
73
|
+
width: pageSize.width,
|
|
74
|
+
height: pageSize.height
|
|
75
|
+
},
|
|
76
|
+
staticSchemas,
|
|
77
|
+
inputs,
|
|
78
|
+
usedNames,
|
|
79
|
+
nameCounters,
|
|
80
|
+
defaultFont: firstPageProps.font,
|
|
81
|
+
font,
|
|
82
|
+
_cache
|
|
83
|
+
});
|
|
84
|
+
for (const page of bodyPages) {
|
|
41
85
|
const props = page.props;
|
|
42
86
|
const margin = resolveBoxSides(props.margin);
|
|
43
87
|
const frame = {
|
|
@@ -55,21 +99,29 @@ var renderToTemplate = async (node, options = {}) => {
|
|
|
55
99
|
font,
|
|
56
100
|
_cache
|
|
57
101
|
};
|
|
58
|
-
await layoutChildren(page.children, frame, "stack", {
|
|
102
|
+
await layoutChildren(page.children, frame, "stack", {
|
|
103
|
+
gap: 0,
|
|
104
|
+
alignItems: "stretch",
|
|
105
|
+
justifyContent: "start"
|
|
106
|
+
}, ctx);
|
|
59
107
|
pageSchemas.push(ctx.schemas);
|
|
60
108
|
}
|
|
109
|
+
const basePdf = options.basePdf ?? {
|
|
110
|
+
width: pageSize.width,
|
|
111
|
+
height: pageSize.height,
|
|
112
|
+
padding: [
|
|
113
|
+
firstMargin.top,
|
|
114
|
+
firstMargin.right,
|
|
115
|
+
firstMargin.bottom,
|
|
116
|
+
firstMargin.left
|
|
117
|
+
]
|
|
118
|
+
};
|
|
61
119
|
return {
|
|
62
120
|
template: {
|
|
63
|
-
basePdf:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
firstMargin.top,
|
|
68
|
-
firstMargin.right,
|
|
69
|
-
firstMargin.bottom,
|
|
70
|
-
firstMargin.left
|
|
71
|
-
]
|
|
72
|
-
},
|
|
121
|
+
basePdf: staticSchemas.length > 0 && isBlankPdf(basePdf) ? {
|
|
122
|
+
...basePdf,
|
|
123
|
+
staticSchema: [...basePdf.staticSchema ?? [], ...staticSchemas]
|
|
124
|
+
} : basePdf,
|
|
73
125
|
schemas: pageSchemas
|
|
74
126
|
},
|
|
75
127
|
inputs: [inputs]
|
|
@@ -115,14 +167,66 @@ var flattenForSplitting = (children) => {
|
|
|
115
167
|
return [children];
|
|
116
168
|
};
|
|
117
169
|
var expandPageBreaks = (node) => splitChildrenByPageBreak(node).flat();
|
|
170
|
+
var extractStaticChildren = (pages) => {
|
|
171
|
+
const blocks = {
|
|
172
|
+
top: [],
|
|
173
|
+
bottom: []
|
|
174
|
+
};
|
|
175
|
+
return {
|
|
176
|
+
pages: pages.map((page, pageIndex) => {
|
|
177
|
+
const bodyChildren = [];
|
|
178
|
+
for (const child of flattenForSplitting(page.children)) {
|
|
179
|
+
if (isPdfJsxElement(child) && child.kind === "static") {
|
|
180
|
+
if (pageIndex === 0) blocks[getStaticPlacement(child)].push(child.children);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
bodyChildren.push(child);
|
|
184
|
+
}
|
|
185
|
+
return cloneElementWithChildren(page, bodyChildren);
|
|
186
|
+
}),
|
|
187
|
+
blocks
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
var hasStaticBlocks = (blocks) => blocks.top.length > 0 || blocks.bottom.length > 0;
|
|
191
|
+
var layoutStaticBlocks = async (arg) => {
|
|
192
|
+
for (const placement of ["top", "bottom"]) {
|
|
193
|
+
const children = arg.blocks[placement];
|
|
194
|
+
if (children.length === 0) continue;
|
|
195
|
+
const schemas = [];
|
|
196
|
+
const ctx = {
|
|
197
|
+
schemas,
|
|
198
|
+
inputs: arg.inputs,
|
|
199
|
+
usedNames: arg.usedNames,
|
|
200
|
+
nameCounters: arg.nameCounters,
|
|
201
|
+
defaultFont: arg.defaultFont,
|
|
202
|
+
font: arg.font,
|
|
203
|
+
_cache: arg._cache
|
|
204
|
+
};
|
|
205
|
+
const size = await layoutChildren(children, arg.frame, "stack", {
|
|
206
|
+
gap: 0,
|
|
207
|
+
alignItems: "stretch",
|
|
208
|
+
justifyContent: "start"
|
|
209
|
+
}, ctx);
|
|
210
|
+
if (placement === "bottom") shiftSchemas(schemas, 0, schemas.length, 0, Math.max(0, arg.frame.height - size.height));
|
|
211
|
+
arg.staticSchemas.push(...schemas);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
118
214
|
var layoutChildren = async (children, frame, mode, opts, ctx) => {
|
|
119
215
|
const items = flattenChildren(children);
|
|
120
|
-
const
|
|
216
|
+
const flowItems = items.filter((item) => !isAbsoluteElement(item));
|
|
217
|
+
const widths = mode === "row" ? resolveRowWidths(flowItems, frame.width, opts.gap) : void 0;
|
|
121
218
|
let cursor = 0;
|
|
122
219
|
let crossMax = 0;
|
|
220
|
+
let flowIndex = 0;
|
|
221
|
+
const layoutItems = [];
|
|
123
222
|
for (let i = 0; i < items.length; i += 1) {
|
|
124
223
|
const child = items[i];
|
|
125
|
-
|
|
224
|
+
if (isAbsoluteElement(child)) {
|
|
225
|
+
await renderAbsolute(child.props, child.children, frame, ctx);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const margin = getChildMargin(child);
|
|
229
|
+
const width = mode === "row" ? widths?.[flowIndex] ?? 0 : resolveStackChildWidth(child, frame.width, margin);
|
|
126
230
|
const childFrame = mode === "stack" ? {
|
|
127
231
|
x: frame.x,
|
|
128
232
|
y: frame.y + cursor,
|
|
@@ -134,68 +238,197 @@ var layoutChildren = async (children, frame, mode, opts, ctx) => {
|
|
|
134
238
|
width,
|
|
135
239
|
height: frame.height
|
|
136
240
|
};
|
|
241
|
+
childFrame.x += margin.left;
|
|
242
|
+
childFrame.y += margin.top;
|
|
243
|
+
childFrame.height = Math.max(0, childFrame.height - margin.top - margin.bottom);
|
|
244
|
+
const schemaStart = ctx.schemas.length;
|
|
137
245
|
const size = typeof child === "string" || typeof child === "number" ? await renderText({ children: String(child) }, childFrame, ctx) : await renderElement(child, childFrame, mode, ctx);
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
246
|
+
const schemaEnd = ctx.schemas.length;
|
|
247
|
+
const mainSize = mode === "stack" ? margin.top + size.height + margin.bottom : margin.left + width + margin.right;
|
|
248
|
+
const outerHeight = margin.top + size.height + margin.bottom;
|
|
249
|
+
layoutItems.push({
|
|
250
|
+
schemaStart,
|
|
251
|
+
schemaEnd,
|
|
252
|
+
outerHeight
|
|
253
|
+
});
|
|
254
|
+
if (mode === "stack") {
|
|
255
|
+
const outerWidth = margin.left + size.width + margin.right;
|
|
256
|
+
const dx = resolveAlignOffset(frame.width, outerWidth, opts.alignItems);
|
|
257
|
+
if (dx !== 0) shiftSchemas(ctx.schemas, schemaStart, schemaEnd, dx, 0);
|
|
258
|
+
}
|
|
259
|
+
cursor += mainSize + (flowIndex < flowItems.length - 1 ? opts.gap : 0);
|
|
260
|
+
flowIndex += 1;
|
|
261
|
+
crossMax = Math.max(crossMax, mode === "stack" ? margin.left + size.width + margin.right : margin.top + size.height + margin.bottom);
|
|
262
|
+
}
|
|
263
|
+
const contentMainSize = cursor;
|
|
264
|
+
const containerMainSize = opts.mainSize ?? contentMainSize;
|
|
265
|
+
applyJustifyContent(ctx.schemas, layoutItems, mode, contentMainSize, containerMainSize, opts);
|
|
266
|
+
if (mode === "row") {
|
|
267
|
+
const rowHeight = opts.crossSize ?? crossMax;
|
|
268
|
+
for (const item of layoutItems) {
|
|
269
|
+
const dy = resolveAlignOffset(rowHeight, item.outerHeight, opts.alignItems);
|
|
270
|
+
if (dy !== 0) shiftSchemas(ctx.schemas, item.schemaStart, item.schemaEnd, 0, dy);
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
width: containerMainSize,
|
|
274
|
+
height: rowHeight
|
|
275
|
+
};
|
|
141
276
|
}
|
|
142
|
-
return
|
|
277
|
+
return {
|
|
143
278
|
width: crossMax,
|
|
144
|
-
height:
|
|
145
|
-
} : {
|
|
146
|
-
width: cursor,
|
|
147
|
-
height: crossMax
|
|
279
|
+
height: containerMainSize
|
|
148
280
|
};
|
|
149
281
|
};
|
|
150
282
|
var resolveRowWidths = (items, frameWidth, gap) => {
|
|
151
|
-
let
|
|
152
|
-
let
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
283
|
+
let usedWidth = 0;
|
|
284
|
+
let totalGrow = 0;
|
|
285
|
+
const parts = items.map((item) => {
|
|
286
|
+
const margin = getChildMargin(item);
|
|
287
|
+
const width = getChildWidth(item);
|
|
288
|
+
const grow = getChildFlexGrow(item) ?? (width == null ? 1 : 0);
|
|
289
|
+
const basis = width ?? 0;
|
|
290
|
+
usedWidth += basis + margin.left + margin.right;
|
|
291
|
+
totalGrow += grow;
|
|
292
|
+
return {
|
|
293
|
+
basis,
|
|
294
|
+
grow
|
|
295
|
+
};
|
|
164
296
|
});
|
|
165
|
-
const remaining = Math.max(0, frameWidth -
|
|
166
|
-
const
|
|
167
|
-
return
|
|
297
|
+
const remaining = Math.max(0, frameWidth - usedWidth - Math.max(0, items.length - 1) * gap);
|
|
298
|
+
const flexUnit = totalGrow > 0 ? remaining / totalGrow : 0;
|
|
299
|
+
return parts.map(({ basis, grow }) => basis + grow * flexUnit);
|
|
300
|
+
};
|
|
301
|
+
var getChildMargin = (child) => {
|
|
302
|
+
if (typeof child === "string" || typeof child === "number") return resolveBoxSides();
|
|
303
|
+
return resolveBoxSides(child.props.margin);
|
|
304
|
+
};
|
|
305
|
+
var getChildWidth = (child) => {
|
|
306
|
+
if (typeof child === "string" || typeof child === "number") return void 0;
|
|
307
|
+
const width = child.props.width;
|
|
308
|
+
return typeof width === "number" ? width : void 0;
|
|
309
|
+
};
|
|
310
|
+
var getChildFlexGrow = (child) => {
|
|
311
|
+
if (typeof child === "string" || typeof child === "number") return void 0;
|
|
312
|
+
const props = child.props;
|
|
313
|
+
const flexGrow = props.flexGrow ?? props.flex;
|
|
314
|
+
return typeof flexGrow === "number" ? Math.max(0, flexGrow) : void 0;
|
|
315
|
+
};
|
|
316
|
+
var isAbsoluteElement = (child) => isPdfJsxElement(child) && child.kind === "absolute";
|
|
317
|
+
var getStaticPlacement = (element) => {
|
|
318
|
+
const placement = element.props.placement ?? "top";
|
|
319
|
+
if (placement !== "top" && placement !== "bottom") throw new Error("@pdfme/jsx: <Static> placement must be \"top\" or \"bottom\".");
|
|
320
|
+
return placement;
|
|
321
|
+
};
|
|
322
|
+
var resolveStackChildWidth = (child, frameWidth, margin) => {
|
|
323
|
+
const width = getChildWidth(child);
|
|
324
|
+
if (width != null) return width;
|
|
325
|
+
return Math.max(0, frameWidth - margin.left - margin.right);
|
|
326
|
+
};
|
|
327
|
+
var applyJustifyContent = (schemas, items, mode, contentMainSize, containerMainSize, opts) => {
|
|
328
|
+
const extraSpace = Math.max(0, containerMainSize - contentMainSize);
|
|
329
|
+
if (extraSpace === 0 || opts.justifyContent === "start") return;
|
|
330
|
+
const extraGap = opts.justifyContent === "space-between" && items.length > 1 ? extraSpace / (items.length - 1) : 0;
|
|
331
|
+
const startOffset = opts.justifyContent === "center" ? extraSpace / 2 : opts.justifyContent === "end" ? extraSpace : 0;
|
|
332
|
+
let runningExtraGap = 0;
|
|
333
|
+
for (const item of items) {
|
|
334
|
+
const offset = startOffset + runningExtraGap;
|
|
335
|
+
if (offset !== 0) shiftSchemas(schemas, item.schemaStart, item.schemaEnd, mode === "row" ? offset : 0, mode === "stack" ? offset : 0);
|
|
336
|
+
runningExtraGap += extraGap;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
var resolveAlignOffset = (containerSize, itemSize, alignItems) => {
|
|
340
|
+
if (alignItems === "center") return Math.max(0, (containerSize - itemSize) / 2);
|
|
341
|
+
if (alignItems === "end") return Math.max(0, containerSize - itemSize);
|
|
342
|
+
return 0;
|
|
343
|
+
};
|
|
344
|
+
var shiftSchemas = (schemas, start, end, dx, dy) => {
|
|
345
|
+
for (let i = start; i < end; i += 1) {
|
|
346
|
+
const schema = schemas[i];
|
|
347
|
+
if (!schema) continue;
|
|
348
|
+
schema.position = {
|
|
349
|
+
x: schema.position.x + dx,
|
|
350
|
+
y: schema.position.y + dy
|
|
351
|
+
};
|
|
352
|
+
}
|
|
168
353
|
};
|
|
169
354
|
var renderElement = async (element, frame, parentMode, ctx) => {
|
|
355
|
+
const props = parentMode === "row" && getChildFlexGrow(element) != null ? {
|
|
356
|
+
...element.props,
|
|
357
|
+
width: frame.width
|
|
358
|
+
} : element.props;
|
|
170
359
|
switch (element.kind) {
|
|
171
|
-
case "stack": return renderStack(
|
|
172
|
-
case "row": return renderRow(
|
|
173
|
-
case "box": return renderBox(
|
|
174
|
-
case "spacer": return Promise.resolve(renderSpacer(
|
|
360
|
+
case "stack": return renderStack(props, element.children, frame, ctx);
|
|
361
|
+
case "row": return renderRow(props, element.children, frame, ctx);
|
|
362
|
+
case "box": return renderBox(props, element.children, frame, parentMode, ctx);
|
|
363
|
+
case "spacer": return Promise.resolve(renderSpacer(props));
|
|
175
364
|
case "text": return renderText({
|
|
176
|
-
...
|
|
365
|
+
...props,
|
|
366
|
+
children: element.children
|
|
367
|
+
}, frame, ctx);
|
|
368
|
+
case "multiVariableText": return renderMultiVariableText({
|
|
369
|
+
...props,
|
|
370
|
+
children: element.children
|
|
371
|
+
}, frame, ctx);
|
|
372
|
+
case "image": return renderImage(props, frame, ctx);
|
|
373
|
+
case "svg": return renderSvg({
|
|
374
|
+
...props,
|
|
177
375
|
children: element.children
|
|
178
376
|
}, frame, ctx);
|
|
377
|
+
case "rectangle": return renderShape("rectangle", props, frame, ctx);
|
|
378
|
+
case "ellipse": return renderShape("ellipse", props, frame, ctx);
|
|
379
|
+
case "line": return renderLine(props, frame, ctx);
|
|
179
380
|
case "list": return renderList({
|
|
180
|
-
...
|
|
381
|
+
...props,
|
|
181
382
|
children: element.children
|
|
182
383
|
}, frame, ctx);
|
|
183
|
-
case "table": return renderTable(
|
|
384
|
+
case "table": return renderTable(props, frame, ctx);
|
|
385
|
+
case "static": throw new Error("@pdfme/jsx: <Static> can only be used as a direct child of the first <Page>.");
|
|
386
|
+
case "absolute": return renderAbsolute(props, element.children, frame, ctx);
|
|
184
387
|
default: return {
|
|
185
388
|
width: 0,
|
|
186
389
|
height: 0
|
|
187
390
|
};
|
|
188
391
|
}
|
|
189
392
|
};
|
|
393
|
+
var renderAbsolute = async (props, children, frame, ctx) => {
|
|
394
|
+
const x = props.x ?? 0;
|
|
395
|
+
const y = props.y ?? 0;
|
|
396
|
+
await layoutChildren(children, {
|
|
397
|
+
x: frame.x + x,
|
|
398
|
+
y: frame.y + y,
|
|
399
|
+
width: props.width ?? Math.max(0, frame.width - x),
|
|
400
|
+
height: props.height ?? Math.max(0, frame.height - y)
|
|
401
|
+
}, "stack", {
|
|
402
|
+
gap: 0,
|
|
403
|
+
alignItems: "stretch",
|
|
404
|
+
justifyContent: "start"
|
|
405
|
+
}, ctx);
|
|
406
|
+
return {
|
|
407
|
+
width: 0,
|
|
408
|
+
height: 0
|
|
409
|
+
};
|
|
410
|
+
};
|
|
190
411
|
var renderStack = (props, children, frame, ctx) => layoutChildren(children, {
|
|
191
412
|
...frame,
|
|
192
|
-
width: props.width ?? frame.width
|
|
193
|
-
|
|
413
|
+
width: props.width ?? frame.width,
|
|
414
|
+
height: props.height ?? frame.height
|
|
415
|
+
}, "stack", {
|
|
416
|
+
gap: props.gap ?? 0,
|
|
417
|
+
alignItems: props.alignItems ?? "stretch",
|
|
418
|
+
justifyContent: props.justifyContent ?? "start",
|
|
419
|
+
mainSize: props.height
|
|
420
|
+
}, ctx);
|
|
194
421
|
var renderRow = (props, children, frame, ctx) => layoutChildren(children, {
|
|
195
422
|
...frame,
|
|
196
423
|
width: props.width ?? frame.width,
|
|
197
424
|
height: props.height ?? frame.height
|
|
198
|
-
}, "row", {
|
|
425
|
+
}, "row", {
|
|
426
|
+
gap: props.gap ?? 0,
|
|
427
|
+
alignItems: props.alignItems ?? "start",
|
|
428
|
+
justifyContent: props.justifyContent ?? "start",
|
|
429
|
+
mainSize: props.width,
|
|
430
|
+
crossSize: props.height
|
|
431
|
+
}, ctx);
|
|
199
432
|
var renderBox = async (props, children, frame, _parentMode, ctx) => {
|
|
200
433
|
const width = props.width ?? frame.width;
|
|
201
434
|
const padding = resolveBoxSides(props.padding);
|
|
@@ -223,7 +456,11 @@ var renderBox = async (props, children, frame, _parentMode, ctx) => {
|
|
|
223
456
|
y: frame.y + padding.top,
|
|
224
457
|
width: width - padding.left - padding.right,
|
|
225
458
|
height: (props.height ?? frame.height) - padding.top - padding.bottom
|
|
226
|
-
}, "stack", {
|
|
459
|
+
}, "stack", {
|
|
460
|
+
gap: 0,
|
|
461
|
+
alignItems: "stretch",
|
|
462
|
+
justifyContent: "start"
|
|
463
|
+
}, ctx);
|
|
227
464
|
const height = props.height ?? childSize.height + padding.top + padding.bottom;
|
|
228
465
|
if (needsRect) ctx.schemas[beforeCount] = {
|
|
229
466
|
...ctx.schemas[beforeCount],
|
|
@@ -243,8 +480,10 @@ var renderText = async (props, frame, ctx) => {
|
|
|
243
480
|
const lineHeight = props.lineHeight ?? DEFAULT_LINE_HEIGHT;
|
|
244
481
|
const width = props.width ?? frame.width;
|
|
245
482
|
const value = childrenToString(props.children);
|
|
246
|
-
const name = resolveName(ctx, "text", props.name);
|
|
247
483
|
const readOnly = props.readOnly ?? props.name == null;
|
|
484
|
+
const textFormat = props.textFormat ?? "plain";
|
|
485
|
+
if (!readOnly && textFormat === "inline-markdown") throw new Error("@pdfme/jsx: editable <Text> does not support textFormat=\"inline-markdown\". Use read-only <Text> or <MultiVariableText>.");
|
|
486
|
+
const name = resolveName(ctx, "text", props.name);
|
|
248
487
|
const schema = {
|
|
249
488
|
name,
|
|
250
489
|
type: "text",
|
|
@@ -267,13 +506,14 @@ var renderText = async (props, frame, ctx) => {
|
|
|
267
506
|
characterSpacing: props.spacing ?? DEFAULT_CHARACTER_SPACING,
|
|
268
507
|
fontColor: props.color ?? DEFAULT_FONT_COLOR,
|
|
269
508
|
backgroundColor: props.background ?? "",
|
|
270
|
-
textFormat
|
|
509
|
+
textFormat,
|
|
271
510
|
overflow: props.overflow,
|
|
272
511
|
strikethrough: props.strikethrough ?? false,
|
|
273
512
|
underline: props.underline ?? false
|
|
274
513
|
};
|
|
275
514
|
if (props.borderColor) schema.borderColor = props.borderColor;
|
|
276
|
-
if (props.borderWidth != null) schema.borderWidth = props.borderWidth;
|
|
515
|
+
if (props.borderWidth != null) schema.borderWidth = resolveBoxSides(props.borderWidth);
|
|
516
|
+
if (props.padding != null) schema.padding = resolveBoxSides(props.padding);
|
|
277
517
|
if (props.dynamicFontSize) schema.dynamicFontSize = {
|
|
278
518
|
min: props.dynamicFontSize.min ?? DEFAULT_DYNAMIC_FONT_SIZE.min,
|
|
279
519
|
max: props.dynamicFontSize.max ?? DEFAULT_DYNAMIC_FONT_SIZE.max,
|
|
@@ -292,6 +532,174 @@ var renderText = async (props, frame, ctx) => {
|
|
|
292
532
|
height: schema.height
|
|
293
533
|
};
|
|
294
534
|
};
|
|
535
|
+
var renderMultiVariableText = async (props, frame, ctx) => {
|
|
536
|
+
const fontSize = props.size ?? DEFAULT_FONT_SIZE;
|
|
537
|
+
const lineHeight = props.lineHeight ?? DEFAULT_LINE_HEIGHT;
|
|
538
|
+
const width = props.width ?? frame.width;
|
|
539
|
+
const templateText = props.text ?? childrenToString(props.children);
|
|
540
|
+
const values = normalizeMultiVariableTextValues(props.values);
|
|
541
|
+
const variables = resolveMultiVariableTextVariables(templateText, props.variables, values);
|
|
542
|
+
const name = resolveName(ctx, "multiVariableText", props.name);
|
|
543
|
+
const readOnly = props.readOnly ?? props.name == null;
|
|
544
|
+
const textFormat = props.textFormat ?? "plain";
|
|
545
|
+
const content = readOnly ? substituteMultiVariableText(templateText, values, textFormat === "inline-markdown") : JSON.stringify(values);
|
|
546
|
+
const schema = {
|
|
547
|
+
name,
|
|
548
|
+
type: "multiVariableText",
|
|
549
|
+
content,
|
|
550
|
+
position: {
|
|
551
|
+
x: frame.x,
|
|
552
|
+
y: frame.y
|
|
553
|
+
},
|
|
554
|
+
width,
|
|
555
|
+
height: props.height ?? 0,
|
|
556
|
+
rotate: props.rotate ?? 0,
|
|
557
|
+
opacity: props.opacity ?? 1,
|
|
558
|
+
readOnly,
|
|
559
|
+
required: props.required,
|
|
560
|
+
alignment: props.align ?? "left",
|
|
561
|
+
verticalAlignment: props.valign ?? "top",
|
|
562
|
+
fontSize,
|
|
563
|
+
fontName: props.font ?? ctx.defaultFont,
|
|
564
|
+
lineHeight,
|
|
565
|
+
characterSpacing: props.spacing ?? DEFAULT_CHARACTER_SPACING,
|
|
566
|
+
fontColor: props.color ?? DEFAULT_FONT_COLOR,
|
|
567
|
+
backgroundColor: props.background ?? "",
|
|
568
|
+
textFormat,
|
|
569
|
+
overflow: props.overflow,
|
|
570
|
+
strikethrough: props.strikethrough ?? false,
|
|
571
|
+
underline: props.underline ?? false,
|
|
572
|
+
text: templateText,
|
|
573
|
+
variables
|
|
574
|
+
};
|
|
575
|
+
if (props.borderColor) schema.borderColor = props.borderColor;
|
|
576
|
+
if (props.borderWidth != null) schema.borderWidth = resolveBoxSides(props.borderWidth);
|
|
577
|
+
if (props.padding != null) schema.padding = resolveBoxSides(props.padding);
|
|
578
|
+
if (props.dynamicFontSize) schema.dynamicFontSize = {
|
|
579
|
+
min: props.dynamicFontSize.min ?? DEFAULT_DYNAMIC_FONT_SIZE.min,
|
|
580
|
+
max: props.dynamicFontSize.max ?? DEFAULT_DYNAMIC_FONT_SIZE.max,
|
|
581
|
+
fit: props.dynamicFontSize.fit ?? DEFAULT_DYNAMIC_FONT_SIZE.fit
|
|
582
|
+
};
|
|
583
|
+
if (props.height == null) schema.height = await measureTextHeight({
|
|
584
|
+
value: readOnly ? content : substituteMultiVariableText(templateText, values, textFormat === "inline-markdown"),
|
|
585
|
+
schema,
|
|
586
|
+
font: ctx.font,
|
|
587
|
+
_cache: ctx._cache
|
|
588
|
+
});
|
|
589
|
+
if (!readOnly) ctx.inputs[name] = content;
|
|
590
|
+
ctx.schemas.push(schema);
|
|
591
|
+
return {
|
|
592
|
+
width,
|
|
593
|
+
height: schema.height
|
|
594
|
+
};
|
|
595
|
+
};
|
|
596
|
+
var renderImage = (props, frame, ctx) => {
|
|
597
|
+
const width = props.width ?? frame.width;
|
|
598
|
+
const height = props.height ?? DEFAULT_VISUAL_HEIGHT;
|
|
599
|
+
const name = resolveName(ctx, "image", props.name);
|
|
600
|
+
const readOnly = props.readOnly ?? props.name == null;
|
|
601
|
+
const content = props.src ?? "";
|
|
602
|
+
const schema = {
|
|
603
|
+
name,
|
|
604
|
+
type: "image",
|
|
605
|
+
content,
|
|
606
|
+
position: {
|
|
607
|
+
x: frame.x,
|
|
608
|
+
y: frame.y
|
|
609
|
+
},
|
|
610
|
+
width,
|
|
611
|
+
height,
|
|
612
|
+
rotate: props.rotate ?? 0,
|
|
613
|
+
opacity: props.opacity ?? 1,
|
|
614
|
+
readOnly,
|
|
615
|
+
required: props.required
|
|
616
|
+
};
|
|
617
|
+
if (!readOnly) ctx.inputs[name] = content;
|
|
618
|
+
ctx.schemas.push(schema);
|
|
619
|
+
return {
|
|
620
|
+
width,
|
|
621
|
+
height
|
|
622
|
+
};
|
|
623
|
+
};
|
|
624
|
+
var renderSvg = (props, frame, ctx) => {
|
|
625
|
+
const width = props.width ?? frame.width;
|
|
626
|
+
const height = props.height ?? DEFAULT_VISUAL_HEIGHT;
|
|
627
|
+
const name = resolveName(ctx, "svg", props.name);
|
|
628
|
+
const readOnly = props.readOnly ?? props.name == null;
|
|
629
|
+
const content = props.svg ?? childrenToString(props.children);
|
|
630
|
+
const schema = {
|
|
631
|
+
name,
|
|
632
|
+
type: "svg",
|
|
633
|
+
content,
|
|
634
|
+
position: {
|
|
635
|
+
x: frame.x,
|
|
636
|
+
y: frame.y
|
|
637
|
+
},
|
|
638
|
+
width,
|
|
639
|
+
height,
|
|
640
|
+
rotate: props.rotate ?? 0,
|
|
641
|
+
opacity: props.opacity ?? 1,
|
|
642
|
+
readOnly,
|
|
643
|
+
required: props.required
|
|
644
|
+
};
|
|
645
|
+
if (!readOnly) ctx.inputs[name] = content;
|
|
646
|
+
ctx.schemas.push(schema);
|
|
647
|
+
return {
|
|
648
|
+
width,
|
|
649
|
+
height
|
|
650
|
+
};
|
|
651
|
+
};
|
|
652
|
+
var renderShape = (type, props, frame, ctx) => {
|
|
653
|
+
const width = props.width ?? frame.width;
|
|
654
|
+
const height = props.height ?? DEFAULT_VISUAL_HEIGHT;
|
|
655
|
+
const fill = props.fill ?? "";
|
|
656
|
+
const borderWidth = props.borderWidth ?? (props.borderColor || !fill ? 1 : 0);
|
|
657
|
+
const schema = {
|
|
658
|
+
name: resolveName(ctx, type, props.name),
|
|
659
|
+
type,
|
|
660
|
+
position: {
|
|
661
|
+
x: frame.x,
|
|
662
|
+
y: frame.y
|
|
663
|
+
},
|
|
664
|
+
width,
|
|
665
|
+
height,
|
|
666
|
+
rotate: props.rotate ?? 0,
|
|
667
|
+
opacity: props.opacity ?? 1,
|
|
668
|
+
readOnly: true,
|
|
669
|
+
borderWidth,
|
|
670
|
+
borderColor: props.borderColor ?? (borderWidth > 0 ? DEFAULT_SHAPE_BORDER_COLOR : ""),
|
|
671
|
+
color: fill,
|
|
672
|
+
radius: type === "rectangle" ? props.radius ?? 0 : 0
|
|
673
|
+
};
|
|
674
|
+
ctx.schemas.push(schema);
|
|
675
|
+
return {
|
|
676
|
+
width,
|
|
677
|
+
height
|
|
678
|
+
};
|
|
679
|
+
};
|
|
680
|
+
var renderLine = (props, frame, ctx) => {
|
|
681
|
+
const width = props.width ?? frame.width;
|
|
682
|
+
const height = props.height ?? DEFAULT_LINE_THICKNESS;
|
|
683
|
+
const schema = {
|
|
684
|
+
name: resolveName(ctx, "line", props.name),
|
|
685
|
+
type: "line",
|
|
686
|
+
position: {
|
|
687
|
+
x: frame.x,
|
|
688
|
+
y: frame.y
|
|
689
|
+
},
|
|
690
|
+
width,
|
|
691
|
+
height,
|
|
692
|
+
rotate: props.rotate ?? 0,
|
|
693
|
+
opacity: props.opacity ?? 1,
|
|
694
|
+
readOnly: true,
|
|
695
|
+
color: props.color ?? DEFAULT_LINE_COLOR
|
|
696
|
+
};
|
|
697
|
+
ctx.schemas.push(schema);
|
|
698
|
+
return {
|
|
699
|
+
width,
|
|
700
|
+
height
|
|
701
|
+
};
|
|
702
|
+
};
|
|
295
703
|
var renderList = (props, frame, ctx) => {
|
|
296
704
|
const fontSize = props.size ?? DEFAULT_FONT_SIZE;
|
|
297
705
|
const lineHeight = props.lineHeight ?? DEFAULT_LINE_HEIGHT;
|
|
@@ -363,7 +771,7 @@ var renderTable = (props, frame, ctx) => {
|
|
|
363
771
|
showHead,
|
|
364
772
|
repeatHead: props.repeatHead ?? false,
|
|
365
773
|
head: props.head,
|
|
366
|
-
headWidthPercentages:
|
|
774
|
+
headWidthPercentages: normalizeColumnWeights(props.columnWeights, props.head.length),
|
|
367
775
|
tableStyles: {
|
|
368
776
|
borderColor: props.tableStyles?.borderColor ?? "#000000",
|
|
369
777
|
borderWidth: props.tableStyles?.borderWidth ?? .3
|
|
@@ -402,8 +810,47 @@ var normalizeListItems = (props) => {
|
|
|
402
810
|
}));
|
|
403
811
|
};
|
|
404
812
|
var serializeListItem = (item) => `${" ".repeat(Math.max(0, item.level))}${item.text}`;
|
|
405
|
-
var
|
|
406
|
-
|
|
813
|
+
var normalizeMultiVariableTextValues = (values) => {
|
|
814
|
+
const normalized = {};
|
|
815
|
+
Object.entries(values ?? {}).forEach(([key, value]) => {
|
|
816
|
+
normalized[key] = value == null ? "" : String(value);
|
|
817
|
+
});
|
|
818
|
+
return normalized;
|
|
819
|
+
};
|
|
820
|
+
var resolveMultiVariableTextVariables = (templateText, variables, values) => {
|
|
821
|
+
const result = [];
|
|
822
|
+
const seen = /* @__PURE__ */ new Set();
|
|
823
|
+
const add = (name) => {
|
|
824
|
+
if (!seen.has(name)) {
|
|
825
|
+
seen.add(name);
|
|
826
|
+
result.push(name);
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
variables?.forEach(add);
|
|
830
|
+
getVariableNames(templateText).forEach(add);
|
|
831
|
+
Object.keys(values).forEach(add);
|
|
832
|
+
return result;
|
|
833
|
+
};
|
|
834
|
+
var substituteMultiVariableText = (templateText, values, escapeMarkdown) => {
|
|
835
|
+
let result = "";
|
|
836
|
+
let lastIndex = 0;
|
|
837
|
+
visitVariables(templateText, ({ name, startIndex, endIndex }) => {
|
|
838
|
+
result += templateText.slice(lastIndex, startIndex);
|
|
839
|
+
const value = values[name];
|
|
840
|
+
if (value != null) result += escapeMarkdown ? escapeInlineMarkdown(value) : value;
|
|
841
|
+
lastIndex = endIndex + 1;
|
|
842
|
+
});
|
|
843
|
+
return result + templateText.slice(lastIndex);
|
|
844
|
+
};
|
|
845
|
+
var normalizeColumnWeights = (columnWeights, columnCount) => {
|
|
846
|
+
if (columnWeights && columnWeights.length > 0) {
|
|
847
|
+
const normalizedWidths = Array.from({ length: columnCount }, (_, index) => {
|
|
848
|
+
const width = columnWeights[index];
|
|
849
|
+
return typeof width === "number" && Number.isFinite(width) && width > 0 ? width : 1;
|
|
850
|
+
});
|
|
851
|
+
const totalWidth = normalizedWidths.reduce((sum, width) => sum + width, 0);
|
|
852
|
+
if (totalWidth > 0) return normalizedWidths.map((width) => width / totalWidth * 100);
|
|
853
|
+
}
|
|
407
854
|
if (columnCount <= 0) return [];
|
|
408
855
|
return Array.from({ length: columnCount }, () => 100 / columnCount);
|
|
409
856
|
};
|
|
@@ -491,6 +938,26 @@ var PAGE_BREAK_PARENT_KINDS = new Set([
|
|
|
491
938
|
"stack",
|
|
492
939
|
"box"
|
|
493
940
|
]);
|
|
941
|
+
var STATIC_CONTAINER_KINDS = new Set([
|
|
942
|
+
"absolute",
|
|
943
|
+
"stack",
|
|
944
|
+
"row",
|
|
945
|
+
"box"
|
|
946
|
+
]);
|
|
947
|
+
var STATIC_LEAF_KINDS = new Set([
|
|
948
|
+
"spacer",
|
|
949
|
+
"text",
|
|
950
|
+
"image",
|
|
951
|
+
"svg",
|
|
952
|
+
"rectangle",
|
|
953
|
+
"ellipse",
|
|
954
|
+
"line"
|
|
955
|
+
]);
|
|
956
|
+
var ABSOLUTE_PARENT_KINDS = new Set([
|
|
957
|
+
"page",
|
|
958
|
+
"static",
|
|
959
|
+
"box"
|
|
960
|
+
]);
|
|
494
961
|
var validatePageBreakPlacement = (node, parentKind = void 0, canBreak = false) => {
|
|
495
962
|
for (const child of flattenForSplitting(node)) {
|
|
496
963
|
if (!isPdfJsxElement(child)) continue;
|
|
@@ -502,7 +969,61 @@ var validatePageBreakPlacement = (node, parentKind = void 0, canBreak = false) =
|
|
|
502
969
|
validatePageBreakPlacement(child.children, child.kind, childCanBreak);
|
|
503
970
|
}
|
|
504
971
|
};
|
|
972
|
+
var validateAbsolutePlacement = (node, parentKind = void 0) => {
|
|
973
|
+
for (const child of flattenForSplitting(node)) {
|
|
974
|
+
if (!isPdfJsxElement(child)) continue;
|
|
975
|
+
if (child.kind === "absolute" && (!parentKind || !ABSOLUTE_PARENT_KINDS.has(parentKind))) throw new Error("@pdfme/jsx: <Absolute> can only be used inside <Page>, <Static>, or <Box>.");
|
|
976
|
+
validateAbsolutePlacement(child.children, child.kind);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
var validateStaticPlacement = (pages) => {
|
|
980
|
+
for (let pageIndex = 0; pageIndex < pages.length; pageIndex += 1) {
|
|
981
|
+
const page = pages[pageIndex];
|
|
982
|
+
for (const child of flattenForSplitting(page?.children ?? [])) {
|
|
983
|
+
if (isPdfJsxElement(child) && child.kind === "static") {
|
|
984
|
+
if (pageIndex !== 0) throw new Error("@pdfme/jsx: <Static> must appear before any <PageBreak> and can only be used inside the first <Page>.");
|
|
985
|
+
if (getStaticPlacement(child) === "bottom" && hasElementKind(child.children, "absolute")) throw new Error("@pdfme/jsx: <Absolute> is not supported inside bottom <Static>. Use top <Static> or <Page> for fixed page coordinates.");
|
|
986
|
+
validateStaticChildren(child.children);
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
validateNoNestedStatic(child);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
var validateNoNestedStatic = (node) => {
|
|
994
|
+
if (!isPdfJsxElement(node)) return;
|
|
995
|
+
for (const child of flattenForSplitting(node.children)) {
|
|
996
|
+
if (isPdfJsxElement(child) && child.kind === "static") throw new Error("@pdfme/jsx: <Static> can only be used as a direct child of the first <Page>.");
|
|
997
|
+
validateNoNestedStatic(child);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
var hasElementKind = (node, kind) => {
|
|
1001
|
+
for (const child of flattenForSplitting(node)) {
|
|
1002
|
+
if (!isPdfJsxElement(child)) continue;
|
|
1003
|
+
if (child.kind === kind || hasElementKind(child.children, kind)) return true;
|
|
1004
|
+
}
|
|
1005
|
+
return false;
|
|
1006
|
+
};
|
|
1007
|
+
var validateNoTopLevelStatic = (node) => {
|
|
1008
|
+
for (const child of flattenChildren(node)) if (isPdfJsxElement(child) && child.kind === "static") throw new Error("@pdfme/jsx: <Static> can only be used as a direct child of the first <Page>.");
|
|
1009
|
+
};
|
|
1010
|
+
var validateStaticChildren = (children) => {
|
|
1011
|
+
for (const child of flattenForSplitting(children)) {
|
|
1012
|
+
if (!isPdfJsxElement(child)) continue;
|
|
1013
|
+
if (STATIC_CONTAINER_KINDS.has(child.kind)) {
|
|
1014
|
+
validateStaticChildren(child.children);
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (!STATIC_LEAF_KINDS.has(child.kind)) throw new Error(`@pdfme/jsx: <Static> does not support <${child.kind}> children. Supported: read-only Stack, Row, Box, Spacer, Text, Image, Svg, Rectangle, Ellipse, and Line.`);
|
|
1018
|
+
validateStaticLeafProps(child);
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
var validateStaticLeafProps = (element) => {
|
|
1022
|
+
if (element.kind !== "text" && element.kind !== "image" && element.kind !== "svg") return;
|
|
1023
|
+
const props = element.props;
|
|
1024
|
+
if (props.readOnly === false || props.name != null && props.readOnly !== true) throw new Error("@pdfme/jsx: <Static> children must be read-only.");
|
|
1025
|
+
};
|
|
505
1026
|
//#endregion
|
|
506
|
-
export { Box, List, Page, PageBreak, Row, Spacer, Stack, Table, Text, renderToTemplate };
|
|
1027
|
+
export { Absolute, Box, Ellipse, Footer, Header, Image, Line, List, MultiVariableText, Page, PageBreak, Rectangle, Row, Spacer, Stack, Static, Svg, Table, Text, renderToTemplate };
|
|
507
1028
|
|
|
508
1029
|
//# sourceMappingURL=index.js.map
|