@ziyarago/ui 0.2.0 → 0.4.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 (120) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +24 -2
  3. package/dist/llms-full.txt +101 -9
  4. package/dist/llms.txt +2 -2
  5. package/dist/manifest.json +412 -20
  6. package/dist/style.css +73 -4
  7. package/docs/INTEGRATION.md +153 -0
  8. package/docs/MIGRATION.md +453 -0
  9. package/package.json +88 -8
  10. package/src/compat/index.js +468 -0
  11. package/src/compat/map.js +282 -0
  12. package/src/compat/resolver.js +22 -0
  13. package/src/compat/vite.js +29 -0
  14. package/src/core/bools.js +4 -0
  15. package/src/core/components.js +40 -31
  16. package/src/core/components2.js +52 -47
  17. package/src/core/components3.js +8 -7
  18. package/src/core/components4.js +25 -24
  19. package/src/core/components6.js +30 -20
  20. package/src/core/components7.js +10 -9
  21. package/src/core/index.js +2 -0
  22. package/src/i18n/components/ActionCard.js +5 -0
  23. package/src/i18n/components/Actionsheet.js +5 -0
  24. package/src/i18n/components/Alert.js +5 -0
  25. package/src/i18n/components/Breadcrumbs.js +5 -0
  26. package/src/i18n/components/Calendar.js +5 -0
  27. package/src/i18n/components/CallCard.js +5 -0
  28. package/src/i18n/components/CallRow.js +5 -0
  29. package/src/i18n/components/Carousel.js +5 -0
  30. package/src/i18n/components/ChartCard.js +5 -0
  31. package/src/i18n/components/ChatAi.js +5 -0
  32. package/src/i18n/components/Chip.js +5 -0
  33. package/src/i18n/components/ChipInput.js +5 -0
  34. package/src/i18n/components/CodeInput.js +5 -0
  35. package/src/i18n/components/Combobox.js +5 -0
  36. package/src/i18n/components/CommandPalette.js +5 -0
  37. package/src/i18n/components/ConfirmDialog.js +5 -0
  38. package/src/i18n/components/ContactPanel.js +5 -0
  39. package/src/i18n/components/CopyButton.js +5 -0
  40. package/src/i18n/components/DataGroup.js +5 -0
  41. package/src/i18n/components/DataState.js +5 -0
  42. package/src/i18n/components/DataTable.js +5 -0
  43. package/src/i18n/components/DatePicker.js +5 -0
  44. package/src/i18n/components/DealCard.js +5 -0
  45. package/src/i18n/components/Drawer.js +5 -0
  46. package/src/i18n/components/ErrorPage.js +5 -0
  47. package/src/i18n/components/FileUpload.js +5 -0
  48. package/src/i18n/components/FullscreenDialog.js +5 -0
  49. package/src/i18n/components/Gallery.js +5 -0
  50. package/src/i18n/components/GuestCard.js +5 -0
  51. package/src/i18n/components/ImageUpload.js +5 -0
  52. package/src/i18n/components/ImageViewer.js +5 -0
  53. package/src/i18n/components/IncomingCall.js +5 -0
  54. package/src/i18n/components/InlineEdit.js +5 -0
  55. package/src/i18n/components/IntegrationCard.js +5 -0
  56. package/src/i18n/components/LoginForm.js +5 -0
  57. package/src/i18n/components/Map.js +5 -0
  58. package/src/i18n/components/Modal.js +5 -0
  59. package/src/i18n/components/MultiSelect.js +5 -0
  60. package/src/i18n/components/NotificationBell.js +5 -0
  61. package/src/i18n/components/NumberInput.js +5 -0
  62. package/src/i18n/components/Pagination.js +5 -0
  63. package/src/i18n/components/PasswordInput.js +5 -0
  64. package/src/i18n/components/Popconfirm.js +5 -0
  65. package/src/i18n/components/PricingCard.js +5 -0
  66. package/src/i18n/components/RamadanTracker.js +5 -0
  67. package/src/i18n/components/RangeCalendar.js +5 -0
  68. package/src/i18n/components/RangeSlider.js +5 -0
  69. package/src/i18n/components/Rating.js +5 -0
  70. package/src/i18n/components/RichEditor.js +5 -0
  71. package/src/i18n/components/Screensaver.js +5 -0
  72. package/src/i18n/components/SearchInput.js +5 -0
  73. package/src/i18n/components/SideNav.js +5 -0
  74. package/src/i18n/components/Snackbar.js +5 -0
  75. package/src/i18n/components/Sortable.js +5 -0
  76. package/src/i18n/components/Spinner.js +5 -0
  77. package/src/i18n/components/StatusPage.js +5 -0
  78. package/src/i18n/components/StepDialog.js +5 -0
  79. package/src/i18n/components/StepForm.js +5 -0
  80. package/src/i18n/components/TabTiles.js +5 -0
  81. package/src/i18n/components/Tag.js +5 -0
  82. package/src/i18n/components/TopNav.js +5 -0
  83. package/src/i18n/components/Tour.js +5 -0
  84. package/src/i18n/components/TourCard.js +5 -0
  85. package/src/i18n/components/TourPopover.js +5 -0
  86. package/src/i18n/components/TreeSelect.js +5 -0
  87. package/src/i18n/components/Validation.js +5 -0
  88. package/src/i18n/components/index.js +135 -0
  89. package/src/i18n/index.js +50 -0
  90. package/src/meta/actions.js +10 -3
  91. package/src/meta/data.js +8 -3
  92. package/src/meta/feedback.js +2 -1
  93. package/src/meta/forms.js +44 -4
  94. package/src/meta/media.js +7 -2
  95. package/src/meta/navigation.js +3 -0
  96. package/src/meta/overlay.js +8 -2
  97. package/src/nuxt/module.mjs +2 -2
  98. package/src/nuxt/plugin.mjs +6 -5
  99. package/src/react/index.js +202 -8
  100. package/src/resolver.js +33 -0
  101. package/src/styles/components.css +7 -0
  102. package/src/styles/components6.css +2 -0
  103. package/src/styles/effects.css +6 -4
  104. package/src/styles/extras.css +55 -0
  105. package/src/styles/index.css +1 -0
  106. package/src/theme.js +16 -4
  107. package/src/vue/global.js +2 -0
  108. package/src/vue/index.js +13 -5
  109. package/types/compat-resolver.d.ts +12 -0
  110. package/types/compat-vite.d.ts +11 -0
  111. package/types/compat.d.ts +176 -0
  112. package/types/i18n.d.ts +14 -0
  113. package/types/meta.d.ts +4 -0
  114. package/types/nuxt.d.ts +1 -1
  115. package/types/react.d.ts +6282 -186
  116. package/types/resolver.d.ts +14 -0
  117. package/types/shared.d.ts +7 -7
  118. package/types/theme.d.ts +20 -1
  119. package/types/vue-global.d.ts +193 -0
  120. package/types/vue.d.ts +6178 -186
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { add: 'Add' },
3
+ ar: { add: 'إضافة' },
4
+ ru: { add: 'Добавить' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { remove: 'Remove' },
3
+ ar: { remove: 'إزالة' },
4
+ ru: { remove: 'Удалить' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { label: 'Main' },
3
+ ar: { label: 'الرئيسية' },
4
+ ru: { label: 'Основная' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { label: 'Tour' },
3
+ ar: { label: 'جولة تعريفية' },
4
+ ru: { label: 'Тур' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { seats: 'Seats' },
3
+ ar: { seats: 'المقاعد' },
4
+ ru: { seats: 'Места' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { close: 'Close', back: 'Back', next: 'Next', finish: 'Finish' },
3
+ ar: { close: 'إغلاق', back: 'رجوع', next: 'التالي', finish: 'إنهاء' },
4
+ ru: { close: 'Закрыть', back: 'Назад', next: 'Следующий', finish: 'Готово' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { search: 'Search' },
3
+ ar: { search: 'بحث' },
4
+ ru: { search: 'Поиск' },
5
+ };
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { required: 'This field is required', email: 'Enter a valid email', url: 'Enter a valid URL', digits: 'Exactly {n} digits', alpha: 'Letters only', alphaDash: 'Letters, digits, dash and underscore', minLength: 'At least {n} characters', maxLength: 'At most {n} characters', range: 'Between {a} and {b}', invalid: 'Invalid format', confirmed: 'Values do not match', password: '8+ characters, a digit and a capital letter' },
3
+ ar: { required: 'هذا الحقل مطلوب', email: 'أدخل بريدًا إلكترونيًا صالحًا', url: 'أدخل رابطًا صالحًا', digits: '{n} أرقام بالضبط', alpha: 'أحرف فقط', alphaDash: 'أحرف وأرقام وشرطة وشرطة سفلية', minLength: '{n} أحرف على الأقل', maxLength: '{n} أحرف كحد أقصى', range: 'بين {a} و {b}', invalid: 'تنسيق غير صالح', confirmed: 'القيمتان غير متطابقتين', password: '8 أحرف أو أكثر ورقم وحرف كبير' },
4
+ ru: { required: 'Обязательное поле', email: 'Введите корректный email', url: 'Введите корректный URL', digits: 'Ровно {n} цифр', alpha: 'Только буквы', alphaDash: 'Буквы, цифры, дефис и подчёркивание', minLength: 'Не менее {n} символов', maxLength: 'Не более {n} символов', range: 'От {a} до {b}', invalid: 'Неверный формат', confirmed: 'Значения не совпадают', password: '8+ символов, цифра и заглавная буква' },
5
+ };
@@ -0,0 +1,135 @@
1
+ // generated by scripts/i18n-index.mjs: do not edit
2
+ import { defineMessages } from '../index.js';
3
+ import ActionCard from './ActionCard.js';
4
+ import Actionsheet from './Actionsheet.js';
5
+ import Alert from './Alert.js';
6
+ import Breadcrumbs from './Breadcrumbs.js';
7
+ 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
+ import Chip from './Chip.js';
14
+ import ChipInput from './ChipInput.js';
15
+ import CodeInput from './CodeInput.js';
16
+ import Combobox from './Combobox.js';
17
+ import CommandPalette from './CommandPalette.js';
18
+ import ConfirmDialog from './ConfirmDialog.js';
19
+ import ContactPanel from './ContactPanel.js';
20
+ import CopyButton from './CopyButton.js';
21
+ import DataGroup from './DataGroup.js';
22
+ import DataState from './DataState.js';
23
+ import DataTable from './DataTable.js';
24
+ import DatePicker from './DatePicker.js';
25
+ import DealCard from './DealCard.js';
26
+ import Drawer from './Drawer.js';
27
+ import ErrorPage from './ErrorPage.js';
28
+ 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
+ import LoginForm from './LoginForm.js';
38
+ import Map from './Map.js';
39
+ import Modal from './Modal.js';
40
+ import MultiSelect from './MultiSelect.js';
41
+ import NotificationBell from './NotificationBell.js';
42
+ import NumberInput from './NumberInput.js';
43
+ import Pagination from './Pagination.js';
44
+ import PasswordInput from './PasswordInput.js';
45
+ import Popconfirm from './Popconfirm.js';
46
+ import PricingCard from './PricingCard.js';
47
+ import RamadanTracker from './RamadanTracker.js';
48
+ import RangeCalendar from './RangeCalendar.js';
49
+ import RangeSlider from './RangeSlider.js';
50
+ import Rating from './Rating.js';
51
+ import RichEditor from './RichEditor.js';
52
+ import Screensaver from './Screensaver.js';
53
+ import SearchInput from './SearchInput.js';
54
+ import SideNav from './SideNav.js';
55
+ import Snackbar from './Snackbar.js';
56
+ import Sortable from './Sortable.js';
57
+ import Spinner from './Spinner.js';
58
+ import StatusPage from './StatusPage.js';
59
+ import StepDialog from './StepDialog.js';
60
+ import StepForm from './StepForm.js';
61
+ import TabTiles from './TabTiles.js';
62
+ import Tag from './Tag.js';
63
+ import TopNav from './TopNav.js';
64
+ import Tour from './Tour.js';
65
+ import TourCard from './TourCard.js';
66
+ import TourPopover from './TourPopover.js';
67
+ import TreeSelect from './TreeSelect.js';
68
+ import Validation from './Validation.js';
69
+
70
+ defineMessages('ActionCard', ActionCard);
71
+ defineMessages('Actionsheet', Actionsheet);
72
+ defineMessages('Alert', Alert);
73
+ defineMessages('Breadcrumbs', Breadcrumbs);
74
+ defineMessages('Calendar', Calendar);
75
+ defineMessages('CallCard', CallCard);
76
+ defineMessages('CallRow', CallRow);
77
+ defineMessages('Carousel', Carousel);
78
+ defineMessages('ChartCard', ChartCard);
79
+ defineMessages('ChatAi', ChatAi);
80
+ defineMessages('Chip', Chip);
81
+ defineMessages('ChipInput', ChipInput);
82
+ defineMessages('CodeInput', CodeInput);
83
+ defineMessages('Combobox', Combobox);
84
+ defineMessages('CommandPalette', CommandPalette);
85
+ defineMessages('ConfirmDialog', ConfirmDialog);
86
+ defineMessages('ContactPanel', ContactPanel);
87
+ defineMessages('CopyButton', CopyButton);
88
+ defineMessages('DataGroup', DataGroup);
89
+ defineMessages('DataState', DataState);
90
+ defineMessages('DataTable', DataTable);
91
+ defineMessages('DatePicker', DatePicker);
92
+ defineMessages('DealCard', DealCard);
93
+ defineMessages('Drawer', Drawer);
94
+ defineMessages('ErrorPage', ErrorPage);
95
+ defineMessages('FileUpload', FileUpload);
96
+ defineMessages('FullscreenDialog', FullscreenDialog);
97
+ defineMessages('Gallery', Gallery);
98
+ defineMessages('GuestCard', GuestCard);
99
+ defineMessages('ImageUpload', ImageUpload);
100
+ defineMessages('ImageViewer', ImageViewer);
101
+ defineMessages('IncomingCall', IncomingCall);
102
+ defineMessages('InlineEdit', InlineEdit);
103
+ defineMessages('IntegrationCard', IntegrationCard);
104
+ defineMessages('LoginForm', LoginForm);
105
+ defineMessages('Map', Map);
106
+ defineMessages('Modal', Modal);
107
+ defineMessages('MultiSelect', MultiSelect);
108
+ defineMessages('NotificationBell', NotificationBell);
109
+ defineMessages('NumberInput', NumberInput);
110
+ defineMessages('Pagination', Pagination);
111
+ defineMessages('PasswordInput', PasswordInput);
112
+ defineMessages('Popconfirm', Popconfirm);
113
+ defineMessages('PricingCard', PricingCard);
114
+ defineMessages('RamadanTracker', RamadanTracker);
115
+ defineMessages('RangeCalendar', RangeCalendar);
116
+ defineMessages('RangeSlider', RangeSlider);
117
+ defineMessages('Rating', Rating);
118
+ defineMessages('RichEditor', RichEditor);
119
+ defineMessages('Screensaver', Screensaver);
120
+ defineMessages('SearchInput', SearchInput);
121
+ defineMessages('SideNav', SideNav);
122
+ defineMessages('Snackbar', Snackbar);
123
+ defineMessages('Sortable', Sortable);
124
+ defineMessages('Spinner', Spinner);
125
+ defineMessages('StatusPage', StatusPage);
126
+ defineMessages('StepDialog', StepDialog);
127
+ defineMessages('StepForm', StepForm);
128
+ defineMessages('TabTiles', TabTiles);
129
+ defineMessages('Tag', Tag);
130
+ defineMessages('TopNav', TopNav);
131
+ defineMessages('Tour', Tour);
132
+ defineMessages('TourCard', TourCard);
133
+ defineMessages('TourPopover', TourPopover);
134
+ defineMessages('TreeSelect', TreeSelect);
135
+ defineMessages('Validation', Validation);
@@ -0,0 +1,50 @@
1
+ // Built-in component strings. One file per component in ./components/<Name>.js with all locales:
2
+ // export default { en: { copy: 'Copy' } } (the open source package ships en, ar, ru; the other 13 languages come from the Pro language pack
3
+ // that calls defineMessages(component, { uz: {...} }) or from the app via setUiMessages). A locale without strings falls back to English.
4
+ // The kit has its own translator: it never depends on the host app's i18n library. Sync it with yours:
5
+ // watch(() => i18n.locale.value, l => setUiLocale(l)) // vue-i18n
6
+ // setUiMessages('ru', { CopyButton: { copy: 'Скопировать' } }) // override single strings from the app
7
+ export const LOCALES = ['en', 'ar', 'ru', 'uz', 'tg', 'tr', 'fr', 'fa', 'hi', 'ur', 'bn', 'id', 'kk', 'ky', 'ms', 'ha'];
8
+ /** Languages whose strings ship in the free package. The rest come from the Pro language pack. */
9
+ export const FREE_LOCALES = ['en', 'ar', 'ru'];
10
+ export const RTL_LOCALES = ['ar', 'fa', 'ur'];
11
+
12
+ const registry = {};
13
+ const overrides = {};
14
+ const subs = new Set();
15
+ let locale = 'en';
16
+ let version = 0;
17
+
18
+ const norm = l => { const k = String(l || 'en').toLowerCase().split(/[-_]/)[0]; return LOCALES.includes(k) ? k : 'en'; };
19
+ const bump = () => { version++; subs.forEach(f => f(locale)); };
20
+
21
+ /** Register strings of a component. Calling it again for the same component MERGES locales: a language pack can add locales on top of the built-in ones. */
22
+ export function defineMessages(component, messages) {
23
+ const cur = registry[component] || (registry[component] = {});
24
+ for (const [l, msgs] of Object.entries(messages)) cur[l] = { ...(cur[l] || {}), ...msgs };
25
+ return registry[component];
26
+ }
27
+ export function getUiLocale() { return locale; }
28
+ export function isRtlLocale(l = locale) { return RTL_LOCALES.includes(norm(l)); }
29
+ export function setUiLocale(l) { const n = norm(l); if (n === locale) return; locale = n; bump(); }
30
+ /** Override single strings: setUiMessages('ru', { Pagination: { prev: 'Назад' } }). Call again to change; pass null to clear a locale. */
31
+ export function setUiMessages(l, partial) {
32
+ const k = norm(l);
33
+ if (partial === null) delete overrides[k];
34
+ else for (const [c, msgs] of Object.entries(partial || {})) overrides[k] = { ...(overrides[k] || {}), [c]: { ...(overrides[k]?.[c] || {}), ...msgs } };
35
+ bump();
36
+ }
37
+ export function subscribeUiLocale(fn) { subs.add(fn); return () => subs.delete(fn); }
38
+ export function getUiVersion() { return version; }
39
+
40
+ const fill = (s, p) => (p ? s.replace(/\{(\w+)\}/g, (m, k) => (k in p ? String(p[k]) : m)) : s);
41
+
42
+ /** Translate a component string. Order: app overrides, component file in the current locale, app overrides in English, component file in English, the key. */
43
+ export function t(component, key, params) {
44
+ const hit = overrides[locale]?.[component]?.[key] ?? registry[component]?.[locale]?.[key]
45
+ ?? overrides.en?.[component]?.[key] ?? registry[component]?.en?.[key] ?? key;
46
+ return fill(hit, params);
47
+ }
48
+
49
+ /** Locale-aware helper for numbers and dates in components (uses the browser/Node Intl). */
50
+ export const intlLocale = () => ({ en: 'en-US', ar: 'ar', ru: 'ru-RU', uz: 'uz-UZ', tg: 'tg-TJ', tr: 'tr-TR', fr: 'fr-FR', fa: 'fa-IR', hi: 'hi-IN', ur: 'ur-PK', bn: 'bn-BD', id: 'id-ID', kk: 'kk-KZ', ky: 'ky-KG', ms: 'ms-MY', ha: 'ha-NG' })[locale];
@@ -17,10 +17,13 @@ export default {
17
17
  loading: { type: 'boolean', default: false, description: 'Shows a spinner instead of the icon and disables the button.' },
18
18
  disabled: { type: 'boolean', default: false, description: 'Blocks interaction and dims the button.' },
19
19
  block: { type: 'boolean', default: false, description: 'Stretches the button to the full width of its container.' },
20
+ type: { type: "'button' | 'submit' | 'reset'", values: ['button', 'submit', 'reset'], default: 'button', description: 'Native button type. Use submit inside a form.' },
21
+ iconOnly: { type: 'boolean', default: false, description: 'Square button (width equals height) with no horizontal padding, for a lone icon. Pass an aria-label.' },
22
+ title: { type: 'string', description: 'Native tooltip text.' },
20
23
  },
21
24
  events: { click: 'Native click event. Not fired while disabled or loading.' },
22
25
  slots: { default: 'Button label.' },
23
- notes: ['Always renders type="button", so it never submits a form by itself.'],
26
+ notes: ['Renders type="button" unless type is set, so it never submits a form by itself.'],
24
27
  },
25
28
  IconButton: {
26
29
  description: 'Square button with only an icon; use for toolbars and compact actions.',
@@ -80,9 +83,12 @@ export default {
80
83
  SegmentedControl: {
81
84
  description: 'Segmented switch for choosing exactly one of a few options.',
82
85
  props: {
83
- items: { type: '{ value: string; label: string }[]', default: '[]', required: true, description: 'Segments to render.' },
86
+ items: { type: '{ value: string; label: string; icon?: string; disabled?: boolean }[]', default: '[]', required: true, description: 'Segments to render. icon is an icon name; disabled: true dims one segment.' },
84
87
  modelValue: { type: 'string', model: true, description: 'Value of the selected segment.' },
85
88
  size: sizeProp('md', 'Control size. sm and md also have a dedicated compact style.'),
89
+ block: { type: 'boolean', default: false, description: 'Stretches the control to the container width with equal-width segments.' },
90
+ iconOnly: { type: 'boolean', default: false, description: 'Hides labels of segments that have an icon; the label stays as tooltip and aria-label.' },
91
+ ariaLabel: { type: 'string', description: 'Accessible name of the group.' },
86
92
  },
87
93
  events: { change: 'Called with the value of the clicked segment.' },
88
94
  },
@@ -119,8 +125,9 @@ export default {
119
125
  Badge: {
120
126
  description: 'Status badge with a colored tone and optional dot.',
121
127
  props: {
122
- tone: { type: "'brand' | 'success' | 'warning' | 'danger' | 'info'", values: ['brand', 'success', 'warning', 'danger', 'info'], description: 'Color. Omit for the neutral style.' },
128
+ tone: { type: "'brand' | 'success' | 'warning' | 'danger' | 'info' | 'inverse'", values: ['brand', 'success', 'warning', 'danger', 'info', 'inverse'], description: 'Color. inverse is a solid high-contrast badge (dark on light themes, light on dark). Omit for the neutral style.' },
123
129
  dot: { type: 'boolean', default: false, description: 'Shows a status dot before the content.' },
130
+ shape: { type: "'pill' | 'square'", values: ['pill', 'square'], default: 'pill', description: 'square uses small rounded corners instead of a full pill.' },
124
131
  size: sizeProp('md', 'Badge height: xs 18px, sm 20px, md 24px, lg 28px, xl 32px.'),
125
132
  },
126
133
  slots: { default: 'Badge content.' },
package/src/meta/data.js CHANGED
@@ -12,19 +12,22 @@ export default {
12
12
  props: {
13
13
  title: { type: 'string', description: 'Header title. The header renders only when title or the actions slot is set.' },
14
14
  subtitle: { type: 'string', description: 'Muted line under the title.' },
15
- variant: { type: "'inverse' | 'gradient'", values: ['inverse', 'gradient'], description: 'inverse is a dark card regardless of the page theme; gradient is a tinted gradient card colored by tone. Omit for the default glass card.' },
15
+ variant: { type: "'inverse' | 'gradient' | 'outline'", values: ['inverse', 'gradient', 'outline'], description: 'inverse is a dark card regardless of the page theme; gradient is a tinted gradient card colored by tone; outline is transparent with a border. Omit for the default glass card.' },
16
16
  tone: { type: "'brand' | 'sky' | 'success' | 'warning' | 'danger' | 'neutral' | 'rose' | 'violet'", values: ['brand', 'sky', 'success', 'warning', 'danger', 'neutral', 'rose', 'violet'], default: 'brand', description: 'Gradient color. Used only with variant="gradient".' },
17
17
  intensity: { type: "'vivid'", values: ['vivid'], description: 'With variant="gradient", fills the card with a saturated color instead of a soft tint.' },
18
+ padding: { type: "'none'", values: ['none'], description: 'none removes the inner padding (for full-bleed tables or images). Other paddings come from size.' },
19
+ interactive: { type: 'boolean', default: false, description: 'Adds a pointer cursor and hover lift. With a click handler the card also becomes keyboard focusable (Enter activates).' },
18
20
  size: size('md', 'Padding, gap and title size.'),
19
21
  },
20
- slots: { default: 'Card body.', actions: 'Right side of the header, for buttons or menus.' },
22
+ slots: { default: 'Card body.', actions: 'Right side of the header, for buttons or menus.', header: 'Replaces the whole title/actions header with custom content.', footer: 'Row under the body, for buttons or meta.' },
23
+ events: { click: 'Native click on the card. Combine with interactive.' },
21
24
  notes: ['Vue slot names are React props (actions) and children (default).'],
22
25
  },
23
26
 
24
27
  DataTable: {
25
28
  description: 'Table with sortable columns, custom cell rendering and optional row selection checkboxes.',
26
29
  props: {
27
- columns: { type: '{ key: string; label: string; sortable?: boolean; num?: boolean; render?: (value, row, h) => VNode | string }[]', required: true, default: [], description: 'Column definitions. key reads row[key]; num right-aligns numbers; render customizes the cell; sortable shows a sort button in the header.' },
30
+ columns: { type: '{ key: string; label: string; sortable?: boolean; num?: boolean; align?: "left" | "center" | "right"; width?: string; render?: (value, row, h) => VNode | string }[]', required: true, default: [], description: 'Column definitions. key reads row[key]; num right-aligns numbers; render customizes the cell; sortable shows a sort button in the header.' },
28
31
  rows: { type: '({ id: string | number; [key: string]: any })[]', required: true, default: [], description: 'Row objects. Every row needs a unique id; missing cell values render as an em dash.' },
29
32
  selected: { type: '(string | number)[]', default: [], description: 'Ids of selected rows. Checkboxes show only when the select event is handled.' },
30
33
  sortKey: { type: 'string', description: 'Key of the column currently sorted. The component does not sort rows itself.' },
@@ -33,7 +36,9 @@ export default {
33
36
  labels: { type: '{ selectAll?: string; selectRow?: string }', default: "{ selectAll: 'Select all', selectRow: 'Select row' }", description: 'Accessible names of the selection checkboxes.' },
34
37
  size: size('md', 'Row density and font size.'),
35
38
  },
39
+ slots: { empty: 'Replaces the empty text with custom content when rows is empty.' },
36
40
  events: {
41
+ rowClick: 'Called with (row, index) when a body row is clicked. Rows get a pointer cursor.',
37
42
  select: 'Called with the new array of selected row ids. Handling it enables the checkbox column and select-all.',
38
43
  sort: 'Called with (key, dir) where dir is "asc" or "desc". Sort the rows yourself and pass sortKey/sortDir back.',
39
44
  },
@@ -16,8 +16,9 @@ export default {
16
16
  props: {
17
17
  ...alertProps,
18
18
  banner: { type: 'boolean', default: false, description: 'Removes the border radius so the alert spans the full width like a Banner.' },
19
+ hideIcon: { type: 'boolean', default: false, description: 'Hides the leading tone icon (the icon slot is hidden too).' },
19
20
  },
20
- slots: { default: 'Message text.' },
21
+ slots: { default: 'Message text.', title: 'Replaces the title prop with custom content.', icon: 'Replaces the tone icon inside the icon tile.', actions: 'Row under the message for buttons or links.' },
21
22
  events: { close: 'Called when the close button is clicked. The button is rendered only when this handler is set.' },
22
23
  notes: ['Has role="alert", so screen readers announce it when it appears.', 'Not self-dismissing: hide it yourself in the close handler.'],
23
24
  },
package/src/meta/forms.js CHANGED
@@ -23,10 +23,24 @@ export default {
23
23
  density: { type: "'compact' | 'default'", values: ['compact', 'default'], default: 'default', description: 'compact uses the small control height.' },
24
24
  disabled,
25
25
  readonly: { type: 'boolean', default: false, description: 'Makes the input read-only.' },
26
+ required: { type: 'boolean', default: false, description: 'Adds a red asterisk to the label and the native required attribute (browser validation inside a form).' },
27
+ name: { type: 'string', forwarded: true, description: 'Native name attribute of the input.' },
28
+ autocomplete: { type: 'string', forwarded: true, description: 'Native autocomplete hint, for example "email" or "new-password".' },
29
+ min: { type: 'number | string', forwarded: true, description: 'Native min for number, date and time types.' },
30
+ max: { type: 'number | string', forwarded: true, description: 'Native max for number, date and time types.' },
31
+ step: { type: 'number | string', forwarded: true, description: 'Native step for number, date and time types.' },
32
+ maxlength: { type: 'number', forwarded: true, description: 'Maximum number of characters.' },
33
+ minlength: { type: 'number', forwarded: true, description: 'Minimum number of characters (native validation).' },
34
+ inputmode: { type: 'string', forwarded: true, description: 'Virtual keyboard hint: numeric, decimal, tel, email, url, search or none.' },
35
+ pattern: { type: 'string', forwarded: true, description: 'Native validation pattern.' },
36
+ spellcheck: { type: 'boolean', forwarded: true, description: 'Enables or disables spell checking.' },
37
+ autofocus: { type: 'boolean', forwarded: true, description: 'Focuses the input on mount.' },
38
+ autocapitalize: { type: 'string', forwarded: true, description: 'Native autocapitalize hint.' },
26
39
  size: size(),
27
40
  },
28
- events: change('Called with the new string on every keystroke.'),
29
- notes: ['Wrapped in a label, so clicking the label focuses the input.'],
41
+ events: { ...change('Called with the new string on every keystroke.'), blur: 'Native blur of the input (Vue @blur, React onBlur).', focus: 'Native focus of the input.', keydown: 'Native keydown of the input; modifiers like @keydown.enter work in Vue.', input: 'Native input event (after change), receives the Event.' },
42
+ slots: { prefix: 'Content before the input (icon or text). Replaces the icon prop. React: prefix prop.', suffix: 'Content after the input (button, unit). Same as the suffix prop. React: suffix prop.' },
43
+ notes: ['Wrapped in a label, so clicking the label focuses the input.', 'Native attributes (name, autocomplete, min, max, step, maxlength, inputmode, pattern ...) and the blur, focus, keydown, keyup and paste listeners are forwarded to the inner input. id, class, style, aria-* and data-* land on the root label.'],
30
44
  },
31
45
  Textarea: {
32
46
  description: 'Multi-line text input. Use for comments, descriptions and other long text.',
@@ -35,9 +49,15 @@ export default {
35
49
  label, placeholder: placeholder(), hint, error, disabled,
36
50
  rows: { type: 'number', default: 4, description: 'Visible text rows.' },
37
51
  maxlength: { type: 'number', description: 'Maximum number of characters.' },
52
+ readonly: { type: 'boolean', default: false, description: 'Makes the textarea read-only.' },
53
+ required: { type: 'boolean', default: false, forwarded: true, description: 'Adds a red asterisk to the label and the native required attribute.' },
54
+ autoResize: { type: 'boolean', default: false, description: 'Grows with the content (CSS field-sizing: content, Chromium and Safari).' },
55
+ resize: { type: 'boolean', default: true, description: 'false removes the manual resize handle.' },
56
+ showCount: { type: 'boolean', default: false, description: 'Shows the character count under the field, as "n / maxlength" when maxlength is set.' },
57
+ name: { type: 'string', forwarded: true, description: 'Native name attribute.' },
38
58
  size: size(),
39
59
  },
40
- events: change('Called with the new string on every keystroke.'),
60
+ events: { ...change('Called with the new string on every keystroke.'), input: 'Native input event (after change), receives the Event.', blur: 'Native blur.', focus: 'Native focus.' },
41
61
  },
42
62
  NumberInput: {
43
63
  description: 'Numeric stepper with minus and plus buttons and a typed value. Use for quantities, guest counts and small integers.',
@@ -137,6 +157,9 @@ export default {
137
157
  modelValue: { type: 'string | number', model: true, description: 'Value of the selected option.' },
138
158
  options: { type: optShape, required: true, default: '[]', description: 'Available options. An option with disabled: true is dimmed and cannot be chosen.' },
139
159
  label, placeholder: placeholder('Shown when nothing is selected. Defaults to "—".'),
160
+ hint, error,
161
+ required: { type: 'boolean', default: false, description: 'Adds a red asterisk to the label. Does not validate.' },
162
+ name: { type: 'string', description: 'Renders a hidden input with this name and the selected value, so the control posts with a native form.' },
140
163
  disabled,
141
164
  size: size(),
142
165
  },
@@ -175,6 +198,8 @@ export default {
175
198
  label, hint, error,
176
199
  placeholder: placeholder('Defaults to "Search…".'),
177
200
  emptyText: { type: 'string', default: '—', description: 'Shown when no option matches the query.' },
201
+ clearable: { type: 'boolean', default: false, description: 'Shows a clear (x) button while a value is selected; it calls change with null.' },
202
+ filter: { type: '(option, query) => boolean', description: 'Custom matcher. Default is a case-insensitive substring match on label.' },
178
203
  disabled,
179
204
  size: size(),
180
205
  },
@@ -212,6 +237,9 @@ export default {
212
237
  props: {
213
238
  modelValue: { type: 'boolean', model: true, default: false, description: 'Checked state.' },
214
239
  label: { type: 'string', description: 'Text next to the box.' },
240
+ hint: { type: 'string', description: 'Second line under the label.' },
241
+ error: { type: 'string', description: 'Error message under the label (announced with role="alert"); a boolean or empty string shows nothing.' },
242
+ indeterminate: { type: 'boolean', default: false, description: 'Shows a dash instead of a check (aria-checked="mixed"). Clicking calls change with true.' },
215
243
  disabled,
216
244
  size: size('Box and label size.'),
217
245
  },
@@ -223,6 +251,9 @@ export default {
223
251
  props: {
224
252
  modelValue: { type: 'boolean', model: true, default: false, description: 'On state.' },
225
253
  label: { type: 'string', description: 'Text next to the toggle.' },
254
+ hint: { type: 'string', description: 'Second line under the label.' },
255
+ error: { type: 'string', description: 'Error message under the label (announced with role="alert").' },
256
+ labelLeft: { type: 'boolean', default: false, description: 'Places the label before the toggle instead of after it.' },
226
257
  disabled,
227
258
  size: size('Track and label size.'),
228
259
  },
@@ -234,7 +265,8 @@ export default {
234
265
  props: {
235
266
  modelValue: { type: 'string | number', model: true, description: 'Value of the selected option.' },
236
267
  options: { type: '{ value: string | number; label: string; hint?: string; disabled?: boolean }[]', default: '[]', description: 'Radio options. hint is a second line under the label; disabled: true disables that option only.' },
237
- label,
268
+ label, hint, error,
269
+ orientation: { type: "'vertical' | 'horizontal'", values: ['vertical', 'horizontal'], default: 'vertical', description: 'horizontal lays the options out in a wrapping row under the label.' },
238
270
  disabled,
239
271
  size: size(),
240
272
  },
@@ -321,6 +353,9 @@ export default {
321
353
  modelValue: { type: 'Date | string | number', model: true, description: 'Selected date: a Date, ISO string or timestamp. Also sets the visible month. A date-only string like "2026-10-21" is read as a local date, so the day does not shift with the time zone.' },
322
354
  locale: { type: 'string', default: 'en-GB', description: 'BCP 47 locale for month and weekday names.' },
323
355
  weekStartsOn: { type: 'number', default: 1, description: 'First day of the week: 0 = Sunday, 1 = Monday.' },
356
+ min: { type: 'Date | string | number', description: 'Earliest selectable day; earlier days are disabled.' },
357
+ max: { type: 'Date | string | number', description: 'Latest selectable day; later days are disabled.' },
358
+ disabledDate: { type: '(date: Date) => boolean', description: 'Return true to disable a specific day.' },
324
359
  events: { type: 'Record<string, string>', default: '{}', description: 'Marked days: keys are YYYY-MM-DD, values are the tooltip text.' },
325
360
  size: size('Day cell and header size.'),
326
361
  },
@@ -345,6 +380,11 @@ export default {
345
380
  modelValue: { type: 'string | Date | number', model: true, description: 'Selected date (ISO string recommended, e.g. 2026-10-21).' },
346
381
  locale: { type: 'string', default: 'en-GB', description: 'BCP 47 locale used for the trigger text and the calendar.' },
347
382
  weekStartsOn: { type: 'number', default: 1, description: 'First day of the week: 0 = Sunday, 1 = Monday.' },
383
+ clearable: { type: 'boolean', default: false, description: 'Shows a clear (x) button while a date is set; it calls change with null.' },
384
+ min: { type: 'Date | string | number', forwarded: true, description: 'Earliest selectable day, forwarded to the calendar.' },
385
+ max: { type: 'Date | string | number', forwarded: true, description: 'Latest selectable day, forwarded to the calendar.' },
386
+ disabledDate: { type: '(date: Date) => boolean', forwarded: true, description: 'Return true to disable a specific day, forwarded to the calendar.' },
387
+ required: { type: 'boolean', default: false, forwarded: true, description: 'Adds a red asterisk to the label. Does not validate.' },
348
388
  label, hint, error,
349
389
  placeholder: placeholder('Shown when no date is set. Defaults to "Select date".'),
350
390
  disabled,
package/src/meta/media.js CHANGED
@@ -9,6 +9,11 @@ export default {
9
9
  props: {
10
10
  name: { type: 'string', description: 'Full name. Shown as the tooltip and used for up to two initials; "?" when empty.' },
11
11
  src: { type: 'string', description: 'Image URL. Initials are shown without it.' },
12
+ initials: { type: 'string', description: 'Explicit initials (up to 3 characters, uppercased) instead of the ones derived from name.' },
13
+ tone: { type: "'brand' | 'sky' | 'success' | 'warning' | 'danger' | 'neutral'", values: ['brand', 'sky', 'success', 'warning', 'danger', 'neutral'], default: 'brand', description: 'Background color of the initials avatar.' },
14
+ shape: { type: "'circle' | 'rounded'", values: ['circle', 'rounded'], default: 'circle', description: 'rounded gives a squircle with a 30% corner radius.' },
15
+ ring: { type: 'boolean', default: false, description: 'Adds a background-colored ring so overlapping avatars stay separated.' },
16
+ status: { type: "'online' | 'offline' | 'away' | 'busy'", values: ['online', 'offline', 'away', 'busy'], description: 'Shows a presence dot in the bottom corner.' },
12
17
  size: { type: "'xs' | 'sm' | 'md' | 'lg' | 'xl' | number", values: SZ, default: 'md', description: 'Diameter: xs 24, sm 32, md 40, lg 56, xl 72 px. A number is used directly as px.' },
13
18
  },
14
19
  notes: ['Avatar sizes differ from other components (lg 56, xl 72), and a number gives any custom size.'],
@@ -74,8 +79,8 @@ export default {
74
79
  label: { type: 'string', default: 'Map', description: 'aria-label of the map region.' },
75
80
  labels: { type: '{ zoomIn?: string; zoomOut?: string }', default: "{ zoomIn: 'Zoom in', zoomOut: 'Zoom out' }", description: 'Accessible names of the zoom buttons.' },
76
81
  },
77
- events: { select: 'Called with the marker object when a marker is clicked.' },
78
- notes: ['The center and zoom props are initial values; user panning and zooming is kept in internal state.', 'Tiles come from a third-party CDN, so it needs network access.'],
82
+ events: { select: 'Called with the marker object when a marker is clicked.', move: 'Called with { lat, lon, zoom } while the user pans or zooms (drag, touch, wheel, double click or the +/- buttons).', zoom: 'Called with the new zoom level when it changes.' },
83
+ notes: ['The center and zoom props are initial values; user panning and zooming is kept in internal state. Listen to move/zoom to track it.','Drag or touch to pan, wheel or double click to zoom around the pointer. The tile theme follows the page data-theme after mount (light tiles on the server render) unless theme or style is set.', 'Tiles come from a third-party CDN, so it needs network access.'],
79
84
  },
80
85
 
81
86
  ProfileHeader: {
@@ -72,6 +72,7 @@ export default {
72
72
  props: {
73
73
  items: { type: '{ label: string; href?: string }[]', default: '[]', description: 'Trail from root to current. All but the last render as links (href defaults to "#"); the last is bold with aria-current="page".' },
74
74
  size: size('text and separator size'),
75
+ separator: { type: "'chevron' | 'slash' | 'dot'", values: ['chevron', 'slash', 'dot'], default: 'chevron', description: 'Glyph between items.' },
75
76
  },
76
77
  },
77
78
 
@@ -82,6 +83,8 @@ export default {
82
83
  pages: { type: 'number', default: 1, description: 'Total number of pages.' },
83
84
  siblings: { type: 'number', default: 1, description: 'Page buttons shown on each side of the current page. First and last page are always shown; gaps become an ellipsis.' },
84
85
  label: { type: 'string', default: 'Pagination', description: 'Accessible name of the navigation landmark.' },
86
+ hideArrows: { type: 'boolean', default: false, description: 'Hides the previous and next buttons.' },
87
+ labels: { type: '{ prev?: string; next?: string; page?: string }', default: "{ prev: 'Previous page', next: 'Next page', page: 'Page' }", description: 'Accessible names of the arrow buttons and of each page button ("Page 3").' },
85
88
  size: size('button size and text'),
86
89
  },
87
90
  events: { change: 'Called with the clicked page number (also from the previous and next buttons).' },
@@ -17,9 +17,14 @@ export default {
17
17
  props: {
18
18
  open: open('dialog'),
19
19
  title: { type: 'string', description: 'Header text and aria-label of the dialog.' },
20
+ subtitle: { type: 'string', description: 'Muted line under the title in the header.' },
21
+ closable: { type: 'boolean', default: true, description: 'false hides the close (x) button in the header.' },
22
+ closeOnBackdrop: { type: 'boolean', default: true, description: 'false ignores clicks on the scrim.' },
23
+ closeOnEsc: { type: 'boolean', default: true, description: 'false ignores the Escape key (focus trap stays active).' },
24
+ width: { type: 'string', description: 'CSS max-width of the dialog, for example "960px". Overrides the width of size.' },
20
25
  size: size('width (320 to 720 px max), padding and text'),
21
26
  },
22
- slots: { default: 'Dialog body.', footer: 'Footer area, usually action buttons. Rendered only when provided.' },
27
+ slots: { default: 'Dialog body.', footer: 'Footer area, usually action buttons. Rendered only when provided.', title: 'Replaces the title prop with custom header content.', subtitle: 'Replaces the subtitle prop.' },
23
28
  events: { close: 'Called on the close button, a click on the scrim or the Escape key. Set open to false in the handler.' },
24
29
  notes: ['Has role="dialog" and aria-modal. Escape calls close; on open focus moves into the dialog, Tab is trapped inside it and focus returns to the previously focused element on close.', 'Put data-autofocus on an element to choose which one receives initial focus (default: first focusable).', 'Closed state renders nothing, so inner state is lost on close.'],
25
30
  },
@@ -146,10 +151,11 @@ export default {
146
151
  description: 'Short text bubble shown on hover or focus of the wrapped element; use for icon-only controls and hints.',
147
152
  props: {
148
153
  text: { type: 'string', required: true, description: 'Tooltip text.' },
154
+ placement: { type: "'top' | 'bottom' | 'left' | 'right'", values: ['top', 'bottom', 'left', 'right'], default: 'top', description: 'Side of the wrapped element where the bubble appears.' },
149
155
  size: size('bubble padding and font'),
150
156
  },
151
157
  slots: { default: 'The element the tooltip is attached to.' },
152
- notes: ['Pure CSS bubble with fixed placement; it cannot contain markup. For rich content use HoverCard.'],
158
+ notes: ['Pure CSS bubble; it cannot contain markup. For rich content use HoverCard.'],
153
159
  },
154
160
 
155
161
  Dropdown: {
@@ -5,7 +5,7 @@ import { themeInitScript } from '../theme.js';
5
5
 
6
6
  export default defineNuxtModule({
7
7
  meta: { name: '@ziyarago/ui', configKey: 'ziyarago', compatibility: { nuxt: '>=3.0.0' } },
8
- defaults: { css: true, prefix: 'Ui', theme: { theme: 'dark', palette: 'gold', dir: 'ltr' } },
8
+ defaults: { css: true, prefix: 'Ui', theme: { theme: 'dark', palette: 'gold', dir: 'ltr', bg: 'none', locale: 'en' } },
9
9
  setup(opts, nuxt) {
10
10
  const { resolve } = createResolver(import.meta.url);
11
11
  if (opts.css) nuxt.options.css.push('@ziyarago/ui/style.css');
@@ -21,7 +21,7 @@ export default defineNuxtModule({
21
21
  if (opts.theme) {
22
22
  nuxt.options.runtimeConfig.public.ziyarago = opts.theme;
23
23
  const head = nuxt.options.app.head ||= {};
24
- head.htmlAttrs = { ...(head.htmlAttrs || {}), 'data-theme': opts.theme.theme, 'data-palette': opts.theme.palette, dir: opts.theme.dir };
24
+ head.htmlAttrs = { ...(head.htmlAttrs || {}), 'data-theme': opts.theme.theme, 'data-palette': opts.theme.palette, 'data-bg': opts.theme.bg || 'none', dir: opts.theme.dir };
25
25
  addPlugin(resolve('./plugin.mjs'));
26
26
  head.script = [...(head.script || []), { innerHTML: themeInitScript, tagPosition: 'head' }];
27
27
  }
@@ -1,9 +1,10 @@
1
1
  import { defineNuxtPlugin, useRuntimeConfig } from '#imports';
2
- import { useUiTheme } from '../theme.js';
2
+ import { applySavedLocale, configureTheme, useUiTheme } from '../theme.js';
3
+ import { setUiLocale } from '../i18n/index.js';
3
4
 
4
- export default defineNuxtPlugin(() => {
5
- const ui = useUiTheme();
5
+ export default defineNuxtPlugin(nuxtApp => {
6
6
  const d = useRuntimeConfig().public.ziyarago || {};
7
- const saved = (() => { try { return localStorage.getItem('zg-ui'); } catch { return null; } })();
8
- if (!saved) { ui.setTheme(d.theme || 'dark'); ui.setPalette(d.palette || 'gold'); ui.setDir(d.dir || 'ltr'); }
7
+ configureTheme({ theme: d.theme || 'dark', palette: d.palette || 'gold', dir: d.dir || 'ltr', bg: d.bg || 'none', locale: d.locale || 'en' });
8
+ useUiTheme();
9
+ nuxtApp.hook('app:mounted', () => { if (d.locale) setUiLocale(d.locale); applySavedLocale(); });
9
10
  });