@sproutsocial/seeds-react-menu 0.2.3 → 0.4.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 (39) hide show
  1. package/.turbo/turbo-build.log +10 -10
  2. package/CHANGELOG.md +27 -0
  3. package/dist/esm/index.js +243 -75
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/index.d.mts +81 -49
  6. package/dist/index.d.ts +81 -49
  7. package/dist/index.js +237 -67
  8. package/dist/index.js.map +1 -1
  9. package/package.json +3 -1
  10. package/src/Autocomplete/Autocomplete.feature +14 -43
  11. package/src/Autocomplete/Autocomplete.stories.tsx +128 -0
  12. package/src/Autocomplete/Autocomplete.tsx +29 -11
  13. package/src/Autocomplete/AutocompleteInput.tsx +51 -0
  14. package/src/Autocomplete/AutocompleteTypes.ts +8 -1
  15. package/src/Autocomplete/__tests__/Autocomplete.test.tsx +142 -89
  16. package/src/Autocomplete/__tests__/Autocomplete.typetest.tsx +25 -43
  17. package/src/Autocomplete/index.ts +1 -0
  18. package/src/MenuContent/MenuContent.tsx +2 -2
  19. package/src/MenuContext.tsx +11 -5
  20. package/src/MenuGroup/MenuGroup.feature +19 -37
  21. package/src/MenuGroup/MenuGroup.tsx +18 -3
  22. package/src/MenuGroup/MenuGroupTypes.ts +6 -1
  23. package/src/MenuGroup/__tests__/MenuGroup.test.tsx +167 -9
  24. package/src/MenuGroup/__tests__/MenuGroup.typetest.tsx +27 -13
  25. package/src/MenuItem/MenuItem.tsx +7 -4
  26. package/src/MenuLabel.tsx +4 -4
  27. package/src/MenuRoot/MenuRoot.tsx +5 -3
  28. package/src/MenuRoot/__tests__/MenuRoot.test.tsx +1 -1
  29. package/src/MultiSelectMenu/MultiSelectMenu.tsx +8 -0
  30. package/src/MultiSelectMenu/__tests__/MultiSelectMenu.test.tsx +6 -6
  31. package/src/SingleSelectMenu/SingleSelectMenu.tsx +2 -2
  32. package/src/SingleSelectMenu/__tests__/SingleSelectMenu.test.tsx +3 -3
  33. package/src/__fixtures__/menu-test-data.ts +36 -0
  34. package/src/__tests__/Menu.test.tsx +29 -96
  35. package/src/hooks/useItemsFromChildren.tsx +71 -21
  36. package/src/index.ts +1 -0
  37. package/src/reducers/useComboboxStateReducer.tsx +11 -8
  38. package/src/storybookUtilities/menu-storybook-components.tsx +39 -0
  39. package/src/types.ts +3 -0
@@ -8,14 +8,14 @@ CLI Target: es2022
8
8
  CLI Cleaning output folder
9
9
  CJS Build start
10
10
  ESM Build start
11
- ESM dist/esm/index.js 80.44 KB
12
- ESM dist/esm/index.js.map 253.72 KB
13
- ESM ⚡️ Build success in 647ms
14
- CJS dist/index.js 85.04 KB
15
- CJS dist/index.js.map 254.58 KB
16
- CJS ⚡️ Build success in 676ms
11
+ CJS dist/index.js 90.75 KB
12
+ CJS dist/index.js.map 265.73 KB
13
+ CJS ⚡️ Build success in 873ms
14
+ ESM dist/esm/index.js 85.79 KB
15
+ ESM dist/esm/index.js.map 264.83 KB
16
+ ESM ⚡️ Build success in 888ms
17
17
  DTS Build start
18
- DTS ⚡️ Build success in 16400ms
19
- DTS dist/index.d.ts 15.61 KB
20
- DTS dist/index.d.mts 15.61 KB
21
- Done in 20.31s.
18
+ DTS ⚡️ Build success in 28301ms
19
+ DTS dist/index.d.ts 17.70 KB
20
+ DTS dist/index.d.mts 17.70 KB
21
+ Done in 36.29s.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @sproutsocial/seeds-react-menu
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 1e8337a: Added the Autocomplete and AutocompleteInput components, which can be used to make a text-based, single-select autocomplete form input.
8
+ - cc584e7: Adds items prop to MenuGroup
9
+ - Allows passing an array of `items` to the `MenuGroup` component
10
+ - Updates `TypeMenuGroupProps` to require either `children` or `items`
11
+ - Adds `MenuItemComponent` to `TypeMenuGroupProps` to allow custom rendering of menu items
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [1e8337a]
16
+ - @sproutsocial/seeds-react-input@1.3.1
17
+
18
+ ## 0.3.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 1178353: Implements isSingleSelect prop on MenuGroup
23
+ - This prop allows you to specify that only one item in the MenuGroup can be selected at a time.
24
+ - This prop is necessary if you need to combine multiple single-select MenuGroups or a mix of single-select and multi-select MenuGroups within a single Menu.
25
+ - In this case, you should use MultiSelectMenu and set isSingleSelect to true on the MenuGroup(s) that should only allow one selection.
26
+ - By contrast, the SingleSelectMenu component only allows one item to be selected across all MenuGroups.
27
+ - If you only have one MenuGroup, or if you only want to allow a single selection across all MenuGroups, you should use SingleSelectMenu instead.
28
+ - SingleSelectMenu ignores the `isSingleSelect` prop on MenuGroup.
29
+
3
30
  ## 0.2.3
4
31
 
5
32
  ### Patch Changes
package/dist/esm/index.js CHANGED
@@ -95,7 +95,7 @@ var require_object_assign = __commonJS({
95
95
  });
96
96
 
97
97
  // src/MenuItem/MenuItem.tsx
98
- import { useContext as useContext3 } from "react";
98
+ import "react";
99
99
 
100
100
  // src/MenuContext.tsx
101
101
  import {
@@ -112,15 +112,18 @@ var useMenu = ({
112
112
  items = [],
113
113
  isListbox = false,
114
114
  isOpen = false,
115
+ itemsMap: itemsMapFromProps,
115
116
  ...rest
116
117
  } = {}) => {
117
118
  const menuProps = useMemo(() => ({ ...rest }), [rest]);
118
119
  const itemsMap = useMemo(
119
- () => items.reduce((map, item) => {
120
- map[`${item.id}`] = item;
120
+ () => itemsMapFromProps || items.reduce((map, item) => {
121
+ map[`${item.id}`] = {
122
+ ...item
123
+ };
121
124
  return map;
122
125
  }, {}),
123
- [items]
126
+ [items, itemsMapFromProps]
124
127
  );
125
128
  return {
126
129
  isOpen,
@@ -133,9 +136,9 @@ var useMenu = ({
133
136
  var MenuContext = createContext(defaultMenuContext);
134
137
  var MenuProvider = ({
135
138
  children,
136
- ...overrides
139
+ menuProps
137
140
  }) => {
138
- const filterContext = useMenu(overrides);
141
+ const filterContext = useMenu(menuProps);
139
142
  return /* @__PURE__ */ jsx(MenuContext.Provider, { value: { ...filterContext }, children });
140
143
  };
141
144
  var useMenuContext = () => {
@@ -222,8 +225,7 @@ function _isNativeReflectConstruct() {
222
225
 
223
226
  // ../../node_modules/@babel/runtime/helpers/esm/construct.js
224
227
  function _construct(t, e, r) {
225
- if (_isNativeReflectConstruct())
226
- return Reflect.construct.apply(null, arguments);
228
+ if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
227
229
  var o = [null];
228
230
  o.push.apply(o, e);
229
231
  var p = new (t.bind.apply(t, o))();
@@ -234,14 +236,12 @@ function _construct(t, e, r) {
234
236
  function _wrapNativeSuper(Class) {
235
237
  var _cache = typeof Map === "function" ? /* @__PURE__ */ new Map() : void 0;
236
238
  _wrapNativeSuper = function _wrapNativeSuper2(Class2) {
237
- if (Class2 === null || !_isNativeFunction(Class2))
238
- return Class2;
239
+ if (Class2 === null || !_isNativeFunction(Class2)) return Class2;
239
240
  if (typeof Class2 !== "function") {
240
241
  throw new TypeError("Super expression must either be null or a function");
241
242
  }
242
243
  if (typeof _cache !== "undefined") {
243
- if (_cache.has(Class2))
244
- return _cache.get(Class2);
244
+ if (_cache.has(Class2)) return _cache.get(Class2);
245
245
  _cache.set(Class2, Wrapper);
246
246
  }
247
247
  function Wrapper() {
@@ -564,8 +564,7 @@ var namedColorMap = {
564
564
  yellowgreen: "9acd32"
565
565
  };
566
566
  function nameToHex(color2) {
567
- if (typeof color2 !== "string")
568
- return color2;
567
+ if (typeof color2 !== "string") return color2;
569
568
  var normalizedColorName = color2.toLowerCase();
570
569
  return namedColorMap[normalizedColorName] ? "#" + namedColorMap[normalizedColorName] : color2;
571
570
  }
@@ -708,8 +707,7 @@ function guard(lowerBoundary, upperBoundary, value) {
708
707
  return Math.max(lowerBoundary, Math.min(upperBoundary, value));
709
708
  }
710
709
  function transparentize(amount, color2) {
711
- if (color2 === "transparent")
712
- return color2;
710
+ if (color2 === "transparent") return color2;
713
711
  var parsedColor = parseToRgb(color2);
714
712
  var alpha = typeof parsedColor.alpha === "number" ? parsedColor.alpha : 1;
715
713
  var colorWithAlpha = _extends({}, parsedColor, {
@@ -719,7 +717,7 @@ function transparentize(amount, color2) {
719
717
  }
720
718
  var curriedTransparentize = /* @__PURE__ */ curry(transparentize);
721
719
 
722
- // ../seeds-react-mixins/src/index.ts
720
+ // ../seeds-react-mixins/dist/esm/index.js
723
721
  import { css } from "styled-components";
724
722
  import { theme } from "@sproutsocial/seeds-react-theme";
725
723
  var visuallyHidden = css`
@@ -759,8 +757,7 @@ var merge = function merge2(a, b) {
759
757
  var result = (0, import_object_assign.default)({}, a, b);
760
758
  for (var key in a) {
761
759
  var _assign;
762
- if (!a[key] || typeof b[key] !== "object")
763
- continue;
760
+ if (!a[key] || typeof b[key] !== "object") continue;
764
761
  (0, import_object_assign.default)(result, (_assign = {}, _assign[key] = (0, import_object_assign.default)(a[key], b[key]), _assign));
765
762
  }
766
763
  return result;
@@ -802,8 +799,7 @@ var createParser = function createParser2(config9) {
802
799
  var shouldSort = false;
803
800
  var isCacheDisabled = props.theme && props.theme.disableStyledSystemCache;
804
801
  for (var key in props) {
805
- if (!config9[key])
806
- continue;
802
+ if (!config9[key]) continue;
807
803
  var sx = config9[key];
808
804
  var raw = props[key];
809
805
  var scale = get(props.theme, sx.scale, sx.defaults);
@@ -877,8 +873,7 @@ var createStyleFunction = function createStyleFunction2(_ref) {
877
873
  var sx = function sx2(value, scale2, _props) {
878
874
  var result = {};
879
875
  var n = transform(value, scale2, _props);
880
- if (n === null)
881
- return;
876
+ if (n === null) return;
882
877
  properties.forEach(function(prop) {
883
878
  result[prop] = n;
884
879
  });
@@ -917,8 +912,7 @@ var compose = function compose2() {
917
912
  parsers[_key] = arguments[_key];
918
913
  }
919
914
  parsers.forEach(function(parser2) {
920
- if (!parser2 || !parser2.config)
921
- return;
915
+ if (!parser2 || !parser2.config) return;
922
916
  (0, import_object_assign.default)(config9, parser2.config);
923
917
  });
924
918
  var parser = createParser(config9);
@@ -1514,8 +1508,7 @@ var positiveOrNegative = function positiveOrNegative2(scale, value) {
1514
1508
  }
1515
1509
  var absolute = Math.abs(value);
1516
1510
  var n = get3(scale, absolute, absolute);
1517
- if (typeof n === "string")
1518
- return "-" + n;
1511
+ if (typeof n === "string") return "-" + n;
1519
1512
  return n * -1;
1520
1513
  };
1521
1514
  var transforms = ["margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "marginX", "marginY", "top", "bottom", "left", "right"].reduce(function(acc, curr) {
@@ -1531,8 +1524,7 @@ var responsive = function responsive2(styles) {
1531
1524
  }));
1532
1525
  for (var key in styles) {
1533
1526
  var value = typeof styles[key] === "function" ? styles[key](theme2) : styles[key];
1534
- if (value == null)
1535
- continue;
1527
+ if (value == null) continue;
1536
1528
  if (!Array.isArray(value)) {
1537
1529
  next[key] = value;
1538
1530
  continue;
@@ -1544,8 +1536,7 @@ var responsive = function responsive2(styles) {
1544
1536
  continue;
1545
1537
  }
1546
1538
  next[media] = next[media] || {};
1547
- if (value[i] == null)
1548
- continue;
1539
+ if (value[i] == null) continue;
1549
1540
  next[media][key] = value[i];
1550
1541
  }
1551
1542
  }
@@ -1887,7 +1878,7 @@ var useOptionProps = ({
1887
1878
  };
1888
1879
 
1889
1880
  // src/MenuItem/MenuItem.tsx
1890
- import { jsx as jsx3 } from "react/jsx-runtime";
1881
+ import { Fragment, jsx as jsx3 } from "react/jsx-runtime";
1891
1882
  var MenuItem = ({
1892
1883
  id,
1893
1884
  children,
@@ -1899,7 +1890,7 @@ var MenuItem = ({
1899
1890
  color: color2,
1900
1891
  ...props
1901
1892
  }) => {
1902
- const { getItemProps, itemsMap, highlightedIndex, isListbox } = useContext3(MenuContext);
1893
+ const { getItemProps, itemsMap, highlightedIndex, isListbox } = useMenuContext();
1903
1894
  const { ...optionProps } = useOptionProps({
1904
1895
  id,
1905
1896
  children,
@@ -1907,7 +1898,7 @@ var MenuItem = ({
1907
1898
  });
1908
1899
  const item = itemsMap[id] || { index: 0, id };
1909
1900
  const highlighted = highlightedIndex === item?.index;
1910
- return /* @__PURE__ */ jsx3(MenuItemContainer, { role: "none", children: /* @__PURE__ */ jsx3(
1901
+ return item.hidden ? /* @__PURE__ */ jsx3(Fragment, {}) : /* @__PURE__ */ jsx3(MenuItemContainer, { role: "none", children: /* @__PURE__ */ jsx3(
1911
1902
  StyledMenuItem,
1912
1903
  {
1913
1904
  id,
@@ -1998,7 +1989,7 @@ var MenuHeaderFeatures = styled2.div`
1998
1989
  `;
1999
1990
 
2000
1991
  // src/MenuHeader/MenuHeader.tsx
2001
- import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1992
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
2002
1993
  var MenuHeader = ({
2003
1994
  children,
2004
1995
  title,
@@ -2006,7 +1997,7 @@ var MenuHeader = ({
2006
1997
  rightAction,
2007
1998
  ...rest
2008
1999
  }) => {
2009
- return /* @__PURE__ */ jsx4(Fragment, { children: /* @__PURE__ */ jsxs2(MenuHeaderContainer, { $leftAction: !!leftAction, ...rest, children: [
2000
+ return /* @__PURE__ */ jsx4(Fragment2, { children: /* @__PURE__ */ jsxs2(MenuHeaderContainer, { $leftAction: !!leftAction, ...rest, children: [
2010
2001
  /* @__PURE__ */ jsxs2(MenuHeaderFeatures, { $leftAction: !!leftAction, children: [
2011
2002
  leftAction && leftAction,
2012
2003
  title && /* @__PURE__ */ jsx4(MenuTitleText, { $leftAction: !!leftAction, children: title }),
@@ -2094,9 +2085,7 @@ var Container = styled5.span`
2094
2085
  padding-left: 0;
2095
2086
  padding-right: 0;
2096
2087
  font-family: ${(props) => props.theme.fontFamily};
2097
- font-style: ${(props) => {
2098
- return props.isItalicized && "italic";
2099
- }};
2088
+ font-style: ${(props) => props.isItalicized && "italic"};
2100
2089
 
2101
2090
  ${(props) => props.truncated && css5`
2102
2091
  display: block;
@@ -2190,7 +2179,7 @@ var SmallBodyCopyWithLogic = withTextLogic(SmallBodyCopy);
2190
2179
  SmallBodyCopyWithLogic.displayName = "Text.SmallBodyCopy";
2191
2180
  Text.SmallBodyCopy = SmallBodyCopyWithLogic;
2192
2181
  var Text_default = Text;
2193
- var src_default = Text_default;
2182
+ var index_default = Text_default;
2194
2183
 
2195
2184
  // src/MenuGroup/styles.tsx
2196
2185
  var StyledMenuGroup = styled6.li`
@@ -2209,7 +2198,7 @@ var StyledMenuGroup = styled6.li`
2209
2198
  ${layout}
2210
2199
  ${space}
2211
2200
  `;
2212
- var StyledTitle = styled6(src_default.SmallSubHeadline)`
2201
+ var StyledTitle = styled6(index_default.SmallSubHeadline)`
2213
2202
  margin: ${({ theme: theme2 }) => theme2.space[400]} ${({ theme: theme2 }) => theme2.space[400]}
2214
2203
  0px ${({ theme: theme2 }) => theme2.space[400]};
2215
2204
  `;
@@ -2222,16 +2211,26 @@ var StyledMenuGroupUl = styled6.ul`
2222
2211
  import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
2223
2212
  var MenuGroup = ({
2224
2213
  titleAs = "h3",
2225
- children,
2214
+ children: childrenProp,
2226
2215
  title,
2227
2216
  color: color2,
2217
+ isSingleSelect,
2218
+ id,
2219
+ items,
2220
+ MenuItemComponent = MenuItem,
2228
2221
  ...rest
2229
2222
  }) => {
2230
2223
  const titleId = `menu-group-title-${Math.random().toString(36).slice(2, 11)}`;
2224
+ const children = childrenProp || !items || !items.length ? childrenProp : items.map((item) => /* @__PURE__ */ jsx8(MenuItemComponent, { ...item }, item.id));
2225
+ if (!children) {
2226
+ return null;
2227
+ }
2231
2228
  return /* @__PURE__ */ jsxs3(
2232
2229
  StyledMenuGroup,
2233
2230
  {
2234
2231
  role: "group",
2232
+ id,
2233
+ isSingleSelect,
2235
2234
  "aria-labelledby": title ? titleId : void 0,
2236
2235
  color: color2,
2237
2236
  ...rest,
@@ -2256,7 +2255,7 @@ var CustomPopoutContent = styled7(Popout.Content)`
2256
2255
  var MenuRoot = ({
2257
2256
  children,
2258
2257
  menuToggleElement,
2259
- popoutProps,
2258
+ popoutProps: { focusLockProps, ...popoutProps } = {},
2260
2259
  width: width2 = "300px",
2261
2260
  ...contextProps
2262
2261
  }) => {
@@ -2267,7 +2266,7 @@ var MenuRoot = ({
2267
2266
  },
2268
2267
  [openMenu, closeMenu]
2269
2268
  );
2270
- return /* @__PURE__ */ jsx9(MenuProvider, { ...contextProps, children: /* @__PURE__ */ jsx9(
2269
+ return /* @__PURE__ */ jsx9(MenuProvider, { menuProps: contextProps, children: /* @__PURE__ */ jsx9(
2271
2270
  Popout,
2272
2271
  {
2273
2272
  menuPopout: true,
@@ -2277,7 +2276,8 @@ var MenuRoot = ({
2277
2276
  focusLockProps: {
2278
2277
  // correct jerking motion when scrolling while the Popout is open
2279
2278
  // returnFocus: false,
2280
- crossFrame: false
2279
+ crossFrame: false,
2280
+ ...focusLockProps
2281
2281
  },
2282
2282
  disableWrapperAria: true,
2283
2283
  ...popoutProps,
@@ -2288,21 +2288,22 @@ var MenuRoot = ({
2288
2288
 
2289
2289
  // src/MenuLabel.tsx
2290
2290
  import "react";
2291
+ import { Label } from "@sproutsocial/seeds-react-label";
2291
2292
  import { jsx as jsx10 } from "react/jsx-runtime";
2292
2293
  var MenuLabel = ({ children, ...rest }) => {
2293
2294
  const { getLabelProps } = useMenuContext();
2294
- return /* @__PURE__ */ jsx10(Text_default, { as: "label", color: "text.body", ...getLabelProps?.(), ...rest, children });
2295
+ return /* @__PURE__ */ jsx10(Label, { htmlFor: "fallback_menu_label", ...getLabelProps?.(), ...rest, children });
2295
2296
  };
2296
2297
 
2297
2298
  // src/MenuToggleButton.tsx
2298
- import { useContext as useContext4 } from "react";
2299
+ import { useContext as useContext3 } from "react";
2299
2300
  import { Button } from "@sproutsocial/seeds-react-button";
2300
2301
  import { jsx as jsx11 } from "react/jsx-runtime";
2301
2302
  var MenuToggleButton = ({
2302
2303
  children,
2303
2304
  ...rest
2304
2305
  }) => {
2305
- const { getToggleButtonProps, isListbox, getDropdownProps } = useContext4(MenuContext);
2306
+ const { getToggleButtonProps, isListbox, getDropdownProps } = useContext3(MenuContext);
2306
2307
  return /* @__PURE__ */ jsx11(
2307
2308
  Button,
2308
2309
  {
@@ -2320,26 +2321,25 @@ var MenuToggleButton = ({
2320
2321
  };
2321
2322
 
2322
2323
  // src/ActionMenu/ActionMenu.tsx
2323
- import React11, { useEffect } from "react";
2324
+ import React10, { useEffect } from "react";
2324
2325
  import {
2325
2326
  useSelect as useSelect2
2326
2327
  } from "downshift";
2327
2328
 
2328
2329
  // src/hooks/useItemsFromChildren.tsx
2329
- import React10, { useMemo as useMemo3 } from "react";
2330
+ import React9, { useMemo as useMemo4 } from "react";
2330
2331
  var walkAllChildren = (children, callback) => {
2331
2332
  const walk = (element, parents2) => {
2332
- if (element === null || element === void 0)
2333
- return;
2333
+ if (element === null || element === void 0) return;
2334
2334
  callback(element, parents2);
2335
2335
  const newParents = [...parents2, element];
2336
2336
  const children2 = element.props?.children;
2337
- React10.Children.toArray(children2).forEach((child) => {
2337
+ React9.Children.toArray(children2).forEach((child) => {
2338
2338
  walk(child, newParents);
2339
2339
  });
2340
2340
  };
2341
2341
  const parents = [];
2342
- React10.Children.toArray(children).forEach((child) => {
2342
+ React9.Children.toArray(children).forEach((child) => {
2343
2343
  walk(child, parents);
2344
2344
  });
2345
2345
  };
@@ -2347,35 +2347,76 @@ var checkIfIsElement = (element, name) => {
2347
2347
  return !!(element && typeof element === "object" && "type" in element && typeof element.type !== "string" && typeof element.type.name === "string" && element.type.name === name);
2348
2348
  };
2349
2349
  var getAllMenuItems = (children) => {
2350
- const allMenuItems = [];
2351
- walkAllChildren(children, (element, parents) => {
2350
+ const orderedElements = [];
2351
+ walkAllChildren(children, (element) => {
2352
2352
  if (checkIfIsElement(element, "MenuItem")) {
2353
- allMenuItems.push({
2354
- element,
2355
- parents
2353
+ orderedElements.push({
2354
+ type: "item",
2355
+ element
2356
+ });
2357
+ } else if (checkIfIsElement(element, "MenuGroup")) {
2358
+ orderedElements.push({
2359
+ type: "group",
2360
+ element
2356
2361
  });
2357
2362
  }
2358
2363
  });
2359
- return allMenuItems;
2364
+ return { orderedElements };
2360
2365
  };
2361
2366
  var useItemsFromChildren = ({
2362
2367
  children
2363
2368
  }) => {
2364
- const { allMenuItems, menuItemsMap } = useMemo3(() => {
2365
- const allMenuItemElements = getAllMenuItems(children);
2369
+ const { allMenuItems, menuItemsMap } = useMemo4(() => {
2370
+ const { orderedElements } = getAllMenuItems(children);
2366
2371
  const menuItemsMap2 = {};
2367
- const allMenuItems2 = allMenuItemElements.map(
2368
- ({ element }, index) => {
2372
+ const allMenuItems2 = [];
2373
+ let index = 0;
2374
+ orderedElements.forEach(({ type, element }) => {
2375
+ if (type === "group") {
2376
+ const menuGroup = element;
2377
+ const items = menuGroup.props.items;
2378
+ if (items) {
2379
+ items.forEach((menuItem) => {
2380
+ const item = {
2381
+ id: menuItem.id,
2382
+ index: index++,
2383
+ disabled: menuItem.disabled,
2384
+ menuItemProps: menuItem,
2385
+ menuGroupProps: element.props
2386
+ };
2387
+ allMenuItems2.push(item);
2388
+ menuItemsMap2[`${item.id}`] = item;
2389
+ });
2390
+ } else if (menuGroup.props.children) {
2391
+ let children2 = menuGroup.props.children;
2392
+ if (!Array.isArray(children2)) {
2393
+ children2 = [children2];
2394
+ }
2395
+ children2.forEach((menuItem) => {
2396
+ const item = {
2397
+ id: menuItem.props.id,
2398
+ index: index++,
2399
+ disabled: menuItem.props.disabled,
2400
+ menuItemProps: menuItem.props,
2401
+ menuGroupProps: element.props
2402
+ };
2403
+ allMenuItems2.push(item);
2404
+ menuItemsMap2[`${item.id}`] = item;
2405
+ });
2406
+ }
2407
+ } else {
2408
+ if (menuItemsMap2[`${element.props.id}`]) return;
2409
+ const menuItem = element;
2369
2410
  const item = {
2370
- id: element.props.id,
2371
- disabled: element.props.disabled,
2372
- index,
2373
- menuItemProps: element.props
2411
+ id: menuItem.props.id,
2412
+ index: index++,
2413
+ disabled: menuItem.props.disabled,
2414
+ menuItemProps: menuItem.props
2374
2415
  };
2416
+ allMenuItems2.push(item);
2375
2417
  menuItemsMap2[`${item.id}`] = item;
2376
- return item;
2377
2418
  }
2378
- );
2419
+ });
2379
2420
  return { allMenuItems: allMenuItems2, menuItemsMap: menuItemsMap2 };
2380
2421
  }, [children]);
2381
2422
  return { allMenuItems, menuItemsMap };
@@ -2386,12 +2427,14 @@ import { useSelect } from "downshift";
2386
2427
  var useSelectStateReducer = (state, actionAndChanges) => {
2387
2428
  const { type, changes } = actionAndChanges;
2388
2429
  switch (type) {
2430
+ /** If downshift is blurred by tabbing within the menu, stay open */
2389
2431
  case useSelect.stateChangeTypes.ToggleButtonBlur:
2390
2432
  return {
2391
2433
  ...changes,
2392
2434
  // keep menu open on blur
2393
2435
  isOpen: true
2394
2436
  };
2437
+ /** Return standard change payload */
2395
2438
  default:
2396
2439
  return changes;
2397
2440
  }
@@ -2413,8 +2456,7 @@ var handleStateChange = (changes, currentSelectedItem) => {
2413
2456
  return;
2414
2457
  }
2415
2458
  const selectedItem = changes.selectedItem || currentSelectedItem;
2416
- if (!selectedItem)
2417
- return;
2459
+ if (!selectedItem) return;
2418
2460
  if (selectedItem.disabled) {
2419
2461
  return;
2420
2462
  }
@@ -2446,7 +2488,7 @@ var ActionMenu = ({
2446
2488
  ...useSelectProps
2447
2489
  }) => {
2448
2490
  const { allMenuItems, menuItemsMap } = useItemsFromChildren({ children });
2449
- const [currentSelectedItem, setCurrentSelectedItem] = React11.useState(null);
2491
+ const [currentSelectedItem, setCurrentSelectedItem] = React10.useState(null);
2450
2492
  const { isOpen, ...useSelectReturnProps } = useSelect2({
2451
2493
  ...defaultUseSelectProps,
2452
2494
  items: allMenuItems,
@@ -2597,13 +2639,18 @@ var MultiSelectMenu = ({
2597
2639
  case useSelect4.stateChangeTypes.ToggleButtonKeyDownEnter:
2598
2640
  case useSelect4.stateChangeTypes.ToggleButtonKeyDownSpaceButton:
2599
2641
  case useSelect4.stateChangeTypes.ItemClick:
2600
- if (!newSelectedItem)
2601
- break;
2642
+ if (!newSelectedItem) break;
2602
2643
  if (selectedItems?.find((item) => item?.id === newSelectedItem.id)) {
2603
2644
  removeSelectedItem(newSelectedItem);
2604
2645
  } else {
2605
2646
  addSelectedItem(newSelectedItem);
2606
2647
  }
2648
+ if (newSelectedItem.menuGroupProps?.isSingleSelect) {
2649
+ const groupItems = selectedItems.filter(
2650
+ (item) => item.menuGroupProps?.id === newSelectedItem.menuGroupProps?.id
2651
+ );
2652
+ groupItems.forEach((item) => removeSelectedItem(item));
2653
+ }
2607
2654
  break;
2608
2655
  default:
2609
2656
  break;
@@ -2636,8 +2683,129 @@ var MultiSelectMenu = ({
2636
2683
  }
2637
2684
  );
2638
2685
  };
2686
+
2687
+ // src/Autocomplete/Autocomplete.tsx
2688
+ import React13 from "react";
2689
+ import { useCombobox as useCombobox2 } from "downshift";
2690
+
2691
+ // src/reducers/useComboboxStateReducer.tsx
2692
+ import { useCombobox } from "downshift";
2693
+ var useComboboxStateReducer = (state, actionAndChanges) => {
2694
+ const { type, changes } = actionAndChanges;
2695
+ switch (type) {
2696
+ /** If downshift is blurred by tabbing within the menu, stay open */
2697
+ case useCombobox.stateChangeTypes.InputBlur:
2698
+ return {
2699
+ ...changes,
2700
+ // keep menu open on blur
2701
+ isOpen: true
2702
+ };
2703
+ /** Return standard change payload */
2704
+ default:
2705
+ return changes;
2706
+ }
2707
+ };
2708
+ var defaultUseComboboxProps = {
2709
+ // disabling while item.hidden so that hidden items are ignored by downshift
2710
+ isItemDisabled: (item) => Boolean(item.disabled || item.hidden)
2711
+ };
2712
+
2713
+ // src/Autocomplete/Autocomplete.tsx
2714
+ import { jsx as jsx15 } from "react/jsx-runtime";
2715
+ var Autocomplete = ({
2716
+ children,
2717
+ stateReducer: externalStateReducer,
2718
+ itemToString: itemToString2 = itemToString,
2719
+ getIsItemVisible = (item, inputValue) => itemToString2(item).toLowerCase().startsWith(inputValue.toLowerCase()),
2720
+ ...useComboboxProps
2721
+ }) => {
2722
+ const { allMenuItems } = useItemsFromChildren({ children });
2723
+ const [items, setItems] = React13.useState(allMenuItems);
2724
+ const { isOpen, ...useComboboxReturnProps } = useCombobox2({
2725
+ ...defaultUseComboboxProps,
2726
+ items,
2727
+ itemToString: itemToString2,
2728
+ onInputValueChange({ inputValue }) {
2729
+ setItems(
2730
+ inputValue ? allMenuItems.reduce(
2731
+ (items2, item) => [
2732
+ ...items2,
2733
+ { ...item, hidden: !getIsItemVisible(item, inputValue) }
2734
+ ],
2735
+ []
2736
+ ) : allMenuItems
2737
+ );
2738
+ },
2739
+ stateReducer: (state, actionAndChanges) => {
2740
+ let newState;
2741
+ newState = useComboboxStateReducer(state, actionAndChanges);
2742
+ return externalStateReducer ? externalStateReducer(state, {
2743
+ ...actionAndChanges,
2744
+ changes: newState
2745
+ }) : newState;
2746
+ },
2747
+ ...useComboboxProps
2748
+ });
2749
+ return /* @__PURE__ */ jsx15(
2750
+ MenuRoot,
2751
+ {
2752
+ ...{
2753
+ isListbox: true,
2754
+ items,
2755
+ itemToString: itemToString2,
2756
+ isOpen,
2757
+ ...useComboboxProps,
2758
+ ...useComboboxReturnProps
2759
+ },
2760
+ popoutProps: {
2761
+ focusOnContent: false
2762
+ },
2763
+ children
2764
+ }
2765
+ );
2766
+ };
2767
+
2768
+ // src/Autocomplete/AutocompleteInput.tsx
2769
+ import { useContext as useContext4 } from "react";
2770
+ import { Input } from "@sproutsocial/seeds-react-input";
2771
+ import { jsx as jsx16 } from "react/jsx-runtime";
2772
+ var AutocompleteInput = ({
2773
+ onKeyDown,
2774
+ onChange,
2775
+ onInput,
2776
+ onBlur,
2777
+ onClick,
2778
+ inputProps,
2779
+ ...rest
2780
+ }) => {
2781
+ const { getInputProps, inputValue } = useContext4(MenuContext);
2782
+ return /* @__PURE__ */ jsx16(
2783
+ Input,
2784
+ {
2785
+ id: "autocomplete_input",
2786
+ name: "autocomplete_input",
2787
+ inputProps: {
2788
+ ...getInputProps?.({
2789
+ // refKey: "innerRef",
2790
+ onKeyDown,
2791
+ onChange,
2792
+ onInput,
2793
+ onBlur,
2794
+ onClick,
2795
+ value: inputValue
2796
+ }),
2797
+ ...inputProps
2798
+ },
2799
+ autoComplete: false,
2800
+ value: inputValue,
2801
+ ...rest
2802
+ }
2803
+ );
2804
+ };
2639
2805
  export {
2640
2806
  ActionMenu,
2807
+ Autocomplete,
2808
+ AutocompleteInput,
2641
2809
  INPUT_TYPES,
2642
2810
  MenuContent,
2643
2811
  MenuContext,