@sproutsocial/seeds-react-menu 1.2.1 → 1.2.3
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 +10 -10
- package/CHANGELOG.md +12 -0
- package/dist/esm/index.js +90 -83
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +119 -59
- package/dist/index.d.ts +119 -59
- package/dist/index.js +118 -111
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/ActionMenu/ActionMenu.tsx +2 -2
- package/src/Autocomplete/Autocomplete.stories.tsx +6 -18
- package/src/Autocomplete/Autocomplete.tsx +2 -3
- package/src/Autocomplete/AutocompleteTypes.ts +16 -12
- package/src/Autocomplete/MultiAutocomplete.tsx +26 -18
- package/src/Autocomplete/SingleAutocomplete.tsx +20 -9
- package/src/MenuContent/MenuContent.tsx +4 -4
- package/src/MenuContext.tsx +3 -0
- package/src/MenuFooter/MenuFooter.tsx +2 -2
- package/src/MenuGroup/MenuGroup.tsx +4 -4
- package/src/MenuHeader/MenuHeader.tsx +4 -2
- package/src/MenuLabel.tsx +32 -2
- package/src/MenuRoot/MenuRoot.tsx +7 -24
- package/src/MenuSearchInput/MenuSearchInput.tsx +5 -11
- package/src/MenuSearchTokenInput/MenuSearchTokenInput.tsx +6 -3
- package/src/MenuToggleButton/MenuToggleButton.tsx +11 -12
- package/src/MenuTokenInput.tsx +10 -4
- package/src/MultiSelectMenu/MultiSelectMenu.tsx +4 -3
- package/src/NestedMenu/NestedMenu.feature +2 -2
- package/src/NestedMenu/NestedMenuTypes.ts +3 -0
- package/src/SingleSelectMenu/SingleSelectMenu.tsx +5 -4
- package/src/hooks/useItemFiltering.tsx +2 -1
- package/src/hooks/useMenuChildren.tsx +1 -1
- package/src/types.ts +28 -15
package/package.json
CHANGED
|
@@ -78,8 +78,8 @@ const handleStateChange = (
|
|
|
78
78
|
* @description An ActionMenu contains a list of clickable items like buttons or links. ActionMenus do not hold a selection.
|
|
79
79
|
*
|
|
80
80
|
* **To select menu items:**
|
|
81
|
-
* @see {@link https://
|
|
82
|
-
* @see {@link https://
|
|
81
|
+
* @see {@link https://seeds.sproutsocial.com/components/single-select-menu SingleSelectMenu}
|
|
82
|
+
* @see {@link https://seeds.sproutsocial.com/components/multi-select-menu MultiSelectMenu}
|
|
83
83
|
*/
|
|
84
84
|
export const ActionMenu = <I extends TypeMenuItemProps = TypeMenuItemProps>({
|
|
85
85
|
children: childrenProp,
|
|
@@ -52,9 +52,7 @@ export const AutocompleteTextInputExample: Story = {
|
|
|
52
52
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
53
53
|
menuToggleElement={
|
|
54
54
|
<>
|
|
55
|
-
<MenuLabel
|
|
56
|
-
Choose a book
|
|
57
|
-
</MenuLabel>
|
|
55
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
58
56
|
<AutocompleteInput />
|
|
59
57
|
</>
|
|
60
58
|
}
|
|
@@ -80,9 +78,7 @@ export const AutocompleteWithItemsAsProps: Story = {
|
|
|
80
78
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
81
79
|
menuToggleElement={
|
|
82
80
|
<>
|
|
83
|
-
<MenuLabel
|
|
84
|
-
Choose a book
|
|
85
|
-
</MenuLabel>
|
|
81
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
86
82
|
<AutocompleteInput />
|
|
87
83
|
</>
|
|
88
84
|
}
|
|
@@ -104,9 +100,7 @@ export const AutocompleteTextWithButtonExample: Story = {
|
|
|
104
100
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
105
101
|
menuToggleElement={
|
|
106
102
|
<>
|
|
107
|
-
<MenuLabel
|
|
108
|
-
Choose a book
|
|
109
|
-
</MenuLabel>
|
|
103
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
110
104
|
<Box display="flex" alignItems="center" gap={200}>
|
|
111
105
|
<AutocompleteInput style={{ flex: 2 }} />
|
|
112
106
|
<MenuToggleButton>
|
|
@@ -137,9 +131,7 @@ export const AutocompleteTokenInputExample: Story = {
|
|
|
137
131
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
138
132
|
menuToggleElement={
|
|
139
133
|
<>
|
|
140
|
-
<MenuLabel
|
|
141
|
-
Choose a book
|
|
142
|
-
</MenuLabel>
|
|
134
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
143
135
|
<AutocompleteTokenInput />
|
|
144
136
|
<MenuToggleButton mt={200} width="100%" p="0">
|
|
145
137
|
<Icon name="chevron-down" aria-label="Open Menu" />
|
|
@@ -170,9 +162,7 @@ export const AutocompleteSelectExample: Story = {
|
|
|
170
162
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
171
163
|
menuToggleElement={
|
|
172
164
|
<>
|
|
173
|
-
<MenuLabel
|
|
174
|
-
Choose a book
|
|
175
|
-
</MenuLabel>
|
|
165
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
176
166
|
<AutocompleteSelect />
|
|
177
167
|
</>
|
|
178
168
|
}
|
|
@@ -247,9 +237,7 @@ const TestControlledMultiAutocomplete = (args: CustomAutocompleteArgs) => {
|
|
|
247
237
|
itemToString={(item) => (item ? TEST_BOOKS[item.index].title : "")}
|
|
248
238
|
menuToggleElement={
|
|
249
239
|
<>
|
|
250
|
-
<MenuLabel
|
|
251
|
-
Choose a book
|
|
252
|
-
</MenuLabel>
|
|
240
|
+
<MenuLabel mb={300}>Choose a book</MenuLabel>
|
|
253
241
|
<AutocompleteTokenInput />
|
|
254
242
|
<MenuToggleButton mt={200} width="100%" p="0">
|
|
255
243
|
<Icon name="chevron-down" aria-label="Open Menu" />
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import type { TypeMenuItemProps } from "../MenuItem";
|
|
4
|
-
import type { TypeMenuRootProps } from "../MenuRoot";
|
|
5
4
|
import type { TypeAutocompleteProps } from "./AutocompleteTypes";
|
|
6
5
|
import { SingleAutocomplete } from "./SingleAutocomplete";
|
|
7
6
|
import { MultiAutocomplete } from "./MultiAutocomplete";
|
|
@@ -9,11 +8,11 @@ import { MultiAutocomplete } from "./MultiAutocomplete";
|
|
|
9
8
|
/**
|
|
10
9
|
* @link https://seeds.sproutsocial.com/components/autocomplete/
|
|
11
10
|
*
|
|
12
|
-
* @description A Autocomplete allows selecting
|
|
11
|
+
* @description A Autocomplete allows selecting {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItems} from a list or groups of lists to populate an input.
|
|
13
12
|
*
|
|
14
13
|
*/
|
|
15
14
|
export const Autocomplete = <I extends TypeMenuItemProps = TypeMenuItemProps>({
|
|
16
|
-
multiSelect,
|
|
15
|
+
multiSelect = false,
|
|
17
16
|
...rest
|
|
18
17
|
}: TypeAutocompleteProps<I>) => {
|
|
19
18
|
if (multiSelect) {
|
|
@@ -1,34 +1,38 @@
|
|
|
1
|
-
import type { TypeMenuRootOwnProps } from "../MenuRoot";
|
|
2
1
|
import type {
|
|
3
2
|
TypeDownshiftComboboxProps,
|
|
4
3
|
TypeDownshiftMultiSelectProps,
|
|
5
4
|
} from "../MenuContext";
|
|
6
5
|
import type { TypeGetIsItemVisibleFn } from "../hooks/useItemFiltering";
|
|
7
|
-
import type { TypeMenuRootProps } from "../MenuRoot";
|
|
8
6
|
import type { TypeMenuItemProps } from "../MenuItem";
|
|
9
7
|
import type {
|
|
10
8
|
TypeChildrenOrItems,
|
|
11
9
|
TypeHigherOrderComponentProps,
|
|
12
10
|
} from "../types";
|
|
13
11
|
|
|
14
|
-
export type
|
|
15
|
-
I extends TypeMenuItemProps = TypeMenuItemProps
|
|
16
|
-
> = TypeHigherOrderComponentProps &
|
|
17
|
-
TypeChildrenOrItems<I> &
|
|
12
|
+
export type TypeBaseAutocompleteProps = TypeHigherOrderComponentProps &
|
|
18
13
|
TypeDownshiftComboboxProps & {
|
|
14
|
+
/** A function that can be passed to override the default filtering logic */
|
|
19
15
|
getIsItemVisible?: TypeGetIsItemVisibleFn;
|
|
16
|
+
/** Set multiSelect to true to allow multiple selections.
|
|
17
|
+
* Default: false*/
|
|
18
|
+
multiSelect?: boolean;
|
|
20
19
|
};
|
|
21
20
|
|
|
21
|
+
export type TypeSingleAutocompleteProps<
|
|
22
|
+
I extends TypeMenuItemProps = TypeMenuItemProps
|
|
23
|
+
> = TypeBaseAutocompleteProps & {
|
|
24
|
+
multiSelect?: false;
|
|
25
|
+
} & TypeChildrenOrItems<I>;
|
|
26
|
+
|
|
22
27
|
export type TypeMultiAutocompleteProps<
|
|
23
28
|
I extends TypeMenuItemProps = TypeMenuItemProps
|
|
24
|
-
> =
|
|
29
|
+
> = TypeBaseAutocompleteProps &
|
|
25
30
|
TypeDownshiftMultiSelectProps & {
|
|
26
|
-
|
|
31
|
+
multiSelect?: true;
|
|
32
|
+
/** Determines whether a multiselect autocomplete will display selected items in the dropdown */
|
|
27
33
|
showSelectedItemsInDropdown?: boolean;
|
|
28
|
-
}
|
|
34
|
+
} & TypeChildrenOrItems<I>;
|
|
29
35
|
|
|
30
36
|
export type TypeAutocompleteProps<
|
|
31
37
|
I extends TypeMenuItemProps = TypeMenuItemProps
|
|
32
|
-
> =
|
|
33
|
-
| (TypeSingleAutocompleteProps<I> & { multiSelect?: false })
|
|
34
|
-
| (TypeMultiAutocompleteProps<I> & { multiSelect: true });
|
|
38
|
+
> = TypeSingleAutocompleteProps<I> | TypeMultiAutocompleteProps<I>;
|
|
@@ -74,18 +74,20 @@ export const MultiAutocomplete = <
|
|
|
74
74
|
[selectedItemIds, showSelectedItemsInDropdown, getIsItemVisible]
|
|
75
75
|
);
|
|
76
76
|
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
77
|
+
const downshiftDefaults = useDownshiftDefaults({
|
|
78
|
+
isCombobox: true,
|
|
79
|
+
isMulti: true,
|
|
80
|
+
// handles the prop name mapping for multi select
|
|
81
|
+
multiSelectProps: {
|
|
82
|
+
getA11yMultiStatusMessage,
|
|
83
|
+
onMultiSelectStateChange,
|
|
84
|
+
multiSelectStateReducer,
|
|
85
|
+
...useComboboxProps,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const { setHiddenItemsMap, defaultDownshiftProps, hiddenItemsCount } =
|
|
90
|
+
downshiftDefaults;
|
|
89
91
|
|
|
90
92
|
// used to handle filtering of items
|
|
91
93
|
const { updateFilteredItems } = useItemFiltering({
|
|
@@ -118,9 +120,8 @@ export const MultiAutocomplete = <
|
|
|
118
120
|
/**
|
|
119
121
|
* Destructure Downshift props and call the core useCombobox with items and state handler
|
|
120
122
|
*/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
>({
|
|
123
|
+
|
|
124
|
+
const useComboboxReturnProps = useCombobox<(typeof allMenuItems)[number]>({
|
|
124
125
|
...defaultDownshiftProps.combobox,
|
|
125
126
|
items: allMenuItems,
|
|
126
127
|
itemToString,
|
|
@@ -160,24 +161,31 @@ export const MultiAutocomplete = <
|
|
|
160
161
|
...useComboboxProps,
|
|
161
162
|
});
|
|
162
163
|
|
|
164
|
+
const { isOpen, closeMenu, inputValue } = useComboboxReturnProps;
|
|
165
|
+
|
|
166
|
+
React.useEffect(() => {
|
|
167
|
+
if (!inputValue) return;
|
|
168
|
+
if (allMenuItems && hiddenItemsCount >= allMenuItems.length && isOpen) {
|
|
169
|
+
closeMenu?.();
|
|
170
|
+
}
|
|
171
|
+
}, [hiddenItemsCount, allMenuItems?.length, isOpen, inputValue]);
|
|
172
|
+
|
|
163
173
|
return (
|
|
164
174
|
<MenuRootComponent
|
|
165
175
|
{...{
|
|
166
176
|
isListbox: true,
|
|
167
177
|
items: allMenuItems,
|
|
168
178
|
itemToString,
|
|
169
|
-
isOpen,
|
|
170
179
|
initialSelectedItems,
|
|
171
180
|
onStateChange,
|
|
172
181
|
onSelectedItemsChange,
|
|
173
182
|
getA11yMultiStatusMessage,
|
|
174
183
|
onMultiSelectStateChange,
|
|
175
184
|
multiSelectStateReducer,
|
|
176
|
-
setHiddenItemsMap,
|
|
177
185
|
...useComboboxProps,
|
|
178
186
|
...useComboboxReturnProps,
|
|
179
187
|
...useMultipleSelectionReturnProps,
|
|
180
|
-
...
|
|
188
|
+
...downshiftDefaults,
|
|
181
189
|
}}
|
|
182
190
|
popoutProps={{
|
|
183
191
|
focusOnContent: false,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { useCombobox } from "downshift";
|
|
3
3
|
import { useMenuChildren } from "../hooks/useMenuChildren";
|
|
4
4
|
import { itemToString as defaultItemToString } from "../utils/downshiftDefaults";
|
|
@@ -8,7 +8,7 @@ import { useItemFiltering } from "../hooks/useItemFiltering";
|
|
|
8
8
|
import { MenuRoot } from "../MenuRoot";
|
|
9
9
|
|
|
10
10
|
import type { TypeMenuItemProps } from "../MenuItem";
|
|
11
|
-
import type {
|
|
11
|
+
import type { TypeSingleAutocompleteProps } from "./AutocompleteTypes";
|
|
12
12
|
|
|
13
13
|
export const SingleAutocomplete = <
|
|
14
14
|
I extends TypeMenuItemProps = TypeMenuItemProps
|
|
@@ -21,15 +21,19 @@ export const SingleAutocomplete = <
|
|
|
21
21
|
itemToString = defaultItemToString,
|
|
22
22
|
getIsItemVisible,
|
|
23
23
|
...useComboboxProps
|
|
24
|
-
}:
|
|
24
|
+
}: TypeSingleAutocompleteProps<I>) => {
|
|
25
25
|
/** Get a list of menuItems and children */
|
|
26
26
|
const { allMenuItems, children } = useMenuChildren({
|
|
27
27
|
children: childrenProp,
|
|
28
28
|
menuItems,
|
|
29
29
|
MenuItemComponent,
|
|
30
30
|
});
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
const downshiftDefaults = useDownshiftDefaults({ isCombobox: true });
|
|
33
|
+
|
|
34
|
+
const { setHiddenItemsMap, defaultDownshiftProps, hiddenItemsCount } =
|
|
35
|
+
downshiftDefaults;
|
|
36
|
+
|
|
33
37
|
const { updateFilteredItems } = useItemFiltering({
|
|
34
38
|
allMenuItems,
|
|
35
39
|
itemToString,
|
|
@@ -40,7 +44,7 @@ export const SingleAutocomplete = <
|
|
|
40
44
|
/**
|
|
41
45
|
* Destructure Downshift props and call the core useCombobox with items and state handler
|
|
42
46
|
*/
|
|
43
|
-
const
|
|
47
|
+
const useComboboxReturnProps = useCombobox({
|
|
44
48
|
...defaultDownshiftProps.combobox,
|
|
45
49
|
items: allMenuItems,
|
|
46
50
|
itemToString,
|
|
@@ -52,17 +56,24 @@ export const SingleAutocomplete = <
|
|
|
52
56
|
...useComboboxProps,
|
|
53
57
|
});
|
|
54
58
|
|
|
59
|
+
const { isOpen, closeMenu, inputValue } = useComboboxReturnProps;
|
|
60
|
+
|
|
61
|
+
React.useEffect(() => {
|
|
62
|
+
if (!inputValue) return;
|
|
63
|
+
if (allMenuItems && hiddenItemsCount >= allMenuItems.length && isOpen) {
|
|
64
|
+
closeMenu?.();
|
|
65
|
+
}
|
|
66
|
+
}, [hiddenItemsCount, allMenuItems?.length, isOpen, inputValue]);
|
|
67
|
+
|
|
55
68
|
return (
|
|
56
69
|
<MenuRootComponent
|
|
57
70
|
{...{
|
|
58
71
|
isListbox: true,
|
|
59
72
|
items: allMenuItems,
|
|
60
73
|
itemToString,
|
|
61
|
-
isOpen,
|
|
62
|
-
setHiddenItemsMap,
|
|
63
74
|
...useComboboxProps,
|
|
64
75
|
...useComboboxReturnProps,
|
|
65
|
-
...
|
|
76
|
+
...downshiftDefaults,
|
|
66
77
|
}}
|
|
67
78
|
popoutProps={{
|
|
68
79
|
focusOnContent: false,
|
|
@@ -6,9 +6,9 @@ import { useCallback } from "react";
|
|
|
6
6
|
import type { TypeMenuItemProps } from "../MenuItem";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @link https://seeds.sproutsocial.com/components/menu
|
|
9
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menucontent
|
|
10
10
|
*
|
|
11
|
-
* @description MenuContent is used to contain lists or grouped lists of {@link https://
|
|
11
|
+
* @description MenuContent is used to contain lists or grouped lists of {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItems}.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* <ActionMenu>
|
|
@@ -24,8 +24,8 @@ import type { TypeMenuItemProps } from "../MenuItem";
|
|
|
24
24
|
* <MenuFooter>Footer</MenuFooter>
|
|
25
25
|
* </ActionMenu>
|
|
26
26
|
*
|
|
27
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
28
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
27
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItem}
|
|
28
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menugroup MenuGroup}
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
const MenuContent = <I extends TypeMenuItemProps = TypeMenuItemProps>({
|
package/src/MenuContext.tsx
CHANGED
|
@@ -28,8 +28,11 @@ export interface TypeDownshiftMultiSelectProps
|
|
|
28
28
|
>
|
|
29
29
|
> {
|
|
30
30
|
// Multi Select Props with conflicting useSelect prop names
|
|
31
|
+
/** Optional override to the built-in getA11yStatusMessage function for multiple selection*/
|
|
31
32
|
getA11yMultiStatusMessage?: UseMultipleSelectionProps<TypeInternalItemProps>["getA11yStatusMessage"];
|
|
33
|
+
/** Optional override to the built-in onStateChange function for multiple selection*/
|
|
32
34
|
onMultiSelectStateChange?: UseMultipleSelectionProps<TypeInternalItemProps>["onStateChange"];
|
|
35
|
+
/** Optional override to the built-in stateReducer function for multiple selection*/
|
|
33
36
|
multiSelectStateReducer?: UseMultipleSelectionProps<TypeInternalItemProps>["stateReducer"];
|
|
34
37
|
}
|
|
35
38
|
|
|
@@ -3,11 +3,11 @@ import type { TypeMenuFooterProps } from "./MenuFooterTypes";
|
|
|
3
3
|
import { StyledMenuFooterBox } from "./styles";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @link https://seeds.sproutsocial.com/components/menu
|
|
6
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menufooter
|
|
7
7
|
*
|
|
8
8
|
* @description MenuFooter is a container used to hold footer content within a Menu.
|
|
9
9
|
*
|
|
10
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
10
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuheader MenuHeader}
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
export const MenuFooter = ({ children, ...rest }: TypeMenuFooterProps) => {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import type { TypeMenuItemProps } from "../MenuItem";
|
|
3
|
-
import type { TypeMenuRootProps } from "../MenuRoot";
|
|
4
3
|
import type { TypeMenuGroupProps } from "./MenuGroupTypes";
|
|
5
4
|
import { StyledMenuGroup, StyledTitle, StyledMenuGroupUl } from "./styles";
|
|
6
5
|
import { mapMenuItems } from "../hooks/useMenuChildren";
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
|
-
* @link https://seeds.sproutsocial.com/components/menu
|
|
8
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menugroup
|
|
10
9
|
*
|
|
11
|
-
* @description MenuGroup is used to group lists of {@link https://
|
|
10
|
+
* @description MenuGroup is used to group lists of {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItems}.
|
|
12
11
|
*
|
|
13
12
|
* @example
|
|
14
13
|
* <ActionMenu>
|
|
@@ -22,7 +21,8 @@ import { mapMenuItems } from "../hooks/useMenuChildren";
|
|
|
22
21
|
* </MenuContent>
|
|
23
22
|
* </ActionMenu>
|
|
24
23
|
*
|
|
25
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
24
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItem}
|
|
25
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menucontent MenuContent}
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
const MenuGroup = <I extends TypeMenuItemProps = TypeMenuItemProps>({
|
|
@@ -8,11 +8,13 @@ import {
|
|
|
8
8
|
import type { TypeMenuHeaderProps } from "./MenuHeaderTypes";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @link https://seeds.sproutsocial.com/components/menu
|
|
11
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuheader
|
|
12
12
|
*
|
|
13
13
|
* @description MenuHeader is a container used to hold header content within a Menu.
|
|
14
14
|
*
|
|
15
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
15
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menufooter MenuFooter}
|
|
16
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchinput MenuSearchInput}
|
|
17
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchtokeninput MenuSearchTokenInput}
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
const MenuHeader = ({
|
package/src/MenuLabel.tsx
CHANGED
|
@@ -2,10 +2,40 @@ import React from "react";
|
|
|
2
2
|
import { Label, type TypeLabelProps } from "@sproutsocial/seeds-react-label";
|
|
3
3
|
import { useMenuToggleContext } from "./MenuContext";
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export interface TypeMenuLabelProps extends Omit<TypeLabelProps, "htmlFor"> {
|
|
6
|
+
// The children and required types are redundant, but they power the MenuLabel PropTable.
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
/** Whether making a selection in the associated menu is required. */
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** ID of the associated form element. This prop is never valid to pass into MenuLabel
|
|
11
|
+
* because MenuLabel passes its own htmlFor prop to the underlying Label component.*/
|
|
12
|
+
htmlFor?: never;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menulabel
|
|
17
|
+
*
|
|
18
|
+
* @description MenuLabel extends Label to create an accessible label for a Menu's toggle element.
|
|
19
|
+
* A MenuLabel will automatically be associated with the corresponding menuToggleElement,
|
|
20
|
+
* so an `htmlFor` prop is not necessary or allowed.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menutogglebutton MenuToggleButton}
|
|
23
|
+
* @see {@link https://seeds.sproutsocial.com/components/label/ Label}
|
|
24
|
+
*/
|
|
25
|
+
export const MenuLabel = ({
|
|
26
|
+
children,
|
|
27
|
+
required = false,
|
|
28
|
+
...rest
|
|
29
|
+
}: TypeMenuLabelProps) => {
|
|
6
30
|
const { getLabelProps } = useMenuToggleContext();
|
|
7
31
|
return (
|
|
8
|
-
|
|
32
|
+
// This fallback id should never be used, but it is here to satisfy TypeScript since getLabelProps could be undefined.
|
|
33
|
+
<Label
|
|
34
|
+
htmlFor="fallback_menu_label"
|
|
35
|
+
required={required}
|
|
36
|
+
{...getLabelProps?.()}
|
|
37
|
+
{...rest}
|
|
38
|
+
>
|
|
9
39
|
{children}
|
|
10
40
|
</Label>
|
|
11
41
|
);
|
|
@@ -18,10 +18,16 @@ import {
|
|
|
18
18
|
import { MOTION_DURATION_FAST } from "@sproutsocial/seeds-motion/unitless";
|
|
19
19
|
|
|
20
20
|
export interface TypeMenuRootOwnProps {
|
|
21
|
+
/** The element that is or contains an element that will toggle the menu when clicked.
|
|
22
|
+
* May contain labels, buttons, inputs or other content as needed. */
|
|
21
23
|
menuToggleElement: React.ReactElement<any>;
|
|
24
|
+
/** Props to pass through to the underlying Popout.
|
|
25
|
+
* Any Popout prop is valid except those explicitly omitted. */
|
|
22
26
|
popoutProps?: Partial<
|
|
23
27
|
Omit<TypePopoutProps, "isOpen" | "setIsOpen" | "content" | "children">
|
|
24
28
|
>;
|
|
29
|
+
/** The width of the Popout content.
|
|
30
|
+
* Defaults to 200px or the width of the toggle element, whichever is greater.*/
|
|
25
31
|
width?: TypePopoutProps["width"];
|
|
26
32
|
}
|
|
27
33
|
export interface TypeMenuRootProps
|
|
@@ -108,9 +114,7 @@ export const MenuPopout = ({
|
|
|
108
114
|
};
|
|
109
115
|
|
|
110
116
|
/**
|
|
111
|
-
* @
|
|
112
|
-
*
|
|
113
|
-
* @description MenuRoot is a utility component used to handle {@link https://github.com/sproutsocial/seeds/blob/dev/seeds-react/seeds-react-menu/src/MenuContext.tsx | MenuContext}. This component should rarely, if ever, be used directly unless building a custom menu type.
|
|
117
|
+
* @description MenuRoot is a utility component used to handle React Context for our Menus. This component should rarely, if ever, be used directly unless building a custom menu type.
|
|
114
118
|
*/
|
|
115
119
|
|
|
116
120
|
export const MenuRoot = ({
|
|
@@ -146,13 +150,6 @@ export const MenuRoot = ({
|
|
|
146
150
|
}
|
|
147
151
|
}, [width, toggleElementRef.current?.offsetWidth]);
|
|
148
152
|
|
|
149
|
-
useEffect(() => {
|
|
150
|
-
if (!inputValue) return;
|
|
151
|
-
if (items && hiddenItemsCount >= items.length && isOpen) {
|
|
152
|
-
closeMenu?.();
|
|
153
|
-
}
|
|
154
|
-
}, [hiddenItemsCount, items?.length, isOpen, inputValue]);
|
|
155
|
-
|
|
156
153
|
const menuContext = useMenu(contextProps);
|
|
157
154
|
|
|
158
155
|
// Hack to suppress error: "downshift: You forgot to call the getMenuProps getter function on your component / element."
|
|
@@ -189,17 +186,3 @@ export const MenuRoot = ({
|
|
|
189
186
|
</MenuPopout>
|
|
190
187
|
);
|
|
191
188
|
};
|
|
192
|
-
|
|
193
|
-
export const MenuRootNoPopout = ({
|
|
194
|
-
children,
|
|
195
|
-
menuToggleElement,
|
|
196
|
-
...contextProps
|
|
197
|
-
}: TypeMenuRootProps) => {
|
|
198
|
-
const menuContext = useMenu(contextProps);
|
|
199
|
-
|
|
200
|
-
return (
|
|
201
|
-
<MenuContentProvider menuContext={menuContext}>
|
|
202
|
-
{children}
|
|
203
|
-
</MenuContentProvider>
|
|
204
|
-
);
|
|
205
|
-
};
|
|
@@ -10,23 +10,17 @@ import {
|
|
|
10
10
|
} from "../MenuContext";
|
|
11
11
|
|
|
12
12
|
export interface TypeMenuSearchInputProps extends TypeInputProps {
|
|
13
|
-
|
|
13
|
+
/** A function that can be passed to override the default filtering logic */
|
|
14
14
|
getIsItemVisible?: TypeGetIsItemVisibleFn;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
* aria-activedescendant=""
|
|
20
|
-
* aria-autocomplete="list"
|
|
21
|
-
* aria-controls="downshift-:r1:-menu"
|
|
22
|
-
* aria-expanded="true"
|
|
23
|
-
* />
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @link https://seeds.sproutsocial.com/components/menu-header/
|
|
18
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchinput
|
|
28
19
|
*
|
|
29
20
|
* @description MenuSearchInput is search input that can be added to the MenuHeader to filter the items.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuheader MenuHeader}
|
|
23
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchtokeninput MenuSearchTokenInput}
|
|
30
24
|
*/
|
|
31
25
|
export const MenuSearchInput = ({
|
|
32
26
|
getIsItemVisible,
|
|
@@ -14,14 +14,17 @@ import {
|
|
|
14
14
|
} from "../MenuTokenInput";
|
|
15
15
|
|
|
16
16
|
export interface TypeMenuSearchTokenInputProps extends TypeMenuTokenInputProps {
|
|
17
|
-
|
|
17
|
+
/** A function that can be passed to override the default filtering logic */
|
|
18
18
|
getIsItemVisible?: TypeGetIsItemVisibleFn;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @link https://seeds.sproutsocial.com/components/
|
|
22
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchtokeninput
|
|
23
23
|
*
|
|
24
|
-
* @description MenuSearchTokenInput is
|
|
24
|
+
* @description MenuSearchTokenInput is a token input that can be added to the MenuHeader to filter the items.
|
|
25
|
+
*
|
|
26
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuheader MenuHeader}
|
|
27
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchinput MenuSearchInput}
|
|
25
28
|
*/
|
|
26
29
|
export const MenuSearchTokenInput = ({
|
|
27
30
|
getIsItemVisible,
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import React, { type ReactNode } from "react";
|
|
2
1
|
import { Button, type TypeButtonProps } from "@sproutsocial/seeds-react-button";
|
|
3
2
|
import { useMenuToggleContext } from "../MenuContext";
|
|
4
3
|
|
|
5
|
-
export interface TypeMenuToggleButtonProps extends
|
|
6
|
-
children: ReactNode;
|
|
7
|
-
}
|
|
4
|
+
export interface TypeMenuToggleButtonProps extends TypeButtonProps {}
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
/**
|
|
7
|
+
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menutogglebutton
|
|
8
|
+
* @param props - MenuToggleButton accepts all the same props as Button.
|
|
9
|
+
* @description MenuToggleButton extends the Button component to create a toggle for a menu.
|
|
10
|
+
* @see {@link https://seeds.sproutsocial.com/components/button/ Button}
|
|
11
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menulabel MenuLabel}
|
|
12
|
+
*/
|
|
13
|
+
export const MenuToggleButton = (props: TypeMenuToggleButtonProps) => {
|
|
13
14
|
const { getToggleButtonProps, isListbox, getDropdownProps, ref, ariaProps } =
|
|
14
15
|
useMenuToggleContext();
|
|
15
16
|
return (
|
|
@@ -22,9 +23,7 @@ export const MenuToggleButton = ({
|
|
|
22
23
|
...ariaProps,
|
|
23
24
|
...(isListbox ? {} : { role: "button", "aria-haspopup": "menu" }),
|
|
24
25
|
})}
|
|
25
|
-
{...
|
|
26
|
-
|
|
27
|
-
{children}
|
|
28
|
-
</Button>
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
29
28
|
);
|
|
30
29
|
};
|
package/src/MenuTokenInput.tsx
CHANGED
|
@@ -26,13 +26,19 @@ const StyledTokenInputWrapper = styled.div`
|
|
|
26
26
|
`;
|
|
27
27
|
|
|
28
28
|
export interface TypeMenuTokenInputProps extends TypeTokenInputProps {
|
|
29
|
-
|
|
30
|
-
getTokenProps?: (
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
/** A function that can be passed to override the default token props */
|
|
30
|
+
getTokenProps?: (itemId: string) => Partial<TypeTokenSpec>;
|
|
31
|
+
/** Specify the menu context to use. MenuToggleContext is the default.
|
|
32
|
+
* This prop is only needed for specialized use cases. */
|
|
33
33
|
MenuContext?: typeof MenuToggleContext | typeof MenuContentContext;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* @description MenuTokenInput is the basis of the MenuSearchTokenInput and AutocompleteTokenInput components
|
|
38
|
+
*
|
|
39
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchinput MenuSearchInput}
|
|
40
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menusearchtokeninput MenuSearchTokenInput}
|
|
41
|
+
*/
|
|
36
42
|
export const MenuTokenInput = ({
|
|
37
43
|
inputProps = {},
|
|
38
44
|
getTokenProps,
|
|
@@ -10,11 +10,12 @@ import type { TypeMultiSelectMenuProps } from "./MultiSelectMenuTypes";
|
|
|
10
10
|
import type { TypeInternalItemProps } from "../types";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* @link https://seeds.sproutsocial.com/components/
|
|
13
|
+
* @link https://seeds.sproutsocial.com/components/multi-select-menu/
|
|
14
14
|
*
|
|
15
|
-
* @description A MultiSelectMenu allows multiple {@link https://
|
|
15
|
+
* @description A MultiSelectMenu allows multiple {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItems} to be selected from a list or groups of lists.
|
|
16
16
|
*
|
|
17
|
-
* @see {@link https://seeds.sproutsocial.com/components/menu
|
|
17
|
+
* @see {@link https://seeds.sproutsocial.com/components/single-select-menu/ SingleSelectMenu}
|
|
18
|
+
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menugroup MenuGroup}
|
|
18
19
|
*/
|
|
19
20
|
|
|
20
21
|
export const MultiSelectMenu = <
|