@skbkontur/react-ui 6.4.4 → 6.4.6-b246a.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [6.4.5](https://github.com/skbkontur/retail-ui/compare/@skbkontur/react-ui@6.4.4...@skbkontur/react-ui@6.4.5) (2026-10-21)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **TokenInput:** deselect tokens upon shift selection ([c830f52](https://github.com/skbkontur/retail-ui/commit/c830f52cc691e7e1c63bcfbcff3bd4819b1d157b))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [6.4.4](https://github.com/skbkontur/retail-ui/compare/@skbkontur/react-ui@6.4.3...@skbkontur/react-ui@6.4.4) (2026-10-13)
7
18
 
8
19
 
@@ -155,6 +155,7 @@ export declare class TokenInput<T = string> extends React.PureComponent<TokenInp
155
155
  private textHelper;
156
156
  private wrapper;
157
157
  private scrollContainerRef;
158
+ private scrollContainerInnerRef;
158
159
  getRootNode: TGetRootNode;
159
160
  private setRootNode;
160
161
  private memoizedTokens;
@@ -238,6 +239,7 @@ export declare class TokenInput<T = string> extends React.PureComponent<TokenInp
238
239
  private selectInputText;
239
240
  private handleWrapperKeyDown;
240
241
  private handleWrapperArrows;
242
+ private scrollToSelection;
241
243
  private handleWrapperArrowsWithoutShift;
242
244
  private handleWrapperArrowsWithShift;
243
245
  private handleValueChange;
@@ -148,6 +148,7 @@ var TokenInput = /** @class */ (function (_super) {
148
148
  _this.textHelper = null;
149
149
  _this.wrapper = null;
150
150
  _this.scrollContainerRef = React.createRef();
151
+ _this.scrollContainerInnerRef = React.createRef();
151
152
  _this.memoizedTokens = new Map();
152
153
  _this.menuNavigatedByUser = false;
153
154
  _this.requestId = 0;
@@ -199,6 +200,7 @@ var TokenInput = /** @class */ (function (_super) {
199
200
  _c));
200
201
  var placeholder = selectedItems.length === 0 && !inputValue ? _this.props.placeholder : '';
201
202
  var inputNode = (React.createElement(TokenView, { size: _this.size, className: _this.cx((_d = {},
203
+ _d[_this.styles.inputWrapperDisabled()] = !!disabled,
202
204
  // input растягивается на всю ширину чтобы placeholder не обрезался
203
205
  _d[_this.styles.inputPlaceholderWrapper()] = Boolean(placeholder),
204
206
  _d)), hideCloseButton: Boolean(placeholder) },
@@ -211,7 +213,7 @@ var TokenInput = /** @class */ (function (_super) {
211
213
  _this.renderTokensEnd(interactive),
212
214
  _this.isEditingMode ? (React.createElement(TokenView, { size: _this.size },
213
215
  React.createElement("span", { className: _this.styles.reservedInput(theme) }, reservedInputValue))) : null));
214
- var container = maxHeight && !isMobileFooter ? (React.createElement(ScrollContainer, { className: _this.styles.inputPlaceholderScrollWrapper(), scrollRef: _this.scrollContainerRef, maxHeight: maxHeight, showScrollBar: "always", style: { width: '100%' } }, inner)) : (inner);
216
+ var container = maxHeight && !isMobileFooter ? (React.createElement(ScrollContainer, { ref: _this.scrollContainerRef, className: _this.styles.inputPlaceholderScrollWrapper(), scrollRef: _this.scrollContainerInnerRef, maxHeight: maxHeight, showScrollBar: "always", style: { width: '100%' } }, inner)) : (inner);
215
217
  var labelStyle = {
216
218
  width: fieldWidth,
217
219
  };
@@ -362,7 +364,7 @@ var TokenInput = /** @class */ (function (_super) {
362
364
  var _a;
363
365
  // Имитируем поведение label, когда задан maxHeight.
364
366
  if (_this.props.maxHeight &&
365
- e.target === _this.scrollContainerRef.current &&
367
+ e.target === _this.scrollContainerInnerRef.current &&
366
368
  (_this.state.activeTokens.length !== 0 || !_this.state.inFocus)) {
367
369
  _this.dispatch({ type: 'BLUR' });
368
370
  _this.dispatch({ type: 'SET_FOCUS_IN' });
@@ -576,7 +578,7 @@ var TokenInput = /** @class */ (function (_super) {
576
578
  var index = _this.getAvailableTokenIndex(_this.getProps().selectedItems.length);
577
579
  var itemNew = _this.getProps().selectedItems[index];
578
580
  if (itemNew) {
579
- _this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: [itemNew] });
581
+ _this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: [itemNew] }, _this.scrollToSelection);
580
582
  }
581
583
  }
582
584
  break;
@@ -638,33 +640,82 @@ var TokenInput = /** @class */ (function (_super) {
638
640
  var selectedItems = _this.getProps().selectedItems;
639
641
  var activeTokens = _this.state.activeTokens;
640
642
  var activeItemIndex = selectedItems.indexOf(activeTokens[0]);
643
+ var isRightDirection = isKeyArrowRight(e);
641
644
  var newItemIndex = _this.getAvailableTokenIndex(activeItemIndex, isKeyArrowLeft(e));
642
- var isLeftEdge = activeItemIndex === 0 && isKeyArrowLeft(e);
643
- var isRightEdge = newItemIndex === selectedItems.length && isKeyArrowRight(e);
645
+ var isLeftEdge = newItemIndex === activeItemIndex && isKeyArrowLeft(e);
646
+ var isRightEdge = newItemIndex === selectedItems.length && isRightDirection;
647
+ if (!e.shiftKey && activeTokens.length > 1) {
648
+ var activeIndices = activeTokens.map(function (item) { return selectedItems.indexOf(item); });
649
+ var edgeIndex = isRightDirection ? Math.max.apply(Math, activeIndices) : Math.min.apply(Math, activeIndices);
650
+ var isRightEdgeOfSelection = isRightDirection && _this.getAvailableTokenIndex(edgeIndex, false) === selectedItems.length;
651
+ var nextActiveTokens = isRightEdgeOfSelection ? [] : [selectedItems[edgeIndex]];
652
+ _this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: nextActiveTokens }, _this.scrollToSelection);
653
+ return;
654
+ }
644
655
  if (!e.shiftKey && activeTokens.length === 1) {
645
656
  _this.handleWrapperArrowsWithoutShift(isLeftEdge, isRightEdge, newItemIndex);
646
657
  }
647
658
  else {
648
- _this.handleWrapperArrowsWithShift(isLeftEdge, isRightEdge, newItemIndex);
659
+ _this.handleWrapperArrowsWithShift(isLeftEdge, isRightEdge, isRightDirection, newItemIndex, activeItemIndex);
649
660
  }
650
661
  };
662
+ _this.scrollToSelection = function () {
663
+ var _a, _b;
664
+ var activeItemIndex = _this.getProps().selectedItems.indexOf(_this.state.activeTokens[0]);
665
+ // TextWidthHelper is the first child; each token renders one root element.
666
+ var node = activeItemIndex < 0
667
+ ? _this.input
668
+ : (_a = _this.scrollContainerInnerRef.current) === null || _a === void 0 ? void 0 : _a.children.item(activeItemIndex + 1);
669
+ (_b = _this.scrollContainerRef.current) === null || _b === void 0 ? void 0 : _b.scrollTo(node);
670
+ };
651
671
  _this.handleWrapperArrowsWithoutShift = function (isLeftEdge, isRightEdge, newItemIndex) {
652
672
  if (isRightEdge) {
653
- _this.dispatch({ type: 'REMOVE_ALL_ACTIVE_TOKENS' }, function () { var _a; return (_a = _this.input) === null || _a === void 0 ? void 0 : _a.focus(); });
673
+ _this.dispatch({ type: 'REMOVE_ALL_ACTIVE_TOKENS' }, _this.scrollToSelection);
654
674
  }
655
675
  else if (!isLeftEdge) {
656
676
  _this.dispatch({
657
677
  type: 'SET_ACTIVE_TOKENS',
658
678
  payload: [_this.getProps().selectedItems[newItemIndex]],
659
- });
679
+ }, _this.scrollToSelection);
660
680
  }
661
681
  };
662
- _this.handleWrapperArrowsWithShift = function (isLeftEdge, isRightEdge, newItemIndex) {
663
- if (!isLeftEdge && !isRightEdge) {
664
- var itemNew_1 = _this.getProps().selectedItems[newItemIndex];
665
- var itemsNew = __spreadArray([itemNew_1], _this.state.activeTokens.filter(function (item) { return !_this.isEqual(item, itemNew_1); }), true);
666
- _this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: itemsNew });
682
+ _this.handleWrapperArrowsWithShift = function (isLeftEdge, isRightEdge, isRightDirection, newItemIndex, activeItemIndex) {
683
+ var selectedItems = _this.getProps().selectedItems;
684
+ var activeTokens = _this.state.activeTokens;
685
+ var isActive = function (item) {
686
+ return activeTokens.some(function (activeItem) { return _this.isEqual(activeItem, item); });
687
+ };
688
+ var currentItem = selectedItems[activeItemIndex];
689
+ var selectionWithoutCurrentItem = function () { return activeTokens.filter(function (item) { return !_this.isEqual(item, currentItem); }); };
690
+ if (isLeftEdge || isRightEdge) {
691
+ /** Когда стрелка упирается в край, дальше двигаться нельзя.
692
+ * Проверяем ближайший доступный токен в обратном направлении,
693
+ * пропуская disabled токены.
694
+ Если текущий токен выделен, а сосед не выделен или его нет,
695
+ снимаем выделение с текущего токена.
696
+ Если сосед тоже выделен, сохраняем выделение. */
697
+ var searchNeighborToLeft = isRightDirection;
698
+ var neighborIndex = _this.getAvailableTokenIndex(activeItemIndex, searchNeighborToLeft);
699
+ var neighborItem = selectedItems[neighborIndex];
700
+ var hasNoNeighbor = neighborIndex === activeItemIndex;
701
+ var canRemoveCurrentItem = isActive(currentItem) && (hasNoNeighbor || !isActive(neighborItem));
702
+ if (canRemoveCurrentItem) {
703
+ _this.dispatch({
704
+ type: 'SET_ACTIVE_TOKENS',
705
+ payload: selectionWithoutCurrentItem(),
706
+ }, _this.scrollToSelection);
707
+ }
708
+ return;
667
709
  }
710
+ var targetItem = selectedItems[newItemIndex];
711
+ var isShrinkingSelection = isActive(targetItem);
712
+ var nextActiveTokens = isShrinkingSelection
713
+ ? selectionWithoutCurrentItem()
714
+ : __spreadArray([targetItem], activeTokens.filter(function (item) { return !_this.isEqual(item, targetItem); }), true);
715
+ _this.dispatch({
716
+ type: 'SET_ACTIVE_TOKENS',
717
+ payload: nextActiveTokens,
718
+ }, _this.scrollToSelection);
668
719
  };
669
720
  _this.handleValueChange = function (items) {
670
721
  _this.getProps().onValueChange(items);
@@ -898,16 +949,10 @@ var TokenInput = /** @class */ (function (_super) {
898
949
  var selectedItems = _this.getProps().selectedItems;
899
950
  var step = isDirectionLeft ? -1 : +1;
900
951
  var availableIndex = startIndex + step;
901
- while (_this.isTokenDisabled(availableIndex)) {
952
+ while (availableIndex >= 0 && availableIndex < selectedItems.length && _this.isTokenDisabled(availableIndex)) {
902
953
  availableIndex += step;
903
- if (availableIndex === selectedItems.length) {
904
- return availableIndex;
905
- }
906
- else if (availableIndex === -1) {
907
- return startIndex;
908
- }
909
954
  }
910
- return availableIndex;
955
+ return availableIndex < 0 ? startIndex : availableIndex;
911
956
  };
912
957
  return _this;
913
958
  }
@@ -1100,7 +1145,7 @@ var TokenInput = /** @class */ (function (_super) {
1100
1145
  configurable: true
1101
1146
  });
1102
1147
  TokenInput.prototype.isCursorVisibleForState = function (state) {
1103
- return state.inFocus && (this.isInputValueChanged || state.activeTokens.length === 0);
1148
+ return state.inFocus && (state.editingTokenIndex > -1 || state.activeTokens.length === 0);
1104
1149
  };
1105
1150
  TokenInput.prototype.getMenuItems = function () {
1106
1151
  if (this.state.requestStatus === ComboBoxRequestStatus.Failed) {
@@ -1261,7 +1306,7 @@ var TokenInput = /** @class */ (function (_super) {
1261
1306
  TokenInput.prototype.moveFocusToLastToken = function () {
1262
1307
  var items = this.getProps().selectedItems;
1263
1308
  if (this.state.inputValue === '' && items && items.length > 0) {
1264
- this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: items.slice(-1) });
1309
+ this.dispatch({ type: 'SET_ACTIVE_TOKENS', payload: items.slice(-1) }, this.scrollToSelection);
1265
1310
  }
1266
1311
  };
1267
1312
  var TokenInput_1;