@sberbusiness/triplex-next-mcp-server 1.50.0-beta → 1.53.1

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.
Files changed (74) hide show
  1. package/README.md +1 -0
  2. package/bundle/components/AlertProcess.md +6 -3
  3. package/bundle/components/AlertProcessSpoiler.md +216 -0
  4. package/bundle/components/Badge.md +4 -3
  5. package/bundle/components/ButtonDropdown.md +5 -3
  6. package/bundle/components/Carousel.md +671 -0
  7. package/bundle/components/CarouselExtended.md +7 -5
  8. package/bundle/components/CarouselIndicators.md +666 -0
  9. package/bundle/components/CarouselItem.md +579 -0
  10. package/bundle/components/CarouselNextButton.md +633 -0
  11. package/bundle/components/CarouselPrevButton.md +633 -0
  12. package/bundle/components/CarouselViewport.md +631 -0
  13. package/bundle/components/CheckboxTreeExtended.md +21 -7
  14. package/bundle/components/CheckboxTreeExtendedCheckbox.md +591 -0
  15. package/bundle/components/CheckboxTreeExtendedNode.md +577 -0
  16. package/bundle/components/Chip.md +1 -0
  17. package/bundle/components/ChipDatePicker.md +332 -0
  18. package/bundle/components/ChipDatePickerTarget.md +316 -0
  19. package/bundle/components/ChipMonthYearPicker.md +4 -3
  20. package/bundle/components/ChipMonthYearPickerTarget.md +318 -0
  21. package/bundle/components/ChipMultiselect.md +63 -73
  22. package/bundle/components/ChipSelect.md +385 -0
  23. package/bundle/components/ChipSelectTarget.md +388 -0
  24. package/bundle/components/ChipSuggest.md +10 -16
  25. package/bundle/components/ChipSuggestTarget.md +506 -0
  26. package/bundle/components/CollapsibleTree.md +2 -1
  27. package/bundle/components/CollapsibleTreeExtended.md +2 -1
  28. package/bundle/components/DateField.md +4 -2
  29. package/bundle/components/DatePickerExtended.md +16 -14
  30. package/bundle/components/DateRange.md +17 -10
  31. package/bundle/components/Dropdown.md +36 -63
  32. package/bundle/components/EmptyView.md +9 -4
  33. package/bundle/components/ExpandAnimation.md +9 -5
  34. package/bundle/components/FormField.md +1 -1
  35. package/bundle/components/ImageGallery.md +19 -52
  36. package/bundle/components/ImageGalleryExtended.md +123 -139
  37. package/bundle/components/ListItemControlsButtonDropdown.md +3 -2
  38. package/bundle/components/LoaderSmall.md +5 -4
  39. package/bundle/components/MonthYearRange.md +334 -0
  40. package/bundle/components/MultiselectField.md +81 -143
  41. package/bundle/components/Notification.md +2 -1
  42. package/bundle/components/NotificationGrouped.md +174 -0
  43. package/bundle/components/NumberField.md +259 -116
  44. package/bundle/components/OrderedList.md +149 -112
  45. package/bundle/components/Overlay.md +3 -2
  46. package/bundle/components/PageIndicators.md +306 -0
  47. package/bundle/components/Pagination.md +81 -3
  48. package/bundle/components/PaginationExtended.md +160 -0
  49. package/bundle/components/Portal.md +5 -2
  50. package/bundle/components/Puller.md +375 -0
  51. package/bundle/components/SMSField.md +277 -102
  52. package/bundle/components/SelectExtendedField.md +11 -7
  53. package/bundle/components/SelectField.md +7 -4
  54. package/bundle/components/SmartSpot.md +259 -0
  55. package/bundle/components/Step.md +2 -1
  56. package/bundle/components/Stepper.md +7 -7
  57. package/bundle/components/Suggest.md +7 -6
  58. package/bundle/components/SuggestField.md +8 -6
  59. package/bundle/components/TableBasic.md +12 -14
  60. package/bundle/components/Tooltip.md +9 -8
  61. package/bundle/guides/commits.md +4 -1
  62. package/bundle/guides/context.md +5 -5
  63. package/bundle/guides/stories.md +29 -21
  64. package/bundle/manifest.json +145 -13
  65. package/bundle/release-notes/1.50.0.mdx +4 -0
  66. package/bundle/release-notes/1.51.0.mdx +57 -0
  67. package/bundle/release-notes/1.52.0.mdx +55 -0
  68. package/bundle/release-notes/1.53.0.mdx +60 -0
  69. package/bundle/release-notes/1.54.0.mdx +45 -0
  70. package/bundle/release-notes/1.55.0.mdx +7 -0
  71. package/bundle/tokens.json +377 -222
  72. package/dist/index.js +39 -1
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
@@ -71,7 +71,7 @@ html-атрибуты корневого `<div>` — приходит из `Sele
71
71
  | `width` | `EDropdownWidth` | `EDropdownWidth.MIN_TARGET` | Умолчание задаёт компонент; потребитель может переопределить |
72
72
  | `size` | `EComponentSize` | из контекста | Умолчание — `size` мульти-списка; явный prop имеет приоритет |
73
73
  | `opened`, `setOpened`, `targetRef` | — | — | Обязательные, приходят из рендер-функции `children` |
74
- | `mobileViewProps` | `Omit<IDropdownMobileProps, "opened" \| "setOpened">` | — | Содержимое мобильной версии. Мобильная версия включена **всегда** — см. «Инварианты» |
74
+ | `pullerProps` | `Omit<IPullerProps, "opened" \| "setOpened">` | — | Содержимое мобильной версии. Мобильная версия включена **всегда** — см. «Инварианты» |
75
75
 
76
76
  Умолчания `focusTrapOptions`: `clickOutsideDeactivates: true`,
77
77
  `preventScroll: true`, `returnFocusOnDeactivate` — по признаку «блок открыт мышью».
@@ -118,7 +118,7 @@ MultiselectField.Divider_Color
118
118
  - Barrel `src/components/MultiselectField/index.ts` экспортирует только `MultiselectField` и `IMultiselectFieldProps`. Части выпадающего блока публичны **через статические свойства** (`MultiselectField.Dropdown.Header` и т.д.), а не через barrel. Их типы (`IMultiselectFieldDropdownProps`, `IMultiselectFieldDropdownContentProps`, ...) в публичный API не входят — выносить их туда без отдельного решения не нужно.
119
119
  - Статические свойства `MultiselectField.Target`, `MultiselectField.Dropdown` и `MultiselectFieldDropdown.Header` / `.Content` / `.Footer` — часть публичного API.
120
120
  - `MultiselectField.Target` — это `SelectExtendedFieldTarget` по ссылке (`MultiselectField.Target === SelectExtendedFieldTarget`). Правки в нём затрагивают также `SelectField` и `ChipSelect`.
121
- - **Мобильная версия выпадающего блока включена всегда.** `MultiselectFieldDropdown` передаёт в `Dropdown` объект `mobileViewProps` даже когда потребитель ничего не передал — для этого есть константа-заглушка `ALWAYS_MOBILE_VIEW_PROPS`: `Dropdown` выбирает мобильную версию по truthiness этого prop'а. Убрать объект — значит на мобильной ширине отрендерить десктопный блок вместо полноэкранного. Наблюдаемое поведение, покрыто unit-тестом «Should render the mobile version on mobile width even without mobileViewProps». Visual-стори этот инвариант не держат: `PlaygroundExample` передаёт `mobileViewProps` сам, поэтому скриншоты не упадут, даже если убрать объект из компонента.
121
+ - **Мобильная версия выпадающего блока включена всегда.** `MultiselectFieldDropdown` передаёт в `Dropdown` объект `pullerProps` даже когда потребитель ничего не передал — для этого есть константа-заглушка `ALWAYS_PULLER_PROPS`: `Dropdown` выбирает мобильную версию по truthiness этого prop'а. Убрать объект — значит на мобильной ширине отрендерить десктопный блок вместо шторки `Puller`. Наблюдаемое поведение, покрыто unit-тестом «Should render the mobile version on mobile width even without pullerProps». Visual-стори этот инвариант не держат: `PlaygroundExample` передаёт `pullerProps` сам, поэтому скриншоты не упадут, даже если убрать объект из компонента.
122
122
  - Признак «открыт мышью» живёт в `mouseUsedRef` в контексте: `MultiselectField` ставит его в `true` на `mousedown`, `MultiselectFieldDropdown` сбрасывает в `false`, когда блок закрылся. Он не state — переключение не должно вызывать перерисовку.
123
123
  - `size` из props раздаётся **только через контекст** и до поля выбора не доходит. Потребитель передаёт размер в `MultiselectField.Target` сам. Не «чинить» это без согласования: у поля и у выпадающего блока размеры могут различаться намеренно (в примерах фильтр внутри `Header` — размера SM при MD-поле).
124
124
  - `Header` / `Content` / `Footer` объявлены как `React.FC` и `ref` **не пробрасывают** — в отличие от `MultiselectField` и `MultiselectField.Dropdown`. Перевод их на `forwardRef` обратно совместим по props, но меняет тип компонента, поэтому делается отдельной задачей, а не попутно.
@@ -133,7 +133,7 @@ MultiselectField.Divider_Color
133
133
  - Пока выпадающий блок открыт, фокус заперт внутри него (`FocusTrap` из `focus-trap-react`). Содержимое обёрнуто в `<div role="presentation">` — обёртка нужна `FocusTrap` как единственный контейнер и не должна попадать в дерево доступности.
134
134
  - `clickOutsideDeactivates: true` — нажатие вне блока снимает перехват фокуса, после чего блок закрывает уже `SelectExtendedField` по своему `mousedown`-слушателю.
135
135
  - Возврат фокуса на поле при закрытии зависит от того, как блок открыли: после клавиатуры фокус возвращается, после мыши — нет (иначе клик вне блока повторно подсвечивал бы поле). Признак сбрасывается на каждое закрытие, поэтому следующее открытие оценивается заново.
136
- - `aria-haspopup="listbox"` и `aria-expanded` выставляет `MultiselectField.Target` (то есть `SelectExtendedFieldTarget`). Клавиши открытия поля — `Space`, `Enter`, `ArrowDown`, `ArrowUp`.
136
+ - `aria-haspopup="listbox"` и `aria-expanded` выставляет `MultiselectField.Target` (то есть `SelectExtendedFieldTarget`). Клавиши открытия поля — `Space`, `Enter`, `ArrowDown`, `ArrowUp`, только когда фокус на самом поле, а не на кнопке тега.
137
137
  - `Escape` закрывает блок из любого места страницы — слушатель `SelectExtendedField` висит на `window`.
138
138
  - Роли и клавиатурную навигацию **внутри** блока компонент не задаёт: содержимое произвольное (чекбоксы, дерево, кнопки), связь поля со списком (`aria-controls`, `aria-activedescendant`) и `aria-label` на элементах — забота потребителя.
139
139
  - Компонент не хардкодит текстовые строки: `fieldLabel`, `placeholder`, подписи кнопок и заголовок мобильной версии передаёт потребитель — библиотека мультиязычная.
@@ -164,7 +164,7 @@ MultiselectField.Divider_Color
164
164
 
165
165
  **Инфраструктура:**
166
166
 
167
- - `Dropdown` — выпадающее меню через `Portal`, позиционирование и полноэкранная мобильная версия.
167
+ - `Dropdown` — выпадающее меню через `Portal`, позиционирование и мобильная версия в нижней шторке `Puller`.
168
168
  - `LoaderScreen` — лоадер поверх содержимого при `Content loading`.
169
169
  - `FormField` — визуальный контейнер поля выбора и поля фильтра в `Header`.
170
170
  - `Tag` / `TagGroup`, `Checkbox`, `CheckboxTree` — типовое наполнение поля и выпадающего блока в примерах; частью компонента не являются.
@@ -189,7 +189,7 @@ MultiselectField.Divider_Color
189
189
  | `Example` | `ProductionExample.tsx` | Приближенный к продуктовому сценарий (в Storybook — «Example: production») |
190
190
  | `WithCheckboxTree` | `WithCheckboxTreeExample.tsx` | Дерево категорий вместо плоского списка чекбоксов (в Storybook — «Example: with CheckboxTree») |
191
191
  | `VisualTests` | `PlaygroundExample.tsx` | Скриншот-регрессия: поле с выбранным значением и раскрытый блок |
192
- | `VisualTestsNotFound` | `PlaygroundExample.tsx` | Скриншот-регрессия: пустой результат фильтра во всех размерах; на мобильной ширине — полноэкранная версия |
192
+ | `VisualTestsNotFound` | `PlaygroundExample.tsx` | Скриншот-регрессия: пустой результат фильтра во всех размерах; на мобильной ширине — шторка `Puller` |
193
193
 
194
194
  ---
195
195
 
@@ -199,6 +199,8 @@ MultiselectField.Divider_Color
199
199
  |---|---|
200
200
  | 2026-09-03 | Создан документ AI-ready для `MultiselectField` (TRI-61). |
201
201
  | 2026-09-03 | AI-рефакторинг (TRI-61): JSDoc на props, контексте и всех частях выпадающего блока; значение контекста обёрнуто в `useMemo`, обработчик `onMouseDown` — в `useCallback` (выигрыша в текущей связке нет: части приходят из рендер-функции `children` и пересоздаются каждый рендер независимо от контекста, — это страховка на случай `React.memo` у потребителя); объект-заглушка `mobileViewProps` вынесен в константу, чтобы инвариант «мобильная версия включена всегда» читался из самого выражения; unit-тесты разбиты по субкомпонентам и расширены с 1 до 45 кейсов. Публичный API и наблюдаемое поведение не изменены. |
202
+ | 2026-10-21 | **Breaking** (TRIPLEX-961): prop `mobileViewProps`, унаследованный от `Dropdown`, переименован в `pullerProps`. |
203
+ | 2026-10-29 | TRIPLEX-1028: клик и Enter / Space на кнопках тегов и других фокусируемых элементах внутри `MultiselectField.Target` больше не переключают выпадающий блок, `stopPropagation` в `onKeyDown` тегов для этого не нужен. Клавиши открытия — см. «Accessibility». `onClear` у `MultiselectField.Target` получает событие клика. |
202
204
 
203
205
  ---
204
206
 
@@ -226,11 +228,11 @@ import {
226
228
  TagGroup,
227
229
  Text,
228
230
  ETextSize,
229
- DropdownMobileFooter,
230
- DropdownMobileBody,
231
- DropdownMobileHeader,
232
- DropdownMobileInput,
233
- DropdownMobileClose,
231
+ PullerFooter,
232
+ PullerBody,
233
+ PullerHeader,
234
+ PullerInput,
235
+ PullerClose,
234
236
  } from "@sberbusiness/triplex-next";
235
237
  import "../MultiselectField.less";
236
238
 
@@ -315,11 +317,6 @@ export const DefaultExample = () => {
315
317
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
316
318
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
317
319
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
318
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
319
- if (event.code === "Enter" || event.code === "Space") {
320
- event.stopPropagation();
321
- }
322
- };
323
320
 
324
321
  if (!selectedOptions.length) return null;
325
322
  if (selectedOptions.length > 3) {
@@ -330,7 +327,6 @@ export const DefaultExample = () => {
330
327
  onFocus={handleTagFocus}
331
328
  onBlur={handleTagBlur}
332
329
  onClick={handleTagClick}
333
- onKeyDown={handleTagKeyDown}
334
330
  onRemove={handleClearAll}
335
331
  >
336
332
  {`Выбрано ${selectedOptions.length} значения`}
@@ -348,7 +344,6 @@ export const DefaultExample = () => {
348
344
  onFocus={handleTagFocus}
349
345
  onBlur={handleTagBlur}
350
346
  onClick={handleTagClick}
351
- onKeyDown={handleTagKeyDown}
352
347
  onRemove={() => handleToggle(opt, false)}
353
348
  >
354
349
  {opt.label}
@@ -379,28 +374,26 @@ export const DefaultExample = () => {
379
374
  targetRef={dropdownTargetRef}
380
375
  ref={dropdownRef}
381
376
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
382
- mobileViewProps={{
377
+ pullerProps={{
383
378
  children: (
384
379
  <>
385
- <DropdownMobileHeader
386
- controlButtons={<DropdownMobileClose onClick={() => setOpened(false)} />}
387
- >
388
- <DropdownMobileInput
380
+ <PullerHeader controlButtons={<PullerClose onClick={() => setOpened(false)} />}>
381
+ <PullerInput
389
382
  autoFocus={true}
390
383
  placeholder="Type to proceed"
391
384
  value={filter}
392
385
  onChange={(event) => setFilter(event.target.value)}
393
386
  />
394
- </DropdownMobileHeader>
395
- <DropdownMobileBody>
387
+ </PullerHeader>
388
+ <PullerBody>
396
389
  {renderCheckboxList()}
397
390
  {!!filter.trim().length && !visibleOptions.length && (
398
391
  <Text size={ETextSize.B3} className="not-found">
399
392
  Nothing was found.
400
393
  </Text>
401
394
  )}
402
- </DropdownMobileBody>
403
- <DropdownMobileFooter>
395
+ </PullerBody>
396
+ <PullerFooter>
404
397
  <Button
405
398
  theme={EButtonTheme.SECONDARY}
406
399
  size={EComponentSize.MD}
@@ -415,7 +408,7 @@ export const DefaultExample = () => {
415
408
  >
416
409
  Button link text
417
410
  </Button>
418
- </DropdownMobileFooter>
411
+ </PullerFooter>
419
412
  </>
420
413
  ),
421
414
  }}
@@ -577,11 +570,6 @@ const SizeItem = ({ size }: ISizeItemProps) => {
577
570
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
578
571
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
579
572
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
580
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
581
- if (event.code === "Enter" || event.code === "Space") {
582
- event.stopPropagation();
583
- }
584
- };
585
573
 
586
574
  if (!selectedOptions.length) return null;
587
575
 
@@ -595,7 +583,6 @@ const SizeItem = ({ size }: ISizeItemProps) => {
595
583
  onFocus={handleTagFocus}
596
584
  onBlur={handleTagBlur}
597
585
  onClick={handleTagClick}
598
- onKeyDown={handleTagKeyDown}
599
586
  onRemove={() => handleToggle(opt, false)}
600
587
  >
601
588
  {opt.label}
@@ -790,11 +777,6 @@ const StatusItem = ({ idPrefix, status }: IStatusItemProps) => {
790
777
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
791
778
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
792
779
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
793
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
794
- if (event.code === "Enter" || event.code === "Space") {
795
- event.stopPropagation();
796
- }
797
- };
798
780
 
799
781
  if (!selectedOptions.length) return null;
800
782
 
@@ -808,7 +790,6 @@ const StatusItem = ({ idPrefix, status }: IStatusItemProps) => {
808
790
  onFocus={handleTagFocus}
809
791
  onBlur={handleTagBlur}
810
792
  onClick={handleTagClick}
811
- onKeyDown={handleTagKeyDown}
812
793
  onRemove={() => handleToggle(opt, false)}
813
794
  >
814
795
  {opt.label}
@@ -903,12 +884,12 @@ import {
903
884
  ETextSize,
904
885
  Tag,
905
886
  TagGroup,
906
- DropdownMobileHeader,
907
- DropdownMobileClose,
908
- DropdownMobileInput,
909
- DropdownMobileBody,
910
- DropdownMobileFooter,
911
- DropdownMobileLoader,
887
+ PullerHeader,
888
+ PullerClose,
889
+ PullerInput,
890
+ PullerBody,
891
+ PullerFooter,
892
+ PullerLoader,
912
893
  } from "@sberbusiness/triplex-next";
913
894
  import "../MultiselectField.less";
914
895
 
@@ -1010,11 +991,6 @@ const LoadingMultiselect = ({
1010
991
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1011
992
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1012
993
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
1013
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
1014
- if (event.code === "Enter" || event.code === "Space") {
1015
- event.stopPropagation();
1016
- }
1017
- };
1018
994
 
1019
995
  if (!selectedOptions.length) return null;
1020
996
 
@@ -1028,7 +1004,6 @@ const LoadingMultiselect = ({
1028
1004
  onFocus={handleTagFocus}
1029
1005
  onBlur={handleTagBlur}
1030
1006
  onClick={handleTagClick}
1031
- onKeyDown={handleTagKeyDown}
1032
1007
  onRemove={() => handleToggle(opt, false)}
1033
1008
  >
1034
1009
  {opt.label}
@@ -1059,33 +1034,33 @@ const LoadingMultiselect = ({
1059
1034
  targetRef={dropdownTargetRef}
1060
1035
  ref={dropdownRef}
1061
1036
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
1062
- mobileViewProps={{
1037
+ pullerProps={{
1063
1038
  children: (
1064
1039
  <>
1065
- <DropdownMobileHeader
1040
+ <PullerHeader
1066
1041
  controlButtons={
1067
1042
  <>
1068
- <DropdownMobileLoader />
1069
- <DropdownMobileClose onClick={() => setOpened(false)} />
1043
+ <PullerLoader />
1044
+ <PullerClose onClick={() => setOpened(false)} />
1070
1045
  </>
1071
1046
  }
1072
1047
  >
1073
- <DropdownMobileInput
1048
+ <PullerInput
1074
1049
  autoFocus={true}
1075
1050
  placeholder="Type to proceed"
1076
1051
  value={filter}
1077
1052
  onChange={(event) => setFilter(event.target.value)}
1078
1053
  />
1079
- </DropdownMobileHeader>
1080
- <DropdownMobileBody>
1054
+ </PullerHeader>
1055
+ <PullerBody>
1081
1056
  {renderCheckboxList()}
1082
1057
  {!!filter.trim().length && !visibleOptions.length && (
1083
1058
  <Text size={ETextSize.B3} className="not-found">
1084
1059
  Nothing was found.
1085
1060
  </Text>
1086
1061
  )}
1087
- </DropdownMobileBody>
1088
- <DropdownMobileFooter>
1062
+ </PullerBody>
1063
+ <PullerFooter>
1089
1064
  <Button
1090
1065
  theme={EButtonTheme.SECONDARY}
1091
1066
  size={EComponentSize.MD}
@@ -1096,7 +1071,7 @@ const LoadingMultiselect = ({
1096
1071
  <Button theme={EButtonTheme.LINK} size={EComponentSize.MD} onClick={handleClearAll}>
1097
1072
  Button link text
1098
1073
  </Button>
1099
- </DropdownMobileFooter>
1074
+ </PullerFooter>
1100
1075
  </>
1101
1076
  ),
1102
1077
  }}
@@ -1147,11 +1122,11 @@ import {
1147
1122
  Button,
1148
1123
  Checkbox,
1149
1124
  CheckboxYGroup,
1150
- DropdownMobileBody,
1151
- DropdownMobileFooter,
1152
1125
  EButtonTheme,
1153
1126
  EComponentSize,
1154
1127
  MultiselectField,
1128
+ PullerBody,
1129
+ PullerFooter,
1155
1130
  Tag,
1156
1131
  TagGroup,
1157
1132
  } from "@sberbusiness/triplex-next";
@@ -1217,11 +1192,6 @@ export const DropdownWithoutInputExample = () => {
1217
1192
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1218
1193
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1219
1194
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
1220
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
1221
- if (event.code === "Enter" || event.code === "Space") {
1222
- event.stopPropagation();
1223
- }
1224
- };
1225
1195
 
1226
1196
  if (!selectedOptions.length) return null;
1227
1197
 
@@ -1235,7 +1205,6 @@ export const DropdownWithoutInputExample = () => {
1235
1205
  onFocus={handleTagFocus}
1236
1206
  onBlur={handleTagBlur}
1237
1207
  onClick={handleTagClick}
1238
- onKeyDown={handleTagKeyDown}
1239
1208
  onRemove={() => handleToggle(opt, false)}
1240
1209
  >
1241
1210
  {opt.label}
@@ -1266,11 +1235,11 @@ export const DropdownWithoutInputExample = () => {
1266
1235
  targetRef={dropdownTargetRef}
1267
1236
  ref={dropdownRef}
1268
1237
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
1269
- mobileViewProps={{
1238
+ pullerProps={{
1270
1239
  children: (
1271
1240
  <>
1272
- <DropdownMobileBody>{renderCheckboxList()}</DropdownMobileBody>
1273
- <DropdownMobileFooter>
1241
+ <PullerBody>{renderCheckboxList()}</PullerBody>
1242
+ <PullerFooter>
1274
1243
  <Button
1275
1244
  theme={EButtonTheme.SECONDARY}
1276
1245
  size={EComponentSize.MD}
@@ -1285,7 +1254,7 @@ export const DropdownWithoutInputExample = () => {
1285
1254
  >
1286
1255
  Button link text
1287
1256
  </Button>
1288
- </DropdownMobileFooter>
1257
+ </PullerFooter>
1289
1258
  </>
1290
1259
  ),
1291
1260
  }}
@@ -1333,11 +1302,11 @@ import {
1333
1302
  ETextSize,
1334
1303
  Tag,
1335
1304
  TagGroup,
1336
- DropdownMobileHeader,
1337
- DropdownMobileClose,
1338
- DropdownMobileInput,
1339
- DropdownMobileBody,
1340
- DropdownMobileFooter,
1305
+ PullerHeader,
1306
+ PullerClose,
1307
+ PullerInput,
1308
+ PullerBody,
1309
+ PullerFooter,
1341
1310
  } from "@sberbusiness/triplex-next";
1342
1311
  import "../MultiselectField.less";
1343
1312
 
@@ -1414,11 +1383,6 @@ export const WithClearButtonExample = () => {
1414
1383
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1415
1384
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1416
1385
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
1417
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
1418
- if (event.code === "Enter" || event.code === "Space") {
1419
- event.stopPropagation();
1420
- }
1421
- };
1422
1386
 
1423
1387
  if (!selectedOptions.length) return null;
1424
1388
 
@@ -1432,7 +1396,6 @@ export const WithClearButtonExample = () => {
1432
1396
  onFocus={handleTagFocus}
1433
1397
  onBlur={handleTagBlur}
1434
1398
  onClick={handleTagClick}
1435
- onKeyDown={handleTagKeyDown}
1436
1399
  onRemove={() => handleToggle(opt, false)}
1437
1400
  >
1438
1401
  {opt.label}
@@ -1464,28 +1427,26 @@ export const WithClearButtonExample = () => {
1464
1427
  targetRef={dropdownTargetRef}
1465
1428
  ref={dropdownRef}
1466
1429
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
1467
- mobileViewProps={{
1430
+ pullerProps={{
1468
1431
  children: (
1469
1432
  <>
1470
- <DropdownMobileHeader
1471
- controlButtons={<DropdownMobileClose onClick={() => setOpened(false)} />}
1472
- >
1473
- <DropdownMobileInput
1433
+ <PullerHeader controlButtons={<PullerClose onClick={() => setOpened(false)} />}>
1434
+ <PullerInput
1474
1435
  autoFocus={true}
1475
1436
  placeholder="Type to proceed"
1476
1437
  value={filter}
1477
1438
  onChange={(event) => setFilter(event.target.value)}
1478
1439
  />
1479
- </DropdownMobileHeader>
1480
- <DropdownMobileBody>
1440
+ </PullerHeader>
1441
+ <PullerBody>
1481
1442
  {renderCheckboxList()}
1482
1443
  {!!filter.trim().length && !visibleOptions.length && (
1483
1444
  <Text size={ETextSize.B3} className="not-found">
1484
1445
  Nothing was found.
1485
1446
  </Text>
1486
1447
  )}
1487
- </DropdownMobileBody>
1488
- <DropdownMobileFooter>
1448
+ </PullerBody>
1449
+ <PullerFooter>
1489
1450
  <Button
1490
1451
  theme={EButtonTheme.SECONDARY}
1491
1452
  size={EComponentSize.MD}
@@ -1500,7 +1461,7 @@ export const WithClearButtonExample = () => {
1500
1461
  >
1501
1462
  Button link text
1502
1463
  </Button>
1503
- </DropdownMobileFooter>
1464
+ </PullerFooter>
1504
1465
  </>
1505
1466
  ),
1506
1467
  }}
@@ -1566,11 +1527,11 @@ import {
1566
1527
  ETextSize,
1567
1528
  Tag,
1568
1529
  TagGroup,
1569
- DropdownMobileHeader,
1570
- DropdownMobileClose,
1571
- DropdownMobileInput,
1572
- DropdownMobileBody,
1573
- DropdownMobileFooter,
1530
+ PullerHeader,
1531
+ PullerClose,
1532
+ PullerInput,
1533
+ PullerBody,
1534
+ PullerFooter,
1574
1535
  IconWrapper,
1575
1536
  } from "@sberbusiness/triplex-next";
1576
1537
  import { DefaulticonStrokePrdIcon20 } from "@sberbusiness/icons-next";
@@ -1648,11 +1609,6 @@ export const WithPrefixAndPostfixExample = () => {
1648
1609
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1649
1610
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1650
1611
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
1651
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
1652
- if (event.code === "Enter" || event.code === "Space") {
1653
- event.stopPropagation();
1654
- }
1655
- };
1656
1612
 
1657
1613
  if (!selectedOptions.length) return null;
1658
1614
 
@@ -1666,7 +1622,6 @@ export const WithPrefixAndPostfixExample = () => {
1666
1622
  onFocus={handleTagFocus}
1667
1623
  onBlur={handleTagBlur}
1668
1624
  onClick={handleTagClick}
1669
- onKeyDown={handleTagKeyDown}
1670
1625
  onRemove={() => handleToggle(opt, false)}
1671
1626
  >
1672
1627
  {opt.label}
@@ -1703,28 +1658,26 @@ export const WithPrefixAndPostfixExample = () => {
1703
1658
  targetRef={dropdownTargetRef}
1704
1659
  ref={dropdownRef}
1705
1660
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
1706
- mobileViewProps={{
1661
+ pullerProps={{
1707
1662
  children: (
1708
1663
  <>
1709
- <DropdownMobileHeader
1710
- controlButtons={<DropdownMobileClose onClick={() => setOpened(false)} />}
1711
- >
1712
- <DropdownMobileInput
1664
+ <PullerHeader controlButtons={<PullerClose onClick={() => setOpened(false)} />}>
1665
+ <PullerInput
1713
1666
  autoFocus={true}
1714
1667
  placeholder="Type to proceed"
1715
1668
  value={filter}
1716
1669
  onChange={(event) => setFilter(event.target.value)}
1717
1670
  />
1718
- </DropdownMobileHeader>
1719
- <DropdownMobileBody>
1671
+ </PullerHeader>
1672
+ <PullerBody>
1720
1673
  {renderCheckboxList()}
1721
1674
  {!!filter.trim().length && !visibleOptions.length && (
1722
1675
  <Text size={ETextSize.B3} className="not-found">
1723
1676
  Nothing was found.
1724
1677
  </Text>
1725
1678
  )}
1726
- </DropdownMobileBody>
1727
- <DropdownMobileFooter>
1679
+ </PullerBody>
1680
+ <PullerFooter>
1728
1681
  <Button
1729
1682
  theme={EButtonTheme.SECONDARY}
1730
1683
  size={EComponentSize.MD}
@@ -1739,7 +1692,7 @@ export const WithPrefixAndPostfixExample = () => {
1739
1692
  >
1740
1693
  Button link text
1741
1694
  </Button>
1742
- </DropdownMobileFooter>
1695
+ </PullerFooter>
1743
1696
  </>
1744
1697
  ),
1745
1698
  }}
@@ -1791,11 +1744,6 @@ import {
1791
1744
  Button,
1792
1745
  Checkbox,
1793
1746
  CheckboxYGroup,
1794
- DropdownMobileBody,
1795
- DropdownMobileClose,
1796
- DropdownMobileFooter,
1797
- DropdownMobileHeader,
1798
- DropdownMobileInput,
1799
1747
  EButtonTheme,
1800
1748
  EComponentSize,
1801
1749
  EFontType,
@@ -1810,6 +1758,11 @@ import {
1810
1758
  HelpBox,
1811
1759
  Link,
1812
1760
  MultiselectField,
1761
+ PullerBody,
1762
+ PullerClose,
1763
+ PullerFooter,
1764
+ PullerHeader,
1765
+ PullerInput,
1813
1766
  Tag,
1814
1767
  TagGroup,
1815
1768
  Text,
@@ -1904,11 +1857,6 @@ const ProductionMultiselect = () => {
1904
1857
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1905
1858
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
1906
1859
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
1907
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
1908
- if (event.code === "Enter" || event.code === "Space") {
1909
- event.stopPropagation();
1910
- }
1911
- };
1912
1860
 
1913
1861
  if (!selectedOptions.length) return null;
1914
1862
 
@@ -1922,7 +1870,6 @@ const ProductionMultiselect = () => {
1922
1870
  onFocus={handleTagFocus}
1923
1871
  onBlur={handleTagBlur}
1924
1872
  onClick={handleTagClick}
1925
- onKeyDown={handleTagKeyDown}
1926
1873
  onRemove={() => handleToggle(opt, false)}
1927
1874
  >
1928
1875
  {opt.label}
@@ -1955,28 +1902,26 @@ const ProductionMultiselect = () => {
1955
1902
  targetRef={dropdownTargetRef}
1956
1903
  ref={dropdownRef}
1957
1904
  focusTrapProps={{ focusTrapOptions: { initialFocus: false } }}
1958
- mobileViewProps={{
1905
+ pullerProps={{
1959
1906
  children: (
1960
1907
  <>
1961
- <DropdownMobileHeader
1962
- controlButtons={<DropdownMobileClose onClick={() => setOpened(false)} />}
1963
- >
1964
- <DropdownMobileInput
1908
+ <PullerHeader controlButtons={<PullerClose onClick={() => setOpened(false)} />}>
1909
+ <PullerInput
1965
1910
  autoFocus={true}
1966
1911
  placeholder="Type to proceed"
1967
1912
  value={filter}
1968
1913
  onChange={(event) => setFilter(event.target.value)}
1969
1914
  />
1970
- </DropdownMobileHeader>
1971
- <DropdownMobileBody>
1915
+ </PullerHeader>
1916
+ <PullerBody>
1972
1917
  {renderCheckboxList()}
1973
1918
  {!!filter.trim().length && !visibleOptions.length && (
1974
1919
  <Text size={ETextSize.B3} className="not-found">
1975
1920
  Nothing was found.
1976
1921
  </Text>
1977
1922
  )}
1978
- </DropdownMobileBody>
1979
- <DropdownMobileFooter>
1923
+ </PullerBody>
1924
+ <PullerFooter>
1980
1925
  <Button
1981
1926
  theme={EButtonTheme.SECONDARY}
1982
1927
  size={EComponentSize.MD}
@@ -1987,7 +1932,7 @@ const ProductionMultiselect = () => {
1987
1932
  <Button theme={EButtonTheme.LINK} size={EComponentSize.MD} onClick={handleClearAll}>
1988
1933
  Button link text
1989
1934
  </Button>
1990
- </DropdownMobileFooter>
1935
+ </PullerFooter>
1991
1936
  </>
1992
1937
  ),
1993
1938
  }}
@@ -2159,11 +2104,6 @@ export const WithCheckboxTreeExample = () => {
2159
2104
  const handleTagFocus = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
2160
2105
  const handleTagBlur = (event: React.FocusEvent<HTMLSpanElement>) => event.stopPropagation();
2161
2106
  const handleTagClick = (event: React.MouseEvent<HTMLSpanElement>) => event.stopPropagation();
2162
- const handleTagKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
2163
- if (event.code === "Enter" || event.code === "Space") {
2164
- event.stopPropagation();
2165
- }
2166
- };
2167
2107
 
2168
2108
  if (!selectedLeafNodes.length) return null;
2169
2109
  if (selectedLeafNodes.length > 3) {
@@ -2174,7 +2114,6 @@ export const WithCheckboxTreeExample = () => {
2174
2114
  onFocus={handleTagFocus}
2175
2115
  onBlur={handleTagBlur}
2176
2116
  onClick={handleTagClick}
2177
- onKeyDown={handleTagKeyDown}
2178
2117
  onRemove={() => setSelectedIds([])}
2179
2118
  >
2180
2119
  {`Выбрано ${selectedLeafNodes.length} значения`}
@@ -2191,7 +2130,6 @@ export const WithCheckboxTreeExample = () => {
2191
2130
  onFocus={handleTagFocus}
2192
2131
  onBlur={handleTagBlur}
2193
2132
  onClick={handleTagClick}
2194
- onKeyDown={handleTagKeyDown}
2195
2133
  onRemove={() => setSelectedIds((prev) => prev.filter((id) => id !== node.id))}
2196
2134
  >
2197
2135
  {node.label}
@@ -123,7 +123,7 @@ Notification.TimeColor (цвет времени)
123
123
 
124
124
  ## Связанные компоненты
125
125
 
126
- - `NotificationGrouped` — обёртка для отображения уведомления стопкой.
126
+ - `NotificationGrouped` — обёртка для отображения уведомления стопкой; см. [`NotificationGrouped-ai.md`](./NotificationGrouped-ai.md).
127
127
  - `Button` — типичное содержимое `Notification.Body.Footer`.
128
128
  - `AlertContext` — может вкладываться в `Notification.Body.Footer`.
129
129
  - `UnorderedList` — основа `Notification.Body.List`.
@@ -153,6 +153,7 @@ Notification.TimeColor (цвет времени)
153
153
  |---|---|
154
154
  | 2026-06-16 | Создан AI-документ. `Notification`, `NotificationGrouped`, `NotificationBody` переведены на `forwardRef` (паттерн `Object.assign`); удалены типы `INotificationSFC`/`INotificationBodySFC`; тип `Notification.Time.time` расширен с `React.ReactText` до `React.ReactNode`. Stories мигрированы на modern pattern. |
155
155
  | 2026-09-28 | Токен `Notification.Shadow` ссылается на `Shadow.07` (светлая) и `DarkShadow.07` (тёмная) вместо литералов; в тёмной теме прозрачность 0.25 вместо 0.35. |
156
+ | 2026-10-15 | Добавлена ссылка на отдельный `NotificationGrouped-ai.md`. |
156
157
 
157
158
  ---
158
159