diff --git a/packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx b/packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx index d55efb4b151..64a5c8f93d1 100644 --- a/packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx +++ b/packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx @@ -673,90 +673,87 @@ export const InsideDialog = () => { )) return ( - -
- {/* Main scrollable content */} -
- - Main Page Content - +
+ {/* Main scrollable content */} +
+ + Main Page Content + + + - - - {/* Show more content after the button to make it scrollable */} - {scrollableContent} -
- - {/* Dialog containing ActionMenu */} - {isDialogOpen && ( - - - This dialog contains an ActionMenu. The main page content behind is long enough to be scrollable. - - - - Document Settings - - - - Configure the document properties and sharing settings. These options allow you to control how the - document is displayed and who has access to it. - - - - Actions - - - alert('Save clicked')}> - Save - ⌘S - - alert('Save as clicked')}> - Save as... - ⌘⇧S - - alert('Export clicked')}> - Export - ⌘E - - alert('Print clicked')}> - Print - ⌘P - - - alert('Copy clicked')}> - Copy - ⌘C - - alert('Paste clicked')}> - Paste - ⌘V - - alert('Duplicate clicked')}> - Duplicate - ⌘D - - - alert('Share clicked')}> - Share - ⌘⇧U - - alert('Share via email clicked')}>Share via email - alert('Share via link clicked')}>Share via link - - - - - - You can interact with the ActionMenu above while the main page content remains scrollable in the - background. - - - )} + {/* Show more content after the button to make it scrollable */} + {scrollableContent}
- + + {/* Dialog containing ActionMenu */} + {isDialogOpen && ( + + + This dialog contains an ActionMenu. The main page content behind is long enough to be scrollable. + + + + Document Settings + + + + Configure the document properties and sharing settings. These options allow you to control how the document + is displayed and who has access to it. + + + + Actions + + + alert('Save clicked')}> + Save + ⌘S + + alert('Save as clicked')}> + Save as... + ⌘⇧S + + alert('Export clicked')}> + Export + ⌘E + + alert('Print clicked')}> + Print + ⌘P + + + alert('Copy clicked')}> + Copy + ⌘C + + alert('Paste clicked')}> + Paste + ⌘V + + alert('Duplicate clicked')}> + Duplicate + ⌘D + + + alert('Share clicked')}> + Share + ⌘⇧U + + alert('Share via email clicked')}>Share via email + alert('Share via link clicked')}>Share via link + + + + + + You can interact with the ActionMenu above while the main page content remains scrollable in the background. + + + )} +
) } diff --git a/packages/react/src/ActionMenu/ActionMenu.test.tsx b/packages/react/src/ActionMenu/ActionMenu.test.tsx index ffdec1402a6..d86b59cf68a 100644 --- a/packages/react/src/ActionMenu/ActionMenu.test.tsx +++ b/packages/react/src/ActionMenu/ActionMenu.test.tsx @@ -904,7 +904,7 @@ describe('ActionMenu', () => { }) }) - describe('feature flag: primer_react_action_menu_display_in_viewport_inside_dialog', () => { + describe('displayInViewport behavior', () => { const mockGetAnchoredPosition = vi.mocked(getAnchoredPosition) beforeEach(() => { @@ -912,47 +912,11 @@ describe('ActionMenu', () => { mockGetAnchoredPosition.mockClear() }) - it('should enable displayInViewport when flag is enabled and ActionMenu is inside a dialog', async () => { + it('should enable displayInViewport when ActionMenu is inside a dialog', async () => { // When the ActionMenu is wrapped in a Dialog, it's inside a dialog context. - // With the flag enabled, displayInViewport should be automatically enabled. + // displayInViewport should be automatically enabled. const component = HTMLRender( - - {}}> - - Toggle Menu - - - New file - - - - - , - ) - - const user = userEvent.setup() - const button = component.getByRole('button', {name: 'Toggle Menu'}) - await user.click(button) - - await waitFor(() => { - expect(component.queryByRole('menu')).toBeInTheDocument() - }) - - // Verify getAnchoredPosition was called with displayInViewport: true - await waitFor(() => { - expect(mockGetAnchoredPosition).toHaveBeenCalled() - }) - - const calls = mockGetAnchoredPosition.mock.calls - const lastCall = calls[calls.length - 1] - expect(lastCall[2]?.displayInViewport).toBe(true) - }) - - it('should not enable displayInViewport when flag is enabled but ActionMenu is NOT inside a dialog', async () => { - // Without being wrapped in a Dialog, the ActionMenu is not in a dialog context. - // Even with the flag enabled, displayInViewport should remain at its default (false/undefined). - const component = HTMLRender( - + {}}> Toggle Menu @@ -961,47 +925,43 @@ describe('ActionMenu', () => { - , + , ) const user = userEvent.setup() - const button = component.getByRole('button') + const button = component.getByRole('button', {name: 'Toggle Menu'}) await user.click(button) await waitFor(() => { expect(component.queryByRole('menu')).toBeInTheDocument() }) - // Verify getAnchoredPosition was called without displayInViewport enabled + // Verify getAnchoredPosition was called with displayInViewport: true await waitFor(() => { expect(mockGetAnchoredPosition).toHaveBeenCalled() }) const calls = mockGetAnchoredPosition.mock.calls const lastCall = calls[calls.length - 1] - expect(lastCall[2]?.displayInViewport).not.toBe(true) + expect(lastCall[2]?.displayInViewport).toBe(true) }) - it('should not enable displayInViewport when flag is disabled, even inside a dialog', async () => { - // Even when inside a Dialog, with the flag disabled, displayInViewport - // should remain at its default (false/undefined). + it('should not enable displayInViewport when ActionMenu is NOT inside a dialog', async () => { + // Without being wrapped in a Dialog, the ActionMenu is not in a dialog context. + // displayInViewport should remain at its default (false/undefined). const component = HTMLRender( - - {}}> - - Toggle Menu - - - New file - - - - - , + + Toggle Menu + + + New file + + + , ) const user = userEvent.setup() - const button = component.getByRole('button', {name: 'Toggle Menu'}) + const button = component.getByRole('button') await user.click(button) await waitFor(() => { @@ -1018,56 +978,20 @@ describe('ActionMenu', () => { expect(lastCall[2]?.displayInViewport).not.toBe(true) }) - it('should not enable displayInViewport when flag is disabled and outside dialog', async () => { - // Default scenario: flag disabled and not in a dialog context. - // displayInViewport should remain at its default (false/undefined). + it('should respect explicit displayInViewport prop over default logic', async () => { + // Test that an explicit displayInViewport=false prop overrides the automatic + // detection, even when the ActionMenu is inside a dialog. const component = HTMLRender( - + {}}> Toggle Menu - + New file - , - ) - - const user = userEvent.setup() - const button = component.getByRole('button') - await user.click(button) - - await waitFor(() => { - expect(component.queryByRole('menu')).toBeInTheDocument() - }) - - // Verify getAnchoredPosition was called without displayInViewport enabled - await waitFor(() => { - expect(mockGetAnchoredPosition).toHaveBeenCalled() - }) - - const calls = mockGetAnchoredPosition.mock.calls - const lastCall = calls[calls.length - 1] - expect(lastCall[2]?.displayInViewport).not.toBe(true) - }) - - it('should respect explicit displayInViewport prop over feature flag logic', async () => { - // Test that an explicit displayInViewport=false prop overrides the automatic - // detection, even when the flag is enabled and the ActionMenu is inside a dialog. - const component = HTMLRender( - - {}}> - - Toggle Menu - - - New file - - - - - , + , ) const user = userEvent.setup() @@ -1088,20 +1012,18 @@ describe('ActionMenu', () => { expect(lastCall[2]?.displayInViewport).toBe(false) }) - it('should respect explicit displayInViewport=true prop even when flag is disabled', async () => { + it('should respect explicit displayInViewport=true prop', async () => { // Test that an explicit displayInViewport=true prop works regardless of - // the flag state or dialog context. + // the dialog context. const component = HTMLRender( - - - Toggle Menu - - - New file - - - - , + + Toggle Menu + + + New file + + + , ) const user = userEvent.setup() diff --git a/packages/react/src/ActionMenu/ActionMenu.tsx b/packages/react/src/ActionMenu/ActionMenu.tsx index 429d1a5d0b0..47a61ae8c42 100644 --- a/packages/react/src/ActionMenu/ActionMenu.tsx +++ b/packages/react/src/ActionMenu/ActionMenu.tsx @@ -330,10 +330,6 @@ const Overlay: FCWithSlotMarker> = ({ } }, [anchorRef]) - const featureFlagDisplayInViewportInsideDialog = useFeatureFlag( - 'primer_react_action_menu_display_in_viewport_inside_dialog', - ) - const featureFlagMaxHeightClampToViewport = useFeatureFlag('primer_react_overlay_max_height_clamp_to_viewport') const isInsideDialog = useContext(DialogContext) !== undefined @@ -352,9 +348,7 @@ const Overlay: FCWithSlotMarker> = ({ focusZoneSettings={isNarrowFullscreen ? {disabled: true} : {focusOutBehavior: 'wrap'}} onPositionChange={onPositionChange} variant={variant} - displayInViewport={ - displayInViewport !== undefined ? displayInViewport : featureFlagDisplayInViewportInsideDialog && isInsideDialog - } + displayInViewport={displayInViewport !== undefined ? displayInViewport : isInsideDialog} >