sh-ui-cli 0.45.2 → 0.45.3

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 (91) hide show
  1. package/data/changelog/versions.json +13 -0
  2. package/data/registry/react/components/accordion/index.tailwind.tsx +5 -7
  3. package/data/registry/react/components/accordion/index.tsx +5 -7
  4. package/data/registry/react/components/avatar/index.tailwind.tsx +4 -6
  5. package/data/registry/react/components/avatar/index.tsx +4 -6
  6. package/data/registry/react/components/badge/index.tailwind.tsx +2 -4
  7. package/data/registry/react/components/badge/index.tsx +2 -4
  8. package/data/registry/react/components/breadcrumb/index.tailwind.tsx +8 -10
  9. package/data/registry/react/components/breadcrumb/index.tsx +8 -10
  10. package/data/registry/react/components/button/index.tailwind.tsx +2 -1
  11. package/data/registry/react/components/button/index.tsx +3 -4
  12. package/data/registry/react/components/calendar/index.tailwind.tsx +10 -12
  13. package/data/registry/react/components/calendar/index.tsx +9 -11
  14. package/data/registry/react/components/card/index.tailwind.tsx +8 -10
  15. package/data/registry/react/components/card/index.tsx +8 -10
  16. package/data/registry/react/components/carousel/index.tailwind.tsx +7 -9
  17. package/data/registry/react/components/carousel/index.tsx +7 -9
  18. package/data/registry/react/components/checkbox/index.tailwind.tsx +3 -5
  19. package/data/registry/react/components/checkbox/index.tsx +3 -5
  20. package/data/registry/react/components/code-editor/index.tailwind.tsx +2 -4
  21. package/data/registry/react/components/code-editor/index.tsx +2 -4
  22. package/data/registry/react/components/code-panel/index.tailwind.tsx +5 -7
  23. package/data/registry/react/components/code-panel/index.tsx +5 -7
  24. package/data/registry/react/components/color-picker/index.tailwind.tsx +7 -6
  25. package/data/registry/react/components/color-picker/index.tsx +7 -6
  26. package/data/registry/react/components/combobox/index.tailwind.tsx +8 -10
  27. package/data/registry/react/components/combobox/index.tsx +8 -10
  28. package/data/registry/react/components/context-menu/index.tailwind.tsx +10 -12
  29. package/data/registry/react/components/context-menu/index.tsx +10 -12
  30. package/data/registry/react/components/date-picker/index.tailwind.tsx +7 -9
  31. package/data/registry/react/components/date-picker/index.tsx +7 -9
  32. package/data/registry/react/components/dialog/index.tailwind.tsx +6 -8
  33. package/data/registry/react/components/dialog/index.tsx +6 -8
  34. package/data/registry/react/components/dropdown-menu/index.tailwind.tsx +10 -12
  35. package/data/registry/react/components/dropdown-menu/index.tsx +10 -12
  36. package/data/registry/react/components/file-upload/index.tailwind.tsx +6 -8
  37. package/data/registry/react/components/file-upload/index.tsx +6 -8
  38. package/data/registry/react/components/form/field.tailwind.tsx +2 -1
  39. package/data/registry/react/components/form/field.tsx +2 -3
  40. package/data/registry/react/components/header/index.tailwind.tsx +17 -19
  41. package/data/registry/react/components/header/index.tsx +17 -19
  42. package/data/registry/react/components/input/index.tailwind.tsx +4 -6
  43. package/data/registry/react/components/input/index.tsx +4 -6
  44. package/data/registry/react/components/label/index.tailwind.tsx +6 -8
  45. package/data/registry/react/components/label/index.tsx +6 -8
  46. package/data/registry/react/components/markdown-editor/index.tailwind.tsx +2 -4
  47. package/data/registry/react/components/markdown-editor/index.tsx +2 -4
  48. package/data/registry/react/components/menubar/index.tailwind.tsx +2 -4
  49. package/data/registry/react/components/menubar/index.tsx +2 -4
  50. package/data/registry/react/components/numeric-input/index.tailwind.tsx +2 -4
  51. package/data/registry/react/components/numeric-input/index.tsx +2 -4
  52. package/data/registry/react/components/page-toc/index.tailwind.tsx +3 -2
  53. package/data/registry/react/components/page-toc/index.tsx +2 -3
  54. package/data/registry/react/components/pagination/index.tailwind.tsx +8 -10
  55. package/data/registry/react/components/pagination/index.tsx +8 -10
  56. package/data/registry/react/components/popover/index.tailwind.tsx +4 -6
  57. package/data/registry/react/components/popover/index.tsx +4 -6
  58. package/data/registry/react/components/progress/index.tailwind.tsx +3 -5
  59. package/data/registry/react/components/progress/index.tsx +2 -4
  60. package/data/registry/react/components/radio/index.tailwind.tsx +3 -5
  61. package/data/registry/react/components/radio/index.tsx +3 -5
  62. package/data/registry/react/components/rich-text-editor/index.tailwind.tsx +3 -5
  63. package/data/registry/react/components/rich-text-editor/index.tsx +3 -5
  64. package/data/registry/react/components/select/index.tailwind.tsx +8 -10
  65. package/data/registry/react/components/select/index.tsx +8 -10
  66. package/data/registry/react/components/separator/index.tailwind.tsx +2 -4
  67. package/data/registry/react/components/separator/index.tsx +2 -4
  68. package/data/registry/react/components/sidebar/index.tailwind.tsx +32 -43
  69. package/data/registry/react/components/sidebar/index.tsx +29 -46
  70. package/data/registry/react/components/skeleton/index.tailwind.tsx +2 -4
  71. package/data/registry/react/components/skeleton/index.tsx +2 -4
  72. package/data/registry/react/components/slider/index.tailwind.tsx +5 -7
  73. package/data/registry/react/components/slider/index.tsx +5 -7
  74. package/data/registry/react/components/spinner/index.tailwind.tsx +3 -5
  75. package/data/registry/react/components/spinner/index.tsx +2 -4
  76. package/data/registry/react/components/switch/index.tailwind.tsx +3 -5
  77. package/data/registry/react/components/switch/index.tsx +2 -4
  78. package/data/registry/react/components/tabs/index.tailwind.tsx +6 -8
  79. package/data/registry/react/components/tabs/index.tsx +6 -8
  80. package/data/registry/react/components/textarea/index.tailwind.tsx +2 -4
  81. package/data/registry/react/components/textarea/index.tsx +2 -4
  82. package/data/registry/react/components/toggle/index.tailwind.tsx +4 -6
  83. package/data/registry/react/components/toggle/index.tsx +4 -6
  84. package/data/registry/react/components/tooltip/index.tailwind.tsx +2 -4
  85. package/data/registry/react/components/tooltip/index.tsx +2 -4
  86. package/data/registry/react/lib/cn.tailwind.ts +17 -0
  87. package/data/registry/react/peer-versions.json +3 -1
  88. package/data/registry/react/registry.json +159 -43
  89. package/package.json +1 -1
  90. package/src/add.mjs +25 -1
  91. package/templates/ui-app-template/sh-ui.config.json +5 -0
@@ -5,10 +5,8 @@ import { Toggle as BaseToggle } from "@base-ui/react/toggle";
5
5
  import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
6
6
  import { cva, type VariantProps } from "class-variance-authority";
7
7
 
8
- function cx(...args: (string | undefined | false)[]) {
9
- return args.filter(Boolean).join(" ");
10
- }
11
8
 
9
+ import { cn } from "@SH_UI_UTILS@";
12
10
  const toggleVariants = cva(
13
11
  "inline-flex items-center justify-center gap-1.5 border border-transparent rounded-[var(--radius)] font-medium leading-none cursor-pointer text-foreground-muted bg-transparent transition-[background-color,color,border-color] duration-[var(--duration-fast)] select-none focus-visible:outline-[length:var(--border-width-strong)] focus-visible:outline-foreground focus-visible:outline-offset-2 disabled:opacity-[var(--opacity-disabled)] disabled:pointer-events-none data-[pressed]:bg-background-muted data-[pressed]:text-foreground motion-reduce:transition-none",
14
12
  {
@@ -45,7 +43,7 @@ export const Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(
45
43
  ({ className, variant = "ghost", size = "md", ...props }, ref) => (
46
44
  <BaseToggle
47
45
  ref={ref}
48
- className={cx(toggleVariants({ variant, size }), className)}
46
+ className={cn(toggleVariants({ variant, size }), className)}
49
47
  {...props}
50
48
  />
51
49
  ),
@@ -78,7 +76,7 @@ export const ToggleGroup = React.forwardRef<HTMLDivElement, ToggleGroupProps>(
78
76
  <ToggleGroupContext.Provider value={{ variant, size }}>
79
77
  <BaseToggleGroup
80
78
  ref={ref}
81
- className={cx(
79
+ className={cn(
82
80
  "inline-flex items-center gap-[var(--space-1)] data-[orientation=vertical]:flex-col",
83
81
  className,
84
82
  )}
@@ -102,7 +100,7 @@ export const ToggleGroupItem = React.forwardRef<HTMLButtonElement, ToggleGroupIt
102
100
  return (
103
101
  <BaseToggle
104
102
  ref={ref}
105
- className={cx(toggleVariants({ variant, size }), className)}
103
+ className={cn(toggleVariants({ variant, size }), className)}
106
104
  {...props}
107
105
  />
108
106
  );
@@ -5,10 +5,8 @@ import { Toggle as BaseToggle } from "@base-ui/react/toggle";
5
5
  import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
6
6
  import "./styles.css";
7
7
 
8
- function cx(...args: (string | undefined | false)[]) {
9
- return args.filter(Boolean).join(" ");
10
- }
11
8
 
9
+ import { cn } from "@SH_UI_UTILS@";
12
10
  /* ───────────── Toggle ───────────── */
13
11
 
14
12
  export type ToggleVariant = "outline" | "ghost";
@@ -43,7 +41,7 @@ export const Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(
43
41
  ({ className, variant = "ghost", size = "md", ...props }, ref) => (
44
42
  <BaseToggle
45
43
  ref={ref}
46
- className={cx(
44
+ className={cn(
47
45
  "sh-ui-toggle",
48
46
  `sh-ui-toggle--${variant}`,
49
47
  `sh-ui-toggle--${size}`,
@@ -95,7 +93,7 @@ export const ToggleGroup = React.forwardRef<HTMLDivElement, ToggleGroupProps>(
95
93
  <ToggleGroupContext.Provider value={{ variant, size }}>
96
94
  <BaseToggleGroup
97
95
  ref={ref}
98
- className={cx("sh-ui-toggle-group", className)}
96
+ className={cn("sh-ui-toggle-group", className)}
99
97
  {...props}
100
98
  />
101
99
  </ToggleGroupContext.Provider>
@@ -119,7 +117,7 @@ export const ToggleGroupItem = React.forwardRef<HTMLButtonElement, ToggleGroupIt
119
117
  return (
120
118
  <BaseToggle
121
119
  ref={ref}
122
- className={cx(
120
+ className={cn(
123
121
  "sh-ui-toggle",
124
122
  `sh-ui-toggle--${variant}`,
125
123
  `sh-ui-toggle--${size}`,
@@ -1,11 +1,9 @@
1
1
  import * as React from "react";
2
2
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
3
3
 
4
+ import { cn } from "@SH_UI_UTILS@";
4
5
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
5
6
 
6
- function cx(...args: (string | undefined | false | null)[]) {
7
- return args.filter(Boolean).join(" ");
8
- }
9
7
 
10
8
  export const TooltipProvider = BaseTooltip.Provider;
11
9
  export const Tooltip = BaseTooltip.Root;
@@ -39,7 +37,7 @@ export const TooltipContent = React.forwardRef<HTMLDivElement, TooltipContentPro
39
37
  >
40
38
  <BaseTooltip.Popup
41
39
  ref={ref}
42
- className={cx(
40
+ className={cn(
43
41
  "px-2.5 py-1.5 bg-foreground text-background rounded-[calc(var(--radius)-2px)] text-[length:var(--text-xs)] leading-snug max-w-xs shadow-[0_4px_12px_rgba(0,0,0,0.12)] origin-[var(--transform-origin)] outline-none transition-[opacity,transform] duration-[120ms] ease-out motion-reduce:transition-none data-[starting-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[ending-style]:scale-95 motion-reduce:data-[starting-style]:scale-100 motion-reduce:data-[ending-style]:scale-100",
44
42
  className,
45
43
  )}
@@ -2,11 +2,9 @@ import * as React from "react";
2
2
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
3
3
  import "./styles.css";
4
4
 
5
+ import { cn } from "@SH_UI_UTILS@";
5
6
  type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
6
7
 
7
- function cx(...args: (string | undefined | false | null)[]) {
8
- return args.filter(Boolean).join(" ");
9
- }
10
8
 
11
9
  /** 여러 Tooltip이 공통 delay를 공유하도록 묶는다. 앱 루트에 한 번 두는 것을 권장. */
12
10
  export const TooltipProvider = BaseTooltip.Provider;
@@ -71,7 +69,7 @@ export const TooltipContent = React.forwardRef<
71
69
  >
72
70
  <BaseTooltip.Popup
73
71
  ref={ref}
74
- className={cx("sh-ui-tooltip__content", className)}
72
+ className={cn("sh-ui-tooltip__content", className)}
75
73
  {...props}
76
74
  >
77
75
  {showArrow && (
@@ -0,0 +1,17 @@
1
+ /**
2
+ * className 합성 헬퍼 (Tailwind 변종) — clsx + tailwind-merge.
3
+ * - falsy 값 자동 제외
4
+ * - 객체 형태 `{ "is-active": true }` 지원
5
+ * - **Tailwind utility 충돌 머지** — `cn("bg-red-500", "bg-blue-500")` → `"bg-blue-500"`
6
+ * 사용자가 `<Button className="bg-red-500" />` 로 default 를 깔끔히 override 가능.
7
+ *
8
+ * cn("base", isActive && "active", { "with-icon": hasIcon }, className)
9
+ */
10
+ import { clsx, type ClassValue } from "clsx";
11
+ import { twMerge } from "tailwind-merge";
12
+
13
+ export type { ClassValue };
14
+
15
+ export function cn(...inputs: ClassValue[]): string {
16
+ return twMerge(clsx(inputs));
17
+ }
@@ -4,8 +4,10 @@
4
4
  "@base-ui/react": "^1.4.1",
5
5
  "@tanstack/react-form": "^1.29.1",
6
6
  "class-variance-authority": "^0.7.1",
7
+ "clsx": "^2.1.1",
7
8
  "lucide-react": "^1.11.0",
8
9
  "react-hook-form": "^7.74.0",
9
- "shiki": "^4.0.2"
10
+ "shiki": "^4.0.2",
11
+ "tailwind-merge": "^3.5.0"
10
12
  }
11
13
  }
@@ -35,7 +35,9 @@
35
35
  ]
36
36
  }
37
37
  ],
38
- "registryDependencies": []
38
+ "registryDependencies": [
39
+ "utils"
40
+ ]
39
41
  },
40
42
  "card": {
41
43
  "name": "card",
@@ -64,7 +66,9 @@
64
66
  }
65
67
  ],
66
68
  "dependencies": [],
67
- "registryDependencies": []
69
+ "registryDependencies": [
70
+ "utils"
71
+ ]
68
72
  },
69
73
  "input": {
70
74
  "name": "input",
@@ -93,7 +97,9 @@
93
97
  }
94
98
  ],
95
99
  "dependencies": [],
96
- "registryDependencies": []
100
+ "registryDependencies": [
101
+ "utils"
102
+ ]
97
103
  },
98
104
  "numeric-input": {
99
105
  "name": "numeric-input",
@@ -122,7 +128,9 @@
122
128
  }
123
129
  ],
124
130
  "dependencies": [],
125
- "registryDependencies": []
131
+ "registryDependencies": [
132
+ "utils"
133
+ ]
126
134
  },
127
135
  "file-upload": {
128
136
  "name": "file-upload",
@@ -151,7 +159,9 @@
151
159
  }
152
160
  ],
153
161
  "dependencies": [],
154
- "registryDependencies": []
162
+ "registryDependencies": [
163
+ "utils"
164
+ ]
155
165
  },
156
166
  "form": {
157
167
  "name": "form",
@@ -240,7 +250,9 @@
240
250
  }
241
251
  ],
242
252
  "dependencies": [],
243
- "registryDependencies": []
253
+ "registryDependencies": [
254
+ "utils"
255
+ ]
244
256
  },
245
257
  "form-yup": {
246
258
  "name": "form-yup",
@@ -292,7 +304,9 @@
292
304
  "dependencies": [
293
305
  "shiki"
294
306
  ],
295
- "registryDependencies": []
307
+ "registryDependencies": [
308
+ "utils"
309
+ ]
296
310
  },
297
311
  "code-tabs": {
298
312
  "name": "code-tabs",
@@ -336,7 +350,9 @@
336
350
  }
337
351
  ],
338
352
  "dependencies": [],
339
- "registryDependencies": []
353
+ "registryDependencies": [
354
+ "utils"
355
+ ]
340
356
  },
341
357
  "code-editor": {
342
358
  "name": "code-editor",
@@ -374,7 +390,9 @@
374
390
  "@codemirror/lang-html",
375
391
  "@codemirror/lang-markdown"
376
392
  ],
377
- "registryDependencies": []
393
+ "registryDependencies": [
394
+ "utils"
395
+ ]
378
396
  },
379
397
  "markdown-editor": {
380
398
  "name": "markdown-editor",
@@ -407,7 +425,8 @@
407
425
  "remark-gfm"
408
426
  ],
409
427
  "registryDependencies": [
410
- "code-editor"
428
+ "code-editor",
429
+ "utils"
411
430
  ]
412
431
  },
413
432
  "rich-text-editor": {
@@ -444,7 +463,9 @@
444
463
  "@tiptap/extension-link",
445
464
  "lucide-react"
446
465
  ],
447
- "registryDependencies": []
466
+ "registryDependencies": [
467
+ "utils"
468
+ ]
448
469
  },
449
470
  "select": {
450
471
  "name": "select",
@@ -475,7 +496,9 @@
475
496
  "dependencies": [
476
497
  "@base-ui/react"
477
498
  ],
478
- "registryDependencies": []
499
+ "registryDependencies": [
500
+ "utils"
501
+ ]
479
502
  },
480
503
  "sidebar": {
481
504
  "name": "sidebar",
@@ -507,7 +530,8 @@
507
530
  "lucide-react"
508
531
  ],
509
532
  "registryDependencies": [
510
- "popover"
533
+ "popover",
534
+ "utils"
511
535
  ]
512
536
  },
513
537
  "header": {
@@ -537,7 +561,9 @@
537
561
  }
538
562
  ],
539
563
  "dependencies": [],
540
- "registryDependencies": []
564
+ "registryDependencies": [
565
+ "utils"
566
+ ]
541
567
  },
542
568
  "base": {
543
569
  "name": "base",
@@ -662,7 +688,9 @@
662
688
  }
663
689
  ],
664
690
  "dependencies": [],
665
- "registryDependencies": []
691
+ "registryDependencies": [
692
+ "utils"
693
+ ]
666
694
  },
667
695
  "color-picker": {
668
696
  "name": "color-picker",
@@ -691,7 +719,9 @@
691
719
  }
692
720
  ],
693
721
  "dependencies": [],
694
- "registryDependencies": []
722
+ "registryDependencies": [
723
+ "utils"
724
+ ]
695
725
  },
696
726
  "slider": {
697
727
  "name": "slider",
@@ -720,7 +750,9 @@
720
750
  }
721
751
  ],
722
752
  "dependencies": [],
723
- "registryDependencies": []
753
+ "registryDependencies": [
754
+ "utils"
755
+ ]
724
756
  },
725
757
  "tabs": {
726
758
  "name": "tabs",
@@ -751,7 +783,9 @@
751
783
  "dependencies": [
752
784
  "@base-ui/react"
753
785
  ],
754
- "registryDependencies": []
786
+ "registryDependencies": [
787
+ "utils"
788
+ ]
755
789
  },
756
790
  "combobox": {
757
791
  "name": "combobox",
@@ -782,7 +816,9 @@
782
816
  "dependencies": [
783
817
  "@base-ui/react"
784
818
  ],
785
- "registryDependencies": []
819
+ "registryDependencies": [
820
+ "utils"
821
+ ]
786
822
  },
787
823
  "popover": {
788
824
  "name": "popover",
@@ -813,7 +849,9 @@
813
849
  "dependencies": [
814
850
  "@base-ui/react"
815
851
  ],
816
- "registryDependencies": []
852
+ "registryDependencies": [
853
+ "utils"
854
+ ]
817
855
  },
818
856
  "dialog": {
819
857
  "name": "dialog",
@@ -844,7 +882,9 @@
844
882
  "dependencies": [
845
883
  "@base-ui/react"
846
884
  ],
847
- "registryDependencies": []
885
+ "registryDependencies": [
886
+ "utils"
887
+ ]
848
888
  },
849
889
  "dropdown-menu": {
850
890
  "name": "dropdown-menu",
@@ -875,7 +915,9 @@
875
915
  "dependencies": [
876
916
  "@base-ui/react"
877
917
  ],
878
- "registryDependencies": []
918
+ "registryDependencies": [
919
+ "utils"
920
+ ]
879
921
  },
880
922
  "context-menu": {
881
923
  "name": "context-menu",
@@ -906,7 +948,9 @@
906
948
  "dependencies": [
907
949
  "@base-ui/react"
908
950
  ],
909
- "registryDependencies": []
951
+ "registryDependencies": [
952
+ "utils"
953
+ ]
910
954
  },
911
955
  "menubar": {
912
956
  "name": "menubar",
@@ -938,7 +982,8 @@
938
982
  "@base-ui/react"
939
983
  ],
940
984
  "registryDependencies": [
941
- "dropdown-menu"
985
+ "dropdown-menu",
986
+ "utils"
942
987
  ]
943
988
  },
944
989
  "tooltip": {
@@ -970,7 +1015,9 @@
970
1015
  "dependencies": [
971
1016
  "@base-ui/react"
972
1017
  ],
973
- "registryDependencies": []
1018
+ "registryDependencies": [
1019
+ "utils"
1020
+ ]
974
1021
  },
975
1022
  "breadcrumb": {
976
1023
  "name": "breadcrumb",
@@ -999,7 +1046,9 @@
999
1046
  }
1000
1047
  ],
1001
1048
  "dependencies": [],
1002
- "registryDependencies": []
1049
+ "registryDependencies": [
1050
+ "utils"
1051
+ ]
1003
1052
  },
1004
1053
  "pagination": {
1005
1054
  "name": "pagination",
@@ -1028,7 +1077,9 @@
1028
1077
  }
1029
1078
  ],
1030
1079
  "dependencies": [],
1031
- "registryDependencies": []
1080
+ "registryDependencies": [
1081
+ "utils"
1082
+ ]
1032
1083
  },
1033
1084
  "avatar": {
1034
1085
  "name": "avatar",
@@ -1065,7 +1116,9 @@
1065
1116
  ]
1066
1117
  }
1067
1118
  ],
1068
- "registryDependencies": []
1119
+ "registryDependencies": [
1120
+ "utils"
1121
+ ]
1069
1122
  },
1070
1123
  "badge": {
1071
1124
  "name": "badge",
@@ -1101,7 +1154,9 @@
1101
1154
  ]
1102
1155
  }
1103
1156
  ],
1104
- "registryDependencies": []
1157
+ "registryDependencies": [
1158
+ "utils"
1159
+ ]
1105
1160
  },
1106
1161
  "progress": {
1107
1162
  "name": "progress",
@@ -1130,7 +1185,9 @@
1130
1185
  }
1131
1186
  ],
1132
1187
  "dependencies": [],
1133
- "registryDependencies": []
1188
+ "registryDependencies": [
1189
+ "utils"
1190
+ ]
1134
1191
  },
1135
1192
  "spinner": {
1136
1193
  "name": "spinner",
@@ -1166,7 +1223,9 @@
1166
1223
  ]
1167
1224
  }
1168
1225
  ],
1169
- "registryDependencies": []
1226
+ "registryDependencies": [
1227
+ "utils"
1228
+ ]
1170
1229
  },
1171
1230
  "separator": {
1172
1231
  "name": "separator",
@@ -1195,7 +1254,9 @@
1195
1254
  }
1196
1255
  ],
1197
1256
  "dependencies": [],
1198
- "registryDependencies": []
1257
+ "registryDependencies": [
1258
+ "utils"
1259
+ ]
1199
1260
  },
1200
1261
  "theme": {
1201
1262
  "name": "theme",
@@ -1238,7 +1299,9 @@
1238
1299
  "dependencies": [
1239
1300
  "@base-ui/react"
1240
1301
  ],
1241
- "registryDependencies": []
1302
+ "registryDependencies": [
1303
+ "utils"
1304
+ ]
1242
1305
  },
1243
1306
  "radio": {
1244
1307
  "name": "radio",
@@ -1269,7 +1332,9 @@
1269
1332
  "dependencies": [
1270
1333
  "@base-ui/react"
1271
1334
  ],
1272
- "registryDependencies": []
1335
+ "registryDependencies": [
1336
+ "utils"
1337
+ ]
1273
1338
  },
1274
1339
  "switch": {
1275
1340
  "name": "switch",
@@ -1306,7 +1371,9 @@
1306
1371
  ]
1307
1372
  }
1308
1373
  ],
1309
- "registryDependencies": []
1374
+ "registryDependencies": [
1375
+ "utils"
1376
+ ]
1310
1377
  },
1311
1378
  "toggle": {
1312
1379
  "name": "toggle",
@@ -1343,7 +1410,9 @@
1343
1410
  ]
1344
1411
  }
1345
1412
  ],
1346
- "registryDependencies": []
1413
+ "registryDependencies": [
1414
+ "utils"
1415
+ ]
1347
1416
  },
1348
1417
  "textarea": {
1349
1418
  "name": "textarea",
@@ -1372,7 +1441,9 @@
1372
1441
  }
1373
1442
  ],
1374
1443
  "dependencies": [],
1375
- "registryDependencies": []
1444
+ "registryDependencies": [
1445
+ "utils"
1446
+ ]
1376
1447
  },
1377
1448
  "toast": {
1378
1449
  "name": "toast",
@@ -1401,7 +1472,9 @@
1401
1472
  }
1402
1473
  ],
1403
1474
  "dependencies": [],
1404
- "registryDependencies": []
1475
+ "registryDependencies": [
1476
+ "utils"
1477
+ ]
1405
1478
  },
1406
1479
  "calendar": {
1407
1480
  "name": "calendar",
@@ -1431,7 +1504,8 @@
1431
1504
  ],
1432
1505
  "dependencies": [],
1433
1506
  "registryDependencies": [
1434
- "select"
1507
+ "select",
1508
+ "utils"
1435
1509
  ]
1436
1510
  },
1437
1511
  "date-picker": {
@@ -1464,7 +1538,8 @@
1464
1538
  "@base-ui/react"
1465
1539
  ],
1466
1540
  "registryDependencies": [
1467
- "calendar"
1541
+ "calendar",
1542
+ "utils"
1468
1543
  ]
1469
1544
  },
1470
1545
  "skeleton": {
@@ -1494,7 +1569,9 @@
1494
1569
  }
1495
1570
  ],
1496
1571
  "dependencies": [],
1497
- "registryDependencies": []
1572
+ "registryDependencies": [
1573
+ "utils"
1574
+ ]
1498
1575
  },
1499
1576
  "accordion": {
1500
1577
  "name": "accordion",
@@ -1525,7 +1602,9 @@
1525
1602
  "dependencies": [
1526
1603
  "@base-ui/react"
1527
1604
  ],
1528
- "registryDependencies": []
1605
+ "registryDependencies": [
1606
+ "utils"
1607
+ ]
1529
1608
  },
1530
1609
  "carousel": {
1531
1610
  "name": "carousel",
@@ -1554,7 +1633,9 @@
1554
1633
  }
1555
1634
  ],
1556
1635
  "dependencies": [],
1557
- "registryDependencies": []
1636
+ "registryDependencies": [
1637
+ "utils"
1638
+ ]
1558
1639
  },
1559
1640
  "form-rhf": {
1560
1641
  "name": "form-rhf",
@@ -1587,6 +1668,41 @@
1587
1668
  "registryDependencies": [
1588
1669
  "form"
1589
1670
  ]
1671
+ },
1672
+ "utils": {
1673
+ "name": "utils",
1674
+ "type": "lib",
1675
+ "files": [
1676
+ {
1677
+ "src": "lib/cn.ts",
1678
+ "dest": "{utils}",
1679
+ "frameworks": [
1680
+ "plain"
1681
+ ]
1682
+ },
1683
+ {
1684
+ "src": "lib/cn.tailwind.ts",
1685
+ "dest": "{utils}",
1686
+ "frameworks": [
1687
+ "tailwind"
1688
+ ]
1689
+ }
1690
+ ],
1691
+ "dependencies": [
1692
+ {
1693
+ "name": "clsx",
1694
+ "frameworks": [
1695
+ "tailwind"
1696
+ ]
1697
+ },
1698
+ {
1699
+ "name": "tailwind-merge",
1700
+ "frameworks": [
1701
+ "tailwind"
1702
+ ]
1703
+ }
1704
+ ],
1705
+ "registryDependencies": []
1590
1706
  }
1591
1707
  }
1592
1708
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sh-ui-cli",
3
- "version": "0.45.2",
3
+ "version": "0.45.3",
4
4
  "description": "sh-ui CLI — 프로젝트 스캐폴드(create) + 컴포넌트 추가(add/list/remove) + IDE-내 AI용 MCP 서버",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/add.mjs CHANGED
@@ -84,6 +84,29 @@ function resolveDest(template, config) {
84
84
  });
85
85
  }
86
86
 
87
+ /**
88
+ * registry source 안의 placeholder 를 사용자 config 값으로 치환.
89
+ * 현재 지원: `@SH_UI_UTILS@` → `aliases.utils` (예: `@/src/shared/lib/utils`).
90
+ *
91
+ * registry 컴포넌트는 cn 유틸을 `import { cn } from "@SH_UI_UTILS@"` 로 import 한다 —
92
+ * CLI 가 add 시점에 사용자 프로젝트의 alias 로 치환해 TS module resolution 이 동작.
93
+ *
94
+ * aliases.utils 가 미설정인데 placeholder 가 등장하면 친절 에러로 안내. 사용자가 매 컴포넌트
95
+ * 추가 후 import 깨진 것을 발견하기 전에 시점에 잡는다.
96
+ */
97
+ function substitutePlaceholders(content, config, srcRel) {
98
+ const PLACEHOLDER = "@SH_UI_UTILS@";
99
+ if (!content.includes(PLACEHOLDER)) return content;
100
+ const alias = config.aliases?.utils;
101
+ if (!alias) {
102
+ throw new Error(
103
+ `${srcRel} 가 cn 유틸을 import 합니다. sh-ui.config.json 에 aliases.utils 를 설정하세요.\n` +
104
+ ` 예: "aliases": { "utils": "@/src/lib/utils" }`,
105
+ );
106
+ }
107
+ return content.replaceAll(PLACEHOLDER, alias);
108
+ }
109
+
87
110
  async function ensureDir(filePath) {
88
111
  await mkdir(dirname(filePath), { recursive: true });
89
112
  }
@@ -223,7 +246,8 @@ async function addComponent(name, config, cwd, installed, pendingDeps, diffMode,
223
246
  if (!frameworkMatches(file, cssFramework)) continue;
224
247
  const src = resolve(registryRoot, file.src);
225
248
  const dest = resolve(cwd, resolveDest(file.dest, config));
226
- const content = await readFile(src, "utf8");
249
+ const raw = await readFile(src, "utf8");
250
+ const content = substitutePlaceholders(raw, config, file.src);
227
251
  const result = await writeOrDiff({ dest, content, cwd, diffMode, summary, conflictResolver });
228
252
  if (!diffMode && result !== "unchanged") {
229
253
  const prefix = result === "kept" ? "↷" : "✓";