@dinachi/cli 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +14 -0
  2. package/dist/index.js +392 -344
  3. package/package.json +5 -5
  4. package/templates/accordion/accordion.tsx +1 -1
  5. package/templates/alert-dialog/alert-dialog.tsx +1 -1
  6. package/templates/autocomplete/autocomplete.tsx +197 -0
  7. package/templates/autocomplete/index.ts +17 -0
  8. package/templates/avatar/avatar.tsx +4 -4
  9. package/templates/checkbox/checkbox.tsx +2 -2
  10. package/templates/checkbox-group/checkbox-group.tsx +2 -2
  11. package/templates/collapsible/collapsible.tsx +4 -4
  12. package/templates/combobox/combobox.tsx +202 -0
  13. package/templates/combobox/index.ts +17 -0
  14. package/templates/context-menu/context-menu.tsx +119 -54
  15. package/templates/dialog/dialog.tsx +1 -1
  16. package/templates/drawer/drawer.tsx +109 -0
  17. package/templates/drawer/index.ts +12 -0
  18. package/templates/field/field.tsx +1 -1
  19. package/templates/fieldset/fieldset.tsx +32 -0
  20. package/templates/fieldset/index.ts +1 -0
  21. package/templates/form/form.tsx +3 -3
  22. package/templates/input/input.tsx +23 -15
  23. package/templates/menu/index.ts +17 -0
  24. package/templates/menu/menu.tsx +282 -0
  25. package/templates/menubar/menubar.tsx +22 -22
  26. package/templates/meter/index.ts +1 -0
  27. package/templates/meter/meter.tsx +64 -0
  28. package/templates/navigation-menu/navigation-menu.tsx +13 -13
  29. package/templates/number-field/index.ts +9 -0
  30. package/templates/number-field/number-field.tsx +114 -0
  31. package/templates/popover/index.ts +12 -0
  32. package/templates/popover/popover.tsx +137 -0
  33. package/templates/preview-card/preview-card.tsx +10 -11
  34. package/templates/progress/index.ts +7 -0
  35. package/templates/progress/progress.tsx +64 -0
  36. package/templates/radio/index.ts +1 -0
  37. package/templates/radio/radio.tsx +39 -0
  38. package/templates/scroll-area/index.ts +8 -0
  39. package/templates/scroll-area/scroll-area.tsx +94 -0
  40. package/templates/select/select.tsx +8 -8
  41. package/templates/separator/index.ts +1 -0
  42. package/templates/separator/separator.tsx +25 -0
  43. package/templates/slider/slider.tsx +10 -10
  44. package/templates/switch/index.ts +1 -0
  45. package/templates/switch/switch.tsx +42 -0
  46. package/templates/tabs/tabs.tsx +6 -6
  47. package/templates/toast/toast.tsx +1 -1
  48. package/templates/toggle/toggle.tsx +2 -2
  49. package/templates/toggle-group/index.ts +1 -0
  50. package/templates/toggle-group/toggle-group.tsx +67 -0
  51. package/templates/toolbar/toolbar.tsx +7 -7
  52. package/templates/tooltip/tooltip.tsx +38 -23
package/dist/index.js CHANGED
@@ -22,311 +22,269 @@ function getUtilityRegistry() {
22
22
  return {
23
23
  cn: {
24
24
  name: "utils",
25
- dependencies: [
26
- "clsx",
27
- "tailwind-merge"
28
- ]
25
+ dependencies: ["clsx", "tailwind-merge"]
29
26
  },
30
27
  variants: {
31
28
  name: "variants",
32
- dependencies: [
33
- "class-variance-authority"
34
- ]
29
+ dependencies: ["class-variance-authority"]
35
30
  }
36
31
  };
37
32
  }
38
33
  function getComponentRegistry() {
39
34
  return {
40
- button: {
41
- name: "button",
42
- description: "A customizable button component with multiple variants",
43
- files: [
44
- { name: "button.tsx" },
45
- { name: "index.ts" }
46
- ],
47
- dependencies: [
48
- "@base-ui-components/react",
49
- "class-variance-authority"
50
- ],
51
- componentDependencies: ["core"],
52
- utilityDependencies: ["cn", "variants"]
53
- },
54
- input: {
55
- name: "input",
56
- description: "A customizable input field component with variants and sizes",
57
- files: [
58
- { name: "input.tsx" },
59
- { name: "index.ts" }
60
- ],
61
- dependencies: [
62
- "@base-ui-components/react"
63
- ],
64
- utilityDependencies: ["cn"]
65
- },
66
- field: {
67
- name: "field",
68
- description: "A component for building accessible forms with custom styling and validation.",
69
- files: [
70
- { name: "field.tsx" },
71
- { name: "index.ts" }
72
- ],
73
- dependencies: [
74
- "@base-ui-components/react"
75
- ],
76
- utilityDependencies: ["cn"]
77
- },
78
- form: {
79
- name: "form",
80
- description: "A native form element with consolidated error handling, built on Base UI foundation.",
81
- files: [
82
- { name: "form.tsx" },
83
- { name: "index.ts" }
84
- ],
85
- dependencies: [
86
- "@base-ui-components/react"
87
- ],
88
- utilityDependencies: ["cn"]
89
- },
90
- "alert-dialog": {
91
- name: "alert-dialog",
92
- description: "A modal dialog that interrupts the user with important content and expects a response.",
93
- files: [
94
- { name: "alert-dialog.tsx" },
95
- { name: "index.ts" }
96
- ],
97
- dependencies: [
98
- "@base-ui-components/react",
99
- "lucide-react"
100
- ],
101
- utilityDependencies: ["cn"]
102
- },
103
35
  accordion: {
104
36
  name: "accordion",
105
37
  description: "A vertically stacked set of interactive headings that each reveal a section of content.",
106
- files: [
107
- { name: "accordion.tsx" },
108
- { name: "index.ts" }
109
- ],
110
- dependencies: [
111
- "@base-ui-components/react",
112
- "lucide-react",
113
- "tailwindcss-animate"
114
- ],
38
+ files: [{ name: "accordion.tsx" }, { name: "index.ts" }],
39
+ dependencies: ["@base-ui/react", "lucide-react", "tailwindcss-animate"],
115
40
  utilityDependencies: ["cn"]
116
41
  },
117
- tabs: {
118
- name: "tabs",
119
- description: "A component for toggling between related panels on the same page.",
120
- files: [
121
- { name: "tabs.tsx" },
122
- { name: "index.ts" }
123
- ],
124
- dependencies: [
125
- "@base-ui-components/react"
126
- ],
42
+ "alert-dialog": {
43
+ name: "alert-dialog",
44
+ description: "A modal dialog that interrupts the user with important content and expects a response.",
45
+ files: [{ name: "alert-dialog.tsx" }, { name: "index.ts" }],
46
+ dependencies: ["@base-ui/react", "lucide-react"],
127
47
  utilityDependencies: ["cn"]
128
48
  },
129
- slider: {
130
- name: "slider",
131
- description: "An input where the user selects a value from within a given range.",
132
- files: [
133
- { name: "slider.tsx" },
134
- { name: "index.ts" }
135
- ],
136
- dependencies: [
137
- "@base-ui-components/react"
138
- ],
49
+ autocomplete: {
50
+ name: "autocomplete",
51
+ description: "A text input with dynamic suggestions that helps users find and select values quickly.",
52
+ files: [{ name: "autocomplete.tsx" }, { name: "index.ts" }],
53
+ dependencies: ["@base-ui/react", "lucide-react"],
139
54
  utilityDependencies: ["cn"]
140
55
  },
141
56
  avatar: {
142
57
  name: "avatar",
143
58
  description: "An image element with a fallback for representing a user.",
144
- files: [
145
- { name: "avatar.tsx" },
146
- { name: "index.ts" }
147
- ],
148
- dependencies: [
149
- "@base-ui-components/react",
150
- "class-variance-authority"
151
- ],
59
+ files: [{ name: "avatar.tsx" }, { name: "index.ts" }],
60
+ dependencies: ["@base-ui/react", "class-variance-authority"],
152
61
  utilityDependencies: ["cn"]
153
62
  },
63
+ button: {
64
+ name: "button",
65
+ description: "A customizable button component with multiple variants.",
66
+ files: [{ name: "button.tsx" }, { name: "index.ts" }],
67
+ dependencies: ["@base-ui/react", "class-variance-authority"],
68
+ componentDependencies: ["core"],
69
+ utilityDependencies: ["cn", "variants"]
70
+ },
154
71
  checkbox: {
155
72
  name: "checkbox",
156
73
  description: "A control that allows the user to select one or more options from a set.",
157
- files: [
158
- { name: "checkbox.tsx" },
159
- { name: "index.ts" }
160
- ],
161
- dependencies: [
162
- "@base-ui-components/react",
163
- "lucide-react"
164
- ],
74
+ files: [{ name: "checkbox.tsx" }, { name: "index.ts" }],
75
+ dependencies: ["@base-ui/react", "lucide-react"],
165
76
  utilityDependencies: ["cn"]
166
77
  },
167
78
  "checkbox-group": {
168
79
  name: "checkbox-group",
169
80
  description: "A group of checkboxes that share a common state.",
170
- files: [
171
- { name: "checkbox-group.tsx" },
172
- { name: "index.ts" }
173
- ],
174
- dependencies: [
175
- "@base-ui-components/react"
176
- ],
81
+ files: [{ name: "checkbox-group.tsx" }, { name: "index.ts" }],
82
+ dependencies: ["@base-ui/react"],
177
83
  componentDependencies: ["checkbox"],
178
84
  utilityDependencies: ["cn"]
179
85
  },
180
- "collapsible": {
86
+ collapsible: {
181
87
  name: "collapsible",
182
88
  description: "A collapsible panel controlled by a button.",
183
- files: [
184
- { name: "collapsible.tsx" },
185
- { name: "index.ts" }
186
- ],
187
- dependencies: [
188
- "@base-ui-components/react",
189
- "tailwindcss-animate"
190
- ],
89
+ files: [{ name: "collapsible.tsx" }, { name: "index.ts" }],
90
+ dependencies: ["@base-ui/react", "tailwindcss-animate"],
91
+ utilityDependencies: ["cn"]
92
+ },
93
+ combobox: {
94
+ name: "combobox",
95
+ description: "A combobox that combines text input with a selectable popup list of options.",
96
+ files: [{ name: "combobox.tsx" }, { name: "index.ts" }],
97
+ dependencies: ["@base-ui/react", "lucide-react"],
98
+ utilityDependencies: ["cn"]
99
+ },
100
+ "context-menu": {
101
+ name: "context-menu",
102
+ description: "A menu that appears at the pointer on right click or long press.",
103
+ files: [{ name: "context-menu.tsx" }, { name: "index.ts" }],
104
+ dependencies: ["@base-ui/react", "lucide-react"],
191
105
  utilityDependencies: ["cn"]
192
106
  },
193
107
  dialog: {
194
108
  name: "dialog",
195
109
  description: "A popup that opens on top of the entire page, providing a modal interface for user interactions.",
196
- files: [
197
- { name: "dialog.tsx" },
198
- { name: "index.ts" }
199
- ],
200
- dependencies: [
201
- "@base-ui-components/react"
202
- ],
110
+ files: [{ name: "dialog.tsx" }, { name: "index.ts" }],
111
+ dependencies: ["@base-ui/react"],
203
112
  utilityDependencies: ["cn"]
204
113
  },
205
- toast: {
206
- name: "toast",
207
- description: "Generates toast notifications with support for different types, promises, actions, and global management.",
208
- files: [
209
- { name: "toast.tsx" },
210
- { name: "index.ts" }
211
- ],
212
- dependencies: [
213
- "@base-ui-components/react",
214
- "class-variance-authority"
215
- ],
114
+ drawer: {
115
+ name: "drawer",
116
+ description: "A panel that slides in from the edge of the screen for focused workflows.",
117
+ files: [{ name: "drawer.tsx" }, { name: "index.ts" }],
118
+ dependencies: ["@base-ui/react"],
216
119
  utilityDependencies: ["cn"]
217
120
  },
218
- select: {
219
- name: "select",
220
- description: "A common form component for choosing a predefined value in a dropdown menu.",
221
- files: [
222
- { name: "select.tsx" },
223
- { name: "index.ts" }
224
- ],
225
- dependencies: [
226
- "@base-ui-components/react",
227
- "lucide-react"
228
- ],
121
+ field: {
122
+ name: "field",
123
+ description: "A component for building accessible forms with custom styling and validation.",
124
+ files: [{ name: "field.tsx" }, { name: "index.ts" }],
125
+ dependencies: ["@base-ui/react"],
229
126
  utilityDependencies: ["cn"]
230
127
  },
231
- "context-menu": {
232
- name: "context-menu",
233
- description: "A menu that appears at the pointer on right click or long press.",
234
- files: [
235
- { name: "context-menu.tsx" },
236
- { name: "index.ts" }
237
- ],
238
- dependencies: [
239
- "@base-ui-components/react",
240
- "lucide-react"
241
- ],
128
+ fieldset: {
129
+ name: "fieldset",
130
+ description: "A grouping container for related form controls with an accessible legend.",
131
+ files: [{ name: "fieldset.tsx" }, { name: "index.ts" }],
132
+ dependencies: ["@base-ui/react"],
133
+ utilityDependencies: ["cn"]
134
+ },
135
+ form: {
136
+ name: "form",
137
+ description: "A native form element with consolidated error handling, built on Base UI foundation.",
138
+ files: [{ name: "form.tsx" }, { name: "index.ts" }],
139
+ dependencies: ["@base-ui/react"],
140
+ utilityDependencies: ["cn"]
141
+ },
142
+ input: {
143
+ name: "input",
144
+ description: "A customizable input field component with variants and sizes.",
145
+ files: [{ name: "input.tsx" }, { name: "index.ts" }],
146
+ dependencies: ["@base-ui/react"],
147
+ utilityDependencies: ["cn"]
148
+ },
149
+ menu: {
150
+ name: "menu",
151
+ description: "A popup menu for actions and options triggered by a button.",
152
+ files: [{ name: "menu.tsx" }, { name: "index.ts" }],
153
+ dependencies: ["@base-ui/react", "lucide-react"],
242
154
  utilityDependencies: ["cn"]
243
155
  },
244
156
  menubar: {
245
157
  name: "menubar",
246
158
  description: "A visually persistent menu common in desktop applications that provides access to a consistent set of commands.",
247
- files: [
248
- { name: "menubar.tsx" },
249
- { name: "index.ts" }
250
- ],
251
- dependencies: [
252
- "@base-ui-components/react",
253
- "lucide-react"
254
- ],
159
+ files: [{ name: "menubar.tsx" }, { name: "index.ts" }],
160
+ dependencies: ["@base-ui/react", "lucide-react"],
161
+ utilityDependencies: ["cn"]
162
+ },
163
+ meter: {
164
+ name: "meter",
165
+ description: "A visual representation of a scalar measurement within a known range.",
166
+ files: [{ name: "meter.tsx" }, { name: "index.ts" }],
167
+ dependencies: ["@base-ui/react"],
255
168
  utilityDependencies: ["cn"]
256
169
  },
257
170
  "navigation-menu": {
258
171
  name: "navigation-menu",
259
172
  description: "A collection of links and menus for website navigation.",
260
- files: [
261
- { name: "navigation-menu.tsx" },
262
- { name: "index.ts" }
263
- ],
264
- dependencies: [
265
- "@base-ui-components/react",
266
- "lucide-react"
267
- ],
173
+ files: [{ name: "navigation-menu.tsx" }, { name: "index.ts" }],
174
+ dependencies: ["@base-ui/react", "lucide-react"],
175
+ utilityDependencies: ["cn"]
176
+ },
177
+ "number-field": {
178
+ name: "number-field",
179
+ description: "A numeric input with increment, decrement, and optional scrubbing controls.",
180
+ files: [{ name: "number-field.tsx" }, { name: "index.ts" }],
181
+ dependencies: ["@base-ui/react", "lucide-react"],
182
+ utilityDependencies: ["cn"]
183
+ },
184
+ popover: {
185
+ name: "popover",
186
+ description: "An anchored floating panel for contextual information and lightweight interactions.",
187
+ files: [{ name: "popover.tsx" }, { name: "index.ts" }],
188
+ dependencies: ["@base-ui/react"],
268
189
  utilityDependencies: ["cn"]
269
190
  },
270
191
  "preview-card": {
271
192
  name: "preview-card",
272
193
  description: "A popup that appears when a link is hovered, showing a preview for sighted users.",
273
- files: [
274
- { name: "preview-card.tsx" },
275
- { name: "index.ts" }
276
- ],
277
- dependencies: [
278
- "@base-ui-components/react"
279
- ],
194
+ files: [{ name: "preview-card.tsx" }, { name: "index.ts" }],
195
+ dependencies: ["@base-ui/react"],
196
+ utilityDependencies: ["cn"]
197
+ },
198
+ progress: {
199
+ name: "progress",
200
+ description: "A progress bar that communicates task completion to users and assistive technology.",
201
+ files: [{ name: "progress.tsx" }, { name: "index.ts" }],
202
+ dependencies: ["@base-ui/react"],
203
+ utilityDependencies: ["cn"]
204
+ },
205
+ radio: {
206
+ name: "radio",
207
+ description: "A radio input and group for selecting a single option from a set.",
208
+ files: [{ name: "radio.tsx" }, { name: "index.ts" }],
209
+ dependencies: ["@base-ui/react", "lucide-react"],
210
+ utilityDependencies: ["cn"]
211
+ },
212
+ "scroll-area": {
213
+ name: "scroll-area",
214
+ description: "A custom scroll container with styled scrollbars and optional corner rendering.",
215
+ files: [{ name: "scroll-area.tsx" }, { name: "index.ts" }],
216
+ dependencies: ["@base-ui/react"],
217
+ utilityDependencies: ["cn"]
218
+ },
219
+ select: {
220
+ name: "select",
221
+ description: "A common form component for choosing a predefined value in a dropdown menu.",
222
+ files: [{ name: "select.tsx" }, { name: "index.ts" }],
223
+ dependencies: ["@base-ui/react", "lucide-react"],
224
+ utilityDependencies: ["cn"]
225
+ },
226
+ separator: {
227
+ name: "separator",
228
+ description: "A visual divider used to separate and organize content.",
229
+ files: [{ name: "separator.tsx" }, { name: "index.ts" }],
230
+ dependencies: ["@base-ui/react"],
231
+ utilityDependencies: ["cn"]
232
+ },
233
+ slider: {
234
+ name: "slider",
235
+ description: "An input where the user selects a value from within a given range.",
236
+ files: [{ name: "slider.tsx" }, { name: "index.ts" }],
237
+ dependencies: ["@base-ui/react"],
238
+ utilityDependencies: ["cn"]
239
+ },
240
+ switch: {
241
+ name: "switch",
242
+ description: "A control that allows users to toggle a setting on or off.",
243
+ files: [{ name: "switch.tsx" }, { name: "index.ts" }],
244
+ dependencies: ["@base-ui/react"],
245
+ utilityDependencies: ["cn"]
246
+ },
247
+ tabs: {
248
+ name: "tabs",
249
+ description: "A component for toggling between related panels on the same page.",
250
+ files: [{ name: "tabs.tsx" }, { name: "index.ts" }],
251
+ dependencies: ["@base-ui/react"],
252
+ utilityDependencies: ["cn"]
253
+ },
254
+ toast: {
255
+ name: "toast",
256
+ description: "Generates toast notifications with support for different types, promises, actions, and global management.",
257
+ files: [{ name: "toast.tsx" }, { name: "index.ts" }],
258
+ dependencies: ["@base-ui/react", "class-variance-authority"],
280
259
  utilityDependencies: ["cn"]
281
260
  },
282
261
  toggle: {
283
262
  name: "toggle",
284
263
  description: "A two-state button that can be on or off.",
285
- files: [
286
- { name: "toggle.tsx" },
287
- { name: "index.ts" }
288
- ],
289
- dependencies: [
290
- "@base-ui-components/react",
291
- "class-variance-authority"
292
- ],
293
- utilityDependencies: ["cn"]
294
- },
295
- "toolbar": {
296
- "name": "toolbar",
297
- "description": "A container for grouping a set of controls, such as buttons, toggle groups, or dropdown menus.",
298
- "files": [
299
- {
300
- "name": "toolbar.tsx"
301
- },
302
- {
303
- "name": "index.ts"
304
- }
305
- ],
306
- "dependencies": [
307
- "@base-ui-components/react"
308
- ],
309
- "utilityDependencies": [
310
- "cn"
311
- ]
312
- },
313
- "tooltip": {
314
- "name": "tooltip",
315
- "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
316
- "files": [
317
- {
318
- "name": "tooltip.tsx"
319
- },
320
- {
321
- "name": "index.ts"
322
- }
323
- ],
324
- "dependencies": [
325
- "@base-ui-components/react"
326
- ],
327
- "utilityDependencies": [
328
- "cn"
329
- ]
264
+ files: [{ name: "toggle.tsx" }, { name: "index.ts" }],
265
+ dependencies: ["@base-ui/react", "class-variance-authority"],
266
+ utilityDependencies: ["cn"]
267
+ },
268
+ "toggle-group": {
269
+ name: "toggle-group",
270
+ description: "A grouped set of toggles supporting single or multiple pressed states.",
271
+ files: [{ name: "toggle-group.tsx" }, { name: "index.ts" }],
272
+ dependencies: ["@base-ui/react", "class-variance-authority"],
273
+ utilityDependencies: ["cn"]
274
+ },
275
+ toolbar: {
276
+ name: "toolbar",
277
+ description: "A container for grouping a set of controls, such as buttons, toggle groups, or dropdown menus.",
278
+ files: [{ name: "toolbar.tsx" }, { name: "index.ts" }],
279
+ dependencies: ["@base-ui/react"],
280
+ utilityDependencies: ["cn"]
281
+ },
282
+ tooltip: {
283
+ name: "tooltip",
284
+ description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.",
285
+ files: [{ name: "tooltip.tsx" }, { name: "index.ts" }],
286
+ dependencies: ["@base-ui/react"],
287
+ utilityDependencies: ["cn"]
330
288
  }
331
289
  };
332
290
  }
@@ -347,22 +305,8 @@ async function getConfig() {
347
305
  var __filename2 = fileURLToPath2(import.meta.url);
348
306
  var __dirname2 = path2.dirname(__filename2);
349
307
  function resolveAliasPath(aliasPath, projectRoot) {
350
- const cleanPath = aliasPath.replace(/^@\//, "");
351
- const possibleBasePaths = [
352
- path2.join(projectRoot, "src"),
353
- // src/ prefix (most common)
354
- path2.join(projectRoot, "app"),
355
- // app/ prefix (Next.js app router)
356
- projectRoot
357
- // Direct in project root
358
- ];
359
- for (const basePath of possibleBasePaths) {
360
- const fullPath = path2.join(basePath, cleanPath);
361
- if (fs2.existsSync(basePath)) {
362
- return fullPath;
363
- }
364
- }
365
- return path2.join(projectRoot, "src", cleanPath);
308
+ const cleanPath = aliasPath.replace(/^@\//, "").replace(/^\.\//, "");
309
+ return path2.join(projectRoot, cleanPath);
366
310
  }
367
311
  function getComponentDependencies(componentName) {
368
312
  const registry = getComponentRegistry();
@@ -374,15 +318,26 @@ function getComponentDependencies(componentName) {
374
318
  }
375
319
  return [...new Set(dependencies)];
376
320
  }
377
- async function ensureTailwindConfig(deps) {
321
+ async function ensureTailwindConfig(deps, configFileName) {
378
322
  const needsAnimatePlugin = deps.includes("tailwindcss-animate");
379
323
  if (!needsAnimatePlugin) return;
380
- const configPath = path2.join(process.cwd(), "tailwind.config.js");
324
+ let configPath = path2.join(process.cwd(), configFileName);
325
+ if (!fs2.existsSync(configPath)) {
326
+ const alternatives = ["tailwind.config.js", "tailwind.config.ts", "tailwind.config.mjs"];
327
+ for (const alt of alternatives) {
328
+ const altPath = path2.join(process.cwd(), alt);
329
+ if (fs2.existsSync(altPath)) {
330
+ configPath = altPath;
331
+ break;
332
+ }
333
+ }
334
+ }
381
335
  if (!fs2.existsSync(configPath)) {
382
336
  const configContent = `/** @type {import('tailwindcss').Config} */
383
337
  export default {
384
338
  content: [
385
339
  "./src/**/*.{js,ts,jsx,tsx}",
340
+ "./app/**/*.{js,ts,jsx,tsx}",
386
341
  "./components/**/*.{js,ts,jsx,tsx}",
387
342
  "./pages/**/*.{js,ts,jsx,tsx}",
388
343
  ],
@@ -394,7 +349,7 @@ export default {
394
349
  ],
395
350
  };`;
396
351
  await fs2.writeFile(configPath, configContent);
397
- return { created: true };
352
+ return { created: true, path: configPath };
398
353
  } else {
399
354
  const configContent = await fs2.readFile(configPath, "utf-8");
400
355
  if (!configContent.includes("tailwindcss-animate")) {
@@ -424,17 +379,17 @@ ${pluginsContent},
424
379
  );
425
380
  }
426
381
  await fs2.writeFile(configPath, updatedContent);
427
- return { updated: true };
382
+ return { updated: true, path: configPath };
428
383
  }
429
384
  }
430
- return { exists: true };
385
+ return { exists: true, path: configPath };
431
386
  }
432
- async function handleIndexFile(sourcePath, targetPath, componentName, allFilesAdded, aliasPath) {
387
+ async function handleIndexFile(sourcePath, targetPath, componentName, allFilesAdded, targetDir) {
433
388
  let templateContent = await fs2.readFile(sourcePath, "utf-8");
434
389
  templateContent = templateContent.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
435
390
  if (!fs2.existsSync(targetPath)) {
436
391
  await fs2.writeFile(targetPath, templateContent);
437
- allFilesAdded.push({ name: "index.ts", path: path2.join(aliasPath, "index.ts") });
392
+ allFilesAdded.push({ name: "index.ts", path: path2.join(targetDir, "index.ts") });
438
393
  } else {
439
394
  const existingContent = await fs2.readFile(targetPath, "utf-8");
440
395
  const exportRegex = /export\s+\*\s+from\s+['"]\.\/([^'"]+)['"]/g;
@@ -448,7 +403,7 @@ async function handleIndexFile(sourcePath, targetPath, componentName, allFilesAd
448
403
  const newExportLine = `export * from './${componentName}'`;
449
404
  const updatedContent = existingContent.trim() + "\n" + newExportLine + "\n";
450
405
  await fs2.writeFile(targetPath, updatedContent);
451
- allFilesAdded.push({ name: "index.ts", path: path2.join(aliasPath, "index.ts") });
406
+ allFilesAdded.push({ name: "index.ts", path: path2.join(targetDir, "index.ts") });
452
407
  }
453
408
  }
454
409
  }
@@ -524,7 +479,7 @@ var addCommand = new Command("add").description("Add a component to your project
524
479
  await fs2.writeFile(targetPath, content);
525
480
  allFilesAdded.push({
526
481
  name: utilityFilename,
527
- path: path2.join(config.aliases.lib, utilityFilename)
482
+ path: path2.join(utilsDir, utilityFilename)
528
483
  });
529
484
  if (utility.dependencies?.length) {
530
485
  allDepsInstalled.push(...utility.dependencies);
@@ -539,7 +494,7 @@ var addCommand = new Command("add").description("Add a component to your project
539
494
  const sourcePath = path2.join(__dirname2, "../templates", name, file.name);
540
495
  const targetPath = path2.join(componentDir, file.name);
541
496
  if (file.name === "index.ts") {
542
- await handleIndexFile(sourcePath, targetPath, name, allFilesAdded, config.aliases.ui);
497
+ await handleIndexFile(sourcePath, targetPath, name, allFilesAdded, componentDir);
543
498
  } else {
544
499
  if (fs2.existsSync(targetPath) && !options.overwrite) {
545
500
  spinner.warn(`\u26A0\uFE0F ${file.name} already exists. Use --overwrite to replace it.`);
@@ -548,7 +503,7 @@ var addCommand = new Command("add").description("Add a component to your project
548
503
  let content = await fs2.readFile(sourcePath, "utf-8");
549
504
  content = content.replace(/^\/\/ @ts-nocheck\s*\n/m, "");
550
505
  await fs2.writeFile(targetPath, content);
551
- allFilesAdded.push({ name: file.name, path: path2.join(config.aliases.ui, file.name) });
506
+ allFilesAdded.push({ name: file.name, path: path2.join(componentDir, file.name) });
552
507
  }
553
508
  }
554
509
  if (comp.dependencies?.length) {
@@ -558,7 +513,8 @@ var addCommand = new Command("add").description("Add a component to your project
558
513
  let tailwindConfigInfo = null;
559
514
  if (allDepsInstalled.includes("tailwindcss-animate")) {
560
515
  spinner.text = "Updating Tailwind configuration...";
561
- tailwindConfigInfo = await ensureTailwindConfig(allDepsInstalled);
516
+ const configFileName = config.tailwind?.config || "tailwind.config.js";
517
+ tailwindConfigInfo = await ensureTailwindConfig(allDepsInstalled, configFileName);
562
518
  }
563
519
  const packageJsonPath = path2.join(process.cwd(), "package.json");
564
520
  const packageJson = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
@@ -569,7 +525,7 @@ var addCommand = new Command("add").description("Add a component to your project
569
525
  if (missingDeps.length > 0) {
570
526
  try {
571
527
  const packageManager = getPackageManager();
572
- const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"} ${missingDeps.join(" ")}`;
528
+ const installCmd = getInstallCommand(packageManager, missingDeps);
573
529
  execSync(installCmd, { stdio: "inherit" });
574
530
  } catch (error) {
575
531
  spinner.warn(`\u26A0\uFE0F Failed to install dependencies. Please install manually: ${missingDeps.join(" ")}`);
@@ -581,7 +537,7 @@ var addCommand = new Command("add").description("Add a component to your project
581
537
  if (options.all) {
582
538
  spinner.succeed(`\u2705 Added all ${componentsToInstall.length} components!`);
583
539
  } else {
584
- spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")} component(s)!`);
540
+ spinner.succeed(`\u2705 Added ${componentsToInstall.join(", ")}!`);
585
541
  }
586
542
  console.log();
587
543
  console.log("Files added:");
@@ -591,9 +547,9 @@ var addCommand = new Command("add").description("Add a component to your project
591
547
  if (tailwindConfigInfo) {
592
548
  console.log();
593
549
  if (tailwindConfigInfo.created) {
594
- console.log(` ${chalk.green("+")} tailwind.config.js (created with tailwindcss-animate plugin)`);
550
+ console.log(` ${chalk.green("+")} ${tailwindConfigInfo.path} (created with tailwindcss-animate plugin)`);
595
551
  } else if (tailwindConfigInfo.updated) {
596
- console.log(` ${chalk.blue("~")} tailwind.config.js (updated with tailwindcss-animate plugin)`);
552
+ console.log(` ${chalk.blue("~")} ${tailwindConfigInfo.path} (updated with tailwindcss-animate plugin)`);
597
553
  }
598
554
  }
599
555
  if (missingDeps.length > 0) {
@@ -615,10 +571,24 @@ var addCommand = new Command("add").description("Add a component to your project
615
571
  }
616
572
  });
617
573
  function getPackageManager() {
574
+ if (fs2.existsSync("bun.lockb") || fs2.existsSync("bun.lock")) return "bun";
618
575
  if (fs2.existsSync("pnpm-lock.yaml")) return "pnpm";
619
576
  if (fs2.existsSync("yarn.lock")) return "yarn";
620
577
  return "npm";
621
578
  }
579
+ function getInstallCommand(pm, deps) {
580
+ const depsStr = deps.join(" ");
581
+ switch (pm) {
582
+ case "bun":
583
+ return `bun add ${depsStr}`;
584
+ case "pnpm":
585
+ return `pnpm add ${depsStr}`;
586
+ case "yarn":
587
+ return `yarn add ${depsStr}`;
588
+ default:
589
+ return `npm install ${depsStr}`;
590
+ }
591
+ }
622
592
 
623
593
  // src/commands/init.ts
624
594
  import { Command as Command2 } from "commander";
@@ -651,12 +621,6 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
651
621
  name: "utilsPath",
652
622
  message: "Where would you like to install utilities?",
653
623
  initial: projectConfig.utilsPath
654
- },
655
- {
656
- type: "confirm",
657
- name: "installDeps",
658
- message: "Install required dependencies?",
659
- initial: true
660
624
  }
661
625
  ]);
662
626
  if (!response.componentsPath || !response.utilsPath) {
@@ -665,8 +629,10 @@ var initCommand = new Command2("init").description("Initialize Dinachi UI in you
665
629
  }
666
630
  const spinner = ora2("Setting up Dinachi UI...").start();
667
631
  try {
668
- await fs3.ensureDir(path3.dirname(response.componentsPath));
669
- await fs3.ensureDir(response.utilsPath);
632
+ const normalizedComponentsPath = normalizePath(response.componentsPath);
633
+ const normalizedUtilsPath = normalizePath(response.utilsPath);
634
+ await fs3.ensureDir(normalizedComponentsPath);
635
+ await fs3.ensureDir(normalizedUtilsPath);
670
636
  const utilsContent = `import { type ClassValue, clsx } from "clsx"
671
637
  import { twMerge } from "tailwind-merge"
672
638
 
@@ -674,56 +640,58 @@ export function cn(...inputs: ClassValue[]) {
674
640
  return twMerge(clsx(inputs))
675
641
  }
676
642
  `;
677
- await fs3.writeFile(path3.join(response.utilsPath, "utils.ts"), utilsContent);
678
- if (response.installDeps) {
679
- spinner.text = "Installing dependencies...";
680
- const deps = [
681
- "class-variance-authority",
682
- "clsx",
683
- "tailwind-merge"
684
- ];
685
- const packageManager = getPackageManager2();
686
- const installCmd = `${packageManager} ${packageManager === "npm" ? "install" : "add"} ${deps.join(" ")}`;
687
- execSync2(installCmd, { stdio: "inherit" });
688
- }
643
+ await fs3.writeFile(path3.join(normalizedUtilsPath, "utils.ts"), utilsContent);
644
+ spinner.text = "Installing dependencies...";
645
+ const deps = [
646
+ "class-variance-authority",
647
+ "clsx",
648
+ "tailwind-merge"
649
+ ];
650
+ const packageManager = getPackageManager2();
651
+ const installCmd = getInstallCommand2(packageManager, deps);
652
+ execSync2(installCmd, { stdio: "inherit" });
653
+ const componentsAlias = pathToAlias(normalizedComponentsPath);
654
+ const libAlias = pathToAlias(normalizedUtilsPath);
655
+ const uiAlias = componentsAlias;
656
+ const libParentAlias = pathToAlias(path3.dirname(normalizedUtilsPath) === "." ? normalizedUtilsPath : normalizedUtilsPath);
689
657
  const rscEnabled = projectConfig.framework === "next.js";
690
- const configContent = `{
691
- "style": "default",
692
- "rsc": ${rscEnabled},
693
- "tsx": true,
694
- "tailwind": {
695
- "config": "${projectConfig.tailwindConfig}",
696
- "css": "${projectConfig.cssPath}",
697
- "baseColor": "slate",
698
- "cssVariables": true
699
- },
700
- "aliases": {
701
- "components": "@/components",
702
- "utils": "@/lib/utils",
703
- "ui": "@/components/ui",
704
- "lib": "@/lib",
705
- "hooks": "@/hooks"
706
- },
707
- "iconLibrary": "lucide"
708
- }`;
658
+ const configContent = JSON.stringify({
659
+ style: "default",
660
+ rsc: rscEnabled,
661
+ tsx: true,
662
+ tailwind: {
663
+ config: projectConfig.tailwindConfig,
664
+ css: projectConfig.cssPath,
665
+ baseColor: "slate",
666
+ cssVariables: true
667
+ },
668
+ aliases: {
669
+ components: pathToAlias(path3.dirname(normalizedComponentsPath)),
670
+ utils: `${libAlias}/utils`,
671
+ ui: uiAlias,
672
+ lib: libAlias,
673
+ hooks: `${pathToAlias(projectConfig.srcDir)}/hooks`
674
+ },
675
+ iconLibrary: "lucide"
676
+ }, null, 2);
709
677
  await fs3.writeFile("components.json", configContent);
710
678
  spinner.succeed("\u2705 Dinachi UI setup complete!");
711
679
  console.log();
712
680
  console.log("Next steps:");
713
681
  console.log(` 1. Add a component: ${chalk2.cyan("npx @dinachi/cli add button")}`);
714
- console.log(` 2. Components will be installed to: ${chalk2.cyan("@/components/ui")}`);
715
- console.log(` 3. Utils available at: ${chalk2.cyan("@/lib/utils")}`);
682
+ console.log(` 2. Components will be installed to: ${chalk2.cyan(normalizedComponentsPath)}`);
683
+ console.log(` 3. Utils available at: ${chalk2.cyan(path3.join(normalizedUtilsPath, "utils.ts"))}`);
716
684
  if (projectConfig.framework === "next.js") {
717
685
  console.log();
718
686
  console.log(chalk2.blue("\u{1F4DD} Next.js specific notes:"));
719
687
  console.log(` - RSC (React Server Components) enabled in config`);
720
688
  console.log(` - Make sure to add "use client" directive if needed`);
721
- console.log(` - Tailwind config set to: ${chalk2.cyan(projectConfig.tailwindConfig)}`);
689
+ console.log(` - Tailwind config: ${chalk2.cyan(projectConfig.tailwindConfig)}`);
722
690
  } else if (projectConfig.framework === "remix") {
723
691
  console.log();
724
692
  console.log(chalk2.blue("\u{1F4DD} Remix specific notes:"));
725
- console.log(` - Components will be installed to: ${chalk2.cyan(projectConfig.componentsPath)}`);
726
- console.log(` - Utils will be installed to: ${chalk2.cyan(projectConfig.utilsPath)}`);
693
+ console.log(` - Components will be installed to: ${chalk2.cyan(normalizedComponentsPath)}`);
694
+ console.log(` - Utils will be installed to: ${chalk2.cyan(normalizedUtilsPath)}`);
727
695
  }
728
696
  console.log();
729
697
  console.log("\u{1F4A1} Tip: Install globally for shorter commands:");
@@ -734,43 +702,82 @@ export function cn(...inputs: ClassValue[]) {
734
702
  process.exit(1);
735
703
  }
736
704
  });
705
+ function normalizePath(inputPath) {
706
+ return inputPath.replace(/^\.\//, "").replace(/\/$/, "");
707
+ }
708
+ function pathToAlias(filePath) {
709
+ const normalized = normalizePath(filePath);
710
+ return `@/${normalized}`;
711
+ }
737
712
  function getPackageManager2() {
713
+ if (fs3.existsSync("bun.lockb") || fs3.existsSync("bun.lock")) return "bun";
738
714
  if (fs3.existsSync("pnpm-lock.yaml")) return "pnpm";
739
715
  if (fs3.existsSync("yarn.lock")) return "yarn";
740
716
  return "npm";
741
717
  }
718
+ function getInstallCommand2(pm, deps) {
719
+ const depsStr = deps.join(" ");
720
+ switch (pm) {
721
+ case "bun":
722
+ return `bun add ${depsStr}`;
723
+ case "pnpm":
724
+ return `pnpm add ${depsStr}`;
725
+ case "yarn":
726
+ return `yarn add ${depsStr}`;
727
+ default:
728
+ return `npm install ${depsStr}`;
729
+ }
730
+ }
742
731
  function detectProjectType() {
743
732
  const packageJsonPath = path3.join(process.cwd(), "package.json");
744
733
  if (!fs3.existsSync(packageJsonPath)) {
745
- return {
746
- framework: "react",
747
- componentsPath: "./src/components/ui",
748
- utilsPath: "./src/lib",
749
- tailwindConfig: "tailwind.config.js",
750
- cssPath: "src/index.css",
751
- srcDir: "src"
752
- };
734
+ return getDefaultConfig("react", false);
753
735
  }
754
736
  const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
755
737
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
738
+ const hasSrcDir = fs3.existsSync(path3.join(process.cwd(), "src"));
739
+ const hasAppDir = fs3.existsSync(path3.join(process.cwd(), "app"));
740
+ const hasSrcAppDir = fs3.existsSync(path3.join(process.cwd(), "src", "app"));
741
+ const tailwindConfig = detectTailwindConfig();
742
+ const cssPath = detectCssPath(hasSrcDir, hasSrcAppDir);
756
743
  if (deps.next) {
744
+ if (hasSrcDir && hasSrcAppDir) {
745
+ return {
746
+ framework: "next.js",
747
+ componentsPath: "./src/components/ui",
748
+ utilsPath: "./src/lib",
749
+ tailwindConfig,
750
+ cssPath,
751
+ srcDir: "src"
752
+ };
753
+ }
754
+ if (hasAppDir && !hasSrcDir) {
755
+ return {
756
+ framework: "next.js",
757
+ componentsPath: "./components/ui",
758
+ utilsPath: "./lib",
759
+ tailwindConfig,
760
+ cssPath,
761
+ srcDir: "."
762
+ };
763
+ }
757
764
  return {
758
765
  framework: "next.js",
759
- componentsPath: "./src/components/ui",
760
- utilsPath: "./src/lib",
761
- tailwindConfig: "tailwind.config.ts",
762
- cssPath: "src/app/globals.css",
763
- srcDir: "src"
766
+ componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
767
+ utilsPath: hasSrcDir ? "./src/lib" : "./lib",
768
+ tailwindConfig,
769
+ cssPath,
770
+ srcDir: hasSrcDir ? "src" : "."
764
771
  };
765
772
  }
766
773
  if (deps.vite || deps["@vitejs/plugin-react"]) {
767
774
  return {
768
775
  framework: "vite",
769
- componentsPath: "./src/components/ui",
770
- utilsPath: "./src/lib",
771
- tailwindConfig: "tailwind.config.js",
772
- cssPath: "src/index.css",
773
- srcDir: "src"
776
+ componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
777
+ utilsPath: hasSrcDir ? "./src/lib" : "./lib",
778
+ tailwindConfig,
779
+ cssPath,
780
+ srcDir: hasSrcDir ? "src" : "."
774
781
  };
775
782
  }
776
783
  if (deps["react-scripts"]) {
@@ -778,8 +785,8 @@ function detectProjectType() {
778
785
  framework: "create-react-app",
779
786
  componentsPath: "./src/components/ui",
780
787
  utilsPath: "./src/lib",
781
- tailwindConfig: "tailwind.config.js",
782
- cssPath: "src/index.css",
788
+ tailwindConfig,
789
+ cssPath,
783
790
  srcDir: "src"
784
791
  };
785
792
  }
@@ -788,23 +795,64 @@ function detectProjectType() {
788
795
  framework: "remix",
789
796
  componentsPath: "./app/components/ui",
790
797
  utilsPath: "./app/lib",
791
- tailwindConfig: "tailwind.config.ts",
792
- cssPath: "app/tailwind.css",
798
+ tailwindConfig,
799
+ cssPath: detectCssPath(false, false, true),
793
800
  srcDir: "app"
794
801
  };
795
802
  }
803
+ return getDefaultConfig("react", hasSrcDir);
804
+ }
805
+ function getDefaultConfig(framework, hasSrcDir) {
796
806
  return {
797
- framework: "react",
798
- componentsPath: "./src/components/ui",
799
- utilsPath: "./src/lib",
800
- tailwindConfig: "tailwind.config.js",
801
- cssPath: "src/index.css",
802
- srcDir: "src"
807
+ framework,
808
+ componentsPath: hasSrcDir ? "./src/components/ui" : "./components/ui",
809
+ utilsPath: hasSrcDir ? "./src/lib" : "./lib",
810
+ tailwindConfig: detectTailwindConfig(),
811
+ cssPath: hasSrcDir ? "src/index.css" : "index.css",
812
+ srcDir: hasSrcDir ? "src" : "."
803
813
  };
804
814
  }
815
+ function detectTailwindConfig() {
816
+ if (fs3.existsSync(path3.join(process.cwd(), "tailwind.config.ts"))) {
817
+ return "tailwind.config.ts";
818
+ }
819
+ if (fs3.existsSync(path3.join(process.cwd(), "tailwind.config.js"))) {
820
+ return "tailwind.config.js";
821
+ }
822
+ if (fs3.existsSync(path3.join(process.cwd(), "tailwind.config.mjs"))) {
823
+ return "tailwind.config.mjs";
824
+ }
825
+ return "tailwind.config.js";
826
+ }
827
+ function detectCssPath(hasSrcDir, hasSrcAppDir, isRemix = false) {
828
+ const cwd = process.cwd();
829
+ const possiblePaths = [
830
+ // Next.js App Router
831
+ "app/globals.css",
832
+ "src/app/globals.css",
833
+ // Next.js Pages / General
834
+ "styles/globals.css",
835
+ "src/styles/globals.css",
836
+ // Vite / CRA
837
+ "src/index.css",
838
+ "index.css",
839
+ // Remix
840
+ "app/tailwind.css",
841
+ "app/styles/tailwind.css"
842
+ ];
843
+ for (const cssPath of possiblePaths) {
844
+ if (fs3.existsSync(path3.join(cwd, cssPath))) {
845
+ return cssPath;
846
+ }
847
+ }
848
+ if (isRemix) return "app/tailwind.css";
849
+ if (hasSrcAppDir) return "src/app/globals.css";
850
+ if (hasSrcDir) return "src/index.css";
851
+ return "app/globals.css";
852
+ }
805
853
 
806
854
  // src/index.ts
807
855
  var program = new Command3();
808
- program.name("dinachi").description("Add Dinachi UI components to your project").version("0.1.0");
856
+ program.name("dinachi").description("Add Dinachi UI components to your project").version("0.5.0");
809
857
  program.addCommand(addCommand).addCommand(initCommand);
810
858
  program.parse();