@broadpaper/forme 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/{chunk-2C3MAW2U.js → chunk-FAKBQDQG.js} +199 -23
- package/dist/chunk-FAKBQDQG.js.map +1 -0
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.js +11 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +89 -14
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-2C3MAW2U.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Browserless PDF generation for BroadPaper, via the Forme WebAssembly engine. The recommended backend.
|
|
8
8
|
|
|
9
|
-
Part of [**BroadPaper**](https://www.broadpaper.com/developers
|
|
9
|
+
Part of [**BroadPaper**](https://www.broadpaper.com/developers/?utm_source=npm&utm_medium=readme) — an embeddable visual report designer and PDF renderer.
|
|
10
10
|
Your users design the report in your application; BroadPaper owns the layout, the branding,
|
|
11
11
|
the pagination and the output.
|
|
12
12
|
|
|
@@ -43,7 +43,7 @@ production use. No seats, no activation, no machine binding, no telemetry, and n
|
|
|
43
43
|
any point.
|
|
44
44
|
|
|
45
45
|
- [How licensing works](https://www.broadpaper.com/docs/guide/licensing/)
|
|
46
|
-
- [Pricing](https://www.broadpaper.com/developers/pricing
|
|
46
|
+
- [Pricing](https://www.broadpaper.com/developers/pricing/?utm_source=npm&utm_medium=readme)
|
|
47
47
|
- [Licence agreement](https://www.broadpaper.com/legal/terms/)
|
|
48
48
|
|
|
49
49
|
## Documentation
|
|
@@ -51,6 +51,8 @@ any point.
|
|
|
51
51
|
- [Browserless PDF](https://www.broadpaper.com/docs/guide/browserless-pdf)
|
|
52
52
|
- [Themes and branding](https://www.broadpaper.com/docs/guide/themes)
|
|
53
53
|
- [Full documentation](https://www.broadpaper.com/docs/)
|
|
54
|
+
- [Sample application](https://github.com/codingbadger/broadpaper-sample-application): the same app in React and Angular over one .NET back end
|
|
55
|
+
- [How BroadPaper compares](https://www.broadpaper.com/developers/compare/?utm_source=npm&utm_medium=readme) with react-pdf, pdfmake, Puppeteer and embedded report designers
|
|
54
56
|
|
|
55
57
|
## Support
|
|
56
58
|
|
|
@@ -38,6 +38,21 @@ function num(value) {
|
|
|
38
38
|
const n = Number.parseFloat(value);
|
|
39
39
|
return Number.isFinite(n) ? n : void 0;
|
|
40
40
|
}
|
|
41
|
+
function flexShorthand(value) {
|
|
42
|
+
const v = value.trim().toLowerCase();
|
|
43
|
+
if (v === "none") return { grow: 0, shrink: 0 };
|
|
44
|
+
if (v === "auto") return { grow: 1, shrink: 1 };
|
|
45
|
+
if (v === "initial") return { grow: 0, shrink: 1 };
|
|
46
|
+
const parts = v.split(/\s+/).filter(Boolean);
|
|
47
|
+
const isCount = (p) => /^-?(\d+\.?\d*|\.\d+)$/.test(p);
|
|
48
|
+
const [a, b, c] = parts;
|
|
49
|
+
if (!a) return {};
|
|
50
|
+
if (parts.length === 1) return isCount(a) ? { grow: num(a), shrink: 1, basis: 0 } : { grow: 1, shrink: 1, basis: length(a) };
|
|
51
|
+
if (parts.length === 2) {
|
|
52
|
+
return isCount(b) ? { grow: num(a), shrink: num(b), basis: 0 } : { grow: num(a), shrink: 1, basis: length(b) };
|
|
53
|
+
}
|
|
54
|
+
return { grow: num(a), shrink: num(b), basis: length(c) };
|
|
55
|
+
}
|
|
41
56
|
function colour(value) {
|
|
42
57
|
const v = value.trim().toLowerCase();
|
|
43
58
|
if (!v || v === "transparent" || v === "none" || v === "inherit" || v === "currentcolor") return void 0;
|
|
@@ -127,9 +142,13 @@ function translateStyle(css) {
|
|
|
127
142
|
case "flex-wrap":
|
|
128
143
|
set("flexWrap", value === "wrap" ? "wrap" : "nowrap");
|
|
129
144
|
break;
|
|
130
|
-
case "flex":
|
|
131
|
-
|
|
145
|
+
case "flex": {
|
|
146
|
+
const f = flexShorthand(value);
|
|
147
|
+
set("flexGrow", f.grow);
|
|
148
|
+
set("flexShrink", f.shrink);
|
|
149
|
+
set("flexBasis", f.basis);
|
|
132
150
|
break;
|
|
151
|
+
}
|
|
133
152
|
case "flex-grow":
|
|
134
153
|
set("flexGrow", num(value));
|
|
135
154
|
break;
|
|
@@ -701,7 +720,7 @@ function translate(v, ctx) {
|
|
|
701
720
|
if (textual && (!blank2 || /bp-p--empty/.test(cls))) {
|
|
702
721
|
const kind = heading ? { type: "Heading", level: Number(heading[1]), content } : { type: "Text", content };
|
|
703
722
|
const node = { kind, style, children: [] };
|
|
704
|
-
if (v.tag === "a" && typeof v.props.href === "string")
|
|
723
|
+
if (v.tag === "a" && typeof v.props.href === "string") kind.href = v.props.href;
|
|
705
724
|
result = leaf(node);
|
|
706
725
|
} else {
|
|
707
726
|
const inner = childNodes(v, ctx);
|
|
@@ -902,6 +921,146 @@ var FormeMeasurer = class {
|
|
|
902
921
|
}
|
|
903
922
|
};
|
|
904
923
|
|
|
924
|
+
// src/fonts.ts
|
|
925
|
+
var localReader = null;
|
|
926
|
+
function setFontFileReader(reader) {
|
|
927
|
+
localReader = reader;
|
|
928
|
+
}
|
|
929
|
+
var MAX_FONT_BYTES = 32 * 1024 * 1024;
|
|
930
|
+
var FETCH_TIMEOUT_MS = 15e3;
|
|
931
|
+
var MAX_CACHED = 64;
|
|
932
|
+
var cache = /* @__PURE__ */ new Map();
|
|
933
|
+
async function resolveFonts(input) {
|
|
934
|
+
const fonts = [];
|
|
935
|
+
const warnings = [];
|
|
936
|
+
const seen = /* @__PURE__ */ new Set();
|
|
937
|
+
const add = (font) => {
|
|
938
|
+
const weight = font.weight ?? 400;
|
|
939
|
+
const style = font.style ?? "normal";
|
|
940
|
+
const key = `${font.family.trim().toLowerCase()}|${weight}|${style}`;
|
|
941
|
+
if (seen.has(key)) return;
|
|
942
|
+
seen.add(key);
|
|
943
|
+
fonts.push({ family: font.family, src: font.src, weight, style });
|
|
944
|
+
};
|
|
945
|
+
for (const font of input.fonts ?? []) add(font);
|
|
946
|
+
const faces = await Promise.all((input.theme?.fonts ?? []).map((face) => themeFace(face, input.sources ?? {})));
|
|
947
|
+
for (const face of faces) {
|
|
948
|
+
warnings.push(...face.warnings);
|
|
949
|
+
if (face.font) add(face.font);
|
|
950
|
+
}
|
|
951
|
+
return { fonts, warnings };
|
|
952
|
+
}
|
|
953
|
+
async function themeFace(face, policy) {
|
|
954
|
+
const { weight, range } = weightOf(face.weight);
|
|
955
|
+
const style = face.style === "italic" ? "italic" : "normal";
|
|
956
|
+
const name = `"${face.family}" (${weight}${style === "italic" ? " italic" : ""})`;
|
|
957
|
+
const sources = (Array.isArray(face.src) ? face.src : [face.src]).filter((s) => typeof s === "string" && s.trim() !== "");
|
|
958
|
+
const reasons = [];
|
|
959
|
+
for (const src of sources) {
|
|
960
|
+
const loaded = await load(src.trim(), policy);
|
|
961
|
+
if ("reason" in loaded) {
|
|
962
|
+
reasons.push(loaded.reason);
|
|
963
|
+
continue;
|
|
964
|
+
}
|
|
965
|
+
const warnings = range ? [`The font "${face.family}" declares the weights ${String(face.weight)} from one file; the PDF engine is given it at ${weight} only. Declare a file per weight for the others to be embedded.`] : [];
|
|
966
|
+
return { font: { family: face.family, src: loaded.src, weight, style }, warnings };
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
warnings: [
|
|
970
|
+
`The font ${name} has no TrueType or OpenType source the PDF engine can read, so the PDF draws that text in a standard face and breaks its lines differently from the screen. Add a .ttf or .otf to its src${reasons.length ? ` (${reasons.join("; ")})` : ""}.`
|
|
971
|
+
]
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
function weightOf(value) {
|
|
975
|
+
if (typeof value === "number" && Number.isFinite(value)) return { weight: Math.round(value), range: false };
|
|
976
|
+
const text = String(value ?? "").trim().toLowerCase();
|
|
977
|
+
if (text === "bold") return { weight: 700, range: false };
|
|
978
|
+
const numbers = text.split(/\s+/).map(Number).filter((n) => Number.isFinite(n) && n > 0);
|
|
979
|
+
if (!numbers.length) return { weight: 400, range: false };
|
|
980
|
+
return { weight: Math.round(numbers[0]), range: numbers.length > 1 && numbers[1] !== numbers[0] };
|
|
981
|
+
}
|
|
982
|
+
async function load(src, policy) {
|
|
983
|
+
if (/^data:(font|application)\/(x-)?woff2?[;,]/i.test(src) || /\.woff2?([?#]|$)/i.test(src.startsWith("data:") ? "" : src)) {
|
|
984
|
+
return { reason: `${describe(src)} is WOFF, which only a browser reads` };
|
|
985
|
+
}
|
|
986
|
+
if (src.startsWith("data:")) return fromDataUri(src);
|
|
987
|
+
const remote = /^https?:\/\//i.test(src);
|
|
988
|
+
if (remote) {
|
|
989
|
+
let host;
|
|
990
|
+
try {
|
|
991
|
+
host = new URL(src).hostname;
|
|
992
|
+
} catch {
|
|
993
|
+
return { reason: `${describe(src)} is not a valid address` };
|
|
994
|
+
}
|
|
995
|
+
const allowed = policy.allowedHosts;
|
|
996
|
+
if (allowed && !allowed.includes("*") && !allowed.includes(host)) return { reason: `${host} is not an allowed host` };
|
|
997
|
+
} else if (policy.local === false) {
|
|
998
|
+
return { reason: `${describe(src)} is neither a data: URI nor a web address, and files are not read here` };
|
|
999
|
+
} else if (!localReader) {
|
|
1000
|
+
return { src };
|
|
1001
|
+
}
|
|
1002
|
+
const key = src;
|
|
1003
|
+
const hit = cache.get(key);
|
|
1004
|
+
if (hit) return hit;
|
|
1005
|
+
const pending = (async () => {
|
|
1006
|
+
const bytes = remote ? await download(src, Boolean(policy.allowedHosts && !policy.allowedHosts.includes("*"))) : await localReader(src);
|
|
1007
|
+
if (bytes.byteLength > MAX_FONT_BYTES) return { reason: `${describe(src)} is larger than ${MAX_FONT_BYTES / 1024 / 1024} MB` };
|
|
1008
|
+
const problem = notEmbeddable(bytes, src);
|
|
1009
|
+
return problem ? { reason: problem } : { src: `data:font/ttf;base64,${toBase64(bytes)}` };
|
|
1010
|
+
})().catch((e) => {
|
|
1011
|
+
cache.delete(key);
|
|
1012
|
+
return { reason: `${describe(src)} could not be read (${e.message || String(e)})` };
|
|
1013
|
+
});
|
|
1014
|
+
cache.set(key, pending);
|
|
1015
|
+
while (cache.size > MAX_CACHED) cache.delete(cache.keys().next().value);
|
|
1016
|
+
return pending;
|
|
1017
|
+
}
|
|
1018
|
+
async function download(src, restricted) {
|
|
1019
|
+
const signal = typeof AbortSignal !== "undefined" && "timeout" in AbortSignal ? AbortSignal.timeout(FETCH_TIMEOUT_MS) : void 0;
|
|
1020
|
+
const response = await fetch(src, { redirect: restricted ? "error" : "follow", ...signal ? { signal } : {} });
|
|
1021
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
1022
|
+
const length2 = Number(response.headers.get("content-length"));
|
|
1023
|
+
if (length2 > MAX_FONT_BYTES) throw new Error(`larger than ${MAX_FONT_BYTES / 1024 / 1024} MB`);
|
|
1024
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
1025
|
+
}
|
|
1026
|
+
function fromDataUri(src) {
|
|
1027
|
+
const match = /^data:([^,]*),(.*)$/s.exec(src);
|
|
1028
|
+
if (!match) return { reason: "a data: URI with no data" };
|
|
1029
|
+
const base64 = /;base64$/i.test(match[1]);
|
|
1030
|
+
let head;
|
|
1031
|
+
try {
|
|
1032
|
+
head = base64 ? fromBase64(match[2].slice(0, 8)) : Uint8Array.from(decodeURIComponent(match[2].slice(0, 64)), (c) => c.charCodeAt(0) & 255);
|
|
1033
|
+
} catch {
|
|
1034
|
+
return { reason: "a data: URI that does not decode" };
|
|
1035
|
+
}
|
|
1036
|
+
const problem = notEmbeddable(head, "a data: URI");
|
|
1037
|
+
if (problem) return { reason: problem };
|
|
1038
|
+
if (base64) return { src };
|
|
1039
|
+
const bytes = Uint8Array.from(decodeURIComponent(match[2]), (c) => c.charCodeAt(0) & 255);
|
|
1040
|
+
return { src: `data:font/ttf;base64,${toBase64(bytes)}` };
|
|
1041
|
+
}
|
|
1042
|
+
function notEmbeddable(bytes, src) {
|
|
1043
|
+
if (bytes.length < 4) return `${describe(src)} is not a font file`;
|
|
1044
|
+
const tag = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
1045
|
+
if (bytes[0] === 0 && bytes[1] === 1 && bytes[2] === 0 && bytes[3] === 0 || tag === "OTTO" || tag === "true") return null;
|
|
1046
|
+
if (tag === "wOFF" || tag === "wOF2") return `${describe(src)} is WOFF, which only a browser reads`;
|
|
1047
|
+
if (tag === "ttcf") return `${describe(src)} is a font collection; give the single face instead`;
|
|
1048
|
+
return `${describe(src)} is not a TrueType or OpenType file`;
|
|
1049
|
+
}
|
|
1050
|
+
function describe(src) {
|
|
1051
|
+
return src.startsWith("data:") ? "a data: URI" : src.length > 80 ? `${src.slice(0, 77)}\u2026` : src;
|
|
1052
|
+
}
|
|
1053
|
+
function toBase64(bytes) {
|
|
1054
|
+
let binary = "";
|
|
1055
|
+
for (let i = 0; i < bytes.length; i += 32768) binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
1056
|
+
return btoa(binary);
|
|
1057
|
+
}
|
|
1058
|
+
function fromBase64(text) {
|
|
1059
|
+
const clean = text.replace(/[^A-Za-z0-9+/]/g, "");
|
|
1060
|
+
const binary = atob(clean.slice(0, clean.length - clean.length % 4));
|
|
1061
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
1062
|
+
}
|
|
1063
|
+
|
|
905
1064
|
// src/editor.ts
|
|
906
1065
|
function hash(s) {
|
|
907
1066
|
let h = 2166136261;
|
|
@@ -928,8 +1087,8 @@ var FormeEditorMeasurer = class {
|
|
|
928
1087
|
destroy() {
|
|
929
1088
|
this.cache.clear();
|
|
930
1089
|
}
|
|
931
|
-
key(section, width, mode) {
|
|
932
|
-
return hash(JSON.stringify(section)) + ":" + Math.round(width * 100) + ":" + mode;
|
|
1090
|
+
key(section, width, mode, faces) {
|
|
1091
|
+
return hash(JSON.stringify(section)) + ":" + Math.round(width * 100) + ":" + mode + ":" + faces;
|
|
933
1092
|
}
|
|
934
1093
|
async measure(sections, width) {
|
|
935
1094
|
const opts = this.opts;
|
|
@@ -937,8 +1096,9 @@ var FormeEditorMeasurer = class {
|
|
|
937
1096
|
const out = {};
|
|
938
1097
|
const pending = [];
|
|
939
1098
|
const keys = /* @__PURE__ */ new Map();
|
|
1099
|
+
const faces = facesKey(opts.theme.fonts);
|
|
940
1100
|
for (const section of sections) {
|
|
941
|
-
const k = this.key(section, width, opts.mode);
|
|
1101
|
+
const k = this.key(section, width, opts.mode, faces);
|
|
942
1102
|
const hit = this.cache.get(k);
|
|
943
1103
|
if (hit) out[section.key] = hit;
|
|
944
1104
|
else {
|
|
@@ -947,7 +1107,9 @@ var FormeEditorMeasurer = class {
|
|
|
947
1107
|
}
|
|
948
1108
|
}
|
|
949
1109
|
if (!pending.length) return out;
|
|
950
|
-
const
|
|
1110
|
+
const given = await this.config.fonts;
|
|
1111
|
+
const { fonts, warnings } = await resolveFonts({ fonts: given, theme: opts.theme });
|
|
1112
|
+
for (const w of warnings) this.warn(w);
|
|
951
1113
|
const measurer = new FormeMeasurer({
|
|
952
1114
|
registry: opts.registry,
|
|
953
1115
|
theme: opts.theme,
|
|
@@ -965,14 +1127,21 @@ var FormeEditorMeasurer = class {
|
|
|
965
1127
|
const k = keys.get(sectionKey);
|
|
966
1128
|
if (k) this.cache.set(k, geometry);
|
|
967
1129
|
}
|
|
968
|
-
for (const w of measurer.warnings)
|
|
969
|
-
if (this.seen.has(w)) continue;
|
|
970
|
-
this.seen.add(w);
|
|
971
|
-
this.config.onWarning?.(w);
|
|
972
|
-
}
|
|
1130
|
+
for (const w of measurer.warnings) this.warn(w);
|
|
973
1131
|
return out;
|
|
974
1132
|
}
|
|
1133
|
+
warn(message) {
|
|
1134
|
+
if (this.seen.has(message)) return;
|
|
1135
|
+
this.seen.add(message);
|
|
1136
|
+
this.config.onWarning?.(message);
|
|
1137
|
+
}
|
|
975
1138
|
};
|
|
1139
|
+
function facesKey(faces) {
|
|
1140
|
+
if (!faces?.length) return "";
|
|
1141
|
+
return hash(
|
|
1142
|
+
faces.map((f) => [f.family, f.weight, f.style, ...(Array.isArray(f.src) ? f.src : [f.src]).map((s) => `${s.length}:${s.slice(0, 64)}${s.slice(-64)}`)].join("|")).join(";")
|
|
1143
|
+
);
|
|
1144
|
+
}
|
|
976
1145
|
|
|
977
1146
|
// src/api.ts
|
|
978
1147
|
import {
|
|
@@ -997,8 +1166,11 @@ function creditNode(spec, width, ctx) {
|
|
|
997
1166
|
});
|
|
998
1167
|
}
|
|
999
1168
|
children.push({
|
|
1000
|
-
tag: "span",
|
|
1001
|
-
props: {
|
|
1169
|
+
tag: spec.href ? "a" : "span",
|
|
1170
|
+
props: {
|
|
1171
|
+
...spec.href ? { href: spec.href } : {},
|
|
1172
|
+
style: { "font-size": `${size}px`, color: spec.color, opacity: String(spec.opacity), "line-height": "1.2" }
|
|
1173
|
+
},
|
|
1002
1174
|
children: [spec.text]
|
|
1003
1175
|
});
|
|
1004
1176
|
const line = {
|
|
@@ -1313,7 +1485,7 @@ function emitPages(input) {
|
|
|
1313
1485
|
const width = page.contentWidth;
|
|
1314
1486
|
const bleed = page.margins.right;
|
|
1315
1487
|
const bodyDependsOnPage = isPageDependent(resolved.body);
|
|
1316
|
-
const
|
|
1488
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
1317
1489
|
const rendered = /* @__PURE__ */ new Map();
|
|
1318
1490
|
const treeOf = (section, opts) => {
|
|
1319
1491
|
if (bodyDependsOnPage) return renderNode2(section, opts, width);
|
|
@@ -1322,7 +1494,7 @@ function emitPages(input) {
|
|
|
1322
1494
|
};
|
|
1323
1495
|
const translateSection = (section, opts, from, to) => {
|
|
1324
1496
|
const cacheKey = `${section.key}|${from}|${to}`;
|
|
1325
|
-
if (!bodyDependsOnPage &&
|
|
1497
|
+
if (!bodyDependsOnPage && cache2.has(cacheKey)) return cache2.get(cacheKey);
|
|
1326
1498
|
const v = treeOf(section, opts);
|
|
1327
1499
|
if (!v) return null;
|
|
1328
1500
|
const geom = geometry[section.key];
|
|
@@ -1330,7 +1502,7 @@ function emitPages(input) {
|
|
|
1330
1502
|
const t = translate(cropped.node, ctx);
|
|
1331
1503
|
if (!t) return null;
|
|
1332
1504
|
const out = { node: t.node, offset: cropped.offset };
|
|
1333
|
-
if (!bodyDependsOnPage)
|
|
1505
|
+
if (!bodyDependsOnPage) cache2.set(cacheKey, out);
|
|
1334
1506
|
return out;
|
|
1335
1507
|
};
|
|
1336
1508
|
const headers = /* @__PURE__ */ new Map();
|
|
@@ -1487,11 +1659,12 @@ async function buildFormeDocument(opts) {
|
|
|
1487
1659
|
defaultPage: { size: "A4", margin: { top: 54, right: 54, bottom: 54, left: 54 }, wrap: true },
|
|
1488
1660
|
defaultStyle: mapStyle4({ fontSize: pxToPt(theme.typography.baseFontSize ?? 11), fontFamily: theme.typography.bodyFont.split(",")[0].trim().replace(/^['"]|['"]$/g, "") })
|
|
1489
1661
|
};
|
|
1490
|
-
|
|
1662
|
+
const fonts = await resolveFonts({ fonts: opts.fonts, theme, sources: opts.fontSources });
|
|
1663
|
+
if (fonts.fonts.length) doc.fonts = fontEntries(fonts.fonts);
|
|
1491
1664
|
if (opts.tagged) doc.tagged = true;
|
|
1492
1665
|
if (opts.pdfUa) doc.pdfUa = true;
|
|
1493
1666
|
if (opts.pdfA) doc.pdfa = opts.pdfA;
|
|
1494
|
-
const warnings = [...ctx.warnings, ...resolved.warnings.map((w) => w.message)];
|
|
1667
|
+
const warnings = [...ctx.warnings, ...resolved.warnings.map((w) => w.message), ...fonts.warnings];
|
|
1495
1668
|
return { doc, warnings, license };
|
|
1496
1669
|
}
|
|
1497
1670
|
var engineLoader = null;
|
|
@@ -1572,6 +1745,7 @@ async function layoutPaginated(opts) {
|
|
|
1572
1745
|
};
|
|
1573
1746
|
const ctx = { warnings: /* @__PURE__ */ new Set(), suppressPageBreaks: true };
|
|
1574
1747
|
const render = opts.renderer ?? defaultRenderer;
|
|
1748
|
+
const fonts = await resolveFonts({ fonts: opts.fonts, theme, sources: opts.fontSources });
|
|
1575
1749
|
const layoutSections = async (list) => {
|
|
1576
1750
|
if (!list.length) return {};
|
|
1577
1751
|
const measured = [];
|
|
@@ -1599,7 +1773,7 @@ async function layoutPaginated(opts) {
|
|
|
1599
1773
|
defaultPage: { size: "A4", margin: { top: 54, right: 54, bottom: 54, left: 54 }, wrap: true },
|
|
1600
1774
|
defaultStyle: baseStyle(theme)
|
|
1601
1775
|
};
|
|
1602
|
-
if (
|
|
1776
|
+
if (fonts.fonts.length) doc.fonts = fontEntries(fonts.fonts);
|
|
1603
1777
|
const result = await render(doc);
|
|
1604
1778
|
const pages = result.layout?.pages ?? [];
|
|
1605
1779
|
const scale2 = 1 / PX_TO_PT_LOCAL;
|
|
@@ -1663,7 +1837,7 @@ async function layoutPaginated(opts) {
|
|
|
1663
1837
|
defaultPage: { size: "A4", margin: { top: 54, right: 54, bottom: 54, left: 54 }, wrap: true },
|
|
1664
1838
|
defaultStyle: baseStyle(theme)
|
|
1665
1839
|
};
|
|
1666
|
-
if (
|
|
1840
|
+
if (fonts.fonts.length) doc.fonts = fontEntries(fonts.fonts);
|
|
1667
1841
|
if (opts.tagged) doc.tagged = true;
|
|
1668
1842
|
if (opts.pdfUa) doc.pdfUa = true;
|
|
1669
1843
|
if (opts.pdfA) doc.pdfa = opts.pdfA;
|
|
@@ -1673,7 +1847,7 @@ async function layoutPaginated(opts) {
|
|
|
1673
1847
|
pdf: result.pdf,
|
|
1674
1848
|
pages: layout?.pages.length ?? to - from,
|
|
1675
1849
|
layout,
|
|
1676
|
-
warnings: [...ctx.warnings, ...resolved.warnings.map((w) => w.message), ...paged.warnings.map((w) => w.message), ...result.warnings ?? []]
|
|
1850
|
+
warnings: [...ctx.warnings, ...resolved.warnings.map((w) => w.message), ...paged.warnings.map((w) => w.message), ...fonts.warnings, ...result.warnings ?? []]
|
|
1677
1851
|
};
|
|
1678
1852
|
}
|
|
1679
1853
|
};
|
|
@@ -1711,6 +1885,8 @@ export {
|
|
|
1711
1885
|
UNBOUNDED_PAGE_HEIGHT,
|
|
1712
1886
|
geometryFromLayout,
|
|
1713
1887
|
FormeMeasurer,
|
|
1888
|
+
setFontFileReader,
|
|
1889
|
+
resolveFonts,
|
|
1714
1890
|
FormeEditorMeasurer,
|
|
1715
1891
|
buildFormeDocument,
|
|
1716
1892
|
setEngineLoader,
|
|
@@ -1724,4 +1900,4 @@ export {
|
|
|
1724
1900
|
verifyLicense,
|
|
1725
1901
|
parseLicense
|
|
1726
1902
|
};
|
|
1727
|
-
//# sourceMappingURL=chunk-
|
|
1903
|
+
//# sourceMappingURL=chunk-FAKBQDQG.js.map
|