@worm-vue3-print/core 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2108,6 +2108,35 @@ function elementPositionStyle(left, top, width, height, zIndex) {
2108
2108
  return parts.join(";") + ";";
2109
2109
  }
2110
2110
 
2111
+ // src/render/element-border.ts
2112
+ var ELEMENT_BORDER_SIDES = ["top", "right", "bottom", "left"];
2113
+ var SELF_BORDER_TYPES = /* @__PURE__ */ new Set(["rect", "oval", "hline", "vline", "table"]);
2114
+ var VALID_STYLES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double"]);
2115
+ function parseBorder(width, style, color) {
2116
+ if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) return null;
2117
+ return {
2118
+ borderWidth: `${width}px`,
2119
+ borderStyle: typeof style === "string" && VALID_STYLES.has(style) ? style : "solid",
2120
+ borderColor: color || "#000"
2121
+ };
2122
+ }
2123
+ function resolveElementBorder(type, opts) {
2124
+ if (!type || SELF_BORDER_TYPES.has(type)) return null;
2125
+ const all = parseBorder(opts?.borderWidth, opts?.borderStyle, opts?.borderColor);
2126
+ const edges = {};
2127
+ const src = opts?.borders;
2128
+ if (src) {
2129
+ for (const side of ELEMENT_BORDER_SIDES) {
2130
+ const edge = src[side];
2131
+ if (!edge) continue;
2132
+ const css = parseBorder(edge.width, edge.style, edge.color);
2133
+ if (css) edges[side] = css;
2134
+ }
2135
+ }
2136
+ if (!all && Object.keys(edges).length === 0) return null;
2137
+ return { all, edges };
2138
+ }
2139
+
2111
2140
  // src/render/watermark.ts
2112
2141
  var PX_PER_MM = 96 / 25.4;
2113
2142
  var MM_PER_PX = 25.4 / 96;
@@ -2268,10 +2297,9 @@ function tableDesignBottom(el) {
2268
2297
  const opts = el.options ?? {};
2269
2298
  const top = opts.top ?? 0;
2270
2299
  const rows = opts.tableRows ?? [];
2271
- if (rows.length > 0) {
2272
- return top + rows.reduce((s, r) => s + (r.height ?? 0), 0);
2273
- }
2274
- return top + (opts.height ?? 0);
2300
+ const rowSum = rows.reduce((s, r) => s + (r.height ?? 0), 0);
2301
+ const designHeight = Math.max(opts.height ?? 0, rowSum);
2302
+ return top + designHeight;
2275
2303
  }
2276
2304
  function buildFollowMap(sorted, excludedIds) {
2277
2305
  const map = /* @__PURE__ */ new Map();
@@ -2412,7 +2440,10 @@ function paginate(template, measuredElements) {
2412
2440
  let isFirstPage = true;
2413
2441
  let pageBroken = false;
2414
2442
  function sectionTop(el) {
2415
- return pageBroken ? 0 : el.options?.top ?? 0;
2443
+ return pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2444
+ }
2445
+ function pageCursorTop() {
2446
+ return Math.max(0, fullPageHeight() - remaining);
2416
2447
  }
2417
2448
  function fullPageHeight() {
2418
2449
  return isFirstPage ? contentHeight - overlayH - SAFETY_MARGIN : contentHeight - SAFETY_MARGIN;
@@ -2479,7 +2510,7 @@ function paginate(template, measuredElements) {
2479
2510
  function paginateNonTable(el, measured, sortedList, idx) {
2480
2511
  const elHeight = measured.get(el.id)?.measuredHeight ?? el.options?.height ?? 0;
2481
2512
  if (elHeight <= remaining) {
2482
- const top2 = pageBroken ? 0 : el.options?.top ?? 0;
2513
+ const top2 = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2483
2514
  noteOverflow(top2 + elHeight);
2484
2515
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
2485
2516
  remaining -= elHeight;
@@ -2498,8 +2529,9 @@ function paginate(template, measuredElements) {
2498
2529
  }
2499
2530
  return idx + 1;
2500
2531
  }
2501
- const top = pageBroken ? 0 : el.options?.top ?? 0;
2502
- finishPage(top + elHeight > contentHeight);
2532
+ finishPage();
2533
+ const top = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2534
+ if (top + elHeight > contentHeight) overflowOnCurrent = true;
2503
2535
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
2504
2536
  remaining -= elHeight;
2505
2537
  return idx + 1;
@@ -2515,7 +2547,7 @@ function paginate(template, measuredElements) {
2515
2547
  }
2516
2548
  const unitHeight = Math.max(maxBottom - minTop, 0);
2517
2549
  const place = () => {
2518
- const offset = pageBroken ? -minTop : 0;
2550
+ const offset = pageBroken ? pageCursorTop() - minTop : 0;
2519
2551
  noteOverflow(minTop + offset + unitHeight);
2520
2552
  for (const m of members) {
2521
2553
  currentPage.push({
@@ -2589,6 +2621,7 @@ function paginate(template, measuredElements) {
2589
2621
  const groups = buildRowGroups(bodyRows, rowCount);
2590
2622
  let sliceStart = 0;
2591
2623
  let firstSlice = true;
2624
+ let sliceTop = sectionTop(el);
2592
2625
  for (const g of groups) {
2593
2626
  const gh = bodyHeights.slice(g.start, g.end).reduce((s, h) => s + h, 0);
2594
2627
  if (gh + subtotalH <= remaining) {
@@ -2603,12 +2636,13 @@ function paginate(template, measuredElements) {
2603
2636
  endRow: g.start,
2604
2637
  subtotal: subtotalH > 0,
2605
2638
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2606
- renderTop: sectionTop(el)
2639
+ renderTop: sliceTop
2607
2640
  });
2608
2641
  firstSlice = false;
2609
2642
  sliceStart = g.start;
2610
2643
  }
2611
2644
  finishPage();
2645
+ sliceTop = sectionTop(el);
2612
2646
  if (!firstSlice) remaining -= repeatH;
2613
2647
  remaining -= gh;
2614
2648
  }
@@ -2620,7 +2654,7 @@ function paginate(template, measuredElements) {
2620
2654
  endRow: rowCount,
2621
2655
  subtotal: subtotalH > 0,
2622
2656
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2623
- renderTop: sectionTop(el)
2657
+ renderTop: sliceTop
2624
2658
  });
2625
2659
  }
2626
2660
  if (summaryH > 0) {
@@ -2911,7 +2945,18 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
2911
2945
  const type = el.type || el.printElementType?.type || "text";
2912
2946
  const fit = resolveElementTextFit(type, opts);
2913
2947
  const fitHeight = fit === "autoHeight" ? void 0 : height;
2914
- const style = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2948
+ const baseStyle = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2949
+ const elBorders = resolveElementBorder(type, opts);
2950
+ let style = baseStyle;
2951
+ if (elBorders?.all) {
2952
+ style += `border:${elBorders.all.borderWidth} ${elBorders.all.borderStyle} ${elBorders.all.borderColor};`;
2953
+ }
2954
+ if (elBorders) {
2955
+ for (const side of ELEMENT_BORDER_SIDES) {
2956
+ const e = elBorders.edges[side];
2957
+ if (e) style += `border-${side}:${e.borderWidth} ${e.borderStyle} ${e.borderColor};`;
2958
+ }
2959
+ }
2915
2960
  const measureAttr = isMeasure ? ` data-measure-id="${el.id}"` : "";
2916
2961
  const fitAttr = fitAttrs(fit, el.id, opts.fontSize ?? 12, opts);
2917
2962
  switch (type) {
@@ -1,5 +1,5 @@
1
- import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-Dn_YAzO5.cjs';
2
- import { P as PrintRuntime, F as FitFontSize } from '../ports-Cf5sjwls.cjs';
1
+ import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-CNJVZK_L.cjs';
2
+ import { P as PrintRuntime, F as FitFontSize } from '../ports-DeEgE2SL.cjs';
3
3
 
4
4
  interface BrowserRenderResult {
5
5
  /** 最终多页 HTML 字符串 */
@@ -1,5 +1,5 @@
1
- import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-Dn_YAzO5.js';
2
- import { P as PrintRuntime, F as FitFontSize } from '../ports-BvwlA_km.js';
1
+ import { P as PageLayout, T as TemplateData, M as MultiPageTemplateData, C as CodeRenderer, D as DriverFactory, R as RawMeasurement, a as CodeSpec } from '../driver-CNJVZK_L.js';
2
+ import { P as PrintRuntime, F as FitFontSize } from '../ports-DSfECjvT.js';
3
3
 
4
4
  interface BrowserRenderResult {
5
5
  /** 最终多页 HTML 字符串 */
@@ -11,7 +11,7 @@ import {
11
11
  prepareDocument,
12
12
  resolveBarcodeSize,
13
13
  resolveShrinkMinFontSize
14
- } from "../chunk-KFRPTLFV.js";
14
+ } from "../chunk-DCQGN54P.js";
15
15
 
16
16
  // src/browser/browser-code-renderer.ts
17
17
  import JsBarcode from "jsbarcode";
@@ -1589,6 +1589,38 @@ function cellFitCapMm(rows, rowIndex, cell, defaultPadding = 1) {
1589
1589
  return Math.max(height - padding * 2 - borderMm, 0.5);
1590
1590
  }
1591
1591
 
1592
+ // src/render/element-border.ts
1593
+ var ELEMENT_BORDER_SIDES = ["top", "right", "bottom", "left"];
1594
+ var SELF_BORDER_TYPES = /* @__PURE__ */ new Set(["rect", "oval", "hline", "vline", "table"]);
1595
+ function acceptsElementBorder(type) {
1596
+ return !!type && !SELF_BORDER_TYPES.has(type);
1597
+ }
1598
+ var VALID_STYLES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double"]);
1599
+ function parseBorder(width, style, color) {
1600
+ if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) return null;
1601
+ return {
1602
+ borderWidth: `${width}px`,
1603
+ borderStyle: typeof style === "string" && VALID_STYLES.has(style) ? style : "solid",
1604
+ borderColor: color || "#000"
1605
+ };
1606
+ }
1607
+ function resolveElementBorder(type, opts) {
1608
+ if (!type || SELF_BORDER_TYPES.has(type)) return null;
1609
+ const all = parseBorder(opts?.borderWidth, opts?.borderStyle, opts?.borderColor);
1610
+ const edges = {};
1611
+ const src = opts?.borders;
1612
+ if (src) {
1613
+ for (const side of ELEMENT_BORDER_SIDES) {
1614
+ const edge = src[side];
1615
+ if (!edge) continue;
1616
+ const css = parseBorder(edge.width, edge.style, edge.color);
1617
+ if (css) edges[side] = css;
1618
+ }
1619
+ }
1620
+ if (!all && Object.keys(edges).length === 0) return null;
1621
+ return { all, edges };
1622
+ }
1623
+
1592
1624
  // src/render/watermark.ts
1593
1625
  var PX_PER_MM = 96 / 25.4;
1594
1626
  var MM_PER_PX = 25.4 / 96;
@@ -1754,10 +1786,9 @@ function tableDesignBottom(el) {
1754
1786
  const opts = el.options ?? {};
1755
1787
  const top = opts.top ?? 0;
1756
1788
  const rows = opts.tableRows ?? [];
1757
- if (rows.length > 0) {
1758
- return top + rows.reduce((s, r) => s + (r.height ?? 0), 0);
1759
- }
1760
- return top + (opts.height ?? 0);
1789
+ const rowSum = rows.reduce((s, r) => s + (r.height ?? 0), 0);
1790
+ const designHeight = Math.max(opts.height ?? 0, rowSum);
1791
+ return top + designHeight;
1761
1792
  }
1762
1793
  function buildFollowMap(sorted, excludedIds) {
1763
1794
  const map = /* @__PURE__ */ new Map();
@@ -1898,7 +1929,10 @@ function paginate(template, measuredElements) {
1898
1929
  let isFirstPage = true;
1899
1930
  let pageBroken = false;
1900
1931
  function sectionTop(el) {
1901
- return pageBroken ? 0 : el.options?.top ?? 0;
1932
+ return pageBroken ? pageCursorTop() : el.options?.top ?? 0;
1933
+ }
1934
+ function pageCursorTop() {
1935
+ return Math.max(0, fullPageHeight() - remaining);
1902
1936
  }
1903
1937
  function fullPageHeight() {
1904
1938
  return isFirstPage ? contentHeight - overlayH - SAFETY_MARGIN : contentHeight - SAFETY_MARGIN;
@@ -1965,7 +1999,7 @@ function paginate(template, measuredElements) {
1965
1999
  function paginateNonTable(el, measured, sortedList, idx) {
1966
2000
  const elHeight = measured.get(el.id)?.measuredHeight ?? el.options?.height ?? 0;
1967
2001
  if (elHeight <= remaining) {
1968
- const top2 = pageBroken ? 0 : el.options?.top ?? 0;
2002
+ const top2 = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
1969
2003
  noteOverflow(top2 + elHeight);
1970
2004
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
1971
2005
  remaining -= elHeight;
@@ -1984,8 +2018,9 @@ function paginate(template, measuredElements) {
1984
2018
  }
1985
2019
  return idx + 1;
1986
2020
  }
1987
- const top = pageBroken ? 0 : el.options?.top ?? 0;
1988
- finishPage(top + elHeight > contentHeight);
2021
+ finishPage();
2022
+ const top = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2023
+ if (top + elHeight > contentHeight) overflowOnCurrent = true;
1989
2024
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
1990
2025
  remaining -= elHeight;
1991
2026
  return idx + 1;
@@ -2001,7 +2036,7 @@ function paginate(template, measuredElements) {
2001
2036
  }
2002
2037
  const unitHeight = Math.max(maxBottom - minTop, 0);
2003
2038
  const place = () => {
2004
- const offset = pageBroken ? -minTop : 0;
2039
+ const offset = pageBroken ? pageCursorTop() - minTop : 0;
2005
2040
  noteOverflow(minTop + offset + unitHeight);
2006
2041
  for (const m of members) {
2007
2042
  currentPage.push({
@@ -2075,6 +2110,7 @@ function paginate(template, measuredElements) {
2075
2110
  const groups = buildRowGroups(bodyRows, rowCount);
2076
2111
  let sliceStart = 0;
2077
2112
  let firstSlice = true;
2113
+ let sliceTop = sectionTop(el);
2078
2114
  for (const g of groups) {
2079
2115
  const gh = bodyHeights.slice(g.start, g.end).reduce((s, h) => s + h, 0);
2080
2116
  if (gh + subtotalH <= remaining) {
@@ -2089,12 +2125,13 @@ function paginate(template, measuredElements) {
2089
2125
  endRow: g.start,
2090
2126
  subtotal: subtotalH > 0,
2091
2127
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2092
- renderTop: sectionTop(el)
2128
+ renderTop: sliceTop
2093
2129
  });
2094
2130
  firstSlice = false;
2095
2131
  sliceStart = g.start;
2096
2132
  }
2097
2133
  finishPage();
2134
+ sliceTop = sectionTop(el);
2098
2135
  if (!firstSlice) remaining -= repeatH;
2099
2136
  remaining -= gh;
2100
2137
  }
@@ -2106,7 +2143,7 @@ function paginate(template, measuredElements) {
2106
2143
  endRow: rowCount,
2107
2144
  subtotal: subtotalH > 0,
2108
2145
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2109
- renderTop: sectionTop(el)
2146
+ renderTop: sliceTop
2110
2147
  });
2111
2148
  }
2112
2149
  if (summaryH > 0) {
@@ -2451,7 +2488,18 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
2451
2488
  const type = el.type || el.printElementType?.type || "text";
2452
2489
  const fit = resolveElementTextFit(type, opts);
2453
2490
  const fitHeight = fit === "autoHeight" ? void 0 : height;
2454
- const style = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2491
+ const baseStyle = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2492
+ const elBorders = resolveElementBorder(type, opts);
2493
+ let style = baseStyle;
2494
+ if (elBorders?.all) {
2495
+ style += `border:${elBorders.all.borderWidth} ${elBorders.all.borderStyle} ${elBorders.all.borderColor};`;
2496
+ }
2497
+ if (elBorders) {
2498
+ for (const side of ELEMENT_BORDER_SIDES) {
2499
+ const e = elBorders.edges[side];
2500
+ if (e) style += `border-${side}:${e.borderWidth} ${e.borderStyle} ${e.borderColor};`;
2501
+ }
2502
+ }
2455
2503
  const measureAttr = isMeasure ? ` data-measure-id="${el.id}"` : "";
2456
2504
  const fitAttr = fitAttrs(fit, el.id, opts.fontSize ?? 12, opts);
2457
2505
  switch (type) {
@@ -3743,6 +3791,9 @@ export {
3743
3791
  parseCellFitKey,
3744
3792
  cellFitWidthMm,
3745
3793
  cellFitCapMm,
3794
+ ELEMENT_BORDER_SIDES,
3795
+ acceptsElementBorder,
3796
+ resolveElementBorder,
3746
3797
  PX_PER_MM,
3747
3798
  MM_PER_PX,
3748
3799
  WATERMARK_DEFAULTS,
@@ -3,7 +3,7 @@ import {
3
3
  evaluate,
4
4
  parse,
5
5
  tokenize
6
- } from "./chunk-KFRPTLFV.js";
6
+ } from "./chunk-DCQGN54P.js";
7
7
 
8
8
  // src/index.ts
9
9
  var TemplateEngine = class {
@@ -28,6 +28,7 @@ __export(designer_exports, {
28
28
  DEFAULT_DEMO_DATA: () => DEFAULT_DEMO_DATA,
29
29
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT: () => DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
30
30
  ELEMENT_BINDING_REGISTRY: () => ELEMENT_BINDING_REGISTRY,
31
+ ELEMENT_BORDER_SIDES: () => ELEMENT_BORDER_SIDES,
31
32
  EXTENDED_FUNCTIONS: () => EXTENDED_FUNCTIONS,
32
33
  FIT_SCALE_MIN_PERCENT: () => FIT_SCALE_MIN_PERCENT,
33
34
  GHOST_BORDER_CSS: () => GHOST_BORDER_CSS,
@@ -42,6 +43,7 @@ __export(designer_exports, {
42
43
  RESIZE_POINTS: () => RESIZE_POINTS,
43
44
  RULER_THICKNESS: () => RULER_THICKNESS,
44
45
  ZONE_ALLOWED_TYPES: () => ZONE_ALLOWED_TYPES,
46
+ acceptsElementBorder: () => acceptsElementBorder,
45
47
  applyBorderPreset: () => applyBorderPreset,
46
48
  barcodeAvailableBoxMm: () => barcodeAvailableBoxMm,
47
49
  barcodePreferredModuleWidthMm: () => barcodePreferredModuleWidthMm,
@@ -100,6 +102,7 @@ __export(designer_exports, {
100
102
  resolveBarcodeSize: () => resolveBarcodeSize,
101
103
  resolveCellBorderCss: () => resolveCellBorderCss,
102
104
  resolveCellTextFit: () => resolveCellTextFit,
105
+ resolveElementBorder: () => resolveElementBorder,
103
106
  resolveElementTextFit: () => resolveElementTextFit,
104
107
  resolveShrinkMinFontSize: () => resolveShrinkMinFontSize,
105
108
  resolveTextBinding: () => resolveTextBinding,
@@ -246,6 +249,38 @@ function resolveBarcodeSize(input) {
246
249
  };
247
250
  }
248
251
 
252
+ // src/render/element-border.ts
253
+ var ELEMENT_BORDER_SIDES = ["top", "right", "bottom", "left"];
254
+ var SELF_BORDER_TYPES = /* @__PURE__ */ new Set(["rect", "oval", "hline", "vline", "table"]);
255
+ function acceptsElementBorder(type) {
256
+ return !!type && !SELF_BORDER_TYPES.has(type);
257
+ }
258
+ var VALID_STYLES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double"]);
259
+ function parseBorder(width, style, color) {
260
+ if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) return null;
261
+ return {
262
+ borderWidth: `${width}px`,
263
+ borderStyle: typeof style === "string" && VALID_STYLES.has(style) ? style : "solid",
264
+ borderColor: color || "#000"
265
+ };
266
+ }
267
+ function resolveElementBorder(type, opts) {
268
+ if (!type || SELF_BORDER_TYPES.has(type)) return null;
269
+ const all = parseBorder(opts?.borderWidth, opts?.borderStyle, opts?.borderColor);
270
+ const edges = {};
271
+ const src = opts?.borders;
272
+ if (src) {
273
+ for (const side of ELEMENT_BORDER_SIDES) {
274
+ const edge = src[side];
275
+ if (!edge) continue;
276
+ const css = parseBorder(edge.width, edge.style, edge.color);
277
+ if (css) edges[side] = css;
278
+ }
279
+ }
280
+ if (!all && Object.keys(edges).length === 0) return null;
281
+ return { all, edges };
282
+ }
283
+
249
284
  // src/designer/utils/scale.ts
250
285
  var MIN_SCALE_PERCENT = 25;
251
286
  var FIT_SCALE_MIN_PERCENT = 5;
@@ -2735,6 +2770,7 @@ function useBindingDisplay() {
2735
2770
  DEFAULT_DEMO_DATA,
2736
2771
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
2737
2772
  ELEMENT_BINDING_REGISTRY,
2773
+ ELEMENT_BORDER_SIDES,
2738
2774
  EXTENDED_FUNCTIONS,
2739
2775
  FIT_SCALE_MIN_PERCENT,
2740
2776
  GHOST_BORDER_CSS,
@@ -2749,6 +2785,7 @@ function useBindingDisplay() {
2749
2785
  RESIZE_POINTS,
2750
2786
  RULER_THICKNESS,
2751
2787
  ZONE_ALLOWED_TYPES,
2788
+ acceptsElementBorder,
2752
2789
  applyBorderPreset,
2753
2790
  barcodeAvailableBoxMm,
2754
2791
  barcodePreferredModuleWidthMm,
@@ -2807,6 +2844,7 @@ function useBindingDisplay() {
2807
2844
  resolveBarcodeSize,
2808
2845
  resolveCellBorderCss,
2809
2846
  resolveCellTextFit,
2847
+ resolveElementBorder,
2810
2848
  resolveElementTextFit,
2811
2849
  resolveShrinkMinFontSize,
2812
2850
  resolveTextBinding,
@@ -1,6 +1,6 @@
1
- import { b as TemplateData, c as TableRow, d as TableCellBorder, e as TableCell, f as TableRowType, E as ElementOptions, g as ElementType, h as RuntimeElement, i as ElementZone, j as PrintBusinessField, B as BindingDescriptor, k as ElementRect, A as AdsorbResult, l as ResizePoint } from '../driver-Dn_YAzO5.cjs';
2
- export { m as AlignLine, n as DesignBackground, o as ElementFieldBinding, p as MultiPageTemplateData, q as PaginationConfig, r as PaperSize, s as PrintElementData, t as PrintElementTypeMeta, u as RequestScreenshotFn, S as ScreenshotRequest, v as TableCellBorders, w as TableCellType, x as TablePaginationConfig, y as TableSelection, z as TemplateElement, F as TextAlign, G as TextFit, U as UploadDesignBackgroundFn, H as UploadImageFn, V as VerticalAlign, W as WatermarkOptions } from '../driver-Dn_YAzO5.cjs';
3
- export { C as CellFitRowKind, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, F as FitFontSize, M as MIN_SHRINK_FONT_SIZE_PT, c as cellFitCapMm, a as cellFitKey, b as cellFitWidthMm, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from '../ports-Cf5sjwls.cjs';
1
+ import { E as ElementBorderSide, b as ElementOptions, c as TemplateData, d as TableRow, e as TableCellBorder, f as TableCell, g as TableRowType, h as ElementType, i as RuntimeElement, j as ElementZone, k as PrintBusinessField, B as BindingDescriptor, l as ElementRect, A as AdsorbResult, m as ResizePoint } from '../driver-CNJVZK_L.cjs';
2
+ export { n as AlignLine, o as DesignBackground, p as ElementBorderEdge, q as ElementFieldBinding, r as MultiPageTemplateData, s as PaginationConfig, t as PaperSize, u as PrintElementData, v as PrintElementTypeMeta, w as RequestScreenshotFn, S as ScreenshotRequest, x as TableCellBorders, y as TableCellType, z as TablePaginationConfig, F as TableSelection, G as TemplateElement, H as TextAlign, I as TextFit, U as UploadDesignBackgroundFn, J as UploadImageFn, V as VerticalAlign, W as WatermarkOptions } from '../driver-CNJVZK_L.cjs';
3
+ export { C as CellFitRowKind, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, F as FitFontSize, M as MIN_SHRINK_FONT_SIZE_PT, c as cellFitCapMm, a as cellFitKey, b as cellFitWidthMm, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from '../ports-DeEgE2SL.cjs';
4
4
  import { TemplateEngine, formatMoney, ifFn, addNumbers, subtractNumbers, multiplyNumbers, divideNumbers, round, roundUp, roundDown, roundHalfEven, formatDate, toUpperCaseAmount } from '../index.cjs';
5
5
 
6
6
  /** 1 英寸 = 25.4mm */
@@ -64,6 +64,24 @@ declare function barcodeAvailableBoxMm(boxMm: number | undefined, maxMm: number
64
64
  */
65
65
  declare function resolveBarcodeSize(input: BarcodeSizeInput): BarcodeSize;
66
66
 
67
+ interface ElementBorderCss {
68
+ /** CSS 长度,px 口径(与 rect/oval 现有一致) */
69
+ borderWidth: string;
70
+ borderStyle: string;
71
+ borderColor: string;
72
+ }
73
+ /** 元素级边框解析结果:整圈 + 逐边覆盖(渲染时先写整圈、后写各边,CSS 后者覆盖前者) */
74
+ interface ElementBordersCss {
75
+ all: ElementBorderCss | null;
76
+ edges: Partial<Record<ElementBorderSide, ElementBorderCss>>;
77
+ }
78
+ declare const ELEMENT_BORDER_SIDES: readonly ElementBorderSide[];
79
+ /** 该元素类型是否可携带元素级边框(供设计器格式刷等按类型过滤写入目标) */
80
+ declare function acceptsElementBorder(type: string | undefined): boolean;
81
+ type BorderFields = Pick<ElementOptions, 'borderWidth' | 'borderStyle' | 'borderColor' | 'borders'>;
82
+ /** 解析元素级边框;返回 null 表示无任何生效边框 */
83
+ declare function resolveElementBorder(type: string | undefined, opts: BorderFields | undefined): ElementBordersCss | null;
84
+
67
85
  /** pt 转 mm */
68
86
  declare function ptToMm(pt: number): number;
69
87
  /** px 转 mm(基于 96dpi 屏幕) */
@@ -460,4 +478,4 @@ declare function useBindingDisplay(): {
460
478
  getBindingDisplayState: (element: any) => BindingDisplayState;
461
479
  };
462
480
 
463
- export { type AdsorbConfig, AdsorbResult, type AlignMode, BARCODE_BAR_HEIGHT_MODULES, BARCODE_MARGIN_BOTTOM_MODULES, BARCODE_MODULE_WIDTH_MM, BARCODE_QUIET_ZONE_MODULES, BARCODE_TEXT_FONT_SIZE_MODULES, type BarcodeSize, type BarcodeSizeInput, BindingDescriptor, type BorderPreset, type CellRect, DEFAULT_DEMO_DATA, ELEMENT_BINDING_REGISTRY, EXTENDED_FUNCTIONS, ElementOptions, ElementRect, ElementType, ElementZone, FIT_SCALE_MIN_PERCENT, type FieldGroup, GHOST_BORDER_CSS, type KeyboardHandlers, LABEL_PAPER_GROUP, MIN_COL_WIDTH_MM, MIN_SCALE_PERCENT, MM_PER_INCH, type ManualGuides, PAPER_PRESETS, PRESET_COLORS, PROPERTY_REGISTRY, type PaperPreset, PrintBusinessField, type PropertyGroupDef, type PropertyItem, RESIZE_POINTS, RULER_THICKNESS, type ResizeOptions, ResizePoint, type ResizeRect, type RulerTick, RuntimeElement, TableCell, TableCellBorder, TableRow, TableRowType, TemplateData, ZONE_ALLOWED_TYPES, type ZoneRectPt, applyBorderPreset, barcodeAvailableBoxMm, barcodePreferredModuleWidthMm, barcodeUnitsPerModule, buildRulerTicks, calcResizeRect, canMergeReason, chooseMajorStepMM, clampResizedColumnWidth, clampScalePercent, clampToZone, computeAdsorb, computeFitScale, createCell, createDefaultOptions, createDefaultTable, createFieldElement, createRuntimeElement, deleteCol, deleteRow, engine, evaluateTemplate, filterGroups, finalizeElementZone, findMainCell, generateGroupId, generateId, getDemoData, getElementBindings, getPaperDimensions, getPaperSizeMM, getSpanRect, getTableCellBindings, getZoneRects, groupFields, insertCol, insertRow, isContinuousPaperSize, isLabelPaperSize, labelPaperDefaults, matchKeywords, mergeCells, minorStepMM, mmToPx, nextWheelScale, normalizeSelection, normalizeTemplateUnits, ptToMm, pxToMm, resolveBarcodeDesignValue, resolveBarcodeSize, resolveCellBorderCss, resolveTextBinding, safeEval, searchProperties, setHeaderRepeat, setRowType, splitCells, syncTableElementSize, useAlign, useBindingDisplay, useGroup, useKeyboard, useResize, zoneFromPaperPoint };
481
+ export { type AdsorbConfig, AdsorbResult, type AlignMode, BARCODE_BAR_HEIGHT_MODULES, BARCODE_MARGIN_BOTTOM_MODULES, BARCODE_MODULE_WIDTH_MM, BARCODE_QUIET_ZONE_MODULES, BARCODE_TEXT_FONT_SIZE_MODULES, type BarcodeSize, type BarcodeSizeInput, BindingDescriptor, type BorderPreset, type CellRect, DEFAULT_DEMO_DATA, ELEMENT_BINDING_REGISTRY, ELEMENT_BORDER_SIDES, EXTENDED_FUNCTIONS, type ElementBorderCss, ElementBorderSide, type ElementBordersCss, ElementOptions, ElementRect, ElementType, ElementZone, FIT_SCALE_MIN_PERCENT, type FieldGroup, GHOST_BORDER_CSS, type KeyboardHandlers, LABEL_PAPER_GROUP, MIN_COL_WIDTH_MM, MIN_SCALE_PERCENT, MM_PER_INCH, type ManualGuides, PAPER_PRESETS, PRESET_COLORS, PROPERTY_REGISTRY, type PaperPreset, PrintBusinessField, type PropertyGroupDef, type PropertyItem, RESIZE_POINTS, RULER_THICKNESS, type ResizeOptions, ResizePoint, type ResizeRect, type RulerTick, RuntimeElement, TableCell, TableCellBorder, TableRow, TableRowType, TemplateData, ZONE_ALLOWED_TYPES, type ZoneRectPt, acceptsElementBorder, applyBorderPreset, barcodeAvailableBoxMm, barcodePreferredModuleWidthMm, barcodeUnitsPerModule, buildRulerTicks, calcResizeRect, canMergeReason, chooseMajorStepMM, clampResizedColumnWidth, clampScalePercent, clampToZone, computeAdsorb, computeFitScale, createCell, createDefaultOptions, createDefaultTable, createFieldElement, createRuntimeElement, deleteCol, deleteRow, engine, evaluateTemplate, filterGroups, finalizeElementZone, findMainCell, generateGroupId, generateId, getDemoData, getElementBindings, getPaperDimensions, getPaperSizeMM, getSpanRect, getTableCellBindings, getZoneRects, groupFields, insertCol, insertRow, isContinuousPaperSize, isLabelPaperSize, labelPaperDefaults, matchKeywords, mergeCells, minorStepMM, mmToPx, nextWheelScale, normalizeSelection, normalizeTemplateUnits, ptToMm, pxToMm, resolveBarcodeDesignValue, resolveBarcodeSize, resolveCellBorderCss, resolveElementBorder, resolveTextBinding, safeEval, searchProperties, setHeaderRepeat, setRowType, splitCells, syncTableElementSize, useAlign, useBindingDisplay, useGroup, useKeyboard, useResize, zoneFromPaperPoint };
@@ -1,6 +1,6 @@
1
- import { b as TemplateData, c as TableRow, d as TableCellBorder, e as TableCell, f as TableRowType, E as ElementOptions, g as ElementType, h as RuntimeElement, i as ElementZone, j as PrintBusinessField, B as BindingDescriptor, k as ElementRect, A as AdsorbResult, l as ResizePoint } from '../driver-Dn_YAzO5.js';
2
- export { m as AlignLine, n as DesignBackground, o as ElementFieldBinding, p as MultiPageTemplateData, q as PaginationConfig, r as PaperSize, s as PrintElementData, t as PrintElementTypeMeta, u as RequestScreenshotFn, S as ScreenshotRequest, v as TableCellBorders, w as TableCellType, x as TablePaginationConfig, y as TableSelection, z as TemplateElement, F as TextAlign, G as TextFit, U as UploadDesignBackgroundFn, H as UploadImageFn, V as VerticalAlign, W as WatermarkOptions } from '../driver-Dn_YAzO5.js';
3
- export { C as CellFitRowKind, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, F as FitFontSize, M as MIN_SHRINK_FONT_SIZE_PT, c as cellFitCapMm, a as cellFitKey, b as cellFitWidthMm, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from '../ports-BvwlA_km.js';
1
+ import { E as ElementBorderSide, b as ElementOptions, c as TemplateData, d as TableRow, e as TableCellBorder, f as TableCell, g as TableRowType, h as ElementType, i as RuntimeElement, j as ElementZone, k as PrintBusinessField, B as BindingDescriptor, l as ElementRect, A as AdsorbResult, m as ResizePoint } from '../driver-CNJVZK_L.js';
2
+ export { n as AlignLine, o as DesignBackground, p as ElementBorderEdge, q as ElementFieldBinding, r as MultiPageTemplateData, s as PaginationConfig, t as PaperSize, u as PrintElementData, v as PrintElementTypeMeta, w as RequestScreenshotFn, S as ScreenshotRequest, x as TableCellBorders, y as TableCellType, z as TablePaginationConfig, F as TableSelection, G as TemplateElement, H as TextAlign, I as TextFit, U as UploadDesignBackgroundFn, J as UploadImageFn, V as VerticalAlign, W as WatermarkOptions } from '../driver-CNJVZK_L.js';
3
+ export { C as CellFitRowKind, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, F as FitFontSize, M as MIN_SHRINK_FONT_SIZE_PT, c as cellFitCapMm, a as cellFitKey, b as cellFitWidthMm, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from '../ports-DSfECjvT.js';
4
4
  import { TemplateEngine, formatMoney, ifFn, addNumbers, subtractNumbers, multiplyNumbers, divideNumbers, round, roundUp, roundDown, roundHalfEven, formatDate, toUpperCaseAmount } from '../index.js';
5
5
 
6
6
  /** 1 英寸 = 25.4mm */
@@ -64,6 +64,24 @@ declare function barcodeAvailableBoxMm(boxMm: number | undefined, maxMm: number
64
64
  */
65
65
  declare function resolveBarcodeSize(input: BarcodeSizeInput): BarcodeSize;
66
66
 
67
+ interface ElementBorderCss {
68
+ /** CSS 长度,px 口径(与 rect/oval 现有一致) */
69
+ borderWidth: string;
70
+ borderStyle: string;
71
+ borderColor: string;
72
+ }
73
+ /** 元素级边框解析结果:整圈 + 逐边覆盖(渲染时先写整圈、后写各边,CSS 后者覆盖前者) */
74
+ interface ElementBordersCss {
75
+ all: ElementBorderCss | null;
76
+ edges: Partial<Record<ElementBorderSide, ElementBorderCss>>;
77
+ }
78
+ declare const ELEMENT_BORDER_SIDES: readonly ElementBorderSide[];
79
+ /** 该元素类型是否可携带元素级边框(供设计器格式刷等按类型过滤写入目标) */
80
+ declare function acceptsElementBorder(type: string | undefined): boolean;
81
+ type BorderFields = Pick<ElementOptions, 'borderWidth' | 'borderStyle' | 'borderColor' | 'borders'>;
82
+ /** 解析元素级边框;返回 null 表示无任何生效边框 */
83
+ declare function resolveElementBorder(type: string | undefined, opts: BorderFields | undefined): ElementBordersCss | null;
84
+
67
85
  /** pt 转 mm */
68
86
  declare function ptToMm(pt: number): number;
69
87
  /** px 转 mm(基于 96dpi 屏幕) */
@@ -460,4 +478,4 @@ declare function useBindingDisplay(): {
460
478
  getBindingDisplayState: (element: any) => BindingDisplayState;
461
479
  };
462
480
 
463
- export { type AdsorbConfig, AdsorbResult, type AlignMode, BARCODE_BAR_HEIGHT_MODULES, BARCODE_MARGIN_BOTTOM_MODULES, BARCODE_MODULE_WIDTH_MM, BARCODE_QUIET_ZONE_MODULES, BARCODE_TEXT_FONT_SIZE_MODULES, type BarcodeSize, type BarcodeSizeInput, BindingDescriptor, type BorderPreset, type CellRect, DEFAULT_DEMO_DATA, ELEMENT_BINDING_REGISTRY, EXTENDED_FUNCTIONS, ElementOptions, ElementRect, ElementType, ElementZone, FIT_SCALE_MIN_PERCENT, type FieldGroup, GHOST_BORDER_CSS, type KeyboardHandlers, LABEL_PAPER_GROUP, MIN_COL_WIDTH_MM, MIN_SCALE_PERCENT, MM_PER_INCH, type ManualGuides, PAPER_PRESETS, PRESET_COLORS, PROPERTY_REGISTRY, type PaperPreset, PrintBusinessField, type PropertyGroupDef, type PropertyItem, RESIZE_POINTS, RULER_THICKNESS, type ResizeOptions, ResizePoint, type ResizeRect, type RulerTick, RuntimeElement, TableCell, TableCellBorder, TableRow, TableRowType, TemplateData, ZONE_ALLOWED_TYPES, type ZoneRectPt, applyBorderPreset, barcodeAvailableBoxMm, barcodePreferredModuleWidthMm, barcodeUnitsPerModule, buildRulerTicks, calcResizeRect, canMergeReason, chooseMajorStepMM, clampResizedColumnWidth, clampScalePercent, clampToZone, computeAdsorb, computeFitScale, createCell, createDefaultOptions, createDefaultTable, createFieldElement, createRuntimeElement, deleteCol, deleteRow, engine, evaluateTemplate, filterGroups, finalizeElementZone, findMainCell, generateGroupId, generateId, getDemoData, getElementBindings, getPaperDimensions, getPaperSizeMM, getSpanRect, getTableCellBindings, getZoneRects, groupFields, insertCol, insertRow, isContinuousPaperSize, isLabelPaperSize, labelPaperDefaults, matchKeywords, mergeCells, minorStepMM, mmToPx, nextWheelScale, normalizeSelection, normalizeTemplateUnits, ptToMm, pxToMm, resolveBarcodeDesignValue, resolveBarcodeSize, resolveCellBorderCss, resolveTextBinding, safeEval, searchProperties, setHeaderRepeat, setRowType, splitCells, syncTableElementSize, useAlign, useBindingDisplay, useGroup, useKeyboard, useResize, zoneFromPaperPoint };
481
+ export { type AdsorbConfig, AdsorbResult, type AlignMode, BARCODE_BAR_HEIGHT_MODULES, BARCODE_MARGIN_BOTTOM_MODULES, BARCODE_MODULE_WIDTH_MM, BARCODE_QUIET_ZONE_MODULES, BARCODE_TEXT_FONT_SIZE_MODULES, type BarcodeSize, type BarcodeSizeInput, BindingDescriptor, type BorderPreset, type CellRect, DEFAULT_DEMO_DATA, ELEMENT_BINDING_REGISTRY, ELEMENT_BORDER_SIDES, EXTENDED_FUNCTIONS, type ElementBorderCss, ElementBorderSide, type ElementBordersCss, ElementOptions, ElementRect, ElementType, ElementZone, FIT_SCALE_MIN_PERCENT, type FieldGroup, GHOST_BORDER_CSS, type KeyboardHandlers, LABEL_PAPER_GROUP, MIN_COL_WIDTH_MM, MIN_SCALE_PERCENT, MM_PER_INCH, type ManualGuides, PAPER_PRESETS, PRESET_COLORS, PROPERTY_REGISTRY, type PaperPreset, PrintBusinessField, type PropertyGroupDef, type PropertyItem, RESIZE_POINTS, RULER_THICKNESS, type ResizeOptions, ResizePoint, type ResizeRect, type RulerTick, RuntimeElement, TableCell, TableCellBorder, TableRow, TableRowType, TemplateData, ZONE_ALLOWED_TYPES, type ZoneRectPt, acceptsElementBorder, applyBorderPreset, barcodeAvailableBoxMm, barcodePreferredModuleWidthMm, barcodeUnitsPerModule, buildRulerTicks, calcResizeRect, canMergeReason, chooseMajorStepMM, clampResizedColumnWidth, clampScalePercent, clampToZone, computeAdsorb, computeFitScale, createCell, createDefaultOptions, createDefaultTable, createFieldElement, createRuntimeElement, deleteCol, deleteRow, engine, evaluateTemplate, filterGroups, finalizeElementZone, findMainCell, generateGroupId, generateId, getDemoData, getElementBindings, getPaperDimensions, getPaperSizeMM, getSpanRect, getTableCellBindings, getZoneRects, groupFields, insertCol, insertRow, isContinuousPaperSize, isLabelPaperSize, labelPaperDefaults, matchKeywords, mergeCells, minorStepMM, mmToPx, nextWheelScale, normalizeSelection, normalizeTemplateUnits, ptToMm, pxToMm, resolveBarcodeDesignValue, resolveBarcodeSize, resolveCellBorderCss, resolveElementBorder, resolveTextBinding, safeEval, searchProperties, setHeaderRepeat, setRowType, splitCells, syncTableElementSize, useAlign, useBindingDisplay, useGroup, useKeyboard, useResize, zoneFromPaperPoint };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TemplateEngine
3
- } from "../chunk-AKWV6SID.js";
3
+ } from "../chunk-RXSLSQFO.js";
4
4
  import {
5
5
  BARCODE_BAR_HEIGHT_MODULES,
6
6
  BARCODE_MARGIN_BOTTOM_MODULES,
@@ -8,8 +8,10 @@ import {
8
8
  BARCODE_QUIET_ZONE_MODULES,
9
9
  BARCODE_TEXT_FONT_SIZE_MODULES,
10
10
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
11
+ ELEMENT_BORDER_SIDES,
11
12
  MIN_SHRINK_FONT_SIZE_PT,
12
13
  MM_PER_INCH,
14
+ acceptsElementBorder,
13
15
  addNumbers,
14
16
  avg,
15
17
  barcodeAvailableBoxMm,
@@ -33,6 +35,7 @@ import {
33
35
  pxToMm,
34
36
  resolveBarcodeSize,
35
37
  resolveCellTextFit,
38
+ resolveElementBorder,
36
39
  resolveElementTextFit,
37
40
  resolveShrinkMinFontSize,
38
41
  round,
@@ -43,7 +46,7 @@ import {
43
46
  subtractNumbers,
44
47
  sum,
45
48
  toUpperCaseAmount
46
- } from "../chunk-KFRPTLFV.js";
49
+ } from "../chunk-DCQGN54P.js";
47
50
 
48
51
  // src/designer/utils/scale.ts
49
52
  var MIN_SCALE_PERCENT = 25;
@@ -1650,6 +1653,7 @@ export {
1650
1653
  DEFAULT_DEMO_DATA,
1651
1654
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
1652
1655
  ELEMENT_BINDING_REGISTRY,
1656
+ ELEMENT_BORDER_SIDES,
1653
1657
  EXTENDED_FUNCTIONS,
1654
1658
  FIT_SCALE_MIN_PERCENT,
1655
1659
  GHOST_BORDER_CSS,
@@ -1664,6 +1668,7 @@ export {
1664
1668
  RESIZE_POINTS,
1665
1669
  RULER_THICKNESS,
1666
1670
  ZONE_ALLOWED_TYPES,
1671
+ acceptsElementBorder,
1667
1672
  applyBorderPreset,
1668
1673
  barcodeAvailableBoxMm,
1669
1674
  barcodePreferredModuleWidthMm,
@@ -1722,6 +1727,7 @@ export {
1722
1727
  resolveBarcodeSize,
1723
1728
  resolveCellBorderCss,
1724
1729
  resolveCellTextFit,
1730
+ resolveElementBorder,
1725
1731
  resolveElementTextFit,
1726
1732
  resolveShrinkMinFontSize,
1727
1733
  resolveTextBinding,
@@ -362,6 +362,14 @@ interface ElementFieldBinding {
362
362
  text?: string;
363
363
  dataSource?: string;
364
364
  }
365
+ /** 元素分边边框的边位 */
366
+ type ElementBorderSide = 'top' | 'right' | 'bottom' | 'left';
367
+ /** 元素单边边框规格(px 口径,与整圈 borderWidth 一致;区别于单元格的 pt 口径) */
368
+ interface ElementBorderEdge {
369
+ width: number;
370
+ style?: string;
371
+ color?: string;
372
+ }
365
373
  /** 元素选项(序列化到 JSON) */
366
374
  interface ElementOptions {
367
375
  left: number;
@@ -393,6 +401,8 @@ interface ElementOptions {
393
401
  borderWidth?: number;
394
402
  borderStyle?: string;
395
403
  borderColor?: string;
404
+ /** 元素分边边框(px 口径):在整圈三字段之上逐边覆盖;未设整圈时仅这些边生效 */
405
+ borders?: Partial<Record<ElementBorderSide, ElementBorderEdge>>;
396
406
  contentPaddingLeft?: number;
397
407
  contentPaddingTop?: number;
398
408
  contentPaddingRight?: number;
@@ -932,4 +942,4 @@ interface DriverFactory {
932
942
  createDriver(): Promise<PageDriver>;
933
943
  }
934
944
 
935
- export { type PrintJob as $, type AdsorbResult as A, type BindingDescriptor as B, type CodeRenderer as C, type DriverFactory as D, type ElementOptions as E, type TextAlign as F, type TextFit as G, type UploadImageFn as H, type MeasuredElement as I, type TemplateElement as J, type PaperMm as K, type ViewportPx as L, type MultiPageTemplateData as M, type HeightSource as N, type MarginsMm as O, type PageLayout as P, type PdfTargetSpec as Q, type RawMeasurement as R, type ScreenshotRequest as S, type TemplateData as T, type UploadDesignBackgroundFn as U, type VerticalAlign as V, type WatermarkOptions as W, type ScreenshotTargetSpec as X, type CodeRenderOptions as Y, type ExecutorBundle as Z, type TileLayout as _, type CodeSpec as a, type PreparedDocument as a0, type RenderPdfResult as a1, type PrintFontDeclaration as a2, type ContinuousPaperSize as a3, EXECUTOR_TARGETS as a4, type ExecutorMethod as a5, type ExecutorTargetKind as a6, FALLBACK_FONT_STACK as a7, MAX_BATCH_COPIES as a8, type NormalizedPrintData as a9, resolveSheetMm as aA, roundMm as aB, tilePosition as aC, toFontFamilyStack as aD, validateTiling as aE, PAPER_DIMENSIONS as aa, type PageDriver as ab, type PageSection as ac, type PaperSize as ad, type PrintDataInput as ae, type PrintFontFile as af, type RenderCell as ag, type RenderRequest as ah, type RenderRow as ai, type SheetPaperSize as aj, TILE_DEFAULTS as ak, TilingError as al, type TilingIssue as am, type TilingIssueCode as an, type TilingOptions as ao, type TilingResolveOptions as ap, type TilingTemplateInput as aq, buildFontFaceCss as ar, computeMaxColumns as as, computeTileLayout as at, escapeInlineStyleValue as au, getPaperDimensions as av, isContinuousPaper as aw, isContinuousPaperSize as ax, normalizePrintData as ay, normalizeTilingOptions as az, type TemplateData$1 as b, type TableRow as c, type TableCellBorder as d, type TableCell as e, type TableRowType as f, type ElementType as g, type RuntimeElement as h, type ElementZone as i, type PrintBusinessField as j, type ElementRect as k, type ResizePoint as l, type AlignLine as m, type DesignBackground as n, type ElementFieldBinding as o, type MultiPageTemplateData$1 as p, type PaginationConfig$1 as q, type PaperSize$1 as r, type PrintElementData as s, type PrintElementTypeMeta as t, type RequestScreenshotFn as u, type TableCellBorders as v, type TableCellType as w, type TablePaginationConfig$1 as x, type TableSelection as y, type TemplateElement$1 as z };
945
+ export { type ExecutorBundle as $, type AdsorbResult as A, type BindingDescriptor as B, type CodeRenderer as C, type DriverFactory as D, type ElementBorderSide as E, type TableSelection as F, type TemplateElement$1 as G, type TextAlign as H, type TextFit as I, type UploadImageFn as J, type MeasuredElement as K, type TemplateElement as L, type MultiPageTemplateData as M, type PaperMm as N, type ViewportPx as O, type PageLayout as P, type HeightSource as Q, type RawMeasurement as R, type ScreenshotRequest as S, type TemplateData as T, type UploadDesignBackgroundFn as U, type VerticalAlign as V, type WatermarkOptions as W, type MarginsMm as X, type PdfTargetSpec as Y, type ScreenshotTargetSpec as Z, type CodeRenderOptions as _, type CodeSpec as a, type TileLayout as a0, type PrintJob as a1, type PreparedDocument as a2, type RenderPdfResult as a3, type PrintFontDeclaration as a4, type ContinuousPaperSize as a5, EXECUTOR_TARGETS as a6, type ExecutorMethod as a7, type ExecutorTargetKind as a8, FALLBACK_FONT_STACK as a9, normalizePrintData as aA, normalizeTilingOptions as aB, resolveSheetMm as aC, roundMm as aD, tilePosition as aE, toFontFamilyStack as aF, validateTiling as aG, MAX_BATCH_COPIES as aa, type NormalizedPrintData as ab, PAPER_DIMENSIONS as ac, type PageDriver as ad, type PageSection as ae, type PaperSize as af, type PrintDataInput as ag, type PrintFontFile as ah, type RenderCell as ai, type RenderRequest as aj, type RenderRow as ak, type SheetPaperSize as al, TILE_DEFAULTS as am, TilingError as an, type TilingIssue as ao, type TilingIssueCode as ap, type TilingOptions as aq, type TilingResolveOptions as ar, type TilingTemplateInput as as, buildFontFaceCss as at, computeMaxColumns as au, computeTileLayout as av, escapeInlineStyleValue as aw, getPaperDimensions as ax, isContinuousPaper as ay, isContinuousPaperSize as az, type ElementOptions as b, type TemplateData$1 as c, type TableRow as d, type TableCellBorder as e, type TableCell as f, type TableRowType as g, type ElementType as h, type RuntimeElement as i, type ElementZone as j, type PrintBusinessField as k, type ElementRect as l, type ResizePoint as m, type AlignLine as n, type DesignBackground as o, type ElementBorderEdge as p, type ElementFieldBinding as q, type MultiPageTemplateData$1 as r, type PaginationConfig$1 as s, type PaperSize$1 as t, type PrintElementData as u, type PrintElementTypeMeta as v, type RequestScreenshotFn as w, type TableCellBorders as x, type TableCellType as y, type TablePaginationConfig$1 as z };
@@ -362,6 +362,14 @@ interface ElementFieldBinding {
362
362
  text?: string;
363
363
  dataSource?: string;
364
364
  }
365
+ /** 元素分边边框的边位 */
366
+ type ElementBorderSide = 'top' | 'right' | 'bottom' | 'left';
367
+ /** 元素单边边框规格(px 口径,与整圈 borderWidth 一致;区别于单元格的 pt 口径) */
368
+ interface ElementBorderEdge {
369
+ width: number;
370
+ style?: string;
371
+ color?: string;
372
+ }
365
373
  /** 元素选项(序列化到 JSON) */
366
374
  interface ElementOptions {
367
375
  left: number;
@@ -393,6 +401,8 @@ interface ElementOptions {
393
401
  borderWidth?: number;
394
402
  borderStyle?: string;
395
403
  borderColor?: string;
404
+ /** 元素分边边框(px 口径):在整圈三字段之上逐边覆盖;未设整圈时仅这些边生效 */
405
+ borders?: Partial<Record<ElementBorderSide, ElementBorderEdge>>;
396
406
  contentPaddingLeft?: number;
397
407
  contentPaddingTop?: number;
398
408
  contentPaddingRight?: number;
@@ -932,4 +942,4 @@ interface DriverFactory {
932
942
  createDriver(): Promise<PageDriver>;
933
943
  }
934
944
 
935
- export { type PrintJob as $, type AdsorbResult as A, type BindingDescriptor as B, type CodeRenderer as C, type DriverFactory as D, type ElementOptions as E, type TextAlign as F, type TextFit as G, type UploadImageFn as H, type MeasuredElement as I, type TemplateElement as J, type PaperMm as K, type ViewportPx as L, type MultiPageTemplateData as M, type HeightSource as N, type MarginsMm as O, type PageLayout as P, type PdfTargetSpec as Q, type RawMeasurement as R, type ScreenshotRequest as S, type TemplateData as T, type UploadDesignBackgroundFn as U, type VerticalAlign as V, type WatermarkOptions as W, type ScreenshotTargetSpec as X, type CodeRenderOptions as Y, type ExecutorBundle as Z, type TileLayout as _, type CodeSpec as a, type PreparedDocument as a0, type RenderPdfResult as a1, type PrintFontDeclaration as a2, type ContinuousPaperSize as a3, EXECUTOR_TARGETS as a4, type ExecutorMethod as a5, type ExecutorTargetKind as a6, FALLBACK_FONT_STACK as a7, MAX_BATCH_COPIES as a8, type NormalizedPrintData as a9, resolveSheetMm as aA, roundMm as aB, tilePosition as aC, toFontFamilyStack as aD, validateTiling as aE, PAPER_DIMENSIONS as aa, type PageDriver as ab, type PageSection as ac, type PaperSize as ad, type PrintDataInput as ae, type PrintFontFile as af, type RenderCell as ag, type RenderRequest as ah, type RenderRow as ai, type SheetPaperSize as aj, TILE_DEFAULTS as ak, TilingError as al, type TilingIssue as am, type TilingIssueCode as an, type TilingOptions as ao, type TilingResolveOptions as ap, type TilingTemplateInput as aq, buildFontFaceCss as ar, computeMaxColumns as as, computeTileLayout as at, escapeInlineStyleValue as au, getPaperDimensions as av, isContinuousPaper as aw, isContinuousPaperSize as ax, normalizePrintData as ay, normalizeTilingOptions as az, type TemplateData$1 as b, type TableRow as c, type TableCellBorder as d, type TableCell as e, type TableRowType as f, type ElementType as g, type RuntimeElement as h, type ElementZone as i, type PrintBusinessField as j, type ElementRect as k, type ResizePoint as l, type AlignLine as m, type DesignBackground as n, type ElementFieldBinding as o, type MultiPageTemplateData$1 as p, type PaginationConfig$1 as q, type PaperSize$1 as r, type PrintElementData as s, type PrintElementTypeMeta as t, type RequestScreenshotFn as u, type TableCellBorders as v, type TableCellType as w, type TablePaginationConfig$1 as x, type TableSelection as y, type TemplateElement$1 as z };
945
+ export { type ExecutorBundle as $, type AdsorbResult as A, type BindingDescriptor as B, type CodeRenderer as C, type DriverFactory as D, type ElementBorderSide as E, type TableSelection as F, type TemplateElement$1 as G, type TextAlign as H, type TextFit as I, type UploadImageFn as J, type MeasuredElement as K, type TemplateElement as L, type MultiPageTemplateData as M, type PaperMm as N, type ViewportPx as O, type PageLayout as P, type HeightSource as Q, type RawMeasurement as R, type ScreenshotRequest as S, type TemplateData as T, type UploadDesignBackgroundFn as U, type VerticalAlign as V, type WatermarkOptions as W, type MarginsMm as X, type PdfTargetSpec as Y, type ScreenshotTargetSpec as Z, type CodeRenderOptions as _, type CodeSpec as a, type TileLayout as a0, type PrintJob as a1, type PreparedDocument as a2, type RenderPdfResult as a3, type PrintFontDeclaration as a4, type ContinuousPaperSize as a5, EXECUTOR_TARGETS as a6, type ExecutorMethod as a7, type ExecutorTargetKind as a8, FALLBACK_FONT_STACK as a9, normalizePrintData as aA, normalizeTilingOptions as aB, resolveSheetMm as aC, roundMm as aD, tilePosition as aE, toFontFamilyStack as aF, validateTiling as aG, MAX_BATCH_COPIES as aa, type NormalizedPrintData as ab, PAPER_DIMENSIONS as ac, type PageDriver as ad, type PageSection as ae, type PaperSize as af, type PrintDataInput as ag, type PrintFontFile as ah, type RenderCell as ai, type RenderRequest as aj, type RenderRow as ak, type SheetPaperSize as al, TILE_DEFAULTS as am, TilingError as an, type TilingIssue as ao, type TilingIssueCode as ap, type TilingOptions as aq, type TilingResolveOptions as ar, type TilingTemplateInput as as, buildFontFaceCss as at, computeMaxColumns as au, computeTileLayout as av, escapeInlineStyleValue as aw, getPaperDimensions as ax, isContinuousPaper as ay, isContinuousPaperSize as az, type ElementOptions as b, type TemplateData$1 as c, type TableRow as d, type TableCellBorder as e, type TableCell as f, type TableRowType as g, type ElementType as h, type RuntimeElement as i, type ElementZone as j, type PrintBusinessField as k, type ElementRect as l, type ResizePoint as m, type AlignLine as n, type DesignBackground as o, type ElementBorderEdge as p, type ElementFieldBinding as q, type MultiPageTemplateData$1 as r, type PaginationConfig$1 as s, type PaperSize$1 as t, type PrintElementData as u, type PrintElementTypeMeta as v, type RequestScreenshotFn as w, type TableCellBorders as x, type TableCellType as y, type TablePaginationConfig$1 as z };
package/dist/index.cjs CHANGED
@@ -1728,6 +1728,35 @@ function cellFitCapMm(rows, rowIndex, cell, defaultPadding = 1) {
1728
1728
  return Math.max(height - padding * 2 - borderMm, 0.5);
1729
1729
  }
1730
1730
 
1731
+ // src/render/element-border.ts
1732
+ var ELEMENT_BORDER_SIDES = ["top", "right", "bottom", "left"];
1733
+ var SELF_BORDER_TYPES = /* @__PURE__ */ new Set(["rect", "oval", "hline", "vline", "table"]);
1734
+ var VALID_STYLES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double"]);
1735
+ function parseBorder(width, style, color) {
1736
+ if (typeof width !== "number" || !Number.isFinite(width) || width <= 0) return null;
1737
+ return {
1738
+ borderWidth: `${width}px`,
1739
+ borderStyle: typeof style === "string" && VALID_STYLES.has(style) ? style : "solid",
1740
+ borderColor: color || "#000"
1741
+ };
1742
+ }
1743
+ function resolveElementBorder(type, opts) {
1744
+ if (!type || SELF_BORDER_TYPES.has(type)) return null;
1745
+ const all = parseBorder(opts?.borderWidth, opts?.borderStyle, opts?.borderColor);
1746
+ const edges = {};
1747
+ const src = opts?.borders;
1748
+ if (src) {
1749
+ for (const side of ELEMENT_BORDER_SIDES) {
1750
+ const edge = src[side];
1751
+ if (!edge) continue;
1752
+ const css = parseBorder(edge.width, edge.style, edge.color);
1753
+ if (css) edges[side] = css;
1754
+ }
1755
+ }
1756
+ if (!all && Object.keys(edges).length === 0) return null;
1757
+ return { all, edges };
1758
+ }
1759
+
1731
1760
  // src/render/watermark.ts
1732
1761
  var PX_PER_MM = 96 / 25.4;
1733
1762
  var MM_PER_PX = 25.4 / 96;
@@ -1893,10 +1922,9 @@ function tableDesignBottom(el) {
1893
1922
  const opts = el.options ?? {};
1894
1923
  const top = opts.top ?? 0;
1895
1924
  const rows = opts.tableRows ?? [];
1896
- if (rows.length > 0) {
1897
- return top + rows.reduce((s, r) => s + (r.height ?? 0), 0);
1898
- }
1899
- return top + (opts.height ?? 0);
1925
+ const rowSum = rows.reduce((s, r) => s + (r.height ?? 0), 0);
1926
+ const designHeight = Math.max(opts.height ?? 0, rowSum);
1927
+ return top + designHeight;
1900
1928
  }
1901
1929
  function buildFollowMap(sorted, excludedIds) {
1902
1930
  const map = /* @__PURE__ */ new Map();
@@ -2037,7 +2065,10 @@ function paginate(template, measuredElements) {
2037
2065
  let isFirstPage = true;
2038
2066
  let pageBroken = false;
2039
2067
  function sectionTop(el) {
2040
- return pageBroken ? 0 : el.options?.top ?? 0;
2068
+ return pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2069
+ }
2070
+ function pageCursorTop() {
2071
+ return Math.max(0, fullPageHeight() - remaining);
2041
2072
  }
2042
2073
  function fullPageHeight() {
2043
2074
  return isFirstPage ? contentHeight - overlayH - SAFETY_MARGIN : contentHeight - SAFETY_MARGIN;
@@ -2104,7 +2135,7 @@ function paginate(template, measuredElements) {
2104
2135
  function paginateNonTable(el, measured, sortedList, idx) {
2105
2136
  const elHeight = measured.get(el.id)?.measuredHeight ?? el.options?.height ?? 0;
2106
2137
  if (elHeight <= remaining) {
2107
- const top2 = pageBroken ? 0 : el.options?.top ?? 0;
2138
+ const top2 = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2108
2139
  noteOverflow(top2 + elHeight);
2109
2140
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
2110
2141
  remaining -= elHeight;
@@ -2123,8 +2154,9 @@ function paginate(template, measuredElements) {
2123
2154
  }
2124
2155
  return idx + 1;
2125
2156
  }
2126
- const top = pageBroken ? 0 : el.options?.top ?? 0;
2127
- finishPage(top + elHeight > contentHeight);
2157
+ finishPage();
2158
+ const top = pageBroken ? pageCursorTop() : el.options?.top ?? 0;
2159
+ if (top + elHeight > contentHeight) overflowOnCurrent = true;
2128
2160
  currentPage.push({ elementId: el.id, type: "element", renderTop: sectionTop(el) });
2129
2161
  remaining -= elHeight;
2130
2162
  return idx + 1;
@@ -2140,7 +2172,7 @@ function paginate(template, measuredElements) {
2140
2172
  }
2141
2173
  const unitHeight = Math.max(maxBottom - minTop, 0);
2142
2174
  const place = () => {
2143
- const offset = pageBroken ? -minTop : 0;
2175
+ const offset = pageBroken ? pageCursorTop() - minTop : 0;
2144
2176
  noteOverflow(minTop + offset + unitHeight);
2145
2177
  for (const m of members) {
2146
2178
  currentPage.push({
@@ -2214,6 +2246,7 @@ function paginate(template, measuredElements) {
2214
2246
  const groups = buildRowGroups(bodyRows, rowCount);
2215
2247
  let sliceStart = 0;
2216
2248
  let firstSlice = true;
2249
+ let sliceTop = sectionTop(el);
2217
2250
  for (const g of groups) {
2218
2251
  const gh = bodyHeights.slice(g.start, g.end).reduce((s, h) => s + h, 0);
2219
2252
  if (gh + subtotalH <= remaining) {
@@ -2228,12 +2261,13 @@ function paginate(template, measuredElements) {
2228
2261
  endRow: g.start,
2229
2262
  subtotal: subtotalH > 0,
2230
2263
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2231
- renderTop: sectionTop(el)
2264
+ renderTop: sliceTop
2232
2265
  });
2233
2266
  firstSlice = false;
2234
2267
  sliceStart = g.start;
2235
2268
  }
2236
2269
  finishPage();
2270
+ sliceTop = sectionTop(el);
2237
2271
  if (!firstSlice) remaining -= repeatH;
2238
2272
  remaining -= gh;
2239
2273
  }
@@ -2245,7 +2279,7 @@ function paginate(template, measuredElements) {
2245
2279
  endRow: rowCount,
2246
2280
  subtotal: subtotalH > 0,
2247
2281
  ...!firstSlice && repeatCount > 0 ? { repeatHeader: true } : {},
2248
- renderTop: sectionTop(el)
2282
+ renderTop: sliceTop
2249
2283
  });
2250
2284
  }
2251
2285
  if (summaryH > 0) {
@@ -2543,7 +2577,18 @@ function renderElement(el, isMeasure, containerStyle, overrideTop, ctx) {
2543
2577
  const type = el.type || el.printElementType?.type || "text";
2544
2578
  const fit = resolveElementTextFit(type, opts);
2545
2579
  const fitHeight = fit === "autoHeight" ? void 0 : height;
2546
- const style = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2580
+ const baseStyle = containerStyle ?? elementPositionStyle(left, top, width, fitHeight, opts.zIndex);
2581
+ const elBorders = resolveElementBorder(type, opts);
2582
+ let style = baseStyle;
2583
+ if (elBorders?.all) {
2584
+ style += `border:${elBorders.all.borderWidth} ${elBorders.all.borderStyle} ${elBorders.all.borderColor};`;
2585
+ }
2586
+ if (elBorders) {
2587
+ for (const side of ELEMENT_BORDER_SIDES) {
2588
+ const e = elBorders.edges[side];
2589
+ if (e) style += `border-${side}:${e.borderWidth} ${e.borderStyle} ${e.borderColor};`;
2590
+ }
2591
+ }
2547
2592
  const measureAttr = isMeasure ? ` data-measure-id="${el.id}"` : "";
2548
2593
  const fitAttr = fitAttrs(fit, el.id, opts.fontSize ?? 12, opts);
2549
2594
  switch (type) {
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { T as TemplateData, C as CodeRenderer, P as PageLayout, I as MeasuredElement, J as TemplateElement, W as WatermarkOptions, K as PaperMm, L as ViewportPx, N as HeightSource, O as MarginsMm, Q as PdfTargetSpec, X as ScreenshotTargetSpec, R as RawMeasurement, a as CodeSpec, Y as CodeRenderOptions, D as DriverFactory, Z as ExecutorBundle, _ as TileLayout, $ as PrintJob, a0 as PreparedDocument, a1 as RenderPdfResult, M as MultiPageTemplateData, a2 as PrintFontDeclaration } from './driver-Dn_YAzO5.cjs';
2
- export { a3 as ContinuousPaperSize, a4 as EXECUTOR_TARGETS, a5 as ExecutorMethod, a6 as ExecutorTargetKind, a7 as FALLBACK_FONT_STACK, a8 as MAX_BATCH_COPIES, a9 as NormalizedPrintData, aa as PAPER_DIMENSIONS, ab as PageDriver, ac as PageSection, ad as PaperSize, ae as PrintDataInput, af as PrintFontFile, ag as RenderCell, ah as RenderRequest, ai as RenderRow, aj as SheetPaperSize, ak as TILE_DEFAULTS, G as TextFit, al as TilingError, am as TilingIssue, an as TilingIssueCode, ao as TilingOptions, ap as TilingResolveOptions, aq as TilingTemplateInput, ar as buildFontFaceCss, as as computeMaxColumns, at as computeTileLayout, au as escapeInlineStyleValue, av as getPaperDimensions, aw as isContinuousPaper, ax as isContinuousPaperSize, ay as normalizePrintData, az as normalizeTilingOptions, aA as resolveSheetMm, aB as roundMm, aC as tilePosition, aD as toFontFamilyStack, aE as validateTiling } from './driver-Dn_YAzO5.cjs';
3
- import { F as FitFontSize, P as PrintRuntime } from './ports-Cf5sjwls.cjs';
4
- export { C as CellFitRowKind, h as DEFAULT_READINESS_MS, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, i as DEFAULT_TIMEOUT_MS, M as MIN_SHRINK_FONT_SIZE_PT, j as MeasureResult, k as PrintSession, S as SessionBudget, c as cellFitCapMm, a as cellFitKey, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from './ports-Cf5sjwls.cjs';
1
+ import { T as TemplateData, C as CodeRenderer, P as PageLayout, K as MeasuredElement, L as TemplateElement, W as WatermarkOptions, N as PaperMm, O as ViewportPx, Q as HeightSource, X as MarginsMm, Y as PdfTargetSpec, Z as ScreenshotTargetSpec, R as RawMeasurement, a as CodeSpec, _ as CodeRenderOptions, D as DriverFactory, $ as ExecutorBundle, a0 as TileLayout, a1 as PrintJob, a2 as PreparedDocument, a3 as RenderPdfResult, M as MultiPageTemplateData, a4 as PrintFontDeclaration } from './driver-CNJVZK_L.cjs';
2
+ export { a5 as ContinuousPaperSize, a6 as EXECUTOR_TARGETS, a7 as ExecutorMethod, a8 as ExecutorTargetKind, a9 as FALLBACK_FONT_STACK, aa as MAX_BATCH_COPIES, ab as NormalizedPrintData, ac as PAPER_DIMENSIONS, ad as PageDriver, ae as PageSection, af as PaperSize, ag as PrintDataInput, ah as PrintFontFile, ai as RenderCell, aj as RenderRequest, ak as RenderRow, al as SheetPaperSize, am as TILE_DEFAULTS, I as TextFit, an as TilingError, ao as TilingIssue, ap as TilingIssueCode, aq as TilingOptions, ar as TilingResolveOptions, as as TilingTemplateInput, at as buildFontFaceCss, au as computeMaxColumns, av as computeTileLayout, aw as escapeInlineStyleValue, ax as getPaperDimensions, ay as isContinuousPaper, az as isContinuousPaperSize, aA as normalizePrintData, aB as normalizeTilingOptions, aC as resolveSheetMm, aD as roundMm, aE as tilePosition, aF as toFontFamilyStack, aG as validateTiling } from './driver-CNJVZK_L.cjs';
3
+ import { F as FitFontSize, P as PrintRuntime } from './ports-DeEgE2SL.cjs';
4
+ export { C as CellFitRowKind, h as DEFAULT_READINESS_MS, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, i as DEFAULT_TIMEOUT_MS, M as MIN_SHRINK_FONT_SIZE_PT, j as MeasureResult, k as PrintSession, S as SessionBudget, c as cellFitCapMm, a as cellFitKey, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from './ports-DeEgE2SL.cjs';
5
5
 
6
6
  type TokenType = 'num' | 'str' | 'bool' | 'ident' | 'punc';
7
7
  interface Token {
@@ -232,8 +232,11 @@ declare function elementPositionStyle(left: number, top: number, width: number,
232
232
 
233
233
  /**
234
234
  * 表格设计底部(mm)= 设计 top + 设计高度。
235
- * 设计高度优先取 tableRows 设计行高之和(设计意图,不受渲染数据量影响),
236
- * 缺失时回退 options.height。
235
+ * 设计高度取 max(options.height, tableRows 行高之和):
236
+ * - options.height 是设计器实测回写的渲染高度(用户在画布上所见并据此对齐下方元素的底部),
237
+ * 为相对布局偏移的忠实基准;
238
+ * - tableRows 行高之和是 min-height 语义下表格实际渲染的物理下界,
239
+ * 当 options.height 缺失或被低估时兜底,避免跟随元素偏移算成负值反向叠压表格。
237
240
  */
238
241
  declare function tableDesignBottom(el: TemplateElement): number;
239
242
  /**
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { T as TemplateData, C as CodeRenderer, P as PageLayout, I as MeasuredElement, J as TemplateElement, W as WatermarkOptions, K as PaperMm, L as ViewportPx, N as HeightSource, O as MarginsMm, Q as PdfTargetSpec, X as ScreenshotTargetSpec, R as RawMeasurement, a as CodeSpec, Y as CodeRenderOptions, D as DriverFactory, Z as ExecutorBundle, _ as TileLayout, $ as PrintJob, a0 as PreparedDocument, a1 as RenderPdfResult, M as MultiPageTemplateData, a2 as PrintFontDeclaration } from './driver-Dn_YAzO5.js';
2
- export { a3 as ContinuousPaperSize, a4 as EXECUTOR_TARGETS, a5 as ExecutorMethod, a6 as ExecutorTargetKind, a7 as FALLBACK_FONT_STACK, a8 as MAX_BATCH_COPIES, a9 as NormalizedPrintData, aa as PAPER_DIMENSIONS, ab as PageDriver, ac as PageSection, ad as PaperSize, ae as PrintDataInput, af as PrintFontFile, ag as RenderCell, ah as RenderRequest, ai as RenderRow, aj as SheetPaperSize, ak as TILE_DEFAULTS, G as TextFit, al as TilingError, am as TilingIssue, an as TilingIssueCode, ao as TilingOptions, ap as TilingResolveOptions, aq as TilingTemplateInput, ar as buildFontFaceCss, as as computeMaxColumns, at as computeTileLayout, au as escapeInlineStyleValue, av as getPaperDimensions, aw as isContinuousPaper, ax as isContinuousPaperSize, ay as normalizePrintData, az as normalizeTilingOptions, aA as resolveSheetMm, aB as roundMm, aC as tilePosition, aD as toFontFamilyStack, aE as validateTiling } from './driver-Dn_YAzO5.js';
3
- import { F as FitFontSize, P as PrintRuntime } from './ports-BvwlA_km.js';
4
- export { C as CellFitRowKind, h as DEFAULT_READINESS_MS, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, i as DEFAULT_TIMEOUT_MS, M as MIN_SHRINK_FONT_SIZE_PT, j as MeasureResult, k as PrintSession, S as SessionBudget, c as cellFitCapMm, a as cellFitKey, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from './ports-BvwlA_km.js';
1
+ import { T as TemplateData, C as CodeRenderer, P as PageLayout, K as MeasuredElement, L as TemplateElement, W as WatermarkOptions, N as PaperMm, O as ViewportPx, Q as HeightSource, X as MarginsMm, Y as PdfTargetSpec, Z as ScreenshotTargetSpec, R as RawMeasurement, a as CodeSpec, _ as CodeRenderOptions, D as DriverFactory, $ as ExecutorBundle, a0 as TileLayout, a1 as PrintJob, a2 as PreparedDocument, a3 as RenderPdfResult, M as MultiPageTemplateData, a4 as PrintFontDeclaration } from './driver-CNJVZK_L.js';
2
+ export { a5 as ContinuousPaperSize, a6 as EXECUTOR_TARGETS, a7 as ExecutorMethod, a8 as ExecutorTargetKind, a9 as FALLBACK_FONT_STACK, aa as MAX_BATCH_COPIES, ab as NormalizedPrintData, ac as PAPER_DIMENSIONS, ad as PageDriver, ae as PageSection, af as PaperSize, ag as PrintDataInput, ah as PrintFontFile, ai as RenderCell, aj as RenderRequest, ak as RenderRow, al as SheetPaperSize, am as TILE_DEFAULTS, I as TextFit, an as TilingError, ao as TilingIssue, ap as TilingIssueCode, aq as TilingOptions, ar as TilingResolveOptions, as as TilingTemplateInput, at as buildFontFaceCss, au as computeMaxColumns, av as computeTileLayout, aw as escapeInlineStyleValue, ax as getPaperDimensions, ay as isContinuousPaper, az as isContinuousPaperSize, aA as normalizePrintData, aB as normalizeTilingOptions, aC as resolveSheetMm, aD as roundMm, aE as tilePosition, aF as toFontFamilyStack, aG as validateTiling } from './driver-CNJVZK_L.js';
3
+ import { F as FitFontSize, P as PrintRuntime } from './ports-DSfECjvT.js';
4
+ export { C as CellFitRowKind, h as DEFAULT_READINESS_MS, D as DEFAULT_SHRINK_MIN_FONT_SIZE_PT, i as DEFAULT_TIMEOUT_MS, M as MIN_SHRINK_FONT_SIZE_PT, j as MeasureResult, k as PrintSession, S as SessionBudget, c as cellFitCapMm, a as cellFitKey, f as floorFontSize, p as parseCellFitKey, r as resolveCellTextFit, d as resolveElementTextFit, e as resolveShrinkMinFontSize, g as roundFontSize } from './ports-DSfECjvT.js';
5
5
 
6
6
  type TokenType = 'num' | 'str' | 'bool' | 'ident' | 'punc';
7
7
  interface Token {
@@ -232,8 +232,11 @@ declare function elementPositionStyle(left: number, top: number, width: number,
232
232
 
233
233
  /**
234
234
  * 表格设计底部(mm)= 设计 top + 设计高度。
235
- * 设计高度优先取 tableRows 设计行高之和(设计意图,不受渲染数据量影响),
236
- * 缺失时回退 options.height。
235
+ * 设计高度取 max(options.height, tableRows 行高之和):
236
+ * - options.height 是设计器实测回写的渲染高度(用户在画布上所见并据此对齐下方元素的底部),
237
+ * 为相对布局偏移的忠实基准;
238
+ * - tableRows 行高之和是 min-height 语义下表格实际渲染的物理下界,
239
+ * 当 options.height 缺失或被低估时兜底,避免跟随元素偏移算成负值反向叠压表格。
237
240
  */
238
241
  declare function tableDesignBottom(el: TemplateElement): number;
239
242
  /**
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TemplateEngine
3
- } from "./chunk-AKWV6SID.js";
3
+ } from "./chunk-RXSLSQFO.js";
4
4
  import {
5
5
  DEFAULT_READINESS_MS,
6
6
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
@@ -121,7 +121,7 @@ import {
121
121
  tokenize,
122
122
  validateTiling,
123
123
  withTimeout
124
- } from "./chunk-KFRPTLFV.js";
124
+ } from "./chunk-DCQGN54P.js";
125
125
  export {
126
126
  DEFAULT_READINESS_MS,
127
127
  DEFAULT_SHRINK_MIN_FONT_SIZE_PT,
@@ -1,4 +1,4 @@
1
- import { Z as ExecutorBundle } from '../driver-Dn_YAzO5.cjs';
1
+ import { $ as ExecutorBundle } from '../driver-CNJVZK_L.cjs';
2
2
 
3
3
  /** 读取 core 自带的 DOM 执行器 IIFE 产物;宿主把它注入页面后即可调用 __wormDom */
4
4
  declare function loadExecutorBundle(): ExecutorBundle;
@@ -1,4 +1,4 @@
1
- import { Z as ExecutorBundle } from '../driver-Dn_YAzO5.js';
1
+ import { $ as ExecutorBundle } from '../driver-CNJVZK_L.js';
2
2
 
3
3
  /** 读取 core 自带的 DOM 执行器 IIFE 产物;宿主把它注入页面后即可调用 __wormDom */
4
4
  declare function loadExecutorBundle(): ExecutorBundle;
@@ -1,4 +1,4 @@
1
- import { G as TextFit, a as CodeSpec, L as ViewportPx, R as RawMeasurement, Q as PdfTargetSpec, X as ScreenshotTargetSpec } from './driver-Dn_YAzO5.js';
1
+ import { I as TextFit, a as CodeSpec, O as ViewportPx, R as RawMeasurement, Y as PdfTargetSpec, Z as ScreenshotTargetSpec } from './driver-CNJVZK_L.js';
2
2
 
3
3
  /** 自动缩小的默认下限字号(pt) */
4
4
  declare const DEFAULT_SHRINK_MIN_FONT_SIZE_PT = 6;
@@ -1,4 +1,4 @@
1
- import { G as TextFit, a as CodeSpec, L as ViewportPx, R as RawMeasurement, Q as PdfTargetSpec, X as ScreenshotTargetSpec } from './driver-Dn_YAzO5.cjs';
1
+ import { I as TextFit, a as CodeSpec, O as ViewportPx, R as RawMeasurement, Y as PdfTargetSpec, Z as ScreenshotTargetSpec } from './driver-CNJVZK_L.cjs';
2
2
 
3
3
  /** 自动缩小的默认下限字号(pt) */
4
4
  declare const DEFAULT_SHRINK_MIN_FONT_SIZE_PT = 6;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worm-vue3-print/core",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "type": "module",
5
5
  "description": "打印模板表达式引擎、同构渲染管线与框架无关的设计器内核(HTML 生成/分页/数据绑定/设计器模型与工具),无 Vue/React 依赖",
6
6
  "main": "dist/index.cjs",