@pixum/combobox 5.10.9 → 7.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +741 -0
  2. package/lib/ComboBox.d.ts +4 -36
  3. package/lib/ComboBox.js +67 -240
  4. package/lib/ComboBox.js.map +1 -1
  5. package/lib/ComboboxOptions/Options.d.ts +1 -0
  6. package/lib/ComboboxOptions/Options.js +9 -12
  7. package/lib/ComboboxOptions/Options.js.map +1 -1
  8. package/lib/ComboboxOptions/OptionsGroup.d.ts +1 -0
  9. package/lib/ComboboxOptions/OptionsGroup.js +2 -2
  10. package/lib/ComboboxOptions/OptionsGroup.js.map +1 -1
  11. package/lib/ComboboxOptions/index.js +7 -4
  12. package/lib/ComboboxOptions/index.js.map +1 -1
  13. package/lib/helper/scrollOptionToViewport.js +3 -4
  14. package/lib/helper/scrollOptionToViewport.js.map +1 -1
  15. package/lib/helper/useIsDesktopScreenWidth.js.map +1 -1
  16. package/lib/index.d.ts +3 -4
  17. package/lib/index.js +3 -3
  18. package/lib/index.js.map +1 -1
  19. package/lib/styles.css +1 -1
  20. package/lib/types.d.ts +14 -196
  21. package/package.json +9 -8
  22. package/lib/ComboBox.module.css +0 -1
  23. package/lib/ComboBox.test.d.ts +0 -1
  24. package/lib/ComboBox.test.js +0 -32
  25. package/lib/ComboBox.test.js.map +0 -1
  26. package/lib/hooks/index.d.ts +0 -3
  27. package/lib/hooks/index.js +0 -4
  28. package/lib/hooks/index.js.map +0 -1
  29. package/lib/hooks/useComboBox.d.ts +0 -60
  30. package/lib/hooks/useComboBox.js +0 -226
  31. package/lib/hooks/useComboBox.js.map +0 -1
  32. package/lib/hooks/useComboBoxFocus.d.ts +0 -35
  33. package/lib/hooks/useComboBoxFocus.js +0 -49
  34. package/lib/hooks/useComboBoxFocus.js.map +0 -1
  35. package/lib/hooks/useIsDesktopScreenWidth.d.ts +0 -6
  36. package/lib/hooks/useIsDesktopScreenWidth.js +0 -46
  37. package/lib/hooks/useIsDesktopScreenWidth.js.map +0 -1
  38. package/lib/partials/ComboBoxNoResults.d.ts +0 -14
  39. package/lib/partials/ComboBoxNoResults.js +0 -18
  40. package/lib/partials/ComboBoxNoResults.js.map +0 -1
  41. package/lib/partials/ComboBoxOptions.d.ts +0 -21
  42. package/lib/partials/ComboBoxOptions.js +0 -33
  43. package/lib/partials/ComboBoxOptions.js.map +0 -1
  44. package/lib/partials/ComboBoxOptionsGroup.d.ts +0 -15
  45. package/lib/partials/ComboBoxOptionsGroup.js +0 -31
  46. package/lib/partials/ComboBoxOptionsGroup.js.map +0 -1
  47. package/lib/partials/ComboBoxOptionsItems.d.ts +0 -39
  48. package/lib/partials/ComboBoxOptionsItems.js +0 -56
  49. package/lib/partials/ComboBoxOptionsItems.js.map +0 -1
  50. package/lib/partials/ComboBoxOptionsSlot.d.ts +0 -35
  51. package/lib/partials/ComboBoxOptionsSlot.js +0 -47
  52. package/lib/partials/ComboBoxOptionsSlot.js.map +0 -1
  53. package/lib/partials/ComboBoxOptionsWithGrouping.d.ts +0 -26
  54. package/lib/partials/ComboBoxOptionsWithGrouping.js +0 -14
  55. package/lib/partials/ComboBoxOptionsWithGrouping.js.map +0 -1
  56. package/lib/partials/index.d.ts +0 -5
  57. package/lib/partials/index.js +0 -6
  58. package/lib/partials/index.js.map +0 -1
  59. package/lib/utils/calculateListMaxHeight.d.ts +0 -7
  60. package/lib/utils/calculateListMaxHeight.js +0 -14
  61. package/lib/utils/calculateListMaxHeight.js.map +0 -1
  62. package/lib/utils/index.d.ts +0 -1
  63. package/lib/utils/index.js +0 -2
  64. package/lib/utils/index.js.map +0 -1
  65. package/lib/utils/options.d.ts +0 -77
  66. package/lib/utils/options.js +0 -145
  67. package/lib/utils/options.js.map +0 -1
  68. package/lib/utils/scrollOptionToViewport.d.ts +0 -7
  69. package/lib/utils/scrollOptionToViewport.js +0 -26
  70. package/lib/utils/scrollOptionToViewport.js.map +0 -1
package/lib/types.d.ts CHANGED
@@ -1,216 +1,34 @@
1
- import type { LeadingType, MenuItemProps } from '@pixum/menu-item';
2
- import type { ThemeType } from '@pixum/theme-provider';
3
- import type { InputModesType } from '@pixum/web-input';
4
- /**
5
- * An option as handed in by the consumer.
6
- *
7
- * Everything a `MenuItem` understands is accepted and forwarded unchanged -
8
- * the ComboBox only adds `key` and `disabled` on top. That keeps existing
9
- * consumers working: they pass their MenuItem props as they always did, and
10
- * props the ComboBox does not know about still reach the `MenuItem`.
11
- */
12
- export interface ComboBoxOptionItemProps extends MenuItemProps {
13
- /** Unique key for the option item */
14
- key?: string;
15
- /**
16
- * Disabled options are rendered, but skipped by mouse and keyboard.
17
- *
18
- * Newly added. Consumer types that already carry a `disabled` field of a
19
- * different type (e.g. `disabled: 'true' | 'false'`) are no longer
20
- * assignable - widen it to `boolean` on the consumer side.
21
- */
22
- disabled?: boolean;
23
- }
24
- /** Options are accepted either as a flat list or grouped by a group headline. */
25
- export type ComboBoxOptionsInput = ComboBoxOptionItemProps[] | Record<string, ComboBoxOptionItemProps[]>;
26
- /**
27
- * An option after normalisation. Flat and grouped options are reduced to this
28
- * shape once, so keyboard navigation, rendering and ARIA ids all work on the
29
- * very same list in the very same order.
30
- */
31
- export interface ComboBoxOption {
32
- /** The original option as handed in by the consumer. */
33
- item: ComboBoxOptionItemProps;
34
- /**
35
- * Stable value of the option, reported by `onOptionItemClick` and compared
36
- * against `value`. Resolved by `resolveOptionValue`: the option's `text` when
37
- * it is a string, otherwise `key`, otherwise the render index.
38
- */
39
- value: string;
40
- /** Position in render order. Drives the DOM id and the keyboard navigation. */
41
- index: number;
42
- /** DOM id, referenced by `aria-activedescendant`. */
43
- id: string;
44
- /** Group headline the option belongs to, `undefined` for flat lists. */
45
- group?: string;
46
- /** Whether the option can be activated. */
47
- disabled: boolean;
48
- }
49
- /** Options of one render group, produced by `groupOptions`. */
50
- export interface ComboBoxOptionGroup {
51
- /** Group headline, `undefined` for flat lists. */
52
- group?: string;
53
- /** Options of this group, still carrying their global render index. */
54
- options: ComboBoxOption[];
55
- }
56
- /** ARIA props for the element that owns the `combobox` role. */
57
- export interface ComboBoxAriaProps {
58
- role: 'combobox';
59
- 'aria-expanded': boolean;
60
- 'aria-haspopup': 'listbox';
61
- 'aria-controls': string | undefined;
62
- 'aria-activedescendant': string | undefined;
63
- 'aria-autocomplete': 'list' | 'none';
64
- }
65
- /** ARIA props for the element that owns the `listbox` role. */
66
- export interface ListboxAriaProps {
67
- role: 'listbox';
68
- id: string;
69
- /** Only set for multi select; single select listboxes omit it. */
70
- 'aria-multiselectable'?: boolean;
71
- }
72
- /**
73
- * Public options contract, kept for backwards compatibility.
74
- *
75
- * In the previous version this interface was the base of `ComboBoxProps` and
76
- * the prop type of
77
- * the exported options component. It describes the options as the *consumer*
78
- * hands them in - not the normalised list the internal panel renders. The
79
- * internal shape now lives in `ComboBoxOptionsPanelProps`.
80
- *
81
- * @deprecated Use `ComboBoxProps` (or `Pick<ComboBoxProps, 'options'>`)
82
- * directly. Kept so existing imports do not silently change meaning; will be
83
- * removed in the next major.
84
- */
85
- export interface ComboBoxOptionsProps {
86
- /** Options to display, either flat or grouped. */
87
- options: ComboBoxOptionsInput;
88
- /**
89
- * Currently selected option value.
90
- *
91
- * @deprecated Use `value`. When both are set, `value` wins.
92
- */
1
+ /// <reference types="react" />
2
+ import { LeadingType, MenuItemProps } from '@pixum/menu-item';
3
+ import { InputMode } from '@pixum/user-input';
4
+ interface ComboBoxOptionsProps {
5
+ options: Record<string, ComboBoxOptionProps[]> | ComboBoxOptionProps[];
93
6
  selectedOption?: string;
94
- /**
95
- * Callback fired when an option is clicked.
96
- *
97
- * @deprecated Use `onOptionItemClick`. On `ComboBoxProps` this prop is
98
- * narrowed to the trigger click handler `() => void`.
99
- */
100
7
  onClick?: (value: string) => void;
101
- /** Type of leading element to display (icon, avatar, checkbox …). */
102
- leadingType?: LeadingType;
103
- /** Additional details rendered below the options. */
104
- optionDetails?: React.ReactNode;
105
- }
106
- /**
107
- * Props of the rendered options panel - the internal, normalised shape.
108
- *
109
- * This is what `ComboBoxOptions` consumes. It is exported so custom panels can
110
- * be typed against it, but it is not part of the consumer-facing API and may
111
- * change without a major bump.
112
- */
113
- export interface ComboBoxOptionsPanelProps {
114
- /** Normalised options in render order. */
115
- options: ComboBoxOption[];
116
- /** ARIA props of the listbox element. */
117
- listboxAriaProps: ListboxAriaProps;
118
- /** Values that are currently selected. */
119
- selectedValues: string[];
120
- /** DOM id of the active option (`aria-activedescendant`). */
121
- activeOptionId?: string;
122
- /** Type of the leading element, e.g. a checkbox for multi select. */
123
8
  leadingType?: LeadingType;
124
- /** Additional details rendered as a sticky footer below the options. */
125
9
  optionDetails?: React.ReactNode;
126
- /** Called with the value of the clicked option. */
127
- onOptionClick: (value: string) => void;
128
10
  }
129
- /**
130
- * Props of the ComboBox component.
131
- *
132
- * Extends the deprecated `ComboBoxOptionsProps` so that consumers who built
133
- * their own prop types on top of it keep compiling.
134
- */
135
- export interface ComboBoxProps extends ComboBoxOptionsProps {
136
- /** Additional CSS class name for the trigger field. */
11
+ interface ComboBoxProps extends ComboBoxOptionsProps {
137
12
  className?: string;
138
- /** Name attribute for the input field. */
139
- name?: string;
140
- /**
141
- * ID attribute for the input field.
142
- *
143
- * @deprecated The trigger generates its own ids for the ARIA wiring; `id` is
144
- * forwarded to the underlying input untouched and no longer used internally.
145
- */
146
- id?: string;
147
- /** Headline text displayed in the mobile bottom sheet. */
148
13
  headline?: string;
149
- /** Helper text displayed below the input field. */
150
14
  helperText?: string;
151
- /** Label text for the input field. */
15
+ id?: string;
152
16
  label?: string;
153
- /** Options to display, either flat or grouped. */
154
- options: ComboBoxOptionsInput;
155
- /** Whether the popover / bottom sheet is currently open. */
156
17
  isOpen: boolean;
157
- /** State setter that controls the open state. */
158
18
  setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
159
- /**
160
- * Selected value: a string for single select, an array of strings when
161
- * `multiple` is set.
162
- *
163
- * The array member is new in this version. Code that *reads* this prop back
164
- * out of
165
- * a props object has to narrow it (`Array.isArray(value)`).
166
- */
167
- value?: string | string[];
168
- /** Allows selecting several options; combine with a checkbox `leadingType`. */
169
- multiple?: boolean;
170
- /** Called with the value of the selected (in multi select: toggled) option. */
171
- onOptionItemClick?: (value: string) => void;
172
- /** Called when the search input value changes. */
173
19
  onChange?: (value: string) => void;
174
- /** Called when the user clicks outside of the component. */
20
+ onOptionItemClick?: (value: string) => void;
175
21
  onOutsideClick?: () => void;
176
- /** Called when the trigger field is clicked. */
177
22
  onClick?: () => void;
178
- /** Called when the bottom sheet has been closed. */
179
23
  onSheetClose?: () => void;
180
- /** Placeholder text for the input field. */
181
24
  placeholder?: string;
182
- /** Search pattern for input validation. */
183
25
  searchPattern?: string;
184
- /** Text to display when there is no option to show. */
26
+ value?: string;
185
27
  noResultsText?: string;
186
- /** Input mode for mobile keyboards. */
187
- inputMode?: InputModesType;
188
- /** Renders a search input inside the popover / bottom sheet. */
28
+ inputMode?: InputMode;
189
29
  withSearch?: boolean;
190
- /** Enter opens the closed list. Disable it inside forms with implicit submit. */
191
- openOnEnter?: boolean;
192
- /** Whether the combobox is disabled. */
193
- disabled?: boolean;
194
- /** Disabled style plus shimmer animation while content is loading. */
195
- loading?: boolean;
196
- /** Type of the leading element of an option (icon, avatar, checkbox …). */
197
- leadingType?: LeadingType;
198
- /** Additional details rendered below the options. */
199
- optionDetails?: React.ReactNode;
200
- /** Theme configuration for the component. */
201
- theme?: ThemeType;
202
- /** Custom slot that replaces the standard options / no-results block. */
203
- optionsSlot?: React.ReactNode;
204
- /**
205
- * Icon element displayed at the leading side of the trigger input.
206
- *
207
- * Deliberately `ReactNode`, not `ReactElement`: fragments, strings and
208
- * conditional `false` have always been accepted here.
209
- */
210
- leadingIcon?: React.ReactNode;
211
- /**
212
- * Formats the selected values for the trigger field.
213
- * Defaults to the labels of the selected options joined by a comma.
214
- */
215
- renderValue?: (labels: string[]) => string;
216
30
  }
31
+ interface ComboBoxOptionProps extends MenuItemProps {
32
+ key?: string;
33
+ }
34
+ export { ComboBoxProps, ComboBoxOptionProps, ComboBoxOptionsProps };
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@pixum/combobox",
3
- "version": "5.10.9",
3
+ "version": "7.0.0-alpha.0",
4
4
  "main": "lib/index.js",
5
5
  "module": "lib/index.js",
6
6
  "license": "UNLICENSED",
7
7
  "peerDependencies": {
8
- "@pixum/bottom-sheet": "4.9.0",
9
- "@pixum/menu": "4.4.2",
10
- "@pixum/menu-item": "3.4.3",
11
- "@pixum/text": "3.7.0",
12
- "@pixum/theme-provider": "^6.0.0",
13
- "@pixum/web-input": "2.5.6"
8
+ "@pixum/bottom-sheet": "^1.4.0",
9
+ "@pixum/button": "^1.15.0",
10
+ "@pixum/menu": "^2.1.0",
11
+ "@pixum/menu-item": "^0.11.0",
12
+ "@pixum/svg-icon": "^1.23.0",
13
+ "@pixum/text": "^1.2.2",
14
+ "@pixum/user-input": "^0.12.2"
14
15
  },
15
16
  "files": [
16
17
  "lib"
@@ -18,5 +19,5 @@
18
19
  "sideEffects": [
19
20
  "*.css"
20
21
  ],
21
- "gitHead": "2d1168fb9cce7bcc670b48681705144522dabcfe"
22
+ "gitHead": "b0af49dd6fe46f93f5c4bf7c7d3fc86bd32408eb"
22
23
  }
@@ -1 +0,0 @@
1
- .comboBox{position:relative;width:100%}.comboBox .headline[class*=text--]+*{margin-top:var(--spacing)}:is(.comboBox,.sheet) :is(.panel,.optionsSlot,.header){position:relative;width:100%}:is(.comboBox,.sheet) .panel{display:flex;flex-direction:column;max-height:inherit;overflow:hidden}:is(.sheet) .panel{box-shadow:none}:is(.comboBox,.sheet) :is(.options,.optionsSlot){display:flex;flex:1 1 auto;flex-direction:column;min-height:0;overflow:auto;scroll-padding-block-start:var(--combobox-sticky-offset,2.75rem)}.sheet .header{align-items:flex-start;height:auto;margin:var(--spacing-5) auto var(--spacing-2);padding:0 var(--spacing-2)}:is(.comboBox,.sheet) ul.optionsSlot{list-style:none;padding:0}:is(.comboBox,.sheet) .option{cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none}:is(.comboBox,.sheet) .optionCheckbox[data-selected=true] :global(.menu-item){background-color:initial}:is(.comboBox,.sheet) .option.optionActive :global(.menu-item),:is(.comboBox,.sheet) .optionCheckbox.optionActive :global(.menu-item){background-color:var(--color-canvas--hover)}:is(.comboBox,.sheet) .option[data-selected=true]:not(.optionCheckbox) :global(.menu-item){background-color:var(--color-accent);color:var(--color-surface)}:is(.comboBox,.sheet) .option[aria-disabled=true]{cursor:not-allowed;opacity:.5}@media (forced-colors:active){:is(.comboBox,.sheet) .option.optionActive :global(.menu-item){outline:2px solid Highlight;outline-offset:-2px}}:is(.comboBox,.sheet) .stickyHeader{background-color:var(--color-surface);border-bottom:1px solid var(--color-dim);padding:var(--spacing-1_25) var(--spacing-2);position:-webkit-sticky;position:sticky;top:0}:is(.comboBox,.sheet) .options :global(.text--caption){color:var(--color-on-secondary)}:is(.comboBox,.sheet) .option[data-selected=true]:not(.optionCheckbox) :global(.menu-item .text--caption){color:var(--color-surface)}:is(.comboBox,.sheet) .options :global(.item-header){display:flex;justify-content:space-between}:is(.comboBox,.sheet) .optionDetails{background-color:var(--color-surface);border-top:1px solid var(--color-dim);flex:0 0 auto;padding:var(--spacing-1_25) var(--spacing)}:is(.comboBox,.sheet) .noResults{padding:var(--spacing-2) var(--spacing);text-align:center}@media screen and (min-width:960px){.comboBox :is(.panel,.optionsSlot){border-radius:var(--border-radius-3);margin-top:var(--spacing);max-height:330px;position:absolute}}
@@ -1 +0,0 @@
1
- export {};
@@ -1,32 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { fireEvent, render } from '@testing-library/react';
3
- import { ComboBox } from './ComboBox';
4
- // jsdom sets window.innerWidth to 0, so useIsDesktopScreenWidth returns false.
5
- // When !isDesktop, showSelectField is always true — SelectInput always renders.
6
- const baseProps = {
7
- isOpen: false,
8
- setIsOpen: jest.fn(),
9
- options: [],
10
- label: 'Test',
11
- };
12
- describe('ComboBox disabled', () => {
13
- it('does not fire onClick when disabled', () => {
14
- const onClick = jest.fn();
15
- const { container } = render(_jsx(ComboBox, Object.assign({}, baseProps, { disabled: true, onClick: onClick })));
16
- fireEvent.click(container.querySelector('.input-inner-container'));
17
- expect(onClick).not.toHaveBeenCalled();
18
- });
19
- it('passes disabled to the trigger input', () => {
20
- const { container } = render(_jsx(ComboBox, Object.assign({}, baseProps, { disabled: true, value: "some option" })));
21
- expect(container.querySelector('input')).toBeDisabled();
22
- });
23
- });
24
- describe('ComboBox enabled', () => {
25
- it('fires onClick when not disabled', () => {
26
- const onClick = jest.fn();
27
- const { container } = render(_jsx(ComboBox, Object.assign({}, baseProps, { onClick: onClick })));
28
- fireEvent.click(container.querySelector('.input-inner-container'));
29
- expect(onClick).toHaveBeenCalledTimes(1);
30
- });
31
- });
32
- //# sourceMappingURL=ComboBox.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ComboBox.test.js","sourceRoot":"","sources":["../src/ComboBox.test.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAGrC,+EAA+E;AAC/E,gFAAgF;AAEhF,MAAM,SAAS,GAAG;IAChB,MAAM,EAAE,KAAK;IACb,SAAS,EAAE,IAAI,CAAC,EAAE,EAAE;IACpB,OAAO,EAAE,EAA+B;IACxC,KAAK,EAAE,MAAM;CACd,CAAA;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,CAAA;QACzB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAC1B,KAAC,QAAQ,oBAAK,SAAS,IAAE,QAAQ,QAAC,OAAO,EAAE,OAAO,IAAI,CACvD,CAAA;QACD,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,wBAAwB,CAAE,CAAC,CAAA;QACnE,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;IACxC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAC1B,KAAC,QAAQ,oBAAK,SAAS,IAAE,QAAQ,QAAC,KAAK,EAAC,aAAa,IAAG,CACzD,CAAA;QACD,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,CAAA;IACzD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,CAAA;QACzB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAC1B,KAAC,QAAQ,oBAAK,SAAS,IAAE,OAAO,EAAE,OAAO,IAAI,CAC9C,CAAA;QACD,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,aAAa,CAAC,wBAAwB,CAAE,CAAC,CAAA;QACnE,MAAM,CAAC,OAAO,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;IAC1C,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1,3 +0,0 @@
1
- export * from './useIsDesktopScreenWidth';
2
- export * from './useComboBox';
3
- export * from './useComboBoxFocus';
@@ -1,4 +0,0 @@
1
- export * from './useIsDesktopScreenWidth';
2
- export * from './useComboBox';
3
- export * from './useComboBoxFocus';
4
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,eAAe,CAAA;AAC7B,cAAc,oBAAoB,CAAA"}
@@ -1,60 +0,0 @@
1
- import type { ComboBoxAriaProps, ComboBoxOption, ListboxAriaProps } from '../types';
2
- export interface UseComboBoxOptions {
3
- /** Normalised options in render order. */
4
- options: ComboBoxOption[];
5
- /** Whether the list is currently open. */
6
- isOpen: boolean;
7
- /** Opens the list. */
8
- open: () => void;
9
- /**
10
- * Closes the list. `restoreFocus` is `false` when the focus must stay where
11
- * the user put it (Tab).
12
- */
13
- close: (restoreFocus?: boolean) => void;
14
- /** Values that are currently selected. */
15
- selectedValues: string[];
16
- /** Called with the value of the option that was activated by the keyboard. */
17
- onSelect: (value: string) => void;
18
- /** Id of the listbox element. */
19
- listboxId: string;
20
- /** Whether the open list offers a freely typeable search field. */
21
- searchable?: boolean;
22
- /** Multi select keeps the list open after a selection. */
23
- multiple?: boolean;
24
- /** Enter opens the closed list (APG select-only). */
25
- openOnEnter?: boolean;
26
- }
27
- export interface UseComboBoxResult {
28
- /** ARIA props for the element that owns the `combobox` role. */
29
- comboboxAriaProps: ComboBoxAriaProps;
30
- /** ARIA props for the element that owns the `listbox` role. */
31
- listboxAriaProps: ListboxAriaProps;
32
- /** Keyboard handler for the combobox element. */
33
- onKeyDown: React.KeyboardEventHandler<HTMLInputElement>;
34
- /** DOM id of the active option, `undefined` while closed. */
35
- activeOptionId: string | undefined;
36
- /** Index of the active option, `null` while closed or empty. */
37
- activeIndex: number | null;
38
- }
39
- /**
40
- * Headless controller for the WAI-ARIA combobox pattern.
41
- *
42
- * The focus never moves into the list: the active option is communicated
43
- * exclusively via `aria-activedescendant`, which keeps the search field
44
- * typeable while the user navigates.
45
- *
46
- * Keyboard (APG combobox with listbox popup):
47
- * - closed: ArrowUp/ArrowDown/Alt+ArrowDown, Enter, Space open the list
48
- * - open: ArrowUp/ArrowDown navigate (skipping disabled options),
49
- * Home/End jump to the first/last option, Enter selects,
50
- * Escape and Alt+ArrowUp close, Tab closes and lets the focus move on
51
- * - Space selects while the field is not typeable; as soon as a search field
52
- * is open it types a space character instead, as APG requires
53
- *
54
- * On open the starting point is always the selected option, so ArrowDown moves
55
- * to the option right after it.
56
- *
57
- * @param options - Configuration of the combobox
58
- * @returns ARIA props, the keyboard handler and the active option
59
- */
60
- export declare function useComboBox({ options, isOpen, open, close, selectedValues, onSelect, listboxId, searchable, multiple, openOnEnter, }: UseComboBoxOptions): UseComboBoxResult;
@@ -1,226 +0,0 @@
1
- 'use client';
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { findEnabledIndex } from '../utils';
4
- /**
5
- * Headless controller for the WAI-ARIA combobox pattern.
6
- *
7
- * The focus never moves into the list: the active option is communicated
8
- * exclusively via `aria-activedescendant`, which keeps the search field
9
- * typeable while the user navigates.
10
- *
11
- * Keyboard (APG combobox with listbox popup):
12
- * - closed: ArrowUp/ArrowDown/Alt+ArrowDown, Enter, Space open the list
13
- * - open: ArrowUp/ArrowDown navigate (skipping disabled options),
14
- * Home/End jump to the first/last option, Enter selects,
15
- * Escape and Alt+ArrowUp close, Tab closes and lets the focus move on
16
- * - Space selects while the field is not typeable; as soon as a search field
17
- * is open it types a space character instead, as APG requires
18
- *
19
- * On open the starting point is always the selected option, so ArrowDown moves
20
- * to the option right after it.
21
- *
22
- * @param options - Configuration of the combobox
23
- * @returns ARIA props, the keyboard handler and the active option
24
- */
25
- export function useComboBox({ options, isOpen, open, close, selectedValues, onSelect, listboxId, searchable = true, multiple = false, openOnEnter = true, }) {
26
- var _a;
27
- const [activeIndex, setActiveIndex] = useState(null);
28
- /**
29
- * Read inside effects only. Keeping the selection in a ref avoids re-running
30
- * the "open" effect when a consumer passes a new array instance per render.
31
- */
32
- const selectedValuesRef = useRef(selectedValues);
33
- selectedValuesRef.current = selectedValues;
34
- /** Tracks the closed -> open edge so navigation is not reset while open. */
35
- const wasOpen = useRef(false);
36
- /**
37
- * Active option requested while the list was still closed (Home/End). The
38
- * open effect consumes it instead of falling back to the selected option.
39
- */
40
- const pendingActiveIndex = useRef(null);
41
- /** Typing is only possible while an open search field is rendered. */
42
- const canType = isOpen && searchable;
43
- /**
44
- * Sets the starting point when the list opens: the selected option, or the
45
- * first enabled one as a fallback.
46
- */
47
- useEffect(() => {
48
- if (!isOpen) {
49
- wasOpen.current = false;
50
- setActiveIndex(null);
51
- return;
52
- }
53
- if (wasOpen.current)
54
- return;
55
- wasOpen.current = true;
56
- const pending = pendingActiveIndex.current;
57
- pendingActiveIndex.current = null;
58
- if (pending !== null) {
59
- setActiveIndex(pending);
60
- return;
61
- }
62
- const selectedIndex = options.findIndex(option => !option.disabled && selectedValuesRef.current.includes(option.value));
63
- setActiveIndex(selectedIndex !== -1 ? selectedIndex : findEnabledIndex(options, -1, 1));
64
- }, [isOpen, options]);
65
- /**
66
- * Keeps the active index valid while the list is filtered down.
67
- */
68
- useEffect(() => {
69
- if (!isOpen)
70
- return;
71
- setActiveIndex(previous => {
72
- const isStillValid = previous !== null &&
73
- previous < options.length &&
74
- !options[previous].disabled;
75
- if (isStillValid)
76
- return previous;
77
- return findEnabledIndex(options, -1, 1);
78
- });
79
- }, [isOpen, options]);
80
- /**
81
- * Moves the active option by `delta` positions, wrapping around and skipping
82
- * disabled options.
83
- *
84
- * @param delta - Number of positions to move; negative moves backwards
85
- */
86
- const move = useCallback((delta) => setActiveIndex(previous => findEnabledIndex(options, previous !== null && previous !== void 0 ? previous : (delta > 0 ? -1 : 0), delta)), [options]);
87
- /**
88
- * Selects the active option. In single select the list closes afterwards,
89
- * in multi select it stays open so further options can be toggled.
90
- */
91
- const selectActiveOption = useCallback(() => {
92
- if (activeIndex === null)
93
- return;
94
- const option = options[activeIndex];
95
- if (!option || option.disabled)
96
- return;
97
- onSelect(option.value);
98
- }, [activeIndex, options, onSelect]);
99
- const onKeyDown = useCallback(event => {
100
- switch (event.key) {
101
- case 'ArrowDown':
102
- case 'ArrowUp': {
103
- event.preventDefault();
104
- if (!isOpen) {
105
- open();
106
- break;
107
- }
108
- // Alt+ArrowUp closes and keeps the current selection.
109
- if (event.key === 'ArrowUp' && event.altKey) {
110
- close();
111
- break;
112
- }
113
- // Alt+ArrowDown only opens, it never moves the active option.
114
- if (event.altKey)
115
- break;
116
- move(event.key === 'ArrowDown' ? 1 : -1);
117
- break;
118
- }
119
- case 'Enter': {
120
- if (!isOpen) {
121
- if (!openOnEnter)
122
- break;
123
- // preventDefault stops an implicit form submit.
124
- event.preventDefault();
125
- open();
126
- break;
127
- }
128
- if (activeIndex === null)
129
- break;
130
- event.preventDefault();
131
- selectActiveOption();
132
- break;
133
- }
134
- case ' ': {
135
- // An open search field must receive a real space character.
136
- if (canType)
137
- break;
138
- event.preventDefault();
139
- if (isOpen && activeIndex !== null) {
140
- selectActiveOption();
141
- break;
142
- }
143
- open();
144
- break;
145
- }
146
- case 'Escape': {
147
- if (!isOpen)
148
- break;
149
- event.preventDefault();
150
- close();
151
- break;
152
- }
153
- case 'Tab': {
154
- // No preventDefault: the focus moves on, the popup just closes.
155
- if (isOpen)
156
- close(false);
157
- break;
158
- }
159
- case 'Home':
160
- case 'End': {
161
- if (options.length === 0)
162
- break;
163
- event.preventDefault();
164
- const targetIndex = event.key === 'Home'
165
- ? findEnabledIndex(options, -1, 1)
166
- : findEnabledIndex(options, options.length, -1);
167
- // Closed: open first, the effect picks the index up from the ref.
168
- if (!isOpen) {
169
- pendingActiveIndex.current = targetIndex;
170
- open();
171
- break;
172
- }
173
- setActiveIndex(targetIndex);
174
- break;
175
- }
176
- default:
177
- break;
178
- }
179
- }, [
180
- isOpen,
181
- open,
182
- close,
183
- move,
184
- activeIndex,
185
- selectActiveOption,
186
- canType,
187
- openOnEnter,
188
- options,
189
- ]);
190
- const activeOptionId = isOpen && activeIndex !== null ? (_a = options[activeIndex]) === null || _a === void 0 ? void 0 : _a.id : undefined;
191
- /**
192
- * Scrolls the active option into view. Purely DOM based, so it works for the
193
- * desktop popover and the bottom sheet alike.
194
- */
195
- useEffect(() => {
196
- if (!activeOptionId)
197
- return;
198
- const frameId = requestAnimationFrame(() => {
199
- var _a;
200
- (_a = document
201
- .getElementById(activeOptionId)) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'nearest' });
202
- });
203
- return () => cancelAnimationFrame(frameId);
204
- }, [activeOptionId]);
205
- const comboboxAriaProps = useMemo(() => ({
206
- role: 'combobox',
207
- 'aria-expanded': isOpen,
208
- 'aria-haspopup': 'listbox',
209
- 'aria-controls': isOpen ? listboxId : undefined,
210
- 'aria-activedescendant': activeOptionId,
211
- 'aria-autocomplete': searchable ? 'list' : 'none',
212
- }), [isOpen, listboxId, activeOptionId, searchable]);
213
- const listboxAriaProps = useMemo(() => ({
214
- role: 'listbox',
215
- id: listboxId,
216
- 'aria-multiselectable': multiple || undefined,
217
- }), [listboxId, multiple]);
218
- return {
219
- comboboxAriaProps,
220
- listboxAriaProps,
221
- onKeyDown,
222
- activeOptionId,
223
- activeIndex,
224
- };
225
- }
226
- //# sourceMappingURL=useComboBox.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useComboBox.js","sourceRoot":"","sources":["../../src/hooks/useComboBox.ts"],"names":[],"mappings":"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"}
@@ -1,35 +0,0 @@
1
- export interface UseComboBoxFocusResult {
2
- /**
3
- * Ref for the trigger field (SelectInput).
4
- *
5
- * `| null` is part of the type parameter: since React 19 `useRef<T>(null)`
6
- * returns `RefObject<T | null>` instead of the old `RefObject<T>`.
7
- */
8
- triggerRef: React.RefObject<HTMLInputElement | null>;
9
- /**
10
- * Callback ref for the search field. Focuses it the moment it is mounted -
11
- * in the desktop popover as well as in the bottom sheet.
12
- */
13
- searchInputRef: (input: HTMLInputElement | null) => void;
14
- /** Moves the focus back to the trigger without re-opening the list. */
15
- returnFocusToTrigger: () => void;
16
- /**
17
- * Whether the current focus event on the trigger was caused by
18
- * `returnFocusToTrigger` and must therefore not open the list.
19
- */
20
- isReturningFocus: () => boolean;
21
- }
22
- /**
23
- * Bundles the focus choreography of the ComboBox:
24
- *
25
- * - opening moves the focus into the search field as soon as it mounts,
26
- * - closing moves it back to the trigger,
27
- * - the focus handler of the trigger can tell a returning focus from a real
28
- * user focus and therefore does not re-open the list it just closed.
29
- *
30
- * The search field is wired up with a callback ref, so both the popover and the
31
- * bottom sheet share one implementation and no polling is needed.
32
- *
33
- * @returns Refs and helpers for the focus handling
34
- */
35
- export declare function useComboBoxFocus(): UseComboBoxFocusResult;