@sberbusiness/triplex-next-mcp-server 1.45.0-beta → 1.48.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/AmountField.md +222 -323
- package/bundle/components/Avatar.md +138 -146
- package/bundle/components/CardAction.md +615 -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/Chip.md +7 -6
- package/bundle/components/ChipGroup.md +1 -1
- package/bundle/components/ChipMonthYearPicker.md +344 -0
- package/bundle/components/ChipMultiselect.md +1251 -0
- package/bundle/components/ChipOptions.md +329 -0
- package/bundle/components/ChipSort.md +333 -0
- package/bundle/components/ChipSuggest.md +588 -0
- package/bundle/components/CollapsibleTree.md +8 -4
- package/bundle/components/CollapsibleTreeExtended.md +8 -6
- package/bundle/components/Confirm.md +346 -281
- package/bundle/components/DateField.md +222 -303
- package/bundle/components/DatePickerExtended.md +3 -1
- package/bundle/components/DateRange.md +351 -210
- package/bundle/components/FooterPage.md +1 -0
- package/bundle/components/FormField.md +14 -5
- package/bundle/components/FormGroup.md +3 -2
- package/bundle/components/HelpBox.md +7 -1
- package/bundle/components/IslandAccordion.md +443 -152
- package/bundle/components/IslandWidget.md +622 -157
- package/bundle/components/LightBox.md +8 -0
- package/bundle/components/ListMaster.md +2 -2
- package/bundle/components/ListTableItem.md +6 -6
- package/bundle/components/MaskedField.md +2 -1
- package/bundle/components/MonthYearField.md +18 -5
- package/bundle/components/Slider.md +389 -97
- package/bundle/components/SliderRange.md +486 -105
- package/bundle/components/StatusTracker.md +386 -94
- package/bundle/components/Stepper.md +355 -102
- package/bundle/components/StepperExtended.md +633 -0
- package/bundle/components/SuggestField.md +1049 -96
- package/bundle/components/SwipeableArea.md +7 -7
- package/bundle/components/Tabs.md +265 -92
- package/bundle/components/TabsExtended.md +18 -18
- package/bundle/components/TabsLine.md +301 -127
- package/bundle/components/TagColor.md +187 -66
- package/bundle/components/TagGroup.md +184 -48
- package/bundle/components/TextareaField.md +278 -70
- 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/tests.md +23 -2
- package/bundle/manifest.json +92 -24
- package/bundle/release-notes/1.46.0.mdx +59 -0
- package/bundle/release-notes/1.47.0.mdx +122 -0
- package/bundle/release-notes/1.48.0.mdx +68 -0
- package/bundle/release-notes/1.49.0.mdx +7 -0
- package/bundle/tokens.json +3 -3
- 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: Chip
|
|
3
3
|
category: Chips
|
|
4
|
-
related: [ChipGroup, ChipIcon, ChipOptions, ChipSelect, ChipMultiselect, ChipSort, ChipSuggest, ChipDatePicker, ChipClearButton, ChipDropdownArrow, Badge, IconWrapper]
|
|
4
|
+
related: [ChipGroup, ChipIcon, ChipOptions, ChipSelect, ChipMultiselect, ChipSort, ChipSuggest, ChipDatePicker, ChipMonthYearPicker, ChipClearButton, ChipDropdownArrow, Badge, IconWrapper]
|
|
5
5
|
tokens:
|
|
6
6
|
- Chip.Background_Type1_Default
|
|
7
7
|
- Chip.Background_Type1_Hover
|
|
@@ -33,7 +33,7 @@ version: "1.0"
|
|
|
33
33
|
Компактный интерактивный элемент-«чипс»: выполняет действие по нажатию и отображает
|
|
34
34
|
выбранное (`selected`) состояние. Одновременно служит базой для всего семейства Chip*
|
|
35
35
|
— поверх него построены `ChipIcon`, `ChipOptions`, а также target-элементы
|
|
36
|
-
`ChipSelect`, `ChipMultiselect`, `ChipSuggest`, `ChipDatePicker`.
|
|
36
|
+
`ChipSelect`, `ChipMultiselect`, `ChipSuggest`, `ChipDatePicker`, `ChipMonthYearPicker`.
|
|
37
37
|
|
|
38
38
|
Используй когда: нужен переключаемый фильтр, тег или компактная кнопка-действие
|
|
39
39
|
в ряду однотипных элементов.
|
|
@@ -152,7 +152,7 @@ Default и Hover. Цвет текста (`Color_*`) от типа не зави
|
|
|
152
152
|
- **Класс `.chipGroupItem`** выставляется всегда, наравне с `.chip`. Объявлен
|
|
153
153
|
в `styles/Chip.module.less` и служит общим маркером «элемент верхнего уровня
|
|
154
154
|
в ряду чипсов»: его проставляют себе все члены семейства — `Chip`, `ChipSort`,
|
|
155
|
-
`ChipMultiselect`, `ChipSelect`, `ChipDatePicker`, `ChipSuggest`. Причём
|
|
155
|
+
`ChipMultiselect`, `ChipSelect`, `ChipDatePicker`, `ChipMonthYearPicker`, `ChipSuggest`. Причём
|
|
156
156
|
`.chipGroupItem` не всегда совпадает с `.chip`: в `ChipSelect` / `ChipMultiselect`
|
|
157
157
|
`.chip` лежит внутри элемента с `.chipGroupItem`. Раскладка `ChipGroup` на этот
|
|
158
158
|
класс не опирается — в её стилях он не встречается. Не удалять и не переименовывать.
|
|
@@ -177,7 +177,7 @@ Default и Hover. Цвет текста (`Color_*`) от типа не зави
|
|
|
177
177
|
компонент не генерирует (у `<span role="button">` нет нативного поведения кнопки),
|
|
178
178
|
внешний `onKeyDown` вызывается всегда и после `preventDefault`. Если чипс должен
|
|
179
179
|
срабатывать с клавиатуры, потребитель обрабатывает Enter/Space сам через `onKeyDown`.
|
|
180
|
-
Обёртки семейства (`ChipSelect`, `ChipSuggest`, `ChipDatePicker`) делают это на своём уровне.
|
|
180
|
+
Обёртки семейства (`ChipSelect`, `ChipSuggest`, `ChipDatePicker`, `ChipMonthYearPicker`) делают это на своём уровне.
|
|
181
181
|
- Фокус-стиль через `:focus-visible` (`Chip.Shadow_Focus`) — виден только
|
|
182
182
|
при клавиатурной навигации. Нативная обводка на корневом элементе намеренно отключена
|
|
183
183
|
(`outline: none` в LESS) в пользу `box-shadow` — убирать правило нельзя, иначе фокус
|
|
@@ -206,8 +206,8 @@ Default и Hover. Цвет текста (`Color_*`) от типа не зави
|
|
|
206
206
|
- `ChipDropdownArrow` — стрелка дропдауна для `postfix`; объявлена как `React.FC`
|
|
207
207
|
(не `forwardRef`), собственных обработчиков не имеет. Props: **обязательный**
|
|
208
208
|
`rotated: boolean` (даёт класс `.rotated`) и `size?: EComponentSize`
|
|
209
|
-
- `ChipSelect`, `ChipMultiselect`, `ChipSuggest`, `ChipDatePicker`, `
|
|
210
|
-
составные компоненты, использующие `Chip` как target-элемент дропдауна
|
|
209
|
+
- `ChipSelect`, `ChipMultiselect`, `ChipSuggest`, `ChipDatePicker`, `ChipMonthYearPicker`,
|
|
210
|
+
`ChipSort` — составные компоненты, использующие `Chip` как target-элемент дропдауна
|
|
211
211
|
- `Badge` (`Badge.Dot`) — значок уведомлений при `showNotificationIcon`
|
|
212
212
|
- `IconWrapper` — обёртка `prefix` / `postfix`, добавляет классы `hoverable` / `disabled`,
|
|
213
213
|
управляющие цветом иконки при взаимодействии
|
|
@@ -239,6 +239,7 @@ Default и Hover. Цвет текста (`Color_*`) от типа не зави
|
|
|
239
239
|
| 2026-07-29 | Создан документ (TRI-26, AI-Ready Phase 1) |
|
|
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
|
+
| 2026-09-07 | В семейство добавлен `ChipMonthYearPicker` — упомянут в списках потребителей `Chip` и `.chipGroupItem` |
|
|
242
243
|
|
|
243
244
|
---
|
|
244
245
|
|