@sberbusiness/triplex-next-mcp-server 0.24.0-beta2 → 1.40.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 +10 -0
- package/bundle/components/AlertContext.md +268 -0
- package/bundle/components/BodyPage.md +186 -0
- package/bundle/components/Button.md +93 -85
- package/bundle/components/ButtonDropdown.md +36 -70
- package/bundle/components/ButtonDropdownExtended.md +422 -0
- package/bundle/components/ButtonIcon.md +41 -48
- package/bundle/components/Caption.md +291 -0
- package/bundle/components/Checkbox.md +43 -122
- package/bundle/components/CheckboxXGroup.md +109 -46
- package/bundle/components/CheckboxYGroup.md +77 -49
- package/bundle/components/CodeText.md +197 -0
- package/bundle/components/Col.md +311 -162
- package/bundle/components/CollapsibleTree.md +584 -0
- package/bundle/components/CollapsibleTreeExtended.md +422 -0
- package/bundle/components/Dropdown.md +748 -346
- package/bundle/components/EmptyView.md +14 -15
- package/bundle/components/FooterPage.md +203 -0
- package/bundle/components/Gap.md +115 -57
- package/bundle/components/HeaderPage.md +226 -0
- package/bundle/components/HelpBox.md +45 -84
- package/bundle/components/ImageGallery.md +423 -0
- package/bundle/components/ImageGalleryExtended.md +606 -0
- package/bundle/components/LightBox.md +2252 -233
- package/bundle/components/List.md +216 -183
- package/bundle/components/ListActionItem.md +157 -0
- package/bundle/components/ListItem.md +276 -0
- package/bundle/components/ListItemControlsButton.md +103 -0
- package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
- package/bundle/components/ListItemSelectable.md +99 -0
- package/bundle/components/ListItemTable.md +390 -0
- package/bundle/components/ListMaster.md +876 -156
- package/bundle/components/ListMasterFooter.md +80 -0
- package/bundle/components/ListMasterHeader.md +86 -0
- package/bundle/components/ListSortable.md +153 -0
- package/bundle/components/ListSortableItem.md +175 -0
- package/bundle/components/ListTableItem.md +391 -0
- package/bundle/components/ModalWindow.md +427 -237
- package/bundle/components/MonthYearField.md +145 -109
- package/bundle/components/Notification.md +625 -155
- package/bundle/components/Overlay.md +271 -170
- package/bundle/components/Page.md +284 -186
- package/bundle/components/Pagination.md +206 -229
- package/bundle/components/Portal.md +131 -67
- package/bundle/components/Row.md +171 -69
- package/bundle/components/Text.md +320 -0
- package/bundle/components/TextField.md +364 -97
- package/bundle/components/Title.md +296 -0
- package/bundle/guides/codestyle.md +38 -11
- package/bundle/guides/commits.md +119 -26
- package/bundle/guides/context.md +34 -30
- package/bundle/guides/stories.md +110 -40
- package/bundle/guides/template.md +3 -7
- package/bundle/guides/tests.md +48 -2
- package/bundle/manifest.json +275 -30
- package/bundle/release-notes/1.26.0.mdx +33 -2
- package/bundle/release-notes/1.27.0.mdx +43 -0
- package/bundle/release-notes/1.28.0.mdx +25 -0
- package/bundle/release-notes/1.29.0.mdx +47 -0
- package/bundle/release-notes/1.30.0.mdx +56 -0
- package/bundle/release-notes/1.31.0.mdx +52 -0
- package/bundle/release-notes/1.32.0.mdx +35 -0
- package/bundle/release-notes/1.33.0.mdx +61 -0
- package/bundle/release-notes/1.34.0.mdx +35 -0
- package/bundle/release-notes/1.35.0.mdx +21 -0
- package/bundle/release-notes/1.35.1.mdx +11 -0
- package/bundle/release-notes/1.36.0.mdx +21 -0
- package/bundle/release-notes/1.37.0.mdx +71 -0
- package/bundle/release-notes/1.38.0.mdx +36 -0
- package/bundle/release-notes/1.39.0.mdx +66 -0
- package/bundle/release-notes/1.40.0.mdx +27 -0
- package/bundle/release-notes/1.41.0.mdx +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ListMasterFooter
|
|
3
|
+
category: List
|
|
4
|
+
related: [ListMaster, ListMasterFooterDescription, ListMasterFooterControls]
|
|
5
|
+
tokens:
|
|
6
|
+
- --triplex-next-ListMaster-Footer_Background
|
|
7
|
+
- --triplex-next-ListMaster-Footer_Shadow
|
|
8
|
+
stories: stories/ListMaster/ListMaster.stories.tsx
|
|
9
|
+
version: "1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ListMasterFooter
|
|
13
|
+
|
|
14
|
+
## Назначение
|
|
15
|
+
|
|
16
|
+
Sticky-футер `ListMaster`. Используется обычно при выделении ≥1 элемента
|
|
17
|
+
списка для показа агрегатов (например, суммы выбранных) и действий по
|
|
18
|
+
выбранному. По умолчанию имеет `display: flex; justify-content: space-between;
|
|
19
|
+
align-items: center` — слева текст (`FooterDescription`), справа кнопки
|
|
20
|
+
(`FooterControls`).
|
|
21
|
+
|
|
22
|
+
Используется как `<ListMaster.Footer>` или импортируется напрямую.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Варианты и props
|
|
27
|
+
|
|
28
|
+
### Опциональные props
|
|
29
|
+
|
|
30
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `sticky` | `boolean` | `true` | Sticky-позиционирование (`bottom: 0`). При `false` футер ведёт себя как обычный блок |
|
|
33
|
+
| `children` | `React.ReactNode` | — | Содержимое футера (обычно пара `FooterDescription` + `FooterControls`) |
|
|
34
|
+
| `...HTMLDivAttributes` | — | — | Все атрибуты `<div>` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Дизайн-токены
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
--triplex-next-ListMaster-Footer_Background // фон футера
|
|
42
|
+
--triplex-next-ListMaster-Footer_Shadow // тень сверху
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Инварианты
|
|
48
|
+
|
|
49
|
+
- **`forwardRef`** — обязателен, target — `HTMLDivElement`. Не убирать.
|
|
50
|
+
- **Внутренний layout `flex / space-between`** — публичный визуальный контракт. `FooterDescription` и `FooterControls` не делают `justify-content` сами — это задача футера.
|
|
51
|
+
- **Корневой DOM** — `<div>`. Не менять.
|
|
52
|
+
- В отличие от `ListMasterHeader`, scroll-компенсации НЕТ — футер не сдвигает контент при появлении.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Связанные компоненты
|
|
57
|
+
|
|
58
|
+
- **`ListMaster`** — родительский compound. `ListMasterFooter` доступен как `ListMaster.Footer`.
|
|
59
|
+
- **`ListMasterFooterDescription`** (`ListMaster.FooterDescription`) — левая текстовая часть. Тривиальный wrapper, описан в `ListMaster-ai.md`.
|
|
60
|
+
- **`ListMasterFooterControls`** (`ListMaster.FooterControls`) — правый контейнер кнопок. Тривиальный wrapper, описан в `ListMaster-ai.md`.
|
|
61
|
+
- **`ListMasterHeader`** — симметричная sticky-шапка.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Stories
|
|
66
|
+
|
|
67
|
+
Демонстрируется в общей story `Default` компонента `ListMaster` — появляется,
|
|
68
|
+
когда `selectedListItemIds.length > 0`. Отдельных stories нет.
|
|
69
|
+
|
|
70
|
+
| Story | Example file | Что демонстрирует |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `Default` (в `ListMaster.stories.tsx`) | `Default.tsx` | Sticky-футер с суммой выбранных (`FooterDescription`) и действиями `ButtonDropdown` + `Button` (`FooterControls`) |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## История изменений
|
|
77
|
+
|
|
78
|
+
| Дата | Изменение |
|
|
79
|
+
|---|---|
|
|
80
|
+
| 2026-04-29 | Создан документ. Уточнён JSDoc по дефолтному значению `sticky`. Добавлены unit-тесты. |
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ListMasterHeader
|
|
3
|
+
category: List
|
|
4
|
+
related: [ListMaster, SelectionControls]
|
|
5
|
+
tokens:
|
|
6
|
+
- --triplex-next-ListMaster-Header_Background
|
|
7
|
+
- --triplex-next-ListMaster-Header_Shadow
|
|
8
|
+
stories: stories/ListMaster/ListMaster.stories.tsx
|
|
9
|
+
version: "1.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# ListMasterHeader
|
|
13
|
+
|
|
14
|
+
## Назначение
|
|
15
|
+
|
|
16
|
+
Sticky-шапка `ListMaster`. Показывается обычно при выделении ≥1 элемента
|
|
17
|
+
списка (для отображения selection controls). При монтировании компенсирует
|
|
18
|
+
свою высоту через `window.scrollTo`, чтобы появление шапки не сдвигало
|
|
19
|
+
содержимое визуально вниз; при размонтировании — откатывает скролл.
|
|
20
|
+
|
|
21
|
+
Используется как `<ListMaster.Header>` или импортируется напрямую — оба
|
|
22
|
+
варианта поддерживаются barrel'ом.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Варианты и props
|
|
27
|
+
|
|
28
|
+
### Опциональные props
|
|
29
|
+
|
|
30
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `sticky` | `boolean` | `true` | Sticky-позиционирование (`top: 0`, `z-index: 1`). При `false` шапка ведёт себя как обычный блок |
|
|
33
|
+
| `children` | `React.ReactNode` | — | Содержимое шапки (обычно `<ListMaster.SelectionControls>`) |
|
|
34
|
+
| `...HTMLDivAttributes` | — | — | Все атрибуты `<div>` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Дизайн-токены
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
--triplex-next-ListMaster-Header_Background // фон шапки
|
|
42
|
+
--triplex-next-ListMaster-Header_Shadow // тень снизу
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Инварианты
|
|
48
|
+
|
|
49
|
+
- **`forwardRef`** — обязателен, target — `HTMLDivElement`. Не убирать.
|
|
50
|
+
- **`useEffect` со scroll-компенсацией** — публичное наблюдаемое поведение, на котором завязан UX (контент не «прыгает» при появлении шапки). Не удалять без согласования с дизайнером.
|
|
51
|
+
- **`z-index: 1`** в sticky-режиме — нужен чтобы шапка перекрывала `ListMasterBody`. Не уменьшать.
|
|
52
|
+
- **Корневой DOM** — `<div>`. Не менять.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Accessibility
|
|
57
|
+
|
|
58
|
+
- Семантика — обычный `<div>`. Если используется как landmark, потребитель должен передать `role="banner"` или обернуть в `<header>` через `as`-паттерн (сейчас не поддерживается, см. барьер: компонент рендерит `<div>` хардкодом).
|
|
59
|
+
- Содержимое (selection-controls) обычно содержит `<button>`-ы — их accessibility — задача потребителя.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Связанные компоненты
|
|
64
|
+
|
|
65
|
+
- **`ListMaster`** — родительский compound. `ListMasterHeader` доступен как `ListMaster.Header`.
|
|
66
|
+
- **`SelectionControls`** (`ListMaster.SelectionControls`) — flex-контейнер для типичного контента шапки (выбрать все / счётчик / сбросить).
|
|
67
|
+
- **`ListMasterFooter`** — симметричный sticky-футер.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Stories
|
|
72
|
+
|
|
73
|
+
Демонстрируется в общей story `Default` компонента `ListMaster` — появляется,
|
|
74
|
+
когда `selectedListItemIds.length > 0`. Отдельных stories нет.
|
|
75
|
+
|
|
76
|
+
| Story | Example file | Что демонстрирует |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `Default` (в `ListMaster.stories.tsx`) | `Default.tsx` | Sticky-шапка с `SelectionControls` (Выбрать все / счётчик / Сбросить) при наличии выделенных элементов |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## История изменений
|
|
83
|
+
|
|
84
|
+
| Дата | Изменение |
|
|
85
|
+
|---|---|
|
|
86
|
+
| 2026-04-29 | Создан документ. Уточнён JSDoc по `useEffect`-логике компенсации скролла. Добавлены unit-тесты. |
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ListSortable
|
|
3
|
+
category: List
|
|
4
|
+
related: [List, ListSortableItem, ListSortableItemTarget, ListSortableItemControls]
|
|
5
|
+
tokens: []
|
|
6
|
+
stories: stories/List/List.stories.tsx
|
|
7
|
+
version: "1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# ListSortable
|
|
11
|
+
|
|
12
|
+
## Назначение
|
|
13
|
+
|
|
14
|
+
`<ul>`-контейнер с поддержкой drag-and-drop сортировки на основе `@dnd-kit`.
|
|
15
|
+
Принимает массив `items` (каждый объект должен иметь `id: string`) и
|
|
16
|
+
callback `onItemsChange`, в который пробрасывает результат `arrayMove` после
|
|
17
|
+
успешного перетаскивания.
|
|
18
|
+
|
|
19
|
+
Используй `ListSortable` когда: нужна сортировка элементов мышью/тачем.
|
|
20
|
+
Иначе используй обычный `List`.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Варианты и props
|
|
25
|
+
|
|
26
|
+
`ListSortable<T extends { id: string }>` — generic.
|
|
27
|
+
|
|
28
|
+
### Обязательные props
|
|
29
|
+
|
|
30
|
+
| Prop | Тип | Описание |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `items` | `T[]` | Текущий упорядоченный список элементов. У каждого должен быть уникальный `id: string` |
|
|
33
|
+
| `onItemsChange` | `(items: T[]) => void` | Вызывается с новым порядком после drag-and-drop |
|
|
34
|
+
|
|
35
|
+
### Опциональные props
|
|
36
|
+
|
|
37
|
+
| Prop | Тип | Описание |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `loading` | `boolean` | Передаётся во внутренний `<List>` (overlay-спиннер) |
|
|
40
|
+
| `children` | `React.ReactNode` | Обычно `items.map(item => <ListSortableItem id={item.id}>...)` |
|
|
41
|
+
| `...HTMLUListElementAttributes` | — | Прокидываются во внутренний `<ul>` |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Инварианты
|
|
46
|
+
|
|
47
|
+
- **`forwardRef`** — обязателен, target — `HTMLUListElement` (внутренний `<List>`). Не убирать.
|
|
48
|
+
- **Generic `T extends { id: string }`** — обязательно, иначе `arrayMove` + `findIndex` сломаются.
|
|
49
|
+
- **`AdvancedMouseSensor` / `AdvancedTouchSensor`** — экспортируются из barrel, переименовывать или удалять — breaking change.
|
|
50
|
+
- **`isDraggableTarget`** (из `src/components/List/utils.ts`) — общий хелпер для обоих сенсоров; проверяет цепочку `data-draggable="false"` вверх по DOM. Используй `ListSortableItemControls` или вручную выставляй `data-draggable="false"`, чтобы исключить элемент из drag-area (см. `SortableWithInteractiveElements`-стори).
|
|
51
|
+
- **`measuring.droppable.frequency: WhileDragging`** — нужен для корректной перерисовки виртуализированных списков; не менять без причины.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Accessibility
|
|
56
|
+
|
|
57
|
+
- DnD на `@dnd-kit` поддерживает клавиатурную навигацию через `KeyboardSensor`, но в текущей конфигурации он **не включён** — добавляется потребителем при необходимости.
|
|
58
|
+
- Сенсоры реагируют только на клик левой кнопкой мыши (правая кнопка `event.button === 2` отбрасывается).
|
|
59
|
+
- Touch — отбрасывается мульти-тач (`event.touches.length > 1`).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Связанные компоненты
|
|
64
|
+
|
|
65
|
+
- `List` — внутренний `<ul>`-контейнер; `ListSortable` оборачивает его в `DndContext` + `SortableContext`.
|
|
66
|
+
- `ListSortableItem` — элемент с `useSortable`-обвязкой; обычно используется как непосредственный child.
|
|
67
|
+
- `ListSortableItemTarget` — визуальная «карточка» элемента с drag-индикатором.
|
|
68
|
+
- `ListSortableItemControls` — обёртка для интерактивных элементов внутри строки (`data-draggable="false"`).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Stories
|
|
73
|
+
|
|
74
|
+
Основные истории: `stories/List/List.stories.tsx`
|
|
75
|
+
Файлы примеров: `stories/List/examples/List/`
|
|
76
|
+
|
|
77
|
+
| Story | Example file | Что демонстрирует |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `Sortable` | `Sortable.tsx` | Базовая DnD-сортировка |
|
|
80
|
+
| `SortableWithInteractiveElements` | `SortableWithInteractiveElements.tsx` | Сортировка с интерактивными элементами внутри строк (`data-draggable="false"` через `ListSortableItemControls`) |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## История изменений
|
|
85
|
+
|
|
86
|
+
| Дата | Изменение |
|
|
87
|
+
|---|---|
|
|
88
|
+
| 2026-04-29 | Создан документ |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Примеры использования
|
|
93
|
+
|
|
94
|
+
### Sortable
|
|
95
|
+
|
|
96
|
+
`stories/List/examples/List/Sortable.tsx`
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import React, { useState } from "react";
|
|
100
|
+
import { ListSortable, ListSortableItem } from "@sberbusiness/triplex-next";
|
|
101
|
+
|
|
102
|
+
export const Sortable = () => {
|
|
103
|
+
const [items, setItems] = useState(
|
|
104
|
+
Array.from({ length: 10 }, (_, index) => ({ id: `list-sortable-item-0-${index}`, index })),
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<ListSortable items={items} onItemsChange={setItems}>
|
|
109
|
+
{items.map(({ id, index }) => (
|
|
110
|
+
<ListSortableItem key={id} id={id}>
|
|
111
|
+
{({ listeners, dragging, setActivatorNodeRef }) => (
|
|
112
|
+
<ListSortableItem.Target {...listeners} dragging={dragging} ref={setActivatorNodeRef}>
|
|
113
|
+
List item {index}
|
|
114
|
+
</ListSortableItem.Target>
|
|
115
|
+
)}
|
|
116
|
+
</ListSortableItem>
|
|
117
|
+
))}
|
|
118
|
+
</ListSortable>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### SortableWithInteractiveElements
|
|
124
|
+
|
|
125
|
+
`stories/List/examples/List/SortableWithInteractiveElements.tsx`
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
import React, { useState } from "react";
|
|
129
|
+
import { Checkbox, ListSortable, ListSortableItem, ListSortableItemControls } from "@sberbusiness/triplex-next";
|
|
130
|
+
|
|
131
|
+
export const SortableWithInteractiveElements = () => {
|
|
132
|
+
const [items, setItems] = useState(
|
|
133
|
+
Array.from({ length: 10 }, (_, index) => ({ id: `list-sortable-item-1-${index}`, index })),
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
<ListSortable items={items} onItemsChange={setItems}>
|
|
138
|
+
{items.map(({ id, index }) => (
|
|
139
|
+
<ListSortableItem key={id} id={id}>
|
|
140
|
+
{({ listeners, dragging, setActivatorNodeRef }) => (
|
|
141
|
+
<ListSortableItem.Target {...listeners} dragging={dragging} ref={setActivatorNodeRef}>
|
|
142
|
+
<ListSortableItemControls>
|
|
143
|
+
<Checkbox>List item {index}</Checkbox>
|
|
144
|
+
</ListSortableItemControls>
|
|
145
|
+
</ListSortableItem.Target>
|
|
146
|
+
)}
|
|
147
|
+
</ListSortableItem>
|
|
148
|
+
))}
|
|
149
|
+
</ListSortable>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: ListSortableItem
|
|
3
|
+
category: List
|
|
4
|
+
related: [ListSortable, ListSortableItemTarget, ListSortableItemControls, ListItem]
|
|
5
|
+
tokens:
|
|
6
|
+
- --triplex-next-ListItem-Background
|
|
7
|
+
- --triplex-next-ListItem-Background_Selected
|
|
8
|
+
- --triplex-next-ListItem-Background_Dragging
|
|
9
|
+
- --triplex-next-ListItem-Shadow_Dragging
|
|
10
|
+
stories: stories/List/List.stories.tsx
|
|
11
|
+
version: "1.0"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# ListSortableItem
|
|
15
|
+
|
|
16
|
+
## Назначение
|
|
17
|
+
|
|
18
|
+
Элемент `<li>` с обвязкой `useSortable` из `@dnd-kit/sortable` — даёт ему
|
|
19
|
+
transform/transition для анимации перетаскивания и активирует drag-handle.
|
|
20
|
+
Имеет статический подкомпонент `Target` (`ListSortableItem.Target`) для
|
|
21
|
+
визуальной «карточки» с drag-индикатором.
|
|
22
|
+
|
|
23
|
+
Используй `ListSortableItem` внутри `ListSortable` для элементов, которые
|
|
24
|
+
надо перетаскивать. Может принимать render-prop children — это даёт доступ к
|
|
25
|
+
`dragging`/`disabled`/`listeners`/`setActivatorNodeRef` для случаев, когда
|
|
26
|
+
drag-handle нужно вынести в отдельный элемент.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Варианты и props
|
|
31
|
+
|
|
32
|
+
### Обязательные props
|
|
33
|
+
|
|
34
|
+
| Prop | Тип | Описание |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `id` | `string` | Уникальный идентификатор. Должен совпадать с `id` в массиве `items` родительского `ListSortable` |
|
|
37
|
+
|
|
38
|
+
### Опциональные props
|
|
39
|
+
|
|
40
|
+
| Prop | Тип | Описание |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `disabled` | `boolean` | Запрещает drag для конкретного элемента |
|
|
43
|
+
| `children` | `React.ReactNode \| ((provideProps) => React.ReactNode)` | Контент или render-prop. Render-prop принимает `{ disabled, dragging, listeners, setActivatorNodeRef }` |
|
|
44
|
+
| `style` | `React.CSSProperties` | Дополняется автоматическими `transform`/`transition` от `useSortable` |
|
|
45
|
+
| `...HTMLLIElementAttributes` | — | Прокидываются на корневой `<li>` через `ListItem` |
|
|
46
|
+
|
|
47
|
+
### Статический подкомпонент
|
|
48
|
+
|
|
49
|
+
| Имя | Описание |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `ListSortableItem.Target` | `ListSortableItemTarget` — стандартная карточка с drag-индикатором (`DragdotsStrokeSrvIcon24`) |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Дизайн-токены
|
|
56
|
+
|
|
57
|
+
Сам `ListSortableItem` не использует токены (только z-index при `dragging`).
|
|
58
|
+
Токены применяются в `ListSortableItem.Target`:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
--triplex-next-ListItem-Background // фон по умолчанию
|
|
62
|
+
--triplex-next-ListItem-Background_Selected // фон при hover
|
|
63
|
+
--triplex-next-ListItem-Background_Dragging // фон во время drag
|
|
64
|
+
--triplex-next-ListItem-Shadow_Dragging // тень во время drag
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Инварианты
|
|
70
|
+
|
|
71
|
+
- **`forwardRef`** — обязателен, target — `HTMLLIElement`. Объявлен через `Object.assign` с `Target` в качестве static-свойства, чтобы `displayName` работал корректно.
|
|
72
|
+
- **`Object.assign({...forwardRef}, { Target })`** — паттерн compound-component. Не разворачивай в отдельный экспорт, иначе сломается DX (`<ListSortableItem.Target>`).
|
|
73
|
+
- **`transition: { duration: 300, easing: "ease-out" }`** — фиксированное значение, согласовано с дизайнером. Не менять без согласования.
|
|
74
|
+
- **Render-prop children** — публичный API, потребитель может полагаться на сигнатуру `IListSortableItemChildrenProvideProps`.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Accessibility
|
|
79
|
+
|
|
80
|
+
- Drag-handle по умолчанию — вся карточка (`<li>`-элемент). Если нужно вынести handle — используй render-prop и `setActivatorNodeRef`.
|
|
81
|
+
- В нативном виде — поддержка только мыши/тача (см. ограничения `ListSortable`).
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Связанные компоненты
|
|
86
|
+
|
|
87
|
+
- `ListSortable` — родительский контекст DnD; без него `useSortable` не работает.
|
|
88
|
+
- `ListSortableItemTarget` (= `ListSortableItem.Target`) — стандартная визуальная «карточка».
|
|
89
|
+
- `ListSortableItemControls` — обёртка с `data-draggable="false"` для интерактивных элементов внутри строки (кнопки, чекбоксы), которые не должны инициировать drag.
|
|
90
|
+
- `ListItem` — внутренний `<li>`-контейнер.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Stories
|
|
95
|
+
|
|
96
|
+
Основные истории: `stories/List/List.stories.tsx`
|
|
97
|
+
Файлы примеров: `stories/List/examples/List/`
|
|
98
|
+
|
|
99
|
+
| Story | Example file | Что демонстрирует |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `Sortable` | `Sortable.tsx` | Простой случай — `ListSortableItem` с `ListSortableItem.Target` |
|
|
102
|
+
| `SortableWithInteractiveElements` | `SortableWithInteractiveElements.tsx` | Render-prop children + `ListSortableItemControls` для исключения интерактивных элементов из drag-области |
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## История изменений
|
|
107
|
+
|
|
108
|
+
| Дата | Изменение |
|
|
109
|
+
|---|---|
|
|
110
|
+
| 2026-04-29 | Создан документ |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Примеры использования
|
|
115
|
+
|
|
116
|
+
### Sortable
|
|
117
|
+
|
|
118
|
+
`stories/List/examples/List/Sortable.tsx`
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import React, { useState } from "react";
|
|
122
|
+
import { ListSortable, ListSortableItem } from "@sberbusiness/triplex-next";
|
|
123
|
+
|
|
124
|
+
export const Sortable = () => {
|
|
125
|
+
const [items, setItems] = useState(
|
|
126
|
+
Array.from({ length: 10 }, (_, index) => ({ id: `list-sortable-item-0-${index}`, index })),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<ListSortable items={items} onItemsChange={setItems}>
|
|
131
|
+
{items.map(({ id, index }) => (
|
|
132
|
+
<ListSortableItem key={id} id={id}>
|
|
133
|
+
{({ listeners, dragging, setActivatorNodeRef }) => (
|
|
134
|
+
<ListSortableItem.Target {...listeners} dragging={dragging} ref={setActivatorNodeRef}>
|
|
135
|
+
List item {index}
|
|
136
|
+
</ListSortableItem.Target>
|
|
137
|
+
)}
|
|
138
|
+
</ListSortableItem>
|
|
139
|
+
))}
|
|
140
|
+
</ListSortable>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### SortableWithInteractiveElements
|
|
146
|
+
|
|
147
|
+
`stories/List/examples/List/SortableWithInteractiveElements.tsx`
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import React, { useState } from "react";
|
|
151
|
+
import { Checkbox, ListSortable, ListSortableItem, ListSortableItemControls } from "@sberbusiness/triplex-next";
|
|
152
|
+
|
|
153
|
+
export const SortableWithInteractiveElements = () => {
|
|
154
|
+
const [items, setItems] = useState(
|
|
155
|
+
Array.from({ length: 10 }, (_, index) => ({ id: `list-sortable-item-1-${index}`, index })),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<ListSortable items={items} onItemsChange={setItems}>
|
|
160
|
+
{items.map(({ id, index }) => (
|
|
161
|
+
<ListSortableItem key={id} id={id}>
|
|
162
|
+
{({ listeners, dragging, setActivatorNodeRef }) => (
|
|
163
|
+
<ListSortableItem.Target {...listeners} dragging={dragging} ref={setActivatorNodeRef}>
|
|
164
|
+
<ListSortableItemControls>
|
|
165
|
+
<Checkbox>List item {index}</Checkbox>
|
|
166
|
+
</ListSortableItemControls>
|
|
167
|
+
</ListSortableItem.Target>
|
|
168
|
+
)}
|
|
169
|
+
</ListSortableItem>
|
|
170
|
+
))}
|
|
171
|
+
</ListSortable>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
```
|
|
175
|
+
|