diff --git a/.changeset/thick-pugs-hammer.md b/.changeset/thick-pugs-hammer.md new file mode 100644 index 00000000000..d6872b6f4ff --- /dev/null +++ b/.changeset/thick-pugs-hammer.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +feat(AnchoredOverlay): allow overlay to reflow diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.docs.json b/packages/react/src/AnchoredOverlay/AnchoredOverlay.docs.json index d8683ed5dc1..1cb80dfa148 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.docs.json +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.docs.json @@ -89,6 +89,12 @@ "type": "string", "defaultValue": "", "description": "Class name for custom styling." + }, + { + "name": "preventOverflow", + "type": "boolean", + "defaultValue": "true", + "description": "Determines if the Overlay width should be adjusted responsively if there is not enough space to display the Overlay. If `preventOverflow` is set to `false`, the Overlay will be displayed at the maximum width that fits within the viewport." } ] } diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx index 3f914def820..bddbdace866 100644 --- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx +++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.features.stories.tsx @@ -18,7 +18,7 @@ export default { } as Meta const hoverCard = ( - + @@ -103,8 +103,9 @@ export const CustomAnchorId = () => { onClose={() => setOpen(false)} renderAnchor={props => } anchorId="my-custom-anchor-id" - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -121,8 +122,9 @@ export const Height = () => { onClose={() => setOpen(false)} renderAnchor={props => } height="large" - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -139,8 +141,9 @@ export const Width = () => { onClose={() => setOpen(false)} renderAnchor={props => } width="large" - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > { )} align="center" - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -188,8 +192,9 @@ export const AnchorSide = () => { onClose={() => setOpen(false)} renderAnchor={props => } side="outside-right" - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -206,8 +211,9 @@ export const OffsetPositionFromAnchor = () => { onClose={() => setOpen(false)} renderAnchor={props => } anchorOffset={100} - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -224,8 +230,9 @@ export const OffsetAlignmentFromAnchor = () => { onClose={() => setOpen(false)} renderAnchor={props => } alignmentOffset={100} - overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}} + overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > {hoverCard} @@ -245,6 +252,7 @@ export const FocusTrapOverrides = () => { focusTrapSettings={{initialFocusRef}} overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'Focus Trap Demo Overlay'}} focusZoneSettings={{disabled: true}} + preventOverflow={false} > @@ -263,6 +271,7 @@ export const FocusZoneOverrides = () => { renderAnchor={props => } focusZoneSettings={{bindKeys: FocusKeys.JK}} overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'Focus Zone Demo Overlay'}} + preventOverflow={false} >

Use J and K keys to move focus. @@ -289,8 +298,10 @@ export const OverlayPropsOverrides = () => { role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', + sx: {minWidth: '320px'}, }} focusZoneSettings={{disabled: true}} + preventOverflow={false} >

Overlay props have been overridden to set:
diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.stories.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.stories.tsx
index 84ec0727c24..54945b9464d 100644
--- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.stories.tsx
+++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.stories.tsx
@@ -15,7 +15,7 @@ export default {
 } as Meta
 
 const hoverCard = (
-  
+  
     
       
       
@@ -53,8 +53,9 @@ export const Default = () => {
       onOpen={() => setOpen(true)}
       onClose={() => setOpen(false)}
       renderAnchor={props => }
-      overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay'}}
+      overlayProps={{role: 'dialog', 'aria-modal': true, 'aria-label': 'User Card Overlay', sx: {minWidth: '320px'}}}
       focusZoneSettings={{disabled: true}}
+      preventOverflow={false}
     >
       {hoverCard}
     
@@ -83,9 +84,11 @@ export const Playground = (args: Args) => {
         role: 'dialog',
         'aria-modal': true,
         'aria-label': 'User Card Overlay',
+        sx: {minWidth: '320px'},
       }}
       side={args.side}
       focusZoneSettings={{disabled: true}}
+      preventOverflow={false}
     >
       {hoverCard}
     
diff --git a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
index bfc08cf041a..e046e301938 100644
--- a/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
+++ b/packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
@@ -84,6 +84,11 @@ interface AnchoredOverlayBaseProps extends Pick {
   const anchorRef = useProvidedRefOrCreate(externalAnchorRef)
   const [overlayRef, updateOverlayRef] = useRenderForcingRef()
@@ -198,7 +204,7 @@ export const AnchoredOverlay: React.FC
           {children}
diff --git a/packages/react/src/Overlay/Overlay.test.tsx b/packages/react/src/Overlay/Overlay.test.tsx
index 7c8c90b953a..61b6fbe6073 100644
--- a/packages/react/src/Overlay/Overlay.test.tsx
+++ b/packages/react/src/Overlay/Overlay.test.tsx
@@ -313,18 +313,4 @@ describe('Overlay', () => {
     const container = getByRole('none')
     expect(container).toHaveAttribute('data-reflow-container')
   })
-
-  it('should not have `data-reflow-container` if FF is enabled but the overlay is above `medium`', async () => {
-    const user = userEvent.setup()
-    const {getByRole} = render(
-      
-        
-      ,
-    )
-
-    await user.click(getByRole('button', {name: 'open overlay'}))
-
-    const container = getByRole('none')
-    expect(container).not.toHaveAttribute('data-reflow-container')
-  })
 })
diff --git a/packages/react/src/Overlay/Overlay.tsx b/packages/react/src/Overlay/Overlay.tsx
index 8b9579d99eb..ce69ef27f5c 100644
--- a/packages/react/src/Overlay/Overlay.tsx
+++ b/packages/react/src/Overlay/Overlay.tsx
@@ -139,7 +139,7 @@ type OwnOverlayProps = Merge
  * @param bottom Optional. Vertical bottom position of the overlay, relative to its closest positioned ancestor (often its `Portal`).
  * @param position Optional. Sets how an element is positioned in a document. Defaults to `absolute` positioning.
  * @param portalContainerName Optional. The name of the portal container to render the Overlay into.
- * @param preventOverflow Optional. The Overlay width will be adjusted responsively if width is `auto`, `medium` or lower and there is not enough space to display the Overlay. If `preventOverflow` is `true`, the width of the `Overlay` will not be adjusted.
+ * @param preventOverflow Optional. The Overlay width will be adjusted responsively if there is not enough space to display the Overlay. If `preventOverflow` is `true`, the width of the `Overlay` will not be adjusted.
  */
 const Overlay = React.forwardRef(
   (
@@ -207,10 +207,8 @@ const Overlay = React.forwardRef(
 
     // To be backwards compatible with the old Overlay, we need to set the left prop if x-position is not specified
     const leftPosition: React.CSSProperties = left === undefined && right === undefined ? {left: 0} : {left}
-    const reflowSize = ['xsmall', 'small', 'medium', 'auto'].includes(width)
 
     const enabled = useFeatureFlag('primer_react_overlay_overflow')
-    const overflow = enabled && reflowSize ? true : undefined
 
     return (
       
@@ -231,7 +229,7 @@ const Overlay = React.forwardRef(
               ...styleFromProps,
             } as React.CSSProperties
           }
-          data-reflow-container={overflow || (reflowSize && !preventOverflow) ? true : undefined}
+          data-reflow-container={enabled || !preventOverflow ? true : undefined}
         />
       
     )