bolt-table 0.1.11 → 0.1.13

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
@@ -952,7 +952,9 @@ var Cell = React3.memo(
952
952
  return prev.isExpanded === next.isExpanded;
953
953
  }
954
954
  if (prev.column.render) {
955
- return prev.record === next.record && prev.rowIndex === next.rowIndex;
955
+ if (prev.recordFingerprint !== next.recordFingerprint) return false;
956
+ if (prev.rowIndex !== next.rowIndex) return false;
957
+ return prev.column.render === next.column.render;
956
958
  }
957
959
  return prev.value === next.value && prev.rowIndex === next.rowIndex && prev.column.key === next.column.key;
958
960
  }
@@ -998,15 +1000,26 @@ var TableBody = ({
998
1000
  expandable,
999
1001
  resolvedExpandedKeys,
1000
1002
  rowHeight = 40,
1003
+ totalTableWidth,
1001
1004
  scrollAreaWidth,
1002
1005
  accentColor,
1003
1006
  isLoading = false,
1004
1007
  onExpandedRowResize,
1005
- maxExpandedRowHeight
1008
+ maxExpandedRowHeight,
1009
+ pinnedTopData = [],
1010
+ pinnedBottomData = [],
1011
+ gridTemplateColumns,
1012
+ headerHeight = 36
1006
1013
  }) => {
1007
1014
  const virtualItems = rowVirtualizer.getVirtualItems();
1008
1015
  const totalSize = rowVirtualizer.getTotalSize();
1009
1016
  const selectedKeySet = useMemo(() => new Set(normalizedSelectedKeys), [normalizedSelectedKeys]);
1017
+ const allDataForSelection = useMemo(() => {
1018
+ if (pinnedTopData.length === 0 && pinnedBottomData.length === 0)
1019
+ return data;
1020
+ return [...pinnedTopData, ...data, ...pinnedBottomData];
1021
+ }, [pinnedTopData, data, pinnedBottomData]);
1022
+ const pinnedRowBg = styles?.pinnedRowBg ?? styles?.pinnedBg;
1010
1023
  const columnStyles = useMemo(() => {
1011
1024
  return orderedColumns.map((col, colIndex) => {
1012
1025
  const stickyOffset = columnOffsets.get(col.key);
@@ -1035,6 +1048,7 @@ var TableBody = ({
1035
1048
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1036
1049
  columnStyles.map((colStyle, colIndex) => {
1037
1050
  const col = orderedColumns[colIndex];
1051
+ const hasRender = !!col.render;
1038
1052
  return /* @__PURE__ */ jsx4(
1039
1053
  "div",
1040
1054
  {
@@ -1046,6 +1060,7 @@ var TableBody = ({
1046
1060
  const isExpanded = resolvedExpandedKeys?.has(rowKey) ?? false;
1047
1061
  const cellValue = row[col.dataIndex];
1048
1062
  const isRowShimmer = isLoading || rowKey.startsWith("__shimmer_");
1063
+ const recordFingerprint = hasRender && !isRowShimmer ? JSON.stringify(row) : void 0;
1049
1064
  return (
1050
1065
  /*
1051
1066
  * Row wrapper div:
@@ -1090,10 +1105,11 @@ var TableBody = ({
1090
1105
  rowSelection,
1091
1106
  normalizedSelectedKeys,
1092
1107
  rowKey,
1093
- allData: data,
1108
+ allData: allDataForSelection,
1094
1109
  getRowKey,
1095
1110
  accentColor,
1096
- isLoading: isRowShimmer
1111
+ isLoading: isRowShimmer,
1112
+ recordFingerprint
1097
1113
  }
1098
1114
  )
1099
1115
  }
@@ -1167,6 +1183,181 @@ var TableBody = ({
1167
1183
  );
1168
1184
  })
1169
1185
  }
1186
+ ),
1187
+ pinnedTopData.length > 0 && /* @__PURE__ */ jsx4(
1188
+ "div",
1189
+ {
1190
+ style: {
1191
+ gridColumn: "1 / -1",
1192
+ gridRow: 2,
1193
+ position: "sticky",
1194
+ top: headerHeight,
1195
+ zIndex: 20,
1196
+ boxShadow: "0 2px 6px -1px rgba(0,0,0,0.08)"
1197
+ },
1198
+ children: pinnedTopData.map((row, rowIdx) => {
1199
+ const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
1200
+ const isSelected = selectedKeySet.has(rk);
1201
+ const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
1202
+ return /* @__PURE__ */ jsx4(
1203
+ "div",
1204
+ {
1205
+ className: classNames?.pinnedRow ?? "",
1206
+ style: {
1207
+ display: "grid",
1208
+ gridTemplateColumns: gridTemplateColumns ?? "",
1209
+ minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
1210
+ ...styles?.pinnedRow
1211
+ },
1212
+ children: orderedColumns.map((col) => {
1213
+ const cellValue = row[col.dataIndex];
1214
+ const stickyOffset = columnOffsets.get(col.key);
1215
+ const isPinned = Boolean(col.pinned);
1216
+ let zIndex = 0;
1217
+ if (col.key === "__select__" || col.key === "__expand__")
1218
+ zIndex = 11;
1219
+ else if (isPinned) zIndex = 2;
1220
+ const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
1221
+ return /* @__PURE__ */ jsx4(
1222
+ "div",
1223
+ {
1224
+ "data-row-key": rk,
1225
+ "data-selected": isSelected || void 0,
1226
+ style: {
1227
+ position: isPinned ? "sticky" : "relative",
1228
+ ...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
1229
+ ...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
1230
+ zIndex,
1231
+ backgroundColor: pinnedRowBg,
1232
+ ...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
1233
+ },
1234
+ children: /* @__PURE__ */ jsx4(
1235
+ "div",
1236
+ {
1237
+ style: {
1238
+ height: `${rowHeight}px`,
1239
+ position: "relative"
1240
+ },
1241
+ children: /* @__PURE__ */ jsx4(
1242
+ Cell,
1243
+ {
1244
+ value: cellValue,
1245
+ record: row,
1246
+ column: col,
1247
+ rowIndex: rowIdx,
1248
+ classNames,
1249
+ styles,
1250
+ isSelected,
1251
+ isExpanded,
1252
+ rowSelection,
1253
+ normalizedSelectedKeys,
1254
+ rowKey: rk,
1255
+ allData: allDataForSelection,
1256
+ getRowKey,
1257
+ accentColor,
1258
+ isLoading: false,
1259
+ recordFingerprint
1260
+ }
1261
+ )
1262
+ }
1263
+ )
1264
+ },
1265
+ col.key
1266
+ );
1267
+ })
1268
+ },
1269
+ `pinned-top-${rk}`
1270
+ );
1271
+ })
1272
+ }
1273
+ ),
1274
+ pinnedBottomData.length > 0 && /* @__PURE__ */ jsx4(
1275
+ "div",
1276
+ {
1277
+ style: {
1278
+ gridColumn: "1 / -1",
1279
+ gridRow: 2,
1280
+ position: "sticky",
1281
+ bottom: 0,
1282
+ alignSelf: "end",
1283
+ zIndex: 20,
1284
+ boxShadow: "0 -2px 6px -1px rgba(0,0,0,0.08)"
1285
+ },
1286
+ children: pinnedBottomData.map((row, rowIdx) => {
1287
+ const rk = getRowKey ? getRowKey(row, rowIdx) : String(rowIdx);
1288
+ const isSelected = selectedKeySet.has(rk);
1289
+ const isExpanded = resolvedExpandedKeys?.has(rk) ?? false;
1290
+ return /* @__PURE__ */ jsx4(
1291
+ "div",
1292
+ {
1293
+ className: classNames?.pinnedRow ?? "",
1294
+ style: {
1295
+ display: "grid",
1296
+ gridTemplateColumns: gridTemplateColumns ?? "",
1297
+ minWidth: totalTableWidth ? `${totalTableWidth}px` : void 0,
1298
+ ...styles?.pinnedRow
1299
+ },
1300
+ children: orderedColumns.map((col) => {
1301
+ const cellValue = row[col.dataIndex];
1302
+ const stickyOffset = columnOffsets.get(col.key);
1303
+ const isPinned = Boolean(col.pinned);
1304
+ let zIndex = 0;
1305
+ if (col.key === "__select__" || col.key === "__expand__")
1306
+ zIndex = 11;
1307
+ else if (isPinned) zIndex = 2;
1308
+ const recordFingerprint = col.render ? JSON.stringify(row) : void 0;
1309
+ return /* @__PURE__ */ jsx4(
1310
+ "div",
1311
+ {
1312
+ "data-row-key": rk,
1313
+ "data-selected": isSelected || void 0,
1314
+ style: {
1315
+ position: isPinned ? "sticky" : "relative",
1316
+ ...col.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
1317
+ ...col.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
1318
+ zIndex,
1319
+ backgroundColor: pinnedRowBg,
1320
+ ...isPinned && styles?.pinnedCell ? styles.pinnedCell : {}
1321
+ },
1322
+ children: /* @__PURE__ */ jsx4(
1323
+ "div",
1324
+ {
1325
+ style: {
1326
+ height: `${rowHeight}px`,
1327
+ position: "relative"
1328
+ },
1329
+ children: /* @__PURE__ */ jsx4(
1330
+ Cell,
1331
+ {
1332
+ value: cellValue,
1333
+ record: row,
1334
+ column: col,
1335
+ rowIndex: rowIdx,
1336
+ classNames,
1337
+ styles,
1338
+ isSelected,
1339
+ isExpanded,
1340
+ rowSelection,
1341
+ normalizedSelectedKeys,
1342
+ rowKey: rk,
1343
+ allData: allDataForSelection,
1344
+ getRowKey,
1345
+ accentColor,
1346
+ isLoading: false,
1347
+ recordFingerprint
1348
+ }
1349
+ )
1350
+ }
1351
+ )
1352
+ },
1353
+ col.key
1354
+ );
1355
+ })
1356
+ },
1357
+ `pinned-bottom-${rk}`
1358
+ );
1359
+ })
1360
+ }
1170
1361
  )
1171
1362
  ] });
1172
1363
  };
@@ -1202,6 +1393,7 @@ function BoltTable({
1202
1393
  onColumnPin,
1203
1394
  onColumnHide,
1204
1395
  rowSelection,
1396
+ rowPinning,
1205
1397
  expandable,
1206
1398
  rowKey = "id",
1207
1399
  onEndReached,
@@ -1600,6 +1792,23 @@ function BoltTable({
1600
1792
  () => [...leftPinned, ...unpinned, ...rightPinned],
1601
1793
  [leftPinned, unpinned, rightPinned]
1602
1794
  );
1795
+ const freshOrderedColumns = useMemo2(() => {
1796
+ const latestMap = new Map(
1797
+ initialColumnsRef.current.map((c) => [c.key, c])
1798
+ );
1799
+ return orderedColumns.map((col) => {
1800
+ if (col.key === "__select__" || col.key === "__expand__") return col;
1801
+ const latest = latestMap.get(col.key);
1802
+ if (!latest) return col;
1803
+ if (col.render === latest.render && col.shimmerRender === latest.shimmerRender)
1804
+ return col;
1805
+ return {
1806
+ ...col,
1807
+ render: latest.render,
1808
+ shimmerRender: latest.shimmerRender
1809
+ };
1810
+ });
1811
+ }, [orderedColumns, initialColumns]);
1603
1812
  const totalTableWidth = useMemo2(
1604
1813
  () => orderedColumns.slice(0, -1).reduce((sum, col) => sum + (col.width ?? 150), 0) + (orderedColumns.at(-1)?.width ?? 150),
1605
1814
  [orderedColumns]
@@ -1725,6 +1934,35 @@ function BoltTable({
1725
1934
  }
1726
1935
  return result;
1727
1936
  }, [data, sortState, columnFilters]);
1937
+ const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = useMemo2(() => {
1938
+ if (!rowPinning || !rowPinning.top?.length && !rowPinning.bottom?.length) {
1939
+ return {
1940
+ pinnedTopRows: [],
1941
+ pinnedBottomRows: [],
1942
+ unpinnedProcessedData: processedData
1943
+ };
1944
+ }
1945
+ const topKeySet = new Set((rowPinning.top ?? []).map(String));
1946
+ const bottomKeySet = new Set((rowPinning.bottom ?? []).map(String));
1947
+ const topMap = /* @__PURE__ */ new Map();
1948
+ const bottomMap = /* @__PURE__ */ new Map();
1949
+ const rest = [];
1950
+ processedData.forEach((row, idx) => {
1951
+ const key = getRowKey(row, idx);
1952
+ if (topKeySet.has(key)) topMap.set(key, row);
1953
+ else if (bottomKeySet.has(key)) bottomMap.set(key, row);
1954
+ else rest.push(row);
1955
+ });
1956
+ const orderedTop = (rowPinning.top ?? []).map((k) => topMap.get(String(k))).filter((r) => r !== void 0);
1957
+ const orderedBottom = (rowPinning.bottom ?? []).map((k) => bottomMap.get(String(k))).filter((r) => r !== void 0);
1958
+ return {
1959
+ pinnedTopRows: orderedTop,
1960
+ pinnedBottomRows: orderedBottom,
1961
+ unpinnedProcessedData: rest
1962
+ };
1963
+ }, [processedData, rowPinning, getRowKey]);
1964
+ const pinnedTopHeight = pinnedTopRows.length * rowHeight;
1965
+ const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
1728
1966
  const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
1729
1967
  React4.useEffect(() => {
1730
1968
  tableAreaRef.current?.scrollTo({ top: 0 });
@@ -1732,12 +1970,12 @@ function BoltTable({
1732
1970
  const pgEnabled = pagination !== false && !!pagination;
1733
1971
  const pgSize = pgEnabled ? pagination.pageSize ?? 10 : 10;
1734
1972
  const pgCurrent = pgEnabled ? Number(pagination.current ?? 1) : 1;
1735
- const needsClientPagination = pgEnabled && processedData.length > pgSize;
1973
+ const needsClientPagination = pgEnabled && unpinnedProcessedData.length > pgSize;
1736
1974
  const paginatedData = useMemo2(() => {
1737
- if (!needsClientPagination) return processedData;
1975
+ if (!needsClientPagination) return unpinnedProcessedData;
1738
1976
  const start = (pgCurrent - 1) * pgSize;
1739
- return processedData.slice(start, start + pgSize);
1740
- }, [processedData, needsClientPagination, pgCurrent, pgSize]);
1977
+ return unpinnedProcessedData.slice(start, start + pgSize);
1978
+ }, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
1741
1979
  const shimmerCount = pgEnabled ? pgSize : 15;
1742
1980
  const showShimmer = isLoading && processedData.length === 0;
1743
1981
  const shimmerData = useMemo2(() => {
@@ -1795,8 +2033,9 @@ function BoltTable({
1795
2033
  return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
1796
2034
  },
1797
2035
  overscan: 5,
1798
- // Render 5 extra rows above and below the visible window
1799
- getItemKey: (index) => shimmerData ? `__shimmer_${index}__` : getRowKey(displayData[index], index)
2036
+ getItemKey: (index) => shimmerData ? `__shimmer_${index}__` : getRowKey(displayData[index], index),
2037
+ paddingStart: pinnedTopHeight,
2038
+ paddingEnd: pinnedBottomHeight
1800
2039
  });
1801
2040
  const rowVirtualizerRef = useRef4(rowVirtualizer);
1802
2041
  rowVirtualizerRef.current = rowVirtualizer;
@@ -1836,7 +2075,7 @@ function BoltTable({
1836
2075
  const activeColumn = activeId ? orderedColumns.find((col) => col.key === activeId) : null;
1837
2076
  const currentPage = pgCurrent;
1838
2077
  const pageSize = pgSize;
1839
- const rawTotal = pgEnabled ? pagination.total ?? (needsClientPagination ? processedData.length : data.length) : data.length;
2078
+ const rawTotal = pgEnabled ? pagination.total ?? (needsClientPagination ? unpinnedProcessedData.length : data.length) : data.length;
1840
2079
  const lastKnownTotalRef = useRef4(0);
1841
2080
  if (!isLoading || rawTotal > 0) {
1842
2081
  lastKnownTotalRef.current = rawTotal;
@@ -2256,7 +2495,7 @@ function BoltTable({
2256
2495
  TableBody_default,
2257
2496
  {
2258
2497
  data: displayData,
2259
- orderedColumns,
2498
+ orderedColumns: freshOrderedColumns,
2260
2499
  rowVirtualizer,
2261
2500
  columnOffsets,
2262
2501
  styles,
@@ -2273,7 +2512,11 @@ function BoltTable({
2273
2512
  scrollContainerRef: tableAreaRef,
2274
2513
  isLoading: showShimmer,
2275
2514
  onExpandedRowResize: handleExpandedRowResize,
2276
- maxExpandedRowHeight
2515
+ maxExpandedRowHeight,
2516
+ pinnedTopData: pinnedTopRows,
2517
+ pinnedBottomData: pinnedBottomRows,
2518
+ gridTemplateColumns,
2519
+ headerHeight: HEADER_HEIGHT
2277
2520
  }
2278
2521
  )
2279
2522
  )
@@ -2522,6 +2765,7 @@ function BoltTable({
2522
2765
  position: "fixed",
2523
2766
  zIndex: 99999,
2524
2767
  height: 36,
2768
+ fontSize: 12,
2525
2769
  alignItems: "center",
2526
2770
  overflow: "hidden",
2527
2771
  textOverflow: "ellipsis",