import { Component, createRef } from 'react'; import cx from 'classnames'; import Popover, { IPositionFunction, IPopoverClickTriggerChildProps, IPopoverClickTriggerProps, IPopoverTriggerProps, IPopoverHoverTriggerChildProps, IPopoverHoverTriggerProps, IPopoverFocusTriggerChildProps, IPopoverFocusTriggerProps, IPopoverBeforeHook, } from '../popover'; import { exposePopover } from '../popover/withPopover'; import getArrowPosition from '../utils/getArrowPosition'; import Action, { IPopActionCallback } from './Action'; import noop from '../utils/noop'; const { Trigger } = Popover; // eslint-disable-next-line @typescript-eslint/ban-types export interface IPopNoneTriggerProps extends IPopoverTriggerProps, IPopCommonProps { trigger: 'none'; } export interface IPopClickTriggerProps< Props extends IPopoverClickTriggerChildProps > extends IPopoverClickTriggerProps, IPopCommonProps { trigger: 'click'; } export interface IPopHoverTriggerProps< Props extends IPopoverHoverTriggerChildProps > extends IPopoverHoverTriggerProps, IPopCommonProps { trigger: 'hover'; mouseEnterDelay?: number; mouseLeaveDelay?: number; fixMouseEventsOnDisabledChildren?: boolean; } export interface IPopFocusTriggerProps< Props extends IPopoverFocusTriggerChildProps > extends IPopoverFocusTriggerProps, IPopCommonProps { trigger: 'focus'; } export type PopPositions = | 'left-top' | 'left-center' | 'left-bottom' | 'right-top' | 'right-center' | 'right-bottom' | 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'auto-bottom-center' | 'auto-bottom-left' | 'auto-bottom-right' | 'auto-top-center' | 'auto-top-left' | 'auto-top-right'; export interface IPopCommonProps { content: React.ReactNode; position?: PopPositions | IPositionFunction; cushion?: number; centerArrow?: boolean; header?: React.ReactNode; onShow?: () => void; onClose?: () => void; onBeforeShow?: IPopoverBeforeHook; onBeforeClose?: IPopoverBeforeHook; type?: 'primary' | 'default' | 'danger' | 'success'; visible?: boolean; onVisibleChange?: (visible: boolean) => void; onPositionUpdated?: () => void; onPositionReady?: () => void; className?: string; style?: React.CSSProperties; containerSelector?: string; onConfirm?: IPopActionCallback; onCancel?: IPopActionCallback; confirmText?: string; cancelText?: string; } export type IPopProps = | IPopNoneTriggerProps | IPopClickTriggerProps | IPopHoverTriggerProps | IPopFocusTriggerProps; export interface IPopState { confirmPending: boolean; cancelPending: boolean; } export class Pop extends Component { static defaultProps = { trigger: 'none', position: 'top-center', cushion: 10, type: 'primary', mouseLeaveDelay: 200, mouseEnterDelay: 200, containerSelector: 'body', }; static withPop = exposePopover('pop'); private popoverRef = createRef(); private isUnmounted = false; state = { confirmPending: false, cancelPending: false, }; changePending = ( key: keyof IPopState, pending: boolean, callback?: () => void ) => { if (this.isUnmounted) { return; } this.setState( { [key]: pending, } as any, callback ); }; adjustPosition() { const popover = this.popoverRef.current; if (popover) { popover.adjustPosition(); } } getWrappedPopover() { return this.popoverRef.current; } renderTrigger() { const { props } = this; switch (props.trigger) { case 'click': return ( {props.children} ); case 'hover': return ( {props.children} ); case 'focus': return {props.children}; case 'none': return {props.children}; default: throw new Error('Pop trigger not assigned'); } } componentWillUnmount() { this.isUnmounted = true; } render() { const { className, style, trigger, visible, onShow, onClose, position, cushion, header, content, centerArrow, onBeforeClose, onBeforeShow, onPositionUpdated, onPositionReady, containerSelector, onCancel, onConfirm, confirmText, cancelText, type, } = this.props; const hasHeader = header != null; let { onVisibleChange } = this.props; if (trigger === 'none') { onVisibleChange = onVisibleChange || noop; } const { confirmPending, cancelPending } = this.state; const closePending = confirmPending || cancelPending; return ( {this.renderTrigger()} {hasHeader &&
{header}
}
{content} {(onCancel || onConfirm) && ( )}
); } } export default Pop;