@@ -33,6 +33,9 @@ function xor(a: boolean, b: boolean): boolean {
3333 return ( a || b ) && ! ( a && b ) ;
3434}
3535
36+ type TagBoxItem = string | number | any ;
37+ type SelectedItemsMap = Record < string , TagBoxItem > ;
38+
3639const TAGBOX_TAG_DATA_KEY = 'dxTagData' ;
3740const TAGBOX_TAG_DISPLAY_VALUE = 'dxTagDisplayValue' ;
3841
@@ -51,13 +54,13 @@ const TEXTEDITOR_INPUT_CONTAINER_CLASS = 'dx-texteditor-input-container';
5154
5255const TAGBOX_MOUSE_WHEEL_DELTA_MULTIPLIER = - 0.3 ;
5356
54- export interface TagBoxProperties extends Omit < Properties ,
55- 'onCustomItemCreating'
56- | 'onItemClick' | 'onSelectionChanged '
57- | 'onOpened ' | 'onClosed '
58- | 'onChange' | 'onCopy ' | 'onCut' | 'onEnterKey' | 'onFocusIn' | 'onFocusOut' | 'onInput' | 'onKeyDown' | 'onKeyUp' | 'onPaste '
59- | 'onValueChanged ' | 'validationMessagePosition ' | 'onContentReady ' | 'onDisposing ' | 'onOptionChanged ' | 'onInitialized' > {
60-
57+ export interface TagBoxProperties extends Omit <
58+ Properties ,
59+ 'onCustomItemCreating '
60+ | 'onItemClick ' | 'onSelectionChanged '
61+ | 'onOpened ' | 'onClosed '
62+ | 'onChange ' | 'onCopy ' | 'onCut ' | 'onEnterKey ' | 'onFocusIn ' | 'onFocusOut' | 'onInput' | 'onKeyDown' | 'onKeyUp' | 'onPaste'
63+ | 'onValueChanged' | 'validationMessagePosition' | 'onContentReady' | 'onDisposing' | 'onOptionChanged' | 'onInitialized' > {
6164}
6265
6366class TagBox <
@@ -856,7 +859,7 @@ class TagBox<
856859 // @ts -expect-error ts-error
857860 const isListItemsLoaded = ! ! listSelectedItems && this . _list . _dataController . isLoaded ( ) ;
858861 const selectedItems = listSelectedItems || this . option ( 'selectedItems' ) ;
859- // @ts -expect-error ts-error
862+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
860863 const clientFilterFunction = creator . getLocalFilter ( this . _valueGetter ) ;
861864 // @ts -expect-error ts-error
862865 const filteredItems = selectedItems . filter ( clientFilterFunction ) ;
@@ -903,13 +906,13 @@ class TagBox<
903906 _createTagsData ( values , filteredItems ) {
904907 const items = [ ] ;
905908 const cache = { } ;
906- // @ts -expect-error ts-error
909+ // @ts -expect-error _valueGetterExpr is injected by DataExpressionMixin
907910 const isValueExprSpecified = this . _valueGetterExpr ( ) === 'this' ;
908911 const { acceptCustomValue } = this . option ( ) ;
909912 const filteredValues = { } ;
910913
911914 filteredItems . forEach ( ( filteredItem ) => {
912- // @ts -expect-error
915+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
913916 const filteredItemValue = isValueExprSpecified ? JSON . stringify ( filteredItem ) : this . _valueGetter ( filteredItem ) ;
914917
915918 filteredValues [ filteredItemValue ] = filteredItem ;
@@ -963,7 +966,7 @@ class TagBox<
963966 return item ;
964967 }
965968 const selectedItem = this . option ( 'selectedItem' ) ;
966- // @ts -expect-error
969+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
967970 const customItem = this . _valueGetter ( selectedItem ) === value ? selectedItem : value ;
968971
969972 return customItem ;
@@ -1042,7 +1045,10 @@ class TagBox<
10421045 this . _selectedItems = this . _getItemsFromPlain ( this . _valuesToUpdate ) ;
10431046
10441047 if ( this . _selectedItems . length === this . _valuesToUpdate . length ) {
1045- this . _tagsToRender = this . _selectedItems ;
1048+ this . _tagsToRender = this . _sortSelectedItemsByValues (
1049+ this . _selectedItems ,
1050+ this . _valuesToUpdate ,
1051+ ) ;
10461052 this . _renderTagsImpl ( ) ;
10471053 isPlainDataUsed = true ;
10481054 d . resolve ( ) ;
@@ -1109,6 +1115,45 @@ class TagBox<
11091115 return selectedItems ;
11101116 }
11111117
1118+ _shouldUseClickOrderForTags ( values : TagBox [ '_valuesToUpdate' ] ) : boolean {
1119+ const { maxDisplayedTags, showMultiTagOnly } = this . option ( ) ;
1120+
1121+ return ! showMultiTagOnly
1122+ && isDefined ( maxDisplayedTags )
1123+ && values . length > maxDisplayedTags ;
1124+ }
1125+
1126+ _sortSelectedItemsByValues (
1127+ selectedItems : TagBoxItem [ ] ,
1128+ values : TagBoxItem [ ] ,
1129+ ) : TagBoxItem [ ] {
1130+ if ( ! this . _shouldUseClickOrderForTags ( values ) || ! selectedItems . length ) {
1131+ return selectedItems ;
1132+ }
1133+ // @ts -expect-error _valueGetterExpr is injected by DataExpressionMixin
1134+ const isValueExprDefault = this . _valueGetterExpr ( ) === 'this' ;
1135+
1136+ const mappedSelectedItems = selectedItems . reduce < SelectedItemsMap > ( ( result , item ) => {
1137+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
1138+ const itemValue = isValueExprDefault ? JSON . stringify ( item ) : this . _valueGetter ( item ) ;
1139+ result [ itemValue ] = item ;
1140+
1141+ return result ;
1142+ } , { } ) ;
1143+
1144+ const selectedByOrderItems : TagBoxItem [ ] = values . reduce ( ( result , currentValue ) => {
1145+ const normalizedValue = isValueExprDefault ? JSON . stringify ( currentValue ) : currentValue ;
1146+ const item = mappedSelectedItems [ normalizedValue ] ;
1147+ if ( isDefined ( item ) ) {
1148+ result . push ( item ) ;
1149+ }
1150+
1151+ return result ;
1152+ } , [ ] ) ;
1153+
1154+ return selectedByOrderItems ;
1155+ }
1156+
11121157 _filterSelectedItems ( plainItems , values ) {
11131158 const selectedItems = plainItems . filter ( ( dataItem ) => {
11141159 let currentValue ;
@@ -1176,8 +1221,7 @@ class TagBox<
11761221
11771222 _renderTagsElements ( items ) : void {
11781223 const $multiTag = this . _multiTagRequired ( ) && this . _renderMultiTag ( this . _input ( ) ) ;
1179- const showMultiTagOnly = this . option ( 'showMultiTagOnly' ) ;
1180- const maxDisplayedTags = this . option ( 'maxDisplayedTags' ) ;
1224+ const { showMultiTagOnly, maxDisplayedTags } = this . option ( ) ;
11811225
11821226 items . forEach ( ( item , index ) => {
11831227 // @ts -expect-error ts-error
@@ -1202,7 +1246,7 @@ class TagBox<
12021246 const $tags = this . _tagElements ( ) ;
12031247
12041248 const selectedItems = this . option ( 'selectedItems' ) ?? [ ] ;
1205- // @ts -expect-error ts-error
1249+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
12061250 const values = selectedItems . map ( ( item ) => this . _valueGetter ( item ) ) ;
12071251
12081252 each ( $tags , ( _ , tag ) => {
@@ -1248,7 +1292,7 @@ class TagBox<
12481292 }
12491293
12501294 _renderTag ( item , $input ) : void {
1251- // @ts -expect-error ts-error
1295+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
12521296 const value = this . _valueGetter ( item ) ;
12531297
12541298 if ( ! isDefined ( value ) ) {
@@ -1395,12 +1439,12 @@ class TagBox<
13951439 const value = this . _getValue ( ) . slice ( ) ;
13961440
13971441 each ( e . removedItems || [ ] , ( _ , removedItem ) => {
1398- // @ts -expect-error ts-error
1442+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
13991443 this . _removeTag ( value , this . _valueGetter ( removedItem ) ) ;
14001444 } ) ;
14011445
14021446 each ( e . addedItems || [ ] , ( _ , addedItem ) => {
1403- // @ts -expect-error ts-error
1447+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
14041448 this . _addTag ( value , this . _valueGetter ( addedItem ) ) ;
14051449 } ) ;
14061450
@@ -1558,7 +1602,7 @@ class TagBox<
15581602 }
15591603
15601604 const dataController = this . _dataController ;
1561- // @ts -expect-error ts-error
1605+ // @ts -expect-error _valueGetterExpr is injected by DataExpressionMixin
15621606 const valueGetterExpr = this . _valueGetterExpr ( ) ;
15631607
15641608 if ( isString ( valueGetterExpr ) && valueGetterExpr !== 'this' ) {
@@ -1580,14 +1624,14 @@ class TagBox<
15801624
15811625 _dataSourceFilterExpr ( ) {
15821626 const filter = [ ] ;
1583- // @ts -expect-error
1627+ // @ts -expect-error _valueGetterExpr is injected by DataExpressionMixin
15841628 this . _getValue ( ) . forEach ( ( value ) => filter . push ( [ '!' , [ this . _valueGetterExpr ( ) , value ] ] ) ) ;
15851629
15861630 return filter ;
15871631 }
15881632
15891633 _dataSourceFilterFunction ( itemData ) {
1590- // @ts -expect-error ts-error
1634+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
15911635 const itemValue = this . _valueGetter ( itemData ) ;
15921636 let result = true ;
15931637
@@ -1636,7 +1680,7 @@ class TagBox<
16361680
16371681 return this
16381682 . _getPlainItems ( this . _list . option ( 'selectedItems' ) )
1639- // @ts -expect-error
1683+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
16401684 . map ( ( item ) => this . _valueGetter ( item ) ) ;
16411685 }
16421686
@@ -1695,15 +1739,15 @@ class TagBox<
16951739 }
16961740
16971741 const previousItemsValuesMap = previousItems . reduce ( ( map , item ) => {
1698- // @ts -expect-error ts-error
1742+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
16991743 const value = this . _valueGetter ( item ) ;
17001744 map [ value ] = item ;
17011745 return map ;
17021746 } , { } ) ;
17031747
17041748 const addedItems = [ ] ;
17051749 newItems . forEach ( ( item ) => {
1706- // @ts -expect-error ts-error
1750+ // @ts -expect-error _valueGetter is injected by DataExpressionMixin
17071751 const value = this . _valueGetter ( item ) ;
17081752 if ( ! previousItemsValuesMap [ value ] ) {
17091753 addedItems . push ( item as never ) ;
0 commit comments