@elcrm/components 0.0.1 → 0.1.0
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 +450 -202
- package/dist/Avatar-Jzan87XD.js +101 -0
- package/dist/Avatar.css +1 -1
- package/dist/Avatar.d.ts +81 -2
- package/dist/Avatar.js +1 -1
- package/dist/AvatarGroup-DUe7-T3B.js +81 -0
- package/dist/AvatarGroup.css +1 -0
- package/dist/AvatarGroup.d.ts +77 -0
- package/dist/AvatarGroup.js +4 -0
- package/dist/AvatarName-KBbQrVta.js +56 -0
- package/dist/AvatarName.css +1 -0
- package/dist/AvatarName.d.ts +76 -0
- package/dist/AvatarName.js +4 -0
- package/dist/Badge.css +1 -1
- package/dist/Badge.d.ts +26 -2
- package/dist/Block-BAXh0PPp.js +8 -0
- package/dist/Block.d.ts +30 -2
- package/dist/Block.js +1 -1
- package/dist/Brand.css +1 -1
- package/dist/Brand.d.ts +37 -2
- package/dist/Breadcrumb-D0wXkE38.js +98 -0
- package/dist/Breadcrumb.css +1 -0
- package/dist/Breadcrumb.d.ts +80 -0
- package/dist/Breadcrumb.js +4 -0
- package/dist/Card.css +1 -1
- package/dist/Card.d.ts +28 -2
- package/dist/Column-DDaqX-A7.js +8 -0
- package/dist/Column.d.ts +24 -2
- package/dist/Column.js +1 -1
- package/dist/Dropdown-Cw5LKpcT.js +168 -0
- package/dist/Dropdown.css +1 -0
- package/dist/Dropdown.d.ts +124 -0
- package/dist/Dropdown.js +4 -0
- package/dist/EmptyState.css +1 -1
- package/dist/EmptyState.d.ts +36 -2
- package/dist/Footer.css +1 -1
- package/dist/Footer.d.ts +25 -2
- package/dist/Header.css +1 -1
- package/dist/Header.d.ts +36 -2
- package/dist/Item.css +1 -1
- package/dist/Item.d.ts +42 -2
- package/dist/Layout.css +1 -1
- package/dist/Layout.d.ts +30 -2
- package/dist/List.css +1 -1
- package/dist/List.d.ts +29 -2
- package/dist/Loading.css +1 -1
- package/dist/Loading.d.ts +24 -2
- package/dist/Menu-DRBHvSdJ.js +40 -0
- package/dist/Menu.css +1 -1
- package/dist/Menu.d.ts +78 -2
- package/dist/Menu.js +1 -1
- package/dist/{NavSections-CM-VPai2.js → NavSections-NDcIDD6H.js} +26 -26
- package/dist/NavSections.css +1 -1
- package/dist/NavSections.d.ts +101 -2
- package/dist/NavSections.js +1 -1
- package/dist/PageHead-Baz9BLuA.js +22 -0
- package/dist/PageHead.css +1 -0
- package/dist/PageHead.d.ts +36 -0
- package/dist/PageHead.js +4 -0
- package/dist/PageShell-CghThHS3.js +28 -0
- package/dist/PageShell.css +1 -0
- package/dist/PageShell.d.ts +33 -0
- package/dist/PageShell.js +4 -0
- package/dist/PricingGroup-CiqQtzjd.js +126 -0
- package/dist/PricingGroup.css +1 -0
- package/dist/PricingGroup.d.ts +130 -0
- package/dist/PricingGroup.js +4 -0
- package/dist/PricingTable-DYTJG4AU.js +158 -0
- package/dist/PricingTable.css +1 -0
- package/dist/PricingTable.d.ts +108 -0
- package/dist/PricingTable.js +4 -0
- package/dist/RadioGroup-DxoPHPIF.js +138 -0
- package/dist/RadioGroup.css +1 -0
- package/dist/RadioGroup.d.ts +111 -0
- package/dist/RadioGroup.js +4 -0
- package/dist/Row--HIe6vb9.js +8 -0
- package/dist/Row.d.ts +24 -2
- package/dist/Row.js +1 -1
- package/dist/Section.css +1 -1
- package/dist/Section.d.ts +49 -2
- package/dist/Stack-b0-XWwQ1.js +31 -0
- package/dist/Stack.css +1 -0
- package/dist/Stack.d.ts +34 -0
- package/dist/Stack.js +4 -0
- package/dist/TabSections-DL7DufKU.js +50 -0
- package/dist/TabSections.css +1 -1
- package/dist/TabSections.d.ts +87 -2
- package/dist/TabSections.js +1 -1
- package/dist/cx.d.ts +8 -1
- package/dist/dark.css +24 -0
- package/dist/index.css +32 -18
- package/dist/index.d.ts +21 -1
- package/dist/index.es.js +58 -38
- package/dist/lazyRoute.d.ts +19 -3
- package/dist/light.css +25 -0
- package/dist/stackGap.d.ts +13 -1
- package/dist/tokens.css +57 -0
- package/package.json +33 -6
- package/dist/Avatar-DHNPaIjZ.js +0 -64
- package/dist/Block-CVKukh1e.js +0 -28
- package/dist/Block.css +0 -1
- package/dist/Column-DlNrvFq1.js +0 -26
- package/dist/Column.css +0 -1
- package/dist/Menu-DS7zKQbY.js +0 -40
- package/dist/Row-CnD7Q7pD.js +0 -20
- package/dist/Row.css +0 -1
- package/dist/TabSections-oeEBx0nM.js +0 -50
- 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`, `
|
|
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
|
-
|
|
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
|
|
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
|
-
| **
|
|
57
|
-
| **
|
|
58
|
-
| **
|
|
59
|
-
| **
|
|
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
|
-
| **
|
|
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={[{
|
|
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((
|
|
490
|
+
const resolve = createLazyResolver((value) => import(`./sections/${value}.tsx`));
|
|
112
491
|
|
|
113
492
|
<NavSections
|
|
114
|
-
|
|
493
|
+
defaultValue="Profile"
|
|
115
494
|
resolveSection={resolve}
|
|
116
495
|
groups={[
|
|
117
496
|
{
|
|
118
497
|
label: "Личное",
|
|
119
498
|
items: [
|
|
120
|
-
{
|
|
121
|
-
{
|
|
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
|
-
|
|
136
|
-
resolveSection={createLazyResolver((
|
|
514
|
+
defaultValue="News"
|
|
515
|
+
resolveSection={createLazyResolver((v) => import(`./sections/${v}.tsx`))}
|
|
137
516
|
items={[
|
|
138
|
-
{
|
|
139
|
-
{
|
|
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
|
-
|
|
148
|
-
Эталон: panel `theme.css` (геометрия) + `theme-light` / `theme-dark` (цвета).
|
|
526
|
+
Как в `@elcrm/form`: сначала **общие**, потом узкие.
|
|
149
527
|
|
|
150
|
-
|
|
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
|
-
**
|
|
538
|
+
**shell (геометрия → theme.css)**
|
|
161
539
|
|
|
162
540
|
```
|
|
163
|
-
--
|
|
164
|
-
--
|
|
165
|
-
--
|
|
166
|
-
--
|
|
167
|
-
--
|
|
168
|
-
--
|
|
169
|
-
--
|
|
170
|
-
--
|
|
171
|
-
--
|
|
172
|
-
--
|
|
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
|
-
**
|
|
555
|
+
**shell (цвет → light / dark, обычно алиасы палитры)**
|
|
176
556
|
|
|
177
557
|
```
|
|
178
|
-
--
|
|
179
|
-
--
|
|
180
|
-
--
|
|
181
|
-
--
|
|
182
|
-
--
|
|
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
|
-
|
|
570
|
+
**Узкие (только если нужно иначе)**
|
|
186
571
|
|
|
187
572
|
```
|
|
188
|
-
--
|
|
189
|
-
--
|
|
190
|
-
--
|
|
191
|
-
--
|
|
192
|
-
--
|
|
193
|
-
--
|
|
194
|
-
--
|
|
195
|
-
--
|
|
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
|
-
|
|
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
|
-
|
|
586
|
+
## Миграция в приложениях
|
|
215
587
|
|
|
216
|
-
```
|
|
217
|
-
--
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
|