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

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 (110) hide show
  1. package/README.md +7 -7
  2. package/bundle/components/Amount.md +2 -1
  3. package/bundle/components/AmountField.md +222 -323
  4. package/bundle/components/Avatar.md +138 -146
  5. package/bundle/components/Badge.md +2 -1
  6. package/bundle/components/BodyPage.md +2 -1
  7. package/bundle/components/Button.md +5 -1
  8. package/bundle/components/ButtonDropdownExtended.md +3 -1
  9. package/bundle/components/ButtonIcon.md +3 -1
  10. package/bundle/components/Calendar.md +3 -1
  11. package/bundle/components/CardAction.md +1 -0
  12. package/bundle/components/CardStatic.md +402 -0
  13. package/bundle/components/CheckboxTree.md +157 -215
  14. package/bundle/components/CheckboxTreeExtended.md +7 -7
  15. package/bundle/components/CheckboxXGroup.md +2 -1
  16. package/bundle/components/Chip.md +2 -1
  17. package/bundle/components/ChipGroup.md +1 -1
  18. package/bundle/components/ChipMonthYearPicker.md +6 -5
  19. package/bundle/components/ChipMultiselect.md +4 -1
  20. package/bundle/components/ChipOptions.md +2 -1
  21. package/bundle/components/ChipSort.md +4 -1
  22. package/bundle/components/ChipSuggest.md +7 -6
  23. package/bundle/components/CollapsibleTree.md +10 -5
  24. package/bundle/components/CollapsibleTreeExtended.md +8 -6
  25. package/bundle/components/ComposedKeyDownListener.md +4 -3
  26. package/bundle/components/Confirm.md +346 -281
  27. package/bundle/components/DateField.md +7 -1
  28. package/bundle/components/DateRange.md +351 -210
  29. package/bundle/components/Divider.md +85 -138
  30. package/bundle/components/DocumentNumberEdit.md +173 -214
  31. package/bundle/components/Dropdown.md +11 -1
  32. package/bundle/components/Ellipsis.md +131 -147
  33. package/bundle/components/FooterPage.md +4 -1
  34. package/bundle/components/FormField.md +13 -5
  35. package/bundle/components/FormGroup.md +3 -2
  36. package/bundle/components/Gap.md +1 -1
  37. package/bundle/components/Header.md +1 -0
  38. package/bundle/components/HeaderPage.md +3 -1
  39. package/bundle/components/HelpBox.md +2 -1
  40. package/bundle/components/IconWrapper.md +10 -6
  41. package/bundle/components/ImageGallery.md +2 -1
  42. package/bundle/components/ImageGalleryExtended.md +2 -1
  43. package/bundle/components/IslandAccordion.md +6 -1
  44. package/bundle/components/KeyDownListener.md +3 -2
  45. package/bundle/components/LightBox.md +15 -1
  46. package/bundle/components/List.md +2 -1
  47. package/bundle/components/ListActionItem.md +2 -1
  48. package/bundle/components/ListItem.md +3 -1
  49. package/bundle/components/ListItemControlsButton.md +2 -1
  50. package/bundle/components/ListItemSelectable.md +2 -1
  51. package/bundle/components/ListMaster.md +2 -2
  52. package/bundle/components/ListMasterFooter.md +2 -1
  53. package/bundle/components/ListMasterHeader.md +2 -1
  54. package/bundle/components/ListSortable.md +2 -1
  55. package/bundle/components/ListSortableItem.md +2 -1
  56. package/bundle/components/ListTableItem.md +10 -7
  57. package/bundle/components/LoaderMiddle.md +5 -1
  58. package/bundle/components/LoaderScreen.md +7 -1
  59. package/bundle/components/LoaderSmall.md +10 -4
  60. package/bundle/components/MaskedField.md +3 -1
  61. package/bundle/components/MediaWidth.md +2 -1
  62. package/bundle/components/MobileView.md +2 -1
  63. package/bundle/components/ModalWindow.md +4 -1
  64. package/bundle/components/MonthYearField.md +19 -5
  65. package/bundle/components/Notification.md +1 -0
  66. package/bundle/components/Overlay.md +7 -2
  67. package/bundle/components/Pagination.md +1 -7
  68. package/bundle/components/Radio.md +238 -115
  69. package/bundle/components/RadioXGroup.md +259 -0
  70. package/bundle/components/RadioYGroup.md +266 -0
  71. package/bundle/components/SegmentedControl.md +505 -158
  72. package/bundle/components/SelectExtendedField.md +2 -1
  73. package/bundle/components/SelectField.md +4 -1
  74. package/bundle/components/Skeleton.md +140 -69
  75. package/bundle/components/Slider.md +389 -97
  76. package/bundle/components/SliderRange.md +486 -105
  77. package/bundle/components/Spoiler.md +245 -63
  78. package/bundle/components/StatusTracker.md +386 -94
  79. package/bundle/components/Step.md +257 -68
  80. package/bundle/components/Stepper.md +355 -102
  81. package/bundle/components/StepperExtended.md +633 -0
  82. package/bundle/components/SuggestField.md +1061 -96
  83. package/bundle/components/SwipeableArea.md +7 -7
  84. package/bundle/components/Tabs.md +266 -92
  85. package/bundle/components/TabsExtended.md +18 -18
  86. package/bundle/components/TabsLine.md +302 -127
  87. package/bundle/components/TagColor.md +187 -66
  88. package/bundle/components/TagGroup.md +184 -48
  89. package/bundle/components/TextField.md +8 -4
  90. package/bundle/components/TextareaField.md +279 -70
  91. package/bundle/components/ThemeProvider.md +2 -1
  92. package/bundle/components/Tooltip.md +6 -3
  93. package/bundle/components/TopOverlay.md +17 -1
  94. package/bundle/components/TreeView.md +16 -7
  95. package/bundle/components/TriggerClickOnKeyDownEvent.md +277 -0
  96. package/bundle/components/UploadZone.md +318 -0
  97. package/bundle/guides/codestyle.md +16 -1
  98. package/bundle/guides/commits.md +47 -1
  99. package/bundle/guides/context.md +4 -1
  100. package/bundle/guides/tests.md +23 -2
  101. package/bundle/manifest.json +78 -29
  102. package/bundle/release-notes/1.47.0.mdx +115 -0
  103. package/bundle/release-notes/1.48.0.mdx +68 -0
  104. package/bundle/release-notes/1.49.0.mdx +85 -0
  105. package/bundle/release-notes/1.50.0.mdx +35 -0
  106. package/bundle/release-notes/1.51.0.mdx +7 -0
  107. package/bundle/tokens.json +163 -13
  108. package/dist/index.js +220 -6
  109. package/dist/index.js.map +1 -1
  110. package/package.json +1 -1
@@ -1,9 +1,7 @@
1
1
  ---
2
2
  component: Spoiler
3
- category: Disclosure
4
- figma-node: ""
5
- figma-file: ""
6
- related: [AccordionBase, Button]
3
+ category: Spoiler
4
+ related: [IslandAccordion, Button]
7
5
  tokens: []
8
6
  stories: stories/Spoiler/Spoiler.stories.tsx
9
7
  version: "1.0"
@@ -13,104 +11,181 @@ version: "1.0"
13
11
 
14
12
  ## Назначение
15
13
 
16
- Раскрывающаяся область с link-кнопкой-триггером сверху. Текст триггера
17
- переключается между `labelExpand` / `labelCollapse`, содержимое скрывается
18
- CSS-классом (`hidden`) — DOM не размонтируется.
14
+ Кнопка-ссылка с кареткой, по клику раскрывающая блок содержимого под собой. Самый
15
+ лёгкий способ спрятать необязательные детали: собственного оформления у компонента
16
+ почти нет — ни рамки, ни фона, ни отступов вокруг. Кнопку рисует `Button` с темой
17
+ `EButtonTheme.LINK`, содержимое в свёрнутом состоянии просто выключено через
18
+ `display: none`.
19
19
 
20
- Используй когда: нужно показать/скрыть блок вспомогательной информации
21
- через простой inline-триггер (не секцию-«аккордеон»).
22
- Не используй когда: нужна секционированная навигация с несколькими
23
- панелями — используй `AccordionBase`.
20
+ Используй когда: рядом с основным контентом нужно спрятать пояснение, подробности
21
+ операции, «показать ещё» — и хочется, чтобы блок не выглядел отдельной секцией.
24
22
 
25
- ---
26
-
27
- ## Файловая структура
23
+ Не используй когда:
28
24
 
29
- ```text
30
- src/components/Spoiler/
31
- ├── Spoiler.tsx # forwardRef<HTMLDivElement, TSpoilerProps>
32
- ├── index.ts
33
- └── styles/Spoiler.module.less
34
- ```
25
+ - нужен аккордеон как самостоятельная секция страницы — с фоном, разделителями,
26
+ несколькими элементами и одновременным закрытием соседей: это `IslandAccordion`;
27
+ - нужна плавная анимация раскрытия по высоте: `Spoiler` переключает содержимое
28
+ мгновенно, анимирована только каретка. Анимация высоты — `ExpandAnimation` плюс
29
+ своя кнопка;
30
+ - нужен спойлер внутри `AlertProcess` — там своя реализация `AlertProcess.Spoiler`,
31
+ связанная с родителем через контекст.
35
32
 
36
33
  ---
37
34
 
38
35
  ## Варианты и props
39
36
 
40
- `TSpoilerProps = ISpoilerControlledProps | ISpoilerUncontrolledProps`.
41
-
42
- ### Общие (`ISpoilerBaseProps`)
37
+ `ISpoilerBaseProps` расширяет `React.HTMLAttributes<HTMLDivElement>` — `...rest`
38
+ уходит на корневой `<div>`.
43
39
 
44
- | Prop | Тип | Default | Описание |
45
- |---|---|---|---|
46
- | `labelExpand` | `string` | — | Текст кнопки в свернутом состоянии. |
47
- | `labelCollapse?` | `string` | — | Текст кнопки в раскрытом состоянии. Если не задан — кнопка показывает `labelExpand` всегда. |
48
- | `onToggle?` | `(expanded: boolean) => void` | — | Колбэк изменения состояния. Вызывается ВСЕГДА (и в controlled, и в uncontrolled). |
49
- | `rightBlock?` | `ReactNode` | — | Доп. контент справа от триггера в шапке. |
50
- | `size?` | `EComponentSize` | `MD` | `SM` → icon-16, `MD`/`LG` → icon-20. |
51
- | `...HTMLAttributes<HTMLDivElement>` | — | — | Прокидываются на корень. |
52
-
53
- ### Controlled (`ISpoilerControlledProps`)
40
+ ### Обязательные props
54
41
 
55
42
  | Prop | Тип | Описание |
56
43
  |---|---|---|
57
- | `expanded` | `boolean` | Контролируемое состояние. |
58
- | `toggle` | `(next: boolean) => void` | Контролирующий handler. Обязателен если передан `expanded`. |
44
+ | `labelExpand` | `string` | Текст кнопки в свёрнутом состоянии |
59
45
 
60
- ### Uncontrolled (`ISpoilerUncontrolledProps`)
46
+ ### Опциональные props
61
47
 
62
- | Prop | Тип | Описание |
63
- |---|---|---|
64
- | `expanded` | `never` | Запрещено. |
65
- | `toggle` | `never` | Запрещено. |
48
+ | Prop | Тип | По умолчанию | Описание |
49
+ |---|---|---|---|
50
+ | `labelCollapse` | `string` | — | Текст кнопки в раскрытом состоянии. Не передан — в раскрытом состоянии у кнопки остаётся одна каретка без текста, кнопка теряет доступное имя. Передавать стоит всегда |
51
+ | `size` | `EComponentSize` | `EComponentSize.MD` | Размер: уходит в `Button` (у темы `LINK` от размера зависит только типографика — `font-size` и `line-height`, высота и отступы не задаются) и выбирает каретку — 16px для `SM`, 20px для `MD` и `LG` |
52
+ | `onToggle` | `(expanded: boolean) => void` | — | Уведомление о клике по кнопке. Вызывается в **обоих** режимах и получает следующее состояние |
53
+ | `rightBlock` | `React.ReactNode` | — | Содержимое правой части заголовка |
54
+ | `children` | `React.ReactNode` | — | Раскрываемое содержимое |
55
+ | `className` | `string` | — | Мерджится с собственными классами корневого `<div>` через `clsx` |
56
+
57
+ ### Два режима: контролируемый и неконтролируемый
66
58
 
67
- Различение controlled/uncontrolled — по `expanded !== undefined` внутри компонента.
59
+ `TSpoilerProps` — discriminated union по наличию `expanded`
60
+ (`ISpoilerControlledProps | ISpoilerUncontrolledProps`):
61
+
62
+ | Режим | Признак | Кто хранит состояние | Что происходит по клику |
63
+ |---|---|---|---|
64
+ | Неконтролируемый | `expanded` не передан | компонент (`useState`) | состояние переключается внутри, вызывается `onToggle(next)` |
65
+ | Контролируемый | передан `expanded` + `toggle` | потребитель | вызывается `toggle(next)` и `onToggle(next)`, вид не меняется до обновления `expanded` |
66
+
67
+ - В контролируемом режиме `toggle` обязателен — без него клик ничего не сделает.
68
+ Компонент сам `expanded` не меняет.
69
+ - `expanded?: never` / `toggle?: never` в `ISpoilerUncontrolledProps` — это запрет
70
+ на смешивание режимов на уровне типов, а не props, которые можно передать.
71
+ - Режим вычисляется на каждом рендере (`expanded !== undefined`). Переключать его
72
+ по ходу жизни компонента не стоит: внутреннее состояние при этом сохраняется от
73
+ прошлого неконтролируемого периода.
74
+
75
+ ### `rightBlock` — что это на самом деле
76
+
77
+ Рендерится в заголовке сразу после кнопки, **вне** её: клик по `rightBlock`
78
+ содержимое не раскрывает. Заголовок (`.head`) — обычный блок, а не
79
+ flex-контейнер, поэтому `rightBlock` встаёт в общий инлайн-поток справа от
80
+ кнопки, а не прижимается к правому краю. Снаружи это не лечится: обёртка вокруг
81
+ `Spoiler` управляет раскладкой его корневого элемента, а не содержимого
82
+ заголовка. Прижать `rightBlock` к правому краю можно только раскладкой внутри
83
+ `.head`, то есть правкой самого компонента.
84
+
85
+ ### Известные особенности
86
+
87
+ Ниже — расхождения реализации с ожиданиями, зафиксированные при AI-рефакторинге
88
+ (TRI-81). Все они видны в текущем коде и **не исправлены**: починка меняет разметку
89
+ или внешний вид, то есть требует отдельного решения мейнтейнера.
90
+
91
+ - **Отступ содержимого от заголовка не работает.** В `Spoiler.module.less`
92
+ селекторы `.lg` / `.md` / `.sm` вложены внутрь `.spoiler` как потомки
93
+ (`.spoiler .lg .content`), а размерный класс навешивается на сам корень
94
+ `.spoiler`. Поэтому `margin-top` у `.content` (8px / 0 / −4px) не применяется ни
95
+ при каком размере. Распаковка вложенности изменит вид компонента.
96
+ - **`aria-expanded` отсутствует на первом рендере в неконтролируемом режиме.**
97
+ Внутреннее состояние инициализируется значением пропа (`useState(expanded)`),
98
+ то есть `undefined`, и атрибут не попадает в разметку до первого клика.
99
+ Визуально всё верно (содержимое скрыто), но скринридер не знает, что кнопка
100
+ управляет раскрытием.
68
101
 
69
102
  ---
70
103
 
71
- ## Иконка
104
+ ## Дизайн-токены
72
105
 
73
- | Size | Icon |
74
- |---|---|
75
- | `SM` | `CaretdownStrokeSrvIcon16` (paletteIndex=5) |
76
- | `MD` | `CaretdownStrokeSrvIcon20` (paletteIndex=5) |
77
- | `LG` | `CaretdownStrokeSrvIcon20` (paletteIndex=5) |
106
+ Своих токенов у компонента нет: `Spoiler.module.less` задаёт только раскладку,
107
+ поворот каретки и перенос текста кнопки, CSS-переменных в нём не встречается.
78
108
 
79
- Поворот иконки — через CSS (`styles.opened` на root применяет transform к `.caretIcon`).
109
+ Цвет, типографика и фокус кнопки приходят из `Button` с темой
110
+ `EButtonTheme.LINK` — переопределяются через её токены (`Button.Link_Color_Default`,
111
+ `Button.Link_Color_Hover`, `Button.Link_Color_Active`, `Button.Link_Shadow_Focus`
112
+ и остальные, см. `Button-ai.md`). Цвет каретки задаёт `paletteIndex={5}` иконки,
113
+ а не токен. Оформление содержимого — полностью на стороне потребителя.
80
114
 
81
115
  ---
82
116
 
83
117
  ## Инварианты
84
118
 
85
- - **`forwardRef<HTMLDivElement>`** — не убирать.
86
- - **Триггер — `Button` с `theme={EButtonTheme.LINK}`** и размером `size` из props. Замена на `ButtonIcon` / `Link` — breaking change.
87
- - **Контент не размонтируется** при сворачивании — скрывается классом `styles.hidden`. Это сохраняет state детей между раскрытиями; потребитель должен учитывать, что скрытый контент остаётся в DOM (focusability, форм-валидация).
88
- - **`aria-expanded` на Button, `aria-controls` → id контента, `id` контента** — генерируется через `uniqueId()` один раз в `useRef`. Не переопределять.
89
- - **`onToggle` вызывается всегда** — даже в controlled варианте (удобно для аналитики рядом с `toggle`).
90
- - **`labelCollapse` опционален** — если не задан, открытое состояние покажет `labelExpand`. Это допустимо, но нетипично.
119
+ - **`forwardRef` на компоненте — не убирать.** Ref идёт на корневой `<div>`, тот
120
+ же элемент, что получает `className` и `...rest`.
121
+ - **Корневой DOM — `<div>`** с `data-tx` (версия пакета). Тег не настраивается.
122
+ - **Публичные экспорты barrel** (`src/components/Spoiler/index.ts`): `Spoiler`,
123
+ `ISpoilerBaseProps`, `ISpoilerControlledProps`, `ISpoilerUncontrolledProps`,
124
+ `TSpoilerProps`. Переименование — breaking change.
125
+ - **`displayName = "Spoiler"`.**
126
+ - **Кнопку раскрытия рисует `Button` с темой `EButtonTheme.LINK`.** Она же
127
+ отвечает за визуальное состояние «раскрыто»: `Button` читает переданный
128
+ `aria-expanded` и по нему навешивает свой класс `expanded` и активное состояние
129
+ иконки. Убрать `aria-expanded` — значит сломать не только a11y, но и внешний вид.
130
+ - **Связка `aria-controls` → `id` содержимого** держится на `useRef` с
131
+ `uniqueId()`. Id генерируется один раз на монтирование.
132
+ - **React 17-совместимость.** Компонент уходит в ветку `release-0`, поэтому
133
+ `useId` и другие React 18-only API использовать нельзя — для уникальных id
134
+ остаётся `uniqueId()` из `lodash-es`.
135
+ - **Размерные классы `sm` / `md` / `lg` навешиваются на корень** через
136
+ `createSizeToClassNameMap`. На них опираются unit-тесты.
91
137
 
92
138
  ---
93
139
 
94
140
  ## Accessibility
95
141
 
96
- - `aria-expanded={open}` и `aria-controls={instanceId}` связывают триггер-кнопку с контентом.
97
- - Контент получает `id={instanceId.current}` — уникальный per-instance.
98
- - Триггер — нативная `<button>` (через `Button` → `theme=LINK`), стандартные keyboard-обработчики (Enter/Space).
99
- - Скрытый контент остаётся в DOM (не `display:none` → `hidden` класс; точная CSS-имплементация — в `Spoiler.module.less`). Проверь перед изменением, не должен ли контент быть недоступен для screen reader'а.
142
+ - Раскрытием управляет настоящая `<button>` (внутри `Button`), поэтому
143
+ клавиатура работает штатно: `Tab` — фокус, `Enter` / `Space` — переключение.
144
+ Собственных клавиатурных обработчиков у компонента нет.
145
+ - `aria-expanded` на кнопке отражает состояние раскрытия. Исключение —
146
+ первый рендер в неконтролируемом режиме, см. «Известные особенности».
147
+ - `aria-controls` на кнопке указывает на `id` блока содержимого. Id генерируется
148
+ сам, передавать его снаружи нельзя.
149
+ - Свёрнутое содержимое скрыто через `display: none`, поэтому не попадает ни в
150
+ порядок обхода по `Tab`, ни в дерево доступности.
151
+ - **Текст кнопки — ответственность потребителя.** Библиотека мультиязычная,
152
+ компонент ничего не хардкодит. Без `labelCollapse` в раскрытом состоянии у
153
+ кнопки не остаётся доступного имени — передавай оба текста.
154
+ - `rightBlock` лежит вне кнопки и в её доступное имя не попадает.
100
155
 
101
156
  ---
102
157
 
103
158
  ## Связанные компоненты
104
159
 
105
- - `AccordionBase` — многосекционный аккордеон.
106
- - `Button` — триггер (LINK theme).
160
+ - `IslandAccordion` — альтернатива уровнем выше: раскрываемые секции с фоном,
161
+ разделителями, анимацией высоты и группировкой нескольких элементов. Если
162
+ раскрываемый блок должен выглядеть самостоятельной секцией, это он, а не
163
+ `Spoiler`.
164
+ - `Button` — рендерится внутри как кнопка раскрытия (`EButtonTheme.LINK`,
165
+ тот же `size`). Отсюда берутся типографика, цвета, hover/active/focus и
166
+ визуальное состояние «раскрыто» по `aria-expanded`.
167
+ - `ExpandAnimation` — строительный блок для плавного раскрытия по высоте.
168
+ `Spoiler` его не использует: содержимое переключается мгновенно. Нужна
169
+ анимация — собирай связку сам или бери `IslandAccordion`.
170
+ - `AlertProcess` — не путать: у него есть собственный `AlertProcess.Spoiler`
171
+ (`AlertProcessSpoiler`) с похожим названием и другим API (`open` / `onOpen`),
172
+ живущий только внутри `AlertProcess` и не использующий этот компонент.
107
173
 
108
174
  ---
109
175
 
110
176
  ## Stories
111
177
 
112
- `stories/Spoiler/Spoiler.stories.tsx`
113
- Примеры: `stories/Spoiler/examples/`
178
+ Основные истории: `stories/Spoiler/Spoiler.stories.tsx`
179
+ Файлы примеров: `stories/Spoiler/examples/`
180
+
181
+ | Story | Example file | Что демонстрирует |
182
+ |---|---|---|
183
+ | `Playground` | `Playground.tsx` | Интерактивный контроль `size`, `labelExpand`, `labelCollapse` |
184
+ | `Default` | `Default.tsx` | Минимальный неконтролируемый спойлер |
185
+ | `Sizes` | `Sizes.tsx` | Размеры SM / MD / LG с подписями |
186
+ | `With right block` | `WithRightBlock.tsx` | Содержимое правой части заголовка |
187
+ | `Controlled` | `Controlled.tsx` | Контролируемый режим: `expanded` + `toggle` |
188
+ | `VisualTests` | `VisualTests.tsx` | Свёрнутое и раскрытое состояние всех размеров, `rightBlock`, перенос длинного текста кнопки |
114
189
 
115
190
  ---
116
191
 
@@ -118,4 +193,111 @@ src/components/Spoiler/
118
193
 
119
194
  | Дата | Изменение |
120
195
  |---|---|
121
- | 2026-04-18 | Создан документ |
196
+ | 2026-09-25 | Создан документ. Зафиксированы: два режима работы и контракт `toggle`, поведение `rightBlock` в неflex-заголовке, связка `aria-controls` → `id` на `uniqueId`, зависимость визуального состояния «раскрыто» от `aria-expanded` в `Button`, отсутствие своих токенов и две известные особенности (неработающий `margin-top` у содержимого, отсутствие `aria-expanded` на первом неконтролируемом рендере) |
197
+
198
+ ---
199
+
200
+ ## Примеры использования
201
+
202
+ ### Default
203
+
204
+ `stories/Spoiler/examples/Default.tsx`
205
+
206
+ ```tsx
207
+ import React from "react";
208
+ import { Spoiler, Text, ETextSize, EFontType } from "@sberbusiness/triplex-next";
209
+
210
+ export const Default = () => (
211
+ <Spoiler labelExpand="Развернуть" labelCollapse="Свернуть">
212
+ <Text size={ETextSize.B3} type={EFontType.PRIMARY}>
213
+ Скрытый контент
214
+ </Text>
215
+ </Spoiler>
216
+ );
217
+ ```
218
+
219
+ ### Sizes
220
+
221
+ `stories/Spoiler/examples/Sizes.tsx`
222
+
223
+ ```tsx
224
+ import React from "react";
225
+ import { Spoiler, Text, EComponentSize, ETextSize, EFontType } from "@sberbusiness/triplex-next";
226
+
227
+ const SIZES = Object.values(EComponentSize);
228
+
229
+ const SIZE_TO_TEXT_SIZE_MAP: Record<EComponentSize, ETextSize> = {
230
+ [EComponentSize.SM]: ETextSize.B4,
231
+ [EComponentSize.MD]: ETextSize.B3,
232
+ [EComponentSize.LG]: ETextSize.B2,
233
+ };
234
+
235
+ export const Sizes = () => (
236
+ <div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
237
+ {SIZES.map((size) => (
238
+ <div key={size}>
239
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{size.toUpperCase()}</div>
240
+ <Spoiler size={size} labelExpand="Развернуть" labelCollapse="Свернуть">
241
+ <Text size={SIZE_TO_TEXT_SIZE_MAP[size]} type={EFontType.PRIMARY}>
242
+ Скрытый контент
243
+ </Text>
244
+ </Spoiler>
245
+ </div>
246
+ ))}
247
+ </div>
248
+ );
249
+ ```
250
+
251
+ ### With right block
252
+
253
+ `stories/Spoiler/examples/WithRightBlock.tsx`
254
+
255
+ ```tsx
256
+ import React from "react";
257
+ import { Spoiler, Text, EComponentSize, ETextSize, EFontType } from "@sberbusiness/triplex-next";
258
+
259
+ export const WithRightBlock = () => (
260
+ <Spoiler
261
+ labelExpand="Развернуть"
262
+ labelCollapse="Свернуть"
263
+ size={EComponentSize.MD}
264
+ rightBlock={
265
+ <Text size={ETextSize.B3} type={EFontType.SECONDARY}>
266
+ 12 документов
267
+ </Text>
268
+ }
269
+ >
270
+ <Text size={ETextSize.B3} type={EFontType.PRIMARY}>
271
+ Скрытый контент
272
+ </Text>
273
+ </Spoiler>
274
+ );
275
+ ```
276
+
277
+ ### Controlled
278
+
279
+ `stories/Spoiler/examples/Controlled.tsx`
280
+
281
+ ```tsx
282
+ import React, { useState } from "react";
283
+ import { Spoiler, Text, EComponentSize, ETextSize, EFontType } from "@sberbusiness/triplex-next";
284
+
285
+ export const Controlled = () => {
286
+ const [expanded, setExpanded] = useState(false);
287
+
288
+ return (
289
+ <Spoiler
290
+ expanded={expanded}
291
+ toggle={setExpanded}
292
+ labelExpand="Развернуть"
293
+ labelCollapse="Свернуть"
294
+ size={EComponentSize.MD}
295
+ >
296
+ <Text size={ETextSize.B3} type={EFontType.PRIMARY}>
297
+ Скрытый контент
298
+ </Text>
299
+ </Spoiler>
300
+ );
301
+ };
302
+ ```
303
+