@sproutsocial/seeds-react-menu 0.5.0 → 1.0.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 (104) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +72 -0
  3. package/dist/esm/index.js +1529 -440
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/index.d.mts +275 -92
  6. package/dist/index.d.ts +275 -92
  7. package/dist/index.js +1558 -444
  8. package/dist/index.js.map +1 -1
  9. package/package.json +15 -12
  10. package/src/ActionMenu/ActionMenu.stories.tsx +422 -0
  11. package/src/ActionMenu/ActionMenu.tsx +24 -27
  12. package/src/ActionMenu/ActionMenuTypes.ts +8 -7
  13. package/src/ActionMenu/__tests__/ActionMenu.test.tsx +17 -8
  14. package/src/ActionMenu/__tests__/ActionMenu.typetest.tsx +8 -8
  15. package/src/Autocomplete/Autocomplete.stories.tsx +38 -3
  16. package/src/Autocomplete/Autocomplete.tsx +15 -80
  17. package/src/Autocomplete/AutocompleteInput.tsx +18 -27
  18. package/src/Autocomplete/AutocompleteTokenInput.tsx +50 -0
  19. package/src/Autocomplete/AutocompleteTypes.ts +25 -12
  20. package/src/Autocomplete/MultiAutocomplete.tsx +188 -0
  21. package/src/Autocomplete/SingleAutocomplete.tsx +74 -0
  22. package/src/Autocomplete/__tests__/Autocomplete.test.tsx +207 -3
  23. package/src/Autocomplete/__tests__/Autocomplete.typetest.tsx +90 -8
  24. package/src/MenuContent/MenuContent.stories.tsx +164 -0
  25. package/src/MenuContent/MenuContent.tsx +28 -12
  26. package/src/MenuContent/MenuContentTypes.ts +6 -4
  27. package/src/MenuContent/__tests__/MenuContent.typetest.tsx +8 -8
  28. package/src/MenuContext.tsx +192 -37
  29. package/src/MenuFooter/MenuFooter.stories.tsx +202 -0
  30. package/src/MenuFooter/__tests__/MenuFooter.test.tsx +16 -11
  31. package/src/MenuFooter/styles.tsx +1 -1
  32. package/src/MenuGroup/MenuGroup.feature +16 -16
  33. package/src/MenuGroup/MenuGroup.stories.tsx +248 -0
  34. package/src/MenuGroup/MenuGroup.tsx +12 -7
  35. package/src/MenuGroup/MenuGroupTypes.ts +6 -2
  36. package/src/MenuGroup/__tests__/MenuGroup.test.tsx +6 -6
  37. package/src/MenuGroup/__tests__/MenuGroup.typetest.tsx +7 -7
  38. package/src/MenuGroup/styles.tsx +4 -2
  39. package/src/MenuHeader/MenuHeader.stories.tsx +276 -0
  40. package/src/MenuHeader/MenuHeader.tsx +12 -7
  41. package/src/MenuHeader/__tests__/MenuHeader.test.tsx +23 -13
  42. package/src/MenuHeader/styles.tsx +22 -14
  43. package/src/MenuItem/MenuItem.stories.tsx +507 -0
  44. package/src/MenuItem/MenuItem.tsx +23 -9
  45. package/src/MenuItem/MenuItemTypes.ts +9 -4
  46. package/src/MenuItem/__tests__/MenuItem.test.tsx +6 -6
  47. package/src/MenuItem/styles.tsx +23 -5
  48. package/src/MenuItem/useOptionProps.tsx +11 -9
  49. package/src/MenuLabel.tsx +2 -2
  50. package/src/MenuRoot/MenuRoot.tsx +52 -24
  51. package/src/MenuRoot/__tests__/MenuRoot.test.tsx +59 -32
  52. package/src/MenuSearchInput/MenuSearchInput.tsx +85 -0
  53. package/src/MenuSearchInput/__tests__/MenuSearchInput.test.tsx +157 -0
  54. package/src/MenuSearchInput/__tests__/MenuSearchInput.typetest.tsx +31 -0
  55. package/src/MenuSearchInput/index.ts +1 -0
  56. package/src/MenuSearchTokenInput/MenuSearchTokenInput.tsx +108 -0
  57. package/src/MenuSearchTokenInput/__tests__/MenuSearchTokenInput.test.tsx +247 -0
  58. package/src/MenuSearchTokenInput/__tests__/MenuSearchTokenInput.typetest.tsx +33 -0
  59. package/src/MenuSearchTokenInput/index.ts +1 -0
  60. package/src/MenuToggleButton/MenuToggleButton.stories.tsx +72 -0
  61. package/src/{MenuToggleButton.tsx → MenuToggleButton/MenuToggleButton.tsx} +6 -5
  62. package/src/MenuToggleButton/index.ts +1 -0
  63. package/src/MenuTokenInput.tsx +104 -0
  64. package/src/MultiSelectMenu/MultiSelectMenu.stories.tsx +222 -0
  65. package/src/MultiSelectMenu/MultiSelectMenu.tsx +38 -68
  66. package/src/MultiSelectMenu/MultiSelectMenuTypes.ts +8 -6
  67. package/src/MultiSelectMenu/__tests__/MultiSelectMenu.test.tsx +46 -17
  68. package/src/MultiSelectMenu/__tests__/MultiSelectMenu.typetest.tsx +6 -6
  69. package/src/NestedMenu/NestedMenu.feature +109 -0
  70. package/src/NestedMenu/NestedMenu.stories.tsx +157 -0
  71. package/src/NestedMenu/NestedMenu.tsx +102 -0
  72. package/src/NestedMenu/NestedMenuContent.tsx +75 -0
  73. package/src/NestedMenu/NestedMenuContext.tsx +56 -0
  74. package/src/NestedMenu/NestedMenuHeader.tsx +25 -0
  75. package/src/NestedMenu/NestedMenuItem.tsx +41 -0
  76. package/src/NestedMenu/NestedMenuTypes.ts +47 -0
  77. package/src/NestedMenu/__tests__/NestedMenu.test.tsx +31 -0
  78. package/src/NestedMenu/__tests__/NestedMenu.typetest.tsx +134 -0
  79. package/src/NestedMenu/index.ts +5 -0
  80. package/src/SingleSelectMenu/SingleSelectMenu.stories.tsx +233 -0
  81. package/src/SingleSelectMenu/SingleSelectMenu.tsx +23 -26
  82. package/src/SingleSelectMenu/SingleSelectMenuTypes.ts +7 -5
  83. package/src/SingleSelectMenu/__tests__/SingleSelectMenu.typetest.tsx +6 -6
  84. package/src/SubmenuItem/SubmenuItem.feature +82 -0
  85. package/src/SubmenuItem/SubmenuItem.stories.tsx +163 -0
  86. package/src/SubmenuItem/SubmenuItem.tsx +258 -0
  87. package/src/SubmenuItem/SubmenuItemTypes.ts +24 -0
  88. package/src/SubmenuItem/__tests__/SubmenuItem.test.tsx +3 -0
  89. package/src/SubmenuItem/__tests__/SubmenuItem.typetest.tsx +112 -0
  90. package/src/SubmenuItem/index.ts +2 -0
  91. package/src/hooks/useDownshiftDefaults.tsx +117 -0
  92. package/src/hooks/useItemFiltering.tsx +68 -0
  93. package/src/hooks/useMenuChildren.tsx +205 -131
  94. package/src/index.ts +6 -0
  95. package/src/menuTestingUtils.tsx +21 -10
  96. package/src/reducers/nestedMenuStateReducer.tsx +23 -0
  97. package/src/reducers/useComboboxStateReducer.tsx +26 -8
  98. package/src/reducers/useSelectStateReducer.tsx +24 -6
  99. package/src/storybookUtilities/menu-storybook-components.tsx +5 -3
  100. package/src/types.ts +38 -30
  101. package/src/utils/downshiftDefaults.ts +9 -0
  102. package/src/utils/getMultiSelectOverrides.ts +21 -0
  103. package/src/utils/reduceReducers.ts +19 -0
  104. package/src/utils/itemToString.ts +0 -5
package/dist/esm/index.js CHANGED
@@ -95,23 +95,36 @@ var require_object_assign = __commonJS({
95
95
  });
96
96
 
97
97
  // src/MenuContext.tsx
98
- import {
99
- createContext,
100
- useMemo,
101
- useContext
102
- } from "react";
98
+ import React, { createContext, useMemo, useContext } from "react";
103
99
  import { jsx } from "react/jsx-runtime";
104
100
  var defaultMenuContext = {
105
101
  items: [],
106
- itemsMap: {}
107
- };
102
+ itemsMap: {},
103
+ isItemSelected: () => false,
104
+ getInputComponentProps: () => ({})
105
+ };
106
+ var getSelectedItemIds = (selectedItems) => selectedItems?.reduce(
107
+ (selected, item) => ({ ...selected, [item.id]: true }),
108
+ {}
109
+ );
110
+ var checkIfItemSelected = ({
111
+ id,
112
+ selectedItem,
113
+ selectedItemIds
114
+ }) => selectedItemIds ? !!selectedItemIds[id] : selectedItem?.id === id;
108
115
  var useMenu = ({
109
116
  items = [],
110
117
  isListbox = false,
111
118
  isOpen = false,
112
119
  itemsMap: itemsMapFromProps,
120
+ selectedItemIds: selectedItemIdsFromProps,
121
+ selectedItem,
122
+ selectedItems,
123
+ getInputProps,
124
+ contentRef: contentRefFromProps,
113
125
  ...rest
114
126
  } = {}) => {
127
+ const contentRef = contentRefFromProps || React.createRef();
115
128
  const menuProps = useMemo(() => ({ ...rest }), [rest]);
116
129
  const itemsMap = useMemo(
117
130
  () => itemsMapFromProps || items.reduce((map, item) => {
@@ -122,27 +135,90 @@ var useMenu = ({
122
135
  }, {}),
123
136
  [items, itemsMapFromProps]
124
137
  );
138
+ const selectedItemIds = useMemo(
139
+ () => selectedItemIdsFromProps || getSelectedItemIds(selectedItems),
140
+ [selectedItems, selectedItemIdsFromProps]
141
+ );
142
+ const isItemSelected = React.useCallback(
143
+ (id) => checkIfItemSelected({ id, selectedItem, selectedItemIds }),
144
+ [selectedItem?.id, selectedItemIds]
145
+ );
146
+ const getInputComponentProps = React.useCallback(
147
+ ({ inputProps, ...props }) => {
148
+ if (!getInputProps) return {};
149
+ const {
150
+ ["aria-activedescendant"]: activedescendant,
151
+ ["aria-autocomplete"]: autocomplete,
152
+ ["aria-controls"]: controls,
153
+ ["aria-expanded"]: expanded,
154
+ ["aria-labelledby"]: labelledby,
155
+ role,
156
+ autoComplete,
157
+ onClick,
158
+ value,
159
+ ...restProps
160
+ } = getInputProps(props);
161
+ return {
162
+ ...restProps,
163
+ inputProps: {
164
+ ["aria-activedescendant"]: activedescendant,
165
+ ["aria-autocomplete"]: autocomplete,
166
+ ["aria-controls"]: controls,
167
+ ["aria-expanded"]: expanded,
168
+ ["aria-labelledby"]: labelledby,
169
+ role,
170
+ autoComplete,
171
+ onClick,
172
+ value,
173
+ ...inputProps
174
+ }
175
+ };
176
+ },
177
+ [getInputProps]
178
+ );
125
179
  return {
126
180
  isOpen,
127
181
  isListbox,
128
182
  items,
129
183
  itemsMap,
184
+ selectedItem,
185
+ selectedItems,
186
+ selectedItemIds,
187
+ isItemSelected,
188
+ getInputProps,
189
+ getInputComponentProps,
190
+ contentRef,
130
191
  ...menuProps
131
192
  };
132
193
  };
133
- var MenuContext = createContext(defaultMenuContext);
134
- var MenuProvider = ({
194
+ var MenuToggleContext = createContext(defaultMenuContext);
195
+ var MenuToggleProvider = ({
196
+ children,
197
+ menuContext
198
+ }) => {
199
+ return /* @__PURE__ */ jsx(MenuToggleContext.Provider, { value: { ...menuContext }, children });
200
+ };
201
+ var useMenuToggleContext = () => {
202
+ const menuContextValue = useContext(MenuToggleContext);
203
+ if (menuContextValue === null) {
204
+ throw new Error(
205
+ "useMenuToggleContext must be used within a <MenuToggleContext.Provider />"
206
+ );
207
+ }
208
+ return menuContextValue;
209
+ };
210
+ var MenuContentContext = createContext(defaultMenuContext);
211
+ var MenuContentProvider = ({
135
212
  children,
136
- menuProps
213
+ menuContext
137
214
  }) => {
138
- const filterContext = useMenu(menuProps);
139
- return /* @__PURE__ */ jsx(MenuContext.Provider, { value: { ...filterContext }, children });
215
+ return /* @__PURE__ */ jsx(MenuContentContext.Provider, { value: { ...menuContext }, children });
140
216
  };
141
- var useMenuContext = () => {
142
- const menuContextValue = useContext(MenuContext);
217
+ var useMenuContentContext = () => {
218
+ const menuContextValue = useContext(MenuContentContext);
143
219
  if (menuContextValue === null) {
144
220
  throw new Error(
145
- "useMenuContext must be used within a <MenuContext.Provider />"
221
+ "useMenuContentContext must be used within a <MenuContentContext.Provider />"
146
222
  );
147
223
  }
148
224
  return menuContextValue;
@@ -1692,6 +1768,12 @@ var highlightedStyles = css4`
1692
1768
  color: ${({ theme: theme2 }) => theme2.colors.text.body};
1693
1769
  text-decoration: none;
1694
1770
  `;
1771
+ var activeStyles = css4`
1772
+ border: 1px solid ${({ theme: theme2 }) => theme2.colors.listItem.border.base};
1773
+ background-color: ${({ theme: theme2 }) => theme2.colors.menuItem.background.active};
1774
+ color: ${({ theme: theme2 }) => theme2.colors.text.body};
1775
+ text-decoration: none;
1776
+ `;
1695
1777
  var MenuItemContainer = styled.li`
1696
1778
  box-sizing: border-box;
1697
1779
  list-style-type: none;
@@ -1706,7 +1788,7 @@ var MenuItemContainer = styled.li`
1706
1788
  margin-bottom: ${({ theme: theme2 }) => theme2.space[300]};
1707
1789
  }
1708
1790
  `;
1709
- var StyledMenuItem = styled.div`
1791
+ var StyledMenuItem = styled.button`
1710
1792
  display: block;
1711
1793
  box-sizing: border-box;
1712
1794
  width: 100%;
@@ -1745,10 +1827,12 @@ var StyledMenuItem = styled.div`
1745
1827
  ${focusRing}
1746
1828
  }
1747
1829
 
1830
+ /* Active */
1831
+ ${({ $active }) => $active && activeStyles}
1832
+
1748
1833
  /* Pressed state*/
1749
1834
  &:active {
1750
- background-color: ${({ theme: theme2 }) => theme2.colors.listItem.background.active};
1751
- color: ${({ theme: theme2 }) => theme2.colors.text.inverse};
1835
+ ${activeStyles}
1752
1836
  }
1753
1837
 
1754
1838
  &[aria-disabled="true"] {
@@ -1769,12 +1853,17 @@ var MenuItemRow = styled.div`
1769
1853
  pointer-events: none;
1770
1854
  `;
1771
1855
  var MenuItemAction = styled.div`
1772
- margin-right: ${({ theme: theme2 }) => theme2.space[300]};
1773
1856
  display: flex;
1774
1857
  align-items: center;
1775
1858
  justify-content: center;
1776
1859
  flex-shrink: 0;
1777
1860
  `;
1861
+ var MenuItemActionLeft = styled(MenuItemAction)`
1862
+ margin-right: ${({ theme: theme2 }) => theme2.space[300]};
1863
+ `;
1864
+ var MenuItemActionRight = styled(MenuItemAction)`
1865
+ margin-left: ${({ theme: theme2 }) => theme2.space[300]};
1866
+ `;
1778
1867
  var MenuItemText = styled.div`
1779
1868
  word-break: break-word;
1780
1869
  flex-grow: 1;
@@ -1782,7 +1871,7 @@ var MenuItemText = styled.div`
1782
1871
  `;
1783
1872
 
1784
1873
  // src/MenuItem/useOptionProps.tsx
1785
- import { useContext as useContext2, useMemo as useMemo2 } from "react";
1874
+ import { useMemo as useMemo2 } from "react";
1786
1875
  import { Icon } from "@sproutsocial/seeds-react-icon";
1787
1876
  import { Checkbox } from "@sproutsocial/seeds-react-checkbox";
1788
1877
  import { Switch } from "@sproutsocial/seeds-react-switch";
@@ -1805,6 +1894,7 @@ var SelectionIndicator = ({
1805
1894
  return /* @__PURE__ */ jsx2(
1806
1895
  Checkbox,
1807
1896
  {
1897
+ tabIndex: -1,
1808
1898
  onChange: () => {
1809
1899
  },
1810
1900
  checked: selected,
@@ -1816,6 +1906,7 @@ var SelectionIndicator = ({
1816
1906
  return /* @__PURE__ */ jsx2(
1817
1907
  Switch,
1818
1908
  {
1909
+ tabIndex: -1,
1819
1910
  onClick: inputStub,
1820
1911
  checked: !!selected,
1821
1912
  "aria-labelledby": labeledBy,
@@ -1826,6 +1917,7 @@ var SelectionIndicator = ({
1826
1917
  return /* @__PURE__ */ jsx2(
1827
1918
  Radio,
1828
1919
  {
1920
+ tabIndex: -1,
1829
1921
  checked: selected,
1830
1922
  id: `MenuItem-${inputType}-${id}`,
1831
1923
  name: `MenuItem-${inputType}`,
@@ -1849,17 +1941,17 @@ var useOptionProps = ({
1849
1941
  inputLabelId,
1850
1942
  ...props
1851
1943
  }) => {
1852
- const { selectedItem, selectedItems, isListbox } = useContext2(MenuContext);
1944
+ const { selectedItem, selectedItemIds, isListbox, isItemSelected } = useMenuContentContext();
1853
1945
  const selected = useMemo2(
1854
- () => selectedItem?.id === id || !!selectedItems?.find((item) => item?.id === id),
1855
- [selectedItem, selectedItems]
1946
+ () => isItemSelected(id),
1947
+ [selectedItem?.id, selectedItemIds]
1856
1948
  );
1857
1949
  const label = inputLabelId || `menu-item-child-${id}`;
1858
1950
  return isListbox ? {
1859
1951
  active: selected,
1860
1952
  ["aria-selected"]: selected,
1861
1953
  children: /* @__PURE__ */ jsxs(MenuItemRow, { children: [
1862
- /* @__PURE__ */ jsx2(MenuItemAction, { children: /* @__PURE__ */ jsx2(
1954
+ /* @__PURE__ */ jsx2(MenuItemActionLeft, { children: /* @__PURE__ */ jsx2(
1863
1955
  SelectionIndicator,
1864
1956
  {
1865
1957
  id,
@@ -1882,12 +1974,19 @@ var MenuItem = ({
1882
1974
  onClick,
1883
1975
  onKeyDown,
1884
1976
  disabled: disabled2 = false,
1885
- ref,
1977
+ active,
1978
+ innerRef,
1886
1979
  href,
1887
1980
  color: color2,
1888
1981
  ...props
1889
1982
  }) => {
1890
- const { getItemProps, itemsMap, highlightedIndex, isListbox } = useMenuContext();
1983
+ const {
1984
+ getItemProps,
1985
+ itemsMap,
1986
+ highlightedIndex,
1987
+ isListbox,
1988
+ hiddenItemsMap = {}
1989
+ } = useMenuContentContext();
1891
1990
  const { ...optionProps } = useOptionProps({
1892
1991
  id,
1893
1992
  children,
@@ -1895,28 +1994,32 @@ var MenuItem = ({
1895
1994
  });
1896
1995
  const item = itemsMap[id] || { index: 0, id };
1897
1996
  const highlighted = highlightedIndex === item?.index;
1898
- return item.hidden ? /* @__PURE__ */ jsx3(Fragment, {}) : /* @__PURE__ */ jsx3(MenuItemContainer, { role: "none", children: /* @__PURE__ */ jsx3(
1997
+ return hiddenItemsMap[item.id] ? /* @__PURE__ */ jsx3(Fragment, {}) : /* @__PURE__ */ jsx3(MenuItemContainer, { role: "none", children: /* @__PURE__ */ jsx3(
1899
1998
  StyledMenuItem,
1900
1999
  {
1901
2000
  id,
1902
2001
  $highlighted: highlighted,
2002
+ $active: active,
1903
2003
  ...getItemProps?.({
1904
2004
  ...isListbox ? {} : { role: "menuitem" },
1905
2005
  item,
1906
2006
  index: item.index,
1907
- // This prop no longer supported in downshift
2007
+ // The disabled prop no longer supported in downshift. Use isItemDisabled instead.
1908
2008
  // disabled,
1909
2009
  onClick,
1910
- onKeyDown
2010
+ onKeyDown,
2011
+ ref: innerRef
1911
2012
  }),
1912
2013
  as: isListbox ? void 0 : href ? "a" : "button",
1913
2014
  href,
1914
2015
  children,
2016
+ tabIndex: -1,
1915
2017
  ...optionProps,
1916
2018
  ...props
1917
2019
  }
1918
2020
  ) });
1919
2021
  };
2022
+ MenuItem.__MENU_PRIMITIVE_TYPE = "MenuItem";
1920
2023
 
1921
2024
  // src/MenuItem/MenuItemTypes.ts
1922
2025
  var INPUT_TYPES = {
@@ -1954,34 +2057,42 @@ var MenuTitleText = styled2.h3`
1954
2057
  color: ${({ theme: theme2 }) => theme2.colors.text.headline};
1955
2058
  font-weight: ${({ theme: theme2 }) => theme2.fontWeights.bold};
1956
2059
  margin: 0px;
1957
- flex-grow: 2;
1958
- justify-self: start;
2060
+ flex-grow: 1;
1959
2061
 
1960
2062
  ${({ theme: theme2 }) => theme2.typography[200]}
1961
2063
 
1962
2064
  ${({ $leftAction, theme: theme2 }) => $leftAction && `
1963
- padding-left: ${theme2.space[350]};
1964
- `}
2065
+ padding-left: ${theme2.space[350]};
2066
+ `}
1965
2067
  `;
1966
2068
  var MenuChildrenContainer = styled2.div`
1967
2069
  grid-column: 1 / -1;
1968
2070
  margin-top: ${({ theme: theme2 }) => theme2.space[300]};
2071
+
2072
+ &:first-child {
2073
+ margin-top: 0;
2074
+ }
1969
2075
  `;
1970
2076
  var MenuHeaderFeatures = styled2.div`
1971
2077
  display: flex;
2078
+ align-items: center;
2079
+ justify-content: space-between;
2080
+ width: 100%;
1972
2081
 
1973
- > a {
1974
- white-space: nowrap;
1975
- }
1976
-
1977
- &:first-child {
1978
- flex-grow: 1;
1979
- justify-self: start;
2082
+ .right-action {
2083
+ margin-left: auto; /* Pushes the right action to the right */
2084
+ display: flex;
2085
+ justify-content: flex-end;
2086
+ flex-shrink: 0; /* Prevents it from shrinking */
2087
+ max-width: 40%; /* Prevents it from taking too much space */
2088
+ text-align: right;
1980
2089
  }
1981
2090
 
1982
- &:last-child {
1983
- flex-grow: 1;
1984
- justify-self: end;
2091
+ > a,
2092
+ > button {
2093
+ display: flex;
2094
+ align-items: center;
2095
+ word-break: break-word;
1985
2096
  }
1986
2097
  `;
1987
2098
 
@@ -1994,11 +2105,12 @@ var MenuHeader = ({
1994
2105
  rightAction,
1995
2106
  ...rest
1996
2107
  }) => {
2108
+ const showTopRow = title || leftAction || rightAction;
1997
2109
  return /* @__PURE__ */ jsx4(Fragment2, { children: /* @__PURE__ */ jsxs2(MenuHeaderContainer, { $leftAction: !!leftAction, ...rest, children: [
1998
- /* @__PURE__ */ jsxs2(MenuHeaderFeatures, { $leftAction: !!leftAction, children: [
2110
+ showTopRow && /* @__PURE__ */ jsxs2(MenuHeaderFeatures, { $leftAction: !!leftAction, children: [
1999
2111
  leftAction && leftAction,
2000
2112
  title && /* @__PURE__ */ jsx4(MenuTitleText, { $leftAction: !!leftAction, children: title }),
2001
- rightAction && rightAction
2113
+ rightAction && /* @__PURE__ */ jsx4("div", { className: "right-action", children: rightAction })
2002
2114
  ] }),
2003
2115
  children && /* @__PURE__ */ jsx4(MenuChildrenContainer, { children })
2004
2116
  ] }) });
@@ -2031,164 +2143,194 @@ var walkAllChildren = (children, callback) => {
2031
2143
  });
2032
2144
  };
2033
2145
  var getComponentName = (element) => {
2034
- if (element && typeof element === "object" && "type" in element && typeof element.type !== "string" && typeof element.type.name === "string") {
2035
- return element.type.name;
2146
+ if (element && typeof element === "object" && "type" in element && (typeof element.type === "function" || typeof element.type === "object") && "__MENU_PRIMITIVE_TYPE" in element.type && typeof element.type.__MENU_PRIMITIVE_TYPE === "string") {
2147
+ return element.type.__MENU_PRIMITIVE_TYPE;
2148
+ }
2149
+ };
2150
+ var addMenuItem = ({
2151
+ itemProps,
2152
+ allMenuItems,
2153
+ menuItemsMap
2154
+ }) => {
2155
+ const item = {
2156
+ ...itemProps,
2157
+ index: allMenuItems.length
2158
+ };
2159
+ allMenuItems.push(item);
2160
+ menuItemsMap[`${item.id}`] = item;
2161
+ };
2162
+ var addItemsFromGroup = ({
2163
+ groupElement: menuGroup,
2164
+ allMenuItems,
2165
+ menuItemsMap
2166
+ }) => {
2167
+ const menuItems = menuGroup.props.menuItems;
2168
+ if (menuItems) {
2169
+ menuItems.forEach((menuItem) => {
2170
+ addMenuItem({
2171
+ itemProps: {
2172
+ id: menuItem.id,
2173
+ disabled: menuItem.disabled,
2174
+ menuItemProps: menuItem,
2175
+ menuGroupProps: menuGroup.props
2176
+ },
2177
+ allMenuItems,
2178
+ menuItemsMap
2179
+ });
2180
+ });
2181
+ } else if (menuGroup.props.children) {
2182
+ let children = menuGroup.props.children;
2183
+ if (!Array.isArray(children)) {
2184
+ children = [children];
2185
+ }
2186
+ children.forEach((menuItem) => {
2187
+ addMenuItem({
2188
+ itemProps: {
2189
+ id: menuItem.props.id,
2190
+ disabled: menuItem.props.disabled,
2191
+ menuItemProps: menuItem.props,
2192
+ menuGroupProps: menuGroup.props
2193
+ },
2194
+ allMenuItems,
2195
+ menuItemsMap
2196
+ });
2197
+ });
2198
+ }
2199
+ };
2200
+ var addItemsFromContent = ({
2201
+ contentElement: menuContent,
2202
+ allMenuItems,
2203
+ menuItemsMap
2204
+ }) => {
2205
+ if (!("menuItems" in menuContent.props)) return;
2206
+ if (menuContent.props.menuItems) {
2207
+ menuContent.props.menuItems.forEach((menuItem) => {
2208
+ addMenuItem({
2209
+ itemProps: {
2210
+ id: menuItem.id,
2211
+ disabled: menuItem.disabled,
2212
+ menuItemProps: menuItem
2213
+ },
2214
+ allMenuItems,
2215
+ menuItemsMap
2216
+ });
2217
+ });
2036
2218
  }
2037
2219
  };
2038
- var getAllMenuItems = (children) => {
2039
- const orderedElements = [];
2220
+ var setMenuItemsFromChildren = ({
2221
+ children,
2222
+ allMenuItems,
2223
+ menuItemsMap
2224
+ }) => {
2040
2225
  walkAllChildren(children, (element) => {
2041
2226
  switch (getComponentName(element)) {
2042
2227
  case "MenuItem":
2043
- orderedElements.push({
2044
- type: "item",
2045
- element
2228
+ const menuItem = element;
2229
+ if (menuItemsMap[`${menuItem.props.id}`]) return;
2230
+ addMenuItem({
2231
+ itemProps: {
2232
+ id: menuItem.props.id,
2233
+ disabled: menuItem.props.disabled,
2234
+ menuItemProps: menuItem.props
2235
+ },
2236
+ allMenuItems,
2237
+ menuItemsMap
2046
2238
  });
2047
2239
  break;
2048
2240
  case "MenuGroup":
2049
- orderedElements.push({
2050
- type: "group",
2051
- element
2241
+ addItemsFromGroup({
2242
+ // Cast element to the TypeMenuGroupElement since we know it's a group and is needed for addItemsFromGroup.
2243
+ groupElement: element,
2244
+ allMenuItems,
2245
+ menuItemsMap
2052
2246
  });
2053
2247
  break;
2054
2248
  case "MenuContent":
2055
- orderedElements.push({
2056
- type: "content",
2057
- element
2249
+ addItemsFromContent({
2250
+ // Cast element to the TypeMenuContentElement since we know it's a content and is needed for addItemsFromContent.
2251
+ contentElement: element,
2252
+ allMenuItems,
2253
+ menuItemsMap
2058
2254
  });
2059
2255
  break;
2060
2256
  default:
2061
2257
  break;
2062
2258
  }
2063
2259
  });
2064
- return { orderedElements };
2065
2260
  };
2066
2261
  var mapMenuItems = ({
2067
- items,
2068
- MenuItemComponent
2262
+ menuItems,
2263
+ MenuItemComponent = MenuItem
2069
2264
  }) => {
2070
- return /* @__PURE__ */ jsx5(Fragment3, { children: items.map((menuItem) => /* @__PURE__ */ jsx5(MenuItemComponent, { ...menuItem }, menuItem.id)) });
2265
+ return /* @__PURE__ */ jsx5(Fragment3, { children: menuItems.map((menuItemProps) => /* @__PURE__ */ jsx5(MenuItemComponent, { ...menuItemProps }, menuItemProps.id)) });
2071
2266
  };
2267
+ var getChildrenFromMenuItems = ({
2268
+ menuItems,
2269
+ MenuItemComponent
2270
+ }) => /* @__PURE__ */ jsx5(MenuContent, { menuItems, MenuItemComponent });
2072
2271
  var useMenuChildren = ({
2073
2272
  children: childrenProp,
2074
- items,
2075
- MenuItemComponent = MenuItem
2273
+ menuItems,
2274
+ MenuItemComponent
2076
2275
  }) => {
2077
2276
  const { allMenuItems, menuItemsMap, children } = useMemo3(() => {
2078
2277
  let children2 = /* @__PURE__ */ jsx5(Fragment3, {});
2079
- let index = 0;
2080
2278
  const menuItemsMap2 = {};
2081
2279
  const allMenuItems2 = [];
2082
- if (items && items.length) {
2083
- items.forEach((menuItem) => {
2084
- const item = {
2085
- id: menuItem.id,
2086
- index: index++,
2087
- disabled: menuItem.disabled,
2088
- menuItemProps: menuItem
2089
- };
2090
- allMenuItems2.push(item);
2091
- menuItemsMap2[`${item.id}`] = item;
2280
+ if (menuItems && menuItems.length) {
2281
+ menuItems.forEach((menuItem) => {
2282
+ addMenuItem({ itemProps: menuItem, allMenuItems: allMenuItems2, menuItemsMap: menuItemsMap2 });
2092
2283
  });
2093
- children2 = /* @__PURE__ */ jsx5(MenuContent, { children: mapMenuItems({ items, MenuItemComponent }) });
2284
+ children2 = getChildrenFromMenuItems({ menuItems, MenuItemComponent });
2094
2285
  } else if (childrenProp) {
2095
2286
  children2 = childrenProp;
2096
- const { orderedElements } = getAllMenuItems(childrenProp);
2097
- orderedElements.forEach(({ type, element }) => {
2098
- if (type === "content") {
2099
- const menuContent = element;
2100
- const items2 = menuContent.props.items;
2101
- if (items2) {
2102
- items2.forEach((menuItem) => {
2103
- const item = {
2104
- id: menuItem.id,
2105
- index: index++,
2106
- children: menuItem.children,
2107
- disabled: menuItem.disabled,
2108
- menuItemProps: menuItem
2109
- };
2110
- allMenuItems2.push(item);
2111
- menuItemsMap2[`${item.id}`] = item;
2112
- });
2113
- }
2114
- } else if (type === "group") {
2115
- const menuGroup = element;
2116
- const items2 = menuGroup.props.items;
2117
- if (items2) {
2118
- items2.forEach((menuItem) => {
2119
- const item = {
2120
- id: menuItem.id,
2121
- index: index++,
2122
- children: menuItem.children,
2123
- disabled: menuItem.disabled,
2124
- menuItemProps: menuItem,
2125
- menuGroupProps: element.props
2126
- };
2127
- allMenuItems2.push(item);
2128
- menuItemsMap2[`${item.id}`] = item;
2129
- });
2130
- } else if (menuGroup.props.children) {
2131
- let children3 = menuGroup.props.children;
2132
- if (!Array.isArray(children3)) {
2133
- children3 = [children3];
2134
- }
2135
- children3.forEach((menuItem) => {
2136
- const item = {
2137
- id: menuItem.props.id,
2138
- index: index++,
2139
- children: menuItem.props.children,
2140
- disabled: menuItem.props.disabled,
2141
- menuItemProps: menuItem.props,
2142
- menuGroupProps: element.props
2143
- };
2144
- allMenuItems2.push(item);
2145
- menuItemsMap2[`${item.id}`] = item;
2146
- });
2147
- }
2148
- } else {
2149
- if (menuItemsMap2[`${element.props.id}`]) return;
2150
- const menuItem = element;
2151
- const item = {
2152
- id: menuItem.props.id,
2153
- index: index++,
2154
- disabled: menuItem.props.disabled,
2155
- menuItemProps: menuItem.props
2156
- };
2157
- allMenuItems2.push(item);
2158
- menuItemsMap2[`${item.id}`] = item;
2159
- }
2287
+ setMenuItemsFromChildren({
2288
+ children: childrenProp,
2289
+ allMenuItems: allMenuItems2,
2290
+ menuItemsMap: menuItemsMap2
2160
2291
  });
2161
2292
  }
2162
2293
  return { allMenuItems: allMenuItems2, menuItemsMap: menuItemsMap2, children: children2 };
2163
- }, [childrenProp, items, MenuItemComponent]);
2294
+ }, [childrenProp, menuItems, MenuItemComponent]);
2164
2295
  return { allMenuItems, menuItemsMap, children };
2165
2296
  };
2166
2297
 
2167
2298
  // src/MenuContent/MenuContent.tsx
2299
+ import { useCallback } from "react";
2168
2300
  import { jsx as jsx6 } from "react/jsx-runtime";
2169
2301
  var MenuContent = ({
2170
2302
  id = "menu_content",
2171
2303
  children: childrenProp,
2172
- items,
2173
- MenuItemComponent = MenuItem,
2304
+ menuItems,
2305
+ MenuItemComponent,
2306
+ onKeyDown,
2307
+ innerRef = null,
2174
2308
  ...rest
2175
2309
  }) => {
2176
- const { getToggleButtonProps, getMenuProps, isListbox } = useMenuContext();
2177
- const children = childrenProp || !items || !items.length ? childrenProp : mapMenuItems({ items, MenuItemComponent });
2310
+ const { getToggleButtonProps, getMenuProps, isListbox } = useMenuContentContext();
2311
+ const toggleButtonProps = getToggleButtonProps?.();
2312
+ const children = childrenProp || !menuItems || !menuItems.length ? childrenProp : mapMenuItems({ menuItems, MenuItemComponent });
2178
2313
  if (!children) {
2179
2314
  return null;
2180
2315
  }
2316
+ const handleKeyDown = useCallback(
2317
+ (e) => {
2318
+ toggleButtonProps?.["onKeyDown"]?.(e);
2319
+ onKeyDown?.(e);
2320
+ },
2321
+ [onKeyDown, toggleButtonProps?.["onKeyDown"]]
2322
+ );
2181
2323
  return /* @__PURE__ */ jsx6(
2182
2324
  StyledMenuContent,
2183
2325
  {
2184
2326
  autoFocus: true,
2185
2327
  id,
2186
2328
  tabIndex: 0,
2187
- onKeyDown: getToggleButtonProps?.()["onKeyDown"] || void 0,
2188
- "aria-activedescendant": getToggleButtonProps?.()["aria-activedescendant"],
2329
+ onKeyDown: handleKeyDown,
2330
+ "aria-activedescendant": toggleButtonProps?.["aria-activedescendant"],
2189
2331
  ...getMenuProps?.(
2190
2332
  {
2191
- ...isListbox ? {} : { role: "menu" }
2333
+ ...isListbox ? { ref: innerRef } : { ref: innerRef, role: "menu" }
2192
2334
  },
2193
2335
  // Suppress ref error for now
2194
2336
  { suppressRefError: true }
@@ -2198,6 +2340,7 @@ var MenuContent = ({
2198
2340
  }
2199
2341
  );
2200
2342
  };
2343
+ MenuContent.__MENU_PRIMITIVE_TYPE = "MenuContent";
2201
2344
 
2202
2345
  // src/MenuFooter/MenuFooter.tsx
2203
2346
  import "react";
@@ -2206,7 +2349,7 @@ import "react";
2206
2349
  import styled4 from "styled-components";
2207
2350
  import { Box as Box2 } from "@sproutsocial/seeds-react-box";
2208
2351
  var StyledMenuFooterBox = styled4(Box2)`
2209
- padding: ${(p) => p.theme.space[400]};
2352
+ padding: ${({ theme: theme2 }) => theme2.space[350]} ${({ theme: theme2 }) => theme2.space[400]};
2210
2353
  border-top: 1px solid ${(p) => p.theme.colors.container.border.base};
2211
2354
  `;
2212
2355
 
@@ -2354,6 +2497,7 @@ var StyledMenuGroup = styled6.li`
2354
2497
  ${space}
2355
2498
  `;
2356
2499
  var StyledTitle = styled6(index_default.SmallSubHeadline)`
2500
+ font-size: ${({ theme: theme2 }) => theme2.typography[100].fontSize};
2357
2501
  margin: ${({ theme: theme2 }) => theme2.space[400]} ${({ theme: theme2 }) => theme2.space[400]}
2358
2502
  0px ${({ theme: theme2 }) => theme2.space[400]};
2359
2503
  `;
@@ -2371,12 +2515,12 @@ var MenuGroup = ({
2371
2515
  color: color2,
2372
2516
  isSingleSelect,
2373
2517
  id,
2374
- items,
2375
- MenuItemComponent = MenuItem,
2518
+ menuItems,
2519
+ MenuItemComponent,
2376
2520
  ...rest
2377
2521
  }) => {
2378
2522
  const titleId = `menu-group-title-${Math.random().toString(36).slice(2, 11)}`;
2379
- const children = childrenProp || !items || !items.length ? childrenProp : mapMenuItems({ items, MenuItemComponent });
2523
+ const children = childrenProp || !menuItems || !menuItems.length ? childrenProp : mapMenuItems({ menuItems, MenuItemComponent });
2380
2524
  if (!children) {
2381
2525
  return null;
2382
2526
  }
@@ -2396,9 +2540,10 @@ var MenuGroup = ({
2396
2540
  }
2397
2541
  );
2398
2542
  };
2543
+ MenuGroup.__MENU_PRIMITIVE_TYPE = "MenuGroup";
2399
2544
 
2400
2545
  // src/MenuRoot/MenuRoot.tsx
2401
- import { useCallback } from "react";
2546
+ import { useCallback as useCallback2, useEffect } from "react";
2402
2547
  import styled7 from "styled-components";
2403
2548
  import { Popout } from "@sproutsocial/seeds-react-popout";
2404
2549
  import { jsx as jsx10 } from "react/jsx-runtime";
@@ -2410,24 +2555,39 @@ var CustomPopoutContent = styled7(Popout.Content)`
2410
2555
  var MenuRoot = ({
2411
2556
  children,
2412
2557
  menuToggleElement,
2413
- popoutProps: { focusLockProps, ...popoutProps } = {},
2558
+ popoutProps: { placement = "bottom", focusLockProps, ...popoutProps } = {},
2414
2559
  width: width2 = "300px",
2415
2560
  ...contextProps
2416
2561
  }) => {
2417
- const { isOpen, openMenu, closeMenu } = contextProps;
2418
- const setIsOpen = useCallback(
2562
+ const {
2563
+ isOpen,
2564
+ openMenu,
2565
+ closeMenu,
2566
+ inputValue,
2567
+ hiddenItemsCount = 0,
2568
+ items
2569
+ } = contextProps;
2570
+ const setIsOpen = useCallback2(
2419
2571
  (newIsOpen) => {
2420
2572
  newIsOpen ? openMenu?.() : closeMenu?.();
2421
2573
  },
2422
2574
  [openMenu, closeMenu]
2423
2575
  );
2424
- return /* @__PURE__ */ jsx10(MenuProvider, { menuProps: contextProps, children: /* @__PURE__ */ jsx10(
2576
+ useEffect(() => {
2577
+ if (!inputValue) return;
2578
+ if (items && hiddenItemsCount >= items.length && isOpen) {
2579
+ closeMenu?.();
2580
+ }
2581
+ }, [hiddenItemsCount, items?.length, isOpen, inputValue]);
2582
+ const menuContext = useMenu(contextProps);
2583
+ return /* @__PURE__ */ jsx10(
2425
2584
  Popout,
2426
2585
  {
2427
2586
  menuPopout: true,
2587
+ placement,
2428
2588
  isOpen: !!isOpen,
2429
2589
  setIsOpen,
2430
- content: /* @__PURE__ */ jsx10(CustomPopoutContent, { width: width2, children }),
2590
+ content: /* @__PURE__ */ jsx10(MenuContentProvider, { menuContext, children: /* @__PURE__ */ jsx10(CustomPopoutContent, { width: width2, children }) }),
2431
2591
  focusLockProps: {
2432
2592
  // correct jerking motion when scrolling while the Popout is open
2433
2593
  // returnFocus: false,
@@ -2436,9 +2596,9 @@ var MenuRoot = ({
2436
2596
  },
2437
2597
  disableWrapperAria: true,
2438
2598
  ...popoutProps,
2439
- children: menuToggleElement
2599
+ children: (toggleProps) => /* @__PURE__ */ jsx10(MenuToggleProvider, { menuContext: { ...menuContext, ...toggleProps }, children: menuToggleElement })
2440
2600
  }
2441
- ) });
2601
+ );
2442
2602
  };
2443
2603
 
2444
2604
  // src/MenuLabel.tsx
@@ -2446,27 +2606,28 @@ import "react";
2446
2606
  import { Label } from "@sproutsocial/seeds-react-label";
2447
2607
  import { jsx as jsx11 } from "react/jsx-runtime";
2448
2608
  var MenuLabel = ({ children, ...rest }) => {
2449
- const { getLabelProps } = useMenuContext();
2609
+ const { getLabelProps } = useMenuToggleContext();
2450
2610
  return /* @__PURE__ */ jsx11(Label, { htmlFor: "fallback_menu_label", ...getLabelProps?.(), ...rest, children });
2451
2611
  };
2452
2612
 
2453
- // src/MenuToggleButton.tsx
2454
- import { useContext as useContext3 } from "react";
2613
+ // src/MenuToggleButton/MenuToggleButton.tsx
2614
+ import "react";
2455
2615
  import { Button } from "@sproutsocial/seeds-react-button";
2456
2616
  import { jsx as jsx12 } from "react/jsx-runtime";
2457
2617
  var MenuToggleButton = ({
2458
2618
  children,
2459
2619
  ...rest
2460
2620
  }) => {
2461
- const { getToggleButtonProps, isListbox, getDropdownProps } = useContext3(MenuContext);
2621
+ const { getToggleButtonProps, isListbox, getDropdownProps, ref, ariaProps } = useMenuToggleContext();
2462
2622
  return /* @__PURE__ */ jsx12(
2463
2623
  Button,
2464
2624
  {
2465
2625
  appearance: "secondary",
2466
2626
  ...getToggleButtonProps?.({
2467
2627
  // Decide if we want the preventKeyAction stuff. Maybe create a prop to allow for this to be overriden.
2468
- ...getDropdownProps?.({ preventKeyAction: true }),
2628
+ ...getDropdownProps?.({ ref, preventKeyAction: true }) || { ref },
2469
2629
  refKey: "innerRef",
2630
+ ...ariaProps,
2470
2631
  ...isListbox ? {} : { role: "button", "aria-haspopup": "menu" }
2471
2632
  }),
2472
2633
  ...rest,
@@ -2475,216 +2636,774 @@ var MenuToggleButton = ({
2475
2636
  );
2476
2637
  };
2477
2638
 
2478
- // src/ActionMenu/ActionMenu.tsx
2479
- import React10, { useEffect } from "react";
2480
- import {
2481
- useSelect as useSelect2
2482
- } from "downshift";
2639
+ // src/MenuSearchInput/MenuSearchInput.tsx
2640
+ import React11 from "react";
2641
+ import { Input } from "@sproutsocial/seeds-react-input";
2483
2642
 
2484
- // src/reducers/useSelectStateReducer.tsx
2485
- import { useSelect } from "downshift";
2486
- var useSelectStateReducer = (state, actionAndChanges) => {
2487
- const { type, changes } = actionAndChanges;
2488
- switch (type) {
2489
- /** If downshift is blurred by tabbing within the menu, stay open */
2490
- case useSelect.stateChangeTypes.ToggleButtonBlur:
2491
- return {
2492
- ...changes,
2493
- // keep menu open on blur
2494
- isOpen: true
2495
- };
2496
- /** Return standard change payload */
2497
- default:
2498
- return changes;
2499
- }
2500
- };
2501
- var defaultUseSelectProps = {
2502
- stateReducer: useSelectStateReducer,
2503
- isItemDisabled: (item) => !!item.disabled
2504
- };
2643
+ // src/hooks/useItemFiltering.tsx
2644
+ import React10 from "react";
2505
2645
 
2506
- // src/utils/itemToString.ts
2646
+ // src/utils/downshiftDefaults.ts
2507
2647
  var itemToString = (item) => {
2508
2648
  return item ? item.id : "";
2509
2649
  };
2510
-
2511
- // src/ActionMenu/ActionMenu.tsx
2512
- import { jsx as jsx13 } from "react/jsx-runtime";
2513
- var handleStateChange = (changes, currentSelectedItem) => {
2514
- if (!(changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter || changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownSpaceButton)) {
2515
- return;
2516
- }
2517
- const selectedItem = changes.selectedItem || currentSelectedItem;
2518
- if (!selectedItem) return;
2519
- if (selectedItem.disabled) {
2520
- return;
2521
- }
2522
- const isEnterKeyDown = changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter;
2523
- const selectedItemProps = selectedItem.menuItemProps;
2524
- if (selectedItemProps?.onClick) {
2525
- const syntheticKeyboardEvent = new KeyboardEvent("keydown", {
2526
- key: isEnterKeyDown ? "Enter" : " ",
2527
- code: isEnterKeyDown ? "Enter" : "Space",
2528
- bubbles: true,
2529
- cancelable: true,
2530
- view: window
2531
- });
2532
- selectedItemProps?.onClick?.(
2533
- syntheticKeyboardEvent
2534
- );
2535
- }
2536
- if (selectedItemProps?.href) {
2537
- if (selectedItemProps.target) {
2538
- window.open(selectedItemProps.href, selectedItemProps.target);
2539
- } else {
2540
- window.location.href = selectedItemProps?.href;
2541
- }
2542
- }
2650
+ var itemToKey = (item) => {
2651
+ return item ? item.id : "";
2543
2652
  };
2544
- var ActionMenu = ({
2545
- children: childrenProp,
2546
- items,
2547
- MenuItemComponent = MenuItem,
2548
- stateReducer: externalStateReducer,
2549
- ...useSelectProps
2653
+
2654
+ // src/hooks/useItemFiltering.tsx
2655
+ var getDefaultGetIsItemVisible = (itemToString2 = itemToString) => (item, inputValue) => itemToString2(item).toLowerCase().includes(inputValue.toLowerCase());
2656
+ var defaultGetShouldFilter = ({ inputValue }) => Boolean(inputValue);
2657
+ var useItemFiltering = ({
2658
+ allMenuItems,
2659
+ itemToString: itemToString2,
2660
+ getIsItemVisible = getDefaultGetIsItemVisible(itemToString2),
2661
+ getShouldFilter = defaultGetShouldFilter,
2662
+ setHiddenItemsMap: setHiddenItemsMapProp
2550
2663
  }) => {
2551
- const { allMenuItems, menuItemsMap, children } = useMenuChildren({
2552
- children: childrenProp,
2553
- items,
2554
- MenuItemComponent
2555
- });
2556
- const [currentSelectedItem, setCurrentSelectedItem] = React10.useState(null);
2557
- const { isOpen, ...useSelectReturnProps } = useSelect2({
2558
- ...defaultUseSelectProps,
2559
- items: allMenuItems,
2560
- itemToString,
2561
- onStateChange: (changes) => handleStateChange(changes, currentSelectedItem),
2562
- stateReducer: (state, actionAndChanges) => {
2563
- let newState;
2564
- newState = useSelectStateReducer(state, actionAndChanges);
2565
- return externalStateReducer ? externalStateReducer(state, {
2566
- ...actionAndChanges,
2567
- changes: newState
2568
- }) : newState;
2664
+ const [hiddenItemsMap, setHiddenItemsMap] = React10.useState({});
2665
+ const updateFilteredItems = React10.useCallback(
2666
+ ({ inputValue }) => {
2667
+ const newHiddenItems = getShouldFilter({ inputValue }) ? allMenuItems.reduce((map, item) => {
2668
+ const isItemVisible = getIsItemVisible(item, inputValue);
2669
+ return isItemVisible ? map : { ...map, [item.id]: true };
2670
+ }, {}) : {};
2671
+ setHiddenItemsMap(newHiddenItems);
2672
+ setHiddenItemsMapProp?.(newHiddenItems);
2569
2673
  },
2570
- ...useSelectProps
2571
- });
2572
- useEffect(() => {
2573
- setCurrentSelectedItem(useSelectReturnProps.selectedItem);
2574
- }, [useSelectReturnProps.selectedItem]);
2575
- return /* @__PURE__ */ jsx13(
2576
- MenuRoot,
2577
- {
2578
- ...{
2579
- isListbox: false,
2580
- items: allMenuItems,
2581
- itemsMap: menuItemsMap,
2582
- itemToString,
2583
- isOpen,
2584
- ...useSelectProps,
2585
- ...useSelectReturnProps
2586
- },
2587
- children
2588
- }
2674
+ [allMenuItems, getIsItemVisible, getShouldFilter]
2589
2675
  );
2676
+ return {
2677
+ getIsItemVisible,
2678
+ updateFilteredItems
2679
+ };
2590
2680
  };
2591
2681
 
2592
- // src/SingleSelectMenu/SingleSelectMenu.tsx
2593
- import "react";
2594
- import { useSelect as useSelect3 } from "downshift";
2595
- import { jsx as jsx14 } from "react/jsx-runtime";
2596
- var SingleSelectMenu = ({
2597
- children: childrenProp,
2598
- stateReducer: externalStateReducer,
2599
- items,
2600
- MenuItemComponent = MenuItem,
2601
- ...useSelectProps
2682
+ // src/MenuSearchInput/MenuSearchInput.tsx
2683
+ import { jsx as jsx13 } from "react/jsx-runtime";
2684
+ var MenuSearchInput = ({
2685
+ getIsItemVisible,
2686
+ inputProps,
2687
+ ...restInputProps
2602
2688
  }) => {
2603
- const { allMenuItems, menuItemsMap, children } = useMenuChildren({
2604
- children: childrenProp,
2689
+ const {
2605
2690
  items,
2606
- MenuItemComponent
2691
+ itemToString: itemToString2,
2692
+ setHiddenItemsMap,
2693
+ isOpen,
2694
+ getToggleButtonProps
2695
+ } = useMenuContentContext();
2696
+ const { updateFilteredItems } = useItemFiltering({
2697
+ allMenuItems: items,
2698
+ itemToString: itemToString2,
2699
+ getIsItemVisible,
2700
+ setHiddenItemsMap
2607
2701
  });
2608
- const { isOpen, ...useSelectReturnProps } = useSelect3({
2609
- ...defaultUseSelectProps,
2610
- items: allMenuItems,
2611
- itemToString,
2612
- stateReducer: (state, actionAndChanges) => {
2613
- let newState;
2614
- newState = useSelectStateReducer(state, actionAndChanges);
2615
- return externalStateReducer ? externalStateReducer(state, {
2616
- ...actionAndChanges,
2617
- changes: newState
2618
- }) : newState;
2702
+ React11.useEffect(() => {
2703
+ updateFilteredItems({ inputValue: restInputProps.value || "" });
2704
+ }, [isOpen, restInputProps.value]);
2705
+ const toggleButtonProps = getToggleButtonProps?.() || {};
2706
+ const handleKeyDown = React11.useCallback(
2707
+ (e) => {
2708
+ if (e.key === " ") return;
2709
+ toggleButtonProps.onKeyDown?.(e);
2619
2710
  },
2620
- ...useSelectProps
2621
- });
2622
- return /* @__PURE__ */ jsx14(
2623
- MenuRoot,
2711
+ [toggleButtonProps.onKeyDown]
2712
+ );
2713
+ return /* @__PURE__ */ jsx13(
2714
+ Input,
2624
2715
  {
2625
- ...{
2626
- isListbox: true,
2627
- items: allMenuItems,
2628
- itemsMap: menuItemsMap,
2629
- itemToString,
2630
- isOpen,
2631
- ...useSelectProps,
2632
- ...useSelectReturnProps
2716
+ onChange: (e, value) => {
2717
+ updateFilteredItems({ inputValue: value });
2633
2718
  },
2634
- children
2719
+ onKeyDown: handleKeyDown,
2720
+ autoComplete: false,
2721
+ "aria-autocomplete": "list",
2722
+ inputProps: {
2723
+ ["aria-activedescendant"]: toggleButtonProps["aria-activedescendant"],
2724
+ ["aria-controls"]: toggleButtonProps["aria-controls"],
2725
+ ...inputProps
2726
+ },
2727
+ ...restInputProps
2635
2728
  }
2636
2729
  );
2637
2730
  };
2638
2731
 
2639
- // src/MultiSelectMenu/MultiSelectMenu.tsx
2640
- import "react";
2732
+ // src/MenuTokenInput.tsx
2733
+ import React12 from "react";
2734
+ import styled8 from "styled-components";
2641
2735
  import {
2642
- useSelect as useSelect4,
2643
- useMultipleSelection
2644
- } from "downshift";
2645
- import { jsx as jsx15 } from "react/jsx-runtime";
2646
- var selectReducerForMultiSelect = (state, actionAndChanges) => {
2647
- const { changes, type } = actionAndChanges;
2648
- switch (type) {
2649
- case useSelect4.stateChangeTypes.ToggleButtonKeyDownEnter:
2650
- case useSelect4.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
2651
- case useSelect4.stateChangeTypes.ItemClick:
2652
- return {
2653
- ...changes,
2654
- isOpen: true,
2655
- // keep the menu open after selection.
2656
- // TODO: Confirm that keeping highlightedIndex the same is the desired UX
2657
- // highlightedIndex: 0, // with the first option highlighted.
2658
- highlightedIndex: state.highlightedIndex
2659
- // keep highlightedIndex the same instead of returning to 0
2660
- };
2736
+ TokenInput
2737
+ } from "@sproutsocial/seeds-react-token-input";
2738
+ import { jsx as jsx14 } from "react/jsx-runtime";
2739
+ var StyledTokenInputWrapper = styled8.div`
2740
+ > div {
2741
+ padding: 4px;
2661
2742
  }
2662
- return changes;
2663
- };
2664
- var MultiSelectMenu = ({
2665
- children: childrenProp,
2666
- items,
2667
- MenuItemComponent = MenuItem,
2668
- stateReducer: externalStateReducer,
2669
- getA11yMultiStatusMessage,
2670
- onMultiSelectStateChange,
2671
- multiSelectStateReducer,
2672
- ...useSelectProps
2743
+
2744
+ input {
2745
+ line-height: 21px;
2746
+ margin: 0;
2747
+ padding: 2px 4px;
2748
+ }
2749
+
2750
+ .TokenInput-token button {
2751
+ margin-top: 0;
2752
+ padding: 1px 4px;
2753
+ }
2754
+ `;
2755
+ var MenuTokenInput = ({
2756
+ inputProps = {},
2757
+ getTokenProps,
2758
+ onKeyDown,
2759
+ MenuContext = MenuToggleContext,
2760
+ ...tokenInputProps
2761
+ }) => {
2762
+ const {
2763
+ itemToString: itemToString2,
2764
+ getSelectedItemProps,
2765
+ removeSelectedItem,
2766
+ setActiveIndex,
2767
+ selectedItems = []
2768
+ } = React12.useContext(MenuContext);
2769
+ const removeToken = (tokenId) => {
2770
+ const tokenToRemove = selectedItems?.find((item) => item.id === tokenId);
2771
+ tokenToRemove && removeSelectedItem?.(tokenToRemove);
2772
+ };
2773
+ return /* @__PURE__ */ jsx14(StyledTokenInputWrapper, { children: /* @__PURE__ */ jsx14(
2774
+ TokenInput,
2775
+ {
2776
+ onKeyDown: (e, value) => {
2777
+ if (e.key === "ArrowLeft" && !value && selectedItems.length) {
2778
+ setActiveIndex?.(selectedItems.length - 1);
2779
+ }
2780
+ onKeyDown?.(e, value);
2781
+ },
2782
+ inputProps: {
2783
+ autoComplete: "off",
2784
+ type: "search",
2785
+ ...inputProps
2786
+ },
2787
+ tokens: selectedItems.map((item, index) => {
2788
+ const {
2789
+ tokenProps: { ref, onKeyDown: onKeyDown2, ...restTokenProps } = {
2790
+ ref: void 0,
2791
+ onKeyDown: void 0
2792
+ },
2793
+ ...rest
2794
+ } = getTokenProps?.(item.id) || {};
2795
+ return {
2796
+ id: item.id,
2797
+ value: itemToString2?.(item) || item.id,
2798
+ tokenProps: {
2799
+ ...getSelectedItemProps?.({
2800
+ selectedItem: item,
2801
+ index,
2802
+ ref,
2803
+ refKey: "innerRef",
2804
+ onKeyDown: onKeyDown2
2805
+ }),
2806
+ // nullify the onclick provided from downshift
2807
+ // TokenInput deletes the token on click
2808
+ onClick: void 0,
2809
+ tabIndex: 0,
2810
+ ...restTokenProps
2811
+ },
2812
+ ...rest
2813
+ };
2814
+ }),
2815
+ onRemoveToken: removeToken,
2816
+ ...tokenInputProps
2817
+ }
2818
+ ) });
2819
+ };
2820
+
2821
+ // src/MenuSearchTokenInput/MenuSearchTokenInput.tsx
2822
+ import React13 from "react";
2823
+ import { jsx as jsx15 } from "react/jsx-runtime";
2824
+ var MenuSearchTokenInput = ({
2825
+ getIsItemVisible,
2826
+ getTokenProps,
2827
+ onChange,
2828
+ inputProps: { value: inputPropsValue, ...inputProps } = {},
2829
+ value,
2830
+ ...tokenInputProps
2831
+ }) => {
2832
+ const {
2833
+ items,
2834
+ itemToString: itemToString2,
2835
+ setHiddenItemsMap,
2836
+ isOpen,
2837
+ getToggleButtonProps
2838
+ } = useMenuContentContext();
2839
+ const { updateFilteredItems } = useItemFiltering({
2840
+ allMenuItems: items,
2841
+ itemToString: itemToString2,
2842
+ getIsItemVisible,
2843
+ setHiddenItemsMap
2844
+ });
2845
+ const controlledValue = value || inputPropsValue !== void 0 ? `${inputPropsValue}` : void 0;
2846
+ const [internalValue, setInternalValue] = React13.useState(
2847
+ controlledValue || ""
2848
+ );
2849
+ const updateFilteredState = React13.useCallback(
2850
+ // defaults to an empty string if no value is passed
2851
+ (value2 = "") => {
2852
+ setInternalValue(value2);
2853
+ updateFilteredItems({ inputValue: value2 });
2854
+ },
2855
+ [updateFilteredItems]
2856
+ );
2857
+ React13.useEffect(() => {
2858
+ updateFilteredState(controlledValue);
2859
+ }, [controlledValue]);
2860
+ React13.useEffect(() => {
2861
+ updateFilteredState(controlledValue);
2862
+ }, [isOpen]);
2863
+ const toggleButtonProps = getToggleButtonProps?.() || {};
2864
+ const handleKeyDown = React13.useCallback(
2865
+ (e) => {
2866
+ if (e.key === " ") return;
2867
+ toggleButtonProps.onKeyDown?.(e);
2868
+ },
2869
+ [toggleButtonProps.onKeyDown]
2870
+ );
2871
+ return /* @__PURE__ */ jsx15(
2872
+ MenuTokenInput,
2873
+ {
2874
+ onChange: (e, value2) => {
2875
+ updateFilteredState(value2);
2876
+ onChange?.(e, value2);
2877
+ },
2878
+ onKeyDown: handleKeyDown,
2879
+ inputProps: {
2880
+ value: internalValue,
2881
+ ["aria-activedescendant"]: toggleButtonProps["aria-activedescendant"],
2882
+ ["aria-controls"]: toggleButtonProps["aria-controls"],
2883
+ ...inputProps
2884
+ },
2885
+ MenuContext: MenuContentContext,
2886
+ ...tokenInputProps
2887
+ }
2888
+ );
2889
+ };
2890
+
2891
+ // src/SubmenuItem/SubmenuItem.tsx
2892
+ import React14 from "react";
2893
+ import { Icon as Icon2 } from "@sproutsocial/seeds-react-icon";
2894
+ import { Box as Box3 } from "@sproutsocial/seeds-react-box";
2895
+ import { mergeRefs } from "@sproutsocial/seeds-react-utilities";
2896
+ import { jsx as jsx16, jsxs as jsxs4 } from "react/jsx-runtime";
2897
+ var SubmenuItemTrigger = ({
2898
+ id,
2899
+ children,
2900
+ innerRef,
2901
+ ...rest
2902
+ }) => {
2903
+ const { getToggleButtonProps, getDropdownProps, ref, ariaProps } = useMenuToggleContext();
2904
+ const toggleRef = ref && innerRef ? mergeRefs([ref, innerRef].filter(Boolean)) : ref || innerRef;
2905
+ return /* @__PURE__ */ jsx16(
2906
+ MenuItem,
2907
+ {
2908
+ ...rest,
2909
+ ...getToggleButtonProps?.(
2910
+ {
2911
+ ...getDropdownProps?.({
2912
+ ref: toggleRef,
2913
+ preventKeyAction: true
2914
+ }) || { ref: toggleRef },
2915
+ refKey: "innerRef",
2916
+ role: "menuitem",
2917
+ ...ariaProps
2918
+ },
2919
+ { suppressRefError: true }
2920
+ ),
2921
+ id,
2922
+ children: /* @__PURE__ */ jsxs4(Box3, { display: "flex", justifyContent: "space-between", children: [
2923
+ children,
2924
+ /* @__PURE__ */ jsx16(MenuItemActionRight, { children: /* @__PURE__ */ jsx16(Icon2, { name: "chevron-right-outline" }) })
2925
+ ] })
2926
+ }
2927
+ );
2928
+ };
2929
+ var doesRefContainEventTarget = (ref, event) => {
2930
+ return ref.current && event.target instanceof Node && ref.current.contains(event.target);
2931
+ };
2932
+ var SubmenuItem = ({
2933
+ MenuComponent,
2934
+ menuProps: {
2935
+ children: menuChildren,
2936
+ menuItems,
2937
+ MenuItemComponent,
2938
+ popoutProps: { popperProps, ...popoutProps } = {},
2939
+ onStateChange,
2940
+ ...menuProps
2941
+ },
2942
+ // isOpen,
2943
+ // onToggleSubmenu,
2944
+ id,
2945
+ children,
2946
+ ...rest
2947
+ }) => {
2948
+ const {
2949
+ highlightedIndex,
2950
+ setHighlightedIndex,
2951
+ itemsMap,
2952
+ isOpen: parentIsOpen
2953
+ } = useMenuContentContext();
2954
+ const [submenuIsFocused, setSubmenuIsFocused] = React14.useState(false);
2955
+ const [submenuIsOpen, setSubmenuIsOpen] = React14.useState(false);
2956
+ const [submenuIsActive, setSubmenuIsActive] = React14.useState(false);
2957
+ const submenuItemRef = React14.useRef(null);
2958
+ const submenuRef = React14.useRef(null);
2959
+ const menuContent = menuItems ? getChildrenFromMenuItems({ menuItems, MenuItemComponent }) : menuChildren;
2960
+ const item = itemsMap[id] || {
2961
+ index: 0,
2962
+ id
2963
+ };
2964
+ React14.useEffect(() => {
2965
+ if (highlightedIndex === item.index) {
2966
+ !submenuIsOpen && setSubmenuIsOpen(true);
2967
+ } else if (submenuIsOpen && highlightedIndex !== -1) {
2968
+ setSubmenuIsOpen(false);
2969
+ setSubmenuIsActive(false);
2970
+ }
2971
+ }, [highlightedIndex, item.index, submenuIsOpen, setSubmenuIsOpen]);
2972
+ const onSubmenuStateChange = React14.useCallback(
2973
+ (state) => {
2974
+ if (state.isOpen !== void 0) {
2975
+ setSubmenuIsOpen(state.isOpen);
2976
+ if (!state.isOpen) {
2977
+ setSubmenuIsFocused(false);
2978
+ setHighlightedIndex?.(-1);
2979
+ }
2980
+ }
2981
+ onStateChange?.(state);
2982
+ },
2983
+ [onStateChange, setSubmenuIsOpen]
2984
+ );
2985
+ const onSubmenuKeydown = (e) => {
2986
+ switch (e.key) {
2987
+ case "ArrowRight":
2988
+ case " ":
2989
+ case "Enter":
2990
+ if (!submenuIsFocused && submenuIsOpen) {
2991
+ e.stopPropagation();
2992
+ setSubmenuIsFocused(true);
2993
+ }
2994
+ break;
2995
+ case "ArrowLeft":
2996
+ if (submenuIsFocused) {
2997
+ e.stopPropagation();
2998
+ setSubmenuIsFocused(false);
2999
+ }
3000
+ break;
3001
+ default:
3002
+ break;
3003
+ }
3004
+ };
3005
+ const onMenuItemClick = () => {
3006
+ const newIsActive = !submenuIsActive;
3007
+ setSubmenuIsActive(newIsActive);
3008
+ setSubmenuIsOpen(newIsActive);
3009
+ };
3010
+ const onBodyClick = (e) => {
3011
+ if (doesRefContainEventTarget(submenuItemRef, e)) {
3012
+ e.stopPropagation();
3013
+ onMenuItemClick();
3014
+ }
3015
+ };
3016
+ React14.useEffect(() => {
3017
+ if (document && document.body) {
3018
+ document.body.addEventListener("click", onBodyClick, {
3019
+ capture: true
3020
+ });
3021
+ document.body.addEventListener("keydown", onSubmenuKeydown, {
3022
+ capture: true
3023
+ });
3024
+ return () => {
3025
+ document.body.removeEventListener("click", onBodyClick, {
3026
+ capture: true
3027
+ });
3028
+ document.body.removeEventListener("keydown", onSubmenuKeydown, {
3029
+ capture: true
3030
+ });
3031
+ };
3032
+ }
3033
+ }, [document, onSubmenuKeydown]);
3034
+ const subMenuContent = /* @__PURE__ */ jsx16(
3035
+ "div",
3036
+ {
3037
+ ref: submenuRef,
3038
+ onKeyDown: (e) => {
3039
+ e.stopPropagation();
3040
+ },
3041
+ tabIndex: -1,
3042
+ children: menuContent
3043
+ }
3044
+ );
3045
+ return /* @__PURE__ */ jsx16(
3046
+ MenuComponent,
3047
+ {
3048
+ ...{
3049
+ ...menuProps,
3050
+ children: subMenuContent,
3051
+ menuToggleElement: /* @__PURE__ */ jsx16(
3052
+ SubmenuItemTrigger,
3053
+ {
3054
+ innerRef: submenuItemRef,
3055
+ id,
3056
+ children,
3057
+ active: submenuIsActive,
3058
+ ...rest
3059
+ }
3060
+ ),
3061
+ isOpen: submenuIsOpen,
3062
+ onStateChange: onSubmenuStateChange,
3063
+ popoutProps: {
3064
+ placement: "right",
3065
+ popperProps: {
3066
+ modifiers: {
3067
+ offset: {
3068
+ offset: "0,18"
3069
+ }
3070
+ },
3071
+ ...popperProps
3072
+ },
3073
+ focusOnContent: submenuIsFocused,
3074
+ ...popoutProps
3075
+ }
3076
+ }
3077
+ }
3078
+ );
3079
+ };
3080
+ SubmenuItem.__MENU_PRIMITIVE_TYPE = "MenuItem";
3081
+
3082
+ // src/ActionMenu/ActionMenu.tsx
3083
+ import React16, { useEffect as useEffect2 } from "react";
3084
+ import {
3085
+ useSelect as useSelect2
3086
+ } from "downshift";
3087
+
3088
+ // src/hooks/useDownshiftDefaults.tsx
3089
+ import React15 from "react";
3090
+
3091
+ // src/reducers/useComboboxStateReducer.tsx
3092
+ import { useCombobox } from "downshift";
3093
+
3094
+ // src/utils/reduceReducers.ts
3095
+ var reduceReducers = (...reducers) => (state, action) => reducers.reduce(
3096
+ (changes, nextReducer) => nextReducer ? nextReducer(state, {
3097
+ ...action,
3098
+ changes
3099
+ }) : changes,
3100
+ action.changes
3101
+ );
3102
+
3103
+ // src/reducers/useComboboxStateReducer.tsx
3104
+ var useComboboxStateReducer = (state, actionAndChanges) => {
3105
+ const { type, changes } = actionAndChanges;
3106
+ switch (type) {
3107
+ /** If downshift is blurred by tabbing within the menu, stay open */
3108
+ case useCombobox.stateChangeTypes.InputBlur:
3109
+ return {
3110
+ ...changes,
3111
+ // keep menu open on blur
3112
+ isOpen: true
3113
+ };
3114
+ /** Return standard change payload */
3115
+ default:
3116
+ return changes;
3117
+ }
3118
+ };
3119
+ var useComboboxStateReducerForMulti = reduceReducers(
3120
+ useComboboxStateReducer,
3121
+ (state, actionAndChanges) => {
3122
+ const { changes, type } = actionAndChanges;
3123
+ switch (type) {
3124
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
3125
+ case useCombobox.stateChangeTypes.ItemClick:
3126
+ case useCombobox.stateChangeTypes.InputBlur:
3127
+ return {
3128
+ ...changes,
3129
+ ...changes.selectedItem && {
3130
+ inputValue: ""
3131
+ }
3132
+ };
3133
+ default:
3134
+ return changes;
3135
+ }
3136
+ }
3137
+ );
3138
+
3139
+ // src/reducers/useSelectStateReducer.tsx
3140
+ import { useSelect } from "downshift";
3141
+ var useSelectStateReducer = (state, actionAndChanges) => {
3142
+ const { type, changes } = actionAndChanges;
3143
+ switch (type) {
3144
+ /** If downshift is blurred by tabbing within the menu, stay open */
3145
+ case useSelect.stateChangeTypes.ToggleButtonBlur:
3146
+ return {
3147
+ ...changes,
3148
+ // keep menu open on blur
3149
+ isOpen: true
3150
+ };
3151
+ /** Return standard change payload */
3152
+ default:
3153
+ return changes;
3154
+ }
3155
+ };
3156
+ var useSelectStateReducerForMulti = reduceReducers(
3157
+ useSelectStateReducer,
3158
+ (state, actionAndChanges) => {
3159
+ const { changes, type } = actionAndChanges;
3160
+ switch (type) {
3161
+ case useSelect.stateChangeTypes.ToggleButtonKeyDownEnter:
3162
+ case useSelect.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
3163
+ case useSelect.stateChangeTypes.ItemClick:
3164
+ return {
3165
+ ...changes,
3166
+ isOpen: true,
3167
+ // keep the menu open after selection.
3168
+ // TODO: Confirm that keeping highlightedIndex the same is the desired UX
3169
+ // highlightedIndex: 0, // with the first option highlighted.
3170
+ highlightedIndex: state.highlightedIndex
3171
+ // keep highlightedIndex the same instead of returning to 0
3172
+ };
3173
+ }
3174
+ return changes;
3175
+ }
3176
+ );
3177
+
3178
+ // src/utils/getMultiSelectOverrides.ts
3179
+ var getMultiSelectOverrides = ({
3180
+ getA11yMultiStatusMessage,
3181
+ onMultiSelectStateChange,
3182
+ multiSelectStateReducer,
3183
+ ...useSelectProps
3184
+ }) => Object.entries({
3185
+ ...useSelectProps,
3186
+ getA11yStatusMessage: getA11yMultiStatusMessage,
3187
+ onStateChange: onMultiSelectStateChange,
3188
+ stateReducer: multiSelectStateReducer
3189
+ }).reduce(
3190
+ (a, [k, v]) => v ? (a[k] = v, a) : a,
3191
+ {}
3192
+ );
3193
+
3194
+ // src/hooks/useDownshiftDefaults.tsx
3195
+ var defaultUseSelectProps = {
3196
+ stateReducer: useSelectStateReducer
3197
+ };
3198
+ var defaultUseComboboxProps = {
3199
+ stateReducer: useComboboxStateReducer
3200
+ };
3201
+ var defaultUseSelectPropsForMulti = {
3202
+ stateReducer: useSelectStateReducerForMulti
3203
+ };
3204
+ var defaultUseComboboxPropsForMulti = {
3205
+ stateReducer: useComboboxStateReducerForMulti
3206
+ };
3207
+ var itemToKey2 = (item) => item?.id;
3208
+ var useDownshiftDefaults = ({
3209
+ isCombobox = false,
3210
+ isMulti = false,
3211
+ multiSelectProps = {}
3212
+ } = {}) => {
3213
+ const [hiddenItemsMap, setHiddenItemsMap] = React15.useState({});
3214
+ const hiddenItemsCount = React15.useMemo(
3215
+ () => Object.keys(hiddenItemsMap).filter(Boolean).length,
3216
+ [hiddenItemsMap]
3217
+ );
3218
+ const isItemDisabled = React15.useCallback(
3219
+ (item) => Boolean(item.disabled || hiddenItemsMap[item.id]),
3220
+ [hiddenItemsMap]
3221
+ );
3222
+ return {
3223
+ hiddenItemsMap,
3224
+ hiddenItemsCount,
3225
+ setHiddenItemsMap,
3226
+ defaultDownshiftProps: {
3227
+ select: !isCombobox ? {
3228
+ itemToKey: itemToKey2,
3229
+ // disabling while item.hidden so that hidden items are ignored by downshift
3230
+ isItemDisabled,
3231
+ ...isMulti ? defaultUseSelectPropsForMulti : defaultUseSelectProps
3232
+ } : {},
3233
+ combobox: isCombobox ? {
3234
+ itemToKey: itemToKey2,
3235
+ // disabling while item.hidden so that hidden items are ignored by downshift
3236
+ isItemDisabled,
3237
+ ...isMulti ? defaultUseComboboxPropsForMulti : defaultUseComboboxProps
3238
+ } : {},
3239
+ multi: isMulti ? {
3240
+ itemToKey: itemToKey2,
3241
+ // handles the prop name mapping for multi select
3242
+ ...getMultiSelectOverrides(multiSelectProps)
3243
+ } : {}
3244
+ }
3245
+ };
3246
+ };
3247
+
3248
+ // src/ActionMenu/ActionMenu.tsx
3249
+ import { jsx as jsx17 } from "react/jsx-runtime";
3250
+ var handleStateChange = (changes, currentSelectedItem) => {
3251
+ if (!(changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter || changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownSpaceButton)) {
3252
+ return;
3253
+ }
3254
+ const selectedItem = changes.selectedItem || currentSelectedItem;
3255
+ if (!selectedItem) return;
3256
+ if (selectedItem.disabled) {
3257
+ return;
3258
+ }
3259
+ const isEnterKeyDown = changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter;
3260
+ const selectedItemProps = selectedItem.menuItemProps;
3261
+ if (selectedItemProps?.onClick) {
3262
+ const syntheticKeyboardEvent = new KeyboardEvent("keydown", {
3263
+ key: isEnterKeyDown ? "Enter" : " ",
3264
+ code: isEnterKeyDown ? "Enter" : "Space",
3265
+ bubbles: true,
3266
+ cancelable: true,
3267
+ view: window
3268
+ });
3269
+ selectedItemProps?.onClick?.(
3270
+ syntheticKeyboardEvent
3271
+ );
3272
+ }
3273
+ if (selectedItemProps?.href) {
3274
+ if (selectedItemProps.target) {
3275
+ window.open(selectedItemProps.href, selectedItemProps.target);
3276
+ } else {
3277
+ window.location.href = selectedItemProps?.href;
3278
+ }
3279
+ }
3280
+ };
3281
+ var ActionMenu = ({
3282
+ children: childrenProp,
3283
+ menuItems,
3284
+ MenuItemComponent,
3285
+ stateReducer: externalStateReducer,
3286
+ ...useSelectProps
2673
3287
  }) => {
2674
3288
  const { allMenuItems, menuItemsMap, children } = useMenuChildren({
2675
3289
  children: childrenProp,
2676
- items,
3290
+ menuItems,
3291
+ MenuItemComponent
3292
+ });
3293
+ const { defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({
3294
+ isCombobox: false
3295
+ });
3296
+ const [currentSelectedItem, setCurrentSelectedItem] = React16.useState(null);
3297
+ const { isOpen, ...useSelectReturnProps } = useSelect2({
3298
+ ...defaultDownshiftProps.select,
3299
+ items: allMenuItems,
3300
+ itemToString,
3301
+ onStateChange: (changes) => handleStateChange(changes, currentSelectedItem),
3302
+ stateReducer: reduceReducers(
3303
+ defaultDownshiftProps.select.stateReducer,
3304
+ externalStateReducer
3305
+ ),
3306
+ ...useSelectProps
3307
+ });
3308
+ useEffect2(() => {
3309
+ setCurrentSelectedItem(useSelectReturnProps.selectedItem);
3310
+ }, [useSelectReturnProps.selectedItem]);
3311
+ return /* @__PURE__ */ jsx17(
3312
+ MenuRoot,
3313
+ {
3314
+ ...{
3315
+ isListbox: false,
3316
+ items: allMenuItems,
3317
+ itemsMap: menuItemsMap,
3318
+ itemToString,
3319
+ isOpen,
3320
+ ...useSelectProps,
3321
+ ...useSelectReturnProps,
3322
+ ...restDefaults
3323
+ },
3324
+ children
3325
+ }
3326
+ );
3327
+ };
3328
+
3329
+ // src/SingleSelectMenu/SingleSelectMenu.tsx
3330
+ import "react";
3331
+ import { useSelect as useSelect3 } from "downshift";
3332
+ import { jsx as jsx18 } from "react/jsx-runtime";
3333
+ var SingleSelectMenu = ({
3334
+ children: childrenProp,
3335
+ stateReducer: externalStateReducer,
3336
+ menuItems,
3337
+ MenuItemComponent,
3338
+ ...useSelectProps
3339
+ }) => {
3340
+ const { allMenuItems, menuItemsMap, children } = useMenuChildren({
3341
+ children: childrenProp,
3342
+ menuItems,
2677
3343
  MenuItemComponent
2678
3344
  });
2679
- const multiSelectOverrides = Object.entries({
2680
- ...useSelectProps,
2681
- getA11yStatusMessage: getA11yMultiStatusMessage,
2682
- onStateChange: onMultiSelectStateChange,
2683
- stateReducer: multiSelectStateReducer
2684
- }).reduce(
2685
- (a, [k, v]) => v ? (a[k] = v, a) : a,
2686
- {}
3345
+ const { defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({
3346
+ isCombobox: false
3347
+ });
3348
+ const { isOpen, ...useSelectReturnProps } = useSelect3({
3349
+ ...defaultDownshiftProps.select,
3350
+ items: allMenuItems,
3351
+ itemToString,
3352
+ stateReducer: reduceReducers(
3353
+ defaultDownshiftProps.select.stateReducer,
3354
+ externalStateReducer
3355
+ ),
3356
+ ...useSelectProps
3357
+ });
3358
+ return /* @__PURE__ */ jsx18(
3359
+ MenuRoot,
3360
+ {
3361
+ ...{
3362
+ isListbox: true,
3363
+ items: allMenuItems,
3364
+ itemsMap: menuItemsMap,
3365
+ itemToString,
3366
+ isOpen,
3367
+ ...useSelectProps,
3368
+ ...useSelectReturnProps,
3369
+ ...restDefaults
3370
+ },
3371
+ children
3372
+ }
2687
3373
  );
3374
+ };
3375
+
3376
+ // src/MultiSelectMenu/MultiSelectMenu.tsx
3377
+ import "react";
3378
+ import { useSelect as useSelect4, useMultipleSelection } from "downshift";
3379
+ import { jsx as jsx19 } from "react/jsx-runtime";
3380
+ var MultiSelectMenu = ({
3381
+ children: childrenProp,
3382
+ menuItems,
3383
+ MenuItemComponent,
3384
+ onSelectedItemChange: externalOnSelectedItemChange,
3385
+ stateReducer: externalStateReducer,
3386
+ getA11yMultiStatusMessage,
3387
+ onMultiSelectStateChange,
3388
+ multiSelectStateReducer,
3389
+ ...useSelectProps
3390
+ }) => {
3391
+ const { allMenuItems, menuItemsMap, children } = useMenuChildren({
3392
+ children: childrenProp,
3393
+ menuItems,
3394
+ MenuItemComponent
3395
+ });
3396
+ const { defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({
3397
+ isCombobox: false,
3398
+ isMulti: true,
3399
+ // handles the prop name mapping for multi select
3400
+ multiSelectProps: {
3401
+ getA11yMultiStatusMessage,
3402
+ onMultiSelectStateChange,
3403
+ multiSelectStateReducer,
3404
+ ...useSelectProps
3405
+ }
3406
+ });
2688
3407
  const {
2689
3408
  getSelectedItemProps,
2690
3409
  addSelectedItem,
@@ -2692,26 +3411,19 @@ var MultiSelectMenu = ({
2692
3411
  selectedItems,
2693
3412
  getDropdownProps,
2694
3413
  ...useMultipleSelectionReturnProps
2695
- } = useMultipleSelection(multiSelectOverrides);
3414
+ } = useMultipleSelection(defaultDownshiftProps.multi);
2696
3415
  const { isOpen, ...useSelectReturnProps } = useSelect4({
2697
- ...defaultUseSelectProps,
3416
+ ...defaultDownshiftProps.select,
2698
3417
  items: allMenuItems,
2699
3418
  itemToString,
2700
3419
  selectedItem: null,
2701
3420
  defaultHighlightedIndex: 0,
2702
- stateReducer: (state, actionAndChanges) => {
2703
- let newState;
2704
- newState = useSelectStateReducer(state, actionAndChanges);
2705
- newState = selectReducerForMultiSelect(state, {
2706
- ...actionAndChanges,
2707
- changes: newState
2708
- });
2709
- return externalStateReducer ? externalStateReducer(state, {
2710
- ...actionAndChanges,
2711
- changes: newState
2712
- }) : newState;
2713
- },
2714
- onStateChange: ({ type, selectedItem: newSelectedItem }) => {
3421
+ stateReducer: reduceReducers(
3422
+ defaultDownshiftProps.select.stateReducer,
3423
+ externalStateReducer
3424
+ ),
3425
+ onSelectedItemChange: (changes) => {
3426
+ const { type, selectedItem: newSelectedItem } = changes;
2715
3427
  switch (type) {
2716
3428
  case useSelect4.stateChangeTypes.ToggleButtonKeyDownEnter:
2717
3429
  case useSelect4.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
@@ -2732,10 +3444,11 @@ var MultiSelectMenu = ({
2732
3444
  default:
2733
3445
  break;
2734
3446
  }
3447
+ externalOnSelectedItemChange?.(changes);
2735
3448
  },
2736
3449
  ...useSelectProps
2737
3450
  });
2738
- return /* @__PURE__ */ jsx15(
3451
+ return /* @__PURE__ */ jsx19(
2739
3452
  MenuRoot,
2740
3453
  {
2741
3454
  ...{
@@ -2754,7 +3467,8 @@ var MultiSelectMenu = ({
2754
3467
  multiSelectStateReducer,
2755
3468
  ...useSelectProps,
2756
3469
  ...useSelectReturnProps,
2757
- ...useMultipleSelectionReturnProps
3470
+ ...useMultipleSelectionReturnProps,
3471
+ ...restDefaults
2758
3472
  },
2759
3473
  children
2760
3474
  }
@@ -2762,83 +3476,191 @@ var MultiSelectMenu = ({
2762
3476
  };
2763
3477
 
2764
3478
  // src/Autocomplete/Autocomplete.tsx
2765
- import React13 from "react";
2766
- import { useCombobox as useCombobox2 } from "downshift";
2767
-
2768
- // src/reducers/useComboboxStateReducer.tsx
2769
- import { useCombobox } from "downshift";
2770
- var useComboboxStateReducer = (state, actionAndChanges) => {
2771
- const { type, changes } = actionAndChanges;
2772
- switch (type) {
2773
- /** If downshift is blurred by tabbing within the menu, stay open */
2774
- case useCombobox.stateChangeTypes.InputBlur:
2775
- return {
2776
- ...changes,
2777
- // keep menu open on blur
2778
- isOpen: true
2779
- };
2780
- /** Return standard change payload */
2781
- default:
2782
- return changes;
2783
- }
2784
- };
2785
- var defaultUseComboboxProps = {
2786
- // disabling while item.hidden so that hidden items are ignored by downshift
2787
- isItemDisabled: (item) => Boolean(item.disabled || item.hidden)
2788
- };
3479
+ import "react";
2789
3480
 
2790
- // src/Autocomplete/Autocomplete.tsx
2791
- import { jsx as jsx16 } from "react/jsx-runtime";
2792
- var Autocomplete = ({
3481
+ // src/Autocomplete/SingleAutocomplete.tsx
3482
+ import "react";
3483
+ import { useCombobox as useCombobox2 } from "downshift";
3484
+ import { jsx as jsx20 } from "react/jsx-runtime";
3485
+ var SingleAutocomplete = ({
2793
3486
  children: childrenProp,
2794
3487
  stateReducer: externalStateReducer,
2795
- items: itemsProp,
2796
- MenuItemComponent = MenuItem,
3488
+ menuItems,
3489
+ MenuItemComponent,
2797
3490
  itemToString: itemToString2 = itemToString,
2798
- getIsItemVisible = (item, inputValue) => itemToString2(item).toLowerCase().startsWith(inputValue.toLowerCase()),
3491
+ getIsItemVisible,
2799
3492
  ...useComboboxProps
2800
3493
  }) => {
2801
3494
  const { allMenuItems, children } = useMenuChildren({
2802
3495
  children: childrenProp,
2803
- items: itemsProp,
3496
+ menuItems,
2804
3497
  MenuItemComponent
2805
3498
  });
2806
- const [items, setItems] = React13.useState(allMenuItems);
3499
+ const { setHiddenItemsMap, defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({ isCombobox: true });
3500
+ const { updateFilteredItems } = useItemFiltering({
3501
+ allMenuItems,
3502
+ itemToString: itemToString2,
3503
+ getIsItemVisible,
3504
+ setHiddenItemsMap
3505
+ });
2807
3506
  const { isOpen, ...useComboboxReturnProps } = useCombobox2({
2808
- ...defaultUseComboboxProps,
2809
- items,
3507
+ ...defaultDownshiftProps.combobox,
3508
+ items: allMenuItems,
2810
3509
  itemToString: itemToString2,
2811
- onInputValueChange({ inputValue }) {
2812
- setItems(
2813
- inputValue ? allMenuItems.reduce(
2814
- (items2, item) => [
2815
- ...items2,
2816
- { ...item, hidden: !getIsItemVisible(item, inputValue) }
2817
- ],
2818
- []
2819
- ) : allMenuItems
2820
- );
3510
+ onInputValueChange: updateFilteredItems,
3511
+ stateReducer: reduceReducers(
3512
+ defaultDownshiftProps.combobox.stateReducer,
3513
+ externalStateReducer
3514
+ ),
3515
+ ...useComboboxProps
3516
+ });
3517
+ return /* @__PURE__ */ jsx20(
3518
+ MenuRoot,
3519
+ {
3520
+ ...{
3521
+ isListbox: true,
3522
+ items: allMenuItems,
3523
+ itemToString: itemToString2,
3524
+ isOpen,
3525
+ setHiddenItemsMap,
3526
+ ...useComboboxProps,
3527
+ ...useComboboxReturnProps,
3528
+ ...restDefaults
3529
+ },
3530
+ popoutProps: {
3531
+ focusOnContent: false
3532
+ },
3533
+ children
3534
+ }
3535
+ );
3536
+ };
3537
+
3538
+ // src/Autocomplete/MultiAutocomplete.tsx
3539
+ import React20 from "react";
3540
+ import { useCombobox as useCombobox3, useMultipleSelection as useMultipleSelection2 } from "downshift";
3541
+ import { jsx as jsx21 } from "react/jsx-runtime";
3542
+ var MultiAutocomplete = ({
3543
+ children: childrenProp,
3544
+ stateReducer: externalStateReducer,
3545
+ menuItems,
3546
+ MenuItemComponent,
3547
+ itemToString: itemToString2 = itemToString,
3548
+ itemToKey: itemToKey3 = itemToKey,
3549
+ getIsItemVisible = getDefaultGetIsItemVisible(itemToString2),
3550
+ showSelectedItemsInDropdown = false,
3551
+ initialSelectedItems = [],
3552
+ onStateChange,
3553
+ onSelectedItemsChange,
3554
+ getA11yMultiStatusMessage,
3555
+ onMultiSelectStateChange,
3556
+ multiSelectStateReducer,
3557
+ ...useComboboxProps
3558
+ }) => {
3559
+ const { allMenuItems, children } = useMenuChildren({
3560
+ children: childrenProp,
3561
+ menuItems,
3562
+ MenuItemComponent
3563
+ });
3564
+ const [selectedItems, setSelectedItems] = React20.useState(initialSelectedItems);
3565
+ const [selectedItemIds, setSelectedItemIds] = React20.useState(getSelectedItemIds(initialSelectedItems));
3566
+ const getIsItemVisibleMulti = React20.useCallback(
3567
+ (item, inputValue) => {
3568
+ return (showSelectedItemsInDropdown || !selectedItemIds[item.id]) && getIsItemVisible(item, inputValue);
2821
3569
  },
2822
- stateReducer: (state, actionAndChanges) => {
2823
- let newState;
2824
- newState = useComboboxStateReducer(state, actionAndChanges);
2825
- return externalStateReducer ? externalStateReducer(state, {
2826
- ...actionAndChanges,
2827
- changes: newState
2828
- }) : newState;
3570
+ [selectedItemIds, showSelectedItemsInDropdown, getIsItemVisible]
3571
+ );
3572
+ const getShouldFilterMulti = React20.useCallback(
3573
+ (args) => {
3574
+ return !showSelectedItemsInDropdown && Object.keys(selectedItemIds).length > 0 || defaultGetShouldFilter(args);
3575
+ },
3576
+ [selectedItemIds, showSelectedItemsInDropdown, getIsItemVisible]
3577
+ );
3578
+ const { setHiddenItemsMap, defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({
3579
+ isCombobox: true,
3580
+ isMulti: true,
3581
+ // handles the prop name mapping for multi select
3582
+ multiSelectProps: {
3583
+ getA11yMultiStatusMessage,
3584
+ onMultiSelectStateChange,
3585
+ multiSelectStateReducer,
3586
+ ...useComboboxProps
3587
+ }
3588
+ });
3589
+ const { updateFilteredItems } = useItemFiltering({
3590
+ allMenuItems,
3591
+ itemToString: itemToString2,
3592
+ getIsItemVisible: getIsItemVisibleMulti,
3593
+ getShouldFilter: getShouldFilterMulti,
3594
+ setHiddenItemsMap
3595
+ });
3596
+ React20.useEffect(() => {
3597
+ updateFilteredItems({ inputValue: "" });
3598
+ }, [selectedItemIds]);
3599
+ const useMultipleSelectionReturnProps = useMultipleSelection2({
3600
+ ...defaultDownshiftProps.multi,
3601
+ itemToKey: itemToKey3,
3602
+ selectedItems,
3603
+ onSelectedItemsChange: ({ selectedItems: selectedItems2, ...changes }) => {
3604
+ setSelectedItems(selectedItems2);
3605
+ setSelectedItemIds(getSelectedItemIds(selectedItems2));
3606
+ onSelectedItemsChange && onSelectedItemsChange({ selectedItems: selectedItems2, ...changes });
3607
+ }
3608
+ });
3609
+ const { isOpen, ...useComboboxReturnProps } = useCombobox3({
3610
+ ...defaultDownshiftProps.combobox,
3611
+ items: allMenuItems,
3612
+ itemToString: itemToString2,
3613
+ itemToKey: itemToKey3,
3614
+ stateReducer: reduceReducers(
3615
+ defaultDownshiftProps.combobox.stateReducer,
3616
+ externalStateReducer
3617
+ ),
3618
+ onStateChange(changes) {
3619
+ const { type, selectedItem: newSelectedItem, inputValue } = changes;
3620
+ switch (type) {
3621
+ // Add the selected item to the selected items list
3622
+ case useCombobox3.stateChangeTypes.InputKeyDownEnter:
3623
+ case useCombobox3.stateChangeTypes.ItemClick:
3624
+ if (newSelectedItem) {
3625
+ const newSelectedItems = [...selectedItems, newSelectedItem];
3626
+ setSelectedItems(newSelectedItems);
3627
+ setSelectedItemIds({
3628
+ ...selectedItemIds,
3629
+ [newSelectedItem.id]: true
3630
+ });
3631
+ onSelectedItemsChange && onSelectedItemsChange({
3632
+ selectedItems: newSelectedItems,
3633
+ type: useMultipleSelection2.stateChangeTypes.FunctionSetSelectedItems
3634
+ });
3635
+ }
3636
+ break;
3637
+ default:
3638
+ break;
3639
+ }
3640
+ if (inputValue !== void 0) updateFilteredItems({ inputValue });
3641
+ onStateChange && onStateChange(changes);
2829
3642
  },
2830
3643
  ...useComboboxProps
2831
3644
  });
2832
- return /* @__PURE__ */ jsx16(
3645
+ return /* @__PURE__ */ jsx21(
2833
3646
  MenuRoot,
2834
3647
  {
2835
3648
  ...{
2836
3649
  isListbox: true,
2837
- items,
3650
+ items: allMenuItems,
2838
3651
  itemToString: itemToString2,
2839
3652
  isOpen,
3653
+ initialSelectedItems,
3654
+ onStateChange,
3655
+ onSelectedItemsChange,
3656
+ getA11yMultiStatusMessage,
3657
+ onMultiSelectStateChange,
3658
+ multiSelectStateReducer,
3659
+ setHiddenItemsMap,
2840
3660
  ...useComboboxProps,
2841
- ...useComboboxReturnProps
3661
+ ...useComboboxReturnProps,
3662
+ ...useMultipleSelectionReturnProps,
3663
+ ...restDefaults
2842
3664
  },
2843
3665
  popoutProps: {
2844
3666
  focusOnContent: false
@@ -2848,10 +3670,22 @@ var Autocomplete = ({
2848
3670
  );
2849
3671
  };
2850
3672
 
3673
+ // src/Autocomplete/Autocomplete.tsx
3674
+ import { jsx as jsx22 } from "react/jsx-runtime";
3675
+ var Autocomplete = ({
3676
+ multiSelect,
3677
+ ...rest
3678
+ }) => {
3679
+ if (multiSelect) {
3680
+ return /* @__PURE__ */ jsx22(MultiAutocomplete, { ...rest });
3681
+ }
3682
+ return /* @__PURE__ */ jsx22(SingleAutocomplete, { ...rest });
3683
+ };
3684
+
2851
3685
  // src/Autocomplete/AutocompleteInput.tsx
2852
- import { useContext as useContext4 } from "react";
2853
- import { Input } from "@sproutsocial/seeds-react-input";
2854
- import { jsx as jsx17 } from "react/jsx-runtime";
3686
+ import "react";
3687
+ import { Input as Input2 } from "@sproutsocial/seeds-react-input";
3688
+ import { jsx as jsx23 } from "react/jsx-runtime";
2855
3689
  var AutocompleteInput = ({
2856
3690
  onKeyDown,
2857
3691
  onChange,
@@ -2861,61 +3695,316 @@ var AutocompleteInput = ({
2861
3695
  inputProps,
2862
3696
  ...rest
2863
3697
  }) => {
2864
- const { getInputProps, inputValue } = useContext4(MenuContext);
2865
- return /* @__PURE__ */ jsx17(
2866
- Input,
3698
+ const { getInputComponentProps, inputValue, ref, ariaProps } = useMenuToggleContext();
3699
+ return /* @__PURE__ */ jsx23(
3700
+ Input2,
2867
3701
  {
2868
3702
  id: "autocomplete_input",
2869
3703
  name: "autocomplete_input",
2870
- inputProps: {
2871
- ...getInputProps?.({
2872
- // refKey: "innerRef",
2873
- onKeyDown,
2874
- onChange,
2875
- onInput,
2876
- onBlur,
2877
- onClick,
2878
- value: inputValue
2879
- }),
2880
- ...inputProps
2881
- },
3704
+ ...getInputComponentProps({
3705
+ onKeyDown,
3706
+ onChange,
3707
+ onInput,
3708
+ onBlur,
3709
+ onClick,
3710
+ value: inputValue,
3711
+ ref,
3712
+ refKey: "innerRef",
3713
+ inputProps,
3714
+ ...ariaProps
3715
+ }),
2882
3716
  autoComplete: false,
2883
3717
  value: inputValue,
2884
3718
  ...rest
2885
3719
  }
2886
3720
  );
2887
3721
  };
3722
+
3723
+ // src/NestedMenu/NestedMenu.tsx
3724
+ import { useState } from "react";
3725
+
3726
+ // src/NestedMenu/NestedMenuContext.tsx
3727
+ import { createContext as createContext2, useContext as useContext4 } from "react";
3728
+ import { jsx as jsx24 } from "react/jsx-runtime";
3729
+ var defaultNestedMenuContext = {
3730
+ selectedMenuPath: [],
3731
+ setSelectedMenuId: () => {
3732
+ },
3733
+ setSelectedMenuPath: () => {
3734
+ },
3735
+ goBack: () => {
3736
+ }
3737
+ };
3738
+ var NestedMenuContext = createContext2(
3739
+ defaultNestedMenuContext
3740
+ );
3741
+ var NestedMenuProvider = ({
3742
+ children,
3743
+ ...nestedMenuProps
3744
+ }) => {
3745
+ return /* @__PURE__ */ jsx24(NestedMenuContext.Provider, { value: nestedMenuProps, children });
3746
+ };
3747
+ var useNestedMenuContext = () => {
3748
+ const nestedMenuContextValue = useContext4(NestedMenuContext);
3749
+ if (nestedMenuContextValue === null) {
3750
+ throw new Error(
3751
+ "useNestedMenuContext must be used within a <NestedMenuContext.Provider />"
3752
+ );
3753
+ }
3754
+ return nestedMenuContextValue;
3755
+ };
3756
+
3757
+ // src/NestedMenu/NestedMenuHeader.tsx
3758
+ import { Button as Button2 } from "@sproutsocial/seeds-react-button";
3759
+ import { Icon as Icon3 } from "@sproutsocial/seeds-react-icon";
3760
+ import { jsx as jsx25 } from "react/jsx-runtime";
3761
+ var NestedMenuHeader = ({
3762
+ backArrowLabel,
3763
+ ...props
3764
+ }) => {
3765
+ const { goBack, selectedMenuPath } = useNestedMenuContext();
3766
+ const showBackArrow = selectedMenuPath.length > 1;
3767
+ return /* @__PURE__ */ jsx25(
3768
+ MenuHeader,
3769
+ {
3770
+ leftAction: showBackArrow ? /* @__PURE__ */ jsx25(Button2, { onClick: goBack, ariaLabel: backArrowLabel, children: /* @__PURE__ */ jsx25(Icon3, { name: "arrow-left" }) }) : void 0,
3771
+ ...props
3772
+ }
3773
+ );
3774
+ };
3775
+
3776
+ // src/reducers/nestedMenuStateReducer.tsx
3777
+ import { useCombobox as useCombobox4, useSelect as useSelect5 } from "downshift";
3778
+ var nestedMenuStateReducer = (_state, actionAndChanges) => {
3779
+ const { type, changes } = actionAndChanges;
3780
+ const hasChildMenu = !!changes?.selectedItem?.menuItemProps?.childMenuId;
3781
+ if (!hasChildMenu) {
3782
+ return changes;
3783
+ }
3784
+ switch (type) {
3785
+ case useSelect5.stateChangeTypes.ToggleButtonBlur:
3786
+ case useSelect5.stateChangeTypes.ToggleButtonKeyDownEnter:
3787
+ case useSelect5.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
3788
+ case useSelect5.stateChangeTypes.ItemClick:
3789
+ case useCombobox4.stateChangeTypes.ItemClick:
3790
+ return {
3791
+ ...changes,
3792
+ isOpen: true,
3793
+ highlightedIndex: 0
3794
+ };
3795
+ default:
3796
+ return changes;
3797
+ }
3798
+ };
3799
+
3800
+ // src/NestedMenu/NestedMenuContent.tsx
3801
+ import { useEffect as useEffect3, useRef } from "react";
3802
+ import { mergeRefs as mergeRefs2 } from "@sproutsocial/seeds-react-utilities/src/index";
3803
+
3804
+ // src/NestedMenu/NestedMenuItem.tsx
3805
+ import { Icon as Icon4 } from "@sproutsocial/seeds-react-icon";
3806
+ import { Box as Box4 } from "@sproutsocial/seeds-react-box";
3807
+ import { jsx as jsx26, jsxs as jsxs5 } from "react/jsx-runtime";
3808
+ var NestedMenuItem = ({
3809
+ children,
3810
+ childMenuId,
3811
+ onClick: onClickProp,
3812
+ ...rest
3813
+ }) => {
3814
+ const { setSelectedMenuId } = useNestedMenuContext();
3815
+ const onClickProps = childMenuId ? {
3816
+ onClick: (e) => {
3817
+ onClickProp?.(e);
3818
+ setSelectedMenuId?.(childMenuId);
3819
+ }
3820
+ } : {};
3821
+ return /* @__PURE__ */ jsx26(MenuItem, { ...onClickProps, ...rest, children: /* @__PURE__ */ jsxs5(Box4, { display: "flex", justifyContent: "space-between", children: [
3822
+ children,
3823
+ childMenuId && /* @__PURE__ */ jsx26(MenuItemActionRight, { children: /* @__PURE__ */ jsx26(Icon4, { name: "arrow-right-outline" }) })
3824
+ ] }) });
3825
+ };
3826
+ NestedMenuItem.__MENU_PRIMITIVE_TYPE = "MenuItem";
3827
+
3828
+ // src/NestedMenu/NestedMenuContent.tsx
3829
+ import { jsx as jsx27 } from "react/jsx-runtime";
3830
+ var NestedMenuContent = ({
3831
+ innerRef: innerRefProp = null,
3832
+ onKeyDown: onKeyDownProp,
3833
+ children,
3834
+ menuItems,
3835
+ MenuItemComponent = NestedMenuItem,
3836
+ ...props
3837
+ }) => {
3838
+ const { highlightedIndex, items } = useMenuContentContext();
3839
+ const { setSelectedMenuId, selectedMenuPath, goBack } = useNestedMenuContext();
3840
+ const internalRef = useRef(null);
3841
+ const innerRef = mergeRefs2(internalRef, innerRefProp);
3842
+ const contentProps = children ? { children } : { menuItems, MenuItemComponent };
3843
+ useEffect3(() => {
3844
+ internalRef?.current?.focus();
3845
+ }, []);
3846
+ const onKeyDown = (e) => {
3847
+ onKeyDownProp?.(e);
3848
+ switch (e.key) {
3849
+ case "ArrowRight":
3850
+ case " ":
3851
+ case "Enter":
3852
+ if (highlightedIndex !== void 0 && highlightedIndex !== -1) {
3853
+ const item = items[highlightedIndex];
3854
+ if (item?.menuItemProps?.childMenuId !== void 0) {
3855
+ setSelectedMenuId?.(item?.menuItemProps?.childMenuId);
3856
+ }
3857
+ }
3858
+ break;
3859
+ case "ArrowLeft":
3860
+ if (selectedMenuPath.length > 1) {
3861
+ goBack?.();
3862
+ }
3863
+ break;
3864
+ }
3865
+ };
3866
+ return /* @__PURE__ */ jsx27(
3867
+ MenuContent,
3868
+ {
3869
+ onKeyDown,
3870
+ innerRef,
3871
+ ...contentProps,
3872
+ ...props
3873
+ }
3874
+ );
3875
+ };
3876
+ NestedMenuContent.__MENU_PRIMITIVE_TYPE = "MenuContent";
3877
+
3878
+ // src/NestedMenu/NestedMenu.tsx
3879
+ import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs6 } from "react/jsx-runtime";
3880
+ var NestedMenu = ({
3881
+ initialMenuId,
3882
+ menus,
3883
+ onBackButtonClick,
3884
+ backArrowLabel,
3885
+ menuToggleElement
3886
+ }) => {
3887
+ const [selectedMenuPath, setSelectedMenuPath] = useState([initialMenuId]);
3888
+ const selectedMenuId = selectedMenuPath[selectedMenuPath.length - 1];
3889
+ const setSelectedMenuId = (id) => {
3890
+ setSelectedMenuPath((currentPath) => [...currentPath, id]);
3891
+ };
3892
+ const goBack = () => {
3893
+ setSelectedMenuPath((currentPath) => currentPath.slice(0, -1));
3894
+ onBackButtonClick?.(selectedMenuId);
3895
+ };
3896
+ const {
3897
+ MenuComponent,
3898
+ menuProps,
3899
+ MenuHeaderComponent = NestedMenuHeader,
3900
+ menuHeaderProps = {}
3901
+ } = menus[selectedMenuId] || {};
3902
+ const {
3903
+ children,
3904
+ menuItems,
3905
+ MenuItemComponent,
3906
+ stateReducer: externalStateReducer,
3907
+ onStateChange: externalOnStateChange,
3908
+ ...props
3909
+ } = menuProps || {};
3910
+ const stateReducer = reduceReducers(
3911
+ nestedMenuStateReducer,
3912
+ externalStateReducer
3913
+ );
3914
+ const onStateChange = (changes) => {
3915
+ externalOnStateChange?.(changes);
3916
+ if (changes.isOpen === false) {
3917
+ setTimeout(() => {
3918
+ setSelectedMenuPath([initialMenuId]);
3919
+ }, 100);
3920
+ }
3921
+ };
3922
+ const nestedMenuProps = {
3923
+ menuToggleElement,
3924
+ stateReducer,
3925
+ onStateChange,
3926
+ initialIsOpen: selectedMenuPath.length > 1,
3927
+ children: /* @__PURE__ */ jsxs6(Fragment4, { children: [
3928
+ MenuHeaderComponent && /* @__PURE__ */ jsx28(
3929
+ MenuHeaderComponent,
3930
+ {
3931
+ backArrowLabel,
3932
+ ...menuHeaderProps
3933
+ }
3934
+ ),
3935
+ children && children,
3936
+ menuItems && !children && /* @__PURE__ */ jsx28(
3937
+ NestedMenuContent,
3938
+ {
3939
+ menuItems,
3940
+ MenuItemComponent: MenuItemComponent ?? NestedMenuItem
3941
+ }
3942
+ )
3943
+ ] }),
3944
+ ...props
3945
+ };
3946
+ return /* @__PURE__ */ jsx28(
3947
+ NestedMenuProvider,
3948
+ {
3949
+ selectedMenuPath,
3950
+ setSelectedMenuPath,
3951
+ setSelectedMenuId,
3952
+ goBack,
3953
+ children: MenuComponent && /* @__PURE__ */ jsx28(MenuComponent, { ...nestedMenuProps })
3954
+ }
3955
+ );
3956
+ };
2888
3957
  export {
2889
3958
  ActionMenu,
2890
3959
  Autocomplete,
2891
3960
  AutocompleteInput,
2892
3961
  INPUT_TYPES,
2893
3962
  MenuContent,
2894
- MenuContext,
3963
+ MenuContentContext,
3964
+ MenuContentProvider,
2895
3965
  MenuFooter,
2896
3966
  MenuGroup,
2897
3967
  MenuHeader,
2898
3968
  MenuItem,
2899
3969
  MenuItemAction,
3970
+ MenuItemActionLeft,
3971
+ MenuItemActionRight,
2900
3972
  MenuItemContainer,
2901
3973
  MenuItemRow,
2902
3974
  MenuItemText,
2903
3975
  MenuLabel,
2904
- MenuProvider,
2905
3976
  MenuRoot,
3977
+ MenuSearchInput,
3978
+ MenuSearchTokenInput,
2906
3979
  MenuToggleButton,
3980
+ MenuToggleContext,
3981
+ MenuToggleProvider,
3982
+ MenuTokenInput,
2907
3983
  MultiSelectMenu,
3984
+ NestedMenu,
3985
+ NestedMenuContent,
3986
+ NestedMenuContext,
3987
+ NestedMenuHeader,
3988
+ NestedMenuItem,
3989
+ NestedMenuProvider,
2908
3990
  SingleSelectMenu,
2909
3991
  StyledMenuGroup,
2910
3992
  StyledMenuGroupUl,
2911
3993
  StyledMenuItem,
2912
3994
  StyledTitle,
2913
- defaultUseSelectProps,
3995
+ SubmenuItem,
3996
+ checkIfItemSelected,
3997
+ defaultMenuContext,
3998
+ getChildrenFromMenuItems,
3999
+ getSelectedItemIds,
2914
4000
  mapMenuItems,
2915
4001
  useMenu,
2916
4002
  useMenuChildren,
2917
- useMenuContext,
2918
- useSelectStateReducer
4003
+ useMenuContentContext,
4004
+ useMenuToggleContext,
4005
+ useNestedMenuContext,
4006
+ useSelectStateReducer,
4007
+ useSelectStateReducerForMulti
2919
4008
  };
2920
4009
  /*! Bundled license information:
2921
4010