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