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.mjs CHANGED
@@ -90,6 +90,18 @@ var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgB
90
90
  /* @__PURE__ */ 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" }),
91
91
  /* @__PURE__ */ jsx("line", { x1: "2", x2: "22", y1: "2", y2: "22" })
92
92
  ] });
93
+ var SearchIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
94
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
95
+ /* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
96
+ ] });
97
+ var ColumnsIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
98
+ /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }),
99
+ /* @__PURE__ */ jsx("line", { x1: "12", x2: "12", y1: "3", y2: "21" })
100
+ ] });
101
+ var XIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
102
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
103
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
104
+ ] });
93
105
 
94
106
  // src/DraggableHeader.tsx
95
107
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -762,7 +774,13 @@ ResizeOverlay.displayName = "ResizeOverlay";
762
774
  var ResizeOverlay_default = ResizeOverlay;
763
775
 
764
776
  // src/TableBody.tsx
765
- import React3, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef3, useState as useState2 } from "react";
777
+ import React3, {
778
+ useCallback,
779
+ useEffect as useEffect2,
780
+ useMemo,
781
+ useRef as useRef3,
782
+ useState as useState2
783
+ } from "react";
766
784
  import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
767
785
  var SHIMMER_WIDTHS = [55, 70, 45, 80, 60, 50, 75, 65];
768
786
  var EditableCell = ({
@@ -789,7 +807,15 @@ var EditableCell = ({
789
807
  onEdit(coerced, record, column.dataIndex, rowIndex);
790
808
  }
791
809
  onEditComplete();
792
- }, [draft, value, column.dataIndex, record, rowIndex, onEdit, onEditComplete]);
810
+ }, [
811
+ draft,
812
+ value,
813
+ column.dataIndex,
814
+ record,
815
+ rowIndex,
816
+ onEdit,
817
+ onEditComplete
818
+ ]);
793
819
  const cancel = useCallback(() => {
794
820
  onEditComplete();
795
821
  }, [onEditComplete]);
@@ -891,7 +917,11 @@ var Cell = React3.memo(
891
917
  rowSelection.onSelect?.(record, true, [record], e.nativeEvent);
892
918
  rowSelection.onChange?.([rawKey], [record], { type: "single" });
893
919
  },
894
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
920
+ style: {
921
+ cursor: "pointer",
922
+ accentColor,
923
+ backgroundColor: "#94A3B8"
924
+ }
895
925
  }
896
926
  ) : /* @__PURE__ */ jsx4(
897
927
  "input",
@@ -917,7 +947,11 @@ var Cell = React3.memo(
917
947
  type: "multiple"
918
948
  });
919
949
  },
920
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
950
+ style: {
951
+ cursor: "pointer",
952
+ accentColor,
953
+ backgroundColor: "#94A3B8"
954
+ }
921
955
  }
922
956
  );
923
957
  return /* @__PURE__ */ jsx4(
@@ -1053,6 +1087,33 @@ var MeasuredExpandedRow = React3.memo(
1053
1087
  }
1054
1088
  );
1055
1089
  MeasuredExpandedRow.displayName = "MeasuredExpandedRow";
1090
+ var DynamicRowMeasurer = React3.memo(
1091
+ ({
1092
+ index,
1093
+ onHeightChange,
1094
+ children
1095
+ }) => {
1096
+ const ref = useRef3(null);
1097
+ const onHeightChangeRef = useRef3(onHeightChange);
1098
+ useEffect2(() => {
1099
+ onHeightChangeRef.current = onHeightChange;
1100
+ }, [onHeightChange]);
1101
+ useEffect2(() => {
1102
+ const el = ref.current;
1103
+ if (!el) return;
1104
+ const observer = new ResizeObserver((entries) => {
1105
+ const height = entries[0]?.borderBoxSize?.[0]?.blockSize;
1106
+ if (height != null && height > 0) {
1107
+ onHeightChangeRef.current(index, Math.ceil(height));
1108
+ }
1109
+ });
1110
+ observer.observe(el);
1111
+ return () => observer.disconnect();
1112
+ }, [index]);
1113
+ return /* @__PURE__ */ jsx4("div", { ref, children });
1114
+ }
1115
+ );
1116
+ DynamicRowMeasurer.displayName = "DynamicRowMeasurer";
1056
1117
  var TableBody = ({
1057
1118
  data,
1058
1119
  orderedColumns,
@@ -1082,11 +1143,17 @@ var TableBody = ({
1082
1143
  bodyGridRow = 2,
1083
1144
  onEdit,
1084
1145
  editingCell,
1085
- onEditComplete
1146
+ onEditComplete,
1147
+ enableDynamicRowHeight = false,
1148
+ onRowHeightChange,
1149
+ columnGridIndexMap
1086
1150
  }) => {
1087
1151
  const virtualItems = rowVirtualizer.getVirtualItems();
1088
1152
  const totalSize = rowVirtualizer.getTotalSize();
1089
- const selectedKeySet = useMemo(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
1153
+ const selectedKeySet = useMemo(
1154
+ () => new Set(normalizedSelectedKeys),
1155
+ [normalizedSelectedKeys]
1156
+ );
1090
1157
  const safeData = data ?? [];
1091
1158
  const safeColumns = orderedColumns ?? [];
1092
1159
  const allDataForSelection = useMemo(() => {
@@ -1102,8 +1169,9 @@ var TableBody = ({
1102
1169
  let zIndex = 0;
1103
1170
  if (col.key === "__select__" || col.key === "__expand__") zIndex = 11;
1104
1171
  else if (isPinned) zIndex = 2;
1172
+ const gridCol = columnGridIndexMap?.get(col.key) ?? colIndex + 1;
1105
1173
  const style = {
1106
- gridColumn: colIndex + 1,
1174
+ gridColumn: gridCol,
1107
1175
  gridRow: bodyGridRow,
1108
1176
  height: `${totalSize}px`,
1109
1177
  position: isPinned ? "sticky" : "relative",
@@ -1118,7 +1186,7 @@ var TableBody = ({
1118
1186
  }
1119
1187
  return { key: col.key, style, isPinned };
1120
1188
  });
1121
- }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow]);
1189
+ }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow, columnGridIndexMap]);
1122
1190
  if (safeData.length === 0 || safeColumns.length === 0) return null;
1123
1191
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1124
1192
  columnStyles.map((colStyle, colIndex) => {
@@ -1169,15 +1237,58 @@ var TableBody = ({
1169
1237
  top: `${virtualRow.start}px`,
1170
1238
  left: 0,
1171
1239
  right: 0,
1172
- height: `${virtualRow.size}px`,
1173
- ...rowSty
1240
+ height: enableDynamicRowHeight ? void 0 : `${virtualRow.size}px`,
1241
+ minHeight: enableDynamicRowHeight ? `${rowHeight}px` : void 0
1174
1242
  },
1175
- children: /* @__PURE__ */ jsx4(
1243
+ children: enableDynamicRowHeight && onRowHeightChange && colIndex === 0 ? /* @__PURE__ */ jsx4(
1244
+ DynamicRowMeasurer,
1245
+ {
1246
+ index: virtualRow.index,
1247
+ onHeightChange: onRowHeightChange,
1248
+ children: /* @__PURE__ */ jsx4(
1249
+ "div",
1250
+ {
1251
+ style: {
1252
+ minHeight: `${rowHeight}px`,
1253
+ position: "relative",
1254
+ ...rowSty
1255
+ },
1256
+ children: /* @__PURE__ */ jsx4(
1257
+ Cell,
1258
+ {
1259
+ value: cellValue,
1260
+ record: row,
1261
+ column: col,
1262
+ rowIndex: virtualRow.index,
1263
+ classNames,
1264
+ styles,
1265
+ isSelected,
1266
+ isExpanded,
1267
+ rowSelection,
1268
+ normalizedSelectedKeys,
1269
+ rowKey,
1270
+ allData: allDataForSelection,
1271
+ getRowKey,
1272
+ getRawRowKey,
1273
+ accentColor,
1274
+ isLoading: isRowShimmer,
1275
+ recordFingerprint,
1276
+ onEdit,
1277
+ isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
1278
+ onEditComplete
1279
+ }
1280
+ )
1281
+ }
1282
+ )
1283
+ }
1284
+ ) : /* @__PURE__ */ jsx4(
1176
1285
  "div",
1177
1286
  {
1178
1287
  style: {
1179
- height: `${rowHeight}px`,
1180
- position: "relative"
1288
+ height: enableDynamicRowHeight ? void 0 : `${rowHeight}px`,
1289
+ minHeight: enableDynamicRowHeight ? `${rowHeight}px` : void 0,
1290
+ position: "relative",
1291
+ ...rowSty
1181
1292
  },
1182
1293
  children: /* @__PURE__ */ jsx4(
1183
1294
  Cell,
@@ -1232,7 +1343,12 @@ var TableBody = ({
1232
1343
  if (!(resolvedExpandedKeys?.has(rk) ?? false)) return null;
1233
1344
  let expandedRenderResult = null;
1234
1345
  try {
1235
- expandedRenderResult = expandable.expandedRowRender(row, virtualRow.index, 0, true);
1346
+ expandedRenderResult = expandable.expandedRowRender(
1347
+ row,
1348
+ virtualRow.index,
1349
+ 0,
1350
+ true
1351
+ );
1236
1352
  } catch {
1237
1353
  }
1238
1354
  const expandedContent = /* @__PURE__ */ jsx4(
@@ -1600,7 +1716,16 @@ function BoltTable({
1600
1716
  onCopy,
1601
1717
  keepPinnedRowsAcrossPages,
1602
1718
  onEdit,
1603
- onRowClick
1719
+ onRowClick,
1720
+ enableColumnVirtualization = false,
1721
+ enableDynamicRowHeight = false,
1722
+ columnPersistence = false,
1723
+ showColumnSettings = true,
1724
+ hideGlobalSearch = false,
1725
+ globalSearchValue,
1726
+ onGlobalSearchChange,
1727
+ toolbarContent,
1728
+ columnSettingsLabel
1604
1729
  }) {
1605
1730
  const data = useMemo2(() => {
1606
1731
  if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
@@ -1608,7 +1733,8 @@ function BoltTable({
1608
1733
  return filtered.length > 0 ? filtered : STABLE_EMPTY_DATA;
1609
1734
  }, [rawData]);
1610
1735
  const initialColumns = useMemo2(() => {
1611
- if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1736
+ if (!Array.isArray(rawInitialColumns))
1737
+ return STABLE_EMPTY_COLS;
1612
1738
  const safe = rawInitialColumns.filter(
1613
1739
  (col) => col != null && typeof col.key === "string"
1614
1740
  );
@@ -1673,6 +1799,106 @@ function BoltTable({
1673
1799
  () => /* @__PURE__ */ new Map()
1674
1800
  );
1675
1801
  const manuallyResizedRef = useRef4(/* @__PURE__ */ new Set());
1802
+ const persistenceAppliedRef = useRef4(false);
1803
+ React4.useEffect(() => {
1804
+ if (!columnPersistence || persistenceAppliedRef.current) return;
1805
+ persistenceAppliedRef.current = true;
1806
+ const {
1807
+ storageKey,
1808
+ persistOrder = true,
1809
+ persistWidths = true,
1810
+ persistVisibility = true,
1811
+ persistPinned = true
1812
+ } = columnPersistence;
1813
+ try {
1814
+ const raw = localStorage.getItem(`bt_${storageKey}`);
1815
+ if (!raw) return;
1816
+ const saved = JSON.parse(raw);
1817
+ if (persistOrder && saved.order) {
1818
+ setColumnOrder(saved.order);
1819
+ }
1820
+ if (persistWidths && saved.widths) {
1821
+ setColumnWidths(
1822
+ new Map(Object.entries(saved.widths).map(([k, v]) => [k, Number(v)]))
1823
+ );
1824
+ }
1825
+ if (persistVisibility && saved.hidden || persistPinned && saved.pinned) {
1826
+ setColumns(
1827
+ (prev) => prev.map((col) => {
1828
+ let updated = col;
1829
+ if (persistVisibility && saved.hidden && col.key in saved.hidden) {
1830
+ updated = { ...updated, hidden: saved.hidden[col.key] };
1831
+ }
1832
+ if (persistPinned && saved.pinned && col.key in saved.pinned) {
1833
+ updated = { ...updated, pinned: saved.pinned[col.key] };
1834
+ }
1835
+ return updated;
1836
+ })
1837
+ );
1838
+ }
1839
+ } catch {
1840
+ }
1841
+ }, [columnPersistence]);
1842
+ const persistColumnsToStorage = useCallback2(() => {
1843
+ if (!columnPersistence) return;
1844
+ const {
1845
+ storageKey,
1846
+ persistOrder = true,
1847
+ persistWidths = true,
1848
+ persistVisibility = true,
1849
+ persistPinned = true
1850
+ } = columnPersistence;
1851
+ try {
1852
+ const saved = {};
1853
+ if (persistOrder) saved.order = columnOrder;
1854
+ if (persistWidths) {
1855
+ const widths = {};
1856
+ columnWidths.forEach((v, k) => {
1857
+ widths[k] = v;
1858
+ });
1859
+ saved.widths = widths;
1860
+ }
1861
+ if (persistVisibility) {
1862
+ const hidden = {};
1863
+ columns.forEach((c) => {
1864
+ if (c.hidden) hidden[c.key] = true;
1865
+ });
1866
+ saved.hidden = hidden;
1867
+ }
1868
+ if (persistPinned) {
1869
+ const pinned = {};
1870
+ columns.forEach((c) => {
1871
+ if (c.pinned) pinned[c.key] = c.pinned;
1872
+ });
1873
+ saved.pinned = pinned;
1874
+ }
1875
+ localStorage.setItem(`bt_${storageKey}`, JSON.stringify(saved));
1876
+ } catch {
1877
+ }
1878
+ }, [columnPersistence, columnOrder, columnWidths, columns]);
1879
+ React4.useEffect(() => {
1880
+ if (!columnPersistence || !persistenceAppliedRef.current) return;
1881
+ persistColumnsToStorage();
1882
+ }, [columnPersistence, persistColumnsToStorage]);
1883
+ const [showColumnPicker, setShowColumnPicker] = useState3(false);
1884
+ const columnPickerRef = useRef4(null);
1885
+ React4.useEffect(() => {
1886
+ if (!showColumnPicker) return;
1887
+ const close = (e) => {
1888
+ if (columnPickerRef.current && !columnPickerRef.current.contains(e.target)) {
1889
+ setShowColumnPicker(false);
1890
+ }
1891
+ };
1892
+ const onKey = (e) => {
1893
+ if (e.key === "Escape") setShowColumnPicker(false);
1894
+ };
1895
+ document.addEventListener("mousedown", close);
1896
+ document.addEventListener("keydown", onKey);
1897
+ return () => {
1898
+ document.removeEventListener("mousedown", close);
1899
+ document.removeEventListener("keydown", onKey);
1900
+ };
1901
+ }, [showColumnPicker]);
1676
1902
  const columnsWithPersistedWidths = useMemo2(
1677
1903
  () => columns.map((col) => ({
1678
1904
  ...col,
@@ -1737,6 +1963,32 @@ function BoltTable({
1737
1963
  },
1738
1964
  [rowKey]
1739
1965
  );
1966
+ const deduplicatedRowKeys = useMemo2(() => {
1967
+ const seen = /* @__PURE__ */ new Map();
1968
+ return data.map((row, idx) => {
1969
+ const raw = getRowKey(row, idx);
1970
+ const count = seen.get(raw) ?? 0;
1971
+ seen.set(raw, count + 1);
1972
+ return count > 0 ? `${raw}__${idx}` : raw;
1973
+ });
1974
+ }, [data, getRowKey]);
1975
+ const hasDuplicateKeys = useMemo2(() => {
1976
+ const seen = /* @__PURE__ */ new Set();
1977
+ for (const row of data) {
1978
+ if (row == null) continue;
1979
+ const k = getRowKey(row, 0);
1980
+ if (seen.has(k)) return true;
1981
+ seen.add(k);
1982
+ }
1983
+ return false;
1984
+ }, [data, getRowKey]);
1985
+ const getSafeRowKey = useCallback2(
1986
+ (record, index) => {
1987
+ if (!hasDuplicateKeys) return getRowKey(record, index);
1988
+ return deduplicatedRowKeys[index] ?? getRowKey(record, index);
1989
+ },
1990
+ [getRowKey, hasDuplicateKeys, deduplicatedRowKeys]
1991
+ );
1740
1992
  const getRawRowKey = useCallback2(
1741
1993
  (record, index) => {
1742
1994
  if (record == null) return index;
@@ -1754,16 +2006,13 @@ function BoltTable({
1754
2006
  },
1755
2007
  [rowKey]
1756
2008
  );
1757
- const normalizedSelectedKeys = useMemo2(
1758
- () => {
1759
- const keys = rowSelection?.selectedRowKeys;
1760
- if (!Array.isArray(keys)) return [];
1761
- return keys.filter((k) => k != null).map((k) => String(k));
1762
- },
1763
- [rowSelection?.selectedRowKeys]
1764
- );
1765
- const getRowKeyRef = useRef4(getRowKey);
1766
- getRowKeyRef.current = getRowKey;
2009
+ const normalizedSelectedKeys = useMemo2(() => {
2010
+ const keys = rowSelection?.selectedRowKeys;
2011
+ if (!Array.isArray(keys)) return [];
2012
+ return keys.filter((k) => k != null).map((k) => String(k));
2013
+ }, [rowSelection?.selectedRowKeys]);
2014
+ const getRowKeyRef = useRef4(getSafeRowKey);
2015
+ getRowKeyRef.current = getSafeRowKey;
1767
2016
  const resolvedExpandedKeysRef = useRef4(resolvedExpandedKeys);
1768
2017
  resolvedExpandedKeysRef.current = resolvedExpandedKeys;
1769
2018
  const toggleExpandRef = useRef4(toggleExpand);
@@ -1946,7 +2195,9 @@ function BoltTable({
1946
2195
  }
1947
2196
  const scrollEl = tableAreaRef.current;
1948
2197
  if (!scrollEl) return;
1949
- const headers = scrollEl.querySelectorAll("[data-bt-header][data-column-key]");
2198
+ const headers = scrollEl.querySelectorAll(
2199
+ "[data-bt-header][data-column-key]"
2200
+ );
1950
2201
  let newOverId = null;
1951
2202
  headers.forEach((h) => {
1952
2203
  const key = h.dataset.columnKey;
@@ -1988,10 +2239,7 @@ function BoltTable({
1988
2239
  const newIndex = items.indexOf(currentOverId);
1989
2240
  if (oldIndex === -1 || newIndex === -1) return items;
1990
2241
  const newOrder = arrayMove(items, oldIndex, newIndex);
1991
- setTimeout(
1992
- () => onColumnOrderChangeRef.current?.(newOrder),
1993
- 0
1994
- );
2242
+ setTimeout(() => onColumnOrderChangeRef.current?.(newOrder), 0);
1995
2243
  return newOrder;
1996
2244
  });
1997
2245
  });
@@ -2091,9 +2339,7 @@ function BoltTable({
2091
2339
  [leftPinned, unpinned, rightPinned]
2092
2340
  );
2093
2341
  const freshOrderedColumns = useMemo2(() => {
2094
- const latestMap = new Map(
2095
- initialColumnsRef.current.map((c) => [c.key, c])
2096
- );
2342
+ const latestMap = new Map(initialColumnsRef.current.map((c) => [c.key, c]));
2097
2343
  return orderedColumns.map((col) => {
2098
2344
  if (col.key === "__select__" || col.key === "__expand__") return col;
2099
2345
  const latest = latestMap.get(col.key);
@@ -2132,6 +2378,11 @@ function BoltTable({
2132
2378
  }
2133
2379
  return offsets;
2134
2380
  }, [leftPinned, rightPinned]);
2381
+ const columnGridIndexMap = useMemo2(() => {
2382
+ const map = /* @__PURE__ */ new Map();
2383
+ orderedColumns.forEach((col, i) => map.set(col.key, i + 1));
2384
+ return map;
2385
+ }, [orderedColumns]);
2135
2386
  const handleTogglePin = (columnKey, pinned) => {
2136
2387
  setColumns(
2137
2388
  (prev) => prev.map((col) => col.key === columnKey ? { ...col, pinned } : col)
@@ -2150,22 +2401,27 @@ function BoltTable({
2150
2401
  };
2151
2402
  const [internalRowPinning, setInternalRowPinning] = useState3({ top: [], bottom: [] });
2152
2403
  const resolvedRowPinning = rowPinning === true ? internalRowPinning : rowPinning && typeof rowPinning === "object" ? rowPinning : void 0;
2153
- const handleRowPin = useCallback2((rk, pinned) => {
2154
- if (onRowPin) {
2155
- onRowPin(rk, pinned);
2156
- return;
2157
- }
2158
- if (rowPinning === true) {
2159
- setInternalRowPinning((prev) => {
2160
- const rkStr = String(rk);
2161
- const newTop = (prev.top ?? []).filter((k) => String(k) !== rkStr);
2162
- const newBottom = (prev.bottom ?? []).filter((k) => String(k) !== rkStr);
2163
- if (pinned === "top") newTop.push(rk);
2164
- else if (pinned === "bottom") newBottom.push(rk);
2165
- return { top: newTop, bottom: newBottom };
2166
- });
2167
- }
2168
- }, [onRowPin, rowPinning]);
2404
+ const handleRowPin = useCallback2(
2405
+ (rk, pinned) => {
2406
+ if (onRowPin) {
2407
+ onRowPin(rk, pinned);
2408
+ return;
2409
+ }
2410
+ if (rowPinning === true) {
2411
+ setInternalRowPinning((prev) => {
2412
+ const rkStr = String(rk);
2413
+ const newTop = (prev.top ?? []).filter((k) => String(k) !== rkStr);
2414
+ const newBottom = (prev.bottom ?? []).filter(
2415
+ (k) => String(k) !== rkStr
2416
+ );
2417
+ if (pinned === "top") newTop.push(rk);
2418
+ else if (pinned === "bottom") newBottom.push(rk);
2419
+ return { top: newTop, bottom: newBottom };
2420
+ });
2421
+ }
2422
+ },
2423
+ [onRowPin, rowPinning]
2424
+ );
2169
2425
  const onSortChangeRef = useRef4(onSortChange);
2170
2426
  onSortChangeRef.current = onSortChange;
2171
2427
  const [sortState, setSortState] = useState3({ key: "", direction: null });
@@ -2188,6 +2444,7 @@ function BoltTable({
2188
2444
  const [columnFilters, setColumnFilters] = useState3(
2189
2445
  {}
2190
2446
  );
2447
+ const [internalGlobalSearch, setInternalGlobalSearch] = useState3("");
2191
2448
  const handleColumnFilter = useCallback2(
2192
2449
  (columnKey, value) => {
2193
2450
  setColumnFilters((prev) => {
@@ -2212,6 +2469,20 @@ function BoltTable({
2212
2469
  columnsLookupRef.current = initialColumns;
2213
2470
  const processedData = useMemo2(() => {
2214
2471
  let result = data;
2472
+ const globalSearch = globalSearchValue ?? internalGlobalSearch;
2473
+ if (globalSearch) {
2474
+ const searchLower = globalSearch.toLowerCase();
2475
+ result = result.filter((row) => {
2476
+ if (row == null) return false;
2477
+ for (const key of Object.keys(row)) {
2478
+ const val = row[key];
2479
+ if (val != null && String(val).toLowerCase().includes(searchLower)) {
2480
+ return true;
2481
+ }
2482
+ }
2483
+ return false;
2484
+ });
2485
+ }
2215
2486
  if (!onFilterChangeRef.current) {
2216
2487
  const filterKeys = Object.keys(columnFilters);
2217
2488
  if (filterKeys.length > 0) {
@@ -2221,7 +2492,11 @@ function BoltTable({
2221
2492
  try {
2222
2493
  const col = columnsLookupRef.current.find((c) => c.key === key);
2223
2494
  if (typeof col?.filterFn === "function") {
2224
- return col.filterFn(columnFilters[key], row, col.dataIndex ?? key);
2495
+ return col.filterFn(
2496
+ columnFilters[key],
2497
+ row,
2498
+ col.dataIndex ?? key
2499
+ );
2225
2500
  }
2226
2501
  const cellVal = String(row[key] ?? "").toLowerCase();
2227
2502
  return cellVal.includes(columnFilters[key].toLowerCase());
@@ -2264,7 +2539,7 @@ function BoltTable({
2264
2539
  }
2265
2540
  }
2266
2541
  return result;
2267
- }, [data, sortState, columnFilters]);
2542
+ }, [data, sortState, columnFilters, globalSearchValue, internalGlobalSearch]);
2268
2543
  const pinnedRowCacheRef = useRef4(/* @__PURE__ */ new Map());
2269
2544
  const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = useMemo2(() => {
2270
2545
  if (!resolvedRowPinning || !resolvedRowPinning.top?.length && !resolvedRowPinning.bottom?.length) {
@@ -2276,19 +2551,23 @@ function BoltTable({
2276
2551
  };
2277
2552
  }
2278
2553
  const topKeySet = new Set((resolvedRowPinning.top ?? []).map(String));
2279
- const bottomKeySet = new Set((resolvedRowPinning.bottom ?? []).map(String));
2554
+ const bottomKeySet = new Set(
2555
+ (resolvedRowPinning.bottom ?? []).map(String)
2556
+ );
2280
2557
  const topMap = /* @__PURE__ */ new Map();
2281
2558
  const bottomMap = /* @__PURE__ */ new Map();
2282
2559
  const rest = [];
2283
2560
  processedData.forEach((row, idx) => {
2284
2561
  if (row == null) return;
2285
- const key = getRowKey(row, idx);
2562
+ const key = getSafeRowKey(row, idx);
2286
2563
  if (topKeySet.has(key)) {
2287
2564
  topMap.set(key, row);
2288
- if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2565
+ if (keepPinnedRowsAcrossPages)
2566
+ pinnedRowCacheRef.current.set(key, row);
2289
2567
  } else if (bottomKeySet.has(key)) {
2290
2568
  bottomMap.set(key, row);
2291
- if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2569
+ if (keepPinnedRowsAcrossPages)
2570
+ pinnedRowCacheRef.current.set(key, row);
2292
2571
  } else {
2293
2572
  rest.push(row);
2294
2573
  }
@@ -2306,7 +2585,8 @@ function BoltTable({
2306
2585
  }
2307
2586
  const allPinnedKeys = /* @__PURE__ */ new Set([...topKeySet, ...bottomKeySet]);
2308
2587
  for (const cachedKey of pinnedRowCacheRef.current.keys()) {
2309
- if (!allPinnedKeys.has(cachedKey)) pinnedRowCacheRef.current.delete(cachedKey);
2588
+ if (!allPinnedKeys.has(cachedKey))
2589
+ pinnedRowCacheRef.current.delete(cachedKey);
2310
2590
  }
2311
2591
  }
2312
2592
  const orderedTop = (resolvedRowPinning.top ?? []).map((k) => topMap.get(String(k))).filter((r) => r !== void 0);
@@ -2316,7 +2596,12 @@ function BoltTable({
2316
2596
  pinnedBottomRows: orderedBottom,
2317
2597
  unpinnedProcessedData: rest
2318
2598
  };
2319
- }, [processedData, resolvedRowPinning, getRowKey, keepPinnedRowsAcrossPages]);
2599
+ }, [
2600
+ processedData,
2601
+ resolvedRowPinning,
2602
+ getSafeRowKey,
2603
+ keepPinnedRowsAcrossPages
2604
+ ]);
2320
2605
  const pinnedTopHeight = pinnedTopRows.length * rowHeight;
2321
2606
  const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
2322
2607
  const pinnedTopKeySet = useMemo2(
@@ -2333,9 +2618,7 @@ function BoltTable({
2333
2618
  }, []);
2334
2619
  const [cellContextMenu, setCellContextMenu] = useState3(null);
2335
2620
  const cellMenuRef = useRef4(null);
2336
- const cellLongPressTimer = useRef4(
2337
- null
2338
- );
2621
+ const cellLongPressTimer = useRef4(null);
2339
2622
  const cellTouchStart = useRef4(null);
2340
2623
  const cancelCellLongPress = useCallback2(() => {
2341
2624
  if (cellLongPressTimer.current) {
@@ -2362,10 +2645,11 @@ function BoltTable({
2362
2645
  };
2363
2646
  }, [cellContextMenu]);
2364
2647
  const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
2648
+ const activeGlobalSearch = globalSearchValue ?? internalGlobalSearch;
2365
2649
  React4.useEffect(() => {
2366
2650
  setInternalPage(1);
2367
2651
  tableAreaRef.current?.scrollTo({ top: 0 });
2368
- }, [columnFiltersKey]);
2652
+ }, [columnFiltersKey, activeGlobalSearch]);
2369
2653
  const DEFAULT_PAGE_SIZE = 15;
2370
2654
  const [internalPage, setInternalPage] = useState3(1);
2371
2655
  const [internalPageSize, setInternalPageSize] = useState3(DEFAULT_PAGE_SIZE);
@@ -2411,6 +2695,17 @@ function BoltTable({
2411
2695
  return paginatedData;
2412
2696
  }, [shimmerData, infiniteLoadingShimmer, paginatedData]);
2413
2697
  const measuredExpandedHeights = useRef4(/* @__PURE__ */ new Map());
2698
+ const measuredRowHeights = useRef4(/* @__PURE__ */ new Map());
2699
+ const handleRowHeightChange = useCallback2(
2700
+ (index, height) => {
2701
+ if (!enableDynamicRowHeight) return;
2702
+ const prev = measuredRowHeights.current.get(index);
2703
+ if (prev === height) return;
2704
+ measuredRowHeights.current.set(index, height);
2705
+ rowVirtualizerRef.current?.measure();
2706
+ },
2707
+ [enableDynamicRowHeight]
2708
+ );
2414
2709
  const expandedRowMeasureRafRef = useRef4(null);
2415
2710
  const handleExpandedRowResize = useCallback2(
2416
2711
  (rk, contentHeight) => {
@@ -2435,23 +2730,73 @@ function BoltTable({
2435
2730
  if (shimmerData) return rowHeight;
2436
2731
  const item = displayData[index];
2437
2732
  if (!item) return rowHeight;
2438
- const key = getRowKey(item, index);
2439
- if (!resolvedExpandedKeys.has(key)) return rowHeight;
2733
+ const baseHeight = enableDynamicRowHeight ? measuredRowHeights.current.get(index) ?? rowHeight : rowHeight;
2734
+ const key = getSafeRowKey(item, index);
2735
+ if (!resolvedExpandedKeys.has(key)) return baseHeight;
2440
2736
  const cached = measuredExpandedHeights.current.get(key);
2441
- return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
2737
+ return cached ? baseHeight + cached : baseHeight + expandedRowHeight;
2442
2738
  },
2443
2739
  overscan: 5,
2444
2740
  getItemKey: (index) => {
2445
2741
  if (shimmerData) return `__shimmer_${index}__`;
2446
2742
  const item = displayData[index];
2447
2743
  if (!item) return `__fallback_${index}__`;
2448
- return getRowKey(item, index);
2744
+ return getSafeRowKey(item, index);
2449
2745
  },
2450
2746
  paddingStart: pinnedTopHeight,
2451
2747
  paddingEnd: pinnedBottomHeight
2452
2748
  });
2453
2749
  const rowVirtualizerRef = useRef4(rowVirtualizer);
2454
2750
  rowVirtualizerRef.current = rowVirtualizer;
2751
+ const scrollLeftRef = useRef4(0);
2752
+ const [visibleColumnRange, setVisibleColumnRange] = useState3(null);
2753
+ React4.useEffect(() => {
2754
+ if (!enableColumnVirtualization) return;
2755
+ const el = tableAreaRef.current;
2756
+ if (!el) return;
2757
+ const updateVisibleColumns = () => {
2758
+ const scrollLeft = el.scrollLeft;
2759
+ scrollLeftRef.current = scrollLeft;
2760
+ const viewportWidth = el.clientWidth;
2761
+ const viewStart = scrollLeft;
2762
+ const viewEnd = scrollLeft + viewportWidth;
2763
+ let cumWidth = 0;
2764
+ let startIdx = -1;
2765
+ let endIdx = orderedColumns.length - 1;
2766
+ for (let i = 0; i < orderedColumns.length; i++) {
2767
+ const col = orderedColumns[i];
2768
+ const colWidth = col.width ?? 150;
2769
+ const colStart = cumWidth;
2770
+ const colEnd = cumWidth + colWidth;
2771
+ cumWidth = colEnd;
2772
+ if (col.pinned) continue;
2773
+ if (startIdx === -1 && colEnd > viewStart) {
2774
+ startIdx = Math.max(0, i - 1);
2775
+ }
2776
+ if (colStart > viewEnd) {
2777
+ endIdx = Math.min(orderedColumns.length - 1, i + 1);
2778
+ break;
2779
+ }
2780
+ }
2781
+ if (startIdx === -1) startIdx = 0;
2782
+ setVisibleColumnRange((prev) => {
2783
+ if (prev && prev.start === startIdx && prev.end === endIdx) return prev;
2784
+ return { start: startIdx, end: endIdx };
2785
+ });
2786
+ };
2787
+ updateVisibleColumns();
2788
+ el.addEventListener("scroll", updateVisibleColumns, { passive: true });
2789
+ return () => el.removeEventListener("scroll", updateVisibleColumns);
2790
+ }, [enableColumnVirtualization, orderedColumns]);
2791
+ const virtualizedColumns = useMemo2(() => {
2792
+ if (!enableColumnVirtualization || !visibleColumnRange)
2793
+ return freshOrderedColumns;
2794
+ return freshOrderedColumns.filter((col, idx) => {
2795
+ if (col.pinned) return true;
2796
+ if (col.key === "__select__" || col.key === "__expand__") return true;
2797
+ return idx >= visibleColumnRange.start && idx <= visibleColumnRange.end;
2798
+ });
2799
+ }, [enableColumnVirtualization, visibleColumnRange, freshOrderedColumns]);
2455
2800
  const resolvedExpandedKeysFingerprint = Array.from(resolvedExpandedKeys).sort().join(",");
2456
2801
  React4.useLayoutEffect(() => {
2457
2802
  rowVirtualizer.measure();
@@ -2518,7 +2863,10 @@ function BoltTable({
2518
2863
  }, [pgCurrent, needsClientPagination]);
2519
2864
  const getPageNumbers = () => {
2520
2865
  if (totalPages <= 7)
2521
- return Array.from({ length: totalPages }, (_, i) => i + 1);
2866
+ return Array.from(
2867
+ { length: totalPages },
2868
+ (_, i) => i + 1
2869
+ );
2522
2870
  const leftSibling = Math.max(currentPage - 1, 2);
2523
2871
  const showLeftEllipsis = leftSibling > 2;
2524
2872
  const rightSibling = Math.min(currentPage + 1, totalPages - 1);
@@ -2529,7 +2877,10 @@ function BoltTable({
2529
2877
  return [
2530
2878
  1,
2531
2879
  "ellipsis-left",
2532
- ...Array.from({ length: 5 }, (_, i) => totalPages - 4 + i)
2880
+ ...Array.from(
2881
+ { length: 5 },
2882
+ (_, i) => totalPages - 4 + i
2883
+ )
2533
2884
  ];
2534
2885
  return [
2535
2886
  1,
@@ -2600,6 +2951,190 @@ function BoltTable({
2600
2951
  }
2601
2952
  ${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
2602
2953
  ` }),
2954
+ (!hideGlobalSearch || showColumnSettings) && /* @__PURE__ */ jsxs5(
2955
+ "div",
2956
+ {
2957
+ style: {
2958
+ display: "flex",
2959
+ alignItems: "center",
2960
+ gap: 8,
2961
+ padding: "6px 8px",
2962
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2963
+ fontSize: 12,
2964
+ flexShrink: 0
2965
+ },
2966
+ children: [
2967
+ !hideGlobalSearch && /* @__PURE__ */ jsxs5(
2968
+ "div",
2969
+ {
2970
+ style: {
2971
+ display: "flex",
2972
+ alignItems: "center",
2973
+ gap: 4,
2974
+ flex: "1 1 0%",
2975
+ position: "relative"
2976
+ },
2977
+ children: [
2978
+ /* @__PURE__ */ jsx5(
2979
+ "span",
2980
+ {
2981
+ style: { display: "flex", color: "GrayText", flexShrink: 0 },
2982
+ children: icons?.search ?? /* @__PURE__ */ jsx5(SearchIcon, { style: { width: 14, height: 14 } })
2983
+ }
2984
+ ),
2985
+ /* @__PURE__ */ jsx5(
2986
+ "input",
2987
+ {
2988
+ type: "text",
2989
+ placeholder: "Search all columns...",
2990
+ value: globalSearchValue ?? internalGlobalSearch,
2991
+ onChange: (e) => {
2992
+ const v = e.target.value;
2993
+ if (onGlobalSearchChange) onGlobalSearchChange(v);
2994
+ else setInternalGlobalSearch(v);
2995
+ },
2996
+ style: {
2997
+ flex: "1 1 0%",
2998
+ border: "none",
2999
+ outline: "none",
3000
+ background: "transparent",
3001
+ font: "inherit",
3002
+ color: "inherit",
3003
+ padding: "4px 6px",
3004
+ minWidth: 0
3005
+ }
3006
+ }
3007
+ ),
3008
+ (globalSearchValue ?? internalGlobalSearch) && /* @__PURE__ */ jsx5(
3009
+ "button",
3010
+ {
3011
+ type: "button",
3012
+ onClick: () => {
3013
+ if (onGlobalSearchChange) onGlobalSearchChange("");
3014
+ else setInternalGlobalSearch("");
3015
+ },
3016
+ style: {
3017
+ display: "flex",
3018
+ alignItems: "center",
3019
+ justifyContent: "center",
3020
+ background: "none",
3021
+ border: "none",
3022
+ cursor: "pointer",
3023
+ padding: 2,
3024
+ color: "GrayText",
3025
+ flexShrink: 0
3026
+ },
3027
+ children: icons?.close ?? /* @__PURE__ */ jsx5(XIcon, { style: { width: 12, height: 12 } })
3028
+ }
3029
+ )
3030
+ ]
3031
+ }
3032
+ ),
3033
+ toolbarContent,
3034
+ showColumnSettings && /* @__PURE__ */ jsxs5("div", { style: { position: "relative", flexShrink: 0 }, children: [
3035
+ /* @__PURE__ */ jsxs5(
3036
+ "button",
3037
+ {
3038
+ type: "button",
3039
+ onClick: () => setShowColumnPicker((p) => !p),
3040
+ style: {
3041
+ display: "flex",
3042
+ alignItems: "center",
3043
+ justifyContent: "center",
3044
+ background: "none",
3045
+ border: "1px solid rgba(128,128,128,0.2)",
3046
+ borderRadius: 4,
3047
+ cursor: "pointer",
3048
+ padding: "4px 6px",
3049
+ color: "inherit",
3050
+ gap: 4,
3051
+ fontSize: 12
3052
+ },
3053
+ title: "Column settings",
3054
+ children: [
3055
+ icons?.columns ?? /* @__PURE__ */ jsx5(ColumnsIcon, { style: { width: 14, height: 14 } }),
3056
+ /* @__PURE__ */ jsx5("span", { children: columnSettingsLabel ?? "Columns" })
3057
+ ]
3058
+ }
3059
+ ),
3060
+ showColumnPicker && /* @__PURE__ */ jsx5(
3061
+ "div",
3062
+ {
3063
+ ref: columnPickerRef,
3064
+ style: {
3065
+ position: "absolute",
3066
+ top: "100%",
3067
+ right: 0,
3068
+ zIndex: 99999,
3069
+ minWidth: 200,
3070
+ maxHeight: 320,
3071
+ overflowY: "auto",
3072
+ borderRadius: 8,
3073
+ border: "1px solid rgba(128,128,128,0.2)",
3074
+ boxShadow: "0 4px 24px rgba(0,0,0,0.12)",
3075
+ backdropFilter: "blur(16px)",
3076
+ WebkitBackdropFilter: "blur(16px)",
3077
+ backgroundColor: "rgba(128,128,128,0.08)",
3078
+ padding: "4px 0",
3079
+ marginTop: 4
3080
+ },
3081
+ children: initialColumns.filter(
3082
+ (c) => c.key !== "__select__" && c.key !== "__expand__"
3083
+ ).map((col) => {
3084
+ const current = columns.find((c) => c.key === col.key);
3085
+ const isHidden = current?.hidden ?? false;
3086
+ const isPinned = !!current?.pinned;
3087
+ return /* @__PURE__ */ jsxs5(
3088
+ "label",
3089
+ {
3090
+ style: {
3091
+ display: "flex",
3092
+ alignItems: "center",
3093
+ gap: 8,
3094
+ padding: "6px 12px",
3095
+ cursor: isPinned ? "not-allowed" : "pointer",
3096
+ opacity: isPinned ? 0.5 : 1,
3097
+ fontSize: 12
3098
+ },
3099
+ children: [
3100
+ /* @__PURE__ */ jsx5(
3101
+ "input",
3102
+ {
3103
+ type: "checkbox",
3104
+ checked: !isHidden,
3105
+ disabled: isPinned,
3106
+ onChange: () => {
3107
+ if (isPinned) return;
3108
+ handleToggleHide(col.key);
3109
+ },
3110
+ style: {
3111
+ cursor: isPinned ? "not-allowed" : "pointer",
3112
+ accentColor
3113
+ }
3114
+ }
3115
+ ),
3116
+ /* @__PURE__ */ jsx5(
3117
+ "span",
3118
+ {
3119
+ style: {
3120
+ overflow: "hidden",
3121
+ textOverflow: "ellipsis",
3122
+ whiteSpace: "nowrap"
3123
+ },
3124
+ children: typeof col.title === "string" ? col.title : col.key
3125
+ }
3126
+ )
3127
+ ]
3128
+ },
3129
+ col.key
3130
+ );
3131
+ })
3132
+ }
3133
+ )
3134
+ ] })
3135
+ ]
3136
+ }
3137
+ ),
2603
3138
  /* @__PURE__ */ jsx5(
2604
3139
  "div",
2605
3140
  {
@@ -2744,19 +3279,20 @@ function BoltTable({
2744
3279
  ...isEmpty ? { height: "100%" } : {}
2745
3280
  },
2746
3281
  onContextMenu: (e) => {
2747
- const cell = e.target.closest("[data-bt-cell]");
3282
+ const cell = e.target.closest(
3283
+ "[data-bt-cell]"
3284
+ );
2748
3285
  if (!cell) return;
2749
3286
  const rk = cell.dataset.rowKey;
2750
3287
  const ck = cell.dataset.columnKey;
2751
3288
  if (!rk || !ck) return;
2752
- const col = freshOrderedColumns.find(
2753
- (c) => c.key === ck
2754
- );
3289
+ const col = freshOrderedColumns.find((c) => c.key === ck);
2755
3290
  const hasCopy = !!col?.copy;
2756
3291
  const hasRowPin = !!rowPinning;
2757
3292
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2758
3293
  const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2759
- if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
3294
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit)
3295
+ return;
2760
3296
  e.preventDefault();
2761
3297
  setCellContextMenu({
2762
3298
  x: Math.min(e.clientX, window.innerWidth - 200),
@@ -2767,7 +3303,9 @@ function BoltTable({
2767
3303
  },
2768
3304
  onTouchStart: (e) => {
2769
3305
  cancelCellLongPress();
2770
- const cell = e.target.closest("[data-bt-cell]");
3306
+ const cell = e.target.closest(
3307
+ "[data-bt-cell]"
3308
+ );
2771
3309
  if (!cell) return;
2772
3310
  const touch = e.touches[0];
2773
3311
  cellTouchStart.current = {
@@ -2779,14 +3317,13 @@ function BoltTable({
2779
3317
  cellLongPressTimer.current = setTimeout(() => {
2780
3318
  cellLongPressTimer.current = null;
2781
3319
  if (!rk || !ck) return;
2782
- const col = freshOrderedColumns.find(
2783
- (c) => c.key === ck
2784
- );
3320
+ const col = freshOrderedColumns.find((c) => c.key === ck);
2785
3321
  const hasCopy = !!col?.copy;
2786
3322
  const hasRowPin = !!rowPinning;
2787
3323
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2788
3324
  const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2789
- if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
3325
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit)
3326
+ return;
2790
3327
  setCellContextMenu({
2791
3328
  x: Math.min(touch.clientX, window.innerWidth - 200),
2792
3329
  y: Math.min(touch.clientY, window.innerHeight - 200),
@@ -2807,7 +3344,8 @@ function BoltTable({
2807
3344
  onTouchCancel: cancelCellLongPress,
2808
3345
  onClick: onRowClick ? (e) => {
2809
3346
  const target = e.target;
2810
- if (target.closest("input, button, a, select, textarea")) return;
3347
+ if (target.closest("input, button, a, select, textarea"))
3348
+ return;
2811
3349
  const cell = target.closest("[data-bt-cell]");
2812
3350
  if (!cell) return;
2813
3351
  const rk = cell.dataset.rowKey;
@@ -2815,21 +3353,21 @@ function BoltTable({
2815
3353
  for (let i = 0; i < displayData.length; i++) {
2816
3354
  const row = displayData[i];
2817
3355
  if (row == null) continue;
2818
- if (getRowKey(row, i) === rk) {
3356
+ if (getSafeRowKey(row, i) === rk) {
2819
3357
  onRowClick(row, i, e);
2820
3358
  return;
2821
3359
  }
2822
3360
  }
2823
3361
  for (let i = 0; i < pinnedTopRows.length; i++) {
2824
3362
  if (pinnedTopRows[i] == null) continue;
2825
- if (getRowKey(pinnedTopRows[i], i) === rk) {
3363
+ if (getSafeRowKey(pinnedTopRows[i], i) === rk) {
2826
3364
  onRowClick(pinnedTopRows[i], i, e);
2827
3365
  return;
2828
3366
  }
2829
3367
  }
2830
3368
  for (let i = 0; i < pinnedBottomRows.length; i++) {
2831
3369
  if (pinnedBottomRows[i] == null) continue;
2832
- if (getRowKey(pinnedBottomRows[i], i) === rk) {
3370
+ if (getSafeRowKey(pinnedBottomRows[i], i) === rk) {
2833
3371
  onRowClick(pinnedBottomRows[i], i, e);
2834
3372
  return;
2835
3373
  }
@@ -2939,7 +3477,11 @@ function BoltTable({
2939
3477
  });
2940
3478
  }
2941
3479
  },
2942
- style: { cursor: "pointer", accentColor, backgroundColor: "#94A3B8" }
3480
+ style: {
3481
+ cursor: "pointer",
3482
+ accentColor,
3483
+ backgroundColor: "#94A3B8"
3484
+ }
2943
3485
  }
2944
3486
  )
2945
3487
  },
@@ -2999,7 +3541,10 @@ function BoltTable({
2999
3541
  filterValue: columnFilters[column.key] ?? "",
3000
3542
  onFilter: handleColumnFilter,
3001
3543
  onClearFilter: handleClearFilter,
3002
- customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
3544
+ customContextMenuItems: column.columnHeaderContextMenuItems ? [
3545
+ ...columnContextMenuItems ?? [],
3546
+ ...column.columnHeaderContextMenuItems
3547
+ ] : columnContextMenuItems,
3003
3548
  disabledFilters,
3004
3549
  headerGridRow: leafGridRow,
3005
3550
  headerHeight: leafHeight,
@@ -3051,14 +3596,14 @@ function BoltTable({
3051
3596
  TableBody_default,
3052
3597
  {
3053
3598
  data: displayData,
3054
- orderedColumns: freshOrderedColumns,
3599
+ orderedColumns: virtualizedColumns,
3055
3600
  rowVirtualizer,
3056
3601
  columnOffsets,
3057
3602
  styles,
3058
3603
  classNames,
3059
3604
  rowSelection: !showShimmer ? rowSelection : void 0,
3060
3605
  normalizedSelectedKeys,
3061
- getRowKey,
3606
+ getRowKey: getSafeRowKey,
3062
3607
  getRawRowKey,
3063
3608
  expandable: !showShimmer ? expandable : void 0,
3064
3609
  resolvedExpandedKeys,
@@ -3079,7 +3624,10 @@ function BoltTable({
3079
3624
  bodyGridRow: hasColumnGroups ? 3 : 2,
3080
3625
  onEdit,
3081
3626
  editingCell,
3082
- onEditComplete: handleEditComplete
3627
+ onEditComplete: handleEditComplete,
3628
+ enableDynamicRowHeight,
3629
+ onRowHeightChange: handleRowHeightChange,
3630
+ columnGridIndexMap
3083
3631
  }
3084
3632
  )
3085
3633
  ]
@@ -3109,39 +3657,53 @@ function BoltTable({
3109
3657
  ...styles.pagination
3110
3658
  },
3111
3659
  children: [
3112
- /* @__PURE__ */ jsx5("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
3113
- const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
3114
- const rangeEnd = Math.min(currentPage * pageSize, total);
3115
- return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5(
3116
- "span",
3117
- {
3118
- className: classNames.paginationInfo ?? "",
3119
- style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3120
- children: [
3121
- "Showing",
3122
- " ",
3123
- pagination.showTotal(total, [rangeStart, rangeEnd]),
3124
- " of",
3125
- " ",
3126
- total,
3127
- " items"
3128
- ]
3129
- }
3130
- ) : /* @__PURE__ */ jsxs5(
3131
- "span",
3132
- {
3133
- className: classNames.paginationInfo ?? "",
3134
- style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3135
- children: [
3136
- rangeStart,
3137
- "\u2013",
3138
- rangeEnd,
3139
- " of ",
3140
- total
3141
- ]
3142
- }
3143
- );
3144
- })() }),
3660
+ /* @__PURE__ */ jsx5(
3661
+ "div",
3662
+ {
3663
+ style: { display: "flex", flex: "1 1 0%", alignItems: "center" },
3664
+ children: (() => {
3665
+ const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
3666
+ const rangeEnd = Math.min(currentPage * pageSize, total);
3667
+ return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5(
3668
+ "span",
3669
+ {
3670
+ className: classNames.paginationInfo ?? "",
3671
+ style: {
3672
+ color: "GrayText",
3673
+ fontSize: 12,
3674
+ ...styles.paginationInfo
3675
+ },
3676
+ children: [
3677
+ "Showing",
3678
+ " ",
3679
+ pagination.showTotal(total, [rangeStart, rangeEnd]),
3680
+ " of",
3681
+ " ",
3682
+ total,
3683
+ " items"
3684
+ ]
3685
+ }
3686
+ ) : /* @__PURE__ */ jsxs5(
3687
+ "span",
3688
+ {
3689
+ className: classNames.paginationInfo ?? "",
3690
+ style: {
3691
+ color: "GrayText",
3692
+ fontSize: 12,
3693
+ ...styles.paginationInfo
3694
+ },
3695
+ children: [
3696
+ rangeStart,
3697
+ "\u2013",
3698
+ rangeEnd,
3699
+ " of ",
3700
+ total
3701
+ ]
3702
+ }
3703
+ );
3704
+ })()
3705
+ }
3706
+ ),
3145
3707
  /* @__PURE__ */ jsxs5(
3146
3708
  "div",
3147
3709
  {
@@ -3424,9 +3986,7 @@ function BoltTable({
3424
3986
  (c) => c.key === cellContextMenu.columnKey
3425
3987
  );
3426
3988
  const isPinnedTop = pinnedTopKeySet.has(cellContextMenu.rowKey);
3427
- const isPinnedBottom = pinnedBottomKeySet.has(
3428
- cellContextMenu.rowKey
3429
- );
3989
+ const isPinnedBottom = pinnedBottomKeySet.has(cellContextMenu.rowKey);
3430
3990
  const hasCopy = !!menuCol?.copy;
3431
3991
  const hasRowPin = !!rowPinning;
3432
3992
  const hasEdit = !!menuCol?.editable && !menuCol?.render && !!onEdit;
@@ -3439,7 +3999,7 @@ function BoltTable({
3439
3999
  ];
3440
4000
  for (let i = 0; i < allRows.length; i++) {
3441
4001
  if (allRows[i] == null) continue;
3442
- const rk = getRowKey(allRows[i], i);
4002
+ const rk = getSafeRowKey(allRows[i], i);
3443
4003
  if (rk === cellContextMenu.rowKey) {
3444
4004
  menuRecord = allRows[i];
3445
4005
  menuRowIndex = i;
@@ -3641,7 +4201,20 @@ function BoltTable({
3641
4201
  setCellContextMenu(null);
3642
4202
  },
3643
4203
  children: [
3644
- item.icon && /* @__PURE__ */ jsx5("span", { style: { display: "flex", width: 14, height: 14, alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: item.icon }),
4204
+ item.icon && /* @__PURE__ */ jsx5(
4205
+ "span",
4206
+ {
4207
+ style: {
4208
+ display: "flex",
4209
+ width: 14,
4210
+ height: 14,
4211
+ alignItems: "center",
4212
+ justifyContent: "center",
4213
+ flexShrink: 0
4214
+ },
4215
+ children: item.icon
4216
+ }
4217
+ ),
3645
4218
  item.label
3646
4219
  ]
3647
4220
  },