bolt-table 0.1.23 → 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 = {};
@@ -1479,7 +1587,8 @@ function BoltTable({
1479
1587
  rowStyle,
1480
1588
  disabledFilters,
1481
1589
  onCopy,
1482
- keepPinnedRowsAcrossPages
1590
+ keepPinnedRowsAcrossPages,
1591
+ onEdit
1483
1592
  }) {
1484
1593
  const data = useMemo2(() => {
1485
1594
  if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
@@ -1488,17 +1597,49 @@ function BoltTable({
1488
1597
  }, [rawData]);
1489
1598
  const initialColumns = useMemo2(() => {
1490
1599
  if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1491
- const filtered = rawInitialColumns.filter(
1600
+ const safe = rawInitialColumns.filter(
1492
1601
  (col) => col != null && typeof col.key === "string"
1493
1602
  );
1494
- 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;
1495
1627
  }, [rawInitialColumns]);
1496
- const [columns, setColumns] = useState2(initialColumns);
1497
- 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(
1498
1639
  () => initialColumns.map((c) => c.key)
1499
1640
  );
1500
- const [activeId, setActiveId] = useState2(null);
1501
- const [mounted, setMounted] = useState2(false);
1641
+ const [activeId, setActiveId] = useState3(null);
1642
+ const [mounted, setMounted] = useState3(false);
1502
1643
  React4.useEffect(() => {
1503
1644
  setMounted(true);
1504
1645
  }, []);
@@ -1516,7 +1657,7 @@ function BoltTable({
1516
1657
  setColumnOrder(initialColumnsRef.current.map((c) => c.key));
1517
1658
  }, [newFingerprint]);
1518
1659
  const safeWidth = (w, fallback = 150) => typeof w === "number" && Number.isFinite(w) ? w : fallback;
1519
- const [columnWidths, setColumnWidths] = useState2(
1660
+ const [columnWidths, setColumnWidths] = useState3(
1520
1661
  () => /* @__PURE__ */ new Map()
1521
1662
  );
1522
1663
  const manuallyResizedRef = useRef4(/* @__PURE__ */ new Set());
@@ -1527,7 +1668,7 @@ function BoltTable({
1527
1668
  })),
1528
1669
  [columns, columnWidths]
1529
1670
  );
1530
- const [internalExpandedKeys, setInternalExpandedKeys] = useState2(() => {
1671
+ const [internalExpandedKeys, setInternalExpandedKeys] = useState3(() => {
1531
1672
  if (expandable?.defaultExpandAllRows && data.length > 0) {
1532
1673
  return new Set(
1533
1674
  data.map((row, idx) => {
@@ -1553,7 +1694,7 @@ function BoltTable({
1553
1694
  }, [expandedKeysFingerprint, internalExpandedKeys]);
1554
1695
  const expandableRef = useRef4(expandable);
1555
1696
  expandableRef.current = expandable;
1556
- const toggleExpand = useCallback((key) => {
1697
+ const toggleExpand = useCallback2((key) => {
1557
1698
  const exp = expandableRef.current;
1558
1699
  if (exp?.expandedRowKeys !== void 0) {
1559
1700
  const next = new Set(exp.expandedRowKeys);
@@ -1568,7 +1709,7 @@ function BoltTable({
1568
1709
  });
1569
1710
  }
1570
1711
  }, []);
1571
- const getRowKey = useCallback(
1712
+ const getRowKey = useCallback2(
1572
1713
  (record, index) => {
1573
1714
  if (record == null) return String(index);
1574
1715
  try {
@@ -1584,7 +1725,7 @@ function BoltTable({
1584
1725
  },
1585
1726
  [rowKey]
1586
1727
  );
1587
- const getRawRowKey = useCallback(
1728
+ const getRawRowKey = useCallback2(
1588
1729
  (record, index) => {
1589
1730
  if (record == null) return index;
1590
1731
  try {
@@ -1683,11 +1824,11 @@ function BoltTable({
1683
1824
  }, [rowSelection, columnsWithExpand]);
1684
1825
  const resizeOverlayRef = useRef4(null);
1685
1826
  const tableAreaRef = useRef4(null);
1686
- const [scrollAreaWidth, setScrollAreaWidth] = useState2(0);
1827
+ const [scrollAreaWidth, setScrollAreaWidth] = useState3(0);
1687
1828
  const prevScrollAreaWidthRef = useRef4(0);
1688
1829
  const roRef = useRef4(null);
1689
1830
  const rafRef = useRef4(null);
1690
- const tableAreaCallbackRef = useCallback((el) => {
1831
+ const tableAreaCallbackRef = useCallback2((el) => {
1691
1832
  roRef.current?.disconnect();
1692
1833
  roRef.current = null;
1693
1834
  if (rafRef.current !== null) {
@@ -1745,12 +1886,23 @@ function BoltTable({
1745
1886
  };
1746
1887
  }, []);
1747
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]);
1748
1900
  const overIdRef = useRef4(null);
1749
1901
  const dragActiveIdRef = useRef4(null);
1750
1902
  const ghostRef = useRef4(null);
1751
1903
  const onColumnOrderChangeRef = useRef4(onColumnOrderChange);
1752
1904
  onColumnOrderChangeRef.current = onColumnOrderChange;
1753
- const handleColumnDragStart = useCallback(
1905
+ const handleColumnDragStart = useCallback2(
1754
1906
  (columnKey, e) => {
1755
1907
  if (columnKey === "__select__" || columnKey === "__expand__") return;
1756
1908
  const headerEl = e.currentTarget.closest(
@@ -1773,6 +1925,7 @@ function BoltTable({
1773
1925
  const grabStyle = document.createElement("style");
1774
1926
  grabStyle.textContent = "* { cursor: grabbing !important; }";
1775
1927
  document.head.appendChild(grabStyle);
1928
+ const draggedGroup = columnGroupMapRef.current.get(columnKey);
1776
1929
  const onMove = (ev) => {
1777
1930
  if (ghost) {
1778
1931
  ghost.style.left = `${ev.clientX - offsetX}px`;
@@ -1788,6 +1941,11 @@ function BoltTable({
1788
1941
  h.removeAttribute("data-drag-over");
1789
1942
  return;
1790
1943
  }
1944
+ const targetGroup = columnGroupMapRef.current.get(key);
1945
+ if (draggedGroup !== targetGroup) {
1946
+ h.removeAttribute("data-drag-over");
1947
+ return;
1948
+ }
1791
1949
  const r = h.getBoundingClientRect();
1792
1950
  if (ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top - 20 && ev.clientY <= r.bottom + 20) {
1793
1951
  newOverId = key;
@@ -1810,7 +1968,7 @@ function BoltTable({
1810
1968
  if (ghost) ghost.style.display = "none";
1811
1969
  const currentOverId = overIdRef.current;
1812
1970
  const currentActiveId = dragActiveIdRef.current;
1813
- if (currentOverId && currentActiveId && currentOverId !== currentActiveId) {
1971
+ if (currentOverId && currentActiveId && currentOverId !== currentActiveId && columnGroupMapRef.current.get(currentActiveId) === columnGroupMapRef.current.get(currentOverId)) {
1814
1972
  React4.startTransition(() => {
1815
1973
  setColumnOrder((items) => {
1816
1974
  const oldIndex = items.indexOf(currentActiveId);
@@ -1977,9 +2135,9 @@ function BoltTable({
1977
2135
  const column = columns.find((col) => col.key === columnKey);
1978
2136
  if (column && !column.pinned) onColumnHide?.(columnKey, !column.hidden);
1979
2137
  };
1980
- const [internalRowPinning, setInternalRowPinning] = useState2({ top: [], bottom: [] });
2138
+ const [internalRowPinning, setInternalRowPinning] = useState3({ top: [], bottom: [] });
1981
2139
  const resolvedRowPinning = rowPinning === true ? internalRowPinning : rowPinning && typeof rowPinning === "object" ? rowPinning : void 0;
1982
- const handleRowPin = useCallback((rk, pinned) => {
2140
+ const handleRowPin = useCallback2((rk, pinned) => {
1983
2141
  if (onRowPin) {
1984
2142
  onRowPin(rk, pinned);
1985
2143
  return;
@@ -1997,8 +2155,8 @@ function BoltTable({
1997
2155
  }, [onRowPin, rowPinning]);
1998
2156
  const onSortChangeRef = useRef4(onSortChange);
1999
2157
  onSortChangeRef.current = onSortChange;
2000
- const [sortState, setSortState] = useState2({ key: "", direction: null });
2001
- const handleSort = useCallback(
2158
+ const [sortState, setSortState] = useState3({ key: "", direction: null });
2159
+ const handleSort = useCallback2(
2002
2160
  (columnKey, direction) => {
2003
2161
  setSortState((prev) => {
2004
2162
  let next;
@@ -2014,10 +2172,10 @@ function BoltTable({
2014
2172
  },
2015
2173
  []
2016
2174
  );
2017
- const [columnFilters, setColumnFilters] = useState2(
2175
+ const [columnFilters, setColumnFilters] = useState3(
2018
2176
  {}
2019
2177
  );
2020
- const handleColumnFilter = useCallback(
2178
+ const handleColumnFilter = useCallback2(
2021
2179
  (columnKey, value) => {
2022
2180
  setColumnFilters((prev) => {
2023
2181
  const next = { ...prev };
@@ -2029,7 +2187,7 @@ function BoltTable({
2029
2187
  },
2030
2188
  [onFilterChange]
2031
2189
  );
2032
- const handleClearFilter = useCallback(
2190
+ const handleClearFilter = useCallback2(
2033
2191
  (columnKey) => {
2034
2192
  handleColumnFilter(columnKey, "");
2035
2193
  },
@@ -2050,7 +2208,7 @@ function BoltTable({
2050
2208
  try {
2051
2209
  const col = columnsLookupRef.current.find((c) => c.key === key);
2052
2210
  if (typeof col?.filterFn === "function") {
2053
- return col.filterFn(columnFilters[key], row, col.dataIndex);
2211
+ return col.filterFn(columnFilters[key], row, col.dataIndex ?? key);
2054
2212
  }
2055
2213
  const cellVal = String(row[key] ?? "").toLowerCase();
2056
2214
  return cellVal.includes(columnFilters[key].toLowerCase());
@@ -2156,13 +2314,17 @@ function BoltTable({
2156
2314
  () => new Set((resolvedRowPinning?.bottom ?? []).map(String)),
2157
2315
  [resolvedRowPinning?.bottom]
2158
2316
  );
2159
- 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);
2160
2322
  const cellMenuRef = useRef4(null);
2161
2323
  const cellLongPressTimer = useRef4(
2162
2324
  null
2163
2325
  );
2164
2326
  const cellTouchStart = useRef4(null);
2165
- const cancelCellLongPress = useCallback(() => {
2327
+ const cancelCellLongPress = useCallback2(() => {
2166
2328
  if (cellLongPressTimer.current) {
2167
2329
  clearTimeout(cellLongPressTimer.current);
2168
2330
  cellLongPressTimer.current = null;
@@ -2192,8 +2354,8 @@ function BoltTable({
2192
2354
  tableAreaRef.current?.scrollTo({ top: 0 });
2193
2355
  }, [columnFiltersKey]);
2194
2356
  const DEFAULT_PAGE_SIZE = 15;
2195
- const [internalPage, setInternalPage] = useState2(1);
2196
- const [internalPageSize, setInternalPageSize] = useState2(DEFAULT_PAGE_SIZE);
2357
+ const [internalPage, setInternalPage] = useState3(1);
2358
+ const [internalPageSize, setInternalPageSize] = useState3(DEFAULT_PAGE_SIZE);
2197
2359
  const dataLength = data.length;
2198
2360
  const autoPagination = pagination === void 0 && dataLength > DEFAULT_PAGE_SIZE;
2199
2361
  const pgEnabled = pagination === false ? false : !!pagination || autoPagination;
@@ -2237,7 +2399,7 @@ function BoltTable({
2237
2399
  }, [shimmerData, infiniteLoadingShimmer, paginatedData]);
2238
2400
  const measuredExpandedHeights = useRef4(/* @__PURE__ */ new Map());
2239
2401
  const expandedRowMeasureRafRef = useRef4(null);
2240
- const handleExpandedRowResize = useCallback(
2402
+ const handleExpandedRowResize = useCallback2(
2241
2403
  (rk, contentHeight) => {
2242
2404
  const prev = measuredExpandedHeights.current.get(rk);
2243
2405
  const rounded = Math.round(contentHeight);
@@ -2366,7 +2528,7 @@ function BoltTable({
2366
2528
  totalPages
2367
2529
  ];
2368
2530
  };
2369
- const HEADER_HEIGHT = 36;
2531
+ const HEADER_HEIGHT = hasColumnGroups ? 72 : 36;
2370
2532
  const MAX_AUTO_ROWS = 10;
2371
2533
  const virtualTotalSize = rowVirtualizer.getTotalSize();
2372
2534
  const naturalContentHeight = virtualTotalSize + HEADER_HEIGHT;
@@ -2561,7 +2723,7 @@ function BoltTable({
2561
2723
  style: {
2562
2724
  display: "grid",
2563
2725
  gridTemplateColumns,
2564
- gridTemplateRows: isEmpty ? "36px 1fr" : `36px ${virtualTotalSize}px`,
2726
+ gridTemplateRows: isEmpty ? hasColumnGroups ? "36px 36px 1fr" : "36px 1fr" : hasColumnGroups ? `36px 36px ${virtualTotalSize}px` : `36px ${virtualTotalSize}px`,
2565
2727
  minWidth: `${totalTableWidth}px`,
2566
2728
  width: "100%",
2567
2729
  position: "relative",
@@ -2579,7 +2741,8 @@ function BoltTable({
2579
2741
  const hasCopy = !!col?.copy;
2580
2742
  const hasRowPin = !!rowPinning;
2581
2743
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2582
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2744
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2745
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2583
2746
  e.preventDefault();
2584
2747
  setCellContextMenu({
2585
2748
  x: Math.min(e.clientX, window.innerWidth - 200),
@@ -2608,7 +2771,8 @@ function BoltTable({
2608
2771
  const hasCopy = !!col?.copy;
2609
2772
  const hasRowPin = !!rowPinning;
2610
2773
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2611
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2774
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2775
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2612
2776
  setCellContextMenu({
2613
2777
  x: Math.min(touch.clientX, window.innerWidth - 200),
2614
2778
  y: Math.min(touch.clientY, window.innerHeight - 200),
@@ -2628,7 +2792,50 @@ function BoltTable({
2628
2792
  onTouchEnd: cancelCellLongPress,
2629
2793
  onTouchCancel: cancelCellLongPress,
2630
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
+ }),
2631
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;
2632
2839
  if (column.key === "__select__" && rowSelection) {
2633
2840
  return /* @__PURE__ */ jsx5(
2634
2841
  "div",
@@ -2638,7 +2845,7 @@ function BoltTable({
2638
2845
  className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2639
2846
  style: {
2640
2847
  display: "flex",
2641
- height: 36,
2848
+ height: leafHeight,
2642
2849
  alignItems: "center",
2643
2850
  justifyContent: "center",
2644
2851
  overflow: "hidden",
@@ -2650,6 +2857,7 @@ function BoltTable({
2650
2857
  top: 0,
2651
2858
  zIndex: 13,
2652
2859
  width: "48px",
2860
+ gridRow: leafGridRow,
2653
2861
  ...styles.header,
2654
2862
  ...styles.pinnedHeader
2655
2863
  },
@@ -2683,7 +2891,7 @@ function BoltTable({
2683
2891
  });
2684
2892
  }
2685
2893
  },
2686
- style: { cursor: "pointer", accentColor }
2894
+ style: { cursor: "pointer", accentColor, colorScheme: "light dark" }
2687
2895
  }
2688
2896
  )
2689
2897
  },
@@ -2699,7 +2907,7 @@ function BoltTable({
2699
2907
  className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2700
2908
  style: {
2701
2909
  display: "flex",
2702
- height: 36,
2910
+ height: leafHeight,
2703
2911
  alignItems: "center",
2704
2912
  justifyContent: "center",
2705
2913
  overflow: "hidden",
@@ -2711,6 +2919,7 @@ function BoltTable({
2711
2919
  top: 0,
2712
2920
  zIndex: 13,
2713
2921
  width: "40px",
2922
+ gridRow: leafGridRow,
2714
2923
  ...styles.header,
2715
2924
  ...styles.pinnedHeader
2716
2925
  }
@@ -2741,7 +2950,10 @@ function BoltTable({
2741
2950
  onFilter: handleColumnFilter,
2742
2951
  onClearFilter: handleClearFilter,
2743
2952
  customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
2744
- disabledFilters
2953
+ disabledFilters,
2954
+ headerGridRow: leafGridRow,
2955
+ headerHeight: leafHeight,
2956
+ stickyTop: leafStickyTop
2745
2957
  },
2746
2958
  column.key
2747
2959
  );
@@ -2812,7 +3024,11 @@ function BoltTable({
2812
3024
  gridTemplateColumns,
2813
3025
  headerHeight: HEADER_HEIGHT,
2814
3026
  rowClassName,
2815
- rowStyle
3027
+ rowStyle,
3028
+ bodyGridRow: hasColumnGroups ? 3 : 2,
3029
+ onEdit,
3030
+ editingCell,
3031
+ onEditComplete: handleEditComplete
2816
3032
  }
2817
3033
  )
2818
3034
  ]
@@ -2826,6 +3042,7 @@ function BoltTable({
2826
3042
  pgEnabled && /* @__PURE__ */ jsxs5(
2827
3043
  "div",
2828
3044
  {
3045
+ className: classNames.pagination ?? "",
2829
3046
  style: {
2830
3047
  display: "flex",
2831
3048
  height: 36,
@@ -2837,27 +3054,42 @@ function BoltTable({
2837
3054
  fontSize: 12,
2838
3055
  backdropFilter: "blur(8px)",
2839
3056
  backgroundColor: "rgba(128,128,128,0.06)",
2840
- gap: 12
3057
+ gap: 12,
3058
+ ...styles.pagination
2841
3059
  },
2842
3060
  children: [
2843
3061
  /* @__PURE__ */ jsx5("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
2844
3062
  const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
2845
3063
  const rangeEnd = Math.min(currentPage * pageSize, total);
2846
- return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5("span", { style: { color: "GrayText", fontSize: 12 }, children: [
2847
- "Showing",
2848
- " ",
2849
- pagination.showTotal(total, [rangeStart, rangeEnd]),
2850
- " of",
2851
- " ",
2852
- total,
2853
- " items"
2854
- ] }) : /* @__PURE__ */ jsxs5("span", { style: { color: "GrayText", fontSize: 12 }, children: [
2855
- rangeStart,
2856
- "\u2013",
2857
- rangeEnd,
2858
- " of ",
2859
- total
2860
- ] });
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
+ );
2861
3093
  })() }),
2862
3094
  /* @__PURE__ */ jsxs5(
2863
3095
  "div",
@@ -2875,6 +3107,7 @@ function BoltTable({
2875
3107
  {
2876
3108
  onClick: () => handlePageChange(1),
2877
3109
  disabled: currentPage === 1,
3110
+ className: classNames.paginationButton ?? "",
2878
3111
  style: {
2879
3112
  display: "inline-flex",
2880
3113
  height: 24,
@@ -2887,7 +3120,8 @@ function BoltTable({
2887
3120
  background: "none",
2888
3121
  border: "none",
2889
3122
  padding: 0,
2890
- color: "inherit"
3123
+ color: "inherit",
3124
+ ...styles.paginationButton
2891
3125
  },
2892
3126
  title: "First page",
2893
3127
  children: icons?.chevronsLeft ?? /* @__PURE__ */ jsx5(ChevronsLeftIcon, { style: { width: 12, height: 12 } })
@@ -2898,6 +3132,7 @@ function BoltTable({
2898
3132
  {
2899
3133
  onClick: () => handlePageChange(currentPage - 1),
2900
3134
  disabled: currentPage === 1,
3135
+ className: classNames.paginationButton ?? "",
2901
3136
  style: {
2902
3137
  display: "inline-flex",
2903
3138
  height: 24,
@@ -2910,7 +3145,8 @@ function BoltTable({
2910
3145
  background: "none",
2911
3146
  border: "none",
2912
3147
  padding: 0,
2913
- color: "inherit"
3148
+ color: "inherit",
3149
+ ...styles.paginationButton
2914
3150
  },
2915
3151
  title: "Previous page",
2916
3152
  children: icons?.chevronLeft ?? /* @__PURE__ */ jsx5(ChevronLeftIcon, { style: { width: 12, height: 12 } })
@@ -2933,9 +3169,11 @@ function BoltTable({
2933
3169
  page
2934
3170
  );
2935
3171
  }
3172
+ const isActivePage = page === currentPage;
2936
3173
  return /* @__PURE__ */ jsx5(
2937
3174
  "button",
2938
3175
  {
3176
+ className: `${classNames.paginationButton ?? ""} ${isActivePage ? classNames.paginationActiveButton ?? "" : ""}`.trim() || void 0,
2939
3177
  style: {
2940
3178
  display: "inline-flex",
2941
3179
  height: 24,
@@ -2947,9 +3185,11 @@ function BoltTable({
2947
3185
  paddingLeft: 6,
2948
3186
  paddingRight: 6,
2949
3187
  fontSize: 12,
2950
- color: page === currentPage ? accentColor : void 0,
3188
+ color: isActivePage ? accentColor : void 0,
2951
3189
  background: "none",
2952
- border: "none"
3190
+ border: "none",
3191
+ ...styles.paginationButton,
3192
+ ...isActivePage ? styles.paginationActiveButton : void 0
2953
3193
  },
2954
3194
  onClick: () => handlePageChange(page),
2955
3195
  children: page
@@ -2962,6 +3202,7 @@ function BoltTable({
2962
3202
  {
2963
3203
  onClick: () => handlePageChange(currentPage + 1),
2964
3204
  disabled: currentPage === totalPages,
3205
+ className: classNames.paginationButton ?? "",
2965
3206
  style: {
2966
3207
  display: "inline-flex",
2967
3208
  height: 24,
@@ -2974,7 +3215,8 @@ function BoltTable({
2974
3215
  background: "none",
2975
3216
  border: "none",
2976
3217
  padding: 0,
2977
- color: "inherit"
3218
+ color: "inherit",
3219
+ ...styles.paginationButton
2978
3220
  },
2979
3221
  title: "Next page",
2980
3222
  children: icons?.chevronRight ?? /* @__PURE__ */ jsx5(ChevronRightIcon, { style: { width: 12, height: 12 } })
@@ -2985,6 +3227,7 @@ function BoltTable({
2985
3227
  {
2986
3228
  onClick: () => handlePageChange(totalPages),
2987
3229
  disabled: currentPage === totalPages,
3230
+ className: classNames.paginationButton ?? "",
2988
3231
  style: {
2989
3232
  display: "inline-flex",
2990
3233
  height: 24,
@@ -2997,7 +3240,8 @@ function BoltTable({
2997
3240
  background: "none",
2998
3241
  border: "none",
2999
3242
  padding: 0,
3000
- color: "inherit"
3243
+ color: "inherit",
3244
+ ...styles.paginationButton
3001
3245
  },
3002
3246
  title: "Last page",
3003
3247
  children: icons?.chevronsRight ?? /* @__PURE__ */ jsx5(ChevronsRightIcon, { style: { width: 12, height: 12 } })
@@ -3021,6 +3265,7 @@ function BoltTable({
3021
3265
  {
3022
3266
  value: pageSize,
3023
3267
  onChange: (e) => handlePageSizeChange(Number(e.target.value)),
3268
+ className: classNames.paginationSelect ?? "",
3024
3269
  style: {
3025
3270
  cursor: "pointer",
3026
3271
  borderRadius: 4,
@@ -3032,7 +3277,8 @@ function BoltTable({
3032
3277
  fontSize: 12,
3033
3278
  height: 24,
3034
3279
  background: "inherit",
3035
- color: "inherit"
3280
+ color: "inherit",
3281
+ ...styles.paginationSelect
3036
3282
  },
3037
3283
  children: (typeof pagination === "object" && pagination?.pageSizeOptions ? pagination.pageSizeOptions : [10, 15, 20, 25, 50, 100]).map((size) => /* @__PURE__ */ jsxs5("option", { value: size, children: [
3038
3284
  size,
@@ -3127,6 +3373,7 @@ function BoltTable({
3127
3373
  );
3128
3374
  const hasCopy = !!menuCol?.copy;
3129
3375
  const hasRowPin = !!rowPinning;
3376
+ const hasEdit = !!menuCol?.editable && !menuCol?.render && !!onEdit;
3130
3377
  let menuRecord;
3131
3378
  let menuRowIndex = 0;
3132
3379
  const allRows = [
@@ -3143,7 +3390,7 @@ function BoltTable({
3143
3390
  break;
3144
3391
  }
3145
3392
  }
3146
- const menuValue = menuRecord && menuCol ? menuRecord[menuCol.dataIndex] : void 0;
3393
+ const menuValue = menuRecord && menuCol?.dataIndex != null ? menuRecord[menuCol.dataIndex] : void 0;
3147
3394
  const btnStyle = {
3148
3395
  display: "flex",
3149
3396
  width: "100%",
@@ -3242,7 +3489,39 @@ function BoltTable({
3242
3489
  }
3243
3490
  )
3244
3491
  ] }),
3245
- 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(
3246
3525
  "div",
3247
3526
  {
3248
3527
  style: {
@@ -3274,7 +3553,7 @@ function BoltTable({
3274
3553
  }
3275
3554
  ),
3276
3555
  menuCol?.columnCellContextMenuItems && menuCol.columnCellContextMenuItems.length > 0 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
3277
- (hasCopy || hasRowPin) && /* @__PURE__ */ jsx5(
3556
+ (hasCopy || hasRowPin || hasEdit) && /* @__PURE__ */ jsx5(
3278
3557
  "div",
3279
3558
  {
3280
3559
  style: {