1
- import React , { ElementType , forwardRef , HTMLAttributes , useEffect , useRef , useState } from 'react'
1
+ import React , {
2
+ ElementType ,
3
+ forwardRef ,
4
+ HTMLAttributes ,
5
+ useCallback ,
6
+ useEffect ,
7
+ useMemo ,
8
+ useRef ,
9
+ useState ,
10
+ } from 'react'
2
11
import PropTypes from 'prop-types'
3
12
import classNames from 'classnames'
4
13
import type { Options } from '@popperjs/core'
@@ -190,59 +199,63 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
190
199
ref
191
200
) => {
192
201
const dropdownRef = useRef < HTMLDivElement > ( null )
193
- const dropdownToggleRef = useRef < HTMLElement > ( null )
194
202
const dropdownMenuRef = useRef < HTMLDivElement | HTMLUListElement > ( null )
195
203
const forkedRef = useForkedRef ( ref , dropdownRef )
204
+ const [ dropdownToggleElement , setDropdownToggleElement ] = useState < HTMLElement | null > ( null )
196
205
const [ _visible , setVisible ] = useState ( visible )
197
206
const { initPopper, destroyPopper } = usePopper ( )
198
207
199
- const Component = variant === 'nav-item' ? 'li' : as
208
+ const dropdownToggleRef = useCallback ( ( node : HTMLElement | null ) => {
209
+ if ( node ) {
210
+ setDropdownToggleElement ( node )
211
+ }
212
+ } , [ ] )
200
213
201
- // Disable popper if responsive aligment is set.
202
- if ( typeof alignment === 'object' ) {
203
- popper = false
204
- }
214
+ const allowPopperUse = popper && typeof alignment !== 'object'
215
+ const Component = variant === 'nav-item' ? 'li' : as
205
216
206
217
const contextValues = {
207
218
alignment,
208
219
container,
209
220
dark,
210
- dropdownToggleRef,
211
221
dropdownMenuRef,
212
- popper,
222
+ dropdownToggleRef,
223
+ popper : allowPopperUse ,
213
224
portal,
214
225
variant,
215
226
visible : _visible ,
216
227
setVisible,
217
228
}
218
229
219
- const defaultPopperConfig = {
220
- modifiers : [
221
- {
222
- name : 'offset' ,
223
- options : {
224
- offset : offset ,
230
+ const computedPopperConfig : Partial < Options > = useMemo ( ( ) => {
231
+ const defaultPopperConfig = {
232
+ modifiers : [
233
+ {
234
+ name : 'offset' ,
235
+ options : {
236
+ offset,
237
+ } ,
225
238
} ,
226
- } ,
227
- ] ,
228
- placement : getPlacement ( placement , direction , alignment , isRTL ( dropdownMenuRef . current ) ) ,
229
- }
239
+ ] ,
240
+ placement : getPlacement ( placement , direction , alignment , isRTL ( dropdownMenuRef . current ) ) ,
241
+ }
230
242
231
- const computedPopperConfig : Partial < Options > = {
232
- ...defaultPopperConfig ,
233
- ...( typeof popperConfig === 'function' ? popperConfig ( defaultPopperConfig ) : popperConfig ) ,
234
- }
243
+ return {
244
+ ...defaultPopperConfig ,
245
+ ...( typeof popperConfig === 'function' ? popperConfig ( defaultPopperConfig ) : popperConfig ) ,
246
+ }
247
+ } , [ offset , placement , direction , alignment , popperConfig ] )
235
248
236
249
useEffect ( ( ) => {
237
250
setVisible ( visible )
238
251
} , [ visible ] )
239
252
240
253
useEffect ( ( ) => {
241
- const toggleElement = dropdownToggleRef . current
254
+ const toggleElement = dropdownToggleElement
242
255
const menuElement = dropdownMenuRef . current
243
256
244
257
if ( _visible && toggleElement && menuElement ) {
245
- if ( popper ) {
258
+ if ( allowPopperUse ) {
246
259
initPopper ( toggleElement , menuElement , computedPopperConfig )
247
260
}
248
261
@@ -257,7 +270,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
257
270
}
258
271
259
272
return ( ) => {
260
- if ( popper ) {
273
+ if ( allowPopperUse ) {
261
274
destroyPopper ( )
262
275
}
263
276
@@ -269,14 +282,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
269
282
270
283
onHide ?.( )
271
284
}
272
- } , [
273
- computedPopperConfig ,
274
- destroyPopper ,
275
- dropdownMenuRef ,
276
- dropdownToggleRef ,
277
- initPopper ,
278
- _visible ,
279
- ] )
285
+ } , [ dropdownToggleElement , _visible ] )
280
286
281
287
const handleKeydown = ( event : KeyboardEvent ) => {
282
288
if (
@@ -304,11 +310,11 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
304
310
}
305
311
306
312
const handleMouseUp = ( event : Event ) => {
307
- if ( ! dropdownToggleRef . current || ! dropdownMenuRef . current ) {
313
+ if ( ! dropdownToggleElement || ! dropdownMenuRef . current ) {
308
314
return
309
315
}
310
316
311
- if ( dropdownToggleRef . current . contains ( event . target as HTMLElement ) ) {
317
+ if ( dropdownToggleElement . contains ( event . target as HTMLElement ) ) {
312
318
return
313
319
}
314
320
0 commit comments