@canvas-components/list-table 0.3.22 → 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
@@ -1090,16 +1090,149 @@ function applyInitialColumnVisibility(columns) {
1090
1090
  function replaceColumns(target, source) {
1091
1091
  target.splice(0, target.length, ...cloneColumns(source));
1092
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
+ }
1093
1116
  function buildHeaderSettingsItems(columns) {
1094
1117
  ensureColumnKeysInPlace(columns);
1095
1118
  const totalVisibleLeafCount = countVisibleLeafColumns(columns);
1096
- return columns.flatMap((column) => {
1119
+ return columns.flatMap((column, index) => {
1097
1120
  if (column.hideInSetting) {
1098
1121
  return [];
1099
1122
  }
1100
- return [buildHeaderSettingsItem(column, totalVisibleLeafCount, false)];
1123
+ return [
1124
+ buildHeaderSettingsItem(
1125
+ column,
1126
+ totalVisibleLeafCount,
1127
+ false,
1128
+ index + 1,
1129
+ columns.length
1130
+ )
1131
+ ];
1101
1132
  });
1102
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
+ }
1103
1236
  function setHeaderColumnVisible(columns, columnKey, visible) {
1104
1237
  if (!visible) {
1105
1238
  const targetLeafCount = getColumnLeafCount(columns, columnKey);
@@ -1298,10 +1431,18 @@ function findColumnNode(columns, columnKey) {
1298
1431
  }
1299
1432
  return null;
1300
1433
  }
1301
- function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1434
+ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden, order, siblingCount) {
1302
1435
  const hidden = parentHidden || !!column.hidden;
1303
- const children = column.children?.filter((child) => !child.hideInSetting).map(
1304
- (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
+ ]
1305
1446
  );
1306
1447
  const leafCount = countLeafColumns([column]);
1307
1448
  const visibleLeafCount = hidden ? 0 : countVisibleLeafColumns([column]);
@@ -1313,6 +1454,14 @@ function buildHeaderSettingsItem(column, totalVisibleLeafCount, parentHidden) {
1313
1454
  title: String(
1314
1455
  column.settingTitle ?? column.title ?? resolveColumnKey(column)
1315
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,
1316
1465
  checked,
1317
1466
  indeterminate,
1318
1467
  disabled,
@@ -6489,12 +6638,12 @@ function queryFilterWorkerEntrypoint() {
6489
6638
  let filters = [];
6490
6639
  const matchedIndices = [];
6491
6640
  const now2 = () => typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
6492
- const escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6641
+ const escapeRegExp3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6493
6642
  const wildcardToRegExp2 = (value) => {
6494
6643
  const pattern = Array.from(value).map((char) => {
6495
6644
  if (char === "%") return ".*";
6496
6645
  if (char === "_") return ".";
6497
- return escapeRegExp2(char);
6646
+ return escapeRegExp3(char);
6498
6647
  }).join("");
6499
6648
  return new RegExp(`^${pattern}$`, "i");
6500
6649
  };
@@ -11211,7 +11360,6 @@ function roundRectPath3(ctx, x, y, width, height, radius) {
11211
11360
  var TAG_HORIZONTAL_PADDING = 8;
11212
11361
  var TAG_HEIGHT = 22;
11213
11362
  var TAG_RADIUS = 4;
11214
- var TAG_TEXT_OPTICAL_OFFSET_Y = 1;
11215
11363
  var ANT_TAG_PRESET_MAP = {
11216
11364
  default: {
11217
11365
  backgroundColor: "#fafafa",
@@ -11357,7 +11505,7 @@ function drawBodyTagContent(params) {
11357
11505
  textIndent,
11358
11506
  textAlign: resolveContentTextAlign(content, "center")
11359
11507
  });
11360
- const centerY = top + height / 2 + TAG_TEXT_OPTICAL_OFFSET_Y;
11508
+ const centerY = rect.y + rect.height / 2;
11361
11509
  const textY = resolveCenteredTextBaselineY({
11362
11510
  centerY,
11363
11511
  ascent: bounds.ascent,
@@ -11566,7 +11714,7 @@ function drawBodyTextContent(params) {
11566
11714
  textHeight: bounds.height,
11567
11715
  color: theme.textSelectionBackgroundColor ?? "#99c2ff"
11568
11716
  });
11569
- 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) {
11570
11718
  const start = Math.max(0, Math.min(searchMatch.start, content.text.length));
11571
11719
  const end = Math.max(start, Math.min(searchMatch.end, content.text.length));
11572
11720
  const prefixWidth = ctx.measureText(content.text.slice(0, start)).width;
@@ -12322,6 +12470,12 @@ function resolveRawBodyCellContents(params) {
12322
12470
  }
12323
12471
  ];
12324
12472
  }
12473
+ if (column.cellType === "emoji") {
12474
+ return normalizeCellContents({
12475
+ type: "emoji",
12476
+ emoji: formattedText ?? String(value ?? "")
12477
+ });
12478
+ }
12325
12479
  if (column.cellType === "money") {
12326
12480
  return [
12327
12481
  {
@@ -12379,6 +12533,21 @@ function normalizeDrawableCellContents(contents) {
12379
12533
  ).map(normalizeCellContentItem);
12380
12534
  }
12381
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
+ }
12382
12551
  if (content.type === "timeline") {
12383
12552
  return { ...content, style: { ...content.style, display: "block" } };
12384
12553
  }
@@ -13840,6 +14009,9 @@ function buildBodyContentsPlainText(contents) {
13840
14009
  if (content.type === "icon") {
13841
14010
  return content.icon;
13842
14011
  }
14012
+ if (content.type === "emoji") {
14013
+ return content.emoji;
14014
+ }
13843
14015
  if (content.type === "text" || content.type === "link" || content.type === "tag") {
13844
14016
  return content.text;
13845
14017
  }
@@ -14177,6 +14349,9 @@ function isCellContentDisabled(content) {
14177
14349
  if (content.type === "tag") {
14178
14350
  return false;
14179
14351
  }
14352
+ if (content.type === "emoji") {
14353
+ return false;
14354
+ }
14180
14355
  if (content.type === "money") {
14181
14356
  return false;
14182
14357
  }
@@ -18777,7 +18952,7 @@ function openCellEditingSession(params) {
18777
18952
  }
18778
18953
  const editorConfig = resolveEditorConfig(editConfig);
18779
18954
  const editingValue = initialValue === void 0 ? currentValue : initialValue;
18780
- const selectOnFocus = !(initialValue !== void 0 && (currentValue == null || currentValue === ""));
18955
+ const selectOnFocus = initialValue === void 0;
18781
18956
  const hostRect = toHostRect ? toHostRect(descriptor.rect) : descriptor.rect;
18782
18957
  const zoom = typeof theme.contentZoom === "number" && Number.isFinite(theme.contentZoom) && theme.contentZoom > 0 ? theme.contentZoom : 1;
18783
18958
  const paddingInline = (column.cellStyle?.paddingInline ?? DEFAULT_EDITOR_PADDING_INLINE) * zoom;
@@ -26203,6 +26378,134 @@ function measureHeaderWidth(ctx, column, theme) {
26203
26378
  return Math.ceil(contentWidth + HEADER_PADDING_INLINE * 2 + actionWidth);
26204
26379
  }
26205
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
+
26206
26509
  // src/features/overlay/context-menu-builder.ts
26207
26510
  function createListTableContextMenuActions(params) {
26208
26511
  return {
@@ -26365,6 +26668,8 @@ function createListTableContextMenuActions(params) {
26365
26668
  onChangeZoom: params.onChangeZoom,
26366
26669
  onToggleCurrentColumn: params.onToggleCurrentColumn ?? params.onToggleColumn,
26367
26670
  onToggleColumn: params.onToggleColumn,
26671
+ onSaveColumn: params.onSaveColumn,
26672
+ onDeleteColumn: params.onDeleteColumn,
26368
26673
  onChangeCachePreference: params.onChangeCachePreference ? (category, enabled) => {
26369
26674
  params.hideMenu();
26370
26675
  params.onChangeCachePreference?.(category, enabled);
@@ -26433,6 +26738,7 @@ function buildListTableContextMenuConfig(params) {
26433
26738
  x,
26434
26739
  y,
26435
26740
  columns,
26741
+ dataSource,
26436
26742
  columnKey,
26437
26743
  isHeaderArea,
26438
26744
  isSummaryArea = false,
@@ -26457,6 +26763,7 @@ function buildListTableContextMenuConfig(params) {
26457
26763
  const isBodyArea = bodyRowIndex != null;
26458
26764
  const isSelectionColumn = columnKey === ROW_SELECTION_COLUMN_KEY || columnKey === ROW_SELECTOR_COLUMN_KEY;
26459
26765
  const enableCopy = enabledFeatures.has("copy");
26766
+ const enableChart = enabledFeatures.has("chart");
26460
26767
  const enableSearch = enabledFeatures.has("search");
26461
26768
  const enableExport = enabledFeatures.has("export");
26462
26769
  const enableDownloadContent = enabledFeatures.has("downloadContent");
@@ -26504,6 +26811,7 @@ function buildListTableContextMenuConfig(params) {
26504
26811
  return {
26505
26812
  x,
26506
26813
  y,
26814
+ onCreateChart: enableChart && (isBodyArea || isExpandedArea || isHeaderArea && columnKey !== ROW_SELECTION_COLUMN_KEY) ? params.onCreateChart : void 0,
26507
26815
  columns: enableColumnVisibility ? headerItems : void 0,
26508
26816
  density: enableDensity ? density : void 0,
26509
26817
  zoom: enableZoom ? normalizeContextMenuZoom(zoom) : void 0,
@@ -26592,6 +26900,9 @@ function buildListTableContextMenuConfig(params) {
26592
26900
  onChangeDensity: enableDensity ? actions.onChangeDensity : void 0,
26593
26901
  onChangeZoom: enableZoom ? actions.onChangeZoom : void 0,
26594
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,
26595
26906
  columnSettingsCacheAvailable: Boolean(params.storageKey),
26596
26907
  cachePreferences: params.cachePreferences,
26597
26908
  onChangeCachePreference: enabledFeatures.has("cache") ? actions.onChangeCachePreference : void 0,
@@ -26647,6 +26958,7 @@ function findSummaryColumn(columns, columnKey) {
26647
26958
  }
26648
26959
  var DEFAULT_CONTEXT_MENU_FEATURES = [
26649
26960
  "copy",
26961
+ "chart",
26650
26962
  "search",
26651
26963
  "export",
26652
26964
  "downloadContent",
@@ -26803,6 +27115,8 @@ function showHeaderContextMenu(params) {
26803
27115
  onChangeZoom,
26804
27116
  onToggleCurrentColumn,
26805
27117
  onToggleColumn,
27118
+ onSaveColumn,
27119
+ onDeleteColumn,
26806
27120
  onExpandAllCollapsedColumns,
26807
27121
  onClose,
26808
27122
  onToggleSummary,
@@ -26830,7 +27144,8 @@ function showHeaderContextMenu(params) {
26830
27144
  const isSummaryArea = result.area === "summary";
26831
27145
  const isExpandedArea = result.area === "expanded-row" || result.columnKey === "__expanded_row__";
26832
27146
  const isSelectionColumn = result.columnKey === ROW_SELECTION_COLUMN_KEY || result.columnKey === ROW_SELECTOR_COLUMN_KEY;
26833
- 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) {
26834
27149
  headerContextMenu.hide();
26835
27150
  return false;
26836
27151
  }
@@ -26843,7 +27158,7 @@ function showHeaderContextMenu(params) {
26843
27158
  fixedPopup.hide();
26844
27159
  hideBodyTooltip();
26845
27160
  const contextColumnKey = result.columnKey ?? "";
26846
- if (isHeaderArea) {
27161
+ if (isHeaderArea && !isChartCorner) {
26847
27162
  onSelectHeader(contextColumnKey, result.rect);
26848
27163
  }
26849
27164
  const bodyRowIndex = isBodyArea && !isSummaryArea && !isExpandedArea && typeof result.rowIndex === "number" ? result.rowIndex : null;
@@ -26859,11 +27174,13 @@ function showHeaderContextMenu(params) {
26859
27174
  x: event.clientX,
26860
27175
  y: event.clientY,
26861
27176
  columns: options.columns,
27177
+ dataSource: options.dataSource,
26862
27178
  columnKey: result.columnKey ?? "",
26863
27179
  isHeaderArea,
26864
27180
  isSummaryArea,
26865
27181
  isExpandedArea,
26866
27182
  onCopySummaryRowText: params.onCopySummaryRowText,
27183
+ onCreateChart: params.onCreateChart,
26867
27184
  onCopyImage: params.onCopyImage,
26868
27185
  onExportImage: params.onExportImage,
26869
27186
  canCopySelectionImage: params.canCopySelectionImage,
@@ -26915,6 +27232,8 @@ function showHeaderContextMenu(params) {
26915
27232
  onChangeZoom,
26916
27233
  onToggleCurrentColumn,
26917
27234
  onToggleColumn,
27235
+ onSaveColumn,
27236
+ onDeleteColumn,
26918
27237
  onExpandAllCollapsedColumns,
26919
27238
  onClose,
26920
27239
  onToggleSummary,
@@ -26954,6 +27273,77 @@ function resolveContextMenuDensity(rowHeight) {
26954
27273
  return rowHeight === 48 ? "middle" : "compact";
26955
27274
  }
26956
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
+
26957
27347
  // src/features/tooltip/tooltip-feature.ts
26958
27348
  function getHeaderActionTooltipText(result, sortState) {
26959
27349
  const area = result.area;
@@ -27975,6 +28365,11 @@ var EDITABLE_CELL_ROW_SELECTION_DELAY = 300;
27975
28365
  var ListTableEventController = class {
27976
28366
  constructor(host) {
27977
28367
  __publicField(this, "searchKeyword", "");
28368
+ __publicField(this, "searchOptions", {
28369
+ mode: "fuzzy",
28370
+ caseSensitive: false
28371
+ });
28372
+ __publicField(this, "searchError", null);
27978
28373
  __publicField(this, "searchMatches", []);
27979
28374
  __publicField(this, "searchCurrentIndex", -1);
27980
28375
  __publicField(this, "textSelectionDrag", null);
@@ -28537,6 +28932,15 @@ var ListTableEventController = class {
28537
28932
  getAllRows: () => this.host.options.dataSource,
28538
28933
  getExportSummaryEnabled: () => Boolean(this.host.currentRenderSnapshot?.hasSummary),
28539
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
+ }),
28540
28944
  onExportImage: (scope) => this.copyImage(scope, event, true),
28541
28945
  canCopySelectionImage: resolveImageSelection(this.host) != null,
28542
28946
  onCopySummaryRowText: () => {
@@ -28569,15 +28973,21 @@ var ListTableEventController = class {
28569
28973
  this.host.selectHeader(columnKey, rect);
28570
28974
  },
28571
28975
  onSelectBodyRow: (rowIndex, columnKey) => {
28976
+ const selectedCellRange = this.host.rangeHighlight.selectedCellRange;
28977
+ const columnIndex = this.host.leafColumns.findIndex(
28978
+ (column) => column.key === columnKey
28979
+ );
28572
28980
  this.host.selection = {
28573
28981
  rowIndex,
28574
28982
  columnKey
28575
28983
  };
28576
28984
  this.host.clearSelectedHeader();
28577
- this.host.rangeHighlight = resolveNextRowHighlightForContextMenu({
28578
- current: this.host.rangeHighlight,
28579
- rowIndex
28580
- });
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
+ }
28581
28991
  this.host.summarySelected = false;
28582
28992
  },
28583
28993
  getSelectionRange: () => this.host.rangeHighlight.selectedCellRange ?? null,
@@ -28708,6 +29118,8 @@ var ListTableEventController = class {
28708
29118
  onToggleColumn: (columnKey, visible) => {
28709
29119
  this.host.toggleHeaderColumnVisible(columnKey, visible);
28710
29120
  },
29121
+ onSaveColumn: (draft) => this.host.saveHeaderColumn(draft),
29122
+ onDeleteColumn: (columnKey) => this.host.deleteHeaderColumn(columnKey),
28711
29123
  onExpandAllCollapsedColumns: () => {
28712
29124
  this.host.expandAllCollapsedColumns();
28713
29125
  },
@@ -29508,11 +29920,17 @@ var ListTableEventController = class {
29508
29920
  publishSearchRequest() {
29509
29921
  const request = {
29510
29922
  keyword: this.searchKeyword,
29923
+ mode: this.searchOptions.mode,
29924
+ caseSensitive: this.searchOptions.caseSensitive,
29925
+ error: this.searchError,
29511
29926
  matchCount: this.searchMatches.length,
29512
29927
  currentIndex: this.searchCurrentIndex,
29513
- onSubmit: (keyword) => {
29928
+ onSubmit: (keyword, options) => {
29514
29929
  this.searchKeyword = keyword;
29515
- 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) : [];
29516
29934
  this.searchCurrentIndex = this.searchMatches.length > 0 ? 0 : -1;
29517
29935
  this.applyCurrentSearchMatch();
29518
29936
  this.publishSearchRequest();
@@ -29526,6 +29944,7 @@ var ListTableEventController = class {
29526
29944
  },
29527
29945
  onClose: () => {
29528
29946
  this.searchKeyword = "";
29947
+ this.searchError = null;
29529
29948
  this.searchMatches = [];
29530
29949
  this.searchCurrentIndex = -1;
29531
29950
  this.host.rangeHighlight = {
@@ -29538,30 +29957,24 @@ var ListTableEventController = class {
29538
29957
  };
29539
29958
  this.host.options.ui?.onSearchRequest?.(request);
29540
29959
  }
29541
- resolveSearchMatches(keyword) {
29542
- const normalizedKeyword = keyword.trim().toLocaleLowerCase();
29543
- if (!normalizedKeyword) return [];
29960
+ resolveSearchMatches(findMatches) {
29544
29961
  const matches = [];
29545
29962
  this.host.getDisplayData().forEach((record, rowIndex) => {
29546
29963
  this.host.leafColumns.forEach((column) => {
29547
29964
  if (isSystemColumnKey(column.key)) return;
29548
- const text = String(
29549
- 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
+ }
29550
29977
  );
29551
- const source = text.toLocaleLowerCase();
29552
- let start = source.indexOf(normalizedKeyword);
29553
- while (start >= 0) {
29554
- matches.push({
29555
- rowIndex,
29556
- columnKey: column.key,
29557
- start,
29558
- end: start + normalizedKeyword.length
29559
- });
29560
- start = source.indexOf(
29561
- normalizedKeyword,
29562
- start + normalizedKeyword.length
29563
- );
29564
- }
29565
29978
  });
29566
29979
  });
29567
29980
  return matches;
@@ -31100,6 +31513,8 @@ function createListTableEventHost(core) {
31100
31513
  changeTableDensity: (density) => core.headerActionController.changeTableDensity(density),
31101
31514
  changeTableZoom: (zoom) => core.headerActionController.changeTableZoom(zoom),
31102
31515
  toggleHeaderColumnVisible: (columnKey, visible) => core.headerActionController.toggleHeaderColumnVisible(columnKey, visible),
31516
+ saveHeaderColumn: (draft) => core.headerActionController.saveHeaderColumn(draft),
31517
+ deleteHeaderColumn: (columnKey) => core.headerActionController.deleteHeaderColumn(columnKey),
31103
31518
  toggleHighlightedHeaderColumns: (columnKey, visible) => core.headerActionController.toggleHighlightedHeaderColumns(
31104
31519
  columnKey,
31105
31520
  visible
@@ -31451,6 +31866,34 @@ var ListTableHeaderActionController = class {
31451
31866
  });
31452
31867
  this.options.headerContextMenu.updateColumns(resolved.menuItems);
31453
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
+ }
31454
31897
  toggleHighlightedHeaderColumns(columnKey, visible) {
31455
31898
  if (visible) {
31456
31899
  this.toggleHeaderColumnVisible(columnKey, true);
@@ -31775,20 +32218,74 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31775
32218
  return false;
31776
32219
  }
31777
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
+ }
31778
32261
  const applyToColumns = (cols) => {
31779
32262
  if (cacheColumnSettings && columnOrder?.length) {
31780
- const rank = new Map(columnOrder.map((key, index) => [key, index]));
31781
- cols.sort(
31782
- (a, b) => (rank.get(a.key ?? "") ?? Infinity) - (rank.get(b.key ?? "") ?? Infinity)
31783
- );
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
+ });
31784
32269
  }
31785
32270
  for (const col of cols) {
31786
32271
  if (!col.key) {
31787
32272
  continue;
31788
32273
  }
31789
32274
  const stored = storedColumns[col.key];
31790
- 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
+ }
31791
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;
31792
32289
  if (stored.width != null) {
31793
32290
  if ((col.width ?? 160) !== stored.width) columnWidthsChanged = true;
31794
32291
  col.width = stored.width;
@@ -31851,7 +32348,7 @@ function applyStoredColumnConfig(columns, storedColumns, cacheColumnSettings = t
31851
32348
  function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryRowHeight, density, cacheColumnSettings = true, cachePreferences) {
31852
32349
  const result = {};
31853
32350
  const columnOrder = [];
31854
- const collectColumns = (cols) => {
32351
+ const collectColumns = (cols, parentKey) => {
31855
32352
  for (const col of cols) {
31856
32353
  if (!col.key) {
31857
32354
  continue;
@@ -31860,8 +32357,19 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31860
32357
  result[col.key] = {
31861
32358
  ...cacheColumnSettings ? {
31862
32359
  width: col.width ?? 160,
32360
+ minWidth: col.minWidth,
32361
+ maxWidth: col.maxWidth,
31863
32362
  fixed: col.fixed,
31864
- 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
31865
32373
  } : null,
31866
32374
  // IndexedDB 保留 undefined 属性;字段存在即表示显式恢复/清除,避免默认配置回弹。
31867
32375
  align: col.align,
@@ -31885,7 +32393,7 @@ function buildStoredColumnConfig(columns, sortState, filterState, zoom, summaryR
31885
32393
  } : false
31886
32394
  };
31887
32395
  if (col.children?.length) {
31888
- collectColumns(col.children);
32396
+ collectColumns(col.children, col.key);
31889
32397
  }
31890
32398
  }
31891
32399
  };
@@ -35273,6 +35781,12 @@ var ListTableCore = class {
35273
35781
  const incomingColumnsAreRuntimeColumns = options.columns === this.options.columns;
35274
35782
  const nextInitialColumns = incomingColumnsAreRuntimeColumns ? cloneColumns(host.initialColumns) : cloneColumns(options.columns);
35275
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
+ }
35276
35790
  const shouldPreserveRuntimeWidths = !shouldResetColumnConfig && this.options.stretchColumns === false && options.stretchColumns === host.initialStretchColumns;
35277
35791
  if (shouldPreserveRuntimeWidths) {
35278
35792
  preserveRuntimeColumnWidths({