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";