@vuu-ui/vuu-table 2.1.19-beta.1 → 2.1.19-beta.2

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.
Files changed (85) hide show
  1. package/package.json +12 -13
  2. package/src/CellFocusState.mjs +25 -0
  3. package/src/Row.mjs +83 -0
  4. package/src/Table.css.js +441 -0
  5. package/src/Table.mjs +297 -0
  6. package/src/VirtualColSpan.mjs +12 -0
  7. package/src/applyHighlighting.mjs +28 -0
  8. package/src/bulk-edit/BulkEditPanel.css.js +27 -0
  9. package/src/bulk-edit/BulkEditPanel.mjs +77 -0
  10. package/src/bulk-edit/ColumnCascadingUpdateEditor.css.js +86 -0
  11. package/src/bulk-edit/ColumnCascadingUpdateEditor.mjs +59 -0
  12. package/src/bulk-edit/InsertNewRowEditor.css.js +86 -0
  13. package/src/bulk-edit/InsertNewRowEditor.mjs +59 -0
  14. package/src/bulk-edit/useBulkEditPanel.mjs +61 -0
  15. package/src/bulk-edit/useColumnCascadingEditor.mjs +124 -0
  16. package/src/cell-block/CellBlock.css.js +95 -0
  17. package/src/cell-block/CellBlock.mjs +32 -0
  18. package/src/cell-block/cellblock-utils.mjs +114 -0
  19. package/src/cell-block/useCellBlockSelection.mjs +245 -0
  20. package/src/cell-renderers/checkbox-cell/CheckboxCell.css.js +16 -0
  21. package/src/cell-renderers/checkbox-cell/CheckboxCell.mjs +56 -0
  22. package/src/cell-renderers/checkbox-cell/index.mjs +1 -0
  23. package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.css.js +19 -0
  24. package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.mjs +34 -0
  25. package/src/cell-renderers/checkbox-row-selector/index.mjs +1 -0
  26. package/src/cell-renderers/index.mjs +4 -0
  27. package/src/cell-renderers/input-cell/InputCell.css.js +81 -0
  28. package/src/cell-renderers/input-cell/InputCell.mjs +73 -0
  29. package/src/cell-renderers/input-cell/index.mjs +1 -0
  30. package/src/cell-renderers/input-cell/useInputCell.mjs +199 -0
  31. package/src/cell-renderers/toggle-cell/ToggleCell.css.js +31 -0
  32. package/src/cell-renderers/toggle-cell/ToggleCell.mjs +47 -0
  33. package/src/cell-renderers/toggle-cell/index.mjs +1 -0
  34. package/src/column-header-pill/ColumnHeaderPill.css.js +34 -0
  35. package/src/column-header-pill/ColumnHeaderPill.mjs +39 -0
  36. package/src/column-header-pill/GroupColumnPill.css.js +10 -0
  37. package/src/column-header-pill/GroupColumnPill.mjs +33 -0
  38. package/src/column-header-pill/SortIndicator.css.js +15 -0
  39. package/src/column-header-pill/SortIndicator.mjs +29 -0
  40. package/src/column-header-pill/index.mjs +3 -0
  41. package/src/column-resizing/ColumnResizer.css.js +32 -0
  42. package/src/column-resizing/ColumnResizer.mjs +69 -0
  43. package/src/column-resizing/index.mjs +2 -0
  44. package/src/column-resizing/useTableColumnResize.mjs +57 -0
  45. package/src/data-row/DataRow.mjs +298 -0
  46. package/src/header-cell/GroupHeaderCell.css.js +91 -0
  47. package/src/header-cell/GroupHeaderCell.mjs +98 -0
  48. package/src/header-cell/HeaderCell.css.js +182 -0
  49. package/src/header-cell/HeaderCell.mjs +126 -0
  50. package/src/header-cell/index.mjs +2 -0
  51. package/src/index.mjs +20 -0
  52. package/src/pagination/PaginationControl.css.js +18 -0
  53. package/src/pagination/PaginationControl.mjs +34 -0
  54. package/src/pagination/index.mjs +1 -0
  55. package/src/pagination/usePagination.mjs +29 -0
  56. package/src/table-cell/TableCell.css.js +67 -0
  57. package/src/table-cell/TableCell.mjs +54 -0
  58. package/src/table-cell/TableGroupCell.css.js +91 -0
  59. package/src/table-cell/TableGroupCell.mjs +61 -0
  60. package/src/table-cell/index.mjs +2 -0
  61. package/src/table-config/useTableConfig.mjs +49 -0
  62. package/src/table-config.mjs +38 -0
  63. package/src/table-data-source/DataRowMovingWindow.mjs +66 -0
  64. package/src/table-data-source/useDataSource.mjs +177 -0
  65. package/src/table-dom-utils.mjs +162 -0
  66. package/src/table-header/HeaderProvider.mjs +14 -0
  67. package/src/table-header/TableHeader.mjs +182 -0
  68. package/src/table-header/index.mjs +2 -0
  69. package/src/table-header/useTableHeader.mjs +69 -0
  70. package/src/useCell.mjs +22 -0
  71. package/src/useCellEditing.mjs +58 -0
  72. package/src/useCellFocus.mjs +112 -0
  73. package/src/useControlledTableNavigation.mjs +34 -0
  74. package/src/useEditableCell.mjs +18 -0
  75. package/src/useInitialValue.mjs +6 -0
  76. package/src/useKeyboardNavigation.mjs +275 -0
  77. package/src/useMeasuredHeight.mjs +44 -0
  78. package/src/useResizeObserver.mjs +118 -0
  79. package/src/useRowClassNameGenerators.mjs +21 -0
  80. package/src/useSelection.mjs +101 -0
  81. package/src/useTable.mjs +588 -0
  82. package/src/useTableContextMenu.mjs +54 -0
  83. package/src/useTableModel.mjs +344 -0
  84. package/src/useTableScroll.mjs +382 -0
  85. package/src/useTableViewport.mjs +120 -0
@@ -0,0 +1,177 @@
1
+ import { Range } from "@vuu-ui/vuu-utils";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { DataRowMovingWindow } from "./DataRowMovingWindow.mjs";
4
+ import { dataRowFactory } from "../data-row/DataRow.mjs";
5
+ const NullDataRow = ()=>({});
6
+ const useDataSource = ({ autoSelectFirstRow, autoSelectRowKey, dataSource, onSizeChange, onSubscribed, renderBufferSize = 0, revealSelected, onSelect, selectionModel, suspenseProps })=>{
7
+ const [, forceUpdate] = useState(null);
8
+ const dataRows = useRef([]);
9
+ const isMounted = useRef(true);
10
+ const hasUpdated = useRef(false);
11
+ const rangeRef = useRef(dataSource.range);
12
+ const dataRowRef = useRef(NullDataRow);
13
+ const setColumnsRef = useRef(void 0);
14
+ const totalRowCountRef = useRef(0);
15
+ const rowAutoSelected = useRef(false);
16
+ const autoSelect = autoSelectRowKey ?? (autoSelectFirstRow || "single-no-deselect" === selectionModel);
17
+ const handleConfigChange = useCallback((_config, _range, _confirmed, configChanges)=>{
18
+ if (configChanges?.filterChanged) rowAutoSelected.current = false;
19
+ }, []);
20
+ useEffect(()=>{
21
+ if (autoSelect) dataSource.on("config", handleConfigChange);
22
+ return ()=>{
23
+ if (autoSelect) dataSource.removeListener("config", handleConfigChange);
24
+ };
25
+ }, [
26
+ autoSelect,
27
+ dataSource,
28
+ handleConfigChange
29
+ ]);
30
+ const dataRowWindow = useMemo(()=>new DataRowMovingWindow(rangeRef.current.withBuffer), []);
31
+ const handleResume = useCallback(()=>{
32
+ const { range } = dataSource;
33
+ if (0 !== range.to) dataRowWindow.setRange(dataSource.range.withBuffer);
34
+ }, [
35
+ dataRowWindow,
36
+ dataSource
37
+ ]);
38
+ useEffect(()=>()=>{
39
+ dataSource.removeListener("resumed", handleResume);
40
+ }, [
41
+ dataSource,
42
+ handleResume
43
+ ]);
44
+ const setData = useCallback((updates)=>{
45
+ const { current: DataRow } = dataRowRef;
46
+ for (const row of updates)dataRowWindow.add(DataRow(row));
47
+ dataRows.current = dataRowWindow.data;
48
+ if (isMounted.current) forceUpdate({});
49
+ }, [
50
+ dataRowWindow
51
+ ]);
52
+ const selectRow = useCallback((dataRow)=>{
53
+ const rowKey = dataRow.key;
54
+ dataSource.select?.({
55
+ preserveExistingSelection: false,
56
+ rowKey,
57
+ type: "SELECT_ROW"
58
+ });
59
+ onSelect?.(dataRow);
60
+ }, [
61
+ dataSource,
62
+ onSelect
63
+ ]);
64
+ const createDataRow = useCallback((columns, schemaColumns)=>{
65
+ const [DataRow, setColumns] = dataRowFactory(columns, schemaColumns);
66
+ dataRowRef.current = DataRow;
67
+ setColumnsRef.current = setColumns;
68
+ }, []);
69
+ const datasourceMessageHandler = useCallback((message)=>{
70
+ if ("subscribed" === message.type) {
71
+ createDataRow(message.columns, message.tableSchema.columns);
72
+ onSubscribed?.(message);
73
+ } else if ("subscribe-failed" === message.type) console.warn(`subscribe failed ${message.msg}`);
74
+ else if ("viewport-update" === message.type) {
75
+ if ("number" == typeof message.size) {
76
+ onSizeChange?.(message.size);
77
+ dataRowWindow.setRowCount(message.size);
78
+ totalRowCountRef.current = message.size;
79
+ }
80
+ if (message.rows) {
81
+ setData(message.rows);
82
+ if (autoSelect && false === rowAutoSelected.current) {
83
+ rowAutoSelected.current = true;
84
+ if ("string" == typeof autoSelect) {
85
+ const dataRow = dataRowWindow.getByKey(autoSelect);
86
+ if (dataRow) selectRow(dataRow);
87
+ else console.warn(`[useDataSource] autoSelect row key ${autoSelect} not in viewport`);
88
+ } else if (dataRowWindow.hasData) selectRow(dataRowWindow.firstRow);
89
+ }
90
+ } else if (0 === message.size) setData([]);
91
+ else if ("number" == typeof message.size) {
92
+ dataRows.current = dataRowWindow.data;
93
+ hasUpdated.current = true;
94
+ }
95
+ } else if ("viewport-clear" === message.type) {
96
+ onSizeChange?.(0);
97
+ dataRowWindow.setRowCount(0);
98
+ setData([]);
99
+ forceUpdate({});
100
+ } else console.log(`useDataSource unexpected message ${message.type}`);
101
+ }, [
102
+ autoSelect,
103
+ createDataRow,
104
+ dataRowWindow,
105
+ onSizeChange,
106
+ onSubscribed,
107
+ selectRow,
108
+ setData
109
+ ]);
110
+ const getSelectedRows = useCallback(()=>dataRowWindow.getSelectedRows(), [
111
+ dataRowWindow
112
+ ]);
113
+ useEffect(()=>{
114
+ if ("disabled" === dataSource.status) dataSource.enable?.(datasourceMessageHandler);
115
+ }, [
116
+ dataSource,
117
+ datasourceMessageHandler
118
+ ]);
119
+ useMemo(()=>{
120
+ setColumnsRef.current?.(dataSource.columns);
121
+ }, [
122
+ dataSource.columns
123
+ ]);
124
+ const setRange = useCallback((viewportRange)=>{
125
+ if (!rangeRef.current.equals(viewportRange)) {
126
+ const range = Range(viewportRange.from, viewportRange.to, renderBufferSize);
127
+ dataRowWindow.setRange(range.withBuffer);
128
+ if ("subscribed" !== dataSource.status && "subscribing" !== dataSource.status && "enabling" !== dataSource.status) dataSource?.subscribe({
129
+ range,
130
+ revealSelected,
131
+ selectedKeyValues: autoSelectRowKey ? [
132
+ autoSelectRowKey
133
+ ] : void 0
134
+ }, datasourceMessageHandler);
135
+ else dataSource.range = rangeRef.current = range;
136
+ }
137
+ }, [
138
+ autoSelectRowKey,
139
+ dataRowWindow,
140
+ dataSource,
141
+ datasourceMessageHandler,
142
+ renderBufferSize,
143
+ revealSelected
144
+ ]);
145
+ useEffect(()=>{
146
+ if ("initialising" !== dataSource.status) {
147
+ const { columns, tableSchema } = dataSource;
148
+ if (tableSchema) createDataRow(columns, tableSchema.columns);
149
+ else throw Error("[useDataSource] a resumed dataSource must have a tableSchema");
150
+ dataSource.resume?.(datasourceMessageHandler);
151
+ if (dataSource.range.from > 0) {
152
+ const { from, to } = rangeRef.current.reset;
153
+ setRange({
154
+ from,
155
+ to
156
+ });
157
+ }
158
+ }
159
+ return ()=>{
160
+ dataSource.suspend?.(suspenseProps?.escalateToDisable, suspenseProps?.escalateDelay);
161
+ };
162
+ }, [
163
+ createDataRow,
164
+ dataSource,
165
+ datasourceMessageHandler,
166
+ setRange,
167
+ suspenseProps
168
+ ]);
169
+ return {
170
+ dataRows: dataRows.current,
171
+ dataRowsRef: dataRows,
172
+ getSelectedRows,
173
+ range: rangeRef.current,
174
+ setRange
175
+ };
176
+ };
177
+ export { useDataSource };
@@ -0,0 +1,162 @@
1
+ import { getAriaColIndex, getAriaRowIndex } from "@vuu-ui/vuu-utils";
2
+ const headerCellQuery = (colIdx)=>`.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx}']`;
3
+ const dataCellQuery = (ariaRowIdx, ariaColIdx)=>`.vuuTable-table [aria-rowindex='${ariaRowIdx}'] > [aria-colindex='${ariaColIdx}']`;
4
+ const getLevelUp = (containerRef, cellPos)=>{
5
+ const cell = getTableCell(containerRef, cellPos);
6
+ let row = cell?.parentElement;
7
+ const level = parseInt(row?.ariaLevel ?? "1");
8
+ if (level > 1) {
9
+ const targetLevel = `${level - 1}`;
10
+ while(null !== row && row.ariaLevel !== targetLevel)row = row.previousElementSibling;
11
+ if (row) {
12
+ const nextRowIndex = parseInt(row.ariaRowIndex ?? "- 1");
13
+ if (-1 !== nextRowIndex) return [
14
+ nextRowIndex,
15
+ 1
16
+ ];
17
+ }
18
+ }
19
+ return cellPos;
20
+ };
21
+ const getTableCellElement = (containerRef, [rowIdx, colIdx])=>{
22
+ const cssQuery = dataCellQuery(rowIdx, colIdx);
23
+ return containerRef.current?.querySelector(cssQuery);
24
+ };
25
+ const getTableCell = (containerRef, cellPos)=>{
26
+ const cell = getTableCellElement(containerRef, cellPos);
27
+ if (!cellIsEditable(cell)) return cell;
28
+ {
29
+ const focusableContent = cell.querySelector('button,input[type="checkbox"]');
30
+ return focusableContent || cell;
31
+ }
32
+ };
33
+ const getHeaderCell = (containerRef, columnName)=>containerRef.current?.querySelector(`.vuuTableHeaderCell[data-column-name="${columnName}"]`);
34
+ const getFocusedCell = (el)=>{
35
+ if (el?.role == "cell" || el?.role === "columnheader") return el;
36
+ return el?.closest("[role='columnHeader'],[role='cell']");
37
+ };
38
+ const cellIsEditable = (cell)=>cell?.classList.contains("vuuTableCell-editable");
39
+ const cellDropdownShowing = (cell)=>{
40
+ if (cellIsEditable(cell)) return cell?.querySelector('.saltDropdown[aria-expanded="true"]') !== null;
41
+ return false;
42
+ };
43
+ const cellIsGroupCell = (cell)=>cell?.classList.contains("vuuTableGroupCell");
44
+ const rowIsExpanded = (cell)=>{
45
+ switch(cell.parentElement?.ariaExpanded){
46
+ case "true":
47
+ return true;
48
+ case "false":
49
+ return false;
50
+ default:
51
+ return;
52
+ }
53
+ };
54
+ const cellIsTextInput = (cell)=>null !== cell.querySelector(".vuuTableInputCell");
55
+ const getRowElementByAriaIndex = (container, rowIndex)=>{
56
+ if (-1 === rowIndex) return null;
57
+ {
58
+ const activeRow = container.querySelector(`[aria-rowindex="${rowIndex}"]`);
59
+ if (activeRow) return activeRow;
60
+ throw Error(`getRowElementAtIndex no row found for index index ${rowIndex}`);
61
+ }
62
+ };
63
+ const getIndexFromCellElement = (cellElement)=>getAriaColIndex(cellElement);
64
+ const getAriaCellPos = (tableCell)=>{
65
+ const focusedRow = tableCell.closest("[role='row']");
66
+ return [
67
+ getAriaRowIndex(focusedRow),
68
+ getAriaColIndex(tableCell)
69
+ ];
70
+ };
71
+ const closestRow = (el)=>el.closest('[role="row"]');
72
+ const closestRowIndex = (el)=>getAriaRowIndex(closestRow(el));
73
+ function getNextCellPos(key, [rowIdx, colIdx], columnCount, maxRowIndex) {
74
+ if ("ArrowUp" === key) {
75
+ if (rowIdx > -1) return [
76
+ rowIdx - 1,
77
+ colIdx
78
+ ];
79
+ } else if ("ArrowDown" === key) {
80
+ if (-1 === rowIdx) return [
81
+ 1,
82
+ colIdx
83
+ ];
84
+ else if (rowIdx !== maxRowIndex) return [
85
+ rowIdx + 1,
86
+ colIdx
87
+ ];
88
+ } else if ("ArrowRight" === key) {
89
+ if (colIdx < columnCount) return [
90
+ rowIdx,
91
+ colIdx + 1
92
+ ];
93
+ } else if ("ArrowLeft" === key) {
94
+ if (colIdx > 1) return [
95
+ rowIdx,
96
+ colIdx - 1
97
+ ];
98
+ }
99
+ return [
100
+ rowIdx,
101
+ colIdx
102
+ ];
103
+ }
104
+ const getNextEditableCellPos = (containerRef, key, cellPos, columnCount, maxRowIndex)=>{
105
+ let [lastRowIdx, lastColIdx] = cellPos;
106
+ do {
107
+ const [nextRowIdx, nextColIdx] = getNextCellPos(key, [
108
+ lastRowIdx,
109
+ lastColIdx
110
+ ], columnCount, maxRowIndex);
111
+ if (nextRowIdx === lastRowIdx && nextColIdx === lastColIdx) return cellPos;
112
+ const cell = getTableCellElement(containerRef, [
113
+ nextRowIdx,
114
+ nextColIdx
115
+ ]);
116
+ if (cellIsEditable(cell)) return [
117
+ nextRowIdx,
118
+ nextColIdx
119
+ ];
120
+ [lastRowIdx, lastColIdx] = [
121
+ nextRowIdx,
122
+ nextColIdx
123
+ ];
124
+ }while (true)
125
+ };
126
+ const getTreeNodeOperation = (containerRef, navigationStyle, cellPos, key, shiftKey)=>{
127
+ const cell = getTableCell(containerRef, cellPos);
128
+ if ("cell" === navigationStyle && !cellIsGroupCell(cell)) return;
129
+ if ("cell" == navigationStyle && !shiftKey) return;
130
+ if (cellIsGroupCell(cell)) {
131
+ const isExpanded = rowIsExpanded(cell);
132
+ if (true === isExpanded) {
133
+ if ("ArrowLeft" === key) return "collapse";
134
+ } else if (false === isExpanded) {
135
+ if ("ArrowRight" === key) return "expand";
136
+ else if ("ArrowLeft" === key) return "level-up";
137
+ } else if ("ArrowLeft" === key) return "level-up";
138
+ }
139
+ };
140
+ const NO_SCROLL_NECESSARY = [
141
+ void 0,
142
+ void 0
143
+ ];
144
+ const howFarIsRowOutsideViewport = (rowEl, totalHeaderHeight, contentContainer = rowEl.closest(".vuuTable-contentContainer"))=>{
145
+ if (contentContainer) {
146
+ const viewport = contentContainer?.getBoundingClientRect();
147
+ const upperBoundary = viewport.top + totalHeaderHeight;
148
+ const row = rowEl.getBoundingClientRect();
149
+ if (row) if (row.bottom > viewport.bottom) return [
150
+ "down",
151
+ row.bottom - viewport.bottom
152
+ ];
153
+ else if (row.top < upperBoundary) return [
154
+ "up",
155
+ row.top - upperBoundary
156
+ ];
157
+ else return NO_SCROLL_NECESSARY;
158
+ throw Error("Whats going on, row not found");
159
+ }
160
+ throw Error("Whats going on, scrollbar container not found");
161
+ };
162
+ export { cellDropdownShowing, cellIsEditable, cellIsTextInput, closestRowIndex, dataCellQuery, getAriaCellPos, getFocusedCell, getHeaderCell, getIndexFromCellElement, getLevelUp, getNextCellPos, getNextEditableCellPos, getRowElementByAriaIndex, getTableCell, getTableCellElement, getTreeNodeOperation, headerCellQuery, howFarIsRowOutsideViewport };
@@ -0,0 +1,14 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from "react";
3
+ const HeaderContext = /*#__PURE__*/ createContext({
4
+ columns: []
5
+ });
6
+ const HeaderProvider = ({ children, columns, virtualColSpan })=>/*#__PURE__*/ jsx(HeaderContext.Provider, {
7
+ value: {
8
+ columns,
9
+ virtualColSpan
10
+ },
11
+ children: children
12
+ });
13
+ const useHeaderProps = ()=>useContext(HeaderContext);
14
+ export { HeaderProvider, useHeaderProps };
@@ -0,0 +1,182 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useComponentCssInjection } from "@salt-ds/styles";
3
+ import { useWindow } from "@salt-ds/window";
4
+ import { DragDropProvider, DragOverlay, KeyboardSensor, PointerSensor, RestrictToHorizontalAxis, isGroupColumn, isNotHidden } from "@vuu-ui/vuu-utils";
5
+ import { cloneElement, isValidElement, memo, useMemo } from "react";
6
+ import { GroupHeaderCell, HeaderCell as index_mjs_HeaderCell } from "../header-cell/index.mjs";
7
+ import { HeaderProvider } from "./HeaderProvider.mjs";
8
+ import { useTableHeader } from "./useTableHeader.mjs";
9
+ import header_cell_HeaderCell from "../header-cell/HeaderCell.css";
10
+ const isHeaderElement = (h)=>/*#__PURE__*/ isValidElement(h);
11
+ const classBase = "vuuTableHeader";
12
+ const TableHeader = /*#__PURE__*/ memo(({ HeaderCell = index_mjs_HeaderCell, allowDragColumnHeader, allowSelectAll, allRowsSelected, columns, customHeader, headings, onCheckBoxColumnHeaderClick, onHeightMeasured, onMoveColumn, onMoveGroupColumn, onRemoveGroupColumn, onResizeColumn, onSortColumn, showBookends, showColumnHeaderMenus, tableConfig, tableId, virtualColSpan = 0 })=>{
13
+ const targetWindow = useWindow();
14
+ useComponentCssInjection({
15
+ testId: "vuu-table-header-cell",
16
+ css: header_cell_HeaderCell,
17
+ window: targetWindow
18
+ });
19
+ const [customHeaders, customHeaderCount] = useMemo(()=>{
20
+ const offset = headings.length;
21
+ const createElement = (Component, index)=>/*#__PURE__*/ jsx(Component, {
22
+ ariaRowIndex: offset + index + 2,
23
+ ariaRole: "row",
24
+ columns: columns,
25
+ virtualColSpan: virtualColSpan
26
+ }, index);
27
+ const enrichElementWithAria = (el, rowIndex)=>{
28
+ const offset = headings.length;
29
+ return /*#__PURE__*/ cloneElement(el, {
30
+ "aria-rowindex": rowIndex + offset + 2,
31
+ ariaRole: "row"
32
+ });
33
+ };
34
+ if (void 0 === customHeader) return [
35
+ null,
36
+ 0
37
+ ];
38
+ if (Array.isArray(customHeader)) {
39
+ const header = /*#__PURE__*/ jsx(HeaderProvider, {
40
+ columns: columns,
41
+ virtualColSpan: virtualColSpan,
42
+ children: customHeader.map((header, i)=>isHeaderElement(header) ? enrichElementWithAria(header, i) : createElement(header, i))
43
+ });
44
+ return [
45
+ header,
46
+ customHeader.length
47
+ ];
48
+ }
49
+ if (!isHeaderElement(customHeader)) return [
50
+ createElement(customHeader, 0),
51
+ 1
52
+ ];
53
+ {
54
+ const header = /*#__PURE__*/ jsx(HeaderProvider, {
55
+ columns: columns,
56
+ virtualColSpan: virtualColSpan,
57
+ children: enrichElementWithAria(customHeader, 0)
58
+ });
59
+ return [
60
+ header,
61
+ 1
62
+ ];
63
+ }
64
+ }, [
65
+ columns,
66
+ customHeader,
67
+ headings.length,
68
+ virtualColSpan
69
+ ]);
70
+ const { dragColumn, onClick, onDragEnd, onDragStart, setContainerRef } = useTableHeader({
71
+ columns,
72
+ customHeaderCount,
73
+ headings,
74
+ onHeightMeasured,
75
+ onMoveColumn,
76
+ onSortColumn,
77
+ tableConfig
78
+ });
79
+ const visibleColumns = columns.filter(isNotHidden);
80
+ return /*#__PURE__*/ jsxs("div", {
81
+ className: classBase,
82
+ ref: setContainerRef,
83
+ role: "rowgroup",
84
+ children: [
85
+ headings.map((colHeaders, i)=>/*#__PURE__*/ jsx("div", {
86
+ className: "vuuTable-heading",
87
+ role: "row",
88
+ "aria-rowindex": i + 1,
89
+ children: colHeaders.map(({ label, width }, j)=>/*#__PURE__*/ jsx("div", {
90
+ className: "vuuTable-headingCell",
91
+ style: {
92
+ width
93
+ },
94
+ children: label
95
+ }, j))
96
+ }, i)),
97
+ /*#__PURE__*/ jsxs(DragDropProvider, {
98
+ onDragEnd: onDragEnd,
99
+ onDragStart: onDragStart,
100
+ modifiers: [
101
+ RestrictToHorizontalAxis
102
+ ],
103
+ sensors: [
104
+ KeyboardSensor.configure({
105
+ keyboardCodes: {
106
+ start: [
107
+ "Space"
108
+ ],
109
+ cancel: [
110
+ "Escape"
111
+ ],
112
+ end: [
113
+ "Space",
114
+ "Enter"
115
+ ],
116
+ left: [
117
+ "ArrowLeft"
118
+ ],
119
+ right: [
120
+ "ArrowRight"
121
+ ],
122
+ up: [],
123
+ down: []
124
+ }
125
+ }),
126
+ PointerSensor
127
+ ],
128
+ children: [
129
+ /*#__PURE__*/ jsxs("div", {
130
+ className: "vuuTableColHeaderRow",
131
+ role: "row",
132
+ "aria-rowindex": headings.length + 1,
133
+ children: [
134
+ showBookends ? /*#__PURE__*/ jsx("div", {
135
+ className: "vuuSelectionDecorator vuuStickyLeft"
136
+ }) : null,
137
+ visibleColumns.map((col, i)=>{
138
+ const allowDragDrop = !!allowDragColumnHeader && !col.pin;
139
+ return isGroupColumn(col) ? /*#__PURE__*/ jsx(GroupHeaderCell, {
140
+ column: col,
141
+ id: `${tableId}-${col.name}`,
142
+ onMoveColumn: onMoveGroupColumn,
143
+ onRemoveColumn: onRemoveGroupColumn,
144
+ onResize: onResizeColumn
145
+ }, col.name) : /*#__PURE__*/ jsx(HeaderCell, {
146
+ allowDragColumnHeader: allowDragDrop,
147
+ allowSelectAll: allowSelectAll,
148
+ allRowsSelected: allRowsSelected,
149
+ column: col,
150
+ index: i,
151
+ id: `${tableId}-${col.name}`,
152
+ onCheckBoxColumnHeaderClick: onCheckBoxColumnHeaderClick,
153
+ onClick: onClick,
154
+ onResize: onResizeColumn,
155
+ showColumnHeaderMenus: showColumnHeaderMenus
156
+ }, `${col.name}-${allowDragDrop}`);
157
+ }),
158
+ showBookends ? /*#__PURE__*/ jsx("div", {
159
+ className: "vuuSelectionDecorator vuuStickyRight"
160
+ }) : null
161
+ ]
162
+ }),
163
+ /*#__PURE__*/ jsx(DragOverlay, {
164
+ children: dragColumn ? /*#__PURE__*/ jsx("div", {
165
+ id: dragColumn.id,
166
+ className: "DragColumn",
167
+ children: /*#__PURE__*/ jsx(HeaderCell, {
168
+ column: dragColumn.column,
169
+ className: "vuuDragging",
170
+ id: `${tableId}-${dragColumn.id}-dragging`,
171
+ index: -1
172
+ })
173
+ }) : null
174
+ })
175
+ ]
176
+ }),
177
+ customHeaders
178
+ ]
179
+ });
180
+ });
181
+ TableHeader.displayName = "TableHeader";
182
+ export { TableHeader };
@@ -0,0 +1,2 @@
1
+ export * from "./HeaderProvider.mjs";
2
+ export * from "./TableHeader.mjs";
@@ -0,0 +1,69 @@
1
+ import { queryClosest, reorderColumnItems, visibleColumnAtIndex } from "@vuu-ui/vuu-utils";
2
+ import { useCallback, useRef, useState } from "react";
3
+ import { useMeasuredHeight } from "../useMeasuredHeight.mjs";
4
+ import { useForkRef } from "@salt-ds/core";
5
+ const useTableHeader = ({ columns, customHeaderCount, headings, onHeightMeasured, onMoveColumn, onSortColumn })=>{
6
+ const containerRef = useRef(null);
7
+ const scrollingContainerRef = useRef(null);
8
+ const [dragColumn, setDragColumn] = useState(null);
9
+ const handleHeightMeasured = useCallback((height)=>{
10
+ onHeightMeasured(height, customHeaderCount + headings.length + 1);
11
+ }, [
12
+ customHeaderCount,
13
+ headings,
14
+ onHeightMeasured
15
+ ]);
16
+ const { measuredRef: rowRef } = useMeasuredHeight({
17
+ onHeightMeasured: handleHeightMeasured
18
+ });
19
+ const setContainerRef = useCallback((el)=>{
20
+ containerRef.current = el;
21
+ if (el) scrollingContainerRef.current = el.closest(".vuuTable-contentContainer");
22
+ else scrollingContainerRef.current = null;
23
+ }, []);
24
+ const handleDragStart = useCallback((evt)=>{
25
+ const element = evt.operation.source;
26
+ const columnName = element.id.split("-").at(-1);
27
+ const column = columns.find((col)=>col.name === columnName);
28
+ if (void 0 === column) throw Error(`[useTableHeader] No column '${columnName}'`);
29
+ setDragColumn({
30
+ column,
31
+ id: element.id
32
+ });
33
+ }, [
34
+ columns
35
+ ]);
36
+ const handleDragEnd = useCallback(()=>{
37
+ setTimeout(()=>{
38
+ const listItems = containerRef.current?.querySelectorAll(".vuuTableHeaderCell");
39
+ if (listItems && dragColumn?.column) {
40
+ const orderedColumnNames = Array.from(listItems).map(({ dataset })=>dataset.columnName);
41
+ onMoveColumn(dragColumn?.column.name, reorderColumnItems(columns, orderedColumnNames));
42
+ }
43
+ }, 300);
44
+ }, [
45
+ columns,
46
+ dragColumn,
47
+ onMoveColumn
48
+ ]);
49
+ const handleColumnHeaderClick = useCallback((evt)=>{
50
+ const headerCell = queryClosest(evt.target, ".vuuTableHeaderCell");
51
+ const colIdx = parseInt(headerCell?.dataset.index ?? "-1");
52
+ const column = visibleColumnAtIndex(columns, colIdx);
53
+ if (column && false !== column.sortable) {
54
+ const isAdditive = evt.shiftKey;
55
+ onSortColumn(column, isAdditive);
56
+ }
57
+ }, [
58
+ columns,
59
+ onSortColumn
60
+ ]);
61
+ return {
62
+ dragColumn,
63
+ onClick: handleColumnHeaderClick,
64
+ onDragEnd: handleDragEnd,
65
+ onDragStart: handleDragStart,
66
+ setContainerRef: useForkRef(setContainerRef, rowRef)
67
+ };
68
+ };
69
+ export { useTableHeader };
@@ -0,0 +1,22 @@
1
+ import { getColumnStyle } from "@vuu-ui/vuu-utils";
2
+ import clsx from "clsx";
3
+ import { useMemo } from "react";
4
+ const useCell = (column, classBase, isHeader)=>useMemo(()=>{
5
+ const className = clsx(classBase, column.className, {
6
+ vuuPinLeft: "left" === column.pin,
7
+ vuuPinRight: "right" === column.pin,
8
+ vuuEndPin: isHeader && column.pinnedWidth,
9
+ [`${classBase}-editable`]: column.editable,
10
+ [`${classBase}-right`]: "right" === column.align
11
+ });
12
+ const style = getColumnStyle(column);
13
+ return {
14
+ className,
15
+ style
16
+ };
17
+ }, [
18
+ classBase,
19
+ column,
20
+ isHeader
21
+ ]);
22
+ export { useCell };
@@ -0,0 +1,58 @@
1
+ import { isCharacterKey } from "@vuu-ui/vuu-utils";
2
+ import { useCallback } from "react";
3
+ import { cellIsTextInput } from "./table-dom-utils.mjs";
4
+ const useCellEditing = ({ navigate })=>{
5
+ const commitHandler = useCallback(()=>{
6
+ navigate();
7
+ }, [
8
+ navigate
9
+ ]);
10
+ const editInput = useCallback((evt)=>{
11
+ const cellEl = evt.target;
12
+ const input = cellEl.matches("input") ? cellEl : cellEl.querySelector("input");
13
+ if (input) input.focus();
14
+ }, []);
15
+ const focusInput = useCallback((evt)=>{
16
+ const cellEl = evt.target;
17
+ const input = cellEl.querySelector("input");
18
+ if (input) input.focus();
19
+ }, []);
20
+ const handleKeyDown = useCallback((e)=>{
21
+ const el = e.target;
22
+ if (cellIsTextInput(el)) {
23
+ if (isCharacterKey(e.key)) editInput(e);
24
+ else if ("Enter" === e.key) focusInput(e);
25
+ }
26
+ }, [
27
+ editInput,
28
+ focusInput
29
+ ]);
30
+ const handleDoubleClick = useCallback((e)=>{
31
+ const el = e.target;
32
+ if (el.matches("input") || el.querySelector("input")) {
33
+ editInput(e);
34
+ e.stopPropagation();
35
+ }
36
+ }, [
37
+ editInput
38
+ ]);
39
+ const handleBlur = useCallback((e)=>{
40
+ const el = e.target;
41
+ el.removeEventListener("vuu-commit", commitHandler, true);
42
+ }, [
43
+ commitHandler
44
+ ]);
45
+ const handleFocus = useCallback((e)=>{
46
+ const el = e.target;
47
+ el.addEventListener("vuu-commit", commitHandler, true);
48
+ }, [
49
+ commitHandler
50
+ ]);
51
+ return {
52
+ onBlur: handleBlur,
53
+ onDoubleClick: handleDoubleClick,
54
+ onFocus: handleFocus,
55
+ onKeyDown: handleKeyDown
56
+ };
57
+ };
58
+ export { useCellEditing };