@vuu-ui/vuu-table 0.9.0 → 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 (89) 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 +30 -18
  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 +71 -28
  30. package/cjs/table-dom-utils.js.map +1 -1
  31. package/cjs/useCell.js +1 -2
  32. package/cjs/useCell.js.map +1 -1
  33. package/cjs/useKeyboardNavigation.js +78 -33
  34. package/cjs/useKeyboardNavigation.js.map +1 -1
  35. package/cjs/useTable.js +21 -14
  36. package/cjs/useTable.js.map +1 -1
  37. package/cjs/useTableContextMenu.js +5 -4
  38. package/cjs/useTableContextMenu.js.map +1 -1
  39. package/cjs/useTableModel.js +24 -9
  40. package/cjs/useTableModel.js.map +1 -1
  41. package/esm/Row.css.js +1 -1
  42. package/esm/Row.js +21 -8
  43. package/esm/Row.js.map +1 -1
  44. package/esm/Table.css.js +1 -1
  45. package/esm/Table.js +30 -18
  46. package/esm/Table.js.map +1 -1
  47. package/esm/cell-block/CellBlock.css.js +1 -1
  48. package/esm/cell-block/CellBlock.js +4 -0
  49. package/esm/cell-block/CellBlock.js.map +1 -1
  50. package/esm/cell-block/cellblock-utils.js +8 -23
  51. package/esm/cell-block/cellblock-utils.js.map +1 -1
  52. package/esm/cell-block/useCellBlockSelection.js +38 -16
  53. package/esm/cell-block/useCellBlockSelection.js.map +1 -1
  54. package/esm/column-header-pill/ColumnHeaderPill.js +2 -1
  55. package/esm/column-header-pill/ColumnHeaderPill.js.map +1 -1
  56. package/esm/column-menu/ColumnMenu.css.js +1 -1
  57. package/esm/context-menu/buildContextMenuDescriptors.js +2 -2
  58. package/esm/context-menu/buildContextMenuDescriptors.js.map +1 -1
  59. package/esm/context-menu/useHandleTableContextMenu.js +2 -2
  60. package/esm/context-menu/useHandleTableContextMenu.js.map +1 -1
  61. package/esm/header-cell/GroupHeaderCell.css.js +1 -1
  62. package/esm/header-cell/GroupHeaderCell.js +10 -1
  63. package/esm/header-cell/GroupHeaderCell.js.map +1 -1
  64. package/esm/header-cell/HeaderCell.css.js +1 -1
  65. package/esm/table-cell/TableCell.css.js +1 -1
  66. package/esm/table-cell/TableGroupCell.css.js +1 -1
  67. package/esm/table-cell/TableGroupCell.js +18 -9
  68. package/esm/table-cell/TableGroupCell.js.map +1 -1
  69. package/esm/table-dom-utils.js +69 -26
  70. package/esm/table-dom-utils.js.map +1 -1
  71. package/esm/useCell.js +1 -2
  72. package/esm/useCell.js.map +1 -1
  73. package/esm/useKeyboardNavigation.js +77 -32
  74. package/esm/useKeyboardNavigation.js.map +1 -1
  75. package/esm/useTable.js +22 -15
  76. package/esm/useTable.js.map +1 -1
  77. package/esm/useTableContextMenu.js +6 -5
  78. package/esm/useTableContextMenu.js.map +1 -1
  79. package/esm/useTableModel.js +24 -9
  80. package/esm/useTableModel.js.map +1 -1
  81. package/package.json +9 -9
  82. package/types/Row.d.ts +1 -1
  83. package/types/Table.d.ts +14 -3
  84. package/types/cell-block/useCellBlockSelection.d.ts +1 -3
  85. package/types/table-dom-utils.d.ts +6 -4
  86. package/types/useKeyboardNavigation.d.ts +4 -2
  87. package/types/useTable.d.ts +2 -2
  88. package/types/useTableContextMenu.d.ts +2 -1
  89. package/types/useTableModel.d.ts +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"TableGroupCell.js","sources":["../../src/table-cell/TableGroupCell.tsx"],"sourcesContent":["import { GroupColumnDescriptor, TableCellProps } from \"@vuu-ui/vuu-table-types\";\nimport { getGroupValueAndOffset, metadataKeys } from \"@vuu-ui/vuu-utils\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { MouseEvent, useCallback } from \"react\";\nimport { useCell } from \"../useCell\";\nimport cx from \"clsx\";\n\nimport tableGroupCellCss from \"./TableGroupCell.css\";\n\nconst { IS_LEAF } = metadataKeys;\n\nconst classBase = \"vuuTableGroupCell\";\n\nexport const TableGroupCell = ({\n column,\n columnMap,\n onClick,\n row,\n}: TableCellProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-table-group-cell\",\n css: tableGroupCellCss,\n window: targetWindow,\n });\n\n const { columns } = column as GroupColumnDescriptor;\n const [value, offset] = getGroupValueAndOffset(columns, row, columnMap);\n const { className, style } = useCell(column, classBase);\n\n const handleClick = useCallback(\n (evt: MouseEvent<HTMLDivElement>) => {\n onClick?.(evt, column);\n },\n [column, onClick],\n );\n\n const isLeaf = row[IS_LEAF];\n const spacers = Array(offset)\n .fill(0)\n .map((n, i) => <span className={`${classBase}-spacer`} key={i} />);\n\n return (\n <div\n className={cx(className, \"vuuTableCell\")}\n role=\"cell\"\n style={style}\n onClick={isLeaf ? undefined : handleClick}\n >\n {spacers}\n {isLeaf ? null : (\n <span className={`${classBase}-toggle`} data-icon=\"triangle-right\" />\n )}\n <span>{value}</span>\n </div>\n );\n};\n"],"names":["metadataKeys","useWindow","useComponentCssInjection","tableGroupCellCss","getGroupValueAndOffset","useCell","useCallback","jsxs","jsx"],"mappings":";;;;;;;;;;;AAUA,MAAM,EAAE,SAAY,GAAAA,qBAAA,CAAA;AAEpB,MAAM,SAAY,GAAA,mBAAA,CAAA;AAEX,MAAM,iBAAiB,CAAC;AAAA,EAC7B,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAA;AACF,CAAsB,KAAA;AACpB,EAAA,MAAM,eAAeC,gBAAU,EAAA,CAAA;AAC/B,EAAyBC,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,sBAAA;AAAA,IACR,GAAK,EAAAC,gBAAA;AAAA,IACL,MAAQ,EAAA,YAAA;AAAA,GACT,CAAA,CAAA;AAED,EAAM,MAAA,EAAE,SAAY,GAAA,MAAA,CAAA;AACpB,EAAA,MAAM,CAAC,KAAO,EAAA,MAAM,IAAIC,+BAAuB,CAAA,OAAA,EAAS,KAAK,SAAS,CAAA,CAAA;AACtE,EAAA,MAAM,EAAE,SAAW,EAAA,KAAA,EAAU,GAAAC,eAAA,CAAQ,QAAQ,SAAS,CAAA,CAAA;AAEtD,EAAA,MAAM,WAAc,GAAAC,iBAAA;AAAA,IAClB,CAAC,GAAoC,KAAA;AACnC,MAAA,OAAA,GAAU,KAAK,MAAM,CAAA,CAAA;AAAA,KACvB;AAAA,IACA,CAAC,QAAQ,OAAO,CAAA;AAAA,GAClB,CAAA;AAEA,EAAM,MAAA,MAAA,GAAS,IAAI,OAAO,CAAA,CAAA;AAC1B,EAAA,MAAM,UAAU,KAAM,CAAA,MAAM,EACzB,IAAK,CAAA,CAAC,EACN,GAAI,CAAA,CAAC,CAAG,EAAA,CAAA,oCAAO,MAAK,EAAA,EAAA,SAAA,EAAW,GAAG,SAAS,CAAA,OAAA,CAAA,EAAA,EAAgB,CAAG,CAAE,CAAA,CAAA;AAEnE,EACE,uBAAAC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,cAAc,CAAA;AAAA,MACvC,IAAK,EAAA,MAAA;AAAA,MACL,KAAA;AAAA,MACA,OAAA,EAAS,SAAS,KAAY,CAAA,GAAA,WAAA;AAAA,MAE7B,QAAA,EAAA;AAAA,QAAA,OAAA;AAAA,QACA,MAAA,GAAS,uBACPC,cAAA,CAAA,MAAA,EAAA,EAAK,WAAW,CAAG,EAAA,SAAS,CAAW,OAAA,CAAA,EAAA,WAAA,EAAU,gBAAiB,EAAA,CAAA;AAAA,wBAErEA,cAAA,CAAC,UAAM,QAAM,EAAA,KAAA,EAAA,CAAA;AAAA,OAAA;AAAA,KAAA;AAAA,GACf,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"TableGroupCell.js","sources":["../../src/table-cell/TableGroupCell.tsx"],"sourcesContent":["import { GroupColumnDescriptor, TableCellProps } from \"@vuu-ui/vuu-table-types\";\nimport { Icon, ToggleIconButton } from \"@vuu-ui/vuu-ui-controls\";\nimport { getGroupIcon, getGroupValue, metadataKeys } from \"@vuu-ui/vuu-utils\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport cx from \"clsx\";\nimport { MouseEvent, useCallback } from \"react\";\nimport { useCell } from \"../useCell\";\n\nimport tableCellCss from \"./TableCell.css\";\nimport tableGroupCellCss from \"./TableGroupCell.css\";\n\nconst { COUNT, IS_EXPANDED, IS_LEAF } = metadataKeys;\n\nconst classBase = \"vuuTableGroupCell\";\n\nexport const TableGroupCell = ({\n column,\n columnMap,\n onClick,\n row,\n}: TableCellProps) => {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"vuu-table-cell\",\n css: tableCellCss,\n window: targetWindow,\n });\n useComponentCssInjection({\n testId: \"vuu-table-group-cell\",\n css: tableGroupCellCss,\n window: targetWindow,\n });\n\n const { columns } = column as GroupColumnDescriptor;\n const value = getGroupValue(columns, row, columnMap);\n const icon = getGroupIcon(columns, row);\n const { className, style } = useCell(column, classBase);\n\n const handleClick = useCallback(\n (evt: MouseEvent<HTMLDivElement>) => {\n onClick?.(evt, column);\n },\n [column, onClick],\n );\n\n const { [COUNT]: count, [IS_EXPANDED]: isExpanded, [IS_LEAF]: isLeaf } = row;\n\n return (\n <div\n aria-colindex={1}\n className={cx(className, \"vuuTableCell\")}\n role=\"cell\"\n style={style}\n onClick={isLeaf ? undefined : handleClick}\n >\n <span className={`${classBase}-spacer`} />\n {isLeaf || count == 0 ? null : (\n <ToggleIconButton isExpanded={isExpanded} />\n )}\n {icon ? <Icon name={icon} /> : null}\n <span>{value}</span>\n </div>\n );\n};\n"],"names":["metadataKeys","useWindow","useComponentCssInjection","tableCellCss","tableGroupCellCss","getGroupValue","getGroupIcon","useCell","useCallback","jsxs","jsx","ToggleIconButton","Icon"],"mappings":";;;;;;;;;;;;;AAYA,MAAM,EAAE,KAAA,EAAO,WAAa,EAAA,OAAA,EAAY,GAAAA,qBAAA,CAAA;AAExC,MAAM,SAAY,GAAA,mBAAA,CAAA;AAEX,MAAM,iBAAiB,CAAC;AAAA,EAC7B,MAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,GAAA;AACF,CAAsB,KAAA;AACpB,EAAA,MAAM,eAAeC,gBAAU,EAAA,CAAA;AAC/B,EAAyBC,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,gBAAA;AAAA,IACR,GAAK,EAAAC,SAAA;AAAA,IACL,MAAQ,EAAA,YAAA;AAAA,GACT,CAAA,CAAA;AACD,EAAyBD,+BAAA,CAAA;AAAA,IACvB,MAAQ,EAAA,sBAAA;AAAA,IACR,GAAK,EAAAE,gBAAA;AAAA,IACL,MAAQ,EAAA,YAAA;AAAA,GACT,CAAA,CAAA;AAED,EAAM,MAAA,EAAE,SAAY,GAAA,MAAA,CAAA;AACpB,EAAA,MAAM,KAAQ,GAAAC,sBAAA,CAAc,OAAS,EAAA,GAAA,EAAK,SAAS,CAAA,CAAA;AACnD,EAAM,MAAA,IAAA,GAAOC,qBAAa,CAAA,OAAA,EAAS,GAAG,CAAA,CAAA;AACtC,EAAA,MAAM,EAAE,SAAW,EAAA,KAAA,EAAU,GAAAC,eAAA,CAAQ,QAAQ,SAAS,CAAA,CAAA;AAEtD,EAAA,MAAM,WAAc,GAAAC,iBAAA;AAAA,IAClB,CAAC,GAAoC,KAAA;AACnC,MAAA,OAAA,GAAU,KAAK,MAAM,CAAA,CAAA;AAAA,KACvB;AAAA,IACA,CAAC,QAAQ,OAAO,CAAA;AAAA,GAClB,CAAA;AAEA,EAAA,MAAM,EAAE,CAAC,KAAK,GAAG,KAAO,EAAA,CAAC,WAAW,GAAG,UAAY,EAAA,CAAC,OAAO,GAAG,QAAW,GAAA,GAAA,CAAA;AAEzE,EACE,uBAAAC,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,eAAe,EAAA,CAAA;AAAA,MACf,SAAA,EAAW,EAAG,CAAA,SAAA,EAAW,cAAc,CAAA;AAAA,MACvC,IAAK,EAAA,MAAA;AAAA,MACL,KAAA;AAAA,MACA,OAAA,EAAS,SAAS,KAAY,CAAA,GAAA,WAAA;AAAA,MAE9B,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAC,MAAK,EAAA,EAAA,SAAA,EAAW,CAAG,EAAA,SAAS,CAAW,OAAA,CAAA,EAAA,CAAA;AAAA,QACvC,UAAU,KAAS,IAAA,CAAA,GAAI,IACtB,mBAAAA,cAAA,CAACC,kCAAiB,UAAwB,EAAA,CAAA;AAAA,QAE3C,IAAO,mBAAAD,cAAA,CAACE,kBAAK,EAAA,EAAA,IAAA,EAAM,MAAM,CAAK,GAAA,IAAA;AAAA,wBAC/BF,cAAA,CAAC,UAAM,QAAM,EAAA,KAAA,EAAA,CAAA;AAAA,OAAA;AAAA,KAAA;AAAA,GACf,CAAA;AAEJ;;;;"}
@@ -1,13 +1,28 @@
1
1
  'use strict';
2
2
 
3
- const NULL_CELL_POS = [-1, -1];
4
3
  const headerCellQuery = (colIdx) => `.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx}']`;
5
- const dataCellQuery = (rowIdx, colIdx) => `.vuuTable-table [aria-rowindex='${rowIdx}'] > [aria-colindex='${colIdx}']`;
4
+ const dataCellQuery = (ariaRowIdx, ariaColIdx) => `.vuuTable-table [aria-rowindex='${ariaRowIdx}'] > [aria-colindex='${ariaColIdx}']`;
5
+ const getLevelUp = (containerRef, cellPos) => {
6
+ const cell = getTableCell(containerRef, cellPos);
7
+ let row = cell?.parentElement;
8
+ const level = parseInt(row?.ariaLevel ?? "1");
9
+ if (level > 1) {
10
+ const targetLevel = `${level - 1}`;
11
+ while (row !== null && row.ariaLevel !== targetLevel) {
12
+ row = row.previousElementSibling;
13
+ }
14
+ if (row) {
15
+ const nextRowIndex = parseInt(row.ariaRowIndex ?? "- 1");
16
+ if (nextRowIndex !== -1) {
17
+ return [nextRowIndex - 1, 0];
18
+ }
19
+ }
20
+ }
21
+ return cellPos;
22
+ };
6
23
  const getTableCell = (containerRef, [rowIdx, colIdx]) => {
7
24
  const cssQuery = dataCellQuery(rowIdx, colIdx);
8
- const cell = containerRef.current?.querySelector(
9
- cssQuery
10
- );
25
+ const cell = containerRef.current?.querySelector(cssQuery);
11
26
  if (cellIsEditable(cell)) {
12
27
  const focusableContent = cell.querySelector("button");
13
28
  return focusableContent || cell;
@@ -15,6 +30,15 @@ const getTableCell = (containerRef, [rowIdx, colIdx]) => {
15
30
  return cell;
16
31
  }
17
32
  };
33
+ const getFocusedCell = (el) => {
34
+ if (el?.role == "cell" || el?.role === "columnheader") {
35
+ return el;
36
+ } else {
37
+ return el?.closest(
38
+ "[role='columnHeader'],[role='cell']"
39
+ );
40
+ }
41
+ };
18
42
  const cellIsEditable = (cell) => cell?.classList.contains("vuuTableCell-editable");
19
43
  const cellDropdownShowing = (cell) => {
20
44
  if (cellIsEditable(cell)) {
@@ -22,6 +46,17 @@ const cellDropdownShowing = (cell) => {
22
46
  }
23
47
  return false;
24
48
  };
49
+ const cellIsGroupCell = (cell) => cell?.classList.contains("vuuTableGroupCell");
50
+ const rowIsExpanded = (cell) => {
51
+ switch (cell.parentElement?.ariaExpanded) {
52
+ case "true":
53
+ return true;
54
+ case "false":
55
+ return false;
56
+ default:
57
+ return void 0;
58
+ }
59
+ };
25
60
  const cellIsTextInput = (cell) => cell.querySelector(".vuuTableInputCell") !== null;
26
61
  const getAriaRowIndex = (rowElement) => {
27
62
  const rowIndex = rowElement?.ariaRowIndex;
@@ -33,8 +68,8 @@ const getAriaRowIndex = (rowElement) => {
33
68
  }
34
69
  return -1;
35
70
  };
36
- const getAriaColIndex = (rowElement) => {
37
- const colIndex = rowElement?.ariaColIndex;
71
+ const getAriaColIndex = (cellElement) => {
72
+ const colIndex = cellElement?.ariaColIndex;
38
73
  if (colIndex != null) {
39
74
  const index = parseInt(colIndex);
40
75
  if (!isNaN(index)) {
@@ -59,29 +94,12 @@ const getRowElementByAriaIndex = (container, rowIndex) => {
59
94
  }
60
95
  }
61
96
  };
62
- const getIndexFromRowElement = (rowElement) => {
63
- const ariaRowIndex = getAriaRowIndex(rowElement);
64
- return ariaRowIndex === -1 ? -1 : ariaRowIndex - 1;
65
- };
66
- const getIndexFromCellElement = (cellElement) => getAriaColIndex(cellElement);
67
- const getTableCellPos = (tableCell) => {
68
- const colIdx = getIndexFromCellElement(tableCell);
69
- if (tableCell.role === "columnHeader") {
70
- return [-1, colIdx];
71
- } else {
72
- const focusedRow = tableCell.closest("[role='row']");
73
- if (focusedRow) {
74
- return [getIndexFromRowElement(focusedRow), colIdx];
75
- }
76
- }
77
- return NULL_CELL_POS;
78
- };
79
97
  const getAriaCellPos = (tableCell) => {
80
98
  const focusedRow = tableCell.closest("[role='row']");
81
99
  return [getAriaRowIndex(focusedRow), getAriaColIndex(tableCell)];
82
100
  };
83
101
  const closestRow = (el) => el.closest('[role="row"]');
84
- const closestRowIndex = (el) => getIndexFromRowElement(closestRow(el));
102
+ const closestRowIndex = (el) => getAriaRowIndex(closestRow(el));
85
103
  function getNextCellPos(key, [rowIdx, colIdx], columnCount, maxRowIndex) {
86
104
  if (key === "ArrowUp") {
87
105
  if (rowIdx > -1) {
@@ -112,6 +130,31 @@ function getNextCellPos(key, [rowIdx, colIdx], columnCount, maxRowIndex) {
112
130
  }
113
131
  return [rowIdx, colIdx];
114
132
  }
133
+ const getTreeNodeOperation = (containerRef, navigationStyle, cellPos, key, shiftKey) => {
134
+ const cell = getTableCell(containerRef, cellPos);
135
+ if (navigationStyle === "cell" && !cellIsGroupCell(cell)) {
136
+ return void 0;
137
+ }
138
+ if (navigationStyle == "cell" && !shiftKey) {
139
+ return void 0;
140
+ }
141
+ if (cellIsGroupCell(cell)) {
142
+ const isExpanded = rowIsExpanded(cell);
143
+ if (isExpanded === true) {
144
+ if (key === "ArrowLeft") {
145
+ return "collapse";
146
+ }
147
+ } else if (isExpanded === false) {
148
+ if (key === "ArrowRight") {
149
+ return "expand";
150
+ } else if (key === "ArrowLeft") {
151
+ return "level-up";
152
+ }
153
+ } else if (key === "ArrowLeft") {
154
+ return "level-up";
155
+ }
156
+ }
157
+ };
115
158
  const NO_SCROLL_NECESSARY = [void 0, void 0];
116
159
  const howFarIsRowOutsideViewport = (rowEl, totalHeaderHeight, contentContainer = rowEl.closest(".vuuTable-contentContainer")) => {
117
160
  if (contentContainer) {
@@ -142,12 +185,12 @@ exports.dataCellQuery = dataCellQuery;
142
185
  exports.getAriaCellPos = getAriaCellPos;
143
186
  exports.getAriaColIndex = getAriaColIndex;
144
187
  exports.getAriaRowIndex = getAriaRowIndex;
145
- exports.getIndexFromCellElement = getIndexFromCellElement;
146
- exports.getIndexFromRowElement = getIndexFromRowElement;
188
+ exports.getFocusedCell = getFocusedCell;
189
+ exports.getLevelUp = getLevelUp;
147
190
  exports.getNextCellPos = getNextCellPos;
148
191
  exports.getRowElementByAriaIndex = getRowElementByAriaIndex;
149
192
  exports.getTableCell = getTableCell;
150
- exports.getTableCellPos = getTableCellPos;
193
+ exports.getTreeNodeOperation = getTreeNodeOperation;
151
194
  exports.headerCellQuery = headerCellQuery;
152
195
  exports.howFarIsRowOutsideViewport = howFarIsRowOutsideViewport;
153
196
  //# sourceMappingURL=table-dom-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"table-dom-utils.js","sources":["../src/table-dom-utils.ts"],"sourcesContent":["import { RefObject } from \"react\";\nimport { ScrollDirection } from \"./useTableScroll\";\nimport type { ArrowKey, PageKey } from \"@vuu-ui/vuu-utils\";\nimport type { CellPos } from \"@vuu-ui/vuu-table-types\";\n\nconst NULL_CELL_POS: CellPos = [-1, -1];\n\nexport type NavigationKey = PageKey | ArrowKey;\n\nexport const headerCellQuery = (colIdx: number) =>\n `.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx}']`;\n\nexport const dataCellQuery = (rowIdx: number, colIdx: number) =>\n `.vuuTable-table [aria-rowindex='${rowIdx}'] > [aria-colindex='${colIdx}']`;\n\nexport const getTableCell = (\n containerRef: RefObject<HTMLElement>,\n [rowIdx, colIdx]: CellPos,\n) => {\n const cssQuery = dataCellQuery(rowIdx, colIdx);\n const cell = containerRef.current?.querySelector(\n cssQuery,\n ) as HTMLTableCellElement;\n\n if (cellIsEditable(cell)) {\n // Dropdown gets focus, Input does not\n const focusableContent = cell.querySelector(\"button\") as HTMLElement;\n return focusableContent || cell;\n } else {\n return cell;\n }\n};\n\nexport const cellIsEditable = (cell: HTMLDivElement | null) =>\n cell?.classList.contains(\"vuuTableCell-editable\");\n\nexport const cellDropdownShowing = (cell: HTMLDivElement | null) => {\n if (cellIsEditable(cell)) {\n return cell?.querySelector('.saltDropdown[aria-expanded=\"true\"]') !== null;\n }\n return false;\n};\n\nexport const cellIsTextInput = (cell: HTMLElement) =>\n cell.querySelector(\".vuuTableInputCell\") !== null;\n\nexport const getAriaRowIndex = (rowElement: HTMLElement | null) => {\n const rowIndex = rowElement?.ariaRowIndex;\n if (rowIndex != null) {\n const index = parseInt(rowIndex);\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getAriaColIndex = (rowElement: HTMLElement | null) => {\n const colIndex = rowElement?.ariaColIndex;\n if (colIndex != null) {\n const index = parseInt(colIndex);\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getRowElementByAriaIndex = (\n container: HTMLDivElement | EventTarget,\n rowIndex: number,\n) => {\n if (rowIndex === -1) {\n return null;\n } else {\n const activeRow = (container as HTMLElement).querySelector(\n `[aria-rowindex=\"${rowIndex}\"]`,\n ) as HTMLElement;\n\n if (activeRow) {\n return activeRow;\n } else {\n throw Error(\n `getRowElementAtIndex no row found for index index ${rowIndex}`,\n );\n }\n }\n};\n\nexport const getIndexFromRowElement = (rowElement: HTMLElement | null) => {\n const ariaRowIndex = getAriaRowIndex(rowElement);\n return ariaRowIndex === -1 ? -1 : ariaRowIndex - 1;\n};\n\nexport const getIndexFromCellElement = (cellElement: HTMLElement | null) =>\n getAriaColIndex(cellElement);\n\nexport const getTableCellPos = (tableCell: HTMLDivElement): CellPos => {\n const colIdx = getIndexFromCellElement(tableCell);\n if (tableCell.role === \"columnHeader\") {\n return [-1, colIdx];\n } else {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n if (focusedRow) {\n return [getIndexFromRowElement(focusedRow), colIdx];\n }\n }\n return NULL_CELL_POS;\n};\n\nexport const getAriaCellPos = (tableCell: HTMLDivElement): CellPos => {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n return [getAriaRowIndex(focusedRow), getAriaColIndex(tableCell)];\n};\n\nconst closestRow = (el: HTMLElement) =>\n el.closest('[role=\"row\"]') as HTMLElement;\n\nexport const closestRowIndex = (el: HTMLElement) =>\n getIndexFromRowElement(closestRow(el));\n\nexport function getNextCellPos(\n key: ArrowKey,\n [rowIdx, colIdx]: CellPos,\n columnCount: number,\n maxRowIndex: 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 [1, colIdx];\n } else if (rowIdx === maxRowIndex) {\n return [rowIdx, colIdx];\n } else {\n return [rowIdx + 1, colIdx];\n }\n } else if (key === \"ArrowRight\") {\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\nconst NO_SCROLL_NECESSARY = [undefined, undefined] as const;\n\nexport const howFarIsRowOutsideViewport = (\n rowEl: HTMLElement,\n totalHeaderHeight: number,\n contentContainer = rowEl.closest(\".vuuTable-contentContainer\"),\n): readonly [ScrollDirection | undefined, number | undefined] => {\n //TODO lots of scope for optimisation here\n if (contentContainer) {\n // TODO take totalHeaderHeight into consideration\n const viewport = contentContainer?.getBoundingClientRect();\n const upperBoundary = viewport.top + totalHeaderHeight;\n const row = rowEl.getBoundingClientRect();\n if (row) {\n if (row.bottom > viewport.bottom) {\n return [\"down\", row.bottom - viewport.bottom];\n } else if (row.top < upperBoundary) {\n return [\"up\", row.top - upperBoundary];\n } else {\n return NO_SCROLL_NECESSARY;\n }\n } else {\n throw Error(\"Whats going on, row not found\");\n }\n } else {\n throw Error(\"Whats going on, scrollbar container not found\");\n }\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"table-dom-utils.js","sources":["../src/table-dom-utils.ts"],"sourcesContent":["import { RefObject } from \"react\";\nimport { ScrollDirection } from \"./useTableScroll\";\nimport type { ArrowKey, PageKey } from \"@vuu-ui/vuu-utils\";\nimport type { CellPos } from \"@vuu-ui/vuu-table-types\";\n\nexport type NavigationKey = PageKey | ArrowKey;\n\nexport const headerCellQuery = (colIdx: number) =>\n `.vuuTable-col-headers .vuuTableHeaderCell[aria-colindex='${colIdx}']`;\n\nexport const dataCellQuery = (ariaRowIdx: number, ariaColIdx: number) =>\n `.vuuTable-table [aria-rowindex='${ariaRowIdx}'] > [aria-colindex='${ariaColIdx}']`;\n\nexport const getLevelUp = (\n containerRef: RefObject<HTMLElement>,\n cellPos: CellPos,\n): CellPos => {\n const cell = getTableCell(containerRef, cellPos);\n let row = cell?.parentElement;\n const level = parseInt(row?.ariaLevel ?? \"1\");\n if (level > 1) {\n const targetLevel = `${level - 1}`;\n while (row !== null && row.ariaLevel !== targetLevel) {\n row = row.previousElementSibling as HTMLElement;\n }\n if (row) {\n const nextRowIndex = parseInt(row.ariaRowIndex ?? \"- 1\");\n if (nextRowIndex !== -1) {\n return [nextRowIndex - 1, 0];\n }\n }\n }\n return cellPos;\n};\nexport const getTableCell = (\n containerRef: RefObject<HTMLElement>,\n [rowIdx, colIdx]: CellPos,\n) => {\n const cssQuery = dataCellQuery(rowIdx, colIdx);\n const cell = containerRef.current?.querySelector(cssQuery) as HTMLDivElement;\n\n if (cellIsEditable(cell)) {\n // Dropdown gets focus, Input does not\n const focusableContent = cell.querySelector(\"button\") as HTMLElement;\n return focusableContent || cell;\n } else {\n return cell;\n }\n};\n\nexport 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\nexport const cellIsEditable = (cell: HTMLDivElement | null) =>\n cell?.classList.contains(\"vuuTableCell-editable\");\n\nexport const cellDropdownShowing = (cell: HTMLDivElement | null) => {\n if (cellIsEditable(cell)) {\n return cell?.querySelector('.saltDropdown[aria-expanded=\"true\"]') !== null;\n }\n return false;\n};\n\nconst cellIsGroupCell = (cell: HTMLElement | null) =>\n cell?.classList.contains(\"vuuTableGroupCell\");\n\nconst rowIsExpanded = (cell: HTMLElement) => {\n switch (cell.parentElement?.ariaExpanded) {\n case \"true\":\n return true;\n case \"false\":\n return false;\n default:\n return undefined;\n }\n};\n\nexport const cellIsTextInput = (cell: HTMLElement) =>\n cell.querySelector(\".vuuTableInputCell\") !== null;\n\nexport const getAriaRowIndex = (rowElement: HTMLElement | null) => {\n const rowIndex = rowElement?.ariaRowIndex;\n if (rowIndex != null) {\n const index = parseInt(rowIndex);\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getAriaColIndex = (cellElement: HTMLElement | null) => {\n const colIndex = cellElement?.ariaColIndex;\n if (colIndex != null) {\n const index = parseInt(colIndex);\n if (!isNaN(index)) {\n return index;\n }\n }\n return -1;\n};\n\nexport const getRowElementByAriaIndex = (\n container: HTMLDivElement | EventTarget,\n rowIndex: number,\n) => {\n if (rowIndex === -1) {\n return null;\n } else {\n const activeRow = (container as HTMLElement).querySelector(\n `[aria-rowindex=\"${rowIndex}\"]`,\n ) as HTMLElement;\n\n if (activeRow) {\n return activeRow;\n } else {\n throw Error(\n `getRowElementAtIndex no row found for index index ${rowIndex}`,\n );\n }\n }\n};\n\nexport const getIndexFromCellElement = (cellElement: HTMLElement | null) =>\n getAriaColIndex(cellElement);\n\nexport const getAriaCellPos = (tableCell: HTMLDivElement): CellPos => {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n return [getAriaRowIndex(focusedRow), getAriaColIndex(tableCell)];\n};\n\nconst closestRow = (el: HTMLElement) =>\n el.closest('[role=\"row\"]') as HTMLElement;\n\nexport const closestRowIndex = (el: HTMLElement) =>\n getAriaRowIndex(closestRow(el));\n\nexport function getNextCellPos(\n key: ArrowKey,\n [rowIdx, colIdx]: CellPos,\n columnCount: number,\n maxRowIndex: 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 [1, colIdx];\n } else if (rowIdx === maxRowIndex) {\n return [rowIdx, colIdx];\n } else {\n return [rowIdx + 1, colIdx];\n }\n } else if (key === \"ArrowRight\") {\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 type TreeNodeOperation = \"expand\" | \"collapse\" | \"level-up\";\n\nexport const getTreeNodeOperation = (\n containerRef: RefObject<HTMLElement>,\n navigationStyle: \"cell\" | \"tree\",\n cellPos: CellPos,\n key: NavigationKey,\n shiftKey: boolean,\n): TreeNodeOperation | undefined => {\n const cell = getTableCell(containerRef, cellPos);\n if (navigationStyle === \"cell\" && !cellIsGroupCell(cell)) {\n return undefined;\n }\n if (navigationStyle == \"cell\" && !shiftKey) {\n return undefined;\n }\n if (cellIsGroupCell(cell)) {\n const isExpanded = rowIsExpanded(cell);\n if (isExpanded === true) {\n if (key === \"ArrowLeft\") {\n return \"collapse\";\n }\n } else if (isExpanded === false) {\n if (key === \"ArrowRight\") {\n return \"expand\";\n } else if (key === \"ArrowLeft\") {\n return \"level-up\";\n }\n } else if (key === \"ArrowLeft\") {\n return \"level-up\";\n }\n }\n};\n\nconst NO_SCROLL_NECESSARY = [undefined, undefined] as const;\n\nexport const howFarIsRowOutsideViewport = (\n rowEl: HTMLElement,\n totalHeaderHeight: number,\n contentContainer = rowEl.closest(\".vuuTable-contentContainer\"),\n): readonly [ScrollDirection | undefined, number | undefined] => {\n //TODO lots of scope for optimisation here\n if (contentContainer) {\n // TODO take totalHeaderHeight into consideration\n const viewport = contentContainer?.getBoundingClientRect();\n const upperBoundary = viewport.top + totalHeaderHeight;\n const row = rowEl.getBoundingClientRect();\n if (row) {\n if (row.bottom > viewport.bottom) {\n return [\"down\", row.bottom - viewport.bottom];\n } else if (row.top < upperBoundary) {\n return [\"up\", row.top - upperBoundary];\n } else {\n return NO_SCROLL_NECESSARY;\n }\n } else {\n throw Error(\"Whats going on, row not found\");\n }\n } else {\n throw Error(\"Whats going on, scrollbar container not found\");\n }\n};\n"],"names":[],"mappings":"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"}
package/cjs/useCell.js CHANGED
@@ -7,12 +7,11 @@ var react = require('react');
7
7
  const useCell = (column, classBase, isHeader) => (
8
8
  // TODO measure perf without the memo, might not be worth the cost
9
9
  react.useMemo(() => {
10
- const className = cx(classBase, {
10
+ const className = cx(classBase, column.className, {
11
11
  vuuPinFloating: column.pin === "floating",
12
12
  vuuPinLeft: column.pin === "left",
13
13
  vuuPinRight: column.pin === "right",
14
14
  vuuEndPin: isHeader && column.endPin,
15
- // [`${classBase}-resizing`]: column.resizing,
16
15
  [`${classBase}-editable`]: column.editable,
17
16
  [`${classBase}-right`]: column.align === "right"
18
17
  });
@@ -1 +1 @@
1
- {"version":3,"file":"useCell.js","sources":["../src/useCell.ts"],"sourcesContent":["import { RuntimeColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { getColumnStyle } from \"@vuu-ui/vuu-utils\";\nimport cx from \"clsx\";\nimport { useMemo } from \"react\";\n\nexport const useCell = (\n column: RuntimeColumnDescriptor,\n classBase: string,\n isHeader?: boolean,\n) =>\n // TODO measure perf without the memo, might not be worth the cost\n useMemo(() => {\n const className = cx(classBase, {\n vuuPinFloating: column.pin === \"floating\",\n vuuPinLeft: column.pin === \"left\",\n vuuPinRight: column.pin === \"right\",\n vuuEndPin: isHeader && column.endPin,\n // [`${classBase}-resizing`]: column.resizing,\n [`${classBase}-editable`]: column.editable,\n [`${classBase}-right`]: column.align === \"right\",\n });\n\n const style = getColumnStyle(column);\n return {\n className,\n style,\n };\n }, [column, classBase, isHeader]);\n"],"names":["useMemo","getColumnStyle"],"mappings":";;;;;;AAKa,MAAA,OAAA,GAAU,CACrB,MAAA,EACA,SACA,EAAA,QAAA;AAAA;AAAA,EAGAA,cAAQ,MAAM;AACZ,IAAM,MAAA,SAAA,GAAY,GAAG,SAAW,EAAA;AAAA,MAC9B,cAAA,EAAgB,OAAO,GAAQ,KAAA,UAAA;AAAA,MAC/B,UAAA,EAAY,OAAO,GAAQ,KAAA,MAAA;AAAA,MAC3B,WAAA,EAAa,OAAO,GAAQ,KAAA,OAAA;AAAA,MAC5B,SAAA,EAAW,YAAY,MAAO,CAAA,MAAA;AAAA;AAAA,MAE9B,CAAC,CAAA,EAAG,SAAS,CAAA,SAAA,CAAW,GAAG,MAAO,CAAA,QAAA;AAAA,MAClC,CAAC,CAAG,EAAA,SAAS,CAAQ,MAAA,CAAA,GAAG,OAAO,KAAU,KAAA,OAAA;AAAA,KAC1C,CAAA,CAAA;AAED,IAAM,MAAA,KAAA,GAAQC,wBAAe,MAAM,CAAA,CAAA;AACnC,IAAO,OAAA;AAAA,MACL,SAAA;AAAA,MACA,KAAA;AAAA,KACF,CAAA;AAAA,GACC,EAAA,CAAC,MAAQ,EAAA,SAAA,EAAW,QAAQ,CAAC,CAAA;AAAA;;;;"}
1
+ {"version":3,"file":"useCell.js","sources":["../src/useCell.ts"],"sourcesContent":["import { RuntimeColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { getColumnStyle } from \"@vuu-ui/vuu-utils\";\nimport cx from \"clsx\";\nimport { useMemo } from \"react\";\n\nexport const useCell = (\n column: RuntimeColumnDescriptor,\n classBase: string,\n isHeader?: boolean,\n) =>\n // TODO measure perf without the memo, might not be worth the cost\n useMemo(() => {\n const className = cx(classBase, column.className, {\n vuuPinFloating: column.pin === \"floating\",\n vuuPinLeft: column.pin === \"left\",\n vuuPinRight: column.pin === \"right\",\n vuuEndPin: isHeader && column.endPin,\n [`${classBase}-editable`]: column.editable,\n [`${classBase}-right`]: column.align === \"right\",\n });\n\n const style = getColumnStyle(column);\n return {\n className,\n style,\n };\n }, [column, classBase, isHeader]);\n"],"names":["useMemo","getColumnStyle"],"mappings":";;;;;;AAKa,MAAA,OAAA,GAAU,CACrB,MAAA,EACA,SACA,EAAA,QAAA;AAAA;AAAA,EAGAA,cAAQ,MAAM;AACZ,IAAA,MAAM,SAAY,GAAA,EAAA,CAAG,SAAW,EAAA,MAAA,CAAO,SAAW,EAAA;AAAA,MAChD,cAAA,EAAgB,OAAO,GAAQ,KAAA,UAAA;AAAA,MAC/B,UAAA,EAAY,OAAO,GAAQ,KAAA,MAAA;AAAA,MAC3B,WAAA,EAAa,OAAO,GAAQ,KAAA,OAAA;AAAA,MAC5B,SAAA,EAAW,YAAY,MAAO,CAAA,MAAA;AAAA,MAC9B,CAAC,CAAA,EAAG,SAAS,CAAA,SAAA,CAAW,GAAG,MAAO,CAAA,QAAA;AAAA,MAClC,CAAC,CAAG,EAAA,SAAS,CAAQ,MAAA,CAAA,GAAG,OAAO,KAAU,KAAA,OAAA;AAAA,KAC1C,CAAA,CAAA;AAED,IAAM,MAAA,KAAA,GAAQC,wBAAe,MAAM,CAAA,CAAA;AACnC,IAAO,OAAA;AAAA,MACL,SAAA;AAAA,MACA,KAAA;AAAA,KACF,CAAA;AAAA,GACC,EAAA,CAAC,MAAQ,EAAA,SAAA,EAAW,QAAQ,CAAC,CAAA;AAAA;;;;"}
@@ -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,7 +29,7 @@ const isNavigationKey = (key, navigationStyle) => {
26
29
  return false;
27
30
  }
28
31
  };
29
- const focusColumnMenuIfAppropriate = (e, el) => {
32
+ const focusControlWithinCell = (e, el) => {
30
33
  if (e.shiftKey && e.key.match(/Arrow(Left|Right)/)) {
31
34
  if (el?.classList.contains("vuuTableHeaderCell")) {
32
35
  const menuButton = el?.querySelector(".vuuColumnMenu");
@@ -34,6 +37,30 @@ const focusColumnMenuIfAppropriate = (e, el) => {
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;
@@ -52,6 +79,7 @@ const useKeyboardNavigation = ({
52
79
  navigationStyle,
53
80
  requestScroll,
54
81
  onHighlight,
82
+ onToggleGroup,
55
83
  rowCount = 0,
56
84
  viewportRowCount
57
85
  }) => {
@@ -67,18 +95,10 @@ const useKeyboardNavigation = ({
67
95
  (idx) => {
68
96
  onHighlight?.(idx);
69
97
  setHighlightedIdx(idx);
98
+ highlightedIndexRef.current = idx;
70
99
  },
71
100
  [onHighlight, setHighlightedIdx]
72
101
  );
73
- const getFocusedCell = (el) => {
74
- if (el?.role == "cell" || el?.role === "columnheader") {
75
- return el;
76
- } else {
77
- return el?.closest(
78
- "[role='columnHeader'],[role='cell']"
79
- );
80
- }
81
- };
82
102
  const setActiveCell = react.useCallback(
83
103
  (rowIdx, colIdx, fromKeyboard = false) => {
84
104
  const pos = [rowIdx, colIdx];
@@ -137,10 +157,9 @@ const useKeyboardNavigation = ({
137
157
  const handleFocus = react.useCallback(() => {
138
158
  if (disableHighlightOnFocus !== true) {
139
159
  if (containerRef.current?.contains(document.activeElement)) {
140
- const focusedCell = getFocusedCell(document.activeElement);
160
+ const focusedCell = tableDomUtils.getFocusedCell(document.activeElement);
141
161
  if (focusedCell) {
142
162
  cellFocusStateRef.current.cellPos = tableDomUtils.getAriaCellPos(focusedCell);
143
- console.log({ pos: cellFocusStateRef.current.cellPos });
144
163
  if (navigationStyle === "row") {
145
164
  setHighlightedIdx(cellFocusStateRef.current.cellPos[0]);
146
165
  }
@@ -155,22 +174,48 @@ const useKeyboardNavigation = ({
155
174
  setHighlightedIdx
156
175
  ]);
157
176
  const navigateChildItems = react.useCallback(
158
- async (key) => {
159
- const {
160
- current: { cellPos }
161
- } = cellFocusStateRef;
162
- const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, cellPos) : tableDomUtils.getNextCellPos(key, cellPos, columnCount, maxRowIndex);
177
+ async (navigationStyle2 = "cell", key, shiftKey = false) => {
178
+ const { cellPos } = cellFocusStateRef.current;
163
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
+ }
164
204
  if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {
165
205
  setActiveCell(nextRowIdx, nextColIdx, true);
206
+ setHighlightedIndex(nextRowIdx);
166
207
  }
167
208
  },
168
209
  [
169
210
  cellFocusStateRef,
170
- columnCount,
171
211
  nextPageItemIdx,
212
+ containerRef,
213
+ onToggleGroup,
214
+ headerCount,
215
+ columnCount,
172
216
  maxRowIndex,
173
- setActiveCell
217
+ setActiveCell,
218
+ setHighlightedIndex
174
219
  ]
175
220
  );
176
221
  const scrollRowIntoViewIfNecessary = react.useCallback(
@@ -182,7 +227,7 @@ const useKeyboardNavigation = ({
182
227
  const moveHighlightedRow = react.useCallback(
183
228
  async (key) => {
184
229
  const { current: highlighted } = highlightedIndexRef;
185
- 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);
186
231
  if (nextRowIdx !== highlighted) {
187
232
  setHighlightedIndex(nextRowIdx);
188
233
  scrollRowIntoViewIfNecessary(nextRowIdx);
@@ -190,8 +235,8 @@ const useKeyboardNavigation = ({
190
235
  },
191
236
  [
192
237
  columnCount,
238
+ maxRowIndex,
193
239
  nextPageItemIdx,
194
- rowCount,
195
240
  scrollRowIntoViewIfNecessary,
196
241
  setHighlightedIndex
197
242
  ]
@@ -207,7 +252,7 @@ const useKeyboardNavigation = ({
207
252
  (e) => {
208
253
  const cell = vuuUtils.queryClosest(
209
254
  e.target,
210
- ".vuuTableCell,.vuuColumnMenu,.vuuTableHeaderCell"
255
+ `${CellLocator},${CellControlLocator}`
211
256
  );
212
257
  if (tableDomUtils.cellDropdownShowing(cell)) {
213
258
  return;
@@ -217,9 +262,9 @@ const useKeyboardNavigation = ({
217
262
  e.stopPropagation();
218
263
  if (navigationStyle === "row") {
219
264
  moveHighlightedRow(e.key);
220
- } else {
221
- if (!focusColumnMenuIfAppropriate(e, cell)) {
222
- navigateChildItems(e.key);
265
+ } else if (navigationStyle !== "none") {
266
+ if (!focusControlWithinCell(e, cell)) {
267
+ navigateChildItems(navigationStyle, e.key, e.shiftKey);
223
268
  }
224
269
  }
225
270
  }
@@ -229,8 +274,8 @@ const useKeyboardNavigation = ({
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
280
  const [rowIdx, colIdx] = tableDomUtils.getAriaCellPos(focusedCell);
236
281
  setActiveCell(rowIdx, colIdx);
@@ -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 getNextCellPos,\n getAriaCellPos,\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 el: HTMLElement | null,\n) => {\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 }\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 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 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 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 },\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 = 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 console.log({ pos: cellFocusStateRef.current.cellPos });\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, maxRowIndex);\n\n const [rowIdx, colIdx] = cellPos;\n if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {\n setActiveCell(nextRowIdx, nextColIdx, true);\n }\n },\n [\n cellFocusStateRef,\n columnCount,\n nextPageItemIdx,\n maxRowIndex,\n setActiveCell,\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, 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 if (!focusColumnMenuIfAppropriate(e, cell)) {\n navigateChildItems(e.key);\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 = evt.target as HTMLElement;\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 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","getAriaCellPos","getNextCellPos","useEffect","queryClosest","cellDropdownShowing","closestRowIndex"],"mappings":";;;;;;;AAwBA,MAAM,iBAAA,uBAAwB,GAAmB,CAAA;AAAA,EAC/C,MAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,SAAA;AACF,CAAC,CAAA,CAAA;AAED,MAAM,kBAAA,GAAqB,IAAI,GAAA,CAAI,iBAAiB,CAAA,CAAA;AACpD,kBAAA,CAAmB,IAAI,WAAW,CAAA,CAAA;AAClC,kBAAA,CAAmB,IAAI,YAAY,CAAA,CAAA;AAEtB,MAAA,eAAA,GAAkB,CAC7B,GAAA,EACA,eACyB,KAAA;AACzB,EAAA,QAAQ,eAAiB;AAAA,IACvB,KAAK,MAAA;AACH,MAAO,OAAA,kBAAA,CAAmB,IAAI,GAAoB,CAAA,CAAA;AAAA,IACpD,KAAK,KAAA;AACH,MAAO,OAAA,iBAAA,CAAkB,IAAI,GAAoB,CAAA,CAAA;AAAA,IACnD;AACE,MAAO,OAAA,KAAA,CAAA;AAAA,GACX;AACF,EAAA;AAEA,MAAM,4BAAA,GAA+B,CACnC,CAAA,EACA,EACG,KAAA;AACH,EAAA,IAAI,EAAE,QAAY,IAAA,CAAA,CAAE,GAAI,CAAA,KAAA,CAAM,mBAAmB,CAAG,EAAA;AAClD,IAAA,IAAI,EAAI,EAAA,SAAA,CAAU,QAAS,CAAA,oBAAoB,CAAG,EAAA;AAChD,MAAM,MAAA,UAAA,GAAa,EAAI,EAAA,aAAA,CAAiC,gBAAgB,CAAA,CAAA;AACxE,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,UAAA,CAAW,KAAM,EAAA,CAAA;AACjB,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,KACF;AAAA,GACF;AACA,EAAO,OAAA,KAAA,CAAA;AACT,CAAA,CAAA;AAEA,MAAM,QAAW,GAAA,CAAC,MAAQ,EAAA,KAAA,EAAO,UAAU,UAAU,CAAA,CAAA;AAC9C,MAAM,WAAc,GAAA,CAAC,GAC1B,KAAA,QAAA,CAAS,SAAS,GAAG,EAAA;AAuBhB,MAAM,wBAAwB,CAAC;AAAA,EACpC,iBAAA;AAAA,EACA,WAAc,GAAA,CAAA;AAAA,EACd,YAAA;AAAA,EACA,uBAAA;AAAA,EACA,uBAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAkB,EAAA,oBAAA;AAAA,EAClB,eAAA;AAAA,EACA,aAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAW,GAAA,CAAA;AAAA,EACX,gBAAA;AACF,CAA2B,KAAA;AAKzB,EAAA,MAAM,sBAAsBA,YAA2B,EAAA,CAAA;AAEvD,EAAA,MAAM,CAAC,gBAAA,EAAkB,iBAAiB,CAAA,GAAIC,kBAAc,CAAA;AAAA,IAC1D,UAAY,EAAA,oBAAA;AAAA,IACZ,OAAS,EAAA,uBAAA;AAAA,IACT,IAAM,EAAA,uBAAA;AAAA,GACP,CAAA,CAAA;AACD,EAAA,mBAAA,CAAoB,OAAU,GAAA,gBAAA,CAAA;AAG9B,EAAA,MAAM,cAAc,QAAW,GAAA,WAAA,CAAA;AAE/B,EAAA,MAAM,mBAAsB,GAAAC,iBAAA;AAAA,IAC1B,CAAC,GAAgB,KAAA;AACf,MAAA,WAAA,GAAc,GAAG,CAAA,CAAA;AACjB,MAAA,iBAAA,CAAkB,GAAG,CAAA,CAAA;AAAA,KACvB;AAAA,IACA,CAAC,aAAa,iBAAiB,CAAA;AAAA,GACjC,CAAA;AAEA,EAAM,MAAA,cAAA,GAAiB,CAAC,EAAqC,KAAA;AAC3D,IAAA,IAAI,EAAI,EAAA,IAAA,IAAQ,MAAU,IAAA,EAAA,EAAI,SAAS,cAAgB,EAAA;AACrD,MAAO,OAAA,EAAA,CAAA;AAAA,KACF,MAAA;AACL,MAAA,OAAO,EAAI,EAAA,OAAA;AAAA,QACT,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAA,MAAM,aAAgB,GAAAA,iBAAA;AAAA,IACpB,CAAC,MAAA,EAAgB,MAAgB,EAAA,YAAA,GAAe,KAAU,KAAA;AACxD,MAAM,MAAA,GAAA,GAAe,CAAC,MAAA,EAAQ,MAAM,CAAA,CAAA;AACpC,MAAA,IAAI,oBAAoB,KAAO,EAAA;AAC7B,QAAA,iBAAA,CAAkB,MAAM,CAAA,CAAA;AAAA,OACnB,MAAA;AACL,QAAA,SAAA,CAAU,KAAK,YAAY,CAAA,CAAA;AAAA,OAC7B;AAAA,KACF;AAAA,IACA,CAAC,SAAW,EAAA,eAAA,EAAiB,iBAAiB,CAAA;AAAA,GAChD,CAAA;AAEA,EAAA,MAAM,eAAkB,GAAAA,iBAAA;AAAA,IACtB,CACE,KACA,CAAC,MAAA,EAAQ,MAAM,CAEf,KAAA,IAAI,OAAQ,CAAA,CAAC,OAAY,KAAA;AACvB,MAAA,IAAI,SAAY,GAAA,MAAA,CAAA;AAChB,MAAM,MAAA,EAAE,OAAS,EAAA,UAAA,EAAe,GAAA,iBAAA,CAAA;AAChC,MAAA,QAAQ,GAAK;AAAA,QACX,KAAK,UAAY,EAAA;AACf,UAAA,SAAA,GAAY,IAAK,CAAA,GAAA,CAAI,QAAW,GAAA,CAAA,EAAG,SAAS,gBAAgB,CAAA,CAAA;AAC5D,UAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,YAAW,UAAA,CAAA,OAAA,GAAU,CAAC,SAAA,EAAW,MAAM,CAAA,CAAA;AACvC,YAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,aAAe,EAAA,SAAA,EAAW,QAAQ,CAAA,CAAA;AAAA,WAC5D;AACA,UAAA,MAAA;AAAA,SACF;AAAA,QACA,KAAK,QAAU,EAAA;AACb,UAAA,SAAA,GAAY,IAAK,CAAA,GAAA,CAAI,CAAG,EAAA,MAAA,GAAS,gBAAgB,CAAA,CAAA;AACjD,UAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,YAAW,UAAA,CAAA,OAAA,GAAU,CAAC,SAAA,EAAW,MAAM,CAAA,CAAA;AACvC,YAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,aAAe,EAAA,SAAA,EAAW,MAAM,CAAA,CAAA;AAAA,WAC1D;AACA,UAAA,MAAA;AAAA,SACF;AAAA,QACA,KAAK,MAAQ,EAAA;AACX,UAAA,SAAA,GAAY,WAAc,GAAA,CAAA,CAAA;AAC1B,UAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,YAAW,UAAA,CAAA,OAAA,GAAU,CAAC,SAAA,EAAW,MAAM,CAAA,CAAA;AACvC,YAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,YAAc,EAAA,SAAA,EAAW,QAAQ,CAAA,CAAA;AAAA,WAC3D;AACA,UAAA,MAAA;AAAA,SACF;AAAA,QACA,KAAK,KAAO,EAAA;AACV,UAAA,SAAA,GAAY,QAAW,GAAA,WAAA,CAAA;AACvB,UAAA,IAAI,cAAc,MAAQ,EAAA;AACxB,YAAW,UAAA,CAAA,OAAA,GAAU,CAAC,SAAA,EAAW,MAAM,CAAA,CAAA;AACvC,YAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,YAAc,EAAA,SAAA,EAAW,OAAO,CAAA,CAAA;AAAA,WAC1D;AACA,UAAA,MAAA;AAAA,SACF;AAAA,OACF;AAWA,MAAA,UAAA,CAAW,MAAM;AACf,QAAQ,OAAA,CAAA,CAAC,SAAW,EAAA,MAAM,CAAC,CAAA,CAAA;AAAA,SAC1B,EAAE,CAAA,CAAA;AAAA,KACN,CAAA;AAAA,IACH,CAAC,iBAAA,EAAmB,WAAa,EAAA,aAAA,EAAe,UAAU,gBAAgB,CAAA;AAAA,GAC5E,CAAA;AAEA,EAAM,MAAA,WAAA,GAAcA,kBAAY,MAAM;AACpC,IAAA,IAAI,4BAA4B,IAAM,EAAA;AACpC,MAAA,IAAI,YAAa,CAAA,OAAA,EAAS,QAAS,CAAA,QAAA,CAAS,aAAa,CAAG,EAAA;AAK1D,QAAM,MAAA,WAAA,GAAc,cAAe,CAAA,QAAA,CAAS,aAAa,CAAA,CAAA;AACzD,QAAA,IAAI,WAAa,EAAA;AACf,UAAkB,iBAAA,CAAA,OAAA,CAAQ,OAAU,GAAAC,4BAAA,CAAe,WAAW,CAAA,CAAA;AAC9D,UAAA,OAAA,CAAQ,IAAI,EAAE,GAAA,EAAK,iBAAkB,CAAA,OAAA,CAAQ,SAAS,CAAA,CAAA;AACtD,UAAA,IAAI,oBAAoB,KAAO,EAAA;AAC7B,YAAA,iBAAA,CAAkB,iBAAkB,CAAA,OAAA,CAAQ,OAAQ,CAAA,CAAC,CAAC,CAAA,CAAA;AAAA,WACxD;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,GACC,EAAA;AAAA,IACD,uBAAA;AAAA,IACA,YAAA;AAAA,IACA,iBAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA;AAAA,GACD,CAAA,CAAA;AAED,EAAA,MAAM,kBAAqB,GAAAD,iBAAA;AAAA,IACzB,OAAO,GAAuB,KAAA;AAC5B,MAAM,MAAA;AAAA,QACJ,OAAA,EAAS,EAAE,OAAQ,EAAA;AAAA,OACjB,GAAA,iBAAA,CAAA;AACJ,MAAA,MAAM,CAAC,UAAY,EAAA,UAAU,CAAI,GAAA,WAAA,CAAY,GAAG,CAC5C,GAAA,MAAM,eAAgB,CAAA,GAAA,EAAK,OAAO,CAClC,GAAAE,4BAAA,CAAe,GAAK,EAAA,OAAA,EAAS,aAAa,WAAW,CAAA,CAAA;AAEzD,MAAM,MAAA,CAAC,MAAQ,EAAA,MAAM,CAAI,GAAA,OAAA,CAAA;AACzB,MAAI,IAAA,UAAA,KAAe,MAAU,IAAA,UAAA,KAAe,MAAQ,EAAA;AAClD,QAAc,aAAA,CAAA,UAAA,EAAY,YAAY,IAAI,CAAA,CAAA;AAAA,OAC5C;AAAA,KACF;AAAA,IACA;AAAA,MACE,iBAAA;AAAA,MACA,WAAA;AAAA,MACA,eAAA;AAAA,MACA,WAAA;AAAA,MACA,aAAA;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAA,MAAM,4BAA+B,GAAAF,iBAAA;AAAA,IACnC,CAAC,QAAqB,KAAA;AACpB,MAAA,aAAA,GAAgB,EAAE,IAAA,EAAM,YAAc,EAAA,QAAA,EAAU,CAAA,CAAA;AAAA,KAClD;AAAA,IACA,CAAC,aAAa,CAAA;AAAA,GAChB,CAAA;AAEA,EAAA,MAAM,kBAAqB,GAAAA,iBAAA;AAAA,IACzB,OAAO,GAAuB,KAAA;AAC5B,MAAM,MAAA,EAAE,OAAS,EAAA,WAAA,EAAgB,GAAA,mBAAA,CAAA;AACjC,MAAM,MAAA,CAAC,UAAU,CAAI,GAAA,WAAA,CAAY,GAAG,CAChC,GAAA,MAAM,eAAgB,CAAA,GAAA,EAAK,CAAC,WAAA,IAAe,IAAI,CAAC,CAAC,CACjD,GAAAE,4BAAA,CAAe,GAAK,EAAA,CAAC,eAAe,CAAI,CAAA,EAAA,CAAC,CAAG,EAAA,WAAA,EAAa,QAAQ,CAAA,CAAA;AACrE,MAAA,IAAI,eAAe,WAAa,EAAA;AAC9B,QAAA,mBAAA,CAAoB,UAAU,CAAA,CAAA;AAE9B,QAAA,4BAAA,CAA6B,UAAU,CAAA,CAAA;AAAA,OACzC;AAAA,KACF;AAAA,IACA;AAAA,MACE,WAAA;AAAA,MACA,eAAA;AAAA,MACA,QAAA;AAAA,MACA,4BAAA;AAAA,MACA,mBAAA;AAAA,KACF;AAAA,GACF,CAAA;AAEA,EAAAC,eAAA,CAAU,MAAM;AACd,IAAI,IAAA,oBAAA,KAAyB,KAAa,CAAA,IAAA,oBAAA,KAAyB,CAAI,CAAA,EAAA;AACrE,MAAA,qBAAA,CAAsB,MAAM;AAE1B,QAAA,4BAAA,CAA6B,oBAAoB,CAAA,CAAA;AAAA,OAClD,CAAA,CAAA;AAAA,KACH;AAAA,GACC,EAAA,CAAC,oBAAsB,EAAA,4BAA4B,CAAC,CAAA,CAAA;AAEvD,EAAA,MAAM,aAAgB,GAAAH,iBAAA;AAAA,IACpB,CAAC,CAAqB,KAAA;AACpB,MAAA,MAAM,IAAO,GAAAI,qBAAA;AAAA,QACX,CAAE,CAAA,MAAA;AAAA,QACF,kDAAA;AAAA,OACF,CAAA;AACA,MAAI,IAAAC,iCAAA,CAAoB,IAAI,CAAG,EAAA;AAC7B,QAAA,OAAA;AAAA,OACF;AACA,MAAA,IAAI,WAAW,CAAK,IAAA,eAAA,CAAgB,CAAE,CAAA,GAAA,EAAK,eAAe,CAAG,EAAA;AAC3D,QAAA,CAAA,CAAE,cAAe,EAAA,CAAA;AACjB,QAAA,CAAA,CAAE,eAAgB,EAAA,CAAA;AAClB,QAAA,IAAI,oBAAoB,KAAO,EAAA;AAC7B,UAAA,kBAAA,CAAmB,EAAE,GAAG,CAAA,CAAA;AAAA,SACnB,MAAA;AACL,UAAA,IAAI,CAAC,4BAAA,CAA6B,CAAG,EAAA,IAAI,CAAG,EAAA;AAC1C,YAAA,kBAAA,CAAmB,EAAE,GAAG,CAAA,CAAA;AAAA,WAC1B;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,QAAA,EAAU,eAAiB,EAAA,kBAAA,EAAoB,kBAAkB,CAAA;AAAA,GACpE,CAAA;AAEA,EAAA,MAAM,WAAc,GAAAL,iBAAA;AAAA;AAAA,IAElB,CAAC,GAAoB,KAAA;AACnB,MAAA,MAAM,SAAS,GAAI,CAAA,MAAA,CAAA;AACnB,MAAM,MAAA,WAAA,GAAc,eAAe,MAAM,CAAA,CAAA;AACzC,MAAA,IAAI,WAAa,EAAA;AACf,QAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAIC,6BAAe,WAAW,CAAA,CAAA;AACnD,QAAA,aAAA,CAAc,QAAQ,MAAM,CAAA,CAAA;AAAA,OAC9B;AAAA,KACF;AAAA,IACA,CAAC,aAAa,CAAA;AAAA,GAChB,CAAA;AAEA,EAAM,MAAA,gBAAA,GAAmBD,kBAAY,MAAM;AACzC,IAAA,mBAAA,CAAoB,CAAE,CAAA,CAAA,CAAA;AAAA,GACxB,EAAG,CAAC,mBAAmB,CAAC,CAAA,CAAA;AAExB,EAAA,MAAM,eAAkB,GAAAA,iBAAA;AAAA,IACtB,CAAC,GAAoB,KAAA;AACnB,MAAM,MAAA,GAAA,GAAMM,6BAAgB,CAAA,GAAA,CAAI,MAAqB,CAAA,CAAA;AACrD,MAAA,IAAI,GAAQ,KAAA,CAAA,CAAA,IAAM,GAAQ,KAAA,mBAAA,CAAoB,OAAS,EAAA;AACrD,QAAA,mBAAA,CAAoB,GAAG,CAAA,CAAA;AAAA,OACzB;AAAA,KACF;AAAA,IACA,CAAC,mBAAmB,CAAA;AAAA,GACtB,CAAA;AAEA,EAAM,MAAA,QAAA,GAAWN,kBAAY,MAAM;AACjC,IAAA,kBAAA,CAAmB,WAAW,CAAA,CAAA;AAAA,GAChC,EAAG,CAAC,kBAAkB,CAAC,CAAA,CAAA;AAEvB,EAAO,OAAA;AAAA,IACL,mBAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAS,EAAA,WAAA;AAAA,IACT,OAAS,EAAA,WAAA;AAAA,IACT,SAAW,EAAA,aAAA;AAAA,IACX,YAAA,EAAc,eAAoB,KAAA,KAAA,GAAQ,gBAAmB,GAAA,KAAA,CAAA;AAAA,IAC7D,WAAA,EAAa,eAAoB,KAAA,KAAA,GAAQ,eAAkB,GAAA,KAAA,CAAA;AAAA,GAC7D,CAAA;AACF;;;;;;"}
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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"}