@spaced-out/ui-design-system 0.6.36 → 0.6.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.cspell/custom-words.txt +9 -0
  2. package/CHANGELOG.md +9 -0
  3. package/lib/components/ButtonDropdown/ButtonDropdown.d.ts +10 -0
  4. package/lib/components/ButtonDropdown/ButtonDropdown.d.ts.map +1 -1
  5. package/lib/components/ButtonDropdown/ButtonDropdown.js +26 -3
  6. package/lib/components/ButtonTabs/ButtonTab/ButtonTab.d.ts +9 -1
  7. package/lib/components/ButtonTabs/ButtonTab/ButtonTab.d.ts.map +1 -1
  8. package/lib/components/ButtonTabs/ButtonTab/ButtonTab.js +8 -0
  9. package/lib/components/ButtonTabs/ButtonTabDropdown.d.ts +10 -1
  10. package/lib/components/ButtonTabs/ButtonTabDropdown.d.ts.map +1 -1
  11. package/lib/components/ButtonTabs/ButtonTabDropdown.js +31 -3
  12. package/lib/components/ButtonTabs/ButtonTabs.d.ts +6 -0
  13. package/lib/components/ButtonTabs/ButtonTabs.d.ts.map +1 -1
  14. package/lib/components/ButtonTabs/ButtonTabs.js +2 -0
  15. package/lib/components/Combobox/Combobox.d.ts +9 -0
  16. package/lib/components/Combobox/Combobox.d.ts.map +1 -1
  17. package/lib/components/Combobox/Combobox.js +21 -0
  18. package/lib/components/Combobox/helper.d.ts.map +1 -1
  19. package/lib/components/Combobox/helper.js +0 -4
  20. package/lib/components/Dropdown/Dropdown.d.ts +9 -0
  21. package/lib/components/Dropdown/Dropdown.d.ts.map +1 -1
  22. package/lib/components/Dropdown/Dropdown.js +92 -24
  23. package/lib/components/Dropdown/Dropdown.module.css +24 -0
  24. package/lib/components/InlineDropdown/InlineDropdown.d.ts +10 -0
  25. package/lib/components/InlineDropdown/InlineDropdown.d.ts.map +1 -1
  26. package/lib/components/InlineDropdown/InlineDropdown.js +23 -3
  27. package/lib/components/Input/Input.module.css +38 -0
  28. package/lib/components/Menu/Menu.d.ts +99 -0
  29. package/lib/components/Menu/Menu.d.ts.map +1 -1
  30. package/lib/components/Menu/Menu.js +1152 -187
  31. package/lib/components/Menu/Menu.module.css +191 -7
  32. package/lib/components/Menu/MenuFocusScope.d.ts +21 -0
  33. package/lib/components/Menu/MenuFocusScope.d.ts.map +1 -0
  34. package/lib/components/Menu/MenuFocusScope.js +37 -0
  35. package/lib/components/Menu/MenuOptionButton.d.ts +36 -0
  36. package/lib/components/Menu/MenuOptionButton.d.ts.map +1 -1
  37. package/lib/components/Menu/MenuOptionButton.js +137 -29
  38. package/lib/components/Menu/index.d.ts +2 -0
  39. package/lib/components/Menu/index.d.ts.map +1 -1
  40. package/lib/components/Menu/index.js +22 -0
  41. package/lib/components/Menu/menuOptionId.d.ts +12 -0
  42. package/lib/components/Menu/menuOptionId.d.ts.map +1 -0
  43. package/lib/components/Menu/menuOptionId.js +18 -0
  44. package/lib/components/Menu/useMenuKeyboardNavigation.d.ts +93 -0
  45. package/lib/components/Menu/useMenuKeyboardNavigation.d.ts.map +1 -0
  46. package/lib/components/Menu/useMenuKeyboardNavigation.js +471 -0
  47. package/lib/components/Menu/useMenuTrigger.d.ts +207 -0
  48. package/lib/components/Menu/useMenuTrigger.d.ts.map +1 -0
  49. package/lib/components/Menu/useMenuTrigger.js +389 -0
  50. package/lib/components/OptionButton/OptionButton.d.ts +16 -0
  51. package/lib/components/OptionButton/OptionButton.d.ts.map +1 -1
  52. package/lib/components/OptionButton/OptionButton.js +4 -1
  53. package/lib/components/Tabs/Tab/Tab.d.ts +8 -1
  54. package/lib/components/Tabs/Tab/Tab.d.ts.map +1 -1
  55. package/lib/components/Tabs/Tab/Tab.js +8 -0
  56. package/lib/components/Tabs/TabList/TabDropdown.d.ts +10 -1
  57. package/lib/components/Tabs/TabList/TabDropdown.d.ts.map +1 -1
  58. package/lib/components/Tabs/TabList/TabDropdown.js +23 -3
  59. package/lib/components/Tabs/TabList/TabList.d.ts +14 -0
  60. package/lib/components/Tabs/TabList/TabList.d.ts.map +1 -1
  61. package/lib/components/Tabs/TabList/TabList.js +6 -0
  62. package/lib/components/Typeahead/Typeahead.d.ts +9 -0
  63. package/lib/components/Typeahead/Typeahead.d.ts.map +1 -1
  64. package/lib/components/Typeahead/Typeahead.js +107 -13
  65. package/lib/components/Typeahead/Typeahead.module.css +13 -0
  66. package/lib/hooks/index.d.ts +1 -0
  67. package/lib/hooks/index.d.ts.map +1 -1
  68. package/lib/hooks/index.js +11 -0
  69. package/lib/hooks/useInteractionModality/index.d.ts +2 -0
  70. package/lib/hooks/useInteractionModality/index.d.ts.map +1 -0
  71. package/lib/hooks/useInteractionModality/index.js +16 -0
  72. package/lib/hooks/useInteractionModality/useInteractionModality.d.ts +39 -0
  73. package/lib/hooks/useInteractionModality/useInteractionModality.d.ts.map +1 -0
  74. package/lib/hooks/useInteractionModality/useInteractionModality.js +111 -0
  75. package/lib/utils/click-away/click-away.d.ts +16 -0
  76. package/lib/utils/click-away/click-away.d.ts.map +1 -1
  77. package/lib/utils/click-away/click-away.js +49 -0
  78. package/mcp/package.json +1 -1
  79. package/package.json +1 -1
@@ -0,0 +1,207 @@
1
+ import * as React from 'react';
2
+ import type { MenuOption, MenuProps } from '../../components/Menu/Menu';
3
+ /**
4
+ * Wires a trigger to the Menu it opens.
5
+ *
6
+ * Three things have to live on the trigger rather than in Menu, because they
7
+ * exist while the menu does NOT: `aria-haspopup`, `aria-expanded="false"`, and
8
+ * the ArrowDown/ArrowUp that opens the popup in the first place. That is the
9
+ * floor — no Menu prop can supply them — so these hooks hand them over as props
10
+ * to spread instead, and own everything else: the ids, the tie between the
11
+ * trigger's name and the listbox, and the ref Menu focuses into on open.
12
+ *
13
+ * `useMenuTrigger` is for triggers whose popup options own focus — a button, a
14
+ * tab overflow chevron, an inline label — so arrows move real DOM focus.
15
+ * `useComboboxMenuTrigger` is for triggers that are text inputs, where focus
16
+ * stays put and the highlight is virtual (`aria-activedescendant`).
17
+ *
18
+ * `getTriggerProps` is a getter rather than a static object because open state
19
+ * belongs to the consumer's `ClickAway`, which exposes it through a render
20
+ * callback — where a hook cannot be called.
21
+ *
22
+ * const menuTrigger = useMenuTrigger({id: props.id, ariaLabel: menu?.ariaLabel});
23
+ * <ClickAway restoreFocusOnClose>
24
+ * {({isOpen, onOpen, clickAway}) => (
25
+ * <>
26
+ * <Button {...props} {...menuTrigger.getTriggerProps({isOpen, onOpen})} />
27
+ * {isOpen && (
28
+ * <Menu
29
+ * {...menu}
30
+ * {...menuTrigger.menuProps}
31
+ * enableA11y
32
+ * onTabOut={clickAway}
33
+ * />
34
+ * )}
35
+ * </>
36
+ * )}
37
+ * </ClickAway>
38
+ *
39
+ * `restoreFocusOnClose` is what returns focus to the trigger when the menu
40
+ * closes. Menu moves focus INTO the popup on open, so without it Escape, a
41
+ * selection or Tab leaves focus on `document.body` — the components in this
42
+ * package pass it alongside their own `enableA11y`.
43
+ */
44
+ export interface UseMenuTriggerArgs {
45
+ /**
46
+ * Produce the wiring at all. False returns empty props and an inert handler,
47
+ * so a consumer can call the hook unconditionally (hooks cannot be
48
+ * conditional) while its own accessibility opt-in is off.
49
+ */
50
+ enabled?: boolean;
51
+ /**
52
+ * The trigger's own `id`, when the consumer supplied one. It is kept — the
53
+ * hook only mints an id when there is none, since the listbox is named after
54
+ * the trigger through it.
55
+ */
56
+ id?: string;
57
+ /** The listbox id, when the consumer set `menu.menuId`. Minted otherwise. */
58
+ menuId?: string;
59
+ /** Literal name for the listbox. Wins over naming it after the trigger. */
60
+ ariaLabel?: string;
61
+ /** Id of the element naming the listbox. Defaults to the trigger itself. */
62
+ ariaLabelledBy?: string;
63
+ }
64
+ /**
65
+ * Generic in the trigger element so the returned handler matches whatever it is
66
+ * spread onto — inferred from the trigger's own `onKeyDown` where it has one.
67
+ */
68
+ export interface GetTriggerPropsArgs<T extends HTMLElement = HTMLElement> {
69
+ /** The consumer's popup state — what ClickAway reports. */
70
+ isOpen: boolean;
71
+ onOpen: () => void;
72
+ /** The trigger's own key handler, if it has one. Runs first. */
73
+ onKeyDown?: React.KeyboardEventHandler<T>;
74
+ }
75
+ export interface MenuTriggerProps<T extends HTMLElement = HTMLElement> {
76
+ id: string;
77
+ 'aria-haspopup': 'listbox';
78
+ 'aria-expanded': boolean;
79
+ 'aria-controls': string | undefined;
80
+ onKeyDown: React.KeyboardEventHandler<T>;
81
+ }
82
+ export interface MenuTriggerMenuProps {
83
+ menuId: string;
84
+ ariaLabelledBy?: string;
85
+ ariaLabel?: string;
86
+ initialFocusRef: React.RefObject<HTMLElement | null>;
87
+ }
88
+ export declare const useMenuTrigger: ({ enabled, id, menuId: consumerMenuId, ariaLabel, ariaLabelledBy, }?: UseMenuTriggerArgs) => {
89
+ getTriggerProps: <T extends HTMLElement = HTMLElement>(args: GetTriggerPropsArgs<T>) => MenuTriggerProps<T>;
90
+ menuProps: MenuTriggerMenuProps;
91
+ };
92
+ /**
93
+ * Which of ARIA's two combobox patterns the trigger implements.
94
+ *
95
+ * - `select` — a read-only field standing in for a `<select>`. An option is
96
+ * highlighted as soon as the list opens, Space selects it (the field has no
97
+ * typing role), and Enter or Space opens the list in the first place.
98
+ * - `autocomplete` — an editable field that filters the list as you type.
99
+ * Nothing is highlighted until the user arrows to it (APG calls this manual
100
+ * selection: auto-highlighting would let Enter select something they never
101
+ * chose), Space types a space, and only the arrow keys open the list.
102
+ */
103
+ export type ComboboxPattern = 'select' | 'autocomplete';
104
+ export interface UseComboboxMenuTriggerArgs {
105
+ /**
106
+ * Produce the wiring at all. False returns empty props and an inert handler,
107
+ * so a consumer can call the hook unconditionally while its own accessibility
108
+ * opt-in is off.
109
+ */
110
+ enabled?: boolean;
111
+ /** Which pattern this trigger implements. Defaults to `select`. */
112
+ pattern?: ComboboxPattern;
113
+ /**
114
+ * The menu this trigger opens. Read for the option source (unless `options`
115
+ * is given), the selection, `virtualization`, `menuDisabled`, `resolveLabel`,
116
+ * `allowSearch` and the consumer's own `menuId` / `ariaLabel` /
117
+ * `ariaLabelledBy`, all of which win over what the hook would derive.
118
+ */
119
+ menu?: MenuProps;
120
+ /**
121
+ * Option source, when it is not `menu` — a consumer that owns filtering and
122
+ * hands the already-filtered options to Menu supplies them here instead. Every
123
+ * derivation (navigation list, highlight seed, selection lookup) uses it.
124
+ */
125
+ options?: Array<MenuOption>;
126
+ /**
127
+ * Refuse to open, e.g. until enough has been typed. Consulted only for the
128
+ * keys that would otherwise open the list.
129
+ */
130
+ canOpen?: () => boolean;
131
+ /** Ref on the rendered Menu, for reaching its header/footer controls. */
132
+ menuRef: React.RefObject<HTMLElement | null>;
133
+ /**
134
+ * The consumer's popup state — what ClickAway reports. Drives which keys the
135
+ * trigger handles (open-state navigation vs. closed-state opening) and the
136
+ * highlight's lifecycle. If the listbox can be WITHHELD while the popup is
137
+ * open (still loading, no matches), keep passing the open state here and hand
138
+ * `isExpanded` to `getTriggerProps` for the ARIA — routing keys off the
139
+ * rendered state instead would make an arrow key call `onOpen` on an
140
+ * already-open popup, and `onOpen` toggles.
141
+ */
142
+ isOpen: boolean;
143
+ /** Apply a selection. Called with the option the keyboard acted on. */
144
+ onSelectOption: (option: MenuOption) => void;
145
+ /** Close the popup — used when Tab leaves a menu with no chrome to land on. */
146
+ onClose: () => void;
147
+ /** Put focus back on the trigger input, keeping the menu open. */
148
+ focusTrigger: () => void;
149
+ /** What already labels the trigger, used to name the listbox after it. */
150
+ triggerAriaLabelledBy?: string;
151
+ triggerAriaLabel?: string;
152
+ /**
153
+ * Literal name for the listbox when nothing else supplies one. Defaults to
154
+ * `'Options'`; a suggestion list wants something truer to what it holds.
155
+ */
156
+ defaultAriaLabel?: string;
157
+ }
158
+ export interface GetComboboxTriggerPropsArgs<T extends HTMLElement = HTMLElement> extends GetTriggerPropsArgs<T> {
159
+ /**
160
+ * Whether the listbox is actually rendered right now, when that can differ
161
+ * from `isOpen` (a popup withheld while loading or with no matches). Drives
162
+ * `aria-expanded`, `aria-controls` and `aria-activedescendant`, so the trigger
163
+ * never claims an expanded listbox that is not in the DOM. Defaults to
164
+ * `isOpen`.
165
+ */
166
+ isExpanded?: boolean;
167
+ }
168
+ export interface ComboboxTriggerProps<T extends HTMLElement = HTMLElement> {
169
+ role: 'combobox';
170
+ 'aria-haspopup': 'listbox';
171
+ 'aria-expanded': boolean;
172
+ 'aria-controls': string | undefined;
173
+ 'aria-autocomplete': 'none' | 'list';
174
+ 'aria-activedescendant': string | undefined;
175
+ onKeyDown: React.KeyboardEventHandler<T>;
176
+ }
177
+ export interface ComboboxMenuProps {
178
+ menuId: string;
179
+ ariaLabelledBy?: string;
180
+ ariaLabel?: string;
181
+ externalKeyboardNav: boolean;
182
+ activeOptionKey?: string | null;
183
+ onActiveOptionKeyChange?: (key: string | null) => void;
184
+ onReturnFocusToInput?: () => void;
185
+ initialFocusRef?: React.RefObject<HTMLElement | null>;
186
+ }
187
+ /**
188
+ * Wires a COMBOBOX trigger — a text input — to the Menu it opens. Focus stays
189
+ * on the input and the highlight is virtual, reported through
190
+ * `aria-activedescendant`, because the input has to keep receiving the keys it
191
+ * filters with.
192
+ *
193
+ * Driving the highlight from outside Menu means owning the active option as
194
+ * state, and owning it means deriving the same option list, initial highlight
195
+ * and navigation list that Menu derives internally. Both combobox consumers had
196
+ * grown their own copies of all three; they come from Menu itself now.
197
+ *
198
+ * A menu that carries its own filter field (`menu.allowSearch`) inverts the
199
+ * model: navigation lives inside Menu, so the trigger stops driving it and
200
+ * hands over an `initialFocusRef` instead. Both shapes come out of this hook.
201
+ */
202
+ export declare const useComboboxMenuTrigger: ({ enabled, pattern, menu, options, canOpen, menuRef, isOpen, onSelectOption, onClose, focusTrigger, triggerAriaLabelledBy, triggerAriaLabel, defaultAriaLabel, }: UseComboboxMenuTriggerArgs) => {
203
+ getTriggerProps: <T extends HTMLElement = HTMLElement>(args: GetComboboxTriggerPropsArgs<T>) => ComboboxTriggerProps<T>;
204
+ menuProps: ComboboxMenuProps;
205
+ activeOptionKey: string | null;
206
+ };
207
+ //# sourceMappingURL=useMenuTrigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMenuTrigger.d.ts","sourceRoot":"","sources":["../../../src/components/Menu/useMenuTrigger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useMenuTrigger = exports.useComboboxMenuTrigger = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _hooks = require("../../hooks");
9
+ var _Menu = require("./Menu");
10
+ var _menuOptionId = require("./menuOptionId");
11
+ var _useMenuKeyboardNavigation = require("./useMenuKeyboardNavigation");
12
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
+ /**
14
+ * Drop undefined-valued keys. The props these hooks return are spread AFTER the
15
+ * consumer's own `menu` props, and an own property holding `undefined` would
16
+ * erase a value the consumer set — `{...menu, ...{ariaLabel: undefined}}` has no
17
+ * label at all.
18
+ */
19
+ const compact = obj => Object.fromEntries(Object.entries(obj).filter(_ref => {
20
+ let [, value] = _ref;
21
+ return value !== undefined;
22
+ }));
23
+
24
+ /**
25
+ * Wires a trigger to the Menu it opens.
26
+ *
27
+ * Three things have to live on the trigger rather than in Menu, because they
28
+ * exist while the menu does NOT: `aria-haspopup`, `aria-expanded="false"`, and
29
+ * the ArrowDown/ArrowUp that opens the popup in the first place. That is the
30
+ * floor — no Menu prop can supply them — so these hooks hand them over as props
31
+ * to spread instead, and own everything else: the ids, the tie between the
32
+ * trigger's name and the listbox, and the ref Menu focuses into on open.
33
+ *
34
+ * `useMenuTrigger` is for triggers whose popup options own focus — a button, a
35
+ * tab overflow chevron, an inline label — so arrows move real DOM focus.
36
+ * `useComboboxMenuTrigger` is for triggers that are text inputs, where focus
37
+ * stays put and the highlight is virtual (`aria-activedescendant`).
38
+ *
39
+ * `getTriggerProps` is a getter rather than a static object because open state
40
+ * belongs to the consumer's `ClickAway`, which exposes it through a render
41
+ * callback — where a hook cannot be called.
42
+ *
43
+ * const menuTrigger = useMenuTrigger({id: props.id, ariaLabel: menu?.ariaLabel});
44
+ * <ClickAway restoreFocusOnClose>
45
+ * {({isOpen, onOpen, clickAway}) => (
46
+ * <>
47
+ * <Button {...props} {...menuTrigger.getTriggerProps({isOpen, onOpen})} />
48
+ * {isOpen && (
49
+ * <Menu
50
+ * {...menu}
51
+ * {...menuTrigger.menuProps}
52
+ * enableA11y
53
+ * onTabOut={clickAway}
54
+ * />
55
+ * )}
56
+ * </>
57
+ * )}
58
+ * </ClickAway>
59
+ *
60
+ * `restoreFocusOnClose` is what returns focus to the trigger when the menu
61
+ * closes. Menu moves focus INTO the popup on open, so without it Escape, a
62
+ * selection or Tab leaves focus on `document.body` — the components in this
63
+ * package pass it alongside their own `enableA11y`.
64
+ */
65
+
66
+ /**
67
+ * Generic in the trigger element so the returned handler matches whatever it is
68
+ * spread onto — inferred from the trigger's own `onKeyDown` where it has one.
69
+ */
70
+
71
+ const useMenuTrigger = function () {
72
+ let {
73
+ enabled = true,
74
+ id,
75
+ menuId: consumerMenuId,
76
+ ariaLabel,
77
+ ariaLabelledBy
78
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
79
+ const generatedMenuId = React.useId();
80
+ const generatedTriggerId = React.useId();
81
+ const menuId = consumerMenuId ?? generatedMenuId;
82
+ const triggerId = id ?? generatedTriggerId;
83
+ const initialFocusRef = React.useRef(null);
84
+ // The trigger exists before the popup does, which is the only point early
85
+ // enough to observe the keypress that opens it.
86
+ React.useEffect(() => {
87
+ if (enabled) {
88
+ (0, _hooks.startInteractionModalityTracking)();
89
+ }
90
+ }, [enabled]);
91
+ const getTriggerProps = _ref2 => {
92
+ let {
93
+ isOpen,
94
+ onOpen,
95
+ onKeyDown
96
+ } = _ref2;
97
+ return !enabled ?
98
+ // Nothing but the consumer's own handler, so spreading this changes
99
+ // nothing about the trigger. Compacted because these props are spread
100
+ // AFTER the consumer's: a key holding `undefined` would erase theirs.
101
+ compact({
102
+ onKeyDown
103
+ }) : {
104
+ id: triggerId,
105
+ 'aria-haspopup': 'listbox',
106
+ 'aria-expanded': isOpen,
107
+ // Only while the listbox is actually rendered: an IDREF that resolves to
108
+ // nothing is an invalid value, not an empty one.
109
+ 'aria-controls': isOpen ? menuId : undefined,
110
+ onKeyDown: event => {
111
+ onKeyDown?.(event);
112
+ // Opening on an arrow key is the trigger's job precisely because the menu
113
+ // does not exist yet to handle it. Leave the key alone if the trigger's
114
+ // own handler already claimed it.
115
+ if (event.defaultPrevented || isOpen) {
116
+ return;
117
+ }
118
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
119
+ event.preventDefault();
120
+ onOpen();
121
+ }
122
+ }
123
+ };
124
+ };
125
+ return {
126
+ getTriggerProps,
127
+ menuProps: !enabled ? {} : compact({
128
+ menuId,
129
+ // An explicit label suppresses the idref, so the two never compete.
130
+ ariaLabelledBy: ariaLabel ? undefined : ariaLabelledBy ?? triggerId,
131
+ ariaLabel,
132
+ initialFocusRef
133
+ })
134
+ };
135
+ };
136
+
137
+ /**
138
+ * Which of ARIA's two combobox patterns the trigger implements.
139
+ *
140
+ * - `select` — a read-only field standing in for a `<select>`. An option is
141
+ * highlighted as soon as the list opens, Space selects it (the field has no
142
+ * typing role), and Enter or Space opens the list in the first place.
143
+ * - `autocomplete` — an editable field that filters the list as you type.
144
+ * Nothing is highlighted until the user arrows to it (APG calls this manual
145
+ * selection: auto-highlighting would let Enter select something they never
146
+ * chose), Space types a space, and only the arrow keys open the list.
147
+ */
148
+ exports.useMenuTrigger = useMenuTrigger;
149
+ /**
150
+ * Wires a COMBOBOX trigger — a text input — to the Menu it opens. Focus stays
151
+ * on the input and the highlight is virtual, reported through
152
+ * `aria-activedescendant`, because the input has to keep receiving the keys it
153
+ * filters with.
154
+ *
155
+ * Driving the highlight from outside Menu means owning the active option as
156
+ * state, and owning it means deriving the same option list, initial highlight
157
+ * and navigation list that Menu derives internally. Both combobox consumers had
158
+ * grown their own copies of all three; they come from Menu itself now.
159
+ *
160
+ * A menu that carries its own filter field (`menu.allowSearch`) inverts the
161
+ * model: navigation lives inside Menu, so the trigger stops driving it and
162
+ * hands over an `initialFocusRef` instead. Both shapes come out of this hook.
163
+ */
164
+ const useComboboxMenuTrigger = _ref3 => {
165
+ let {
166
+ enabled = true,
167
+ pattern = 'select',
168
+ menu,
169
+ options,
170
+ canOpen,
171
+ menuRef,
172
+ isOpen,
173
+ onSelectOption,
174
+ onClose,
175
+ focusTrigger,
176
+ triggerAriaLabelledBy,
177
+ triggerAriaLabel,
178
+ defaultAriaLabel = 'Options'
179
+ } = _ref3;
180
+ const generatedMenuId = React.useId();
181
+ // The consumer's own id wins: it is what their `aria-controls` elsewhere, or
182
+ // their tests, already point at.
183
+ const menuId = menu?.menuId ?? generatedMenuId;
184
+ // See the note in useMenuTrigger.
185
+ React.useEffect(() => {
186
+ if (enabled) {
187
+ (0, _hooks.startInteractionModalityTracking)();
188
+ }
189
+ }, [enabled]);
190
+ const initialFocusRef = React.useRef(null);
191
+ const [activeOptionKey, setActiveOptionKey] = React.useState(null);
192
+ const isAutocomplete = pattern === 'autocomplete';
193
+
194
+ // A searchable menu drives navigation internally from its own filter field; a
195
+ // select-only menu is driven by this trigger instead, with focus never
196
+ // entering the listbox. An autocomplete trigger IS the filter field, so it
197
+ // always drives navigation itself.
198
+ const usesExternalNav = isAutocomplete || !menu?.allowSearch;
199
+
200
+ /** The options the keyboard navigates, whatever supplied them. */
201
+ const optionSource = React.useMemo(() => options ?? (menu ? (0, _Menu.getFlatOptions)(menu) : []), [options, menu]);
202
+
203
+ /*
204
+ * `listbox` is an accessible-name-required role, so the popup must be named.
205
+ * Best name first:
206
+ * 1. what the consumer said (`menu.ariaLabelledBy` / `menu.ariaLabel`),
207
+ * 2. whatever already labels the trigger — a field label is the most useful
208
+ * name there is,
209
+ * 3. a literal fallback. Deliberately NOT the placeholder: echoing
210
+ * "Select..." names the list after an instruction, not its contents.
211
+ * An explicit label suppresses the idref, since a listbox drops `aria-label`
212
+ * whenever `aria-labelledby` is present.
213
+ */
214
+ const menuAriaLabelledBy = menu?.ariaLabelledBy ?? (menu?.ariaLabel ? undefined : triggerAriaLabelledBy);
215
+ const menuAriaLabel = menu?.ariaLabel ?? (menuAriaLabelledBy ? undefined : triggerAriaLabel ?? defaultAriaLabel);
216
+ const selectByKey = key => {
217
+ const option = optionSource.find(opt => opt.key === key);
218
+ if (option) {
219
+ onSelectOption(option);
220
+ }
221
+ };
222
+
223
+ /*
224
+ * A virtualized menu keeps only a window of rows in the DOM, so the keyboard
225
+ * hook would otherwise clamp End / PageDown / wrap-around / type-ahead to that
226
+ * window. Hand it the real option list in that case — whichever source it came
227
+ * from, and flat or grouped alike, since Menu handles both — and Menu
228
+ * scrolls the active row into view. Plain menus stay on the DOM-driven path,
229
+ * which keeps grouped layouts and `resolveLabel` type-ahead working off the
230
+ * rendered text.
231
+ */
232
+ const resolveLabel = menu?.resolveLabel;
233
+ const navigationOptions = React.useMemo(() => {
234
+ // A wholly disabled menu has no navigable options at all.
235
+ if (!menu?.virtualization?.enable || menu.menuDisabled) {
236
+ return undefined;
237
+ }
238
+ return optionSource.filter(option => !option.disabled).map(option => {
239
+ // Type-ahead must match the text the user can actually read.
240
+ const resolved = resolveLabel?.(option);
241
+ return {
242
+ key: option.key,
243
+ label: typeof resolved === 'string' ? resolved : option.label ?? ''
244
+ };
245
+ });
246
+ }, [menu?.virtualization?.enable, menu?.menuDisabled, resolveLabel, optionSource]);
247
+ const {
248
+ onKeyDown: onComboboxKeyDown
249
+ } = (0, _useMenuKeyboardNavigation.useMenuKeyboardNavigation)({
250
+ containerRef: menuRef,
251
+ enabled: enabled && isOpen && usesExternalNav && !menu?.menuDisabled,
252
+ // An editable trigger keeps printable keys for filtering; a read-only one
253
+ // spends them on type-ahead.
254
+ mode: isAutocomplete ? 'search' : 'activedescendant',
255
+ activeOptionKey,
256
+ onSelectKey: selectByKey,
257
+ setActiveOptionKey,
258
+ options: navigationOptions
259
+ });
260
+
261
+ /*
262
+ * Seed the highlight when the menu opens, drop it when it closes, and keep it
263
+ * valid while the option set changes underneath it (async or cascading
264
+ * options). Menu skips its own re-validation under `externalKeyboardNav`, so
265
+ * the trigger owns it — without this, `aria-activedescendant` could point at
266
+ * the id of an option that no longer exists. A layout effect, so the id is in
267
+ * place before the browser paints the open menu.
268
+ */
269
+ const selectedKeys = menu?.selectedKeys;
270
+ const selectedOption = menu?.selectedOption;
271
+ React.useLayoutEffect(() => {
272
+ // A closed list has no active option, whichever pattern this is.
273
+ if (!isOpen) {
274
+ setActiveOptionKey(null);
275
+ return;
276
+ }
277
+ const enabledKeys = optionSource.filter(option => !option.disabled).map(option => option.key);
278
+ const surviving = prev => prev && enabledKeys.includes(prev) ? prev : null;
279
+ if (isAutocomplete) {
280
+ // Manual selection: never highlight anything on the user's behalf, only
281
+ // drop a highlight that the filtering has removed under them.
282
+ setActiveOptionKey(surviving);
283
+ return;
284
+ }
285
+ if (!usesExternalNav) {
286
+ setActiveOptionKey(null);
287
+ return;
288
+ }
289
+ setActiveOptionKey(prev => surviving(prev) ?? (0, _Menu.getInitialActiveOptionKey)({
290
+ options: optionSource,
291
+ selectedKeys,
292
+ selectedOption
293
+ }));
294
+ }, [isAutocomplete, isOpen, usesExternalNav, optionSource, selectedKeys, selectedOption]);
295
+ const getTriggerProps = _ref4 => {
296
+ let {
297
+ isOpen: triggerIsOpen,
298
+ isExpanded,
299
+ onOpen,
300
+ onKeyDown
301
+ } = _ref4;
302
+ const expanded = isExpanded ?? triggerIsOpen;
303
+ if (!enabled) {
304
+ // Only the consumer's own handler, so spreading this is a no-op — and
305
+ // compacted, since a key holding `undefined` spread after the consumer's
306
+ // props would erase theirs.
307
+ return compact({
308
+ onKeyDown
309
+ });
310
+ }
311
+ return {
312
+ // The one combobox for both shapes: the menu's own filter field is a
313
+ // `searchbox`, so nothing competes for the listbox. Keeping the role
314
+ // unconditional also keeps `aria-expanded` valid — it is not an allowed
315
+ // attribute on a plain textbox.
316
+ role: 'combobox',
317
+ 'aria-haspopup': 'listbox',
318
+ 'aria-expanded': expanded,
319
+ // Only reference the listbox while it is actually rendered. The hook always
320
+ // hands `menuId` to Menu, so the element exists whenever `expanded` says so,
321
+ // whichever option source was supplied.
322
+ 'aria-controls': expanded ? menuId : undefined,
323
+ // 'list' whenever typing narrows the list: the autocomplete pattern, or a
324
+ // menu carrying its own filter field.
325
+ 'aria-autocomplete': isAutocomplete || !usesExternalNav ? 'list' : 'none',
326
+ 'aria-activedescendant': expanded && usesExternalNav && activeOptionKey ? (0, _menuOptionId.menuOptionId)(menuId, activeOptionKey) : undefined,
327
+ onKeyDown: event => {
328
+ onKeyDown?.(event);
329
+ if (event.defaultPrevented) {
330
+ return;
331
+ }
332
+ if (!triggerIsOpen) {
333
+ // Closed: the arrow keys open the list, and a read-only trigger takes
334
+ // Enter and Space for it too — a typed space belongs to an editable
335
+ // one. This is the part no Menu prop can supply: the menu does not
336
+ // exist yet.
337
+ const opensList = event.key === 'ArrowDown' || event.key === 'ArrowUp' || !isAutocomplete && (event.key === 'Enter' || event.key === ' ');
338
+ if (opensList && (canOpen?.() ?? true)) {
339
+ event.preventDefault();
340
+ onOpen();
341
+ }
342
+ return;
343
+ }
344
+ // Open + searchable: focus is in the menu's own filter field, which owns
345
+ // navigation — nothing to do here.
346
+ if (!usesExternalNav) {
347
+ return;
348
+ }
349
+ // Tab moves into the menu's footer, Shift+Tab into its header, when that
350
+ // region has focusable controls. With none there, the listbox closes
351
+ // (APG: the popup closes when the combobox loses focus) and focus moves
352
+ // on.
353
+ if (event.key === 'Tab') {
354
+ if ((0, _useMenuKeyboardNavigation.moveFocusToMenuChrome)(menuRef.current, event.shiftKey)) {
355
+ event.preventDefault();
356
+ } else {
357
+ onClose();
358
+ }
359
+ return;
360
+ }
361
+ // Space selects the active option — only where it has no typing role.
362
+ if (!isAutocomplete && event.key === ' ') {
363
+ event.preventDefault();
364
+ if (activeOptionKey) {
365
+ selectByKey(activeOptionKey);
366
+ }
367
+ return;
368
+ }
369
+ // Arrows / Home / End / Enter / type-ahead.
370
+ onComboboxKeyDown(event);
371
+ }
372
+ };
373
+ };
374
+ return {
375
+ getTriggerProps,
376
+ menuProps: !enabled ? {} : compact({
377
+ menuId,
378
+ ariaLabelledBy: menuAriaLabelledBy,
379
+ ariaLabel: menuAriaLabel,
380
+ externalKeyboardNav: usesExternalNav,
381
+ activeOptionKey: usesExternalNav ? activeOptionKey : undefined,
382
+ onActiveOptionKeyChange: usesExternalNav ? setActiveOptionKey : undefined,
383
+ onReturnFocusToInput: usesExternalNav ? focusTrigger : undefined,
384
+ initialFocusRef: usesExternalNav ? undefined : initialFocusRef
385
+ }),
386
+ activeOptionKey
387
+ };
388
+ };
389
+ exports.useComboboxMenuTrigger = useComboboxMenuTrigger;
@@ -27,6 +27,22 @@ export interface OptionButtonProps extends Omit<ButtonProps, 'menu' | 'anchorPos
27
27
  tooltip?: OptionButtonTooltipProps;
28
28
  classNames?: ClassNames;
29
29
  clickAwayRef?: React.RefObject<ClickAwayRefType | null>;
30
+ /**
31
+ * Opt in to the accessibility behavior. Forwarded to the `ButtonDropdown`
32
+ * this renders, which owns the trigger and the menu.
33
+ *
34
+ * Off by default, and off is this component exactly as it behaved before any
35
+ * of it existed.
36
+ */
37
+ enableA11y?: boolean;
38
+ /**
39
+ * Accessible name for the options button — the icon-only half of the split
40
+ * button, which has no text of its own. It also names the listbox that button
41
+ * opens, so without it the listbox ends up unnamed. Override it for another
42
+ * language, as `TabList` does with `overflowTabLabel`. A consumer's own
43
+ * `ariaLabel` still wins.
44
+ */
45
+ optionsLabel?: string;
30
46
  testId?: string;
31
47
  }
32
48
  export declare const OptionButton: Flow.AbstractComponent<OptionButtonProps, HTMLDivElement>;
@@ -1 +1 @@
1
- {"version":3,"file":"OptionButton.d.ts","sourceRoot":"","sources":["../../../src/components/OptionButton/OptionButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,4BAA4B,CAAC;AAGrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAC;AAG9D,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAM7D,KAAK,UAAU,GAAG,QAAQ,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC,CAAC;AAEH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC;AAED,MAAM,WAAW,iBACf,SAAQ,IAAI,CACV,WAAW,EACT,MAAM,GACN,gBAAgB,GAChB,gBAAgB,GAChB,eAAe,GACf,YAAY,GACZ,aAAa,GACb,SAAS,GACT,YAAY,GACZ,cAAc,CACjB;IACD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,UAAU,EAClB,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,KACxD,OAAO,CAAC;IACb,aAAa,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC3D,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,iBAAiB,CAC/C,iBAAiB,EACjB,cAAc,CA6Gf,CAAC"}
1
+ {"version":3,"file":"OptionButton.d.ts","sourceRoot":"","sources":["../../../src/components/OptionButton/OptionButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,4BAA4B,CAAC;AAGrD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,uBAAuB,CAAC;AAEvD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,+BAA+B,CAAC;AAG9D,OAAO,KAAK,EAAC,UAAU,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAM7D,KAAK,UAAU,GAAG,QAAQ,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC,CAAC;AAEH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAClC;AAED,MAAM,WAAW,iBACf,SAAQ,IAAI,CACV,WAAW,EACT,MAAM,GACN,gBAAgB,GAChB,gBAAgB,GAChB,eAAe,GACf,YAAY,GACZ,aAAa,GACb,SAAS,GACT,YAAY,GACZ,cAAc,CACjB;IACD,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,UAAU,EAClB,IAAI,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,GAAG,IAAI,GAAG,SAAS,KACxD,OAAO,CAAC;IACb,aAAa,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC3D,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,wBAAwB,CAAC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IACxD;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,YAAY,EAAE,IAAI,CAAC,iBAAiB,CAC/C,iBAAiB,EACjB,cAAc,CAgHf,CAAC"}
@@ -36,6 +36,8 @@ const OptionButton = exports.OptionButton = /*#__PURE__*/React.forwardRef((_ref,
36
36
  tooltip,
37
37
  classNames,
38
38
  clickAwayRef,
39
+ enableA11y = false,
40
+ optionsLabel = 'More options',
39
41
  testId
40
42
  } = _ref;
41
43
  const [iconName, setIconName] = React.useState('chevron-down');
@@ -83,7 +85,7 @@ const OptionButton = exports.OptionButton = /*#__PURE__*/React.forwardRef((_ref,
83
85
  })
84
86
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_ButtonDropdown.ButtonDropdown, {
85
87
  anchorPosition: anchorPosition,
86
- ariaLabel: ariaLabel,
88
+ ariaLabel: ariaLabel ?? (enableA11y ? optionsLabel : undefined),
87
89
  iconLeftName: iconName,
88
90
  tooltip: tooltip?.optionsButton,
89
91
  classNames: {
@@ -107,6 +109,7 @@ const OptionButton = exports.OptionButton = /*#__PURE__*/React.forwardRef((_ref,
107
109
  onOptionSelect: onOptionSelect,
108
110
  size: size,
109
111
  clickAwayRef: clickAwayRef,
112
+ enableA11y: enableA11y,
110
113
  testId: (0, _qa.generateTestId)({
111
114
  base: testId,
112
115
  slot: 'dropdown'