@vuu-ui/vuu-table 0.8.99 → 0.9.1

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 (111) hide show
  1. package/cjs/Row.css.js +1 -1
  2. package/cjs/Row.js +20 -7
  3. package/cjs/Row.js.map +1 -1
  4. package/cjs/Table.css.js +1 -1
  5. package/cjs/Table.js +31 -19
  6. package/cjs/Table.js.map +1 -1
  7. package/cjs/cell-block/CellBlock.css.js +1 -1
  8. package/cjs/cell-block/CellBlock.js +4 -0
  9. package/cjs/cell-block/CellBlock.js.map +1 -1
  10. package/cjs/cell-block/cellblock-utils.js +7 -22
  11. package/cjs/cell-block/cellblock-utils.js.map +1 -1
  12. package/cjs/cell-block/useCellBlockSelection.js +37 -15
  13. package/cjs/cell-block/useCellBlockSelection.js.map +1 -1
  14. package/cjs/column-header-pill/ColumnHeaderPill.js +2 -1
  15. package/cjs/column-header-pill/ColumnHeaderPill.js.map +1 -1
  16. package/cjs/column-menu/ColumnMenu.css.js +1 -1
  17. package/cjs/context-menu/buildContextMenuDescriptors.js +2 -2
  18. package/cjs/context-menu/buildContextMenuDescriptors.js.map +1 -1
  19. package/cjs/context-menu/useHandleTableContextMenu.js +2 -2
  20. package/cjs/context-menu/useHandleTableContextMenu.js.map +1 -1
  21. package/cjs/header-cell/GroupHeaderCell.css.js +1 -1
  22. package/cjs/header-cell/GroupHeaderCell.js +10 -1
  23. package/cjs/header-cell/GroupHeaderCell.js.map +1 -1
  24. package/cjs/header-cell/HeaderCell.css.js +1 -1
  25. package/cjs/table-cell/TableCell.css.js +1 -1
  26. package/cjs/table-cell/TableGroupCell.css.js +1 -1
  27. package/cjs/table-cell/TableGroupCell.js +16 -7
  28. package/cjs/table-cell/TableGroupCell.js.map +1 -1
  29. package/cjs/table-dom-utils.js +100 -28
  30. package/cjs/table-dom-utils.js.map +1 -1
  31. package/cjs/table-header/TableHeader.js +105 -66
  32. package/cjs/table-header/TableHeader.js.map +1 -1
  33. package/cjs/table-header/useTableHeader.js +9 -1
  34. package/cjs/table-header/useTableHeader.js.map +1 -1
  35. package/cjs/useCell.js +1 -2
  36. package/cjs/useCell.js.map +1 -1
  37. package/cjs/useCellFocus.js +3 -3
  38. package/cjs/useCellFocus.js.map +1 -1
  39. package/cjs/useKeyboardNavigation.js +93 -48
  40. package/cjs/useKeyboardNavigation.js.map +1 -1
  41. package/cjs/useSelection.js +2 -1
  42. package/cjs/useSelection.js.map +1 -1
  43. package/cjs/useTable.js +42 -21
  44. package/cjs/useTable.js.map +1 -1
  45. package/cjs/useTableContextMenu.js +5 -4
  46. package/cjs/useTableContextMenu.js.map +1 -1
  47. package/cjs/useTableModel.js +24 -9
  48. package/cjs/useTableModel.js.map +1 -1
  49. package/cjs/useTableScroll.js +2 -2
  50. package/cjs/useTableScroll.js.map +1 -1
  51. package/esm/Row.css.js +1 -1
  52. package/esm/Row.js +21 -8
  53. package/esm/Row.js.map +1 -1
  54. package/esm/Table.css.js +1 -1
  55. package/esm/Table.js +31 -19
  56. package/esm/Table.js.map +1 -1
  57. package/esm/cell-block/CellBlock.css.js +1 -1
  58. package/esm/cell-block/CellBlock.js +4 -0
  59. package/esm/cell-block/CellBlock.js.map +1 -1
  60. package/esm/cell-block/cellblock-utils.js +8 -23
  61. package/esm/cell-block/cellblock-utils.js.map +1 -1
  62. package/esm/cell-block/useCellBlockSelection.js +38 -16
  63. package/esm/cell-block/useCellBlockSelection.js.map +1 -1
  64. package/esm/column-header-pill/ColumnHeaderPill.js +2 -1
  65. package/esm/column-header-pill/ColumnHeaderPill.js.map +1 -1
  66. package/esm/column-menu/ColumnMenu.css.js +1 -1
  67. package/esm/context-menu/buildContextMenuDescriptors.js +2 -2
  68. package/esm/context-menu/buildContextMenuDescriptors.js.map +1 -1
  69. package/esm/context-menu/useHandleTableContextMenu.js +2 -2
  70. package/esm/context-menu/useHandleTableContextMenu.js.map +1 -1
  71. package/esm/header-cell/GroupHeaderCell.css.js +1 -1
  72. package/esm/header-cell/GroupHeaderCell.js +10 -1
  73. package/esm/header-cell/GroupHeaderCell.js.map +1 -1
  74. package/esm/header-cell/HeaderCell.css.js +1 -1
  75. package/esm/table-cell/TableCell.css.js +1 -1
  76. package/esm/table-cell/TableGroupCell.css.js +1 -1
  77. package/esm/table-cell/TableGroupCell.js +18 -9
  78. package/esm/table-cell/TableGroupCell.js.map +1 -1
  79. package/esm/table-dom-utils.js +94 -26
  80. package/esm/table-dom-utils.js.map +1 -1
  81. package/esm/table-header/TableHeader.js +106 -67
  82. package/esm/table-header/TableHeader.js.map +1 -1
  83. package/esm/table-header/useTableHeader.js +9 -1
  84. package/esm/table-header/useTableHeader.js.map +1 -1
  85. package/esm/useCell.js +1 -2
  86. package/esm/useCell.js.map +1 -1
  87. package/esm/useCellFocus.js +3 -3
  88. package/esm/useCellFocus.js.map +1 -1
  89. package/esm/useKeyboardNavigation.js +92 -47
  90. package/esm/useKeyboardNavigation.js.map +1 -1
  91. package/esm/useSelection.js +3 -2
  92. package/esm/useSelection.js.map +1 -1
  93. package/esm/useTable.js +43 -22
  94. package/esm/useTable.js.map +1 -1
  95. package/esm/useTableContextMenu.js +6 -5
  96. package/esm/useTableContextMenu.js.map +1 -1
  97. package/esm/useTableModel.js +24 -9
  98. package/esm/useTableModel.js.map +1 -1
  99. package/esm/useTableScroll.js +4 -4
  100. package/esm/useTableScroll.js.map +1 -1
  101. package/package.json +9 -9
  102. package/types/Row.d.ts +1 -1
  103. package/types/Table.d.ts +14 -3
  104. package/types/cell-block/useCellBlockSelection.d.ts +1 -3
  105. package/types/table-dom-utils.d.ts +10 -4
  106. package/types/table-header/TableHeader.d.ts +1 -1
  107. package/types/table-header/useTableHeader.d.ts +5 -3
  108. package/types/useKeyboardNavigation.d.ts +5 -2
  109. package/types/useTable.d.ts +9 -4
  110. package/types/useTableContextMenu.d.ts +2 -1
  111. package/types/useTableModel.d.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"useCellFocus.js","sources":["../src/useCellFocus.ts"],"sourcesContent":["import {\n KeyboardEventHandler,\n MutableRefObject,\n RefCallback,\n RefObject,\n useCallback,\n} from \"react\";\nimport {\n dataCellQuery,\n getTableCell,\n headerCellQuery,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\nimport { isArrowKey, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { CellFocusState, CellPos } from \"@vuu-ui/vuu-table-types\";\n\nexport interface CellFocusHookProps {\n cellFocusStateRef: MutableRefObject<CellFocusState>;\n containerRef: RefObject<HTMLElement>;\n disableFocus?: boolean;\n requestScroll?: ScrollRequestHandler;\n}\n\nconst getCellPosition = (el: HTMLElement) => {\n const top = parseInt(el.parentElement?.style.top ?? \"-1\");\n return { top };\n};\n\nexport type FocusCell = (cellPos: CellPos, fromKeyboard?: boolean) => void;\n\nexport const useCellFocus = ({\n cellFocusStateRef,\n containerRef,\n disableFocus = false,\n requestScroll,\n}: CellFocusHookProps) => {\n const focusCellPlaceholderRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => (cellFocusStateRef.current.placeholderEl = el),\n [cellFocusStateRef],\n );\n\n const focusCell = useCallback<FocusCell>(\n (cellPos, fromKeyboard = false) => {\n if (containerRef.current) {\n const { current: state } = cellFocusStateRef;\n\n if (fromKeyboard && state.outsideViewport) {\n state.cellPos = cellPos;\n } else {\n const activeCell = getTableCell(containerRef, cellPos);\n if (activeCell) {\n if (activeCell !== state.el) {\n state.el?.removeAttribute(\"tabindex\");\n activeCell.setAttribute(\"tabindex\", \"0\");\n\n // TODO no need to measure if we're navigating horizontally\n state.cellPos = cellPos;\n state.el = activeCell;\n state.pos = getCellPosition(activeCell);\n state.outsideViewport = false;\n\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `${state.pos.top}px`;\n }\n }\n // TODO needs to be scroll cell to accommodate horizontal virtualization\n requestScroll?.({ type: \"scroll-row\", rowIndex: cellPos[0] });\n activeCell.focus({ preventScroll: true });\n }\n }\n }\n },\n [cellFocusStateRef, containerRef, requestScroll],\n );\n\n const tableBodyRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n if (el) {\n const { current: state } = cellFocusStateRef;\n const table = queryClosest<HTMLDivElement>(el, \".vuuTable\");\n if (table) {\n if (state.el === null && !disableFocus) {\n const headerCell = table.querySelector<HTMLDivElement>(\n headerCellQuery(0),\n );\n if (headerCell) {\n headerCell.setAttribute(\"tabindex\", \"0\");\n state.cellPos = [-1, 0];\n state.el = headerCell;\n state.pos = { top: -20 };\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `-20px`;\n }\n } else {\n const cell = table.querySelector<HTMLDivElement>(\n dataCellQuery(0, 0),\n );\n if (cell) {\n cell.setAttribute(\"tabindex\", \"0\");\n state.cellPos = [0, 0];\n state.el = cell;\n state.pos = { top: 0 };\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `0px`;\n }\n }\n }\n }\n }\n }\n },\n [cellFocusStateRef, disableFocus],\n );\n\n const focusCellPlaceholderKeyDown = useCallback<KeyboardEventHandler>(\n (evt) => {\n const { outsideViewport, pos } = cellFocusStateRef.current;\n if (pos && isArrowKey(evt.key)) {\n // TODO depends on whether we're scrolling up or down\n if (outsideViewport === \"above\") {\n requestScroll?.({ type: \"scroll-top\", scrollPos: pos.top });\n } else if (outsideViewport === \"below\") {\n requestScroll?.({ type: \"scroll-bottom\", scrollPos: pos.top });\n } else {\n throw Error(\n `cellFocusPlaceholder should not have focus if inside viewport`,\n );\n }\n }\n },\n [cellFocusStateRef, requestScroll],\n );\n\n return {\n focusCell,\n focusCellPlaceholderKeyDown,\n focusCellPlaceholderRef,\n tableBodyRef,\n };\n};\n"],"names":["useCallback","getTableCell","queryClosest","headerCellQuery","dataCellQuery","isArrowKey"],"mappings":"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"}
1
+ {"version":3,"file":"useCellFocus.js","sources":["../src/useCellFocus.ts"],"sourcesContent":["import {\n KeyboardEventHandler,\n MutableRefObject,\n RefCallback,\n RefObject,\n useCallback,\n} from \"react\";\nimport {\n dataCellQuery,\n getTableCell,\n headerCellQuery,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\nimport { isArrowKey, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { CellFocusState, CellPos } from \"@vuu-ui/vuu-table-types\";\n\nexport interface CellFocusHookProps {\n cellFocusStateRef: MutableRefObject<CellFocusState>;\n containerRef: RefObject<HTMLElement>;\n disableFocus?: boolean;\n requestScroll?: ScrollRequestHandler;\n}\n\nconst getCellPosition = (el: HTMLElement) => {\n const top = parseInt(el.parentElement?.style.top ?? \"-1\");\n return { top };\n};\n\nexport type FocusCell = (cellPos: CellPos, fromKeyboard?: boolean) => void;\n\nexport const useCellFocus = ({\n cellFocusStateRef,\n containerRef,\n disableFocus = false,\n requestScroll,\n}: CellFocusHookProps) => {\n const focusCellPlaceholderRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => (cellFocusStateRef.current.placeholderEl = el),\n [cellFocusStateRef],\n );\n\n const focusCell = useCallback<FocusCell>(\n (cellPos, fromKeyboard = false) => {\n if (containerRef.current) {\n const { current: state } = cellFocusStateRef;\n\n if (fromKeyboard && state.outsideViewport) {\n state.cellPos = cellPos;\n } else {\n const activeCell = getTableCell(containerRef, cellPos);\n if (activeCell) {\n if (activeCell !== state.el) {\n state.el?.removeAttribute(\"tabindex\");\n activeCell.setAttribute(\"tabindex\", \"0\");\n\n // TODO no need to measure if we're navigating horizontally\n state.cellPos = cellPos;\n state.el = activeCell;\n state.pos = getCellPosition(activeCell);\n state.outsideViewport = false;\n\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `${state.pos.top}px`;\n }\n }\n // TODO needs to be scroll cell to accommodate horizontal virtualization\n requestScroll?.({ type: \"scroll-row\", rowIndex: cellPos[0] });\n activeCell.focus({ preventScroll: true });\n }\n }\n }\n },\n [cellFocusStateRef, containerRef, requestScroll],\n );\n\n const tableBodyRef = useCallback<RefCallback<HTMLDivElement>>(\n (el) => {\n if (el) {\n const { current: state } = cellFocusStateRef;\n const table = queryClosest<HTMLDivElement>(el, \".vuuTable\");\n if (table) {\n if (state.el === null && !disableFocus) {\n const headerCell = table.querySelector<HTMLDivElement>(\n headerCellQuery(1),\n );\n if (headerCell) {\n headerCell.setAttribute(\"tabindex\", \"0\");\n state.cellPos = [1, 1];\n state.el = headerCell;\n state.pos = { top: -20 };\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `-20px`;\n }\n } else {\n const cell = table.querySelector<HTMLDivElement>(\n dataCellQuery(0, 0),\n );\n if (cell) {\n cell.setAttribute(\"tabindex\", \"0\");\n state.cellPos = [1, 1];\n state.el = cell;\n state.pos = { top: 0 };\n if (state.placeholderEl) {\n state.placeholderEl.style.top = `0px`;\n }\n }\n }\n }\n }\n }\n },\n [cellFocusStateRef, disableFocus],\n );\n\n const focusCellPlaceholderKeyDown = useCallback<KeyboardEventHandler>(\n (evt) => {\n const { outsideViewport, pos } = cellFocusStateRef.current;\n if (pos && isArrowKey(evt.key)) {\n // TODO depends on whether we're scrolling up or down\n if (outsideViewport === \"above\") {\n requestScroll?.({ type: \"scroll-top\", scrollPos: pos.top });\n } else if (outsideViewport === \"below\") {\n requestScroll?.({ type: \"scroll-bottom\", scrollPos: pos.top });\n } else {\n throw Error(\n `cellFocusPlaceholder should not have focus if inside viewport`,\n );\n }\n }\n },\n [cellFocusStateRef, requestScroll],\n );\n\n return {\n focusCell,\n focusCellPlaceholderKeyDown,\n focusCellPlaceholderRef,\n tableBodyRef,\n };\n};\n"],"names":["useCallback","getTableCell","queryClosest","headerCellQuery","dataCellQuery","isArrowKey"],"mappings":"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"}
@@ -13,12 +13,15 @@ const rowNavigationKeys = /* @__PURE__ */ new Set([
13
13
  "ArrowDown",
14
14
  "ArrowUp"
15
15
  ]);
16
+ const CellLocator = ".vuuTableCell,.vuuTableHeaderCell,.vuuTableGroupHeaderCell";
17
+ const CellControlLocator = ".vuuColumnMenu,.vuuColumnHeaderPill";
16
18
  const cellNavigationKeys = new Set(rowNavigationKeys);
17
19
  cellNavigationKeys.add("ArrowLeft");
18
20
  cellNavigationKeys.add("ArrowRight");
19
21
  const isNavigationKey = (key, navigationStyle) => {
20
22
  switch (navigationStyle) {
21
23
  case "cell":
24
+ case "tree":
22
25
  return cellNavigationKeys.has(key);
23
26
  case "row":
24
27
  return rowNavigationKeys.has(key);
@@ -26,14 +29,38 @@ const isNavigationKey = (key, navigationStyle) => {
26
29
  return false;
27
30
  }
28
31
  };
29
- const focusColumnMenuIfAppropriate = (e, [rowIdx], el) => {
30
- if (e.shiftKey && e.key.match(/Arrow(Left|Right)/) && rowIdx === -1) {
32
+ const focusControlWithinCell = (e, el) => {
33
+ if (e.shiftKey && e.key.match(/Arrow(Left|Right)/)) {
31
34
  if (el?.classList.contains("vuuTableHeaderCell")) {
32
35
  const menuButton = el?.querySelector(".vuuColumnMenu");
33
36
  if (menuButton) {
34
37
  menuButton.focus();
35
38
  return true;
36
39
  }
40
+ } else if (el?.classList.contains("vuuTableGroupHeaderCell")) {
41
+ const headerPill = el?.querySelector(
42
+ ".vuuColumnHeaderPill"
43
+ );
44
+ if (headerPill) {
45
+ headerPill.focus();
46
+ return true;
47
+ }
48
+ } else if (el?.classList.contains("vuuColumnHeaderPill")) {
49
+ const nextPill = el.parentElement?.nextElementSibling?.firstChild;
50
+ if (nextPill?.classList.contains("vuuColumnHeaderPill")) {
51
+ nextPill.focus();
52
+ return true;
53
+ } else {
54
+ const removeButton = vuuUtils.queryClosest(
55
+ el,
56
+ ".vuuTableGroupHeaderCell",
57
+ true
58
+ ).querySelector(".vuuTableGroupHeaderCell-removeAll");
59
+ if (removeButton) {
60
+ removeButton.focus();
61
+ return true;
62
+ }
63
+ }
37
64
  }
38
65
  }
39
66
  return false;
@@ -47,10 +74,12 @@ const useKeyboardNavigation = ({
47
74
  defaultHighlightedIndex,
48
75
  disableHighlightOnFocus,
49
76
  focusCell,
77
+ headerCount,
50
78
  highlightedIndex: highlightedIndexProp,
51
79
  navigationStyle,
52
80
  requestScroll,
53
81
  onHighlight,
82
+ onToggleGroup,
54
83
  rowCount = 0,
55
84
  viewportRowCount
56
85
  }) => {
@@ -61,22 +90,15 @@ const useKeyboardNavigation = ({
61
90
  name: "UseKeyboardNavigation"
62
91
  });
63
92
  highlightedIndexRef.current = highlightedIndex;
93
+ const maxRowIndex = rowCount + headerCount;
64
94
  const setHighlightedIndex = react.useCallback(
65
95
  (idx) => {
66
96
  onHighlight?.(idx);
67
97
  setHighlightedIdx(idx);
98
+ highlightedIndexRef.current = idx;
68
99
  },
69
100
  [onHighlight, setHighlightedIdx]
70
101
  );
71
- const getFocusedCell = (el) => {
72
- if (el?.role == "cell" || el?.role === "columnheader") {
73
- return el;
74
- } else {
75
- return el?.closest(
76
- "[role='columnHeader'],[role='cell']"
77
- );
78
- }
79
- };
80
102
  const setActiveCell = react.useCallback(
81
103
  (rowIdx, colIdx, fromKeyboard = false) => {
82
104
  const pos = [rowIdx, colIdx];
@@ -110,15 +132,15 @@ const useKeyboardNavigation = ({
110
132
  break;
111
133
  }
112
134
  case "Home": {
113
- newRowIdx = 0;
135
+ newRowIdx = headerCount + 1;
114
136
  if (newRowIdx !== rowIdx) {
115
- focusState.cellPos = [0, colIdx];
137
+ focusState.cellPos = [newRowIdx, colIdx];
116
138
  requestScroll?.({ type: "scroll-end", direction: "home" });
117
139
  }
118
140
  break;
119
141
  }
120
142
  case "End": {
121
- newRowIdx = rowCount - 1;
143
+ newRowIdx = rowCount + headerCount;
122
144
  if (newRowIdx !== rowIdx) {
123
145
  focusState.cellPos = [newRowIdx, colIdx];
124
146
  requestScroll?.({ type: "scroll-end", direction: "end" });
@@ -130,14 +152,14 @@ const useKeyboardNavigation = ({
130
152
  resolve([newRowIdx, colIdx]);
131
153
  }, 35);
132
154
  }),
133
- [cellFocusStateRef, requestScroll, rowCount, viewportRowCount]
155
+ [cellFocusStateRef, headerCount, requestScroll, rowCount, viewportRowCount]
134
156
  );
135
157
  const handleFocus = react.useCallback(() => {
136
158
  if (disableHighlightOnFocus !== true) {
137
159
  if (containerRef.current?.contains(document.activeElement)) {
138
- const focusedCell = getFocusedCell(document.activeElement);
160
+ const focusedCell = tableDomUtils.getFocusedCell(document.activeElement);
139
161
  if (focusedCell) {
140
- cellFocusStateRef.current.cellPos = tableDomUtils.getTableCellPos(focusedCell);
162
+ cellFocusStateRef.current.cellPos = tableDomUtils.getAriaCellPos(focusedCell);
141
163
  if (navigationStyle === "row") {
142
164
  setHighlightedIdx(cellFocusStateRef.current.cellPos[0]);
143
165
  }
@@ -152,17 +174,49 @@ const useKeyboardNavigation = ({
152
174
  setHighlightedIdx
153
175
  ]);
154
176
  const navigateChildItems = react.useCallback(
155
- async (key) => {
156
- const {
157
- current: { cellPos }
158
- } = cellFocusStateRef;
159
- const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, cellPos) : tableDomUtils.getNextCellPos(key, cellPos, columnCount, rowCount);
177
+ async (navigationStyle2 = "cell", key, shiftKey = false) => {
178
+ const { cellPos } = cellFocusStateRef.current;
160
179
  const [rowIdx, colIdx] = cellPos;
180
+ let nextRowIdx = -1, nextColIdx = -1;
181
+ if (isPagingKey(key)) {
182
+ [nextRowIdx, nextColIdx] = await nextPageItemIdx(key, cellPos);
183
+ } else {
184
+ const treeNodeOperation = tableDomUtils.getTreeNodeOperation(
185
+ containerRef,
186
+ navigationStyle2,
187
+ cellPos,
188
+ key,
189
+ shiftKey
190
+ );
191
+ if (treeNodeOperation === "expand" || treeNodeOperation === "collapse") {
192
+ onToggleGroup(treeNodeOperation, rowIdx - headerCount - 1);
193
+ } else if (treeNodeOperation === "level-up") {
194
+ [nextRowIdx, nextColIdx] = tableDomUtils.getLevelUp(containerRef, cellPos);
195
+ } else {
196
+ [nextRowIdx, nextColIdx] = tableDomUtils.getNextCellPos(
197
+ key,
198
+ cellPos,
199
+ columnCount,
200
+ maxRowIndex
201
+ );
202
+ }
203
+ }
161
204
  if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {
162
205
  setActiveCell(nextRowIdx, nextColIdx, true);
206
+ setHighlightedIndex(nextRowIdx);
163
207
  }
164
208
  },
165
- [cellFocusStateRef, columnCount, nextPageItemIdx, rowCount, setActiveCell]
209
+ [
210
+ cellFocusStateRef,
211
+ nextPageItemIdx,
212
+ containerRef,
213
+ onToggleGroup,
214
+ headerCount,
215
+ columnCount,
216
+ maxRowIndex,
217
+ setActiveCell,
218
+ setHighlightedIndex
219
+ ]
166
220
  );
167
221
  const scrollRowIntoViewIfNecessary = react.useCallback(
168
222
  (rowIndex) => {
@@ -173,7 +227,7 @@ const useKeyboardNavigation = ({
173
227
  const moveHighlightedRow = react.useCallback(
174
228
  async (key) => {
175
229
  const { current: highlighted } = highlightedIndexRef;
176
- const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) : tableDomUtils.getNextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);
230
+ const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) : tableDomUtils.getNextCellPos(key, [highlighted ?? -1, 0], columnCount, maxRowIndex);
177
231
  if (nextRowIdx !== highlighted) {
178
232
  setHighlightedIndex(nextRowIdx);
179
233
  scrollRowIntoViewIfNecessary(nextRowIdx);
@@ -181,8 +235,8 @@ const useKeyboardNavigation = ({
181
235
  },
182
236
  [
183
237
  columnCount,
238
+ maxRowIndex,
184
239
  nextPageItemIdx,
185
- rowCount,
186
240
  scrollRowIntoViewIfNecessary,
187
241
  setHighlightedIndex
188
242
  ]
@@ -198,7 +252,7 @@ const useKeyboardNavigation = ({
198
252
  (e) => {
199
253
  const cell = vuuUtils.queryClosest(
200
254
  e.target,
201
- ".vuuTableCell,.vuuColumnMenu,.vuuTableHeaderCell"
255
+ `${CellLocator},${CellControlLocator}`
202
256
  );
203
257
  if (tableDomUtils.cellDropdownShowing(cell)) {
204
258
  return;
@@ -208,31 +262,22 @@ const useKeyboardNavigation = ({
208
262
  e.stopPropagation();
209
263
  if (navigationStyle === "row") {
210
264
  moveHighlightedRow(e.key);
211
- } else {
212
- const {
213
- current: { cellPos }
214
- } = cellFocusStateRef;
215
- if (!focusColumnMenuIfAppropriate(e, cellPos, cell)) {
216
- navigateChildItems(e.key);
265
+ } else if (navigationStyle !== "none") {
266
+ if (!focusControlWithinCell(e, cell)) {
267
+ navigateChildItems(navigationStyle, e.key, e.shiftKey);
217
268
  }
218
269
  }
219
270
  }
220
271
  },
221
- [
222
- rowCount,
223
- navigationStyle,
224
- moveHighlightedRow,
225
- cellFocusStateRef,
226
- navigateChildItems
227
- ]
272
+ [rowCount, navigationStyle, moveHighlightedRow, navigateChildItems]
228
273
  );
229
274
  const handleClick = react.useCallback(
230
275
  // Might not be a cell e.g the Settings button
231
276
  (evt) => {
232
- const target = evt.target;
233
- const focusedCell = getFocusedCell(target);
277
+ const target = vuuUtils.queryClosest(evt.target, CellLocator);
278
+ const focusedCell = tableDomUtils.getFocusedCell(target);
234
279
  if (focusedCell) {
235
- const [rowIdx, colIdx] = tableDomUtils.getTableCellPos(focusedCell);
280
+ const [rowIdx, colIdx] = tableDomUtils.getAriaCellPos(focusedCell);
236
281
  setActiveCell(rowIdx, colIdx);
237
282
  }
238
283
  },
@@ -243,19 +288,19 @@ const useKeyboardNavigation = ({
243
288
  }, [setHighlightedIndex]);
244
289
  const handleMouseMove = react.useCallback(
245
290
  (evt) => {
246
- const idx = tableDomUtils.closestRowIndex(evt.target);
247
- if (idx !== -1 && idx !== highlightedIndexRef.current) {
248
- setHighlightedIndex(idx);
291
+ const rowIdx = tableDomUtils.closestRowIndex(evt.target);
292
+ if (rowIdx !== -1 && rowIdx !== highlightedIndexRef.current) {
293
+ setHighlightedIndex(rowIdx);
249
294
  }
250
295
  },
251
296
  [setHighlightedIndex]
252
297
  );
253
- const navigate = react.useCallback(() => {
254
- navigateChildItems("ArrowDown");
298
+ const navigateCell = react.useCallback(() => {
299
+ navigateChildItems("cell", "ArrowDown");
255
300
  }, [navigateChildItems]);
256
301
  return {
257
302
  highlightedIndexRef,
258
- navigate,
303
+ navigateCell,
259
304
  onClick: handleClick,
260
305
  onFocus: handleFocus,
261
306
  onKeyDown: handleKeyDown,
@@ -1 +1 @@
1
- {"version":3,"file":"useKeyboardNavigation.js","sources":["../src/useKeyboardNavigation.ts"],"sourcesContent":["import { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { PageKey, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { useControlled } from \"@salt-ds/core\";\nimport {\n KeyboardEvent,\n MouseEvent,\n MutableRefObject,\n RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { TableNavigationStyle } from \"./Table\";\nimport {\n NavigationKey,\n cellDropdownShowing,\n closestRowIndex,\n getTableCellPos,\n getNextCellPos,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\nimport { FocusCell } from \"./useCellFocus\";\nimport { CellFocusState, CellPos } from \"@vuu-ui/vuu-table-types\";\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\nconst focusColumnMenuIfAppropriate = (\n e: KeyboardEvent,\n [rowIdx]: CellPos,\n el: HTMLElement | null,\n) => {\n if (e.shiftKey && e.key.match(/Arrow(Left|Right)/) && rowIdx === -1) {\n if (el?.classList.contains(\"vuuTableHeaderCell\")) {\n const menuButton = el?.querySelector<HTMLButtonElement>(\".vuuColumnMenu\");\n if (menuButton) {\n menuButton.focus();\n return true;\n }\n }\n }\n return false;\n};\n\nconst PageKeys = [\"Home\", \"End\", \"PageUp\", \"PageDown\"];\nexport const isPagingKey = (key: string): key is PageKey =>\n PageKeys.includes(key);\n\nexport interface NavigationHookProps {\n cellFocusStateRef: MutableRefObject<CellFocusState>;\n containerRef: RefObject<HTMLElement>;\n columnCount?: number;\n defaultHighlightedIndex?: number;\n disableFocus?: boolean;\n disableHighlightOnFocus?: boolean;\n focusCell: FocusCell;\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 cellFocusStateRef,\n columnCount = 0,\n containerRef,\n defaultHighlightedIndex,\n disableHighlightOnFocus,\n focusCell,\n highlightedIndex: highlightedIndexProp,\n navigationStyle,\n requestScroll,\n onHighlight,\n rowCount = 0,\n viewportRowCount,\n}: NavigationHookProps) => {\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) => {\n onHighlight?.(idx);\n setHighlightedIdx(idx);\n },\n [onHighlight, setHighlightedIdx],\n );\n\n const getFocusedCell = (el: HTMLElement | Element | null) => {\n if (el?.role == \"cell\" || el?.role === \"columnheader\") {\n return el as HTMLDivElement;\n } else {\n return el?.closest(\n \"[role='columnHeader'],[role='cell']\",\n ) as HTMLDivElement | null;\n }\n };\n\n const setActiveCell = useCallback(\n (rowIdx: number, colIdx: number, fromKeyboard = false) => {\n const pos: CellPos = [rowIdx, colIdx];\n if (navigationStyle === \"row\") {\n setHighlightedIdx(rowIdx);\n } else {\n focusCell(pos, fromKeyboard);\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 const { current: focusState } = cellFocusStateRef;\n switch (key) {\n case \"PageDown\": {\n newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [newRowIdx, colIdx];\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 focusState.cellPos = [newRowIdx, colIdx];\n requestScroll?.({ type: \"scroll-page\", direction: \"up\" });\n }\n break;\n }\n case \"Home\": {\n newRowIdx = 0;\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [0, colIdx];\n requestScroll?.({ type: \"scroll-end\", direction: \"home\" });\n }\n break;\n }\n case \"End\": {\n newRowIdx = rowCount - 1;\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [newRowIdx, colIdx];\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 [cellFocusStateRef, 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 cellFocusStateRef.current.cellPos = getTableCellPos(focusedCell);\n if (navigationStyle === \"row\") {\n setHighlightedIdx(cellFocusStateRef.current.cellPos[0]);\n }\n }\n }\n }\n }, [\n disableHighlightOnFocus,\n containerRef,\n cellFocusStateRef,\n navigationStyle,\n setHighlightedIdx,\n ]);\n\n const navigateChildItems = useCallback(\n async (key: NavigationKey) => {\n const {\n current: { cellPos },\n } = cellFocusStateRef;\n const [nextRowIdx, nextColIdx] = isPagingKey(key)\n ? await nextPageItemIdx(key, cellPos)\n : getNextCellPos(key, cellPos, columnCount, rowCount);\n const [rowIdx, colIdx] = cellPos;\n if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {\n setActiveCell(nextRowIdx, nextColIdx, true);\n }\n },\n [cellFocusStateRef, 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 : getNextCellPos(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 requestAnimationFrame(() => {\n // deferred call, ensuring table has fully rendered\n scrollRowIntoViewIfNecessary(highlightedIndexProp);\n });\n }\n }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const cell = queryClosest<HTMLDivElement>(\n e.target,\n \".vuuTableCell,.vuuColumnMenu,.vuuTableHeaderCell\",\n );\n if (cellDropdownShowing(cell)) {\n return;\n }\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 const {\n current: { cellPos },\n } = cellFocusStateRef;\n if (!focusColumnMenuIfAppropriate(e, cellPos, cell)) {\n navigateChildItems(e.key);\n }\n }\n }\n },\n [\n rowCount,\n navigationStyle,\n moveHighlightedRow,\n cellFocusStateRef,\n navigateChildItems,\n ],\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 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","getTableCellPos","getNextCellPos","useEffect","queryClosest","cellDropdownShowing","closestRowIndex"],"mappings":"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"}
1
+ {"version":3,"file":"useKeyboardNavigation.js","sources":["../src/useKeyboardNavigation.ts"],"sourcesContent":["import { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { PageKey, queryClosest } from \"@vuu-ui/vuu-utils\";\nimport { useControlled } from \"@salt-ds/core\";\nimport {\n KeyboardEvent,\n MouseEvent,\n MutableRefObject,\n RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { TableNavigationStyle } from \"./Table\";\nimport {\n NavigationKey,\n cellDropdownShowing,\n closestRowIndex,\n getAriaCellPos,\n getFocusedCell,\n getNextCellPos,\n getTreeNodeOperation,\n getLevelUp as getLevelUp,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\nimport { FocusCell } from \"./useCellFocus\";\nimport { CellFocusState, CellPos } from \"@vuu-ui/vuu-table-types\";\n\nconst rowNavigationKeys = new Set<NavigationKey>([\n \"Home\",\n \"End\",\n \"PageUp\",\n \"PageDown\",\n \"ArrowDown\",\n \"ArrowUp\",\n]);\n\nconst CellLocator =\n \".vuuTableCell,.vuuTableHeaderCell,.vuuTableGroupHeaderCell\";\n\nconst CellControlLocator = \".vuuColumnMenu,.vuuColumnHeaderPill\";\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 case \"tree\":\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\nconst focusControlWithinCell = (e: KeyboardEvent, el: HTMLElement | null) => {\n if (e.shiftKey && e.key.match(/Arrow(Left|Right)/)) {\n if (el?.classList.contains(\"vuuTableHeaderCell\")) {\n const menuButton = el?.querySelector<HTMLButtonElement>(\".vuuColumnMenu\");\n if (menuButton) {\n menuButton.focus();\n return true;\n }\n } else if (el?.classList.contains(\"vuuTableGroupHeaderCell\")) {\n const headerPill = el?.querySelector<HTMLButtonElement>(\n \".vuuColumnHeaderPill\",\n );\n if (headerPill) {\n headerPill.focus();\n return true;\n }\n } else if (el?.classList.contains(\"vuuColumnHeaderPill\")) {\n const nextPill = el.parentElement?.nextElementSibling\n ?.firstChild as HTMLElement;\n if (nextPill?.classList.contains(\"vuuColumnHeaderPill\")) {\n nextPill.focus();\n return true;\n } else {\n const removeButton = queryClosest(\n el,\n \".vuuTableGroupHeaderCell\",\n true,\n ).querySelector(\".vuuTableGroupHeaderCell-removeAll\") as HTMLElement;\n if (removeButton) {\n removeButton.focus();\n return true;\n }\n }\n }\n }\n return false;\n};\n\nconst PageKeys = [\"Home\", \"End\", \"PageUp\", \"PageDown\"];\nexport const isPagingKey = (key: string): key is PageKey =>\n PageKeys.includes(key);\n\nexport type GroupToggleHandler = (\n treeNodeOperation: \"expand\" | \"collapse\",\n rowIndex: number,\n) => void;\n\nexport interface NavigationHookProps {\n cellFocusStateRef: MutableRefObject<CellFocusState>;\n containerRef: RefObject<HTMLElement>;\n columnCount?: number;\n headerCount: number;\n defaultHighlightedIndex?: number;\n disableFocus?: boolean;\n disableHighlightOnFocus?: boolean;\n focusCell: FocusCell;\n highlightedIndex?: number;\n label?: string;\n navigationStyle: TableNavigationStyle;\n viewportRange: VuuRange;\n onHighlight?: (idx: number) => void;\n onToggleGroup: GroupToggleHandler;\n requestScroll?: ScrollRequestHandler;\n restoreLastFocus?: boolean;\n rowCount?: number;\n selected?: unknown;\n viewportRowCount: number;\n}\n\nexport const useKeyboardNavigation = ({\n cellFocusStateRef,\n columnCount = 0,\n containerRef,\n defaultHighlightedIndex,\n disableHighlightOnFocus,\n focusCell,\n headerCount,\n highlightedIndex: highlightedIndexProp,\n navigationStyle,\n requestScroll,\n onHighlight,\n onToggleGroup,\n rowCount = 0,\n viewportRowCount,\n}: NavigationHookProps) => {\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\n // We use aria row index for tracking rows\n const maxRowIndex = rowCount + headerCount;\n\n const setHighlightedIndex = useCallback(\n (idx: number) => {\n onHighlight?.(idx);\n setHighlightedIdx(idx);\n highlightedIndexRef.current = idx;\n },\n [onHighlight, setHighlightedIdx],\n );\n\n const setActiveCell = useCallback(\n (rowIdx: number, colIdx: number, fromKeyboard = false) => {\n const pos: CellPos = [rowIdx, colIdx];\n if (navigationStyle === \"row\") {\n setHighlightedIdx(rowIdx);\n } else {\n focusCell(pos, fromKeyboard);\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 const { current: focusState } = cellFocusStateRef;\n switch (key) {\n case \"PageDown\": {\n newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [newRowIdx, colIdx];\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 focusState.cellPos = [newRowIdx, colIdx];\n requestScroll?.({ type: \"scroll-page\", direction: \"up\" });\n }\n break;\n }\n case \"Home\": {\n newRowIdx = headerCount + 1;\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [newRowIdx, colIdx];\n requestScroll?.({ type: \"scroll-end\", direction: \"home\" });\n }\n break;\n }\n case \"End\": {\n newRowIdx = rowCount + headerCount;\n if (newRowIdx !== rowIdx) {\n focusState.cellPos = [newRowIdx, colIdx];\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 [cellFocusStateRef, headerCount, 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 cellFocusStateRef.current.cellPos = getAriaCellPos(focusedCell);\n if (navigationStyle === \"row\") {\n setHighlightedIdx(cellFocusStateRef.current.cellPos[0]);\n }\n }\n }\n }\n }, [\n disableHighlightOnFocus,\n containerRef,\n cellFocusStateRef,\n navigationStyle,\n setHighlightedIdx,\n ]);\n\n const navigateChildItems = useCallback(\n async (\n navigationStyle: \"cell\" | \"tree\" = \"cell\",\n key: NavigationKey,\n shiftKey = false,\n ): Promise<undefined> => {\n const { cellPos } = cellFocusStateRef.current;\n const [rowIdx, colIdx] = cellPos;\n let nextRowIdx = -1,\n nextColIdx = -1;\n\n if (isPagingKey(key)) {\n [nextRowIdx, nextColIdx] = await nextPageItemIdx(key, cellPos);\n } else {\n const treeNodeOperation = getTreeNodeOperation(\n containerRef,\n navigationStyle,\n cellPos,\n key,\n shiftKey,\n );\n if (\n treeNodeOperation === \"expand\" ||\n treeNodeOperation === \"collapse\"\n ) {\n onToggleGroup(treeNodeOperation, rowIdx - headerCount - 1);\n } else if (treeNodeOperation === \"level-up\") {\n [nextRowIdx, nextColIdx] = getLevelUp(containerRef, cellPos);\n } else {\n [nextRowIdx, nextColIdx] = getNextCellPos(\n key,\n cellPos,\n columnCount,\n maxRowIndex,\n );\n }\n }\n\n if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {\n setActiveCell(nextRowIdx, nextColIdx, true);\n setHighlightedIndex(nextRowIdx);\n }\n },\n [\n cellFocusStateRef,\n nextPageItemIdx,\n containerRef,\n onToggleGroup,\n headerCount,\n columnCount,\n maxRowIndex,\n setActiveCell,\n setHighlightedIndex,\n ],\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 : getNextCellPos(key, [highlighted ?? -1, 0], columnCount, maxRowIndex);\n if (nextRowIdx !== highlighted) {\n setHighlightedIndex(nextRowIdx);\n // TO(DO make this a scroll request)\n scrollRowIntoViewIfNecessary(nextRowIdx);\n }\n },\n [\n columnCount,\n maxRowIndex,\n nextPageItemIdx,\n scrollRowIntoViewIfNecessary,\n setHighlightedIndex,\n ],\n );\n\n useEffect(() => {\n if (highlightedIndexProp !== undefined && highlightedIndexProp !== -1) {\n requestAnimationFrame(() => {\n // deferred call, ensuring table has fully rendered\n scrollRowIntoViewIfNecessary(highlightedIndexProp);\n });\n }\n }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n const cell = queryClosest<HTMLDivElement>(\n e.target,\n `${CellLocator},${CellControlLocator}`,\n );\n if (cellDropdownShowing(cell)) {\n return;\n }\n if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) {\n e.preventDefault();\n e.stopPropagation();\n if (navigationStyle === \"row\") {\n moveHighlightedRow(e.key);\n } else if (navigationStyle !== \"none\") {\n if (!focusControlWithinCell(e, cell)) {\n navigateChildItems(navigationStyle, e.key, e.shiftKey);\n }\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 = queryClosest<HTMLDivElement>(evt.target, CellLocator);\n const focusedCell = getFocusedCell(target);\n if (focusedCell) {\n const [rowIdx, colIdx] = getAriaCellPos(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 rowIdx = closestRowIndex(evt.target as HTMLElement);\n if (rowIdx !== -1 && rowIdx !== highlightedIndexRef.current) {\n setHighlightedIndex(rowIdx);\n }\n },\n [setHighlightedIndex],\n );\n\n /**\n * used when editing cells\n */\n const navigateCell = useCallback(() => {\n navigateChildItems(\"cell\", \"ArrowDown\");\n }, [navigateChildItems]);\n\n return {\n highlightedIndexRef,\n navigateCell,\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":["queryClosest","useRef","useControlled","useCallback","getFocusedCell","getAriaCellPos","navigationStyle","getTreeNodeOperation","getLevelUp","getNextCellPos","useEffect","cellDropdownShowing","closestRowIndex"],"mappings":"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"}
@@ -2,6 +2,7 @@
2
2
 
3
3
  var vuuUtils = require('@vuu-ui/vuu-utils');
4
4
  var react = require('react');
5
+ var tableDomUtils = require('./table-dom-utils.js');
5
6
 
6
7
  const { IDX } = vuuUtils.metadataKeys;
7
8
  const NO_SELECTION = [];
@@ -51,7 +52,7 @@ const useSelection = ({
51
52
  if (isSelectionEvent(e)) {
52
53
  const { current: rowIndex } = highlightedIndexRef;
53
54
  if (rowIndex !== void 0 && rowIndex !== -1) {
54
- const rowEl = vuuUtils.getRowElementAtIndex(e.target, rowIndex);
55
+ const rowEl = tableDomUtils.getRowElementByAriaIndex(e.target, rowIndex);
55
56
  if (rowEl) {
56
57
  vuuUtils.dispatchMouseEvent(rowEl, "click");
57
58
  }
@@ -1 +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 queryClosest,\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 (e, 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 if (selectionModel === \"checkbox\") {\n const cell = queryClosest(e.target, \".vuuTableCell\");\n if (!cell?.querySelector(\".vuuCheckboxRowSelector\")) {\n return;\n }\n }\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","queryClosest","getRowElementAtIndex","dispatchMouseEvent"],"mappings":";;;;;AAuBA,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,CAAA,EAAG,GAAK,EAAA,WAAA,EAAa,qBAA0B,KAAA;AAC9C,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,IAAI,mBAAmB,UAAY,EAAA;AACjC,QAAA,MAAM,IAAO,GAAAC,qBAAA,CAAa,CAAE,CAAA,MAAA,EAAQ,eAAe,CAAA,CAAA;AACnD,QAAA,IAAI,CAAC,IAAA,EAAM,aAAc,CAAA,yBAAyB,CAAG,EAAA;AACnD,UAAA,OAAA;AAAA,SACF;AAAA,OACF;AAEA,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,KAAoBD,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,GAAAK,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;;;;"}
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 isRowSelected,\n metadataKeys,\n queryClosest,\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\";\nimport { getRowElementByAriaIndex } from \"./table-dom-utils\";\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 (e, 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 if (selectionModel === \"checkbox\") {\n const cell = queryClosest(e.target, \".vuuTableCell\");\n if (!cell?.querySelector(\".vuuCheckboxRowSelector\")) {\n return;\n }\n }\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 = getRowElementByAriaIndex(e.target, rowIndex);\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","queryClosest","getRowElementByAriaIndex","dispatchMouseEvent"],"mappings":";;;;;;AAuBA,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,CAAA,EAAG,GAAK,EAAA,WAAA,EAAa,qBAA0B,KAAA;AAC9C,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,IAAI,mBAAmB,UAAY,EAAA;AACjC,QAAA,MAAM,IAAO,GAAAC,qBAAA,CAAa,CAAE,CAAA,MAAA,EAAQ,eAAe,CAAA,CAAA;AACnD,QAAA,IAAI,CAAC,IAAA,EAAM,aAAc,CAAA,yBAAyB,CAAG,EAAA;AACnD,UAAA,OAAA;AAAA,SACF;AAAA,OACF;AAEA,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,KAAoBD,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,GAAAK,sCAAA,CAAyB,CAAE,CAAA,MAAA,EAAQ,QAAQ,CAAA,CAAA;AACzD,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;;;;"}
package/cjs/useTable.js CHANGED
@@ -20,6 +20,14 @@ var useTableModel = require('./useTableModel.js');
20
20
  var useTableScroll = require('./useTableScroll.js');
21
21
  var useTableViewport = require('./useTableViewport.js');
22
22
 
23
+ const nullHeaderState = {
24
+ height: -1,
25
+ count: -1
26
+ };
27
+ const zeroHeaderState = {
28
+ height: 0,
29
+ count: 0
30
+ };
23
31
  const stripInternalProperties = (tableConfig) => {
24
32
  return tableConfig;
25
33
  };
@@ -63,6 +71,7 @@ const useTable = ({
63
71
  renderBufferSize = 0,
64
72
  rowHeight = 20,
65
73
  scrollingApiRef,
74
+ selectionBookendWidth,
66
75
  selectionModel,
67
76
  showColumnHeaders,
68
77
  showPaginationControls,
@@ -75,7 +84,9 @@ const useTable = ({
75
84
  const initialState = react.useMemo(() => ({ ...NullCellFocusState }), []);
76
85
  const cellFocusStateRef = react.useRef(initialState);
77
86
  const focusCellRef = react.useRef();
78
- const [headerHeight, setHeaderHeight] = react.useState(showColumnHeaders ? -1 : 0);
87
+ const [headerState, setHeaderState] = react.useState(
88
+ showColumnHeaders ? nullHeaderState : zeroHeaderState
89
+ );
79
90
  const [rowCount, setRowCount] = react.useState(dataSource.size);
80
91
  if (dataSource === void 0) {
81
92
  throw Error("no data source provided to Vuu Table");
@@ -84,7 +95,7 @@ const useTable = ({
84
95
  setRowCount(size2);
85
96
  }, []);
86
97
  const virtualContentHeight = rowHeight * rowCount;
87
- const viewportBodyHeight = size.height - (headerHeight === -1 ? 0 : headerHeight);
98
+ const viewportBodyHeight = size.height - (headerState.height === -1 ? 0 : headerState.height);
88
99
  const verticalScrollbarWidth = virtualContentHeight > viewportBodyHeight ? 10 : 0;
89
100
  const availableWidth = size.width - (verticalScrollbarWidth + 8);
90
101
  const rowClassNameGenerator = useRowClassNameGenerators.useRowClassNameGenerators(config);
@@ -104,17 +115,10 @@ const useTable = ({
104
115
  dispatchTableModelAction({
105
116
  availableWidth,
106
117
  type: "init",
107
- // tableConfig: config,
108
118
  tableConfig: tableConfigRef.current,
109
119
  dataSource
110
120
  });
111
- }, [
112
- availableWidth,
113
- config,
114
- dataSource,
115
- dispatchTableModelAction,
116
- verticalScrollbarWidth
117
- ]);
121
+ }, [availableWidth, config, dataSource, dispatchTableModelAction]);
118
122
  const applyTableConfigChange = react.useCallback(
119
123
  (config2) => {
120
124
  dispatchTableModelAction({
@@ -153,9 +157,10 @@ const useTable = ({
153
157
  ...viewportMeasurements
154
158
  } = useTableViewport.useTableViewport({
155
159
  columns,
156
- headerHeight,
160
+ headerHeight: headerState.height,
157
161
  rowCount,
158
162
  rowHeight,
163
+ selectionEndSize: selectionBookendWidth,
159
164
  size,
160
165
  showPaginationControls
161
166
  });
@@ -210,6 +215,7 @@ const useTable = ({
210
215
  direction: "home"
211
216
  });
212
217
  }
218
+ console.log(`useTable dispatch tableConfig`);
213
219
  dispatchTableModelAction({
214
220
  type: "tableConfig",
215
221
  ...config2,
@@ -396,6 +402,16 @@ const useTable = ({
396
402
  },
397
403
  [columnMap, columns, dataSource, dispatchTableModelAction]
398
404
  );
405
+ const handleToggleGroup = react.useCallback(
406
+ (treeNodeOperation, rowIdx) => {
407
+ if (treeNodeOperation === "expand") {
408
+ dataSource.openTreeNode(rowIdx);
409
+ } else {
410
+ dataSource.closeTreeNode(rowIdx);
411
+ }
412
+ },
413
+ [dataSource]
414
+ );
399
415
  const {
400
416
  focusCell,
401
417
  focusCellPlaceholderKeyDown,
@@ -411,7 +427,7 @@ const useTable = ({
411
427
  const columnCount = columns.filter((c) => c.hidden !== true).length;
412
428
  const {
413
429
  highlightedIndexRef,
414
- navigate,
430
+ navigateCell: navigate,
415
431
  onFocus: navigationFocus,
416
432
  onKeyDown: navigationKeyDown,
417
433
  ...containerProps
@@ -421,11 +437,13 @@ const useTable = ({
421
437
  containerRef,
422
438
  disableFocus,
423
439
  focusCell,
440
+ headerCount: headerState.count,
424
441
  highlightedIndex: highlightedIndexProp,
425
442
  navigationStyle,
426
443
  requestScroll,
427
444
  rowCount,
428
445
  onHighlight,
446
+ onToggleGroup: handleToggleGroup,
429
447
  viewportRange: range,
430
448
  viewportRowCount: viewportMeasurements.rowCount
431
449
  });
@@ -450,7 +468,8 @@ const useTable = ({
450
468
  columns,
451
469
  data,
452
470
  dataSource,
453
- getSelectedRows
471
+ getSelectedRows,
472
+ headerCount: headerState.count
454
473
  });
455
474
  const onMoveGroupColumn = react.useCallback(
456
475
  (columns2) => {
@@ -463,7 +482,7 @@ const useTable = ({
463
482
  if (vuuUtils.isGroupColumn(column)) {
464
483
  dataSource.groupBy = [];
465
484
  } else {
466
- if (dataSource && dataSource.groupBy.includes(column.name)) {
485
+ if (dataSource && dataSource.groupBy?.includes(column.name)) {
467
486
  dataSource.groupBy = dataSource.groupBy.filter(
468
487
  (columnName) => columnName !== column.name
469
488
  );
@@ -511,7 +530,6 @@ const useTable = ({
511
530
  allowCellBlockSelection,
512
531
  columnCount,
513
532
  containerRef,
514
- focusCell,
515
533
  onSelectCellBlock: handleSelectCellBlock,
516
534
  rowCount
517
535
  });
@@ -580,18 +598,21 @@ const useTable = ({
580
598
  const handleDragStartRow = react.useCallback(
581
599
  (dragDropState) => {
582
600
  const { initialDragElement } = dragDropState;
583
- const rowIndex = tableDomUtils.getIndexFromRowElement(initialDragElement);
601
+ const rowIndex = tableDomUtils.getAriaRowIndex(initialDragElement) - headerState.count - 1;
584
602
  const row = dataRef.current.find((row2) => row2[0] === rowIndex);
585
603
  if (row) {
586
604
  dragDropState.setPayload(row);
587
605
  }
588
606
  onDragStart?.(dragDropState);
589
607
  },
590
- [dataRef, onDragStart]
608
+ [dataRef, headerState.count, onDragStart]
609
+ );
610
+ const onHeaderHeightMeasured = react.useCallback(
611
+ (height, count) => {
612
+ setHeaderState({ height, count });
613
+ },
614
+ []
591
615
  );
592
- const onHeaderHeightMeasured = react.useCallback((height) => {
593
- setHeaderHeight(height);
594
- }, []);
595
616
  const { onMouseDown: rowDragMouseDown, draggable: draggableRow } = useRowDragDrop({
596
617
  allowDragDrop,
597
618
  containerRef,
@@ -623,7 +644,7 @@ const useTable = ({
623
644
  focusCellPlaceholderRef,
624
645
  getRowOffset,
625
646
  handleContextMenuAction,
626
- headerHeight,
647
+ headerState,
627
648
  headings,
628
649
  highlightedIndex: highlightedIndexRef.current,
629
650
  menuBuilder,