Skip to content

Commit 76bf60d

Browse files
authored
AnchoredOverlay: Add responsive variant prop (#5759)
Co-authored-by: siddharthkp <[email protected]>
1 parent e0c34d0 commit 76bf60d

File tree

17 files changed

+117
-3
lines changed

17 files changed

+117
-3
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@primer/react": minor
3+
---
4+
5+
AnchoredOverlay: Add prop to set responsive variant. Example: `variant: {regular: 'anchored', narrow: 'anchored'}`
Loading

e2e/components/SelectPanel.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,24 @@ test.describe('SelectPanel', () => {
108108
`SelectPanel-Default-forced-colors-dark-modern-action-list--true.png`,
109109
)
110110
})
111+
112+
test(`Default @vrt responsive width .modern-action-list--true`, async ({page}) => {
113+
await visit(page, {
114+
id: 'components-selectpanel--default',
115+
globals: {featureFlags: {primer_react_select_panel_with_modern_action_list: true}},
116+
})
117+
118+
await page.setViewportSize({width: 767, height: 767})
119+
120+
// Open select panel
121+
const isPanelOpen = await page.isVisible('[role="listbox"]')
122+
if (!isPanelOpen) {
123+
await page.keyboard.press('Tab')
124+
await page.keyboard.press('Enter')
125+
}
126+
127+
expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(
128+
`SelectPanel-Default-responsive-width-light-modern-action-list--true.png`,
129+
)
130+
})
111131
})

packages/react/src/AnchoredOverlay/AnchoredOverlay.docs.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,20 @@
147147
"required": false,
148148
"description": "",
149149
"defaultValue": ""
150-
}, {
150+
},
151+
{
151152
"name": "pinPosition",
152153
"type": "boolean",
153154
"required": false,
154155
"description": "If true, the overlay will attempt to prevent position shifting when sitting at the top of the anchor.",
155156
"defaultValue": "false"
157+
},
158+
{
159+
"name": "variant",
160+
"type": "{ regular?: 'anchored', narrow?: 'anchored' | 'fullscreen' }",
161+
"required": false,
162+
"description": "Optional prop to set variant for narrow screen sizes",
163+
"defaultValue": "{ regular: 'anchored', narrow: 'anchored' }"
156164
}
157165
]
158166
}

packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {useFocusZone} from '../hooks/useFocusZone'
88
import {useAnchoredPosition, useProvidedRefOrCreate, useRenderForcingRef} from '../hooks'
99
import {useId} from '../hooks/useId'
1010
import type {PositionSettings} from '@primer/behaviors'
11+
import {useResponsiveValue, type ResponsiveValue} from '../hooks/useResponsiveValue'
1112

1213
interface AnchoredOverlayPropsWithAnchor {
1314
/**
@@ -93,6 +94,10 @@ interface AnchoredOverlayBaseProps extends Pick<OverlayProps, 'height' | 'width'
9394
* If true, the overlay will attempt to prevent position shifting when sitting at the top of the anchor.
9495
*/
9596
pinPosition?: boolean
97+
/**
98+
* Optional prop to set variant for narrow screen sizes
99+
*/
100+
variant?: ResponsiveValue<'anchored', 'anchored' | 'fullscreen'>
96101
}
97102

98103
export type AnchoredOverlayProps = AnchoredOverlayBaseProps &
@@ -122,6 +127,7 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
122127
anchorOffset,
123128
className,
124129
pinPosition,
130+
variant = {regular: 'anchored', narrow: 'anchored'},
125131
preventOverflow = true,
126132
}) => {
127133
const anchorRef = useProvidedRefOrCreate(externalAnchorRef)
@@ -183,6 +189,8 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
183189
})
184190
useFocusTrap({containerRef: overlayRef, disabled: !open || !position, ...focusTrapSettings})
185191

192+
const currentResponsiveVariant = useResponsiveValue(variant, 'anchored')
193+
186194
return (
187195
<>
188196
{renderAnchor &&
@@ -206,8 +214,9 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
206214
visibility={position ? 'visible' : 'hidden'}
207215
height={height}
208216
width={width}
209-
top={position?.top || 0}
210-
left={position?.left || 0}
217+
top={currentResponsiveVariant === 'anchored' ? position?.top || 0 : undefined}
218+
left={currentResponsiveVariant === 'anchored' ? position?.left || 0 : undefined}
219+
data-variant={currentResponsiveVariant}
211220
anchorSide={position?.anchorSide}
212221
className={className}
213222
preventOverflow={preventOverflow}

packages/react/src/ConfirmationDialog/ConfirmationDialog.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {ConfirmationDialog, useConfirm} from './ConfirmationDialog'
1010
import theme from '../theme'
1111
import {ThemeProvider} from '../ThemeProvider'
1212
import {behavesAsComponent, checkExports} from '../utils/testing'
13+
import {setupMatchMedia} from '../utils/test-helpers'
14+
15+
setupMatchMedia() // need to mock media for deprecated/ActionMenu
1316

1417
const Basic = ({confirmButtonType}: Pick<React.ComponentProps<typeof ConfirmationDialog>, 'confirmButtonType'>) => {
1518
const [isOpen, setIsOpen] = useState(false)

packages/react/src/Overlay/Overlay.module.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,13 @@
156156
&:where([data-visibility-hidden]) {
157157
visibility: hidden;
158158
}
159+
160+
&:where([data-variant='fullscreen']) {
161+
top: 0;
162+
left: 0;
163+
width: 100vw;
164+
height: 100vh;
165+
margin: 0;
166+
border-radius: unset;
167+
}
159168
}

packages/react/src/Overlay/Overlay.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import BaseStyles from '../BaseStyles'
88
import {ThemeProvider} from '../ThemeProvider'
99
import {NestedOverlays, MemexNestedOverlays, MemexIssueOverlay, PositionedOverlays} from './Overlay.features.stories'
1010
import {FeatureFlags} from '../FeatureFlags'
11+
import {setupMatchMedia} from '../utils/test-helpers'
12+
13+
setupMatchMedia()
1114

1215
type TestComponentSettings = {
1316
initialFocus?: 'button'

packages/react/src/Overlay/Overlay.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ const StyledOverlay = toggleStyledComponent(
103103
max-width: calc(100vw - 2rem);
104104
}
105105
106+
&:where([data-variant='fullscreen']) {
107+
top: 0;
108+
left: 0;
109+
width: 100vw;
110+
height: 100vh;
111+
margin: 0;
112+
border-radius: unset;
113+
}
114+
106115
${sx};
107116
`,
108117
)

packages/react/src/SelectPanel/SelectPanel.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {getLiveRegion} from '../utils/testing'
1010
import {IconButton} from '../Button'
1111
import {ArrowLeftIcon} from '@primer/octicons-react'
1212
import Box from '../Box'
13+
import {setupMatchMedia} from '../utils/test-helpers'
14+
15+
setupMatchMedia()
1316

1417
const renderWithFlag = (children: React.ReactNode, flag: boolean) => {
1518
return render(

0 commit comments

Comments
 (0)