@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.cjs CHANGED
@@ -951,15 +951,23 @@ function setColumnFixed(columns, targetKey, direction, initialColumns) {
951
951
  }
952
952
  updateColumnFixed(columns, targetKey, direction, initialColumns);
953
953
  }
954
- function setNestedColumnWidth(columns, targetKey, newWidth) {
954
+ function setNestedColumnWidth(columns, targetKey, newWidth, expandMaxWidth = false) {
955
955
  ensureColumnKeysInPlace(columns);
956
956
  for (const column of columns) {
957
957
  if (column.key === targetKey) {
958
958
  column.width = newWidth;
959
+ if (expandMaxWidth && newWidth > (column.maxWidth ?? DEFAULT_MAX_WIDTH)) {
960
+ column.maxWidth = newWidth;
961
+ }
959
962
  return;
960
963
  }
961
964
  if (column.children?.length) {
962
- setNestedColumnWidth(column.children, targetKey, newWidth);
965
+ setNestedColumnWidth(
966
+ column.children,
967
+ targetKey,
968
+ newWidth,
969
+ expandMaxWidth
970
+ );
963
971
  }
964
972
  }
965
973
  }
@@ -1104,16 +1112,149 @@ function applyInitialColumnVisibility(columns) {
1104
1112
  function replaceColumns(target, source) {
1105
1113
  target.splice(0, target.length, ...cloneColumns(source));
1106
1114
  }
1115
+ function preserveUserAddedColumns(params) {
1116
+ const keys = /* @__PURE__ */ new Set();
1117
+ const collect = (columns) => {
1118
+ columns.forEach((column) => {
1119
+ keys.add(resolveColumnKey(column));
1120
+ if (column.children?.length) collect(column.children);
1121
+ });
1122
+ };
1123
+ collect(params.nextColumns);
1124
+ const preserve = (source, target) => {
1125
+ source.forEach((column) => {
1126
+ const key = resolveColumnKey(column);
1127
+ if (column.userDefined && !keys.has(key)) {
1128
+ target.push({ ...column });
1129
+ keys.add(key);
1130
+ } else if (column.children?.length) {
1131
+ const matching = findColumnNode(params.nextColumns, key);
1132
+ if (matching?.children) preserve(column.children, matching.children);
1133
+ }
1134
+ });
1135
+ };
1136
+ preserve(params.runtimeColumns, params.nextColumns);
1137
+ }
1107
1138
  function buildHeaderSettingsItems(columns) {
1108
1139
  ensureColumnKeysInPlace(columns);
1109
1140
  const totalVisibleLeafCount = countVisibleLeafColumns(columns);
1110
- return columns.flatMap((column) => {
1141
+ return columns.flatMap((column, index) => {
1111
1142
  if (column.hideInSetting) {
1112
1143
  return [];
1113
1144
  }
1114
- return [buildHeaderSettingsItem(column, totalVisibleLeafCount, false)];
1145
+ return [
1146
+ buildHeaderSettingsItem(
1147
+ column,
1148
+ totalVisibleLeafCount,
1149
+ false,
1150
+ index + 1,
1151
+ columns.length
1152
+ )
1153
+ ];
1115
1154
  });
1116
1155
  }
1156
+ function saveHeaderSettingsColumn(columns, draft) {
1157
+ const title = draft.title.trim();
1158
+ if (!title) return "\u8BF7\u8F93\u5165\u5217\u540D\u79F0";
1159
+ const existing = draft.key ? findColumnNode(columns, draft.key) : null;
1160
+ if (draft.key && !existing) return "\u5217\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1161
+ const parent = !existing && draft.parentKey ? findColumnNode(columns, draft.parentKey) : null;
1162
+ if (draft.parentKey && !existing && !parent?.children?.length) {
1163
+ return "\u6240\u5C5E\u591A\u7EA7\u8868\u5934\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1164
+ }
1165
+ const siblings = existing ? findSiblingColumnsByKey(columns, draft.key) : parent?.children ?? columns;
1166
+ if (!siblings) return "\u5217\u4E0D\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u6253\u5F00\u5217\u663E\u793A\u83DC\u5355";
1167
+ const maxOrder = siblings.length + (existing ? 0 : 1);
1168
+ if (draft.order != null && (!Number.isInteger(draft.order) || draft.order < 1 || draft.order > maxOrder)) {
1169
+ return `\u5217\u987A\u5E8F\u987B\u4ECB\u4E8E 1 \u548C ${maxOrder} \u4E4B\u95F4`;
1170
+ }
1171
+ const minWidth = draft.minWidth ?? 40;
1172
+ const maxWidth = draft.maxWidth ?? 2e3;
1173
+ const width = draft.width ?? 160;
1174
+ if (![minWidth, maxWidth, width].every(
1175
+ (value) => Number.isFinite(value) && value > 0
1176
+ ) || minWidth > maxWidth || width < minWidth || width > maxWidth) {
1177
+ return "\u5BBD\u5EA6\u987B\u4ECB\u4E8E\u6700\u5C0F\u5BBD\u5EA6\u548C\u6700\u5927\u5BBD\u5EA6\u4E4B\u95F4";
1178
+ }
1179
+ if (existing && !existing.userDefined) {
1180
+ existing.title = title;
1181
+ existing.settingTitle = title;
1182
+ existing.userTitle = title;
1183
+ existing.width = width;
1184
+ existing.minWidth = minWidth;
1185
+ existing.maxWidth = maxWidth;
1186
+ if (draft.order != null) moveColumnToOrder(siblings, existing, draft.order);
1187
+ return null;
1188
+ }
1189
+ const dataIndex = draft.dataIndex?.trim();
1190
+ if (!dataIndex || dataIndex.split(".").some((part) => !part.trim())) {
1191
+ return "dataIndex \u4E3A\u5FC5\u586B\u9879";
1192
+ }
1193
+ if (isHeaderDataIndexUsed(columns, dataIndex, draft.key)) {
1194
+ return "\u8BE5 dataIndex \u5DF2\u88AB\u5176\u4ED6\u5217\u4F7F\u7528";
1195
+ }
1196
+ const column = existing ?? { key: createUserColumnKey(columns) };
1197
+ column.title = title;
1198
+ column.settingTitle = title;
1199
+ column.dataIndex = dataIndex.split(".");
1200
+ column.width = width;
1201
+ column.minWidth = minWidth;
1202
+ column.maxWidth = maxWidth;
1203
+ column.fixed = draft.fixed;
1204
+ column.userDefined = true;
1205
+ column.allowSort = true;
1206
+ column.sorter = true;
1207
+ if (existing && draft.order != null) {
1208
+ moveColumnToOrder(siblings, existing, draft.order);
1209
+ } else if (!existing) {
1210
+ siblings.splice((draft.order ?? maxOrder) - 1, 0, column);
1211
+ }
1212
+ return null;
1213
+ }
1214
+ function findSiblingColumnsByKey(columns, key) {
1215
+ if (columns.some((column) => resolveColumnKey(column) === key))
1216
+ return columns;
1217
+ for (const column of columns) {
1218
+ if (!column.children?.length) continue;
1219
+ const siblings = findSiblingColumnsByKey(column.children, key);
1220
+ if (siblings) return siblings;
1221
+ }
1222
+ return null;
1223
+ }
1224
+ function moveColumnToOrder(siblings, column, order) {
1225
+ const currentIndex = siblings.indexOf(column);
1226
+ if (currentIndex < 0 || currentIndex === order - 1) return;
1227
+ siblings.splice(currentIndex, 1);
1228
+ siblings.splice(order - 1, 0, column);
1229
+ }
1230
+ function deleteHeaderSettingsColumn(columns, columnKey) {
1231
+ const target = findColumnNode(columns, columnKey);
1232
+ if (!target?.userDefined || countVisibleLeafColumns(columns) <= countVisibleLeafColumns([target]))
1233
+ return false;
1234
+ const remove = (items) => {
1235
+ const index = items.findIndex(
1236
+ (column) => resolveColumnKey(column) === columnKey
1237
+ );
1238
+ if (index >= 0) {
1239
+ items.splice(index, 1);
1240
+ return true;
1241
+ }
1242
+ return items.some(
1243
+ (column) => column.children?.length && remove(column.children)
1244
+ );
1245
+ };
1246
+ return remove(columns);
1247
+ }
1248
+ function createUserColumnKey(columns) {
1249
+ let index = 1;
1250
+ while (findColumnNode(columns, `user-column-${index}`)) index += 1;
1251
+ return `user-column-${index}`;
1252
+ }
1253
+ function isHeaderDataIndexUsed(columns, dataIndex, excludeKey) {
1254
+ return columns.some(
1255
+ (column) => resolveColumnKey(column) !== excludeKey && column.dataIndex != null && utils.stringifyDataIndex(column.dataIndex) === dataIndex || column.children?.length && isHeaderDataIndexUsed(column.children, dataIndex, excludeKey)
1256
+ );
1257
+ }
1117
1258
  function setHeaderColumnVisible(columns, columnKey, visible) {
1118
1259
  if (!visible) {
1119
1260
  const targetLeafCount = getColumnLeafCount(columns, columnKey);
@@ -1312,10 +1453,18 @@ function findColumnNode(columns, columnKey) {
1312
1453
  }
1313
1454
  return null;
1314
1455
  }
1315
- function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1456
+ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden, order, siblingCount) {
1316
1457
  const hidden = parentHidden || !!column.hidden;
1317
- const children = column.children?.filter((child) => !child.hideInSetting).map(
1318
- (child) => buildHeaderSettingsItem(child, totalVisibleLeafCount, hidden)
1458
+ const children = column.children?.flatMap(
1459
+ (child, index) => child.hideInSetting ? [] : [
1460
+ buildHeaderSettingsItem(
1461
+ child,
1462
+ totalVisibleLeafCount,
1463
+ hidden,
1464
+ index + 1,
1465
+ column.children.length
1466
+ )
1467
+ ]
1319
1468
  );
1320
1469
  const leafCount = countLeafColumns([column]);
1321
1470
  const visibleLeafCount = hidden ? 0 : countVisibleLeafColumns([column]);
@@ -1327,6 +1476,14 @@ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1327
1476
  title: String(
1328
1477
  column.settingTitle ?? column.title ?? resolveColumnKey(column)
1329
1478
  ),
1479
+ dataIndex: column.dataIndex == null ? void 0 : utils.stringifyDataIndex(column.dataIndex),
1480
+ userDefined: column.userDefined === true,
1481
+ width: column.width,
1482
+ minWidth: column.minWidth,
1483
+ maxWidth: column.maxWidth,
1484
+ fixed: column.fixed,
1485
+ order,
1486
+ siblingCount,
1330
1487
  checked,
1331
1488
  indeterminate,
1332
1489
  disabled,
@@ -1506,6 +1663,7 @@ var ListTableDomHost = class {
1506
1663
  wrapper.style.display = "flex";
1507
1664
  wrapper.style.flexDirection = "column";
1508
1665
  wrapper.style.minWidth = "0";
1666
+ wrapper.style.maxWidth = "100%";
1509
1667
  wrapper.style.boxSizing = "border-box";
1510
1668
  wrapper.style.overflow = "visible";
1511
1669
  const contentLayer = document.createElement("div");
@@ -6502,12 +6660,12 @@ function queryFilterWorkerEntrypoint() {
6502
6660
  let filters = [];
6503
6661
  const matchedIndices = [];
6504
6662
  const now2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
6505
- const escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6663
+ const escapeRegExp3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6506
6664
  const wildcardToRegExp2 = (value) => {
6507
6665
  const pattern = Array.from(value).map((char) => {
6508
6666
  if (char === "%") return ".*";
6509
6667
  if (char === "_") return ".";
6510
- return escapeRegExp2(char);
6668
+ return escapeRegExp3(char);
6511
6669
  }).join("");
6512
6670
  return new RegExp(`^${pattern}$`, "i");
6513
6671
  };
@@ -9135,7 +9293,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9135
9293
  const fontSize = style?.fontSize ?? theme.fontSize;
9136
9294
  const paddingInline = style?.paddingInline ?? 12;
9137
9295
  const paddingBlock = style?.paddingBlock ?? 0;
9138
- 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;
9296
+ 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;
9139
9297
  if (!cellClip) {
9140
9298
  ctx.restore();
9141
9299
  return;
@@ -9160,7 +9318,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9160
9318
  ctx.clip();
9161
9319
  ctx.fillStyle = style?.color ?? theme.headerTextColor;
9162
9320
  ctx.font = `${style?.fontWeight ?? "600"} ${fontSize}px ${style?.fontFamily ?? theme.fontFamily}`;
9163
- ctx.textBaseline = "middle";
9321
+ ctx.textBaseline = "alphabetic";
9164
9322
  const align = style?.textAlign ?? column.align ?? "left";
9165
9323
  ctx.textAlign = align;
9166
9324
  const contentInsetStart = column.key === inlineContentInset?.columnKey ? inlineContentInset.width : 0;
@@ -9181,9 +9339,15 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9181
9339
  visibleRect,
9182
9340
  padding: paddingInline
9183
9341
  });
9184
- const textWidth = ctx.measureText(displayText).width;
9342
+ const bounds = measureTextBounds(ctx, displayText);
9343
+ const textY = resolveCenteredTextBaselineY({
9344
+ centerY,
9345
+ ascent: bounds.ascent,
9346
+ descent: bounds.descent
9347
+ });
9348
+ const textWidth = bounds.width;
9185
9349
  const textOriginX = textX - (align === "right" ? textWidth : align === "center" ? textWidth / 2 : 0);
9186
- const textTop = textY - fontSize / 2;
9350
+ const textTop = textY - bounds.ascent;
9187
9351
  const fragmentKey = `summary:${column.key}`;
9188
9352
  drawSelectableTextSelectionBackground({
9189
9353
  ctx,
@@ -9191,7 +9355,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9191
9355
  textSelection,
9192
9356
  textOriginX,
9193
9357
  textTop,
9194
- textHeight: fontSize,
9358
+ textHeight: bounds.height,
9195
9359
  rowIndex: Number.MAX_SAFE_INTEGER,
9196
9360
  columnKey: column.key,
9197
9361
  contentIndex: 0,
@@ -9211,7 +9375,7 @@ function drawSummaryCell(ctx, rect, column, theme, summaryValues, selectedHeader
9211
9375
  x: textOriginX,
9212
9376
  y: textTop,
9213
9377
  width: textWidth,
9214
- height: fontSize
9378
+ height: bounds.height
9215
9379
  },
9216
9380
  cellClip
9217
9381
  ) ?? void 0,
@@ -11218,7 +11382,6 @@ function roundRectPath3(ctx, x, y, width, height, radius) {
11218
11382
  var TAG_HORIZONTAL_PADDING = 8;
11219
11383
  var TAG_HEIGHT = 22;
11220
11384
  var TAG_RADIUS = 4;
11221
- var TAG_TEXT_OPTICAL_OFFSET_Y = 1;
11222
11385
  var ANT_TAG_PRESET_MAP = {
11223
11386
  default: {
11224
11387
  backgroundColor: "#fafafa",
@@ -11325,12 +11488,24 @@ function drawBodyTagContent(params) {
11325
11488
  const textColor = resolveTagTextColor(content, palette.textColor);
11326
11489
  const textIndent = resolveContentTextIndent(content);
11327
11490
  const paddingInline = content.paddingInline ?? TAG_HORIZONTAL_PADDING;
11491
+ const drawLeft = Math.round(cursorX);
11492
+ const drawTop = Math.round(top);
11493
+ const drawWidth = Math.max(Math.round(cursorX + width) - drawLeft, 1);
11494
+ const drawHeight = Math.max(Math.round(top + height) - drawTop, 1);
11328
11495
  ctx.save();
11329
11496
  ctx.globalAlpha *= resolveContentOpacity(content);
11330
- drawRoundedRectPath2(ctx, cursorX, top, width, height, radius);
11497
+ drawRoundedRectPath2(ctx, drawLeft, drawTop, drawWidth, drawHeight, radius);
11331
11498
  ctx.fillStyle = content.style?.backgroundColor ?? palette.backgroundColor;
11332
11499
  ctx.fill();
11333
11500
  if (bordered) {
11501
+ drawRoundedRectPath2(
11502
+ ctx,
11503
+ drawLeft + 0.5,
11504
+ drawTop + 0.5,
11505
+ Math.max(drawWidth - 1, 0),
11506
+ Math.max(drawHeight - 1, 0),
11507
+ Math.max(radius - 0.5, 0)
11508
+ );
11334
11509
  ctx.strokeStyle = palette.borderColor;
11335
11510
  ctx.lineWidth = 1;
11336
11511
  ctx.stroke();
@@ -11352,7 +11527,7 @@ function drawBodyTagContent(params) {
11352
11527
  textIndent,
11353
11528
  textAlign: resolveContentTextAlign(content, "center")
11354
11529
  });
11355
- const centerY = top + height / 2 + TAG_TEXT_OPTICAL_OFFSET_Y;
11530
+ const centerY = rect.y + rect.height / 2;
11356
11531
  const textY = resolveCenteredTextBaselineY({
11357
11532
  centerY,
11358
11533
  ascent: bounds.ascent,
@@ -11561,7 +11736,7 @@ function drawBodyTextContent(params) {
11561
11736
  textHeight: bounds.height,
11562
11737
  color: theme.textSelectionBackgroundColor ?? "#99c2ff"
11563
11738
  });
11564
- if (searchMatch && searchMatch.rowIndex === rowIndex && searchMatch.columnKey === column.key && searchMatch.keyword) {
11739
+ if (searchMatch && searchMatch.rowIndex === rowIndex && searchMatch.columnKey === column.key && (searchMatch.contentIndex == null || searchMatch.contentIndex === contentIndex) && searchMatch.keyword) {
11565
11740
  const start = Math.max(0, Math.min(searchMatch.start, content.text.length));
11566
11741
  const end = Math.max(start, Math.min(searchMatch.end, content.text.length));
11567
11742
  const prefixWidth = ctx.measureText(content.text.slice(0, start)).width;
@@ -12317,6 +12492,12 @@ function resolveRawBodyCellContents(params) {
12317
12492
  }
12318
12493
  ];
12319
12494
  }
12495
+ if (column.cellType === "emoji") {
12496
+ return normalizeCellContents({
12497
+ type: "emoji",
12498
+ emoji: formattedText ?? String(value ?? "")
12499
+ });
12500
+ }
12320
12501
  if (column.cellType === "money") {
12321
12502
  return [
12322
12503
  {
@@ -12374,6 +12555,21 @@ function normalizeDrawableCellContents(contents) {
12374
12555
  ).map(normalizeCellContentItem);
12375
12556
  }
12376
12557
  function normalizeCellContentItem(content) {
12558
+ if (content.type === "emoji") {
12559
+ const { emoji, size, ...rest } = content;
12560
+ return {
12561
+ ...rest,
12562
+ type: "text",
12563
+ text: emoji,
12564
+ fontSize: size ?? 20,
12565
+ style: {
12566
+ ...content.style,
12567
+ fontSize: content.style?.fontSize ?? size ?? 20,
12568
+ fontWeight: content.style?.fontWeight ?? "normal",
12569
+ fontFamily: content.style?.fontFamily ?? '"Segoe UI Emoji", "Apple Color Emoji", "Noto Color Emoji", "Segoe UI Symbol", sans-serif'
12570
+ }
12571
+ };
12572
+ }
12377
12573
  if (content.type === "timeline") {
12378
12574
  return { ...content, style: { ...content.style, display: "block" } };
12379
12575
  }
@@ -13835,6 +14031,9 @@ function buildBodyContentsPlainText(contents) {
13835
14031
  if (content.type === "icon") {
13836
14032
  return content.icon;
13837
14033
  }
14034
+ if (content.type === "emoji") {
14035
+ return content.emoji;
14036
+ }
13838
14037
  if (content.type === "text" || content.type === "link" || content.type === "tag") {
13839
14038
  return content.text;
13840
14039
  }
@@ -14172,6 +14371,9 @@ function isCellContentDisabled(content) {
14172
14371
  if (content.type === "tag") {
14173
14372
  return false;
14174
14373
  }
14374
+ if (content.type === "emoji") {
14375
+ return false;
14376
+ }
14175
14377
  if (content.type === "money") {
14176
14378
  return false;
14177
14379
  }
@@ -18772,7 +18974,7 @@ function openCellEditingSession(params) {
18772
18974
  }
18773
18975
  const editorConfig = resolveEditorConfig(editConfig);
18774
18976
  const editingValue = initialValue === void 0 ? currentValue : initialValue;
18775
- const selectOnFocus = !(initialValue !== void 0 && (currentValue == null || currentValue === ""));
18977
+ const selectOnFocus = initialValue === void 0;
18776
18978
  const hostRect = toHostRect ? toHostRect(descriptor.rect) : descriptor.rect;
18777
18979
  const zoom = typeof theme.contentZoom === "number" && Number.isFinite(theme.contentZoom) && theme.contentZoom > 0 ? theme.contentZoom : 1;
18778
18980
  const paddingInline = (column.cellStyle?.paddingInline ?? DEFAULT_EDITOR_PADDING_INLINE) * zoom;
@@ -26080,18 +26282,58 @@ function autoFitListTableColumnWidths(params) {
26080
26282
  );
26081
26283
  }
26082
26284
  const nextWidth = Math.ceil(
26083
- utils.clamp(measuredWidth, column.minWidth, column.maxWidth)
26285
+ params.fillContainerWidth == null ? utils.clamp(measuredWidth, column.minWidth, column.maxWidth) : Math.max(measuredWidth, column.minWidth)
26084
26286
  );
26085
26287
  column.width = nextWidth;
26086
- setNestedColumnWidth(options.columns, column.key, nextWidth);
26288
+ if (params.fillContainerWidth != null) {
26289
+ column.maxWidth = Math.max(column.maxWidth, nextWidth);
26290
+ }
26291
+ setNestedColumnWidth(
26292
+ options.columns,
26293
+ column.key,
26294
+ nextWidth,
26295
+ params.fillContainerWidth != null
26296
+ );
26087
26297
  fitted = true;
26088
26298
  });
26299
+ if (fitted && params.fillContainerWidth != null) {
26300
+ const hostWidth = params.hostWidth;
26301
+ const measuredTotalWidth = leafColumns.reduce(
26302
+ (sum, column) => sum + column.width,
26303
+ 0
26304
+ );
26305
+ const shouldPreserveOverflow = hostWidth != null && measuredTotalWidth > params.fillContainerWidth && measuredTotalWidth <= hostWidth;
26306
+ fillAutoFitColumnWidths(leafColumns, params.fillContainerWidth);
26307
+ if (shouldPreserveOverflow && hostWidth != null) {
26308
+ fillAutoFitColumnWidths(leafColumns, Math.ceil(hostWidth) + 1);
26309
+ }
26310
+ leafColumns.forEach((column) => {
26311
+ if (!isSystemColumnKey(column.key)) {
26312
+ setNestedColumnWidth(options.columns, column.key, column.width, true);
26313
+ }
26314
+ });
26315
+ }
26089
26316
  ctx.restore();
26090
26317
  if (fitted) {
26091
26318
  options.stretchColumns = false;
26092
26319
  }
26093
26320
  return fitted;
26094
26321
  }
26322
+ function fillAutoFitColumnWidths(columns, containerWidth) {
26323
+ let remaining = Math.max(
26324
+ Math.round(
26325
+ containerWidth - columns.reduce((sum, column) => sum + column.width, 0)
26326
+ ),
26327
+ 0
26328
+ );
26329
+ const candidates = columns.filter((column) => !isSystemColumnKey(column.key));
26330
+ candidates.forEach((column, index) => {
26331
+ const extra = Math.ceil(remaining / (candidates.length - index));
26332
+ column.width += extra;
26333
+ column.maxWidth = Math.max(column.maxWidth, column.width);
26334
+ remaining -= extra;
26335
+ });
26336
+ }
26095
26337
  function resolveAutoFitMeasureRows(rows, range = {}) {
26096
26338
  if (rows.length === 0) {
26097
26339
  return [];
@@ -26158,6 +26400,134 @@ function measureHeaderWidth(ctx, column, theme) {
26158
26400
  return Math.ceil(contentWidth + HEADER_PADDING_INLINE * 2 + actionWidth);
26159
26401
  }
26160
26402
 
26403
+ // src/features/search/search-matcher.ts
26404
+ function createListTableSearchMatcher(keyword, options) {
26405
+ const pattern = options.mode === "regex" ? keyword : keyword.trim();
26406
+ if (!pattern) {
26407
+ return { findMatches: () => [], error: null, active: false };
26408
+ }
26409
+ if (options.mode === "fuzzy") {
26410
+ const needle = options.caseSensitive ? pattern : pattern.toLocaleLowerCase();
26411
+ return {
26412
+ error: null,
26413
+ active: true,
26414
+ findMatches: (text) => {
26415
+ const source = options.caseSensitive ? text : text.toLocaleLowerCase();
26416
+ const matches = [];
26417
+ let start = source.indexOf(needle);
26418
+ while (start >= 0) {
26419
+ matches.push({ start, end: start + pattern.length });
26420
+ start = source.indexOf(needle, start + needle.length);
26421
+ }
26422
+ return matches;
26423
+ }
26424
+ };
26425
+ }
26426
+ if (options.mode === "exact") {
26427
+ const needle = options.caseSensitive ? pattern : pattern.toLocaleLowerCase();
26428
+ return {
26429
+ error: null,
26430
+ active: true,
26431
+ findMatches: (text) => {
26432
+ const source = options.caseSensitive ? text : text.toLocaleLowerCase();
26433
+ return source === needle ? [{ start: 0, end: text.length }] : [];
26434
+ }
26435
+ };
26436
+ }
26437
+ try {
26438
+ const source = options.mode === "wildcard" ? wildcardToRegExpSource(pattern) : pattern;
26439
+ const expression = new RegExp(source, options.caseSensitive ? "g" : "gi");
26440
+ return {
26441
+ error: null,
26442
+ active: true,
26443
+ findMatches: (text) => {
26444
+ const matches = [];
26445
+ expression.lastIndex = 0;
26446
+ let result;
26447
+ while ((result = expression.exec(text)) !== null) {
26448
+ if (result[0].length > 0) {
26449
+ matches.push({ start: result.index, end: expression.lastIndex });
26450
+ } else {
26451
+ expression.lastIndex += 1;
26452
+ }
26453
+ }
26454
+ return matches;
26455
+ }
26456
+ };
26457
+ } catch {
26458
+ return { findMatches: () => [], error: "\u6B63\u5219\u8868\u8FBE\u5F0F\u65E0\u6548", active: false };
26459
+ }
26460
+ }
26461
+ function wildcardToRegExpSource(pattern) {
26462
+ let source = "";
26463
+ for (let index = 0; index < pattern.length; index += 1) {
26464
+ const char = pattern[index];
26465
+ if (char === "\\" && index + 1 < pattern.length) {
26466
+ source += escapeRegExp2(pattern[++index]);
26467
+ } else if (char === "*") {
26468
+ source += ".*";
26469
+ } else if (char === "?") {
26470
+ source += ".";
26471
+ } else {
26472
+ source += escapeRegExp2(char);
26473
+ }
26474
+ }
26475
+ return source;
26476
+ }
26477
+ function escapeRegExp2(value) {
26478
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26479
+ }
26480
+ function resolveListTableSearchCellTexts(params) {
26481
+ const { record, rowIndex, column } = params;
26482
+ if (!column.render && !column.dataFormat && !column.cellType) {
26483
+ return [
26484
+ {
26485
+ contentIndex: 0,
26486
+ text: String(utils.getValueByDataIndex(record, column.dataIndex) ?? "")
26487
+ }
26488
+ ];
26489
+ }
26490
+ return resolveBodyCellContents({ record, rowIndex, column }).flatMap(
26491
+ (content, contentIndex) => content.type === "text" ? [{ contentIndex, text: content.text }] : []
26492
+ );
26493
+ }
26494
+ function buildHeaderDataIndexOptions(rows, columns) {
26495
+ const paths = /* @__PURE__ */ new Set();
26496
+ const used = /* @__PURE__ */ new Map();
26497
+ const visitColumns = (items) => {
26498
+ items.forEach((column) => {
26499
+ if (column.dataIndex != null) {
26500
+ const path = utils.stringifyDataIndex(column.dataIndex);
26501
+ if (!used.has(path)) {
26502
+ used.set(
26503
+ path,
26504
+ String(column.settingTitle ?? column.title ?? column.key ?? path)
26505
+ );
26506
+ }
26507
+ }
26508
+ if (column.children?.length) visitColumns(column.children);
26509
+ });
26510
+ };
26511
+ visitColumns(columns);
26512
+ const visitValue = (value, prefix, depth) => {
26513
+ if (!value || typeof value !== "object" || Array.isArray(value) || value instanceof Date)
26514
+ return;
26515
+ Object.entries(value).forEach(([key, child]) => {
26516
+ if (paths.size >= 200) return;
26517
+ const path = prefix ? `${prefix}.${key}` : key;
26518
+ paths.add(path);
26519
+ if (depth < 3) visitValue(child, path, depth + 1);
26520
+ });
26521
+ };
26522
+ rows.slice(0, 50).forEach((row) => visitValue(row, "", 0));
26523
+ used.forEach((_label, path) => paths.add(path));
26524
+ return [...paths].map((value) => ({
26525
+ value,
26526
+ disabled: used.has(value),
26527
+ ...used.has(value) ? { label: used.get(value) } : null
26528
+ }));
26529
+ }
26530
+
26161
26531
  // src/features/overlay/context-menu-builder.ts
26162
26532
  function createListTableContextMenuActions(params) {
26163
26533
  return {
@@ -26308,6 +26678,10 @@ function createListTableContextMenuActions(params) {
26308
26678
  params.hideMenu();
26309
26679
  params.onAutoFitAllColumns?.();
26310
26680
  } : void 0,
26681
+ onAutoFitFillContainer: params.onAutoFitFillContainer ? () => {
26682
+ params.hideMenu();
26683
+ params.onAutoFitFillContainer?.();
26684
+ } : void 0,
26311
26685
  onToggleGroupingBar: params.onToggleGroupingBar ? () => {
26312
26686
  params.hideMenu();
26313
26687
  params.onToggleGroupingBar?.();
@@ -26316,6 +26690,8 @@ function createListTableContextMenuActions(params) {
26316
26690
  onChangeZoom: params.onChangeZoom,
26317
26691
  onToggleCurrentColumn: params.onToggleCurrentColumn ?? params.onToggleColumn,
26318
26692
  onToggleColumn: params.onToggleColumn,
26693
+ onSaveColumn: params.onSaveColumn,
26694
+ onDeleteColumn: params.onDeleteColumn,
26319
26695
  onChangeCachePreference: params.onChangeCachePreference ? (category, enabled) => {
26320
26696
  params.hideMenu();
26321
26697
  params.onChangeCachePreference?.(category, enabled);
@@ -26384,6 +26760,7 @@ function buildListTableContextMenuConfig(params) {
26384
26760
  x,
26385
26761
  y,
26386
26762
  columns,
26763
+ dataSource,
26387
26764
  columnKey,
26388
26765
  isHeaderArea,
26389
26766
  isSummaryArea = false,
@@ -26408,6 +26785,7 @@ function buildListTableContextMenuConfig(params) {
26408
26785
  const isBodyArea = bodyRowIndex != null;
26409
26786
  const isSelectionColumn = columnKey === ROW_SELECTION_COLUMN_KEY || columnKey === ROW_SELECTOR_COLUMN_KEY;
26410
26787
  const enableCopy = enabledFeatures.has("copy");
26788
+ const enableChart = enabledFeatures.has("chart");
26411
26789
  const enableSearch = enabledFeatures.has("search");
26412
26790
  const enableExport = enabledFeatures.has("export");
26413
26791
  const enableDownloadContent = enabledFeatures.has("downloadContent");
@@ -26455,6 +26833,7 @@ function buildListTableContextMenuConfig(params) {
26455
26833
  return {
26456
26834
  x,
26457
26835
  y,
26836
+ onCreateChart: enableChart && (isBodyArea || isExpandedArea || isHeaderArea && columnKey !== ROW_SELECTION_COLUMN_KEY) ? params.onCreateChart : void 0,
26458
26837
  columns: enableColumnVisibility ? headerItems : void 0,
26459
26838
  density: enableDensity ? density : void 0,
26460
26839
  zoom: enableZoom ? normalizeContextMenuZoom(zoom) : void 0,
@@ -26537,11 +26916,15 @@ function buildListTableContextMenuConfig(params) {
26537
26916
  onResetDataFormat: enableReset && isTableSettingsArea ? actions.onResetDataFormat : void 0,
26538
26917
  onAutoFitCurrentColumn: enableColumnWidth && isHeaderArea && !isSelectionColumn && actions.onAutoFitCurrentColumn ? () => actions.onAutoFitCurrentColumn?.(columnKey) : void 0,
26539
26918
  onAutoFitAllColumns: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitAllColumns ? actions.onAutoFitAllColumns : void 0,
26919
+ onAutoFitFillContainer: enableColumnWidth && isTableSettingsArea && !isSelectionColumn && actions.onAutoFitFillContainer ? actions.onAutoFitFillContainer : void 0,
26540
26920
  groupingBarVisible,
26541
26921
  onToggleGroupingBar: enableGrouping && (isTableSettingsArea || groupingBarArea) ? actions.onToggleGroupingBar : void 0,
26542
26922
  onChangeDensity: enableDensity ? actions.onChangeDensity : void 0,
26543
26923
  onChangeZoom: enableZoom ? actions.onChangeZoom : void 0,
26544
26924
  onToggleColumn: enableColumnVisibility && isTableSettingsArea ? actions.onToggleColumn : void 0,
26925
+ dataIndexOptions: enableColumnVisibility && isTableSettingsArea ? buildHeaderDataIndexOptions(dataSource ?? [], columns) : void 0,
26926
+ onSaveColumn: enableColumnVisibility && isTableSettingsArea ? actions.onSaveColumn : void 0,
26927
+ onDeleteColumn: enableColumnVisibility && isTableSettingsArea ? actions.onDeleteColumn : void 0,
26545
26928
  columnSettingsCacheAvailable: Boolean(params.storageKey),
26546
26929
  cachePreferences: params.cachePreferences,
26547
26930
  onChangeCachePreference: enabledFeatures.has("cache") ? actions.onChangeCachePreference : void 0,
@@ -26597,6 +26980,7 @@ function findSummaryColumn(columns, columnKey) {
26597
26980
  }
26598
26981
  var DEFAULT_CONTEXT_MENU_FEATURES = [
26599
26982
  "copy",
26983
+ "chart",
26600
26984
  "search",
26601
26985
  "export",
26602
26986
  "downloadContent",
@@ -26745,6 +27129,7 @@ function showHeaderContextMenu(params) {
26745
27129
  onResetDataFormat,
26746
27130
  onAutoFitCurrentColumn,
26747
27131
  onAutoFitAllColumns,
27132
+ onAutoFitFillContainer,
26748
27133
  groupingBarVisible,
26749
27134
  groupingBarArea,
26750
27135
  onToggleGroupingBar,
@@ -26752,6 +27137,8 @@ function showHeaderContextMenu(params) {
26752
27137
  onChangeZoom,
26753
27138
  onToggleCurrentColumn,
26754
27139
  onToggleColumn,
27140
+ onSaveColumn,
27141
+ onDeleteColumn,
26755
27142
  onExpandAllCollapsedColumns,
26756
27143
  onClose,
26757
27144
  onToggleSummary,
@@ -26779,7 +27166,8 @@ function showHeaderContextMenu(params) {
26779
27166
  const isSummaryArea = result.area === "summary";
26780
27167
  const isExpandedArea = result.area === "expanded-row" || result.columnKey === "__expanded_row__";
26781
27168
  const isSelectionColumn = result.columnKey === ROW_SELECTION_COLUMN_KEY || result.columnKey === ROW_SELECTOR_COLUMN_KEY;
26782
- if (!isHeaderArea && !isBodyArea && !groupingBarArea && !isExpandedArea || !result.columnKey && !groupingBarArea && !isExpandedArea || isHeaderArea && isSelectionColumn) {
27169
+ const isChartCorner = isHeaderArea && result.columnKey === ROW_SELECTOR_COLUMN_KEY && resolveEnabledContextMenuFeatures(options.contextMenu).has("chart");
27170
+ if (!isHeaderArea && !isBodyArea && !groupingBarArea && !isExpandedArea || !result.columnKey && !groupingBarArea && !isExpandedArea || isHeaderArea && isSelectionColumn && !isChartCorner) {
26783
27171
  headerContextMenu.hide();
26784
27172
  return false;
26785
27173
  }
@@ -26792,7 +27180,7 @@ function showHeaderContextMenu(params) {
26792
27180
  fixedPopup.hide();
26793
27181
  hideBodyTooltip();
26794
27182
  const contextColumnKey = result.columnKey ?? "";
26795
- if (isHeaderArea) {
27183
+ if (isHeaderArea && !isChartCorner) {
26796
27184
  onSelectHeader(contextColumnKey, result.rect);
26797
27185
  }
26798
27186
  const bodyRowIndex = isBodyArea && !isSummaryArea && !isExpandedArea && typeof result.rowIndex === "number" ? result.rowIndex : null;
@@ -26808,11 +27196,13 @@ function showHeaderContextMenu(params) {
26808
27196
  x: event.clientX,
26809
27197
  y: event.clientY,
26810
27198
  columns: options.columns,
27199
+ dataSource: options.dataSource,
26811
27200
  columnKey: result.columnKey ?? "",
26812
27201
  isHeaderArea,
26813
27202
  isSummaryArea,
26814
27203
  isExpandedArea,
26815
27204
  onCopySummaryRowText: params.onCopySummaryRowText,
27205
+ onCreateChart: params.onCreateChart,
26816
27206
  onCopyImage: params.onCopyImage,
26817
27207
  onExportImage: params.onExportImage,
26818
27208
  canCopySelectionImage: params.canCopySelectionImage,
@@ -26858,11 +27248,14 @@ function showHeaderContextMenu(params) {
26858
27248
  onResetDataFormat,
26859
27249
  onAutoFitCurrentColumn,
26860
27250
  onAutoFitAllColumns,
27251
+ onAutoFitFillContainer,
26861
27252
  onToggleGroupingBar,
26862
27253
  onChangeDensity,
26863
27254
  onChangeZoom,
26864
27255
  onToggleCurrentColumn,
26865
27256
  onToggleColumn,
27257
+ onSaveColumn,
27258
+ onDeleteColumn,
26866
27259
  onExpandAllCollapsedColumns,
26867
27260
  onClose,
26868
27261
  onToggleSummary,
@@ -26902,6 +27295,77 @@ function resolveContextMenuDensity(rowHeight) {
26902
27295
  return rowHeight === 48 ? "middle" : "compact";
26903
27296
  }
26904
27297
 
27298
+ // src/features/overlay/chart-data.ts
27299
+ function createListTableChartData(params) {
27300
+ const {
27301
+ rows,
27302
+ columns,
27303
+ columnKey,
27304
+ rowIndex,
27305
+ selectionRange,
27306
+ selectedRowRange,
27307
+ selectedColumnRange
27308
+ } = params;
27309
+ const startRow = Math.max(
27310
+ selectionRange?.startRowIndex ?? selectedRowRange?.start ?? Math.max((rowIndex ?? 0) - 10, 0),
27311
+ 0
27312
+ );
27313
+ const endRow = Math.min(
27314
+ selectionRange?.endRowIndex ?? selectedRowRange?.end ?? startRow + 199,
27315
+ rows.length - 1
27316
+ );
27317
+ const selectedColumns = selectionRange ? columns.slice(
27318
+ Math.max(selectionRange.startColumnIndex, 0),
27319
+ selectionRange.endColumnIndex + 1
27320
+ ) : selectedRowRange ? columns : selectedColumnRange ? columns.slice(
27321
+ Math.max(selectedColumnRange.start, 0),
27322
+ selectedColumnRange.end + 1
27323
+ ) : columns.filter((column) => column.key === columnKey);
27324
+ const chartColumns = selectedColumns.filter(
27325
+ (column) => column.key !== ROW_SELECTION_COLUMN_KEY && column.key !== ROW_SELECTOR_COLUMN_KEY && column.key !== EXPAND_COLUMN_KEY
27326
+ ).slice(0, 12);
27327
+ if (startRow > endRow || chartColumns.length === 0) return null;
27328
+ const sampledRows = rows.slice(
27329
+ startRow,
27330
+ Math.min(endRow + 1, startRow + 200)
27331
+ );
27332
+ const values = chartColumns.map(
27333
+ (column) => sampledRows.map(
27334
+ (record, offset) => getCellClipboardText(record, startRow + offset, column)
27335
+ )
27336
+ );
27337
+ const numericColumns = chartColumns.flatMap((column, index) => {
27338
+ const numbers = values[index]?.map(parseChartNumber) ?? [];
27339
+ return numbers.some((value) => value !== null) ? [{ name: column.title, data: numbers.map((value) => value ?? 0) }] : [];
27340
+ });
27341
+ if (numericColumns.length === 0) return null;
27342
+ const labelIndex = chartColumns.findIndex(
27343
+ (_, index) => values[index]?.every((value) => parseChartNumber(value) === null)
27344
+ );
27345
+ if (sampledRows.length === 1 && chartColumns.length > 1) {
27346
+ return {
27347
+ labels: numericColumns.map((series) => series.name),
27348
+ series: [
27349
+ {
27350
+ name: values[labelIndex]?.[0] || String(startRow + 1),
27351
+ data: numericColumns.map((series) => series.data[0] ?? 0)
27352
+ }
27353
+ ]
27354
+ };
27355
+ }
27356
+ const labels = sampledRows.map(
27357
+ (_, index) => labelIndex >= 0 ? values[labelIndex]?.[index] || String(startRow + index + 1) : String(startRow + index + 1)
27358
+ );
27359
+ return { labels, series: numericColumns };
27360
+ }
27361
+ function parseChartNumber(value) {
27362
+ const normalized = value.trim().replace(/[,,\s¥¥$]/g, "");
27363
+ if (!normalized) return null;
27364
+ const percentage = normalized.endsWith("%");
27365
+ const parsed = Number(percentage ? normalized.slice(0, -1) : normalized);
27366
+ return Number.isFinite(parsed) ? parsed : null;
27367
+ }
27368
+
26905
27369
  // src/features/tooltip/tooltip-feature.ts
26906
27370
  function getHeaderActionTooltipText(result, sortState) {
26907
27371
  const area = result.area;
@@ -27923,6 +28387,11 @@ var EDITABLE_CELL_ROW_SELECTION_DELAY = 300;
27923
28387
  var ListTableEventController = class {
27924
28388
  constructor(host) {
27925
28389
  __publicField(this, "searchKeyword", "");
28390
+ __publicField(this, "searchOptions", {
28391
+ mode: "fuzzy",
28392
+ caseSensitive: false
28393
+ });
28394
+ __publicField(this, "searchError", null);
27926
28395
  __publicField(this, "searchMatches", []);
27927
28396
  __publicField(this, "searchCurrentIndex", -1);
27928
28397
  __publicField(this, "textSelectionDrag", null);
@@ -28485,6 +28954,15 @@ var ListTableEventController = class {
28485
28954
  getAllRows: () => this.host.options.dataSource,
28486
28955
  getExportSummaryEnabled: () => Boolean(this.host.currentRenderSnapshot?.hasSummary),
28487
28956
  onCopyImage: (scope) => this.copyImage(scope, event),
28957
+ onCreateChart: () => createListTableChartData({
28958
+ rows: this.host.getDisplayData(),
28959
+ columns: this.host.leafColumns,
28960
+ columnKey: contextResult.columnKey ?? "",
28961
+ rowIndex: typeof contextResult.rowIndex === "number" ? contextResult.rowIndex : null,
28962
+ selectionRange: this.host.rangeHighlight.selectedCellRange,
28963
+ selectedRowRange: this.host.rangeHighlight.selectedRowRange,
28964
+ selectedColumnRange: this.host.rangeHighlight.selectedColumnRange
28965
+ }),
28488
28966
  onExportImage: (scope) => this.copyImage(scope, event, true),
28489
28967
  canCopySelectionImage: resolveImageSelection(this.host) != null,
28490
28968
  onCopySummaryRowText: () => {
@@ -28517,15 +28995,21 @@ var ListTableEventController = class {
28517
28995
  this.host.selectHeader(columnKey, rect);
28518
28996
  },
28519
28997
  onSelectBodyRow: (rowIndex, columnKey) => {
28998
+ const selectedCellRange = this.host.rangeHighlight.selectedCellRange;
28999
+ const columnIndex = this.host.leafColumns.findIndex(
29000
+ (column) => column.key === columnKey
29001
+ );
28520
29002
  this.host.selection = {
28521
29003
  rowIndex,
28522
29004
  columnKey
28523
29005
  };
28524
29006
  this.host.clearSelectedHeader();
28525
- this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
28526
- current: this.host.rangeHighlight,
28527
- rowIndex
28528
- });
29007
+ if (!selectedCellRange || rowIndex < selectedCellRange.startRowIndex || rowIndex > selectedCellRange.endRowIndex || columnIndex < selectedCellRange.startColumnIndex || columnIndex > selectedCellRange.endColumnIndex) {
29008
+ this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
29009
+ current: this.host.rangeHighlight,
29010
+ rowIndex
29011
+ });
29012
+ }
28529
29013
  this.host.summarySelected = false;
28530
29014
  },
28531
29015
  getSelectionRange: () => this.host.rangeHighlight.selectedCellRange ?? null,
@@ -28635,6 +29119,9 @@ var ListTableEventController = class {
28635
29119
  onAutoFitAllColumns: () => {
28636
29120
  this.autoFitColumnWidths();
28637
29121
  },
29122
+ onAutoFitFillContainer: () => {
29123
+ this.autoFitColumnWidths(void 0, true);
29124
+ },
28638
29125
  groupingBarVisible: this.host.groupBarVisible,
28639
29126
  groupingBarArea,
28640
29127
  onToggleGroupingBar: () => {
@@ -28653,6 +29140,8 @@ var ListTableEventController = class {
28653
29140
  onToggleColumn: (columnKey, visible) => {
28654
29141
  this.host.toggleHeaderColumnVisible(columnKey, visible);
28655
29142
  },
29143
+ onSaveColumn: (draft) => this.host.saveHeaderColumn(draft),
29144
+ onDeleteColumn: (columnKey) => this.host.deleteHeaderColumn(columnKey),
28656
29145
  onExpandAllCollapsedColumns: () => {
28657
29146
  this.host.expandAllCollapsedColumns();
28658
29147
  },
@@ -29453,11 +29942,17 @@ var ListTableEventController = class {
29453
29942
  publishSearchRequest() {
29454
29943
  const request = {
29455
29944
  keyword: this.searchKeyword,
29945
+ mode: this.searchOptions.mode,
29946
+ caseSensitive: this.searchOptions.caseSensitive,
29947
+ error: this.searchError,
29456
29948
  matchCount: this.searchMatches.length,
29457
29949
  currentIndex: this.searchCurrentIndex,
29458
- onSubmit: (keyword) => {
29950
+ onSubmit: (keyword, options) => {
29459
29951
  this.searchKeyword = keyword;
29460
- this.searchMatches = this.resolveSearchMatches(keyword);
29952
+ this.searchOptions = options;
29953
+ const matcher = createListTableSearchMatcher(keyword, options);
29954
+ this.searchError = matcher.error;
29955
+ this.searchMatches = matcher.active ? this.resolveSearchMatches(matcher.findMatches) : [];
29461
29956
  this.searchCurrentIndex = this.searchMatches.length > 0 ? 0 : -1;
29462
29957
  this.applyCurrentSearchMatch();
29463
29958
  this.publishSearchRequest();
@@ -29471,6 +29966,7 @@ var ListTableEventController = class {
29471
29966
  },
29472
29967
  onClose: () => {
29473
29968
  this.searchKeyword = "";
29969
+ this.searchError = null;
29474
29970
  this.searchMatches = [];
29475
29971
  this.searchCurrentIndex = -1;
29476
29972
  this.host.rangeHighlight = {
@@ -29483,30 +29979,24 @@ var ListTableEventController = class {
29483
29979
  };
29484
29980
  this.host.options.ui?.onSearchRequest?.(request);
29485
29981
  }
29486
- resolveSearchMatches(keyword) {
29487
- const normalizedKeyword = keyword.trim().toLocaleLowerCase();
29488
- if (!normalizedKeyword) return [];
29982
+ resolveSearchMatches(findMatches) {
29489
29983
  const matches = [];
29490
29984
  this.host.getDisplayData().forEach((record, rowIndex) => {
29491
29985
  this.host.leafColumns.forEach((column) => {
29492
29986
  if (isSystemColumnKey(column.key)) return;
29493
- const text = String(
29494
- utils.getValueByDataIndex(record, column.dataIndex) ?? ""
29987
+ resolveListTableSearchCellTexts({ record, rowIndex, column }).forEach(
29988
+ ({ text, contentIndex }) => {
29989
+ findMatches(text).forEach(({ start, end }) => {
29990
+ matches.push({
29991
+ rowIndex,
29992
+ columnKey: column.key,
29993
+ contentIndex,
29994
+ start,
29995
+ end
29996
+ });
29997
+ });
29998
+ }
29495
29999
  );
29496
- const source = text.toLocaleLowerCase();
29497
- let start = source.indexOf(normalizedKeyword);
29498
- while (start >= 0) {
29499
- matches.push({
29500
- rowIndex,
29501
- columnKey: column.key,
29502
- start,
29503
- end: start + normalizedKeyword.length
29504
- });
29505
- start = source.indexOf(
29506
- normalizedKeyword,
29507
- start + normalizedKeyword.length
29508
- );
29509
- }
29510
30000
  });
29511
30001
  });
29512
30002
  return matches;
@@ -29855,7 +30345,7 @@ var ListTableEventController = class {
29855
30345
  } catch {
29856
30346
  }
29857
30347
  }
29858
- async autoFitColumnWidths(columnKey) {
30348
+ async autoFitColumnWidths(columnKey, fillContainer = false) {
29859
30349
  const ctx = this.host.canvasElement?.getContext("2d");
29860
30350
  if (!ctx) {
29861
30351
  return;
@@ -29894,7 +30384,9 @@ var ListTableEventController = class {
29894
30384
  columnKeys,
29895
30385
  rowStartIndex: startIndex,
29896
30386
  rowEndIndex: endIndex,
29897
- summaryValues
30387
+ summaryValues,
30388
+ fillContainerWidth: fillContainer ? snapshot?.viewport.width ?? this.host.canvasElement?.clientWidth : void 0,
30389
+ hostWidth: fillContainer ? this.host.canvasElement?.clientWidth || snapshot?.viewport.width : void 0
29898
30390
  });
29899
30391
  if (!changed) {
29900
30392
  return;
@@ -31043,6 +31535,8 @@ function createListTableEventHost(core) {
31043
31535
  changeTableDensity: (density) => core.headerActionController.changeTableDensity(density),
31044
31536
  changeTableZoom: (zoom) => core.headerActionController.changeTableZoom(zoom),
31045
31537
  toggleHeaderColumnVisible: (columnKey, visible) => core.headerActionController.toggleHeaderColumnVisible(columnKey, visible),
31538
+ saveHeaderColumn: (draft) => core.headerActionController.saveHeaderColumn(draft),
31539
+ deleteHeaderColumn: (columnKey) => core.headerActionController.deleteHeaderColumn(columnKey),
31046
31540
  toggleHighlightedHeaderColumns: (columnKey, visible) => core.headerActionController.toggleHighlightedHeaderColumns(
31047
31541
  columnKey,
31048
31542
  visible
@@ -31394,6 +31888,34 @@ var ListTableHeaderActionController = class {
31394
31888
  });
31395
31889
  this.options.headerContextMenu.updateColumns(resolved.menuItems);
31396
31890
  }
31891
+ saveHeaderColumn(draft) {
31892
+ const columns = this.options.getOptions().columns;
31893
+ const error = saveHeaderSettingsColumn(columns, draft);
31894
+ if (error) return error;
31895
+ this.options.refreshRuntimeColumns();
31896
+ this.options.resetSummaryValues();
31897
+ this.options.persistColumnConfig();
31898
+ this.options.headerContextMenu.updateColumns(
31899
+ buildHeaderSettingsItems(columns)
31900
+ );
31901
+ this.options.requestRender();
31902
+ return null;
31903
+ }
31904
+ deleteHeaderColumn(columnKey) {
31905
+ const columns = this.options.getOptions().columns;
31906
+ if (!deleteHeaderSettingsColumn(columns, columnKey)) return false;
31907
+ this.options.setSortState(
31908
+ this.options.getSortState().filter((entry) => entry.key !== columnKey)
31909
+ );
31910
+ this.options.refreshRuntimeColumns();
31911
+ this.options.resetSummaryValues();
31912
+ this.options.persistColumnConfig();
31913
+ this.options.headerContextMenu.updateColumns(
31914
+ buildHeaderSettingsItems(columns)
31915
+ );
31916
+ this.options.requestRender();
31917
+ return true;
31918
+ }
31397
31919
  toggleHighlightedHeaderColumns(columnKey, visible) {
31398
31920
  if (visible) {
31399
31921
  this.toggleHeaderColumnVisible(columnKey, true);
@@ -31718,20 +32240,74 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31718
32240
  return false;
31719
32241
  }
31720
32242
  let columnWidthsChanged = false;
32243
+ if (cacheColumnSettings) {
32244
+ const existingKeys = /* @__PURE__ */ new Set();
32245
+ const collectKeys = (items) => {
32246
+ items.forEach((column) => {
32247
+ if (column.key) existingKeys.add(column.key);
32248
+ if (column.children?.length) collectKeys(column.children);
32249
+ });
32250
+ };
32251
+ collectKeys(columns);
32252
+ const findChildren = (items, parentKey) => {
32253
+ for (const column of items) {
32254
+ if (column.key === parentKey) return column.children ?? null;
32255
+ if (column.children?.length) {
32256
+ const children = findChildren(column.children, parentKey);
32257
+ if (children) return children;
32258
+ }
32259
+ }
32260
+ return null;
32261
+ };
32262
+ Object.entries(storedColumns).forEach(([key, stored]) => {
32263
+ if (!stored.userDefined || existingKeys.has(key) || !stored.dataIndex)
32264
+ return;
32265
+ const target = stored.parentKey ? findChildren(columns, stored.parentKey) : columns;
32266
+ (target ?? columns).push({
32267
+ key,
32268
+ title: stored.title ?? key,
32269
+ settingTitle: stored.title ?? key,
32270
+ dataIndex: stored.dataIndex,
32271
+ width: stored.width,
32272
+ minWidth: stored.minWidth,
32273
+ maxWidth: stored.maxWidth,
32274
+ fixed: stored.fixed,
32275
+ hidden: stored.hidden,
32276
+ userDefined: true,
32277
+ allowSort: true,
32278
+ sorter: true
32279
+ });
32280
+ existingKeys.add(key);
32281
+ });
32282
+ }
31721
32283
  const applyToColumns = (cols) => {
31722
32284
  if (cacheColumnSettings && columnOrder?.length) {
31723
- const rank = new Map(columnOrder.map((key, index) => [key, index]));
31724
- cols.sort(
31725
- (a, b) => (rank.get(a.key ?? "") ?? Infinity) - (rank.get(b.key ?? "") ?? Infinity)
31726
- );
32285
+ const rank = new Map(columnOrder.map((key, index2) => [key, index2]));
32286
+ const ranked = cols.filter((column) => rank.has(column.key ?? "")).sort((a, b) => rank.get(a.key ?? "") - rank.get(b.key ?? ""));
32287
+ let index = 0;
32288
+ cols.forEach((column, position) => {
32289
+ if (rank.has(column.key ?? "")) cols[position] = ranked[index++];
32290
+ });
31727
32291
  }
31728
32292
  for (const col of cols) {
31729
32293
  if (!col.key) {
31730
32294
  continue;
31731
32295
  }
31732
32296
  const stored = storedColumns[col.key];
31733
- if (stored) {
32297
+ if (stored && (!stored.userDefined || col.userDefined)) {
32298
+ if (cacheColumnSettings && stored.userTitle != null) {
32299
+ col.title = stored.userTitle;
32300
+ col.settingTitle = stored.userTitle;
32301
+ col.userTitle = stored.userTitle;
32302
+ }
31734
32303
  if (cacheColumnSettings) {
32304
+ if (col.userDefined && stored.userDefined) {
32305
+ col.title = stored.title ?? col.title;
32306
+ col.settingTitle = stored.title ?? col.settingTitle;
32307
+ col.dataIndex = stored.dataIndex ?? col.dataIndex;
32308
+ }
32309
+ if ("minWidth" in stored) col.minWidth = stored.minWidth;
32310
+ if ("maxWidth" in stored) col.maxWidth = stored.maxWidth;
31735
32311
  if (stored.width != null) {
31736
32312
  if ((col.width ?? 160) !== stored.width) columnWidthsChanged = true;
31737
32313
  col.width = stored.width;
@@ -31794,7 +32370,7 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31794
32370
  function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryRowHeight, density, cacheColumnSettings = true, cachePreferences) {
31795
32371
  const result = {};
31796
32372
  const columnOrder = [];
31797
- const collectColumns = (cols) => {
32373
+ const collectColumns = (cols, parentKey) => {
31798
32374
  for (const col of cols) {
31799
32375
  if (!col.key) {
31800
32376
  continue;
@@ -31803,8 +32379,19 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31803
32379
  result[col.key] = {
31804
32380
  ...cacheColumnSettings ? {
31805
32381
  width: col.width ?? 160,
32382
+ minWidth: col.minWidth,
32383
+ maxWidth: col.maxWidth,
31806
32384
  fixed: col.fixed,
31807
- hidden: !!col.hidden
32385
+ hidden: !!col.hidden,
32386
+ ...col.userTitle ? { userTitle: col.userTitle } : null,
32387
+ ...col.userDefined && col.dataIndex != null ? {
32388
+ userDefined: true,
32389
+ ...parentKey ? { parentKey } : null,
32390
+ title: String(col.settingTitle ?? col.title ?? col.key),
32391
+ dataIndex: col.dataIndex,
32392
+ minWidth: col.minWidth,
32393
+ maxWidth: col.maxWidth
32394
+ } : null
31808
32395
  } : null,
31809
32396
  // IndexedDB 保留 undefined 属性;字段存在即表示显式恢复/清除,避免默认配置回弹。
31810
32397
  align: col.align,
@@ -31828,7 +32415,7 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31828
32415
  } : false
31829
32416
  };
31830
32417
  if (col.children?.length) {
31831
- collectColumns(col.children);
32418
+ collectColumns(col.children, col.key);
31832
32419
  }
31833
32420
  }
31834
32421
  };
@@ -35216,6 +35803,12 @@ var ListTableCore = class {
35216
35803
  const incomingColumnsAreRuntimeColumns = options.columns === this.options.columns;
35217
35804
  const nextInitialColumns = incomingColumnsAreRuntimeColumns ? cloneColumns(host.initialColumns) : cloneColumns(options.columns);
35218
35805
  const nextInitialStretchColumns = incomingColumnsAreRuntimeColumns ? host.initialStretchColumns : options.stretchColumns;
35806
+ if (!shouldResetColumnConfig && !incomingColumnsAreRuntimeColumns && this.options.storageKey === options.storageKey) {
35807
+ preserveUserAddedColumns({
35808
+ nextColumns: options.columns,
35809
+ runtimeColumns: this.options.columns
35810
+ });
35811
+ }
35219
35812
  const shouldPreserveRuntimeWidths = !shouldResetColumnConfig && this.options.stretchColumns === false && options.stretchColumns === host.initialStretchColumns;
35220
35813
  if (shouldPreserveRuntimeWidths) {
35221
35814
  preserveRuntimeColumnWidths({