This pattern appears inside a nested DropdownMenu in Memex view options.
+ This pattern appears inside a nested menu in Memex view options.
{options.map((option, index) => (
@@ -266,7 +266,7 @@ export function MixedSelection(): JSX.Element {
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
+ is an action. This pattern appears inside a menu for selection view options in Memex
diff --git a/src/stories/ActionMenu2/examples.stories.tsx b/src/stories/ActionMenu2/examples.stories.tsx
index 0130751049a..3412c22e6e7 100644
--- a/src/stories/ActionMenu2/examples.stories.tsx
+++ b/src/stories/ActionMenu2/examples.stories.tsx
@@ -1,9 +1,20 @@
import React from 'react'
import {Meta} from '@storybook/react'
-import {ThemeProvider} from '../..'
-import BaseStyles from '../../BaseStyles'
-import {ActionMenu} from '../../ActionMenu2'
-import {ActionList} from '../../ActionList2'
+import {ThemeProvider, BaseStyles, Box, Text, Avatar} from '../..'
+import {ActionMenu, ActionList} from '../../drafts'
+import {
+ GearIcon,
+ MilestoneIcon,
+ CalendarIcon,
+ IterationsIcon,
+ NumberIcon,
+ SingleSelectIcon,
+ TypographyIcon,
+ IssueOpenedIcon,
+ TableIcon,
+ PeopleIcon,
+ XIcon
+} from '@primer/octicons-react'
const meta: Meta = {
title: 'Composite components/ActionMenu2/examples',
@@ -25,7 +36,7 @@ const meta: Meta = {
}
export default meta
-export function SimpleListStory(): JSX.Element {
+export function MenuWithActions(): JSX.Element {
const [actionFired, fireAction] = React.useState('')
const onSelect = (name: string) => fireAction(name)
@@ -60,4 +71,285 @@ export function SimpleListStory(): JSX.Element {
>
)
}
-SimpleListStory.storyName = 'Simple Menu'
+
+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 (
+ <>
+ Single Selection
+
+ This pattern has a single section with the selected value shown in the button
+
+
+
+ {selectedType.name}
+
+
+
+ {fieldTypes.map((type, index) => (
+ setSelectedIndex(index)}
+ disabled={index === 3}
+ >
+ {type.name}
+
+ ))}
+
+
+
+ >
+ )
+}
+
+export function SingleSelectionWithPlaceholder(): JSX.Element {
+ const [selectedIndex, setSelectedIndex] = React.useState(-1)
+ const selectedType = fieldTypes[selectedIndex] || {}
+
+ return (
+ <>
+ With placeholder
+
+ This pattern has a placeholder in menu button when no value is selected yet
+
+
+
+ {selectedType.name || 'Pick a field type'}
+
+
+
+ {fieldTypes.map((type, index) => (
+ setSelectedIndex(index)}>
+ {type.name}
+
+ ))}
+
+
+
+ >
+ )
+}
+
+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()
+
+ return (
+ <>
+ Milestone selector
+
+
+
+ Milestone
+
+
+
+
+ {milestones
+ .filter(milestone => !milestone.name.includes('21'))
+ .map((milestone, index) => (
+ setSelectedMilestone(milestone)}
+ >
+
+
+
+ {milestone.name}
+ Due by {milestone.due}
+
+ ))}
+
+
+ {milestones
+ .filter(milestone => milestone.name.includes('21'))
+ .map((milestone, index) => (
+ setSelectedMilestone(milestone)}
+ >
+
+
+
+ {milestone.name}
+ Due by {milestone.due}
+
+ ))}
+
+
+
+
+ {selectedMilestone ? (
+
+ {selectedMilestone.name}
+
+ ) : (
+
+ No milestone
+
+ )}
+
+ >
+ )
+}
+
+const users = [
+ {login: 'pksjce', name: 'Pavithra Kodmad'},
+ {login: 'jfuchs', name: 'Jonathan Fuchs'},
+ {login: 'colebemis', name: 'Cole Bemis'},
+ {login: 'mperrotti', name: 'Mike Perrotti'},
+ {login: 'dgreif', name: 'Dusty Greif'},
+ {login: 'smockle', name: 'Clay Miller'},
+ {login: 'siddharthkp', name: 'Siddharth Kshetrapal'}
+]
+
+export function MultipleSelection(): JSX.Element {
+ const [assignees, setAssignees] = React.useState(users.slice(0, 2))
+
+ const toggleAssignee = (assignee: typeof users[number]) => {
+ const assigneeIndex = assignees.findIndex(a => a.login === assignee.login)
+
+ if (assigneeIndex === -1) setAssignees([...assignees, assignee])
+ else setAssignees(assignees.filter((_, index) => index !== assigneeIndex))
+ }
+
+ return (
+ <>
+ Multi Select List
+
+ ActionMenu with multiple selection is not seen in production. You see SelectPanel used instead.
+
+
+
+
+ Assignees
+
+
+
+ {users.map(user => (
+ assignee.login === user.login))}
+ onSelect={() => toggleAssignee(user)}
+ >
+
+
+
+ {user.login}
+ {user.name}
+
+ ))}
+
+
+
+
+ >
+ )
+}
+
+export function MixedSelection(): JSX.Element {
+ const [selectedIndex, setSelectedIndex] = React.useState(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 !== null && options[selectedIndex]
+
+ return (
+ <>
+ List with mixed selection
+
+
+ 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 ActionMenu for selection view options in Memex
+
+
+
+
+ {selectedOption ? `Group by ${selectedOption.text}` : 'Group items by'}
+
+
+
+
+ {options.map((option, index) => (
+ setSelectedIndex(index)}
+ >
+
+
+
+ {option.text}
+
+ ))}
+
+ {typeof selectedIndex === 'number' && (
+
+
+ setSelectedIndex(null)} role="menuitem">
+
+
+
+ Clear Group by
+
+
+ )}
+
+
+
+ >
+ )
+}
diff --git a/src/stories/ActionMenu2/fixtures.stories.tsx b/src/stories/ActionMenu2/fixtures.stories.tsx
index 3fbf73013dc..1a279b1d46b 100644
--- a/src/stories/ActionMenu2/fixtures.stories.tsx
+++ b/src/stories/ActionMenu2/fixtures.stories.tsx
@@ -1,16 +1,7 @@
import React from 'react'
import {Meta} from '@storybook/react'
-import {ThemeProvider} from '../..'
-import BaseStyles from '../../BaseStyles'
-import {ActionMenu} from '../../ActionMenu2'
-import {ActionList} from '../../ActionList2'
-import {Button} from '../../Button2'
-import {IconButton} from '../../Button2/IconButton'
-import Box from '../../Box'
-import Text from '../../Text'
-import TextInput from '../../TextInput'
-import StyledOcticon from '../../StyledOcticon'
-import FormGroup from '../../FormGroup'
+import {ThemeProvider, BaseStyles, Box, Text, TextInput, StyledOcticon, FormGroup} from '../..'
+import {ActionMenu, ActionList, Button, IconButton} from '../../drafts'
import {
ServerIcon,
PlusCircleIcon,
@@ -25,6 +16,11 @@ import {
SearchIcon,
VersionsIcon,
TableIcon,
+ CalendarIcon,
+ IterationsIcon,
+ NumberIcon,
+ SingleSelectIcon,
+ TypographyIcon,
IconProps
} from '@primer/octicons-react'
@@ -86,7 +82,6 @@ export function ActionsStory(): JSX.Element {
>
)
}
-ActionsStory.storyName = 'Actions'
export function ExternalAnchor(): JSX.Element {
const [actionFired, fireAction] = React.useState('')
@@ -133,7 +128,6 @@ export function ExternalAnchor(): JSX.Element {
>
)
}
-ExternalAnchor.storyName = 'External Anchor'
export function ControlledMenu(): JSX.Element {
const [actionFired, fireAction] = React.useState('')
@@ -191,7 +185,6 @@ export function ControlledMenu(): JSX.Element {
>
)
}
-ControlledMenu.storyName = 'Controlled Menu'
export function CustomAnchor(): JSX.Element {
const [actionFired, fireAction] = React.useState('')
@@ -233,7 +226,6 @@ export function CustomAnchor(): JSX.Element {
>
)
}
-CustomAnchor.storyName = 'Custom Anchor'
export function MemexTableMenu(): JSX.Element {
const [name, setName] = React.useState('Estimate')
@@ -297,7 +289,6 @@ export function MemexTableMenu(): JSX.Element {
>
)
}
-MemexTableMenu.storyName = 'Memex Table Menu'
/* copied from github/memex */
const LayoutToggleItem = ({
@@ -408,19 +399,15 @@ export function MemexViewOptionsMenu(): JSX.Element {
React
-
-
-
+
+
+
@@ -495,7 +482,105 @@ export function MemexViewOptionsMenu(): JSX.Element {
>
)
}
-MemexViewOptionsMenu.storyName = 'Memex View Options Menu'
+
+export function MemexIteration(): JSX.Element {
+ const [duration, setDuration] = React.useState(1)
+
+ return (
+ <>
+ Memex Iteration Menu
+
+
+
+ {duration} {duration > 1 ? 'weeks' : 'week'}
+
+
+
+ {[1, 2, 3, 4, 5, 6].map(weeks => (
+ setDuration(weeks)}>
+ {weeks} {weeks > 1 ? 'weeks' : 'week'}
+
+ ))}
+
+
+
+ >
+ )
+}
+
+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 MemexAddColumn(): JSX.Element {
+ const [selectedIndex, setSelectedIndex] = React.useState(0)
+ const selectedType = fieldTypes[selectedIndex]
+
+ const [duration, setDuration] = React.useState(1)
+
+ return (
+ <>
+ Memex Add column
+
+
+
+
+
+ {selectedType.name}
+
+
+
+ {fieldTypes.map((type, index) => (
+ setSelectedIndex(index)}
+ >
+ {type.icon} {type.name}
+
+ ))}
+
+
+
+ Options
+
+
+ Duration:
+
+
+ {duration} {duration > 1 ? 'weeks' : 'week'}
+
+
+
+ {[1, 2, 3, 4, 5, 6].map(weeks => (
+ setDuration(weeks)}>
+ {weeks} {weeks > 1 ? 'weeks' : 'week'}
+
+ ))}
+
+
+
+
+
+ >
+ )
+}
export function OverlayProps(): JSX.Element {
const [open, setOpen] = React.useState(false)
@@ -534,30 +619,7 @@ export function OverlayProps(): JSX.Element {
-
- >
- )
-}
-OverlayProps.storyName = 'Overlay Props'
-
-export function UnexpectedSelectionVariant(): JSX.Element {
- return (
- <>
- Expect error if selectionVariant is passed
-
-
- Menu
-
-
- Copy link
- Quote reply
- Edit comment
-
- Delete file
-
-
-
+
>
)
}
-UnexpectedSelectionVariant.storyName = 'Unexpected selectionVariant'
diff --git a/src/stories/Overlay.stories.tsx b/src/stories/Overlay.stories.tsx
index 5392d4c9a15..dd635c6338a 100644
--- a/src/stories/Overlay.stories.tsx
+++ b/src/stories/Overlay.stories.tsx
@@ -23,7 +23,7 @@ import {
} from '..'
import type {AnchorSide} from '@primer/behaviors'
import {DropdownMenu, DropdownButton} from '../DropdownMenu'
-import {DropdownMenu as DropdownMenu2, ActionList as ActionList2} from '../drafts'
+import {ActionMenu, ActionList as ActionList2} from '../drafts'
import {ItemInput} from '../ActionList/List'
export default {
@@ -362,20 +362,20 @@ export const MemexNestedOverlays = () => {
Duration:
-
-
+
+
{duration}
-
-
-
+
+
+
{durations.map(item => (
setDuration(item)}>
{item}
))}
-
-
+
+
diff --git a/src/utils/types/AriaRole.ts b/src/utils/types/AriaRole.ts
index 87471c6c67f..b1d1d1f4914 100644
--- a/src/utils/types/AriaRole.ts
+++ b/src/utils/types/AriaRole.ts
@@ -35,7 +35,7 @@ export type AriaRole =
| 'menu'
| 'menubar'
| 'menuitem'
- | 'menuitemcheckbox '
+ | 'menuitemcheckbox'
| 'menuitemradio'
| 'navigation'
| 'none'