@canvas-components/list-table 0.3.21 → 0.3.23

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.js CHANGED
@@ -929,15 +929,23 @@ function setColumnFixed(columns, targetKey, direction, initialColumns) {
929
929
  }
930
930
  updateColumnFixed(columns, targetKey, direction, initialColumns);
931
931
  }
932
- function setNestedColumnWidth(columns, targetKey, newWidth) {
932
+ function setNestedColumnWidth(columns, targetKey, newWidth, expandMaxWidth = false) {
933
933
  ensureColumnKeysInPlace(columns);
934
934
  for (const column of columns) {
935
935
  if (column.key === targetKey) {
936
936
  column.width = newWidth;
937
+ if (expandMaxWidth && newWidth > (column.maxWidth ?? DEFAULT_MAX_WIDTH)) {
938
+ column.maxWidth = newWidth;
939
+ }
937
940
  return;
938
941
  }
939
942
  if (column.children?.length) {
940
- setNestedColumnWidth(column.children, targetKey, newWidth);
943
+ setNestedColumnWidth(
944
+ column.children,
945
+ targetKey,
946
+ newWidth,
947
+ expandMaxWidth
948
+ );
941
949
  }
942
950
  }
943
951
  }
@@ -1082,16 +1090,149 @@ function applyInitialColumnVisibility(columns) {
1082
1090
  function replaceColumns(target, source) {
1083
1091
  target.splice(0, target.length, ...cloneColumns(source));
1084
1092
  }
1093
+ function preserveUserAddedColumns(params) {
1094
+ const keys = /* @__PURE__ */ new Set();
1095
+ const collect = (columns) => {
1096
+ columns.forEach((column) => {
1097
+ keys.add(resolveColumnKey(column));
1098
+ if (column.children?.length) collect(column.children);
1099
+ });
1100
+ };
1101
+ collect(params.nextColumns);
1102
+ const preserve = (source, target) => {
1103
+ source.forEach((column) => {
1104
+ const key = resolveColumnKey(column);
1105
+ if (column.userDefined && !keys.has(key)) {
1106
+ target.push({ ...column });
1107
+ keys.add(key);
1108
+ } else if (column.children?.length) {
1109
+ const matching = findColumnNode(params.nextColumns, key);
1110
+ if (matching?.children) preserve(column.children, matching.children);
1111
+ }
1112
+ });
1113
+ };
1114
+ preserve(params.runtimeColumns, params.nextColumns);
1115
+ }
1085
1116
  function buildHeaderSettingsItems(columns) {
1086
1117
  ensureColumnKeysInPlace(columns);
1087
1118
  const totalVisibleLeafCount = countVisibleLeafColumns(columns);
1088
- return columns.flatMap((column) => {
1119
+ return columns.flatMap((column, index) => {
1089
1120
  if (column.hideInSetting) {
1090
1121
  return [];
1091
1122
  }
1092
- return [buildHeaderSettingsItem(column, totalVisibleLeafCount, false)];
1123
+ return [
1124
+ buildHeaderSettingsItem(
1125
+ column,
1126
+ totalVisibleLeafCount,
1127
+ false,
1128
+ index + 1,
1129
+ columns.length
1130
+ )
1131
+ ];
1093
1132
  });
1094
1133
  }
1134
+ function saveHeaderSettingsColumn(columns, draft) {
1135
+ const title = draft.title.trim();
1136
+ if (!title) return "\u8BF7\u8F93\u5165\u5217\u540D\u79F0";
1137
+ const existing = draft.key ? findColumnNode(columns, draft.key) : null;
1138
+ if (draft.key && !existing) return "\u5217\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1139
+ const parent = !existing && draft.parentKey ? findColumnNode(columns, draft.parentKey) : null;
1140
+ if (draft.parentKey && !existing && !parent?.children?.length) {
1141
+ return "\u6240\u5C5E\u591A\u7EA7\u8868\u5934\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1142
+ }
1143
+ const siblings = existing ? findSiblingColumnsByKey(columns, draft.key) : parent?.children ?? columns;
1144
+ if (!siblings) return "\u5217\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1145
+ const maxOrder = siblings.length + (existing ? 0 : 1);
1146
+ if (draft.order != null && (!Number.isInteger(draft.order) || draft.order < 1 || draft.order > maxOrder)) {
1147
+ return `\u5217\u987A\u5E8F\u987B\u4ECB\u4E8E 1 \u548C ${maxOrder} \u4E4B\u95F4`;
1148
+ }
1149
+ const minWidth = draft.minWidth ?? 40;
1150
+ const maxWidth = draft.maxWidth ?? 2e3;
1151
+ const width = draft.width ?? 160;
1152
+ if (![minWidth, maxWidth, width].every(
1153
+ (value) => Number.isFinite(value) && value > 0
1154
+ ) || minWidth > maxWidth || width < minWidth || width > maxWidth) {
1155
+ return "\u5BBD\u5EA6\u987B\u4ECB\u4E8E\u6700\u5C0F\u5BBD\u5EA6\u548C\u6700\u5927\u5BBD\u5EA6\u4E4B\u95F4";
1156
+ }
1157
+ if (existing && !existing.userDefined) {
1158
+ existing.title = title;
1159
+ existing.settingTitle = title;
1160
+ existing.userTitle = title;
1161
+ existing.width = width;
1162
+ existing.minWidth = minWidth;
1163
+ existing.maxWidth = maxWidth;
1164
+ if (draft.order != null) moveColumnToOrder(siblings, existing, draft.order);
1165
+ return null;
1166
+ }
1167
+ const dataIndex = draft.dataIndex?.trim();
1168
+ if (!dataIndex || dataIndex.split(".").some((part) => !part.trim())) {
1169
+ return "dataIndex \u4E3A\u5FC5\u586B\u9879";
1170
+ }
1171
+ if (isHeaderDataIndexUsed(columns, dataIndex, draft.key)) {
1172
+ return "\u8BE5 dataIndex \u5DF2\u88AB\u5176\u4ED6\u5217\u4F7F\u7528";
1173
+ }
1174
+ const column = existing ?? { key: createUserColumnKey(columns) };
1175
+ column.title = title;
1176
+ column.settingTitle = title;
1177
+ column.dataIndex = dataIndex.split(".");
1178
+ column.width = width;
1179
+ column.minWidth = minWidth;
1180
+ column.maxWidth = maxWidth;
1181
+ column.fixed = draft.fixed;
1182
+ column.userDefined = true;
1183
+ column.allowSort = true;
1184
+ column.sorter = true;
1185
+ if (existing && draft.order != null) {
1186
+ moveColumnToOrder(siblings, existing, draft.order);
1187
+ } else if (!existing) {
1188
+ siblings.splice((draft.order ?? maxOrder) - 1, 0, column);
1189
+ }
1190
+ return null;
1191
+ }
1192
+ function findSiblingColumnsByKey(columns, key) {
1193
+ if (columns.some((column) => resolveColumnKey(column) === key))
1194
+ return columns;
1195
+ for (const column of columns) {
1196
+ if (!column.children?.length) continue;
1197
+ const siblings = findSiblingColumnsByKey(column.children, key);
1198
+ if (siblings) return siblings;
1199
+ }
1200
+ return null;
1201
+ }
1202
+ function moveColumnToOrder(siblings, column, order) {
1203
+ const currentIndex = siblings.indexOf(column);
1204
+ if (currentIndex < 0 || currentIndex === order - 1) return;
1205
+ siblings.splice(currentIndex, 1);
1206
+ siblings.splice(order - 1, 0, column);
1207
+ }
1208
+ function deleteHeaderSettingsColumn(columns, columnKey) {
1209
+ const target = findColumnNode(columns, columnKey);
1210
+ if (!target?.userDefined || countVisibleLeafColumns(columns) <= countVisibleLeafColumns([target]))
1211
+ return false;
1212
+ const remove = (items) => {
1213
+ const index = items.findIndex(
1214
+ (column) => resolveColumnKey(column) === columnKey
1215
+ );
1216
+ if (index >= 0) {
1217
+ items.splice(index, 1);
1218
+ return true;
1219
+ }
1220
+ return items.some(
1221
+ (column) => column.children?.length && remove(column.children)
1222
+ );
1223
+ };
1224
+ return remove(columns);
1225
+ }
1226
+ function createUserColumnKey(columns) {
1227
+ let index = 1;
1228
+ while (findColumnNode(columns, `user-column-${index}`)) index += 1;
1229
+ return `user-column-${index}`;
1230
+ }
1231
+ function isHeaderDataIndexUsed(columns, dataIndex, excludeKey) {
1232
+ return columns.some(
1233
+ (column) => resolveColumnKey(column) !== excludeKey && column.dataIndex != null && stringifyDataIndex(column.dataIndex) === dataIndex || column.children?.length && isHeaderDataIndexUsed(column.children, dataIndex, excludeKey)
1234
+ );
1235
+ }
1095
1236
  function setHeaderColumnVisible(columns, columnKey, visible) {
1096
1237
  if (!visible) {
1097
1238
  const targetLeafCount = getColumnLeafCount(columns, columnKey);
@@ -1290,10 +1431,18 @@ function findColumnNode(columns, columnKey) {
1290
1431
  }
1291
1432
  return null;
1292
1433
  }
1293
- function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1434
+ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden, order, siblingCount) {
1294
1435
  const hidden = parentHidden || !!column.hidden;
1295
- const children = column.children?.filter((child) => !child.hideInSetting).map(
1296
- (child) => buildHeaderSettingsItem(child, totalVisibleLeafCount, hidden)
1436
+ const children = column.children?.flatMap(
1437
+ (child, index) => child.hideInSetting ? [] : [
1438
+ buildHeaderSettingsItem(
1439
+ child,
1440
+ totalVisibleLeafCount,
1441
+ hidden,
1442
+ index + 1,
1443
+ column.children.length
1444
+ )
1445
+ ]
1297
1446
  );
1298
1447
  const leafCount = countLeafColumns([column]);
1299
1448
  const visibleLeafCount = hidden ? 0 : countVisibleLeafColumns([column]);
@@ -1305,6 +1454,14 @@ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1305
1454
  title: String(
1306
1455
  column.settingTitle ?? column.title ?? resolveColumnKey(column)
1307
1456
  ),
1457
+ dataIndex: column.dataIndex == null ? void 0 : stringifyDataIndex(column.dataIndex),
1458
+ userDefined: column.userDefined === true,
1459
+ width: column.width,
1460
+ minWidth: column.minWidth,
1461
+ maxWidth: column.maxWidth,
1462
+ fixed: column.fixed,
1463
+ order,
1464
+ siblingCount,
1308
1465
  checked,
1309
1466
  indeterminate,
1310
1467
  disabled,
@@ -1484,6 +1641,7 @@ var ListTableDomHost = class {
1484
1641
  wrapper.style.display = "flex";
1485
1642
  wrapper.style.flexDirection = "column";
1486
1643
  wrapper.style.minWidth = "0";
1644
+ wrapper.style.maxWidth = "100%";
1487
1645
  wrapper.style.boxSizing = "border-box";
1488
1646
  wrapper.style.overflow = "visible";
1489
1647
  const contentLayer = document.createElement("div");
@@ -6480,12 +6638,12 @@ function queryFilterWorkerEntrypoint() {
6480
6638
  let filters = [];
6481
6639
  const matchedIndices = [];
6482
6640
  const now2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
6483
- const escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6641
+ const escapeRegExp3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6484
6642
  const wildcardToRegExp2 = (value) => {
6485
6643
  const pattern = Array.from(value).map((char) => {
6486
6644
  if (char === "%") return ".*";
6487
6645
  if (char === "_") return ".";
6488
- return escapeRegExp2(char);
6646
+ return escapeRegExp3(char);
6489
6647
  }).join("");
6490
6648
  return new RegExp(`^${pattern}$`, "i");
6491
6649
  };
@@ -9113,7 +9271,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9113
9271
  const fontSize = style?.fontSize ?? theme.fontSize;
9114
9272
  const paddingInline = style?.paddingInline ?? 12;
9115
9273
  const paddingBlock = style?.paddingBlock ?? 0;
9116
- const textY = style?.verticalAlign === "top" ? rect.y + paddingBlock + fontSize / 2 : style?.verticalAlign === "bottom" ? rect.y + rect.height - paddingBlock - fontSize / 2 : rect.y + rect.height / 2;
9274
+ const centerY = style?.verticalAlign === "top" ? rect.y + paddingBlock + fontSize / 2 : style?.verticalAlign === "bottom" ? rect.y + rect.height - paddingBlock - fontSize / 2 : rect.y + rect.height / 2;
9117
9275
  if (!cellClip) {
9118
9276
  ctx.restore();
9119
9277
  return;
@@ -9138,7 +9296,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9138
9296
  ctx.clip();
9139
9297
  ctx.fillStyle = style?.color ?? theme.headerTextColor;
9140
9298
  ctx.font = `${style?.fontWeight ?? "600"} ${fontSize}px ${style?.fontFamily ?? theme.fontFamily}`;
9141
- ctx.textBaseline = "middle";
9299
+ ctx.textBaseline = "alphabetic";
9142
9300
  const align = style?.textAlign ?? column.align ?? "left";
9143
9301
  ctx.textAlign = align;
9144
9302
  const contentInsetStart = column.key === inlineContentInset?.columnKey ? inlineContentInset.width : 0;
@@ -9159,9 +9317,15 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9159
9317
  visibleRect,
9160
9318
  padding: paddingInline
9161
9319
  });
9162
- const textWidth = ctx.measureText(displayText).width;
9320
+ const bounds = measureTextBounds(ctx, displayText);
9321
+ const textY = resolveCenteredTextBaselineY({
9322
+ centerY,
9323
+ ascent: bounds.ascent,
9324
+ descent: bounds.descent
9325
+ });
9326
+ const textWidth = bounds.width;
9163
9327
  const textOriginX = textX - (align === "right" ? textWidth : align === "center" ? textWidth / 2 : 0);
9164
- const textTop = textY - fontSize / 2;
9328
+ const textTop = textY - bounds.ascent;
9165
9329
  const fragmentKey = `summary:${column.key}`;
9166
9330
  drawSelectableTextSelectionBackground({
9167
9331
  ctx,
@@ -9169,7 +9333,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9169
9333
  textSelection,
9170
9334
  textOriginX,
9171
9335
  textTop,
9172
- textHeight: fontSize,
9336
+ textHeight: bounds.height,
9173
9337
  rowIndex: Number.MAX_SAFE_INTEGER,
9174
9338
  columnKey: column.key,
9175
9339
  contentIndex: 0,
@@ -9189,7 +9353,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9189
9353
  x: textOriginX,
9190
9354
  y: textTop,
9191
9355
  width: textWidth,
9192
- height: fontSize
9356
+ height: bounds.height
9193
9357
  },
9194
9358
  cellClip
9195
9359
  ) ?? void 0,
@@ -11196,7 +11360,6 @@ function roundRectPath3(ctx, x, y, width, height, radius) {
11196
11360
  var TAG_HORIZONTAL_PADDING = 8;
11197
11361
  var TAG_HEIGHT = 22;
11198
11362
  var TAG_RADIUS = 4;
11199
- var TAG_TEXT_OPTICAL_OFFSET_Y = 1;
11200
11363
  var ANT_TAG_PRESET_MAP = {
11201
11364
  default: {
11202
11365
  backgroundColor: "#fafafa",
@@ -11303,12 +11466,24 @@ function drawBodyTagContent(params) {
11303
11466
  const textColor = resolveTagTextColor(content, palette.textColor);
11304
11467
  const textIndent = resolveContentTextIndent(content);
11305
11468
  const paddingInline = content.paddingInline ?? TAG_HORIZONTAL_PADDING;
11469
+ const drawLeft = Math.round(cursorX);
11470
+ const drawTop = Math.round(top);
11471
+ const drawWidth = Math.max(Math.round(cursorX + width) - drawLeft, 1);
11472
+ const drawHeight = Math.max(Math.round(top + height) - drawTop, 1);
11306
11473
  ctx.save();
11307
11474
  ctx.globalAlpha *= resolveContentOpacity(content);
11308
- drawRoundedRectPath2(ctx, cursorX, top, width, height, radius);
11475
+ drawRoundedRectPath2(ctx, drawLeft, drawTop, drawWidth, drawHeight, radius);
11309
11476
  ctx.fillStyle = content.style?.backgroundColor ?? palette.backgroundColor;
11310
11477
  ctx.fill();
11311
11478
  if (bordered) {
11479
+ drawRoundedRectPath2(
11480
+ ctx,
11481
+ drawLeft + 0.5,
11482
+ drawTop + 0.5,
11483
+ Math.max(drawWidth - 1, 0),
11484
+ Math.max(drawHeight - 1, 0),
11485
+ Math.max(radius - 0.5, 0)
11486
+ );
11312
11487
  ctx.strokeStyle = palette.borderColor;
11313
11488
  ctx.lineWidth = 1;
11314
11489
  ctx.stroke();
@@ -11330,7 +11505,7 @@ function drawBodyTagContent(params) {
11330
11505
  textIndent,
11331
11506
  textAlign: resolveContentTextAlign(content, "center")
11332
11507
  });
11333
- const centerY = top + height / 2 + TAG_TEXT_OPTICAL_OFFSET_Y;
11508
+ const centerY = rect.y + rect.height / 2;
11334
11509
  const textY = resolveCenteredTextBaselineY({
11335
11510
  centerY,
11336
11511
  ascent: bounds.ascent,
@@ -11539,7 +11714,7 @@ function drawBodyTextContent(params) {
11539
11714
  textHeight: bounds.height,
11540
11715
  color: theme.textSelectionBackgroundColor ?? "#99c2ff"
11541
11716
  });
11542
- if (searchMatch && searchMatch.rowIndex === rowIndex && searchMatch.columnKey === column.key && searchMatch.keyword) {
11717
+ if (searchMatch && searchMatch.rowIndex === rowIndex && searchMatch.columnKey === column.key && (searchMatch.contentIndex == null || searchMatch.contentIndex === contentIndex) && searchMatch.keyword) {
11543
11718
  const start = Math.max(0, Math.min(searchMatch.start, content.text.length));
11544
11719
  const end = Math.max(start, Math.min(searchMatch.end, content.text.length));
11545
11720
  const prefixWidth = ctx.measureText(content.text.slice(0, start)).width;
@@ -12295,6 +12470,12 @@ function resolveRawBodyCellContents(params) {
12295
12470
  }
12296
12471
  ];
12297
12472
  }
12473
+ if (column.cellType === "emoji") {
12474
+ return normalizeCellContents({
12475
+ type: "emoji",
12476
+ emoji: formattedText ?? String(value ?? "")
12477
+ });
12478
+ }
12298
12479
  if (column.cellType === "money") {
12299
12480
  return [
12300
12481
  {
@@ -12352,6 +12533,21 @@ function normalizeDrawableCellContents(contents) {
12352
12533
  ).map(normalizeCellContentItem);
12353
12534
  }
12354
12535
  function normalizeCellContentItem(content) {
12536
+ if (content.type === "emoji") {
12537
+ const { emoji, size, ...rest } = content;
12538
+ return {
12539
+ ...rest,
12540
+ type: "text",
12541
+ text: emoji,
12542
+ fontSize: size ?? 20,
12543
+ style: {
12544
+ ...content.style,
12545
+ fontSize: content.style?.fontSize ?? size ?? 20,
12546
+ fontWeight: content.style?.fontWeight ?? "normal",
12547
+ fontFamily: content.style?.fontFamily ?? '"Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif'
12548
+ }
12549
+ };
12550
+ }
12355
12551
  if (content.type === "timeline") {
12356
12552
  return { ...content, style: { ...content.style, display: "block" } };
12357
12553
  }
@@ -13813,6 +14009,9 @@ function buildBodyContentsPlainText(contents) {
13813
14009
  if (content.type === "icon") {
13814
14010
  return content.icon;
13815
14011
  }
14012
+ if (content.type === "emoji") {
14013
+ return content.emoji;
14014
+ }
13816
14015
  if (content.type === "text" || content.type === "link" || content.type === "tag") {
13817
14016
  return content.text;
13818
14017
  }
@@ -14150,6 +14349,9 @@ function isCellContentDisabled(content) {
14150
14349
  if (content.type === "tag") {
14151
14350
  return false;
14152
14351
  }
14352
+ if (content.type === "emoji") {
14353
+ return false;
14354
+ }
14153
14355
  if (content.type === "money") {
14154
14356
  return false;
14155
14357
  }
@@ -18750,7 +18952,7 @@ function openCellEditingSession(params) {
18750
18952
  }
18751
18953
  const editorConfig = resolveEditorConfig(editConfig);
18752
18954
  const editingValue = initialValue === void 0 ? currentValue : initialValue;
18753
- const selectOnFocus = !(initialValue !== void 0 && (currentValue == null || currentValue === ""));
18955
+ const selectOnFocus = initialValue === void 0;
18754
18956
  const hostRect = toHostRect ? toHostRect(descriptor.rect) : descriptor.rect;
18755
18957
  const zoom = typeof theme.contentZoom === "number" && Number.isFinite(theme.contentZoom) && theme.contentZoom > 0 ? theme.contentZoom : 1;
18756
18958
  const paddingInline = (column.cellStyle?.paddingInline ?? DEFAULT_EDITOR_PADDING_INLINE) * zoom;
@@ -26058,18 +26260,58 @@ function autoFitListTableColumnWidths(params) {
26058
26260
  );
26059
26261
  }
26060
26262
  const nextWidth = Math.ceil(
26061
- clamp(measuredWidth, column.minWidth, column.maxWidth)
26263
+ params.fillContainerWidth == null ? clamp(measuredWidth, column.minWidth, column.maxWidth) : Math.max(measuredWidth, column.minWidth)
26062
26264
  );
26063
26265
  column.width = nextWidth;
26064
- setNestedColumnWidth(options.columns, column.key, nextWidth);
26266
+ if (params.fillContainerWidth != null) {
26267
+ column.maxWidth = Math.max(column.maxWidth, nextWidth);
26268
+ }
26269
+ setNestedColumnWidth(
26270
+ options.columns,
26271
+ column.key,
26272
+ nextWidth,
26273
+ params.fillContainerWidth != null
26274
+ );
26065
26275
  fitted = true;
26066
26276
  });
26277
+ if (fitted && params.fillContainerWidth != null) {
26278
+ const hostWidth = params.hostWidth;
26279
+ const measuredTotalWidth = leafColumns.reduce(
26280
+ (sum, column) => sum + column.width,
26281
+ 0
26282
+ );
26283
+ const shouldPreserveOverflow = hostWidth != null && measuredTotalWidth > params.fillContainerWidth && measuredTotalWidth <= hostWidth;
26284
+ fillAutoFitColumnWidths(leafColumns, params.fillContainerWidth);
26285
+ if (shouldPreserveOverflow && hostWidth != null) {
26286
+ fillAutoFitColumnWidths(leafColumns, Math.ceil(hostWidth) + 1);
26287
+ }
26288
+ leafColumns.forEach((column) => {
26289
+ if (!isSystemColumnKey(column.key)) {
26290
+ setNestedColumnWidth(options.columns, column.key, column.width, true);
26291
+ }
26292
+ });
26293
+ }
26067
26294
  ctx.restore();
26068
26295
  if (fitted) {
26069
26296
  options.stretchColumns = false;
26070
26297
  }
26071
26298
  return fitted;
26072
26299
  }
26300
+ function fillAutoFitColumnWidths(columns, containerWidth) {
26301
+ let remaining = Math.max(
26302
+ Math.round(
26303
+ containerWidth - columns.reduce((sum, column) => sum + column.width, 0)
26304
+ ),
26305
+ 0
26306
+ );
26307
+ const candidates = columns.filter((column) => !isSystemColumnKey(column.key));
26308
+ candidates.forEach((column, index) => {
26309
+ const extra = Math.ceil(remaining / (candidates.length - index));
26310
+ column.width += extra;
26311
+ column.maxWidth = Math.max(column.maxWidth, column.width);
26312
+ remaining -= extra;
26313
+ });
26314
+ }
26073
26315
  function resolveAutoFitMeasureRows(rows, range = {}) {
26074
26316
  if (rows.length === 0) {
26075
26317
  return [];
@@ -26136,6 +26378,134 @@ function measureHeaderWidth(ctx, column, theme) {
26136
26378
  return Math.ceil(contentWidth + HEADER_PADDING_INLINE * 2 + actionWidth);
26137
26379
  }
26138
26380
 
26381
+ // src/features/search/search-matcher.ts
26382
+ function createListTableSearchMatcher(keyword, options) {
26383
+ const pattern = options.mode === "regex" ? keyword : keyword.trim();
26384
+ if (!pattern) {
26385
+ return { findMatches: () => [], error: null, active: false };
26386
+ }
26387
+ if (options.mode === "fuzzy") {
26388
+ const needle = options.caseSensitive ? pattern : pattern.toLocaleLowerCase();
26389
+ return {
26390
+ error: null,
26391
+ active: true,
26392
+ findMatches: (text) => {
26393
+ const source = options.caseSensitive ? text : text.toLocaleLowerCase();
26394
+ const matches = [];
26395
+ let start = source.indexOf(needle);
26396
+ while (start >= 0) {
26397
+ matches.push({ start, end: start + pattern.length });
26398
+ start = source.indexOf(needle, start + needle.length);
26399
+ }
26400
+ return matches;
26401
+ }
26402
+ };
26403
+ }
26404
+ if (options.mode === "exact") {
26405
+ const needle = options.caseSensitive ? pattern : pattern.toLocaleLowerCase();
26406
+ return {
26407
+ error: null,
26408
+ active: true,
26409
+ findMatches: (text) => {
26410
+ const source = options.caseSensitive ? text : text.toLocaleLowerCase();
26411
+ return source === needle ? [{ start: 0, end: text.length }] : [];
26412
+ }
26413
+ };
26414
+ }
26415
+ try {
26416
+ const source = options.mode === "wildcard" ? wildcardToRegExpSource(pattern) : pattern;
26417
+ const expression = new RegExp(source, options.caseSensitive ? "g" : "gi");
26418
+ return {
26419
+ error: null,
26420
+ active: true,
26421
+ findMatches: (text) => {
26422
+ const matches = [];
26423
+ expression.lastIndex = 0;
26424
+ let result;
26425
+ while ((result = expression.exec(text)) !== null) {
26426
+ if (result[0].length > 0) {
26427
+ matches.push({ start: result.index, end: expression.lastIndex });
26428
+ } else {
26429
+ expression.lastIndex += 1;
26430
+ }
26431
+ }
26432
+ return matches;
26433
+ }
26434
+ };
26435
+ } catch {
26436
+ return { findMatches: () => [], error: "\u6B63\u5219\u8868\u8FBE\u5F0F\u65E0\u6548", active: false };
26437
+ }
26438
+ }
26439
+ function wildcardToRegExpSource(pattern) {
26440
+ let source = "";
26441
+ for (let index = 0; index < pattern.length; index += 1) {
26442
+ const char = pattern[index];
26443
+ if (char === "\\" && index + 1 < pattern.length) {
26444
+ source += escapeRegExp2(pattern[++index]);
26445
+ } else if (char === "*") {
26446
+ source += ".*";
26447
+ } else if (char === "?") {
26448
+ source += ".";
26449
+ } else {
26450
+ source += escapeRegExp2(char);
26451
+ }
26452
+ }
26453
+ return source;
26454
+ }
26455
+ function escapeRegExp2(value) {
26456
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26457
+ }
26458
+ function resolveListTableSearchCellTexts(params) {
26459
+ const { record, rowIndex, column } = params;
26460
+ if (!column.render && !column.dataFormat && !column.cellType) {
26461
+ return [
26462
+ {
26463
+ contentIndex: 0,
26464
+ text: String(getValueByDataIndex(record, column.dataIndex) ?? "")
26465
+ }
26466
+ ];
26467
+ }
26468
+ return resolveBodyCellContents({ record, rowIndex, column }).flatMap(
26469
+ (content, contentIndex) => content.type === "text" ? [{ contentIndex, text: content.text }] : []
26470
+ );
26471
+ }
26472
+ function buildHeaderDataIndexOptions(rows, columns) {
26473
+ const paths = /* @__PURE__ */ new Set();
26474
+ const used = /* @__PURE__ */ new Map();
26475
+ const visitColumns = (items) => {
26476
+ items.forEach((column) => {
26477
+ if (column.dataIndex != null) {
26478
+ const path = stringifyDataIndex(column.dataIndex);
26479
+ if (!used.has(path)) {
26480
+ used.set(
26481
+ path,
26482
+ String(column.settingTitle ?? column.title ?? column.key ?? path)
26483
+ );
26484
+ }
26485
+ }
26486
+ if (column.children?.length) visitColumns(column.children);
26487
+ });
26488
+ };
26489
+ visitColumns(columns);
26490
+ const visitValue = (value, prefix, depth) => {
26491
+ if (!value || typeof value !== "object" || Array.isArray(value) || value instanceof Date)
26492
+ return;
26493
+ Object.entries(value).forEach(([key, child]) => {
26494
+ if (paths.size >= 200) return;
26495
+ const path = prefix ? `${prefix}.${key}` : key;
26496
+ paths.add(path);
26497
+ if (depth < 3) visitValue(child, path, depth + 1);
26498
+ });
26499
+ };
26500
+ rows.slice(0, 50).forEach((row) => visitValue(row, "", 0));
26501
+ used.forEach((_label, path) => paths.add(path));
26502
+ return [...paths].map((value) => ({
26503
+ value,
26504
+ disabled: used.has(value),
26505
+ ...used.has(value) ? { label: used.get(value) } : null
26506
+ }));
26507
+ }
26508
+
26139
26509
  // src/features/overlay/context-menu-builder.ts
26140
26510
  function createListTableContextMenuActions(params) {
26141
26511
  return {
@@ -26286,6 +26656,10 @@ function createListTableContextMenuActions(params) {
26286
26656
  params.hideMenu();
26287
26657
  params.onAutoFitAllColumns?.();
26288
26658
  } : void 0,
26659
+ onAutoFitFillContainer: params.onAutoFitFillContainer ? () => {
26660
+ params.hideMenu();
26661
+ params.onAutoFitFillContainer?.();
26662
+ } : void 0,
26289
26663
  onToggleGroupingBar: params.onToggleGroupingBar ? () => {
26290
26664
  params.hideMenu();
26291
26665
  params.onToggleGroupingBar?.();
@@ -26294,6 +26668,8 @@ function createListTableContextMenuActions(params) {
26294
26668
  onChangeZoom: params.onChangeZoom,
26295
26669
  onToggleCurrentColumn: params.onToggleCurrentColumn ?? params.onToggleColumn,
26296
26670
  onToggleColumn: params.onToggleColumn,
26671
+ onSaveColumn: params.onSaveColumn,
26672
+ onDeleteColumn: params.onDeleteColumn,
26297
26673
  onChangeCachePreference: params.onChangeCachePreference ? (category, enabled) => {
26298
26674
  params.hideMenu();
26299
26675
  params.onChangeCachePreference?.(category, enabled);
@@ -26362,6 +26738,7 @@ function buildListTableContextMenuConfig(params) {
26362
26738
  x,
26363
26739
  y,
26364
26740
  columns,
26741
+ dataSource,
26365
26742
  columnKey,
26366
26743
  isHeaderArea,
26367
26744
  isSummaryArea = false,
@@ -26386,6 +26763,7 @@ function buildListTableContextMenuConfig(params) {
26386
26763
  const isBodyArea = bodyRowIndex != null;
26387
26764
  const isSelectionColumn = columnKey === ROW_SELECTION_COLUMN_KEY || columnKey === ROW_SELECTOR_COLUMN_KEY;
26388
26765
  const enableCopy = enabledFeatures.has("copy");
26766
+ const enableChart = enabledFeatures.has("chart");
26389
26767
  const enableSearch = enabledFeatures.has("search");
26390
26768
  const enableExport = enabledFeatures.has("export");
26391
26769
  const enableDownloadContent = enabledFeatures.has("downloadContent");
@@ -26433,6 +26811,7 @@ function buildListTableContextMenuConfig(params) {
26433
26811
  return {
26434
26812
  x,
26435
26813
  y,
26814
+ onCreateChart: enableChart && (isBodyArea || isExpandedArea || isHeaderArea && columnKey !== ROW_SELECTION_COLUMN_KEY) ? params.onCreateChart : void 0,
26436
26815
  columns: enableColumnVisibility ? headerItems : void 0,
26437
26816
  density: enableDensity ? density : void 0,
26438
26817
  zoom: enableZoom ? normalizeContextMenuZoom(zoom) : void 0,
@@ -26515,11 +26894,15 @@ function buildListTableContextMenuConfig(params) {
26515
26894
  onResetDataFormat: enableReset && isTableSettingsArea ? actions.onResetDataFormat : void 0,
26516
26895
  onAutoFitCurrentColumn: enableColumnWidth && isHeaderArea && !isSelectionColumn && actions.onAutoFitCurrentColumn ? () => actions.onAutoFitCurrentColumn?.(columnKey) : void 0,
26517
26896
  onAutoFitAllColumns: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitAllColumns ? actions.onAutoFitAllColumns : void 0,
26897
+ onAutoFitFillContainer: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitFillContainer ? actions.onAutoFitFillContainer : void 0,
26518
26898
  groupingBarVisible,
26519
26899
  onToggleGroupingBar: enableGrouping && (isTableSettingsArea || groupingBarArea) ? actions.onToggleGroupingBar : void 0,
26520
26900
  onChangeDensity: enableDensity ? actions.onChangeDensity : void 0,
26521
26901
  onChangeZoom: enableZoom ? actions.onChangeZoom : void 0,
26522
26902
  onToggleColumn: enableColumnVisibility && isTableSettingsArea ? actions.onToggleColumn : void 0,
26903
+ dataIndexOptions: enableColumnVisibility && isTableSettingsArea ? buildHeaderDataIndexOptions(dataSource ?? [], columns) : void 0,
26904
+ onSaveColumn: enableColumnVisibility && isTableSettingsArea ? actions.onSaveColumn : void 0,
26905
+ onDeleteColumn: enableColumnVisibility && isTableSettingsArea ? actions.onDeleteColumn : void 0,
26523
26906
  columnSettingsCacheAvailable: Boolean(params.storageKey),
26524
26907
  cachePreferences: params.cachePreferences,
26525
26908
  onChangeCachePreference: enabledFeatures.has("cache") ? actions.onChangeCachePreference : void 0,
@@ -26575,6 +26958,7 @@ function findSummaryColumn(columns, columnKey) {
26575
26958
  }
26576
26959
  var DEFAULT_CONTEXT_MENU_FEATURES = [
26577
26960
  "copy",
26961
+ "chart",
26578
26962
  "search",
26579
26963
  "export",
26580
26964
  "downloadContent",
@@ -26723,6 +27107,7 @@ function showHeaderContextMenu(params) {
26723
27107
  onResetDataFormat,
26724
27108
  onAutoFitCurrentColumn,
26725
27109
  onAutoFitAllColumns,
27110
+ onAutoFitFillContainer,
26726
27111
  groupingBarVisible,
26727
27112
  groupingBarArea,
26728
27113
  onToggleGroupingBar,
@@ -26730,6 +27115,8 @@ function showHeaderContextMenu(params) {
26730
27115
  onChangeZoom,
26731
27116
  onToggleCurrentColumn,
26732
27117
  onToggleColumn,
27118
+ onSaveColumn,
27119
+ onDeleteColumn,
26733
27120
  onExpandAllCollapsedColumns,
26734
27121
  onClose,
26735
27122
  onToggleSummary,
@@ -26757,7 +27144,8 @@ function showHeaderContextMenu(params) {
26757
27144
  const isSummaryArea = result.area === "summary";
26758
27145
  const isExpandedArea = result.area === "expanded-row" || result.columnKey === "__expanded_row__";
26759
27146
  const isSelectionColumn = result.columnKey === ROW_SELECTION_COLUMN_KEY || result.columnKey === ROW_SELECTOR_COLUMN_KEY;
26760
- if (!isHeaderArea && !isBodyArea && !groupingBarArea && !isExpandedArea || !result.columnKey && !groupingBarArea && !isExpandedArea || isHeaderArea && isSelectionColumn) {
27147
+ const isChartCorner = isHeaderArea && result.columnKey === ROW_SELECTOR_COLUMN_KEY && resolveEnabledContextMenuFeatures(options.contextMenu).has("chart");
27148
+ if (!isHeaderArea && !isBodyArea && !groupingBarArea && !isExpandedArea || !result.columnKey && !groupingBarArea && !isExpandedArea || isHeaderArea && isSelectionColumn && !isChartCorner) {
26761
27149
  headerContextMenu.hide();
26762
27150
  return false;
26763
27151
  }
@@ -26770,7 +27158,7 @@ function showHeaderContextMenu(params) {
26770
27158
  fixedPopup.hide();
26771
27159
  hideBodyTooltip();
26772
27160
  const contextColumnKey = result.columnKey ?? "";
26773
- if (isHeaderArea) {
27161
+ if (isHeaderArea && !isChartCorner) {
26774
27162
  onSelectHeader(contextColumnKey, result.rect);
26775
27163
  }
26776
27164
  const bodyRowIndex = isBodyArea && !isSummaryArea && !isExpandedArea && typeof result.rowIndex === "number" ? result.rowIndex : null;
@@ -26786,11 +27174,13 @@ function showHeaderContextMenu(params) {
26786
27174
  x: event.clientX,
26787
27175
  y: event.clientY,
26788
27176
  columns: options.columns,
27177
+ dataSource: options.dataSource,
26789
27178
  columnKey: result.columnKey ?? "",
26790
27179
  isHeaderArea,
26791
27180
  isSummaryArea,
26792
27181
  isExpandedArea,
26793
27182
  onCopySummaryRowText: params.onCopySummaryRowText,
27183
+ onCreateChart: params.onCreateChart,
26794
27184
  onCopyImage: params.onCopyImage,
26795
27185
  onExportImage: params.onExportImage,
26796
27186
  canCopySelectionImage: params.canCopySelectionImage,
@@ -26836,11 +27226,14 @@ function showHeaderContextMenu(params) {
26836
27226
  onResetDataFormat,
26837
27227
  onAutoFitCurrentColumn,
26838
27228
  onAutoFitAllColumns,
27229
+ onAutoFitFillContainer,
26839
27230
  onToggleGroupingBar,
26840
27231
  onChangeDensity,
26841
27232
  onChangeZoom,
26842
27233
  onToggleCurrentColumn,
26843
27234
  onToggleColumn,
27235
+ onSaveColumn,
27236
+ onDeleteColumn,
26844
27237
  onExpandAllCollapsedColumns,
26845
27238
  onClose,
26846
27239
  onToggleSummary,
@@ -26880,6 +27273,77 @@ function resolveContextMenuDensity(rowHeight) {
26880
27273
  return rowHeight === 48 ? "middle" : "compact";
26881
27274
  }
26882
27275
 
27276
+ // src/features/overlay/chart-data.ts
27277
+ function createListTableChartData(params) {
27278
+ const {
27279
+ rows,
27280
+ columns,
27281
+ columnKey,
27282
+ rowIndex,
27283
+ selectionRange,
27284
+ selectedRowRange,
27285
+ selectedColumnRange
27286
+ } = params;
27287
+ const startRow = Math.max(
27288
+ selectionRange?.startRowIndex ?? selectedRowRange?.start ?? Math.max((rowIndex ?? 0) - 10, 0),
27289
+ 0
27290
+ );
27291
+ const endRow = Math.min(
27292
+ selectionRange?.endRowIndex ?? selectedRowRange?.end ?? startRow + 199,
27293
+ rows.length - 1
27294
+ );
27295
+ const selectedColumns = selectionRange ? columns.slice(
27296
+ Math.max(selectionRange.startColumnIndex, 0),
27297
+ selectionRange.endColumnIndex + 1
27298
+ ) : selectedRowRange ? columns : selectedColumnRange ? columns.slice(
27299
+ Math.max(selectedColumnRange.start, 0),
27300
+ selectedColumnRange.end + 1
27301
+ ) : columns.filter((column) => column.key === columnKey);
27302
+ const chartColumns = selectedColumns.filter(
27303
+ (column) => column.key !== ROW_SELECTION_COLUMN_KEY && column.key !== ROW_SELECTOR_COLUMN_KEY && column.key !== EXPAND_COLUMN_KEY
27304
+ ).slice(0, 12);
27305
+ if (startRow > endRow || chartColumns.length === 0) return null;
27306
+ const sampledRows = rows.slice(
27307
+ startRow,
27308
+ Math.min(endRow + 1, startRow + 200)
27309
+ );
27310
+ const values = chartColumns.map(
27311
+ (column) => sampledRows.map(
27312
+ (record, offset) => getCellClipboardText(record, startRow + offset, column)
27313
+ )
27314
+ );
27315
+ const numericColumns = chartColumns.flatMap((column, index) => {
27316
+ const numbers = values[index]?.map(parseChartNumber) ?? [];
27317
+ return numbers.some((value) => value !== null) ? [{ name: column.title, data: numbers.map((value) => value ?? 0) }] : [];
27318
+ });
27319
+ if (numericColumns.length === 0) return null;
27320
+ const labelIndex = chartColumns.findIndex(
27321
+ (_, index) => values[index]?.every((value) => parseChartNumber(value) === null)
27322
+ );
27323
+ if (sampledRows.length === 1 && chartColumns.length > 1) {
27324
+ return {
27325
+ labels: numericColumns.map((series) => series.name),
27326
+ series: [
27327
+ {
27328
+ name: values[labelIndex]?.[0] || String(startRow + 1),
27329
+ data: numericColumns.map((series) => series.data[0] ?? 0)
27330
+ }
27331
+ ]
27332
+ };
27333
+ }
27334
+ const labels = sampledRows.map(
27335
+ (_, index) => labelIndex >= 0 ? values[labelIndex]?.[index] || String(startRow + index + 1) : String(startRow + index + 1)
27336
+ );
27337
+ return { labels, series: numericColumns };
27338
+ }
27339
+ function parseChartNumber(value) {
27340
+ const normalized = value.trim().replace(/[,,\s¥¥$]/g, "");
27341
+ if (!normalized) return null;
27342
+ const percentage = normalized.endsWith("%");
27343
+ const parsed = Number(percentage ? normalized.slice(0, -1) : normalized);
27344
+ return Number.isFinite(parsed) ? parsed : null;
27345
+ }
27346
+
26883
27347
  // src/features/tooltip/tooltip-feature.ts
26884
27348
  function getHeaderActionTooltipText(result, sortState) {
26885
27349
  const area = result.area;
@@ -27901,6 +28365,11 @@ var EDITABLE_CELL_ROW_SELECTION_DELAY = 300;
27901
28365
  var ListTableEventController = class {
27902
28366
  constructor(host) {
27903
28367
  __publicField(this, "searchKeyword", "");
28368
+ __publicField(this, "searchOptions", {
28369
+ mode: "fuzzy",
28370
+ caseSensitive: false
28371
+ });
28372
+ __publicField(this, "searchError", null);
27904
28373
  __publicField(this, "searchMatches", []);
27905
28374
  __publicField(this, "searchCurrentIndex", -1);
27906
28375
  __publicField(this, "textSelectionDrag", null);
@@ -28463,6 +28932,15 @@ var ListTableEventController = class {
28463
28932
  getAllRows: () => this.host.options.dataSource,
28464
28933
  getExportSummaryEnabled: () => Boolean(this.host.currentRenderSnapshot?.hasSummary),
28465
28934
  onCopyImage: (scope) => this.copyImage(scope, event),
28935
+ onCreateChart: () => createListTableChartData({
28936
+ rows: this.host.getDisplayData(),
28937
+ columns: this.host.leafColumns,
28938
+ columnKey: contextResult.columnKey ?? "",
28939
+ rowIndex: typeof contextResult.rowIndex === "number" ? contextResult.rowIndex : null,
28940
+ selectionRange: this.host.rangeHighlight.selectedCellRange,
28941
+ selectedRowRange: this.host.rangeHighlight.selectedRowRange,
28942
+ selectedColumnRange: this.host.rangeHighlight.selectedColumnRange
28943
+ }),
28466
28944
  onExportImage: (scope) => this.copyImage(scope, event, true),
28467
28945
  canCopySelectionImage: resolveImageSelection(this.host) != null,
28468
28946
  onCopySummaryRowText: () => {
@@ -28495,15 +28973,21 @@ var ListTableEventController = class {
28495
28973
  this.host.selectHeader(columnKey, rect);
28496
28974
  },
28497
28975
  onSelectBodyRow: (rowIndex, columnKey) => {
28976
+ const selectedCellRange = this.host.rangeHighlight.selectedCellRange;
28977
+ const columnIndex = this.host.leafColumns.findIndex(
28978
+ (column) => column.key === columnKey
28979
+ );
28498
28980
  this.host.selection = {
28499
28981
  rowIndex,
28500
28982
  columnKey
28501
28983
  };
28502
28984
  this.host.clearSelectedHeader();
28503
- this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
28504
- current: this.host.rangeHighlight,
28505
- rowIndex
28506
- });
28985
+ if (!selectedCellRange || rowIndex < selectedCellRange.startRowIndex || rowIndex > selectedCellRange.endRowIndex || columnIndex < selectedCellRange.startColumnIndex || columnIndex > selectedCellRange.endColumnIndex) {
28986
+ this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
28987
+ current: this.host.rangeHighlight,
28988
+ rowIndex
28989
+ });
28990
+ }
28507
28991
  this.host.summarySelected = false;
28508
28992
  },
28509
28993
  getSelectionRange: () => this.host.rangeHighlight.selectedCellRange ?? null,
@@ -28613,6 +29097,9 @@ var ListTableEventController = class {
28613
29097
  onAutoFitAllColumns: () => {
28614
29098
  this.autoFitColumnWidths();
28615
29099
  },
29100
+ onAutoFitFillContainer: () => {
29101
+ this.autoFitColumnWidths(void 0, true);
29102
+ },
28616
29103
  groupingBarVisible: this.host.groupBarVisible,
28617
29104
  groupingBarArea,
28618
29105
  onToggleGroupingBar: () => {
@@ -28631,6 +29118,8 @@ var ListTableEventController = class {
28631
29118
  onToggleColumn: (columnKey, visible) => {
28632
29119
  this.host.toggleHeaderColumnVisible(columnKey, visible);
28633
29120
  },
29121
+ onSaveColumn: (draft) => this.host.saveHeaderColumn(draft),
29122
+ onDeleteColumn: (columnKey) => this.host.deleteHeaderColumn(columnKey),
28634
29123
  onExpandAllCollapsedColumns: () => {
28635
29124
  this.host.expandAllCollapsedColumns();
28636
29125
  },
@@ -29431,11 +29920,17 @@ var ListTableEventController = class {
29431
29920
  publishSearchRequest() {
29432
29921
  const request = {
29433
29922
  keyword: this.searchKeyword,
29923
+ mode: this.searchOptions.mode,
29924
+ caseSensitive: this.searchOptions.caseSensitive,
29925
+ error: this.searchError,
29434
29926
  matchCount: this.searchMatches.length,
29435
29927
  currentIndex: this.searchCurrentIndex,
29436
- onSubmit: (keyword) => {
29928
+ onSubmit: (keyword, options) => {
29437
29929
  this.searchKeyword = keyword;
29438
- this.searchMatches = this.resolveSearchMatches(keyword);
29930
+ this.searchOptions = options;
29931
+ const matcher = createListTableSearchMatcher(keyword, options);
29932
+ this.searchError = matcher.error;
29933
+ this.searchMatches = matcher.active ? this.resolveSearchMatches(matcher.findMatches) : [];
29439
29934
  this.searchCurrentIndex = this.searchMatches.length > 0 ? 0 : -1;
29440
29935
  this.applyCurrentSearchMatch();
29441
29936
  this.publishSearchRequest();
@@ -29449,6 +29944,7 @@ var ListTableEventController = class {
29449
29944
  },
29450
29945
  onClose: () => {
29451
29946
  this.searchKeyword = "";
29947
+ this.searchError = null;
29452
29948
  this.searchMatches = [];
29453
29949
  this.searchCurrentIndex = -1;
29454
29950
  this.host.rangeHighlight = {
@@ -29461,30 +29957,24 @@ var ListTableEventController = class {
29461
29957
  };
29462
29958
  this.host.options.ui?.onSearchRequest?.(request);
29463
29959
  }
29464
- resolveSearchMatches(keyword) {
29465
- const normalizedKeyword = keyword.trim().toLocaleLowerCase();
29466
- if (!normalizedKeyword) return [];
29960
+ resolveSearchMatches(findMatches) {
29467
29961
  const matches = [];
29468
29962
  this.host.getDisplayData().forEach((record, rowIndex) => {
29469
29963
  this.host.leafColumns.forEach((column) => {
29470
29964
  if (isSystemColumnKey(column.key)) return;
29471
- const text = String(
29472
- getValueByDataIndex(record, column.dataIndex) ?? ""
29965
+ resolveListTableSearchCellTexts({ record, rowIndex, column }).forEach(
29966
+ ({ text, contentIndex }) => {
29967
+ findMatches(text).forEach(({ start, end }) => {
29968
+ matches.push({
29969
+ rowIndex,
29970
+ columnKey: column.key,
29971
+ contentIndex,
29972
+ start,
29973
+ end
29974
+ });
29975
+ });
29976
+ }
29473
29977
  );
29474
- const source = text.toLocaleLowerCase();
29475
- let start = source.indexOf(normalizedKeyword);
29476
- while (start >= 0) {
29477
- matches.push({
29478
- rowIndex,
29479
- columnKey: column.key,
29480
- start,
29481
- end: start + normalizedKeyword.length
29482
- });
29483
- start = source.indexOf(
29484
- normalizedKeyword,
29485
- start + normalizedKeyword.length
29486
- );
29487
- }
29488
29978
  });
29489
29979
  });
29490
29980
  return matches;
@@ -29833,7 +30323,7 @@ var ListTableEventController = class {
29833
30323
  } catch {
29834
30324
  }
29835
30325
  }
29836
- async autoFitColumnWidths(columnKey) {
30326
+ async autoFitColumnWidths(columnKey, fillContainer = false) {
29837
30327
  const ctx = this.host.canvasElement?.getContext("2d");
29838
30328
  if (!ctx) {
29839
30329
  return;
@@ -29872,7 +30362,9 @@ var ListTableEventController = class {
29872
30362
  columnKeys,
29873
30363
  rowStartIndex: startIndex,
29874
30364
  rowEndIndex: endIndex,
29875
- summaryValues
30365
+ summaryValues,
30366
+ fillContainerWidth: fillContainer ? snapshot?.viewport.width ?? this.host.canvasElement?.clientWidth : void 0,
30367
+ hostWidth: fillContainer ? this.host.canvasElement?.clientWidth || snapshot?.viewport.width : void 0
29876
30368
  });
29877
30369
  if (!changed) {
29878
30370
  return;
@@ -31021,6 +31513,8 @@ function createListTableEventHost(core) {
31021
31513
  changeTableDensity: (density) => core.headerActionController.changeTableDensity(density),
31022
31514
  changeTableZoom: (zoom) => core.headerActionController.changeTableZoom(zoom),
31023
31515
  toggleHeaderColumnVisible: (columnKey, visible) => core.headerActionController.toggleHeaderColumnVisible(columnKey, visible),
31516
+ saveHeaderColumn: (draft) => core.headerActionController.saveHeaderColumn(draft),
31517
+ deleteHeaderColumn: (columnKey) => core.headerActionController.deleteHeaderColumn(columnKey),
31024
31518
  toggleHighlightedHeaderColumns: (columnKey, visible) => core.headerActionController.toggleHighlightedHeaderColumns(
31025
31519
  columnKey,
31026
31520
  visible
@@ -31372,6 +31866,34 @@ var ListTableHeaderActionController = class {
31372
31866
  });
31373
31867
  this.options.headerContextMenu.updateColumns(resolved.menuItems);
31374
31868
  }
31869
+ saveHeaderColumn(draft) {
31870
+ const columns = this.options.getOptions().columns;
31871
+ const error = saveHeaderSettingsColumn(columns, draft);
31872
+ if (error) return error;
31873
+ this.options.refreshRuntimeColumns();
31874
+ this.options.resetSummaryValues();
31875
+ this.options.persistColumnConfig();
31876
+ this.options.headerContextMenu.updateColumns(
31877
+ buildHeaderSettingsItems(columns)
31878
+ );
31879
+ this.options.requestRender();
31880
+ return null;
31881
+ }
31882
+ deleteHeaderColumn(columnKey) {
31883
+ const columns = this.options.getOptions().columns;
31884
+ if (!deleteHeaderSettingsColumn(columns, columnKey)) return false;
31885
+ this.options.setSortState(
31886
+ this.options.getSortState().filter((entry) => entry.key !== columnKey)
31887
+ );
31888
+ this.options.refreshRuntimeColumns();
31889
+ this.options.resetSummaryValues();
31890
+ this.options.persistColumnConfig();
31891
+ this.options.headerContextMenu.updateColumns(
31892
+ buildHeaderSettingsItems(columns)
31893
+ );
31894
+ this.options.requestRender();
31895
+ return true;
31896
+ }
31375
31897
  toggleHighlightedHeaderColumns(columnKey, visible) {
31376
31898
  if (visible) {
31377
31899
  this.toggleHeaderColumnVisible(columnKey, true);
@@ -31696,20 +32218,74 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31696
32218
  return false;
31697
32219
  }
31698
32220
  let columnWidthsChanged = false;
32221
+ if (cacheColumnSettings) {
32222
+ const existingKeys = /* @__PURE__ */ new Set();
32223
+ const collectKeys = (items) => {
32224
+ items.forEach((column) => {
32225
+ if (column.key) existingKeys.add(column.key);
32226
+ if (column.children?.length) collectKeys(column.children);
32227
+ });
32228
+ };
32229
+ collectKeys(columns);
32230
+ const findChildren = (items, parentKey) => {
32231
+ for (const column of items) {
32232
+ if (column.key === parentKey) return column.children ?? null;
32233
+ if (column.children?.length) {
32234
+ const children = findChildren(column.children, parentKey);
32235
+ if (children) return children;
32236
+ }
32237
+ }
32238
+ return null;
32239
+ };
32240
+ Object.entries(storedColumns).forEach(([key, stored]) => {
32241
+ if (!stored.userDefined || existingKeys.has(key) || !stored.dataIndex)
32242
+ return;
32243
+ const target = stored.parentKey ? findChildren(columns, stored.parentKey) : columns;
32244
+ (target ?? columns).push({
32245
+ key,
32246
+ title: stored.title ?? key,
32247
+ settingTitle: stored.title ?? key,
32248
+ dataIndex: stored.dataIndex,
32249
+ width: stored.width,
32250
+ minWidth: stored.minWidth,
32251
+ maxWidth: stored.maxWidth,
32252
+ fixed: stored.fixed,
32253
+ hidden: stored.hidden,
32254
+ userDefined: true,
32255
+ allowSort: true,
32256
+ sorter: true
32257
+ });
32258
+ existingKeys.add(key);
32259
+ });
32260
+ }
31699
32261
  const applyToColumns = (cols) => {
31700
32262
  if (cacheColumnSettings && columnOrder?.length) {
31701
- const rank = new Map(columnOrder.map((key, index) => [key, index]));
31702
- cols.sort(
31703
- (a, b) => (rank.get(a.key ?? "") ?? Infinity) - (rank.get(b.key ?? "") ?? Infinity)
31704
- );
32263
+ const rank = new Map(columnOrder.map((key, index2) => [key, index2]));
32264
+ const ranked = cols.filter((column) => rank.has(column.key ?? "")).sort((a, b) => rank.get(a.key ?? "") - rank.get(b.key ?? ""));
32265
+ let index = 0;
32266
+ cols.forEach((column, position) => {
32267
+ if (rank.has(column.key ?? "")) cols[position] = ranked[index++];
32268
+ });
31705
32269
  }
31706
32270
  for (const col of cols) {
31707
32271
  if (!col.key) {
31708
32272
  continue;
31709
32273
  }
31710
32274
  const stored = storedColumns[col.key];
31711
- if (stored) {
32275
+ if (stored && (!stored.userDefined || col.userDefined)) {
32276
+ if (cacheColumnSettings && stored.userTitle != null) {
32277
+ col.title = stored.userTitle;
32278
+ col.settingTitle = stored.userTitle;
32279
+ col.userTitle = stored.userTitle;
32280
+ }
31712
32281
  if (cacheColumnSettings) {
32282
+ if (col.userDefined && stored.userDefined) {
32283
+ col.title = stored.title ?? col.title;
32284
+ col.settingTitle = stored.title ?? col.settingTitle;
32285
+ col.dataIndex = stored.dataIndex ?? col.dataIndex;
32286
+ }
32287
+ if ("minWidth" in stored) col.minWidth = stored.minWidth;
32288
+ if ("maxWidth" in stored) col.maxWidth = stored.maxWidth;
31713
32289
  if (stored.width != null) {
31714
32290
  if ((col.width ?? 160) !== stored.width) columnWidthsChanged = true;
31715
32291
  col.width = stored.width;
@@ -31772,7 +32348,7 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31772
32348
  function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryRowHeight, density, cacheColumnSettings = true, cachePreferences) {
31773
32349
  const result = {};
31774
32350
  const columnOrder = [];
31775
- const collectColumns = (cols) => {
32351
+ const collectColumns = (cols, parentKey) => {
31776
32352
  for (const col of cols) {
31777
32353
  if (!col.key) {
31778
32354
  continue;
@@ -31781,8 +32357,19 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31781
32357
  result[col.key] = {
31782
32358
  ...cacheColumnSettings ? {
31783
32359
  width: col.width ?? 160,
32360
+ minWidth: col.minWidth,
32361
+ maxWidth: col.maxWidth,
31784
32362
  fixed: col.fixed,
31785
- hidden: !!col.hidden
32363
+ hidden: !!col.hidden,
32364
+ ...col.userTitle ? { userTitle: col.userTitle } : null,
32365
+ ...col.userDefined && col.dataIndex != null ? {
32366
+ userDefined: true,
32367
+ ...parentKey ? { parentKey } : null,
32368
+ title: String(col.settingTitle ?? col.title ?? col.key),
32369
+ dataIndex: col.dataIndex,
32370
+ minWidth: col.minWidth,
32371
+ maxWidth: col.maxWidth
32372
+ } : null
31786
32373
  } : null,
31787
32374
  // IndexedDB 保留 undefined 属性;字段存在即表示显式恢复/清除,避免默认配置回弹。
31788
32375
  align: col.align,
@@ -31806,7 +32393,7 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31806
32393
  } : false
31807
32394
  };
31808
32395
  if (col.children?.length) {
31809
- collectColumns(col.children);
32396
+ collectColumns(col.children, col.key);
31810
32397
  }
31811
32398
  }
31812
32399
  };
@@ -35194,6 +35781,12 @@ var ListTableCore = class {
35194
35781
  const incomingColumnsAreRuntimeColumns = options.columns === this.options.columns;
35195
35782
  const nextInitialColumns = incomingColumnsAreRuntimeColumns ? cloneColumns(host.initialColumns) : cloneColumns(options.columns);
35196
35783
  const nextInitialStretchColumns = incomingColumnsAreRuntimeColumns ? host.initialStretchColumns : options.stretchColumns;
35784
+ if (!shouldResetColumnConfig && !incomingColumnsAreRuntimeColumns && this.options.storageKey === options.storageKey) {
35785
+ preserveUserAddedColumns({
35786
+ nextColumns: options.columns,
35787
+ runtimeColumns: this.options.columns
35788
+ });
35789
+ }
35197
35790
  const shouldPreserveRuntimeWidths = !shouldResetColumnConfig && this.options.stretchColumns === false && options.stretchColumns === host.initialStretchColumns;
35198
35791
  if (shouldPreserveRuntimeWidths) {
35199
35792
  preserveRuntimeColumnWidths({