bolt-table 0.1.12 → 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
@@ -1000,15 +1000,26 @@ var TableBody = ({
1000
1000
  expandable,
1001
1001
  resolvedExpandedKeys,
1002
1002
  rowHeight = 40,
1003
+ totalTableWidth,
1003
1004
  scrollAreaWidth,
1004
1005
  accentColor,
1005
1006
  isLoading = false,
1006
1007
  onExpandedRowResize,
1007
- maxExpandedRowHeight
1008
+ maxExpandedRowHeight,
1009
+ pinnedTopData = [],
1010
+ pinnedBottomData = [],
1011
+ gridTemplateColumns,
1012
+ headerHeight = 36
1008
1013
  }) => {
1009
1014
  const virtualItems = rowVirtualizer.getVirtualItems();
1010
1015
  const totalSize = rowVirtualizer.getTotalSize();
1011
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;
1012
1023
  const columnStyles = useMemo(() => {
1013
1024
  return orderedColumns.map((col, colIndex) => {
1014
1025
  const stickyOffset = columnOffsets.get(col.key);
@@ -1094,7 +1105,7 @@ var TableBody = ({
1094
1105
  rowSelection,
1095
1106
  normalizedSelectedKeys,
1096
1107
  rowKey,
1097
- allData: data,
1108
+ allData: allDataForSelection,
1098
1109
  getRowKey,
1099
1110
  accentColor,
1100
1111
  isLoading: isRowShimmer,
@@ -1172,6 +1183,181 @@ var TableBody = ({
1172
1183
  );
1173
1184
  })
1174
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
+ }
1175
1361
  )
1176
1362
  ] });
1177
1363
  };
@@ -1207,6 +1393,7 @@ function BoltTable({
1207
1393
  onColumnPin,
1208
1394
  onColumnHide,
1209
1395
  rowSelection,
1396
+ rowPinning,
1210
1397
  expandable,
1211
1398
  rowKey = "id",
1212
1399
  onEndReached,
@@ -1747,6 +1934,35 @@ function BoltTable({
1747
1934
  }
1748
1935
  return result;
1749
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;
1750
1966
  const columnFiltersKey = Object.keys(columnFilters).sort().map((k) => `${k}:${columnFilters[k]}`).join("|");
1751
1967
  React4.useEffect(() => {
1752
1968
  tableAreaRef.current?.scrollTo({ top: 0 });
@@ -1754,12 +1970,12 @@ function BoltTable({
1754
1970
  const pgEnabled = pagination !== false && !!pagination;
1755
1971
  const pgSize = pgEnabled ? pagination.pageSize ?? 10 : 10;
1756
1972
  const pgCurrent = pgEnabled ? Number(pagination.current ?? 1) : 1;
1757
- const needsClientPagination = pgEnabled && processedData.length > pgSize;
1973
+ const needsClientPagination = pgEnabled && unpinnedProcessedData.length > pgSize;
1758
1974
  const paginatedData = useMemo2(() => {
1759
- if (!needsClientPagination) return processedData;
1975
+ if (!needsClientPagination) return unpinnedProcessedData;
1760
1976
  const start = (pgCurrent - 1) * pgSize;
1761
- return processedData.slice(start, start + pgSize);
1762
- }, [processedData, needsClientPagination, pgCurrent, pgSize]);
1977
+ return unpinnedProcessedData.slice(start, start + pgSize);
1978
+ }, [unpinnedProcessedData, needsClientPagination, pgCurrent, pgSize]);
1763
1979
  const shimmerCount = pgEnabled ? pgSize : 15;
1764
1980
  const showShimmer = isLoading && processedData.length === 0;
1765
1981
  const shimmerData = useMemo2(() => {
@@ -1817,8 +2033,9 @@ function BoltTable({
1817
2033
  return cached ? rowHeight + cached : rowHeight + expandedRowHeight;
1818
2034
  },
1819
2035
  overscan: 5,
1820
- // Render 5 extra rows above and below the visible window
1821
- 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
1822
2039
  });
1823
2040
  const rowVirtualizerRef = useRef4(rowVirtualizer);
1824
2041
  rowVirtualizerRef.current = rowVirtualizer;
@@ -1858,7 +2075,7 @@ function BoltTable({
1858
2075
  const activeColumn = activeId ? orderedColumns.find((col) => col.key === activeId) : null;
1859
2076
  const currentPage = pgCurrent;
1860
2077
  const pageSize = pgSize;
1861
- 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;
1862
2079
  const lastKnownTotalRef = useRef4(0);
1863
2080
  if (!isLoading || rawTotal > 0) {
1864
2081
  lastKnownTotalRef.current = rawTotal;
@@ -2295,7 +2512,11 @@ function BoltTable({
2295
2512
  scrollContainerRef: tableAreaRef,
2296
2513
  isLoading: showShimmer,
2297
2514
  onExpandedRowResize: handleExpandedRowResize,
2298
- maxExpandedRowHeight
2515
+ maxExpandedRowHeight,
2516
+ pinnedTopData: pinnedTopRows,
2517
+ pinnedBottomData: pinnedBottomRows,
2518
+ gridTemplateColumns,
2519
+ headerHeight: HEADER_HEIGHT
2299
2520
  }
2300
2521
  )
2301
2522
  )