src/stories/DropdownMenu2/examples.stories.tsx (226 lines of code) (raw):

import React from 'react' import {Meta} from '@storybook/react' import {ThemeProvider} from '../..' import BaseStyles from '../../BaseStyles' import {DropdownMenu} from '../../DropdownMenu2' import {ActionList} from '../../ActionList2' import Box from '../../Box' import Text from '../../Text' import { GearIcon, MilestoneIcon, CalendarIcon, IterationsIcon, NumberIcon, SingleSelectIcon, TypographyIcon, IssueOpenedIcon, TableIcon, PeopleIcon, XIcon } from '@primer/octicons-react' const meta: Meta = { title: 'Composite components/DropdownMenu2/examples', component: DropdownMenu, decorators: [ (Story: React.ComponentType): JSX.Element => ( <ThemeProvider> <BaseStyles> <Story /> </BaseStyles> </ThemeProvider> ) ], parameters: { controls: { disabled: true } } } export default meta const fieldTypes = [ {icon: TypographyIcon, name: 'Text'}, {icon: NumberIcon, name: 'Number'}, {icon: CalendarIcon, name: 'Date'}, {icon: SingleSelectIcon, name: 'Single select'}, {icon: IterationsIcon, name: 'Iteration'} ] export function SingleSelection(): JSX.Element { const [selectedIndex, setSelectedIndex] = React.useState(0) const selectedType = fieldTypes[selectedIndex] return ( <> <h1>Simple Dropdown Menu</h1> <p>This pattern is the classic dropdown menu - single section with the selected value shown in the button</p> <DropdownMenu> <DropdownMenu.Button aria-label="Select field type" leadingIcon={selectedType.icon}> {selectedType.name} </DropdownMenu.Button> <DropdownMenu.Overlay width="medium"> <ActionList> {fieldTypes.map((type, index) => ( <ActionList.Item key={index} selected={index === selectedIndex} onSelect={() => setSelectedIndex(index)}> <type.icon /> {type.name} </ActionList.Item> ))} </ActionList> </DropdownMenu.Overlay> </DropdownMenu> </> ) } export function WithPlaceholder(): JSX.Element { const [selectedIndex, setSelectedIndex] = React.useState(-1) const selectedType = fieldTypes[selectedIndex] || {} return ( <> <h1>With placeholder</h1> <p>This pattern is the starting state of the dropdown menu with a placeholder when there is default value</p> <DropdownMenu> <DropdownMenu.Button aria-label="Select field type" leadingIcon={selectedType.icon}> {selectedType.name || 'Pick a field type'} </DropdownMenu.Button> <DropdownMenu.Overlay width="medium"> <ActionList> {fieldTypes.map((type, index) => ( <ActionList.Item key={index} selected={index === selectedIndex} onSelect={() => setSelectedIndex(index)}> <type.icon /> {type.name} </ActionList.Item> ))} </ActionList> </DropdownMenu.Overlay> </DropdownMenu> </> ) } const milestones = [ {name: 'FY21 - Q2', due: 'December 31, 2021', progress: 90}, {name: 'FY22 - Q3', due: 'March 31, 2022', progress: 10}, {name: 'FY23 - Q1', due: 'June 30, 2022', progress: 0}, {name: 'FY23 - Q2', due: 'December 30, 2022', progress: 0} ] export function GroupsAndDescription(): JSX.Element { const [selectedMilestone, setSelectedMilestone] = React.useState<typeof milestones[0] | undefined>() return ( <> <h1>Milestone selector</h1> <Box sx={{width: 200}}> <DropdownMenu> <DropdownMenu.Button aria-label="Select a milestone" variant="invisible" trailingIcon={GearIcon} sx={{ color: 'fg.muted', width: '100%', paddingX: 0, gridTemplateColumns: 'min-content 1fr min-content', textAlign: 'left', ':hover, :focus': {background: 'none !important', color: 'accent.fg'} }} > Milestone </DropdownMenu.Button> <DropdownMenu.Overlay width="medium"> <ActionList showDividers role="none"> <ActionList.Group title="Open" role="menu"> {milestones .filter(milestone => !milestone.name.includes('21')) .map((milestone, index) => ( <ActionList.Item key={index} selected={milestone.name === selectedMilestone?.name} onSelect={() => setSelectedMilestone(milestone)} > <ActionList.LeadingVisual> <MilestoneIcon /> </ActionList.LeadingVisual> {milestone.name} <ActionList.Description variant="block">Due by {milestone.due}</ActionList.Description> </ActionList.Item> ))} </ActionList.Group> <ActionList.Group title="Closed" role="menu"> {milestones .filter(milestone => milestone.name.includes('21')) .map((milestone, index) => ( <ActionList.Item key={index} selected={milestone.name === selectedMilestone?.name} onSelect={() => setSelectedMilestone(milestone)} > <ActionList.LeadingVisual> <MilestoneIcon /> </ActionList.LeadingVisual> {milestone.name} <ActionList.Description variant="block">Due by {milestone.due}</ActionList.Description> </ActionList.Item> ))} </ActionList.Group> </ActionList> </DropdownMenu.Overlay> </DropdownMenu> {selectedMilestone ? ( <Text as="div" color="fg.muted" sx={{fontSize: 1, mt: 2}}> {selectedMilestone.name} </Text> ) : ( <Text as="div" color="fg.muted" sx={{fontSize: 1, mt: 2}}> No milestone </Text> )} </Box> </> ) } export function MixedSelection(): JSX.Element { const [selectedIndex, setSelectedIndex] = React.useState<number | null>(1) const options = [ {text: 'Status', icon: IssueOpenedIcon}, {text: 'Stage', icon: TableIcon}, {text: 'Assignee', icon: PeopleIcon}, {text: 'Team', icon: TypographyIcon}, {text: 'Estimate', icon: NumberIcon}, {text: 'Due Date', icon: CalendarIcon} ] const selectedOption = selectedIndex && options[selectedIndex] return ( <> <h1>List with mixed selection</h1> <p> In this list, there is a ActionList.Group with single selection for picking one option, followed by a Item that is an action. This pattern appears inside a DropdownMenu for selection view options in Memex </p> <DropdownMenu> <DropdownMenu.Button aria-label="Select field type" leadingIcon={selectedOption && selectedOption.icon}> {selectedOption ? `Group by ${selectedOption.text}` : 'Group items by'} </DropdownMenu.Button> <DropdownMenu.Overlay width="medium"> <ActionList role="none"> <ActionList.Group title="Group by" role="menu"> {options.map((option, index) => ( <ActionList.Item key={index} selected={index === selectedIndex} onSelect={() => setSelectedIndex(index)} > <ActionList.LeadingVisual>{option.icon}</ActionList.LeadingVisual> {option.text} </ActionList.Item> ))} </ActionList.Group> {typeof selectedIndex === 'number' && ( <ActionList.Group role="menu"> <ActionList.Divider /> <ActionList.Item onSelect={() => setSelectedIndex(null)} role="menuitem"> <ActionList.LeadingVisual> <XIcon /> </ActionList.LeadingVisual> Clear Group by </ActionList.Item> </ActionList.Group> )} </ActionList> </DropdownMenu.Overlay> </DropdownMenu> </> ) }