@elcrm/components 0.2.8 → 0.2.11

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 CHANGED
@@ -92,14 +92,14 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
92
92
  | **Dropdown** | Выпадающее меню (items, portal) | `label`/`trigger`, `items`/`groups`, `onSelect` |
93
93
  | **Popover** | Свой попап в portal | `trigger`, `children`, `align`, `open` |
94
94
  | **Breadcrumb** | Хлебные крошки | `items`, `separator`, `collapseAfter` |
95
- | **Sidebar** | Левое меню приложения | `groups`, `value`, `footer` + `footerItems`, `variant` |
95
+ | **Sidebar** | Левое меню приложения | `groups`, `value`, `item.items` + `defaultOpen`, `open` / `onOpenChange`, `footerItems` |
96
96
  | **PageShell** | Каркас модуля (скролл + footer) | `wide`, `scroll`, `footer`, `children` |
97
97
  | **ChatList** | Колонка диалогов | `header`, `footer`, `children` (`List`/`Item`), `bodyRef` |
98
98
  | **ChatMessages** | Колонка переписки | `header`, `footer`, `children`, `bodyRef`, `onBodyScroll` |
99
99
  | **ChatSplit** | Список + лента | `list`, `messages` |
100
100
  | **PageHead** | Заголовок страницы + actions | `title`, `sup` (текст/Badge), `subtitle`, `actions`, `sticky`, `children` |
101
101
  | **Section** | Блок контента / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant` |
102
- | **NavSections** | Сайдбар + lazy-панель | `groups` (`value`), `resolveSection`, `defaultValue` |
102
+ | **NavSections** | Сайдбар + lazy-панель | `groups`, `item.items` + `defaultOpen`, `open` / `onOpenChange`, `resolveSection` |
103
103
  | **TabSections** | Горизонтальные вкладки + lazy | `items` (`value` + `badge`), `resolveSection` |
104
104
  | **Card** | Карточка | `title`, `--card-pointer` |
105
105
  | **ActionGroup** | Ряд иконок в карточке | `label`, `items` и/или `children` |
@@ -136,7 +136,17 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
136
136
  {
137
137
  value: "admin",
138
138
  title: "Админ",
139
- items: [{ value: "ops", label: "Операции" }],
139
+ items: [
140
+ {
141
+ value: "bridge",
142
+ label: "VK Bridge",
143
+ defaultOpen: true,
144
+ items: [
145
+ { value: "intro", label: "Введение" },
146
+ { value: "events", label: "События" },
147
+ ],
148
+ },
149
+ ],
140
150
  },
141
151
  ]}
142
152
  footer={<AvatarName title="Паша" description="mail@…" />}
@@ -150,7 +160,7 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
150
160
  />
151
161
  ```
152
162
 
153
- Токены: `--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` в теме приложения.
163
+ Токены: `--sidebar-width`, `--sidebar-item-font-size`, `--sidebar-item-padding`, `--sidebar-icon-size`, `--sidebar-group-font-size`, `--sidebar-indent`, `--sidebar-item-active`. Для orange active в `plain` переопределите `--sidebar-item-active` в теме приложения.
154
164
 
155
165
  ### Stack
156
166
 
@@ -656,6 +666,15 @@ const resolve = createLazyResolver(
656
666
  label: "Личное",
657
667
  items: [
658
668
  { value: "Profile", label: "Профиль" },
669
+ {
670
+ value: "bridge",
671
+ label: "VK Bridge",
672
+ defaultOpen: true,
673
+ items: [
674
+ { value: "Intro", label: "Введение" },
675
+ { value: "Events", label: "События" },
676
+ ],
677
+ },
659
678
  { value: "Appearance", label: "Оформление" },
660
679
  ],
661
680
  },
@@ -0,0 +1,142 @@
1
+ import e, { useMemo as B, Suspense as D } from "react";
2
+ import { c as K } from "./cx-CcykAxZN.js";
3
+ import { I as F } from "./Item-D4okhsfW.js";
4
+ import { f as I, c as M, a as O, b as P, i as V } from "./navTree-BRyaILN9.js";
5
+ import { h as j } from "./rovingKeys-CGlfTtNQ.js";
6
+ import { u as y } from "./useControllableValue-CWqH1kpM.js";
7
+ import './NavSections.css';const A = "cvr", W = "cvn", $ = "cvg", q = "cvl", z = "cvi", G = "cva", H = "cvc", J = "cvt", Q = "cve", T = "cvs", U = "cvf", X = "cvm", c = {
8
+ r: A,
9
+ n: W,
10
+ g: $,
11
+ l: q,
12
+ i: z,
13
+ a: G,
14
+ c: H,
15
+ t: J,
16
+ e: Q,
17
+ s: T,
18
+ f: U,
19
+ m: X
20
+ };
21
+ function Y({ className: a }) {
22
+ return /* @__PURE__ */ e.createElement("svg", { className: a, viewBox: "0 0 12 12", "aria-hidden": !0 }, /* @__PURE__ */ e.createElement(
23
+ "path",
24
+ {
25
+ d: "M2.5 4.5 6 8l3.5-3.5",
26
+ fill: "none",
27
+ stroke: "currentColor",
28
+ strokeWidth: "1.5",
29
+ strokeLinecap: "round",
30
+ strokeLinejoin: "round"
31
+ }
32
+ ));
33
+ }
34
+ function C({
35
+ items: a,
36
+ value: d,
37
+ open: f,
38
+ onSelect: m,
39
+ onToggle: E
40
+ }) {
41
+ return /* @__PURE__ */ e.createElement(e.Fragment, null, a.map((t) => {
42
+ const v = t.items, s = v != null && v.length > 0, u = s && f.includes(t.value), r = !s && t.value === d;
43
+ return /* @__PURE__ */ e.createElement(e.Fragment, { key: t.value }, /* @__PURE__ */ e.createElement(
44
+ F,
45
+ {
46
+ as: "button",
47
+ active: r,
48
+ className: K(c.i, r && c.a),
49
+ "data-active": r ? "true" : void 0,
50
+ "data-open": u ? "true" : void 0,
51
+ "aria-current": r ? "page" : void 0,
52
+ "aria-expanded": s ? u : void 0,
53
+ disabled: t.disabled,
54
+ onClick: () => {
55
+ s ? E(t.value) : m(t.value);
56
+ }
57
+ },
58
+ t.icon != null ? /* @__PURE__ */ e.createElement("span", { className: c.c, "aria-hidden": !0 }, t.icon) : null,
59
+ /* @__PURE__ */ e.createElement("span", { className: c.t }, t.label),
60
+ s ? /* @__PURE__ */ e.createElement(Y, { className: c.e }) : null
61
+ ), s && u ? /* @__PURE__ */ e.createElement("div", { className: c.s }, /* @__PURE__ */ e.createElement(
62
+ C,
63
+ {
64
+ items: v,
65
+ value: d,
66
+ open: f,
67
+ onSelect: m,
68
+ onToggle: E
69
+ }
70
+ )) : null);
71
+ }));
72
+ }
73
+ function le({
74
+ groups: a,
75
+ resolveSection: d,
76
+ value: f,
77
+ defaultValue: m,
78
+ onValueChange: E,
79
+ open: t,
80
+ defaultOpen: v,
81
+ onOpenChange: s,
82
+ loading: u = null,
83
+ footer: r,
84
+ className: R,
85
+ navLabel: S = "Разделы"
86
+ }) {
87
+ const g = B(
88
+ () => m || I(a),
89
+ [m, a]
90
+ ), [l, b] = y(
91
+ f,
92
+ g,
93
+ E
94
+ ), [o = [], N] = y(
95
+ t,
96
+ M(a, v, l),
97
+ s
98
+ ), x = O(a).map((n) => n.value), p = e.useRef(l);
99
+ e.useEffect(() => {
100
+ if (l == null || l === p.current) {
101
+ p.current = l;
102
+ return;
103
+ }
104
+ p.current = l;
105
+ const i = P(a, l).filter((w) => !o.includes(w));
106
+ i.length && N([...o, ...i]);
107
+ }, [l, a, o, N]);
108
+ const h = (n) => {
109
+ N(
110
+ o.includes(n) ? o.filter((i) => i !== n) : [...o, n]
111
+ );
112
+ }, L = (n) => {
113
+ V(a, n) ? h(n) : b(n);
114
+ }, k = l ? d(l) : null;
115
+ return /* @__PURE__ */ e.createElement("div", { className: K(c.r, R) }, /* @__PURE__ */ e.createElement(
116
+ "nav",
117
+ {
118
+ className: c.n,
119
+ "aria-label": S,
120
+ onKeyDown: (n) => j(n, {
121
+ values: x,
122
+ value: l,
123
+ onSelect: L,
124
+ vertical: !0
125
+ })
126
+ },
127
+ a.map((n, i) => /* @__PURE__ */ e.createElement("div", { key: i, className: c.g }, n.label != null ? /* @__PURE__ */ e.createElement("div", { className: c.l }, n.label) : null, /* @__PURE__ */ e.createElement(
128
+ C,
129
+ {
130
+ items: n.items,
131
+ value: l,
132
+ open: o,
133
+ onSelect: b,
134
+ onToggle: h
135
+ }
136
+ ))),
137
+ r != null ? /* @__PURE__ */ e.createElement("div", { className: c.f }, r) : null
138
+ ), /* @__PURE__ */ e.createElement("div", { className: c.m }, k ? /* @__PURE__ */ e.createElement(D, { fallback: u }, e.createElement(k)) : null));
139
+ }
140
+ export {
141
+ le as N
142
+ };
@@ -1 +1 @@
1
- @layer elcrm-components{.cvr{display:flex;align-items:stretch;gap:var(--shell-gap-lg);width:100%;flex:1 1 auto;min-height:0;box-sizing:border-box;padding:var(--nav-sections-padding)}.cvn{display:flex;flex-direction:column;gap:var(--shell-gap);flex:0 0 var(--nav-sections-nav-width);width:var(--nav-sections-nav-width);min-width:var(--nav-sections-nav-width);box-sizing:border-box}.cvg{display:flex;flex-direction:column;gap:2px;padding-bottom:var(--shell-gap);border-bottom:1px solid var(--shell-border)}.cvg:last-of-type{border-bottom:none;padding-bottom:0}.cvl{font-size:var(--sidebar-group-font-size);font-weight:var(--shell-font-weight);letter-spacing:.04em;text-transform:uppercase;color:var(--shell-color-muted);padding:0 var(--shell-padding-inline) var(--shell-gap-sm)}.cvi:is(button){position:relative;font-size:var(--shell-font-size-sm)}.cva:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--shell-color-accent)}.cvi:disabled{opacity:var(--shell-disabled-opacity);cursor:not-allowed}.cvc{display:inline-flex;flex:0 0 auto;color:var(--shell-color-muted);line-height:0}.cva .cvc{color:var(--shell-color)}.cvt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cvf{margin-top:auto;padding-top:var(--shell-gap);border-top:1px solid var(--shell-border)}.cvm{flex:1 1 auto;min-width:0;max-width:var(--nav-sections-main-max-width);width:100%;min-height:0;overflow:auto}@media (max-width: 720px){.cvr{flex-direction:column}.cvn{flex:none;width:100%;min-width:0;max-width:none}}}
1
+ @layer elcrm-components{.cvr{display:flex;align-items:stretch;gap:var(--shell-gap-lg);width:100%;flex:1 1 auto;min-height:0;box-sizing:border-box;padding:var(--nav-sections-padding)}.cvn{display:flex;flex-direction:column;gap:var(--shell-gap);flex:0 0 var(--nav-sections-nav-width);width:var(--nav-sections-nav-width);min-width:var(--nav-sections-nav-width);box-sizing:border-box}.cvg{display:flex;flex-direction:column;gap:2px;padding-bottom:var(--shell-gap);border-bottom:1px solid var(--shell-border)}.cvg:last-of-type{border-bottom:none;padding-bottom:0}.cvl{font-size:var(--sidebar-group-font-size);font-weight:var(--shell-font-weight);letter-spacing:.04em;text-transform:uppercase;color:var(--shell-color-muted);padding:0 var(--shell-padding-inline) var(--shell-gap-sm)}.cvi:is(button){position:relative;display:flex;width:100%;align-items:center;font-size:var(--shell-font-size-sm)}.cva:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--shell-color-accent)}.cvi:disabled{opacity:var(--shell-disabled-opacity);cursor:not-allowed}.cvc{display:inline-flex;flex:0 0 auto;color:var(--shell-color-muted);line-height:0}.cva .cvc{color:var(--shell-color)}.cvt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cve{flex-shrink:0;width:12px;height:12px;margin-left:auto;color:var(--shell-color-muted);transition:transform .15s ease}.cvi:is(button)[data-open=true] .cve{transform:rotate(180deg);color:inherit}.cvs{display:flex;flex-direction:column;gap:2px;padding-inline-start:var(--sidebar-indent)}.cvf{margin-top:auto;padding-top:var(--shell-gap);border-top:1px solid var(--shell-border)}.cvm{flex:1 1 auto;min-width:0;max-width:var(--nav-sections-main-max-width);width:100%;min-height:0;overflow:auto}@media (max-width: 720px){.cvr{flex-direction:column}.cvn{flex:none;width:100%;min-width:0;max-width:none}}}
@@ -15,6 +15,17 @@ export type NavSectionsItem = {
15
15
  icon?: React.ReactNode;
16
16
  /** Недоступный пункт. */
17
17
  disabled?: boolean;
18
+ /**
19
+ * Вложенные пункты — есть → шеврон и раскрытие.
20
+ * Клик по родителю только открывает/закрывает, панель не меняем.
21
+ */
22
+ items?: NavSectionsItem[];
23
+ /**
24
+ * Подменю открыто при первом рендере.
25
+ * Если выбран потомок — ветка откроется сама.
26
+ * @default false
27
+ */
28
+ defaultOpen?: boolean;
18
29
  };
19
30
  /**
20
31
  * Группа пунктов сайдбара (опциональный заголовок + `items`).
@@ -46,6 +57,17 @@ export type NavSectionsProps = {
46
57
  defaultValue?: string;
47
58
  /** Смена активного раздела (`next` = `item.value`). */
48
59
  onValueChange?: (value: string) => void;
60
+ /**
61
+ * Раскрытые родители (их `value`). Контролируемый режим.
62
+ * Вместе с `onOpenChange`.
63
+ */
64
+ open?: string[];
65
+ /**
66
+ * Начально раскрытые (плюс `item.defaultOpen` и предки выбранного).
67
+ */
68
+ defaultOpen?: string[];
69
+ /** Смена набора раскрытых родителей */
70
+ onOpenChange?: (open: string[]) => void;
49
71
  /** Fallback для `<Suspense>` при ленивой загрузке секции. */
50
72
  loading?: React.ReactNode;
51
73
  /** Низ сайдбара (например кнопка «Назад»). */
@@ -68,34 +90,40 @@ export type NavSectionsProps = {
68
90
  * - {@link Menu} — простая навигация без панелей.
69
91
  *
70
92
  * API: декларативные `groups` / `items`. Идентификатор раздела — `value` (не `key`).
93
+ * У пункта `items` + `defaultOpen` — раскрываемое подменю (как у Sidebar).
71
94
  * Compound-слоты (`NavSections.Item`) не используются.
72
95
  *
73
96
  * CSS-токены: `--shell-*`, `--nav-sections-padding`, `--nav-sections-nav-width`,
74
- * `--nav-sections-main-max-width`.
97
+ * `--nav-sections-main-max-width`, `--sidebar-indent`.
75
98
  *
76
99
  * @example
77
100
  * ```tsx
78
101
  * const groups = [
79
102
  * {
80
- * label: "Личное",
103
+ * label: "Документация",
81
104
  * items: [
82
- * { value: "profile", label: "Профиль", icon: <Icons.Line name="user" /> },
83
- * { value: "security", label: "Безопасность" },
105
+ * {
106
+ * value: "bridge",
107
+ * label: "VK Bridge",
108
+ * defaultOpen: true,
109
+ * items: [
110
+ * { value: "intro", label: "Введение" },
111
+ * { value: "events", label: "События", items: [
112
+ * { value: "evt-init", label: "VKWebAppInit" },
113
+ * ] },
114
+ * ],
115
+ * },
116
+ * { value: "auth", label: "Авторизация VK" },
84
117
  * ],
85
118
  * },
86
119
  * ];
87
120
  *
88
- * const resolveSection = createLazyResolver(
89
- * (v) => import(`./sections/${v}.tsx`),
90
- * );
91
- *
92
121
  * <NavSections
93
122
  * groups={groups}
94
123
  * resolveSection={resolveSection}
95
124
  * value={section}
96
125
  * onValueChange={setSection}
97
- * footer={<Button onSend={() => navigate(-1)}>Назад</Button>}
98
126
  * />
99
127
  * ```
100
128
  */
101
- export declare function NavSections({ groups, resolveSection, value: valueProp, defaultValue, onValueChange, loading, footer, className, navLabel, }: NavSectionsProps): React.JSX.Element;
129
+ export declare function NavSections({ groups, resolveSection, value: valueProp, defaultValue, onValueChange, open: openProp, defaultOpen, onOpenChange, loading, footer, className, navLabel, }: NavSectionsProps): React.JSX.Element;
@@ -1,4 +1,4 @@
1
- import { N as e } from "./NavSections-BpyZPimZ.js";
1
+ import { N as e } from "./NavSections-D6rDEtT1.js";
2
2
  export {
3
3
  e as NavSections
4
4
  };
@@ -0,0 +1,178 @@
1
+ import e from "react";
2
+ import { B as K } from "./Badge-jp-9iNNL.js";
3
+ import { D as R } from "./Dropdown-DosvDR13.js";
4
+ import { I as F } from "./Item-D4okhsfW.js";
5
+ import { b as I } from "./badgeText-CRzlIzi3.js";
6
+ import { c as f } from "./cx-CcykAxZN.js";
7
+ import { c as L, b as M } from "./navTree-BRyaILN9.js";
8
+ import { u as O } from "./useControllableValue-CWqH1kpM.js";
9
+ import './Sidebar.css';const T = "c2r", V = "c2b", j = "c2x", z = "c2g", A = "c2s", W = "c2p", $ = "c2h", G = "c2n", H = "c2i", J = "c2a", P = "c2o", Q = "c2l", U = "c2d", X = "c2c", Y = "c2m", Z = "c2f", _ = "c2q", S = "c2w", ee = "c2u", ne = "c2k", ce = "c2v", n = {
10
+ r: T,
11
+ b: V,
12
+ x: j,
13
+ g: z,
14
+ s: A,
15
+ p: W,
16
+ h: $,
17
+ n: G,
18
+ i: H,
19
+ a: J,
20
+ o: P,
21
+ l: Q,
22
+ d: U,
23
+ c: X,
24
+ m: Y,
25
+ f: Z,
26
+ q: _,
27
+ w: S,
28
+ u: ee,
29
+ k: ne,
30
+ v: ce
31
+ };
32
+ function te({ className: l }) {
33
+ return /* @__PURE__ */ e.createElement("svg", { className: l, viewBox: "0 0 16 16", "aria-hidden": !0 }, /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "3", r: "1.3", fill: "currentColor" }), /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "8", r: "1.3", fill: "currentColor" }), /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "13", r: "1.3", fill: "currentColor" }));
34
+ }
35
+ function le({
36
+ footer: l,
37
+ className: u,
38
+ ...c
39
+ }) {
40
+ const o = /* @__PURE__ */ e.createElement(te, { className: n.k });
41
+ if (e.isValidElement(l) && typeof l.type != "string") {
42
+ const s = l.props;
43
+ return e.cloneElement(l, {
44
+ as: "button",
45
+ extra: s.extra ?? o,
46
+ className: f(s.className, u),
47
+ ...c,
48
+ onClick: (t) => {
49
+ var i, a;
50
+ (i = s.onClick) == null || i.call(s, t), (a = c.onClick) == null || a.call(c, t);
51
+ }
52
+ });
53
+ }
54
+ return /* @__PURE__ */ e.createElement("button", { type: "button", className: f(n.u, u), ...c }, /* @__PURE__ */ e.createElement("span", { className: n.w }, l), o);
55
+ }
56
+ function ae({ className: l }) {
57
+ return /* @__PURE__ */ e.createElement("svg", { className: l, viewBox: "0 0 12 12", "aria-hidden": !0 }, /* @__PURE__ */ e.createElement(
58
+ "path",
59
+ {
60
+ d: "M2.5 4.5 6 8l3.5-3.5",
61
+ fill: "none",
62
+ stroke: "currentColor",
63
+ strokeWidth: "1.5",
64
+ strokeLinecap: "round",
65
+ strokeLinejoin: "round"
66
+ }
67
+ ));
68
+ }
69
+ function x({
70
+ items: l,
71
+ value: u,
72
+ open: c,
73
+ onSelect: o,
74
+ onToggle: s
75
+ }) {
76
+ return /* @__PURE__ */ e.createElement(e.Fragment, null, l.map((t) => {
77
+ const i = t.items, a = i != null && i.length > 0, E = a && c.includes(t.value), p = I(t.badge), m = !a && u === t.value;
78
+ return /* @__PURE__ */ e.createElement("li", { key: t.value }, /* @__PURE__ */ e.createElement(
79
+ F,
80
+ {
81
+ as: "button",
82
+ active: m,
83
+ className: f(n.i, m && n.a),
84
+ "aria-current": m ? "page" : void 0,
85
+ "aria-expanded": a ? E : void 0,
86
+ "data-open": E ? "true" : void 0,
87
+ onClick: () => {
88
+ a ? s(t.value) : o == null || o(t.value);
89
+ }
90
+ },
91
+ t.icon != null ? /* @__PURE__ */ e.createElement("span", { className: n.o, "aria-hidden": !0 }, t.icon) : null,
92
+ /* @__PURE__ */ e.createElement("span", { className: n.l }, t.label),
93
+ p != null ? /* @__PURE__ */ e.createElement(K, { className: n.d, tone: "accent", size: "s" }, p) : null,
94
+ a ? /* @__PURE__ */ e.createElement(ae, { className: n.c }) : null
95
+ ), a && E ? /* @__PURE__ */ e.createElement("ul", { className: n.m }, /* @__PURE__ */ e.createElement(
96
+ x,
97
+ {
98
+ items: i,
99
+ value: u,
100
+ open: c,
101
+ onSelect: o,
102
+ onToggle: s
103
+ }
104
+ )) : null);
105
+ }));
106
+ }
107
+ function pe({
108
+ groups: l,
109
+ items: u,
110
+ value: c,
111
+ onSelect: o,
112
+ open: s,
113
+ defaultOpen: t,
114
+ onOpenChange: i,
115
+ variant: a = "cards",
116
+ brand: E,
117
+ extra: p,
118
+ footer: m,
119
+ footerItems: g,
120
+ onFooterSelect: y,
121
+ footerMenuLabel: C = "Меню аккаунта",
122
+ version: v,
123
+ className: w,
124
+ "aria-label": q = "Основное меню"
125
+ }) {
126
+ const N = l ?? u ?? [], [d = [], k] = O(
127
+ s,
128
+ L(N, t, c),
129
+ i
130
+ ), h = e.useRef(c);
131
+ e.useEffect(() => {
132
+ if (c == null || c === h.current) {
133
+ h.current = c;
134
+ return;
135
+ }
136
+ h.current = c;
137
+ const b = M(N, c).filter((D) => !d.includes(D));
138
+ b.length && k([...d, ...b]);
139
+ }, [c, N, d, k]);
140
+ const B = (r) => {
141
+ k(
142
+ d.includes(r) ? d.filter((b) => b !== r) : [...d, r]
143
+ );
144
+ };
145
+ return /* @__PURE__ */ e.createElement(
146
+ "aside",
147
+ {
148
+ className: f(n.r, a === "plain" && n.p, w),
149
+ "aria-label": q
150
+ },
151
+ E != null || p != null ? /* @__PURE__ */ e.createElement("div", { className: n.b }, E, p != null ? /* @__PURE__ */ e.createElement("div", { className: n.x }, p) : null) : null,
152
+ /* @__PURE__ */ e.createElement("div", { className: n.g }, N.map((r) => /* @__PURE__ */ e.createElement("nav", { key: r.value, className: n.s, "aria-label": r.title ?? "Навигация" }, r.title ? /* @__PURE__ */ e.createElement("div", { className: n.h }, r.title) : null, /* @__PURE__ */ e.createElement("ul", { className: n.n }, /* @__PURE__ */ e.createElement(
153
+ x,
154
+ {
155
+ items: r.items ?? [],
156
+ value: c,
157
+ open: d,
158
+ onSelect: o,
159
+ onToggle: B
160
+ }
161
+ ))))),
162
+ m != null || v != null ? /* @__PURE__ */ e.createElement("div", { className: f(n.s, n.f) }, m != null && g != null && g.length > 0 ? /* @__PURE__ */ e.createElement(
163
+ R,
164
+ {
165
+ className: n.q,
166
+ align: "start",
167
+ placement: "top",
168
+ label: C,
169
+ trigger: /* @__PURE__ */ e.createElement(le, { footer: m, className: n.w }),
170
+ items: g,
171
+ onSelect: y
172
+ }
173
+ ) : m, v != null ? /* @__PURE__ */ e.createElement("div", { className: n.v }, v) : null) : null
174
+ );
175
+ }
176
+ export {
177
+ pe as S
178
+ };
package/dist/Sidebar.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.c2r{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;width:var(--sidebar-width, 248px);min-width:0;min-height:0;height:100%;max-height:100%;padding:var(--sidebar-pad-y, 16px) var(--sidebar-pad-x, 12px);gap:var(--shell-gap-sm, 8px);color:var(--shell-color);align-self:stretch}.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);border:1px solid var(--sidebar-block-border);border-radius:var(--sidebar-block-radius);box-shadow:var(--sidebar-block-shadow)}.c2h{margin:2px 10px 6px;font-size:var(--sidebar-group-font-size);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);border:0;border-radius:8px;background:transparent;color:var(--shell-color-muted);font-family:inherit;font-size:var(--sidebar-item-font-size);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);background:var(--sidebar-item-active-bg)}.c2o{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:inherit}.c2o :is(svg){display:block;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size)}.c2a .c2o{color:var(--sidebar-icon-active)}.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}.c2q{display:flex;width:100%;min-width:0;flex:0 0 auto;height:auto;align-items:center}.c2q>*{display:flex;width:100%;min-width:0;height:auto;align-items:center}.c2w{display:flex;width:100%;min-width:0;align-items:center}.c2u{display:flex;align-items:center;width:100%;min-width:0;gap:var(--shell-gap-sm);margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-align:left}.c2k{flex-shrink:0;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:var(--shell-color-muted)}.c2v{margin-top:var(--shell-gap-sm);font-size:11px;color:var(--shell-color-muted);text-align:center}@media (max-width: 900px){.c2r{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}}}
1
+ @layer elcrm-components{.c2r{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;width:var(--sidebar-width, 248px);min-width:0;min-height:0;height:100%;max-height:100%;padding:var(--sidebar-pad-y, 16px) var(--sidebar-pad-x, 12px);gap:var(--shell-gap-sm, 8px);color:var(--shell-color);align-self:stretch}.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);border:1px solid var(--sidebar-block-border);border-radius:var(--sidebar-block-radius);box-shadow:var(--sidebar-block-shadow)}.c2h{margin:2px 10px 6px;font-size:var(--sidebar-group-font-size);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);border:0;border-radius:8px;background:transparent;color:var(--shell-color-muted);font-family:inherit;font-size:var(--sidebar-item-font-size);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);background:var(--sidebar-item-active-bg)}.c2o{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:inherit}.c2o :is(svg){display:block;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size)}.c2a .c2o{color:var(--sidebar-icon-active)}.c2l{flex:1;min-width:0}.c2d{flex-shrink:0;min-width:16px;height:16px;padding:0 4px;font-size:10px}.c2c{flex-shrink:0;width:12px;height:12px;margin-left:auto;color:var(--shell-color-muted);transition:transform .15s ease}.c2n .c2i:is(button)[data-open=true] .c2c{transform:rotate(180deg);color:inherit}.c2m{margin:0;padding:0 0 0 var(--sidebar-indent);list-style:none}.c2m>li{list-style:none}.c2f{margin-top:auto}.c2q{display:flex;width:100%;min-width:0;flex:0 0 auto;height:auto;align-items:center}.c2q>*{display:flex;width:100%;min-width:0;height:auto;align-items:center}.c2w{display:flex;width:100%;min-width:0;align-items:center}.c2u{display:flex;align-items:center;width:100%;min-width:0;gap:var(--shell-gap-sm);margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-align:left}.c2k{flex-shrink:0;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:var(--shell-color-muted)}.c2v{margin-top:var(--shell-gap-sm);font-size:11px;color:var(--shell-color-muted);text-align:center}@media (max-width: 900px){.c2r{width:72px;padding:12px 8px}.c2l,.c2h,.c2v,.c2c,.c2m{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}}}
package/dist/Sidebar.d.ts CHANGED
@@ -11,6 +11,17 @@ export type SidebarItem = {
11
11
  icon?: React.ReactNode;
12
12
  /** Счётчик справа */
13
13
  badge?: number | string | null;
14
+ /**
15
+ * Вложенные пункты — есть → шеврон и раскрытие.
16
+ * Клик по родителю только открывает/закрывает, `onSelect` не зовём.
17
+ */
18
+ items?: SidebarItem[];
19
+ /**
20
+ * Подменю открыто при первом рендере.
21
+ * Если выбран потомок — ветка откроется сама.
22
+ * @default false
23
+ */
24
+ defaultOpen?: boolean;
14
25
  };
15
26
  /** Группа пунктов. `title` — «Аккаунт» / «Админ». */
16
27
  export type SidebarGroup = {
@@ -39,8 +50,23 @@ export type SidebarGroup = {
39
50
  * brand={<Brand as="strong">App</Brand>}
40
51
  * extra={<Notifications.Bell />}
41
52
  * groups={[
42
- * { value: "main", items: [{ value: "home", label: "Обзор", icon: <Icon /> }] },
43
- * { value: "admin", title: "Админ", items: [{ value: "users", label: "Люди" }] },
53
+ * {
54
+ * value: "docs",
55
+ * items: [
56
+ * { value: "games", label: "VK Games" },
57
+ * {
58
+ * value: "bridge",
59
+ * label: "VK Bridge",
60
+ * defaultOpen: true,
61
+ * items: [
62
+ * { value: "intro", label: "Введение" },
63
+ * { value: "events", label: "События", items: [
64
+ * { value: "evt-init", label: "VKWebAppInit" },
65
+ * ] },
66
+ * ],
67
+ * },
68
+ * ],
69
+ * },
44
70
  * ]}
45
71
  * footer={<AvatarName title="Паша" description="mail@…" />}
46
72
  * footerItems={[
@@ -62,8 +88,19 @@ export type SidebarProps = {
62
88
  items?: SidebarGroup[];
63
89
  /** Текущий пункт */
64
90
  value?: string;
65
- /** Выбор пункта */
91
+ /** Выбор пункта (только листья, без `items`) */
66
92
  onSelect?: (value: string) => void;
93
+ /**
94
+ * Раскрытые родители (их `value`). Контролируемый режим.
95
+ * Вместе с `onOpenChange`.
96
+ */
97
+ open?: string[];
98
+ /**
99
+ * Начально раскрытые (плюс `item.defaultOpen` и предки выбранного).
100
+ */
101
+ defaultOpen?: string[];
102
+ /** Смена набора раскрытых родителей */
103
+ onOpenChange?: (open: string[]) => void;
67
104
  /**
68
105
  * `cards` — блоки-карточки.
69
106
  * `plain` — плоский список.
@@ -96,4 +133,4 @@ export type SidebarProps = {
96
133
  *
97
134
  * @see Layout, Brand, Item, Badge, NavSections
98
135
  */
99
- export declare function Sidebar({ groups, items, value, onSelect, variant, brand, extra, footer, footerItems, onFooterSelect, footerMenuLabel, version, className, "aria-label": ariaLabel, }: SidebarProps): React.JSX.Element;
136
+ export declare function Sidebar({ groups, items, value, onSelect, open: openProp, defaultOpen, onOpenChange, variant, brand, extra, footer, footerItems, onFooterSelect, footerMenuLabel, version, className, "aria-label": ariaLabel, }: SidebarProps): React.JSX.Element;
package/dist/Sidebar.js CHANGED
@@ -1,4 +1,4 @@
1
- import { S as e } from "./Sidebar-BgZiGEDH.js";
1
+ import { S as e } from "./Sidebar-CYFaPqdC.js";
2
2
  export {
3
3
  e as Sidebar
4
4
  };
package/dist/Toolbar.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cCr{display:flex;flex-wrap:wrap;align-items:center;gap:var(--toolbar-gap);width:100%;min-width:0;box-sizing:border-box}.cCr[data-width=s]{display:inline-flex;width:auto;max-width:100%}.cCr[data-align=center]{justify-content:center}.cCr[data-align=end]{justify-content:flex-end}.cCr[data-align=between]{justify-content:space-between}.cCr[data-size=s]{--control-height: var(--control-height-s);--field-height: var(--control-height-s);--control-font-size: 13px;--button-height: var(--button-height-s);--button-height-m: var(--button-height-s);--button-padding: var(--button-padding-s);--button-size-m: var(--button-size-s)}.cCr[data-size=l]{--control-height: var(--control-height-l);--field-height: var(--control-height-l);--button-height: var(--button-height-l);--button-height-m: var(--button-height-l);--button-size-m: var(--button-size-l)}}
1
+ @layer elcrm-components{.cCr{display:flex;flex-wrap:wrap;align-items:center;gap:var(--toolbar-gap);width:100%;min-width:0;box-sizing:border-box;--field-width: auto}.cCr>[data-field]{flex:0 1 auto;width:auto;min-width:0;max-width:100%}.cCr>[data-field=search]{flex:1 1 var(--field-search-min-width, 10rem);width:auto!important;max-width:none}.cCr[data-width=s]{display:inline-flex;width:auto;max-width:100%}.cCr[data-align=center]{justify-content:center}.cCr[data-align=end]{justify-content:flex-end}.cCr[data-align=between]{justify-content:space-between}.cCr[data-size=s]{--control-height: var(--control-height-s);--field-height: var(--control-height-s);--control-font-size: 13px;--button-height: var(--button-height-s);--button-height-m: var(--button-height-s);--button-padding: var(--button-padding-s);--button-size-m: var(--button-size-s)}.cCr[data-size=l]{--control-height: var(--control-height-l);--field-height: var(--control-height-l);--button-height: var(--button-height-l);--button-height-m: var(--button-height-l);--button-size-m: var(--button-size-l)}}
package/dist/index.css CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
  @layer elcrm-components{.cmr{display:flex;align-items:center;gap:var(--shell-gap-sm);margin:0;padding:0;list-style:none}.cmv{flex-direction:column;align-items:stretch}.cmi{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;color:var(--button-color-muted);padding:var(--button-padding);border-radius:var(--button-radius);font:inherit;line-height:1;cursor:pointer;text-align:left;gap:var(--shell-gap-sm)}.cmd{flex-shrink:0;min-width:16px;height:16px;padding:0 4px;font-size:10px}.cmi>svg{display:block;flex-shrink:0}.cmi:hover{background:var(--button-background-hover);color:var(--button-color)}.cma,.cmi[aria-current=page],.cmi[data-active=true]{background:var(--button-background-selected);color:var(--button-color)}.cmu{width:100%;align-items:stretch;gap:1.25rem;padding:0;border-bottom:1px solid var(--shell-border)}.cmu .cmi{border-radius:0;background:transparent;padding:.45rem .1rem .55rem;border-bottom:2px solid transparent;margin-bottom:-1px}.cmu .cmi:hover{background:transparent;color:var(--shell-color)}.cmu .cma,.cmu .cmi[aria-current=page],.cmu .cmi[data-active=true]{background:transparent;color:var(--shell-color);border-bottom-color:var(--shell-color-accent)}}
40
40
 
41
- @layer elcrm-components{.cvr{display:flex;align-items:stretch;gap:var(--shell-gap-lg);width:100%;flex:1 1 auto;min-height:0;box-sizing:border-box;padding:var(--nav-sections-padding)}.cvn{display:flex;flex-direction:column;gap:var(--shell-gap);flex:0 0 var(--nav-sections-nav-width);width:var(--nav-sections-nav-width);min-width:var(--nav-sections-nav-width);box-sizing:border-box}.cvg{display:flex;flex-direction:column;gap:2px;padding-bottom:var(--shell-gap);border-bottom:1px solid var(--shell-border)}.cvg:last-of-type{border-bottom:none;padding-bottom:0}.cvl{font-size:var(--sidebar-group-font-size);font-weight:var(--shell-font-weight);letter-spacing:.04em;text-transform:uppercase;color:var(--shell-color-muted);padding:0 var(--shell-padding-inline) var(--shell-gap-sm)}.cvi:is(button){position:relative;font-size:var(--shell-font-size-sm)}.cva:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--shell-color-accent)}.cvi:disabled{opacity:var(--shell-disabled-opacity);cursor:not-allowed}.cvc{display:inline-flex;flex:0 0 auto;color:var(--shell-color-muted);line-height:0}.cva .cvc{color:var(--shell-color)}.cvt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cvf{margin-top:auto;padding-top:var(--shell-gap);border-top:1px solid var(--shell-border)}.cvm{flex:1 1 auto;min-width:0;max-width:var(--nav-sections-main-max-width);width:100%;min-height:0;overflow:auto}@media (max-width: 720px){.cvr{flex-direction:column}.cvn{flex:none;width:100%;min-width:0;max-width:none}}}
41
+ @layer elcrm-components{.cvr{display:flex;align-items:stretch;gap:var(--shell-gap-lg);width:100%;flex:1 1 auto;min-height:0;box-sizing:border-box;padding:var(--nav-sections-padding)}.cvn{display:flex;flex-direction:column;gap:var(--shell-gap);flex:0 0 var(--nav-sections-nav-width);width:var(--nav-sections-nav-width);min-width:var(--nav-sections-nav-width);box-sizing:border-box}.cvg{display:flex;flex-direction:column;gap:2px;padding-bottom:var(--shell-gap);border-bottom:1px solid var(--shell-border)}.cvg:last-of-type{border-bottom:none;padding-bottom:0}.cvl{font-size:var(--sidebar-group-font-size);font-weight:var(--shell-font-weight);letter-spacing:.04em;text-transform:uppercase;color:var(--shell-color-muted);padding:0 var(--shell-padding-inline) var(--shell-gap-sm)}.cvi:is(button){position:relative;display:flex;width:100%;align-items:center;font-size:var(--shell-font-size-sm)}.cva:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--shell-color-accent)}.cvi:disabled{opacity:var(--shell-disabled-opacity);cursor:not-allowed}.cvc{display:inline-flex;flex:0 0 auto;color:var(--shell-color-muted);line-height:0}.cva .cvc{color:var(--shell-color)}.cvt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cve{flex-shrink:0;width:12px;height:12px;margin-left:auto;color:var(--shell-color-muted);transition:transform .15s ease}.cvi:is(button)[data-open=true] .cve{transform:rotate(180deg);color:inherit}.cvs{display:flex;flex-direction:column;gap:2px;padding-inline-start:var(--sidebar-indent)}.cvf{margin-top:auto;padding-top:var(--shell-gap);border-top:1px solid var(--shell-border)}.cvm{flex:1 1 auto;min-width:0;max-width:var(--nav-sections-main-max-width);width:100%;min-height:0;overflow:auto}@media (max-width: 720px){.cvr{flex-direction:column}.cvn{flex:none;width:100%;min-width:0;max-width:none}}}
42
42
 
43
43
  @layer elcrm-components{.ccr{display:flex;flex-direction:column;gap:var(--shell-gap);margin:0 0 var(--shell-gap)}.cck{position:sticky;top:0;z-index:var(--shell-z);background:var(--shell-bg)}.ccw{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--shell-gap-sm)}.cct{min-width:0;max-width:36rem}.cch{margin:0;display:flex;align-items:flex-start;gap:.4em;font-size:var(--section-title-size);font-weight:var(--shell-font-weight);color:var(--shell-color);line-height:1.15}.ccn{min-width:0}.ccu{display:inline-flex;align-items:center;margin-top:.12em;font-size:.7rem;font-weight:600;line-height:1;color:var(--shell-color-muted)}.ccs{margin:var(--shell-gap-sm) 0 0;font-size:var(--shell-font-size);color:var(--shell-color-muted);line-height:1.45}.cca{display:flex;flex-wrap:wrap;align-items:center;gap:var(--shell-gap-sm)}.ccc{display:flex;flex-direction:column;gap:var(--shell-gap);min-width:0}}
44
44
 
@@ -56,7 +56,7 @@
56
56
 
57
57
  @layer elcrm-components{.cep{display:flex;flex-direction:column;gap:var(--shell-gap);padding:var(--section-padding);flex:1;min-width:0}.ceu{box-sizing:border-box;min-height:100svh;display:flex;align-items:center;justify-content:center;padding:var(--section-padding)}.cek{box-sizing:border-box;width:100%;max-width:var(--section-auth-card-max-width);padding:var(--shell-gap-lg);background:var(--shell-background);border:1px solid var(--shell-border);border-radius:var(--shell-radius);box-shadow:var(--shell-shadow);display:flex;flex-direction:column;gap:var(--shell-gap)}.ceh{display:flex;flex-direction:column;gap:var(--shell-gap-sm)}.cec{text-align:center;align-items:center}.cei{display:flex;margin-bottom:var(--shell-gap-sm)}.cec .cei{justify-content:center}.cet{margin:0;font-size:var(--section-title-size);font-weight:var(--shell-font-weight);letter-spacing:-.02em;color:var(--shell-color);line-height:1.25}.ced{font-size:var(--section-title-size-md)}.cee{margin:0;font-size:var(--shell-font-size);color:var(--shell-color-muted);line-height:1.45}.ceb{display:flex;flex-direction:column;gap:var(--shell-gap);width:100%;text-align:left}.ces{display:flex;flex-direction:column;gap:var(--shell-gap-sm);width:100%}.cel{display:flex;flex-direction:column;gap:var(--shell-gap);margin-bottom:var(--shell-gap-lg);padding-bottom:var(--shell-gap-lg);border-bottom:1px solid var(--shell-border)}.cel:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}.cel .cet{font-size:var(--shell-font-size);font-weight:var(--shell-font-weight)}}
58
58
 
59
- @layer elcrm-components{.c2r{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;width:var(--sidebar-width, 248px);min-width:0;min-height:0;height:100%;max-height:100%;padding:var(--sidebar-pad-y, 16px) var(--sidebar-pad-x, 12px);gap:var(--shell-gap-sm, 8px);color:var(--shell-color);align-self:stretch}.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);border:1px solid var(--sidebar-block-border);border-radius:var(--sidebar-block-radius);box-shadow:var(--sidebar-block-shadow)}.c2h{margin:2px 10px 6px;font-size:var(--sidebar-group-font-size);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);border:0;border-radius:8px;background:transparent;color:var(--shell-color-muted);font-family:inherit;font-size:var(--sidebar-item-font-size);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);background:var(--sidebar-item-active-bg)}.c2o{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:inherit}.c2o :is(svg){display:block;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size)}.c2a .c2o{color:var(--sidebar-icon-active)}.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}.c2q{display:flex;width:100%;min-width:0;flex:0 0 auto;height:auto;align-items:center}.c2q>*{display:flex;width:100%;min-width:0;height:auto;align-items:center}.c2w{display:flex;width:100%;min-width:0;align-items:center}.c2u{display:flex;align-items:center;width:100%;min-width:0;gap:var(--shell-gap-sm);margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-align:left}.c2k{flex-shrink:0;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:var(--shell-color-muted)}.c2v{margin-top:var(--shell-gap-sm);font-size:11px;color:var(--shell-color-muted);text-align:center}@media (max-width: 900px){.c2r{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}}}
59
+ @layer elcrm-components{.c2r{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;width:var(--sidebar-width, 248px);min-width:0;min-height:0;height:100%;max-height:100%;padding:var(--sidebar-pad-y, 16px) var(--sidebar-pad-x, 12px);gap:var(--shell-gap-sm, 8px);color:var(--shell-color);align-self:stretch}.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);border:1px solid var(--sidebar-block-border);border-radius:var(--sidebar-block-radius);box-shadow:var(--sidebar-block-shadow)}.c2h{margin:2px 10px 6px;font-size:var(--sidebar-group-font-size);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);border:0;border-radius:8px;background:transparent;color:var(--shell-color-muted);font-family:inherit;font-size:var(--sidebar-item-font-size);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);background:var(--sidebar-item-active-bg)}.c2o{display:inline-flex;flex-shrink:0;align-items:center;justify-content:center;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:inherit}.c2o :is(svg){display:block;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size)}.c2a .c2o{color:var(--sidebar-icon-active)}.c2l{flex:1;min-width:0}.c2d{flex-shrink:0;min-width:16px;height:16px;padding:0 4px;font-size:10px}.c2c{flex-shrink:0;width:12px;height:12px;margin-left:auto;color:var(--shell-color-muted);transition:transform .15s ease}.c2n .c2i:is(button)[data-open=true] .c2c{transform:rotate(180deg);color:inherit}.c2m{margin:0;padding:0 0 0 var(--sidebar-indent);list-style:none}.c2m>li{list-style:none}.c2f{margin-top:auto}.c2q{display:flex;width:100%;min-width:0;flex:0 0 auto;height:auto;align-items:center}.c2q>*{display:flex;width:100%;min-width:0;height:auto;align-items:center}.c2w{display:flex;width:100%;min-width:0;align-items:center}.c2u{display:flex;align-items:center;width:100%;min-width:0;gap:var(--shell-gap-sm);margin:0;padding:0;border:none;background:transparent;font:inherit;color:inherit;cursor:pointer;text-align:left}.c2k{flex-shrink:0;width:var(--sidebar-icon-size);height:var(--sidebar-icon-size);color:var(--shell-color-muted)}.c2v{margin-top:var(--shell-gap-sm);font-size:11px;color:var(--shell-color-muted);text-align:center}@media (max-width: 900px){.c2r{width:72px;padding:12px 8px}.c2l,.c2h,.c2v,.c2c,.c2m{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}}}
60
60
 
61
61
  @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)}}
62
62
 
@@ -66,4 +66,4 @@
66
66
 
67
67
  @layer elcrm-components{.c6r{display:flex;flex-direction:column;gap:2px;min-width:0;text-align:left}.c6t{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}.c6d{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}.c6s .c6t{font-size:var(--shell-font-size-sm)}.c6l .c6t{font-size:var(--shell-font-size-lg)}.c6l .c6d{font-size:var(--shell-font-size)}}
68
68
 
69
- @layer elcrm-components{.cCr{display:flex;flex-wrap:wrap;align-items:center;gap:var(--toolbar-gap);width:100%;min-width:0;box-sizing:border-box}.cCr[data-width=s]{display:inline-flex;width:auto;max-width:100%}.cCr[data-align=center]{justify-content:center}.cCr[data-align=end]{justify-content:flex-end}.cCr[data-align=between]{justify-content:space-between}.cCr[data-size=s]{--control-height: var(--control-height-s);--field-height: var(--control-height-s);--control-font-size: 13px;--button-height: var(--button-height-s);--button-height-m: var(--button-height-s);--button-padding: var(--button-padding-s);--button-size-m: var(--button-size-s)}.cCr[data-size=l]{--control-height: var(--control-height-l);--field-height: var(--control-height-l);--button-height: var(--button-height-l);--button-height-m: var(--button-height-l);--button-size-m: var(--button-size-l)}}
69
+ @layer elcrm-components{.cCr{display:flex;flex-wrap:wrap;align-items:center;gap:var(--toolbar-gap);width:100%;min-width:0;box-sizing:border-box;--field-width: auto}.cCr>[data-field]{flex:0 1 auto;width:auto;min-width:0;max-width:100%}.cCr>[data-field=search]{flex:1 1 var(--field-search-min-width, 10rem);width:auto!important;max-width:none}.cCr[data-width=s]{display:inline-flex;width:auto;max-width:100%}.cCr[data-align=center]{justify-content:center}.cCr[data-align=end]{justify-content:flex-end}.cCr[data-align=between]{justify-content:space-between}.cCr[data-size=s]{--control-height: var(--control-height-s);--field-height: var(--control-height-s);--control-font-size: 13px;--button-height: var(--button-height-s);--button-height-m: var(--button-height-s);--button-padding: var(--button-padding-s);--button-size-m: var(--button-size-s)}.cCr[data-size=l]{--control-height: var(--control-height-l);--field-height: var(--control-height-l);--button-height: var(--button-height-l);--button-height-m: var(--button-height-l);--button-size-m: var(--button-size-l)}}
package/dist/index.es.js CHANGED
@@ -18,7 +18,7 @@ import { D as j } from "./Dropdown-DosvDR13.js";
18
18
  import { B as K } from "./Breadcrumb-CAM_e9LN.js";
19
19
  import { L as U } from "./Loading-DkkG7RcE.js";
20
20
  import { S as W } from "./Section-Crxk2J-E.js";
21
- import { N as Y } from "./NavSections-BpyZPimZ.js";
21
+ import { N as Y } from "./NavSections-D6rDEtT1.js";
22
22
  import { T as $ } from "./TabSections-DN7yVJoF.js";
23
23
  import { A as or, a as ar, i as er } from "./Avatar-loGgFt72.js";
24
24
  import { A as sr } from "./AvatarGroup-D1gnT3Od.js";
@@ -34,7 +34,7 @@ import { P as Br } from "./PageShell-D9EZiO8o.js";
34
34
  import { C as Lr, a as br } from "./ChatSplit-DNnu3TNq.js";
35
35
  import { C as Rr } from "./ChatFrame-BW2TmCkZ.js";
36
36
  import { C as Hr } from "./ChatMessages-B8rdXiK-.js";
37
- import { S as kr } from "./Sidebar-BgZiGEDH.js";
37
+ import { S as kr } from "./Sidebar-CYFaPqdC.js";
38
38
  import { P as Nr } from "./Popover-DWdvZTuA.js";
39
39
  import { H as Mr } from "./Healthmap-B6cdiLUl.js";
40
40
  import { P as Zr } from "./PanelInfo-A5y5ysH8.js";
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "format": "elcrm-kit-manifest-v1",
3
3
  "package": "@elcrm/components",
4
- "version": "0.2.8",
4
+ "version": "0.2.11",
5
5
  "pkg": "components",
6
- "generatedAt": "2026-08-22T21:22:46.462Z",
6
+ "generatedAt": "2026-08-23T09:13:24.421Z",
7
7
  "components": [
8
8
  {
9
9
  "slug": "ActionGroup",
@@ -749,12 +749,12 @@
749
749
  {
750
750
  "slug": "NavSections",
751
751
  "title": "NavSections",
752
- "description": "Макет «настройки / профиль»: вертикальный сайдбар + lazy-секция справа. Когда использовать: - страницы с несколькими разделами и боковым меню; - контент секции грузится по `value` через `resolveSection`. Связанные компоненты: - {@link TabSections} — то же, но вкладки горизонтально; - {@link createLazyResolver} из `lazyRoute` — кэш lazy-импортов; - {@link Menu} — простая навигация без панелей. API: декларативные `groups` / `items`. Идентификатор раздела — `value` (не `key`). Compound-слоты (`NavSections.Item`) не используются. CSS-токены: `--shell-*`, `--nav-sections-padding`, `--nav-sections-nav-width`, `--nav-sections-main-max-width`.",
752
+ "description": "Макет «настройки / профиль»: вертикальный сайдбар + lazy-секция справа. Когда использовать: - страницы с несколькими разделами и боковым меню; - контент секции грузится по `value` через `resolveSection`. Связанные компоненты: - {@link TabSections} — то же, но вкладки горизонтально; - {@link createLazyResolver} из `lazyRoute` — кэш lazy-импортов; - {@link Menu} — простая навигация без панелей. API: декларативные `groups` / `items`. Идентификатор раздела — `value` (не `key`). У пункта `items` + `defaultOpen` — раскрываемое подменю (как у Sidebar). Compound-слоты (`NavSections.Item`) не используются. CSS-токены: `--shell-*`, `--nav-sections-padding`, `--nav-sections-nav-width`, `--nav-sections-main-max-width`, `--sidebar-indent`.",
753
753
  "importFrom": "@elcrm/components",
754
754
  "examples": [
755
755
  {
756
756
  "title": "Пример",
757
- "code": "const groups = [\n {\n label: \"Личное\",\n items: [\n { value: \"profile\", label: \"Профиль\", icon: <Icons.Line name=\"user\" /> },\n { value: \"security\", label: \"Безопасность\" },\n ],\n },\n];\n\nconst resolveSection = createLazyResolver(\n (v) => import(`./sections/${v}.tsx`),\n);\n\n<NavSections\n groups={groups}\n resolveSection={resolveSection}\n value={section}\n onValueChange={setSection}\n footer={<Button onSend={() => navigate(-1)}>Назад</Button>}\n/>"
757
+ "code": "const groups = [\n {\n label: \"Документация\",\n items: [\n {\n value: \"bridge\",\n label: \"VK Bridge\",\n defaultOpen: true,\n items: [\n { value: \"intro\", label: \"Введение\" },\n { value: \"events\", label: \"События\", items: [\n { value: \"evt-init\", label: \"VKWebAppInit\" },\n ] },\n ],\n },\n { value: \"auth\", label: \"Авторизация VK\" },\n ],\n },\n];\n\n<NavSections\n groups={groups}\n resolveSection={resolveSection}\n value={section}\n onValueChange={setSection}\n/>"
758
758
  }
759
759
  ],
760
760
  "props": [
@@ -783,6 +783,21 @@
783
783
  "type": "(value: string) => void",
784
784
  "description": "Смена активного раздела (`next` = `item.value`)."
785
785
  },
786
+ {
787
+ "name": "open",
788
+ "type": "string[]",
789
+ "description": "Раскрытые родители (их `value`). Контролируемый режим. Вместе с `onOpenChange`."
790
+ },
791
+ {
792
+ "name": "defaultOpen",
793
+ "type": "string[]",
794
+ "description": "Начально раскрытые (плюс `item.defaultOpen` и предки выбранного)."
795
+ },
796
+ {
797
+ "name": "onOpenChange",
798
+ "type": "(open: string[]) => void",
799
+ "description": "Смена набора раскрытых родителей"
800
+ },
786
801
  {
787
802
  "name": "loading",
788
803
  "type": "React.ReactNode",
@@ -1228,7 +1243,7 @@
1228
1243
  "examples": [
1229
1244
  {
1230
1245
  "title": "Пример",
1231
- "code": "<Sidebar\n variant=\"cards\"\n value={page}\n onSelect={setPage}\n brand={<Brand as=\"strong\">App</Brand>}\n extra={<Notifications.Bell />}\n groups={[\n { value: \"main\", items: [{ value: \"home\", label: \"Обзор\", icon: <Icon /> }] },\n { value: \"admin\", title: \"Админ\", items: [{ value: \"users\", label: \"Люди\" }] },\n ]}\n footer={<AvatarName title=\"Паша\" description=\"mail@…\" />}\n footerItems={[\n { value: \"home\", label: \"Главная\", icon: <Icon /> },\n { value: \"theme\", label: \"Тема\", submenu: true },\n { value: \"logout\", label: \"Выйти\", danger: true },\n ]}\n onFooterSelect={(value) => console.log(value)}\n version=\"v 0.2.26\"\n/>"
1246
+ "code": "<Sidebar\n variant=\"cards\"\n value={page}\n onSelect={setPage}\n brand={<Brand as=\"strong\">App</Brand>}\n extra={<Notifications.Bell />}\n groups={[\n {\n value: \"docs\",\n items: [\n { value: \"games\", label: \"VK Games\" },\n {\n value: \"bridge\",\n label: \"VK Bridge\",\n defaultOpen: true,\n items: [\n { value: \"intro\", label: \"Введение\" },\n { value: \"events\", label: \"События\", items: [\n { value: \"evt-init\", label: \"VKWebAppInit\" },\n ] },\n ],\n },\n ],\n },\n ]}\n footer={<AvatarName title=\"Паша\" description=\"mail@…\" />}\n footerItems={[\n { value: \"home\", label: \"Главная\", icon: <Icon /> },\n { value: \"theme\", label: \"Тема\", submenu: true },\n { value: \"logout\", label: \"Выйти\", danger: true },\n ]}\n onFooterSelect={(value) => console.log(value)}\n version=\"v 0.2.26\"\n/>"
1232
1247
  }
1233
1248
  ],
1234
1249
  "props": [
@@ -1250,7 +1265,22 @@
1250
1265
  {
1251
1266
  "name": "onSelect",
1252
1267
  "type": "(value: string) => void",
1253
- "description": "Выбор пункта"
1268
+ "description": "Выбор пункта (только листья, без `items`)"
1269
+ },
1270
+ {
1271
+ "name": "open",
1272
+ "type": "string[]",
1273
+ "description": "Раскрытые родители (их `value`). Контролируемый режим. Вместе с `onOpenChange`."
1274
+ },
1275
+ {
1276
+ "name": "defaultOpen",
1277
+ "type": "string[]",
1278
+ "description": "Начально раскрытые (плюс `item.defaultOpen` и предки выбранного)."
1279
+ },
1280
+ {
1281
+ "name": "onOpenChange",
1282
+ "type": "(open: string[]) => void",
1283
+ "description": "Смена набора раскрытых родителей"
1254
1284
  },
1255
1285
  {
1256
1286
  "name": "variant",
@@ -0,0 +1,57 @@
1
+ function o(e, n, t = []) {
2
+ var u;
3
+ for (const a of e ?? [])
4
+ n(a, t), (u = a.items) != null && u.length && o(a.items, n, [...t, a.value]);
5
+ }
6
+ function f(e, n) {
7
+ for (const t of e)
8
+ o(t.items, n);
9
+ }
10
+ function r(e, n) {
11
+ if (n == null) return [];
12
+ let t = null;
13
+ return f(e, (u, a) => {
14
+ u.value === n && (t = a);
15
+ }), t ?? [];
16
+ }
17
+ function i(e, n, t) {
18
+ const u = new Set(n ?? []);
19
+ f(e, (a) => {
20
+ var l;
21
+ a.defaultOpen && ((l = a.items) != null && l.length) && u.add(a.value);
22
+ });
23
+ for (const a of r(e, t)) u.add(a);
24
+ return [...u];
25
+ }
26
+ function c(e, n) {
27
+ if (n == null) return !1;
28
+ let t = !1;
29
+ return f(e, (u) => {
30
+ var a;
31
+ u.value === n && ((a = u.items) != null && a.length) && (t = !0);
32
+ }), t;
33
+ }
34
+ function s(e) {
35
+ const n = [];
36
+ return f(e, (t) => {
37
+ var u;
38
+ !((u = t.items) != null && u.length) && !t.disabled && n.push(t);
39
+ }), n;
40
+ }
41
+ function d(e) {
42
+ var n;
43
+ return ((n = s(e)[0]) == null ? void 0 : n.value) ?? "";
44
+ }
45
+ function v(e) {
46
+ const n = [];
47
+ return f(e, (t) => {
48
+ t.disabled || n.push(t);
49
+ }), n;
50
+ }
51
+ export {
52
+ v as a,
53
+ r as b,
54
+ i as c,
55
+ d as f,
56
+ c as i
57
+ };
@@ -0,0 +1,33 @@
1
+ /** Узел дерева меню (Sidebar / NavSections). */
2
+ export type NavTreeNode = {
3
+ value: string;
4
+ items?: NavTreeNode[];
5
+ defaultOpen?: boolean;
6
+ disabled?: boolean;
7
+ };
8
+ export declare function walkNavTree<T extends NavTreeNode>(items: T[] | undefined, fn: (item: T, ancestors: string[]) => void, ancestors?: string[]): void;
9
+ export declare function walkNavGroups<T extends NavTreeNode>(groups: {
10
+ items?: T[];
11
+ }[], fn: (item: T, ancestors: string[]) => void): void;
12
+ /** Предки выбранного листа — ветку нужно раскрыть. */
13
+ export declare function findNavAncestors<T extends NavTreeNode>(groups: {
14
+ items?: T[];
15
+ }[], selected: string | undefined): string[];
16
+ /** Стартовый набор раскрытых: defaultOpen + extra + предки selected. */
17
+ export declare function collectNavDefaultOpen<T extends NavTreeNode>(groups: {
18
+ items?: T[];
19
+ }[], extra: string[] | undefined, selected: string | undefined): string[];
20
+ export declare function isNavParent<T extends NavTreeNode>(groups: {
21
+ items?: T[];
22
+ }[], value: string | undefined): boolean;
23
+ /** Листья без `items` (для панели / firstValue). */
24
+ export declare function flattenNavLeaves<T extends NavTreeNode>(groups: {
25
+ items?: T[];
26
+ }[]): T[];
27
+ export declare function firstNavLeafValue<T extends NavTreeNode>(groups: {
28
+ items?: T[];
29
+ }[]): string;
30
+ /** Все доступные пункты (родители + листья) — для клавиатуры. */
31
+ export declare function flattenNavEnabled<T extends NavTreeNode>(groups: {
32
+ items?: T[];
33
+ }[]): T[];
package/dist/tokens.css CHANGED
@@ -113,6 +113,7 @@
113
113
  --sidebar-item-padding: 6px 10px;
114
114
  --sidebar-icon-size: 16px;
115
115
  --sidebar-group-font-size: 11px;
116
+ --sidebar-indent: 14px;
116
117
 
117
118
  /* —— chat —— */
118
119
  --chat-list-width: 340px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elcrm/components",
3
- "version": "0.2.8",
3
+ "version": "0.2.11",
4
4
  "description": "Shell UI elCRM: Layout, Header, Sidebar, Popover, Healthmap, PanelInfo, PageHead, PageShell, Section, Stack, Stat и др.",
5
5
  "type": "module",
6
6
  "author": "MaSkal <dev@elcrm.online>",
@@ -1,79 +0,0 @@
1
- import a, { useMemo as h, Suspense as S } from "react";
2
- import { c as d } from "./cx-CcykAxZN.js";
3
- import { I as g } from "./Item-D4okhsfW.js";
4
- import { h as x } from "./rovingKeys-CGlfTtNQ.js";
5
- import { u as C } from "./useControllableValue-CWqH1kpM.js";
6
- import './NavSections.css';const I = "cvr", K = "cvn", M = "cvg", R = "cvl", V = "cvi", w = "cva", D = "cvc", P = "cvt", j = "cvf", q = "cvm", l = {
7
- r: I,
8
- n: K,
9
- g: M,
10
- l: R,
11
- i: V,
12
- a: w,
13
- c: D,
14
- t: P,
15
- f: j,
16
- m: q
17
- };
18
- function z(n) {
19
- for (const m of n) {
20
- const c = m.items.find((s) => !s.disabled);
21
- if (c) return c.value;
22
- }
23
- return "";
24
- }
25
- function J({
26
- groups: n,
27
- resolveSection: m,
28
- value: c,
29
- defaultValue: s,
30
- onValueChange: f,
31
- loading: b = null,
32
- footer: i,
33
- className: E,
34
- navLabel: N = "Разделы"
35
- }) {
36
- const p = h(
37
- () => s || z(n),
38
- [s, n]
39
- ), [r, v] = C(
40
- c,
41
- p,
42
- f
43
- ), k = n.flatMap((e) => e.items).filter((e) => !e.disabled).map((e) => e.value), u = r ? m(r) : null;
44
- return /* @__PURE__ */ a.createElement("div", { className: d(l.r, E) }, /* @__PURE__ */ a.createElement(
45
- "nav",
46
- {
47
- className: l.n,
48
- "aria-label": N,
49
- onKeyDown: (e) => x(e, {
50
- values: k,
51
- value: r,
52
- onSelect: v,
53
- vertical: !0
54
- })
55
- },
56
- n.map((e, y) => /* @__PURE__ */ a.createElement("div", { key: y, className: l.g }, e.label != null ? /* @__PURE__ */ a.createElement("div", { className: l.l }, e.label) : null, e.items.map((t) => {
57
- const o = t.value === r;
58
- return /* @__PURE__ */ a.createElement(
59
- g,
60
- {
61
- key: t.value,
62
- as: "button",
63
- active: o,
64
- className: d(l.i, o && l.a),
65
- "data-active": o ? "true" : void 0,
66
- "aria-current": o ? "page" : void 0,
67
- disabled: t.disabled,
68
- onClick: () => v(t.value)
69
- },
70
- t.icon != null ? /* @__PURE__ */ a.createElement("span", { className: l.c, "aria-hidden": !0 }, t.icon) : null,
71
- /* @__PURE__ */ a.createElement("span", { className: l.t }, t.label)
72
- );
73
- }))),
74
- i != null ? /* @__PURE__ */ a.createElement("div", { className: l.f }, i) : null
75
- ), /* @__PURE__ */ a.createElement("div", { className: l.m }, u ? /* @__PURE__ */ a.createElement(S, { fallback: b }, a.createElement(u)) : null));
76
- }
77
- export {
78
- J as N
79
- };
@@ -1,108 +0,0 @@
1
- import e from "react";
2
- import { B as h } from "./Badge-jp-9iNNL.js";
3
- import { D as w } from "./Dropdown-DosvDR13.js";
4
- import { I as y } from "./Item-D4okhsfW.js";
5
- import { b as C } from "./badgeText-CRzlIzi3.js";
6
- import { c as u } from "./cx-CcykAxZN.js";
7
- import './Sidebar.css';const q = "c2r", B = "c2b", D = "c2x", T = "c2g", z = "c2s", F = "c2p", I = "c2h", M = "c2n", R = "c2i", V = "c2a", $ = "c2o", j = "c2l", A = "c2d", G = "c2f", H = "c2q", J = "c2w", K = "c2u", L = "c2k", O = "c2v", l = {
8
- r: q,
9
- b: B,
10
- x: D,
11
- g: T,
12
- s: z,
13
- p: F,
14
- h: I,
15
- n: M,
16
- i: R,
17
- a: V,
18
- o: $,
19
- l: j,
20
- d: A,
21
- f: G,
22
- q: H,
23
- w: J,
24
- u: K,
25
- k: L,
26
- v: O
27
- };
28
- function P({ className: c }) {
29
- return /* @__PURE__ */ e.createElement("svg", { className: c, viewBox: "0 0 16 16", "aria-hidden": !0 }, /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "3", r: "1.3", fill: "currentColor" }), /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "8", r: "1.3", fill: "currentColor" }), /* @__PURE__ */ e.createElement("circle", { cx: "8", cy: "13", r: "1.3", fill: "currentColor" }));
30
- }
31
- function Q({
32
- footer: c,
33
- className: E,
34
- ...a
35
- }) {
36
- const r = /* @__PURE__ */ e.createElement(P, { className: l.k });
37
- if (e.isValidElement(c) && typeof c.type != "string") {
38
- const n = c.props;
39
- return e.cloneElement(c, {
40
- as: "button",
41
- extra: n.extra ?? r,
42
- className: u(n.className, E),
43
- ...a,
44
- onClick: (i) => {
45
- var m, t;
46
- (m = n.onClick) == null || m.call(n, i), (t = a.onClick) == null || t.call(a, i);
47
- }
48
- });
49
- }
50
- return /* @__PURE__ */ e.createElement("button", { type: "button", className: u(l.u, E), ...a }, /* @__PURE__ */ e.createElement("span", { className: l.w }, c), r);
51
- }
52
- function S({
53
- groups: c,
54
- items: E,
55
- value: a,
56
- onSelect: r,
57
- variant: n = "cards",
58
- brand: i,
59
- extra: m,
60
- footer: t,
61
- footerItems: d,
62
- onFooterSelect: v,
63
- footerMenuLabel: g = "Меню аккаунта",
64
- version: p,
65
- className: k,
66
- "aria-label": x = "Основное меню"
67
- }) {
68
- const f = c ?? E ?? [];
69
- return /* @__PURE__ */ e.createElement(
70
- "aside",
71
- {
72
- className: u(l.r, n === "plain" && l.p, k),
73
- "aria-label": x
74
- },
75
- i != null || m != null ? /* @__PURE__ */ e.createElement("div", { className: l.b }, i, m != null ? /* @__PURE__ */ e.createElement("div", { className: l.x }, m) : null) : null,
76
- /* @__PURE__ */ e.createElement("div", { className: l.g }, f.map((o) => /* @__PURE__ */ e.createElement("nav", { key: o.value, className: l.s, "aria-label": o.title ?? "Навигация" }, o.title ? /* @__PURE__ */ e.createElement("div", { className: l.h }, o.title) : null, /* @__PURE__ */ e.createElement("ul", { className: l.n }, (o.items ?? []).map((s) => {
77
- const b = C(s.badge), N = a === s.value;
78
- return /* @__PURE__ */ e.createElement("li", { key: s.value }, /* @__PURE__ */ e.createElement(
79
- y,
80
- {
81
- as: "button",
82
- active: N,
83
- className: u(l.i, N && l.a),
84
- "aria-current": N ? "page" : void 0,
85
- onClick: () => r == null ? void 0 : r(s.value)
86
- },
87
- s.icon != null ? /* @__PURE__ */ e.createElement("span", { className: l.o, "aria-hidden": !0 }, s.icon) : null,
88
- /* @__PURE__ */ e.createElement("span", { className: l.l }, s.label),
89
- b != null ? /* @__PURE__ */ e.createElement(h, { className: l.d, tone: "accent", size: "s" }, b) : null
90
- ));
91
- }))))),
92
- t != null || p != null ? /* @__PURE__ */ e.createElement("div", { className: u(l.s, l.f) }, t != null && d != null && d.length > 0 ? /* @__PURE__ */ e.createElement(
93
- w,
94
- {
95
- className: l.q,
96
- align: "start",
97
- placement: "top",
98
- label: g,
99
- trigger: /* @__PURE__ */ e.createElement(Q, { footer: t, className: l.w }),
100
- items: d,
101
- onSelect: v
102
- }
103
- ) : t, p != null ? /* @__PURE__ */ e.createElement("div", { className: l.v }, p) : null) : null
104
- );
105
- }
106
- export {
107
- S
108
- };