3
3
import PropTypes from 'prop-types'
4
4
import { Component , cloneElement } from 'react'
5
5
import { isForwardRef } from 'react-is'
6
+ import memoize from 'fast-memoize'
6
7
import { isPreact , isReactNative } from './is.macro'
7
8
import setA11yStatus from './set-a11y-status'
8
9
import * as stateChangeTypes from './stateChangeTypes'
@@ -833,10 +834,8 @@ class Downshift extends Component {
833
834
! ! this . props . environment . document . activeElement &&
834
835
! ! this . props . environment . document . activeElement . dataset &&
835
836
this . props . environment . document . activeElement . dataset . toggle &&
836
- ( this . _rootNode &&
837
- this . _rootNode . contains (
838
- this . props . environment . document . activeElement ,
839
- ) )
837
+ this . _rootNode &&
838
+ this . _rootNode . contains ( this . props . environment . document . activeElement )
840
839
if ( ! this . isMouseDown && ! downshiftButtonIsActive ) {
841
840
this . reset ( { type : stateChangeTypes . blurInput } )
842
841
}
@@ -869,6 +868,49 @@ class Downshift extends Component {
869
868
}
870
869
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ MENU
871
870
871
+ getItemPropsEventHandlers = memoize (
872
+ ( index , item , onClick , onPress , onMouseMove , onMouseDown ) => {
873
+ const onSelectKey = isReactNative
874
+ ? /* istanbul ignore next (react-native) */ 'onPress'
875
+ : 'onClick'
876
+ const customClickHandler = isReactNative
877
+ ? /* istanbul ignore next (react-native) */ onPress
878
+ : onClick
879
+
880
+ return {
881
+ // onMouseMove is used over onMouseEnter here. onMouseMove
882
+ // is only triggered on actual mouse movement while onMouseEnter
883
+ // can fire on DOM changes, interrupting keyboard navigation
884
+ onMouseMove : callAllEventHandlers ( onMouseMove , ( ) => {
885
+ if ( index === this . getState ( ) . highlightedIndex ) {
886
+ return
887
+ }
888
+ this . setHighlightedIndex ( index , {
889
+ type : stateChangeTypes . itemMouseEnter ,
890
+ } )
891
+
892
+ // We never want to manually scroll when changing state based
893
+ // on `onMouseMove` because we will be moving the element out
894
+ // from under the user which is currently scrolling/moving the
895
+ // cursor
896
+ this . avoidScrolling = true
897
+ this . internalSetTimeout ( ( ) => ( this . avoidScrolling = false ) , 250 )
898
+ } ) ,
899
+ onMouseDown : callAllEventHandlers ( onMouseDown , event => {
900
+ // This prevents the activeElement from being changed
901
+ // to the item so it can remain with the current activeElement
902
+ // which is a more common use case.
903
+ event . preventDefault ( )
904
+ } ) ,
905
+ [ onSelectKey ] : callAllEventHandlers ( customClickHandler , ( ) => {
906
+ this . selectItemAtIndex ( index , {
907
+ type : stateChangeTypes . clickItem ,
908
+ } )
909
+ } ) ,
910
+ }
911
+ } ,
912
+ )
913
+
872
914
/////////////////////////////// ITEM
873
915
getItemProps = ( {
874
916
onMouseMove,
@@ -888,44 +930,14 @@ class Downshift extends Component {
888
930
this . items [ index ] = item
889
931
}
890
932
891
- const onSelectKey = isReactNative
892
- ? /* istanbul ignore next (react-native) */ 'onPress'
893
- : 'onClick'
894
- const customClickHandler = isReactNative
895
- ? /* istanbul ignore next (react-native) */ onPress
896
- : onClick
897
-
898
- const enabledEventHandlers = {
899
- // onMouseMove is used over onMouseEnter here. onMouseMove
900
- // is only triggered on actual mouse movement while onMouseEnter
901
- // can fire on DOM changes, interrupting keyboard navigation
902
- onMouseMove : callAllEventHandlers ( onMouseMove , ( ) => {
903
- if ( index === this . getState ( ) . highlightedIndex ) {
904
- return
905
- }
906
- this . setHighlightedIndex ( index , {
907
- type : stateChangeTypes . itemMouseEnter ,
908
- } )
909
-
910
- // We never want to manually scroll when changing state based
911
- // on `onMouseMove` because we will be moving the element out
912
- // from under the user which is currently scrolling/moving the
913
- // cursor
914
- this . avoidScrolling = true
915
- this . internalSetTimeout ( ( ) => ( this . avoidScrolling = false ) , 250 )
916
- } ) ,
917
- onMouseDown : callAllEventHandlers ( onMouseDown , event => {
918
- // This prevents the activeElement from being changed
919
- // to the item so it can remain with the current activeElement
920
- // which is a more common use case.
921
- event . preventDefault ( )
922
- } ) ,
923
- [ onSelectKey ] : callAllEventHandlers ( customClickHandler , ( ) => {
924
- this . selectItemAtIndex ( index , {
925
- type : stateChangeTypes . clickItem ,
926
- } )
927
- } ) ,
928
- }
933
+ const enabledEventHandlers = this . getItemPropsEventHandlers (
934
+ index ,
935
+ item ,
936
+ onClick ,
937
+ onMouseDown ,
938
+ onMouseMove ,
939
+ onPress ,
940
+ )
929
941
930
942
// Passing down the onMouseDown handler to prevent redirect
931
943
// of the activeElement if clicking on disabled items
0 commit comments