@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.
Files changed (73) hide show
  1. package/README.md +10 -0
  2. package/bundle/components/AlertContext.md +268 -0
  3. package/bundle/components/BodyPage.md +186 -0
  4. package/bundle/components/Button.md +93 -85
  5. package/bundle/components/ButtonDropdown.md +36 -70
  6. package/bundle/components/ButtonDropdownExtended.md +422 -0
  7. package/bundle/components/ButtonIcon.md +41 -48
  8. package/bundle/components/Caption.md +291 -0
  9. package/bundle/components/Checkbox.md +43 -122
  10. package/bundle/components/CheckboxXGroup.md +109 -46
  11. package/bundle/components/CheckboxYGroup.md +77 -49
  12. package/bundle/components/CodeText.md +197 -0
  13. package/bundle/components/Col.md +311 -162
  14. package/bundle/components/CollapsibleTree.md +584 -0
  15. package/bundle/components/CollapsibleTreeExtended.md +422 -0
  16. package/bundle/components/Dropdown.md +748 -346
  17. package/bundle/components/EmptyView.md +14 -15
  18. package/bundle/components/FooterPage.md +203 -0
  19. package/bundle/components/Gap.md +115 -57
  20. package/bundle/components/HeaderPage.md +226 -0
  21. package/bundle/components/HelpBox.md +45 -84
  22. package/bundle/components/ImageGallery.md +423 -0
  23. package/bundle/components/ImageGalleryExtended.md +606 -0
  24. package/bundle/components/LightBox.md +2252 -233
  25. package/bundle/components/List.md +216 -183
  26. package/bundle/components/ListActionItem.md +157 -0
  27. package/bundle/components/ListItem.md +276 -0
  28. package/bundle/components/ListItemControlsButton.md +103 -0
  29. package/bundle/components/ListItemControlsButtonDropdown.md +107 -0
  30. package/bundle/components/ListItemSelectable.md +99 -0
  31. package/bundle/components/ListItemTable.md +390 -0
  32. package/bundle/components/ListMaster.md +876 -156
  33. package/bundle/components/ListMasterFooter.md +80 -0
  34. package/bundle/components/ListMasterHeader.md +86 -0
  35. package/bundle/components/ListSortable.md +153 -0
  36. package/bundle/components/ListSortableItem.md +175 -0
  37. package/bundle/components/ListTableItem.md +391 -0
  38. package/bundle/components/ModalWindow.md +427 -237
  39. package/bundle/components/MonthYearField.md +145 -109
  40. package/bundle/components/Notification.md +625 -155
  41. package/bundle/components/Overlay.md +271 -170
  42. package/bundle/components/Page.md +284 -186
  43. package/bundle/components/Pagination.md +206 -229
  44. package/bundle/components/Portal.md +131 -67
  45. package/bundle/components/Row.md +171 -69
  46. package/bundle/components/Text.md +320 -0
  47. package/bundle/components/TextField.md +364 -97
  48. package/bundle/components/Title.md +296 -0
  49. package/bundle/guides/codestyle.md +38 -11
  50. package/bundle/guides/commits.md +119 -26
  51. package/bundle/guides/context.md +34 -30
  52. package/bundle/guides/stories.md +110 -40
  53. package/bundle/guides/template.md +3 -7
  54. package/bundle/guides/tests.md +48 -2
  55. package/bundle/manifest.json +275 -30
  56. package/bundle/release-notes/1.26.0.mdx +33 -2
  57. package/bundle/release-notes/1.27.0.mdx +43 -0
  58. package/bundle/release-notes/1.28.0.mdx +25 -0
  59. package/bundle/release-notes/1.29.0.mdx +47 -0
  60. package/bundle/release-notes/1.30.0.mdx +56 -0
  61. package/bundle/release-notes/1.31.0.mdx +52 -0
  62. package/bundle/release-notes/1.32.0.mdx +35 -0
  63. package/bundle/release-notes/1.33.0.mdx +61 -0
  64. package/bundle/release-notes/1.34.0.mdx +35 -0
  65. package/bundle/release-notes/1.35.0.mdx +21 -0
  66. package/bundle/release-notes/1.35.1.mdx +11 -0
  67. package/bundle/release-notes/1.36.0.mdx +21 -0
  68. package/bundle/release-notes/1.37.0.mdx +71 -0
  69. package/bundle/release-notes/1.38.0.mdx +36 -0
  70. package/bundle/release-notes/1.39.0.mdx +66 -0
  71. package/bundle/release-notes/1.40.0.mdx +27 -0
  72. package/bundle/release-notes/1.41.0.mdx +7 -0
  73. package/package.json +1 -1
@@ -0,0 +1,276 @@
1
+ ---
2
+ component: ListItem
3
+ category: List
4
+ related: [List, ListItemContent, ListActionItem, ListItemSelectable, ListTableItem, ListSortableItem]
5
+ tokens:
6
+ - --triplex-next-ListItem-Background
7
+ - --triplex-next-ListItem-Background_Selected
8
+ - --triplex-next-ListItem-Background_Hover
9
+ - --triplex-next-ListItem-BorderColor_Focus
10
+ stories: stories/List/ListItem.stories.tsx
11
+ version: "1.0"
12
+ ---
13
+
14
+ # ListItem
15
+
16
+ ## Назначение
17
+
18
+ Базовый элемент списка `<li>` — обёртка вокруг произвольного содержимого
19
+ (`ListItemContent`, `ListItemSelectable`, `SwipeableArea` и т.п.). Создаёт
20
+ React-контекст `ListItemContext` с состояниями `selected` и `selectable`:
21
+ `selected` управляет подсветкой `ListItemContent`, `selectable` сообщает
22
+ дочернему `ListItemContent`, что элемент выбираемый — для применения скругления
23
+ углов (`border-radius`). Оба флага пишутся `ListItemSelectable` через `useEffect`.
24
+
25
+ Используй `ListItem` когда: нужен произвольный layout строки списка.
26
+ Используй `ListTableItem` когда: нужна готовая табличная строка с support'ом
27
+ swipe-actions и selectable.
28
+
29
+ ---
30
+
31
+ ## Варианты и props
32
+
33
+ ### Опциональные props
34
+
35
+ | Prop | Тип | По умолчанию | Описание |
36
+ |---|---|---|---|
37
+ | `children` | `React.ReactNode` | — | Содержимое строки |
38
+ | `...HTMLLIElementAttributes` | — | — | Все стандартные атрибуты `<li>` |
39
+
40
+ ---
41
+
42
+ ## Дизайн-токены
43
+
44
+ Сами стили `ListItem.tsx` пустые — токены применяются в подкомпонентах
45
+ (`ListItemContent`, `ListItemSelectable`, `ListActionItem`):
46
+
47
+ ```text
48
+ --triplex-next-ListItem-Background // фон по умолчанию (ListItemContent)
49
+ --triplex-next-ListItem-Background_Selected // фон, когда selected=true (ListItemContent)
50
+ --triplex-next-ListItem-Background_Hover // фон при hover на desktop (ListActionItem на ListItemContent)
51
+ --triplex-next-ListItem-BorderColor_Focus // цвет focus-обводки на desktop (ListActionItem)
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Инварианты
57
+
58
+ - **`forwardRef`** — обязателен, target — `HTMLLIElement`. Не убирать.
59
+ - **`ListItemContext`** — провайдер на каждом `ListItem`. Не выносить наружу — context используется парой `ListItemSelectable` (writer для `selected` и `selectable`) ↔ `ListItemContent` (reader) внутри одной строки.
60
+ - **Поля контекста `selected` / `selectable`** — оба `boolean`, дефолт `false`. `selectable` всегда выставляется в `true` из `ListItemSelectable` (через `useEffect`), `selected` синхронизируется с одноимённым prop'ом `ListItemSelectable`. Сеттеры (`setSelected`, `setSelectable`) предназначены только для внутренних консьюмеров.
61
+ - **Корневой элемент `<li>`** — не менять. Семантика важна для accessibility.
62
+
63
+ ---
64
+
65
+ ## Связанные компоненты
66
+
67
+ - `ListItemContent` — внутренняя обёртка для контента, читает `selected` из контекста.
68
+ - `ListActionItem` — самодостаточный интерактивный элемент: сам рендерит `ListItem` + `ListItemContent` (hover, focus по Tab, клик по всей строке — `onClick`, Enter/Space). Используется напрямую внутри `List`. Другие компоненты семейства его не используют.
69
+ - `ListItemSelectable` — добавляет чекбокс выбора, синхронизирует `selected` в контекст через `useEffect`.
70
+ - `ListItemLoading` — элемент-спиннер для пагинации (используется как последний элемент).
71
+ - `ListItemControls`, `ListItemControlsButton`, `ListItemControlsButtonDropdown` — кнопки действий, обычно внутри `SwipeableArea.rightSwipeableArea`.
72
+ - `ListItemTailLeft` / `ListItemTailRight` — декоративные хвосты для `SwipeableArea`.
73
+ - `ListTableItem` — комбинированная высокоуровневая обёртка.
74
+
75
+ ---
76
+
77
+ ## Stories
78
+
79
+ Основные истории: `stories/List/ListItem.stories.tsx`
80
+ Файлы примеров: `stories/List/examples/ListItem/`
81
+
82
+ | Story | Example file | Что демонстрирует |
83
+ |---|---|---|
84
+ | `Default` | `Default.tsx` | Базовый элемент с произвольным контентом |
85
+ | `Action` | `Action.tsx` | Использование `ListActionItem` |
86
+ | `Loading` | `Loading.tsx` | `ListItemLoading` как последний элемент при пагинации |
87
+ | `Selectable` | `Selectable.tsx` | Использование `ListItemSelectable` внутри `ListItem` |
88
+ | `Swipeable` | `Swipeable.tsx` | `ListItem` внутри `SwipeableArea` с `ListItemControls` |
89
+
90
+ ---
91
+
92
+ ## История изменений
93
+
94
+ | Дата | Изменение |
95
+ |---|---|
96
+ | 2026-04-29 | Создан документ |
97
+ | 2026-05-21 | `ListItemContext` расширен полями `selectable` / `setSelectable`. Исправлен цвет токена `Background_Selected` в тёмной теме (`ColorDarkNeutral.10` → `ColorDarkNeutral.60`). |
98
+ | 2026-07-16 | Добавлен самодостаточный компонент `ListActionItem` (сам рендерит `ListItem` + `ListItemContent`; hover, focus по Tab, `onClick` + Enter/Space). Координация фона через контекст не понадобилась — `ListItemContext` без изменений. Другие компоненты семейства его не используют. |
99
+
100
+ ---
101
+
102
+ ## Примеры использования
103
+
104
+ ### Default
105
+
106
+ `stories/List/examples/ListItem/Default.tsx`
107
+
108
+ ```tsx
109
+ import React from "react";
110
+ import { List, ListItem, ListItemContent } from "@sberbusiness/triplex-next";
111
+
112
+ export const Default = () => (
113
+ <div style={{ maxWidth: "500px" }}>
114
+ <List>
115
+ <ListItem>
116
+ <ListItemContent>Элемент списка</ListItemContent>
117
+ </ListItem>
118
+ </List>
119
+ </div>
120
+ );
121
+ ```
122
+
123
+ ### Action
124
+
125
+ `stories/List/examples/ListItem/Action.tsx`
126
+
127
+ ```tsx
128
+ import React from "react";
129
+ import { List, ListActionItem } from "@sberbusiness/triplex-next";
130
+
131
+ export const Action = () => (
132
+ <div style={{ maxWidth: "500px" }}>
133
+ <List>
134
+ <ListActionItem listItemContentProps={{ onClick: () => alert("Клик по элементу списка") }}>
135
+ Элемент списка
136
+ </ListActionItem>
137
+ </List>
138
+ </div>
139
+ );
140
+ ```
141
+
142
+ ### Loading
143
+
144
+ `stories/List/examples/ListItem/Loading.tsx`
145
+
146
+ ```tsx
147
+ import React from "react";
148
+ import { List, ListItem, ListItemLoading } from "@sberbusiness/triplex-next";
149
+
150
+ export const Loading = () => (
151
+ <div style={{ maxWidth: "500px" }}>
152
+ <List>
153
+ <ListItem>
154
+ <ListItemLoading />
155
+ </ListItem>
156
+ </List>
157
+ </div>
158
+ );
159
+ ```
160
+
161
+ ### Selectable
162
+
163
+ `stories/List/examples/ListItem/Selectable.tsx`
164
+
165
+ ```tsx
166
+ import React, { useState } from "react";
167
+ import { List, ListItem, ListItemContent, ListItemSelectable } from "@sberbusiness/triplex-next";
168
+
169
+ export const Selectable = () => {
170
+ const [selected, setSelected] = useState(false);
171
+
172
+ return (
173
+ <div style={{ maxWidth: "500px" }}>
174
+ <List>
175
+ <ListItem>
176
+ <ListItemSelectable selected={selected} onSelect={setSelected}>
177
+ <ListItemContent>Элемент списка</ListItemContent>
178
+ </ListItemSelectable>
179
+ </ListItem>
180
+ </List>
181
+ </div>
182
+ );
183
+ };
184
+ ```
185
+
186
+ ### Swipeable
187
+
188
+ `stories/List/examples/ListItem/Swipeable.tsx`
189
+
190
+ ```tsx
191
+ import React from "react";
192
+ import {
193
+ ISwipeableAreaRef,
194
+ List,
195
+ ListItem,
196
+ ListItemContent,
197
+ ListItemControls,
198
+ ListItemControlsButton,
199
+ ListItemControlsButtonDropdown,
200
+ ListItemTailRight,
201
+ SwipeableArea,
202
+ } from "@sberbusiness/triplex-next";
203
+ import { DefaulticonStrokePrdIcon20 } from "@sberbusiness/icons-next";
204
+
205
+ export const Swipeable = () => {
206
+ const options = [
207
+ {
208
+ id: "list-item-swipe-controls-dropdown-option-1",
209
+ label: "Текст пункта меню 1",
210
+ onSelect: () => alert("Выбран пункт меню 1."),
211
+ },
212
+ {
213
+ id: "list-item-swipe-controls-dropdown-option-2",
214
+ label: "Текст пункта меню 2",
215
+ onSelect: () => alert("Выбран пункт меню 2."),
216
+ },
217
+ {
218
+ id: "list-item-swipe-controls-dropdown-option-3",
219
+ label: "Текст пункта меню 3",
220
+ onSelect: () => alert("Выбран пункт меню 3."),
221
+ },
222
+ ];
223
+
224
+ const ref = React.useRef<ISwipeableAreaRef>(null);
225
+
226
+ return (
227
+ <div style={{ maxWidth: "500px" }}>
228
+ <button
229
+ onClick={() => {
230
+ if (ref.current) {
231
+ ref.current.swipeLeft();
232
+ }
233
+ }}
234
+ >
235
+ swipe
236
+ </button>
237
+ <button
238
+ onClick={() => {
239
+ if (ref.current) {
240
+ ref.current.closeSwipe();
241
+ }
242
+ }}
243
+ >
244
+ close
245
+ </button>
246
+ <br />
247
+
248
+ <List>
249
+ <ListItem>
250
+ <SwipeableArea
251
+ ref={ref}
252
+ rightSwipeableArea={
253
+ <ListItemControls>
254
+ <ListItemControlsButton icon={<DefaulticonStrokePrdIcon20 paletteIndex={0} />}>
255
+ Button name
256
+ </ListItemControlsButton>
257
+ <ListItemControlsButtonDropdown
258
+ icon={<DefaulticonStrokePrdIcon20 paletteIndex={0} />}
259
+ options={options}
260
+ >
261
+ Button name
262
+ </ListItemControlsButtonDropdown>
263
+ </ListItemControls>
264
+ }
265
+ >
266
+ <ListItemTailRight />
267
+ {/* Минимальная высота, из-за блока Action с кнопками при свайпе. */}
268
+ <ListItemContent style={{ minHeight: "56px" }}>Свайп влево</ListItemContent>
269
+ </SwipeableArea>
270
+ </ListItem>
271
+ </List>
272
+ </div>
273
+ );
274
+ };
275
+ ```
276
+
@@ -0,0 +1,103 @@
1
+ ---
2
+ component: ListItemControlsButton
3
+ category: List
4
+ related: [ListItemControls, ListItemControlsButtonDropdown, IconWrapper]
5
+ tokens:
6
+ - --triplex-next-ListItemControlsButton-Background_Default
7
+ - --triplex-next-ListItemControlsButton-Background_Hover
8
+ - --triplex-next-ListItemControlsButton-Background_Active
9
+ - --triplex-next-ListItemControlsButton-Color_Default
10
+ - --triplex-next-ListItemControlsButton-Color_Hover
11
+ - --triplex-next-ListItemControlsButton-Color_Active
12
+ stories: stories/List/ListItemControls.stories.tsx
13
+ version: "1.0"
14
+ ---
15
+
16
+ # ListItemControlsButton
17
+
18
+ ## Назначение
19
+
20
+ Кнопка действия для области под свайпом списка. Рендерит вертикальную
21
+ композицию `icon` + `children` (текст), оборачивает их в `IconWrapper`,
22
+ который автоматически меняет цвет иконки/текста в hover/active состоянии.
23
+
24
+ Используй `ListItemControlsButton` когда: нужно одно действие в swipe-actions.
25
+ Используй `ListItemControlsButtonDropdown` когда: нужен выбор из нескольких
26
+ действий через dropdown.
27
+
28
+ ---
29
+
30
+ ## Варианты и props
31
+
32
+ ### Опциональные props
33
+
34
+ | Prop | Тип | По умолчанию | Описание |
35
+ |---|---|---|---|
36
+ | `icon` | `React.ReactNode` | — | Иконка, отображается над текстом. Добавляет класс `withIcon` |
37
+ | `children` | `React.ReactNode` | — | Текст кнопки (рендерится через `<Text size={B4} weight={SEMIBOLD}>`). Добавляет класс `withText` |
38
+ | `disabled` | `boolean` | — | Стандартный атрибут `<button>`. Передаётся в `IconWrapper.disabled` |
39
+ | `aria-expanded` | `boolean` | — | Стандартный ARIA-атрибут. Если `true` — `IconWrapper` получает класс `active` (визуальное состояние «нажато») |
40
+ | `...HTMLButtonAttributes` | — | — | Все стандартные атрибуты `<button>`. `type` по умолчанию `"button"` |
41
+
42
+ ---
43
+
44
+ ## Дизайн-токены
45
+
46
+ Паттерн: `--triplex-next-ListItemControlsButton-{Property}_{State}`
47
+
48
+ ```text
49
+ --triplex-next-ListItemControlsButton-Background_Default
50
+ --triplex-next-ListItemControlsButton-Background_Hover
51
+ --triplex-next-ListItemControlsButton-Background_Active // применяется при :active или классе .expanded (если выставлен снаружи)
52
+ --triplex-next-ListItemControlsButton-Color_Default
53
+ --triplex-next-ListItemControlsButton-Color_Hover
54
+ --triplex-next-ListItemControlsButton-Color_Active
55
+ ```
56
+
57
+ Цвет лейбла переопределяет токен `Color_*` через `!important`, потому что
58
+ `<Text>` имеет свой `color`-стиль.
59
+
60
+ ---
61
+
62
+ ## Инварианты
63
+
64
+ - **`forwardRef`** — обязателен, target — `HTMLButtonElement`. Не убирать.
65
+ - **`type="button"`** по умолчанию — не убирать, иначе кнопка внутри `<form>` будет сабмитить.
66
+ - **Классы `withIcon` / `withText`** — выставляются автоматически по наличию `icon` / `children`. Не передавать вручную.
67
+ - **Лейбл оборачивается в `<Text>`** — не заменять на `<span>`, иначе сломается типографика и переопределение цвета через токены.
68
+
69
+ ---
70
+
71
+ ## Accessibility
72
+
73
+ - Нативный `<button>` — полная поддержка клавиатуры (Tab, Enter, Space).
74
+ - **Иконочный режим** (без `children`) — потребитель **обязан** передать `aria-label` через `...rest`. Библиотека мультиязычная, текст не хардкодится.
75
+ - **`aria-expanded`** — используется когда кнопка является триггером dropdown (см. `ListItemControlsButtonDropdown`); визуально активирует подсветку иконки/текста через `IconWrapper.active`.
76
+
77
+ ---
78
+
79
+ ## Связанные компоненты
80
+
81
+ - `ListItemControls` — обёртка-контейнер для группы `ListItemControlsButton`.
82
+ - `ListItemControlsButtonDropdown` — расширение, добавляющее dropdown.
83
+ - `IconWrapper` — обёртка для иконки, управляет цветом через `hoverable` / `active` / `disabled`.
84
+ - `Text` — типографический компонент для лейбла.
85
+
86
+ ---
87
+
88
+ ## Stories
89
+
90
+ Основные истории: `stories/List/ListItemControls.stories.tsx`
91
+ Файл примера: `stories/List/examples/ListItemControls/Default.tsx`
92
+
93
+ | Story | Example file | Что демонстрирует |
94
+ |---|---|---|
95
+ | `Default` | `Default.tsx` | Несколько кнопок (icon-only, text-only, icon+text) и `ListItemControlsButtonDropdown` внутри `ListItemControls` |
96
+
97
+ ---
98
+
99
+ ## История изменений
100
+
101
+ | Дата | Изменение |
102
+ |---|---|
103
+ | 2026-04-29 | Создан документ |
@@ -0,0 +1,107 @@
1
+ ---
2
+ component: ListItemControlsButtonDropdown
3
+ category: List
4
+ related: [ListItemControlsButton, ButtonDropdownExtended, Dropdown]
5
+ tokens:
6
+ - --triplex-next-ListItemControlsButton-Background_Default
7
+ - --triplex-next-ListItemControlsButton-Background_Hover
8
+ - --triplex-next-ListItemControlsButton-Background_Active
9
+ - --triplex-next-ListItemControlsButton-Color_Default
10
+ - --triplex-next-ListItemControlsButton-Color_Hover
11
+ - --triplex-next-ListItemControlsButton-Color_Active
12
+ stories: stories/List/ListItemControls.stories.tsx
13
+ version: "1.0"
14
+ ---
15
+
16
+ # ListItemControlsButtonDropdown
17
+
18
+ ## Назначение
19
+
20
+ Кнопка-триггер для dropdown-меню в swipe-actions списка. Использует
21
+ `ListItemControlsButton` как кнопку и `ButtonDropdownExtended` для
22
+ выпадающего списка опций. На мобильном — bottom sheet, на десктопе — обычный
23
+ dropdown.
24
+
25
+ Используй когда: в swipe-actions нужно несколько действий, объединённых под
26
+ одной кнопкой (обычно «Действия» / «Ещё»).
27
+
28
+ ---
29
+
30
+ ## Варианты и props
31
+
32
+ Тип props: `Omit<IButtonDropdownProps, "size"> & Pick<IListItemControlsButtonProps, "icon">`
33
+
34
+ ### Обязательные props
35
+
36
+ | Prop | Тип | Описание |
37
+ |---|---|---|
38
+ | `options` | `IButtonDropdownOption[]` | Список опций dropdown. Каждая опция: `{ id, label, onSelect?, ...IDropdownListItemProps }` |
39
+ | `children` | `React.ReactNode` | Текст кнопки (становится заголовком mobile-bottom-sheet) |
40
+
41
+ ### Опциональные props
42
+
43
+ | Prop | Тип | Описание |
44
+ |---|---|---|
45
+ | `icon` | `React.ReactNode` | Иконка кнопки (как в `ListItemControlsButton`) |
46
+ | `selected` | `IButtonDropdownOption` | Текущая выбранная опция (отмечается в dropdown) |
47
+ | `disabled` | `boolean` | Блокирует кнопку и открытие dropdown |
48
+ | `buttonAttributes` | `React.ButtonHTMLAttributes<HTMLButtonElement>` | Атрибуты, пробрасываемые на `<button>` |
49
+ | `...HTMLDivAttributes` | — | Атрибуты внешнего `<div>` контейнера |
50
+
51
+ ---
52
+
53
+ ## Дизайн-токены
54
+
55
+ Использует те же токены, что и `ListItemControlsButton`. Дополнительно — стиль
56
+ `.buttonDropdownMenuItem` для опций dropdown (ellipsis для длинных лейблов).
57
+
58
+ ---
59
+
60
+ ## Инварианты
61
+
62
+ - **`forwardRef`** — обязателен, target — `HTMLButtonElement` (на саму кнопку, не на контейнер).
63
+ - **`aria-haspopup="menu"`, `aria-controls={instanceId}`** — выставляются автоматически. `aria-expanded` синхронизируется с состоянием `opened`.
64
+ - **`closeOnTab`** — включён всегда (Tab закрывает dropdown).
65
+ - **`uniqueId` для `instanceId`** — используется `lodash-es/uniqueId` через `useRef(uniqueId())`. **Не** мигрировать на `useId()` — ветка `release-0` поддерживает React 17, см. `docs/ai/ai-refactoring.md`.
66
+
67
+ ---
68
+
69
+ ## Accessibility
70
+
71
+ - **Клавиатура:**
72
+ - `Space`, `ArrowUp`, `ArrowDown` — `preventDefault` (не скроллит страницу).
73
+ - `ArrowUp` / `ArrowDown` в закрытом состоянии — открывают dropdown.
74
+ - `Escape` / `Tab` — закрывают dropdown (через `ButtonDropdownExtended`).
75
+ - **`aria-haspopup="menu"`** — указывает на наличие меню.
76
+ - **`aria-expanded`** — синхронизирован с `opened` (true/false).
77
+ - **`aria-controls`** — связывает кнопку с id dropdown.
78
+ - **`aria-activedescendant`** — управляется через `DropdownListContext`, указывает на текущий выделенный элемент.
79
+
80
+ ---
81
+
82
+ ## Связанные компоненты
83
+
84
+ - `ListItemControlsButton` — используется как сама кнопка-триггер.
85
+ - `ButtonDropdownExtended` — обвязка для кастомных кнопок + dropdown.
86
+ - `Dropdown`, `DropdownList` (desktop) — выпадающий список на десктопе.
87
+ - `DropdownMobileBody`, `DropdownMobileList`, `DropdownMobileListItem`, `DropdownMobileHeader`, `DropdownMobileClose` — bottom-sheet на мобильном.
88
+ - `DropdownListContext` — управление `activeDescendant`.
89
+
90
+ ---
91
+
92
+ ## Stories
93
+
94
+ Основные истории: `stories/List/ListItemControls.stories.tsx`
95
+ Файл примера: `stories/List/examples/ListItemControls/Default.tsx`
96
+
97
+ | Story | Example file | Что демонстрирует |
98
+ |---|---|---|
99
+ | `Default` | `Default.tsx` | `ListItemControlsButtonDropdown` рядом с `ListItemControlsButton` внутри `ListItemControls` |
100
+
101
+ ---
102
+
103
+ ## История изменений
104
+
105
+ | Дата | Изменение |
106
+ |---|---|
107
+ | 2026-04-29 | Создан документ |
@@ -0,0 +1,99 @@
1
+ ---
2
+ component: ListItemSelectable
3
+ category: List
4
+ related: [ListItem, ListItemContent, Checkbox]
5
+ tokens:
6
+ - --triplex-next-ListItem-Background
7
+ - --triplex-next-ListItem-Background_Selected
8
+ stories: stories/List/ListItem.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # ListItemSelectable
13
+
14
+ ## Назначение
15
+
16
+ Контейнер выбора элемента списка. Рендерит контент + чекбокс справа.
17
+ Управляется снаружи (`selected` + `onSelect`). Через `useEffect` записывает
18
+ в `ListItemContext` два флага: `selected` — для подсветки фона дочернего
19
+ `ListItemContent` (`background_selected`); `selectable: true` — для
20
+ применения скругления углов (`border-radius`) в `ListItemContent`.
21
+
22
+ Используй `ListItemSelectable` когда: нужен выбор отдельного элемента списка
23
+ с собственным чекбоксом (multi-select).
24
+
25
+ ---
26
+
27
+ ## Варианты и props
28
+
29
+ ### Обязательные props
30
+
31
+ | Prop | Тип | Описание |
32
+ |---|---|---|
33
+ | `selected` | `boolean` | Состояние «выбран». Управляется снаружи |
34
+ | `onSelect` | `(selected: boolean) => void` | Вызывается при изменении состояния чекбокса |
35
+
36
+ ### Опциональные props
37
+
38
+ | Prop | Тип | Описание |
39
+ |---|---|---|
40
+ | `disabled` | `boolean` | Блокирует встроенный `Checkbox` (передаётся в `Checkbox` как есть) |
41
+ | `children` | `React.ReactNode` | Контент строки (рендерится в `<div className="childrenWrapper">`) |
42
+ | `...HTMLDivAttributes` | — | Все атрибуты `<div>`, кроме конфликтующего `onSelect` (исключён через `Omit`) |
43
+
44
+ ---
45
+
46
+ ## Дизайн-токены
47
+
48
+ ```text
49
+ --triplex-next-ListItem-Background // фон по умолчанию
50
+ --triplex-next-ListItem-Background_Selected // фон, когда selected=true
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Инварианты
56
+
57
+ - **`forwardRef`** — обязателен, target — `HTMLDivElement`. Не убирать.
58
+ - **Контракт `onSelect: (boolean) => void`** — не путать с нативным `onSelect: SelectionEvent` от `<div>`. Тип специально перекрывает нативный через `Omit<..., "onSelect">`.
59
+ - **Два `useEffect`** — синхронизируют `ListItemContext`:
60
+ - `[selected, setSelected]` → запись `selected` (для подсветки `ListItemContent`).
61
+ - `[setSelectable]` → запись `selectable = true` при монтировании и cleanup в `false` при размонтировании (для скругления углов `ListItemContent`). Не убирать запись — иначе у выбираемого элемента не появится `border-radius`. Не убирать cleanup — иначе при условном размонтировании `ListItemSelectable` внутри живого `ListItem` состояние «прилипнет» в `true`.
62
+ - **Использование внутри `ListItem`** — `setSelected` / `setSelectable` берутся из `ListItemContext`. Если рендерить `ListItemSelectable` без родительского `ListItem`, контекст вернёт no-op сеттеры.
63
+
64
+ ---
65
+
66
+ ## Accessibility
67
+
68
+ - Чекбокс — встроенный `<Checkbox>` из библиотеки, имеет нативный `<input type="checkbox">`.
69
+ - Клик по любой части `.childrenWrapper` **не** переключает чекбокс — только клик по самому чекбоксу или его расширенной области (`.checkboxLabelClickArea`, `+4px` со всех сторон).
70
+ - Если нужен клик по всей строке — оборачивай в `<label>` или используй `ListTableItem` + `onClickItem`.
71
+
72
+ ---
73
+
74
+ ## Связанные компоненты
75
+
76
+ - `ListItem` — родительский `<li>`, провайдер `ListItemContext`.
77
+ - `ListItemContent` — потребитель `ListItemContext.selected` для применения класса `selected`.
78
+ - `Checkbox` — встроенный чекбокс выбора.
79
+ - `ListTableItem` — использует `ListItemSelectable` автоматически в selectable-варианте.
80
+
81
+ ---
82
+
83
+ ## Stories
84
+
85
+ Основные истории: `stories/List/ListItem.stories.tsx`
86
+ Файл примера: `stories/List/examples/ListItem/Selectable.tsx`
87
+
88
+ | Story | Example file | Что демонстрирует |
89
+ |---|---|---|
90
+ | `Selectable` | `Selectable.tsx` | Использование `ListItemSelectable` внутри `ListItem` |
91
+
92
+ ---
93
+
94
+ ## История изменений
95
+
96
+ | Дата | Изменение |
97
+ |---|---|
98
+ | 2026-04-29 | Создан документ |
99
+ | 2026-05-21 | Добавлен опциональный prop `disabled` (пробрасывается в `Checkbox`). Компонент пишет в `ListItemContext` флаг `selectable = true` при монтировании. |