@elcrm/components 0.2.14 → 0.5.1
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 +70 -36
- package/dist/ActionGroup-DcApj_Mz.js +27 -0
- package/dist/ActionGroup.css +1 -1
- package/dist/ActionGroup.d.ts +19 -19
- package/dist/ActionGroup.js +1 -1
- package/dist/Avatar-eGdLrMCv.js +113 -0
- package/dist/Avatar.css +1 -1
- package/dist/Avatar.d.ts +4 -4
- package/dist/Avatar.js +1 -1
- package/dist/AvatarGroup-Dq-UrOaC.js +81 -0
- package/dist/AvatarGroup.css +1 -1
- package/dist/AvatarGroup.d.ts +8 -28
- package/dist/AvatarGroup.js +1 -1
- package/dist/AvatarName-3B4yCxHn.js +68 -0
- package/dist/AvatarName.css +1 -1
- package/dist/AvatarName.js +1 -1
- package/dist/Badge-BjScAXGy.js +28 -0
- package/dist/Badge.css +1 -1
- package/dist/Badge.js +1 -1
- package/dist/Banner-DAY18FWO.js +34 -0
- package/dist/Banner.css +1 -1
- package/dist/Banner.js +1 -1
- package/dist/Brand-BfCuiyf7.js +34 -0
- package/dist/Brand.css +1 -1
- package/dist/Brand.d.ts +8 -10
- package/dist/Brand.js +1 -1
- package/dist/Breadcrumb-DM_hWw5n.js +98 -0
- package/dist/Breadcrumb.css +1 -1
- package/dist/Breadcrumb.d.ts +8 -5
- package/dist/Breadcrumb.js +1 -1
- package/dist/Card-a7N8Uh_H.js +12 -0
- package/dist/Card.css +1 -1
- package/dist/Card.js +1 -1
- package/dist/ChatFrame-BdSYRF-B.js +37 -0
- package/dist/ChatFrame.css +1 -1
- package/dist/ChatList.js +2 -2
- package/dist/{ChatMessages-B8rdXiK-.js → ChatMessages-CLxwRGIa.js} +1 -1
- package/dist/ChatMessages.js +1 -1
- package/dist/ChatSplit-8iw_1Shp.js +21 -0
- package/dist/CodeBlock-B3wvMejv.js +34 -0
- package/dist/CodeBlock.css +1 -1
- package/dist/CodeBlock.js +1 -1
- package/dist/Dropdown-CR_XxNak.js +185 -0
- package/dist/Dropdown.css +1 -1
- package/dist/Dropdown.d.ts +4 -94
- package/dist/Dropdown.js +1 -1
- package/dist/EmptyState-B_wWPjUu.js +23 -0
- package/dist/EmptyState.css +1 -1
- package/dist/EmptyState.js +1 -1
- package/dist/{Footer-qxUlnPR9.js → Footer-Bgh_JCUe.js} +4 -4
- package/dist/Footer.css +1 -1
- package/dist/Footer.js +1 -1
- package/dist/Header-BMDIi3u2.js +21 -0
- package/dist/Header.css +1 -1
- package/dist/Header.js +1 -1
- package/dist/Healthmap-Z-LLfGW0.js +359 -0
- package/dist/Healthmap.css +1 -1
- package/dist/Healthmap.d.ts +25 -3
- package/dist/Healthmap.js +1 -1
- package/dist/{Item-D4okhsfW.js → Item-CGpkMJu0.js} +13 -13
- package/dist/Item.css +1 -1
- package/dist/Item.d.ts +7 -7
- package/dist/Item.js +1 -1
- package/dist/ItemColumn-Ch61LqE0.js +41 -0
- package/dist/ItemColumn.css +1 -1
- package/dist/ItemColumn.js +1 -1
- package/dist/Layout-CzEGKl9s.js +31 -0
- package/dist/Layout.css +1 -1
- package/dist/Layout.d.ts +1 -1
- package/dist/Layout.js +1 -1
- package/dist/List-D13pqaUY.js +12 -0
- package/dist/List.css +1 -1
- package/dist/List.js +1 -1
- package/dist/Loading-C_CKD-zt.js +16 -0
- package/dist/Loading.css +1 -1
- package/dist/Loading.js +1 -1
- package/dist/Menu-D2kf7fN_.js +72 -0
- package/dist/Menu.css +1 -1
- package/dist/Menu.d.ts +7 -25
- package/dist/Menu.js +1 -1
- package/dist/NavSections-CNxxBMPT.js +154 -0
- package/dist/NavSections.css +1 -1
- package/dist/NavSections.d.ts +16 -28
- package/dist/NavSections.js +1 -1
- package/dist/PageHead-BfClTLrF.js +31 -0
- package/dist/PageHead.css +1 -1
- package/dist/PageHead.d.ts +1 -1
- package/dist/PageHead.js +1 -1
- package/dist/PageShell-BAJges-G.js +30 -0
- package/dist/PageShell.css +1 -1
- package/dist/PageShell.js +1 -1
- package/dist/PanelInfo-Db5GCr-c.js +137 -0
- package/dist/PanelInfo.css +1 -1
- package/dist/PanelInfo.d.ts +16 -9
- package/dist/PanelInfo.js +1 -1
- package/dist/Popover-xEZoMY-h.js +143 -0
- package/dist/Popover.css +1 -1
- package/dist/Popover.d.ts +40 -11
- package/dist/Popover.js +1 -1
- package/dist/PricingGroup-CWy47MlE.js +138 -0
- package/dist/PricingGroup.css +1 -1
- package/dist/PricingGroup.d.ts +0 -2
- package/dist/PricingGroup.js +1 -1
- package/dist/PricingTable-BjpGVAhi.js +157 -0
- package/dist/PricingTable.css +1 -1
- package/dist/PricingTable.d.ts +4 -7
- package/dist/PricingTable.js +1 -1
- package/dist/RadioGroup-DI4KKUvZ.js +121 -0
- package/dist/RadioGroup.css +1 -1
- package/dist/RadioGroup.js +1 -1
- package/dist/Section-PprWjOvt.js +47 -0
- package/dist/Section.css +1 -1
- package/dist/Section.d.ts +29 -9
- package/dist/Section.js +1 -1
- package/dist/Sidebar-Bouhd5SS.js +205 -0
- package/dist/Sidebar.css +1 -1
- package/dist/Sidebar.d.ts +18 -26
- package/dist/Sidebar.js +1 -1
- package/dist/SplitPane-DBa-g9td.js +92 -0
- package/dist/SplitPane.css +1 -1
- package/dist/SplitPane.d.ts +8 -7
- package/dist/SplitPane.js +1 -1
- package/dist/Stack-BPTehVYc.js +53 -0
- package/dist/Stack.css +1 -1
- package/dist/Stack.d.ts +2 -1
- package/dist/Stack.js +1 -1
- package/dist/Stat-p8j4PjrC.js +28 -0
- package/dist/Stat.css +1 -1
- package/dist/Stat.js +1 -1
- package/dist/TabSections-Dppe9wiz.js +84 -0
- package/dist/TabSections.css +1 -1
- package/dist/TabSections.d.ts +7 -2
- package/dist/TabSections.js +1 -1
- package/dist/Table-DqrDUUtb.js +27 -0
- package/dist/Table.css +1 -1
- package/dist/Table.d.ts +10 -2
- package/dist/Table.js +1 -1
- package/dist/Text-Bo1u7gVC.js +25 -0
- package/dist/Text.css +1 -1
- package/dist/Text.js +1 -1
- package/dist/TextGroup-236jHxdT.js +23 -0
- package/dist/TextGroup.css +1 -1
- package/dist/TextGroup.js +1 -1
- package/dist/Toolbar-Bl9-5Mis.js +35 -0
- package/dist/Toolbar.css +1 -1
- package/dist/Toolbar.d.ts +7 -12
- package/dist/Toolbar.js +1 -2
- package/dist/cx.d.ts +1 -1
- package/dist/dark.css +12 -0
- package/dist/index.css +40 -40
- package/dist/index.d.ts +5 -12
- package/dist/index.es.d.ts +5 -12
- package/dist/index.es.js +109 -108
- package/dist/kit-manifest.json +1646 -0
- package/dist/lazyRoute.d.ts +12 -6
- package/dist/light.css +12 -0
- package/dist/navTree.d.ts +13 -1
- package/dist/rovingKeys-Di9N1Nct.js +23 -0
- package/dist/rovingKeys.d.ts +7 -1
- package/dist/stackGap.d.ts +1 -1
- package/dist/tokens.css +13 -0
- package/dist/useControllableValue-BaE0VR5d.js +13 -0
- package/dist/useControllableValue.d.ts +3 -0
- package/package.json +48 -4
- package/dist/ActionGroup-ChKFW0mt.js +0 -27
- package/dist/Avatar-loGgFt72.js +0 -113
- package/dist/AvatarGroup-D1gnT3Od.js +0 -81
- package/dist/AvatarName-0BzyfpMq.js +0 -68
- package/dist/Badge-jp-9iNNL.js +0 -28
- package/dist/Banner-B72lcEMo.js +0 -34
- package/dist/Block-Bu7NEA0g.js +0 -8
- package/dist/Block.d.ts +0 -30
- package/dist/Block.js +0 -4
- package/dist/Brand-Zq-Idks4.js +0 -34
- package/dist/Breadcrumb-CAM_e9LN.js +0 -98
- package/dist/Card-hn37Opo3.js +0 -12
- package/dist/ChatFrame-BW2TmCkZ.js +0 -37
- package/dist/ChatSplit-DNnu3TNq.js +0 -21
- package/dist/CodeBlock-CRzVopIv.js +0 -25
- package/dist/Column-BiogBDf8.js +0 -8
- package/dist/Column.d.ts +0 -24
- package/dist/Column.js +0 -4
- package/dist/Dropdown-DosvDR13.js +0 -147
- package/dist/EmptyState-mBiWtMIM.js +0 -23
- package/dist/Header-DZQopVNy.js +0 -21
- package/dist/Healthmap-B6cdiLUl.js +0 -243
- package/dist/ItemColumn-M7a9L8CI.js +0 -41
- package/dist/Layout-mi6Ghayv.js +0 -31
- package/dist/List-BgKkYaGO.js +0 -12
- package/dist/Loading-DkkG7RcE.js +0 -16
- package/dist/Menu-DuXQv-zT.js +0 -66
- package/dist/NavSections-D6rDEtT1.js +0 -142
- package/dist/PageHead-DgaJ1mXY.js +0 -31
- package/dist/PageShell-D9EZiO8o.js +0 -30
- package/dist/PanelInfo-A5y5ysH8.js +0 -81
- package/dist/Popover-DWdvZTuA.js +0 -135
- package/dist/PricingGroup-Czuhe81Z.js +0 -120
- package/dist/PricingTable-BuLC0opK.js +0 -152
- package/dist/RadioGroup-fcXzhvMu.js +0 -129
- package/dist/Row-DsQOVn18.js +0 -8
- package/dist/Row.d.ts +0 -24
- package/dist/Row.js +0 -4
- package/dist/Section-Crxk2J-E.js +0 -34
- package/dist/Sidebar-CYFaPqdC.js +0 -178
- package/dist/SplitPane-DR7PCZ8f.js +0 -74
- package/dist/Stack-XkmPSswj.js +0 -53
- package/dist/Stat-sKXJwz5L.js +0 -27
- package/dist/TabSections-DN7yVJoF.js +0 -69
- package/dist/Table-BoDr3X2d.js +0 -25
- package/dist/Text-zHK2wmsw.js +0 -25
- package/dist/TextGroup-DmhuyMR1.js +0 -23
- package/dist/Toolbar-C1zAk9ak.js +0 -42
- package/dist/rovingKeys-CGlfTtNQ.js +0 -15
- package/dist/useControllableValue-CWqH1kpM.js +0 -10
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
Shell UI для elCRM: `Layout`, `Header`, `Section`, `Stack`, `NavSections`, `TabSections` и др.
|
|
4
4
|
|
|
5
|
-
Стили — CSS Modules
|
|
5
|
+
Стили — CSS Modules. В DOM className всегда **3 буквы** `{семья}{компонент}{первая буква локального}` (короткий код вроде c8s, только a–z): List `.root` → `llr`, Layout `.root` → `slr`, Sidebar `.root` → `nsr`. В исходнике — слова (`.root`, `.icon`). Семьи: `l` lists, `n` nav, `s` shell, `k` kit, `t` type, `a` avatar, `o` overlay, `g` pricing, `h` healthmap, `d` data. Значения токенов задаёт приложение (`theme-dark.css` / `theme-light.css`). Fallback в пакете нет.
|
|
6
|
+
|
|
7
|
+
**Локаль:** дефолтные подписи UI — на русском (`navLabel`, `label`, `copyLabel`, `aria-label` и т.п. можно переопределить). Пакет не тянет i18n-runtime.
|
|
6
8
|
|
|
7
9
|
## Визуальный стенд
|
|
8
10
|
|
|
@@ -64,13 +66,18 @@ import {
|
|
|
64
66
|
ChatSplit,
|
|
65
67
|
Sidebar,
|
|
66
68
|
Popover,
|
|
69
|
+
Healthmap,
|
|
70
|
+
PanelInfo,
|
|
67
71
|
createLazyResolver,
|
|
72
|
+
acquireOverlayZIndex,
|
|
68
73
|
} from "@elcrm/components";
|
|
69
|
-
import type { PricingPlan } from "@elcrm/components";
|
|
74
|
+
import type { PricingPlan, HealthmapData, NavTreeItem } from "@elcrm/components";
|
|
70
75
|
// CSS подтягивается с чанками; при необходимости единый файл:
|
|
71
76
|
// import "@elcrm/components/style.css";
|
|
72
77
|
```
|
|
73
78
|
|
|
79
|
+
Слоты `Header` заполняет приложение: поиск — `@elcrm/form` (`Search`), кнопки — `@elcrm/button`.
|
|
80
|
+
|
|
74
81
|
Точечный импорт:
|
|
75
82
|
|
|
76
83
|
```ts
|
|
@@ -89,45 +96,65 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
|
|
|
89
96
|
| **Brand** | Название / логотип | `as`, `children`, `onClick` |
|
|
90
97
|
| **Avatar** | Фото или инициалы | `src`, `name`, `size`, `radius`, `status`, `as` |
|
|
91
98
|
| **AvatarName** | Аватар + title + description | `title`, `description`, `radius`, `--avatar-name-*-color` |
|
|
92
|
-
| **AvatarGroup** | Стопка аватаров + «+N» | `items` (`value
|
|
99
|
+
| **AvatarGroup** | Стопка аватаров + «+N» | `items` (`value` обязателен), `max`, `add`, `onValueChange` |
|
|
93
100
|
| **Badge** | Метка / статус | `tone`, `size`, `dot`, `children` |
|
|
94
|
-
| **RadioGroup** | Выбор одной опции-карточки | `items`, `value`, `indicator`, `indicatorSide`
|
|
95
|
-
| **PricingGroup** | Тарифные карточки в ряд | `items` (`PricingPlan`), `selectable`, `value`
|
|
101
|
+
| **RadioGroup** | Выбор одной опции-карточки | `items`, `value`, `onValueChange`, `indicator`, `indicatorSide` |
|
|
102
|
+
| **PricingGroup** | Тарифные карточки в ряд | `items` (`PricingPlan`), `selectable`, `value`, `onValueChange` |
|
|
96
103
|
| **PricingTable** | Сравнение тарифов (таблица) | те же `items` + `sections` |
|
|
97
|
-
| **Table** | Таблица данных со скроллом | `layout
|
|
104
|
+
| **Table** | Таблица данных со скроллом | `layout`, `stickyHeader`, `<caption>` |
|
|
98
105
|
| **CodeBlock** | Блок кода с bar и копированием | `title`, `code` / `children`, `onCopy`, `actions` |
|
|
99
|
-
| **SplitPane** | Две панели с разделителем | `direction`, `ratio`, `onRatioChange`, `first`, `second
|
|
106
|
+
| **SplitPane** | Две панели с разделителем | `direction`, `ratio` / `defaultRatio`, `onRatioChange`, `first`, `second` |
|
|
100
107
|
| **Banner** | Статусная полоса | `tone` (`info`/`warning`/`danger`/`success`), не toast |
|
|
101
108
|
| **IconButton** | Иконка + tooltip | `name`, обязательный `label`, `tooltip` (`false` — без подсказки) |
|
|
102
|
-
| **Menu** | Навигация в шапке (не popover) | `items
|
|
103
|
-
| **Dropdown** | Выпадающее меню (items, portal) | `label`/`trigger`, `items`/`groups`, `
|
|
104
|
-
| **Popover** | Свой попап в portal | `trigger
|
|
105
|
-
| **Breadcrumb** | Хлебные крошки | `items`, `separator`, `collapseAfter`
|
|
106
|
-
| **Sidebar** | Левое меню приложения | `groups`, `value
|
|
109
|
+
| **Menu** | Навигация в шапке (не popover) | `items`, `value` / `defaultValue`, `onValueChange`, `variant` (`plain`/`line`) |
|
|
110
|
+
| **Dropdown** | Выпадающее меню (items, portal) | `label`/`trigger`, `items`/`groups`, `onValueChange` |
|
|
111
|
+
| **Popover** | Свой попап в portal | `trigger` (render-prop `anchorProps` или узел), `children`, `align`, `open` |
|
|
112
|
+
| **Breadcrumb** | Хлебные крошки | `items`, `separator`, `collapseAfter`, `onValueChange` |
|
|
113
|
+
| **Sidebar** | Левое меню приложения | `groups`, `value` / `defaultValue`, `onValueChange`, `footerItems` + `onFooterValueChange` |
|
|
107
114
|
| **PageShell** | Каркас модуля (скролл + footer) | `wide`, `scroll`, `footer`, `children` |
|
|
108
115
|
| **ChatList** | Колонка диалогов | `header`, `footer`, `children` (`List`/`Item`), `bodyRef` |
|
|
109
116
|
| **ChatMessages** | Колонка переписки | `header`, `footer`, `children`, `bodyRef`, `onBodyScroll` |
|
|
110
117
|
| **ChatSplit** | Список + лента | `list`, `messages` |
|
|
111
118
|
| **PageHead** | Заголовок страницы + actions | `title`, `sup` (текст/Badge), `subtitle`, `actions`, `sticky`, `children` |
|
|
112
|
-
| **Section** | Блок контента / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant`
|
|
113
|
-
| **NavSections** | Сайдбар + lazy-панель | `groups
|
|
114
|
-
| **TabSections** | Горизонтальные вкладки + lazy | `items
|
|
119
|
+
| **Section** | Блок контента / auth / подраздел | `title`, `description`, `icon`, `actions`, `variant`, `direction`/`gap`/`columns` (тело = Stack) |
|
|
120
|
+
| **NavSections** | Сайдбар + lazy-панель | `groups` (`value`), `resolveSection?`, `children` (готовая панель) |
|
|
121
|
+
| **TabSections** | Горизонтальные вкладки + lazy | `items`, `resolveSection?`, `children` |
|
|
115
122
|
| **Card** | Карточка | `title`, `--card-pointer` |
|
|
116
|
-
| **ActionGroup** | Ряд иконок в карточке | `label`, `
|
|
117
|
-
| **Toolbar** | Фильтры одной высоты | `size
|
|
123
|
+
| **ActionGroup** | Ряд иконок в карточке | `label`, `actions` и/или `children` (не декларативные `items`) |
|
|
124
|
+
| **Toolbar** | Фильтры одной высоты | `size` → `useToolbar` + `data-size`, `width`, `align`, `label`, `children` |
|
|
118
125
|
| **TextGroup** | Title + description | `title`, `description`, `size` |
|
|
119
126
|
| **Text** | Короткий текст | `tone` (`default`/`muted`), `as` |
|
|
120
127
|
| **ItemColumn** | Иконка + столбик в Item | `icon`, `title`, `extra`, `aside`, `description`, `footer` / `meta`, `unread` |
|
|
121
128
|
| **Stat** | Карточка-метрика | `label`, `value`, `tone`, `labelMuted` |
|
|
122
|
-
| **List** / **Item** | Список и строка | List: `row`; Item:
|
|
129
|
+
| **List** / **Item** | Список и строка | List: `row`; Item: по умолчанию `li`, кликабельный — `as="button"` |
|
|
123
130
|
| **Stack** | Ряд / колонка / сетка | `direction`, `columns` (N или `["1fr", "100px"]`), `gap` |
|
|
124
131
|
| **Loading** | Плейсхолдер загрузки | `children`; `--loading-min-height` |
|
|
125
132
|
| **EmptyState** | Пустой / ошибка | `title`, `description`, `icon`, `actions`; `--empty-*` |
|
|
126
|
-
| **
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
| **PanelInfo** | Выезд справа | `open` / `defaultOpen`, `onOpenChange` |
|
|
134
|
+
| **createLazyResolver** | Кэш `import()` секций | `(key) => import(…)`; `.clear(segment?)` при ошибке / retry |
|
|
135
|
+
|
|
136
|
+
Раскладка — только `Stack` (или `Section` с `direction`/`gap`/`columns`). `Block` / `Row` / `Column` **удалены** из пакета; в проектах: `elcrm migrate components`.
|
|
137
|
+
|
|
138
|
+
### Кто когда (роли)
|
|
139
|
+
|
|
140
|
+
Не сливаем компоненты — выбирай по слою:
|
|
141
|
+
|
|
142
|
+
| Слой | Компоненты | Не путать с |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| Оболочка app | `Layout` (+ Header / Footer / Sidebar) | PageShell |
|
|
145
|
+
| Каркас модуля | `PageShell` | Section |
|
|
146
|
+
| Шапка страницы | `PageHead` | Section title |
|
|
147
|
+
| Блок контента | `Section` (`direction` / `gap` / `columns` как у Stack) | PageHead |
|
|
148
|
+
| Нав app | `Sidebar` | NavSections (страница + lazy-панель) |
|
|
149
|
+
| Вкладки | `Menu variant="line"` = только табы; `TabSections` = табы + lazy-панель | |
|
|
150
|
+
| Две колонки | `SplitPane` = resize; `ChatSplit` = чат list+messages без resize | |
|
|
151
|
+
| Чат | `ChatList` / `ChatMessages` / `ChatSplit`; `ChatFrame` — deep `@elcrm/components/ChatFrame` | |
|
|
152
|
+
| Таблица | `Table` (`stickyHeader`) | PricingTable |
|
|
153
|
+
| Выбор планов | `PricingGroup` / `PricingTable`; `RadioGroup variant="split"` — общий radio-UI | |
|
|
154
|
+
| Toolbar | `Toolbar` = фильтры одной высоты; `ActionGroup` = иконки в карточке | |
|
|
155
|
+
| Текст | `Text` / `TextGroup` / `AvatarName` (+аватар) | |
|
|
156
|
+
| Статус | `Badge` метка; `Banner` полоса; `EmptyState` пустой экран | |
|
|
157
|
+
| Раскладка | `Stack` | Block / Row / Column |
|
|
131
158
|
|
|
132
159
|
### Sidebar
|
|
133
160
|
|
|
@@ -137,8 +164,8 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
|
|
|
137
164
|
<Sidebar
|
|
138
165
|
variant="cards"
|
|
139
166
|
value={page}
|
|
140
|
-
|
|
141
|
-
brand={<Brand
|
|
167
|
+
onValueChange={setPage}
|
|
168
|
+
brand={<Brand>App</Brand>}
|
|
142
169
|
extra={<Notifications.Bell />}
|
|
143
170
|
groups={[
|
|
144
171
|
{
|
|
@@ -167,7 +194,7 @@ import { RadioGroup } from "@elcrm/components/RadioGroup";
|
|
|
167
194
|
{ value: "theme", label: "Тема", submenu: true },
|
|
168
195
|
{ value: "logout", label: "Выйти", danger: true },
|
|
169
196
|
]}
|
|
170
|
-
|
|
197
|
+
onFooterValueChange={(value) => console.log(value)}
|
|
171
198
|
version="v 0.2.26"
|
|
172
199
|
/>
|
|
173
200
|
```
|
|
@@ -359,18 +386,24 @@ const sections = [
|
|
|
359
386
|
| ------------- | -------------------------------------------------------------------------------------------------------- |
|
|
360
387
|
| **PageShell** | Каркас модуля: скролл в body (`scroll`, по умолчанию да), опциональный footer снизу |
|
|
361
388
|
| **PageHead** | Строка title (+ `sup` надстрочно, subtitle) слева и actions справа; `sticky` — прилипает к верху скролла |
|
|
362
|
-
| **Section** | Блок контента / auth
|
|
389
|
+
| **Section** | Блок контента / auth / подраздел. Корень по умолчанию `<section>` (не `<main>` — его даёт Layout). Тело: `direction` / `gap` / `columns` как у Stack |
|
|
363
390
|
|
|
364
391
|
```tsx
|
|
365
|
-
<PageShell scroll footer={<
|
|
392
|
+
<PageShell scroll footer={<Button>Сохранить</Button>}>
|
|
366
393
|
<PageHead
|
|
367
394
|
sticky
|
|
368
395
|
title="Товары"
|
|
369
396
|
sup={12}
|
|
370
397
|
subtitle="Каталог"
|
|
371
|
-
actions={<
|
|
398
|
+
actions={<Button>Добавить</Button>}
|
|
372
399
|
/>
|
|
373
|
-
<Section title="Фильтры"
|
|
400
|
+
<Section title="Фильтры" direction="row" gap={12}>
|
|
401
|
+
<SearchField name="q" />
|
|
402
|
+
<Button>Найти</Button>
|
|
403
|
+
</Section>
|
|
404
|
+
<Section title="Метрики" direction="grid" columns={3} gap={16}>
|
|
405
|
+
<Stat label="Всего" value={10} />
|
|
406
|
+
</Section>
|
|
374
407
|
</PageShell>
|
|
375
408
|
```
|
|
376
409
|
|
|
@@ -433,11 +466,11 @@ const people = [
|
|
|
433
466
|
max={5}
|
|
434
467
|
add
|
|
435
468
|
onAdd={() => {}}
|
|
436
|
-
|
|
469
|
+
onValueChange={(value) => console.log(value)}
|
|
437
470
|
/>
|
|
438
471
|
```
|
|
439
472
|
|
|
440
|
-
`max` — сколько показать; остаток → «+N». `add` — кнопка «+» справа.
|
|
473
|
+
`max` — сколько показать; остаток → «+N». `add` — кнопка «+» справа. У каждого пункта обязателен `value`.
|
|
441
474
|
|
|
442
475
|
### Avatar / AvatarName
|
|
443
476
|
|
|
@@ -493,7 +526,7 @@ const people = [
|
|
|
493
526
|
items: [{ value: "details", label: "View details", submenu: true }],
|
|
494
527
|
},
|
|
495
528
|
]}
|
|
496
|
-
|
|
529
|
+
onValueChange={(value) => console.log(value)}
|
|
497
530
|
/>;
|
|
498
531
|
|
|
499
532
|
{
|
|
@@ -568,13 +601,13 @@ const people = [
|
|
|
568
601
|
},
|
|
569
602
|
{ value: "brand", label: "Бренд", checkbox: true, checked: false },
|
|
570
603
|
]}
|
|
571
|
-
|
|
604
|
+
onValueChange={(value) => toggleColumn(value)}
|
|
572
605
|
/>;
|
|
573
606
|
```
|
|
574
607
|
|
|
575
608
|
`Menu` — навигация в шапке (inline, не popover).
|
|
576
609
|
|
|
577
|
-
**Dropdown vs Popover:** `Dropdown` — пункты `items`/`groups`. `Popover` — свой `children` в portal (
|
|
610
|
+
**Dropdown vs Popover:** `Dropdown` — пункты `items`/`groups`. `Popover` — свой `children` в portal; канон `trigger={(api) => <button {...api.anchorProps}>…</button>}` (без cloneElement). `@elcrm/overlay` `Menu` — устаревший алиас `Popover`. Select — `@elcrm/form`, не overlay.
|
|
578
611
|
|
|
579
612
|
### Breadcrumb
|
|
580
613
|
|
|
@@ -621,7 +654,7 @@ const people = [
|
|
|
621
654
|
```tsx
|
|
622
655
|
<Layout
|
|
623
656
|
fixed={["header", "footer", "sidebar"]}
|
|
624
|
-
sidebar={<Sidebar groups={groups} value={page}
|
|
657
|
+
sidebar={<Sidebar groups={groups} value={page} onValueChange={setPage} />}
|
|
625
658
|
header={
|
|
626
659
|
<Header
|
|
627
660
|
brand={<Brand onClick={() => {}}>App</Brand>}
|
|
@@ -675,6 +708,7 @@ const resolve = createLazyResolver(
|
|
|
675
708
|
resolveSection={resolve}
|
|
676
709
|
groups={[
|
|
677
710
|
{
|
|
711
|
+
value: "personal",
|
|
678
712
|
label: "Личное",
|
|
679
713
|
items: [
|
|
680
714
|
{ value: "Profile", label: "Профиль" },
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import c from "react";
|
|
2
|
+
import { c as l } from "./cx-CcykAxZN.js";
|
|
3
|
+
import './ActionGroup.css';const n = "lgr", s = {
|
|
4
|
+
root: n
|
|
5
|
+
};
|
|
6
|
+
function p({
|
|
7
|
+
label: o,
|
|
8
|
+
actions: r,
|
|
9
|
+
children: t,
|
|
10
|
+
className: a,
|
|
11
|
+
...e
|
|
12
|
+
}) {
|
|
13
|
+
return /* @__PURE__ */ c.createElement(
|
|
14
|
+
"div",
|
|
15
|
+
{
|
|
16
|
+
className: l(s.root, a),
|
|
17
|
+
role: "toolbar",
|
|
18
|
+
"aria-label": o,
|
|
19
|
+
...e
|
|
20
|
+
},
|
|
21
|
+
r,
|
|
22
|
+
t
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
p as A
|
|
27
|
+
};
|
package/dist/ActionGroup.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer elcrm-components{.
|
|
1
|
+
@layer elcrm-components{.lgr{display:flex;flex-wrap:nowrap;align-items:center;gap:var(--action-group-gap);flex:0 0 auto}}
|
package/dist/ActionGroup.d.ts
CHANGED
|
@@ -2,26 +2,23 @@ import { default as React } from 'react';
|
|
|
2
2
|
/**
|
|
3
3
|
* Ряд действий в строке списка / карточке (`role="toolbar"`).
|
|
4
4
|
*
|
|
5
|
-
* Роли: тулбар иконок справа в Card. Кнопки — `@elcrm/button` / свои
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @param label подпись для `aria-label`
|
|
9
|
-
* @param items массив узлов (если нет — только `children`)
|
|
10
|
-
* @param children слот кнопок; можно вместе с `items` (сначала items)
|
|
5
|
+
* Роли: тулбар иконок справа в Card. Кнопки — `@elcrm/button` / свои слоты.
|
|
6
|
+
* Слоты — `children` (и опционально `actions` массивом узлов).
|
|
7
|
+
* Не путать с декларативными `items` у Menu / RadioGroup.
|
|
11
8
|
*
|
|
12
9
|
* @example
|
|
13
10
|
* ```tsx
|
|
11
|
+
* <ActionGroup label="Действия: Иван">
|
|
12
|
+
* <Button variant="ghost" onClick={edit}>Изменить</Button>
|
|
13
|
+
* <Button variant="ghost" onClick={remove}>Удалить</Button>
|
|
14
|
+
* </ActionGroup>
|
|
15
|
+
*
|
|
14
16
|
* <ActionGroup
|
|
15
|
-
* label="
|
|
16
|
-
*
|
|
17
|
-
* <Button key="
|
|
18
|
-
* <Button key="del" variant="ghost" onClick={remove}>Удалить</Button>,
|
|
17
|
+
* label="Ещё"
|
|
18
|
+
* actions={[
|
|
19
|
+
* <Button key="copy" variant="ghost">Копировать</Button>,
|
|
19
20
|
* ]}
|
|
20
21
|
* />
|
|
21
|
-
*
|
|
22
|
-
* <ActionGroup label="Ещё">
|
|
23
|
-
* <Button variant="ghost">Копировать</Button>
|
|
24
|
-
* </ActionGroup>
|
|
25
22
|
* ```
|
|
26
23
|
*
|
|
27
24
|
* Токены: `--action-group-gap` (иначе `--shell-gap-sm`).
|
|
@@ -29,14 +26,17 @@ import { default as React } from 'react';
|
|
|
29
26
|
export type ActionGroupProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
30
27
|
/** Подпись тулбара (`aria-label`) */
|
|
31
28
|
label: string;
|
|
32
|
-
/**
|
|
33
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Кнопки массивом узлов (не декларативные `items` групп).
|
|
31
|
+
* Можно вместе с `children` (сначала `actions`).
|
|
32
|
+
*/
|
|
33
|
+
actions?: React.ReactNode[];
|
|
34
34
|
/** Свои кнопки / слоты */
|
|
35
35
|
children?: React.ReactNode;
|
|
36
36
|
};
|
|
37
37
|
/**
|
|
38
|
-
* Группа действий: `
|
|
38
|
+
* Группа действий: `actions` и/или `children`.
|
|
39
39
|
*
|
|
40
|
-
* @see Card, Stack, Item
|
|
40
|
+
* @see Card, Stack, Item, Toolbar
|
|
41
41
|
*/
|
|
42
|
-
export declare function ActionGroup({ label,
|
|
42
|
+
export declare function ActionGroup({ label, actions, children, className, ...rest }: ActionGroupProps): React.JSX.Element;
|
package/dist/ActionGroup.js
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import a from "react";
|
|
2
|
+
import { c as p } from "./cx-CcykAxZN.js";
|
|
3
|
+
import './Avatar.css';const x = "aar", h = "aav", A = "aas", C = "aam", S = "aal", z = "aaa", B = "aai", F = "aab", R = "aao", U = "aaf", e = {
|
|
4
|
+
root: x,
|
|
5
|
+
vtext: h,
|
|
6
|
+
small: A,
|
|
7
|
+
middle: C,
|
|
8
|
+
large: S,
|
|
9
|
+
active: z,
|
|
10
|
+
img: B,
|
|
11
|
+
bead: F,
|
|
12
|
+
online: R,
|
|
13
|
+
foff: U
|
|
14
|
+
};
|
|
15
|
+
function D(t) {
|
|
16
|
+
const n = t.trim();
|
|
17
|
+
if (!n) return "?";
|
|
18
|
+
const l = n.split(/\s+/).filter(Boolean);
|
|
19
|
+
return l.length >= 2 ? (l[0][0] + l[1][0]).toUpperCase() : n.slice(0, 2).toUpperCase();
|
|
20
|
+
}
|
|
21
|
+
function $(t) {
|
|
22
|
+
if (!(t == null || t === ""))
|
|
23
|
+
return {
|
|
24
|
+
"--avatar-radius": typeof t == "number" ? `${t}px` : t
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function j({ status: t }) {
|
|
28
|
+
return /* @__PURE__ */ a.createElement(
|
|
29
|
+
"span",
|
|
30
|
+
{
|
|
31
|
+
className: p(e.bead, t === "online" ? e.online : e.foff),
|
|
32
|
+
"data-status": t,
|
|
33
|
+
"aria-hidden": !0
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function k({
|
|
38
|
+
src: t,
|
|
39
|
+
label: n,
|
|
40
|
+
children: l,
|
|
41
|
+
name: r,
|
|
42
|
+
status: i
|
|
43
|
+
}) {
|
|
44
|
+
const s = t != null && t !== "" ? /* @__PURE__ */ a.createElement("img", { className: e.img, src: t, alt: n ?? "", draggable: !1 }) : l ?? (r != null ? D(r) : "?");
|
|
45
|
+
return /* @__PURE__ */ a.createElement(a.Fragment, null, /* @__PURE__ */ a.createElement("span", { className: e.vtext }, s), i != null ? /* @__PURE__ */ a.createElement(j, { status: i }) : null);
|
|
46
|
+
}
|
|
47
|
+
function G(t) {
|
|
48
|
+
const {
|
|
49
|
+
src: n,
|
|
50
|
+
alt: l,
|
|
51
|
+
name: r,
|
|
52
|
+
size: i = "m",
|
|
53
|
+
status: s,
|
|
54
|
+
active: c,
|
|
55
|
+
children: b,
|
|
56
|
+
className: g,
|
|
57
|
+
radius: y,
|
|
58
|
+
as: v = "span",
|
|
59
|
+
style: E,
|
|
60
|
+
...m
|
|
61
|
+
} = t, N = i === "s" ? e.small : i === "l" ? e.large : e.middle, u = p(e.root, N, c && e.active, g), o = l ?? r, d = { ...$(y), ...E }, f = /* @__PURE__ */ a.createElement(
|
|
62
|
+
k,
|
|
63
|
+
{
|
|
64
|
+
src: n,
|
|
65
|
+
label: o,
|
|
66
|
+
name: r,
|
|
67
|
+
status: s,
|
|
68
|
+
children: b
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
return v === "button" ? /* @__PURE__ */ a.createElement(
|
|
72
|
+
"button",
|
|
73
|
+
{
|
|
74
|
+
type: "button",
|
|
75
|
+
className: u,
|
|
76
|
+
"aria-label": o,
|
|
77
|
+
"data-active": c ? "true" : void 0,
|
|
78
|
+
"data-status": s,
|
|
79
|
+
style: d,
|
|
80
|
+
...m
|
|
81
|
+
},
|
|
82
|
+
f
|
|
83
|
+
) : v === "div" ? /* @__PURE__ */ a.createElement(
|
|
84
|
+
"div",
|
|
85
|
+
{
|
|
86
|
+
className: u,
|
|
87
|
+
role: o ? "img" : void 0,
|
|
88
|
+
"aria-label": o,
|
|
89
|
+
"data-active": c ? "true" : void 0,
|
|
90
|
+
"data-status": s,
|
|
91
|
+
style: d,
|
|
92
|
+
...m
|
|
93
|
+
},
|
|
94
|
+
f
|
|
95
|
+
) : /* @__PURE__ */ a.createElement(
|
|
96
|
+
"span",
|
|
97
|
+
{
|
|
98
|
+
className: u,
|
|
99
|
+
role: o ? "img" : void 0,
|
|
100
|
+
"aria-label": o,
|
|
101
|
+
"data-active": c ? "true" : void 0,
|
|
102
|
+
"data-status": s,
|
|
103
|
+
style: d,
|
|
104
|
+
...m
|
|
105
|
+
},
|
|
106
|
+
f
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
G as A,
|
|
111
|
+
$ as a,
|
|
112
|
+
D as i
|
|
113
|
+
};
|
package/dist/Avatar.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer elcrm-components{.
|
|
1
|
+
@layer elcrm-components{.aar{position:relative;box-sizing:border-box;display:inline-flex;flex-shrink:0;width:fit-content;height:fit-content;border-radius:var(--avatar-radius);-webkit-user-select:none;user-select:none;vertical-align:middle}.aar:is(button){-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0;padding:0;font:inherit;cursor:pointer;background:transparent;border:none}.aav{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;overflow:hidden;width:100%;height:100%;border-radius:inherit;border:var(--avatar-border);background:var(--avatar-background);color:var(--avatar-color);font-weight:var(--avatar-font-weight);line-height:1}.aas{width:var(--avatar-size-s);height:var(--avatar-size-s);font-size:var(--avatar-font-size-s)}.aas .aav{font-size:inherit}.aam{width:var(--avatar-size-m);height:var(--avatar-size-m);font-size:var(--avatar-font-size-m)}.aam .aav{font-size:inherit}.aal{width:var(--avatar-size-l);height:var(--avatar-size-l);font-size:var(--avatar-font-size-l)}.aal .aav{font-size:inherit}.aaa .aav,.aar[data-active=true] .aav{outline:var(--avatar-outline-active);outline-offset:var(--avatar-outline-offset)}.aai{width:100%;height:100%;object-fit:cover;display:block}.aab{position:absolute;right:0;bottom:0;box-sizing:border-box;width:var(--shell-status-size);height:var(--shell-status-size);border-radius:50%;border:2px solid var(--shell-background);pointer-events:none}.aas .aab{width:8px;height:8px}.aam .aab{width:var(--shell-status-size);height:var(--shell-status-size)}.aal .aab{width:12px;height:12px}.aao{background:var(--shell-color-success)}.aaf{background:var(--shell-color-muted)}}
|
package/dist/Avatar.d.ts
CHANGED
|
@@ -48,10 +48,10 @@ export declare function avatarRadiusStyle(radius?: number | string): React.CSSPr
|
|
|
48
48
|
*
|
|
49
49
|
* По умолчанию `as="span"`. Для кликабельного аватара — `as="button"`.
|
|
50
50
|
*/
|
|
51
|
-
export type AvatarProps = (Common & React.
|
|
52
|
-
as?: "
|
|
53
|
-
}) | (Common & React.
|
|
54
|
-
as: "
|
|
51
|
+
export type AvatarProps = (Common & React.HTMLAttributes<HTMLSpanElement> & {
|
|
52
|
+
as?: "span";
|
|
53
|
+
}) | (Common & React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
54
|
+
as: "button";
|
|
55
55
|
}) | (Common & React.HTMLAttributes<HTMLDivElement> & {
|
|
56
56
|
as: "div";
|
|
57
57
|
});
|
package/dist/Avatar.js
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import e from "react";
|
|
2
|
+
import { A as f } from "./Avatar-eGdLrMCv.js";
|
|
3
|
+
import { c } from "./cx-CcykAxZN.js";
|
|
4
|
+
import './AvatarGroup.css';const C = "lar", I = "lai", P = "lao", x = "lad", G = "las", M = "lam", R = "lal", t = {
|
|
5
|
+
root: C,
|
|
6
|
+
item: I,
|
|
7
|
+
overflow: P,
|
|
8
|
+
dadd: x,
|
|
9
|
+
small: G,
|
|
10
|
+
middle: M,
|
|
11
|
+
large: R
|
|
12
|
+
};
|
|
13
|
+
function $(a) {
|
|
14
|
+
if (a.name != null && a.name !== "") return a.name;
|
|
15
|
+
if (a.title != null && a.title !== "") return a.title;
|
|
16
|
+
}
|
|
17
|
+
function B({
|
|
18
|
+
items: a,
|
|
19
|
+
max: s,
|
|
20
|
+
size: n = "m",
|
|
21
|
+
add: v = !1,
|
|
22
|
+
addLabel: b = "Добавить",
|
|
23
|
+
onAdd: r,
|
|
24
|
+
onValueChange: u,
|
|
25
|
+
className: g,
|
|
26
|
+
"aria-label": E = "Аватары",
|
|
27
|
+
...h
|
|
28
|
+
}) {
|
|
29
|
+
const i = n === "s" ? t.small : n === "l" ? t.large : t.middle, k = s != null && s >= 0 ? Math.min(s, a.length) : a.length, m = a.slice(0, k), o = a.length - m.length;
|
|
30
|
+
return /* @__PURE__ */ e.createElement(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
className: c(t.root, g),
|
|
34
|
+
role: "group",
|
|
35
|
+
"aria-label": E,
|
|
36
|
+
...h
|
|
37
|
+
},
|
|
38
|
+
m.map((l, N) => {
|
|
39
|
+
const p = $(l), d = l.alt ?? l.title ?? l.name, w = u != null;
|
|
40
|
+
return /* @__PURE__ */ e.createElement("span", { key: l.value, className: t.item, style: { zIndex: N + 1 } }, w ? /* @__PURE__ */ e.createElement(
|
|
41
|
+
f,
|
|
42
|
+
{
|
|
43
|
+
as: "button",
|
|
44
|
+
src: l.src,
|
|
45
|
+
name: p,
|
|
46
|
+
alt: d,
|
|
47
|
+
size: n,
|
|
48
|
+
status: l.status,
|
|
49
|
+
onClick: (y) => {
|
|
50
|
+
y.stopPropagation(), u(l.value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
) : /* @__PURE__ */ e.createElement(
|
|
54
|
+
f,
|
|
55
|
+
{
|
|
56
|
+
src: l.src,
|
|
57
|
+
name: p,
|
|
58
|
+
alt: d,
|
|
59
|
+
size: n,
|
|
60
|
+
status: l.status
|
|
61
|
+
}
|
|
62
|
+
));
|
|
63
|
+
}),
|
|
64
|
+
o > 0 ? /* @__PURE__ */ e.createElement("span", { className: c(t.overflow, i), "aria-label": `Ещё ${o}` }, "+", o) : null,
|
|
65
|
+
v ? /* @__PURE__ */ e.createElement(
|
|
66
|
+
"button",
|
|
67
|
+
{
|
|
68
|
+
type: "button",
|
|
69
|
+
className: c(t.dadd, i),
|
|
70
|
+
"aria-label": b,
|
|
71
|
+
onClick: (l) => {
|
|
72
|
+
l.stopPropagation(), r == null || r();
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"+"
|
|
76
|
+
) : null
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
B as A
|
|
81
|
+
};
|
package/dist/AvatarGroup.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer elcrm-components{.
|
|
1
|
+
@layer elcrm-components{.lar{display:inline-flex;align-items:center;vertical-align:middle}.lai{position:relative;margin-left:var(--avatar-group-overlap);box-shadow:0 0 0 var(--avatar-group-ring) var(--shell-background);border-radius:var(--avatar-radius)}.lai:first-child{margin-left:0}.lao,.lad{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;margin-left:var(--avatar-group-overlap);border-radius:var(--avatar-radius);font-weight:var(--avatar-font-weight);line-height:1;-webkit-user-select:none;user-select:none}.lao{z-index:20;color:var(--shell-color-muted);background:var(--shell-background-muted);border:1px solid var(--shell-border);box-shadow:0 0 0 var(--avatar-group-ring) var(--shell-background)}.lad{z-index:21;margin-left:var(--shell-gap-sm);color:var(--shell-color-muted);background:var(--shell-background);border:1px dashed var(--shell-border);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;font:inherit;font-weight:var(--avatar-font-weight)}.lad:hover{background:var(--shell-background-hover)}.las{width:var(--avatar-size-s);height:var(--avatar-size-s);font-size:var(--avatar-font-size-s)}.lam{width:var(--avatar-size-m);height:var(--avatar-size-m);font-size:var(--avatar-font-size-m)}.lal{width:var(--avatar-size-l);height:var(--avatar-size-l);font-size:var(--avatar-font-size-l)}}
|
package/dist/AvatarGroup.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { UiSize } from './types';
|
|
|
3
3
|
/**
|
|
4
4
|
* Элемент стопки {@link AvatarGroup}.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* `name` — только для инициалов; видимую подпись
|
|
6
|
+
* Идентификатор — `value` (как у остальных group-UI).
|
|
7
|
+
* `name` — только для инициалов; видимую подпись — {@link AvatarName}.
|
|
8
8
|
*/
|
|
9
9
|
export type AvatarGroupItem = {
|
|
10
|
-
/** Уникальный id (
|
|
11
|
-
value
|
|
10
|
+
/** Уникальный id (не React `key`). */
|
|
11
|
+
value: string;
|
|
12
12
|
/** URL фото. */
|
|
13
13
|
src?: string;
|
|
14
14
|
/** Только для инициалов (если нет `src`). */
|
|
@@ -38,41 +38,21 @@ export type AvatarGroupProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
|
38
38
|
addLabel?: string;
|
|
39
39
|
/** Клик по кнопке добавления. */
|
|
40
40
|
onAdd?: () => void;
|
|
41
|
-
/** Клик по
|
|
42
|
-
|
|
41
|
+
/** Клик по аватару (`item.value`). */
|
|
42
|
+
onValueChange?: (value: string) => void;
|
|
43
43
|
};
|
|
44
44
|
/**
|
|
45
45
|
* Стопка аватаров с оверлапом, счётчиком «+N» и опциональной кнопкой добавления.
|
|
46
46
|
*
|
|
47
|
-
* Когда использовать:
|
|
48
|
-
* - участники задачи / канала / сделки в одну строку;
|
|
49
|
-
* - нужно ограничить видимое число (`max`) и добавить «+».
|
|
50
|
-
*
|
|
51
|
-
* Связанные компоненты:
|
|
52
|
-
* - {@link Avatar} — одиночный аватар;
|
|
53
|
-
* - {@link AvatarName} — аватар с текстовой подписью (`title` / `description`).
|
|
54
|
-
*
|
|
55
|
-
* API: декларативные `items`. Идентификатор предпочтительно `value` (не `key`).
|
|
56
|
-
* Compound-слоты не используются.
|
|
57
|
-
*
|
|
58
|
-
* CSS-токены: `--avatar-group-*`, размеры из `--avatar-size-*`.
|
|
59
|
-
*
|
|
60
47
|
* @example
|
|
61
48
|
* ```tsx
|
|
62
|
-
* const items = [
|
|
63
|
-
* { value: "u1", name: "Иван Петров", src: "/u/1.jpg", status: "online" },
|
|
64
|
-
* { value: "u2", name: "Мария Смирнова" },
|
|
65
|
-
* { value: "u3", name: "Алексей" },
|
|
66
|
-
* ];
|
|
67
|
-
*
|
|
68
49
|
* <AvatarGroup
|
|
69
50
|
* items={items}
|
|
70
51
|
* max={5}
|
|
71
|
-
* size="m"
|
|
72
52
|
* add
|
|
73
53
|
* onAdd={() => openInvite()}
|
|
74
|
-
*
|
|
54
|
+
* onValueChange={(value) => openProfile(value)}
|
|
75
55
|
* />
|
|
76
56
|
* ```
|
|
77
57
|
*/
|
|
78
|
-
export declare function AvatarGroup({ items, max, size, add, addLabel, onAdd,
|
|
58
|
+
export declare function AvatarGroup({ items, max, size, add, addLabel, onAdd, onValueChange, className, "aria-label": ariaLabel, ...rest }: AvatarGroupProps): React.JSX.Element;
|
package/dist/AvatarGroup.js
CHANGED