@sberbusiness/triplex-next-mcp-server 1.46.0-beta → 1.48.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.
- package/README.md +7 -7
- package/bundle/components/AmountField.md +222 -323
- package/bundle/components/Avatar.md +138 -146
- package/bundle/components/CardStatic.md +402 -0
- package/bundle/components/CheckboxTree.md +157 -215
- package/bundle/components/CheckboxTreeExtended.md +7 -7
- package/bundle/components/ChipGroup.md +1 -1
- package/bundle/components/ChipMonthYearPicker.md +4 -4
- package/bundle/components/ChipSuggest.md +7 -6
- package/bundle/components/CollapsibleTree.md +8 -4
- package/bundle/components/CollapsibleTreeExtended.md +8 -6
- package/bundle/components/Confirm.md +346 -281
- package/bundle/components/DateRange.md +351 -210
- package/bundle/components/FooterPage.md +1 -0
- package/bundle/components/FormField.md +11 -4
- package/bundle/components/FormGroup.md +3 -2
- package/bundle/components/LightBox.md +8 -0
- package/bundle/components/ListMaster.md +2 -2
- package/bundle/components/ListTableItem.md +6 -6
- package/bundle/components/MonthYearField.md +15 -4
- package/bundle/components/Slider.md +389 -97
- package/bundle/components/SliderRange.md +486 -105
- package/bundle/components/StatusTracker.md +386 -94
- package/bundle/components/Stepper.md +355 -102
- package/bundle/components/StepperExtended.md +633 -0
- package/bundle/components/SuggestField.md +1049 -96
- package/bundle/components/SwipeableArea.md +7 -7
- package/bundle/components/Tabs.md +265 -92
- package/bundle/components/TabsExtended.md +18 -18
- package/bundle/components/TabsLine.md +301 -127
- package/bundle/components/TagColor.md +187 -66
- package/bundle/components/TagGroup.md +184 -48
- package/bundle/components/TextareaField.md +278 -70
- package/bundle/components/TopOverlay.md +17 -1
- package/bundle/components/TreeView.md +16 -7
- package/bundle/components/TriggerClickOnKeyDownEvent.md +277 -0
- package/bundle/components/UploadZone.md +318 -0
- package/bundle/guides/codestyle.md +16 -1
- package/bundle/guides/commits.md +47 -1
- package/bundle/guides/tests.md +23 -2
- package/bundle/manifest.json +48 -21
- package/bundle/release-notes/1.47.0.mdx +115 -0
- package/bundle/release-notes/1.48.0.mdx +68 -0
- package/bundle/release-notes/1.49.0.mdx +7 -0
- package/bundle/tokens.json +3 -3
- package/dist/index.js +220 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Slider
|
|
3
|
-
category:
|
|
4
|
-
figma-node: ""
|
|
5
|
-
figma-file: ""
|
|
3
|
+
category: Slider
|
|
6
4
|
related: [SliderExtended, SliderRange]
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/Slider/Slider.stories.tsx
|
|
@@ -13,145 +11,439 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
если передан `renderTooltipContent`. Под капотом — `SliderExtended` с
|
|
19
|
-
ровно одним `Dot`.
|
|
14
|
+
Слайдер с одним ползунком — готовая сборка `SliderExtended`: полоса, ползунок, трек и метки
|
|
15
|
+
уже собраны, потребителю остаётся задать диапазон, шаг, метки и владеть значением.
|
|
20
16
|
|
|
21
|
-
Используй когда:
|
|
22
|
-
|
|
23
|
-
компоновки (свой Tooltip, отдельные Marks) — `SliderExtended`.
|
|
17
|
+
Используй когда: пользователь выбирает одно число из диапазона и точность ввода не важна —
|
|
18
|
+
сумма, срок, процент, громкость.
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
## Файловая структура
|
|
20
|
+
Не используй когда:
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
- Нужен выбор диапазона двумя ползунками — возьми `SliderRange`.
|
|
23
|
+
- Нужен нестандартный состав частей (без меток, без трека, своё содержимое ползунка) или
|
|
24
|
+
собственная разметка подсказки — собери слайдер из `SliderExtended`.
|
|
25
|
+
- Нужно ввести точное число — слайдер не заменяет `NumberField` / `AmountField`; при крупных
|
|
26
|
+
диапазонах их обычно ставят рядом со слайдером.
|
|
27
|
+
- Ползунку нужна текстовая подпись для скринридера — `Slider` её передать не позволяет
|
|
28
|
+
(см. Accessibility), собирай из `SliderExtended`.
|
|
35
29
|
|
|
36
30
|
---
|
|
37
31
|
|
|
38
32
|
## Варианты и props
|
|
39
33
|
|
|
40
|
-
###
|
|
34
|
+
### Обязательные props
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
| Prop | Тип | Описание |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `min` | `number` | Минимальное значение диапазона |
|
|
39
|
+
| `max` | `number` | Максимальное значение диапазона |
|
|
40
|
+
| `size` | `EComponentSize.MD \| EComponentSize.LG` | Размер. `SM` не поддерживается |
|
|
41
|
+
| `value` | `number` | Текущее значение ползунка |
|
|
42
|
+
| `onChange` | `(value: number) => void` | Вызывается со значением шага, на который переместился ползунок |
|
|
43
|
+
| `marks` | `ISliderMark[]` | Метки под полосой: `{ value: number; label: React.ReactNode }` |
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
### Опциональные props
|
|
46
|
+
|
|
47
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
48
48
|
|---|---|---|---|
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
| `step` | `number \| number[]` | `1` | Длина шага либо массив значений шагов. В массиве первое значение равно `min`, последнее — `max` |
|
|
50
|
+
| `reverse` | `boolean` | `false` | Значения возрастают справа налево |
|
|
51
|
+
| `disabled` | `boolean` | `false` | Слайдер не активен: части не реагируют на курсор и выпадают из табуляции |
|
|
52
|
+
| `renderTooltipContent` | `(value: number) => React.ReactNode` | — | Содержимое подсказки над ползунком. Без этого prop подсказка не рендерится вовсе |
|
|
53
|
+
|
|
54
|
+
Остальные атрибуты `React.HTMLAttributes<HTMLDivElement>` (включая `className`, `id`,
|
|
55
|
+
`aria-*`, `data-*`) уходят на **корневой `div`** слайдера. `children` запрещён
|
|
56
|
+
(`children?: never`): разметку собирает сам компонент.
|
|
57
|
+
|
|
58
|
+
### Особенности поведения
|
|
59
|
+
|
|
60
|
+
- **Значение контролируемое.** Компонент не хранит значение: он рисует позицию по `value` и
|
|
61
|
+
сообщает новое значение через `onChange`. Без обновления `value` снаружи ползунок не
|
|
62
|
+
двигается — включая `disabled`-слайдер, где источник правды тем более остаётся у
|
|
63
|
+
потребителя.
|
|
64
|
+
- **`step` числом строит шаги как `[...range(min, max, step), max]`.** Последний шаг всегда
|
|
65
|
+
равен `max`, даже если он не кратен шагу: при `min: 0, max: 10, step: 3` шаги равны
|
|
66
|
+
`0, 3, 6, 9, 10`.
|
|
67
|
+
- **`step` массивом задаёт произвольную шкалу.** Шаги равны визуально, а не по значению —
|
|
68
|
+
так делается шкала сумм с укрупняющимся шагом (см. story `Amounts`). Массив, собранный
|
|
69
|
+
инлайн в JSX, пересчитывает шаги на каждом рендере потребителя; вынеси его в константу.
|
|
70
|
+
- **Пустой массив шагов (`step: []`) не рендерит ничего** — `SliderExtended` возвращает `null`.
|
|
71
|
+
- **Значение вне диапазона не отбрасывается, а зажимается** при расчёте позиции: ползунок
|
|
72
|
+
встаёт на край. В `onChange` при этом уходят только значения из массива шагов.
|
|
73
|
+
- **Клик по полосе и по метке двигает ползунок** на ближайший шаг / на значение метки.
|
|
74
|
+
- **`marks` не обязаны совпадать с шагами.** Метка со значением вне `[min, max]` прижимается
|
|
75
|
+
к краю полосы; `value` метки используется как React-ключ, поэтому дубли значений дадут
|
|
76
|
+
предупреждение о неуникальных ключах. Подпись рендерится через `Text` (`B3` для `LG`,
|
|
77
|
+
`B4` для `MD`).
|
|
78
|
+
- **Подсказка видна только при `:hover` и `:focus` ползунка** — управляется стилями, не
|
|
79
|
+
props. Постоянно видимой подсказки нет, поэтому текущее значение обычно дублируют рядом со
|
|
80
|
+
слайдером (так сделано во всех stories).
|
|
81
|
+
- **Ширину и внешние отступы задаёт потребитель.** Своей ширины у слайдера нет; собственные
|
|
82
|
+
вертикальные отступы (под ползунок и под метки) он добавляет сам.
|
|
64
83
|
|
|
65
|
-
|
|
84
|
+
---
|
|
66
85
|
|
|
67
|
-
|
|
86
|
+
## Дизайн-токены
|
|
68
87
|
|
|
69
|
-
|
|
70
|
-
|
|
88
|
+
Собственных токенов у компонента нет: своих стилей `Slider` не имеет и целиком состоит из
|
|
89
|
+
`SliderExtended`. Внешний вид настраивается токенами группы `Slider` — их список и порядок
|
|
90
|
+
переопределения см. в `SliderExtended-ai.md` → «Дизайн-токены». Значения по умолчанию —
|
|
91
|
+
`src/components/DesignTokens/components/Slider.ts`.
|
|
71
92
|
|
|
72
93
|
---
|
|
73
94
|
|
|
74
|
-
##
|
|
95
|
+
## Инварианты
|
|
75
96
|
|
|
76
|
-
|
|
97
|
+
- **`Slider` пробрасывает `ref` на корневой `div`:** обёрнут в `React.forwardRef`, `ref`
|
|
98
|
+
уходит в `SliderExtended`, который вешает его на свой корень. `forwardRef` не убирать —
|
|
99
|
+
это публичный контракт. У `SliderExtended` и всех его частей `forwardRef` есть — тоже не
|
|
100
|
+
убирать. Исключение в семействе — `SliderRange`: это class-компонент, и `ref` на нём даёт
|
|
101
|
+
инстанс класса, а не корневой `div`.
|
|
102
|
+
- **`ISliderProps` наследуется от `ISliderExtendedProps` и `ISliderExtendedDotProps`**
|
|
103
|
+
(`Omit<..., "onChange" | "step">` + `Pick<..., "onChange" | "value">`). Переименование
|
|
104
|
+
props в `SliderExtended` ломает публичный API `Slider` — менять только вместе.
|
|
105
|
+
- **Порядок частей в разметке (`Rail` → `Dot` → `Track` → `Marks`) и наличие `Rail`
|
|
106
|
+
обязательны.** Позиции клика и перетаскивания считаются от DOM-узла полосы; без `Rail`
|
|
107
|
+
работает только клавиатура. `Tooltip` обязан лежать внутри `Dot`.
|
|
108
|
+
- **`renderTooltipContent` вызывается на каждом рендере** с текущим `value` — держи её
|
|
109
|
+
дешёвой и без side effects.
|
|
110
|
+
- **`children?: never`** — часть публичного API: состав слайдера фиксирован, расширяется он
|
|
111
|
+
только через `SliderExtended`.
|
|
112
|
+
- Реализация остаётся React 17-совместимой (без `useId`, `useSyncExternalStore` и прочих
|
|
113
|
+
React 18-only API): код синхронизируется в `release-0`.
|
|
77
114
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<SliderExtended.Dot value={value} onChange={onChange}>
|
|
82
|
-
{renderTooltipContent && <SliderExtended.Tooltip ...>{renderTooltipContent(value)}</SliderExtended.Tooltip>}
|
|
83
|
-
</SliderExtended.Dot>
|
|
84
|
-
<SliderExtended.Track />
|
|
85
|
-
<SliderExtended.Marks>
|
|
86
|
-
{marks.map(m => <SliderExtended.Mark key={m.value} value={m.value}>{m.label}</SliderExtended.Mark>)}
|
|
87
|
-
</SliderExtended.Marks>
|
|
88
|
-
</SliderExtended>
|
|
89
|
-
```
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Accessibility
|
|
90
118
|
|
|
91
|
-
-
|
|
92
|
-
|
|
119
|
+
- **Ползунок — `role="slider"`** с `aria-valuemin`, `aria-valuenow`, `aria-valuemax` из
|
|
120
|
+
`min` / `value` / `max` (рендерится `SliderExtended.Dot`).
|
|
121
|
+
- **Подпись ползунку `Slider` передать нельзя.** Все лишние props уходят на корневой `div`,
|
|
122
|
+
а не на ползунок, поэтому `aria-label` / `aria-labelledby` окажутся на контейнере без роли.
|
|
123
|
+
Если подпись или `aria-valuetext` (нелинейная шкала, суммы, единицы измерения) обязательны —
|
|
124
|
+
собирай слайдер из `SliderExtended` и передавай атрибуты прямо в `SliderExtended.Dot`.
|
|
125
|
+
- **Клавиатура:** `ArrowLeft` / `ArrowDown` — шаг назад, `ArrowRight` / `ArrowUp` — шаг
|
|
126
|
+
вперёд. Обработчики вызывают `preventDefault`, чтобы страница не скроллилась.
|
|
127
|
+
`Home` / `End` / `PageUp` / `PageDown` не поддерживаются.
|
|
128
|
+
- **Трек в табуляцию не попадает:** перетаскивание трека клавиатурой имеет смысл только для
|
|
129
|
+
двух ползунков, а у `Slider` он один.
|
|
130
|
+
- **Метки кликабельны, но не фокусируются** и не читаются как элементы управления: это
|
|
131
|
+
ускоритель для мыши, дублирующий клавиатурное перемещение по шагам.
|
|
132
|
+
- **Подсказка не связана с ползунком через `aria`** — она показывается по `:hover`/`:focus`
|
|
133
|
+
и для скринридера бесполезна; значение доступно через `aria-valuenow`.
|
|
134
|
+
- **`disabled` только визуальный и мышиный.** Части получают `pointer-events: none` и
|
|
135
|
+
`tabIndex -1`, но нативного `disabled` у `span` нет: программно установленный фокус
|
|
136
|
+
оставляет клавиатурное перемещение работающим. Источником правды остаётся `value`
|
|
137
|
+
потребителя.
|
|
93
138
|
|
|
94
|
-
|
|
139
|
+
---
|
|
95
140
|
|
|
96
|
-
|
|
141
|
+
## Связанные компоненты
|
|
97
142
|
|
|
98
|
-
|
|
143
|
+
- `SliderExtended` (`src/components/SliderExtended/`) — составной слайдер, из которого
|
|
144
|
+
собран `Slider`. Нужен, когда состава `Slider` не хватает: свой набор частей, своя
|
|
145
|
+
подсказка, `aria`-атрибуты на ползунке.
|
|
146
|
+
- `SliderRange` (`src/components/SliderRange/`) — тот же слайдер на два ползунка: принимает
|
|
147
|
+
`values` парой, следит за их порядком и прокидывает `draggableTrack`.
|
|
99
148
|
|
|
100
|
-
|
|
149
|
+
---
|
|
101
150
|
|
|
102
|
-
|
|
151
|
+
## Stories
|
|
103
152
|
|
|
104
|
-
|
|
153
|
+
Основные истории: `stories/Slider/Slider.stories.tsx`
|
|
154
|
+
Файлы примеров: `stories/Slider/examples/Slider/`
|
|
105
155
|
|
|
106
|
-
|
|
156
|
+
| Story | Example file | Что демонстрирует |
|
|
157
|
+
|---|---|---|
|
|
158
|
+
| `Playground` | `Playground.tsx` | Интерактивный подбор `min`, `max`, `step`, `marks`, `size`, `disabled`, `reverse` |
|
|
159
|
+
| `Default` | `Default.tsx` | Слайдер с метками и шагом по умолчанию |
|
|
160
|
+
| `Sizes` | `Sizes.tsx` | Размеры MD и LG |
|
|
161
|
+
| `WithTooltip` | `WithTooltip.tsx` | Подсказка над ползунком через `renderTooltipContent` |
|
|
162
|
+
| `WithCustomSteps` | `WithCustomSteps.tsx` | Шаги заданы массивом значений |
|
|
163
|
+
| `Disabled` | `Disabled.tsx` | Неактивный слайдер |
|
|
164
|
+
| `Reverse` | `Reverse.tsx` | Значения возрастают справа налево |
|
|
165
|
+
| `Amounts` | `Amounts.tsx` | Production-like шкала сумм с неравномерным шагом: слайдер работает с индексами шкалы |
|
|
166
|
+
| `VisualTests` | `VisualTests.tsx` | Размеры, шаги массивом, реверс и неактивное состояние; `play` ставит фокус на первый ползунок, чтобы в кадр попали обводка фокуса и подсказка |
|
|
107
167
|
|
|
108
|
-
|
|
168
|
+
`Playground` исключён из скриншот-тестов. `WithTooltip` тоже исключён: подсказка скрыта, пока
|
|
169
|
+
ползунок не в фокусе, поэтому её кадр повторяет `Default`.
|
|
109
170
|
|
|
110
171
|
---
|
|
111
172
|
|
|
112
|
-
##
|
|
173
|
+
## История изменений
|
|
113
174
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
- **`size: MD | LG`** — `SM` не поддерживается.
|
|
119
|
-
- **`children: never`**.
|
|
120
|
-
- **`value` ∈ `[min, max]`** — потребитель ответственен (валидации нет).
|
|
121
|
-
- **Если `step` — массив**, первое значение = `min`, последнее = `max`.
|
|
122
|
-
- **`FC, не forwardRef`**.
|
|
175
|
+
| Дата | Изменение |
|
|
176
|
+
|---|---|
|
|
177
|
+
| 2026-09-11 | Создан документ. AI-рефакторинг (TRI-77): добавлен `displayName`, props задокументированы JSDoc, из разметки убран избыточный проброс `size` (значение приходит тем же spread'ом). Публичный API props, интерфейсов и barrel-экспортов не изменён. Добавлены unit-тесты, stories переведены на modern pattern. |
|
|
178
|
+
| 2026-09-14 | Правки по ревью (TRI-77): `Slider` обёрнут в `React.forwardRef` и пробрасывает `ref` на корневой `div` — раньше был `React.FC` и `ref` терялся. Тип компонента изменился на `React.ForwardRefExoticComponent`, запись в release notes 1.47.0. |
|
|
123
179
|
|
|
124
180
|
---
|
|
125
181
|
|
|
126
|
-
##
|
|
182
|
+
## Примеры использования
|
|
127
183
|
|
|
128
|
-
|
|
129
|
-
- Keyboard navigation — стрелки (детали в SliderExtendedDot).
|
|
184
|
+
### Default
|
|
130
185
|
|
|
131
|
-
|
|
186
|
+
`stories/Slider/examples/Slider/Default.tsx`
|
|
132
187
|
|
|
133
|
-
|
|
188
|
+
```tsx
|
|
189
|
+
import React, { useState } from "react";
|
|
190
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
191
|
+
|
|
192
|
+
const MARKS = [
|
|
193
|
+
{ value: 0, label: "0" },
|
|
194
|
+
{ value: 35, label: "35" },
|
|
195
|
+
{ value: 66, label: "66" },
|
|
196
|
+
{ value: 100, label: "100" },
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
export const Default = () => {
|
|
200
|
+
const [value, setValue] = useState(35);
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
204
|
+
<div>value = {value}</div>
|
|
205
|
+
<br />
|
|
206
|
+
<Slider min={0} max={100} size={EComponentSize.MD} marks={MARKS} value={value} onChange={setValue} />
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
```
|
|
134
211
|
|
|
135
|
-
|
|
212
|
+
### Sizes
|
|
136
213
|
|
|
137
|
-
|
|
214
|
+
`stories/Slider/examples/Slider/Sizes.tsx`
|
|
138
215
|
|
|
139
|
-
|
|
216
|
+
```tsx
|
|
217
|
+
import React, { useState } from "react";
|
|
218
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
219
|
+
|
|
220
|
+
const MARKS = [
|
|
221
|
+
{ value: 0, label: "0" },
|
|
222
|
+
{ value: 50, label: "50" },
|
|
223
|
+
{ value: 100, label: "100" },
|
|
224
|
+
];
|
|
225
|
+
|
|
226
|
+
interface ISizeItemProps {
|
|
227
|
+
size: EComponentSize.MD | EComponentSize.LG;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const SIZES: ISizeItemProps["size"][] = [EComponentSize.MD, EComponentSize.LG];
|
|
231
|
+
|
|
232
|
+
const SizeItem = ({ size }: ISizeItemProps) => {
|
|
233
|
+
const [value, setValue] = useState(35);
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<div>
|
|
237
|
+
<div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>{size.toUpperCase()}</div>
|
|
238
|
+
<Slider min={0} max={100} size={size} marks={MARKS} value={value} onChange={setValue} />
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export const Sizes = () => (
|
|
244
|
+
<div style={{ maxWidth: "750px", padding: "30px", display: "flex", flexDirection: "column", gap: "24px" }}>
|
|
245
|
+
{SIZES.map((size) => (
|
|
246
|
+
<SizeItem key={size} size={size} />
|
|
247
|
+
))}
|
|
248
|
+
</div>
|
|
249
|
+
);
|
|
250
|
+
```
|
|
140
251
|
|
|
141
|
-
|
|
142
|
-
- `SliderRange` — два ползунка.
|
|
252
|
+
### WithTooltip
|
|
143
253
|
|
|
144
|
-
|
|
254
|
+
`stories/Slider/examples/Slider/WithTooltip.tsx`
|
|
145
255
|
|
|
146
|
-
|
|
256
|
+
```tsx
|
|
257
|
+
import React, { useState } from "react";
|
|
258
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
259
|
+
|
|
260
|
+
const MARKS = [
|
|
261
|
+
{ value: 0, label: "0" },
|
|
262
|
+
{ value: 35, label: "35" },
|
|
263
|
+
{ value: 66, label: "66" },
|
|
264
|
+
{ value: 100, label: "100" },
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
export const WithTooltip = () => {
|
|
268
|
+
const [value, setValue] = useState(35);
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
272
|
+
<div>value = {value}</div>
|
|
273
|
+
<br />
|
|
274
|
+
<Slider
|
|
275
|
+
min={0}
|
|
276
|
+
max={100}
|
|
277
|
+
size={EComponentSize.MD}
|
|
278
|
+
marks={MARKS}
|
|
279
|
+
value={value}
|
|
280
|
+
onChange={setValue}
|
|
281
|
+
renderTooltipContent={(tooltipValue) => `${tooltipValue} %`}
|
|
282
|
+
/>
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
};
|
|
286
|
+
```
|
|
147
287
|
|
|
148
|
-
|
|
149
|
-
Примеры: `stories/Slider/examples/`
|
|
288
|
+
### WithCustomSteps
|
|
150
289
|
|
|
151
|
-
|
|
290
|
+
`stories/Slider/examples/Slider/WithCustomSteps.tsx`
|
|
152
291
|
|
|
153
|
-
|
|
292
|
+
```tsx
|
|
293
|
+
import React, { useState } from "react";
|
|
294
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
295
|
+
|
|
296
|
+
// Массив шагов вынесен из JSX: инлайновый массив пересчитывает шаги на каждом рендере.
|
|
297
|
+
const STEPS = [0, 25, 50, 75, 100];
|
|
298
|
+
|
|
299
|
+
const MARKS = STEPS.map((step) => ({ value: step, label: String(step) }));
|
|
300
|
+
|
|
301
|
+
export const WithCustomSteps = () => {
|
|
302
|
+
const [value, setValue] = useState(50);
|
|
303
|
+
|
|
304
|
+
return (
|
|
305
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
306
|
+
<div>value = {value}</div>
|
|
307
|
+
<br />
|
|
308
|
+
<Slider
|
|
309
|
+
min={0}
|
|
310
|
+
max={100}
|
|
311
|
+
step={STEPS}
|
|
312
|
+
size={EComponentSize.MD}
|
|
313
|
+
marks={MARKS}
|
|
314
|
+
value={value}
|
|
315
|
+
onChange={setValue}
|
|
316
|
+
/>
|
|
317
|
+
</div>
|
|
318
|
+
);
|
|
319
|
+
};
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Disabled
|
|
323
|
+
|
|
324
|
+
`stories/Slider/examples/Slider/Disabled.tsx`
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import React from "react";
|
|
328
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
329
|
+
|
|
330
|
+
const MARKS = [
|
|
331
|
+
{ value: 0, label: "0" },
|
|
332
|
+
{ value: 35, label: "35" },
|
|
333
|
+
{ value: 66, label: "66" },
|
|
334
|
+
{ value: 100, label: "100" },
|
|
335
|
+
];
|
|
336
|
+
|
|
337
|
+
export const Disabled = () => (
|
|
338
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
339
|
+
<Slider min={0} max={100} size={EComponentSize.MD} marks={MARKS} value={35} onChange={() => {}} disabled />
|
|
340
|
+
</div>
|
|
341
|
+
);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Reverse
|
|
345
|
+
|
|
346
|
+
`stories/Slider/examples/Slider/Reverse.tsx`
|
|
347
|
+
|
|
348
|
+
```tsx
|
|
349
|
+
import React, { useState } from "react";
|
|
350
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
351
|
+
|
|
352
|
+
const MARKS = [
|
|
353
|
+
{ value: 0, label: "0" },
|
|
354
|
+
{ value: 35, label: "35" },
|
|
355
|
+
{ value: 66, label: "66" },
|
|
356
|
+
{ value: 100, label: "100" },
|
|
357
|
+
];
|
|
358
|
+
|
|
359
|
+
export const Reverse = () => {
|
|
360
|
+
const [value, setValue] = useState(35);
|
|
361
|
+
|
|
362
|
+
return (
|
|
363
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
364
|
+
<div>value = {value}</div>
|
|
365
|
+
<br />
|
|
366
|
+
<Slider
|
|
367
|
+
min={0}
|
|
368
|
+
max={100}
|
|
369
|
+
size={EComponentSize.MD}
|
|
370
|
+
marks={MARKS}
|
|
371
|
+
value={value}
|
|
372
|
+
onChange={setValue}
|
|
373
|
+
reverse
|
|
374
|
+
/>
|
|
375
|
+
</div>
|
|
376
|
+
);
|
|
377
|
+
};
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Amounts
|
|
381
|
+
|
|
382
|
+
`stories/Slider/examples/Slider/Amounts.tsx`
|
|
383
|
+
|
|
384
|
+
```tsx
|
|
385
|
+
import React, { useState } from "react";
|
|
386
|
+
import { EComponentSize, Slider } from "@sberbusiness/triplex-next";
|
|
387
|
+
|
|
388
|
+
/** Возвращает значения от from до to (не включая), с шагом step. */
|
|
389
|
+
const range = (from: number, to: number, step: number): number[] => {
|
|
390
|
+
const values: number[] = [];
|
|
391
|
+
|
|
392
|
+
for (let value = from; value < to; value += step) {
|
|
393
|
+
values.push(value);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return values;
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Шкала сумм с неравномерным шагом: чем больше сумма, тем крупнее шаг.
|
|
401
|
+
* Слайдер работает с индексами шкалы, поэтому шаги равны визуально.
|
|
402
|
+
*/
|
|
403
|
+
const AMOUNTS = [
|
|
404
|
+
0,
|
|
405
|
+
10000,
|
|
406
|
+
...range(20000, 240000, 20000),
|
|
407
|
+
...range(240000, 1000000, 40000),
|
|
408
|
+
...range(1000000, 2150000, 50000),
|
|
409
|
+
...range(2150000, 2600000, 75000),
|
|
410
|
+
...range(2600000, 3000000, 100000),
|
|
411
|
+
...range(3000000, 3800000, 200000),
|
|
412
|
+
...range(3800000, 9000000, 400000),
|
|
413
|
+
...range(9000000, 10000000, 500000),
|
|
414
|
+
...range(10000000, 25000000, 2500000),
|
|
415
|
+
...range(25000000, 40000000, 5000000),
|
|
416
|
+
...range(40000000, 90000001, 10000000),
|
|
417
|
+
100000000,
|
|
418
|
+
];
|
|
419
|
+
|
|
420
|
+
const amountFormat = new Intl.NumberFormat("ru-RU");
|
|
421
|
+
|
|
422
|
+
const MARKS = [
|
|
423
|
+
{ value: 0, label: "0 млн" },
|
|
424
|
+
{ value: AMOUNTS.indexOf(1000000), label: "1 млн" },
|
|
425
|
+
{ value: AMOUNTS.indexOf(3000000), label: "3 млн" },
|
|
426
|
+
{ value: AMOUNTS.length - 1, label: "100 млн" },
|
|
427
|
+
];
|
|
428
|
+
|
|
429
|
+
export const Amounts = () => {
|
|
430
|
+
const [amountIndex, setAmountIndex] = useState(AMOUNTS.indexOf(1000000));
|
|
431
|
+
|
|
432
|
+
return (
|
|
433
|
+
<div style={{ maxWidth: "750px", padding: "30px" }}>
|
|
434
|
+
<div>{amountFormat.format(AMOUNTS[amountIndex])}</div>
|
|
435
|
+
<br />
|
|
436
|
+
<Slider
|
|
437
|
+
min={0}
|
|
438
|
+
max={AMOUNTS.length - 1}
|
|
439
|
+
size={EComponentSize.MD}
|
|
440
|
+
marks={MARKS}
|
|
441
|
+
value={amountIndex}
|
|
442
|
+
onChange={setAmountIndex}
|
|
443
|
+
renderTooltipContent={(value) => amountFormat.format(AMOUNTS[value])}
|
|
444
|
+
/>
|
|
445
|
+
</div>
|
|
446
|
+
);
|
|
447
|
+
};
|
|
448
|
+
```
|
|
154
449
|
|
|
155
|
-
| Дата | Изменение |
|
|
156
|
-
|---|---|
|
|
157
|
-
| 2026-04-18 | Создан документ |
|