@worm-vue3-print/core 1.2.1 → 1.3.0

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.
@@ -0,0 +1,2641 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/designer/index.ts
21
+ var designer_exports = {};
22
+ __export(designer_exports, {
23
+ BARCODE_BAR_HEIGHT_MODULES: () => BARCODE_BAR_HEIGHT_MODULES,
24
+ BARCODE_MARGIN_BOTTOM_MODULES: () => BARCODE_MARGIN_BOTTOM_MODULES,
25
+ BARCODE_MODULE_WIDTH_MM: () => BARCODE_MODULE_WIDTH_MM,
26
+ BARCODE_QUIET_ZONE_MODULES: () => BARCODE_QUIET_ZONE_MODULES,
27
+ BARCODE_TEXT_FONT_SIZE_MODULES: () => BARCODE_TEXT_FONT_SIZE_MODULES,
28
+ DEFAULT_DEMO_DATA: () => DEFAULT_DEMO_DATA,
29
+ DEFAULT_SHRINK_MIN_FONT_SIZE_PT: () => DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
30
+ ELEMENT_BINDING_REGISTRY: () => ELEMENT_BINDING_REGISTRY,
31
+ EXTENDED_FUNCTIONS: () => EXTENDED_FUNCTIONS,
32
+ FIT_SCALE_MIN_PERCENT: () => FIT_SCALE_MIN_PERCENT,
33
+ GHOST_BORDER_CSS: () => GHOST_BORDER_CSS,
34
+ LABEL_PAPER_GROUP: () => LABEL_PAPER_GROUP,
35
+ MIN_COL_WIDTH_MM: () => MIN_COL_WIDTH_MM,
36
+ MIN_SCALE_PERCENT: () => MIN_SCALE_PERCENT,
37
+ MIN_SHRINK_FONT_SIZE_PT: () => MIN_SHRINK_FONT_SIZE_PT,
38
+ MM_PER_INCH: () => MM_PER_INCH,
39
+ PAPER_PRESETS: () => PAPER_PRESETS,
40
+ PRESET_COLORS: () => PRESET_COLORS,
41
+ PROPERTY_REGISTRY: () => PROPERTY_REGISTRY,
42
+ RESIZE_POINTS: () => RESIZE_POINTS,
43
+ RULER_THICKNESS: () => RULER_THICKNESS,
44
+ ZONE_ALLOWED_TYPES: () => ZONE_ALLOWED_TYPES,
45
+ applyBorderPreset: () => applyBorderPreset,
46
+ barcodeAvailableBoxMm: () => barcodeAvailableBoxMm,
47
+ barcodePreferredModuleWidthMm: () => barcodePreferredModuleWidthMm,
48
+ barcodeUnitsPerModule: () => barcodeUnitsPerModule,
49
+ buildRulerTicks: () => buildRulerTicks,
50
+ calcResizeRect: () => calcResizeRect,
51
+ canMergeReason: () => canMergeReason,
52
+ cellFitCapMm: () => cellFitCapMm,
53
+ cellFitKey: () => cellFitKey,
54
+ cellFitWidthMm: () => cellFitWidthMm,
55
+ chooseMajorStepMM: () => chooseMajorStepMM,
56
+ clampResizedColumnWidth: () => clampResizedColumnWidth,
57
+ clampScalePercent: () => clampScalePercent,
58
+ clampToZone: () => clampToZone,
59
+ computeAdsorb: () => computeAdsorb,
60
+ computeFitScale: () => computeFitScale,
61
+ createCell: () => createCell,
62
+ createDefaultOptions: () => createDefaultOptions,
63
+ createDefaultTable: () => createDefaultTable,
64
+ createFieldElement: () => createFieldElement,
65
+ createRuntimeElement: () => createRuntimeElement,
66
+ deleteCol: () => deleteCol,
67
+ deleteRow: () => deleteRow,
68
+ engine: () => engine2,
69
+ evaluateTemplate: () => evaluateTemplate2,
70
+ filterGroups: () => filterGroups,
71
+ finalizeElementZone: () => finalizeElementZone,
72
+ findMainCell: () => findMainCell,
73
+ floorFontSize: () => floorFontSize,
74
+ generateGroupId: () => generateGroupId,
75
+ generateId: () => generateId,
76
+ getDemoData: () => getDemoData,
77
+ getElementBindings: () => getElementBindings,
78
+ getPaperDimensions: () => getPaperDimensions,
79
+ getPaperSizeMM: () => getPaperSizeMM,
80
+ getSpanRect: () => getSpanRect,
81
+ getTableCellBindings: () => getTableCellBindings,
82
+ getZoneRects: () => getZoneRects,
83
+ groupFields: () => groupFields,
84
+ insertCol: () => insertCol,
85
+ insertRow: () => insertRow,
86
+ isContinuousPaperSize: () => isContinuousPaperSize,
87
+ isLabelPaperSize: () => isLabelPaperSize,
88
+ labelPaperDefaults: () => labelPaperDefaults,
89
+ matchKeywords: () => matchKeywords,
90
+ mergeCells: () => mergeCells,
91
+ minorStepMM: () => minorStepMM,
92
+ mmToPx: () => mmToPx,
93
+ nextWheelScale: () => nextWheelScale,
94
+ normalizeSelection: () => normalizeSelection,
95
+ normalizeTemplateUnits: () => normalizeTemplateUnits,
96
+ parseCellFitKey: () => parseCellFitKey,
97
+ ptToMm: () => ptToMm,
98
+ pxToMm: () => pxToMm,
99
+ resolveBarcodeDesignValue: () => resolveBarcodeDesignValue,
100
+ resolveBarcodeSize: () => resolveBarcodeSize,
101
+ resolveCellBorderCss: () => resolveCellBorderCss,
102
+ resolveCellTextFit: () => resolveCellTextFit,
103
+ resolveElementTextFit: () => resolveElementTextFit,
104
+ resolveShrinkMinFontSize: () => resolveShrinkMinFontSize,
105
+ resolveTextBinding: () => resolveTextBinding,
106
+ roundFontSize: () => roundFontSize,
107
+ safeEval: () => safeEval2,
108
+ searchProperties: () => searchProperties,
109
+ setRowType: () => setRowType,
110
+ splitCells: () => splitCells,
111
+ syncTableElementSize: () => syncTableElementSize,
112
+ useAlign: () => useAlign,
113
+ useBindingDisplay: () => useBindingDisplay,
114
+ useGroup: () => useGroup,
115
+ useKeyboard: () => useKeyboard,
116
+ useResize: () => useResize,
117
+ zoneFromPaperPoint: () => zoneFromPaperPoint
118
+ });
119
+ module.exports = __toCommonJS(designer_exports);
120
+
121
+ // src/designer/utils/units.ts
122
+ function ptToMm(pt) {
123
+ return pt / 2.83464566929;
124
+ }
125
+ function pxToMm(px) {
126
+ return px * (25.4 / 96);
127
+ }
128
+ function mmToPx(mm2) {
129
+ return mm2 * (96 / 25.4);
130
+ }
131
+
132
+ // src/render/text-fit.ts
133
+ var DEFAULT_SHRINK_MIN_FONT_SIZE_PT = 6;
134
+ var MIN_SHRINK_FONT_SIZE_PT = 1;
135
+ var VALID_FITS = ["clip", "shrink", "autoHeight"];
136
+ function normalizeFit(value) {
137
+ return typeof value === "string" && VALID_FITS.includes(value) ? value : void 0;
138
+ }
139
+ var ELEMENT_DEFAULT_FIT = {
140
+ text: "clip",
141
+ longText: "autoHeight"
142
+ };
143
+ function resolveElementTextFit(type, opts) {
144
+ return normalizeFit(opts?.textFit) ?? ELEMENT_DEFAULT_FIT[type] ?? "clip";
145
+ }
146
+ function resolveCellTextFit(cell) {
147
+ return normalizeFit(cell?.textFit) ?? (cell?.wordWrap === false ? "clip" : "autoHeight");
148
+ }
149
+ function resolveShrinkMinFontSize(pt) {
150
+ if (typeof pt !== "number" || !Number.isFinite(pt) || pt <= 0) return DEFAULT_SHRINK_MIN_FONT_SIZE_PT;
151
+ return Math.max(pt, MIN_SHRINK_FONT_SIZE_PT);
152
+ }
153
+ function roundFontSize(pt) {
154
+ return Math.round(pt * 100) / 100;
155
+ }
156
+ function floorFontSize(pt) {
157
+ return Math.floor(pt * 100) / 100;
158
+ }
159
+ function cellFitKey(elementId, kind, rowIndex, colIndex) {
160
+ return `${elementId}#${kind}#${rowIndex}:${colIndex}`;
161
+ }
162
+ function parseCellFitKey(key) {
163
+ const first = key.indexOf("#");
164
+ if (first < 0) return void 0;
165
+ const last = key.lastIndexOf("#");
166
+ const kind = key.slice(first + 1, last);
167
+ if (kind !== "b" && kind !== "st" && kind !== "sm") return void 0;
168
+ const [rowIndex, colIndex] = key.slice(last + 1).split(":").map(Number);
169
+ if (!Number.isFinite(rowIndex) || !Number.isFinite(colIndex)) return void 0;
170
+ return { elementId: key.slice(0, first), kind, rowIndex, colIndex };
171
+ }
172
+ function cellFitWidthMm(colWidths, colIndex, cell, defaultPadding = 1) {
173
+ const span = Math.max(cell?.colspan ?? 1, 1);
174
+ let width = 0;
175
+ for (let i = 0; i < span; i++) {
176
+ width += colWidths[colIndex + i] ?? 0;
177
+ }
178
+ if (width <= 0) return 0;
179
+ const padding = cell?.padding ?? defaultPadding;
180
+ const borderMm = (ptToMm(cell?.borders?.left?.width ?? 0) + ptToMm(cell?.borders?.right?.width ?? 0)) / 2;
181
+ return Math.max(width - padding * 2 - borderMm, 0.5);
182
+ }
183
+ function cellFitCapMm(rows, rowIndex, cell, defaultPadding = 1) {
184
+ const span = Math.max(cell?.rowspan ?? 1, 1);
185
+ let height = 0;
186
+ for (let i = 0; i < span; i++) {
187
+ height += rows[rowIndex + i]?.height ?? 8;
188
+ }
189
+ const padding = cell?.padding ?? defaultPadding;
190
+ const borderMm = (ptToMm(cell?.borders?.top?.width ?? 0) + ptToMm(cell?.borders?.bottom?.width ?? 0)) / 2;
191
+ return Math.max(height - padding * 2 - borderMm, 0.5);
192
+ }
193
+
194
+ // src/render/barcode-dot.ts
195
+ var MM_PER_INCH = 25.4;
196
+ var BARCODE_QUIET_ZONE_MODULES = 10;
197
+ var BARCODE_BAR_HEIGHT_MODULES = 30;
198
+ var BARCODE_TEXT_FONT_SIZE_MODULES = 10;
199
+ var BARCODE_MARGIN_BOTTOM_MODULES = 2;
200
+ var BARCODE_MODULE_WIDTH_MM = 0.25;
201
+ function barcodeUnitsPerModule(barWidth) {
202
+ const raw = typeof barWidth === "number" && Number.isFinite(barWidth) ? barWidth : 2;
203
+ return Math.max(1, raw / 2);
204
+ }
205
+ function barcodePreferredModuleWidthMm(barWidth) {
206
+ return barcodeUnitsPerModule(barWidth) * BARCODE_MODULE_WIDTH_MM;
207
+ }
208
+ function barcodeAvailableBoxMm(boxMm, maxMm) {
209
+ const box = typeof boxMm === "number" && boxMm > 0 ? boxMm : Number.POSITIVE_INFINITY;
210
+ const limit = typeof maxMm === "number" && maxMm > 0 ? Math.min(box, maxMm) : box;
211
+ return Number.isFinite(limit) ? limit : 0;
212
+ }
213
+ function resolveBarcodeSize(input) {
214
+ const unitWidth = Math.max(1, Math.ceil(input.unitWidth));
215
+ const unitHeight = Math.max(1, Math.ceil(input.unitHeight));
216
+ const preferredModuleMm = barcodePreferredModuleWidthMm(input.barWidth);
217
+ const maxModuleMm = Math.min(
218
+ input.boxWidthMm > 0 ? input.boxWidthMm / unitWidth : Number.POSITIVE_INFINITY,
219
+ input.boxHeightMm > 0 ? input.boxHeightMm / unitHeight : Number.POSITIVE_INFINITY
220
+ );
221
+ const dpi = input.dpi;
222
+ if (typeof dpi === "number" && Number.isFinite(dpi) && dpi > 0) {
223
+ const dotsPerMm = dpi / MM_PER_INCH;
224
+ const preferredDots = Math.max(1, Math.round(preferredModuleMm * dotsPerMm));
225
+ const maxDots = Math.floor(maxModuleMm * dotsPerMm);
226
+ if (maxDots >= 1) {
227
+ const dotsPerModule = Math.min(preferredDots, maxDots);
228
+ const moduleWidthMm2 = dotsPerModule / dotsPerMm;
229
+ return {
230
+ moduleWidthMm: moduleWidthMm2,
231
+ widthMm: unitWidth * moduleWidthMm2,
232
+ heightMm: unitHeight * moduleWidthMm2,
233
+ dotsPerModule,
234
+ scaledDown: dotsPerModule < preferredDots
235
+ };
236
+ }
237
+ }
238
+ const moduleWidthMm = Math.min(preferredModuleMm, maxModuleMm);
239
+ return {
240
+ moduleWidthMm,
241
+ widthMm: unitWidth * moduleWidthMm,
242
+ heightMm: unitHeight * moduleWidthMm,
243
+ dotsPerModule: null,
244
+ scaledDown: moduleWidthMm < preferredModuleMm
245
+ };
246
+ }
247
+
248
+ // src/designer/utils/scale.ts
249
+ var MIN_SCALE_PERCENT = 25;
250
+ var FIT_SCALE_MIN_PERCENT = 5;
251
+ function clampScalePercent(percent) {
252
+ return Math.max(MIN_SCALE_PERCENT, percent);
253
+ }
254
+ function nextWheelScale(percent, direction, factor = 1.1) {
255
+ const next = direction > 0 ? percent * factor : percent / factor;
256
+ return clampScalePercent(Math.round(next));
257
+ }
258
+ function computeFitScale(containerW, containerH, paperW, paperH, ratio = 0.9) {
259
+ if (paperW <= 0 || paperH <= 0) return 100;
260
+ const fit = Math.min(containerW / paperW, containerH / paperH) * ratio;
261
+ const pct = Math.round(fit * 100);
262
+ return Math.max(FIT_SCALE_MIN_PERCENT, pct);
263
+ }
264
+
265
+ // src/designer/utils/migrate.ts
266
+ var PT_KEYS = ["left", "top", "width", "height"];
267
+ function convertElement(el) {
268
+ const options = { ...el.options };
269
+ for (const key of PT_KEYS) {
270
+ const v = options[key];
271
+ if (typeof v === "number" && Number.isFinite(v)) {
272
+ ;
273
+ options[key] = round2(ptToMm(v));
274
+ }
275
+ }
276
+ return { ...el, options };
277
+ }
278
+ function round2(n) {
279
+ return Math.round(n * 100) / 100;
280
+ }
281
+ function normalizeTemplateUnits(data) {
282
+ if (data.unit === "mm") return data;
283
+ const convert = (els) => els?.map(convertElement) ?? [];
284
+ return {
285
+ ...data,
286
+ unit: "mm",
287
+ elements: convert(data.elements),
288
+ header: data.header ? { ...data.header, elements: convert(data.header.elements) } : data.header,
289
+ footer: data.footer ? { ...data.footer, elements: convert(data.footer.elements) } : data.footer,
290
+ firstPageOverlay: data.firstPageOverlay ? { ...data.firstPageOverlay, elements: convert(data.firstPageOverlay.elements) } : data.firstPageOverlay
291
+ };
292
+ }
293
+
294
+ // src/designer/utils/default-config.ts
295
+ var LABEL_PAPER_GROUP = "\u6807\u7B7E\u7EB8";
296
+ var PAPER_PRESETS = {
297
+ A4: { width: 210, height: 297, label: "A4 210\xD7297mm", group: "\u5E38\u7528\u7EB8\u5F20" },
298
+ A3: { width: 297, height: 420, label: "A3 297\xD7420mm", group: "\u5E38\u7528\u7EB8\u5F20" },
299
+ A5: { width: 148, height: 210, label: "A5 148\xD7210mm", group: "\u5E38\u7528\u7EB8\u5F20" },
300
+ Letter: { width: 216, height: 279, label: "Letter 216\xD7279mm", group: "\u5E38\u7528\u7EB8\u5F20" },
301
+ Legal: { width: 216, height: 356, label: "Legal 216\xD7356mm", group: "\u5E38\u7528\u7EB8\u5F20" },
302
+ // 针式打印纸(241 系列等分):11 英寸整张 279.4mm 按等分取整
303
+ DOT_FULL: { width: 241, height: 279.4, label: "\u5168\u7B49\u5206 241\xD7279.4mm", group: "\u9488\u5F0F\u6253\u5370\u7EB8" },
304
+ DOT_HALF: { width: 241, height: 139.7, label: "\u4E8C\u7B49\u5206 241\xD7139.7mm", group: "\u9488\u5F0F\u6253\u5370\u7EB8" },
305
+ DOT_THIRD: { width: 241, height: 93.1, label: "\u4E09\u7B49\u5206 241\xD793.1mm", group: "\u9488\u5F0F\u6253\u5370\u7EB8" },
306
+ // 标签纸
307
+ LABEL_80X60: { width: 80, height: 60, label: "80\xD760mm", group: LABEL_PAPER_GROUP },
308
+ LABEL_60X40: { width: 60, height: 40, label: "60\xD740mm", group: LABEL_PAPER_GROUP },
309
+ LABEL_40X30: { width: 40, height: 30, label: "40\xD730mm", group: LABEL_PAPER_GROUP },
310
+ // 小票纸(热敏卷纸):高度仅为设计画布高度,出纸按内容推导
311
+ THERMAL_57: { width: 57, height: 297, continuous: true, label: "57mm", group: "\u5C0F\u7968\u7EB8" },
312
+ THERMAL_80: { width: 80, height: 297, continuous: true, label: "80mm", group: "\u5C0F\u7968\u7EB8" },
313
+ THERMAL_110: { width: 110, height: 297, continuous: true, label: "110mm", group: "\u5C0F\u7968\u7EB8" },
314
+ // 连续纸:默认 80mm 热敏;高度仅为设计画布高度,出纸按内容推导
315
+ CONTINUOUS: { width: 80, height: 297, continuous: true, label: "\u8FDE\u7EED\u7EB8\uFF08\u81EA\u5B9A\u4E49\u5BBD\u5EA6\uFF09", group: "\u8FDE\u7EED\u7EB8" }
316
+ };
317
+ function isContinuousPaperSize(paperSize) {
318
+ return !!paperSize && PAPER_PRESETS[paperSize]?.continuous === true;
319
+ }
320
+ function isLabelPaperSize(paperSize) {
321
+ return !!paperSize && PAPER_PRESETS[paperSize]?.group === LABEL_PAPER_GROUP;
322
+ }
323
+ function labelPaperDefaults(t) {
324
+ return {
325
+ margins: { top: 0, right: 0, bottom: 0, left: 0 },
326
+ header: { ...t.header, height: 0 },
327
+ footer: { ...t.footer, height: 0 }
328
+ };
329
+ }
330
+ function getPaperDimensions(t) {
331
+ const continuous = isContinuousPaperSize(t.paperSize);
332
+ let base;
333
+ if (t.paperSize === "CUSTOM" || continuous) {
334
+ const preset = PAPER_PRESETS[t.paperSize];
335
+ base = {
336
+ width: t.customWidth ?? preset?.width ?? 210,
337
+ height: t.customHeight ?? preset?.height ?? 297
338
+ };
339
+ } else {
340
+ const preset = PAPER_PRESETS[t.paperSize] || PAPER_PRESETS["A4"];
341
+ base = { width: preset.width, height: preset.height };
342
+ }
343
+ return t.orientation === "landscape" && !continuous ? { width: base.height, height: base.width } : base;
344
+ }
345
+
346
+ // src/designer/utils/table-matrix.ts
347
+ function createCellIdGenerator() {
348
+ let seq = 0;
349
+ return function genCellId2() {
350
+ seq += 1;
351
+ return `cell-${Date.now().toString(36)}-${seq}`;
352
+ };
353
+ }
354
+ function createRowIdGenerator() {
355
+ let seq = 0;
356
+ return function genRowId2() {
357
+ seq += 1;
358
+ return `row-${Date.now().toString(36)}-${seq}`;
359
+ };
360
+ }
361
+ var genCellId = createCellIdGenerator();
362
+ var genRowId = createRowIdGenerator();
363
+ var DEFAULT_BORDER = { width: 0.75, style: "solid", color: "#333333" };
364
+ function deepClone(v) {
365
+ return JSON.parse(JSON.stringify(v));
366
+ }
367
+ function createCell(partial) {
368
+ return {
369
+ id: genCellId(),
370
+ borders: {
371
+ top: { ...DEFAULT_BORDER },
372
+ right: { ...DEFAULT_BORDER },
373
+ bottom: { ...DEFAULT_BORDER },
374
+ left: { ...DEFAULT_BORDER }
375
+ },
376
+ ...partial
377
+ };
378
+ }
379
+ function createDefaultTable() {
380
+ const colWidths = [50, 50, 50];
381
+ const mk = (type, repeat) => ({
382
+ id: genRowId(),
383
+ type,
384
+ height: 8,
385
+ ...repeat !== void 0 ? { repeatOnPage: repeat } : {},
386
+ cells: colWidths.map(() => createCell())
387
+ });
388
+ const header = mk("header", true);
389
+ header.cells.forEach((c, i) => {
390
+ c.formatter = `\u5217${i + 1}`;
391
+ c.align = "center";
392
+ c.fontWeight = "bold";
393
+ });
394
+ return { rows: [header, mk("data"), mk("subtotal"), mk("summary")], colWidths };
395
+ }
396
+ function findMainCell(rows, r, c) {
397
+ if (!rows[r].cells[c].merged) {
398
+ return { r, c };
399
+ }
400
+ for (let ri = r; ri >= 0; ri--) {
401
+ for (let ci = c; ci >= 0; ci--) {
402
+ const cell = rows[ri].cells[ci];
403
+ if (cell.merged) {
404
+ continue;
405
+ }
406
+ const rs = cell.rowspan ?? 1;
407
+ const cs = cell.colspan ?? 1;
408
+ if (ri + rs - 1 >= r && ci + cs - 1 >= c) {
409
+ return { r: ri, c: ci };
410
+ }
411
+ }
412
+ }
413
+ return { r, c };
414
+ }
415
+ function getSpanRect(rows, r, c) {
416
+ const main = findMainCell(rows, r, c);
417
+ const cell = rows[main.r].cells[main.c];
418
+ return {
419
+ r1: main.r,
420
+ c1: main.c,
421
+ r2: main.r + (cell.rowspan ?? 1) - 1,
422
+ c2: main.c + (cell.colspan ?? 1) - 1
423
+ };
424
+ }
425
+ function normalizeSelection(rows, a, b) {
426
+ let rect = {
427
+ r1: Math.min(a.r, b.r),
428
+ c1: Math.min(a.c, b.c),
429
+ r2: Math.max(a.r, b.r),
430
+ c2: Math.max(a.c, b.c)
431
+ };
432
+ for (; ; ) {
433
+ let changed = false;
434
+ for (let r = rect.r1; r <= rect.r2; r++) {
435
+ for (let c = rect.c1; c <= rect.c2; c++) {
436
+ const span = getSpanRect(rows, r, c);
437
+ const merged = {
438
+ r1: Math.min(rect.r1, span.r1),
439
+ c1: Math.min(rect.c1, span.c1),
440
+ r2: Math.max(rect.r2, span.r2),
441
+ c2: Math.max(rect.c2, span.c2)
442
+ };
443
+ if (merged.r1 !== rect.r1 || merged.c1 !== rect.c1 || merged.r2 !== rect.r2 || merged.c2 !== rect.c2) {
444
+ rect = merged;
445
+ changed = true;
446
+ }
447
+ }
448
+ }
449
+ if (!changed) {
450
+ return rect;
451
+ }
452
+ }
453
+ }
454
+ function canMergeReason(rows, rect) {
455
+ const cellCount = (rect.r2 - rect.r1 + 1) * (rect.c2 - rect.c1 + 1);
456
+ if (cellCount < 2) {
457
+ return "\u81F3\u5C11\u9009\u62E9 2 \u4E2A\u5355\u5143\u683C";
458
+ }
459
+ const types = /* @__PURE__ */ new Set();
460
+ for (let r = rect.r1; r <= rect.r2; r++) {
461
+ types.add(rows[r].type);
462
+ }
463
+ if (types.size > 1) {
464
+ return "\u5408\u5E76\u533A\u57DF\u4E0D\u80FD\u8DE8\u8D8A\u4E0D\u540C\u7C7B\u578B\u7684\u884C";
465
+ }
466
+ const norm = normalizeSelection(rows, { r: rect.r1, c: rect.c1 }, { r: rect.r2, c: rect.c2 });
467
+ if (norm.r1 !== rect.r1 || norm.c1 !== rect.c1 || norm.r2 !== rect.r2 || norm.c2 !== rect.c2) {
468
+ return "\u9009\u533A\u4E0E\u5DF2\u6709\u5408\u5E76\u533A\u57DF\u90E8\u5206\u91CD\u53E0";
469
+ }
470
+ return null;
471
+ }
472
+ function mergeCells(rows, rect) {
473
+ const main = rows[rect.r1].cells[rect.c1];
474
+ const contents = [];
475
+ for (let r = rect.r1; r <= rect.r2; r++) {
476
+ for (let c = rect.c1; c <= rect.c2; c++) {
477
+ const cell = rows[r].cells[c];
478
+ if (cell.formatter) {
479
+ contents.push(cell.formatter);
480
+ }
481
+ if (r === rect.r1 && c === rect.c1) {
482
+ continue;
483
+ }
484
+ cell.merged = true;
485
+ cell.rowspan = 1;
486
+ cell.colspan = 1;
487
+ cell.formatter = "";
488
+ }
489
+ }
490
+ main.rowspan = rect.r2 - rect.r1 + 1;
491
+ main.colspan = rect.c2 - rect.c1 + 1;
492
+ main.formatter = contents.join(" ");
493
+ }
494
+ function splitCells(rows, rect) {
495
+ for (let r = rect.r1; r <= rect.r2; r++) {
496
+ for (let c = rect.c1; c <= rect.c2; c++) {
497
+ const cell = rows[r].cells[c];
498
+ if (!cell.merged && ((cell.rowspan ?? 1) > 1 || (cell.colspan ?? 1) > 1)) {
499
+ const span = getSpanRect(rows, r, c);
500
+ const styleSrc = cell;
501
+ for (let sr = span.r1; sr <= span.r2; sr++) {
502
+ for (let sc = span.c1; sc <= span.c2; sc++) {
503
+ const t = rows[sr].cells[sc];
504
+ t.merged = false;
505
+ t.rowspan = 1;
506
+ t.colspan = 1;
507
+ copyCellStyle(styleSrc, t);
508
+ }
509
+ }
510
+ cell.rowspan = 1;
511
+ cell.colspan = 1;
512
+ }
513
+ }
514
+ }
515
+ }
516
+ function copyCellStyle(src, dst) {
517
+ if (src === dst) {
518
+ return;
519
+ }
520
+ dst.align = src.align;
521
+ dst.valign = src.valign;
522
+ dst.fontSize = src.fontSize;
523
+ dst.fontFamily = src.fontFamily;
524
+ dst.fontWeight = src.fontWeight;
525
+ dst.color = src.color;
526
+ dst.backgroundColor = src.backgroundColor;
527
+ dst.borders = src.borders ? deepClone(src.borders) : void 0;
528
+ dst.padding = src.padding;
529
+ dst.wordWrap = src.wordWrap;
530
+ }
531
+ function insertRow(rows, index, position) {
532
+ const insertAt = position === "above" ? index : index + 1;
533
+ const ref = rows[index];
534
+ const colCount = ref.cells.length;
535
+ const type = ref.type === "data" ? "header" : ref.type;
536
+ const newRow = {
537
+ id: `row-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`,
538
+ type,
539
+ height: ref.height,
540
+ cells: Array.from({ length: colCount }, () => createCell())
541
+ };
542
+ for (let c = 0; c < colCount; c++) {
543
+ if (insertAt > 0 && insertAt < rows.length) {
544
+ const span = getSpanRect(rows, insertAt - 1, c);
545
+ if (span.r1 < insertAt && span.r2 >= insertAt) {
546
+ const main = rows[span.r1].cells[span.c1];
547
+ main.rowspan = (main.rowspan ?? 1) + 1;
548
+ newRow.cells[c].merged = true;
549
+ }
550
+ }
551
+ }
552
+ rows.splice(insertAt, 0, newRow);
553
+ }
554
+ function deleteRow(rows, index) {
555
+ if (rows.length <= 1) {
556
+ return "\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u884C";
557
+ }
558
+ const row = rows[index];
559
+ const colCount = row.cells.length;
560
+ for (let c = 0; c < colCount; c++) {
561
+ const cell = row.cells[c];
562
+ if (!cell.merged && (cell.rowspan ?? 1) > 1) {
563
+ const next = rows[index + 1].cells[c];
564
+ Object.assign(next, deepClone(cell), { id: next.id });
565
+ next.rowspan = (cell.rowspan ?? 1) - 1;
566
+ next.merged = false;
567
+ } else if (cell.merged) {
568
+ const span = getSpanRect(rows, index, c);
569
+ if (span.r1 < index && span.c1 === c) {
570
+ const main = rows[span.r1].cells[span.c1];
571
+ main.rowspan = (main.rowspan ?? 1) - 1;
572
+ }
573
+ }
574
+ }
575
+ rows.splice(index, 1);
576
+ return null;
577
+ }
578
+ function insertCol(rows, colWidths, index, position) {
579
+ const insertAt = position === "left" ? index : index + 1;
580
+ colWidths.splice(insertAt, 0, colWidths[index]);
581
+ for (const row of rows) {
582
+ const newCell = createCell();
583
+ if (insertAt > 0 && insertAt < row.cells.length) {
584
+ const r = rows.indexOf(row);
585
+ const span = getSpanRect(rows, r, insertAt - 1);
586
+ if (span.c1 < insertAt && span.c2 >= insertAt) {
587
+ const main = rows[span.r1].cells[span.c1];
588
+ if (r === span.r1) {
589
+ main.colspan = (main.colspan ?? 1) + 1;
590
+ }
591
+ newCell.merged = true;
592
+ }
593
+ }
594
+ row.cells.splice(insertAt, 0, newCell);
595
+ }
596
+ }
597
+ function deleteCol(rows, colWidths, index) {
598
+ if (colWidths.length <= 1) {
599
+ return "\u4E0D\u80FD\u5220\u9664\u6700\u540E\u4E00\u5217";
600
+ }
601
+ for (let r = 0; r < rows.length; r++) {
602
+ const cell = rows[r].cells[index];
603
+ if (!cell.merged && (cell.colspan ?? 1) > 1) {
604
+ const next = rows[r].cells[index + 1];
605
+ Object.assign(next, deepClone(cell), { id: next.id });
606
+ next.colspan = (cell.colspan ?? 1) - 1;
607
+ next.merged = false;
608
+ } else if (cell.merged) {
609
+ const span = getSpanRect(rows, r, index);
610
+ if (span.c1 < index && span.r1 === r) {
611
+ const main = rows[span.r1].cells[span.c1];
612
+ main.colspan = (main.colspan ?? 1) - 1;
613
+ }
614
+ }
615
+ }
616
+ for (const row of rows) {
617
+ row.cells.splice(index, 1);
618
+ }
619
+ colWidths.splice(index, 1);
620
+ return null;
621
+ }
622
+ function setRowType(rows, index, type) {
623
+ if (type === "data") {
624
+ const existing = rows.findIndex((r, i) => r.type === "data" && i !== index);
625
+ if (existing >= 0) {
626
+ return `\u6570\u636E\u884C\u5DF2\u5B58\u5728\uFF08\u7B2C ${existing + 1} \u884C\uFF09\uFF0C\u5168\u8868\u6700\u591A\u4E00\u884C`;
627
+ }
628
+ }
629
+ if (type === "header") {
630
+ for (let i = 0; i < index; i++) {
631
+ if (rows[i].type !== "header") {
632
+ return "\u6807\u9898\u884C\u5FC5\u987B\u4ECE\u8868\u683C\u9876\u90E8\u8FDE\u7EED\u8BBE\u7F6E";
633
+ }
634
+ }
635
+ }
636
+ if (type === "subtotal" || type === "summary") {
637
+ const dataIdx = rows.findIndex((r) => r.type === "data");
638
+ if (dataIdx < 0) {
639
+ return "\u8BF7\u5148\u8BBE\u7F6E\u6570\u636E\u884C\uFF0C\u5C0F\u8BA1/\u6C47\u603B\u884C\u5FC5\u987B\u4F4D\u4E8E\u6570\u636E\u884C\u4E4B\u540E";
640
+ }
641
+ if (index < dataIdx) {
642
+ return "\u5C0F\u8BA1/\u6C47\u603B\u884C\u5FC5\u987B\u4F4D\u4E8E\u6570\u636E\u884C\u4E4B\u540E";
643
+ }
644
+ }
645
+ if (type === "subtotal") {
646
+ if (rows.slice(0, index).some((r) => r.type === "summary")) {
647
+ return "\u5C0F\u8BA1\u884C\u5FC5\u987B\u4F4D\u4E8E\u6C47\u603B\u884C\u4E4B\u524D";
648
+ }
649
+ }
650
+ if (type === "summary") {
651
+ if (rows.slice(index + 1).some((r) => r.type === "subtotal")) {
652
+ return "\u6C47\u603B\u884C\u5FC5\u987B\u4F4D\u4E8E\u5C0F\u8BA1\u884C\u4E4B\u540E";
653
+ }
654
+ }
655
+ if (rows[index].type === "header" && type !== "header") {
656
+ for (let i = index + 1; i < rows.length; i++) {
657
+ if (rows[i].type === "header") {
658
+ return "\u53D6\u6D88\u8BE5\u6807\u9898\u884C\u4F1A\u5BFC\u81F4\u6807\u9898\u884C\u4E0D\u8FDE\u7EED\uFF0C\u8BF7\u5148\u8C03\u6574\u540E\u7EED\u6807\u9898\u884C";
659
+ }
660
+ }
661
+ }
662
+ rows[index].type = type;
663
+ if (type !== "header") {
664
+ delete rows[index].repeatOnPage;
665
+ }
666
+ return null;
667
+ }
668
+ function applyBorderPreset(rows, rect, preset, border) {
669
+ for (let r = rect.r1; r <= rect.r2; r++) {
670
+ for (let c = rect.c1; c <= rect.c2; c++) {
671
+ const cell = rows[r].cells[c];
672
+ if (cell.merged) {
673
+ continue;
674
+ }
675
+ if (preset === "none") {
676
+ delete cell.borders;
677
+ continue;
678
+ }
679
+ const span = getSpanRect(rows, r, c);
680
+ const atTop = span.r1 === rect.r1;
681
+ const atBottom = span.r2 === rect.r2;
682
+ const atLeft = span.c1 === rect.c1;
683
+ const atRight = span.c2 === rect.c2;
684
+ const b = { ...cell.borders ?? {} };
685
+ if (preset === "all") {
686
+ b.top = { ...border };
687
+ b.bottom = { ...border };
688
+ b.left = { ...border };
689
+ b.right = { ...border };
690
+ } else if (preset === "outer") {
691
+ if (atTop) {
692
+ b.top = { ...border };
693
+ }
694
+ if (atBottom) {
695
+ b.bottom = { ...border };
696
+ }
697
+ if (atLeft) {
698
+ b.left = { ...border };
699
+ }
700
+ if (atRight) {
701
+ b.right = { ...border };
702
+ }
703
+ } else if (preset === "inner") {
704
+ if (!atTop) {
705
+ b.top = { ...border };
706
+ }
707
+ if (!atBottom) {
708
+ b.bottom = { ...border };
709
+ }
710
+ if (!atLeft) {
711
+ b.left = { ...border };
712
+ }
713
+ if (!atRight) {
714
+ b.right = { ...border };
715
+ }
716
+ }
717
+ cell.borders = b;
718
+ }
719
+ }
720
+ }
721
+ var GHOST_BORDER_CSS = "1px dashed rgba(0,0,0,0.18)";
722
+ function resolveCellBorderCss(b, opts = {}) {
723
+ if (b && b.style !== "none") return `${b.width}pt ${b.style} ${b.color}`;
724
+ if (opts.designMode && opts.showGhostBorder !== false) return GHOST_BORDER_CSS;
725
+ return "none";
726
+ }
727
+ function syncTableElementSize(options) {
728
+ const wMm = (options.tableColWidths ?? []).reduce((s, w) => s + w, 0);
729
+ const hMm = (options.tableRows ?? []).reduce((s, r) => s + r.height, 0);
730
+ options.width = Math.round(wMm * 100) / 100;
731
+ options.height = Math.round(hMm * 100) / 100;
732
+ }
733
+ var MIN_COL_WIDTH_MM = 5;
734
+ function clampResizedColumnWidth(colWidths, index, targetMm, maxTableWidth) {
735
+ const others = colWidths.reduce((s, w, i) => i === index ? s : s + w, 0);
736
+ const cap = maxTableWidth === Infinity ? Infinity : Math.max(MIN_COL_WIDTH_MM, maxTableWidth - others);
737
+ const rounded = Math.round(targetMm * 10) / 10;
738
+ return Math.min(Math.max(rounded, MIN_COL_WIDTH_MM), cap);
739
+ }
740
+
741
+ // src/designer/utils/element-factory.ts
742
+ function generateId() {
743
+ return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
744
+ }
745
+ function createDefaultOptions(type) {
746
+ const base = { left: 7, top: 17.6, width: 42.3, height: 7.1 };
747
+ switch (type) {
748
+ case "text":
749
+ return { ...base, formatter: "\u6587\u672C", fontSize: 12, textAlign: "left", height: 5.3 };
750
+ case "image":
751
+ return { ...base, width: 28.2, height: 28.2, fit: "contain" };
752
+ case "longText":
753
+ return { ...base, width: 141.1, height: 28.2, fontSize: 12, lineHeight: 18 };
754
+ case "table": {
755
+ const { rows, colWidths } = createDefaultTable();
756
+ const totalW = colWidths.reduce((s, w) => s + w, 0);
757
+ const totalH = rows.reduce((s, r) => s + r.height, 0);
758
+ return {
759
+ ...base,
760
+ width: totalW,
761
+ height: totalH,
762
+ // 表格尺寸由列宽/行高(mm)派生,与渲染端一致
763
+ tableMode: "dynamic",
764
+ tableRows: rows,
765
+ tableColWidths: colWidths,
766
+ tableDefaultFontSize: 10,
767
+ tableDefaultColor: "#333333",
768
+ tableDefaultPadding: 1,
769
+ fields: [],
770
+ tablePagination: { enabled: true }
771
+ };
772
+ }
773
+ case "hline":
774
+ return { ...base, width: 70.6, height: 1.8, borderWidth: 0.75 };
775
+ case "vline":
776
+ return { ...base, width: 1.8, height: 35.3, borderWidth: 0.75 };
777
+ case "rect":
778
+ return { ...base, width: 28.2, height: 28.2, borderWidth: 1, borderColor: "#333" };
779
+ case "oval":
780
+ return { ...base, width: 28.2, height: 28.2, borderWidth: 1, borderColor: "#333" };
781
+ case "barcode":
782
+ return { ...base, width: 56.4, height: 14.1, title: "\u6761\u5F62\u7801", barcodeType: "code128", testData: "12345678" };
783
+ case "qrcode":
784
+ return { ...base, width: 28.2, height: 28.2, title: "\u4E8C\u7EF4\u7801", testData: "qrcode" };
785
+ case "html":
786
+ return { ...base, width: 28.2, height: 28.2 };
787
+ default:
788
+ return base;
789
+ }
790
+ }
791
+ function createRuntimeElement(type, options) {
792
+ const typeMetaMap = {
793
+ text: { title: "\u6587\u672C" },
794
+ image: { title: "\u56FE\u7247" },
795
+ longText: { title: "\u957F\u6587" },
796
+ table: { title: "\u8868\u683C" },
797
+ hline: { title: "\u6A2A\u7EBF" },
798
+ vline: { title: "\u7AD6\u7EBF" },
799
+ rect: { title: "\u77E9\u5F62" },
800
+ oval: { title: "\u692D\u5706" },
801
+ barcode: { title: "\u6761\u5F62\u7801" },
802
+ qrcode: { title: "\u4E8C\u7EF4\u7801" },
803
+ html: { title: "HTML" },
804
+ pageNumber: { title: "\u9875\u7801" }
805
+ };
806
+ return {
807
+ id: generateId(),
808
+ options: { ...createDefaultOptions(type), ...options },
809
+ printElementType: { type, title: typeMetaMap[type]?.title || type }
810
+ };
811
+ }
812
+
813
+ // src/designer/utils/zone-layout.ts
814
+ var ZONE_ALLOWED_TYPES = ["text", "image", "hline", "vline", "rect", "oval", "barcode", "qrcode"];
815
+ function getPaperSizeMM(t) {
816
+ return getPaperDimensions(t);
817
+ }
818
+ function getZoneRects(t) {
819
+ const paper = getPaperSizeMM(t);
820
+ const m = t.margins;
821
+ const headerH = t.header.height;
822
+ const footerH = t.footer.height;
823
+ const contentW = paper.width - m.left - m.right;
824
+ const contentH = paper.height - m.top - m.bottom - headerH - footerH;
825
+ const rect = (l, tp, w, h) => ({
826
+ left: l,
827
+ top: tp,
828
+ width: w,
829
+ height: h
830
+ });
831
+ return {
832
+ header: rect(m.left, m.top, contentW, headerH),
833
+ content: rect(m.left, m.top + headerH, contentW, contentH),
834
+ footer: rect(m.left, paper.height - m.bottom - footerH, contentW, footerH)
835
+ };
836
+ }
837
+ function zoneFromPaperPoint(t, _x, y) {
838
+ const r = getZoneRects(t);
839
+ if (r.footer.height > 0 && y >= r.footer.top) return "footer";
840
+ if (r.header.height > 0 && y < r.header.top + r.header.height) return "header";
841
+ return "content";
842
+ }
843
+ function clampToZone(el, zone) {
844
+ const o = el.options;
845
+ o.width = Math.min(o.width, zone.width);
846
+ o.height = Math.min(o.height, zone.height);
847
+ o.left = Math.min(Math.max(0, o.left), zone.width - o.width);
848
+ o.top = Math.min(Math.max(0, o.top), zone.height - o.height);
849
+ }
850
+ function finalizeElementZone(el, t) {
851
+ const rects = getZoneRects(t);
852
+ const fromZone = el.zone || "content";
853
+ const from = rects[fromZone];
854
+ const cx = from.left + el.options.left + el.options.width / 2;
855
+ const cy = from.top + el.options.top + el.options.height / 2;
856
+ let target = zoneFromPaperPoint(t, cx, cy);
857
+ let rejected = false;
858
+ if (target !== "content" && !ZONE_ALLOWED_TYPES.includes(el.printElementType.type)) {
859
+ target = "content";
860
+ rejected = true;
861
+ }
862
+ if (target !== fromZone) {
863
+ const to = rects[target];
864
+ el.options.left = from.left + el.options.left - to.left;
865
+ el.options.top = from.top + el.options.top - to.top;
866
+ el.zone = target;
867
+ }
868
+ if (target !== "content") {
869
+ clampToZone(el, rects[target]);
870
+ } else if (rejected) {
871
+ clampToZone(el, rects.content);
872
+ }
873
+ return { rejected };
874
+ }
875
+
876
+ // src/designer/utils/ruler.ts
877
+ var RULER_THICKNESS = 22;
878
+ var STEP_SEQUENCE = [1, 2, 5, 10, 20, 50, 100, 200, 500, 1e3];
879
+ function chooseMajorStepMM(scale, targetPx = 64) {
880
+ const pxPerMM = scale * (96 / 25.4);
881
+ for (const step of STEP_SEQUENCE) {
882
+ if (step * pxPerMM >= targetPx) return step;
883
+ }
884
+ return STEP_SEQUENCE[STEP_SEQUENCE.length - 1];
885
+ }
886
+ function minorStepMM(majorStepMM) {
887
+ const exp = Math.floor(Math.log10(majorStepMM) + 1e-9);
888
+ const base = majorStepMM / 10 ** exp;
889
+ if (base === 5 || base === 1 && majorStepMM >= 10) return majorStepMM / 5;
890
+ if (base === 2) return majorStepMM / 2;
891
+ return null;
892
+ }
893
+ function roundMM(mm2) {
894
+ return Math.round(mm2 * 1e3) / 1e3;
895
+ }
896
+ function buildRulerTicks(startMM, endMM, majorStepMM) {
897
+ if (endMM < startMM || majorStepMM <= 0) return [];
898
+ const minor = minorStepMM(majorStepMM);
899
+ const fine = minor ?? majorStepMM;
900
+ const first = Math.ceil(startMM / fine - 1e-9) * fine;
901
+ const lastIndex = Math.floor((endMM - first) / fine + 1e-9);
902
+ const ticks = [];
903
+ for (let i = 0; i <= lastIndex; i++) {
904
+ const mm2 = roundMM(first + i * fine);
905
+ const isMajor = Math.abs(mm2 / majorStepMM - Math.round(mm2 / majorStepMM)) < 1e-6;
906
+ if (isMajor) {
907
+ ticks.push({ mm: mm2, major: true, label: String(mm2) });
908
+ } else {
909
+ ticks.push({ mm: mm2, major: false });
910
+ }
911
+ }
912
+ return ticks;
913
+ }
914
+
915
+ // src/designer/utils/preset-colors.ts
916
+ var PRESET_COLORS = [
917
+ "#000000",
918
+ "#333333",
919
+ "#666666",
920
+ "#999999",
921
+ "#cccccc",
922
+ "#ffffff",
923
+ "#e53935",
924
+ "#fb8c00",
925
+ "#1e88e5",
926
+ "#43a047",
927
+ "#8d6e63",
928
+ "#00acc1"
929
+ ];
930
+
931
+ // src/designer/utils/property-search.ts
932
+ var PROPERTY_REGISTRY = [
933
+ {
934
+ group: "position-size",
935
+ groupLabel: "\u4F4D\u7F6E\u4E0E\u5C3A\u5BF8",
936
+ items: [
937
+ { key: "ps-left", keywords: ["X", "\u6A2A\u5750\u6807", "left", "\u4F4D\u7F6E"] },
938
+ { key: "ps-top", keywords: ["Y", "\u7EB5\u5750\u6807", "top", "\u4F4D\u7F6E"] },
939
+ { key: "ps-width", keywords: ["W", "\u5BBD\u5EA6", "width", "\u5C3A\u5BF8"] },
940
+ { key: "ps-height", keywords: ["H", "\u9AD8\u5EA6", "height", "\u5C3A\u5BF8"] }
941
+ ]
942
+ },
943
+ {
944
+ group: "appearance",
945
+ groupLabel: "\u5916\u89C2",
946
+ items: [
947
+ { key: "ap-font-family", keywords: ["\u5B57\u4F53", "\u5B57\u4F53\u540D", "\u5B57\u4F53\u65CF", "fontfamily"] },
948
+ { key: "ap-font-size", keywords: ["\u5B57\u4F53\u5927\u5C0F", "fontsize", "\u5B57\u53F7"] },
949
+ { key: "ap-font-weight", keywords: ["\u5B57\u4F53\u7C97\u7EC6", "\u7C97\u4F53", "bold"] },
950
+ { key: "ap-align", keywords: ["\u5BF9\u9F50", "align"] },
951
+ { key: "ap-vertical-align", keywords: ["\u5782\u76F4\u5BF9\u9F50", "verticalalign", "\u9876\u5BF9\u9F50", "\u5E95\u5BF9\u9F50"] },
952
+ { key: "ap-color", keywords: ["\u989C\u8272", "color"] },
953
+ { key: "ap-bg-color", keywords: ["\u80CC\u666F\u8272", "background"] },
954
+ { key: "ap-line-height", keywords: ["\u884C\u9AD8", "lineheight"] },
955
+ { key: "ap-letter-spacing", keywords: ["\u5B57\u95F4\u8DDD", "letterspacing"] },
956
+ { key: "ap-text-fit", keywords: ["\u6EA2\u51FA", "\u6EA2\u51FA\u663E\u793A", "\u622A\u65AD", "\u81EA\u52A8\u7F29\u5C0F", "\u81EA\u9002\u5E94\u884C\u9AD8", "textfit", "overflow"] },
957
+ { key: "ap-shrink-min", keywords: ["\u6700\u5C0F\u5B57\u53F7", "\u7F29\u653E\u4E0B\u9650", "shrinkminfontsize"] },
958
+ { key: "ap-word-wrap", keywords: ["\u81EA\u52A8\u6362\u884C", "\u4E0D\u6362\u884C", "wordwrap"] }
959
+ ]
960
+ },
961
+ {
962
+ group: "code",
963
+ groupLabel: "\u6761\u7801\u8BBE\u7F6E",
964
+ items: [
965
+ { key: "cd-type", keywords: ["\u7801\u5236", "\u6761\u7801\u7C7B\u578B", "\u6761\u5F62\u7801\u7C7B\u578B", "barcodetype", "code128", "ean13", "code39", "itf14"] },
966
+ { key: "cd-dpi", keywords: ["\u6253\u5370\u673A\u5206\u8FA8\u7387", "dpi", "\u6253\u5370\u70B9", "\u70B9\u9635\u5BF9\u9F50", "203", "300"] },
967
+ { key: "cd-bar-width", keywords: ["\u6761\u5BBD", "\u6761\u7C97\u7EC6", "barwidth", "\u6A21\u5757\u5BBD"] },
968
+ { key: "cd-show-text", keywords: ["\u663E\u793A\u6587\u672C", "\u6761\u7801\u6587\u672C", "\u663E\u793A\u6570\u5B57"] },
969
+ { key: "cd-font-size", keywords: ["\u6761\u7801\u5B57\u53F7", "\u6587\u672C\u5B57\u53F7"] },
970
+ { key: "cd-ec-level", keywords: ["\u7EA0\u9519\u7EA7\u522B", "\u5BB9\u9519", "qrcodelevel"] },
971
+ { key: "cd-fit", keywords: ["\u7F29\u653E\u6A21\u5F0F", "\u62C9\u4F38", "\u7B49\u6BD4", "fit", "contain", "cover"] },
972
+ { key: "cd-max-width", keywords: ["\u6700\u5927\u5BBD\u5EA6", "\u6700\u5927\u5BBD", "maxwidth"] },
973
+ { key: "cd-max-height", keywords: ["\u6700\u5927\u9AD8\u5EA6", "\u6700\u5927\u9AD8", "maxheight"] }
974
+ ]
975
+ },
976
+ {
977
+ group: "content",
978
+ groupLabel: "\u5185\u5BB9",
979
+ items: [
980
+ { key: "ct-title", keywords: ["\u5185\u5BB9", "\u6587\u672C", "title"] },
981
+ { key: "ct-formatter", keywords: ["\u683C\u5F0F\u5316", "\u8868\u8FBE\u5F0F", "formatter"] },
982
+ { key: "ct-table-mode", keywords: ["\u6570\u636E\u6A21\u5F0F", "\u9759\u6001\u5E03\u5C40", "\u52A8\u6001\u6570\u636E"] },
983
+ { key: "ct-table-source", keywords: ["\u6570\u636E\u6E90", "\u5217\u8868\u5B57\u6BB5"] },
984
+ { key: "ct-table-font", keywords: ["\u9ED8\u8BA4\u5B57\u53F7", "\u9ED8\u8BA4\u989C\u8272", "\u9ED8\u8BA4\u5185\u8FB9\u8DDD"] },
985
+ { key: "ct-table-cols", keywords: ["\u5217\u5BBD", "\u8868\u683C\u5217"] }
986
+ ]
987
+ },
988
+ {
989
+ group: "border-bg",
990
+ groupLabel: "\u8FB9\u6846\u4E0E\u80CC\u666F",
991
+ items: [
992
+ { key: "bb-border-width", keywords: ["\u8FB9\u6846\u5BBD\u5EA6", "border"] },
993
+ { key: "bb-border-color", keywords: ["\u8FB9\u6846\u989C\u8272"] },
994
+ { key: "bb-bg-color", keywords: ["\u80CC\u666F\u8272", "background"] }
995
+ ]
996
+ },
997
+ {
998
+ group: "binding",
999
+ groupLabel: "\u5B57\u6BB5\u7ED1\u5B9A",
1000
+ items: [
1001
+ { key: "bd-formatter", keywords: ["\u683C\u5F0F\u5316", "\u8868\u8FBE\u5F0F", "formatter", "fx", "\u5B57\u6BB5", "\u7ED1\u5B9A", "field"] },
1002
+ { key: "bd-content", keywords: ["\u5185\u5BB9", "\u8868\u8FBE\u5F0F", "\u6587\u672C", "\u53D8\u91CF"] }
1003
+ ]
1004
+ },
1005
+ {
1006
+ group: "pagination",
1007
+ groupLabel: "\u5206\u9875",
1008
+ items: [
1009
+ { key: "pg-enabled", keywords: ["\u5206\u9875", "pagination", "\u542F\u7528\u5206\u9875"] },
1010
+ { key: "pg-pageable", keywords: ["\u53C2\u4E0E\u5206\u9875", "pageable"] },
1011
+ { key: "pg-keep-with-next", keywords: ["\u540C\u9875", "keepWithNext"] }
1012
+ ]
1013
+ },
1014
+ {
1015
+ group: "advanced",
1016
+ groupLabel: "\u9AD8\u7EA7",
1017
+ items: [
1018
+ { key: "ad-locked", keywords: ["\u9501\u5B9A", "lock"] },
1019
+ { key: "ad-fixed", keywords: ["\u6BCF\u9875\u91CD\u590D", "repeat"] },
1020
+ { key: "ad-z-index", keywords: ["\u5C42\u7EA7", "zindex"] },
1021
+ { key: "ad-delete", keywords: ["\u5220\u9664"] }
1022
+ ]
1023
+ }
1024
+ ];
1025
+ function matchKeywords(search, keywords) {
1026
+ const s = search.trim().toLowerCase();
1027
+ if (!s) {
1028
+ return true;
1029
+ }
1030
+ return keywords.some((k) => k.toLowerCase().includes(s));
1031
+ }
1032
+ function searchProperties(search) {
1033
+ const groups = [];
1034
+ const itemKeys = /* @__PURE__ */ new Set();
1035
+ for (const g of PROPERTY_REGISTRY) {
1036
+ const matched = g.items.filter((item) => matchKeywords(search, [...item.keywords, g.groupLabel]));
1037
+ if (matched.length > 0) {
1038
+ groups.push(g.group);
1039
+ for (const item of matched) {
1040
+ itemKeys.add(item.key);
1041
+ }
1042
+ }
1043
+ }
1044
+ return { groups, itemKeys };
1045
+ }
1046
+
1047
+ // src/designer/utils/field-groups.ts
1048
+ function groupFields(fields) {
1049
+ const sorted = [...fields].sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
1050
+ const groupMap = /* @__PURE__ */ new Map();
1051
+ const groupOrder = [];
1052
+ for (const f of sorted) {
1053
+ const dot = f.fieldKey.indexOf(".");
1054
+ if (dot === -1) continue;
1055
+ const key = f.fieldKey.slice(0, dot);
1056
+ let g = groupMap.get(key);
1057
+ if (!g) {
1058
+ g = { key, label: key, isList: false, fields: [] };
1059
+ groupMap.set(key, g);
1060
+ groupOrder.push(key);
1061
+ }
1062
+ g.fields.push(f);
1063
+ }
1064
+ const groups = [];
1065
+ const standalone = [];
1066
+ for (const f of sorted) {
1067
+ if (f.fieldKey.includes(".")) continue;
1068
+ const g = groupMap.get(f.fieldKey);
1069
+ if (g) {
1070
+ g.label = f.fieldLabel;
1071
+ g.isList = f.fieldType === "list";
1072
+ } else {
1073
+ standalone.push(f);
1074
+ }
1075
+ }
1076
+ if (standalone.length) groups.push({ key: "", label: "", isList: false, fields: standalone });
1077
+ for (const key of groupOrder) groups.push(groupMap.get(key));
1078
+ return groups;
1079
+ }
1080
+ function filterGroups(groups, keyword) {
1081
+ const kw = keyword.trim().toLowerCase();
1082
+ if (!kw) return groups;
1083
+ return groups.map((g) => ({
1084
+ ...g,
1085
+ fields: g.fields.filter(
1086
+ (f) => f.fieldLabel.toLowerCase().includes(kw) || f.fieldKey.toLowerCase().includes(kw)
1087
+ )
1088
+ })).filter((g) => g.fields.length > 0);
1089
+ }
1090
+
1091
+ // src/designer/utils/binding-registry.ts
1092
+ var ELEMENT_BINDING_REGISTRY = {
1093
+ text: [
1094
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1095
+ ],
1096
+ longText: [
1097
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" },
1098
+ { targetPath: "options.styler", label: "\u6837\u5F0F", dataSource: "main" }
1099
+ ],
1100
+ barcode: [
1101
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1102
+ ],
1103
+ qrcode: [
1104
+ { targetPath: "options.formatter", label: "\u5185\u5BB9", dataSource: "main" }
1105
+ ],
1106
+ image: [
1107
+ { targetPath: "options.src", label: "\u5185\u5BB9", dataSource: "main", placeholder: "\u8F93\u5165\u56FE\u7247\u8DEF\u5F84\uFF0C\u652F\u6301 /docfiles/... \u76F8\u5BF9\u8DEF\u5F84\u3001\u7EDD\u5BF9 URL \u6216 {\u5B57\u6BB5} \u8868\u8FBE\u5F0F" }
1108
+ ],
1109
+ table: []
1110
+ };
1111
+ function getTableCellBindings(rowType, rowIndex, cellIndex, listField) {
1112
+ if (rowType === "data") {
1113
+ return [{
1114
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1115
+ label: "\u5185\u5BB9",
1116
+ dataSource: "list",
1117
+ listField,
1118
+ placeholder: "{name}"
1119
+ }];
1120
+ }
1121
+ if (rowType === "subtotal") {
1122
+ return [{
1123
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1124
+ label: "\u5185\u5BB9",
1125
+ dataSource: "subtotal",
1126
+ placeholder: "{MONEY(SUM(amount))}"
1127
+ }];
1128
+ }
1129
+ if (rowType === "summary") {
1130
+ return [{
1131
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1132
+ label: "\u5185\u5BB9",
1133
+ dataSource: "summary",
1134
+ placeholder: "{MONEY(SUM(amount))}"
1135
+ }];
1136
+ }
1137
+ return [{
1138
+ targetPath: `options.tableRows[${rowIndex}].cells[${cellIndex}].formatter`,
1139
+ label: "\u5185\u5BB9",
1140
+ dataSource: "main",
1141
+ placeholder: "\u5408\u8BA1: {order.total}"
1142
+ }];
1143
+ }
1144
+ function getElementBindings(element) {
1145
+ const type = element.printElementType.type;
1146
+ const staticBindings = ELEMENT_BINDING_REGISTRY[type] ?? [];
1147
+ const dynamicBindings = [];
1148
+ if (type === "table") {
1149
+ const listField = element.options.dataSource;
1150
+ for (const [ri, row] of (element.options.tableRows ?? []).entries()) {
1151
+ for (const [ci, cell] of row.cells.entries()) {
1152
+ if (cell.merged) continue;
1153
+ dynamicBindings.push(...getTableCellBindings(row.type, ri, ci, listField));
1154
+ }
1155
+ }
1156
+ }
1157
+ return [...staticBindings, ...dynamicBindings];
1158
+ }
1159
+
1160
+ // src/designer/utils/demo-data.ts
1161
+ function getDemoData() {
1162
+ return DEFAULT_DEMO_DATA;
1163
+ }
1164
+ var DEFAULT_DEMO_DATA = {
1165
+ supplier: {
1166
+ name: "\u946B\u8FBE\u4E94\u91D1\u6709\u9650\u516C\u53F8",
1167
+ phone: "0571-88776655",
1168
+ address: "\u676D\u5DDE\u5E02\u8427\u5C71\u533A\u7ECF\u6D4E\u5F00\u53D1\u533A88\u53F7"
1169
+ },
1170
+ receiver: {
1171
+ name: "\u674E\u56DB",
1172
+ phone: "13912345678",
1173
+ address: "\u676D\u5DDE\u5E02\u4F59\u676D\u533A\u6587\u4E00\u897F\u8DEF998\u53F7"
1174
+ },
1175
+ order: {
1176
+ no: "PO20260801001",
1177
+ date: "2026-08-01",
1178
+ total: 69543.75
1179
+ },
1180
+ // 50 条商品明细, 用于验证多页分页效果
1181
+ goods: [
1182
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 100, price: 0.5, amount: 50, remark: "A\u7EA7" },
1183
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 117, price: 0.75, amount: 87.75, remark: "" },
1184
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 134, price: 1, amount: 134, remark: "" },
1185
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 151, price: 1.25, amount: 188.75, remark: "" },
1186
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 168, price: 1.5, amount: 252, remark: "" },
1187
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 185, price: 1.75, amount: 323.75, remark: "" },
1188
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 202, price: 2, amount: 404, remark: "" },
1189
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 219, price: 2.25, amount: 492.75, remark: "A\u7EA7" },
1190
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 236, price: 2.5, amount: 590, remark: "" },
1191
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 253, price: 2.75, amount: 695.75, remark: "" },
1192
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD720", unit: "\u4E2A", qty: 270, price: 3, amount: 810, remark: "" },
1193
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD721", unit: "\u5957", qty: 287, price: 3.25, amount: 932.75, remark: "" },
1194
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD722", unit: "\u76D2", qty: 304, price: 3.5, amount: 1064, remark: "" },
1195
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD723", unit: "\u652F", qty: 321, price: 3.75, amount: 1203.75, remark: "" },
1196
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD724", unit: "\u888B", qty: 338, price: 4, amount: 1352, remark: "A\u7EA7" },
1197
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD725", unit: "\u4EF6", qty: 355, price: 4.25, amount: 1508.75, remark: "" },
1198
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD726", unit: "\u6839", qty: 372, price: 4.5, amount: 1674, remark: "" },
1199
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD727", unit: "\u5305", qty: 389, price: 4.75, amount: 1847.75, remark: "" },
1200
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD728", unit: "\u53EA", qty: 406, price: 5, amount: 2030, remark: "" },
1201
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD729", unit: "\u7EC4", qty: 423, price: 5.25, amount: 2220.75, remark: "" },
1202
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD730", unit: "\u4E2A", qty: 440, price: 0.5, amount: 220, remark: "" },
1203
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD731", unit: "\u5957", qty: 457, price: 0.75, amount: 342.75, remark: "A\u7EA7" },
1204
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD732", unit: "\u76D2", qty: 474, price: 1, amount: 474, remark: "" },
1205
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD733", unit: "\u652F", qty: 491, price: 1.25, amount: 613.75, remark: "" },
1206
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD734", unit: "\u888B", qty: 508, price: 1.5, amount: 762, remark: "" },
1207
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD735", unit: "\u4EF6", qty: 525, price: 1.75, amount: 918.75, remark: "" },
1208
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD736", unit: "\u6839", qty: 542, price: 2, amount: 1084, remark: "" },
1209
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD737", unit: "\u5305", qty: 559, price: 2.25, amount: 1257.75, remark: "" },
1210
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD738", unit: "\u53EA", qty: 576, price: 2.5, amount: 1440, remark: "A\u7EA7" },
1211
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD739", unit: "\u7EC4", qty: 593, price: 2.75, amount: 1630.75, remark: "" },
1212
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD740", unit: "\u4E2A", qty: 610, price: 3, amount: 1830, remark: "" },
1213
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD741", unit: "\u5957", qty: 627, price: 3.25, amount: 2037.75, remark: "" },
1214
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD742", unit: "\u76D2", qty: 644, price: 3.5, amount: 2254, remark: "" },
1215
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD743", unit: "\u652F", qty: 661, price: 3.75, amount: 2478.75, remark: "" },
1216
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD744", unit: "\u888B", qty: 678, price: 4, amount: 2712, remark: "" },
1217
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD745", unit: "\u4EF6", qty: 695, price: 4.25, amount: 2953.75, remark: "A\u7EA7" },
1218
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD746", unit: "\u6839", qty: 712, price: 4.5, amount: 3204, remark: "" },
1219
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD747", unit: "\u5305", qty: 729, price: 4.75, amount: 3462.75, remark: "" },
1220
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD748", unit: "\u53EA", qty: 746, price: 5, amount: 3730, remark: "" },
1221
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD749", unit: "\u7EC4", qty: 763, price: 5.25, amount: 4005.75, remark: "" },
1222
+ { name: "\u78B3\u94A2\u87BA\u4E1D M8", spec: "M14\xD710", unit: "\u4E2A", qty: 780, price: 0.5, amount: 390, remark: "" },
1223
+ { name: "\u4E0D\u9508\u94A2\u87BA\u6BCD M10", spec: "M16\xD711", unit: "\u5957", qty: 797, price: 0.75, amount: 597.75, remark: "" },
1224
+ { name: "\u5F39\u7C27\u57AB\u5708 M12", spec: "M6\xD712", unit: "\u76D2", qty: 814, price: 1, amount: 814, remark: "A\u7EA7" },
1225
+ { name: "\u516D\u89D2\u87BA\u6813 M14", spec: "M5\xD713", unit: "\u652F", qty: 831, price: 1.25, amount: 1038.75, remark: "" },
1226
+ { name: "\u5185\u516D\u89D2\u87BA\u9489 M16", spec: "M20\xD714", unit: "\u888B", qty: 848, price: 1.5, amount: 1272, remark: "" },
1227
+ { name: "\u5E73\u57AB\u5708 M6", spec: "M4\xD715", unit: "\u4EF6", qty: 865, price: 1.75, amount: 1513.75, remark: "" },
1228
+ { name: "\u81EA\u653B\u87BA\u9489 M5", spec: "M3\xD716", unit: "\u6839", qty: 882, price: 2, amount: 1764, remark: "" },
1229
+ { name: "\u53CC\u5934\u87BA\u67F1 M20", spec: "M8\xD717", unit: "\u5305", qty: 899, price: 2.25, amount: 2022.75, remark: "" },
1230
+ { name: "\u7D27\u5B9A\u87BA\u9489 M4", spec: "M10\xD718", unit: "\u53EA", qty: 916, price: 2.5, amount: 2290, remark: "" },
1231
+ { name: "\u5341\u5B57\u76D8\u5934\u9489 M3", spec: "M12\xD719", unit: "\u7EC4", qty: 933, price: 2.75, amount: 2565.75, remark: "A\u7EA7" }
1232
+ ]
1233
+ };
1234
+
1235
+ // src/lexer.ts
1236
+ var DANGEROUS_PROPS = /* @__PURE__ */ new Set([
1237
+ "constructor",
1238
+ "__proto__",
1239
+ "prototype",
1240
+ "__defineGetter__",
1241
+ "__defineSetter__",
1242
+ "__lookupGetter__",
1243
+ "__lookupSetter__"
1244
+ ]);
1245
+ var RESERVED_WORDS = /* @__PURE__ */ new Set([
1246
+ "new",
1247
+ "function",
1248
+ "class",
1249
+ "this",
1250
+ "delete",
1251
+ "typeof",
1252
+ "void",
1253
+ "in",
1254
+ "of",
1255
+ "var",
1256
+ "let",
1257
+ "const",
1258
+ "return",
1259
+ "if",
1260
+ "while",
1261
+ "for"
1262
+ ]);
1263
+ function tokenize(input) {
1264
+ const tokens = [];
1265
+ let i = 0;
1266
+ const n = input.length;
1267
+ while (i < n) {
1268
+ const ch = input[i];
1269
+ if (/\s/.test(ch)) {
1270
+ i++;
1271
+ continue;
1272
+ }
1273
+ if (/[0-9]/.test(ch) || ch === "." && i + 1 < n && /[0-9]/.test(input[i + 1])) {
1274
+ let j = i;
1275
+ while (j < n && /[0-9.]/.test(input[j])) j++;
1276
+ tokens.push({ type: "num", value: input.slice(i, j), position: i });
1277
+ i = j;
1278
+ continue;
1279
+ }
1280
+ if (ch === "'" || ch === '"') {
1281
+ let j = i + 1;
1282
+ let s = "";
1283
+ while (j < n && input[j] !== ch) {
1284
+ if (input[j] === "\\" && j + 1 < n) {
1285
+ s += input[j + 1];
1286
+ j += 2;
1287
+ } else {
1288
+ s += input[j];
1289
+ j++;
1290
+ }
1291
+ }
1292
+ if (j >= n) throw new Error("\u5B57\u7B26\u4E32\u672A\u95ED\u5408");
1293
+ tokens.push({ type: "str", value: s, position: i });
1294
+ i = j + 1;
1295
+ continue;
1296
+ }
1297
+ if (/[A-Za-z_$]/.test(ch)) {
1298
+ let j = i;
1299
+ while (j < n && /[A-Za-z0-9_$]/.test(input[j])) j++;
1300
+ const word = input.slice(i, j);
1301
+ if (RESERVED_WORDS.has(word)) {
1302
+ throw new Error(`\u4E0D\u5141\u8BB8\u4F7F\u7528\u5173\u952E\u5B57: ${word}`);
1303
+ }
1304
+ if (DANGEROUS_PROPS.has(word)) {
1305
+ throw new Error(`\u7981\u6B62\u8BBF\u95EE: ${word}`);
1306
+ }
1307
+ if (word === "true" || word === "false") {
1308
+ tokens.push({ type: "bool", value: word, position: i });
1309
+ } else {
1310
+ tokens.push({ type: "ident", value: word, position: i });
1311
+ }
1312
+ i = j;
1313
+ continue;
1314
+ }
1315
+ const three = input.slice(i, i + 3);
1316
+ if (three === "===" || three === "!==") {
1317
+ tokens.push({ type: "punc", value: three, position: i });
1318
+ i += 3;
1319
+ continue;
1320
+ }
1321
+ const two = input.slice(i, i + 2);
1322
+ if (two === "=>") throw new Error("\u4E0D\u5141\u8BB8\u51FD\u6570\u5B9A\u4E49");
1323
+ if (["==", "!=", "<=", ">=", "&&", "||"].includes(two)) {
1324
+ tokens.push({ type: "punc", value: two, position: i });
1325
+ i += 2;
1326
+ continue;
1327
+ }
1328
+ if (ch === "=") throw new Error("\u4E0D\u5141\u8BB8\u8D4B\u503C");
1329
+ if (ch === ";") throw new Error("\u4E0D\u5141\u8BB8\u591A\u6761\u8BED\u53E5");
1330
+ if ("+-*/%()[]{},:.?!<>".includes(ch)) {
1331
+ tokens.push({ type: "punc", value: ch, position: i });
1332
+ i++;
1333
+ continue;
1334
+ }
1335
+ throw new Error(`\u975E\u6CD5\u5B57\u7B26: ${ch}`);
1336
+ }
1337
+ return tokens;
1338
+ }
1339
+
1340
+ // src/parser.ts
1341
+ function parse(tokens) {
1342
+ const parser = new Parser(tokens);
1343
+ return parser.parse();
1344
+ }
1345
+ var Parser = class {
1346
+ constructor(tokens) {
1347
+ this.pos = 0;
1348
+ this.tokens = tokens;
1349
+ }
1350
+ parse() {
1351
+ const node = this.parseTernary();
1352
+ if (this.pos < this.tokens.length) {
1353
+ throw new Error(`\u8868\u8FBE\u5F0F\u5B58\u5728\u591A\u4F59\u5185\u5BB9: ${this.tokens[this.pos].value}`);
1354
+ }
1355
+ return node;
1356
+ }
1357
+ peek() {
1358
+ return this.tokens[this.pos];
1359
+ }
1360
+ next() {
1361
+ const t = this.tokens[this.pos++];
1362
+ if (!t) throw new Error("\u8868\u8FBE\u5F0F\u610F\u5916\u7ED3\u675F");
1363
+ return t;
1364
+ }
1365
+ eatPunc(value) {
1366
+ const t = this.peek();
1367
+ if (t && t.type === "punc" && t.value === value) {
1368
+ this.pos++;
1369
+ return true;
1370
+ }
1371
+ return false;
1372
+ }
1373
+ expectPunc(value) {
1374
+ if (!this.eatPunc(value)) {
1375
+ const pos = this.peek()?.position ?? 0;
1376
+ throw new Error(`\u4F4D\u7F6E ${pos}: \u671F\u671B "${value}"`);
1377
+ }
1378
+ }
1379
+ // 三元运算符 ?: (优先级最低)
1380
+ parseTernary() {
1381
+ const cond = this.parseLogicalOr();
1382
+ if (this.eatPunc("?")) {
1383
+ const consequent = this.parseTernary();
1384
+ this.expectPunc(":");
1385
+ const alternate = this.parseTernary();
1386
+ return { type: "ternary", cond, consequent, alternate };
1387
+ }
1388
+ return cond;
1389
+ }
1390
+ // ||
1391
+ parseLogicalOr() {
1392
+ let left = this.parseLogicalAnd();
1393
+ while (this.eatPunc("||")) {
1394
+ const right = this.parseLogicalAnd();
1395
+ left = { type: "binary", op: "||", left, right };
1396
+ }
1397
+ return left;
1398
+ }
1399
+ // &&
1400
+ parseLogicalAnd() {
1401
+ let left = this.parseEquality();
1402
+ while (this.eatPunc("&&")) {
1403
+ const right = this.parseEquality();
1404
+ left = { type: "binary", op: "&&", left, right };
1405
+ }
1406
+ return left;
1407
+ }
1408
+ // == != === !==
1409
+ parseEquality() {
1410
+ let left = this.parseRelational();
1411
+ for (; ; ) {
1412
+ const t = this.peek();
1413
+ if (t?.type === "punc" && ["==", "!=", "===", "!=="].includes(t.value)) {
1414
+ this.pos++;
1415
+ const right = this.parseRelational();
1416
+ left = { type: "binary", op: t.value, left, right };
1417
+ } else {
1418
+ return left;
1419
+ }
1420
+ }
1421
+ }
1422
+ // < > <= >=
1423
+ parseRelational() {
1424
+ let left = this.parseAdditive();
1425
+ for (; ; ) {
1426
+ const t = this.peek();
1427
+ if (t?.type === "punc" && ["<", ">", "<=", ">="].includes(t.value)) {
1428
+ this.pos++;
1429
+ const right = this.parseAdditive();
1430
+ left = { type: "binary", op: t.value, left, right };
1431
+ } else {
1432
+ return left;
1433
+ }
1434
+ }
1435
+ }
1436
+ // + - (二元)
1437
+ parseAdditive() {
1438
+ let left = this.parseMultiplicative();
1439
+ for (; ; ) {
1440
+ const t = this.peek();
1441
+ if (t?.type === "punc" && (t.value === "+" || t.value === "-")) {
1442
+ this.pos++;
1443
+ const right = this.parseMultiplicative();
1444
+ left = { type: "binary", op: t.value, left, right };
1445
+ } else {
1446
+ return left;
1447
+ }
1448
+ }
1449
+ }
1450
+ // * / %
1451
+ parseMultiplicative() {
1452
+ let left = this.parseUnary();
1453
+ for (; ; ) {
1454
+ const t = this.peek();
1455
+ if (t?.type === "punc" && ["*", "/", "%"].includes(t.value)) {
1456
+ this.pos++;
1457
+ const right = this.parseUnary();
1458
+ left = { type: "binary", op: t.value, left, right };
1459
+ } else {
1460
+ return left;
1461
+ }
1462
+ }
1463
+ }
1464
+ // 一元 ! - +
1465
+ parseUnary() {
1466
+ const t = this.peek();
1467
+ if (t?.type === "punc" && ["!", "-", "+"].includes(t.value)) {
1468
+ this.pos++;
1469
+ const arg = this.parseUnary();
1470
+ return { type: "unary", op: t.value, arg, prefix: true };
1471
+ }
1472
+ return this.parsePostfix();
1473
+ }
1474
+ // 成员访问 x.y, x[i], 函数调用 f()
1475
+ parsePostfix() {
1476
+ let node = this.parsePrimary();
1477
+ for (; ; ) {
1478
+ if (this.eatPunc(".")) {
1479
+ const prop = this.next();
1480
+ if (prop.type !== "ident") {
1481
+ throw new Error(`\u4F4D\u7F6E ${prop.position}: \u6210\u5458\u8BBF\u95EE\u9700\u8981\u5C5E\u6027\u540D`);
1482
+ }
1483
+ node = {
1484
+ type: "member",
1485
+ object: node,
1486
+ property: prop.value,
1487
+ computed: false
1488
+ };
1489
+ } else if (this.eatPunc("[")) {
1490
+ const index = this.parseTernary();
1491
+ this.expectPunc("]");
1492
+ if (index.type === "str") {
1493
+ node = {
1494
+ type: "member",
1495
+ object: node,
1496
+ property: index.value,
1497
+ computed: false
1498
+ };
1499
+ } else {
1500
+ node = {
1501
+ type: "member",
1502
+ object: node,
1503
+ property: index.name ?? String(index.value),
1504
+ computed: true
1505
+ };
1506
+ }
1507
+ } else if (this.peek()?.type === "punc" && this.peek()?.value === "(" && (node.type === "ident" || node.type === "member")) {
1508
+ this.pos++;
1509
+ const args = this.parseArgs();
1510
+ node = { type: "call", callee: node, args };
1511
+ } else {
1512
+ return node;
1513
+ }
1514
+ }
1515
+ }
1516
+ parseArgs() {
1517
+ const args = [];
1518
+ if (this.eatPunc(")")) return args;
1519
+ for (; ; ) {
1520
+ args.push(this.parseTernary());
1521
+ if (this.eatPunc(")")) return args;
1522
+ this.expectPunc(",");
1523
+ }
1524
+ }
1525
+ parsePrimary() {
1526
+ const t = this.next();
1527
+ if (t.type === "num") {
1528
+ const v = Number(t.value);
1529
+ if (isNaN(v)) throw new Error(`\u975E\u6CD5\u6570\u5B57: ${t.value}`);
1530
+ return { type: "num", value: v };
1531
+ }
1532
+ if (t.type === "str") {
1533
+ return { type: "str", value: t.value };
1534
+ }
1535
+ if (t.type === "bool") {
1536
+ return { type: "bool", value: t.value === "true" };
1537
+ }
1538
+ if (t.type === "ident") {
1539
+ return { type: "ident", name: t.value };
1540
+ }
1541
+ if (t.value === "(") {
1542
+ const inner = this.parseTernary();
1543
+ this.expectPunc(")");
1544
+ return inner;
1545
+ }
1546
+ if (t.value === "[") {
1547
+ const elements = [];
1548
+ if (!this.eatPunc("]")) {
1549
+ for (; ; ) {
1550
+ elements.push(this.parseTernary());
1551
+ if (this.eatPunc("]")) break;
1552
+ this.expectPunc(",");
1553
+ }
1554
+ }
1555
+ return { type: "array", elements };
1556
+ }
1557
+ if (t.value === "{") {
1558
+ const properties = [];
1559
+ if (!this.eatPunc("}")) {
1560
+ for (; ; ) {
1561
+ const keyToken = this.next();
1562
+ if (keyToken.type !== "ident" && keyToken.type !== "str") {
1563
+ throw new Error(`\u4F4D\u7F6E ${keyToken.position}: \u5BF9\u8C61\u952E\u5FC5\u987B\u662F\u6807\u8BC6\u7B26\u6216\u5B57\u7B26\u4E32`);
1564
+ }
1565
+ this.expectPunc(":");
1566
+ properties.push({ key: keyToken.value, value: this.parseTernary() });
1567
+ if (this.eatPunc("}")) break;
1568
+ this.expectPunc(",");
1569
+ }
1570
+ }
1571
+ return { type: "object", properties };
1572
+ }
1573
+ throw new Error(`\u4F4D\u7F6E ${t.position}: \u610F\u5916\u7684\u7B26\u53F7: ${t.value}`);
1574
+ }
1575
+ };
1576
+
1577
+ // src/evaluator.ts
1578
+ var SAFE_GLOBALS = {
1579
+ Math,
1580
+ Number,
1581
+ String,
1582
+ Boolean,
1583
+ parseInt,
1584
+ parseFloat,
1585
+ isNaN,
1586
+ true: true,
1587
+ false: false,
1588
+ null: null,
1589
+ undefined: void 0
1590
+ };
1591
+ var DANGEROUS_PROPS2 = /* @__PURE__ */ new Set([
1592
+ "constructor",
1593
+ "__proto__",
1594
+ "prototype",
1595
+ "__defineGetter__",
1596
+ "__defineSetter__",
1597
+ "__lookupGetter__",
1598
+ "__lookupSetter__"
1599
+ ]);
1600
+ var CALLABLE_GLOBALS = /* @__PURE__ */ new Set(["Number", "String", "Boolean", "parseInt", "parseFloat", "isNaN"]);
1601
+ function evaluate(node, context, functions = {}) {
1602
+ switch (node.type) {
1603
+ case "num":
1604
+ return node.value;
1605
+ case "str":
1606
+ return node.value;
1607
+ case "bool":
1608
+ return node.value;
1609
+ case "ident":
1610
+ return evalIdent(node.name, context, functions);
1611
+ case "binary":
1612
+ return evalBinary(node, context, functions);
1613
+ case "unary":
1614
+ return evalUnary(node, context, functions);
1615
+ case "ternary":
1616
+ return evaluate(node.cond, context, functions) ? evaluate(node.consequent, context, functions) : evaluate(node.alternate, context, functions);
1617
+ case "member":
1618
+ return evalMember(node, context, functions);
1619
+ case "call":
1620
+ return evalCall(node, context, functions);
1621
+ case "array":
1622
+ return node.elements.map((e) => evaluate(e, context, functions));
1623
+ case "object":
1624
+ return Object.fromEntries(
1625
+ node.properties.map((p) => [p.key, evaluate(p.value, context, functions)])
1626
+ );
1627
+ }
1628
+ }
1629
+ function evalIdent(name, context, functions) {
1630
+ if (Object.prototype.hasOwnProperty.call(context, name)) {
1631
+ return context[name];
1632
+ }
1633
+ if (Object.prototype.hasOwnProperty.call(SAFE_GLOBALS, name)) {
1634
+ return SAFE_GLOBALS[name];
1635
+ }
1636
+ throw new Error(`\u672A\u5B9A\u4E49\u7684\u6807\u8BC6\u7B26: ${name}`);
1637
+ }
1638
+ function evalBinary(node, context, functions) {
1639
+ const left = evaluate(node.left, context, functions);
1640
+ const right = evaluate(node.right, context, functions);
1641
+ switch (node.op) {
1642
+ case "+":
1643
+ return left + right;
1644
+ case "-":
1645
+ return left - right;
1646
+ case "*":
1647
+ return left * right;
1648
+ case "/":
1649
+ return left / right;
1650
+ case "%":
1651
+ return left % right;
1652
+ case "<":
1653
+ return left < right;
1654
+ case ">":
1655
+ return left > right;
1656
+ case "<=":
1657
+ return left <= right;
1658
+ case ">=":
1659
+ return left >= right;
1660
+ case "==":
1661
+ return left == right;
1662
+ case "!=":
1663
+ return left != right;
1664
+ case "===":
1665
+ return left === right;
1666
+ case "!==":
1667
+ return left !== right;
1668
+ case "&&":
1669
+ return left && right;
1670
+ case "||":
1671
+ return left || right;
1672
+ default:
1673
+ throw new Error(`\u672A\u77E5\u8FD0\u7B97\u7B26: ${node.op}`);
1674
+ }
1675
+ }
1676
+ function evalUnary(node, context, functions) {
1677
+ const arg = evaluate(node.arg, context, functions);
1678
+ switch (node.op) {
1679
+ case "-":
1680
+ return -arg;
1681
+ case "+":
1682
+ return +arg;
1683
+ case "!":
1684
+ return !arg;
1685
+ default:
1686
+ throw new Error(`\u672A\u77E5\u4E00\u5143\u8FD0\u7B97\u7B26: ${node.op}`);
1687
+ }
1688
+ }
1689
+ function evalMember(node, context, functions) {
1690
+ const obj = evaluate(node.object, context, functions);
1691
+ if (obj == null) {
1692
+ throw new Error("\u65E0\u6CD5\u8BBF\u95EE\u7A7A\u503C\u7684\u5C5E\u6027");
1693
+ }
1694
+ if (DANGEROUS_PROPS2.has(node.property)) {
1695
+ throw new Error(`\u7981\u6B62\u8BBF\u95EE\u5C5E\u6027: ${node.property}`);
1696
+ }
1697
+ return obj[node.property];
1698
+ }
1699
+ function evalCall(node, context, functions) {
1700
+ if (node.callee.type === "ident" && CALLABLE_GLOBALS.has(node.callee.name)) {
1701
+ const fn = SAFE_GLOBALS[node.callee.name];
1702
+ const args = node.args.map((a) => evaluate(a, context, functions));
1703
+ return fn(...args);
1704
+ }
1705
+ if (node.callee.type === "member" && node.callee.object.type === "ident" && node.callee.object.name === "Math") {
1706
+ const method = Math[node.callee.property];
1707
+ if (typeof method !== "function") {
1708
+ throw new Error(`Math.${node.callee.property} \u4E0D\u662F\u65B9\u6CD5`);
1709
+ }
1710
+ const args = node.args.map((a) => evaluate(a, context, functions));
1711
+ return method(...args);
1712
+ }
1713
+ let fnName;
1714
+ if (node.callee.type === "ident") {
1715
+ fnName = node.callee.name;
1716
+ } else if (node.callee.type === "member") {
1717
+ throw new Error("\u4E0D\u652F\u6301\u65B9\u6CD5\u8C03\u7528\uFF0C\u8BF7\u4F7F\u7528\u9876\u7EA7\u51FD\u6570");
1718
+ }
1719
+ if (fnName && functions[fnName]) {
1720
+ const args = node.args.map((a) => evaluate(a, context, functions));
1721
+ return functions[fnName](...args);
1722
+ }
1723
+ if (fnName && Object.prototype.hasOwnProperty.call(context, fnName)) {
1724
+ throw new Error(`${fnName} \u4E0D\u662F\u51FD\u6570`);
1725
+ }
1726
+ throw new Error(`\u4E0D\u5141\u8BB8\u8C03\u7528: ${fnName ?? "\u8868\u8FBE\u5F0F"}`);
1727
+ }
1728
+
1729
+ // src/template-parser.ts
1730
+ function parseTemplate(template) {
1731
+ const parts = [];
1732
+ let i = 0;
1733
+ const n = template.length;
1734
+ while (i < n) {
1735
+ if (template[i] === "{") {
1736
+ let depth = 1;
1737
+ let j2 = i + 1;
1738
+ while (j2 < n && depth > 0) {
1739
+ if (template[j2] === "{") depth++;
1740
+ else if (template[j2] === "}") depth--;
1741
+ j2++;
1742
+ }
1743
+ if (depth !== 0) {
1744
+ throw new Error(`\u4F4D\u7F6E ${i}: \u82B1\u62EC\u53F7\u672A\u95ED\u5408`);
1745
+ }
1746
+ const exprStr = template.slice(i + 1, j2 - 1);
1747
+ if (exprStr.trim() === "") {
1748
+ throw new Error(`\u4F4D\u7F6E ${i}: \u7A7A\u8868\u8FBE\u5F0F`);
1749
+ }
1750
+ const tokens = tokenize(exprStr);
1751
+ const expression = parse(tokens);
1752
+ parts.push({ type: "expr", expression });
1753
+ i = j2;
1754
+ continue;
1755
+ }
1756
+ let j = i;
1757
+ while (j < n && template[j] !== "{") {
1758
+ if (template[j] === "\\" && j + 1 < n && (template[j + 1] === "{" || template[j + 1] === "}")) {
1759
+ j += 2;
1760
+ } else {
1761
+ j++;
1762
+ }
1763
+ }
1764
+ parts.push({ type: "text", value: template.slice(i, j).replace(/\\([{}])/g, "$1") });
1765
+ i = j;
1766
+ }
1767
+ return { type: "template", parts };
1768
+ }
1769
+ function renderTemplate(ast, context, functions = {}) {
1770
+ let result = "";
1771
+ for (const part of ast.parts) {
1772
+ if (part.type === "text") {
1773
+ result += part.value;
1774
+ } else {
1775
+ const value = evaluate(part.expression, context, functions);
1776
+ result += String(value ?? "");
1777
+ }
1778
+ }
1779
+ return result;
1780
+ }
1781
+ function compileTemplate(template, functions = {}) {
1782
+ const ast = parseTemplate(template);
1783
+ return (context) => renderTemplate(ast, context, functions);
1784
+ }
1785
+
1786
+ // src/utils.ts
1787
+ function getByPath(obj, path) {
1788
+ if (obj == null || path == null) return void 0;
1789
+ if (typeof obj === "object" && path in obj) return obj[path];
1790
+ const parts = path.split(".");
1791
+ let cur = obj;
1792
+ for (const p of parts) {
1793
+ if (cur == null) return void 0;
1794
+ cur = cur[p];
1795
+ }
1796
+ return cur;
1797
+ }
1798
+
1799
+ // src/functions/format.ts
1800
+ function formatMoney(value) {
1801
+ const num = Number(value);
1802
+ if (isNaN(num)) return String(value);
1803
+ const sign = num < 0 ? "-" : "";
1804
+ const abs = Math.abs(num);
1805
+ const [intPart, decPart] = abs.toFixed(2).split(".");
1806
+ const formatted = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1807
+ return `${sign}${formatted}.${decPart}`;
1808
+ }
1809
+ function formatDate(value, fmt) {
1810
+ let date;
1811
+ if (value instanceof Date) {
1812
+ date = value;
1813
+ } else if (typeof value === "number") {
1814
+ date = new Date(value);
1815
+ } else if (typeof value === "string") {
1816
+ date = new Date(value);
1817
+ } else {
1818
+ return String(value);
1819
+ }
1820
+ if (isNaN(date.getTime())) return String(value);
1821
+ const pad = (n) => String(n).padStart(2, "0");
1822
+ return fmt.replace("YYYY", String(date.getFullYear())).replace("MM", pad(date.getMonth() + 1)).replace("DD", pad(date.getDate())).replace("HH", pad(date.getHours())).replace("mm", pad(date.getMinutes())).replace("ss", pad(date.getSeconds()));
1823
+ }
1824
+ function toUpperCaseAmount(value) {
1825
+ const num = Number(value);
1826
+ if (isNaN(num)) return String(value);
1827
+ if (num === 0) return "\u96F6\u5143\u6574";
1828
+ const digits = ["\u96F6", "\u58F9", "\u8D30", "\u53C1", "\u8086", "\u4F0D", "\u9646", "\u67D2", "\u634C", "\u7396"];
1829
+ const units = ["", "\u62FE", "\u4F70", "\u4EDF"];
1830
+ const bigUnits = ["", "\u4E07", "\u4EBF"];
1831
+ const sign = num < 0 ? "\u8D1F" : "";
1832
+ const abs = Math.abs(num);
1833
+ const [intStr, decStr] = abs.toFixed(2).split(".");
1834
+ const intNum = parseInt(intStr, 10);
1835
+ let result = "";
1836
+ if (intNum > 0) {
1837
+ const intChars = intStr.split("").reverse();
1838
+ let groupIdx = 0;
1839
+ let lastDigit = 0;
1840
+ let needZero = false;
1841
+ for (let i = 0; i < intChars.length; i++) {
1842
+ const d = parseInt(intChars[i], 10);
1843
+ const unit = units[groupIdx % 4];
1844
+ const bigUnit = bigUnits[Math.floor(groupIdx / 4)];
1845
+ if (d === 0) {
1846
+ if (lastDigit !== 0) needZero = true;
1847
+ } else {
1848
+ if (needZero) {
1849
+ result = "\u96F6" + result;
1850
+ needZero = false;
1851
+ }
1852
+ result = digits[d] + unit + result;
1853
+ lastDigit = d;
1854
+ }
1855
+ if (groupIdx % 4 === 3 && groupIdx > 0) {
1856
+ result = bigUnit + result;
1857
+ }
1858
+ groupIdx++;
1859
+ }
1860
+ result += "\u5143";
1861
+ }
1862
+ const jiao = parseInt(decStr[0], 10);
1863
+ const fen = parseInt(decStr[1], 10);
1864
+ if (jiao === 0 && fen === 0) {
1865
+ result += "\u6574";
1866
+ } else {
1867
+ if (jiao > 0) {
1868
+ result += digits[jiao] + "\u89D2";
1869
+ }
1870
+ if (fen > 0) {
1871
+ result += digits[fen] + "\u5206";
1872
+ }
1873
+ }
1874
+ return sign + result;
1875
+ }
1876
+ function ifFn(condition, trueVal, falseVal) {
1877
+ return condition ? trueVal : falseVal;
1878
+ }
1879
+
1880
+ // src/functions/aggregate.ts
1881
+ function sum(rows, field) {
1882
+ return rows.reduce((acc, row) => acc + (Number(getByPath(row, field)) || 0), 0);
1883
+ }
1884
+ function avg(rows, field) {
1885
+ if (rows.length === 0) return 0;
1886
+ return sum(rows, field) / rows.length;
1887
+ }
1888
+ function count(rows, field) {
1889
+ return rows.length;
1890
+ }
1891
+ function min(rows, field) {
1892
+ if (rows.length === 0) return 0;
1893
+ return Math.min(...rows.map((row) => Number(getByPath(row, field)) || 0));
1894
+ }
1895
+ function max(rows, field) {
1896
+ if (rows.length === 0) return 0;
1897
+ return Math.max(...rows.map((row) => Number(getByPath(row, field)) || 0));
1898
+ }
1899
+
1900
+ // src/render/expression-eval.ts
1901
+ var RenderEngine = class {
1902
+ constructor() {
1903
+ this.functions = {};
1904
+ }
1905
+ registerFunction(name, fn) {
1906
+ this.functions[name] = fn;
1907
+ }
1908
+ evaluate(expression, context) {
1909
+ const tokens = tokenize(expression);
1910
+ const ast = parse(tokens);
1911
+ return evaluate(ast, context, this.functions);
1912
+ }
1913
+ render(template, context) {
1914
+ return compileTemplate(template, this.functions)(context);
1915
+ }
1916
+ };
1917
+ var engine = new RenderEngine();
1918
+ var FORMAT_FUNCTIONS = {
1919
+ MONEY: formatMoney,
1920
+ DATE: formatDate,
1921
+ UPPER: toUpperCaseAmount,
1922
+ IF: ifFn,
1923
+ CONCAT: (...args) => args.filter((v) => v != null).map(String).join(""),
1924
+ IFEMPTY: (v, d) => v != null && v !== "" ? String(v) : d,
1925
+ ROUND: (n, d) => Number(Number(n).toFixed(d)),
1926
+ LEN: (s) => String(s).length
1927
+ };
1928
+ for (const [name, fn] of Object.entries(FORMAT_FUNCTIONS)) {
1929
+ engine.registerFunction(name, fn);
1930
+ }
1931
+
1932
+ // src/render/watermark.ts
1933
+ var PX_PER_MM = 96 / 25.4;
1934
+ var MM_PER_PX = 25.4 / 96;
1935
+
1936
+ // src/index.ts
1937
+ var TemplateEngine = class {
1938
+ constructor(options) {
1939
+ this.functions = {};
1940
+ if (options?.functions) {
1941
+ this.functions = { ...options.functions };
1942
+ }
1943
+ }
1944
+ registerFunction(name, fn) {
1945
+ this.functions[name] = fn;
1946
+ }
1947
+ evaluate(expression, context) {
1948
+ const tokens = tokenize(expression);
1949
+ const ast = parse(tokens);
1950
+ return evaluate(ast, context, this.functions);
1951
+ }
1952
+ render(template, context) {
1953
+ return compileTemplate(template, this.functions)(context);
1954
+ }
1955
+ };
1956
+
1957
+ // src/designer/utils/engine.ts
1958
+ var engine2 = new TemplateEngine();
1959
+
1960
+ // src/designer/utils/expression-eval.ts
1961
+ var EXTENDED_FUNCTIONS = {
1962
+ MONEY: formatMoney,
1963
+ CONCAT: (...args) => args.filter((v) => v != null).join(""),
1964
+ IF: ifFn,
1965
+ FORMAT: (value) => {
1966
+ if (typeof value !== "number") return String(value);
1967
+ return value.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1968
+ },
1969
+ SUBSTR: (str, start, len) => String(str).slice(start, len ? start + len : void 0),
1970
+ LEN: (str) => String(str).length,
1971
+ ROUND: (num, decimals) => Number(Number(num).toFixed(decimals)),
1972
+ NOW: () => (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
1973
+ IFEMPTY: (value, defaultVal) => value != null && value !== "" ? String(value) : defaultVal,
1974
+ PAD: (value, len, char) => String(value).padStart(len, char),
1975
+ REPLACE: (str, from, to) => String(str).replace(new RegExp(from, "g"), to),
1976
+ JSON: (value) => JSON.stringify(value, null, 2),
1977
+ DATE: formatDate,
1978
+ UPPER: toUpperCaseAmount
1979
+ };
1980
+ for (const [name, fn] of Object.entries(EXTENDED_FUNCTIONS)) {
1981
+ engine2.registerFunction(name, fn);
1982
+ }
1983
+ function aggregate(fn, field, rows) {
1984
+ switch (fn.toUpperCase()) {
1985
+ case "SUM":
1986
+ return sum(rows, field);
1987
+ case "AVG":
1988
+ return avg(rows, field);
1989
+ case "COUNT":
1990
+ return count(rows, field);
1991
+ case "MIN":
1992
+ return min(rows, field);
1993
+ case "MAX":
1994
+ return max(rows, field);
1995
+ default:
1996
+ return 0;
1997
+ }
1998
+ }
1999
+ function safeEval2(expr, context, _callableNames) {
2000
+ return engine2.evaluate(expr, context);
2001
+ }
2002
+ function evaluateTemplate2(text, ctx) {
2003
+ if (!text) return "";
2004
+ if (!text.includes("{")) return text;
2005
+ const rows = Array.isArray(ctx.rows) ? ctx.rows : [];
2006
+ let processedText = text.replace(/\{([^}]+)\}/g, (_match, inner) => {
2007
+ let expr = inner.trim();
2008
+ expr = expr.replace(/\b(SUM|AVG|COUNT|MIN|MAX)\(([^)]+)\)/g, (_m, fn, arg) => {
2009
+ const field = arg.trim().replace(/^['"]|['"]$/g, "");
2010
+ return String(aggregate(fn, field, rows));
2011
+ });
2012
+ return `{${expr}}`;
2013
+ });
2014
+ try {
2015
+ const result = engine2.render(processedText, ctx);
2016
+ return result;
2017
+ } catch {
2018
+ return text;
2019
+ }
2020
+ }
2021
+
2022
+ // src/designer/utils/binding.ts
2023
+ function createFieldElement(field) {
2024
+ return createRuntimeElement("text", {
2025
+ formatter: `{${field.fieldKey}}`,
2026
+ title: field.fieldLabel
2027
+ });
2028
+ }
2029
+ function resolveTextBinding(options, data) {
2030
+ if (options.formatter) {
2031
+ if (!data || data.length === 0) return "";
2032
+ const row = data[0];
2033
+ try {
2034
+ return engine2.render(options.formatter, row ?? {});
2035
+ } catch {
2036
+ return options.formatter;
2037
+ }
2038
+ }
2039
+ return "";
2040
+ }
2041
+ function lookupDemoPath(path) {
2042
+ let cur = DEFAULT_DEMO_DATA;
2043
+ for (const seg of path.split(".")) {
2044
+ if (cur == null) return void 0;
2045
+ cur = Array.isArray(cur) ? cur[0]?.[seg] : cur[seg];
2046
+ }
2047
+ return cur;
2048
+ }
2049
+ function resolveBarcodeDesignValue(formatter, listSource) {
2050
+ const first = listSource?.[0];
2051
+ const resolved = (formatter ?? "").replace(/\{([^{}]+)\}/g, (_, expr) => {
2052
+ const key = expr.trim();
2053
+ const v = key.includes(".") ? lookupDemoPath(key) : first?.[key] ?? lookupDemoPath(key);
2054
+ return v == null ? "" : String(v);
2055
+ }).trim();
2056
+ return resolved || "1234567890128";
2057
+ }
2058
+
2059
+ // src/designer/interactions/adsorb.ts
2060
+ var SNAP_COLORS = {
2061
+ left: "#3b82f6",
2062
+ center: "#10b981",
2063
+ right: "#f59e0b",
2064
+ top: "#3b82f6",
2065
+ middle: "#10b981",
2066
+ bottom: "#f59e0b"
2067
+ };
2068
+ function snapColor(mk) {
2069
+ if (mk === "vCenter") return SNAP_COLORS.center;
2070
+ if (mk === "hCenter") return SNAP_COLORS.middle;
2071
+ return SNAP_COLORS[mk] ?? SNAP_COLORS.left;
2072
+ }
2073
+ function computeAdsorb(movingRect, others, manualGuides, config = {}) {
2074
+ const adsorbMin = config.adsorbMin ?? 1;
2075
+ const adsorbLineMin = config.adsorbLineMin ?? 2;
2076
+ const showAdsorbLine = config.showAdsorbLine ?? true;
2077
+ let left = movingRect.left;
2078
+ let top = movingRect.top;
2079
+ const lines = [];
2080
+ const m = {
2081
+ left: movingRect.left,
2082
+ right: movingRect.left + movingRect.width,
2083
+ vCenter: movingRect.left + movingRect.width / 2,
2084
+ top: movingRect.top,
2085
+ bottom: movingRect.top + movingRect.height,
2086
+ hCenter: movingRect.top + movingRect.height / 2
2087
+ };
2088
+ let minDist = Infinity;
2089
+ for (const other of others) {
2090
+ if (other.id === movingRect.id) continue;
2091
+ const o = {
2092
+ left: other.left,
2093
+ right: other.left + other.width,
2094
+ vCenter: other.left + other.width / 2,
2095
+ top: other.top,
2096
+ bottom: other.top + other.height,
2097
+ hCenter: other.top + other.height / 2
2098
+ };
2099
+ const hPairs = [
2100
+ ["left", "left"],
2101
+ ["left", "vCenter"],
2102
+ ["left", "right"],
2103
+ ["vCenter", "left"],
2104
+ ["vCenter", "vCenter"],
2105
+ ["vCenter", "right"],
2106
+ ["right", "left"],
2107
+ ["right", "vCenter"],
2108
+ ["right", "right"]
2109
+ ];
2110
+ const vPairs = [
2111
+ ["top", "top"],
2112
+ ["top", "hCenter"],
2113
+ ["top", "bottom"],
2114
+ ["hCenter", "top"],
2115
+ ["hCenter", "hCenter"],
2116
+ ["hCenter", "bottom"],
2117
+ ["bottom", "top"],
2118
+ ["bottom", "hCenter"],
2119
+ ["bottom", "bottom"]
2120
+ ];
2121
+ for (const [mk, ok] of hPairs) {
2122
+ const dist = Math.abs(m[mk] - o[ok]);
2123
+ if (dist <= adsorbMin && dist < minDist) {
2124
+ minDist = dist;
2125
+ left = movingRect.left + (o[ok] - m[mk]);
2126
+ }
2127
+ }
2128
+ for (const [mk, ok] of vPairs) {
2129
+ const dist = Math.abs(m[mk] - o[ok]);
2130
+ if (dist <= adsorbMin && dist < minDist) {
2131
+ minDist = dist;
2132
+ top = movingRect.top + (o[ok] - m[mk]);
2133
+ }
2134
+ }
2135
+ }
2136
+ if (manualGuides) {
2137
+ const m2 = {
2138
+ left,
2139
+ right: left + movingRect.width,
2140
+ vCenter: left + movingRect.width / 2,
2141
+ top,
2142
+ bottom: top + movingRect.height,
2143
+ hCenter: top + movingRect.height / 2
2144
+ };
2145
+ const hKeys = ["left", "vCenter", "right"];
2146
+ for (const pos of manualGuides.vertical) {
2147
+ for (const k of hKeys) {
2148
+ const d = Math.abs(m2[k] - pos);
2149
+ if (d <= adsorbMin && d < minDist) {
2150
+ minDist = d;
2151
+ left = movingRect.left + (pos - m2[k]);
2152
+ }
2153
+ }
2154
+ }
2155
+ const vKeys = ["top", "hCenter", "bottom"];
2156
+ for (const pos of manualGuides.horizontal) {
2157
+ for (const k of vKeys) {
2158
+ const d = Math.abs(m2[k] - pos);
2159
+ if (d <= adsorbMin && d < minDist) {
2160
+ minDist = d;
2161
+ top = movingRect.top + (pos - m2[k]);
2162
+ }
2163
+ }
2164
+ }
2165
+ }
2166
+ const adjustedM = {
2167
+ left,
2168
+ right: left + movingRect.width,
2169
+ vCenter: left + movingRect.width / 2,
2170
+ top,
2171
+ bottom: top + movingRect.height,
2172
+ hCenter: top + movingRect.height / 2
2173
+ };
2174
+ if (showAdsorbLine) {
2175
+ const seen = /* @__PURE__ */ new Set();
2176
+ for (const other of others) {
2177
+ if (other.id === movingRect.id) continue;
2178
+ const o = {
2179
+ left: other.left,
2180
+ right: other.left + other.width,
2181
+ vCenter: other.left + other.width / 2,
2182
+ top: other.top,
2183
+ bottom: other.top + other.height,
2184
+ hCenter: other.top + other.height / 2
2185
+ };
2186
+ const hPairs = [
2187
+ ["left", "left"],
2188
+ ["left", "vCenter"],
2189
+ ["left", "right"],
2190
+ ["vCenter", "left"],
2191
+ ["vCenter", "vCenter"],
2192
+ ["vCenter", "right"],
2193
+ ["right", "left"],
2194
+ ["right", "vCenter"],
2195
+ ["right", "right"]
2196
+ ];
2197
+ const vPairs = [
2198
+ ["top", "top"],
2199
+ ["top", "hCenter"],
2200
+ ["top", "bottom"],
2201
+ ["hCenter", "top"],
2202
+ ["hCenter", "hCenter"],
2203
+ ["hCenter", "bottom"],
2204
+ ["bottom", "top"],
2205
+ ["bottom", "hCenter"],
2206
+ ["bottom", "bottom"]
2207
+ ];
2208
+ for (const [mk, ok] of hPairs) {
2209
+ const dist = Math.abs(adjustedM[mk] - o[ok]);
2210
+ if (dist <= adsorbLineMin) {
2211
+ const key = `v:${o[ok]}`;
2212
+ if (!seen.has(key)) {
2213
+ seen.add(key);
2214
+ lines.push({ type: "vertical", position: o[ok], id: other.id, color: snapColor(mk) });
2215
+ }
2216
+ }
2217
+ }
2218
+ for (const [mk, ok] of vPairs) {
2219
+ const dist = Math.abs(adjustedM[mk] - o[ok]);
2220
+ if (dist <= adsorbLineMin) {
2221
+ const key = `h:${o[ok]}`;
2222
+ if (!seen.has(key)) {
2223
+ seen.add(key);
2224
+ lines.push({ type: "horizontal", position: o[ok], id: other.id, color: snapColor(mk) });
2225
+ }
2226
+ }
2227
+ }
2228
+ }
2229
+ }
2230
+ if (manualGuides) {
2231
+ for (const pos of manualGuides.vertical) {
2232
+ if (!lines.some((l) => l.type === "vertical" && l.position === pos)) {
2233
+ lines.push({ type: "vertical", position: pos });
2234
+ }
2235
+ }
2236
+ for (const pos of manualGuides.horizontal) {
2237
+ if (!lines.some((l) => l.type === "horizontal" && l.position === pos)) {
2238
+ lines.push({ type: "horizontal", position: pos });
2239
+ }
2240
+ }
2241
+ }
2242
+ return { left, top, lines };
2243
+ }
2244
+
2245
+ // src/designer/interactions/useAlign.ts
2246
+ function useAlign() {
2247
+ function align(elements, mode) {
2248
+ if (elements.length < 2) return;
2249
+ const bounds = {
2250
+ minLeft: Math.min(...elements.map((e) => e.options.left)),
2251
+ maxRight: Math.max(...elements.map((e) => e.options.left + e.options.width)),
2252
+ minTop: Math.min(...elements.map((e) => e.options.top)),
2253
+ maxBottom: Math.max(...elements.map((e) => e.options.top + e.options.height))
2254
+ };
2255
+ switch (mode) {
2256
+ case "left":
2257
+ elements.forEach((e) => {
2258
+ e.options.left = bounds.minLeft;
2259
+ });
2260
+ break;
2261
+ case "right":
2262
+ elements.forEach((e) => {
2263
+ e.options.left = bounds.maxRight - e.options.width;
2264
+ });
2265
+ break;
2266
+ case "top":
2267
+ elements.forEach((e) => {
2268
+ e.options.top = bounds.minTop;
2269
+ });
2270
+ break;
2271
+ case "bottom":
2272
+ elements.forEach((e) => {
2273
+ e.options.top = bounds.maxBottom - e.options.height;
2274
+ });
2275
+ break;
2276
+ case "vertical": {
2277
+ const centerX = bounds.minLeft + (bounds.maxRight - bounds.minLeft) / 2;
2278
+ elements.forEach((e) => {
2279
+ e.options.left = centerX - e.options.width / 2;
2280
+ });
2281
+ break;
2282
+ }
2283
+ case "horizontal": {
2284
+ const centerY = bounds.minTop + (bounds.maxBottom - bounds.minTop) / 2;
2285
+ elements.forEach((e) => {
2286
+ e.options.top = centerY - e.options.height / 2;
2287
+ });
2288
+ break;
2289
+ }
2290
+ case "distributeHor": {
2291
+ const sorted = [...elements].sort((a, b) => a.options.left - b.options.left);
2292
+ const totalW = sorted.reduce((s, e) => s + e.options.width, 0);
2293
+ const gap = (bounds.maxRight - bounds.minLeft - totalW) / (sorted.length - 1);
2294
+ let x = bounds.minLeft;
2295
+ sorted.forEach((e) => {
2296
+ e.options.left = x;
2297
+ x += e.options.width + gap;
2298
+ });
2299
+ break;
2300
+ }
2301
+ case "distributeVer": {
2302
+ const sorted = [...elements].sort((a, b) => a.options.top - b.options.top);
2303
+ const totalH = sorted.reduce((s, e) => s + e.options.height, 0);
2304
+ const gap = (bounds.maxBottom - bounds.minTop - totalH) / (sorted.length - 1);
2305
+ let y = bounds.minTop;
2306
+ sorted.forEach((e) => {
2307
+ e.options.top = y;
2308
+ y += e.options.height + gap;
2309
+ });
2310
+ break;
2311
+ }
2312
+ }
2313
+ }
2314
+ return { align };
2315
+ }
2316
+
2317
+ // src/designer/interactions/useGroup.ts
2318
+ function generateGroupId() {
2319
+ return `grp-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
2320
+ }
2321
+ function useGroup() {
2322
+ function group(elements, selectedIds) {
2323
+ const selected = elements.filter((e) => selectedIds.has(e.id));
2324
+ if (selected.length < 2) return elements;
2325
+ const groupId = generateGroupId();
2326
+ return elements.map(
2327
+ (e) => selectedIds.has(e.id) ? { ...e, options: { ...e.options, groupId } } : e
2328
+ );
2329
+ }
2330
+ function ungroup(elements, selectedIds) {
2331
+ const selected = elements.filter((e) => selectedIds.has(e.id));
2332
+ const groupIds = new Set(selected.map((e) => e.options.groupId).filter(Boolean));
2333
+ return elements.map(
2334
+ (e) => e.options.groupId && groupIds.has(e.options.groupId) ? { ...e, options: { ...e.options, groupId: void 0 } } : e
2335
+ );
2336
+ }
2337
+ function getGroupedIds(elements, selectedId) {
2338
+ const el = elements.find((e) => e.id === selectedId);
2339
+ if (!el?.options.groupId) return /* @__PURE__ */ new Set([selectedId]);
2340
+ const ids = /* @__PURE__ */ new Set();
2341
+ for (const e of elements) {
2342
+ if (e.options.groupId === el.options.groupId) {
2343
+ ids.add(e.id);
2344
+ }
2345
+ }
2346
+ return ids;
2347
+ }
2348
+ return { group, ungroup, getGroupedIds };
2349
+ }
2350
+
2351
+ // src/designer/interactions/useKeyboard.ts
2352
+ var STEP = 1;
2353
+ var STEP_LARGE = 10;
2354
+ var STEP_SMALL = 0.5;
2355
+ function useKeyboard(handlers) {
2356
+ function onKeyDown(e) {
2357
+ const tag = e.target.tagName;
2358
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
2359
+ const ctrl = e.ctrlKey || e.metaKey;
2360
+ if (e.key.startsWith("Arrow")) {
2361
+ e.preventDefault();
2362
+ const step = e.shiftKey ? STEP_LARGE : e.ctrlKey ? STEP_SMALL : STEP;
2363
+ const dx = e.key === "ArrowLeft" ? -step : e.key === "ArrowRight" ? step : 0;
2364
+ const dy = e.key === "ArrowUp" ? -step : e.key === "ArrowDown" ? step : 0;
2365
+ handlers.onMove?.(dx, dy);
2366
+ return;
2367
+ }
2368
+ if (e.key === "Delete" || e.key === "Backspace") {
2369
+ e.preventDefault();
2370
+ handlers.onDelete?.();
2371
+ return;
2372
+ }
2373
+ if (ctrl) {
2374
+ const k = e.key.toLowerCase();
2375
+ if (k === "c") {
2376
+ e.preventDefault();
2377
+ handlers.onCopy?.();
2378
+ } else if (k === "v") {
2379
+ e.preventDefault();
2380
+ handlers.onPaste?.();
2381
+ } else if (k === "a") {
2382
+ e.preventDefault();
2383
+ handlers.onSelectAll?.();
2384
+ } else if (k === "d") {
2385
+ e.preventDefault();
2386
+ handlers.onDuplicate?.();
2387
+ } else if (k === "z") {
2388
+ e.preventDefault();
2389
+ e.shiftKey ? handlers.onRedo?.() : handlers.onUndo?.();
2390
+ } else if (k === "y") {
2391
+ e.preventDefault();
2392
+ handlers.onRedo?.();
2393
+ } else if (k === "1") {
2394
+ e.preventDefault();
2395
+ handlers.onResetZoom?.();
2396
+ } else if (k === "l") {
2397
+ e.preventDefault();
2398
+ handlers.onAlignLeft?.();
2399
+ } else if (k === "r") {
2400
+ e.preventDefault();
2401
+ handlers.onAlignRight?.();
2402
+ } else if (k === "e") {
2403
+ e.preventDefault();
2404
+ handlers.onAlignCenterH?.();
2405
+ } else if (k === "t") {
2406
+ e.preventDefault();
2407
+ handlers.onAlignTop?.();
2408
+ } else if (k === "b") {
2409
+ e.preventDefault();
2410
+ handlers.onAlignBottom?.();
2411
+ } else if (k === "g") {
2412
+ e.preventDefault();
2413
+ e.shiftKey ? handlers.onUngroup?.() : handlers.onGroup?.();
2414
+ }
2415
+ }
2416
+ }
2417
+ function setup() {
2418
+ document.addEventListener("keydown", onKeyDown);
2419
+ }
2420
+ function cleanup() {
2421
+ document.removeEventListener("keydown", onKeyDown);
2422
+ }
2423
+ return { setup, cleanup };
2424
+ }
2425
+
2426
+ // src/designer/interactions/useResize.ts
2427
+ var RESIZE_POINTS = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
2428
+ function calcResizeRect(point, startRect, dx, dy, minW, minH) {
2429
+ let { left, top, width, height } = startRect;
2430
+ switch (point) {
2431
+ case "e":
2432
+ width = Math.max(minW, startRect.width + dx);
2433
+ break;
2434
+ case "w":
2435
+ width = Math.max(minW, startRect.width - dx);
2436
+ left = startRect.left + startRect.width - width;
2437
+ break;
2438
+ case "s":
2439
+ height = Math.max(minH, startRect.height + dy);
2440
+ break;
2441
+ case "n":
2442
+ height = Math.max(minH, startRect.height - dy);
2443
+ top = startRect.top + startRect.height - height;
2444
+ break;
2445
+ case "se":
2446
+ width = Math.max(minW, startRect.width + dx);
2447
+ height = Math.max(minH, startRect.height + dy);
2448
+ break;
2449
+ case "sw":
2450
+ width = Math.max(minW, startRect.width - dx);
2451
+ left = startRect.left + startRect.width - width;
2452
+ height = Math.max(minH, startRect.height + dy);
2453
+ break;
2454
+ case "ne":
2455
+ width = Math.max(minW, startRect.width + dx);
2456
+ height = Math.max(minH, startRect.height - dy);
2457
+ top = startRect.top + startRect.height - height;
2458
+ break;
2459
+ case "nw":
2460
+ width = Math.max(minW, startRect.width - dx);
2461
+ left = startRect.left + startRect.width - width;
2462
+ height = Math.max(minH, startRect.height - dy);
2463
+ top = startRect.top + startRect.height - height;
2464
+ break;
2465
+ }
2466
+ return { left, top, width, height };
2467
+ }
2468
+ function useResize(options) {
2469
+ let startX = 0, startY = 0;
2470
+ let startRect = { left: 0, top: 0, width: 0, height: 0 };
2471
+ let activePoint = null;
2472
+ function startResize(point, e) {
2473
+ if (e.button !== 0) return;
2474
+ activePoint = point;
2475
+ startX = e.clientX;
2476
+ startY = e.clientY;
2477
+ startRect = { ...options.getRect() };
2478
+ options.onStart?.();
2479
+ document.addEventListener("mousemove", onResizeMove);
2480
+ document.addEventListener("mouseup", onResizeEnd);
2481
+ e.preventDefault();
2482
+ }
2483
+ function onResizeMove(e) {
2484
+ if (!activePoint) {
2485
+ return;
2486
+ }
2487
+ const scale = options.getScale?.() || 1;
2488
+ const dx = (e.clientX - startX) / scale;
2489
+ const dy = (e.clientY - startY) / scale;
2490
+ const minW = options.minWidth || 20;
2491
+ const minH = options.minHeight || 20;
2492
+ options.onResize(calcResizeRect(activePoint, startRect, dx, dy, minW, minH));
2493
+ }
2494
+ function onResizeEnd() {
2495
+ activePoint = null;
2496
+ options.onStop?.();
2497
+ document.removeEventListener("mousemove", onResizeMove);
2498
+ document.removeEventListener("mouseup", onResizeEnd);
2499
+ }
2500
+ function cleanup() {
2501
+ document.removeEventListener("mousemove", onResizeMove);
2502
+ document.removeEventListener("mouseup", onResizeEnd);
2503
+ }
2504
+ return { startResize, cleanup };
2505
+ }
2506
+
2507
+ // src/designer/interactions/useBindingDisplay.ts
2508
+ function getNestedValue(obj, path) {
2509
+ return path.split(".").reduce((current, key) => current?.[key], obj);
2510
+ }
2511
+ function useBindingDisplay() {
2512
+ function getBindingDisplayState(element) {
2513
+ const formatter = element.options.formatter;
2514
+ const title = element.options.title;
2515
+ if (!formatter) {
2516
+ return {
2517
+ status: "unbound",
2518
+ badge: title || "\u6587\u672C",
2519
+ badgeColor: "#909399",
2520
+ demoPreview: title || "\u6587\u672C"
2521
+ };
2522
+ }
2523
+ const demoData = getDemoData();
2524
+ const fieldMatch = formatter.match(/\{([^}]+)\}/);
2525
+ if (fieldMatch) {
2526
+ const fieldPath = fieldMatch[1];
2527
+ const demoValue = getNestedValue(demoData, fieldPath);
2528
+ return {
2529
+ status: "bound",
2530
+ badge: `fx ${formatter}`,
2531
+ badgeColor: "#409EFF",
2532
+ demoPreview: demoValue != null ? String(demoValue) : formatter
2533
+ };
2534
+ }
2535
+ return {
2536
+ status: "bound",
2537
+ badge: `fx ${formatter}`,
2538
+ badgeColor: "#409EFF",
2539
+ demoPreview: formatter
2540
+ };
2541
+ }
2542
+ return { getBindingDisplayState };
2543
+ }
2544
+ // Annotate the CommonJS export names for ESM import in node:
2545
+ 0 && (module.exports = {
2546
+ BARCODE_BAR_HEIGHT_MODULES,
2547
+ BARCODE_MARGIN_BOTTOM_MODULES,
2548
+ BARCODE_MODULE_WIDTH_MM,
2549
+ BARCODE_QUIET_ZONE_MODULES,
2550
+ BARCODE_TEXT_FONT_SIZE_MODULES,
2551
+ DEFAULT_DEMO_DATA,
2552
+ DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
2553
+ ELEMENT_BINDING_REGISTRY,
2554
+ EXTENDED_FUNCTIONS,
2555
+ FIT_SCALE_MIN_PERCENT,
2556
+ GHOST_BORDER_CSS,
2557
+ LABEL_PAPER_GROUP,
2558
+ MIN_COL_WIDTH_MM,
2559
+ MIN_SCALE_PERCENT,
2560
+ MIN_SHRINK_FONT_SIZE_PT,
2561
+ MM_PER_INCH,
2562
+ PAPER_PRESETS,
2563
+ PRESET_COLORS,
2564
+ PROPERTY_REGISTRY,
2565
+ RESIZE_POINTS,
2566
+ RULER_THICKNESS,
2567
+ ZONE_ALLOWED_TYPES,
2568
+ applyBorderPreset,
2569
+ barcodeAvailableBoxMm,
2570
+ barcodePreferredModuleWidthMm,
2571
+ barcodeUnitsPerModule,
2572
+ buildRulerTicks,
2573
+ calcResizeRect,
2574
+ canMergeReason,
2575
+ cellFitCapMm,
2576
+ cellFitKey,
2577
+ cellFitWidthMm,
2578
+ chooseMajorStepMM,
2579
+ clampResizedColumnWidth,
2580
+ clampScalePercent,
2581
+ clampToZone,
2582
+ computeAdsorb,
2583
+ computeFitScale,
2584
+ createCell,
2585
+ createDefaultOptions,
2586
+ createDefaultTable,
2587
+ createFieldElement,
2588
+ createRuntimeElement,
2589
+ deleteCol,
2590
+ deleteRow,
2591
+ engine,
2592
+ evaluateTemplate,
2593
+ filterGroups,
2594
+ finalizeElementZone,
2595
+ findMainCell,
2596
+ floorFontSize,
2597
+ generateGroupId,
2598
+ generateId,
2599
+ getDemoData,
2600
+ getElementBindings,
2601
+ getPaperDimensions,
2602
+ getPaperSizeMM,
2603
+ getSpanRect,
2604
+ getTableCellBindings,
2605
+ getZoneRects,
2606
+ groupFields,
2607
+ insertCol,
2608
+ insertRow,
2609
+ isContinuousPaperSize,
2610
+ isLabelPaperSize,
2611
+ labelPaperDefaults,
2612
+ matchKeywords,
2613
+ mergeCells,
2614
+ minorStepMM,
2615
+ mmToPx,
2616
+ nextWheelScale,
2617
+ normalizeSelection,
2618
+ normalizeTemplateUnits,
2619
+ parseCellFitKey,
2620
+ ptToMm,
2621
+ pxToMm,
2622
+ resolveBarcodeDesignValue,
2623
+ resolveBarcodeSize,
2624
+ resolveCellBorderCss,
2625
+ resolveCellTextFit,
2626
+ resolveElementTextFit,
2627
+ resolveShrinkMinFontSize,
2628
+ resolveTextBinding,
2629
+ roundFontSize,
2630
+ safeEval,
2631
+ searchProperties,
2632
+ setRowType,
2633
+ splitCells,
2634
+ syncTableElementSize,
2635
+ useAlign,
2636
+ useBindingDisplay,
2637
+ useGroup,
2638
+ useKeyboard,
2639
+ useResize,
2640
+ zoneFromPaperPoint
2641
+ });