@sberbusiness/triplex-next-mcp-server 1.44.0-beta → 1.46.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 -6
- package/bundle/components/AlertContext.md +11 -8
- package/bundle/components/AlertProcess.md +13 -10
- package/bundle/components/Badge.md +6 -3
- package/bundle/components/Button.md +46 -43
- package/bundle/components/ButtonDropdownExtended.md +3 -2
- package/bundle/components/ButtonIcon.md +7 -4
- package/bundle/components/Calendar.md +62 -59
- package/bundle/components/Caption.md +26 -23
- package/bundle/components/CardAction.md +615 -0
- package/bundle/components/Checkbox.md +32 -29
- package/bundle/components/CheckboxTreeExtended.md +9 -5
- package/bundle/components/Chip.md +51 -47
- package/bundle/components/ChipMonthYearPicker.md +344 -0
- package/bundle/components/ChipMultiselect.md +1251 -0
- package/bundle/components/ChipOptions.md +329 -0
- package/bundle/components/ChipSort.md +333 -0
- package/bundle/components/ChipSuggest.md +587 -0
- package/bundle/components/CodeText.md +26 -23
- package/bundle/components/Col.md +1 -2
- package/bundle/components/CollapsibleTree.md +8 -5
- package/bundle/components/DateField.md +222 -303
- package/bundle/components/DatePickerExtended.md +3 -1
- package/bundle/components/Dropdown.md +33 -28
- package/bundle/components/EmptyView.md +12 -5
- package/bundle/components/FooterPage.md +6 -2
- package/bundle/components/FormField.md +47 -42
- package/bundle/components/FormGroup.md +192 -52
- package/bundle/components/Header.md +491 -211
- package/bundle/components/HeaderPage.md +6 -2
- package/bundle/components/HelpBox.md +7 -1
- package/bundle/components/ImageGallery.md +33 -34
- package/bundle/components/ImageGalleryExtended.md +33 -34
- package/bundle/components/Island.md +16 -13
- package/bundle/components/IslandAccordion.md +443 -152
- package/bundle/components/IslandWidget.md +622 -157
- package/bundle/components/LightBox.md +14 -12
- package/bundle/components/Link.md +211 -96
- package/bundle/components/ListActionItem.md +7 -4
- package/bundle/components/ListItem.md +11 -8
- package/bundle/components/ListItemControlsButton.md +16 -13
- package/bundle/components/ListItemControlsButtonDropdown.md +9 -6
- package/bundle/components/ListItemSelectable.md +7 -4
- package/bundle/components/ListMasterFooter.md +8 -5
- package/bundle/components/ListMasterHeader.md +8 -5
- package/bundle/components/ListSortableItem.md +11 -8
- package/bundle/components/ListTableItem.md +7 -4
- package/bundle/components/LoaderMiddle.md +7 -4
- package/bundle/components/LoaderScreen.md +11 -8
- package/bundle/components/LoaderSmall.md +7 -4
- package/bundle/components/Marker.md +184 -69
- package/bundle/components/MarkerStatus.md +206 -88
- package/bundle/components/MaskedField.md +4 -5
- package/bundle/components/MasterTable.md +602 -0
- package/bundle/components/ModalWindow.md +7 -4
- package/bundle/components/MonthYearField.md +3 -1
- package/bundle/components/MultiselectField.md +2183 -132
- package/bundle/components/Notification.md +12 -9
- package/bundle/components/Overlay.md +9 -4
- package/bundle/components/Page.md +2 -2
- package/bundle/components/Pagination.md +15 -8
- package/bundle/components/Row.md +1 -1
- package/bundle/components/SelectExtendedField.md +3 -3
- package/bundle/components/SelectField.md +466 -148
- package/bundle/components/SliderExtended.md +39 -36
- package/bundle/components/SmallInput.md +194 -51
- package/bundle/components/Suggest.md +535 -99
- package/bundle/components/SwipeableArea.md +428 -79
- package/bundle/components/TableBasic.md +19 -11
- package/bundle/components/TabsExtended.md +24 -21
- package/bundle/components/Tag.md +6 -2
- package/bundle/components/Text.md +28 -25
- package/bundle/components/TextField.md +3 -4
- package/bundle/components/ThemeProvider.md +50 -1
- package/bundle/components/Title.md +26 -23
- package/bundle/components/Tooltip.md +24 -21
- package/bundle/components/TopOverlay.md +7 -4
- package/bundle/guides/codestyle.md +3 -0
- package/bundle/guides/context.md +84 -12
- package/bundle/guides/guidelines.md +321 -0
- package/bundle/guides/template.md +22 -12
- package/bundle/manifest.json +75 -17
- package/bundle/release-notes/1.45.0.mdx +117 -0
- package/bundle/release-notes/1.46.0.mdx +66 -0
- package/bundle/release-notes/1.47.0.mdx +7 -0
- package/bundle/tokens.json +6362 -0
- package/dist/index.js +177 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: SwipeableArea
|
|
3
|
-
category:
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [MobileView]
|
|
3
|
+
category: SwipeableArea
|
|
4
|
+
related: [ListTableItem]
|
|
7
5
|
tokens: []
|
|
8
|
-
stories:
|
|
6
|
+
stories: stories/SwipeableArea/SwipeableArea.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
10
8
|
---
|
|
11
9
|
|
|
@@ -13,127 +11,190 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`
|
|
19
|
-
Работает только через touch-события (нет mouse drag).
|
|
14
|
+
Контейнер карточки с реализацией горизонтального свайпа: движение пальца
|
|
15
|
+
сдвигает контент и открывает боковую область с действиями. Свайп влево
|
|
16
|
+
открывает `rightSwipeableArea`, свайп вправо — `leftSwipeableArea`.
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
mouse events.
|
|
18
|
+
Собственного оформления у компонента нет — только позиционирование боковых
|
|
19
|
+
областей, transition сдвига и блокировки скролла и кликов на время жеста. Фон,
|
|
20
|
+
отступы и содержимое карточки приходят снаружи (обычно `ListItemContent`).
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
## Файловая структура
|
|
22
|
+
Используй когда: на мобильной ширине нужно спрятать действия карточки под
|
|
23
|
+
свайп — так устроены элементы списков (`ListItem`, `ListTableItem`).
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```
|
|
25
|
+
Не используй когда: действия должны быть доступны без тач-жеста. Свайп
|
|
26
|
+
воспроизводится только пальцем: ни мышь, ни клавиатура его не выполняют,
|
|
27
|
+
а компонент не даёт визуального триггера для открытия области. Для готового
|
|
28
|
+
табличного элемента списка со свайпом бери `ListTableItem` — он сам собирает
|
|
29
|
+
`SwipeableArea` и `ListItemControls`.
|
|
36
30
|
|
|
37
31
|
---
|
|
38
32
|
|
|
39
33
|
## Варианты и props
|
|
40
34
|
|
|
41
|
-
|
|
35
|
+
`ISwipeableAreaProps` расширяет `React.HTMLAttributes<HTMLDivElement>` —
|
|
36
|
+
`...rest` уходит на корневой `<div>`.
|
|
37
|
+
|
|
38
|
+
### Обязательные props
|
|
42
39
|
|
|
43
40
|
| Prop | Тип | Описание |
|
|
44
41
|
|---|---|---|
|
|
45
|
-
| `children` | `ReactNode` |
|
|
46
|
-
| `leftSwipeableArea?` | `ReactNode` | Контент, появляющийся при свайпе вправо. Если не задан — свайп вправо игнорируется. |
|
|
47
|
-
| `rightSwipeableArea?` | `ReactNode` | Контент, появляющийся при свайпе влево. Если не задан — свайп влево игнорируется. |
|
|
48
|
-
| `...HTMLAttributes<HTMLDivElement>` | — | Прокидываются на корневой div. |
|
|
49
|
-
|
|
50
|
-
### `ISwipeableAreaRef` (imperative API)
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
interface ISwipeableAreaRef {
|
|
54
|
-
closeSwipe(): void; // закрыть любую открытую панель
|
|
55
|
-
swipeLeft(): void; // открыть rightSwipeableArea (свайп влево)
|
|
56
|
-
swipeRight(): void; // открыть leftSwipeableArea (свайп вправо)
|
|
57
|
-
}
|
|
58
|
-
```
|
|
42
|
+
| `children` | `React.ReactNode` | Контент карточки. Лежит поверх боковых областей и сдвигается при свайпе |
|
|
59
43
|
|
|
60
|
-
|
|
44
|
+
### Опциональные props
|
|
61
45
|
|
|
62
|
-
|
|
46
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| `leftSwipeableArea` | `React.ReactNode` | — | Контент, открывающийся свайпом **вправо**. Если не передан, свайп вправо ничего не двигает |
|
|
49
|
+
| `rightSwipeableArea` | `React.ReactNode` | — | Контент, открывающийся свайпом **влево**. Если не передан, свайп влево ничего не двигает |
|
|
50
|
+
| `onSwipeLeft` | `() => void` | — | Открылась `rightSwipeableArea`. Вызывается только на открытии и только если свайп длиннее порога |
|
|
51
|
+
| `onSwipeRight` | `() => void` | — | Открылась `leftSwipeableArea`. Те же условия |
|
|
52
|
+
| `className` | `string` | — | Мерджится с собственным классом через `clsx` |
|
|
63
53
|
|
|
64
|
-
|
|
54
|
+
Закрывающий свайп (когда область уже открыта) колбэки **не** вызывает — они
|
|
55
|
+
сообщают только о факте открытия.
|
|
65
56
|
|
|
66
|
-
###
|
|
57
|
+
### Императивный ref — `ISwipeableAreaRef`
|
|
67
58
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| `SWIPE_MIN_DISTANCE` | `24` (px) | Порог, ниже которого свайп считается «недотянутым» и контент возвращается в исходное положение. |
|
|
59
|
+
`ref` компонента — не DOM-элемент, а объект с методами. Единственный способ
|
|
60
|
+
подвинуть контент без тач-жеста.
|
|
71
61
|
|
|
72
|
-
|
|
62
|
+
| Метод | Что делает |
|
|
63
|
+
|---|---|
|
|
64
|
+
| `swipeLeft()` | Открывает `rightSwipeableArea` |
|
|
65
|
+
| `swipeRight()` | Открывает `leftSwipeableArea` |
|
|
66
|
+
| `closeSwipe()` | Закрывает открытую область |
|
|
67
|
+
|
|
68
|
+
Метод молча ничего не делает, если соответствующая область не отрисована.
|
|
69
|
+
Колбэки `onSwipeLeft` / `onSwipeRight` при вызове методов **не** срабатывают.
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
- `|deltaY| > |deltaX|` → `dragType = vertical` (скролл), свайп не обрабатывается.
|
|
76
|
-
- иначе → `horizontal` (свайп), контент двигается.
|
|
71
|
+
### Как обрабатывается жест
|
|
77
72
|
|
|
78
|
-
|
|
73
|
+
| Фаза | Поведение |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `touchstart` на контенте | Запоминаются координаты пальца и текущий сдвиг контента; на документ вешается разовый слушатель `touchend` |
|
|
76
|
+
| Первое `touchmove` | Определяется тип жеста: `abs(deltaY) > abs(deltaX)` — это скролл, контент до конца жеста не двигается; иначе — свайп |
|
|
77
|
+
| Последующие `touchmove` | Контент едет за пальцем, но не дальше ширины открываемой области; на время свайпа у контента `touch-action: none` |
|
|
78
|
+
| `touchend` (на документе) | Если длина свайпа больше `SWIPE_MIN_DISTANCE` (24px) — область открывается или закрывается, иначе контент возвращается в положение, с которого начинался жест |
|
|
79
|
+
| `touchstart` вне компонента | Открытая область закрывается |
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
Мультитач (`event.touches.length !== 1`) игнорируется при перемещении: на
|
|
82
|
+
старте координаты запоминаются всегда, но контент не поедет, пока в жесте
|
|
83
|
+
не останется ровно один палец.
|
|
81
84
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
Прозрачность боковой области считается как `|сдвиг| / ширина области`, поэтому
|
|
86
|
+
она проявляется по мере свайпа. Ширина берётся из `getBoundingClientRect()` в
|
|
87
|
+
момент жеста — область с нулевой шириной открыться не сможет; для неё
|
|
88
|
+
`getSwipeableAreaOpacity` возвращает `1`, как в состоянии покоя, вместо `NaN`
|
|
89
|
+
от деления на ноль.
|
|
87
90
|
|
|
88
|
-
|
|
91
|
+
Логика жеста вынесена в чистые функции `resolveSwipeMove`, `resolveSwipeEnd` и
|
|
92
|
+
`getSwipeableAreaOpacity` (`src/components/SwipeableArea/utils.ts`) и покрыта
|
|
93
|
+
unit-тестами. Компонент
|
|
94
|
+
хранит только состояние: сдвиг контента, тип жеста и флаг анимации.
|
|
89
95
|
|
|
90
|
-
|
|
96
|
+
### Известные ограничения
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
Пункт существует с первой версии компонента и не менялся при AI-рефакторинге —
|
|
99
|
+
при правках его стоит держать в голове.
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
- **Сдвиг контента не сбрасывается, если боковая область перестала
|
|
102
|
+
передаваться.** Открыли `leftSwipeableArea`, затем перестали передавать этот
|
|
103
|
+
prop — область размонтируется, а контент останется сдвинутым, оставив пустую
|
|
104
|
+
полосу внутри `overflow: hidden`. Закрыть можно через `closeSwipe()`.
|
|
95
105
|
|
|
96
|
-
|
|
106
|
+
---
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
`animating = false` в `onTransitionEnd`.
|
|
108
|
+
## Дизайн-токены
|
|
100
109
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
Токенов нет. `SwipeableArea.module.less` содержит только позиционирование,
|
|
111
|
+
`transition` сдвига и `touch-action`. Цвета и фон приходят от контента —
|
|
112
|
+
например, `ListItem.Background` у `ListItemContent`.
|
|
104
113
|
|
|
105
114
|
---
|
|
106
115
|
|
|
107
116
|
## Инварианты
|
|
108
117
|
|
|
109
|
-
- **`forwardRef
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- **`
|
|
118
|
+
- **`forwardRef` на компоненте — не убирать.** Ref типизирован
|
|
119
|
+
`ISwipeableAreaRef` и наполняется через `useImperativeHandle`: получить через
|
|
120
|
+
него корневой `<div>` нельзя, и менять это — breaking change для
|
|
121
|
+
`ListTableItem` и потребителей библиотеки.
|
|
122
|
+
- **Публичные экспорты barrel** (`src/components/SwipeableArea/index.ts`):
|
|
123
|
+
`SwipeableArea`, `ISwipeableAreaProps`, `ISwipeableAreaRef`. Переименование —
|
|
124
|
+
breaking change. `utils.ts` — внутренний модуль, в barrel не попадает.
|
|
125
|
+
- **`displayName = "SwipeableArea"`.**
|
|
126
|
+
- **Корневой DOM — `<div>`.** На него уходят `className`, `...rest` и `data-tx`;
|
|
127
|
+
тег не настраивается.
|
|
128
|
+
- **Порог свайпа `SWIPE_MIN_DISTANCE = 24` — внутренняя константа.** Пропа для
|
|
129
|
+
него нет; изменение значения меняет ощущение жеста у всех потребителей.
|
|
130
|
+
- **Боковые области рендерятся, только если соответствующий prop передан**
|
|
131
|
+
(`!== undefined`), и остаются в DOM всё время жизни компонента. Скрытость
|
|
132
|
+
закрытой области — следствие `opacity` и перекрытия контентом, а не
|
|
133
|
+
размонтирования.
|
|
134
|
+
- **`touch-action: pan-y` на контенте и `touch-action: none` во время
|
|
135
|
+
горизонтального свайпа** — без этого браузер уводит жест в скролл страницы.
|
|
136
|
+
- **`::after` поверх контента при открытой области** — гасит нажатия на
|
|
137
|
+
вложенные элементы карточки, пока область открыта. Убрать — значит разрешить
|
|
138
|
+
случайные клики по карточке при открытых кнопках.
|
|
139
|
+
- **Слушатели документа снимаются при размонтировании** (`touchstart` — всегда,
|
|
140
|
+
`touchend` — если компонент размонтирован в середине жеста).
|
|
141
|
+
- **React 17-совместимость.** Компонент уходит в ветку `release-0`; React
|
|
142
|
+
18-only API (`useId`, `useSyncExternalStore`, `useInsertionEffect`)
|
|
143
|
+
использовать нельзя.
|
|
117
144
|
|
|
118
145
|
---
|
|
119
146
|
|
|
120
147
|
## Accessibility
|
|
121
148
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
149
|
+
Собственных ARIA-атрибутов компонент не выставляет и текстов не хардкодит —
|
|
150
|
+
библиотека мультиязычная, а содержимое боковых областей приходит снаружи.
|
|
151
|
+
|
|
152
|
+
Что важно знать потребителю:
|
|
153
|
+
|
|
154
|
+
- **Клавиатурного эквивалента свайпа нет.** Компонент слушает только `touch`-
|
|
155
|
+
события. Если действия из боковой области критичны, продублируй их доступным
|
|
156
|
+
элементом или открывай область через `ISwipeableAreaRef`.
|
|
157
|
+
- **Кнопки боковых областей фокусируются по Tab и в закрытом состоянии** —
|
|
158
|
+
области всегда в DOM, а `opacity: 0` фокус не забирает. Это осознанный
|
|
159
|
+
компромисс текущей реализации: если такой обход недопустим, скрывай
|
|
160
|
+
содержимое области на своей стороне.
|
|
161
|
+
- **Открытая область не помечается для скринридера.** `::after` блокирует
|
|
162
|
+
только указатель; порядок чтения и фокус остаются прежними.
|
|
125
163
|
|
|
126
164
|
---
|
|
127
165
|
|
|
128
166
|
## Связанные компоненты
|
|
129
167
|
|
|
130
|
-
- `
|
|
168
|
+
- `ListTableItem` (`src/components/List`) — единственный потребитель внутри
|
|
169
|
+
библиотеки, который опирается на императивный контракт: он всегда оборачивает
|
|
170
|
+
свой контент в `SwipeableArea`, прокидывает наружу `swipeableAreaRef` типа
|
|
171
|
+
`React.Ref<ISwipeableAreaRef>` и подключает `controlButtons` как
|
|
172
|
+
`rightSwipeableArea`. Любая правка `ISwipeableAreaRef` должна сверяться с ним.
|
|
173
|
+
- `ListItemControls`, `ListItemControlsButton`, `ListItemControlsButtonDropdown`
|
|
174
|
+
(`src/components/List`) — стандартное наполнение боковой области: контейнер
|
|
175
|
+
кнопок действий и сами кнопки.
|
|
176
|
+
- `ListItemTailLeft` / `ListItemTailRight` (`src/components/List`) —
|
|
177
|
+
декоративные «хвосты», подсказывающие, что карточку можно свайпнуть.
|
|
178
|
+
Размещаются внутри `SwipeableArea` рядом с контентом.
|
|
179
|
+
- `ListItem` / `ListItemContent` (`src/components/List`) — типичное окружение:
|
|
180
|
+
`ListItem` даёт элемент списка, `ListItemContent` — фон и отступы карточки,
|
|
181
|
+
без которых боковые области просвечивали бы сквозь контент.
|
|
131
182
|
|
|
132
183
|
---
|
|
133
184
|
|
|
134
185
|
## Stories
|
|
135
186
|
|
|
136
|
-
|
|
187
|
+
Основные истории: `stories/SwipeableArea/SwipeableArea.stories.tsx`
|
|
188
|
+
Файлы примеров: `stories/SwipeableArea/examples/`
|
|
189
|
+
|
|
190
|
+
| Story | Example file | Что демонстрирует |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| `Playground` | `Playground.tsx` | Переключение боковых областей, колбэки в Actions, кнопки императивного API |
|
|
193
|
+
| `Default` | `Default.tsx` | Минимальная карточка: свайп влево открывает кнопку действия |
|
|
194
|
+
| `With both areas` | `WithBothAreas.tsx` | Обе боковые области сразу |
|
|
195
|
+
| `Imperative API` | `ImperativeApi.tsx` | `swipeLeft` / `swipeRight` / `closeSwipe` через `ISwipeableAreaRef` |
|
|
196
|
+
| `Example` | `Example.tsx` | Список платежей, где открытой остаётся только одна карточка |
|
|
197
|
+
| `VisualTests` | `VisualTests.tsx` | Скриншоты закрытого состояния и обеих открытых областей |
|
|
137
198
|
|
|
138
199
|
---
|
|
139
200
|
|
|
@@ -141,4 +202,292 @@ CSS-класс `swipeAnimationFinish` (`animating = true`) → CSS transition.
|
|
|
141
202
|
|
|
142
203
|
| Дата | Изменение |
|
|
143
204
|
|---|---|
|
|
144
|
-
| 2026-
|
|
205
|
+
| 2026-08-31 | Создан документ. Зафиксированы: контракт императивного `ref` вместо DOM-ref, порог свайпа 24px, правила определения жеста и мультитача, зависимость открытия от ширины боковой области, отсутствие клавиатурного эквивалента и фокусируемость кнопок закрытой области |
|
|
206
|
+
| 2026-09-02 | Прозрачность боковой области нулевой ширины больше не даёт `NaN` — `getSwipeableAreaOpacity` возвращает `1`. Пункт убран из «Известных ограничений» |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Примеры использования
|
|
211
|
+
|
|
212
|
+
### Default
|
|
213
|
+
|
|
214
|
+
`stories/SwipeableArea/examples/Default.tsx`
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import React from "react";
|
|
218
|
+
import {
|
|
219
|
+
List,
|
|
220
|
+
ListItem,
|
|
221
|
+
ListItemContent,
|
|
222
|
+
ListItemControls,
|
|
223
|
+
ListItemControlsButton,
|
|
224
|
+
ListItemTailRight,
|
|
225
|
+
SwipeableArea,
|
|
226
|
+
} from "@sberbusiness/triplex-next";
|
|
227
|
+
import { AttachmentStrokeSrvIcon20 } from "@sberbusiness/icons-next";
|
|
228
|
+
|
|
229
|
+
export const Default = () => (
|
|
230
|
+
<div style={{ maxWidth: "500px" }}>
|
|
231
|
+
<List>
|
|
232
|
+
<ListItem>
|
|
233
|
+
<SwipeableArea
|
|
234
|
+
rightSwipeableArea={
|
|
235
|
+
<ListItemControls>
|
|
236
|
+
<ListItemControlsButton
|
|
237
|
+
icon={<AttachmentStrokeSrvIcon20 paletteIndex={5} />}
|
|
238
|
+
onClick={() => {}}
|
|
239
|
+
>
|
|
240
|
+
Скачать
|
|
241
|
+
</ListItemControlsButton>
|
|
242
|
+
</ListItemControls>
|
|
243
|
+
}
|
|
244
|
+
onSwipeLeft={() => {}}
|
|
245
|
+
>
|
|
246
|
+
<ListItemTailRight />
|
|
247
|
+
{/* Минимальная высота, из-за блока с кнопками, появляющегося при свайпе. */}
|
|
248
|
+
<ListItemContent style={{ minHeight: "56px" }}>Свайп влево открывает кнопки</ListItemContent>
|
|
249
|
+
</SwipeableArea>
|
|
250
|
+
</ListItem>
|
|
251
|
+
</List>
|
|
252
|
+
</div>
|
|
253
|
+
);
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### With both areas
|
|
257
|
+
|
|
258
|
+
`stories/SwipeableArea/examples/WithBothAreas.tsx`
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
import React from "react";
|
|
262
|
+
import {
|
|
263
|
+
List,
|
|
264
|
+
ListItem,
|
|
265
|
+
ListItemContent,
|
|
266
|
+
ListItemControls,
|
|
267
|
+
ListItemControlsButton,
|
|
268
|
+
ListItemTailLeft,
|
|
269
|
+
ListItemTailRight,
|
|
270
|
+
SwipeableArea,
|
|
271
|
+
} from "@sberbusiness/triplex-next";
|
|
272
|
+
import { AttachmentStrokeSrvIcon20, DefaulticonStrokePrdIcon20 } from "@sberbusiness/icons-next";
|
|
273
|
+
|
|
274
|
+
export const WithBothAreas = () => (
|
|
275
|
+
<div style={{ maxWidth: "500px" }}>
|
|
276
|
+
<List>
|
|
277
|
+
<ListItem>
|
|
278
|
+
<SwipeableArea
|
|
279
|
+
leftSwipeableArea={
|
|
280
|
+
<ListItemControls>
|
|
281
|
+
<ListItemControlsButton
|
|
282
|
+
icon={<DefaulticonStrokePrdIcon20 paletteIndex={5} />}
|
|
283
|
+
onClick={() => {}}
|
|
284
|
+
>
|
|
285
|
+
В архив
|
|
286
|
+
</ListItemControlsButton>
|
|
287
|
+
</ListItemControls>
|
|
288
|
+
}
|
|
289
|
+
rightSwipeableArea={
|
|
290
|
+
<ListItemControls>
|
|
291
|
+
<ListItemControlsButton
|
|
292
|
+
icon={<AttachmentStrokeSrvIcon20 paletteIndex={5} />}
|
|
293
|
+
onClick={() => {}}
|
|
294
|
+
>
|
|
295
|
+
Скачать
|
|
296
|
+
</ListItemControlsButton>
|
|
297
|
+
</ListItemControls>
|
|
298
|
+
}
|
|
299
|
+
onSwipeLeft={() => {}}
|
|
300
|
+
onSwipeRight={() => {}}
|
|
301
|
+
>
|
|
302
|
+
<ListItemTailLeft />
|
|
303
|
+
<ListItemTailRight />
|
|
304
|
+
{/* Минимальная высота, из-за блока с кнопками, появляющегося при свайпе. */}
|
|
305
|
+
<ListItemContent style={{ minHeight: "56px" }}>Свайп влево и вправо</ListItemContent>
|
|
306
|
+
</SwipeableArea>
|
|
307
|
+
</ListItem>
|
|
308
|
+
</List>
|
|
309
|
+
</div>
|
|
310
|
+
);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Imperative API
|
|
314
|
+
|
|
315
|
+
`stories/SwipeableArea/examples/ImperativeApi.tsx`
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import React, { useRef } from "react";
|
|
319
|
+
import {
|
|
320
|
+
Button,
|
|
321
|
+
EButtonTheme,
|
|
322
|
+
EComponentSize,
|
|
323
|
+
ISwipeableAreaRef,
|
|
324
|
+
List,
|
|
325
|
+
ListItem,
|
|
326
|
+
ListItemContent,
|
|
327
|
+
ListItemControls,
|
|
328
|
+
ListItemControlsButton,
|
|
329
|
+
ListItemTailLeft,
|
|
330
|
+
ListItemTailRight,
|
|
331
|
+
SwipeableArea,
|
|
332
|
+
} from "@sberbusiness/triplex-next";
|
|
333
|
+
import { AttachmentStrokeSrvIcon20, DefaulticonStrokePrdIcon20 } from "@sberbusiness/icons-next";
|
|
334
|
+
|
|
335
|
+
export const ImperativeApi = () => {
|
|
336
|
+
const swipeableAreaRef = useRef<ISwipeableAreaRef>(null);
|
|
337
|
+
|
|
338
|
+
return (
|
|
339
|
+
<div style={{ maxWidth: "500px" }}>
|
|
340
|
+
<div style={{ display: "flex", gap: "8px", marginBottom: "16px" }}>
|
|
341
|
+
<Button
|
|
342
|
+
theme={EButtonTheme.SECONDARY}
|
|
343
|
+
size={EComponentSize.SM}
|
|
344
|
+
onClick={() => swipeableAreaRef.current?.swipeRight()}
|
|
345
|
+
>
|
|
346
|
+
swipeRight
|
|
347
|
+
</Button>
|
|
348
|
+
<Button
|
|
349
|
+
theme={EButtonTheme.SECONDARY}
|
|
350
|
+
size={EComponentSize.SM}
|
|
351
|
+
onClick={() => swipeableAreaRef.current?.swipeLeft()}
|
|
352
|
+
>
|
|
353
|
+
swipeLeft
|
|
354
|
+
</Button>
|
|
355
|
+
<Button
|
|
356
|
+
theme={EButtonTheme.SECONDARY}
|
|
357
|
+
size={EComponentSize.SM}
|
|
358
|
+
onClick={() => swipeableAreaRef.current?.closeSwipe()}
|
|
359
|
+
>
|
|
360
|
+
closeSwipe
|
|
361
|
+
</Button>
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
<List>
|
|
365
|
+
<ListItem>
|
|
366
|
+
<SwipeableArea
|
|
367
|
+
ref={swipeableAreaRef}
|
|
368
|
+
leftSwipeableArea={
|
|
369
|
+
<ListItemControls>
|
|
370
|
+
<ListItemControlsButton
|
|
371
|
+
icon={<DefaulticonStrokePrdIcon20 paletteIndex={5} />}
|
|
372
|
+
onClick={() => {}}
|
|
373
|
+
>
|
|
374
|
+
В архив
|
|
375
|
+
</ListItemControlsButton>
|
|
376
|
+
</ListItemControls>
|
|
377
|
+
}
|
|
378
|
+
rightSwipeableArea={
|
|
379
|
+
<ListItemControls>
|
|
380
|
+
<ListItemControlsButton
|
|
381
|
+
icon={<AttachmentStrokeSrvIcon20 paletteIndex={5} />}
|
|
382
|
+
onClick={() => {}}
|
|
383
|
+
>
|
|
384
|
+
Скачать
|
|
385
|
+
</ListItemControlsButton>
|
|
386
|
+
</ListItemControls>
|
|
387
|
+
}
|
|
388
|
+
>
|
|
389
|
+
<ListItemTailLeft />
|
|
390
|
+
<ListItemTailRight />
|
|
391
|
+
{/* Минимальная высота, из-за блока с кнопками, появляющегося при свайпе. */}
|
|
392
|
+
<ListItemContent style={{ minHeight: "56px" }}>Управление через ref</ListItemContent>
|
|
393
|
+
</SwipeableArea>
|
|
394
|
+
</ListItem>
|
|
395
|
+
</List>
|
|
396
|
+
</div>
|
|
397
|
+
);
|
|
398
|
+
};
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Example
|
|
402
|
+
|
|
403
|
+
`stories/SwipeableArea/examples/Example.tsx`
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
import React, { useRef } from "react";
|
|
407
|
+
import {
|
|
408
|
+
EFontType,
|
|
409
|
+
EFontWeightText,
|
|
410
|
+
ETextSize,
|
|
411
|
+
ISwipeableAreaRef,
|
|
412
|
+
List,
|
|
413
|
+
ListItem,
|
|
414
|
+
ListItemContent,
|
|
415
|
+
ListItemControls,
|
|
416
|
+
ListItemControlsButton,
|
|
417
|
+
ListItemControlsButtonDropdown,
|
|
418
|
+
ListItemTailRight,
|
|
419
|
+
SwipeableArea,
|
|
420
|
+
Text,
|
|
421
|
+
} from "@sberbusiness/triplex-next";
|
|
422
|
+
import { AttachmentStrokeSrvIcon20, DotshorizontalStrokeSrvIcon20 } from "@sberbusiness/icons-next";
|
|
423
|
+
|
|
424
|
+
const PAYMENTS = [
|
|
425
|
+
{ id: "swipeable-area-payment-1", amount: "1 220 000,00 ₽", counterparty: "ООО «Голубая роза»" },
|
|
426
|
+
{ id: "swipeable-area-payment-2", amount: "84 300,00 ₽", counterparty: "ООО «Северный ветер»" },
|
|
427
|
+
{ id: "swipeable-area-payment-3", amount: "12 500,00 ₽", counterparty: "ИП Иванов И. И." },
|
|
428
|
+
];
|
|
429
|
+
|
|
430
|
+
export const Example = () => {
|
|
431
|
+
const swipeableAreaRefs = useRef<Record<string, ISwipeableAreaRef | null>>({});
|
|
432
|
+
|
|
433
|
+
// Открытой остаётся только одна карточка: свайп по одной закрывает остальные.
|
|
434
|
+
const handleSwipeLeft = (paymentId: string) => {
|
|
435
|
+
Object.entries(swipeableAreaRefs.current).forEach(([id, swipeableArea]) => {
|
|
436
|
+
if (id !== paymentId) {
|
|
437
|
+
swipeableArea?.closeSwipe();
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
return (
|
|
443
|
+
<div style={{ maxWidth: "500px" }}>
|
|
444
|
+
<List>
|
|
445
|
+
{PAYMENTS.map((payment) => (
|
|
446
|
+
<ListItem key={payment.id}>
|
|
447
|
+
<SwipeableArea
|
|
448
|
+
ref={(instance) => {
|
|
449
|
+
swipeableAreaRefs.current[payment.id] = instance;
|
|
450
|
+
}}
|
|
451
|
+
rightSwipeableArea={
|
|
452
|
+
<ListItemControls>
|
|
453
|
+
<ListItemControlsButton
|
|
454
|
+
icon={<AttachmentStrokeSrvIcon20 paletteIndex={5} />}
|
|
455
|
+
onClick={() => {}}
|
|
456
|
+
>
|
|
457
|
+
Скачать
|
|
458
|
+
</ListItemControlsButton>
|
|
459
|
+
<ListItemControlsButtonDropdown
|
|
460
|
+
icon={<DotshorizontalStrokeSrvIcon20 paletteIndex={5} />}
|
|
461
|
+
options={[
|
|
462
|
+
{ id: `${payment.id}-option-1`, label: "Повторить", onSelect: () => {} },
|
|
463
|
+
{ id: `${payment.id}-option-2`, label: "Удалить", onSelect: () => {} },
|
|
464
|
+
]}
|
|
465
|
+
>
|
|
466
|
+
Действия
|
|
467
|
+
</ListItemControlsButtonDropdown>
|
|
468
|
+
</ListItemControls>
|
|
469
|
+
}
|
|
470
|
+
onSwipeLeft={() => handleSwipeLeft(payment.id)}
|
|
471
|
+
>
|
|
472
|
+
<ListItemTailRight />
|
|
473
|
+
{/* Минимальная высота, из-за блока с кнопками, появляющегося при свайпе. */}
|
|
474
|
+
<ListItemContent style={{ minHeight: "56px" }}>
|
|
475
|
+
<Text size={ETextSize.B2} weight={EFontWeightText.SEMIBOLD} tag="div">
|
|
476
|
+
{payment.amount}
|
|
477
|
+
</Text>
|
|
478
|
+
<Text size={ETextSize.B3} tag="div">
|
|
479
|
+
{payment.counterparty}
|
|
480
|
+
</Text>
|
|
481
|
+
<Text size={ETextSize.B3} type={EFontType.SECONDARY} tag="div">
|
|
482
|
+
Оплата по счёту от 09.04.24
|
|
483
|
+
</Text>
|
|
484
|
+
</ListItemContent>
|
|
485
|
+
</SwipeableArea>
|
|
486
|
+
</ListItem>
|
|
487
|
+
))}
|
|
488
|
+
</List>
|
|
489
|
+
</div>
|
|
490
|
+
);
|
|
491
|
+
};
|
|
492
|
+
```
|
|
493
|
+
|
|
@@ -3,10 +3,10 @@ component: TableBasic
|
|
|
3
3
|
category: Table
|
|
4
4
|
related: [MasterTable, ListTableItem, LoaderScreen, LoaderMiddle, Text]
|
|
5
5
|
tokens:
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
6
|
+
- TableBasic.Header_Background
|
|
7
|
+
- TableBasic.Color
|
|
8
|
+
- TableBasic.Background_Hover
|
|
9
|
+
- TableBasic.Background_Selected
|
|
10
10
|
stories: stories/TableBasic/TableBasic.stories.tsx
|
|
11
11
|
version: "1.0"
|
|
12
12
|
---
|
|
@@ -93,15 +93,23 @@ version: "1.0"
|
|
|
93
93
|
|
|
94
94
|
## Дизайн-токены
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
Переопределяются через `ThemeProvider` (prop `tokens`) — см. `ThemeProvider-ai.md` →
|
|
97
|
+
«Как переопределять токены». Значения по умолчанию — `src/components/DesignTokens/components/TableBasic.ts`.
|
|
98
|
+
|
|
99
|
+
```text
|
|
100
|
+
TableBasic.Header_Background
|
|
101
|
+
TableBasic.Color
|
|
102
|
+
TableBasic.Background_Hover
|
|
103
|
+
TableBasic.Background_Selected
|
|
101
104
|
```
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
В группе `TableBasic` лежат и токены соседних компонентов семейства —
|
|
107
|
+
`TableFooter_*` применяются в `TableFooter`, `TableBasicSettings_*` — в
|
|
108
|
+
`TableBasicSettings`. Переопределяются они там же, в группе `TableBasic`:
|
|
109
|
+
имя группы — не имя компонента. Здесь они не перечислены, потому что сам
|
|
110
|
+
`TableBasic` их не использует, а собственных AI.md у этих компонентов пока нет —
|
|
111
|
+
поэтому `syncAiMdTokens` и предупреждает, что токены есть в LESS директории,
|
|
112
|
+
но не описаны ни в одном документе.
|
|
105
113
|
|
|
106
114
|
---
|
|
107
115
|
|