bolt-table 0.1.23 → 0.1.25

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,11 @@ 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,
128
+ isFirstColumn = false
121
129
  }) => {
122
130
  const effectivelySortable = isColumnSortable(column);
123
131
  const effectivelyFilterable = !disabledFilters && isColumnFilterable(column);
@@ -191,23 +199,23 @@ var DraggableHeader = React.memo(
191
199
  const zIndex = isPinned ? 12 : 10;
192
200
  const headerStyle = {
193
201
  position: "sticky",
194
- top: 0,
202
+ top: stickyTop,
195
203
  zIndex,
196
204
  width: isLastColumn ? "100%" : widthPx,
197
205
  minWidth: widthPx,
198
206
  ...isLastColumn ? {} : { maxWidth: widthPx },
199
207
  gridColumn: visualIndex + 1,
200
- gridRow: 1,
208
+ gridRow: headerGridRow,
201
209
  display: "flex",
202
- height: 36,
210
+ height: headerHeight,
203
211
  alignItems: "center",
204
212
  overflow: "hidden",
205
213
  textOverflow: "ellipsis",
206
214
  whiteSpace: "nowrap",
207
215
  borderTop: "none",
208
- borderRight: "none",
216
+ borderRight: "0.5px solid rgba(128,128,128,0.2)",
209
217
  borderBottom: "1px solid rgba(128,128,128,0.2)",
210
- borderLeft: "none",
218
+ borderLeft: isFirstColumn ? "none" : "0.5px solid rgba(128,128,128,0.2)",
211
219
  ...column.pinned === "left" && stickyOffset !== void 0 ? { left: `${stickyOffset}px` } : {},
212
220
  ...column.pinned === "right" && stickyOffset !== void 0 ? { right: `${stickyOffset}px` } : {},
213
221
  ...column.style,
@@ -254,7 +262,7 @@ var DraggableHeader = React.memo(
254
262
  whiteSpace: "nowrap",
255
263
  paddingLeft: 8,
256
264
  paddingRight: 8,
257
- borderLeft: "1px solid rgba(128,128,128,0.2)",
265
+ borderLeft: isFirstColumn ? "none" : "1px solid rgba(128,128,128,0.2)",
258
266
  fontWeight: 500,
259
267
  cursor: isPinned ? "default" : "grab"
260
268
  },
@@ -289,6 +297,7 @@ var DraggableHeader = React.memo(
289
297
  isPinned && /* @__PURE__ */ jsx2(
290
298
  "button",
291
299
  {
300
+ type: "button",
292
301
  style: {
293
302
  position: "relative",
294
303
  height: "100%",
@@ -316,6 +325,7 @@ var DraggableHeader = React.memo(
316
325
  !isPinned && /* @__PURE__ */ jsx2(
317
326
  "button",
318
327
  {
328
+ type: "button",
319
329
  "data-bt-resize": "",
320
330
  style: {
321
331
  position: "relative",
@@ -394,6 +404,7 @@ var DraggableHeader = React.memo(
394
404
  /* @__PURE__ */ jsxs2(
395
405
  "button",
396
406
  {
407
+ type: "button",
397
408
  "data-bt-ctx-item": "",
398
409
  style: {
399
410
  ...ctxItemBase,
@@ -413,6 +424,7 @@ var DraggableHeader = React.memo(
413
424
  /* @__PURE__ */ jsxs2(
414
425
  "button",
415
426
  {
427
+ type: "button",
416
428
  "data-bt-ctx-item": "",
417
429
  style: {
418
430
  ...ctxItemBase,
@@ -470,6 +482,7 @@ var DraggableHeader = React.memo(
470
482
  ) }) : /* @__PURE__ */ jsxs2(
471
483
  "button",
472
484
  {
485
+ type: "button",
473
486
  "data-bt-ctx-item": "",
474
487
  style: ctxItemBase,
475
488
  onClick: () => {
@@ -484,6 +497,7 @@ var DraggableHeader = React.memo(
484
497
  filterValue && /* @__PURE__ */ jsxs2(
485
498
  "button",
486
499
  {
500
+ type: "button",
487
501
  "data-bt-ctx-item": "",
488
502
  style: {
489
503
  ...ctxItemBase,
@@ -505,6 +519,7 @@ var DraggableHeader = React.memo(
505
519
  /* @__PURE__ */ jsxs2(
506
520
  "button",
507
521
  {
522
+ type: "button",
508
523
  "data-bt-ctx-item": "",
509
524
  style: ctxItemBase,
510
525
  onClick: () => {
@@ -523,6 +538,7 @@ var DraggableHeader = React.memo(
523
538
  /* @__PURE__ */ jsxs2(
524
539
  "button",
525
540
  {
541
+ type: "button",
526
542
  "data-bt-ctx-item": "",
527
543
  style: ctxItemBase,
528
544
  onClick: () => {
@@ -543,6 +559,7 @@ var DraggableHeader = React.memo(
543
559
  /* @__PURE__ */ jsxs2(
544
560
  "button",
545
561
  {
562
+ type: "button",
546
563
  "data-bt-ctx-item": "",
547
564
  style: ctxItemBase,
548
565
  onClick: () => {
@@ -561,6 +578,7 @@ var DraggableHeader = React.memo(
561
578
  customContextMenuItems.map((item) => /* @__PURE__ */ jsxs2(
562
579
  "button",
563
580
  {
581
+ type: "button",
564
582
  "data-bt-ctx-item": "",
565
583
  disabled: item.disabled,
566
584
  style: {
@@ -601,7 +619,7 @@ var DraggableHeader = React.memo(
601
619
  ] });
602
620
  },
603
621
  (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;
622
+ 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 && prevProps.isFirstColumn === nextProps.isFirstColumn;
605
623
  }
606
624
  );
607
625
  DraggableHeader.displayName = "DraggableHeader";
@@ -744,9 +762,64 @@ ResizeOverlay.displayName = "ResizeOverlay";
744
762
  var ResizeOverlay_default = ResizeOverlay;
745
763
 
746
764
  // src/TableBody.tsx
747
- import React3, { useEffect as useEffect2, useMemo, useRef as useRef3 } from "react";
765
+ import React3, { useCallback, useEffect as useEffect2, useMemo, useRef as useRef3, useState as useState2 } from "react";
748
766
  import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
749
767
  var SHIMMER_WIDTHS = [55, 70, 45, 80, 60, 50, 75, 65];
768
+ var EditableCell = ({
769
+ value,
770
+ record,
771
+ column,
772
+ rowIndex,
773
+ onEdit,
774
+ onEditComplete
775
+ }) => {
776
+ const [draft, setDraft] = useState2(String(value ?? ""));
777
+ const inputRef = useRef3(null);
778
+ useEffect2(() => {
779
+ setDraft(String(value ?? ""));
780
+ requestAnimationFrame(() => {
781
+ inputRef.current?.focus();
782
+ inputRef.current?.select();
783
+ });
784
+ }, [value]);
785
+ const commit = useCallback(() => {
786
+ const raw = String(value ?? "");
787
+ if (draft !== raw && column.dataIndex) {
788
+ const coerced = typeof value === "number" && !Number.isNaN(Number(draft)) ? Number(draft) : draft;
789
+ onEdit(coerced, record, column.dataIndex, rowIndex);
790
+ }
791
+ onEditComplete();
792
+ }, [draft, value, column.dataIndex, record, rowIndex, onEdit, onEditComplete]);
793
+ const cancel = useCallback(() => {
794
+ onEditComplete();
795
+ }, [onEditComplete]);
796
+ return /* @__PURE__ */ jsx4(
797
+ "input",
798
+ {
799
+ ref: inputRef,
800
+ value: draft,
801
+ onChange: (e) => setDraft(e.target.value),
802
+ onBlur: commit,
803
+ onKeyDown: (e) => {
804
+ if (e.key === "Enter") commit();
805
+ if (e.key === "Escape") cancel();
806
+ },
807
+ style: {
808
+ width: "100%",
809
+ height: "100%",
810
+ border: "none",
811
+ outline: "none",
812
+ background: "transparent",
813
+ font: "inherit",
814
+ color: "inherit",
815
+ padding: 0,
816
+ margin: 0,
817
+ boxSizing: "border-box"
818
+ }
819
+ }
820
+ );
821
+ };
822
+ EditableCell.displayName = "EditableCell";
750
823
  var Cell = React3.memo(
751
824
  ({
752
825
  value,
@@ -762,7 +835,10 @@ var Cell = React3.memo(
762
835
  getRowKey,
763
836
  getRawRowKey,
764
837
  accentColor,
765
- isLoading
838
+ isLoading,
839
+ onEdit,
840
+ isEditing,
841
+ onEditComplete
766
842
  }) => {
767
843
  const isPinned = Boolean(column.pinned);
768
844
  if (isLoading && column.key !== "__select__" && column.key !== "__expand__") {
@@ -841,7 +917,7 @@ var Cell = React3.memo(
841
917
  type: "multiple"
842
918
  });
843
919
  },
844
- style: { cursor: "pointer", accentColor }
920
+ style: { cursor: "pointer", accentColor, colorScheme: "light dark" }
845
921
  }
846
922
  );
847
923
  return /* @__PURE__ */ jsx4(
@@ -866,8 +942,22 @@ var Cell = React3.memo(
866
942
  }
867
943
  );
868
944
  }
945
+ const isEditable = !!column.editable && !column.render && !!onEdit;
946
+ const showEditor = isEditable && isEditing && onEditComplete;
869
947
  let content;
870
- if (column.render) {
948
+ if (showEditor) {
949
+ content = /* @__PURE__ */ jsx4(
950
+ EditableCell,
951
+ {
952
+ value,
953
+ record,
954
+ column,
955
+ rowIndex,
956
+ onEdit,
957
+ onEditComplete
958
+ }
959
+ );
960
+ } else if (column.render) {
871
961
  try {
872
962
  content = column.render(value, record, rowIndex);
873
963
  } catch {
@@ -896,7 +986,7 @@ var Cell = React3.memo(
896
986
  ...isPinned ? styles?.pinnedCell : void 0,
897
987
  ...styles?.cell
898
988
  },
899
- children: isSystem ? content : /* @__PURE__ */ jsx4(
989
+ children: isSystem ? content : showEditor ? content : /* @__PURE__ */ jsx4(
900
990
  "div",
901
991
  {
902
992
  style: {
@@ -917,6 +1007,10 @@ var Cell = React3.memo(
917
1007
  if (prev.column.pinned !== next.column.pinned) return false;
918
1008
  if (prev.classNames !== next.classNames) return false;
919
1009
  if (prev.styles !== next.styles) return false;
1010
+ if (prev.column.editable !== next.column.editable) return false;
1011
+ if (prev.onEdit !== next.onEdit) return false;
1012
+ if (prev.isEditing !== next.isEditing) return false;
1013
+ if (prev.onEditComplete !== next.onEditComplete) return false;
920
1014
  if (prev.column.key === "__select__") {
921
1015
  return prev.isSelected === next.isSelected && prev.normalizedSelectedKeys === next.normalizedSelectedKeys;
922
1016
  }
@@ -984,7 +1078,11 @@ var TableBody = ({
984
1078
  gridTemplateColumns,
985
1079
  headerHeight = 36,
986
1080
  rowClassName,
987
- rowStyle
1081
+ rowStyle,
1082
+ bodyGridRow = 2,
1083
+ onEdit,
1084
+ editingCell,
1085
+ onEditComplete
988
1086
  }) => {
989
1087
  const virtualItems = rowVirtualizer.getVirtualItems();
990
1088
  const totalSize = rowVirtualizer.getTotalSize();
@@ -1006,7 +1104,7 @@ var TableBody = ({
1006
1104
  else if (isPinned) zIndex = 2;
1007
1105
  const style = {
1008
1106
  gridColumn: colIndex + 1,
1009
- gridRow: 2,
1107
+ gridRow: bodyGridRow,
1010
1108
  height: `${totalSize}px`,
1011
1109
  position: isPinned ? "sticky" : "relative",
1012
1110
  zIndex
@@ -1020,7 +1118,7 @@ var TableBody = ({
1020
1118
  }
1021
1119
  return { key: col.key, style, isPinned };
1022
1120
  });
1023
- }, [safeColumns, columnOffsets, totalSize, styles]);
1121
+ }, [safeColumns, columnOffsets, totalSize, styles, bodyGridRow]);
1024
1122
  if (safeData.length === 0 || safeColumns.length === 0) return null;
1025
1123
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1026
1124
  columnStyles.map((colStyle, colIndex) => {
@@ -1038,7 +1136,7 @@ var TableBody = ({
1038
1136
  const rowKey = getRowKey ? getRowKey(row, virtualRow.index) : String(virtualRow.index);
1039
1137
  const isSelected = selectedKeySet.has(rowKey);
1040
1138
  const isExpanded = resolvedExpandedKeys?.has(rowKey) ?? false;
1041
- const cellValue = row[col.dataIndex];
1139
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1042
1140
  const isRowShimmer = isLoading || rowKey.startsWith("__shimmer_");
1043
1141
  let recordFingerprint;
1044
1142
  if (hasRender && !isRowShimmer) {
@@ -1100,7 +1198,10 @@ var TableBody = ({
1100
1198
  getRawRowKey,
1101
1199
  accentColor,
1102
1200
  isLoading: isRowShimmer,
1103
- recordFingerprint
1201
+ recordFingerprint,
1202
+ onEdit,
1203
+ isEditing: editingCell?.rowKey === rowKey && editingCell?.columnKey === col.key,
1204
+ onEditComplete
1104
1205
  }
1105
1206
  )
1106
1207
  }
@@ -1118,7 +1219,7 @@ var TableBody = ({
1118
1219
  {
1119
1220
  style: {
1120
1221
  gridColumn: "1 / -1",
1121
- gridRow: 2,
1222
+ gridRow: bodyGridRow,
1122
1223
  height: `${totalSize}px`,
1123
1224
  position: "relative",
1124
1225
  zIndex: 15,
@@ -1182,7 +1283,7 @@ var TableBody = ({
1182
1283
  {
1183
1284
  style: {
1184
1285
  gridColumn: "1 / -1",
1185
- gridRow: 2,
1286
+ gridRow: bodyGridRow,
1186
1287
  height: `${totalSize}px`,
1187
1288
  position: "relative",
1188
1289
  zIndex: 20,
@@ -1224,7 +1325,7 @@ var TableBody = ({
1224
1325
  ...rowSty
1225
1326
  },
1226
1327
  children: safeColumns.map((col) => {
1227
- const cellValue = row[col.dataIndex];
1328
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1228
1329
  const stickyOffset = columnOffsets.get(col.key);
1229
1330
  const isPinned = Boolean(col.pinned);
1230
1331
  let zIndex = 0;
@@ -1282,7 +1383,10 @@ var TableBody = ({
1282
1383
  getRawRowKey,
1283
1384
  accentColor,
1284
1385
  isLoading: false,
1285
- recordFingerprint
1386
+ recordFingerprint,
1387
+ onEdit,
1388
+ isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
1389
+ onEditComplete
1286
1390
  }
1287
1391
  )
1288
1392
  }
@@ -1304,7 +1408,7 @@ var TableBody = ({
1304
1408
  {
1305
1409
  style: {
1306
1410
  gridColumn: "1 / -1",
1307
- gridRow: 2,
1411
+ gridRow: bodyGridRow,
1308
1412
  height: `${totalSize}px`,
1309
1413
  position: "relative",
1310
1414
  zIndex: 20,
@@ -1349,7 +1453,7 @@ var TableBody = ({
1349
1453
  ...rowSty
1350
1454
  },
1351
1455
  children: safeColumns.map((col) => {
1352
- const cellValue = row[col.dataIndex];
1456
+ const cellValue = col.dataIndex != null ? row[col.dataIndex] : void 0;
1353
1457
  const stickyOffset = columnOffsets.get(col.key);
1354
1458
  const isPinned = Boolean(col.pinned);
1355
1459
  let zIndex = 0;
@@ -1407,7 +1511,10 @@ var TableBody = ({
1407
1511
  getRawRowKey,
1408
1512
  accentColor,
1409
1513
  isLoading: false,
1410
- recordFingerprint
1514
+ recordFingerprint,
1515
+ onEdit,
1516
+ isEditing: editingCell?.rowKey === rk && editingCell?.columnKey === col.key,
1517
+ onEditComplete
1411
1518
  }
1412
1519
  )
1413
1520
  }
@@ -1437,6 +1544,18 @@ function arrayMove(arr, from, to) {
1437
1544
  result.splice(to, 0, item);
1438
1545
  return result;
1439
1546
  }
1547
+ function flattenColumns(columns) {
1548
+ const result = [];
1549
+ for (const col of columns) {
1550
+ if (col == null) continue;
1551
+ if (col.children && col.children.length > 0) {
1552
+ result.push(...flattenColumns(col.children));
1553
+ } else {
1554
+ result.push(col);
1555
+ }
1556
+ }
1557
+ return result;
1558
+ }
1440
1559
  var SHIMMER_WIDTHS2 = [55, 70, 45, 80, 60, 50, 75, 65, 40, 72];
1441
1560
  var EMPTY_CLASSNAMES = {};
1442
1561
  var EMPTY_STYLES = {};
@@ -1479,7 +1598,9 @@ function BoltTable({
1479
1598
  rowStyle,
1480
1599
  disabledFilters,
1481
1600
  onCopy,
1482
- keepPinnedRowsAcrossPages
1601
+ keepPinnedRowsAcrossPages,
1602
+ onEdit,
1603
+ onRowClick
1483
1604
  }) {
1484
1605
  const data = useMemo2(() => {
1485
1606
  if (!Array.isArray(rawData)) return STABLE_EMPTY_DATA;
@@ -1488,17 +1609,49 @@ function BoltTable({
1488
1609
  }, [rawData]);
1489
1610
  const initialColumns = useMemo2(() => {
1490
1611
  if (!Array.isArray(rawInitialColumns)) return STABLE_EMPTY_COLS;
1491
- const filtered = rawInitialColumns.filter(
1612
+ const safe = rawInitialColumns.filter(
1613
+ (col) => col != null && typeof col.key === "string"
1614
+ );
1615
+ const flattened = flattenColumns(safe);
1616
+ const validated = flattened.filter(
1492
1617
  (col) => col != null && typeof col.key === "string"
1493
1618
  );
1494
- return filtered.length > 0 ? filtered : STABLE_EMPTY_COLS;
1619
+ return validated.length > 0 ? validated : STABLE_EMPTY_COLS;
1495
1620
  }, [rawInitialColumns]);
1496
- const [columns, setColumns] = useState2(initialColumns);
1497
- const [columnOrder, setColumnOrder] = useState2(
1621
+ const headerGroups = useMemo2(() => {
1622
+ if (!Array.isArray(rawInitialColumns)) return [];
1623
+ const groups = [];
1624
+ for (const col of rawInitialColumns) {
1625
+ if (col != null && typeof col.key === "string" && col.children && col.children.length > 0) {
1626
+ const leafKeys = flattenColumns([col]).filter((c) => c != null && typeof c.key === "string").map((c) => c.key);
1627
+ if (leafKeys.length > 0) {
1628
+ groups.push({
1629
+ key: col.key,
1630
+ title: col.title,
1631
+ childKeys: leafKeys,
1632
+ style: col.style,
1633
+ className: col.className
1634
+ });
1635
+ }
1636
+ }
1637
+ }
1638
+ return groups;
1639
+ }, [rawInitialColumns]);
1640
+ const hasColumnGroups = headerGroups.length > 0;
1641
+ const groupedColumnKeySet = useMemo2(() => {
1642
+ if (!hasColumnGroups) return null;
1643
+ const keys = /* @__PURE__ */ new Set();
1644
+ for (const g of headerGroups) {
1645
+ for (const k of g.childKeys) keys.add(k);
1646
+ }
1647
+ return keys;
1648
+ }, [headerGroups, hasColumnGroups]);
1649
+ const [columns, setColumns] = useState3(initialColumns);
1650
+ const [columnOrder, setColumnOrder] = useState3(
1498
1651
  () => initialColumns.map((c) => c.key)
1499
1652
  );
1500
- const [activeId, setActiveId] = useState2(null);
1501
- const [mounted, setMounted] = useState2(false);
1653
+ const [activeId, setActiveId] = useState3(null);
1654
+ const [mounted, setMounted] = useState3(false);
1502
1655
  React4.useEffect(() => {
1503
1656
  setMounted(true);
1504
1657
  }, []);
@@ -1516,7 +1669,7 @@ function BoltTable({
1516
1669
  setColumnOrder(initialColumnsRef.current.map((c) => c.key));
1517
1670
  }, [newFingerprint]);
1518
1671
  const safeWidth = (w, fallback = 150) => typeof w === "number" && Number.isFinite(w) ? w : fallback;
1519
- const [columnWidths, setColumnWidths] = useState2(
1672
+ const [columnWidths, setColumnWidths] = useState3(
1520
1673
  () => /* @__PURE__ */ new Map()
1521
1674
  );
1522
1675
  const manuallyResizedRef = useRef4(/* @__PURE__ */ new Set());
@@ -1527,7 +1680,7 @@ function BoltTable({
1527
1680
  })),
1528
1681
  [columns, columnWidths]
1529
1682
  );
1530
- const [internalExpandedKeys, setInternalExpandedKeys] = useState2(() => {
1683
+ const [internalExpandedKeys, setInternalExpandedKeys] = useState3(() => {
1531
1684
  if (expandable?.defaultExpandAllRows && data.length > 0) {
1532
1685
  return new Set(
1533
1686
  data.map((row, idx) => {
@@ -1553,7 +1706,7 @@ function BoltTable({
1553
1706
  }, [expandedKeysFingerprint, internalExpandedKeys]);
1554
1707
  const expandableRef = useRef4(expandable);
1555
1708
  expandableRef.current = expandable;
1556
- const toggleExpand = useCallback((key) => {
1709
+ const toggleExpand = useCallback2((key) => {
1557
1710
  const exp = expandableRef.current;
1558
1711
  if (exp?.expandedRowKeys !== void 0) {
1559
1712
  const next = new Set(exp.expandedRowKeys);
@@ -1568,7 +1721,7 @@ function BoltTable({
1568
1721
  });
1569
1722
  }
1570
1723
  }, []);
1571
- const getRowKey = useCallback(
1724
+ const getRowKey = useCallback2(
1572
1725
  (record, index) => {
1573
1726
  if (record == null) return String(index);
1574
1727
  try {
@@ -1584,7 +1737,7 @@ function BoltTable({
1584
1737
  },
1585
1738
  [rowKey]
1586
1739
  );
1587
- const getRawRowKey = useCallback(
1740
+ const getRawRowKey = useCallback2(
1588
1741
  (record, index) => {
1589
1742
  if (record == null) return index;
1590
1743
  try {
@@ -1646,6 +1799,7 @@ function BoltTable({
1646
1799
  return /* @__PURE__ */ jsx5(
1647
1800
  "button",
1648
1801
  {
1802
+ type: "button",
1649
1803
  onClick: (e) => {
1650
1804
  e.stopPropagation();
1651
1805
  toggleExpandRef.current(key);
@@ -1683,11 +1837,11 @@ function BoltTable({
1683
1837
  }, [rowSelection, columnsWithExpand]);
1684
1838
  const resizeOverlayRef = useRef4(null);
1685
1839
  const tableAreaRef = useRef4(null);
1686
- const [scrollAreaWidth, setScrollAreaWidth] = useState2(0);
1840
+ const [scrollAreaWidth, setScrollAreaWidth] = useState3(0);
1687
1841
  const prevScrollAreaWidthRef = useRef4(0);
1688
1842
  const roRef = useRef4(null);
1689
1843
  const rafRef = useRef4(null);
1690
- const tableAreaCallbackRef = useCallback((el) => {
1844
+ const tableAreaCallbackRef = useCallback2((el) => {
1691
1845
  roRef.current?.disconnect();
1692
1846
  roRef.current = null;
1693
1847
  if (rafRef.current !== null) {
@@ -1745,12 +1899,23 @@ function BoltTable({
1745
1899
  };
1746
1900
  }, []);
1747
1901
  const resizeStateRef = useRef4(null);
1902
+ const columnGroupMapRef = useRef4(/* @__PURE__ */ new Map());
1903
+ useMemo2(() => {
1904
+ const map = /* @__PURE__ */ new Map();
1905
+ for (const g of headerGroups) {
1906
+ for (const k of g.childKeys) map.set(k, g.key);
1907
+ }
1908
+ for (const col of initialColumns) {
1909
+ if (!map.has(col.key)) map.set(col.key, null);
1910
+ }
1911
+ columnGroupMapRef.current = map;
1912
+ }, [headerGroups, initialColumns]);
1748
1913
  const overIdRef = useRef4(null);
1749
1914
  const dragActiveIdRef = useRef4(null);
1750
1915
  const ghostRef = useRef4(null);
1751
1916
  const onColumnOrderChangeRef = useRef4(onColumnOrderChange);
1752
1917
  onColumnOrderChangeRef.current = onColumnOrderChange;
1753
- const handleColumnDragStart = useCallback(
1918
+ const handleColumnDragStart = useCallback2(
1754
1919
  (columnKey, e) => {
1755
1920
  if (columnKey === "__select__" || columnKey === "__expand__") return;
1756
1921
  const headerEl = e.currentTarget.closest(
@@ -1773,6 +1938,7 @@ function BoltTable({
1773
1938
  const grabStyle = document.createElement("style");
1774
1939
  grabStyle.textContent = "* { cursor: grabbing !important; }";
1775
1940
  document.head.appendChild(grabStyle);
1941
+ const draggedGroup = columnGroupMapRef.current.get(columnKey);
1776
1942
  const onMove = (ev) => {
1777
1943
  if (ghost) {
1778
1944
  ghost.style.left = `${ev.clientX - offsetX}px`;
@@ -1788,6 +1954,11 @@ function BoltTable({
1788
1954
  h.removeAttribute("data-drag-over");
1789
1955
  return;
1790
1956
  }
1957
+ const targetGroup = columnGroupMapRef.current.get(key);
1958
+ if (draggedGroup !== targetGroup) {
1959
+ h.removeAttribute("data-drag-over");
1960
+ return;
1961
+ }
1791
1962
  const r = h.getBoundingClientRect();
1792
1963
  if (ev.clientX >= r.left && ev.clientX <= r.right && ev.clientY >= r.top - 20 && ev.clientY <= r.bottom + 20) {
1793
1964
  newOverId = key;
@@ -1810,7 +1981,7 @@ function BoltTable({
1810
1981
  if (ghost) ghost.style.display = "none";
1811
1982
  const currentOverId = overIdRef.current;
1812
1983
  const currentActiveId = dragActiveIdRef.current;
1813
- if (currentOverId && currentActiveId && currentOverId !== currentActiveId) {
1984
+ if (currentOverId && currentActiveId && currentOverId !== currentActiveId && columnGroupMapRef.current.get(currentActiveId) === columnGroupMapRef.current.get(currentOverId)) {
1814
1985
  React4.startTransition(() => {
1815
1986
  setColumnOrder((items) => {
1816
1987
  const oldIndex = items.indexOf(currentActiveId);
@@ -1977,9 +2148,9 @@ function BoltTable({
1977
2148
  const column = columns.find((col) => col.key === columnKey);
1978
2149
  if (column && !column.pinned) onColumnHide?.(columnKey, !column.hidden);
1979
2150
  };
1980
- const [internalRowPinning, setInternalRowPinning] = useState2({ top: [], bottom: [] });
2151
+ const [internalRowPinning, setInternalRowPinning] = useState3({ top: [], bottom: [] });
1981
2152
  const resolvedRowPinning = rowPinning === true ? internalRowPinning : rowPinning && typeof rowPinning === "object" ? rowPinning : void 0;
1982
- const handleRowPin = useCallback((rk, pinned) => {
2153
+ const handleRowPin = useCallback2((rk, pinned) => {
1983
2154
  if (onRowPin) {
1984
2155
  onRowPin(rk, pinned);
1985
2156
  return;
@@ -1997,8 +2168,8 @@ function BoltTable({
1997
2168
  }, [onRowPin, rowPinning]);
1998
2169
  const onSortChangeRef = useRef4(onSortChange);
1999
2170
  onSortChangeRef.current = onSortChange;
2000
- const [sortState, setSortState] = useState2({ key: "", direction: null });
2001
- const handleSort = useCallback(
2171
+ const [sortState, setSortState] = useState3({ key: "", direction: null });
2172
+ const handleSort = useCallback2(
2002
2173
  (columnKey, direction) => {
2003
2174
  setSortState((prev) => {
2004
2175
  let next;
@@ -2014,10 +2185,10 @@ function BoltTable({
2014
2185
  },
2015
2186
  []
2016
2187
  );
2017
- const [columnFilters, setColumnFilters] = useState2(
2188
+ const [columnFilters, setColumnFilters] = useState3(
2018
2189
  {}
2019
2190
  );
2020
- const handleColumnFilter = useCallback(
2191
+ const handleColumnFilter = useCallback2(
2021
2192
  (columnKey, value) => {
2022
2193
  setColumnFilters((prev) => {
2023
2194
  const next = { ...prev };
@@ -2029,7 +2200,7 @@ function BoltTable({
2029
2200
  },
2030
2201
  [onFilterChange]
2031
2202
  );
2032
- const handleClearFilter = useCallback(
2203
+ const handleClearFilter = useCallback2(
2033
2204
  (columnKey) => {
2034
2205
  handleColumnFilter(columnKey, "");
2035
2206
  },
@@ -2050,7 +2221,7 @@ function BoltTable({
2050
2221
  try {
2051
2222
  const col = columnsLookupRef.current.find((c) => c.key === key);
2052
2223
  if (typeof col?.filterFn === "function") {
2053
- return col.filterFn(columnFilters[key], row, col.dataIndex);
2224
+ return col.filterFn(columnFilters[key], row, col.dataIndex ?? key);
2054
2225
  }
2055
2226
  const cellVal = String(row[key] ?? "").toLowerCase();
2056
2227
  return cellVal.includes(columnFilters[key].toLowerCase());
@@ -2156,13 +2327,17 @@ function BoltTable({
2156
2327
  () => new Set((resolvedRowPinning?.bottom ?? []).map(String)),
2157
2328
  [resolvedRowPinning?.bottom]
2158
2329
  );
2159
- const [cellContextMenu, setCellContextMenu] = useState2(null);
2330
+ const [editingCell, setEditingCell] = useState3(null);
2331
+ const handleEditComplete = useCallback2(() => {
2332
+ setEditingCell(null);
2333
+ }, []);
2334
+ const [cellContextMenu, setCellContextMenu] = useState3(null);
2160
2335
  const cellMenuRef = useRef4(null);
2161
2336
  const cellLongPressTimer = useRef4(
2162
2337
  null
2163
2338
  );
2164
2339
  const cellTouchStart = useRef4(null);
2165
- const cancelCellLongPress = useCallback(() => {
2340
+ const cancelCellLongPress = useCallback2(() => {
2166
2341
  if (cellLongPressTimer.current) {
2167
2342
  clearTimeout(cellLongPressTimer.current);
2168
2343
  cellLongPressTimer.current = null;
@@ -2192,8 +2367,8 @@ function BoltTable({
2192
2367
  tableAreaRef.current?.scrollTo({ top: 0 });
2193
2368
  }, [columnFiltersKey]);
2194
2369
  const DEFAULT_PAGE_SIZE = 15;
2195
- const [internalPage, setInternalPage] = useState2(1);
2196
- const [internalPageSize, setInternalPageSize] = useState2(DEFAULT_PAGE_SIZE);
2370
+ const [internalPage, setInternalPage] = useState3(1);
2371
+ const [internalPageSize, setInternalPageSize] = useState3(DEFAULT_PAGE_SIZE);
2197
2372
  const dataLength = data.length;
2198
2373
  const autoPagination = pagination === void 0 && dataLength > DEFAULT_PAGE_SIZE;
2199
2374
  const pgEnabled = pagination === false ? false : !!pagination || autoPagination;
@@ -2237,7 +2412,7 @@ function BoltTable({
2237
2412
  }, [shimmerData, infiniteLoadingShimmer, paginatedData]);
2238
2413
  const measuredExpandedHeights = useRef4(/* @__PURE__ */ new Map());
2239
2414
  const expandedRowMeasureRafRef = useRef4(null);
2240
- const handleExpandedRowResize = useCallback(
2415
+ const handleExpandedRowResize = useCallback2(
2241
2416
  (rk, contentHeight) => {
2242
2417
  const prev = measuredExpandedHeights.current.get(rk);
2243
2418
  const rounded = Math.round(contentHeight);
@@ -2366,7 +2541,7 @@ function BoltTable({
2366
2541
  totalPages
2367
2542
  ];
2368
2543
  };
2369
- const HEADER_HEIGHT = 36;
2544
+ const HEADER_HEIGHT = hasColumnGroups ? 72 : 36;
2370
2545
  const MAX_AUTO_ROWS = 10;
2371
2546
  const virtualTotalSize = rowVirtualizer.getTotalSize();
2372
2547
  const naturalContentHeight = virtualTotalSize + HEADER_HEIGHT;
@@ -2423,6 +2598,7 @@ function BoltTable({
2423
2598
  [data-bt-header][data-drag-over] {
2424
2599
  border: 1px dashed ${accentColor} !important;
2425
2600
  }
2601
+ ${onRowClick ? "[data-bt-cell] { cursor: pointer; }" : ""}
2426
2602
  ` }),
2427
2603
  /* @__PURE__ */ jsx5(
2428
2604
  "div",
@@ -2561,7 +2737,7 @@ function BoltTable({
2561
2737
  style: {
2562
2738
  display: "grid",
2563
2739
  gridTemplateColumns,
2564
- gridTemplateRows: isEmpty ? "36px 1fr" : `36px ${virtualTotalSize}px`,
2740
+ gridTemplateRows: isEmpty ? hasColumnGroups ? "36px 36px 1fr" : "36px 1fr" : hasColumnGroups ? `36px 36px ${virtualTotalSize}px` : `36px ${virtualTotalSize}px`,
2565
2741
  minWidth: `${totalTableWidth}px`,
2566
2742
  width: "100%",
2567
2743
  position: "relative",
@@ -2579,7 +2755,8 @@ function BoltTable({
2579
2755
  const hasCopy = !!col?.copy;
2580
2756
  const hasRowPin = !!rowPinning;
2581
2757
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2582
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2758
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2759
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2583
2760
  e.preventDefault();
2584
2761
  setCellContextMenu({
2585
2762
  x: Math.min(e.clientX, window.innerWidth - 200),
@@ -2608,7 +2785,8 @@ function BoltTable({
2608
2785
  const hasCopy = !!col?.copy;
2609
2786
  const hasRowPin = !!rowPinning;
2610
2787
  const hasCellItems = col?.columnCellContextMenuItems && col.columnCellContextMenuItems.length > 0;
2611
- if (!hasCopy && !hasRowPin && !hasCellItems) return;
2788
+ const hasEdit = !!col?.editable && !col?.render && !!onEdit;
2789
+ if (!hasCopy && !hasRowPin && !hasCellItems && !hasEdit) return;
2612
2790
  setCellContextMenu({
2613
2791
  x: Math.min(touch.clientX, window.innerWidth - 200),
2614
2792
  y: Math.min(touch.clientY, window.innerHeight - 200),
@@ -2627,125 +2805,209 @@ function BoltTable({
2627
2805
  },
2628
2806
  onTouchEnd: cancelCellLongPress,
2629
2807
  onTouchCancel: cancelCellLongPress,
2630
- children: [
2631
- orderedColumns.map((column, visualIndex) => {
2632
- if (column.key === "__select__" && rowSelection) {
2633
- return /* @__PURE__ */ jsx5(
2634
- "div",
2635
- {
2636
- "data-bt-header": "",
2637
- "data-bt-pinned": "",
2638
- className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2639
- style: {
2640
- display: "flex",
2641
- height: 36,
2642
- alignItems: "center",
2643
- justifyContent: "center",
2644
- overflow: "hidden",
2645
- textOverflow: "ellipsis",
2646
- whiteSpace: "nowrap",
2647
- borderBottom: "1px solid rgba(128,128,128,0.2)",
2648
- position: "sticky",
2649
- left: columnOffsets.get("__select__") ?? 0,
2650
- top: 0,
2651
- zIndex: 13,
2652
- width: "48px",
2653
- ...styles.header,
2654
- ...styles.pinnedHeader
2655
- },
2656
- children: rowSelection.type !== "radio" && !rowSelection.hideSelectAll && /* @__PURE__ */ jsx5(
2657
- "input",
2658
- {
2659
- type: "checkbox",
2660
- checked: dataLength > 0 && normalizedSelectedKeys.length === dataLength,
2661
- ref: (input) => {
2662
- if (input) {
2663
- input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < dataLength;
2664
- }
2665
- },
2666
- onChange: (e) => {
2667
- if (e.target.checked) {
2668
- const allKeys = data.map(
2669
- (row, idx) => getRawRowKey(row, idx)
2670
- );
2671
- rowSelection.onSelectAll?.(
2672
- true,
2673
- data,
2674
- data
2675
- );
2676
- rowSelection.onChange?.(allKeys, data, {
2677
- type: "all"
2678
- });
2679
- } else {
2680
- rowSelection.onSelectAll?.(false, [], data);
2681
- rowSelection.onChange?.([], [], {
2682
- type: "all"
2683
- });
2684
- }
2685
- },
2686
- style: { cursor: "pointer", accentColor }
2687
- }
2688
- )
2689
- },
2690
- "__select__"
2691
- );
2808
+ onClick: onRowClick ? (e) => {
2809
+ const target = e.target;
2810
+ if (target.closest("input, button, a, select, textarea")) return;
2811
+ const cell = target.closest("[data-bt-cell]");
2812
+ if (!cell) return;
2813
+ const rk = cell.dataset.rowKey;
2814
+ if (!rk) return;
2815
+ for (let i = 0; i < displayData.length; i++) {
2816
+ const row = displayData[i];
2817
+ if (row == null) continue;
2818
+ if (getRowKey(row, i) === rk) {
2819
+ onRowClick(row, i, e);
2820
+ return;
2692
2821
  }
2693
- if (column.key === "__expand__") {
2694
- return /* @__PURE__ */ jsx5(
2695
- "div",
2696
- {
2697
- "data-bt-header": "",
2698
- "data-bt-pinned": "",
2699
- className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2700
- style: {
2701
- display: "flex",
2702
- height: 36,
2703
- alignItems: "center",
2704
- justifyContent: "center",
2705
- overflow: "hidden",
2706
- textOverflow: "ellipsis",
2707
- whiteSpace: "nowrap",
2708
- borderBottom: "1px solid rgba(128,128,128,0.2)",
2709
- position: "sticky",
2710
- left: columnOffsets.get("__expand__") ?? 0,
2711
- top: 0,
2712
- zIndex: 13,
2713
- width: "40px",
2714
- ...styles.header,
2715
- ...styles.pinnedHeader
2716
- }
2717
- },
2718
- "__expand__"
2719
- );
2822
+ }
2823
+ for (let i = 0; i < pinnedTopRows.length; i++) {
2824
+ if (pinnedTopRows[i] == null) continue;
2825
+ if (getRowKey(pinnedTopRows[i], i) === rk) {
2826
+ onRowClick(pinnedTopRows[i], i, e);
2827
+ return;
2720
2828
  }
2829
+ }
2830
+ for (let i = 0; i < pinnedBottomRows.length; i++) {
2831
+ if (pinnedBottomRows[i] == null) continue;
2832
+ if (getRowKey(pinnedBottomRows[i], i) === rk) {
2833
+ onRowClick(pinnedBottomRows[i], i, e);
2834
+ return;
2835
+ }
2836
+ }
2837
+ } : void 0,
2838
+ children: [
2839
+ hasColumnGroups && headerGroups.map((group) => {
2840
+ let minIdx = Infinity;
2841
+ let maxIdx = -1;
2842
+ orderedColumns.forEach((col, idx) => {
2843
+ if (group.childKeys.includes(col.key)) {
2844
+ minIdx = Math.min(minIdx, idx);
2845
+ maxIdx = Math.max(maxIdx, idx);
2846
+ }
2847
+ });
2848
+ if (minIdx === Infinity) return null;
2721
2849
  return /* @__PURE__ */ jsx5(
2722
- DraggableHeader_default,
2850
+ "div",
2723
2851
  {
2724
- column,
2725
- accentColor,
2726
- visualIndex,
2727
- onResizeStart: handleResizeStart,
2728
- onColumnDragStart: handleColumnDragStart,
2729
- styles,
2730
- classNames,
2731
- gripIcon,
2732
- hideGripIcon,
2733
- icons,
2734
- stickyOffset: columnOffsets.get(column.key),
2735
- onTogglePin: handleTogglePin,
2736
- onToggleHide: handleToggleHide,
2737
- isLastColumn: visualIndex === orderedColumns.length - 1,
2738
- sortDirection: sortState.key === column.key ? sortState.direction : null,
2739
- onSort: handleSort,
2740
- filterValue: columnFilters[column.key] ?? "",
2741
- onFilter: handleColumnFilter,
2742
- onClearFilter: handleClearFilter,
2743
- customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
2744
- disabledFilters
2852
+ "data-bt-header": "",
2853
+ className: `${group.className ?? ""} ${classNames.header ?? ""}`,
2854
+ style: {
2855
+ gridColumn: `${minIdx + 1} / ${maxIdx + 2}`,
2856
+ gridRow: 1,
2857
+ position: "sticky",
2858
+ top: 0,
2859
+ zIndex: 10,
2860
+ display: "flex",
2861
+ height: 36,
2862
+ alignItems: "center",
2863
+ justifyContent: "center",
2864
+ overflow: "hidden",
2865
+ textOverflow: "ellipsis",
2866
+ whiteSpace: "nowrap",
2867
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2868
+ fontWeight: 500,
2869
+ userSelect: "none",
2870
+ ...group.style,
2871
+ ...styles.header
2872
+ },
2873
+ children: group.title
2745
2874
  },
2746
- column.key
2875
+ `group-${group.key}`
2747
2876
  );
2748
2877
  }),
2878
+ (() => {
2879
+ const firstDataColIndex = orderedColumns.findIndex(
2880
+ (c) => c.key !== "__select__" && c.key !== "__expand__"
2881
+ );
2882
+ return orderedColumns.map((column, visualIndex) => {
2883
+ const isInGroup = groupedColumnKeySet?.has(column.key) ?? false;
2884
+ const leafGridRow = hasColumnGroups ? isInGroup ? 2 : "1 / 3" : 1;
2885
+ const leafHeight = hasColumnGroups && !isInGroup ? 72 : 36;
2886
+ const leafStickyTop = hasColumnGroups && isInGroup ? 36 : 0;
2887
+ if (column.key === "__select__" && rowSelection) {
2888
+ return /* @__PURE__ */ jsx5(
2889
+ "div",
2890
+ {
2891
+ "data-bt-header": "",
2892
+ "data-bt-pinned": "",
2893
+ className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2894
+ style: {
2895
+ display: "flex",
2896
+ height: leafHeight,
2897
+ alignItems: "center",
2898
+ justifyContent: "center",
2899
+ overflow: "hidden",
2900
+ textOverflow: "ellipsis",
2901
+ whiteSpace: "nowrap",
2902
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2903
+ position: "sticky",
2904
+ left: columnOffsets.get("__select__") ?? 0,
2905
+ top: 0,
2906
+ zIndex: 13,
2907
+ width: "48px",
2908
+ gridRow: leafGridRow,
2909
+ ...styles.header,
2910
+ ...styles.pinnedHeader
2911
+ },
2912
+ children: rowSelection.type !== "radio" && !rowSelection.hideSelectAll && /* @__PURE__ */ jsx5(
2913
+ "input",
2914
+ {
2915
+ type: "checkbox",
2916
+ checked: dataLength > 0 && normalizedSelectedKeys.length === dataLength,
2917
+ ref: (input) => {
2918
+ if (input) {
2919
+ input.indeterminate = normalizedSelectedKeys.length > 0 && normalizedSelectedKeys.length < dataLength;
2920
+ }
2921
+ },
2922
+ onChange: (e) => {
2923
+ if (e.target.checked) {
2924
+ const allKeys = data.map(
2925
+ (row, idx) => getRawRowKey(row, idx)
2926
+ );
2927
+ rowSelection.onSelectAll?.(
2928
+ true,
2929
+ data,
2930
+ data
2931
+ );
2932
+ rowSelection.onChange?.(allKeys, data, {
2933
+ type: "all"
2934
+ });
2935
+ } else {
2936
+ rowSelection.onSelectAll?.(false, [], data);
2937
+ rowSelection.onChange?.([], [], {
2938
+ type: "all"
2939
+ });
2940
+ }
2941
+ },
2942
+ style: { cursor: "pointer", accentColor, colorScheme: "light dark" }
2943
+ }
2944
+ )
2945
+ },
2946
+ "__select__"
2947
+ );
2948
+ }
2949
+ if (column.key === "__expand__") {
2950
+ return /* @__PURE__ */ jsx5(
2951
+ "div",
2952
+ {
2953
+ "data-bt-header": "",
2954
+ "data-bt-pinned": "",
2955
+ className: `${classNames.header ?? ""} ${classNames.pinnedHeader ?? ""}`,
2956
+ style: {
2957
+ display: "flex",
2958
+ height: leafHeight,
2959
+ alignItems: "center",
2960
+ justifyContent: "center",
2961
+ overflow: "hidden",
2962
+ textOverflow: "ellipsis",
2963
+ whiteSpace: "nowrap",
2964
+ borderBottom: "1px solid rgba(128,128,128,0.2)",
2965
+ position: "sticky",
2966
+ left: columnOffsets.get("__expand__") ?? 0,
2967
+ top: 0,
2968
+ zIndex: 13,
2969
+ width: "40px",
2970
+ gridRow: leafGridRow,
2971
+ ...styles.header,
2972
+ ...styles.pinnedHeader
2973
+ }
2974
+ },
2975
+ "__expand__"
2976
+ );
2977
+ }
2978
+ return /* @__PURE__ */ jsx5(
2979
+ DraggableHeader_default,
2980
+ {
2981
+ column,
2982
+ accentColor,
2983
+ visualIndex,
2984
+ onResizeStart: handleResizeStart,
2985
+ onColumnDragStart: handleColumnDragStart,
2986
+ styles,
2987
+ classNames,
2988
+ gripIcon,
2989
+ hideGripIcon,
2990
+ icons,
2991
+ stickyOffset: columnOffsets.get(column.key),
2992
+ onTogglePin: handleTogglePin,
2993
+ onToggleHide: handleToggleHide,
2994
+ isLastColumn: visualIndex === orderedColumns.length - 1,
2995
+ isFirstColumn: visualIndex === firstDataColIndex,
2996
+ sortDirection: sortState.key === column.key ? sortState.direction : null,
2997
+ onSort: handleSort,
2998
+ filterValue: columnFilters[column.key] ?? "",
2999
+ onFilter: handleColumnFilter,
3000
+ onClearFilter: handleClearFilter,
3001
+ customContextMenuItems: column.columnHeaderContextMenuItems ? [...columnContextMenuItems ?? [], ...column.columnHeaderContextMenuItems] : columnContextMenuItems,
3002
+ disabledFilters,
3003
+ headerGridRow: leafGridRow,
3004
+ headerHeight: leafHeight,
3005
+ stickyTop: leafStickyTop
3006
+ },
3007
+ column.key
3008
+ );
3009
+ });
3010
+ })(),
2749
3011
  isEmpty ? /* @__PURE__ */ jsx5(
2750
3012
  "div",
2751
3013
  {
@@ -2812,7 +3074,11 @@ function BoltTable({
2812
3074
  gridTemplateColumns,
2813
3075
  headerHeight: HEADER_HEIGHT,
2814
3076
  rowClassName,
2815
- rowStyle
3077
+ rowStyle,
3078
+ bodyGridRow: hasColumnGroups ? 3 : 2,
3079
+ onEdit,
3080
+ editingCell,
3081
+ onEditComplete: handleEditComplete
2816
3082
  }
2817
3083
  )
2818
3084
  ]
@@ -2826,6 +3092,7 @@ function BoltTable({
2826
3092
  pgEnabled && /* @__PURE__ */ jsxs5(
2827
3093
  "div",
2828
3094
  {
3095
+ className: classNames.pagination ?? "",
2829
3096
  style: {
2830
3097
  display: "flex",
2831
3098
  height: 36,
@@ -2837,27 +3104,42 @@ function BoltTable({
2837
3104
  fontSize: 12,
2838
3105
  backdropFilter: "blur(8px)",
2839
3106
  backgroundColor: "rgba(128,128,128,0.06)",
2840
- gap: 12
3107
+ gap: 12,
3108
+ ...styles.pagination
2841
3109
  },
2842
3110
  children: [
2843
3111
  /* @__PURE__ */ jsx5("div", { style: { display: "flex", flex: "1 1 0%", alignItems: "center" }, children: (() => {
2844
3112
  const rangeStart = total > 0 ? (currentPage - 1) * pageSize + 1 : 0;
2845
3113
  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
- ] });
3114
+ return typeof pagination === "object" && pagination?.showTotal ? /* @__PURE__ */ jsxs5(
3115
+ "span",
3116
+ {
3117
+ className: classNames.paginationInfo ?? "",
3118
+ style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3119
+ children: [
3120
+ "Showing",
3121
+ " ",
3122
+ pagination.showTotal(total, [rangeStart, rangeEnd]),
3123
+ " of",
3124
+ " ",
3125
+ total,
3126
+ " items"
3127
+ ]
3128
+ }
3129
+ ) : /* @__PURE__ */ jsxs5(
3130
+ "span",
3131
+ {
3132
+ className: classNames.paginationInfo ?? "",
3133
+ style: { color: "GrayText", fontSize: 12, ...styles.paginationInfo },
3134
+ children: [
3135
+ rangeStart,
3136
+ "\u2013",
3137
+ rangeEnd,
3138
+ " of ",
3139
+ total
3140
+ ]
3141
+ }
3142
+ );
2861
3143
  })() }),
2862
3144
  /* @__PURE__ */ jsxs5(
2863
3145
  "div",
@@ -2873,8 +3155,10 @@ function BoltTable({
2873
3155
  /* @__PURE__ */ jsx5(
2874
3156
  "button",
2875
3157
  {
3158
+ type: "button",
2876
3159
  onClick: () => handlePageChange(1),
2877
3160
  disabled: currentPage === 1,
3161
+ className: classNames.paginationButton ?? "",
2878
3162
  style: {
2879
3163
  display: "inline-flex",
2880
3164
  height: 24,
@@ -2887,7 +3171,8 @@ function BoltTable({
2887
3171
  background: "none",
2888
3172
  border: "none",
2889
3173
  padding: 0,
2890
- color: "inherit"
3174
+ color: "inherit",
3175
+ ...styles.paginationButton
2891
3176
  },
2892
3177
  title: "First page",
2893
3178
  children: icons?.chevronsLeft ?? /* @__PURE__ */ jsx5(ChevronsLeftIcon, { style: { width: 12, height: 12 } })
@@ -2896,8 +3181,10 @@ function BoltTable({
2896
3181
  /* @__PURE__ */ jsx5(
2897
3182
  "button",
2898
3183
  {
3184
+ type: "button",
2899
3185
  onClick: () => handlePageChange(currentPage - 1),
2900
3186
  disabled: currentPage === 1,
3187
+ className: classNames.paginationButton ?? "",
2901
3188
  style: {
2902
3189
  display: "inline-flex",
2903
3190
  height: 24,
@@ -2910,7 +3197,8 @@ function BoltTable({
2910
3197
  background: "none",
2911
3198
  border: "none",
2912
3199
  padding: 0,
2913
- color: "inherit"
3200
+ color: "inherit",
3201
+ ...styles.paginationButton
2914
3202
  },
2915
3203
  title: "Previous page",
2916
3204
  children: icons?.chevronLeft ?? /* @__PURE__ */ jsx5(ChevronLeftIcon, { style: { width: 12, height: 12 } })
@@ -2933,9 +3221,12 @@ function BoltTable({
2933
3221
  page
2934
3222
  );
2935
3223
  }
3224
+ const isActivePage = page === currentPage;
2936
3225
  return /* @__PURE__ */ jsx5(
2937
3226
  "button",
2938
3227
  {
3228
+ type: "button",
3229
+ className: `${classNames.paginationButton ?? ""} ${isActivePage ? classNames.paginationActiveButton ?? "" : ""}`.trim() || void 0,
2939
3230
  style: {
2940
3231
  display: "inline-flex",
2941
3232
  height: 24,
@@ -2947,9 +3238,11 @@ function BoltTable({
2947
3238
  paddingLeft: 6,
2948
3239
  paddingRight: 6,
2949
3240
  fontSize: 12,
2950
- color: page === currentPage ? accentColor : void 0,
3241
+ color: isActivePage ? accentColor : void 0,
2951
3242
  background: "none",
2952
- border: "none"
3243
+ border: "none",
3244
+ ...styles.paginationButton,
3245
+ ...isActivePage ? styles.paginationActiveButton : void 0
2953
3246
  },
2954
3247
  onClick: () => handlePageChange(page),
2955
3248
  children: page
@@ -2960,8 +3253,10 @@ function BoltTable({
2960
3253
  /* @__PURE__ */ jsx5(
2961
3254
  "button",
2962
3255
  {
3256
+ type: "button",
2963
3257
  onClick: () => handlePageChange(currentPage + 1),
2964
3258
  disabled: currentPage === totalPages,
3259
+ className: classNames.paginationButton ?? "",
2965
3260
  style: {
2966
3261
  display: "inline-flex",
2967
3262
  height: 24,
@@ -2974,7 +3269,8 @@ function BoltTable({
2974
3269
  background: "none",
2975
3270
  border: "none",
2976
3271
  padding: 0,
2977
- color: "inherit"
3272
+ color: "inherit",
3273
+ ...styles.paginationButton
2978
3274
  },
2979
3275
  title: "Next page",
2980
3276
  children: icons?.chevronRight ?? /* @__PURE__ */ jsx5(ChevronRightIcon, { style: { width: 12, height: 12 } })
@@ -2983,8 +3279,10 @@ function BoltTable({
2983
3279
  /* @__PURE__ */ jsx5(
2984
3280
  "button",
2985
3281
  {
3282
+ type: "button",
2986
3283
  onClick: () => handlePageChange(totalPages),
2987
3284
  disabled: currentPage === totalPages,
3285
+ className: classNames.paginationButton ?? "",
2988
3286
  style: {
2989
3287
  display: "inline-flex",
2990
3288
  height: 24,
@@ -2997,7 +3295,8 @@ function BoltTable({
2997
3295
  background: "none",
2998
3296
  border: "none",
2999
3297
  padding: 0,
3000
- color: "inherit"
3298
+ color: "inherit",
3299
+ ...styles.paginationButton
3001
3300
  },
3002
3301
  title: "Last page",
3003
3302
  children: icons?.chevronsRight ?? /* @__PURE__ */ jsx5(ChevronsRightIcon, { style: { width: 12, height: 12 } })
@@ -3021,6 +3320,7 @@ function BoltTable({
3021
3320
  {
3022
3321
  value: pageSize,
3023
3322
  onChange: (e) => handlePageSizeChange(Number(e.target.value)),
3323
+ className: classNames.paginationSelect ?? "",
3024
3324
  style: {
3025
3325
  cursor: "pointer",
3026
3326
  borderRadius: 4,
@@ -3032,7 +3332,8 @@ function BoltTable({
3032
3332
  fontSize: 12,
3033
3333
  height: 24,
3034
3334
  background: "inherit",
3035
- color: "inherit"
3335
+ color: "inherit",
3336
+ ...styles.paginationSelect
3036
3337
  },
3037
3338
  children: (typeof pagination === "object" && pagination?.pageSizeOptions ? pagination.pageSizeOptions : [10, 15, 20, 25, 50, 100]).map((size) => /* @__PURE__ */ jsxs5("option", { value: size, children: [
3038
3339
  size,
@@ -3127,6 +3428,7 @@ function BoltTable({
3127
3428
  );
3128
3429
  const hasCopy = !!menuCol?.copy;
3129
3430
  const hasRowPin = !!rowPinning;
3431
+ const hasEdit = !!menuCol?.editable && !menuCol?.render && !!onEdit;
3130
3432
  let menuRecord;
3131
3433
  let menuRowIndex = 0;
3132
3434
  const allRows = [
@@ -3143,7 +3445,7 @@ function BoltTable({
3143
3445
  break;
3144
3446
  }
3145
3447
  }
3146
- const menuValue = menuRecord && menuCol ? menuRecord[menuCol.dataIndex] : void 0;
3448
+ const menuValue = menuRecord && menuCol?.dataIndex != null ? menuRecord[menuCol.dataIndex] : void 0;
3147
3449
  const btnStyle = {
3148
3450
  display: "flex",
3149
3451
  width: "100%",
@@ -3183,6 +3485,7 @@ function BoltTable({
3183
3485
  /* @__PURE__ */ jsxs5(
3184
3486
  "button",
3185
3487
  {
3488
+ type: "button",
3186
3489
  "data-bt-ctx-item": true,
3187
3490
  style: btnStyle,
3188
3491
  onClick: () => {
@@ -3211,6 +3514,7 @@ function BoltTable({
3211
3514
  /* @__PURE__ */ jsxs5(
3212
3515
  "button",
3213
3516
  {
3517
+ type: "button",
3214
3518
  "data-bt-ctx-item": true,
3215
3519
  style: btnStyle,
3216
3520
  onClick: () => {
@@ -3242,7 +3546,40 @@ function BoltTable({
3242
3546
  }
3243
3547
  )
3244
3548
  ] }),
3245
- hasRowPin && hasCopy && /* @__PURE__ */ jsx5(
3549
+ hasRowPin && (hasCopy || hasEdit) && /* @__PURE__ */ jsx5(
3550
+ "div",
3551
+ {
3552
+ style: {
3553
+ borderTop: "1px solid rgba(128,128,128,0.2)",
3554
+ margin: "4px 0"
3555
+ }
3556
+ }
3557
+ ),
3558
+ hasEdit && /* @__PURE__ */ jsxs5(
3559
+ "button",
3560
+ {
3561
+ type: "button",
3562
+ "data-bt-ctx-item": true,
3563
+ style: btnStyle,
3564
+ onClick: () => {
3565
+ setEditingCell({
3566
+ rowKey: cellContextMenu.rowKey,
3567
+ columnKey: cellContextMenu.columnKey
3568
+ });
3569
+ setCellContextMenu(null);
3570
+ },
3571
+ children: [
3572
+ icons?.edit ?? /* @__PURE__ */ jsx5(
3573
+ PencilIcon,
3574
+ {
3575
+ style: { width: 14, height: 14, flexShrink: 0 }
3576
+ }
3577
+ ),
3578
+ "Edit"
3579
+ ]
3580
+ }
3581
+ ),
3582
+ (hasEdit || hasRowPin) && hasCopy && /* @__PURE__ */ jsx5(
3246
3583
  "div",
3247
3584
  {
3248
3585
  style: {
@@ -3254,6 +3591,7 @@ function BoltTable({
3254
3591
  hasCopy && menuRecord && menuCol && /* @__PURE__ */ jsxs5(
3255
3592
  "button",
3256
3593
  {
3594
+ type: "button",
3257
3595
  "data-bt-ctx-item": true,
3258
3596
  style: btnStyle,
3259
3597
  onClick: () => {
@@ -3274,7 +3612,7 @@ function BoltTable({
3274
3612
  }
3275
3613
  ),
3276
3614
  menuCol?.columnCellContextMenuItems && menuCol.columnCellContextMenuItems.length > 0 && /* @__PURE__ */ jsxs5(Fragment4, { children: [
3277
- (hasCopy || hasRowPin) && /* @__PURE__ */ jsx5(
3615
+ (hasCopy || hasRowPin || hasEdit) && /* @__PURE__ */ jsx5(
3278
3616
  "div",
3279
3617
  {
3280
3618
  style: {
@@ -3286,6 +3624,7 @@ function BoltTable({
3286
3624
  menuCol.columnCellContextMenuItems.map((item) => /* @__PURE__ */ jsxs5(
3287
3625
  "button",
3288
3626
  {
3627
+ type: "button",
3289
3628
  "data-bt-ctx-item": "",
3290
3629
  disabled: item.disabled,
3291
3630
  style: {