@canvas-components/list-table 0.3.19 → 0.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3,9 +3,30 @@
3
3
  var utils = require('@canvas-components/utils');
4
4
  var barcode = require('@canvas-components/barcode');
5
5
  var chart = require('@canvas-components/chart');
6
+ var antDesignIcons = require('@ant-design/icons-svg');
6
7
  var qrcode = require('@canvas-components/qrcode');
7
8
  var stats = require('@canvas-components/stats');
8
9
 
10
+ function _interopNamespace(e) {
11
+ if (e && e.__esModule) return e;
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var antDesignIcons__namespace = /*#__PURE__*/_interopNamespace(antDesignIcons);
29
+
9
30
  var __defProp = Object.defineProperty;
10
31
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
32
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -4534,7 +4555,7 @@ function drawImagePlaceholder(ctx, x, y, width, height, backgroundColor = PLACEH
4534
4555
  ctx.fill();
4535
4556
  }
4536
4557
 
4537
- // src/rendering/cell-content/draw-symbol.ts
4558
+ // src/rendering/icons/draw-symbol.ts
4538
4559
  var SYMBOL_COLOR_MAP = {
4539
4560
  star: "#fadb14",
4540
4561
  sun: "#faad14",
@@ -4558,6 +4579,11 @@ function drawCellSymbol(ctx, params) {
4558
4579
  return;
4559
4580
  }
4560
4581
  appendCellSymbolPath(ctx, type, x, y, size);
4582
+ if (fillRatio >= 1) {
4583
+ ctx.fillStyle = activeColor;
4584
+ ctx.fill("evenodd");
4585
+ return;
4586
+ }
4561
4587
  ctx.fillStyle = inactiveColor;
4562
4588
  ctx.fill("evenodd");
4563
4589
  if (fillRatio <= 0) {
@@ -4605,6 +4631,12 @@ function drawStatusSymbol(ctx, params) {
4605
4631
  ctx.lineJoin = "round";
4606
4632
  ctx.lineWidth = Math.max(size * 0.12, 1.5);
4607
4633
  appendStatusSymbolPath(ctx, type, x, y, size);
4634
+ if (fillRatio >= 1) {
4635
+ ctx.strokeStyle = activeColor;
4636
+ ctx.stroke();
4637
+ ctx.restore();
4638
+ return;
4639
+ }
4608
4640
  ctx.strokeStyle = inactiveColor;
4609
4641
  ctx.stroke();
4610
4642
  if (fillRatio > 0) {
@@ -4668,6 +4700,838 @@ function appendMoonPath(ctx, x, y, size) {
4668
4700
  ctx.closePath();
4669
4701
  }
4670
4702
 
4703
+ // src/rendering/icons/icon-stroke.ts
4704
+ function resolveIconStroke(ctx) {
4705
+ const identity = (value) => value;
4706
+ const fallback = { width: 2, snapX: identity, snapY: identity };
4707
+ const transform = ctx.getTransform?.();
4708
+ if (!transform || ![
4709
+ transform.a,
4710
+ transform.b,
4711
+ transform.c,
4712
+ transform.d,
4713
+ transform.e,
4714
+ transform.f
4715
+ ].every(Number.isFinite))
4716
+ return fallback;
4717
+ if (Math.abs(transform.b) > 1e-8 || Math.abs(transform.c) > 1e-8 || transform.a <= 0 || Math.abs(transform.a - transform.d) > 1e-8)
4718
+ return fallback;
4719
+ const scale = transform.a;
4720
+ const pixels = Math.max(1, Math.round(2 * scale));
4721
+ const phase = pixels % 2 / 2;
4722
+ const snap = (value, translation) => (Math.round(value * scale + translation - phase) + phase - translation) / scale;
4723
+ return {
4724
+ width: pixels / scale,
4725
+ snapX: (value) => snap(value, transform.e),
4726
+ snapY: (value) => snap(value, transform.f)
4727
+ };
4728
+ }
4729
+ var listTableBuiltinIconNames = [
4730
+ "star",
4731
+ "sun",
4732
+ "moon",
4733
+ "check",
4734
+ "close",
4735
+ "circle",
4736
+ "check-circle",
4737
+ "close-circle",
4738
+ "clock-circle",
4739
+ "info-circle",
4740
+ "question-circle",
4741
+ "warning",
4742
+ "loading",
4743
+ "plus",
4744
+ "minus",
4745
+ "plus-circle",
4746
+ "minus-circle",
4747
+ "up",
4748
+ "down",
4749
+ "left",
4750
+ "right",
4751
+ "arrow-up",
4752
+ "arrow-down",
4753
+ "arrow-left",
4754
+ "arrow-right",
4755
+ "search",
4756
+ "edit",
4757
+ "delete",
4758
+ "copy",
4759
+ "save",
4760
+ "upload",
4761
+ "download",
4762
+ "reload",
4763
+ "ellipsis",
4764
+ "file",
4765
+ "file-text",
4766
+ "file-pdf",
4767
+ "folder",
4768
+ "folder-open",
4769
+ "picture",
4770
+ "user",
4771
+ "team",
4772
+ "calendar",
4773
+ "filter",
4774
+ "sort-ascending",
4775
+ "sort-descending",
4776
+ "link",
4777
+ "eye",
4778
+ "lock",
4779
+ "unlock",
4780
+ "home",
4781
+ "mail",
4782
+ "setting",
4783
+ "header-sort",
4784
+ "header-sort-ascending",
4785
+ "header-sort-descending",
4786
+ "header-filter",
4787
+ "header-fixed"
4788
+ ];
4789
+ var listTableAntdIconNames = Object.keys(
4790
+ antDesignIcons__namespace
4791
+ );
4792
+ var listTableIconNames = [
4793
+ ...listTableBuiltinIconNames,
4794
+ ...listTableAntdIconNames
4795
+ ];
4796
+ function getAntdIconDefinition(name) {
4797
+ return Object.prototype.hasOwnProperty.call(antDesignIcons__namespace, name) ? antDesignIcons__namespace[name] : void 0;
4798
+ }
4799
+
4800
+ // src/rendering/icons/svg-path.ts
4801
+ function parseSvgPath(source) {
4802
+ const output = [];
4803
+ let offset = 0, command = "", previous = "", x = 0, y = 0, startX = 0, startY = 0, controlX = 0, controlY = 0;
4804
+ const skip = () => {
4805
+ while (/[\s,]/.test(source[offset] ?? "!") && offset < source.length)
4806
+ offset++;
4807
+ };
4808
+ const number = (flag = false) => {
4809
+ skip();
4810
+ const match = source.slice(offset).match(flag ? /^[01]/ : /^[-+]?(?:\d*\.\d+|\d+\.?\d*)(?:[eE][-+]?\d+)?/);
4811
+ if (!match) throw new Error(`\u65E0\u6548 SVG \u8DEF\u5F84\u53C2\u6570\uFF0C\u4F4D\u7F6E ${offset}`);
4812
+ offset += match[0].length;
4813
+ const value = Number(match[0]);
4814
+ if (!Number.isFinite(value)) throw new Error("SVG \u8DEF\u5F84\u5305\u542B\u975E\u6709\u9650\u5750\u6807");
4815
+ return value;
4816
+ };
4817
+ while (offset < source.length) {
4818
+ skip();
4819
+ if (offset >= source.length) break;
4820
+ if (/[a-z]/i.test(source[offset])) command = source[offset++];
4821
+ else if (!command) throw new Error(`\u7F3A\u5C11 SVG \u8DEF\u5F84\u547D\u4EE4\uFF0C\u4F4D\u7F6E ${offset}`);
4822
+ const upper = command.toUpperCase();
4823
+ const relative = upper !== command;
4824
+ const point = () => [
4825
+ number() + (relative ? x : 0),
4826
+ number() + (relative ? y : 0)
4827
+ ];
4828
+ if (upper === "Z") {
4829
+ output.push({ op: "Z", args: [] });
4830
+ x = startX;
4831
+ y = startY;
4832
+ command = "";
4833
+ } else if (upper === "M" || upper === "L") {
4834
+ const target = point();
4835
+ output.push({ op: upper, args: target });
4836
+ [x, y] = target;
4837
+ if (upper === "M") {
4838
+ startX = x;
4839
+ startY = y;
4840
+ command = relative ? "l" : "L";
4841
+ }
4842
+ } else if (upper === "H" || upper === "V") {
4843
+ const value = number();
4844
+ if (upper === "H") x = value + (relative ? x : 0);
4845
+ else y = value + (relative ? y : 0);
4846
+ output.push({ op: "L", args: [x, y] });
4847
+ } else if (upper === "C" || upper === "S") {
4848
+ const first = upper === "C" ? point() : [
4849
+ /[CS]/.test(previous) ? 2 * x - controlX : x,
4850
+ /[CS]/.test(previous) ? 2 * y - controlY : y
4851
+ ];
4852
+ const second = point();
4853
+ const target = point();
4854
+ output.push({ op: "C", args: [...first, ...second, ...target] });
4855
+ [controlX, controlY] = second;
4856
+ [x, y] = target;
4857
+ } else if (upper === "Q" || upper === "T") {
4858
+ const control = upper === "Q" ? point() : [
4859
+ /[QT]/.test(previous) ? 2 * x - controlX : x,
4860
+ /[QT]/.test(previous) ? 2 * y - controlY : y
4861
+ ];
4862
+ const target = point();
4863
+ output.push({ op: "Q", args: [...control, ...target] });
4864
+ [controlX, controlY] = control;
4865
+ [x, y] = target;
4866
+ } else if (upper === "A") {
4867
+ const rx = number(), ry = number(), rotation = number(), large = number(true), sweep = number(true);
4868
+ const target = point();
4869
+ output.push(
4870
+ ...arcCommands(
4871
+ x,
4872
+ y,
4873
+ rx,
4874
+ ry,
4875
+ rotation,
4876
+ large,
4877
+ sweep,
4878
+ target[0],
4879
+ target[1]
4880
+ )
4881
+ );
4882
+ [x, y] = target;
4883
+ } else throw new Error(`\u4E0D\u652F\u6301\u7684 SVG \u8DEF\u5F84\u547D\u4EE4 ${command}`);
4884
+ previous = upper;
4885
+ }
4886
+ return output;
4887
+ }
4888
+ function arcCommands(x1, y1, rx, ry, rotation, large, sweep, x2, y2) {
4889
+ if (x1 === x2 && y1 === y2) return [];
4890
+ rx = Math.abs(rx);
4891
+ ry = Math.abs(ry);
4892
+ if (!rx || !ry) return [{ op: "L", args: [x2, y2] }];
4893
+ const phi = rotation * Math.PI / 180, cos = Math.cos(phi), sin = Math.sin(phi);
4894
+ const px = cos * (x1 - x2) / 2 + sin * (y1 - y2) / 2;
4895
+ const py = -sin * (x1 - x2) / 2 + cos * (y1 - y2) / 2;
4896
+ const scale = Math.max(
4897
+ 1,
4898
+ Math.sqrt(px * px / (rx * rx) + py * py / (ry * ry))
4899
+ );
4900
+ rx *= scale;
4901
+ ry *= scale;
4902
+ const denominator = rx * rx * py * py + ry * ry * px * px;
4903
+ const factor = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, (rx * rx * ry * ry - denominator) / denominator));
4904
+ const cxp = factor * rx * py / ry, cyp = -factor * ry * px / rx;
4905
+ const cx = cos * cxp - sin * cyp + (x1 + x2) / 2, cy = sin * cxp + cos * cyp + (y1 + y2) / 2;
4906
+ const start = Math.atan2((py - cyp) / ry, (px - cxp) / rx);
4907
+ const finish = Math.atan2((-py - cyp) / ry, (-px - cxp) / rx);
4908
+ let delta = finish - start;
4909
+ if (sweep && delta < 0) delta += Math.PI * 2;
4910
+ if (!sweep && delta > 0) delta -= Math.PI * 2;
4911
+ const count = Math.max(1, Math.ceil(Math.abs(delta) / (Math.PI / 2)));
4912
+ const step = delta / count;
4913
+ const point = (angle) => [
4914
+ cx + rx * cos * Math.cos(angle) - ry * sin * Math.sin(angle),
4915
+ cy + rx * sin * Math.cos(angle) + ry * cos * Math.sin(angle)
4916
+ ];
4917
+ const derivative = (angle) => [
4918
+ -rx * cos * Math.sin(angle) - ry * sin * Math.cos(angle),
4919
+ -rx * sin * Math.sin(angle) + ry * cos * Math.cos(angle)
4920
+ ];
4921
+ return Array.from({ length: count }, (_, index) => {
4922
+ const a = start + step * index, b = a + step, k = 4 / 3 * Math.tan(step / 4);
4923
+ const p = point(a), q = point(b), dp = derivative(a), dq = derivative(b);
4924
+ return {
4925
+ op: "C",
4926
+ args: [
4927
+ p[0] + k * dp[0],
4928
+ p[1] + k * dp[1],
4929
+ q[0] - k * dq[0],
4930
+ q[1] - k * dq[1],
4931
+ ...index === count - 1 ? [x2, y2] : q
4932
+ ]
4933
+ };
4934
+ });
4935
+ }
4936
+ function traceSvgPath(ctx, commands) {
4937
+ ctx.beginPath();
4938
+ for (const { op, args: a } of commands) {
4939
+ if (op === "M") ctx.moveTo(a[0], a[1]);
4940
+ else if (op === "L") ctx.lineTo(a[0], a[1]);
4941
+ else if (op === "C") ctx.bezierCurveTo(a[0], a[1], a[2], a[3], a[4], a[5]);
4942
+ else if (op === "Q") ctx.quadraticCurveTo(a[0], a[1], a[2], a[3]);
4943
+ else ctx.closePath();
4944
+ }
4945
+ }
4946
+
4947
+ // src/rendering/icons/draw-antd-icon.ts
4948
+ var pathCache = /* @__PURE__ */ new Map();
4949
+ var CACHE_LIMIT = 256;
4950
+ function secondaryColor(primary) {
4951
+ let hex = primary.replace(/^#/, "");
4952
+ if (/^[\da-f]{3}$/i.test(hex))
4953
+ hex = [...hex].map((char) => char + char).join("");
4954
+ if (!/^[\da-f]{6}$/i.test(hex)) return "#e6f4ff";
4955
+ const channels = [0, 2, 4].map(
4956
+ (start) => Math.round(255 * 0.85 + parseInt(hex.slice(start, start + 2), 16) * 0.15)
4957
+ );
4958
+ return `rgb(${channels.join(",")})`;
4959
+ }
4960
+ function drawAntdIcon(ctx, params) {
4961
+ const definition = getAntdIconDefinition(params.type);
4962
+ if (!definition) return false;
4963
+ const primary = Array.isArray(params.twoToneColor) ? params.twoToneColor[0] : params.twoToneColor ?? params.color;
4964
+ const secondary = Array.isArray(params.twoToneColor) ? params.twoToneColor[1] : secondaryColor(primary);
4965
+ const root = typeof definition.icon === "function" ? definition.icon(primary, secondary) : definition.icon;
4966
+ const [vx, vy, vw, vh] = (root.attrs.viewBox ?? "0 0 1024 1024").split(/[\s,]+/).map(Number);
4967
+ ctx.save();
4968
+ try {
4969
+ const scale = params.size / Math.max(vw, vh);
4970
+ ctx.translate(
4971
+ params.x + (params.size - vw * scale) / 2,
4972
+ params.y + (params.size - vh * scale) / 2
4973
+ );
4974
+ ctx.scale(scale, scale);
4975
+ ctx.translate(-vx, -vy);
4976
+ drawNode(ctx, root, primary);
4977
+ } finally {
4978
+ ctx.restore();
4979
+ }
4980
+ return true;
4981
+ }
4982
+ function drawNode(ctx, node, inheritedColor) {
4983
+ if (node.tag === "defs" || node.tag === "style") return;
4984
+ const color = node.attrs.fill ?? inheritedColor;
4985
+ ctx.save();
4986
+ try {
4987
+ const opacity = Number(node.attrs["fill-opacity"] ?? 1);
4988
+ ctx.globalAlpha *= Number.isFinite(opacity) ? Math.max(0, Math.min(opacity, 1)) : 1;
4989
+ if (node.tag === "path" && node.attrs.d && color !== "none") {
4990
+ ctx.fillStyle = color === "currentColor" ? inheritedColor : color;
4991
+ const data = node.attrs.d;
4992
+ let entry = pathCache.get(data);
4993
+ if (entry) pathCache.delete(data);
4994
+ else if (typeof Path2D === "function") {
4995
+ try {
4996
+ entry = { path: new Path2D(data) };
4997
+ } catch {
4998
+ entry = { commands: parseSvgPath(data) };
4999
+ }
5000
+ } else entry = { commands: parseSvgPath(data) };
5001
+ pathCache.set(data, entry);
5002
+ if (pathCache.size > CACHE_LIMIT)
5003
+ pathCache.delete(pathCache.keys().next().value);
5004
+ const rule = node.attrs["fill-rule"] === "evenodd" ? "evenodd" : "nonzero";
5005
+ if (entry.path) ctx.fill(entry.path, rule);
5006
+ else {
5007
+ traceSvgPath(ctx, entry.commands);
5008
+ ctx.fill(rule);
5009
+ }
5010
+ }
5011
+ for (const child of node.children ?? []) drawNode(ctx, child, color);
5012
+ } finally {
5013
+ ctx.restore();
5014
+ }
5015
+ }
5016
+
5017
+ // src/rendering/icons/draw-header-action-icon.ts
5018
+ var FILTER_ICON_VIEWBOX_SIZE = 1024;
5019
+ var FILTER_ICON_PATH_DATA = "M922.366667 114.813333A53.04 53.04 0 0 0 874.666667 85.333333H149.333333a53.333333 53.333333 0 0 0-42.666666 85.333334l277.333333 369.78V917.333333a21.333333 21.333333 0 0 0 29.253333 19.806667l213.333334-85.333333A21.333333 21.333333 0 0 0 640 832V540.446667L917.333333 170.666667a53.04 53.04 0 0 0 5.033334-55.853334z";
5020
+ var FIXED_PIN_VIEWBOX_SIZE = 1024;
5021
+ var FIXED_PIN_PATH_DATA = "M963.925333 326.997333L697.002667 60.074667a25.6 25.6 0 0 0-43.52 21.845333l14.506666 99.498667-273.066666 151.381333c-91.477333-45.738667-170.666667-36.693333-234.496 27.306667a25.941333 25.941333 0 0 0 0 36.352L327.68 563.2 57.685333 930.645333a25.6 25.6 0 0 0 35.84 35.669334l366.250667-270.677334 167.765333 167.936a25.941333 25.941333 0 0 0 36.352 0c79.530667-79.701333 58.538667-165.546667 26.965334-233.813333l152.064-273.066667 99.157333 14.165334a25.6 25.6 0 0 0 26.624-13.824 25.941333 25.941333 0 0 0-4.778667-30.037334z";
5022
+ var filterIconPath = null;
5023
+ var fixedPinPath = null;
5024
+ function drawHeaderActionGlyph(ctx, rect, actionType, color = "#8c8c8c", sortOrder = null, activeColor = "#1677ff") {
5025
+ ctx.save();
5026
+ ctx.strokeStyle = color;
5027
+ ctx.fillStyle = color;
5028
+ if (actionType === "sort") {
5029
+ ctx.beginPath();
5030
+ ctx.fillStyle = sortOrder === "ascend" ? activeColor : color;
5031
+ ctx.moveTo(rect.x + rect.width / 2, rect.y + 1);
5032
+ ctx.lineTo(rect.x + rect.width - 2, rect.y + 6);
5033
+ ctx.lineTo(rect.x + 2, rect.y + 6);
5034
+ ctx.closePath();
5035
+ ctx.fill();
5036
+ ctx.beginPath();
5037
+ ctx.fillStyle = sortOrder === "descend" ? activeColor : color;
5038
+ ctx.moveTo(rect.x + 2, rect.y + rect.height - 6);
5039
+ ctx.lineTo(rect.x + rect.width - 2, rect.y + rect.height - 6);
5040
+ ctx.lineTo(rect.x + rect.width / 2, rect.y + rect.height - 1);
5041
+ ctx.closePath();
5042
+ ctx.fill();
5043
+ } else if (actionType === "filter") {
5044
+ drawFilterIcon(ctx, rect);
5045
+ } else {
5046
+ drawFixedPinIcon(ctx, rect);
5047
+ }
5048
+ ctx.restore();
5049
+ }
5050
+ function drawFilterIcon(ctx, rect) {
5051
+ const iconWidth = rect.width * 0.92;
5052
+ const iconHeight = rect.height * 0.7;
5053
+ const offsetX = rect.x + (rect.width - iconWidth) / 2;
5054
+ const offsetY = rect.y + (rect.height - iconHeight) / 2;
5055
+ const path = resolveIconPath("filter");
5056
+ if (path) {
5057
+ ctx.save();
5058
+ ctx.translate(offsetX, offsetY);
5059
+ ctx.scale(
5060
+ iconWidth / FILTER_ICON_VIEWBOX_SIZE,
5061
+ iconHeight / FILTER_ICON_VIEWBOX_SIZE
5062
+ );
5063
+ ctx.fill(path);
5064
+ ctx.restore();
5065
+ return;
5066
+ }
5067
+ ctx.beginPath();
5068
+ ctx.moveTo(offsetX, offsetY);
5069
+ ctx.lineTo(offsetX + iconWidth, offsetY);
5070
+ ctx.lineTo(offsetX + iconWidth * 0.62, offsetY + iconHeight * 0.52);
5071
+ ctx.lineTo(offsetX + iconWidth * 0.62, offsetY + iconHeight);
5072
+ ctx.lineTo(offsetX + iconWidth * 0.38, offsetY + iconHeight * 0.88);
5073
+ ctx.lineTo(offsetX + iconWidth * 0.38, offsetY + iconHeight * 0.52);
5074
+ ctx.closePath();
5075
+ ctx.fill();
5076
+ }
5077
+ function drawFixedPinIcon(ctx, rect) {
5078
+ const iconSize = Math.min(rect.width, rect.height) * 0.92;
5079
+ const offsetX = rect.x + (rect.width - iconSize) / 2;
5080
+ const offsetY = rect.y + (rect.height - iconSize) / 2;
5081
+ const scale = iconSize / FIXED_PIN_VIEWBOX_SIZE;
5082
+ const path = resolveIconPath("fixed");
5083
+ if (path) {
5084
+ ctx.save();
5085
+ ctx.translate(offsetX, offsetY);
5086
+ ctx.scale(scale, scale);
5087
+ ctx.fill(path);
5088
+ ctx.restore();
5089
+ return;
5090
+ }
5091
+ ctx.beginPath();
5092
+ ctx.moveTo(offsetX + iconSize * 0.68, offsetY);
5093
+ ctx.lineTo(offsetX + iconSize, offsetY + iconSize * 0.32);
5094
+ ctx.lineTo(offsetX + iconSize * 0.78, offsetY + iconSize * 0.34);
5095
+ ctx.lineTo(offsetX + iconSize * 0.62, offsetY + iconSize * 0.64);
5096
+ ctx.lineTo(offsetX + iconSize * 0.74, offsetY + iconSize * 0.76);
5097
+ ctx.lineTo(offsetX + iconSize * 0.52, offsetY + iconSize * 0.82);
5098
+ ctx.lineTo(offsetX + iconSize * 0.16, offsetY + iconSize);
5099
+ ctx.lineTo(offsetX + iconSize * 0.34, offsetY + iconSize * 0.64);
5100
+ ctx.lineTo(offsetX + iconSize * 0.2, offsetY + iconSize * 0.5);
5101
+ ctx.lineTo(offsetX + iconSize * 0.5, offsetY + iconSize * 0.34);
5102
+ ctx.closePath();
5103
+ ctx.fill();
5104
+ }
5105
+ function resolveIconPath(type) {
5106
+ if (typeof Path2D === "undefined") return null;
5107
+ if (type === "filter") {
5108
+ filterIconPath ?? (filterIconPath = new Path2D(FILTER_ICON_PATH_DATA));
5109
+ return filterIconPath;
5110
+ }
5111
+ fixedPinPath ?? (fixedPinPath = new Path2D(FIXED_PIN_PATH_DATA));
5112
+ return fixedPinPath;
5113
+ }
5114
+
5115
+ // src/rendering/icons/draw-icon.ts
5116
+ function resolveIconColor(type, fallback = "#1f2329") {
5117
+ if (isLegacy(type)) return resolveCellSymbolColor(type);
5118
+ if (type === "check-circle") return "#52c41a";
5119
+ if (type === "close-circle") return "#ff4d4f";
5120
+ if (type === "warning") return "#faad14";
5121
+ if (type === "info-circle" || type === "question-circle") return "#1677ff";
5122
+ if (type.endsWith("TwoTone")) return "#1677ff";
5123
+ if (type.startsWith("header-")) return "#8c8c8c";
5124
+ return fallback;
5125
+ }
5126
+ function isLegacy(type) {
5127
+ return type === "star" || type === "sun" || type === "moon" || type === "check" || type === "close";
5128
+ }
5129
+ function drawIcon(ctx, params) {
5130
+ const { type, x, y, size } = params;
5131
+ if (![x, y, size].every(Number.isFinite) || size <= 0) return;
5132
+ const color = params.color ?? resolveIconColor(type);
5133
+ if (drawAntdIcon(ctx, { ...params, color })) return;
5134
+ ctx.save();
5135
+ try {
5136
+ if (type.startsWith("header-")) {
5137
+ ctx.translate(x, y);
5138
+ ctx.scale(size / 14, size / 14);
5139
+ drawHeaderActionGlyph(
5140
+ ctx,
5141
+ { x: 0, y: 0, width: 14, height: 14 },
5142
+ type === "header-filter" ? "filter" : type === "header-fixed" ? "fixed" : "sort",
5143
+ color,
5144
+ type === "header-sort-ascending" ? "ascend" : type === "header-sort-descending" ? "descend" : null,
5145
+ params.color ?? "#1677ff"
5146
+ );
5147
+ return;
5148
+ }
5149
+ if (isLegacy(type)) {
5150
+ drawCellSymbol(ctx, {
5151
+ type,
5152
+ x,
5153
+ y,
5154
+ size,
5155
+ activeColor: color,
5156
+ inactiveColor: color,
5157
+ fillRatio: 1
5158
+ });
5159
+ return;
5160
+ }
5161
+ ctx.translate(x, y);
5162
+ ctx.scale(size / 24, size / 24);
5163
+ ctx.strokeStyle = color;
5164
+ ctx.fillStyle = color;
5165
+ const stroke = resolveIconStroke(ctx);
5166
+ ctx.lineWidth = stroke.width;
5167
+ ctx.lineCap = "round";
5168
+ ctx.lineJoin = "round";
5169
+ ctx.setLineDash([]);
5170
+ appendIconPath(ctx, type, stroke);
5171
+ ctx.stroke();
5172
+ } finally {
5173
+ ctx.restore();
5174
+ }
5175
+ }
5176
+ function appendIconPath(ctx, type, stroke) {
5177
+ const line = (...points) => {
5178
+ const aligned = [...points];
5179
+ for (let i = 2; i < points.length; i += 2) {
5180
+ if (points[i - 2] === points[i])
5181
+ aligned[i - 2] = aligned[i] = stroke.snapX(points[i]);
5182
+ if (points[i - 1] === points[i + 1])
5183
+ aligned[i - 1] = aligned[i + 1] = stroke.snapY(points[i + 1]);
5184
+ }
5185
+ ctx.moveTo(aligned[0], aligned[1]);
5186
+ for (let i = 2; i < aligned.length; i += 2)
5187
+ ctx.lineTo(aligned[i], aligned[i + 1]);
5188
+ };
5189
+ const rect = (x, y, width, height) => {
5190
+ const left = stroke.snapX(x);
5191
+ const top = stroke.snapY(y);
5192
+ ctx.rect(
5193
+ left,
5194
+ top,
5195
+ stroke.snapX(x + width) - left,
5196
+ stroke.snapY(y + height) - top
5197
+ );
5198
+ };
5199
+ const circle = (x = 12, y = 12, r = 9) => {
5200
+ ctx.moveTo(x + r, y);
5201
+ ctx.arc(x, y, r, 0, Math.PI * 2);
5202
+ };
5203
+ const plus = () => {
5204
+ line(7, 12, 17, 12);
5205
+ line(12, 7, 12, 17);
5206
+ };
5207
+ const check = () => line(7, 12, 10.5, 15.5, 17, 8.5);
5208
+ const cross = () => {
5209
+ line(8, 8, 16, 16);
5210
+ line(16, 8, 8, 16);
5211
+ };
5212
+ const file = () => {
5213
+ line(5, 3, 14, 3, 19, 8, 19, 21, 5, 21, 5, 3);
5214
+ line(14, 3, 14, 8, 19, 8);
5215
+ };
5216
+ ctx.beginPath();
5217
+ switch (type) {
5218
+ case "circle":
5219
+ circle();
5220
+ break;
5221
+ case "check-circle":
5222
+ circle();
5223
+ check();
5224
+ break;
5225
+ case "close-circle":
5226
+ circle();
5227
+ cross();
5228
+ break;
5229
+ case "clock-circle":
5230
+ circle();
5231
+ line(12, 6, 12, 12, 16, 14);
5232
+ break;
5233
+ case "info-circle":
5234
+ circle();
5235
+ line(12, 11, 12, 17);
5236
+ circle(12, 7, 0.4);
5237
+ break;
5238
+ case "question-circle":
5239
+ circle();
5240
+ ctx.moveTo(9, 8);
5241
+ ctx.bezierCurveTo(9, 4, 18, 6, 14, 11);
5242
+ line(14, 11, 12, 13, 12, 14);
5243
+ circle(12, 17, 0.4);
5244
+ break;
5245
+ case "warning":
5246
+ line(12, 3, 22, 20, 2, 20, 12, 3);
5247
+ line(12, 9, 12, 13);
5248
+ circle(12, 17, 0.4);
5249
+ break;
5250
+ case "loading":
5251
+ ctx.arc(12, 12, 9, -Math.PI / 2, Math.PI);
5252
+ break;
5253
+ case "plus":
5254
+ plus();
5255
+ break;
5256
+ case "minus":
5257
+ line(5, 12, 19, 12);
5258
+ break;
5259
+ case "plus-circle":
5260
+ circle();
5261
+ plus();
5262
+ break;
5263
+ case "minus-circle":
5264
+ circle();
5265
+ line(7, 12, 17, 12);
5266
+ break;
5267
+ case "up":
5268
+ line(5, 15, 12, 8, 19, 15);
5269
+ break;
5270
+ case "down":
5271
+ line(5, 9, 12, 16, 19, 9);
5272
+ break;
5273
+ case "left":
5274
+ line(15, 5, 8, 12, 15, 19);
5275
+ break;
5276
+ case "right":
5277
+ line(9, 5, 16, 12, 9, 19);
5278
+ break;
5279
+ case "arrow-up":
5280
+ line(12, 21, 12, 3);
5281
+ line(5, 10, 12, 3, 19, 10);
5282
+ break;
5283
+ case "arrow-down":
5284
+ line(12, 3, 12, 21);
5285
+ line(5, 14, 12, 21, 19, 14);
5286
+ break;
5287
+ case "arrow-left":
5288
+ line(21, 12, 3, 12);
5289
+ line(10, 5, 3, 12, 10, 19);
5290
+ break;
5291
+ case "arrow-right":
5292
+ line(3, 12, 21, 12);
5293
+ line(14, 5, 21, 12, 14, 19);
5294
+ break;
5295
+ case "search":
5296
+ circle(10, 10, 6.5);
5297
+ line(15, 15, 21, 21);
5298
+ break;
5299
+ case "edit":
5300
+ line(4, 15, 16, 3, 21, 8, 9, 20, 3, 21, 4, 15);
5301
+ line(13, 6, 18, 11);
5302
+ break;
5303
+ case "delete":
5304
+ line(3, 6, 21, 6);
5305
+ line(8, 6, 8, 3, 16, 3, 16, 6);
5306
+ line(5, 6, 6, 21, 18, 21, 19, 6);
5307
+ line(10, 10, 10, 17);
5308
+ line(14, 10, 14, 17);
5309
+ break;
5310
+ case "copy":
5311
+ rect(8, 8, 13, 13);
5312
+ line(16, 5, 16, 3, 3, 3, 3, 16, 5, 16);
5313
+ break;
5314
+ case "save":
5315
+ line(3, 3, 17, 3, 21, 7, 21, 21, 3, 21, 3, 3);
5316
+ rect(7, 3, 9, 6);
5317
+ rect(7, 14, 10, 7);
5318
+ break;
5319
+ case "upload":
5320
+ line(12, 17, 12, 3);
5321
+ line(7, 8, 12, 3, 17, 8);
5322
+ line(3, 16, 3, 21, 21, 21, 21, 16);
5323
+ break;
5324
+ case "download":
5325
+ line(12, 3, 12, 17);
5326
+ line(7, 12, 12, 17, 17, 12);
5327
+ line(3, 16, 3, 21, 21, 21, 21, 16);
5328
+ break;
5329
+ case "reload": {
5330
+ const end = Math.PI * 11 / 6;
5331
+ ctx.arc(12, 12, 8, Math.PI / 6, end);
5332
+ const tipX = 12 + 8 * Math.cos(end);
5333
+ const tipY = 12 + 8 * Math.sin(end);
5334
+ const arrowAngle = end + Math.PI / 2 - Math.PI / 9;
5335
+ const tangentX = Math.cos(arrowAngle);
5336
+ const tangentY = Math.sin(arrowAngle);
5337
+ const baseX = tipX - tangentX * 4;
5338
+ const baseY = tipY - tangentY * 4;
5339
+ line(
5340
+ baseX - tangentY * 3,
5341
+ baseY + tangentX * 3,
5342
+ tipX,
5343
+ tipY,
5344
+ baseX + tangentY * 3,
5345
+ baseY - tangentX * 3
5346
+ );
5347
+ break;
5348
+ }
5349
+ case "ellipsis":
5350
+ circle(5, 12, 1);
5351
+ circle(12, 12, 1);
5352
+ circle(19, 12, 1);
5353
+ break;
5354
+ case "file":
5355
+ file();
5356
+ break;
5357
+ case "file-text":
5358
+ file();
5359
+ line(8, 12, 16, 12);
5360
+ line(8, 16, 16, 16);
5361
+ break;
5362
+ case "file-pdf":
5363
+ file();
5364
+ line(8, 17, 8, 11, 11, 11, 12, 12, 12, 14, 8, 14);
5365
+ line(14, 17, 14, 12, 17, 12);
5366
+ line(14, 14.5, 16, 14.5);
5367
+ break;
5368
+ case "folder":
5369
+ line(2, 5, 9, 5, 11, 8, 22, 8, 22, 20, 2, 20, 2, 5);
5370
+ break;
5371
+ case "folder-open":
5372
+ line(2, 18, 2, 5, 9, 5, 11, 8, 20, 8, 20, 10);
5373
+ line(2, 20, 6, 11, 22, 11, 18, 20, 2, 20);
5374
+ break;
5375
+ case "picture":
5376
+ rect(3, 3, 18, 18);
5377
+ circle(8, 8, 2);
5378
+ line(3, 19, 9, 13, 13, 16, 17, 11, 21, 15);
5379
+ break;
5380
+ case "user":
5381
+ circle(12, 7, 4);
5382
+ ctx.moveTo(4, 21);
5383
+ ctx.bezierCurveTo(4, 10, 20, 10, 20, 21);
5384
+ break;
5385
+ case "team":
5386
+ circle(9, 7, 3.5);
5387
+ ctx.moveTo(2, 21);
5388
+ ctx.bezierCurveTo(2, 11, 16, 11, 16, 21);
5389
+ ctx.moveTo(17, 4);
5390
+ ctx.arc(17, 7, 3, -Math.PI / 2, Math.PI / 2);
5391
+ ctx.moveTo(18, 14);
5392
+ ctx.bezierCurveTo(22, 14, 22, 18, 22, 21);
5393
+ break;
5394
+ case "calendar":
5395
+ rect(3, 5, 18, 16);
5396
+ line(3, 10, 21, 10);
5397
+ line(8, 2, 8, 7);
5398
+ line(16, 2, 16, 7);
5399
+ line(7, 14, 10, 14);
5400
+ line(14, 14, 17, 14);
5401
+ line(7, 17, 10, 17);
5402
+ break;
5403
+ case "filter":
5404
+ line(3, 3, 21, 3, 14, 12, 14, 20, 10, 22, 10, 12, 3, 3);
5405
+ break;
5406
+ case "sort-ascending":
5407
+ line(4, 6, 18, 6);
5408
+ line(4, 12, 13, 12);
5409
+ line(4, 18, 8, 18);
5410
+ line(19, 10, 19, 21);
5411
+ line(16, 18, 19, 21, 22, 18);
5412
+ break;
5413
+ case "sort-descending":
5414
+ line(4, 6, 8, 6);
5415
+ line(4, 12, 13, 12);
5416
+ line(4, 18, 15, 18);
5417
+ line(19, 3, 19, 14);
5418
+ line(16, 6, 19, 3, 22, 6);
5419
+ break;
5420
+ case "link":
5421
+ line(8, 16, 16, 8);
5422
+ ctx.moveTo(10, 6);
5423
+ ctx.bezierCurveTo(16, -2, 26, 8, 18, 14);
5424
+ ctx.moveTo(14, 18);
5425
+ ctx.bezierCurveTo(8, 26, -2, 16, 6, 10);
5426
+ break;
5427
+ case "eye":
5428
+ ctx.moveTo(2, 12);
5429
+ ctx.bezierCurveTo(8, 2, 16, 2, 22, 12);
5430
+ ctx.bezierCurveTo(16, 22, 8, 22, 2, 12);
5431
+ circle(12, 12, 3);
5432
+ break;
5433
+ case "lock":
5434
+ rect(5, 10, 14, 11);
5435
+ ctx.moveTo(8, 10);
5436
+ ctx.lineTo(8, 7);
5437
+ ctx.arc(12, 7, 4, Math.PI, Math.PI * 2);
5438
+ ctx.lineTo(16, 10);
5439
+ line(12, 14, 12, 17);
5440
+ break;
5441
+ case "unlock":
5442
+ rect(5, 10, 14, 11);
5443
+ ctx.moveTo(8, 10);
5444
+ ctx.lineTo(8, 6);
5445
+ ctx.arc(12, 6, 4, Math.PI, Math.PI * 2);
5446
+ line(12, 14, 12, 17);
5447
+ break;
5448
+ case "home":
5449
+ line(2, 11, 12, 2, 22, 11);
5450
+ line(5, 9, 5, 21, 19, 21, 19, 9);
5451
+ line(9, 21, 9, 14, 15, 14, 15, 21);
5452
+ break;
5453
+ case "mail":
5454
+ rect(3, 5, 18, 14);
5455
+ line(3, 5, 12, 13, 21, 5);
5456
+ break;
5457
+ case "setting": {
5458
+ for (let i = 0; i <= 32; i++) {
5459
+ const angle = i / 32 * Math.PI * 2;
5460
+ const radius = i % 4 < 2 ? 10 : 8;
5461
+ const x = 12 + radius * Math.cos(angle);
5462
+ const y = 12 + radius * Math.sin(angle);
5463
+ if (!i) ctx.moveTo(x, y);
5464
+ else ctx.lineTo(x, y);
5465
+ }
5466
+ ctx.closePath();
5467
+ circle(12, 12, 3.5);
5468
+ break;
5469
+ }
5470
+ }
5471
+ }
5472
+
5473
+ // src/rendering/icons/draw-timeline-marker.ts
5474
+ var COLORS = {
5475
+ blue: "#1677ff",
5476
+ green: "#52c41a",
5477
+ red: "#ff4d4f",
5478
+ gray: "#8c8c8c"
5479
+ };
5480
+ function drawTimelineMarker(ctx, item, x, y, size, filled) {
5481
+ const color = COLORS[item.color ?? "blue"] ?? item.color ?? COLORS.blue;
5482
+ const radius = size / 2;
5483
+ ctx.save();
5484
+ try {
5485
+ if (item.loading) {
5486
+ drawIcon(ctx, {
5487
+ type: "loading",
5488
+ x: x - radius,
5489
+ y: y - radius,
5490
+ size,
5491
+ color
5492
+ });
5493
+ return;
5494
+ }
5495
+ const icon = item.icon ?? "circle";
5496
+ const type = icon === "cross" ? "close" : icon === "clock" ? "clock-circle" : icon;
5497
+ if (!filled && type.endsWith("-circle")) {
5498
+ const iconSize = size * 4 / 3;
5499
+ drawIcon(ctx, {
5500
+ type,
5501
+ x: x - iconSize / 2,
5502
+ y: y - iconSize / 2,
5503
+ size: iconSize,
5504
+ color
5505
+ });
5506
+ return;
5507
+ }
5508
+ ctx.strokeStyle = color;
5509
+ ctx.fillStyle = color;
5510
+ ctx.lineWidth = 2;
5511
+ ctx.beginPath();
5512
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
5513
+ if (filled) ctx.fill();
5514
+ else ctx.stroke();
5515
+ if (icon === "circle") return;
5516
+ drawIcon(ctx, {
5517
+ type,
5518
+ x: x - size * 0.36,
5519
+ y: y - size * 0.36,
5520
+ size: size * 0.72,
5521
+ color: filled ? "#fff" : color
5522
+ });
5523
+ } finally {
5524
+ ctx.restore();
5525
+ }
5526
+ }
5527
+
5528
+ // src/rendering/icons/file-type-icon.ts
5529
+ function createFileTypeIconSource(filename) {
5530
+ const extension = (filename.split(".").length > 1 ? filename.split(".").pop() : "FILE").toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 4) || "FILE";
5531
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28"><path d="M5 1h12l6 6v20H5z" fill="#eef4ff" stroke="#8caadb"/><path d="M17 1v7h6" fill="none" stroke="#8caadb"/><text x="14" y="20" text-anchor="middle" font-family="sans-serif" font-size="7" fill="#315b91">${extension}</text></svg>`;
5532
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`;
5533
+ }
5534
+
4671
5535
  // src/rendering/cell-content/draw-icon-content.ts
4672
5536
  var DEFAULT_ICON_SIZE = 20;
4673
5537
  function drawBodyIconContent(params) {
@@ -4687,17 +5551,16 @@ function drawBodyIconContent(params) {
4687
5551
  const size = Math.min(width, height);
4688
5552
  const left = cursorX + (width - size) / 2;
4689
5553
  const top = rect.y + (rect.height - size) / 2;
4690
- const color = content.style?.color ?? content.color ?? resolveCellSymbolColor(content.icon);
5554
+ const color = content.style?.color ?? content.color ?? (content.icon.startsWith("header-") ? void 0 : resolveIconColor(content.icon, params.theme?.textColor));
4691
5555
  ctx.save();
4692
5556
  ctx.globalAlpha *= resolveContentOpacity(content);
4693
- drawCellSymbol(ctx, {
5557
+ drawIcon(ctx, {
4694
5558
  type: content.icon,
4695
5559
  x: left,
4696
5560
  y: top,
4697
5561
  size,
4698
- activeColor: color,
4699
- inactiveColor: color,
4700
- fillRatio: 1
5562
+ color,
5563
+ twoToneColor: content.twoToneColor
4701
5564
  });
4702
5565
  ctx.restore();
4703
5566
  if (content.onClick || content.cursor) {
@@ -7496,7 +8359,7 @@ function resolveHeaderTextLayout(params) {
7496
8359
  Math.min(baseX - textLeft, textRight - baseX) * 2,
7497
8360
  0
7498
8361
  );
7499
- if (centeredWidth >= 12) {
8362
+ if (centeredWidth >= Math.max(params.contentWidth ?? 0, 12)) {
7500
8363
  return {
7501
8364
  align,
7502
8365
  x: baseX,
@@ -7555,12 +8418,6 @@ var ACTION_GAP2 = 4;
7555
8418
  var ACTION_SIZE2 = 14;
7556
8419
  var ACTION_PADDING_INLINE2 = 10;
7557
8420
  var GRID_LINE_OFFSET = 0.5;
7558
- var FILTER_ICON_VIEWBOX_SIZE = 1024;
7559
- var FILTER_ICON_PATH_DATA = "M922.366667 114.813333A53.04 53.04 0 0 0 874.666667 85.333333H149.333333a53.333333 53.333333 0 0 0-42.666666 85.333334l277.333333 369.78V917.333333a21.333333 21.333333 0 0 0 29.253333 19.806667l213.333334-85.333333A21.333333 21.333333 0 0 0 640 832V540.446667L917.333333 170.666667a53.04 53.04 0 0 0 5.033334-55.853334z";
7560
- var FIXED_PIN_VIEWBOX_SIZE = 1024;
7561
- var FIXED_PIN_PATH_DATA = "M963.925333 326.997333L697.002667 60.074667a25.6 25.6 0 0 0-43.52 21.845333l14.506666 99.498667-273.066666 151.381333c-91.477333-45.738667-170.666667-36.693333-234.496 27.306667a25.941333 25.941333 0 0 0 0 36.352L327.68 563.2 57.685333 930.645333a25.6 25.6 0 0 0 35.84 35.669334l366.250667-270.677334 167.765333 167.936a25.941333 25.941333 0 0 0 36.352 0c79.530667-79.701333 58.538667-165.546667 26.965334-233.813333l152.064-273.066667 99.157333 14.165334a25.6 25.6 0 0 0 26.624-13.824 25.941333 25.941333 0 0 0-4.778667-30.037334z";
7562
- var filterIconPath = null;
7563
- var fixedPinPath = null;
7564
8421
  var EMPTY_RANGE_HIGHLIGHT = {
7565
8422
  selectedColumnRange: null
7566
8423
  };
@@ -7956,9 +8813,14 @@ function isSameRect(left, right) {
7956
8813
  }
7957
8814
  function drawResizeHandles(params, rect, columnKey, fixed) {
7958
8815
  if (params.isResizable(columnKey)) {
8816
+ const rightHandleRect = getResizeHandleRect(params, rect, "right");
8817
+ const keys = params.leafColumnKeys;
8818
+ if (keys?.[keys.length - 1] === columnKey) {
8819
+ rightHandleRect.width += 5;
8820
+ }
7959
8821
  params.descriptors.push({
7960
8822
  kind: "resize-handle",
7961
- rect: getResizeHandleRect(params, rect, "right"),
8823
+ rect: rightHandleRect,
7962
8824
  columnKey,
7963
8825
  resizeEdge: "right",
7964
8826
  fixed
@@ -8042,95 +8904,13 @@ function drawHeaderActionIcon(ctx, rect, actionType, active, hovered = false, se
8042
8904
  ctx.fill();
8043
8905
  ctx.restore();
8044
8906
  }
8045
- const color = active ? "#1677ff" : "#8c8c8c";
8046
- ctx.save();
8047
- ctx.strokeStyle = color;
8048
- ctx.fillStyle = color;
8049
- if (actionType === "sort") {
8050
- ctx.beginPath();
8051
- ctx.fillStyle = sortOrder === "ascend" ? "#1677ff" : "#8c8c8c";
8052
- ctx.moveTo(rect.x + rect.width / 2, rect.y + 1);
8053
- ctx.lineTo(rect.x + rect.width - 2, rect.y + 6);
8054
- ctx.lineTo(rect.x + 2, rect.y + 6);
8055
- ctx.closePath();
8056
- ctx.fill();
8057
- ctx.beginPath();
8058
- ctx.fillStyle = sortOrder === "descend" ? "#1677ff" : "#8c8c8c";
8059
- ctx.moveTo(rect.x + 2, rect.y + rect.height - 6);
8060
- ctx.lineTo(rect.x + rect.width - 2, rect.y + rect.height - 6);
8061
- ctx.lineTo(rect.x + rect.width / 2, rect.y + rect.height - 1);
8062
- ctx.closePath();
8063
- ctx.fill();
8064
- } else if (actionType === "filter") {
8065
- drawFilterIcon(ctx, rect);
8066
- } else {
8067
- drawFixedPinIcon(ctx, rect);
8068
- }
8069
- ctx.restore();
8070
- }
8071
- function drawFilterIcon(ctx, rect) {
8072
- const iconWidth = rect.width * 0.92;
8073
- const iconHeight = rect.height * 0.7;
8074
- const offsetX = rect.x + (rect.width - iconWidth) / 2;
8075
- const offsetY = rect.y + (rect.height - iconHeight) / 2;
8076
- const path = resolveIconPath("filter");
8077
- if (path) {
8078
- ctx.save();
8079
- ctx.translate(offsetX, offsetY);
8080
- ctx.scale(
8081
- iconWidth / FILTER_ICON_VIEWBOX_SIZE,
8082
- iconHeight / FILTER_ICON_VIEWBOX_SIZE
8083
- );
8084
- ctx.fill(path);
8085
- ctx.restore();
8086
- return;
8087
- }
8088
- ctx.beginPath();
8089
- ctx.moveTo(offsetX, offsetY);
8090
- ctx.lineTo(offsetX + iconWidth, offsetY);
8091
- ctx.lineTo(offsetX + iconWidth * 0.62, offsetY + iconHeight * 0.52);
8092
- ctx.lineTo(offsetX + iconWidth * 0.62, offsetY + iconHeight);
8093
- ctx.lineTo(offsetX + iconWidth * 0.38, offsetY + iconHeight * 0.88);
8094
- ctx.lineTo(offsetX + iconWidth * 0.38, offsetY + iconHeight * 0.52);
8095
- ctx.closePath();
8096
- ctx.fill();
8097
- }
8098
- function drawFixedPinIcon(ctx, rect) {
8099
- const iconSize = Math.min(rect.width, rect.height) * 0.92;
8100
- const offsetX = rect.x + (rect.width - iconSize) / 2;
8101
- const offsetY = rect.y + (rect.height - iconSize) / 2;
8102
- const scale = iconSize / FIXED_PIN_VIEWBOX_SIZE;
8103
- const path = resolveIconPath("fixed");
8104
- if (path) {
8105
- ctx.save();
8106
- ctx.translate(offsetX, offsetY);
8107
- ctx.scale(scale, scale);
8108
- ctx.fill(path);
8109
- ctx.restore();
8110
- return;
8111
- }
8112
- ctx.beginPath();
8113
- ctx.moveTo(offsetX + iconSize * 0.68, offsetY);
8114
- ctx.lineTo(offsetX + iconSize, offsetY + iconSize * 0.32);
8115
- ctx.lineTo(offsetX + iconSize * 0.78, offsetY + iconSize * 0.34);
8116
- ctx.lineTo(offsetX + iconSize * 0.62, offsetY + iconSize * 0.64);
8117
- ctx.lineTo(offsetX + iconSize * 0.74, offsetY + iconSize * 0.76);
8118
- ctx.lineTo(offsetX + iconSize * 0.52, offsetY + iconSize * 0.82);
8119
- ctx.lineTo(offsetX + iconSize * 0.16, offsetY + iconSize);
8120
- ctx.lineTo(offsetX + iconSize * 0.34, offsetY + iconSize * 0.64);
8121
- ctx.lineTo(offsetX + iconSize * 0.2, offsetY + iconSize * 0.5);
8122
- ctx.lineTo(offsetX + iconSize * 0.5, offsetY + iconSize * 0.34);
8123
- ctx.closePath();
8124
- ctx.fill();
8125
- }
8126
- function resolveIconPath(type) {
8127
- if (typeof Path2D === "undefined") return null;
8128
- if (type === "filter") {
8129
- filterIconPath ?? (filterIconPath = new Path2D(FILTER_ICON_PATH_DATA));
8130
- return filterIconPath;
8131
- }
8132
- fixedPinPath ?? (fixedPinPath = new Path2D(FIXED_PIN_PATH_DATA));
8133
- return fixedPinPath;
8907
+ drawHeaderActionGlyph(
8908
+ ctx,
8909
+ rect,
8910
+ actionType,
8911
+ actionType === "sort" ? "#8c8c8c" : active ? "#1677ff" : "#8c8c8c",
8912
+ sortOrder
8913
+ );
8134
8914
  }
8135
8915
  function drawHeaderContent(ctx, contents, x, y, maxWidth, align, requestRender) {
8136
8916
  const gap = 4;
@@ -10884,6 +11664,131 @@ function applyTextContentStyle(ctx, content, fallbackColor, theme) {
10884
11664
  ctx.textBaseline = "alphabetic";
10885
11665
  ctx.textAlign = "left";
10886
11666
  }
11667
+
11668
+ // src/features/editing/cascader-display.ts
11669
+ function normalizeCascaderDisplayPaths(options, values, strategy) {
11670
+ const index = /* @__PURE__ */ new Map();
11671
+ const visit = (items, parent, disabled = false) => items.map((item) => {
11672
+ const path = [...parent, item.value];
11673
+ const blocked = disabled || !!item.disabled;
11674
+ const children = visit(item.children ?? [], path, blocked);
11675
+ const node = {
11676
+ path,
11677
+ children,
11678
+ leaves: blocked ? [] : children.length ? children.flatMap((child) => child.leaves) : [JSON.stringify(path)]
11679
+ };
11680
+ index.set(JSON.stringify(path), node);
11681
+ return node;
11682
+ });
11683
+ const roots = visit(options, []);
11684
+ const selected = /* @__PURE__ */ new Set();
11685
+ const preserved = /* @__PURE__ */ new Map();
11686
+ for (const path of values) {
11687
+ const key = JSON.stringify(path);
11688
+ const leaves = index.get(key)?.leaves;
11689
+ if (!leaves?.length) preserved.set(key, path);
11690
+ else leaves.forEach((leaf) => selected.add(leaf));
11691
+ }
11692
+ const result = [];
11693
+ const collect = (node) => {
11694
+ if (node.leaves.length && node.leaves.every((leaf) => selected.has(leaf)) && (strategy === "SHOW_PARENT" || !node.children.length))
11695
+ result.push(node.path);
11696
+ else node.children.forEach(collect);
11697
+ };
11698
+ roots.forEach(collect);
11699
+ return [...result, ...preserved.values()];
11700
+ }
11701
+
11702
+ // src/features/upload/upload-preview.ts
11703
+ var localUrls = /* @__PURE__ */ new WeakMap();
11704
+ var ownedUrls = /* @__PURE__ */ new Set();
11705
+ function canPreviewUploadPdf(file) {
11706
+ return (file.type?.toLowerCase() === "application/pdf" || /\.pdf$/i.test(file.name)) && Boolean(resolveRemoteUrl(file.url) || file.originFileObj);
11707
+ }
11708
+ function previewUploadPdf(file) {
11709
+ if (typeof window === "undefined" || !canPreviewUploadPdf(file)) return;
11710
+ let url = resolveRemoteUrl(file.url);
11711
+ if (!url && file.originFileObj) {
11712
+ const raw = file.originFileObj;
11713
+ url = localUrls.get(raw);
11714
+ if (!url) {
11715
+ url = URL.createObjectURL(
11716
+ raw.type === "application/pdf" ? raw : raw.slice(0, raw.size, "application/pdf")
11717
+ );
11718
+ localUrls.set(raw, url);
11719
+ if (!ownedUrls.size) {
11720
+ window.addEventListener(
11721
+ "pagehide",
11722
+ () => {
11723
+ ownedUrls.forEach((source) => URL.revokeObjectURL(source));
11724
+ ownedUrls.clear();
11725
+ localUrls = /* @__PURE__ */ new WeakMap();
11726
+ },
11727
+ { once: true }
11728
+ );
11729
+ }
11730
+ ownedUrls.add(url);
11731
+ }
11732
+ }
11733
+ if (url) window.open(url, "_blank", "noopener,noreferrer");
11734
+ }
11735
+ function resolveRemoteUrl(source) {
11736
+ if (!source || typeof window === "undefined") return void 0;
11737
+ try {
11738
+ const url = new URL(source, window.location.href);
11739
+ return ["http:", "https:", "blob:"].includes(url.protocol) ? url.href : void 0;
11740
+ } catch {
11741
+ return void 0;
11742
+ }
11743
+ }
11744
+
11745
+ // src/features/upload/upload-display.ts
11746
+ function normalizeUploadFiles(value) {
11747
+ return Array.isArray(value) ? value.filter((file) => file && typeof file.name === "string").map((file, index) => ({ ...file, uid: String(file.uid ?? index) })) : [];
11748
+ }
11749
+ function isUploadImage(file) {
11750
+ return file.type?.startsWith("image/") || /\.(png|jpe?g|gif|webp|bmp|avif|svg)$/i.test(file.name);
11751
+ }
11752
+ function uploadImageSource(file) {
11753
+ const source = file.thumbUrl || file.url || "";
11754
+ return /^(https?:|blob:|data:image\/)/i.test(source) || /^(\/|\.\/|\.\.\/)/.test(source) ? source : "";
11755
+ }
11756
+ function resolveUploadContents(value, editable = false) {
11757
+ return normalizeUploadFiles(value).flatMap((file) => {
11758
+ const src = isUploadImage(file) ? uploadImageSource(file) : "";
11759
+ if (src)
11760
+ return [
11761
+ {
11762
+ type: "image",
11763
+ src,
11764
+ alt: file.name,
11765
+ style: { width: 24, height: 24 }
11766
+ }
11767
+ ];
11768
+ const preview = canPreviewUploadPdf(file) ? { cursor: "pointer", onClick: () => previewUploadPdf(file) } : {};
11769
+ const directPreview = editable ? {} : preview;
11770
+ return [
11771
+ {
11772
+ type: "image",
11773
+ src: createFileTypeIconSource(file.name),
11774
+ preview: false,
11775
+ ...directPreview,
11776
+ style: { width: 24, height: 24 }
11777
+ },
11778
+ { type: "text", text: file.name, ...directPreview },
11779
+ ...editable && preview.onClick ? [
11780
+ {
11781
+ type: "button",
11782
+ text: "\u9884\u89C8",
11783
+ buttonType: "link",
11784
+ ...preview
11785
+ }
11786
+ ] : []
11787
+ ];
11788
+ });
11789
+ }
11790
+
11791
+ // src/features/editing/editing-utils.ts
10887
11792
  function canEditCell(column, context) {
10888
11793
  if (!column || column.key === ROW_SELECTION_COLUMN_KEY || column.key === ROW_SELECTOR_COLUMN_KEY || column.key === EXPAND_COLUMN_KEY) {
10889
11794
  return false;
@@ -10917,7 +11822,13 @@ function getColumnEditConfig(column, context) {
10917
11822
  max: resolvedFormItemProps.max,
10918
11823
  step: resolvedFormItemProps.step,
10919
11824
  options: resolvedFormItemProps.options,
11825
+ treeData: resolvedFormItemProps.treeData,
11826
+ upload: resolvedFormItemProps.upload,
11827
+ treeDefaultExpandAll: resolvedFormItemProps.treeDefaultExpandAll,
11828
+ treeDefaultExpandedKeys: resolvedFormItemProps.treeDefaultExpandedKeys,
10920
11829
  changeOnSelect: resolvedFormItemProps.changeOnSelect,
11830
+ multiple: resolvedFormItemProps.multiple,
11831
+ showCheckedStrategy: resolvedFormItemProps.showCheckedStrategy,
10921
11832
  expandTrigger: resolvedFormItemProps.expandTrigger,
10922
11833
  allowClear: resolvedFormItemProps.allowClear,
10923
11834
  displayRender: resolvedFormItemProps.displayRender,
@@ -10954,16 +11865,43 @@ function resolveFormattedCellText(params) {
10954
11865
  if (formatter === "") {
10955
11866
  return "";
10956
11867
  }
11868
+ if (resolvedFormItemProps?.valueType === "upload") {
11869
+ return normalizeUploadFiles(value).map((file) => file.name).join("\u3001");
11870
+ }
11871
+ if (resolvedFormItemProps?.valueType === "tree-select") {
11872
+ const titles = /* @__PURE__ */ new Map();
11873
+ const pending = [...resolvedFormItemProps.treeData ?? []];
11874
+ while (pending.length) {
11875
+ const node = pending.pop();
11876
+ titles.set(node.value, node.title);
11877
+ if (node.children) pending.push(...node.children);
11878
+ }
11879
+ const values = resolvedFormItemProps.multiple ? Array.isArray(value) ? value : [] : [value];
11880
+ return [
11881
+ ...new Set(
11882
+ values.filter(
11883
+ (part) => typeof part === "string" || typeof part === "number"
11884
+ )
11885
+ )
11886
+ ].map((part) => titles.get(part) ?? String(part)).join("\uFF1B");
11887
+ }
10957
11888
  if (resolvedFormItemProps?.valueType === "cascader" && Array.isArray(value)) {
10958
- let options = resolvedFormItemProps.options ?? [];
10959
- const selectedOptions = [];
10960
- const labels = value.map((part) => {
10961
- const option = options.find((item) => item.value === part);
10962
- options = option?.children ?? [];
10963
- if (option) selectedOptions.push(option);
10964
- return option?.label ?? String(part ?? "");
10965
- });
10966
- return resolvedFormItemProps.displayRender?.(labels, selectedOptions) ?? labels.join(" / ");
11889
+ const formatPath = (path) => {
11890
+ let options = resolvedFormItemProps.options ?? [];
11891
+ const selectedOptions = [];
11892
+ const labels = path.map((part) => {
11893
+ const option = options.find((item) => item.value === part);
11894
+ options = option?.children ?? [];
11895
+ if (option) selectedOptions.push(option);
11896
+ return option?.label ?? String(part ?? "");
11897
+ });
11898
+ return resolvedFormItemProps.displayRender?.(labels, selectedOptions) ?? labels.join(" / ");
11899
+ };
11900
+ return resolvedFormItemProps.multiple ? normalizeCascaderDisplayPaths(
11901
+ resolvedFormItemProps.options ?? [],
11902
+ value.filter(Array.isArray),
11903
+ resolvedFormItemProps.showCheckedStrategy ?? "SHOW_PARENT"
11904
+ ).map(formatPath).join("\uFF1B") : formatPath(value);
10967
11905
  }
10968
11906
  if (Array.isArray(value) && (resolvedFormItemProps?.valueType === "date-range" || resolvedFormItemProps?.valueType === "datetime-range" || resolvedFormItemProps?.valueType === "timerange")) {
10969
11907
  const [start = "", end = ""] = value;
@@ -11056,6 +11994,196 @@ function resolveColumnFormItemProps(column, context) {
11056
11994
  return column.formItemProps;
11057
11995
  }
11058
11996
 
11997
+ // src/rendering/cell-content/draw-timeline-content.ts
11998
+ function positive(value, fallback) {
11999
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
12000
+ }
12001
+ function timelineItems(content) {
12002
+ const items = content.items ?? [];
12003
+ return content.reverse ? [...items].reverse() : items;
12004
+ }
12005
+ function timelinePlainText(content) {
12006
+ return timelineItems(content).map((item) => [item.title, item.content].filter(Boolean).join(" ")).join("\n");
12007
+ }
12008
+ function measureTimelineWidth(content) {
12009
+ return positive(content.style?.width ?? content.width, 220);
12010
+ }
12011
+ function wrap(ctx, text, width) {
12012
+ const lines = [];
12013
+ for (const paragraph of String(text ?? "").split(/\r?\n/)) {
12014
+ let line = "";
12015
+ for (const character of paragraph) {
12016
+ if (line && ctx.measureText(line + character).width > width) {
12017
+ lines.push(line);
12018
+ line = "";
12019
+ }
12020
+ line += character;
12021
+ }
12022
+ lines.push(line);
12023
+ }
12024
+ return lines;
12025
+ }
12026
+ function layoutTimeline(ctx, content, theme, availableWidth = measureTimelineWidth(content)) {
12027
+ const width = Math.max(
12028
+ 1,
12029
+ Math.min(measureTimelineWidth(content), availableWidth)
12030
+ );
12031
+ const fontSize = positive(
12032
+ resolveContentFontSize(content, theme.fontSize),
12033
+ theme.fontSize
12034
+ );
12035
+ const font = buildCanvasFont({
12036
+ fontSize,
12037
+ fontFamily: resolveContentFontFamily(content, theme),
12038
+ fontWeight: resolveContentFontWeight(content)
12039
+ });
12040
+ const lineHeight = Math.ceil(fontSize * 1.5);
12041
+ const dot = Math.min(positive(content.dotSize, 16), lineHeight);
12042
+ const gap = typeof content.itemGap === "number" && Number.isFinite(content.itemGap) ? Math.max(0, content.itemGap) : 12;
12043
+ const items = timelineItems(content);
12044
+ const mode = content.mode ?? "start";
12045
+ const paired = mode === "alternate" || items.some(
12046
+ (item) => item.title || item.position && item.position !== mode
12047
+ );
12048
+ const axis = paired ? width / 2 : mode === "end" ? width - dot / 2 - 1 : dot / 2 + 1;
12049
+ const gutter = dot / 2 + 8;
12050
+ const leftWidth = Math.max(1, axis - gutter);
12051
+ const rightWidth = Math.max(1, width - axis - gutter);
12052
+ let height = 0;
12053
+ ctx.save();
12054
+ ctx.font = font;
12055
+ const nodes = items.map((item, index) => {
12056
+ const position = item.position ?? (mode === "alternate" ? index % 2 ? "end" : "start" : mode);
12057
+ const onRight = position === "start";
12058
+ const textWidth = onRight ? rightWidth : leftWidth;
12059
+ const titleWidth = onRight ? leftWidth : rightWidth;
12060
+ const lines = wrap(ctx, item.content, textWidth);
12061
+ const titles = item.title ? wrap(ctx, item.title, titleWidth) : [];
12062
+ const nodeHeight = Math.max(lines.length, titles.length, 1) * lineHeight;
12063
+ const node = {
12064
+ item,
12065
+ onRight,
12066
+ lines,
12067
+ titles,
12068
+ y: height,
12069
+ height: nodeHeight,
12070
+ textWidth,
12071
+ titleWidth
12072
+ };
12073
+ height += nodeHeight + (index < items.length - 1 ? gap : 0);
12074
+ return node;
12075
+ });
12076
+ ctx.restore();
12077
+ return {
12078
+ width,
12079
+ height,
12080
+ font,
12081
+ fontSize,
12082
+ lineHeight,
12083
+ dot,
12084
+ axis,
12085
+ gutter,
12086
+ nodes
12087
+ };
12088
+ }
12089
+ function drawBodyTimelineContent(params) {
12090
+ const {
12091
+ ctx,
12092
+ content,
12093
+ theme,
12094
+ rect,
12095
+ cursorX,
12096
+ descriptors,
12097
+ column,
12098
+ rowIndex,
12099
+ contentIndex,
12100
+ frozen
12101
+ } = params;
12102
+ const layout = layoutTimeline(ctx, content, theme, rect.width);
12103
+ if (!layout.nodes.length) return;
12104
+ const top = rect.y + Math.max(0, (rect.height - layout.height) / 2);
12105
+ const axis = cursorX + layout.axis;
12106
+ ctx.save();
12107
+ ctx.beginPath();
12108
+ ctx.rect(cursorX, top, layout.width, Math.min(layout.height, rect.height));
12109
+ ctx.clip();
12110
+ ctx.globalAlpha *= resolveContentOpacity(content);
12111
+ ctx.font = layout.font;
12112
+ ctx.textBaseline = "middle";
12113
+ layout.nodes.forEach((node, index) => {
12114
+ const centerY = top + node.y + layout.lineHeight / 2;
12115
+ const next = layout.nodes[index + 1];
12116
+ if (next) {
12117
+ ctx.strokeStyle = content.lineColor ?? theme.borderColor;
12118
+ ctx.lineWidth = 1;
12119
+ ctx.setLineDash(node.item.loading || next.item.loading ? [3, 3] : []);
12120
+ ctx.beginPath();
12121
+ ctx.moveTo(axis, centerY + layout.dot / 2 + 2);
12122
+ ctx.lineTo(
12123
+ axis,
12124
+ top + next.y + layout.lineHeight / 2 - layout.dot / 2 - 2
12125
+ );
12126
+ ctx.stroke();
12127
+ ctx.setLineDash([]);
12128
+ }
12129
+ drawTimelineMarker(
12130
+ ctx,
12131
+ node.item,
12132
+ axis,
12133
+ centerY,
12134
+ layout.dot,
12135
+ content.variant === "filled"
12136
+ );
12137
+ const drawLines = (lines, right, width, color) => {
12138
+ const x = right ? axis + layout.gutter : cursorX;
12139
+ ctx.save();
12140
+ ctx.beginPath();
12141
+ ctx.rect(x, top + node.y, width, node.height);
12142
+ ctx.clip();
12143
+ ctx.fillStyle = color;
12144
+ ctx.textAlign = right ? "left" : "right";
12145
+ lines.forEach(
12146
+ (line, lineIndex) => ctx.fillText(
12147
+ line,
12148
+ right ? x : axis - layout.gutter,
12149
+ centerY + lineIndex * layout.lineHeight
12150
+ )
12151
+ );
12152
+ ctx.restore();
12153
+ };
12154
+ drawLines(
12155
+ node.lines,
12156
+ node.onRight,
12157
+ node.textWidth,
12158
+ content.style?.color ?? theme.textColor
12159
+ );
12160
+ drawLines(
12161
+ node.titles,
12162
+ !node.onRight,
12163
+ node.titleWidth,
12164
+ content.titleColor ?? theme.mutedTextColor ?? theme.textColor
12165
+ );
12166
+ });
12167
+ ctx.restore();
12168
+ descriptors.push({
12169
+ kind: "body-content",
12170
+ rect: {
12171
+ x: cursorX,
12172
+ y: top,
12173
+ width: layout.width,
12174
+ height: Math.min(layout.height, rect.height)
12175
+ },
12176
+ rowIndex,
12177
+ columnKey: column.key,
12178
+ fixed: column.fixed,
12179
+ frozen,
12180
+ contentIndex,
12181
+ contentKey: content.key,
12182
+ cursor: content.cursor ?? (content.onClick ? "pointer" : void 0),
12183
+ tooltipText: timelinePlainText(content)
12184
+ });
12185
+ }
12186
+
11059
12187
  // src/rendering/cell-content/cell-content-renderer.ts
11060
12188
  var CONTENT_HORIZONTAL_PADDING = 12;
11061
12189
  var CONTENT_GAP = 8;
@@ -11073,6 +12201,12 @@ function resolveRawBodyCellContents(params) {
11073
12201
  if (rendered != null) {
11074
12202
  return normalizeCellContents(rendered);
11075
12203
  }
12204
+ if (resolveColumnFormItemProps(column, { value, record, rowIndex })?.valueType === "upload") {
12205
+ return resolveUploadContents(
12206
+ value,
12207
+ canEditCell(column, { value, record, rowIndex })
12208
+ );
12209
+ }
11076
12210
  const formattedText = resolveFormattedCellText({
11077
12211
  column,
11078
12212
  value,
@@ -11148,6 +12282,11 @@ function resolveRawBodyCellContents(params) {
11148
12282
  }
11149
12283
  ] : [];
11150
12284
  }
12285
+ if (column.cellType === "timeline") {
12286
+ return [
12287
+ { type: "timeline", items: Array.isArray(value) ? value : [] }
12288
+ ];
12289
+ }
11151
12290
  if (column.cellType === "progress") {
11152
12291
  const numericValue = typeof value === "number" ? value : typeof value === "string" ? Number(value) : 0;
11153
12292
  return [
@@ -11235,6 +12374,9 @@ function normalizeDrawableCellContents(contents) {
11235
12374
  ).map(normalizeCellContentItem);
11236
12375
  }
11237
12376
  function normalizeCellContentItem(content) {
12377
+ if (content.type === "timeline") {
12378
+ return { ...content, style: { ...content.style, display: "block" } };
12379
+ }
11238
12380
  if (content.type !== "money") {
11239
12381
  return content;
11240
12382
  }
@@ -11480,7 +12622,12 @@ function drawBodyCellContents(params) {
11480
12622
  );
11481
12623
  return void 0;
11482
12624
  }
11483
- const lineHeight = getBodyCellContentsLineHeight(contents, theme);
12625
+ const lineHeight = getBodyCellContentsLineHeight(
12626
+ contents,
12627
+ theme,
12628
+ ctx,
12629
+ availableWidth
12630
+ );
11484
12631
  const layout = layoutBodyCellContents({
11485
12632
  ctx,
11486
12633
  contents,
@@ -11653,7 +12800,12 @@ function measureBodyCellContentsHeight(params) {
11653
12800
  if (availableWidth <= 0) {
11654
12801
  return paddingBlock * 2;
11655
12802
  }
11656
- const lineHeight = getBodyCellContentsLineHeight(contents, theme);
12803
+ const lineHeight = getBodyCellContentsLineHeight(
12804
+ contents,
12805
+ theme,
12806
+ ctx,
12807
+ availableWidth
12808
+ );
11657
12809
  const layout = layoutBodyCellContents({
11658
12810
  ctx,
11659
12811
  contents,
@@ -12132,6 +13284,7 @@ function drawExpandedBodyContent(params) {
12132
13284
  if (content.type === "icon") {
12133
13285
  drawBodyIconContent({
12134
13286
  ctx,
13287
+ theme,
12135
13288
  rect,
12136
13289
  content,
12137
13290
  contentIndex,
@@ -12204,6 +13357,21 @@ function drawExpandedBodyContent(params) {
12204
13357
  });
12205
13358
  return;
12206
13359
  }
13360
+ if (content.type === "timeline") {
13361
+ drawBodyTimelineContent({
13362
+ ctx,
13363
+ rect,
13364
+ content,
13365
+ contentIndex,
13366
+ cursorX,
13367
+ rowIndex,
13368
+ column,
13369
+ theme,
13370
+ frozen,
13371
+ descriptors
13372
+ });
13373
+ return;
13374
+ }
12207
13375
  if (content.type === "progress") {
12208
13376
  drawBodyProgressContent({
12209
13377
  ctx,
@@ -12379,6 +13547,7 @@ function measureExpandedContentWidth(ctx, content, theme) {
12379
13547
  if (content.type === "button") {
12380
13548
  return measureButtonContentWidth(ctx, content, theme);
12381
13549
  }
13550
+ if (content.type === "timeline") return measureTimelineWidth(content);
12382
13551
  if (content.type === "progress") {
12383
13552
  return measureProgressContentWidth(ctx, content, theme);
12384
13553
  }
@@ -12433,9 +13602,16 @@ function getBodyCellContentsLineGap(contents, lineHeight) {
12433
13602
  }
12434
13603
  return tagHeight > 0 ? Math.max(CONTENT_GAP - (lineHeight - tagHeight), 0) : 0;
12435
13604
  }
12436
- function getBodyCellContentsLineHeight(contents, theme) {
13605
+ function getBodyCellContentsLineHeight(contents, theme, ctx, availableWidth) {
12437
13606
  let lineHeight = theme.fontSize + 8;
12438
13607
  contents.forEach((item) => {
13608
+ if (item.type === "timeline") {
13609
+ lineHeight = Math.max(
13610
+ lineHeight,
13611
+ layoutTimeline(ctx, item, theme, availableWidth).height
13612
+ );
13613
+ return;
13614
+ }
12439
13615
  if (item.type === "arrow") {
12440
13616
  lineHeight = Math.max(lineHeight, measureArrowContentHeight(item));
12441
13617
  return;
@@ -12510,6 +13686,15 @@ function getBodyCellContentsLineHeight(contents, theme) {
12510
13686
  return lineHeight;
12511
13687
  }
12512
13688
  function truncateExpandedContent(ctx, content, theme, maxWidth, withEllipsis) {
13689
+ if (content.type === "timeline") {
13690
+ return maxWidth > 0 ? {
13691
+ ...content,
13692
+ style: {
13693
+ ...content.style,
13694
+ width: Math.min(measureTimelineWidth(content), maxWidth)
13695
+ }
13696
+ } : null;
13697
+ }
12513
13698
  if (content.type === "text" || content.type === "link") {
12514
13699
  const nextText = fitTextToWidth(
12515
13700
  getBreakableContentText(content),
@@ -12659,6 +13844,7 @@ function buildBodyContentsPlainText(contents) {
12659
13844
  if (content.type === "progress") {
12660
13845
  return content.text ?? `${Math.round(resolveProgressPercent(content))}%`;
12661
13846
  }
13847
+ if (content.type === "timeline") return timelinePlainText(content);
12662
13848
  if (content.type === "chart") {
12663
13849
  return resolveChartContentPlainText(content);
12664
13850
  }
@@ -12973,6 +14159,7 @@ function isCellContentDisabled(content) {
12973
14159
  if (content.type === "button") {
12974
14160
  return content.disabled === true;
12975
14161
  }
14162
+ if (content.type === "timeline") return false;
12976
14163
  if (content.type === "progress") {
12977
14164
  return false;
12978
14165
  }
@@ -16424,6 +17611,11 @@ function getCellClipboardText(record, rowIndex, column) {
16424
17611
  if (column.cellType === "checkbox" || column.cellType === "radio") {
16425
17612
  return String(Boolean(value));
16426
17613
  }
17614
+ if (column.cellType === "timeline") {
17615
+ return timelinePlainText({
17616
+ items: Array.isArray(value) ? value : []
17617
+ });
17618
+ }
16427
17619
  return resolveFormattedCellText({
16428
17620
  column,
16429
17621
  value,
@@ -16574,7 +17766,7 @@ async function copyRowJsonContent(params) {
16574
17766
  }
16575
17767
  async function exportAllRowsJsonContent(params) {
16576
17768
  await utils.downloadJsonFile({
16577
- fileName: buildTableExportFileName("json"),
17769
+ fileName: params.fileName?.trim() || buildTableExportFileName("json"),
16578
17770
  data: utils.mapRowsToExportRecords({
16579
17771
  rows: params.rows,
16580
17772
  columns: buildExportColumns(params.columns)
@@ -16583,14 +17775,14 @@ async function exportAllRowsJsonContent(params) {
16583
17775
  }
16584
17776
  async function exportAllRowsCsvContent(params) {
16585
17777
  await utils.exportTableToCsv({
16586
- fileName: buildTableExportFileName("csv"),
17778
+ fileName: params.fileName?.trim() || buildTableExportFileName("csv"),
16587
17779
  rows: params.rows,
16588
17780
  columns: buildExportColumns(params.columns)
16589
17781
  });
16590
17782
  }
16591
17783
  async function exportAllRowsTxtContent(params) {
16592
17784
  await utils.exportTableToTxt({
16593
- fileName: buildTableExportFileName("txt"),
17785
+ fileName: params.fileName?.trim() || buildTableExportFileName("txt"),
16594
17786
  rows: params.rows,
16595
17787
  columns: buildExportColumns(params.columns)
16596
17788
  });
@@ -16660,6 +17852,7 @@ function cellContentToClipboardText(content) {
16660
17852
  if (content.type === "progress") {
16661
17853
  return content.text ?? `${Math.round(resolveProgressClipboardPercent(content))}%`;
16662
17854
  }
17855
+ if (content.type === "timeline") return timelinePlainText(content);
16663
17856
  if (content.type === "chart") {
16664
17857
  return resolveChartContentPlainText(content);
16665
17858
  }
@@ -16872,17 +18065,21 @@ var ListTableContentActionController = class {
16872
18065
  constructor(options) {
16873
18066
  __publicField(this, "options");
16874
18067
  __publicField(this, "exportTaskRunning", false);
18068
+ __publicField(this, "exportNamePending", false);
16875
18069
  this.options = options;
16876
18070
  }
16877
18071
  /**
16878
18072
  * 异步导出全部原始数据为 XLSX。
16879
18073
  */
16880
18074
  exportXlsx(options) {
18075
+ options = { ...this.options.getOptions().exportOptions, ...options };
16881
18076
  this.startExportTask(
16882
- () => exportAllRowsXlsxContent({
18077
+ (fileName) => exportAllRowsXlsxContent({
16883
18078
  rows: this.options.getOptions().dataSource,
16884
18079
  columns: this.options.getLeafColumns(),
16885
18080
  ...options,
18081
+ includeSummary: options?.includeSummary ?? this.options.getSummaryVisible?.() ?? false,
18082
+ fileName: fileName ?? options?.fileName,
16886
18083
  onProgress: (progress) => {
16887
18084
  const fileLabel = progress.fileCount && progress.fileCount > 1 ? `\uFF08\u7B2C ${progress.fileIndex}/${progress.fileCount} \u4EFD\uFF09` : "";
16888
18085
  this.options.overlayController.showLoading(
@@ -16892,16 +18089,55 @@ var ListTableContentActionController = class {
16892
18089
  }
16893
18090
  }),
16894
18091
  "\u6B63\u5728\u5BFC\u51FA XLSX\u2026",
16895
- options?.onError
18092
+ options?.onError,
18093
+ options?.fileName?.trim() ? `${options.fileName.trim().replace(/\.xlsx$/i, "")}.xlsx` : buildTableExportFileName("xlsx"),
18094
+ options?.promptFileName
16896
18095
  );
16897
18096
  }
16898
- startExportTask(task, text, onError) {
16899
- if (this.exportTaskRunning) {
18097
+ startExportTask(task, text, onError, defaultFileName, promptFileName = this.options.getOptions().exportOptions?.promptFileName ?? true) {
18098
+ if (this.exportTaskRunning || this.exportNamePending) {
18099
+ return;
18100
+ }
18101
+ if (defaultFileName !== void 0 && promptFileName) {
18102
+ this.exportNamePending = true;
18103
+ const notify = this.options.getOptions().ui?.onExportNameRequest;
18104
+ let settled = false;
18105
+ const close = () => {
18106
+ settled = true;
18107
+ this.exportNamePending = false;
18108
+ notify?.(null);
18109
+ };
18110
+ const request = {
18111
+ fileName: defaultFileName,
18112
+ onConfirm: (value) => {
18113
+ if (settled || !value.trim()) return;
18114
+ close();
18115
+ const extension = defaultFileName.match(
18116
+ /\.(xlsx|csv|txt|json)$/i
18117
+ )?.[0];
18118
+ const name = extension && !value.trim().toLowerCase().endsWith(extension.toLowerCase()) ? `${value.trim()}${extension}` : value.trim();
18119
+ this.startExportTask(() => task(name), text, onError);
18120
+ },
18121
+ onCancel: () => {
18122
+ if (!settled) close();
18123
+ }
18124
+ };
18125
+ if (notify) notify(request);
18126
+ else if (typeof window !== "undefined" && typeof window.prompt === "function") {
18127
+ const extension = defaultFileName.match(/\.(xlsx|csv|txt|json)$/i)?.[0] ?? "";
18128
+ const baseName = extension ? defaultFileName.slice(0, -extension.length) : defaultFileName;
18129
+ const value = window.prompt(
18130
+ `\u8BF7\u8F93\u5165\u5BFC\u51FA\u6587\u4EF6\u540D\u79F0\uFF08\u56FA\u5B9A\u540E\u7F00\uFF1A${extension}\uFF09`,
18131
+ baseName
18132
+ );
18133
+ if (value == null || !value.trim()) request.onCancel();
18134
+ else request.onConfirm(`${value.trim()}${extension}`);
18135
+ } else request.onConfirm(defaultFileName);
16900
18136
  return;
16901
18137
  }
16902
18138
  this.exportTaskRunning = true;
16903
18139
  this.options.overlayController.showLoading(text);
16904
- void task().catch((error) => {
18140
+ void Promise.resolve().then(() => task(defaultFileName)).catch((error) => {
16905
18141
  if (error?.name === "AbortError") return;
16906
18142
  console.error("[ListTable] Failed to export table data:", error);
16907
18143
  onError?.(error);
@@ -17179,6 +18415,312 @@ function setValueByDataIndex(record, dataIndex, value) {
17179
18415
  return true;
17180
18416
  }
17181
18417
 
18418
+ // src/features/upload/upload-editor.ts
18419
+ function createUploadEditor(params) {
18420
+ const config = params.config ?? {};
18421
+ let files = normalizeUploadFiles(params.value);
18422
+ let alive = true;
18423
+ let pending = 0;
18424
+ let sequence = 0;
18425
+ const requests = /* @__PURE__ */ new Map();
18426
+ const readers = /* @__PURE__ */ new Set();
18427
+ const root = document.createElement("div");
18428
+ root.setAttribute("role", "dialog");
18429
+ root.setAttribute("aria-label", "\u4E0A\u4F20\u9644\u4EF6");
18430
+ root.tabIndex = -1;
18431
+ const width = Math.min(360, Math.max(200, window.innerWidth - 16));
18432
+ Object.assign(root.style, {
18433
+ position: "fixed",
18434
+ zIndex: "10000",
18435
+ boxSizing: "border-box",
18436
+ width: `${width}px`,
18437
+ left: `${Math.max(8, Math.min(params.rect.x, window.innerWidth - width - 8))}px`,
18438
+ top: `${Math.max(8, Math.min(params.rect.y, window.innerHeight - 280))}px`,
18439
+ maxHeight: "calc(100vh - 16px)",
18440
+ overflow: "auto",
18441
+ padding: "12px",
18442
+ background: "#fff",
18443
+ color: "#1f2937",
18444
+ border: "1px solid #d9e1ec",
18445
+ borderRadius: "6px",
18446
+ boxShadow: "0 6px 24px #0002",
18447
+ font: "13px sans-serif"
18448
+ });
18449
+ for (const event of [
18450
+ "pointerdown",
18451
+ "mousedown",
18452
+ "click",
18453
+ "dblclick",
18454
+ "contextmenu"
18455
+ ])
18456
+ root.addEventListener(event, (e) => e.stopPropagation());
18457
+ const title = document.createElement("div");
18458
+ title.textContent = "\u4E0A\u4F20\u9644\u4EF6";
18459
+ title.style.fontWeight = "600";
18460
+ const list = document.createElement("div");
18461
+ Object.assign(list.style, {
18462
+ maxHeight: "180px",
18463
+ overflow: "auto",
18464
+ margin: "10px 0"
18465
+ });
18466
+ const message = document.createElement("div");
18467
+ message.setAttribute("role", "status");
18468
+ message.style.color = "#c53030";
18469
+ const input = document.createElement("input");
18470
+ input.type = "file";
18471
+ input.accept = config.accept ?? "";
18472
+ input.multiple = config.multiple ?? false;
18473
+ input.hidden = true;
18474
+ const actions = document.createElement("div");
18475
+ Object.assign(actions.style, {
18476
+ display: "flex",
18477
+ gap: "8px",
18478
+ marginTop: "10px",
18479
+ flexWrap: "wrap"
18480
+ });
18481
+ const button = (label, callback) => {
18482
+ const element = document.createElement("button");
18483
+ element.type = "button";
18484
+ element.textContent = label;
18485
+ Object.assign(element.style, {
18486
+ padding: "4px 10px",
18487
+ border: "1px solid #cbd5e1",
18488
+ background: "#fff",
18489
+ borderRadius: "4px",
18490
+ cursor: "pointer",
18491
+ color: "inherit"
18492
+ });
18493
+ element.onclick = callback;
18494
+ return element;
18495
+ };
18496
+ const choose = button("\u9009\u62E9\u6587\u4EF6", () => input.click());
18497
+ const done = button("\u5B8C\u6210", () => {
18498
+ if (!pending) params.onCommit();
18499
+ });
18500
+ const cancel = button("\u53D6\u6D88", params.onCancel);
18501
+ actions.append(choose, done, cancel);
18502
+ root.append(title, list, message, input, actions);
18503
+ function render() {
18504
+ if (!alive) return;
18505
+ list.replaceChildren();
18506
+ done.disabled = pending > 0;
18507
+ if (!files.length) list.textContent = "\u6682\u65E0\u9644\u4EF6";
18508
+ for (const file of files) {
18509
+ const row = document.createElement("div");
18510
+ Object.assign(row.style, {
18511
+ display: "flex",
18512
+ alignItems: "center",
18513
+ gap: "8px",
18514
+ padding: "6px 0"
18515
+ });
18516
+ const source = isUploadImage(file) ? uploadImageSource(file) : "";
18517
+ if (source) {
18518
+ const image = document.createElement("img");
18519
+ image.src = source;
18520
+ image.alt = file.name;
18521
+ Object.assign(image.style, {
18522
+ width: "32px",
18523
+ height: "32px",
18524
+ objectFit: "contain"
18525
+ });
18526
+ row.append(image);
18527
+ }
18528
+ const label = document.createElement("span");
18529
+ label.textContent = `${file.name} \xB7 ${file.status === "uploading" ? `${Math.round(file.percent ?? 0)}%` : file.status === "error" ? file.error || "\u4E0A\u4F20\u5931\u8D25" : file.status === "selected" ? "\u672A\u4E0A\u4F20" : "\u5DF2\u4E0A\u4F20"}`;
18530
+ Object.assign(label.style, {
18531
+ flex: "1",
18532
+ minWidth: "0",
18533
+ overflowWrap: "anywhere"
18534
+ });
18535
+ row.append(label);
18536
+ if (canPreviewUploadPdf(file)) {
18537
+ row.append(button("\u9884\u89C8", () => previewUploadPdf(file)));
18538
+ }
18539
+ if (file.status === "error" && file.originFileObj)
18540
+ row.append(button("\u91CD\u8BD5", () => upload(file)));
18541
+ row.append(
18542
+ button("\u79FB\u9664", () => {
18543
+ requests.get(file.uid)?.();
18544
+ files = files.filter((item) => item !== file);
18545
+ render();
18546
+ })
18547
+ );
18548
+ list.append(row);
18549
+ }
18550
+ }
18551
+ function upload(file) {
18552
+ if (!alive || !file.originFileObj || !config.action && !config.customRequest)
18553
+ return;
18554
+ requests.get(file.uid)?.();
18555
+ const raw = file.originFileObj;
18556
+ let active = true;
18557
+ let abort;
18558
+ pending++;
18559
+ file.status = "uploading";
18560
+ file.percent = 0;
18561
+ const finish = () => {
18562
+ active = false;
18563
+ pending--;
18564
+ requests.delete(file.uid);
18565
+ };
18566
+ requests.set(file.uid, () => {
18567
+ if (!active) return;
18568
+ finish();
18569
+ abort?.();
18570
+ });
18571
+ const onError = (error) => {
18572
+ if (!active || !alive) return;
18573
+ finish();
18574
+ file.status = "error";
18575
+ file.error = error.message || "\u4E0A\u4F20\u5931\u8D25";
18576
+ render();
18577
+ };
18578
+ const onSuccess = (response) => {
18579
+ if (!active || !alive) return;
18580
+ try {
18581
+ const url = config.getResponseUrl ? config.getResponseUrl(response, raw) : response && typeof response === "object" && "url" in response && typeof response.url === "string" ? response.url : void 0;
18582
+ file.url = url ?? file.url;
18583
+ file.response = response;
18584
+ file.status = "done";
18585
+ file.percent = 100;
18586
+ finish();
18587
+ render();
18588
+ } catch (error) {
18589
+ onError(error instanceof Error ? error : new Error(String(error)));
18590
+ }
18591
+ };
18592
+ const onProgress = (percent) => {
18593
+ if (alive && active) {
18594
+ file.percent = Math.max(0, Math.min(100, percent));
18595
+ render();
18596
+ }
18597
+ };
18598
+ try {
18599
+ if (config.customRequest) {
18600
+ const handle = config.customRequest({
18601
+ file: raw,
18602
+ onProgress,
18603
+ onSuccess,
18604
+ onError
18605
+ });
18606
+ abort = handle ? () => handle.abort() : void 0;
18607
+ } else {
18608
+ const xhr = new XMLHttpRequest();
18609
+ abort = () => xhr.abort();
18610
+ xhr.open("POST", config.action);
18611
+ xhr.withCredentials = config.withCredentials ?? false;
18612
+ for (const [key, value] of Object.entries(config.headers ?? {}))
18613
+ xhr.setRequestHeader(key, value);
18614
+ xhr.upload.onprogress = (event) => {
18615
+ if (event.lengthComputable)
18616
+ onProgress(event.loaded / event.total * 100);
18617
+ };
18618
+ xhr.onerror = () => onError(new Error("\u7F51\u7EDC\u9519\u8BEF\uFF0C\u4E0A\u4F20\u5931\u8D25"));
18619
+ xhr.onabort = () => onError(new Error("\u4E0A\u4F20\u5DF2\u53D6\u6D88"));
18620
+ xhr.onload = () => {
18621
+ if (xhr.status < 200 || xhr.status >= 300)
18622
+ return onError(new Error(`\u4E0A\u4F20\u5931\u8D25 (${xhr.status})`));
18623
+ let response = xhr.responseText;
18624
+ try {
18625
+ response = JSON.parse(xhr.responseText);
18626
+ } catch {
18627
+ }
18628
+ onSuccess(response);
18629
+ };
18630
+ const body = new FormData();
18631
+ for (const [key, value] of Object.entries(config.data ?? {}))
18632
+ body.append(key, value);
18633
+ body.append(config.name ?? "file", raw);
18634
+ xhr.send(body);
18635
+ }
18636
+ } catch (error) {
18637
+ onError(error instanceof Error ? error : new Error(String(error)));
18638
+ }
18639
+ render();
18640
+ }
18641
+ input.onchange = async () => {
18642
+ const selected = Array.from(input.files ?? []);
18643
+ input.value = "";
18644
+ message.textContent = "";
18645
+ pending++;
18646
+ render();
18647
+ for (const raw of selected) {
18648
+ try {
18649
+ if (config.maxSize && raw.size > config.maxSize)
18650
+ throw new Error(`${raw.name} \u8D85\u8FC7\u6587\u4EF6\u5927\u5C0F\u9650\u5236`);
18651
+ const allowed = await config.beforeUpload?.(raw);
18652
+ if (!alive) break;
18653
+ const max = Math.max(1, config.maxCount ?? Infinity);
18654
+ if (max === 1) {
18655
+ for (const file2 of files) requests.get(file2.uid)?.();
18656
+ files = [];
18657
+ }
18658
+ if (files.length >= max) throw new Error(`\u6700\u591A\u9009\u62E9 ${max} \u4E2A\u6587\u4EF6`);
18659
+ const file = {
18660
+ uid: `upload-${Date.now()}-${++sequence}`,
18661
+ name: raw.name,
18662
+ type: raw.type,
18663
+ size: raw.size,
18664
+ originFileObj: raw,
18665
+ status: "selected"
18666
+ };
18667
+ files.push(file);
18668
+ if (isUploadImage(file)) {
18669
+ const reader = new FileReader();
18670
+ readers.add(reader);
18671
+ pending++;
18672
+ reader.onload = () => {
18673
+ if (alive && files.includes(file)) {
18674
+ file.thumbUrl = String(reader.result);
18675
+ render();
18676
+ }
18677
+ };
18678
+ reader.onloadend = () => {
18679
+ readers.delete(reader);
18680
+ pending--;
18681
+ render();
18682
+ };
18683
+ reader.readAsDataURL(raw);
18684
+ }
18685
+ if (allowed !== false) upload(file);
18686
+ } catch (error) {
18687
+ if (alive)
18688
+ message.textContent = error instanceof Error ? error.message : String(error);
18689
+ }
18690
+ }
18691
+ pending--;
18692
+ render();
18693
+ };
18694
+ root.onkeydown = (event) => {
18695
+ event.stopPropagation();
18696
+ if (event.key === "Escape") {
18697
+ event.preventDefault();
18698
+ params.onCancel();
18699
+ }
18700
+ if (event.key === "Tab") {
18701
+ const items = Array.from(
18702
+ root.querySelectorAll("button:not(:disabled)")
18703
+ );
18704
+ const next = items[(items.indexOf(document.activeElement) + (event.shiftKey ? -1 : 1) + items.length) % items.length];
18705
+ event.preventDefault();
18706
+ next?.focus();
18707
+ }
18708
+ };
18709
+ document.body.append(root);
18710
+ render();
18711
+ return {
18712
+ element: root,
18713
+ focus: () => choose.focus(),
18714
+ getValue: () => files,
18715
+ destroy: () => {
18716
+ alive = false;
18717
+ for (const abort of [...requests.values()]) abort();
18718
+ for (const reader of readers) reader.abort();
18719
+ root.remove();
18720
+ }
18721
+ };
18722
+ }
18723
+
17182
18724
  // src/features/editing/editing-feature.ts
17183
18725
  var DEFAULT_EDITOR_PADDING_INLINE = 12;
17184
18726
  function openCellEditingSession(params) {
@@ -17230,6 +18772,7 @@ function openCellEditingSession(params) {
17230
18772
  }
17231
18773
  const editorConfig = resolveEditorConfig(editConfig);
17232
18774
  const editingValue = initialValue === void 0 ? currentValue : initialValue;
18775
+ const selectOnFocus = !(initialValue !== void 0 && (currentValue == null || currentValue === ""));
17233
18776
  const hostRect = toHostRect ? toHostRect(descriptor.rect) : descriptor.rect;
17234
18777
  const zoom = typeof theme.contentZoom === "number" && Number.isFinite(theme.contentZoom) && theme.contentZoom > 0 ? theme.contentZoom : 1;
17235
18778
  const paddingInline = (column.cellStyle?.paddingInline ?? DEFAULT_EDITOR_PADDING_INLINE) * zoom;
@@ -17243,10 +18786,26 @@ function openCellEditingSession(params) {
17243
18786
  paddingBlock,
17244
18787
  contentZoom: zoom
17245
18788
  };
18789
+ if (editorConfig.valueType === "upload" && typeof document !== "undefined") {
18790
+ const session2 = createUploadEditor({
18791
+ value: editingValue,
18792
+ config: editorConfig.upload,
18793
+ rect: toViewportRect(descriptor.rect),
18794
+ onCommit: () => onCommit(),
18795
+ onCancel
18796
+ });
18797
+ session2.focus();
18798
+ return {
18799
+ ...session2,
18800
+ rowIndex,
18801
+ columnKey
18802
+ };
18803
+ }
17246
18804
  if (onEditorRequest) {
17247
18805
  let nextValue = editingValue;
17248
18806
  onEditorRequest({
17249
18807
  editorKey: JSON.stringify([rowIndex, columnKey]),
18808
+ selectOnFocus,
17250
18809
  rect: toViewportRect(descriptor.rect),
17251
18810
  clipRect: getViewportClipRect?.() ?? void 0,
17252
18811
  hostRect,
@@ -17276,6 +18835,7 @@ function openCellEditingSession(params) {
17276
18835
  return null;
17277
18836
  }
17278
18837
  const session = editorFactory.createCellEditorSession({
18838
+ selectOnFocus,
17279
18839
  rect: toViewportRect(descriptor.rect),
17280
18840
  clipRect: getViewportClipRect?.() ?? void 0,
17281
18841
  hostRect,
@@ -17312,7 +18872,13 @@ function resolveEditorConfig(config) {
17312
18872
  max: config.max,
17313
18873
  min: config.min,
17314
18874
  options: config.options,
18875
+ treeData: config.treeData,
18876
+ treeDefaultExpandAll: config.treeDefaultExpandAll,
18877
+ treeDefaultExpandedKeys: config.treeDefaultExpandedKeys,
17315
18878
  changeOnSelect: config.changeOnSelect,
18879
+ multiple: config.multiple,
18880
+ showCheckedStrategy: config.showCheckedStrategy,
18881
+ upload: config.upload,
17316
18882
  expandTrigger: config.expandTrigger,
17317
18883
  allowClear: config.allowClear,
17318
18884
  displayRender: config.displayRender,
@@ -17505,6 +19071,7 @@ var ListTableEditingController = class {
17505
19071
  __publicField(this, "nestedEditingSource", null);
17506
19072
  __publicField(this, "validationMessages", /* @__PURE__ */ new Map());
17507
19073
  __publicField(this, "validationTaskId", 0);
19074
+ __publicField(this, "editingRequestId", 0);
17508
19075
  this.options = options;
17509
19076
  }
17510
19077
  hasSession() {
@@ -17516,6 +19083,18 @@ var ListTableEditingController = class {
17516
19083
  open(rowIndex, columnKey, initialValue) {
17517
19084
  this.close(false);
17518
19085
  this.options.clearBodyTooltip();
19086
+ const requestId = this.editingRequestId;
19087
+ const openVisibleEditor = () => {
19088
+ if (requestId !== this.editingRequestId) return;
19089
+ this.openVisibleCell(rowIndex, columnKey, initialValue);
19090
+ };
19091
+ if (this.ensureCellVisibleForEditing(rowIndex, columnKey, openVisibleEditor)) {
19092
+ return;
19093
+ }
19094
+ openVisibleEditor();
19095
+ }
19096
+ /** 使用滚动完成后的描述符定位编辑器,避免浏览器移动整个画布宿主。 */
19097
+ openVisibleCell(rowIndex, columnKey, initialValue) {
17519
19098
  const zoom = this.options.getTableZoom() > 0 ? this.options.getTableZoom() : 1;
17520
19099
  const theme = this.options.getTheme();
17521
19100
  const configuredRowHeight = this.options.getOptions().rowHeight;
@@ -17671,40 +19250,14 @@ var ListTableEditingController = class {
17671
19250
  void this.validateCellTargets(session.rowIndex, session.columnKey);
17672
19251
  this.close(false);
17673
19252
  this.options.requestRender();
17674
- if (direction === "up" || direction === "down") {
17675
- if (!nextTarget) {
17676
- this.options.focusTable?.();
17677
- return;
17678
- }
17679
- this.options.setSelection?.(nextTarget);
17680
- const revealTarget = () => {
17681
- this.options.requestRender();
19253
+ if (!nextTarget) {
19254
+ if (direction === "up" || direction === "down") {
17682
19255
  this.options.focusTable?.();
17683
- };
17684
- const scrolled2 = this.ensureCellVisibleForEditing(
17685
- nextTarget.rowIndex,
17686
- nextTarget.columnKey,
17687
- revealTarget
17688
- );
17689
- if (!scrolled2) {
17690
- revealTarget();
17691
19256
  }
17692
19257
  return;
17693
19258
  }
17694
- if (!nextTarget) {
17695
- return;
17696
- }
17697
19259
  this.options.setSelection?.(nextTarget);
17698
- const scrolled = this.ensureCellVisibleForEditing(
17699
- nextTarget.rowIndex,
17700
- nextTarget.columnKey,
17701
- () => {
17702
- this.open(nextTarget.rowIndex, nextTarget.columnKey);
17703
- }
17704
- );
17705
- if (!scrolled) {
17706
- this.open(nextTarget.rowIndex, nextTarget.columnKey);
17707
- }
19260
+ this.open(nextTarget.rowIndex, nextTarget.columnKey);
17708
19261
  }
17709
19262
  /**
17710
19263
  * 确保目标可编辑单元格完整进入视口。
@@ -17743,11 +19296,15 @@ var ListTableEditingController = class {
17743
19296
  targetLeft: leftChanged ? nextLeft : scroll.left,
17744
19297
  targetTop: topChanged ? nextTop : scroll.top,
17745
19298
  duration: 240,
17746
- onComplete: onVisible
19299
+ onComplete: () => {
19300
+ this.options.requestRender();
19301
+ onVisible?.();
19302
+ }
17747
19303
  });
17748
19304
  return true;
17749
19305
  }
17750
19306
  close(_keepFocusState = false) {
19307
+ this.editingRequestId++;
17751
19308
  this.editingSession = closeCellEditingSession(this.editingSession);
17752
19309
  this.editingSource = null;
17753
19310
  this.nestedEditingSource = null;
@@ -24658,41 +26215,50 @@ function createListTableContextMenuActions(params) {
24658
26215
  onExportJson: () => {
24659
26216
  params.hideMenu();
24660
26217
  params.startExportTask(
24661
- () => exportAllRowsJsonContent({
26218
+ (fileName) => exportAllRowsJsonContent({
26219
+ fileName,
24662
26220
  rows: params.getAllRows(),
24663
26221
  columns: params.getColumns()
24664
26222
  }),
24665
- "\u6B63\u5728\u5BFC\u51FA JSON\u2026"
26223
+ "\u6B63\u5728\u5BFC\u51FA JSON\u2026",
26224
+ buildTableExportFileName("json")
24666
26225
  );
24667
26226
  },
24668
26227
  onExportCsv: () => {
24669
26228
  params.hideMenu();
24670
26229
  params.startExportTask(
24671
- () => exportAllRowsCsvContent({
26230
+ (fileName) => exportAllRowsCsvContent({
26231
+ fileName,
24672
26232
  rows: params.getAllRows(),
24673
26233
  columns: params.getColumns()
24674
26234
  }),
24675
- "\u6B63\u5728\u5BFC\u51FA CSV\u2026"
26235
+ "\u6B63\u5728\u5BFC\u51FA CSV\u2026",
26236
+ buildTableExportFileName("csv")
24676
26237
  );
24677
26238
  },
24678
26239
  onExportTxt: () => {
24679
26240
  params.hideMenu();
24680
26241
  params.startExportTask(
24681
- () => exportAllRowsTxtContent({
26242
+ (fileName) => exportAllRowsTxtContent({
26243
+ fileName,
24682
26244
  rows: params.getAllRows(),
24683
26245
  columns: params.getColumns()
24684
26246
  }),
24685
- "\u6B63\u5728\u5BFC\u51FA TXT\u2026"
26247
+ "\u6B63\u5728\u5BFC\u51FA TXT\u2026",
26248
+ buildTableExportFileName("txt")
24686
26249
  );
24687
26250
  },
24688
26251
  onExportXlsx: () => {
24689
26252
  params.hideMenu();
24690
26253
  params.startExportTask(
24691
- () => exportAllRowsXlsxContent({
26254
+ (fileName) => exportAllRowsXlsxContent({
26255
+ includeSummary: params.getExportSummaryEnabled?.() ?? false,
26256
+ fileName,
24692
26257
  rows: params.getAllRows(),
24693
26258
  columns: params.getColumns()
24694
26259
  }),
24695
- "\u6B63\u5728\u5BFC\u51FA XLSX\u2026"
26260
+ "\u6B63\u5728\u5BFC\u51FA XLSX\u2026",
26261
+ buildTableExportFileName("xlsx")
24696
26262
  );
24697
26263
  },
24698
26264
  onFreezeRow: params.onFreezeRow,
@@ -25264,6 +26830,7 @@ function showHeaderContextMenu(params) {
25264
26830
  rowCount: getRows().length,
25265
26831
  columnCount: getColumns().length,
25266
26832
  actions: createListTableContextMenuActions({
26833
+ getExportSummaryEnabled: params.getExportSummaryEnabled,
25267
26834
  getRows,
25268
26835
  getAllRows,
25269
26836
  getColumns,
@@ -25374,9 +26941,9 @@ function updateHeaderActionTooltip(params) {
25374
26941
  tooltip.show(tooltipPoint.x, tooltipPoint.y, text);
25375
26942
  }
25376
26943
  function showDragTooltip(params) {
25377
- const { tooltip, toViewportPoint, x, y, text } = params;
26944
+ const { tooltip, toViewportPoint, x, y, text, variant } = params;
25378
26945
  const point = toViewportPoint(x, y + 16);
25379
- tooltip.show(point.x, point.y, text);
26946
+ tooltip.show(point.x, point.y, text, variant);
25380
26947
  }
25381
26948
 
25382
26949
  // src/shared/utils/hit-result.ts
@@ -26829,6 +28396,11 @@ var ListTableEventController = class {
26829
28396
  event.clientY
26830
28397
  );
26831
28398
  const result = this.host.resolvePointerHit(position.x, position.y);
28399
+ if (result.area === "resize-handle" && result.columnKey) {
28400
+ event.preventDefault();
28401
+ void this.autoFitColumnWidths(result.columnKey);
28402
+ return;
28403
+ }
26832
28404
  if (this.tryOpenNestedTableEditor(result, 2)) {
26833
28405
  return;
26834
28406
  }
@@ -26911,6 +28483,7 @@ var ListTableEventController = class {
26911
28483
  },
26912
28484
  getRows: () => this.host.getDisplayData(),
26913
28485
  getAllRows: () => this.host.options.dataSource,
28486
+ getExportSummaryEnabled: () => Boolean(this.host.currentRenderSnapshot?.hasSummary),
26914
28487
  onCopyImage: (scope) => this.copyImage(scope, event),
26915
28488
  onExportImage: (scope) => this.copyImage(scope, event, true),
26916
28489
  canCopySelectionImage: resolveImageSelection(this.host) != null,
@@ -26934,8 +28507,8 @@ var ListTableEventController = class {
26934
28507
  getColumns: () => this.host.leafColumns,
26935
28508
  getHeaderTree: () => this.host.headerTree,
26936
28509
  getFrozenRowPosition: (rowIndex) => this.host.getFrozenRowPosition(rowIndex),
26937
- startExportTask: (task, text) => {
26938
- this.host.startExportTask(task, text);
28510
+ startExportTask: (task, text, defaultFileName) => {
28511
+ this.host.startExportTask(task, text, defaultFileName);
26939
28512
  },
26940
28513
  contentDownload: this.host.resolveContentDownloadAction(hitContent),
26941
28514
  onSelectHeader: (columnKey, rect) => {
@@ -27565,7 +29138,8 @@ var ListTableEventController = class {
27565
29138
  toViewportPoint: (x, y) => this.host.toViewportPoint(x, y),
27566
29139
  x: dragPos.x,
27567
29140
  y: dragPos.y,
27568
- text: `${resizeResult.column.title}: ${resizeResult.nextWidth}px`
29141
+ text: `${resizeResult.column.title}: ${resizeResult.nextWidth}px`,
29142
+ variant: "resize"
27569
29143
  });
27570
29144
  }
27571
29145
  this.host.scheduleRender();
@@ -28084,10 +29658,11 @@ var ListTableEventController = class {
28084
29658
  const actions = createListTableContextMenuActions({
28085
29659
  getRows: () => resolveNestedTableDisplayRows(content, getNestedState()),
28086
29660
  getAllRows: () => content.dataSource,
29661
+ getExportSummaryEnabled: () => getNestedState()?.summaryVisible === true,
28087
29662
  getColumns: () => columns,
28088
29663
  getHeaderTree: () => headerTree,
28089
29664
  hideMenu,
28090
- startExportTask: (task, text) => this.host.startExportTask(task, text),
29665
+ startExportTask: (task, text, defaultFileName) => this.host.startExportTask(task, text, defaultFileName),
28091
29666
  onFreezeRow: () => {
28092
29667
  },
28093
29668
  onUnfreezeRow: () => {
@@ -29479,7 +31054,17 @@ function createListTableEventHost(core) {
29479
31054
  return snapshot?.columnSegments ?? core.columnSegments;
29480
31055
  },
29481
31056
  persistColumnConfig: () => core.persistenceController.persistColumnConfig(),
29482
- startExportTask: (task, text) => core.contentActionController.startExportTask(task, text),
31057
+ startExportTask: (task, text, defaultFileName) => {
31058
+ const configured = core.options.exportOptions?.fileName?.trim();
31059
+ const extension = defaultFileName?.match(/\.(xlsx|csv|txt|json)$/i)?.[0];
31060
+ const fileName = configured && extension ? configured.replace(/\.(xlsx|csv|txt|json)$/i, "") + extension : defaultFileName;
31061
+ core.contentActionController.startExportTask(
31062
+ task,
31063
+ text,
31064
+ void 0,
31065
+ fileName
31066
+ );
31067
+ },
29483
31068
  resolveContentDownloadAction: (content) => core.contentActionController.resolveContentDownloadAction(
29484
31069
  content
29485
31070
  )
@@ -33180,6 +34765,7 @@ function assembleListTableCoreControllers(core, options) {
33180
34765
  requestRender: () => render()
33181
34766
  });
33182
34767
  core.contentActionController = new ListTableContentActionController({
34768
+ getSummaryVisible: () => Boolean(getCurrentRenderSnapshot()?.hasSummary),
33183
34769
  getOptions: () => core.options,
33184
34770
  getLeafColumns: () => core.leafColumns,
33185
34771
  overlayController: core.overlayController,
@@ -33946,6 +35532,9 @@ exports.ListTable = ListTable;
33946
35532
  exports.ROW_SELECTION_COLUMN = ROW_SELECTION_COLUMN;
33947
35533
  exports.SELECTION_COLUMN = SELECTION_COLUMN;
33948
35534
  exports.getListTableStoredPageSize = getListTableStoredPageSize;
35535
+ exports.listTableAntdIconNames = listTableAntdIconNames;
35536
+ exports.listTableBuiltinIconNames = listTableBuiltinIconNames;
35537
+ exports.listTableIconNames = listTableIconNames;
33949
35538
  exports.resetListTableStoredColumnConfig = resetListTableStoredColumnConfig;
33950
35539
  //# sourceMappingURL=index.cjs.map
33951
35540
  //# sourceMappingURL=index.cjs.map