@@ -195,23 +195,39 @@ class Combobox extends React.Component {
195195
196196 // eslint-disable-next-line react/no-unsafe
197197 UNSAFE_componentWillReceiveProps ( nextProps ) {
198- if ( ! nextProps . value || isEqual ( nextProps . value , this . state . currentValue ) ) {
199- return ;
198+ if ( nextProps . value && ! isEqual ( nextProps . value , this . state . currentValue ) ) {
199+ this . setValue ( nextProps . value ) ;
200200 }
201- this . setValue ( nextProps . value ) ;
202201
203202 if ( nextProps . options !== undefined ) {
204203 // If the options have an id property, we use that to compare them and determine if they changed, if not
205204 // we'll use the whole options array.
206- if ( has ( nextProps . options , '0.id' ) ) {
207- if (
208- nextProps . options . some ( ( option , index ) => ! isEqual ( option . id , this . props . options [ index ] . id ) ) ||
209- nextProps . alreadySelectedOptions . some ( ( alreadySelectedOption , index ) => ! isEqual ( alreadySelectedOption . id , this . props . alreadySelectedOptions [ index ] . id ) )
210- ) {
205+ const optionsChanged = has ( nextProps . options , '0.id' )
206+ ? nextProps . options . some ( ( option , index ) => ! isEqual ( option . id , this . props . options [ index ] && this . props . options [ index ] . id ) )
207+ : ! isEqual ( nextProps . options , this . props . options ) ;
208+
209+ // Check if alreadySelectedOptions changed - compare by id if available, otherwise by value or full comparison
210+ const hasAlreadySelectedId = nextProps . alreadySelectedOptions && nextProps . alreadySelectedOptions . length > 0 && has ( nextProps . alreadySelectedOptions [ 0 ] , 'id' ) ;
211+
212+ const alreadySelectedChanged = hasAlreadySelectedId
213+ ? nextProps . alreadySelectedOptions . length !== this . props . alreadySelectedOptions . length ||
214+ nextProps . alreadySelectedOptions . some ( ( alreadySelectedOption , index ) => {
215+ const prevOption = this . props . alreadySelectedOptions [ index ] ;
216+ return ! prevOption || ! isEqual ( alreadySelectedOption . id , prevOption . id ) ;
217+ } )
218+ : ! isEqual ( nextProps . alreadySelectedOptions , this . props . alreadySelectedOptions ) ;
219+
220+ if ( optionsChanged || alreadySelectedChanged ) {
221+ // If only alreadySelectedOptions changed and dropdown is open, just update options without resetting
222+ if ( ! optionsChanged && alreadySelectedChanged && this . state . isDropdownOpen ) {
223+ const { currentValue} = this . state ;
224+ this . setState ( ( ) => ( {
225+ options : this . getTruncatedOptions ( currentValue , nextProps . alreadySelectedOptions ) ,
226+ } ) ) ;
227+ } else {
228+ // Options changed or dropdown is closed - do full reset
211229 this . reset ( false , nextProps . options , nextProps . alreadySelectedOptions ) ;
212230 }
213- } else if ( ! isEqual ( nextProps . options , this . props . options ) || ! isEqual ( nextProps . alreadySelectedOptions , this . props . alreadySelectedOptions ) ) {
214- this . reset ( false , nextProps . options , nextProps . alreadySelectedOptions ) ;
215231 }
216232 }
217233
@@ -484,12 +500,14 @@ class Combobox extends React.Component {
484500 // Get the divider index if we have one
485501 const findDivider = ( option ) => option . divider ;
486502 const dividerIndex = this . options . findIndex ( findDivider ) ;
503+
487504 // Split into two arrays everything before and after the divider (if the divider does not exist then we'll return a single array)
488505 const splitOptions = dividerIndex ? [ this . options . slice ( 0 , dividerIndex + 1 ) , this . options . slice ( dividerIndex + 1 ) ] : [ this . options ] ;
489506
490- const formatOption = ( option ) => ( {
507+ const formatOption = ( option , index ) => ( {
491508 focused : false ,
492- isSelected : option . selected && ( isEqual ( option . value , currentValue ) || ! ! alreadySelected . find ( ( item ) => item . value === option . value ) ) ,
509+ isSelected : ( option . selected && isEqual ( option . value , currentValue ) ) || ! ! alreadySelected . find ( ( item ) => item . value === option . value ) ,
510+ originalIndex : index , // Added for stable sorting
493511 ...option ,
494512 } ) ;
495513
@@ -498,18 +516,29 @@ class Combobox extends React.Component {
498516 if ( o . showLast ) {
499517 return 2 ;
500518 }
501-
502519 return o . isSelected && this . props . alwaysShowSelectedOnTop ? 0 : 1 ;
503520 } ;
504521
505522 // Take each array and format it, sort it, and move selected items to top (if applicable)
506- const formatOptions = ( array ) =>
507- array
508- . map ( formatOption )
509- . sort ( ( a , b ) => sortByOption ( a ) - sortByOption ( b ) )
523+ const formatOptions = ( array , arrayStartIndex ) => {
524+ return array
525+ . map ( ( option , index ) => formatOption ( option , arrayStartIndex + index ) )
526+ . sort ( ( a , b ) => {
527+ const sortDiff = sortByOption ( a ) - sortByOption ( b ) ;
528+ // If sort priority is the same, preserve original order using originalIndex
529+ return sortDiff !== 0 ? sortDiff : a . originalIndex - b . originalIndex ;
530+ } )
510531 . slice ( 0 , this . props . maxItemsToShow ) ;
532+ } ;
511533
512- const truncatedOptions = splitOptions . map ( formatOptions ) . flat ( ) ;
534+ let cumulativeIndex = 0 ;
535+ const truncatedOptions = splitOptions
536+ . map ( ( array ) => {
537+ const result = formatOptions ( array , cumulativeIndex ) ;
538+ cumulativeIndex += array . length ;
539+ return result ;
540+ } )
541+ . flat ( ) ;
513542
514543 if ( ! truncatedOptions . length ) {
515544 truncatedOptions . push ( {
0 commit comments