theluyuan 38ba663466
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
init
2025-09-02 14:49:16 +08:00

158 lines
4.5 KiB
TypeScript

import React, { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { keyframes } from 'tss-react';
import { makeStyles } from 'tss-react/mui';
import { IReduxState } from '../../../app/types';
import { isMobileBrowser } from '../../environment/utils';
import Popover from '../../popover/components/Popover.web';
import { TOOLTIP_POSITION } from '../../ui/constants.any';
import { hideTooltip, showTooltip } from '../actions';
const TOOLTIP_DELAY = 300;
const ANIMATION_DURATION = 0.2;
interface IProps {
children: ReactElement;
containerClassName?: string;
content: string | ReactElement;
position?: TOOLTIP_POSITION;
}
const useStyles = makeStyles()(theme => {
return {
container: {
backgroundColor: theme.palette.uiBackground,
borderRadius: '3px',
padding: theme.spacing(2),
...theme.typography.labelRegular,
color: theme.palette.text01,
position: 'relative',
'&.mounting-animation': {
animation: `${keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`} ${ANIMATION_DURATION}s forwards ease-in`
},
'&.unmounting': {
animation: `${keyframes`
0% {
opacity: 1;
}
100% {
opacity: 0;
}
`} ${ANIMATION_DURATION}s forwards ease-out`
}
}
};
});
const Tooltip = ({ containerClassName, content, children, position = 'top' }: IProps) => {
const dispatch = useDispatch();
const [ visible, setVisible ] = useState(false);
const [ isUnmounting, setIsUnmounting ] = useState(false);
const overflowDrawer = useSelector((state: IReduxState) => state['features/toolbox'].overflowDrawer);
const { classes, cx } = useStyles();
const timeoutID = useRef({
open: 0,
close: 0
});
const {
content: storeContent,
previousContent,
visible: isVisible
} = useSelector((state: IReduxState) => state['features/base/tooltip']);
const contentComponent = (
<div
className = { cx(classes.container, previousContent === '' && 'mounting-animation',
isUnmounting && 'unmounting') }>
{content}
</div>
);
const openPopover = () => {
setVisible(true);
dispatch(showTooltip(content));
};
const closePopover = () => {
setVisible(false);
dispatch(hideTooltip(content));
setIsUnmounting(false);
};
const onPopoverOpen = useCallback(() => {
if (isUnmounting) {
return;
}
clearTimeout(timeoutID.current.close);
timeoutID.current.close = 0;
if (!visible) {
if (isVisible) {
openPopover();
} else {
timeoutID.current.open = window.setTimeout(() => {
openPopover();
}, TOOLTIP_DELAY);
}
}
}, [ visible, isVisible, isUnmounting ]);
const onPopoverClose = useCallback(() => {
clearTimeout(timeoutID.current.open);
if (visible) {
timeoutID.current.close = window.setTimeout(() => {
setIsUnmounting(true);
}, TOOLTIP_DELAY);
}
}, [ visible ]);
useEffect(() => {
if (isUnmounting) {
setTimeout(() => {
if (timeoutID.current.close !== 0) {
closePopover();
}
}, (ANIMATION_DURATION * 1000) + 10);
}
}, [ isUnmounting ]);
useEffect(() => {
if (storeContent !== content) {
closePopover();
clearTimeout(timeoutID.current.close);
timeoutID.current.close = 0;
}
}, [ storeContent ]);
if (isMobileBrowser() || overflowDrawer) {
return children;
}
return (
<Popover
allowClick = { true }
className = { containerClassName }
content = { contentComponent }
focusable = { false }
onPopoverClose = { onPopoverClose }
onPopoverOpen = { onPopoverOpen }
position = { position }
visible = { visible }>
{children}
</Popover>
);
};
export default Tooltip;