bolt-table 0.1.26 → 0.1.28

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
@@ -124,6 +124,18 @@ var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtim
124
124
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" }),
125
125
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "2", x2: "22", y1: "2", y2: "22" })
126
126
  ] });
127
+ var SearchIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "11", cy: "11", r: "8" }),
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21 21-4.3-4.3" })
130
+ ] });
131
+ var ColumnsIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", x2: "12", y1: "3", y2: "21" })
134
+ ] });
135
+ var XIcon = ({ style, className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { ...svgBase, style, className, children: [
136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18 6 6 18" }),
137
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })
138
+ ] });
127
139
 
128
140
  // src/DraggableHeader.tsx
129
141
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -823,7 +835,15 @@ var EditableCell = ({
823
835
  onEdit(coerced, record, column.dataIndex, rowIndex);
824
836
  }
825
837
  onEditComplete();
826
- }, [draft, value, column.dataIndex, record, rowIndex, onEdit, onEditComplete]);
838
+ }, [
839
+ draft,
840
+ value,
841
+ column.dataIndex,
842
+ record,
843
+ rowIndex,
844
+ onEdit,
845
+ onEditComplete
846
+ ]);
827
847
  const cancel = (0, import_react3.useCallback)(() => {
828
848
  onEditComplete();
829
849
  }, [onEditComplete]);
@@ -925,7 +945,11 @@ var Cell = import_react3.default.memo(
925
945
  rowSelection.onSelect?.(record, true, [record], e.nativeEvent);
926
946
  rowSelection.onChange?.([rawKey], [record], { type: "single" });
927
947
  },
928
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
948
+ style: {
949
+ cursor: "pointer",
950
+ accentColor,
951
+ backgroundColor: "#94A3B8"
952
+ }
929
953
  }
930
954
  ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
931
955
  "input",
@@ -951,7 +975,11 @@ var Cell = import_react3.default.memo(
951
975
  type: "multiple"
952
976
  });
953
977
  },
954
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
978
+ style: {
979
+ cursor: "pointer",
980
+ accentColor,
981
+ backgroundColor: "#94A3B8"
982
+ }
955
983
  }
956
984
  );
957
985
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1087,6 +1115,33 @@ var MeasuredExpandedRow = import_react3.default.memo(
1087
1115
  }
1088
1116
  );
1089
1117
  MeasuredExpandedRow.displayName = "MeasuredExpandedRow";
1118
+ var DynamicRowMeasurer = import_react3.default.memo(
1119
+ ({
1120
+ index,
1121
+ onHeightChange,
1122
+ children
1123
+ }) => {
1124
+ const ref = (0, import_react3.useRef)(null);
1125
+ const onHeightChangeRef = (0, import_react3.useRef)(onHeightChange);
1126
+ (0, import_react3.useEffect)(() => {
1127
+ onHeightChangeRef.current = onHeightChange;
1128
+ }, [onHeightChange]);
1129
+ (0, import_react3.useEffect)(() => {
1130
+ const el = ref.current;
1131
+ if (!el) return;
1132
+ const observer = new ResizeObserver((entries) => {
1133
+ const height = entries[0]?.borderBoxSize?.[0]?.blockSize;
1134
+ if (height != null && height > 0) {
1135
+ onHeightChangeRef.current(index, Math.ceil(height));
1136
+ }
1137
+ });
1138
+ observer.observe(el);
1139
+ return () => observer.disconnect();
1140
+ }, [index]);
1141
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref, children });
1142
+ }
1143
+ );
1144
+ DynamicRowMeasurer.displayName = "DynamicRowMeasurer";
1090
1145
  var TableBody = ({
1091
1146
  data,
1092
1147
  orderedColumns,
@@ -1116,11 +1171,17 @@ var TableBody = ({
1116
1171
  bodyGridRow = 2,
1117
1172
  onEdit,
1118
1173
  editingCell,
1119
- onEditComplete
1174
+ onEditComplete,
1175
+ enableDynamicRowHeight = false,
1176
+ onRowHeightChange,
1177
+ columnGridIndexMap
1120
1178
  }) => {
1121
1179
  const virtualItems = rowVirtualizer.getVirtualItems();
1122
1180
  const totalSize = rowVirtualizer.getTotalSize();
1123
- const selectedKeySet = (0, import_react3.useMemo)(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
1181
+ const selectedKeySet = (0, import_react3.useMemo)(
1182
+ () => new Set(normalizedSelectedKeys),
1183
+ [normalizedSelectedKeys]
1184
+ );
1124
1185
  const safeData = data ?? [];
1125
1186
  const safeColumns = orderedColumns ?? [];
1126
1187
  const allDataForSelection = (0, import_react3.useMemo)(() => {
@@ -1136,8 +1197,9 @@ var TableBody = ({
1136
1197
  let zIndex = 0;
1137
1198
  if (col.key === "__select__" || col.key === "__expand__") zIndex = 11;
1138
1199
  else if (isPinned) zIndex = 2;
1200
+ const gridCol = columnGridIndexMap?.get(col.key) ?? colIndex + 1;
1139
1201
  const style = {
1140
- gridColumn: colIndex + 1,
1202
+ gridColumn: gridCol,
1141
1203
  gridRow: bodyGridRow,
1142
1204
  height: `${totalSize}px`,
1143
1205
  position: isPinned ? "sticky" : "relative",
@@ -1152,7 +1214,7 @@ var TableBody = ({
1152
1214
  }
1153
1215
  return { key: col.key, style, isPinned };
1154
1216
  });
1155
- }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow]);
1217
+ }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow, columnGridIndexMap]);
1156
1218
  if (safeData.length === 0 || safeColumns.length === 0) return null;
1157
1219
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1158
1220
  columnStyles.map((colStyle, colIndex) => {
@@ -1203,15 +1265,58 @@ var TableBody = ({
1203
1265
  top: `${virtualRow.start}px`,
1204
1266
  left: 0,
1205
1267
  right: 0,
1206
- height: `${virtualRow.size}px`,
1207
- ...rowSty
1268
+ height: enableDynamicRowHeight ? void 0 : `${virtualRow.size}px`,
1269
+ minHeight: enableDynamicRowHeight ? `${rowHeight}px` : void 0
1208
1270
  },
1209
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1271
+ children: enableDynamicRowHeight && onRowHeightChange && colIndex === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1272
+ DynamicRowMeasurer,
1273
+ {
1274
+ index: virtualRow.index,
1275
+ onHeightChange: onRowHeightChange,
1276
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1277
+ "div",
1278
+ {
1279
+ style: {
1280
+ minHeight: `${rowHeight}px`,
1281
+ position: "relative",
1282
+ ...rowSty
1283
+ },
1284
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1285
+ Cell,
1286
+ {
1287
+ value: cellValue,
1288
+ record: row,
1289
+ column: col,
1290
+ rowIndex: virtualRow.index,
1291
+ classNames,
1292
+ styles,
1293
+ isSelected,
1294
+ isExpanded,
1295
+ rowSelection,
1296
+ normalizedSelectedKeys,
1297
+ rowKey,
1298
+ allData: allDataForSelection,
1299
+ getRowKey,
1300
+ getRawRowKey,
1301
+ accentColor,
1302
+ isLoading: isRowShimmer,
1303
+ recordFingerprint,
1304
+ onEdit,
1305
+ isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
1306
+ onEditComplete
1307
+ }
1308
+ )
1309
+ }
1310
+ )
1311
+ }
1312
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1210
1313
  "div",
1211
1314
  {
1212
1315
  style: {
1213
- height: `${rowHeight}px`,
1214
- position: "relative"
1316
+ height: enableDynamicRowHeight ? void 0 : `${rowHeight}px`,
1317
+ minHeight: enableDynamicRowHeight ? `${rowHeight}px` : void 0,
1318
+ position: "relative",
1319
+ ...rowSty
1215
1320
  },
1216
1321
  children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1217
1322
  Cell,
@@ -1266,7 +1371,12 @@ var TableBody = ({
1266
1371
  if (!(resolvedExpandedKeys?.has(rk) ?? false)) return null;
1267
1372
  let expandedRenderResult = null;
1268
1373
  try {
1269
- expandedRenderResult = expandable.expandedRowRender(row, virtualRow.index, 0, true);
1374
+ expandedRenderResult = expandable.expandedRowRender(
1375
+ row,
1376
+ virtualRow.index,
1377
+ 0,
1378
+ true
1379
+ );
1270
1380
  } catch {
1271
1381
  }
1272
1382
  const expandedContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1634,7 +1744,16 @@ function BoltTable({
1634
1744
  onCopy,
1635
1745
  keepPinnedRowsAcrossPages,
1636
1746
  onEdit,
1637
- onRowClick
1747
+ onRowClick,
1748
+ enableColumnVirtualization = false,
1749
+ enableDynamicRowHeight = false,
1750
+ columnPersistence = false,
1751
+ showColumnSettings = true,
1752
+ hideGlobalSearch = false,
1753
+ globalSearchValue,
1754
+ onGlobalSearchChange,
1755
+ toolbarContent,
1756
+ columnSettingsLabel
1638
1757
  }) {
1639
1758
  const data = (0, import_react4.useMemo)(() => {
1640
1759
  if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
@@ -1642,7 +1761,8 @@ function BoltTable({
1642
1761
  return filtered.length > 0 ? filtered : STABLE_EMPTY_DATA;
1643
1762
  }, [rawData]);
1644
1763
  const initialColumns = (0, import_react4.useMemo)(() => {
1645
- if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1764
+ if (!Array.isArray(rawInitialColumns))
1765
+ return STABLE_EMPTY_COLS;
1646
1766
  const safe = rawInitialColumns.filter(
1647
1767
  (col) => col != null && typeof col.key === "string"
1648
1768
  );
@@ -1707,6 +1827,106 @@ function BoltTable({
1707
1827
  () => /* @__PURE__ */ new Map()
1708
1828
  );
1709
1829
  const manuallyResizedRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
1830
+ const persistenceAppliedRef = (0, import_react4.useRef)(false);
1831
+ import_react4.default.useEffect(() => {
1832
+ if (!columnPersistence || persistenceAppliedRef.current) return;
1833
+ persistenceAppliedRef.current = true;
1834
+ const {
1835
+ storageKey,
1836
+ persistOrder = true,
1837
+ persistWidths = true,
1838
+ persistVisibility = true,
1839
+ persistPinned = true
1840
+ } = columnPersistence;
1841
+ try {
1842
+ const raw = localStorage.getItem(`bt_${storageKey}`);
1843
+ if (!raw) return;
1844
+ const saved = JSON.parse(raw);
1845
+ if (persistOrder && saved.order) {
1846
+ setColumnOrder(saved.order);
1847
+ }
1848
+ if (persistWidths && saved.widths) {
1849
+ setColumnWidths(
1850
+ new Map(Object.entries(saved.widths).map(([k, v]) => [k, Number(v)]))
1851
+ );
1852
+ }
1853
+ if (persistVisibility && saved.hidden || persistPinned && saved.pinned) {
1854
+ setColumns(
1855
+ (prev) => prev.map((col) => {
1856
+ let updated = col;
1857
+ if (persistVisibility && saved.hidden && col.key in saved.hidden) {
1858
+ updated = { ...updated, hidden: saved.hidden[col.key] };
1859
+ }
1860
+ if (persistPinned && saved.pinned && col.key in saved.pinned) {
1861
+ updated = { ...updated, pinned: saved.pinned[col.key] };
1862
+ }
1863
+ return updated;
1864
+ })
1865
+ );
1866
+ }
1867
+ } catch {
1868
+ }
1869
+ }, [columnPersistence]);
1870
+ const persistColumnsToStorage = (0, import_react4.useCallback)(() => {
1871
+ if (!columnPersistence) return;
1872
+ const {
1873
+ storageKey,
1874
+ persistOrder = true,
1875
+ persistWidths = true,
1876
+ persistVisibility = true,
1877
+ persistPinned = true
1878
+ } = columnPersistence;
1879
+ try {
1880
+ const saved = {};
1881
+ if (persistOrder) saved.order = columnOrder;
1882
+ if (persistWidths) {
1883
+ const widths = {};
1884
+ columnWidths.forEach((v, k) => {
1885
+ widths[k] = v;
1886
+ });
1887
+ saved.widths = widths;
1888
+ }
1889
+ if (persistVisibility) {
1890
+ const hidden = {};
1891
+ columns.forEach((c) => {
1892
+ if (c.hidden) hidden[c.key] = true;
1893
+ });
1894
+ saved.hidden = hidden;
1895
+ }
1896
+ if (persistPinned) {
1897
+ const pinned = {};
1898
+ columns.forEach((c) => {
1899
+ if (c.pinned) pinned[c.key] = c.pinned;
1900
+ });
1901
+ saved.pinned = pinned;
1902
+ }
1903
+ localStorage.setItem(`bt_${storageKey}`, JSON.stringify(saved));
1904
+ } catch {
1905
+ }
1906
+ }, [columnPersistence, columnOrder, columnWidths, columns]);
1907
+ import_react4.default.useEffect(() => {
1908
+ if (!columnPersistence || !persistenceAppliedRef.current) return;
1909
+ persistColumnsToStorage();
1910
+ }, [columnPersistence, persistColumnsToStorage]);
1911
+ const [showColumnPicker, setShowColumnPicker] = (0, import_react4.useState)(false);
1912
+ const columnPickerRef = (0, import_react4.useRef)(null);
1913
+ import_react4.default.useEffect(() => {
1914
+ if (!showColumnPicker) return;
1915
+ const close = (e) => {
1916
+ if (columnPickerRef.current && !columnPickerRef.current.contains(e.target)) {
1917
+ setShowColumnPicker(false);
1918
+ }
1919
+ };
1920
+ const onKey = (e) => {
1921
+ if (e.key === "Escape") setShowColumnPicker(false);
1922
+ };
1923
+ document.addEventListener("mousedown", close);
1924
+ document.addEventListener("keydown", onKey);
1925
+ return () => {
1926
+ document.removeEventListener("mousedown", close);
1927
+ document.removeEventListener("keydown", onKey);
1928
+ };
1929
+ }, [showColumnPicker]);
1710
1930
  const columnsWithPersistedWidths = (0, import_react4.useMemo)(
1711
1931
  () => columns.map((col) => ({
1712
1932
  ...col,
@@ -1771,6 +1991,32 @@ function BoltTable({
1771
1991
  },
1772
1992
  [rowKey]
1773
1993
  );
1994
+ const deduplicatedRowKeys = (0, import_react4.useMemo)(() => {
1995
+ const seen = /* @__PURE__ */ new Map();
1996
+ return data.map((row, idx) => {
1997
+ const raw = getRowKey(row, idx);
1998
+ const count = seen.get(raw) ?? 0;
1999
+ seen.set(raw, count + 1);
2000
+ return count > 0 ? `${raw}__${idx}` : raw;
2001
+ });
2002
+ }, [data, getRowKey]);
2003
+ const hasDuplicateKeys = (0, import_react4.useMemo)(() => {
2004
+ const seen = /* @__PURE__ */ new Set();
2005
+ for (const row of data) {
2006
+ if (row == null) continue;
2007
+ const k = getRowKey(row, 0);
2008
+ if (seen.has(k)) return true;
2009
+ seen.add(k);
2010
+ }
2011
+ return false;
2012
+ }, [data, getRowKey]);
2013
+ const getSafeRowKey = (0, import_react4.useCallback)(
2014
+ (record, index) => {
2015
+ if (!hasDuplicateKeys) return getRowKey(record, index);
2016
+ return deduplicatedRowKeys[index] ?? getRowKey(record, index);
2017
+ },
2018
+ [getRowKey, hasDuplicateKeys, deduplicatedRowKeys]
2019
+ );
1774
2020
  const getRawRowKey = (0, import_react4.useCallback)(
1775
2021
  (record, index) => {
1776
2022
  if (record == null) return index;
@@ -1788,16 +2034,13 @@ function BoltTable({
1788
2034
  },
1789
2035
  [rowKey]
1790
2036
  );
1791
- const normalizedSelectedKeys = (0, import_react4.useMemo)(
1792
- () => {
1793
- const keys = rowSelection?.selectedRowKeys;
1794
- if (!Array.isArray(keys)) return [];
1795
- return keys.filter((k) => k != null).map((k) => String(k));
1796
- },
1797
- [rowSelection?.selectedRowKeys]
1798
- );
1799
- const getRowKeyRef = (0, import_react4.useRef)(getRowKey);
1800
- getRowKeyRef.current = getRowKey;
2037
+ const normalizedSelectedKeys = (0, import_react4.useMemo)(() => {
2038
+ const keys = rowSelection?.selectedRowKeys;
2039
+ if (!Array.isArray(keys)) return [];
2040
+ return keys.filter((k) => k != null).map((k) => String(k));
2041
+ }, [rowSelection?.selectedRowKeys]);
2042
+ const getRowKeyRef = (0, import_react4.useRef)(getSafeRowKey);
2043
+ getRowKeyRef.current = getSafeRowKey;
1801
2044
  const resolvedExpandedKeysRef = (0, import_react4.useRef)(resolvedExpandedKeys);
1802
2045
  resolvedExpandedKeysRef.current = resolvedExpandedKeys;
1803
2046
  const toggleExpandRef = (0, import_react4.useRef)(toggleExpand);
@@ -1980,7 +2223,9 @@ function BoltTable({
1980
2223
  }
1981
2224
  const scrollEl = tableAreaRef.current;
1982
2225
  if (!scrollEl) return;
1983
- const headers = scrollEl.querySelectorAll("[data-bt-header][data-column-key]");
2226
+ const headers = scrollEl.querySelectorAll(
2227
+ "[data-bt-header][data-column-key]"
2228
+ );
1984
2229
  let newOverId = null;
1985
2230
  headers.forEach((h) => {
1986
2231
  const key = h.dataset.columnKey;
@@ -2022,10 +2267,7 @@ function BoltTable({
2022
2267
  const newIndex = items.indexOf(currentOverId);
2023
2268
  if (oldIndex === -1 || newIndex === -1) return items;
2024
2269
  const newOrder = arrayMove(items, oldIndex, newIndex);
2025
- setTimeout(
2026
- () => onColumnOrderChangeRef.current?.(newOrder),
2027
- 0
2028
- );
2270
+ setTimeout(() => onColumnOrderChangeRef.current?.(newOrder), 0);
2029
2271
  return newOrder;
2030
2272
  });
2031
2273
  });
@@ -2125,9 +2367,7 @@ function BoltTable({
2125
2367
  [leftPinned, unpinned, rightPinned]
2126
2368
  );
2127
2369
  const freshOrderedColumns = (0, import_react4.useMemo)(() => {
2128
- const latestMap = new Map(
2129
- initialColumnsRef.current.map((c) => [c.key, c])
2130
- );
2370
+ const latestMap = new Map(initialColumnsRef.current.map((c) => [c.key, c]));
2131
2371
  return orderedColumns.map((col) => {
2132
2372
  if (col.key === "__select__" || col.key === "__expand__") return col;
2133
2373
  const latest = latestMap.get(col.key);
@@ -2166,6 +2406,11 @@ function BoltTable({
2166
2406
  }
2167
2407
  return offsets;
2168
2408
  }, [leftPinned, rightPinned]);
2409
+ const columnGridIndexMap = (0, import_react4.useMemo)(() => {
2410
+ const map = /* @__PURE__ */ new Map();
2411
+ orderedColumns.forEach((col, i) => map.set(col.key, i + 1));
2412
+ return map;
2413
+ }, [orderedColumns]);
2169
2414
  const handleTogglePin = (columnKey, pinned) => {
2170
2415
  setColumns(
2171
2416
  (prev) => prev.map((col) => col.key === columnKey ? { ...col, pinned } : col)
@@ -2184,22 +2429,27 @@ function BoltTable({
2184
2429
  };
2185
2430
  const [internalRowPinning, setInternalRowPinning] = (0, import_react4.useState)({ top: [], bottom: [] });
2186
2431
  const resolvedRowPinning = rowPinning === true ? internalRowPinning : rowPinning && typeof rowPinning === "object" ? rowPinning : void 0;
2187
- const handleRowPin = (0, import_react4.useCallback)((rk, pinned) => {
2188
- if (onRowPin) {
2189
- onRowPin(rk, pinned);
2190
- return;
2191
- }
2192
- if (rowPinning === true) {
2193
- setInternalRowPinning((prev) => {
2194
- const rkStr = String(rk);
2195
- const newTop = (prev.top ?? []).filter((k) => String(k) !== rkStr);
2196
- const newBottom = (prev.bottom ?? []).filter((k) => String(k) !== rkStr);
2197
- if (pinned === "top") newTop.push(rk);
2198
- else if (pinned === "bottom") newBottom.push(rk);
2199
- return { top: newTop, bottom: newBottom };
2200
- });
2201
- }
2202
- }, [onRowPin, rowPinning]);
2432
+ const handleRowPin = (0, import_react4.useCallback)(
2433
+ (rk, pinned) => {
2434
+ if (onRowPin) {
2435
+ onRowPin(rk, pinned);
2436
+ return;
2437
+ }
2438
+ if (rowPinning === true) {
2439
+ setInternalRowPinning((prev) => {
2440
+ const rkStr = String(rk);
2441
+ const newTop = (prev.top ?? []).filter((k) => String(k) !== rkStr);
2442
+ const newBottom = (prev.bottom ?? []).filter(
2443
+ (k) => String(k) !== rkStr
2444
+ );
2445
+ if (pinned === "top") newTop.push(rk);
2446
+ else if (pinned === "bottom") newBottom.push(rk);
2447
+ return { top: newTop, bottom: newBottom };
2448
+ });
2449
+ }
2450
+ },
2451
+ [onRowPin, rowPinning]
2452
+ );
2203
2453
  const onSortChangeRef = (0, import_react4.useRef)(onSortChange);
2204
2454
  onSortChangeRef.current = onSortChange;
2205
2455
  const [sortState, setSortState] = (0, import_react4.useState)({ key: "", direction: null });
@@ -2222,6 +2472,7 @@ function BoltTable({
2222
2472
  const [columnFilters, setColumnFilters] = (0, import_react4.useState)(
2223
2473
  {}
2224
2474
  );
2475
+ const [internalGlobalSearch, setInternalGlobalSearch] = (0, import_react4.useState)("");
2225
2476
  const handleColumnFilter = (0, import_react4.useCallback)(
2226
2477
  (columnKey, value) => {
2227
2478
  setColumnFilters((prev) => {
@@ -2246,6 +2497,20 @@ function BoltTable({
2246
2497
  columnsLookupRef.current = initialColumns;
2247
2498
  const processedData = (0, import_react4.useMemo)(() => {
2248
2499
  let result = data;
2500
+ const globalSearch = globalSearchValue ?? internalGlobalSearch;
2501
+ if (globalSearch) {
2502
+ const searchLower = globalSearch.toLowerCase();
2503
+ result = result.filter((row) => {
2504
+ if (row == null) return false;
2505
+ for (const key of Object.keys(row)) {
2506
+ const val = row[key];
2507
+ if (val != null && String(val).toLowerCase().includes(searchLower)) {
2508
+ return true;
2509
+ }
2510
+ }
2511
+ return false;
2512
+ });
2513
+ }
2249
2514
  if (!onFilterChangeRef.current) {
2250
2515
  const filterKeys = Object.keys(columnFilters);
2251
2516
  if (filterKeys.length > 0) {
@@ -2255,7 +2520,11 @@ function BoltTable({
2255
2520
  try {
2256
2521
  const col = columnsLookupRef.current.find((c) => c.key === key);
2257
2522
  if (typeof col?.filterFn === "function") {
2258
- return col.filterFn(columnFilters[key], row, col.dataIndex ?? key);
2523
+ return col.filterFn(
2524
+ columnFilters[key],
2525
+ row,
2526
+ col.dataIndex ?? key
2527
+ );
2259
2528
  }
2260
2529
  const cellVal = String(row[key] ?? "").toLowerCase();
2261
2530
  return cellVal.includes(columnFilters[key].toLowerCase());
@@ -2298,7 +2567,7 @@ function BoltTable({
2298
2567
  }
2299
2568
  }
2300
2569
  return result;
2301
- }, [data, sortState, columnFilters]);
2570
+ }, [data, sortState, columnFilters, globalSearchValue, internalGlobalSearch]);
2302
2571
  const pinnedRowCacheRef = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
2303
2572
  const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = (0, import_react4.useMemo)(() => {
2304
2573
  if (!resolvedRowPinning || !resolvedRowPinning.top?.length && !resolvedRowPinning.bottom?.length) {
@@ -2310,19 +2579,23 @@ function BoltTable({
2310
2579
  };
2311
2580
  }
2312
2581
  const topKeySet = new Set((resolvedRowPinning.top ?? []).map(String));
2313
- const bottomKeySet = new Set((resolvedRowPinning.bottom ?? []).map(String));
2582
+ const bottomKeySet = new Set(
2583
+ (resolvedRowPinning.bottom ?? []).map(String)
2584
+ );
2314
2585
  const topMap = /* @__PURE__ */ new Map();
2315
2586
  const bottomMap = /* @__PURE__ */ new Map();
2316
2587
  const rest = [];
2317
2588
  processedData.forEach((row, idx) => {
2318
2589
  if (row == null) return;
2319
- const key = getRowKey(row, idx);
2590
+ const key = getSafeRowKey(row, idx);
2320
2591
  if (topKeySet.has(key)) {
2321
2592
  topMap.set(key, row);
2322
- if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2593
+ if (keepPinnedRowsAcrossPages)
2594
+ pinnedRowCacheRef.current.set(key, row);
2323
2595
  } else if (bottomKeySet.has(key)) {
2324
2596
  bottomMap.set(key, row);
2325
- if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2597
+ if (keepPinnedRowsAcrossPages)
2598
+ pinnedRowCacheRef.current.set(key, row);
2326
2599
  } else {
2327
2600
  rest.push(row);
2328
2601
  }
@@ -2340,7 +2613,8 @@ function BoltTable({
2340
2613
  }
2341
2614
  const allPinnedKeys = /* @__PURE__ */ new Set([...topKeySet, ...bottomKeySet]);
2342
2615
  for (const cachedKey of pinnedRowCacheRef.current.keys()) {
2343
- if (!allPinnedKeys.has(cachedKey)) pinnedRowCacheRef.current.delete(cachedKey);
2616
+ if (!allPinnedKeys.has(cachedKey))
2617
+ pinnedRowCacheRef.current.delete(cachedKey);
2344
2618
  }
2345
2619
  }
2346
2620
  const orderedTop = (resolvedRowPinning.top ?? []).map((k) => topMap.get(String(k))).filter((r) => r !== void 0);
@@ -2350,7 +2624,12 @@ function BoltTable({
2350
2624
  pinnedBottomRows: orderedBottom,
2351
2625
  unpinnedProcessedData: rest
2352
2626
  };
2353
- }, [processedData, resolvedRowPinning, getRowKey, keepPinnedRowsAcrossPages]);
2627
+ }, [
2628
+ processedData,
2629
+ resolvedRowPinning,
2630
+ getSafeRowKey,
2631
+ keepPinnedRowsAcrossPages
2632
+ ]);
2354
2633
  const pinnedTopHeight = pinnedTopRows.length * rowHeight;
2355
2634
  const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
2356
2635
  const pinnedTopKeySet = (0, import_react4.useMemo)(
@@ -2367,9 +2646,7 @@ function BoltTable({
2367
2646
  }, []);
2368
2647
  const [cellContextMenu, setCellContextMenu] = (0, import_react4.useState)(null);
2369
2648
  const cellMenuRef = (0, import_react4.useRef)(null);
2370
- const cellLongPressTimer = (0, import_react4.useRef)(
2371
- null
2372
- );
2649
+ const cellLongPressTimer = (0, import_react4.useRef)(null);
2373
2650
  const cellTouchStart = (0, import_react4.useRef)(null);
2374
2651
  const cancelCellLongPress = (0, import_react4.useCallback)(() => {
2375
2652
  if (cellLongPressTimer.current) {
@@ -2396,10 +2673,11 @@ function BoltTable({
2396
2673
  };
2397
2674
  }, [cellContextMenu]);
2398
2675
  const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
2676
+ const activeGlobalSearch = globalSearchValue ?? internalGlobalSearch;
2399
2677
  import_react4.default.useEffect(() => {
2400
2678
  setInternalPage(1);
2401
2679
  tableAreaRef.current?.scrollTo({ top: 0 });
2402
- }, [columnFiltersKey]);
2680
+ }, [columnFiltersKey, activeGlobalSearch]);
2403
2681
  const DEFAULT_PAGE_SIZE = 15;
2404
2682
  const [internalPage, setInternalPage] = (0, import_react4.useState)(1);
2405
2683
  const [internalPageSize, setInternalPageSize] = (0, import_react4.useState)(DEFAULT_PAGE_SIZE);
@@ -2445,6 +2723,17 @@ function BoltTable({
2445
2723
  return paginatedData;
2446
2724
  }, [shimmerData, infiniteLoadingShimmer, paginatedData]);
2447
2725
  const measuredExpandedHeights = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
2726
+ const measuredRowHeights = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
2727
+ const handleRowHeightChange = (0, import_react4.useCallback)(
2728
+ (index, height) => {
2729
+ if (!enableDynamicRowHeight) return;
2730
+ const prev = measuredRowHeights.current.get(index);
2731
+ if (prev === height) return;
2732
+ measuredRowHeights.current.set(index, height);
2733
+ rowVirtualizerRef.current?.measure();
2734
+ },
2735
+ [enableDynamicRowHeight]
2736
+ );
2448
2737
  const expandedRowMeasureRafRef = (0, import_react4.useRef)(null);
2449
2738
  const handleExpandedRowResize = (0, import_react4.useCallback)(
2450
2739
  (rk, contentHeight) => {
@@ -2469,23 +2758,73 @@ function BoltTable({
2469
2758
  if (shimmerData) return rowHeight;
2470
2759
  const item = displayData[index];
2471
2760
  if (!item) return rowHeight;
2472
- const key = getRowKey(item, index);
2473
- if (!resolvedExpandedKeys.has(key)) return rowHeight;
2761
+ const baseHeight = enableDynamicRowHeight ? measuredRowHeights.current.get(index) ?? rowHeight : rowHeight;
2762
+ const key = getSafeRowKey(item, index);
2763
+ if (!resolvedExpandedKeys.has(key)) return baseHeight;
2474
2764
  const cached = measuredExpandedHeights.current.get(key);
2475
- return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
2765
+ return cached ? baseHeight + cached : baseHeight + expandedRowHeight;
2476
2766
  },
2477
2767
  overscan: 5,
2478
2768
  getItemKey: (index) => {
2479
2769
  if (shimmerData) return `__shimmer_${index}__`;
2480
2770
  const item = displayData[index];
2481
2771
  if (!item) return `__fallback_${index}__`;
2482
- return getRowKey(item, index);
2772
+ return getSafeRowKey(item, index);
2483
2773
  },
2484
2774
  paddingStart: pinnedTopHeight,
2485
2775
  paddingEnd: pinnedBottomHeight
2486
2776
  });
2487
2777
  const rowVirtualizerRef = (0, import_react4.useRef)(rowVirtualizer);
2488
2778
  rowVirtualizerRef.current = rowVirtualizer;
2779
+ const scrollLeftRef = (0, import_react4.useRef)(0);
2780
+ const [visibleColumnRange, setVisibleColumnRange] = (0, import_react4.useState)(null);
2781
+ import_react4.default.useEffect(() => {
2782
+ if (!enableColumnVirtualization) return;
2783
+ const el = tableAreaRef.current;
2784
+ if (!el) return;
2785
+ const updateVisibleColumns = () => {
2786
+ const scrollLeft = el.scrollLeft;
2787
+ scrollLeftRef.current = scrollLeft;
2788
+ const viewportWidth = el.clientWidth;
2789
+ const viewStart = scrollLeft;
2790
+ const viewEnd = scrollLeft + viewportWidth;
2791
+ let cumWidth = 0;
2792
+ let startIdx = -1;
2793
+ let endIdx = orderedColumns.length - 1;
2794
+ for (let i = 0; i < orderedColumns.length; i++) {
2795
+ const col = orderedColumns[i];
2796
+ const colWidth = col.width ?? 150;
2797
+ const colStart = cumWidth;
2798
+ const colEnd = cumWidth + colWidth;
2799
+ cumWidth = colEnd;
2800
+ if (col.pinned) continue;
2801
+ if (startIdx === -1 && colEnd > viewStart) {
2802
+ startIdx = Math.max(0, i - 1);
2803
+ }
2804
+ if (colStart > viewEnd) {
2805
+ endIdx = Math.min(orderedColumns.length - 1, i + 1);
2806
+ break;
2807
+ }
2808
+ }
2809
+ if (startIdx === -1) startIdx = 0;
2810
+ setVisibleColumnRange((prev) => {
2811
+ if (prev && prev.start === startIdx && prev.end === endIdx) return prev;
2812
+ return { start: startIdx, end: endIdx };
2813
+ });
2814
+ };
2815
+ updateVisibleColumns();
2816
+ el.addEventListener("scroll", updateVisibleColumns, { passive: true });
2817
+ return () => el.removeEventListener("scroll", updateVisibleColumns);
2818
+ }, [enableColumnVirtualization, orderedColumns]);
2819
+ const virtualizedColumns = (0, import_react4.useMemo)(() => {
2820
+ if (!enableColumnVirtualization || !visibleColumnRange)
2821
+ return freshOrderedColumns;
2822
+ return freshOrderedColumns.filter((col, idx) => {
2823
+ if (col.pinned) return true;
2824
+ if (col.key === "__select__" || col.key === "__expand__") return true;
2825
+ return idx >= visibleColumnRange.start && idx <= visibleColumnRange.end;
2826
+ });
2827
+ }, [enableColumnVirtualization, visibleColumnRange, freshOrderedColumns]);
2489
2828
  const resolvedExpandedKeysFingerprint = Array.from(resolvedExpandedKeys).sort().join(",");
2490
2829
  import_react4.default.useLayoutEffect(() => {
2491
2830
  rowVirtualizer.measure();
@@ -2552,7 +2891,10 @@ function BoltTable({
2552
2891
  }, [pgCurrent, needsClientPagination]);
2553
2892
  const getPageNumbers = () => {
2554
2893
  if (totalPages <= 7)
2555
- return Array.from({ length: totalPages }, (_, i) => i + 1);
2894
+ return Array.from(
2895
+ { length: totalPages },
2896
+ (_, i) => i + 1
2897
+ );
2556
2898
  const leftSibling = Math.max(currentPage - 1, 2);
2557
2899
  const showLeftEllipsis = leftSibling > 2;
2558
2900
  const rightSibling = Math.min(currentPage + 1, totalPages - 1);
@@ -2563,7 +2905,10 @@ function BoltTable({
2563
2905
  return [
2564
2906
  1,
2565
2907
  "ellipsis-left",
2566
- ...Array.from({ length: 5 }, (_, i) => totalPages - 4 + i)
2908
+ ...Array.from(
2909
+ { length: 5 },
2910
+ (_, i) => totalPages - 4 + i
2911
+ )
2567
2912
  ];
2568
2913
  return [
2569
2914
  1,
@@ -2634,6 +2979,190 @@ function BoltTable({
2634
2979
  }
2635
2980
  ${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
2636
2981
  ` }),
2982
+ (!hideGlobalSearch || showColumnSettings) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2983
+ "div",
2984
+ {
2985
+ style: {
2986
+ display: "flex",
2987
+ alignItems: "center",
2988
+ gap: 8,
2989
+ padding: "6px 8px",
2990
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2991
+ fontSize: 12,
2992
+ flexShrink: 0
2993
+ },
2994
+ children: [
2995
+ !hideGlobalSearch && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2996
+ "div",
2997
+ {
2998
+ style: {
2999
+ display: "flex",
3000
+ alignItems: "center",
3001
+ gap: 4,
3002
+ flex: "1 1 0%",
3003
+ position: "relative"
3004
+ },
3005
+ children: [
3006
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3007
+ "span",
3008
+ {
3009
+ style: { display: "flex", color: "GrayText", flexShrink: 0 },
3010
+ children: icons?.search ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SearchIcon, { style: { width: 14, height: 14 } })
3011
+ }
3012
+ ),
3013
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3014
+ "input",
3015
+ {
3016
+ type: "text",
3017
+ placeholder: "Search all columns...",
3018
+ value: globalSearchValue ?? internalGlobalSearch,
3019
+ onChange: (e) => {
3020
+ const v = e.target.value;
3021
+ if (onGlobalSearchChange) onGlobalSearchChange(v);
3022
+ else setInternalGlobalSearch(v);
3023
+ },
3024
+ style: {
3025
+ flex: "1 1 0%",
3026
+ border: "none",
3027
+ outline: "none",
3028
+ background: "transparent",
3029
+ font: "inherit",
3030
+ color: "inherit",
3031
+ padding: "4px 6px",
3032
+ minWidth: 0
3033
+ }
3034
+ }
3035
+ ),
3036
+ (globalSearchValue ?? internalGlobalSearch) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3037
+ "button",
3038
+ {
3039
+ type: "button",
3040
+ onClick: () => {
3041
+ if (onGlobalSearchChange) onGlobalSearchChange("");
3042
+ else setInternalGlobalSearch("");
3043
+ },
3044
+ style: {
3045
+ display: "flex",
3046
+ alignItems: "center",
3047
+ justifyContent: "center",
3048
+ background: "none",
3049
+ border: "none",
3050
+ cursor: "pointer",
3051
+ padding: 2,
3052
+ color: "GrayText",
3053
+ flexShrink: 0
3054
+ },
3055
+ children: icons?.close ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { style: { width: 12, height: 12 } })
3056
+ }
3057
+ )
3058
+ ]
3059
+ }
3060
+ ),
3061
+ toolbarContent,
3062
+ showColumnSettings && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", flexShrink: 0 }, children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3064
+ "button",
3065
+ {
3066
+ type: "button",
3067
+ onClick: () => setShowColumnPicker((p) => !p),
3068
+ style: {
3069
+ display: "flex",
3070
+ alignItems: "center",
3071
+ justifyContent: "center",
3072
+ background: "none",
3073
+ border: "1px solid rgba(128,128,128,0.2)",
3074
+ borderRadius: 4,
3075
+ cursor: "pointer",
3076
+ padding: "4px 6px",
3077
+ color: "inherit",
3078
+ gap: 4,
3079
+ fontSize: 12
3080
+ },
3081
+ title: "Column settings",
3082
+ children: [
3083
+ icons?.columns ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ColumnsIcon, { style: { width: 14, height: 14 } }),
3084
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: columnSettingsLabel ?? "Columns" })
3085
+ ]
3086
+ }
3087
+ ),
3088
+ showColumnPicker && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3089
+ "div",
3090
+ {
3091
+ ref: columnPickerRef,
3092
+ style: {
3093
+ position: "absolute",
3094
+ top: "100%",
3095
+ right: 0,
3096
+ zIndex: 99999,
3097
+ minWidth: 200,
3098
+ maxHeight: 320,
3099
+ overflowY: "auto",
3100
+ borderRadius: 8,
3101
+ border: "1px solid rgba(128,128,128,0.2)",
3102
+ boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
3103
+ backdropFilter: "blur(16px)",
3104
+ WebkitBackdropFilter: "blur(16px)",
3105
+ backgroundColor: "rgba(128,128,128,0.08)",
3106
+ padding: "4px 0",
3107
+ marginTop: 4
3108
+ },
3109
+ children: initialColumns.filter(
3110
+ (c) => c.key !== "__select__" && c.key !== "__expand__"
3111
+ ).map((col) => {
3112
+ const current = columns.find((c) => c.key === col.key);
3113
+ const isHidden = current?.hidden ?? false;
3114
+ const isPinned = !!current?.pinned;
3115
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3116
+ "label",
3117
+ {
3118
+ style: {
3119
+ display: "flex",
3120
+ alignItems: "center",
3121
+ gap: 8,
3122
+ padding: "6px 12px",
3123
+ cursor: isPinned ? "not-allowed" : "pointer",
3124
+ opacity: isPinned ? 0.5 : 1,
3125
+ fontSize: 12
3126
+ },
3127
+ children: [
3128
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3129
+ "input",
3130
+ {
3131
+ type: "checkbox",
3132
+ checked: !isHidden,
3133
+ disabled: isPinned,
3134
+ onChange: () => {
3135
+ if (isPinned) return;
3136
+ handleToggleHide(col.key);
3137
+ },
3138
+ style: {
3139
+ cursor: isPinned ? "not-allowed" : "pointer",
3140
+ accentColor
3141
+ }
3142
+ }
3143
+ ),
3144
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3145
+ "span",
3146
+ {
3147
+ style: {
3148
+ overflow: "hidden",
3149
+ textOverflow: "ellipsis",
3150
+ whiteSpace: "nowrap"
3151
+ },
3152
+ children: typeof col.title === "string" ? col.title : col.key
3153
+ }
3154
+ )
3155
+ ]
3156
+ },
3157
+ col.key
3158
+ );
3159
+ })
3160
+ }
3161
+ )
3162
+ ] })
3163
+ ]
3164
+ }
3165
+ ),
2637
3166
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2638
3167
  "div",
2639
3168
  {
@@ -2778,19 +3307,20 @@ function BoltTable({
2778
3307
  ...isEmpty ? { height: "100%" } : {}
2779
3308
  },
2780
3309
  onContextMenu: (e) => {
2781
- const cell = e.target.closest("[data-bt-cell]");
3310
+ const cell = e.target.closest(
3311
+ "[data-bt-cell]"
3312
+ );
2782
3313
  if (!cell) return;
2783
3314
  const rk = cell.dataset.rowKey;
2784
3315
  const ck = cell.dataset.columnKey;
2785
3316
  if (!rk || !ck) return;
2786
- const col = freshOrderedColumns.find(
2787
- (c) => c.key === ck
2788
- );
3317
+ const col = freshOrderedColumns.find((c) => c.key === ck);
2789
3318
  const hasCopy = !!col?.copy;
2790
3319
  const hasRowPin = !!rowPinning;
2791
3320
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2792
3321
  const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2793
- if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
3322
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit)
3323
+ return;
2794
3324
  e.preventDefault();
2795
3325
  setCellContextMenu({
2796
3326
  x: Math.min(e.clientX, window.innerWidth - 200),
@@ -2801,7 +3331,9 @@ function BoltTable({
2801
3331
  },
2802
3332
  onTouchStart: (e) => {
2803
3333
  cancelCellLongPress();
2804
- const cell = e.target.closest("[data-bt-cell]");
3334
+ const cell = e.target.closest(
3335
+ "[data-bt-cell]"
3336
+ );
2805
3337
  if (!cell) return;
2806
3338
  const touch = e.touches[0];
2807
3339
  cellTouchStart.current = {
@@ -2813,14 +3345,13 @@ function BoltTable({
2813
3345
  cellLongPressTimer.current = setTimeout(() => {
2814
3346
  cellLongPressTimer.current = null;
2815
3347
  if (!rk || !ck) return;
2816
- const col = freshOrderedColumns.find(
2817
- (c) => c.key === ck
2818
- );
3348
+ const col = freshOrderedColumns.find((c) => c.key === ck);
2819
3349
  const hasCopy = !!col?.copy;
2820
3350
  const hasRowPin = !!rowPinning;
2821
3351
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2822
3352
  const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2823
- if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
3353
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit)
3354
+ return;
2824
3355
  setCellContextMenu({
2825
3356
  x: Math.min(touch.clientX, window.innerWidth - 200),
2826
3357
  y: Math.min(touch.clientY, window.innerHeight - 200),
@@ -2841,7 +3372,8 @@ function BoltTable({
2841
3372
  onTouchCancel: cancelCellLongPress,
2842
3373
  onClick: onRowClick ? (e) => {
2843
3374
  const target = e.target;
2844
- if (target.closest("input, button, a, select, textarea")) return;
3375
+ if (target.closest("input, button, a, select, textarea"))
3376
+ return;
2845
3377
  const cell = target.closest("[data-bt-cell]");
2846
3378
  if (!cell) return;
2847
3379
  const rk = cell.dataset.rowKey;
@@ -2849,21 +3381,21 @@ function BoltTable({
2849
3381
  for (let i = 0; i < displayData.length; i++) {
2850
3382
  const row = displayData[i];
2851
3383
  if (row == null) continue;
2852
- if (getRowKey(row, i) === rk) {
3384
+ if (getSafeRowKey(row, i) === rk) {
2853
3385
  onRowClick(row, i, e);
2854
3386
  return;
2855
3387
  }
2856
3388
  }
2857
3389
  for (let i = 0; i < pinnedTopRows.length; i++) {
2858
3390
  if (pinnedTopRows[i] == null) continue;
2859
- if (getRowKey(pinnedTopRows[i], i) === rk) {
3391
+ if (getSafeRowKey(pinnedTopRows[i], i) === rk) {
2860
3392
  onRowClick(pinnedTopRows[i], i, e);
2861
3393
  return;
2862
3394
  }
2863
3395
  }
2864
3396
  for (let i = 0; i < pinnedBottomRows.length; i++) {
2865
3397
  if (pinnedBottomRows[i] == null) continue;
2866
- if (getRowKey(pinnedBottomRows[i], i) === rk) {
3398
+ if (getSafeRowKey(pinnedBottomRows[i], i) === rk) {
2867
3399
  onRowClick(pinnedBottomRows[i], i, e);
2868
3400
  return;
2869
3401
  }
@@ -2973,7 +3505,11 @@ function BoltTable({
2973
3505
  });
2974
3506
  }
2975
3507
  },
2976
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
3508
+ style: {
3509
+ cursor: "pointer",
3510
+ accentColor,
3511
+ backgroundColor: "#94A3B8"
3512
+ }
2977
3513
  }
2978
3514
  )
2979
3515
  },
@@ -3033,7 +3569,10 @@ function BoltTable({
3033
3569
  filterValue: columnFilters[column.key] ?? "",
3034
3570
  onFilter: handleColumnFilter,
3035
3571
  onClearFilter: handleClearFilter,
3036
- customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
3572
+ customContextMenuItems: column.columnHeaderContextMenuItems ? [
3573
+ ...columnContextMenuItems ?? [],
3574
+ ...column.columnHeaderContextMenuItems
3575
+ ] : columnContextMenuItems,
3037
3576
  disabledFilters,
3038
3577
  headerGridRow: leafGridRow,
3039
3578
  headerHeight: leafHeight,
@@ -3085,14 +3624,14 @@ function BoltTable({
3085
3624
  TableBody_default,
3086
3625
  {
3087
3626
  data: displayData,
3088
- orderedColumns: freshOrderedColumns,
3627
+ orderedColumns: virtualizedColumns,
3089
3628
  rowVirtualizer,
3090
3629
  columnOffsets,
3091
3630
  styles,
3092
3631
  classNames,
3093
3632
  rowSelection: !showShimmer ? rowSelection : void 0,
3094
3633
  normalizedSelectedKeys,
3095
- getRowKey,
3634
+ getRowKey: getSafeRowKey,
3096
3635
  getRawRowKey,
3097
3636
  expandable: !showShimmer ? expandable : void 0,
3098
3637
  resolvedExpandedKeys,
@@ -3113,7 +3652,10 @@ function BoltTable({
3113
3652
  bodyGridRow: hasColumnGroups ? 3 : 2,
3114
3653
  onEdit,
3115
3654
  editingCell,
3116
- onEditComplete: handleEditComplete
3655
+ onEditComplete: handleEditComplete,
3656
+ enableDynamicRowHeight,
3657
+ onRowHeightChange: handleRowHeightChange,
3658
+ columnGridIndexMap
3117
3659
  }
3118
3660
  )
3119
3661
  ]
@@ -3143,39 +3685,53 @@ function BoltTable({
3143
3685
  ...styles.pagination
3144
3686
  },
3145
3687
  children: [
3146
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
3147
- const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
3148
- const rangeEnd = Math.min(currentPage * pageSize, total);
3149
- return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3150
- "span",
3151
- {
3152
- className: classNames.paginationInfo ?? "",
3153
- style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3154
- children: [
3155
- "Showing",
3156
- " ",
3157
- pagination.showTotal(total, [rangeStart, rangeEnd]),
3158
- " of",
3159
- " ",
3160
- total,
3161
- " items"
3162
- ]
3163
- }
3164
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3165
- "span",
3166
- {
3167
- className: classNames.paginationInfo ?? "",
3168
- style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3169
- children: [
3170
- rangeStart,
3171
- "\u2013",
3172
- rangeEnd,
3173
- " of ",
3174
- total
3175
- ]
3176
- }
3177
- );
3178
- })() }),
3688
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3689
+ "div",
3690
+ {
3691
+ style: { display: "flex", flex: "1 1 0%", alignItems: "center" },
3692
+ children: (() => {
3693
+ const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
3694
+ const rangeEnd = Math.min(currentPage * pageSize, total);
3695
+ return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3696
+ "span",
3697
+ {
3698
+ className: classNames.paginationInfo ?? "",
3699
+ style: {
3700
+ color: "GrayText",
3701
+ fontSize: 12,
3702
+ ...styles.paginationInfo
3703
+ },
3704
+ children: [
3705
+ "Showing",
3706
+ " ",
3707
+ pagination.showTotal(total, [rangeStart, rangeEnd]),
3708
+ " of",
3709
+ " ",
3710
+ total,
3711
+ " items"
3712
+ ]
3713
+ }
3714
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3715
+ "span",
3716
+ {
3717
+ className: classNames.paginationInfo ?? "",
3718
+ style: {
3719
+ color: "GrayText",
3720
+ fontSize: 12,
3721
+ ...styles.paginationInfo
3722
+ },
3723
+ children: [
3724
+ rangeStart,
3725
+ "\u2013",
3726
+ rangeEnd,
3727
+ " of ",
3728
+ total
3729
+ ]
3730
+ }
3731
+ );
3732
+ })()
3733
+ }
3734
+ ),
3179
3735
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3180
3736
  "div",
3181
3737
  {
@@ -3458,9 +4014,7 @@ function BoltTable({
3458
4014
  (c) => c.key === cellContextMenu.columnKey
3459
4015
  );
3460
4016
  const isPinnedTop = pinnedTopKeySet.has(cellContextMenu.rowKey);
3461
- const isPinnedBottom = pinnedBottomKeySet.has(
3462
- cellContextMenu.rowKey
3463
- );
4017
+ const isPinnedBottom = pinnedBottomKeySet.has(cellContextMenu.rowKey);
3464
4018
  const hasCopy = !!menuCol?.copy;
3465
4019
  const hasRowPin = !!rowPinning;
3466
4020
  const hasEdit = !!menuCol?.editable && !menuCol?.render && !!onEdit;
@@ -3473,7 +4027,7 @@ function BoltTable({
3473
4027
  ];
3474
4028
  for (let i = 0; i < allRows.length; i++) {
3475
4029
  if (allRows[i] == null) continue;
3476
- const rk = getRowKey(allRows[i], i);
4030
+ const rk = getSafeRowKey(allRows[i], i);
3477
4031
  if (rk === cellContextMenu.rowKey) {
3478
4032
  menuRecord = allRows[i];
3479
4033
  menuRowIndex = i;
@@ -3675,7 +4229,20 @@ function BoltTable({
3675
4229
  setCellContextMenu(null);
3676
4230
  },
3677
4231
  children: [
3678
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { display: "flex", width: 14, height: 14, alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: item.icon }),
4232
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4233
+ "span",
4234
+ {
4235
+ style: {
4236
+ display: "flex",
4237
+ width: 14,
4238
+ height: 14,
4239
+ alignItems: "center",
4240
+ justifyContent: "center",
4241
+ flexShrink: 0
4242
+ },
4243
+ children: item.icon
4244
+ }
4245
+ ),
3679
4246
  item.label
3680
4247
  ]
3681
4248
  },