8
8
*/
9
9
10
10
import * as React from 'react' ;
11
+ import { useState , useRef , useEffect , useMemo } from 'react' ;
11
12
import KeyCode from 'rc-util/lib/KeyCode' ;
12
13
import classNames from 'classnames' ;
13
14
import useMergedState from 'rc-util/lib/hooks/useMergedState' ;
@@ -316,17 +317,17 @@ export default function generateSelector<
316
317
delete domProps [ prop ] ;
317
318
} ) ;
318
319
319
- const containerRef = React . useRef < HTMLDivElement > ( null ) ;
320
- const triggerRef = React . useRef < RefTriggerProps > ( null ) ;
321
- const selectorRef = React . useRef < RefSelectorProps > ( null ) ;
322
- const listRef = React . useRef < RefOptionListProps > ( null ) ;
320
+ const containerRef = useRef < HTMLDivElement > ( null ) ;
321
+ const triggerRef = useRef < RefTriggerProps > ( null ) ;
322
+ const selectorRef = useRef < RefSelectorProps > ( null ) ;
323
+ const listRef = useRef < RefOptionListProps > ( null ) ;
323
324
324
325
/** Used for component focused management */
325
326
const [ mockFocused , setMockFocused , cancelSetMockFocused ] = useDelayReset ( ) ;
326
327
327
328
// Inner id for accessibility usage. Only work in client side
328
- const [ innerId , setInnerId ] = React . useState < string > ( ) ;
329
- React . useEffect ( ( ) => {
329
+ const [ innerId , setInnerId ] = useState < string > ( ) ;
330
+ useEffect ( ( ) => {
330
331
setInnerId ( `rc_select_${ getUUID ( ) } ` ) ;
331
332
} , [ ] ) ;
332
333
const mergedId = id || innerId ;
@@ -346,7 +347,7 @@ export default function generateSelector<
346
347
showSearch !== undefined ? showSearch : isMultiple || mode === 'combobox' ;
347
348
348
349
// ============================== Ref ===============================
349
- const selectorDomRef = React . useRef < HTMLDivElement > ( null ) ;
350
+ const selectorDomRef = useRef < HTMLDivElement > ( null ) ;
350
351
351
352
React . useImperativeHandle ( ref , ( ) => ( {
352
353
focus : selectorRef . current . focus ,
@@ -359,7 +360,7 @@ export default function generateSelector<
359
360
} ) ;
360
361
361
362
/** Unique raw values */
362
- const mergedRawValue = React . useMemo < RawValueType [ ] > (
363
+ const mergedRawValue = useMemo < RawValueType [ ] > (
363
364
( ) =>
364
365
toInnerValue ( mergedValue , {
365
366
labelInValue : mergedLabelInValue ,
@@ -368,14 +369,12 @@ export default function generateSelector<
368
369
[ mergedValue , mergedLabelInValue ] ,
369
370
) ;
370
371
/** We cache a set of raw values to speed up check */
371
- const rawValues = React . useMemo < Set < RawValueType > > ( ( ) => new Set ( mergedRawValue ) , [
372
- mergedRawValue ,
373
- ] ) ;
372
+ const rawValues = useMemo < Set < RawValueType > > ( ( ) => new Set ( mergedRawValue ) , [ mergedRawValue ] ) ;
374
373
375
374
// ============================= Option =============================
376
375
// Set by option list active, it will merge into search input when mode is `combobox`
377
- const [ activeValue , setActiveValue ] = React . useState < string > ( null ) ;
378
- const [ innerSearchValue , setInnerSearchValue ] = React . useState ( '' ) ;
376
+ const [ activeValue , setActiveValue ] = useState < string > ( null ) ;
377
+ const [ innerSearchValue , setInnerSearchValue ] = useState ( '' ) ;
379
378
let mergedSearchValue = innerSearchValue ;
380
379
if ( mode === 'combobox' && mergedValue !== undefined ) {
381
380
mergedSearchValue = mergedValue as string ;
@@ -385,7 +384,7 @@ export default function generateSelector<
385
384
mergedSearchValue = inputValue ;
386
385
}
387
386
388
- const mergedOptions = React . useMemo < OptionsType > ( ( ) : OptionsType => {
387
+ const mergedOptions = useMemo < OptionsType > ( ( ) : OptionsType => {
389
388
let newOptions = options ;
390
389
if ( newOptions === undefined ) {
391
390
newOptions = convertChildrenToData ( children ) ;
@@ -407,15 +406,15 @@ export default function generateSelector<
407
406
return newOptions || ( [ ] as OptionsType ) ;
408
407
} , [ options , children , mode , mergedValue ] ) ;
409
408
410
- const mergedFlattenOptions : FlattenOptionsType < OptionsType > = React . useMemo (
409
+ const mergedFlattenOptions : FlattenOptionsType < OptionsType > = useMemo (
411
410
( ) => flattenOptions ( mergedOptions , props ) ,
412
411
[ mergedOptions ] ,
413
412
) ;
414
413
415
414
const getValueOption = useCacheOptions ( mergedRawValue , mergedFlattenOptions ) ;
416
415
417
416
// Display options for OptionList
418
- const displayOptions = React . useMemo < OptionsType > ( ( ) => {
417
+ const displayOptions = useMemo < OptionsType > ( ( ) => {
419
418
if ( ! mergedSearchValue || ! mergedShowSearch ) {
420
419
return [ ...mergedOptions ] as OptionsType ;
421
420
}
@@ -434,19 +433,19 @@ export default function generateSelector<
434
433
return filteredOptions ;
435
434
} , [ mergedOptions , mergedSearchValue , mode , mergedShowSearch ] ) ;
436
435
437
- const displayFlattenOptions : FlattenOptionsType < OptionsType > = React . useMemo (
436
+ const displayFlattenOptions : FlattenOptionsType < OptionsType > = useMemo (
438
437
( ) => flattenOptions ( displayOptions , props ) ,
439
438
[ displayOptions ] ,
440
439
) ;
441
440
442
- React . useEffect ( ( ) => {
441
+ useEffect ( ( ) => {
443
442
if ( listRef . current && listRef . current . scrollTo ) {
444
443
listRef . current . scrollTo ( 0 ) ;
445
444
}
446
445
} , [ mergedSearchValue ] ) ;
447
446
448
447
// ============================ Selector ============================
449
- let displayValues = React . useMemo < DisplayLabelValueType [ ] > ( ( ) => {
448
+ let displayValues = useMemo < DisplayLabelValueType [ ] > ( ( ) => {
450
449
const tmpValues = mergedRawValue . map ( ( val : RawValueType ) => {
451
450
const valueOptions = getValueOption ( [ val ] ) ;
452
451
const displayValue = getLabeledValue ( val , {
@@ -675,14 +674,14 @@ export default function generateSelector<
675
674
} ;
676
675
677
676
// Close dropdown when disabled change
678
- React . useEffect ( ( ) => {
677
+ useEffect ( ( ) => {
679
678
if ( innerOpen && ! ! disabled ) {
680
679
setInnerOpen ( false ) ;
681
680
}
682
681
} , [ disabled ] ) ;
683
682
684
683
// Close will clean up single mode search text
685
- React . useEffect ( ( ) => {
684
+ useEffect ( ( ) => {
686
685
if ( ! mergedOpen && ! isMultiple && mode !== 'combobox' ) {
687
686
triggerSearch ( '' , false , false ) ;
688
687
}
@@ -747,7 +746,7 @@ export default function generateSelector<
747
746
748
747
// ========================== Focus / Blur ==========================
749
748
/** Record real focus status */
750
- const focusRef = React . useRef < boolean > ( false ) ;
749
+ const focusRef = useRef < boolean > ( false ) ;
751
750
752
751
const onContainerFocus : React . FocusEventHandler < HTMLElement > = ( ...args ) => {
753
752
setMockFocused ( true ) ;
@@ -793,7 +792,7 @@ export default function generateSelector<
793
792
} ;
794
793
795
794
const activeTimeoutIds : number [ ] = [ ] ;
796
- React . useEffect (
795
+ useEffect (
797
796
( ) => ( ) => {
798
797
activeTimeoutIds . forEach ( timeoutId => clearTimeout ( timeoutId ) ) ;
799
798
activeTimeoutIds . splice ( 0 , activeTimeoutIds . length ) ;
@@ -830,7 +829,7 @@ export default function generateSelector<
830
829
} ;
831
830
832
831
// ========================= Accessibility ==========================
833
- const [ accessibilityIndex , setAccessibilityIndex ] = React . useState < number > ( 0 ) ;
832
+ const [ accessibilityIndex , setAccessibilityIndex ] = useState < number > ( 0 ) ;
834
833
const mergedDefaultActiveFirstOption =
835
834
defaultActiveFirstOption !== undefined ? defaultActiveFirstOption : mode !== 'combobox' ;
836
835
@@ -843,7 +842,13 @@ export default function generateSelector<
843
842
} ;
844
843
845
844
// ============================= Popup ==============================
846
- const [ containerWidth , setContainerWidth ] = React . useState ( null ) ;
845
+ const [ containerWidth , setContainerWidth ] = useState ( null ) ;
846
+
847
+ const [ , forceUpdate ] = useState ( { } ) ;
848
+ // We need force update here since popup dom is render async
849
+ function onPopupMouseEnter ( ) {
850
+ forceUpdate ( { } ) ;
851
+ }
847
852
848
853
useLayoutEffect ( ( ) => {
849
854
if ( triggerOpen ) {
@@ -876,6 +881,7 @@ export default function generateSelector<
876
881
searchValue = { mergedSearchValue }
877
882
menuItemSelectedIcon = { menuItemSelectedIcon }
878
883
virtual = { virtual !== false && dropdownMatchSelectWidth !== false }
884
+ onMouseEnter = { onPopupMouseEnter }
879
885
/>
880
886
) ;
881
887
0 commit comments