Skip to content

Commit

Permalink
feat(popover): add useAnchorWidth prop (#826)
Browse files Browse the repository at this point in the history
* feat(popover): add useAnchorWidth prop

#787

* refactor(popover): replace custom logic with resize observer

* fix(popover): replace update with updatePopperRef

* chore(popover): add useAnchorWidth check

Co-authored-by: Кононенко Артем Игоревич <AIKononenko@alfabank.ru>
  • Loading branch information
Artess999 and Кононенко Артем Игоревич committed Sep 14, 2021
1 parent f3c0d62 commit 8df55c4
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
3 changes: 2 additions & 1 deletion packages/popover/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"classnames": "^2.2.6",
"react-merge-refs": "^1.1.0",
"react-popper": "^2.2.5",
"react-transition-group": "^4.3.0"
"react-transition-group": "^4.3.0",
"resize-observer": "^1.0.0"
},
"devDependencies": {
"@types/react-transition-group": "^4.2.4"
Expand Down
35 changes: 35 additions & 0 deletions packages/popover/src/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import React, {
MutableRefObject,
forwardRef,
ReactNode,
useRef,
} from 'react';
import cn from 'classnames';
import { CSSTransition } from 'react-transition-group';
import { CSSTransitionProps } from 'react-transition-group/CSSTransition';
import { usePopper } from 'react-popper';
import { BasePlacement, VariationPlacement, Obj } from '@popperjs/core';
import mergeRefs from 'react-merge-refs';
import { ResizeObserver } from 'resize-observer';

import { Stack, stackingOrder } from '@alfalab/core-components-stack';
import { Portal } from '@alfalab/core-components-portal';
Expand All @@ -39,6 +41,11 @@ export type PopoverProps = {
*/
anchorElement: RefElement;

/**
* Использовать ширину родительского элемента
*/
useAnchorWidth?: boolean;

/**
* Позиционирование поповера
*/
Expand Down Expand Up @@ -148,6 +155,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
getPortalContainer,
transition = DEFAULT_TRANSITION,
anchorElement,
useAnchorWidth,
offset = [0, 0],
withArrow = false,
withTransition = true,
Expand All @@ -169,6 +177,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
const [referenceElement, setReferenceElement] = useState<RefElement>(anchorElement);
const [popperElement, setPopperElement] = useState<RefElement>(null);
const [arrowElement, setArrowElement] = useState<RefElement>(null);
const updatePopperRef = useRef<() => void>();

const getModifiers = useCallback(() => {
const modifiers: PopperModifier[] = [{ name: 'offset', options: { offset } }];
Expand Down Expand Up @@ -201,6 +210,16 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
},
);

if (updatePopper) {
updatePopperRef.current = updatePopper;
}

const updatePopoverWidth = useCallback(() => {
if (useAnchorWidth && updatePopperRef.current) {
updatePopperRef.current();
}
}, [useAnchorWidth]);

useEffect(() => {
setReferenceElement(anchorElement);
}, [anchorElement]);
Expand All @@ -218,13 +237,29 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
}
});

useEffect(() => {
if (useAnchorWidth) {
const observer = new ResizeObserver(updatePopoverWidth);
if (anchorElement) {
observer.observe(anchorElement);
}

return () => {
observer.disconnect();
};
}

return () => ({});
}, [anchorElement, updatePopoverWidth, useAnchorWidth]);

const renderContent = (computedZIndex: number, style?: CSSProperties) => {
return (
<div
ref={mergeRefs([ref, setPopperElement])}
// ref={setPopperElement}
style={{
zIndex: computedZIndex,
width: useAnchorWidth ? referenceElement?.offsetWidth : undefined,
...popperStyles.popper,
}}
data-test-id={dataTestId}
Expand Down
1 change: 1 addition & 0 deletions packages/popover/src/docs/Component.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import styles from '!!raw-loader!../index.module.css';
>
<Popover
anchorElement={buttonElement}
useAnchorWidth={boolean('useAnchorWidth', false)}
position={select('position', POSITION_OPTIONS, 'bottom')}
open={open}
transition={{ timeout: transitionTimeout }}
Expand Down
1 change: 1 addition & 0 deletions packages/popover/src/docs/description.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ render(() => {
>
<Popover
anchorElement={buttonElement}
useAnchorWidth={true}
position='bottom'
open={true}
update={updatePopover}
Expand Down

0 comments on commit 8df55c4

Please sign in to comment.