@sproutsocial/seeds-react-menu 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +6 -0
- package/dist/esm/index.js +18 -18
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/ActionMenu/ActionMenu.stories.tsx +20 -1
- package/src/MenuGroup/__tests__/MenuGroup.test.tsx +33 -0
- package/src/MenuGroup/__tests__/MenuGroup.typetest.tsx +5 -0
- package/src/hooks/useMenuChildren.tsx +23 -22
- package/src/types.ts +2 -4
package/package.json
CHANGED
|
@@ -65,11 +65,22 @@ const handleOnClick = (e: React.MouseEvent<HTMLElement>, itemName: string) => {
|
|
|
65
65
|
action(`${itemName}`)(e);
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
type ActionMenuSimpleStoryArgs = ActionMenuStoryArgs & {
|
|
69
|
+
"Show Conditional Item"?: boolean;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const ActionMenuSimple: StoryObj<ActionMenuSimpleStoryArgs> = {
|
|
69
73
|
name: "Simple Action Menu",
|
|
70
74
|
args: {
|
|
71
75
|
"Trigger Text": "ActionMenu",
|
|
72
76
|
"Trigger Appearance": "secondary",
|
|
77
|
+
"Show Conditional Item": false,
|
|
78
|
+
},
|
|
79
|
+
argTypes: {
|
|
80
|
+
"Show Conditional Item": {
|
|
81
|
+
control: { type: "boolean" },
|
|
82
|
+
description: "Toggle to show/hide the conditional menu item",
|
|
83
|
+
},
|
|
73
84
|
},
|
|
74
85
|
render: (args) => {
|
|
75
86
|
return (
|
|
@@ -106,6 +117,14 @@ export const ActionMenuSimple: Story = {
|
|
|
106
117
|
>
|
|
107
118
|
This Opens a Link
|
|
108
119
|
</MenuItem>
|
|
120
|
+
{args["Show Conditional Item"] && (
|
|
121
|
+
<MenuItem
|
|
122
|
+
onClick={(e) => handleOnClick(e, "Conditional Menu Item")}
|
|
123
|
+
id="conditional"
|
|
124
|
+
>
|
|
125
|
+
Conditional Menu Item
|
|
126
|
+
</MenuItem>
|
|
127
|
+
)}
|
|
109
128
|
</MenuGroup>
|
|
110
129
|
</MenuContent>
|
|
111
130
|
</ActionMenu>
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
SingleSelectMenu,
|
|
10
10
|
MultiSelectMenu,
|
|
11
|
+
ActionMenu,
|
|
11
12
|
MenuContent,
|
|
12
13
|
MenuGroup,
|
|
13
14
|
MenuToggleButton,
|
|
@@ -284,4 +285,36 @@ describe("MenuGroup", () => {
|
|
|
284
285
|
xit("ignores the customMenuItem prop", () => {});
|
|
285
286
|
});
|
|
286
287
|
});
|
|
288
|
+
|
|
289
|
+
it("supports conditionally rendered items when false", () => {
|
|
290
|
+
// Spy on console.error to catch and verify console errors
|
|
291
|
+
const consoleErrorSpy = jest
|
|
292
|
+
.spyOn(console, "error")
|
|
293
|
+
.mockImplementation(() => {});
|
|
294
|
+
|
|
295
|
+
render(
|
|
296
|
+
<ActionMenu
|
|
297
|
+
defaultIsOpen
|
|
298
|
+
menuToggleElement={<MenuToggleButton>Test Menu</MenuToggleButton>}
|
|
299
|
+
>
|
|
300
|
+
<MenuContent>
|
|
301
|
+
<MenuGroup id="group">
|
|
302
|
+
<MenuItem id="item-1">Item 1</MenuItem>
|
|
303
|
+
{false && (
|
|
304
|
+
<MenuItem id="conditional" onClick={() => {}}>
|
|
305
|
+
Conditional Menu Item
|
|
306
|
+
</MenuItem>
|
|
307
|
+
)}
|
|
308
|
+
<MenuItem id="item-2">Item 2</MenuItem>
|
|
309
|
+
</MenuGroup>
|
|
310
|
+
</MenuContent>
|
|
311
|
+
</ActionMenu>
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
// Verify no console errors occurred during render
|
|
315
|
+
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
|
316
|
+
|
|
317
|
+
// Restore console.error
|
|
318
|
+
consoleErrorSpy.mockRestore();
|
|
319
|
+
});
|
|
287
320
|
});
|
|
@@ -10,6 +10,11 @@ export const MenuGroupTypeTest = () => (
|
|
|
10
10
|
<MenuItem id="1">Test 1</MenuItem>
|
|
11
11
|
<MenuItem id="2">Test 2</MenuItem>
|
|
12
12
|
</MenuGroup>
|
|
13
|
+
{/* MenuGroup allows children with conditional MenuItems */}
|
|
14
|
+
<MenuGroup id="group">
|
|
15
|
+
<MenuItem id="1">Test 1</MenuItem>
|
|
16
|
+
{false && <MenuItem id="2">Test 2</MenuItem>}
|
|
17
|
+
</MenuGroup>
|
|
13
18
|
{/* MenuGroup allows menuItems prop */}
|
|
14
19
|
<MenuGroup id="group" menuItems={[{ id: "1", children: "1" }]} />
|
|
15
20
|
{/* MenuGroup allows menuItems prop with MenuItemComponent */}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
TypeSubmenuValidMenuComponentProps,
|
|
6
6
|
} from "../SubmenuItem";
|
|
7
7
|
import type { TypeMenuContext } from "../MenuContext";
|
|
8
|
-
import type { TypeMenuGroupProps
|
|
8
|
+
import type { TypeMenuGroupProps } from "../MenuGroup";
|
|
9
9
|
import type { TypeMenuRootProps } from "../MenuRoot";
|
|
10
10
|
import type {
|
|
11
11
|
TypeNotEmptyChildren,
|
|
@@ -46,12 +46,13 @@ const walkAllChildren = (
|
|
|
46
46
|
if (element === null || element === undefined) return;
|
|
47
47
|
callback(element, parents);
|
|
48
48
|
const newParents = [...parents, element];
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
if (React.isValidElement(element) && element.props?.children) {
|
|
50
|
+
React.Children.toArray(element.props.children).forEach((child) => {
|
|
51
|
+
walk(child, newParents);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
53
54
|
};
|
|
54
|
-
const parents = [];
|
|
55
|
+
const parents: ReactNode[] = [];
|
|
55
56
|
React.Children.toArray(children).forEach((child) => {
|
|
56
57
|
walk(child, parents);
|
|
57
58
|
});
|
|
@@ -114,22 +115,22 @@ const addItemsFromGroup = <I extends TypeMenuItemProps = TypeMenuItemProps>({
|
|
|
114
115
|
});
|
|
115
116
|
});
|
|
116
117
|
} else if (menuGroup.props.children) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (!Array.isArray(children)) {
|
|
120
|
-
children = [children];
|
|
121
|
-
}
|
|
118
|
+
// Convert children to array to handle both arrays and iterables
|
|
119
|
+
const children = React.Children.toArray(menuGroup.props.children);
|
|
122
120
|
children.forEach((menuItem) => {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
121
|
+
// Only process React elements that have props
|
|
122
|
+
if (React.isValidElement(menuItem)) {
|
|
123
|
+
addMenuItem({
|
|
124
|
+
itemProps: {
|
|
125
|
+
id: menuItem.props.id,
|
|
126
|
+
disabled: menuItem.props.disabled,
|
|
127
|
+
menuItemProps: menuItem.props,
|
|
128
|
+
menuGroupProps: menuGroup.props,
|
|
129
|
+
},
|
|
130
|
+
allMenuItems,
|
|
131
|
+
menuItemsMap,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
133
134
|
});
|
|
134
135
|
}
|
|
135
136
|
};
|
|
@@ -269,7 +270,7 @@ export const useMenuChildren = <
|
|
|
269
270
|
});
|
|
270
271
|
children = getChildrenFromMenuItems({ menuItems, MenuItemComponent });
|
|
271
272
|
} else if (childrenProp) {
|
|
272
|
-
children = childrenProp
|
|
273
|
+
children = childrenProp;
|
|
273
274
|
setMenuItemsFromChildren({
|
|
274
275
|
children: childrenProp,
|
|
275
276
|
allMenuItems,
|
package/src/types.ts
CHANGED
|
@@ -46,10 +46,8 @@ export type TypeChildrenOrItems<
|
|
|
46
46
|
}
|
|
47
47
|
);
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
| React.ReactFragment
|
|
52
|
-
| React.ReactPortal;
|
|
49
|
+
// Type that excludes null and undefined from React.ReactNode
|
|
50
|
+
export type TypeNotEmptyChildren = Exclude<React.ReactNode, null | undefined>;
|
|
53
51
|
|
|
54
52
|
type TypeInputEventListeners =
|
|
55
53
|
| "onKeyDown"
|