import { ReferenceObject } from "popper.js"; import React, { RefObject, HTMLProps } from "react"; import { isMobile } from "../_util/is-mobile"; import { useOutsideClick } from "../_util/use-outside-click"; export type Trigger = (props: TriggerProps) => JSX.Element; export type TriggerWithProps

= [ (triggerProps: P & TriggerProps) => JSX.Element, P ]; export interface TriggerProps { overlayElementRef: RefObject; childrenElementRef: RefObject; visible: boolean; setVisible: (visible: boolean, delay?: number) => Promise; openDelay: number; closeDelay: number; render: (renderProps: TriggerRenderProps) => JSX.Element; } export interface TriggerRenderProps { overlayProps: HTMLProps; childrenProps: HTMLProps; referenceElement?: ReferenceObject; } export const buildinTriggers = { click: ClickTrigger as Trigger, hover: HoverTrigger as Trigger, focus: FocusTrigger as Trigger, empty: EmptyTrigger as Trigger, contextMenu: ContextMenuTrigger as Trigger, }; /** * 点击的时候打开 * * - children 上绑定 onClick 事件,点击时打开 * - children 上添加 useClickOutside Hook,外部点击时关闭,并排除 overlayElement */ export function ClickTrigger({ childrenElementRef, overlayElementRef, visible, setVisible, openDelay = 0, closeDelay = 0, render, }: TriggerProps) { const { listen, ignoreProps } = useOutsideClick([ childrenElementRef, overlayElementRef, ]); listen(() => visible && setVisible(false, closeDelay)); return render({ overlayProps: ignoreProps, childrenProps: { onClick: () => setVisible(!visible, openDelay), }, }); } ClickTrigger.displayName = "ClickTrigger"; /** * 右键点击的时候打开 * * - children 上绑定 onContextMenu 事件,点击时打开 * - children 上添加 useClickOutside Hook,外部点击时关闭,并排除 overlayElement */ export function ContextMenuTrigger({ childrenElementRef, overlayElementRef, visible, setVisible, openDelay = 0, closeDelay = 0, render, }: TriggerProps) { const { listen, ignoreProps } = useOutsideClick([ childrenElementRef, overlayElementRef, ]); listen(() => visible && setVisible(false, closeDelay)); return render({ overlayProps: ignoreProps, childrenProps: { onContextMenu: e => { e.preventDefault(); setVisible(!visible, openDelay); }, }, }); } ContextMenuTrigger.displayName = "ContextMenuTrigger"; /** * 鼠标经过的时候打开 */ export function HoverTrigger(props: TriggerProps) { if (isMobile) { return ; } const { setVisible, openDelay = 50, closeDelay = 100, render } = props; const commonProps: HTMLProps = { onMouseEnter: () => setVisible(true, openDelay), onMouseLeave: () => setVisible(false, closeDelay), }; return render({ overlayProps: commonProps, childrenProps: commonProps, }); } HoverTrigger.displayName = "HoverTrigger"; export function FocusTrigger({ setVisible, openDelay = 50, closeDelay = 100, render, }: TriggerProps) { const commonProps: HTMLProps = { onFocus: () => setVisible(true, openDelay), onBlur: () => setVisible(false, closeDelay), }; return render({ overlayProps: { ...commonProps, tabIndex: 1000 }, childrenProps: commonProps, }); } FocusTrigger.displayName = "FocusTrigger"; /** * 表示空的触发交互 */ export function EmptyTrigger(props: TriggerProps) { return props.render({ overlayProps: {}, childrenProps: {} }); } EmptyTrigger.displayName = "EmptyTrigger";