@sproutsocial/seeds-react-menu 1.0.1 → 1.2.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 (44) hide show
  1. package/.turbo/turbo-build.log +86 -10
  2. package/CHANGELOG.md +44 -0
  3. package/dist/esm/index.js +537 -126
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/index.d.mts +47 -16
  6. package/dist/index.d.ts +47 -16
  7. package/dist/index.js +602 -184
  8. package/dist/index.js.map +1 -1
  9. package/package.json +5 -5
  10. package/src/ActionMenu/ActionMenu.tsx +4 -3
  11. package/src/ActionMenu/ActionMenuTypes.ts +5 -4
  12. package/src/ActionMenu/__tests__/ActionMenu.test.tsx +1 -1
  13. package/src/Autocomplete/Autocomplete.stories.tsx +124 -32
  14. package/src/Autocomplete/AutocompleteSelect.tsx +24 -0
  15. package/src/Autocomplete/AutocompleteTypes.ts +5 -2
  16. package/src/Autocomplete/MultiAutocomplete.tsx +3 -2
  17. package/src/Autocomplete/SingleAutocomplete.tsx +4 -4
  18. package/src/Autocomplete/index.ts +2 -0
  19. package/src/ListboxToggleButton.tsx +65 -0
  20. package/src/MenuContent/MenuContentTypes.ts +1 -2
  21. package/src/MenuContent/styles.tsx +6 -9
  22. package/src/MenuGroup/__tests__/MenuGroup.test.tsx +1 -1
  23. package/src/MenuItem/__tests__/MenuItem.test.tsx +1 -3
  24. package/src/MenuRoot/MenuRoot.tsx +95 -15
  25. package/src/MultiSelectMenu/MultiSelectMenu.stories.tsx +0 -1
  26. package/src/MultiSelectMenu/MultiSelectMenu.tsx +3 -2
  27. package/src/MultiSelectMenu/MultiSelectMenuTypes.ts +5 -3
  28. package/src/NestedMenu/NestedMenu.feature +1 -1
  29. package/src/NestedMenu/NestedMenu.stories.tsx +25 -7
  30. package/src/NestedMenu/NestedMenu.tsx +217 -43
  31. package/src/NestedMenu/NestedMenuContext.tsx +16 -0
  32. package/src/NestedMenu/NestedMenuHeader.tsx +19 -6
  33. package/src/NestedMenu/NestedMenuItem.tsx +11 -8
  34. package/src/NestedMenu/NestedMenuPopout.tsx +55 -0
  35. package/src/NestedMenu/NestedMenuRoot.tsx +27 -0
  36. package/src/NestedMenu/NestedMenuTypes.ts +3 -2
  37. package/src/NestedMenu/__tests__/NestedMenu.test.tsx +210 -19
  38. package/src/SingleSelectMenu/SingleSelectMenu.stories.tsx +0 -1
  39. package/src/SingleSelectMenu/SingleSelectMenu.tsx +3 -2
  40. package/src/SingleSelectMenu/SingleSelectMenuTypes.ts +5 -3
  41. package/src/__tests__/Menu.test.tsx +1 -1
  42. package/src/index.ts +1 -0
  43. package/src/storybookUtilities/menu-storybook-components.tsx +11 -31
  44. package/src/types.ts +5 -1
package/dist/esm/index.js CHANGED
@@ -2118,10 +2118,14 @@ var MenuHeader = ({
2118
2118
 
2119
2119
  // src/MenuContent/styles.tsx
2120
2120
  import styled3 from "styled-components";
2121
- import { motion } from "motion/react";
2122
- var StyledMenuContent = styled3(motion.ul)`
2121
+ var StyledMenuContent = styled3.ul`
2123
2122
  margin: 0;
2124
2123
  padding: 0;
2124
+
2125
+ &:focus {
2126
+ outline: none;
2127
+ box-shadow: none;
2128
+ }
2125
2129
  `;
2126
2130
 
2127
2131
  // src/hooks/useMenuChildren.tsx
@@ -2546,12 +2550,78 @@ MenuGroup.__MENU_PRIMITIVE_TYPE = "MenuGroup";
2546
2550
  import { useCallback as useCallback2, useEffect } from "react";
2547
2551
  import styled7 from "styled-components";
2548
2552
  import { Popout } from "@sproutsocial/seeds-react-popout";
2553
+
2554
+ // ../../seeds-design-tokens/seeds-motion/dist/seeds-motion-unitless.esm.js
2555
+ var MOTION_DURATION_FAST = 0.15;
2556
+
2557
+ // src/MenuRoot/MenuRoot.tsx
2549
2558
  import { jsx as jsx10 } from "react/jsx-runtime";
2550
2559
  var CustomPopoutContent = styled7(Popout.Content)`
2551
2560
  padding: 0;
2552
2561
  margin-left: 0;
2553
2562
  margin-right: 0;
2554
2563
  `;
2564
+ var menuAnimationConfig = {
2565
+ initial: {
2566
+ scale: 0,
2567
+ opacity: 0,
2568
+ originX: 0,
2569
+ originY: 0
2570
+ },
2571
+ animate: {
2572
+ opacity: 1,
2573
+ scale: 1,
2574
+ originX: 0,
2575
+ originY: 0,
2576
+ transition: {
2577
+ type: "tween",
2578
+ duration: MOTION_DURATION_FAST,
2579
+ ease: "circOut"
2580
+ }
2581
+ },
2582
+ exit: {
2583
+ opacity: 0,
2584
+ scale: 1,
2585
+ transition: {
2586
+ type: "tween",
2587
+ duration: MOTION_DURATION_FAST,
2588
+ ease: "circIn"
2589
+ }
2590
+ }
2591
+ };
2592
+ var MenuPopout = ({
2593
+ content,
2594
+ width: width2 = "300px",
2595
+ isOpen,
2596
+ openMenu,
2597
+ closeMenu,
2598
+ focusLockProps,
2599
+ ...popoutProps
2600
+ }) => {
2601
+ const setIsOpen = useCallback2(
2602
+ (newIsOpen) => {
2603
+ newIsOpen ? openMenu?.() : closeMenu?.();
2604
+ },
2605
+ [openMenu, closeMenu]
2606
+ );
2607
+ return /* @__PURE__ */ jsx10(
2608
+ Popout,
2609
+ {
2610
+ isOpen: !!isOpen,
2611
+ setIsOpen,
2612
+ content: (props) => /* @__PURE__ */ jsx10(CustomPopoutContent, { width: popoutProps.fullWidth ? "initial" : width2, children: typeof content === "function" ? content(props) : content }),
2613
+ focusLockProps: {
2614
+ // correct jerking motion when scrolling while the Popout is open
2615
+ // returnFocus: false,
2616
+ crossFrame: false,
2617
+ ...focusLockProps
2618
+ },
2619
+ disableWrapperAria: true,
2620
+ animationConfig: menuAnimationConfig,
2621
+ ...popoutProps
2622
+ }
2623
+ );
2624
+ };
2555
2625
  var MenuRoot = ({
2556
2626
  children,
2557
2627
  menuToggleElement,
@@ -2581,25 +2651,26 @@ var MenuRoot = ({
2581
2651
  }, [hiddenItemsCount, items?.length, isOpen, inputValue]);
2582
2652
  const menuContext = useMenu(contextProps);
2583
2653
  return /* @__PURE__ */ jsx10(
2584
- Popout,
2654
+ MenuPopout,
2585
2655
  {
2586
- menuPopout: true,
2587
2656
  placement,
2588
2657
  isOpen: !!isOpen,
2589
- setIsOpen,
2590
- content: /* @__PURE__ */ jsx10(MenuContentProvider, { menuContext, children: /* @__PURE__ */ jsx10(CustomPopoutContent, { width: width2, children }) }),
2591
- focusLockProps: {
2592
- // correct jerking motion when scrolling while the Popout is open
2593
- // returnFocus: false,
2594
- crossFrame: false,
2595
- ...focusLockProps
2596
- },
2597
- disableWrapperAria: true,
2658
+ openMenu,
2659
+ closeMenu,
2660
+ content: /* @__PURE__ */ jsx10(MenuContentProvider, { menuContext, children }),
2598
2661
  ...popoutProps,
2599
2662
  children: (toggleProps) => /* @__PURE__ */ jsx10(MenuToggleProvider, { menuContext: { ...menuContext, ...toggleProps }, children: menuToggleElement })
2600
2663
  }
2601
2664
  );
2602
2665
  };
2666
+ var MenuRootNoPopout = ({
2667
+ children,
2668
+ menuToggleElement,
2669
+ ...contextProps
2670
+ }) => {
2671
+ const menuContext = useMenu(contextProps);
2672
+ return /* @__PURE__ */ jsx10(MenuContentProvider, { menuContext, children });
2673
+ };
2603
2674
 
2604
2675
  // src/MenuLabel.tsx
2605
2676
  import "react";
@@ -3079,6 +3150,43 @@ var SubmenuItem = ({
3079
3150
  };
3080
3151
  SubmenuItem.__MENU_PRIMITIVE_TYPE = "MenuItem";
3081
3152
 
3153
+ // src/ListboxToggleButton.tsx
3154
+ import styled9, { css as css6 } from "styled-components";
3155
+ import { Icon as Icon3 } from "@sproutsocial/seeds-react-icon";
3156
+ import { jsx as jsx17, jsxs as jsxs5 } from "react/jsx-runtime";
3157
+ var StyledListboxToggleButton = styled9(
3158
+ MenuToggleButton
3159
+ )`
3160
+ ${(props) => props.invalid && css6`
3161
+ border-color: ${(props2) => props2.theme.colors.form.border.error};
3162
+ `}
3163
+ `;
3164
+ var StyledChevron = styled9.div`
3165
+ margin-left: ${({ theme: theme2 }) => theme2.space[300]};
3166
+ ${({ $isOpen }) => $isOpen && `
3167
+ transform: rotate(-180deg);
3168
+ `}
3169
+ transition: transform 0.15s;
3170
+
3171
+ ${({ invalid }) => invalid && css6`
3172
+ color: ${(props) => props.theme.colors.icon.error};
3173
+ `}
3174
+ `;
3175
+ var StyledInnerButton = styled9.div`
3176
+ display: flex;
3177
+ justify-content: space-between;
3178
+ `;
3179
+ var ListboxToggleButton = ({
3180
+ children,
3181
+ ...buttonProps
3182
+ }) => {
3183
+ const { isOpen } = useMenuToggleContext();
3184
+ return /* @__PURE__ */ jsx17(StyledListboxToggleButton, { appearance: "secondary", ...buttonProps, children: /* @__PURE__ */ jsxs5(StyledInnerButton, { children: [
3185
+ children,
3186
+ /* @__PURE__ */ jsx17(StyledChevron, { $isOpen: isOpen, invalid: buttonProps.invalid, children: /* @__PURE__ */ jsx17(Icon3, { name: "chevron-down-outline", fixedWidth: true, "aria-hidden": true }) })
3187
+ ] }) });
3188
+ };
3189
+
3082
3190
  // src/ActionMenu/ActionMenu.tsx
3083
3191
  import React16, { useEffect as useEffect2 } from "react";
3084
3192
  import {
@@ -3246,7 +3354,7 @@ var useDownshiftDefaults = ({
3246
3354
  };
3247
3355
 
3248
3356
  // src/ActionMenu/ActionMenu.tsx
3249
- import { jsx as jsx17 } from "react/jsx-runtime";
3357
+ import { jsx as jsx18 } from "react/jsx-runtime";
3250
3358
  var handleStateChange = (changes, currentSelectedItem) => {
3251
3359
  if (!(changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter || changes.type === useSelect2.stateChangeTypes.ToggleButtonKeyDownSpaceButton)) {
3252
3360
  return;
@@ -3283,6 +3391,7 @@ var ActionMenu = ({
3283
3391
  menuItems,
3284
3392
  MenuItemComponent,
3285
3393
  stateReducer: externalStateReducer,
3394
+ MenuRootComponent = MenuRoot,
3286
3395
  ...useSelectProps
3287
3396
  }) => {
3288
3397
  const { allMenuItems, menuItemsMap, children } = useMenuChildren({
@@ -3308,8 +3417,8 @@ var ActionMenu = ({
3308
3417
  useEffect2(() => {
3309
3418
  setCurrentSelectedItem(useSelectReturnProps.selectedItem);
3310
3419
  }, [useSelectReturnProps.selectedItem]);
3311
- return /* @__PURE__ */ jsx17(
3312
- MenuRoot,
3420
+ return /* @__PURE__ */ jsx18(
3421
+ MenuRootComponent,
3313
3422
  {
3314
3423
  ...{
3315
3424
  isListbox: false,
@@ -3329,12 +3438,13 @@ var ActionMenu = ({
3329
3438
  // src/SingleSelectMenu/SingleSelectMenu.tsx
3330
3439
  import "react";
3331
3440
  import { useSelect as useSelect3 } from "downshift";
3332
- import { jsx as jsx18 } from "react/jsx-runtime";
3441
+ import { jsx as jsx19 } from "react/jsx-runtime";
3333
3442
  var SingleSelectMenu = ({
3334
3443
  children: childrenProp,
3335
3444
  stateReducer: externalStateReducer,
3336
3445
  menuItems,
3337
3446
  MenuItemComponent,
3447
+ MenuRootComponent = MenuRoot,
3338
3448
  ...useSelectProps
3339
3449
  }) => {
3340
3450
  const { allMenuItems, menuItemsMap, children } = useMenuChildren({
@@ -3355,8 +3465,8 @@ var SingleSelectMenu = ({
3355
3465
  ),
3356
3466
  ...useSelectProps
3357
3467
  });
3358
- return /* @__PURE__ */ jsx18(
3359
- MenuRoot,
3468
+ return /* @__PURE__ */ jsx19(
3469
+ MenuRootComponent,
3360
3470
  {
3361
3471
  ...{
3362
3472
  isListbox: true,
@@ -3376,13 +3486,14 @@ var SingleSelectMenu = ({
3376
3486
  // src/MultiSelectMenu/MultiSelectMenu.tsx
3377
3487
  import "react";
3378
3488
  import { useSelect as useSelect4, useMultipleSelection } from "downshift";
3379
- import { jsx as jsx19 } from "react/jsx-runtime";
3489
+ import { jsx as jsx20 } from "react/jsx-runtime";
3380
3490
  var MultiSelectMenu = ({
3381
3491
  children: childrenProp,
3382
3492
  menuItems,
3383
3493
  MenuItemComponent,
3384
3494
  onSelectedItemChange: externalOnSelectedItemChange,
3385
3495
  stateReducer: externalStateReducer,
3496
+ MenuRootComponent = MenuRoot,
3386
3497
  getA11yMultiStatusMessage,
3387
3498
  onMultiSelectStateChange,
3388
3499
  multiSelectStateReducer,
@@ -3448,8 +3559,8 @@ var MultiSelectMenu = ({
3448
3559
  },
3449
3560
  ...useSelectProps
3450
3561
  });
3451
- return /* @__PURE__ */ jsx19(
3452
- MenuRoot,
3562
+ return /* @__PURE__ */ jsx20(
3563
+ MenuRootComponent,
3453
3564
  {
3454
3565
  ...{
3455
3566
  isListbox: true,
@@ -3481,11 +3592,12 @@ import "react";
3481
3592
  // src/Autocomplete/SingleAutocomplete.tsx
3482
3593
  import "react";
3483
3594
  import { useCombobox as useCombobox2 } from "downshift";
3484
- import { jsx as jsx20 } from "react/jsx-runtime";
3595
+ import { jsx as jsx21 } from "react/jsx-runtime";
3485
3596
  var SingleAutocomplete = ({
3486
3597
  children: childrenProp,
3487
3598
  stateReducer: externalStateReducer,
3488
3599
  menuItems,
3600
+ MenuRootComponent = MenuRoot,
3489
3601
  MenuItemComponent,
3490
3602
  itemToString: itemToString2 = itemToString,
3491
3603
  getIsItemVisible,
@@ -3514,8 +3626,8 @@ var SingleAutocomplete = ({
3514
3626
  ),
3515
3627
  ...useComboboxProps
3516
3628
  });
3517
- return /* @__PURE__ */ jsx20(
3518
- MenuRoot,
3629
+ return /* @__PURE__ */ jsx21(
3630
+ MenuRootComponent,
3519
3631
  {
3520
3632
  ...{
3521
3633
  isListbox: true,
@@ -3538,12 +3650,13 @@ var SingleAutocomplete = ({
3538
3650
  // src/Autocomplete/MultiAutocomplete.tsx
3539
3651
  import React20 from "react";
3540
3652
  import { useCombobox as useCombobox3, useMultipleSelection as useMultipleSelection2 } from "downshift";
3541
- import { jsx as jsx21 } from "react/jsx-runtime";
3653
+ import { jsx as jsx22 } from "react/jsx-runtime";
3542
3654
  var MultiAutocomplete = ({
3543
3655
  children: childrenProp,
3544
3656
  stateReducer: externalStateReducer,
3545
3657
  menuItems,
3546
3658
  MenuItemComponent,
3659
+ MenuRootComponent = MenuRoot,
3547
3660
  itemToString: itemToString2 = itemToString,
3548
3661
  itemToKey: itemToKey3 = itemToKey,
3549
3662
  getIsItemVisible = getDefaultGetIsItemVisible(itemToString2),
@@ -3642,8 +3755,8 @@ var MultiAutocomplete = ({
3642
3755
  },
3643
3756
  ...useComboboxProps
3644
3757
  });
3645
- return /* @__PURE__ */ jsx21(
3646
- MenuRoot,
3758
+ return /* @__PURE__ */ jsx22(
3759
+ MenuRootComponent,
3647
3760
  {
3648
3761
  ...{
3649
3762
  isListbox: true,
@@ -3671,21 +3784,21 @@ var MultiAutocomplete = ({
3671
3784
  };
3672
3785
 
3673
3786
  // src/Autocomplete/Autocomplete.tsx
3674
- import { jsx as jsx22 } from "react/jsx-runtime";
3787
+ import { jsx as jsx23 } from "react/jsx-runtime";
3675
3788
  var Autocomplete = ({
3676
3789
  multiSelect,
3677
3790
  ...rest
3678
3791
  }) => {
3679
3792
  if (multiSelect) {
3680
- return /* @__PURE__ */ jsx22(MultiAutocomplete, { ...rest });
3793
+ return /* @__PURE__ */ jsx23(MultiAutocomplete, { ...rest });
3681
3794
  }
3682
- return /* @__PURE__ */ jsx22(SingleAutocomplete, { ...rest });
3795
+ return /* @__PURE__ */ jsx23(SingleAutocomplete, { ...rest });
3683
3796
  };
3684
3797
 
3685
3798
  // src/Autocomplete/AutocompleteInput.tsx
3686
3799
  import "react";
3687
3800
  import { Input as Input2 } from "@sproutsocial/seeds-react-input";
3688
- import { jsx as jsx23 } from "react/jsx-runtime";
3801
+ import { jsx as jsx24 } from "react/jsx-runtime";
3689
3802
  var AutocompleteInput = ({
3690
3803
  onKeyDown,
3691
3804
  onChange,
@@ -3696,7 +3809,7 @@ var AutocompleteInput = ({
3696
3809
  ...rest
3697
3810
  }) => {
3698
3811
  const { getInputComponentProps, inputValue, ref, ariaProps } = useMenuToggleContext();
3699
- return /* @__PURE__ */ jsx23(
3812
+ return /* @__PURE__ */ jsx24(
3700
3813
  Input2,
3701
3814
  {
3702
3815
  id: "autocomplete_input",
@@ -3720,59 +3833,75 @@ var AutocompleteInput = ({
3720
3833
  );
3721
3834
  };
3722
3835
 
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";
3836
+ // src/Autocomplete/AutocompleteTokenInput.tsx
3837
+ import "react";
3760
3838
  import { jsx as jsx25 } from "react/jsx-runtime";
3761
- var NestedMenuHeader = ({
3762
- backArrowLabel,
3763
- ...props
3839
+ var AutocompleteTokenInput = ({
3840
+ onKeyDown,
3841
+ onChange,
3842
+ onInput,
3843
+ onBlur,
3844
+ onClick,
3845
+ inputProps,
3846
+ getTokenProps,
3847
+ ...rest
3764
3848
  }) => {
3765
- const { goBack, selectedMenuPath } = useNestedMenuContext();
3766
- const showBackArrow = selectedMenuPath.length > 1;
3849
+ const {
3850
+ getInputComponentProps,
3851
+ getDropdownProps,
3852
+ inputValue,
3853
+ isOpen,
3854
+ ref,
3855
+ ariaProps
3856
+ } = useMenuToggleContext();
3767
3857
  return /* @__PURE__ */ jsx25(
3768
- MenuHeader,
3858
+ MenuTokenInput,
3769
3859
  {
3770
- leftAction: showBackArrow ? /* @__PURE__ */ jsx25(Button2, { onClick: goBack, ariaLabel: backArrowLabel, children: /* @__PURE__ */ jsx25(Icon3, { name: "arrow-left" }) }) : void 0,
3860
+ id: "autocomplete_input",
3861
+ name: "autocomplete_input",
3862
+ ...getInputComponentProps({
3863
+ ...getDropdownProps?.({ ref, preventKeyAction: isOpen }) || { ref },
3864
+ onKeyDown,
3865
+ onChange,
3866
+ onInput,
3867
+ onBlur,
3868
+ onClick,
3869
+ value: inputValue,
3870
+ refKey: "innerRef",
3871
+ inputProps,
3872
+ ...ariaProps
3873
+ }),
3874
+ ...rest
3875
+ }
3876
+ );
3877
+ };
3878
+
3879
+ // src/Autocomplete/AutocompleteSelect.tsx
3880
+ import Icon4 from "@sproutsocial/seeds-react-icon";
3881
+ import "react";
3882
+ import styled10 from "styled-components";
3883
+ import { Accessory } from "@sproutsocial/seeds-react-input";
3884
+ import { jsx as jsx26 } from "react/jsx-runtime";
3885
+ var StyledAutocompleteInput = styled10(AutocompleteInput)`
3886
+ ${Accessory} {
3887
+ pointer-events: none;
3888
+ }
3889
+ `;
3890
+ var AutocompleteSelect = (props) => {
3891
+ return /* @__PURE__ */ jsx26(
3892
+ StyledAutocompleteInput,
3893
+ {
3894
+ elemAfter: /* @__PURE__ */ jsx26(Icon4, { name: "chevron-down" }),
3771
3895
  ...props
3772
3896
  }
3773
3897
  );
3774
3898
  };
3775
3899
 
3900
+ // src/NestedMenu/NestedMenu.tsx
3901
+ import { useId, useEffect as useEffect5, useState } from "react";
3902
+ import { AnimatePresence as AnimatePresence2, motion as motion3 } from "motion/react";
3903
+ import { useSelect as useSelect6 } from "downshift";
3904
+
3776
3905
  // src/reducers/nestedMenuStateReducer.tsx
3777
3906
  import { useCombobox as useCombobox4, useSelect as useSelect5 } from "downshift";
3778
3907
  var nestedMenuStateReducer = (_state, actionAndChanges) => {
@@ -3797,14 +3926,52 @@ var nestedMenuStateReducer = (_state, actionAndChanges) => {
3797
3926
  }
3798
3927
  };
3799
3928
 
3929
+ // src/NestedMenu/NestedMenuContext.tsx
3930
+ import { createContext as createContext2, useContext as useContext5 } from "react";
3931
+ import { jsx as jsx27 } from "react/jsx-runtime";
3932
+ var defaultNestedMenuContext = {
3933
+ selectedMenuPath: [],
3934
+ setSelectedMenuId: () => {
3935
+ },
3936
+ setSelectedMenuPath: () => {
3937
+ },
3938
+ resetSelectedMenuPath: () => {
3939
+ },
3940
+ goBack: () => {
3941
+ },
3942
+ rootMenuContextProps: {},
3943
+ activeMenuContext: defaultMenuContext,
3944
+ setActiveMenuContext: () => {
3945
+ },
3946
+ animationSpeed: MOTION_DURATION_FAST
3947
+ };
3948
+ var NestedMenuContext = createContext2(
3949
+ defaultNestedMenuContext
3950
+ );
3951
+ var NestedMenuProvider = ({
3952
+ children,
3953
+ ...nestedMenuProps
3954
+ }) => {
3955
+ return /* @__PURE__ */ jsx27(NestedMenuContext.Provider, { value: nestedMenuProps, children });
3956
+ };
3957
+ var useNestedMenuContext = () => {
3958
+ const nestedMenuContextValue = useContext5(NestedMenuContext);
3959
+ if (nestedMenuContextValue === null) {
3960
+ throw new Error(
3961
+ "useNestedMenuContext must be used within a <NestedMenuContext.Provider />"
3962
+ );
3963
+ }
3964
+ return nestedMenuContextValue;
3965
+ };
3966
+
3800
3967
  // src/NestedMenu/NestedMenuContent.tsx
3801
- import { useEffect as useEffect3, useRef } from "react";
3968
+ import { useEffect as useEffect4, useRef } from "react";
3802
3969
  import { mergeRefs as mergeRefs2 } from "@sproutsocial/seeds-react-utilities";
3803
3970
 
3804
3971
  // src/NestedMenu/NestedMenuItem.tsx
3805
- import { Icon as Icon4 } from "@sproutsocial/seeds-react-icon";
3972
+ import { Icon as Icon5 } from "@sproutsocial/seeds-react-icon";
3806
3973
  import { Box as Box4 } from "@sproutsocial/seeds-react-box";
3807
- import { jsx as jsx26, jsxs as jsxs5 } from "react/jsx-runtime";
3974
+ import { jsx as jsx28, jsxs as jsxs6 } from "react/jsx-runtime";
3808
3975
  var NestedMenuItem = ({
3809
3976
  children,
3810
3977
  childMenuId,
@@ -3812,21 +3979,23 @@ var NestedMenuItem = ({
3812
3979
  ...rest
3813
3980
  }) => {
3814
3981
  const { setSelectedMenuId } = useNestedMenuContext();
3815
- const onClickProps = childMenuId ? {
3982
+ const onClickProps = childMenuId || onClickProp ? {
3816
3983
  onClick: (e) => {
3817
3984
  onClickProp?.(e);
3818
- setSelectedMenuId?.(childMenuId);
3985
+ if (childMenuId) {
3986
+ setSelectedMenuId?.(childMenuId);
3987
+ }
3819
3988
  }
3820
3989
  } : {};
3821
- return /* @__PURE__ */ jsx26(MenuItem, { ...onClickProps, ...rest, children: /* @__PURE__ */ jsxs5(Box4, { display: "flex", justifyContent: "space-between", children: [
3990
+ return /* @__PURE__ */ jsx28(MenuItem, { ...onClickProps, ...rest, children: /* @__PURE__ */ jsxs6(Box4, { display: "flex", justifyContent: "space-between", children: [
3822
3991
  children,
3823
- childMenuId && /* @__PURE__ */ jsx26(MenuItemActionRight, { children: /* @__PURE__ */ jsx26(Icon4, { name: "arrow-right-outline" }) })
3992
+ childMenuId && /* @__PURE__ */ jsx28(MenuItemActionRight, { children: /* @__PURE__ */ jsx28(Icon5, { name: "arrow-right-outline" }) })
3824
3993
  ] }) });
3825
3994
  };
3826
3995
  NestedMenuItem.__MENU_PRIMITIVE_TYPE = "MenuItem";
3827
3996
 
3828
3997
  // src/NestedMenu/NestedMenuContent.tsx
3829
- import { jsx as jsx27 } from "react/jsx-runtime";
3998
+ import { jsx as jsx29 } from "react/jsx-runtime";
3830
3999
  var NestedMenuContent = ({
3831
4000
  innerRef: innerRefProp = null,
3832
4001
  onKeyDown: onKeyDownProp,
@@ -3840,7 +4009,7 @@ var NestedMenuContent = ({
3840
4009
  const internalRef = useRef(null);
3841
4010
  const innerRef = mergeRefs2(internalRef, innerRefProp);
3842
4011
  const contentProps = children ? { children } : { menuItems, MenuItemComponent };
3843
- useEffect3(() => {
4012
+ useEffect4(() => {
3844
4013
  internalRef?.current?.focus();
3845
4014
  }, []);
3846
4015
  const onKeyDown = (e) => {
@@ -3863,7 +4032,7 @@ var NestedMenuContent = ({
3863
4032
  break;
3864
4033
  }
3865
4034
  };
3866
- return /* @__PURE__ */ jsx27(
4035
+ return /* @__PURE__ */ jsx29(
3867
4036
  MenuContent,
3868
4037
  {
3869
4038
  onKeyDown,
@@ -3875,82 +4044,317 @@ var NestedMenuContent = ({
3875
4044
  };
3876
4045
  NestedMenuContent.__MENU_PRIMITIVE_TYPE = "MenuContent";
3877
4046
 
4047
+ // src/NestedMenu/NestedMenuHeader.tsx
4048
+ import { Button as Button2 } from "@sproutsocial/seeds-react-button";
4049
+ import { Icon as Icon6 } from "@sproutsocial/seeds-react-icon";
4050
+ import { AnimatePresence, motion } from "motion/react";
4051
+ import { jsx as jsx30 } from "react/jsx-runtime";
4052
+ var NestedMenuHeader = ({
4053
+ backArrowLabel,
4054
+ ...props
4055
+ }) => {
4056
+ const { goBack, selectedMenuPath, animationSpeed } = useNestedMenuContext();
4057
+ const showBackArrow = selectedMenuPath.length > 1;
4058
+ return /* @__PURE__ */ jsx30(
4059
+ MenuHeader,
4060
+ {
4061
+ leftAction: /* @__PURE__ */ jsx30(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsx30(
4062
+ motion.div,
4063
+ {
4064
+ initial: { opacity: 0 },
4065
+ animate: { opacity: 1 },
4066
+ exit: {
4067
+ opacity: 0,
4068
+ transition: { duration: animationSpeed }
4069
+ },
4070
+ children: showBackArrow ? /* @__PURE__ */ jsx30(Button2, { onClick: goBack, ariaLabel: backArrowLabel, children: /* @__PURE__ */ jsx30(Icon6, { name: "arrow-left" }) }) : void 0
4071
+ },
4072
+ `${selectedMenuPath}-header--button`
4073
+ ) }),
4074
+ ...props
4075
+ }
4076
+ );
4077
+ };
4078
+
4079
+ // src/NestedMenu/NestedMenuRoot.tsx
4080
+ import React25 from "react";
4081
+ import { jsx as jsx31 } from "react/jsx-runtime";
4082
+ var NestedMenuRoot = ({
4083
+ children,
4084
+ menuToggleElement,
4085
+ ...contextProps
4086
+ }) => {
4087
+ const menuContext = useMenu(contextProps);
4088
+ const { setActiveMenuContext, selectedMenuPath } = useNestedMenuContext();
4089
+ React25.useEffect(() => {
4090
+ setActiveMenuContext(menuContext);
4091
+ }, [
4092
+ selectedMenuPath[selectedMenuPath.length - 1],
4093
+ menuContext.selectedItem,
4094
+ menuContext.selectedItems?.length
4095
+ ]);
4096
+ return /* @__PURE__ */ jsx31(MenuContentProvider, { menuContext, children });
4097
+ };
4098
+
4099
+ // src/NestedMenu/NestedMenuPopout.tsx
4100
+ import { motion as motion2 } from "motion/react";
4101
+ import styled11 from "styled-components";
4102
+ import { jsx as jsx32 } from "react/jsx-runtime";
4103
+ var StyledDiv = styled11(motion2.div)`
4104
+ overflow: hidden;
4105
+ `;
4106
+ var NestedMenuPopout = ({
4107
+ content,
4108
+ menuToggleElement,
4109
+ width: width2,
4110
+ ...popoutProps
4111
+ }) => {
4112
+ const { activeMenuContext, rootMenuContextProps, resetSelectedMenuPath } = useNestedMenuContext();
4113
+ return /* @__PURE__ */ jsx32(
4114
+ MenuPopout,
4115
+ {
4116
+ ...popoutProps,
4117
+ onClose: () => setTimeout(() => resetSelectedMenuPath?.(), 100),
4118
+ isOpen: !!rootMenuContextProps.isOpen,
4119
+ openMenu: rootMenuContextProps.openMenu,
4120
+ closeMenu: rootMenuContextProps.closeMenu,
4121
+ width: width2,
4122
+ content: (props) => /* @__PURE__ */ jsx32(StyledDiv, { layout: "position", children: typeof content === "function" ? content(props) : content }),
4123
+ children: (toggleProps) => /* @__PURE__ */ jsx32(
4124
+ MenuToggleProvider,
4125
+ {
4126
+ menuContext: {
4127
+ ...activeMenuContext,
4128
+ ...rootMenuContextProps,
4129
+ ...toggleProps
4130
+ },
4131
+ children: menuToggleElement
4132
+ }
4133
+ )
4134
+ }
4135
+ );
4136
+ };
4137
+
3878
4138
  // src/NestedMenu/NestedMenu.tsx
3879
- import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs6 } from "react/jsx-runtime";
4139
+ import { jsx as jsx33, jsxs as jsxs7 } from "react/jsx-runtime";
3880
4140
  var NestedMenu = ({
3881
4141
  initialMenuId,
3882
4142
  menus,
3883
4143
  onBackButtonClick,
3884
4144
  backArrowLabel,
3885
- menuToggleElement
4145
+ menuToggleElement,
4146
+ popoutProps = {},
4147
+ width: width2 = "300px",
4148
+ stateReducer: rootExternalStateReducer,
4149
+ id: externalNestedMenuId,
4150
+ ...useSelectProps
3886
4151
  }) => {
4152
+ const { defaultDownshiftProps, ...restDefaults } = useDownshiftDefaults({
4153
+ isCombobox: false
4154
+ });
4155
+ const uniqueId = useId();
4156
+ const nestedMenuId = externalNestedMenuId ?? `nested-menu-${uniqueId}`;
4157
+ const [hasLoadedOnce, setHasLoadedOnce] = useState(false);
4158
+ const useSelectReturnProps = useSelect6({
4159
+ ...defaultDownshiftProps.select,
4160
+ id: nestedMenuId,
4161
+ items: [],
4162
+ stateReducer: reduceReducers(
4163
+ defaultDownshiftProps.select.stateReducer,
4164
+ rootExternalStateReducer
4165
+ ),
4166
+ ...useSelectProps
4167
+ });
4168
+ const rootMenuContextProps = {
4169
+ ...useSelectProps,
4170
+ ...useSelectReturnProps,
4171
+ ...restDefaults
4172
+ };
4173
+ useEffect5(() => {
4174
+ if (!useSelectReturnProps.isOpen) {
4175
+ setHasLoadedOnce(false);
4176
+ } else {
4177
+ !hasLoadedOnce && setHasLoadedOnce(true);
4178
+ }
4179
+ }, [useSelectReturnProps.isOpen]);
4180
+ const onNestedIsOpenChange = ({
4181
+ isOpen: newIsOpen
4182
+ }) => {
4183
+ !newIsOpen && useSelectReturnProps.closeMenu?.();
4184
+ };
4185
+ const nestedMenuPropsFromRoot = {
4186
+ // The selected menu needs to receive this id so that the toggle element can be properly associated with it.
4187
+ id: nestedMenuId,
4188
+ onIsOpenChange: onNestedIsOpenChange
4189
+ };
3887
4190
  const [selectedMenuPath, setSelectedMenuPath] = useState([initialMenuId]);
3888
- const selectedMenuId = selectedMenuPath[selectedMenuPath.length - 1];
4191
+ const [activeMenuContext, setActiveMenuContext] = useState(defaultMenuContext);
4192
+ const [currentMenuId, setCurrentMenuId] = useState(initialMenuId);
4193
+ const [isAdding, setIsAdding] = useState(false);
3889
4194
  const setSelectedMenuId = (id) => {
4195
+ setIsAdding(true);
3890
4196
  setSelectedMenuPath((currentPath) => [...currentPath, id]);
3891
4197
  };
4198
+ useEffect5(() => {
4199
+ if (selectedMenuPath.length > 0) {
4200
+ const newMenuId = selectedMenuPath[selectedMenuPath.length - 1];
4201
+ setCurrentMenuId(newMenuId);
4202
+ }
4203
+ }, [selectedMenuPath.join("-")]);
4204
+ const resetSelectedMenuPath = () => {
4205
+ setSelectedMenuPath([initialMenuId]);
4206
+ setCurrentMenuId(initialMenuId);
4207
+ };
3892
4208
  const goBack = () => {
4209
+ setIsAdding(false);
3893
4210
  setSelectedMenuPath((currentPath) => currentPath.slice(0, -1));
3894
- onBackButtonClick?.(selectedMenuId);
4211
+ onBackButtonClick?.(currentMenuId);
3895
4212
  };
3896
4213
  const {
3897
4214
  MenuComponent,
3898
4215
  menuProps,
3899
4216
  MenuHeaderComponent = NestedMenuHeader,
3900
4217
  menuHeaderProps = {}
3901
- } = menus[selectedMenuId] || {};
4218
+ } = menus[currentMenuId] || {};
3902
4219
  const {
3903
4220
  children,
3904
4221
  menuItems,
3905
4222
  MenuItemComponent,
3906
4223
  stateReducer: externalStateReducer,
3907
- onStateChange: externalOnStateChange,
3908
- ...props
4224
+ ...restMenuProps
3909
4225
  } = menuProps || {};
3910
4226
  const stateReducer = reduceReducers(
3911
4227
  nestedMenuStateReducer,
3912
4228
  externalStateReducer
3913
4229
  );
3914
- const onStateChange = (changes) => {
3915
- externalOnStateChange?.(changes);
3916
- if (changes.isOpen === false) {
3917
- setTimeout(() => {
3918
- setSelectedMenuPath([initialMenuId]);
3919
- }, 100);
3920
- }
4230
+ const animationSpeed = MOTION_DURATION_FAST;
4231
+ const contentVariants = {
4232
+ arrive: (custom = { hasLoadedOnce: false, isAdding: false }) => ({
4233
+ opacity: 0,
4234
+ // Start from left if is first render of root, else use default
4235
+ x: !custom?.hasLoadedOnce ? "200%" : custom?.isAdding ? "200%" : "-200%"
4236
+ }),
4237
+ enter: (custom = { hasLoadedOnce: false }) => ({
4238
+ opacity: 1,
4239
+ x: 0,
4240
+ transition: {
4241
+ type: "tween",
4242
+ duration: animationSpeed,
4243
+ ease: "circOut",
4244
+ delay: !custom.hasLoadedOnce ? animationSpeed : 0
4245
+ }
4246
+ }),
4247
+ leave: (custom = { hasLoadedOnce: false, isAdding: false }) => ({
4248
+ opacity: 0,
4249
+ x: custom?.isAdding ? "-200%" : "200%",
4250
+ transition: {
4251
+ type: "tween",
4252
+ duration: animationSpeed,
4253
+ ease: "circIn"
4254
+ }
4255
+ })
4256
+ };
4257
+ const menuVariants = {
4258
+ arrive: (custom = { hasLoadedOnce: false, isAdding: false }) => ({
4259
+ opacity: 0,
4260
+ // Start from left if is first render of root, else use default
4261
+ x: !custom?.hasLoadedOnce ? "200%" : custom?.isAdding ? "200%" : "-200%"
4262
+ }),
4263
+ enter: (custom = { hasLoadedOnce: false }) => ({
4264
+ opacity: 1,
4265
+ x: 0,
4266
+ transition: {
4267
+ type: "tween",
4268
+ duration: animationSpeed,
4269
+ ease: "circOut",
4270
+ delay: !custom.hasLoadedOnce ? animationSpeed : 0
4271
+ }
4272
+ }),
4273
+ leave: (custom = { hasLoadedOnce: false, isAdding: false }) => ({
4274
+ opacity: 0,
4275
+ x: custom?.isAdding ? "-200%" : "200%",
4276
+ transition: {
4277
+ type: "tween",
4278
+ duration: animationSpeed,
4279
+ ease: "circIn"
4280
+ }
4281
+ })
3921
4282
  };
3922
4283
  const nestedMenuProps = {
4284
+ ...nestedMenuPropsFromRoot,
3923
4285
  menuToggleElement,
3924
4286
  stateReducer,
3925
- onStateChange,
3926
- initialIsOpen: selectedMenuPath.length > 1,
3927
- children: /* @__PURE__ */ jsxs6(Fragment4, { children: [
3928
- MenuHeaderComponent && /* @__PURE__ */ jsx28(
3929
- MenuHeaderComponent,
4287
+ MenuRootComponent: NestedMenuRoot,
4288
+ // This ensures that onNestedIsOpenChange will be triggered if the selected menu attempts to close itself.
4289
+ initialIsOpen: true,
4290
+ children: (
4291
+ // Handles the smooth animating of the content
4292
+ /* @__PURE__ */ jsx33(AnimatePresence2, { mode: "wait", children: /* @__PURE__ */ jsxs7(
4293
+ motion3.div,
3930
4294
  {
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
4295
+ variants: contentVariants,
4296
+ initial: "arrive",
4297
+ animate: "enter",
4298
+ exit: "leave",
4299
+ custom: { isAdding, hasLoadedOnce },
4300
+ children: [
4301
+ MenuHeaderComponent && /* @__PURE__ */ jsx33(
4302
+ MenuHeaderComponent,
4303
+ {
4304
+ backArrowLabel,
4305
+ ...menuHeaderProps
4306
+ }
4307
+ ),
4308
+ children && children,
4309
+ menuItems && !children && /* @__PURE__ */ jsx33(
4310
+ NestedMenuContent,
4311
+ {
4312
+ menuItems,
4313
+ MenuItemComponent: MenuItemComponent ?? NestedMenuItem
4314
+ }
4315
+ )
4316
+ ]
4317
+ },
4318
+ currentMenuId
4319
+ ) })
4320
+ ),
4321
+ ...restMenuProps
3945
4322
  };
3946
- return /* @__PURE__ */ jsx28(
4323
+ return /* @__PURE__ */ jsx33(
3947
4324
  NestedMenuProvider,
3948
4325
  {
3949
- selectedMenuPath,
3950
- setSelectedMenuPath,
3951
- setSelectedMenuId,
3952
- goBack,
3953
- children: MenuComponent && /* @__PURE__ */ jsx28(MenuComponent, { ...nestedMenuProps })
4326
+ ...{
4327
+ selectedMenuPath,
4328
+ setSelectedMenuPath,
4329
+ setSelectedMenuId,
4330
+ resetSelectedMenuPath,
4331
+ goBack,
4332
+ rootMenuContextProps,
4333
+ activeMenuContext,
4334
+ setActiveMenuContext,
4335
+ animationSpeed
4336
+ },
4337
+ children: /* @__PURE__ */ jsx33(
4338
+ NestedMenuPopout,
4339
+ {
4340
+ content: MenuComponent && // Handles the rerender of the component
4341
+ /* @__PURE__ */ jsx33(AnimatePresence2, { mode: "wait", children: /* @__PURE__ */ jsx33(
4342
+ motion3.div,
4343
+ {
4344
+ variants: menuVariants,
4345
+ initial: "arrive",
4346
+ animate: "enter",
4347
+ exit: "leave",
4348
+ custom: { isAdding, hasLoadedOnce },
4349
+ children: /* @__PURE__ */ jsx33(MenuComponent, { ...nestedMenuProps })
4350
+ },
4351
+ `${currentMenuId}-content`
4352
+ ) }),
4353
+ menuToggleElement,
4354
+ width: width2,
4355
+ ...popoutProps
4356
+ }
4357
+ )
3954
4358
  }
3955
4359
  );
3956
4360
  };
@@ -3958,7 +4362,11 @@ export {
3958
4362
  ActionMenu,
3959
4363
  Autocomplete,
3960
4364
  AutocompleteInput,
4365
+ AutocompleteSelect,
4366
+ AutocompleteTokenInput,
4367
+ CustomPopoutContent,
3961
4368
  INPUT_TYPES,
4369
+ ListboxToggleButton,
3962
4370
  MenuContent,
3963
4371
  MenuContentContext,
3964
4372
  MenuContentProvider,
@@ -3973,7 +4381,9 @@ export {
3973
4381
  MenuItemRow,
3974
4382
  MenuItemText,
3975
4383
  MenuLabel,
4384
+ MenuPopout,
3976
4385
  MenuRoot,
4386
+ MenuRootNoPopout,
3977
4387
  MenuSearchInput,
3978
4388
  MenuSearchTokenInput,
3979
4389
  MenuToggleButton,
@@ -3988,6 +4398,7 @@ export {
3988
4398
  NestedMenuItem,
3989
4399
  NestedMenuProvider,
3990
4400
  SingleSelectMenu,
4401
+ StyledListboxToggleButton,
3991
4402
  StyledMenuGroup,
3992
4403
  StyledMenuGroupUl,
3993
4404
  StyledMenuItem,