@razorpay/blade-mcp
Version:
Model Context Protocol server for Blade
373 lines (321 loc) • 8.93 kB
Markdown
## Component Name
Menu
## Description
Action Menu displays a list of actions on temporary surfaces. They allow users to perform actions from multiple options. Menus appear when users interact with a button, action, or other control, creating a contextual interface for related actions. Note that Menus are not responsive by default and are not intended for selection - use Dropdown with Select or AutoComplete for selectable options.
## TypeScript Types
The following types represent the props that the Menu component and its subcomponents accept. These types should be used when implementing the Menu component in your application.
```typescript
// The main Menu component props
type MenuProps = {
/**
* First children is trigger and second children is MenuOverlay
*/
children: [React.ReactElement, React.ReactElement];
/**
* Open controlled state
*/
isOpen?: boolean;
/**
* On Menu open change callback
*/
onOpenChange?: ({ isOpen }: { isOpen: boolean }) => void;
/**
* Should menu open on click or hover
*
* @default 'click'
*/
openInteraction?: 'hover' | 'click';
};
// MenuItem props
type MenuItemProps = {
/**
* title of item
*/
title?: string;
/**
* Description text for the item
*/
description?: string;
/**
* Slot to render custom menu items
*/
children?: React.ReactNode;
/**
* HTML element to render as
*/
as?: React.ElementType;
/**
* Click handler for MenuItem
*
* Absence of this prop and href will turn the item into non-interactive item
*/
onClick?: (event: React.MouseEvent) => void;
/**
* Focus handler for MenuItem
*
* Absence of this prop and href will turn the item into non-interactive item
*/
onFocus?: (event: React.FocusEvent) => void;
/**
* Link to open when item is clicked.
*
* Absence of this prop and onClick will turn the item into non-interactive item
*/
href?: string;
/**
* HTML target of the link
*/
target?: string;
/**
* Item that goes on left-side of item.
*
* Will be overridden in multiselect
*/
leading?: React.ReactNode;
/**
* Item that goes on right-side of item.
*/
trailing?: React.ReactNode;
/**
* Item that goes immediately next to the title.
*/
titleSuffix?: React.ReactElement;
/**
* disabled state of item
*/
isDisabled?: boolean;
/**
* Color of item. set to negative for dangerous actions like Delete, Remove, etc
*/
color?: 'negative';
} & DataAnalyticsAttribute;
// MenuOverlay props
type MenuOverlayProps = {
/**
* JSX Slot for MenuItem or anything else
*/
children: React.ReactElement[] | React.ReactElement | React.ReactNode;
/**
* zIndex override
*/
zIndex?: number | string;
/**
* width override.
*
* By default width is not set
*/
width?: string | number;
/**
* minWidth override
*/
minWidth?: string | number;
/**
* maxWidth override
*/
maxWidth?: string | number;
} & TestID &
DataAnalyticsAttribute;
// MenuHeader props
type MenuHeaderProps = {
/**
* Title of the menu header
*/
title: string;
/**
* Subtitle of the menu header
*/
subtitle?: string;
/**
* Leading element of the menu header
*/
leading?: React.ReactNode;
/**
* Trailing element of the menu header
*/
trailing?: React.ReactNode;
/**
* Item that goes immediately next to the title
*/
titleSuffix?: React.ReactNode;
/**
* Test ID for testing
*/
testID?: string;
/**
* Data analytics attributes
*/
'data-analytics'?: string;
};
// MenuFooter props
type MenuFooterProps = {
/**
* Children of the menu footer
*/
children: React.ReactNode;
/**
* Test ID for testing
*/
testID?: string;
/**
* Data analytics attributes
*/
'data-analytics'?: string;
};
// MenuDivider props
type MenuDividerProps = TestID & DataAnalyticsAttribute;
```
## Example
### Comprehensive Profile Menu
This example demonstrates a comprehensive menu with an Avatar trigger and various menu components including MenuHeader, MenuItem, nested menus, MenuDivider, and MenuFooter. It shows how to structure a user profile menu with details, actions, and a footer message.
```tsx
import React from 'react';
import {
Menu,
MenuDivider,
MenuItem,
MenuOverlay,
MenuHeader,
MenuFooter,
Button,
Box,
Link,
Text,
Avatar,
CopyIcon,
LogOutIcon,
ShareIcon,
TestIcon,
TicketIcon,
UserIcon,
} from '@razorpay/blade/components';
function BasicMenu() {
return (
<Box>
<Menu>
<Avatar name="Saurabh Daware" size="large" color="primary" />
<MenuOverlay>
<MenuHeader title="Saurabh Daware" subtitle="Admin" leading={<UserIcon />} />
<Box paddingY="spacing.4" paddingX="spacing.3">
<Text display="block" size="medium" weight="semibold">
Razorpay Pvt Ltd
</Text>
<Box display="flex" alignItems="center" gap="spacing.3">
<Text size="small">MID: Xyzyspoon13857</Text>
<Link variant="button" size="small" icon={CopyIcon} />
</Box>
</Box>
<Button variant="tertiary" isFullWidth size="xsmall">
Switch Merchant
</Button>
<MenuDivider marginY="spacing.3" />
<MenuItem
title="Enable Test Mode"
leading={<TestIcon size="small" />}
description="Enable test mode"
/>
<MenuItem
title="View Support Tickets"
leading={<TicketIcon size="small" />}
description="View all your support tickets"
/>
<Menu>
<MenuItem leading={<ShareIcon size="small" />} title="Share Profile" />
<MenuOverlay>
<MenuItem title="Mail" />
<Menu>
<MenuItem title="Instagram" />
<MenuOverlay>
<MenuItem title="Instagram Stories" />
<MenuItem title="Instagram Post" />
<MenuItem title="Instagram Chat" />
</MenuOverlay>
</Menu>
</MenuOverlay>
</Menu>
<MenuItem
leading={<LogOutIcon size="small" color="feedback.icon.negative.intense" />}
title="Log Out"
color="negative"
/>
<MenuFooter>
<Text variant="caption" size="small">
Partner with us and start earning on every referral
</Text>
</MenuFooter>
</MenuOverlay>
</Menu>
</Box>
);
}
export default BasicMenu;
```
### Controlled Menu
This example shows how to create a controlled menu where the open state is managed by the component's state. It uses a button to explicitly open the menu and demonstrates the `isOpen` and `onOpenChange` props for programmatic control of the menu's visibility.
```tsx
import React, { useState } from 'react';
import {
Menu,
MenuDivider,
MenuItem,
MenuOverlay,
MenuHeader,
MenuFooter,
Button,
Box,
Link,
Text,
Avatar,
CopyIcon,
LogOutIcon,
ShareIcon,
TestIcon,
TicketIcon,
UserIcon,
} from '@razorpay/blade/components';
function ControlledMenu() {
const [isOpen, setIsOpen] = useState(false);
return (
<Box>
<Button marginY="spacing.4" onClick={() => setIsOpen(true)}>
Open Menu
</Button>
<Menu isOpen={isOpen} onOpenChange={({ isOpen }) => setIsOpen(isOpen)}>
<Avatar name="Saurabh Daware" size="large" color="primary" />
<MenuOverlay>
<MenuHeader title="Saurabh Daware" subtitle="Admin" leading={<UserIcon />} />
<Box paddingY="spacing.4" paddingX="spacing.3">
<Text display="block" size="medium" weight="semibold">
Razorpay Pvt Ltd
</Text>
<Box display="flex" alignItems="center" gap="spacing.3">
<Text size="small">MID: Xyzyspoon13857</Text>
<Link variant="button" size="small" icon={CopyIcon} />
</Box>
</Box>
<Button variant="tertiary" isFullWidth size="xsmall">
Switch Merchant
</Button>
<MenuDivider marginY="spacing.3" />
<MenuItem
title="Enable Test Mode"
leading={<TestIcon size="small" />}
description="Enable test mode"
/>
<MenuItem
title="View Support Tickets"
leading={<TicketIcon size="small" />}
description="View all your support tickets"
/>
<MenuItem
leading={<LogOutIcon size="small" color="feedback.icon.negative.intense" />}
title="Log Out"
color="negative"
onClick={() => console.log('Logging out')}
/>
</MenuOverlay>
</Menu>
</Box>
);
}
export default ControlledMenu;
```