8000 refactor(CPopover): move from `FC` to `forwardRef` · mattstern31/coreui-react@e7fc7fe · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e7fc7fe

Browse files
committed
refactor(CPopover): move from FC to forwardRef
1 parent 317dc92 commit e7fc7fe

File tree

1 file changed

+126
-117
lines changed

1 file changed

+126
-117
lines changed

packages/coreui-react/src/components/popover/CPopover.tsx

Lines changed: 126 additions & 117 deletions
< A851 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import React, { FC, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
1+
import React, { forwardRef, HTMLAttributes, ReactNode, useRef, useEffect, useState } from 'react'
22
import { createPortal } from 'react-dom'
33
import classNames from 'classnames'
44
import PropTypes from 'prop-types'
55
import { Transition } from 'react-transition-group'
66

7-
import { usePopper } from '../../hooks'
7+
import { useForkedRef, usePopper } from '../../hooks'
88
import { fallbackPlacementsPropType, triggerPropType } from '../../props'
99
import type { Placements, Triggers } from '../../types'
1010
import { getRTLPlacement, getTransitionDurationFromElement } from '../../utils'
@@ -68,132 +68,141 @@ export interface CPopoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'tit
6868
visible?: boolean
6969
}
7070

71-
export const CPopover: FC<CPopoverProps> = ({
72-
children,
73-
animation = true,
74-
className,
75-
content,
76-
delay = 0,
77-
fallbackPlacements = ['top', 'right', 'bottom', 'left'],
78-
offset = [0, 8],
79-
onHide,
80-
onShow,
81-
placement = 'top',
82-
title,
83-
trigger = 'click',
84-
visible,
85-
...rest
86-
}) => {
87-
const popoverRef = useRef(null)
88-
const togglerRef = useRef(null)
89-
const { initPopper, destroyPopper } = usePopper()
90-
const [_visible, setVisible] = useState(visible)
71+
export const CPopover = forwardRef<HTMLDivElement, CPopoverProps>(
72+
(
73+
{
74+
children,
75+
animation = true,
76+
className,
77+
content,
78+
delay = 0,
79+
fallbackPlacements = ['top', 'right', 'bottom', 'left'],
80+
offset = [0, 8],
81+
onHide,
82+
onShow,
83+
placement = 'top',
84+
title,
85+
trigger = 'click',
86+
visible,
87+
...rest
88+
},
89+
ref,
90+
) => {
91+
const popoverRef = useRef(null)
92+
const togglerRef = useRef(null)
93+
const forkedRef = useForkedRef(ref, popoverRef)
9194

92-
const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
95+
const { initPopper, destroyPopper } = usePopper()
96+
const [_visible, setVisible] = useState(visible)
9397

94-
const popperConfig = {
95-
modifiers: [
96-
{
97-
name: 'arrow',
98-
options: {
99-
element: '.popover-arrow',
98+
const _delay = typeof delay === 'number' ? { show: delay, hide: delay } : delay
99+
100+
const popperConfig = {
101+
mo 341A difiers: [
102+
{
103+
name: 'arrow',
104+
options: {
105+
element: '.popover-arrow',
106+
},
100107
},
101-
},
102-
{
103-
name: 'flip',
104-
options: {
105-
fallbackPlacements: fallbackPlacements,
108+
{
109+
name: 'flip',
110+
options: {
111+
fallbackPlacements: fallbackPlacements,
112+
},
106113
},
107-
},
108-
{
109-
name: 'offset',
110-
options: {
111-
offset: offset,
114+
{
115+
name: 'offset',
116+
options: {
117+
offset: offset,
118+
},
112119
},
113-
},
114-
],
115-
placement: getRTLPlacement(placement, togglerRef.current),
116-
}
120+
],
121+
placement: getRTLPlacement(placement, togglerRef.current),
122+
}
117123

118-
useEffect(() => {
119-
setVisible(visible)
120-
}, [visible])
124+
useEffect(() => {
125+
setVisible(visible)
126+
}, [visible])
121127

122-
useEffect(() => {
123-
if (_visible && togglerRef.current && popoverRef.current) {
124-
initPopper(togglerRef.current, popoverRef.current, popperConfig)
125-
}
128+
useEffect(() => {
129+
if (_visible && togglerRef.current && popoverRef.current) {
130+
initPopper(toggler 10000 Ref.current, popoverRef.current, popperConfig)
131+
}
126132

127-
return () => {
128-
destroyPopper()
129-
}
130-
}, [_visible])
133+
return () => {
134+
destroyPopper()
135+
}
136+
}, [_visible])
131137

132-
const toggleVisible = (visible: boolean) => {
133-
if (visible) {
134-
setTimeout(() => setVisible(true), _delay.show)
135-
return
136-
}
138+
const toggleVisible = (visible: boolean) => {
139+
if (visible) {
140+
setTimeout(() => setVisible(true), _delay.show)
141+
return
142+
}
137143

138-
setTimeout(() => setVisible(false), _delay.hide)
139-
}
144+
setTimeout(() => setVisible(false), _delay.hide)
145+
}
140146

141-
return (
142-
<>
143-
{React.cloneElement(children as React.ReactElement<any>, {
144-
ref: togglerRef,
145-
...((trigger === 'click' || trigger.includes('click')) && {
146-
onClick: () => toggleVisible(!_visible),
147-
}),
148-
...((trigger === 'focus' || trigger.includes('focus')) && {
149-
onFocus: () => toggleVisible(true),
150-
onBlur: () => toggleVisible(false),
151-
}),
152-
...((trigger === 'hover' || trigger.includes('hover')) && {
153-
onMouseEnter: () => toggleVisible(true),
154-
onMouseLeave: () => toggleVisible(false),
155-
}),
156-
})}
157-
{typeof window !== 'undefined' &&
158-
createPortal(
159-
<Transition
160-
in={_visible}
161-
mountOnEnter
162-
nodeRef={popoverRef}
163-
onEnter={onShow}
164-
onExit={onHide}
165-
timeout={{
166-
enter: 0,
167-
exit: popoverRef.current ? getTransitionDurationFromElement(popoverRef.current) + 50 : 200,
168-
}}
169-
unmountOnExit
170-
>
171-
{(state) => (
172-
<div
173-
className={classNames(
174-
'popover',
175-
'bs-popover-auto',
176-
{
177-
fade: animation,
178-
show: state === 'entered',
179-
},
180-
className,
181-
)}
182-
ref={popoverRef}
183-
role="tooltip"
184-
{...rest}
185-
>
186-
<div className="popover-arrow"></div>
187-
<div className="popover-header">{title}</div>
188-
<div className="popover-body">{content}</div>
189-
</div>
190-
)}
191-
</Transition>,
192-
document.body,
193-
)}
194-
</>
195-
)
196-
}
147+
return (
148+
<>
149+
{React.cloneElement(children as React.ReactElement<any>, {
150+
ref: togglerRef,
151+
...((trigger === 'click' || trigger.includes('click')) && {
152+
onClick: () => toggleVisible(!_visible),
153+
}),
154+
...((trigger === 'focus' || trigger.includes('focus')) && {
155+
onFocus: () => toggleVisible(true),
156+
onBlur: () => toggleVisible(false),
157+
}),
158+
...((trigger === 'hover' || trigger.includes('hover')) && {
159+
onMouseEnter: () => toggleVisible(true),
160+
onMouseLeave: () => toggleVisible(false),
161+
}),
162+
})}
163+
{typeof window !== 'undefined' &&
164+
createPortal(
165+
<Transition
166+
in={_visible}
167+
mountOnEnter
168+
nodeRef={popoverRef}
169+
onEnter={onShow}
170+
onExit={onHide}
171+
timeout={{
172+
enter: 0,
173+
exit: popoverRef.current
174+
? getTransitionDurationFromElement(popoverRef.current) + 50
175+
: 200,
176+
}}
177+
unmountOnExit
178+
>
179+
{(state) => (
180+
<div
181+
className={classNames(
182+
'popover',
183+
'bs-popover-auto',
184+
{
185+
fade: animation,
186+
show: state === 'entered',
187+
},
188+
className,
189+
)}
190+
ref={forkedRef}
191+
role="tooltip"
192+
{...rest}
193+
>
194+
<div className="popover-arrow"></div>
195+
<div className="popover-header">{title}</div>
196+
<div className="popover-body">{content}</div>
197+
</div>
198+
)}
199+
</Transition>,
200+
document.body,
201+
)}
202+
</>
203+
)
204+
},
205+
)
197206

198207
CPopover.propTypes = {
199208
animation: PropTypes.bool,

0 commit comments

Comments
 (0)
0