feat: modify popper

This commit is contained in:
QiShaoXuan 2022-11-03 18:59:54 +08:00
parent d9205bb405
commit 75f05cb399
4 changed files with 70 additions and 147 deletions

View File

@ -1,65 +0,0 @@
import { useState } from 'react';
import type { CSSProperties, PropsWithChildren, ReactNode } from 'react';
import Grow from '@mui/material/Grow';
import ClickAwayListener from '@mui/base/ClickAwayListener';
import { styled } from '@/styles';
type PopoverProps = {
popoverContent?: ReactNode;
style?: CSSProperties;
};
const StyledPopoverContainer = styled('div')({
position: 'relative',
cursor: 'pointer',
});
const StyledPopoverWrapper = styled('div')({
position: 'absolute',
bottom: '0',
right: '0',
paddingTop: '46px',
zIndex: 1000,
});
const StyledPopover = styled('div')(({ theme }) => {
return {
width: '248px',
background: theme.colors.popoverBackground,
boxShadow: theme.shadow.popover,
color: theme.colors.popoverColor,
borderRadius: '10px 0px 10px 10px',
padding: '8px 4px',
position: 'absolute',
top: '46px',
right: '0',
};
});
export const Popover = ({
children,
popoverContent,
style = {},
}: PropsWithChildren<PopoverProps>) => {
const [show, setShow] = useState(false);
return (
<ClickAwayListener
onClickAway={() => {
setShow(false);
}}
>
<StyledPopoverContainer
onClick={() => {
setShow(!show);
}}
style={style}
>
{children}
<Grow in={show}>
<StyledPopoverWrapper>
<StyledPopover>{popoverContent}</StyledPopover>
</StyledPopoverWrapper>
</Grow>
</StyledPopoverContainer>
</ClickAwayListener>
);
};

View File

@ -4,6 +4,7 @@ import {
useMemo, useMemo,
useRef, useRef,
useState, useState,
cloneElement,
} from 'react'; } from 'react';
import PopperUnstyled from '@mui/base/PopperUnstyled'; import PopperUnstyled from '@mui/base/PopperUnstyled';
import ClickAwayListener from '@mui/base/ClickAwayListener'; import ClickAwayListener from '@mui/base/ClickAwayListener';
@ -26,7 +27,6 @@ export const Popper = ({
onVisibleChange, onVisibleChange,
popoverStyle, popoverStyle,
popoverClassName, popoverClassName,
anchorStyle,
anchorClassName, anchorClassName,
zIndex, zIndex,
offset = [0, 5], offset = [0, 5],
@ -36,12 +36,9 @@ export const Popper = ({
onClickAway, onClickAway,
...popperProps ...popperProps
}: PopperProps) => { }: PopperProps) => {
// @ts-ignore const [anchorEl, setAnchorEl] = useState<VirtualElement>();
const [anchorEl, setAnchorEl] = useState<VirtualElement>(null);
const [visible, setVisible] = useState(defaultVisible); const [visible, setVisible] = useState(defaultVisible);
// @ts-ignore const [arrowRef, setArrowRef] = useState<HTMLElement>();
const [arrowRef, setArrowRef] = useState<HTMLElement>(null);
const popperRef = useRef();
const pointerLeaveTimer = useRef<number>(); const pointerLeaveTimer = useRef<number>();
const pointerEnterTimer = useRef<number>(); const pointerEnterTimer = useRef<number>();
@ -95,7 +92,6 @@ export const Popper = ({
}; };
}); });
// @ts-ignore
return ( return (
<ClickAwayListener <ClickAwayListener
onClickAway={() => { onClickAway={() => {
@ -107,27 +103,23 @@ export const Popper = ({
}} }}
> >
<Container> <Container>
{isAnchorCustom ? null : ( {cloneElement(children, {
<div ref: (dom: HTMLDivElement) => setAnchorEl(dom),
ref={(dom: HTMLDivElement) => setAnchorEl(dom)} onClick: (e: MouseEvent) => {
onClick={e => {
if (!hasClickTrigger || visibleControlledByParent) { if (!hasClickTrigger || visibleControlledByParent) {
// @ts-ignore
onClick?.(e); onClick?.(e);
return; return;
} }
setVisible(!visible); setVisible(!visible);
}} },
onPointerEnter={onPointerEnterHandler} onPointerEnter: onPointerEnterHandler,
onPointerLeave={onPointerLeaveHandler} onPointerLeave: onPointerLeaveHandler,
style={anchorStyle} className: anchorClassName,
className={anchorClassName} popperVisible: visible,
> })}
{children} {content && (
</div>
)}
<BasicStyledPopper <BasicStyledPopper
// @ts-ignore
popperRef={popperRef}
open={visibleControlledByParent ? propsVisible : visible} open={visibleControlledByParent ? propsVisible : visible}
zIndex={zIndex} zIndex={zIndex}
anchorEl={isAnchorCustom ? propsAnchorEl : anchorEl} anchorEl={isAnchorCustom ? propsAnchorEl : anchorEl}
@ -167,6 +159,7 @@ export const Popper = ({
</Grow> </Grow>
)} )}
</BasicStyledPopper> </BasicStyledPopper>
)}
</Container> </Container>
</ClickAwayListener> </ClickAwayListener>
); );
@ -184,6 +177,6 @@ const BasicStyledPopper = styled(PopperUnstyled, {
zIndex?: number; zIndex?: number;
}>(({ zIndex, theme }) => { }>(({ zIndex, theme }) => {
return { return {
zIndex: zIndex, zIndex: zIndex ?? theme.zIndex.popover,
}; };
}); });

View File

@ -1,4 +1,4 @@
import type { CSSProperties, ReactNode, Ref } from 'react'; import type { CSSProperties, ReactNode, Ref, ReactElement } from 'react';
import { import {
type PopperPlacementType, type PopperPlacementType,
type PopperUnstyledProps, type PopperUnstyledProps,
@ -18,10 +18,10 @@ export type PopperArrowProps = {
export type PopperProps = { export type PopperProps = {
// Popover content // Popover content
content: ReactNode; content?: ReactNode;
// Popover trigger // Popover trigger
children?: ReactNode; children: ReactElement;
// Whether the default is implicit // Whether the default is implicit
defaultVisible?: boolean; defaultVisible?: boolean;
@ -47,9 +47,6 @@ export type PopperProps = {
// Popover container class name // Popover container class name
popoverClassName?: string; popoverClassName?: string;
// Anchor style
anchorStyle?: CSSProperties;
// Anchor class name // Anchor class name
anchorClassName?: string; anchorClassName?: string;
@ -63,4 +60,4 @@ export type PopperProps = {
popperHandlerRef?: Ref<PopperHandler>; popperHandlerRef?: Ref<PopperHandler>;
onClickAway?: () => void; onClickAway?: () => void;
} & Omit<PopperUnstyledProps, 'open' | 'ref'>; } & Omit<PopperUnstyledProps, 'open'>;

View File

@ -1,4 +1,3 @@
import { type PropsWithChildren } from 'react';
import StyledPopperContainer from '../shared/Container'; import StyledPopperContainer from '../shared/Container';
import { Popper, type PopperProps } from '../popper'; import { Popper, type PopperProps } from '../popper';
import { styled } from '@/styles'; import { styled } from '@/styles';
@ -14,16 +13,15 @@ const StyledTooltip = styled(StyledPopperContainer)(({ theme }) => {
}; };
}); });
export const Tooltip = ( export const Tooltip = (props: PopperProps & Omit<TooltipProps, 'title'>) => {
props: PropsWithChildren<PopperProps & Omit<TooltipProps, 'title'>> const { content, placement = 'top-start', children } = props;
) => { return (
const { content, placement = 'top-start' } = props;
// If there is no content, hide forever
return content ? (
<Popper <Popper
{...props} {...props}
showArrow={false} showArrow={false}
content={<StyledTooltip placement={placement}>{content}</StyledTooltip>} content={<StyledTooltip placement={placement}>{content}</StyledTooltip>}
/> >
) : null; {children}
</Popper>
);
}; };