@elcrm/components 0.0.3 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +450 -202
  2. package/dist/Avatar-CyNXYvsa.js +101 -0
  3. package/dist/Avatar.css +1 -1
  4. package/dist/Avatar.d.ts +56 -5
  5. package/dist/Avatar.js +1 -1
  6. package/dist/AvatarGroup-BAWas4pU.js +81 -0
  7. package/dist/AvatarGroup.css +1 -0
  8. package/dist/AvatarGroup.d.ts +77 -0
  9. package/dist/AvatarGroup.js +4 -0
  10. package/dist/AvatarName-DhD3TytF.js +56 -0
  11. package/dist/AvatarName.css +1 -0
  12. package/dist/AvatarName.d.ts +76 -0
  13. package/dist/AvatarName.js +4 -0
  14. package/dist/Badge.css +1 -1
  15. package/dist/Badge.d.ts +16 -1
  16. package/dist/Block-BAXh0PPp.js +8 -0
  17. package/dist/Block.d.ts +27 -6
  18. package/dist/Block.js +1 -1
  19. package/dist/Brand.css +1 -1
  20. package/dist/Brand.d.ts +20 -1
  21. package/dist/Breadcrumb-CAM_e9LN.js +98 -0
  22. package/dist/Breadcrumb.css +1 -0
  23. package/dist/Breadcrumb.d.ts +80 -0
  24. package/dist/Breadcrumb.js +4 -0
  25. package/dist/Card.css +1 -1
  26. package/dist/Card.d.ts +22 -1
  27. package/dist/Column-DDaqX-A7.js +8 -0
  28. package/dist/Column.d.ts +23 -7
  29. package/dist/Column.js +1 -1
  30. package/dist/Dropdown-DQlDiWCR.js +168 -0
  31. package/dist/Dropdown.css +1 -0
  32. package/dist/Dropdown.d.ts +124 -0
  33. package/dist/Dropdown.js +4 -0
  34. package/dist/EmptyState.css +1 -1
  35. package/dist/EmptyState.d.ts +24 -1
  36. package/dist/Footer.css +1 -1
  37. package/dist/Footer.d.ts +20 -1
  38. package/dist/Header.css +1 -1
  39. package/dist/Header.d.ts +25 -2
  40. package/dist/Item.css +1 -1
  41. package/dist/Item.d.ts +24 -1
  42. package/dist/Layout.css +1 -1
  43. package/dist/Layout.d.ts +23 -3
  44. package/dist/List.css +1 -1
  45. package/dist/List.d.ts +22 -1
  46. package/dist/Loading.css +1 -1
  47. package/dist/Loading.d.ts +19 -1
  48. package/dist/Menu-DRBHvSdJ.js +40 -0
  49. package/dist/Menu.css +1 -1
  50. package/dist/Menu.d.ts +64 -8
  51. package/dist/Menu.js +1 -1
  52. package/dist/{NavSections-CM-VPai2.js → NavSections-NDcIDD6H.js} +26 -26
  53. package/dist/NavSections.css +1 -1
  54. package/dist/NavSections.d.ts +79 -15
  55. package/dist/NavSections.js +1 -1
  56. package/dist/PageHead-Baz9BLuA.js +22 -0
  57. package/dist/PageHead.css +1 -0
  58. package/dist/PageHead.d.ts +36 -0
  59. package/dist/PageHead.js +4 -0
  60. package/dist/PageShell-CghThHS3.js +28 -0
  61. package/dist/PageShell.css +1 -0
  62. package/dist/PageShell.d.ts +33 -0
  63. package/dist/PageShell.js +4 -0
  64. package/dist/PricingGroup-DgcdVSq8.js +126 -0
  65. package/dist/PricingGroup.css +1 -0
  66. package/dist/PricingGroup.d.ts +130 -0
  67. package/dist/PricingGroup.js +4 -0
  68. package/dist/PricingTable-DALddSwM.js +158 -0
  69. package/dist/PricingTable.css +1 -0
  70. package/dist/PricingTable.d.ts +108 -0
  71. package/dist/PricingTable.js +4 -0
  72. package/dist/RadioGroup-D2UUOTkY.js +138 -0
  73. package/dist/RadioGroup.css +1 -0
  74. package/dist/RadioGroup.d.ts +111 -0
  75. package/dist/RadioGroup.js +4 -0
  76. package/dist/Row--HIe6vb9.js +8 -0
  77. package/dist/Row.d.ts +23 -7
  78. package/dist/Row.js +1 -1
  79. package/dist/Section.css +1 -1
  80. package/dist/Section.d.ts +23 -3
  81. package/dist/Stack-b0-XWwQ1.js +31 -0
  82. package/dist/Stack.css +1 -0
  83. package/dist/Stack.d.ts +34 -0
  84. package/dist/Stack.js +4 -0
  85. package/dist/TabSections-DL7DufKU.js +50 -0
  86. package/dist/TabSections.css +1 -1
  87. package/dist/TabSections.d.ts +69 -13
  88. package/dist/TabSections.js +1 -1
  89. package/dist/cx.d.ts +8 -1
  90. package/dist/dark.css +24 -0
  91. package/dist/index.css +32 -18
  92. package/dist/index.d.ts +21 -1
  93. package/dist/index.es.js +58 -38
  94. package/dist/lazyRoute.d.ts +19 -3
  95. package/dist/light.css +25 -0
  96. package/dist/stackGap.d.ts +13 -1
  97. package/dist/tokens.css +57 -0
  98. package/package.json +20 -4
  99. package/dist/Avatar-DHNPaIjZ.js +0 -64
  100. package/dist/Block-CVKukh1e.js +0 -28
  101. package/dist/Block.css +0 -1
  102. package/dist/Column-DlNrvFq1.js +0 -26
  103. package/dist/Column.css +0 -1
  104. package/dist/Menu-DS7zKQbY.js +0 -40
  105. package/dist/Row-CnD7Q7pD.js +0 -20
  106. package/dist/Row.css +0 -1
  107. package/dist/TabSections-oeEBx0nM.js +0 -50
  108. package/dist/stackGap-CDsjER0g.js +0 -7
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @elcrm/components
2
2
 
3
- Shell UI для elCRM: `Layout`, `Header`, `Section`, `NavSections`, `TabSections`, `Row`, `Column` и др.
3
+ Shell UI для elCRM: `Layout`, `Header`, `Section`, `Stack`, `NavSections`, `TabSections` и др.
4
4
 
5
5
  Стили — CSS Modules с короткими уникальными классами; значения токенов задаёт приложение (`theme-dark.css` / `theme-light.css`). Fallback в пакете нет.
6
6
 
@@ -18,20 +18,28 @@ import {
18
18
  List,
19
19
  Item,
20
20
  Card,
21
- Block,
22
- Row,
23
- Column,
21
+ Stack,
24
22
  Menu,
25
23
  Loading,
26
24
  Section,
27
25
  NavSections,
28
26
  TabSections,
29
27
  Avatar,
28
+ AvatarGroup,
29
+ AvatarName,
30
30
  Badge,
31
31
  Brand,
32
32
  EmptyState,
33
+ RadioGroup,
34
+ PricingGroup,
35
+ PricingTable,
36
+ Dropdown,
37
+ Breadcrumb,
38
+ PageHead,
39
+ PageShell,
33
40
  createLazyResolver,
34
41
  } from "@elcrm/components";
42
+ import type { PricingPlan } from "@elcrm/components";
35
43
  // CSS подтягивается с чанками; при необходимости единый файл:
36
44
  // import "@elcrm/components/style.css";
37
45
  ```
@@ -41,6 +49,7 @@ import {
41
49
  ```ts
42
50
  import { Header } from "@elcrm/components/Header";
43
51
  import { Avatar } from "@elcrm/components/Avatar";
52
+ import { RadioGroup } from "@elcrm/components/RadioGroup";
44
53
  ```
45
54
 
46
55
  ## Компоненты
@@ -51,21 +60,391 @@ import { Avatar } from "@elcrm/components/Avatar";
51
60
  | **Header** | Шапка со слотами | `brand`, `nav`, `search`, `actions` |
52
61
  | **Footer** | Подвал | `children` |
53
62
  | **Brand** | Название / логотип | `as`, `children`, `onClick` |
54
- | **Avatar** | Фото или инициалы | `src`, `name`, `size`, `active`, `as` |
63
+ | **Avatar** | Фото или инициалы | `src`, `name` (инициалы), `size`, `status`, `as` |
64
+ | **AvatarName** | Аватар + title + description | `title`, `description`, `name?`, `size`, `status` |
65
+ | **AvatarGroup** | Стопка аватаров + «+N» | `items` (`value`/`title`/`name`), `max`, `add` |
55
66
  | **Badge** | Метка / статус | `tone`, `children` |
56
- | **Menu** | Навигация (не overlay) | `items`, `activeKey`, `vertical`, `onSelect` |
57
- | **Section** | Блок страницы / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant` |
58
- | **NavSections** | Сайдбар + lazy-панель | `groups`, `resolveSection`, `defaultActiveKey` |
59
- | **TabSections** | Горизонтальные вкладки + lazy | `items` (+ `badge`), `resolveSection` |
67
+ | **RadioGroup** | Выбор одной опции-карточки | `items`, `value`, `indicator`, `indicatorSide` |
68
+ | **PricingGroup** | Тарифные карточки в ряд | `items` (`PricingPlan`), `selectable`, `value` |
69
+ | **PricingTable** | Сравнение тарифов (таблица) | те же `items` + `sections` |
70
+ | **Menu** | Навигация в шапке (не popover) | `items` (`value`), `value`, `onSelect` |
71
+ | **Dropdown** | Выпадающее меню (items) | `label`/`trigger`, `items`/`groups`, `onSelect` |
72
+ | **Breadcrumb** | Хлебные крошки | `items`, `separator`, `collapseAfter` |
73
+ | **PageShell** | Каркас модуля (скролл + footer) | `wide`, `footer`, `children` |
74
+ | **PageHead** | Заголовок страницы + actions | `title`, `subtitle`, `actions` |
75
+ | **Section** | Блок контента / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant` |
76
+ | **NavSections** | Сайдбар + lazy-панель | `groups` (`value`), `resolveSection`, `defaultValue` |
77
+ | **TabSections** | Горизонтальные вкладки + lazy | `items` (`value` + `badge`), `resolveSection` |
60
78
  | **Card** | Карточка | `title`, `children` |
61
79
  | **List** / **Item** | Список и строка | List: `row`; Item: `as`, `active` |
62
- | **Block** / **Row** / **Column** | Стеки | `gap`; Block ещё `row` |
80
+ | **Stack** | Ряд / колонка | `direction`, `gap` |
63
81
  | **Loading** | Плейсхолдер загрузки | `children` |
64
82
  | **EmptyState** | Заглушка «нет данных» | `title`, `description`, `icon`, `actions` |
65
83
  | **createLazyResolver** | Кэш `import()` секций | `(key) => import(…)` |
66
84
 
67
85
  Слоты `Header` заполняет приложение: поиск — `@elcrm/search`, кнопки — `@elcrm/button`, и т.д.
68
86
 
87
+ `Block` / `Row` / `Column` — deprecated-обёртки над `Stack`. В проектах: `elcrm migrate components`.
88
+
89
+ ### Stack
90
+
91
+ ```tsx
92
+ <Stack gap="0.75rem">{/* колонка */}</Stack>
93
+ <Stack direction="row" gap={8}>{/* ряд */}</Stack>
94
+ ```
95
+
96
+ ### RadioGroup
97
+
98
+ Декларативно через `items` — всё из коробки. Нет поля → блок не рисуется.
99
+
100
+ ```tsx
101
+ const items = [
102
+ {
103
+ value: "basic",
104
+ icon: <LayersIcon />,
105
+ title: "Basic plan",
106
+ meta: "$10/month",
107
+ description: "Includes up to 10 users…",
108
+ },
109
+ {
110
+ value: "pro",
111
+ title: "Pro plan",
112
+ meta: "$20/month",
113
+ description: "Includes up to 20 users…",
114
+ },
115
+ {
116
+ value: "olivia",
117
+ icon: <Avatar name="Olivia Rhye" src="…" />,
118
+ iconFramed: false,
119
+ title: "Olivia Rhye",
120
+ meta: "@olivia",
121
+ description: "Product Manager",
122
+ },
123
+ {
124
+ value: "visa",
125
+ icon: <VisaLogo />,
126
+ title: "Visa ending in 1234",
127
+ description: "Expiry 06/2028",
128
+ actions: (
129
+ <>
130
+ <button type="button">Set as default</button>
131
+ <button type="button">Edit</button>
132
+ </>
133
+ ),
134
+ },
135
+ {
136
+ value: "enterprise",
137
+ variant: "split",
138
+ icon: <BoltIcon />,
139
+ title: "Enterprise plan",
140
+ price: "$40",
141
+ meta: "per month",
142
+ badge: <Badge tone="success">Limited time only</Badge>,
143
+ description: "Unlimited users…",
144
+ },
145
+ ];
146
+
147
+ <RadioGroup
148
+ items={items}
149
+ value={plan}
150
+ onValueChange={setPlan}
151
+ indicator="check"
152
+ />
153
+
154
+ {/* Круглый radio слева */}
155
+ <RadioGroup
156
+ items={items}
157
+ value={plan}
158
+ onValueChange={setPlan}
159
+ indicator="radio"
160
+ indicatorSide="start"
161
+ />
162
+ ```
163
+
164
+ ### PricingGroup / PricingTable
165
+
166
+ Один тип **`PricingPlan`** и один массив `plans` на оба компонента. Table только добавляет `sections` (матрица по `plan.value`).
167
+
168
+ ```tsx
169
+ import type { PricingPlan } from "@elcrm/components";
170
+
171
+ const plans: PricingPlan[] = [
172
+ {
173
+ value: "basic",
174
+ title: "Basic plan",
175
+ price: "$10",
176
+ meta: "per month",
177
+ description: "Basic features for up to 10 users.",
178
+ actions: (
179
+ <>
180
+ <button type="button">Get started</button>
181
+ <button type="button">Chat to sales</button>
182
+ </>
183
+ ),
184
+ actionsPlacement: "before",
185
+ featuresLabel: "FEATURES",
186
+ featuresSummary: "Everything in Starter plus…",
187
+ features: [
188
+ "Access to basic features",
189
+ "Basic reporting and analytics",
190
+ ],
191
+ },
192
+ {
193
+ value: "business",
194
+ title: "Business plan",
195
+ badge: "Popular",
196
+ badgePlacement: "pill",
197
+ highlighted: true,
198
+ price: "$20",
199
+ meta: "per month",
200
+ description: "Growing teams up to 20 users.",
201
+ actions: <button type="button">Get started</button>,
202
+ features: ["200+ integrations", "Advanced custom fields"],
203
+ },
204
+ {
205
+ value: "enterprise",
206
+ badge: "Most popular plan",
207
+ badgePlacement: "banner",
208
+ priceFirst: true,
209
+ price: "$40/mth",
210
+ title: "Enterprise plan",
211
+ description: "Advanced features + unlimited users.",
212
+ features: ["Audit log", "Data loss prevention"],
213
+ actions: <button type="button">Get started</button>,
214
+ },
215
+ ];
216
+
217
+ <PricingGroup items={plans} />
218
+ <PricingGroup items={plans} selectable value={plan} onValueChange={setPlan} />
219
+
220
+ const sections = [
221
+ {
222
+ title: "Overview",
223
+ rows: [
224
+ {
225
+ key: "basic",
226
+ label: "Basic features",
227
+ hint: "Core product features",
228
+ values: { basic: true, business: true, enterprise: true },
229
+ },
230
+ {
231
+ key: "users",
232
+ label: "Users",
233
+ values: { basic: "10", business: "20", enterprise: "Unlimited" },
234
+ },
235
+ ],
236
+ },
237
+ ];
238
+
239
+ <PricingTable items={plans} sections={sections} />
240
+ <PricingTable
241
+ items={plans}
242
+ sections={sections}
243
+ footerActions
244
+ selectable
245
+ value={plan}
246
+ onValueChange={setPlan}
247
+ />
248
+ ```
249
+
250
+ `true` → галочка, `false` / нет значения → «—», иначе текст/node.
251
+
252
+ ### PageShell / PageHead / Section
253
+
254
+ Три разных роли — не путать:
255
+
256
+ | | Роль |
257
+ | --- | --- |
258
+ | **PageShell** | Каркас модуля: скролл в body, опциональный footer снизу |
259
+ | **PageHead** | Строка title (+ subtitle) слева и actions справа |
260
+ | **Section** | Блок контента / auth-карточка / подраздел с title+description |
261
+
262
+ ```tsx
263
+ <PageShell footer={<button type="button">Сохранить</button>}>
264
+ <PageHead title="Товары" subtitle="Каталог" actions={<button>Добавить</button>} />
265
+ <Section title="Фильтры">{/* … */}</Section>
266
+ </PageShell>
267
+ ```
268
+
269
+ ### AvatarGroup
270
+
271
+ Стопка аватаров через `items`:
272
+
273
+ ```tsx
274
+ const people = [
275
+ { value: "1", src: "/a.jpg", name: "Anna" },
276
+ { value: "2", name: "Boris" },
277
+ { value: "3", src: "/c.jpg", name: "Clara" },
278
+ // …
279
+ ];
280
+
281
+ <AvatarGroup items={people} size="s" max={5} />
282
+ <AvatarGroup items={people} size="m" max={5} add onAdd={() => {}} />
283
+ <AvatarGroup
284
+ items={people}
285
+ size="l"
286
+ max={5}
287
+ add
288
+ onAdd={() => {}}
289
+ onItemClick={(item) => console.log(item)}
290
+ />
291
+ ```
292
+
293
+ `max` — сколько показать; остаток → «+N». `add` — кнопка «+» справа.
294
+
295
+ ### Avatar / AvatarName
296
+
297
+ Канон: у текста — `title` + `description`; `name` — только для инициалов (если нет `src`).
298
+
299
+ ```tsx
300
+ <Avatar src="/a.jpg" name="Olivia" size="m" status="online" />
301
+ <Avatar name="Olivia Rhye" size="l" status="offline" />
302
+
303
+ <AvatarName
304
+ src="/a.jpg"
305
+ title="Olivia Rhye"
306
+ description="olivia@untitledui.com"
307
+ size="m"
308
+ status="online"
309
+ />
310
+
311
+ {/* name — инициалы; title — подпись */}
312
+ <AvatarName
313
+ as="button"
314
+ name="Olivia Rhye"
315
+ title="Olivia Rhye"
316
+ description="Product Manager"
317
+ size="s"
318
+ onClick={() => {}}
319
+ />
320
+ ```
321
+
322
+ ### Dropdown
323
+
324
+ Выпадающее меню через `items` или `groups` (разделители между группами):
325
+
326
+ ```tsx
327
+ <Dropdown
328
+ label="Account"
329
+ align="end"
330
+ groups={[
331
+ {
332
+ items: [
333
+ { value: "cut", label: "Cut", shortcut: "⌘X" },
334
+ { value: "copy", label: "Copy", shortcut: "⌘C" },
335
+ { value: "paste", label: "Paste", shortcut: "⌘V" },
336
+ ],
337
+ },
338
+ {
339
+ items: [
340
+ { value: "edit", label: "Edit" },
341
+ { value: "dup", label: "Duplicate" },
342
+ { value: "del", label: "Delete", danger: true },
343
+ ],
344
+ },
345
+ {
346
+ items: [
347
+ { value: "details", label: "View details", submenu: true },
348
+ ],
349
+ },
350
+ ]}
351
+ onSelect={(value) => console.log(value)}
352
+ />
353
+
354
+ {/* Выбор с галочкой */}
355
+ <Dropdown
356
+ label="Can edit"
357
+ items={[
358
+ { value: "owner", label: "Owner" },
359
+ { value: "edit", label: "Can edit", checked: true },
360
+ { value: "view", label: "Can view" },
361
+ ]}
362
+ />
363
+
364
+ {/* Иконки, статус, submenu */}
365
+ <Dropdown
366
+ label="Actions"
367
+ groups={[
368
+ {
369
+ items: [
370
+ { value: "back", label: "Back", icon: <BackIcon /> },
371
+ { value: "reload", label: "Reload", icon: <ReloadIcon />, shortcut: "⌘R" },
372
+ ],
373
+ },
374
+ {
375
+ items: [
376
+ { value: "bm", label: "Show bookmarks", checked: true },
377
+ { value: "url", label: "Show full URLs" },
378
+ ],
379
+ },
380
+ {
381
+ items: [
382
+ { value: "o", label: "Olivia Rhye", status: "online" },
383
+ { value: "s", label: "Sienna Hewitt", status: "offline" },
384
+ ],
385
+ },
386
+ {
387
+ items: [
388
+ { value: "more", label: "More tools", icon: <CubeIcon />, submenu: true },
389
+ ],
390
+ },
391
+ ]}
392
+ />
393
+
394
+ {/* Колонки: checkbox, title, не закрывать при клике */}
395
+ <Dropdown
396
+ trigger={<button type="button">⚙</button>}
397
+ title="Колонки в списке"
398
+ closeOnSelect={false}
399
+ items={[
400
+ { value: "photo", label: "Фото", checkbox: true, checked: true },
401
+ { value: "sku", label: "SKU", checkbox: true, checked: true, disabled: true },
402
+ { value: "brand", label: "Бренд", checkbox: true, checked: false },
403
+ ]}
404
+ onSelect={(value) => toggleColumn(value)}
405
+ />
406
+ ```
407
+
408
+ `Menu` — навигация в шапке (inline, не popover).
409
+
410
+ **Dropdown vs `@elcrm/overlay`:** в пакете `Dropdown` — готовое меню по `items`/`groups` (контент + поведение выбора). `@elcrm/overlay` — portal, позиционирование и z-index стек, когда нужен свой попап или общий слой поверх страницы. Не смешивать: для типового меню пунктов — `Dropdown`; для кастомного портала — overlay.
411
+
412
+ ### Breadcrumb
413
+
414
+ ```tsx
415
+ <Breadcrumb
416
+ separator="chevron" // или "slash"
417
+ items={[
418
+ { value: "home", icon: <HomeIcon />, href: "/" },
419
+ { value: "settings", label: "Settings", href: "/settings" },
420
+ { value: "team", label: "Team" }, // текущий — последний
421
+ ]}
422
+ />
423
+
424
+ {/* Иконка + avatar + dropdown */}
425
+ <Breadcrumb
426
+ items={[
427
+ { value: "org", icon: <Logo />, label: "Warpspeed", href: "/" },
428
+ {
429
+ value: "user",
430
+ icon: <Avatar src="…" name="Caitlyn" size="s" />,
431
+ label: "Caitlyn King",
432
+ dropdown: true,
433
+ onClick: () => openSwitcher(),
434
+ },
435
+ { value: "settings", label: "Settings" },
436
+ ]}
437
+ />
438
+
439
+ {/* Длинный путь → первые 2, …, последний */}
440
+ <Breadcrumb
441
+ collapseAfter={2}
442
+ separator="slash"
443
+ items={longPath}
444
+ onEllipsisClick={() => {}}
445
+ />
446
+ ```
447
+
69
448
  ## Пример
70
449
 
71
450
  ```tsx
@@ -73,7 +452,7 @@ import { Avatar } from "@elcrm/components/Avatar";
73
452
  header={
74
453
  <Header
75
454
  brand={<Brand onClick={() => {}}>App</Brand>}
76
- nav={<Menu items={[{ key: "home", label: "Главная", active: true }]} />}
455
+ nav={<Menu items={[{ value: "home", label: "Главная", active: true }]} />}
77
456
  actions={
78
457
  <>
79
458
  <Avatar as="button" name="Admin" />
@@ -108,17 +487,17 @@ import { Avatar } from "@elcrm/components/Avatar";
108
487
  {
109
488
  /* Настройки: меню слева + sections/*.tsx справа */
110
489
  }
111
- const resolve = createLazyResolver((key) => import(`./sections/${key}.tsx`));
490
+ const resolve = createLazyResolver((value) => import(`./sections/${value}.tsx`));
112
491
 
113
492
  <NavSections
114
- defaultActiveKey="Profile"
493
+ defaultValue="Profile"
115
494
  resolveSection={resolve}
116
495
  groups={[
117
496
  {
118
497
  label: "Личное",
119
498
  items: [
120
- { key: "Profile", label: "Профиль" },
121
- { key: "Appearance", label: "Оформление" },
499
+ { value: "Profile", label: "Профиль" },
500
+ { value: "Appearance", label: "Оформление" },
122
501
  ],
123
502
  },
124
503
  ]}
@@ -132,11 +511,11 @@ const resolve = createLazyResolver((key) => import(`./sections/${key}.tsx`));
132
511
  ```tsx
133
512
  <Section title="Дети" description="Список">
134
513
  <TabSections
135
- defaultActiveKey="News"
136
- resolveSection={createLazyResolver((k) => import(`./sections/${k}.tsx`))}
514
+ defaultValue="News"
515
+ resolveSection={createLazyResolver((v) => import(`./sections/${v}.tsx`))}
137
516
  items={[
138
- { key: "News", label: "Новые", badge: 1 },
139
- { key: "Active", label: "Активные" },
517
+ { value: "News", label: "Новые", badge: 1 },
518
+ { value: "Active", label: "Активные" },
140
519
  ]}
141
520
  />
142
521
  </Section>
@@ -144,208 +523,77 @@ const resolve = createLazyResolver((key) => import(`./sections/${key}.tsx`));
144
523
 
145
524
  ## CSS-токены
146
525
 
147
- Тема приложения объявляет **все** переменные (fallback в пакете нет).
148
- Эталон: panel `theme.css` (геометрия) + `theme-light` / `theme-dark` (цвета).
526
+ Как в `@elcrm/form`: сначала **общие**, потом узкие.
149
527
 
150
- **layout** · Loading
528
+ | Слой | Где | Примеры |
529
+ | ---- | --- | ------- |
530
+ | Палитра | theme-light / dark | `--text`, `--muted`, `--line`, `--panel`, `--accent`, `--shadow` |
531
+ | Control | theme.css | `--control-height`, `--control-radius`, `--control-font-size` |
532
+ | **Shell** | theme.css + light/dark | `--shell-*` — общие для Dropdown, RadioGroup, Pricing*, Breadcrumb, AvatarName… |
533
+ | Popover | light/dark | `--popup-shadow` (общий с form) |
534
+ | Узкие | theme.css | `--header-height`, `--avatar-size-*`, `--dropdown-min-width`, `--pricing-card-min-width`… |
151
535
 
152
- ```
153
- --layout-background
154
- --layout-gap
155
- --layout-min-height
156
- --loading-color
157
- --loading-padding
158
- ```
536
+ Задай `--shell-*` один раз — большинство новых компонентов подхватят.
159
537
 
160
- **header**
538
+ **shell (геометрия → theme.css)**
161
539
 
162
540
  ```
163
- --header-background
164
- --header-border
165
- --header-color
166
- --header-gap
167
- --header-height
168
- --header-margin
169
- --header-padding
170
- --header-radius
171
- --header-shadow
172
- --header-z
541
+ --shell-radius (= --control-radius)
542
+ --shell-font-size (= --control-font-size)
543
+ --shell-font-size-sm
544
+ --shell-font-size-lg
545
+ --shell-font-weight
546
+ --shell-gap / -sm / -lg
547
+ --shell-padding (или -block / -inline)
548
+ --shell-icon-size
549
+ --shell-check-size
550
+ --shell-status-size
551
+ --shell-disabled-opacity
552
+ --shell-z
173
553
  ```
174
554
 
175
- **footer**
555
+ **shell (цвет → light / dark, обычно алиасы палитры)**
176
556
 
177
557
  ```
178
- --footer-background
179
- --footer-border
180
- --footer-color
181
- --footer-font-size
182
- --footer-padding
558
+ --shell-color (= --text)
559
+ --shell-color-muted (= --muted)
560
+ --shell-color-accent (= --accent)
561
+ --shell-color-danger
562
+ --shell-color-success
563
+ --shell-color-warning
564
+ --shell-border (= --line, только цвет)
565
+ --shell-background (= --panel)
566
+ --shell-background-muted / -hover / -selected
567
+ --shell-shadow
183
568
  ```
184
569
 
185
- **list** · Item
570
+ **Узкие (только если нужно иначе)**
186
571
 
187
572
  ```
188
- --list-gap
189
- --list-padding
190
- --item-background
191
- --item-background-active
192
- --item-background-hover
193
- --item-border
194
- --item-color
195
- --item-gap
196
- --item-padding
197
- --item-radius
573
+ --header-height / --header-z / --header-margin / --header-shadow / --header-radius
574
+ --section-padding / --section-title-size / --section-title-size-md / --section-auth-card-max-width
575
+ --nav-sections-padding / --nav-sections-nav-width / --nav-sections-main-max-width
576
+ --avatar-size-s|m|l / --avatar-group-overlap
577
+ --dropdown-min-width / --dropdown-max-width / --dropdown-max-height
578
+ --pricing-card-min-width / --pricing-table-label-width
579
+ --row-gap / --column-gap
580
+ --popup-shadow
198
581
  ```
199
582
 
200
- **card** · Block · Row · Column
201
-
202
- ```
203
- --card-background
204
- --card-border
205
- --card-padding
206
- --card-radius
207
- --card-shadow
208
- --block-gap
209
- --block-padding
210
- --row-gap
211
- --column-gap
212
- ```
583
+ Эталон геометрии+shell: panel `theme.css`. Цвета: `theme-light` / `theme-dark`.
584
+ В пакете: `tokens.css` / `light.css` / `dark.css` — дефолты для `elcrm css`.
213
585
 
214
- **menu**
586
+ ## Миграция в приложениях
215
587
 
216
- ```
217
- --menu-gap
218
- --menu-item-background
219
- --menu-item-background-active
220
- --menu-item-background-hover
221
- --menu-item-color
222
- --menu-item-color-active
223
- --menu-item-padding
224
- --menu-item-radius
225
- ```
226
-
227
- **section**
228
-
229
- ```
230
- --section-padding
231
- --section-gap
232
- --section-title-color
233
- --section-title-size
234
- --section-title-size-md
235
- --section-description-color
236
- --section-description-size
237
- --section-icon-gap
238
- --section-body-gap
239
- --section-actions-gap
240
- --section-auth-padding
241
- --section-auth-card-background
242
- --section-auth-card-border
243
- --section-auth-card-max-width
244
- --section-auth-card-padding
245
- --section-auth-card-radius
246
- --section-auth-card-shadow
247
- --section-block-border
248
- --section-block-margin-bottom
249
- --section-block-padding-bottom
250
- ```
251
-
252
- **nav-sections**
253
-
254
- ```
255
- --nav-sections-padding
256
- --nav-sections-gap
257
- --nav-sections-nav-width
258
- --nav-sections-main-max-width
259
- --nav-sections-label-color
260
- --nav-sections-item-color
261
- --nav-sections-item-background-hover
262
- --nav-sections-item-background-active
263
- --nav-sections-item-padding
264
- --nav-sections-item-radius
265
- --nav-sections-accent
266
- --nav-sections-icon-color
267
- --nav-sections-group-border
268
- --nav-sections-footer-border
269
- ```
270
-
271
- **tab-sections**
272
-
273
- ```
274
- --tab-sections-gap
275
- --tab-sections-border
276
- --tab-sections-color
277
- --tab-sections-color-active
278
- --tab-sections-accent
279
- --tab-sections-tab-gap
280
- --tab-sections-tab-padding
281
- --tab-sections-badge-background
282
- --tab-sections-badge-color
283
- --tab-sections-badge-size
284
- ```
285
-
286
- **avatar**
287
-
288
- ```
289
- --avatar-size-s
290
- --avatar-size-m
291
- --avatar-size-l
292
- --avatar-radius
293
- --avatar-font-size-s
294
- --avatar-font-size-m
295
- --avatar-font-size-l
296
- --avatar-font-weight
297
- --avatar-background
298
- --avatar-color
299
- --avatar-border
300
- --avatar-outline-active
301
- --avatar-outline-offset
302
- ```
303
-
304
- **badge**
305
-
306
- ```
307
- --badge-padding
308
- --badge-radius
309
- --badge-font-size
310
- --badge-font-weight
311
- --badge-border
312
- --badge-neutral-background
313
- --badge-neutral-color
314
- --badge-accent-background
315
- --badge-accent-color
316
- --badge-success-background
317
- --badge-success-color
318
- --badge-warning-background
319
- --badge-warning-color
320
- --badge-danger-background
321
- --badge-danger-color
322
- ```
323
-
324
- **brand**
325
-
326
- ```
327
- --brand-font-weight
328
- --brand-letter-spacing
329
- --brand-color
330
- --brand-color-hover
588
+ ```bash
589
+ elcrm update --fix --test # включает migrate components
590
+ # или точечно:
591
+ elcrm migrate components
592
+ elcrm css
593
+ elcrm docs && elcrm cursor
331
594
  ```
332
595
 
333
- **empty-state**
334
-
335
- ```
336
- --empty-state-gap
337
- --empty-state-padding
338
- --empty-state-icon-gap
339
- --empty-state-title-size
340
- --empty-state-description-size
341
- --empty-state-max-width
342
- --empty-state-actions-gap
343
- --empty-state-actions-margin-top
344
- --empty-state-color
345
- --empty-state-icon-color
346
- --empty-state-title-color
347
- --empty-state-description-color
348
- ```
596
+ Пилюля `components`: Block/Row/Column → Stack; `key`/`activeKey` → `value`; старые `--item-*` / `--menu-*` / … → `--shell-*`.
349
597
 
350
598
  ## Лицензия
351
599