@mortenbrudvik/waveui 0.15.0 → 0.17.0

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 (188) hide show
  1. package/README.md +339 -40
  2. package/dist/components/data-display/List.cjs +1 -1
  3. package/dist/components/data-display/List.cjs.map +1 -1
  4. package/dist/components/data-display/List.mjs +405 -219
  5. package/dist/components/data-display/List.mjs.map +1 -1
  6. package/dist/components/data-display/List.registry.cjs +1 -1
  7. package/dist/components/data-display/List.registry.cjs.map +1 -1
  8. package/dist/components/data-display/List.registry.mjs +12 -6
  9. package/dist/components/data-display/List.registry.mjs.map +1 -1
  10. package/dist/components/input/Combobox.cjs +1 -1
  11. package/dist/components/input/Combobox.cjs.map +1 -1
  12. package/dist/components/input/Combobox.mjs +163 -148
  13. package/dist/components/input/Combobox.mjs.map +1 -1
  14. package/dist/components/input/Dropdown.cjs +1 -1
  15. package/dist/components/input/Dropdown.cjs.map +1 -1
  16. package/dist/components/input/Dropdown.mjs +132 -117
  17. package/dist/components/input/Dropdown.mjs.map +1 -1
  18. package/dist/components/input/Label.cjs +1 -1
  19. package/dist/components/input/Label.cjs.map +1 -1
  20. package/dist/components/input/Label.mjs +1 -0
  21. package/dist/components/input/Label.mjs.map +1 -1
  22. package/dist/components/input/Listbox.cjs +1 -1
  23. package/dist/components/input/Listbox.cjs.map +1 -1
  24. package/dist/components/input/Listbox.mjs +90 -78
  25. package/dist/components/input/Listbox.mjs.map +1 -1
  26. package/dist/components/input/Option.cjs +1 -1
  27. package/dist/components/input/Option.cjs.map +1 -1
  28. package/dist/components/input/Option.data.cjs +2 -0
  29. package/dist/components/input/Option.data.cjs.map +1 -0
  30. package/dist/components/input/Option.data.mjs +114 -0
  31. package/dist/components/input/Option.data.mjs.map +1 -0
  32. package/dist/components/input/Option.mjs +21 -17
  33. package/dist/components/input/Option.mjs.map +1 -1
  34. package/dist/components/layout/FlatTree.cjs +2 -0
  35. package/dist/components/layout/FlatTree.cjs.map +1 -0
  36. package/dist/components/layout/FlatTree.context.cjs +2 -0
  37. package/dist/components/layout/FlatTree.context.cjs.map +1 -0
  38. package/dist/components/layout/FlatTree.context.mjs +20 -0
  39. package/dist/components/layout/FlatTree.context.mjs.map +1 -0
  40. package/dist/components/layout/FlatTree.item.cjs +2 -0
  41. package/dist/components/layout/FlatTree.item.cjs.map +1 -0
  42. package/dist/components/layout/FlatTree.item.mjs +90 -0
  43. package/dist/components/layout/FlatTree.item.mjs.map +1 -0
  44. package/dist/components/layout/FlatTree.mjs +276 -0
  45. package/dist/components/layout/FlatTree.mjs.map +1 -0
  46. package/dist/components/layout/Tree.core.cjs +1 -1
  47. package/dist/components/layout/Tree.core.cjs.map +1 -1
  48. package/dist/components/layout/Tree.core.mjs +166 -165
  49. package/dist/components/layout/Tree.core.mjs.map +1 -1
  50. package/dist/components/layout/Tree.selection.cjs +1 -1
  51. package/dist/components/layout/Tree.selection.cjs.map +1 -1
  52. package/dist/components/layout/Tree.selection.mjs +11 -57
  53. package/dist/components/layout/Tree.selection.mjs.map +1 -1
  54. package/dist/components/layout/useFlatTree.cjs +2 -0
  55. package/dist/components/layout/useFlatTree.cjs.map +1 -0
  56. package/dist/components/layout/useFlatTree.mjs +83 -0
  57. package/dist/components/layout/useFlatTree.mjs.map +1 -0
  58. package/dist/components/portal/Portal.cjs +1 -1
  59. package/dist/components/portal/Portal.cjs.map +1 -1
  60. package/dist/components/portal/Portal.mjs +12 -11
  61. package/dist/components/portal/Portal.mjs.map +1 -1
  62. package/dist/components/provider/WaveProvider.cjs +1 -1
  63. package/dist/components/provider/WaveProvider.cjs.map +1 -1
  64. package/dist/components/provider/WaveProvider.mjs +59 -35
  65. package/dist/components/provider/WaveProvider.mjs.map +1 -1
  66. package/dist/components/table/DataGrid.cjs +1 -1
  67. package/dist/components/table/DataGrid.cjs.map +1 -1
  68. package/dist/components/table/DataGrid.context.cjs +2 -0
  69. package/dist/components/table/DataGrid.context.cjs.map +1 -0
  70. package/dist/components/table/DataGrid.context.mjs +74 -0
  71. package/dist/components/table/DataGrid.context.mjs.map +1 -0
  72. package/dist/components/table/DataGrid.header.cjs +2 -0
  73. package/dist/components/table/DataGrid.header.cjs.map +1 -0
  74. package/dist/components/table/DataGrid.header.mjs +168 -0
  75. package/dist/components/table/DataGrid.header.mjs.map +1 -0
  76. package/dist/components/table/DataGrid.mjs +488 -591
  77. package/dist/components/table/DataGrid.mjs.map +1 -1
  78. package/dist/components/table/DataGrid.sizing.cjs +2 -0
  79. package/dist/components/table/DataGrid.sizing.cjs.map +1 -0
  80. package/dist/components/table/DataGrid.sizing.mjs +187 -0
  81. package/dist/components/table/DataGrid.sizing.mjs.map +1 -0
  82. package/dist/components/table/DataGrid.store.cjs +2 -0
  83. package/dist/components/table/DataGrid.store.cjs.map +1 -0
  84. package/dist/components/table/DataGrid.store.mjs +108 -0
  85. package/dist/components/table/DataGrid.store.mjs.map +1 -0
  86. package/dist/components/table/DataGrid.window.cjs +2 -0
  87. package/dist/components/table/DataGrid.window.cjs.map +1 -0
  88. package/dist/components/table/DataGrid.window.mjs +165 -0
  89. package/dist/components/table/DataGrid.window.mjs.map +1 -0
  90. package/dist/components/table/Table.cjs +1 -1
  91. package/dist/components/table/Table.cjs.map +1 -1
  92. package/dist/components/table/Table.mjs +74 -72
  93. package/dist/components/table/Table.mjs.map +1 -1
  94. package/dist/components/table/Table.resize.cjs +2 -0
  95. package/dist/components/table/Table.resize.cjs.map +1 -0
  96. package/dist/components/table/Table.resize.mjs +98 -0
  97. package/dist/components/table/Table.resize.mjs.map +1 -0
  98. package/dist/components/table/useGridNavigation.cjs +1 -1
  99. package/dist/components/table/useGridNavigation.cjs.map +1 -1
  100. package/dist/components/table/useGridNavigation.mjs +343 -140
  101. package/dist/components/table/useGridNavigation.mjs.map +1 -1
  102. package/dist/components/table/useTableColumnSizing.cjs +2 -0
  103. package/dist/components/table/useTableColumnSizing.cjs.map +1 -0
  104. package/dist/components/table/useTableColumnSizing.mjs +76 -0
  105. package/dist/components/table/useTableColumnSizing.mjs.map +1 -0
  106. package/dist/components/table/useTableFeatures.cjs +2 -0
  107. package/dist/components/table/useTableFeatures.cjs.map +1 -0
  108. package/dist/components/table/useTableFeatures.mjs +110 -0
  109. package/dist/components/table/useTableFeatures.mjs.map +1 -0
  110. package/dist/components/table/useTableSelection.cjs +2 -0
  111. package/dist/components/table/useTableSelection.cjs.map +1 -0
  112. package/dist/components/table/useTableSelection.mjs +39 -0
  113. package/dist/components/table/useTableSelection.mjs.map +1 -0
  114. package/dist/components/table/useTableSort.cjs +2 -0
  115. package/dist/components/table/useTableSort.cjs.map +1 -0
  116. package/dist/components/table/useTableSort.mjs +58 -0
  117. package/dist/components/table/useTableSort.mjs.map +1 -0
  118. package/dist/components/typography/Text.cjs +1 -1
  119. package/dist/components/typography/Text.cjs.map +1 -1
  120. package/dist/components/typography/Text.mjs +11 -7
  121. package/dist/components/typography/Text.mjs.map +1 -1
  122. package/dist/hooks/useActiveDescendant.cjs +1 -1
  123. package/dist/hooks/useActiveDescendant.cjs.map +1 -1
  124. package/dist/hooks/useActiveDescendant.mjs +33 -25
  125. package/dist/hooks/useActiveDescendant.mjs.map +1 -1
  126. package/dist/hooks/useListbox.cjs +1 -1
  127. package/dist/hooks/useListbox.cjs.map +1 -1
  128. package/dist/hooks/useListbox.mjs +140 -130
  129. package/dist/hooks/useListbox.mjs.map +1 -1
  130. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  131. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  132. package/dist/hooks/useRovingTabIndex.mjs +1 -1
  133. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  134. package/dist/hooks/useSelection.cjs +2 -0
  135. package/dist/hooks/useSelection.cjs.map +1 -0
  136. package/dist/hooks/useSelection.mjs +57 -0
  137. package/dist/hooks/useSelection.mjs.map +1 -0
  138. package/dist/hooks/useVirtualWindow.cjs +2 -0
  139. package/dist/hooks/useVirtualWindow.cjs.map +1 -0
  140. package/dist/hooks/useVirtualWindow.mjs +102 -0
  141. package/dist/hooks/useVirtualWindow.mjs.map +1 -0
  142. package/dist/index.cjs +1 -1
  143. package/dist/index.d.cts +1799 -63
  144. package/dist/index.d.ts +1799 -63
  145. package/dist/index.mjs +150 -136
  146. package/dist/lib/brand.cjs +2 -0
  147. package/dist/lib/brand.cjs.map +1 -0
  148. package/dist/lib/brand.mjs +358 -0
  149. package/dist/lib/brand.mjs.map +1 -0
  150. package/dist/lib/classNames.cjs +1 -1
  151. package/dist/lib/classNames.cjs.map +1 -1
  152. package/dist/lib/classNames.mjs +68 -49
  153. package/dist/lib/classNames.mjs.map +1 -1
  154. package/dist/lib/cn.cjs +1 -1
  155. package/dist/lib/cn.cjs.map +1 -1
  156. package/dist/lib/cn.mjs +5 -1
  157. package/dist/lib/cn.mjs.map +1 -1
  158. package/dist/lib/columnSizing.cjs +2 -0
  159. package/dist/lib/columnSizing.cjs.map +1 -0
  160. package/dist/lib/columnSizing.mjs +27 -0
  161. package/dist/lib/columnSizing.mjs.map +1 -0
  162. package/dist/lib/flatTree.cjs +2 -0
  163. package/dist/lib/flatTree.cjs.map +1 -0
  164. package/dist/lib/flatTree.mjs +118 -0
  165. package/dist/lib/flatTree.mjs.map +1 -0
  166. package/dist/lib/selection.cjs +2 -0
  167. package/dist/lib/selection.cjs.map +1 -0
  168. package/dist/lib/selection.mjs +28 -0
  169. package/dist/lib/selection.mjs.map +1 -0
  170. package/dist/lib/tokens.cjs +2 -0
  171. package/dist/lib/tokens.cjs.map +1 -0
  172. package/dist/lib/tokens.mjs +43 -0
  173. package/dist/lib/tokens.mjs.map +1 -0
  174. package/dist/lib/treeCascade.cjs +2 -0
  175. package/dist/lib/treeCascade.cjs.map +1 -0
  176. package/dist/lib/treeCascade.mjs +52 -0
  177. package/dist/lib/treeCascade.mjs.map +1 -0
  178. package/dist/lib/virtual.cjs +2 -0
  179. package/dist/lib/virtual.cjs.map +1 -0
  180. package/dist/lib/virtual.mjs +54 -0
  181. package/dist/lib/virtual.mjs.map +1 -0
  182. package/dist/lib/waveTokens.cjs +2 -0
  183. package/dist/lib/waveTokens.cjs.map +1 -0
  184. package/dist/lib/waveTokens.mjs +24 -0
  185. package/dist/lib/waveTokens.mjs.map +1 -0
  186. package/dist/styles.css +1 -1
  187. package/package.json +3 -1
  188. package/src/styles/tokens.css +210 -10
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ import { cn as e } from "../../lib/cn.mjs";
3
+ import { composeEventHandlers as t } from "../../lib/composeEventHandlers.mjs";
4
+ import { tableResizeHandleClassNames as n } from "../../lib/classNames.mjs";
5
+ import { useEventCallback as r } from "../../hooks/useEventCallback.mjs";
6
+ import { getArrowIntent as i, getDirection as a } from "../../lib/direction.mjs";
7
+ import { focusRing as o } from "../../lib/styles.mjs";
8
+ import * as s from "react";
9
+ import { jsx as c } from "react/jsx-runtime";
10
+ //#region src/components/table/Table.resize.tsx
11
+ var l = 20, u = 5, d = ({ width: d, minWidth: f = 0, maxWidth: p, onResize: m, onReset: h, onLeave: g, label: _ = "Resize column", valueText: v, onPointerDown: y, onPointerMove: b, onPointerUp: x, onPointerCancel: S, onLostPointerCapture: C, onDoubleClick: w, onKeyDown: T, onKeyUp: E, onBlur: D, className: O, ref: k, ...A }) => {
12
+ let j = s.useRef(null), [M, N] = s.useState(!1), P = s.useRef(null), F = (e) => Math.max(f, Math.min(p ?? Infinity, e)), I = r(() => {
13
+ let e = j.current;
14
+ if (!e?.latestEvent) return;
15
+ let t = F(Math.round(e.startWidth + (e.latestX - e.startX) * e.sign));
16
+ t !== e.lastWidth && (e.lastWidth = t, m(t, { event: e.latestEvent }));
17
+ }), L = (e) => {
18
+ let t = j.current;
19
+ t && (t.frame !== null && window.cancelAnimationFrame(t.frame), t.frame = null, e && I(), j.current = null, N(!1));
20
+ }, R = r(() => L(!1));
21
+ s.useLayoutEffect(() => R, [R]);
22
+ let z = r((e) => {
23
+ e.button === 0 && e.isPrimary && !j.current && (e.currentTarget.setPointerCapture(e.pointerId), j.current = {
24
+ pointerId: e.pointerId,
25
+ startX: e.clientX,
26
+ startWidth: d,
27
+ sign: a(e.currentTarget) === "rtl" ? -1 : 1,
28
+ latestX: e.clientX,
29
+ latestEvent: null,
30
+ lastWidth: d,
31
+ frame: null
32
+ }, N(!0));
33
+ }), B = r((e) => {
34
+ let t = j.current;
35
+ t && e.pointerId === t.pointerId && (t.latestX = e.clientX, t.latestEvent = e.nativeEvent, t.frame === null && (t.frame = window.requestAnimationFrame(() => {
36
+ t.frame = null, I();
37
+ })));
38
+ }), V = r((e) => {
39
+ e.pointerId === j.current?.pointerId && (e.currentTarget.hasPointerCapture(e.pointerId) && e.currentTarget.releasePointerCapture(e.pointerId), L(!0));
40
+ }), H = r((e) => {
41
+ e.pointerId === j.current?.pointerId && L(!1);
42
+ }), U = r((e) => {
43
+ e.pointerId === j.current?.pointerId && L(!1);
44
+ }), W = t(w, (e) => {
45
+ h?.({ event: e.nativeEvent });
46
+ }), G = r((e) => {
47
+ if (e.target !== e.currentTarget || e.ctrlKey || e.altKey || e.metaKey) return;
48
+ let t = (t) => {
49
+ t !== d && m(t, { event: e.nativeEvent });
50
+ }, n = i(e.key, {
51
+ orientation: "horizontal",
52
+ dir: a(e.currentTarget)
53
+ });
54
+ if (n) {
55
+ let r = e.shiftKey ? u : l;
56
+ t(F(Math.round(d + (n === "next" ? r : -r))));
57
+ } else if (e.key === "Home") t(F(f));
58
+ else if (e.key === "End" && p !== void 0) t(F(p));
59
+ else if (g && e.key === "Escape") g();
60
+ else if (g && (e.key === "Enter" || e.key === " ")) e.repeat || (P.current = e.key);
61
+ else return;
62
+ e.preventDefault(), e.stopPropagation();
63
+ }), K = r((e) => {
64
+ let t = P.current !== null && e.key === P.current;
65
+ t && (P.current = null), t && !e.defaultPrevented && e.target === e.currentTarget && (e.preventDefault(), e.stopPropagation(), g?.());
66
+ }), q = r(() => {
67
+ P.current = null;
68
+ });
69
+ return /* @__PURE__ */ c("div", {
70
+ ref: k,
71
+ tabIndex: 0,
72
+ "aria-label": _,
73
+ "data-dragging": M ? "" : void 0,
74
+ ...A,
75
+ role: "separator",
76
+ "aria-orientation": "vertical",
77
+ "aria-valuenow": d,
78
+ "aria-valuemin": f,
79
+ "aria-valuemax": p,
80
+ "aria-valuetext": v ? v(d) : `${Math.round(d)} pixels`,
81
+ "data-grid-auxiliary": "",
82
+ className: e(n.root, "absolute inset-y-0 end-0 z-1 w-2 cursor-col-resize touch-none select-none border-e-2 border-transparent", "hover:border-stroke-accessible focus-visible:border-primary data-[dragging]:border-primary", "forced-colors:forced-color-adjust-none forced-colors:hover:border-[ButtonText] forced-colors:focus-visible:border-[Highlight] forced-colors:data-[dragging]:border-[Highlight]", o, O),
83
+ onPointerDown: t(y, z),
84
+ onPointerMove: t(b, B),
85
+ onPointerUp: t(x, V, { checkDefaultPrevented: !1 }),
86
+ onPointerCancel: t(S, H, { checkDefaultPrevented: !1 }),
87
+ onLostPointerCapture: t(C, U, { checkDefaultPrevented: !1 }),
88
+ onDoubleClick: W,
89
+ onKeyDown: t(T, G),
90
+ onKeyUp: t(E, K, { checkDefaultPrevented: !1 }),
91
+ onBlur: t(D, q, { checkDefaultPrevented: !1 })
92
+ });
93
+ };
94
+ d.displayName = "TableResizeHandle";
95
+ //#endregion
96
+ export { d as TableResizeHandle };
97
+
98
+ //# sourceMappingURL=Table.resize.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Table.resize.mjs","names":["React","KEY_STEP","SHIFT_KEY_STEP","TableResizeHandle","rest","dragRef","dragging","setDragging","leaveKeyRef","clamp","minWidth","maxWidth","value","applyDrag","useEventCallback","drag","next","onResize","endDrag","flush","cancelDragOnUnmount","startDrag","event","width","getDirection","moveDrag","releaseDrag","cancelDrag","loseCapture","handleDoubleClick","composeEventHandlers","onDoubleClick","handleKey","resizeTo","intent","getArrowIntent","step","onLeave","leaveOnRelease","pressed","forgetPressedKey","label","valueText","cn","tableResizeHandleClassNames","focusRing","className","onPointerDown","onPointerMove","onPointerUp","onPointerCancel","onLostPointerCapture","onKeyDown","onKeyUp","onBlur"],"sources":["../../../src/components/table/Table.resize.tsx"],"sourcesContent":["import * as React from 'react';\nimport { tableResizeHandleClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { focusRing } from '../../lib/styles';\nimport { useEventCallback } from '../../hooks/useEventCallback';\n\n/** How far an arrow key moves the edge, in pixels, and how far with Shift held. */\nconst KEY_STEP = 20;\nconst SHIFT_KEY_STEP = 5;\n\n/** Properties for the TableResizeHandle sub-component. */\nexport interface TableResizeHandleProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onResize' | 'onReset'\n> {\n /** The column's current width in pixels. It is reported as `aria-valuenow`. */\n width: number;\n /**\n * The narrowest the column can be, in pixels. The handle never asks for less, and Home sets it.\n * It is reported as `aria-valuemin`.\n * @default 0\n */\n minWidth?: number;\n /**\n * The widest the column can be, in pixels. The handle never asks for more, and End sets it.\n * Without a maximum there is no `aria-valuemax` and End does nothing.\n */\n maxWidth?: number;\n /**\n * Called with the width the user asks for, in whole pixels, held between `minWidth` and\n * `maxWidth`: while a pointer drags (at most once per animation frame) and for every handled\n * key, then `details` with the event behind it. The handle always passes `details`; it is typed\n * optional through 0.x, as every `details` argument. The handle keeps no width of its own, so a\n * parent that ignores the call leaves the column where it is.\n */\n onResize: (width: number, details?: { event: Event }) => void;\n /** Called with the event when the handle is double-clicked: reset the column's width. */\n onReset?: (details: { event: Event }) => void;\n /**\n * Called when Escape is pressed on the handle, or Enter or Space is released on it after being\n * pressed there: move focus back to the header cell. Enter and Space are consumed from their\n * keydown on (their repeats included), so a held key never reaches the element that focus moves\n * to. Without it those keys are left to the handle's ancestors.\n */\n onLeave?: () => void;\n /**\n * The accessible name of the separator.\n * @default 'Resize column'\n */\n label?: string;\n /**\n * Builds `aria-valuetext` from the width.\n * @default (width) => `${width} pixels`\n */\n valueText?: (width: number) => string;\n /** Ref to the `<div>` element. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** What a pointer drag keeps between its events. */\ninterface DragState {\n pointerId: number;\n startX: number;\n startWidth: number;\n /** `1`, or `-1` in a right-to-left table, where moving toward the end narrows the column. */\n sign: 1 | -1;\n latestX: number;\n latestEvent: Event | null;\n /** The last width handed to `onResize`, so a width is not reported twice in a row. */\n lastWidth: number;\n /** The animation frame that will apply the latest position, while one is waiting. */\n frame: number | null;\n}\n\n/**\n * The drag handle of a column's edge: a vertical `role=\"separator\"` with `aria-valuenow`, meant\n * for the `aside` slot of a `Table.HeaderCell` whose cell is positioned, since the handle is drawn\n * along the cell's end edge. A DataGrid with `resizableColumns` renders it in the header cell of\n * each of its columns itself (a `DataGrid.HeaderCell` has no `aside` slot). A pointer drag (mouse,\n * touch or pen) resizes through `onResize`, with the movement mirrored in right-to-left tables;\n * the arrow keys move the edge by 20 pixels (5 with Shift), Home sets the minimum width and End\n * the maximum one. A double click calls `onReset`. The handle is a Tab stop (`tabIndex` 0), so the\n * keys work in a static table; a grid that manages its own tab stops overrides `tabIndex`. The\n * handle carries `data-grid-auxiliary`, so a grid's cell navigation does not take it for the\n * cell's own widget.\n *\n * It keeps no width: spread the result of `useTableColumnSizing`'s `getResizeHandleProps(columnId)`\n * onto it, or pass `width`, `minWidth` and `onResize` from your own state.\n */\nconst TableResizeHandle = ({\n width,\n minWidth = 0,\n maxWidth,\n onResize,\n onReset,\n onLeave,\n label = 'Resize column',\n valueText,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n onLostPointerCapture,\n onDoubleClick,\n onKeyDown,\n onKeyUp,\n onBlur,\n className,\n ref,\n ...rest\n}: TableResizeHandleProps) => {\n const dragRef = React.useRef<DragState | null>(null);\n const [dragging, setDragging] = React.useState(false);\n /** The Enter or Space pressed on the handle whose release leaves it; `null` otherwise. */\n const leaveKeyRef = React.useRef<string | null>(null);\n\n const clamp = (value: number) => Math.max(minWidth, Math.min(maxWidth ?? Infinity, value));\n\n // Applies the latest pointer position of the drag. It reads the latest props, also when an\n // animation frame calls it after a render.\n const applyDrag = useEventCallback(() => {\n const drag = dragRef.current;\n if (!drag?.latestEvent) return;\n const next = clamp(Math.round(drag.startWidth + (drag.latestX - drag.startX) * drag.sign));\n if (next === drag.lastWidth) return;\n drag.lastWidth = next;\n onResize(next, { event: drag.latestEvent });\n });\n\n // Ends the drag; `flush` first applies a move that still waits for its frame.\n const endDrag = (flush: boolean) => {\n const drag = dragRef.current;\n if (!drag) return;\n if (drag.frame !== null) window.cancelAnimationFrame(drag.frame);\n drag.frame = null;\n if (flush) applyDrag();\n dragRef.current = null;\n setDragging(false);\n };\n\n // A frame that is still waiting when the handle unmounts must not call `onResize`: cancelled in\n // the commit that removes the handle, before a frame can run.\n const cancelDragOnUnmount = useEventCallback(() => endDrag(false));\n React.useLayoutEffect(() => cancelDragOnUnmount, [cancelDragOnUnmount]);\n\n const startDrag = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0 || !event.isPrimary || dragRef.current) return;\n event.currentTarget.setPointerCapture(event.pointerId);\n dragRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startWidth: width,\n sign: getDirection(event.currentTarget) === 'rtl' ? -1 : 1,\n latestX: event.clientX,\n latestEvent: null,\n lastWidth: width,\n frame: null,\n };\n setDragging(true);\n });\n\n const moveDrag = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n const drag = dragRef.current;\n if (!drag || event.pointerId !== drag.pointerId) return;\n drag.latestX = event.clientX;\n drag.latestEvent = event.nativeEvent;\n // One call per frame, with the last position.\n if (drag.frame === null) {\n drag.frame = window.requestAnimationFrame(() => {\n drag.frame = null;\n applyDrag();\n });\n }\n });\n\n const releaseDrag = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (event.pointerId !== dragRef.current?.pointerId) return;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n endDrag(true);\n });\n\n const cancelDrag = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (event.pointerId === dragRef.current?.pointerId) endDrag(false);\n });\n\n const loseCapture = useEventCallback((event: React.PointerEvent<HTMLDivElement>) => {\n if (event.pointerId === dragRef.current?.pointerId) endDrag(false);\n });\n\n const handleDoubleClick = composeEventHandlers(\n onDoubleClick,\n (event: React.MouseEvent<HTMLDivElement>) => {\n onReset?.({ event: event.nativeEvent });\n },\n );\n\n const handleKey = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.target !== event.currentTarget || event.ctrlKey || event.altKey || event.metaKey) {\n return;\n }\n const resizeTo = (next: number) => {\n if (next !== width) onResize(next, { event: event.nativeEvent });\n };\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n if (intent) {\n const step = event.shiftKey ? SHIFT_KEY_STEP : KEY_STEP;\n resizeTo(clamp(Math.round(width + (intent === 'next' ? step : -step))));\n } else if (event.key === 'Home') {\n resizeTo(clamp(minWidth));\n } else if (event.key === 'End' && maxWidth !== undefined) {\n resizeTo(clamp(maxWidth));\n } else if (onLeave && event.key === 'Escape') {\n onLeave();\n } else if (onLeave && (event.key === 'Enter' || event.key === ' ')) {\n // Left on the release: focus moved now would hand the key's repeats (and Space's keyup,\n // which activates a button) to the element focus moves to. A repeat alone, of a key\n // pressed before focus came here, leaves nothing to release.\n if (!event.repeat) leaveKeyRef.current = event.key;\n } else {\n return;\n }\n // A handled key does not also move the grid.\n event.preventDefault();\n event.stopPropagation();\n });\n\n // Composed without the default-prevented check: the pressed key is forgotten at its release,\n // also when a consumer handled the release (then nothing else happens).\n const leaveOnRelease = useEventCallback((event: React.KeyboardEvent<HTMLDivElement>) => {\n const pressed = leaveKeyRef.current !== null && event.key === leaveKeyRef.current;\n if (pressed) leaveKeyRef.current = null;\n if (!pressed || event.defaultPrevented || event.target !== event.currentTarget) return;\n event.preventDefault();\n event.stopPropagation();\n onLeave?.();\n });\n\n // A pressed Enter or Space is forgotten when focus leaves the handle before its release.\n const forgetPressedKey = useEventCallback(() => {\n leaveKeyRef.current = null;\n });\n\n return (\n <div\n ref={ref}\n tabIndex={0}\n aria-label={label}\n data-dragging={dragging ? '' : undefined}\n {...rest}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-valuenow={width}\n aria-valuemin={minWidth}\n aria-valuemax={maxWidth}\n aria-valuetext={valueText ? valueText(width) : `${Math.round(width)} pixels`}\n data-grid-auxiliary=\"\"\n className={cn(\n tableResizeHandleClassNames.root,\n 'absolute inset-y-0 end-0 z-1 w-2 cursor-col-resize touch-none select-none border-e-2 border-transparent',\n 'hover:border-stroke-accessible focus-visible:border-primary data-[dragging]:border-primary',\n // The line is a border, so forced colors paint it only where it shows.\n 'forced-colors:forced-color-adjust-none forced-colors:hover:border-[ButtonText] forced-colors:focus-visible:border-[Highlight] forced-colors:data-[dragging]:border-[Highlight]',\n focusRing,\n className,\n )}\n onPointerDown={composeEventHandlers(onPointerDown, startDrag)}\n onPointerMove={composeEventHandlers(onPointerMove, moveDrag)}\n onPointerUp={composeEventHandlers(onPointerUp, releaseDrag, { checkDefaultPrevented: false })}\n onPointerCancel={composeEventHandlers(onPointerCancel, cancelDrag, {\n checkDefaultPrevented: false,\n })}\n onLostPointerCapture={composeEventHandlers(onLostPointerCapture, loseCapture, {\n checkDefaultPrevented: false,\n })}\n onDoubleClick={handleDoubleClick}\n onKeyDown={composeEventHandlers(onKeyDown, handleKey)}\n onKeyUp={composeEventHandlers(onKeyUp, leaveOnRelease, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, forgetPressedKey, { checkDefaultPrevented: false })}\n />\n );\n};\nTableResizeHandle.displayName = 'TableResizeHandle';\n\nexport { TableResizeHandle };\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/direction.cjs"),n=require("../../lib/focus.cjs");let r=require("react");r=e.__toESM(r,1);var i=new Set([`checkbox`,`radio`,`button`,`submit`,`reset`,`image`,`file`,`color`]),a=new Set([`textbox`,`searchbox`,`combobox`,`spinbutton`,`slider`]),o=[`[data-roving-container]`,...[`toolbar`,`radiogroup`,`listbox`,`grid`,`treegrid`,`tablist`,`menu`,`menubar`,`tree`].map(e=>`[role="${e}"]`)].join(`, `),s=`${n.FOCUSABLE_SELECTOR}, ${o}`,c=[`disabled`,`tabindex`,`hidden`,`inert`,`type`,`contenteditable`,`role`,`data-roving-container`,`aria-selected`];function l(e){let t=e.localName;if(t===`textarea`||t===`select`)return!0;if(t===`input`)return!i.has(e.type);let n=e.getAttribute(`contenteditable`);if(n!==null&&n!==`false`)return!0;let r=e.getAttribute(`role`);return r!==null&&a.has(r)}function u(e){return e.matches(o)}function d(e,t){if(e===t)return!1;for(let n=e.parentElement;n&&n!==t;n=n.parentElement)if(u(n))return!0;return!1}function f(e){let t=e.querySelector(`[tabindex="0"]`);return t&&n.isFocusable(t)?t:n.getFirstTabbable(e,{includeContainer:!0})}function p(e){return e.localName===`input`&&e.type===`hidden`||e.matches(`:disabled`)?!1:e.closest(`[hidden], [inert]`)===null}function m(e){if(!e.name)return!1;let t=e.getRootNode();if(typeof t.querySelectorAll!=`function`)return!1;let n=t.querySelectorAll(`input[type="radio"]:checked`);for(let t of Array.from(n))if(t!==e&&t.name===e.name&&t.form===e.form)return!0;return!1}function h(e){return e.localName===`td`||e.localName===`th`}function g(e,t){let n=t instanceof Element?t:null;for(;n&&n!==e;){if(h(n)&&n.closest(`table`)===e)return n;n=n.parentElement}return null}function _(e){return Array.from(e.rows).filter(e=>e.cells.length>0&&!e.hidden)}var v=1e3;function y(e){let t=new Map(e.map((e,t)=>[e,t])),n=e.map(()=>[]),r=(e,t,r,i)=>{for(let a=0;a<r;a+=1)n[e][t+a]=i};return e.forEach((e,i)=>{let a=n[i],o=0;for(let n of Array.from(e.cells)){for(;a[o];)o+=1;let s=Math.min(Math.max(n.colSpan,1),v);r(i,o,s,n);let c=n.rowSpan===0?1/0:n.rowSpan-1;for(let i=e.nextElementSibling;i&&c>0;i=i.nextElementSibling){if(i.localName!==`tr`)continue;--c;let e=t.get(i);e!==void 0&&r(e,o,s,n)}o+=s}}),n}function b(e,t){for(let n=Math.min(t,e.length-1);n>=0;--n){let t=e[n];if(t)return t}return null}function x(e,t,n){if(t instanceof Element){h(t)&&t.closest(`table`)===e&&n.add(t);for(let r of Array.from(t.querySelectorAll(`td, th`)))r.closest(`table`)===e&&n.add(r)}}function S(e={}){let i=Math.max(1,e.pageSize??10),[a,o]=r.useState(null),v=r.useRef(null),S=r.useRef(null),[C]=r.useState(()=>new WeakSet),[w]=r.useState(()=>new WeakMap),[T]=r.useState(()=>new WeakSet),E=r.useRef(i);r.useLayoutEffect(()=>{E.current=i},[i]);let D=r.useCallback((e,t)=>{let r=[],i=null;for(let a of Array.from(e.querySelectorAll(s))){if(i&&i.contains(a))continue;if(u(a)){i=a,(t?f(a)!==null:p(a))&&r.push({element:a,composite:!0});continue}let e=a.getAttribute(`tabindex`);e!==null&&Number(e)<0&&!C.has(a)||(t?n.isFocusable(a):p(a))&&r.push({element:a,composite:!1})}return r},[C]),O=r.useCallback((e,t,n)=>{if(t.length!==1)return e;let[{element:r,composite:i}]=t;return i||l(r)||n&&r instanceof HTMLInputElement&&r.type===`radio`&&!r.checked&&m(r)?e:r},[]),k=r.useCallback((e,t)=>{let n=String(t);e.getAttribute(`tabindex`)!==n&&(w.set(e,n),e.setAttribute(`tabindex`,n)),C.add(e)},[C,w]),A=r.useCallback((e,t,r)=>{let i=D(e,t);if(r){T.delete(e),k(e,-1);for(let e of i)e.composite||k(e.element,0);return}let a=O(e,i,t),o=!1;a===e?(T.delete(e),k(e,t?0:-1)):C.has(e)&&n.isFocused(e)?(o=!0,T.add(e),k(e,t?0:-1)):C.has(e)&&(T.delete(e),C.delete(e),e.hasAttribute(`tabindex`)&&(w.set(e,null),e.removeAttribute(`tabindex`)));for(let e of i){if(e.composite)continue;let n=e.element===a&&t&&!o;k(e.element,n?0:-1)}},[O,D,T,k,C,w]),j=r.useCallback((e,t)=>{let n=_(e),r=v.current,i=new Set;if((!r||!r.isConnected||!n.includes(r.parentElement))&&(r=n[0]?.cells[0]??null,v.current=r,r&&i.add(r)),S.current!==null&&S.current!==r){let e=S.current;S.current=null,i.add(e)}let a=S.current;if(t===void 0)for(let e of n)for(let t of Array.from(e.cells))i.add(t);else for(let e of t)e&&i.add(e);for(let t of i)t.isConnected&&g(e,t)===t&&A(t,t===r,t===a)},[A]);r.useLayoutEffect(()=>{if(!a||(j(a),typeof MutationObserver>`u`))return;let e=new MutationObserver(e=>{let t=!1,n=!1,r=new Set;for(let i of e){let e=i.target;if(!(e instanceof Element)||d(e,a))continue;if(i.type===`attributes`){if(i.attributeName===`tabindex`&&w.has(e)&&w.get(e)===e.getAttribute(`tabindex`))continue;t=!0;let o=g(a,e);o?r.add(o):e.localName===`tr`?x(a,e,r):n=!0;continue}t=!0;let o=g(a,e);if(o){r.add(o);continue}for(let e of Array.from(i.addedNodes))x(a,e,r)}t&&(v.current&&r.add(v.current),j(a,n?void 0:r))});return e.observe(a,{childList:!0,subtree:!0,attributes:!0,attributeFilter:c}),()=>e.disconnect()},[a,j,w]);let M=r.useCallback((e,t,n)=>{let r=v.current,i=S.current;v.current=t,S.current=n?t:null,j(e,[r,i,t])},[j]),N=r.useCallback((e,t)=>{M(e,t,!1),O(t,D(t,!0),!0).focus()},[M,O,D]),P=r.useCallback(e=>{let n=e.currentTarget;if(e.defaultPrevented)return;let r=g(n,e.target);if(!r)return;let i=D(r,!0),a=O(r,i,!1),o=e.target===r;if(!o&&e.target!==a){e.key===`Escape`&&(e.preventDefault(),N(n,r));return}if(e.altKey||e.metaKey)return;if((e.key===`Enter`||e.key===`F2`)&&o){let t=null;for(let e of i)if(t=e.composite?f(e.element):e.element,t)break;if(!t)return;e.preventDefault(),M(n,r,!0),t.focus();return}let s=_(n),c=s.findIndex(e=>e===r.parentElement);if(c<0)return;let l=Array.from(s[c].cells).indexOf(r),u=s.length-1,d=e.ctrlKey,p=null,m=null;switch(e.key){case`ArrowLeft`:case`ArrowRight`:if(d)break;p=[c,l+(t.getArrowIntent(e.key,{orientation:`horizontal`,dir:t.getDirection(n)})===`next`?1:-1)];break;case`ArrowDown`:d||(m=[c+1,1]);break;case`ArrowUp`:d||(m=[c-1,-1]);break;case`Home`:p=d?[0,0]:[c,0];break;case`End`:p=d?[u,1/0]:[c,1/0];break;case`PageDown`:d||(m=[Math.min(c+E.current,u),1]);break;case`PageUp`:d||(m=[Math.max(c-E.current,0),-1])}if(!p&&!m)return;e.preventDefault();let h=null;if(m){let e=y(s),t=Math.max(e[c].indexOf(r),0);for(let n=m[0];n>=0&&n<=u;n+=m[1]){let i=b(e[n],t);if(i&&i!==r){h=i;break}}}else if(p){let[e,t]=p,n=s[e].cells;h=t===1/0?n[n.length-1]:n.item(t)}h&&h!==r&&N(n,h)},[M,N,O,D]),F=r.useCallback(e=>{let t=e.currentTarget,n=e.target,r=g(t,n);if(!r)return;let i=n!==r&&n!==O(r,D(r,!0),!1);M(t,r,i)},[M,O,D]),I=r.useCallback(e=>{let t=e.currentTarget,n=e.target,r=[];n instanceof Element&&h(n)&&T.has(n)&&r.push(n);let i=e.relatedTarget,a=S.current;a!==null&&!(i instanceof Node&&t.contains(i))&&(S.current=null,r.push(a)),r.length>0&&j(t,r)},[T,j]);return{gridRef:o,gridProps:r.useMemo(()=>({onKeyDown:P,onFocus:F,onBlur:I}),[I,F,P])}}exports.isTextEntryElement=l,exports.useGridNavigation=S;
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/direction.cjs"),n=require("../../lib/focus.cjs");let r=require("react");r=e.__toESM(r,1);var i=new Set([`checkbox`,`radio`,`button`,`submit`,`reset`,`image`,`file`,`color`]),a=new Set([`textbox`,`searchbox`,`combobox`,`spinbutton`,`slider`]),o=[`[data-roving-container]`,...[`toolbar`,`radiogroup`,`listbox`,`grid`,`treegrid`,`tablist`,`menu`,`menubar`,`tree`].map(e=>`[role="${e}"]`)].join(`, `),s=`${n.FOCUSABLE_SELECTOR}, ${o}`,c=`data-grid-auxiliary`,l=`data-row-index`,u=[`disabled`,`tabindex`,`hidden`,`inert`,`type`,`contenteditable`,`role`,`data-roving-container`,`aria-selected`,c,l];function d(e){let t=e.localName;if(t===`textarea`||t===`select`)return!0;if(t===`input`)return!i.has(e.type);let n=e.getAttribute(`contenteditable`);if(n!==null&&n!==`false`)return!0;let r=e.getAttribute(`role`);return r!==null&&a.has(r)}function f(e){return e.matches(o)}function p(e,t){if(e===t)return!1;for(let n=e.parentElement;n&&n!==t;n=n.parentElement)if(f(n))return!0;return!1}function m(e){let t=e.querySelector(`[tabindex="0"]`);return t&&n.isFocusable(t)?t:n.getFirstTabbable(e,{includeContainer:!0})}function h(e){return e.localName===`input`&&e.type===`hidden`||e.matches(`:disabled`)?!1:e.closest(`[hidden], [inert]`)===null}function ee(e){if(!e.name)return!1;let t=e.getRootNode();if(typeof t.querySelectorAll!=`function`)return!1;let n=t.querySelectorAll(`input[type="radio"]:checked`);for(let t of Array.from(n))if(t!==e&&t.name===e.name&&t.form===e.form)return!0;return!1}function g(e){return e.localName===`td`||e.localName===`th`}function _(e,t){let n=t instanceof Element?t:null;for(;n&&n!==e;){if(g(n)&&n.closest(`table`)===e)return n;n=n.parentElement}return null}function v(e){return Array.from(e.rows).filter(e=>e.cells.length>0&&!e.hidden)}var y=1e3;function b(e){let t=new Map(e.map((e,t)=>[e,t])),n=e.map(()=>[]),r=(e,t,r,i)=>{for(let a=0;a<r;a+=1)n[e][t+a]=i};return e.forEach((e,i)=>{let a=n[i],o=0;for(let n of Array.from(e.cells)){for(;a[o];)o+=1;let s=Math.min(Math.max(n.colSpan,1),y);r(i,o,s,n);let c=n.rowSpan===0?1/0:n.rowSpan-1;for(let i=e.nextElementSibling;i&&c>0;i=i.nextElementSibling){if(i.localName!==`tr`)continue;--c;let e=t.get(i);e!==void 0&&r(e,o,s,n)}o+=s}}),n}function x(e,t){for(let n=Math.min(t,e.length-1);n>=0;--n){let t=e[n];if(t)return t}return null}function S(e){let t=e?.getAttribute(l);return t!=null&&/^\d+$/.test(t)?Number(t):null}function C(e){return Number.isFinite(e)?Math.max(0,Math.floor(e)):0}function w(e,t){if(!t)return v(e);let n=C(t.headerRowCount),r=0;return v(e).filter(e=>S(e)===null?r>=n||e.getAttribute(`aria-hidden`)===`true`?!1:(r+=1,!0):!0)}function T(e,t){let n=t.parentElement,r=e.indexOf(n);return{row:r<0?null:n,index:S(n),column:r<0?0:Math.max(b(e)[r].indexOf(t),0)}}function E(e,t,n){let r=-1,i=1/0;return e.forEach((e,n)=>{let a=S(e);a===null||Math.abs(a-t)>=i||(r=n,i=Math.abs(a-t))}),r<0?null:x(b(e)[r],n)}function te(e,t,n,r){let i=t.row!==null&&e.includes(t.row),a=i?S(t.row):t.index;if(a===null?!i:a>=n)return null;let o=i?t.row:e.find(e=>S(e)===a)??null,{column:s}=t;if(!o)return{activeRow:t,cell:r??E(e,a,s)};let c=r?.parentElement===o?r:x(b(e)[e.indexOf(o)],s);return{activeRow:{row:o,index:a,column:s},cell:c}}function ne(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement;)t=t.shadowRoot.activeElement;return t}var re=class{active=null;pending=null;listeners=new Set;subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});getActive=()=>this.active;getPending=()=>this.pending;set(e,t){if(e!==this.active||t!==this.pending){this.active=e,this.pending=t;for(let e of Array.from(this.listeners))e()}}},D=()=>null;function O(e,t,n){if(t instanceof Element){g(t)&&t.closest(`table`)===e&&n.add(t);for(let r of Array.from(t.querySelectorAll(`td, th`)))r.closest(`table`)===e&&n.add(r)}}function k(e){return e.composite?m(e.element):e.element}function ie(e){for(let t of e){let e=t.auxiliary?k(t):null;if(e)return e}return null}function A(e,t,n,r,i){return t===e?!1:t!==n||i===e&&r.some(e=>e.auxiliary)}var j=new WeakMap;function M(e){for(let t=e.parentElement;t;t=t.parentElement){let n=j.get(t);if(!n)continue;let r=_(t,e);return r?(n(r),!0):!1}return!1}function N(e={}){let{model:i}=e,a=Math.max(1,e.pageSize??10),[o,l]=r.useState(null),v=r.useRef(i),y=r.useRef(null),E=r.useRef(null),[M]=r.useState(()=>new re),N=r.useSyncExternalStore(M.subscribe,M.getActive,D),ae=r.useSyncExternalStore(M.subscribe,M.getPending,D),P=r.useRef(null),F=r.useRef(null),[I]=r.useState(()=>new WeakSet),[L]=r.useState(()=>new WeakMap),[R]=r.useState(()=>new WeakSet),z=r.useRef(a);r.useLayoutEffect(()=>{z.current=a},[a]);let B=r.useCallback((e,t)=>{let r=[],i=null;for(let a of Array.from(e.querySelectorAll(s))){if(i&&i.contains(a))continue;if(f(a)){i=a,(t?m(a)!==null:h(a))&&r.push({element:a,composite:!0,auxiliary:a.hasAttribute(c)});continue}let e=a.getAttribute(`tabindex`);e!==null&&Number(e)<0&&!I.has(a)||(t?n.isFocusable(a):h(a))&&r.push({element:a,composite:!1,auxiliary:a.hasAttribute(c)})}return r},[I]),V=r.useCallback((e,t,n)=>{let r=null;for(let n of t)if(!n.auxiliary){if(r)return e;r=n}if(!r)return e;let{element:i,composite:a}=r;return a||d(i)||n&&i instanceof HTMLInputElement&&i.type===`radio`&&!i.checked&&ee(i)?e:i},[]),H=r.useCallback((e,t)=>{let n=String(t);e.getAttribute(`tabindex`)!==n&&(L.set(e,n),e.setAttribute(`tabindex`,n)),I.add(e)},[I,L]),U=r.useCallback((e,t,r)=>{let i=B(e,t);if(r){R.delete(e),H(e,-1);for(let e of i)e.composite||H(e.element,0);return}let a=V(e,i,t),o=!1;a===e?(R.delete(e),H(e,t?0:-1)):I.has(e)&&n.isFocused(e)?(o=!0,R.add(e),H(e,t?0:-1)):I.has(e)&&(R.delete(e),I.delete(e),e.hasAttribute(`tabindex`)&&(L.set(e,null),e.removeAttribute(`tabindex`)));for(let e of i){if(e.composite)continue;let n=e.element===a&&t&&!o;H(e.element,n?0:-1)}},[V,B,R,H,I,L]),W=r.useCallback(()=>{M.set(y.current?.index??null,E.current?.index??null)},[M]),G=r.useCallback((e,t)=>{let n=v.current,r=w(e,n),i=P.current,a=new Set,o=!i||!i.isConnected||!r.includes(i.parentElement),s=n&&y.current?te(r,y.current,C(n.rowCount),o?null:i):null;if(s&&(y.current=s.activeRow,s.cell&&(o=!1,s.cell!==i&&(i&&a.add(i),i=s.cell,P.current=i,a.add(i)))),o&&(i=r[0]?.cells[0]??null,P.current=i,i&&a.add(i),n&&!s&&(y.current=null)),n&&i&&y.current===null&&(y.current=T(r,i)),F.current!==null&&F.current!==i){let e=F.current;F.current=null,a.add(e)}let c=F.current;if(t===void 0)for(let e of r)for(let t of Array.from(e.cells))a.add(t);else for(let e of t)e&&a.add(e);let l=n?new Set(r):null;for(let t of a)t.isConnected&&_(e,t)===t&&(!l||l.has(t.parentElement)||I.has(t))&&U(t,t===i,t===c);n&&W()},[W,I,U]),K=r.useCallback((e,t,n)=>{let r=P.current,i=F.current;P.current=t,F.current=n?t:null;let a=v.current;a&&(y.current=T(w(e,a),t),E.current=null),G(e,[r,i,t])},[G]),q=r.useCallback((e,t)=>{K(e,t,!1),V(t,B(t,!0),!0).focus()},[K,V,B]),J=r.useCallback((e,t)=>{let n=v.current;if(!n)return;let r=E.current;E.current={index:e,column:t},W(),r?.index!==e&&n.scrollToRow(e)},[W]),Y=r.useCallback(e=>{let t=E.current,n=v.current;if(!t||!n)return;if(t.index>=C(n.rowCount)){E.current=null,W();return}let r=w(e,n),i=r.findIndex(e=>S(e)===t.index);if(i<0)return;E.current=null;let a=x(b(r)[i],t.column),o=ne(e.ownerDocument),s=o===null||o===e.ownerDocument.body||e.contains(o);a&&s?q(e,a):W()},[q,W]),X=r.useCallback((e,t,n,r)=>{let i=v.current;if(!i)return;let a=n.filter(e=>S(e)===null),o=new Map;n.forEach((e,t)=>{let n=S(e);n!==null&&o.set(n,t)});let s=C(i.rowCount),c=a.length+s-1,l=b(n),u=E.current,d,f;if(u)d=a.length+Math.min(u.index,s-1),f=u.column;else{let e=t.parentElement,r=S(e);d=r===null?a.indexOf(e):a.length+r,f=Math.max(l[n.indexOf(e)].indexOf(t),0)}let p,m=1,h=!1;switch(r){case`ArrowDown`:p=d+1;break;case`ArrowUp`:p=d-1,m=-1;break;case`PageDown`:p=Math.min(d+z.current,c);break;case`PageUp`:p=Math.max(d-z.current,0),m=-1;break;case`Home`:p=0,f=0,h=!0;break;default:p=c,f=1/0,h=!0}for(let r=p;r>=0&&r<=c;r+=m){let i=r<a.length?n.indexOf(a[r]):o.get(r-a.length)??-1;if(i<0){J(r-a.length,f);break}let s=x(l[i],f);if(s&&(u||s!==t)){q(e,s);break}if(h)break}r===`Home`&&a.length>0&&s>0&&i.scrollToRow(0)},[q,J]);r.useLayoutEffect(()=>{if(!o||(G(o),typeof MutationObserver>`u`))return;let e=new MutationObserver(e=>{let t=!1,n=!1,r=new Set;for(let i of e){let e=i.target;if(!(e instanceof Element)||p(e,o))continue;if(i.type===`attributes`){if(i.attributeName===`tabindex`&&L.has(e)&&L.get(e)===e.getAttribute(`tabindex`))continue;t=!0;let a=_(o,e);a?r.add(a):e.localName===`tr`?O(o,e,r):n=!0;continue}t=!0;let a=_(o,e);if(a){r.add(a);continue}for(let e of Array.from(i.addedNodes))O(o,e,r)}t&&(P.current&&r.add(P.current),G(o,n?void 0:r),Y(o))});return e.observe(o,{childList:!0,subtree:!0,attributes:!0,attributeFilter:u}),()=>e.disconnect()},[o,Y,G,L]),r.useLayoutEffect(()=>{if(!o)return;let e=e=>q(o,e);return j.set(o,e),()=>{j.get(o)===e&&j.delete(o)}},[o,q]),r.useLayoutEffect(()=>{if(v.current=i,!i){y.current=null,E.current=null,M.set(null,null);return}o&&Y(o)});let Z=r.useCallback(e=>{let n=e.currentTarget;if(e.defaultPrevented)return;let r=_(n,e.target);if(!r)return;let i=B(r,!0),a=V(r,i,!1),o=e.target===r;if(A(r,e.target,a,i,F.current)){e.key===`Escape`&&(e.preventDefault(),q(n,r));return}if(e.altKey||e.metaKey)return;let s=e.key===`F2`?ie(i):null;if(s){e.preventDefault(),K(n,r,!0),s.focus();return}if((e.key===`Enter`||e.key===`F2`)&&o){let t=null;for(let e of i)if(t=k(e),t)break;if(!t)return;e.preventDefault(),K(n,r,!0),t.focus();return}let c=w(n,v.current),l=c.findIndex(e=>e===r.parentElement);if(l<0)return;let u=Array.from(c[l].cells).indexOf(r),d=c.length-1,f=e.ctrlKey,p=null,m=null;switch(e.key){case`ArrowLeft`:case`ArrowRight`:if(f)break;p=[l,u+(t.getArrowIntent(e.key,{orientation:`horizontal`,dir:t.getDirection(n)})===`next`?1:-1)];break;case`ArrowDown`:f||(m=[l+1,1]);break;case`ArrowUp`:f||(m=[l-1,-1]);break;case`Home`:p=f?[0,0]:[l,0];break;case`End`:p=f?[d,1/0]:[l,1/0];break;case`PageDown`:f||(m=[Math.min(l+z.current,d),1]);break;case`PageUp`:f||(m=[Math.max(l-z.current,0),-1])}if(!p&&!m)return;if(e.preventDefault(),v.current&&(m||f)){X(n,r,c,e.key);return}let h=null;if(m){let e=b(c),t=Math.max(e[l].indexOf(r),0);for(let n=m[0];n>=0&&n<=d;n+=m[1]){let i=x(e[n],t);if(i&&i!==r){h=i;break}}}else if(p){let[e,t]=p,n=c[e].cells;h=t===1/0?n[n.length-1]:n.item(t)}h&&h!==r&&q(n,h)},[K,q,V,B,X]),Q=r.useCallback(e=>{let t=e.currentTarget,n=e.target,r=_(t,n);if(!r)return;let i=!1;if(n!==r){let e=B(r,!0);i=A(r,n,V(r,e,!1),e,F.current)}K(t,r,i)},[K,V,B]),$=r.useCallback(e=>{let t=e.currentTarget,n=e.target,r=[];n instanceof Element&&g(n)&&R.has(n)&&r.push(n);let i=e.relatedTarget,a=F.current;a!==null&&!(i instanceof Node&&t.contains(i))&&(F.current=null,r.push(a)),r.length>0&&G(t,r)},[R,G]);return{gridRef:l,gridProps:r.useMemo(()=>({onKeyDown:Z,onFocus:Q,onBlur:$}),[$,Q,Z]),activeRowIndex:N,pendingRowIndex:ae}}exports.isTextEntryElement=d,exports.returnFocusToGridCell=M,exports.useGridNavigation=N;
2
2
  //# sourceMappingURL=useGridNavigation.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useGridNavigation.cjs","names":["FOCUSABLE_SELECTOR","isFocusable","getFirstTabbable","React","isFocused","getArrowIntent","getDirection","require_runtime","require_direction","require_focus","react","NON_TEXT_INPUT_TYPES","KEY_CONSUMING_ROLES","COMPOSITE_SELECTOR","role","WIDGET_CANDIDATE_SELECTOR","OBSERVED_ATTRIBUTES","isTextEntryElement","tag","el","editable","isNestedComposite","isInsideNestedComposite","node","grid","getCompositeEntry","stop","composite","isLikelyFocusable","hasCheckedPeer","radio","root","checked","other","isCellElement","getCell","getRows","row","MAX_COL_SPAN","getColumnMap","indexOf","rows","index","map","cover","offset","colSpan","rowIndex","column","cell","own","remaining","next","covered","getCellAtColumn","rowMap","collectCells","into","useGridNavigation","pageSize","options","setGrid","activeCellRef","interactionCellRef","stamped","written","retained","pageSizeRef","getWidgets","widgets","precise","tabIndex","getTarget","element","checkRadioGroup","setTabIndex","value","syncCell","isActive","isInteraction","widget","target","keepCell","isStop","sync","table","active","targets","previous","interaction","cells","observer","relevant","all","dirty","record","records","activate","previousActive","previousInteraction","focusCell","onKeyDown","event","widgetTarget","onCell","entry","columnIndex","lastRow","ctrl","vertical","destination","columns","candidate","nextRow","nextColumn","rowCells","onFocus","onBlur","left"],"sources":["../../../src/components/table/useGridNavigation.ts"],"sourcesContent":["import * as React from 'react';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { FOCUSABLE_SELECTOR, getFirstTabbable, isFocusable, isFocused } from '../../lib/focus';\n\n/** Options of {@link useGridNavigation}. */\nexport interface UseGridNavigationOptions {\n /**\n * How many rows PageUp and PageDown move focus.\n * @default 10\n */\n pageSize?: number;\n}\n\n/** Handlers {@link useGridNavigation} needs on the grid element (compose them with the consumer's). */\nexport interface GridNavigationHandlers {\n onKeyDown: React.KeyboardEventHandler<HTMLTableElement>;\n onFocus: React.FocusEventHandler<HTMLTableElement>;\n onBlur: React.FocusEventHandler<HTMLTableElement>;\n}\n\n/** Result of {@link useGridNavigation}. */\nexport interface UseGridNavigationResult {\n /** Callback ref for the `<table role=\"grid\">` element. Stable identity. */\n gridRef: React.RefCallback<HTMLTableElement>;\n /** Keyboard and focus handlers for the grid element. Stable identities. */\n gridProps: GridNavigationHandlers;\n}\n\n/** Input types that do not take arrow or character keys, so a lone one can be a cell's focus target. */\nconst NON_TEXT_INPUT_TYPES: ReadonlySet<string> = new Set([\n 'checkbox',\n 'radio',\n 'button',\n 'submit',\n 'reset',\n 'image',\n 'file',\n 'color',\n]);\n\n/** Widget roles that use arrow or character keys themselves (treated like text entry). */\nconst KEY_CONSUMING_ROLES: ReadonlySet<string> = new Set([\n 'textbox',\n 'searchbox',\n 'combobox',\n 'spinbutton',\n 'slider',\n]);\n\n/**\n * Roles of composite widgets that manage their own children (and usually their tab indexes): an\n * element with one of them, or with `data-roving-container`, is a nested composite. Close to the\n * list of `useRovingTabIndex`, which is kept separately and differs on purpose: here a `toolbar`\n * is a composite (a toolbar in a cell is one widget), while `spinbutton` is not (it is one\n * focusable control that uses the arrow keys, handled by `KEY_CONSUMING_ROLES` like a text\n * field). Keep both lists in mind when adding a role.\n */\nconst COMPOSITE_ROLES: readonly string[] = [\n 'toolbar',\n 'radiogroup',\n 'listbox',\n 'grid',\n 'treegrid',\n 'tablist',\n 'menu',\n 'menubar',\n 'tree',\n];\n\nconst COMPOSITE_SELECTOR = [\n '[data-roving-container]',\n ...COMPOSITE_ROLES.map((role) => `[role=\"${role}\"]`),\n].join(', ');\n\n/** Every element that can be a cell widget: a focusable element or a nested composite root. */\nconst WIDGET_CANDIDATE_SELECTOR = `${FOCUSABLE_SELECTOR}, ${COMPOSITE_SELECTOR}`;\n\n/**\n * Attributes whose changes can change a cell's widgets or the grid's rows. `aria-selected` on a row\n * signals a selection change, which can change the active cell's target (radio groups).\n */\nconst OBSERVED_ATTRIBUTES = [\n 'disabled',\n 'tabindex',\n 'hidden',\n 'inert',\n 'type',\n 'contenteditable',\n 'role',\n 'data-roving-container',\n 'aria-selected',\n];\n\n/**\n * Whether `el` is a text-entry control (or another widget that uses arrow keys itself): a text-like\n * `input`, `textarea`, `select`, a `contenteditable` element, or an element with role textbox,\n * searchbox, combobox, spinbutton or slider. Such widgets are never a cell's navigation target: the\n * cell takes focus and Enter/F2 moves into the widget, so the arrow keys keep moving the caret.\n */\nexport function isTextEntryElement(el: Element): boolean {\n const tag = el.localName;\n if (tag === 'textarea' || tag === 'select') return true;\n if (tag === 'input') return !NON_TEXT_INPUT_TYPES.has((el as HTMLInputElement).type);\n const editable = el.getAttribute('contenteditable');\n if (editable !== null && editable !== 'false') return true;\n const role = el.getAttribute('role');\n return role !== null && KEY_CONSUMING_ROLES.has(role);\n}\n\n/** Whether `el` is a nested composite widget (own roving container or a composite role). */\nfunction isNestedComposite(el: Element): boolean {\n return el.matches(COMPOSITE_SELECTOR);\n}\n\n/** Whether `node` is strictly inside a nested composite of `grid` (the composite root excluded). */\nfunction isInsideNestedComposite(node: Element, grid: HTMLTableElement): boolean {\n if (node === grid) return false;\n for (let el = node.parentElement; el && el !== grid; el = el.parentElement) {\n if (isNestedComposite(el)) return true;\n }\n return false;\n}\n\n/**\n * The element a nested composite is entered at: its own tab stop (`tabindex=\"0\"`), else its first\n * tabbable element (the root itself when it is the focusable element).\n */\nfunction getCompositeEntry(composite: HTMLElement): HTMLElement | null {\n const stop = composite.querySelector<HTMLElement>('[tabindex=\"0\"]');\n if (stop && isFocusable(stop)) return stop;\n return getFirstTabbable(composite, { includeContainer: true });\n}\n\n/**\n * A cheap focusability check for cells that do not hold the tab stop: no style reads, only the\n * attributes that take an element out of the focus order. The cell that holds (or receives) the tab\n * stop is checked precisely with `isFocusable`.\n */\nfunction isLikelyFocusable(el: HTMLElement): boolean {\n if (el.localName === 'input' && (el as HTMLInputElement).type === 'hidden') return false;\n if (el.matches(':disabled')) return false;\n return el.closest('[hidden], [inert]') === null;\n}\n\n/** Whether another radio of `radio`'s named group is checked (the browser's tab stop of the group). */\nfunction hasCheckedPeer(radio: HTMLInputElement): boolean {\n if (!radio.name) return false;\n const root = radio.getRootNode() as Document | ShadowRoot;\n if (typeof root.querySelectorAll !== 'function') return false;\n const checked = root.querySelectorAll<HTMLInputElement>('input[type=\"radio\"]:checked');\n for (const other of Array.from(checked)) {\n if (other !== radio && other.name === radio.name && other.form === radio.form) return true;\n }\n return false;\n}\n\nfunction isCellElement(el: Element): el is HTMLTableCellElement {\n return el.localName === 'td' || el.localName === 'th';\n}\n\n/** The cell of `grid` that contains `node` (a nested table's cells belong to the outer cell). */\nfunction getCell(grid: HTMLTableElement, node: EventTarget | null): HTMLTableCellElement | null {\n let el: Element | null = node instanceof Element ? node : null;\n while (el && el !== grid) {\n if (isCellElement(el) && el.closest('table') === grid) return el;\n el = el.parentElement;\n }\n return null;\n}\n\n/** The rows of `grid` (header, body and footer rows; a nested table's rows are not included). */\nfunction getRows(grid: HTMLTableElement): HTMLTableRowElement[] {\n return Array.from(grid.rows).filter((row) => row.cells.length > 0 && !row.hidden);\n}\n\n/** Browsers clamp `colSpan` to 1..1000 (`rowSpan` 0 covers the rest of its row group). */\nconst MAX_COL_SPAN = 1000;\n\n/** Per row, the cell covering each visual column (see {@link getColumnMap}). */\ntype ColumnMap = ReadonlyArray<ReadonlyArray<HTMLTableCellElement | undefined>>;\n\n/**\n * The HTML table model of `rows`: per row, the cell covering each visual column, with `colSpan` and\n * `rowSpan` counted. A row span covers the next rows of its row group in the DOM (a hidden row\n * counts, but gets no entry). A column no cell covers is empty. O(number of cells).\n */\nfunction getColumnMap(rows: readonly HTMLTableRowElement[]): ColumnMap {\n const indexOf = new Map<Element, number>(rows.map((row, index) => [row, index]));\n const map: Array<Array<HTMLTableCellElement | undefined>> = rows.map(() => []);\n const cover = (rowIndex: number, column: number, colSpan: number, cell: HTMLTableCellElement) => {\n for (let offset = 0; offset < colSpan; offset += 1) map[rowIndex][column + offset] = cell;\n };\n rows.forEach((row, rowIndex) => {\n const own = map[rowIndex];\n let column = 0;\n for (const cell of Array.from(row.cells)) {\n while (own[column]) column += 1;\n const colSpan = Math.min(Math.max(cell.colSpan, 1), MAX_COL_SPAN);\n cover(rowIndex, column, colSpan, cell);\n let remaining = cell.rowSpan === 0 ? Infinity : cell.rowSpan - 1;\n for (\n let next = row.nextElementSibling;\n next && remaining > 0;\n next = next.nextElementSibling\n ) {\n if (next.localName !== 'tr') continue;\n remaining -= 1;\n const covered = indexOf.get(next);\n if (covered !== undefined) cover(covered, column, colSpan, cell);\n }\n column += colSpan;\n }\n });\n return map;\n}\n\n/** The cell of a row (as {@link getColumnMap} maps it) at `column`, else the last one before it. */\nfunction getCellAtColumn(\n rowMap: ReadonlyArray<HTMLTableCellElement | undefined>,\n column: number,\n): HTMLTableCellElement | null {\n for (let index = Math.min(column, rowMap.length - 1); index >= 0; index -= 1) {\n const cell = rowMap[index];\n if (cell) return cell;\n }\n return null;\n}\n\n/** The grid cells in `node` (itself, or its descendants that belong to `grid`). */\nfunction collectCells(grid: HTMLTableElement, node: Node, into: Set<HTMLTableCellElement>): void {\n if (!(node instanceof Element)) return;\n if (isCellElement(node) && node.closest('table') === grid) into.add(node);\n for (const el of Array.from(node.querySelectorAll<HTMLTableCellElement>('td, th'))) {\n if (el.closest('table') === grid) into.add(el);\n }\n}\n\n/** A widget of a cell: a focusable element, or a nested composite counted as one widget. */\ninterface CellWidget {\n /** The focusable element, or the nested composite's root. */\n element: HTMLElement;\n /** A nested composite: the grid never writes `tabindex` on or inside it. */\n composite: boolean;\n}\n\n/**\n * Grid keyboard model of the APG Grid pattern for a `<table role=\"grid\">` (DataGrid).\n *\n * - **One tab stop.** Exactly one cell of the grid is in the tab order (initially the first cell).\n * Its focus target is its only focusable widget when that widget is not a text-entry control\n * (a checkbox, a sort button, a link); otherwise — no widget, several widgets, a text-entry\n * control or a nested composite — the cell itself. An unchecked radio whose named group has a\n * checked radio is not a target either (browsers skip it in the Tab order), so its cell is.\n * Every other cell and every widget inside a cell gets `tabindex=\"-1\"`. Rows are never focusable.\n * When a widget becomes the target of the focused cell (Space on the cell checks its radio), the\n * cell keeps focus and the tab stop (removing its `tabindex` would blur it) while its target stays\n * at `tabindex=\"-1\"`; the target takes the tab stop once the cell is blurred.\n * - **Navigation mode** (focus on a cell or on its target widget): ArrowLeft/ArrowRight (the\n * previous/next cell of the row, mirrored in RTL), ArrowUp/ArrowDown, Home/End (first/last cell\n * of the row), Ctrl+Home/Ctrl+End (first cell of the grid / last cell of the last row) and\n * PageUp/PageDown ({@link UseGridNavigationOptions.pageSize} rows) move focus between cells.\n * ArrowUp/ArrowDown and PageUp/PageDown keep the visual column (`colSpan` and `rowSpan` counted,\n * so a grouped header works), clamped to a shorter row. Space and Enter on a target widget reach\n * the widget.\n * - **Interaction mode**: Enter or F2 on a cell that is its own target moves focus into its first\n * widget; clicking a widget that is not the cell's target (a text input) enters it too. The\n * grid keys are then ignored, so the arrow keys move the caret, and Tab moves between the cell's\n * widgets. Escape returns focus to the cell. Leaving the grid ends interaction mode.\n * - **Nested composites** (an element with `data-roving-container` or role toolbar, radiogroup,\n * listbox, grid, treegrid, tablist, menu, menubar or tree) count as one widget that uses the arrow\n * keys: its cell takes focus, and Enter/F2 enters the composite at its own tab stop. The grid never\n * writes `tabindex` on or inside a composite (the composite manages its own), so a composite\n * keeps its own Tab stop — the same documented limitation as `useRovingTabIndex`.\n *\n * Keys are ignored when the event's default was prevented (a widget that handled the key, a\n * consumer handler), or with Alt/Meta held. The tab indexes are written to the DOM (layout effect\n * plus a `MutationObserver`), so rows and widgets added later are covered without a re-render. Focus\n * moves re-sync only the cells involved, the observer only the cells that changed, and the grid's\n * own `tabindex` writes do not trigger a re-sync.\n *\n * Internal to the table package.\n */\nexport function useGridNavigation(options: UseGridNavigationOptions = {}): UseGridNavigationResult {\n const pageSize = Math.max(1, options.pageSize ?? 10);\n const [grid, setGrid] = React.useState<HTMLTableElement | null>(null);\n /** The cell that holds the tab stop. */\n const activeCellRef = React.useRef<HTMLTableCellElement | null>(null);\n /** The cell whose widgets are being interacted with, or `null` (navigation mode). */\n const interactionCellRef = React.useRef<HTMLTableCellElement | null>(null);\n /** Elements whose `tabindex` this hook wrote. */\n const [stamped] = React.useState(() => new WeakSet<Element>());\n /** The `tabindex` value this hook last wrote per element (`null`: removed), to skip own records. */\n const [written] = React.useState(() => new WeakMap<Element, string | null>());\n /**\n * Cells kept focusable (holding the tab stop, their target at -1) because they were focused when\n * a widget became their target (a radio that got checked, a widget added): they lose the\n * attribute once blurred.\n */\n const [retained] = React.useState(() => new WeakSet<Element>());\n const pageSizeRef = React.useRef(pageSize);\n\n React.useLayoutEffect(() => {\n pageSizeRef.current = pageSize;\n }, [pageSize]);\n\n /**\n * The widgets of `cell` in DOM order. `precise` checks focusability with `isFocusable` (style\n * reads); otherwise only attributes are checked (cells that do not hold the tab stop).\n */\n const getWidgets = React.useCallback(\n (cell: HTMLTableCellElement, precise: boolean): CellWidget[] => {\n const widgets: CellWidget[] = [];\n let composite: HTMLElement | null = null;\n for (const el of Array.from(cell.querySelectorAll<HTMLElement>(WIDGET_CANDIDATE_SELECTOR))) {\n // Descendants of a nested composite belong to it (candidates come in document order).\n if (composite && composite.contains(el)) continue;\n if (isNestedComposite(el)) {\n composite = el;\n const available = precise ? getCompositeEntry(el) !== null : isLikelyFocusable(el);\n if (available) widgets.push({ element: el, composite: true });\n continue;\n }\n const tabIndex = el.getAttribute('tabindex');\n // An author tabindex=\"-1\" (not written by this hook) opts the element out.\n if (tabIndex !== null && Number(tabIndex) < 0 && !stamped.has(el)) continue;\n if (precise ? isFocusable(el) : isLikelyFocusable(el)) {\n widgets.push({ element: el, composite: false });\n }\n }\n return widgets;\n },\n [stamped],\n );\n\n /**\n * The element of `cell` that takes focus in navigation mode. `checkRadioGroup` applies the radio\n * group rule, which only decides where the tab stop goes (the cell that holds it); a focused\n * lone radio is in navigation mode either way.\n */\n const getTarget = React.useCallback(\n (cell: HTMLTableCellElement, widgets: CellWidget[], checkRadioGroup: boolean): HTMLElement => {\n if (widgets.length !== 1) return cell;\n const [{ element, composite }] = widgets;\n if (composite || isTextEntryElement(element)) return cell;\n if (\n checkRadioGroup &&\n element instanceof HTMLInputElement &&\n element.type === 'radio' &&\n !element.checked &&\n hasCheckedPeer(element)\n ) {\n return cell;\n }\n return element;\n },\n [],\n );\n\n const setTabIndex = React.useCallback(\n (el: HTMLElement, value: 0 | -1) => {\n const next = String(value);\n if (el.getAttribute('tabindex') !== next) {\n written.set(el, next);\n el.setAttribute('tabindex', next);\n }\n stamped.add(el);\n },\n [stamped, written],\n );\n\n /** Writes the tab indexes of one cell and its widgets (only attributes that change). */\n const syncCell = React.useCallback(\n (cell: HTMLTableCellElement, isActive: boolean, isInteraction: boolean) => {\n const widgets = getWidgets(cell, isActive);\n if (isInteraction) {\n retained.delete(cell);\n setTabIndex(cell, -1);\n for (const widget of widgets) {\n if (!widget.composite) setTabIndex(widget.element, 0);\n }\n return;\n }\n const target = getTarget(cell, widgets, isActive);\n /** The focused cell stands in for its target until it is blurred (see below). */\n let keepCell = false;\n if (target === cell) {\n retained.delete(cell);\n setTabIndex(cell, isActive ? 0 : -1);\n } else if (stamped.has(cell) && isFocused(cell)) {\n // A widget became the focused cell's target (its radio got checked, a widget was added).\n // Removing the tabindex of the focused element blurs it (browsers move focus to the body,\n // which ends the grid session), so the cell stays focusable and stays the grid's position.\n // It keeps the tab stop (`tabindex=\"0\"`, when active) and its target stays at -1: the grid\n // still has exactly one Tab stop even if focus is lost without a focusout, and Tab and\n // Shift+Tab from the cell leave the grid (nothing after or before it inside is tabbable).\n // Once the cell is blurred, onBlur re-syncs it and the target takes the tab stop.\n keepCell = true;\n retained.add(cell);\n setTabIndex(cell, isActive ? 0 : -1);\n } else if (stamped.has(cell)) {\n // The cell's widget is its target: the cell itself is not focusable.\n retained.delete(cell);\n stamped.delete(cell);\n if (cell.hasAttribute('tabindex')) {\n written.set(cell, null);\n cell.removeAttribute('tabindex');\n }\n }\n for (const widget of widgets) {\n if (widget.composite) continue;\n const isStop = widget.element === target && isActive && !keepCell;\n setTabIndex(widget.element, isStop ? 0 : -1);\n }\n },\n [getTarget, getWidgets, retained, setTabIndex, stamped, written],\n );\n\n /**\n * Re-resolves the active cell (the first cell when it is gone) and syncs `cells` — every cell\n * when omitted. A new active cell is always synced.\n */\n const sync = React.useCallback(\n (table: HTMLTableElement, cells?: Iterable<HTMLTableCellElement | null>) => {\n const rows = getRows(table);\n let active = activeCellRef.current;\n const targets = new Set<HTMLTableCellElement>();\n if (\n !active ||\n !active.isConnected ||\n !rows.includes(active.parentElement as HTMLTableRowElement)\n ) {\n active = rows[0]?.cells[0] ?? null;\n activeCellRef.current = active;\n if (active) targets.add(active);\n }\n if (interactionCellRef.current !== null && interactionCellRef.current !== active) {\n const previous = interactionCellRef.current;\n interactionCellRef.current = null;\n targets.add(previous);\n }\n const interaction = interactionCellRef.current;\n\n if (cells === undefined) {\n for (const row of rows) for (const cell of Array.from(row.cells)) targets.add(cell);\n } else {\n for (const cell of cells) if (cell) targets.add(cell);\n }\n for (const cell of targets) {\n if (!cell.isConnected || getCell(table, cell) !== cell) continue;\n syncCell(cell, cell === active, cell === interaction);\n }\n },\n [syncCell],\n );\n\n React.useLayoutEffect(() => {\n if (!grid) return;\n sync(grid);\n if (typeof MutationObserver === 'undefined') return;\n const observer = new MutationObserver((records) => {\n let relevant = false;\n let all = false;\n const dirty = new Set<HTMLTableCellElement>();\n for (const record of records) {\n const target = record.target;\n if (!(target instanceof Element)) continue;\n // A nested composite manages its own items (and their tab indexes).\n if (isInsideNestedComposite(target, grid)) continue;\n if (record.type === 'attributes') {\n // The record of one of our own writes.\n if (\n record.attributeName === 'tabindex' &&\n written.has(target) &&\n written.get(target) === target.getAttribute('tabindex')\n ) {\n continue;\n }\n relevant = true;\n const cell = getCell(grid, target);\n if (cell) dirty.add(cell);\n else if (target.localName === 'tr') collectCells(grid, target, dirty);\n else all = true;\n continue;\n }\n relevant = true;\n const cell = getCell(grid, target);\n if (cell) {\n dirty.add(cell);\n continue;\n }\n // Rows, sections or cells added (removed ones need no sync; `sync` re-resolves the\n // active cell when it went away).\n for (const node of Array.from(record.addedNodes)) collectCells(grid, node, dirty);\n }\n if (!relevant) return;\n // The active cell's target can depend on other cells (a radio group whose checked radio\n // changed, reflected by the rows' `aria-selected`), so it is always re-checked.\n if (activeCellRef.current) dirty.add(activeCellRef.current);\n sync(grid, all ? undefined : dirty);\n });\n observer.observe(grid, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n return () => observer.disconnect();\n }, [grid, sync, written]);\n\n /**\n * Makes `cell` the active cell (in interaction mode when `interaction`) and re-syncs only the\n * cells involved: the previous active and interaction cells and `cell`.\n */\n const activate = React.useCallback(\n (table: HTMLTableElement, cell: HTMLTableCellElement, interaction: boolean) => {\n const previousActive = activeCellRef.current;\n const previousInteraction = interactionCellRef.current;\n activeCellRef.current = cell;\n interactionCellRef.current = interaction ? cell : null;\n sync(table, [previousActive, previousInteraction, cell]);\n },\n [sync],\n );\n\n const focusCell = React.useCallback(\n (table: HTMLTableElement, cell: HTMLTableCellElement) => {\n activate(table, cell, false);\n getTarget(cell, getWidgets(cell, true), true).focus();\n },\n [activate, getTarget, getWidgets],\n );\n\n const onKeyDown = React.useCallback<React.KeyboardEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n if (event.defaultPrevented) return;\n const cell = getCell(table, event.target);\n if (!cell) return;\n const widgets = getWidgets(cell, true);\n // A lone non-text widget is in navigation mode when focused, even an unchecked radio that\n // the radio group rule keeps from holding the tab stop.\n const widgetTarget = getTarget(cell, widgets, false);\n const onCell = event.target === cell;\n\n if (!onCell && event.target !== widgetTarget) {\n // Interaction mode: the widget keeps its keys; Escape returns to the cell.\n if (event.key === 'Escape') {\n event.preventDefault();\n focusCell(table, cell);\n }\n return;\n }\n if (event.altKey || event.metaKey) return;\n\n if ((event.key === 'Enter' || event.key === 'F2') && onCell) {\n let entry: HTMLElement | null = null;\n for (const widget of widgets) {\n entry = widget.composite ? getCompositeEntry(widget.element) : widget.element;\n if (entry) break;\n }\n if (!entry) return;\n event.preventDefault();\n activate(table, cell, true);\n entry.focus();\n return;\n }\n\n const rows = getRows(table);\n const rowIndex = rows.findIndex((row) => row === cell.parentElement);\n if (rowIndex < 0) return;\n const columnIndex = Array.from(rows[rowIndex].cells).indexOf(cell);\n const lastRow = rows.length - 1;\n const ctrl = event.ctrlKey;\n /** Left/Right, Home/End: target row and cell index in it (`Infinity`: the row's last cell). */\n let next: [row: number, column: number] | null = null;\n /** Up/Down, PageUp/PageDown: the first row to try and the direction to keep going in. */\n let vertical: [row: number, step: 1 | -1] | null = null;\n\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n if (ctrl) break;\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(table),\n });\n next = [rowIndex, columnIndex + (intent === 'next' ? 1 : -1)];\n break;\n }\n case 'ArrowDown':\n if (!ctrl) vertical = [rowIndex + 1, 1];\n break;\n case 'ArrowUp':\n if (!ctrl) vertical = [rowIndex - 1, -1];\n break;\n case 'Home':\n next = ctrl ? [0, 0] : [rowIndex, 0];\n break;\n case 'End':\n next = ctrl ? [lastRow, Infinity] : [rowIndex, Infinity];\n break;\n case 'PageDown':\n if (!ctrl) vertical = [Math.min(rowIndex + pageSizeRef.current, lastRow), 1];\n break;\n case 'PageUp':\n if (!ctrl) vertical = [Math.max(rowIndex - pageSizeRef.current, 0), -1];\n break;\n default:\n break;\n }\n if (!next && !vertical) return;\n // A handled key never scrolls the page or reaches the widget, even at the grid's edge.\n event.preventDefault();\n let destination: HTMLTableCellElement | null = null;\n if (vertical) {\n // Up/Down keep the visual column (spans counted), clamped to a shorter row; the rows a\n // row-spanning cell covers are skipped when moving away from it.\n const columns = getColumnMap(rows);\n const column = Math.max(columns[rowIndex].indexOf(cell), 0);\n for (let row = vertical[0]; row >= 0 && row <= lastRow; row += vertical[1]) {\n const candidate = getCellAtColumn(columns[row], column);\n if (candidate && candidate !== cell) {\n destination = candidate;\n break;\n }\n }\n } else if (next) {\n // Left/Right stop at the row's edges (no cell there).\n const [nextRow, nextColumn] = next;\n const rowCells = rows[nextRow].cells;\n destination =\n nextColumn === Infinity ? rowCells[rowCells.length - 1] : rowCells.item(nextColumn);\n }\n if (destination && destination !== cell) focusCell(table, destination);\n },\n [activate, focusCell, getTarget, getWidgets],\n );\n\n const onFocus = React.useCallback<React.FocusEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n // React types `target` as the handler's element type; it is the focused descendant.\n const target: EventTarget = event.target;\n const cell = getCell(table, target);\n if (!cell) return;\n const interaction =\n target !== cell && target !== getTarget(cell, getWidgets(cell, true), false);\n activate(table, cell, interaction);\n },\n [activate, getTarget, getWidgets],\n );\n\n const onBlur = React.useCallback<React.FocusEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n // React types `target` as the handler's element type; it is the blurred descendant.\n const left: EventTarget = event.target;\n const cells: HTMLTableCellElement[] = [];\n // A cell kept focusable while focused (see syncCell) is re-synced now that it is blurred\n // (during focusout the blurred element is no longer the active element).\n if (left instanceof Element && isCellElement(left) && retained.has(left)) cells.push(left);\n const next = event.relatedTarget;\n const interaction = interactionCellRef.current;\n if (interaction !== null && !(next instanceof Node && table.contains(next))) {\n interactionCellRef.current = null;\n cells.push(interaction);\n }\n if (cells.length > 0) sync(table, cells);\n },\n [retained, sync],\n );\n\n const gridProps = React.useMemo<GridNavigationHandlers>(\n () => ({ onKeyDown, onFocus, onBlur }),\n [onBlur, onFocus, onKeyDown],\n );\n\n return { gridRef: setGrid, gridProps };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useGridNavigation.cjs","names":["FOCUSABLE_SELECTOR","isFocusable","getFirstTabbable","React","isFocused","getArrowIntent","getDirection","require_runtime","require_direction","require_focus","react","NON_TEXT_INPUT_TYPES","KEY_CONSUMING_ROLES","COMPOSITE_SELECTOR","role","WIDGET_CANDIDATE_SELECTOR","AUXILIARY_ATTRIBUTE","ROW_INDEX_ATTRIBUTE","OBSERVED_ATTRIBUTES","isTextEntryElement","tag","el","editable","isNestedComposite","isInsideNestedComposite","node","grid","getCompositeEntry","stop","composite","isLikelyFocusable","hasCheckedPeer","radio","root","checked","other","isCellElement","getCell","getRows","row","MAX_COL_SPAN","getColumnMap","indexOf","rows","index","map","cover","offset","colSpan","rowIndex","column","cell","own","remaining","next","covered","getCellAtColumn","rowMap","getRowIndex","value","toCount","getGridRows","model","headerRowCount","headers","locateCell","at","getNearestRowCell","nearest","distance","placeActiveRow","mounted","activeRow","rowCount","each","current","getDeepActiveElement","active","doc","GridRowIndexes","listener","pending","getNoRow","collectCells","into","getWidgetEntry","widget","getAuxiliaryEntry","widgets","entry","isInteractionFocus","focused","target","interactionCell","cellReturns","returnFocusToGridCell","element","returnTo","useGridNavigation","options","pageSize","setGrid","modelRef","activeRowRef","pendingRef","rowIndexes","activeRowIndex","pendingRowIndex","activeCellRef","interactionCellRef","stamped","written","retained","pageSizeRef","getWidgets","precise","tabIndex","getTarget","only","checkRadioGroup","setTabIndex","syncCell","isActive","isInteraction","keepCell","isStop","publish","sync","currentModel","table","targets","gone","placed","previous","interaction","cells","skipped","activate","previousActive","previousInteraction","focusCell","requestRow","resolvePending","focusInGrid","moveByRow","last","columns","from","start","step","single","key","position","candidate","observer","relevant","all","dirty","record","records","onKeyDown","event","widgetTarget","onCell","auxiliaryEntry","columnIndex","lastRow","ctrl","vertical","destination","nextRow","nextColumn","rowCells","onFocus","onBlur","left"],"sources":["../../../src/components/table/useGridNavigation.ts"],"sourcesContent":["import * as React from 'react';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { FOCUSABLE_SELECTOR, getFirstTabbable, isFocusable, isFocused } from '../../lib/focus';\n\n/**\n * The data behind the rows of a windowed grid, whose rows are mounted only in part (see\n * {@link UseGridNavigationOptions.model}). Each mounted data row carries its 0-based index in the\n * data as `data-row-index`.\n */\nexport interface GridNavigationModel {\n /** How many data rows there are, mounted or not. */\n rowCount: number;\n /**\n * How many header rows are above the data rows: the first rows of the grid without a\n * `data-row-index` (they stay mounted). Other rows without one, such as the spacer rows of a\n * window, are not navigated.\n */\n headerRowCount: number;\n /**\n * Brings data row `index` into the mounted rows (scrolls the window to it). Called once for each\n * row a key moves focus to that is not mounted; focus moves to the row's cell in the commit that\n * mounts it. Ctrl+Home in a grid with header rows also calls it for row 0, so the first rows\n * show under the header.\n */\n scrollToRow(index: number): void;\n}\n\n/** Options of {@link useGridNavigation}. */\nexport interface UseGridNavigationOptions {\n /**\n * How many rows PageUp and PageDown move focus.\n * @default 10\n */\n pageSize?: number;\n /**\n * The data of a windowed grid (DataGrid with a virtual window). ArrowUp/ArrowDown,\n * PageUp/PageDown and Ctrl+Home/Ctrl+End then move by the rows of the data: a target row that is\n * not mounted is asked for with `scrollToRow` and focused when it mounts. The active row is kept\n * by its index (see {@link UseGridNavigationResult.activeRowIndex}). Without it, the mounted\n * rows are the whole grid.\n */\n model?: GridNavigationModel;\n}\n\n/** Handlers {@link useGridNavigation} needs on the grid element (compose them with the consumer's). */\nexport interface GridNavigationHandlers {\n onKeyDown: React.KeyboardEventHandler<HTMLTableElement>;\n onFocus: React.FocusEventHandler<HTMLTableElement>;\n onBlur: React.FocusEventHandler<HTMLTableElement>;\n}\n\n/** Result of {@link useGridNavigation}. */\nexport interface UseGridNavigationResult {\n /** Callback ref for the `<table role=\"grid\">` element. Stable identity. */\n gridRef: React.RefCallback<HTMLTableElement>;\n /** Keyboard and focus handlers for the grid element. Stable identities. */\n gridProps: GridNavigationHandlers;\n /**\n * With a `model`: the `data-row-index` of the active cell's row, the row that holds the grid's\n * tab stop (or takes it back once it is mounted again), so the owner keeps that row mounted.\n * `null` on a header row, and always `null` without a model. A change re-renders the owner.\n */\n activeRowIndex: number | null;\n /**\n * With a `model`: the index of the data row a key moved focus to while it is not mounted (asked\n * for with `scrollToRow`); focus moves there in the commit that mounts it, so the owner keeps it\n * mounted too. `null` when no row is awaited, and always `null` without a model. A change\n * re-renders the owner.\n */\n pendingRowIndex: number | null;\n}\n\n/** Input types that do not take arrow or character keys, so a lone one can be a cell's focus target. */\nconst NON_TEXT_INPUT_TYPES: ReadonlySet<string> = new Set([\n 'checkbox',\n 'radio',\n 'button',\n 'submit',\n 'reset',\n 'image',\n 'file',\n 'color',\n]);\n\n/** Widget roles that use arrow or character keys themselves (treated like text entry). */\nconst KEY_CONSUMING_ROLES: ReadonlySet<string> = new Set([\n 'textbox',\n 'searchbox',\n 'combobox',\n 'spinbutton',\n 'slider',\n]);\n\n/**\n * Roles of composite widgets that manage their own children (and usually their tab indexes): an\n * element with one of them, or with `data-roving-container`, is a nested composite. Close to the\n * list of `useRovingTabIndex`, which is kept separately and differs on purpose: here a `toolbar`\n * is a composite (a toolbar in a cell is one widget), while `spinbutton` is not (it is one\n * focusable control that uses the arrow keys, handled by `KEY_CONSUMING_ROLES` like a text\n * field). Keep both lists in mind when adding a role.\n */\nconst COMPOSITE_ROLES: readonly string[] = [\n 'toolbar',\n 'radiogroup',\n 'listbox',\n 'grid',\n 'treegrid',\n 'tablist',\n 'menu',\n 'menubar',\n 'tree',\n];\n\nconst COMPOSITE_SELECTOR = [\n '[data-roving-container]',\n ...COMPOSITE_ROLES.map((role) => `[role=\"${role}\"]`),\n].join(', ');\n\n/** Every element that can be a cell widget: a focusable element or a nested composite root. */\nconst WIDGET_CANDIDATE_SELECTOR = `${FOCUSABLE_SELECTOR}, ${COMPOSITE_SELECTOR}`;\n\n/**\n * Marks an auxiliary widget (a column's resize handle): a widget of its cell that never decides the\n * cell's target and is entered with F2.\n */\nconst AUXILIARY_ATTRIBUTE = 'data-grid-auxiliary';\n\n/** The attribute of a windowed grid's data rows that holds their 0-based index in the data. */\nconst ROW_INDEX_ATTRIBUTE = 'data-row-index';\n\n/**\n * Attributes whose changes can change a cell's widgets or the grid's rows. `aria-selected` on a row\n * signals a selection change, which can change the active cell's target (radio groups). A row's\n * index changes in place when rows keyed by id are shown at other indexes (items inserted above).\n */\nconst OBSERVED_ATTRIBUTES = [\n 'disabled',\n 'tabindex',\n 'hidden',\n 'inert',\n 'type',\n 'contenteditable',\n 'role',\n 'data-roving-container',\n 'aria-selected',\n AUXILIARY_ATTRIBUTE,\n ROW_INDEX_ATTRIBUTE,\n];\n\n/**\n * Whether `el` is a text-entry control (or another widget that uses arrow keys itself): a text-like\n * `input`, `textarea`, `select`, a `contenteditable` element, or an element with role textbox,\n * searchbox, combobox, spinbutton or slider. Such widgets are never a cell's navigation target: the\n * cell takes focus and Enter/F2 moves into the widget, so the arrow keys keep moving the caret.\n */\nexport function isTextEntryElement(el: Element): boolean {\n const tag = el.localName;\n if (tag === 'textarea' || tag === 'select') return true;\n if (tag === 'input') return !NON_TEXT_INPUT_TYPES.has((el as HTMLInputElement).type);\n const editable = el.getAttribute('contenteditable');\n if (editable !== null && editable !== 'false') return true;\n const role = el.getAttribute('role');\n return role !== null && KEY_CONSUMING_ROLES.has(role);\n}\n\n/** Whether `el` is a nested composite widget (own roving container or a composite role). */\nfunction isNestedComposite(el: Element): boolean {\n return el.matches(COMPOSITE_SELECTOR);\n}\n\n/** Whether `node` is strictly inside a nested composite of `grid` (the composite root excluded). */\nfunction isInsideNestedComposite(node: Element, grid: HTMLTableElement): boolean {\n if (node === grid) return false;\n for (let el = node.parentElement; el && el !== grid; el = el.parentElement) {\n if (isNestedComposite(el)) return true;\n }\n return false;\n}\n\n/**\n * The element a nested composite is entered at: its own tab stop (`tabindex=\"0\"`), else its first\n * tabbable element (the root itself when it is the focusable element).\n */\nfunction getCompositeEntry(composite: HTMLElement): HTMLElement | null {\n const stop = composite.querySelector<HTMLElement>('[tabindex=\"0\"]');\n if (stop && isFocusable(stop)) return stop;\n return getFirstTabbable(composite, { includeContainer: true });\n}\n\n/**\n * A cheap focusability check for cells that do not hold the tab stop: no style reads, only the\n * attributes that take an element out of the focus order. The cell that holds (or receives) the tab\n * stop is checked precisely with `isFocusable`.\n */\nfunction isLikelyFocusable(el: HTMLElement): boolean {\n if (el.localName === 'input' && (el as HTMLInputElement).type === 'hidden') return false;\n if (el.matches(':disabled')) return false;\n return el.closest('[hidden], [inert]') === null;\n}\n\n/** Whether another radio of `radio`'s named group is checked (the browser's tab stop of the group). */\nfunction hasCheckedPeer(radio: HTMLInputElement): boolean {\n if (!radio.name) return false;\n const root = radio.getRootNode() as Document | ShadowRoot;\n if (typeof root.querySelectorAll !== 'function') return false;\n const checked = root.querySelectorAll<HTMLInputElement>('input[type=\"radio\"]:checked');\n for (const other of Array.from(checked)) {\n if (other !== radio && other.name === radio.name && other.form === radio.form) return true;\n }\n return false;\n}\n\nfunction isCellElement(el: Element): el is HTMLTableCellElement {\n return el.localName === 'td' || el.localName === 'th';\n}\n\n/** The cell of `grid` that contains `node` (a nested table's cells belong to the outer cell). */\nfunction getCell(grid: HTMLTableElement, node: EventTarget | null): HTMLTableCellElement | null {\n let el: Element | null = node instanceof Element ? node : null;\n while (el && el !== grid) {\n if (isCellElement(el) && el.closest('table') === grid) return el;\n el = el.parentElement;\n }\n return null;\n}\n\n/** The rows of `grid` (header, body and footer rows; a nested table's rows are not included). */\nfunction getRows(grid: HTMLTableElement): HTMLTableRowElement[] {\n return Array.from(grid.rows).filter((row) => row.cells.length > 0 && !row.hidden);\n}\n\n/** Browsers clamp `colSpan` to 1..1000 (`rowSpan` 0 covers the rest of its row group). */\nconst MAX_COL_SPAN = 1000;\n\n/** Per row, the cell covering each visual column (see {@link getColumnMap}). */\ntype ColumnMap = ReadonlyArray<ReadonlyArray<HTMLTableCellElement | undefined>>;\n\n/**\n * The HTML table model of `rows`: per row, the cell covering each visual column, with `colSpan` and\n * `rowSpan` counted. A row span covers the next rows of its row group in the DOM (a hidden row\n * counts, but gets no entry). A column no cell covers is empty. O(number of cells).\n */\nfunction getColumnMap(rows: readonly HTMLTableRowElement[]): ColumnMap {\n const indexOf = new Map<Element, number>(rows.map((row, index) => [row, index]));\n const map: Array<Array<HTMLTableCellElement | undefined>> = rows.map(() => []);\n const cover = (rowIndex: number, column: number, colSpan: number, cell: HTMLTableCellElement) => {\n for (let offset = 0; offset < colSpan; offset += 1) map[rowIndex][column + offset] = cell;\n };\n rows.forEach((row, rowIndex) => {\n const own = map[rowIndex];\n let column = 0;\n for (const cell of Array.from(row.cells)) {\n while (own[column]) column += 1;\n const colSpan = Math.min(Math.max(cell.colSpan, 1), MAX_COL_SPAN);\n cover(rowIndex, column, colSpan, cell);\n let remaining = cell.rowSpan === 0 ? Infinity : cell.rowSpan - 1;\n for (\n let next = row.nextElementSibling;\n next && remaining > 0;\n next = next.nextElementSibling\n ) {\n if (next.localName !== 'tr') continue;\n remaining -= 1;\n const covered = indexOf.get(next);\n if (covered !== undefined) cover(covered, column, colSpan, cell);\n }\n column += colSpan;\n }\n });\n return map;\n}\n\n/** The cell of a row (as {@link getColumnMap} maps it) at `column`, else the last one before it. */\nfunction getCellAtColumn(\n rowMap: ReadonlyArray<HTMLTableCellElement | undefined>,\n column: number,\n): HTMLTableCellElement | null {\n for (let index = Math.min(column, rowMap.length - 1); index >= 0; index -= 1) {\n const cell = rowMap[index];\n if (cell) return cell;\n }\n return null;\n}\n\n/** The data row index `row` carries, or `null` (a header or spacer row, or no row). */\nfunction getRowIndex(row: Element | null): number | null {\n const value = row?.getAttribute(ROW_INDEX_ATTRIBUTE);\n return value != null && /^\\d+$/.test(value) ? Number(value) : null;\n}\n\n/** A count of a model: a whole number, at least 0 (0 when it is not finite). */\nfunction toCount(value: number): number {\n return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;\n}\n\n/**\n * The rows keys move between. With a model: the first `headerRowCount` rows without a row index\n * that are not `aria-hidden` (the header rows) and every row with one (the data rows); other rows,\n * the spacer rows of a window, are left out.\n */\nfunction getGridRows(\n grid: HTMLTableElement,\n model: GridNavigationModel | undefined,\n): HTMLTableRowElement[] {\n if (!model) return getRows(grid);\n const headerRowCount = toCount(model.headerRowCount);\n let headers = 0;\n return getRows(grid).filter((row) => {\n if (getRowIndex(row) !== null) return true;\n if (headers >= headerRowCount || row.getAttribute('aria-hidden') === 'true') return false;\n headers += 1;\n return true;\n });\n}\n\n/**\n * With a model, the active cell by its row and visual column, so the tab stop survives the row\n * unmounting: the row's element while it is mounted, and its data row index (`null`: a header row).\n */\ninterface ActiveRow {\n row: HTMLTableRowElement | null;\n index: number | null;\n column: number;\n}\n\n/** With a model, a data row a key moved to that is not mounted yet. */\ninterface PendingRow {\n index: number;\n /** The visual column to focus there (`Infinity`: the row's last cell). */\n column: number;\n}\n\n/** The row and visual column of `cell` among `rows` (column 0 for a cell outside them). */\nfunction locateCell(rows: readonly HTMLTableRowElement[], cell: HTMLTableCellElement): ActiveRow {\n const row = cell.parentElement as HTMLTableRowElement;\n const at = rows.indexOf(row);\n return {\n row: at < 0 ? null : row,\n index: getRowIndex(row),\n column: at < 0 ? 0 : Math.max(getColumnMap(rows)[at].indexOf(cell), 0),\n };\n}\n\n/** The cell at visual `column` of the mounted data row nearest to `index` (`null`: none). */\nfunction getNearestRowCell(\n rows: readonly HTMLTableRowElement[],\n index: number,\n column: number,\n): HTMLTableCellElement | null {\n let nearest = -1;\n let distance = Infinity;\n rows.forEach((row, at) => {\n const rowIndex = getRowIndex(row);\n if (rowIndex === null || Math.abs(rowIndex - index) >= distance) return;\n nearest = at;\n distance = Math.abs(rowIndex - index);\n });\n return nearest < 0 ? null : getCellAtColumn(getColumnMap(rows)[nearest], column);\n}\n\n/**\n * With a model, where `activeRow` is now and which cell holds the tab stop for it; `null` when the\n * rule without a model applies (the first cell once the active cell is gone): a header row that is\n * gone, or a data row that left the data (`rowCount`). The row is its element while that is\n * mounted (its index follows it: rows keyed by id are shown at other indexes when items are\n * inserted above), else the mounted row of its index (a row mounted again). While neither is mounted, a stand-in holds the tab stop:\n * `current` (the active cell, while it is mounted), else the cell of the nearest mounted data row\n * (`cell` is `null` when none is mounted).\n */\nfunction placeActiveRow(\n rows: readonly HTMLTableRowElement[],\n activeRow: ActiveRow,\n rowCount: number,\n current: HTMLTableCellElement | null,\n): { activeRow: ActiveRow; cell: HTMLTableCellElement | null } | null {\n const mounted = activeRow.row !== null && rows.includes(activeRow.row);\n const index = mounted ? getRowIndex(activeRow.row) : activeRow.index;\n if (index === null ? !mounted : index >= rowCount) return null;\n const row = mounted ? activeRow.row : (rows.find((each) => getRowIndex(each) === index) ?? null);\n const { column } = activeRow;\n if (!row) {\n // `index` is a data row index here (a header row is always `mounted`).\n return { activeRow, cell: current ?? getNearestRowCell(rows, index as number, column) };\n }\n const cell =\n current?.parentElement === row\n ? current\n : getCellAtColumn(getColumnMap(rows)[rows.indexOf(row)], column);\n return { activeRow: { row, index, column }, cell };\n}\n\n/** The focused element, through open shadow roots (the body, or `null`, when focus is lost). */\nfunction getDeepActiveElement(doc: Document): Element | null {\n let active = doc.activeElement;\n while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;\n return active;\n}\n\n/**\n * The row indexes of {@link UseGridNavigationResult} (`activeRowIndex`, `pendingRowIndex`), read\n * by the owner's render through `useSyncExternalStore` and written by the handlers, the observer\n * and the layout effects. Without a model it stays at `null` and never notifies.\n */\nclass GridRowIndexes {\n private active: number | null = null;\n private pending: number | null = null;\n private readonly listeners = new Set<() => void>();\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n getActive = (): number | null => this.active;\n\n getPending = (): number | null => this.pending;\n\n set(active: number | null, pending: number | null): void {\n if (active === this.active && pending === this.pending) return;\n this.active = active;\n this.pending = pending;\n for (const listener of Array.from(this.listeners)) listener();\n }\n}\n\n/** The server snapshot of the row indexes: no row. */\nconst getNoRow = (): null => null;\n\n/** The grid cells in `node` (itself, or its descendants that belong to `grid`). */\nfunction collectCells(grid: HTMLTableElement, node: Node, into: Set<HTMLTableCellElement>): void {\n if (!(node instanceof Element)) return;\n if (isCellElement(node) && node.closest('table') === grid) into.add(node);\n for (const el of Array.from(node.querySelectorAll<HTMLTableCellElement>('td, th'))) {\n if (el.closest('table') === grid) into.add(el);\n }\n}\n\n/** A widget of a cell: a focusable element, or a nested composite counted as one widget. */\ninterface CellWidget {\n /** The focusable element, or the nested composite's root. */\n element: HTMLElement;\n /** A nested composite: the grid never writes `tabindex` on or inside it. */\n composite: boolean;\n /** An auxiliary widget (`data-grid-auxiliary`): never the cell's target, entered with F2. */\n auxiliary: boolean;\n}\n\n/** The element a widget is entered at: the widget, or a nested composite's entry. */\nfunction getWidgetEntry(widget: CellWidget): HTMLElement | null {\n return widget.composite ? getCompositeEntry(widget.element) : widget.element;\n}\n\n/** The element F2 moves focus to: the entry of the cell's first auxiliary widget that has one. */\nfunction getAuxiliaryEntry(widgets: readonly CellWidget[]): HTMLElement | null {\n for (const widget of widgets) {\n const entry = widget.auxiliary ? getWidgetEntry(widget) : null;\n if (entry) return entry;\n }\n return null;\n}\n\n/**\n * Whether focus on `focused`, inside `cell` whose target is `target`, is interaction mode: on\n * anything but the cell and its target; and on its target too while the widgets of a cell with an\n * auxiliary widget are being interacted with (`interactionCell`), so Tab moves between all of them.\n */\nfunction isInteractionFocus(\n cell: HTMLTableCellElement,\n focused: EventTarget | null,\n target: HTMLElement,\n widgets: readonly CellWidget[],\n interactionCell: HTMLTableCellElement | null,\n): boolean {\n if (focused === cell) return false;\n if (focused !== target) return true;\n return interactionCell === cell && widgets.some((widget) => widget.auxiliary);\n}\n\n/**\n * The grids of mounted {@link useGridNavigation} hooks, each with the function that returns focus\n * to one of its cells, as Escape does (see {@link returnFocusToGridCell}).\n */\nconst cellReturns = new WeakMap<Element, (cell: HTMLTableCellElement) => void>();\n\n/**\n * Ends interaction mode in the grid cell that holds `element` and moves focus to the cell's target\n * (the cell, or its target widget), as Escape does: for a widget that handles Escape, Enter or\n * Space itself to leave (a DataGrid column's resize handle). Returns whether a grid of\n * {@link useGridNavigation} holds `element` in one of its cells. Module-only.\n */\nexport function returnFocusToGridCell(element: Element): boolean {\n for (let el = element.parentElement; el; el = el.parentElement) {\n const returnTo = cellReturns.get(el);\n if (!returnTo) continue;\n const cell = getCell(el as HTMLTableElement, element);\n if (!cell) return false;\n returnTo(cell);\n return true;\n }\n return false;\n}\n\n/**\n * Grid keyboard model of the APG Grid pattern for a `<table role=\"grid\">` (DataGrid).\n *\n * - **One tab stop.** Exactly one cell of the grid is in the tab order (initially the first cell).\n * Its focus target is its only focusable widget when that widget is not a text-entry control\n * (a checkbox, a sort button, a link); otherwise — no widget, several widgets, a text-entry\n * control or a nested composite — the cell itself. An unchecked radio whose named group has a\n * checked radio is not a target either (browsers skip it in the Tab order), so its cell is.\n * Every other cell and every widget inside a cell gets `tabindex=\"-1\"`. Rows are never focusable.\n * When a widget becomes the target of the focused cell (Space on the cell checks its radio), the\n * cell keeps focus and the tab stop (removing its `tabindex` would blur it) while its target stays\n * at `tabindex=\"-1\"`; the target takes the tab stop once the cell is blurred.\n * - **Navigation mode** (focus on a cell or on its target widget): ArrowLeft/ArrowRight (the\n * previous/next cell of the row, mirrored in RTL), ArrowUp/ArrowDown, Home/End (first/last cell\n * of the row), Ctrl+Home/Ctrl+End (first cell of the grid / last cell of the last row) and\n * PageUp/PageDown ({@link UseGridNavigationOptions.pageSize} rows) move focus between cells.\n * ArrowUp/ArrowDown and PageUp/PageDown keep the visual column (`colSpan` and `rowSpan` counted,\n * so a grouped header works), clamped to a shorter row. Space and Enter on a target widget reach\n * the widget.\n * - **Interaction mode**: Enter or F2 on a cell that is its own target moves focus into its first\n * widget; clicking a widget that is not the cell's target (a text input) enters it too. The\n * grid keys are then ignored, so the arrow keys move the caret, and Tab moves between the cell's\n * widgets. Escape returns focus to the cell. Leaving the grid ends interaction mode.\n * - **Nested composites** (an element with `data-roving-container` or role toolbar, radiogroup,\n * listbox, grid, treegrid, tablist, menu, menubar or tree) count as one widget that uses the arrow\n * keys: its cell takes focus, and Enter/F2 enters the composite at its own tab stop. The grid never\n * writes `tabindex` on or inside a composite (the composite manages its own), so a composite\n * keeps its own Tab stop — the same documented limitation as `useRovingTabIndex`.\n * - **Auxiliary widgets** (a widget that carries `data-grid-auxiliary`, such as a column's resize\n * handle) are left out when the cell's target is chosen, so a header with a sort button and a\n * resize handle keeps the button as its target (Enter sorts), and a cell whose only widget is\n * auxiliary is its own target. Like every widget they are at `tabindex=\"-1\"` in navigation mode\n * and take part in interaction mode. F2 on a cell that has one, or on its target widget, enters\n * interaction mode at the first auxiliary widget (Enter on a cell that is its own target still\n * enters its first widget); Escape returns to the cell's target, the cell or its target widget.\n * While the widgets of such a cell are interacted with, its target widget is in interaction mode\n * too, so Tab moves between all of them and Escape on the target ends the mode. A cell without\n * auxiliary widgets behaves as described above.\n * - **Rows by their data** (a `model`: a windowed grid, whose rows are mounted in part): the rows\n * are the header rows and the data rows, which carry their index in the data as `data-row-index`\n * (other rows, such as the spacer rows of a window, are skipped). ArrowUp/ArrowDown,\n * PageUp/PageDown and Ctrl+Home/Ctrl+End go by that index over every row of the data, header\n * rows first, with the rules above: a target row that is not mounted is asked for with\n * `scrollToRow` (once per row) and focused in the commit that mounts it, and Ctrl+Home also\n * brings data row 0 back under the header rows. The active cell is kept by its row and column:\n * `activeRowIndex` and `pendingRowIndex` name the rows the owner keeps mounted, and while the\n * active row is not mounted anyway, a cell of the nearest mounted row holds the tab stop until\n * the row is back. ArrowLeft/ArrowRight and Home/End work in the row as above.\n *\n * Keys are ignored when the event's default was prevented (a widget that handled the key, a\n * consumer handler), or with Alt/Meta held. The tab indexes are written to the DOM (layout effect\n * plus a `MutationObserver`), so rows and widgets added later are covered without a re-render. Focus\n * moves re-sync only the cells involved, the observer only the cells that changed, and the grid's\n * own `tabindex` writes do not trigger a re-sync.\n */\nexport function useGridNavigation(options: UseGridNavigationOptions = {}): UseGridNavigationResult {\n const { model } = options;\n const pageSize = Math.max(1, options.pageSize ?? 10);\n const [grid, setGrid] = React.useState<HTMLTableElement | null>(null);\n /** The model of the last commit (read by the handlers, the observer and the effects). */\n const modelRef = React.useRef(model);\n /** With a model: the active cell's row and column (see {@link ActiveRow}). */\n const activeRowRef = React.useRef<ActiveRow | null>(null);\n /** With a model: the data row a key moved to that is not mounted yet. */\n const pendingRef = React.useRef<PendingRow | null>(null);\n const [rowIndexes] = React.useState(() => new GridRowIndexes());\n const activeRowIndex = React.useSyncExternalStore(\n rowIndexes.subscribe,\n rowIndexes.getActive,\n getNoRow,\n );\n const pendingRowIndex = React.useSyncExternalStore(\n rowIndexes.subscribe,\n rowIndexes.getPending,\n getNoRow,\n );\n /** The cell that holds the tab stop. */\n const activeCellRef = React.useRef<HTMLTableCellElement | null>(null);\n /** The cell whose widgets are being interacted with, or `null` (navigation mode). */\n const interactionCellRef = React.useRef<HTMLTableCellElement | null>(null);\n /** Elements whose `tabindex` this hook wrote. */\n const [stamped] = React.useState(() => new WeakSet<Element>());\n /** The `tabindex` value this hook last wrote per element (`null`: removed), to skip own records. */\n const [written] = React.useState(() => new WeakMap<Element, string | null>());\n /**\n * Cells kept focusable (holding the tab stop, their target at -1) because they were focused when\n * a widget became their target (a radio that got checked, a widget added): they lose the\n * attribute once blurred.\n */\n const [retained] = React.useState(() => new WeakSet<Element>());\n const pageSizeRef = React.useRef(pageSize);\n\n React.useLayoutEffect(() => {\n pageSizeRef.current = pageSize;\n }, [pageSize]);\n\n /**\n * The widgets of `cell` in DOM order. `precise` checks focusability with `isFocusable` (style\n * reads); otherwise only attributes are checked (cells that do not hold the tab stop).\n */\n const getWidgets = React.useCallback(\n (cell: HTMLTableCellElement, precise: boolean): CellWidget[] => {\n const widgets: CellWidget[] = [];\n let composite: HTMLElement | null = null;\n for (const el of Array.from(cell.querySelectorAll<HTMLElement>(WIDGET_CANDIDATE_SELECTOR))) {\n // Descendants of a nested composite belong to it (candidates come in document order).\n if (composite && composite.contains(el)) continue;\n if (isNestedComposite(el)) {\n composite = el;\n const available = precise ? getCompositeEntry(el) !== null : isLikelyFocusable(el);\n if (available) {\n widgets.push({\n element: el,\n composite: true,\n auxiliary: el.hasAttribute(AUXILIARY_ATTRIBUTE),\n });\n }\n continue;\n }\n const tabIndex = el.getAttribute('tabindex');\n // An author tabindex=\"-1\" (not written by this hook) opts the element out.\n if (tabIndex !== null && Number(tabIndex) < 0 && !stamped.has(el)) continue;\n if (precise ? isFocusable(el) : isLikelyFocusable(el)) {\n widgets.push({\n element: el,\n composite: false,\n auxiliary: el.hasAttribute(AUXILIARY_ATTRIBUTE),\n });\n }\n }\n return widgets;\n },\n [stamped],\n );\n\n /**\n * The element of `cell` that takes focus in navigation mode. `checkRadioGroup` applies the radio\n * group rule, which only decides where the tab stop goes (the cell that holds it); a focused\n * lone radio is in navigation mode either way. Auxiliary widgets are not counted.\n */\n const getTarget = React.useCallback(\n (cell: HTMLTableCellElement, widgets: CellWidget[], checkRadioGroup: boolean): HTMLElement => {\n let only: CellWidget | null = null;\n for (const widget of widgets) {\n if (widget.auxiliary) continue;\n if (only) return cell;\n only = widget;\n }\n if (!only) return cell;\n const { element, composite } = only;\n if (composite || isTextEntryElement(element)) return cell;\n if (\n checkRadioGroup &&\n element instanceof HTMLInputElement &&\n element.type === 'radio' &&\n !element.checked &&\n hasCheckedPeer(element)\n ) {\n return cell;\n }\n return element;\n },\n [],\n );\n\n const setTabIndex = React.useCallback(\n (el: HTMLElement, value: 0 | -1) => {\n const next = String(value);\n if (el.getAttribute('tabindex') !== next) {\n written.set(el, next);\n el.setAttribute('tabindex', next);\n }\n stamped.add(el);\n },\n [stamped, written],\n );\n\n /** Writes the tab indexes of one cell and its widgets (only attributes that change). */\n const syncCell = React.useCallback(\n (cell: HTMLTableCellElement, isActive: boolean, isInteraction: boolean) => {\n const widgets = getWidgets(cell, isActive);\n if (isInteraction) {\n retained.delete(cell);\n setTabIndex(cell, -1);\n for (const widget of widgets) {\n if (!widget.composite) setTabIndex(widget.element, 0);\n }\n return;\n }\n const target = getTarget(cell, widgets, isActive);\n /** The focused cell stands in for its target until it is blurred (see below). */\n let keepCell = false;\n if (target === cell) {\n retained.delete(cell);\n setTabIndex(cell, isActive ? 0 : -1);\n } else if (stamped.has(cell) && isFocused(cell)) {\n // A widget became the focused cell's target (its radio got checked, a widget was added).\n // Removing the tabindex of the focused element blurs it (browsers move focus to the body,\n // which ends the grid session), so the cell stays focusable and stays the grid's position.\n // It keeps the tab stop (`tabindex=\"0\"`, when active) and its target stays at -1: the grid\n // still has exactly one Tab stop even if focus is lost without a focusout, and Tab and\n // Shift+Tab from the cell leave the grid (nothing after or before it inside is tabbable).\n // Once the cell is blurred, onBlur re-syncs it and the target takes the tab stop.\n keepCell = true;\n retained.add(cell);\n setTabIndex(cell, isActive ? 0 : -1);\n } else if (stamped.has(cell)) {\n // The cell's widget is its target: the cell itself is not focusable.\n retained.delete(cell);\n stamped.delete(cell);\n if (cell.hasAttribute('tabindex')) {\n written.set(cell, null);\n cell.removeAttribute('tabindex');\n }\n }\n for (const widget of widgets) {\n if (widget.composite) continue;\n const isStop = widget.element === target && isActive && !keepCell;\n setTabIndex(widget.element, isStop ? 0 : -1);\n }\n },\n [getTarget, getWidgets, retained, setTabIndex, stamped, written],\n );\n\n /** With a model: publishes the active and the pending row index to the owner's render. */\n const publish = React.useCallback(() => {\n rowIndexes.set(activeRowRef.current?.index ?? null, pendingRef.current?.index ?? null);\n }, [rowIndexes]);\n\n /**\n * Re-resolves the active cell (the first cell when it is gone) and syncs `cells` — every cell\n * when omitted. A new active cell is always synced. With a model, an active cell that is gone\n * while its row index is in the data is replaced in its row instead (see `placeActiveRow`).\n */\n const sync = React.useCallback(\n (table: HTMLTableElement, cells?: Iterable<HTMLTableCellElement | null>) => {\n const currentModel = modelRef.current;\n const rows = getGridRows(table, currentModel);\n let active = activeCellRef.current;\n const targets = new Set<HTMLTableCellElement>();\n let gone =\n !active ||\n !active.isConnected ||\n !rows.includes(active.parentElement as HTMLTableRowElement);\n const placed =\n currentModel && activeRowRef.current\n ? placeActiveRow(\n rows,\n activeRowRef.current,\n toCount(currentModel.rowCount),\n gone ? null : active,\n )\n : null;\n if (placed) {\n activeRowRef.current = placed.activeRow;\n if (placed.cell) {\n gone = false;\n if (placed.cell !== active) {\n // The cell that held the tab stop (a stand-in) gives it up.\n if (active) targets.add(active);\n active = placed.cell;\n activeCellRef.current = active;\n targets.add(active);\n }\n }\n }\n if (gone) {\n active = rows[0]?.cells[0] ?? null;\n activeCellRef.current = active;\n if (active) targets.add(active);\n if (currentModel && !placed) activeRowRef.current = null;\n }\n if (currentModel && active && activeRowRef.current === null) {\n activeRowRef.current = locateCell(rows, active);\n }\n if (interactionCellRef.current !== null && interactionCellRef.current !== active) {\n const previous = interactionCellRef.current;\n interactionCellRef.current = null;\n targets.add(previous);\n }\n const interaction = interactionCellRef.current;\n\n if (cells === undefined) {\n for (const row of rows) for (const cell of Array.from(row.cells)) targets.add(cell);\n } else {\n for (const cell of cells) if (cell) targets.add(cell);\n }\n // With a model, the cells of rows keys skip (the spacer rows of a window) are never stamped.\n const skipped = currentModel ? new Set(rows) : null;\n for (const cell of targets) {\n if (!cell.isConnected || getCell(table, cell) !== cell) continue;\n if (\n skipped &&\n !skipped.has(cell.parentElement as HTMLTableRowElement) &&\n !stamped.has(cell)\n ) {\n continue;\n }\n syncCell(cell, cell === active, cell === interaction);\n }\n if (currentModel) publish();\n },\n [publish, stamped, syncCell],\n );\n\n /**\n * Makes `cell` the active cell (in interaction mode when `interaction`) and re-syncs only the\n * cells involved: the previous active and interaction cells and `cell`. With a model, its row is\n * the active row, and a row that was awaited is not any more (focus moved).\n */\n const activate = React.useCallback(\n (table: HTMLTableElement, cell: HTMLTableCellElement, interaction: boolean) => {\n const previousActive = activeCellRef.current;\n const previousInteraction = interactionCellRef.current;\n activeCellRef.current = cell;\n interactionCellRef.current = interaction ? cell : null;\n const currentModel = modelRef.current;\n if (currentModel) {\n activeRowRef.current = locateCell(getGridRows(table, currentModel), cell);\n pendingRef.current = null;\n }\n sync(table, [previousActive, previousInteraction, cell]);\n },\n [sync],\n );\n\n const focusCell = React.useCallback(\n (table: HTMLTableElement, cell: HTMLTableCellElement) => {\n activate(table, cell, false);\n getTarget(cell, getWidgets(cell, true), true).focus();\n },\n [activate, getTarget, getWidgets],\n );\n\n /**\n * With a model: awaits data row `index`, which is not mounted. The model scrolls to it (once per\n * row: a key pressed again before it mounts replaces the target, and asks again only for another\n * row), and focus moves to its cell at `column` once it is mounted (`resolvePending`).\n */\n const requestRow = React.useCallback(\n (index: number, column: number) => {\n const currentModel = modelRef.current;\n if (!currentModel) return;\n const previous = pendingRef.current;\n pendingRef.current = { index, column };\n publish();\n if (previous?.index !== index) currentModel.scrollToRow(index);\n },\n [publish],\n );\n\n /**\n * With a model: focuses the awaited row's cell once the row is mounted, from the layout effect of\n * the owner's commit that mounts it or from the observer (a row mounted by another component's\n * commit). The request is dropped when the row left the data, and when focus went to an element\n * outside the grid meanwhile (focus stays there).\n */\n const resolvePending = React.useCallback(\n (table: HTMLTableElement) => {\n const pending = pendingRef.current;\n const currentModel = modelRef.current;\n if (!pending || !currentModel) return;\n if (pending.index >= toCount(currentModel.rowCount)) {\n pendingRef.current = null;\n publish();\n return;\n }\n const rows = getGridRows(table, currentModel);\n const at = rows.findIndex((row) => getRowIndex(row) === pending.index);\n if (at < 0) return;\n pendingRef.current = null;\n const target = getCellAtColumn(getColumnMap(rows)[at], pending.column);\n const focused = getDeepActiveElement(table.ownerDocument);\n const focusInGrid =\n focused === null || focused === table.ownerDocument.body || table.contains(focused);\n if (target && focusInGrid) focusCell(table, target);\n else publish();\n },\n [focusCell, publish],\n );\n\n /**\n * With a model: moves focus by the rows of the data for `key` (ArrowUp/ArrowDown, PageUp/PageDown,\n * or Home/End with Ctrl held), from the awaited row while there is one, else from `cell`. The\n * header rows come first, then the data rows by index. Up/Down and PageUp/PageDown keep the\n * visual column; Ctrl+Home goes to the first cell of the grid and Ctrl+End to the last cell of the\n * last data row. A target row that is not mounted is awaited (`requestRow`).\n */\n const moveByRow = React.useCallback(\n (\n table: HTMLTableElement,\n cell: HTMLTableCellElement,\n rows: HTMLTableRowElement[],\n key: string,\n ) => {\n const currentModel = modelRef.current;\n if (!currentModel) return;\n const headers = rows.filter((row) => getRowIndex(row) === null);\n /** Where each mounted data row is in `rows`, by its index. */\n const mounted = new Map<number, number>();\n rows.forEach((row, at) => {\n const index = getRowIndex(row);\n if (index !== null) mounted.set(index, at);\n });\n const rowCount = toCount(currentModel.rowCount);\n const last = headers.length + rowCount - 1;\n const columns = getColumnMap(rows);\n const pending = pendingRef.current;\n /** The row the move starts from (header rows, then data rows) and its visual column. */\n let from: number;\n let column: number;\n if (pending) {\n from = headers.length + Math.min(pending.index, rowCount - 1);\n column = pending.column;\n } else {\n const row = cell.parentElement as HTMLTableRowElement;\n const index = getRowIndex(row);\n from = index === null ? headers.indexOf(row) : headers.length + index;\n column = Math.max(columns[rows.indexOf(row)].indexOf(cell), 0);\n }\n let start: number;\n let step: 1 | -1 = 1;\n /** Ctrl+Home and Ctrl+End go to one row (no row a spanning cell covers is skipped). */\n let single = false;\n switch (key) {\n case 'ArrowDown':\n start = from + 1;\n break;\n case 'ArrowUp':\n start = from - 1;\n step = -1;\n break;\n case 'PageDown':\n start = Math.min(from + pageSizeRef.current, last);\n break;\n case 'PageUp':\n start = Math.max(from - pageSizeRef.current, 0);\n step = -1;\n break;\n case 'Home':\n start = 0;\n column = 0;\n single = true;\n break;\n default:\n start = last;\n column = Infinity;\n single = true;\n break;\n }\n for (let position = start; position >= 0 && position <= last; position += step) {\n const at =\n position < headers.length\n ? rows.indexOf(headers[position])\n : (mounted.get(position - headers.length) ?? -1);\n if (at < 0) {\n requestRow(position - headers.length, column);\n break;\n }\n const candidate = getCellAtColumn(columns[at], column);\n // The focused cell itself is passed over (a cell spanning rows), except while a row is\n // awaited: the move starts from that row, so a key back to the focused cell targets it\n // (focusing it drops the request).\n if (candidate && (pending || candidate !== cell)) {\n focusCell(table, candidate);\n break;\n }\n if (single) break;\n }\n // Focus on a header row: the first data rows come back under it, as the top of the grid.\n if (key === 'Home' && headers.length > 0 && rowCount > 0) currentModel.scrollToRow(0);\n },\n [focusCell, requestRow],\n );\n\n React.useLayoutEffect(() => {\n if (!grid) return;\n sync(grid);\n if (typeof MutationObserver === 'undefined') return;\n const observer = new MutationObserver((records) => {\n let relevant = false;\n let all = false;\n const dirty = new Set<HTMLTableCellElement>();\n for (const record of records) {\n const target = record.target;\n if (!(target instanceof Element)) continue;\n // A nested composite manages its own items (and their tab indexes).\n if (isInsideNestedComposite(target, grid)) continue;\n if (record.type === 'attributes') {\n // The record of one of our own writes.\n if (\n record.attributeName === 'tabindex' &&\n written.has(target) &&\n written.get(target) === target.getAttribute('tabindex')\n ) {\n continue;\n }\n relevant = true;\n const cell = getCell(grid, target);\n if (cell) dirty.add(cell);\n else if (target.localName === 'tr') collectCells(grid, target, dirty);\n else all = true;\n continue;\n }\n relevant = true;\n const cell = getCell(grid, target);\n if (cell) {\n dirty.add(cell);\n continue;\n }\n // Rows, sections or cells added (removed ones need no sync; `sync` re-resolves the\n // active cell when it went away).\n for (const node of Array.from(record.addedNodes)) collectCells(grid, node, dirty);\n }\n if (!relevant) return;\n // The active cell's target can depend on other cells (a radio group whose checked radio\n // changed, reflected by the rows' `aria-selected`), so it is always re-checked.\n if (activeCellRef.current) dirty.add(activeCellRef.current);\n sync(grid, all ? undefined : dirty);\n // With a model, an awaited row mounted by a commit of another component.\n resolvePending(grid);\n });\n observer.observe(grid, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n return () => observer.disconnect();\n }, [grid, resolvePending, sync, written]);\n\n // A widget that handles its leaving keys itself returns through `returnFocusToGridCell`.\n React.useLayoutEffect(() => {\n if (!grid) return;\n const returnTo = (cell: HTMLTableCellElement) => focusCell(grid, cell);\n cellReturns.set(grid, returnTo);\n return () => {\n if (cellReturns.get(grid) === returnTo) cellReturns.delete(grid);\n };\n }, [grid, focusCell]);\n\n // After every commit: the model of this render, and focus on an awaited row that the commit\n // mounted. Without a model, no row is kept by its index.\n React.useLayoutEffect(() => {\n modelRef.current = model;\n if (!model) {\n activeRowRef.current = null;\n pendingRef.current = null;\n rowIndexes.set(null, null);\n return;\n }\n if (grid) resolvePending(grid);\n });\n\n const onKeyDown = React.useCallback<React.KeyboardEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n if (event.defaultPrevented) return;\n const cell = getCell(table, event.target);\n if (!cell) return;\n const widgets = getWidgets(cell, true);\n // A lone non-text widget is in navigation mode when focused, even an unchecked radio that\n // the radio group rule keeps from holding the tab stop.\n const widgetTarget = getTarget(cell, widgets, false);\n const onCell = event.target === cell;\n\n if (\n isInteractionFocus(cell, event.target, widgetTarget, widgets, interactionCellRef.current)\n ) {\n // Interaction mode: the widget keeps its keys; Escape returns to the cell.\n if (event.key === 'Escape') {\n event.preventDefault();\n focusCell(table, cell);\n }\n return;\n }\n if (event.altKey || event.metaKey) return;\n\n // F2 on a cell with an auxiliary widget, or on its target widget, enters the auxiliary one.\n const auxiliaryEntry = event.key === 'F2' ? getAuxiliaryEntry(widgets) : null;\n if (auxiliaryEntry) {\n event.preventDefault();\n activate(table, cell, true);\n auxiliaryEntry.focus();\n return;\n }\n\n if ((event.key === 'Enter' || event.key === 'F2') && onCell) {\n let entry: HTMLElement | null = null;\n for (const widget of widgets) {\n entry = getWidgetEntry(widget);\n if (entry) break;\n }\n if (!entry) return;\n event.preventDefault();\n activate(table, cell, true);\n entry.focus();\n return;\n }\n\n const rows = getGridRows(table, modelRef.current);\n const rowIndex = rows.findIndex((row) => row === cell.parentElement);\n if (rowIndex < 0) return;\n const columnIndex = Array.from(rows[rowIndex].cells).indexOf(cell);\n const lastRow = rows.length - 1;\n const ctrl = event.ctrlKey;\n /** Left/Right, Home/End: target row and cell index in it (`Infinity`: the row's last cell). */\n let next: [row: number, column: number] | null = null;\n /** Up/Down, PageUp/PageDown: the first row to try and the direction to keep going in. */\n let vertical: [row: number, step: 1 | -1] | null = null;\n\n switch (event.key) {\n case 'ArrowLeft':\n case 'ArrowRight': {\n if (ctrl) break;\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(table),\n });\n next = [rowIndex, columnIndex + (intent === 'next' ? 1 : -1)];\n break;\n }\n case 'ArrowDown':\n if (!ctrl) vertical = [rowIndex + 1, 1];\n break;\n case 'ArrowUp':\n if (!ctrl) vertical = [rowIndex - 1, -1];\n break;\n case 'Home':\n next = ctrl ? [0, 0] : [rowIndex, 0];\n break;\n case 'End':\n next = ctrl ? [lastRow, Infinity] : [rowIndex, Infinity];\n break;\n case 'PageDown':\n if (!ctrl) vertical = [Math.min(rowIndex + pageSizeRef.current, lastRow), 1];\n break;\n case 'PageUp':\n if (!ctrl) vertical = [Math.max(rowIndex - pageSizeRef.current, 0), -1];\n break;\n default:\n break;\n }\n if (!next && !vertical) return;\n // A handled key never scrolls the page or reaches the widget, even at the grid's edge.\n event.preventDefault();\n // With a model, Up/Down, PageUp/PageDown and Ctrl+Home/Ctrl+End go by the rows of the data.\n if (modelRef.current && (vertical || ctrl)) {\n moveByRow(table, cell, rows, event.key);\n return;\n }\n let destination: HTMLTableCellElement | null = null;\n if (vertical) {\n // Up/Down keep the visual column (spans counted), clamped to a shorter row; the rows a\n // row-spanning cell covers are skipped when moving away from it.\n const columns = getColumnMap(rows);\n const column = Math.max(columns[rowIndex].indexOf(cell), 0);\n for (let row = vertical[0]; row >= 0 && row <= lastRow; row += vertical[1]) {\n const candidate = getCellAtColumn(columns[row], column);\n if (candidate && candidate !== cell) {\n destination = candidate;\n break;\n }\n }\n } else if (next) {\n // Left/Right stop at the row's edges (no cell there).\n const [nextRow, nextColumn] = next;\n const rowCells = rows[nextRow].cells;\n destination =\n nextColumn === Infinity ? rowCells[rowCells.length - 1] : rowCells.item(nextColumn);\n }\n if (destination && destination !== cell) focusCell(table, destination);\n },\n [activate, focusCell, getTarget, getWidgets, moveByRow],\n );\n\n const onFocus = React.useCallback<React.FocusEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n // React types `target` as the handler's element type; it is the focused descendant.\n const target: EventTarget = event.target;\n const cell = getCell(table, target);\n if (!cell) return;\n let interaction = false;\n if (target !== cell) {\n const widgets = getWidgets(cell, true);\n interaction = isInteractionFocus(\n cell,\n target,\n getTarget(cell, widgets, false),\n widgets,\n interactionCellRef.current,\n );\n }\n activate(table, cell, interaction);\n },\n [activate, getTarget, getWidgets],\n );\n\n const onBlur = React.useCallback<React.FocusEventHandler<HTMLTableElement>>(\n (event) => {\n const table = event.currentTarget;\n // React types `target` as the handler's element type; it is the blurred descendant.\n const left: EventTarget = event.target;\n const cells: HTMLTableCellElement[] = [];\n // A cell kept focusable while focused (see syncCell) is re-synced now that it is blurred\n // (during focusout the blurred element is no longer the active element).\n if (left instanceof Element && isCellElement(left) && retained.has(left)) cells.push(left);\n const next = event.relatedTarget;\n const interaction = interactionCellRef.current;\n if (interaction !== null && !(next instanceof Node && table.contains(next))) {\n interactionCellRef.current = null;\n cells.push(interaction);\n }\n if (cells.length > 0) sync(table, cells);\n },\n [retained, sync],\n );\n\n const gridProps = React.useMemo<GridNavigationHandlers>(\n () => ({ onKeyDown, onFocus, onBlur }),\n [onBlur, onFocus, onKeyDown],\n );\n\n return { gridRef: setGrid, gridProps, activeRowIndex, pendingRowIndex };\n}\n"],"mappings":"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"}