Skip to content

Commit

Permalink
Add controlled popover
Browse files Browse the repository at this point in the history
  • Loading branch information
atmelmicro committed Dec 3, 2024
1 parent 3808ce4 commit 4e54b81
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 13 deletions.
38 changes: 25 additions & 13 deletions src/components/Popover/Popover.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,29 @@ export const Popover = React.forwardRef((props, ref) => {
const {
placement,
children,
popoverHelperId,
portalId,
...restProps
} = props;

const PopoverEl = (
<div
{...transferProps(restProps)}
className={classNames(
styles.root,
ref && styles.isRootControlled,
getRootSideClassName(placement, styles),
getRootAlignmentClassName(placement, styles),
)}
ref={ref}
>
{children}
<span className={styles.arrow} />
</div>
<>
{!!popoverHelperId && <div className={styles.helper} id={popoverHelperId} popover="auto" />}
<div
{...transferProps(restProps)}
className={classNames(
styles.root,
ref && styles.isRootControlled,
popoverHelperId && styles.controlledPopover,
getRootSideClassName(placement, styles),
getRootAlignmentClassName(placement, styles),
)}
ref={ref}
>
{children}
<span className={styles.arrow} />
</div>
</>
);

if (portalId === null) {
Expand All @@ -41,6 +46,7 @@ export const Popover = React.forwardRef((props, ref) => {

Popover.defaultProps = {
placement: 'bottom',
popoverHelperId: null,
portalId: null,
};

Expand All @@ -67,6 +73,12 @@ Popover.propTypes = {
'left-start',
'left-end',
]),
/**
* If set, the popover will become controlled, meaning it will be hidden by default and will need a trigger to open.
* This sets the ID of the internal helper element for the popover.
* Assign the same ID to `popovertarget` of a trigger to make it open and close.
*/
popoverHelperId: PropTypes.string,
/**
* If set, popover is rendered in the React Portal with that ID.
*/
Expand Down
22 changes: 22 additions & 0 deletions src/components/Popover/Popover.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,28 @@
}
}

// Controlled popover
.controlledPopover {
display: none;
}

.helper {
position: fixed;
inset: unset;
top: 0;
right: 0;
width: auto;
height: auto;
padding: 0;
border: none;
background: transparent;
pointer-events: none;
}

.helper:popover-open ~ .controlledPopover {
display: block;
}

// Sides
.isRootAtTop {
bottom: calc(100% + #{theme.$arrow-gap} - #{theme.$arrow-safe-rendering-overlap});
Expand Down
30 changes: 30 additions & 0 deletions src/components/Popover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,36 @@ React.createElement(() => {
});
```

## Controlled Popover

To make it easier to implement the popover in your app, you can set the `popoverHelperId` prop to the same ID as the `popovertarget` of a trigger. This uses the browser Popover API and will control the popover by closing it when the trigger or backdrop is pressed.

```docoff-react-preview
React.createElement(() => {
// All inline styles in this example are for demonstration purposes only.
return (
<div
style={{
display: 'grid',
placeContent: 'center',
minWidth: '20rem',
minHeight: '10rem',
}}
>
<PopoverWrapper>
<Button
label="Want to see a popover? Click me!"
popovertarget="my-popover-helper"
/>
<Popover id="my-popover" popoverHelperId="my-popover-helper">
Hello there!
</Popover>
</PopoverWrapper>
</div>
);
});
```

## Forwarding HTML Attributes

In addition to the options below in the [component's API](#api) section, you
Expand Down

0 comments on commit 4e54b81

Please sign in to comment.