@primer/components 32.1.1-rc.92743105 → 33.0.0-rc.9cc2a259

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. package/.devcontainer/devcontainer.json +1 -1
  2. package/.github/workflows/ci.yml +1 -1
  3. package/.github/workflows/release.yml +1 -1
  4. package/.github/workflows/release_canary.yml +1 -1
  5. package/.github/workflows/release_candidate.yml +1 -1
  6. package/.github/workflows/statuses.yml +32 -0
  7. package/.gitignore +1 -0
  8. package/.nvmrc +1 -1
  9. package/CHANGELOG.md +20 -2
  10. package/contributor-docs/CONTRIBUTING.md +14 -58
  11. package/dist/browser.esm.js +105 -108
  12. package/dist/browser.esm.js.map +1 -1
  13. package/dist/browser.umd.js +105 -108
  14. package/dist/browser.umd.js.map +1 -1
  15. package/docs/content/BranchName.md +6 -5
  16. package/docs/content/Details.md +4 -8
  17. package/docs/content/Heading.md +5 -10
  18. package/docs/content/Label.md +6 -7
  19. package/docs/content/ProgressBar.mdx +7 -6
  20. package/docs/content/Text.md +0 -6
  21. package/docs/content/{ActionList2.mdx → drafts/ActionList2.mdx} +5 -9
  22. package/docs/content/drafts/ActionMenu2.mdx +251 -0
  23. package/docs/content/status.mdx +1 -1
  24. package/docs/content/system-props.mdx +1 -1
  25. package/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +9 -1
  26. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +1 -1
  27. package/docs/src/component-checklist.js +10 -2
  28. package/lib/ActionList/Item.js +1 -1
  29. package/lib/ActionList2/Divider.d.ts +3 -2
  30. package/lib/ActionList2/Divider.js +10 -5
  31. package/lib/ActionList2/Item.js +21 -5
  32. package/lib/ActionList2/List.js +11 -1
  33. package/lib/ActionList2/MenuContext.d.ts +10 -0
  34. package/lib/ActionList2/MenuContext.js +15 -0
  35. package/lib/ActionList2/Selection.js +14 -1
  36. package/lib/ActionList2/index.d.ts +1 -2
  37. package/lib/ActionMenu2.d.ts +313 -0
  38. package/lib/ActionMenu2.js +91 -0
  39. package/lib/Autocomplete/Autocomplete.d.ts +2 -1
  40. package/lib/Autocomplete/AutocompleteInput.d.ts +2 -1
  41. package/lib/Avatar.d.ts +1 -2
  42. package/lib/Avatar.js +1 -1
  43. package/lib/BranchName.d.ts +1 -2
  44. package/lib/BranchName.js +1 -1
  45. package/lib/Button/Button.d.ts +2 -2
  46. package/lib/Button/ButtonClose.d.ts +2 -2
  47. package/lib/Button/ButtonDanger.d.ts +2 -2
  48. package/lib/Button/ButtonInvisible.d.ts +2 -2
  49. package/lib/Button/ButtonOutline.d.ts +2 -2
  50. package/lib/Button/ButtonPrimary.d.ts +2 -2
  51. package/lib/CircleOcticon.d.ts +35 -35
  52. package/lib/Details.d.ts +1 -2
  53. package/lib/Details.js +1 -3
  54. package/lib/Dialog.d.ts +37 -37
  55. package/lib/Dropdown.d.ts +8 -72
  56. package/lib/DropdownMenu/DropdownButton.d.ts +6 -3
  57. package/lib/FilterList.d.ts +1 -1
  58. package/lib/Heading.d.ts +1 -2
  59. package/lib/Heading.js +1 -6
  60. package/lib/Position.d.ts +4 -4
  61. package/lib/ProgressBar.d.ts +16 -11
  62. package/lib/ProgressBar.js +6 -10
  63. package/lib/SelectMenu/SelectMenu.d.ts +11 -10
  64. package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
  65. package/lib/SelectMenu/SelectMenuModal.d.ts +1 -1
  66. package/lib/Spinner.d.ts +1 -2
  67. package/lib/Spinner.js +1 -3
  68. package/lib/TextInputWithTokens.d.ts +2 -1
  69. package/lib/Token/AvatarToken.d.ts +1 -1
  70. package/lib/Token/IssueLabelToken.d.ts +1 -1
  71. package/lib/Token/Token.d.ts +1 -1
  72. package/lib/__tests__/Avatar.test.js +4 -2
  73. package/lib/__tests__/Avatar.types.test.d.ts +3 -0
  74. package/lib/__tests__/Avatar.types.test.js +31 -0
  75. package/lib/__tests__/BranchName.types.test.d.ts +3 -0
  76. package/lib/__tests__/BranchName.types.test.js +28 -0
  77. package/lib/__tests__/Details.types.test.d.ts +3 -0
  78. package/lib/__tests__/Details.types.test.js +28 -0
  79. package/lib/__tests__/Heading.test.js +63 -30
  80. package/lib/__tests__/Heading.types.test.d.ts +3 -0
  81. package/lib/__tests__/Heading.types.test.js +28 -0
  82. package/lib/drafts.d.ts +1 -0
  83. package/lib/drafts.js +13 -0
  84. package/lib/stories/ActionMenu2.stories.js +433 -0
  85. package/lib-esm/ActionList/Item.js +1 -1
  86. package/lib-esm/ActionList2/Divider.d.ts +3 -2
  87. package/lib-esm/ActionList2/Divider.js +8 -5
  88. package/lib-esm/ActionList2/Item.js +19 -5
  89. package/lib-esm/ActionList2/List.js +9 -1
  90. package/lib-esm/ActionList2/MenuContext.d.ts +10 -0
  91. package/lib-esm/ActionList2/MenuContext.js +3 -0
  92. package/lib-esm/ActionList2/Selection.js +12 -1
  93. package/lib-esm/ActionList2/index.d.ts +1 -2
  94. package/lib-esm/ActionMenu2.d.ts +313 -0
  95. package/lib-esm/ActionMenu2.js +67 -0
  96. package/lib-esm/Autocomplete/Autocomplete.d.ts +2 -1
  97. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +2 -1
  98. package/lib-esm/Avatar.d.ts +1 -2
  99. package/lib-esm/Avatar.js +2 -2
  100. package/lib-esm/BranchName.d.ts +1 -2
  101. package/lib-esm/BranchName.js +2 -2
  102. package/lib-esm/Button/Button.d.ts +2 -2
  103. package/lib-esm/Button/ButtonClose.d.ts +2 -2
  104. package/lib-esm/Button/ButtonDanger.d.ts +2 -2
  105. package/lib-esm/Button/ButtonInvisible.d.ts +2 -2
  106. package/lib-esm/Button/ButtonOutline.d.ts +2 -2
  107. package/lib-esm/Button/ButtonPrimary.d.ts +2 -2
  108. package/lib-esm/CircleOcticon.d.ts +35 -35
  109. package/lib-esm/Details.d.ts +1 -2
  110. package/lib-esm/Details.js +1 -2
  111. package/lib-esm/Dialog.d.ts +37 -37
  112. package/lib-esm/Dropdown.d.ts +8 -72
  113. package/lib-esm/DropdownMenu/DropdownButton.d.ts +6 -3
  114. package/lib-esm/FilterList.d.ts +1 -1
  115. package/lib-esm/Heading.d.ts +1 -2
  116. package/lib-esm/Heading.js +2 -6
  117. package/lib-esm/Position.d.ts +4 -4
  118. package/lib-esm/ProgressBar.d.ts +16 -11
  119. package/lib-esm/ProgressBar.js +7 -11
  120. package/lib-esm/SelectMenu/SelectMenu.d.ts +11 -10
  121. package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
  122. package/lib-esm/SelectMenu/SelectMenuModal.d.ts +1 -1
  123. package/lib-esm/Spinner.d.ts +1 -2
  124. package/lib-esm/Spinner.js +1 -2
  125. package/lib-esm/TextInputWithTokens.d.ts +2 -1
  126. package/lib-esm/Token/AvatarToken.d.ts +1 -1
  127. package/lib-esm/Token/IssueLabelToken.d.ts +1 -1
  128. package/lib-esm/Token/Token.d.ts +1 -1
  129. package/lib-esm/__tests__/Avatar.test.js +4 -2
  130. package/lib-esm/__tests__/Avatar.types.test.d.ts +3 -0
  131. package/lib-esm/__tests__/Avatar.types.test.js +16 -0
  132. package/lib-esm/__tests__/BranchName.types.test.d.ts +3 -0
  133. package/lib-esm/__tests__/BranchName.types.test.js +13 -0
  134. package/lib-esm/__tests__/Details.types.test.d.ts +3 -0
  135. package/lib-esm/__tests__/Details.types.test.js +13 -0
  136. package/lib-esm/__tests__/Heading.test.js +62 -30
  137. package/lib-esm/__tests__/Heading.types.test.d.ts +3 -0
  138. package/lib-esm/__tests__/Heading.types.test.js +13 -0
  139. package/lib-esm/drafts.d.ts +1 -0
  140. package/lib-esm/drafts.js +2 -1
  141. package/lib-esm/stories/ActionMenu2.stories.js +376 -0
  142. package/package-lock.json +321 -269
  143. package/package.json +11 -5
  144. package/script/component-status-project/build.ts +100 -0
  145. package/script/component-status-project/deploy.rb +142 -0
  146. package/src/ActionList/Item.tsx +1 -0
  147. package/src/ActionList2/Divider.tsx +13 -8
  148. package/src/ActionList2/Item.tsx +13 -3
  149. package/src/ActionList2/List.tsx +6 -2
  150. package/src/ActionList2/MenuContext.tsx +6 -0
  151. package/src/ActionList2/Selection.tsx +11 -1
  152. package/src/ActionMenu2.tsx +94 -0
  153. package/src/Avatar.tsx +2 -4
  154. package/src/BranchName.tsx +3 -3
  155. package/src/Details.tsx +1 -5
  156. package/src/Heading.tsx +2 -9
  157. package/src/ProgressBar.tsx +11 -10
  158. package/src/Spinner.tsx +1 -3
  159. package/src/__tests__/Avatar.test.tsx +1 -1
  160. package/src/__tests__/Avatar.types.test.tsx +11 -0
  161. package/src/__tests__/BranchName.types.test.tsx +11 -0
  162. package/src/__tests__/Details.types.test.tsx +11 -0
  163. package/src/__tests__/Heading.test.tsx +71 -25
  164. package/src/__tests__/Heading.types.test.tsx +11 -0
  165. package/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +4 -0
  166. package/src/drafts.ts +1 -0
  167. package/src/stories/ActionMenu2.stories.tsx +551 -0
  168. package/stats.html +1 -1
  169. package/tsconfig.build.json +1 -1
  170. package/tsconfig.json +1 -1
@@ -0,0 +1,551 @@
1
+ import React from 'react'
2
+ import {Meta} from '@storybook/react'
3
+ import {ThemeProvider} from '..'
4
+ import BaseStyles from '../BaseStyles'
5
+ import {ActionMenu} from '../ActionMenu2'
6
+ import {ActionList} from '../ActionList2'
7
+ import Button, {ButtonInvisible} from '../Button'
8
+ import Box from '../Box'
9
+ import Text from '../Text'
10
+ import TextInput from '../TextInput'
11
+ import StyledOcticon from '../StyledOcticon'
12
+ import FormGroup from '../FormGroup'
13
+ import {
14
+ ServerIcon,
15
+ PlusCircleIcon,
16
+ TriangleDownIcon,
17
+ KebabHorizontalIcon,
18
+ PencilIcon,
19
+ ArchiveIcon,
20
+ TrashIcon,
21
+ ProjectIcon,
22
+ ListUnorderedIcon,
23
+ ArrowDownIcon,
24
+ SearchIcon,
25
+ VersionsIcon,
26
+ TableIcon,
27
+ IconProps
28
+ } from '@primer/octicons-react'
29
+
30
+ const meta: Meta = {
31
+ title: 'Composite components/ActionMenu2',
32
+ component: ActionMenu,
33
+ decorators: [
34
+ (Story: React.ComponentType): JSX.Element => (
35
+ <ThemeProvider>
36
+ <BaseStyles>
37
+ <Story />
38
+ </BaseStyles>
39
+ </ThemeProvider>
40
+ )
41
+ ],
42
+ parameters: {
43
+ controls: {
44
+ disabled: true
45
+ }
46
+ }
47
+ }
48
+ export default meta
49
+
50
+ export function SimpleListStory(): JSX.Element {
51
+ const [actionFired, fireAction] = React.useState('')
52
+ const onSelect = (name: string) => fireAction(name)
53
+
54
+ return (
55
+ <>
56
+ <h1>Simple Menu</h1>
57
+ <h2>Last option activated: {actionFired}</h2>
58
+ <ActionMenu>
59
+ <ActionMenu.Button>Menu</ActionMenu.Button>
60
+
61
+ <ActionList>
62
+ <ActionList.Item onSelect={() => onSelect('Copy link')}>
63
+ Copy link
64
+ <ActionList.TrailingVisual>⌘C</ActionList.TrailingVisual>
65
+ </ActionList.Item>
66
+ <ActionList.Item onSelect={() => onSelect('Quote reply')}>
67
+ Quote reply
68
+ <ActionList.TrailingVisual>⌘Q</ActionList.TrailingVisual>
69
+ </ActionList.Item>
70
+ <ActionList.Item onSelect={() => onSelect('Edit comment')}>
71
+ Edit comment
72
+ <ActionList.TrailingVisual>⌘E</ActionList.TrailingVisual>
73
+ </ActionList.Item>
74
+ <ActionList.Divider />
75
+ <ActionList.Item variant="danger" onSelect={() => onSelect('Delete file')}>
76
+ Delete file
77
+ <ActionList.TrailingVisual>⌘D</ActionList.TrailingVisual>
78
+ </ActionList.Item>
79
+ </ActionList>
80
+ </ActionMenu>
81
+ </>
82
+ )
83
+ }
84
+ SimpleListStory.storyName = 'Simple Menu'
85
+
86
+ export function ActionsStory(): JSX.Element {
87
+ return (
88
+ <>
89
+ <h1>Actions</h1>
90
+
91
+ <ActionMenu overlayProps={{width: 'medium'}}>
92
+ <ActionMenu.Button aria-label="Open Actions Menu">
93
+ <ServerIcon />
94
+ </ActionMenu.Button>
95
+ <ActionList>
96
+ <ActionList.Item>
97
+ <ActionList.LeadingVisual>
98
+ <ServerIcon />
99
+ </ActionList.LeadingVisual>
100
+ Open current Codespace
101
+ <ActionList.Description variant="block">
102
+ Your existing Codespace will be opened to its previous state, and you&apos;ll be asked to manually switch
103
+ to new-branch.
104
+ </ActionList.Description>
105
+ <ActionList.TrailingVisual>⌘O</ActionList.TrailingVisual>
106
+ </ActionList.Item>
107
+ <ActionList.Item>
108
+ <ActionList.LeadingVisual>
109
+ <PlusCircleIcon />
110
+ </ActionList.LeadingVisual>
111
+ Create new Codespace
112
+ <ActionList.Description variant="block">
113
+ Create a brand new Codespace with a fresh image and checkout this branch.
114
+ </ActionList.Description>
115
+ <ActionList.TrailingVisual>⌘C</ActionList.TrailingVisual>
116
+ </ActionList.Item>
117
+ </ActionList>
118
+ </ActionMenu>
119
+ </>
120
+ )
121
+ }
122
+ ActionsStory.storyName = 'Actions'
123
+
124
+ export function ExternalAnchor(): JSX.Element {
125
+ const [actionFired, fireAction] = React.useState('')
126
+ const onSelect = (name: string) => fireAction(name)
127
+
128
+ const [open, setOpen] = React.useState(false)
129
+ const triggerRef = React.createRef<HTMLButtonElement>()
130
+
131
+ return (
132
+ <>
133
+ <h1>External Anchor</h1>
134
+ <h2>External Open State: {open ? 'Open' : 'Closed'}</h2>
135
+ <h2>Last option activated: {actionFired}</h2>
136
+ <div>
137
+ <Button ref={triggerRef} onClick={() => setOpen(!open)}>
138
+ {open ? 'Close Menu' : 'Open Menu'}
139
+ </Button>
140
+ </div>
141
+ <br />
142
+
143
+ <ActionMenu open={open} onOpenChange={setOpen} anchorRef={triggerRef}>
144
+ <ActionList>
145
+ <ActionList.Item onSelect={() => onSelect('Copy link')}>
146
+ Copy link
147
+ <ActionList.TrailingVisual>⌘C</ActionList.TrailingVisual>
148
+ </ActionList.Item>
149
+ <ActionList.Item onSelect={() => onSelect('Quote reply')}>
150
+ Quote reply
151
+ <ActionList.TrailingVisual>⌘Q</ActionList.TrailingVisual>
152
+ </ActionList.Item>
153
+ <ActionList.Item onSelect={() => onSelect('Edit comment')}>
154
+ Edit comment
155
+ <ActionList.TrailingVisual>⌘E</ActionList.TrailingVisual>
156
+ </ActionList.Item>
157
+ <ActionList.Divider />
158
+ <ActionList.Item variant="danger" onSelect={() => onSelect('Delete file')}>
159
+ Delete file
160
+ <ActionList.TrailingVisual>⌘D</ActionList.TrailingVisual>
161
+ </ActionList.Item>
162
+ </ActionList>
163
+ </ActionMenu>
164
+ </>
165
+ )
166
+ }
167
+ ExternalAnchor.storyName = 'External Anchor'
168
+
169
+ export function ControlledMenu(): JSX.Element {
170
+ const [actionFired, fireAction] = React.useState('')
171
+ const onSelect = (name: string) => fireAction(name)
172
+
173
+ const [open, setOpen] = React.useState(false)
174
+ const triggerRef = React.createRef<HTMLButtonElement>()
175
+
176
+ return (
177
+ <>
178
+ <h1>Controlled Menu</h1>
179
+ <h2>External Open State: {open ? 'Open' : 'Closed'}</h2>
180
+ <h2>Last option activated: {actionFired}</h2>
181
+ <div>
182
+ <Button ref={triggerRef} onClick={() => setOpen(!open)}>
183
+ {open ? 'Close Menu' : 'Open Menu'}
184
+ </Button>
185
+ </div>
186
+ <br />
187
+
188
+ <ActionMenu
189
+ open={open}
190
+ onOpenChange={setOpen}
191
+ overlayProps={{
192
+ // Because the component is controlled from outside, but the anchor is still internal,
193
+ // clicking the external button should not be counted as "clicking outside"
194
+ ignoreClickRefs: [triggerRef]
195
+ }}
196
+ >
197
+ {/**
198
+ * Even though the state is controlled externally,
199
+ * we can pass an Anchor for the menu to "anchor to"
200
+ */}
201
+ <ActionMenu.Button>Anchor</ActionMenu.Button>
202
+ <ActionList>
203
+ <ActionList.Item onSelect={() => onSelect('Copy link')}>
204
+ Copy link
205
+ <ActionList.TrailingVisual>⌘C</ActionList.TrailingVisual>
206
+ </ActionList.Item>
207
+ <ActionList.Item onSelect={() => onSelect('Quote reply')}>
208
+ Quote reply
209
+ <ActionList.TrailingVisual>⌘Q</ActionList.TrailingVisual>
210
+ </ActionList.Item>
211
+ <ActionList.Item onSelect={() => onSelect('Edit comment')}>
212
+ Edit comment
213
+ <ActionList.TrailingVisual>⌘E</ActionList.TrailingVisual>
214
+ </ActionList.Item>
215
+ <ActionList.Divider />
216
+ <ActionList.Item variant="danger" onSelect={() => onSelect('Delete file')}>
217
+ Delete file
218
+ <ActionList.TrailingVisual>⌘D</ActionList.TrailingVisual>
219
+ </ActionList.Item>
220
+ </ActionList>
221
+ </ActionMenu>
222
+ </>
223
+ )
224
+ }
225
+ ControlledMenu.storyName = 'Controlled Menu'
226
+
227
+ export function CustomAnchor(): JSX.Element {
228
+ const [actionFired, fireAction] = React.useState('')
229
+ const onSelect = (name: string) => fireAction(name)
230
+
231
+ return (
232
+ <>
233
+ <h1>Custom Anchor</h1>
234
+ <h2>Last option activated: {actionFired}</h2>
235
+ <ActionMenu>
236
+ <ActionMenu.Anchor>
237
+ <summary style={{cursor: 'pointer'}} aria-label="Open column options">
238
+ <KebabHorizontalIcon />
239
+ </summary>
240
+ </ActionMenu.Anchor>
241
+
242
+ <ActionList>
243
+ <ActionList.Item onSelect={() => onSelect('Rename')}>
244
+ <ActionList.LeadingVisual>
245
+ <PencilIcon />
246
+ </ActionList.LeadingVisual>
247
+ Rename
248
+ </ActionList.Item>
249
+ <ActionList.Item onSelect={() => onSelect('Archive')}>
250
+ <ActionList.LeadingVisual>
251
+ <ArchiveIcon />
252
+ </ActionList.LeadingVisual>
253
+ Archive all cards
254
+ </ActionList.Item>
255
+ <ActionList.Item variant="danger" onSelect={() => onSelect('Delete file')}>
256
+ <ActionList.LeadingVisual>
257
+ <TrashIcon />
258
+ </ActionList.LeadingVisual>
259
+ Delete
260
+ </ActionList.Item>
261
+ </ActionList>
262
+ </ActionMenu>
263
+ </>
264
+ )
265
+ }
266
+ CustomAnchor.storyName = 'Custom Anchor'
267
+
268
+ export function MemexTableMenu(): JSX.Element {
269
+ const [name, setName] = React.useState('Estimate')
270
+ const inputRef = React.createRef<HTMLInputElement>()
271
+
272
+ /** To add custom components to the Menu,
273
+ * you need to switch to a controlled menu
274
+ */
275
+ const [open, setOpen] = React.useState(false)
276
+ const handleKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
277
+ if (event.key === 'Enter') {
278
+ setName(event.currentTarget.value)
279
+ setOpen(false)
280
+ }
281
+ }
282
+
283
+ /** This requires inside knowledge. If you to do this with onBlur
284
+ * on the input, it doesn't work :(
285
+ */
286
+ const handleClickOutside = () => {
287
+ if (inputRef.current) setName(inputRef.current.value)
288
+ setOpen(false)
289
+ }
290
+
291
+ return (
292
+ <>
293
+ <h1>Memex Table Menu</h1>
294
+ <Box
295
+ sx={{
296
+ width: 200,
297
+ display: 'flex',
298
+ justifyContent: 'space-between',
299
+ p: 2,
300
+ border: '1px solid',
301
+ borderColor: 'border.default'
302
+ }}
303
+ >
304
+ <Text sx={{fontSize: 0, fontWeight: 'bold'}}>{name}</Text>
305
+ <ActionMenu open={open} onOpenChange={setOpen} overlayProps={{onClickOutside: handleClickOutside}}>
306
+ <ActionMenu.Button
307
+ aria-label="Open Estimate column options menu"
308
+ sx={{
309
+ p: 0,
310
+ display: 'flex',
311
+ alignItems: 'center',
312
+ justifyContent: 'center'
313
+ }}
314
+ >
315
+ <TriangleDownIcon />
316
+ </ActionMenu.Button>
317
+
318
+ <TextInput ref={inputRef} sx={{m: 2}} defaultValue={name} onKeyPress={handleKeyPress} />
319
+ <ActionMenu.Divider sx={{m: 0}} />
320
+
321
+ <ActionList>
322
+ <ActionList.Item>Sort ascending (123...)</ActionList.Item>
323
+ <ActionList.Item>Sort descending (123...)</ActionList.Item>
324
+ <ActionList.Divider />
325
+ <ActionList.Item>Filter by values</ActionList.Item>
326
+ <ActionList.Item>Group by values</ActionList.Item>
327
+ <ActionList.Divider />
328
+ <ActionList.Item disabled>Hide field</ActionList.Item>
329
+ <ActionList.Item variant="danger">Delete file</ActionList.Item>
330
+ </ActionList>
331
+ </ActionMenu>
332
+ </Box>
333
+ </>
334
+ )
335
+ }
336
+ MemexTableMenu.storyName = 'Memex Table Menu'
337
+
338
+ /* copied from github/memex */
339
+ const LayoutToggleItem = ({
340
+ selected,
341
+ children,
342
+ Icon,
343
+ ...props
344
+ }: {
345
+ selected: boolean
346
+ children: React.ReactNode
347
+ Icon: React.ComponentType<IconProps>
348
+ }) => {
349
+ return (
350
+ <FormGroup
351
+ sx={{
352
+ flex: 'auto',
353
+ borderRadius: 2,
354
+ border: '1px solid',
355
+ borderColor: selected ? 'accent.emphasis' : 'border.default',
356
+ textAlign: 'center',
357
+ cursor: 'pointer',
358
+ backgroundColor: selected ? 'accent.subtle' : '',
359
+ boxShadow: selected ? theme => `inset 0 0 0 1px ${theme.colors.accent.emphasis}` : '',
360
+ mb: 2,
361
+ mt: 1,
362
+ '&:hover': {
363
+ backgroundColor: !selected ? 'canvas.subtle' : ''
364
+ },
365
+ '&:first-of-type': {
366
+ borderTopRightRadius: '0px',
367
+ borderBottomRightRadius: '0px',
368
+ borderRight: selected ? undefined : '0'
369
+ },
370
+ '&:last-of-type': {
371
+ borderTopLeftRadius: '0px',
372
+ borderBottomLeftRadius: '0px',
373
+ borderLeft: selected ? undefined : '0'
374
+ }
375
+ }}
376
+ >
377
+ <FormGroup.Label
378
+ htmlFor="layout-selector"
379
+ sx={{fontWeight: 'normal', cursor: 'pointer', px: 3, py: 2, mb: 0}}
380
+ {...props}
381
+ >
382
+ <Box sx={{textAlign: 'center', flexDirection: 'column', m: 'auto', alignItems: 'center', display: 'flex'}}>
383
+ <Icon size="medium" />
384
+ <Text sx={{color: selected ? 'fg.default' : 'fg.muted', fontSize: 0}}>{children}</Text>
385
+ </Box>
386
+ </FormGroup.Label>
387
+ </FormGroup>
388
+ )
389
+ }
390
+
391
+ /* copied from github/memex */
392
+ const ViewChangeButtons = ({setOpen}: {setOpen: (open: boolean) => void}) => (
393
+ <Box sx={{display: 'flex'}}>
394
+ <ButtonInvisible
395
+ onClick={() => setOpen(false)}
396
+ sx={{
397
+ flex: 'auto',
398
+ minWidth: '50%',
399
+ borderRight: '1px solid',
400
+ borderColor: 'border.default',
401
+ borderRadius: 0,
402
+ mt: -2,
403
+ mb: -2,
404
+ py: 3,
405
+ '&:hover': {
406
+ bg: 'canvas.inset'
407
+ }
408
+ }}
409
+ >
410
+ Save changes
411
+ </ButtonInvisible>
412
+
413
+ <ButtonInvisible
414
+ onClick={() => setOpen(false)}
415
+ sx={{
416
+ flex: 'auto',
417
+ color: 'fg.muted',
418
+ borderRadius: 0,
419
+ mt: -2,
420
+ mb: -2,
421
+ py: 3,
422
+ fontWeight: 'normal',
423
+ '&:hover': {
424
+ bg: 'canvas.inset'
425
+ }
426
+ }}
427
+ >
428
+ Discard changes
429
+ </ButtonInvisible>
430
+ </Box>
431
+ )
432
+
433
+ export function MemexViewOptionsMenu(): JSX.Element {
434
+ const [open, setOpen] = React.useState(false)
435
+
436
+ return (
437
+ <>
438
+ <h1>Memex View Options Menu</h1>
439
+ <Box sx={{display: 'flex', alignItems: 'center'}}>
440
+ <Text sx={{fontSize: 1, mr: 3}}>
441
+ <StyledOcticon icon={ProjectIcon} sx={{mr: 2}} />
442
+ React
443
+ </Text>
444
+ <ActionMenu open={open} onOpenChange={setOpen} overlayProps={{width: 'medium'}}>
445
+ <ActionMenu.Button
446
+ aria-label="Open View options menu"
447
+ sx={{
448
+ p: 0,
449
+ width: 18,
450
+ height: 18,
451
+ display: 'flex',
452
+ alignItems: 'center',
453
+ justifyContent: 'center'
454
+ }}
455
+ >
456
+ <TriangleDownIcon />
457
+ </ActionMenu.Button>
458
+
459
+ <ActionList>
460
+ <ActionList.Group title="Layout">
461
+ <li style={{listStyle: 'none'}}>
462
+ <Box sx={{mx: 3, display: 'flex'}}>
463
+ <LayoutToggleItem selected Icon={TableIcon}>
464
+ Table
465
+ </LayoutToggleItem>
466
+ <LayoutToggleItem selected={false} Icon={ProjectIcon}>
467
+ Board
468
+ </LayoutToggleItem>
469
+ </Box>
470
+ </li>
471
+ </ActionList.Group>
472
+ <ActionList.Divider />
473
+
474
+ <ActionList.Group title="Configuration">
475
+ <ActionList.Item>
476
+ <ActionList.LeadingVisual>
477
+ <ListUnorderedIcon />
478
+ </ActionList.LeadingVisual>
479
+ Title, Assignees, Status, Labels, Repositories
480
+ </ActionList.Item>
481
+ <ActionList.Item>
482
+ <ActionList.LeadingVisual>
483
+ <ListUnorderedIcon />
484
+ </ActionList.LeadingVisual>
485
+ group: none
486
+ </ActionList.Item>
487
+ <ActionList.Item>
488
+ <ActionList.LeadingVisual>
489
+ <ArrowDownIcon />
490
+ </ActionList.LeadingVisual>
491
+ sort: manual
492
+ </ActionList.Item>
493
+ <ActionList.Item>
494
+ <ActionList.LeadingVisual>
495
+ <SearchIcon />
496
+ </ActionList.LeadingVisual>
497
+ Search or filter this view
498
+ </ActionList.Item>
499
+ </ActionList.Group>
500
+ <ActionList.Divider />
501
+ <ActionList.Item>
502
+ <ActionList.LeadingVisual>
503
+ <PencilIcon />
504
+ </ActionList.LeadingVisual>
505
+ Rename view
506
+ </ActionList.Item>
507
+ <ActionList.Item>
508
+ <ActionList.LeadingVisual>
509
+ <VersionsIcon />
510
+ </ActionList.LeadingVisual>
511
+ Save changes to new view
512
+ </ActionList.Item>
513
+ <ActionList.Item disabled>
514
+ <ActionList.LeadingVisual>
515
+ <TrashIcon />
516
+ </ActionList.LeadingVisual>
517
+ Delete view
518
+ </ActionList.Item>
519
+ <ActionList.Divider />
520
+
521
+ <li style={{listStyle: 'none'}}>
522
+ <ViewChangeButtons setOpen={setOpen} />
523
+ </li>
524
+ </ActionList>
525
+ </ActionMenu>
526
+ </Box>
527
+ </>
528
+ )
529
+ }
530
+ MemexViewOptionsMenu.storyName = 'Memex View Options Menu'
531
+
532
+ export function UnexpectedSelectionVariant(): JSX.Element {
533
+ return (
534
+ <>
535
+ <h1>Expect error if selectionVariant is passed</h1>
536
+
537
+ <ActionMenu>
538
+ <ActionMenu.Button>Menu</ActionMenu.Button>
539
+
540
+ <ActionList selectionVariant="multiple">
541
+ <ActionList.Item>Copy link</ActionList.Item>
542
+ <ActionList.Item>Quote reply</ActionList.Item>
543
+ <ActionList.Item>Edit comment</ActionList.Item>
544
+ <ActionList.Divider />
545
+ <ActionList.Item variant="danger">Delete file</ActionList.Item>
546
+ </ActionList>
547
+ </ActionMenu>
548
+ </>
549
+ )
550
+ }
551
+ UnexpectedSelectionVariant.storyName = 'Unexpected selectionVariant'