@sproutsocial/seeds-react-menu 1.16.16 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +14 -14
- package/CHANGELOG.md +21 -0
- package/dist/esm/v3/index.js +90 -56
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +18 -0
- package/dist/v3/index.d.ts +18 -0
- package/dist/v3/index.js +90 -56
- package/dist/v3/index.js.map +1 -1
- package/package.json +1 -1
- package/src/ActionMenu/ActionMenu.stories.tsx +1 -1
- package/src/Autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/MenuContent/MenuContent.stories.tsx +1 -1
- package/src/MenuFooter/MenuFooter.stories.tsx +1 -1
- package/src/MenuGroup/MenuGroup.stories.tsx +1 -1
- package/src/MenuHeader/MenuHeader.stories.tsx +1 -1
- package/src/MenuItem/MenuItem.stories.tsx +1 -1
- package/src/MenuToggleButton/MenuToggleButton.stories.tsx +1 -1
- package/src/MultiSelectMenu/MultiSelectMenu.stories.tsx +1 -1
- package/src/NestedMenu/NestedMenu.stories.tsx +1 -1
- package/src/SingleSelectMenu/SingleSelectMenu.stories.tsx +1 -1
- package/src/SubmenuItem/SubmenuItem.stories.tsx +1 -1
- package/src/v2/Autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/v2/Select/Select.stories.tsx +1 -1
- package/src/v3/ActionMenu.stories.tsx +1 -1
- package/src/v3/MenuButton.stories.tsx +1 -1
- package/src/v3/ModalStories.stories.tsx +1 -1
- package/src/v3/MultiCombobox.stories.tsx +1 -1
- package/src/v3/MultiCombobox.tsx +7 -0
- package/src/v3/MultiSearchableSelect.stories.tsx +1 -1
- package/src/v3/MultiSearchableSelect.tsx +7 -0
- package/src/v3/MultiSelect.stories.tsx +1 -1
- package/src/v3/MultiSelect.tsx +9 -1
- package/src/v3/SingleCombobox.stories.tsx +1 -1
- package/src/v3/SingleCombobox.tsx +7 -0
- package/src/v3/SingleSearchableSelect.stories.tsx +1 -1
- package/src/v3/SingleSearchableSelect.tsx +7 -0
- package/src/v3/SingleSelect.stories.tsx +1 -1
- package/src/v3/SingleSelect.tsx +9 -1
- package/src/v3/__tests__/ariaLabels.test.tsx +133 -0
package/package.json
CHANGED
|
@@ -42,7 +42,7 @@ type ActionMenuStoryArgs = TypeActionMenuProps & {
|
|
|
42
42
|
type Story = StoryObj<ActionMenuStoryArgs>;
|
|
43
43
|
|
|
44
44
|
const meta: Meta<ActionMenuStoryArgs> = {
|
|
45
|
-
title: "
|
|
45
|
+
title: "Components/Menus/v1/ActionMenu",
|
|
46
46
|
component: ActionMenu,
|
|
47
47
|
argTypes: {
|
|
48
48
|
"Trigger Appearance": {
|
|
@@ -25,7 +25,7 @@ import Button from "@sproutsocial/seeds-react-button";
|
|
|
25
25
|
type CustomAutocompleteArgs = React.ComponentProps<typeof Autocomplete>;
|
|
26
26
|
|
|
27
27
|
const meta: Meta<CustomAutocompleteArgs> = {
|
|
28
|
-
title: "
|
|
28
|
+
title: "Components/Menus/v1/Autocomplete",
|
|
29
29
|
component: Autocomplete,
|
|
30
30
|
parameters: {
|
|
31
31
|
controls: {
|
|
@@ -31,7 +31,7 @@ type Story = StoryObj<MenuFooterStoryArgs>;
|
|
|
31
31
|
const optionsArr = ["Button Example", "Link Example", "Text Example", "none"];
|
|
32
32
|
|
|
33
33
|
const meta: Meta<MenuFooterStoryArgs> = {
|
|
34
|
-
title: "
|
|
34
|
+
title: "Components/Menus/v1/Primitives/MenuFooter",
|
|
35
35
|
component: MenuFooter,
|
|
36
36
|
parameters: {
|
|
37
37
|
controls: { expanded: true, sort: "requiredFirst" },
|
|
@@ -29,7 +29,7 @@ interface MenuHeaderStoryArgs extends TypeMenuHeaderProps {
|
|
|
29
29
|
type Story = StoryObj<MenuHeaderStoryArgs>;
|
|
30
30
|
|
|
31
31
|
const meta: Meta<MenuHeaderStoryArgs> = {
|
|
32
|
-
title: "
|
|
32
|
+
title: "Components/Menus/v1/Primitives/MenuHeader",
|
|
33
33
|
component: MenuHeader,
|
|
34
34
|
parameters: {
|
|
35
35
|
controls: { expanded: true, sort: "requiredFirst" },
|
|
@@ -34,7 +34,7 @@ interface MenuItemStoryArgs extends TypeMenuItemProps {
|
|
|
34
34
|
type Story = StoryObj<MenuItemStoryArgs>;
|
|
35
35
|
|
|
36
36
|
const meta: Meta<MenuItemStoryArgs> = {
|
|
37
|
-
title: "
|
|
37
|
+
title: "Components/Menus/v1/Primitives/MenuItem",
|
|
38
38
|
component: MenuItem,
|
|
39
39
|
decorators: [
|
|
40
40
|
(Story) => (
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "../index";
|
|
11
11
|
|
|
12
12
|
const meta: Meta<typeof MenuToggleButton> = {
|
|
13
|
-
title: "
|
|
13
|
+
title: "Components/Menus/v1/Primitives/MenuToggleButton",
|
|
14
14
|
component: MenuToggleButton,
|
|
15
15
|
decorators: [
|
|
16
16
|
(Story) => (
|
|
@@ -23,7 +23,7 @@ type TypeMultiSelectMenuStoryProps = TypeMultiSelectMenuProps & {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const meta: Meta<TypeMultiSelectMenuStoryProps> = {
|
|
26
|
-
title: "
|
|
26
|
+
title: "Components/Menus/v1/MultiSelectMenu",
|
|
27
27
|
component: MultiSelectMenu,
|
|
28
28
|
decorators: [
|
|
29
29
|
(Story) => (
|
|
@@ -23,7 +23,7 @@ import { MotionConfig } from "motion/react";
|
|
|
23
23
|
type CustomNestedMenuArgs = React.ComponentProps<typeof NestedMenu>;
|
|
24
24
|
|
|
25
25
|
const meta: Meta<CustomNestedMenuArgs> = {
|
|
26
|
-
title: "
|
|
26
|
+
title: "Components/Menus/v1/NestedMenu",
|
|
27
27
|
component: NestedMenu,
|
|
28
28
|
parameters: {
|
|
29
29
|
controls: {
|
|
@@ -24,7 +24,7 @@ type CustomSingleSelectArgs = TypeSingleSelectMenuProps & {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const meta: Meta<CustomSingleSelectArgs> = {
|
|
27
|
-
title: "
|
|
27
|
+
title: "Components/Menus/v1/SingleSelectMenu",
|
|
28
28
|
component: SingleSelectMenu,
|
|
29
29
|
parameters: {
|
|
30
30
|
controls: {
|
|
@@ -18,7 +18,7 @@ type SubmenuItemStoryArgs = TypeMenuItemProps & {
|
|
|
18
18
|
type Story = StoryObj<SubmenuItemStoryArgs>;
|
|
19
19
|
|
|
20
20
|
const meta: Meta<SubmenuItemStoryArgs> = {
|
|
21
|
-
title: "
|
|
21
|
+
title: "Components/Menus/v1/Submenu",
|
|
22
22
|
decorators: [(Story) => <Story />],
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -15,7 +15,7 @@ import type { ToggleItem, GroupHeading } from "../Common-V2";
|
|
|
15
15
|
type CustomAutocompleteArgs = React.ComponentProps<typeof MultiAutocomplete>;
|
|
16
16
|
|
|
17
17
|
const meta: Meta<CustomAutocompleteArgs> = {
|
|
18
|
-
title: "
|
|
18
|
+
title: "Components/Menus/v2/Autocomplete",
|
|
19
19
|
component: MultiAutocomplete,
|
|
20
20
|
parameters: {
|
|
21
21
|
controls: {
|
|
@@ -17,7 +17,7 @@ import type { ToggleItem } from "../Common-V2";
|
|
|
17
17
|
type CustomSelectArgs = React.ComponentProps<typeof MultiSelect>;
|
|
18
18
|
|
|
19
19
|
const meta: Meta<CustomSelectArgs> = {
|
|
20
|
-
title: "
|
|
20
|
+
title: "Components/Menus/v2/Select",
|
|
21
21
|
component: MultiSelect,
|
|
22
22
|
parameters: {
|
|
23
23
|
controls: {
|
|
@@ -6,7 +6,7 @@ import { MenuButton } from "./MenuButton";
|
|
|
6
6
|
import { MenuItem } from "./ActionMenu";
|
|
7
7
|
|
|
8
8
|
const meta: Meta<typeof MenuButton> = {
|
|
9
|
-
title: "
|
|
9
|
+
title: "Components/Menus/v3/MenuButton",
|
|
10
10
|
component: MenuButton,
|
|
11
11
|
decorators: [
|
|
12
12
|
(Story) => (
|
|
@@ -138,7 +138,7 @@ function AllComponents() {
|
|
|
138
138
|
// ─── Meta ─────────────────────────────────────────────────────────────────────
|
|
139
139
|
|
|
140
140
|
const meta: Meta = {
|
|
141
|
-
title: "
|
|
141
|
+
title: "Components/Menus/v3/In Modal",
|
|
142
142
|
};
|
|
143
143
|
|
|
144
144
|
export default meta;
|
package/src/v3/MultiCombobox.tsx
CHANGED
|
@@ -74,6 +74,9 @@ interface MultiComboboxBaseProps {
|
|
|
74
74
|
filter?: ((item: unknown, query: string) => boolean) | null;
|
|
75
75
|
inputValue?: string;
|
|
76
76
|
onInputValueChange?: (value: string) => void;
|
|
77
|
+
"aria-label"?: string;
|
|
78
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
79
|
+
"aria-labelledby"?: string;
|
|
77
80
|
"aria-describedby"?: string;
|
|
78
81
|
isInvalid?: boolean;
|
|
79
82
|
required?: boolean;
|
|
@@ -150,6 +153,8 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
150
153
|
fullWidth = true,
|
|
151
154
|
} = props;
|
|
152
155
|
const ariaDescribedBy = props["aria-describedby"];
|
|
156
|
+
const ariaLabel = props["aria-label"];
|
|
157
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
153
158
|
const isInvalid = props.isInvalid;
|
|
154
159
|
|
|
155
160
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -674,6 +679,8 @@ export function MultiCombobox<T extends DataWithId>(
|
|
|
674
679
|
<ComboboxStatus>{isLoading ? loadingText : null}</ComboboxStatus>
|
|
675
680
|
<ComboboxEmpty>{isLoading ? null : emptyText}</ComboboxEmpty>
|
|
676
681
|
<ComboboxList
|
|
682
|
+
aria-label={ariaLabel}
|
|
683
|
+
aria-labelledby={ariaLabelledBy}
|
|
677
684
|
style={
|
|
678
685
|
isVirtualized
|
|
679
686
|
? {
|
|
@@ -79,6 +79,9 @@ interface MultiSearchableSelectBaseProps {
|
|
|
79
79
|
loadingText?: string;
|
|
80
80
|
disabled?: boolean;
|
|
81
81
|
filter?: ((item: unknown, query: string) => boolean) | null;
|
|
82
|
+
"aria-label"?: string;
|
|
83
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
84
|
+
"aria-labelledby"?: string;
|
|
82
85
|
"aria-describedby"?: string;
|
|
83
86
|
isInvalid?: boolean;
|
|
84
87
|
required?: boolean;
|
|
@@ -151,6 +154,8 @@ export function MultiSearchableSelect<T extends DataWithId>(
|
|
|
151
154
|
fullWidth = true,
|
|
152
155
|
} = props;
|
|
153
156
|
const ariaDescribedBy = props["aria-describedby"];
|
|
157
|
+
const ariaLabel = props["aria-label"];
|
|
158
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
154
159
|
const isInvalid = props.isInvalid;
|
|
155
160
|
|
|
156
161
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -609,6 +614,8 @@ export function MultiSearchableSelect<T extends DataWithId>(
|
|
|
609
614
|
<ComboboxStatus>{isLoading ? loadingText : null}</ComboboxStatus>
|
|
610
615
|
<ComboboxEmpty>{isLoading ? null : emptyText}</ComboboxEmpty>
|
|
611
616
|
<SearchableSelectList
|
|
617
|
+
aria-label={ariaLabel}
|
|
618
|
+
aria-labelledby={ariaLabelledBy}
|
|
612
619
|
style={
|
|
613
620
|
isVirtualized
|
|
614
621
|
? {
|
package/src/v3/MultiSelect.tsx
CHANGED
|
@@ -43,6 +43,9 @@ interface MultiSelectBaseProps {
|
|
|
43
43
|
id?: string;
|
|
44
44
|
placeholder?: string;
|
|
45
45
|
disabled?: boolean;
|
|
46
|
+
"aria-label"?: string;
|
|
47
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
48
|
+
"aria-labelledby"?: string;
|
|
46
49
|
"aria-describedby"?: string;
|
|
47
50
|
isInvalid?: boolean;
|
|
48
51
|
required?: boolean;
|
|
@@ -93,6 +96,8 @@ export type MultiSelectProps<T extends DataWithId> =
|
|
|
93
96
|
export function MultiSelect<T extends DataWithId>(props: MultiSelectProps<T>) {
|
|
94
97
|
const { id, placeholder = "Select...", fullWidth = true } = props;
|
|
95
98
|
const ariaDescribedBy = props["aria-describedby"];
|
|
99
|
+
const ariaLabel = props["aria-label"];
|
|
100
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
96
101
|
const isInvalid = props.isInvalid;
|
|
97
102
|
|
|
98
103
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -232,7 +237,10 @@ export function MultiSelect<T extends DataWithId>(props: MultiSelectProps<T>) {
|
|
|
232
237
|
<SelectPositioner sideOffset={8} alignItemWithTrigger={false}>
|
|
233
238
|
<SelectPopup>
|
|
234
239
|
<Select.ScrollUpArrow />
|
|
235
|
-
<Select.List
|
|
240
|
+
<Select.List
|
|
241
|
+
aria-label={ariaLabel}
|
|
242
|
+
aria-labelledby={ariaLabelledBy}
|
|
243
|
+
>
|
|
236
244
|
{children
|
|
237
245
|
? children
|
|
238
246
|
: groupBy
|
|
@@ -32,6 +32,9 @@ interface SingleComboboxBaseProps {
|
|
|
32
32
|
emptyText?: string;
|
|
33
33
|
disabled?: boolean;
|
|
34
34
|
filter?: ((item: unknown, query: string) => boolean) | null;
|
|
35
|
+
"aria-label"?: string;
|
|
36
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
37
|
+
"aria-labelledby"?: string;
|
|
35
38
|
"aria-describedby"?: string;
|
|
36
39
|
isInvalid?: boolean;
|
|
37
40
|
required?: boolean;
|
|
@@ -96,6 +99,8 @@ export function SingleCombobox<T extends DataWithId>(
|
|
|
96
99
|
fullWidth = true,
|
|
97
100
|
} = props;
|
|
98
101
|
const ariaDescribedBy = props["aria-describedby"];
|
|
102
|
+
const ariaLabel = props["aria-label"];
|
|
103
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
99
104
|
const isInvalid = props.isInvalid;
|
|
100
105
|
|
|
101
106
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -244,6 +249,8 @@ export function SingleCombobox<T extends DataWithId>(
|
|
|
244
249
|
>
|
|
245
250
|
<ComboboxEmpty>{emptyText}</ComboboxEmpty>
|
|
246
251
|
<ComboboxList
|
|
252
|
+
aria-label={ariaLabel}
|
|
253
|
+
aria-labelledby={ariaLabelledBy}
|
|
247
254
|
style={
|
|
248
255
|
isVirtualized
|
|
249
256
|
? {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./storyData";
|
|
12
12
|
|
|
13
13
|
const meta: Meta<typeof SingleSearchableSelect> = {
|
|
14
|
-
title: "
|
|
14
|
+
title: "Components/Menus/v3/Single Searchable Select",
|
|
15
15
|
component: SingleSearchableSelect,
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -41,6 +41,9 @@ interface SingleSearchableSelectBaseProps {
|
|
|
41
41
|
loadingText?: string;
|
|
42
42
|
disabled?: boolean;
|
|
43
43
|
filter?: ((item: unknown, query: string) => boolean) | null;
|
|
44
|
+
"aria-label"?: string;
|
|
45
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
46
|
+
"aria-labelledby"?: string;
|
|
44
47
|
"aria-describedby"?: string;
|
|
45
48
|
isInvalid?: boolean;
|
|
46
49
|
required?: boolean;
|
|
@@ -112,6 +115,8 @@ export function SingleSearchableSelect<T extends DataWithId>(
|
|
|
112
115
|
fullWidth = true,
|
|
113
116
|
} = props;
|
|
114
117
|
const ariaDescribedBy = props["aria-describedby"];
|
|
118
|
+
const ariaLabel = props["aria-label"];
|
|
119
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
115
120
|
const isInvalid = props.isInvalid;
|
|
116
121
|
|
|
117
122
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -278,6 +283,8 @@ export function SingleSearchableSelect<T extends DataWithId>(
|
|
|
278
283
|
<ComboboxStatus>{isLoading ? loadingText : null}</ComboboxStatus>
|
|
279
284
|
<ComboboxEmpty>{isLoading ? null : emptyText}</ComboboxEmpty>
|
|
280
285
|
<SearchableSelectList
|
|
286
|
+
aria-label={ariaLabel}
|
|
287
|
+
aria-labelledby={ariaLabelledBy}
|
|
281
288
|
style={
|
|
282
289
|
isVirtualized
|
|
283
290
|
? {
|
package/src/v3/SingleSelect.tsx
CHANGED
|
@@ -39,6 +39,9 @@ interface SingleSelectBaseProps {
|
|
|
39
39
|
placeholder?: string;
|
|
40
40
|
includePlaceholderItem?: boolean;
|
|
41
41
|
disabled?: boolean;
|
|
42
|
+
"aria-label"?: string;
|
|
43
|
+
/** Id of a visible label. Preferred over `aria-label`. */
|
|
44
|
+
"aria-labelledby"?: string;
|
|
42
45
|
"aria-describedby"?: string;
|
|
43
46
|
isInvalid?: boolean;
|
|
44
47
|
required?: boolean;
|
|
@@ -85,6 +88,8 @@ export function SingleSelect<T extends DataWithId>(
|
|
|
85
88
|
) {
|
|
86
89
|
const { id, placeholder, includePlaceholderItem, fullWidth = true } = props;
|
|
87
90
|
const ariaDescribedBy = props["aria-describedby"];
|
|
91
|
+
const ariaLabel = props["aria-label"];
|
|
92
|
+
const ariaLabelledBy = props["aria-labelledby"];
|
|
88
93
|
const isInvalid = props.isInvalid;
|
|
89
94
|
|
|
90
95
|
const isChildrenMode = "children" in props && props.children != null;
|
|
@@ -193,7 +198,10 @@ export function SingleSelect<T extends DataWithId>(
|
|
|
193
198
|
<SelectPositioner sideOffset={8} alignItemWithTrigger={false}>
|
|
194
199
|
<SelectPopup>
|
|
195
200
|
<Select.ScrollUpArrow />
|
|
196
|
-
<Select.List
|
|
201
|
+
<Select.List
|
|
202
|
+
aria-label={ariaLabel}
|
|
203
|
+
aria-labelledby={ariaLabelledBy}
|
|
204
|
+
>
|
|
197
205
|
{children ? (
|
|
198
206
|
children
|
|
199
207
|
) : groupBy ? (
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
fireEvent,
|
|
4
|
+
render,
|
|
5
|
+
screen,
|
|
6
|
+
} from "@sproutsocial/seeds-react-testing-library";
|
|
7
|
+
import { SingleSelect } from "../SingleSelect";
|
|
8
|
+
import { MultiSelect } from "../MultiSelect";
|
|
9
|
+
import { SingleCombobox } from "../SingleCombobox";
|
|
10
|
+
import { MultiCombobox } from "../MultiCombobox";
|
|
11
|
+
import { SingleSearchableSelect } from "../SingleSearchableSelect";
|
|
12
|
+
import { MultiSearchableSelect } from "../MultiSearchableSelect";
|
|
13
|
+
import { books, itemToString } from "../storyData";
|
|
14
|
+
|
|
15
|
+
// Base UI's Select.List and Combobox.List render role="listbox" with no name of
|
|
16
|
+
// their own. axe only reports that as aria-input-field-name once the trigger has
|
|
17
|
+
// dropped its aria-controls, which happens while the popup animates closed — a
|
|
18
|
+
// state jsdom does not reach. So these assert the property that fixes the rule:
|
|
19
|
+
// the listbox carries a name of its own, independent of the trigger.
|
|
20
|
+
|
|
21
|
+
const LABEL_ID = "book-label";
|
|
22
|
+
const VisibleLabel = () => <span id={LABEL_ID}>Book</span>;
|
|
23
|
+
|
|
24
|
+
const openSelectPopup = () => {
|
|
25
|
+
fireEvent.click(screen.getByRole("combobox"));
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const openComboboxPopup = () => {
|
|
29
|
+
fireEvent.click(screen.getByRole("button", { name: "Open popup" }));
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
interface Labelling {
|
|
33
|
+
"aria-label"?: string;
|
|
34
|
+
"aria-labelledby"?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Case {
|
|
38
|
+
name: string;
|
|
39
|
+
renderWith: (labelling: Labelling) => ReturnType<typeof render>;
|
|
40
|
+
openPopup: () => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const cases: Case[] = [
|
|
44
|
+
{
|
|
45
|
+
name: "SingleSelect",
|
|
46
|
+
renderWith: (labelling) =>
|
|
47
|
+
render(
|
|
48
|
+
<SingleSelect data={books} itemToString={itemToString} {...labelling} />
|
|
49
|
+
),
|
|
50
|
+
openPopup: openSelectPopup,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "MultiSelect",
|
|
54
|
+
renderWith: (labelling) =>
|
|
55
|
+
render(
|
|
56
|
+
<MultiSelect data={books} itemToString={itemToString} {...labelling} />
|
|
57
|
+
),
|
|
58
|
+
openPopup: openSelectPopup,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "SingleSearchableSelect",
|
|
62
|
+
renderWith: (labelling) =>
|
|
63
|
+
render(
|
|
64
|
+
<SingleSearchableSelect
|
|
65
|
+
data={books}
|
|
66
|
+
itemToString={itemToString}
|
|
67
|
+
{...labelling}
|
|
68
|
+
/>
|
|
69
|
+
),
|
|
70
|
+
openPopup: openSelectPopup,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "MultiSearchableSelect",
|
|
74
|
+
renderWith: (labelling) =>
|
|
75
|
+
render(
|
|
76
|
+
<MultiSearchableSelect
|
|
77
|
+
data={books}
|
|
78
|
+
itemToString={itemToString}
|
|
79
|
+
{...labelling}
|
|
80
|
+
/>
|
|
81
|
+
),
|
|
82
|
+
openPopup: openSelectPopup,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "SingleCombobox",
|
|
86
|
+
renderWith: (labelling) =>
|
|
87
|
+
render(
|
|
88
|
+
<SingleCombobox
|
|
89
|
+
data={books}
|
|
90
|
+
itemToString={itemToString}
|
|
91
|
+
{...labelling}
|
|
92
|
+
/>
|
|
93
|
+
),
|
|
94
|
+
openPopup: openComboboxPopup,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "MultiCombobox",
|
|
98
|
+
renderWith: (labelling) =>
|
|
99
|
+
render(
|
|
100
|
+
<MultiCombobox
|
|
101
|
+
data={books}
|
|
102
|
+
itemToString={itemToString}
|
|
103
|
+
{...labelling}
|
|
104
|
+
/>
|
|
105
|
+
),
|
|
106
|
+
openPopup: openComboboxPopup,
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
describe.each(cases)("$name popup listbox", ({ renderWith, openPopup }) => {
|
|
111
|
+
test("is named by aria-label", () => {
|
|
112
|
+
renderWith({ "aria-label": "Book" });
|
|
113
|
+
openPopup();
|
|
114
|
+
|
|
115
|
+
expect(screen.getByRole("listbox", { name: "Book" })).toBeInTheDocument();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("is named by aria-labelledby", () => {
|
|
119
|
+
render(<VisibleLabel />);
|
|
120
|
+
renderWith({ "aria-labelledby": LABEL_ID });
|
|
121
|
+
openPopup();
|
|
122
|
+
|
|
123
|
+
expect(screen.getByRole("listbox", { name: "Book" })).toBeInTheDocument();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("is unnamed when neither is given", () => {
|
|
127
|
+
renderWith({});
|
|
128
|
+
openPopup();
|
|
129
|
+
|
|
130
|
+
expect(screen.getByRole("listbox")).not.toHaveAttribute("aria-label");
|
|
131
|
+
expect(screen.getByRole("listbox")).not.toHaveAttribute("aria-labelledby");
|
|
132
|
+
});
|
|
133
|
+
});
|