@sberbusiness/triplex-next-mcp-server 0.24.0-beta1

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 (140) hide show
  1. package/README.md +124 -0
  2. package/bundle/.gitkeep +0 -0
  3. package/bundle/components/AbstractTree.md +198 -0
  4. package/bundle/components/AccordionBase.md +227 -0
  5. package/bundle/components/Alert.md +317 -0
  6. package/bundle/components/Amount.md +225 -0
  7. package/bundle/components/AmountField.md +289 -0
  8. package/bundle/components/Avatar.md +209 -0
  9. package/bundle/components/Badge.md +277 -0
  10. package/bundle/components/Body.md +167 -0
  11. package/bundle/components/Button.md +230 -0
  12. package/bundle/components/ButtonDropdown.md +159 -0
  13. package/bundle/components/ButtonIcon.md +122 -0
  14. package/bundle/components/Calendar.md +445 -0
  15. package/bundle/components/Card.md +374 -0
  16. package/bundle/components/CarouselExtended.md +250 -0
  17. package/bundle/components/Checkbox.md +126 -0
  18. package/bundle/components/CheckboxTree.md +280 -0
  19. package/bundle/components/CheckboxTreeExtended.md +321 -0
  20. package/bundle/components/CheckboxXGroup.md +68 -0
  21. package/bundle/components/CheckboxYGroup.md +67 -0
  22. package/bundle/components/Chip.md +404 -0
  23. package/bundle/components/ChipGroup.md +179 -0
  24. package/bundle/components/Col.md +221 -0
  25. package/bundle/components/CollapsableTree.md +255 -0
  26. package/bundle/components/Confirm.md +343 -0
  27. package/bundle/components/DateField.md +371 -0
  28. package/bundle/components/DatePickerExtended.md +342 -0
  29. package/bundle/components/DateRange.md +275 -0
  30. package/bundle/components/DesignTokens.md +385 -0
  31. package/bundle/components/Divider.md +196 -0
  32. package/bundle/components/DocumentNumberEdit.md +280 -0
  33. package/bundle/components/Dropdown.md +433 -0
  34. package/bundle/components/Ellipsis.md +208 -0
  35. package/bundle/components/EmptyView.md +99 -0
  36. package/bundle/components/ExpandAnimation.md +281 -0
  37. package/bundle/components/Footer.md +339 -0
  38. package/bundle/components/FormField.md +326 -0
  39. package/bundle/components/FormGroup.md +99 -0
  40. package/bundle/components/Gap.md +113 -0
  41. package/bundle/components/Header.md +280 -0
  42. package/bundle/components/HelpBox.md +154 -0
  43. package/bundle/components/IconWrapper.md +145 -0
  44. package/bundle/components/Island.md +197 -0
  45. package/bundle/components/IslandAccordion.md +230 -0
  46. package/bundle/components/IslandWidget.md +233 -0
  47. package/bundle/components/KeyDownListener.md +157 -0
  48. package/bundle/components/LightBox.md +322 -0
  49. package/bundle/components/Link.md +161 -0
  50. package/bundle/components/List.md +247 -0
  51. package/bundle/components/ListMaster.md +204 -0
  52. package/bundle/components/Loader.md +161 -0
  53. package/bundle/components/LoaderScreen.md +134 -0
  54. package/bundle/components/Marker.md +127 -0
  55. package/bundle/components/MarkerStatus.md +148 -0
  56. package/bundle/components/MediaWidth.md +169 -0
  57. package/bundle/components/MobileView.md +120 -0
  58. package/bundle/components/ModalWindow.md +308 -0
  59. package/bundle/components/MonthYearField.md +168 -0
  60. package/bundle/components/MultiselectField.md +213 -0
  61. package/bundle/components/Notification.md +233 -0
  62. package/bundle/components/NumberField.md +178 -0
  63. package/bundle/components/OrderedList.md +169 -0
  64. package/bundle/components/Overlay.md +237 -0
  65. package/bundle/components/Page.md +246 -0
  66. package/bundle/components/Pagination.md +298 -0
  67. package/bundle/components/Portal.md +119 -0
  68. package/bundle/components/Radio.md +174 -0
  69. package/bundle/components/Row.md +125 -0
  70. package/bundle/components/SMSField.md +160 -0
  71. package/bundle/components/SegmentedControl.md +235 -0
  72. package/bundle/components/SelectExtendedField.md +322 -0
  73. package/bundle/components/SelectField.md +213 -0
  74. package/bundle/components/Skeleton.md +129 -0
  75. package/bundle/components/Slider.md +157 -0
  76. package/bundle/components/SliderExtended.md +210 -0
  77. package/bundle/components/SliderRange.md +160 -0
  78. package/bundle/components/SmallInput.md +101 -0
  79. package/bundle/components/Spoiler.md +121 -0
  80. package/bundle/components/StatusTracker.md +151 -0
  81. package/bundle/components/Step.md +121 -0
  82. package/bundle/components/Stepper.md +163 -0
  83. package/bundle/components/Suggest.md +160 -0
  84. package/bundle/components/SuggestField.md +157 -0
  85. package/bundle/components/SwipeableArea.md +144 -0
  86. package/bundle/components/Table.md +199 -0
  87. package/bundle/components/Tabs.md +152 -0
  88. package/bundle/components/TabsExtended.md +273 -0
  89. package/bundle/components/TabsLine.md +189 -0
  90. package/bundle/components/Tag.md +135 -0
  91. package/bundle/components/TagColor.md +121 -0
  92. package/bundle/components/TagGroup.md +100 -0
  93. package/bundle/components/TextField.md +152 -0
  94. package/bundle/components/TextareaField.md +124 -0
  95. package/bundle/components/ThemeProvider.md +181 -0
  96. package/bundle/components/Tooltip.md +254 -0
  97. package/bundle/components/TopOverlay.md +145 -0
  98. package/bundle/components/TreeView.md +224 -0
  99. package/bundle/components/Triggers.md +121 -0
  100. package/bundle/guides/codestyle.md +205 -0
  101. package/bundle/guides/commits.md +166 -0
  102. package/bundle/guides/context.md +277 -0
  103. package/bundle/guides/stories.md +618 -0
  104. package/bundle/guides/template.md +154 -0
  105. package/bundle/guides/tests.md +301 -0
  106. package/bundle/icons.json +4156 -0
  107. package/bundle/manifest.json +796 -0
  108. package/bundle/release-notes/1.1.0.mdx +26 -0
  109. package/bundle/release-notes/1.1.1.mdx +14 -0
  110. package/bundle/release-notes/1.10.0.mdx +43 -0
  111. package/bundle/release-notes/1.11.0.mdx +19 -0
  112. package/bundle/release-notes/1.12.0.mdx +21 -0
  113. package/bundle/release-notes/1.13.0.mdx +43 -0
  114. package/bundle/release-notes/1.14.0.mdx +29 -0
  115. package/bundle/release-notes/1.15.0.mdx +56 -0
  116. package/bundle/release-notes/1.16.0.mdx +55 -0
  117. package/bundle/release-notes/1.17.0.mdx +15 -0
  118. package/bundle/release-notes/1.18.0.mdx +24 -0
  119. package/bundle/release-notes/1.19.0.mdx +48 -0
  120. package/bundle/release-notes/1.19.1.mdx +9 -0
  121. package/bundle/release-notes/1.2.0.mdx +80 -0
  122. package/bundle/release-notes/1.20.0.mdx +48 -0
  123. package/bundle/release-notes/1.21.0.mdx +66 -0
  124. package/bundle/release-notes/1.22.0.mdx +75 -0
  125. package/bundle/release-notes/1.23.0.mdx +50 -0
  126. package/bundle/release-notes/1.24.0.mdx +59 -0
  127. package/bundle/release-notes/1.25.0.mdx +52 -0
  128. package/bundle/release-notes/1.26.0.mdx +11 -0
  129. package/bundle/release-notes/1.3.0.mdx +21 -0
  130. package/bundle/release-notes/1.4.0.mdx +37 -0
  131. package/bundle/release-notes/1.5.0.mdx +24 -0
  132. package/bundle/release-notes/1.6.0.mdx +37 -0
  133. package/bundle/release-notes/1.6.1.mdx +11 -0
  134. package/bundle/release-notes/1.7.0.mdx +29 -0
  135. package/bundle/release-notes/1.8.0.mdx +38 -0
  136. package/bundle/release-notes/1.9.0.mdx +28 -0
  137. package/dist/index.d.ts +2 -0
  138. package/dist/index.js +324 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +51 -0
@@ -0,0 +1,247 @@
1
+ ---
2
+ component: List
3
+ category: Data Display
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [ListMaster, Table, TreeView, Checkbox, LoaderScreen]
7
+ tokens: []
8
+ stories: stories/List/List.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # List
13
+
14
+ ## Назначение
15
+
16
+ Семейство компонентов для списков (`<ul>` / `<li>`) с набором слотов
17
+ для строк: контент, правый контролы-блок, хвосты слева/справа, чекбокс-
18
+ выбор, вложенный DropdownButton, drag-and-drop. Поддерживает loading-overlay
19
+ на уровне списка.
20
+
21
+ Используй когда: нужен табличный список с повторяющимися строками и
22
+ фиксированной визуальной структурой. Для таблиц с колонками — `Table`,
23
+ для древовидных — `TreeView`, для master-detail интерфейсов — `ListMaster`.
24
+
25
+ ---
26
+
27
+ ## Файловая структура
28
+
29
+ ```text
30
+ src/components/List/
31
+ ├── List.tsx # <ul>, loading-overlay
32
+ ├── ListSortable.tsx # DnD обёртка (dnd-kit)
33
+ ├── index.ts # Barrel всех слотов
34
+ ├── components/
35
+ │ ├── ListItem.tsx # <li> + Provider ListItemContext
36
+ │ ├── ListItemContext.ts # { selected, setSelected }
37
+ │ ├── ListItemContent.tsx # Основной контент строки
38
+ │ ├── ListItemControls.tsx # Правый блок кнопок
39
+ │ ├── ListItemControlsButton.tsx # Стилизованная кнопка в Controls
40
+ │ ├── ListItemControlsButtonDropdown.tsx # Кнопка с выпадающим меню
41
+ │ ├── ListItemSelectable.tsx # Обёртка с Checkbox, пишет selected в Context
42
+ │ ├── ListItemTable.tsx # Табличный вид строки
43
+ │ ├── ListItemTailLeft.tsx # Левый хвост (иконка, аватар)
44
+ │ ├── ListItemTailRight.tsx # Правый хвост
45
+ │ ├── ListItemLoading.tsx # Placeholder-строка при loading
46
+ │ ├── ListEmptyState.tsx # Пустое состояние
47
+ │ ├── ListSortableItem.tsx # <li> с useSortable (DnD)
48
+ │ ├── ListSortableItemControls.tsx # DnD-handle control (drag)
49
+ │ └── ListSortableItemTarget.tsx # Цель сортировки
50
+ └── styles/*.module.less
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Варианты и props
56
+
57
+ ### List — `IListProps extends HTMLAttributes<HTMLUListElement>`
58
+
59
+ | Prop | Тип | Default | Описание |
60
+ |---|---|---|---|
61
+ | `loading` | `boolean` | — | Накладывает `LoaderScreen type="middle"` поверх списка. |
62
+ | `...ulAttributes` | — | — | Стандартные `<ul>`-атрибуты. |
63
+
64
+ ### ListItem — `IListItemProps extends LiHTMLAttributes<HTMLLIElement>`
65
+
66
+ Создаёт собственный `ListItemContext` с `{ selected, setSelected }`. Подкомпоненты (`ListItemSelectable`) пишут в него.
67
+
68
+ ### ListItemSelectable — `IListItemSelectableProps extends Omit<HTMLDivAttributes, "onSelect">`
69
+
70
+ | Prop | Тип | Обязателен | Описание |
71
+ |---|---|---|---|
72
+ | `selected` | `boolean` | Да | Управляемое состояние выбора. |
73
+ | `onSelect` | `(selected: boolean) => void` | Да | Callback при изменении. |
74
+
75
+ - Внутри — `<Checkbox>` + `useEffect(() => setSelected(selected))` — синхронизирует с `ListItemContext`, чтобы сиблинги (например, стили строки) могли реагировать на выбор.
76
+ - `<span className={styles.checkboxLabelClickArea} />` — растягивающаяся область клика (не только на чекбокс).
77
+
78
+ ### ListItemContent — базовый слот для текста/описания строки.
79
+
80
+ ### ListItemControls / ListItemControlsButton / …ButtonDropdown
81
+
82
+ | Компонент | Назначение |
83
+ |---|---|
84
+ | `ListItemControls` | Контейнер для кнопок справа. |
85
+ | `ListItemControlsButton` | Стилизованная кнопка-иконка. |
86
+ | `ListItemControlsButtonDropdown` | Кнопка + вложенное выпадающее меню. |
87
+
88
+ ### ListItemTailLeft / ListItemTailRight — хвосты (иконки, аватары, статусы) по краям строки.
89
+
90
+ ### ListItemTable
91
+
92
+ Табличный вид строки: внутренняя сетка для выравнивания колонок между строками.
93
+
94
+ ### ListItemLoading — скелетон-строка, показывается во время загрузки.
95
+
96
+ ### ListEmptyState — рендерится, когда `items.length === 0`, параметры для заголовка/описания/иконки.
97
+
98
+ ### ListSortable<T extends { id: string }> — `IListSortableProps<T>`
99
+
100
+ | Prop | Тип | Обязателен | Описание |
101
+ |---|---|---|---|
102
+ | `items` | `T[]` | Да | Массив элементов, у каждого должно быть поле `id`. |
103
+ | `onItemsChange` | `(items: T[]) => void` | Да | Callback после перестановки. |
104
+ | `...IListProps` | — | — | Проброс на `<List>`. |
105
+
106
+ - Обёртка над `@dnd-kit/core` + `@dnd-kit/sortable`.
107
+ - Modifiers: `restrictToParentElement` + `restrictToVerticalAxis` — нельзя перетащить в другой родитель или по горизонтали.
108
+ - Внутри использует `AdvancedMouseSensor` / `AdvancedTouchSensor` — расширенные sensor'ы.
109
+
110
+ ### ListSortableItem — `IListSortableItemProps extends Omit<LiHTMLAttributes, "children">`
111
+
112
+ | Prop | Тип | Обязателен | Описание |
113
+ |---|---|---|---|
114
+ | `id` | `string` | Да | Уникальный идентификатор, должен совпадать с `items[i].id`. |
115
+ | `disabled` | `boolean` | Нет | Блокирует drag. |
116
+ | `children` | `ReactNode \| (provideProps) => ReactNode` | — | **Render-props или обычные children**. Provide-props: `{ dragging, disabled, listeners, setActivatorNodeRef }`. |
117
+
118
+ - Использует `useSortable` из dnd-kit, применяет `transform` стиль.
119
+ - Render-props позволяют **селективно назначать drag handle** (через `listeners` + `setActivatorNodeRef`), а не делать перетаскиваемым всю строку.
120
+ - `ListSortableItem.Target` (Object.assign) — подкомпонент `ListSortableItemTarget`.
121
+
122
+ ---
123
+
124
+ ## Ключевые особенности реализации
125
+
126
+ ### `AdvancedMouseSensor` / `AdvancedTouchSensor` — `data-draggable="false"` escape hatch
127
+
128
+ ```ts
129
+ while (element !== null) {
130
+ if (element.dataset?.draggable === "false") return false;
131
+ element = element.parentElement;
132
+ }
133
+ ```
134
+
135
+ - Любой потомок с `data-draggable="false"` **блокирует инициализацию drag'а**. Используется для кнопок/ссылок внутри строки — иначе клик по ним случайно запускает перетаскивание.
136
+ - `MouseSensor`: игнорирует правую кнопку (`button === 2`).
137
+ - `TouchSensor`: игнорирует мультитач (`touches.length > 1`).
138
+
139
+ ### `ListItemContext` — связь выбора и стилей сиблингов
140
+
141
+ ```tsx
142
+ <ListItemContext.Provider value={{ selected, setSelected }}>
143
+ <li>{children}</li>
144
+ </ListItemContext.Provider>
145
+ ```
146
+
147
+ - `ListItemSelectable` пишет `selected` в контекст через `useEffect`.
148
+ - Другие подкомпоненты (например, `ListItemContent`) могут подписаться и изменить стиль.
149
+ - **Паттерн "выбор известен всей строке"** — без prop-drilling.
150
+
151
+ ### `loading` на уровне `List`
152
+
153
+ ```tsx
154
+ <ul>
155
+ {children}
156
+ {loading ? <LoaderScreen type="middle" /> : null}
157
+ </ul>
158
+ ```
159
+
160
+ LoaderScreen рендерится **внутри `<ul>`**, но позиционируется абсолютно (overlay). Структурно `<ul>` содержит `<li>` и невалидный для семантики элемент — это сознательный trade-off в пользу простоты позиционирования.
161
+
162
+ ### `data-tx={process.env.npm_package_version}` на `<ul>` и `<li>`
163
+
164
+ Версия библиотеки в DOM для отладки. Сохранять при изменениях.
165
+
166
+ ### ListSortable — vertical-axis only
167
+
168
+ ```ts
169
+ modifiers: [restrictToParentElement, restrictToVerticalAxis]
170
+ ```
171
+
172
+ - Список только вертикальный. Для горизонтальных списков — нужен отдельный компонент (сейчас не реализован).
173
+
174
+ ### ListSortableItem render-props
175
+
176
+ ```tsx
177
+ <ListSortableItem id="1">
178
+ {({ listeners, setActivatorNodeRef }) => (
179
+ <>
180
+ <ListSortableItem.Target ref={setActivatorNodeRef} {...listeners}>
181
+ ≡
182
+ </ListSortableItem.Target>
183
+ {/* остальной контент — не перетаскиваемый */}
184
+ </>
185
+ )}
186
+ </ListSortableItem>
187
+ ```
188
+
189
+ Стандартный паттерн dnd-kit. `setActivatorNodeRef` задаёт элемент-триггер перетаскивания (handle), `listeners` — события.
190
+
191
+ ---
192
+
193
+ ## Инварианты
194
+
195
+ - **`<ul>` + `<li>`** семантика — не заменять на `<div>`.
196
+ - **`ListItemContext` shape** (`selected`, `setSelected`) — публичная точка расширения для сторонних кастомных подкомпонентов.
197
+ - **`data-draggable="false"`** — атрибут-escape-hatch для ListSortable. Потребители в product-коде могут опираться на него, не менять семантику.
198
+ - **`ListSortable` требует `items[].id: string`** — id как в React key, так и в dnd-kit. Переход на number/symbol — breaking.
199
+ - **`arrayMove` от dnd-kit** — не собственная реализация. При смене DnD-библиотеки переписать.
200
+ - **`IListSortableItemProps.children` — `ReactNode` или функция** — публичный render-props API.
201
+ - **`LoaderScreen` внутри `<ul>`** — визуальное решение, не менять без согласования.
202
+ - **ForwardRef** на всех компонентах; `ListSortable` — generic через `as <T>(props) => ...` cast.
203
+ - **`Object.assign` на `ListSortableItem` → `Target`** — сохранить.
204
+
205
+ ---
206
+
207
+ ## Accessibility
208
+
209
+ - Семантика списка `<ul>`/`<li>` — правильная. Screen reader'ы объявляют "list, N items".
210
+ - `ListItemSelectable` — `<Checkbox>` внутри: нативная клавиатурная навигация, label через расширяющую clickable-область.
211
+ - `ListItemControlsButton` / `ListItemControlsButtonDropdown` — проверь, что `aria-label` проставлен (иконки без текста).
212
+ - **DnD не доступен с клавиатуры** из коробки (dnd-kit поддерживает `KeyboardSensor`, но здесь не подключён). Known debt.
213
+ - Loader'овый overlay скрывает контент — добавь `aria-busy="true"` на `<ul>` через `...rest` на время загрузки.
214
+
215
+ ---
216
+
217
+ ## Дизайн-токены
218
+
219
+ Нет прямых — визуал строки зависит от подкомпонентов (`ListItemSelectable`, `ListItemControls` используют собственные стили в `styles/*.module.less`).
220
+
221
+ ---
222
+
223
+ ## Связанные компоненты
224
+
225
+ - `ListMaster` — master-detail layout на базе List.
226
+ - `Table` — табличный вид с колонками.
227
+ - `TreeView` — древовидный список.
228
+ - `Checkbox` — используется в `ListItemSelectable`.
229
+ - `LoaderScreen` — overlay для loading.
230
+ - `@dnd-kit/core`, `@dnd-kit/sortable`, `@dnd-kit/modifiers` — DnD-инфраструктура.
231
+
232
+ ---
233
+
234
+ ## Stories
235
+
236
+ - `stories/List/List.stories.tsx`
237
+ - `stories/List/ListItem.stories.tsx`
238
+ - `stories/List/ListItemControls.stories.tsx`
239
+ - Примеры: `stories/List/examples/`
240
+
241
+ ---
242
+
243
+ ## История изменений
244
+
245
+ | Дата | Изменение |
246
+ |---|---|
247
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,204 @@
1
+ ---
2
+ component: ListMaster
3
+ category: Data Display
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [List, ChipGroup, Checkbox]
7
+ tokens: []
8
+ stories: ""
9
+ version: "1.0"
10
+ ---
11
+
12
+ # ListMaster
13
+
14
+ ## Назначение
15
+
16
+ Тонкий layout-контейнер для экрана "список + фильтры + контролы выбора":
17
+ оборачивает Header (sticky, со sticky-компенсацией scroll'а), Body (контент),
18
+ ChipGroup (горизонтальные фильтры-чипы), Footer (sticky), SelectionControls
19
+ (пакетные действия над выбранными элементами). Всё через compound-api
20
+ `ListMaster.Header` / `.Body` / `.Footer` / `.ChipGroup` / `.SelectionControls`.
21
+
22
+ Используй когда: нужен стандартный экран списка с фильтрами сверху и
23
+ sticky-действиями снизу. Для самого списка — отдельно `List` / `Table`.
24
+
25
+ ---
26
+
27
+ ## Файловая структура
28
+
29
+ ```text
30
+ src/components/ListMaster/
31
+ ├── ListMaster.tsx # <div>, compound через Object.assign
32
+ ├── index.ts # Barrel
33
+ ├── components/
34
+ │ ├── ListMasterHeader.tsx # sticky + scroll-компенсация при mount/unmount
35
+ │ ├── ListMasterBody.tsx # прозрачный <div>-wrapper
36
+ │ ├── ListMasterFooter.tsx # sticky
37
+ │ ├── ListMasterFooterControls.tsx
38
+ │ ├── ListMasterFooterDescription.tsx
39
+ │ ├── ListMasterChipGroup.tsx # обёртка над <ChipGroup oneLine>
40
+ │ └── SelectionControls.tsx # блок пакетных действий
41
+ └── styles/
42
+ ├── ListMasterHeader.module.less
43
+ ├── ListMasterFooter.module.less
44
+ ├── ListMasterChipGroup.module.less
45
+ └── SelectionControls.module.less
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Compound-структура
51
+
52
+ ```tsx
53
+ <ListMaster>
54
+ <ListMaster.Header sticky>
55
+ {/* Заголовок страницы, поиск, крупные фильтры */}
56
+ </ListMaster.Header>
57
+
58
+ <ListMaster.ChipGroup>
59
+ <Chip>Фильтр 1</Chip>
60
+ <Chip>Фильтр 2</Chip>
61
+ </ListMaster.ChipGroup>
62
+
63
+ <ListMaster.SelectionControls>
64
+ {/* Кнопки массовых действий: "Удалить", "Экспортировать" */}
65
+ </ListMaster.SelectionControls>
66
+
67
+ <ListMaster.Body>
68
+ <List>{/* ListItem'ы */}</List>
69
+ </ListMaster.Body>
70
+
71
+ <ListMaster.Footer sticky>
72
+ <ListMaster.FooterDescription>{/* "Показано 10 из 100" */}</ListMaster.FooterDescription>
73
+ <ListMaster.FooterControls>{/* Pagination */}</ListMaster.FooterControls>
74
+ </ListMaster.Footer>
75
+ </ListMaster>
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Варианты и props
81
+
82
+ ### ListMaster — `IListMasterProps extends HTMLAttributes<HTMLDivElement>`
83
+
84
+ Без собственных props'ов. Просто `<div>` + `data-tx` + compound-подкомпоненты.
85
+
86
+ ### ListMaster.Header — `IListMasterHeaderProps`
87
+
88
+ | Prop | Тип | Default | Описание |
89
+ |---|---|---|---|
90
+ | `sticky` | `boolean` | `true` | Добавляет класс `.sticky` (CSS `position: sticky`). |
91
+
92
+ **Scroll-компенсация при mount/unmount** — см. ниже.
93
+
94
+ ### ListMaster.Footer — `IListMasterFooterProps`
95
+
96
+ | Prop | Тип | Default | Описание |
97
+ |---|---|---|---|
98
+ | `sticky` | `boolean` | `true` | Аналогично Header. Но без scroll-компенсации. |
99
+
100
+ ### ListMaster.FooterControls / FooterDescription
101
+
102
+ Простые `<div>`-слоты с семантическими именами для Footer.
103
+
104
+ ### ListMaster.ChipGroup
105
+
106
+ Обёртка над `<ChipGroup oneLine>` (из компонента `ChipGroup`) с доп. стилем (horizontal padding). **`oneLine` зашит** — нельзя отключить через props.
107
+
108
+ ### ListMaster.Body
109
+
110
+ Прозрачный forwardRef-wrapper, без стилей.
111
+
112
+ ### ListMaster.SelectionControls
113
+
114
+ `<div>` с классом `.selectionControls`. Рендерится, когда нужно показать действия над выбранными элементами (например, по флагу контроллера).
115
+
116
+ ---
117
+
118
+ ## Ключевые особенности реализации
119
+
120
+ ### Scroll-компенсация в `ListMasterHeader`
121
+
122
+ ```tsx
123
+ useEffect(() => {
124
+ containerHeightRef.current = containerRef.current.getBoundingClientRect().height;
125
+ window.scrollTo({ top: window.scrollY + containerHeightRef.current });
126
+ return () => window.scrollTo({ top: Math.max(window.scrollY - containerHeightRef.current, 0) });
127
+ }, []);
128
+ ```
129
+
130
+ - **При монтировании Header** (который обычно появляется при выборе элементов — `SelectionControls` mode) — страница "проскроллена" на высоту header'а, чтобы чекбоксы не "прыгнули" вниз.
131
+ - **При размонтировании** — обратный scroll.
132
+ - **Критичный side effect**: меняет `window.scrollY`. Если Header рендерится и пропадает часто — поведение видно. Этот UX-паттерн специфичен для случаев "выбрал строку → появился контрол-бар".
133
+
134
+ ### `data-tx` на нескольких слотах
135
+
136
+ `ListMaster`, `ListMasterBody`, `SelectionControls` имеют `data-tx={process.env.npm_package_version}`. Header/Footer/ChipGroup — **нет**. Неконсистентно, но это исторический паттерн — не добавляй/убирай без согласования.
137
+
138
+ ### `ListMasterChipGroup` зашивает `oneLine`
139
+
140
+ ```tsx
141
+ <ChipGroup className={...} oneLine {...rest} ref={ref}>
142
+ ```
143
+
144
+ Если потребителю нужен многострочный ChipGroup в ListMaster — использовать `<ChipGroup>` напрямую, не через `.ChipGroup` слот.
145
+
146
+ ### Compound через `FC & { ...slots }` + присваивания
147
+
148
+ ```tsx
149
+ export interface IListMasterFC extends FC<IListMasterProps> { Body, ChipGroup, ... }
150
+ export const ListMaster: IListMasterFC = (...) => <div>...</div>;
151
+ ListMaster.Body = ListMasterBody;
152
+ // ...
153
+ ```
154
+
155
+ **Не `Object.assign`** — явное присваивание после определения. Паттерн-вариант, используй тот же при добавлении слотов.
156
+
157
+ ---
158
+
159
+ ## Инварианты
160
+
161
+ - **`sticky=true` по умолчанию** на Header/Footer — публичный контракт.
162
+ - **Scroll-компенсация в Header** — UX-решение, не удалять без обсуждения (ломает visual continuity в scenario "выбор элементов").
163
+ - **`ListMasterChipGroup` зашитый `oneLine`** — контракт. Для многострочного — потребитель использует `ChipGroup` напрямую.
164
+ - **ForwardRef** на всех слотах.
165
+ - **Compound: `ListMaster.{Body,ChipGroup,Footer,FooterControls,FooterDescription,Header,SelectionControls}`** — публичный API.
166
+ - **Отсутствуют собственные токены** — визуал наследуется от `ChipGroup` и общих CSS-переменных.
167
+ - **Нет stories/тестов** — compound тонкий, покрытие лежит на демо-приложении. При добавлении новых слотов **обязательно** написать story.
168
+
169
+ ---
170
+
171
+ ## Accessibility
172
+
173
+ - `<div>`-контейнеры, без ARIA-ролей. Семантика — на совести потребителя (добавь `role="region"` + `aria-label` через `...rest` для скринридеров).
174
+ - Sticky Header не ломает фокусируемость (CSS, не portal).
175
+ - **Scroll-переход в Header при mount** — может сбивать скринридер на слабых устройствах (меняется позиция scroll'а). Не отключается через prop.
176
+
177
+ ---
178
+
179
+ ## Дизайн-токены
180
+
181
+ Нет собственных.
182
+
183
+ ---
184
+
185
+ ## Связанные компоненты
186
+
187
+ - `List` / `Table` / `TreeView` — то, что обычно внутри `<ListMaster.Body>`.
188
+ - `ChipGroup` — используется в `.ChipGroup`.
189
+ - `Checkbox` — часто в `.SelectionControls`.
190
+ - `Pagination` — типично в `.FooterControls`.
191
+
192
+ ---
193
+
194
+ ## Stories
195
+
196
+ Нет. Кандидат на добавление при следующей работе с компонентом.
197
+
198
+ ---
199
+
200
+ ## История изменений
201
+
202
+ | Дата | Изменение |
203
+ |---|---|
204
+ | 2026-04-18 | Создан документ |
@@ -0,0 +1,161 @@
1
+ ---
2
+ component: Loader
3
+ category: Feedback
4
+ figma-node: ""
5
+ figma-file: ""
6
+ related: [LoaderScreen, Skeleton]
7
+ tokens: []
8
+ stories: stories/Loaders/LoaderMiddle/LoaderMiddle.stories.tsx
9
+ version: "1.0"
10
+ ---
11
+
12
+ # Loader
13
+
14
+ ## Назначение
15
+
16
+ Две точечные анимации для индикации загрузки:
17
+ - **`LoaderSmall`** — три точки, встраивается в кнопки/инпуты, поддерживает темы (`BRAND`/`NEUTRAL`) и размеры (`SM`/`MD`/`LG`).
18
+ - **`LoaderMiddle`** — точки с линией, для центрирования в блоке (карточки, empty-state'ы).
19
+
20
+ Для полноэкранной/мозаичной загрузки — `LoaderScreen`. Для skeleton-stub — `Skeleton`.
21
+
22
+ ---
23
+
24
+ ## Файловая структура
25
+
26
+ ```text
27
+ src/components/Loader/
28
+ ├── index.ts # Barrel: LoaderSmall, enum (ELoaderSmallTheme/Size), LoaderMiddle
29
+ ├── LoaderSmall/
30
+ │ ├── LoaderSmall.tsx # FC, <span role="status">
31
+ │ ├── enum.ts # ELoaderSmallTheme, ELoaderSmallSize (unused? см. ниже)
32
+ │ ├── styles/LoaderSmall.module.less
33
+ │ └── __tests__/LoaderSmall.test.tsx
34
+ └── LoaderMiddle/
35
+ ├── LoaderMiddle.tsx # FC, без props
36
+ ├── styles/LoaderMiddle.module.less
37
+ └── __tests__/LoaderMiddle.test.tsx
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Варианты и props
43
+
44
+ ### LoaderSmall — `ILoaderSmallProps extends HTMLAttributes<HTMLSpanElement>`
45
+
46
+ | Prop | Тип | Обязателен | Описание |
47
+ |---|---|---|---|
48
+ | `theme` | `ELoaderSmallTheme` (`BRAND` / `NEUTRAL`) | Да | Цветовая тема точек. |
49
+ | `size` | `EComponentSize` (`SM`/`MD`/`LG`) | Да | Размер. |
50
+ | `className`, `...HTMLSpanAttributes` | — | — | Стандартные. |
51
+
52
+ **Важно:** используется общий `EComponentSize`, а НЕ `ELoaderSmallSize` (хотя последний определён в `enum.ts` и экспортирован). **`ELoaderSmallSize` — unused в самом компоненте**. Считать legacy; рефакторинг — убрать из экспорта или переключить компонент на него.
53
+
54
+ ### LoaderMiddle — без props
55
+
56
+ ```ts
57
+ export const LoaderMiddle: React.FC = () => (...);
58
+ ```
59
+
60
+ Чистая визуальная анимация. Не принимает `className`/других атрибутов — если нужна кастомизация позиционирования, оборачивай снаружи.
61
+
62
+ ### ELoaderSmallTheme
63
+
64
+ ```ts
65
+ enum ELoaderSmallTheme { BRAND = "brand", NEUTRAL = "neutral" }
66
+ ```
67
+
68
+ ### ELoaderSmallSize (экспортируется, но не используется компонентом)
69
+
70
+ ```ts
71
+ enum ELoaderSmallSize { SM = "sm", MD = "md", LG = "lg" }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Ключевые особенности реализации
77
+
78
+ ### `role="status"` + `aria-label="loading"` — хардкод
79
+
80
+ Оба лоадера используют:
81
+ ```tsx
82
+ <span role="status" aria-label="loading" ...>
83
+ ```
84
+
85
+ - **Хардкод английского текста** `"loading"` — технический долг для мультиязычной версии.
86
+ - `role="status"` + непустой accessible name — скринридер анонсирует появление loader'а (live region).
87
+ - **Не менять `role="status"`** без согласования a11y-regression.
88
+
89
+ ### LoaderMiddle — 4 точки + статическая линия
90
+
91
+ ```tsx
92
+ <span className={styles.line} />
93
+ <span className={clsx(styles.dot, styles.dot1)} />
94
+ ... dot2, dot3, dot4
95
+ ```
96
+
97
+ 4 точки с разной задержкой анимации — передают последовательную "волну". Линия — визуальный baseline.
98
+
99
+ ### LoaderSmall — 3 точки
100
+
101
+ ```tsx
102
+ <span .dot .dot1 />
103
+ <span .dot .dot2 />
104
+ <span .dot .dot3 />
105
+ ```
106
+
107
+ Темы (цвет) задаются через класс на корне, цвет точек — через CSS-переменные или текущий `color` (не проверено, зависит от less-файла).
108
+
109
+ ### `createSizeToClassNameMap(styles)` — утилита общая
110
+
111
+ Мапит `EComponentSize.SM` → `styles.sm`, и т.д. Используется в других компонентах библиотеки — паттерн сохранять.
112
+
113
+ ---
114
+
115
+ ## Инварианты
116
+
117
+ - **`LoaderSmall.theme` и `LoaderSmall.size` обязательны** — не делать опциональными без default'а.
118
+ - **`ELoaderSmallTheme`** — публичный API.
119
+ - **`ELoaderSmallSize`** — экспортирован, но не используется — **если трогаешь**, проверь потребителей (возможно, кто-то уже импортирует) прежде чем удалять.
120
+ - **`LoaderSmall` использует `EComponentSize`**, а не `ELoaderSmallSize` — не менять без breaking-change-плана.
121
+ - **`LoaderMiddle` без props** — расширение API требует RFC.
122
+ - **`role="status"` + `aria-label="loading"`** — ARIA-контракт. Не менять на `"Загрузка"` без i18n-решения для всей библиотеки.
123
+ - **`<span>` контейнер** у LoaderSmall (inline) vs **`<div>`** у LoaderMiddle (block) — семантическое различие, не унифицировать.
124
+
125
+ ---
126
+
127
+ ## Accessibility
128
+
129
+ - `role="status"` создаёт **polite live region** — screen reader анонсирует появление без прерывания. Для одновременного показа двух лоадеров скринридер может анонсировать дважды.
130
+ - `aria-label="loading"` — **захардкожен en**. Для i18n-проекта потребитель должен переопределить через `aria-label={t("loading")}` (prop принимается через `...restProps` только у LoaderSmall).
131
+ - `LoaderMiddle` не принимает `aria-label` через props — текст "loading" фиксирован. Known debt.
132
+ - Нет `aria-busy` на родительском контейнере — потребитель должен добавить на секцию, находящуюся в процессе загрузки.
133
+
134
+ ---
135
+
136
+ ## Дизайн-токены
137
+
138
+ Нет публичных CSS-переменных. Цвета приходят от теории (BRAND/NEUTRAL) напрямую через LESS.
139
+
140
+ ---
141
+
142
+ ## Связанные компоненты
143
+
144
+ - `LoaderScreen` — оверлей с лоадером для больших областей/полноэкранного режима (использует `LoaderMiddle` или `LoaderSmall` внутри).
145
+ - `Skeleton` — альтернатива при загрузке контента с известной структурой.
146
+ - `Button` — LoaderSmall встраивается в кнопку при `isLoading`.
147
+
148
+ ---
149
+
150
+ ## Stories
151
+
152
+ - `stories/Loaders/LoaderMiddle/LoaderMiddle.stories.tsx`
153
+ - `stories/Loaders/LoaderSmall/LoaderSmall.stories.tsx`
154
+
155
+ ---
156
+
157
+ ## История изменений
158
+
159
+ | Дата | Изменение |
160
+ |---|---|
161
+ | 2026-04-18 | Создан документ |