@ziyarago/ui 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +1 -0
- package/dist/llms-full.txt +100 -8
- package/dist/llms.txt +1 -1
- package/dist/manifest.json +412 -20
- package/dist/style.css +73 -4
- package/docs/INTEGRATION.md +153 -0
- package/docs/MIGRATION.md +453 -0
- package/package.json +87 -7
- package/src/compat/index.js +468 -0
- package/src/compat/map.js +282 -0
- package/src/compat/resolver.js +22 -0
- package/src/compat/vite.js +29 -0
- package/src/core/bools.js +4 -0
- package/src/core/components.js +31 -23
- package/src/core/components2.js +20 -16
- package/src/core/components4.js +3 -3
- package/src/core/components6.js +25 -16
- package/src/core/index.js +2 -0
- package/src/i18n/components/CopyButton.js +3 -0
- package/src/i18n/components/index.js +5 -0
- package/src/i18n/index.js +48 -0
- package/src/meta/actions.js +10 -3
- package/src/meta/data.js +8 -3
- package/src/meta/feedback.js +2 -1
- package/src/meta/forms.js +44 -4
- package/src/meta/media.js +7 -2
- package/src/meta/navigation.js +3 -0
- package/src/meta/overlay.js +8 -2
- package/src/nuxt/module.mjs +2 -2
- package/src/nuxt/plugin.mjs +6 -5
- package/src/react/index.js +202 -8
- package/src/resolver.js +33 -0
- package/src/styles/components.css +7 -0
- package/src/styles/components6.css +2 -0
- package/src/styles/effects.css +6 -4
- package/src/styles/extras.css +55 -0
- package/src/styles/index.css +1 -0
- package/src/theme.js +16 -4
- package/src/vue/global.js +2 -0
- package/src/vue/index.js +13 -5
- package/types/compat-resolver.d.ts +12 -0
- package/types/compat-vite.d.ts +11 -0
- package/types/compat.d.ts +176 -0
- package/types/i18n.d.ts +12 -0
- package/types/meta.d.ts +4 -0
- package/types/nuxt.d.ts +1 -1
- package/types/react.d.ts +6282 -186
- package/types/resolver.d.ts +14 -0
- package/types/shared.d.ts +7 -7
- package/types/theme.d.ts +20 -1
- package/types/vue-global.d.ts +193 -0
- package/types/vue.d.ts +6178 -186
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: {
|
package/src/meta/navigation.js
CHANGED
|
@@ -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).' },
|
package/src/meta/overlay.js
CHANGED
|
@@ -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
|
|
158
|
+
notes: ['Pure CSS bubble; it cannot contain markup. For rich content use HoverCard.'],
|
|
153
159
|
},
|
|
154
160
|
|
|
155
161
|
Dropdown: {
|
package/src/nuxt/module.mjs
CHANGED
|
@@ -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
|
}
|
package/src/nuxt/plugin.mjs
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
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
|
});
|
package/src/react/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
// React 18+ adapter. Usage: import { UiButton, UiAppShell } from '@ziyarago/ui/react'
|
|
2
|
-
import React, { useState, createElement, cloneElement, isValidElement } from 'react';
|
|
3
|
+
import React, { useState, useRef, useEffect, useLayoutEffect, useSyncExternalStore, createElement, cloneElement, isValidElement } from 'react';
|
|
3
4
|
import { createPortal } from 'react-dom';
|
|
4
|
-
import { components } from '../core/index.js';
|
|
5
|
+
import { components, subscribeUiLocale, getUiVersion } from '../core/index.js';
|
|
5
6
|
|
|
6
7
|
const C = {};
|
|
7
|
-
const
|
|
8
|
+
const useIsoLayoutEffect = typeof document === 'undefined' ? useEffect : useLayoutEffect;
|
|
9
|
+
const EV = { keydown: 'KeyDown', keyup: 'KeyUp', dragenter: 'DragEnter', dragover: 'DragOver', dragleave: 'DragLeave', pointerdown: 'PointerDown', pointerup: 'PointerUp', pointermove: 'PointerMove', mousedown: 'MouseDown', mouseup: 'MouseUp', mouseenter: 'MouseEnter', mouseleave: 'MouseLeave', mousemove: 'MouseMove', mouseover: 'MouseOver', mouseout: 'MouseOut', dragstart: 'DragStart', dragend: 'DragEnd', dblclick: 'DoubleClick', contextmenu: 'ContextMenu', pointerenter: 'PointerEnter', pointerleave: 'PointerLeave', pointercancel: 'PointerCancel', touchstart: 'TouchStart', touchend: 'TouchEnd', touchmove: 'TouchMove', focusin: 'FocusIn', focusout: 'FocusOut' };
|
|
8
10
|
const hh = (t, p, ...k) => {
|
|
9
|
-
if (p && typeof t === 'string') { const q = {}; for (const key in p) { const m = /^on([
|
|
11
|
+
if (p && typeof t === 'string') { const q = {}; for (const key in p) { const m = /^on([A-Za-z]+)$/.exec(key), n = m && EV[m[1].toLowerCase()]; q[n ? 'on' + n : key] = p[key]; } p = q; }
|
|
10
12
|
if (p && 'class' in p) { const { class: cls, ...rest } = p; p = { ...rest, className: cls }; }
|
|
11
13
|
if (p) { const q = {}; for (const key in p) q[/^(aria|data)-/.test(key) || !key.includes('-') ? key : key.replace(/-(\w)/g, (_, c) => c.toUpperCase())] = p[key]; p = q; }
|
|
12
14
|
if (p && typeof p.innerHTML === 'string') { const { innerHTML, ...rest } = p; p = { ...rest, dangerouslySetInnerHTML: { __html: innerHTML }, suppressContentEditableWarning: true }; }
|
|
@@ -14,18 +16,210 @@ const hh = (t, p, ...k) => {
|
|
|
14
16
|
};
|
|
15
17
|
const wrap = (name, def) => {
|
|
16
18
|
const Comp = ({ children, ...props }) => {
|
|
19
|
+
useSyncExternalStore(subscribeUiLocale, getUiVersion, () => 0);
|
|
17
20
|
const [state, setState] = useState({ ...(def.state || {}) });
|
|
18
21
|
const set = o => setState(s => ({ ...s, ...o }));
|
|
22
|
+
// Portals must not render on the server pass or during hydration (React throws a hydration mismatch): the first render returns null
|
|
23
|
+
// and, only if portal() was asked for, a layout effect re-renders once mounted.
|
|
24
|
+
const mounted = useRef(false), wantPortal = useRef(false), [, bump] = useState(0);
|
|
25
|
+
useIsoLayoutEffect(() => { mounted.current = true; if (wantPortal.current) bump(n => n + 1); }, []);
|
|
19
26
|
const slots = {}; for (const k of [...(def.slots || []), 'actions', 'footer']) if (props[k] !== undefined) slots[k] = props[k];
|
|
20
27
|
if (props.onChange === undefined && props.onValueChange) props.onChange = props.onValueChange;
|
|
21
|
-
const out = def.render({ C, h: hh, props, children: React.Children.toArray(children), slots, state, set, portal: (kids, to) =>
|
|
22
|
-
|
|
28
|
+
const out = def.render({ C, h: hh, props, children: React.Children.toArray(children), slots, state, set, portal: (kids, to) => { if (!mounted.current) { wantPortal.current = true; return null; } return createPortal(kids, (typeof to === 'string' ? document.querySelector(to) : to) || document.body); } });
|
|
29
|
+
if (!isValidElement(out) || typeof out.type !== 'string') return out;
|
|
30
|
+
const root = {}; for (const k in props) if (/^(aria|data)-|^id$/.test(k)) root[k] = props[k];
|
|
31
|
+
if (props.size) root['data-size'] = props.size;
|
|
32
|
+
if (props.className) root.className = [out.props.className, props.className].filter(Boolean).join(' ');
|
|
33
|
+
if (props.style && typeof props.style === 'object') root.style = { ...out.props.style, ...props.style };
|
|
34
|
+
return Object.keys(root).length ? cloneElement(out, root) : out;
|
|
23
35
|
};
|
|
24
36
|
Comp.displayName = 'Ui' + name;
|
|
25
37
|
return Comp;
|
|
26
38
|
};
|
|
27
39
|
for (const [name, def] of Object.entries(components)) C[name] = wrap(name, def);
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
export
|
|
41
|
+
// Explicit named exports (not destructuring): Next.js reads the export names of a 'use client' module statically.
|
|
42
|
+
export const UiButton = C.Button;
|
|
43
|
+
export const UiIconButton = C.IconButton;
|
|
44
|
+
export const UiBadge = C.Badge;
|
|
45
|
+
export const UiAvatar = C.Avatar;
|
|
46
|
+
export const UiSwitch = C.Switch;
|
|
47
|
+
export const UiCheckbox = C.Checkbox;
|
|
48
|
+
export const UiSegmentedControl = C.SegmentedControl;
|
|
49
|
+
export const UiTabs = C.Tabs;
|
|
50
|
+
export const UiFilterChips = C.FilterChips;
|
|
51
|
+
export const UiTextField = C.TextField;
|
|
52
|
+
export const UiSelect = C.Select;
|
|
53
|
+
export const UiCodeInput = C.CodeInput;
|
|
54
|
+
export const UiStepper = C.Stepper;
|
|
55
|
+
export const UiCard = C.Card;
|
|
56
|
+
export const UiModal = C.Modal;
|
|
57
|
+
export const UiDrawer = C.Drawer;
|
|
58
|
+
export const UiToast = C.Toast;
|
|
59
|
+
export const UiBreadcrumbs = C.Breadcrumbs;
|
|
60
|
+
export const UiPagination = C.Pagination;
|
|
61
|
+
export const UiProgress = C.Progress;
|
|
62
|
+
export const UiRing = C.Ring;
|
|
63
|
+
export const UiKpiTile = C.KpiTile;
|
|
64
|
+
export const UiDataTable = C.DataTable;
|
|
65
|
+
export const UiKanbanColumn = C.KanbanColumn;
|
|
66
|
+
export const UiKanbanCard = C.KanbanCard;
|
|
67
|
+
export const UiTimeline = C.Timeline;
|
|
68
|
+
export const UiTopNav = C.TopNav;
|
|
69
|
+
export const UiSideNav = C.SideNav;
|
|
70
|
+
export const UiAppShell = C.AppShell;
|
|
71
|
+
export const UiPageHeader = C.PageHeader;
|
|
72
|
+
export const UiAuthLayout = C.AuthLayout;
|
|
73
|
+
export const UiLeadCard = C.LeadCard;
|
|
74
|
+
export const UiHotelCard = C.HotelCard;
|
|
75
|
+
export const UiTourCard = C.TourCard;
|
|
76
|
+
export const UiPrayerTimes = C.PrayerTimes;
|
|
77
|
+
export const UiRamadanTracker = C.RamadanTracker;
|
|
78
|
+
export const UiCallRow = C.CallRow;
|
|
79
|
+
export const UiAlert = C.Alert;
|
|
80
|
+
export const UiBanner = C.Banner;
|
|
81
|
+
export const UiAccordion = C.Accordion;
|
|
82
|
+
export const UiSkeleton = C.Skeleton;
|
|
83
|
+
export const UiSpinner = C.Spinner;
|
|
84
|
+
export const UiDivider = C.Divider;
|
|
85
|
+
export const UiEmptyState = C.EmptyState;
|
|
86
|
+
export const UiErrorPage = C.ErrorPage;
|
|
87
|
+
export const UiDataState = C.DataState;
|
|
88
|
+
export const UiLoadingOverlay = C.LoadingOverlay;
|
|
89
|
+
export const UiConfirmDialog = C.ConfirmDialog;
|
|
90
|
+
export const UiPopconfirm = C.Popconfirm;
|
|
91
|
+
export const UiCarousel = C.Carousel;
|
|
92
|
+
export const UiGallery = C.Gallery;
|
|
93
|
+
export const UiCode = C.Code;
|
|
94
|
+
export const UiPricingCard = C.PricingCard;
|
|
95
|
+
export const UiIntegrationCard = C.IntegrationCard;
|
|
96
|
+
export const UiIncomingCall = C.IncomingCall;
|
|
97
|
+
export const UiCallCard = C.CallCard;
|
|
98
|
+
export const UiDropdown = C.Dropdown;
|
|
99
|
+
export const UiMenu = C.Menu;
|
|
100
|
+
export const UiTooltip = C.Tooltip;
|
|
101
|
+
export const UiHoverCard = C.HoverCard;
|
|
102
|
+
export const UiPopover = C.Popover;
|
|
103
|
+
export const UiCopyButton = C.CopyButton;
|
|
104
|
+
export const UiCommandBar = C.CommandBar;
|
|
105
|
+
export const UiCommandPalette = C.CommandPalette;
|
|
106
|
+
export const UiNotificationBell = C.NotificationBell;
|
|
107
|
+
export const UiToggleGroup = C.ToggleGroup;
|
|
108
|
+
export const UiFab = C.Fab;
|
|
109
|
+
export const UiTextarea = C.Textarea;
|
|
110
|
+
export const UiNumberInput = C.NumberInput;
|
|
111
|
+
export const UiPasswordInput = C.PasswordInput;
|
|
112
|
+
export const UiSearchInput = C.SearchInput;
|
|
113
|
+
export const UiRadioGroup = C.RadioGroup;
|
|
114
|
+
export const UiSlider = C.Slider;
|
|
115
|
+
export const UiRating = C.Rating;
|
|
116
|
+
export const UiChipInput = C.ChipInput;
|
|
117
|
+
export const UiInlineEdit = C.InlineEdit;
|
|
118
|
+
export const UiColorPicker = C.ColorPicker;
|
|
119
|
+
export const UiFileUpload = C.FileUpload;
|
|
120
|
+
export const UiCombobox = C.Combobox;
|
|
121
|
+
export const UiMultiSelect = C.MultiSelect;
|
|
122
|
+
export const UiGroupedSelect = C.GroupedSelect;
|
|
123
|
+
export const UiPhoneInput = C.PhoneInput;
|
|
124
|
+
export const UiCalendar = C.Calendar;
|
|
125
|
+
export const UiDatePicker = C.DatePicker;
|
|
126
|
+
export const UiTimePicker = C.TimePicker;
|
|
127
|
+
export const UiFormField = C.FormField;
|
|
128
|
+
export const UiLoginForm = C.LoginForm;
|
|
129
|
+
export const UiStepForm = C.StepForm;
|
|
130
|
+
export const UiTag = C.Tag;
|
|
131
|
+
export const UiKbd = C.Kbd;
|
|
132
|
+
export const UiStatsCard = C.StatsCard;
|
|
133
|
+
export const UiKpiInline = C.KpiInline;
|
|
134
|
+
export const UiMiniChart = C.MiniChart;
|
|
135
|
+
export const UiDescriptions = C.Descriptions;
|
|
136
|
+
export const UiLazyImage = C.LazyImage;
|
|
137
|
+
export const UiSystemStatus = C.SystemStatus;
|
|
138
|
+
export const UiTreeView = C.TreeView;
|
|
139
|
+
export const UiCalendarView = C.CalendarView;
|
|
140
|
+
export const UiSubNav = C.SubNav;
|
|
141
|
+
export const UiActionRail = C.ActionRail;
|
|
142
|
+
export const UiSplitLayout = C.SplitLayout;
|
|
143
|
+
export const UiSettingsSection = C.SettingsSection;
|
|
144
|
+
export const UiScrollArea = C.ScrollArea;
|
|
145
|
+
export const UiDealCard = C.DealCard;
|
|
146
|
+
export const UiPipelineBoard = C.PipelineBoard;
|
|
147
|
+
export const UiContactPanel = C.ContactPanel;
|
|
148
|
+
export const UiSalesFunnel = C.SalesFunnel;
|
|
149
|
+
export const UiBookingCard = C.BookingCard;
|
|
150
|
+
export const UiGuestCard = C.GuestCard;
|
|
151
|
+
export const UiRoomGrid = C.RoomGrid;
|
|
152
|
+
export const UiRoomCalendar = C.RoomCalendar;
|
|
153
|
+
export const UiOccupancyChart = C.OccupancyChart;
|
|
154
|
+
export const UiChip = C.Chip;
|
|
155
|
+
export const UiIconTile = C.IconTile;
|
|
156
|
+
export const UiStatusIcon = C.StatusIcon;
|
|
157
|
+
export const UiUserCell = C.UserCell;
|
|
158
|
+
export const UiStatRow = C.StatRow;
|
|
159
|
+
export const UiCountryRow = C.CountryRow;
|
|
160
|
+
export const UiStatLine = C.StatLine;
|
|
161
|
+
export const UiStatStrip = C.StatStrip;
|
|
162
|
+
export const UiVersusBar = C.VersusBar;
|
|
163
|
+
export const UiSegBar = C.SegBar;
|
|
164
|
+
export const UiHeroBanner = C.HeroBanner;
|
|
165
|
+
export const UiTabTiles = C.TabTiles;
|
|
166
|
+
export const UiPillTabs = C.PillTabs;
|
|
167
|
+
export const UiPillSelect = C.PillSelect;
|
|
168
|
+
export const UiChartCard = C.ChartCard;
|
|
169
|
+
export const UiActionCard = C.ActionCard;
|
|
170
|
+
export const UiSnackbar = C.Snackbar;
|
|
171
|
+
export const UiTourPopover = C.TourPopover;
|
|
172
|
+
export const UiProfileHeader = C.ProfileHeader;
|
|
173
|
+
export const UiAuthSplit = C.AuthSplit;
|
|
174
|
+
export const UiStatusPage = C.StatusPage;
|
|
175
|
+
export const UiValidatedField = C.ValidatedField;
|
|
176
|
+
export const UiFooter = C.Footer;
|
|
177
|
+
export const UiDataGroup = C.DataGroup;
|
|
178
|
+
export const UiOptionCard = C.OptionCard;
|
|
179
|
+
export const UiOptionCards = C.OptionCards;
|
|
180
|
+
export const UiRichEditor = C.RichEditor;
|
|
181
|
+
export const UiRangeSlider = C.RangeSlider;
|
|
182
|
+
export const UiRangeCalendar = C.RangeCalendar;
|
|
183
|
+
export const UiStepDialog = C.StepDialog;
|
|
184
|
+
export const UiFullscreenDialog = C.FullscreenDialog;
|
|
185
|
+
export const UiPageDashboard = C.PageDashboard;
|
|
186
|
+
export const UiPagePatterns = C.PagePatterns;
|
|
187
|
+
export const UiPageCrm = C.PageCrm;
|
|
188
|
+
export const UiPageBookings = C.PageBookings;
|
|
189
|
+
export const UiPageCatalog = C.PageCatalog;
|
|
190
|
+
export const UiPageDetail = C.PageDetail;
|
|
191
|
+
export const UiPageSettings = C.PageSettings;
|
|
192
|
+
export const UiPageUserList = C.PageUserList;
|
|
193
|
+
export const UiPageProfile = C.PageProfile;
|
|
194
|
+
export const UiPageForm = C.PageForm;
|
|
195
|
+
export const UiPageOrder = C.PageOrder;
|
|
196
|
+
export const UiPageAccount = C.PageAccount;
|
|
197
|
+
export const UiPagePricing = C.PagePricing;
|
|
198
|
+
export const UiPageFaq = C.PageFaq;
|
|
199
|
+
export const UiPageAuth = C.PageAuth;
|
|
200
|
+
export const UiPageStatus = C.PageStatus;
|
|
201
|
+
export const UiTreeSelect = C.TreeSelect;
|
|
202
|
+
export const UiContextMenu = C.ContextMenu;
|
|
203
|
+
export const UiSortable = C.Sortable;
|
|
204
|
+
export const UiMap = C.Map;
|
|
205
|
+
export const UiImageUpload = C.ImageUpload;
|
|
206
|
+
export const UiScreensaver = C.Screensaver;
|
|
207
|
+
export const UiTour = C.Tour;
|
|
208
|
+
export const UiHeading = C.Heading;
|
|
209
|
+
export const UiText = C.Text;
|
|
210
|
+
export const UiBox = C.Box;
|
|
211
|
+
export const UiCenter = C.Center;
|
|
212
|
+
export const UiHStack = C.HStack;
|
|
213
|
+
export const UiVStack = C.VStack;
|
|
214
|
+
export const UiGrid = C.Grid;
|
|
215
|
+
export const UiLink = C.Link;
|
|
216
|
+
export const UiPressable = C.Pressable;
|
|
217
|
+
export const UiIcon = C.Icon;
|
|
218
|
+
export const UiPortal = C.Portal;
|
|
219
|
+
export const UiLiquidGlass = C.LiquidGlass;
|
|
220
|
+
export const UiBottomSheet = C.BottomSheet;
|
|
221
|
+
export const UiActionsheet = C.Actionsheet;
|
|
222
|
+
export const UiImageViewer = C.ImageViewer;
|
|
223
|
+
export const UiChatAi = C.ChatAi;
|
|
224
|
+
export { fmt, setIconBase, rules, LOCALES, setUiLocale, getUiLocale, setUiMessages, isRtlLocale } from '../core/index.js';
|
|
31
225
|
export { useUiTheme } from '../theme.js';
|
package/src/resolver.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Auto-import resolver for unplugin-vue-components (Vite, Webpack, Rollup, Rspack).
|
|
2
|
+
// import Components from 'unplugin-vue-components/vite'
|
|
3
|
+
// import { ZiyaragoUiResolver } from '@ziyarago/ui/resolver'
|
|
4
|
+
// Components({ resolvers: [ZiyaragoUiResolver()] })
|
|
5
|
+
// Zero dependencies: it only maps <UiButton> to { name: 'UiButton', from: '@ziyarago/ui/vue' }.
|
|
6
|
+
import { components } from './core/index.js';
|
|
7
|
+
|
|
8
|
+
const NAMES = new Set(Object.keys(components));
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {{ prefix?: string, css?: boolean | string, exclude?: string[], from?: string }} [options]
|
|
12
|
+
* prefix component prefix, default 'Ui' (must match the registered names, which are always Ui*)
|
|
13
|
+
* css true: import '@ziyarago/ui/style.css' as a side effect together with the first resolved component (once per module that uses one);
|
|
14
|
+
* a string: import that path instead (for example your own entry that imports the css inside a Tailwind @layer). Default false.
|
|
15
|
+
* exclude component names (without prefix) that must not be auto-imported, e.g. ['Button'] if you keep your own UiButton.
|
|
16
|
+
* from module the components are imported from, default '@ziyarago/ui/vue'
|
|
17
|
+
*/
|
|
18
|
+
export function ZiyaragoUiResolver(options = {}) {
|
|
19
|
+
const { prefix = 'Ui', css = false, exclude = [], from = '@ziyarago/ui/vue' } = options;
|
|
20
|
+
const skip = new Set(exclude.map(n => n.replace(/^Ui/, '')));
|
|
21
|
+
const sideEffects = css ? (css === true ? '@ziyarago/ui/style.css' : css) : undefined;
|
|
22
|
+
return {
|
|
23
|
+
type: 'component',
|
|
24
|
+
resolve(name) {
|
|
25
|
+
if (!name.startsWith(prefix)) return;
|
|
26
|
+
const bare = name.slice(prefix.length);
|
|
27
|
+
if (!NAMES.has(bare) || skip.has(bare)) return;
|
|
28
|
+
return { name: 'Ui' + bare, from, ...(sideEffects ? { sideEffects } : {}) };
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default ZiyaragoUiResolver;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/* @ziyarago/ui · components. Every class is zg-*; no global resets except .zg-root */
|
|
2
2
|
.zg-root{font-family:var(--zg-font);color:var(--zg-text-1);background:var(--zg-bg);-webkit-font-smoothing:antialiased}
|
|
3
3
|
.zg-root *,.zg-root *::before,.zg-root *::after{box-sizing:border-box}
|
|
4
|
+
/* Host-CSS robustness. Zero specificity (:where), so any zg-* rule, utility class or app rule wins. Makes a component look the same with or without
|
|
5
|
+
Tailwind preflight / a CSS reset: form controls inherit font and color, no UA padding, border-box, normal line-height, svg without a baseline gap. */
|
|
6
|
+
:where(.zg-root,[class*="zg-"]){line-height:normal}
|
|
7
|
+
:where([class*="zg-"]),:where([class*="zg-"])::before,:where([class*="zg-"])::after,:where(.zg-root,[class*="zg-"]) :where(*,*::before,*::after){box-sizing:border-box}
|
|
8
|
+
:where(.zg-root,[class*="zg-"]) :where(button,input,select,textarea),:where(button,input,select,textarea):where([class*="zg-"]){font:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0;background-color:transparent}
|
|
9
|
+
:where(.zg-root,[class*="zg-"]) a:where(:not([class])){text-decoration:underline}
|
|
10
|
+
:where(.zg-root,[class*="zg-"]) svg,svg:where([class*="zg-"]){vertical-align:middle}
|
|
4
11
|
.zg-glass{background:var(--zg-s1);backdrop-filter:blur(24px) saturate(1.5);-webkit-backdrop-filter:blur(24px) saturate(1.5);box-shadow:var(--zg-rim),var(--zg-shadow-1)}
|
|
5
12
|
.zg-icon:not([style*="--zg-icon"]){visibility:hidden}
|
|
6
13
|
.zg-icon{display:inline-block;flex:none;width:1em;height:1em;background:currentColor;-webkit-mask:var(--zg-icon) center/contain no-repeat;mask:var(--zg-icon) center/contain no-repeat}
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
.zg-saver__c{position:relative;display:flex;flex-direction:column;align-items:center;gap:12px;text-align:center}.zg-saver__m{width:72px;height:72px;background:center/contain no-repeat;opacity:.9}
|
|
12
12
|
.zg-tourov{position:fixed;inset:0;z-index:250}.zg-tourov__full{position:absolute;inset:0;background:oklch(0.1 0 0 / .7)}.zg-tourov__cut{position:absolute;border-radius:14px;box-shadow:0 0 0 9999px oklch(0.1 0 0 / .7),0 0 0 2px var(--zg-brand);pointer-events:none}
|
|
13
13
|
.zg-rte__c blockquote{margin:8px 0;padding:4px 14px;border-inline-start:3px solid var(--zg-brand);color:var(--zg-text-2)}.zg-rte__c pre{margin:8px 0;padding:12px 14px;border-radius:12px;background:oklch(0.17 0.006 240);color:oklch(0.9 0.01 240);font:500 13px var(--zg-font-mono);overflow:auto;direction:ltr;text-align:left}
|
|
14
|
+
/* Rich text defaults that a CSS reset (Tailwind preflight) would remove; :where keeps them overridable. */
|
|
15
|
+
:where(.zg-rte__c) :where(p){margin:0 0 .6em}:where(.zg-rte__c) :where(ul,ol){margin:.5em 0;padding-inline-start:1.5em}:where(.zg-rte__c) ul{list-style:disc}:where(.zg-rte__c) ol{list-style:decimal}:where(.zg-rte__c) :where(h1,h2,h3){font-weight:700;margin:.8em 0 .4em}:where(.zg-rte__c) h1{font-size:1.5em}:where(.zg-rte__c) h2{font-size:1.25em}:where(.zg-rte__c) h3{font-size:1.1em}:where(.zg-rte__c) a{color:var(--zg-brand-text);text-decoration:underline}
|
|
14
16
|
/* focus + disabled audit */
|
|
15
17
|
.zg-btn:focus-visible,.zg-ibtn:focus-visible,.zg-chip:focus-visible,.zg-chip2 button:focus-visible,.zg-tt__i:focus-visible,.zg-pt button:focus-visible,.zg-navitem:focus-visible,.zg-menu__i:focus-visible,.zg-check:focus-visible,.zg-switch:focus-visible,.zg-cal__d:focus-visible,.zg-acc__h:focus-visible,.zg-tree__n:focus-visible,.zg-room:focus-visible,.zg-pin:focus-visible,.zg-sort__i:focus-visible,.zg-inline:focus-visible{outline:3px solid var(--zg-brand-soft);outline-offset:2px}
|
|
16
18
|
.zg-btn:disabled,.zg-ibtn:disabled,.zg-chip:disabled,[aria-disabled="true"]{opacity:.45;cursor:not-allowed;pointer-events:none}.zg-tt__i:hover,.zg-chip:hover:not([aria-pressed="true"]){background:var(--zg-s2)}.zg-room:hover,.zg-hotel:hover,.zg-lead:hover{box-shadow:var(--zg-rim),var(--zg-shadow-1)}.zg-table tbody tr:hover{background:var(--zg-s1)}
|
package/src/styles/effects.css
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
[data-fx="lite"] .zg-glass{background:var(--zg-pop)}
|
|
11
11
|
|
|
12
12
|
/* ── page backgrounds ── set data-bg on <html> (useUiTheme().setBackground) or on any element with class zg-bg ── */
|
|
13
|
-
:root{--zg-bgL:.62;--zg-bgC:.
|
|
14
|
-
[data-theme="light"]{--zg-bgL:.8;--zg-bgC:.
|
|
13
|
+
:root{--zg-bgL:.62;--zg-bgC:.2;--zg-bgA:42%}
|
|
14
|
+
[data-theme="light"]{--zg-bgL:.8;--zg-bgC:.14;--zg-bgA:50%}
|
|
15
15
|
[data-bg="aurora"]{--zg-bg-image:radial-gradient(60% 50% at 12% 8%,color-mix(in oklch,var(--zg-brand) var(--zg-bgA),transparent),transparent 70%),radial-gradient(50% 45% at 88% 18%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 250) var(--zg-bgA),transparent),transparent 70%),radial-gradient(65% 55% at 50% 105%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 320) var(--zg-bgA),transparent),transparent 70%)}
|
|
16
16
|
[data-bg="sunset"]{--zg-bg-image:radial-gradient(70% 55% at 10% 0%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 55) var(--zg-bgA),transparent),transparent 70%),radial-gradient(60% 50% at 95% 25%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 15) var(--zg-bgA),transparent),transparent 70%),radial-gradient(70% 60% at 40% 110%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 340) var(--zg-bgA),transparent),transparent 70%)}
|
|
17
17
|
[data-bg="ocean"]{--zg-bg-image:radial-gradient(70% 55% at 85% 0%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 230) var(--zg-bgA),transparent),transparent 70%),radial-gradient(60% 55% at 5% 40%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 200) var(--zg-bgA),transparent),transparent 70%),radial-gradient(70% 55% at 60% 110%,color-mix(in oklch,oklch(var(--zg-bgL) var(--zg-bgC) 265) var(--zg-bgA),transparent),transparent 70%)}
|
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
html[data-bg]:not([data-bg="none"]),.zg-bg:not([data-bg="none"]){background-color:var(--zg-bg);background-image:var(--zg-bg-image);background-attachment:fixed}
|
|
22
22
|
.zg-bg:not([data-bg="none"]){background-attachment:scroll}
|
|
23
23
|
html[data-bg]:not([data-bg="none"]) .zg-root{background:transparent}
|
|
24
|
-
html[data-
|
|
25
|
-
|
|
24
|
+
html[data-motion="on"][data-bg]:not([data-bg="none"]){background-image:none}
|
|
25
|
+
html[data-motion="on"][data-bg]:not([data-bg="none"])::before{content:"";position:fixed;inset:-25%;z-index:-1;pointer-events:none;background-image:var(--zg-bg-image);background-repeat:no-repeat;animation:zg-bg-float 18s ease-in-out infinite alternate,zg-bg-hue 40s linear infinite;will-change:transform,filter}
|
|
26
|
+
@keyframes zg-bg-hue{from{filter:hue-rotate(0deg) saturate(1.15)}to{filter:hue-rotate(360deg) saturate(1.15)}}
|
|
27
|
+
@keyframes zg-bg-float{0%{transform:translate3d(-3%,-2%,0) scale(1) rotate(0deg)}50%{transform:translate3d(4%,3%,0) scale(1.18) rotate(3deg)}100%{transform:translate3d(-2%,5%,0) scale(1.08) rotate(-3deg)}}
|
|
26
28
|
|
|
27
29
|
/* ── gradient cards ── <UiCard variant="gradient" tone="sky" intensity="soft|vivid"> ── */
|
|
28
30
|
.zg-card--grad{--t:var(--zg-brand);--tv:var(--zg-brand);--on:var(--zg-on-brand)}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* Additions for parity with older UI kits (icon-only buttons, avatar status, card slots, tooltip placement, ...). Plain classes, no size selectors. */
|
|
2
|
+
.zg-req{color:var(--zg-red)}
|
|
3
|
+
.zg-btn--sq{width:var(--h);padding:0}
|
|
4
|
+
.zg-ta--fixed{resize:none}.zg-ta--auto{field-sizing:content}.zg-ta__count{align-self:flex-end}
|
|
5
|
+
.zg-select__trigger--error{box-shadow:var(--zg-rim),inset 0 0 0 1.5px var(--zg-red)}
|
|
6
|
+
.zg-check--error .zg-check__box{box-shadow:inset 0 0 0 1.5px var(--zg-red)}
|
|
7
|
+
.zg-check[aria-checked="mixed"] .zg-check__box{background:var(--zg-brand);box-shadow:none}
|
|
8
|
+
.zg-seg--block{display:flex;width:100%}.zg-seg--block button{flex:1}
|
|
9
|
+
.zg-seg button{display:inline-flex;align-items:center;justify-content:center;gap:6px}.zg-seg button[disabled]{opacity:.45;cursor:not-allowed}
|
|
10
|
+
.zg-alert__act{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
|
|
11
|
+
.zg-badge--sq{border-radius:8px}.zg-badge--inverse{background:var(--zg-inv-bg);color:var(--zg-inv-fg)}
|
|
12
|
+
.zg-avatar--sq{border-radius:30%}
|
|
13
|
+
.zg-avatar--ring{box-shadow:var(--zg-rim),0 0 0 2px var(--zg-bg)}
|
|
14
|
+
.zg-avatar--st{position:relative;overflow:visible}.zg-avatar--st img{border-radius:inherit}
|
|
15
|
+
.zg-avatar__st{position:absolute;inset-inline-end:0;bottom:0;width:max(8px,calc(var(--s)*.26));height:max(8px,calc(var(--s)*.26));border-radius:50%;background:var(--zg-text-3);box-shadow:0 0 0 2px var(--zg-bg)}
|
|
16
|
+
.zg-avatar__st--online{background:var(--zg-green)}.zg-avatar__st--away{background:var(--zg-amber)}.zg-avatar__st--busy{background:var(--zg-red)}
|
|
17
|
+
.zg-avatar--sky{background:var(--zg-sky);color:var(--zg-bg)}.zg-avatar--success{background:var(--zg-green);color:var(--zg-bg)}.zg-avatar--warning{background:var(--zg-amber);color:var(--zg-bg)}.zg-avatar--danger{background:var(--zg-red);color:var(--zg-bg)}.zg-avatar--neutral{background:var(--zg-s3);color:var(--zg-text-1)}
|
|
18
|
+
.zg-card.zg-card--outline{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;box-shadow:inset 0 0 0 1px var(--zg-stroke)}
|
|
19
|
+
.zg-card.zg-card--flush{padding:0}
|
|
20
|
+
.zg-card--click{cursor:pointer;transition:transform .2s var(--zg-ease)}.zg-card--click:hover{transform:translateY(-2px)}.zg-card--click:focus-visible{outline:2px solid var(--zg-brand);outline-offset:2px}
|
|
21
|
+
.zg-card__foot{display:flex;align-items:center;gap:8px;padding-top:14px;box-shadow:0 -1px 0 var(--zg-stroke)}
|
|
22
|
+
.zg-modal__sub{font-size:13px;font-weight:500;color:var(--zg-text-3);margin-top:2px}
|
|
23
|
+
.zg-crumbs__sep{color:var(--zg-text-3)}
|
|
24
|
+
.zg-tr--click{cursor:pointer}
|
|
25
|
+
.zg-tip--bottom::after{bottom:auto;top:calc(100% + 8px);transform:translateX(-50%) translateY(-4px)}
|
|
26
|
+
.zg-tip--bottom:hover::after,.zg-tip--bottom:focus-visible::after{transform:translateX(-50%) translateY(0)}
|
|
27
|
+
.zg-tip--left::after,.zg-tip--right::after{bottom:auto;top:50%;inset-inline-start:auto}
|
|
28
|
+
.zg-tip--left::after{left:auto;right:calc(100% + 8px);transform:translateY(-50%) translateX(4px)}
|
|
29
|
+
.zg-tip--right::after{right:auto;left:calc(100% + 8px);transform:translateY(-50%) translateX(-4px)}
|
|
30
|
+
.zg-tip--left:hover::after,.zg-tip--left:focus-visible::after,.zg-tip--right:hover::after,.zg-tip--right:focus-visible::after{transform:translateY(-50%) translateX(0)}
|
|
31
|
+
.zg-rg{display:flex;flex-direction:column;gap:10px}.zg-rg--row{flex-direction:row;flex-wrap:wrap;gap:10px 22px}
|
|
32
|
+
/* compat layer (@ziyarago/ui/compat): compound components that have no counterpart in the new kit */
|
|
33
|
+
.zg-dd-trig{display:inline-block}.zg-dd__panel{position:fixed;z-index:var(--zg-z-pop,60);animation:zg-pop-in .16s var(--zg-ease) both}
|
|
34
|
+
.zg-menu__lbl{padding:10px 12px 4px;font:700 11px var(--zg-font);letter-spacing:.1em;text-transform:uppercase;color:var(--zg-text-3)}
|
|
35
|
+
.zg-avgroup{display:flex}.zg-avgroup>*+*{margin-inline-start:-8px}.zg-avgroup--tight>*+*{margin-inline-start:-12px}.zg-avgroup--loose>*+*{margin-inline-start:-4px}
|
|
36
|
+
.zg-avgroup>.zg-avatar{box-shadow:var(--zg-rim),0 0 0 2px var(--zg-bg)}.zg-avgroup--rev{flex-direction:row-reverse;justify-content:flex-end}
|
|
37
|
+
.zg-toasts{position:fixed;z-index:calc(var(--zg-z-modal,200) + 20);display:flex;flex-direction:column;gap:10px;padding:16px;max-width:100vw;pointer-events:none}
|
|
38
|
+
.zg-toasts--top-right{top:0;right:0;align-items:flex-end}.zg-toasts--top-left{top:0;left:0;align-items:flex-start}.zg-toasts--top-center{top:0;left:50%;transform:translateX(-50%);align-items:center}
|
|
39
|
+
.zg-toasts--bottom-right{bottom:0;right:0;align-items:flex-end;flex-direction:column-reverse}.zg-toasts--bottom-left{bottom:0;left:0;align-items:flex-start;flex-direction:column-reverse}.zg-toasts--bottom-center{bottom:0;left:50%;transform:translateX(-50%);align-items:center;flex-direction:column-reverse}
|
|
40
|
+
.zg-toasts__i{position:relative;pointer-events:auto}.zg-toasts__x{position:absolute;top:6px;inset-inline-end:6px}.zg-toasts__act{margin-top:6px}
|
|
41
|
+
.zg-sidenav--compat{position:fixed;inset-block:0;inset-inline-start:0;z-index:60;width:min(288px,80vw);height:100vh;transform:translateX(-100%);transition:transform .3s var(--zg-ease),width .3s var(--zg-ease);background-color:var(--sidebar-bg,oklch(0.108 0.022 50));color:var(--zg-text-2)}
|
|
42
|
+
[dir="rtl"] .zg-sidenav--compat{transform:translateX(100%)}.zg-sidenav--compat.is-open{transform:none}
|
|
43
|
+
.zg-sidenav__nav{flex:1;min-height:0;display:flex;flex-direction:column;gap:18px;overflow-y:auto;overflow-x:hidden;padding:8px 0}.zg-sidenav__sec{display:flex;flex-direction:column;gap:2px}
|
|
44
|
+
.zg-sidenav__foot{padding-top:12px;box-shadow:0 -1px 0 var(--zg-stroke)}
|
|
45
|
+
.zg-sidenav-scrim{position:fixed;inset:0;z-index:55;background:oklch(0.12 0.005 40 / .45);backdrop-filter:blur(4px)}
|
|
46
|
+
@media (min-width:1024px){.zg-sidenav--compat{position:sticky;top:12px;margin:12px 0 12px 12px;height:calc(100vh - 24px);width:var(--w);transform:none;border-radius:24px;flex:none}[dir="rtl"] .zg-sidenav--compat{margin:12px 12px 12px 0}.zg-sidenav-scrim{display:none}}
|
|
47
|
+
.zg-sidenav--collapsed .zg-sidenav__group{display:none}
|
|
48
|
+
.zg-topnav--compat{padding-inline:clamp(16px,3vw,32px);min-height:64px}.zg-topnav--compat.zg-topnav--md{min-height:56px}.zg-topnav__mid{flex:1;min-width:0;display:flex;justify-content:center}
|
|
49
|
+
.zg-topnav--compat .zg-topnav__brand{gap:12px}
|
|
50
|
+
.zg-subnav--compat .zg-navitem{text-decoration:none;width:100%}.zg-subnav--compat .zg-sidenav__group{display:flex;align-items:center;gap:8px}
|
|
51
|
+
@media (min-width:1024px){.zg-subnav--compat{position:sticky;top:16px;align-self:flex-start}}
|
|
52
|
+
.zg-check,.zg-switch{text-align:start}
|
|
53
|
+
.zg-sidenav__close{position:absolute;top:12px;inset-inline-end:12px}@media (min-width:1024px){.zg-sidenav__close{display:none}}
|
|
54
|
+
.zg-cal__d:disabled{opacity:.35;cursor:not-allowed;background:none}
|
|
55
|
+
.zg-tipbox{position:fixed;z-index:calc(var(--zg-z-modal,200) + 40);max-width:min(320px,90vw);padding:6px 10px;border-radius:10px;font:600 12px var(--zg-font);background:var(--zg-inv-bg);color:var(--zg-inv-fg);box-shadow:var(--zg-shadow-1);pointer-events:none}.zg-tipbox--glass{background:var(--zg-pop);color:var(--zg-text-1);box-shadow:var(--zg-rim),var(--zg-shadow-1)}
|
package/src/styles/index.css
CHANGED
package/src/theme.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import { setUiLocale, isRtlLocale, LOCALES } from './i18n/index.js';
|
|
1
2
|
// Framework-free theme controller: palette, theme, direction, motion, effects, background → attributes on <html>. Persists to localStorage.
|
|
2
3
|
const KEY = 'zg-ui';
|
|
3
4
|
export const PALETTES = ['gold', 'tamam'];
|
|
4
5
|
export const BACKGROUNDS = ['none', 'aurora', 'sunset', 'ocean', 'emerald', 'rose', 'mesh'];
|
|
5
|
-
const DEFAULTS = { theme: 'dark', palette: 'gold', dir: 'ltr', motion: 'auto', effects: 'auto', bg: 'none' };
|
|
6
|
+
const DEFAULTS = { theme: 'dark', palette: 'gold', dir: 'ltr', motion: 'auto', effects: 'auto', bg: 'none', locale: 'en' };
|
|
6
7
|
const read = () => { try { return JSON.parse(localStorage.getItem(KEY) || '{}'); } catch { return {}; } };
|
|
7
8
|
let cur = typeof localStorage === 'undefined' ? { ...DEFAULTS } : { ...DEFAULTS, ...read() };
|
|
9
|
+
|
|
10
|
+
/** Set the app defaults (used when the visitor has no saved choice). Call before the first useUiTheme(). */
|
|
11
|
+
export function configureTheme(defaults = {}) {
|
|
12
|
+
cur = typeof localStorage === 'undefined' ? { ...DEFAULTS, ...defaults } : { ...DEFAULTS, ...defaults, ...read() };
|
|
13
|
+
}
|
|
8
14
|
const subs = new Set();
|
|
9
15
|
|
|
10
16
|
export const capable = () => {
|
|
@@ -22,14 +28,17 @@ export const resolve = (s = cur) => ({
|
|
|
22
28
|
const apply = () => {
|
|
23
29
|
if (typeof document === 'undefined') return;
|
|
24
30
|
const r = document.documentElement, v = resolve();
|
|
25
|
-
r.dataset.theme = cur.theme; r.dataset.palette = cur.palette; r.dir = cur.dir;
|
|
31
|
+
r.dataset.theme = cur.theme; r.dataset.palette = cur.palette; r.dir = cur.dir; r.lang = cur.locale;
|
|
26
32
|
r.dataset.motion = v.motion; r.dataset.fx = v.effects; r.dataset.bg = cur.bg;
|
|
27
33
|
try { localStorage.setItem(KEY, JSON.stringify(cur)); } catch {}
|
|
28
34
|
subs.forEach(f => f({ ...cur }));
|
|
29
35
|
};
|
|
30
36
|
|
|
31
37
|
/** Inline script for <head>: applies the saved settings before first paint (no flash). */
|
|
32
|
-
export const themeInitScript = `try{var s=JSON.parse(localStorage.getItem('${KEY}')||'{}'),r=document.documentElement,d=r.dataset;if(s.theme)d.theme=s.theme;if(s.palette)d.palette=s.palette;if(s.dir)r.dir=s.dir;if(s.bg)d.bg=s.bg;var m=s.motion||'auto',f=s.effects||'auto';d.motion=m==='auto'?(matchMedia('(prefers-reduced-motion: reduce)').matches?'off':'on'):m;d.fx=f==='auto'?((CSS.supports('backdrop-filter','blur(1px)')&&(navigator.deviceMemory||8)>=4&&(navigator.hardwareConcurrency||8)>=4)?'full':'lite'):f}catch(e){}`;
|
|
38
|
+
export const themeInitScript = `try{var s=JSON.parse(localStorage.getItem('${KEY}')||'{}'),r=document.documentElement,d=r.dataset;if(s.theme)d.theme=s.theme;if(s.palette)d.palette=s.palette;if(s.dir)r.dir=s.dir;if(s.locale)r.lang=s.locale;if(s.bg)d.bg=s.bg;var m=s.motion||'auto',f=s.effects||'auto';d.motion=m==='auto'?(matchMedia('(prefers-reduced-motion: reduce)').matches?'off':'on'):m;d.fx=f==='auto'?((CSS.supports('backdrop-filter','blur(1px)')&&(navigator.deviceMemory||8)>=4&&(navigator.hardwareConcurrency||8)>=4)?'full':'lite'):f}catch(e){}`;
|
|
39
|
+
|
|
40
|
+
/** Apply the saved language to the built-in strings. Call AFTER the first render/hydration (the Nuxt module does it on app:mounted). */
|
|
41
|
+
export function applySavedLocale() { if (cur.locale && cur.locale !== 'en') setUiLocale(cur.locale); }
|
|
33
42
|
|
|
34
43
|
export function useUiTheme() {
|
|
35
44
|
if (typeof document !== 'undefined') apply();
|
|
@@ -40,7 +49,10 @@ export function useUiTheme() {
|
|
|
40
49
|
get resolved() { return resolve(); },
|
|
41
50
|
palettes: PALETTES, backgrounds: BACKGROUNDS,
|
|
42
51
|
setTheme: t => set({ theme: t }), toggleTheme: () => set({ theme: cur.theme === 'dark' ? 'light' : 'dark' }),
|
|
43
|
-
setPalette: p => set({ palette: p }), setDir: d => set({ dir: d }),
|
|
52
|
+
setPalette: p => set({ palette: p }), setDir: d => set({ dir: d }),
|
|
53
|
+
/** Language of the built-in component strings. Also sets dir (rtl for Arabic) and <html lang>. */
|
|
54
|
+
get locale() { return cur.locale; }, locales: LOCALES,
|
|
55
|
+
setLocale: l => { setUiLocale(l); set({ locale: String(l).toLowerCase().split(/[-_]/)[0], dir: isRtlLocale(l) ? 'rtl' : 'ltr' }); },
|
|
44
56
|
/** 'auto' follows prefers-reduced-motion, 'on' enables animations, 'off' disables them */
|
|
45
57
|
setMotion: m => set({ motion: m }),
|
|
46
58
|
/** 'auto' picks by browser capability, 'full' = blur, glow and animated backgrounds, 'lite' = flat and fast */
|
package/src/vue/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Vue 3 adapter. Usage: import { UiButton, UiAppShell } from '@ziyarago/ui/vue'
|
|
2
|
-
import { h, ref, reactive, defineComponent, Teleport, cloneVNode, isVNode } from 'vue';
|
|
3
|
-
import { components } from '../core/index.js';
|
|
2
|
+
import { h, ref, reactive, defineComponent, onMounted, onBeforeUnmount, Teleport, cloneVNode, isVNode } from 'vue';
|
|
3
|
+
import { components, subscribeUiLocale } from '../core/index.js';
|
|
4
|
+
import { BOOL_PROPS } from '../core/bools.js';
|
|
4
5
|
|
|
5
6
|
const C = {};
|
|
6
7
|
const vh = (t, p, ...k) => { const kids = k.flat(); if (p && typeof t === 'string') for (const key of Object.keys(p)) if (/^on[A-Z]/.test(key) && !key.startsWith('onVnode')) { const nk = 'on' + key[2] + key.slice(3).toLowerCase(); if (nk !== key) { p[nk] = p[key]; delete p[key]; } } return typeof t === 'string' || !kids.length ? h(t, p, kids.length ? kids : undefined) : h(t, p, { default: () => kids }); };
|
|
@@ -9,14 +10,20 @@ const wrap = (name, def) => defineComponent({
|
|
|
9
10
|
setup(_, { attrs, slots, emit }) {
|
|
10
11
|
const state = reactive({ ...(def.state || {}) });
|
|
11
12
|
const set = o => Object.assign(state, o);
|
|
13
|
+
// Teleports are client-only: during SSR and hydration portal() renders nothing (a teleport to <body> cannot hydrate), then appears once mounted.
|
|
14
|
+
const mounted = ref(false), localeTick = ref(0); let offLocale; onMounted(() => { mounted.value = true; offLocale = subscribeUiLocale(() => { localeTick.value++; }); }); onBeforeUnmount(() => offLocale && offLocale());
|
|
12
15
|
return () => {
|
|
13
|
-
|
|
16
|
+
void localeTick.value;
|
|
17
|
+
const props = {}, root = {};
|
|
18
|
+
for (const k in attrs) { if (/^(aria|data)-|^(class|style|id)$/.test(k)) root[k] = attrs[k]; const pk = k.includes('-') && !/^(aria|data)-/.test(k) ? k.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) : k; props[pk] = attrs[k] === '' && BOOL_PROPS.has(pk) ? true : attrs[k]; }
|
|
19
|
+
props.onChange = v => { emit('update:modelValue', v); emit('change', v); };
|
|
14
20
|
if (attrs.modelValue === undefined) delete props.modelValue;
|
|
15
21
|
const named = {}; for (const k of Object.keys(slots)) if (k !== 'default') named[k] = slots[k]();
|
|
16
22
|
const children = slots.default ? slots.default() : [];
|
|
17
|
-
const out = def.render({ C, h: vh, props, children, slots: named, state, set, portal: (kids, to) => h(Teleport, { to: to || 'body' }, kids) });
|
|
23
|
+
const out = def.render({ C, h: vh, props, children, slots: named, state, set, portal: (kids, to) => mounted.value ? h(Teleport, { to: to || 'body' }, kids) : null });
|
|
18
24
|
const sz = attrs.size;
|
|
19
|
-
|
|
25
|
+
if (sz) root['data-size'] = sz;
|
|
26
|
+
return isVNode(out) && typeof out.type === 'string' && Object.keys(root).length ? cloneVNode(out, root) : out;
|
|
20
27
|
};
|
|
21
28
|
},
|
|
22
29
|
});
|
|
@@ -27,3 +34,4 @@ export const install = app => { for (const [n, c] of Object.entries(C)) app.comp
|
|
|
27
34
|
export { fmt, setIconBase, rules } from '../core/index.js';
|
|
28
35
|
export { useUiTheme } from '../theme.js';
|
|
29
36
|
export default { install };
|
|
37
|
+
export { LOCALES, setUiLocale, getUiLocale, setUiMessages, isRtlLocale } from '../core/index.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ZiyaragoCompatResolverOptions {
|
|
2
|
+
/** Module the compat components come from. Default '@ziyarago/ui/compat'. */
|
|
3
|
+
from?: string;
|
|
4
|
+
/** Full component names (with the Ui prefix) to leave to other resolvers or local files, for example ['UiTable']. */
|
|
5
|
+
exclude?: string[];
|
|
6
|
+
/** true: also import '@ziyarago/ui/style.css'; a string: import that module instead. Default false. */
|
|
7
|
+
css?: boolean | string;
|
|
8
|
+
}
|
|
9
|
+
export interface ZiyaragoCompatResolverResult { name: string; from: string; sideEffects?: string }
|
|
10
|
+
export interface ZiyaragoCompatResolver { type: 'component'; resolve(name: string): ZiyaragoCompatResolverResult | undefined }
|
|
11
|
+
export function ZiyaragoCompatResolver(options?: ZiyaragoCompatResolverOptions): ZiyaragoCompatResolver;
|
|
12
|
+
export default ZiyaragoCompatResolver;
|