diff --git a/.changeset/fair-sloths-kick.md b/.changeset/fair-sloths-kick.md new file mode 100644 index 00000000000..d2ba47a2483 --- /dev/null +++ b/.changeset/fair-sloths-kick.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +experimental/SelectPanel: Add back button diff --git a/packages/react/src/drafts/SelectPanel2/SelectPanel.examples.stories.tsx b/packages/react/src/drafts/SelectPanel2/SelectPanel.examples.stories.tsx index a4057183ced..a10d42a94b0 100644 --- a/packages/react/src/drafts/SelectPanel2/SelectPanel.examples.stories.tsx +++ b/packages/react/src/drafts/SelectPanel2/SelectPanel.examples.stories.tsx @@ -1,7 +1,16 @@ import React from 'react' import {SelectPanel} from './SelectPanel' -import {ActionList, ActionMenu, Avatar, Box, Button, Text} from '../../index' -import {ArrowRightIcon, EyeIcon, GitBranchIcon, TriangleDownIcon, GearIcon} from '@primer/octicons-react' +import {ActionList, ActionMenu, Avatar, Box, Button, Octicon, Text} from '../../index' +import { + ArrowRightIcon, + EyeIcon, + GitBranchIcon, + TriangleDownIcon, + GearIcon, + GitPullRequestIcon, + GitMergeIcon, + GitPullRequestDraftIcon, +} from '@primer/octicons-react' import data from './mock-story-data' export default { @@ -435,8 +444,8 @@ export const OpenFromMenu = () => { + { @@ -450,6 +459,13 @@ export const OpenFromMenu = () => { setMenuOpen(true) }} > + { + setSelectedCustomEvents(initialCustomEvents) + setSelectPanelOpen(false) + setMenuOpen(true) + }} + /> {itemsToShow.map(item => ( { ) } +export const NestedSelection = () => { + const [panelToShow, setPanelToShow] = React.useState(null) + + const anchorRef = React.useRef(null) + + /* First level: Repo selection */ + const [selectedRepo, setSelectedRepo] = React.useState('') + + const reposToShow = data.repos + + /* Second level: Pull request selection */ + const iconMap = { + open: , + merged: , + draft: , + } + + const initialSelectedPullRequestIds = ['4278'] + const [selectedPullRequestIds, setSelectedPullRequestIds] = React.useState(initialSelectedPullRequestIds) + /* Selection */ + const onPullRequestSelect = (pullId: string) => { + if (!selectedPullRequestIds.includes(pullId)) setSelectedPullRequestIds([...selectedPullRequestIds, pullId]) + else setSelectedPullRequestIds(selectedPullRequestIds.filter(id => id !== pullId)) + } + + return ( + <> +

Nested selection

+ + + + + {data.pulls + .filter(pull => selectedPullRequestIds.includes(pull.id)) + .map(pull => ( + + {iconMap[pull.status as keyof typeof iconMap]} + {pull.name} + #{pull.id} + {pull.description} + + ))} + + + setPanelToShow('pull_requests')} + onCancel={() => setPanelToShow(null)} + > + + + + + + {reposToShow.map(repo => ( + setSelectedRepo(`${repo.org}/${repo.name}`)} + > + + + + {repo.org}/{repo.name} + {repo.description} + + + + + ))} + + + + + + setPanelToShow(null)} + onCancel={() => { + setSelectedPullRequestIds(initialSelectedPullRequestIds) + setPanelToShow('repos') + }} + > + setPanelToShow('repos')}> + + + + + {data.pulls.map(pull => ( + onPullRequestSelect(pull.id)} + > + {iconMap[pull.status as keyof typeof iconMap]} + {pull.name} + #{pull.id} + {pull.description} + + ))} + + + + + + ) +} + // ----- Suspense implementation details ---- const cache = new Map() diff --git a/packages/react/src/drafts/SelectPanel2/SelectPanel.tsx b/packages/react/src/drafts/SelectPanel2/SelectPanel.tsx index 04669a33f13..1461550bc35 100644 --- a/packages/react/src/drafts/SelectPanel2/SelectPanel.tsx +++ b/packages/react/src/drafts/SelectPanel2/SelectPanel.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {SearchIcon, XCircleFillIcon, XIcon, FilterRemoveIcon, AlertIcon} from '@primer/octicons-react' +import {SearchIcon, XCircleFillIcon, XIcon, FilterRemoveIcon, AlertIcon, ArrowLeftIcon} from '@primer/octicons-react' import {FocusKeys} from '@primer/behaviors' import type {ButtonProps, TextInputProps, ActionListProps, LinkProps, CheckboxProps} from '../../index' @@ -192,7 +192,10 @@ const Panel: React.FC = ({ // tl;dr: react takes over autofocus instead of letting the browser handle it, // but not for dialogs, so we have to do it React.useEffect(() => { - if (internalOpen) document.querySelector('input')?.focus() + if (internalOpen) { + const searchInput = document.querySelector('dialog[open] input') as HTMLInputElement | undefined + searchInput?.focus() + } }, [internalOpen]) /* Anchored */ @@ -316,7 +319,7 @@ const SelectPanelButton = React.forwardRef((prop return