@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/dist/style.css
CHANGED
|
@@ -75,6 +75,13 @@
|
|
|
75
75
|
/* @ziyarago/ui · components. Every class is zg-*; no global resets except .zg-root */
|
|
76
76
|
.zg-root{font-family:var(--zg-font);color:var(--zg-text-1);background:var(--zg-bg);-webkit-font-smoothing:antialiased}
|
|
77
77
|
.zg-root *,.zg-root *::before,.zg-root *::after{box-sizing:border-box}
|
|
78
|
+
/* 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
|
|
79
|
+
Tailwind preflight / a CSS reset: form controls inherit font and color, no UA padding, border-box, normal line-height, svg without a baseline gap. */
|
|
80
|
+
:where(.zg-root,[class*="zg-"]){line-height:normal}
|
|
81
|
+
:where([class*="zg-"]),:where([class*="zg-"])::before,:where([class*="zg-"])::after,:where(.zg-root,[class*="zg-"]) :where(*,*::before,*::after){box-sizing:border-box}
|
|
82
|
+
: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}
|
|
83
|
+
:where(.zg-root,[class*="zg-"]) a:where(:not([class])){text-decoration:underline}
|
|
84
|
+
:where(.zg-root,[class*="zg-"]) svg,svg:where([class*="zg-"]){vertical-align:middle}
|
|
78
85
|
.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)}
|
|
79
86
|
.zg-icon:not([style*="--zg-icon"]){visibility:hidden}
|
|
80
87
|
.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}
|
|
@@ -382,6 +389,8 @@
|
|
|
382
389
|
.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}
|
|
383
390
|
.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}
|
|
384
391
|
.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}
|
|
392
|
+
/* Rich text defaults that a CSS reset (Tailwind preflight) would remove; :where keeps them overridable. */
|
|
393
|
+
: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}
|
|
385
394
|
/* focus + disabled audit */
|
|
386
395
|
.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}
|
|
387
396
|
.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)}
|
|
@@ -1310,6 +1319,64 @@
|
|
|
1310
1319
|
.zg-rc.zg-dm[data-size] .zg-rc__c{height:calc(28px*var(--dz))}
|
|
1311
1320
|
|
|
1312
1321
|
|
|
1322
|
+
/* ./extras.css */
|
|
1323
|
+
/* Additions for parity with older UI kits (icon-only buttons, avatar status, card slots, tooltip placement, ...). Plain classes, no size selectors. */
|
|
1324
|
+
.zg-req{color:var(--zg-red)}
|
|
1325
|
+
.zg-btn--sq{width:var(--h);padding:0}
|
|
1326
|
+
.zg-ta--fixed{resize:none}.zg-ta--auto{field-sizing:content}.zg-ta__count{align-self:flex-end}
|
|
1327
|
+
.zg-select__trigger--error{box-shadow:var(--zg-rim),inset 0 0 0 1.5px var(--zg-red)}
|
|
1328
|
+
.zg-check--error .zg-check__box{box-shadow:inset 0 0 0 1.5px var(--zg-red)}
|
|
1329
|
+
.zg-check[aria-checked="mixed"] .zg-check__box{background:var(--zg-brand);box-shadow:none}
|
|
1330
|
+
.zg-seg--block{display:flex;width:100%}.zg-seg--block button{flex:1}
|
|
1331
|
+
.zg-seg button{display:inline-flex;align-items:center;justify-content:center;gap:6px}.zg-seg button[disabled]{opacity:.45;cursor:not-allowed}
|
|
1332
|
+
.zg-alert__act{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
|
|
1333
|
+
.zg-badge--sq{border-radius:8px}.zg-badge--inverse{background:var(--zg-inv-bg);color:var(--zg-inv-fg)}
|
|
1334
|
+
.zg-avatar--sq{border-radius:30%}
|
|
1335
|
+
.zg-avatar--ring{box-shadow:var(--zg-rim),0 0 0 2px var(--zg-bg)}
|
|
1336
|
+
.zg-avatar--st{position:relative;overflow:visible}.zg-avatar--st img{border-radius:inherit}
|
|
1337
|
+
.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)}
|
|
1338
|
+
.zg-avatar__st--online{background:var(--zg-green)}.zg-avatar__st--away{background:var(--zg-amber)}.zg-avatar__st--busy{background:var(--zg-red)}
|
|
1339
|
+
.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)}
|
|
1340
|
+
.zg-card.zg-card--outline{background:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;box-shadow:inset 0 0 0 1px var(--zg-stroke)}
|
|
1341
|
+
.zg-card.zg-card--flush{padding:0}
|
|
1342
|
+
.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}
|
|
1343
|
+
.zg-card__foot{display:flex;align-items:center;gap:8px;padding-top:14px;box-shadow:0 -1px 0 var(--zg-stroke)}
|
|
1344
|
+
.zg-modal__sub{font-size:13px;font-weight:500;color:var(--zg-text-3);margin-top:2px}
|
|
1345
|
+
.zg-crumbs__sep{color:var(--zg-text-3)}
|
|
1346
|
+
.zg-tr--click{cursor:pointer}
|
|
1347
|
+
.zg-tip--bottom::after{bottom:auto;top:calc(100% + 8px);transform:translateX(-50%) translateY(-4px)}
|
|
1348
|
+
.zg-tip--bottom:hover::after,.zg-tip--bottom:focus-visible::after{transform:translateX(-50%) translateY(0)}
|
|
1349
|
+
.zg-tip--left::after,.zg-tip--right::after{bottom:auto;top:50%;inset-inline-start:auto}
|
|
1350
|
+
.zg-tip--left::after{left:auto;right:calc(100% + 8px);transform:translateY(-50%) translateX(4px)}
|
|
1351
|
+
.zg-tip--right::after{right:auto;left:calc(100% + 8px);transform:translateY(-50%) translateX(-4px)}
|
|
1352
|
+
.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)}
|
|
1353
|
+
.zg-rg{display:flex;flex-direction:column;gap:10px}.zg-rg--row{flex-direction:row;flex-wrap:wrap;gap:10px 22px}
|
|
1354
|
+
/* compat layer (@ziyarago/ui/compat): compound components that have no counterpart in the new kit */
|
|
1355
|
+
.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}
|
|
1356
|
+
.zg-menu__lbl{padding:10px 12px 4px;font:700 11px var(--zg-font);letter-spacing:.1em;text-transform:uppercase;color:var(--zg-text-3)}
|
|
1357
|
+
.zg-avgroup{display:flex}.zg-avgroup>*+*{margin-inline-start:-8px}.zg-avgroup--tight>*+*{margin-inline-start:-12px}.zg-avgroup--loose>*+*{margin-inline-start:-4px}
|
|
1358
|
+
.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}
|
|
1359
|
+
.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}
|
|
1360
|
+
.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}
|
|
1361
|
+
.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}
|
|
1362
|
+
.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}
|
|
1363
|
+
.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)}
|
|
1364
|
+
[dir="rtl"] .zg-sidenav--compat{transform:translateX(100%)}.zg-sidenav--compat.is-open{transform:none}
|
|
1365
|
+
.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}
|
|
1366
|
+
.zg-sidenav__foot{padding-top:12px;box-shadow:0 -1px 0 var(--zg-stroke)}
|
|
1367
|
+
.zg-sidenav-scrim{position:fixed;inset:0;z-index:55;background:oklch(0.12 0.005 40 / .45);backdrop-filter:blur(4px)}
|
|
1368
|
+
@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}}
|
|
1369
|
+
.zg-sidenav--collapsed .zg-sidenav__group{display:none}
|
|
1370
|
+
.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}
|
|
1371
|
+
.zg-topnav--compat .zg-topnav__brand{gap:12px}
|
|
1372
|
+
.zg-subnav--compat .zg-navitem{text-decoration:none;width:100%}.zg-subnav--compat .zg-sidenav__group{display:flex;align-items:center;gap:8px}
|
|
1373
|
+
@media (min-width:1024px){.zg-subnav--compat{position:sticky;top:16px;align-self:flex-start}}
|
|
1374
|
+
.zg-check,.zg-switch{text-align:start}
|
|
1375
|
+
.zg-sidenav__close{position:absolute;top:12px;inset-inline-end:12px}@media (min-width:1024px){.zg-sidenav__close{display:none}}
|
|
1376
|
+
.zg-cal__d:disabled{opacity:.35;cursor:not-allowed;background:none}
|
|
1377
|
+
.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)}
|
|
1378
|
+
|
|
1379
|
+
|
|
1313
1380
|
/* ./effects.css */
|
|
1314
1381
|
/* motion, effects, page backgrounds and gradient cards */
|
|
1315
1382
|
|
|
@@ -1323,8 +1390,8 @@
|
|
|
1323
1390
|
[data-fx="lite"] .zg-glass{background:var(--zg-pop)}
|
|
1324
1391
|
|
|
1325
1392
|
/* ── page backgrounds ── set data-bg on <html> (useUiTheme().setBackground) or on any element with class zg-bg ── */
|
|
1326
|
-
:root{--zg-bgL:.62;--zg-bgC:.
|
|
1327
|
-
[data-theme="light"]{--zg-bgL:.8;--zg-bgC:.
|
|
1393
|
+
:root{--zg-bgL:.62;--zg-bgC:.2;--zg-bgA:42%}
|
|
1394
|
+
[data-theme="light"]{--zg-bgL:.8;--zg-bgC:.14;--zg-bgA:50%}
|
|
1328
1395
|
[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%)}
|
|
1329
1396
|
[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%)}
|
|
1330
1397
|
[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%)}
|
|
@@ -1334,8 +1401,10 @@
|
|
|
1334
1401
|
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}
|
|
1335
1402
|
.zg-bg:not([data-bg="none"]){background-attachment:scroll}
|
|
1336
1403
|
html[data-bg]:not([data-bg="none"]) .zg-root{background:transparent}
|
|
1337
|
-
html[data-
|
|
1338
|
-
|
|
1404
|
+
html[data-motion="on"][data-bg]:not([data-bg="none"]){background-image:none}
|
|
1405
|
+
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}
|
|
1406
|
+
@keyframes zg-bg-hue{from{filter:hue-rotate(0deg) saturate(1.15)}to{filter:hue-rotate(360deg) saturate(1.15)}}
|
|
1407
|
+
@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)}}
|
|
1339
1408
|
|
|
1340
1409
|
/* ── gradient cards ── <UiCard variant="gradient" tone="sky" intensity="soft|vivid"> ── */
|
|
1341
1410
|
.zg-card--grad{--t:var(--zg-brand);--tv:var(--zg-brand);--on:var(--zg-on-brand)}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Integration guide
|
|
2
|
+
|
|
3
|
+
Recipes verified against packed tarballs (`npm pack`) in clean projects: Vite 8 + Vue 3.5 + Tailwind 4 + unplugin-vue-components + vue-i18n + pinia + vue-router + vue-tsc 3, Nuxt 3, Next 15 (App Router), React 19.
|
|
4
|
+
|
|
5
|
+
## 1. Vue 3 + Vite + unplugin-vue-components
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i @ziyarago/ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`vite.config.ts`
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { defineConfig } from 'vite';
|
|
15
|
+
import vue from '@vitejs/plugin-vue';
|
|
16
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
17
|
+
import Components from 'unplugin-vue-components/vite';
|
|
18
|
+
import { ZiyaragoUiResolver } from '@ziyarago/ui/resolver';
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
plugins: [
|
|
22
|
+
vue(),
|
|
23
|
+
tailwindcss(),
|
|
24
|
+
Components({
|
|
25
|
+
dirs: ['src/components'],
|
|
26
|
+
dts: 'src/components.d.ts', // typed <UiButton> etc. in templates (vue-tsc reads it)
|
|
27
|
+
resolvers: [ZiyaragoUiResolver()],
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Templates then use `<UiButton>`, `<UiCard>`, `<UiDataTable>` ... with no imports. Resolver options: `css: true` (also import the stylesheet), `exclude: ['Button']` (names you do not want auto-imported), `prefix`, `from`. A component of your own in `src/components/UiButton.vue` wins over the library one (verified), so same-named local files keep working.
|
|
34
|
+
|
|
35
|
+
CSS: load it once, in your Tailwind entry (see section 3) or `main.ts`:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import '@ziyarago/ui/style.css';
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`components.d.ts` is written by the plugin when Vite starts or builds. Run `vite build` (or `vite`) once before `vue-tsc` on a fresh checkout, or commit the file. Your `build` script `vue-tsc --noEmit && vite build` is fine once the file exists.
|
|
42
|
+
|
|
43
|
+
Without unplugin (manual registration): `import ui from '@ziyarago/ui/vue'; app.use(ui)`, and for template typing add once, e.g. in `env.d.ts`:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import '@ziyarago/ui/vue/global'; // GlobalComponents for every Ui* tag
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Plain imports also work: `import { UiButton, type UiButtonProps } from '@ziyarago/ui/vue'`.
|
|
50
|
+
|
|
51
|
+
### What vue-tsc checks
|
|
52
|
+
|
|
53
|
+
Every component has `Ui<Name>Props` (JSDoc from the API metadata, so IDE hover shows docs and `@default`), `Ui<Name>Slots`, event payloads (`@change`, `@sort`, `@select` ...) and `v-model` types. Verified failures: `size="huge"` (not assignable to `Size`), missing required prop (`options` on `UiSelect`), wrong event payload (`(p: string) => ...` on `@change` that sends a number), wrong `v-model` type, unknown slot name. `strictTemplates` is supported. Native listeners and arbitrary attributes other than `class`, `style`, `id`, `aria-*`, `data-*` are not part of the component API (the root element receives class, style, id, aria-* and data-*).
|
|
54
|
+
|
|
55
|
+
Types of shared pieces: `Size` (`'xs' | 'sm' | 'md' | 'lg' | 'xl'`), `Tone`, `Rule`, `Column`, `NavItem`.
|
|
56
|
+
|
|
57
|
+
## 2. Nuxt 3 / 4
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// nuxt.config.ts
|
|
61
|
+
export default defineNuxtConfig({
|
|
62
|
+
modules: ['@ziyarago/ui/nuxt'],
|
|
63
|
+
ziyarago: { theme: { theme: 'dark', palette: 'gold', dir: 'ltr' } }, // theme: false to disable
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The module registers all `Ui*` components (auto-import, typed through the generated `.nuxt/components.d.ts`), pushes `@ziyarago/ui/style.css`, adds `data-theme`, `data-palette`, `dir` to `<html>` during SSR and the no-flash init script in `<head>`. Do not add the unplugin resolver in Nuxt. Verified: `nuxt build` from a tarball, SSR output contains the components, `<html data-theme="dark" data-palette="gold" dir="ltr">`.
|
|
68
|
+
|
|
69
|
+
With Tailwind in Nuxt, use the layered import from section 3: set `css: false` in `ziyarago` and import the stylesheet from your Tailwind CSS file:
|
|
70
|
+
|
|
71
|
+
```css
|
|
72
|
+
@import "tailwindcss";
|
|
73
|
+
@import "@ziyarago/ui/style.css" layer(components);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 3. Tailwind 4 coexistence
|
|
77
|
+
|
|
78
|
+
Tailwind 4 puts preflight in `@layer base` and utilities in `@layer utilities`. CSS outside any layer beats every layer, regardless of specificity. So an unlayered `@ziyarago/ui/style.css` next to Tailwind has two problems (both reproduced):
|
|
79
|
+
|
|
80
|
+
1. Utilities on our components lose: `<UiButton class="px-10 rounded-none bg-red-500">` keeps the padding, radius and background of `.zg-btn`.
|
|
81
|
+
2. Order matters: `@import "tailwindcss"; @import "@ziyarago/ui/style.css";` silently dropped the Google Fonts `@import url(...)` from our file (Manrope did not load).
|
|
82
|
+
|
|
83
|
+
Recipe (single CSS entry, Vite or Nuxt):
|
|
84
|
+
|
|
85
|
+
```css
|
|
86
|
+
@import "tailwindcss";
|
|
87
|
+
@import "@ziyarago/ui/style.css" layer(components);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Result: preflight < our styles < utilities. `class="w-48"`, `px-10`, `rounded-none`, `bg-red-500` on `UiButton`/`UiCard` all apply; the Google Fonts import is kept. Do not also import the stylesheet from `main.ts`.
|
|
91
|
+
|
|
92
|
+
Put `class="zg-root"` on your app root (`<div id="app" class="zg-root">` or body). It sets font, text color, background and the reduced-motion rule.
|
|
93
|
+
|
|
94
|
+
### Conflicts found and fixed on our side
|
|
95
|
+
|
|
96
|
+
Compared computed styles of every element of every documented example (182 components, 1061 examples) with and without Tailwind 4 preflight. Before the fix about 10 500 elements differed; the causes and fixes (all in `src/styles/components.css`, zero specificity via `:where`, so any class, utility or app rule overrides them):
|
|
97
|
+
|
|
98
|
+
- `line-height`: preflight sets 1.5 on `html`; components were designed with `normal`. Now `normal` on `.zg-root` and `zg-*` elements. Without this heights drifted 2-13 px (tables, cards, boards).
|
|
99
|
+
- Form controls: without preflight the browser defaults leaked (inputs black text and white background on the dark theme, Arial font, 13px, UA padding). Now `font`, `color`, `letter-spacing`, `margin`, `padding` are inherited/reset and the background is transparent inside `zg-*` components. This also fixes the same bugs for apps without Tailwind.
|
|
100
|
+
- `box-sizing: border-box` for zg elements even outside `.zg-root` (preflight did it globally, a plain app did not).
|
|
101
|
+
- `svg { vertical-align }` baseline gap and classless links (`LoginForm` forgot link lost its underline under preflight) normalized.
|
|
102
|
+
- Rich text editor content: preflight removes `p` margins, list bullets and heading sizes; defaults restored in `.zg-rte__c`.
|
|
103
|
+
- `all: unset` rules (accordion headers, menu items, tree nodes, ...) are fine: they live in the same layer as the rest of our CSS, so they still win over preflight and still lose to utilities.
|
|
104
|
+
- `--zg-*` custom properties do not collide with Tailwind's `--color-*`, `--spacing`, `--font-*`.
|
|
105
|
+
|
|
106
|
+
After the fix the remaining differences between the two setups are `appearance: button`, `img { max-width: 100% }`, `svg { display: block }` and running animation frames; none is visible.
|
|
107
|
+
|
|
108
|
+
Fonts: `style.css` pulls Manrope and JetBrains Mono from Google Fonts with an `@import url(...)`, which must be the first statement of the final CSS. If your build moves it (or you self-host), load the fonts yourself (for example `@fontsource-variable/manrope`) and keep `--zg-font` in sync. Thmanyah (Arabic) ships inside the package (`assets/fonts`).
|
|
109
|
+
|
|
110
|
+
## 4. vue-i18n, pinia, vue-router
|
|
111
|
+
|
|
112
|
+
- vue-i18n: components do not read any i18n instance. Built-in strings are English for now ("Copy", "Sign in", "Mark all read" ...). Every text has an override prop, usually `labels` or a `*Label` prop (see the API tables), so wire them yourself: `<UiLoginForm :labels="{ email: t('auth.email'), ... }" />`. `useUiTheme().setLocale('ar')` only flips `dir` (rtl for `ar`).
|
|
113
|
+
- pinia, vue-router: no interaction. State is held in your store; components are controlled via props and `v-model`.
|
|
114
|
+
|
|
115
|
+
## 5. SSR
|
|
116
|
+
|
|
117
|
+
- Components render on the server (verified with Nuxt and Next). Overlays use a portal and render nothing on the server.
|
|
118
|
+
- Theme: the init script applies the saved theme before first paint. Nuxt does it for you. For any other SSR setup, inline `themeInitScript` (exported from `@ziyarago/ui/theme`) in `<head>`.
|
|
119
|
+
- `useUiTheme()` reads `localStorage` on the client. Do not render its values into markup during the first render (hydration mismatch); read them in `onMounted` / `useEffect` or in event handlers.
|
|
120
|
+
|
|
121
|
+
## 6. React / Next.js (App Router)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
npm i @ziyarago/ui react react-dom
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`src/react/index.js` starts with `'use client'`, so the components can be imported from server components and client components alike (verified with `next build` of Next 15.x, SSR HTML contains the markup). The adapter uses explicit named exports (`export const UiButton = ...`) because Next reads the export names of a client module statically; a destructured export list is reported as "not exported".
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
// app/layout.tsx
|
|
131
|
+
import type { ReactNode } from 'react';
|
|
132
|
+
import '@ziyarago/ui/style.css';
|
|
133
|
+
import { themeInitScript } from '@ziyarago/ui/theme';
|
|
134
|
+
|
|
135
|
+
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
136
|
+
return (
|
|
137
|
+
<html lang="en" data-theme="dark" data-palette="gold" suppressHydrationWarning>
|
|
138
|
+
<head><script dangerouslySetInnerHTML={{ __html: themeInitScript }} /></head>
|
|
139
|
+
<body className="zg-root">{children}</body>
|
|
140
|
+
</html>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`suppressHydrationWarning` is needed because the script changes `data-theme`, `dir` and friends before React hydrates. Toggle the theme from a client component: `'use client'; import { useUiTheme } from '@ziyarago/ui/theme'; ... useUiTheme().toggleTheme()`.
|
|
146
|
+
|
|
147
|
+
With Tailwind 4 in Next, use the same layered import as in section 3 in `globals.css`.
|
|
148
|
+
|
|
149
|
+
React types: `Ui<Name>Props` (props, callbacks, named slots as `ReactNode` props, `children`), components are `ComponentType<Ui<Name>Props>`. Event props are `onChange`, `onClick` (`React.MouseEvent<HTMLElement>`), `onSort` ...
|
|
150
|
+
|
|
151
|
+
## 7. Checking the types yourself
|
|
152
|
+
|
|
153
|
+
`npm run test:types` in this repository runs vue-tsc and tsc over `tests/types/*`: valid usage must compile, invalid enum / missing required prop / wrong event payload / wrong model type / unknown slot / wrong slot type must fail with the expected message.
|