@sberbusiness/triplex-next-mcp-server 1.46.0-beta → 1.50.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/bundle/components/Amount.md +2 -1
- package/bundle/components/AmountField.md +222 -323
- package/bundle/components/Avatar.md +138 -146
- package/bundle/components/Badge.md +2 -1
- package/bundle/components/BodyPage.md +2 -1
- package/bundle/components/Button.md +5 -1
- package/bundle/components/ButtonDropdownExtended.md +3 -1
- package/bundle/components/ButtonIcon.md +3 -1
- package/bundle/components/Calendar.md +3 -1
- package/bundle/components/CardAction.md +1 -0
- package/bundle/components/CardStatic.md +402 -0
- package/bundle/components/CheckboxTree.md +157 -215
- package/bundle/components/CheckboxTreeExtended.md +7 -7
- package/bundle/components/CheckboxXGroup.md +2 -1
- package/bundle/components/Chip.md +2 -1
- package/bundle/components/ChipGroup.md +1 -1
- package/bundle/components/ChipMonthYearPicker.md +6 -5
- package/bundle/components/ChipMultiselect.md +4 -1
- package/bundle/components/ChipOptions.md +2 -1
- package/bundle/components/ChipSort.md +4 -1
- package/bundle/components/ChipSuggest.md +7 -6
- package/bundle/components/CollapsibleTree.md +10 -5
- package/bundle/components/CollapsibleTreeExtended.md +8 -6
- package/bundle/components/ComposedKeyDownListener.md +4 -3
- package/bundle/components/Confirm.md +346 -281
- package/bundle/components/DateField.md +7 -1
- package/bundle/components/DateRange.md +351 -210
- package/bundle/components/Divider.md +85 -138
- package/bundle/components/DocumentNumberEdit.md +173 -214
- package/bundle/components/Dropdown.md +11 -1
- package/bundle/components/Ellipsis.md +131 -147
- package/bundle/components/FooterPage.md +4 -1
- package/bundle/components/FormField.md +13 -5
- package/bundle/components/FormGroup.md +3 -2
- package/bundle/components/Gap.md +1 -1
- package/bundle/components/Header.md +1 -0
- package/bundle/components/HeaderPage.md +3 -1
- package/bundle/components/HelpBox.md +2 -1
- package/bundle/components/IconWrapper.md +10 -6
- package/bundle/components/ImageGallery.md +2 -1
- package/bundle/components/ImageGalleryExtended.md +2 -1
- package/bundle/components/IslandAccordion.md +6 -1
- package/bundle/components/KeyDownListener.md +3 -2
- package/bundle/components/LightBox.md +15 -1
- package/bundle/components/List.md +2 -1
- package/bundle/components/ListActionItem.md +2 -1
- package/bundle/components/ListItem.md +3 -1
- package/bundle/components/ListItemControlsButton.md +2 -1
- package/bundle/components/ListItemSelectable.md +2 -1
- package/bundle/components/ListMaster.md +2 -2
- package/bundle/components/ListMasterFooter.md +2 -1
- package/bundle/components/ListMasterHeader.md +2 -1
- package/bundle/components/ListSortable.md +2 -1
- package/bundle/components/ListSortableItem.md +2 -1
- package/bundle/components/ListTableItem.md +10 -7
- package/bundle/components/LoaderMiddle.md +5 -1
- package/bundle/components/LoaderScreen.md +7 -1
- package/bundle/components/LoaderSmall.md +10 -4
- package/bundle/components/MaskedField.md +3 -1
- package/bundle/components/MediaWidth.md +2 -1
- package/bundle/components/MobileView.md +2 -1
- package/bundle/components/ModalWindow.md +4 -1
- package/bundle/components/MonthYearField.md +19 -5
- package/bundle/components/Notification.md +1 -0
- package/bundle/components/Overlay.md +7 -2
- package/bundle/components/Pagination.md +1 -7
- package/bundle/components/Radio.md +238 -115
- package/bundle/components/RadioXGroup.md +259 -0
- package/bundle/components/RadioYGroup.md +266 -0
- package/bundle/components/SegmentedControl.md +505 -158
- package/bundle/components/SelectExtendedField.md +2 -1
- package/bundle/components/SelectField.md +4 -1
- package/bundle/components/Skeleton.md +140 -69
- package/bundle/components/Slider.md +389 -97
- package/bundle/components/SliderRange.md +486 -105
- package/bundle/components/Spoiler.md +245 -63
- package/bundle/components/StatusTracker.md +386 -94
- package/bundle/components/Step.md +257 -68
- package/bundle/components/Stepper.md +355 -102
- package/bundle/components/StepperExtended.md +633 -0
- package/bundle/components/SuggestField.md +1061 -96
- package/bundle/components/SwipeableArea.md +7 -7
- package/bundle/components/Tabs.md +266 -92
- package/bundle/components/TabsExtended.md +18 -18
- package/bundle/components/TabsLine.md +302 -127
- package/bundle/components/TagColor.md +187 -66
- package/bundle/components/TagGroup.md +184 -48
- package/bundle/components/TextField.md +8 -4
- package/bundle/components/TextareaField.md +279 -70
- package/bundle/components/ThemeProvider.md +2 -1
- package/bundle/components/Tooltip.md +6 -3
- package/bundle/components/TopOverlay.md +17 -1
- package/bundle/components/TreeView.md +16 -7
- package/bundle/components/TriggerClickOnKeyDownEvent.md +277 -0
- package/bundle/components/UploadZone.md +318 -0
- package/bundle/guides/codestyle.md +16 -1
- package/bundle/guides/commits.md +47 -1
- package/bundle/guides/context.md +4 -1
- package/bundle/guides/tests.md +23 -2
- package/bundle/manifest.json +78 -29
- package/bundle/release-notes/1.47.0.mdx +115 -0
- package/bundle/release-notes/1.48.0.mdx +68 -0
- package/bundle/release-notes/1.49.0.mdx +85 -0
- package/bundle/release-notes/1.50.0.mdx +35 -0
- package/bundle/release-notes/1.51.0.mdx +7 -0
- package/bundle/tokens.json +163 -13
- package/dist/index.js +220 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: CheckboxTree
|
|
3
3
|
category: Inputs
|
|
4
|
-
|
|
5
|
-
figma-file: ""
|
|
6
|
-
related: [CheckboxTreeExtended, Checkbox, CheckboxYGroup, CheckboxXGroup]
|
|
4
|
+
related: [CheckboxTreeExtended, Checkbox]
|
|
7
5
|
tokens: []
|
|
8
6
|
stories: stories/CheckboxTree/CheckboxTree.stories.tsx
|
|
9
7
|
version: "1.0"
|
|
@@ -13,263 +11,206 @@ version: "1.0"
|
|
|
13
11
|
|
|
14
12
|
## Назначение
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
(
|
|
14
|
+
Дерево чекбоксов, которое строится из массива данных и само связывает состояние
|
|
15
|
+
родителей и потомков. Обёртка над `CheckboxTreeExtended`: разметку узлов
|
|
16
|
+
компонент формирует сам, потребитель передаёт только описание дерева
|
|
17
|
+
(`ICheckboxTreeCheckboxData[]`) и получает в `onChange` новый массив с
|
|
18
|
+
пересчитанными флагами `checked` и `bulk`.
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
компонент сам рендерит `CheckboxTreeExtended.Node` + `.Checkbox`, управляет
|
|
24
|
-
состоянием и отдаёт обновлённый массив в `onChange`.
|
|
20
|
+
Каскадная логика — единственное, что компонент добавляет к
|
|
21
|
+
`CheckboxTreeExtended`:
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
- выбор узла выбирает всех его потомков, снятие — снимает всех;
|
|
24
|
+
- если выбрана только часть потомков, родитель становится выбранным частично
|
|
25
|
+
(`bulk`) и рисует bulk-иконку вместо галочки;
|
|
26
|
+
- клик по частично выбранному узлу выбирает поддерево целиком, а не снимает
|
|
27
|
+
выбор;
|
|
28
|
+
- флаги пересчитываются снизу вверх по всему дереву на каждое изменение.
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```text
|
|
38
|
-
src/components/CheckboxTree/
|
|
39
|
-
├── CheckboxTree.tsx # React.FC обёртка над CheckboxTreeExtended
|
|
40
|
-
├── types.ts # ICheckboxTreeCheckboxData
|
|
41
|
-
├── utils.ts # traverseCheckboxes, checkParentCheckboxes, checkChildrenCheckboxes
|
|
42
|
-
├── index.ts # Barrel: компонент + types + utils
|
|
43
|
-
└── __tests__/
|
|
44
|
-
```
|
|
30
|
+
Используй когда: есть готовая иерархия значений (категории, права доступа,
|
|
31
|
+
фильтры) и нужна стандартная логика «родитель ↔ потомки» без ручного
|
|
32
|
+
пересчёта.
|
|
45
33
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
(потребитель обычно работает с самими `checkboxes` через onChange, не с DOM).
|
|
51
|
-
Если нужен ref — переключаться на `CheckboxTreeExtended`.
|
|
52
|
-
- **Utils экспортируются через barrel** (`traverseCheckboxes`,
|
|
53
|
-
`checkParentCheckboxes`, `checkChildrenCheckboxes`) — намеренно, потребитель
|
|
54
|
-
может использовать их для предварительной обработки данных или тестов.
|
|
34
|
+
Не используй когда: нужна своя структура данных, произвольный контент рядом с
|
|
35
|
+
чекбоксом, ленивая загрузка ветки или другая логика связи родителя и потомков —
|
|
36
|
+
бери `CheckboxTreeExtended` и описывай узлы вручную. Если иерархии нет вовсе,
|
|
37
|
+
достаточно `CheckboxYGroup`.
|
|
55
38
|
|
|
56
39
|
---
|
|
57
40
|
|
|
58
41
|
## Варианты и props
|
|
59
42
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
43
|
+
`ICheckboxTreeProps` наследует `ICheckboxTreeExtendedProps` без `children` и
|
|
44
|
+
`onChange`, поэтому тип разрешает и остальные атрибуты `<ul>` (`className`,
|
|
45
|
+
`id`, `data-*`). Собственными компонент считает только `checkboxes`, `onChange`
|
|
46
|
+
и `size`, всё остальное уходит через `...rest` на корневой `<ul role="tree">`.
|
|
47
|
+
`className` при этом складывается с внутренними классами, а не заменяет их.
|
|
48
|
+
|
|
49
|
+
| Prop | Тип | По умолчанию | Описание |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `checkboxes` | `ICheckboxTreeCheckboxData[]` | — | Описание дерева. Вложенность задаётся полем `children` элементов. Обязателен |
|
|
52
|
+
| `onChange` | `(options: ICheckboxTreeCheckboxData[]) => void` | — | Вызывается после каждого клика по чекбоксу — с новым массивом верхнего уровня и уже пересчитанными флагами. Обязателен |
|
|
53
|
+
| `size` | `EComponentSize` | `EComponentSize.MD` | Размер чекбоксов и отступов веток. Раздаётся через контекст `CheckboxTreeExtended`, в DOM не попадает. В мобильном представлении всегда `MD` |
|
|
54
|
+
| `children` | `never` | — | Запрещён типом: разметку узлов формирует сам компонент |
|
|
55
|
+
| `ref` | `React.Ref<HTMLUListElement>` | — | Указывает на корневой `<ul role="tree">` |
|
|
56
|
+
| остальные | `React.HTMLAttributes<HTMLUListElement>` | — | Прокидываются на корневой `<ul>` как есть |
|
|
71
57
|
|
|
72
58
|
### `ICheckboxTreeCheckboxData`
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
interface ICheckboxTreeCheckboxData {
|
|
78
|
-
id: string; // уникальный — ключ и aria-поддержка
|
|
79
|
-
label: React.ReactNode; // подпись
|
|
80
|
-
checked: boolean; // текущее состояние
|
|
81
|
-
bulk?: boolean; // "indeterminate", рассчитывается автоматически
|
|
82
|
-
children?: ICheckboxTreeCheckboxData[]; // рекурсивно
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**`bulk` — вычисляется компонентом**, потребитель не должен устанавливать
|
|
87
|
-
его руками. На входе можно передать `false`/`undefined`; после onChange
|
|
88
|
-
массив вернётся с актуальным bulk.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## Ключевые особенности реализации
|
|
93
|
-
|
|
94
|
-
### Мутация массива на месте
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
checkbox.checked = checkbox.bulk ? true : checked;
|
|
98
|
-
checkChildrenCheckboxes(checkbox);
|
|
99
|
-
traverseCheckboxes(checkboxes, checkParentCheckboxes);
|
|
100
|
-
onChange([...checkboxes]);
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Компонент **мутирует** исходный `checkboxes` массив (меняет `checked`/`bulk`
|
|
104
|
-
на узлах) и только на outer-level передаёт новую ссылку через спред. Это
|
|
105
|
-
значит:
|
|
106
|
-
- Потребитель НЕ должен передавать readonly/immutable данные (Object.freeze
|
|
107
|
-
сломает).
|
|
108
|
-
- Потребитель должен либо хранить в state `useState` (React сравнит ссылку
|
|
109
|
-
верхнего уровня), либо всегда клонировать перед передачей.
|
|
110
|
-
- Внутренние референсы не меняются — потомки, которые хранят ссылку на
|
|
111
|
-
конкретный узел, увидят обновлённое значение.
|
|
112
|
-
|
|
113
|
-
Это архитектурный компромисс ради простоты алгоритма. **Не рефакторить
|
|
114
|
-
на immutable-подход без серьёзного повода** — сломает внешний контракт.
|
|
115
|
-
|
|
116
|
-
### `bulk → checked = true` при клике на bulk-узел
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
checkbox.checked = checkbox.bulk ? true : checked;
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
Клик по узлу в `bulk`-состоянии (частично выбран) делает **всех** потомков
|
|
123
|
-
`checked: true`, не снимает выбор. Это соответствует стандартной UX
|
|
124
|
-
tri-state чекбокса: indeterminate → всё выбрано (не → ничего).
|
|
125
|
-
|
|
126
|
-
### `checkChildrenCheckboxes` — рекурсивный каскад вниз
|
|
127
|
-
|
|
128
|
-
```ts
|
|
129
|
-
checkbox.children.forEach((c) => {
|
|
130
|
-
c.checked = checkbox.checked;
|
|
131
|
-
checkChildrenCheckboxes(c);
|
|
132
|
-
});
|
|
133
|
-
```
|
|
60
|
+
Описание одного узла. Поля `checked` и `bulk` у узлов с потомками
|
|
61
|
+
пересчитываются компонентом — задавать их вручную имеет смысл только как
|
|
62
|
+
начальное состояние.
|
|
134
63
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
`
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (c.children) traverseCheckboxes(c.children, cb);
|
|
143
|
-
cb(c);
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
`traverseCheckboxes` идёт **post-order** (сначала потомки, потом узел) —
|
|
147
|
-
это ключевое: чтобы `checkParentCheckboxes` к моменту обработки узла видел
|
|
148
|
-
актуальное состояние потомков.
|
|
149
|
-
|
|
150
|
-
Логика узла:
|
|
151
|
-
- Все потомки checked → `checked: true`, `bulk: true` только если у кого-то
|
|
152
|
-
был bulk (не обычный полный чек).
|
|
153
|
-
- Часть потомков checked → `checked: true, bulk: true`.
|
|
154
|
-
- Никого не checked → `checked: false`.
|
|
155
|
-
|
|
156
|
-
**Нюанс:** "все checked" с хотя бы одним bulk → родитель тоже bulk. То есть
|
|
157
|
-
bulk распространяется вверх, даже если с точки зрения текущего уровня всё
|
|
158
|
-
выбрано.
|
|
159
|
-
|
|
160
|
-
### `onChange([...checkboxes])` — shallow clone
|
|
161
|
-
|
|
162
|
-
```ts
|
|
163
|
-
onChange([...checkboxes]);
|
|
164
|
-
```
|
|
64
|
+
| Поле | Тип | Описание |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `id` | `string` | Идентификатор узла, уникальный в пределах всего дерева |
|
|
67
|
+
| `label` | `React.ReactNode` | Видимая подпись чекбокса. За счёт вложенности `<input>` в корневой `<label>` она же становится доступным именем |
|
|
68
|
+
| `checked` | `boolean` | Признак выбора |
|
|
69
|
+
| `bulk` | `boolean` | Признак частичного выбора: bulk-иконка вместо галочки |
|
|
70
|
+
| `children` | `ICheckboxTreeCheckboxData[]` | Вложенные узлы |
|
|
165
71
|
|
|
166
|
-
|
|
167
|
-
Это совпадает с тем, что нужно React для перерендера при `useState`
|
|
168
|
-
(новая ссылка на массив).
|
|
72
|
+
### Утилиты пересчёта
|
|
169
73
|
|
|
170
|
-
|
|
74
|
+
`utils.ts` экспортируется через barrel, поэтому три функции — часть публичного
|
|
75
|
+
API. Они предназначены для случая, когда потребитель считает состояние дерева
|
|
76
|
+
сам; рабочий пример — `stories/Chips/examples/ChipMultiselect/WithCheckboxTreeExample.tsx`,
|
|
77
|
+
где они импортируются из `@sberbusiness/triplex-next` и пересчитывают дерево
|
|
78
|
+
опций внутри `ChipMultiselect`:
|
|
171
79
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
CheckboxTreeExtended использует prev/next для клавиатурной навигации
|
|
180
|
-
(стрелки вверх/вниз между узлами). CheckboxTree автоматически вычисляет
|
|
181
|
-
их из массива. Это значит, что arrow-navigation работает только в пределах
|
|
182
|
-
одного parent'а — между siblings. **Не менять порядок вызовов в children**:
|
|
183
|
-
первый элемент родителя получает prevNodeId=undefined, и это ожидаемо.
|
|
184
|
-
|
|
185
|
-
### Функциональный чекбокс через render-проп
|
|
80
|
+
| Функция | Что делает |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `traverseCheckboxes(checkboxes, callback)` | Обход в глубину **снизу вверх**: callback вызывается сначала для потомков, затем для родителя |
|
|
83
|
+
| `checkParentCheckboxes(checkbox)` | Пересчитывает `checked` / `bulk` узла по его прямым потомкам. Узел без потомков не трогает |
|
|
84
|
+
| `checkChildrenCheckboxes(checkbox)` | Проставляет `checked` узла всем его потомкам вниз по дереву |
|
|
186
85
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
<CheckboxTreeExtended.Checkbox {...props} onChange={...} bulk={...} checked={...}>
|
|
190
|
-
{checkbox.label}
|
|
191
|
-
</CheckboxTreeExtended.Checkbox>
|
|
192
|
-
)}
|
|
193
|
-
```
|
|
86
|
+
Порядок обхода в `traverseCheckboxes` — не деталь реализации, а контракт:
|
|
87
|
+
`checkParentCheckboxes` работает корректно только если потомки уже пересчитаны.
|
|
194
88
|
|
|
195
|
-
|
|
196
|
-
aria-атрибуты). CheckboxTree передаёт их наружу и добавляет свои
|
|
197
|
-
onChange/bulk/checked. **Не упрощать** — CheckboxTreeExtended полагается
|
|
198
|
-
на render-проп для управления фокусом и ARIA.
|
|
89
|
+
---
|
|
199
90
|
|
|
200
|
-
|
|
91
|
+
## Дизайн-токены
|
|
201
92
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
`
|
|
205
|
-
|
|
206
|
-
|
|
93
|
+
Собственных стилей и токенов у компонента нет — он не содержит ни одного
|
|
94
|
+
LESS-модуля. Всё оформление приходит из `CheckboxTreeExtended` (отступы веток,
|
|
95
|
+
общий токен `Checkbox.BorderColor_Focus`) и из `Checkbox` (цвета, размеры,
|
|
96
|
+
состояния). Переопределять их нужно у этих компонентов — см.
|
|
97
|
+
`CheckboxTreeExtended-ai.md` и `Checkbox-ai.md`.
|
|
207
98
|
|
|
208
99
|
---
|
|
209
100
|
|
|
210
101
|
## Инварианты
|
|
211
102
|
|
|
212
|
-
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
- **`
|
|
219
|
-
|
|
220
|
-
- **`
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
103
|
+
- **Компонент мутирует переданные объекты.** `handleChange` пишет `checked` и
|
|
104
|
+
`bulk` прямо в элементы массива `checkboxes`, а в `onChange` отдаёт поверхностную
|
|
105
|
+
копию массива верхнего уровня (`[...checkboxes]`). Идентичность самих узлов при
|
|
106
|
+
этом сохраняется. На этом держится связка с `useState` у потребителя (новая
|
|
107
|
+
ссылка на массив → перерисовка), и это наблюдаемое поведение: переход на
|
|
108
|
+
иммутабельный пересчёт — breaking change, а не рефакторинг.
|
|
109
|
+
- **`children` запрещён типом** (`children?: never`). Разметка узлов —
|
|
110
|
+
ответственность компонента; своя разметка — это `CheckboxTreeExtended`.
|
|
111
|
+
- **`id` узла обязан быть уникальным во всём дереве.** По `id` строятся
|
|
112
|
+
`prevNodeId` / `nextNodeId`, а по ним `TreeView` ведёт клавиатурную навигацию.
|
|
113
|
+
Дубликаты ломают перемещение по дереву.
|
|
114
|
+
- **Порядок клавиатурного обхода задаётся порядком массива** на каждом уровне:
|
|
115
|
+
соседями узла считаются элементы `checkboxes` (или `children`) по соседним
|
|
116
|
+
индексам.
|
|
117
|
+
- **Дерево всегда полностью раскрыто** — флаг `isStaticCheckboxTreeExtended` в
|
|
118
|
+
`CheckboxTreeExtended` прячет стрелки и раскрывает все узлы. Сворачивания у
|
|
119
|
+
`CheckboxTree` нет по построению.
|
|
120
|
+
- **`ref` указывает на корневой `<ul role="tree">`.** Компонент обёрнут
|
|
121
|
+
`forwardRef`, ссылка проходит насквозь через `CheckboxTreeExtended` →
|
|
122
|
+
`CollapsibleTreeExtended` → `TreeView`. Собственного DOM-узла у `CheckboxTree`
|
|
123
|
+
нет, поэтому другого разумного адресата у `ref` тоже нет.
|
|
124
|
+
- **Публичный API** — имена `ICheckboxTreeProps`, `ICheckboxTreeCheckboxData`,
|
|
125
|
+
функции `traverseCheckboxes`, `checkParentCheckboxes`,
|
|
126
|
+
`checkChildrenCheckboxes` и состав barrel `index.ts` менять нельзя.
|
|
127
|
+
`displayName` — `"CheckboxTree"`.
|
|
227
128
|
|
|
228
129
|
---
|
|
229
130
|
|
|
230
|
-
##
|
|
231
|
-
|
|
232
|
-
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
(
|
|
131
|
+
## Известные ограничения
|
|
132
|
+
|
|
133
|
+
Найдено при AI-рефакторинге (TRI-22). Поведение оставлено как есть — его меняют
|
|
134
|
+
только отдельным решением, это публичный контракт.
|
|
135
|
+
|
|
136
|
+
- **Вход в поддерево с клавиатуры не переводит фокус.** Пока фокус стоит на
|
|
137
|
+
`<li>` ветки, стрелка вниз меняет активный узел на её потомка, но фокус
|
|
138
|
+
остаётся на ветке. Причина — guard в `CheckboxTreeExtendedCheckbox`:
|
|
139
|
+
`if (!document.activeElement?.contains(checkboxNode.current))`. Он защищается
|
|
140
|
+
от лишнего перевода фокуса при клике мышью, но `contains` истинно и для любого
|
|
141
|
+
предка, а `<li>` ветки содержит чекбоксы всех своих потомков. При переходе на
|
|
142
|
+
узел вне текущего поддерева фокус двигается штатно. Лечится на уровне
|
|
143
|
+
`CheckboxTreeExtended` (сравнивать с самим узлом, а не через `contains`) —
|
|
144
|
+
наблюдаемое изменение, отдельное решение и запись в release notes.
|
|
145
|
+
Покрыто тестом `Should move focus between nodes on ArrowDown`, который
|
|
146
|
+
фиксирует текущее поведение, включая это залипание. Когда ограничение
|
|
147
|
+
починят, тест упадёт на трёх «холостых» `ArrowDown` в начале — это ожидаемо,
|
|
148
|
+
его нужно будет переписать под новое поведение.
|
|
149
|
+
- **`bulk` у листа не пересчитывается.** `checkParentCheckboxes` выходит сразу
|
|
150
|
+
для узла без потомков, поэтому флаг остаётся таким, каким его задал
|
|
151
|
+
потребитель. Лист с `bulk: true` невозможно снять кликом: `checked` ставится
|
|
152
|
+
по правилу «клик по частичному выбирает целиком». Задавать `bulk` листу не
|
|
153
|
+
нужно — флаг осмыслен только для узлов с потомками.
|
|
154
|
+
- **`bulk` не сбрасывается, когда все потомки сняты.** В ветке «не выбран ни
|
|
155
|
+
один потомок» пишется только `checked = false`. Визуально это незаметно:
|
|
156
|
+
`Checkbox` показывает иконку (галочку или bulk) только при `checked`, а при
|
|
157
|
+
следующем выборе флаг всё равно пересчитается.
|
|
158
|
+
- **`<li> cannot appear as a descendant of <li>`** — предупреждение React на
|
|
159
|
+
первом рендере вложенных узлов. Приходит из `TreeView` и общее для всего
|
|
160
|
+
семейства (`CollapsibleTree`, `CollapsibleTreeExtended`, `CheckboxTreeExtended`),
|
|
161
|
+
лечится только на уровне `TreeView`.
|
|
243
162
|
|
|
244
163
|
---
|
|
245
164
|
|
|
246
|
-
##
|
|
165
|
+
## Accessibility
|
|
247
166
|
|
|
248
|
-
|
|
167
|
+
- Семантику (`<ul role="tree">`, `<li>`, группы) и клавиатурную навигацию
|
|
168
|
+
обеспечивает `TreeView` через `CheckboxTreeExtended`. `CheckboxTree` добавляет
|
|
169
|
+
к этому только связывание соседних узлов: каждому `CheckboxTreeExtended.Node`
|
|
170
|
+
передаются `prevNodeId` и `nextNodeId` соседей по массиву.
|
|
171
|
+
- Фокус при навигации с клавиатуры забирает чекбокс активного узла — это делает
|
|
172
|
+
`CheckboxTreeExtended.Checkbox`, подробности в `CheckboxTreeExtended-ai.md` →
|
|
173
|
+
«Accessibility».
|
|
174
|
+
- Подпись чекбокса — поле `label`. Связь подписи и поля структурная: в
|
|
175
|
+
`Checkbox` корневой элемент — `<label>`, а `<input type="checkbox">` лежит
|
|
176
|
+
внутри него (`htmlFor` / `id` не используются), поэтому связь работает и при
|
|
177
|
+
пустом `label` — только доступного имени у такого чекбокса не будет.
|
|
178
|
+
Собственных текстов компонент не содержит: библиотека мультиязычная, и
|
|
179
|
+
доступное имя для узла без видимой подписи передаёт потребитель через `label`.
|
|
180
|
+
- Частичный выбор кодируется только визуально (bulk-иконка). `aria-checked="mixed"`
|
|
181
|
+
компонент не выставляет — под капотом нативный `<input type="checkbox">` без
|
|
182
|
+
`indeterminate`. Если полумерное состояние нужно ассистивным технологиям,
|
|
183
|
+
это отдельная доработка `Checkbox`.
|
|
249
184
|
|
|
250
185
|
---
|
|
251
186
|
|
|
252
187
|
## Связанные компоненты
|
|
253
188
|
|
|
254
|
-
- `CheckboxTreeExtended` (`src/components/CheckboxTreeExtended`) — нижний
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
- `
|
|
189
|
+
- `CheckboxTreeExtended` (`src/components/CheckboxTreeExtended`) — нижний слой и
|
|
190
|
+
одновременно альтернатива. `ICheckboxTreeProps` наследует его props, а
|
|
191
|
+
`CheckboxTree` рендерит `CheckboxTreeExtended`, `.Node` и `.Checkbox`. Бери
|
|
192
|
+
его, когда нужна своя разметка узлов или своя логика связи родителя и
|
|
193
|
+
потомков.
|
|
194
|
+
- `Checkbox` (`src/components/Checkbox`) — чекбокс каждого узла. Отсюда приходят
|
|
195
|
+
все токены, размеры и семантика `bulk` (иконка вместо галочки, видимость по
|
|
196
|
+
`checked`).
|
|
197
|
+
- `CheckboxYGroup` (`src/components/Checkbox`) — плоская вертикальная группа
|
|
198
|
+
чекбоксов. Подходит, когда иерархии нет и каскадный пересчёт не нужен.
|
|
199
|
+
- `MultiselectField` и `ChipMultiselect` — типовые потребители: показывают
|
|
200
|
+
`CheckboxTree` как дерево опций внутри выпадающего блока (см. их stories).
|
|
260
201
|
|
|
261
202
|
---
|
|
262
203
|
|
|
263
204
|
## Stories
|
|
264
205
|
|
|
265
|
-
`stories/CheckboxTree/CheckboxTree.stories.tsx`
|
|
206
|
+
Основные истории: `stories/CheckboxTree/CheckboxTree.stories.tsx`
|
|
266
207
|
Файлы примеров: `stories/CheckboxTree/examples/`
|
|
267
208
|
|
|
268
209
|
| Story | Example file | Что демонстрирует |
|
|
269
210
|
|---|---|---|
|
|
270
|
-
| `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль `size`
|
|
271
|
-
| `Default` | `DefaultExample.tsx` |
|
|
272
|
-
| `Sizes` | `SizesExample.tsx` |
|
|
211
|
+
| `Playground` | `PlaygroundExample.tsx` | Интерактивный контроль `size` на дереве из трёх веток |
|
|
212
|
+
| `Default` | `DefaultExample.tsx` | Минимальный сценарий: массив в `useState` потребителя, `onChange` передаётся сеттером |
|
|
213
|
+
| `Sizes` | `SizesExample.tsx` | Размеры SM / MD / LG рядом |
|
|
273
214
|
|
|
274
215
|
---
|
|
275
216
|
|
|
@@ -277,7 +218,8 @@ onChange/bulk/checked. **Не упрощать** — CheckboxTreeExtended пол
|
|
|
277
218
|
|
|
278
219
|
| Дата | Изменение |
|
|
279
220
|
|---|---|
|
|
280
|
-
| 2026-
|
|
221
|
+
| 2026-09-17 | TRI-22: добавлен `forwardRef` на корневой `<ul>` (насквозь через всё семейство Tree), прокидываются html-атрибуты, узел с `children: []` больше не становится выбранным. В «Известные ограничения» добавлено залипание фокуса при входе в поддерево |
|
|
222
|
+
| 2026-09-14 | Создан документ. Проведён AI-рефакторинг (TRI-22): JSDoc на props и полях `ICheckboxTreeCheckboxData`, убраны `eslint-disable` в `utils.ts`, рендер узлов вынесен в общий `renderNodes`; добавлены unit-тесты на утилиты и на каскадный пересчёт |
|
|
281
223
|
|
|
282
224
|
---
|
|
283
225
|
|
|
@@ -114,14 +114,13 @@ Checkbox.BorderColor_Focus
|
|
|
114
114
|
отрисовывается. Файл и обе ветки кода намеренно оставлены — по TODO флаг
|
|
115
115
|
снимут, когда сворачиваемое дерево станет стандартом. Не удаляй ветки
|
|
116
116
|
`!isStaticCheckboxTreeExtended` как «мёртвый код».
|
|
117
|
-
- **`
|
|
118
|
-
|
|
119
|
-
`
|
|
120
|
-
`
|
|
121
|
-
форму экспортируемого `ICheckboxTreeExtendedSFC` — это отдельное решение
|
|
122
|
-
мейнтейнера, а не рефакторинг.
|
|
117
|
+
- **`ref` указывает на корневой `<ul role="tree">`.** Компонент обёрнут
|
|
118
|
+
`forwardRef`, ссылка уходит в `CollapsibleTreeExtended` и дальше в `TreeView`.
|
|
119
|
+
У `.Node` и `.Checkbox` своего `forwardRef` по-прежнему нет: `.Node` —
|
|
120
|
+
class-компонент, `.Checkbox` управляет фокусом сам.
|
|
123
121
|
- **Публичный API** — имена `ICheckboxTreeExtendedProps`,
|
|
124
|
-
`
|
|
122
|
+
`ICheckboxTreeExtendedFC` (и deprecated-алиас `ICheckboxTreeExtendedSFC`),
|
|
123
|
+
`ICheckboxTreeExtendedCheckboxProvideProps`,
|
|
125
124
|
`ICheckboxTreeExtendedNodeProps`,
|
|
126
125
|
статические `Checkbox` / `Node` и barrel-экспорты `index.ts` менять нельзя:
|
|
127
126
|
на них опирается `CheckboxTree`, а также stories `Chips` и `MultiselectField`.
|
|
@@ -224,6 +223,7 @@ Checkbox.BorderColor_Focus
|
|
|
224
223
|
| 2026-08-17 | `className` у `CheckboxTreeExtended.Node` больше не затирает собственный класс узла — классы мерджатся через `clsx` (правка по ревью PR #535) |
|
|
225
224
|
| 2026-08-17 | Убран мёртвый селектор `.checkboxTreeCheckbox` из мобильной медиа-выборки (рабочие `> span` и `> svg` оставлены), `.caretIconWrapper:focus` заменён на `:focus-visible` (правки по ревью PR #535) |
|
|
226
225
|
| 2026-08-17 | `ICheckboxTreeExtendedNodeProps` экспортируется — тип уходит в barrel и становится частью публичного API (решение владельца по ревью PR #535) |
|
|
226
|
+
| 2026-09-17 | TRI-22: `CheckboxTreeExtended` обёрнут `forwardRef` — `ref` отдаёт корневой `<ul>`; тип переименован в `ICheckboxTreeExtendedFC`, старое имя оставлено deprecated-алиасом |
|
|
227
227
|
|
|
228
228
|
---
|
|
229
229
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: CheckboxXGroup
|
|
3
3
|
category: Inputs
|
|
4
|
-
related: [Checkbox]
|
|
4
|
+
related: [Checkbox, CheckboxYGroup]
|
|
5
5
|
tokens: []
|
|
6
6
|
stories: stories/CheckboxXGroup/CheckboxXGroup.stories.tsx
|
|
7
7
|
version: "1.0"
|
|
@@ -88,6 +88,7 @@ version: "1.0"
|
|
|
88
88
|
| 2026-04-16 | Приведение `CheckboxXGroup` к AI-ready: добавлен `forwardRef`, типизирован `children`, созданы AI-документ и инварианты. |
|
|
89
89
|
| 2026-04-27 | Приведён в соответствие с `docs/ai/template-ai.md`: убрана секция «Ключевые особенности реализации» (содержимое перенесено в `Ограничения использования`), переставлены секции, добавлена колонка `Example file` и пустой раздел `Дизайн-токены`. |
|
|
90
90
|
| 2026-08-18 | AI-рефакторинг: JSDoc на props и компоненте, комментарий про кросс-модульный класс `.label` в LESS, добавлены unit-тесты `__tests__/CheckboxXGroup.test.tsx`. Публичный API не изменён. |
|
|
91
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): добавлены обратные ссылки (`CheckboxYGroup`). Публичный API и поведение не затронуты. |
|
|
91
92
|
|
|
92
93
|
---
|
|
93
94
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: Chip
|
|
3
3
|
category: Chips
|
|
4
|
-
related: [ChipGroup,
|
|
4
|
+
related: [ChipGroup, ChipOptions, ChipSelect, ChipMultiselect, ChipSort, ChipSuggest, ChipDatePicker, ChipMonthYearPicker, Badge, IconWrapper]
|
|
5
5
|
tokens:
|
|
6
6
|
- Chip.Background_Type1_Default
|
|
7
7
|
- Chip.Background_Type1_Hover
|
|
@@ -240,6 +240,7 @@ Default и Hover. Цвет текста (`Color_*`) от типа не зави
|
|
|
240
240
|
| 2026-07-29 | AI-рефакторинг (TRI-26): codestyle-чистка `Chip.tsx` (константы-маппинги в UPPER_SNAKE_CASE, эквивалентные упрощения в `clsx`, JSDoc на `children` и `handleKeyDown`), unit-тесты расширены с 5 до 22 кейсов; публичный API, DOM и визуал не изменены |
|
|
241
241
|
| 2026-07-29 | Правки по ревью PR #487: уточнена атрибуция класса `.chipGroupItem` (его проставляет семейство Chip*, а не раскладка `ChipGroup`) и описание API `ChipClearButton` / `ChipDropdownArrow` |
|
|
242
242
|
| 2026-09-07 | В семейство добавлен `ChipMonthYearPicker` — упомянут в списках потребителей `Chip` и `.chipGroupItem` |
|
|
243
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны имена без строки в `docs/ai/ROADMAP.md` (`ChipIcon`, `ChipClearButton`, `ChipDropdownArrow`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
243
244
|
|
|
244
245
|
---
|
|
245
246
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: ChipMonthYearPicker
|
|
3
3
|
category: Chips
|
|
4
|
-
related: [Chip, ChipDatePicker,
|
|
4
|
+
related: [Chip, ChipDatePicker, MonthYearField, DatePickerExtended]
|
|
5
5
|
tokens: []
|
|
6
6
|
stories: stories/Chips/ChipMonthYearPicker.stories.tsx
|
|
7
7
|
version: "1.0"
|
|
@@ -197,6 +197,7 @@ selected = getPickerValues(value, format, limitRange).calendarDate !== null
|
|
|
197
197
|
| Дата | Изменение |
|
|
198
198
|
|---|---|
|
|
199
199
|
| 2026-09-07 | Создан компонент и документ (AI-Ready Phase 1) |
|
|
200
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`ChipGroup`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
200
201
|
|
|
201
202
|
---
|
|
202
203
|
|
|
@@ -216,7 +217,7 @@ export const DefaultExample = () => {
|
|
|
216
217
|
<ChipMonthYearPicker
|
|
217
218
|
value={value}
|
|
218
219
|
label="MonthYear label"
|
|
219
|
-
placeholder="
|
|
220
|
+
placeholder="Select to proceed"
|
|
220
221
|
onChange={setValue}
|
|
221
222
|
alignment={EDropdownAlignment.LEFT}
|
|
222
223
|
size={EComponentSize.MD}
|
|
@@ -248,7 +249,7 @@ const TypeItem = ({ type, label }: TypeItemProps) => {
|
|
|
248
249
|
<ChipMonthYearPicker
|
|
249
250
|
value={value}
|
|
250
251
|
label="MonthYear label"
|
|
251
|
-
placeholder="
|
|
252
|
+
placeholder="Select to proceed"
|
|
252
253
|
clearButtonProps={{ "aria-label": "Очистить" }}
|
|
253
254
|
type={type}
|
|
254
255
|
alignment={EDropdownAlignment.LEFT}
|
|
@@ -296,7 +297,7 @@ const SizeItem = ({ size, label }: SizeItemProps) => {
|
|
|
296
297
|
alignment={EDropdownAlignment.LEFT}
|
|
297
298
|
value={value}
|
|
298
299
|
label="MonthYear label"
|
|
299
|
-
placeholder="
|
|
300
|
+
placeholder="Select to proceed"
|
|
300
301
|
clearButtonProps={{ "aria-label": "Очистить" }}
|
|
301
302
|
onChange={setValue}
|
|
302
303
|
/>
|
|
@@ -332,7 +333,7 @@ export const WithCustomDisplayedValueExample = () => {
|
|
|
332
333
|
<ChipMonthYearPicker
|
|
333
334
|
value={value}
|
|
334
335
|
label="MonthYear label"
|
|
335
|
-
placeholder="
|
|
336
|
+
placeholder="Select to proceed"
|
|
336
337
|
onChange={setValue}
|
|
337
338
|
alignment={EDropdownAlignment.LEFT}
|
|
338
339
|
size={EComponentSize.MD}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
component: ChipMultiselect
|
|
3
3
|
category: Chips
|
|
4
|
-
related: [Chip,
|
|
4
|
+
related: [Chip, ChipSelect, ChipOptions, MultiselectField, SelectExtendedField]
|
|
5
5
|
tokens: []
|
|
6
6
|
stories: stories/Chips/ChipMultiselect.stories.tsx
|
|
7
7
|
version: "1.0"
|
|
@@ -169,6 +169,8 @@ Postfix переключается тем же флагом `selected`: `ChipDro
|
|
|
169
169
|
- `ChipGroup` — контейнер для ряда чипсов; корневой класс `chipGroupItem`
|
|
170
170
|
проставляется именно ради него.
|
|
171
171
|
- `ChipSelect` — тот же чипс-фильтр, но для выбора одного значения.
|
|
172
|
+
- `ChipOptions` — альтернатива, когда содержимое дропдауна произвольное, а не готовый
|
|
173
|
+
список значений: тот же `clearSelected` и счётчик, но без собственного target-элемента.
|
|
172
174
|
- `MultiselectField` — родитель по типам и по рендеру: даёт состояние открытости,
|
|
173
175
|
выпадающий блок (`MultiselectField.Dropdown`), focus trap и раздачу размера.
|
|
174
176
|
- `SelectExtendedField` — уровнем ниже `MultiselectField`; из него приходит тип
|
|
@@ -202,6 +204,7 @@ Postfix переключается тем же флагом `selected`: `ChipDro
|
|
|
202
204
|
| Дата | Изменение |
|
|
203
205
|
|---|---|
|
|
204
206
|
| 2026-09-07 | Создан документ (TRI-135). AI-рефакторинг: JSDoc на props и компоненте, мемоизация обработчиков кнопки сброса, порядок импортов; поведение и публичный API не менялись |
|
|
207
|
+
| 2026-09-29 | Аудит симметрии `related` (TRI-156): из `related` убраны несимметричные имена (`ChipGroup`); добавлены обратные ссылки (`ChipOptions`). Пояснения к убранным именам сохранены прозой в «Связанные компоненты»; публичный API и поведение не затронуты. |
|
|
205
208
|
|
|
206
209
|
---
|
|
207
210
|
|