@sproutsocial/seeds-react-menu 1.3.2 → 1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sproutsocial/seeds-react-menu",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Seeds React Menu",
5
5
  "author": "Sprout Social, Inc.",
6
6
  "license": "MIT",
@@ -1,9 +1,30 @@
1
+ import type {
2
+ TypeBorderSystemProps,
3
+ TypeColorSystemProps,
4
+ TypeFlexboxSystemProps,
5
+ TypeGridSystemProps,
6
+ TypeLayoutSystemProps,
7
+ TypePositionSystemProps,
8
+ TypeSpaceSystemProps,
9
+ TypeStyledComponentsCommonProps,
10
+ } from "@sproutsocial/seeds-react-system-props";
1
11
  import type { TypeMenuItemProps } from "../MenuItem";
2
12
  import type { TypeChildrenOrItems } from "../types";
3
13
 
14
+ export interface TypeMenuContentContainerProps
15
+ extends Omit<React.ComponentPropsWithoutRef<"ul">, "children" | "color">,
16
+ TypeStyledComponentsCommonProps,
17
+ TypeBorderSystemProps,
18
+ TypeColorSystemProps,
19
+ TypeFlexboxSystemProps,
20
+ TypeGridSystemProps,
21
+ TypeLayoutSystemProps,
22
+ TypeSpaceSystemProps,
23
+ TypePositionSystemProps {}
24
+
4
25
  export type TypeMenuContentProps<
5
26
  I extends TypeMenuItemProps = TypeMenuItemProps
6
- > = Omit<React.ComponentPropsWithoutRef<"ul">, "children"> & {
27
+ > = TypeMenuContentContainerProps & {
7
28
  innerRef?: React.Ref<HTMLUListElement>;
8
29
  /* Custom component to display when no menu items are visible (e.g. "No results found"). */
9
30
  emptyStateElement?: React.ReactNode;
@@ -1,11 +1,30 @@
1
1
  import styled from "styled-components";
2
+ import {
3
+ border,
4
+ color,
5
+ flexbox,
6
+ grid,
7
+ layout,
8
+ position,
9
+ space,
10
+ } from "styled-system";
11
+ import type { TypeMenuContentProps } from "./MenuContentTypes";
2
12
 
3
- export const StyledMenuContent = styled.ul`
13
+ export const StyledMenuContent = styled.ul<TypeMenuContentProps>`
4
14
  margin: 0;
5
15
  padding: 0;
16
+ overflow: auto;
6
17
 
7
18
  &:focus {
8
19
  outline: none;
9
20
  box-shadow: none;
10
21
  }
22
+
23
+ ${border}
24
+ ${color}
25
+ ${flexbox}
26
+ ${grid}
27
+ ${layout}
28
+ ${space}
29
+ ${position}
11
30
  `;
@@ -39,9 +39,11 @@ export const CustomPopoutContent = styled(Popout.Content)`
39
39
  padding: 0;
40
40
  margin-left: 0;
41
41
  margin-right: 0;
42
+ overflow: hidden;
42
43
  `;
43
44
 
44
45
  const menuAnimationConfig = {
46
+ layout: true,
45
47
  initial: {
46
48
  scale: 0,
47
49
  opacity: 0,
@@ -13,6 +13,7 @@ import {
13
13
  MultiSelectMenu,
14
14
  NestedMenu,
15
15
  MenuSearchInput,
16
+ MenuSearchTokenInput,
16
17
  } from "../index";
17
18
  import { NestedMenuItem } from "./NestedMenuItem";
18
19
  import { NestedMenuContent } from "./NestedMenuContent";
@@ -89,11 +90,16 @@ const menus = {
89
90
  "books-action": {
90
91
  MenuComponent: ActionMenu,
91
92
  menuProps: {
92
- menuItems: TEST_BOOKS.map((book) => ({
93
- id: book.id,
94
- children: book.title,
95
- childMenuId: "edit-book",
96
- })),
93
+ children: (
94
+ <NestedMenuContent
95
+ menuItems={TEST_BOOKS.map((book) => ({
96
+ id: book.id,
97
+ children: book.title,
98
+ childMenuId: "edit-book",
99
+ }))}
100
+ // maxHeight="300px"
101
+ />
102
+ ),
97
103
  },
98
104
  menuHeaderProps: {
99
105
  title: "Manage Books",
@@ -103,24 +109,36 @@ const menus = {
103
109
  MenuComponent: MultiSelectMenu,
104
110
  menuProps: {
105
111
  itemToString: (item) => item.menuItemProps.children,
106
- menuItems: TEST_BOOKS.map((book) => ({
107
- id: book.id,
108
- children: book.title,
109
- })),
112
+ children: (
113
+ <NestedMenuContent
114
+ menuItems={TEST_BOOKS.map((book) => ({
115
+ id: book.id,
116
+ children: book.title,
117
+ }))}
118
+ // maxHeight="300px"
119
+ />
120
+ ),
110
121
  },
111
122
  menuHeaderProps: {
112
123
  title: "Select Books",
113
- children: <MenuSearchInput id="nested-search" name="nested-search" />,
124
+ children: (
125
+ <MenuSearchTokenInput id="nested-search" name="nested-search" />
126
+ ),
114
127
  },
115
128
  },
116
129
  "books-select": {
117
130
  MenuComponent: SingleSelectMenu,
118
131
  menuProps: {
119
132
  itemToString: (item) => item.menuItemProps.children,
120
- menuItems: TEST_BOOKS.map((book) => ({
121
- id: book.id,
122
- children: book.title,
123
- })),
133
+ children: (
134
+ <NestedMenuContent
135
+ menuItems={TEST_BOOKS.map((book) => ({
136
+ id: book.id,
137
+ children: book.title,
138
+ }))}
139
+ // maxHeight="300px"
140
+ />
141
+ ),
124
142
  },
125
143
  menuHeaderProps: {
126
144
  title: "Select One Book",
@@ -167,6 +185,9 @@ export const NestedMenuMultiLevelStory: Story = {
167
185
  menuToggleElement={
168
186
  <MenuToggleButton width="200px">Open Menu</MenuToggleButton>
169
187
  }
188
+ popoutProps={{
189
+ placement: "top",
190
+ }}
170
191
  />
171
192
  </Box>
172
193
  </MotionConfig>
@@ -1,5 +1,5 @@
1
1
  import { useId, useEffect, useState } from "react";
2
- import { AnimatePresence, LayoutGroup, motion } from "motion/react";
2
+ import { AnimatePresence, motion } from "motion/react";
3
3
  import { useSelect } from "downshift";
4
4
 
5
5
  import { useDownshiftDefaults } from "../hooks/useDownshiftDefaults";
@@ -31,7 +31,10 @@ export const NestedMenu = <
31
31
  onBackButtonClick,
32
32
  backArrowLabel,
33
33
  menuToggleElement,
34
- popoutProps = {},
34
+ popoutProps: {
35
+ scheduleUpdateRef: externalPopoutUpdateRef,
36
+ ...restPopoutProps
37
+ } = {},
35
38
  width = "300px",
36
39
  stateReducer: rootExternalStateReducer,
37
40
  id: externalNestedMenuId,
@@ -96,6 +99,8 @@ export const NestedMenu = <
96
99
  useState<TypeMenuContext>(defaultMenuContext);
97
100
  const [currentMenuId, setCurrentMenuId] = useState(initialMenuId);
98
101
  const [isAdding, setIsAdding] = useState(false);
102
+ const [popoutUpdateRef, setPopoutUpdateRef] =
103
+ useState<() => void | undefined>();
99
104
 
100
105
  const setSelectedMenuId = (id: string) => {
101
106
  setIsAdding(true);
@@ -108,6 +113,7 @@ export const NestedMenu = <
108
113
  if (selectedMenuPath.length > 0) {
109
114
  const newMenuId = selectedMenuPath[selectedMenuPath.length - 1];
110
115
  setCurrentMenuId(newMenuId);
116
+ popoutUpdateRef?.();
111
117
  }
112
118
  }, [selectedMenuPath.join("-")]);
113
119
 
@@ -272,7 +278,11 @@ export const NestedMenu = <
272
278
  }
273
279
  menuToggleElement={menuToggleElement}
274
280
  width={width}
275
- {...popoutProps}
281
+ scheduleUpdateRef={(callback) => {
282
+ setPopoutUpdateRef(callback);
283
+ externalPopoutUpdateRef?.(callback);
284
+ }}
285
+ {...restPopoutProps}
276
286
  />
277
287
  </NestedMenuProvider>
278
288
  );
@@ -16,6 +16,7 @@ export const NestedMenuPopout = ({
16
16
  content,
17
17
  menuToggleElement,
18
18
  width,
19
+ onClose,
19
20
  ...popoutProps
20
21
  }: Omit<TypeMenuPopoutProps, "children"> & {
21
22
  menuToggleElement: TypeMenuRootProps["menuToggleElement"];
@@ -25,9 +26,13 @@ export const NestedMenuPopout = ({
25
26
 
26
27
  return (
27
28
  <MenuPopout
28
- {...popoutProps}
29
+ // TODO: add after prop is added to Popout
30
+ // lockPlacement
29
31
  // Reset the selected menu path after the close animation completes
30
- onClose={() => setTimeout(() => resetSelectedMenuPath?.(), 100)}
32
+ onClose={() => {
33
+ onClose?.();
34
+ setTimeout(() => resetSelectedMenuPath?.(), 100);
35
+ }}
31
36
  isOpen={!!rootMenuContextProps.isOpen}
32
37
  openMenu={rootMenuContextProps.openMenu}
33
38
  closeMenu={rootMenuContextProps.closeMenu}
@@ -37,6 +42,7 @@ export const NestedMenuPopout = ({
37
42
  {typeof content === "function" ? content(props) : content}
38
43
  </StyledDiv>
39
44
  )}
45
+ {...popoutProps}
40
46
  >
41
47
  {(toggleProps) => (
42
48
  <MenuToggleProvider