@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.
- package/CHANGELOG.md +741 -0
- package/lib/ComboBox.d.ts +4 -36
- package/lib/ComboBox.js +67 -240
- package/lib/ComboBox.js.map +1 -1
- package/lib/ComboboxOptions/Options.d.ts +1 -0
- package/lib/ComboboxOptions/Options.js +9 -12
- package/lib/ComboboxOptions/Options.js.map +1 -1
- package/lib/ComboboxOptions/OptionsGroup.d.ts +1 -0
- package/lib/ComboboxOptions/OptionsGroup.js +2 -2
- package/lib/ComboboxOptions/OptionsGroup.js.map +1 -1
- package/lib/ComboboxOptions/index.js +7 -4
- package/lib/ComboboxOptions/index.js.map +1 -1
- package/lib/helper/scrollOptionToViewport.js +3 -4
- package/lib/helper/scrollOptionToViewport.js.map +1 -1
- package/lib/helper/useIsDesktopScreenWidth.js.map +1 -1
- package/lib/index.d.ts +3 -4
- package/lib/index.js +3 -3
- package/lib/index.js.map +1 -1
- package/lib/styles.css +1 -1
- package/lib/types.d.ts +14 -196
- package/package.json +9 -8
- package/lib/ComboBox.module.css +0 -1
- package/lib/ComboBox.test.d.ts +0 -1
- package/lib/ComboBox.test.js +0 -32
- package/lib/ComboBox.test.js.map +0 -1
- package/lib/hooks/index.d.ts +0 -3
- package/lib/hooks/index.js +0 -4
- package/lib/hooks/index.js.map +0 -1
- package/lib/hooks/useComboBox.d.ts +0 -60
- package/lib/hooks/useComboBox.js +0 -226
- package/lib/hooks/useComboBox.js.map +0 -1
- package/lib/hooks/useComboBoxFocus.d.ts +0 -35
- package/lib/hooks/useComboBoxFocus.js +0 -49
- package/lib/hooks/useComboBoxFocus.js.map +0 -1
- package/lib/hooks/useIsDesktopScreenWidth.d.ts +0 -6
- package/lib/hooks/useIsDesktopScreenWidth.js +0 -46
- package/lib/hooks/useIsDesktopScreenWidth.js.map +0 -1
- package/lib/partials/ComboBoxNoResults.d.ts +0 -14
- package/lib/partials/ComboBoxNoResults.js +0 -18
- package/lib/partials/ComboBoxNoResults.js.map +0 -1
- package/lib/partials/ComboBoxOptions.d.ts +0 -21
- package/lib/partials/ComboBoxOptions.js +0 -33
- package/lib/partials/ComboBoxOptions.js.map +0 -1
- package/lib/partials/ComboBoxOptionsGroup.d.ts +0 -15
- package/lib/partials/ComboBoxOptionsGroup.js +0 -31
- package/lib/partials/ComboBoxOptionsGroup.js.map +0 -1
- package/lib/partials/ComboBoxOptionsItems.d.ts +0 -39
- package/lib/partials/ComboBoxOptionsItems.js +0 -56
- package/lib/partials/ComboBoxOptionsItems.js.map +0 -1
- package/lib/partials/ComboBoxOptionsSlot.d.ts +0 -35
- package/lib/partials/ComboBoxOptionsSlot.js +0 -47
- package/lib/partials/ComboBoxOptionsSlot.js.map +0 -1
- package/lib/partials/ComboBoxOptionsWithGrouping.d.ts +0 -26
- package/lib/partials/ComboBoxOptionsWithGrouping.js +0 -14
- package/lib/partials/ComboBoxOptionsWithGrouping.js.map +0 -1
- package/lib/partials/index.d.ts +0 -5
- package/lib/partials/index.js +0 -6
- package/lib/partials/index.js.map +0 -1
- package/lib/utils/calculateListMaxHeight.d.ts +0 -7
- package/lib/utils/calculateListMaxHeight.js +0 -14
- package/lib/utils/calculateListMaxHeight.js.map +0 -1
- package/lib/utils/index.d.ts +0 -1
- package/lib/utils/index.js +0 -2
- package/lib/utils/index.js.map +0 -1
- package/lib/utils/options.d.ts +0 -77
- package/lib/utils/options.js +0 -145
- package/lib/utils/options.js.map +0 -1
- package/lib/utils/scrollOptionToViewport.d.ts +0 -7
- package/lib/utils/scrollOptionToViewport.js +0 -26
- package/lib/utils/scrollOptionToViewport.js.map +0 -1
package/lib/types.d.ts
CHANGED
|
@@ -1,216 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
26
|
+
value?: string;
|
|
185
27
|
noResultsText?: string;
|
|
186
|
-
|
|
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": "
|
|
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
|
-
"@pixum/
|
|
10
|
-
"@pixum/menu
|
|
11
|
-
"@pixum/
|
|
12
|
-
"@pixum/
|
|
13
|
-
"@pixum/
|
|
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": "
|
|
22
|
+
"gitHead": "b0af49dd6fe46f93f5c4bf7c7d3fc86bd32408eb"
|
|
22
23
|
}
|
package/lib/ComboBox.module.css
DELETED
|
@@ -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}}
|
package/lib/ComboBox.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/lib/ComboBox.test.js
DELETED
|
@@ -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
|
package/lib/ComboBox.test.js.map
DELETED
|
@@ -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"}
|
package/lib/hooks/index.d.ts
DELETED
package/lib/hooks/index.js
DELETED
package/lib/hooks/index.js.map
DELETED
|
@@ -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;
|
package/lib/hooks/useComboBox.js
DELETED
|
@@ -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;
|