@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
@@ -8,8 +8,10 @@ import { default as React } from 'react';
8
8
  *
9
9
  * @example
10
10
  * ```tsx
11
- * <PageShell>
12
- * <PageHead title="Клиенты" subtitle="Все компании" actions={<Button>Создать</Button>} />
11
+ * <PageShell scroll>
12
+ * <PageHead title="Идеи" sup={<Badge size="s" tone="accent">4</Badge>} sticky>
13
+ * <Menu items={tabs} value={tab} onSelect={setTab} />
14
+ * </PageHead>
13
15
  * …
14
16
  * </PageShell>
15
17
  * ```
@@ -19,18 +21,38 @@ import { default as React } from 'react';
19
21
  export type PageHeadProps = {
20
22
  /** Заголовок страницы */
21
23
  title: React.ReactNode;
24
+ /**
25
+ * Надстрочный слот сразу после title: текст или {@link Badge}.
26
+ * Пусто / `0` / `false` — не рендерим.
27
+ */
28
+ sup?: React.ReactNode;
22
29
  /** Подзаголовок */
23
30
  subtitle?: React.ReactNode;
24
31
  /** Кнопки / поиск справа в одной строке с заголовком */
25
32
  actions?: React.ReactNode;
33
+ /**
34
+ * Прилипает к верху скролла предка (`PageShell` с `scroll`).
35
+ * По умолчанию `false`.
36
+ */
37
+ sticky?: boolean;
26
38
  /** Доп. CSS-класс */
27
39
  className?: string;
28
- /** Контент под строкой заголовка (фильтры, Breadcrumb) */
40
+ /**
41
+ * Контент под строкой заголовка (фильтры, поиск, вкладки).
42
+ * Между title и children — `--shell-gap`.
43
+ */
29
44
  children?: React.ReactNode;
30
45
  };
31
46
  /**
32
- * Заголовок: title слева, actions справа (одна линия).
47
+ * Заголовок: title слева (+ `sup` сверху), actions справа.
33
48
  *
34
- * @see PageShell, Section, Header
49
+ * @param props.title заголовок
50
+ * @param props.sup — текст или Badge после title (надстрочно)
51
+ * @param props.subtitle — строка под заголовком
52
+ * @param props.actions — кнопки справа
53
+ * @param props.sticky — прилипает к скроллу
54
+ * @param props.children — фильтры / вкладки под шапкой
55
+ *
56
+ * @see PageShell, Section, Header, Badge
35
57
  */
36
- export declare function PageHead({ title, subtitle, actions, className, children, }: PageHeadProps): React.JSX.Element;
58
+ export declare function PageHead({ title, sup, subtitle, actions, sticky, className, children, }: PageHeadProps): React.JSX.Element;
package/dist/PageHead.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as o } from "./PageHead-Baz9BLuA.js";
1
+ import { P as o } from "./PageHead-DgaJ1mXY.js";
2
2
  export {
3
3
  o as PageHead
4
4
  };
@@ -1,28 +1,30 @@
1
1
  import e from "react";
2
2
  import { c as l } from "./cx-CcykAxZN.js";
3
- import './PageShell.css';const m = "ckr", o = "ckw", f = "ckb", i = "ckf", c = {
3
+ import './PageShell.css';const m = "ckr", f = "ckw", i = "ckb", k = "ckf", u = "cko", c = {
4
4
  r: m,
5
- w: o,
6
- b: f,
7
- f: i
5
+ w: f,
6
+ b: i,
7
+ f: k,
8
+ o: u
8
9
  };
9
- function u({
10
+ function d({
10
11
  children: s,
11
- className: a,
12
- wide: n,
12
+ className: n,
13
+ wide: o,
14
+ scroll: r = !0,
13
15
  footer: t,
14
- ...r
16
+ ...a
15
17
  }) {
16
18
  return /* @__PURE__ */ e.createElement(
17
19
  "div",
18
20
  {
19
- ...r,
20
- className: l(c.r, n && c.w, a)
21
+ ...a,
22
+ className: l(c.r, o && c.w, !r && c.o, n)
21
23
  },
22
24
  /* @__PURE__ */ e.createElement("div", { className: c.b }, s),
23
25
  t != null ? /* @__PURE__ */ e.createElement("div", { className: c.f }, t) : null
24
26
  );
25
27
  }
26
28
  export {
27
- u as P
29
+ d as P
28
30
  };
@@ -1 +1 @@
1
- @layer elcrm-components{.ckr{flex:1 1 auto;min-height:0;height:100%;width:100%;display:flex;flex-direction:column;box-sizing:border-box;padding:var(--shell-padding);overflow:hidden}.ckw{max-width:none}.ckb{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:var(--shell-gap)}.ckf{flex:0 0 auto;padding-top:var(--shell-gap-sm)}}
1
+ @layer elcrm-components{.ckr{flex:1 1 auto;min-height:0;height:100%;width:100%;display:flex;flex-direction:column;box-sizing:border-box;padding:var(--shell-padding);overflow:hidden}.ckw{max-width:none}.ckb{flex:1 1 auto;min-height:0;overflow:auto;display:flex;flex-direction:column;gap:var(--shell-gap)}.ckf{flex:0 0 auto;padding-top:var(--shell-gap-sm)}.cko{overflow:visible;height:auto}.cko .ckb{overflow:visible;flex:0 1 auto;min-height:auto}}
@@ -1,14 +1,14 @@
1
1
  import { default as React } from 'react';
2
2
  /**
3
- * Каркас модуля: скролл в body, опциональный footer прибит к низу.
3
+ * Каркас модуля: опциональный скролл в body, footer прибит к низу.
4
4
  *
5
5
  * Роли: PageShell = внутренний каркас контента в Layout;
6
6
  * сверху часто PageHead / Section, снизу — панель действий.
7
7
  *
8
8
  * @example
9
9
  * ```tsx
10
- * <PageShell wide footer={<Footer><Button>Сохранить</Button></Footer>}>
11
- * <PageHead title="Редактор" />
10
+ * <PageShell wide scroll footer={<Footer><Button>Сохранить</Button></Footer>}>
11
+ * <PageHead title="Редактор" sticky />
12
12
  * …
13
13
  * </PageShell>
14
14
  * ```
@@ -16,18 +16,23 @@ import { default as React } from 'react';
16
16
  * Токены: `--shell-*`.
17
17
  */
18
18
  export type PageShellProps = {
19
- /** Контент модуля (скроллится) */
19
+ /** Контент модуля */
20
20
  children: React.ReactNode;
21
21
  /** Доп. CSS-класс */
22
22
  className?: string;
23
23
  /** Шире контент (редакторы, таблицы) */
24
24
  wide?: boolean;
25
+ /**
26
+ * Скролл внутри body. По умолчанию `true`.
27
+ * `false` — шелл растёт с контентом, крутит предок.
28
+ */
29
+ scroll?: boolean;
25
30
  /** Нижняя панель вне скролла */
26
31
  footer?: React.ReactNode;
27
32
  } & Omit<React.HTMLAttributes<HTMLDivElement>, "children" | "className">;
28
33
  /**
29
- * Каркас модуля: скролл в body, footer прибит к низу.
34
+ * Каркас модуля: скролл в body (если `scroll`), footer прибит к низу.
30
35
  *
31
36
  * @see PageHead, Layout, Section, Footer
32
37
  */
33
- export declare function PageShell({ children, className, wide, footer, ...rootProps }: PageShellProps): React.JSX.Element;
38
+ export declare function PageShell({ children, className, wide, scroll, footer, ...rootProps }: PageShellProps): React.JSX.Element;
package/dist/PageShell.js CHANGED
@@ -1,4 +1,4 @@
1
- import { P as l } from "./PageShell-CghThHS3.js";
1
+ import { P as l } from "./PageShell-D9EZiO8o.js";
2
2
  export {
3
3
  l as PageShell
4
4
  };
@@ -0,0 +1,123 @@
1
+ import w, { useRef as h, useId as Q, useState as x, useLayoutEffect as S, useEffect as W } from "react";
2
+ import { createPortal as V } from "react-dom";
3
+ import { c as H } from "./cx-CcykAxZN.js";
4
+ import './Popover.css';const N = 1e3, X = 10;
5
+ function E() {
6
+ const e = globalThis;
7
+ return e.elcrm || (e.elcrm = {}), e.elcrm.overlayZ || (e.elcrm.overlayZ = { seq: 0, active: /* @__PURE__ */ new Set() }), e.elcrm.overlayZ;
8
+ }
9
+ function Y() {
10
+ const e = E();
11
+ e.seq += 1;
12
+ const r = N + e.seq * X;
13
+ return e.active.add(r), r;
14
+ }
15
+ function B(e) {
16
+ const r = E();
17
+ r.active.delete(e), r.active.size === 0 && (r.seq = 0);
18
+ }
19
+ function oe() {
20
+ const e = E();
21
+ return e.active.size === 0 ? N : Math.max(...e.active);
22
+ }
23
+ const _ = "c3r", $ = "c3t", C = "c3p", y = {
24
+ r: _,
25
+ t: $,
26
+ p: C
27
+ };
28
+ function re({
29
+ trigger: e,
30
+ children: r,
31
+ open: L,
32
+ defaultOpen: D = !1,
33
+ onOpenChange: m,
34
+ align: M = "end",
35
+ disabled: g = !1,
36
+ label: O,
37
+ role: T = "menu",
38
+ className: A,
39
+ panelClassName: F
40
+ }) {
41
+ const f = h(null), z = h(null), R = Q(), [K, U] = x(D), Z = L !== void 0, n = Z ? L : K, [c, I] = x(null), [i, P] = x(null), p = h(null);
42
+ p.current = i;
43
+ const v = (t) => {
44
+ g && t || (Z || U(t), m == null || m(t));
45
+ };
46
+ S(() => {
47
+ if (n) {
48
+ i == null && P(Y());
49
+ return;
50
+ }
51
+ i != null && (B(i), P(null));
52
+ }, [n, i]), W(() => () => {
53
+ p.current != null && B(p.current);
54
+ }, []);
55
+ const b = () => {
56
+ const t = f.current;
57
+ if (!t) return;
58
+ const o = t.getBoundingClientRect(), s = 8, a = window.innerHeight - o.bottom - s - 8, l = o.top - s - 8, u = a >= 160 || a >= l, q = Math.min(420, Math.max(120, u ? a : l)), d = Math.max(200, o.width), G = u ? o.bottom + s : Math.max(8, o.top - s - q), J = M === "end" ? Math.max(8, Math.min(o.right - d, window.innerWidth - d - 8)) : Math.max(8, Math.min(o.left, window.innerWidth - d - 8));
59
+ I({ top: G, left: J, minWidth: d, maxHeight: q });
60
+ };
61
+ S(() => {
62
+ if (!n) {
63
+ I(null);
64
+ return;
65
+ }
66
+ b();
67
+ const t = () => b();
68
+ return window.addEventListener("resize", t), window.addEventListener("scroll", t, !0), () => {
69
+ window.removeEventListener("resize", t), window.removeEventListener("scroll", t, !0);
70
+ };
71
+ }, [n, M]), W(() => {
72
+ if (!n) return;
73
+ const t = (s) => {
74
+ var l, u;
75
+ const a = s.target;
76
+ (l = f.current) != null && l.contains(a) || (u = z.current) != null && u.contains(a) || v(!1);
77
+ }, o = (s) => {
78
+ s.key === "Escape" && v(!1);
79
+ };
80
+ return document.addEventListener("mousedown", t), document.addEventListener("keydown", o), () => {
81
+ document.removeEventListener("mousedown", t), document.removeEventListener("keydown", o);
82
+ };
83
+ }, [n]);
84
+ const j = c ? {
85
+ position: "fixed",
86
+ top: c.top,
87
+ left: c.left,
88
+ minWidth: c.minWidth,
89
+ maxHeight: c.maxHeight,
90
+ zIndex: i ?? 1e3
91
+ } : void 0, k = n && c ? /* @__PURE__ */ w.createElement(
92
+ "div",
93
+ {
94
+ ref: z,
95
+ id: R,
96
+ role: T,
97
+ "aria-label": O,
98
+ className: H(y.p, F),
99
+ style: j,
100
+ onMouseDown: (t) => t.stopPropagation()
101
+ },
102
+ r
103
+ ) : null;
104
+ return /* @__PURE__ */ w.createElement("div", { ref: f, className: H(y.r, A) }, /* @__PURE__ */ w.createElement(
105
+ "div",
106
+ {
107
+ className: y.t,
108
+ "aria-haspopup": "menu",
109
+ "aria-expanded": n,
110
+ "aria-controls": n ? R : void 0,
111
+ onClick: () => {
112
+ g || v(!n);
113
+ }
114
+ },
115
+ e
116
+ ), k && typeof document < "u" ? V(k, document.body) : null);
117
+ }
118
+ export {
119
+ re as P,
120
+ Y as a,
121
+ oe as p,
122
+ B as r
123
+ };
@@ -0,0 +1 @@
1
+ @layer elcrm-components{.c3r{position:relative;display:inline-flex;vertical-align:middle}.c3t{display:inline-flex;align-items:center;min-width:0}.c3p{box-sizing:border-box;overflow:auto;padding:var(--shell-gap-sm);background:var(--shell-background);border:1px solid var(--shell-border);border-radius:var(--shell-radius);box-shadow:var(--popup-shadow);color:var(--shell-color);min-width:var(--dropdown-min-width, 200px);max-width:var(--dropdown-max-width, min(360px, calc(100vw - 16px) ));max-height:var(--dropdown-max-height, 420px)}}
@@ -0,0 +1,54 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Портал у якоря: Escape, клик снаружи, z-index (`globalThis.elcrm.overlayZ`).
4
+ *
5
+ * Роли: Popover = свой попап (слот `children`).
6
+ * Типовое меню пунктов — {@link Dropdown}.
7
+ * Инлайн-навигация — {@link Menu} (не путать).
8
+ *
9
+ * Бывший `@elcrm/overlay` `Menu` — этот компонент (`Popover`).
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <Popover
14
+ * trigger={<Button>Ещё</Button>}
15
+ * label="Действия"
16
+ * align="end"
17
+ * >
18
+ * <List>
19
+ * <Item as="button">Скачать</Item>
20
+ * </List>
21
+ * </Popover>
22
+ * ```
23
+ *
24
+ * Токены: `--shell-*`, `--popup-shadow`, `--dropdown-min-width`.
25
+ */
26
+ export type PopoverProps = {
27
+ /** Якорь (кнопка / иконка) */
28
+ trigger: React.ReactNode;
29
+ /** Содержимое панели */
30
+ children?: React.ReactNode;
31
+ /** Контролируемое открытие */
32
+ open?: boolean;
33
+ /** Начальное открытие */
34
+ defaultOpen?: boolean;
35
+ /** Смена open */
36
+ onOpenChange?: (open: boolean) => void;
37
+ /** Выравнивание панели */
38
+ align?: "start" | "end";
39
+ /** Не открывать по клику на якорь */
40
+ disabled?: boolean;
41
+ /** aria-label панели */
42
+ label?: string;
43
+ /** role панели */
44
+ role?: React.AriaRole;
45
+ className?: string;
46
+ /** Класс панели (portal) */
47
+ panelClassName?: string;
48
+ };
49
+ /**
50
+ * Панель в portal рядом с триггером.
51
+ *
52
+ * @see Dropdown, Menu
53
+ */
54
+ export declare function Popover({ trigger, children, open: openProp, defaultOpen, onOpenChange, align, disabled, label, role, className, panelClassName, }: PopoverProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { P as e } from "./Popover-g2xTGubK.js";
2
+ export {
3
+ e as Popover
4
+ };
@@ -1,5 +1,5 @@
1
1
  import t from "react";
2
- import { S as o } from "./Stack-b0-XWwQ1.js";
2
+ import { S as o } from "./Stack-XkmPSswj.js";
3
3
  function c(r) {
4
4
  return /* @__PURE__ */ t.createElement(o, { direction: "row", ...r });
5
5
  }
package/dist/Row.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R } from "./Row--HIe6vb9.js";
1
+ import { R } from "./Row-DsQOVn18.js";
2
2
  export {
3
3
  R as Row
4
4
  };
@@ -0,0 +1,69 @@
1
+ import l from "react";
2
+ import { B as h } from "./Badge-jp-9iNNL.js";
3
+ import { I as x } from "./Item-D4okhsfW.js";
4
+ import { c as u } from "./cx-CcykAxZN.js";
5
+ import './Sidebar.css';const k = "c2r", g = "c2b", y = "c2x", B = "c2g", I = "c2s", w = "c2p", z = "c2h", C = "c2n", R = "c2i", T = "c2a", $ = "c2o", j = "c2l", q = "c2d", A = "c2f", D = "c2v", e = {
6
+ r: k,
7
+ b: g,
8
+ x: y,
9
+ g: B,
10
+ s: I,
11
+ p: w,
12
+ h: z,
13
+ n: C,
14
+ i: R,
15
+ a: T,
16
+ o: $,
17
+ l: j,
18
+ d: q,
19
+ f: A,
20
+ v: D
21
+ };
22
+ function F(n) {
23
+ if (n == null || n === "") return null;
24
+ const c = Number(n);
25
+ return !Number.isNaN(c) && c === 0 ? null : !Number.isNaN(c) && c > 99 ? "99+" : String(n);
26
+ }
27
+ function L({
28
+ groups: n,
29
+ items: c,
30
+ value: v,
31
+ onSelect: s,
32
+ variant: E = "cards",
33
+ brand: o,
34
+ extra: r,
35
+ footer: N,
36
+ version: m,
37
+ className: f,
38
+ "aria-label": b = "Основное меню"
39
+ }) {
40
+ const p = n ?? c ?? [];
41
+ return /* @__PURE__ */ l.createElement(
42
+ "aside",
43
+ {
44
+ className: u(e.r, E === "plain" && e.p, f),
45
+ "aria-label": b
46
+ },
47
+ o != null || r != null ? /* @__PURE__ */ l.createElement("div", { className: e.b }, o, r != null ? /* @__PURE__ */ l.createElement("div", { className: e.x }, r) : null) : null,
48
+ /* @__PURE__ */ l.createElement("div", { className: e.g }, p.map((t) => /* @__PURE__ */ l.createElement("nav", { key: t.value, className: e.s, "aria-label": t.title ?? "Навигация" }, t.title ? /* @__PURE__ */ l.createElement("div", { className: e.h }, t.title) : null, /* @__PURE__ */ l.createElement("ul", { className: e.n }, (t.items ?? []).map((a) => {
49
+ const d = F(a.badge), i = v === a.value;
50
+ return /* @__PURE__ */ l.createElement("li", { key: a.value }, /* @__PURE__ */ l.createElement(
51
+ x,
52
+ {
53
+ as: "button",
54
+ active: i,
55
+ className: u(e.i, i && e.a),
56
+ "aria-current": i ? "page" : void 0,
57
+ onClick: () => s == null ? void 0 : s(a.value)
58
+ },
59
+ a.icon != null ? /* @__PURE__ */ l.createElement("span", { className: e.o, "aria-hidden": !0 }, a.icon) : null,
60
+ /* @__PURE__ */ l.createElement("span", { className: e.l }, a.label),
61
+ d != null ? /* @__PURE__ */ l.createElement(h, { className: e.d, tone: "accent", size: "s" }, d) : null
62
+ ));
63
+ }))))),
64
+ N != null || m != null ? /* @__PURE__ */ l.createElement("div", { className: u(e.s, e.f) }, N, m != null ? /* @__PURE__ */ l.createElement("div", { className: e.v }, m) : null) : null
65
+ );
66
+ }
67
+ export {
68
+ L as S
69
+ };
@@ -0,0 +1 @@
1
+ @layer elcrm-components{.c2r{box-sizing:border-box;display:flex;flex-direction:column;flex:0 0 var(--sidebar-width);width:var(--sidebar-width);min-height:100svh;max-height:100svh;padding:var(--sidebar-pad-y) var(--sidebar-pad-x);gap:var(--shell-gap-sm);color:var(--shell-color);position:sticky;top:0;align-self:flex-start}.c2b{display:flex;flex-direction:row;align-items:center;gap:var(--shell-gap);padding:4px 8px;min-width:0}.c2x{flex-shrink:0;margin-left:auto}.c2g{flex:1;min-height:0;display:flex;flex-direction:column;gap:var(--shell-gap-sm);overflow-y:auto;overflow-x:hidden;scrollbar-width:thin}.c2s{box-sizing:border-box;flex-shrink:0;padding:8px}.c2p{--sidebar-plain: 1}.c2r:not(.c2p) .c2s{background:var(--sidebar-block-bg, var(--shell-background));border:1px solid var(--sidebar-block-border, var(--shell-border));border-radius:var(--sidebar-block-radius, var(--shell-radius));box-shadow:var(--sidebar-block-shadow, none)}.c2h{margin:2px 10px 6px;font-size:var(--sidebar-group-font-size, 11px);font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--shell-color-muted)}.c2n{margin:0;padding:0;list-style:none}.c2n>li{list-style:none}.c2n .c2i:is(button){position:relative;display:flex;width:100%;box-sizing:border-box;flex-direction:row;align-items:center;gap:8px;margin:0 0 1px;padding:var(--sidebar-item-padding, 6px 10px);border:0;border-radius:8px;background:transparent;color:var(--shell-color-muted);font-family:inherit;font-size:var(--sidebar-item-font-size, 13px);font-weight:500;line-height:1.25;letter-spacing:0;text-align:left;cursor:pointer}.c2n .c2i:is(button):hover{color:var(--shell-color);background:var(--shell-background-hover)}.c2n .c2i:is(button).c2a,.c2n .c2i:is(button)[aria-current=page],.c2n .c2i:is(button)[data-active=true],.c2n .c2i:is(button).c2a:hover{color:var(--sidebar-item-active, var(--shell-color));background:var(--sidebar-item-active-bg, var(--shell-background-selected))}.c2o{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:var(--sidebar-icon-size, 16px);height:var(--sidebar-icon-size, 16px);color:inherit}.c2o :is(svg){display:block;width:var(--sidebar-icon-size, 16px);height:var(--sidebar-icon-size, 16px)}.c2a .c2o{color:var(--sidebar-icon-active, var(--shell-color-accent))}.c2l{flex:1;min-width:0}.c2d{flex-shrink:0;min-width:16px;height:16px;padding:0 4px;font-size:10px}.c2f{margin-top:auto}.c2v{margin-top:var(--shell-gap-sm);font-size:11px;color:var(--shell-color-muted);text-align:center}@media (max-width: 900px){.c2r{flex:0 0 72px;width:72px;padding:12px 8px}.c2l,.c2h,.c2v{display:none}.c2b{flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:4px 0}.c2x{margin-left:0}.c2s{padding:6px}.c2n .c2i{justify-content:center;align-items:center;gap:0;width:100%;min-height:40px;padding:10px 0}.c2n .c2d{position:absolute;top:4px;right:4px;min-width:14px;height:14px;padding:0 4px;font-size:.625rem;line-height:14px;pointer-events:none}}}
@@ -0,0 +1,83 @@
1
+ import { default as React } from 'react';
2
+ /** Вид колонки: карточки (консоль) или плоский список (backoffice) */
3
+ export type SidebarVariant = "cards" | "plain";
4
+ /** Пункт бокового меню. Идентификатор — `value`. */
5
+ export type SidebarItem = {
6
+ value: string;
7
+ /** Подпись */
8
+ label: string;
9
+ /** Иконка (слот приложения) */
10
+ icon?: React.ReactNode;
11
+ /** Счётчик справа */
12
+ badge?: number | string | null;
13
+ };
14
+ /** Группа пунктов. `title` — «Аккаунт» / «Админ». */
15
+ export type SidebarGroup = {
16
+ value: string;
17
+ title?: string;
18
+ items: SidebarItem[];
19
+ };
20
+ /**
21
+ * Левая колонка приложения: бренд, группы меню, футер.
22
+ *
23
+ * Роли: Sidebar = навигация приложения; не путать с NavSections
24
+ * (сайдбар внутри страницы + lazy-панель).
25
+ *
26
+ * `variant="cards"` — секции-карточки (elWMS Console).
27
+ * `variant="plain"` — плоский список и заголовок группы (backoffice).
28
+ *
29
+ * Иконки, колокольчик, тема, выход — слоты приложения
30
+ * (`brand`, `extra`, `footer`). Роутер не подключаем.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <Sidebar
35
+ * variant="cards"
36
+ * value={page}
37
+ * onSelect={setPage}
38
+ * brand={<Brand as="strong">App</Brand>}
39
+ * extra={<Notifications.Bell />}
40
+ * groups={[
41
+ * { value: "main", items: [{ value: "home", label: "Обзор", icon: <Icon /> }] },
42
+ * { value: "admin", title: "Админ", items: [{ value: "users", label: "Люди" }] },
43
+ * ]}
44
+ * footer={<AvatarName title="Паша" description="mail@…" />}
45
+ * version="v 0.2.26"
46
+ * />
47
+ * ```
48
+ *
49
+ * Токены: `--sidebar-*`, цвета — `--shell-*`.
50
+ */
51
+ export type SidebarProps = {
52
+ /** Группы пунктов (`value` + `items`) */
53
+ groups?: SidebarGroup[];
54
+ /** То же, что `groups` (совместимость) */
55
+ items?: SidebarGroup[];
56
+ /** Текущий пункт */
57
+ value?: string;
58
+ /** Выбор пункта */
59
+ onSelect?: (value: string) => void;
60
+ /**
61
+ * `cards` — блоки-карточки.
62
+ * `plain` — плоский список.
63
+ * @default "cards"
64
+ */
65
+ variant?: SidebarVariant;
66
+ /** Логотип / название */
67
+ brand?: React.ReactNode;
68
+ /** Справа от бренда (колокольчик) */
69
+ extra?: React.ReactNode;
70
+ /** Низ: тема, выход или карточка пользователя */
71
+ footer?: React.ReactNode;
72
+ /** Версия под футером */
73
+ version?: React.ReactNode;
74
+ /** Подпись колонки */
75
+ "aria-label"?: string;
76
+ className?: string;
77
+ };
78
+ /**
79
+ * Левая навигация приложения.
80
+ *
81
+ * @see Layout, Brand, Item, Badge, NavSections
82
+ */
83
+ export declare function Sidebar({ groups, items, value, onSelect, variant, brand, extra, footer, version, className, "aria-label": ariaLabel, }: SidebarProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { S as e } from "./Sidebar-DeqxYgxn.js";
2
+ export {
3
+ e as Sidebar
4
+ };
@@ -0,0 +1,53 @@
1
+ import m from "react";
2
+ import { c as f } from "./cx-CcykAxZN.js";
3
+ import './Stack.css';function l(t) {
4
+ if (t != null)
5
+ return { gap: typeof t == "number" ? `${t}px` : t };
6
+ }
7
+ const i = "c1r", p = "c1c", g = "c1g", h = "c1h", v = "c1n", r = {
8
+ r: i,
9
+ c: p,
10
+ g,
11
+ h,
12
+ n: v
13
+ };
14
+ function x(t) {
15
+ if (typeof t == "number")
16
+ return t <= 0 ? void 0 : `repeat(${t}, minmax(0, 1fr))`;
17
+ if (t.length !== 0)
18
+ return t.map((n) => typeof n == "number" ? `${n}px` : n).join(" ");
19
+ }
20
+ function k({
21
+ direction: t = "column",
22
+ columns: n,
23
+ gap: c,
24
+ children: o,
25
+ className: a,
26
+ style: s,
27
+ ...u
28
+ }) {
29
+ const e = t === "grid" && n != null ? x(n) : void 0;
30
+ return /* @__PURE__ */ m.createElement(
31
+ "div",
32
+ {
33
+ className: f(
34
+ r.r,
35
+ t === "column" && r.c,
36
+ t === "row" && r.h,
37
+ t === "grid" && (e ? r.n : r.g),
38
+ a
39
+ ),
40
+ style: {
41
+ ...l(c),
42
+ ...e ? { "--stack-columns-template": e } : null,
43
+ ...s
44
+ },
45
+ ...u
46
+ },
47
+ o
48
+ );
49
+ }
50
+ export {
51
+ k as S,
52
+ x as s
53
+ };
package/dist/Stack.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.c1r{display:flex;flex-direction:column;gap:var(--shell-gap)}.c1h{flex-direction:row;flex-wrap:wrap;align-items:center}}
1
+ @layer elcrm-components{.c1r{box-sizing:border-box;min-width:0;gap:var(--shell-gap)}.c1c,.c1g{width:100%}.c1c{display:flex;flex-direction:column}.c1h{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;width:auto;max-width:100%}.c1g{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--stack-grid-min)),1fr))}.c1n{display:grid;width:100%;align-items:stretch;grid-template-columns:var(--stack-columns-template)}}
package/dist/Stack.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { default as React } from 'react';
2
2
  /** Направление раскладки стека */
3
- export type StackDirection = "row" | "column";
3
+ export type StackDirection = "row" | "column" | "grid";
4
+ /** Сетка: число равных колонок или треки (`1fr`, `100px`, …). Число в массиве — px. */
5
+ export type StackColumns = number | Array<number | string>;
6
+ /** CSS `grid-template-columns` из пропа `columns`. */
7
+ export declare function stackColumnsTemplate(columns: StackColumns): string | undefined;
4
8
  /**
5
9
  * Универсальный стек (ряд / колонка) с отступами между детьми.
6
10
  *
@@ -13,13 +17,21 @@ export type StackDirection = "row" | "column";
13
17
  * <Button>Отмена</Button>
14
18
  * <Button>Сохранить</Button>
15
19
  * </Stack>
20
+ * <Stack direction="grid" columns={["1fr", "100px", "100px"]} gap={12} />
16
21
  * ```
17
22
  *
18
- * Токены: `--shell-gap` (если `gap` не задан); при `gap` inline-стиль.
23
+ * Токены: `--shell-gap` (если `gap` не задан); сетка`--stack-grid-min`.
24
+ * `columns` — число равных колонок или массив треков (`--stack-columns-template`).
25
+ * Явные колонки: `align-items: stretch` (несколько рядов). Центр в одном ряду — `style={{ alignItems: "center" }}`.
19
26
  */
20
27
  export type StackProps = React.HTMLAttributes<HTMLDivElement> & {
21
- /** Направление: по умолчанию `column` */
28
+ /** Направление: по умолчанию `column`. `grid` — сетка */
22
29
  direction?: StackDirection;
30
+ /**
31
+ * Сетка: `4` — четыре равные колонки;
32
+ * `["1fr", "100px", "auto"]` — свои треки (число в массиве = px).
33
+ */
34
+ columns?: StackColumns;
23
35
  /** Отступ между детьми: число (px) или CSS-строка */
24
36
  gap?: number | string;
25
37
  /** Дочерние элементы стека */
@@ -31,4 +43,4 @@ export type StackProps = React.HTMLAttributes<HTMLDivElement> & {
31
43
  *
32
44
  * @see Block, Row, Column
33
45
  */
34
- export declare function Stack({ direction, gap, children, className, style, ...rest }: StackProps): React.JSX.Element;
46
+ export declare function Stack({ direction, columns, gap, children, className, style, ...rest }: StackProps): React.JSX.Element;
package/dist/Stack.js CHANGED
@@ -1,4 +1,5 @@
1
- import { S as r } from "./Stack-b0-XWwQ1.js";
1
+ import { S as t, s as e } from "./Stack-XkmPSswj.js";
2
2
  export {
3
- r as Stack
3
+ t as Stack,
4
+ e as stackColumnsTemplate
4
5
  };