@ziyarago/ui 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +5 -5
  3. package/dist/llms-full.txt +3 -3
  4. package/dist/llms.txt +2 -2
  5. package/dist/manifest.json +316 -2
  6. package/docs/INTEGRATION.md +14 -0
  7. package/package.json +10 -25
  8. package/src/core/components.js +0 -11
  9. package/src/core/components2.js +1 -71
  10. package/src/core/components3.js +2 -44
  11. package/src/core/components4.js +0 -38
  12. package/src/core/components6.js +0 -50
  13. package/src/core/components7.js +0 -34
  14. package/src/core/index.js +6 -0
  15. package/src/core/pages.js +2 -36
  16. package/src/i18n/components/index.js +0 -72
  17. package/src/internal.js +10 -0
  18. package/src/meta/index.js +15 -0
  19. package/src/meta/pages.js +1 -1
  20. package/src/nuxt/module.mjs +9 -1
  21. package/src/react/index.js +8 -107
  22. package/src/resolver.js +17 -4
  23. package/src/vue/index.js +9 -2
  24. package/types/core.d.ts +3 -0
  25. package/types/internal.d.ts +30 -0
  26. package/types/meta.d.ts +8 -0
  27. package/types/nuxt.d.ts +2 -0
  28. package/types/react.d.ts +138 -4143
  29. package/types/resolver.d.ts +2 -0
  30. package/types/vue-global.d.ts +0 -106
  31. package/types/vue.d.ts +147 -3598
  32. package/docs/MIGRATION.md +0 -455
  33. package/src/compat/index.js +0 -469
  34. package/src/compat/map.js +0 -282
  35. package/src/compat/resolver.js +0 -22
  36. package/src/compat/vite.js +0 -29
  37. package/src/i18n/components/ActionCard.js +0 -5
  38. package/src/i18n/components/Actionsheet.js +0 -5
  39. package/src/i18n/components/CallCard.js +0 -5
  40. package/src/i18n/components/CallRow.js +0 -5
  41. package/src/i18n/components/Carousel.js +0 -5
  42. package/src/i18n/components/ChartCard.js +0 -5
  43. package/src/i18n/components/ChatAi.js +0 -5
  44. package/src/i18n/components/ChipInput.js +0 -5
  45. package/src/i18n/components/ContactPanel.js +0 -5
  46. package/src/i18n/components/DataGroup.js +0 -5
  47. package/src/i18n/components/DealCard.js +0 -5
  48. package/src/i18n/components/FullscreenDialog.js +0 -5
  49. package/src/i18n/components/Gallery.js +0 -5
  50. package/src/i18n/components/GuestCard.js +0 -5
  51. package/src/i18n/components/ImageUpload.js +0 -5
  52. package/src/i18n/components/ImageViewer.js +0 -5
  53. package/src/i18n/components/IncomingCall.js +0 -5
  54. package/src/i18n/components/InlineEdit.js +0 -5
  55. package/src/i18n/components/IntegrationCard.js +0 -5
  56. package/src/i18n/components/Map.js +0 -5
  57. package/src/i18n/components/NotificationBell.js +0 -5
  58. package/src/i18n/components/PricingCard.js +0 -5
  59. package/src/i18n/components/QiblaCompass.js +0 -5
  60. package/src/i18n/components/RamadanTracker.js +0 -5
  61. package/src/i18n/components/RangeCalendar.js +0 -5
  62. package/src/i18n/components/RangeSlider.js +0 -5
  63. package/src/i18n/components/RichEditor.js +0 -5
  64. package/src/i18n/components/Screensaver.js +0 -5
  65. package/src/i18n/components/Sortable.js +0 -5
  66. package/src/i18n/components/StepDialog.js +0 -5
  67. package/src/i18n/components/StepForm.js +0 -5
  68. package/src/i18n/components/TabTiles.js +0 -5
  69. package/src/i18n/components/Tour.js +0 -5
  70. package/src/i18n/components/TourCard.js +0 -5
  71. package/src/i18n/components/TourPopover.js +0 -5
  72. package/src/i18n/components/TreeSelect.js +0 -5
  73. package/types/compat-resolver.d.ts +0 -12
  74. package/types/compat-vite.d.ts +0 -11
  75. package/types/compat.d.ts +0 -176
@@ -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
@@ -7,5 +7,11 @@ 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
9
  export { fmt, setIconBase, rules };
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
+ export function registerComponents(defs, { override = false } = {}) {
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)`);
13
+ Object.assign(components, defs);
14
+ return components;
15
+ }
10
16
  export { LOCALES, FREE_LOCALES, t, setUiLocale, getUiLocale, setUiMessages, isRtlLocale, subscribeUiLocale, getUiVersion, defineMessages } from '../i18n/index.js';
11
17
  import '../i18n/components/index.js';
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);
@@ -0,0 +1,10 @@
1
+ // Semi-internal entry for add-on packages such as @ziyarago/ui-pro. Not part of the public API: it can change in any minor release.
2
+ // It re-exports the helpers the component definitions are built from, so a plugin does not copy them.
3
+ export { cx, pick, INPUT_ATTRS, DZ, dzp, dzf, dzb, ddRef, icon, fmt } from './core/components.js';
4
+ export { trap, life } from './core/dialog.js';
5
+ export { rove, tabIdx, listKeys, openKeys, focusIn, toTrigger, trigger } from './core/keys.js';
6
+ export { rules } from './core/components4.js';
7
+ export { page } from './core/pages.js';
8
+ export { t, getUiLocale, intlLocale, defineMessages } from './i18n/index.js';
9
+ export { registerComponents, components } from './core/index.js';
10
+ export { BOOL_PROPS } from './core/bools.js';
package/src/meta/index.js CHANGED
@@ -11,4 +11,19 @@ import domain from './domain.js';
11
11
  import pages from './pages.js';
12
12
 
13
13
  export const meta = { ...typography, ...layout, ...actions, ...forms, ...data, ...feedback, ...overlay, ...navigation, ...media, ...domain, ...pages };
14
+ import { PRO_NAMES } from './tiers.js';
15
+ export { PRO, PRO_NAMES, isPro } from './tiers.js';
16
+ export { GROUPS } from './groups.js';
17
+ import { GROUPS } from './groups.js';
18
+ /** Extension API: adds API metadata for plugin components. `tiers` marks names as Pro, `groups` ({ id, title, blurb, names }) lists them in the manifest. */
19
+ export function registerMeta(extra, { tiers, groups } = {}) {
20
+ Object.assign(meta, extra);
21
+ for (const n of tiers || []) PRO_NAMES.add(n);
22
+ for (const g of groups || []) {
23
+ const ex = GROUPS.find(x => x.id === g.id);
24
+ if (ex) ex.names.push(...g.names.filter(n => !ex.names.includes(n)));
25
+ else GROUPS.push({ blurb: '', title: g.id, ...g, names: [...g.names] });
26
+ }
27
+ return meta;
28
+ }
14
29
  export default meta;
package/src/meta/pages.js CHANGED
@@ -481,7 +481,7 @@ export default {
481
481
  PageAuth: {
482
482
  description: 'Sign-in page template without the app shell, as a centered card or a split layout.',
483
483
  props: {
484
- layout: { forwarded: true, type: "'card' | 'split' | 'photo' | 'light' | 'tint'", values: ['card', 'split', 'photo', 'light', 'tint'], default: 'card', description: "'split' uses AuthSplit with a side panel. 'photo', 'light' and 'tint' use AuthShowcase with a media panel. Anything else renders a centered AuthLayout card over the background." },
484
+ layout: { forwarded: true, type: "'card' | 'split' | 'photo' | 'light' | 'tint'", values: ['card', 'split', 'photo', 'light', 'tint'], default: 'card', description: "'split' uses AuthSplit with a side panel. 'photo', 'light' and 'tint' use AuthShowcase with a media panel (Pro: needs @ziyarago/ui-pro, otherwise they fall back to the centered card). Anything else renders a centered AuthLayout card over the background." },
485
485
  image: { forwarded: true, type: 'string', description: 'Media image URL; photo, light and tint layouts.' },
486
486
  headline: { forwarded: true, type: 'string', description: 'Large text on the media panel; photo and tint.' },
487
487
  caption: { forwarded: true, type: 'string', description: 'Small text on the media panel or glass bar.' },
@@ -1,11 +1,12 @@
1
1
  // Nuxt 3/4 module. nuxt.config: modules: ['@ziyarago/ui/nuxt'], ziyarago: { theme: true }
2
2
  import { defineNuxtModule, addComponent, addImports, addPlugin, createResolver } from '@nuxt/kit';
3
+ import { createRequire } from 'node:module';
3
4
  import { components } from '../core/index.js';
4
5
  import { themeInitScript } from '../theme.js';
5
6
 
6
7
  export default defineNuxtModule({
7
8
  meta: { name: '@ziyarago/ui', configKey: 'ziyarago', compatibility: { nuxt: '>=3.0.0' } },
8
- defaults: { css: true, prefix: 'Ui', theme: { theme: 'dark', palette: 'gold', dir: 'ltr', bg: 'none', locale: 'en' } },
9
+ defaults: { css: true, plugins: [], prefix: 'Ui', theme: { theme: 'dark', palette: 'gold', dir: 'ltr', bg: 'none', locale: 'en' } },
9
10
  setup(opts, nuxt) {
10
11
  const { resolve } = createResolver(import.meta.url);
11
12
  if (opts.css) nuxt.options.css.push('@ziyarago/ui/style.css');
@@ -13,6 +14,13 @@ export default defineNuxtModule({
13
14
  for (const name of Object.keys(components)) {
14
15
  addComponent({ name: opts.prefix + name, export: opts.prefix + name, filePath: '@ziyarago/ui/vue' });
15
16
  }
17
+ for (const pkg of opts.plugins) {
18
+ nuxt.options.build.transpile.push(pkg);
19
+ let names = [];
20
+ try { names = createRequire(import.meta.url)(pkg + '/names'); } catch { try { names = createRequire(nuxt.options.rootDir + '/')(pkg + '/names'); } catch { console.warn(`[@ziyarago/ui] plugin ${pkg}: cannot load ${pkg}/names`); } }
21
+ for (const name of names) addComponent({ name: opts.prefix + name, export: 'Ui' + name, filePath: pkg + '/vue' });
22
+ if (opts.css) nuxt.options.css.push(pkg + '/style.css');
23
+ }
16
24
  addImports([
17
25
  { name: 'useUiTheme', from: '@ziyarago/ui/theme' },
18
26
  { name: 'fmt', from: '@ziyarago/ui/vue' },