@nqlib/nqui 0.4.1 → 0.4.2

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 (83) hide show
  1. package/INSTALLATION.md +215 -0
  2. package/README.md +2 -1
  3. package/dist/command-palette-BuYcxPCc.cjs +5 -0
  4. package/dist/command-palette-dEJ9aEk4.js +694 -0
  5. package/dist/command.cjs.js +1 -1
  6. package/dist/command.es.js +1 -1
  7. package/dist/components/custom/enhanced-badge.d.ts +1 -1
  8. package/dist/components/custom/enhanced-button.d.ts +6 -1
  9. package/dist/components/custom/enhanced-button.d.ts.map +1 -1
  10. package/dist/components/custom/enhanced-checkbox.d.ts +11 -0
  11. package/dist/components/custom/enhanced-checkbox.d.ts.map +1 -1
  12. package/dist/components/custom/enhanced-radio-group.d.ts +13 -4
  13. package/dist/components/custom/enhanced-radio-group.d.ts.map +1 -1
  14. package/dist/components/custom/enhanced-sonner.d.ts +5 -6
  15. package/dist/components/custom/enhanced-sonner.d.ts.map +1 -1
  16. package/dist/components/custom/enhanced-tabs.d.ts.map +1 -1
  17. package/dist/components/error-boundary.d.ts +20 -0
  18. package/dist/components/error-boundary.d.ts.map +1 -0
  19. package/dist/components/index.d.ts +102 -0
  20. package/dist/components/index.d.ts.map +1 -0
  21. package/dist/components/ui/badge.d.ts +1 -1
  22. package/dist/components/ui/button.d.ts +1 -1
  23. package/dist/components/ui/checkbox.d.ts +4 -1
  24. package/dist/components/ui/checkbox.d.ts.map +1 -1
  25. package/dist/components/ui/input-group.d.ts +1 -1
  26. package/dist/components/ui/input-group.d.ts.map +1 -1
  27. package/dist/components/ui/radio-group.d.ts +3 -1
  28. package/dist/components/ui/radio-group.d.ts.map +1 -1
  29. package/dist/components/ui/sidebar.d.ts.map +1 -1
  30. package/dist/debug-panel-AjzBdMMz.js +9198 -0
  31. package/dist/debug-panel-NaOmD68t.cjs +171 -0
  32. package/dist/debug.cjs.js +1 -0
  33. package/dist/debug.es.js +7 -0
  34. package/dist/drawer-Cqq0Ozb2.cjs +1 -0
  35. package/dist/{drawer-CU4lkcz7.js → drawer-pUXPg3lF.js} +2 -2
  36. package/dist/drawer.cjs.js +1 -1
  37. package/dist/drawer.es.js +1 -1
  38. package/dist/entries/debug.d.ts +14 -0
  39. package/dist/entries/debug.d.ts.map +1 -0
  40. package/dist/hooks/use-mobile.d.ts.map +1 -1
  41. package/dist/hooks/use-scroll-spy.d.ts.map +1 -1
  42. package/dist/index-CI756mSv.cjs +41 -0
  43. package/dist/index-CgfzsUO6.js +1069 -0
  44. package/dist/index.d.ts +2 -98
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/lib/index.d.ts +9 -0
  47. package/dist/lib/index.d.ts.map +1 -0
  48. package/dist/nqui.cjs.js +42 -212
  49. package/dist/nqui.es.js +8589 -17780
  50. package/dist/sonner-BtzU00r3.js +248 -0
  51. package/dist/sonner-Dfk26eds.cjs +54 -0
  52. package/dist/sonner.cjs.js +1 -1
  53. package/dist/sonner.es.js +1 -1
  54. package/dist/styles.css +3 -0
  55. package/docs/components/README.md +99 -1
  56. package/docs/components/nqui-card.md +7 -0
  57. package/docs/components/nqui-checkbox.md +23 -1
  58. package/docs/components/nqui-radio-group.md +45 -2
  59. package/docs/components/nqui-tabs.md +11 -1
  60. package/docs/nqui-skills/SKILL.md +95 -0
  61. package/docs/nqui-skills/design-system.md +130 -0
  62. package/docs/nqui-skills/rules/composition.md +183 -0
  63. package/docs/nqui-skills/rules/forms.md +190 -0
  64. package/docs/nqui-skills/rules/icons.md +158 -0
  65. package/docs/nqui-skills/rules/styling.md +192 -0
  66. package/package.json +23 -10
  67. package/scripts/cli.js +1 -0
  68. package/scripts/download-skills.js +91 -0
  69. package/scripts/examples/nextjs-layout-sidebar.tsx +100 -0
  70. package/scripts/examples/nextjs-page-sidebar.tsx +81 -0
  71. package/scripts/examples/vite-app.tsx +135 -0
  72. package/scripts/examples/vite-main.tsx +17 -0
  73. package/scripts/examples.js +92 -6
  74. package/scripts/generate-docs.js +169 -0
  75. package/scripts/init-css.js +34 -14
  76. package/scripts/init-cursor.js +8 -0
  77. package/scripts/post-install.js +41 -9
  78. package/scripts/wizard.js +12 -7
  79. package/dist/command-palette-UHk8zZOg.cjs +0 -45
  80. package/dist/command-palette-d-TrdBsM.js +0 -1778
  81. package/dist/drawer-BcIxWRN8.cjs +0 -1
  82. package/dist/sonner-Co6YpYVs.js +0 -546
  83. package/dist/sonner-DbQhVp8m.cjs +0 -330
@@ -0,0 +1,248 @@
1
+ import { jsx as o } from "react/jsx-runtime";
2
+ import { Toaster as x } from "sonner";
3
+ import { HugeiconsIcon as r } from "@hugeicons/react";
4
+ import { Loading03Icon as b, MultiplicationSignCircleIcon as w, Alert02Icon as y, InformationCircleIcon as k, CheckmarkCircle02Icon as N } from "@hugeicons/core-free-icons";
5
+ import * as d from "react";
6
+ var C = (t, n, c, a, l, s, u, p) => {
7
+ let i = document.documentElement, g = ["light", "dark"];
8
+ function m(e) {
9
+ (Array.isArray(t) ? t : [t]).forEach((h) => {
10
+ let f = h === "class", T = f && s ? l.map((v) => s[v] || v) : l;
11
+ f ? (i.classList.remove(...T), i.classList.add(s && s[e] ? s[e] : e)) : i.setAttribute(h, e);
12
+ }), W(e);
13
+ }
14
+ function W(e) {
15
+ p && g.includes(e) && (i.style.colorScheme = e);
16
+ }
17
+ function z() {
18
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
19
+ }
20
+ if (a) m(a);
21
+ else try {
22
+ let e = localStorage.getItem(n) || c, h = u && e === "system" ? z() : e;
23
+ m(h);
24
+ } catch {
25
+ }
26
+ }, E = d.createContext(void 0), S = { setTheme: (t) => {
27
+ }, themes: [] }, I = () => {
28
+ var t;
29
+ return (t = d.useContext(E)) != null ? t : S;
30
+ };
31
+ d.memo(({ forcedTheme: t, storageKey: n, attribute: c, enableSystem: a, enableColorScheme: l, defaultTheme: s, value: u, themes: p, nonce: i, scriptProps: g }) => {
32
+ let m = JSON.stringify([c, n, s, t, p, u, a, l]).slice(1, -1);
33
+ return d.createElement("script", { ...g, suppressHydrationWarning: !0, nonce: typeof window > "u" ? i : "", dangerouslySetInnerHTML: { __html: `(${C.toString()})(${m})` } });
34
+ });
35
+ const L = ({ ...t }) => {
36
+ const { theme: n = "system" } = I();
37
+ return d.useEffect(() => {
38
+ const c = "enhanced-toast-styles";
39
+ if (document.getElementById(c)) return;
40
+ const a = document.createElement("style");
41
+ a.id = c, a.textContent = `
42
+ /* Toast Base - Card-style design */
43
+ [data-sonner-toast] .enhanced-cn-toast {
44
+ border: 1px solid color-mix(in oklch, var(--border) 50%, transparent) !important;
45
+ box-shadow:
46
+ 0 1px 0 0 color-mix(in oklch, var(--border) 40%, transparent),
47
+ 0 1px 2px 0 oklch(0.15 0 0 / 0.05);
48
+ border-radius: var(--border-radius) !important;
49
+ transition: all 200ms ease-in-out !important;
50
+ }
51
+
52
+ .dark [data-sonner-toast] .enhanced-cn-toast {
53
+ box-shadow:
54
+ 0 1px 0 0 color-mix(in oklch, var(--border) 40%, transparent),
55
+ 0 1px 2px 0 oklch(0 0 0 / 0.3);
56
+ }
57
+
58
+ /* Success toast */
59
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-success {
60
+ border-left-width: 3px !important;
61
+ border-left-color: var(--success-500) !important;
62
+ }
63
+
64
+ /* Error toast */
65
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-error {
66
+ border-left-width: 3px !important;
67
+ border-left-color: var(--danger-500) !important;
68
+ }
69
+
70
+ /* Warning toast */
71
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-warning {
72
+ border-left-width: 3px !important;
73
+ border-left-color: var(--warning-500) !important;
74
+ }
75
+
76
+ /* Info toast */
77
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-info {
78
+ border-left-width: 3px !important;
79
+ border-left-color: var(--info-500) !important;
80
+ }
81
+
82
+ /* Loading toast */
83
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-loading {
84
+ border-left-width: 3px !important;
85
+ border-left-color: var(--primary-500) !important;
86
+ }
87
+
88
+ /* Icon colors */
89
+ .enhanced-cn-toast .toast-icon-success { color: var(--success); }
90
+ .enhanced-cn-toast .toast-icon-error { color: var(--destructive); }
91
+ .enhanced-cn-toast .toast-icon-warning { color: var(--warning); }
92
+ .enhanced-cn-toast .toast-icon-info { color: var(--info); }
93
+ .enhanced-cn-toast .toast-icon-loading { color: var(--primary); }
94
+ `, document.head.appendChild(a);
95
+ }, []), /* @__PURE__ */ o(
96
+ x,
97
+ {
98
+ theme: n,
99
+ className: "toaster group",
100
+ icons: {
101
+ success: /* @__PURE__ */ o(
102
+ r,
103
+ {
104
+ icon: N,
105
+ strokeWidth: 2,
106
+ className: "size-4 text-success toast-icon-success"
107
+ }
108
+ ),
109
+ info: /* @__PURE__ */ o(
110
+ r,
111
+ {
112
+ icon: k,
113
+ strokeWidth: 2,
114
+ className: "size-4 text-info toast-icon-info"
115
+ }
116
+ ),
117
+ warning: /* @__PURE__ */ o(
118
+ r,
119
+ {
120
+ icon: y,
121
+ strokeWidth: 2,
122
+ className: "size-4 text-warning toast-icon-warning"
123
+ }
124
+ ),
125
+ error: /* @__PURE__ */ o(
126
+ r,
127
+ {
128
+ icon: w,
129
+ strokeWidth: 2,
130
+ className: "size-4 text-destructive toast-icon-error"
131
+ }
132
+ ),
133
+ loading: /* @__PURE__ */ o(
134
+ r,
135
+ {
136
+ icon: b,
137
+ strokeWidth: 2,
138
+ className: "size-4 text-primary toast-icon-loading animate-spin"
139
+ }
140
+ )
141
+ },
142
+ style: {
143
+ "--normal-bg": "var(--popover)",
144
+ "--normal-text": "var(--popover-foreground)",
145
+ "--normal-border": "var(--border)",
146
+ "--border-radius": "var(--radius)"
147
+ },
148
+ toastOptions: {
149
+ classNames: {
150
+ toast: "enhanced-cn-toast",
151
+ success: "enhanced-toast-success",
152
+ error: "enhanced-toast-error",
153
+ warning: "enhanced-toast-warning",
154
+ info: "enhanced-toast-info",
155
+ loading: "enhanced-toast-loading"
156
+ }
157
+ },
158
+ ...t
159
+ }
160
+ );
161
+ };
162
+ L.displayName = "EnhancedToaster";
163
+ const $ = ({ ...t }) => {
164
+ const { theme: n = "system" } = I();
165
+ return /* @__PURE__ */ o(
166
+ x,
167
+ {
168
+ theme: n,
169
+ className: "toaster group",
170
+ icons: {
171
+ success: /* @__PURE__ */ o(
172
+ r,
173
+ {
174
+ icon: N,
175
+ strokeWidth: 2,
176
+ className: "size-4 text-success toast-icon-success"
177
+ }
178
+ ),
179
+ info: /* @__PURE__ */ o(
180
+ r,
181
+ {
182
+ icon: k,
183
+ strokeWidth: 2,
184
+ className: "size-4 text-info toast-icon-info"
185
+ }
186
+ ),
187
+ warning: /* @__PURE__ */ o(
188
+ r,
189
+ {
190
+ icon: y,
191
+ strokeWidth: 2,
192
+ className: "size-4 text-warning toast-icon-warning"
193
+ }
194
+ ),
195
+ error: /* @__PURE__ */ o(
196
+ r,
197
+ {
198
+ icon: w,
199
+ strokeWidth: 2,
200
+ className: "size-4 text-destructive toast-icon-error"
201
+ }
202
+ ),
203
+ loading: /* @__PURE__ */ o(
204
+ r,
205
+ {
206
+ icon: b,
207
+ strokeWidth: 2,
208
+ className: "size-4 text-primary toast-icon-loading animate-spin"
209
+ }
210
+ )
211
+ },
212
+ style: {
213
+ "--normal-bg": "var(--popover)",
214
+ "--normal-text": "var(--popover-foreground)",
215
+ "--normal-border": "var(--border)",
216
+ "--border-radius": "var(--radius)",
217
+ "--success-bg": "var(--success)",
218
+ "--success-text": "var(--success-foreground)",
219
+ "--success-border": "var(--success-400)",
220
+ "--error-bg": "var(--destructive)",
221
+ "--error-text": "var(--destructive-foreground)",
222
+ "--error-border": "var(--danger-400)",
223
+ "--warning-bg": "var(--warning)",
224
+ "--warning-text": "var(--warning-foreground)",
225
+ "--warning-border": "var(--warning-400)",
226
+ "--info-bg": "var(--info)",
227
+ "--info-text": "var(--info-foreground)",
228
+ "--info-border": "var(--info-400)"
229
+ },
230
+ toastOptions: {
231
+ classNames: {
232
+ toast: "cn-toast",
233
+ success: "toast-success",
234
+ error: "toast-error",
235
+ warning: "toast-warning",
236
+ info: "toast-info",
237
+ loading: "toast-loading"
238
+ }
239
+ },
240
+ ...t
241
+ }
242
+ );
243
+ };
244
+ export {
245
+ L as E,
246
+ $ as T,
247
+ I as z
248
+ };
@@ -0,0 +1,54 @@
1
+ "use strict";const o=require("react/jsx-runtime"),w=require("sonner"),a=require("@hugeicons/react"),c=require("@hugeicons/core-free-icons"),N=require("react");function C(e){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(r,n,s.get?s:{enumerable:!0,get:()=>e[n]})}}return r.default=e,Object.freeze(r)}const l=C(N);var z=(e,r,n,s,u,i,h,p)=>{let d=document.documentElement,f=["light","dark"];function m(t){(Array.isArray(e)?e:[e]).forEach(g=>{let x=g==="class",j=x&&i?u.map(b=>i[b]||b):u;x?(d.classList.remove(...j),d.classList.add(i&&i[t]?i[t]:t)):d.setAttribute(g,t)}),I(t)}function I(t){p&&f.includes(t)&&(d.style.colorScheme=t)}function k(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}if(s)m(s);else try{let t=localStorage.getItem(r)||n,g=h&&t==="system"?k():t;m(g)}catch{}},S=l.createContext(void 0),T={setTheme:e=>{},themes:[]},v=()=>{var e;return(e=l.useContext(S))!=null?e:T};l.memo(({forcedTheme:e,storageKey:r,attribute:n,enableSystem:s,enableColorScheme:u,defaultTheme:i,value:h,themes:p,nonce:d,scriptProps:f})=>{let m=JSON.stringify([n,r,i,e,p,h,s,u]).slice(1,-1);return l.createElement("script",{...f,suppressHydrationWarning:!0,nonce:typeof window>"u"?d:"",dangerouslySetInnerHTML:{__html:`(${z.toString()})(${m})`}})});const y=({...e})=>{const{theme:r="system"}=v();return l.useEffect(()=>{const n="enhanced-toast-styles";if(document.getElementById(n))return;const s=document.createElement("style");s.id=n,s.textContent=`
2
+ /* Toast Base - Card-style design */
3
+ [data-sonner-toast] .enhanced-cn-toast {
4
+ border: 1px solid color-mix(in oklch, var(--border) 50%, transparent) !important;
5
+ box-shadow:
6
+ 0 1px 0 0 color-mix(in oklch, var(--border) 40%, transparent),
7
+ 0 1px 2px 0 oklch(0.15 0 0 / 0.05);
8
+ border-radius: var(--border-radius) !important;
9
+ transition: all 200ms ease-in-out !important;
10
+ }
11
+
12
+ .dark [data-sonner-toast] .enhanced-cn-toast {
13
+ box-shadow:
14
+ 0 1px 0 0 color-mix(in oklch, var(--border) 40%, transparent),
15
+ 0 1px 2px 0 oklch(0 0 0 / 0.3);
16
+ }
17
+
18
+ /* Success toast */
19
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-success {
20
+ border-left-width: 3px !important;
21
+ border-left-color: var(--success-500) !important;
22
+ }
23
+
24
+ /* Error toast */
25
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-error {
26
+ border-left-width: 3px !important;
27
+ border-left-color: var(--danger-500) !important;
28
+ }
29
+
30
+ /* Warning toast */
31
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-warning {
32
+ border-left-width: 3px !important;
33
+ border-left-color: var(--warning-500) !important;
34
+ }
35
+
36
+ /* Info toast */
37
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-info {
38
+ border-left-width: 3px !important;
39
+ border-left-color: var(--info-500) !important;
40
+ }
41
+
42
+ /* Loading toast */
43
+ [data-sonner-toast] .enhanced-cn-toast.enhanced-toast-loading {
44
+ border-left-width: 3px !important;
45
+ border-left-color: var(--primary-500) !important;
46
+ }
47
+
48
+ /* Icon colors */
49
+ .enhanced-cn-toast .toast-icon-success { color: var(--success); }
50
+ .enhanced-cn-toast .toast-icon-error { color: var(--destructive); }
51
+ .enhanced-cn-toast .toast-icon-warning { color: var(--warning); }
52
+ .enhanced-cn-toast .toast-icon-info { color: var(--info); }
53
+ .enhanced-cn-toast .toast-icon-loading { color: var(--primary); }
54
+ `,document.head.appendChild(s)},[]),o.jsx(w.Toaster,{theme:r,className:"toaster group",icons:{success:o.jsx(a.HugeiconsIcon,{icon:c.CheckmarkCircle02Icon,strokeWidth:2,className:"size-4 text-success toast-icon-success"}),info:o.jsx(a.HugeiconsIcon,{icon:c.InformationCircleIcon,strokeWidth:2,className:"size-4 text-info toast-icon-info"}),warning:o.jsx(a.HugeiconsIcon,{icon:c.Alert02Icon,strokeWidth:2,className:"size-4 text-warning toast-icon-warning"}),error:o.jsx(a.HugeiconsIcon,{icon:c.MultiplicationSignCircleIcon,strokeWidth:2,className:"size-4 text-destructive toast-icon-error"}),loading:o.jsx(a.HugeiconsIcon,{icon:c.Loading03Icon,strokeWidth:2,className:"size-4 text-primary toast-icon-loading animate-spin"})},style:{"--normal-bg":"var(--popover)","--normal-text":"var(--popover-foreground)","--normal-border":"var(--border)","--border-radius":"var(--radius)"},toastOptions:{classNames:{toast:"enhanced-cn-toast",success:"enhanced-toast-success",error:"enhanced-toast-error",warning:"enhanced-toast-warning",info:"enhanced-toast-info",loading:"enhanced-toast-loading"}},...e})};y.displayName="EnhancedToaster";const H=({...e})=>{const{theme:r="system"}=v();return o.jsx(w.Toaster,{theme:r,className:"toaster group",icons:{success:o.jsx(a.HugeiconsIcon,{icon:c.CheckmarkCircle02Icon,strokeWidth:2,className:"size-4 text-success toast-icon-success"}),info:o.jsx(a.HugeiconsIcon,{icon:c.InformationCircleIcon,strokeWidth:2,className:"size-4 text-info toast-icon-info"}),warning:o.jsx(a.HugeiconsIcon,{icon:c.Alert02Icon,strokeWidth:2,className:"size-4 text-warning toast-icon-warning"}),error:o.jsx(a.HugeiconsIcon,{icon:c.MultiplicationSignCircleIcon,strokeWidth:2,className:"size-4 text-destructive toast-icon-error"}),loading:o.jsx(a.HugeiconsIcon,{icon:c.Loading03Icon,strokeWidth:2,className:"size-4 text-primary toast-icon-loading animate-spin"})},style:{"--normal-bg":"var(--popover)","--normal-text":"var(--popover-foreground)","--normal-border":"var(--border)","--border-radius":"var(--radius)","--success-bg":"var(--success)","--success-text":"var(--success-foreground)","--success-border":"var(--success-400)","--error-bg":"var(--destructive)","--error-text":"var(--destructive-foreground)","--error-border":"var(--danger-400)","--warning-bg":"var(--warning)","--warning-text":"var(--warning-foreground)","--warning-border":"var(--warning-400)","--info-bg":"var(--info)","--info-text":"var(--info-foreground)","--info-border":"var(--info-400)"},toastOptions:{classNames:{toast:"cn-toast",success:"toast-success",error:"toast-error",warning:"toast-warning",info:"toast-info",loading:"toast-loading"}},...e})};exports.EnhancedToaster=y;exports.Toaster=H;exports.z=v;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./sonner-DbQhVp8m.cjs");exports.CoreToaster=e.Toaster;exports.EnhancedSonner=e.EnhancedToaster;exports.Toaster=e.EnhancedToaster;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./sonner-Dfk26eds.cjs");exports.CoreToaster=e.Toaster;exports.EnhancedSonner=e.EnhancedToaster;exports.Toaster=e.EnhancedToaster;
package/dist/sonner.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import { T as o, E as r, E as s } from "./sonner-Co6YpYVs.js";
1
+ import { T as o, E as r, E as s } from "./sonner-BtzU00r3.js";
2
2
  export {
3
3
  o as CoreToaster,
4
4
  r as EnhancedSonner,
package/dist/styles.css CHANGED
@@ -541,6 +541,7 @@
541
541
  position: absolute;
542
542
  z-index: 0;
543
543
  pointer-events: none;
544
+ overflow: visible;
544
545
  transition:
545
546
  left 0.3s ease-in-out,
546
547
  top 0.3s ease-in-out,
@@ -550,6 +551,8 @@
550
551
 
551
552
  .sliding-indicator-container {
552
553
  position: relative;
554
+ overflow: hidden;
555
+ min-width: 0;
553
556
  }
554
557
 
555
558
  .sliding-indicator-target {
@@ -17,7 +17,7 @@ Implementation guides for each component. **AI Skill:** Optimized for AI/LLM con
17
17
  | Dependency | Version | Notes |
18
18
  |------------|---------|-------|
19
19
  | **React** | 18+ or 19 | nqui supports React 18 and 19 via `^18.0.0 \|\| ^19.0.0` peer. |
20
- | **Tailwind CSS** | ^4.x | Required. Vite: `@tailwindcss/vite`. Next.js: `@source` directives in CSS. |
20
+ | **Tailwind CSS** | ^4.x | Required. Vite: `@tailwindcss/vite`. Both Vite and Next.js need `@source` for `node_modules/@nqlib/nqui/dist` (Tailwind does not scan node_modules). |
21
21
  | **tw-animate-css** | — | `@import "tw-animate-css"` in your CSS (added by init-css). |
22
22
  | **Radix UI** | — | Bundled (Dialog, Select, etc.). |
23
23
  | **Hugeicons** | @hugeicons/react, @hugeicons/core-free-icons | Required for icon display in components. |
@@ -41,6 +41,104 @@ Implementation guides for each component. **AI Skill:** Optimized for AI/LLM con
41
41
 
42
42
  ---
43
43
 
44
+ ## Layout & Scroll Patterns
45
+
46
+ This section documents the CSS patterns used in the showcase app to ensure proper scroll behavior and prevent sticky element issues.
47
+
48
+ ### Sticky Elements & Momentum Scroll
49
+
50
+ **The problem:** When using default body scroll, sticky elements can exhibit "momentum push" behavior during fast scrolling - they appear to float or lag before snapping back. This happens because sticky positioning is relative to the viewport, not the scroll container.
51
+
52
+ **The solution:** Use a custom scroll container instead of body/html scroll.
53
+
54
+ ```tsx
55
+ // App layout structure - prevents momentum push on sticky elements
56
+ <div className="h-screen overflow-hidden">
57
+ <header className="sticky top-0 z-[var(--z-sticky-page)]">
58
+ {/* Page header */}
59
+ </header>
60
+ <main className="flex-1 min-h-0 overflow-y-auto">
61
+ {/* Scrollable content */}
62
+ </main>
63
+ </div>
64
+ ```
65
+
66
+ ### Z-Index Layering for Sticky Elements
67
+
68
+ Use the correct z-index variables to prevent sticky element conflicts:
69
+
70
+ | Element | CSS Variable | Value |
71
+ |---------|-------------|-------|
72
+ | Page headers, navigation bars | `z-[var(--z-sticky-page)]` | 20 |
73
+ | Card headers, table headers | `z-[var(--z-sticky-content)]` | 15 |
74
+
75
+ **Rule:** Page-level sticky elements (20) must be above container-level sticky elements (15) to prevent scroll conflicts.
76
+
77
+ ### Flex Scroll Pattern
78
+
79
+ For nested scrolling to work correctly, flex children must have `min-height: 0` (or `min-h-0` in Tailwind):
80
+
81
+ ```tsx
82
+ // Correct - flex child can shrink and scroll
83
+ <div className="flex flex-col h-screen">
84
+ <header className="flex-shrink-0">...</header>
85
+ <main className="flex-1 min-h-0 overflow-y-auto">
86
+ {/* This will scroll */}
87
+ </main>
88
+ </div>
89
+
90
+ // Wrong - flex child cannot shrink below content height
91
+ <div className="flex flex-col h-screen">
92
+ <header>...</header>
93
+ <main className="flex-1 overflow-y-auto">
94
+ {/* May not scroll - overflows instead */}
95
+ </main>
96
+ </div>
97
+ ```
98
+
99
+ ### Body Scroll Prevention
100
+
101
+ For app-like experiences, disable body/html scroll:
102
+
103
+ ```tsx
104
+ useEffect(() => {
105
+ // Disable browser scroll restoration
106
+ if ('scrollRestoration' in history) {
107
+ history.scrollRestoration = 'manual'
108
+ }
109
+
110
+ // Prevent body/html from scrolling
111
+ document.body.style.overflow = 'hidden'
112
+ document.documentElement.style.overflow = 'hidden'
113
+
114
+ return () => {
115
+ document.body.style.overflow = ''
116
+ document.documentElement.style.overflow = ''
117
+ }
118
+ }, [])
119
+ ```
120
+
121
+ ### Sliding Indicator Containers
122
+
123
+ Components with sliding indicators (Tabs, RadioGroup `sliding` variant) need specific container styling:
124
+
125
+ ```tsx
126
+ // Required CSS for sliding indicator containers
127
+ .sliding-indicator-container {
128
+ position: relative;
129
+ overflow: hidden;
130
+ min-width: 0;
131
+ }
132
+
133
+ .sliding-indicator {
134
+ position: absolute;
135
+ overflow: visible;
136
+ /* transitions for smooth sliding */
137
+ }
138
+ ```
139
+
140
+ ---
141
+
44
142
  ## When to Use (Selection & Action Components)
45
143
 
46
144
  Use these rules to choose the right component. **Selection** = user picks from options. **Action** = user triggers a command.
@@ -29,3 +29,10 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }
29
29
  <CardContent>Scrollable content</CardContent>
30
30
  </Card>
31
31
  ```
32
+
33
+ ## Notes
34
+
35
+ - **stickyHeader:** Use `stickyHeader` prop on Card for scrollable content with sticky header. The header uses `--z-sticky-content` (z-index: 15).
36
+ - **Z-index layering:** Card sticky headers (15) are below page headers (20). If using in a page with sticky header, ensure proper z-index layering.
37
+ - **Height required:** Card needs a defined height (e.g., `h-[400px]` or `h-full`) for sticky behavior to work.
38
+ - **Content scroll:** The CardContent becomes scrollable when Card has `stickyHeader` and a defined height.
@@ -11,9 +11,31 @@ import { Checkbox } from "@nqlib/nqui"
11
11
  ## Basic
12
12
 
13
13
  ```tsx
14
- <Checkbox checked={checked} onCheckedChange={setChecked} />
14
+ const [checked, setChecked] = useState(false)
15
+
16
+ <Checkbox checked={checked} onCheckedChange={setChecked}>Accept terms</Checkbox>
17
+ ```
18
+
19
+ ## With Label
20
+
21
+ Checkbox automatically wraps in a label when children are provided:
22
+
23
+ ```tsx
24
+ <Checkbox>Accept terms</Checkbox>
15
25
  ```
16
26
 
27
+ ## Gap
28
+
29
+ Control the gap between checkbox and label:
30
+
31
+ ```tsx
32
+ <Checkbox gap={2}>Compact gap (8px)</Checkbox>
33
+ <Checkbox gap={3}>Default gap (12px)</Checkbox>
34
+ <Checkbox gap={4}>Loose gap (16px)</Checkbox>
35
+ ```
36
+
37
+ Options: `0`, `1`, `2`, `3`, `4` (maps to Tailwind gap-0 through gap-4).
38
+
17
39
  ## Variants
18
40
 
19
41
  ```tsx
@@ -18,13 +18,56 @@ import { RadioGroup, RadioGroupItem } from "@nqlib/nqui"
18
18
 
19
19
  ## Basic
20
20
 
21
+ RadioGroupItem now automatically wraps the radio button with a label when children are provided:
22
+
21
23
  ```tsx
24
+ const [value, setValue] = useState("a")
25
+
22
26
  <RadioGroup value={value} onValueChange={setValue}>
23
- <RadioGroupItem value="a" /> A
24
- <RadioGroupItem value="b" /> B
27
+ <RadioGroupItem value="a">Option A</RadioGroupItem>
28
+ <RadioGroupItem value="b">Option B</RadioGroupItem>
25
29
  </RadioGroup>
26
30
  ```
27
31
 
32
+ ## With Complex Content
33
+
34
+ ```tsx
35
+ <RadioGroup value={value} onValueChange={setValue}>
36
+ <RadioGroupItem value="email">
37
+ <div>
38
+ <div className="font-medium">Email</div>
39
+ <div className="text-sm text-muted-foreground">Receive notifications via email</div>
40
+ </div>
41
+ </RadioGroupItem>
42
+ <RadioGroupItem value="sms">
43
+ <div>
44
+ <div className="font-medium">SMS</div>
45
+ <div className="text-sm text-muted-foreground">Receive notifications via SMS</div>
46
+ </div>
47
+ </RadioGroupItem>
48
+ </RadioGroup>
49
+ ```
50
+
51
+ ## Spacing
52
+
53
+ Control the gap between radio items with the `gap` prop on RadioGroup:
54
+
55
+ ```tsx
56
+ <RadioGroup gap={0}>No gap</RadioGroup>
57
+ <RadioGroup gap={1}>4px gap</RadioGroup>
58
+ <RadioGroup gap={2}>Compact (8px)</RadioGroup>
59
+ <RadioGroup gap={3}>Default (12px)</RadioGroup>
60
+ <RadioGroup gap={4}>Loose (16px)</RadioGroup>
61
+ ```
62
+
63
+ Control the gap between radio button and label with the `spacing` prop on RadioGroupItem:
64
+
65
+ ```tsx
66
+ <RadioGroupItem value="a" spacing="compact">Tight spacing (8px)</RadioGroupItem>
67
+ <RadioGroupItem value="b" spacing="default">Default spacing (12px)</RadioGroupItem>
68
+ <RadioGroupItem value="c" spacing="comfortable">Loose spacing (16px)</RadioGroupItem>
69
+ ```
70
+
28
71
  ## Variants
29
72
 
30
73
  ```tsx
@@ -31,5 +31,15 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@nqlib/nqui"
31
31
 
32
32
  ## Notes
33
33
 
34
- - Sliding indicator needs `position: relative` on TabsList container.
34
+ - **Sliding indicator:** Requires `position: relative` on TabsList container (handled automatically by the component).
35
+ - **Responsive behavior:** On small screens, TabsList can overflow horizontally. Use `overflow-x-auto` on parent if needed.
36
+ - **Container requirements:** For the sliding indicator to work correctly, the TabsList container needs:
37
+ ```css
38
+ .sliding-indicator-container {
39
+ position: relative;
40
+ overflow: hidden;
41
+ min-width: 0;
42
+ }
43
+ ```
44
+ - **Resize handling:** The indicator recalculates position on window resize (built-in).
35
45
  - Use `EnhancedTabsList` props for additional customization.
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: nqui Components
3
+ description: Component implementation guide for nqui. Use when building UI, designing app layouts, or implementing components with @nqlib/nqui.
4
+ ---
5
+
6
+ # nqui Components Guide
7
+
8
+ Reference `packages/nqui/docs/components/README.md` for the full component index and implementation rules.
9
+
10
+ ## Quick Reference
11
+
12
+ 1. **Main index:** `packages/nqui/docs/components/README.md` - all components, use cases, prerequisites
13
+ 2. **Per-component:** `packages/nqui/docs/components/nqui-<name>.md` - import, examples, variants
14
+ 3. **Design system:** this folder - sizing, grouped controls
15
+
16
+ ## App Design Rule: Inline Selection → ToggleGroup
17
+
18
+ When designing app UI (toolbars, headers, inline controls):
19
+
20
+ | Context | Use | NOT |
21
+ |---------|-----|-----|
22
+ | View mode (List/Grid/Table), scale (Linear/Log), size (S/M/L) | **ToggleGroup** `type="single"` | RadioGroup |
23
+ | Format toolbar (Bold/Italic/Underline), multi-toggle | **ToggleGroup** `type="multiple"` | Multiple Checkboxes |
24
+ | Toolbar actions (Undo/Redo, align) | **ButtonGroup** | - |
25
+ | Single on/off (Bold, Mute) | **Toggle** | - |
26
+
27
+ **Rule:** Inline/toolbar selection = ToggleGroup. Use RadioGroup only for form context (settings page, modal form, stacked list).
28
+
29
+ ## App Design Rule: Context-First (Toolbar in Real Environment)
30
+
31
+ **Rule:** Never show Toggle/ToggleGroup/ButtonGroup in isolation. Always place them in realistic app context.
32
+
33
+ | Context | Layout | Reference |
34
+ |---------|--------|-----------|
35
+ | Document editor | Toolbar above content; `bg-muted/30` container; `Separator` between groups | ComponentShowcase → Toggle & ToggleGroup |
36
+ | Chart/settings | Label + inline controls; `rounded-lg border bg-muted/30 p-3` | ComponentShowcase → Chart settings |
37
+ | Standalone | Inline with related UI | ComponentShowcase → Standalone toggle |
38
+
39
+ **Canonical implementation:** `packages/nqui/src/pages/ComponentShowcase.tsx` — Toggle & ToggleGroup section.
40
+
41
+ ## Design System Conventions
42
+
43
+ ### Control Sizing
44
+ - sm = h-6
45
+ - default = h-7
46
+ - lg = h-8
47
+
48
+ ### Z-Index
49
+ Always use CSS variables from elevation.css:
50
+ - `--z-content` (10) - standard content
51
+ - `--z-sticky-content` (15) - sticky within containers
52
+ - `--z-sticky-page` (20) - page-level sticky
53
+ - `--z-floating` (30) - floating panels
54
+ - `--z-modal-backdrop` (40)
55
+ - `--z-modal` (50)
56
+ - `--z-popover` (60)
57
+ - `--z-tooltip` (70)
58
+
59
+ ### Component Naming
60
+ - Enhanced vs Core: default is enhanced; use Core* for plain
61
+ - File names: kebab-case
62
+ - Component names: PascalCase
63
+
64
+ ## Key Dependencies
65
+
66
+ Required peer dependencies:
67
+ - `@hugeicons/react`
68
+ - `@hugeicons/core-free-icons`
69
+
70
+ Optional:
71
+ - `next-themes` - for theme toggle
72
+ - `tw-animate-css` - for animations
73
+
74
+ ## Installation & Setup
75
+
76
+ ```bash
77
+ # Quick setup
78
+ npx @nqlib/nqui init-css
79
+
80
+ # App setup with sidebar
81
+ npx @nqlib/nqui init-css --sidebar
82
+
83
+ # Install peer dependencies
84
+ npx @nqlib/nqui install-peers
85
+ ```
86
+
87
+ ## CSS Variables
88
+
89
+ All components use CSS variables. Key ones:
90
+ - `--background`, `--foreground`
91
+ - `--muted`, `--muted-foreground`
92
+ - `--accent`, `--accent-foreground`
93
+ - `--border`, `--ring`
94
+ - `--primary`, `--primary-foreground`
95
+ - `--destructive`, `--destructive-foreground`