refactor(Popover): Upgrade Popover to Antd5 (#31973)

Co-authored-by: Geido <60598000+geido@users.noreply.github.com>
This commit is contained in:
Alexandru Soare
2025-02-10 16:38:17 +02:00
committed by GitHub
parent 06f8f8e608
commit 0030f46d2d
30 changed files with 157 additions and 228 deletions

View File

@@ -88,7 +88,7 @@ test('Should lock the vertical scroll when the popover is visible', () => {
test('Should place popover at the top', async () => {
const { setStateMock } = setupTest({
...createProps(),
getVisibilityRatio: () => 0.2,
getVisibilityRatio: () => ({ yRatio: 0.2, xRatio: 0.3 }),
});
expect(screen.getByTestId('control-popover')).toBeInTheDocument();
@@ -102,21 +102,21 @@ test('Should place popover at the top', async () => {
test('Should place popover at the center', async () => {
const { setStateMock } = setupTest({
...createProps(),
getVisibilityRatio: () => 0.5,
getVisibilityRatio: () => ({ yRatio: 0.5, xRatio: 0.7 }),
});
expect(screen.getByTestId('control-popover')).toBeInTheDocument();
userEvent.click(screen.getByTestId('control-popover'));
await waitFor(() => {
expect(setStateMock).toHaveBeenCalledWith('right');
expect(setStateMock).toHaveBeenCalledWith('left');
});
});
test('Should place popover at the bottom', async () => {
const { setStateMock } = setupTest({
...createProps(),
getVisibilityRatio: () => 0.7,
getVisibilityRatio: () => ({ yRatio: 0.9, xRatio: 0.2 }),
});
expect(screen.getByTestId('control-popover')).toBeInTheDocument();
@@ -162,7 +162,7 @@ test('Controlled mode', async () => {
const baseProps = {
...createProps(),
destroyTooltipOnHide: true,
visible: false,
open: false,
};
const { rerender } = setupTest(baseProps);
@@ -170,7 +170,7 @@ test('Controlled mode', async () => {
expect(screen.getByTestId('control-popover')).toBeInTheDocument();
expect(screen.queryByText('Control Popover Test')).not.toBeInTheDocument();
rerender(<TestComponent {...baseProps} visible />);
rerender(<TestComponent {...baseProps} open />);
expect(await screen.findByText('Control Popover Test')).toBeInTheDocument();
rerender(<TestComponent {...baseProps} />);

View File

@@ -21,49 +21,70 @@ import React, { FC, useCallback, useRef, useEffect, useState } from 'react';
import Popover, {
PopoverProps as BasePopoverProps,
TooltipPlacement,
} from 'src/components/Popover';
import { TooltipPlacement } from 'src/components/Tooltip';
const sectionContainerId = 'controlSections';
export const getSectionContainerElement = () =>
document.getElementById(sectionContainerId)?.lastElementChild as HTMLElement;
const getElementYVisibilityRatioOnContainer = (node: HTMLElement) => {
const getElementVisibilityRatio = (node?: HTMLElement) => {
const containerHeight = window?.innerHeight;
const nodePositionInViewport = node?.getBoundingClientRect()?.top;
if (!containerHeight || !nodePositionInViewport) {
return 0;
const containerWidth = window?.innerWidth;
const rect = node?.getBoundingClientRect();
if (!containerHeight || !containerWidth || !rect?.top) {
return { yRatio: 0, xRatio: 0 };
}
return nodePositionInViewport / containerHeight;
const yRatio = rect.top / containerHeight;
const xRatio = rect.left / containerWidth;
return { yRatio, xRatio };
};
export type PopoverProps = BasePopoverProps & {
getVisibilityRatio?: typeof getElementYVisibilityRatioOnContainer;
getVisibilityRatio?: typeof getElementVisibilityRatio;
};
const ControlPopover: FC<PopoverProps> = ({
getPopupContainer,
getVisibilityRatio = getElementYVisibilityRatioOnContainer,
visible: visibleProp,
getVisibilityRatio = getElementVisibilityRatio,
open: visibleProp,
destroyTooltipOnHide = false,
placement: initialPlacement = 'right',
...props
}) => {
const triggerElementRef = useRef<HTMLElement>();
const [visible, setVisible] = useState(
visibleProp === undefined ? props.defaultVisible : visibleProp,
visibleProp === undefined ? props.defaultOpen : visibleProp,
);
const [placement, setPlacement] = React.useState<TooltipPlacement>('right');
const [placement, setPlacement] =
React.useState<TooltipPlacement>(initialPlacement);
const calculatePlacement = useCallback(() => {
const visibilityRatio = getVisibilityRatio(triggerElementRef.current!);
if (visibilityRatio < 0.35 && placement !== 'rightTop') {
setPlacement('rightTop');
} else if (visibilityRatio > 0.65 && placement !== 'rightBottom') {
setPlacement('rightBottom');
} else {
setPlacement('right');
if (!triggerElementRef.current) return;
const { yRatio, xRatio } = getVisibilityRatio(triggerElementRef.current);
const horizontalPlacement =
xRatio < 0.35 ? 'right' : xRatio > 0.65 ? 'left' : '';
const verticalPlacement = (() => {
if (yRatio < 0.35) return horizontalPlacement ? 'top' : 'bottom';
if (yRatio > 0.65) return horizontalPlacement ? 'bottom' : 'top';
return '';
})();
const newPlacement =
((horizontalPlacement
? horizontalPlacement +
verticalPlacement.charAt(0).toUpperCase() +
verticalPlacement.slice(1)
: verticalPlacement) as TooltipPlacement) || 'left';
if (newPlacement !== placement) {
setPlacement(newPlacement);
}
}, [getVisibilityRatio]);
@@ -97,7 +118,7 @@ const ControlPopover: FC<PopoverProps> = ({
}
setVisible(!!visible);
props.onVisibleChange?.(!!visible);
props.onOpenChange?.(!!visible);
},
[props, changeContainerScrollStatus],
);
@@ -106,7 +127,7 @@ const ControlPopover: FC<PopoverProps> = ({
(event: KeyboardEvent) => {
if (event.key === 'Escape') {
setVisible(false);
props.onVisibleChange?.(false);
props.onOpenChange?.(false);
}
},
[props],
@@ -143,10 +164,10 @@ const ControlPopover: FC<PopoverProps> = ({
return (
<Popover
{...props}
visible={visible}
arrowPointAtCenter
open={visible}
arrow={{ pointAtCenter: true }}
placement={placement}
onVisibleChange={handleOnVisibleChange}
onOpenChange={handleOnVisibleChange}
getPopupContainer={handleGetPopupContainer}
destroyTooltipOnHide={destroyTooltipOnHide}
/>