mirror of
https://github.com/apache/superset.git
synced 2026-05-31 21:29:19 +00:00
refactor(Popover): Upgrade Popover to Antd5 (#31973)
Co-authored-by: Geido <60598000+geido@users.noreply.github.com>
This commit is contained in:
@@ -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} />);
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user