UNPKG

@razorpay/blade-mcp

Version:

Model Context Protocol server for Blade

528 lines (454 loc) 12.4 kB
## Component Name Dropdown ## Description Dropdown is a versatile component that displays a floating overlay with content beneath a trigger element. It supports various trigger types (buttons, links, inputs) and content patterns including selection menus, filter chips, and autocomplete. Dropdown offers controlled and uncontrolled modes, with built-in positioning logic to ensure the overlay appears in the optimal location regardless of available space. ## TypeScript Types The following types represent the props that the Dropdown component and its subcomponents accept. ```typescript /** * Props for the Dropdown component */ type DropdownProps = { /** * The type of selection the dropdown supports * @default 'single' */ selectionType?: 'single' | 'multiple'; /** * Children of the dropdown (typically a trigger and overlay) */ children: React.ReactNode; /** * Controls whether the dropdown is open (controlled mode) */ isOpen?: boolean; /** * Controls whether the dropdown is initially open (uncontrolled mode) */ defaultIsOpen?: boolean; /** * Callback fired when the open state changes */ onOpenChange?: (isOpen: boolean) => void; /** * If true, dropdown will close when clicking outside * @default true */ shouldCloseOnClickOutside?: boolean; /** * If true, dropdown will close when pressing the escape key * @default true */ shouldCloseOnEscape?: boolean; } & StyledPropsBlade & TestID; /** * Props for the DropdownOverlay component */ type DropdownOverlayProps = { /** * Children of the overlay */ children: React.ReactNode; /** * Width of the overlay */ width?: string | number; /** * Maximum width of the overlay */ maxWidth?: string | number; /** * Maximum height of the overlay */ maxHeight?: string | number; } & StyledPropsBlade; /** * Props for the DropdownButton component */ type DropdownButtonProps = { /** * Children of the button (typically text content) */ children: React.ReactNode; /** * The variant of the button * @default 'primary' */ variant?: 'primary' | 'secondary' | 'tertiary'; /** * Size of the button * @default 'medium' */ size?: 'small' | 'medium' | 'large'; /** * Whether the button is disabled * @default false */ isDisabled?: boolean; } & StyledPropsBlade; /** * Props for the DropdownLink component */ type DropdownLinkProps = { /** * Children of the link (typically text content) */ children: React.ReactNode; /** * Icon to display with the link */ icon?: IconComponent; /** * Position of the icon * @default 'left' */ iconPosition?: 'left' | 'right'; /** * Whether the link is disabled * @default false */ isDisabled?: boolean; } & StyledPropsBlade; /** * Props for the DropdownIconButton component */ type DropdownIconButtonProps = { /** * Icon to display in the button */ icon: IconComponent; /** * Accessibility label for the button */ accessibilityLabel: string; /** * Size of the icon button * @default 'medium' */ size?: 'small' | 'medium' | 'large'; /** * Whether the button is disabled * @default false */ isDisabled?: boolean; } & StyledPropsBlade; /** * Props for the DropdownHeader component */ type DropdownHeaderProps = { /** * Title of the header */ title?: string; /** * Subtitle of the header */ subtitle?: string; /** * Content to display at the start of the header */ leading?: React.ReactNode; /** * Content to display at the end of the header */ trailing?: React.ReactNode; /** * Content to display after the title */ titleSuffix?: React.ReactNode; /** * Children of the header (typically for custom content) */ children?: React.ReactNode; } & StyledPropsBlade; /** * Props for the DropdownFooter component */ type DropdownFooterProps = { /** * Children of the footer */ children: React.ReactNode; } & StyledPropsBlade; /** * Props for the FilterChipSelectInput component */ type FilterChipSelectInputProps = { /** * Label text for the filter chip */ label: string; /** * Current value(s) selected */ value?: string | string[]; /** * Callback when selection changes */ onChange?: (value: string | string[]) => void; /** * Callback when clear button is clicked */ onClearButtonClick?: (value: string | string[]) => void; /** * Whether the filter chip is disabled * @default false */ isDisabled?: boolean; } & StyledPropsBlade; /** * Props for the FilterChipGroup component */ type FilterChipGroupProps = { /** * Children of the filter chip group (typically FilterChipSelectInput components) */ children: React.ReactNode; } & StyledPropsBlade; /** * Type for the Icon component */ type IconComponent = React.ComponentType<any>; ``` ## Examples ### Basic Dropdown with Button Trigger This example shows a simple dropdown with a button trigger and action list items. ```tsx import React, { useState } from 'react'; import { Dropdown, DropdownButton, DropdownOverlay, ActionList, ActionListItem, ActionListItemIcon, CheckIcon, ClockIcon, CloseIcon, } from '@razorpay/blade/components'; const BasicDropdownExample = () => { const [status, setStatus] = useState<string | undefined>(); return ( <Dropdown> {/* Button trigger with dynamic text based on selection */} <DropdownButton variant="tertiary" size="medium"> Status: {status || 'Select'} </DropdownButton> <DropdownOverlay width="240px"> <ActionList> <ActionListItem onClick={({ name }) => setStatus(name)} leading={<ActionListItemIcon icon={CheckIcon} />} isSelected={status === 'approve'} title="Approve" value="approve" /> <ActionListItem onClick={({ name }) => setStatus(name)} leading={<ActionListItemIcon icon={ClockIcon} />} isSelected={status === 'in-progress'} title="In Progress" value="in-progress" /> <ActionListItem onClick={({ name }) => setStatus(name)} leading={<ActionListItemIcon icon={CloseIcon} />} isSelected={status === 'reject'} title="Reject" value="reject" intent="negative" /> </ActionList> </DropdownOverlay> </Dropdown> ); }; ``` ### Dropdown with Select Input (Single and Multiple Selection) This example demonstrates a form-style dropdown for selecting values, supporting both single and multiple selection modes. ```tsx import React, { useState } from 'react'; import { Dropdown, DropdownOverlay, DropdownHeader, DropdownFooter, ActionList, ActionListItem, SelectInput, Button, Box, CheckIcon, ClockIcon, CloseIcon, } from '@razorpay/blade/components'; const SelectDropdownExample = () => { // Single selection state const [singleValue, setSingleValue] = useState<string>(''); // Multiple selection state const [multiValues, setMultiValues] = useState<string[]>([]); // Controlled open state for multiple selection dropdown const [isMultiOpen, setIsMultiOpen] = useState(false); return ( <Box display="flex" flexDirection="column" gap="spacing.6"> {/* Single Selection Dropdown */} <Dropdown> <SelectInput label="Select City" placeholder="Choose a city" value={singleValue} onChange={(args) => { if (args) { setSingleValue(args.values[0]); } }} helpText="Select your preferred city" size="medium" /> <DropdownOverlay> <ActionList> <ActionListItem title="Mumbai" value="mumbai" /> <ActionListItem title="Bangalore" value="bangalore" /> <ActionListItem title="Delhi" value="delhi" /> <ActionListItem title="Chennai" value="chennai" /> <ActionListItem title="Hyderabad" value="hyderabad" /> </ActionList> </DropdownOverlay> </Dropdown> {/* Multiple Selection Dropdown with Header and Footer */} <Dropdown selectionType="multiple" isOpen={isMultiOpen} onOpenChange={setIsMultiOpen}> <SelectInput label="Select Multiple Cities" placeholder="Choose cities" value={multiValues} onChange={(args) => { if (args) { setMultiValues(args.values); } }} maxRows="multiple" // Show multiple selected values as tags validationState={multiValues.length === 0 ? 'error' : 'none'} errorText="Please select at least one city" isRequired /> <DropdownOverlay width="300px"> <DropdownHeader title="Available Cities" subtitle="Select one or more" /> <ActionList> <ActionListItem title="Mumbai" value="mumbai" /> <ActionListItem title="Bangalore" value="bangalore" /> <ActionListItem title="Delhi" value="delhi" /> <ActionListItem title="Chennai" value="chennai" /> <ActionListItem title="Hyderabad" value="hyderabad" /> </ActionList> <DropdownFooter> <Box display="flex" justifyContent="space-between" width="100%"> <Button variant="tertiary" size="small" onClick={() => setMultiValues([])}> Clear All </Button> <Button size="small" onClick={() => setIsMultiOpen(false)}> Apply </Button> </Box> </DropdownFooter> </DropdownOverlay> </Dropdown> </Box> ); }; ``` ### AutoComplete Dropdown This example demonstrates the AutoComplete dropdown for searching and selecting options with filtering capabilities. ```tsx import React, { useState } from 'react'; import { Dropdown, DropdownOverlay, DropdownHeader, ActionList, ActionListItem, AutoComplete, Box, CheckIcon, ClockIcon, CloseIcon, TextInput, } from '@razorpay/blade/components'; const AutoCompleteDropdownExample = () => { const fruits = [ 'Apples', 'Apricots', 'Avocados', 'Bananas', 'Blueberries', 'Cherries', 'Cranberries', 'Grapes', 'Lemons', 'Mangoes', 'Oranges', 'Peaches', 'Pears', 'Pineapples', 'Strawberries', ]; const [query, setQuery] = useState(''); const [selectedFruits, setSelectedFruits] = useState<string[]>([]); // Filter fruits based on search query const filteredFruits = query ? fruits.filter((fruit) => fruit.toLowerCase().includes(query.toLowerCase())) : fruits; // Toggle selection of a fruit const toggleFruit = (fruit: string) => { if (selectedFruits.includes(fruit)) { setSelectedFruits(selectedFruits.filter((f) => f !== fruit)); } else { setSelectedFruits([...selectedFruits, fruit]); } }; return ( <Box maxWidth="300px"> <Dropdown selectionType="multiple"> <AutoComplete label="Select Fruits" placeholder="Search fruits..." value={selectedFruits} onChange={(args) => { if (args) { setSelectedFruits(args.values); } }} maxRows="multiple" size="medium" /> <DropdownOverlay> <DropdownHeader> <TextInput label="Search Fruits" value={query} onChange={({ value }) => setQuery(value)} autoFocus /> </DropdownHeader> <ActionList> {filteredFruits.map((fruit) => ( <ActionListItem key={fruit} title={fruit} value={fruit} isSelected={selectedFruits.includes(fruit)} onClick={() => toggleFruit(fruit)} /> ))} {filteredFruits.length === 0 && ( <Box padding="spacing.4" textAlign="center"> No matching fruits found </Box> )} </ActionList> </DropdownOverlay> </Dropdown> </Box> ); }; ```