Skip to content

Commit

Permalink
[Menu, Select, Dialog] Use internal backdrop for pointer modality (#1161
Browse files Browse the repository at this point in the history
)
  • Loading branch information
atomiks authored Dec 23, 2024
1 parent 46dba37 commit e014564
Show file tree
Hide file tree
Showing 20 changed files with 441 additions and 208 deletions.
75 changes: 36 additions & 39 deletions docs/src/app/(private)/experiments/popups-in-popups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ export default function PopupsInPopups() {

{withBackdrop && <Dialog.Backdrop render={<Backdrop />} />}

<DialogPopup>
<div style={{ display: 'flex', gap: '10px' }}>
<SelectDemo modal={modal} />
<MenuDemo modal={modal} />
</div>
<DialogControls>
<DialogCloseButton>Cancel</DialogCloseButton>
</DialogControls>
</DialogPopup>
<Dialog.Portal>
<DialogPopup>
<div style={{ display: 'flex', gap: '10px' }}>
<SelectDemo modal={modal} />
<MenuDemo modal={modal} />
</div>
<DialogControls>
<DialogCloseButton>Cancel</DialogCloseButton>
</DialogControls>
</DialogPopup>
</Dialog.Portal>
</Dialog.Root>
</div>
</div>
Expand All @@ -48,38 +50,40 @@ export default function PopupsInPopups() {

function SelectDemo({ modal }: Props) {
return (
<Select.Root defaultValue="system" modal={modal} alignItemToTrigger={false}>
<Select.Root modal={modal} defaultValue="system" alignItemToTrigger={false}>
<Tooltip.Root>
<Select.Trigger
aria-label="Select font"
render={<Tooltip.Trigger render={<Trigger />} />}
>
<Select.Value placeholder="System font" />
<SelectDropdownArrow />
<Tooltip.Portal>
<Tooltip.Positioner sideOffset={10} render={<TooltipPositioner />}>
<Tooltip.Popup render={<TooltipPopup />}>Choose a font</Tooltip.Popup>
</Tooltip.Positioner>
</Tooltip.Portal>
</Select.Trigger>
<Tooltip.Portal>
<Tooltip.Positioner sideOffset={10} render={<TooltipPositioner />}>
<Tooltip.Popup render={<TooltipPopup />}>Choose a font</Tooltip.Popup>
</Tooltip.Positioner>
</Tooltip.Portal>
</Tooltip.Root>

<Select.Positioner sideOffset={5} render={<Positioner />}>
<SelectPopup>
<SelectItem value="system">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>System font</Select.ItemText>
</SelectItem>
<SelectItem value="arial">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>Arial</Select.ItemText>
</SelectItem>
<SelectItem value="roboto">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>Roboto</Select.ItemText>
</SelectItem>
</SelectPopup>
</Select.Positioner>
<Select.Portal>
<Select.Positioner sideOffset={5} render={<Positioner />}>
<SelectPopup>
<SelectItem value="system">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>System font</Select.ItemText>
</SelectItem>
<SelectItem value="arial">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>Arial</Select.ItemText>
</SelectItem>
<SelectItem value="roboto">
<SelectItemIndicator render={<CheckIcon />} />
<Select.ItemText>Roboto</Select.ItemText>
</SelectItem>
</SelectPopup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
);
}
Expand Down Expand Up @@ -283,8 +287,6 @@ const SelectDropdownArrow = styled(Select.Icon)`
`;

const Positioner = styled('div')`
z-index: 2900;
&:focus-visible {
outline: 0;
}
Expand Down Expand Up @@ -364,7 +366,6 @@ const MenuPopup = styled(Menu.Popup)(
border: 1px solid ${theme.palette.mode === 'dark' ? grey[700] : grey[200]};
color: ${theme.palette.mode === 'dark' ? grey[300] : grey[900]};
box-shadow: 0px 4px 30px ${theme.palette.mode === 'dark' ? grey[900] : grey[200]};
z-index: 1;
transform-origin: var(--transform-origin);
opacity: 1;
transform: scale(1, 1);
Expand Down Expand Up @@ -460,7 +461,6 @@ const DialogPopup = styled(Dialog.Popup)(
font-family: "IBM Plex Sans", sans-serif;
transform: translate(-50%, -50%);
padding: 16px;
z-index: 2100;
`,
);

Expand Down Expand Up @@ -491,9 +491,7 @@ const DialogCloseButton = styled(Dialog.Close)(
`,
);

const TooltipPositioner = styled('div')`
z-index: 3000;
`;
const TooltipPositioner = styled('div')``;

const TooltipPopup = styled('div')`
box-sizing: border-box;
Expand Down Expand Up @@ -537,5 +535,4 @@ const Backdrop = styled('div')`
position: fixed;
inset: 0;
backdrop-filter: blur(4px);
z-index: 2000;
`;
25 changes: 15 additions & 10 deletions packages/react/src/alert-dialog/popup/AlertDialogPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useForkRef } from '../../utils/useForkRef';
import { InteractionType } from '../../utils/useEnhancedClickHandler';
import { transitionStatusMapping } from '../../utils/styleHookMapping';
import { AlertDialogPopupDataAttributes } from './AlertDialogPopupDataAttributes';
import { InternalBackdrop } from '../../utils/InternalBackdrop';

const customStyleHookMapping: CustomStyleHookMapping<AlertDialogPopup.State> = {
...baseMapping,
Expand Down Expand Up @@ -50,6 +51,7 @@ const AlertDialogPopup = React.forwardRef(function AlertDialogPopup(
setPopupElementId,
titleElementId,
transitionStatus,
modal,
} = useAlertDialogRootContext();

const mergedRef = useForkRef(forwardedRef, popupRef);
Expand Down Expand Up @@ -101,16 +103,19 @@ const AlertDialogPopup = React.forwardRef(function AlertDialogPopup(
}

return (
<FloatingFocusManager
context={floatingContext}
modal={open}
disabled={!mounted}
initialFocus={resolvedInitialFocus}
returnFocus={finalFocus}
outsideElementsInert
>
{renderElement()}
</FloatingFocusManager>
<React.Fragment>
{mounted && modal && <InternalBackdrop />}
<FloatingFocusManager
context={floatingContext}
modal={open}
disabled={!mounted}
initialFocus={resolvedInitialFocus}
returnFocus={finalFocus}
outsideElementsInert
>
{renderElement()}
</FloatingFocusManager>
</React.Fragment>
);
});

Expand Down
26 changes: 15 additions & 11 deletions packages/react/src/dialog/popup/DialogPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { InteractionType } from '../../utils/useEnhancedClickHandler';
import { transitionStatusMapping } from '../../utils/styleHookMapping';
import { DialogPopupCssVars } from './DialogPopupCssVars';
import { DialogPopupDataAttributes } from './DialogPopupDataAttributes';
import { InternalBackdrop } from '../../utils/InternalBackdrop';

const customStyleHookMapping: CustomStyleHookMapping<DialogPopup.State> = {
...baseMapping,
Expand Down Expand Up @@ -98,17 +99,20 @@ const DialogPopup = React.forwardRef(function DialogPopup(
}

return (
<FloatingFocusManager
context={floatingContext}
modal={open}
disabled={!mounted}
closeOnFocusOut={dismissible}
initialFocus={resolvedInitialFocus}
returnFocus={finalFocus}
outsideElementsInert={modal}
>
{renderElement()}
</FloatingFocusManager>
<React.Fragment>
{mounted && modal && <InternalBackdrop />}
<FloatingFocusManager
context={floatingContext}
modal={open}
disabled={!mounted}
closeOnFocusOut={dismissible}
initialFocus={resolvedInitialFocus}
returnFocus={finalFocus}
outsideElementsInert={modal}
>
{renderElement()}
</FloatingFocusManager>
</React.Fragment>
);
});

Expand Down
4 changes: 2 additions & 2 deletions packages/react/src/dialog/popup/useDialogPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function useDialogPopup(parameters: useDialogPopup.Parameters): useDialog
const id = useBaseUiId(idParam);
const handleRef = useForkRef(ref, popupRef, setPopupElement);

useScrollLock(modal && open, elements.floating);
useScrollLock(open && modal, elements.floating);

// Default initial focus logic:
// If opened by touch, focus the popup element to prevent the virtual keyboard from opening
Expand Down Expand Up @@ -91,7 +91,7 @@ export function useDialogPopup(parameters: useDialogPopup.Parameters): useDialog
mergeReactProps<'div'>(externalProps, {
'aria-labelledby': titleElementId ?? undefined,
'aria-describedby': descriptionElementId ?? undefined,
'aria-modal': open && modal ? true : undefined,
'aria-modal': mounted && modal ? true : undefined,
role: 'dialog',
tabIndex: -1,
...getPopupProps(),
Expand Down
Loading

0 comments on commit e014564

Please sign in to comment.