@vuu-ui/vuu-table 0.8.32 → 0.8.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/cjs/Row.css +115 -0
  2. package/cjs/Row.js +115 -0
  3. package/cjs/Row.js.map +1 -0
  4. package/cjs/Table.css +151 -0
  5. package/cjs/Table.js +276 -0
  6. package/cjs/Table.js.map +1 -0
  7. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.css +5 -0
  8. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.js +33 -0
  9. package/cjs/cell-renderers/checkbox-cell/CheckboxCell.js.map +1 -0
  10. package/cjs/cell-renderers/input-cell/InputCell.css +31 -0
  11. package/cjs/cell-renderers/input-cell/InputCell.js +49 -0
  12. package/cjs/cell-renderers/input-cell/InputCell.js.map +1 -0
  13. package/cjs/cell-renderers/toggle-cell/ToggleCell.css +32 -0
  14. package/cjs/cell-renderers/toggle-cell/ToggleCell.js +59 -0
  15. package/cjs/cell-renderers/toggle-cell/ToggleCell.js.map +1 -0
  16. package/cjs/column-header-pill/ColumnHeaderPill.css +30 -0
  17. package/cjs/column-header-pill/ColumnHeaderPill.js +44 -0
  18. package/cjs/column-header-pill/ColumnHeaderPill.js.map +1 -0
  19. package/cjs/column-header-pill/GroupColumnPill.css +7 -0
  20. package/cjs/column-header-pill/GroupColumnPill.js +20 -0
  21. package/cjs/column-header-pill/GroupColumnPill.js.map +1 -0
  22. package/cjs/column-header-pill/SortIndicator.css +7 -0
  23. package/cjs/column-header-pill/SortIndicator.js +18 -0
  24. package/cjs/column-header-pill/SortIndicator.js.map +1 -0
  25. package/cjs/column-menu/ColumnMenu.css +21 -0
  26. package/cjs/column-menu/ColumnMenu.js +21 -0
  27. package/cjs/column-menu/ColumnMenu.js.map +1 -0
  28. package/cjs/column-resizing/ColumnResizer.css +28 -0
  29. package/cjs/column-resizing/ColumnResizer.js +63 -0
  30. package/cjs/column-resizing/ColumnResizer.js.map +1 -0
  31. package/cjs/column-resizing/useTableColumnResize.js +55 -0
  32. package/cjs/column-resizing/useTableColumnResize.js.map +1 -0
  33. package/cjs/context-menu/buildContextMenuDescriptors.js +214 -0
  34. package/cjs/context-menu/buildContextMenuDescriptors.js.map +1 -0
  35. package/cjs/context-menu/useHandleTableContextMenu.js +81 -0
  36. package/cjs/context-menu/useHandleTableContextMenu.js.map +1 -0
  37. package/cjs/header-cell/GroupHeaderCell.css +65 -0
  38. package/cjs/header-cell/GroupHeaderCell.js +108 -0
  39. package/cjs/header-cell/GroupHeaderCell.js.map +1 -0
  40. package/cjs/header-cell/HeaderCell.css +146 -0
  41. package/cjs/header-cell/HeaderCell.js +100 -0
  42. package/cjs/header-cell/HeaderCell.js.map +1 -0
  43. package/cjs/index.js +35 -1
  44. package/cjs/index.js.map +1 -7
  45. package/cjs/moving-window.js +61 -0
  46. package/cjs/moving-window.js.map +1 -0
  47. package/cjs/table-cell/TableCell.css +41 -0
  48. package/cjs/table-cell/TableCell.js +63 -0
  49. package/cjs/table-cell/TableCell.js.map +1 -0
  50. package/cjs/table-cell/TableGroupCell.css +26 -0
  51. package/cjs/table-cell/TableGroupCell.js +45 -0
  52. package/cjs/table-cell/TableGroupCell.js.map +1 -0
  53. package/cjs/table-config.js +25 -0
  54. package/cjs/table-config.js.map +1 -0
  55. package/cjs/table-dom-utils.js +60 -0
  56. package/cjs/table-dom-utils.js.map +1 -0
  57. package/cjs/table-header/TableHeader.js +87 -0
  58. package/cjs/table-header/TableHeader.js.map +1 -0
  59. package/cjs/table-header/useTableHeader.js +72 -0
  60. package/cjs/table-header/useTableHeader.js.map +1 -0
  61. package/cjs/useCell.js +28 -0
  62. package/cjs/useCell.js.map +1 -0
  63. package/cjs/useCellEditing.js +79 -0
  64. package/cjs/useCellEditing.js.map +1 -0
  65. package/cjs/useControlledTableNavigation.js +43 -0
  66. package/cjs/useControlledTableNavigation.js.map +1 -0
  67. package/cjs/useDataSource.js +104 -0
  68. package/cjs/useDataSource.js.map +1 -0
  69. package/cjs/useInitialValue.js +11 -0
  70. package/cjs/useInitialValue.js.map +1 -0
  71. package/cjs/useKeyboardNavigation.js +304 -0
  72. package/cjs/useKeyboardNavigation.js.map +1 -0
  73. package/cjs/useRowClassNameGenerators.js +34 -0
  74. package/cjs/useRowClassNameGenerators.js.map +1 -0
  75. package/cjs/useRowHeight.js +43 -0
  76. package/cjs/useRowHeight.js.map +1 -0
  77. package/cjs/useSelection.js +64 -0
  78. package/cjs/useSelection.js.map +1 -0
  79. package/cjs/useTable.js +553 -0
  80. package/cjs/useTable.js.map +1 -0
  81. package/cjs/useTableAndColumnSettings.js +128 -0
  82. package/cjs/useTableAndColumnSettings.js.map +1 -0
  83. package/cjs/useTableContextMenu.js +42 -0
  84. package/cjs/useTableContextMenu.js.map +1 -0
  85. package/cjs/useTableModel.js +297 -0
  86. package/cjs/useTableModel.js.map +1 -0
  87. package/cjs/useTableScroll.js +396 -0
  88. package/cjs/useTableScroll.js.map +1 -0
  89. package/cjs/useTableViewport.js +122 -0
  90. package/cjs/useTableViewport.js.map +1 -0
  91. package/esm/Row.css +115 -0
  92. package/esm/Row.js +112 -0
  93. package/esm/Row.js.map +1 -0
  94. package/esm/Table.css +151 -0
  95. package/esm/Table.js +274 -0
  96. package/esm/Table.js.map +1 -0
  97. package/esm/cell-renderers/checkbox-cell/CheckboxCell.css +5 -0
  98. package/esm/cell-renderers/checkbox-cell/CheckboxCell.js +31 -0
  99. package/esm/cell-renderers/checkbox-cell/CheckboxCell.js.map +1 -0
  100. package/esm/cell-renderers/input-cell/InputCell.css +31 -0
  101. package/esm/cell-renderers/input-cell/InputCell.js +47 -0
  102. package/esm/cell-renderers/input-cell/InputCell.js.map +1 -0
  103. package/esm/cell-renderers/toggle-cell/ToggleCell.css +32 -0
  104. package/esm/cell-renderers/toggle-cell/ToggleCell.js +57 -0
  105. package/esm/cell-renderers/toggle-cell/ToggleCell.js.map +1 -0
  106. package/esm/column-header-pill/ColumnHeaderPill.css +30 -0
  107. package/esm/column-header-pill/ColumnHeaderPill.js +42 -0
  108. package/esm/column-header-pill/ColumnHeaderPill.js.map +1 -0
  109. package/esm/column-header-pill/GroupColumnPill.css +7 -0
  110. package/esm/column-header-pill/GroupColumnPill.js +18 -0
  111. package/esm/column-header-pill/GroupColumnPill.js.map +1 -0
  112. package/esm/column-header-pill/SortIndicator.css +7 -0
  113. package/esm/column-header-pill/SortIndicator.js +16 -0
  114. package/esm/column-header-pill/SortIndicator.js.map +1 -0
  115. package/esm/column-menu/ColumnMenu.css +21 -0
  116. package/esm/column-menu/ColumnMenu.js +19 -0
  117. package/esm/column-menu/ColumnMenu.js.map +1 -0
  118. package/esm/column-resizing/ColumnResizer.css +28 -0
  119. package/esm/column-resizing/ColumnResizer.js +61 -0
  120. package/esm/column-resizing/ColumnResizer.js.map +1 -0
  121. package/esm/column-resizing/useTableColumnResize.js +53 -0
  122. package/esm/column-resizing/useTableColumnResize.js.map +1 -0
  123. package/esm/context-menu/buildContextMenuDescriptors.js +212 -0
  124. package/esm/context-menu/buildContextMenuDescriptors.js.map +1 -0
  125. package/esm/context-menu/useHandleTableContextMenu.js +79 -0
  126. package/esm/context-menu/useHandleTableContextMenu.js.map +1 -0
  127. package/esm/header-cell/GroupHeaderCell.css +65 -0
  128. package/esm/header-cell/GroupHeaderCell.js +106 -0
  129. package/esm/header-cell/GroupHeaderCell.js.map +1 -0
  130. package/esm/header-cell/HeaderCell.css +146 -0
  131. package/esm/header-cell/HeaderCell.js +98 -0
  132. package/esm/header-cell/HeaderCell.js.map +1 -0
  133. package/esm/index.js +13 -1
  134. package/esm/index.js.map +1 -7
  135. package/esm/moving-window.js +59 -0
  136. package/esm/moving-window.js.map +1 -0
  137. package/esm/table-cell/TableCell.css +41 -0
  138. package/esm/table-cell/TableCell.js +61 -0
  139. package/esm/table-cell/TableCell.js.map +1 -0
  140. package/esm/table-cell/TableGroupCell.css +26 -0
  141. package/esm/table-cell/TableGroupCell.js +43 -0
  142. package/esm/table-cell/TableGroupCell.js.map +1 -0
  143. package/esm/table-config.js +23 -0
  144. package/esm/table-config.js.map +1 -0
  145. package/esm/table-dom-utils.js +51 -0
  146. package/esm/table-dom-utils.js.map +1 -0
  147. package/esm/table-header/TableHeader.js +85 -0
  148. package/esm/table-header/TableHeader.js.map +1 -0
  149. package/esm/table-header/useTableHeader.js +70 -0
  150. package/esm/table-header/useTableHeader.js.map +1 -0
  151. package/esm/useCell.js +26 -0
  152. package/esm/useCell.js.map +1 -0
  153. package/esm/useCellEditing.js +77 -0
  154. package/esm/useCellEditing.js.map +1 -0
  155. package/esm/useControlledTableNavigation.js +41 -0
  156. package/esm/useControlledTableNavigation.js.map +1 -0
  157. package/esm/useDataSource.js +101 -0
  158. package/esm/useDataSource.js.map +1 -0
  159. package/esm/useInitialValue.js +9 -0
  160. package/esm/useInitialValue.js.map +1 -0
  161. package/esm/useKeyboardNavigation.js +300 -0
  162. package/esm/useKeyboardNavigation.js.map +1 -0
  163. package/esm/useRowClassNameGenerators.js +32 -0
  164. package/esm/useRowClassNameGenerators.js.map +1 -0
  165. package/esm/useRowHeight.js +41 -0
  166. package/esm/useRowHeight.js.map +1 -0
  167. package/esm/useSelection.js +62 -0
  168. package/esm/useSelection.js.map +1 -0
  169. package/esm/useTable.js +551 -0
  170. package/esm/useTable.js.map +1 -0
  171. package/esm/useTableAndColumnSettings.js +126 -0
  172. package/esm/useTableAndColumnSettings.js.map +1 -0
  173. package/esm/useTableContextMenu.js +40 -0
  174. package/esm/useTableContextMenu.js.map +1 -0
  175. package/esm/useTableModel.js +293 -0
  176. package/esm/useTableModel.js.map +1 -0
  177. package/esm/useTableScroll.js +393 -0
  178. package/esm/useTableScroll.js.map +1 -0
  179. package/esm/useTableViewport.js +120 -0
  180. package/esm/useTableViewport.js.map +1 -0
  181. package/package.json +12 -14
  182. package/LICENSE +0 -201
  183. package/index.css +0 -2
  184. package/index.css.map +0 -7
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var react = require('react');
5
+ var tableDomUtils = require('./table-dom-utils.js');
6
+
7
+ const useCellEditing = ({ navigate }) => {
8
+ const commitHandler = react.useCallback(() => {
9
+ navigate();
10
+ }, [navigate]);
11
+ const editInput = react.useCallback(
12
+ (evt) => {
13
+ const cellEl = evt.target;
14
+ const input = cellEl.matches("input") ? cellEl : cellEl.querySelector("input");
15
+ if (input) {
16
+ input.focus();
17
+ input.select();
18
+ }
19
+ },
20
+ []
21
+ );
22
+ const focusInput = react.useCallback(
23
+ (evt) => {
24
+ const cellEl = evt.target;
25
+ const input = cellEl.querySelector("input");
26
+ if (input) {
27
+ input.focus();
28
+ input.select();
29
+ }
30
+ },
31
+ []
32
+ );
33
+ const handleKeyDown = react.useCallback(
34
+ (e) => {
35
+ const el = e.target;
36
+ if (tableDomUtils.cellIsTextInput(el)) {
37
+ if (vuuUtils.isCharacterKey(e.key)) {
38
+ editInput(e);
39
+ } else if (e.key === "Enter") {
40
+ focusInput(e);
41
+ }
42
+ }
43
+ },
44
+ [editInput, focusInput]
45
+ );
46
+ const handleDoubleClick = react.useCallback(
47
+ (e) => {
48
+ const el = e.target;
49
+ if (el.matches("input") || el.querySelector("input")) {
50
+ editInput(e);
51
+ e.stopPropagation();
52
+ }
53
+ },
54
+ [editInput]
55
+ );
56
+ const handleBlur = react.useCallback(
57
+ (e) => {
58
+ const el = e.target;
59
+ el.removeEventListener("vuu-commit", commitHandler, true);
60
+ },
61
+ [commitHandler]
62
+ );
63
+ const handleFocus = react.useCallback(
64
+ (e) => {
65
+ const el = e.target;
66
+ el.addEventListener("vuu-commit", commitHandler, true);
67
+ },
68
+ [commitHandler]
69
+ );
70
+ return {
71
+ onBlur: handleBlur,
72
+ onDoubleClick: handleDoubleClick,
73
+ onFocus: handleFocus,
74
+ onKeyDown: handleKeyDown
75
+ };
76
+ };
77
+
78
+ exports.useCellEditing = useCellEditing;
79
+ //# sourceMappingURL=useCellEditing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCellEditing.js","sources":["../src/useCellEditing.ts"],"sourcesContent":["import { isCharacterKey } from \"@vuu-ui/vuu-utils\";\nimport {\n FocusEventHandler,\n KeyboardEvent as ReactKeyboardEvent,\n MouseEvent,\n useCallback,\n} from \"react\";\nimport { cellIsTextInput } from \"./table-dom-utils\";\n\nexport interface CellEditingHookProps {\n navigate: () => void;\n}\n\nexport const useCellEditing = ({ navigate }: CellEditingHookProps) => {\n const commitHandler = useCallback(() => {\n navigate();\n }, [navigate]);\n\n const editInput = useCallback(\n (evt: MouseEvent<HTMLElement> | ReactKeyboardEvent<HTMLElement>) => {\n const cellEl = evt.target as HTMLDivElement;\n const input = cellEl.matches(\"input\")\n ? (cellEl as HTMLInputElement)\n : cellEl.querySelector(\"input\");\n\n if (input) {\n input.focus();\n input.select();\n }\n },\n []\n );\n\n const focusInput = useCallback(\n (evt: MouseEvent<HTMLElement> | ReactKeyboardEvent<HTMLElement>) => {\n const cellEl = evt.target as HTMLDivElement;\n const input = cellEl.querySelector(\"input\");\n if (input) {\n input.focus();\n input.select();\n }\n },\n []\n );\n\n const handleKeyDown = useCallback(\n (e: ReactKeyboardEvent<HTMLElement>) => {\n const el = e.target as HTMLElement;\n if (cellIsTextInput(el)) {\n if (isCharacterKey(e.key)) {\n editInput(e);\n } else if (e.key === \"Enter\") {\n focusInput(e);\n }\n }\n },\n [editInput, focusInput]\n );\n\n const handleDoubleClick = useCallback(\n (e: MouseEvent<HTMLElement>) => {\n const el = e.target as HTMLElement;\n if (el.matches(\"input\") || el.querySelector(\"input\")) {\n editInput(e);\n e.stopPropagation();\n }\n },\n [editInput]\n );\n\n const handleBlur = useCallback<FocusEventHandler>(\n (e) => {\n const el = e.target as HTMLElement;\n el.removeEventListener(\"vuu-commit\", commitHandler, true);\n },\n [commitHandler]\n );\n\n const handleFocus = useCallback<FocusEventHandler>(\n (e) => {\n const el = e.target as HTMLElement;\n el.addEventListener(\"vuu-commit\", commitHandler, true);\n },\n [commitHandler]\n );\n\n return {\n onBlur: handleBlur,\n onDoubleClick: handleDoubleClick,\n onFocus: handleFocus,\n onKeyDown: handleKeyDown,\n };\n};\n"],"names":["useCallback","cellIsTextInput","isCharacterKey"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ var vuuUiControls = require('@vuu-ui/vuu-ui-controls');
4
+ var vuuUtils = require('@vuu-ui/vuu-utils');
5
+ var react = require('react');
6
+
7
+ const useControlledTableNavigation = (initialValue, rowCount) => {
8
+ const tableRef = react.useRef(null);
9
+ const [highlightedIndexRef, setHighlightedIndex] = vuuUiControls.useStateRef(initialValue);
10
+ const handleKeyDown = react.useCallback(
11
+ (e) => {
12
+ if (e.key === "ArrowDown") {
13
+ setHighlightedIndex((index = -1) => Math.min(rowCount - 1, index + 1));
14
+ } else if (e.key === "ArrowUp") {
15
+ setHighlightedIndex((index = -1) => Math.max(0, index - 1));
16
+ } else if (e.key === "Enter" || e.key === " ") {
17
+ const { current: rowIdx } = highlightedIndexRef;
18
+ const rowEl = tableRef.current?.querySelector(
19
+ `[aria-rowindex="${rowIdx}"]`
20
+ );
21
+ if (rowEl) {
22
+ vuuUtils.dispatchMouseEvent(rowEl, "click");
23
+ }
24
+ }
25
+ },
26
+ [highlightedIndexRef, rowCount, setHighlightedIndex]
27
+ );
28
+ const handleHighlight = react.useCallback(
29
+ (idx) => {
30
+ setHighlightedIndex(idx);
31
+ },
32
+ [setHighlightedIndex]
33
+ );
34
+ return {
35
+ highlightedIndexRef,
36
+ onHighlight: handleHighlight,
37
+ onKeyDown: handleKeyDown,
38
+ tableRef
39
+ };
40
+ };
41
+
42
+ exports.useControlledTableNavigation = useControlledTableNavigation;
43
+ //# sourceMappingURL=useControlledTableNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useControlledTableNavigation.js","sources":["../src/useControlledTableNavigation.ts"],"sourcesContent":["import { useStateRef } from \"@vuu-ui/vuu-ui-controls\";\nimport { dispatchMouseEvent } from \"@vuu-ui/vuu-utils\";\nimport { KeyboardEventHandler, useCallback, useRef } from \"react\";\n\nexport const useControlledTableNavigation = (\n initialValue: number,\n rowCount: number\n) => {\n const tableRef = useRef<HTMLDivElement>(null);\n\n const [highlightedIndexRef, setHighlightedIndex] = useStateRef<\n number | undefined\n >(initialValue);\n\n const handleKeyDown = useCallback<KeyboardEventHandler>(\n (e) => {\n if (e.key === \"ArrowDown\") {\n setHighlightedIndex((index = -1) => Math.min(rowCount - 1, index + 1));\n } else if (e.key === \"ArrowUp\") {\n setHighlightedIndex((index = -1) => Math.max(0, index - 1));\n } else if (e.key === \"Enter\" || e.key === \" \") {\n const { current: rowIdx } = highlightedIndexRef;\n // induce an onSelect event by 'clicking' the row\n const rowEl = tableRef.current?.querySelector(\n `[aria-rowindex=\"${rowIdx}\"]`\n ) as HTMLElement;\n if (rowEl) {\n dispatchMouseEvent(rowEl, \"click\");\n }\n }\n },\n [highlightedIndexRef, rowCount, setHighlightedIndex]\n );\n\n const handleHighlight = useCallback(\n (idx: number) => {\n setHighlightedIndex(idx);\n },\n [setHighlightedIndex]\n );\n\n return {\n highlightedIndexRef,\n onHighlight: handleHighlight,\n onKeyDown: handleKeyDown,\n tableRef,\n };\n};\n"],"names":["useRef","useStateRef","useCallback","dispatchMouseEvent"],"mappings":";;;;;;AAIa,MAAA,4BAAA,GAA+B,CAC1C,YAAA,EACA,QACG,KAAA;AACH,EAAM,MAAA,QAAA,GAAWA,aAAuB,IAAI,CAAA,CAAA;AAE5C,EAAA,MAAM,CAAC,mBAAA,EAAqB,mBAAmB,CAAA,GAAIC,0BAEjD,YAAY,CAAA,CAAA;AAEd,EAAA,MAAM,aAAgB,GAAAC,iBAAA;AAAA,IACpB,CAAC,CAAM,KAAA;AACL,MAAI,IAAA,CAAA,CAAE,QAAQ,WAAa,EAAA;AACzB,QAAoB,mBAAA,CAAA,CAAC,QAAQ,CAAO,CAAA,KAAA,IAAA,CAAK,IAAI,QAAW,GAAA,CAAA,EAAG,KAAQ,GAAA,CAAC,CAAC,CAAA,CAAA;AAAA,OACvE,MAAA,IAAW,CAAE,CAAA,GAAA,KAAQ,SAAW,EAAA;AAC9B,QAAoB,mBAAA,CAAA,CAAC,QAAQ,CAAO,CAAA,KAAA,IAAA,CAAK,IAAI,CAAG,EAAA,KAAA,GAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,iBACjD,CAAE,CAAA,GAAA,KAAQ,OAAW,IAAA,CAAA,CAAE,QAAQ,GAAK,EAAA;AAC7C,QAAM,MAAA,EAAE,OAAS,EAAA,MAAA,EAAW,GAAA,mBAAA,CAAA;AAE5B,QAAM,MAAA,KAAA,GAAQ,SAAS,OAAS,EAAA,aAAA;AAAA,UAC9B,mBAAmB,MAAM,CAAA,EAAA,CAAA;AAAA,SAC3B,CAAA;AACA,QAAA,IAAI,KAAO,EAAA;AACT,UAAAC,2BAAA,CAAmB,OAAO,OAAO,CAAA,CAAA;AAAA,SACnC;AAAA,OACF;AAAA,KACF;AAAA,IACA,CAAC,mBAAqB,EAAA,QAAA,EAAU,mBAAmB,CAAA;AAAA,GACrD,CAAA;AAEA,EAAA,MAAM,eAAkB,GAAAD,iBAAA;AAAA,IACtB,CAAC,GAAgB,KAAA;AACf,MAAA,mBAAA,CAAoB,GAAG,CAAA,CAAA;AAAA,KACzB;AAAA,IACA,CAAC,mBAAmB,CAAA;AAAA,GACtB,CAAA;AAEA,EAAO,OAAA;AAAA,IACL,mBAAA;AAAA,IACA,WAAa,EAAA,eAAA;AAAA,IACb,SAAW,EAAA,aAAA;AAAA,IACX,QAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var react = require('react');
5
+ var movingWindow = require('./moving-window.js');
6
+
7
+ const isVuuFeatureInvocation = (action) => action.type === "vuu-link-created" || action.type === "vuu-link-removed";
8
+ const useDataSource = ({
9
+ dataSource,
10
+ onFeatureInvocation,
11
+ onSizeChange,
12
+ onSubscribed,
13
+ range = vuuUtils.NULL_RANGE,
14
+ renderBufferSize = 0
15
+ }) => {
16
+ const [, forceUpdate] = react.useState(null);
17
+ const data = react.useRef([]);
18
+ const isMounted = react.useRef(true);
19
+ const hasUpdated = react.useRef(false);
20
+ const rangeRef = react.useRef(range);
21
+ const dataWindow = react.useMemo(
22
+ () => new movingWindow.MovingWindow(vuuUtils.getFullRange(range, renderBufferSize)),
23
+ // eslint-disable-next-line react-hooks/exhaustive-deps
24
+ []
25
+ );
26
+ const setData = react.useCallback(
27
+ (updates) => {
28
+ for (const row of updates) {
29
+ dataWindow.add(row);
30
+ }
31
+ data.current = dataWindow.data;
32
+ if (isMounted.current) {
33
+ forceUpdate({});
34
+ }
35
+ },
36
+ [dataWindow]
37
+ );
38
+ const datasourceMessageHandler = react.useCallback(
39
+ (message) => {
40
+ if (message.type === "subscribed") {
41
+ onSubscribed?.(message);
42
+ } else if (message.type === "viewport-update") {
43
+ if (typeof message.size === "number") {
44
+ onSizeChange?.(message.size);
45
+ dataWindow.setRowCount(message.size);
46
+ }
47
+ if (message.rows) {
48
+ setData(message.rows);
49
+ } else if (typeof message.size === "number") {
50
+ data.current = dataWindow.data;
51
+ hasUpdated.current = true;
52
+ }
53
+ } else if (isVuuFeatureInvocation(message)) {
54
+ onFeatureInvocation?.(message);
55
+ } else {
56
+ console.log(`useDataSource unexpected message ${message.type}`);
57
+ }
58
+ },
59
+ [dataWindow, onFeatureInvocation, onSizeChange, onSubscribed, setData]
60
+ );
61
+ const getSelectedRows = react.useCallback(() => {
62
+ return dataWindow.getSelectedRows();
63
+ }, [dataWindow]);
64
+ react.useEffect(() => {
65
+ isMounted.current = true;
66
+ dataSource.resume?.();
67
+ return () => {
68
+ isMounted.current = false;
69
+ dataSource.suspend?.();
70
+ };
71
+ }, [dataSource]);
72
+ react.useEffect(() => {
73
+ if (dataSource.status === "disabled") {
74
+ dataSource.enable?.(datasourceMessageHandler);
75
+ } else {
76
+ dataSource?.subscribe(
77
+ { range: vuuUtils.getFullRange(range, renderBufferSize) },
78
+ datasourceMessageHandler
79
+ );
80
+ }
81
+ }, [dataSource, datasourceMessageHandler, range, renderBufferSize]);
82
+ const setRange = react.useCallback(
83
+ (range2) => {
84
+ if (!vuuUtils.rangesAreSame(range2, rangeRef.current)) {
85
+ const fullRange = vuuUtils.getFullRange(range2, renderBufferSize);
86
+ dataWindow.setRange(fullRange);
87
+ dataSource.range = rangeRef.current = fullRange;
88
+ dataSource.emit("range", range2);
89
+ }
90
+ },
91
+ [dataSource, dataWindow, renderBufferSize]
92
+ );
93
+ return {
94
+ data: data.current,
95
+ dataRef: data,
96
+ getSelectedRows,
97
+ range: rangeRef.current,
98
+ setRange
99
+ };
100
+ };
101
+
102
+ exports.isVuuFeatureInvocation = isVuuFeatureInvocation;
103
+ exports.useDataSource = useDataSource;
104
+ //# sourceMappingURL=useDataSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDataSource.js","sources":["../src/useDataSource.ts"],"sourcesContent":["import {\n DataSource,\n DataSourceRow,\n DataSourceSubscribedMessage,\n SubscribeCallback,\n VuuFeatureInvocationMessage,\n} from \"@vuu-ui/vuu-data-types\";\nimport { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { getFullRange, NULL_RANGE, rangesAreSame } from \"@vuu-ui/vuu-utils\";\nimport { GridAction } from \"@vuu-ui/vuu-table-types\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { MovingWindow } from \"./moving-window\";\n\nexport interface DataSourceHookProps {\n dataSource: DataSource;\n onFeatureInvocation?: (message: VuuFeatureInvocationMessage) => void;\n onSizeChange: (size: number) => void;\n onSubscribed: (subscription: DataSourceSubscribedMessage) => void;\n range?: VuuRange;\n renderBufferSize?: number;\n}\n\nexport const isVuuFeatureInvocation = (\n action: GridAction\n): action is VuuFeatureInvocationMessage =>\n action.type === \"vuu-link-created\" || action.type === \"vuu-link-removed\";\n\nexport const useDataSource = ({\n dataSource,\n onFeatureInvocation,\n onSizeChange,\n onSubscribed,\n range = NULL_RANGE,\n renderBufferSize = 0,\n}: DataSourceHookProps) => {\n const [, forceUpdate] = useState<unknown>(null);\n const data = useRef<DataSourceRow[]>([]);\n const isMounted = useRef(true);\n const hasUpdated = useRef(false);\n const rangeRef = useRef<VuuRange>(range);\n\n const dataWindow = useMemo(\n () => new MovingWindow(getFullRange(range, renderBufferSize)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const setData = useCallback(\n (updates: DataSourceRow[]) => {\n for (const row of updates) {\n dataWindow.add(row);\n }\n data.current = dataWindow.data;\n if (isMounted.current) {\n // TODO do we ever need to worry about missing updates here ?\n forceUpdate({});\n } else {\n // do nothing\n }\n },\n [dataWindow]\n );\n\n const datasourceMessageHandler: SubscribeCallback = useCallback(\n (message) => {\n if (message.type === \"subscribed\") {\n onSubscribed?.(message);\n } else if (message.type === \"viewport-update\") {\n if (typeof message.size === \"number\") {\n onSizeChange?.(message.size);\n dataWindow.setRowCount(message.size);\n }\n if (message.rows) {\n setData(message.rows);\n } else if (typeof message.size === \"number\") {\n data.current = dataWindow.data;\n hasUpdated.current = true;\n }\n } else if (isVuuFeatureInvocation(message)) {\n onFeatureInvocation?.(message);\n } else {\n console.log(`useDataSource unexpected message ${message.type}`);\n }\n },\n [dataWindow, onFeatureInvocation, onSizeChange, onSubscribed, setData]\n );\n\n const getSelectedRows = useCallback(() => {\n return dataWindow.getSelectedRows();\n }, [dataWindow]);\n\n useEffect(() => {\n isMounted.current = true;\n dataSource.resume?.();\n return () => {\n isMounted.current = false;\n dataSource.suspend?.();\n };\n }, [dataSource]);\n\n useEffect(() => {\n if (dataSource.status === \"disabled\") {\n dataSource.enable?.(datasourceMessageHandler);\n } else {\n //TODO could we improve this by using a ref for range ?\n dataSource?.subscribe(\n { range: getFullRange(range, renderBufferSize) },\n datasourceMessageHandler\n );\n }\n }, [dataSource, datasourceMessageHandler, range, renderBufferSize]);\n\n const setRange = useCallback(\n (range: VuuRange) => {\n if (!rangesAreSame(range, rangeRef.current)) {\n const fullRange = getFullRange(range, renderBufferSize);\n dataWindow.setRange(fullRange);\n dataSource.range = rangeRef.current = fullRange;\n // emit a range event omitting the renderBufferSize\n // This isn't great, we're using the dataSource as a conduit to emit a\n // message that has nothing to do with the dataSource itself. CLient\n // is the DataSourceState component.\n dataSource.emit(\"range\", range);\n }\n },\n [dataSource, dataWindow, renderBufferSize]\n );\n\n return {\n data: data.current,\n dataRef: data,\n getSelectedRows,\n range: rangeRef.current,\n setRange,\n };\n};\n"],"names":["NULL_RANGE","useState","useRef","useMemo","MovingWindow","getFullRange","useCallback","useEffect","range","rangesAreSame"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ const useInitialValue = (value) => {
6
+ const ref = react.useRef(value);
7
+ return react.useMemo(() => ref.current, []);
8
+ };
9
+
10
+ exports.useInitialValue = useInitialValue;
11
+ //# sourceMappingURL=useInitialValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInitialValue.js","sources":["../src/useInitialValue.ts"],"sourcesContent":["import { useMemo, useRef } from \"react\";\n\nexport const useInitialValue = <T = unknown>(value: T): T => {\n const ref = useRef<T>(value);\n return useMemo(() => ref.current, []);\n};\n"],"names":["useRef","useMemo"],"mappings":";;;;AAEa,MAAA,eAAA,GAAkB,CAAc,KAAgB,KAAA;AAC3D,EAAM,MAAA,GAAA,GAAMA,aAAU,KAAK,CAAA,CAAA;AAC3B,EAAA,OAAOC,aAAQ,CAAA,MAAM,GAAI,CAAA,OAAA,EAAS,EAAE,CAAA,CAAA;AACtC;;;;"}
@@ -0,0 +1,304 @@
1
+ 'use strict';
2
+
3
+ var vuuUtils = require('@vuu-ui/vuu-utils');
4
+ var core = require('@salt-ds/core');
5
+ var react = require('react');
6
+ var tableDomUtils = require('./table-dom-utils.js');
7
+
8
+ const rowNavigationKeys = /* @__PURE__ */ new Set([
9
+ "Home",
10
+ "End",
11
+ "PageUp",
12
+ "PageDown",
13
+ "ArrowDown",
14
+ "ArrowUp"
15
+ ]);
16
+ const cellNavigationKeys = new Set(rowNavigationKeys);
17
+ cellNavigationKeys.add("ArrowLeft");
18
+ cellNavigationKeys.add("ArrowRight");
19
+ const isNavigationKey = (key, navigationStyle) => {
20
+ switch (navigationStyle) {
21
+ case "cell":
22
+ return cellNavigationKeys.has(key);
23
+ case "row":
24
+ return rowNavigationKeys.has(key);
25
+ default:
26
+ return false;
27
+ }
28
+ };
29
+ const PageKeys = ["Home", "End", "PageUp", "PageDown"];
30
+ const isPagingKey = (key) => PageKeys.includes(key);
31
+ const NULL_CELL_POS = [-1, -1];
32
+ function nextCellPos(key, [rowIdx, colIdx], columnCount, rowCount) {
33
+ if (key === "ArrowUp") {
34
+ if (rowIdx > -1) {
35
+ return [rowIdx - 1, colIdx];
36
+ } else {
37
+ return [rowIdx, colIdx];
38
+ }
39
+ } else if (key === "ArrowDown") {
40
+ if (rowIdx === -1) {
41
+ return [0, colIdx];
42
+ } else if (rowIdx === rowCount - 1) {
43
+ return [rowIdx, colIdx];
44
+ } else {
45
+ return [rowIdx + 1, colIdx];
46
+ }
47
+ } else if (key === "ArrowRight") {
48
+ if (colIdx < columnCount) {
49
+ return [rowIdx, colIdx + 1];
50
+ } else {
51
+ return [rowIdx, colIdx];
52
+ }
53
+ } else if (key === "ArrowLeft") {
54
+ if (colIdx > 1) {
55
+ return [rowIdx, colIdx - 1];
56
+ } else {
57
+ return [rowIdx, colIdx];
58
+ }
59
+ }
60
+ return [rowIdx, colIdx];
61
+ }
62
+ const useKeyboardNavigation = ({
63
+ columnCount = 0,
64
+ containerRef,
65
+ disableFocus = false,
66
+ defaultHighlightedIndex,
67
+ disableHighlightOnFocus,
68
+ highlightedIndex: highlightedIndexProp,
69
+ navigationStyle,
70
+ requestScroll,
71
+ onHighlight,
72
+ rowCount = 0,
73
+ viewportRowCount
74
+ }) => {
75
+ const focusedCellPos = react.useRef([-1, -1]);
76
+ const focusableCell = react.useRef();
77
+ const activeCellPos = react.useRef([-1, 0]);
78
+ const highlightedIndexRef = react.useRef();
79
+ const [highlightedIndex, setHighlightedIdx] = core.useControlled({
80
+ controlled: highlightedIndexProp,
81
+ default: defaultHighlightedIndex,
82
+ name: "UseKeyboardNavigation"
83
+ });
84
+ highlightedIndexRef.current = highlightedIndex;
85
+ const setHighlightedIndex = react.useCallback(
86
+ (idx, fromKeyboard = false) => {
87
+ onHighlight?.(idx);
88
+ setHighlightedIdx(idx);
89
+ },
90
+ [onHighlight, setHighlightedIdx]
91
+ );
92
+ const getFocusedCell = (element) => element?.closest(
93
+ "[role='columnHeader'],[role='cell']"
94
+ );
95
+ const getTableCellPos = (tableCell) => {
96
+ if (tableCell.role === "columnHeader") {
97
+ const colIdx = parseInt(tableCell.dataset.idx ?? "-1", 10);
98
+ return [-1, colIdx];
99
+ } else {
100
+ const focusedRow = tableCell.closest("[role='row']");
101
+ if (focusedRow) {
102
+ const rowIdx = vuuUtils.getIndexFromRowElement(focusedRow);
103
+ const colIdx = Array.from(focusedRow.childNodes).indexOf(tableCell);
104
+ return [rowIdx, colIdx];
105
+ }
106
+ }
107
+ return NULL_CELL_POS;
108
+ };
109
+ const focusCell = react.useCallback(
110
+ (cellPos) => {
111
+ if (containerRef.current) {
112
+ const activeCell = tableDomUtils.getTableCell(containerRef, cellPos);
113
+ if (activeCell) {
114
+ if (activeCell !== focusableCell.current) {
115
+ focusableCell.current?.removeAttribute("tabindex");
116
+ focusableCell.current = activeCell;
117
+ activeCell.setAttribute("tabindex", "0");
118
+ }
119
+ requestScroll?.({ type: "scroll-row", rowIndex: cellPos[0] });
120
+ activeCell.focus({ preventScroll: true });
121
+ }
122
+ }
123
+ },
124
+ // TODO we recreate this function whenever viewportRange changes, which will
125
+ // be often whilst scrolling - store range in a a ref ?
126
+ [containerRef, requestScroll]
127
+ );
128
+ const setActiveCell = react.useCallback(
129
+ (rowIdx, colIdx, fromKeyboard = false) => {
130
+ const pos = [rowIdx, colIdx];
131
+ activeCellPos.current = pos;
132
+ if (navigationStyle === "row") {
133
+ setHighlightedIdx(rowIdx);
134
+ } else {
135
+ focusCell(pos);
136
+ }
137
+ if (fromKeyboard) {
138
+ focusedCellPos.current = pos;
139
+ }
140
+ },
141
+ [focusCell, navigationStyle, setHighlightedIdx]
142
+ );
143
+ const nextPageItemIdx = react.useCallback(
144
+ (key, [rowIdx, colIdx]) => new Promise((resolve) => {
145
+ let newRowIdx = rowIdx;
146
+ switch (key) {
147
+ case "PageDown": {
148
+ newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);
149
+ if (newRowIdx !== rowIdx) {
150
+ requestScroll?.({ type: "scroll-page", direction: "down" });
151
+ }
152
+ break;
153
+ }
154
+ case "PageUp": {
155
+ newRowIdx = Math.max(0, rowIdx - viewportRowCount);
156
+ if (newRowIdx !== rowIdx) {
157
+ requestScroll?.({ type: "scroll-page", direction: "up" });
158
+ }
159
+ break;
160
+ }
161
+ case "Home": {
162
+ newRowIdx = 0;
163
+ if (newRowIdx !== rowIdx) {
164
+ requestScroll?.({ type: "scroll-end", direction: "home" });
165
+ }
166
+ break;
167
+ }
168
+ case "End": {
169
+ newRowIdx = rowCount - 1;
170
+ if (newRowIdx !== rowIdx) {
171
+ requestScroll?.({ type: "scroll-end", direction: "end" });
172
+ }
173
+ break;
174
+ }
175
+ }
176
+ setTimeout(() => {
177
+ resolve([newRowIdx, colIdx]);
178
+ }, 35);
179
+ }),
180
+ [requestScroll, rowCount, viewportRowCount]
181
+ );
182
+ const handleFocus = react.useCallback(() => {
183
+ if (disableHighlightOnFocus !== true) {
184
+ if (containerRef.current?.contains(document.activeElement)) {
185
+ const focusedCell = getFocusedCell(document.activeElement);
186
+ if (focusedCell) {
187
+ focusedCellPos.current = getTableCellPos(focusedCell);
188
+ if (navigationStyle === "row") {
189
+ setHighlightedIdx(focusedCellPos.current[0]);
190
+ }
191
+ }
192
+ }
193
+ }
194
+ }, [
195
+ disableHighlightOnFocus,
196
+ containerRef,
197
+ navigationStyle,
198
+ setHighlightedIdx
199
+ ]);
200
+ const navigateChildItems = react.useCallback(
201
+ async (key) => {
202
+ const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, activeCellPos.current) : nextCellPos(key, activeCellPos.current, columnCount, rowCount);
203
+ const [rowIdx, colIdx] = activeCellPos.current;
204
+ if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {
205
+ setActiveCell(nextRowIdx, nextColIdx, true);
206
+ }
207
+ },
208
+ [columnCount, nextPageItemIdx, rowCount, setActiveCell]
209
+ );
210
+ const scrollRowIntoViewIfNecessary = react.useCallback(
211
+ (rowIndex) => {
212
+ requestScroll?.({ type: "scroll-row", rowIndex });
213
+ },
214
+ [requestScroll]
215
+ );
216
+ const moveHighlightedRow = react.useCallback(
217
+ async (key) => {
218
+ const { current: highlighted } = highlightedIndexRef;
219
+ const [nextRowIdx] = isPagingKey(key) ? await nextPageItemIdx(key, [highlighted ?? -1, 0]) : nextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);
220
+ if (nextRowIdx !== highlighted) {
221
+ setHighlightedIndex(nextRowIdx);
222
+ scrollRowIntoViewIfNecessary(nextRowIdx);
223
+ }
224
+ },
225
+ [
226
+ columnCount,
227
+ nextPageItemIdx,
228
+ rowCount,
229
+ scrollRowIntoViewIfNecessary,
230
+ setHighlightedIndex
231
+ ]
232
+ );
233
+ react.useEffect(() => {
234
+ if (highlightedIndexProp !== void 0 && highlightedIndexProp !== -1) {
235
+ scrollRowIntoViewIfNecessary(highlightedIndexProp);
236
+ }
237
+ }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);
238
+ const handleKeyDown = react.useCallback(
239
+ (e) => {
240
+ if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) {
241
+ e.preventDefault();
242
+ e.stopPropagation();
243
+ if (navigationStyle === "row") {
244
+ moveHighlightedRow(e.key);
245
+ } else {
246
+ void navigateChildItems(e.key);
247
+ }
248
+ }
249
+ },
250
+ [rowCount, navigationStyle, moveHighlightedRow, navigateChildItems]
251
+ );
252
+ const handleClick = react.useCallback(
253
+ // Might not be a cell e.g the Settings button
254
+ (evt) => {
255
+ const target = evt.target;
256
+ const focusedCell = getFocusedCell(target);
257
+ if (focusedCell) {
258
+ const [rowIdx, colIdx] = getTableCellPos(focusedCell);
259
+ setActiveCell(rowIdx, colIdx);
260
+ }
261
+ },
262
+ [setActiveCell]
263
+ );
264
+ const handleMouseLeave = react.useCallback(() => {
265
+ setHighlightedIndex(-1);
266
+ }, [setHighlightedIndex]);
267
+ const handleMouseMove = react.useCallback(
268
+ (evt) => {
269
+ const idx = tableDomUtils.closestRowIndex(evt.target);
270
+ if (idx !== -1 && idx !== highlightedIndexRef.current) {
271
+ setHighlightedIndex(idx);
272
+ }
273
+ },
274
+ [setHighlightedIndex]
275
+ );
276
+ const navigate = react.useCallback(() => {
277
+ navigateChildItems("ArrowDown");
278
+ }, [navigateChildItems]);
279
+ const fullyRendered = containerRef.current?.firstChild != null;
280
+ react.useEffect(() => {
281
+ if (fullyRendered && focusableCell.current === void 0 && !disableFocus) {
282
+ const { current: container } = containerRef;
283
+ const cell = container?.querySelector(tableDomUtils.headerCellQuery(0)) || container?.querySelector(tableDomUtils.dataCellQuery(0, 0));
284
+ if (cell) {
285
+ cell.setAttribute("tabindex", "0");
286
+ focusableCell.current = cell;
287
+ }
288
+ }
289
+ }, [containerRef, disableFocus, fullyRendered]);
290
+ return {
291
+ highlightedIndexRef,
292
+ navigate,
293
+ onClick: handleClick,
294
+ onFocus: handleFocus,
295
+ onKeyDown: handleKeyDown,
296
+ onMouseLeave: navigationStyle === "row" ? handleMouseLeave : void 0,
297
+ onMouseMove: navigationStyle === "row" ? handleMouseMove : void 0
298
+ };
299
+ };
300
+
301
+ exports.isNavigationKey = isNavigationKey;
302
+ exports.isPagingKey = isPagingKey;
303
+ exports.useKeyboardNavigation = useKeyboardNavigation;
304
+ //# sourceMappingURL=useKeyboardNavigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useKeyboardNavigation.js","sources":["../src/useKeyboardNavigation.ts"],"sourcesContent":["import { VuuRange } from \"@vuu-ui/vuu-protocol-types\";\nimport { getIndexFromRowElement } from \"@vuu-ui/vuu-utils\";\nimport { useControlled } from \"@salt-ds/core\";\nimport {\n KeyboardEvent,\n MouseEvent,\n RefObject,\n useCallback,\n useEffect,\n useRef,\n} from \"react\";\nimport { TableNavigationStyle } from \"./Table\";\nimport {\n CellPos,\n closestRowIndex,\n dataCellQuery,\n getTableCell,\n headerCellQuery,\n} from \"./table-dom-utils\";\nimport { ScrollRequestHandler } from \"./useTableScroll\";\n\nconst rowNavigationKeys = new Set<NavigationKey>([\n \"Home\",\n \"End\",\n \"PageUp\",\n \"PageDown\",\n \"ArrowDown\",\n \"ArrowUp\",\n]);\n\nconst cellNavigationKeys = new Set(rowNavigationKeys);\ncellNavigationKeys.add(\"ArrowLeft\");\ncellNavigationKeys.add(\"ArrowRight\");\n\nexport const isNavigationKey = (\n key: string,\n navigationStyle: TableNavigationStyle\n): key is NavigationKey => {\n switch (navigationStyle) {\n case \"cell\":\n return cellNavigationKeys.has(key as NavigationKey);\n case \"row\":\n return rowNavigationKeys.has(key as NavigationKey);\n default:\n return false;\n }\n};\n\ntype ArrowKey = \"ArrowUp\" | \"ArrowDown\" | \"ArrowLeft\" | \"ArrowRight\";\ntype PageKey = \"Home\" | \"End\" | \"PageUp\" | \"PageDown\";\ntype NavigationKey = PageKey | ArrowKey;\n\nconst PageKeys = [\"Home\", \"End\", \"PageUp\", \"PageDown\"];\nexport const isPagingKey = (key: string): key is PageKey =>\n PageKeys.includes(key);\n\nconst NULL_CELL_POS: CellPos = [-1, -1];\n\nfunction nextCellPos(\n key: ArrowKey,\n [rowIdx, colIdx]: CellPos,\n columnCount: number,\n rowCount: number\n): CellPos {\n if (key === \"ArrowUp\") {\n if (rowIdx > -1) {\n return [rowIdx - 1, colIdx];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowDown\") {\n if (rowIdx === -1) {\n return [0, colIdx];\n } else if (rowIdx === rowCount - 1) {\n return [rowIdx, colIdx];\n } else {\n return [rowIdx + 1, colIdx];\n }\n } else if (key === \"ArrowRight\") {\n // The colIdx is 1 based, because of the selection decorator\n if (colIdx < columnCount) {\n return [rowIdx, colIdx + 1];\n } else {\n return [rowIdx, colIdx];\n }\n } else if (key === \"ArrowLeft\") {\n if (colIdx > 1) {\n return [rowIdx, colIdx - 1];\n } else {\n return [rowIdx, colIdx];\n }\n }\n return [rowIdx, colIdx];\n}\n\nexport interface NavigationHookProps {\n containerRef: RefObject<HTMLElement>;\n columnCount?: number;\n defaultHighlightedIndex?: number;\n disableFocus?: boolean;\n disableHighlightOnFocus?: boolean;\n highlightedIndex?: number;\n label?: string;\n navigationStyle: TableNavigationStyle;\n viewportRange: VuuRange;\n onHighlight?: (idx: number) => void;\n requestScroll?: ScrollRequestHandler;\n restoreLastFocus?: boolean;\n rowCount?: number;\n selected?: unknown;\n viewportRowCount: number;\n}\n\nexport const useKeyboardNavigation = ({\n columnCount = 0,\n containerRef,\n disableFocus = false,\n defaultHighlightedIndex,\n disableHighlightOnFocus,\n highlightedIndex: highlightedIndexProp,\n navigationStyle,\n requestScroll,\n onHighlight,\n rowCount = 0,\n viewportRowCount,\n}: // viewportRange,\nNavigationHookProps) => {\n // const { from: viewportFirstRow, to: viewportLastRow } = viewportRange;\n const focusedCellPos = useRef<CellPos>([-1, -1]);\n const focusableCell = useRef<HTMLElement>();\n const activeCellPos = useRef<CellPos>([-1, 0]);\n // Keep this in sync with state value. This can be used by functions that need\n // to reference highlightedIndex at call time but do not need to be regenerated\n // every time it changes (i.e keep highlightedIndex out of their dependency\n // arrays, as it can update frequently)\n const highlightedIndexRef = useRef<number | undefined>();\n\n const [highlightedIndex, setHighlightedIdx] = useControlled({\n controlled: highlightedIndexProp,\n default: defaultHighlightedIndex,\n name: \"UseKeyboardNavigation\",\n });\n highlightedIndexRef.current = highlightedIndex;\n const setHighlightedIndex = useCallback(\n (idx: number, fromKeyboard = false) => {\n onHighlight?.(idx);\n setHighlightedIdx(idx);\n if (fromKeyboard) {\n // lastFocus.current = idx;\n }\n },\n [onHighlight, setHighlightedIdx]\n );\n\n const getFocusedCell = (element: HTMLElement | Element | null) =>\n element?.closest(\n \"[role='columnHeader'],[role='cell']\"\n ) as HTMLDivElement | null;\n\n const getTableCellPos = (tableCell: HTMLDivElement): CellPos => {\n if (tableCell.role === \"columnHeader\") {\n const colIdx = parseInt(tableCell.dataset.idx ?? \"-1\", 10);\n return [-1, colIdx];\n } else {\n const focusedRow = tableCell.closest(\"[role='row']\") as HTMLElement;\n if (focusedRow) {\n const rowIdx = getIndexFromRowElement(focusedRow);\n // TODO will get trickier when we introduce horizontal virtualisation\n const colIdx = Array.from(focusedRow.childNodes).indexOf(tableCell);\n return [rowIdx, colIdx];\n }\n }\n return NULL_CELL_POS;\n };\n\n const focusCell = useCallback(\n (cellPos: CellPos) => {\n if (containerRef.current) {\n const activeCell = getTableCell(containerRef, cellPos);\n if (activeCell) {\n if (activeCell !== focusableCell.current) {\n focusableCell.current?.removeAttribute(\"tabindex\");\n focusableCell.current = activeCell;\n activeCell.setAttribute(\"tabindex\", \"0\");\n }\n // TODO needs to be scroll cell\n requestScroll?.({ type: \"scroll-row\", rowIndex: cellPos[0] });\n activeCell.focus({ preventScroll: true });\n }\n }\n },\n // TODO we recreate this function whenever viewportRange changes, which will\n // be often whilst scrolling - store range in a a ref ?\n [containerRef, requestScroll]\n );\n\n const setActiveCell = useCallback(\n (rowIdx: number, colIdx: number, fromKeyboard = false) => {\n const pos: CellPos = [rowIdx, colIdx];\n activeCellPos.current = pos;\n if (navigationStyle === \"row\") {\n setHighlightedIdx(rowIdx);\n } else {\n focusCell(pos);\n }\n if (fromKeyboard) {\n focusedCellPos.current = pos;\n }\n },\n [focusCell, navigationStyle, setHighlightedIdx]\n );\n\n const nextPageItemIdx = useCallback(\n (\n key: \"PageDown\" | \"PageUp\" | \"Home\" | \"End\",\n [rowIdx, colIdx]: CellPos\n ): Promise<CellPos> =>\n new Promise((resolve) => {\n let newRowIdx = rowIdx;\n switch (key) {\n case \"PageDown\": {\n newRowIdx = Math.min(rowCount - 1, rowIdx + viewportRowCount);\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-page\", direction: \"down\" });\n }\n break;\n }\n case \"PageUp\": {\n newRowIdx = Math.max(0, rowIdx - viewportRowCount);\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-page\", direction: \"up\" });\n }\n break;\n }\n case \"Home\": {\n newRowIdx = 0;\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-end\", direction: \"home\" });\n }\n break;\n }\n case \"End\": {\n newRowIdx = rowCount - 1;\n if (newRowIdx !== rowIdx) {\n requestScroll?.({ type: \"scroll-end\", direction: \"end\" });\n }\n break;\n }\n }\n // Introduce a delay to allow the scroll operation to complete,\n // which will trigger a range reset and rerender of rows. We\n // might need to tweak how this works. If we introduce too big\n // a delay, we risk seeing the newly rendered rows, with the focus\n // still on the old cell, which will be apparent as a brief flash\n // of the old cell focus before switching to correct cell. If we were\n // to change the way re assign keys such that we can guarantee that\n // when we page down, rows in same position get same keys, then same\n // cell would be focussed in new page as previous and issue would not\n // arise.\n setTimeout(() => {\n resolve([newRowIdx, colIdx]);\n }, 35);\n }),\n [requestScroll, rowCount, viewportRowCount]\n );\n\n const handleFocus = useCallback(() => {\n if (disableHighlightOnFocus !== true) {\n if (containerRef.current?.contains(document.activeElement)) {\n // IF focus arrives via keyboard, a cell will have received focus,\n // we handle that here. If focus arrives via click on a cell with\n // no tabindex (i.e all cells except one) we leave that to the\n // click handler.\n const focusedCell = getFocusedCell(document.activeElement);\n if (focusedCell) {\n focusedCellPos.current = getTableCellPos(focusedCell);\n if (navigationStyle === \"row\") {\n setHighlightedIdx(focusedCellPos.current[0]);\n }\n }\n }\n }\n }, [\n disableHighlightOnFocus,\n containerRef,\n navigationStyle,\n setHighlightedIdx,\n ]);\n\n const navigateChildItems = useCallback(\n async (key: NavigationKey) => {\n const [nextRowIdx, nextColIdx] = isPagingKey(key)\n ? await nextPageItemIdx(key, activeCellPos.current)\n : nextCellPos(key, activeCellPos.current, columnCount, rowCount);\n const [rowIdx, colIdx] = activeCellPos.current;\n if (nextRowIdx !== rowIdx || nextColIdx !== colIdx) {\n setActiveCell(nextRowIdx, nextColIdx, true);\n }\n },\n [columnCount, nextPageItemIdx, rowCount, setActiveCell]\n );\n\n const scrollRowIntoViewIfNecessary = useCallback(\n (rowIndex: number) => {\n requestScroll?.({ type: \"scroll-row\", rowIndex });\n },\n [requestScroll]\n );\n\n const moveHighlightedRow = useCallback(\n async (key: NavigationKey) => {\n const { current: highlighted } = highlightedIndexRef;\n const [nextRowIdx] = isPagingKey(key)\n ? await nextPageItemIdx(key, [highlighted ?? -1, 0])\n : nextCellPos(key, [highlighted ?? -1, 0], columnCount, rowCount);\n if (nextRowIdx !== highlighted) {\n setHighlightedIndex(nextRowIdx);\n // TO(DO make this a scroll request)\n scrollRowIntoViewIfNecessary(nextRowIdx);\n }\n },\n [\n columnCount,\n nextPageItemIdx,\n rowCount,\n scrollRowIntoViewIfNecessary,\n setHighlightedIndex,\n ]\n );\n\n useEffect(() => {\n if (highlightedIndexProp !== undefined && highlightedIndexProp !== -1) {\n scrollRowIntoViewIfNecessary(highlightedIndexProp);\n }\n }, [highlightedIndexProp, scrollRowIntoViewIfNecessary]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) {\n e.preventDefault();\n e.stopPropagation();\n if (navigationStyle === \"row\") {\n moveHighlightedRow(e.key);\n } else {\n void navigateChildItems(e.key);\n }\n }\n },\n [rowCount, navigationStyle, moveHighlightedRow, navigateChildItems]\n );\n\n const handleClick = useCallback(\n // Might not be a cell e.g the Settings button\n (evt: MouseEvent) => {\n const target = evt.target as HTMLElement;\n const focusedCell = getFocusedCell(target);\n if (focusedCell) {\n const [rowIdx, colIdx] = getTableCellPos(focusedCell);\n setActiveCell(rowIdx, colIdx);\n }\n },\n [setActiveCell]\n );\n\n const handleMouseLeave = useCallback(() => {\n setHighlightedIndex(-1);\n }, [setHighlightedIndex]);\n\n const handleMouseMove = useCallback(\n (evt: MouseEvent) => {\n const idx = closestRowIndex(evt.target as HTMLElement);\n if (idx !== -1 && idx !== highlightedIndexRef.current) {\n setHighlightedIndex(idx);\n }\n },\n [setHighlightedIndex]\n );\n\n const navigate = useCallback(() => {\n navigateChildItems(\"ArrowDown\");\n }, [navigateChildItems]);\n\n // First render will only render the outer container when explicit\n // sizing has not been provided. Outer container is measured and\n // only then, on second render, is content rendered.\n const fullyRendered = containerRef.current?.firstChild != null;\n useEffect(() => {\n if (fullyRendered && focusableCell.current === undefined && !disableFocus) {\n const { current: container } = containerRef;\n const cell = (container?.querySelector(headerCellQuery(0)) ||\n container?.querySelector(dataCellQuery(0, 0))) as HTMLElement;\n if (cell) {\n cell.setAttribute(\"tabindex\", \"0\");\n focusableCell.current = cell;\n }\n }\n }, [containerRef, disableFocus, fullyRendered]);\n\n return {\n highlightedIndexRef,\n navigate,\n onClick: handleClick,\n onFocus: handleFocus,\n onKeyDown: handleKeyDown,\n onMouseLeave: navigationStyle === \"row\" ? handleMouseLeave : undefined,\n onMouseMove: navigationStyle === \"row\" ? handleMouseMove : undefined,\n };\n};\n"],"names":["useRef","useControlled","useCallback","getIndexFromRowElement","getTableCell","useEffect","closestRowIndex","headerCellQuery","dataCellQuery"],"mappings":"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"}