@ziyarago/ui 0.14.0 → 0.15.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +5 -5
  3. package/dist/llms-full.txt +8 -4
  4. package/dist/llms.txt +2 -2
  5. package/dist/manifest.json +343 -4
  6. package/dist/style.css +13 -13
  7. package/docs/INTEGRATION.md +12 -0
  8. package/package.json +12 -25
  9. package/src/core/components.js +11 -15
  10. package/src/core/components2.js +2 -72
  11. package/src/core/components3.js +2 -44
  12. package/src/core/components4.js +0 -38
  13. package/src/core/components6.js +0 -50
  14. package/src/core/components7.js +0 -34
  15. package/src/core/index.js +2 -2
  16. package/src/core/pages.js +2 -36
  17. package/src/i18n/components/index.js +0 -72
  18. package/src/icons/builtin.js +99 -0
  19. package/src/internal.js +10 -0
  20. package/src/meta/forms.js +5 -1
  21. package/src/meta/index.js +2 -0
  22. package/src/meta/pages.js +1 -1
  23. package/src/react/index.js +1 -107
  24. package/src/styles/components.css +8 -8
  25. package/src/styles/components2.css +2 -2
  26. package/src/styles/components7.css +1 -1
  27. package/src/styles/components8.css +1 -1
  28. package/src/styles/extras.css +1 -1
  29. package/src/vue/index.js +2 -2
  30. package/types/core.d.ts +1 -1
  31. package/types/internal.d.ts +30 -0
  32. package/types/meta.d.ts +5 -0
  33. package/types/react.d.ts +154 -4141
  34. package/types/shared.d.ts +2 -0
  35. package/types/vue-global.d.ts +0 -106
  36. package/types/vue.d.ts +168 -3601
  37. package/docs/MIGRATION.md +0 -455
  38. package/src/compat/index.js +0 -469
  39. package/src/compat/map.js +0 -282
  40. package/src/compat/resolver.js +0 -22
  41. package/src/compat/vite.js +0 -29
  42. package/src/i18n/components/ActionCard.js +0 -5
  43. package/src/i18n/components/Actionsheet.js +0 -5
  44. package/src/i18n/components/CallCard.js +0 -5
  45. package/src/i18n/components/CallRow.js +0 -5
  46. package/src/i18n/components/Carousel.js +0 -5
  47. package/src/i18n/components/ChartCard.js +0 -5
  48. package/src/i18n/components/ChatAi.js +0 -5
  49. package/src/i18n/components/ChipInput.js +0 -5
  50. package/src/i18n/components/ContactPanel.js +0 -5
  51. package/src/i18n/components/DataGroup.js +0 -5
  52. package/src/i18n/components/DealCard.js +0 -5
  53. package/src/i18n/components/FullscreenDialog.js +0 -5
  54. package/src/i18n/components/Gallery.js +0 -5
  55. package/src/i18n/components/GuestCard.js +0 -5
  56. package/src/i18n/components/ImageUpload.js +0 -5
  57. package/src/i18n/components/ImageViewer.js +0 -5
  58. package/src/i18n/components/IncomingCall.js +0 -5
  59. package/src/i18n/components/InlineEdit.js +0 -5
  60. package/src/i18n/components/IntegrationCard.js +0 -5
  61. package/src/i18n/components/Map.js +0 -5
  62. package/src/i18n/components/NotificationBell.js +0 -5
  63. package/src/i18n/components/PricingCard.js +0 -5
  64. package/src/i18n/components/QiblaCompass.js +0 -5
  65. package/src/i18n/components/RamadanTracker.js +0 -5
  66. package/src/i18n/components/RangeCalendar.js +0 -5
  67. package/src/i18n/components/RangeSlider.js +0 -5
  68. package/src/i18n/components/RichEditor.js +0 -5
  69. package/src/i18n/components/Screensaver.js +0 -5
  70. package/src/i18n/components/Sortable.js +0 -5
  71. package/src/i18n/components/StepDialog.js +0 -5
  72. package/src/i18n/components/StepForm.js +0 -5
  73. package/src/i18n/components/TabTiles.js +0 -5
  74. package/src/i18n/components/Tour.js +0 -5
  75. package/src/i18n/components/TourCard.js +0 -5
  76. package/src/i18n/components/TourPopover.js +0 -5
  77. package/src/i18n/components/TreeSelect.js +0 -5
  78. package/types/compat-resolver.d.ts +0 -12
  79. package/types/compat-vite.d.ts +0 -11
  80. package/types/compat.d.ts +0 -176
@@ -1,36 +1,15 @@
1
1
  // @ziyarago/ui · components, part 3 — card patterns, tonal variants, shells for auth/profile/status pages.
2
- import { icon, cx, fmt, ddRef } from './components.js';
2
+ import { icon, cx } from './components.js';
3
3
  import { t } from '../i18n/index.js';
4
- import { rove, tabIdx, listKeys, openKeys, toTrigger, trigger } from './keys.js';
4
+ import { rove, tabIdx } from './keys.js';
5
5
  const TONES = ['brand', 'sky', 'success', 'warning', 'danger', 'neutral'];
6
6
  const tc = t => 'zg-t-' + (TONES.includes(t) ? t : 'brand');
7
- const delta = (h, d) => d ? h('span', { class: cx('zg-delta', String(d).trim().startsWith('-') ? 'zg-delta--down' : 'zg-delta--up') }, (String(d).trim().startsWith('-') ? '▼ ' : '▲ ') + String(d).replace(/^[+-]/, '')) : null;
8
-
9
7
  export const more3 = {
10
8
  Chip: { render: ({ h, props: p, children }) => h('span', { class: cx('zg-chip2', tc(p.tone), 'zg-chip2--' + (p.variant || 'tonal'), p.size && 'zg-chip2--' + p.size, p.pill && 'zg-chip2--pill') }, p.icon ? icon(h, p.icon, 14) : null, ...children, (p.onClose || p.onRemove) ? h('button', { type: 'button', 'aria-label': t('Chip', 'remove'), onClick: p.onClose || p.onRemove }, icon(h, 'x', 12)) : null) },
11
9
  IconTile: { render: ({ h, props: p }) => h('span', { class: cx('zg-tile', tc(p.tone), p.shape === 'circle' && 'zg-tile--circle'), style: { '--s': ({ xs: 28, sm: 32, md: 40, lg: 48, xl: 56 }[p.size] || p.size || 40) + 'px' } }, icon(h, p.icon || 'circle', Math.round(({ xs: 28, sm: 32, md: 40, lg: 48, xl: 56 }[p.size] || p.size || 40) * .5))) },
12
10
  StatusIcon: { render: ({ h, props: p }) => h('span', { class: cx('zg-tile zg-tile--circle zg-tip', tc(p.tone)), 'data-tip': p.tip, tabIndex: 0, style: { '--s': ({ xs: 24, sm: 30, md: 36, lg: 44, xl: 52 }[p.size] || p.size || 36) + 'px' } }, icon(h, p.icon || 'circle', Math.round(({ xs: 24, sm: 30, md: 36, lg: 44, xl: 52 }[p.size] || p.size || 36) * .44))) },
13
- UserCell: { render: ({ C, h, props: p }) => h('span', { class: 'zg-usercell' }, h(C.Avatar, { name: p.name, src: p.src, size: { xs: 24, sm: 30, md: 36, lg: 44, xl: 56 }[p.size] || p.size || 36 }), h('span', null, h('b', null, p.name), p.sub ? h('span', { class: 'zg-hint' }, p.sub) : null)) },
14
- StatRow: { render: ({ C, h, props: p }) => h('div', { class: 'zg-srow' }, h(C.IconTile, { icon: p.icon, tone: p.tone, size: { xs: 28, sm: 34, md: 40, lg: 48, xl: 56 }[p.size] || p.size || 40 }), h('div', { style: { flex: 1, minWidth: 0 } }, h('b', { class: 'zg-srow__t', style: { fontSize: '15px' } }, p.title), p.sub ? h('div', { class: 'zg-hint' }, p.sub) : null), h('div', { style: { textAlign: 'end' } }, h('div', { class: 'zg-num zg-srow__v', style: { fontSize: '17px', fontWeight: 600 } }, p.value), delta(h, p.delta))) },
15
- CountryRow: { render: ({ h, props: p }) => h('div', { class: 'zg-srow' }, h('span', { class: 'zg-tile zg-tile--circle zg-t-neutral', style: { '--s': '38px', font: '700 12px var(--zg-font)' } }, p.code), h('div', { style: { flex: 1, minWidth: 0 } }, h('b', { class: 'zg-num', style: { fontSize: '16px' } }, p.amount), h('div', { class: 'zg-hint' }, p.name)), delta(h, p.pct)) },
16
- StatLine: { render: ({ C, h, props: p }) => h('div', { class: cx('zg-card zg-glass zg-statline', tc(p.tone)) }, h('div', { style: { display: 'flex', alignItems: 'center', gap: '12px' } }, h(C.IconTile, { icon: p.icon, tone: p.tone, size: { xs: 28, sm: 34, md: 40, lg: 48, xl: 56 }[p.size] || p.size || 40 }), h('span', { class: 'zg-num zg-statline__v', style: { fontSize: '26px', fontWeight: 400 } }, p.value)), h('span', { class: 'zg-hint' }, p.label), p.delta ? h('span', null, delta(h, p.delta)) : null, h('i', { class: 'zg-statline__bar' })) },
17
- StatStrip: { render: ({ C, h, props: p }) => h('div', { class: 'zg-card zg-glass zg-strip' }, ...(p.items || []).map((it, i) => h('div', { key: i, class: 'zg-strip__i' }, h(C.IconTile, { icon: it.icon, tone: it.tone, size: { xs: 30, sm: 36, md: 44, lg: 52, xl: 60 }[p.size] || p.size || 44 }), h('div', null, h('div', { class: 'zg-num zg-strip__v', style: { fontSize: '22px', fontWeight: 400 } }, it.value), h('div', { class: 'zg-hint' }, it.label))))) },
18
- VersusBar: { render: ({ h, props: p }) => { const a = { ...p.left }, b = { ...p.right }; a.value = Math.max(0, Number(a.value) || 0); b.value = Math.max(0, Number(b.value) || 0); const t = (a.value + b.value) || 1;
19
- return h('div', { class: 'zg-vs' }, h('div', { class: 'zg-vs__r' }, h('div', null, h('div', { class: 'zg-hint' }, a.label), h('b', { class: 'zg-num', style: { fontSize: '20px' } }, fmt.num(a.value))), h('span', { class: 'zg-tile zg-tile--circle zg-t-neutral', style: { '--s': '32px', font: '700 11px var(--zg-font)' } }, 'VS'), h('div', { style: { textAlign: 'end' } }, h('div', { class: 'zg-hint' }, b.label), h('b', { class: 'zg-num', style: { fontSize: '20px' } }, fmt.num(b.value)))),
20
- h('div', { class: 'zg-vs__bar' }, h('i', { style: { width: (a.value / t * 100) + '%', background: 'var(--zg-brand)' } }), h('i', { style: { flex: 1, background: 'var(--zg-sky)' } }))); } },
21
- SegBar: { render: ({ h, props: p }) => { const s = (Array.isArray(p.segments) ? p.segments : []).filter(Boolean).map(x => ({ ...x, value: Math.max(0, Number(x.value) || 0) })), t = s.reduce((a, x) => a + x.value, 0) || 1, col = ['var(--zg-brand)', 'var(--zg-sky)', 'var(--zg-green)', 'var(--zg-amber)', 'var(--zg-red)'];
22
- return h('div', { class: 'zg-field', style: { gap: '12px' } }, h('div', { class: 'zg-segbar' }, ...s.map((x, i) => h('i', { key: i, title: x.label, style: { width: (x.value / t * 100) + '%', background: x.color || col[i % 5] } }))), h('div', { class: 'zg-chips' }, ...s.map((x, i) => h('span', { key: i, class: 'zg-hint', style: { display: 'inline-flex', alignItems: 'center', gap: '6px' } }, h('i', { style: { width: '8px', height: '8px', borderRadius: '50%', background: x.color || col[i % 5] } }), x.label + ' · ' + x.value)))); } },
23
- HeroBanner: { render: ({ C, h, props: p, children }) => h('section', { class: 'zg-hero zg-glass' }, h('div', { class: 'zg-hero__t' }, h('b', { style: { fontSize: '20px', fontWeight: 500 } }, p.title), p.text ? h('span', { style: { color: 'var(--zg-text-2)', lineHeight: 1.5 } }, p.text) : null, p.value ? h('span', { class: 'zg-num', style: { fontSize: '36px', fontWeight: 300 } }, p.value) : null, ...children, p.cta ? h(C.Button, { variant: 'primary', size: 'sm', onClick: p.onCta }, p.cta) : null), p.image ? h('span', { class: 'zg-hero__img', style: { backgroundImage: `url(${p.image})` } }) : null) },
24
- TabTiles: { render: ({ h, props: p }) => h('div', { class: 'zg-tt' }, ...(p.items || []).map(it => h('button', { key: it.value, type: 'button', class: 'zg-tt__i', 'aria-pressed': String(it.value === p.value), onClick: () => p.onChange && p.onChange(it.value) }, icon(h, it.icon || 'circle', 20), h('span', null, it.label))), p.addable ? h('button', { type: 'button', class: 'zg-tt__i zg-tt__add', 'aria-label': t('TabTiles', 'add'), onClick: p.onAdd }, icon(h, 'plus', 20)) : null) },
25
11
  PillTabs: { render: ({ h, props: p }) => h('div', { class: cx('zg-pt', p.vertical && 'zg-pt--v'), role: 'tablist', 'aria-orientation': p.vertical ? 'vertical' : undefined, onKeydown: rove('[role=tab]', { vertical: !!p.vertical }) }, ...(p.items || []).map((it, i, all) => h('button', { key: it.value, type: 'button', role: 'tab', tabIndex: tabIdx(all, x => x.value === p.value)(i), disabled: it.disabled, 'aria-selected': String(it.value === p.value), onClick: () => p.onChange && p.onChange(it.value) }, it.icon ? icon(h, it.icon, 16) : null, it.label))) },
26
- PillSelect: { state: { open: false }, render: ({ h, props: p, state, set }) => { const opts = p.options || [], v = p.modelValue !== undefined ? p.modelValue : p.value, open = state.open && !p.disabled; return h('div', { class: 'zg-dd' }, h('button', { type: 'button', class: 'zg-btn zg-btn--tonal zg-btn--sm', 'aria-haspopup': 'listbox', 'aria-expanded': String(open), disabled: p.disabled, onClick: () => set({ open: !state.open }), onKeydown: openKeys(open, () => set({ open: true })) }, (opts.find(o => o.value === v) || {}).label || p.placeholder, icon(h, 'chevron-down', 14)), open ? h('div', { class: 'zg-menu', role: 'listbox', 'aria-label': p.placeholder || (opts.find(o => o.value === v) || {}).label, 'data-zg-dd': '', ref: ddRef(() => set({ open: false }), { focus: true }), onKeydown: listKeys('[role=option]', { onTab: e => { const t = trigger(e.currentTarget); t && t.focus(); set({ open: false }); } }) }, ...opts.map((o, i) => h('button', { key: o.value, type: 'button', role: 'option', tabIndex: tabIdx(opts, x => x.value === v)(i), class: 'zg-menu__i', disabled: o.disabled, 'aria-disabled': o.disabled ? 'true' : undefined, 'aria-selected': String(o.value === v), onClick: e => { toTrigger(e); set({ open: false }); p.onChange && p.onChange(o.value); } }, o.label))) : null); } },
27
- ChartCard: { state: { open: false }, render: ({ h, props: p, state, set, children }) => h('section', { class: 'zg-card zg-glass' }, h('div', { class: 'zg-card__head' }, h('div', { style: { flex: 1, minWidth: 0 } }, h('h3', { class: 'zg-card__title' }, p.title), p.subtitle ? h('div', { class: 'zg-card__sub' }, p.subtitle) : null),
28
- p.menu ? h('div', { class: 'zg-dd' }, h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('ChartCard', 'more'), 'aria-haspopup': 'menu', onClick: () => set({ open: !state.open }) }, icon(h, 'ellipsis-vertical')), state.open ? h('div', { class: 'zg-menu', role: 'menu', style: { insetInlineStart: 'auto', insetInlineEnd: 0 } }, ...p.menu.map(m => h('button', { key: m, type: 'button', role: 'menuitem', class: cx('zg-menu__i', m === 'Delete' && 'zg-menu__i--danger'), onClick: () => { set({ open: false }); p.onMenu && p.onMenu(m); } }, m))) : null) : null), ...children) },
29
- ActionCard: { state: { collapsed: false, loading: false, removed: false }, render: ({ C, h, props: p, state, set, children }) => { const col = p.collapsed !== undefined ? !!p.collapsed && p.collapsed !== 'false' : state.collapsed, busy = p.loading !== undefined ? !!p.loading && p.loading !== 'false' : state.loading; return state.removed ? null : h('section', { class: 'zg-card zg-glass zg-lo' }, h('div', { class: 'zg-card__head' }, h('div', { style: { flex: 1 } }, h('h3', { class: 'zg-card__title' }, p.title), p.subtitle ? h('div', { class: 'zg-card__sub' }, p.subtitle) : null), h('div', { style: { display: 'flex', gap: '2px' } }, h(C.IconButton, { icon: col ? 'chevron-down' : 'chevron-up', label: col ? t('ActionCard', 'expand') : t('ActionCard', 'collapse'), size: 'sm', ghost: true, onClick: () => { set({ collapsed: !col }); p.onCollapse && p.onCollapse(!col); } }), h(C.IconButton, { icon: 'refresh-cw', label: t('ActionCard', 'refresh'), size: 'sm', ghost: true, onClick: () => { if (p.loading === undefined) { set({ loading: true }); setTimeout(() => set({ loading: false }), 1800); } p.onRefresh && p.onRefresh(); } }), h(C.IconButton, { icon: 'x', label: t('ActionCard', 'remove'), size: 'sm', ghost: true, onClick: () => { set({ removed: true }); p.onRemove && p.onRemove(); } }))),
30
- col ? null : h('div', null, ...children), busy ? h('div', { class: 'zg-lo__o' }, h(C.Spinner, { size: 28 })) : null); } },
31
12
  Snackbar: { render: ({ h, props: p, children }) => h('div', { class: cx('zg-snack', p.variant === 'tonal' && 'zg-snack--tonal', tc(p.tone)), role: 'status' }, h('span', { style: { flex: 1 } }, ...children), p.action ? h('button', { type: 'button', onClick: p.onAction, style: { color: p.tone === 'success' ? 'var(--zg-green)' : 'var(--zg-red)' } }, p.action) : null, p.onClose ? h('button', { type: 'button', onClick: p.onClose, 'aria-label': t('Snackbar', 'close') }, icon(h, 'x', 14)) : null) },
32
- TourPopover: { render: ({ C, h, props: p }) => h('div', { class: 'zg-tour' }, h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, h('b', { style: { flex: 1, fontSize: '16px' } }, p.title), h('button', { type: 'button', 'aria-label': t('TourPopover', 'close'), class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', onClick: p.onClose }, icon(h, 'x', 14))), h('span', { style: { fontSize: '14px', lineHeight: 1.5 } }, p.text), h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } }, h('span', { class: 'zg-hint zg-mono' }, p.step || ''), h('div', { style: { display: 'flex', gap: '8px' } }, p.onBack ? h(C.Button, { size: 'sm', onClick: p.onBack }, t('TourPopover', 'back')) : null, h(C.Button, { size: 'sm', variant: 'primary', onClick: p.onNext }, p.last ? t('TourPopover', 'finish') : t('TourPopover', 'next'))))) },
33
- ProfileHeader: { render: ({ C, h, props: p, children }) => h('section', { class: 'zg-card zg-glass zg-prof' }, h('div', { class: 'zg-prof__cover', style: { backgroundImage: p.cover ? `url(${p.cover})` : undefined } }), h('div', { class: 'zg-prof__row' }, h('span', { class: 'zg-prof__av' }, h(C.Avatar, { name: p.name, src: p.src, size: 104 })), h('div', { style: { flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' } }, h('b', { style: { fontSize: '22px', fontWeight: 500 } }, p.name), h('div', { class: 'zg-chips', style: { color: 'var(--zg-text-3)', fontSize: '13px' } }, ...(p.meta || []).map(m => h('span', { key: m.label, style: { display: 'inline-flex', gap: '6px', alignItems: 'center' } }, icon(h, m.icon, 14), m.label)))), ...children)) },
34
13
  SocialAuth: { render: ({ C, h, props: p }) => {
35
14
  const list = (p.providers || ['google', 'apple']).filter(k => k === 'google' || k === 'apple');
36
15
  const icon = k => k === 'apple'
@@ -46,27 +25,6 @@ export const more3 = {
46
25
  p.divider === false ? null : h('div', { class: 'zg-social__or', role: 'separator' }, h('span', null, t('SocialAuth', 'or'))),
47
26
  h('div', { class: 'zg-social__row' }, ...list.map(k => h(C.Button, { key: k, variant: 'secondary', size: 'lg', block: stack, iconOnly: !stack, title: t('SocialAuth', 'continueWith', { provider: name(k) }), 'aria-label': t('SocialAuth', 'continueWith', { provider: name(k) }), onClick: () => p.onSelect && p.onSelect(k) }, icon(k), stack ? t('SocialAuth', 'continueWith', { provider: name(k) }) : null))));
48
27
  } },
49
- AuthShowcase: { render: ({ C, h, props: p, children }) => {
50
- const v = p.variant === 'light' || p.variant === 'tint' ? p.variant : 'photo';
51
- const people = p.people || [];
52
- const stack = size => h('span', { class: 'zg-ash__stack' }, ...people.slice(0, 4).map((u, i) => h(C.Avatar, { key: i, name: u.name, src: u.src, size })));
53
- const head = h('div', { class: 'zg-ash__head' }, p.logo || null, h('h1', { class: 'zg-ash__title' }, p.title), p.subtitle ? h('p', { class: 'zg-ash__sub' }, p.subtitle) : null);
54
- const form = h('div', { class: 'zg-ash__form' }, head, h('div', { class: 'zg-ash__fields' }, ...children), p.footer ? h('div', { class: 'zg-ash__foot' }, p.footer) : null);
55
- const art = { backgroundImage: p.image ? 'url(' + p.image + ')' : undefined };
56
- if (v === 'photo') {
57
- const spots = ['a', 'b', 'c'];
58
- return h('div', { class: 'zg-root zg-ash zg-ash--photo' }, h('div', { class: 'zg-ash__frame' },
59
- h('section', { class: 'zg-ash__media', style: art }, h('div', { class: 'zg-ash__copy' }, p.headline ? h('h2', null, p.headline) : null, p.caption ? h('p', null, p.caption) : null),
60
- ...people.slice(0, 3).map((u, i) => h('span', { key: i, class: 'zg-ash__float zg-ash__float--' + spots[i] }, h(C.Avatar, { name: u.name, src: u.src, size: i === 1 ? 'lg' : 'md' }))),
61
- p.quote ? h('small', { class: 'zg-ash__quote' }, p.quote) : null),
62
- h('main', { class: 'zg-ash__side' }, form)));
63
- }
64
- return h('div', { class: 'zg-root zg-ash zg-ash--' + v }, h('div', { class: 'zg-ash__grid' },
65
- h('div', { class: 'zg-ash__col' }, h('main', { class: 'zg-ash__card' }, form),
66
- p.proof ? h('div', { class: 'zg-ash__proof' }, stack('sm'), h('div', { class: 'zg-ash__proofT' }, h('b', null, p.proof), p.proofHint ? h('span', null, p.proofHint) : null), h(C.IconButton, { icon: 'arrow-up-right', label: p.proof, ghost: true })) : null),
67
- h('section', { class: 'zg-ash__media', style: art }, v === 'tint' && p.headline ? h('h2', { class: 'zg-ash__mh' }, p.headline) : null,
68
- h('div', { class: 'zg-ash__glass' }, (p.chips || []).length ? h('div', { class: 'zg-ash__chips' }, ...p.chips.map((c, i) => h('span', { key: i, class: 'zg-ash__chip' }, c))) : null, p.caption ? h('p', null, p.caption) : null))));
69
- } },
70
28
  AuthSplit: { render: ({ h, props: p, children }) => h('div', { class: 'zg-root zg-split2' }, h('aside', { class: 'zg-split2__a' }, p.aside), h('main', { class: 'zg-split2__m' }, h('div', { style: { width: '100%', maxWidth: '420px', display: 'flex', flexDirection: 'column', gap: '20px' } }, p.logo || null, h('div', null, h('h1', { style: { margin: 0, font: '300 28px var(--zg-font)', letterSpacing: '-.03em' } }, p.title), p.subtitle ? h('p', { style: { margin: '6px 0 0', color: 'var(--zg-text-2)', lineHeight: 1.5 } }, p.subtitle) : null), ...children))) },
71
29
  StatusPage: { state: { email: '' }, render: ({ C, h, props: p, children, state, set }) => { const K = { 404: ['404', t('StatusPage', 'nfTitle'), t('StatusPage', 'nfDesc'), t('StatusPage', 'home')], 401: ['401', t('StatusPage', 'authTitle'), t('StatusPage', 'authDesc'), t('StatusPage', 'home')], maintenance: ['', t('StatusPage', 'mtTitle'), t('StatusPage', 'mtDesc'), t('StatusPage', 'home')], soon: ['', t('StatusPage', 'soonTitle'), t('StatusPage', 'soonDesc'), t('StatusPage', 'notify')] }[p.kind || '404'];
72
30
  return h('div', { class: 'zg-es zg-es--page' }, p.codeNode || (K[0] ? h('span', { class: 'zg-num', style: { fontSize: 'clamp(80px,14vw,150px)', lineHeight: 1, color: 'var(--zg-brand-text)' } }, K[0]) : h('span', { class: 'zg-es__ico' }, icon(h, p.kind === 'soon' ? 'rocket' : 'wrench', 28))), p.messageNode || [h('b', { key: 't', style: { fontSize: '24px' } }, p.title || K[1]), h('span', { key: 'd' }, p.description || K[2])], p.actionNode || (p.kind === 'soon' ? h('div', { style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'center', width: '100%', maxWidth: '420px' } }, h('div', { style: { flex: '1 1 200px' } }, h(C.TextField, { placeholder: p.emailLabel || 'name@email.com', icon: 'mail', modelValue: state.email, onChange: v => set({ email: v }) })), h(C.Button, { variant: 'primary', onClick: () => p.onNotify && p.onNotify(state.email) }, p.notifyLabel || K[3])) : h(C.Button, { variant: 'primary', onClick: p.onAction }, p.actionLabel || K[3])), ...children); } }
@@ -1,16 +1,6 @@
1
1
  // @ziyarago/ui · components, part 4 — gaps closed after the Vuexy audit.
2
2
  import { t } from '../i18n/index.js';
3
- import { icon, cx, fmt } from './components.js';
4
- import { trap } from './dialog.js';
5
3
  const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
6
- export const pd = v => { if (v == null || v === '') return null; if (v instanceof Date) return isNaN(v) ? null : v; if (typeof v === 'string') { const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(v.trim()); if (m) return new Date(+m[1], +m[2] - 1, +m[3]); } const d = new Date(v); return isNaN(d) ? null : d; };
7
- const SAN_TAGS = new Set('a b i u s em strong strike del ins sub sup p div span br hr ul ol li blockquote pre code h1 h2 h3 h4 h5 h6 img table thead tbody tr td th font small mark'.split(' ')), SAN_DROP = new Set('script style iframe object embed link meta base form input button textarea select svg math noscript template frame frameset applet'.split(' ')), SAN_ATTR = new Set('href src alt title target rel class style colspan rowspan align color size width height'.split(' '));
8
- const sanitizeHtml = html => { if (typeof document === 'undefined') return html; const t = document.createElement('template'); t.innerHTML = html;
9
- const walk = node => { for (const c of [...node.childNodes]) { if (c.nodeType !== 1) { if (c.nodeType !== 3) c.remove(); continue; } const tag = c.tagName.toLowerCase(); if (SAN_DROP.has(tag)) { c.remove(); continue; } walk(c); if (!SAN_TAGS.has(tag)) { c.replaceWith(...c.childNodes); continue; }
10
- for (const a of [...c.attributes]) { const n = a.name.toLowerCase(), v = a.value.replace(/[\s\u0000-\u001f]/g, '').toLowerCase(); if (!SAN_ATTR.has(n) || n.startsWith('on') || (/^(javascript|vbscript|data):/.test(v) && !(n === 'src' && /^data:image\//.test(v))) || (n === 'style' && /expression\(|javascript:|url\(|@import/.test(v))) c.removeAttribute(a.name); }
11
- if (tag === 'a' && c.getAttribute('target') === '_blank') c.setAttribute('rel', 'noopener noreferrer'); } };
12
- walk(t.content); return t.innerHTML; };
13
-
14
4
  export const rules = {
15
5
  required: () => v => (v == null || String(v).trim() === '') ? t('Validation', 'required') : true,
16
6
  email: () => v => !v || /^\S+@\S+\.\S+$/.test(v) || t('Validation', 'email'),
@@ -27,33 +17,5 @@ export const rules = {
27
17
  };
28
18
 
29
19
  export const more4 = {
30
- ValidatedField: { state: { v: undefined, touched: false }, render: ({ C, h, props: p, state, set }) => {
31
- const val = state.v ?? p.modelValue ?? '', rs = p.rules || [];
32
- let err = null; if (state.touched) for (const r of rs) { const x = r(val); if (x !== true) { err = x; break; } }
33
- const Comp = p.type === 'password' ? C.PasswordInput : C.TextField;
34
- return h(Comp, { ...p, modelValue: val, error: p.error || err, onChange: v => { set({ v, touched: true }); p.onChange && p.onChange(v); } }); } },
35
20
  Footer: { render: ({ h, props: p, children }) => h('footer', { class: 'zg-foot' }, h('span', { style: { color: 'var(--zg-text-3)', fontSize: '13px' } }, p.copyright || '© 2026 ZiyaraGo'), h('nav', { style: { display: 'flex', gap: '16px', flexWrap: 'wrap' } }, ...(p.links || []).map(l => h('a', { key: l.label, href: l.href || '#', style: { color: 'var(--zg-brand-text)', fontSize: '13px', fontWeight: 600 } }, l.label))), ...children) },
36
- DataGroup: { state: { open: {} , grp: {} }, render: ({ C, h, props: p, state, set }) => { const cols = p.columns || [];
37
- const row = r => { const o = !!state.open[r.id]; return [h('tr', { key: r.id, 'aria-selected': o ? 'true' : undefined }, p.expand ? h('td', { style: { width: '44px' } }, h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-expanded': String(o), 'aria-label': t('DataGroup', 'expand'), onClick: () => set({ open: { ...state.open, [r.id]: !o } }) }, icon(h, o ? 'chevron-down' : 'chevron-right', 16))) : null, ...cols.map(c => h('td', { key: c.key, class: c.num ? 'num' : undefined }, c.render ? c.render(r[c.key], r) : r[c.key]))), o && p.expand ? h('tr', { key: r.id + 'x' }, h('td', { colSpan: cols.length + 1, style: { background: 'var(--zg-s1)', padding: '16px 20px' } }, p.expand(r))) : null]; };
38
- return h('div', { class: 'zg-table-wrap', tabIndex: 0 }, h('table', { class: 'zg-table' }, h('thead', null, h('tr', null, p.expand ? h('th') : null, ...cols.map(c => h('th', { key: c.key, class: c.num ? 'num' : undefined }, c.label)))),
39
- h('tbody', null, ...(p.groups || []).flatMap(g => { const c = !!state.grp[g.label]; return [h('tr', { key: 'g' + g.label }, h('td', { colSpan: cols.length + 1, style: { padding: 0 } }, h('button', { type: 'button', class: 'zg-dg__g', onClick: () => set({ grp: { ...state.grp, [g.label]: !c } }), style: { all: 'unset', boxSizing: 'border-box', display: 'flex', alignItems: 'center', gap: '8px', width: '100%', padding: '10px 16px', cursor: 'pointer', fontWeight: 700, fontSize: '13px', background: 'var(--zg-s1)' } }, icon(h, c ? 'chevron-right' : 'chevron-down', 14), g.label + ' (' + g.rows.length + ')'))), ...(c ? [] : g.rows.flatMap(row))]; })))); } },
40
- OptionCard: { render: ({ h, props: p }) => h('button', { type: 'button', role: p.multiple ? 'checkbox' : 'radio', 'aria-checked': String(!!p.checked), class: 'zg-opt', onClick: p.onClick }, p.image ? h('span', { class: 'zg-opt__img', style: { backgroundImage: `url(${p.image})` } }) : p.icon ? h('span', { class: 'zg-tile zg-t-brand', style: { '--s': '40px' } }, icon(h, p.icon, 20)) : null, h('span', { style: { display: 'flex', flexDirection: 'column', gap: '2px', flex: 1, textAlign: 'start' } }, h('b', { style: { fontSize: '15px' } }, p.title), p.desc ? h('span', { class: 'zg-hint' }, p.desc) : null), p.price ? h('b', { class: 'zg-num', style: { fontSize: '16px' } }, p.price) : null, h('span', { class: cx('zg-check__box', !p.multiple && 'zg-radio'), style: { background: p.checked ? 'var(--zg-brand)' : 'transparent' } }, p.checked ? (p.multiple ? icon(h, 'check', 12) : h('i')) : null)) },
41
- OptionCards: { render: ({ C, h, props: p }) => { const cur = p.multiple ? (p.modelValue || []) : p.modelValue;
42
- return h('div', { class: 'zg-field' }, p.label ? h('span', { class: 'zg-label' }, p.label) : null, h('div', { style: { display: 'grid', gridTemplateColumns: `repeat(auto-fit,minmax(min(100%,${p.min || 220}px),1fr))`, gap: '10px' } }, ...(p.options || []).map(o => h(C.OptionCard, { ...o, multiple: p.multiple, checked: p.multiple ? cur.includes(o.value) : cur === o.value, onClick: () => p.onChange && p.onChange(p.multiple ? (cur.includes(o.value) ? cur.filter(x => x !== o.value) : [...cur, o.value]) : o.value) })))); } },
43
- RichEditor: { render: ({ h, props: p }) => { let ed; const san = x => p.sanitize ? sanitizeHtml(x) : x, emit = () => { if (!ed) return; const x = san(ed.innerHTML); ed.__zg = x; p.onChange && p.onChange(x); }; const cmd = (c, v) => () => { if (!ed) return; ed.focus(); try { document.execCommand(c, false, v); } catch (e) {} emit(); };
44
- const B = [['bold', 'bold', t('RichEditor', 'bold')], ['italic', 'italic', t('RichEditor', 'italic')], ['underline', 'underline', t('RichEditor', 'underline')], ['strikeThrough', 'strikethrough', t('RichEditor', 'strike')], null, ['justifyLeft', 'align-left', t('RichEditor', 'left')], ['justifyCenter', 'align-center', t('RichEditor', 'center')], ['justifyRight', 'align-right', t('RichEditor', 'right')], null, ['insertUnorderedList', 'list', t('RichEditor', 'bullets')], ['insertOrderedList', 'list-ordered', t('RichEditor', 'numbers')], null, ['formatBlock', 'quote', t('RichEditor', 'quote'), 'blockquote'], ['formatBlock', 'code', t('RichEditor', 'codeBlock'), 'pre']];
45
- const area = h('div', { class: 'zg-rte__c', contentEditable: 'true', role: 'textbox', 'aria-multiline': 'true', 'aria-label': p.label || t('RichEditor', 'editor'), 'data-ph': p.placeholder || t('RichEditor', 'placeholder'), ref: el => { if (!el) return; ed = el; const want = p.modelValue ?? ''; if (el.__zg !== want && el.innerHTML !== want) el.innerHTML = san(want); el.__zg = want; }, onFocus: e => { ed = e.currentTarget; }, onInput: e => { ed = e.currentTarget; emit(); } });
46
- return h('div', { class: 'zg-field' }, p.label ? h('span', { class: 'zg-label' }, p.label) : null, h('div', { class: 'zg-rte' }, h('div', { class: 'zg-rte__t' }, ...B.map((b, i) => b ? h('button', { key: b[0] + i, type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', title: b[2], 'aria-label': b[2], onMouseDown: e => e.preventDefault(), onClick: cmd(b[0], b[3]) }, icon(h, b[1], 16)) : h('span', { key: 's' + i, class: 'zg-cb__s' }))), area)); } },
47
- RangeSlider: { render: ({ h, props: p }) => { const mn = p.min ?? 0, mx = p.max ?? 100, [a, b] = p.modelValue || [mn, mx], pa = (a - mn) / (mx - mn) * 100, pb = (b - mn) / (mx - mn) * 100, f = p.formatValue || (v => v);
48
- const inp = (v, k) => h('input', { type: 'range', class: 'zg-range2', min: mn, max: mx, step: p.step || 1, value: v, 'aria-label': k ? t('RangeSlider', 'max') : t('RangeSlider', 'min'), onInput: e => { const x = Number(e.target.value); p.onChange && p.onChange(k ? [a, Math.max(x, a)] : [Math.min(x, b), b]); } });
49
- return h('div', { class: 'zg-field' }, h('div', { style: { display: 'flex', justifyContent: 'space-between' } }, p.label ? h('span', { class: 'zg-label' }, p.label) : h('span'), h('span', { class: 'zg-mono', style: { fontSize: '13px' } }, f(a) + ' – ' + f(b))), h('div', { class: 'zg-range2w', style: { '--a': pa + '%', '--b': pb + '%' } }, h('i'), inp(a, 0), inp(b, 1))); } },
50
- RangeCalendar: { state: { from: null, to: null, hover: null, ym: null }, render: ({ h, props: p, state, set }) => { const loc = p.locale || 'en-GB', ctl = p.modelValue !== undefined, mv = ctl ? (p.modelValue || []) : [], day = v => { const d = pd(v); return d ? new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() : null; }, f = ctl ? day(mv[0]) : state.from, tt = ctl ? day(mv[1]) : state.to, b = state.ym ? new Date(state.ym) : (f != null ? new Date(f) : (pd(p.start) || new Date())), y = b.getFullYear(), m = b.getMonth(), ws = p.weekStartsOn ?? 1, off = (new Date(y, m, 1).getDay() - ws + 7) % 7, dn = new Date(y, m + 1, 0).getDate();
51
- const wd = Array.from({ length: 7 }, (_, i) => new Intl.DateTimeFormat(loc, { weekday: 'narrow' }).format(new Date(2023, 0, 1 + ((i + ws) % 7)))), td = d => new Date(y, m, d).getTime(), e = tt ?? (f && state.hover && state.hover > f ? state.hover : null);
52
- const pick = d => { const x = td(d); if (f == null || tt != null || x < f) { if (ctl) { set({ hover: null }); p.onChange && p.onChange([new Date(x), null]); } else set({ from: x, to: null, hover: null }); } else { if (!ctl) set({ to: x }); p.onChange && p.onChange([new Date(f), new Date(x)]); } };
53
- return h('div', { class: 'zg-cal' }, h('div', { class: 'zg-cal__h' }, h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('RangeCalendar', 'prev'), onClick: () => set({ ym: new Date(y, m - 1, 1).getTime() }) }, icon(h, 'chevron-left', 16)), h('b', null, new Intl.DateTimeFormat(loc, { month: 'long', year: 'numeric' }).format(b)), h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('RangeCalendar', 'next'), onClick: () => set({ ym: new Date(y, m + 1, 1).getTime() }) }, icon(h, 'chevron-right', 16))),
54
- h('div', { class: 'zg-cal__g' }, ...wd.map((d, i) => h('span', { key: 'w' + i, class: 'zg-cal__w' }, d)), ...Array.from({ length: off }, (_, i) => h('span', { key: 'o' + i })), ...Array.from({ length: dn }, (_, i) => { const d = i + 1, x = td(d), edge = x === f || x === e, mid = f && e && x > f && x < e; return h('button', { key: d, type: 'button', class: 'zg-cal__d', 'aria-pressed': String(!!edge), 'data-mid': mid ? '' : undefined, onMouseEnter: () => f != null && tt == null && set({ hover: x }), onClick: () => pick(d) }, d); }))); } },
55
- StepDialog: { render: ({ C, h, props: p, children, slots }) => !p.open ? null : h('div', { class: 'zg-modal-scrim', onClick: p.onClose }, h('div', { class: 'zg-modal zg-stepdlg', role: 'dialog', 'aria-modal': 'true', 'aria-label': p.title, ref: trap({ onClose: p.onClose }), onClick: e => e.stopPropagation() },
56
- h('aside', { class: 'zg-stepdlg__s' }, ...(p.steps || []).map((s, i) => h('div', { key: i, class: cx('zg-stepdlg__i', i < p.current && 'is-done', i === p.current && 'is-cur') }, h('span', { class: 'zg-step__n' }, i < p.current ? icon(h, 'check', 14) : i + 1), h('span', { style: { display: 'flex', flexDirection: 'column' } }, h('b', { style: { fontSize: '14px' } }, s.title), s.sub ? h('span', { class: 'zg-hint' }, s.sub) : null)))),
57
- h('div', { style: { flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' } }, h('div', { class: 'zg-modal__head' }, h('h3', null, p.title), h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('StepDialog', 'close'), onClick: p.onClose }, icon(h, 'x'))), h('div', { class: 'zg-modal__body', style: { flex: 1 } }, ...children), h('div', { class: 'zg-modal__foot', style: { justifyContent: 'space-between' } }, h(C.Button, { disabled: p.current === 0, onClick: p.onBack }, t('StepDialog', 'previous')), h(C.Button, { variant: 'primary', onClick: p.onNext }, p.current === (p.steps || []).length - 1 ? t('StepDialog', 'submit') : t('StepDialog', 'next')))))) },
58
- FullscreenDialog: { render: ({ C, h, props: p, children }) => !p.open ? null : h('div', { class: 'zg-fsd', role: 'dialog', 'aria-modal': 'true', 'aria-label': p.title, ref: trap({ onClose: p.onClose }) }, h('div', { class: 'zg-fsd__h' }, h(C.IconButton, { icon: 'x', label: t('FullscreenDialog', 'close'), onClick: p.onClose }), h('b', { style: { flex: 1, fontSize: '18px' } }, p.title), h(C.Button, { variant: 'inverse', onClick: p.onSave }, p.saveLabel || t('FullscreenDialog', 'save'))), h('div', { class: 'zg-fsd__b' }, ...children)) }
59
21
  };
@@ -1,59 +1,9 @@
1
1
  // @ziyarago/ui · components, part 6 — last catalog gaps: TreeSelect, ContextMenu, Sortable, Map, Screensaver, ImageUpload, Tour.
2
- import { t } from '../i18n/index.js';
3
2
  import { icon, cx, ddRef } from './components.js';
4
- import { trap, life } from './dialog.js';
5
3
  import { listKeys, tabIdx } from './keys.js';
6
- const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
7
-
8
4
  export const more6 = {
9
- TreeSelect: { state: { open: false, q: '', ex: {} }, render: ({ h, props: p, state, set }) => {
10
- const flat = (ns, d = 0) => ns.flatMap(n => [{ ...n, d }, ...(n.children ? flat(n.children, d + 1) : [])]), all = flat(p.nodes || []), cur = all.find(n => n.id === p.modelValue), q = state.q.toLowerCase();
11
- const node = (n, d) => { const has = n.children && n.children.length, o = q ? true : (state.ex[n.id] ?? d < 1);
12
- if (q && !all.filter(x => x.label.toLowerCase().includes(q)).some(x => x.id === n.id || (n.children || []).some(function f(c) { return c.id === x.id || (c.children || []).some(f); }))) return null;
13
- return h('div', { key: n.id }, h('button', { type: 'button', role: 'treeitem', disabled: n.disabled, 'aria-disabled': n.disabled ? 'true' : undefined, class: cx('zg-tree__n', n.id === p.modelValue && 'zg-tree__n--on'), style: { paddingInlineStart: 8 + d * 18 + 'px', width: '100%' }, onClick: () => { if (has && !q) set({ ex: { ...state.ex, [n.id]: !o } }); if (!has || p.selectGroups) { set({ open: false, q: '' }); p.onChange && p.onChange(n.id); } } }, has ? icon(h, o ? 'chevron-down' : 'chevron-right', 14) : h('span', { style: { width: '14px' } }), n.label), has && o ? n.children.map(c => node(c, d + 1)) : null); };
14
- return h('div', { class: 'zg-field' }, p.label ? h('span', { class: 'zg-label' }, p.label) : null, h('div', { class: 'zg-select' }, h('button', { type: 'button', class: 'zg-btn zg-select__trigger', 'aria-haspopup': 'tree', 'aria-expanded': String(state.open && !p.disabled), disabled: p.disabled, style: { height: 'var(--zg-h-lg)' }, onClick: () => set({ open: !state.open }) }, h('span', null, cur ? cur.label : (p.placeholder || '—')), icon(h, 'chevron-down', 16)),
15
- state.open && !p.disabled ? h('div', { class: 'zg-select__list', role: 'tree', 'data-zg-dd': '', ref: ddRef(() => set({ open: false, q: '' })), style: { padding: '8px' } }, h('span', { class: 'zg-input', style: { '--h': '36px', marginBottom: '6px' } }, icon(h, 'search', 14), h('input', { value: state.q, placeholder: t('TreeSelect', 'search'), onInput: e => set({ q: e.target.value }) })), ...(p.nodes || []).map(n => node(n, 0))) : null)); } },
16
5
  ContextMenu: { state: { x: 0, y: 0, open: false }, render: ({ h, props: p, state, set, children }) => {
17
6
  const close = () => set({ open: false });
18
7
  return h('div', { class: 'zg-ctx', onContextmenu: e => { e.preventDefault(); set({ open: true, x: e.clientX, y: e.clientY }); } }, ...children,
19
8
  state.open ? h('div', { class: 'zg-ctx__scrim', onClick: close, onContextmenu: e => { e.preventDefault(); close(); } }, h('div', { class: 'zg-menu', role: 'menu', 'data-zg-dd': '', ref: ddRef(close, { self: true, focus: true }), onKeydown: listKeys('[role=menuitem]', { wrap: true, onTab: close }), style: { position: 'fixed', left: Math.min(state.x, innerWidth - 240) + 'px', top: Math.min(state.y, innerHeight - (p.items || []).length * 42 - 20) + 'px', insetInlineStart: 'auto' }, onClick: e => e.stopPropagation() }, ...(p.items || []).map((it, i, all) => it.separator ? h('div', { key: i, class: 'zg-menu__sep', role: 'separator' }) : h('button', { key: i, type: 'button', role: 'menuitem', tabIndex: tabIdx(all.map(x => ({ disabled: x.separator || x.disabled })), () => false)(i), class: cx('zg-menu__i', it.tone === 'danger' && 'zg-menu__i--danger'), onClick: () => { close(); p.onSelect && p.onSelect(it.value); } }, it.icon ? icon(h, it.icon, 16) : null, it.label, it.shortcut ? h('span', { class: 'zg-kbd' }, it.shortcut) : null)))) : null); } },
20
- Sortable: { state: { drag: null, over: null }, render: ({ h, props: p, state, set }) => { const items = p.items || [];
21
- const drop = (to, f) => { const from = f === undefined ? state.drag : f; set({ drag: null, over: null }); if (from == null || from === to) return; const a = items.slice(); const [m] = a.splice(from, 1); a.splice(to, 0, m); p.onChange && p.onChange(a); };
22
- return h('div', { class: 'zg-sort', role: 'list' }, ...items.map((it, i) => h('div', { key: it.id ?? i, role: 'listitem', class: cx('zg-sort__i', state.over === i && state.drag !== i && 'is-over', state.drag === i && 'is-drag'), draggable: 'true', onDragstart: e => { e.dataTransfer.effectAllowed = 'move'; try { e.dataTransfer.setData('text/plain', String(i)); } catch (x) {} set({ drag: i }); }, onDragover: e => { e.preventDefault(); if (state.over !== i) set({ over: i }); }, onDrop: e => { e.preventDefault(); drop(i); }, onDragend: () => set({ drag: null, over: null }) },
23
- h('span', { class: 'zg-sort__h', 'aria-hidden': 'true' }, icon(h, 'grip-vertical', 16)), h('div', { style: { flex: 1, minWidth: 0 } }, p.render ? p.render(it, i) : h('b', null, it.label)),
24
- h('span', { style: { display: 'flex', gap: '2px' } }, h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('Sortable', 'moveUp'), disabled: i === 0, onClick: () => drop(i - 1, i) }, icon(h, 'chevron-up', 14)), h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', 'aria-label': t('Sortable', 'moveDown'), disabled: i === items.length - 1, onClick: () => drop(i + 1, i) }, icon(h, 'chevron-down', 14)))))); } },
25
- Map: { state: { lon: null, lat: null, z: null, dk: null, w: null }, render: ({ h, props: p, state, set }) => {
26
- const W = state.w || p.width || 640, H = p.height || 360, z = state.z ?? p.zoom ?? 14, lat0 = state.lat ?? p.lat ?? 21.4225, lon0 = state.lon ?? p.lon ?? 39.8262, n = 2 ** z;
27
- const mpx = (lat, lon, nn) => [(lon + 180) / 360 * nn * 256, (1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2 * nn * 256], px = (lat, lon) => mpx(lat, lon, n);
28
- const [cx0, cy0] = mpx(lat0, lon0, n), x0 = cx0 - W / 2, y0 = cy0 - H / 2, dark = p.theme ? p.theme === 'dark' : state.dk === true;
29
- const tiles = []; for (let tx = Math.floor(x0 / 256); tx <= Math.floor((x0 + W) / 256); tx++) for (let ty = Math.floor(y0 / 256); ty <= Math.floor((y0 + H) / 256); ty++) if (ty >= 0 && ty < n) tiles.push(h('img', { key: tx + '_' + ty, alt: '', draggable: 'false', src: `https://${'abc'[(tx + ty) & 1]}.basemaps.cartocdn.com/${p.style || (dark ? 'dark_all' : 'light_all')}/${z}/${((tx % n) + n) % n}/${ty}.png`, style: { position: 'absolute', left: (tx * 256 - x0) + 'px', top: (ty * 256 - y0) + 'px', width: '256px', height: '256px' } }));
30
- const unpx = (x, y, nn) => [Math.atan(Math.sinh(Math.PI * (1 - 2 * y / (nn * 256)))) * 180 / Math.PI, x / (nn * 256) * 360 - 180];
31
- const emit = (la, lo, zz) => { p.onMove && p.onMove({ lat: la, lon: lo, zoom: zz }); if (zz !== z) p.onZoom && p.onZoom(zz); };
32
- const zoomAt = (dz, ox, oy) => { const nz = clamp(z + dz, 3, 18); if (nz === z) return; const s = 2 ** (nz - z), nn = 2 ** nz, [la, lo] = unpx((cx0 + ox) * s - ox, (cy0 + oy) * s - oy, nn); set({ z: nz, lat: la, lon: lo }); emit(la, lo, nz); };
33
- const rel = (e, el) => { const q = el.getBoundingClientRect(); return [e.clientX - q.left - q.width / 2, e.clientY - q.top - q.height / 2]; };
34
- const pan = e => { if (e.button > 0 || !e.isPrimary) return; const el = e.currentTarget, sx = e.clientX, sy = e.clientY, pid = e.pointerId; let cap = false;
35
- const mv = ev => { if (ev.pointerId !== pid) return; const dx = ev.clientX - sx, dy = ev.clientY - sy; if (!cap) { if (Math.abs(dx) + Math.abs(dy) < 4) return; cap = true; try { el.setPointerCapture(pid); } catch (x) {} } const [la, lo] = unpx(cx0 - dx, cy0 - dy, n); set({ lat: la, lon: lo }); emit(la, lo, z); };
36
- const up = ev => { if (ev.pointerId !== pid) return; el.removeEventListener('pointermove', mv); el.removeEventListener('pointerup', up); el.removeEventListener('pointercancel', up); };
37
- el.addEventListener('pointermove', mv); el.addEventListener('pointerup', up); el.addEventListener('pointercancel', up); };
38
- const mk = (p.markers || []).map((m, i) => { const [mx, my] = px(m.lat, m.lon); return h('button', { key: 'm' + i, type: 'button', class: cx('zg-pin', m.tone && 'zg-t-' + m.tone), title: m.label, style: { left: (mx - x0) + 'px', top: (my - y0) + 'px' }, onClick: () => p.onSelect && p.onSelect(m) }, icon(h, m.icon || 'map-pin', 16)); });
39
- const stop = e => e.stopPropagation(), zb = (dz, k, d, ic) => h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--sm', 'aria-label': (p.labels && p.labels[k]) || d, onPointerdown: stop, onDblclick: stop, onClick: () => zoomAt(dz, 0, 0) }, icon(h, ic, 16));
40
- return h('div', { class: 'zg-map', role: 'application', 'aria-label': p.label || t('Map', 'label'), style: { height: H + 'px' }, onPointerdown: pan, onDblclick: e => { const [ox, oy] = rel(e, e.currentTarget); zoomAt(1, ox, oy); },
41
- ref: el => { if (!el) return; el.__zgw = e => { e.preventDefault(); const t = Date.now(); if (t - (el.__zgt || 0) < 180) return; el.__zgt = t; const [ox, oy] = rel(e, el); zoomAt(e.deltaY < 0 ? 1 : -1, ox, oy); };
42
- if (!el.__zgi) { el.__zgi = 1; el.addEventListener('wheel', e => el.__zgw(e), { passive: false }); if (typeof ResizeObserver !== 'undefined') new ResizeObserver(() => { const w = Math.round(el.clientWidth); if (w && w !== el.__zgl) { el.__zgl = w; set({ w }); } }).observe(el); }
43
- if (p.theme == null && state.dk == null) set({ dk: !!el.closest('[data-theme="dark"]') }); } }, ...tiles, ...mk,
44
- h('div', { class: 'zg-map__z' }, zb(1, 'zoomIn', t('Map', 'zoomIn'), 'plus'), zb(-1, 'zoomOut', t('Map', 'zoomOut'), 'minus')),
45
- h('span', { class: 'zg-map__c' }, '© OpenStreetMap · CARTO')); } },
46
- ImageUpload: { state: { src: null }, render: ({ h, props: p, state, set }) => { const src = state.src || p.modelValue, round = p.shape === 'circle';
47
- return h('div', { class: 'zg-field' }, p.label ? h('span', { class: 'zg-label' }, p.label) : null, h('label', { class: 'zg-imgup', style: { aspectRatio: p.aspect || '1/1', maxWidth: (({ xs: 112, sm: 128, md: 160, lg: 192, xl: 224 })[p.size] || p.size || 160) + 'px', borderRadius: round ? '50%' : '24px', backgroundImage: src ? `url(${src})` : undefined } }, src ? null : h('span', { class: 'zg-imgup__e' }, icon(h, 'image-up', 24), h('span', { class: 'zg-hint' }, p.hint || t('ImageUpload', 'upload'))), h('span', { class: 'zg-imgup__o' }, icon(h, 'camera', 18)),
48
- h('input', { type: 'file', accept: 'image/*', style: { display: 'none' }, onChange: e => { const f = e.target.files[0]; if (!f) return; const r = new FileReader(); r.onload = () => { set({ src: r.result }); p.onChange && p.onChange(r.result, f); }; r.readAsDataURL(f); } }))); } },
49
- Screensaver: { state: { t: 0 }, render: ({ h, props: p, state, set }) => { if (!p.open) return p.idleMs > 0 ? h('span', { hidden: true, 'aria-hidden': 'true', ref: life({ idleMs: p.idleMs, onIdle: p.onIdle, mount: (el, get) => { let tm; const arm = () => { clearTimeout(tm); tm = setTimeout(() => { const o = get(); o.onIdle && o.onIdle(); }, get().idleMs); }, evs = ['pointermove', 'pointerdown', 'keydown', 'wheel', 'touchstart']; evs.forEach(e => document.addEventListener(e, arm, { passive: true })); arm(); return () => { clearTimeout(tm); evs.forEach(e => document.removeEventListener(e, arm)); }; } }) }) : null;
50
- const d = new Date(state.t || 0), pad = n => String(n).padStart(2, '0'), ph = (d.getSeconds() % 40) / 40;
51
- return h('div', { class: 'zg-saver', role: 'dialog', 'aria-modal': 'true', 'aria-label': t('Screensaver', 'label'), tabIndex: 0, ref: trap({ onClose: p.onClose, onKey: e => { if (e.key === 'Tab') return false; p.onClose && p.onClose(); return true; }, mount: el => { const id = setInterval(() => set({ t: Date.now() }), 1000); set({ t: Date.now() }); return () => clearInterval(id); } }), onClick: p.onClose }, h('span', { class: 'zg-saver__g', style: { left: (10 + ph * 60) + '%', top: (20 + Math.sin(ph * 6.28) * 18) + '%' } }),
52
- h('div', { class: 'zg-saver__c' }, h('span', { class: 'zg-saver__m', style: { backgroundImage: 'url(assets/brand/ziyarago-mark.svg)' } }), h('b', { class: 'zg-num', style: { fontSize: 'clamp(64px,12vw,160px)', fontWeight: 200, letterSpacing: '-.04em', lineHeight: 1 } }, state.t ? pad(d.getHours()) + ':' + pad(d.getMinutes()) : '--:--'), h('span', { style: { color: 'var(--zg-text-2)', fontSize: '18px' } }, state.t ? new Intl.DateTimeFormat(p.locale || 'en-GB', { weekday: 'long', day: 'numeric', month: 'long' }).format(d) : '\u00a0'), p.hint ? h('span', { class: 'zg-hint' }, p.hint) : null)); } },
53
- Tour: { state: { i: 0, r: null }, render: ({ C, h, props: p, state, set }) => { if (!p.open) return null; const st = p.steps || [], i = clamp(p.step != null ? p.step : state.i, 0, Math.max(0, st.length - 1)), s = st[i] || {};
54
- const measure = () => { if (state.r || state.busy || !s.target) return; const el0 = document.querySelector(s.target); if (!el0) return; state.busy = true; setTimeout(() => { const el = document.querySelector(s.target) || el0, q = el.getBoundingClientRect(); if (q.top < 80 || q.bottom > innerHeight - 220) { let a = el.parentElement; while (a && !(/(auto|scroll)/.test(getComputedStyle(a).overflowY) && a.scrollHeight > a.clientHeight + 4)) a = a.parentElement; const dy = q.top - innerHeight / 3; if (a) a.scrollTop += dy; else window.scrollTo(0, window.scrollY + dy); } setTimeout(() => { state.busy = false; set({ r: (document.querySelector(s.target) || el).getBoundingClientRect() }); }, 160); }, 0); };
55
- const r = state.r, pad = 8, below = r ? r.bottom + 12 + 190 < innerHeight : true;
56
- const go = d => { const n = clamp(i + d, 0, st.length - 1); if (n === i) return; set({ i: n, r: null }); p.onStep && p.onStep(n); }, done = () => { set({ i: 0, r: null }); p.onClose && p.onClose(); };
57
- return h('div', { class: 'zg-tourov', role: 'dialog', 'aria-label': t('Tour', 'label'), ref: el => { if (el) measure(); trap({ focus: false, onClose: done, mount: () => () => set({ i: 0, r: null }), onKey: e => { const rtl = document.documentElement.dir === 'rtl', k = e.key === 'ArrowRight' ? (rtl ? -1 : 1) : e.key === 'ArrowLeft' ? (rtl ? 1 : -1) : 0; if (k) { e.preventDefault(); go(k); return true; } } })(el); } }, r ? h('span', { class: 'zg-tourov__cut', style: { left: (r.left - pad) + 'px', top: (r.top - pad) + 'px', width: (r.width + pad * 2) + 'px', height: (r.height + pad * 2) + 'px' } }) : h('span', { class: 'zg-tourov__full' }),
58
- h('div', { style: { position: 'fixed', zIndex: 2, left: r ? clamp(r.left, 12, innerWidth - 392) + 'px' : '50%', top: r ? (below ? r.bottom + 12 : Math.max(12, r.top - 12 - 190)) + 'px' : '40%', transform: r ? 'none' : 'translateX(-50%)' } }, h(C.TourPopover, { title: s.title, text: s.text, step: (i + 1) + ' / ' + st.length, last: i === st.length - 1, onBack: i ? () => go(-1) : null, onNext: () => i === st.length - 1 ? done() : go(1), onClose: done }))); } }
59
9
  };
@@ -1,5 +1,4 @@
1
1
  // @ziyarago/ui · components, part 7 — gluestack parity: typography, layout primitives, Link, Pressable, Icon, Portal, sheets, ImageViewer, ChatAi, LiquidGlass.
2
- import { t } from '../i18n/index.js';
3
2
  import { icon, cx } from './components.js';
4
3
  import { trap } from './dialog.js';
5
4
  const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
@@ -7,19 +6,6 @@ const sp = v => (typeof v === 'number' ? v + 'px' : v);
7
6
  const stack = (dir) => ({ render: ({ h, props: p, children }) => h(p.as || 'div', { class: 'zg-stack', style: { flexDirection: dir, gap: sp(p.gap ?? 12), alignItems: p.align, justifyContent: p.justify, flexWrap: p.wrap ? 'wrap' : undefined, ...(p.style || {}) } }, ...children) });
8
7
 
9
8
  export const more7 = {
10
- QiblaCompass: { render: ({ h, props: p }) => {
11
- const px = { xs: 120, sm: 160, md: 200, lg: 250, xl: 300 }[p.size] || (Number(p.size) > 0 ? Number(p.size) : 200), norm = v => ((Number(v) || 0) % 360 + 360) % 360, b = norm(p.bearing), hd = norm(p.heading), deg = Math.round(b), ticks = [];
12
- for (let i = 0; i < 72; i++) { const major = i % 9 === 0, a = i * 5 * Math.PI / 180, r1 = 92, r2 = major ? 80 : i % 3 ? 87 : 84; ticks.push(h('line', { key: i, class: major ? 'zg-qb__tk zg-qb__tk--m' : 'zg-qb__tk', x1: +(100 + Math.sin(a) * r1).toFixed(2), y1: +(100 - Math.cos(a) * r1).toFixed(2), x2: +(100 + Math.sin(a) * r2).toFixed(2), y2: +(100 - Math.cos(a) * r2).toFixed(2) })); }
13
- return h('div', { class: 'zg-qb zg-dm', role: 'img', 'aria-label': t('QiblaCompass', 'label', { deg }), style: { width: px + 'px' } },
14
- h('svg', { class: 'zg-qb__svg', viewBox: '0 0 200 200', 'aria-hidden': 'true', focusable: 'false' },
15
- h('circle', { class: 'zg-qb__ring', cx: 100, cy: 100, r: 98 }),
16
- h('g', { class: 'zg-qb__dial', transform: `rotate(${-hd} 100 100)` }, ...ticks, h('path', { class: 'zg-qb__n', d: 'M100 6 L106 20 L94 20 Z' })),
17
- h('g', { class: 'zg-qb__ptr', transform: `rotate(${b - hd} 100 100)` },
18
- h('line', { class: 'zg-qb__ln', x1: 100, y1: 100, x2: 100, y2: 46 }),
19
- h('rect', { class: 'zg-qb__kb', x: 88, y: 24, width: 24, height: 24, rx: 5 }),
20
- h('rect', { class: 'zg-qb__kg', x: 88, y: 31, width: 24, height: 4 })),
21
- h('circle', { class: 'zg-qb__hub', cx: 100, cy: 100, r: 5 })),
22
- h('div', { class: 'zg-qb__txt' }, h('b', { class: 'zg-num' }, deg + '°'), h('span', null, t('QiblaCompass', 'qibla')), p.distance ? h('small', null, p.distance) : null)); } },
23
9
  Heading: { render: ({ h, props: p, children }) => h('h' + clamp(p.level || 2, 1, 6), { class: cx('zg-heading', 'zg-heading--' + (p.size || 'lg'), p.brand && 'zg-heading--brand') }, ...children) },
24
10
  Text: { render: ({ h, props: p, children }) => h(p.as || 'p', { class: cx('zg-text', 'zg-text--' + (p.size || 'md'), p.tone && 'zg-text--' + p.tone, p.bold && 'zg-text--bold', p.truncate && 'zg-text--truncate') }, ...children) },
25
11
  Box: { render: ({ h, props: p, children }) => h(p.as || 'div', { class: cx('zg-box', p.glass && 'zg-glass'), style: { padding: sp(p.p), ...(p.style || {}) } }, ...children) },
@@ -31,26 +17,6 @@ export const more7 = {
31
17
  Pressable: { render: ({ h, props: p, children }) => h(p.as || 'button', { type: (p.as || 'button') === 'button' ? 'button' : undefined, class: 'zg-press', disabled: p.disabled, 'aria-label': p.label, onClick: p.onClick }, ...children) },
32
18
  Icon: { render: ({ h, props: p }) => icon(h, p.name || 'circle', { xs: 14, sm: 16, md: 20, lg: 24, xl: 32 }[p.size] || p.size || 20) },
33
19
  Portal: { render: ({ props: p, children, portal }) => (portal ? portal(children, p.to) : null) },
34
- LiquidGlass: { render: ({ h, props: p, children }) => h('div', { class: 'zg-liquid', style: { '--zg-liquid-r': sp(p.radius ?? 24), '--zg-liquid-b': sp(p.blur ?? 18) } }, ...children) },
35
20
  BottomSheet: { render: ({ h, props: p, children, slots }) => !p.open ? null : h('div', { class: 'zg-modal-scrim zg-sheet-scrim', onClick: p.onClose }, h('div', { class: 'zg-sheet', role: 'dialog', 'aria-modal': 'true', 'aria-label': p.title, ref: trap({ onClose: p.onClose }), style: { maxHeight: sp(p.maxHeight || '85vh') }, onClick: e => e.stopPropagation() },
36
21
  h('span', { class: 'zg-sheet__grab', 'aria-hidden': 'true' }), p.title ? h('h3', { class: 'zg-sheet__t' }, p.title) : null, h('div', { class: 'zg-sheet__b' }, ...children), (slots.footer || p.footer) ? h('div', { class: 'zg-sheet__f' }, slots.footer || p.footer) : null)) },
37
- Actionsheet: { render: ({ C, h, props: p }) => h(C.BottomSheet, { open: p.open, size: p.size, onClose: p.onClose, title: p.title },
38
- h('div', { class: 'zg-as' }, ...(p.items || []).map((it, i) => h('button', { key: i, type: 'button', class: cx('zg-as__i', it.tone && 'zg-as__i--' + it.tone), disabled: it.disabled, onClick: () => { it.onClick && it.onClick(); p.onSelect && p.onSelect(it); p.onClose && p.onClose(); } }, it.icon ? icon(h, it.icon, 18) : null, h('span', null, it.label)))),
39
- h('button', { type: 'button', class: 'zg-as__i zg-as__i--cancel', onClick: p.onClose }, p.cancelLabel || t('Actionsheet', 'cancel'))) },
40
- ImageViewer: { state: { i: null }, render: ({ h, props: p, state, set }) => {
41
- if (!p.open) return null;
42
- const im = p.images || [], i = clamp(state.i ?? p.index ?? 0, 0, Math.max(0, im.length - 1)), go = d => set({ i: (i + d + im.length) % im.length });
43
- return h('div', { class: 'zg-iv', role: 'dialog', 'aria-modal': 'true', 'aria-label': p.alt || t('ImageViewer', 'label'), onClick: p.onClose },
44
- h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--ghost zg-iv__x', 'aria-label': t('ImageViewer', 'close'), onClick: p.onClose }, icon(h, 'x', 20)),
45
- im.length > 1 ? h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--ghost zg-iv__p', 'aria-label': t('ImageViewer', 'previous'), onClick: e => { e.stopPropagation(); go(-1); } }, icon(h, 'chevron-left', 22)) : null,
46
- h('img', { class: 'zg-iv__img', src: im[i], alt: p.alt || '', onClick: e => e.stopPropagation() }),
47
- im.length > 1 ? h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--ghost zg-iv__n', 'aria-label': t('ImageViewer', 'next'), onClick: e => { e.stopPropagation(); go(1); } }, icon(h, 'chevron-right', 22)) : null,
48
- h('span', { class: 'zg-badge zg-iv__c' }, `${i + 1} / ${im.length}`)); } },
49
- ChatAi: { state: { q: '' }, render: ({ h, props: p, state, set }) => {
50
- const send = () => { const t = state.q.trim(); if (!t || p.loading) return; set({ q: '' }); p.onSend && p.onSend(t); };
51
- return h('section', { class: 'zg-chat zg-glass', 'aria-label': p.title || t('ChatAi', 'assistant') },
52
- p.title ? h('div', { class: 'zg-chat__h' }, h('b', null, p.title), p.subtitle ? h('span', { class: 'zg-hint' }, p.subtitle) : null) : null,
53
- h('div', { class: 'zg-chat__m', role: 'log', 'aria-live': 'polite' }, ...(p.messages || []).map((m, i) => h('div', { key: i, class: cx('zg-chat__b', 'zg-chat__b--' + (m.role === 'user' ? 'user' : 'ai')) }, m.text)), p.loading ? h('div', { class: 'zg-chat__b zg-chat__b--ai zg-chat__dots', 'aria-label': t('ChatAi', 'typing') }, h('i'), h('i'), h('i')) : null),
54
- h('div', { class: 'zg-chat__f' }, h('input', { class: 'zg-chat__in', value: state.q, placeholder: p.placeholder || t('ChatAi', 'placeholder'), 'aria-label': t('ChatAi', 'message'), onInput: e => set({ q: e.target.value }), onKeydown: e => { if (e.key === 'Enter') { e.preventDefault(); send(); } } }),
55
- h('button', { type: 'button', class: 'zg-ibtn zg-ibtn--brand', 'aria-label': t('ChatAi', 'send'), disabled: p.loading || !state.q.trim(), onClick: send }, icon(h, 'send', 18)))); } },
56
22
  };
package/src/core/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { components as base, fmt, setIconBase } from './components.js';
1
+ import { components as base, fmt, setIconBase, registerIcons } from './components.js';
2
2
  import { more } from './components2.js';
3
3
  import { more3 } from './components3.js';
4
4
  import { more4, rules } from './components4.js';
@@ -6,7 +6,7 @@ import { pages } from './pages.js';
6
6
  import { more6 } from './components6.js';
7
7
  import { more7 } from './components7.js';
8
8
  export const components = { ...base, ...more, ...more3, ...more4, ...more6, ...more7, ...pages };
9
- export { fmt, setIconBase, rules };
9
+ export { fmt, setIconBase, registerIcons, rules };
10
10
  /** Extension API: adds definitions to the shared registry (used by add-on packages such as @ziyarago/ui-pro). Registering the very same definition twice is a no-op (Vue and React adapters can both load one plugin). */
11
11
  export function registerComponents(defs, { override = false } = {}) {
12
12
  for (const name of Object.keys(defs)) if (!override && name in components && components[name] !== defs[name]) throw new Error(`@ziyarago/ui: component "${name}" is already registered (pass { override: true } to replace it)`);
package/src/core/pages.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // @ziyarago/ui · page templates — real slot contracts. Put inside <UiAppShell>, fill only the slots you need.
2
2
  // Vue: <UiPageDashboard title="Dashboard"><template #kpis>…</template></UiPageDashboard>
3
3
  // React: <UiPageDashboard title="Dashboard" kpis={<…/>} />
4
- import { cx } from './components.js';
5
4
 
6
5
  const region = (h, id, kids, stick) => (kids == null || (Array.isArray(kids) && !kids.length)) ? null : h('div', { key: id, class: stick ? 'zg-pg__r zg-pg__stick' : 'zg-pg__r', 'data-slot': id }, kids);
7
6
 
@@ -15,7 +14,7 @@ const draw = (h, node, ctx) => {
15
14
  return null;
16
15
  };
17
16
 
18
- const page = (name, slots, tree) => [name, {
17
+ export const page = (name, slots, tree) => [name, {
19
18
  slots,
20
19
  render: ({ C, h, props: p, slots: s }) => {
21
20
  const header = () => s.header ? region(h, 'header', s.header) : (p.title ? h('div', { class: 'zg-pg__r', 'data-slot': 'header' }, h('div', { class: 'zg-page-head' }, h('div', { style: { flex: 1, minWidth: 0 } }, p.crumbs ? h(C.Breadcrumbs, { items: p.crumbs }) : null, h('h1', null, p.title), p.subtitle ? h('p', null, p.subtitle) : null), s.actions || null)) : (s.actions ? h('div', { class: 'zg-pg__r', 'data-slot': 'header' }, h('div', { class: 'zg-page-head', style: { justifyContent: 'flex-end' } }, s.actions)) : null));
@@ -25,47 +24,14 @@ const page = (name, slots, tree) => [name, {
25
24
 
26
25
  const T = Object.fromEntries([
27
26
  page('PageDashboard', ['header', 'hero', 'kpis', 'occupancy', 'funnel', 'top', 'activity'], ['col', 'header', ['auto', 340, 'hero', 'kpis'], ['auto', 360, 'occupancy', 'funnel'], ['auto', 360, 'top', 'activity']]),
28
- page('PagePatterns', ['header', 'hero', 'strip', 'statlines', 'chartcard', 'tiles', 'listrows', 'countries', 'versus', 'segbar', 'activity', 'actioncard'], ['col', 'header', ['auto', 340, 'hero', 'strip'], 'statlines', ['auto', 360, 'chartcard', 'tiles'], ['auto', 320, 'listrows', 'countries', 'versus'], 'segbar', ['auto', 360, 'activity', 'actioncard']]),
29
- page('PageCrm', ['header', 'summary', 'filters', 'board', 'calls'], ['col', 'header', 'summary', 'filters', 'board', 'calls']),
30
- page('PageBookings', ['header', 'stats', 'toolbar', 'bulk', 'table', 'pager'], ['col', 'header', 'stats', 'toolbar', 'bulk', 'table', 'pager']),
31
- page('PageCatalog', ['header', 'filters', 'toolbar', 'grid', 'pager'], ['col', 'header', ['wrap', ['filters'], ['toolbar', 'grid', 'pager'], 260]]),
32
- page('PageDetail', ['header', 'gallery', 'summary', 'tabs', 'history', 'booking'], ['col', 'header', ['two', ['gallery', 'summary', 'tabs', 'history'], ['booking']]]),
33
27
  page('PageSettings', ['header', 'subnav', 'profile', 'notifications', 'integrations', 'danger'], ['col', 'header', ['wrap', ['subnav'], ['profile', 'notifications', 'integrations', 'danger'], 220]]),
34
28
  page('PageUserList', ['header', 'stats', 'filters', 'toolbar', 'table', 'drawer'], ['col', 'header', 'stats', ['two', ['filters', 'toolbar', 'table'], ['drawer']]]),
35
- page('PageProfile', ['header', 'profile', 'tabs', 'about', 'activity', 'plan'], ['col', 'header', 'profile', 'tabs', ['wrap', ['about'], ['activity', 'plan'], 320]]),
36
- page('PageForm', ['header', 'main', 'media', 'side', 'actions'], ['col', 'header', ['two', ['main', 'media'], ['side']]]),
37
- page('PageOrder', ['header', 'status', 'items', 'shipping', 'side'], ['col', 'header', 'status', ['two', ['items', 'shipping'], ['side']]]),
38
- page('PageAccount', ['header', 'tabs', 'panel'], ['col', 'header', 'tabs', 'panel']),
39
29
  page('PagePricing', ['header', 'toggle', 'plans', 'faq'], ['col', 'header', 'toggle', 'plans', 'faq']),
40
- page('PageFaq', ['header', 'search', 'cats', 'answers', 'contact'], ['col', 'header', 'search', ['wrap', ['cats'], ['answers'], 200], 'contact']),
41
- page('PageLanding', ['hero', 'logos', 'features', 'proof', 'pricing', 'cta', 'footer'], ['col', 'hero', 'logos', 'features', 'proof', 'pricing', 'cta', 'footer']),
42
- page('PageOnboarding', ['header', 'progress', 'steps', 'checklist', 'tips'], ['col', 'header', 'progress', ['two', ['steps', 'checklist'], ['tips']]]),
43
- page('PageCheckout', ['header', 'steps', 'items', 'address', 'payment', 'summary'], ['col', 'header', 'steps', ['two', ['items', 'address', 'payment'], ['summary']]]),
44
- page('PageInbox', ['header', 'filters', 'list', 'thread', 'composer', 'customer'], ['col', 'header', ['wrap', ['filters', 'list'], [['two', ['thread', 'composer'], ['customer']]], 320]]),
45
- page('PageNotifications', ['header', 'filters', 'feed', 'empty'], ['col', 'header', 'filters', 'feed', 'empty']),
46
- page('PageAnalytics', ['header', 'period', 'kpis', 'trend', 'breakdown', 'table'], ['col', 'header', 'period', 'kpis', ['auto', 420, 'trend', 'breakdown'], 'table']),
47
- page('PageCalendar', ['header', 'toolbar', 'grid', 'mini', 'details'], ['col', 'header', 'toolbar', ['two', ['grid'], ['mini', 'details']]]),
48
- page('PageKanban', ['header', 'filters', 'board', 'detail'], ['col', 'header', 'filters', ['two', ['board'], ['detail']]]),
49
- page('PageBilling', ['header', 'plan', 'usage', 'invoices', 'methods', 'upgrade'], ['col', 'header', ['two', ['plan', 'usage', 'invoices'], ['methods', 'upgrade']]]),
50
- page('PageTeam', ['header', 'stats', 'members', 'roles', 'invite'], ['col', 'header', 'stats', ['two', ['members', 'roles'], ['invite']]]),
51
- page('PageIntegrations', ['header', 'filters', 'connections', 'keys', 'webhooks'], ['col', 'header', 'filters', 'connections', ['auto', 420, 'keys', 'webhooks']]),
52
- page('PageSearch', ['header', 'search', 'filters', 'results', 'empty'], ['col', 'header', 'search', ['wrap', ['filters'], ['results', 'empty'], 260]]),
53
- page('PageArticle', ['header', 'cover', 'body', 'toc', 'share', 'related'], ['col', 'header', 'cover', ['two', ['body', 'share', 'related'], ['toc'], 'sticky:toc']]),
54
- page('PageChangelog', ['header', 'filters', 'timeline', 'subscribe'], ['col', 'header', ['two', ['filters', 'timeline'], ['subscribe'], 'sticky:subscribe']]),
55
- page('PageHelp', ['header', 'search', 'categories', 'popular', 'contact'], ['col', 'header', 'search', 'categories', ['auto', 360, 'popular', 'contact']]),
56
- page('PageStates', ['header', 'empty', 'noresults', 'forbidden', 'offline', 'error', 'loading', 'success'], ['col', 'header', ['auto', 300, 'empty', 'noresults', 'forbidden'], ['auto', 300, 'offline', 'error', 'loading'], 'success']),
57
- page('PageLegal', ['header', 'meta', 'toc', 'document', 'contact'], ['col', 'header', 'meta', ['wrap', ['toc'], ['document', 'contact'], 260, 'sticky:toc']]),
58
- page('PageLocations', ['header', 'filters', 'list', 'map'], ['col', 'header', 'filters', ['wrap', ['list'], ['map'], 380, 'sticky:map']]),
59
- page('PageBookingFlow', ['header', 'steps', 'content', 'nav', 'summary'], ['col', 'header', 'steps', ['two', ['content', 'nav'], ['summary'], 'sticky:summary']]),
60
- page('PageItinerary', ['header', 'days', 'timeline', 'transport', 'hotel', 'summary'], ['col', 'header', 'days', ['two', ['timeline', 'transport', 'hotel'], ['summary'], 'sticky:summary']]),
61
- page('PagePrayer', ['header', 'location', 'today', 'month', 'qibla'], ['col', 'header', 'location', ['two', ['today', 'month'], ['qibla'], 'sticky:qibla']]),
62
- page('PageGroupManager', ['header', 'trip', 'toolbar', 'bulk', 'pilgrims', 'rooms', 'payments'], ['col', 'header', 'trip', ['two', ['toolbar', 'bulk', 'pilgrims', 'rooms'], ['payments'], 'sticky:payments']]),
63
- page('PageTourPublic', ['header', 'gallery', 'highlights', 'itinerary', 'included', 'reviews', 'booking'], ['col', 'header', 'gallery', ['two', ['highlights', 'itinerary', 'included', 'reviews'], ['booking'], 'sticky:booking']])
64
30
  ]);
65
31
 
66
32
  T.PageAuth = { slots: ['background', 'logo', 'aside', 'form', 'footer'], render: ({ C, h, props: p, slots: s }) => {
67
33
  const body = [s.form || null, s.footer ? h('div', { class: 'zg-pg__r', 'data-slot': 'footer' }, s.footer) : null];
68
- if (['photo', 'light', 'tint'].includes(p.layout)) return h(C.AuthShowcase, { variant: p.layout, title: p.title, subtitle: p.subtitle, logo: s.logo, footer: s.footer, image: p.image, headline: p.headline, caption: p.caption, quote: p.quote, chips: p.chips, people: p.people, proof: p.proof, proofHint: p.proofHint }, s.form || null);
34
+ if (C.AuthShowcase && ['photo', 'light', 'tint'].includes(p.layout)) return h(C.AuthShowcase, { variant: p.layout, title: p.title, subtitle: p.subtitle, logo: s.logo, footer: s.footer, image: p.image, headline: p.headline, caption: p.caption, quote: p.quote, chips: p.chips, people: p.people, proof: p.proof, proofHint: p.proofHint }, s.form || null);
69
35
  return p.layout === 'split'
70
36
  ? h(C.AuthSplit, { title: p.title, subtitle: p.subtitle, logo: s.logo, aside: s.aside }, ...body)
71
37
  : h('div', { class: 'zg-pgauth' }, s.background ? h('div', { class: 'zg-pg__r zg-pgauth__bg', 'data-slot': 'background' }, s.background) : null, h('div', { class: 'zg-pgauth__c' }, h(C.AuthLayout, { title: p.title, subtitle: p.subtitle, logo: s.logo }, ...body)));
@@ -1,141 +1,69 @@
1
1
  // generated by scripts/i18n-index.mjs: do not edit
2
2
  import { defineMessages } from '../index.js';
3
- import ActionCard from './ActionCard.js';
4
- import Actionsheet from './Actionsheet.js';
5
3
  import Alert from './Alert.js';
6
4
  import Breadcrumbs from './Breadcrumbs.js';
7
5
  import Calendar from './Calendar.js';
8
- import CallCard from './CallCard.js';
9
- import CallRow from './CallRow.js';
10
- import Carousel from './Carousel.js';
11
- import ChartCard from './ChartCard.js';
12
- import ChatAi from './ChatAi.js';
13
6
  import Chip from './Chip.js';
14
- import ChipInput from './ChipInput.js';
15
7
  import CodeInput from './CodeInput.js';
16
8
  import Combobox from './Combobox.js';
17
9
  import CommandPalette from './CommandPalette.js';
18
10
  import ConfirmDialog from './ConfirmDialog.js';
19
- import ContactPanel from './ContactPanel.js';
20
11
  import CopyButton from './CopyButton.js';
21
- import DataGroup from './DataGroup.js';
22
12
  import DataState from './DataState.js';
23
13
  import DataTable from './DataTable.js';
24
14
  import DatePicker from './DatePicker.js';
25
- import DealCard from './DealCard.js';
26
15
  import Drawer from './Drawer.js';
27
16
  import ErrorPage from './ErrorPage.js';
28
17
  import FileUpload from './FileUpload.js';
29
- import FullscreenDialog from './FullscreenDialog.js';
30
- import Gallery from './Gallery.js';
31
- import GuestCard from './GuestCard.js';
32
- import ImageUpload from './ImageUpload.js';
33
- import ImageViewer from './ImageViewer.js';
34
- import IncomingCall from './IncomingCall.js';
35
- import InlineEdit from './InlineEdit.js';
36
- import IntegrationCard from './IntegrationCard.js';
37
18
  import LoginForm from './LoginForm.js';
38
- import Map from './Map.js';
39
19
  import Modal from './Modal.js';
40
20
  import MultiSelect from './MultiSelect.js';
41
- import NotificationBell from './NotificationBell.js';
42
21
  import NumberInput from './NumberInput.js';
43
22
  import Pagination from './Pagination.js';
44
23
  import PasswordInput from './PasswordInput.js';
45
24
  import Popconfirm from './Popconfirm.js';
46
- import PricingCard from './PricingCard.js';
47
25
  import Progress from './Progress.js';
48
- import QiblaCompass from './QiblaCompass.js';
49
- import RamadanTracker from './RamadanTracker.js';
50
- import RangeCalendar from './RangeCalendar.js';
51
- import RangeSlider from './RangeSlider.js';
52
26
  import Rating from './Rating.js';
53
- import RichEditor from './RichEditor.js';
54
- import Screensaver from './Screensaver.js';
55
27
  import SearchInput from './SearchInput.js';
56
28
  import SideNav from './SideNav.js';
57
29
  import Snackbar from './Snackbar.js';
58
30
  import SocialAuth from './SocialAuth.js';
59
- import Sortable from './Sortable.js';
60
31
  import Spinner from './Spinner.js';
61
32
  import StatusPage from './StatusPage.js';
62
- import StepDialog from './StepDialog.js';
63
- import StepForm from './StepForm.js';
64
- import TabTiles from './TabTiles.js';
65
33
  import Tag from './Tag.js';
66
34
  import TopNav from './TopNav.js';
67
- import Tour from './Tour.js';
68
- import TourCard from './TourCard.js';
69
- import TourPopover from './TourPopover.js';
70
- import TreeSelect from './TreeSelect.js';
71
35
  import Validation from './Validation.js';
72
36
 
73
- defineMessages('ActionCard', ActionCard);
74
- defineMessages('Actionsheet', Actionsheet);
75
37
  defineMessages('Alert', Alert);
76
38
  defineMessages('Breadcrumbs', Breadcrumbs);
77
39
  defineMessages('Calendar', Calendar);
78
- defineMessages('CallCard', CallCard);
79
- defineMessages('CallRow', CallRow);
80
- defineMessages('Carousel', Carousel);
81
- defineMessages('ChartCard', ChartCard);
82
- defineMessages('ChatAi', ChatAi);
83
40
  defineMessages('Chip', Chip);
84
- defineMessages('ChipInput', ChipInput);
85
41
  defineMessages('CodeInput', CodeInput);
86
42
  defineMessages('Combobox', Combobox);
87
43
  defineMessages('CommandPalette', CommandPalette);
88
44
  defineMessages('ConfirmDialog', ConfirmDialog);
89
- defineMessages('ContactPanel', ContactPanel);
90
45
  defineMessages('CopyButton', CopyButton);
91
- defineMessages('DataGroup', DataGroup);
92
46
  defineMessages('DataState', DataState);
93
47
  defineMessages('DataTable', DataTable);
94
48
  defineMessages('DatePicker', DatePicker);
95
- defineMessages('DealCard', DealCard);
96
49
  defineMessages('Drawer', Drawer);
97
50
  defineMessages('ErrorPage', ErrorPage);
98
51
  defineMessages('FileUpload', FileUpload);
99
- defineMessages('FullscreenDialog', FullscreenDialog);
100
- defineMessages('Gallery', Gallery);
101
- defineMessages('GuestCard', GuestCard);
102
- defineMessages('ImageUpload', ImageUpload);
103
- defineMessages('ImageViewer', ImageViewer);
104
- defineMessages('IncomingCall', IncomingCall);
105
- defineMessages('InlineEdit', InlineEdit);
106
- defineMessages('IntegrationCard', IntegrationCard);
107
52
  defineMessages('LoginForm', LoginForm);
108
- defineMessages('Map', Map);
109
53
  defineMessages('Modal', Modal);
110
54
  defineMessages('MultiSelect', MultiSelect);
111
- defineMessages('NotificationBell', NotificationBell);
112
55
  defineMessages('NumberInput', NumberInput);
113
56
  defineMessages('Pagination', Pagination);
114
57
  defineMessages('PasswordInput', PasswordInput);
115
58
  defineMessages('Popconfirm', Popconfirm);
116
- defineMessages('PricingCard', PricingCard);
117
59
  defineMessages('Progress', Progress);
118
- defineMessages('QiblaCompass', QiblaCompass);
119
- defineMessages('RamadanTracker', RamadanTracker);
120
- defineMessages('RangeCalendar', RangeCalendar);
121
- defineMessages('RangeSlider', RangeSlider);
122
60
  defineMessages('Rating', Rating);
123
- defineMessages('RichEditor', RichEditor);
124
- defineMessages('Screensaver', Screensaver);
125
61
  defineMessages('SearchInput', SearchInput);
126
62
  defineMessages('SideNav', SideNav);
127
63
  defineMessages('Snackbar', Snackbar);
128
64
  defineMessages('SocialAuth', SocialAuth);
129
- defineMessages('Sortable', Sortable);
130
65
  defineMessages('Spinner', Spinner);
131
66
  defineMessages('StatusPage', StatusPage);
132
- defineMessages('StepDialog', StepDialog);
133
- defineMessages('StepForm', StepForm);
134
- defineMessages('TabTiles', TabTiles);
135
67
  defineMessages('Tag', Tag);
136
68
  defineMessages('TopNav', TopNav);
137
- defineMessages('Tour', Tour);
138
- defineMessages('TourCard', TourCard);
139
- defineMessages('TourPopover', TourPopover);
140
- defineMessages('TreeSelect', TreeSelect);
141
69
  defineMessages('Validation', Validation);