Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/good-ligers-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/react": minor
---

Add disableFullscreenOnNarrow prop to SelectPanel for opt-out of fullscreen behavior
6 changes: 6 additions & 0 deletions packages/react/src/SelectPanel/SelectPanel.docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@
"type": "boolean",
"description": "Whether to display the selected items at the top of the list",
"default": "true"
},
{
"name": "disableFullscreenOnNarrow",
"type": "boolean",
"description": "Whether to disable fullscreen behavior on narrow viewports. When `true`, the panel will maintain its anchored position regardless of viewport size. When `false`, the panel will go fullscreen on narrow viewports (if feature flag is enabled).",
"defaultValue": "undefined (uses feature flag default)"
}
],
"subcomponents": []
Expand Down
94 changes: 94 additions & 0 deletions packages/react/src/SelectPanel/SelectPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,100 @@ for (const useModernActionList of [false, true]) {
expect(options[2]).toHaveTextContent('item three')
})
})

describe('disableFullscreenOnNarrow prop', () => {
const renderSelectPanelWithFlags = (flags: Record<string, boolean>, props: Record<string, unknown> = {}) => {
return render(
<FeatureFlags flags={flags}>
<ThemeProvider>
<SingleSelectPanel {...props} />
</ThemeProvider>
</FeatureFlags>,
)
}

// Create a single-select version to test ResponsiveCloseButton behavior
function SingleSelectPanel(passthroughProps: Record<string, unknown>) {
const [filter, setFilter] = React.useState('')
const [open, setOpen] = React.useState(false)

return (
<ThemeProvider>
<SelectPanel
title="test title"
subtitle="test subtitle"
items={items}
placeholder="Select an item"
placeholderText="Filter items"
selected={undefined}
onSelectedChange={() => {}}
filterValue={filter}
onFilterChange={value => {
setFilter(value)
}}
open={open}
onOpenChange={open => setOpen(open)}
{...passthroughProps}
/>
</ThemeProvider>
)
}

it('should opt out of fullscreen when disableFullscreenOnNarrow=true even when feature flag is enabled', async () => {
const user = userEvent.setup()

renderSelectPanelWithFlags(
{
primer_react_select_panel_with_modern_action_list: useModernActionList,
primer_react_select_panel_fullscreen_on_narrow: true,
},
{disableFullscreenOnNarrow: true},
)

await user.click(screen.getByText('Select an item'))

// When disableFullscreenOnNarrow=true, the ResponsiveCloseButton should not be present
// even when the feature flag is enabled, indicating no fullscreen behavior
const responsiveCloseButton = screen.queryByRole('button', {name: 'Cancel and close'})
expect(responsiveCloseButton).not.toBeInTheDocument()
})

it('should use fullscreen behavior when disableFullscreenOnNarrow=false and feature flag is enabled', async () => {
const user = userEvent.setup()

renderSelectPanelWithFlags(
{
primer_react_select_panel_with_modern_action_list: useModernActionList,
primer_react_select_panel_fullscreen_on_narrow: true,
},
{disableFullscreenOnNarrow: false},
)

await user.click(screen.getByText('Select an item'))

// When feature flag is true and disableFullscreenOnNarrow is false, the ResponsiveCloseButton should be present
// indicating fullscreen behavior is active
const responsiveCloseButton = screen.getByRole('button', {name: 'Cancel and close'})
expect(responsiveCloseButton).toBeInTheDocument()
})

it('should default to feature flag value when disableFullscreenOnNarrow is undefined', async () => {
const user = userEvent.setup()

// Test with feature flag disabled
renderSelectPanelWithFlags({
primer_react_select_panel_with_modern_action_list: useModernActionList,
primer_react_select_panel_fullscreen_on_narrow: false,
})

await user.click(screen.getByText('Select an item'))

// When feature flag is false and disableFullscreenOnNarrow is undefined,
// the ResponsiveCloseButton should not be present
const responsiveCloseButton = screen.queryByRole('button', {name: 'Cancel and close'})
expect(responsiveCloseButton).not.toBeInTheDocument()
})
})
})
})
}
11 changes: 10 additions & 1 deletion packages/react/src/SelectPanel/SelectPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ interface SelectPanelBaseProps {
*/
footer?: string | React.ReactElement
showSelectedOptionsFirst?: boolean
/**
* Whether to disable fullscreen behavior on narrow viewports.
* When `true`, the panel will maintain its anchored position regardless of viewport size.
* When `false`, the panel will go fullscreen on narrow viewports (if feature flag is enabled).
* @default undefined (uses feature flag default)
*/
disableFullscreenOnNarrow?: boolean
}

// onCancel is optional with variant=anchored, but required with variant=modal
Expand Down Expand Up @@ -172,6 +179,7 @@ function Panel({
variant = 'anchored',
secondaryAction,
showSelectedOptionsFirst = true,
disableFullscreenOnNarrow,
...listProps
}: SelectPanelProps): JSX.Element {
const titleId = useId()
Expand All @@ -192,7 +200,8 @@ function Panel({
const [prevOpen, setPrevOpen] = useState(open)

const usingModernActionList = useFeatureFlag('primer_react_select_panel_with_modern_action_list')
const usingFullScreenOnNarrow = useFeatureFlag('primer_react_select_panel_fullscreen_on_narrow')
const featureFlagFullScreenOnNarrow = useFeatureFlag('primer_react_select_panel_fullscreen_on_narrow')
const usingFullScreenOnNarrow = disableFullscreenOnNarrow ? false : featureFlagFullScreenOnNarrow
const shouldOrderSelectedFirst =
useFeatureFlag('primer_react_select_panel_order_selected_at_top') && showSelectedOptionsFirst

Expand Down
Loading