@elcrm/components 0.2.11 → 0.2.13

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.
@@ -1,1523 +0,0 @@
1
- {
2
- "format": "elcrm-kit-manifest-v1",
3
- "package": "@elcrm/components",
4
- "version": "0.2.11",
5
- "pkg": "components",
6
- "generatedAt": "2026-08-23T09:13:24.421Z",
7
- "components": [
8
- {
9
- "slug": "ActionGroup",
10
- "title": "ActionGroup",
11
- "description": "Ряд действий в строке списка / карточке (`role=\"toolbar\"`). Роли: тулбар иконок справа в Card. Кнопки — `@elcrm/button` / свои слоты, не нативный `<button>` в приложении.",
12
- "importFrom": "@elcrm/components",
13
- "examples": [
14
- {
15
- "title": "Пример",
16
- "code": "<ActionGroup\n label=\"Действия: Иван\"\n items={[\n <Button key=\"edit\" variant=\"ghost\" onClick={edit}>Изменить</Button>,\n <Button key=\"del\" variant=\"ghost\" onClick={remove}>Удалить</Button>,\n ]}\n/>\n\n<ActionGroup label=\"Ещё\">\n <Button variant=\"ghost\">Копировать</Button>\n</ActionGroup>"
17
- }
18
- ],
19
- "props": [
20
- {
21
- "name": "label",
22
- "type": "string",
23
- "description": "Подпись тулбара (`aria-label`)"
24
- },
25
- {
26
- "name": "items",
27
- "type": "React.ReactNode[]",
28
- "description": "Кнопки массивом узлов"
29
- },
30
- {
31
- "name": "children",
32
- "type": "React.ReactNode",
33
- "description": "Свои кнопки / слоты"
34
- }
35
- ]
36
- },
37
- {
38
- "slug": "Avatar",
39
- "title": "Avatar",
40
- "description": "Аватар: фото или инициалы, опционально статус присутствия. Когда использовать: - круглая миниатюра пользователя без текстовой подписи рядом; - в шапке, списках, {@link AvatarGroup}. Связанные компоненты: - {@link AvatarName} — аватар + видимые `title` / `description` (`name` у Avatar остаётся только для инициалов); - {@link AvatarGroup} — стопка аватаров из `items`. CSS-токены: `--avatar-*` (в т.ч. `--avatar-size-s|m|l`, `--avatar-radius`). Скругление: `radius={10}` или `style={{ [\"--avatar-radius\"]: \"10px\" }}`.",
41
- "importFrom": "@elcrm/components",
42
- "examples": [
43
- {
44
- "title": "Пример",
45
- "code": "// фото + статус\n<Avatar src=\"/u/42.jpg\" alt=\"Иван Петров\" size=\"m\" status=\"online\" />\n\n// без фото — только инициалы из name\n<Avatar name=\"Иван Петров\" size=\"s\" />\n\n// подпись в UI — через AvatarName (title + description)\n<AvatarName\n name=\"Иван Петров\"\n title=\"Иван Петров\"\n description=\"ivan@elcrm.app\"\n/>"
46
- }
47
- ],
48
- "props": []
49
- },
50
- {
51
- "slug": "AvatarGroup",
52
- "title": "AvatarGroup",
53
- "description": "Стопка аватаров с оверлапом, счётчиком «+N» и опциональной кнопкой добавления. Когда использовать: - участники задачи / канала / сделки в одну строку; - нужно ограничить видимое число (`max`) и добавить «+». Связанные компоненты: - {@link Avatar} — одиночный аватар; - {@link AvatarName} — аватар с текстовой подписью (`title` / `description`). API: декларативные `items`. Идентификатор предпочтительно `value` (не `key`). Compound-слоты не используются. CSS-токены: `--avatar-group-*`, размеры из `--avatar-size-*`.",
54
- "importFrom": "@elcrm/components",
55
- "examples": [
56
- {
57
- "title": "Пример",
58
- "code": "const items = [\n { value: \"u1\", name: \"Иван Петров\", src: \"/u/1.jpg\", status: \"online\" },\n { value: \"u2\", name: \"Мария Смирнова\" },\n { value: \"u3\", name: \"Алексей\" },\n];\n\n<AvatarGroup\n items={items}\n max={5}\n size=\"m\"\n add\n onAdd={() => openInvite()}\n onItemClick={(item) => openProfile(item.value)}\n/>"
59
- }
60
- ],
61
- "props": [
62
- {
63
- "name": "items",
64
- "type": "AvatarGroupItem[]",
65
- "description": "Список людей / аватаров."
66
- },
67
- {
68
- "name": "max",
69
- "type": "number",
70
- "description": "Сколько аватаров показать до «+N». По умолчанию все."
71
- },
72
- {
73
- "name": "size",
74
- "type": "UiSize",
75
- "description": "Размер аватаров: `s` | `m` | `l`."
76
- },
77
- {
78
- "name": "add",
79
- "type": "boolean",
80
- "description": "Кнопка «+» справа."
81
- },
82
- {
83
- "name": "addLabel",
84
- "type": "string",
85
- "description": "Подпись для кнопки добавления (`aria-label`)."
86
- },
87
- {
88
- "name": "onAdd",
89
- "type": "() => void",
90
- "description": "Клик по кнопке добавления."
91
- },
92
- {
93
- "name": "onItemClick",
94
- "type": "(item: AvatarGroupItem, index: number) => void",
95
- "description": "Клик по аватару."
96
- }
97
- ]
98
- },
99
- {
100
- "slug": "AvatarName",
101
- "title": "AvatarName",
102
- "description": "Аватар + видимые `title` и `description` в одну строку. Когда использовать: - строка пользователя в списке / меню / карточке; - нужна подпись рядом с фото (не только инициалы). Связанные компоненты: - {@link Avatar} — только круг (без текста); `name` там лишь для инициалов; - {@link AvatarGroup} — стопка без подписей. Канон: `title` / `description` для UI-текста; `name` — только инициалы. CSS-токены: `--avatar-name-title-color`, `--avatar-name-description-color`, аватар — `--avatar-*`.",
103
- "importFrom": "@elcrm/components",
104
- "examples": [
105
- {
106
- "title": "Пример",
107
- "code": "<AvatarName\n src=\"/u/42.jpg\"\n name=\"Иван Петров\"\n title=\"Иван Петров\"\n description=\"ivan@elcrm.app\"\n size=\"m\"\n status=\"online\"\n/>\n\n<AvatarName\n as=\"button\"\n name=\"Мария\"\n title=\"Мария Смирнова\"\n description=\"Менеджер\"\n onClick={() => openProfile()}\n/>"
108
- }
109
- ],
110
- "props": []
111
- },
112
- {
113
- "slug": "Badge",
114
- "title": "Badge",
115
- "description": "Компактная метка / статус (роль, состояние). Не заменяет Button. Props (`BadgeProps`): - `tone` — `neutral` | `accent` | `success` | `warning` | `danger` - `size` — `s` | `m` | `l` (по умолчанию `m`) - `dot` — точка слева (как online / offline) - `children` — текст метки - плюс атрибуты `span` (`className`, `style`, …)",
116
- "importFrom": "@elcrm/components",
117
- "examples": [
118
- {
119
- "title": "Пример",
120
- "code": "<Badge tone=\"accent\" size=\"s\">ADMIN</Badge>\n<Badge tone=\"success\" size=\"s\" dot>online</Badge>"
121
- }
122
- ],
123
- "props": [
124
- {
125
- "name": "tone",
126
- "type": "BadgeTone",
127
- "description": "Цвет по смыслу. `neutral` | `accent` | `success` | `warning` | `danger`"
128
- },
129
- {
130
- "name": "size",
131
- "type": "BadgeSize",
132
- "description": "Размер пилюли. `s` — в строке списка; `m` — обычная; `l` — крупнее. По умолчанию `m`."
133
- },
134
- {
135
- "name": "dot",
136
- "type": "boolean",
137
- "description": "Точка статуса слева (цвет = `tone`)"
138
- },
139
- {
140
- "name": "children",
141
- "type": "React.ReactNode",
142
- "description": "Текст метки"
143
- }
144
- ]
145
- },
146
- {
147
- "slug": "Block",
148
- "title": "Block",
149
- "description": "Block",
150
- "importFrom": "@elcrm/components",
151
- "examples": [
152
- {
153
- "title": "Пример",
154
- "code": "// Было:\n<Block row gap={8}>…</Block>\n// Стало:\n<Stack direction=\"row\" gap={8}>…</Stack>"
155
- }
156
- ],
157
- "props": [
158
- {
159
- "name": "row",
160
- "type": "boolean",
161
- "description": "@deprecated Используйте `<Stack direction=\"row\">`. Если `true` — горизонтальный стек."
162
- }
163
- ]
164
- },
165
- {
166
- "slug": "Brand",
167
- "title": "Brand",
168
- "description": "Название / логотип в шапке. Роли: Brand = кликабельный или статичный бренд в Header; рендерится как `button` (по умолчанию), `a` или `strong`.",
169
- "importFrom": "@elcrm/components",
170
- "examples": [
171
- {
172
- "title": "Пример",
173
- "code": "<Header brand={<Brand as=\"a\" href=\"/\">elCRM</Brand>} />"
174
- }
175
- ],
176
- "props": [
177
- {
178
- "name": "as",
179
- "type": "\"button\"",
180
- "description": "Тег: кнопка (по умолчанию)"
181
- },
182
- {
183
- "name": "as",
184
- "type": "\"strong\"",
185
- "description": "Тег: статичный заголовок без клика"
186
- },
187
- {
188
- "name": "as",
189
- "type": "\"a\"",
190
- "description": "Тег: ссылка на главную"
191
- }
192
- ]
193
- },
194
- {
195
- "slug": "Breadcrumb",
196
- "title": "Breadcrumb",
197
- "description": "Хлебные крошки пути из декларативного массива `items`. Когда использовать: - показать иерархию страницы / вложенных разделов; - нужна свёртка длинного пути (`collapseAfter`). Связанные компоненты: - {@link PageHead} — шапка страницы, куда часто кладут Breadcrumb; - {@link Dropdown} — если крошка с `dropdown` открывает меню выбора. API: декларативные `items`. Идентификатор — `value` (не `key`). Compound-слоты не используются. CSS-токены: `--shell-*`.",
198
- "importFrom": "@elcrm/components",
199
- "examples": [
200
- {
201
- "title": "Пример",
202
- "code": "const items = [\n { value: \"home\", label: \"Главная\", href: \"/\" },\n { value: \"settings\", label: \"Настройки\", href: \"/settings\" },\n { value: \"team\", label: \"Команда\", icon: <Avatar name=\"Team\" size=\"s\" /> },\n];\n\n<Breadcrumb\n items={items}\n separator=\"chevron\"\n collapseAfter={2}\n onItemClick={(item) => navigate(item.href ?? \"/\")}\n/>"
203
- }
204
- ],
205
- "props": [
206
- {
207
- "name": "items",
208
- "type": "BreadcrumbItem[]",
209
- "description": "Цепочка крошек (`value` — идентификатор)."
210
- },
211
- {
212
- "name": "separator",
213
- "type": "BreadcrumbSeparator",
214
- "description": "Разделитель: chevron `>`, slash `/` или свой node."
215
- },
216
- {
217
- "name": "collapseAfter",
218
- "type": "number",
219
- "description": "Свернуть середину: первые N пунктов, «…», последний. Например `2` → Home, Settings, …, Team."
220
- },
221
- {
222
- "name": "onEllipsisClick",
223
- "type": "() => void",
224
- "description": "Клик по «…» (если нужно раскрыть путь)."
225
- },
226
- {
227
- "name": "onItemClick",
228
- "type": "(item: BreadcrumbItem, index: number) => void",
229
- "description": "Клик по пункту (кроме текущего и disabled)."
230
- }
231
- ]
232
- },
233
- {
234
- "slug": "Card",
235
- "title": "Card",
236
- "description": "Карточка-контейнер с опциональным заголовком. Роли: Card = визуальная рамка для группы контента; для секций модуля — Section; для списков — List / Item.",
237
- "importFrom": "@elcrm/components",
238
- "examples": [
239
- {
240
- "title": "Пример",
241
- "code": "<Card title=\"Тариф\">\n <p>Базовый план</p>\n</Card>"
242
- },
243
- {
244
- "title": "Пример 2",
245
- "code": "<Card title=\"Тенанты\" style={{ [\"--card-pointer\" as string]: \"pointer\" }}>\n 12\n</Card>"
246
- }
247
- ],
248
- "props": [
249
- {
250
- "name": "title",
251
- "type": "React.ReactNode",
252
- "description": "Заголовок карточки (если нет — только children)"
253
- },
254
- {
255
- "name": "children",
256
- "type": "React.ReactNode",
257
- "description": "Содержимое карточки"
258
- }
259
- ]
260
- },
261
- {
262
- "slug": "ChatList",
263
- "title": "ChatList",
264
- "description": "Колонка списка диалогов (`aside`).",
265
- "importFrom": "@elcrm/components",
266
- "examples": [],
267
- "props": []
268
- },
269
- {
270
- "slug": "ChatMessages",
271
- "title": "ChatMessages",
272
- "description": "Колонка переписки (`section`).",
273
- "importFrom": "@elcrm/components",
274
- "examples": [],
275
- "props": []
276
- },
277
- {
278
- "slug": "Column",
279
- "title": "Column",
280
- "description": "Column",
281
- "importFrom": "@elcrm/components",
282
- "examples": [
283
- {
284
- "title": "Пример",
285
- "code": "// Было:\n<Column gap={12}>…</Column>\n// Стало:\n<Stack gap={12}>…</Stack>"
286
- }
287
- ],
288
- "props": []
289
- },
290
- {
291
- "slug": "Dropdown",
292
- "title": "Dropdown",
293
- "description": "Выпадающее меню: триггер + панель с `groups` / `items` (portal, {@link Popover}). Когда использовать: - действия строки списка, переключатели колонок, контекстные пункты у кнопки. Отличия: - {@link Menu} — инлайн-навигация в потоке (шапка), без панели; - {@link Popover} — свой контент в portal, без `items`. API: декларативные `items` / `groups`. Идентификатор пункта — `value` (не `key`). Compound-слоты (`Dropdown.Item`) не используются. CSS-токены: `--shell-*`, узкие `--dropdown-min-width` / `--dropdown-max-width` / `--dropdown-max-height`, `--popup-shadow`.",
294
- "importFrom": "@elcrm/components",
295
- "examples": [
296
- {
297
- "title": "Пример",
298
- "code": "const groups = [\n {\n title: \"Действия\",\n items: [\n { value: \"edit\", label: \"Изменить\", icon: <Icons.Line name=\"edit\" /> },\n { value: \"delete\", label: \"Удалить\", danger: true },\n ],\n },\n {\n title: \"Колонки\",\n items: [\n { value: \"email\", label: \"Email\", checkbox: true, checked: true },\n { value: \"phone\", label: \"Телефон\", checkbox: true },\n ],\n },\n];\n\n<Dropdown\n label=\"Действия\"\n groups={groups}\n closeOnSelect={false}\n onSelect={(value) => console.log(value)}\n/>"
299
- }
300
- ],
301
- "props": [
302
- {
303
- "name": "items",
304
- "type": "DropdownItem[]",
305
- "description": "Плоский декларативный список пунктов. Для секций с разделителями используйте `groups`."
306
- },
307
- {
308
- "name": "groups",
309
- "type": "DropdownGroup[]",
310
- "description": "Секции с разделителями между ними."
311
- },
312
- {
313
- "name": "trigger",
314
- "type": "React.ReactNode",
315
- "description": "Кастомный триггер; иначе кнопка из `label`."
316
- },
317
- {
318
- "name": "label",
319
- "type": "React.ReactNode",
320
- "description": "Текст встроенного триггера."
321
- },
322
- {
323
- "name": "hideChevron",
324
- "type": "boolean",
325
- "description": "Скрыть chevron у встроенного триггера."
326
- },
327
- {
328
- "name": "title",
329
- "type": "React.ReactNode",
330
- "description": "Заголовок панели (если не задан в `groups[].title`)."
331
- },
332
- {
333
- "name": "align",
334
- "type": "\"start\" | \"end\"",
335
- "description": "Выравнивание панели относительно триггера."
336
- },
337
- {
338
- "name": "placement",
339
- "type": "\"auto\" | \"top\" | \"bottom\"",
340
- "description": "Куда открывать панель. Футер Sidebar передаёт `top`. @default \"auto\""
341
- },
342
- {
343
- "name": "open",
344
- "type": "boolean",
345
- "description": "Контролируемое открытие."
346
- },
347
- {
348
- "name": "defaultOpen",
349
- "type": "boolean",
350
- "description": "Начальное открытие (неконтролируемый режим)."
351
- },
352
- {
353
- "name": "onOpenChange",
354
- "type": "(open: boolean) => void",
355
- "description": "Колбэк смены open."
356
- },
357
- {
358
- "name": "closeOnSelect",
359
- "type": "boolean",
360
- "description": "Закрывать панель после выбора. Для checkbox обычно `false`."
361
- },
362
- {
363
- "name": "disabled",
364
- "type": "boolean",
365
- "description": "Заблокировать триггер."
366
- },
367
- {
368
- "name": "size",
369
- "type": "UiSize",
370
- "description": "Высота встроенного триггера (`--control-height`). Внутри {@link Toolbar} берётся из тулбара, если не задан."
371
- },
372
- {
373
- "name": "onSelect",
374
- "type": "(value: string, item: DropdownItem) => void",
375
- "description": "Выбор пункта: `value` + сам item."
376
- }
377
- ]
378
- },
379
- {
380
- "slug": "EmptyState",
381
- "title": "EmptyState",
382
- "description": "Заглушка «нет данных»: иконка, заголовок, описание, действия. Роли: EmptyState после загрузки при пустом списке; во время загрузки — Loading; для секций с контентом — Section.",
383
- "importFrom": "@elcrm/components",
384
- "examples": [
385
- {
386
- "title": "Пример",
387
- "code": "<EmptyState\n title=\"Нет клиентов\"\n description=\"Создайте первого клиента\"\n actions={<Button>Создать</Button>}\n/>"
388
- }
389
- ],
390
- "props": [
391
- {
392
- "name": "title",
393
- "type": "React.ReactNode",
394
- "description": "Заголовок заглушки"
395
- },
396
- {
397
- "name": "description",
398
- "type": "React.ReactNode",
399
- "description": "Поясняющий текст"
400
- },
401
- {
402
- "name": "icon",
403
- "type": "React.ReactNode",
404
- "description": "Иконка над заголовком"
405
- },
406
- {
407
- "name": "actions",
408
- "type": "React.ReactNode",
409
- "description": "Кнопки / CTA под описанием"
410
- },
411
- {
412
- "name": "children",
413
- "type": "React.ReactNode",
414
- "description": "Доп. контент между описанием и actions"
415
- }
416
- ]
417
- },
418
- {
419
- "slug": "Footer",
420
- "title": "Footer",
421
- "description": "Подвал страницы или модуля. Роли: Footer в Layout (глобальный) или в PageShell как `footer` (прибит к низу модуля).",
422
- "importFrom": "@elcrm/components",
423
- "examples": [
424
- {
425
- "title": "Пример",
426
- "code": "<Layout footer={<Footer>© elCRM · v1.0</Footer>}>\n …\n</Layout>"
427
- }
428
- ],
429
- "props": [
430
- {
431
- "name": "children",
432
- "type": "React.ReactNode",
433
- "description": "Содержимое подвала (копирайт, ссылки, статус)"
434
- }
435
- ]
436
- },
437
- {
438
- "slug": "Header",
439
- "title": "Header",
440
- "description": "Шапка приложения со слотами brand / nav / search / actions. Роли: Header = верхняя полоса в Layout; Brand — логотип/название; рядом — Menu, поиск из `@elcrm/form`, кнопки `@elcrm/button`.",
441
- "importFrom": "@elcrm/components",
442
- "examples": [
443
- {
444
- "title": "Пример",
445
- "code": "<Header\n brand={<Brand>elCRM</Brand>}\n nav={<Menu items={navItems} />}\n actions={<Button>Выйти</Button>}\n/>"
446
- }
447
- ],
448
- "props": [
449
- {
450
- "name": "brand",
451
- "type": "React.ReactNode",
452
- "description": "Логотип / название (часто `<Brand />`)"
453
- },
454
- {
455
- "name": "nav",
456
- "type": "React.ReactNode",
457
- "description": "Навигация (Menu, ссылки)"
458
- },
459
- {
460
- "name": "search",
461
- "type": "React.ReactNode",
462
- "description": "Поиск или фильтр в шапке"
463
- },
464
- {
465
- "name": "actions",
466
- "type": "React.ReactNode",
467
- "description": "Действия справа (кнопки, аватар, колокольчик)"
468
- },
469
- {
470
- "name": "children",
471
- "type": "React.ReactNode",
472
- "description": "Доп. контент после слотов"
473
- }
474
- ]
475
- },
476
- {
477
- "slug": "Healthmap",
478
- "title": "Healthmap",
479
- "description": "Теплокарта активности по дням (как GitHub contribution graph). Роли: Healthmap = визуализация `days[]`; данные грузит приложение (`Api.query` / свой RPC), не сам компонент.",
480
- "importFrom": "@elcrm/components",
481
- "examples": [
482
- {
483
- "title": "Пример",
484
- "code": "<Healthmap\n data={heatmap}\n loading={pending}\n year={year}\n onYearChange={setYear}\n brandName=\"eKivi\"\n brandSub=\"клиенты\"\n unit={{ one: \"событие\", few: \"события\", many: \"событий\" }}\n/>"
485
- }
486
- ],
487
- "props": [
488
- {
489
- "name": "data",
490
- "type": "HealthmapData | null",
491
- "description": "Данные года; `null` — пустая сетка."
492
- },
493
- {
494
- "name": "loading",
495
- "type": "boolean",
496
- "description": "Показать «Загрузка…» в заголовке."
497
- },
498
- {
499
- "name": "year",
500
- "type": "number | null",
501
- "description": "Выбранный год. `null` — «последний год» (как в ответе сервера). Контролируемый режим: вместе с `onYearChange`."
502
- },
503
- {
504
- "name": "onYearChange",
505
- "type": "(year: number | null) => void",
506
- "description": "Смена года (клик по вкладке)."
507
- },
508
- {
509
- "name": "hint",
510
- "type": "string",
511
- "description": "Подсказка под сеткой."
512
- },
513
- {
514
- "name": "brandName",
515
- "type": "string",
516
- "description": "Бренд в боковой колонке KPI."
517
- },
518
- {
519
- "name": "brandSub",
520
- "type": "string",
521
- "description": "Подпись под брендом."
522
- },
523
- {
524
- "name": "unit",
525
- "type": "HealthmapUnit",
526
- "description": "Единицы для склонения счётчиков."
527
- }
528
- ]
529
- },
530
- {
531
- "slug": "Item",
532
- "title": "Item",
533
- "description": "Элемент списка / строки меню: кнопка, ссылка или `<li>`. Роли: Item внутри List / Menu; для групповых списков выбора — RadioGroup / Dropdown с `items` (не собирайте Item вручную).",
534
- "importFrom": "@elcrm/components",
535
- "examples": [
536
- {
537
- "title": "Пример",
538
- "code": "<List>\n <Item as=\"li\" active>Текущий</Item>\n <Item as=\"button\" variant=\"card\" active>Карточка</Item>\n</List>"
539
- }
540
- ],
541
- "props": [
542
- {
543
- "name": "as",
544
- "type": "\"button\"",
545
- "description": "Тег: кнопка (по умолчанию)"
546
- },
547
- {
548
- "name": "as",
549
- "type": "\"a\"",
550
- "description": "Тег: ссылка"
551
- },
552
- {
553
- "name": "as",
554
- "type": "\"li\"",
555
- "description": "Тег: элемент списка"
556
- }
557
- ]
558
- },
559
- {
560
- "slug": "ItemColumn",
561
- "title": "ItemColumn",
562
- "description": "Колонка содержимого строки списка: иконка слева, текст столбиком, слоты справа. Роли: внутри {@link Item} / {@link Card} (идеи, тикеты, inbox). Не заменяет Item (клик / active) и не AvatarName (там фото).",
563
- "importFrom": "@elcrm/components",
564
- "examples": [
565
- {
566
- "title": "Пример",
567
- "code": "<Item as=\"button\" onClick={open}>\n <ItemColumn\n icon={<Icon />}\n title=\"Тема\"\n extra={<Badge size=\"s\" tone=\"accent\">Новые</Badge>}\n description=\"Превью текста…\"\n meta={[\"★ 2\", \"3 комм.\", \"Иван\"]}\n />\n</Item>"
568
- }
569
- ],
570
- "props": [
571
- {
572
- "name": "icon",
573
- "type": "React.ReactNode",
574
- "description": "Иконка слева"
575
- },
576
- {
577
- "name": "title",
578
- "type": "React.ReactNode",
579
- "description": "Заголовок"
580
- },
581
- {
582
- "name": "extra",
583
- "type": "React.ReactNode",
584
- "description": "Справа сверху у title (Badge, счётчик)"
585
- },
586
- {
587
- "name": "aside",
588
- "type": "React.ReactNode",
589
- "description": "Правая колонка (верхний край)"
590
- },
591
- {
592
- "name": "description",
593
- "type": "React.ReactNode",
594
- "description": "Описание / превью"
595
- },
596
- {
597
- "name": "footer",
598
- "type": "React.ReactNode",
599
- "description": "Подвал целиком"
600
- },
601
- {
602
- "name": "meta",
603
- "type": "React.ReactNode[]",
604
- "description": "Куски подвала через точку — если нет `footer`"
605
- },
606
- {
607
- "name": "size",
608
- "type": "UiSize",
609
- "description": "Размер текста"
610
- },
611
- {
612
- "name": "unread",
613
- "type": "boolean",
614
- "description": "Жирный title (непрочитанное)"
615
- },
616
- {
617
- "name": "children",
618
- "type": "React.ReactNode",
619
- "description": "Доп. строки под footer"
620
- }
621
- ]
622
- },
623
- {
624
- "slug": "Layout",
625
- "title": "Layout",
626
- "description": "Оболочка приложения: шапка, основной контент, подвал. Роли: Layout = каркас страницы; внутри — Header / Section / PageShell / Footer. Используйте как корневой каркас маршрута или приложения. `fixed` — какие слоты не крутятся вместе со страницей. По умолчанию `[\"header\", \"footer\", \"sidebar\"]`: скроллится только `children` в `<main>`. Пустой массив — обычный поток, скролл у предка. Высота каркаса: `--layout-height` (по умолчанию `100dvh`). Вложенный стенд: `--layout-height: 100%` у родителя с явной высотой.",
627
- "importFrom": "@elcrm/components",
628
- "examples": [
629
- {
630
- "title": "Пример",
631
- "code": "<Layout\n fixed={[\"header\", \"footer\", \"sidebar\"]}\n sidebar={<Sidebar groups={groups} value={page} onSelect={setPage} />}\n header={<Header brand=\"App\" />}\n footer={<Footer>© elCRM</Footer>}\n>\n <PageShell>…</PageShell>\n</Layout>"
632
- }
633
- ],
634
- "props": [
635
- {
636
- "name": "sidebar",
637
- "type": "React.ReactNode",
638
- "description": "Левая колонка (обычно `<Sidebar />`) — ряд: сайдбар + контент"
639
- },
640
- {
641
- "name": "header",
642
- "type": "React.ReactNode",
643
- "description": "Слот шапки (обычно `<Header />`)"
644
- },
645
- {
646
- "name": "footer",
647
- "type": "React.ReactNode",
648
- "description": "Слот подвала (обычно `<Footer />`)"
649
- },
650
- {
651
- "name": "fixed",
652
- "type": "LayoutFixedSlot[]",
653
- "description": "Какие слоты зафиксированы (не прокручиваются). По умолчанию все: `header`, `footer`, `sidebar`. `[]` — ничего не фиксировать."
654
- },
655
- {
656
- "name": "children",
657
- "type": "React.ReactNode",
658
- "description": "Основной контент страницы (рендерится в `<main>`)"
659
- }
660
- ]
661
- },
662
- {
663
- "slug": "List",
664
- "title": "List",
665
- "description": "Список (`<ul>`) — вертикальный или горизонтальный. Роли: List = контейнер; элементы — Item (или свои `<li>`). Для навигации / меню смотрите Menu, NavSections.",
666
- "importFrom": "@elcrm/components",
667
- "examples": [
668
- {
669
- "title": "Пример",
670
- "code": "<List>\n <Item as=\"li\">Первый</Item>\n <Item as=\"li\" active>Второй</Item>\n</List>"
671
- }
672
- ],
673
- "props": [
674
- {
675
- "name": "row",
676
- "type": "boolean",
677
- "description": "Горизонтальный список"
678
- },
679
- {
680
- "name": "children",
681
- "type": "React.ReactNode",
682
- "description": "Элементы списка (обычно `<Item as=\"li\" />`)"
683
- }
684
- ]
685
- },
686
- {
687
- "slug": "Loading",
688
- "title": "Loading",
689
- "description": "Плейсхолдер состояния загрузки (`role=\"status\"`). Роли: Loading = индикация ожидания данных; при пустом результате после загрузки — EmptyState.",
690
- "importFrom": "@elcrm/components",
691
- "examples": [
692
- {
693
- "title": "Пример",
694
- "code": "{isLoading ? <Loading>Загружаем клиентов…</Loading> : <List>…</List>}"
695
- }
696
- ],
697
- "props": [
698
- {
699
- "name": "children",
700
- "type": "React.ReactNode",
701
- "description": "Текст или кастомный индикатор (по умолчанию «Загрузка…»)"
702
- }
703
- ]
704
- },
705
- {
706
- "slug": "Menu",
707
- "title": "Menu",
708
- "description": "Навигационное меню в потоке документа (шапка, сайдбар-ряд) — не popover. Когда использовать: - горизонтальная/вертикальная навигация в layout; - нужно подсветить текущий раздел по `value`. Связанные компоненты: - {@link Dropdown} — выпадающая панель рядом с триггером; - {@link Popover} / {@link Dropdown} — панель в portal; - {@link NavSections} / {@link TabSections} — разделы с lazy-контентом. API: декларативные `items` (идентификатор — `value`). Compound-слоты не используются.",
709
- "importFrom": "@elcrm/components",
710
- "examples": [
711
- {
712
- "title": "Пример",
713
- "code": "const items = [\n { value: \"home\", label: \"Главная\" },\n { value: \"team\", label: \"Команда\", badge: 3 },\n];\n\n<Menu\n items={items}\n value={section}\n onSelect={setSection}\n vertical\n/>"
714
- }
715
- ],
716
- "props": [
717
- {
718
- "name": "items",
719
- "type": "MenuItem[]",
720
- "description": "Декларативный список пунктов. Групповые UI elCRM используют `items`, а не compound-слоты."
721
- },
722
- {
723
- "name": "vertical",
724
- "type": "boolean",
725
- "description": "Вертикальный ряд пунктов."
726
- },
727
- {
728
- "name": "variant",
729
- "type": "\"plain\" | \"line\"",
730
- "description": "`plain` — пилюли. `line` — вкладки с нижней чертой (фильтры страницы)."
731
- },
732
- {
733
- "name": "value",
734
- "type": "string",
735
- "description": "Активный `value` пункта (если у item не задан `active`). Идентификатор — `value`, не `key`."
736
- },
737
- {
738
- "name": "onSelect",
739
- "type": "(value: string) => void",
740
- "description": "Выбор пункта: получает `item.value`."
741
- },
742
- {
743
- "name": "children",
744
- "type": "React.ReactNode",
745
- "description": "Дополнительный контент внутри `<nav>` (редко)."
746
- }
747
- ]
748
- },
749
- {
750
- "slug": "NavSections",
751
- "title": "NavSections",
752
- "description": "Макет «настройки / профиль»: вертикальный сайдбар + lazy-секция справа. Когда использовать: - страницы с несколькими разделами и боковым меню; - контент секции грузится по `value` через `resolveSection`. Связанные компоненты: - {@link TabSections} — то же, но вкладки горизонтально; - {@link createLazyResolver} из `lazyRoute` — кэш lazy-импортов; - {@link Menu} — простая навигация без панелей. API: декларативные `groups` / `items`. Идентификатор раздела — `value` (не `key`). У пункта `items` + `defaultOpen` — раскрываемое подменю (как у Sidebar). Compound-слоты (`NavSections.Item`) не используются. CSS-токены: `--shell-*`, `--nav-sections-padding`, `--nav-sections-nav-width`, `--nav-sections-main-max-width`, `--sidebar-indent`.",
753
- "importFrom": "@elcrm/components",
754
- "examples": [
755
- {
756
- "title": "Пример",
757
- "code": "const groups = [\n {\n label: \"Документация\",\n items: [\n {\n value: \"bridge\",\n label: \"VK Bridge\",\n defaultOpen: true,\n items: [\n { value: \"intro\", label: \"Введение\" },\n { value: \"events\", label: \"События\", items: [\n { value: \"evt-init\", label: \"VKWebAppInit\" },\n ] },\n ],\n },\n { value: \"auth\", label: \"Авторизация VK\" },\n ],\n },\n];\n\n<NavSections\n groups={groups}\n resolveSection={resolveSection}\n value={section}\n onValueChange={setSection}\n/>"
758
- }
759
- ],
760
- "props": [
761
- {
762
- "name": "groups",
763
- "type": "NavSectionsGroup[]",
764
- "description": "Группы бокового меню."
765
- },
766
- {
767
- "name": "resolveSection",
768
- "type": "(value: string) => LazyRouteChunk | React.ComponentType",
769
- "description": "Резолвер панели справа по `value`. Обычно: `createLazyResolver((v) => import(\\`./sections/${v}.tsx\\`))`."
770
- },
771
- {
772
- "name": "value",
773
- "type": "string",
774
- "description": "Контролируемый активный `value`."
775
- },
776
- {
777
- "name": "defaultValue",
778
- "type": "string",
779
- "description": "Начальный `value` в неконтролируемом режиме."
780
- },
781
- {
782
- "name": "onValueChange",
783
- "type": "(value: string) => void",
784
- "description": "Смена активного раздела (`next` = `item.value`)."
785
- },
786
- {
787
- "name": "open",
788
- "type": "string[]",
789
- "description": "Раскрытые родители (их `value`). Контролируемый режим. Вместе с `onOpenChange`."
790
- },
791
- {
792
- "name": "defaultOpen",
793
- "type": "string[]",
794
- "description": "Начально раскрытые (плюс `item.defaultOpen` и предки выбранного)."
795
- },
796
- {
797
- "name": "onOpenChange",
798
- "type": "(open: string[]) => void",
799
- "description": "Смена набора раскрытых родителей"
800
- },
801
- {
802
- "name": "loading",
803
- "type": "React.ReactNode",
804
- "description": "Fallback для `<Suspense>` при ленивой загрузке секции."
805
- },
806
- {
807
- "name": "footer",
808
- "type": "React.ReactNode",
809
- "description": "Низ сайдбара (например кнопка «Назад»)."
810
- },
811
- {
812
- "name": "navLabel",
813
- "type": "string",
814
- "description": "`aria-label` для `<nav>`."
815
- }
816
- ]
817
- },
818
- {
819
- "slug": "PageHead",
820
- "title": "PageHead",
821
- "description": "Заголовок страницы: title слева, actions справа в одной линии. Роли: PageHead = шапка контента внутри PageShell / Section; для полноценной секции с description/icon — Section; глобальная шапка приложения — Header.",
822
- "importFrom": "@elcrm/components",
823
- "examples": [
824
- {
825
- "title": "Пример",
826
- "code": "<PageShell scroll>\n <PageHead title=\"Идеи\" sup={<Badge size=\"s\" tone=\"accent\">4</Badge>} sticky>\n <Menu items={tabs} value={tab} onSelect={setTab} />\n </PageHead>\n …\n</PageShell>"
827
- }
828
- ],
829
- "props": [
830
- {
831
- "name": "title",
832
- "type": "React.ReactNode",
833
- "description": "Заголовок страницы"
834
- },
835
- {
836
- "name": "sup",
837
- "type": "React.ReactNode",
838
- "description": "Надстрочный слот сразу после title: текст или {@link Badge}. Пусто / `0` / `false` — не рендерим."
839
- },
840
- {
841
- "name": "subtitle",
842
- "type": "React.ReactNode",
843
- "description": "Подзаголовок"
844
- },
845
- {
846
- "name": "actions",
847
- "type": "React.ReactNode",
848
- "description": "Кнопки / поиск справа в одной строке с заголовком"
849
- },
850
- {
851
- "name": "sticky",
852
- "type": "boolean",
853
- "description": "Прилипает к верху скролла предка (`PageShell` с `scroll`). По умолчанию `false`."
854
- },
855
- {
856
- "name": "children",
857
- "type": "React.ReactNode",
858
- "description": "Контент под строкой заголовка (фильтры, поиск, вкладки). Между title и children — `--shell-gap`."
859
- }
860
- ]
861
- },
862
- {
863
- "slug": "PageShell",
864
- "title": "PageShell",
865
- "description": "Каркас модуля: опциональный скролл в body, footer прибит к низу. Роли: PageShell = внутренний каркас контента в Layout; сверху часто PageHead / Section, снизу — панель действий.",
866
- "importFrom": "@elcrm/components",
867
- "examples": [
868
- {
869
- "title": "Пример",
870
- "code": "<PageShell wide scroll footer={<Footer><Button>Сохранить</Button></Footer>}>\n <PageHead title=\"Редактор\" sticky />\n …\n</PageShell>"
871
- }
872
- ],
873
- "props": [
874
- {
875
- "name": "children",
876
- "type": "React.ReactNode",
877
- "description": "Контент модуля"
878
- },
879
- {
880
- "name": "wide",
881
- "type": "boolean",
882
- "description": "Шире контент (редакторы, таблицы)"
883
- },
884
- {
885
- "name": "scroll",
886
- "type": "boolean",
887
- "description": "Скролл внутри body. По умолчанию `true`. `false` — шелл растёт с контентом, крутит предок."
888
- },
889
- {
890
- "name": "footer",
891
- "type": "React.ReactNode",
892
- "description": "Нижняя панель вне скролла"
893
- }
894
- ]
895
- },
896
- {
897
- "slug": "PanelInfo",
898
- "title": "PanelInfo",
899
- "description": "Выезжающая панель справа: шапка / body / footer. Широкий экран — flex-колонка рядом со списком. Узкий (`max-width: 56rem`) — поверх контента с затемнением и `acquireOverlayZIndex`.",
900
- "importFrom": "@elcrm/components",
901
- "examples": [
902
- {
903
- "title": "Пример",
904
- "code": "<PanelInfo\n open={!!row}\n title={row?.name ?? \"\"}\n onClose={() => setId(null)}\n footer={<Button width=\"l\" label=\"Сохранить\" onSend={onSave} />}\n>\n <StringField name=\"name\" form={form} label=\"Название\" />\n</PanelInfo>"
905
- }
906
- ],
907
- "props": [
908
- {
909
- "name": "open",
910
- "type": "boolean",
911
- "description": "Открыта ли панель."
912
- },
913
- {
914
- "name": "title",
915
- "type": "React.ReactNode",
916
- "description": "Заголовок шапки."
917
- },
918
- {
919
- "name": "onClose",
920
- "type": "() => void",
921
- "description": "Закрытие: крестик / фон / Escape."
922
- },
923
- {
924
- "name": "children",
925
- "type": "React.ReactNode",
926
- "description": "Тело — форма (`@elcrm/form` поля) или любой контент. Скроллится между шапкой и footer."
927
- },
928
- {
929
- "name": "footer",
930
- "type": "React.ReactNode",
931
- "description": "Низ вне скролла — обычно `Stack` + `@elcrm/button` («Отмена» / «Сохранить»)."
932
- },
933
- {
934
- "name": "headerExtra",
935
- "type": "React.ReactNode",
936
- "description": "Доп. действия в шапке слева от крестика."
937
- },
938
- {
939
- "name": "close",
940
- "type": "React.ReactNode",
941
- "description": "Слот кнопки закрытия. По умолчанию — крестик. Приложение может подставить `@elcrm/button`."
942
- }
943
- ]
944
- },
945
- {
946
- "slug": "Popover",
947
- "title": "Popover",
948
- "description": "Портал у якоря: Escape, клик снаружи, z-index (`globalThis.elcrm.overlayZ`). Роли: Popover = свой попап (слот `children`). Типовое меню пунктов — {@link Dropdown}. Инлайн-навигация — {@link Menu} (не путать). Бывший `@elcrm/overlay` `Menu` — этот компонент (`Popover`).",
949
- "importFrom": "@elcrm/components",
950
- "examples": [
951
- {
952
- "title": "Пример",
953
- "code": "<Popover\n trigger={<Button>Ещё</Button>}\n label=\"Действия\"\n align=\"end\"\n>\n <List>\n <Item as=\"button\">Скачать</Item>\n </List>\n</Popover>"
954
- }
955
- ],
956
- "props": [
957
- {
958
- "name": "trigger",
959
- "type": "React.ReactNode",
960
- "description": "Якорь (кнопка / иконка)"
961
- },
962
- {
963
- "name": "children",
964
- "type": "React.ReactNode",
965
- "description": "Содержимое панели"
966
- },
967
- {
968
- "name": "open",
969
- "type": "boolean",
970
- "description": "Контролируемое открытие"
971
- },
972
- {
973
- "name": "defaultOpen",
974
- "type": "boolean",
975
- "description": "Начальное открытие"
976
- },
977
- {
978
- "name": "onOpenChange",
979
- "type": "(open: boolean) => void",
980
- "description": "Смена open"
981
- },
982
- {
983
- "name": "align",
984
- "type": "\"start\" | \"end\"",
985
- "description": "Выравнивание панели"
986
- },
987
- {
988
- "name": "placement",
989
- "type": "PopoverPlacement",
990
- "description": "Куда открывать панель. `top` — всегда вверх (футер Sidebar). @default \"auto\""
991
- },
992
- {
993
- "name": "disabled",
994
- "type": "boolean",
995
- "description": "Не открывать по клику на якорь"
996
- },
997
- {
998
- "name": "label",
999
- "type": "string",
1000
- "description": "aria-label панели"
1001
- },
1002
- {
1003
- "name": "role",
1004
- "type": "React.AriaRole",
1005
- "description": "role панели"
1006
- },
1007
- {
1008
- "name": "panelClassName",
1009
- "type": "string",
1010
- "description": "Класс панели (portal)"
1011
- }
1012
- ]
1013
- },
1014
- {
1015
- "slug": "PricingGroup",
1016
- "title": "PricingGroup",
1017
- "description": "Горизонтальная группа тарифных карточек из декларативного `items`. Когда использовать: - страница тарифов / upgrade без матрицы сравнения; - один и тот же массив {@link PricingPlan} позже уйдёт в {@link PricingTable}. Связанные компоненты: - {@link PricingTable} — сравнительная матрица поверх тех же `items`; - {@link RadioGroup} — выбор опции с индикатором, не обязательно тариф. Общий тип плана — {@link PricingPlan}. Идентификатор — `value` (не `key`). Compound-слоты не используются. CSS-токены: `--shell-*`, узкие `--pricing-card-min-width`.",
1018
- "importFrom": "@elcrm/components",
1019
- "examples": [
1020
- {
1021
- "title": "Пример",
1022
- "code": "const items: PricingPlan[] = [\n {\n value: \"starter\",\n title: \"Starter\",\n price: \"$9\",\n meta: \"в месяц\",\n features: [\"1 проект\", \"Email-поддержка\"],\n actions: <Button onSend={…}>Выбрать</Button>,\n },\n {\n value: \"pro\",\n title: \"Pro\",\n price: \"$29\",\n badge: \"Popular\",\n badgePlacement: \"float\",\n highlighted: true,\n features: [\"Безлимит\", \"SSO\"],\n actions: <Button onSend={…}>Выбрать</Button>,\n },\n];\n\n<PricingGroup items={items} selectable value={plan} onValueChange={setPlan} />"
1023
- }
1024
- ],
1025
- "props": [
1026
- {
1027
- "name": "items",
1028
- "type": "PricingPlan[]",
1029
- "description": "Тарифные карточки — тот же shape, что у {@link PricingTable}."
1030
- },
1031
- {
1032
- "name": "value",
1033
- "type": "string",
1034
- "description": "Выбранный план (controlled), сравнивается с `item.value`."
1035
- },
1036
- {
1037
- "name": "defaultValue",
1038
- "type": "string",
1039
- "description": "Начальный выбранный план (uncontrolled)."
1040
- },
1041
- {
1042
- "name": "selectable",
1043
- "type": "boolean",
1044
- "description": "Клик по карточке выбирает value (actions не трогают выбор)."
1045
- },
1046
- {
1047
- "name": "disabled",
1048
- "type": "boolean",
1049
- "description": "Заблокировать выбор."
1050
- },
1051
- {
1052
- "name": "onValueChange",
1053
- "type": "(value: string) => void",
1054
- "description": "Смена выбранного плана."
1055
- }
1056
- ]
1057
- },
1058
- {
1059
- "slug": "PricingTable",
1060
- "title": "PricingTable",
1061
- "description": "Сравнительная таблица тарифов: колонки из `items` + матрица `sections`. Когда использовать: - страница сравнения фич между планами; - те же {@link PricingPlan} уже используются в {@link PricingGroup}. Связанные компоненты: - {@link PricingGroup} — карточки без матрицы; - общий тип — {@link PricingPlan}. API: декларативные `items` (+ `sections`). Идентификатор плана — `value` (не `key`). Compound-слоты не используются. CSS-токены: `--shell-*`, узкие `--pricing-table-label-width`, `--pricing-card-min-width`.",
1062
- "importFrom": "@elcrm/components",
1063
- "examples": [
1064
- {
1065
- "title": "Пример",
1066
- "code": "const items: PricingPlan[] = [\n { value: \"starter\", title: \"Starter\", price: \"$9\", actions: <Button>…</Button> },\n { value: \"pro\", title: \"Pro\", price: \"$29\", highlighted: true, actions: <Button>…</Button> },\n];\n\nconst sections = [\n {\n title: \"Команда\",\n rows: [\n {\n key: \"seats\",\n label: \"Участники\",\n values: { starter: \"3\", pro: \"Безлимит\" },\n },\n {\n key: \"sso\",\n label: \"SSO\",\n hint: \"Единый вход\",\n values: { starter: false, pro: true },\n },\n ],\n },\n];\n\n<PricingTable items={items} sections={sections} selectable />"
1067
- }
1068
- ],
1069
- "props": [
1070
- {
1071
- "name": "items",
1072
- "type": "PricingTableItem[]",
1073
- "description": "Колонки планов — тот же shape, что у {@link PricingGroup}."
1074
- },
1075
- {
1076
- "name": "sections",
1077
- "type": "PricingTableSection[]",
1078
- "description": "Матрица сравнения (секции → строки → values по plan.value)."
1079
- },
1080
- {
1081
- "name": "footerActions",
1082
- "type": "boolean",
1083
- "description": "Повторить actions внизу таблицы (как на макетах)."
1084
- },
1085
- {
1086
- "name": "value",
1087
- "type": "string",
1088
- "description": "Выбранный план (controlled)."
1089
- },
1090
- {
1091
- "name": "defaultValue",
1092
- "type": "string",
1093
- "description": "Начальный план (uncontrolled)."
1094
- },
1095
- {
1096
- "name": "selectable",
1097
- "type": "boolean",
1098
- "description": "Клик по шапке колонки выбирает план."
1099
- },
1100
- {
1101
- "name": "disabled",
1102
- "type": "boolean",
1103
- "description": "Заблокировать выбор."
1104
- },
1105
- {
1106
- "name": "onValueChange",
1107
- "type": "(value: string) => void",
1108
- "description": "Смена выбранного плана (`item.value`)."
1109
- }
1110
- ]
1111
- },
1112
- {
1113
- "slug": "RadioGroup",
1114
- "title": "RadioGroup",
1115
- "description": "Группа выбора одной опции из декларативного массива `items`. Когда использовать: - выбор тарифа, способа оплаты, человека, варианта настроек карточкой; - нужен check/radio-индикатор и опциональные icon / meta / actions. Связанные компоненты: - {@link PricingGroup} — тарифные карточки без radio-индикатора; - {@link AvatarName} — часто как `icon` / контент опции «человек». API: только `items` + value/onValueChange. Compound-слоты (`RadioGroup.Item`) не используются. Идентификатор опции — `value` (не `key`). CSS-токены: `--shell-*`.",
1116
- "importFrom": "@elcrm/components",
1117
- "examples": [
1118
- {
1119
- "title": "Пример",
1120
- "code": "const items = [\n {\n value: \"basic\",\n icon: <Icons.Line name=\"zap\" />,\n title: \"Basic\",\n description: \"Для старта\",\n meta: \"$9/мес\",\n },\n {\n value: \"pro\",\n title: \"Pro\",\n description: \"Для команд\",\n price: \"$29\",\n badge: <Badge>Popular</Badge>,\n variant: \"split\",\n },\n];\n\n<RadioGroup\n items={items}\n value={plan}\n onValueChange={setPlan}\n indicator=\"check\"\n indicatorSide=\"end\"\n/>"
1121
- }
1122
- ],
1123
- "props": [
1124
- {
1125
- "name": "items",
1126
- "type": "RadioGroupItem[]",
1127
- "description": "Декларативный список опций."
1128
- },
1129
- {
1130
- "name": "value",
1131
- "type": "string",
1132
- "description": "Выбранное значение (controlled)."
1133
- },
1134
- {
1135
- "name": "defaultValue",
1136
- "type": "string",
1137
- "description": "Начальное значение (uncontrolled)."
1138
- },
1139
- {
1140
- "name": "name",
1141
- "type": "string",
1142
- "description": "`name` для скрытых `input[type=radio]`."
1143
- },
1144
- {
1145
- "name": "disabled",
1146
- "type": "boolean",
1147
- "description": "Заблокировать всю группу."
1148
- },
1149
- {
1150
- "name": "indicator",
1151
- "type": "RadioIndicator",
1152
- "description": "`check` — квадрат с галочкой; `radio` — круг."
1153
- },
1154
- {
1155
- "name": "indicatorSide",
1156
- "type": "RadioIndicatorSide",
1157
- "description": "Сторона индикатора в row-варианте."
1158
- },
1159
- {
1160
- "name": "onValueChange",
1161
- "type": "(value: string) => void",
1162
- "description": "Смена выбора (`next` = `item.value`)."
1163
- }
1164
- ]
1165
- },
1166
- {
1167
- "slug": "Row",
1168
- "title": "Row",
1169
- "description": "Row",
1170
- "importFrom": "@elcrm/components",
1171
- "examples": [
1172
- {
1173
- "title": "Пример",
1174
- "code": "// Было:\n<Row gap={8}>…</Row>\n// Стало:\n<Stack direction=\"row\" gap={8}>…</Stack>"
1175
- }
1176
- ],
1177
- "props": []
1178
- },
1179
- {
1180
- "slug": "Section",
1181
- "title": "Section",
1182
- "description": "Единая секция страницы: заголовок, описание, иконка, контент, действия. Роли: Section = блок модуля / панель / auth-карточка; для строки «title + actions» на странице — PageHead; каркас со скроллом — PageShell.",
1183
- "importFrom": "@elcrm/components",
1184
- "examples": [
1185
- {
1186
- "title": "Пример",
1187
- "code": "<Section title=\"Настройки\" description=\"Профиль и безопасность\" variant=\"page\">\n <Stack gap={16}>…</Stack>\n</Section>"
1188
- }
1189
- ],
1190
- "props": [
1191
- {
1192
- "name": "title",
1193
- "type": "React.ReactNode",
1194
- "description": "Заголовок секции"
1195
- },
1196
- {
1197
- "name": "description",
1198
- "type": "React.ReactNode",
1199
- "description": "Подзаголовок / описание"
1200
- },
1201
- {
1202
- "name": "icon",
1203
- "type": "React.ReactNode",
1204
- "description": "Иконка / логотип над или рядом с заголовком"
1205
- },
1206
- {
1207
- "name": "children",
1208
- "type": "React.ReactNode",
1209
- "description": "Основной контент секции"
1210
- },
1211
- {
1212
- "name": "actions",
1213
- "type": "React.ReactNode",
1214
- "description": "Блок действий (кнопки под контентом или в шапке)"
1215
- },
1216
- {
1217
- "name": "variant",
1218
- "type": "\"page\" | \"block\" | \"auth\"",
1219
- "description": "`page` — секция модуля / панель настроек. `block` — блок внутри панели (заголовок + разделитель). `auth` — центрированная карточка входа."
1220
- },
1221
- {
1222
- "name": "align",
1223
- "type": "\"start\" | \"center\"",
1224
- "description": "Выравнивание шапки (`start` по умолчанию, для `auth` — `center`)"
1225
- },
1226
- {
1227
- "name": "titleSize",
1228
- "type": "\"md\" | \"lg\"",
1229
- "description": "Размер заголовка"
1230
- },
1231
- {
1232
- "name": "as",
1233
- "type": "\"section\" | \"main\" | \"div\"",
1234
- "description": "HTML-тег корня (`main` / `section` / `div`)"
1235
- }
1236
- ]
1237
- },
1238
- {
1239
- "slug": "Sidebar",
1240
- "title": "Sidebar",
1241
- "description": "Левая колонка приложения: бренд, группы меню, футер. Роли: Sidebar = навигация приложения; не путать с NavSections (сайдбар внутри страницы + lazy-панель). `variant=\"cards\"` — секции-карточки (elWMS Console). `variant=\"plain\"` — плоский список и заголовок группы (backoffice). Иконки, колокольчик, тема, выход — слоты приложения (`brand`, `extra`, `footer`). Роутер не подключаем.",
1242
- "importFrom": "@elcrm/components",
1243
- "examples": [
1244
- {
1245
- "title": "Пример",
1246
- "code": "<Sidebar\n variant=\"cards\"\n value={page}\n onSelect={setPage}\n brand={<Brand as=\"strong\">App</Brand>}\n extra={<Notifications.Bell />}\n groups={[\n {\n value: \"docs\",\n items: [\n { value: \"games\", label: \"VK Games\" },\n {\n value: \"bridge\",\n label: \"VK Bridge\",\n defaultOpen: true,\n items: [\n { value: \"intro\", label: \"Введение\" },\n { value: \"events\", label: \"События\", items: [\n { value: \"evt-init\", label: \"VKWebAppInit\" },\n ] },\n ],\n },\n ],\n },\n ]}\n footer={<AvatarName title=\"Паша\" description=\"mail@…\" />}\n footerItems={[\n { value: \"home\", label: \"Главная\", icon: <Icon /> },\n { value: \"theme\", label: \"Тема\", submenu: true },\n { value: \"logout\", label: \"Выйти\", danger: true },\n ]}\n onFooterSelect={(value) => console.log(value)}\n version=\"v 0.2.26\"\n/>"
1247
- }
1248
- ],
1249
- "props": [
1250
- {
1251
- "name": "groups",
1252
- "type": "SidebarGroup[]",
1253
- "description": "Группы пунктов (`value` + `items`)"
1254
- },
1255
- {
1256
- "name": "items",
1257
- "type": "SidebarGroup[]",
1258
- "description": "То же, что `groups` (совместимость)"
1259
- },
1260
- {
1261
- "name": "value",
1262
- "type": "string",
1263
- "description": "Текущий пункт"
1264
- },
1265
- {
1266
- "name": "onSelect",
1267
- "type": "(value: string) => void",
1268
- "description": "Выбор пункта (только листья, без `items`)"
1269
- },
1270
- {
1271
- "name": "open",
1272
- "type": "string[]",
1273
- "description": "Раскрытые родители (их `value`). Контролируемый режим. Вместе с `onOpenChange`."
1274
- },
1275
- {
1276
- "name": "defaultOpen",
1277
- "type": "string[]",
1278
- "description": "Начально раскрытые (плюс `item.defaultOpen` и предки выбранного)."
1279
- },
1280
- {
1281
- "name": "onOpenChange",
1282
- "type": "(open: string[]) => void",
1283
- "description": "Смена набора раскрытых родителей"
1284
- },
1285
- {
1286
- "name": "variant",
1287
- "type": "SidebarVariant",
1288
- "description": "`cards` — блоки-карточки. `plain` — плоский список. @default \"cards\""
1289
- },
1290
- {
1291
- "name": "brand",
1292
- "type": "React.ReactNode",
1293
- "description": "Логотип / название"
1294
- },
1295
- {
1296
- "name": "extra",
1297
- "type": "React.ReactNode",
1298
- "description": "Справа от бренда (колокольчик)"
1299
- },
1300
- {
1301
- "name": "footer",
1302
- "type": "React.ReactNode",
1303
- "description": "Низ: тема, выход или карточка пользователя"
1304
- },
1305
- {
1306
- "name": "footerItems",
1307
- "type": "DropdownItem[]",
1308
- "description": "Меню по клику на `footer` (Dropdown, `placement=\"top\"`). Есть пункты → футер становится триггером, справа ⋮."
1309
- },
1310
- {
1311
- "name": "onFooterSelect",
1312
- "type": "(value: string, item: DropdownItem) => void",
1313
- "description": "Выбор пункта меню аккаунта"
1314
- },
1315
- {
1316
- "name": "footerMenuLabel",
1317
- "type": "string",
1318
- "description": "`aria-label` панели меню аккаунта"
1319
- },
1320
- {
1321
- "name": "version",
1322
- "type": "React.ReactNode",
1323
- "description": "Версия под футером"
1324
- }
1325
- ]
1326
- },
1327
- {
1328
- "slug": "Stack",
1329
- "title": "Stack",
1330
- "description": "Универсальный стек (ряд / колонка) с отступами между детьми. Роли: Stack = базовая раскладка; заменяет устаревшие Block / Row / Column. Внутри Section, Card, форм и списков действий.",
1331
- "importFrom": "@elcrm/components",
1332
- "examples": [
1333
- {
1334
- "title": "Пример",
1335
- "code": "<Stack direction=\"row\" gap={12}>\n <Button>Отмена</Button>\n <Button>Сохранить</Button>\n</Stack>\n<Stack direction=\"grid\" columns={[\"1fr\", \"100px\", \"100px\"]} gap={12} />"
1336
- }
1337
- ],
1338
- "props": [
1339
- {
1340
- "name": "direction",
1341
- "type": "StackDirection",
1342
- "description": "Направление: по умолчанию `column`. `grid` — сетка"
1343
- },
1344
- {
1345
- "name": "columns",
1346
- "type": "StackColumns",
1347
- "description": "Сетка: `4` — четыре равные колонки; `[\"1fr\", \"100px\", \"auto\"]` — свои треки (число в массиве = px)."
1348
- },
1349
- {
1350
- "name": "gap",
1351
- "type": "number | string",
1352
- "description": "Отступ между детьми: число (px) или CSS-строка"
1353
- },
1354
- {
1355
- "name": "children",
1356
- "type": "React.ReactNode",
1357
- "description": "Дочерние элементы стека"
1358
- }
1359
- ]
1360
- },
1361
- {
1362
- "slug": "Stat",
1363
- "title": "Stat",
1364
- "description": "Карточка-метрика: подпись сверху, крупное число снизу. Роли: сводка на PageHead / над списком. Не заменяет Card с произвольным контентом.",
1365
- "importFrom": "@elcrm/components",
1366
- "examples": [
1367
- {
1368
- "title": "Пример",
1369
- "code": "<Stack direction=\"grid\" gap={12}>\n <Stat label=\"Всего\" value={10} labelMuted={false} />\n <Stat label=\"Admin\" value={6} tone=\"accent\" />\n</Stack>"
1370
- }
1371
- ],
1372
- "props": [
1373
- {
1374
- "name": "label",
1375
- "type": "React.ReactNode",
1376
- "description": "Подпись метрики"
1377
- },
1378
- {
1379
- "name": "value",
1380
- "type": "React.ReactNode",
1381
- "description": "Значение"
1382
- },
1383
- {
1384
- "name": "tone",
1385
- "type": "StatTone",
1386
- "description": "Цвет числа"
1387
- },
1388
- {
1389
- "name": "labelMuted",
1390
- "type": "boolean",
1391
- "description": "Приглушить подпись (по умолчанию да)"
1392
- }
1393
- ]
1394
- },
1395
- {
1396
- "slug": "TabSections",
1397
- "title": "TabSections",
1398
- "description": "Как {@link NavSections}, но вкладки горизонтально; без собственного заголовка — обычно оборачивают в `Section` / `PageHead`. Когда использовать: - несколько панелей на одной странице с горизонтальным переключением; - контент грузится lazy по `value`. Связанные компоненты: - {@link NavSections} — сайдбар + секции; - {@link createLazyResolver} — кэш lazy-импортов; - `Section` — обёртка с заголовком страницы. API: декларативные `items`. Идентификатор — `value` (не `key`). Compound-слоты не используются. CSS-токены: `--shell-*`.",
1399
- "importFrom": "@elcrm/components",
1400
- "examples": [
1401
- {
1402
- "title": "Пример",
1403
- "code": "const items = [\n { value: \"members\", label: \"Участники\", badge: 12 },\n { value: \"invites\", label: \"Приглашения\" },\n];\n\nconst resolveSection = createLazyResolver(\n (v) => import(`./sections/${v}.tsx`),\n);\n\n<TabSections\n items={items}\n resolveSection={resolveSection}\n value={tab}\n onValueChange={setTab}\n actions={<Button size=\"s\">Фильтр</Button>}\n/>"
1404
- }
1405
- ],
1406
- "props": [
1407
- {
1408
- "name": "items",
1409
- "type": "TabSectionsItem[]",
1410
- "description": "Горизонтальные вкладки. `value` пункта обычно = имя файла секции для `resolveSection`."
1411
- },
1412
- {
1413
- "name": "resolveSection",
1414
- "type": "(value: string) => LazyRouteChunk | React.ComponentType",
1415
- "description": "Резолвер панели по `value`. Обычно: `createLazyResolver((v) => import(\\`./sections/${v}.tsx\\`))`."
1416
- },
1417
- {
1418
- "name": "value",
1419
- "type": "string",
1420
- "description": "Контролируемый активный `value`."
1421
- },
1422
- {
1423
- "name": "defaultValue",
1424
- "type": "string",
1425
- "description": "Начальный `value` (неконтролируемый режим)."
1426
- },
1427
- {
1428
- "name": "onValueChange",
1429
- "type": "(value: string) => void",
1430
- "description": "Смена вкладки (`next` = `item.value`)."
1431
- },
1432
- {
1433
- "name": "loading",
1434
- "type": "React.ReactNode",
1435
- "description": "Fallback для `<Suspense>`."
1436
- },
1437
- {
1438
- "name": "actions",
1439
- "type": "React.ReactNode",
1440
- "description": "Справа в ряду вкладок (фильтр, сортировка…)."
1441
- },
1442
- {
1443
- "name": "navLabel",
1444
- "type": "string",
1445
- "description": "`aria-label` для `<nav>` вкладок."
1446
- }
1447
- ]
1448
- },
1449
- {
1450
- "slug": "TextGroup",
1451
- "title": "TextGroup",
1452
- "description": "Две строки текста: заголовок + приглушённая подпись. Роли: мета в строке списка (тенант + slug), без аватара. С аватаром — {@link AvatarName}.",
1453
- "importFrom": "@elcrm/components",
1454
- "examples": [
1455
- {
1456
- "title": "Пример",
1457
- "code": "<TextGroup title=\"SHMEL\" description=\"wms-k8voao47\" />"
1458
- }
1459
- ],
1460
- "props": [
1461
- {
1462
- "name": "title",
1463
- "type": "React.ReactNode",
1464
- "description": "Основная строка"
1465
- },
1466
- {
1467
- "name": "description",
1468
- "type": "React.ReactNode",
1469
- "description": "Подпись (email, slug…)"
1470
- },
1471
- {
1472
- "name": "size",
1473
- "type": "UiSize",
1474
- "description": "Размер типографики"
1475
- },
1476
- {
1477
- "name": "children",
1478
- "type": "React.ReactNode",
1479
- "description": "Доп. строки под подписью"
1480
- }
1481
- ]
1482
- },
1483
- {
1484
- "slug": "Toolbar",
1485
- "title": "Toolbar",
1486
- "description": "Ряд контролов одной высоты: поиск, поля, кнопки, меню. Роли: Toolbar = фильтры / действия над списком (`PageHead.children`). Иконки в карточке — `ActionGroup`. Пакет не зависит от `@elcrm/form` / `@elcrm/button`: размер уходит пропом `size` и токенами `--field-height` / `--button-height-*`.",
1487
- "importFrom": "@elcrm/components",
1488
- "examples": [
1489
- {
1490
- "title": "Пример",
1491
- "code": "<Toolbar size=\"s\" align=\"end\" label=\"Фильтры\">\n <Search value={q} onValue={setQ} />\n <Button label=\"Создать\" />\n</Toolbar>\n<Toolbar width=\"s\" align=\"center\">\n <Button label=\"Отмена\" />\n <Button label=\"Сохранить\" />\n</Toolbar>"
1492
- }
1493
- ],
1494
- "props": [
1495
- {
1496
- "name": "size",
1497
- "type": "UiSize",
1498
- "description": "Общий размер вложенных Field / Search / Button / Dropdown / Badge. Явный `size` у ребёнка важнее. @default \"s\""
1499
- },
1500
- {
1501
- "name": "label",
1502
- "type": "string",
1503
- "description": "Подпись для `aria-label`."
1504
- },
1505
- {
1506
- "name": "align",
1507
- "type": "ToolbarAlign",
1508
- "description": "Направление ряда (`justify-content`). @default \"start\""
1509
- },
1510
- {
1511
- "name": "width",
1512
- "type": "ToolbarWidth",
1513
- "description": "Ширина корня: `l` — `100%` (фильтры над списком), `s` — по контенту (компактный ряд, не растягивать). @default \"l\""
1514
- },
1515
- {
1516
- "name": "children",
1517
- "type": "React.ReactNode",
1518
- "description": "Узлы тулбара (`*Field`, `Search`, `Button`, `Dropdown`, …). Компонентам без `size` прокидывается размер тулбара."
1519
- }
1520
- ]
1521
- }
1522
- ]
1523
- }