@elcrm/components 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/README.md +450 -202
  2. package/dist/Avatar-Jzan87XD.js +101 -0
  3. package/dist/Avatar.css +1 -1
  4. package/dist/Avatar.d.ts +81 -2
  5. package/dist/Avatar.js +1 -1
  6. package/dist/AvatarGroup-DUe7-T3B.js +81 -0
  7. package/dist/AvatarGroup.css +1 -0
  8. package/dist/AvatarGroup.d.ts +77 -0
  9. package/dist/AvatarGroup.js +4 -0
  10. package/dist/AvatarName-KBbQrVta.js +56 -0
  11. package/dist/AvatarName.css +1 -0
  12. package/dist/AvatarName.d.ts +76 -0
  13. package/dist/AvatarName.js +4 -0
  14. package/dist/Badge.css +1 -1
  15. package/dist/Badge.d.ts +26 -2
  16. package/dist/Block-BAXh0PPp.js +8 -0
  17. package/dist/Block.d.ts +30 -2
  18. package/dist/Block.js +1 -1
  19. package/dist/Brand.css +1 -1
  20. package/dist/Brand.d.ts +37 -2
  21. package/dist/Breadcrumb-D0wXkE38.js +98 -0
  22. package/dist/Breadcrumb.css +1 -0
  23. package/dist/Breadcrumb.d.ts +80 -0
  24. package/dist/Breadcrumb.js +4 -0
  25. package/dist/Card.css +1 -1
  26. package/dist/Card.d.ts +28 -2
  27. package/dist/Column-DDaqX-A7.js +8 -0
  28. package/dist/Column.d.ts +24 -2
  29. package/dist/Column.js +1 -1
  30. package/dist/Dropdown-Cw5LKpcT.js +168 -0
  31. package/dist/Dropdown.css +1 -0
  32. package/dist/Dropdown.d.ts +124 -0
  33. package/dist/Dropdown.js +4 -0
  34. package/dist/EmptyState.css +1 -1
  35. package/dist/EmptyState.d.ts +36 -2
  36. package/dist/Footer.css +1 -1
  37. package/dist/Footer.d.ts +25 -2
  38. package/dist/Header.css +1 -1
  39. package/dist/Header.d.ts +36 -2
  40. package/dist/Item.css +1 -1
  41. package/dist/Item.d.ts +42 -2
  42. package/dist/Layout.css +1 -1
  43. package/dist/Layout.d.ts +30 -2
  44. package/dist/List.css +1 -1
  45. package/dist/List.d.ts +29 -2
  46. package/dist/Loading.css +1 -1
  47. package/dist/Loading.d.ts +24 -2
  48. package/dist/Menu-DRBHvSdJ.js +40 -0
  49. package/dist/Menu.css +1 -1
  50. package/dist/Menu.d.ts +78 -2
  51. package/dist/Menu.js +1 -1
  52. package/dist/{NavSections-CM-VPai2.js → NavSections-NDcIDD6H.js} +26 -26
  53. package/dist/NavSections.css +1 -1
  54. package/dist/NavSections.d.ts +101 -2
  55. package/dist/NavSections.js +1 -1
  56. package/dist/PageHead-Baz9BLuA.js +22 -0
  57. package/dist/PageHead.css +1 -0
  58. package/dist/PageHead.d.ts +36 -0
  59. package/dist/PageHead.js +4 -0
  60. package/dist/PageShell-CghThHS3.js +28 -0
  61. package/dist/PageShell.css +1 -0
  62. package/dist/PageShell.d.ts +33 -0
  63. package/dist/PageShell.js +4 -0
  64. package/dist/PricingGroup-CiqQtzjd.js +126 -0
  65. package/dist/PricingGroup.css +1 -0
  66. package/dist/PricingGroup.d.ts +130 -0
  67. package/dist/PricingGroup.js +4 -0
  68. package/dist/PricingTable-DYTJG4AU.js +158 -0
  69. package/dist/PricingTable.css +1 -0
  70. package/dist/PricingTable.d.ts +108 -0
  71. package/dist/PricingTable.js +4 -0
  72. package/dist/RadioGroup-DxoPHPIF.js +138 -0
  73. package/dist/RadioGroup.css +1 -0
  74. package/dist/RadioGroup.d.ts +111 -0
  75. package/dist/RadioGroup.js +4 -0
  76. package/dist/Row--HIe6vb9.js +8 -0
  77. package/dist/Row.d.ts +24 -2
  78. package/dist/Row.js +1 -1
  79. package/dist/Section.css +1 -1
  80. package/dist/Section.d.ts +49 -2
  81. package/dist/Stack-b0-XWwQ1.js +31 -0
  82. package/dist/Stack.css +1 -0
  83. package/dist/Stack.d.ts +34 -0
  84. package/dist/Stack.js +4 -0
  85. package/dist/TabSections-DL7DufKU.js +50 -0
  86. package/dist/TabSections.css +1 -1
  87. package/dist/TabSections.d.ts +87 -2
  88. package/dist/TabSections.js +1 -1
  89. package/dist/cx.d.ts +8 -1
  90. package/dist/dark.css +24 -0
  91. package/dist/index.css +32 -18
  92. package/dist/index.d.ts +21 -1
  93. package/dist/index.es.js +58 -38
  94. package/dist/lazyRoute.d.ts +19 -3
  95. package/dist/light.css +25 -0
  96. package/dist/stackGap.d.ts +13 -1
  97. package/dist/tokens.css +57 -0
  98. package/package.json +33 -6
  99. package/dist/Avatar-DHNPaIjZ.js +0 -64
  100. package/dist/Block-CVKukh1e.js +0 -28
  101. package/dist/Block.css +0 -1
  102. package/dist/Column-DlNrvFq1.js +0 -26
  103. package/dist/Column.css +0 -1
  104. package/dist/Menu-DS7zKQbY.js +0 -40
  105. package/dist/Row-CnD7Q7pD.js +0 -20
  106. package/dist/Row.css +0 -1
  107. package/dist/TabSections-oeEBx0nM.js +0 -50
  108. package/dist/stackGap-CDsjER0g.js +0 -7
package/dist/Header.d.ts CHANGED
@@ -1,2 +1,36 @@
1
- export * from './Header/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Шапка приложения со слотами brand / nav / search / actions.
4
+ *
5
+ * Роли: Header = верхняя полоса в Layout; Brand — логотип/название;
6
+ * рядом — Menu, поиск из `@elcrm/form`, кнопки `@elcrm/button`.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <Header
11
+ * brand={<Brand>elCRM</Brand>}
12
+ * nav={<Menu items={navItems} />}
13
+ * actions={<Button>Выйти</Button>}
14
+ * />
15
+ * ```
16
+ *
17
+ * Токены: `--shell-*`, узкие `--header-height`, `--header-z`, `--header-margin`, `--header-shadow`, `--header-radius`.
18
+ */
19
+ export type HeaderProps = React.HTMLAttributes<HTMLElement> & {
20
+ /** Логотип / название (часто `<Brand />`) */
21
+ brand?: React.ReactNode;
22
+ /** Навигация (Menu, ссылки) */
23
+ nav?: React.ReactNode;
24
+ /** Поиск или фильтр в шапке */
25
+ search?: React.ReactNode;
26
+ /** Действия справа (кнопки, аватар, колокольчик) */
27
+ actions?: React.ReactNode;
28
+ /** Доп. контент после слотов */
29
+ children?: React.ReactNode;
30
+ };
31
+ /**
32
+ * Шапка приложения со слотами brand / nav / search / actions.
33
+ *
34
+ * @see Layout, Brand, Menu, Footer
35
+ */
36
+ export declare function Header({ brand, nav, search, actions, children, className, ...rest }: HeaderProps): React.JSX.Element;
package/dist/Item.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cir{display:flex;align-items:center;gap:var(--item-gap);padding:var(--item-padding);color:var(--item-color);background:var(--item-background);border:1px solid var(--item-border);border-radius:var(--item-radius);cursor:default}.cir:is(button,a){-webkit-appearance:none;-moz-appearance:none;appearance:none;font:inherit;text-align:left;width:100%;cursor:pointer}.cir:hover{background:var(--item-background-hover)}.cia,.cir[aria-current=true],.cir[data-active=true]{background:var(--item-background-active)}}
1
+ @layer elcrm-components{.cir{display:flex;align-items:center;gap:var(--shell-gap-sm);padding:var(--shell-padding);color:var(--shell-color);background:transparent;border:1px solid transparent;border-radius:var(--shell-radius);cursor:default}.cir:is(button,a){-webkit-appearance:none;-moz-appearance:none;appearance:none;font:inherit;text-align:left;width:100%;cursor:pointer}.cir:hover{background:var(--shell-background-hover)}.cia,.cir[aria-current=true],.cir[data-active=true]{background:var(--shell-background-selected)}}
package/dist/Item.d.ts CHANGED
@@ -1,2 +1,42 @@
1
- export * from './Item/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ type Common = {
3
+ /** Активное / выбранное состояние */
4
+ active?: boolean;
5
+ /** Содержимое элемента */
6
+ children?: React.ReactNode;
7
+ /** Доп. CSS-класс */
8
+ className?: string;
9
+ };
10
+ /**
11
+ * Элемент списка / строки меню: кнопка, ссылка или `<li>`.
12
+ *
13
+ * Роли: Item внутри List / Menu; для групповых списков выбора —
14
+ * RadioGroup / Dropdown с `items` (не собирайте Item вручную).
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <List>
19
+ * <Item as="li" active>Текущий</Item>
20
+ * <Item as="a" href="/docs">Документация</Item>
21
+ * </List>
22
+ * ```
23
+ *
24
+ * Токены: `--shell-*`.
25
+ */
26
+ export type ItemProps = (Common & React.ButtonHTMLAttributes<HTMLButtonElement> & {
27
+ /** Тег: кнопка (по умолчанию) */
28
+ as?: "button";
29
+ }) | (Common & React.AnchorHTMLAttributes<HTMLAnchorElement> & {
30
+ /** Тег: ссылка */
31
+ as: "a";
32
+ }) | (Common & React.LiHTMLAttributes<HTMLLIElement> & {
33
+ /** Тег: элемент списка */
34
+ as: "li";
35
+ });
36
+ /**
37
+ * Элемент списка / строки.
38
+ *
39
+ * @see List, Menu, Badge
40
+ */
41
+ export declare function Item(props: ItemProps): React.JSX.Element;
42
+ export {};
package/dist/Layout.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.clr{display:flex;flex-direction:column;min-height:var(--layout-min-height);background:var(--layout-background);gap:var(--layout-gap)}.clm{flex:1;min-width:0}}
1
+ @layer elcrm-components{.clr{display:flex;flex-direction:column;flex:1 1 auto;height:100%;min-height:0;max-height:100%;overflow:hidden;background:var(--shell-background-muted);gap:0}.clm{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;overflow:hidden}}
package/dist/Layout.d.ts CHANGED
@@ -1,2 +1,30 @@
1
- export * from './Layout/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Оболочка приложения: шапка, основной контент, подвал.
4
+ *
5
+ * Роли: Layout = каркас страницы; внутри — Header / Section / PageShell / Footer.
6
+ * Используйте как корневой каркас маршрута или приложения.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <Layout header={<Header brand="App" />} footer={<Footer>© 2026</Footer>}>
11
+ * <Section title="Главная">…</Section>
12
+ * </Layout>
13
+ * ```
14
+ *
15
+ * Токены: `--shell-background-muted` (фон main), прочие `--shell-*`.
16
+ */
17
+ export type LayoutProps = React.HTMLAttributes<HTMLDivElement> & {
18
+ /** Слот шапки (обычно `<Header />`) */
19
+ header?: React.ReactNode;
20
+ /** Слот подвала (обычно `<Footer />`) */
21
+ footer?: React.ReactNode;
22
+ /** Основной контент страницы (рендерится в `<main>`) */
23
+ children?: React.ReactNode;
24
+ };
25
+ /**
26
+ * Оболочка страницы: header + main + footer.
27
+ *
28
+ * @see Header, Footer, Section, PageShell
29
+ */
30
+ export declare function Layout({ header, footer, children, className, ...rest }: LayoutProps): React.JSX.Element;
package/dist/List.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.csr{display:flex;flex-direction:column;gap:var(--list-gap);padding:var(--list-padding);margin:0;list-style:none}.csh{flex-direction:row;flex-wrap:wrap}}
1
+ @layer elcrm-components{.csr{display:flex;flex-direction:column;gap:var(--shell-gap-sm);padding:0;margin:0;list-style:none}.csh{flex-direction:row;flex-wrap:wrap}}
package/dist/List.d.ts CHANGED
@@ -1,2 +1,29 @@
1
- export * from './List/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Список (`<ul>`) — вертикальный или горизонтальный.
4
+ *
5
+ * Роли: List = контейнер; элементы — Item (или свои `<li>`).
6
+ * Для навигации / меню смотрите Menu, NavSections.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * <List>
11
+ * <Item as="li">Первый</Item>
12
+ * <Item as="li" active>Второй</Item>
13
+ * </List>
14
+ * ```
15
+ *
16
+ * Токены: `--shell-gap-sm`.
17
+ */
18
+ export type ListProps = React.HTMLAttributes<HTMLUListElement> & {
19
+ /** Горизонтальный список */
20
+ row?: boolean;
21
+ /** Элементы списка (обычно `<Item as="li" />`) */
22
+ children?: React.ReactNode;
23
+ };
24
+ /**
25
+ * Список (`<ul>`).
26
+ *
27
+ * @see Item, Menu, Stack
28
+ */
29
+ export declare function List({ row, children, className, ...rest }: ListProps): React.JSX.Element;
package/dist/Loading.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cgr{display:flex;align-items:center;justify-content:center;padding:var(--loading-padding);color:var(--loading-color)}}
1
+ @layer elcrm-components{.cgr{display:flex;align-items:center;justify-content:center;padding:var(--shell-gap-lg);color:var(--shell-color-muted)}}
package/dist/Loading.d.ts CHANGED
@@ -1,2 +1,24 @@
1
- export * from './Loading/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Плейсхолдер состояния загрузки (`role="status"`).
4
+ *
5
+ * Роли: Loading = индикация ожидания данных;
6
+ * при пустом результате после загрузки — EmptyState.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * {isLoading ? <Loading>Загружаем клиентов…</Loading> : <List>…</List>}
11
+ * ```
12
+ *
13
+ * Токены: `--shell-*`.
14
+ */
15
+ export type LoadingProps = React.HTMLAttributes<HTMLDivElement> & {
16
+ /** Текст или кастомный индикатор (по умолчанию «Загрузка…») */
17
+ children?: React.ReactNode;
18
+ };
19
+ /**
20
+ * Плейсхолдер загрузки.
21
+ *
22
+ * @see EmptyState, PageShell
23
+ */
24
+ export declare function Loading({ children, className, ...rest }: LoadingProps): React.JSX.Element;
@@ -0,0 +1,40 @@
1
+ import u from "react";
2
+ import { c as l } from "./cx-CcykAxZN.js";
3
+ import './Menu.css';const b = "cmr", f = "cmv", i = "cmi", k = "cma", c = {
4
+ r: b,
5
+ v: f,
6
+ i,
7
+ a: k
8
+ };
9
+ function C({
10
+ items: r,
11
+ vertical: t,
12
+ value: v,
13
+ onSelect: n,
14
+ children: d,
15
+ className: e,
16
+ ...p
17
+ }) {
18
+ return /* @__PURE__ */ u.createElement("nav", { className: l(c.r, t && c.v, e), ...p }, r == null ? void 0 : r.map((a) => {
19
+ const o = a.active ?? (v != null && a.value === v);
20
+ return /* @__PURE__ */ u.createElement(
21
+ "button",
22
+ {
23
+ key: a.value,
24
+ type: "button",
25
+ className: l(c.i, o && c.a),
26
+ "data-active": o ? "true" : void 0,
27
+ "aria-current": o ? "page" : void 0,
28
+ disabled: a.disabled,
29
+ onClick: () => {
30
+ var s;
31
+ (s = a.onClick) == null || s.call(a), n == null || n(a.value);
32
+ }
33
+ },
34
+ a.label
35
+ );
36
+ }), d);
37
+ }
38
+ export {
39
+ C as M
40
+ };
package/dist/Menu.css CHANGED
@@ -1 +1 @@
1
- @layer elcrm-components{.cmr{display:flex;align-items:center;gap:var(--menu-gap);margin:0;padding:0;list-style:none}.cmv{flex-direction:column;align-items:stretch}.cmi{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;background:var(--menu-item-background);color:var(--menu-item-color);padding:var(--menu-item-padding);border-radius:var(--menu-item-radius);font:inherit;cursor:pointer;text-align:left}.cmi:hover{background:var(--menu-item-background-hover);color:var(--menu-item-color-active)}.cma,.cmi[aria-current=page],.cmi[data-active=true]{background:var(--menu-item-background-active);color:var(--menu-item-color-active)}}
1
+ @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(--shell-color-muted);padding:var(--shell-padding);border-radius:var(--shell-radius);font:inherit;line-height:1;cursor:pointer;text-align:left}.cmi>svg{display:block;flex-shrink:0}.cmi:hover{background:var(--shell-background-hover);color:var(--shell-color)}.cma,.cmi[aria-current=page],.cmi[data-active=true]{background:var(--shell-background-selected);color:var(--shell-color)}}
package/dist/Menu.d.ts CHANGED
@@ -1,2 +1,78 @@
1
- export * from './Menu/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Пункт навигационного меню.
4
+ *
5
+ * Идентификатор пункта — всегда поле `value` (не `key`).
6
+ * Групповой UI: декларативный массив `items`, без compound-слотов (`Menu.Item`).
7
+ */
8
+ export type MenuItem = {
9
+ /** Уникальный идентификатор пункта (не `key`). */
10
+ value: string;
11
+ /** Подпись пункта (текст или React-узел). */
12
+ label: React.ReactNode;
13
+ /**
14
+ * Явный флаг активного пункта.
15
+ * Если не задан — активность берётся из `MenuProps.value`.
16
+ */
17
+ active?: boolean;
18
+ /** Обработчик клика по пункту (дополнительно к `onSelect` меню). */
19
+ onClick?: () => void;
20
+ /** Недоступный пункт. */
21
+ disabled?: boolean;
22
+ };
23
+ /**
24
+ * Props компонента {@link Menu}.
25
+ *
26
+ * Предпочтительный API — `items` + `value` / `onSelect`.
27
+ * `children` — запасной слот для редких кастомных вставок.
28
+ */
29
+ export type MenuProps = Omit<React.HTMLAttributes<HTMLElement>, "onSelect"> & {
30
+ /**
31
+ * Декларативный список пунктов.
32
+ * Групповые UI elCRM используют `items`, а не compound-слоты.
33
+ */
34
+ items?: MenuItem[];
35
+ /** Вертикальный ряд пунктов. */
36
+ vertical?: boolean;
37
+ /**
38
+ * Активный `value` пункта (если у item не задан `active`).
39
+ * Идентификатор — `value`, не `key`.
40
+ */
41
+ value?: string;
42
+ /** Выбор пункта: получает `item.value`. */
43
+ onSelect?: (value: string) => void;
44
+ /** Дополнительный контент внутри `<nav>` (редко). */
45
+ children?: React.ReactNode;
46
+ };
47
+ /**
48
+ * Навигационное меню в потоке документа (шапка, сайдбар-ряд) — не popover.
49
+ *
50
+ * Когда использовать:
51
+ * - горизонтальная/вертикальная навигация в layout;
52
+ * - нужно подсветить текущий раздел по `value`.
53
+ *
54
+ * Связанные компоненты:
55
+ * - {@link Dropdown} — выпадающая панель рядом с триггером;
56
+ * - `@elcrm/overlay` — портальный popover/меню поверх страницы;
57
+ * - {@link NavSections} / {@link TabSections} — разделы с lazy-контентом.
58
+ *
59
+ * API: декларативные `items` (идентификатор — `value`). Compound-слоты не используются.
60
+ *
61
+ * CSS-токены: `--shell-*` (цвета/отступы shell-навигации).
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * const items = [
66
+ * { value: "home", label: "Главная" },
67
+ * { value: "team", label: "Команда", disabled: true },
68
+ * ];
69
+ *
70
+ * <Menu
71
+ * items={items}
72
+ * value={section}
73
+ * onSelect={setSection}
74
+ * vertical
75
+ * />
76
+ * ```
77
+ */
78
+ export declare function Menu({ items, vertical, value, onSelect, children, className, ...rest }: MenuProps): React.JSX.Element;
package/dist/Menu.js CHANGED
@@ -1,4 +1,4 @@
1
- import { M as r } from "./Menu-DS7zKQbY.js";
1
+ import { M as r } from "./Menu-DRBHvSdJ.js";
2
2
  export {
3
3
  r as Menu
4
4
  };
@@ -1,58 +1,58 @@
1
- import e, { useMemo as S, useState as x, Suspense as I } from "react";
1
+ import e, { useMemo as x, useState as I, Suspense as M } from "react";
2
2
  import { c as d } from "./cx-CcykAxZN.js";
3
- import './NavSections.css';const M = "cvr", R = "cvn", j = "cvg", q = "cvl", w = "cvi", z = "cva", A = "cvc", B = "cvt", D = "cvf", F = "cvm", t = {
4
- r: M,
5
- n: R,
6
- g: j,
7
- l: q,
8
- i: w,
9
- a: z,
10
- c: A,
11
- t: B,
12
- f: D,
13
- m: F
3
+ import './NavSections.css';const R = "cvr", j = "cvn", q = "cvg", w = "cvl", z = "cvi", A = "cva", B = "cvc", D = "cvt", F = "cvf", G = "cvm", t = {
4
+ r: R,
5
+ n: j,
6
+ g: q,
7
+ l: w,
8
+ i: z,
9
+ a: A,
10
+ c: B,
11
+ t: D,
12
+ f: F,
13
+ m: G
14
14
  };
15
- function G(l) {
15
+ function H(l) {
16
16
  for (const r of l) {
17
17
  const n = r.items.find((s) => !s.disabled);
18
- if (n) return n.key;
18
+ if (n) return n.value;
19
19
  }
20
20
  return "";
21
21
  }
22
22
  function L({
23
23
  groups: l,
24
24
  resolveSection: r,
25
- activeKey: n,
26
- defaultActiveKey: s,
27
- onChange: i,
25
+ value: n,
26
+ defaultValue: s,
27
+ onValueChange: i,
28
28
  loading: f = null,
29
29
  footer: v,
30
30
  className: b,
31
31
  navLabel: E = "Разделы"
32
32
  }) {
33
- const N = S(
34
- () => s || G(l),
33
+ const N = x(
34
+ () => s || H(l),
35
35
  [s, l]
36
- ), [y, k] = x(N), m = n ?? y, p = (a) => {
37
- n == null && k(a), i == null || i(a);
36
+ ), [k, p] = I(N), m = n ?? k, y = (a) => {
37
+ n == null && p(a), i == null || i(a);
38
38
  }, u = m ? r(m) : null;
39
- return /* @__PURE__ */ e.createElement("div", { className: d(t.r, b) }, /* @__PURE__ */ e.createElement("nav", { className: t.n, "aria-label": E }, l.map((a, K) => /* @__PURE__ */ e.createElement("div", { key: K, className: t.g }, a.label != null ? /* @__PURE__ */ e.createElement("div", { className: t.l }, a.label) : null, a.items.map((c) => {
40
- const o = c.key === m;
39
+ return /* @__PURE__ */ e.createElement("div", { className: d(t.r, b) }, /* @__PURE__ */ e.createElement("nav", { className: t.n, "aria-label": E }, l.map((a, S) => /* @__PURE__ */ e.createElement("div", { key: S, className: t.g }, a.label != null ? /* @__PURE__ */ e.createElement("div", { className: t.l }, a.label) : null, a.items.map((c) => {
40
+ const o = c.value === m;
41
41
  return /* @__PURE__ */ e.createElement(
42
42
  "button",
43
43
  {
44
- key: c.key,
44
+ key: c.value,
45
45
  type: "button",
46
46
  className: d(t.i, o && t.a),
47
47
  "data-active": o ? "true" : void 0,
48
48
  "aria-current": o ? "page" : void 0,
49
49
  disabled: c.disabled,
50
- onClick: () => p(c.key)
50
+ onClick: () => y(c.value)
51
51
  },
52
52
  c.icon != null ? /* @__PURE__ */ e.createElement("span", { className: t.c, "aria-hidden": !0 }, c.icon) : null,
53
53
  /* @__PURE__ */ e.createElement("span", { className: t.t }, c.label)
54
54
  );
55
- }))), v != null ? /* @__PURE__ */ e.createElement("div", { className: t.f }, v) : null), /* @__PURE__ */ e.createElement("div", { className: t.m }, u ? /* @__PURE__ */ e.createElement(I, { fallback: f }, e.createElement(u)) : null));
55
+ }))), v != null ? /* @__PURE__ */ e.createElement("div", { className: t.f }, v) : null), /* @__PURE__ */ e.createElement("div", { className: t.m }, u ? /* @__PURE__ */ e.createElement(M, { fallback: f }, e.createElement(u)) : null));
56
56
  }
57
57
  export {
58
58
  L as N
@@ -1 +1 @@
1
- @layer elcrm-components{.cvr{display:flex;align-items:stretch;gap:var(--nav-sections-gap);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:1rem;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:.75rem;border-bottom:1px solid var(--nav-sections-group-border)}.cvg:last-of-type{border-bottom:none;padding-bottom:0}.cvl{font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--nav-sections-label-color);padding:0 10px 6px}.cvi{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:flex;align-items:center;gap:8px;width:100%;text-align:left;border:none;border-radius:var(--nav-sections-item-radius);background:transparent;color:var(--nav-sections-item-color);font:inherit;font-size:14px;padding:var(--nav-sections-item-padding);cursor:pointer;position:relative;transition:background .12s ease,color .12s ease}.cvi:hover:not(:disabled){background:var(--nav-sections-item-background-hover)}.cva{background:var(--nav-sections-item-background-active)}.cva:before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--nav-sections-accent)}.cvi:disabled{opacity:.45;cursor:not-allowed}.cvc{display:inline-flex;flex:0 0 auto;color:var(--nav-sections-icon-color);line-height:0}.cva .cvc{color:var(--nav-sections-item-color)}.cvt{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cvf{margin-top:auto;padding-top:.75rem;border-top:1px solid var(--nav-sections-footer-border)}.cvm{flex:1 1 auto;min-width:0;max-width:var(--nav-sections-main-max-width);width:100%;min-height:0;overflow:auto;--section-padding: 0}@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:11px;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{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:flex;align-items:center;gap:var(--shell-gap-sm);width:100%;text-align:left;border:none;border-radius:var(--shell-radius);background:transparent;color:var(--shell-color);font:inherit;font-size:var(--shell-font-size-sm);padding:var(--shell-padding);cursor:pointer;position:relative}.cvi:hover:not(:disabled){background:var(--shell-background-hover)}.cva{background:var(--shell-background-selected)}.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,2 +1,101 @@
1
- export * from './NavSections/index'
2
- export {}
1
+ import { default as React } from 'react';
2
+ import { LazyRouteChunk } from './lazyRoute';
3
+ /**
4
+ * Пункт боковой навигации {@link NavSections}.
5
+ *
6
+ * Идентификатор — `value` (обычно совпадает с именем файла секции).
7
+ * Не используйте `key` как бизнес-идентификатор.
8
+ */
9
+ export type NavSectionsItem = {
10
+ /** Уникальный идентификатор раздела (не `key`). */
11
+ value: string;
12
+ /** Подпись в сайдбаре. */
13
+ label: React.ReactNode;
14
+ /** Иконка слева; нет поля — не рисуем. */
15
+ icon?: React.ReactNode;
16
+ /** Недоступный пункт. */
17
+ disabled?: boolean;
18
+ };
19
+ /**
20
+ * Группа пунктов сайдбара (опциональный заголовок + `items`).
21
+ *
22
+ * Декларативный API: группа собирается из данных, без compound-слотов.
23
+ */
24
+ export type NavSectionsGroup = {
25
+ /** Подпись группы (например «Личное»). Нет — заголовок не рисуется. */
26
+ label?: React.ReactNode;
27
+ /** Пункты группы (`value` — идентификатор). */
28
+ items: NavSectionsItem[];
29
+ };
30
+ /**
31
+ * Props компонента {@link NavSections}.
32
+ *
33
+ * Групповой UI: `groups` → внутри каждой группы декларативные `items`.
34
+ */
35
+ export type NavSectionsProps = {
36
+ /** Группы бокового меню. */
37
+ groups: NavSectionsGroup[];
38
+ /**
39
+ * Резолвер панели справа по `value`.
40
+ * Обычно: `createLazyResolver((v) => import(\`./sections/${v}.tsx\`))`.
41
+ */
42
+ resolveSection: (value: string) => LazyRouteChunk | React.ComponentType;
43
+ /** Контролируемый активный `value`. */
44
+ value?: string;
45
+ /** Начальный `value` в неконтролируемом режиме. */
46
+ defaultValue?: string;
47
+ /** Смена активного раздела (`next` = `item.value`). */
48
+ onValueChange?: (value: string) => void;
49
+ /** Fallback для `<Suspense>` при ленивой загрузке секции. */
50
+ loading?: React.ReactNode;
51
+ /** Низ сайдбара (например кнопка «Назад»). */
52
+ footer?: React.ReactNode;
53
+ /** CSS-класс корня. */
54
+ className?: string;
55
+ /** `aria-label` для `<nav>`. */
56
+ navLabel?: string;
57
+ };
58
+ /**
59
+ * Макет «настройки / профиль»: вертикальный сайдбар + lazy-секция справа.
60
+ *
61
+ * Когда использовать:
62
+ * - страницы с несколькими разделами и боковым меню;
63
+ * - контент секции грузится по `value` через `resolveSection`.
64
+ *
65
+ * Связанные компоненты:
66
+ * - {@link TabSections} — то же, но вкладки горизонтально;
67
+ * - {@link createLazyResolver} из `lazyRoute` — кэш lazy-импортов;
68
+ * - {@link Menu} — простая навигация без панелей.
69
+ *
70
+ * API: декларативные `groups` / `items`. Идентификатор раздела — `value` (не `key`).
71
+ * Compound-слоты (`NavSections.Item`) не используются.
72
+ *
73
+ * CSS-токены: `--shell-*`, `--nav-sections-padding`, `--nav-sections-nav-width`,
74
+ * `--nav-sections-main-max-width`.
75
+ *
76
+ * @example
77
+ * ```tsx
78
+ * const groups = [
79
+ * {
80
+ * label: "Личное",
81
+ * items: [
82
+ * { value: "profile", label: "Профиль", icon: <Icons.Line name="user" /> },
83
+ * { value: "security", label: "Безопасность" },
84
+ * ],
85
+ * },
86
+ * ];
87
+ *
88
+ * const resolveSection = createLazyResolver(
89
+ * (v) => import(`./sections/${v}.tsx`),
90
+ * );
91
+ *
92
+ * <NavSections
93
+ * groups={groups}
94
+ * resolveSection={resolveSection}
95
+ * value={section}
96
+ * onValueChange={setSection}
97
+ * footer={<Button onSend={() => navigate(-1)}>Назад</Button>}
98
+ * />
99
+ * ```
100
+ */
101
+ export declare function NavSections({ groups, resolveSection, value: valueProp, defaultValue, onValueChange, loading, footer, className, navLabel, }: NavSectionsProps): React.JSX.Element;
@@ -1,4 +1,4 @@
1
- import { N as e } from "./NavSections-CM-VPai2.js";
1
+ import { N as e } from "./NavSections-NDcIDD6H.js";
2
2
  export {
3
3
  e as NavSections
4
4
  };
@@ -0,0 +1,22 @@
1
+ import c from "react";
2
+ import { c as r } from "./cx-CcykAxZN.js";
3
+ import './PageHead.css';const m = "ccr", o = "ccw", E = "cct", N = "cch", d = "ccs", h = "cca", e = {
4
+ r: m,
5
+ w: o,
6
+ t: E,
7
+ h: N,
8
+ s: d,
9
+ a: h
10
+ };
11
+ function p({
12
+ title: s,
13
+ subtitle: a,
14
+ actions: t,
15
+ className: l,
16
+ children: n
17
+ }) {
18
+ return /* @__PURE__ */ c.createElement("div", { className: r(e.r, l) }, /* @__PURE__ */ c.createElement("div", { className: e.w }, /* @__PURE__ */ c.createElement("div", { className: e.t }, /* @__PURE__ */ c.createElement("h1", { className: e.h }, s), a != null ? /* @__PURE__ */ c.createElement("p", { className: e.s }, a) : null), t != null ? /* @__PURE__ */ c.createElement("div", { className: e.a }, t) : null), n);
19
+ }
20
+ export {
21
+ p as P
22
+ };
@@ -0,0 +1 @@
1
+ @layer elcrm-components{.ccr{margin:0 0 var(--shell-gap-lg)}.ccw{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:var(--shell-gap)}.cct{min-width:0;max-width:36rem}.cch{margin:0;font-size:var(--section-title-size);font-weight:var(--shell-font-weight);color:var(--shell-color);line-height:1.25}.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)}}
@@ -0,0 +1,36 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Заголовок страницы: title слева, actions справа в одной линии.
4
+ *
5
+ * Роли: PageHead = шапка контента внутри PageShell / Section;
6
+ * для полноценной секции с description/icon — Section;
7
+ * глобальная шапка приложения — Header.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * <PageShell>
12
+ * <PageHead title="Клиенты" subtitle="Все компании" actions={<Button>Создать</Button>} />
13
+ * …
14
+ * </PageShell>
15
+ * ```
16
+ *
17
+ * Токены: `--shell-*`, `--section-title-size`.
18
+ */
19
+ export type PageHeadProps = {
20
+ /** Заголовок страницы */
21
+ title: React.ReactNode;
22
+ /** Подзаголовок */
23
+ subtitle?: React.ReactNode;
24
+ /** Кнопки / поиск справа в одной строке с заголовком */
25
+ actions?: React.ReactNode;
26
+ /** Доп. CSS-класс */
27
+ className?: string;
28
+ /** Контент под строкой заголовка (фильтры, Breadcrumb) */
29
+ children?: React.ReactNode;
30
+ };
31
+ /**
32
+ * Заголовок: title слева, actions справа (одна линия).
33
+ *
34
+ * @see PageShell, Section, Header
35
+ */
36
+ export declare function PageHead({ title, subtitle, actions, className, children, }: PageHeadProps): React.JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { P as o } from "./PageHead-Baz9BLuA.js";
2
+ export {
3
+ o as PageHead
4
+ };
@@ -0,0 +1,28 @@
1
+ import e from "react";
2
+ import { c as l } from "./cx-CcykAxZN.js";
3
+ import './PageShell.css';const m = "ckr", o = "ckw", f = "ckb", i = "ckf", c = {
4
+ r: m,
5
+ w: o,
6
+ b: f,
7
+ f: i
8
+ };
9
+ function u({
10
+ children: s,
11
+ className: a,
12
+ wide: n,
13
+ footer: t,
14
+ ...r
15
+ }) {
16
+ return /* @__PURE__ */ e.createElement(
17
+ "div",
18
+ {
19
+ ...r,
20
+ className: l(c.r, n && c.w, a)
21
+ },
22
+ /* @__PURE__ */ e.createElement("div", { className: c.b }, s),
23
+ t != null ? /* @__PURE__ */ e.createElement("div", { className: c.f }, t) : null
24
+ );
25
+ }
26
+ export {
27
+ u as P
28
+ };
@@ -0,0 +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)}}