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
26 changes: 13 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"@github/tab-container-element": "^4.8.2",
"@lit-labs/react": "1.2.1",
"@oddbird/popover-polyfill": "^0.5.2",
"@primer/behaviors": "^1.10.0",
"@primer/behaviors": "^1.10.2",
"@primer/live-region-element": "^0.7.1",
"@primer/octicons-react": "^19.21.0",
"@primer/primitives": "10.x || 11.x",
Expand Down
105 changes: 103 additions & 2 deletions packages/react/src/ActionMenu/ActionMenu.examples.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import {ActionMenu, ActionList, Button, IconButton, FormControl, TextInput} from '../'
import React, {useState, useCallback} from 'react'
import {ActionMenu, ActionList, Button, IconButton, FormControl, TextInput, Dialog, Text} from '../'
import {
GearIcon,
MilestoneIcon,
Expand Down Expand Up @@ -654,3 +654,104 @@ export const DynamicAnchorSides = () => {
</>
)
}

export const InsideDialog = () => {
const [isDialogOpen, setIsDialogOpen] = useState(false)

const onDialogClose = useCallback(() => setIsDialogOpen(false), [])
const openDialog = useCallback(() => setIsDialogOpen(true), [])

// Create scrollable content with multiple paragraphs
const scrollableContent = Array.from({length: 50}, (_, index) => (
<Text key={index} as="p" style={{marginBottom: '12px'}}>
This is paragraph {index + 1}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur.
</Text>
))

return (
<div style={{padding: '20px'}}>
{/* Main scrollable content */}
<div>
<Text as="h1" style={{marginBottom: '16px'}}>
Main Page Content
</Text>

<Button onClick={openDialog} style={{margin: '16px 0'}}>
Open Dialog with ActionMenu
</Button>

{/* Show more content after the button to make it scrollable */}
{scrollableContent}
</div>

{/* Dialog containing ActionMenu */}
{isDialogOpen && (
<Dialog title="Dialog with ActionMenu" onClose={onDialogClose} width="medium">
<Text as="p" style={{marginBottom: '12px'}}>
This dialog contains an ActionMenu. The main page content behind is long enough to be scrollable.
</Text>

<Text as="h3" style={{marginBottom: '8px', fontWeight: '600'}}>
Document Settings
</Text>

<Text as="p" style={{marginBottom: '16px', color: '#656d76'}}>
Configure the document properties and sharing settings. These options allow you to control how the document
is displayed and who has access to it.
</Text>

<ActionMenu>
<ActionMenu.Button>Actions</ActionMenu.Button>
<ActionMenu.Overlay width="medium" displayInViewport={true}>
<ActionList>
<ActionList.Item onSelect={() => alert('Save clicked')}>
Save
<ActionList.TrailingVisual>⌘S</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Save as clicked')}>
Save as...
<ActionList.TrailingVisual>⌘⇧S</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Export clicked')}>
Export
<ActionList.TrailingVisual>⌘E</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Print clicked')}>
Print
<ActionList.TrailingVisual>⌘P</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Divider />
<ActionList.Item onSelect={() => alert('Copy clicked')}>
Copy
<ActionList.TrailingVisual>⌘C</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Paste clicked')}>
Paste
<ActionList.TrailingVisual>⌘V</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Duplicate clicked')}>
Duplicate
<ActionList.TrailingVisual>⌘D</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Divider />
<ActionList.Item onSelect={() => alert('Share clicked')}>
Share
<ActionList.TrailingVisual>⌘⇧U</ActionList.TrailingVisual>
</ActionList.Item>
<ActionList.Item onSelect={() => alert('Share via email clicked')}>Share via email</ActionList.Item>
<ActionList.Item onSelect={() => alert('Share via link clicked')}>Share via link</ActionList.Item>
</ActionList>
</ActionMenu.Overlay>
</ActionMenu>

<Text as="p" style={{marginTop: '12px'}}>
You can interact with the ActionMenu above while the main page content remains scrollable in the background.
</Text>
</Dialog>
)}
</div>
)
}
3 changes: 3 additions & 0 deletions packages/react/src/ActionMenu/ActionMenu.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.ActionMenuContainer {
/* add default max height */
max-height: 100vh;

&:where([data-variant='fullscreen']) {
padding-top: var(--base-size-36);
}
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/ActionMenu/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ const defaultVariant: ResponsiveValue<'anchored', 'anchored' | 'fullscreen'> = {
}

type MenuOverlayProps = Partial<OverlayProps> &
Pick<AnchoredOverlayProps, 'align' | 'side' | 'variant'> & {
Pick<AnchoredOverlayProps, 'align' | 'side' | 'variant' | 'displayInViewport'> & {
/**
* Recommended: `ActionList`
*/
Expand All @@ -268,6 +268,7 @@ const Overlay: FCWithSlotMarker<React.PropsWithChildren<MenuOverlayProps>> = ({
align = 'start',
side,
onPositionChange,
displayInViewport,
'aria-labelledby': ariaLabelledby,
variant = defaultVariant,
...overlayProps
Expand Down Expand Up @@ -331,6 +332,7 @@ const Overlay: FCWithSlotMarker<React.PropsWithChildren<MenuOverlayProps>> = ({
focusZoneSettings={isNarrowFullscreen ? {disabled: true} : {focusOutBehavior: 'wrap'}}
onPositionChange={onPositionChange}
variant={variant}
displayInViewport={displayInViewport}
>
<div
ref={containerRef}
Expand Down
4 changes: 3 additions & 1 deletion packages/react/src/AnchoredOverlay/AnchoredOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ interface AnchoredOverlayBaseProps extends Pick<OverlayProps, 'height' | 'width'

export type AnchoredOverlayProps = AnchoredOverlayBaseProps &
(AnchoredOverlayPropsWithAnchor | AnchoredOverlayPropsWithoutAnchor) &
Partial<Pick<PositionSettings, 'align' | 'side' | 'anchorOffset' | 'alignmentOffset'>>
Partial<Pick<PositionSettings, 'align' | 'side' | 'anchorOffset' | 'alignmentOffset' | 'displayInViewport'>>

const defaultVariant = {
regular: 'anchored',
Expand Down Expand Up @@ -151,6 +151,7 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
align = 'start',
alignmentOffset,
anchorOffset,
displayInViewport,
className,
pinPosition,
variant = defaultVariant,
Expand Down Expand Up @@ -206,6 +207,7 @@ export const AnchoredOverlay: React.FC<React.PropsWithChildren<AnchoredOverlayPr
align,
alignmentOffset,
anchorOffset,
displayInViewport,
onPositionChange: positionChange,
},
[overlayRef.current],
Expand Down
Loading