@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,101 @@
1
+ import { deselectItem, dispatchMouseEvent, queryClosest, selectItem } from "@vuu-ui/vuu-utils";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { getRowElementByAriaIndex } from "./table-dom-utils.mjs";
4
+ const orderedRowKeys = (activeRowIdentifier, newRowIdentifier, rangeSelect = false)=>{
5
+ if (!rangeSelect || !activeRowIdentifier) return [
6
+ newRowIdentifier.rowKey
7
+ ];
8
+ if (newRowIdentifier.rowIdx > activeRowIdentifier.rowIdx) return [
9
+ activeRowIdentifier.rowKey,
10
+ newRowIdentifier.rowKey
11
+ ];
12
+ return [
13
+ newRowIdentifier.rowKey,
14
+ activeRowIdentifier.rowKey
15
+ ];
16
+ };
17
+ const defaultSelectionKeys = [
18
+ "Enter",
19
+ " "
20
+ ];
21
+ const useSelection = ({ allowSelectCheckboxRow, containerRef, dataSource, highlightedIndexRef, onSelect, onSelectionChange, selectionKeys = defaultSelectionKeys, selectionModel })=>{
22
+ const lastActiveRef = useRef(void 0);
23
+ const [allRowsSelected, setAllRowsSelected] = useState(false);
24
+ const selectionAllowed = "none" !== selectionModel && "checkbox-disabled" !== selectionModel;
25
+ const handleRowSelection = useCallback((selectedRowsCount)=>{
26
+ setAllRowsSelected((allSelected)=>allSelected && selectedRowsCount < dataSource.size ? false : allSelected);
27
+ }, [
28
+ dataSource.size
29
+ ]);
30
+ useEffect(()=>{
31
+ dataSource.on("row-selection", handleRowSelection);
32
+ return ()=>dataSource.removeListener("row-selection", handleRowSelection);
33
+ }, [
34
+ dataSource,
35
+ handleRowSelection
36
+ ]);
37
+ const isSelectionEvent = useCallback((evt)=>selectionKeys.includes(evt.key), [
38
+ selectionKeys
39
+ ]);
40
+ const handleRowClick = useCallback((e, dataRow, rangeSelect, keepExistingSelection)=>{
41
+ const { index: rowIdx, key: rowKey } = dataRow;
42
+ const { current: activeRowKey } = lastActiveRef;
43
+ const newRowIdentifier = {
44
+ rowIdx,
45
+ rowKey
46
+ };
47
+ if (dataRow.isSelected && "single-no-deselect" === selectionModel) return;
48
+ const selectOperation = dataRow.isSelected ? deselectItem : selectItem;
49
+ if ("checkbox" === selectionModel && true !== allowSelectCheckboxRow) {
50
+ const cell = queryClosest(e.target, ".vuuTableCell");
51
+ if (!cell?.querySelector(".vuuCheckboxRowSelector")) return;
52
+ }
53
+ const [fromRowKey, toRowKey] = orderedRowKeys(activeRowKey, newRowIdentifier, rangeSelect);
54
+ const selectRequest = selectOperation(selectionModel, fromRowKey, rangeSelect, keepExistingSelection, toRowKey);
55
+ lastActiveRef.current = newRowIdentifier;
56
+ if (selectRequest) {
57
+ onSelect?.(selectOperation === selectItem ? dataRow : null);
58
+ onSelectionChange?.(selectRequest);
59
+ }
60
+ if (allRowsSelected && selectOperation === deselectItem) setAllRowsSelected(false);
61
+ }, [
62
+ allRowsSelected,
63
+ allowSelectCheckboxRow,
64
+ onSelect,
65
+ onSelectionChange,
66
+ selectionModel
67
+ ]);
68
+ const handleKeyDown = useCallback((e)=>{
69
+ if (isSelectionEvent(e)) {
70
+ const { current: rowIndex } = highlightedIndexRef;
71
+ const { current: container } = containerRef;
72
+ if (void 0 !== rowIndex && -1 !== rowIndex && container) {
73
+ const rowEl = getRowElementByAriaIndex(container, rowIndex);
74
+ if (rowEl) dispatchMouseEvent(rowEl, "click");
75
+ }
76
+ }
77
+ }, [
78
+ containerRef,
79
+ highlightedIndexRef,
80
+ isSelectionEvent
81
+ ]);
82
+ const handleCheckboxColumnHeaderClick = useCallback(()=>{
83
+ setAllRowsSelected((allSelected)=>{
84
+ allSelected ? onSelectionChange({
85
+ type: "DESELECT_ALL"
86
+ }) : onSelectionChange({
87
+ type: "SELECT_ALL"
88
+ });
89
+ return !allSelected;
90
+ });
91
+ }, [
92
+ onSelectionChange
93
+ ]);
94
+ return {
95
+ allRowsSelected,
96
+ onCheckBoxColumnHeaderClick: handleCheckboxColumnHeaderClick,
97
+ onKeyDown: handleKeyDown,
98
+ onRowClick: selectionAllowed ? handleRowClick : void 0
99
+ };
100
+ };
101
+ export { useSelection };
@@ -0,0 +1,588 @@
1
+ import { useColumnActions } from "@vuu-ui/vuu-table-extras";
2
+ import { useDragDrop } from "@vuu-ui/vuu-ui-controls";
3
+ import { getAllCellsInColumn, getAriaRowIndex, getPinStateFromElement, isGroupColumn, isJsonGroup, isValidNumber, logUnhandledMessage, metadataKeys, toggleOrApplySort, updateColumn, useEditSession, useLayoutEffectSkipFirst, useStableReference } from "@vuu-ui/vuu-utils";
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
+ import { useCellBlockSelection } from "./cell-block/useCellBlockSelection.mjs";
6
+ import { CellFocusState } from "./CellFocusState.mjs";
7
+ import { updateTableConfig } from "./table-config.mjs";
8
+ import { getHeaderCell } from "./table-dom-utils.mjs";
9
+ import { useCellEditing } from "./useCellEditing.mjs";
10
+ import { useCellFocus } from "./useCellFocus.mjs";
11
+ import { useDataSource } from "./table-data-source/useDataSource.mjs";
12
+ import { useKeyboardNavigation } from "./useKeyboardNavigation.mjs";
13
+ import { useRowClassNameGenerators } from "./useRowClassNameGenerators.mjs";
14
+ import { useSelection } from "./useSelection.mjs";
15
+ import { useTableContextMenu } from "./useTableContextMenu.mjs";
16
+ import { useTableModel } from "./useTableModel.mjs";
17
+ import { useTableScroll } from "./useTableScroll.mjs";
18
+ import { useTableViewport } from "./useTableViewport.mjs";
19
+ const nullHeaderState = {
20
+ height: -1,
21
+ count: -1
22
+ };
23
+ const zeroHeaderState = {
24
+ height: 0,
25
+ count: 0
26
+ };
27
+ const { IS_EXPANDED: IS_EXPANDED, IS_LEAF: IS_LEAF } = metadataKeys;
28
+ const NULL_DRAG_DROP = {
29
+ draggable: void 0,
30
+ onMouseDown: void 0
31
+ };
32
+ const useNullDragDrop = ()=>NULL_DRAG_DROP;
33
+ const useTable = ({ allowCellBlockSelection, allowSelectCheckboxRow, allowDragDrop = false, autoSelectFirstRow, autoSelectRowKey, config, containerRef, dataSource, disableFocus, highlightedIndex: highlightedIndexProp, id, navigationStyle = "cell", onConfigChange, onDragStart, onDrop, onHighlight, onRowClick: onRowClickProp, onSelect, onSelectCellBlock, onSelectionChange, renderBufferSize = 0, revealSelected, rowHeight, scrollingApiRef, selectionModel, showColumnHeaders, showPaginationControls, size })=>{
34
+ const tableConfigRef = useRef(config);
35
+ const scrollTopRef = useRef(0);
36
+ const requestScrollRef = useRef(void 0);
37
+ useMemo(()=>{
38
+ tableConfigRef.current = config;
39
+ }, [
40
+ config
41
+ ]);
42
+ const editSession = useEditSession();
43
+ const initialState = useMemo(()=>new CellFocusState(), []);
44
+ const cellFocusStateRef = useRef(initialState);
45
+ const focusCellRef = useRef(void 0);
46
+ const [headerState, setHeaderState] = useState(showColumnHeaders ? nullHeaderState : zeroHeaderState);
47
+ const [rowCount, setRowCount] = useState(dataSource.size);
48
+ if (void 0 === dataSource) throw Error("no data source provided to Vuu Table");
49
+ const onDataRowcountChange = useCallback((size)=>{
50
+ setRowCount(size);
51
+ }, []);
52
+ const { selectionBookendWidth = 4 } = config;
53
+ const virtualContentHeight = rowHeight * rowCount;
54
+ const viewportBodyHeight = size.height - (-1 === headerState.height ? 0 : headerState.height);
55
+ const verticalScrollbarWidth = virtualContentHeight > viewportBodyHeight ? 10 : 0;
56
+ const availableWidth = size.width - (verticalScrollbarWidth + 2 * selectionBookendWidth);
57
+ const rowClassNameGenerator = useRowClassNameGenerators(config);
58
+ const useRowDragDrop = allowDragDrop ? useDragDrop : useNullDragDrop;
59
+ const { columns, dispatchTableModelAction, headings, tableAttributes, tableConfig } = useTableModel({
60
+ config,
61
+ dataSource,
62
+ selectionModel,
63
+ availableWidth
64
+ });
65
+ const columnsRef = useStableReference(columns);
66
+ useLayoutEffectSkipFirst(()=>{
67
+ dispatchTableModelAction({
68
+ availableWidth,
69
+ selectionModel,
70
+ type: "init",
71
+ tableConfig: tableConfigRef.current,
72
+ dataSource
73
+ });
74
+ }, [
75
+ availableWidth,
76
+ config,
77
+ dataSource,
78
+ dispatchTableModelAction,
79
+ selectionModel
80
+ ]);
81
+ const applyTableConfigChange = useCallback((config, changeType)=>{
82
+ dispatchTableModelAction({
83
+ availableWidth,
84
+ selectionModel,
85
+ type: "init",
86
+ tableConfig: config,
87
+ dataSource
88
+ });
89
+ tableConfigRef.current = config;
90
+ onConfigChange?.(config, changeType);
91
+ }, [
92
+ availableWidth,
93
+ dataSource,
94
+ dispatchTableModelAction,
95
+ onConfigChange,
96
+ selectionModel
97
+ ]);
98
+ const handleSelectionChange = useCallback((selectRequest)=>{
99
+ dataSource.select?.(selectRequest);
100
+ onSelectionChange?.(selectRequest);
101
+ }, [
102
+ dataSource,
103
+ onSelectionChange
104
+ ]);
105
+ const handleSelect = useCallback((dataRow)=>{
106
+ if (onSelect) onSelect(dataRow);
107
+ }, [
108
+ onSelect
109
+ ]);
110
+ const onSubscribed = useCallback(({ tableSchema })=>{
111
+ if (tableSchema) dispatchTableModelAction({
112
+ type: "setTableSchema",
113
+ tableSchema
114
+ });
115
+ else console.log("subscription message with no schema");
116
+ }, [
117
+ dispatchTableModelAction
118
+ ]);
119
+ const { getRowAtPosition, getRowOffset, setInSituRowOffset: viewportHookSetInSituRowOffset, setScrollTop: viewportHookSetScrollTop, ...viewportMeasurements } = useTableViewport({
120
+ columns,
121
+ headerHeight: headerState.height,
122
+ rowCount,
123
+ rowHeight,
124
+ selectionEndSize: selectionBookendWidth,
125
+ size: size,
126
+ showPaginationControls
127
+ });
128
+ const { dataRows, dataRowsRef, getSelectedRows, range, setRange } = useDataSource({
129
+ autoSelectFirstRow,
130
+ autoSelectRowKey,
131
+ dataSource,
132
+ renderBufferSize,
133
+ revealSelected,
134
+ onSelect: handleSelect,
135
+ onSizeChange: onDataRowcountChange,
136
+ onSubscribed,
137
+ selectionModel
138
+ });
139
+ const { requestScroll, scrollTop, ...scrollProps } = useTableScroll({
140
+ cellFocusStateRef,
141
+ columns,
142
+ getRowAtPosition,
143
+ rowHeight,
144
+ scrollingApiRef,
145
+ setRange,
146
+ showPaginationControls,
147
+ onVerticalScroll: viewportHookSetScrollTop,
148
+ onVerticalScrollInSitu: viewportHookSetInSituRowOffset,
149
+ viewportMeasurements
150
+ });
151
+ scrollTopRef.current = scrollTop;
152
+ requestScrollRef.current = requestScroll;
153
+ const handleConfigChange = useCallback((config, _range, confirmed, changes)=>{
154
+ const scrollSensitiveChanges = changes?.filterChanged || changes?.groupByChanged;
155
+ if (scrollSensitiveChanges && scrollTopRef.current > 0) {
156
+ setRange(range.reset);
157
+ requestScrollRef.current?.({
158
+ type: "scroll-top",
159
+ scrollPos: 0,
160
+ instant: true
161
+ });
162
+ }
163
+ dispatchTableModelAction({
164
+ type: "tableConfig",
165
+ ...config,
166
+ confirmed
167
+ });
168
+ }, [
169
+ dispatchTableModelAction,
170
+ range,
171
+ setRange
172
+ ]);
173
+ useEffect(()=>{
174
+ dataSource.on("config", handleConfigChange);
175
+ return ()=>{
176
+ dataSource.removeListener("config", handleConfigChange);
177
+ };
178
+ }, [
179
+ dataSource,
180
+ dispatchTableModelAction,
181
+ handleConfigChange
182
+ ]);
183
+ const removeColumn = useCallback((action)=>{
184
+ const { column } = action;
185
+ const newTableConfig = {
186
+ ...tableConfig,
187
+ columns: tableConfig.columns.filter((col)=>col.name !== column.name)
188
+ };
189
+ applyTableConfigChange(newTableConfig, {
190
+ type: "column-removed",
191
+ column
192
+ });
193
+ }, [
194
+ applyTableConfigChange,
195
+ tableConfig
196
+ ]);
197
+ const hideColumns = useCallback((action)=>{
198
+ const { columns } = action;
199
+ const hiddenColumns = columns.map((c)=>c.name);
200
+ const newTableConfig = {
201
+ ...tableConfig,
202
+ columns: tableConfig.columns.map((col)=>hiddenColumns.includes(col.name) ? {
203
+ ...col,
204
+ hidden: true
205
+ } : col)
206
+ };
207
+ applyTableConfigChange(newTableConfig, {
208
+ type: "columns-hidden",
209
+ columns
210
+ });
211
+ }, [
212
+ tableConfig,
213
+ applyTableConfigChange
214
+ ]);
215
+ const pinColumn = useCallback(({ column, pin })=>{
216
+ applyTableConfigChange({
217
+ ...tableConfig,
218
+ columns: updateColumn(tableConfig.columns, {
219
+ ...column,
220
+ pin
221
+ })
222
+ }, {
223
+ type: "column-pinned",
224
+ column
225
+ });
226
+ }, [
227
+ tableConfig,
228
+ applyTableConfigChange
229
+ ]);
230
+ const handleColumnDisplayAction = useCallback((action)=>{
231
+ const { type } = action;
232
+ switch(type){
233
+ case "hideColumn":
234
+ return hideColumns({
235
+ type: "hideColumns",
236
+ columns: [
237
+ action.column
238
+ ]
239
+ });
240
+ case "removeColumn":
241
+ return removeColumn({
242
+ type: "removeColumn",
243
+ column: action.column
244
+ });
245
+ case "pinColumn":
246
+ return pinColumn(action);
247
+ default:
248
+ logUnhandledMessage(type, "[vuu-table] handleColumnDisplayAction");
249
+ }
250
+ }, [
251
+ hideColumns,
252
+ pinColumn,
253
+ removeColumn
254
+ ]);
255
+ const handleColumnAction = useColumnActions({
256
+ dataSource,
257
+ onColumnDisplayAction: handleColumnDisplayAction
258
+ });
259
+ const handleSort = useCallback((column, extendSort = false, sortType)=>{
260
+ if (dataSource) dataSource.sort = toggleOrApplySort(dataSource.sort, column, extendSort, sortType);
261
+ }, [
262
+ dataSource
263
+ ]);
264
+ const cellResizeState = useRef(void 0);
265
+ const onResizeColumn = useCallback((phase, columnName, width = 0)=>{
266
+ if ("resize" === phase) {
267
+ cellResizeState.current?.cells.forEach((cell)=>{
268
+ cell.style.width = `${width}px`;
269
+ });
270
+ if (cellResizeState.current?.pinState) {
271
+ const { pinState, startWidth } = cellResizeState.current;
272
+ const { cell: pinnedCell, pinnedWidth } = pinState;
273
+ const diff = width - startWidth;
274
+ if (pinState.pinnedCells) pinState.pinnedCells.forEach((cell)=>{
275
+ cell.style.left = `${parseInt(cell.style.left) + diff}px`;
276
+ });
277
+ pinnedCell.style.setProperty("--pin-width", `${pinnedWidth + diff}px`);
278
+ }
279
+ } else {
280
+ const column = columnsRef.current.find((column)=>column.name === columnName);
281
+ if (column) {
282
+ if ("end" === phase) {
283
+ cellResizeState.current = void 0;
284
+ if (isValidNumber(width)) {
285
+ dispatchTableModelAction({
286
+ type: "resizeColumn",
287
+ phase,
288
+ column,
289
+ width
290
+ });
291
+ onConfigChange?.(updateTableConfig(tableConfig, {
292
+ type: "col-size",
293
+ column,
294
+ columns,
295
+ width
296
+ }), {
297
+ type: "column-resized",
298
+ column,
299
+ width
300
+ });
301
+ }
302
+ } else if ("begin" === phase) {
303
+ cellResizeState.current = {
304
+ cells: getAllCellsInColumn(containerRef.current, column.ariaColIndex),
305
+ startWidth: column.width
306
+ };
307
+ const [headerCell] = cellResizeState.current.cells;
308
+ cellResizeState.current.pinState = getPinStateFromElement(headerCell);
309
+ dispatchTableModelAction({
310
+ type: "resizeColumn",
311
+ phase,
312
+ column,
313
+ width
314
+ });
315
+ onConfigChange?.(updateTableConfig(tableConfig, {
316
+ type: "col-size",
317
+ column,
318
+ columns,
319
+ width
320
+ }), {
321
+ type: "column-resized",
322
+ column,
323
+ width
324
+ });
325
+ }
326
+ } else throw Error(`useDataTable.handleColumnResize, column ${columnName} not found`);
327
+ }
328
+ }, [
329
+ columnsRef,
330
+ dispatchTableModelAction,
331
+ onConfigChange,
332
+ tableConfig,
333
+ columns,
334
+ containerRef
335
+ ]);
336
+ const onToggleGroup = useCallback((dataRow, column)=>{
337
+ const isJson = isJsonGroup(column, dataRow);
338
+ const { key } = dataRow;
339
+ if (dataRow.isExpanded) {
340
+ dataSource.closeTreeNode(key, true);
341
+ if (isJson) {
342
+ const idx = columns.indexOf(column);
343
+ const rows = dataSource.getRowsAtDepth?.(idx + 1);
344
+ if (rows && !rows.some((row)=>row[IS_EXPANDED] || row[IS_LEAF])) dispatchTableModelAction({
345
+ type: "hideColumns",
346
+ columns: columns.slice(idx + 2)
347
+ });
348
+ }
349
+ } else {
350
+ dataSource.openTreeNode(key);
351
+ if (isJson) {
352
+ const childRows = dataSource.getChildRows?.(key);
353
+ const idx = columns.indexOf(column) + 1;
354
+ const columnsToShow = [
355
+ columns[idx]
356
+ ];
357
+ if (childRows && childRows.some((row)=>row[IS_LEAF])) columnsToShow.push(columns[idx + 1]);
358
+ if (columnsToShow.some((col)=>col.hidden)) dispatchTableModelAction({
359
+ type: "showColumns",
360
+ columns: columnsToShow
361
+ });
362
+ }
363
+ }
364
+ }, [
365
+ columns,
366
+ dataSource,
367
+ dispatchTableModelAction
368
+ ]);
369
+ const handleToggleGroup = useCallback((treeNodeOperation, rowIdx)=>{
370
+ if ("expand" === treeNodeOperation) dataSource.openTreeNode(rowIdx);
371
+ else dataSource.closeTreeNode(rowIdx);
372
+ }, [
373
+ dataSource
374
+ ]);
375
+ const { focusCell, focusCellPlaceholderKeyDown, focusCellPlaceholderRef, setTableBodyRef: tableBodyRef } = useCellFocus({
376
+ cellFocusStateRef,
377
+ containerRef,
378
+ disableFocus,
379
+ requestScroll
380
+ });
381
+ focusCellRef.current = focusCell;
382
+ const columnCount = columns.filter((c)=>true !== c.hidden).length;
383
+ const { highlightedIndexRef, navigateCell: navigate, onFocus: navigationFocus, onKeyDown: navigationKeyDown, ...containerProps } = useKeyboardNavigation({
384
+ cellFocusStateRef,
385
+ columnCount,
386
+ containerRef,
387
+ disableFocus,
388
+ editSessionInProgress: editSession?.inEditMode,
389
+ focusCell,
390
+ headerCount: headerState.count,
391
+ highlightedIndex: highlightedIndexProp,
392
+ navigationStyle,
393
+ requestScroll,
394
+ rowCount,
395
+ onHighlight,
396
+ onToggleGroup: handleToggleGroup,
397
+ viewportRange: range,
398
+ viewportRowCount: viewportMeasurements.rowCount
399
+ });
400
+ const { onBlur: editingBlur, onDoubleClick: editingDoubleClick, onKeyDown: editingKeyDown, onFocus: editingFocus } = useCellEditing({
401
+ navigate
402
+ });
403
+ const handleFocus = useCallback((e)=>{
404
+ navigationFocus();
405
+ if (!e.defaultPrevented) editingFocus(e);
406
+ }, [
407
+ editingFocus,
408
+ navigationFocus
409
+ ]);
410
+ const onContextMenu = useTableContextMenu({
411
+ columns,
412
+ dataRows,
413
+ dataSource,
414
+ getSelectedRows,
415
+ headerCount: headerState.count
416
+ });
417
+ const onMoveGroupColumn = useCallback((columns)=>{
418
+ dataSource.groupBy = columns.map((col)=>col.name);
419
+ }, [
420
+ dataSource
421
+ ]);
422
+ const onRemoveGroupColumn = useCallback((column)=>{
423
+ if (isGroupColumn(column)) dataSource.groupBy = [];
424
+ else if (dataSource && dataSource.groupBy?.includes(column.name)) dataSource.groupBy = dataSource.groupBy.filter((columnName)=>columnName !== column.name);
425
+ }, [
426
+ dataSource
427
+ ]);
428
+ const { allRowsSelected, onCheckBoxColumnHeaderClick, onKeyDown: selectionHookKeyDown, onRowClick: selectionHookOnRowClick } = useSelection({
429
+ allowSelectCheckboxRow,
430
+ containerRef,
431
+ dataSource,
432
+ highlightedIndexRef,
433
+ onSelect: handleSelect,
434
+ onSelectionChange: handleSelectionChange,
435
+ selectionModel
436
+ });
437
+ const handleSelectCellBlock = useCallback((cellBlock)=>{
438
+ handleSelectionChange({
439
+ type: "DESELECT_ALL"
440
+ });
441
+ onSelectCellBlock?.(cellBlock);
442
+ }, [
443
+ handleSelectionChange,
444
+ onSelectCellBlock
445
+ ]);
446
+ const { onMouseDown: cellBlockHookMouseDown, cellBlock, onKeyDown: cellBlockSelectionKeyDown } = useCellBlockSelection({
447
+ allowCellBlockSelection,
448
+ columnCount,
449
+ containerRef,
450
+ onSelectCellBlock: handleSelectCellBlock,
451
+ rowCount
452
+ });
453
+ const handleRowClick = useCallback((evt, dataRow, rangeSelect, keepExistingSelection)=>{
454
+ selectionHookOnRowClick?.(evt, dataRow, rangeSelect, keepExistingSelection);
455
+ onRowClickProp?.(evt, dataRow);
456
+ }, [
457
+ onRowClickProp,
458
+ selectionHookOnRowClick
459
+ ]);
460
+ const handleKeyDown = useCallback((e)=>{
461
+ cellBlockSelectionKeyDown?.(e);
462
+ if (!e.defaultPrevented) navigationKeyDown(e);
463
+ if (!e.defaultPrevented) editingKeyDown(e);
464
+ if (!e.defaultPrevented) selectionHookKeyDown(e);
465
+ }, [
466
+ cellBlockSelectionKeyDown,
467
+ navigationKeyDown,
468
+ editingKeyDown,
469
+ selectionHookKeyDown
470
+ ]);
471
+ const onMoveColumn = useCallback((columnName, columns)=>{
472
+ const newTableConfig = {
473
+ ...tableConfig,
474
+ columns
475
+ };
476
+ tableConfigRef.current = newTableConfig;
477
+ dispatchTableModelAction({
478
+ availableWidth,
479
+ type: "init",
480
+ tableConfig: newTableConfig,
481
+ dataSource
482
+ });
483
+ onConfigChange?.(newTableConfig, {
484
+ columnName,
485
+ columns,
486
+ type: "column-moved"
487
+ });
488
+ setTimeout(()=>{
489
+ const headerCell = getHeaderCell(containerRef, columnName);
490
+ if (headerCell) {
491
+ const { ariaColIndex } = headerCell;
492
+ const { ariaRowIndex } = headerCell.parentElement;
493
+ const col = parseInt(ariaColIndex ?? "-1");
494
+ const row = parseInt(ariaRowIndex ?? "-1");
495
+ if (!isNaN(col) && -1 !== col && !isNaN(row) && -1 !== row) focusCell([
496
+ row,
497
+ col
498
+ ]);
499
+ }
500
+ }, 300);
501
+ }, [
502
+ availableWidth,
503
+ containerRef,
504
+ dataSource,
505
+ dispatchTableModelAction,
506
+ focusCell,
507
+ onConfigChange,
508
+ tableConfig
509
+ ]);
510
+ const handleDropRow = useCallback((dragDropState)=>{
511
+ onDrop?.(dragDropState);
512
+ }, [
513
+ onDrop
514
+ ]);
515
+ const handleDragStartRow = useCallback((dragDropState)=>{
516
+ const { initialDragElement } = dragDropState;
517
+ const rowIndex = getAriaRowIndex(initialDragElement) - headerState.count - 1;
518
+ const row = dataRowsRef.current.find((row)=>row.index === rowIndex);
519
+ if (row) dragDropState.setPayload(row);
520
+ onDragStart?.(dragDropState);
521
+ }, [
522
+ dataRowsRef,
523
+ headerState.count,
524
+ onDragStart
525
+ ]);
526
+ const onHeaderHeightMeasured = useCallback((height, count)=>{
527
+ setHeaderState({
528
+ height,
529
+ count
530
+ });
531
+ }, []);
532
+ const { onMouseDown: rowDragMouseDown, draggable: draggableRow } = useRowDragDrop({
533
+ allowDragDrop,
534
+ containerRef,
535
+ draggableClassName: "vuuTable",
536
+ id,
537
+ onDragStart: handleDragStartRow,
538
+ onDrop: handleDropRow,
539
+ orientation: "vertical",
540
+ itemQuery: ".vuuTableRow"
541
+ });
542
+ const handleMouseDown = useCallback((evt)=>{
543
+ rowDragMouseDown?.(evt);
544
+ if (!evt.isPropagationStopped()) cellBlockHookMouseDown?.(evt);
545
+ }, [
546
+ rowDragMouseDown,
547
+ cellBlockHookMouseDown
548
+ ]);
549
+ return {
550
+ ...containerProps,
551
+ allRowsSelected,
552
+ "aria-rowcount": dataSource.size,
553
+ cellBlock,
554
+ columns,
555
+ dataRows,
556
+ draggableRow,
557
+ editSessionInProgress: editSession?.inEditMode,
558
+ focusCellPlaceholderKeyDown,
559
+ focusCellPlaceholderRef,
560
+ getRowOffset,
561
+ handleColumnAction,
562
+ headerState,
563
+ headings,
564
+ highlightedIndex: highlightedIndexRef.current,
565
+ onBlur: editingBlur,
566
+ onCheckBoxColumnHeaderClick,
567
+ onDoubleClick: editingDoubleClick,
568
+ onFocus: handleFocus,
569
+ onKeyDown: handleKeyDown,
570
+ onMouseDown: handleMouseDown,
571
+ onContextMenu,
572
+ onHeaderHeightMeasured,
573
+ onMoveColumn,
574
+ onMoveGroupColumn,
575
+ onRemoveGroupColumn,
576
+ onRowClick: handleRowClick,
577
+ onSortColumn: handleSort,
578
+ onResizeColumn,
579
+ onToggleGroup,
580
+ rowClassNameGenerator,
581
+ scrollProps,
582
+ tableAttributes,
583
+ tableBodyRef,
584
+ tableConfig,
585
+ viewportMeasurements
586
+ };
587
+ };
588
+ export { useTable };