@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
@@ -0,0 +1,633 @@
1
+ ---
2
+ component: CarouselPrevButton
3
+ category: Carousel
4
+ related: [Carousel, ButtonIcon]
5
+ tokens:
6
+ - Carousel.Button_BackgroundColor_Default
7
+ - Carousel.Button_BackgroundColor_Hover
8
+ - Carousel.Button_BackgroundColor_Active
9
+ - Carousel.Button_BackgroundColor_Disabled
10
+ - Carousel.Button_BorderColor
11
+ - Button.Icon_Shadow_Focus
12
+ stories: stories/Carousel/Carousel.stories.tsx
13
+ version: "1.0"
14
+ ---
15
+
16
+ # CarouselPrevButton
17
+
18
+ ## Назначение
19
+
20
+ Кнопка перехода назад в составном `Carousel`. Рендерит `ButtonIcon`;
21
+ направление, край и переход берёт из контекста карусели.
22
+
23
+ Используй внутри `Carousel.Viewport` для навигации мышью и клавиатурой.
24
+ Для отдельного действия с иконкой используй `ButtonIcon`; для прямого выбора
25
+ страницы карусели — `Carousel.Indicators` в режиме `PAGE`.
26
+ На устройствах с `(pointer: coarse)` компонент возвращает `null`, навигацию
27
+ жестами обеспечивает `Carousel.Viewport`.
28
+
29
+ Публичное обращение — `Carousel.PrevButton`. Именованного экспорта
30
+ `CarouselPrevButton` и отдельного интерфейса его props в barrel пакета нет.
31
+
32
+ ```tsx
33
+ import { Carousel } from "@sberbusiness/triplex-next";
34
+
35
+ <Carousel>
36
+ <Carousel.Viewport style={{ width: 320, height: 160 }}>
37
+ <Carousel.Track>
38
+ <Carousel.Item index={0} style={{ width: 240 }}>Первый слайд</Carousel.Item>
39
+ <Carousel.Item index={1} style={{ width: 240 }}>Второй слайд</Carousel.Item>
40
+ </Carousel.Track>
41
+ <Carousel.PrevButton aria-label="Previous slide" />
42
+ <Carousel.NextButton aria-label="Next slide" />
43
+ </Carousel.Viewport>
44
+ </Carousel>
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Варианты и props
50
+
51
+ Обязательных custom-props нет. Компонент принимает `IButtonIconProps`:
52
+
53
+ | Prop | Назначение и ограничения |
54
+ |---|---|
55
+ | `children` | Заменяет стандартную иконку: стрелку влево в горизонтальной карусели и вверх в вертикальной. `0`, `false` и пустая строка тоже дают стандартную иконку |
56
+ | `shape` | Форма `ButtonIcon`: `EButtonIconShape.SQUIRCLE` по умолчанию либо `CIRCLE` |
57
+ | `active` | Активное оформление иконки из `ButtonIcon`; с текущим слайдом не связано |
58
+ | `disabled` | Нативно отключает кнопку и исключает её из табуляции; от края карусели не зависит (см. «Граница и клик») |
59
+ | `onClick` | Вызывается после внутреннего перехода, в начале ленты — без него (см. «Граница и клик») |
60
+ | `className`, `style`, `aria-*`, `data-*`, остальные атрибуты `<button>` | Передаются через `ButtonIcon` на нативную кнопку; `className` объединяется с классами навигации |
61
+ | `ref` | Указывает на `HTMLButtonElement`; на coarse-устройстве — `null` |
62
+
63
+ `type` по умолчанию `"button"`, переопределяется нативным prop. Размер
64
+ задаёт иконка.
65
+
66
+ ### Граница и клик
67
+
68
+ - `aria-disabled` всегда равен `atStart`, пользовательское значение
69
+ перезаписывается. В начале ленты кнопка остаётся enabled и фокусируемой.
70
+ - Без нативного `disabled` (он блокирует оба обработчика):
71
+ - при `atStart=false` сначала вызывается `prevSlide`, затем `onClick(event)`;
72
+ `preventDefault()` в `onClick` переход не отменяет;
73
+ - при `atStart=true` вызывается только `onClick`.
74
+ - Шаг перехода в режимах `ITEM` / `PAGE` — см. `Carousel-ai.md`.
75
+
76
+ ---
77
+
78
+ ## Дизайн-токены
79
+
80
+ Фон и граница определяются стилями карусели:
81
+
82
+ ```text
83
+ Carousel.Button_BackgroundColor_Default
84
+ Carousel.Button_BackgroundColor_Hover
85
+ Carousel.Button_BackgroundColor_Active
86
+ Carousel.Button_BackgroundColor_Disabled
87
+ Carousel.Button_BorderColor
88
+ ```
89
+
90
+ Контур фокуса приходит из `ButtonIcon`:
91
+
92
+ ```text
93
+ Button.Icon_Shadow_Focus
94
+ ```
95
+
96
+ `Carousel.Button_BackgroundColor_Disabled` применяется по `aria-disabled=true`;
97
+ нативный `disabled` этот фон не включает.
98
+
99
+ Переопределяются через `ThemeProvider` (prop `tokens`) — см.
100
+ [ThemeProvider-ai.md](../ThemeProvider/ThemeProvider-ai.md), раздел
101
+ «Как переопределять токены». Источники значений —
102
+ `src/components/DesignTokens/components/Carousel.ts` и `Button.ts`.
103
+ Цвет стандартной иконки задаёт палитра `@sberbusiness/icons-next` с индексом 7.
104
+
105
+ ---
106
+
107
+ ## Инварианты
108
+
109
+ - Сохраняются `forwardRef`, `displayName="Carousel.PrevButton"`, публичное
110
+ статическое поле `Carousel.PrevButton`, `IButtonIconProps` и barrel-экспорты.
111
+ - Внешний DOM-узел — `<span>` `IconWrapper` с `display: contents`. На него
112
+ уходит `active`; нативный `disabled` получают и `<span>`, и `<button>`.
113
+ - Кнопка работает только внутри `Carousel`.
114
+ - Реализация общая с `Carousel.NextButton` во внутреннем `CarouselNavButton`:
115
+ правка в нём меняет обе кнопки.
116
+ - При `(pointer: coarse)` не рендерится и `<span>`; нужен `window.matchMedia`.
117
+ - Стандартную иконку дают все falsy `children` (см. «Варианты и props»);
118
+ переход на nullish-проверку меняет контракт.
119
+ - Классы `navButton`, `prev` и классы ориентации на предке сохраняются:
120
+ кнопка находится слева по центру горизонтального `Viewport` и сверху
121
+ по центру вертикального, с отступом 16 px.
122
+ - По умолчанию кнопка прозрачна (`opacity: 0`); появляется при hover
123
+ `Viewport` либо собственном `:focus-visible`.
124
+
125
+ ---
126
+
127
+ ## Accessibility
128
+
129
+ - Стрелки клавиатуры не обрабатываются, только нативные Enter/Space.
130
+ - На границе кнопка остаётся в порядке Tab и сохраняет фокус. Enter/Space
131
+ вызывают пользовательский `onClick`, но не переход; нативный `disabled`
132
+ исключает кнопку из Tab и блокирует оба обработчика.
133
+ - При смене `(pointer: coarse)` кнопка удаляется из DOM, а её ref становится
134
+ `null`; когда запрос снова возвращает `false`, кнопка рендерится заново.
135
+ - Доступное имя задаёт потребитель через `aria-label` или `aria-labelledby`.
136
+ - Начало ленты объявляется через `aria-disabled` (см. «Граница и клик»).
137
+ - `:focus-visible` даёт контур `Button.Icon_Shadow_Focus`. Прокрутка не
138
+ переносит фокус на слайд.
139
+ - Известное ограничение: `prefers-reduced-motion` отключает только переход
140
+ ленты, плавное появление стрелки остаётся.
141
+ - Связь `aria-controls` с областью слайдов и доступное имя карусели задаёт
142
+ потребитель при необходимости; автоматически они не создаются.
143
+
144
+ ---
145
+
146
+ ## Связанные компоненты
147
+
148
+ - `Carousel` — родитель, источник направления, края и перехода.
149
+ - [ButtonIcon](../Button/ButtonIcon-ai.md) — рендерится внутри; даёт props, ref, форму и контур фокуса.
150
+ - `CarouselViewport` — область позиционирования и hover; обрабатывает touch-жесты.
151
+ - `CarouselNextButton` — парная кнопка прямого направления, доступная как
152
+ `Carousel.NextButton`.
153
+
154
+ ---
155
+
156
+ ## Stories
157
+
158
+ Основные истории: `stories/Carousel/Carousel.stories.tsx`
159
+ Файлы примеров: `stories/Carousel/examples/`
160
+
161
+ | Story | Example file | Что демонстрирует |
162
+ |---|---|---|
163
+ | `Playground` | `Playground.tsx` | Направление и режим карусели; кнопки следуют контексту |
164
+ | `Default` | `Default.tsx` | Горизонтальная лента с кнопками навигации |
165
+ | `ScrollModes` | `ScrollModes.tsx` | Переключение элементов/страниц с тем же составным API |
166
+ | `Orientations` | `Orientations.tsx` | Горизонтальное/вертикальное положение и направление иконки |
167
+ | `Production` | `Production.tsx` | Карусель карточек действий |
168
+ | `DynamicIndicators` | `DynamicIndicators.tsx` | Кнопка назад вместе с постраничными индикаторами |
169
+ | `VisualTests` | `VisualTests.tsx` | Начало ленты; нативный disabled и circle в вертикальной карусели. Фокус и hover общие для обеих кнопок и снимаются на `NextButton` |
170
+
171
+ ---
172
+
173
+ ## История изменений
174
+
175
+ | Дата | Изменение |
176
+ |---|---|
177
+ | 2026-10-29 | Уточнены Tab, Enter/Space и жизненный цикл ref при смене указателя; контракт проверен в отдельном `CarouselPrevButton.test.tsx`. |
178
+ | 2026-10-21 | Создан документ. |
179
+
180
+ ---
181
+
182
+ ## Примеры использования
183
+
184
+ ### Default
185
+
186
+ `stories/Carousel/examples/Default.tsx`
187
+
188
+ ```tsx
189
+ import React from "react";
190
+ import { Carousel } from "@sberbusiness/triplex-next";
191
+
192
+ const BASE_ITEM_STYLE: React.CSSProperties = {
193
+ display: "flex",
194
+ alignItems: "center",
195
+ justifyContent: "center",
196
+ boxSizing: "border-box",
197
+ borderRadius: "8px",
198
+ color: "#ffffff",
199
+ fontSize: "24px",
200
+ fontWeight: "bold",
201
+ userSelect: "none",
202
+ };
203
+
204
+ export const Default = () => {
205
+ const itemSizes = [92, 168, 220, 244, 252, 256, 252, 244, 220, 168, 92];
206
+ const items = itemSizes.map((size, index) => {
207
+ const totalItems = itemSizes.length;
208
+ const hue = (index / (totalItems - 1)) * 280;
209
+
210
+ return {
211
+ id: index + 1,
212
+ size,
213
+ backgroundColor: `hsl(${hue}, 50%, 50%)`,
214
+ };
215
+ });
216
+
217
+ const boxStyle: React.CSSProperties = {
218
+ width: "100%",
219
+ height: "256px",
220
+ maxWidth: "512px",
221
+ };
222
+
223
+ return (
224
+ <div style={boxStyle}>
225
+ <Carousel>
226
+ <Carousel.Viewport>
227
+ <Carousel.Track>
228
+ {items.map((item, index) => (
229
+ <Carousel.Item
230
+ key={item.id}
231
+ index={index}
232
+ style={{
233
+ ...BASE_ITEM_STYLE,
234
+ width: item.size,
235
+ height: "100%",
236
+ backgroundColor: item.backgroundColor,
237
+ }}
238
+ >
239
+ {item.id}
240
+ </Carousel.Item>
241
+ ))}
242
+ </Carousel.Track>
243
+ <Carousel.PrevButton aria-label="Previous slide" />
244
+ <Carousel.NextButton aria-label="Next slide" />
245
+ </Carousel.Viewport>
246
+ </Carousel>
247
+ </div>
248
+ );
249
+ };
250
+ ```
251
+
252
+ ### ScrollModes
253
+
254
+ `stories/Carousel/examples/ScrollModes.tsx`
255
+
256
+ ```tsx
257
+ import React from "react";
258
+ import { Carousel, ECarouselScrollMode } from "@sberbusiness/triplex-next";
259
+
260
+ interface ScrollModeItemProps {
261
+ scrollMode: ECarouselScrollMode;
262
+ }
263
+
264
+ const BASE_ITEM_STYLE: React.CSSProperties = {
265
+ display: "flex",
266
+ alignItems: "center",
267
+ justifyContent: "center",
268
+ boxSizing: "border-box",
269
+ height: "256px",
270
+ borderRadius: "8px",
271
+ color: "#ffffff",
272
+ fontSize: "24px",
273
+ fontWeight: "bold",
274
+ userSelect: "none",
275
+ };
276
+
277
+ const ScrollModeItem = ({ scrollMode }: ScrollModeItemProps) => {
278
+ const itemSizes = [92, 168, 220, 244, 252, 256, 252, 244, 220, 168, 92];
279
+ const items = itemSizes.map((size, index) => {
280
+ const totalItems = itemSizes.length;
281
+ const hue = (index / (totalItems - 1)) * 280;
282
+
283
+ return {
284
+ id: index + 1,
285
+ size,
286
+ backgroundColor: `hsl(${hue}, 50%, 50%)`,
287
+ };
288
+ });
289
+
290
+ const containerStyle: React.CSSProperties = {
291
+ maxWidth: "512px",
292
+ };
293
+
294
+ return (
295
+ <div style={containerStyle}>
296
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{scrollMode.toUpperCase()}</div>
297
+ <Carousel scrollMode={scrollMode}>
298
+ <Carousel.Viewport>
299
+ <Carousel.Track>
300
+ {items.map((item, index) => (
301
+ <Carousel.Item
302
+ key={item.id}
303
+ index={index}
304
+ style={{
305
+ ...BASE_ITEM_STYLE,
306
+ width: item.size,
307
+ backgroundColor: item.backgroundColor,
308
+ }}
309
+ >
310
+ {item.id}
311
+ </Carousel.Item>
312
+ ))}
313
+ </Carousel.Track>
314
+ <Carousel.PrevButton aria-label="Previous slide" />
315
+ <Carousel.NextButton aria-label="Next slide" />
316
+ </Carousel.Viewport>
317
+ <Carousel.Indicators />
318
+ </Carousel>
319
+ </div>
320
+ );
321
+ };
322
+
323
+ const SCROLL_MODES = Object.values(ECarouselScrollMode);
324
+
325
+ export const ScrollModes = () => (
326
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
327
+ {SCROLL_MODES.map((scrollMode) => (
328
+ <ScrollModeItem key={scrollMode} scrollMode={scrollMode} />
329
+ ))}
330
+ </div>
331
+ );
332
+ ```
333
+
334
+ ### Orientations
335
+
336
+ `stories/Carousel/examples/Orientations.tsx`
337
+
338
+ ```tsx
339
+ import React from "react";
340
+ import { Carousel, EOrientation } from "@sberbusiness/triplex-next";
341
+
342
+ interface OrientationItemProps {
343
+ orientation: EOrientation;
344
+ }
345
+
346
+ const BASE_ITEM_STYLE: React.CSSProperties = {
347
+ display: "flex",
348
+ alignItems: "center",
349
+ justifyContent: "center",
350
+ boxSizing: "border-box",
351
+ borderRadius: "8px",
352
+ color: "#ffffff",
353
+ fontSize: "24px",
354
+ fontWeight: "bold",
355
+ userSelect: "none",
356
+ };
357
+
358
+ const ORIENTATION_TO_ITEM_DIMENSIONS_MAP: Record<EOrientation, (size: number) => React.CSSProperties> = {
359
+ [EOrientation.HORIZONTAL]: (size) => ({
360
+ width: size,
361
+ height: "100%",
362
+ }),
363
+ [EOrientation.VERTICAL]: (size) => ({
364
+ width: "100%",
365
+ height: size / 2,
366
+ }),
367
+ };
368
+
369
+ const ORIENTATION_TO_GAP_MAP: Record<EOrientation, number> = {
370
+ [EOrientation.HORIZONTAL]: 16,
371
+ [EOrientation.VERTICAL]: 8,
372
+ };
373
+
374
+ const OrientationItem = ({ orientation }: OrientationItemProps) => {
375
+ const itemSizes = [92, 168, 220, 244, 252, 256, 252, 244, 220, 168, 92];
376
+ const items = itemSizes.map((size, index) => {
377
+ const totalItems = itemSizes.length;
378
+ const hue = (index / (totalItems - 1)) * 280;
379
+
380
+ return {
381
+ id: index + 1,
382
+ size,
383
+ backgroundColor: `hsl(${hue}, 50%, 50%)`,
384
+ };
385
+ });
386
+
387
+ const containerStyle: React.CSSProperties = {
388
+ maxWidth: "512px",
389
+ };
390
+
391
+ const viewportStyle: React.CSSProperties = {
392
+ height: "256px",
393
+ };
394
+
395
+ return (
396
+ <div style={containerStyle}>
397
+ <div style={{ marginBottom: 8, fontSize: 16, fontWeight: 700 }}>{orientation.toUpperCase()}</div>
398
+ <Carousel orientation={orientation} gap={ORIENTATION_TO_GAP_MAP[orientation]}>
399
+ <Carousel.Viewport style={viewportStyle}>
400
+ <Carousel.Track>
401
+ {items.map((item, index) => {
402
+ const itemStyle: React.CSSProperties = {
403
+ ...BASE_ITEM_STYLE,
404
+ ...ORIENTATION_TO_ITEM_DIMENSIONS_MAP[orientation](item.size),
405
+ backgroundColor: item.backgroundColor,
406
+ };
407
+
408
+ return (
409
+ <Carousel.Item key={item.id} index={index} style={itemStyle}>
410
+ {item.id}
411
+ </Carousel.Item>
412
+ );
413
+ })}
414
+ </Carousel.Track>
415
+ <Carousel.PrevButton aria-label="Previous slide" />
416
+ <Carousel.NextButton aria-label="Next slide" />
417
+ </Carousel.Viewport>
418
+ <Carousel.Indicators />
419
+ </Carousel>
420
+ </div>
421
+ );
422
+ };
423
+
424
+ const ORIENTATIONS = Object.values(EOrientation);
425
+
426
+ export const Orientations = () => (
427
+ <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
428
+ {ORIENTATIONS.map((orientation) => (
429
+ <OrientationItem key={orientation} orientation={orientation} />
430
+ ))}
431
+ </div>
432
+ );
433
+ ```
434
+
435
+ ### Production
436
+
437
+ `stories/Carousel/examples/Production.tsx`
438
+
439
+ ```tsx
440
+ import React, { useState } from "react";
441
+ import {
442
+ Carousel,
443
+ CardAction,
444
+ ECardRoundingSize,
445
+ ECardTheme,
446
+ ECardContentPaddingSize,
447
+ Title,
448
+ ETitleSize,
449
+ EFontWeightTitle,
450
+ Text,
451
+ ETextSize,
452
+ EFontType,
453
+ Gap,
454
+ Link,
455
+ Button,
456
+ EButtonTheme,
457
+ EComponentSize,
458
+ } from "@sberbusiness/triplex-next";
459
+ import { DefaulticonStrokePrdIcon20 } from "@sberbusiness/icons-next";
460
+
461
+ const CARDS_IDS = Array.from({ length: 6 }, (_, i) => i);
462
+
463
+ const CardBody = () => (
464
+ <CardAction.Content.Body>
465
+ {[1, 2, 3].map((item) => (
466
+ <div key={item} style={{ display: "flex", alignItems: "center", marginTop: item > 1 ? "16px" : "0" }}>
467
+ <DefaulticonStrokePrdIcon20 paletteIndex={5} />
468
+ <Text size={ETextSize.B3} style={{ marginLeft: "8px" }}>
469
+ List item text
470
+ </Text>
471
+ </div>
472
+ ))}
473
+ <Gap size={8} />
474
+ <Text tag="div" type={EFontType.SECONDARY} size={ETextSize.B4}>
475
+ This message provides additional context or highlights important information to note.
476
+ </Text>
477
+ <Gap size={8} />
478
+ <Text tag="div" type={EFontType.PRIMARY} size={ETextSize.B3}>
479
+ <Link onKeyDown={(event) => event.stopPropagation()} onClick={(event) => event.stopPropagation()}>
480
+ Link text
481
+ </Link>
482
+ </Text>
483
+ </CardAction.Content.Body>
484
+ );
485
+
486
+ export const Production = () => {
487
+ const [selectedId, setSelectedId] = useState<number | null>(null);
488
+
489
+ return (
490
+ <div style={{ width: "100%", maxWidth: "752px" }}>
491
+ <Carousel viewportPadding={8}>
492
+ <Carousel.Viewport>
493
+ <Carousel.Track>
494
+ {CARDS_IDS.map((id, index) => {
495
+ const selected = selectedId === id;
496
+
497
+ return (
498
+ <Carousel.Item
499
+ key={id}
500
+ index={index}
501
+ style={{
502
+ width: "216px",
503
+ height: "100%",
504
+ boxSizing: "border-box",
505
+ }}
506
+ >
507
+ <CardAction
508
+ roundingSize={ECardRoundingSize.MD}
509
+ theme={ECardTheme.GENERAL}
510
+ selected={selected}
511
+ toggle={() => setSelectedId(selected ? null : id)}
512
+ >
513
+ <CardAction.Media
514
+ style={{
515
+ backgroundImage: "url(assets/images/evotor.png)",
516
+ height: "129px",
517
+ }}
518
+ />
519
+ <CardAction.Content paddingSize={ECardContentPaddingSize.SM}>
520
+ <CardAction.Content.Header>
521
+ <Title tag="div" size={ETitleSize.H3} weight={EFontWeightTitle.REGULAR}>
522
+ Title Text
523
+ </Title>
524
+ </CardAction.Content.Header>
525
+
526
+ <CardBody />
527
+
528
+ <CardAction.Content.Footer>
529
+ <Button
530
+ theme={
531
+ selected ? EButtonTheme.SECONDARY_LIGHT : EButtonTheme.SECONDARY
532
+ }
533
+ size={EComponentSize.SM}
534
+ onKeyDown={(event) => event.stopPropagation()}
535
+ onClick={(event) => event.stopPropagation()}
536
+ >
537
+ Button text
538
+ </Button>
539
+ </CardAction.Content.Footer>
540
+ </CardAction.Content>
541
+ </CardAction>
542
+ </Carousel.Item>
543
+ );
544
+ })}
545
+ </Carousel.Track>
546
+ <Carousel.PrevButton aria-label="Previous slide" />
547
+ <Carousel.NextButton aria-label="Next slide" />
548
+ </Carousel.Viewport>
549
+ </Carousel>
550
+ </div>
551
+ );
552
+ };
553
+ ```
554
+
555
+ ### DynamicIndicators
556
+
557
+ `stories/Carousel/examples/DynamicIndicators.tsx`
558
+
559
+ ```tsx
560
+ import React from "react";
561
+ import { Carousel, ECarouselScrollMode } from "@sberbusiness/triplex-next";
562
+
563
+ const BASE_ITEM_STYLE: React.CSSProperties = {
564
+ display: "flex",
565
+ alignItems: "center",
566
+ justifyContent: "center",
567
+ boxSizing: "border-box",
568
+ borderRadius: "8px",
569
+ color: "#ffffff",
570
+ fontSize: "24px",
571
+ fontWeight: "bold",
572
+ userSelect: "none",
573
+ };
574
+
575
+ export const DynamicIndicators = () => {
576
+ const itemSizes = Array.from({ length: 20 }, () => 128);
577
+
578
+ const items = itemSizes.map((size, index) => {
579
+ const totalItems = itemSizes.length;
580
+ const hue = (index / (totalItems - 1)) * 280;
581
+
582
+ return {
583
+ id: index + 1,
584
+ size,
585
+ backgroundColor: `hsl(${hue}, 50%, 50%)`,
586
+ };
587
+ });
588
+
589
+ const boxStyle: React.CSSProperties = {
590
+ display: "flex",
591
+ flexDirection: "column",
592
+ gap: "16px",
593
+ width: "100%",
594
+ maxWidth: "512px",
595
+ };
596
+
597
+ const containerStyle: React.CSSProperties = {
598
+ width: "100%",
599
+ height: "256px",
600
+ };
601
+
602
+ return (
603
+ <div style={boxStyle}>
604
+ <div style={containerStyle}>
605
+ <Carousel scrollMode={ECarouselScrollMode.PAGE}>
606
+ <Carousel.Viewport>
607
+ <Carousel.Track>
608
+ {items.map((item, index) => (
609
+ <Carousel.Item
610
+ key={item.id}
611
+ index={index}
612
+ style={{
613
+ ...BASE_ITEM_STYLE,
614
+ width: item.size,
615
+ height: "100%",
616
+ backgroundColor: item.backgroundColor,
617
+ }}
618
+ >
619
+ {item.id}
620
+ </Carousel.Item>
621
+ ))}
622
+ </Carousel.Track>
623
+ <Carousel.PrevButton aria-label="Previous slide" />
624
+ <Carousel.NextButton aria-label="Next slide" />
625
+ </Carousel.Viewport>
626
+ <Carousel.Indicators />
627
+ </Carousel>
628
+ </div>
629
+ </div>
630
+ );
631
+ };
632
+ ```
633
+