1import React from 'react';
2import { Placement } from '@popperjs/core';
3import { PopoverContent } from './Tooltip';
4
5// This API allows popovers to update Popper's position when e.g. popover content changes
6// updatePopperPosition is delivered to content by react-popper
7
8export interface UsingPopperProps {
9  show?: boolean;
10  placement?: TooltipPlacement;
11  content: PopoverContent;
12  children: JSX.Element;
13}
14
15export type TooltipPlacement =
16  | 'auto-start'
17  | 'auto'
18  | 'auto-end'
19  | 'top-start'
20  | 'top'
21  | 'top-end'
22  | 'right-start'
23  | 'right'
24  | 'right-end'
25  | 'bottom-end'
26  | 'bottom'
27  | 'bottom-start'
28  | 'left-end'
29  | 'left'
30  | 'left-start';
31
32type PopperControllerRenderProp = (
33  showPopper: () => void,
34  hidePopper: () => void,
35  popperProps: {
36    show: boolean;
37    placement: Placement;
38    content: PopoverContent;
39  }
40) => JSX.Element;
41
42interface Props {
43  placement?: Placement;
44  content: PopoverContent;
45  className?: string;
46  children: PopperControllerRenderProp;
47  hideAfter?: number;
48}
49
50interface State {
51  show: boolean;
52}
53
54class PopoverController extends React.Component<Props, State> {
55  private hideTimeout: any;
56  state = { show: false };
57
58  showPopper = () => {
59    clearTimeout(this.hideTimeout);
60    this.setState({ show: true });
61  };
62
63  hidePopper = () => {
64    this.hideTimeout = setTimeout(() => {
65      this.setState({ show: false });
66    }, this.props.hideAfter);
67  };
68
69  render() {
70    const { children, content, placement = 'auto' } = this.props;
71    const { show } = this.state;
72
73    return children(this.showPopper, this.hidePopper, {
74      show,
75      placement,
76      content,
77    });
78  }
79}
80
81export { PopoverController };
82