All files / src/popover trigger.tsx

66.67% Statements 10/15
75% Branches 6/8
50% Functions 5/10
71.43% Lines 10/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99                                              59x                                           4x   4x   4x                                 128x 1x 1x   128x                       1x       1x                        
import { ReferenceObject } from "popper.js";
import { RefObject, HTMLProps, ComponentType } from "react";
import { useOutsideClick } from "../_util/use-outside-click";
 
export type Trigger = ComponentType<TriggerProps>;
export type TriggerWithProps<P = any> = [ComponentType<P & TriggerProps>, P];
 
export interface TriggerProps {
  overlayElementRef: RefObject<HTMLElement>;
  childrenElementRef: RefObject<HTMLElement>;
  visible: boolean;
  setVisible: (visible: boolean, delay?: number) => Promise<boolean>;
  openDelay: number;
  closeDelay: number;
  render: (renderProps: TriggerRenderProps) => JSX.Element;
}
 
export interface TriggerRenderProps {
  overlayProps: HTMLProps<HTMLElement>;
  childrenProps: HTMLProps<HTMLElement>;
  referenceElement?: ReferenceObject;
}
 
export const buildinTriggers = {
  click: ClickTrigger as Trigger,
  hover: HoverTrigger as Trigger,
  focus: FocusTrigger as Trigger,
  empty: EmptyTrigger as Trigger,
};
 
/**
 * 点击的时候打开
 *
 * - children 上绑定 onClick 事件,点击时打开
 * - children 上添加 useClickOutside Hook,外部点击时关闭,并排除 overlayElement
 */
export function ClickTrigger({
  childrenElementRef,
  overlayElementRef,
  visible,
  setVisible,
  openDelay = 0,
  closeDelay = 0,
  render,
}: TriggerProps) {
  const { listen } = useOutsideClick([childrenElementRef, overlayElementRef]);
 
  listen(() => visible && setVisible(false, closeDelay));
 
  return render({
    overlayProps: {},
    childrenProps: {
      onClick: () => setVisible(!visible, openDelay),
    },
  });
}
 
/**
 * 鼠标经过的时候打开
 */
export function HoverTrigger({
  setVisible,
  openDelay = 50,
  closeDelay = 100,
  render,
}: TriggerProps) {
  const commonProps = {
    onMouseEnter: () => setVisible(true, openDelay),
    onMouseLeave: () => setVisible(false, closeDelay),
  };
  return render({
    overlayProps: commonProps,
    childrenProps: commonProps,
  });
}
 
export function FocusTrigger({
  setVisible,
  openDelay = 50,
  closeDelay = 100,
  render,
}: TriggerProps) {
  const commonProps = {
    onFocus: () => setVisible(true, openDelay),
    onBlur: () => setVisible(false, closeDelay),
  };
  return render({
    overlayProps: { ...commonProps, tabIndex: 1000 },
    childrenProps: commonProps,
  });
}
 
/**
 * 表示空的触发交互
 */
export function EmptyTrigger(props: TriggerProps) {
  return props.render({ overlayProps: {}, childrenProps: {} });
}