@worm-vue3-print/core 1.3.8 → 1.3.10
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/browser/index.cjs +281 -44
- package/dist/browser/index.d.cts +3 -3
- package/dist/browser/index.d.ts +3 -3
- package/dist/browser/index.js +33 -30
- package/dist/{chunk-ZKHVOCU5.js → chunk-4ZEP2HSH.js} +2 -2
- package/dist/{chunk-TQJGFV2V.js → chunk-7FXIWNYK.js} +367 -19
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/designer/index.cjs +719 -19
- package/dist/designer/index.d.cts +357 -9
- package/dist/designer/index.d.ts +357 -9
- package/dist/designer/index.js +458 -8
- package/dist/dom-executor.iife.global.js +7 -7
- package/dist/{driver-hJxBl2_n.d.cts → driver-DW3mxuRF.d.cts} +87 -5
- package/dist/{driver-hJxBl2_n.d.ts → driver-DW3mxuRF.d.ts} +87 -5
- package/dist/index.cjs +242 -8
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +15 -3
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +2 -2
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +1 -1
- package/dist/{ports-B-Jb2XwT.d.cts → ports-Brn5xcLD.d.ts} +2 -2
- package/dist/{ports-CJ0SUYFt.d.ts → ports-DJ7_blE7.d.cts} +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @worm-vue3-print/core v1.3.
|
|
2
|
+
* @worm-vue3-print/core v1.3.10
|
|
3
3
|
* Copyright (c) 2026 worm <liu_long_qqcom@qq.com>
|
|
4
4
|
* SPDX-FileCopyrightText: 2026 worm <liu_long_qqcom@qq.com>
|
|
5
5
|
* SPDX-License-Identifier: MIT
|
|
@@ -922,6 +922,130 @@ function evaluateTemplate(text, ctx) {
|
|
|
922
922
|
}
|
|
923
923
|
}
|
|
924
924
|
|
|
925
|
+
// src/render/flow-list.ts
|
|
926
|
+
var FLOW_MIN_COLUMNS = 1;
|
|
927
|
+
var FLOW_MAX_COLUMNS = 12;
|
|
928
|
+
var FLOW_MIN_ROW_HEIGHT_MM = 3;
|
|
929
|
+
var FLOW_MAX_ROW_HEIGHT_MM = 100;
|
|
930
|
+
var FLOW_MIN_GAP_X_MM = 0;
|
|
931
|
+
var FLOW_MAX_GAP_X_MM = 50;
|
|
932
|
+
var PT_TO_MM = 25.4 / 72;
|
|
933
|
+
function clampInt(value, min2, max2, fallback) {
|
|
934
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
935
|
+
return Math.min(max2, Math.max(min2, Math.round(value)));
|
|
936
|
+
}
|
|
937
|
+
function resolveFlowColumns(value) {
|
|
938
|
+
return clampInt(value, FLOW_MIN_COLUMNS, FLOW_MAX_COLUMNS, 4);
|
|
939
|
+
}
|
|
940
|
+
function resolveFlowGapX(value) {
|
|
941
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 4;
|
|
942
|
+
return Math.min(FLOW_MAX_GAP_X_MM, Math.max(FLOW_MIN_GAP_X_MM, value));
|
|
943
|
+
}
|
|
944
|
+
function resolveFlowRowHeight(value) {
|
|
945
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 8;
|
|
946
|
+
return Math.min(FLOW_MAX_ROW_HEIGHT_MM, Math.max(FLOW_MIN_ROW_HEIGHT_MM, value));
|
|
947
|
+
}
|
|
948
|
+
function resolveFlowMaxSpan(value, columns) {
|
|
949
|
+
const cols = resolveFlowColumns(columns);
|
|
950
|
+
const fallback = Math.min(2, cols);
|
|
951
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
952
|
+
return Math.min(cols, Math.max(1, Math.round(value)));
|
|
953
|
+
}
|
|
954
|
+
function flowColumnWidthMm(width, columns, gapX) {
|
|
955
|
+
const cols = resolveFlowColumns(columns);
|
|
956
|
+
const gap = resolveFlowGapX(gapX);
|
|
957
|
+
const avail = width - gap * (cols - 1);
|
|
958
|
+
if (avail <= 0) return 0;
|
|
959
|
+
return avail / cols;
|
|
960
|
+
}
|
|
961
|
+
function flowSpanWidthMm(colUnitMm, gapX, span) {
|
|
962
|
+
const k = Math.max(1, Math.floor(span));
|
|
963
|
+
return colUnitMm * k + gapX * (k - 1);
|
|
964
|
+
}
|
|
965
|
+
function estimateTextWidthMm(text, fontSizePt) {
|
|
966
|
+
if (!text) return 0;
|
|
967
|
+
const em = typeof fontSizePt === "number" && Number.isFinite(fontSizePt) && fontSizePt > 0 ? fontSizePt * PT_TO_MM : 12 * PT_TO_MM;
|
|
968
|
+
let units = 0;
|
|
969
|
+
for (const ch of text) {
|
|
970
|
+
if (ch === " ") {
|
|
971
|
+
units += 0.28;
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const c = ch.codePointAt(0) ?? 0;
|
|
975
|
+
if (c >= 12288 && c <= 12351 || c >= 13312 && c <= 19903 || c >= 19968 && c <= 40959 || c >= 63744 && c <= 64255 || c >= 65280 && c <= 65376 || c >= 65504 && c <= 65510 || c >= 131072) units += 1;
|
|
976
|
+
else if (/^[0-9A-Z]$/.test(ch)) units += 0.6;
|
|
977
|
+
else if (/^[a-z]$/.test(ch)) units += 0.5;
|
|
978
|
+
else if (/^[\u0020-\u007f]$/.test(ch)) units += 0.4;
|
|
979
|
+
else units += 0.75;
|
|
980
|
+
}
|
|
981
|
+
return units * em;
|
|
982
|
+
}
|
|
983
|
+
function spanForText(text, cfg) {
|
|
984
|
+
if (!cfg.autoSpan) return 1;
|
|
985
|
+
const ceiling = resolveFlowMaxSpan(cfg.maxSpan, cfg.columns);
|
|
986
|
+
if (ceiling <= 1 || cfg.colUnitMm <= 0) return 1;
|
|
987
|
+
const need = estimateTextWidthMm(text, cfg.fontSizePt);
|
|
988
|
+
for (let k = 1; k <= ceiling; k++) {
|
|
989
|
+
if (need <= flowSpanWidthMm(cfg.colUnitMm, cfg.gapX, k)) return k;
|
|
990
|
+
}
|
|
991
|
+
return ceiling;
|
|
992
|
+
}
|
|
993
|
+
function layoutFlowList(items, cfg) {
|
|
994
|
+
const columns = resolveFlowColumns(cfg.columns);
|
|
995
|
+
const gapX = resolveFlowGapX(cfg.gapX);
|
|
996
|
+
const colUnitMm = flowColumnWidthMm(cfg.width, columns, gapX);
|
|
997
|
+
const maxSpan = resolveFlowMaxSpan(cfg.maxSpan, columns);
|
|
998
|
+
const rows = [];
|
|
999
|
+
let current = [];
|
|
1000
|
+
let used = 0;
|
|
1001
|
+
for (const raw of items) {
|
|
1002
|
+
const text = String(raw ?? "");
|
|
1003
|
+
const span = spanForText(text, { ...cfg, columns, gapX, maxSpan, colUnitMm });
|
|
1004
|
+
if (current.length > 0 && used + span > columns) {
|
|
1005
|
+
rows.push({ cells: current });
|
|
1006
|
+
current = [];
|
|
1007
|
+
used = 0;
|
|
1008
|
+
}
|
|
1009
|
+
current.push({ text, span });
|
|
1010
|
+
used += span;
|
|
1011
|
+
}
|
|
1012
|
+
if (current.length > 0) rows.push({ cells: current });
|
|
1013
|
+
return rows;
|
|
1014
|
+
}
|
|
1015
|
+
function detectFlowListKey(expr, data) {
|
|
1016
|
+
if (typeof expr !== "string" || !expr.includes("{") || !data) return void 0;
|
|
1017
|
+
const roots = /* @__PURE__ */ new Set();
|
|
1018
|
+
for (const token of expr.matchAll(/\{([^{}]*)\}/g)) {
|
|
1019
|
+
for (const piece of (token[1] ?? "").split(/[^A-Za-z0-9_\u4e00-\u9fa5.]/)) {
|
|
1020
|
+
const root = piece.split(".")[0];
|
|
1021
|
+
if (root && !/^\d/.test(root)) roots.add(root);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
for (const root of roots) {
|
|
1025
|
+
if (Array.isArray(data[root])) return root;
|
|
1026
|
+
}
|
|
1027
|
+
return void 0;
|
|
1028
|
+
}
|
|
1029
|
+
function suggestFlowColumns(width, gapX, fontSizePt) {
|
|
1030
|
+
const gap = resolveFlowGapX(gapX);
|
|
1031
|
+
const minCol = estimateTextWidthMm("\u4E00", fontSizePt);
|
|
1032
|
+
if (minCol <= 0 || width <= 0) return FLOW_MIN_COLUMNS;
|
|
1033
|
+
const fit = Math.floor((width + gap) / (minCol + gap));
|
|
1034
|
+
return Math.min(FLOW_MAX_COLUMNS, Math.max(FLOW_MIN_COLUMNS, fit));
|
|
1035
|
+
}
|
|
1036
|
+
var mmNum = (v) => `${Math.round(v * 1e3) / 1e3}mm`;
|
|
1037
|
+
function flowGridStyle(cfg) {
|
|
1038
|
+
const columns = resolveFlowColumns(cfg.columns);
|
|
1039
|
+
const gapX = resolveFlowGapX(cfg.gapX);
|
|
1040
|
+
const rowHeight = resolveFlowRowHeight(cfg.rowHeight);
|
|
1041
|
+
return [
|
|
1042
|
+
`display:grid`,
|
|
1043
|
+
`grid-template-columns:repeat(${columns},minmax(0,1fr))`,
|
|
1044
|
+
`column-gap:${mmNum(gapX)}`,
|
|
1045
|
+
`grid-auto-rows:minmax(${mmNum(rowHeight)},auto)`
|
|
1046
|
+
].join(";");
|
|
1047
|
+
}
|
|
1048
|
+
|
|
925
1049
|
// src/render/data-binder.ts
|
|
926
1050
|
function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
927
1051
|
const data = { ...resolveSystemVariables(), ...printData ?? {} };
|
|
@@ -949,7 +1073,8 @@ function bindData(template, printData, baseUrl, fontBaseUrl) {
|
|
|
949
1073
|
}
|
|
950
1074
|
function bindElement(el, data, baseUrl) {
|
|
951
1075
|
const cloned = { ...el, options: { ...el.options } };
|
|
952
|
-
|
|
1076
|
+
const isFlowList = cloned.type === "flowList" || cloned.printElementType?.type === "flowList";
|
|
1077
|
+
if (!isFlowList && typeof cloned.options.formatter === "string") {
|
|
953
1078
|
const raw = cloned.options.formatter;
|
|
954
1079
|
if (referencesPageNumbers(raw)) {
|
|
955
1080
|
cloned.options.rawFormatter = raw;
|
|
@@ -971,8 +1096,23 @@ function bindElement(el, data, baseUrl) {
|
|
|
971
1096
|
if (cloned.type === "table" || cloned.printElementType?.type === "table") {
|
|
972
1097
|
bindTableData(cloned, data);
|
|
973
1098
|
}
|
|
1099
|
+
if (cloned.type === "flowList" || cloned.printElementType?.type === "flowList") {
|
|
1100
|
+
bindFlowListData(cloned, data);
|
|
1101
|
+
}
|
|
974
1102
|
return cloned;
|
|
975
1103
|
}
|
|
1104
|
+
function bindFlowListData(el, data) {
|
|
1105
|
+
const template = typeof el.options.formatter === "string" ? el.options.formatter : "";
|
|
1106
|
+
const source = { ...el.options, dataSource: el.options.dataSource ?? detectFlowListKey(template, data) };
|
|
1107
|
+
const { list, key } = resolveListSource(source, data);
|
|
1108
|
+
const itemCtx = (item) => key ? { ...data, ...item, [key]: item } : { ...data, ...item };
|
|
1109
|
+
const items = list.map((item) => {
|
|
1110
|
+
if (!template) return String(item ?? "");
|
|
1111
|
+
return referencesPageNumbers(template) ? template : evaluateTemplate(template, itemCtx(item));
|
|
1112
|
+
});
|
|
1113
|
+
el.options._flowItems = items;
|
|
1114
|
+
el.options._flowRawFormatter = referencesPageNumbers(template) ? template : void 0;
|
|
1115
|
+
}
|
|
976
1116
|
function resolveListSource(opts, data) {
|
|
977
1117
|
const explicitKey = opts.dataSource ?? opts.fields?.[0]?.dataSource ?? opts.fields?.[0]?.field;
|
|
978
1118
|
if (explicitKey && Array.isArray(data[explicitKey])) {
|
|
@@ -1048,6 +1188,12 @@ function makeRenderRow(row, resolve, keepRaw = false) {
|
|
|
1048
1188
|
barcodeType: cell.barcodeType,
|
|
1049
1189
|
qrCodeLevel: cell.qrCodeLevel,
|
|
1050
1190
|
qrQuietZone: cell.qrQuietZone,
|
|
1191
|
+
barQuietZone: cell.barQuietZone,
|
|
1192
|
+
// 条高同样必须进白名单:漏一个,属性台填的 mm 就只在设计器生效、出纸静默按缺省 30 模块
|
|
1193
|
+
barHeight: cell.barHeight,
|
|
1194
|
+
// 条宽与条码文本字号也必须在白名单里:漏一个,属性台填的倍率就只在设计器生效、出纸静默按缺省
|
|
1195
|
+
barWidth: cell.barWidth,
|
|
1196
|
+
barFontSize: cell.barFontSize,
|
|
1051
1197
|
showBarcodeText: cell.showBarcodeText,
|
|
1052
1198
|
printerDpi: cell.printerDpi,
|
|
1053
1199
|
fit: cell.fit,
|
|
@@ -1164,6 +1310,57 @@ function toFontFamilyStack(family) {
|
|
|
1164
1310
|
const head = name.includes(",") ? name : `"${name.replace(/"/g, "")}"`;
|
|
1165
1311
|
return [head, ...FALLBACK_FONT_STACK].join(", ");
|
|
1166
1312
|
}
|
|
1313
|
+
function resolveCanvasFontFamily(family) {
|
|
1314
|
+
return family ? toFontFamilyStack(family) : "inherit";
|
|
1315
|
+
}
|
|
1316
|
+
function normalizeFontCatalog(host) {
|
|
1317
|
+
const out = [];
|
|
1318
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1319
|
+
for (const font of host ?? []) {
|
|
1320
|
+
const family = font?.family?.trim();
|
|
1321
|
+
if (!family) continue;
|
|
1322
|
+
const key = family.toLowerCase();
|
|
1323
|
+
if (seen.has(key)) continue;
|
|
1324
|
+
seen.add(key);
|
|
1325
|
+
const label = font?.label?.trim();
|
|
1326
|
+
out.push(label ? { family, label } : { family });
|
|
1327
|
+
}
|
|
1328
|
+
return out;
|
|
1329
|
+
}
|
|
1330
|
+
function findFontOption(fonts, family) {
|
|
1331
|
+
const key = family?.trim().toLowerCase();
|
|
1332
|
+
if (!key) return void 0;
|
|
1333
|
+
return fonts.find((f) => f.family.trim().toLowerCase() === key);
|
|
1334
|
+
}
|
|
1335
|
+
function fontOptionLabel(option) {
|
|
1336
|
+
return option.label ? `${option.label}\uFF08${option.family}\uFF09` : option.family;
|
|
1337
|
+
}
|
|
1338
|
+
function normalizeFontQuery(value) {
|
|
1339
|
+
return value.toLowerCase().replace(/\s+/g, "");
|
|
1340
|
+
}
|
|
1341
|
+
function matchRank(nameKey, queryKey) {
|
|
1342
|
+
if (nameKey === queryKey) return 0;
|
|
1343
|
+
if (nameKey.startsWith(queryKey)) return 1;
|
|
1344
|
+
if (nameKey.includes(queryKey)) return 2;
|
|
1345
|
+
let cursor = 0;
|
|
1346
|
+
for (const char of nameKey) {
|
|
1347
|
+
if (char === queryKey[cursor]) cursor++;
|
|
1348
|
+
if (cursor === queryKey.length) return 3;
|
|
1349
|
+
}
|
|
1350
|
+
return -1;
|
|
1351
|
+
}
|
|
1352
|
+
function fontMatchRank(font, queryKey) {
|
|
1353
|
+
const byFamily = matchRank(normalizeFontQuery(font.family), queryKey);
|
|
1354
|
+
if (!font.label) return byFamily;
|
|
1355
|
+
const byLabel = matchRank(normalizeFontQuery(font.label), queryKey);
|
|
1356
|
+
if (byFamily < 0) return byLabel;
|
|
1357
|
+
return byLabel < 0 ? byFamily : Math.min(byFamily, byLabel);
|
|
1358
|
+
}
|
|
1359
|
+
function filterFontOptions(fonts, query) {
|
|
1360
|
+
const queryKey = normalizeFontQuery(query.trim());
|
|
1361
|
+
if (!queryKey) return [...fonts];
|
|
1362
|
+
return fonts.map((font, index) => ({ font, index, rank: fontMatchRank(font, queryKey) })).filter((item) => item.rank >= 0).sort((a, b) => a.rank - b.rank || a.index - b.index).map((item) => item.font);
|
|
1363
|
+
}
|
|
1167
1364
|
|
|
1168
1365
|
// src/render/types.ts
|
|
1169
1366
|
var PAPER_DIMENSIONS = {
|
|
@@ -1298,7 +1495,8 @@ function elementBlock() {
|
|
|
1298
1495
|
.print-table td {
|
|
1299
1496
|
border: 1px solid #ccc;
|
|
1300
1497
|
padding: 2mm 3mm;
|
|
1301
|
-
word-break:
|
|
1498
|
+
word-break: normal;
|
|
1499
|
+
overflow-wrap: break-word;
|
|
1302
1500
|
overflow: hidden;
|
|
1303
1501
|
}
|
|
1304
1502
|
.print-table thead th {
|
|
@@ -1536,7 +1734,9 @@ function normalizeFit(value) {
|
|
|
1536
1734
|
}
|
|
1537
1735
|
var ELEMENT_DEFAULT_FIT = {
|
|
1538
1736
|
text: "clip",
|
|
1539
|
-
longText: "autoHeight"
|
|
1737
|
+
longText: "autoHeight",
|
|
1738
|
+
// 流式列表一框一页:超出元素框高的单元按截断处理,不自动撑破纸面(specs 第八节第 8 项)
|
|
1739
|
+
flowList: "clip"
|
|
1540
1740
|
};
|
|
1541
1741
|
function resolveElementTextFit(type, opts) {
|
|
1542
1742
|
return normalizeFit(opts?.textFit) ?? ELEMENT_DEFAULT_FIT[type] ?? "clip";
|
|
@@ -1601,6 +1801,7 @@ function acceptsElementBorder(type) {
|
|
|
1601
1801
|
var VALID_STYLES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double"]);
|
|
1602
1802
|
function parseBorder(width, style, color) {
|
|
1603
1803
|
if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) return null;
|
|
1804
|
+
if (style === "none") return null;
|
|
1604
1805
|
return {
|
|
1605
1806
|
borderWidth: `${width}pt`,
|
|
1606
1807
|
borderStyle: typeof style === "string" && VALID_STYLES.has(style) ? style : "solid",
|
|
@@ -2290,10 +2491,38 @@ function specialRowHeight(renderRows, rowHeights, type) {
|
|
|
2290
2491
|
// src/render/barcode-dot.ts
|
|
2291
2492
|
var MM_PER_INCH = 25.4;
|
|
2292
2493
|
var BARCODE_QUIET_ZONE_MODULES = 10;
|
|
2494
|
+
function barcodeQuietZoneModules(value) {
|
|
2495
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : BARCODE_QUIET_ZONE_MODULES;
|
|
2496
|
+
}
|
|
2293
2497
|
var BARCODE_BAR_HEIGHT_MODULES = 30;
|
|
2294
2498
|
var BARCODE_TEXT_FONT_SIZE_MODULES = 10;
|
|
2295
2499
|
var BARCODE_MARGIN_BOTTOM_MODULES = 2;
|
|
2500
|
+
var QR_DEFAULT_QUIET_MODULES = 0;
|
|
2296
2501
|
var BARCODE_MODULE_WIDTH_MM = 0.25;
|
|
2502
|
+
var BARCODE_MIN_MODULE_WIDTH_MM = 0.254;
|
|
2503
|
+
function recommendBarcodeBarWidth(dpi) {
|
|
2504
|
+
if (typeof dpi !== "number" || !Number.isFinite(dpi) || dpi <= 0) return null;
|
|
2505
|
+
const dotsPerMm = dpi / MM_PER_INCH;
|
|
2506
|
+
for (let bw = 2; bw <= 8; bw += 0.5) {
|
|
2507
|
+
const dotsPerModule = Math.max(1, Math.round(barcodePreferredModuleWidthMm(bw) * dotsPerMm));
|
|
2508
|
+
const moduleWidthMm = dotsPerModule / dotsPerMm;
|
|
2509
|
+
if (moduleWidthMm >= BARCODE_MIN_MODULE_WIDTH_MM - 1e-9) {
|
|
2510
|
+
return { barWidth: bw, dotsPerModule, moduleWidthMm };
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
return null;
|
|
2514
|
+
}
|
|
2515
|
+
function barcodeBarWidthRecommendText(dpi, currentBarWidth) {
|
|
2516
|
+
const rec = recommendBarcodeBarWidth(dpi);
|
|
2517
|
+
if (!rec) return "";
|
|
2518
|
+
const mm2 = (v) => String(Number(v.toFixed(3)));
|
|
2519
|
+
const head = `\u6309 ${dpi}dpi \u63A8\u8350\u6761\u5BBD\u500D\u7387 ${rec.barWidth}\uFF08\u6BCF\u6A21\u5757 ${rec.dotsPerModule} \u4E2A\u6253\u5370\u70B9 = ${mm2(rec.moduleWidthMm)}mm\uFF0C\u53D6\u8FBE\u5230 ${mm2(BARCODE_MIN_MODULE_WIDTH_MM)}mm \u4E0B\u9650\u7684\u6700\u5C0F\u6863\uFF09`;
|
|
2520
|
+
const cur = barcodePreferredModuleWidthMm(currentBarWidth ?? 2);
|
|
2521
|
+
const curDots = Math.max(1, Math.round(cur * dpi / MM_PER_INCH));
|
|
2522
|
+
const curMm = curDots / (dpi / MM_PER_INCH);
|
|
2523
|
+
const tail = curMm >= BARCODE_MIN_MODULE_WIDTH_MM - 1e-9 ? `\u5F53\u524D\u500D\u7387 ${currentBarWidth ?? 2} \u6298\u7B97\u4E3A ${curDots} \u70B9 / ${mm2(curMm)}mm\uFF0C\u5DF2\u8FBE\u6807` : `\u5F53\u524D\u500D\u7387 ${currentBarWidth ?? 2} \u53EA\u6709 ${curDots} \u70B9 / ${mm2(curMm)}mm\uFF0C\u4F4E\u4E8E\u4E0B\u9650`;
|
|
2524
|
+
return `${head}\uFF1B${tail}\u3002\u8FD9\u91CC\u53EA\u63D0\u793A\uFF0C\u4E0D\u4F1A\u66FF\u4F60\u6539\u503C`;
|
|
2525
|
+
}
|
|
2297
2526
|
function barcodeUnitsPerModule(barWidth) {
|
|
2298
2527
|
const raw = typeof barWidth === "number" && Number.isFinite(barWidth) ? barWidth : 2;
|
|
2299
2528
|
return Math.max(1, raw / 2);
|
|
@@ -2301,6 +2530,36 @@ function barcodeUnitsPerModule(barWidth) {
|
|
|
2301
2530
|
function barcodePreferredModuleWidthMm(barWidth) {
|
|
2302
2531
|
return barcodeUnitsPerModule(barWidth) * BARCODE_MODULE_WIDTH_MM;
|
|
2303
2532
|
}
|
|
2533
|
+
function barcodeBarHeightModules(input) {
|
|
2534
|
+
const { barHeightMm, moduleWidthMm, boxHeightMm, textModules } = input;
|
|
2535
|
+
const hasHeight = typeof barHeightMm === "number" && Number.isFinite(barHeightMm) && barHeightMm > 0;
|
|
2536
|
+
const hasGranularity = typeof moduleWidthMm === "number" && Number.isFinite(moduleWidthMm) && moduleWidthMm > 0;
|
|
2537
|
+
if (!hasHeight || !hasGranularity) return BARCODE_BAR_HEIGHT_MODULES;
|
|
2538
|
+
const wanted = Math.max(1, Math.round(barHeightMm / moduleWidthMm));
|
|
2539
|
+
const hasBox = typeof boxHeightMm === "number" && Number.isFinite(boxHeightMm) && boxHeightMm > 0;
|
|
2540
|
+
if (!hasBox) return wanted;
|
|
2541
|
+
const text = typeof textModules === "number" && Number.isFinite(textModules) && textModules > 0 ? textModules : 0;
|
|
2542
|
+
const cap = Math.floor((boxHeightMm - text * moduleWidthMm) / moduleWidthMm);
|
|
2543
|
+
return Math.max(1, Math.min(wanted, cap));
|
|
2544
|
+
}
|
|
2545
|
+
function dotAlignedModuleWidth(preferredMm, maxModuleMm, dotsPerMm) {
|
|
2546
|
+
const preferredDots = Math.max(1, Math.round(preferredMm * dotsPerMm));
|
|
2547
|
+
const maxDots = Math.floor(maxModuleMm * dotsPerMm);
|
|
2548
|
+
if (maxDots < 1) return null;
|
|
2549
|
+
const dotsPerModule = Math.min(preferredDots, maxDots);
|
|
2550
|
+
return { dotsPerModule, preferredDots, moduleWidthMm: dotsPerModule / dotsPerMm };
|
|
2551
|
+
}
|
|
2552
|
+
function barcodeWidthBoundModuleWidthMm(input) {
|
|
2553
|
+
const preferredMm = barcodePreferredModuleWidthMm(input.barWidth);
|
|
2554
|
+
const unitWidth = Math.max(1, Math.ceil(input.unitWidth));
|
|
2555
|
+
const maxModuleMm = input.boxWidthMm > 0 ? input.boxWidthMm / unitWidth : Number.POSITIVE_INFINITY;
|
|
2556
|
+
const dpi = input.dpi;
|
|
2557
|
+
if (typeof dpi === "number" && Number.isFinite(dpi) && dpi > 0) {
|
|
2558
|
+
const aligned = dotAlignedModuleWidth(preferredMm, maxModuleMm, dpi / MM_PER_INCH);
|
|
2559
|
+
if (aligned) return aligned.moduleWidthMm;
|
|
2560
|
+
}
|
|
2561
|
+
return Math.min(preferredMm, maxModuleMm);
|
|
2562
|
+
}
|
|
2304
2563
|
function barcodeAvailableBoxMm(boxMm, maxMm) {
|
|
2305
2564
|
const box = typeof boxMm === "number" && boxMm > 0 ? boxMm : Number.POSITIVE_INFINITY;
|
|
2306
2565
|
const limit = typeof maxMm === "number" && maxMm > 0 ? Math.min(box, maxMm) : box;
|
|
@@ -2316,18 +2575,14 @@ function resolveBarcodeSize(input) {
|
|
|
2316
2575
|
);
|
|
2317
2576
|
const dpi = input.dpi;
|
|
2318
2577
|
if (typeof dpi === "number" && Number.isFinite(dpi) && dpi > 0) {
|
|
2319
|
-
const
|
|
2320
|
-
|
|
2321
|
-
const maxDots = Math.floor(maxModuleMm * dotsPerMm);
|
|
2322
|
-
if (maxDots >= 1) {
|
|
2323
|
-
const dotsPerModule = Math.min(preferredDots, maxDots);
|
|
2324
|
-
const moduleWidthMm2 = dotsPerModule / dotsPerMm;
|
|
2578
|
+
const aligned = dotAlignedModuleWidth(preferredModuleMm, maxModuleMm, dpi / MM_PER_INCH);
|
|
2579
|
+
if (aligned) {
|
|
2325
2580
|
return {
|
|
2326
|
-
moduleWidthMm:
|
|
2327
|
-
widthMm: unitWidth *
|
|
2328
|
-
heightMm: unitHeight *
|
|
2329
|
-
dotsPerModule,
|
|
2330
|
-
scaledDown: dotsPerModule < preferredDots
|
|
2581
|
+
moduleWidthMm: aligned.moduleWidthMm,
|
|
2582
|
+
widthMm: unitWidth * aligned.moduleWidthMm,
|
|
2583
|
+
heightMm: unitHeight * aligned.moduleWidthMm,
|
|
2584
|
+
dotsPerModule: aligned.dotsPerModule,
|
|
2585
|
+
scaledDown: aligned.dotsPerModule < aligned.preferredDots
|
|
2331
2586
|
};
|
|
2332
2587
|
}
|
|
2333
2588
|
}
|
|
@@ -2340,6 +2595,39 @@ function resolveBarcodeSize(input) {
|
|
|
2340
2595
|
scaledDown: moduleWidthMm < preferredModuleMm
|
|
2341
2596
|
};
|
|
2342
2597
|
}
|
|
2598
|
+
function layoutBarcodeSize(input) {
|
|
2599
|
+
const upm = barcodeUnitsPerModule(input.barWidth);
|
|
2600
|
+
const settle = (units) => resolveBarcodeSize({
|
|
2601
|
+
unitWidth: units.widthUnits / upm,
|
|
2602
|
+
unitHeight: units.heightUnits / upm,
|
|
2603
|
+
boxWidthMm: input.boxWidthMm,
|
|
2604
|
+
boxHeightMm: input.boxHeightMm,
|
|
2605
|
+
dpi: input.dpi,
|
|
2606
|
+
barWidth: input.barWidth
|
|
2607
|
+
});
|
|
2608
|
+
const first = input.measure(BARCODE_BAR_HEIGHT_MODULES);
|
|
2609
|
+
if (!first) return { barHeightModules: BARCODE_BAR_HEIGHT_MODULES, size: null };
|
|
2610
|
+
const hasHeight = typeof input.barHeightMm === "number" && Number.isFinite(input.barHeightMm) && input.barHeightMm > 0;
|
|
2611
|
+
if (!hasHeight) return { barHeightModules: BARCODE_BAR_HEIGHT_MODULES, size: settle(first) };
|
|
2612
|
+
const textModules = Math.max(0, first.heightUnits / upm - BARCODE_BAR_HEIGHT_MODULES);
|
|
2613
|
+
const barHeightModules = barcodeBarHeightModules({
|
|
2614
|
+
barHeightMm: input.barHeightMm,
|
|
2615
|
+
moduleWidthMm: barcodeWidthBoundModuleWidthMm({
|
|
2616
|
+
unitWidth: first.widthUnits / upm,
|
|
2617
|
+
boxWidthMm: input.boxWidthMm,
|
|
2618
|
+
dpi: input.dpi,
|
|
2619
|
+
barWidth: input.barWidth
|
|
2620
|
+
}),
|
|
2621
|
+
boxHeightMm: input.boxHeightMm,
|
|
2622
|
+
textModules
|
|
2623
|
+
});
|
|
2624
|
+
if (barHeightModules === BARCODE_BAR_HEIGHT_MODULES) {
|
|
2625
|
+
return { barHeightModules, size: settle(first) };
|
|
2626
|
+
}
|
|
2627
|
+
const second = input.measure(barHeightModules);
|
|
2628
|
+
if (!second) return { barHeightModules: BARCODE_BAR_HEIGHT_MODULES, size: null };
|
|
2629
|
+
return { barHeightModules, size: settle(second) };
|
|
2630
|
+
}
|
|
2343
2631
|
|
|
2344
2632
|
// src/render/html-generator.ts
|
|
2345
2633
|
function pageVarsContext(vars) {
|
|
@@ -2604,6 +2892,27 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
|
|
|
2604
2892
|
return `<div class="print-element" style="${style};border:${opts.borderWidth || 1}pt ${opts.borderStyle || "solid"} ${opts.borderColor || "#333"};border-radius:50%;"${measureAttr}></div>`;
|
|
2605
2893
|
case "longText":
|
|
2606
2894
|
return `<div class="print-element" style="${style}${textStyle(opts)}${indentStyle(opts)}${elementFitStyle(fit, opts)}"${measureAttr}${fitAttr}>${esc(opts.formatter ?? opts.testData ?? "")}</div>`;
|
|
2895
|
+
case "flowList": {
|
|
2896
|
+
const columns = resolveFlowColumns(opts.flowColumns);
|
|
2897
|
+
const gapX = resolveFlowGapX(opts.flowGapX);
|
|
2898
|
+
const rowHeight = resolveFlowRowHeight(opts.flowRowHeight);
|
|
2899
|
+
const maxSpan = resolveFlowMaxSpan(opts.flowMaxSpan, columns);
|
|
2900
|
+
const boundItems = Array.isArray(opts._flowItems) ? opts._flowItems : void 0;
|
|
2901
|
+
const items = boundItems && boundItems.length > 0 ? boundItems : String(opts.testData ?? "").split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
|
|
2902
|
+
const cfg = {
|
|
2903
|
+
width,
|
|
2904
|
+
columns,
|
|
2905
|
+
gapX,
|
|
2906
|
+
rowHeight,
|
|
2907
|
+
maxSpan,
|
|
2908
|
+
fontSizePt: opts.fontSize ?? 12,
|
|
2909
|
+
autoSpan: opts.flowAutoSpan === true
|
|
2910
|
+
};
|
|
2911
|
+
const cells = layoutFlowList(items, cfg).flatMap((row) => row.cells).map((c) => `<div class="print-flow-cell"${c.span > 1 ? ` style="grid-column:span ${c.span};"` : ""}>${esc(c.text)}</div>`).join("\n ");
|
|
2912
|
+
return `<div class="print-element" style="${style}${textStyle(opts)}overflow:hidden;${flowGridStyle(cfg)};"${measureAttr}${fitAttr}>
|
|
2913
|
+
${cells}
|
|
2914
|
+
</div>`;
|
|
2915
|
+
}
|
|
2607
2916
|
case "html":
|
|
2608
2917
|
return `<div class="print-element" style="${style}"${measureAttr}>${opts.testData ?? opts.title ?? ""}</div>`;
|
|
2609
2918
|
default:
|
|
@@ -2620,9 +2929,13 @@ function codeImgHtml(value, cellType, opts, io) {
|
|
|
2620
2929
|
qrCodeLevel: opts.qrCodeLevel != null ? String(opts.qrCodeLevel) : void 0,
|
|
2621
2930
|
// 0 是合法档(无白边),必须用 typeof 判定而非 or/?? 之类假值判断
|
|
2622
2931
|
qrQuietZone: typeof opts.qrQuietZone === "number" ? opts.qrQuietZone : void 0,
|
|
2932
|
+
barQuietZone: typeof opts.barQuietZone === "number" ? opts.barQuietZone : void 0,
|
|
2933
|
+
// 条高(mm):元素台与单元格台都写 barHeight,非法/未填交由布局函数回退缺省档
|
|
2934
|
+
barHeightMm: typeof opts.barHeight === "number" ? opts.barHeight : void 0,
|
|
2623
2935
|
showText: opts.hideTitle !== void 0 ? !opts.hideTitle : opts.showBarcodeText,
|
|
2624
2936
|
barWidth: typeof opts.barWidth === "number" ? opts.barWidth : void 0,
|
|
2625
|
-
|
|
2937
|
+
// 元素台的条码文本字号是 fontSize;单元格台的文本字号是 barFontSize(单元格的 fontSize 是正文字号,不该拿来决定条码)
|
|
2938
|
+
fontSize: typeof (opts.barFontSize ?? opts.fontSize) === "number" ? opts.barFontSize ?? opts.fontSize : void 0,
|
|
2626
2939
|
printerDpi: isBarcode ? io.printerDpi : void 0,
|
|
2627
2940
|
targetWidthMm: isBarcode ? barcodeAvailableBoxMm(io.targetWidthMm, maxWidth) : void 0,
|
|
2628
2941
|
targetHeightMm: isBarcode ? barcodeAvailableBoxMm(io.targetHeightMm, maxHeight) : void 0
|
|
@@ -2653,8 +2966,9 @@ function matrixCellStyle(cell, opts) {
|
|
|
2653
2966
|
const fontSize = cell.fittedFontSize ?? cell.fontSize ?? opts.tableDefaultFontSize;
|
|
2654
2967
|
const color = cell.color ?? opts.tableDefaultColor;
|
|
2655
2968
|
const padding = cell.padding ?? opts.tableDefaultPadding ?? 1;
|
|
2969
|
+
const fontFamily = cell.fontFamily ?? opts.tableDefaultFontFamily;
|
|
2656
2970
|
if (fontSize) parts.push(`font-size:${fontSize}pt`);
|
|
2657
|
-
if (
|
|
2971
|
+
if (fontFamily) parts.push(`font-family:${escapeInlineStyleValue(toFontFamilyStack(fontFamily))}`);
|
|
2658
2972
|
if (cell.fontWeight) parts.push(`font-weight:${cell.fontWeight}`);
|
|
2659
2973
|
if (color) parts.push(`color:${color}`);
|
|
2660
2974
|
if (cell.backgroundColor) parts.push(`background-color:${cell.backgroundColor}`);
|
|
@@ -2662,7 +2976,7 @@ function matrixCellStyle(cell, opts) {
|
|
|
2662
2976
|
if (cell.align === "justify") parts.push("text-align-last:justify");
|
|
2663
2977
|
parts.push(`vertical-align:${cell.valign ?? "middle"}`);
|
|
2664
2978
|
parts.push(`padding:${padding}mm`);
|
|
2665
|
-
parts.push(cell.wordWrap === false ? "white-space:nowrap;overflow:hidden" : "word-break:break-
|
|
2979
|
+
parts.push(cell.wordWrap === false ? "white-space:nowrap;overflow:hidden" : "white-space:pre-wrap;word-break:normal;overflow-wrap:break-word");
|
|
2666
2980
|
const b = cell.borders ?? {};
|
|
2667
2981
|
for (const side of ["top", "right", "bottom", "left"]) {
|
|
2668
2982
|
const border = b[side];
|
|
@@ -3046,7 +3360,9 @@ function codeSpecKey(value, cellType, opts = {}) {
|
|
|
3046
3360
|
opts.showText ?? null,
|
|
3047
3361
|
opts.barWidth ?? null,
|
|
3048
3362
|
opts.fontSize ?? null,
|
|
3049
|
-
opts.qrQuietZone ?? null
|
|
3363
|
+
opts.qrQuietZone ?? null,
|
|
3364
|
+
opts.barQuietZone ?? null,
|
|
3365
|
+
opts.barHeightMm ?? null
|
|
3050
3366
|
]);
|
|
3051
3367
|
}
|
|
3052
3368
|
function createMapCodeRenderer(map) {
|
|
@@ -3786,6 +4102,24 @@ export {
|
|
|
3786
4102
|
roundHalfEven,
|
|
3787
4103
|
safeEval,
|
|
3788
4104
|
evaluateTemplate,
|
|
4105
|
+
FLOW_MIN_COLUMNS,
|
|
4106
|
+
FLOW_MAX_COLUMNS,
|
|
4107
|
+
FLOW_MIN_ROW_HEIGHT_MM,
|
|
4108
|
+
FLOW_MAX_ROW_HEIGHT_MM,
|
|
4109
|
+
FLOW_MIN_GAP_X_MM,
|
|
4110
|
+
FLOW_MAX_GAP_X_MM,
|
|
4111
|
+
resolveFlowColumns,
|
|
4112
|
+
resolveFlowGapX,
|
|
4113
|
+
resolveFlowRowHeight,
|
|
4114
|
+
resolveFlowMaxSpan,
|
|
4115
|
+
flowColumnWidthMm,
|
|
4116
|
+
flowSpanWidthMm,
|
|
4117
|
+
estimateTextWidthMm,
|
|
4118
|
+
spanForText,
|
|
4119
|
+
layoutFlowList,
|
|
4120
|
+
detectFlowListKey,
|
|
4121
|
+
suggestFlowColumns,
|
|
4122
|
+
flowGridStyle,
|
|
3789
4123
|
bindData,
|
|
3790
4124
|
resolveSystemVariables,
|
|
3791
4125
|
injectSystemVariables,
|
|
@@ -3793,6 +4127,12 @@ export {
|
|
|
3793
4127
|
FALLBACK_FONT_STACK,
|
|
3794
4128
|
escapeInlineStyleValue,
|
|
3795
4129
|
toFontFamilyStack,
|
|
4130
|
+
resolveCanvasFontFamily,
|
|
4131
|
+
normalizeFontCatalog,
|
|
4132
|
+
findFontOption,
|
|
4133
|
+
fontOptionLabel,
|
|
4134
|
+
normalizeFontQuery,
|
|
4135
|
+
filterFontOptions,
|
|
3796
4136
|
PAPER_DIMENSIONS,
|
|
3797
4137
|
isContinuousPaperSize,
|
|
3798
4138
|
getPaperDimensions,
|
|
@@ -3840,14 +4180,22 @@ export {
|
|
|
3840
4180
|
paginate,
|
|
3841
4181
|
MM_PER_INCH,
|
|
3842
4182
|
BARCODE_QUIET_ZONE_MODULES,
|
|
4183
|
+
barcodeQuietZoneModules,
|
|
3843
4184
|
BARCODE_BAR_HEIGHT_MODULES,
|
|
3844
4185
|
BARCODE_TEXT_FONT_SIZE_MODULES,
|
|
3845
4186
|
BARCODE_MARGIN_BOTTOM_MODULES,
|
|
4187
|
+
QR_DEFAULT_QUIET_MODULES,
|
|
3846
4188
|
BARCODE_MODULE_WIDTH_MM,
|
|
4189
|
+
BARCODE_MIN_MODULE_WIDTH_MM,
|
|
4190
|
+
recommendBarcodeBarWidth,
|
|
4191
|
+
barcodeBarWidthRecommendText,
|
|
3847
4192
|
barcodeUnitsPerModule,
|
|
3848
4193
|
barcodePreferredModuleWidthMm,
|
|
4194
|
+
barcodeBarHeightModules,
|
|
4195
|
+
barcodeWidthBoundModuleWidthMm,
|
|
3849
4196
|
barcodeAvailableBoxMm,
|
|
3850
4197
|
resolveBarcodeSize,
|
|
4198
|
+
layoutBarcodeSize,
|
|
3851
4199
|
generateHtml,
|
|
3852
4200
|
MIN_CONTINUOUS_HEIGHT_MM,
|
|
3853
4201
|
composeContinuousHeight,
|
package/dist/client/index.cjs
CHANGED
package/dist/client/index.d.cts
CHANGED
package/dist/client/index.d.ts
CHANGED
package/dist/client/index.js
CHANGED