import * as React from 'react'; import classNames from 'classnames'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; import KeyCode from 'rc-util/lib/KeyCode'; import type { RenderFunction } from '../_util/getRenderPropValue'; import { getRenderPropValue } from '../_util/getRenderPropValue'; import { getTransitionName } from '../_util/motion'; import { cloneElement } from '../_util/reactNode'; import { ConfigContext } from '../config-provider'; import type { AbstractTooltipProps, TooltipRef } from '../tooltip'; import Tooltip from '../tooltip'; import PurePanel from './PurePanel'; // CSSINJS import useStyle from './style'; export interface PopoverProps extends AbstractTooltipProps { title?: React.ReactNode | RenderFunction; content?: React.ReactNode | RenderFunction; onOpenChange?: ( open: boolean, e?: React.MouseEvent | React.KeyboardEvent, ) => void; } interface OverlayProps { prefixCls?: string; title?: PopoverProps['title']; content?: PopoverProps['content']; } const Overlay: React.FC = ({ title, content, prefixCls }) => ( <> {title &&
{getRenderPropValue(title)}
}
{getRenderPropValue(content)}
); const InternalPopover = React.forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, title, content, overlayClassName, placement = 'top', trigger = 'hover', children, mouseEnterDelay = 0.1, mouseLeaveDelay = 0.1, onOpenChange, overlayStyle = {}, ...otherProps } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('popover', customizePrefixCls); const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls); const rootPrefixCls = getPrefixCls(); const overlayCls = classNames(overlayClassName, hashId, cssVarCls); const [open, setOpen] = useMergedState(false, { value: props.open ?? props.visible, }); const settingOpen = ( value: boolean, e?: React.MouseEvent | React.KeyboardEvent, ) => { setOpen(value, true); onOpenChange?.(value, e); }; const onKeyDown = (e: React.KeyboardEvent) => { if (e.keyCode === KeyCode.ESC) { settingOpen(false, e); } }; const onInternalOpenChange = (value: boolean) => { settingOpen(value); }; return wrapCSSVar( : null } transitionName={getTransitionName(rootPrefixCls, 'zoom-big', otherProps.transitionName)} data-popover-inject > {cloneElement(children, { onKeyDown: (e: React.KeyboardEvent) => { if (React.isValidElement(children)) { children?.props.onKeyDown?.(e); } onKeyDown(e); }, })} , ); }); type CompoundedComponent = typeof InternalPopover & { _InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel; }; const Popover = InternalPopover as CompoundedComponent; Popover._InternalPanelDoNotUseOrYouWillBeFired = PurePanel; if (process.env.NODE_ENV !== 'production') { Popover.displayName = 'Popover'; } export default Popover;