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