@mortenbrudvik/waveui 0.15.0 → 0.16.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.
- package/README.md +274 -24
- package/dist/components/data-display/List.cjs +1 -1
- package/dist/components/data-display/List.cjs.map +1 -1
- package/dist/components/data-display/List.mjs +405 -219
- package/dist/components/data-display/List.mjs.map +1 -1
- package/dist/components/data-display/List.registry.cjs +1 -1
- package/dist/components/data-display/List.registry.cjs.map +1 -1
- package/dist/components/data-display/List.registry.mjs +12 -6
- package/dist/components/data-display/List.registry.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.mjs +163 -148
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +132 -117
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Listbox.cjs +1 -1
- package/dist/components/input/Listbox.cjs.map +1 -1
- package/dist/components/input/Listbox.mjs +90 -78
- package/dist/components/input/Listbox.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.data.cjs +2 -0
- package/dist/components/input/Option.data.cjs.map +1 -0
- package/dist/components/input/Option.data.mjs +114 -0
- package/dist/components/input/Option.data.mjs.map +1 -0
- package/dist/components/input/Option.mjs +21 -17
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/layout/FlatTree.cjs +2 -0
- package/dist/components/layout/FlatTree.cjs.map +1 -0
- package/dist/components/layout/FlatTree.context.cjs +2 -0
- package/dist/components/layout/FlatTree.context.cjs.map +1 -0
- package/dist/components/layout/FlatTree.context.mjs +20 -0
- package/dist/components/layout/FlatTree.context.mjs.map +1 -0
- package/dist/components/layout/FlatTree.item.cjs +2 -0
- package/dist/components/layout/FlatTree.item.cjs.map +1 -0
- package/dist/components/layout/FlatTree.item.mjs +90 -0
- package/dist/components/layout/FlatTree.item.mjs.map +1 -0
- package/dist/components/layout/FlatTree.mjs +276 -0
- package/dist/components/layout/FlatTree.mjs.map +1 -0
- package/dist/components/layout/Tree.core.cjs +1 -1
- package/dist/components/layout/Tree.core.cjs.map +1 -1
- package/dist/components/layout/Tree.core.mjs +166 -165
- package/dist/components/layout/Tree.core.mjs.map +1 -1
- package/dist/components/layout/Tree.selection.cjs +1 -1
- package/dist/components/layout/Tree.selection.cjs.map +1 -1
- package/dist/components/layout/Tree.selection.mjs +11 -57
- package/dist/components/layout/Tree.selection.mjs.map +1 -1
- package/dist/components/layout/useFlatTree.cjs +2 -0
- package/dist/components/layout/useFlatTree.cjs.map +1 -0
- package/dist/components/layout/useFlatTree.mjs +83 -0
- package/dist/components/layout/useFlatTree.mjs.map +1 -0
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.context.cjs +2 -0
- package/dist/components/table/DataGrid.context.cjs.map +1 -0
- package/dist/components/table/DataGrid.context.mjs +74 -0
- package/dist/components/table/DataGrid.context.mjs.map +1 -0
- package/dist/components/table/DataGrid.header.cjs +2 -0
- package/dist/components/table/DataGrid.header.cjs.map +1 -0
- package/dist/components/table/DataGrid.header.mjs +168 -0
- package/dist/components/table/DataGrid.header.mjs.map +1 -0
- package/dist/components/table/DataGrid.mjs +488 -591
- package/dist/components/table/DataGrid.mjs.map +1 -1
- package/dist/components/table/DataGrid.sizing.cjs +2 -0
- package/dist/components/table/DataGrid.sizing.cjs.map +1 -0
- package/dist/components/table/DataGrid.sizing.mjs +187 -0
- package/dist/components/table/DataGrid.sizing.mjs.map +1 -0
- package/dist/components/table/DataGrid.store.cjs +2 -0
- package/dist/components/table/DataGrid.store.cjs.map +1 -0
- package/dist/components/table/DataGrid.store.mjs +108 -0
- package/dist/components/table/DataGrid.store.mjs.map +1 -0
- package/dist/components/table/DataGrid.window.cjs +2 -0
- package/dist/components/table/DataGrid.window.cjs.map +1 -0
- package/dist/components/table/DataGrid.window.mjs +165 -0
- package/dist/components/table/DataGrid.window.mjs.map +1 -0
- package/dist/components/table/Table.cjs +1 -1
- package/dist/components/table/Table.cjs.map +1 -1
- package/dist/components/table/Table.mjs +74 -72
- package/dist/components/table/Table.mjs.map +1 -1
- package/dist/components/table/Table.resize.cjs +2 -0
- package/dist/components/table/Table.resize.cjs.map +1 -0
- package/dist/components/table/Table.resize.mjs +98 -0
- package/dist/components/table/Table.resize.mjs.map +1 -0
- package/dist/components/table/useGridNavigation.cjs +1 -1
- package/dist/components/table/useGridNavigation.cjs.map +1 -1
- package/dist/components/table/useGridNavigation.mjs +343 -140
- package/dist/components/table/useGridNavigation.mjs.map +1 -1
- package/dist/components/table/useTableColumnSizing.cjs +2 -0
- package/dist/components/table/useTableColumnSizing.cjs.map +1 -0
- package/dist/components/table/useTableColumnSizing.mjs +76 -0
- package/dist/components/table/useTableColumnSizing.mjs.map +1 -0
- package/dist/components/table/useTableFeatures.cjs +2 -0
- package/dist/components/table/useTableFeatures.cjs.map +1 -0
- package/dist/components/table/useTableFeatures.mjs +110 -0
- package/dist/components/table/useTableFeatures.mjs.map +1 -0
- package/dist/components/table/useTableSelection.cjs +2 -0
- package/dist/components/table/useTableSelection.cjs.map +1 -0
- package/dist/components/table/useTableSelection.mjs +39 -0
- package/dist/components/table/useTableSelection.mjs.map +1 -0
- package/dist/components/table/useTableSort.cjs +2 -0
- package/dist/components/table/useTableSort.cjs.map +1 -0
- package/dist/components/table/useTableSort.mjs +58 -0
- package/dist/components/table/useTableSort.mjs.map +1 -0
- package/dist/hooks/useActiveDescendant.cjs +1 -1
- package/dist/hooks/useActiveDescendant.cjs.map +1 -1
- package/dist/hooks/useActiveDescendant.mjs +33 -25
- package/dist/hooks/useActiveDescendant.mjs.map +1 -1
- package/dist/hooks/useListbox.cjs +1 -1
- package/dist/hooks/useListbox.cjs.map +1 -1
- package/dist/hooks/useListbox.mjs +140 -130
- package/dist/hooks/useListbox.mjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +1 -1
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/hooks/useSelection.cjs +2 -0
- package/dist/hooks/useSelection.cjs.map +1 -0
- package/dist/hooks/useSelection.mjs +57 -0
- package/dist/hooks/useSelection.mjs.map +1 -0
- package/dist/hooks/useVirtualWindow.cjs +2 -0
- package/dist/hooks/useVirtualWindow.cjs.map +1 -0
- package/dist/hooks/useVirtualWindow.mjs +102 -0
- package/dist/hooks/useVirtualWindow.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1542 -53
- package/dist/index.d.ts +1542 -53
- package/dist/index.mjs +147 -136
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +68 -49
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/columnSizing.cjs +2 -0
- package/dist/lib/columnSizing.cjs.map +1 -0
- package/dist/lib/columnSizing.mjs +27 -0
- package/dist/lib/columnSizing.mjs.map +1 -0
- package/dist/lib/flatTree.cjs +2 -0
- package/dist/lib/flatTree.cjs.map +1 -0
- package/dist/lib/flatTree.mjs +118 -0
- package/dist/lib/flatTree.mjs.map +1 -0
- package/dist/lib/selection.cjs +2 -0
- package/dist/lib/selection.cjs.map +1 -0
- package/dist/lib/selection.mjs +28 -0
- package/dist/lib/selection.mjs.map +1 -0
- package/dist/lib/treeCascade.cjs +2 -0
- package/dist/lib/treeCascade.cjs.map +1 -0
- package/dist/lib/treeCascade.mjs +52 -0
- package/dist/lib/treeCascade.mjs.map +1 -0
- package/dist/lib/virtual.cjs +2 -0
- package/dist/lib/virtual.cjs.map +1 -0
- package/dist/lib/virtual.mjs +54 -0
- package/dist/lib/virtual.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRovingTabIndex.cjs","names":["getFirstTabbable","isHiddenInput","React","isDev","useTypeahead","useEventCallback","isAltGraphCharacter","getArrowIntent","getDirection","require_runtime","require_dev","require_mergeRefs","require_useEventCallback","require_direction","require_focus","require_useTypeahead","react","groupIntoRows","rowElements","container","ordered","row","item","columns","rows","start","gridTargets","vertical","homeEnd","current","rowIndex","scope","target","column","delta","r","best","bestDistance","distance","index","DEFAULT_ITEM_SELECTOR","COMPOSITE_ROLES","ARROW_KEY_OWNER_ROLES","NON_TEXT_INPUT_TYPES","OBSERVED_ATTRIBUTES","isNestedComposite","el","roleComposites","role","isInNestedComposite","node","STAMPED_SELECTOR","matchesSelector","selector","rewrittenTabIndex","last","record","records","rewritten","isFocusableSelf","getFocusTarget","element","ownStop","tabbable","isDisabledElement","marker","isNativelyDisabled","ownsArrowKeys","tag","editable","canHoldTabStop","isHiddenByCss","view","hidden","cache","parent","child","visibility","hasFocus","active","isValidSelector","toEntry","resolveTabStop","rank","entries","values","value","tabStop","lastFocused","activeValue","orderByItems","items","resolved","byValue","RovingStore","notify","previous","options","candidates","itemSelector","result","seen","cssHidden","candidate","composite","nested","manageTabIndex","stop","tabIndex","original","own","generated","parseSnapshot","snapshot","textOf","isInContainer","findOwningItem","byElement","startsOnItem","useRovingTabIndex","legacyRef","maybeOptions","refOrOptions","store","focusedValue","setFocusedValue","focusedStop","setFocusedStop","orientation","domItems","stopEntries","ranks","present","tabStopValue","getTabIndex","containerRef","typeaheadItemsRef","typeaheadMatchesRef","matches","focusItem","focusFirstOf","handleKeys","gridCtrlHomeEnd","shortcut","enabled","handled","targets","spaceOnly","gridMove","intent","dir","step","count","i","loop","homeEndKeys","typeahead","onTypeahead","next","onFocusMove","handleKeyDown","handleKeyDownCapture","isSearching","handleFocus","focusValue","focusFirst","focusLast"],"sources":["../../src/hooks/useRovingTabIndex.ts"],"sourcesContent":["import * as React from 'react';\nimport type { WaveDir } from '../components/provider/WaveProvider';\nimport { isDev, warnOnce } from '../lib/dev';\nimport { getArrowIntent, getDirection } from '../lib/direction';\nimport { getFirstTabbable, isHiddenInput } from '../lib/focus';\nimport { setRef } from '../lib/mergeRefs';\nimport { useEventCallback } from './useEventCallback';\nimport { isAltGraphCharacter, useTypeahead, type TypeaheadItem } from './useTypeahead';\n\n/**\n * Configuration options for the {@link useRovingTabIndex} hook. Disabled items are skipped; items\n * marked `data-disabled-focusable` (the `disabledFocusable` prop of WaveUI buttons, links and\n * choice controls) stay reachable and may hold the tab stop: APG allows focusable disabled items.\n */\nexport interface UseRovingTabIndexOptions {\n /**\n * The selected value. It may be absent, `''` or `null` (nothing selected) and does not have to be\n * one of the items.\n */\n activeValue?: string | null;\n /**\n * Explicit item order (0.4 call shape). Omitted ⇒ the DOM order of the elements matching\n * `itemSelector`. Disabled items are skipped either way, and so are listed values with no\n * element in the container (not rendered, or `hidden`/`inert`): they never hold the tab stop.\n */\n items?: readonly string[];\n /**\n * Arrow key axis: `'horizontal'` uses Left/Right (mirrored in RTL), `'vertical'` uses Up/Down,\n * `'both'` uses all four, in the DOM order of the items.\n *\n * `'grid'` is a two-dimensional grid: Left/Right move through the cells in reading order across\n * rows (mirrored in RTL); Up/Down go to the cell at the same index in the previous or next row,\n * else to the nearest enabled cell of that row (the earlier one on a tie), skipping rows without\n * an enabled cell, and stop at the first and last row; Home/End go to the first and last enabled\n * cell of the row, Ctrl+Home/End of the grid (whatever `homeEndKeys` says). Rows are the\n * `role=\"row\"` elements inside the container, else groups of `columns` items in DOM order. Without\n * either, `'grid'` acts as `'both'` and a development warning says so.\n * @default 'horizontal'\n */\n orientation?: 'horizontal' | 'vertical' | 'both' | 'grid';\n /**\n * With `orientation: 'grid'` and no `role=\"row\"` elements: the number of cells per row. The last\n * row may be shorter.\n */\n columns?: number;\n /**\n * Whether arrow keys wrap around at the ends.\n * @default true\n */\n loop?: boolean;\n /** Text direction. Defaults to the direction of the container at key time (`getDirection`). */\n dir?: WaveDir;\n /**\n * Selector for the item elements inside the container. A selector the browser rejects matches\n * nothing (no item is navigable or tabbable) and logs a development warning.\n * @default '[data-roving-value]'\n */\n itemSelector?: string;\n /**\n * Printable characters move focus to the next item whose text (`data-roving-text`, else its\n * text content) starts with them. A Space typed within 500 ms of another character continues\n * the search instead of activating the focused item: `containerProps.onKeyDownCapture` calls\n * `preventDefault()` on it before an item's own keydown handler runs, so that handler must skip\n * default-prevented events (`composeEventHandlers` does). Keys typed in content nested inside an\n * item (a row's action button) are not typeahead. A character typed with AltGr (which Windows\n * reports as Ctrl+Alt, e.g. Polish `ł`) is typeahead text; other Ctrl, Alt or Meta\n * combinations, Ctrl+Alt+Space included, are shortcuts and ignored. A match whose `focus()`\n * leaves focus where it was is passed over for the next item that matches.\n * @default false\n */\n typeahead?: boolean;\n /**\n * Whether Home/End move to the first/last enabled item.\n * @default true\n */\n homeEndKeys?: boolean;\n /** Which item holds the tab stop. 'active' (default): the enabled activeValue item, else the first\n * enabled item — APG Tabs/Radio/Listbox/Tree. 'last-focused': the last focused enabled item, else\n * 'active' — APG Toolbar (and the static Menu). Either way a nested composite or a control that\n * uses the arrow keys itself (text field, select, slider, spin button, editable combobox) holds\n * it only when no other item can: arrows pressed there never lead back to the other items, so\n * focusing one keeps the tab stop on the last focused other item. 'none': no item holds it\n * (every item gets tabIndex -1; a nested composite keeps its own tab stop, and one marked\n * `data-roving-transparent` joins the group's arrow order), for a composite reached only by\n * the arrow keys of an enclosing widget or by a script (a tree row's actions); the keys,\n * `focusValue`, `focusFirst` and `focusLast` keep working. */\n tabStop?: 'active' | 'last-focused' | 'none';\n /** true ⇒ the hook writes tabIndex 0/-1 onto item elements itself and assigns\n * data-roving-value=\"auto-<n>\" to items that lack one. For containers that do not render their\n * items (Toolbar children, Menu items, Tree rows). Default false (items call getTabIndex).\n * Matches that cannot take focus are no items: `input[type=hidden]` is skipped, and a control\n * hidden by CSS inside the container (`display: none` or `visibility: hidden` on it or on an\n * ancestor inside the container) is treated as disabled (skipped, never the tab stop, stamped\n * -1). A container hidden as a whole from outside keeps its items and tab stop.\n * When the container stops being one (its ref detaches, as when `containerProps` are no longer\n * spread, or moves to another element) or `manageTabIndex` turns false, every element the hook\n * stamped gets its own `tabindex` back (the attribute it had at its first stamp, or none; a\n * `tabIndex` its author rendered since, the commit that detaches the container included, stays)\n * and loses a `data-roving-value` the hook added (one React rendered stays). An element that\n * stops being an item (`itemSelector`, or a changed selector, no longer matches it) is handed\n * back the same way. The last focused item and the generated values are kept, so a container\n * that attaches again starts where it was. */\n manageTabIndex?: boolean;\n /** Called after an arrow, Home/End or typeahead key moved focus to `value`. */\n onFocusMove?: (value: string, event: React.KeyboardEvent) => void;\n}\n\n/** Props to spread onto the container element. */\nexport interface RovingContainerProps {\n ref: React.RefCallback<HTMLElement>;\n 'data-roving-container': '';\n onKeyDown: React.KeyboardEventHandler;\n /** With `typeahead`: default-prevents a Space that continues a search, before item handlers. */\n onKeyDownCapture: React.KeyboardEventHandler;\n onFocus: React.FocusEventHandler;\n}\n\n/** Result of {@link useRovingTabIndex}. */\nexport interface UseRovingTabIndexResult {\n /** Spread onto the container: ref, `data-roving-container` marker and the key/focus handlers. */\n containerProps: RovingContainerProps;\n /** The container's keydown handler (same function as `containerProps.onKeyDown`). */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n /**\n * The container's capture-phase keydown handler (same function as\n * `containerProps.onKeyDownCapture`). With `typeahead`, it extends the search with a Space that\n * continues one and calls `preventDefault()`, before an item's own keydown handler runs: an item\n * that activates on Space must skip default-prevented events (`composeEventHandlers` does).\n */\n handleKeyDownCapture: (e: React.KeyboardEvent) => void;\n /** The container's focus handler (same function as `containerProps.onFocus`). */\n handleFocus: (e: React.FocusEvent) => void;\n /** `0` for the item that holds the tab stop, `-1` for every other item. */\n getTabIndex: (value: string) => 0 | -1;\n /** The value of the item that last received focus, or `null`. */\n focusedValue: string | null;\n /** Focuses the item with this value (ignored when it is disabled or unknown). */\n focusValue: (value: string) => void;\n /** Focuses the first enabled item. */\n focusFirst: () => void;\n /** Focuses the last enabled item. */\n focusLast: () => void;\n}\n\n/** The rows of a grid: the items of the `role=\"row\"` elements, else groups of `columns` items. */\nfunction groupIntoRows(\n ordered: readonly ResolvedItem[],\n container: HTMLElement,\n columns: number | undefined,\n): ResolvedItem[][] | null {\n const rowElements = container.querySelectorAll<HTMLElement>('[role=\"row\"]');\n if (rowElements.length > 0) {\n return Array.from(rowElements).map((row) =>\n ordered.filter((item) => row.contains(item.element)),\n );\n }\n if (columns !== undefined && columns > 0) {\n const rows: ResolvedItem[][] = [];\n for (let start = 0; start < ordered.length; start += columns) {\n rows.push(ordered.slice(start, start + columns));\n }\n return rows;\n }\n return null;\n}\n\n/**\n * Where a grid key (Up/Down, Home/End, Ctrl+Home/End) goes from `current`: the cells to try, in\n * order; `'stay'` when the key is the grid's but nothing is further that way; `undefined` when it is\n * not a grid key, or focus is not on a cell of a row (the container's own handling applies).\n */\nfunction gridTargets(\n e: React.KeyboardEvent,\n rows: readonly ResolvedItem[][],\n current: ResolvedItem | null | undefined,\n): ResolvedItem[] | 'stay' | undefined {\n const vertical = e.key === 'ArrowUp' || e.key === 'ArrowDown';\n const homeEnd = e.key === 'Home' || e.key === 'End';\n if (!current || (!vertical && !homeEnd)) return undefined;\n const rowIndex = rows.findIndex((row) => row.includes(current));\n if (rowIndex < 0) return undefined;\n if (homeEnd) {\n const scope = (e.ctrlKey ? rows.flat() : rows[rowIndex]).filter((item) => !item.disabled);\n const target = e.key === 'Home' ? scope[0] : scope[scope.length - 1];\n return target && target !== current ? [target] : 'stay';\n }\n // The column is the index in the row, counting every cell (disabled ones included).\n const column = rows[rowIndex].indexOf(current);\n const delta = e.key === 'ArrowDown' ? 1 : -1;\n for (let r = rowIndex + delta; r >= 0 && r < rows.length; r += delta) {\n let best: ResolvedItem | undefined;\n let bestDistance = Infinity;\n rows[r].forEach((item, index) => {\n if (item.disabled) return;\n const distance = Math.abs(index - column);\n if (distance < bestDistance) {\n best = item;\n bestDistance = distance;\n }\n });\n if (best) return [best];\n }\n return 'stay';\n}\n\ninterface ResolvedItem {\n value: string;\n /** The item element (for a nested composite: its root). */\n element: HTMLElement;\n /** A nested composite (own roving container or composite role) counts as one item. */\n nested: boolean;\n /**\n * Skipped by the keys and never the tab stop: disabled, a nested composite with nothing to\n * focus, or (`manageTabIndex`) hidden by CSS.\n */\n disabled: boolean;\n}\n\ninterface StoreOptions {\n itemSelector: string;\n manageTabIndex: boolean;\n items: readonly string[] | undefined;\n activeValue: string | null;\n tabStop: 'active' | 'last-focused' | 'none';\n /**\n * Whether an element with a composite role but no roving container of its own is a nested\n * composite (one item). Off in the 0.4 call shape and with explicit `items`, where such an element\n * is usually the widget's own root inside a wrapper that carries the container ref.\n */\n roleComposites: boolean;\n}\n\nconst DEFAULT_ITEM_SELECTOR = '[data-roving-value]';\n\n/** Roles of widgets that manage their own children: an element with one of them is one item. */\nconst COMPOSITE_ROLES = new Set([\n 'radiogroup',\n 'listbox',\n 'grid',\n 'treegrid',\n 'tablist',\n 'menu',\n 'menubar',\n 'tree',\n 'spinbutton',\n]);\n\n/**\n * Roles whose widgets use the arrow keys themselves. A combobox does only when it is editable (an\n * `<input>` or contenteditable, caught by the native checks): a select-only combobox such as\n * Dropdown's `<button role=\"combobox\">` uses Up/Down, Home and End, never Left/Right.\n */\nconst ARROW_KEY_OWNER_ROLES = new Set(['slider', 'spinbutton', 'textbox', 'searchbox']);\n\n/** `<input>` types that do not use the arrow keys for text editing. */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'reset',\n 'submit',\n]);\n\nconst OBSERVED_ATTRIBUTES = [\n 'disabled',\n 'aria-disabled',\n 'data-disabled-focusable',\n 'data-roving-disabled',\n 'data-roving-value',\n 'data-roving-container',\n 'data-roving-transparent',\n 'tabindex',\n 'hidden',\n 'inert',\n 'role',\n // Whether an item uses the arrow keys itself (text input types, contenteditable).\n 'type',\n 'contenteditable',\n];\n\n/**\n * Whether `el` is a nested composite: it has its own roving container, or (with `roleComposites`)\n * a composite role. An element marked `data-roving-transparent` is never one by its role (a\n * `role=\"radiogroup\"` whose radios are items of the enclosing container, `Toolbar.RadioGroup`);\n * its own `data-roving-container` still makes it one.\n */\nfunction isNestedComposite(el: Element, roleComposites: boolean): boolean {\n if (el.hasAttribute('data-roving-container')) return true;\n if (!roleComposites || el.hasAttribute('data-roving-transparent')) return false;\n const role = el.getAttribute('role');\n return role !== null && COMPOSITE_ROLES.has(role);\n}\n\n/** Whether `el` is a nested composite or inside one, below `container`. */\nfunction isInNestedComposite(el: Element, container: Element, roleComposites: boolean): boolean {\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n if (isNestedComposite(node, roleComposites)) return true;\n }\n return false;\n}\n\n/** What the hook knows of an element it stamped, to hand it back to its author. */\ninterface StampedOriginal {\n /**\n * The author's own `tabindex` attribute, or `null`: read at the first stamp, and replaced by the\n * one the author writes while the element is stamped (React rendering another `tabIndex`; the\n * next stamp overwrites it in the DOM).\n */\n tabIndex: string | null;\n /** The `tabindex` the hook left on the element at its last stamp. */\n stamped: string;\n /** The `data-roving-value` the hook added (a generated value), or `null` when it added none. */\n addedValue: string | null;\n}\n\n/**\n * Every element the hook stamps carries both attributes, whatever `itemSelector` matched it: the\n * hand-back finds its elements through them, also one the selector no longer matches.\n */\nconst STAMPED_SELECTOR = '[tabindex], [data-roving-value]';\n\nfunction matchesSelector(el: Element, selector: string): boolean {\n try {\n return el.matches(selector);\n } catch {\n // A selector the browser rejects matches nothing.\n return false;\n }\n}\n\n/**\n * The elements whose last `tabindex` write in `records` left the value it found: the author\n * (through React) wrote the value the stamp had left. The hook only writes to change a value, so\n * such a write is never its own. Needs records with `attributeOldValue`.\n */\nfunction rewrittenTabIndex(records: readonly MutationRecord[]): Set<Node> {\n const last = new Map<Node, MutationRecord>();\n for (const record of records) {\n if (record.type === 'attributes' && record.attributeName === 'tabindex') {\n last.set(record.target, record);\n }\n }\n const rewritten = new Set<Node>();\n for (const [target, record] of last) {\n if (record.oldValue === (target as Element).getAttribute('tabindex')) rewritten.add(target);\n }\n return rewritten;\n}\n\nfunction isFocusableSelf(el: HTMLElement): boolean {\n return el.tabIndex >= 0 && !el.hasAttribute('disabled');\n}\n\n/** The element to focus for an item: the item itself, or a nested composite's own tab stop. */\nfunction getFocusTarget(item: ResolvedItem): HTMLElement | null {\n const { element } = item;\n if (!item.nested || isFocusableSelf(element)) return element;\n const ownStop = element.querySelector<HTMLElement>('[tabindex=\"0\"]');\n if (ownStop) return ownStop;\n const tabbable = getFirstTabbable(element);\n return tabbable instanceof HTMLElement ? tabbable : null;\n}\n\n/**\n * Whether the keys skip an item, in this order: the composite's own `data-roving-disabled` marker\n * (not `\"false\"`) and native `disabled` skip it; `data-disabled-focusable` keeps it (a\n * `disabledFocusable` control: APG allows focusable disabled items); `aria-disabled=\"true\"` skips\n * it.\n */\nfunction isDisabledElement(el: HTMLElement): boolean {\n const marker = el.getAttribute('data-roving-disabled');\n if (marker !== null && marker !== 'false') return true;\n if (isNativelyDisabled(el)) return true;\n if (el.hasAttribute('data-disabled-focusable')) return false;\n return el.getAttribute('aria-disabled') === 'true';\n}\n\nfunction isNativelyDisabled(el: HTMLElement): boolean {\n if ((el as { disabled?: unknown }).disabled === true) return true;\n try {\n return el.matches(':disabled');\n } catch {\n return false;\n }\n}\n\n/** Text-entry fields and widgets that use the arrow keys themselves (APG Toolbar). */\nfunction ownsArrowKeys(target: EventTarget | null): boolean {\n if (!target || (target as Node).nodeType !== 1) return false;\n const el = target as HTMLElement;\n const role = el.getAttribute('role');\n if (role !== null && ARROW_KEY_OWNER_ROLES.has(role)) return true;\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.closest('[contenteditable]');\n return editable !== null && editable.getAttribute('contenteditable') !== 'false';\n}\n\n/**\n * Whether an item can hold the container's tab stop: not a nested composite (it keeps a tab stop\n * of its own) and not a control that uses the arrow keys itself. From either, the arrow keys never\n * lead to the other items, so a tab stop there would leave them reachable by keyboard only through\n * it (or not at all).\n */\nfunction canHoldTabStop(item: ResolvedItem): boolean {\n return !item.nested && !ownsArrowKeys(item.element);\n}\n\n/**\n * Whether CSS inside `container` keeps `el` from taking focus (browsers ignore `focus()` on it):\n * `display: none` on it or on an ancestor inside `container`, `visibility: hidden`/`collapse` set\n * inside `container`, or a place inside a closed `<details>` other than its summary. Hiding from\n * outside the container (a surface that stays invisible until it is positioned, a consumer panel)\n * hides the whole item set and does not count: showing it again changes nothing the hook observes,\n * so nothing would re-stamp. `cache` holds, for one resolution, whether an element hides its whole\n * subtree (the `display` and `<details>` checks).\n *\n * Internal: shared with Tree's treegrid navigation; not exported from the package.\n */\nexport function isHiddenByCss(\n el: Element,\n container: Element,\n cache: Map<Element, boolean>,\n): boolean {\n const view = el.ownerDocument.defaultView;\n if (!view) return false;\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n let hidden = cache.get(node);\n if (hidden === undefined) {\n const parent = node.parentElement;\n hidden =\n view.getComputedStyle(node).display === 'none' ||\n (parent !== null &&\n parent.localName === 'details' &&\n !parent.hasAttribute('open') &&\n Array.from(parent.children).find((child) => child.localName === 'summary') !== node);\n cache.set(node, hidden);\n }\n if (hidden) return true;\n }\n const { visibility } = view.getComputedStyle(el);\n if (visibility !== 'hidden' && visibility !== 'collapse') return false;\n // Visibility is inherited, so `el` also reads hidden when an ancestor of the container hides the\n // whole container. It counts only when the container itself is visible, i.e. when the hiding is\n // set inside it (on `el` or on a wrapper between them).\n return view.getComputedStyle(container).visibility === 'visible';\n}\n\n/** Whether focus is on `el` or inside it (in its document or shadow root). */\nfunction hasFocus(el: HTMLElement): boolean {\n const active = (el.getRootNode() as Node & { activeElement?: Element | null }).activeElement;\n return !!active && el.contains(active);\n}\n\nfunction isValidSelector(selector: string): boolean {\n try {\n document.createDocumentFragment().querySelector(selector);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * How an item takes part in the tab stop: `0` never (disabled), `1` can hold it, `2` holds it only\n * when no item can (a nested composite, or a control that uses the arrow keys itself).\n */\ntype TabStopRank = 0 | 1 | 2;\n\n/** One item of the published DOM snapshot, and the input of {@link resolveTabStop}. */\ntype SnapshotEntry = [value: string, rank: TabStopRank];\n\nfunction toEntry(item: ResolvedItem): SnapshotEntry {\n return [item.value, item.disabled ? 0 : canHoldTabStop(item) ? 1 : 2];\n}\n\n/**\n * The value that holds the tab stop, among the items of the best rank present (`1`, else `2`):\n * with 'last-focused' the last focused one, else the `activeValue` item, else the first one.\n */\nfunction resolveTabStop(\n entries: readonly SnapshotEntry[],\n activeValue: string | null,\n tabStop: 'active' | 'last-focused',\n lastFocused: string | null,\n): string | null {\n const rank = entries.some(([, r]) => r === 1) ? 1 : 2;\n const values = entries.filter(([, r]) => r === rank).map(([value]) => value);\n if (tabStop === 'last-focused' && lastFocused !== null && values.includes(lastFocused)) {\n return lastFocused;\n }\n if (activeValue !== null && activeValue !== '' && values.includes(activeValue)) {\n return activeValue;\n }\n return values[0] ?? null;\n}\n\nfunction orderByItems(\n resolved: ResolvedItem[],\n items: readonly string[] | undefined,\n): ResolvedItem[] {\n if (!items) return resolved;\n const byValue = new Map(resolved.map((item) => [item.value, item]));\n const ordered: ResolvedItem[] = [];\n for (const value of items) {\n const item = byValue.get(value);\n if (item) ordered.push(item);\n }\n return ordered;\n}\n\n/**\n * Per-hook store: resolves items from the DOM, publishes the enabled set to React through\n * `useSyncExternalStore` (a MutationObserver on the container notifies it), and stamps tabIndex in\n * `manageTabIndex` mode.\n */\nclass RovingStore {\n container: HTMLElement | null = null;\n lastFocused: string | null = null;\n options: StoreOptions = {\n itemSelector: DEFAULT_ITEM_SELECTOR,\n manageTabIndex: false,\n items: undefined,\n activeValue: null,\n tabStop: 'active',\n roleComposites: true,\n };\n\n private readonly stamped = new WeakMap<Element, StampedOriginal>();\n private readonly autoValues = new WeakMap<Element, string>();\n private autoCounter = 0;\n private notify: (() => void) | null = null;\n private observer: MutationObserver | null = null;\n private dirty = true;\n private snapshot = '';\n\n subscribe = (notify: () => void): (() => void) => {\n this.notify = notify;\n this.observe();\n return () => {\n this.notify = null;\n this.disconnect();\n };\n };\n\n getSnapshot = (): string => {\n if (!this.container) return '';\n if (this.dirty) {\n this.dirty = false;\n // DOM facts only (order and tab stop rank); `items` is applied during render.\n this.snapshot = JSON.stringify(this.resolveOwn().map(toEntry));\n }\n return this.snapshot;\n };\n\n getServerSnapshot = (): string => '';\n\n /**\n * Attaches the store to `container` (`null` detaches it). A container that stops being one (its\n * ref detached, or the store moved to another element) first hands every element it stamped back\n * to its author, with the writes its observer has not delivered yet (the `tabIndex` React\n * rendered in the commit that detaches it). Only a store that manages tabIndex has stamped\n * anything: `setOptions` hands the stamps back the moment `manageTabIndex` turns off.\n */\n setContainer(container: HTMLElement | null): void {\n if (container === this.container) return;\n // Disconnecting drops the pending records anyway; the hand-back reads them first.\n const records = this.takeRecords();\n this.disconnect();\n if (this.container && this.options.manageTabIndex) {\n this.release(this.container, 'all', records);\n }\n this.container = container;\n this.dirty = true;\n if (this.notify) {\n this.observe();\n this.notify();\n }\n }\n\n /**\n * Records a focused item for the 'last-focused' tab stop. An item that cannot hold the tab stop\n * (a nested composite, a control that uses the arrow keys itself) leaves the last one in place.\n */\n recordFocus(item: ResolvedItem): void {\n if (canHoldTabStop(item)) this.lastFocused = item.value;\n }\n\n setOptions(options: StoreOptions): void {\n const previous = this.options;\n this.options = options;\n // `manageTabIndex` turned off: the elements stamped so far go back to their author. The records\n // taken here are not delivered; the notification below stands in for them. (A changed\n // `itemSelector` hands back what it no longer matches at the next stamp.)\n if (previous.manageTabIndex && !options.manageTabIndex && this.container) {\n this.release(this.container, 'all', this.takeRecords());\n }\n if (\n previous.itemSelector !== options.itemSelector ||\n previous.manageTabIndex !== options.manageTabIndex ||\n previous.roleComposites !== options.roleComposites\n ) {\n this.dirty = true;\n this.notify?.();\n }\n }\n\n /** Own items in navigation order: the explicit `items` order when given, else DOM order. */\n resolve(container: HTMLElement | null = this.container): ResolvedItem[] {\n return orderByItems(this.resolveOwn(container), this.options.items);\n }\n\n /** Own items of the container in DOM order (items of nested composites excluded). */\n resolveOwn(container: HTMLElement | null = this.container): ResolvedItem[] {\n if (!container) return [];\n const { itemSelector, manageTabIndex, roleComposites } = this.options;\n let candidates: HTMLElement[];\n try {\n candidates = Array.from(container.querySelectorAll<HTMLElement>(itemSelector));\n } catch {\n // An invalid selector (warned from an effect in development): this runs during render\n // (getSnapshot), where throwing would take the whole tree down.\n return [];\n }\n\n const result: ResolvedItem[] = [];\n const seen = new Set<Element>();\n const cssHidden = new Map<Element, boolean>();\n for (const candidate of candidates) {\n let composite: HTMLElement | null = null;\n let hidden = false;\n for (\n let node: HTMLElement | null = candidate;\n node && node !== container;\n node = node.parentElement\n ) {\n if (isNestedComposite(node, roleComposites)) composite = node;\n if (node.hidden || node.hasAttribute('inert')) hidden = true;\n }\n if (hidden) continue;\n\n const element = composite ?? candidate;\n if (seen.has(element)) continue;\n const nested = composite !== null;\n if (!nested && manageTabIndex) {\n // An author tabindex=\"-1\" (a SpinButton stepper, SplitButton internals) opts out.\n if (candidate.getAttribute('tabindex') === '-1' && !this.stamped.has(candidate)) continue;\n // A hidden form input (HiddenInput's `type=\"hidden\"`) is never focusable.\n if (isHiddenInput(candidate)) continue;\n }\n seen.add(element);\n\n const item: ResolvedItem = {\n value: this.valueOf(element, nested),\n element,\n nested,\n disabled: isDisabledElement(element),\n };\n if (nested && !item.disabled && !getFocusTarget(item)) item.disabled = true;\n // Consumer children hidden by CSS (a responsive `hidden md:inline-flex` control). Treated as\n // disabled rather than dropped, so it is stamped -1 and is no extra Tab stop once the CSS\n // shows it again (a CSS change triggers no mutation, hence no re-stamp).\n if (manageTabIndex && !item.disabled && isHiddenByCss(element, container, cssHidden)) {\n item.disabled = true;\n }\n result.push(item);\n }\n return result;\n }\n\n /**\n * manageTabIndex: writes tabIndex 0 on the tab stop and -1 on every other own item. An element\n * it stamped that is no longer one of its items (it now belongs to a nested composite, as when a\n * `data-roving-transparent` marker is removed, or `itemSelector` no longer matches it) is handed\n * back first. A `tabindex` the author rendered since the last stamp becomes the element's own.\n */\n stamp(): void {\n if (!this.options.manageTabIndex || !this.container) return;\n this.release(this.container, 'stale');\n const resolved = this.resolve();\n const stop =\n this.options.tabStop === 'none'\n ? null\n : resolveTabStop(\n resolved.map(toEntry),\n this.options.activeValue,\n this.options.tabStop,\n this.lastFocused,\n );\n for (const item of resolved) {\n if (item.nested) continue;\n const { element } = item;\n const tabIndex = item.value === stop ? '0' : '-1';\n const current = element.getAttribute('tabindex');\n let original = this.stamped.get(element);\n if (!original) {\n original = { tabIndex: current, stamped: tabIndex, addedValue: null };\n this.stamped.set(element, original);\n } else {\n // Another value than the last stamp left: the author rendered it, so it is the element's own.\n if (current !== original.stamped) original.tabIndex = current;\n original.stamped = tabIndex;\n }\n if (current !== tabIndex) element.setAttribute('tabindex', tabIndex);\n if (!element.hasAttribute('data-roving-value')) {\n element.setAttribute('data-roving-value', item.value);\n original.addedValue = item.value;\n }\n }\n }\n\n /**\n * Hands elements it stamped inside `container` back to their author and drops their records, so\n * a later stamp reads them afresh. The `tabindex` the record holds as the author's is put back\n * (removed when there was none), unless the author wrote one since the last stamp, which stays:\n * another value than the stamp's, or the stamp's value written again (seen in the pending\n * `records`). A `data-roving-value` the hook added is removed while it still holds the generated\n * value (one React renders stays). The generated values and the last focused item are kept: a\n * container that attaches again starts where it was. `'stale'`: only the elements that are no\n * longer its items, because they belong to a nested composite or `itemSelector` no longer matches\n * them (every stamp); `'all'`: every element (the container detaches or is replaced, or\n * `manageTabIndex` turns off).\n */\n private release(\n container: HTMLElement,\n scope: 'stale' | 'all',\n records: readonly MutationRecord[] = [],\n ): void {\n const rewritten = rewrittenTabIndex(records);\n const { itemSelector, roleComposites } = this.options;\n for (const element of Array.from(container.querySelectorAll<HTMLElement>(STAMPED_SELECTOR))) {\n const original = this.stamped.get(element);\n if (!original) continue;\n if (\n scope === 'stale' &&\n matchesSelector(element, itemSelector) &&\n !isInNestedComposite(element, container, roleComposites)\n ) {\n continue;\n }\n this.stamped.delete(element);\n const current = element.getAttribute('tabindex');\n const authorWrote = current !== original.stamped || rewritten.has(element);\n // Written only to change the value: the hook's own writes never keep one (`rewrittenTabIndex`).\n if (!authorWrote && current !== original.tabIndex) {\n if (original.tabIndex === null) element.removeAttribute('tabindex');\n else element.setAttribute('tabindex', original.tabIndex);\n }\n if (\n original.addedValue !== null &&\n element.getAttribute('data-roving-value') === original.addedValue\n ) {\n element.removeAttribute('data-roving-value');\n }\n }\n }\n\n /**\n * Takes over, as the element's own, a `tabindex` the author wrote with the value the stamp had\n * left (`rewrittenTabIndex`): the next stamp cannot tell it from its own. Another value is taken\n * over by the next stamp.\n */\n private adopt(records: readonly MutationRecord[]): void {\n for (const target of rewrittenTabIndex(records)) {\n const original = this.stamped.get(target as Element);\n if (original) original.tabIndex = (target as Element).getAttribute('tabindex');\n }\n }\n\n /** The records the observer has not delivered yet; it delivers none of them afterwards. */\n private takeRecords(): MutationRecord[] {\n return this.observer?.takeRecords() ?? [];\n }\n\n private valueOf(element: HTMLElement, nested: boolean): string {\n const own = nested ? null : element.getAttribute('data-roving-value');\n if (own !== null) return own;\n let generated = this.autoValues.get(element);\n if (generated === undefined) {\n this.autoCounter += 1;\n generated = `auto-${this.autoCounter}`;\n this.autoValues.set(element, generated);\n }\n return generated;\n }\n\n private observe(): void {\n if (!this.container || this.observer || typeof MutationObserver === 'undefined') return;\n this.observer = new MutationObserver((records) => {\n this.adopt(records);\n this.stamp();\n this.dirty = true;\n this.notify?.();\n });\n this.observer.observe(this.container, {\n subtree: true,\n childList: true,\n attributes: true,\n // With the old value, a write that keeps a value shows as the author's (`rewrittenTabIndex`).\n attributeOldValue: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n this.dirty = true;\n }\n\n private disconnect(): void {\n this.observer?.disconnect();\n this.observer = null;\n }\n}\n\nfunction parseSnapshot(snapshot: string): SnapshotEntry[] | null {\n if (snapshot === '') return null;\n try {\n return JSON.parse(snapshot) as SnapshotEntry[];\n } catch {\n return null;\n }\n}\n\nfunction textOf(element: HTMLElement): string {\n return element.getAttribute('data-roving-text') ?? element.textContent ?? '';\n}\n\n/**\n * Whether an event target is the container or inside its DOM. React bubbles events from a portal\n * (a Menu.Popover or Popover.Content a Toolbar item renders) through the container although their\n * target is elsewhere in the document; those events are not the container's to handle.\n */\nfunction isInContainer(container: Node, target: EventTarget | null): boolean {\n if (!target || typeof (target as Node).nodeType !== 'number') return false;\n return target === container || container.contains(target as Node);\n}\n\n/**\n * The item an event started in: the innermost item element that is the target or one of its\n * ancestors (up to the container). Items can nest (an APG treeitem contains the group of its child\n * treeitems), so the first containing item in DOM order would be the outermost ancestor.\n */\nfunction findOwningItem(\n items: readonly ResolvedItem[],\n target: EventTarget | null,\n container: Node,\n): ResolvedItem | null {\n if (items.length === 0 || !target || typeof (target as Node).nodeType !== 'number') return null;\n const byElement = new Map<Node, ResolvedItem>(items.map((item) => [item.element, item]));\n for (let node: Node | null = target as Node; node && node !== container; node = node.parentNode) {\n const item = byElement.get(node);\n if (item) return item;\n }\n return null;\n}\n\n/**\n * Whether a key started on the item itself (on the container when it started on no item), not on\n * content nested inside the item, such as a row's action button.\n */\nfunction startsOnItem(item: ResolvedItem | null, target: EventTarget | null, container: Node) {\n return item ? target === getFocusTarget(item) : target === container;\n}\n\n/**\n * Implements the WAI-ARIA roving tabindex pattern for composite widgets: one item holds the tab\n * stop (`tabIndex=0`, all others `-1`), arrow keys move focus between items, Home/End jump to the\n * ends, and (optionally) typeahead jumps by text. Used by RadioGroup, Rating, SwatchPicker, List,\n * TabList, Tree, Menu and Toolbar.\n *\n * - **Items** come from the DOM at event time: elements matching `itemSelector` (default\n * `[data-roving-value]`) whose nearest roving container is this one. A nested composite (an\n * element with its own `data-roving-container`, or a radiogroup/listbox/grid/tablist/menu/tree/\n * spinbutton role) counts as one item whose focus target is its own tab stop; the hook never\n * writes tabindex inside it, so it keeps its own Tab stop. An element marked\n * `data-roving-transparent` is never a nested composite by its role: its items are items of this\n * container (the radios of `Toolbar.RadioGroup`); it must not carry a `data-roving-container`.\n * Pass `items` to fix the order instead.\n * In the 0.4 call shape and with explicit `items`, only elements with their own roving container\n * are nested composites: a role-only `radiogroup`/`tablist`/… element between the container and\n * the items (the widget's root inside a wrapper that holds the ref) does not swallow them.\n * - **Disabled items** (`data-roving-disabled`, `disabled`, `aria-disabled=\"true\"`) are skipped and\n * never hold the tab stop. Items marked `data-disabled-focusable` (the `disabledFocusable` prop\n * of WaveUI buttons, links and choice controls) stay reachable and may hold the tab stop: APG\n * allows focusable disabled items. The attribute only overrides `aria-disabled`: an item that is\n * natively disabled or marked `data-roving-disabled` is still skipped. The enabled set is\n * tracked with a MutationObserver, so an item that disables itself moves the tab stop without\n * the owner re-rendering. With `manageTabIndex`, a control hidden by CSS counts as disabled and\n * `input[type=hidden]` is no item.\n * - **Hand-back** (`manageTabIndex`): a container that stops being one (its ref detaches or moves\n * to another element) or that stops managing tabIndex gives every element it stamped its own\n * `tabindex` back (the one it had, or the one its author rendered since) and removes the\n * `data-roving-value` it added, so each control is its own Tab stop again; attached again, it\n * stamps again from the last focused item. An element `itemSelector` no longer matches is handed\n * back at once.\n * - **Tab stop** (`tabStop`): `'active'` — the enabled `activeValue` item, else the first enabled\n * item; `'last-focused'` — the last focused enabled item, else the `'active'` rule. A nested\n * composite or a control that uses the arrow keys itself holds it only when no other item can;\n * `'none'` — no item: every item is `tabIndex=-1` (a nested composite keeps its own tab stop;\n * mark it `data-roving-transparent` to join the group's arrow order), and focus reaches the\n * items only through the keys or a script.\n * - **Keys** are ignored when another handler already called `preventDefault()`; with Meta; with\n * Alt or Ctrl, except a single character typed with AltGr (Ctrl+Alt on Windows), which is\n * typeahead text (arrows, Home, End and Space with Ctrl+Alt stay ignored); and when they start\n * in a text field, select, contenteditable, slider, spinbutton or editable combobox (Left/Right\n * keep moving the caret; a select-only combobox such as Dropdown's button does not keep them).\n * Left/Right are mirrored in RTL (`dir`, else the direction of the container at key time).\n * Arrows and typeahead move from the item the key started in — the innermost one when items\n * nest, as treeitems do inside their parent's group; when it started on no item (focus on the\n * container itself) next goes to the first enabled item and prev to the last.\n * An item whose `focus()` leaves focus where it was (the browser ignores it on an element CSS\n * hides) is passed over for the next one, and is never recorded or reported to `onFocusMove`.\n * Handled keys call `preventDefault()`. Keys and focus from outside the container's DOM — a\n * popup an item renders through a portal, whose events React bubbles through the container —\n * are ignored, so focus never leaves an open menu or popover for the container's items.\n *\n * @example\n * const { containerProps, getTabIndex } = useRovingTabIndex({ activeValue: value, orientation: 'both' });\n * <div role=\"radiogroup\" {...containerProps}>\n * <button role=\"radio\" data-roving-value=\"a\" tabIndex={getTabIndex('a')} />\n * </div>\n *\n * The 0.4 call shape `useRovingTabIndex(containerRef, options)` still works: pass the container's\n * ref object and attach `handleKeyDown` (and ideally `handleFocus`, and with `typeahead`\n * `handleKeyDownCapture` as `onKeyDownCapture`) yourself.\n *\n * @param options - See {@link UseRovingTabIndexOptions}.\n * @returns See {@link UseRovingTabIndexResult}.\n */\nexport function useRovingTabIndex(options: UseRovingTabIndexOptions): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n containerRef: React.RefObject<HTMLElement | null>,\n options: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n refOrOptions: React.RefObject<HTMLElement | null> | UseRovingTabIndexOptions,\n maybeOptions?: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult {\n const legacyRef =\n maybeOptions !== undefined ? (refOrOptions as React.RefObject<HTMLElement | null>) : undefined;\n const options = (maybeOptions ?? refOrOptions) as UseRovingTabIndexOptions;\n const {\n activeValue = null,\n items,\n orientation = 'horizontal',\n columns,\n loop = true,\n dir,\n itemSelector = DEFAULT_ITEM_SELECTOR,\n typeahead = false,\n homeEndKeys = true,\n tabStop = 'active',\n manageTabIndex = false,\n onFocusMove,\n } = options;\n\n const [store] = React.useState(() => new RovingStore());\n const snapshot = React.useSyncExternalStore(\n store.subscribe,\n store.getSnapshot,\n store.getServerSnapshot,\n );\n const [focusedValue, setFocusedValue] = React.useState<string | null>(null);\n // The last focused item that can hold the tab stop ('last-focused' during render).\n const [focusedStop, setFocusedStop] = React.useState<string | null>(null);\n\n // 0.4 call shape or explicit `items`: only elements with their own roving container are nested\n // composites (a role=radiogroup/tablist/… around the items is the widget's own root).\n const roleComposites = legacyRef === undefined && items === undefined;\n\n React.useLayoutEffect(() => {\n store.setOptions({ itemSelector, manageTabIndex, items, activeValue, tabStop, roleComposites });\n if (legacyRef) store.setContainer(legacyRef.current);\n store.stamp();\n });\n\n // C-DEV: `resolveOwn` treats a selector the browser rejects as \"no items\" (it runs during render,\n // where it must not throw), so the developer hears about it here.\n React.useEffect(() => {\n if (isDev && !isValidSelector(itemSelector)) {\n warnOnce(\n `useRovingTabIndex:itemSelector:${itemSelector}`,\n `useRovingTabIndex: itemSelector \"${itemSelector}\" is not a valid CSS selector in this browser; no item is navigable or tabbable.`,\n );\n }\n }, [itemSelector]);\n\n // C-DEV: a grid needs rows, from role=\"row\" elements or a `columns` count.\n React.useEffect(() => {\n if (!isDev || orientation !== 'grid' || columns) return;\n const container = store.container;\n if (container && container.querySelector('[role=\"row\"]') === null) {\n warnOnce(\n 'useRovingTabIndex:grid-rows',\n 'useRovingTabIndex: orientation \"grid\" needs role=\"row\" elements around the items or a `columns` count; without either it acts as \"both\".',\n );\n }\n });\n\n // Tab stop during render, from the DOM snapshot (null before the container is known).\n const domItems = React.useMemo(() => parseSnapshot(snapshot), [snapshot]);\n const stopEntries = React.useMemo<readonly SnapshotEntry[] | null>(() => {\n if (!items) return domItems;\n // Explicit `items`: the listed values the DOM has, in the listed order. Every listed value\n // before the container is known, or while the DOM has none of them yet (items rendered in the\n // commit the snapshot has not caught up with).\n if (domItems) {\n const ranks = new Map(domItems);\n const present = items.flatMap((value): SnapshotEntry[] => {\n const rank = ranks.get(value);\n return rank === undefined ? [] : [[value, rank]];\n });\n if (present.length > 0) return present;\n }\n return items.map((value): SnapshotEntry => [value, 1]);\n }, [items, domItems]);\n const tabStopValue =\n tabStop === 'none'\n ? null\n : stopEntries\n ? resolveTabStop(stopEntries, activeValue, tabStop, focusedStop)\n : activeValue || null;\n\n const getTabIndex = React.useCallback(\n (value: string): 0 | -1 => (value === tabStopValue ? 0 : -1),\n [tabStopValue],\n );\n\n const containerRef = React.useCallback(\n (node: HTMLElement | null) => {\n store.setContainer(node);\n if (legacyRef) setRef(legacyRef, node);\n },\n [store, legacyRef],\n );\n\n const typeaheadItemsRef = React.useRef<TypeaheadItem[]>([]);\n // Every item matching the typed characters, in search order (the first is the match).\n const typeaheadMatchesRef = React.useRef<readonly string[]>([]);\n const { onTypeahead, isSearching } = useTypeahead({\n getItems: () => typeaheadItemsRef.current,\n onMatch: (_value, matches) => {\n typeaheadMatchesRef.current = matches;\n },\n });\n\n /** Focuses an item; `true` only when focus actually moved there (then it is recorded). */\n const focusItem = (item: ResolvedItem | undefined): boolean => {\n if (!item || item.disabled) return false;\n const target = getFocusTarget(item);\n if (!target) return false;\n target.focus();\n // Browsers ignore focus() on an element CSS hides (display: none, visibility: hidden).\n if (!hasFocus(target)) return false;\n store.recordFocus(item);\n return true;\n };\n\n /** Focuses the first item of `candidates` that takes focus. */\n const focusFirstOf = (candidates: readonly ResolvedItem[]): void => {\n for (const item of candidates) {\n if (focusItem(item)) return;\n }\n };\n\n // `spaceOnly` (the capture phase) handles nothing but a Space that continues a typeahead search.\n const handleKeys = useEventCallback((e: React.KeyboardEvent, spaceOnly: boolean) => {\n // Ctrl, Alt and Meta combinations are shortcuts, except a single character typed with AltGr\n // (Ctrl+Alt on Windows), which is typeahead text: arrows, Home, End and Space with it stay\n // shortcuts.\n const gridCtrlHomeEnd =\n orientation === 'grid' && e.ctrlKey && !e.altKey && (e.key === 'Home' || e.key === 'End');\n const shortcut =\n e.metaKey || ((e.altKey || e.ctrlKey) && !isAltGraphCharacter(e) && !gridCtrlHomeEnd);\n if (e.defaultPrevented || shortcut) return;\n if (ownsArrowKeys(e.target)) return;\n const container = store.container ?? (e.currentTarget as HTMLElement);\n // A key from a portaled popup is the popup's: never pull focus back out of it.\n if (!isInContainer(container, e.target)) return;\n const ordered = store.resolve(container);\n const enabled = ordered.filter((item) => !item.disabled);\n if (enabled.length === 0) return;\n\n // The (innermost) item the key started in. None (the container itself has focus): next → first,\n // prev → last.\n const current = findOwningItem(ordered, e.target, container);\n\n let handled = false;\n // Where focus goes, in order of preference: an item whose focus() does not move focus (hidden\n // by CSS) passes the key on to the next one.\n let targets: ResolvedItem[] = [];\n const rows =\n orientation === 'grid' && !spaceOnly ? groupIntoRows(ordered, container, columns) : null;\n const gridMove = rows ? gridTargets(e, rows, current) : undefined;\n const intent =\n spaceOnly || gridMove\n ? null\n : getArrowIntent(e.key, {\n orientation: orientation === 'grid' ? (rows ? 'horizontal' : 'both') : orientation,\n dir: dir ?? getDirection(e.currentTarget as Element),\n });\n if (gridMove) {\n handled = true;\n targets = gridMove === 'stay' ? [] : gridMove;\n } else if (intent) {\n handled = true;\n if (!current) {\n targets = intent === 'next' ? enabled : [...enabled].reverse();\n } else {\n const step = intent === 'next' ? 1 : -1;\n const count = ordered.length;\n let index = ordered.indexOf(current);\n for (let i = 1; i < count; i++) {\n index += step;\n if (index < 0 || index >= count) {\n if (!loop) break;\n index = (index + count) % count;\n }\n if (!ordered[index].disabled) targets.push(ordered[index]);\n }\n }\n } else if (!spaceOnly && homeEndKeys && (e.key === 'Home' || e.key === 'End')) {\n handled = true;\n targets = e.key === 'Home' ? enabled : [...enabled].reverse();\n } else if (typeahead && startsOnItem(current, e.target, container)) {\n typeaheadItemsRef.current = ordered.map((item) => ({\n value: item.value,\n text: textOf(item.element),\n disabled: item.disabled,\n }));\n typeaheadMatchesRef.current = [];\n if (onTypeahead(e, current?.value ?? null)) {\n handled = true;\n // The match first, then the next ones, for a match that does not take focus.\n targets = typeaheadMatchesRef.current.flatMap((value) =>\n enabled.filter((item) => item.value === value),\n );\n }\n }\n\n if (!handled) return;\n e.preventDefault();\n for (const next of targets) {\n // Back at the item the key started on (Home on the first item): focus stays.\n if (next === current) return;\n if (focusItem(next)) {\n onFocusMove?.(next.value, e);\n return;\n }\n }\n });\n\n const handleKeyDown = useEventCallback((e: React.KeyboardEvent) => handleKeys(e, false));\n\n // A Space that continues a typeahead search belongs to the search, not to the focused item: it is\n // handled and default-prevented in the capture phase, so the item's own keydown handler, which\n // skips default-prevented events, does not activate the item.\n const handleKeyDownCapture = useEventCallback((e: React.KeyboardEvent) => {\n if (typeahead && e.key === ' ' && isSearching()) handleKeys(e, true);\n });\n\n const handleFocus = useEventCallback((e: React.FocusEvent) => {\n const container = store.container ?? (e.currentTarget as HTMLElement);\n if (!isInContainer(container, e.target)) return;\n const item = findOwningItem(store.resolve(container), e.target, container);\n if (!item) return;\n store.recordFocus(item);\n setFocusedValue(item.value);\n if (canHoldTabStop(item)) setFocusedStop(item.value);\n store.stamp();\n });\n\n const focusValue = useEventCallback((value: string) => {\n focusItem(store.resolve().find((item) => item.value === value));\n });\n const focusFirst = useEventCallback(() => {\n focusFirstOf(store.resolve().filter((item) => !item.disabled));\n });\n const focusLast = useEventCallback(() => {\n focusFirstOf(\n store\n .resolve()\n .filter((item) => !item.disabled)\n .reverse(),\n );\n });\n\n const containerProps = React.useMemo<RovingContainerProps>(\n () => ({\n ref: containerRef,\n 'data-roving-container': '',\n onKeyDown: handleKeyDown,\n onKeyDownCapture: handleKeyDownCapture,\n onFocus: handleFocus,\n }),\n [containerRef, handleKeyDown, handleKeyDownCapture, handleFocus],\n );\n\n return {\n containerProps,\n handleKeyDown,\n handleKeyDownCapture,\n handleFocus,\n getTabIndex,\n focusedValue,\n focusValue,\n focusFirst,\n focusLast,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useRovingTabIndex.cjs","names":["getFirstTabbable","isHiddenInput","React","isDev","useTypeahead","useEventCallback","isAltGraphCharacter","getArrowIntent","getDirection","require_runtime","require_dev","require_mergeRefs","require_useEventCallback","require_direction","require_focus","require_useTypeahead","react","groupIntoRows","rowElements","container","ordered","row","item","columns","rows","start","gridTargets","vertical","homeEnd","current","rowIndex","scope","target","column","delta","r","best","bestDistance","distance","index","DEFAULT_ITEM_SELECTOR","COMPOSITE_ROLES","ARROW_KEY_OWNER_ROLES","NON_TEXT_INPUT_TYPES","OBSERVED_ATTRIBUTES","isNestedComposite","el","roleComposites","role","isInNestedComposite","node","STAMPED_SELECTOR","matchesSelector","selector","rewrittenTabIndex","last","record","records","rewritten","isFocusableSelf","getFocusTarget","element","ownStop","tabbable","isDisabledElement","marker","isNativelyDisabled","ownsArrowKeys","tag","editable","canHoldTabStop","isHiddenByCss","view","hidden","cache","parent","child","visibility","hasFocus","active","isValidSelector","toEntry","resolveTabStop","rank","entries","values","value","tabStop","lastFocused","activeValue","orderByItems","items","resolved","byValue","RovingStore","notify","previous","options","candidates","itemSelector","result","seen","cssHidden","candidate","composite","nested","manageTabIndex","stop","tabIndex","original","own","generated","parseSnapshot","snapshot","textOf","isInContainer","findOwningItem","byElement","startsOnItem","useRovingTabIndex","legacyRef","maybeOptions","refOrOptions","store","focusedValue","setFocusedValue","focusedStop","setFocusedStop","orientation","domItems","stopEntries","ranks","present","tabStopValue","getTabIndex","containerRef","typeaheadItemsRef","typeaheadMatchesRef","matches","focusItem","focusFirstOf","handleKeys","gridCtrlHomeEnd","shortcut","enabled","handled","targets","spaceOnly","gridMove","intent","dir","step","count","i","loop","homeEndKeys","typeahead","onTypeahead","next","onFocusMove","handleKeyDown","handleKeyDownCapture","isSearching","handleFocus","focusValue","focusFirst","focusLast"],"sources":["../../src/hooks/useRovingTabIndex.ts"],"sourcesContent":["import * as React from 'react';\nimport type { WaveDir } from '../components/provider/WaveProvider';\nimport { isDev, warnOnce } from '../lib/dev';\nimport { getArrowIntent, getDirection } from '../lib/direction';\nimport { getFirstTabbable, isHiddenInput } from '../lib/focus';\nimport { setRef } from '../lib/mergeRefs';\nimport { useEventCallback } from './useEventCallback';\nimport { isAltGraphCharacter, useTypeahead, type TypeaheadItem } from './useTypeahead';\n\n/**\n * Configuration options for the {@link useRovingTabIndex} hook. Disabled items are skipped; items\n * marked `data-disabled-focusable` (the `disabledFocusable` prop of WaveUI buttons, links and\n * choice controls) stay reachable and may hold the tab stop: APG allows focusable disabled items.\n */\nexport interface UseRovingTabIndexOptions {\n /**\n * The selected value. It may be absent, `''` or `null` (nothing selected) and does not have to be\n * one of the items.\n */\n activeValue?: string | null;\n /**\n * Explicit item order (0.4 call shape). Omitted ⇒ the DOM order of the elements matching\n * `itemSelector`. Disabled items are skipped either way, and so are listed values with no\n * element in the container (not rendered, or `hidden`/`inert`): they never hold the tab stop.\n */\n items?: readonly string[];\n /**\n * Arrow key axis: `'horizontal'` uses Left/Right (mirrored in RTL), `'vertical'` uses Up/Down,\n * `'both'` uses all four, in the DOM order of the items.\n *\n * `'grid'` is a two-dimensional grid: Left/Right move through the cells in reading order across\n * rows (mirrored in RTL); Up/Down go to the cell at the same index in the previous or next row,\n * else to the nearest enabled cell of that row (the earlier one on a tie), skipping rows without\n * an enabled cell, and stop at the first and last row; Home/End go to the first and last enabled\n * cell of the row, Ctrl+Home/End of the grid (whatever `homeEndKeys` says). Rows are the\n * `role=\"row\"` elements inside the container, else groups of `columns` items in DOM order. Without\n * either, `'grid'` acts as `'both'` and a development warning says so.\n * @default 'horizontal'\n */\n orientation?: 'horizontal' | 'vertical' | 'both' | 'grid';\n /**\n * With `orientation: 'grid'` and no `role=\"row\"` elements: the number of cells per row. The last\n * row may be shorter.\n */\n columns?: number;\n /**\n * Whether arrow keys wrap around at the ends.\n * @default true\n */\n loop?: boolean;\n /** Text direction. Defaults to the direction of the container at key time (`getDirection`). */\n dir?: WaveDir;\n /**\n * Selector for the item elements inside the container. A selector the browser rejects matches\n * nothing (no item is navigable or tabbable) and logs a development warning.\n * @default '[data-roving-value]'\n */\n itemSelector?: string;\n /**\n * Printable characters move focus to the next item whose text (`data-roving-text`, else its\n * text content) starts with them. A Space typed within 500 ms of another character continues\n * the search instead of activating the focused item: `containerProps.onKeyDownCapture` calls\n * `preventDefault()` on it before an item's own keydown handler runs, so that handler must skip\n * default-prevented events (`composeEventHandlers` does). Keys typed in content nested inside an\n * item (a row's action button) are not typeahead. A character typed with AltGr (which Windows\n * reports as Ctrl+Alt, e.g. Polish `ł`) is typeahead text; other Ctrl, Alt or Meta\n * combinations, Ctrl+Alt+Space included, are shortcuts and ignored. A match whose `focus()`\n * leaves focus where it was is passed over for the next item that matches.\n * @default false\n */\n typeahead?: boolean;\n /**\n * Whether Home/End move to the first/last enabled item.\n * @default true\n */\n homeEndKeys?: boolean;\n /** Which item holds the tab stop. 'active' (default): the enabled activeValue item, else the first\n * enabled item — APG Tabs/Radio/Listbox/Tree. 'last-focused': the last focused enabled item, else\n * 'active' — APG Toolbar (and the static Menu). Either way a nested composite or a control that\n * uses the arrow keys itself (text field, select, slider, spin button, editable combobox) holds\n * it only when no other item can: arrows pressed there never lead back to the other items, so\n * focusing one keeps the tab stop on the last focused other item. 'none': no item holds it\n * (every item gets tabIndex -1; a nested composite keeps its own tab stop, and one marked\n * `data-roving-transparent` joins the group's arrow order), for a composite reached only by\n * the arrow keys of an enclosing widget or by a script (a tree row's actions); the keys,\n * `focusValue`, `focusFirst` and `focusLast` keep working. */\n tabStop?: 'active' | 'last-focused' | 'none';\n /** true ⇒ the hook writes tabIndex 0/-1 onto item elements itself and assigns\n * data-roving-value=\"auto-<n>\" to items that lack one. For containers that do not render their\n * items (Toolbar children, Menu items, Tree rows). Default false (items call getTabIndex).\n * Matches that cannot take focus are no items: `input[type=hidden]` is skipped, and a control\n * hidden by CSS inside the container (`display: none` or `visibility: hidden` on it or on an\n * ancestor inside the container) is treated as disabled (skipped, never the tab stop, stamped\n * -1). A container hidden as a whole from outside keeps its items and tab stop.\n * When the container stops being one (its ref detaches, as when `containerProps` are no longer\n * spread, or moves to another element) or `manageTabIndex` turns false, every element the hook\n * stamped gets its own `tabindex` back (the attribute it had at its first stamp, or none; a\n * `tabIndex` its author rendered since, the commit that detaches the container included, stays)\n * and loses a `data-roving-value` the hook added (one React rendered stays). An element that\n * stops being an item (`itemSelector`, or a changed selector, no longer matches it) is handed\n * back the same way. The last focused item and the generated values are kept, so a container\n * that attaches again starts where it was. */\n manageTabIndex?: boolean;\n /** Called after an arrow, Home/End or typeahead key moved focus to `value`. */\n onFocusMove?: (value: string, event: React.KeyboardEvent) => void;\n}\n\n/** Props to spread onto the container element. */\nexport interface RovingContainerProps {\n ref: React.RefCallback<HTMLElement>;\n 'data-roving-container': '';\n onKeyDown: React.KeyboardEventHandler;\n /** With `typeahead`: default-prevents a Space that continues a search, before item handlers. */\n onKeyDownCapture: React.KeyboardEventHandler;\n onFocus: React.FocusEventHandler;\n}\n\n/** Result of {@link useRovingTabIndex}. */\nexport interface UseRovingTabIndexResult {\n /** Spread onto the container: ref, `data-roving-container` marker and the key/focus handlers. */\n containerProps: RovingContainerProps;\n /** The container's keydown handler (same function as `containerProps.onKeyDown`). */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n /**\n * The container's capture-phase keydown handler (same function as\n * `containerProps.onKeyDownCapture`). With `typeahead`, it extends the search with a Space that\n * continues one and calls `preventDefault()`, before an item's own keydown handler runs: an item\n * that activates on Space must skip default-prevented events (`composeEventHandlers` does).\n */\n handleKeyDownCapture: (e: React.KeyboardEvent) => void;\n /** The container's focus handler (same function as `containerProps.onFocus`). */\n handleFocus: (e: React.FocusEvent) => void;\n /** `0` for the item that holds the tab stop, `-1` for every other item. */\n getTabIndex: (value: string) => 0 | -1;\n /** The value of the item that last received focus, or `null`. */\n focusedValue: string | null;\n /** Focuses the item with this value (ignored when it is disabled or unknown). */\n focusValue: (value: string) => void;\n /** Focuses the first enabled item. */\n focusFirst: () => void;\n /** Focuses the last enabled item. */\n focusLast: () => void;\n}\n\n/** The rows of a grid: the items of the `role=\"row\"` elements, else groups of `columns` items. */\nfunction groupIntoRows(\n ordered: readonly ResolvedItem[],\n container: HTMLElement,\n columns: number | undefined,\n): ResolvedItem[][] | null {\n const rowElements = container.querySelectorAll<HTMLElement>('[role=\"row\"]');\n if (rowElements.length > 0) {\n return Array.from(rowElements).map((row) =>\n ordered.filter((item) => row.contains(item.element)),\n );\n }\n if (columns !== undefined && columns > 0) {\n const rows: ResolvedItem[][] = [];\n for (let start = 0; start < ordered.length; start += columns) {\n rows.push(ordered.slice(start, start + columns));\n }\n return rows;\n }\n return null;\n}\n\n/**\n * Where a grid key (Up/Down, Home/End, Ctrl+Home/End) goes from `current`: the cells to try, in\n * order; `'stay'` when the key is the grid's but nothing is further that way; `undefined` when it is\n * not a grid key, or focus is not on a cell of a row (the container's own handling applies).\n */\nfunction gridTargets(\n e: React.KeyboardEvent,\n rows: readonly ResolvedItem[][],\n current: ResolvedItem | null | undefined,\n): ResolvedItem[] | 'stay' | undefined {\n const vertical = e.key === 'ArrowUp' || e.key === 'ArrowDown';\n const homeEnd = e.key === 'Home' || e.key === 'End';\n if (!current || (!vertical && !homeEnd)) return undefined;\n const rowIndex = rows.findIndex((row) => row.includes(current));\n if (rowIndex < 0) return undefined;\n if (homeEnd) {\n const scope = (e.ctrlKey ? rows.flat() : rows[rowIndex]).filter((item) => !item.disabled);\n const target = e.key === 'Home' ? scope[0] : scope[scope.length - 1];\n return target && target !== current ? [target] : 'stay';\n }\n // The column is the index in the row, counting every cell (disabled ones included).\n const column = rows[rowIndex].indexOf(current);\n const delta = e.key === 'ArrowDown' ? 1 : -1;\n for (let r = rowIndex + delta; r >= 0 && r < rows.length; r += delta) {\n let best: ResolvedItem | undefined;\n let bestDistance = Infinity;\n rows[r].forEach((item, index) => {\n if (item.disabled) return;\n const distance = Math.abs(index - column);\n if (distance < bestDistance) {\n best = item;\n bestDistance = distance;\n }\n });\n if (best) return [best];\n }\n return 'stay';\n}\n\ninterface ResolvedItem {\n value: string;\n /** The item element (for a nested composite: its root). */\n element: HTMLElement;\n /** A nested composite (own roving container or composite role) counts as one item. */\n nested: boolean;\n /**\n * Skipped by the keys and never the tab stop: disabled, a nested composite with nothing to\n * focus, or (`manageTabIndex`) hidden by CSS.\n */\n disabled: boolean;\n}\n\ninterface StoreOptions {\n itemSelector: string;\n manageTabIndex: boolean;\n items: readonly string[] | undefined;\n activeValue: string | null;\n tabStop: 'active' | 'last-focused' | 'none';\n /**\n * Whether an element with a composite role but no roving container of its own is a nested\n * composite (one item). Off in the 0.4 call shape and with explicit `items`, where such an element\n * is usually the widget's own root inside a wrapper that carries the container ref.\n */\n roleComposites: boolean;\n}\n\nconst DEFAULT_ITEM_SELECTOR = '[data-roving-value]';\n\n/** Roles of widgets that manage their own children: an element with one of them is one item. */\nconst COMPOSITE_ROLES = new Set([\n 'radiogroup',\n 'listbox',\n 'grid',\n 'treegrid',\n 'tablist',\n 'menu',\n 'menubar',\n 'tree',\n 'spinbutton',\n]);\n\n/**\n * Roles whose widgets use the arrow keys themselves. A combobox does only when it is editable (an\n * `<input>` or contenteditable, caught by the native checks): a select-only combobox such as\n * Dropdown's `<button role=\"combobox\">` uses Up/Down, Home and End, never Left/Right.\n */\nconst ARROW_KEY_OWNER_ROLES = new Set(['slider', 'spinbutton', 'textbox', 'searchbox']);\n\n/** `<input>` types that do not use the arrow keys for text editing. */\nconst NON_TEXT_INPUT_TYPES = new Set([\n 'button',\n 'checkbox',\n 'color',\n 'file',\n 'hidden',\n 'image',\n 'radio',\n 'reset',\n 'submit',\n]);\n\nconst OBSERVED_ATTRIBUTES = [\n 'disabled',\n 'aria-disabled',\n 'data-disabled-focusable',\n 'data-roving-disabled',\n 'data-roving-value',\n 'data-roving-container',\n 'data-roving-transparent',\n 'tabindex',\n 'hidden',\n 'inert',\n 'role',\n // Whether an item uses the arrow keys itself (text input types, contenteditable).\n 'type',\n 'contenteditable',\n];\n\n/**\n * Whether `el` is a nested composite: it has its own roving container, or (with `roleComposites`)\n * a composite role. An element marked `data-roving-transparent` is never one by its role (a\n * `role=\"radiogroup\"` whose radios are items of the enclosing container, `Toolbar.RadioGroup`);\n * its own `data-roving-container` still makes it one.\n */\nfunction isNestedComposite(el: Element, roleComposites: boolean): boolean {\n if (el.hasAttribute('data-roving-container')) return true;\n if (!roleComposites || el.hasAttribute('data-roving-transparent')) return false;\n const role = el.getAttribute('role');\n return role !== null && COMPOSITE_ROLES.has(role);\n}\n\n/** Whether `el` is a nested composite or inside one, below `container`. */\nfunction isInNestedComposite(el: Element, container: Element, roleComposites: boolean): boolean {\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n if (isNestedComposite(node, roleComposites)) return true;\n }\n return false;\n}\n\n/** What the hook knows of an element it stamped, to hand it back to its author. */\ninterface StampedOriginal {\n /**\n * The author's own `tabindex` attribute, or `null`: read at the first stamp, and replaced by the\n * one the author writes while the element is stamped (React rendering another `tabIndex`; the\n * next stamp overwrites it in the DOM).\n */\n tabIndex: string | null;\n /** The `tabindex` the hook left on the element at its last stamp. */\n stamped: string;\n /** The `data-roving-value` the hook added (a generated value), or `null` when it added none. */\n addedValue: string | null;\n}\n\n/**\n * Every element the hook stamps carries both attributes, whatever `itemSelector` matched it: the\n * hand-back finds its elements through them, also one the selector no longer matches.\n */\nconst STAMPED_SELECTOR = '[tabindex], [data-roving-value]';\n\nfunction matchesSelector(el: Element, selector: string): boolean {\n try {\n return el.matches(selector);\n } catch {\n // A selector the browser rejects matches nothing.\n return false;\n }\n}\n\n/**\n * The elements whose last `tabindex` write in `records` left the value it found: the author\n * (through React) wrote the value the stamp had left. The hook only writes to change a value, so\n * such a write is never its own. Needs records with `attributeOldValue`.\n */\nfunction rewrittenTabIndex(records: readonly MutationRecord[]): Set<Node> {\n const last = new Map<Node, MutationRecord>();\n for (const record of records) {\n if (record.type === 'attributes' && record.attributeName === 'tabindex') {\n last.set(record.target, record);\n }\n }\n const rewritten = new Set<Node>();\n for (const [target, record] of last) {\n if (record.oldValue === (target as Element).getAttribute('tabindex')) rewritten.add(target);\n }\n return rewritten;\n}\n\nfunction isFocusableSelf(el: HTMLElement): boolean {\n return el.tabIndex >= 0 && !el.hasAttribute('disabled');\n}\n\n/** The element to focus for an item: the item itself, or a nested composite's own tab stop. */\nfunction getFocusTarget(item: ResolvedItem): HTMLElement | null {\n const { element } = item;\n if (!item.nested || isFocusableSelf(element)) return element;\n const ownStop = element.querySelector<HTMLElement>('[tabindex=\"0\"]');\n if (ownStop) return ownStop;\n const tabbable = getFirstTabbable(element);\n return tabbable instanceof HTMLElement ? tabbable : null;\n}\n\n/**\n * Whether the keys skip an item, in this order: the composite's own `data-roving-disabled` marker\n * (not `\"false\"`) and native `disabled` skip it; `data-disabled-focusable` keeps it (a\n * `disabledFocusable` control: APG allows focusable disabled items); `aria-disabled=\"true\"` skips\n * it.\n */\nfunction isDisabledElement(el: HTMLElement): boolean {\n const marker = el.getAttribute('data-roving-disabled');\n if (marker !== null && marker !== 'false') return true;\n if (isNativelyDisabled(el)) return true;\n if (el.hasAttribute('data-disabled-focusable')) return false;\n return el.getAttribute('aria-disabled') === 'true';\n}\n\nfunction isNativelyDisabled(el: HTMLElement): boolean {\n if ((el as { disabled?: unknown }).disabled === true) return true;\n try {\n return el.matches(':disabled');\n } catch {\n return false;\n }\n}\n\n/**\n * Text-entry fields and widgets that use the arrow keys themselves (APG Toolbar).\n *\n * Internal: shared with the windowed List's keys, which leave the same keys alone; not exported\n * from the package.\n */\nexport function ownsArrowKeys(target: EventTarget | null): boolean {\n if (!target || (target as Node).nodeType !== 1) return false;\n const el = target as HTMLElement;\n const role = el.getAttribute('role');\n if (role !== null && ARROW_KEY_OWNER_ROLES.has(role)) return true;\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.closest('[contenteditable]');\n return editable !== null && editable.getAttribute('contenteditable') !== 'false';\n}\n\n/**\n * Whether an item can hold the container's tab stop: not a nested composite (it keeps a tab stop\n * of its own) and not a control that uses the arrow keys itself. From either, the arrow keys never\n * lead to the other items, so a tab stop there would leave them reachable by keyboard only through\n * it (or not at all).\n */\nfunction canHoldTabStop(item: ResolvedItem): boolean {\n return !item.nested && !ownsArrowKeys(item.element);\n}\n\n/**\n * Whether CSS inside `container` keeps `el` from taking focus (browsers ignore `focus()` on it):\n * `display: none` on it or on an ancestor inside `container`, `visibility: hidden`/`collapse` set\n * inside `container`, or a place inside a closed `<details>` other than its summary. Hiding from\n * outside the container (a surface that stays invisible until it is positioned, a consumer panel)\n * hides the whole item set and does not count: showing it again changes nothing the hook observes,\n * so nothing would re-stamp. `cache` holds, for one resolution, whether an element hides its whole\n * subtree (the `display` and `<details>` checks).\n *\n * Internal: shared with Tree's treegrid navigation; not exported from the package.\n */\nexport function isHiddenByCss(\n el: Element,\n container: Element,\n cache: Map<Element, boolean>,\n): boolean {\n const view = el.ownerDocument.defaultView;\n if (!view) return false;\n for (let node: Element | null = el; node && node !== container; node = node.parentElement) {\n let hidden = cache.get(node);\n if (hidden === undefined) {\n const parent = node.parentElement;\n hidden =\n view.getComputedStyle(node).display === 'none' ||\n (parent !== null &&\n parent.localName === 'details' &&\n !parent.hasAttribute('open') &&\n Array.from(parent.children).find((child) => child.localName === 'summary') !== node);\n cache.set(node, hidden);\n }\n if (hidden) return true;\n }\n const { visibility } = view.getComputedStyle(el);\n if (visibility !== 'hidden' && visibility !== 'collapse') return false;\n // Visibility is inherited, so `el` also reads hidden when an ancestor of the container hides the\n // whole container. It counts only when the container itself is visible, i.e. when the hiding is\n // set inside it (on `el` or on a wrapper between them).\n return view.getComputedStyle(container).visibility === 'visible';\n}\n\n/** Whether focus is on `el` or inside it (in its document or shadow root). */\nfunction hasFocus(el: HTMLElement): boolean {\n const active = (el.getRootNode() as Node & { activeElement?: Element | null }).activeElement;\n return !!active && el.contains(active);\n}\n\nfunction isValidSelector(selector: string): boolean {\n try {\n document.createDocumentFragment().querySelector(selector);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * How an item takes part in the tab stop: `0` never (disabled), `1` can hold it, `2` holds it only\n * when no item can (a nested composite, or a control that uses the arrow keys itself).\n */\ntype TabStopRank = 0 | 1 | 2;\n\n/** One item of the published DOM snapshot, and the input of {@link resolveTabStop}. */\ntype SnapshotEntry = [value: string, rank: TabStopRank];\n\nfunction toEntry(item: ResolvedItem): SnapshotEntry {\n return [item.value, item.disabled ? 0 : canHoldTabStop(item) ? 1 : 2];\n}\n\n/**\n * The value that holds the tab stop, among the items of the best rank present (`1`, else `2`):\n * with 'last-focused' the last focused one, else the `activeValue` item, else the first one.\n */\nfunction resolveTabStop(\n entries: readonly SnapshotEntry[],\n activeValue: string | null,\n tabStop: 'active' | 'last-focused',\n lastFocused: string | null,\n): string | null {\n const rank = entries.some(([, r]) => r === 1) ? 1 : 2;\n const values = entries.filter(([, r]) => r === rank).map(([value]) => value);\n if (tabStop === 'last-focused' && lastFocused !== null && values.includes(lastFocused)) {\n return lastFocused;\n }\n if (activeValue !== null && activeValue !== '' && values.includes(activeValue)) {\n return activeValue;\n }\n return values[0] ?? null;\n}\n\nfunction orderByItems(\n resolved: ResolvedItem[],\n items: readonly string[] | undefined,\n): ResolvedItem[] {\n if (!items) return resolved;\n const byValue = new Map(resolved.map((item) => [item.value, item]));\n const ordered: ResolvedItem[] = [];\n for (const value of items) {\n const item = byValue.get(value);\n if (item) ordered.push(item);\n }\n return ordered;\n}\n\n/**\n * Per-hook store: resolves items from the DOM, publishes the enabled set to React through\n * `useSyncExternalStore` (a MutationObserver on the container notifies it), and stamps tabIndex in\n * `manageTabIndex` mode.\n */\nclass RovingStore {\n container: HTMLElement | null = null;\n lastFocused: string | null = null;\n options: StoreOptions = {\n itemSelector: DEFAULT_ITEM_SELECTOR,\n manageTabIndex: false,\n items: undefined,\n activeValue: null,\n tabStop: 'active',\n roleComposites: true,\n };\n\n private readonly stamped = new WeakMap<Element, StampedOriginal>();\n private readonly autoValues = new WeakMap<Element, string>();\n private autoCounter = 0;\n private notify: (() => void) | null = null;\n private observer: MutationObserver | null = null;\n private dirty = true;\n private snapshot = '';\n\n subscribe = (notify: () => void): (() => void) => {\n this.notify = notify;\n this.observe();\n return () => {\n this.notify = null;\n this.disconnect();\n };\n };\n\n getSnapshot = (): string => {\n if (!this.container) return '';\n if (this.dirty) {\n this.dirty = false;\n // DOM facts only (order and tab stop rank); `items` is applied during render.\n this.snapshot = JSON.stringify(this.resolveOwn().map(toEntry));\n }\n return this.snapshot;\n };\n\n getServerSnapshot = (): string => '';\n\n /**\n * Attaches the store to `container` (`null` detaches it). A container that stops being one (its\n * ref detached, or the store moved to another element) first hands every element it stamped back\n * to its author, with the writes its observer has not delivered yet (the `tabIndex` React\n * rendered in the commit that detaches it). Only a store that manages tabIndex has stamped\n * anything: `setOptions` hands the stamps back the moment `manageTabIndex` turns off.\n */\n setContainer(container: HTMLElement | null): void {\n if (container === this.container) return;\n // Disconnecting drops the pending records anyway; the hand-back reads them first.\n const records = this.takeRecords();\n this.disconnect();\n if (this.container && this.options.manageTabIndex) {\n this.release(this.container, 'all', records);\n }\n this.container = container;\n this.dirty = true;\n if (this.notify) {\n this.observe();\n this.notify();\n }\n }\n\n /**\n * Records a focused item for the 'last-focused' tab stop. An item that cannot hold the tab stop\n * (a nested composite, a control that uses the arrow keys itself) leaves the last one in place.\n */\n recordFocus(item: ResolvedItem): void {\n if (canHoldTabStop(item)) this.lastFocused = item.value;\n }\n\n setOptions(options: StoreOptions): void {\n const previous = this.options;\n this.options = options;\n // `manageTabIndex` turned off: the elements stamped so far go back to their author. The records\n // taken here are not delivered; the notification below stands in for them. (A changed\n // `itemSelector` hands back what it no longer matches at the next stamp.)\n if (previous.manageTabIndex && !options.manageTabIndex && this.container) {\n this.release(this.container, 'all', this.takeRecords());\n }\n if (\n previous.itemSelector !== options.itemSelector ||\n previous.manageTabIndex !== options.manageTabIndex ||\n previous.roleComposites !== options.roleComposites\n ) {\n this.dirty = true;\n this.notify?.();\n }\n }\n\n /** Own items in navigation order: the explicit `items` order when given, else DOM order. */\n resolve(container: HTMLElement | null = this.container): ResolvedItem[] {\n return orderByItems(this.resolveOwn(container), this.options.items);\n }\n\n /** Own items of the container in DOM order (items of nested composites excluded). */\n resolveOwn(container: HTMLElement | null = this.container): ResolvedItem[] {\n if (!container) return [];\n const { itemSelector, manageTabIndex, roleComposites } = this.options;\n let candidates: HTMLElement[];\n try {\n candidates = Array.from(container.querySelectorAll<HTMLElement>(itemSelector));\n } catch {\n // An invalid selector (warned from an effect in development): this runs during render\n // (getSnapshot), where throwing would take the whole tree down.\n return [];\n }\n\n const result: ResolvedItem[] = [];\n const seen = new Set<Element>();\n const cssHidden = new Map<Element, boolean>();\n for (const candidate of candidates) {\n let composite: HTMLElement | null = null;\n let hidden = false;\n for (\n let node: HTMLElement | null = candidate;\n node && node !== container;\n node = node.parentElement\n ) {\n if (isNestedComposite(node, roleComposites)) composite = node;\n if (node.hidden || node.hasAttribute('inert')) hidden = true;\n }\n if (hidden) continue;\n\n const element = composite ?? candidate;\n if (seen.has(element)) continue;\n const nested = composite !== null;\n if (!nested && manageTabIndex) {\n // An author tabindex=\"-1\" (a SpinButton stepper, SplitButton internals) opts out.\n if (candidate.getAttribute('tabindex') === '-1' && !this.stamped.has(candidate)) continue;\n // A hidden form input (HiddenInput's `type=\"hidden\"`) is never focusable.\n if (isHiddenInput(candidate)) continue;\n }\n seen.add(element);\n\n const item: ResolvedItem = {\n value: this.valueOf(element, nested),\n element,\n nested,\n disabled: isDisabledElement(element),\n };\n if (nested && !item.disabled && !getFocusTarget(item)) item.disabled = true;\n // Consumer children hidden by CSS (a responsive `hidden md:inline-flex` control). Treated as\n // disabled rather than dropped, so it is stamped -1 and is no extra Tab stop once the CSS\n // shows it again (a CSS change triggers no mutation, hence no re-stamp).\n if (manageTabIndex && !item.disabled && isHiddenByCss(element, container, cssHidden)) {\n item.disabled = true;\n }\n result.push(item);\n }\n return result;\n }\n\n /**\n * manageTabIndex: writes tabIndex 0 on the tab stop and -1 on every other own item. An element\n * it stamped that is no longer one of its items (it now belongs to a nested composite, as when a\n * `data-roving-transparent` marker is removed, or `itemSelector` no longer matches it) is handed\n * back first. A `tabindex` the author rendered since the last stamp becomes the element's own.\n */\n stamp(): void {\n if (!this.options.manageTabIndex || !this.container) return;\n this.release(this.container, 'stale');\n const resolved = this.resolve();\n const stop =\n this.options.tabStop === 'none'\n ? null\n : resolveTabStop(\n resolved.map(toEntry),\n this.options.activeValue,\n this.options.tabStop,\n this.lastFocused,\n );\n for (const item of resolved) {\n if (item.nested) continue;\n const { element } = item;\n const tabIndex = item.value === stop ? '0' : '-1';\n const current = element.getAttribute('tabindex');\n let original = this.stamped.get(element);\n if (!original) {\n original = { tabIndex: current, stamped: tabIndex, addedValue: null };\n this.stamped.set(element, original);\n } else {\n // Another value than the last stamp left: the author rendered it, so it is the element's own.\n if (current !== original.stamped) original.tabIndex = current;\n original.stamped = tabIndex;\n }\n if (current !== tabIndex) element.setAttribute('tabindex', tabIndex);\n if (!element.hasAttribute('data-roving-value')) {\n element.setAttribute('data-roving-value', item.value);\n original.addedValue = item.value;\n }\n }\n }\n\n /**\n * Hands elements it stamped inside `container` back to their author and drops their records, so\n * a later stamp reads them afresh. The `tabindex` the record holds as the author's is put back\n * (removed when there was none), unless the author wrote one since the last stamp, which stays:\n * another value than the stamp's, or the stamp's value written again (seen in the pending\n * `records`). A `data-roving-value` the hook added is removed while it still holds the generated\n * value (one React renders stays). The generated values and the last focused item are kept: a\n * container that attaches again starts where it was. `'stale'`: only the elements that are no\n * longer its items, because they belong to a nested composite or `itemSelector` no longer matches\n * them (every stamp); `'all'`: every element (the container detaches or is replaced, or\n * `manageTabIndex` turns off).\n */\n private release(\n container: HTMLElement,\n scope: 'stale' | 'all',\n records: readonly MutationRecord[] = [],\n ): void {\n const rewritten = rewrittenTabIndex(records);\n const { itemSelector, roleComposites } = this.options;\n for (const element of Array.from(container.querySelectorAll<HTMLElement>(STAMPED_SELECTOR))) {\n const original = this.stamped.get(element);\n if (!original) continue;\n if (\n scope === 'stale' &&\n matchesSelector(element, itemSelector) &&\n !isInNestedComposite(element, container, roleComposites)\n ) {\n continue;\n }\n this.stamped.delete(element);\n const current = element.getAttribute('tabindex');\n const authorWrote = current !== original.stamped || rewritten.has(element);\n // Written only to change the value: the hook's own writes never keep one (`rewrittenTabIndex`).\n if (!authorWrote && current !== original.tabIndex) {\n if (original.tabIndex === null) element.removeAttribute('tabindex');\n else element.setAttribute('tabindex', original.tabIndex);\n }\n if (\n original.addedValue !== null &&\n element.getAttribute('data-roving-value') === original.addedValue\n ) {\n element.removeAttribute('data-roving-value');\n }\n }\n }\n\n /**\n * Takes over, as the element's own, a `tabindex` the author wrote with the value the stamp had\n * left (`rewrittenTabIndex`): the next stamp cannot tell it from its own. Another value is taken\n * over by the next stamp.\n */\n private adopt(records: readonly MutationRecord[]): void {\n for (const target of rewrittenTabIndex(records)) {\n const original = this.stamped.get(target as Element);\n if (original) original.tabIndex = (target as Element).getAttribute('tabindex');\n }\n }\n\n /** The records the observer has not delivered yet; it delivers none of them afterwards. */\n private takeRecords(): MutationRecord[] {\n return this.observer?.takeRecords() ?? [];\n }\n\n private valueOf(element: HTMLElement, nested: boolean): string {\n const own = nested ? null : element.getAttribute('data-roving-value');\n if (own !== null) return own;\n let generated = this.autoValues.get(element);\n if (generated === undefined) {\n this.autoCounter += 1;\n generated = `auto-${this.autoCounter}`;\n this.autoValues.set(element, generated);\n }\n return generated;\n }\n\n private observe(): void {\n if (!this.container || this.observer || typeof MutationObserver === 'undefined') return;\n this.observer = new MutationObserver((records) => {\n this.adopt(records);\n this.stamp();\n this.dirty = true;\n this.notify?.();\n });\n this.observer.observe(this.container, {\n subtree: true,\n childList: true,\n attributes: true,\n // With the old value, a write that keeps a value shows as the author's (`rewrittenTabIndex`).\n attributeOldValue: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n });\n this.dirty = true;\n }\n\n private disconnect(): void {\n this.observer?.disconnect();\n this.observer = null;\n }\n}\n\nfunction parseSnapshot(snapshot: string): SnapshotEntry[] | null {\n if (snapshot === '') return null;\n try {\n return JSON.parse(snapshot) as SnapshotEntry[];\n } catch {\n return null;\n }\n}\n\nfunction textOf(element: HTMLElement): string {\n return element.getAttribute('data-roving-text') ?? element.textContent ?? '';\n}\n\n/**\n * Whether an event target is the container or inside its DOM. React bubbles events from a portal\n * (a Menu.Popover or Popover.Content a Toolbar item renders) through the container although their\n * target is elsewhere in the document; those events are not the container's to handle.\n */\nfunction isInContainer(container: Node, target: EventTarget | null): boolean {\n if (!target || typeof (target as Node).nodeType !== 'number') return false;\n return target === container || container.contains(target as Node);\n}\n\n/**\n * The item an event started in: the innermost item element that is the target or one of its\n * ancestors (up to the container). Items can nest (an APG treeitem contains the group of its child\n * treeitems), so the first containing item in DOM order would be the outermost ancestor.\n */\nfunction findOwningItem(\n items: readonly ResolvedItem[],\n target: EventTarget | null,\n container: Node,\n): ResolvedItem | null {\n if (items.length === 0 || !target || typeof (target as Node).nodeType !== 'number') return null;\n const byElement = new Map<Node, ResolvedItem>(items.map((item) => [item.element, item]));\n for (let node: Node | null = target as Node; node && node !== container; node = node.parentNode) {\n const item = byElement.get(node);\n if (item) return item;\n }\n return null;\n}\n\n/**\n * Whether a key started on the item itself (on the container when it started on no item), not on\n * content nested inside the item, such as a row's action button.\n */\nfunction startsOnItem(item: ResolvedItem | null, target: EventTarget | null, container: Node) {\n return item ? target === getFocusTarget(item) : target === container;\n}\n\n/**\n * Implements the WAI-ARIA roving tabindex pattern for composite widgets: one item holds the tab\n * stop (`tabIndex=0`, all others `-1`), arrow keys move focus between items, Home/End jump to the\n * ends, and (optionally) typeahead jumps by text. Used by RadioGroup, Rating, SwatchPicker, List,\n * TabList, Tree, Menu and Toolbar.\n *\n * - **Items** come from the DOM at event time: elements matching `itemSelector` (default\n * `[data-roving-value]`) whose nearest roving container is this one. A nested composite (an\n * element with its own `data-roving-container`, or a radiogroup/listbox/grid/tablist/menu/tree/\n * spinbutton role) counts as one item whose focus target is its own tab stop; the hook never\n * writes tabindex inside it, so it keeps its own Tab stop. An element marked\n * `data-roving-transparent` is never a nested composite by its role: its items are items of this\n * container (the radios of `Toolbar.RadioGroup`); it must not carry a `data-roving-container`.\n * Pass `items` to fix the order instead.\n * In the 0.4 call shape and with explicit `items`, only elements with their own roving container\n * are nested composites: a role-only `radiogroup`/`tablist`/… element between the container and\n * the items (the widget's root inside a wrapper that holds the ref) does not swallow them.\n * - **Disabled items** (`data-roving-disabled`, `disabled`, `aria-disabled=\"true\"`) are skipped and\n * never hold the tab stop. Items marked `data-disabled-focusable` (the `disabledFocusable` prop\n * of WaveUI buttons, links and choice controls) stay reachable and may hold the tab stop: APG\n * allows focusable disabled items. The attribute only overrides `aria-disabled`: an item that is\n * natively disabled or marked `data-roving-disabled` is still skipped. The enabled set is\n * tracked with a MutationObserver, so an item that disables itself moves the tab stop without\n * the owner re-rendering. With `manageTabIndex`, a control hidden by CSS counts as disabled and\n * `input[type=hidden]` is no item.\n * - **Hand-back** (`manageTabIndex`): a container that stops being one (its ref detaches or moves\n * to another element) or that stops managing tabIndex gives every element it stamped its own\n * `tabindex` back (the one it had, or the one its author rendered since) and removes the\n * `data-roving-value` it added, so each control is its own Tab stop again; attached again, it\n * stamps again from the last focused item. An element `itemSelector` no longer matches is handed\n * back at once.\n * - **Tab stop** (`tabStop`): `'active'` — the enabled `activeValue` item, else the first enabled\n * item; `'last-focused'` — the last focused enabled item, else the `'active'` rule. A nested\n * composite or a control that uses the arrow keys itself holds it only when no other item can;\n * `'none'` — no item: every item is `tabIndex=-1` (a nested composite keeps its own tab stop;\n * mark it `data-roving-transparent` to join the group's arrow order), and focus reaches the\n * items only through the keys or a script.\n * - **Keys** are ignored when another handler already called `preventDefault()`; with Meta; with\n * Alt or Ctrl, except a single character typed with AltGr (Ctrl+Alt on Windows), which is\n * typeahead text (arrows, Home, End and Space with Ctrl+Alt stay ignored); and when they start\n * in a text field, select, contenteditable, slider, spinbutton or editable combobox (Left/Right\n * keep moving the caret; a select-only combobox such as Dropdown's button does not keep them).\n * Left/Right are mirrored in RTL (`dir`, else the direction of the container at key time).\n * Arrows and typeahead move from the item the key started in — the innermost one when items\n * nest, as treeitems do inside their parent's group; when it started on no item (focus on the\n * container itself) next goes to the first enabled item and prev to the last.\n * An item whose `focus()` leaves focus where it was (the browser ignores it on an element CSS\n * hides) is passed over for the next one, and is never recorded or reported to `onFocusMove`.\n * Handled keys call `preventDefault()`. Keys and focus from outside the container's DOM — a\n * popup an item renders through a portal, whose events React bubbles through the container —\n * are ignored, so focus never leaves an open menu or popover for the container's items.\n *\n * @example\n * const { containerProps, getTabIndex } = useRovingTabIndex({ activeValue: value, orientation: 'both' });\n * <div role=\"radiogroup\" {...containerProps}>\n * <button role=\"radio\" data-roving-value=\"a\" tabIndex={getTabIndex('a')} />\n * </div>\n *\n * The 0.4 call shape `useRovingTabIndex(containerRef, options)` still works: pass the container's\n * ref object and attach `handleKeyDown` (and ideally `handleFocus`, and with `typeahead`\n * `handleKeyDownCapture` as `onKeyDownCapture`) yourself.\n *\n * @param options - See {@link UseRovingTabIndexOptions}.\n * @returns See {@link UseRovingTabIndexResult}.\n */\nexport function useRovingTabIndex(options: UseRovingTabIndexOptions): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n containerRef: React.RefObject<HTMLElement | null>,\n options: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult;\nexport function useRovingTabIndex(\n refOrOptions: React.RefObject<HTMLElement | null> | UseRovingTabIndexOptions,\n maybeOptions?: UseRovingTabIndexOptions,\n): UseRovingTabIndexResult {\n const legacyRef =\n maybeOptions !== undefined ? (refOrOptions as React.RefObject<HTMLElement | null>) : undefined;\n const options = (maybeOptions ?? refOrOptions) as UseRovingTabIndexOptions;\n const {\n activeValue = null,\n items,\n orientation = 'horizontal',\n columns,\n loop = true,\n dir,\n itemSelector = DEFAULT_ITEM_SELECTOR,\n typeahead = false,\n homeEndKeys = true,\n tabStop = 'active',\n manageTabIndex = false,\n onFocusMove,\n } = options;\n\n const [store] = React.useState(() => new RovingStore());\n const snapshot = React.useSyncExternalStore(\n store.subscribe,\n store.getSnapshot,\n store.getServerSnapshot,\n );\n const [focusedValue, setFocusedValue] = React.useState<string | null>(null);\n // The last focused item that can hold the tab stop ('last-focused' during render).\n const [focusedStop, setFocusedStop] = React.useState<string | null>(null);\n\n // 0.4 call shape or explicit `items`: only elements with their own roving container are nested\n // composites (a role=radiogroup/tablist/… around the items is the widget's own root).\n const roleComposites = legacyRef === undefined && items === undefined;\n\n React.useLayoutEffect(() => {\n store.setOptions({ itemSelector, manageTabIndex, items, activeValue, tabStop, roleComposites });\n if (legacyRef) store.setContainer(legacyRef.current);\n store.stamp();\n });\n\n // C-DEV: `resolveOwn` treats a selector the browser rejects as \"no items\" (it runs during render,\n // where it must not throw), so the developer hears about it here.\n React.useEffect(() => {\n if (isDev && !isValidSelector(itemSelector)) {\n warnOnce(\n `useRovingTabIndex:itemSelector:${itemSelector}`,\n `useRovingTabIndex: itemSelector \"${itemSelector}\" is not a valid CSS selector in this browser; no item is navigable or tabbable.`,\n );\n }\n }, [itemSelector]);\n\n // C-DEV: a grid needs rows, from role=\"row\" elements or a `columns` count.\n React.useEffect(() => {\n if (!isDev || orientation !== 'grid' || columns) return;\n const container = store.container;\n if (container && container.querySelector('[role=\"row\"]') === null) {\n warnOnce(\n 'useRovingTabIndex:grid-rows',\n 'useRovingTabIndex: orientation \"grid\" needs role=\"row\" elements around the items or a `columns` count; without either it acts as \"both\".',\n );\n }\n });\n\n // Tab stop during render, from the DOM snapshot (null before the container is known).\n const domItems = React.useMemo(() => parseSnapshot(snapshot), [snapshot]);\n const stopEntries = React.useMemo<readonly SnapshotEntry[] | null>(() => {\n if (!items) return domItems;\n // Explicit `items`: the listed values the DOM has, in the listed order. Every listed value\n // before the container is known, or while the DOM has none of them yet (items rendered in the\n // commit the snapshot has not caught up with).\n if (domItems) {\n const ranks = new Map(domItems);\n const present = items.flatMap((value): SnapshotEntry[] => {\n const rank = ranks.get(value);\n return rank === undefined ? [] : [[value, rank]];\n });\n if (present.length > 0) return present;\n }\n return items.map((value): SnapshotEntry => [value, 1]);\n }, [items, domItems]);\n const tabStopValue =\n tabStop === 'none'\n ? null\n : stopEntries\n ? resolveTabStop(stopEntries, activeValue, tabStop, focusedStop)\n : activeValue || null;\n\n const getTabIndex = React.useCallback(\n (value: string): 0 | -1 => (value === tabStopValue ? 0 : -1),\n [tabStopValue],\n );\n\n const containerRef = React.useCallback(\n (node: HTMLElement | null) => {\n store.setContainer(node);\n if (legacyRef) setRef(legacyRef, node);\n },\n [store, legacyRef],\n );\n\n const typeaheadItemsRef = React.useRef<TypeaheadItem[]>([]);\n // Every item matching the typed characters, in search order (the first is the match).\n const typeaheadMatchesRef = React.useRef<readonly string[]>([]);\n const { onTypeahead, isSearching } = useTypeahead({\n getItems: () => typeaheadItemsRef.current,\n onMatch: (_value, matches) => {\n typeaheadMatchesRef.current = matches;\n },\n });\n\n /** Focuses an item; `true` only when focus actually moved there (then it is recorded). */\n const focusItem = (item: ResolvedItem | undefined): boolean => {\n if (!item || item.disabled) return false;\n const target = getFocusTarget(item);\n if (!target) return false;\n target.focus();\n // Browsers ignore focus() on an element CSS hides (display: none, visibility: hidden).\n if (!hasFocus(target)) return false;\n store.recordFocus(item);\n return true;\n };\n\n /** Focuses the first item of `candidates` that takes focus. */\n const focusFirstOf = (candidates: readonly ResolvedItem[]): void => {\n for (const item of candidates) {\n if (focusItem(item)) return;\n }\n };\n\n // `spaceOnly` (the capture phase) handles nothing but a Space that continues a typeahead search.\n const handleKeys = useEventCallback((e: React.KeyboardEvent, spaceOnly: boolean) => {\n // Ctrl, Alt and Meta combinations are shortcuts, except a single character typed with AltGr\n // (Ctrl+Alt on Windows), which is typeahead text: arrows, Home, End and Space with it stay\n // shortcuts.\n const gridCtrlHomeEnd =\n orientation === 'grid' && e.ctrlKey && !e.altKey && (e.key === 'Home' || e.key === 'End');\n const shortcut =\n e.metaKey || ((e.altKey || e.ctrlKey) && !isAltGraphCharacter(e) && !gridCtrlHomeEnd);\n if (e.defaultPrevented || shortcut) return;\n if (ownsArrowKeys(e.target)) return;\n const container = store.container ?? (e.currentTarget as HTMLElement);\n // A key from a portaled popup is the popup's: never pull focus back out of it.\n if (!isInContainer(container, e.target)) return;\n const ordered = store.resolve(container);\n const enabled = ordered.filter((item) => !item.disabled);\n if (enabled.length === 0) return;\n\n // The (innermost) item the key started in. None (the container itself has focus): next → first,\n // prev → last.\n const current = findOwningItem(ordered, e.target, container);\n\n let handled = false;\n // Where focus goes, in order of preference: an item whose focus() does not move focus (hidden\n // by CSS) passes the key on to the next one.\n let targets: ResolvedItem[] = [];\n const rows =\n orientation === 'grid' && !spaceOnly ? groupIntoRows(ordered, container, columns) : null;\n const gridMove = rows ? gridTargets(e, rows, current) : undefined;\n const intent =\n spaceOnly || gridMove\n ? null\n : getArrowIntent(e.key, {\n orientation: orientation === 'grid' ? (rows ? 'horizontal' : 'both') : orientation,\n dir: dir ?? getDirection(e.currentTarget as Element),\n });\n if (gridMove) {\n handled = true;\n targets = gridMove === 'stay' ? [] : gridMove;\n } else if (intent) {\n handled = true;\n if (!current) {\n targets = intent === 'next' ? enabled : [...enabled].reverse();\n } else {\n const step = intent === 'next' ? 1 : -1;\n const count = ordered.length;\n let index = ordered.indexOf(current);\n for (let i = 1; i < count; i++) {\n index += step;\n if (index < 0 || index >= count) {\n if (!loop) break;\n index = (index + count) % count;\n }\n if (!ordered[index].disabled) targets.push(ordered[index]);\n }\n }\n } else if (!spaceOnly && homeEndKeys && (e.key === 'Home' || e.key === 'End')) {\n handled = true;\n targets = e.key === 'Home' ? enabled : [...enabled].reverse();\n } else if (typeahead && startsOnItem(current, e.target, container)) {\n typeaheadItemsRef.current = ordered.map((item) => ({\n value: item.value,\n text: textOf(item.element),\n disabled: item.disabled,\n }));\n typeaheadMatchesRef.current = [];\n if (onTypeahead(e, current?.value ?? null)) {\n handled = true;\n // The match first, then the next ones, for a match that does not take focus.\n targets = typeaheadMatchesRef.current.flatMap((value) =>\n enabled.filter((item) => item.value === value),\n );\n }\n }\n\n if (!handled) return;\n e.preventDefault();\n for (const next of targets) {\n // Back at the item the key started on (Home on the first item): focus stays.\n if (next === current) return;\n if (focusItem(next)) {\n onFocusMove?.(next.value, e);\n return;\n }\n }\n });\n\n const handleKeyDown = useEventCallback((e: React.KeyboardEvent) => handleKeys(e, false));\n\n // A Space that continues a typeahead search belongs to the search, not to the focused item: it is\n // handled and default-prevented in the capture phase, so the item's own keydown handler, which\n // skips default-prevented events, does not activate the item.\n const handleKeyDownCapture = useEventCallback((e: React.KeyboardEvent) => {\n if (typeahead && e.key === ' ' && isSearching()) handleKeys(e, true);\n });\n\n const handleFocus = useEventCallback((e: React.FocusEvent) => {\n const container = store.container ?? (e.currentTarget as HTMLElement);\n if (!isInContainer(container, e.target)) return;\n const item = findOwningItem(store.resolve(container), e.target, container);\n if (!item) return;\n store.recordFocus(item);\n setFocusedValue(item.value);\n if (canHoldTabStop(item)) setFocusedStop(item.value);\n store.stamp();\n });\n\n const focusValue = useEventCallback((value: string) => {\n focusItem(store.resolve().find((item) => item.value === value));\n });\n const focusFirst = useEventCallback(() => {\n focusFirstOf(store.resolve().filter((item) => !item.disabled));\n });\n const focusLast = useEventCallback(() => {\n focusFirstOf(\n store\n .resolve()\n .filter((item) => !item.disabled)\n .reverse(),\n );\n });\n\n const containerProps = React.useMemo<RovingContainerProps>(\n () => ({\n ref: containerRef,\n 'data-roving-container': '',\n onKeyDown: handleKeyDown,\n onKeyDownCapture: handleKeyDownCapture,\n onFocus: handleFocus,\n }),\n [containerRef, handleKeyDown, handleKeyDownCapture, handleFocus],\n );\n\n return {\n containerProps,\n handleKeyDown,\n handleKeyDownCapture,\n handleFocus,\n getTabIndex,\n focusedValue,\n focusValue,\n focusFirst,\n focusLast,\n };\n}\n"],"mappings":"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"}
|