Skip to content

Commit 4b0cf89

Browse files
fix: simple menu with icon (#1758)
1 parent 37bdb93 commit 4b0cf89

File tree

7 files changed

+73
-40
lines changed

7 files changed

+73
-40
lines changed

.changeset/beige-rings-destroy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@strapi/design-system': patch
3+
---
4+
5+
simple menu with icon should work now as expected

docs/stories/SimpleMenu.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import { SimpleMenu, MenuItem } from '@strapi/design-system';
2424

2525
<Canvas of={SimpleMenuStories.Basic} />
2626

27+
### With Icons
28+
29+
<Canvas of={SimpleMenuStories.WithIcons} />
30+
2731
### Using Links & Routing Libraries
2832

2933
By default you can define links in your menu by providing either the `isLink` or `isExternal` prop, the former infers an

docs/stories/SimpleMenu.stories.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { Bell } from '@strapi/icons';
55
const meta: Meta<typeof SimpleMenu> = {
66
title: 'Design System/Components/SimpleMenu',
77
component: SimpleMenu,
8+
parameters: {
9+
chromatic: { disableSnapshot: false },
10+
},
811
};
912

1013
export default meta;
@@ -28,17 +31,16 @@ export const Basic = {
2831
name: 'basic',
2932
} satisfies Story;
3033

31-
// export const WithIcons = {
32-
// render: () => (
33-
// // @ts-expect-error the as prop does not correctly infer props.
34-
// <SimpleMenu aria-label="Notifications" icon={<Bell />}>
35-
// <MenuItem onSelect={() => console.log('view notification')}>Your review has been requested!</MenuItem>
36-
// <MenuItem onSelect={() => console.log('view notification')}>There was an error with your billing.</MenuItem>
37-
// </SimpleMenu>
38-
// ),
34+
export const WithIcons = {
35+
render: () => (
36+
<SimpleMenu label="Notifications" tag={IconButton} icon={<Bell />}>
37+
<MenuItem onSelect={() => console.log('view notification')}>Your review has been requested!</MenuItem>
38+
<MenuItem onSelect={() => console.log('view notification')}>There was an error with your billing.</MenuItem>
39+
</SimpleMenu>
40+
),
3941

40-
// name: 'with icons',
41-
// } satisfies Story;
42+
name: 'with icons',
43+
} satisfies Story;
4244

4345
export const WithLinks = {
4446
render: () => (

packages/design-system/src/components/Breadcrumbs/CrumbSimpleMenu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ const StyledButton = styled(SimpleMenu)`
1414
}
1515
`;
1616

17-
export interface CrumbSimpleMenuProps extends SimpleMenuProps {
17+
export type CrumbSimpleMenuProps = SimpleMenuProps & {
1818
'aria-label': string;
1919
icon?: React.ReactElement;
2020
endIcon?: React.ReactNode;
21-
}
21+
};
2222

2323
export const CrumbSimpleMenu = React.forwardRef<HTMLButtonElement, CrumbSimpleMenuProps>(
2424
({ children, ...props }, forwardedRef) => (

packages/design-system/src/components/SimpleMenu/Menu.tsx

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Flex, FlexComponent, FlexProps } from '../../primitives/Flex';
1010
import { Typography, TypographyComponent, TypographyProps } from '../../primitives/Typography';
1111
import { BaseLink } from '../BaseLink';
1212
import { Button, ButtonProps } from '../Button';
13+
import { IconButton } from '../IconButton';
1314
import { Link, LinkProps } from '../Link';
1415

1516
/* -------------------------------------------------------------------------------------------------
@@ -24,23 +25,48 @@ const MenuRoot = DropdownMenu.Root;
2425
* MenuTrigger
2526
* -----------------------------------------------------------------------------------------------*/
2627

27-
interface TriggerProps extends ButtonProps {}
28+
type TriggerPropsBase = Omit<ButtonProps, 'tag'> & {
29+
endIcon?: React.ReactNode;
30+
label?: React.ReactNode | string;
31+
};
32+
33+
type TriggerPropsWithButton = TriggerPropsBase & {
34+
tag?: typeof Button;
35+
icon?: React.ReactNode;
36+
};
37+
38+
type TriggerPropsWithIconButton = TriggerPropsBase & {
39+
tag: typeof IconButton;
40+
icon: React.ReactNode;
41+
};
42+
43+
type TriggerProps = TriggerPropsWithButton | TriggerPropsWithIconButton;
2844

2945
const MenuTrigger = React.forwardRef<HTMLButtonElement, TriggerProps>(
30-
({ size, endIcon = <CaretDown width="0.6rem" height="0.4rem" aria-hidden />, ...props }, ref) => {
46+
(
47+
{ label, size, endIcon = <CaretDown width="1.2rem" height="1.2rem" aria-hidden />, tag = Button, icon, ...rest },
48+
ref,
49+
) => {
50+
const props: ButtonProps = {
51+
...rest,
52+
ref,
53+
type: 'button',
54+
variant: 'ghost',
55+
paddingTop: size === 'S' ? 1 : 2,
56+
paddingBottom: size === 'S' ? 1 : 2,
57+
paddingLeft: size === 'S' ? 3 : 4,
58+
paddingRight: size === 'S' ? 3 : 4,
59+
};
60+
3161
return (
3262
<DropdownMenu.Trigger asChild>
33-
<Button
34-
ref={ref}
35-
type="button"
36-
variant="ghost"
37-
endIcon={endIcon}
38-
paddingTop={size === 'S' ? 1 : 2}
39-
paddingBottom={size === 'S' ? 1 : 2}
40-
paddingLeft={size === 'S' ? 3 : 4}
41-
paddingRight={size === 'S' ? 3 : 4}
42-
{...props}
43-
/>
63+
{tag === IconButton ? (
64+
<IconButton label={label as string} {...props}>
65+
{icon}
66+
</IconButton>
67+
) : (
68+
<Button endIcon={endIcon} {...props} />
69+
)}
4470
</DropdownMenu.Trigger>
4571
);
4672
},
@@ -68,8 +94,6 @@ const MenuContent = React.forwardRef<HTMLDivElement, ContentProps>(
6894
<Viewport
6995
ref={ref}
7096
direction="column"
71-
borderStyle="solid"
72-
borderWidth="1px"
7397
borderColor="neutral150"
7498
hasRadius
7599
background="neutral0"

packages/design-system/src/components/SimpleMenu/SimpleMenu.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const Component = ({ onClick = () => {}, ...restProps }: SimpleMenuProps) => (
1515
</SimpleMenu>
1616
);
1717

18-
const render = (props: Partial<SimpleMenuProps> = {}) => renderRTL(<Component {...props} />);
18+
const render = (props: SimpleMenuProps = {}) => renderRTL(<Component {...props} />);
1919

2020
describe('SimpleMenu', () => {
2121
it('should render only the trigger initially', () => {

packages/design-system/src/components/SimpleMenu/SimpleMenu.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,16 @@ import * as Menu from './Menu';
1111
* SimpleMenu
1212
* -----------------------------------------------------------------------------------------------*/
1313

14-
interface SimpleMenuProps
15-
extends Omit<Menu.TriggerProps, 'children'>,
16-
Pick<Menu.ContentProps, 'popoverPlacement' | 'intersectionId'> {
17-
children?: React.ReactNode;
18-
label?: React.ReactNode;
19-
onOpen?: () => void;
20-
onClose?: () => void;
21-
/**
22-
* Callback function to be called when the popover reaches the end of the scrollable content
23-
*/
24-
onReachEnd?: (entry: IntersectionObserverEntry) => void;
25-
}
14+
type SimpleMenuProps = Menu.TriggerProps &
15+
Pick<Menu.ContentProps, 'popoverPlacement' | 'intersectionId'> & {
16+
children?: React.ReactNode;
17+
onOpen?: () => void;
18+
onClose?: () => void;
19+
/**
20+
* Callback function to be called when the popover reaches the end of the scrollable content
21+
*/
22+
onReachEnd?: (entry: IntersectionObserverEntry) => void;
23+
};
2624

2725
const SimpleMenu = React.forwardRef<HTMLButtonElement, SimpleMenuProps>(
2826
({ children, onOpen, onClose, popoverPlacement, onReachEnd, ...props }, forwardedRef) => {

0 commit comments

Comments
 (0)