@srcroot/ui 0.0.30 → 0.0.33

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 (77) hide show
  1. package/dist/index.js +426 -594
  2. package/package.json +10 -9
  3. package/src/registry/analytics/google-analytics.tsx +36 -0
  4. package/src/registry/analytics/google-tag-manager.tsx +62 -0
  5. package/src/registry/analytics/meta-pixel.tsx +44 -0
  6. package/src/registry/analytics/microsoft-clarity.tsx +31 -0
  7. package/src/registry/analytics/tiktok-pixel.tsx +34 -0
  8. package/src/registry/lib/utils.ts +6 -0
  9. package/src/registry/themes/gradients.css +236 -0
  10. package/{registry/themes → src/registry/themes/v3}/gray.css +45 -1
  11. package/{registry/themes → src/registry/themes/v3}/neutral.css +45 -1
  12. package/{registry/themes → src/registry/themes/v3}/slate.css +45 -1
  13. package/{registry/themes → src/registry/themes/v3}/stone.css +45 -1
  14. package/{registry/themes → src/registry/themes/v3}/zinc.css +45 -1
  15. package/src/registry/themes/v4/gray.css +183 -0
  16. package/src/registry/themes/v4/neutral.css +183 -0
  17. package/src/registry/themes/v4/slate.css +183 -0
  18. package/src/registry/themes/v4/stone.css +183 -0
  19. package/src/registry/themes/v4/zinc.css +183 -0
  20. package/src/registry/ui/chatbot.tsx +96 -0
  21. package/registry/design-tokens.css +0 -217
  22. package/registry/themes/index.css +0 -19
  23. /package/{registry → src/registry/ui}/accordion.tsx +0 -0
  24. /package/{registry → src/registry/ui}/alert-dialog.tsx +0 -0
  25. /package/{registry → src/registry/ui}/alert.tsx +0 -0
  26. /package/{registry → src/registry/ui}/aspect-ratio.tsx +0 -0
  27. /package/{registry → src/registry/ui}/avatar.tsx +0 -0
  28. /package/{registry → src/registry/ui}/badge.tsx +0 -0
  29. /package/{registry → src/registry/ui}/breadcrumb.tsx +0 -0
  30. /package/{registry → src/registry/ui}/button-group.tsx +0 -0
  31. /package/{registry → src/registry/ui}/button.tsx +0 -0
  32. /package/{registry → src/registry/ui}/calendar.tsx +0 -0
  33. /package/{registry → src/registry/ui}/card.tsx +0 -0
  34. /package/{registry → src/registry/ui}/carousel.tsx +0 -0
  35. /package/{registry → src/registry/ui}/checkbox.tsx +0 -0
  36. /package/{registry → src/registry/ui}/collapsible.tsx +0 -0
  37. /package/{registry → src/registry/ui}/combobox.tsx +0 -0
  38. /package/{registry → src/registry/ui}/command.tsx +0 -0
  39. /package/{registry → src/registry/ui}/container.tsx +0 -0
  40. /package/{registry → src/registry/ui}/context-menu.tsx +0 -0
  41. /package/{registry → src/registry/ui}/date-picker.tsx +0 -0
  42. /package/{registry → src/registry/ui}/dialog.tsx +0 -0
  43. /package/{registry → src/registry/ui}/drawer.tsx +0 -0
  44. /package/{registry → src/registry/ui}/dropdown-menu.tsx +0 -0
  45. /package/{registry → src/registry/ui}/file-upload.tsx +0 -0
  46. /package/{registry → src/registry/ui}/hover-card.tsx +0 -0
  47. /package/{registry → src/registry/ui}/image.tsx +0 -0
  48. /package/{registry → src/registry/ui}/input.tsx +0 -0
  49. /package/{registry → src/registry/ui}/kbd.tsx +0 -0
  50. /package/{registry → src/registry/ui}/label.tsx +0 -0
  51. /package/{registry → src/registry/ui}/loading-spinner.tsx +0 -0
  52. /package/{registry → src/registry/ui}/menubar.tsx +0 -0
  53. /package/{registry → src/registry/ui}/native-select.tsx +0 -0
  54. /package/{registry → src/registry/ui}/otp-input.tsx +0 -0
  55. /package/{registry → src/registry/ui}/pagination.tsx +0 -0
  56. /package/{registry → src/registry/ui}/popover.tsx +0 -0
  57. /package/{registry → src/registry/ui}/progress.tsx +0 -0
  58. /package/{registry → src/registry/ui}/radio.tsx +0 -0
  59. /package/{registry → src/registry/ui}/resizable.tsx +0 -0
  60. /package/{registry → src/registry/ui}/scroll-area.tsx +0 -0
  61. /package/{registry → src/registry/ui}/search.tsx +0 -0
  62. /package/{registry → src/registry/ui}/select.tsx +0 -0
  63. /package/{registry → src/registry/ui}/separator.tsx +0 -0
  64. /package/{registry → src/registry/ui}/sheet.tsx +0 -0
  65. /package/{registry → src/registry/ui}/sidebar.tsx +0 -0
  66. /package/{registry → src/registry/ui}/skeleton.tsx +0 -0
  67. /package/{registry → src/registry/ui}/slider.tsx +0 -0
  68. /package/{registry → src/registry/ui}/star-rating.tsx +0 -0
  69. /package/{registry → src/registry/ui}/switch.tsx +0 -0
  70. /package/{registry → src/registry/ui}/table.tsx +0 -0
  71. /package/{registry → src/registry/ui}/tabs.tsx +0 -0
  72. /package/{registry → src/registry/ui}/text.tsx +0 -0
  73. /package/{registry → src/registry/ui}/textarea.tsx +0 -0
  74. /package/{registry → src/registry/ui}/toast.tsx +0 -0
  75. /package/{registry → src/registry/ui}/toggle-group.tsx +0 -0
  76. /package/{registry → src/registry/ui}/toggle.tsx +0 -0
  77. /package/{registry → src/registry/ui}/tooltip.tsx +0 -0
package/dist/index.js CHANGED
@@ -2,425 +2,73 @@
2
2
 
3
3
  // src/cli/index.ts
4
4
  import { Command } from "commander";
5
+ import chalk3 from "chalk";
5
6
 
6
- // src/cli/commands/init.ts
7
- import fs from "fs-extra";
8
- import path from "path";
9
- import chalk from "chalk";
7
+ // src/cli/services/project-initializer.ts
8
+ import fs2 from "fs-extra";
9
+ import path2 from "path";
10
10
  import ora from "ora";
11
11
  import prompts from "prompts";
12
+ import { fileURLToPath as fileURLToPath2 } from "url";
13
+
14
+ // src/cli/services/theme-service.ts
15
+ import fs from "fs-extra";
16
+ import path from "path";
12
17
  import { fileURLToPath } from "url";
13
18
  var __dirname = path.dirname(fileURLToPath(import.meta.url));
14
- var UTILS_CONTENT = `import { type ClassValue, clsx } from "clsx"
15
- import { twMerge } from "tailwind-merge"
16
-
17
- export function cn(...inputs: ClassValue[]) {
18
- return twMerge(clsx(inputs))
19
- }
20
- `;
21
- var THEMES = {
22
- slate: {
23
- name: "Slate",
24
- description: "Cool gray with strong blue undertones (default)",
25
- light: {
26
- background: "0 0% 100%",
27
- foreground: "222.2 84% 4.9%",
28
- card: "0 0% 100%",
29
- "card-foreground": "222.2 84% 4.9%",
30
- popover: "0 0% 100%",
31
- "popover-foreground": "222.2 84% 4.9%",
32
- primary: "222.2 47.4% 11.2%",
33
- "primary-foreground": "210 40% 98%",
34
- secondary: "210 40% 96.1%",
35
- "secondary-foreground": "222.2 47.4% 11.2%",
36
- muted: "210 40% 96.1%",
37
- "muted-foreground": "215.4 16.3% 46.9%",
38
- accent: "210 40% 96.1%",
39
- "accent-foreground": "222.2 47.4% 11.2%",
40
- destructive: "0 84.2% 60.2%",
41
- "destructive-foreground": "210 40% 98%",
42
- border: "214.3 31.8% 91.4%",
43
- input: "214.3 31.8% 91.4%",
44
- ring: "222.2 84% 4.9%"
45
- },
46
- dark: {
47
- background: "222.2 84% 4.9%",
48
- foreground: "210 40% 98%",
49
- card: "222.2 84% 4.9%",
50
- "card-foreground": "210 40% 98%",
51
- popover: "222.2 84% 4.9%",
52
- "popover-foreground": "210 40% 98%",
53
- primary: "210 40% 98%",
54
- "primary-foreground": "222.2 47.4% 11.2%",
55
- secondary: "217.2 32.6% 17.5%",
56
- "secondary-foreground": "210 40% 98%",
57
- muted: "217.2 32.6% 17.5%",
58
- "muted-foreground": "215 20.2% 65.1%",
59
- accent: "217.2 32.6% 17.5%",
60
- "accent-foreground": "210 40% 98%",
61
- destructive: "0 62.8% 30.6%",
62
- "destructive-foreground": "210 40% 98%",
63
- border: "217.2 32.6% 17.5%",
64
- input: "217.2 32.6% 17.5%",
65
- ring: "212.7 26.8% 83.9%"
66
- }
67
- },
68
- neutral: {
69
- name: "Neutral",
70
- description: "Pure gray, no undertones",
71
- light: {
72
- background: "0 0% 100%",
73
- foreground: "0 0% 3.9%",
74
- card: "0 0% 100%",
75
- "card-foreground": "0 0% 3.9%",
76
- popover: "0 0% 100%",
77
- "popover-foreground": "0 0% 3.9%",
78
- primary: "0 0% 9%",
79
- "primary-foreground": "0 0% 98%",
80
- secondary: "0 0% 96.1%",
81
- "secondary-foreground": "0 0% 9%",
82
- muted: "0 0% 96.1%",
83
- "muted-foreground": "0 0% 45.1%",
84
- accent: "0 0% 96.1%",
85
- "accent-foreground": "0 0% 9%",
86
- destructive: "0 84.2% 60.2%",
87
- "destructive-foreground": "0 0% 98%",
88
- border: "0 0% 89.8%",
89
- input: "0 0% 89.8%",
90
- ring: "0 0% 3.9%"
91
- },
92
- dark: {
93
- background: "0 0% 3.9%",
94
- foreground: "0 0% 98%",
95
- card: "0 0% 3.9%",
96
- "card-foreground": "0 0% 98%",
97
- popover: "0 0% 3.9%",
98
- "popover-foreground": "0 0% 98%",
99
- primary: "0 0% 98%",
100
- "primary-foreground": "0 0% 9%",
101
- secondary: "0 0% 14.9%",
102
- "secondary-foreground": "0 0% 98%",
103
- muted: "0 0% 14.9%",
104
- "muted-foreground": "0 0% 63.9%",
105
- accent: "0 0% 14.9%",
106
- "accent-foreground": "0 0% 98%",
107
- destructive: "0 62.8% 30.6%",
108
- "destructive-foreground": "0 0% 98%",
109
- border: "0 0% 14.9%",
110
- input: "0 0% 14.9%",
111
- ring: "0 0% 83.1%"
112
- }
113
- },
114
- stone: {
115
- name: "Stone",
116
- description: "Warm gray with brown undertones",
117
- light: {
118
- background: "0 0% 100%",
119
- foreground: "24 9.8% 10%",
120
- card: "0 0% 100%",
121
- "card-foreground": "24 9.8% 10%",
122
- popover: "0 0% 100%",
123
- "popover-foreground": "24 9.8% 10%",
124
- primary: "24 9.8% 10%",
125
- "primary-foreground": "60 9.1% 97.8%",
126
- secondary: "60 4.8% 95.9%",
127
- "secondary-foreground": "24 9.8% 10%",
128
- muted: "60 4.8% 95.9%",
129
- "muted-foreground": "25 5.3% 44.7%",
130
- accent: "60 4.8% 95.9%",
131
- "accent-foreground": "24 9.8% 10%",
132
- destructive: "0 84.2% 60.2%",
133
- "destructive-foreground": "60 9.1% 97.8%",
134
- border: "20 5.9% 90%",
135
- input: "20 5.9% 90%",
136
- ring: "24 9.8% 10%"
137
- },
138
- dark: {
139
- background: "24 9.8% 10%",
140
- foreground: "60 9.1% 97.8%",
141
- card: "24 9.8% 10%",
142
- "card-foreground": "60 9.1% 97.8%",
143
- popover: "24 9.8% 10%",
144
- "popover-foreground": "60 9.1% 97.8%",
145
- primary: "60 9.1% 97.8%",
146
- "primary-foreground": "24 9.8% 10%",
147
- secondary: "12 6.5% 15.1%",
148
- "secondary-foreground": "60 9.1% 97.8%",
149
- muted: "12 6.5% 15.1%",
150
- "muted-foreground": "24 5.4% 63.9%",
151
- accent: "12 6.5% 15.1%",
152
- "accent-foreground": "60 9.1% 97.8%",
153
- destructive: "0 62.8% 30.6%",
154
- "destructive-foreground": "60 9.1% 97.8%",
155
- border: "12 6.5% 15.1%",
156
- input: "12 6.5% 15.1%",
157
- ring: "24 5.7% 82.9%"
19
+ var THEME_METADATA = {
20
+ slate: { name: "Slate", description: "Cool gray with strong blue undertones (default)" },
21
+ neutral: { name: "Neutral", description: "Pure gray, no undertones" },
22
+ stone: { name: "Stone", description: "Warm gray with brown undertones" },
23
+ zinc: { name: "Zinc", description: "Cool gray with subtle blue undertones" },
24
+ gray: { name: "Gray", description: "True neutral gray" }
25
+ };
26
+ var ThemeService = class {
27
+ registryThemesPath;
28
+ constructor() {
29
+ this.registryThemesPath = path.resolve(__dirname, "..", "src", "registry", "themes");
30
+ }
31
+ /**
32
+ * Get list of available themes from registry/themes/v3/*.css (v3 as primary source)
33
+ */
34
+ getAvailableThemes() {
35
+ const themes = [];
36
+ const v3Path = path.join(this.registryThemesPath, "v3");
37
+ if (!fs.existsSync(v3Path)) {
38
+ return themes;
158
39
  }
159
- },
160
- zinc: {
161
- name: "Zinc",
162
- description: "Cool gray with subtle blue undertones",
163
- light: {
164
- background: "0 0% 100%",
165
- foreground: "240 10% 3.9%",
166
- card: "0 0% 100%",
167
- "card-foreground": "240 10% 3.9%",
168
- popover: "0 0% 100%",
169
- "popover-foreground": "240 10% 3.9%",
170
- primary: "240 5.9% 10%",
171
- "primary-foreground": "0 0% 98%",
172
- secondary: "240 4.8% 95.9%",
173
- "secondary-foreground": "240 5.9% 10%",
174
- muted: "240 4.8% 95.9%",
175
- "muted-foreground": "240 3.8% 46.1%",
176
- accent: "240 4.8% 95.9%",
177
- "accent-foreground": "240 5.9% 10%",
178
- destructive: "0 84.2% 60.2%",
179
- "destructive-foreground": "0 0% 98%",
180
- border: "240 5.9% 90%",
181
- input: "240 5.9% 90%",
182
- ring: "240 10% 3.9%"
183
- },
184
- dark: {
185
- background: "240 10% 3.9%",
186
- foreground: "0 0% 98%",
187
- card: "240 10% 3.9%",
188
- "card-foreground": "0 0% 98%",
189
- popover: "240 10% 3.9%",
190
- "popover-foreground": "0 0% 98%",
191
- primary: "0 0% 98%",
192
- "primary-foreground": "240 5.9% 10%",
193
- secondary: "240 3.7% 15.9%",
194
- "secondary-foreground": "0 0% 98%",
195
- muted: "240 3.7% 15.9%",
196
- "muted-foreground": "240 5% 64.9%",
197
- accent: "240 3.7% 15.9%",
198
- "accent-foreground": "0 0% 98%",
199
- destructive: "0 62.8% 30.6%",
200
- "destructive-foreground": "0 0% 98%",
201
- border: "240 3.7% 15.9%",
202
- input: "240 3.7% 15.9%",
203
- ring: "240 4.9% 83.9%"
40
+ const files = fs.readdirSync(v3Path);
41
+ for (const file of files) {
42
+ if (file.endsWith(".css")) {
43
+ const themeName = file.replace(".css", "");
44
+ const metadata = THEME_METADATA[themeName] || {
45
+ name: themeName.charAt(0).toUpperCase() + themeName.slice(1),
46
+ description: `${themeName} theme`
47
+ };
48
+ themes.push({
49
+ name: metadata.name,
50
+ description: metadata.description,
51
+ file
52
+ });
53
+ }
204
54
  }
205
- },
206
- gray: {
207
- name: "Gray",
208
- description: "True neutral gray",
209
- light: {
210
- background: "0 0% 100%",
211
- foreground: "224 71.4% 4.1%",
212
- card: "0 0% 100%",
213
- "card-foreground": "224 71.4% 4.1%",
214
- popover: "0 0% 100%",
215
- "popover-foreground": "224 71.4% 4.1%",
216
- primary: "220.9 39.3% 11%",
217
- "primary-foreground": "210 20% 98%",
218
- secondary: "220 14.3% 95.9%",
219
- "secondary-foreground": "220.9 39.3% 11%",
220
- muted: "220 14.3% 95.9%",
221
- "muted-foreground": "220 8.9% 46.1%",
222
- accent: "220 14.3% 95.9%",
223
- "accent-foreground": "220.9 39.3% 11%",
224
- destructive: "0 84.2% 60.2%",
225
- "destructive-foreground": "210 20% 98%",
226
- border: "220 13% 91%",
227
- input: "220 13% 91%",
228
- ring: "224 71.4% 4.1%"
229
- },
230
- dark: {
231
- background: "224 71.4% 4.1%",
232
- foreground: "210 20% 98%",
233
- card: "224 71.4% 4.1%",
234
- "card-foreground": "210 20% 98%",
235
- popover: "224 71.4% 4.1%",
236
- "popover-foreground": "210 20% 98%",
237
- primary: "210 20% 98%",
238
- "primary-foreground": "220.9 39.3% 11%",
239
- secondary: "215 27.9% 16.9%",
240
- "secondary-foreground": "210 20% 98%",
241
- muted: "215 27.9% 16.9%",
242
- "muted-foreground": "217.9 10.6% 64.9%",
243
- accent: "215 27.9% 16.9%",
244
- "accent-foreground": "210 20% 98%",
245
- destructive: "0 62.8% 30.6%",
246
- "destructive-foreground": "210 20% 98%",
247
- border: "215 27.9% 16.9%",
248
- input: "215 27.9% 16.9%",
249
- ring: "216 12.2% 83.9%"
55
+ return themes;
56
+ }
57
+ /**
58
+ * Get the complete CSS content for a theme from the appropriate v3 or v4 folder
59
+ */
60
+ async getThemeCss(themeName, isTailwind4) {
61
+ const versionFolder = isTailwind4 ? "v4" : "v3";
62
+ const themeFilePath = path.join(this.registryThemesPath, versionFolder, `${themeName}.css`);
63
+ if (!fs.existsSync(themeFilePath)) {
64
+ throw new Error(`Theme file not found: ${themeFilePath}`);
250
65
  }
66
+ const content = await fs.readFile(themeFilePath, "utf-8");
67
+ return content;
251
68
  }
252
69
  };
253
- function generateCssVariablesV3(themeName) {
254
- const theme = THEMES[themeName];
255
- if (!theme) return "";
256
- const lightVars = Object.entries(theme.light).map(([key, value]) => ` --${key}: ${value};`).join("\n");
257
- const darkVars = Object.entries(theme.dark).map(([key, value]) => ` --${key}: ${value};`).join("\n");
258
- return `@tailwind base;
259
- @tailwind components;
260
- @tailwind utilities;
261
70
 
262
- @layer base {
263
- :root {
264
- ${lightVars}
265
- --radius: 0.5rem;
266
- --sidebar-width: 16rem;
267
- --sidebar-width-mobile: 18rem;
268
- --sidebar-width-collapsed: 3rem;
269
- --sidebar-width-icon: 3rem;
270
- --header-height: 3.5rem;
271
- --sidebar-background: 0 0% 98%;
272
- --sidebar-foreground: 240 5.3% 26.1%;
273
- --sidebar-primary: 240 5.9% 10%;
274
- --sidebar-primary-foreground: 0 0% 98%;
275
- --sidebar-accent: 240 4.8% 95.9%;
276
- --sidebar-accent-foreground: 240 5.9% 10%;
277
- --sidebar-border: 220 13% 91%;
278
- --sidebar-ring: 217.2 91.2% 59.8%;
279
- }
280
-
281
- .dark {
282
- ${darkVars}
283
- --sidebar-background: 240 5.9% 10%;
284
- --sidebar-foreground: 240 4.8% 95.9%;
285
- --sidebar-primary: 224.3 76.3% 48%;
286
- --sidebar-primary-foreground: 0 0% 100%;
287
- --sidebar-accent: 240 3.7% 15.9%;
288
- --sidebar-accent-foreground: 240 4.8% 95.9%;
289
- --sidebar-border: 240 3.7% 15.9%;
290
- --sidebar-ring: 217.2 91.2% 59.8%;
291
- }
292
- }
293
-
294
- @layer base {
295
- * {
296
- @apply border-border;
297
- }
298
- body {
299
- @apply bg-background text-foreground;
300
- }
301
- }
302
-
303
- @layer utilities {
304
- @keyframes accordion-down {
305
- from { height: 0; }
306
- to { height: var(--radix-accordion-content-height); }
307
- }
308
- @keyframes accordion-up {
309
- from { height: var(--radix-accordion-content-height); }
310
- to { height: 0; }
311
- }
312
- .animate-accordion-down {
313
- animation: accordion-down 0.2s ease-out;
314
- }
315
- .animate-accordion-up {
316
- animation: accordion-up 0.2s ease-out;
317
- }
318
- }
319
- `;
320
- }
321
- function generateCssVariablesV4(themeName) {
322
- const theme = THEMES[themeName];
323
- if (!theme) return "";
324
- const lightVars = Object.entries(theme.light).map(([key, value]) => ` --${key}: ${value};`).join("\n");
325
- const darkVars = Object.entries(theme.dark).map(([key, value]) => ` --${key}: ${value};`).join("\n");
326
- const lightVarsHsl = Object.entries(theme.light).map(([key, value]) => ` --${key}: hsl(${value});`).join("\n");
327
- const darkVarsHsl = Object.entries(theme.dark).map(([key, value]) => ` --${key}: hsl(${value});`).join("\n");
328
- return `@import "tailwindcss";
329
-
330
- :root {
331
- ${lightVarsHsl}
332
- --radius: 0.5rem;
333
- --sidebar-width: 16rem;
334
- --sidebar-width-mobile: 18rem;
335
- --sidebar-width-collapsed: 3rem;
336
- --sidebar-width-icon: 3rem;
337
- --header-height: 3.5rem;
338
- --sidebar-background: 0 0% 98%;
339
- --sidebar-foreground: 240 5.3% 26.1%;
340
- --sidebar-primary: 240 5.9% 10%;
341
- --sidebar-primary-foreground: 0 0% 98%;
342
- --sidebar-accent: 240 4.8% 95.9%;
343
- --sidebar-accent-foreground: 240 5.9% 10%;
344
- --sidebar-border: 220 13% 91%;
345
- --sidebar-ring: 217.2 91.2% 59.8%;
346
- }
347
-
348
- @theme inline {
349
- --color-border: var(--border);
350
- --color-input: var(--input);
351
- --color-ring: var(--ring);
352
- --color-background: var(--background);
353
- --color-foreground: var(--foreground);
354
-
355
- --color-primary: var(--primary);
356
- --color-primary-foreground: var(--primary-foreground);
357
-
358
- --color-secondary: var(--secondary);
359
- --color-secondary-foreground: var(--secondary-foreground);
360
-
361
- --color-destructive: var(--destructive);
362
- --color-destructive-foreground: var(--destructive-foreground);
363
-
364
- --color-muted: var(--muted);
365
- --color-muted-foreground: var(--muted-foreground);
366
-
367
- --color-accent: var(--accent);
368
- --color-accent-foreground: var(--accent-foreground);
369
-
370
- --color-popover: var(--popover);
371
- --color-popover-foreground: var(--popover-foreground);
372
-
373
- --color-card: var(--card);
374
- --color-card-foreground: var(--card-foreground);
375
-
376
- --color-sidebar: var(--sidebar-background);
377
- --color-sidebar-foreground: var(--sidebar-foreground);
378
- --color-sidebar-primary: var(--sidebar-primary);
379
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
380
- --color-sidebar-accent: var(--sidebar-accent);
381
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
382
- --color-sidebar-border: var(--sidebar-border);
383
- --color-sidebar-ring: var(--sidebar-ring);
384
-
385
- --radius-lg: var(--radius);
386
- --radius-md: calc(var(--radius) - 2px);
387
- --radius-sm: calc(var(--radius) - 4px);
388
-
389
- /* Accordion Animations */
390
- --animate-accordion-down: accordion-down 0.2s ease-out;
391
- --animate-accordion-up: accordion-up 0.2s ease-out;
392
-
393
- @keyframes accordion-down {
394
- from { height: 0; }
395
- to { height: var(--radix-accordion-content-height); }
396
- }
397
- @keyframes accordion-up {
398
- from { height: var(--radix-accordion-content-height); }
399
- to { height: 0; }
400
- }
401
- }
402
-
403
- @media (prefers-color-scheme: dark) {
404
- :root {
405
- ${darkVarsHsl}
406
- --sidebar-background: 240 5.9% 10%;
407
- --sidebar-foreground: 240 4.8% 95.9%;
408
- --sidebar-primary: 224.3 76.3% 48%;
409
- --sidebar-primary-foreground: 0 0% 100%;
410
- --sidebar-accent: 240 3.7% 15.9%;
411
- --sidebar-accent-foreground: 240 4.8% 95.9%;
412
- --sidebar-border: 240 3.7% 15.9%;
413
- --sidebar-ring: 217.2 91.2% 59.8%;
414
- }
415
- }
416
-
417
- body {
418
- background: var(--background);
419
- color: var(--foreground);
420
- font-family: Arial, Helvetica, sans-serif;
421
- }
422
- `;
423
- }
71
+ // src/cli/utils/templates.ts
424
72
  var TAILWIND_CONFIG = `import type { Config } from "tailwindcss"
425
73
 
426
74
  const config: Config = {
@@ -493,473 +141,614 @@ const config: Config = {
493
141
 
494
142
  export default config
495
143
  `;
496
- async function init(options) {
497
- const cwd = path.resolve(options.cwd);
498
- const userAgent = process.env.npm_config_user_agent || "";
499
- const isYarn = userAgent.includes("yarn");
500
- const isPnpm = userAgent.includes("pnpm");
501
- const isBun = userAgent.includes("bun");
502
- const packageManager = isPnpm ? "pnpm" : isYarn ? "yarn" : isBun ? "bun" : "npm";
503
- const installCmd = isPnpm ? "add" : isYarn ? "add" : isBun ? "add" : "install";
504
- console.log(chalk.cyan("\n\u{1F680} Initializing @srcroot/ui...\n"));
505
- const packageJsonPath = path.join(cwd, "package.json");
506
- if (!fs.existsSync(packageJsonPath)) {
507
- console.log(chalk.red("Error: No package.json found. Please run this in a project directory."));
508
- process.exit(1);
144
+
145
+ // src/cli/utils/get-package-manager.ts
146
+ function getPackageManager() {
147
+ const userAgent = process.env.npm_config_user_agent;
148
+ if (!userAgent) {
149
+ return "npm";
509
150
  }
510
- const pkg = await fs.readJson(packageJsonPath);
511
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
512
- const tailwindVersion = allDeps["tailwindcss"] || "";
513
- const isTailwind4 = tailwindVersion.includes("^4") || tailwindVersion.startsWith("4") || allDeps["@tailwindcss/postcss"];
514
- const hasSrc = fs.existsSync(path.join(cwd, "src"));
515
- const srcPath = hasSrc ? path.join(cwd, "src") : cwd;
516
- const appPath = path.join(srcPath, "app");
517
- const pagesPath = path.join(srcPath, "pages");
518
- const hasAppDir = fs.existsSync(appPath);
519
- const hasPagesDir = fs.existsSync(pagesPath);
520
- const libDir = path.join(srcPath, "lib");
521
- const componentsDir = path.join(srcPath, "components", "ui");
522
- let globalsPath = "";
523
- if (hasAppDir) {
524
- if (fs.existsSync(path.join(appPath, "globals.css"))) {
525
- globalsPath = path.join(appPath, "globals.css");
526
- } else if (fs.existsSync(path.join(appPath, "global.css"))) {
527
- globalsPath = path.join(appPath, "global.css");
528
- } else {
529
- globalsPath = path.join(appPath, "globals.css");
151
+ if (userAgent.startsWith("yarn")) {
152
+ return "yarn";
153
+ }
154
+ if (userAgent.startsWith("pnpm")) {
155
+ return "pnpm";
156
+ }
157
+ if (userAgent.startsWith("bun")) {
158
+ return "bun";
159
+ }
160
+ return "npm";
161
+ }
162
+
163
+ // src/cli/utils/logger.ts
164
+ import chalk from "chalk";
165
+ var logger = {
166
+ error(...args) {
167
+ console.log(chalk.red(...args));
168
+ },
169
+ warn(...args) {
170
+ console.log(chalk.yellow(...args));
171
+ },
172
+ info(...args) {
173
+ console.log(chalk.cyan(...args));
174
+ },
175
+ success(...args) {
176
+ console.log(chalk.green(...args));
177
+ }
178
+ };
179
+
180
+ // src/cli/services/project-initializer.ts
181
+ var __dirname3 = path2.dirname(fileURLToPath2(import.meta.url));
182
+ var ProjectInitializer = class {
183
+ options;
184
+ config = {};
185
+ themeService;
186
+ constructor(options) {
187
+ this.options = options;
188
+ this.themeService = new ThemeService();
189
+ }
190
+ async run() {
191
+ logger.info("\n\u{1F680} Initializing @srcroot/ui...\n");
192
+ await this.validateEnvironment();
193
+ await this.detectConfiguration();
194
+ await this.promptUser();
195
+ await this.scaffold();
196
+ this.printSuccess();
197
+ }
198
+ async validateEnvironment() {
199
+ const cwd = path2.resolve(this.options.cwd);
200
+ const packageJsonPath = path2.join(cwd, "package.json");
201
+ if (!fs2.existsSync(packageJsonPath)) {
202
+ logger.error("Error: No package.json found. Please run this in a project directory.");
203
+ process.exit(1);
530
204
  }
531
- } else if (hasPagesDir) {
532
- const stylesPath = path.join(srcPath, "styles");
533
- if (fs.existsSync(path.join(stylesPath, "globals.css"))) {
534
- globalsPath = path.join(stylesPath, "globals.css");
535
- } else if (fs.existsSync(path.join(stylesPath, "global.css"))) {
536
- globalsPath = path.join(stylesPath, "global.css");
205
+ const pkg = await fs2.readJson(packageJsonPath);
206
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
207
+ if (!allDeps["react"]) {
208
+ logger.error("Error: React not found in dependencies. Please initialize this in a React project.");
209
+ process.exit(1);
210
+ }
211
+ }
212
+ async detectConfiguration() {
213
+ const cwd = path2.resolve(this.options.cwd);
214
+ const packageManager = getPackageManager();
215
+ const installCmd = packageManager === "npm" ? "install" : "add";
216
+ const pkg = await fs2.readJson(path2.join(cwd, "package.json"));
217
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
218
+ const tailwindVersion = allDeps["tailwindcss"] || "";
219
+ const isTailwind4 = tailwindVersion.includes("^4") || tailwindVersion.startsWith("4") || allDeps["@tailwindcss/postcss"];
220
+ const hasSrc = fs2.existsSync(path2.join(cwd, "src"));
221
+ const srcPath = hasSrc ? path2.join(cwd, "src") : cwd;
222
+ const appPath = path2.join(srcPath, "app");
223
+ const pagesPath = path2.join(srcPath, "pages");
224
+ const hasAppDir = fs2.existsSync(appPath);
225
+ const hasPagesDir = fs2.existsSync(pagesPath);
226
+ const libDir = path2.join(srcPath, "lib");
227
+ const componentsDir = path2.join(srcPath, "components", "ui");
228
+ let globalsPath = "";
229
+ if (hasAppDir) {
230
+ if (fs2.existsSync(path2.join(appPath, "globals.css"))) globalsPath = path2.join(appPath, "globals.css");
231
+ else if (fs2.existsSync(path2.join(appPath, "global.css"))) globalsPath = path2.join(appPath, "global.css");
232
+ else globalsPath = path2.join(appPath, "globals.css");
233
+ } else if (hasPagesDir) {
234
+ const stylesPath = path2.join(srcPath, "styles");
235
+ if (fs2.existsSync(path2.join(stylesPath, "globals.css"))) globalsPath = path2.join(stylesPath, "globals.css");
236
+ else if (fs2.existsSync(path2.join(stylesPath, "global.css"))) globalsPath = path2.join(stylesPath, "global.css");
237
+ else globalsPath = path2.join(stylesPath, "globals.css");
537
238
  } else {
538
- globalsPath = path.join(stylesPath, "globals.css");
239
+ globalsPath = path2.join(srcPath, "globals.css");
539
240
  }
540
- } else {
541
- globalsPath = path.join(srcPath, "globals.css");
241
+ this.config = {
242
+ cwd,
243
+ packageManager,
244
+ installCmd,
245
+ isTailwind4,
246
+ hasSrc,
247
+ srcPath,
248
+ appPath,
249
+ pagesPath,
250
+ hasAppDir,
251
+ hasPagesDir,
252
+ libDir,
253
+ componentsDir,
254
+ globalsPath
255
+ };
542
256
  }
543
- let selectedTheme = options.theme || "slate";
544
- if (!options.yes && !options.theme) {
545
- const themeChoices = Object.entries(THEMES).map(([key, theme]) => ({
546
- title: `${theme.name} - ${chalk.dim(theme.description)}`,
547
- value: key
548
- }));
549
- const themeResponse = await prompts({
550
- type: "select",
551
- name: "theme",
552
- message: "Which color theme would you like to use?",
553
- choices: themeChoices,
554
- initial: 0
555
- // slate is first
556
- });
557
- if (themeResponse.theme) {
558
- selectedTheme = themeResponse.theme;
257
+ async promptUser() {
258
+ let selectedTheme = this.options.theme || "slate";
259
+ if (!this.options.yes && !this.options.theme) {
260
+ const availableThemes = this.themeService.getAvailableThemes();
261
+ if (availableThemes.length === 0) {
262
+ logger.warn("Warning: No themes found in registry. Using default.");
263
+ this.config.selectedTheme = selectedTheme;
264
+ return;
265
+ }
266
+ const themeChoices = availableThemes.map((theme) => ({
267
+ title: `${theme.name} - ${theme.description}`,
268
+ value: theme.file.replace(".css", "")
269
+ }));
270
+ const themeResponse = await prompts({
271
+ type: "select",
272
+ name: "theme",
273
+ message: "Which color theme would you like to use?",
274
+ choices: themeChoices,
275
+ initial: 0
276
+ });
277
+ if (themeResponse.theme) {
278
+ selectedTheme = themeResponse.theme;
279
+ }
559
280
  }
281
+ this.config.selectedTheme = selectedTheme;
560
282
  }
561
- const spinner = ora("Creating project structure...").start();
562
- try {
563
- await fs.ensureDir(libDir);
564
- await fs.ensureDir(componentsDir);
565
- const utilsPath = path.join(libDir, "utils.ts");
566
- await fs.writeFile(utilsPath, UTILS_CONTENT);
567
- spinner.succeed(`Created ${chalk.cyan(path.relative(cwd, utilsPath))}`);
568
- spinner.start(`Setting up ${chalk.cyan(THEMES[selectedTheme].name)} theme...`);
569
- const stylesDir = path.dirname(globalsPath);
570
- await fs.ensureDir(stylesDir);
571
- const cssContent = isTailwind4 ? generateCssVariablesV4(selectedTheme) : generateCssVariablesV3(selectedTheme);
572
- await fs.writeFile(globalsPath, cssContent);
573
- spinner.succeed(`Updated ${chalk.cyan(path.relative(cwd, globalsPath))} with ${chalk.cyan(THEMES[selectedTheme].name)} theme (${isTailwind4 ? "Tailwind 4" : "Tailwind 3"})`);
574
- if (!isTailwind4) {
575
- spinner.start("Setting up Tailwind config...");
576
- const tailwindConfigPath = path.join(cwd, "tailwind.config.ts");
577
- await fs.writeFile(tailwindConfigPath, TAILWIND_CONFIG);
578
- spinner.succeed(`Created ${chalk.cyan("tailwind.config.ts")}`);
579
- } else {
580
- spinner.info(`Tailwind 4 detected - skipping ${chalk.cyan("tailwind.config.ts")}`);
283
+ async scaffold() {
284
+ const spinner = ora("Creating project structure...").start();
285
+ const cfg = this.config;
286
+ try {
287
+ await fs2.ensureDir(cfg.libDir);
288
+ await fs2.ensureDir(cfg.componentsDir);
289
+ const utilsPath = path2.join(cfg.libDir, "utils.ts");
290
+ const registryUtilsPath = path2.resolve(__dirname3, "..", "src", "registry", "lib", "utils.ts");
291
+ let utilsContent = "";
292
+ if (fs2.existsSync(registryUtilsPath)) {
293
+ utilsContent = await fs2.readFile(registryUtilsPath, "utf-8");
294
+ } else {
295
+ utilsContent = `import { type ClassValue, clsx } from "clsx"
296
+ import { twMerge } from "tailwind-merge"
297
+
298
+ export function cn(...inputs: ClassValue[]) {
299
+ return twMerge(clsx(inputs))
300
+ }
301
+ `;
302
+ spinner.warn(`Could not find registry/utils.ts, using fallback content.`);
303
+ }
304
+ await fs2.writeFile(utilsPath, utilsContent);
305
+ spinner.succeed(`Created ${path2.relative(cfg.cwd, utilsPath)}`);
306
+ spinner.start(`Setting up ${cfg.selectedTheme} theme...`);
307
+ const stylesDir = path2.dirname(cfg.globalsPath);
308
+ await fs2.ensureDir(stylesDir);
309
+ try {
310
+ const cssContent = await this.themeService.getThemeCss(cfg.selectedTheme, cfg.isTailwind4);
311
+ await fs2.writeFile(cfg.globalsPath, cssContent);
312
+ spinner.succeed(`Updated ${path2.relative(cfg.cwd, cfg.globalsPath)} with ${cfg.selectedTheme} theme (${cfg.isTailwind4 ? "Tailwind 4" : "Tailwind 3"})`);
313
+ } catch (error) {
314
+ spinner.fail(`Failed to load theme: ${cfg.selectedTheme}`);
315
+ console.error(error);
316
+ process.exit(1);
317
+ }
318
+ if (!cfg.isTailwind4) {
319
+ spinner.start("Setting up Tailwind config...");
320
+ const tailwindConfigPath = path2.join(cfg.cwd, "tailwind.config.ts");
321
+ await fs2.writeFile(tailwindConfigPath, TAILWIND_CONFIG);
322
+ spinner.succeed(`Created tailwind.config.ts`);
323
+ } else {
324
+ spinner.info(`Tailwind 4 detected - skipping tailwind.config.ts`);
325
+ }
326
+ } catch (error) {
327
+ spinner.fail("Failed to initialize project");
328
+ console.error(error);
329
+ process.exit(1);
581
330
  }
582
- console.log(chalk.green("\n\u2705 Project initialized successfully!\n"));
583
- console.log(`Theme: ${chalk.cyan(THEMES[selectedTheme].name)}`);
584
- console.log(`Tailwind: ${chalk.cyan(isTailwind4 ? "v4" : "v3")}`);
331
+ }
332
+ printSuccess() {
333
+ const cfg = this.config;
334
+ logger.success("\n\u2705 Project initialized successfully!\n");
335
+ console.log(`Theme: ${cfg.selectedTheme}`);
336
+ console.log(`Tailwind: ${cfg.isTailwind4 ? "v4" : "v3"}`);
585
337
  const requiredDeps = [
586
338
  "clsx",
587
339
  "tailwind-merge",
588
340
  "class-variance-authority",
589
341
  "react-icons"
590
342
  ];
591
- if (!isTailwind4) {
343
+ if (!cfg.isTailwind4) {
592
344
  requiredDeps.push("tailwindcss-animate");
593
345
  }
594
- console.log(chalk.cyan("\n\u{1F4E6} Required dependencies:"));
595
- console.log(chalk.dim(` ${packageManager} ${installCmd} ${requiredDeps.join(" ")}`));
346
+ logger.info("\n\u{1F4E6} Required dependencies:");
347
+ console.log(` ${cfg.packageManager} ${cfg.installCmd} ${requiredDeps.join(" ")}`);
596
348
  console.log("\n\u2728 Next steps:");
597
- console.log(chalk.dim(" 1. Install dependencies (command above)"));
598
- console.log(chalk.dim(" 2. npx @srcroot/ui add button"));
599
- console.log(chalk.dim(" 3. npx @srcroot/ui add --all"));
349
+ console.log(" 1. Install dependencies (command above)");
350
+ console.log(" 2. npx @srcroot/ui add button");
351
+ console.log(" 3. npx @srcroot/ui add --all");
600
352
  console.log();
601
- } catch (error) {
602
- spinner.fail("Failed to initialize project");
603
- console.error(error);
604
- process.exit(1);
605
353
  }
354
+ };
355
+
356
+ // src/cli/commands/init.ts
357
+ async function init(options) {
358
+ const initializer = new ProjectInitializer(options);
359
+ await initializer.run();
606
360
  }
607
361
 
608
362
  // src/cli/commands/add.ts
609
- import fs2 from "fs-extra";
610
- import path2 from "path";
611
- import chalk2 from "chalk";
363
+ import fs3 from "fs-extra";
364
+ import path3 from "path";
612
365
  import ora2 from "ora";
613
366
  import prompts2 from "prompts";
614
- import { fileURLToPath as fileURLToPath2 } from "url";
367
+ import { fileURLToPath as fileURLToPath3 } from "url";
615
368
 
616
369
  // src/cli/registry.ts
617
370
  var REGISTRY = {
618
371
  // Core
619
372
  button: {
620
- file: "button.tsx",
373
+ file: "ui/button.tsx",
621
374
  description: "Polymorphic button with variants",
622
375
  category: "Core",
623
376
  dependencies: []
624
377
  },
625
378
  badge: {
626
- file: "badge.tsx",
379
+ file: "ui/badge.tsx",
627
380
  description: "Status indicator",
628
381
  category: "Core",
629
382
  dependencies: []
630
383
  },
631
384
  avatar: {
632
- file: "avatar.tsx",
385
+ file: "ui/avatar.tsx",
633
386
  description: "User avatar with fallback",
634
387
  category: "Core",
635
388
  dependencies: []
636
389
  },
637
390
  separator: {
638
- file: "separator.tsx",
391
+ file: "ui/separator.tsx",
639
392
  description: "Visual divider",
640
393
  category: "Core",
641
394
  dependencies: []
642
395
  },
643
396
  // Typography
644
397
  text: {
645
- file: "text.tsx",
398
+ file: "ui/text.tsx",
646
399
  description: "Polymorphic typography",
647
400
  category: "Typography",
648
401
  dependencies: []
649
402
  },
650
403
  label: {
651
- file: "label.tsx",
404
+ file: "ui/label.tsx",
652
405
  description: "Form label",
653
406
  category: "Typography",
654
407
  dependencies: []
655
408
  },
656
409
  // Forms
657
410
  input: {
658
- file: "input.tsx",
411
+ file: "ui/input.tsx",
659
412
  description: "Text input field",
660
413
  category: "Forms",
661
414
  dependencies: []
662
415
  },
663
416
  textarea: {
664
- file: "textarea.tsx",
417
+ file: "ui/textarea.tsx",
665
418
  description: "Multi-line text input",
666
419
  category: "Forms",
667
420
  dependencies: []
668
421
  },
669
422
  checkbox: {
670
- file: "checkbox.tsx",
423
+ file: "ui/checkbox.tsx",
671
424
  description: "Checkbox input",
672
425
  category: "Forms",
673
426
  dependencies: []
674
427
  },
675
428
  radio: {
676
- file: "radio.tsx",
429
+ file: "ui/radio.tsx",
677
430
  description: "Radio button group",
678
431
  category: "Forms",
679
432
  dependencies: []
680
433
  },
681
434
  switch: {
682
- file: "switch.tsx",
435
+ file: "ui/switch.tsx",
683
436
  description: "Toggle switch",
684
437
  category: "Forms",
685
438
  dependencies: []
686
439
  },
687
440
  slider: {
688
- file: "slider.tsx",
441
+ file: "ui/slider.tsx",
689
442
  description: "Range slider",
690
443
  category: "Forms",
691
444
  dependencies: []
692
445
  },
693
446
  select: {
694
- file: "select.tsx",
447
+ file: "ui/select.tsx",
695
448
  description: "Custom select dropdown",
696
449
  category: "Forms",
697
450
  dependencies: []
698
451
  },
699
452
  // Layout
700
453
  card: {
701
- file: "card.tsx",
454
+ file: "ui/card.tsx",
702
455
  description: "Card container",
703
456
  category: "Layout",
704
457
  dependencies: []
705
458
  },
706
459
  container: {
707
- file: "container.tsx",
460
+ file: "ui/container.tsx",
708
461
  description: "Max-width container",
709
462
  category: "Layout",
710
463
  dependencies: []
711
464
  },
712
465
  "aspect-ratio": {
713
- file: "aspect-ratio.tsx",
466
+ file: "ui/aspect-ratio.tsx",
714
467
  description: "Maintain aspect ratio",
715
468
  category: "Layout",
716
469
  dependencies: []
717
470
  },
718
471
  // Data Display
719
472
  accordion: {
720
- file: "accordion.tsx",
473
+ file: "ui/accordion.tsx",
721
474
  description: "Expandable sections",
722
475
  category: "Data Display",
723
476
  dependencies: []
724
477
  },
725
478
  tabs: {
726
- file: "tabs.tsx",
479
+ file: "ui/tabs.tsx",
727
480
  description: "Tab navigation",
728
481
  category: "Data Display",
729
482
  dependencies: []
730
483
  },
731
484
  table: {
732
- file: "table.tsx",
485
+ file: "ui/table.tsx",
733
486
  description: "Data table",
734
487
  category: "Data Display",
735
488
  dependencies: []
736
489
  },
737
490
  progress: {
738
- file: "progress.tsx",
491
+ file: "ui/progress.tsx",
739
492
  description: "Progress indicator",
740
493
  category: "Data Display",
741
494
  dependencies: []
742
495
  },
743
496
  skeleton: {
744
- file: "skeleton.tsx",
497
+ file: "ui/skeleton.tsx",
745
498
  description: "Loading placeholder",
746
499
  category: "Data Display",
747
500
  dependencies: []
748
501
  },
749
502
  // Overlay / Feedback
750
503
  dialog: {
751
- file: "dialog.tsx",
504
+ file: "ui/dialog.tsx",
752
505
  description: "Modal dialog",
753
506
  category: "Overlay / Feedback",
754
507
  dependencies: []
755
508
  },
756
509
  "alert-dialog": {
757
- file: "alert-dialog.tsx",
510
+ file: "ui/alert-dialog.tsx",
758
511
  description: "Confirmation dialog",
759
512
  category: "Overlay / Feedback",
760
513
  dependencies: ["dialog"]
761
514
  },
762
515
  sheet: {
763
- file: "sheet.tsx",
516
+ file: "ui/sheet.tsx",
764
517
  description: "Slide-in panel",
765
518
  category: "Overlay / Feedback",
766
519
  dependencies: []
767
520
  },
768
521
  popover: {
769
- file: "popover.tsx",
522
+ file: "ui/popover.tsx",
770
523
  description: "Floating content",
771
524
  category: "Overlay / Feedback",
772
525
  dependencies: []
773
526
  },
774
527
  tooltip: {
775
- file: "tooltip.tsx",
528
+ file: "ui/tooltip.tsx",
776
529
  description: "Hover tooltip",
777
530
  category: "Overlay / Feedback",
778
531
  dependencies: []
779
532
  },
780
533
  "dropdown-menu": {
781
- file: "dropdown-menu.tsx",
534
+ file: "ui/dropdown-menu.tsx",
782
535
  description: "Action dropdown",
783
536
  category: "Overlay / Feedback",
784
537
  dependencies: []
785
538
  },
786
539
  toast: {
787
- file: "toast.tsx",
540
+ file: "ui/toast.tsx",
788
541
  description: "Notification toast",
789
542
  category: "Overlay / Feedback",
790
543
  dependencies: []
791
544
  },
792
545
  alert: {
793
- file: "alert.tsx",
546
+ file: "ui/alert.tsx",
794
547
  description: "Inline alert",
795
548
  category: "Overlay / Feedback",
796
549
  dependencies: []
797
550
  },
798
551
  // Navigation
799
552
  breadcrumb: {
800
- file: "breadcrumb.tsx",
553
+ file: "ui/breadcrumb.tsx",
801
554
  description: "Breadcrumb navigation",
802
555
  category: "Navigation",
803
556
  dependencies: []
804
557
  },
805
558
  pagination: {
806
- file: "pagination.tsx",
559
+ file: "ui/pagination.tsx",
807
560
  description: "Page navigation",
808
561
  category: "Navigation",
809
562
  dependencies: ["button"]
810
563
  },
811
564
  // New Components
812
565
  "loading-spinner": {
813
- file: "loading-spinner.tsx",
566
+ file: "ui/loading-spinner.tsx",
814
567
  description: "Loading spinner with variants",
815
568
  category: "Feedback",
816
569
  dependencies: []
817
570
  },
818
571
  image: {
819
- file: "image.tsx",
572
+ file: "ui/image.tsx",
820
573
  description: "Enhanced image with loading",
821
574
  category: "Data Display",
822
575
  dependencies: []
823
576
  },
824
577
  "button-group": {
825
- file: "button-group.tsx",
578
+ file: "ui/button-group.tsx",
826
579
  description: "Group buttons together",
827
580
  category: "Core",
828
581
  dependencies: ["button"]
829
582
  },
830
583
  "otp-input": {
831
- file: "otp-input.tsx",
584
+ file: "ui/otp-input.tsx",
832
585
  description: "OTP verification input",
833
586
  category: "Forms",
834
587
  dependencies: []
835
588
  },
836
589
  search: {
837
- file: "search.tsx",
590
+ file: "ui/search.tsx",
838
591
  description: "Search input with debounce",
839
592
  category: "Forms",
840
593
  dependencies: []
841
594
  },
842
595
  "star-rating": {
843
- file: "star-rating.tsx",
596
+ file: "ui/star-rating.tsx",
844
597
  description: "Star rating input",
845
598
  category: "Feedback",
846
599
  dependencies: []
847
600
  },
848
601
  collapsible: {
849
- file: "collapsible.tsx",
602
+ file: "ui/collapsible.tsx",
850
603
  description: "Expandable section",
851
604
  category: "Data Display",
852
605
  dependencies: []
853
606
  },
854
607
  carousel: {
855
- file: "carousel.tsx",
608
+ file: "ui/carousel.tsx",
856
609
  description: "Image/content slider",
857
610
  category: "Data Display",
858
611
  dependencies: []
859
612
  },
860
613
  calendar: {
861
- file: "calendar.tsx",
614
+ file: "ui/calendar.tsx",
862
615
  description: "Date picker",
863
616
  category: "Forms",
864
617
  dependencies: []
865
618
  },
866
619
  sidebar: {
867
- file: "sidebar.tsx",
620
+ file: "ui/sidebar.tsx",
868
621
  description: "Responsive sidebar with mobile drawer",
869
622
  category: "Layout",
870
623
  dependencies: ["sheet", "button"]
871
624
  },
872
625
  // Added Components
873
626
  combobox: {
874
- file: "combobox.tsx",
627
+ file: "ui/combobox.tsx",
875
628
  description: "Searchable select with autocomplete",
876
629
  category: "Forms",
877
630
  dependencies: ["popover"]
878
631
  },
879
632
  command: {
880
- file: "command.tsx",
633
+ file: "ui/command.tsx",
881
634
  description: "Command palette / search menu",
882
635
  category: "Navigation",
883
636
  dependencies: []
884
637
  },
885
638
  "context-menu": {
886
- file: "context-menu.tsx",
639
+ file: "ui/context-menu.tsx",
887
640
  description: "Right-click context menu",
888
641
  category: "Overlay / Feedback",
889
642
  dependencies: []
890
643
  },
891
644
  "date-picker": {
892
- file: "date-picker.tsx",
645
+ file: "ui/date-picker.tsx",
893
646
  description: "Date picker with calendar",
894
647
  category: "Forms",
895
648
  dependencies: ["calendar", "popover", "button"]
896
649
  },
897
650
  drawer: {
898
- file: "drawer.tsx",
651
+ file: "ui/drawer.tsx",
899
652
  description: "Bottom/top sheet drawer",
900
653
  category: "Overlay / Feedback",
901
654
  dependencies: []
902
655
  },
903
656
  "file-upload": {
904
- file: "file-upload.tsx",
657
+ file: "ui/file-upload.tsx",
905
658
  description: "Drag-and-drop file upload",
906
659
  category: "Forms",
907
660
  dependencies: []
908
661
  },
909
662
  "hover-card": {
910
- file: "hover-card.tsx",
663
+ file: "ui/hover-card.tsx",
911
664
  description: "Hover-triggered popover",
912
665
  category: "Overlay / Feedback",
913
666
  dependencies: []
914
667
  },
915
668
  kbd: {
916
- file: "kbd.tsx",
669
+ file: "ui/kbd.tsx",
917
670
  description: "Keyboard shortcut display",
918
671
  category: "Typography",
919
672
  dependencies: []
920
673
  },
921
674
  menubar: {
922
- file: "menubar.tsx",
675
+ file: "ui/menubar.tsx",
923
676
  description: "Horizontal menu with dropdowns",
924
677
  category: "Navigation",
925
678
  dependencies: []
926
679
  },
927
680
  "native-select": {
928
- file: "native-select.tsx",
681
+ file: "ui/native-select.tsx",
929
682
  description: "Styled browser-native select",
930
683
  category: "Forms",
931
684
  dependencies: []
932
685
  },
933
686
  resizable: {
934
- file: "resizable.tsx",
687
+ file: "ui/resizable.tsx",
935
688
  description: "Resizable panel layout",
936
689
  category: "Layout",
937
690
  dependencies: []
938
691
  },
939
692
  "scroll-area": {
940
- file: "scroll-area.tsx",
693
+ file: "ui/scroll-area.tsx",
941
694
  description: "Custom scrollbar container",
942
695
  category: "Layout",
943
696
  dependencies: []
944
697
  },
945
698
  toggle: {
946
- file: "toggle.tsx",
699
+ file: "ui/toggle.tsx",
947
700
  description: "Toggle button",
948
701
  category: "Forms",
949
702
  dependencies: []
950
703
  },
951
704
  "toggle-group": {
952
- file: "toggle-group.tsx",
705
+ file: "ui/toggle-group.tsx",
953
706
  description: "Grouped toggle buttons",
954
707
  category: "Forms",
955
708
  dependencies: ["toggle"]
709
+ },
710
+ "google-analytics": {
711
+ file: "analytics/google-analytics.tsx",
712
+ description: "Google Analytics 4 tracking",
713
+ category: "Analytics",
714
+ dependencies: []
715
+ },
716
+ "google-tag-manager": {
717
+ file: "analytics/google-tag-manager.tsx",
718
+ description: "Google Tag Manager integration",
719
+ category: "Analytics",
720
+ dependencies: []
721
+ },
722
+ "meta-pixel": {
723
+ file: "analytics/meta-pixel.tsx",
724
+ description: "Meta (Facebook) Pixel tracking",
725
+ category: "Analytics",
726
+ dependencies: []
727
+ },
728
+ "microsoft-clarity": {
729
+ file: "analytics/microsoft-clarity.tsx",
730
+ description: "Microsoft Clarity heatmap tracking",
731
+ category: "Analytics",
732
+ dependencies: []
733
+ },
734
+ "tiktok-pixel": {
735
+ file: "analytics/tiktok-pixel.tsx",
736
+ description: "TikTok Pixel tracking",
737
+ category: "Analytics",
738
+ dependencies: []
739
+ },
740
+ chatbot: {
741
+ file: "ui/chatbot.tsx",
742
+ description: "AI chat interface",
743
+ category: "Data Display",
744
+ dependencies: ["button", "input", "scroll-area", "avatar"]
956
745
  }
957
746
  };
958
747
 
959
748
  // src/cli/commands/add.ts
960
- var __dirname3 = path2.dirname(fileURLToPath2(import.meta.url));
749
+ var __dirname4 = path3.dirname(fileURLToPath3(import.meta.url));
961
750
  async function add(components, options) {
962
- const cwd = path2.resolve(options.cwd);
751
+ const cwd = path3.resolve(options.cwd);
963
752
  if (options.all) {
964
753
  components = Object.keys(REGISTRY);
965
754
  }
@@ -976,7 +765,7 @@ async function add(components, options) {
976
765
  }))
977
766
  });
978
767
  if (!items || items.length === 0) {
979
- console.log(chalk2.yellow("No components selected."));
768
+ logger.warn("No components selected.");
980
769
  process.exit(0);
981
770
  }
982
771
  components = items;
@@ -991,8 +780,8 @@ async function add(components, options) {
991
780
  }
992
781
  }
993
782
  if (invalidComponents.length > 0) {
994
- console.log(chalk2.red(`Unknown components: ${invalidComponents.join(", ")}`));
995
- console.log(chalk2.dim("\nRun '@srcroot/ui list' to see available components."));
783
+ logger.error(`Unknown components: ${invalidComponents.join(", ")}`);
784
+ console.log("\nRun '@srcroot/ui list' to see available components.");
996
785
  process.exit(1);
997
786
  }
998
787
  const toInstall = /* @__PURE__ */ new Set();
@@ -1011,57 +800,58 @@ async function add(components, options) {
1011
800
  }
1012
801
  const componentsToAdd = Array.from(toInstall);
1013
802
  if (componentsToAdd.length > 10) {
1014
- console.log(chalk2.cyan(`
803
+ logger.info(`
1015
804
  \u{1F4E6} Adding ${componentsToAdd.length} components...
1016
- `));
805
+ `);
1017
806
  } else {
1018
- console.log(chalk2.cyan("\n\u{1F4E6} Adding components:\n"));
807
+ logger.info("\n\u{1F4E6} Adding components:\n");
1019
808
  componentsToAdd.forEach((name) => {
1020
- console.log(chalk2.dim(` - ${name}`));
809
+ console.log(` - ${name}`);
1021
810
  });
1022
811
  }
1023
812
  console.log();
1024
813
  const spinner = ora2("Adding components...").start();
1025
- const hasSrc = fs2.existsSync(path2.join(cwd, "src"));
1026
- const srcPath = hasSrc ? path2.join(cwd, "src") : cwd;
1027
- const componentsDir = path2.join(srcPath, "components", "ui");
814
+ const hasSrc = fs3.existsSync(path3.join(cwd, "src"));
815
+ const srcPath = hasSrc ? path3.join(cwd, "src") : cwd;
816
+ const componentsDir = path3.join(srcPath, "components", "ui");
1028
817
  try {
1029
- await fs2.ensureDir(componentsDir);
818
+ await fs3.ensureDir(componentsDir);
1030
819
  for (const name of componentsToAdd) {
1031
820
  const comp = REGISTRY[name];
1032
- const targetPath = path2.join(componentsDir, comp.file);
1033
- if (fs2.existsSync(targetPath) && !options.overwrite) {
821
+ const fileName = path3.basename(comp.file);
822
+ const targetPath = path3.join(componentsDir, fileName);
823
+ if (fs3.existsSync(targetPath) && !options.overwrite) {
1034
824
  spinner.stop();
1035
825
  const { overwrite } = await prompts2({
1036
826
  type: "confirm",
1037
827
  name: "overwrite",
1038
- message: `${chalk2.cyan(comp.file)} already exists. Overwrite?`,
828
+ message: `${fileName} already exists. Overwrite?`,
1039
829
  initial: false
1040
830
  });
1041
831
  if (!overwrite) {
1042
- spinner.info(`Skipped ${chalk2.cyan(comp.file)}`);
832
+ spinner.info(`Skipped ${fileName}`);
1043
833
  spinner.start("Adding components...");
1044
834
  continue;
1045
835
  }
1046
836
  spinner.start("Adding components...");
1047
837
  }
1048
- const registryPath = path2.resolve(__dirname3, "..", "registry", comp.file);
1049
- if (!fs2.existsSync(registryPath)) {
838
+ const registryPath = path3.resolve(__dirname4, "..", "src", "registry", comp.file);
839
+ if (!fs3.existsSync(registryPath)) {
1050
840
  spinner.warn(`Registry file not found for ${name}: ${registryPath}`);
1051
841
  continue;
1052
842
  }
1053
- const content = await fs2.readFile(registryPath, "utf-8");
1054
- await fs2.writeFile(targetPath, content);
843
+ const content = await fs3.readFile(registryPath, "utf-8");
844
+ await fs3.writeFile(targetPath, content);
1055
845
  if (componentsToAdd.length > 10) {
1056
- spinner.text = `Adding ${chalk2.cyan(comp.file)}...`;
846
+ spinner.text = `Adding ${fileName}...`;
1057
847
  } else {
1058
- spinner.succeed(`Added ${chalk2.cyan(comp.file)}`);
848
+ spinner.succeed(`Added ${fileName}`);
1059
849
  }
1060
850
  }
1061
851
  if (componentsToAdd.length > 10) {
1062
852
  spinner.succeed(`Added ${componentsToAdd.length} components`);
1063
853
  }
1064
- console.log(chalk2.green("\n\u2705 Components added successfully!\n"));
854
+ logger.success("\n\u2705 Components added successfully!\n");
1065
855
  } catch (error) {
1066
856
  spinner.fail("Failed to add components");
1067
857
  console.error(error);
@@ -1070,9 +860,9 @@ async function add(components, options) {
1070
860
  }
1071
861
 
1072
862
  // src/cli/commands/list.ts
1073
- import chalk3 from "chalk";
863
+ import chalk2 from "chalk";
1074
864
  async function list() {
1075
- console.log(chalk3.cyan("\n\u{1F4E6} Available components:\n"));
865
+ console.log(chalk2.cyan("\n\u{1F4E6} Available components:\n"));
1076
866
  const categories = {
1077
867
  "Core": [],
1078
868
  "Typography": [],
@@ -1080,7 +870,8 @@ async function list() {
1080
870
  "Layout": [],
1081
871
  "Data Display": [],
1082
872
  "Overlay / Feedback": [],
1083
- "Navigation": []
873
+ "Navigation": [],
874
+ "Analytics": []
1084
875
  };
1085
876
  for (const [name, comp] of Object.entries(REGISTRY)) {
1086
877
  if (categories[comp.category]) {
@@ -1089,20 +880,61 @@ async function list() {
1089
880
  }
1090
881
  for (const [category, components] of Object.entries(categories)) {
1091
882
  if (components.length === 0) continue;
1092
- console.log(chalk3.bold.white(` ${category}`));
883
+ console.log(chalk2.bold.white(` ${category}`));
1093
884
  components.forEach((name) => {
1094
885
  const comp = REGISTRY[name];
1095
- console.log(chalk3.dim(` - ${name}`) + chalk3.gray(` (${comp.description})`));
886
+ console.log(chalk2.dim(` - ${name}`) + chalk2.gray(` (${comp.description})`));
1096
887
  });
1097
888
  console.log();
1098
889
  }
1099
- console.log(chalk3.dim("Usage: npx @srcroot/ui add <component>\n"));
890
+ console.log(chalk2.dim("Usage: npx @srcroot/ui add <component>\n"));
891
+ }
892
+
893
+ // src/cli/utils/get-package-info.ts
894
+ import path4 from "path";
895
+ import fs4 from "fs-extra";
896
+ import { fileURLToPath as fileURLToPath4 } from "url";
897
+ function getPackageInfo() {
898
+ const __filename2 = fileURLToPath4(import.meta.url);
899
+ const __dirname5 = path4.dirname(__filename2);
900
+ const pathsToCheck = [
901
+ path4.resolve(__dirname5, "..", "package.json"),
902
+ path4.resolve(__dirname5, "..", "..", "..", "package.json")
903
+ ];
904
+ for (const pkgPath of pathsToCheck) {
905
+ if (fs4.existsSync(pkgPath)) {
906
+ return fs4.readJSONSync(pkgPath);
907
+ }
908
+ }
909
+ return { version: "0.0.0" };
1100
910
  }
1101
911
 
1102
912
  // src/cli/index.ts
1103
- var program = new Command();
1104
- program.name("@srcroot/ui").description("Add polymorphic, accessible UI components to your project").version("0.0.12");
1105
- program.command("init").description("Initialize your project with @srcroot/ui").option("-y, --yes", "Skip confirmation prompts", false).option("-t, --theme <theme>", "Color theme (slate, neutral, stone, zinc, gray)").option("--cwd <path>", "Working directory", process.cwd()).action(init);
1106
- program.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompts", false).option("-o, --overwrite", "Overwrite existing files", false).option("-a, --all", "Add all available components", false).option("--cwd <path>", "Working directory", process.cwd()).action(add);
1107
- program.command("list").description("List all available components").action(list);
1108
- program.parse();
913
+ process.on("SIGINT", () => process.exit(0));
914
+ process.on("SIGTERM", () => process.exit(0));
915
+ async function main() {
916
+ const packageInfo = getPackageInfo();
917
+ const program = new Command().name("@srcroot/ui").description("Add polymorphic, accessible UI components to your project").version(
918
+ packageInfo.version || "0.0.1",
919
+ "-v, --version",
920
+ "display the version number"
921
+ );
922
+ program.command("init").description("Initialize your project with @srcroot/ui").option("-y, --yes", "Skip confirmation prompts", false).option("-t, --theme <theme>", "Color theme (slate, neutral, stone, zinc, gray)").option("--cwd <path>", "Working directory", process.cwd()).action(init);
923
+ program.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompts", false).option("-o, --overwrite", "Overwrite existing files", false).option("-a, --all", "Add all available components", false).option("--cwd <path>", "Working directory", process.cwd()).action(add);
924
+ program.command("list").description("List all available components").action(list);
925
+ if (process.argv.length < 3) {
926
+ console.log(chalk3.cyan(`
927
+ @srcroot/ui v${packageInfo.version}
928
+
929
+ A UI library with polymorphic, accessible components.
930
+ `));
931
+ program.outputHelp();
932
+ console.log();
933
+ return;
934
+ }
935
+ program.parse();
936
+ }
937
+ main().catch((err) => {
938
+ console.error("Results: ", err);
939
+ process.exit(1);
940
+ });