11import React , { FC , ReactNode , useRef , useState } from 'react'
22import { createPortal } from 'react-dom'
3- import PropTypes from 'prop-types'
3+
44import classNames from 'classnames'
5- import { Manager , Popper , Reference } from 'react-popper'
5+ import PropTypes from 'prop-types'
6+ import { usePopper } from 'react-popper'
67import { Transition } from 'react-transition-group'
78
8- // import { CPopoverContent } from './CPopoverContent'
99import { Triggers , triggerPropType } from '../Types'
1010
1111export interface CPopoverProps {
@@ -50,10 +50,10 @@ export interface CPopoverProps {
5050export const CPopover : FC < CPopoverProps > = ( {
5151 children,
5252 content,
53- placement = 'top' ,
5453 offset = [ 0 , 8 ] ,
5554 onHide,
5655 onShow,
56+ placement = 'top' ,
5757 title,
5858 trigger = 'click' ,
5959 visible,
@@ -62,6 +62,22 @@ export const CPopover: FC<CPopoverProps> = ({
6262 const [ _visible , setVisible ] = useState ( visible )
6363 const popoverRef = useRef ( )
6464
65+ const [ referenceElement , setReferenceElement ] = useState ( null )
66+ const [ popperElement , setPopperElement ] = useState < HTMLDivElement | null > ( null )
67+ const [ arrowElement , setArrowElement ] = useState < HTMLDivElement | null > ( null )
68+ const { styles, attributes } = usePopper ( referenceElement , popperElement , {
69+ modifiers : [
70+ { name : 'arrow' , options : { element : arrowElement } } ,
71+ {
72+ name : 'offset' ,
73+ options : {
74+ offset : offset ,
75+ } ,
76+ } ,
77+ ] ,
78+ placement : placement ,
79+ } )
80+
6581 const getTransitionClass = ( state : string ) => {
6682 return state === 'entering'
6783 ? 'fade'
@@ -73,94 +89,71 @@ export const CPopover: FC<CPopoverProps> = ({
7389 }
7490
7591 return (
76- < Manager >
77- < >
78- < Reference >
79- { ( { ref } ) =>
80- React . cloneElement ( children , {
81- ref : ref ,
82- ...( ( trigger === 'click' || trigger . includes ( 'click' ) ) && {
83- onClick : ( ) => setVisible ( ! _visible ) ,
84- } ) ,
85- ...( ( trigger === 'focus' || trigger . includes ( 'focus' ) ) && {
86- onFocus : ( ) => setVisible ( true ) ,
87- onBlur : ( ) => setVisible ( false ) ,
88- } ) ,
89- ...( ( trigger === 'hover' || trigger . includes ( 'hover' ) ) && {
90- onMouseEnter : ( ) => setVisible ( true ) ,
91- onMouseLeave : ( ) => setVisible ( false ) ,
92- } ) ,
93- } )
94- }
95- </ Reference >
96- { typeof window !== 'undefined' &&
97- createPortal (
98- < Transition
99- in = { _visible }
100- mountOnEnter
101- nodeRef = { popoverRef }
102- onEnter = { onShow }
103- onExit = { onHide }
104- timeout = { {
105- enter : 0 ,
106- exit : 200 ,
107- } }
108- unmountOnExit
109- >
110- { ( state ) => {
111- const transitionClass = getTransitionClass ( state )
112- return (
113- < Popper
114- placement = { placement }
115- modifiers = { [
116- {
117- name : 'offset' ,
118- options : {
119- offset : offset ,
120- } ,
121- } ,
122- ] }
123- >
124- { ( { arrowProps, style, ref } ) => (
125- < div
126- className = { classNames (
127- `popover bs-popover-${
128- placement === 'left'
129- ? 'start'
130- : placement === 'right'
131- ? 'end'
132- : placement
133- } `,
134- transitionClass ,
135- ) }
136- ref = { ref }
137- role = "tooltip"
138- style = { style }
139- { ...rest }
140- >
141- < div className = "popover-arrow" { ...arrowProps } > </ div >
142- < div className = "popover-header" > { title } </ div >
143- < div className = "popover-body" > { content } </ div >
144- </ div >
145- ) }
146- </ Popper >
147- )
148- } }
149- </ Transition > ,
150- document . body ,
151- ) }
152- </ >
153- </ Manager >
92+ < >
93+ { React . cloneElement ( children , {
94+ ref : setReferenceElement ,
95+ ...( ( trigger === 'click' || trigger . includes ( 'click' ) ) && {
96+ onClick : ( ) => setVisible ( ! _visible ) ,
97+ } ) ,
98+ ...( ( trigger === 'focus' || trigger . includes ( 'focus' ) ) && {
99+ onFocus : ( ) => setVisible ( true ) ,
100+ onBlur : ( ) => setVisible ( false ) ,
101+ } ) ,
102+ ...( ( trigger === 'hover' || trigger . includes ( 'hover' ) ) && {
103+ onMouseEnter : ( ) => setVisible ( true ) ,
104+ onMouseLeave : ( ) => setVisible ( false ) ,
105+ } ) ,
106+ } ) }
107+ { typeof window !== 'undefined' &&
108+ createPortal (
109+ < Transition
110+ in = { _visible }
111+ mountOnEnter
112+ nodeRef = { popoverRef }
113+ onEnter = { onShow }
114+ onExit = { onHide }
115+ timeout = { {
116+ enter : 0 ,
117+ exit : 200 ,
118+ } }
119+ unmountOnExit
120+ >
121+ { ( state ) => {
122+ const transitionClass = getTransitionClass ( state )
123+ return (
124+ < div
125+ className = { classNames (
126+ `popover bs-popover-${
127+ placement === 'left' ? 'start' : placement === 'right' ? 'end' : placement
128+ } `,
129+ transitionClass ,
130+ ) }
131+ ref = { setPopperElement }
132+ role = "tooltip"
133+ style = { styles . popper }
134+ { ...attributes . popper }
135+ { ...rest }
136+ >
137+ < div className = "popover-arrow" style = { styles . arrow } ref = { setArrowElement } > </ div >
138+ < div className = "popover-header" > { title } </ div >
139+ < div className = "popover-body" > { content } </ div >
140+ </ div >
141+ )
142+ } }
143+ </ Transition > ,
144+ document . body ,
145+ ) }
146+ </ >
154147 )
155148}
156149
157150CPopover . propTypes = {
158151 children : PropTypes . any ,
159152 content : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . node ] ) ,
160- placement : PropTypes . oneOf ( [ 'auto' , 'top' , 'right' , 'bottom' , 'left' ] ) ,
161153 offset : PropTypes . any , // TODO: find good proptype
162154 onHide : PropTypes . func ,
163155 onShow : PropTypes . func ,
156+ placement : PropTypes . oneOf ( [ 'auto' , 'top' , 'right' , 'bottom' , 'left' ] ) ,
164157 title : PropTypes . oneOfType ( [ PropTypes . string , PropTypes . node ] ) ,
165158 trigger : triggerPropType ,
166159 visible : PropTypes . bool ,
0 commit comments