bolt-table 0.1.22 → 0.1.24

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
@@ -1,10 +1,10 @@
1
1
  // src/BoltTable.tsx
2
2
  import { useVirtualizer } from "@tanstack/react-virtual";
3
3
  import React4, {
4
- useCallback,
4
+ useCallback as useCallback2,
5
5
  useMemo as useMemo2,
6
6
  useRef as useRef4,
7
- useState as useState2
7
+ useState as useState3
8
8
  } from "react";
9
9
  import { createPortal as createPortal2 } from "react-dom";
10
10
 
@@ -80,6 +80,10 @@ var CopyIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBas
80
80
  /* @__PURE__ */ jsx("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
81
81
  /* @__PURE__ */ jsx("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
82
82
  ] });
83
+ var PencilIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
84
+ /* @__PURE__ */ jsx("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
85
+ /* @__PURE__ */ jsx("path", { d: "m15 5 4 4" })
86
+ ] });
83
87
  var EyeOffIcon = ({ style, className }) => /* @__PURE__ */ jsxs("svg", { ...svgBase, style, className, children: [
84
88
  /* @__PURE__ */ jsx("path", { d: "M9.88 9.88a3 3 0 1 0 4.24 4.24" }),
85
89
  /* @__PURE__ */ jsx("path", { d: "M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" }),
@@ -117,7 +121,10 @@ var DraggableHeader = React.memo(
117
121
  customContextMenuItems,
118
122
  icons,
119
123
  onColumnDragStart,
120
- disabledFilters
124
+ disabledFilters,
125
+ headerGridRow = 1,
126
+ headerHeight = 36,
127
+ stickyTop = 0
121
128
  }) => {
122
129
  const effectivelySortable = isColumnSortable(column);
123
130
  const effectivelyFilterable = !disabledFilters && isColumnFilterable(column);
@@ -191,23 +198,23 @@ var DraggableHeader = React.memo(
191
198
  const zIndex = isPinned ? 12 : 10;
192
199
  const headerStyle = {
193
200
  position: "sticky",
194
- top: 0,
201
+ top: stickyTop,
195
202
  zIndex,
196
203
  width: isLastColumn ? "100%" : widthPx,
197
204
  minWidth: widthPx,
198
205
  ...isLastColumn ? {} : { maxWidth: widthPx },
199
206
  gridColumn: visualIndex + 1,
200
- gridRow: 1,
207
+ gridRow: headerGridRow,
201
208
  display: "flex",
202
- height: 36,
209
+ height: headerHeight,
203
210
  alignItems: "center",
204
211
  overflow: "hidden",
205
212
  textOverflow: "ellipsis",
206
213
  whiteSpace: "nowrap",
207
214
  borderTop: "none",
208
- borderRight: "none",
215
+ borderRight: "0.5px solid rgba(128,128,128,0.2)",
209
216
  borderBottom: "1px solid rgba(128,128,128,0.2)",
210
- borderLeft: "none",
217
+ borderLeft: "0.5px solid rgba(128,128,128,0.2)",
211
218
  ...column.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
212
219
  ...column.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
213
220
  ...column.style,
@@ -601,7 +608,7 @@ var DraggableHeader = React.memo(
601
608
  ] });
602
609
  },
603
610
  (prevProps, nextProps) => {
604
- return prevProps.column.width === nextProps.column.width && prevProps.column.key === nextProps.column.key && prevProps.column.pinned === nextProps.column.pinned && prevProps.column.sortable === nextProps.column.sortable && prevProps.column.filterable === nextProps.column.filterable && prevProps.column.sorter === nextProps.column.sorter && prevProps.column.filterFn === nextProps.column.filterFn && prevProps.visualIndex === nextProps.visualIndex && prevProps.stickyOffset === nextProps.stickyOffset && prevProps.isLastColumn === nextProps.isLastColumn && prevProps.sortDirection === nextProps.sortDirection && prevProps.filterValue === nextProps.filterValue && prevProps.classNames === nextProps.classNames && prevProps.styles === nextProps.styles && prevProps.customContextMenuItems === nextProps.customContextMenuItems && prevProps.disabledFilters === nextProps.disabledFilters;
611
+ return prevProps.column.width === nextProps.column.width && prevProps.column.key === nextProps.column.key && prevProps.column.pinned === nextProps.column.pinned && prevProps.column.sortable === nextProps.column.sortable && prevProps.column.filterable === nextProps.column.filterable && prevProps.column.sorter === nextProps.column.sorter && prevProps.column.filterFn === nextProps.column.filterFn && prevProps.visualIndex === nextProps.visualIndex && prevProps.stickyOffset === nextProps.stickyOffset && prevProps.isLastColumn === nextProps.isLastColumn && prevProps.sortDirection === nextProps.sortDirection && prevProps.filterValue === nextProps.filterValue && prevProps.classNames === nextProps.classNames && prevProps.styles === nextProps.styles && prevProps.customContextMenuItems === nextProps.customContextMenuItems && prevProps.disabledFilters === nextProps.disabledFilters && prevProps.headerGridRow === nextProps.headerGridRow && prevProps.headerHeight === nextProps.headerHeight && prevProps.stickyTop === nextProps.stickyTop;
605
612
  }
606
613
  );
607
614
  DraggableHeader.displayName = "DraggableHeader";
@@ -744,9 +751,64 @@ ResizeOverlay.displayName = "ResizeOverlay";
744
751
  var ResizeOverlay_default = ResizeOverlay;
745
752
 
746
753
  // src/TableBody.tsx
747
- import React3, { useEffect as useEffect2, useMemo, useRef as useRef3 } from "react";
754
+ import React3, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef3, useState as useState2 } from "react";
748
755
  import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
749
756
  var SHIMMER_WIDTHS = [55, 70, 45, 80, 60, 50, 75, 65];
757
+ var EditableCell = ({
758
+ value,
759
+ record,
760
+ column,
761
+ rowIndex,
762
+ onEdit,
763
+ onEditComplete
764
+ }) => {
765
+ const [draft, setDraft] = useState2(String(value ?? ""));
766
+ const inputRef = useRef3(null);
767
+ useEffect2(() => {
768
+ setDraft(String(value ?? ""));
769
+ requestAnimationFrame(() => {
770
+ inputRef.current?.focus();
771
+ inputRef.current?.select();
772
+ });
773
+ }, [value]);
774
+ const commit = useCallback(() => {
775
+ const raw = String(value ?? "");
776
+ if (draft !== raw && column.dataIndex) {
777
+ const coerced = typeof value === "number" && !Number.isNaN(Number(draft)) ? Number(draft) : draft;
778
+ onEdit(coerced, record, column.dataIndex, rowIndex);
779
+ }
780
+ onEditComplete();
781
+ }, [draft, value, column.dataIndex, record, rowIndex, onEdit, onEditComplete]);
782
+ const cancel = useCallback(() => {
783
+ onEditComplete();
784
+ }, [onEditComplete]);
785
+ return /* @__PURE__ */ jsx4(
786
+ "input",
787
+ {
788
+ ref: inputRef,
789
+ value: draft,
790
+ onChange: (e) => setDraft(e.target.value),
791
+ onBlur: commit,
792
+ onKeyDown: (e) => {
793
+ if (e.key === "Enter") commit();
794
+ if (e.key === "Escape") cancel();
795
+ },
796
+ style: {
797
+ width: "100%",
798
+ height: "100%",
799
+ border: "none",
800
+ outline: "none",
801
+ background: "transparent",
802
+ font: "inherit",
803
+ color: "inherit",
804
+ padding: 0,
805
+ margin: 0,
806
+ boxSizing: "border-box"
807
+ }
808
+ }
809
+ );
810
+ };
811
+ EditableCell.displayName = "EditableCell";
750
812
  var Cell = React3.memo(
751
813
  ({
752
814
  value,
@@ -762,7 +824,10 @@ var Cell = React3.memo(
762
824
  getRowKey,
763
825
  getRawRowKey,
764
826
  accentColor,
765
- isLoading
827
+ isLoading,
828
+ onEdit,
829
+ isEditing,
830
+ onEditComplete
766
831
  }) => {
767
832
  const isPinned = Boolean(column.pinned);
768
833
  if (isLoading && column.key !== "__select__" && column.key !== "__expand__") {
@@ -841,7 +906,7 @@ var Cell = React3.memo(
841
906
  type: "multiple"
842
907
  });
843
908
  },
844
- style: { cursor: "pointer", accentColor }
909
+ style: { cursor: "pointer", accentColor, colorScheme: "light dark" }
845
910
  }
846
911
  );
847
912
  return /* @__PURE__ */ jsx4(
@@ -866,8 +931,22 @@ var Cell = React3.memo(
866
931
  }
867
932
  );
868
933
  }
934
+ const isEditable = !!column.editable && !column.render && !!onEdit;
935
+ const showEditor = isEditable && isEditing && onEditComplete;
869
936
  let content;
870
- if (column.render) {
937
+ if (showEditor) {
938
+ content = /* @__PURE__ */ jsx4(
939
+ EditableCell,
940
+ {
941
+ value,
942
+ record,
943
+ column,
944
+ rowIndex,
945
+ onEdit,
946
+ onEditComplete
947
+ }
948
+ );
949
+ } else if (column.render) {
871
950
  try {
872
951
  content = column.render(value, record, rowIndex);
873
952
  } catch {
@@ -896,7 +975,7 @@ var Cell = React3.memo(
896
975
  ...isPinned ? styles?.pinnedCell : void 0,
897
976
  ...styles?.cell
898
977
  },
899
- children: isSystem ? content : /* @__PURE__ */ jsx4(
978
+ children: isSystem ? content : showEditor ? content : /* @__PURE__ */ jsx4(
900
979
  "div",
901
980
  {
902
981
  style: {
@@ -917,6 +996,10 @@ var Cell = React3.memo(
917
996
  if (prev.column.pinned !== next.column.pinned) return false;
918
997
  if (prev.classNames !== next.classNames) return false;
919
998
  if (prev.styles !== next.styles) return false;
999
+ if (prev.column.editable !== next.column.editable) return false;
1000
+ if (prev.onEdit !== next.onEdit) return false;
1001
+ if (prev.isEditing !== next.isEditing) return false;
1002
+ if (prev.onEditComplete !== next.onEditComplete) return false;
920
1003
  if (prev.column.key === "__select__") {
921
1004
  return prev.isSelected === next.isSelected && prev.normalizedSelectedKeys === next.normalizedSelectedKeys;
922
1005
  }
@@ -984,7 +1067,11 @@ var TableBody = ({
984
1067
  gridTemplateColumns,
985
1068
  headerHeight = 36,
986
1069
  rowClassName,
987
- rowStyle
1070
+ rowStyle,
1071
+ bodyGridRow = 2,
1072
+ onEdit,
1073
+ editingCell,
1074
+ onEditComplete
988
1075
  }) => {
989
1076
  const virtualItems = rowVirtualizer.getVirtualItems();
990
1077
  const totalSize = rowVirtualizer.getTotalSize();
@@ -1006,7 +1093,7 @@ var TableBody = ({
1006
1093
  else if (isPinned) zIndex = 2;
1007
1094
  const style = {
1008
1095
  gridColumn: colIndex + 1,
1009
- gridRow: 2,
1096
+ gridRow: bodyGridRow,
1010
1097
  height: `${totalSize}px`,
1011
1098
  position: isPinned ? "sticky" : "relative",
1012
1099
  zIndex
@@ -1020,7 +1107,7 @@ var TableBody = ({
1020
1107
  }
1021
1108
  return { key: col.key, style, isPinned };
1022
1109
  });
1023
- }, [safeColumns, columnOffsets, totalSize, styles]);
1110
+ }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow]);
1024
1111
  if (safeData.length === 0 || safeColumns.length === 0) return null;
1025
1112
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1026
1113
  columnStyles.map((colStyle, colIndex) => {
@@ -1038,7 +1125,7 @@ var TableBody = ({
1038
1125
  const rowKey = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
1039
1126
  const isSelected = selectedKeySet.has(rowKey);
1040
1127
  const isExpanded = resolvedExpandedKeys?.has(rowKey) ?? false;
1041
- const cellValue = row[col.dataIndex];
1128
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1042
1129
  const isRowShimmer = isLoading || rowKey.startsWith("__shimmer_");
1043
1130
  let recordFingerprint;
1044
1131
  if (hasRender && !isRowShimmer) {
@@ -1100,7 +1187,10 @@ var TableBody = ({
1100
1187
  getRawRowKey,
1101
1188
  accentColor,
1102
1189
  isLoading: isRowShimmer,
1103
- recordFingerprint
1190
+ recordFingerprint,
1191
+ onEdit,
1192
+ isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
1193
+ onEditComplete
1104
1194
  }
1105
1195
  )
1106
1196
  }
@@ -1118,7 +1208,7 @@ var TableBody = ({
1118
1208
  {
1119
1209
  style: {
1120
1210
  gridColumn: "1 / -1",
1121
- gridRow: 2,
1211
+ gridRow: bodyGridRow,
1122
1212
  height: `${totalSize}px`,
1123
1213
  position: "relative",
1124
1214
  zIndex: 15,
@@ -1182,7 +1272,7 @@ var TableBody = ({
1182
1272
  {
1183
1273
  style: {
1184
1274
  gridColumn: "1 / -1",
1185
- gridRow: 2,
1275
+ gridRow: bodyGridRow,
1186
1276
  height: `${totalSize}px`,
1187
1277
  position: "relative",
1188
1278
  zIndex: 20,
@@ -1224,7 +1314,7 @@ var TableBody = ({
1224
1314
  ...rowSty
1225
1315
  },
1226
1316
  children: safeColumns.map((col) => {
1227
- const cellValue = row[col.dataIndex];
1317
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1228
1318
  const stickyOffset = columnOffsets.get(col.key);
1229
1319
  const isPinned = Boolean(col.pinned);
1230
1320
  let zIndex = 0;
@@ -1282,7 +1372,10 @@ var TableBody = ({
1282
1372
  getRawRowKey,
1283
1373
  accentColor,
1284
1374
  isLoading: false,
1285
- recordFingerprint
1375
+ recordFingerprint,
1376
+ onEdit,
1377
+ isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
1378
+ onEditComplete
1286
1379
  }
1287
1380
  )
1288
1381
  }
@@ -1304,7 +1397,7 @@ var TableBody = ({
1304
1397
  {
1305
1398
  style: {
1306
1399
  gridColumn: "1 / -1",
1307
- gridRow: 2,
1400
+ gridRow: bodyGridRow,
1308
1401
  height: `${totalSize}px`,
1309
1402
  position: "relative",
1310
1403
  zIndex: 20,
@@ -1349,7 +1442,7 @@ var TableBody = ({
1349
1442
  ...rowSty
1350
1443
  },
1351
1444
  children: safeColumns.map((col) => {
1352
- const cellValue = row[col.dataIndex];
1445
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1353
1446
  const stickyOffset = columnOffsets.get(col.key);
1354
1447
  const isPinned = Boolean(col.pinned);
1355
1448
  let zIndex = 0;
@@ -1407,7 +1500,10 @@ var TableBody = ({
1407
1500
  getRawRowKey,
1408
1501
  accentColor,
1409
1502
  isLoading: false,
1410
- recordFingerprint
1503
+ recordFingerprint,
1504
+ onEdit,
1505
+ isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
1506
+ onEditComplete
1411
1507
  }
1412
1508
  )
1413
1509
  }
@@ -1437,6 +1533,18 @@ function arrayMove(arr, from, to) {
1437
1533
  result.splice(to, 0, item);
1438
1534
  return result;
1439
1535
  }
1536
+ function flattenColumns(columns) {
1537
+ const result = [];
1538
+ for (const col of columns) {
1539
+ if (col == null) continue;
1540
+ if (col.children && col.children.length > 0) {
1541
+ result.push(...flattenColumns(col.children));
1542
+ } else {
1543
+ result.push(col);
1544
+ }
1545
+ }
1546
+ return result;
1547
+ }
1440
1548
  var SHIMMER_WIDTHS2 = [55, 70, 45, 80, 60, 50, 75, 65, 40, 72];
1441
1549
  var EMPTY_CLASSNAMES = {};
1442
1550
  var EMPTY_STYLES = {};
@@ -1477,7 +1585,10 @@ function BoltTable({
1477
1585
  emptyRenderer,
1478
1586
  rowClassName,
1479
1587
  rowStyle,
1480
- disabledFilters
1588
+ disabledFilters,
1589
+ onCopy,
1590
+ keepPinnedRowsAcrossPages,
1591
+ onEdit
1481
1592
  }) {
1482
1593
  const data = useMemo2(() => {
1483
1594
  if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
@@ -1486,17 +1597,49 @@ function BoltTable({
1486
1597
  }, [rawData]);
1487
1598
  const initialColumns = useMemo2(() => {
1488
1599
  if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1489
- const filtered = rawInitialColumns.filter(
1600
+ const safe = rawInitialColumns.filter(
1490
1601
  (col) => col != null && typeof col.key === "string"
1491
1602
  );
1492
- return filtered.length > 0 ? filtered : STABLE_EMPTY_COLS;
1603
+ const flattened = flattenColumns(safe);
1604
+ const validated = flattened.filter(
1605
+ (col) => col != null && typeof col.key === "string"
1606
+ );
1607
+ return validated.length > 0 ? validated : STABLE_EMPTY_COLS;
1608
+ }, [rawInitialColumns]);
1609
+ const headerGroups = useMemo2(() => {
1610
+ if (!Array.isArray(rawInitialColumns)) return [];
1611
+ const groups = [];
1612
+ for (const col of rawInitialColumns) {
1613
+ if (col != null && typeof col.key === "string" && col.children && col.children.length > 0) {
1614
+ const leafKeys = flattenColumns([col]).filter((c) => c != null && typeof c.key === "string").map((c) => c.key);
1615
+ if (leafKeys.length > 0) {
1616
+ groups.push({
1617
+ key: col.key,
1618
+ title: col.title,
1619
+ childKeys: leafKeys,
1620
+ style: col.style,
1621
+ className: col.className
1622
+ });
1623
+ }
1624
+ }
1625
+ }
1626
+ return groups;
1493
1627
  }, [rawInitialColumns]);
1494
- const [columns, setColumns] = useState2(initialColumns);
1495
- const [columnOrder, setColumnOrder] = useState2(
1628
+ const hasColumnGroups = headerGroups.length > 0;
1629
+ const groupedColumnKeySet = useMemo2(() => {
1630
+ if (!hasColumnGroups) return null;
1631
+ const keys = /* @__PURE__ */ new Set();
1632
+ for (const g of headerGroups) {
1633
+ for (const k of g.childKeys) keys.add(k);
1634
+ }
1635
+ return keys;
1636
+ }, [headerGroups, hasColumnGroups]);
1637
+ const [columns, setColumns] = useState3(initialColumns);
1638
+ const [columnOrder, setColumnOrder] = useState3(
1496
1639
  () => initialColumns.map((c) => c.key)
1497
1640
  );
1498
- const [activeId, setActiveId] = useState2(null);
1499
- const [mounted, setMounted] = useState2(false);
1641
+ const [activeId, setActiveId] = useState3(null);
1642
+ const [mounted, setMounted] = useState3(false);
1500
1643
  React4.useEffect(() => {
1501
1644
  setMounted(true);
1502
1645
  }, []);
@@ -1514,7 +1657,7 @@ function BoltTable({
1514
1657
  setColumnOrder(initialColumnsRef.current.map((c) => c.key));
1515
1658
  }, [newFingerprint]);
1516
1659
  const safeWidth = (w, fallback = 150) => typeof w === "number" && Number.isFinite(w) ? w : fallback;
1517
- const [columnWidths, setColumnWidths] = useState2(
1660
+ const [columnWidths, setColumnWidths] = useState3(
1518
1661
  () => /* @__PURE__ */ new Map()
1519
1662
  );
1520
1663
  const manuallyResizedRef = useRef4(/* @__PURE__ */ new Set());
@@ -1525,7 +1668,7 @@ function BoltTable({
1525
1668
  })),
1526
1669
  [columns, columnWidths]
1527
1670
  );
1528
- const [internalExpandedKeys, setInternalExpandedKeys] = useState2(() => {
1671
+ const [internalExpandedKeys, setInternalExpandedKeys] = useState3(() => {
1529
1672
  if (expandable?.defaultExpandAllRows && data.length > 0) {
1530
1673
  return new Set(
1531
1674
  data.map((row, idx) => {
@@ -1551,7 +1694,7 @@ function BoltTable({
1551
1694
  }, [expandedKeysFingerprint, internalExpandedKeys]);
1552
1695
  const expandableRef = useRef4(expandable);
1553
1696
  expandableRef.current = expandable;
1554
- const toggleExpand = useCallback((key) => {
1697
+ const toggleExpand = useCallback2((key) => {
1555
1698
  const exp = expandableRef.current;
1556
1699
  if (exp?.expandedRowKeys !== void 0) {
1557
1700
  const next = new Set(exp.expandedRowKeys);
@@ -1566,7 +1709,7 @@ function BoltTable({
1566
1709
  });
1567
1710
  }
1568
1711
  }, []);
1569
- const getRowKey = useCallback(
1712
+ const getRowKey = useCallback2(
1570
1713
  (record, index) => {
1571
1714
  if (record == null) return String(index);
1572
1715
  try {
@@ -1582,7 +1725,7 @@ function BoltTable({
1582
1725
  },
1583
1726
  [rowKey]
1584
1727
  );
1585
- const getRawRowKey = useCallback(
1728
+ const getRawRowKey = useCallback2(
1586
1729
  (record, index) => {
1587
1730
  if (record == null) return index;
1588
1731
  try {
@@ -1681,11 +1824,11 @@ function BoltTable({
1681
1824
  }, [rowSelection, columnsWithExpand]);
1682
1825
  const resizeOverlayRef = useRef4(null);
1683
1826
  const tableAreaRef = useRef4(null);
1684
- const [scrollAreaWidth, setScrollAreaWidth] = useState2(0);
1827
+ const [scrollAreaWidth, setScrollAreaWidth] = useState3(0);
1685
1828
  const prevScrollAreaWidthRef = useRef4(0);
1686
1829
  const roRef = useRef4(null);
1687
1830
  const rafRef = useRef4(null);
1688
- const tableAreaCallbackRef = useCallback((el) => {
1831
+ const tableAreaCallbackRef = useCallback2((el) => {
1689
1832
  roRef.current?.disconnect();
1690
1833
  roRef.current = null;
1691
1834
  if (rafRef.current !== null) {
@@ -1743,12 +1886,23 @@ function BoltTable({
1743
1886
  };
1744
1887
  }, []);
1745
1888
  const resizeStateRef = useRef4(null);
1889
+ const columnGroupMapRef = useRef4(/* @__PURE__ */ new Map());
1890
+ useMemo2(() => {
1891
+ const map = /* @__PURE__ */ new Map();
1892
+ for (const g of headerGroups) {
1893
+ for (const k of g.childKeys) map.set(k, g.key);
1894
+ }
1895
+ for (const col of initialColumns) {
1896
+ if (!map.has(col.key)) map.set(col.key, null);
1897
+ }
1898
+ columnGroupMapRef.current = map;
1899
+ }, [headerGroups, initialColumns]);
1746
1900
  const overIdRef = useRef4(null);
1747
1901
  const dragActiveIdRef = useRef4(null);
1748
1902
  const ghostRef = useRef4(null);
1749
1903
  const onColumnOrderChangeRef = useRef4(onColumnOrderChange);
1750
1904
  onColumnOrderChangeRef.current = onColumnOrderChange;
1751
- const handleColumnDragStart = useCallback(
1905
+ const handleColumnDragStart = useCallback2(
1752
1906
  (columnKey, e) => {
1753
1907
  if (columnKey === "__select__" || columnKey === "__expand__") return;
1754
1908
  const headerEl = e.currentTarget.closest(
@@ -1771,6 +1925,7 @@ function BoltTable({
1771
1925
  const grabStyle = document.createElement("style");
1772
1926
  grabStyle.textContent = "* { cursor: grabbing !important; }";
1773
1927
  document.head.appendChild(grabStyle);
1928
+ const draggedGroup = columnGroupMapRef.current.get(columnKey);
1774
1929
  const onMove = (ev) => {
1775
1930
  if (ghost) {
1776
1931
  ghost.style.left = `${ev.clientX - offsetX}px`;
@@ -1786,6 +1941,11 @@ function BoltTable({
1786
1941
  h.removeAttribute("data-drag-over");
1787
1942
  return;
1788
1943
  }
1944
+ const targetGroup = columnGroupMapRef.current.get(key);
1945
+ if (draggedGroup !== targetGroup) {
1946
+ h.removeAttribute("data-drag-over");
1947
+ return;
1948
+ }
1789
1949
  const r = h.getBoundingClientRect();
1790
1950
  if (ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top - 20 && ev.clientY <= r.bottom + 20) {
1791
1951
  newOverId = key;
@@ -1808,7 +1968,7 @@ function BoltTable({
1808
1968
  if (ghost) ghost.style.display = "none";
1809
1969
  const currentOverId = overIdRef.current;
1810
1970
  const currentActiveId = dragActiveIdRef.current;
1811
- if (currentOverId && currentActiveId && currentOverId !== currentActiveId) {
1971
+ if (currentOverId && currentActiveId && currentOverId !== currentActiveId && columnGroupMapRef.current.get(currentActiveId) === columnGroupMapRef.current.get(currentOverId)) {
1812
1972
  React4.startTransition(() => {
1813
1973
  setColumnOrder((items) => {
1814
1974
  const oldIndex = items.indexOf(currentActiveId);
@@ -1975,9 +2135,9 @@ function BoltTable({
1975
2135
  const column = columns.find((col) => col.key === columnKey);
1976
2136
  if (column && !column.pinned) onColumnHide?.(columnKey, !column.hidden);
1977
2137
  };
1978
- const [internalRowPinning, setInternalRowPinning] = useState2({ top: [], bottom: [] });
2138
+ const [internalRowPinning, setInternalRowPinning] = useState3({ top: [], bottom: [] });
1979
2139
  const resolvedRowPinning = rowPinning === true ? internalRowPinning : rowPinning && typeof rowPinning === "object" ? rowPinning : void 0;
1980
- const handleRowPin = useCallback((rk, pinned) => {
2140
+ const handleRowPin = useCallback2((rk, pinned) => {
1981
2141
  if (onRowPin) {
1982
2142
  onRowPin(rk, pinned);
1983
2143
  return;
@@ -1995,8 +2155,8 @@ function BoltTable({
1995
2155
  }, [onRowPin, rowPinning]);
1996
2156
  const onSortChangeRef = useRef4(onSortChange);
1997
2157
  onSortChangeRef.current = onSortChange;
1998
- const [sortState, setSortState] = useState2({ key: "", direction: null });
1999
- const handleSort = useCallback(
2158
+ const [sortState, setSortState] = useState3({ key: "", direction: null });
2159
+ const handleSort = useCallback2(
2000
2160
  (columnKey, direction) => {
2001
2161
  setSortState((prev) => {
2002
2162
  let next;
@@ -2012,10 +2172,10 @@ function BoltTable({
2012
2172
  },
2013
2173
  []
2014
2174
  );
2015
- const [columnFilters, setColumnFilters] = useState2(
2175
+ const [columnFilters, setColumnFilters] = useState3(
2016
2176
  {}
2017
2177
  );
2018
- const handleColumnFilter = useCallback(
2178
+ const handleColumnFilter = useCallback2(
2019
2179
  (columnKey, value) => {
2020
2180
  setColumnFilters((prev) => {
2021
2181
  const next = { ...prev };
@@ -2027,7 +2187,7 @@ function BoltTable({
2027
2187
  },
2028
2188
  [onFilterChange]
2029
2189
  );
2030
- const handleClearFilter = useCallback(
2190
+ const handleClearFilter = useCallback2(
2031
2191
  (columnKey) => {
2032
2192
  handleColumnFilter(columnKey, "");
2033
2193
  },
@@ -2048,7 +2208,7 @@ function BoltTable({
2048
2208
  try {
2049
2209
  const col = columnsLookupRef.current.find((c) => c.key === key);
2050
2210
  if (typeof col?.filterFn === "function") {
2051
- return col.filterFn(columnFilters[key], row, col.dataIndex);
2211
+ return col.filterFn(columnFilters[key], row, col.dataIndex ?? key);
2052
2212
  }
2053
2213
  const cellVal = String(row[key] ?? "").toLowerCase();
2054
2214
  return cellVal.includes(columnFilters[key].toLowerCase());
@@ -2092,8 +2252,10 @@ function BoltTable({
2092
2252
  }
2093
2253
  return result;
2094
2254
  }, [data, sortState, columnFilters]);
2255
+ const pinnedRowCacheRef = useRef4(/* @__PURE__ */ new Map());
2095
2256
  const { pinnedTopRows, pinnedBottomRows, unpinnedProcessedData } = useMemo2(() => {
2096
2257
  if (!resolvedRowPinning || !resolvedRowPinning.top?.length && !resolvedRowPinning.bottom?.length) {
2258
+ if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.clear();
2097
2259
  return {
2098
2260
  pinnedTopRows: [],
2099
2261
  pinnedBottomRows: [],
@@ -2108,10 +2270,32 @@ function BoltTable({
2108
2270
  processedData.forEach((row, idx) => {
2109
2271
  if (row == null) return;
2110
2272
  const key = getRowKey(row, idx);
2111
- if (topKeySet.has(key)) topMap.set(key, row);
2112
- else if (bottomKeySet.has(key)) bottomMap.set(key, row);
2113
- else rest.push(row);
2273
+ if (topKeySet.has(key)) {
2274
+ topMap.set(key, row);
2275
+ if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2276
+ } else if (bottomKeySet.has(key)) {
2277
+ bottomMap.set(key, row);
2278
+ if (keepPinnedRowsAcrossPages) pinnedRowCacheRef.current.set(key, row);
2279
+ } else {
2280
+ rest.push(row);
2281
+ }
2114
2282
  });
2283
+ if (keepPinnedRowsAcrossPages) {
2284
+ for (const k of topKeySet) {
2285
+ if (!topMap.has(k) && pinnedRowCacheRef.current.has(k)) {
2286
+ topMap.set(k, pinnedRowCacheRef.current.get(k));
2287
+ }
2288
+ }
2289
+ for (const k of bottomKeySet) {
2290
+ if (!bottomMap.has(k) && pinnedRowCacheRef.current.has(k)) {
2291
+ bottomMap.set(k, pinnedRowCacheRef.current.get(k));
2292
+ }
2293
+ }
2294
+ const allPinnedKeys = /* @__PURE__ */ new Set([...topKeySet, ...bottomKeySet]);
2295
+ for (const cachedKey of pinnedRowCacheRef.current.keys()) {
2296
+ if (!allPinnedKeys.has(cachedKey)) pinnedRowCacheRef.current.delete(cachedKey);
2297
+ }
2298
+ }
2115
2299
  const orderedTop = (resolvedRowPinning.top ?? []).map((k) => topMap.get(String(k))).filter((r) => r !== void 0);
2116
2300
  const orderedBottom = (resolvedRowPinning.bottom ?? []).map((k) => bottomMap.get(String(k))).filter((r) => r !== void 0);
2117
2301
  return {
@@ -2119,7 +2303,7 @@ function BoltTable({
2119
2303
  pinnedBottomRows: orderedBottom,
2120
2304
  unpinnedProcessedData: rest
2121
2305
  };
2122
- }, [processedData, resolvedRowPinning, getRowKey]);
2306
+ }, [processedData, resolvedRowPinning, getRowKey, keepPinnedRowsAcrossPages]);
2123
2307
  const pinnedTopHeight = pinnedTopRows.length * rowHeight;
2124
2308
  const pinnedBottomHeight = pinnedBottomRows.length * rowHeight;
2125
2309
  const pinnedTopKeySet = useMemo2(
@@ -2130,13 +2314,17 @@ function BoltTable({
2130
2314
  () => new Set((resolvedRowPinning?.bottom ?? []).map(String)),
2131
2315
  [resolvedRowPinning?.bottom]
2132
2316
  );
2133
- const [cellContextMenu, setCellContextMenu] = useState2(null);
2317
+ const [editingCell, setEditingCell] = useState3(null);
2318
+ const handleEditComplete = useCallback2(() => {
2319
+ setEditingCell(null);
2320
+ }, []);
2321
+ const [cellContextMenu, setCellContextMenu] = useState3(null);
2134
2322
  const cellMenuRef = useRef4(null);
2135
2323
  const cellLongPressTimer = useRef4(
2136
2324
  null
2137
2325
  );
2138
2326
  const cellTouchStart = useRef4(null);
2139
- const cancelCellLongPress = useCallback(() => {
2327
+ const cancelCellLongPress = useCallback2(() => {
2140
2328
  if (cellLongPressTimer.current) {
2141
2329
  clearTimeout(cellLongPressTimer.current);
2142
2330
  cellLongPressTimer.current = null;
@@ -2166,8 +2354,8 @@ function BoltTable({
2166
2354
  tableAreaRef.current?.scrollTo({ top: 0 });
2167
2355
  }, [columnFiltersKey]);
2168
2356
  const DEFAULT_PAGE_SIZE = 15;
2169
- const [internalPage, setInternalPage] = useState2(1);
2170
- const [internalPageSize, setInternalPageSize] = useState2(DEFAULT_PAGE_SIZE);
2357
+ const [internalPage, setInternalPage] = useState3(1);
2358
+ const [internalPageSize, setInternalPageSize] = useState3(DEFAULT_PAGE_SIZE);
2171
2359
  const dataLength = data.length;
2172
2360
  const autoPagination = pagination === void 0 && dataLength > DEFAULT_PAGE_SIZE;
2173
2361
  const pgEnabled = pagination === false ? false : !!pagination || autoPagination;
@@ -2211,7 +2399,7 @@ function BoltTable({
2211
2399
  }, [shimmerData, infiniteLoadingShimmer, paginatedData]);
2212
2400
  const measuredExpandedHeights = useRef4(/* @__PURE__ */ new Map());
2213
2401
  const expandedRowMeasureRafRef = useRef4(null);
2214
- const handleExpandedRowResize = useCallback(
2402
+ const handleExpandedRowResize = useCallback2(
2215
2403
  (rk, contentHeight) => {
2216
2404
  const prev = measuredExpandedHeights.current.get(rk);
2217
2405
  const rounded = Math.round(contentHeight);
@@ -2340,7 +2528,7 @@ function BoltTable({
2340
2528
  totalPages
2341
2529
  ];
2342
2530
  };
2343
- const HEADER_HEIGHT = 36;
2531
+ const HEADER_HEIGHT = hasColumnGroups ? 72 : 36;
2344
2532
  const MAX_AUTO_ROWS = 10;
2345
2533
  const virtualTotalSize = rowVirtualizer.getTotalSize();
2346
2534
  const naturalContentHeight = virtualTotalSize + HEADER_HEIGHT;
@@ -2535,7 +2723,7 @@ function BoltTable({
2535
2723
  style: {
2536
2724
  display: "grid",
2537
2725
  gridTemplateColumns,
2538
- gridTemplateRows: isEmpty ? "36px 1fr" : `36px ${virtualTotalSize}px`,
2726
+ gridTemplateRows: isEmpty ? hasColumnGroups ? "36px 36px 1fr" : "36px 1fr" : hasColumnGroups ? `36px 36px ${virtualTotalSize}px` : `36px ${virtualTotalSize}px`,
2539
2727
  minWidth: `${totalTableWidth}px`,
2540
2728
  width: "100%",
2541
2729
  position: "relative",
@@ -2553,7 +2741,8 @@ function BoltTable({
2553
2741
  const hasCopy = !!col?.copy;
2554
2742
  const hasRowPin = !!rowPinning;
2555
2743
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2556
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2744
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2745
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2557
2746
  e.preventDefault();
2558
2747
  setCellContextMenu({
2559
2748
  x: Math.min(e.clientX, window.innerWidth - 200),
@@ -2582,7 +2771,8 @@ function BoltTable({
2582
2771
  const hasCopy = !!col?.copy;
2583
2772
  const hasRowPin = !!rowPinning;
2584
2773
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2585
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2774
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2775
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2586
2776
  setCellContextMenu({
2587
2777
  x: Math.min(touch.clientX, window.innerWidth - 200),
2588
2778
  y: Math.min(touch.clientY, window.innerHeight - 200),
@@ -2602,7 +2792,50 @@ function BoltTable({
2602
2792
  onTouchEnd: cancelCellLongPress,
2603
2793
  onTouchCancel: cancelCellLongPress,
2604
2794
  children: [
2795
+ hasColumnGroups && headerGroups.map((group) => {
2796
+ let minIdx = Infinity;
2797
+ let maxIdx = -1;
2798
+ orderedColumns.forEach((col, idx) => {
2799
+ if (group.childKeys.includes(col.key)) {
2800
+ minIdx = Math.min(minIdx, idx);
2801
+ maxIdx = Math.max(maxIdx, idx);
2802
+ }
2803
+ });
2804
+ if (minIdx === Infinity) return null;
2805
+ return /* @__PURE__ */ jsx5(
2806
+ "div",
2807
+ {
2808
+ "data-bt-header": "",
2809
+ className: `${group.className ?? ""} ${classNames.header ?? ""}`,
2810
+ style: {
2811
+ gridColumn: `${minIdx + 1} / ${maxIdx + 2}`,
2812
+ gridRow: 1,
2813
+ position: "sticky",
2814
+ top: 0,
2815
+ zIndex: 10,
2816
+ display: "flex",
2817
+ height: 36,
2818
+ alignItems: "center",
2819
+ justifyContent: "center",
2820
+ overflow: "hidden",
2821
+ textOverflow: "ellipsis",
2822
+ whiteSpace: "nowrap",
2823
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2824
+ fontWeight: 500,
2825
+ userSelect: "none",
2826
+ ...group.style,
2827
+ ...styles.header
2828
+ },
2829
+ children: group.title
2830
+ },
2831
+ `group-${group.key}`
2832
+ );
2833
+ }),
2605
2834
  orderedColumns.map((column, visualIndex) => {
2835
+ const isInGroup = groupedColumnKeySet?.has(column.key) ?? false;
2836
+ const leafGridRow = hasColumnGroups ? isInGroup ? 2 : "1 / 3" : 1;
2837
+ const leafHeight = hasColumnGroups && !isInGroup ? 72 : 36;
2838
+ const leafStickyTop = hasColumnGroups && isInGroup ? 36 : 0;
2606
2839
  if (column.key === "__select__" && rowSelection) {
2607
2840
  return /* @__PURE__ */ jsx5(
2608
2841
  "div",
@@ -2612,7 +2845,7 @@ function BoltTable({
2612
2845
  className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2613
2846
  style: {
2614
2847
  display: "flex",
2615
- height: 36,
2848
+ height: leafHeight,
2616
2849
  alignItems: "center",
2617
2850
  justifyContent: "center",
2618
2851
  overflow: "hidden",
@@ -2624,6 +2857,7 @@ function BoltTable({
2624
2857
  top: 0,
2625
2858
  zIndex: 13,
2626
2859
  width: "48px",
2860
+ gridRow: leafGridRow,
2627
2861
  ...styles.header,
2628
2862
  ...styles.pinnedHeader
2629
2863
  },
@@ -2657,7 +2891,7 @@ function BoltTable({
2657
2891
  });
2658
2892
  }
2659
2893
  },
2660
- style: { cursor: "pointer", accentColor }
2894
+ style: { cursor: "pointer", accentColor, colorScheme: "light dark" }
2661
2895
  }
2662
2896
  )
2663
2897
  },
@@ -2673,7 +2907,7 @@ function BoltTable({
2673
2907
  className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2674
2908
  style: {
2675
2909
  display: "flex",
2676
- height: 36,
2910
+ height: leafHeight,
2677
2911
  alignItems: "center",
2678
2912
  justifyContent: "center",
2679
2913
  overflow: "hidden",
@@ -2685,6 +2919,7 @@ function BoltTable({
2685
2919
  top: 0,
2686
2920
  zIndex: 13,
2687
2921
  width: "40px",
2922
+ gridRow: leafGridRow,
2688
2923
  ...styles.header,
2689
2924
  ...styles.pinnedHeader
2690
2925
  }
@@ -2715,7 +2950,10 @@ function BoltTable({
2715
2950
  onFilter: handleColumnFilter,
2716
2951
  onClearFilter: handleClearFilter,
2717
2952
  customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
2718
- disabledFilters
2953
+ disabledFilters,
2954
+ headerGridRow: leafGridRow,
2955
+ headerHeight: leafHeight,
2956
+ stickyTop: leafStickyTop
2719
2957
  },
2720
2958
  column.key
2721
2959
  );
@@ -2786,7 +3024,11 @@ function BoltTable({
2786
3024
  gridTemplateColumns,
2787
3025
  headerHeight: HEADER_HEIGHT,
2788
3026
  rowClassName,
2789
- rowStyle
3027
+ rowStyle,
3028
+ bodyGridRow: hasColumnGroups ? 3 : 2,
3029
+ onEdit,
3030
+ editingCell,
3031
+ onEditComplete: handleEditComplete
2790
3032
  }
2791
3033
  )
2792
3034
  ]
@@ -2800,6 +3042,7 @@ function BoltTable({
2800
3042
  pgEnabled && /* @__PURE__ */ jsxs5(
2801
3043
  "div",
2802
3044
  {
3045
+ className: classNames.pagination ?? "",
2803
3046
  style: {
2804
3047
  display: "flex",
2805
3048
  height: 36,
@@ -2811,27 +3054,42 @@ function BoltTable({
2811
3054
  fontSize: 12,
2812
3055
  backdropFilter: "blur(8px)",
2813
3056
  backgroundColor: "rgba(128,128,128,0.06)",
2814
- gap: 12
3057
+ gap: 12,
3058
+ ...styles.pagination
2815
3059
  },
2816
3060
  children: [
2817
3061
  /* @__PURE__ */ jsx5("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
2818
3062
  const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
2819
3063
  const rangeEnd = Math.min(currentPage * pageSize, total);
2820
- return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5("span", { style: { color: "GrayText", fontSize: 12 }, children: [
2821
- "Showing",
2822
- " ",
2823
- pagination.showTotal(total, [rangeStart, rangeEnd]),
2824
- " of",
2825
- " ",
2826
- total,
2827
- " items"
2828
- ] }) : /* @__PURE__ */ jsxs5("span", { style: { color: "GrayText", fontSize: 12 }, children: [
2829
- rangeStart,
2830
- "\u2013",
2831
- rangeEnd,
2832
- " of ",
2833
- total
2834
- ] });
3064
+ return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5(
3065
+ "span",
3066
+ {
3067
+ className: classNames.paginationInfo ?? "",
3068
+ style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3069
+ children: [
3070
+ "Showing",
3071
+ " ",
3072
+ pagination.showTotal(total, [rangeStart, rangeEnd]),
3073
+ " of",
3074
+ " ",
3075
+ total,
3076
+ " items"
3077
+ ]
3078
+ }
3079
+ ) : /* @__PURE__ */ jsxs5(
3080
+ "span",
3081
+ {
3082
+ className: classNames.paginationInfo ?? "",
3083
+ style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3084
+ children: [
3085
+ rangeStart,
3086
+ "\u2013",
3087
+ rangeEnd,
3088
+ " of ",
3089
+ total
3090
+ ]
3091
+ }
3092
+ );
2835
3093
  })() }),
2836
3094
  /* @__PURE__ */ jsxs5(
2837
3095
  "div",
@@ -2849,6 +3107,7 @@ function BoltTable({
2849
3107
  {
2850
3108
  onClick: () => handlePageChange(1),
2851
3109
  disabled: currentPage === 1,
3110
+ className: classNames.paginationButton ?? "",
2852
3111
  style: {
2853
3112
  display: "inline-flex",
2854
3113
  height: 24,
@@ -2861,7 +3120,8 @@ function BoltTable({
2861
3120
  background: "none",
2862
3121
  border: "none",
2863
3122
  padding: 0,
2864
- color: "inherit"
3123
+ color: "inherit",
3124
+ ...styles.paginationButton
2865
3125
  },
2866
3126
  title: "First page",
2867
3127
  children: icons?.chevronsLeft ?? /* @__PURE__ */ jsx5(ChevronsLeftIcon, { style: { width: 12, height: 12 } })
@@ -2872,6 +3132,7 @@ function BoltTable({
2872
3132
  {
2873
3133
  onClick: () => handlePageChange(currentPage - 1),
2874
3134
  disabled: currentPage === 1,
3135
+ className: classNames.paginationButton ?? "",
2875
3136
  style: {
2876
3137
  display: "inline-flex",
2877
3138
  height: 24,
@@ -2884,7 +3145,8 @@ function BoltTable({
2884
3145
  background: "none",
2885
3146
  border: "none",
2886
3147
  padding: 0,
2887
- color: "inherit"
3148
+ color: "inherit",
3149
+ ...styles.paginationButton
2888
3150
  },
2889
3151
  title: "Previous page",
2890
3152
  children: icons?.chevronLeft ?? /* @__PURE__ */ jsx5(ChevronLeftIcon, { style: { width: 12, height: 12 } })
@@ -2907,9 +3169,11 @@ function BoltTable({
2907
3169
  page
2908
3170
  );
2909
3171
  }
3172
+ const isActivePage = page === currentPage;
2910
3173
  return /* @__PURE__ */ jsx5(
2911
3174
  "button",
2912
3175
  {
3176
+ className: `${classNames.paginationButton ?? ""} ${isActivePage ? classNames.paginationActiveButton ?? "" : ""}`.trim() || void 0,
2913
3177
  style: {
2914
3178
  display: "inline-flex",
2915
3179
  height: 24,
@@ -2921,9 +3185,11 @@ function BoltTable({
2921
3185
  paddingLeft: 6,
2922
3186
  paddingRight: 6,
2923
3187
  fontSize: 12,
2924
- color: page === currentPage ? accentColor : void 0,
3188
+ color: isActivePage ? accentColor : void 0,
2925
3189
  background: "none",
2926
- border: "none"
3190
+ border: "none",
3191
+ ...styles.paginationButton,
3192
+ ...isActivePage ? styles.paginationActiveButton : void 0
2927
3193
  },
2928
3194
  onClick: () => handlePageChange(page),
2929
3195
  children: page
@@ -2936,6 +3202,7 @@ function BoltTable({
2936
3202
  {
2937
3203
  onClick: () => handlePageChange(currentPage + 1),
2938
3204
  disabled: currentPage === totalPages,
3205
+ className: classNames.paginationButton ?? "",
2939
3206
  style: {
2940
3207
  display: "inline-flex",
2941
3208
  height: 24,
@@ -2948,7 +3215,8 @@ function BoltTable({
2948
3215
  background: "none",
2949
3216
  border: "none",
2950
3217
  padding: 0,
2951
- color: "inherit"
3218
+ color: "inherit",
3219
+ ...styles.paginationButton
2952
3220
  },
2953
3221
  title: "Next page",
2954
3222
  children: icons?.chevronRight ?? /* @__PURE__ */ jsx5(ChevronRightIcon, { style: { width: 12, height: 12 } })
@@ -2959,6 +3227,7 @@ function BoltTable({
2959
3227
  {
2960
3228
  onClick: () => handlePageChange(totalPages),
2961
3229
  disabled: currentPage === totalPages,
3230
+ className: classNames.paginationButton ?? "",
2962
3231
  style: {
2963
3232
  display: "inline-flex",
2964
3233
  height: 24,
@@ -2971,7 +3240,8 @@ function BoltTable({
2971
3240
  background: "none",
2972
3241
  border: "none",
2973
3242
  padding: 0,
2974
- color: "inherit"
3243
+ color: "inherit",
3244
+ ...styles.paginationButton
2975
3245
  },
2976
3246
  title: "Last page",
2977
3247
  children: icons?.chevronsRight ?? /* @__PURE__ */ jsx5(ChevronsRightIcon, { style: { width: 12, height: 12 } })
@@ -2995,6 +3265,7 @@ function BoltTable({
2995
3265
  {
2996
3266
  value: pageSize,
2997
3267
  onChange: (e) => handlePageSizeChange(Number(e.target.value)),
3268
+ className: classNames.paginationSelect ?? "",
2998
3269
  style: {
2999
3270
  cursor: "pointer",
3000
3271
  borderRadius: 4,
@@ -3006,7 +3277,8 @@ function BoltTable({
3006
3277
  fontSize: 12,
3007
3278
  height: 24,
3008
3279
  background: "inherit",
3009
- color: "inherit"
3280
+ color: "inherit",
3281
+ ...styles.paginationSelect
3010
3282
  },
3011
3283
  children: (typeof pagination === "object" && pagination?.pageSizeOptions ? pagination.pageSizeOptions : [10, 15, 20, 25, 50, 100]).map((size) => /* @__PURE__ */ jsxs5("option", { value: size, children: [
3012
3284
  size,
@@ -3101,6 +3373,7 @@ function BoltTable({
3101
3373
  );
3102
3374
  const hasCopy = !!menuCol?.copy;
3103
3375
  const hasRowPin = !!rowPinning;
3376
+ const hasEdit = !!menuCol?.editable && !menuCol?.render && !!onEdit;
3104
3377
  let menuRecord;
3105
3378
  let menuRowIndex = 0;
3106
3379
  const allRows = [
@@ -3117,7 +3390,7 @@ function BoltTable({
3117
3390
  break;
3118
3391
  }
3119
3392
  }
3120
- const menuValue = menuRecord && menuCol ? menuRecord[menuCol.dataIndex] : void 0;
3393
+ const menuValue = menuRecord && menuCol?.dataIndex != null ? menuRecord[menuCol.dataIndex] : void 0;
3121
3394
  const btnStyle = {
3122
3395
  display: "flex",
3123
3396
  width: "100%",
@@ -3216,7 +3489,39 @@ function BoltTable({
3216
3489
  }
3217
3490
  )
3218
3491
  ] }),
3219
- hasRowPin && hasCopy && /* @__PURE__ */ jsx5(
3492
+ hasRowPin && (hasCopy || hasEdit) && /* @__PURE__ */ jsx5(
3493
+ "div",
3494
+ {
3495
+ style: {
3496
+ borderTop: "1px solid rgba(128,128,128,0.2)",
3497
+ margin: "4px 0"
3498
+ }
3499
+ }
3500
+ ),
3501
+ hasEdit && /* @__PURE__ */ jsxs5(
3502
+ "button",
3503
+ {
3504
+ "data-bt-ctx-item": true,
3505
+ style: btnStyle,
3506
+ onClick: () => {
3507
+ setEditingCell({
3508
+ rowKey: cellContextMenu.rowKey,
3509
+ columnKey: cellContextMenu.columnKey
3510
+ });
3511
+ setCellContextMenu(null);
3512
+ },
3513
+ children: [
3514
+ icons?.edit ?? /* @__PURE__ */ jsx5(
3515
+ PencilIcon,
3516
+ {
3517
+ style: { width: 14, height: 14, flexShrink: 0 }
3518
+ }
3519
+ ),
3520
+ "Edit"
3521
+ ]
3522
+ }
3523
+ ),
3524
+ (hasEdit || hasRowPin) && hasCopy && /* @__PURE__ */ jsx5(
3220
3525
  "div",
3221
3526
  {
3222
3527
  style: {
@@ -3233,6 +3538,7 @@ function BoltTable({
3233
3538
  onClick: () => {
3234
3539
  const text = typeof menuCol.copy === "function" ? menuCol.copy(menuValue, menuRecord, menuRowIndex) : String(menuValue ?? "");
3235
3540
  navigator.clipboard?.writeText(text);
3541
+ onCopy?.(text, menuCol.key, menuRecord, menuRowIndex);
3236
3542
  setCellContextMenu(null);
3237
3543
  },
3238
3544
  children: [
@@ -3247,7 +3553,7 @@ function BoltTable({
3247
3553
  }
3248
3554
  ),
3249
3555
  menuCol?.columnCellContextMenuItems && menuCol.columnCellContextMenuItems.length > 0 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
3250
- (hasCopy || hasRowPin) && /* @__PURE__ */ jsx5(
3556
+ (hasCopy || hasRowPin || hasEdit) && /* @__PURE__ */ jsx5(
3251
3557
  "div",
3252
3558
  {
3253
3559
  style: {