@srcroot/ui 0.0.28 → 0.0.32

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