bolt-table 0.1.19 → 0.1.21

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
@@ -872,6 +872,7 @@ var Cell = import_react3.default.memo(
872
872
  rowKey,
873
873
  allData,
874
874
  getRowKey,
875
+ getRawRowKey,
875
876
  accentColor,
876
877
  isLoading
877
878
  }) => {
@@ -914,6 +915,7 @@ var Cell = import_react3.default.memo(
914
915
  const checkboxProps = rowSelection.getCheckboxProps?.(record) ?? {
915
916
  disabled: false
916
917
  };
918
+ const rawKey = getRawRowKey ? getRawRowKey(record, rowIndex) : rowKey;
917
919
  const content2 = rowSelection.type === "radio" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
918
920
  "input",
919
921
  {
@@ -923,7 +925,7 @@ var Cell = import_react3.default.memo(
923
925
  onChange: (e) => {
924
926
  e.stopPropagation();
925
927
  rowSelection.onSelect?.(record, true, [record], e.nativeEvent);
926
- rowSelection.onChange?.([rowKey], [record], { type: "single" });
928
+ rowSelection.onChange?.([rawKey], [record], { type: "single" });
927
929
  },
928
930
  style: { cursor: "pointer", accentColor }
929
931
  }
@@ -935,15 +937,12 @@ var Cell = import_react3.default.memo(
935
937
  disabled: checkboxProps.disabled,
936
938
  onChange: (e) => {
937
939
  e.stopPropagation();
938
- const currentKeys = (rowSelection.selectedRowKeys ?? []).map(
939
- (k) => String(k)
940
- );
941
- const newSelected = isSelected ? currentKeys.filter((k) => k !== rowKey) : [...currentKeys, rowKey];
942
- const newSelectedRows = (allData ?? []).filter(
943
- (row, idx) => newSelected.includes(
944
- getRowKey ? getRowKey(row, idx) : String(idx)
945
- )
946
- );
940
+ const currentKeys = rowSelection.selectedRowKeys ?? [];
941
+ const newSelected = isSelected ? currentKeys.filter((k) => String(k) !== rowKey) : [...currentKeys, rawKey];
942
+ const newSelectedRows = (allData ?? []).filter((row, idx) => {
943
+ const rk = getRowKey ? getRowKey(row, idx) : String(idx);
944
+ return newSelected.some((k) => String(k) === rk);
945
+ });
947
946
  rowSelection.onSelect?.(
948
947
  record,
949
948
  !isSelected,
@@ -979,7 +978,16 @@ var Cell = import_react3.default.memo(
979
978
  }
980
979
  );
981
980
  }
982
- const content = column.render ? column.render(value, record, rowIndex) : value ?? "";
981
+ let content;
982
+ if (column.render) {
983
+ try {
984
+ content = column.render(value, record, rowIndex);
985
+ } catch {
986
+ content = String(value ?? "");
987
+ }
988
+ } else {
989
+ content = value ?? "";
990
+ }
983
991
  const isSystem = column.key === "__select__" || column.key === "__expand__";
984
992
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
985
993
  "div",
@@ -1073,6 +1081,7 @@ var TableBody = ({
1073
1081
  rowSelection,
1074
1082
  normalizedSelectedKeys = [],
1075
1083
  getRowKey,
1084
+ getRawRowKey,
1076
1085
  expandable,
1077
1086
  resolvedExpandedKeys,
1078
1087
  rowHeight = 40,
@@ -1092,14 +1101,16 @@ var TableBody = ({
1092
1101
  const virtualItems = rowVirtualizer.getVirtualItems();
1093
1102
  const totalSize = rowVirtualizer.getTotalSize();
1094
1103
  const selectedKeySet = (0, import_react3.useMemo)(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
1104
+ const safeData = data ?? [];
1105
+ const safeColumns = orderedColumns ?? [];
1095
1106
  const allDataForSelection = (0, import_react3.useMemo)(() => {
1096
1107
  if (pinnedTopData.length === 0 && pinnedBottomData.length === 0)
1097
- return data;
1098
- return [...pinnedTopData, ...data, ...pinnedBottomData];
1099
- }, [pinnedTopData, data, pinnedBottomData]);
1108
+ return safeData;
1109
+ return [...pinnedTopData, ...safeData, ...pinnedBottomData];
1110
+ }, [pinnedTopData, safeData, pinnedBottomData]);
1100
1111
  const pinnedRowBg = styles?.pinnedRowBg ?? styles?.pinnedBg;
1101
1112
  const columnStyles = (0, import_react3.useMemo)(() => {
1102
- return orderedColumns.map((col, colIndex) => {
1113
+ return safeColumns.map((col, colIndex) => {
1103
1114
  const stickyOffset = columnOffsets.get(col.key);
1104
1115
  const isPinned = Boolean(col.pinned);
1105
1116
  let zIndex = 0;
@@ -1121,10 +1132,12 @@ var TableBody = ({
1121
1132
  }
1122
1133
  return { key: col.key, style, isPinned };
1123
1134
  });
1124
- }, [orderedColumns, columnOffsets, totalSize, styles]);
1135
+ }, [safeColumns, columnOffsets, totalSize, styles]);
1136
+ if (safeData.length === 0 || safeColumns.length === 0) return null;
1125
1137
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1126
1138
  columnStyles.map((colStyle, colIndex) => {
1127
- const col = orderedColumns[colIndex];
1139
+ const col = safeColumns[colIndex];
1140
+ if (!col) return null;
1128
1141
  const hasRender = !!col.render;
1129
1142
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1130
1143
  "div",
@@ -1132,15 +1145,31 @@ var TableBody = ({
1132
1145
  ...colStyle.isPinned ? { "data-bt-pinned": "" } : {},
1133
1146
  style: colStyle.style,
1134
1147
  children: virtualItems.map((virtualRow) => {
1135
- const row = data[virtualRow.index];
1148
+ const row = safeData[virtualRow.index];
1149
+ if (row == null) return null;
1136
1150
  const rowKey = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
1137
1151
  const isSelected = selectedKeySet.has(rowKey);
1138
1152
  const isExpanded = resolvedExpandedKeys?.has(rowKey) ?? false;
1139
1153
  const cellValue = row[col.dataIndex];
1140
1154
  const isRowShimmer = isLoading || rowKey.startsWith("__shimmer_");
1141
- const recordFingerprint = hasRender && !isRowShimmer ? JSON.stringify(row) : void 0;
1142
- const rowCls = rowClassName ? rowClassName(row, virtualRow.index) : "";
1143
- const rowSty = rowStyle ? rowStyle(row, virtualRow.index) : void 0;
1155
+ let recordFingerprint;
1156
+ if (hasRender && !isRowShimmer) {
1157
+ try {
1158
+ recordFingerprint = JSON.stringify(row);
1159
+ } catch {
1160
+ recordFingerprint = rowKey;
1161
+ }
1162
+ }
1163
+ let rowCls = "";
1164
+ try {
1165
+ rowCls = rowClassName ? rowClassName(row, virtualRow.index) : "";
1166
+ } catch {
1167
+ }
1168
+ let rowSty;
1169
+ try {
1170
+ rowSty = rowStyle ? rowStyle(row, virtualRow.index) : void 0;
1171
+ } catch {
1172
+ }
1144
1173
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1145
1174
  "div",
1146
1175
  {
@@ -1180,6 +1209,7 @@ var TableBody = ({
1180
1209
  rowKey,
1181
1210
  allData: allDataForSelection,
1182
1211
  getRowKey,
1212
+ getRawRowKey,
1183
1213
  accentColor,
1184
1214
  isLoading: isRowShimmer,
1185
1215
  recordFingerprint
@@ -1207,9 +1237,15 @@ var TableBody = ({
1207
1237
  pointerEvents: "none"
1208
1238
  },
1209
1239
  children: virtualItems.map((virtualRow) => {
1210
- const row = data[virtualRow.index];
1240
+ const row = safeData[virtualRow.index];
1241
+ if (row == null) return null;
1211
1242
  const rk = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
1212
1243
  if (!(resolvedExpandedKeys?.has(rk) ?? false)) return null;
1244
+ let expandedRenderResult = null;
1245
+ try {
1246
+ expandedRenderResult = expandable.expandedRowRender(row, virtualRow.index, 0, true);
1247
+ } catch {
1248
+ }
1213
1249
  const expandedContent = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1214
1250
  "div",
1215
1251
  {
@@ -1227,7 +1263,7 @@ var TableBody = ({
1227
1263
  ...maxExpandedRowHeight ? { maxHeight: `${maxExpandedRowHeight}px` } : void 0,
1228
1264
  ...styles?.expandedRow
1229
1265
  },
1230
- children: expandable.expandedRowRender(row, virtualRow.index, 0, true)
1266
+ children: expandedRenderResult
1231
1267
  }
1232
1268
  );
1233
1269
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -1274,11 +1310,20 @@ var TableBody = ({
1274
1310
  boxShadow: "0 2px 6px -1px rgba(0,0,0,0.08)"
1275
1311
  },
1276
1312
  children: pinnedTopData.map((row, rowIdx) => {
1313
+ if (row == null) return null;
1277
1314
  const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
1278
1315
  const isSelected = selectedKeySet.has(rk);
1279
1316
  const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
1280
- const rowCls = rowClassName ? rowClassName(row, rowIdx) : "";
1281
- const rowSty = rowStyle ? rowStyle(row, rowIdx) : void 0;
1317
+ let rowCls = "";
1318
+ try {
1319
+ rowCls = rowClassName ? rowClassName(row, rowIdx) : "";
1320
+ } catch {
1321
+ }
1322
+ let rowSty;
1323
+ try {
1324
+ rowSty = rowStyle ? rowStyle(row, rowIdx) : void 0;
1325
+ } catch {
1326
+ }
1282
1327
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1283
1328
  "div",
1284
1329
  {
@@ -1290,7 +1335,7 @@ var TableBody = ({
1290
1335
  ...styles?.pinnedRow,
1291
1336
  ...rowSty
1292
1337
  },
1293
- children: orderedColumns.map((col) => {
1338
+ children: safeColumns.map((col) => {
1294
1339
  const cellValue = row[col.dataIndex];
1295
1340
  const stickyOffset = columnOffsets.get(col.key);
1296
1341
  const isPinned = Boolean(col.pinned);
@@ -1298,7 +1343,14 @@ var TableBody = ({
1298
1343
  if (col.key === "__select__" || col.key === "__expand__")
1299
1344
  zIndex = 11;
1300
1345
  else if (isPinned) zIndex = 2;
1301
- const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
1346
+ let recordFingerprint;
1347
+ if (col.render) {
1348
+ try {
1349
+ recordFingerprint = JSON.stringify(row);
1350
+ } catch {
1351
+ recordFingerprint = rk;
1352
+ }
1353
+ }
1302
1354
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1303
1355
  "div",
1304
1356
  {
@@ -1339,6 +1391,7 @@ var TableBody = ({
1339
1391
  rowKey: rk,
1340
1392
  allData: allDataForSelection,
1341
1393
  getRowKey,
1394
+ getRawRowKey,
1342
1395
  accentColor,
1343
1396
  isLoading: false,
1344
1397
  recordFingerprint
@@ -1382,11 +1435,20 @@ var TableBody = ({
1382
1435
  boxShadow: "0 -2px 6px -1px rgba(0,0,0,0.08)"
1383
1436
  },
1384
1437
  children: pinnedBottomData.map((row, rowIdx) => {
1438
+ if (row == null) return null;
1385
1439
  const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
1386
1440
  const isSelected = selectedKeySet.has(rk);
1387
1441
  const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
1388
- const rowCls = rowClassName ? rowClassName(row, rowIdx) : "";
1389
- const rowSty = rowStyle ? rowStyle(row, rowIdx) : void 0;
1442
+ let rowCls = "";
1443
+ try {
1444
+ rowCls = rowClassName ? rowClassName(row, rowIdx) : "";
1445
+ } catch {
1446
+ }
1447
+ let rowSty;
1448
+ try {
1449
+ rowSty = rowStyle ? rowStyle(row, rowIdx) : void 0;
1450
+ } catch {
1451
+ }
1390
1452
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1391
1453
  "div",
1392
1454
  {
@@ -1398,7 +1460,7 @@ var TableBody = ({
1398
1460
  ...styles?.pinnedRow,
1399
1461
  ...rowSty
1400
1462
  },
1401
- children: orderedColumns.map((col) => {
1463
+ children: safeColumns.map((col) => {
1402
1464
  const cellValue = row[col.dataIndex];
1403
1465
  const stickyOffset = columnOffsets.get(col.key);
1404
1466
  const isPinned = Boolean(col.pinned);
@@ -1406,7 +1468,14 @@ var TableBody = ({
1406
1468
  if (col.key === "__select__" || col.key === "__expand__")
1407
1469
  zIndex = 11;
1408
1470
  else if (isPinned) zIndex = 2;
1409
- const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
1471
+ let recordFingerprint;
1472
+ if (col.render) {
1473
+ try {
1474
+ recordFingerprint = JSON.stringify(row);
1475
+ } catch {
1476
+ recordFingerprint = rk;
1477
+ }
1478
+ }
1410
1479
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1411
1480
  "div",
1412
1481
  {
@@ -1447,6 +1516,7 @@ var TableBody = ({
1447
1516
  rowKey: rk,
1448
1517
  allData: allDataForSelection,
1449
1518
  getRowKey,
1519
+ getRawRowKey,
1450
1520
  accentColor,
1451
1521
  isLoading: false,
1452
1522
  recordFingerprint
@@ -1482,9 +1552,11 @@ function arrayMove(arr, from, to) {
1482
1552
  var SHIMMER_WIDTHS2 = [55, 70, 45, 80, 60, 50, 75, 65, 40, 72];
1483
1553
  var EMPTY_CLASSNAMES = {};
1484
1554
  var EMPTY_STYLES = {};
1555
+ var STABLE_EMPTY_DATA = [];
1556
+ var STABLE_EMPTY_COLS = [];
1485
1557
  function BoltTable({
1486
- columns: initialColumns,
1487
- data,
1558
+ columns: rawInitialColumns,
1559
+ data: rawData,
1488
1560
  rowHeight = 40,
1489
1561
  expandedRowHeight = 200,
1490
1562
  maxExpandedRowHeight,
@@ -1518,6 +1590,18 @@ function BoltTable({
1518
1590
  rowClassName,
1519
1591
  rowStyle
1520
1592
  }) {
1593
+ const data = (0, import_react4.useMemo)(() => {
1594
+ if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
1595
+ const filtered = rawData.filter((item) => item != null);
1596
+ return filtered.length > 0 ? filtered : STABLE_EMPTY_DATA;
1597
+ }, [rawData]);
1598
+ const initialColumns = (0, import_react4.useMemo)(() => {
1599
+ if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1600
+ const filtered = rawInitialColumns.filter(
1601
+ (col) => col != null && typeof col.key === "string"
1602
+ );
1603
+ return filtered.length > 0 ? filtered : STABLE_EMPTY_COLS;
1604
+ }, [rawInitialColumns]);
1521
1605
  const [columns, setColumns] = (0, import_react4.useState)(initialColumns);
1522
1606
  const [columnOrder, setColumnOrder] = (0, import_react4.useState)(
1523
1607
  () => initialColumns.map((c) => c.key)
@@ -1553,10 +1637,15 @@ function BoltTable({
1553
1637
  [columns, columnWidths]
1554
1638
  );
1555
1639
  const [internalExpandedKeys, setInternalExpandedKeys] = (0, import_react4.useState)(() => {
1556
- if (expandable?.defaultExpandAllRows) {
1640
+ if (expandable?.defaultExpandAllRows && data.length > 0) {
1557
1641
  return new Set(
1558
1642
  data.map((row, idx) => {
1559
- if (typeof rowKey === "function") return rowKey(row);
1643
+ if (row == null) return idx;
1644
+ try {
1645
+ if (typeof rowKey === "function") return rowKey(row);
1646
+ } catch {
1647
+ return idx;
1648
+ }
1560
1649
  if (typeof rowKey === "string")
1561
1650
  return row[rowKey] ?? idx;
1562
1651
  return idx;
@@ -1590,21 +1679,56 @@ function BoltTable({
1590
1679
  }, []);
1591
1680
  const getRowKey = (0, import_react4.useCallback)(
1592
1681
  (record, index) => {
1593
- if (typeof rowKey === "function") return String(rowKey(record));
1594
- if (typeof rowKey === "string") {
1595
- const val = record[rowKey];
1596
- return val !== void 0 && val !== null ? String(val) : String(index);
1682
+ if (record == null) return String(index);
1683
+ try {
1684
+ if (typeof rowKey === "function") return String(rowKey(record));
1685
+ if (typeof rowKey === "string") {
1686
+ const val = record[rowKey];
1687
+ return val != null ? String(val) : String(index);
1688
+ }
1689
+ } catch {
1690
+ return String(index);
1597
1691
  }
1598
1692
  return String(index);
1599
1693
  },
1600
1694
  [rowKey]
1601
1695
  );
1696
+ const getRawRowKey = (0, import_react4.useCallback)(
1697
+ (record, index) => {
1698
+ if (record == null) return index;
1699
+ try {
1700
+ if (typeof rowKey === "function") return rowKey(record);
1701
+ if (typeof rowKey === "string") {
1702
+ const val = record[rowKey];
1703
+ if (typeof val === "number" || typeof val === "string") return val;
1704
+ return val != null ? String(val) : index;
1705
+ }
1706
+ } catch {
1707
+ return index;
1708
+ }
1709
+ return index;
1710
+ },
1711
+ [rowKey]
1712
+ );
1602
1713
  const normalizedSelectedKeys = (0, import_react4.useMemo)(
1603
- () => (rowSelection?.selectedRowKeys ?? []).map((k) => String(k)),
1714
+ () => {
1715
+ const keys = rowSelection?.selectedRowKeys;
1716
+ if (!Array.isArray(keys)) return [];
1717
+ return keys.filter((k) => k != null).map((k) => String(k));
1718
+ },
1604
1719
  [rowSelection?.selectedRowKeys]
1605
1720
  );
1721
+ const getRowKeyRef = (0, import_react4.useRef)(getRowKey);
1722
+ getRowKeyRef.current = getRowKey;
1723
+ const resolvedExpandedKeysRef = (0, import_react4.useRef)(resolvedExpandedKeys);
1724
+ resolvedExpandedKeysRef.current = resolvedExpandedKeys;
1725
+ const toggleExpandRef = (0, import_react4.useRef)(toggleExpand);
1726
+ toggleExpandRef.current = toggleExpand;
1727
+ const iconsRef = (0, import_react4.useRef)(icons);
1728
+ iconsRef.current = icons;
1729
+ const hasExpandable = !!expandable?.rowExpandable;
1606
1730
  const columnsWithExpand = (0, import_react4.useMemo)(() => {
1607
- if (!expandable?.rowExpandable) return columnsWithPersistedWidths;
1731
+ if (!hasExpandable) return columnsWithPersistedWidths;
1608
1732
  const expandColumn = {
1609
1733
  key: "__expand__",
1610
1734
  dataIndex: "__expand__",
@@ -1613,17 +1737,17 @@ function BoltTable({
1613
1737
  pinned: "left",
1614
1738
  hidden: false,
1615
1739
  render: (_, record, index) => {
1616
- const key = getRowKey(record, index);
1617
- const canExpand = expandable.rowExpandable?.(record) ?? true;
1618
- const isExpanded = resolvedExpandedKeys.has(key);
1740
+ const key = getRowKeyRef.current(record, index);
1741
+ const canExpand = expandableRef.current?.rowExpandable?.(record) ?? true;
1742
+ const isExpanded = resolvedExpandedKeysRef.current.has(key);
1619
1743
  if (!canExpand)
1620
1744
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { display: "inline-block", width: 16 } });
1621
- if (typeof expandable.expandIcon === "function") {
1622
- return expandable.expandIcon({
1745
+ if (typeof expandableRef.current?.expandIcon === "function") {
1746
+ return expandableRef.current.expandIcon({
1623
1747
  expanded: isExpanded,
1624
1748
  onExpand: (_2, e) => {
1625
1749
  e.stopPropagation();
1626
- toggleExpand(key);
1750
+ toggleExpandRef.current(key);
1627
1751
  },
1628
1752
  record
1629
1753
  });
@@ -1633,7 +1757,7 @@ function BoltTable({
1633
1757
  {
1634
1758
  onClick: (e) => {
1635
1759
  e.stopPropagation();
1636
- toggleExpand(key);
1760
+ toggleExpandRef.current(key);
1637
1761
  },
1638
1762
  style: {
1639
1763
  display: "flex",
@@ -1646,20 +1770,13 @@ function BoltTable({
1646
1770
  borderRadius: "3px",
1647
1771
  color: accentColor
1648
1772
  },
1649
- children: isExpanded ? icons?.chevronDown ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronDownIcon, { style: { width: 14, height: 14 } }) : icons?.chevronRight ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronRightIcon, { style: { width: 14, height: 14 } })
1773
+ children: isExpanded ? iconsRef.current?.chevronDown ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronDownIcon, { style: { width: 14, height: 14 } }) : iconsRef.current?.chevronRight ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronRightIcon, { style: { width: 14, height: 14 } })
1650
1774
  }
1651
1775
  );
1652
1776
  }
1653
1777
  };
1654
1778
  return [expandColumn, ...columnsWithPersistedWidths];
1655
- }, [
1656
- expandable,
1657
- columnsWithPersistedWidths,
1658
- getRowKey,
1659
- resolvedExpandedKeys,
1660
- toggleExpand,
1661
- accentColor
1662
- ]);
1779
+ }, [hasExpandable, columnsWithPersistedWidths, accentColor]);
1663
1780
  const columnsWithSelection = (0, import_react4.useMemo)(() => {
1664
1781
  if (!rowSelection) return columnsWithExpand;
1665
1782
  const selectionColumn = {
@@ -2019,36 +2136,52 @@ function BoltTable({
2019
2136
  if (!onFilterChangeRef.current) {
2020
2137
  const filterKeys = Object.keys(columnFilters);
2021
2138
  if (filterKeys.length > 0) {
2022
- result = result.filter(
2023
- (row) => filterKeys.every((key) => {
2024
- const col = columnsLookupRef.current.find((c) => c.key === key);
2025
- if (typeof col?.filterFn === "function") {
2026
- return col.filterFn(columnFilters[key], row, col.dataIndex);
2139
+ result = result.filter((row) => {
2140
+ if (row == null) return false;
2141
+ return filterKeys.every((key) => {
2142
+ try {
2143
+ const col = columnsLookupRef.current.find((c) => c.key === key);
2144
+ if (typeof col?.filterFn === "function") {
2145
+ return col.filterFn(columnFilters[key], row, col.dataIndex);
2146
+ }
2147
+ const cellVal = String(row[key] ?? "").toLowerCase();
2148
+ return cellVal.includes(columnFilters[key].toLowerCase());
2149
+ } catch {
2150
+ return true;
2027
2151
  }
2028
- const cellVal = String(row[key] ?? "").toLowerCase();
2029
- return cellVal.includes(columnFilters[key].toLowerCase());
2030
- })
2031
- );
2152
+ });
2153
+ });
2032
2154
  }
2033
2155
  }
2034
2156
  if (!onSortChangeRef.current && sortState.key && sortState.direction) {
2035
2157
  const dir = sortState.direction === "asc" ? 1 : -1;
2036
2158
  const key = sortState.key;
2037
2159
  const col = columnsLookupRef.current.find((c) => c.key === key);
2038
- if (typeof col?.sorter === "function") {
2039
- const sorterFn = col.sorter;
2040
- result = [...result].sort((a, b) => sorterFn(a, b) * dir);
2041
- } else {
2042
- result = [...result].sort((a, b) => {
2043
- const aVal = a[key];
2044
- const bVal = b[key];
2045
- if (aVal == null && bVal == null) return 0;
2046
- if (aVal == null) return 1;
2047
- if (bVal == null) return -1;
2048
- if (typeof aVal === "number" && typeof bVal === "number")
2049
- return (aVal - bVal) * dir;
2050
- return String(aVal).localeCompare(String(bVal)) * dir;
2051
- });
2160
+ try {
2161
+ if (typeof col?.sorter === "function") {
2162
+ const sorterFn = col.sorter;
2163
+ result = [...result].sort((a, b) => {
2164
+ if (a == null && b == null) return 0;
2165
+ if (a == null) return 1;
2166
+ if (b == null) return -1;
2167
+ return sorterFn(a, b) * dir;
2168
+ });
2169
+ } else {
2170
+ result = [...result].sort((a, b) => {
2171
+ if (a == null && b == null) return 0;
2172
+ if (a == null) return 1;
2173
+ if (b == null) return -1;
2174
+ const aVal = a[key];
2175
+ const bVal = b[key];
2176
+ if (aVal == null && bVal == null) return 0;
2177
+ if (aVal == null) return 1;
2178
+ if (bVal == null) return -1;
2179
+ if (typeof aVal === "number" && typeof bVal === "number")
2180
+ return (aVal - bVal) * dir;
2181
+ return String(aVal).localeCompare(String(bVal)) * dir;
2182
+ });
2183
+ }
2184
+ } catch {
2052
2185
  }
2053
2186
  }
2054
2187
  return result;
@@ -2067,6 +2200,7 @@ function BoltTable({
2067
2200
  const bottomMap = /* @__PURE__ */ new Map();
2068
2201
  const rest = [];
2069
2202
  processedData.forEach((row, idx) => {
2203
+ if (row == null) return;
2070
2204
  const key = getRowKey(row, idx);
2071
2205
  if (topKeySet.has(key)) topMap.set(key, row);
2072
2206
  else if (bottomKeySet.has(key)) bottomMap.set(key, row);
@@ -2128,7 +2262,8 @@ function BoltTable({
2128
2262
  const DEFAULT_PAGE_SIZE = 15;
2129
2263
  const [internalPage, setInternalPage] = (0, import_react4.useState)(1);
2130
2264
  const [internalPageSize, setInternalPageSize] = (0, import_react4.useState)(DEFAULT_PAGE_SIZE);
2131
- const autoPagination = pagination === void 0 && data.length > DEFAULT_PAGE_SIZE;
2265
+ const dataLength = data.length;
2266
+ const autoPagination = pagination === void 0 && dataLength > DEFAULT_PAGE_SIZE;
2132
2267
  const pgEnabled = pagination === false ? false : !!pagination || autoPagination;
2133
2268
  const pgSize = pgEnabled && typeof pagination === "object" && pagination?.pageSize !== void 0 ? pagination.pageSize : internalPageSize;
2134
2269
  const isControlledPagination = typeof pagination === "object" && pagination?.current !== void 0;
@@ -2141,26 +2276,27 @@ function BoltTable({
2141
2276
  }, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
2142
2277
  const shimmerCount = pgEnabled ? pgSize : 15;
2143
2278
  const showShimmer = isLoading && processedData.length === 0;
2279
+ const shimmerRowKeyField = typeof rowKey === "string" ? rowKey : "id";
2144
2280
  const shimmerData = (0, import_react4.useMemo)(() => {
2145
2281
  if (!showShimmer) return null;
2146
2282
  return Array.from(
2147
2283
  { length: shimmerCount },
2148
2284
  (_, i) => ({
2149
- [typeof rowKey === "string" ? rowKey : "id"]: `__shimmer_${i}__`
2285
+ [shimmerRowKeyField]: `__shimmer_${i}__`
2150
2286
  })
2151
2287
  );
2152
- }, [showShimmer, shimmerCount, rowKey]);
2288
+ }, [showShimmer, shimmerCount, shimmerRowKeyField]);
2153
2289
  const INFINITE_SHIMMER_COUNT = 5;
2290
+ const showInfiniteShimmer = isLoading && paginatedData.length > 0 && !showShimmer && !pgEnabled;
2154
2291
  const infiniteLoadingShimmer = (0, import_react4.useMemo)(() => {
2155
- if (!isLoading || paginatedData.length === 0 || showShimmer) return null;
2156
- if (pgEnabled) return null;
2292
+ if (!showInfiniteShimmer) return null;
2157
2293
  return Array.from(
2158
2294
  { length: INFINITE_SHIMMER_COUNT },
2159
2295
  (_, i) => ({
2160
- [typeof rowKey === "string" ? rowKey : "id"]: `__shimmer_${i}__`
2296
+ [shimmerRowKeyField]: `__shimmer_${i}__`
2161
2297
  })
2162
2298
  );
2163
- }, [isLoading, paginatedData.length, showShimmer, pgEnabled, rowKey]);
2299
+ }, [showInfiniteShimmer, shimmerRowKeyField]);
2164
2300
  const displayData = (0, import_react4.useMemo)(() => {
2165
2301
  if (shimmerData) return shimmerData;
2166
2302
  if (infiniteLoadingShimmer)
@@ -2190,13 +2326,20 @@ function BoltTable({
2190
2326
  getScrollElement: () => tableAreaRef.current,
2191
2327
  estimateSize: (index) => {
2192
2328
  if (shimmerData) return rowHeight;
2193
- const key = getRowKey(displayData[index], index);
2329
+ const item = displayData[index];
2330
+ if (!item) return rowHeight;
2331
+ const key = getRowKey(item, index);
2194
2332
  if (!resolvedExpandedKeys.has(key)) return rowHeight;
2195
2333
  const cached = measuredExpandedHeights.current.get(key);
2196
2334
  return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
2197
2335
  },
2198
2336
  overscan: 5,
2199
- getItemKey: (index) => shimmerData ? `__shimmer_${index}__` : getRowKey(displayData[index], index),
2337
+ getItemKey: (index) => {
2338
+ if (shimmerData) return `__shimmer_${index}__`;
2339
+ const item = displayData[index];
2340
+ if (!item) return `__fallback_${index}__`;
2341
+ return getRowKey(item, index);
2342
+ },
2200
2343
  paddingStart: pinnedTopHeight,
2201
2344
  paddingEnd: pinnedBottomHeight
2202
2345
  });
@@ -2216,7 +2359,7 @@ function BoltTable({
2216
2359
  endReachedFiredRef.current = false;
2217
2360
  }, 200);
2218
2361
  return () => clearTimeout(timer);
2219
- }, [data.length, isLoading]);
2362
+ }, [dataLength, isLoading]);
2220
2363
  import_react4.default.useEffect(() => {
2221
2364
  const el = tableAreaRef.current;
2222
2365
  if (!el) return;
@@ -2238,7 +2381,7 @@ function BoltTable({
2238
2381
  const activeColumn = activeId ? orderedColumns.find((col) => col.key === activeId) : null;
2239
2382
  const currentPage = pgCurrent;
2240
2383
  const pageSize = pgSize;
2241
- const rawTotal = pgEnabled ? (typeof pagination === "object" ? pagination?.total : void 0) ?? (needsClientPagination ? unpinnedProcessedData.length : data.length) : data.length;
2384
+ const rawTotal = pgEnabled ? (typeof pagination === "object" ? pagination?.total : void 0) ?? (needsClientPagination ? unpinnedProcessedData.length : dataLength) : dataLength;
2242
2385
  const lastKnownTotalRef = (0, import_react4.useRef)(0);
2243
2386
  if (!isLoading || rawTotal > 0) {
2244
2387
  lastKnownTotalRef.current = rawTotal;
@@ -2246,8 +2389,8 @@ function BoltTable({
2246
2389
  const total = isLoading && lastKnownTotalRef.current > 0 ? lastKnownTotalRef.current : rawTotal;
2247
2390
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
2248
2391
  import_react4.default.useEffect(() => {
2249
- if (internalPage > totalPages) {
2250
- setInternalPage(Math.max(1, totalPages));
2392
+ if (totalPages > 0 && internalPage > totalPages) {
2393
+ setInternalPage(totalPages);
2251
2394
  }
2252
2395
  }, [totalPages, internalPage]);
2253
2396
  const handlePageChange = (p) => {
@@ -2582,16 +2725,16 @@ function BoltTable({
2582
2725
  "input",
2583
2726
  {
2584
2727
  type: "checkbox",
2585
- checked: data.length > 0 && normalizedSelectedKeys.length === data.length,
2728
+ checked: dataLength > 0 && normalizedSelectedKeys.length === dataLength,
2586
2729
  ref: (input) => {
2587
2730
  if (input) {
2588
- input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < data.length;
2731
+ input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < dataLength;
2589
2732
  }
2590
2733
  },
2591
2734
  onChange: (e) => {
2592
2735
  if (e.target.checked) {
2593
2736
  const allKeys = data.map(
2594
- (row, idx) => getRowKey(row, idx)
2737
+ (row, idx) => getRawRowKey(row, idx)
2595
2738
  );
2596
2739
  rowSelection.onSelectAll?.(
2597
2740
  true,
@@ -2720,6 +2863,7 @@ function BoltTable({
2720
2863
  rowSelection: !showShimmer ? rowSelection : void 0,
2721
2864
  normalizedSelectedKeys,
2722
2865
  getRowKey,
2866
+ getRawRowKey,
2723
2867
  expandable: !showShimmer ? expandable : void 0,
2724
2868
  resolvedExpandedKeys,
2725
2869
  rowHeight,
@@ -3058,6 +3202,7 @@ function BoltTable({
3058
3202
  ...pinnedBottomRows
3059
3203
  ];
3060
3204
  for (let i = 0; i < allRows.length; i++) {
3205
+ if (allRows[i] == null) continue;
3061
3206
  const rk = getRowKey(allRows[i], i);
3062
3207
  if (rk === cellContextMenu.rowKey) {
3063
3208
  menuRecord = allRows[i];