@ziyarago/ui 0.17.0 → 0.19.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.
- package/CHANGELOG.md +12 -0
- package/dist/llms-full.txt +8 -4
- package/dist/llms.txt +1 -1
- package/dist/manifest.json +24 -8
- package/dist/style.css +12 -1
- package/package.json +1 -1
- package/src/core/components.js +63 -3
- package/src/i18n/components/TopNav.js +3 -3
- package/src/icons/builtin.js +6 -0
- package/src/meta/navigation.js +7 -5
- package/src/styles/components.css +1 -1
- package/src/styles/components8.css +11 -0
- package/types/react.d.ts +17 -5
- package/types/vue.d.ts +17 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [0.19.0](https://github.com/ziyarago/ui/compare/v0.18.0...v0.19.0) (2026-10-21)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* SideNav expandable groups with children ([9572ae4](https://github.com/ziyarago/ui/commit/9572ae48a261a8fa3ec3e5d023858d91c2f4cd9b))
|
|
6
|
+
|
|
7
|
+
## [0.18.0](https://github.com/ziyarago/ui/compare/v0.17.0...v0.18.0) (2026-10-21)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* TopNav sub-menus with icons and overflow into a More menu, no edge fade ([ed1addd](https://github.com/ziyarago/ui/commit/ed1addd0d9a9844b4e6e23bbe86b18a5a01a74be))
|
|
12
|
+
|
|
1
13
|
## [0.17.0](https://github.com/ziyarago/ui/compare/v0.16.0...v0.17.0) (2026-10-21)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/dist/llms-full.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 102 free components and 6 page templates (more in @ziyarago/ui-pro).
|
|
4
4
|
|
|
5
|
-
Version 0.
|
|
5
|
+
Version 0.19.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
|
|
6
6
|
|
|
7
7
|
## Setup
|
|
8
8
|
- import { UiButton } from '@ziyarago/ui/vue'
|
|
@@ -1828,22 +1828,25 @@ Notes:
|
|
|
1828
1828
|
Horizontal app header with a brand area, navigation items and an actions area.
|
|
1829
1829
|
Props:
|
|
1830
1830
|
- `brand`: string | VNode. Logo or product name on the left.
|
|
1831
|
-
- `items`: { value: string; label: string; icon?: string; count?: string | number }[] = "[]". Navigation entries. count renders a small counter after the label.
|
|
1831
|
+
- `items`: { value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number; disabled?: boolean } | { heading: string } | { separator: true })[] }[] = "[]". Navigation entries. count renders a small counter after the label. An entry with children becomes a drop-down: click or ArrowDown opens a menu of its children (each with an optional icon and count, headings and separators allowed); selecting one calls change with the child value. The entry is marked current when one of its children is.
|
|
1832
1832
|
- `value`: string. Value of the active item (aria-current="page").
|
|
1833
|
+
- `overflow`: 'menu' | 'none' = "menu". 'menu': entries that do not fit move into a trailing "More" drop-down (measured after render and on resize; server rendering shows all entries). 'none': no collapsing, the row scrolls sideways and sub-menus are clipped, so avoid children with it.
|
|
1834
|
+
- `moreLabel`: string = "More". Accessible name of the overflow drop-down button.
|
|
1833
1835
|
- `size`: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = "md". Scale of header padding, item height and text.
|
|
1834
1836
|
Slots:
|
|
1835
1837
|
- actions: Right side of the header (buttons, avatar). React also accepts an actions prop.
|
|
1836
1838
|
Events:
|
|
1837
|
-
- change: Called with the value of the clicked item.
|
|
1839
|
+
- change: Called with the value of the clicked item or sub-menu item.
|
|
1838
1840
|
Notes:
|
|
1839
1841
|
- Controlled: update value yourself in the change handler.
|
|
1840
1842
|
- Items use count; SubNav uses badge for the same purpose.
|
|
1843
|
+
- Entries with children and the More menu share the Dropdown keyboard behaviour: ArrowDown opens, arrows and Home/End move, Escape closes and returns focus to the button.
|
|
1841
1844
|
|
|
1842
1845
|
## UiSideNav (navigation)
|
|
1843
1846
|
Vertical sidebar with a brand, grouped navigation items, a footer and an optional collapse toggle.
|
|
1844
1847
|
Props:
|
|
1845
1848
|
- `brand`: string | VNode. Logo or product name at the top.
|
|
1846
|
-
- `items`: ({ value: string; label: string; icon?: string; count?: string | number } | { group: string })[] = "[]". Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count.
|
|
1849
|
+
- `items`: ({ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number } | { separator: true })[] } | { group: string })[] = "[]". Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count. An entry with children is an expandable group: its button toggles the list of children (open by default while one of them is current); selecting a child calls change with the child value.
|
|
1847
1850
|
- `value`: string. Value of the active item (aria-current="page").
|
|
1848
1851
|
- `collapsed`: boolean = false. Icon-only mode; labels move to the title tooltip.
|
|
1849
1852
|
- `collapsible`: boolean = false. Always draw the collapse button, even without a toggle handler (the button is also drawn when a toggle handler is set).
|
|
@@ -1857,6 +1860,7 @@ Events:
|
|
|
1857
1860
|
Notes:
|
|
1858
1861
|
- Collapsing is controlled: flip collapsed in the toggle handler.
|
|
1859
1862
|
- Group entries are keyed by their title, so keep group names unique.
|
|
1863
|
+
- In the collapsed rail the children of an open group show as icons (children without an icon get a dot).
|
|
1860
1864
|
|
|
1861
1865
|
## UiSubNav (navigation)
|
|
1862
1866
|
Compact vertical list of sections with an optional title; use for settings and secondary page navigation.
|
package/dist/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 102 free components and 6 page templates (more in @ziyarago/ui-pro).
|
|
4
4
|
|
|
5
|
-
Version 0.
|
|
5
|
+
Version 0.19.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
|
|
6
6
|
|
|
7
7
|
## Setup
|
|
8
8
|
- import { UiButton } from '@ziyarago/ui/vue'
|
package/dist/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziyarago/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"homepage": "https://ziyara.vip",
|
|
5
5
|
"imports": {
|
|
6
6
|
"vue": "import { UiButton } from '@ziyarago/ui/vue'",
|
|
@@ -12173,14 +12173,28 @@
|
|
|
12173
12173
|
"description": "Logo or product name on the left."
|
|
12174
12174
|
},
|
|
12175
12175
|
"items": {
|
|
12176
|
-
"type": "{ value: string; label: string; icon?: string; count?: string | number }[]",
|
|
12176
|
+
"type": "{ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number; disabled?: boolean } | { heading: string } | { separator: true })[] }[]",
|
|
12177
12177
|
"default": "[]",
|
|
12178
|
-
"description": "Navigation entries. count renders a small counter after the label."
|
|
12178
|
+
"description": "Navigation entries. count renders a small counter after the label. An entry with children becomes a drop-down: click or ArrowDown opens a menu of its children (each with an optional icon and count, headings and separators allowed); selecting one calls change with the child value. The entry is marked current when one of its children is."
|
|
12179
12179
|
},
|
|
12180
12180
|
"value": {
|
|
12181
12181
|
"type": "string",
|
|
12182
12182
|
"description": "Value of the active item (aria-current=\"page\")."
|
|
12183
12183
|
},
|
|
12184
|
+
"overflow": {
|
|
12185
|
+
"type": "'menu' | 'none'",
|
|
12186
|
+
"values": [
|
|
12187
|
+
"menu",
|
|
12188
|
+
"none"
|
|
12189
|
+
],
|
|
12190
|
+
"default": "menu",
|
|
12191
|
+
"description": "'menu': entries that do not fit move into a trailing \"More\" drop-down (measured after render and on resize; server rendering shows all entries). 'none': no collapsing, the row scrolls sideways and sub-menus are clipped, so avoid children with it."
|
|
12192
|
+
},
|
|
12193
|
+
"moreLabel": {
|
|
12194
|
+
"type": "string",
|
|
12195
|
+
"default": "More",
|
|
12196
|
+
"description": "Accessible name of the overflow drop-down button."
|
|
12197
|
+
},
|
|
12184
12198
|
"size": {
|
|
12185
12199
|
"type": "'xs' | 'sm' | 'md' | 'lg' | 'xl'",
|
|
12186
12200
|
"values": [
|
|
@@ -12198,11 +12212,12 @@
|
|
|
12198
12212
|
"actions": "Right side of the header (buttons, avatar). React also accepts an actions prop."
|
|
12199
12213
|
},
|
|
12200
12214
|
"events": {
|
|
12201
|
-
"change": "Called with the value of the clicked item."
|
|
12215
|
+
"change": "Called with the value of the clicked item or sub-menu item."
|
|
12202
12216
|
},
|
|
12203
12217
|
"notes": [
|
|
12204
12218
|
"Controlled: update value yourself in the change handler.",
|
|
12205
|
-
"Items use count; SubNav uses badge for the same purpose."
|
|
12219
|
+
"Items use count; SubNav uses badge for the same purpose.",
|
|
12220
|
+
"Entries with children and the More menu share the Dropdown keyboard behaviour: ArrowDown opens, arrows and Home/End move, Escape closes and returns focus to the button."
|
|
12206
12221
|
]
|
|
12207
12222
|
},
|
|
12208
12223
|
{
|
|
@@ -12218,9 +12233,9 @@
|
|
|
12218
12233
|
"description": "Logo or product name at the top."
|
|
12219
12234
|
},
|
|
12220
12235
|
"items": {
|
|
12221
|
-
"type": "({ value: string; label: string; icon?: string; count?: string | number } | { group: string })[]",
|
|
12236
|
+
"type": "({ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number } | { separator: true })[] } | { group: string })[]",
|
|
12222
12237
|
"default": "[]",
|
|
12223
|
-
"description": "Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count."
|
|
12238
|
+
"description": "Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count. An entry with children is an expandable group: its button toggles the list of children (open by default while one of them is current); selecting a child calls change with the child value."
|
|
12224
12239
|
},
|
|
12225
12240
|
"value": {
|
|
12226
12241
|
"type": "string",
|
|
@@ -12263,7 +12278,8 @@
|
|
|
12263
12278
|
},
|
|
12264
12279
|
"notes": [
|
|
12265
12280
|
"Collapsing is controlled: flip collapsed in the toggle handler.",
|
|
12266
|
-
"Group entries are keyed by their title, so keep group names unique."
|
|
12281
|
+
"Group entries are keyed by their title, so keep group names unique.",
|
|
12282
|
+
"In the collapsed rail the children of an open group show as icons (children without an icon get a dot)."
|
|
12267
12283
|
]
|
|
12268
12284
|
},
|
|
12269
12285
|
{
|
package/dist/style.css
CHANGED
|
@@ -248,7 +248,7 @@
|
|
|
248
248
|
.zg-call{display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:12px;align-items:center;padding:10px 12px;border-radius:18px;background:var(--zg-s2)}
|
|
249
249
|
@media(prefers-reduced-motion:reduce){.zg-root *{animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
|
250
250
|
|
|
251
|
-
.zg-topnav__items
|
|
251
|
+
.zg-topnav__items .zg-navitem{padding-inline:12px}
|
|
252
252
|
|
|
253
253
|
|
|
254
254
|
/* ./components2.css */
|
|
@@ -577,6 +577,17 @@
|
|
|
577
577
|
.zg-tip--left:hover::before,.zg-tip--right:hover::before{top:0;bottom:0;height:auto;width:10px}
|
|
578
578
|
.zg-tip--left:hover::before{left:auto;right:100%}.zg-tip--right:hover::before{right:auto;left:100%}
|
|
579
579
|
.zg-tip[data-tip-off]::after{opacity:0!important;pointer-events:none!important}.zg-tip[data-tip-off]::before{display:none}
|
|
580
|
+
/* TopNav: no edge fade; items that do not fit move into a "More" menu, sub-menus open under their item */
|
|
581
|
+
.zg-topnav__items{overflow:visible;flex-wrap:nowrap}.zg-topnav__items[data-overflow="none"]{overflow-x:auto}
|
|
582
|
+
.zg-topnav__dd{display:flex}.zg-topnav__dd>.zg-navitem{height:100%}.zg-topnav__dd .zg-menu{top:calc(100% + 10px);min-width:220px}
|
|
583
|
+
.zg-topnav__dd>.zg-navitem[aria-expanded="true"] .zg-icon:last-child:not(:first-child){transform:rotate(180deg)}
|
|
584
|
+
.zg-menu__i[aria-current="page"]{background:var(--zg-s2);font-weight:700}.zg-menu__i .zg-navitem__count{margin-inline-start:auto}
|
|
585
|
+
.zg-menu__h{padding:8px 12px 4px;font:600 12px var(--zg-font);letter-spacing:.06em;text-transform:uppercase;color:var(--zg-text-3)}
|
|
586
|
+
/* SideNav: expandable groups */
|
|
587
|
+
.zg-sidenav__sub{display:flex;flex-direction:column;gap:2px;flex-shrink:0}
|
|
588
|
+
.zg-sidenav__sub>.zg-navitem{position:relative}.zg-sidenav__chev{margin-inline-start:auto;display:inline-flex;transition:transform .2s var(--zg-ease)}.zg-sidenav__sub>.zg-navitem[aria-expanded="true"] .zg-sidenav__chev{transform:rotate(180deg)}
|
|
589
|
+
.zg-sidenav__kids{display:flex;flex-direction:column;gap:2px;padding-inline-start:16px}.zg-sidenav__kids .zg-navitem{height:40px}
|
|
590
|
+
.zg-sidenav--collapsed .zg-sidenav__kids{padding-inline-start:0}.zg-sidenav--collapsed .zg-sidenav__chev{display:none}
|
|
580
591
|
|
|
581
592
|
|
|
582
593
|
/* ./charts.css */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziyarago/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 102 free components and 6 page templates (more in @ziyarago/ui-pro).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui",
|
package/src/core/components.js
CHANGED
|
@@ -59,6 +59,33 @@ const fmt = {
|
|
|
59
59
|
sar: n => (n == null || Number.isNaN(n)) ? '—' : 'SAR\u00a0' + String(Math.round(n)).replace(/\B(?=(\d{3})+(?!\d))/g, '\u2009'),
|
|
60
60
|
dur: (s, u) => { if (s == null || Number.isNaN(+s)) return '—'; s = Math.max(0, Math.round(+s)); const m = Math.floor(s / 60), r = s % 60; return `${m} ${(u && u.m) || 'm'} ${String(r).padStart(2, '0')} ${(u && u.s) || 's'}`; },
|
|
61
61
|
};
|
|
62
|
+
// TopNav overflow: items that do not fit move into a trailing "More" menu. Measured in the browser after render (ResizeObserver on the header);
|
|
63
|
+
// item widths are cached from the render where every item is visible, so hidden items need no measuring. SSR renders every item.
|
|
64
|
+
const tn = new WeakMap();
|
|
65
|
+
const tnMeasure = (el, ctx) => {
|
|
66
|
+
if (!el || !ctx.collapse || typeof ResizeObserver === 'undefined') return;
|
|
67
|
+
let r = tn.get(el);
|
|
68
|
+
if (!r) { r = { w: {}, sig: '' }; r.ro = new ResizeObserver(() => r.run()); tn.set(el, r); if (el.parentElement) r.ro.observe(el.parentElement); }
|
|
69
|
+
r.ctx = ctx;
|
|
70
|
+
r.run = () => {
|
|
71
|
+
const { items, more, set, state } = r.ctx, kids = [...el.children], header = el.parentElement;
|
|
72
|
+
if (!header || !items.length) return;
|
|
73
|
+
const sig = items.map(i => i.value).join('|');
|
|
74
|
+
if (sig !== r.sig) { r.sig = sig; r.w = {}; }
|
|
75
|
+
const n = items.length, shownN = kids.length - (more ? 1 : 0);
|
|
76
|
+
for (let i = 0; i < shownN; i++) r.w[items[i].value] = kids[i].offsetWidth;
|
|
77
|
+
if (more) r.w.__more = kids[kids.length - 1].offsetWidth;
|
|
78
|
+
if (items.some(i => r.w[i.value] == null)) { if (state.fit != null) set({ fit: null }); return; }
|
|
79
|
+
const hs = getComputedStyle(header), es = getComputedStyle(el), bar = header.querySelector('.zg-topnav__brand'), act = header.querySelector('.zg-topnav__actions');
|
|
80
|
+
const gap = parseFloat(hs.columnGap) || 0, ig = parseFloat(es.columnGap) || 0;
|
|
81
|
+
const avail = header.clientWidth - parseFloat(hs.paddingLeft) - parseFloat(hs.paddingRight) - (bar ? bar.offsetWidth : 0) - (act ? act.offsetWidth : 0) - 2 * gap - parseFloat(es.paddingLeft) - parseFloat(es.paddingRight);
|
|
82
|
+
const total = items.reduce((a, i) => a + r.w[i.value], 0) + ig * (n - 1);
|
|
83
|
+
let want = n;
|
|
84
|
+
if (total > avail) { let acc = r.w.__more || 56, k = 0; for (const i of items) { const need = r.w[i.value] + ig; if (acc + need <= avail) { acc += need; k++; } else break; } want = k; }
|
|
85
|
+
if (want !== (state.fit == null ? n : state.fit)) set({ fit: want >= n ? null : want });
|
|
86
|
+
};
|
|
87
|
+
r.run();
|
|
88
|
+
};
|
|
62
89
|
const nav = (h, it, cur, onChange, collapsed) => h('button', { key: it.value, class: 'zg-navitem', 'aria-current': it.value === cur ? 'page' : undefined, title: collapsed ? it.label : undefined, onClick: () => onChange && onChange(it.value) },
|
|
63
90
|
it.icon ? icon(h, it.icon, 18) : null, h('span', null, it.label), it.count ? h('span', { class: 'zg-navitem__count' }, it.count) : null);
|
|
64
91
|
|
|
@@ -116,9 +143,42 @@ export const components = {
|
|
|
116
143
|
return h('div', { class: 'zg-table-wrap', tabIndex: 0 }, h('table', { class: 'zg-table' }, h('thead', null, h('tr', null, p.onSelect ? h('th', { style: { width: '44px' } }, h('button', { type: 'button', role: 'checkbox', class: 'zg-check', 'aria-checked': String(!!all), 'aria-label': (p.labels && p.labels.selectAll) || t('DataTable', 'selectAll'), onClick: () => p.onSelect(all ? [] : rows.map(r => r.id)) }, h('span', { class: 'zg-check__box' }, all ? icon(h, 'check', 14) : null))) : null, ...cols.map(th))),
|
|
117
144
|
h('tbody', null, ...(rows.length ? rows.map((r, ri) => h('tr', { key: r.id, 'aria-selected': sel.includes(r.id) ? 'true' : undefined, class: p.onRowClick ? 'zg-tr--click' : undefined, onClick: p.onRowClick ? () => p.onRowClick(r, ri) : undefined }, p.onSelect ? h('td', null, h('button', { type: 'button', role: 'checkbox', class: 'zg-check', 'aria-checked': String(sel.includes(r.id)), 'aria-label': (p.labels && p.labels.selectRow) || t('DataTable', 'selectRow'), onClick: () => p.onSelect(sel.includes(r.id) ? sel.filter(i => i !== r.id) : [...sel, r.id]) }, h('span', { class: 'zg-check__box' }, sel.includes(r.id) ? icon(h, 'check', 14) : null))) : null, ...cols.map(c => h('td', { key: c.key, class: c.num ? 'num' : undefined, style: cs(c) }, c.render ? c.render(r[c.key], r, h) : (r[c.key] ?? '—'))))) : [h('tr', { key: 'e' }, h('td', { colSpan: cols.length + 1 }, h('div', { class: 'zg-empty' }, slots.empty || p.empty || '—')))])))); } },
|
|
118
145
|
Timeline: { render: ({ h, props: p }) => h('div', { class: 'zg-timeline' }, ...(p.items || []).map((it, i, a) => h('div', { key: i, class: 'zg-tl' }, h('div', { class: 'zg-tl__rail' }, h('span', { class: 'zg-tl__dot' }), i < a.length - 1 ? h('span', { class: 'zg-tl__line' }) : null), h('div', { class: 'zg-tl__body' }, h('b', null, it.title), it.text ? h('span', null, it.text) : null, h('span', { class: 'zg-tl__time' }, it.time))))) },
|
|
119
|
-
TopNav: {
|
|
120
|
-
|
|
121
|
-
|
|
146
|
+
TopNav: { state: { open: null, fit: null }, render: ({ h, props: p, slots, state, set }) => {
|
|
147
|
+
const items = p.items || [], collapse = p.overflow !== 'none';
|
|
148
|
+
const fit = collapse && state.fit != null && state.fit < items.length ? state.fit : items.length;
|
|
149
|
+
const shown = items.slice(0, fit), rest = items.slice(fit);
|
|
150
|
+
const more = rest.length ? { value: '__more', label: p.moreLabel || t('TopNav', 'more'), icon: 'ellipsis', children: rest.flatMap(it => it.children && it.children.length ? [{ heading: it.label }, ...it.children] : [it]) } : null;
|
|
151
|
+
const close = () => set({ open: null });
|
|
152
|
+
const entry = it => {
|
|
153
|
+
const kids = it.children;
|
|
154
|
+
if (!kids || !kids.length) return nav(h, it, p.value, p.onChange);
|
|
155
|
+
const open = state.open === it.value, active = it.value !== '__more' ? kids.some(c => c.value === p.value) : rest.some(r => r.value === p.value || (r.children || []).some(c => c.value === p.value));
|
|
156
|
+
const flat = kids.map(c => ({ value: c.value, disabled: c.separator || c.heading || c.disabled }));
|
|
157
|
+
return h('div', { key: it.value, class: 'zg-dd zg-topnav__dd' },
|
|
158
|
+
h('button', { type: 'button', class: 'zg-navitem', 'aria-haspopup': 'menu', 'aria-expanded': String(open), 'aria-current': active ? 'page' : undefined, onClick: () => set({ open: open ? null : it.value }), onKeydown: openKeys(open, () => set({ open: it.value })) },
|
|
159
|
+
it.icon ? icon(h, it.icon, 18) : null, it.value === '__more' ? h('span', { class: 'zg-sr' }, it.label) : h('span', null, it.label), it.count ? h('span', { class: 'zg-navitem__count' }, it.count) : null, it.value === '__more' ? null : icon(h, 'chevron-down', 14)),
|
|
160
|
+
open ? h('div', { class: 'zg-menu', role: 'menu', 'data-zg-dd': '', ref: ddRef(close, { focus: true }), onKeydown: listKeys('[role=menuitem]', { wrap: true, onTab: e => { const tr = trigger(e.currentTarget); tr && tr.focus(); close(); } }) },
|
|
161
|
+
...kids.map((c, i) => c.separator ? h('div', { key: 's' + i, class: 'zg-menu__sep', role: 'separator' }) : c.heading ? h('div', { key: 'h' + i, class: 'zg-menu__h', role: 'presentation' }, c.heading)
|
|
162
|
+
: h('button', { key: c.value, type: 'button', role: 'menuitem', tabIndex: tabIdx(flat, x => x.value === p.value)(i), disabled: c.disabled, 'aria-disabled': c.disabled ? 'true' : undefined, 'aria-current': c.value === p.value ? 'page' : undefined, class: 'zg-menu__i', onClick: e => { toTrigger(e); close(); p.onChange && p.onChange(c.value); } },
|
|
163
|
+
c.icon ? icon(h, c.icon, 16) : null, h('span', null, c.label), c.count ? h('span', { class: 'zg-navitem__count' }, c.count) : null))) : null);
|
|
164
|
+
};
|
|
165
|
+
const measure = el => tnMeasure(el, { items, more, set, state, collapse });
|
|
166
|
+
return h('header', { class: 'zg-topnav' }, h('div', { class: 'zg-topnav__brand' }, p.brand),
|
|
167
|
+
h('nav', { class: 'zg-topnav__items', 'data-overflow': collapse ? 'menu' : 'none', 'aria-label': t('TopNav', 'label'), ref: measure }, ...shown.map(entry), more ? entry(more) : null),
|
|
168
|
+
h('div', { class: 'zg-topnav__actions' }, slots.actions || p.actions || null)); } },
|
|
169
|
+
SideNav: { state: { open: {} }, render: ({ h, props: p, slots, state, set }) => {
|
|
170
|
+
const entry = it => {
|
|
171
|
+
if (it.group) return h('div', { key: it.group, class: 'zg-sidenav__group', style: p.collapsed ? { display: 'none' } : undefined }, it.group);
|
|
172
|
+
const kids = it.children;
|
|
173
|
+
if (!kids || !kids.length) return nav(h, it, p.value, p.onChange, p.collapsed);
|
|
174
|
+
const active = kids.some(c => c.value === p.value), open = state.open[it.value] ?? active;
|
|
175
|
+
return h('div', { key: it.value, class: 'zg-sidenav__sub' },
|
|
176
|
+
h('button', { type: 'button', class: 'zg-navitem', 'aria-expanded': String(open), 'aria-current': active && !open ? 'page' : undefined, title: p.collapsed ? it.label : undefined, onClick: () => set({ open: { ...state.open, [it.value]: !open } }) },
|
|
177
|
+
it.icon ? icon(h, it.icon, 18) : null, h('span', null, it.label), it.count ? h('span', { class: 'zg-navitem__count' }, it.count) : null, h('span', { class: 'zg-sidenav__chev' }, icon(h, 'chevron-down', 14))),
|
|
178
|
+
open ? h('div', { class: 'zg-sidenav__kids', role: 'group', 'aria-label': it.label }, ...kids.map((c, i) => c.separator ? h('div', { key: 's' + i, class: 'zg-menu__sep', role: 'separator' }) : nav(h, p.collapsed && !c.icon ? { ...c, icon: 'dot' } : c, p.value, p.onChange, p.collapsed))) : null);
|
|
179
|
+
};
|
|
180
|
+
return h('aside', { class: cx('zg-sidenav', p.collapsed && 'zg-sidenav--collapsed') }, h('div', { class: 'zg-sidenav__brand' }, p.brand), ...(p.items || []).map(entry), h('div', { class: 'zg-sidenav__sp' }), slots.footer || p.footer || null,
|
|
181
|
+
(p.onToggle || p.collapsible) ? h('button', { type: 'button', class: 'zg-navitem', onClick: p.onToggle, 'aria-label': t('SideNav', 'toggle') }, icon(h, p.collapsed ? 'panel-left-open' : 'panel-left-close', 18), h('span', null, p.collapseLabel || t('SideNav', 'collapse'))) : null); } },
|
|
122
182
|
AppShell: { state: { collapsed: false }, render: ({ C, h, props: p, children, slots, state, set }) => {
|
|
123
183
|
const brand = p.brand, top = (p.nav || 'top') === 'top', col = p.collapsed ?? state.collapsed, toggle = () => p.onCollapse ? p.onCollapse(!col) : set({ collapsed: !state.collapsed });
|
|
124
184
|
return h('div', { class: cx('zg-root', 'zg-shell', top && 'zg-shell--top', p.frame && 'zg-shell--frame'), style: { background: 'var(--zg-bg)' } },
|
package/src/icons/builtin.js
CHANGED
|
@@ -27,7 +27,10 @@ export default {
|
|
|
27
27
|
"component": "<svg class=\"lucide lucide-component\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z\" /><path d=\"M2.297 11.293a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0z\" /><path d=\"M8.916 17.912a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0z\" /><path d=\"M8.916 4.674a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z\" /></svg>",
|
|
28
28
|
"contact": "<svg class=\"lucide lucide-contact\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M16 2v2\" /><path d=\"M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2\" /><path d=\"M8 2v2\" /><circle cx=\"12\" cy=\"11\" r=\"3\" /><rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" /></svg>",
|
|
29
29
|
"copy": "<svg class=\"lucide lucide-copy\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" /></svg>",
|
|
30
|
+
"currency": "<svg class=\"lucide lucide-currency\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"12\" cy=\"12\" r=\"8\" /><line x1=\"3\" x2=\"6\" y1=\"3\" y2=\"6\" /><line x1=\"21\" x2=\"18\" y1=\"3\" y2=\"6\" /><line x1=\"3\" x2=\"6\" y1=\"21\" y2=\"18\" /><line x1=\"21\" x2=\"18\" y1=\"21\" y2=\"18\" /></svg>",
|
|
31
|
+
"donut": "<svg class=\"lucide lucide-donut\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M20.5 10a2.5 2.5 0 0 1-2.4-3H18a2.95 2.95 0 0 1-2.6-4.4 10 10 0 1 0 6.3 7.1c-.3.2-.8.3-1.2.3\" /><circle cx=\"12\" cy=\"12\" r=\"3\" /></svg>",
|
|
30
32
|
"dot": "<svg class=\"lucide lucide-dot\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"12.1\" cy=\"12.1\" r=\"1\" /></svg>",
|
|
33
|
+
"ellipsis": "<svg class=\"lucide lucide-ellipsis\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"12\" cy=\"12\" r=\"1\" /><circle cx=\"19\" cy=\"12\" r=\"1\" /><circle cx=\"5\" cy=\"12\" r=\"1\" /></svg>",
|
|
31
34
|
"ellipsis-vertical": "<svg class=\"lucide lucide-ellipsis-vertical\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"12\" cy=\"12\" r=\"1\" /><circle cx=\"12\" cy=\"5\" r=\"1\" /><circle cx=\"12\" cy=\"19\" r=\"1\" /></svg>",
|
|
32
35
|
"expand": "<svg class=\"lucide lucide-expand\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"m21 21-6-6m6 6v-4.8m0 4.8h-4.8\" /><path d=\"M3 16.2V21m0 0h4.8M3 21l6-6\" /><path d=\"M21 7.8V3m0 0h-4.8M21 3l-6 6\" /><path d=\"M3 7.8V3m0 0h4.8M3 3l6 6\" /></svg>",
|
|
33
36
|
"external-link": "<svg class=\"lucide lucide-external-link\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M15 3h6v6\" /><path d=\"M10 14 21 3\" /><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" /></svg>",
|
|
@@ -37,6 +40,7 @@ export default {
|
|
|
37
40
|
"file-check-2": "<svg class=\"lucide lucide-file-check-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\" /><path d=\"M14 2v4a2 2 0 0 0 2 2h4\" /><path d=\"m3 15 2 2 4-4\" /></svg>",
|
|
38
41
|
"file-code-2": "<svg class=\"lucide lucide-file-code-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\" /><path d=\"M14 2v4a2 2 0 0 0 2 2h4\" /><path d=\"m5 12-3 3 3 3\" /><path d=\"m9 18 3-3-3-3\" /></svg>",
|
|
39
42
|
"filter": "<svg class=\"lucide lucide-filter\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><polygon points=\"22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3\" /></svg>",
|
|
43
|
+
"focus": "<svg class=\"lucide lucide-focus\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"12\" cy=\"12\" r=\"3\" /><path d=\"M3 7V5a2 2 0 0 1 2-2h2\" /><path d=\"M17 3h2a2 2 0 0 1 2 2v2\" /><path d=\"M21 17v2a2 2 0 0 1-2 2h-2\" /><path d=\"M7 21H5a2 2 0 0 1-2-2v-2\" /></svg>",
|
|
40
44
|
"frame": "<svg class=\"lucide lucide-frame\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><line x1=\"22\" x2=\"2\" y1=\"6\" y2=\"6\" /><line x1=\"22\" x2=\"2\" y1=\"18\" y2=\"18\" /><line x1=\"6\" x2=\"6\" y1=\"2\" y2=\"22\" /><line x1=\"18\" x2=\"18\" y1=\"2\" y2=\"22\" /></svg>",
|
|
41
45
|
"ghost": "<svg class=\"lucide lucide-ghost\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M9 10h.01\" /><path d=\"M15 10h.01\" /><path d=\"M12 2a8 8 0 0 0-8 8v12l3-3 2.5 2.5L12 19l2.5 2.5L17 19l3 3V10a8 8 0 0 0-8-8z\" /></svg>",
|
|
42
46
|
"grip-vertical": "<svg class=\"lucide lucide-grip-vertical\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><circle cx=\"9\" cy=\"12\" r=\"1\" /><circle cx=\"9\" cy=\"5\" r=\"1\" /><circle cx=\"9\" cy=\"19\" r=\"1\" /><circle cx=\"15\" cy=\"12\" r=\"1\" /><circle cx=\"15\" cy=\"5\" r=\"1\" /><circle cx=\"15\" cy=\"19\" r=\"1\" /></svg>",
|
|
@@ -62,12 +66,14 @@ export default {
|
|
|
62
66
|
"panel-left-close": "<svg class=\"lucide lucide-panel-left-close\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" /><path d=\"M9 3v18\" /><path d=\"m16 15-3-3 3-3\" /></svg>",
|
|
63
67
|
"panel-left-open": "<svg class=\"lucide lucide-panel-left-open\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" /><path d=\"M9 3v18\" /><path d=\"m14 9 3 3-3 3\" /></svg>",
|
|
64
68
|
"pencil": "<svg class=\"lucide lucide-pencil\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\" /><path d=\"m15 5 4 4\" /></svg>",
|
|
69
|
+
"percent": "<svg class=\"lucide lucide-percent\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><line x1=\"19\" x2=\"5\" y1=\"5\" y2=\"19\" /><circle cx=\"6.5\" cy=\"6.5\" r=\"2.5\" /><circle cx=\"17.5\" cy=\"17.5\" r=\"2.5\" /></svg>",
|
|
65
70
|
"phone": "<svg class=\"lucide lucide-phone\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" /></svg>",
|
|
66
71
|
"phone-off": "<svg class=\"lucide lucide-phone-off\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-3.33-2.67m-2.67-3.34a19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91\" /><line x1=\"22\" x2=\"2\" y1=\"2\" y2=\"22\" /></svg>",
|
|
67
72
|
"pill": "<svg class=\"lucide lucide-pill\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"m10.5 20.5 10-10a4.95 4.95 0 1 0-7-7l-10 10a4.95 4.95 0 1 0 7 7Z\" /><path d=\"m8.5 8.5 7 7\" /></svg>",
|
|
68
73
|
"play": "<svg class=\"lucide lucide-play\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><polygon points=\"6 3 20 12 6 21 6 3\" /></svg>",
|
|
69
74
|
"plus": "<svg class=\"lucide lucide-plus\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M5 12h14\" /><path d=\"M12 5v14\" /></svg>",
|
|
70
75
|
"pointer": "<svg class=\"lucide lucide-pointer\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M22 14a8 8 0 0 1-8 8\" /><path d=\"M18 11v-1a2 2 0 0 0-2-2a2 2 0 0 0-2 2\" /><path d=\"M14 10V9a2 2 0 0 0-2-2a2 2 0 0 0-2 2v1\" /><path d=\"M10 9.5V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v10\" /><path d=\"M18 11a2 2 0 1 1 4 0v3a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15\" /></svg>",
|
|
76
|
+
"presentation": "<svg class=\"lucide lucide-presentation\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M2 3h20\" /><path d=\"M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3\" /><path d=\"m7 21 5-5 5 5\" /></svg>",
|
|
71
77
|
"quote": "<svg class=\"lucide lucide-quote\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" /><path d=\"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" /></svg>",
|
|
72
78
|
"radio": "<svg class=\"lucide lucide-radio\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M4.9 19.1C1 15.2 1 8.8 4.9 4.9\" /><path d=\"M7.8 16.2c-2.3-2.3-2.3-6.1 0-8.5\" /><circle cx=\"12\" cy=\"12\" r=\"2\" /><path d=\"M16.2 7.8c2.3 2.3 2.3 6.1 0 8.5\" /><path d=\"M19.1 4.9C23 8.8 23 15.1 19.1 19\" /></svg>",
|
|
73
79
|
"refresh-cw": "<svg class=\"lucide lucide-refresh-cw\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" ><path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" /><path d=\"M21 3v5h-5\" /><path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" /><path d=\"M8 16H3v5\" /></svg>",
|
package/src/meta/navigation.js
CHANGED
|
@@ -9,20 +9,22 @@ export default {
|
|
|
9
9
|
description: 'Horizontal app header with a brand area, navigation items and an actions area.',
|
|
10
10
|
props: {
|
|
11
11
|
brand: { type: 'string | VNode', description: 'Logo or product name on the left.' },
|
|
12
|
-
items: { type: '{ value: string; label: string; icon?: string; count?: string | number }[]', default: '[]', description: 'Navigation entries. count renders a small counter after the label.' },
|
|
12
|
+
items: { type: '{ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number; disabled?: boolean } | { heading: string } | { separator: true })[] }[]', default: '[]', description: 'Navigation entries. count renders a small counter after the label. An entry with children becomes a drop-down: click or ArrowDown opens a menu of its children (each with an optional icon and count, headings and separators allowed); selecting one calls change with the child value. The entry is marked current when one of its children is.' },
|
|
13
13
|
value: current,
|
|
14
|
+
overflow: { type: "'menu' | 'none'", values: ['menu', 'none'], default: 'menu', description: "'menu': entries that do not fit move into a trailing \"More\" drop-down (measured after render and on resize; server rendering shows all entries). 'none': no collapsing, the row scrolls sideways and sub-menus are clipped, so avoid children with it." },
|
|
15
|
+
moreLabel: { type: 'string', default: 'More', description: 'Accessible name of the overflow drop-down button.' },
|
|
14
16
|
size: size('header padding, item height and text'),
|
|
15
17
|
},
|
|
16
18
|
slots: { actions: 'Right side of the header (buttons, avatar). React also accepts an actions prop.' },
|
|
17
|
-
events: { change: 'Called with the value of the clicked item.' },
|
|
18
|
-
notes: ['Controlled: update value yourself in the change handler.', 'Items use count; SubNav uses badge for the same purpose.'],
|
|
19
|
+
events: { change: 'Called with the value of the clicked item or sub-menu item.' },
|
|
20
|
+
notes: ['Controlled: update value yourself in the change handler.', 'Items use count; SubNav uses badge for the same purpose.', 'Entries with children and the More menu share the Dropdown keyboard behaviour: ArrowDown opens, arrows and Home/End move, Escape closes and returns focus to the button.'],
|
|
19
21
|
},
|
|
20
22
|
|
|
21
23
|
SideNav: {
|
|
22
24
|
description: 'Vertical sidebar with a brand, grouped navigation items, a footer and an optional collapse toggle.',
|
|
23
25
|
props: {
|
|
24
26
|
brand: { type: 'string | VNode', description: 'Logo or product name at the top.' },
|
|
25
|
-
items: { type: '({ value: string; label: string; icon?: string; count?: string | number } | { group: string })[]', default: '[]', description: 'Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count.' },
|
|
27
|
+
items: { type: '({ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number } | { separator: true })[] } | { group: string })[]', default: '[]', description: 'Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count. An entry with children is an expandable group: its button toggles the list of children (open by default while one of them is current); selecting a child calls change with the child value.' },
|
|
26
28
|
value: current,
|
|
27
29
|
collapsed: { type: 'boolean', default: false, description: 'Icon-only mode; labels move to the title tooltip.' },
|
|
28
30
|
collapsible: { type: 'boolean', default: false, description: 'Always draw the collapse button, even without a toggle handler (the button is also drawn when a toggle handler is set).' },
|
|
@@ -31,7 +33,7 @@ export default {
|
|
|
31
33
|
},
|
|
32
34
|
slots: { footer: 'Bottom area above the collapse button, e.g. user card. React also accepts a footer prop.' },
|
|
33
35
|
events: { change: 'Called with the value of the clicked item.', toggle: 'Called when the collapse button is clicked. The button is drawn when this handler is set (Vue: @toggle) or when collapsible is true.' },
|
|
34
|
-
notes: ['Collapsing is controlled: flip collapsed in the toggle handler.', 'Group entries are keyed by their title, so keep group names unique.'],
|
|
36
|
+
notes: ['Collapsing is controlled: flip collapsed in the toggle handler.', 'Group entries are keyed by their title, so keep group names unique.', 'In the collapsed rail the children of an open group show as icons (children without an icon get a dot).'],
|
|
35
37
|
},
|
|
36
38
|
|
|
37
39
|
SubNav: {
|
|
@@ -166,4 +166,4 @@
|
|
|
166
166
|
.zg-call{display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:12px;align-items:center;padding:10px 12px;border-radius:18px;background:var(--zg-s2)}
|
|
167
167
|
@media(prefers-reduced-motion:reduce){.zg-root *{animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
|
168
168
|
|
|
169
|
-
.zg-topnav__items
|
|
169
|
+
.zg-topnav__items .zg-navitem{padding-inline:12px}
|
|
@@ -120,3 +120,14 @@
|
|
|
120
120
|
.zg-tip--left:hover::before,.zg-tip--right:hover::before{top:0;bottom:0;height:auto;width:10px}
|
|
121
121
|
.zg-tip--left:hover::before{left:auto;right:100%}.zg-tip--right:hover::before{right:auto;left:100%}
|
|
122
122
|
.zg-tip[data-tip-off]::after{opacity:0!important;pointer-events:none!important}.zg-tip[data-tip-off]::before{display:none}
|
|
123
|
+
/* TopNav: no edge fade; items that do not fit move into a "More" menu, sub-menus open under their item */
|
|
124
|
+
.zg-topnav__items{overflow:visible;flex-wrap:nowrap}.zg-topnav__items[data-overflow="none"]{overflow-x:auto}
|
|
125
|
+
.zg-topnav__dd{display:flex}.zg-topnav__dd>.zg-navitem{height:100%}.zg-topnav__dd .zg-menu{top:calc(100% + 10px);min-width:220px}
|
|
126
|
+
.zg-topnav__dd>.zg-navitem[aria-expanded="true"] .zg-icon:last-child:not(:first-child){transform:rotate(180deg)}
|
|
127
|
+
.zg-menu__i[aria-current="page"]{background:var(--zg-s2);font-weight:700}.zg-menu__i .zg-navitem__count{margin-inline-start:auto}
|
|
128
|
+
.zg-menu__h{padding:8px 12px 4px;font:600 12px var(--zg-font);letter-spacing:.06em;text-transform:uppercase;color:var(--zg-text-3)}
|
|
129
|
+
/* SideNav: expandable groups */
|
|
130
|
+
.zg-sidenav__sub{display:flex;flex-direction:column;gap:2px;flex-shrink:0}
|
|
131
|
+
.zg-sidenav__sub>.zg-navitem{position:relative}.zg-sidenav__chev{margin-inline-start:auto;display:inline-flex;transition:transform .2s var(--zg-ease)}.zg-sidenav__sub>.zg-navitem[aria-expanded="true"] .zg-sidenav__chev{transform:rotate(180deg)}
|
|
132
|
+
.zg-sidenav__kids{display:flex;flex-direction:column;gap:2px;padding-inline-start:16px}.zg-sidenav__kids .zg-navitem{height:40px}
|
|
133
|
+
.zg-sidenav--collapsed .zg-sidenav__kids{padding-inline-start:0}.zg-sidenav--collapsed .zg-sidenav__chev{display:none}
|
package/types/react.d.ts
CHANGED
|
@@ -2814,15 +2814,16 @@ export const UiSettingsSection: ComponentType<UiSettingsSectionProps>;
|
|
|
2814
2814
|
* Vertical sidebar with a brand, grouped navigation items, a footer and an optional collapse toggle.
|
|
2815
2815
|
* Note: Collapsing is controlled: flip collapsed in the toggle handler.
|
|
2816
2816
|
* Note: Group entries are keyed by their title, so keep group names unique.
|
|
2817
|
+
* Note: In the collapsed rail the children of an open group show as icons (children without an icon get a dot).
|
|
2817
2818
|
*/
|
|
2818
2819
|
export interface UiSideNavProps {
|
|
2819
2820
|
/** Logo or product name at the top. */
|
|
2820
2821
|
brand?: string | ReactNode;
|
|
2821
2822
|
/**
|
|
2822
|
-
* Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count.
|
|
2823
|
+
* Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count. An entry with children is an expandable group: its button toggles the list of children (open by default while one of them is current); selecting a child calls change with the child value.
|
|
2823
2824
|
* @default []
|
|
2824
2825
|
*/
|
|
2825
|
-
items?: ({ value: string; label: string; icon?: string; count?: string | number } | { group: string })[];
|
|
2826
|
+
items?: ({ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number } | { separator: true })[] } | { group: string })[];
|
|
2826
2827
|
/** Value of the active item (aria-current="page"). */
|
|
2827
2828
|
value?: string;
|
|
2828
2829
|
/**
|
|
@@ -3695,24 +3696,35 @@ export const UiTooltip: ComponentType<UiTooltipProps>;
|
|
|
3695
3696
|
* Horizontal app header with a brand area, navigation items and an actions area.
|
|
3696
3697
|
* Note: Controlled: update value yourself in the change handler.
|
|
3697
3698
|
* Note: Items use count; SubNav uses badge for the same purpose.
|
|
3699
|
+
* Note: Entries with children and the More menu share the Dropdown keyboard behaviour: ArrowDown opens, arrows and Home/End move, Escape closes and returns focus to the button.
|
|
3698
3700
|
*/
|
|
3699
3701
|
export interface UiTopNavProps {
|
|
3700
3702
|
/** Logo or product name on the left. */
|
|
3701
3703
|
brand?: string | ReactNode;
|
|
3702
3704
|
/**
|
|
3703
|
-
* Navigation entries. count renders a small counter after the label.
|
|
3705
|
+
* Navigation entries. count renders a small counter after the label. An entry with children becomes a drop-down: click or ArrowDown opens a menu of its children (each with an optional icon and count, headings and separators allowed); selecting one calls change with the child value. The entry is marked current when one of its children is.
|
|
3704
3706
|
* @default []
|
|
3705
3707
|
*/
|
|
3706
|
-
items?: { value: string; label: string; icon?: string; count?: string | number }[];
|
|
3708
|
+
items?: { value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number; disabled?: boolean } | { heading: string } | { separator: true })[] }[];
|
|
3707
3709
|
/** Value of the active item (aria-current="page"). */
|
|
3708
3710
|
value?: string;
|
|
3711
|
+
/**
|
|
3712
|
+
* 'menu': entries that do not fit move into a trailing "More" drop-down (measured after render and on resize; server rendering shows all entries). 'none': no collapsing, the row scrolls sideways and sub-menus are clipped, so avoid children with it.
|
|
3713
|
+
* @default 'menu'
|
|
3714
|
+
*/
|
|
3715
|
+
overflow?: 'menu' | 'none';
|
|
3716
|
+
/**
|
|
3717
|
+
* Accessible name of the overflow drop-down button.
|
|
3718
|
+
* @default 'More'
|
|
3719
|
+
*/
|
|
3720
|
+
moreLabel?: string;
|
|
3709
3721
|
/**
|
|
3710
3722
|
* Scale of header padding, item height and text.
|
|
3711
3723
|
* @default 'md'
|
|
3712
3724
|
*/
|
|
3713
3725
|
size?: Size;
|
|
3714
3726
|
/**
|
|
3715
|
-
* Called with the value of the clicked item.
|
|
3727
|
+
* Called with the value of the clicked item or sub-menu item.
|
|
3716
3728
|
* @event change
|
|
3717
3729
|
*/
|
|
3718
3730
|
onChange?: (value: string) => void;
|
package/types/vue.d.ts
CHANGED
|
@@ -2821,15 +2821,16 @@ export const UiSettingsSection: UiVueComponent<UiSettingsSectionProps, UiSetting
|
|
|
2821
2821
|
* Vertical sidebar with a brand, grouped navigation items, a footer and an optional collapse toggle.
|
|
2822
2822
|
* Note: Collapsing is controlled: flip collapsed in the toggle handler.
|
|
2823
2823
|
* Note: Group entries are keyed by their title, so keep group names unique.
|
|
2824
|
+
* Note: In the collapsed rail the children of an open group show as icons (children without an icon get a dot).
|
|
2824
2825
|
*/
|
|
2825
2826
|
export interface UiSideNavProps {
|
|
2826
2827
|
/** Logo or product name at the top. */
|
|
2827
2828
|
brand?: string | VNode;
|
|
2828
2829
|
/**
|
|
2829
|
-
* Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count.
|
|
2830
|
+
* Entries. An object with group renders a section heading (hidden when collapsed); others are links with an optional icon and count. An entry with children is an expandable group: its button toggles the list of children (open by default while one of them is current); selecting a child calls change with the child value.
|
|
2830
2831
|
* @default []
|
|
2831
2832
|
*/
|
|
2832
|
-
items?: ({ value: string; label: string; icon?: string; count?: string | number } | { group: string })[];
|
|
2833
|
+
items?: ({ value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number } | { separator: true })[] } | { group: string })[];
|
|
2833
2834
|
/** Value of the active item (aria-current="page"). */
|
|
2834
2835
|
value?: string;
|
|
2835
2836
|
/**
|
|
@@ -3727,24 +3728,35 @@ export const UiTooltip: UiVueComponent<UiTooltipProps, UiTooltipSlots>;
|
|
|
3727
3728
|
* Horizontal app header with a brand area, navigation items and an actions area.
|
|
3728
3729
|
* Note: Controlled: update value yourself in the change handler.
|
|
3729
3730
|
* Note: Items use count; SubNav uses badge for the same purpose.
|
|
3731
|
+
* Note: Entries with children and the More menu share the Dropdown keyboard behaviour: ArrowDown opens, arrows and Home/End move, Escape closes and returns focus to the button.
|
|
3730
3732
|
*/
|
|
3731
3733
|
export interface UiTopNavProps {
|
|
3732
3734
|
/** Logo or product name on the left. */
|
|
3733
3735
|
brand?: string | VNode;
|
|
3734
3736
|
/**
|
|
3735
|
-
* Navigation entries. count renders a small counter after the label.
|
|
3737
|
+
* Navigation entries. count renders a small counter after the label. An entry with children becomes a drop-down: click or ArrowDown opens a menu of its children (each with an optional icon and count, headings and separators allowed); selecting one calls change with the child value. The entry is marked current when one of its children is.
|
|
3736
3738
|
* @default []
|
|
3737
3739
|
*/
|
|
3738
|
-
items?: { value: string; label: string; icon?: string; count?: string | number }[];
|
|
3740
|
+
items?: { value: string; label: string; icon?: string; count?: string | number; children?: ({ value: string; label: string; icon?: string; count?: string | number; disabled?: boolean } | { heading: string } | { separator: true })[] }[];
|
|
3739
3741
|
/** Value of the active item (aria-current="page"). */
|
|
3740
3742
|
value?: string;
|
|
3743
|
+
/**
|
|
3744
|
+
* 'menu': entries that do not fit move into a trailing "More" drop-down (measured after render and on resize; server rendering shows all entries). 'none': no collapsing, the row scrolls sideways and sub-menus are clipped, so avoid children with it.
|
|
3745
|
+
* @default 'menu'
|
|
3746
|
+
*/
|
|
3747
|
+
overflow?: 'menu' | 'none';
|
|
3748
|
+
/**
|
|
3749
|
+
* Accessible name of the overflow drop-down button.
|
|
3750
|
+
* @default 'More'
|
|
3751
|
+
*/
|
|
3752
|
+
moreLabel?: string;
|
|
3741
3753
|
/**
|
|
3742
3754
|
* Scale of header padding, item height and text.
|
|
3743
3755
|
* @default 'md'
|
|
3744
3756
|
*/
|
|
3745
3757
|
size?: Size;
|
|
3746
3758
|
/**
|
|
3747
|
-
* Called with the value of the clicked item.
|
|
3759
|
+
* Called with the value of the clicked item or sub-menu item.
|
|
3748
3760
|
* @event change
|
|
3749
3761
|
*/
|
|
3750
3762
|
onChange?: (value: string) => void;
|