diff --git a/.changeset/sharp-seahorses-guess.md b/.changeset/sharp-seahorses-guess.md new file mode 100644 index 00000000000..e3ddc8a1c8d --- /dev/null +++ b/.changeset/sharp-seahorses-guess.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +experimental/SelectPanel: Add SelectPanel.SecondaryAction diff --git a/src/drafts/SelectPanel2/SelectPanel.tsx b/src/drafts/SelectPanel2/SelectPanel.tsx index b77c866e8bd..ffbc5d1dbce 100644 --- a/src/drafts/SelectPanel2/SelectPanel.tsx +++ b/src/drafts/SelectPanel2/SelectPanel.tsx @@ -15,12 +15,18 @@ import { Text, ActionListProps, Octicon, + Link, + LinkProps, + Checkbox, + CheckboxProps, } from '../../index' import {ActionListContainerContext} from '../../ActionList/ActionListContainerContext' import {useSlots} from '../../hooks/useSlots' import {useProvidedRefOrCreate, useId, useAnchoredPosition} from '../../hooks' import {useFocusZone} from '../../hooks/useFocusZone' import {StyledOverlay, OverlayProps} from '../../Overlay/Overlay' +import InputLabel from '../../internal/components/InputLabel' +import {invariant} from '../../utils/invariant' const SelectPanelContext = React.createContext<{ title: string @@ -416,6 +422,7 @@ const SelectPanelSearchInput: React.FC = ({onChange: propsOnChan ) } +const FooterContext = React.createContext(false) const SelectPanelFooter = ({...props}) => { const {onCancel, selectionVariant} = React.useContext(SelectPanelContext) @@ -428,38 +435,86 @@ const SelectPanelFooter = ({...props}) => { } return ( - - {props.children} - - {hidePrimaryActions ? null : ( - - - - - )} - + + + {props.children} + + {hidePrimaryActions ? null : ( + + + + + )} + + ) } -// TODO: is this the right way to add button props? -const SelectPanelSecondaryButton: React.FC = props => { +const SecondaryButton: React.FC = props => { return + ) +} + +const SecondaryCheckbox: React.FC = ({id, children, ...props}) => { + const checkboxId = useId(id) + const {selectionVariant} = React.useContext(SelectPanelContext) + + // Checkbox should not be used with instant selection + invariant( + selectionVariant !== 'instant', + 'Sorry! SelectPanel.SecondaryAction with variant="checkbox" is not allowed inside selectionVariant="instant"', + ) + + return ( + + + + {children} + + + ) +} + +type SelectPanelSecondaryActionProps = {children: React.ReactNode} & ( + | ({variant: 'button'} & Partial>) + | ({variant: 'link'} & Partial) + | ({variant: 'checkbox'; id?: string} & CheckboxProps) +) + +const SelectPanelSecondaryAction: React.FC = ({variant, ...props}) => { + const insideFooter = React.useContext(FooterContext) + invariant(insideFooter, 'SelectPanel.SecondaryAction is only allowed inside SelectPanel.Footer') + + // @ts-ignore TODO + if (variant === 'button') return + // @ts-ignore TODO + else if (variant === 'link') return + // @ts-ignore TODO + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + else if (variant === 'checkbox') return +} const SelectPanelLoading: React.FC<{children: string}> = ({children = 'Fetching items...'}) => { return ( @@ -563,7 +618,7 @@ export const SelectPanel = Object.assign(Panel, { Header: SelectPanelHeader, SearchInput: SelectPanelSearchInput, Footer: SelectPanelFooter, - SecondaryButton: SelectPanelSecondaryButton, Loading: SelectPanelLoading, Message: SelectPanelMessage, + SecondaryAction: SelectPanelSecondaryAction, }) diff --git a/src/drafts/SelectPanel2/stories/SelectPanel.default.stories.tsx b/src/drafts/SelectPanel2/stories/SelectPanel.default.stories.tsx index 923ffb5ad53..b5faea6f4e2 100644 --- a/src/drafts/SelectPanel2/stories/SelectPanel.default.stories.tsx +++ b/src/drafts/SelectPanel2/stories/SelectPanel.default.stories.tsx @@ -103,7 +103,7 @@ export const Default = () => { )} - Edit labels + Edit labels diff --git a/src/drafts/SelectPanel2/stories/SelectPanel.examples.stories.tsx b/src/drafts/SelectPanel2/stories/SelectPanel.examples.stories.tsx index 61265d67c53..3d3322d3372 100644 --- a/src/drafts/SelectPanel2/stories/SelectPanel.examples.stories.tsx +++ b/src/drafts/SelectPanel2/stories/SelectPanel.examples.stories.tsx @@ -205,7 +205,9 @@ export const AsyncWithSuspendedList = () => { Fetching labels...}> - Edit labels + + Edit labels + @@ -556,7 +558,7 @@ export const WithFilterButtons = () => { Try a different search term ) : ( - + {itemsToShow.map(item => ( { )} - {/* @ts-ignore TODO as prop is not identified by button? */} - + View all {selectedFilter} - + diff --git a/src/drafts/SelectPanel2/stories/SelectPanel.features.stories.tsx b/src/drafts/SelectPanel2/stories/SelectPanel.features.stories.tsx index 6ef7d694527..1ef2d78b9b1 100644 --- a/src/drafts/SelectPanel2/stories/SelectPanel.features.stories.tsx +++ b/src/drafts/SelectPanel2/stories/SelectPanel.features.stories.tsx @@ -38,7 +38,7 @@ export const InstantSelectionVariant = () => { ))} - Edit tags + Edit tags diff --git a/src/drafts/SelectPanel2/stories/SelectPanel.playground.stories.tsx b/src/drafts/SelectPanel2/stories/SelectPanel.playground.stories.tsx index a9d318eccc7..dd3b0216ce0 100644 --- a/src/drafts/SelectPanel2/stories/SelectPanel.playground.stories.tsx +++ b/src/drafts/SelectPanel2/stories/SelectPanel.playground.stories.tsx @@ -11,10 +11,16 @@ export default { args: { title: 'Select labels', selectionVariant: 'multiple', + secondaryActionVariant: 'button', }, argTypes: { - secondaryButtonText: { - name: 'Secondary button text', + secondaryActionVariant: { + name: 'Secondary action variant', + type: 'enum', + options: ['button', 'link', 'checkbox'], + }, + secondaryActionText: { + name: 'Secondary action text', type: 'string', }, }, @@ -125,8 +131,10 @@ export const Playground: StoryFn = args => { )} - {args.secondaryButtonText ? ( - {args.secondaryButtonText} + {args.secondaryActionText ? ( + + {args.secondaryActionText} + ) : null}