Skip to content

Commit

Permalink
[Dialog, Menu, Select] Set pointer-events on InternalBackdrop bas…
Browse files Browse the repository at this point in the history
…ed on `open` state (#1221)
  • Loading branch information
atomiks authored Dec 26, 2024
1 parent 5023734 commit 1d4206e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/alert-dialog/popup/AlertDialogPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const AlertDialogPopup = React.forwardRef(function AlertDialogPopup(

return (
<React.Fragment>
{mounted && modal && <InternalBackdrop />}
{mounted && modal && <InternalBackdrop inert={!open} />}
<FloatingFocusManager
context={floatingContext}
modal={open}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/dialog/popup/DialogPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ const DialogPopup = React.forwardRef(function DialogPopup(

return (
<React.Fragment>
{mounted && modal && <InternalBackdrop />}
{mounted && modal && <InternalBackdrop inert={!open} />}
<FloatingFocusManager
context={floatingContext}
modal={open}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/menu/positioner/MenuPositioner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ const MenuPositioner = React.forwardRef(function MenuPositioner(

return (
<MenuPositionerContext.Provider value={contextValue}>
{mounted && modal && parentNodeId === null && <InternalBackdrop />}
{mounted && modal && parentNodeId === null && <InternalBackdrop inert={!open} />}
<FloatingNode id={nodeId}>
<CompositeList elementsRef={itemDomElements} labelsRef={itemLabels}>
{renderElement()}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/select/positioner/SelectPositioner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const SelectPositioner = React.forwardRef(function SelectPositioner(
return (
<CompositeList elementsRef={listRef} labelsRef={labelsRef}>
<SelectPositionerContext.Provider value={positioner}>
{mounted && modal && <InternalBackdrop />}
{mounted && modal && <InternalBackdrop inert={!open} />}
{renderElement()}
</SelectPositionerContext.Provider>
</CompositeList>
Expand Down
48 changes: 46 additions & 2 deletions packages/react/src/utils/InternalBackdrop.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
import * as React from 'react';
import PropTypes from 'prop-types';

/**
* @ignore - internal component.
*/
export function InternalBackdrop() {
return <div role="presentation" style={{ position: 'fixed', inset: 0 }} />;
function InternalBackdrop(props: InternalBackdrop.Props) {
const { inert = false } = props;
return (
<div
role="presentation"
style={{
position: 'fixed',
inset: 0,
// Allows `:hover` events immediately after `open` changes to `false`,
// preventing a flicker when the cursor rests on the trigger. Flickers occur
// because CSS `:hover` is temporarily blocked during an exit animation,
// and `[data-popup-open]` is removed.
// Keeping the backdrop in the DOM avoids `[data-floating-ui-inert]`, which
// blocks outside clicks from closing the popup. This issue arises when
// conditionally rendering the backdrop on `open` and using exit animations.
// If the popup reopens before the exit animation finishes, the backdrop
// receives this attribute, breaking outside click behavior.
pointerEvents: inert ? 'none' : undefined,
}}
/>
);
}

namespace InternalBackdrop {
export interface Props {
/**
* Whether the backdrop should be inert (not block pointer events).
* @default false
*/
inert?: boolean;
}
}

InternalBackdrop.propTypes /* remove-proptypes */ = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* Whether the backdrop should be inert (not block pointer events).
* @default false
*/
inert: PropTypes.bool,
} as any;

export { InternalBackdrop };

0 comments on commit 1d4206e

Please sign in to comment.