Skip to content

Commit

Permalink
Fix misplaced Popover when using Floating UI (#566)
Browse files Browse the repository at this point in the history
  • Loading branch information
atmelmicro committed Jan 31, 2025
1 parent d0d9758 commit e8d4e6e
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 3 deletions.
22 changes: 22 additions & 0 deletions src/components/Popover/Popover.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createPortal } from 'react-dom';
import { withGlobalProps } from '../../providers/globalProps';
import { classNames } from '../../utils/classNames';
import { transferProps } from '../../utils/transferProps';
import cleanPlacementStyle from './_helpers/cleanPlacementStyle';
import getRootSideClassName from './_helpers/getRootSideClassName';
import getRootAlignmentClassName from './_helpers/getRootAlignmentClassName';
import styles from './Popover.module.scss';
Expand All @@ -12,6 +13,7 @@ export const Popover = React.forwardRef((props, ref) => {
const {
placement,
children,
placementStyle,
popoverTargetId,
portalId,
...restProps
Expand Down Expand Up @@ -41,6 +43,7 @@ export const Popover = React.forwardRef((props, ref) => {
getRootAlignmentClassName(placement, styles),
)}
ref={ref}
style={cleanPlacementStyle(placementStyle ?? {})}
>
{children}
<span className={styles.arrow} />
Expand All @@ -57,6 +60,7 @@ export const Popover = React.forwardRef((props, ref) => {

Popover.defaultProps = {
placement: 'bottom',
placementStyle: null,
popoverTargetId: null,
portalId: null,
};
Expand Down Expand Up @@ -84,6 +88,24 @@ Popover.propTypes = {
'left-start',
'left-end',
]),
/**
* Used for positioning the popover with a library like Floating UI. It is filtered,
* then passed to the popover as the `style` prop.
*/
placementStyle: PropTypes.shape({
bottom: PropTypes.string,
inset: PropTypes.string,
'inset-block-end': PropTypes.string,
'inset-block-start': PropTypes.string,
'inset-inline-end': PropTypes.string,
'inset-inline-start': PropTypes.string,
left: PropTypes.string,
position: PropTypes.string,
right: PropTypes.string,
top: PropTypes.string,
'transform-origin': PropTypes.string,
translate: PropTypes.string,
}),
/**
* 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.
Expand Down
30 changes: 27 additions & 3 deletions src/components/Popover/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,29 @@ automatically, including smart position updates to ensure Popover visibility,
we recommend to involve an external library designed specifically for this
purpose.

To position the popover, you need to provide the `placementStyle` prop with the
style you want to apply to the popover. This prop should only be used to
position the popover. The allowed props are:

- `position`
- `inset`
- `inset-inline-start`
- `inset-inline-end`
- `inset-block-start`
- `inset-block-end`
- `top`
- `right`
- `bottom`
- `left`
- `translate`
- `transform-origin`

⚠️ [`inset`][mdn-inset] is a shorthand for `top right bottom left`, not for
`inset-*` properties.

As opposed to `top right bottom left` and the `inset` shorthand, `inset-*`
properties are writing-direction aware.

ℹ️ The following example is using external library [Floating UI]. To use
Floating UI, install it first:

Expand Down Expand Up @@ -267,10 +290,10 @@ React.createElement(() => {
<Popover
id="my-advanced-popover"
placement={finalPlacement}
style={{
placementStyle={{
position: strategy,
top: y ? y : '',
left: x ? x : '',
top: `${y}px`,
left: `${x}px`,
}}
ref={floating}
>
Expand Down Expand Up @@ -359,5 +382,6 @@ which enables [Advanced Positioning](#advanced-positioning).

[div-attributes]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div#attributes
[Floating UI]: https://floating-ui.com/docs/react-dom
[mdn-inset]: https://developer.mozilla.org/en-US/docs/Web/CSS/inset
[React common props]: https://react.dev/reference/react-dom/components/common#common-props
[ref]: https://reactjs.org/docs/refs-and-the-dom.html
20 changes: 20 additions & 0 deletions src/components/Popover/_helpers/cleanPlacementStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default (placementStyle) => {
const validProps = [
'position',
'inset',
'inset-inline-start',
'inset-inline-end',
'inset-block-start',
'inset-block-end',
'top',
'right',
'bottom',
'left',
'translate',
'transform-origin',
];

return Object.fromEntries(
Object.entries(placementStyle).filter(([prop]) => validProps.includes(prop)),
);
};

0 comments on commit e8d4e6e

Please sign in to comment.