@elcrm/components 0.1.1 → 0.1.2

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 (94) hide show
  1. package/README.md +66 -16
  2. package/dist/ActionGroup-ChKFW0mt.js +27 -0
  3. package/dist/ActionGroup.css +1 -0
  4. package/dist/ActionGroup.d.ts +42 -0
  5. package/dist/ActionGroup.js +4 -0
  6. package/dist/Avatar-loGgFt72.js +113 -0
  7. package/dist/Avatar.d.ts +9 -1
  8. package/dist/Avatar.js +3 -2
  9. package/dist/{AvatarGroup-BAWas4pU.js → AvatarGroup-D1gnT3Od.js} +1 -1
  10. package/dist/AvatarGroup.js +1 -1
  11. package/dist/AvatarName-C1sIDPH-.js +66 -0
  12. package/dist/AvatarName.css +1 -1
  13. package/dist/AvatarName.d.ts +4 -1
  14. package/dist/AvatarName.js +1 -1
  15. package/dist/Badge-jp-9iNNL.js +28 -0
  16. package/dist/Badge.css +1 -1
  17. package/dist/Badge.d.ts +32 -17
  18. package/dist/Badge.js +1 -1
  19. package/dist/{Block-BAXh0PPp.js → Block-Bu7NEA0g.js} +1 -1
  20. package/dist/Block.js +1 -1
  21. package/dist/Card.css +1 -1
  22. package/dist/Card.d.ts +8 -1
  23. package/dist/{Column-DDaqX-A7.js → Column-BiogBDf8.js} +1 -1
  24. package/dist/Column.js +1 -1
  25. package/dist/Dropdown-CQBMF9aR.js +151 -0
  26. package/dist/Dropdown.css +1 -1
  27. package/dist/Dropdown.d.ts +3 -3
  28. package/dist/Dropdown.js +1 -1
  29. package/dist/Item-D4okhsfW.js +46 -0
  30. package/dist/Item.css +1 -1
  31. package/dist/Item.d.ts +8 -1
  32. package/dist/Item.js +1 -1
  33. package/dist/ItemColumn-M7a9L8CI.js +41 -0
  34. package/dist/ItemColumn.css +1 -0
  35. package/dist/ItemColumn.d.ts +61 -0
  36. package/dist/ItemColumn.js +4 -0
  37. package/dist/Layout-BQwEaeO0.js +22 -0
  38. package/dist/Layout.css +1 -1
  39. package/dist/Layout.d.ts +10 -5
  40. package/dist/Layout.js +1 -1
  41. package/dist/Menu-DpUvOl8Y.js +58 -0
  42. package/dist/Menu.css +1 -1
  43. package/dist/Menu.d.ts +15 -3
  44. package/dist/Menu.js +1 -1
  45. package/dist/PageHead-DgaJ1mXY.js +31 -0
  46. package/dist/PageHead.css +1 -1
  47. package/dist/PageHead.d.ts +28 -6
  48. package/dist/PageHead.js +1 -1
  49. package/dist/{PageShell-CghThHS3.js → PageShell-D9EZiO8o.js} +13 -11
  50. package/dist/PageShell.css +1 -1
  51. package/dist/PageShell.d.ts +11 -6
  52. package/dist/PageShell.js +1 -1
  53. package/dist/Popover-g2xTGubK.js +123 -0
  54. package/dist/Popover.css +1 -0
  55. package/dist/Popover.d.ts +54 -0
  56. package/dist/Popover.js +4 -0
  57. package/dist/{Row--HIe6vb9.js → Row-DsQOVn18.js} +1 -1
  58. package/dist/Row.js +1 -1
  59. package/dist/Sidebar-DeqxYgxn.js +69 -0
  60. package/dist/Sidebar.css +1 -0
  61. package/dist/Sidebar.d.ts +83 -0
  62. package/dist/Sidebar.js +4 -0
  63. package/dist/Stack-XkmPSswj.js +53 -0
  64. package/dist/Stack.css +1 -1
  65. package/dist/Stack.d.ts +16 -4
  66. package/dist/Stack.js +3 -2
  67. package/dist/Stat-C5iZyEoo.js +27 -0
  68. package/dist/Stat.css +1 -0
  69. package/dist/Stat.d.ts +39 -0
  70. package/dist/Stat.js +4 -0
  71. package/dist/{TabSections-DL7DufKU.js → TabSections-Bf_sZo7b.js} +1 -1
  72. package/dist/TabSections.js +1 -1
  73. package/dist/TextGroup-DmhuyMR1.js +23 -0
  74. package/dist/TextGroup.css +1 -0
  75. package/dist/TextGroup.d.ts +35 -0
  76. package/dist/TextGroup.js +4 -0
  77. package/dist/dark.css +10 -0
  78. package/dist/index.css +22 -10
  79. package/dist/index.d.ts +17 -3
  80. package/dist/index.es.d.ts +73 -0
  81. package/dist/index.es.js +76 -59
  82. package/dist/light.css +10 -0
  83. package/dist/overlayZ.d.ts +9 -0
  84. package/dist/tokens.css +19 -0
  85. package/package.json +2 -2
  86. package/dist/Avatar-CyNXYvsa.js +0 -101
  87. package/dist/AvatarName-DhD3TytF.js +0 -56
  88. package/dist/Badge-l6nUkl-H.js +0 -22
  89. package/dist/Dropdown-DQlDiWCR.js +0 -168
  90. package/dist/Item-CaU4RW2G.js +0 -38
  91. package/dist/Layout-Xb3-xsmA.js +0 -18
  92. package/dist/Menu-DRBHvSdJ.js +0 -40
  93. package/dist/PageHead-Baz9BLuA.js +0 -22
  94. package/dist/Stack-b0-XWwQ1.js +0 -31
package/README.md CHANGED
@@ -17,7 +17,11 @@ import {
17
17
  Footer,
18
18
  List,
19
19
  Item,
20
+ ItemColumn,
20
21
  Card,
22
+ ActionGroup,
23
+ TextGroup,
24
+ Stat,
21
25
  Stack,
22
26
  Menu,
23
27
  Loading,
@@ -37,6 +41,8 @@ import {
37
41
  Breadcrumb,
38
42
  PageHead,
39
43
  PageShell,
44
+ Sidebar,
45
+ Popover,
40
46
  createLazyResolver,
41
47
  } from "@elcrm/components";
42
48
  import type { PricingPlan } from "@elcrm/components";
@@ -56,28 +62,34 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
56
62
 
57
63
  | | Назначение | Ключевые props |
58
64
  | -------------------------------- | -------------------------------- | ---------------------------------------------------- |
59
- | **Layout** | Оболочка страницы | `header`, `footer`, `children` |
65
+ | **Layout** | Оболочка страницы | `sidebar`, `header`, `footer`, `children` |
60
66
  | **Header** | Шапка со слотами | `brand`, `nav`, `search`, `actions` |
61
67
  | **Footer** | Подвал | `children` |
62
68
  | **Brand** | Название / логотип | `as`, `children`, `onClick` |
63
- | **Avatar** | Фото или инициалы | `src`, `name` (инициалы), `size`, `status`, `as` |
64
- | **AvatarName** | Аватар + title + description | `title`, `description`, `name?`, `size`, `status` |
69
+ | **Avatar** | Фото или инициалы | `src`, `name`, `size`, `radius`, `status`, `as` |
70
+ | **AvatarName** | Аватар + title + description | `title`, `description`, `radius`, `--avatar-name-*-color` |
65
71
  | **AvatarGroup** | Стопка аватаров + «+N» | `items` (`value`/`title`/`name`), `max`, `add` |
66
- | **Badge** | Метка / статус | `tone`, `children` |
72
+ | **Badge** | Метка / статус | `tone`, `size`, `dot`, `children` |
67
73
  | **RadioGroup** | Выбор одной опции-карточки | `items`, `value`, `indicator`, `indicatorSide` |
68
74
  | **PricingGroup** | Тарифные карточки в ряд | `items` (`PricingPlan`), `selectable`, `value` |
69
75
  | **PricingTable** | Сравнение тарифов (таблица) | те же `items` + `sections` |
70
- | **Menu** | Навигация в шапке (не popover) | `items` (`value`), `value`, `onSelect` |
71
- | **Dropdown** | Выпадающее меню (items) | `label`/`trigger`, `items`/`groups`, `onSelect` |
76
+ | **Menu** | Навигация в шапке (не popover) | `items` (`value`, `badge`: `0` скрыт), `value`, `onSelect`, `variant` (`plain`/`line`) |
77
+ | **Dropdown** | Выпадающее меню (items, portal) | `label`/`trigger`, `items`/`groups`, `onSelect` |
78
+ | **Popover** | Свой попап в portal | `trigger`, `children`, `align`, `open` |
72
79
  | **Breadcrumb** | Хлебные крошки | `items`, `separator`, `collapseAfter` |
73
- | **PageShell** | Каркас модуля (скролл + footer) | `wide`, `footer`, `children` |
74
- | **PageHead** | Заголовок страницы + actions | `title`, `subtitle`, `actions` |
80
+ | **Sidebar** | Левое меню приложения | `groups`, `value`, `variant` (`cards`/`plain`) |
81
+ | **PageShell** | Каркас модуля (скролл + footer) | `wide`, `scroll`, `footer`, `children` |
82
+ | **PageHead** | Заголовок страницы + actions | `title`, `sup` (текст/Badge), `subtitle`, `actions`, `sticky`, `children` |
75
83
  | **Section** | Блок контента / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant` |
76
84
  | **NavSections** | Сайдбар + lazy-панель | `groups` (`value`), `resolveSection`, `defaultValue` |
77
85
  | **TabSections** | Горизонтальные вкладки + lazy | `items` (`value` + `badge`), `resolveSection` |
78
- | **Card** | Карточка | `title`, `children` |
79
- | **List** / **Item** | Список и строка | List: `row`; Item: `as`, `active` |
80
- | **Stack** | Ряд / колонка | `direction`, `gap` |
86
+ | **Card** | Карточка | `title`, `--card-pointer` |
87
+ | **ActionGroup** | Тулбар действий | `label`, `items` и/или `children` |
88
+ | **TextGroup** | Title + description | `title`, `description`, `size` |
89
+ | **ItemColumn** | Иконка + столбик в Item | `icon`, `title`, `extra`, `aside`, `description`, `footer` / `meta`, `unread` |
90
+ | **Stat** | Карточка-метрика | `label`, `value`, `tone`, `labelMuted` |
91
+ | **List** / **Item** | Список и строка | List: `row`; Item: `as`, `active`, `variant` (`plain`/`card`) |
92
+ | **Stack** | Ряд / колонка / сетка | `direction`, `columns` (N или `["1fr", "100px"]`), `gap` |
81
93
  | **Loading** | Плейсхолдер загрузки | `children` |
82
94
  | **EmptyState** | Заглушка «нет данных» | `title`, `description`, `icon`, `actions` |
83
95
  | **createLazyResolver** | Кэш `import()` секций | `(key) => import(…)` |
@@ -86,11 +98,45 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
86
98
 
87
99
  `Block` / `Row` / `Column` — deprecated-обёртки над `Stack`. В проектах: `elcrm migrate components`.
88
100
 
101
+ ### Sidebar
102
+
103
+ Левое меню приложения. `variant="cards"` — секции-карточки; `variant="plain"` — плоский список (backoffice). Иконки, колокольчик, тема, карточка пользователя — слоты приложения. Роутер не подключаем.
104
+
105
+ ```tsx
106
+ <Sidebar
107
+ variant="cards"
108
+ value={page}
109
+ onSelect={setPage}
110
+ brand={<Brand as="strong">App</Brand>}
111
+ extra={<Notifications.Bell />}
112
+ groups={[
113
+ { value: "main", items: [{ value: "home", label: "Обзор", icon: <Icon /> }] },
114
+ { value: "admin", title: "Админ", items: [{ value: "ops", label: "Операции" }] },
115
+ ]}
116
+ footer={<AvatarName title="Паша" description="mail@…" />}
117
+ version="v 0.2.26"
118
+ />
119
+ ```
120
+
121
+ Токены: `--sidebar-width`, `--sidebar-item-font-size`, `--sidebar-item-padding`, `--sidebar-icon-size`, `--sidebar-group-font-size`, `--sidebar-item-active`. Для orange active в `plain` переопределите `--sidebar-item-active` в теме приложения.
122
+
89
123
  ### Stack
90
124
 
91
125
  ```tsx
92
126
  <Stack gap="0.75rem">{/* колонка */}</Stack>
93
127
  <Stack direction="row" gap={8}>{/* ряд */}</Stack>
128
+ <Stack direction="grid" gap={16}>{/* auto-fit, мин. ширина --stack-grid-min */}</Stack>
129
+ <Stack direction="grid" columns={3} gap={12}>{/* stretch; не height:100% у детей */}</Stack>
130
+ ```
131
+
132
+ ### Card
133
+
134
+ Курсор задаёт приложение токеном `--card-pointer` (`auto` по умолчанию):
135
+
136
+ ```tsx
137
+ <Card title="Тенанты" style={{ ["--card-pointer" as string]: "pointer" }}>
138
+ 12
139
+ </Card>
94
140
  ```
95
141
 
96
142
  ### RadioGroup
@@ -255,13 +301,13 @@ const sections = [
255
301
 
256
302
  | | Роль |
257
303
  | --- | --- |
258
- | **PageShell** | Каркас модуля: скролл в body, опциональный footer снизу |
259
- | **PageHead** | Строка title (+ subtitle) слева и actions справа |
304
+ | **PageShell** | Каркас модуля: скролл в body (`scroll`, по умолчанию да), опциональный footer снизу |
305
+ | **PageHead** | Строка title (+ `sup` надстрочно, subtitle) слева и actions справа; `sticky` — прилипает к верху скролла |
260
306
  | **Section** | Блок контента / auth-карточка / подраздел с title+description |
261
307
 
262
308
  ```tsx
263
- <PageShell footer={<button type="button">Сохранить</button>}>
264
- <PageHead title="Товары" subtitle="Каталог" actions={<button>Добавить</button>} />
309
+ <PageShell scroll footer={<button type="button">Сохранить</button>}>
310
+ <PageHead sticky title="Товары" sup={12} subtitle="Каталог" actions={<button>Добавить</button>} />
265
311
  <Section title="Фильтры">{/* … */}</Section>
266
312
  </PageShell>
267
313
  ```
@@ -407,7 +453,7 @@ const people = [
407
453
 
408
454
  `Menu` — навигация в шапке (inline, не popover).
409
455
 
410
- **Dropdown vs `@elcrm/overlay`:** в пакете `Dropdown` — готовое меню по `items`/`groups` (контент + поведение выбора). `@elcrm/overlay` portal, позиционирование и z-index стек, когда нужен свой попап или общий слой поверх страницы. Не смешивать: для типового меню пунктов `Dropdown`; для кастомного портала — overlay.
456
+ **Dropdown vs Popover:** `Dropdown` — пункты `items`/`groups`. `Popover` свой `children` в portal (тот же z-стек, что у `@elcrm/form`). `@elcrm/overlay` `Menu` устаревший алиас `Popover`. Select`@elcrm/form`, не overlay.
411
457
 
412
458
  ### Breadcrumb
413
459
 
@@ -449,6 +495,7 @@ const people = [
449
495
 
450
496
  ```tsx
451
497
  <Layout
498
+ sidebar={<Sidebar groups={groups} value={page} onSelect={setPage} />}
452
499
  header={
453
500
  <Header
454
501
  brand={<Brand onClick={() => {}}>App</Brand>}
@@ -563,6 +610,7 @@ const resolve = createLazyResolver((value) => import(`./sections/${value}.tsx`))
563
610
  --shell-color-warning
564
611
  --shell-border (= --line, только цвет)
565
612
  --shell-background (= --panel)
613
+ --shell-bg фон страницы (sticky PageHead)
566
614
  --shell-background-muted / -hover / -selected
567
615
  --shell-shadow
568
616
  ```
@@ -576,6 +624,8 @@ const resolve = createLazyResolver((value) => import(`./sections/${value}.tsx`))
576
624
  --avatar-size-s|m|l / --avatar-group-overlap
577
625
  --dropdown-min-width / --dropdown-max-width / --dropdown-max-height
578
626
  --pricing-card-min-width / --pricing-table-label-width
627
+ --card-pointer
628
+ --stack-grid-min
579
629
  --row-gap / --column-gap
580
630
  --popup-shadow
581
631
  ```
@@ -0,0 +1,27 @@
1
+ import e from "react";
2
+ import { c as n } from "./cx-CcykAxZN.js";
3
+ import './ActionGroup.css';const s = "c5r", i = {
4
+ r: s
5
+ };
6
+ function p({
7
+ label: r,
8
+ items: o,
9
+ children: t,
10
+ className: a,
11
+ ...c
12
+ }) {
13
+ return /* @__PURE__ */ e.createElement(
14
+ "div",
15
+ {
16
+ className: n(i.r, a),
17
+ role: "toolbar",
18
+ "aria-label": r,
19
+ ...c
20
+ },
21
+ o,
22
+ t
23
+ );
24
+ }
25
+ export {
26
+ p as A
27
+ };
@@ -0,0 +1 @@
1
+ @layer elcrm-components{.c5r{display:flex;flex-wrap:nowrap;align-items:center;gap:var(--action-group-gap, var(--shell-gap-sm));flex:0 0 auto}}
@@ -0,0 +1,42 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Ряд действий в строке списка / карточке (`role="toolbar"`).
4
+ *
5
+ * Роли: тулбар иконок справа в Card. Кнопки — `@elcrm/button` / свои слоты,
6
+ * не нативный `<button>` в приложении.
7
+ *
8
+ * @param label подпись для `aria-label`
9
+ * @param items массив узлов (если нет — только `children`)
10
+ * @param children слот кнопок; можно вместе с `items` (сначала items)
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ActionGroup
15
+ * label="Действия: Иван"
16
+ * items={[
17
+ * <Button key="edit" variant="ghost" onClick={edit}>Изменить</Button>,
18
+ * <Button key="del" variant="ghost" onClick={remove}>Удалить</Button>,
19
+ * ]}
20
+ * />
21
+ *
22
+ * <ActionGroup label="Ещё">
23
+ * <Button variant="ghost">Копировать</Button>
24
+ * </ActionGroup>
25
+ * ```
26
+ *
27
+ * Токены: `--action-group-gap` (иначе `--shell-gap-sm`).
28
+ */
29
+ export type ActionGroupProps = React.HTMLAttributes<HTMLDivElement> & {
30
+ /** Подпись тулбара (`aria-label`) */
31
+ label: string;
32
+ /** Кнопки массивом узлов */
33
+ items?: React.ReactNode[];
34
+ /** Свои кнопки / слоты */
35
+ children?: React.ReactNode;
36
+ };
37
+ /**
38
+ * Группа действий: `items` и/или `children`.
39
+ *
40
+ * @see Card, Stack, Item
41
+ */
42
+ export declare function ActionGroup({ label, items, children, className, ...rest }: ActionGroupProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { A as p } from "./ActionGroup-ChKFW0mt.js";
2
+ export {
3
+ p as ActionGroup
4
+ };
@@ -0,0 +1,113 @@
1
+ import a from "react";
2
+ import { c as p } from "./cx-CcykAxZN.js";
3
+ import './Avatar.css';const h = "car", x = "cav", A = "cas", C = "cam", S = "cal", z = "caa", B = "cai", F = "cab", R = "cao", U = "caf", e = {
4
+ r: h,
5
+ v: x,
6
+ s: A,
7
+ m: C,
8
+ l: S,
9
+ a: z,
10
+ i: B,
11
+ b: F,
12
+ o: R,
13
+ f: U
14
+ };
15
+ function $(t) {
16
+ const n = t.trim();
17
+ if (!n) return "?";
18
+ const s = n.split(/\s+/).filter(Boolean);
19
+ return s.length >= 2 ? (s[0][0] + s[1][0]).toUpperCase() : n.slice(0, 2).toUpperCase();
20
+ }
21
+ function D(t) {
22
+ if (!(t == null || t === ""))
23
+ return {
24
+ "--avatar-radius": typeof t == "number" ? `${t}px` : t
25
+ };
26
+ }
27
+ function j({ status: t }) {
28
+ return /* @__PURE__ */ a.createElement(
29
+ "span",
30
+ {
31
+ className: p(e.b, t === "online" ? e.o : e.f),
32
+ "data-status": t,
33
+ "aria-hidden": !0
34
+ }
35
+ );
36
+ }
37
+ function k({
38
+ src: t,
39
+ label: n,
40
+ children: s,
41
+ name: c,
42
+ status: o
43
+ }) {
44
+ const l = t != null && t !== "" ? /* @__PURE__ */ a.createElement("img", { className: e.i, src: t, alt: n ?? "", draggable: !1 }) : s ?? (c != null ? $(c) : "?");
45
+ return /* @__PURE__ */ a.createElement(a.Fragment, null, /* @__PURE__ */ a.createElement("span", { className: e.v }, l), o != null ? /* @__PURE__ */ a.createElement(j, { status: o }) : null);
46
+ }
47
+ function G(t) {
48
+ const {
49
+ src: n,
50
+ alt: s,
51
+ name: c,
52
+ size: o = "m",
53
+ status: l,
54
+ active: i,
55
+ children: b,
56
+ className: y,
57
+ radius: E,
58
+ as: f = "span",
59
+ style: N,
60
+ ...m
61
+ } = t, g = o === "s" ? e.s : o === "l" ? e.l : e.m, u = p(e.r, g, i && e.a, y), r = s ?? c, d = { ...D(E), ...N }, v = /* @__PURE__ */ a.createElement(
62
+ k,
63
+ {
64
+ src: n,
65
+ label: r,
66
+ name: c,
67
+ status: l,
68
+ children: b
69
+ }
70
+ );
71
+ return f === "button" ? /* @__PURE__ */ a.createElement(
72
+ "button",
73
+ {
74
+ type: "button",
75
+ className: u,
76
+ "aria-label": r,
77
+ "data-active": i ? "true" : void 0,
78
+ "data-status": l,
79
+ style: d,
80
+ ...m
81
+ },
82
+ v
83
+ ) : f === "div" ? /* @__PURE__ */ a.createElement(
84
+ "div",
85
+ {
86
+ className: u,
87
+ role: r ? "img" : void 0,
88
+ "aria-label": r,
89
+ "data-active": i ? "true" : void 0,
90
+ "data-status": l,
91
+ style: d,
92
+ ...m
93
+ },
94
+ v
95
+ ) : /* @__PURE__ */ a.createElement(
96
+ "span",
97
+ {
98
+ className: u,
99
+ role: r ? "img" : void 0,
100
+ "aria-label": r,
101
+ "data-active": i ? "true" : void 0,
102
+ "data-status": l,
103
+ style: d,
104
+ ...m
105
+ },
106
+ v
107
+ );
108
+ }
109
+ export {
110
+ G as A,
111
+ D as a,
112
+ $ as i
113
+ };
package/dist/Avatar.d.ts CHANGED
@@ -30,11 +30,18 @@ type Common = {
30
30
  status?: AvatarStatus;
31
31
  /** Подсветка (например активный пункт шапки). */
32
32
  active?: boolean;
33
+ /**
34
+ * Скругление. Число — пиксели (`10` → `10px`), строка — любой CSS.
35
+ * Пишет `--avatar-radius` на корне (дефолт токена — круг, `999px`).
36
+ */
37
+ radius?: number | string;
33
38
  /** Кастомное содержимое вместо инициалов (если нет `src`). */
34
39
  children?: React.ReactNode;
35
40
  /** CSS-класс корня. */
36
41
  className?: string;
37
42
  };
43
+ /** Стиль `--avatar-radius` из пропа `radius`. */
44
+ export declare function avatarRadiusStyle(radius?: number | string): React.CSSProperties | undefined;
38
45
  /**
39
46
  * Props {@link Avatar}: корень как `button` | `span` | `div`.
40
47
  *
@@ -59,7 +66,8 @@ export type AvatarProps = (Common & React.ButtonHTMLAttributes<HTMLButtonElement
59
66
  * (`name` у Avatar остаётся только для инициалов);
60
67
  * - {@link AvatarGroup} — стопка аватаров из `items`.
61
68
  *
62
- * CSS-токены: `--avatar-*` (в т.ч. `--avatar-size-s|m|l`).
69
+ * CSS-токены: `--avatar-*` (в т.ч. `--avatar-size-s|m|l`, `--avatar-radius`).
70
+ * Скругление: `radius={10}` или `style={{ ["--avatar-radius"]: "10px" }}`.
63
71
  *
64
72
  * @example
65
73
  * ```tsx
package/dist/Avatar.js CHANGED
@@ -1,5 +1,6 @@
1
- import { A as r, i as m } from "./Avatar-CyNXYvsa.js";
1
+ import { A as r, a as s, i as t } from "./Avatar-loGgFt72.js";
2
2
  export {
3
3
  r as Avatar,
4
- m as initialsFromName
4
+ s as avatarRadiusStyle,
5
+ t as initialsFromName
5
6
  };
@@ -1,5 +1,5 @@
1
1
  import n from "react";
2
- import { A as f } from "./Avatar-CyNXYvsa.js";
2
+ import { A as f } from "./Avatar-loGgFt72.js";
3
3
  import { c as u } from "./cx-CcykAxZN.js";
4
4
  import './AvatarGroup.css';const G = "cyr", I = "cyi", M = "cyo", R = "cyd", S = "cys", j = "cym", q = "cyl", l = {
5
5
  r: G,
@@ -1,4 +1,4 @@
1
- import { A as o } from "./AvatarGroup-BAWas4pU.js";
1
+ import { A as o } from "./AvatarGroup-D1gnT3Od.js";
2
2
  export {
3
3
  o as AvatarGroup
4
4
  };
@@ -0,0 +1,66 @@
1
+ import t from "react";
2
+ import { A as b } from "./Avatar-loGgFt72.js";
3
+ import { c as g } from "./cx-CcykAxZN.js";
4
+ import './AvatarName.css';const y = "czr", A = "czc", h = "czt", x = "czd", C = "czs", F = "czm", I = "czl", e = {
5
+ r: y,
6
+ c: A,
7
+ t: h,
8
+ d: x,
9
+ s: C,
10
+ m: F,
11
+ l: I
12
+ };
13
+ function R(s, n) {
14
+ if (s != null && s !== "") return s;
15
+ if (typeof n == "string") return n;
16
+ }
17
+ function k(s) {
18
+ const {
19
+ src: n,
20
+ name: c,
21
+ title: m,
22
+ description: i,
23
+ size: a = "m",
24
+ radius: f,
25
+ status: p,
26
+ className: z,
27
+ children: E,
28
+ as: u = "div",
29
+ ...r
30
+ } = s, N = a === "s" ? e.s : a === "l" ? e.l : e.m, l = g(e.r, N, z), d = m ?? (typeof c == "string" ? c : void 0), v = R(c, m), o = /* @__PURE__ */ t.createElement(t.Fragment, null, /* @__PURE__ */ t.createElement(
31
+ b,
32
+ {
33
+ src: n,
34
+ name: v,
35
+ size: a,
36
+ radius: f,
37
+ status: p
38
+ }
39
+ ), /* @__PURE__ */ t.createElement("span", { className: e.c }, d != null ? /* @__PURE__ */ t.createElement("span", { className: e.t }, d) : null, i != null ? /* @__PURE__ */ t.createElement("span", { className: e.d }, i) : null, E));
40
+ return u === "button" ? /* @__PURE__ */ t.createElement(
41
+ "button",
42
+ {
43
+ type: "button",
44
+ className: l,
45
+ ...r
46
+ },
47
+ o
48
+ ) : u === "a" ? /* @__PURE__ */ t.createElement(
49
+ "a",
50
+ {
51
+ className: l,
52
+ ...r
53
+ },
54
+ o
55
+ ) : /* @__PURE__ */ t.createElement(
56
+ "div",
57
+ {
58
+ className: l,
59
+ ...r
60
+ },
61
+ o
62
+ );
63
+ }
64
+ export {
65
+ k as A
66
+ };
@@ -1 +1 @@
1
- @layer elcrm-components{.czr{display:inline-flex;align-items:center;gap:var(--shell-gap);max-width:100%;text-align:left;vertical-align:middle}.czr:is(button,a){-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-decoration:none}.czc{display:flex;flex-direction:column;gap:2px;min-width:0}.czt{margin:0;font-size:var(--shell-font-size);font-weight:var(--shell-font-weight);color:var(--shell-color);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.czd{margin:0;font-size:var(--shell-font-size-sm);font-weight:400;color:var(--shell-color-muted);line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.czs{gap:var(--shell-gap-sm)}.czs .czt{font-size:var(--shell-font-size-sm)}.czm{gap:var(--shell-gap)}.czl{gap:var(--shell-gap-lg)}.czl .czt{font-size:var(--shell-font-size-lg)}.czl .czd{font-size:var(--shell-font-size)}}
1
+ @layer elcrm-components{.czr{display:inline-flex;align-items:center;gap:var(--shell-gap);max-width:100%;text-align:left;vertical-align:middle}.czr:is(button,a){-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-decoration:none}.czc{display:flex;flex-direction:column;gap:2px;min-width:0}.czt{margin:0;font-size:var(--shell-font-size);font-weight:var(--shell-font-weight);color:var(--avatar-name-title-color, var(--shell-color));line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.czd{margin:0;font-size:var(--shell-font-size-sm);font-weight:400;color:var(--avatar-name-description-color, var(--shell-color-muted));line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.czs{gap:var(--shell-gap-sm)}.czs .czt{font-size:var(--shell-font-size-sm)}.czm{gap:var(--shell-gap)}.czl{gap:var(--shell-gap-lg)}.czl .czt{font-size:var(--shell-font-size-lg)}.czl .czd{font-size:var(--shell-font-size)}}
@@ -20,6 +20,8 @@ type Common = {
20
20
  description?: React.ReactNode;
21
21
  /** Размер: `s` | `m` | `l`. */
22
22
  size?: "s" | "m" | "l";
23
+ /** Скругление аватара (`10` → `10px`). Токен `--avatar-radius`. */
24
+ radius?: number | string;
23
25
  /** Статус у аватара. */
24
26
  status?: AvatarStatus;
25
27
  /** CSS-класс корня. */
@@ -50,7 +52,8 @@ export type AvatarNameProps = (Common & React.ButtonHTMLAttributes<HTMLButtonEle
50
52
  *
51
53
  * Канон: `title` / `description` для UI-текста; `name` — только инициалы.
52
54
  *
53
- * CSS-токены: `--shell-*` (типографика строки), аватар — `--avatar-*`.
55
+ * CSS-токены: `--avatar-name-title-color`, `--avatar-name-description-color`,
56
+ * аватар — `--avatar-*`.
54
57
  *
55
58
  * @example
56
59
  * ```tsx
@@ -1,4 +1,4 @@
1
- import { A as e } from "./AvatarName-DhD3TytF.js";
1
+ import { A as e } from "./AvatarName-C1sIDPH-.js";
2
2
  export {
3
3
  e as AvatarName
4
4
  };
@@ -0,0 +1,28 @@
1
+ import t from "react";
2
+ import { c as j } from "./cx-CcykAxZN.js";
3
+ import './Badge.css';const u = "cjr", i = "cjs", p = "cjm", w = "cjl", f = "cjn", g = "cja", N = "cju", h = "cjw", x = "cjd", z = "cjo", s = {
4
+ r: u,
5
+ s: i,
6
+ m: p,
7
+ l: w,
8
+ n: f,
9
+ a: g,
10
+ u: N,
11
+ w: h,
12
+ d: x,
13
+ o: z
14
+ };
15
+ function E(e) {
16
+ const {
17
+ tone: c = "neutral",
18
+ size: n = "m",
19
+ dot: o,
20
+ children: a,
21
+ className: r,
22
+ ...l
23
+ } = e, m = c === "accent" ? s.a : c === "success" ? s.u : c === "warning" ? s.w : c === "danger" ? s.d : s.n, d = n === "s" ? s.s : n === "l" ? s.l : s.m;
24
+ return /* @__PURE__ */ t.createElement("span", { className: j(s.r, d, m, r), ...l }, o ? /* @__PURE__ */ t.createElement("span", { className: s.o, "aria-hidden": !0 }) : null, a);
25
+ }
26
+ export {
27
+ E as B
28
+ };
package/dist/Badge.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cjr{display:inline-flex;align-items:center;justify-content:center;gap:.25rem;padding:.2rem .5rem;border-radius:999px;border:0;font-size:var(--shell-font-size-sm);font-weight:var(--shell-font-weight);line-height:1;white-space:nowrap}.cjn{background:var(--shell-background-hover);color:var(--shell-color)}.cja{background:color-mix(in srgb,var(--shell-color-accent) 16%,transparent);color:var(--shell-color-accent)}.cju{background:color-mix(in srgb,var(--shell-color-success) 16%,transparent);color:var(--shell-color-success)}.cjw{background:color-mix(in srgb,var(--shell-color-warning) 16%,transparent);color:var(--shell-color-warning)}.cjd{background:color-mix(in srgb,var(--shell-color-danger) 16%,transparent);color:var(--shell-color-danger)}}
1
+ @layer elcrm-components{.cjr{display:inline-flex;align-items:center;justify-content:center;gap:.25rem;padding:.2rem .5rem;border-radius:999px;border:0;font-size:var(--shell-font-size-sm);font-weight:600;line-height:1;white-space:nowrap}.cjs{padding:2px var(--shell-gap-sm);font-size:var(--shell-font-size-sm);letter-spacing:.04em}.cjm{padding:.2rem .5rem;font-size:var(--shell-font-size-sm)}.cjl{padding:.3rem .65rem;font-size:var(--shell-font-size)}.cjn{background:var(--shell-background-hover);color:var(--shell-color)}.cja{background:color-mix(in srgb,var(--shell-color-accent) 16%,transparent);color:var(--shell-color-accent)}.cju{background:color-mix(in srgb,var(--shell-color-success) 16%,transparent);color:var(--shell-color-success)}.cjw{background:color-mix(in srgb,var(--shell-color-warning) 16%,transparent);color:var(--shell-color-warning)}.cjd{background:color-mix(in srgb,var(--shell-color-danger) 16%,transparent);color:var(--shell-color-danger)}.cjo{flex-shrink:0;width:.45em;height:.45em;border-radius:50%;background:currentColor}}
package/dist/Badge.d.ts CHANGED
@@ -1,26 +1,41 @@
1
1
  import { default as React } from 'react';
2
+ /** Тон метки — те же смыслы, что у Stat */
3
+ export type BadgeTone = "neutral" | "accent" | "success" | "warning" | "danger";
4
+ /** Размер метки */
5
+ export type BadgeSize = "s" | "m" | "l";
6
+ export type BadgeProps = React.HTMLAttributes<HTMLSpanElement> & {
7
+ /**
8
+ * Цвет по смыслу.
9
+ * `neutral` | `accent` | `success` | `warning` | `danger`
10
+ */
11
+ tone?: BadgeTone;
12
+ /**
13
+ * Размер пилюли.
14
+ * `s` — в строке списка; `m` — обычная; `l` — крупнее.
15
+ * По умолчанию `m`.
16
+ */
17
+ size?: BadgeSize;
18
+ /** Точка статуса слева (цвет = `tone`) */
19
+ dot?: boolean;
20
+ /** Текст метки */
21
+ children?: React.ReactNode;
22
+ };
2
23
  /**
3
- * Компактная метка / статус (тон по смыслу).
24
+ * Компактная метка / статус (роль, состояние). Не заменяет Button.
4
25
  *
5
- * Роли: Badge рядом с Item, в Card, в PageHead; не заменяет Button.
26
+ * Props (`BadgeProps`):
27
+ * - `tone` — `neutral` | `accent` | `success` | `warning` | `danger`
28
+ * - `size` — `s` | `m` | `l` (по умолчанию `m`)
29
+ * - `dot` — точка слева (как online / offline)
30
+ * - `children` — текст метки
31
+ * - плюс атрибуты `span` (`className`, `style`, …)
6
32
  *
7
33
  * @example
8
34
  * ```tsx
9
- * <Badge tone="success">Активен</Badge>
10
- * <Badge tone="danger">Просрочен</Badge>
35
+ * <Badge tone="accent" size="s">ADMIN</Badge>
36
+ * <Badge tone="success" size="s" dot>online</Badge>
11
37
  * ```
12
38
  *
13
- * Токены: `--shell-*` (tone через color-mix от `--shell-color-*`).
14
- */
15
- export type BadgeProps = React.HTMLAttributes<HTMLSpanElement> & {
16
- /** Визуальный тон */
17
- tone?: "neutral" | "accent" | "success" | "warning" | "danger";
18
- /** Текст или содержимое метки */
19
- children?: React.ReactNode;
20
- };
21
- /**
22
- * Компактная метка / статус.
23
- *
24
- * @see Item, Card, Avatar
39
+ * @see Item, Card, Stat
25
40
  */
26
- export declare function Badge({ tone, children, className, ...rest }: BadgeProps): React.JSX.Element;
41
+ export declare function Badge(props: BadgeProps): React.JSX.Element;
package/dist/Badge.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B as o } from "./Badge-l6nUkl-H.js";
1
+ import { B as o } from "./Badge-jp-9iNNL.js";
2
2
  export {
3
3
  o as Badge
4
4
  };
@@ -1,5 +1,5 @@
1
1
  import t from "react";
2
- import { S as e } from "./Stack-b0-XWwQ1.js";
2
+ import { S as e } from "./Stack-XkmPSswj.js";
3
3
  function n({ row: o, ...r }) {
4
4
  return /* @__PURE__ */ t.createElement(e, { direction: o ? "row" : "column", ...r });
5
5
  }
package/dist/Block.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B } from "./Block-BAXh0PPp.js";
1
+ import { B } from "./Block-Bu7NEA0g.js";
2
2
  export {
3
3
  B as Block
4
4
  };
package/dist/Card.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cdr{background:var(--shell-background);border:1px solid var(--shell-border);border-radius:var(--shell-radius);padding:var(--shell-padding);box-shadow:var(--shell-shadow)}.cdt{margin:0 0 var(--shell-gap-sm);font-size:var(--shell-font-size-lg);font-weight:var(--shell-font-weight);color:var(--shell-color)}}
1
+ @layer elcrm-components{.cdr{background:var(--shell-background);border:1px solid var(--shell-border);border-radius:var(--shell-radius);padding:var(--shell-padding);box-shadow:var(--shell-shadow);cursor:var(--card-pointer, auto)}.cdt{margin:0 0 var(--shell-gap-sm);font-size:var(--shell-font-size-lg);font-weight:var(--shell-font-weight);color:var(--shell-color)}}
package/dist/Card.d.ts CHANGED
@@ -12,7 +12,14 @@ import { default as React } from 'react';
12
12
  * </Card>
13
13
  * ```
14
14
  *
15
- * Токены: `--shell-*`.
15
+ * Токены: `--shell-*`, курсор — `--card-pointer` (по умолчанию `auto`).
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <Card title="Тенанты" style={{ ["--card-pointer" as string]: "pointer" }}>
20
+ * 12
21
+ * </Card>
22
+ * ```
16
23
  */
17
24
  export type CardProps = React.HTMLAttributes<HTMLDivElement> & {
18
25
  /** Заголовок карточки (если нет — только children) */