@@ -43,13 +43,15 @@ type Props = {
4343 onChange : Function ,
4444 /** Function will be called with the user selected option (even on deselect or when the option was previously selected) */
4545 onOptionSelect ?: Function ,
46+ /** Function that allows custom rendering of select field options. When not provided the component will only render the option's displayText by default */
47+ optionRenderer ?: ( option : SelectOptionProp ) => React . Node ,
4648 /** List of options (displayText, value) */
4749 options : Array < SelectOptionProp > ,
4850 /** The select button text shown when no options are selected. */
4951 placeholder ?: string | React . Element < any > ,
5052 /** The currently selected option values (can be empty) */
5153 selectedValues : Array < SelectOptionValueProp > ,
52- /** Array of ordered indices indicating where to insert separators (ex. index 2 means insert a separator after option 2) */
54+ /** Array of ordered indices indicating where to insert separators (ex. index 2 means insert a separator after option 2) */
5355 separatorIndices : Array < number > ,
5456 /** The select button text (by default, component will use comma separated list of all selected option displayText) */
5557 title ?: string | React . Element < any > ,
@@ -59,6 +61,7 @@ type State = {
5961 activeItemID : ?string ,
6062 activeItemIndex : number ,
6163 isOpen : boolean ,
64+ shouldScrollIntoView : boolean ,
6265} ;
6366
6467class BaseSelectField extends React . Component < Props , State > {
@@ -80,20 +83,26 @@ class BaseSelectField extends React.Component<Props, State> {
8083 activeItemID : null ,
8184 activeItemIndex : - 1 ,
8285 isOpen : false ,
86+ shouldScrollIntoView : false ,
8387 } ;
8488 }
8589
86- setActiveItem = ( index : number ) => {
87- this . setState ( { activeItemIndex : index } ) ;
90+ setActiveItem = ( index : number , shouldScrollIntoView ? : boolean = true ) => {
91+ this . setState ( { activeItemIndex : index , shouldScrollIntoView } ) ;
8892 if ( index === - 1 ) {
8993 this . setActiveItemID ( null ) ;
9094 }
9195 } ;
9296
9397 setActiveItemID = ( id : ?string ) => {
98+ const { shouldScrollIntoView } = this . state ;
9499 const itemEl = id ? document . getElementById ( id ) : null ;
95- this . setState ( { activeItemID : id } ) ;
96- scrollIntoView ( itemEl ) ;
100+
101+ this . setState ( { activeItemID : id , shouldScrollIntoView : false } , ( ) => {
102+ if ( shouldScrollIntoView ) {
103+ scrollIntoView ( itemEl , { block : 'nearest' } ) ;
104+ }
105+ } ) ;
97106 } ;
98107
99108 selectFieldID: string ;
@@ -304,7 +313,7 @@ class BaseSelectField extends React.Component<Props, State> {
304313 } ;
305314
306315 renderSelectOptions = ( ) => {
307- const { options, selectedValues, separatorIndices } = this . props ;
316+ const { optionRenderer , options, selectedValues, separatorIndices } = this . props ;
308317 const { activeItemIndex } = this . state ;
309318
310319 const selectOptions = options . map < React . Element < typeof DatalistItem | 'li' >> ( ( item , index ) => {
@@ -321,12 +330,8 @@ class BaseSelectField extends React.Component<Props, State> {
321330
322331 this . selectOption ( index ) ;
323332 } ,
324- /* preventDefault on mousedown so blur doesn't happen before click */
325- onMouseDown : event => {
326- event . preventDefault ( ) ;
327- } ,
328333 onMouseEnter : ( ) => {
329- this . setActiveItem ( index ) ;
334+ this . setActiveItem ( index , false ) ;
330335 } ,
331336 setActiveItemID : this . setActiveItemID ,
332337 } ;
@@ -342,7 +347,7 @@ class BaseSelectField extends React.Component<Props, State> {
342347 < div className = "select-option-check-icon" >
343348 { isSelected ? < IconCheck height = { 16 } width = { 16 } /> : null }
344349 </ div >
345- { displayText }
350+ { optionRenderer ? optionRenderer ( item ) : displayText }
346351 </ DatalistItem >
347352 ) ;
348353 /* eslint-enable react/jsx-key */
@@ -385,7 +390,14 @@ class BaseSelectField extends React.Component<Props, State> {
385390 'is-visible' : isOpen ,
386391 } ) }
387392 >
388- < ul className = "overlay" id = { this . selectFieldID } role = "listbox" { ...listboxProps } >
393+ < ul
394+ className = "overlay"
395+ id = { this . selectFieldID }
396+ role = "listbox"
397+ // preventDefault on mousedown so blur doesn't happen before click
398+ onMouseDown = { event => event . preventDefault ( ) }
399+ { ...listboxProps }
400+ >
389401 { this . renderSelectOptions ( ) }
390402 </ ul >
391403 </ div >
0 commit comments