@vuu-ui/vuu-table 0.8.33 → 0.8.34

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 (180) hide show
  1. package/cjs/Row.css +115 -0
  2. package/cjs/Row.js +115 -0
  3. package/cjs/Row.js.map +1 -0
  4. package/cjs/Table.css +151 -0
  5. package/cjs/Table.js +276 -0
  6. package/cjs/Table.js.map +1 -0
  7. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.css +5 -0
  8. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.js +33 -0
  9. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.js.map +1 -0
  10. package/cjs/cell-renderers/input-cell/InputCell.css +31 -0
  11. package/cjs/cell-renderers/input-cell/InputCell.js +49 -0
  12. package/cjs/cell-renderers/input-cell/InputCell.js.map +1 -0
  13. package/cjs/cell-renderers/toggle-cell/ToggleCell.css +32 -0
  14. package/cjs/cell-renderers/toggle-cell/ToggleCell.js +59 -0
  15. package/cjs/cell-renderers/toggle-cell/ToggleCell.js.map +1 -0
  16. package/cjs/column-header-pill/ColumnHeaderPill.css +30 -0
  17. package/cjs/column-header-pill/ColumnHeaderPill.js +44 -0
  18. package/cjs/column-header-pill/ColumnHeaderPill.js.map +1 -0
  19. package/cjs/column-header-pill/GroupColumnPill.css +7 -0
  20. package/cjs/column-header-pill/GroupColumnPill.js +20 -0
  21. package/cjs/column-header-pill/GroupColumnPill.js.map +1 -0
  22. package/cjs/column-header-pill/SortIndicator.css +7 -0
  23. package/cjs/column-header-pill/SortIndicator.js +18 -0
  24. package/cjs/column-header-pill/SortIndicator.js.map +1 -0
  25. package/cjs/column-menu/ColumnMenu.css +21 -0
  26. package/cjs/column-menu/ColumnMenu.js +21 -0
  27. package/cjs/column-menu/ColumnMenu.js.map +1 -0
  28. package/cjs/column-resizing/ColumnResizer.css +28 -0
  29. package/cjs/column-resizing/ColumnResizer.js +63 -0
  30. package/cjs/column-resizing/ColumnResizer.js.map +1 -0
  31. package/cjs/column-resizing/useTableColumnResize.js +55 -0
  32. package/cjs/column-resizing/useTableColumnResize.js.map +1 -0
  33. package/cjs/context-menu/buildContextMenuDescriptors.js +214 -0
  34. package/cjs/context-menu/buildContextMenuDescriptors.js.map +1 -0
  35. package/cjs/context-menu/useHandleTableContextMenu.js +81 -0
  36. package/cjs/context-menu/useHandleTableContextMenu.js.map +1 -0
  37. package/cjs/header-cell/GroupHeaderCell.css +65 -0
  38. package/cjs/header-cell/GroupHeaderCell.js +108 -0
  39. package/cjs/header-cell/GroupHeaderCell.js.map +1 -0
  40. package/cjs/header-cell/HeaderCell.css +146 -0
  41. package/cjs/header-cell/HeaderCell.js +100 -0
  42. package/cjs/header-cell/HeaderCell.js.map +1 -0
  43. package/cjs/index.js.map +1 -0
  44. package/cjs/moving-window.js +61 -0
  45. package/cjs/moving-window.js.map +1 -0
  46. package/cjs/table-cell/TableCell.css +41 -0
  47. package/cjs/table-cell/TableCell.js +63 -0
  48. package/cjs/table-cell/TableCell.js.map +1 -0
  49. package/cjs/table-cell/TableGroupCell.css +26 -0
  50. package/cjs/table-cell/TableGroupCell.js +45 -0
  51. package/cjs/table-cell/TableGroupCell.js.map +1 -0
  52. package/cjs/table-config.js +25 -0
  53. package/cjs/table-config.js.map +1 -0
  54. package/cjs/table-dom-utils.js +60 -0
  55. package/cjs/table-dom-utils.js.map +1 -0
  56. package/cjs/table-header/TableHeader.js +87 -0
  57. package/cjs/table-header/TableHeader.js.map +1 -0
  58. package/cjs/table-header/useTableHeader.js +72 -0
  59. package/cjs/table-header/useTableHeader.js.map +1 -0
  60. package/cjs/useCell.js +28 -0
  61. package/cjs/useCell.js.map +1 -0
  62. package/cjs/useCellEditing.js +79 -0
  63. package/cjs/useCellEditing.js.map +1 -0
  64. package/cjs/useControlledTableNavigation.js +43 -0
  65. package/cjs/useControlledTableNavigation.js.map +1 -0
  66. package/cjs/useDataSource.js +104 -0
  67. package/cjs/useDataSource.js.map +1 -0
  68. package/cjs/useInitialValue.js +11 -0
  69. package/cjs/useInitialValue.js.map +1 -0
  70. package/cjs/useKeyboardNavigation.js +304 -0
  71. package/cjs/useKeyboardNavigation.js.map +1 -0
  72. package/cjs/useRowClassNameGenerators.js +34 -0
  73. package/cjs/useRowClassNameGenerators.js.map +1 -0
  74. package/cjs/useRowHeight.js +43 -0
  75. package/cjs/useRowHeight.js.map +1 -0
  76. package/cjs/useSelection.js +64 -0
  77. package/cjs/useSelection.js.map +1 -0
  78. package/cjs/useTable.js +553 -0
  79. package/cjs/useTable.js.map +1 -0
  80. package/cjs/useTableAndColumnSettings.js +128 -0
  81. package/cjs/useTableAndColumnSettings.js.map +1 -0
  82. package/cjs/useTableContextMenu.js +42 -0
  83. package/cjs/useTableContextMenu.js.map +1 -0
  84. package/cjs/useTableModel.js +297 -0
  85. package/cjs/useTableModel.js.map +1 -0
  86. package/cjs/useTableScroll.js +396 -0
  87. package/cjs/useTableScroll.js.map +1 -0
  88. package/cjs/useTableViewport.js +122 -0
  89. package/cjs/useTableViewport.js.map +1 -0
  90. package/esm/Row.css +115 -0
  91. package/esm/Row.js +112 -0
  92. package/esm/Row.js.map +1 -0
  93. package/esm/Table.css +151 -0
  94. package/esm/Table.js +274 -0
  95. package/esm/Table.js.map +1 -0
  96. package/esm/cell-renderers/checkbox-cell/CheckboxCell.css +5 -0
  97. package/esm/cell-renderers/checkbox-cell/CheckboxCell.js +31 -0
  98. package/esm/cell-renderers/checkbox-cell/CheckboxCell.js.map +1 -0
  99. package/esm/cell-renderers/input-cell/InputCell.css +31 -0
  100. package/esm/cell-renderers/input-cell/InputCell.js +47 -0
  101. package/esm/cell-renderers/input-cell/InputCell.js.map +1 -0
  102. package/esm/cell-renderers/toggle-cell/ToggleCell.css +32 -0
  103. package/esm/cell-renderers/toggle-cell/ToggleCell.js +57 -0
  104. package/esm/cell-renderers/toggle-cell/ToggleCell.js.map +1 -0
  105. package/esm/column-header-pill/ColumnHeaderPill.css +30 -0
  106. package/esm/column-header-pill/ColumnHeaderPill.js +42 -0
  107. package/esm/column-header-pill/ColumnHeaderPill.js.map +1 -0
  108. package/esm/column-header-pill/GroupColumnPill.css +7 -0
  109. package/esm/column-header-pill/GroupColumnPill.js +18 -0
  110. package/esm/column-header-pill/GroupColumnPill.js.map +1 -0
  111. package/esm/column-header-pill/SortIndicator.css +7 -0
  112. package/esm/column-header-pill/SortIndicator.js +16 -0
  113. package/esm/column-header-pill/SortIndicator.js.map +1 -0
  114. package/esm/column-menu/ColumnMenu.css +21 -0
  115. package/esm/column-menu/ColumnMenu.js +19 -0
  116. package/esm/column-menu/ColumnMenu.js.map +1 -0
  117. package/esm/column-resizing/ColumnResizer.css +28 -0
  118. package/esm/column-resizing/ColumnResizer.js +61 -0
  119. package/esm/column-resizing/ColumnResizer.js.map +1 -0
  120. package/esm/column-resizing/useTableColumnResize.js +53 -0
  121. package/esm/column-resizing/useTableColumnResize.js.map +1 -0
  122. package/esm/context-menu/buildContextMenuDescriptors.js +212 -0
  123. package/esm/context-menu/buildContextMenuDescriptors.js.map +1 -0
  124. package/esm/context-menu/useHandleTableContextMenu.js +79 -0
  125. package/esm/context-menu/useHandleTableContextMenu.js.map +1 -0
  126. package/esm/header-cell/GroupHeaderCell.css +65 -0
  127. package/esm/header-cell/GroupHeaderCell.js +106 -0
  128. package/esm/header-cell/GroupHeaderCell.js.map +1 -0
  129. package/esm/header-cell/HeaderCell.css +146 -0
  130. package/esm/header-cell/HeaderCell.js +98 -0
  131. package/esm/header-cell/HeaderCell.js.map +1 -0
  132. package/esm/index.js +14 -0
  133. package/esm/index.js.map +1 -0
  134. package/esm/moving-window.js +59 -0
  135. package/esm/moving-window.js.map +1 -0
  136. package/esm/table-cell/TableCell.css +41 -0
  137. package/esm/table-cell/TableCell.js +61 -0
  138. package/esm/table-cell/TableCell.js.map +1 -0
  139. package/esm/table-cell/TableGroupCell.css +26 -0
  140. package/esm/table-cell/TableGroupCell.js +43 -0
  141. package/esm/table-cell/TableGroupCell.js.map +1 -0
  142. package/esm/table-config.js +23 -0
  143. package/esm/table-config.js.map +1 -0
  144. package/esm/table-dom-utils.js +51 -0
  145. package/esm/table-dom-utils.js.map +1 -0
  146. package/esm/table-header/TableHeader.js +85 -0
  147. package/esm/table-header/TableHeader.js.map +1 -0
  148. package/esm/table-header/useTableHeader.js +70 -0
  149. package/esm/table-header/useTableHeader.js.map +1 -0
  150. package/esm/useCell.js +26 -0
  151. package/esm/useCell.js.map +1 -0
  152. package/esm/useCellEditing.js +77 -0
  153. package/esm/useCellEditing.js.map +1 -0
  154. package/esm/useControlledTableNavigation.js +41 -0
  155. package/esm/useControlledTableNavigation.js.map +1 -0
  156. package/esm/useDataSource.js +101 -0
  157. package/esm/useDataSource.js.map +1 -0
  158. package/esm/useInitialValue.js +9 -0
  159. package/esm/useInitialValue.js.map +1 -0
  160. package/esm/useKeyboardNavigation.js +300 -0
  161. package/esm/useKeyboardNavigation.js.map +1 -0
  162. package/esm/useRowClassNameGenerators.js +32 -0
  163. package/esm/useRowClassNameGenerators.js.map +1 -0
  164. package/esm/useRowHeight.js +41 -0
  165. package/esm/useRowHeight.js.map +1 -0
  166. package/esm/useSelection.js +62 -0
  167. package/esm/useSelection.js.map +1 -0
  168. package/esm/useTable.js +551 -0
  169. package/esm/useTable.js.map +1 -0
  170. package/esm/useTableAndColumnSettings.js +126 -0
  171. package/esm/useTableAndColumnSettings.js.map +1 -0
  172. package/esm/useTableContextMenu.js +40 -0
  173. package/esm/useTableContextMenu.js.map +1 -0
  174. package/esm/useTableModel.js +293 -0
  175. package/esm/useTableModel.js.map +1 -0
  176. package/esm/useTableScroll.js +393 -0
  177. package/esm/useTableScroll.js.map +1 -0
  178. package/esm/useTableViewport.js +120 -0
  179. package/esm/useTableViewport.js.map +1 -0
  180. package/package.json +10 -8
@@ -0,0 +1,304 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var core = require('@salt-ds/core');
5
+ var react = require('react');
6
+ var tableDomUtils = require('./table-dom-utils.js');
7
+
8
+ const rowNavigationKeys = /* @__PURE__ */ new Set([
9
+ "Home",
10
+ "End",
11
+ "PageUp",
12
+ "PageDown",
13
+ "ArrowDown",
14
+ "ArrowUp"
15
+ ]);
16
+ const cellNavigationKeys = new Set(rowNavigationKeys);
17
+ cellNavigationKeys.add("ArrowLeft");
18
+ cellNavigationKeys.add("ArrowRight");
19
+ const isNavigationKey = (key, navigationStyle) => {
20
+ switch (navigationStyle) {
21
+ case "cell":
22
+ return cellNavigationKeys.has(key);
23
+ case "row":
24
+ return rowNavigationKeys.has(key);
25
+ default:
26
+ return false;
27
+ }
28
+ };
29
+ const PageKeys = ["Home", "End", "PageUp", "PageDown"];
30
+ const isPagingKey = (key) => PageKeys.includes(key);
31
+ const NULL_CELL_POS = [-1, -1];
32
+ function nextCellPos(key, [rowIdx, colIdx], columnCount, rowCount) {
33
+ if (key === "ArrowUp") {
34
+ if (rowIdx > -1) {
35
+ return [rowIdx - 1, colIdx];
36
+ } else {
37
+ return [rowIdx, colIdx];
38
+ }
39
+ } else if (key === "ArrowDown") {
40
+ if (rowIdx === -1) {
41
+ return [0, colIdx];
42
+ } else if (rowIdx === rowCount - 1) {
43
+ return [rowIdx, colIdx];
44
+ } else {
45
+ return [rowIdx + 1, colIdx];
46
+ }
47
+ } else if (key === "ArrowRight") {
48
+ if (colIdx < columnCount) {
49
+ return [rowIdx, colIdx + 1];
50
+ } else {
51
+ return [rowIdx, colIdx];
52
+ }
53
+ } else if (key === "ArrowLeft") {
54
+ if (colIdx > 1) {
55
+ return [rowIdx, colIdx - 1];
56
+ } else {
57
+ return [rowIdx, colIdx];
58
+ }
59
+ }
60
+ return [rowIdx, colIdx];
61
+ }
62
+ const useKeyboardNavigation = ({
63
+ columnCount = 0,
64
+ containerRef,
65
+ disableFocus = false,
66
+ defaultHighlightedIndex,
67
+ disableHighlightOnFocus,
68
+ highlightedIndex: highlightedIndexProp,
69
+ navigationStyle,
70
+ requestScroll,
71
+ onHighlight,
72
+ rowCount = 0,
73
+ viewportRowCount
74
+ }) => {
75
+ const focusedCellPos = react.useRef([-1, -1]);
76
+ const focusableCell = react.useRef();
77
+ const activeCellPos = react.useRef([-1, 0]);
78
+ const highlightedIndexRef = react.useRef();
79
+ const [highlightedIndex, setHighlightedIdx] = core.useControlled({
80
+ controlled: highlightedIndexProp,
81
+ default: defaultHighlightedIndex,
82
+ name: "UseKeyboardNavigation"
83
+ });
84
+ highlightedIndexRef.current = highlightedIndex;
85
+ const setHighlightedIndex = react.useCallback(
86
+ (idx, fromKeyboard = false) => {
87
+ onHighlight?.(idx);
88
+ setHighlightedIdx(idx);
89
+ },
90
+ [onHighlight, setHighlightedIdx]
91
+ );
92
+ const getFocusedCell = (element) => element?.closest(
93
+ "[role='columnHeader'],[role='cell']"
94
+ );
95
+ const getTableCellPos = (tableCell) => {
96
+ if (tableCell.role === "columnHeader") {
97
+ const colIdx = parseInt(tableCell.dataset.idx ?? "-1", 10);
98
+ return [-1, colIdx];
99
+ } else {
100
+ const focusedRow = tableCell.closest("[role='row']");
101
+ if (focusedRow) {
102
+ const rowIdx = vuuUtils.getIndexFromRowElement(focusedRow);
103
+ const colIdx = Array.from(focusedRow.childNodes).indexOf(tableCell);
104
+ return [rowIdx, colIdx];
105
+ }
106
+ }
107
+ return NULL_CELL_POS;
108
+ };
109
+ const focusCell = react.useCallback(
110
+ (cellPos) => {
111
+ if (containerRef.current) {
112
+ const activeCell = tableDomUtils.getTableCell(containerRef, cellPos);
113
+ if (activeCell) {
114
+ if (activeCell !== focusableCell.current) {
115
+ focusableCell.current?.removeAttribute("tabindex");
116
+ focusableCell.current = activeCell;
117
+ activeCell.setAttribute("tabindex", "0");
118
+ }
119
+ requestScroll?.({ type: "scroll-row", rowIndex: cellPos[0] });
120
+ activeCell.focus({ preventScroll: true });
121
+ }
122
+ }
123
+ },
124
+ // TODO we recreate this function whenever viewportRange changes, which will
125
+ // be often whilst scrolling - store range in a a ref ?
126
+ [containerRef, requestScroll]
127
+ );
128
+ const setActiveCell = react.useCallback(
129
+ (rowIdx, colIdx, fromKeyboard = false) => {
130
+ const pos = [rowIdx, colIdx];
131
+ activeCellPos.current = pos;
132
+ if (navigationStyle === "row") {
133
+ setHighlightedIdx(rowIdx);
134
+ } else {
135
+ focusCell(pos);
136
+ }
137
+ if (fromKeyboard) {
138
+ focusedCellPos.current = pos;
139
+ }
140
+ },
141
+ [focusCell, navigationStyle, setHighlightedIdx]
142
+ );
143
+ const nextPageItemIdx = react.useCallback(
144
+ (key, [rowIdx, colIdx]) => new Promise((resolve) => {
145
+ let newRowIdx = rowIdx;
146
+ switch (key) {
147
+ case "PageDown": {
148
+ newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);
149
+ if (newRowIdx !== rowIdx) {
150
+ requestScroll?.({ type: "scroll-page", direction: "down" });
151
+ }
152
+ break;
153
+ }
154
+ case "PageUp": {
155
+ newRowIdx = Math.max(0, rowIdx - viewportRowCount);
156
+ if (newRowIdx !== rowIdx) {
157
+ requestScroll?.({ type: "scroll-page", direction: "up" });
158
+ }
159
+ break;
160
+ }
161
+ case "Home": {
162
+ newRowIdx = 0;
163
+ if (newRowIdx !== rowIdx) {
164
+ requestScroll?.({ type: "scroll-end", direction: "home" });
165
+ }
166
+ break;
167
+ }
168
+ case "End": {
169
+ newRowIdx = rowCount - 1;
170
+ if (newRowIdx !== rowIdx) {
171
+ requestScroll?.({ type: "scroll-end", direction: "end" });
172
+ }
173
+ break;
174
+ }
175
+ }
176
+ setTimeout(() => {
177
+ resolve([newRowIdx, colIdx]);
178
+ }, 35);
179
+ }),
180
+ [requestScroll, rowCount, viewportRowCount]
181
+ );
182
+ const handleFocus = react.useCallback(() => {
183
+ if (disableHighlightOnFocus !== true) {
184
+ if (containerRef.current?.contains(document.activeElement)) {
185
+ const focusedCell = getFocusedCell(document.activeElement);
186
+ if (focusedCell) {
187
+ focusedCellPos.current = getTableCellPos(focusedCell);
188
+ if (navigationStyle === "row") {
189
+ setHighlightedIdx(focusedCellPos.current[0]);
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }, [
195
+ disableHighlightOnFocus,
196
+ containerRef,
197
+ navigationStyle,
198
+ setHighlightedIdx
199
+ ]);
200
+ const navigateChildItems = react.useCallback(
201
+ async (key) => {
202
+ const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, activeCellPos.current) : nextCellPos(key, activeCellPos.current, columnCount, rowCount);
203
+ const [rowIdx, colIdx] = activeCellPos.current;
204
+ if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {
205
+ setActiveCell(nextRowIdx, nextColIdx, true);
206
+ }
207
+ },
208
+ [columnCount, nextPageItemIdx, rowCount, setActiveCell]
209
+ );
210
+ const scrollRowIntoViewIfNecessary = react.useCallback(
211
+ (rowIndex) => {
212
+ requestScroll?.({ type: "scroll-row", rowIndex });
213
+ },
214
+ [requestScroll]
215
+ );
216
+ const moveHighlightedRow = react.useCallback(
217
+ async (key) => {
218
+ const { current: highlighted } = highlightedIndexRef;
219
+ const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) : nextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);
220
+ if (nextRowIdx !== highlighted) {
221
+ setHighlightedIndex(nextRowIdx);
222
+ scrollRowIntoViewIfNecessary(nextRowIdx);
223
+ }
224
+ },
225
+ [
226
+ columnCount,
227
+ nextPageItemIdx,
228
+ rowCount,
229
+ scrollRowIntoViewIfNecessary,
230
+ setHighlightedIndex
231
+ ]
232
+ );
233
+ react.useEffect(() => {
234
+ if (highlightedIndexProp !== void 0 && highlightedIndexProp !== -1) {
235
+ scrollRowIntoViewIfNecessary(highlightedIndexProp);
236
+ }
237
+ }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);
238
+ const handleKeyDown = react.useCallback(
239
+ (e) => {
240
+ if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) {
241
+ e.preventDefault();
242
+ e.stopPropagation();
243
+ if (navigationStyle === "row") {
244
+ moveHighlightedRow(e.key);
245
+ } else {
246
+ void navigateChildItems(e.key);
247
+ }
248
+ }
249
+ },
250
+ [rowCount, navigationStyle, moveHighlightedRow, navigateChildItems]
251
+ );
252
+ const handleClick = react.useCallback(
253
+ // Might not be a cell e.g the Settings button
254
+ (evt) => {
255
+ const target = evt.target;
256
+ const focusedCell = getFocusedCell(target);
257
+ if (focusedCell) {
258
+ const [rowIdx, colIdx] = getTableCellPos(focusedCell);
259
+ setActiveCell(rowIdx, colIdx);
260
+ }
261
+ },
262
+ [setActiveCell]
263
+ );
264
+ const handleMouseLeave = react.useCallback(() => {
265
+ setHighlightedIndex(-1);
266
+ }, [setHighlightedIndex]);
267
+ const handleMouseMove = react.useCallback(
268
+ (evt) => {
269
+ const idx = tableDomUtils.closestRowIndex(evt.target);
270
+ if (idx !== -1 && idx !== highlightedIndexRef.current) {
271
+ setHighlightedIndex(idx);
272
+ }
273
+ },
274
+ [setHighlightedIndex]
275
+ );
276
+ const navigate = react.useCallback(() => {
277
+ navigateChildItems("ArrowDown");
278
+ }, [navigateChildItems]);
279
+ const fullyRendered = containerRef.current?.firstChild != null;
280
+ react.useEffect(() => {
281
+ if (fullyRendered && focusableCell.current === void 0 && !disableFocus) {
282
+ const { current: container } = containerRef;
283
+ const cell = container?.querySelector(tableDomUtils.headerCellQuery(0)) || container?.querySelector(tableDomUtils.dataCellQuery(0, 0));
284
+ if (cell) {
285
+ cell.setAttribute("tabindex", "0");
286
+ focusableCell.current = cell;
287
+ }
288
+ }
289
+ }, [containerRef, disableFocus, fullyRendered]);
290
+ return {
291
+ highlightedIndexRef,
292
+ navigate,
293
+ onClick: handleClick,
294
+ onFocus: handleFocus,
295
+ onKeyDown: handleKeyDown,
296
+ onMouseLeave: navigationStyle === "row" ? handleMouseLeave : void 0,
297
+ onMouseMove: navigationStyle === "row" ? handleMouseMove : void 0
298
+ };
299
+ };
300
+
301
+ exports.isNavigationKey = isNavigationKey;
302
+ exports.isPagingKey = isPagingKey;
303
+ exports.useKeyboardNavigation = useKeyboardNavigation;
304
+ //# sourceMappingURL=useKeyboardNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useKeyboardNavigation.js","sources":["../src/useKeyboardNavigation.ts"],"sourcesContent":["import { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { getIndexFromRowElement } from \"@vuu-ui/vuu-utils\";\nimport { useControlled } from \"@salt-ds/core\";\nimport {\n KeyboardEvent,\n MouseEvent,\n RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { TableNavigationStyle } from \"./Table\";\nimport {\n CellPos,\n closestRowIndex,\n dataCellQuery,\n getTableCell,\n headerCellQuery,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\n\nconst rowNavigationKeys = new Set<NavigationKey>([\n \"Home\",\n \"End\",\n \"PageUp\",\n \"PageDown\",\n \"ArrowDown\",\n \"ArrowUp\",\n]);\n\nconst cellNavigationKeys = new Set(rowNavigationKeys);\ncellNavigationKeys.add(\"ArrowLeft\");\ncellNavigationKeys.add(\"ArrowRight\");\n\nexport const isNavigationKey = (\n key: string,\n navigationStyle: TableNavigationStyle\n): key is NavigationKey => {\n switch (navigationStyle) {\n case \"cell\":\n return cellNavigationKeys.has(key as NavigationKey);\n case \"row\":\n return rowNavigationKeys.has(key as NavigationKey);\n default:\n return false;\n }\n};\n\ntype ArrowKey = \"ArrowUp\" | \"ArrowDown\" | \"ArrowLeft\" | \"ArrowRight\";\ntype PageKey = \"Home\" | \"End\" | \"PageUp\" | \"PageDown\";\ntype NavigationKey = PageKey | ArrowKey;\n\nconst PageKeys = [\"Home\", \"End\", \"PageUp\", \"PageDown\"];\nexport const isPagingKey = (key: string): key is PageKey =>\n PageKeys.includes(key);\n\nconst NULL_CELL_POS: CellPos = [-1, -1];\n\nfunction nextCellPos(\n key: ArrowKey,\n [rowIdx, colIdx]: CellPos,\n columnCount: number,\n rowCount: number\n): CellPos {\n if (key === \"ArrowUp\") {\n if (rowIdx > -1) {\n return [rowIdx - 1, colIdx];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowDown\") {\n if (rowIdx === -1) {\n return [0, colIdx];\n } else if (rowIdx === rowCount - 1) {\n return [rowIdx, colIdx];\n } else {\n return [rowIdx + 1, colIdx];\n }\n } else if (key === \"ArrowRight\") {\n // The colIdx is 1 based, because of the selection decorator\n if (colIdx < columnCount) {\n return [rowIdx, colIdx + 1];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowLeft\") {\n if (colIdx > 1) {\n return [rowIdx, colIdx - 1];\n } else {\n return [rowIdx, colIdx];\n }\n }\n return [rowIdx, colIdx];\n}\n\nexport interface NavigationHookProps {\n containerRef: RefObject<HTMLElement>;\n columnCount?: number;\n defaultHighlightedIndex?: number;\n disableFocus?: boolean;\n disableHighlightOnFocus?: boolean;\n highlightedIndex?: number;\n label?: string;\n navigationStyle: TableNavigationStyle;\n viewportRange: VuuRange;\n onHighlight?: (idx: number) => void;\n requestScroll?: ScrollRequestHandler;\n restoreLastFocus?: boolean;\n rowCount?: number;\n selected?: unknown;\n viewportRowCount: number;\n}\n\nexport const useKeyboardNavigation = ({\n columnCount = 0,\n containerRef,\n disableFocus = false,\n defaultHighlightedIndex,\n disableHighlightOnFocus,\n highlightedIndex: highlightedIndexProp,\n navigationStyle,\n requestScroll,\n onHighlight,\n rowCount = 0,\n viewportRowCount,\n}: // viewportRange,\nNavigationHookProps) => {\n // const { from: viewportFirstRow, to: viewportLastRow } = viewportRange;\n const focusedCellPos = useRef<CellPos>([-1, -1]);\n const focusableCell = useRef<HTMLElement>();\n const activeCellPos = useRef<CellPos>([-1, 0]);\n // Keep this in sync with state value. This can be used by functions that need\n // to reference highlightedIndex at call time but do not need to be regenerated\n // every time it changes (i.e keep highlightedIndex out of their dependency\n // arrays, as it can update frequently)\n const highlightedIndexRef = useRef<number | undefined>();\n\n const [highlightedIndex, setHighlightedIdx] = useControlled({\n controlled: highlightedIndexProp,\n default: defaultHighlightedIndex,\n name: \"UseKeyboardNavigation\",\n });\n highlightedIndexRef.current = highlightedIndex;\n const setHighlightedIndex = useCallback(\n (idx: number, fromKeyboard = false) => {\n onHighlight?.(idx);\n setHighlightedIdx(idx);\n if (fromKeyboard) {\n // lastFocus.current = idx;\n }\n },\n [onHighlight, setHighlightedIdx]\n );\n\n const getFocusedCell = (element: HTMLElement | Element | null) =>\n element?.closest(\n \"[role='columnHeader'],[role='cell']\"\n ) as HTMLDivElement | null;\n\n const getTableCellPos = (tableCell: HTMLDivElement): CellPos => {\n if (tableCell.role === \"columnHeader\") {\n const colIdx = parseInt(tableCell.dataset.idx ?? \"-1\", 10);\n return [-1, colIdx];\n } else {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n if (focusedRow) {\n const rowIdx = getIndexFromRowElement(focusedRow);\n // TODO will get trickier when we introduce horizontal virtualisation\n const colIdx = Array.from(focusedRow.childNodes).indexOf(tableCell);\n return [rowIdx, colIdx];\n }\n }\n return NULL_CELL_POS;\n };\n\n const focusCell = useCallback(\n (cellPos: CellPos) => {\n if (containerRef.current) {\n const activeCell = getTableCell(containerRef, cellPos);\n if (activeCell) {\n if (activeCell !== focusableCell.current) {\n focusableCell.current?.removeAttribute(\"tabindex\");\n focusableCell.current = activeCell;\n activeCell.setAttribute(\"tabindex\", \"0\");\n }\n // TODO needs to be scroll cell\n requestScroll?.({ type: \"scroll-row\", rowIndex: cellPos[0] });\n activeCell.focus({ preventScroll: true });\n }\n }\n },\n // TODO we recreate this function whenever viewportRange changes, which will\n // be often whilst scrolling - store range in a a ref ?\n [containerRef, requestScroll]\n );\n\n const setActiveCell = useCallback(\n (rowIdx: number, colIdx: number, fromKeyboard = false) => {\n const pos: CellPos = [rowIdx, colIdx];\n activeCellPos.current = pos;\n if (navigationStyle === \"row\") {\n setHighlightedIdx(rowIdx);\n } else {\n focusCell(pos);\n }\n if (fromKeyboard) {\n focusedCellPos.current = pos;\n }\n },\n [focusCell, navigationStyle, setHighlightedIdx]\n );\n\n const nextPageItemIdx = useCallback(\n (\n key: \"PageDown\" | \"PageUp\" | \"Home\" | \"End\",\n [rowIdx, colIdx]: CellPos\n ): Promise<CellPos> =>\n new Promise((resolve) => {\n let newRowIdx = rowIdx;\n switch (key) {\n case \"PageDown\": {\n newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-page\", direction: \"down\" });\n }\n break;\n }\n case \"PageUp\": {\n newRowIdx = Math.max(0, rowIdx - viewportRowCount);\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-page\", direction: \"up\" });\n }\n break;\n }\n case \"Home\": {\n newRowIdx = 0;\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-end\", direction: \"home\" });\n }\n break;\n }\n case \"End\": {\n newRowIdx = rowCount - 1;\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-end\", direction: \"end\" });\n }\n break;\n }\n }\n // Introduce a delay to allow the scroll operation to complete,\n // which will trigger a range reset and rerender of rows. We\n // might need to tweak how this works. If we introduce too big\n // a delay, we risk seeing the newly rendered rows, with the focus\n // still on the old cell, which will be apparent as a brief flash\n // of the old cell focus before switching to correct cell. If we were\n // to change the way re assign keys such that we can guarantee that\n // when we page down, rows in same position get same keys, then same\n // cell would be focussed in new page as previous and issue would not\n // arise.\n setTimeout(() => {\n resolve([newRowIdx, colIdx]);\n }, 35);\n }),\n [requestScroll, rowCount, viewportRowCount]\n );\n\n const handleFocus = useCallback(() => {\n if (disableHighlightOnFocus !== true) {\n if (containerRef.current?.contains(document.activeElement)) {\n // IF focus arrives via keyboard, a cell will have received focus,\n // we handle that here. If focus arrives via click on a cell with\n // no tabindex (i.e all cells except one) we leave that to the\n // click handler.\n const focusedCell = getFocusedCell(document.activeElement);\n if (focusedCell) {\n focusedCellPos.current = getTableCellPos(focusedCell);\n if (navigationStyle === \"row\") {\n setHighlightedIdx(focusedCellPos.current[0]);\n }\n }\n }\n }\n }, [\n disableHighlightOnFocus,\n containerRef,\n navigationStyle,\n setHighlightedIdx,\n ]);\n\n const navigateChildItems = useCallback(\n async (key: NavigationKey) => {\n const [nextRowIdx, nextColIdx] = isPagingKey(key)\n ? await nextPageItemIdx(key, activeCellPos.current)\n : nextCellPos(key, activeCellPos.current, columnCount, rowCount);\n const [rowIdx, colIdx] = activeCellPos.current;\n if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {\n setActiveCell(nextRowIdx, nextColIdx, true);\n }\n },\n [columnCount, nextPageItemIdx, rowCount, setActiveCell]\n );\n\n const scrollRowIntoViewIfNecessary = useCallback(\n (rowIndex: number) => {\n requestScroll?.({ type: \"scroll-row\", rowIndex });\n },\n [requestScroll]\n );\n\n const moveHighlightedRow = useCallback(\n async (key: NavigationKey) => {\n const { current: highlighted } = highlightedIndexRef;\n const [nextRowIdx] = isPagingKey(key)\n ? await nextPageItemIdx(key, [highlighted ?? -1, 0])\n : nextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);\n if (nextRowIdx !== highlighted) {\n setHighlightedIndex(nextRowIdx);\n // TO(DO make this a scroll request)\n scrollRowIntoViewIfNecessary(nextRowIdx);\n }\n },\n [\n columnCount,\n nextPageItemIdx,\n rowCount,\n scrollRowIntoViewIfNecessary,\n setHighlightedIndex,\n ]\n );\n\n useEffect(() => {\n if (highlightedIndexProp !== undefined && highlightedIndexProp !== -1) {\n scrollRowIntoViewIfNecessary(highlightedIndexProp);\n }\n }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) {\n e.preventDefault();\n e.stopPropagation();\n if (navigationStyle === \"row\") {\n moveHighlightedRow(e.key);\n } else {\n void navigateChildItems(e.key);\n }\n }\n },\n [rowCount, navigationStyle, moveHighlightedRow, navigateChildItems]\n );\n\n const handleClick = useCallback(\n // Might not be a cell e.g the Settings button\n (evt: MouseEvent) => {\n const target = evt.target as HTMLElement;\n const focusedCell = getFocusedCell(target);\n if (focusedCell) {\n const [rowIdx, colIdx] = getTableCellPos(focusedCell);\n setActiveCell(rowIdx, colIdx);\n }\n },\n [setActiveCell]\n );\n\n const handleMouseLeave = useCallback(() => {\n setHighlightedIndex(-1);\n }, [setHighlightedIndex]);\n\n const handleMouseMove = useCallback(\n (evt: MouseEvent) => {\n const idx = closestRowIndex(evt.target as HTMLElement);\n if (idx !== -1 && idx !== highlightedIndexRef.current) {\n setHighlightedIndex(idx);\n }\n },\n [setHighlightedIndex]\n );\n\n const navigate = useCallback(() => {\n navigateChildItems(\"ArrowDown\");\n }, [navigateChildItems]);\n\n // First render will only render the outer container when explicit\n // sizing has not been provided. Outer container is measured and\n // only then, on second render, is content rendered.\n const fullyRendered = containerRef.current?.firstChild != null;\n useEffect(() => {\n if (fullyRendered && focusableCell.current === undefined && !disableFocus) {\n const { current: container } = containerRef;\n const cell = (container?.querySelector(headerCellQuery(0)) ||\n container?.querySelector(dataCellQuery(0, 0))) as HTMLElement;\n if (cell) {\n cell.setAttribute(\"tabindex\", \"0\");\n focusableCell.current = cell;\n }\n }\n }, [containerRef, disableFocus, fullyRendered]);\n\n return {\n highlightedIndexRef,\n navigate,\n onClick: handleClick,\n onFocus: handleFocus,\n onKeyDown: handleKeyDown,\n onMouseLeave: navigationStyle === \"row\" ? handleMouseLeave : undefined,\n onMouseMove: navigationStyle === \"row\" ? handleMouseMove : undefined,\n };\n};\n"],"names":["useRef","useControlled","useCallback","getIndexFromRowElement","getTableCell","useEffect","closestRowIndex","headerCellQuery","dataCellQuery"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var react = require('react');
5
+
6
+ const createClassNameGenerator = (ids) => {
7
+ const functions = [];
8
+ ids?.forEach((id) => {
9
+ const fn = vuuUtils.getRowClassNameGenerator(id);
10
+ if (fn) {
11
+ functions.push(fn.fn);
12
+ }
13
+ });
14
+ return (row, columnMap) => {
15
+ const classNames = [];
16
+ functions?.forEach((fn) => {
17
+ const className = fn(row, columnMap);
18
+ if (className) {
19
+ classNames.push(className);
20
+ }
21
+ });
22
+ return classNames.join(" ");
23
+ };
24
+ };
25
+ const useRowClassNameGenerators = ({
26
+ rowClassNameGenerators
27
+ }) => {
28
+ return react.useMemo(() => {
29
+ return createClassNameGenerator(rowClassNameGenerators);
30
+ }, [rowClassNameGenerators]);
31
+ };
32
+
33
+ exports.useRowClassNameGenerators = useRowClassNameGenerators;
34
+ //# sourceMappingURL=useRowClassNameGenerators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRowClassNameGenerators.js","sources":["../src/useRowClassNameGenerators.ts"],"sourcesContent":["import { TableConfig } from \"@vuu-ui/vuu-table-types\";\nimport {\n getRowClassNameGenerator,\n RowClassNameGenerator,\n} from \"@vuu-ui/vuu-utils\";\nimport { useMemo } from \"react\";\n\nconst createClassNameGenerator = (\n ids?: string[]\n): RowClassNameGenerator | undefined => {\n const functions: RowClassNameGenerator[] = [];\n ids?.forEach((id) => {\n const fn = getRowClassNameGenerator(id);\n if (fn) {\n functions.push(fn.fn);\n }\n });\n return (row, columnMap) => {\n const classNames: string[] = [];\n functions?.forEach((fn) => {\n const className = fn(row, columnMap);\n if (className) {\n classNames.push(className);\n }\n });\n return classNames.join(\" \");\n };\n};\n\nexport const useRowClassNameGenerators = ({\n rowClassNameGenerators,\n}: TableConfig) => {\n return useMemo<RowClassNameGenerator | undefined>(() => {\n return createClassNameGenerator(rowClassNameGenerators);\n }, [rowClassNameGenerators]);\n};\n"],"names":["getRowClassNameGenerator","useMemo"],"mappings":";;;;;AAOA,MAAM,wBAAA,GAA2B,CAC/B,GACsC,KAAA;AACtC,EAAA,MAAM,YAAqC,EAAC,CAAA;AAC5C,EAAK,GAAA,EAAA,OAAA,CAAQ,CAAC,EAAO,KAAA;AACnB,IAAM,MAAA,EAAA,GAAKA,kCAAyB,EAAE,CAAA,CAAA;AACtC,IAAA,IAAI,EAAI,EAAA;AACN,MAAU,SAAA,CAAA,IAAA,CAAK,GAAG,EAAE,CAAA,CAAA;AAAA,KACtB;AAAA,GACD,CAAA,CAAA;AACD,EAAO,OAAA,CAAC,KAAK,SAAc,KAAA;AACzB,IAAA,MAAM,aAAuB,EAAC,CAAA;AAC9B,IAAW,SAAA,EAAA,OAAA,CAAQ,CAAC,EAAO,KAAA;AACzB,MAAM,MAAA,SAAA,GAAY,EAAG,CAAA,GAAA,EAAK,SAAS,CAAA,CAAA;AACnC,MAAA,IAAI,SAAW,EAAA;AACb,QAAA,UAAA,CAAW,KAAK,SAAS,CAAA,CAAA;AAAA,OAC3B;AAAA,KACD,CAAA,CAAA;AACD,IAAO,OAAA,UAAA,CAAW,KAAK,GAAG,CAAA,CAAA;AAAA,GAC5B,CAAA;AACF,CAAA,CAAA;AAEO,MAAM,4BAA4B,CAAC;AAAA,EACxC,sBAAA;AACF,CAAmB,KAAA;AACjB,EAAA,OAAOC,cAA2C,MAAM;AACtD,IAAA,OAAO,yBAAyB,sBAAsB,CAAA,CAAA;AAAA,GACxD,EAAG,CAAC,sBAAsB,CAAC,CAAA,CAAA;AAC7B;;;;"}
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var react = require('react');
5
+
6
+ const useRowHeight = ({
7
+ rowHeight: rowHeightProp = 0
8
+ }) => {
9
+ const [rowHeight, setRowHeight] = react.useState(rowHeightProp);
10
+ const heightRef = react.useRef(rowHeight);
11
+ const resizeObserver = react.useMemo(() => {
12
+ return new ResizeObserver((entries) => {
13
+ for (const entry of entries) {
14
+ const [{ blockSize: measuredSize }] = entry.borderBoxSize;
15
+ const newHeight = Math.round(measuredSize);
16
+ if (vuuUtils.isValidNumber(newHeight) && heightRef.current !== newHeight) {
17
+ heightRef.current = newHeight;
18
+ setRowHeight(newHeight);
19
+ }
20
+ }
21
+ });
22
+ }, []);
23
+ const rowRef = react.useCallback(
24
+ (el) => {
25
+ if (el) {
26
+ if (rowHeightProp === 0) {
27
+ const { height } = el.getBoundingClientRect();
28
+ console.log({ boundingClientHeight: height });
29
+ console.log(`measured rowHeight = ${height} (${rowHeightProp})`);
30
+ resizeObserver.observe(el);
31
+ setRowHeight(height);
32
+ }
33
+ } else {
34
+ resizeObserver.disconnect();
35
+ }
36
+ },
37
+ [resizeObserver, rowHeightProp]
38
+ );
39
+ return { rowHeight, rowRef };
40
+ };
41
+
42
+ exports.useRowHeight = useRowHeight;
43
+ //# sourceMappingURL=useRowHeight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRowHeight.js","sources":["../src/useRowHeight.ts"],"sourcesContent":["import { isValidNumber } from \"@vuu-ui/vuu-utils\";\nimport { RefCallback, useCallback, useMemo, useRef, useState } from \"react\";\n\ninterface RowHeightHookProps {\n rowHeight?: number;\n}\n\nexport const useRowHeight = ({\n rowHeight: rowHeightProp = 0,\n}: RowHeightHookProps) => {\n const [rowHeight, setRowHeight] = useState(rowHeightProp);\n const heightRef = useRef(rowHeight);\n\n const resizeObserver = useMemo(() => {\n return new ResizeObserver((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const [{ blockSize: measuredSize }] = entry.borderBoxSize;\n const newHeight = Math.round(measuredSize);\n if (isValidNumber(newHeight) && heightRef.current !== newHeight) {\n heightRef.current = newHeight;\n setRowHeight(newHeight);\n }\n }\n });\n }, []);\n\n const rowRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n if (el) {\n if (rowHeightProp === 0) {\n const { height } = el.getBoundingClientRect();\n console.log({ boundingClientHeight: height });\n console.log(`measured rowHeight = ${height} (${rowHeightProp})`);\n resizeObserver.observe(el);\n setRowHeight(height);\n }\n } else {\n resizeObserver.disconnect();\n }\n },\n [resizeObserver, rowHeightProp]\n );\n\n return { rowHeight, rowRef };\n};\n"],"names":["useState","useRef","useMemo","isValidNumber","useCallback"],"mappings":";;;;;AAOO,MAAM,eAAe,CAAC;AAAA,EAC3B,WAAW,aAAgB,GAAA,CAAA;AAC7B,CAA0B,KAAA;AACxB,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,aAAa,CAAA,CAAA;AACxD,EAAM,MAAA,SAAA,GAAYC,aAAO,SAAS,CAAA,CAAA;AAElC,EAAM,MAAA,cAAA,GAAiBC,cAAQ,MAAM;AACnC,IAAO,OAAA,IAAI,cAAe,CAAA,CAAC,OAAmC,KAAA;AAC5D,MAAA,KAAA,MAAW,SAAS,OAAS,EAAA;AAC3B,QAAA,MAAM,CAAC,EAAE,SAAA,EAAW,YAAa,EAAC,IAAI,KAAM,CAAA,aAAA,CAAA;AAC5C,QAAM,MAAA,SAAA,GAAY,IAAK,CAAA,KAAA,CAAM,YAAY,CAAA,CAAA;AACzC,QAAA,IAAIC,sBAAc,CAAA,SAAS,CAAK,IAAA,SAAA,CAAU,YAAY,SAAW,EAAA;AAC/D,UAAA,SAAA,CAAU,OAAU,GAAA,SAAA,CAAA;AACpB,UAAA,YAAA,CAAa,SAAS,CAAA,CAAA;AAAA,SACxB;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAAA,GACH,EAAG,EAAE,CAAA,CAAA;AAEL,EAAA,MAAM,MAAS,GAAAC,iBAAA;AAAA,IACb,CAAC,EAAO,KAAA;AACN,MAAA,IAAI,EAAI,EAAA;AACN,QAAA,IAAI,kBAAkB,CAAG,EAAA;AACvB,UAAA,MAAM,EAAE,MAAA,EAAW,GAAA,EAAA,CAAG,qBAAsB,EAAA,CAAA;AAC5C,UAAA,OAAA,CAAQ,GAAI,CAAA,EAAE,oBAAsB,EAAA,MAAA,EAAQ,CAAA,CAAA;AAC5C,UAAA,OAAA,CAAQ,GAAI,CAAA,CAAA,qBAAA,EAAwB,MAAM,CAAA,EAAA,EAAK,aAAa,CAAG,CAAA,CAAA,CAAA,CAAA;AAC/D,UAAA,cAAA,CAAe,QAAQ,EAAE,CAAA,CAAA;AACzB,UAAA,YAAA,CAAa,MAAM,CAAA,CAAA;AAAA,SACrB;AAAA,OACK,MAAA;AACL,QAAA,cAAA,CAAe,UAAW,EAAA,CAAA;AAAA,OAC5B;AAAA,KACF;AAAA,IACA,CAAC,gBAAgB,aAAa,CAAA;AAAA,GAChC,CAAA;AAEA,EAAO,OAAA,EAAE,WAAW,MAAO,EAAA,CAAA;AAC7B;;;;"}
@@ -0,0 +1,64 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var react = require('react');
5
+
6
+ const { IDX } = vuuUtils.metadataKeys;
7
+ const NO_SELECTION = [];
8
+ const defaultSelectionKeys = ["Enter", " "];
9
+ const useSelection = ({
10
+ highlightedIndexRef,
11
+ selectionKeys = defaultSelectionKeys,
12
+ selectionModel,
13
+ onSelect,
14
+ onSelectionChange
15
+ }) => {
16
+ const lastActiveRef = react.useRef(-1);
17
+ const selectedRef = react.useRef(NO_SELECTION);
18
+ const isSelectionEvent = react.useCallback(
19
+ (evt) => selectionKeys.includes(evt.key),
20
+ [selectionKeys]
21
+ );
22
+ const handleRowClick = react.useCallback(
23
+ (evt, row, rangeSelect, keepExistingSelection) => {
24
+ const { [IDX]: idx } = row;
25
+ const { current: active } = lastActiveRef;
26
+ const { current: selected } = selectedRef;
27
+ const selectOperation = vuuUtils.isRowSelected(row) ? vuuUtils.deselectItem : vuuUtils.selectItem;
28
+ const newSelected = selectOperation(
29
+ selectionModel,
30
+ selected,
31
+ idx,
32
+ rangeSelect,
33
+ keepExistingSelection,
34
+ active
35
+ );
36
+ selectedRef.current = newSelected;
37
+ lastActiveRef.current = idx;
38
+ onSelect?.(selectOperation === vuuUtils.selectItem ? row : null);
39
+ onSelectionChange?.(newSelected);
40
+ },
41
+ [onSelect, onSelectionChange, selectionModel]
42
+ );
43
+ const handleKeyDown = react.useCallback(
44
+ (e) => {
45
+ if (isSelectionEvent(e)) {
46
+ const { current: rowIndex } = highlightedIndexRef;
47
+ if (rowIndex !== void 0 && rowIndex !== -1) {
48
+ const rowEl = vuuUtils.getRowElementAtIndex(e.target, rowIndex);
49
+ if (rowEl) {
50
+ vuuUtils.dispatchMouseEvent(rowEl, "click");
51
+ }
52
+ }
53
+ }
54
+ },
55
+ [highlightedIndexRef, isSelectionEvent]
56
+ );
57
+ return {
58
+ onKeyDown: handleKeyDown,
59
+ onRowClick: handleRowClick
60
+ };
61
+ };
62
+
63
+ exports.useSelection = useSelection;
64
+ //# sourceMappingURL=useSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSelection.js","sources":["../src/useSelection.ts"],"sourcesContent":["import {\n TableRowClickHandlerInternal,\n TableRowSelectHandlerInternal,\n TableSelectionModel,\n} from \"@vuu-ui/vuu-table-types\";\nimport {\n deselectItem,\n dispatchMouseEvent,\n getRowElementAtIndex,\n isRowSelected,\n metadataKeys,\n selectItem,\n} from \"@vuu-ui/vuu-utils\";\nimport { Selection, SelectionChangeHandler } from \"@vuu-ui/vuu-data-types\";\nimport {\n KeyboardEvent,\n KeyboardEventHandler,\n MutableRefObject,\n useCallback,\n useRef,\n} from \"react\";\n\nconst { IDX } = metadataKeys;\n\nconst NO_SELECTION: Selection = [];\n\nconst defaultSelectionKeys = [\"Enter\", \" \"];\n\nexport interface SelectionHookProps {\n highlightedIndexRef: MutableRefObject<number | undefined>;\n selectionKeys?: string[];\n selectionModel: TableSelectionModel;\n onSelect?: TableRowSelectHandlerInternal;\n onSelectionChange: SelectionChangeHandler;\n}\n\nexport const useSelection = ({\n highlightedIndexRef,\n selectionKeys = defaultSelectionKeys,\n selectionModel,\n onSelect,\n onSelectionChange,\n}: SelectionHookProps) => {\n selectionModel === \"extended\" || selectionModel === \"checkbox\";\n const lastActiveRef = useRef(-1);\n const selectedRef = useRef<Selection>(NO_SELECTION);\n\n const isSelectionEvent = useCallback(\n (evt: KeyboardEvent<HTMLElement>) => selectionKeys.includes(evt.key),\n [selectionKeys]\n );\n\n const handleRowClick = useCallback<TableRowClickHandlerInternal>(\n (evt, row, rangeSelect, keepExistingSelection) => {\n const { [IDX]: idx } = row;\n const { current: active } = lastActiveRef;\n const { current: selected } = selectedRef;\n\n const selectOperation = isRowSelected(row) ? deselectItem : selectItem;\n\n const newSelected = selectOperation(\n selectionModel,\n selected,\n idx,\n rangeSelect,\n keepExistingSelection,\n active\n );\n\n selectedRef.current = newSelected;\n lastActiveRef.current = idx;\n\n onSelect?.(selectOperation === selectItem ? row : null);\n onSelectionChange?.(newSelected);\n },\n [onSelect, onSelectionChange, selectionModel]\n );\n\n const handleKeyDown = useCallback<KeyboardEventHandler<HTMLElement>>(\n (e) => {\n if (isSelectionEvent(e)) {\n const { current: rowIndex } = highlightedIndexRef;\n if (rowIndex !== undefined && rowIndex !== -1) {\n const rowEl = getRowElementAtIndex(e.target, rowIndex);\n // const rowEl = (e.target as HTMLElement).querySelector(\n // `[aria-rowindex=\"${rowIndex + 1}\"]`\n // ) as HTMLElement;\n if (rowEl) {\n dispatchMouseEvent(rowEl, \"click\");\n }\n }\n }\n },\n [highlightedIndexRef, isSelectionEvent]\n );\n\n return {\n onKeyDown: handleKeyDown,\n onRowClick: handleRowClick,\n };\n};\n"],"names":["metadataKeys","useRef","useCallback","isRowSelected","deselectItem","selectItem","getRowElementAtIndex","dispatchMouseEvent"],"mappings":";;;;;AAsBA,MAAM,EAAE,KAAQ,GAAAA,qBAAA,CAAA;AAEhB,MAAM,eAA0B,EAAC,CAAA;AAEjC,MAAM,oBAAA,GAAuB,CAAC,OAAA,EAAS,GAAG,CAAA,CAAA;AAUnC,MAAM,eAAe,CAAC;AAAA,EAC3B,mBAAA;AAAA,EACA,aAAgB,GAAA,oBAAA;AAAA,EAChB,cAAA;AAAA,EACA,QAAA;AAAA,EACA,iBAAA;AACF,CAA0B,KAAA;AAExB,EAAM,MAAA,aAAA,GAAgBC,aAAO,CAAE,CAAA,CAAA,CAAA;AAC/B,EAAM,MAAA,WAAA,GAAcA,aAAkB,YAAY,CAAA,CAAA;AAElD,EAAA,MAAM,gBAAmB,GAAAC,iBAAA;AAAA,IACvB,CAAC,GAAA,KAAoC,aAAc,CAAA,QAAA,CAAS,IAAI,GAAG,CAAA;AAAA,IACnE,CAAC,aAAa,CAAA;AAAA,GAChB,CAAA;AAEA,EAAA,MAAM,cAAiB,GAAAA,iBAAA;AAAA,IACrB,CAAC,GAAA,EAAK,GAAK,EAAA,WAAA,EAAa,qBAA0B,KAAA;AAChD,MAAA,MAAM,EAAE,CAAC,GAAG,GAAG,KAAQ,GAAA,GAAA,CAAA;AACvB,MAAM,MAAA,EAAE,OAAS,EAAA,MAAA,EAAW,GAAA,aAAA,CAAA;AAC5B,MAAM,MAAA,EAAE,OAAS,EAAA,QAAA,EAAa,GAAA,WAAA,CAAA;AAE9B,MAAA,MAAM,eAAkB,GAAAC,sBAAA,CAAc,GAAG,CAAA,GAAIC,qBAAe,GAAAC,mBAAA,CAAA;AAE5D,MAAA,MAAM,WAAc,GAAA,eAAA;AAAA,QAClB,cAAA;AAAA,QACA,QAAA;AAAA,QACA,GAAA;AAAA,QACA,WAAA;AAAA,QACA,qBAAA;AAAA,QACA,MAAA;AAAA,OACF,CAAA;AAEA,MAAA,WAAA,CAAY,OAAU,GAAA,WAAA,CAAA;AACtB,MAAA,aAAA,CAAc,OAAU,GAAA,GAAA,CAAA;AAExB,MAAW,QAAA,GAAA,eAAA,KAAoBA,mBAAa,GAAA,GAAA,GAAM,IAAI,CAAA,CAAA;AACtD,MAAA,iBAAA,GAAoB,WAAW,CAAA,CAAA;AAAA,KACjC;AAAA,IACA,CAAC,QAAU,EAAA,iBAAA,EAAmB,cAAc,CAAA;AAAA,GAC9C,CAAA;AAEA,EAAA,MAAM,aAAgB,GAAAH,iBAAA;AAAA,IACpB,CAAC,CAAM,KAAA;AACL,MAAI,IAAA,gBAAA,CAAiB,CAAC,CAAG,EAAA;AACvB,QAAM,MAAA,EAAE,OAAS,EAAA,QAAA,EAAa,GAAA,mBAAA,CAAA;AAC9B,QAAI,IAAA,QAAA,KAAa,KAAa,CAAA,IAAA,QAAA,KAAa,CAAI,CAAA,EAAA;AAC7C,UAAA,MAAM,KAAQ,GAAAI,6BAAA,CAAqB,CAAE,CAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AAIrD,UAAA,IAAI,KAAO,EAAA;AACT,YAAAC,2BAAA,CAAmB,OAAO,OAAO,CAAA,CAAA;AAAA,WACnC;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,qBAAqB,gBAAgB,CAAA;AAAA,GACxC,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,SAAW,EAAA,aAAA;AAAA,IACX,UAAY,EAAA,cAAA;AAAA,GACd,CAAA;AACF;;;;"}