sh-ui-cli 0.52.0 → 0.52.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/data/changelog/versions.json +25 -0
  2. package/data/registry/react/components/_smoke/vanilla-extract.test.ts +33 -0
  3. package/data/registry/react/components/input/styles.css.ts +6 -6
  4. package/data/registry/react/registry.json +35 -852
  5. package/package.json +2 -2
  6. package/src/api.d.ts +3 -4
  7. package/src/constants.js +9 -5
  8. package/src/create/plugins/pluginSchema.js +5 -3
  9. package/src/mcp.mjs +4 -3
  10. package/data/registry/react/components/accordion/index.vanilla-extract.tsx +0 -97
  11. package/data/registry/react/components/accordion/styles.css.ts +0 -131
  12. package/data/registry/react/components/avatar/index.vanilla-extract.tsx +0 -73
  13. package/data/registry/react/components/avatar/styles.css.ts +0 -68
  14. package/data/registry/react/components/badge/index.vanilla-extract.tsx +0 -40
  15. package/data/registry/react/components/badge/styles.css.ts +0 -71
  16. package/data/registry/react/components/breadcrumb/index.vanilla-extract.tsx +0 -152
  17. package/data/registry/react/components/breadcrumb/styles.css.ts +0 -95
  18. package/data/registry/react/components/calendar/index.vanilla-extract.tsx +0 -806
  19. package/data/registry/react/components/calendar/styles.css.ts +0 -250
  20. package/data/registry/react/components/carousel/index.vanilla-extract.tsx +0 -430
  21. package/data/registry/react/components/carousel/styles.css.ts +0 -169
  22. package/data/registry/react/components/checkbox/index.vanilla-extract.tsx +0 -96
  23. package/data/registry/react/components/checkbox/styles.css.ts +0 -74
  24. package/data/registry/react/components/code-editor/index.vanilla-extract.tsx +0 -230
  25. package/data/registry/react/components/code-editor/styles.css.ts +0 -97
  26. package/data/registry/react/components/code-panel/index.vanilla-extract.tsx +0 -191
  27. package/data/registry/react/components/code-panel/styles.css.ts +0 -151
  28. package/data/registry/react/components/color-picker/index.vanilla-extract.tsx +0 -467
  29. package/data/registry/react/components/color-picker/styles.css.ts +0 -169
  30. package/data/registry/react/components/combobox/index.vanilla-extract.tsx +0 -165
  31. package/data/registry/react/components/combobox/styles.css.ts +0 -174
  32. package/data/registry/react/components/context-menu/index.vanilla-extract.tsx +0 -251
  33. package/data/registry/react/components/context-menu/styles.css.ts +0 -167
  34. package/data/registry/react/components/date-picker/index.vanilla-extract.tsx +0 -520
  35. package/data/registry/react/components/date-picker/styles.css.ts +0 -111
  36. package/data/registry/react/components/dialog/index.vanilla-extract.tsx +0 -95
  37. package/data/registry/react/components/dialog/styles.css.ts +0 -140
  38. package/data/registry/react/components/dropdown-menu/index.vanilla-extract.tsx +0 -255
  39. package/data/registry/react/components/dropdown-menu/styles.css.ts +0 -175
  40. package/data/registry/react/components/file-upload/index.vanilla-extract.tsx +0 -487
  41. package/data/registry/react/components/file-upload/styles.css.ts +0 -193
  42. package/data/registry/react/components/form/index.vanilla-extract.tsx +0 -61
  43. package/data/registry/react/components/form/styles.css.ts +0 -56
  44. package/data/registry/react/components/header/index.vanilla-extract.tsx +0 -805
  45. package/data/registry/react/components/header/styles.css.ts +0 -413
  46. package/data/registry/react/components/label/index.vanilla-extract.tsx +0 -52
  47. package/data/registry/react/components/label/styles.css.ts +0 -141
  48. package/data/registry/react/components/markdown-editor/index.vanilla-extract.tsx +0 -119
  49. package/data/registry/react/components/markdown-editor/styles.css.ts +0 -231
  50. package/data/registry/react/components/menubar/index.vanilla-extract.tsx +0 -32
  51. package/data/registry/react/components/menubar/styles.css.ts +0 -53
  52. package/data/registry/react/components/numeric-input/index.vanilla-extract.tsx +0 -148
  53. package/data/registry/react/components/numeric-input/styles.css.ts +0 -65
  54. package/data/registry/react/components/page-toc/index.vanilla-extract.tsx +0 -174
  55. package/data/registry/react/components/page-toc/styles.css.ts +0 -97
  56. package/data/registry/react/components/pagination/index.vanilla-extract.tsx +0 -269
  57. package/data/registry/react/components/pagination/styles.css.ts +0 -113
  58. package/data/registry/react/components/popover/index.vanilla-extract.tsx +0 -113
  59. package/data/registry/react/components/popover/styles.css.ts +0 -78
  60. package/data/registry/react/components/progress/index.vanilla-extract.tsx +0 -54
  61. package/data/registry/react/components/progress/styles.css.ts +0 -53
  62. package/data/registry/react/components/radio/index.vanilla-extract.tsx +0 -65
  63. package/data/registry/react/components/radio/styles.css.ts +0 -79
  64. package/data/registry/react/components/rich-text-editor/index.vanilla-extract.tsx +0 -348
  65. package/data/registry/react/components/rich-text-editor/styles.css.ts +0 -243
  66. package/data/registry/react/components/select/index.vanilla-extract.tsx +0 -234
  67. package/data/registry/react/components/select/styles.css.ts +0 -225
  68. package/data/registry/react/components/separator/index.vanilla-extract.tsx +0 -46
  69. package/data/registry/react/components/separator/styles.css.ts +0 -24
  70. package/data/registry/react/components/sidebar/index.vanilla-extract.tsx +0 -1067
  71. package/data/registry/react/components/sidebar/styles.css.ts +0 -578
  72. package/data/registry/react/components/skeleton/index.vanilla-extract.tsx +0 -22
  73. package/data/registry/react/components/skeleton/styles.css.ts +0 -30
  74. package/data/registry/react/components/slider/index.vanilla-extract.tsx +0 -298
  75. package/data/registry/react/components/slider/styles.css.ts +0 -75
  76. package/data/registry/react/components/spinner/index.vanilla-extract.tsx +0 -38
  77. package/data/registry/react/components/spinner/styles.css.ts +0 -60
  78. package/data/registry/react/components/switch/index.vanilla-extract.tsx +0 -39
  79. package/data/registry/react/components/switch/styles.css.ts +0 -87
  80. package/data/registry/react/components/tabs/index.vanilla-extract.tsx +0 -91
  81. package/data/registry/react/components/tabs/styles.css.ts +0 -145
  82. package/data/registry/react/components/textarea/index.vanilla-extract.tsx +0 -23
  83. package/data/registry/react/components/textarea/styles.css.ts +0 -55
  84. package/data/registry/react/components/toast/index.vanilla-extract.tsx +0 -258
  85. package/data/registry/react/components/toast/styles.css.ts +0 -307
  86. package/data/registry/react/components/toggle/index.vanilla-extract.tsx +0 -131
  87. package/data/registry/react/components/toggle/styles.css.ts +0 -109
  88. package/data/registry/react/components/tooltip/index.vanilla-extract.tsx +0 -83
  89. package/data/registry/react/components/tooltip/styles.css.ts +0 -59
@@ -1,307 +0,0 @@
1
- import { style, keyframes } from "@vanilla-extract/css";
2
-
3
- export const shUiToastEnterRight = keyframes({
4
- "from": {
5
- opacity: 0,
6
- transform: "translateX(100%)",
7
- },
8
- "to": {
9
- opacity: 1,
10
- transform: "translateX(0)",
11
- },
12
- });
13
-
14
- export const shUiToastExitRight = keyframes({
15
- "from": {
16
- opacity: 1,
17
- transform: "translateX(0)",
18
- },
19
- "to": {
20
- opacity: 0,
21
- transform: "translateX(100%)",
22
- },
23
- });
24
-
25
- export const shUiToastEnterLeft = keyframes({
26
- "from": {
27
- opacity: 0,
28
- transform: "translateX(-100%)",
29
- },
30
- "to": {
31
- opacity: 1,
32
- transform: "translateX(0)",
33
- },
34
- });
35
-
36
- export const shUiToastExitLeft = keyframes({
37
- "from": {
38
- opacity: 1,
39
- transform: "translateX(0)",
40
- },
41
- "to": {
42
- opacity: 0,
43
- transform: "translateX(-100%)",
44
- },
45
- });
46
-
47
- export const shUiToastEnterBottom = keyframes({
48
- "from": {
49
- opacity: 0,
50
- transform: "translateY(100%)",
51
- },
52
- "to": {
53
- opacity: 1,
54
- transform: "translateY(0)",
55
- },
56
- });
57
-
58
- export const shUiToastExitBottom = keyframes({
59
- "from": {
60
- opacity: 1,
61
- transform: "translateY(0)",
62
- },
63
- "to": {
64
- opacity: 0,
65
- transform: "translateY(100%)",
66
- },
67
- });
68
-
69
- export const shUiToastEnterTop = keyframes({
70
- "from": {
71
- opacity: 0,
72
- transform: "translateY(-100%)",
73
- },
74
- "to": {
75
- opacity: 1,
76
- transform: "translateY(0)",
77
- },
78
- });
79
-
80
- export const shUiToastExitTop = keyframes({
81
- "from": {
82
- opacity: 1,
83
- transform: "translateY(0)",
84
- },
85
- "to": {
86
- opacity: 0,
87
- transform: "translateY(-100%)",
88
- },
89
- });
90
-
91
- export const toastViewport = style({
92
- position: "fixed",
93
- zIndex: "var(--z-toast)",
94
- display: "flex",
95
- flexDirection: "column",
96
- gap: "var(--space-2)",
97
- maxWidth: "24rem",
98
- width: "100%",
99
- pointerEvents: "none",
100
- selectors: {
101
- "&[data-position="bottom-right"]": {
102
- bottom: "var(--space-4)",
103
- right: "var(--space-4)",
104
- flexDirection: "column-reverse",
105
- },
106
- "&[data-position="bottom-left"]": {
107
- bottom: "var(--space-4)",
108
- left: "var(--space-4)",
109
- flexDirection: "column-reverse",
110
- },
111
- "&[data-position="bottom-center"]": {
112
- bottom: "var(--space-4)",
113
- left: "50%",
114
- transform: "translateX(-50%)",
115
- flexDirection: "column-reverse",
116
- },
117
- "&[data-position="top-right"]": {
118
- top: "var(--space-4)",
119
- right: "var(--space-4)",
120
- },
121
- "&[data-position="top-left"]": {
122
- top: "var(--space-4)",
123
- left: "var(--space-4)",
124
- },
125
- "&[data-position="top-center"]": {
126
- top: "var(--space-4)",
127
- left: "50%",
128
- transform: "translateX(-50%)",
129
- },
130
- },
131
- "@media": {
132
- "(max-width: 40rem)": {
133
- maxWidth: "100%",
134
- padding: "var(--space-4)",
135
- selectors: {
136
- "&[data-position="bottom-right"]": {
137
- right: 0,
138
- left: 0,
139
- bottom: 0,
140
- transform: "none",
141
- },
142
- "&[data-position="bottom-left"]": {
143
- right: 0,
144
- left: 0,
145
- bottom: 0,
146
- transform: "none",
147
- },
148
- "&[data-position="bottom-center"]": {
149
- right: 0,
150
- left: 0,
151
- bottom: 0,
152
- transform: "none",
153
- },
154
- "&[data-position="top-right"]": {
155
- right: 0,
156
- left: 0,
157
- top: 0,
158
- transform: "none",
159
- },
160
- "&[data-position="top-left"]": {
161
- right: 0,
162
- left: 0,
163
- top: 0,
164
- transform: "none",
165
- },
166
- "&[data-position="top-center"]": {
167
- right: 0,
168
- left: 0,
169
- top: 0,
170
- transform: "none",
171
- },
172
- },
173
- },
174
- },
175
- });
176
-
177
- export const toast = style({
178
- position: "relative",
179
- display: "flex",
180
- alignItems: "flex-start",
181
- gap: "0.625rem",
182
- width: "100%",
183
- padding: "var(--space-3) 2.25rem var(--space-3) var(--space-3)",
184
- background: "var(--background)",
185
- color: "var(--foreground)",
186
- border: "1px solid var(--border)",
187
- borderRadius: "var(--radius)",
188
- boxShadow: "0 4px 16px rgba(0, 0, 0, 0.12)",
189
- pointerEvents: "auto",
190
- "@media": {
191
- "(prefers-reduced-motion: reduce)": {
192
- animation: "none !important",
193
- },
194
- },
195
- });
196
-
197
- export const toast__icon = style({
198
- flexShrink: 0,
199
- display: "inline-flex",
200
- alignItems: "center",
201
- marginTop: "0.125rem",
202
- });
203
-
204
- export const toastSuccess = style({
205
- selectors: {
206
- [`& ${toast__icon}`]: {
207
- color: "var(--success, #16a34a)",
208
- },
209
- },
210
- });
211
-
212
- export const toastDanger = style({
213
- selectors: {
214
- [`& ${toast__icon}`]: {
215
- color: "var(--danger)",
216
- },
217
- },
218
- });
219
-
220
- export const toastWarning = style({
221
- selectors: {
222
- [`& ${toast__icon}`]: {
223
- color: "var(--warning, #d97706)",
224
- },
225
- },
226
- });
227
-
228
- export const toast__body = style({
229
- flex: 1,
230
- minWidth: 0,
231
- });
232
-
233
- export const toast__title = style({
234
- margin: 0,
235
- fontSize: "var(--text-sm)",
236
- fontWeight: "var(--weight-semibold)",
237
- lineHeight: 1.4,
238
- selectors: {
239
- [`& + ${toast__description}`]: {
240
- marginTop: "0.125rem",
241
- },
242
- },
243
- });
244
-
245
- export const toast__description = style({
246
- margin: 0,
247
- fontSize: "0.8125rem",
248
- lineHeight: 1.4,
249
- color: "var(--foreground-muted)",
250
- });
251
-
252
- export const toast__action = style({
253
- flexShrink: 0,
254
- display: "inline-flex",
255
- alignItems: "center",
256
- marginLeft: "auto",
257
- });
258
-
259
- export const toast__close = style({
260
- position: "absolute",
261
- top: "0.375rem",
262
- right: "0.375rem",
263
- display: "inline-flex",
264
- alignItems: "center",
265
- justifyContent: "center",
266
- width: "1.5rem",
267
- height: "1.5rem",
268
- padding: 0,
269
- border: "none",
270
- borderRadius: "calc(var(--radius) - 2px)",
271
- background: "transparent",
272
- color: "var(--foreground-muted)",
273
- fontSize: "var(--text-sm)",
274
- lineHeight: 1,
275
- cursor: "pointer",
276
- transition: "background-color var(--duration-fast), color var(--duration-fast)",
277
- selectors: {
278
- "&:hover": {
279
- background: "var(--background-muted)",
280
- color: "var(--foreground)",
281
- },
282
- "&:focus-visible": {
283
- outline: "var(--border-width-strong) solid var(--foreground)",
284
- outlineOffset: "2px",
285
- },
286
- },
287
- "@media": {
288
- "(prefers-reduced-motion: reduce)": {
289
- transition: "none",
290
- },
291
- },
292
- });
293
-
294
- /** 동적 키로 클래스 참조용 — `byKey[\`badge--${variant}\`]` 같은 패턴 지원. */
295
- export const byKey: Record<string, string> = {
296
- "toast-viewport": toastViewport,
297
- "toast": toast,
298
- "toast__icon": toast__icon,
299
- "toast--success": toastSuccess,
300
- "toast--danger": toastDanger,
301
- "toast--warning": toastWarning,
302
- "toast__body": toast__body,
303
- "toast__title": toast__title,
304
- "toast__description": toast__description,
305
- "toast__action": toast__action,
306
- "toast__close": toast__close,
307
- };
@@ -1,131 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { Toggle as BaseToggle } from "@base-ui/react/toggle";
5
- import { ToggleGroup as BaseToggleGroup } from "@base-ui/react/toggle-group";
6
- import { byKey, toggle, toggleSm, toggleMd, toggleLg, toggleOutline, toggleGhost, toggleGroup } from "./styles.css";
7
-
8
-
9
- import { cn } from "@SH_UI_UTILS@";
10
- /* ───────────── Toggle ───────────── */
11
-
12
- export type ToggleVariant = "outline" | "ghost";
13
- export type ToggleSize = "sm" | "md" | "lg";
14
-
15
- export type ToggleProps = Omit<
16
- React.ComponentPropsWithoutRef<typeof BaseToggle>,
17
- "className"
18
- > & {
19
- className?: string;
20
- /**
21
- * 외형 변형.
22
- * - `ghost` — 배경 없음, 눌림 시만 강조 (기본)
23
- * - `outline` — 항상 border 표시
24
- *
25
- * @default "ghost"
26
- */
27
- variant?: ToggleVariant;
28
- /**
29
- * 크기. `sm` / `md` / `lg`.
30
- *
31
- * @default "md"
32
- */
33
- size?: ToggleSize;
34
- };
35
-
36
- /**
37
- * 눌린 상태(pressed)를 가진 버튼. 툴바의 "굵게/기울임" 같은 즉시 토글 액션에 적합.
38
- * 시각만으로 상태를 구분하지 말고 `aria-label`이나 아이콘 옆 텍스트로 의미를 명확히 할 것.
39
- */
40
- export const Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(
41
- ({ className, variant = "ghost", size = "md", ...props }, ref) => (
42
- <BaseToggle
43
- ref={ref}
44
- className={cn(
45
- toggle,
46
- byKey[`toggle--${variant}`],
47
- byKey[`toggle--${size}`],
48
- className,
49
- )}
50
- {...props}
51
- />
52
- ),
53
- );
54
- Toggle.displayName = "Toggle";
55
-
56
- /* ───────────── ToggleGroup ───────────── */
57
-
58
- export type ToggleGroupProps = Omit<
59
- React.ComponentPropsWithoutRef<typeof BaseToggleGroup>,
60
- "className"
61
- > & {
62
- className?: string;
63
- /**
64
- * 그룹 내 모든 항목에 적용될 외형. 자식 ToggleGroupItem이 자동 상속한다.
65
- * @default "ghost"
66
- */
67
- variant?: ToggleVariant;
68
- /**
69
- * 그룹 내 모든 항목에 적용될 크기. 자식 ToggleGroupItem이 자동 상속한다.
70
- * @default "md"
71
- */
72
- size?: ToggleSize;
73
- };
74
-
75
- interface ToggleGroupContextValue {
76
- variant: ToggleVariant;
77
- size: ToggleSize;
78
- }
79
-
80
- const ToggleGroupContext = React.createContext<ToggleGroupContextValue>({
81
- variant: "ghost",
82
- size: "md",
83
- });
84
-
85
- export const useToggleGroupStyle = () => React.useContext(ToggleGroupContext);
86
-
87
- /**
88
- * 여러 ToggleGroupItem을 묶는 컨테이너. `toggleMultiple` 옵션으로 단일/다중 선택을
89
- * 결정하고, 그룹 단위로 variant·size를 적용한다. 항목들은 반드시 `ToggleGroupItem`을 사용할 것.
90
- */
91
- export const ToggleGroup = React.forwardRef<HTMLDivElement, ToggleGroupProps>(
92
- ({ className, variant = "ghost", size = "md", ...props }, ref) => (
93
- <ToggleGroupContext.Provider value={{ variant, size }}>
94
- <BaseToggleGroup
95
- ref={ref}
96
- className={cn(toggleGroup, className)}
97
- {...props}
98
- />
99
- </ToggleGroupContext.Provider>
100
- ),
101
- );
102
- ToggleGroup.displayName = "ToggleGroup";
103
-
104
- /* ───────────── ToggleGroupItem ───────────── */
105
-
106
- export type ToggleGroupItemProps = Omit<
107
- React.ComponentPropsWithoutRef<typeof BaseToggle>,
108
- "className"
109
- > & {
110
- className?: string;
111
- };
112
-
113
- /** ToggleGroup의 자식 항목. 부모 그룹의 variant·size를 자동으로 상속한다. */
114
- export const ToggleGroupItem = React.forwardRef<HTMLButtonElement, ToggleGroupItemProps>(
115
- ({ className, ...props }, ref) => {
116
- const { variant, size } = useToggleGroupStyle();
117
- return (
118
- <BaseToggle
119
- ref={ref}
120
- className={cn(
121
- toggle,
122
- byKey[`toggle--${variant}`],
123
- byKey[`toggle--${size}`],
124
- className,
125
- )}
126
- {...props}
127
- />
128
- );
129
- },
130
- );
131
- ToggleGroupItem.displayName = "ToggleGroupItem";
@@ -1,109 +0,0 @@
1
- import { style } from "@vanilla-extract/css";
2
-
3
- export const toggle = style({
4
- display: "inline-flex",
5
- alignItems: "center",
6
- justifyContent: "center",
7
- gap: "0.375rem",
8
- border: "1px solid transparent",
9
- borderRadius: "var(--radius)",
10
- fontWeight: "var(--weight-medium)",
11
- lineHeight: 1,
12
- cursor: "pointer",
13
- color: "var(--foreground-muted)",
14
- background: "transparent",
15
- transition: "background-color var(--duration-fast), color var(--duration-fast), border-color var(--duration-fast)",
16
- userSelect: "none",
17
- WebkitTapHighlightColor: "transparent",
18
- selectors: {
19
- "&[data-pressed]": {
20
- background: "var(--background-muted)",
21
- color: "var(--foreground)",
22
- },
23
- "&:focus-visible": {
24
- outline: "var(--border-width-strong) solid var(--foreground)",
25
- outlineOffset: "2px",
26
- },
27
- "&:disabled": {
28
- opacity: "var(--opacity-disabled)",
29
- pointerEvents: "none",
30
- },
31
- },
32
- "@media": {
33
- "(prefers-reduced-motion: reduce)": {
34
- transition: "none",
35
- },
36
- },
37
- });
38
-
39
- export const toggleSm = style({
40
- height: "var(--control-sm)",
41
- padding: "0 0.625rem",
42
- fontSize: "var(--text-sm)",
43
- "@media": {
44
- "(hover: none) and (pointer: coarse)": {
45
- height: "2.25rem",
46
- },
47
- },
48
- });
49
-
50
- export const toggleMd = style({
51
- height: "var(--control-md)",
52
- padding: "0 var(--space-3)",
53
- fontSize: "var(--text-sm)",
54
- "@media": {
55
- "(hover: none) and (pointer: coarse)": {
56
- height: "2.75rem",
57
- },
58
- },
59
- });
60
-
61
- export const toggleLg = style({
62
- height: "var(--control-lg)",
63
- padding: "0 var(--space-4)",
64
- fontSize: "var(--text-base)",
65
- });
66
-
67
- export const toggleOutline = style({
68
- borderColor: "var(--border)",
69
- selectors: {
70
- "&:hover:not(:disabled):not([data-pressed])": {
71
- background: "var(--background-muted)",
72
- color: "var(--foreground)",
73
- },
74
- "&[data-pressed]": {
75
- borderColor: "var(--border-strong)",
76
- },
77
- },
78
- });
79
-
80
- export const toggleGhost = style({
81
- selectors: {
82
- "&:hover:not(:disabled):not([data-pressed])": {
83
- background: "var(--background-muted)",
84
- color: "var(--foreground)",
85
- },
86
- },
87
- });
88
-
89
- export const toggleGroup = style({
90
- display: "inline-flex",
91
- alignItems: "center",
92
- gap: "var(--space-1)",
93
- selectors: {
94
- "&[data-orientation="vertical"]": {
95
- flexDirection: "column",
96
- },
97
- },
98
- });
99
-
100
- /** 동적 키로 클래스 참조용 — `byKey[\`badge--${variant}\`]` 같은 패턴 지원. */
101
- export const byKey: Record<string, string> = {
102
- "toggle": toggle,
103
- "toggle--sm": toggleSm,
104
- "toggle--md": toggleMd,
105
- "toggle--lg": toggleLg,
106
- "toggle--outline": toggleOutline,
107
- "toggle--ghost": toggleGhost,
108
- "toggle-group": toggleGroup,
109
- };
@@ -1,83 +0,0 @@
1
- import * as React from "react";
2
- import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
3
- import { byKey, tooltip__positioner, tooltip__content, tooltip__arrow } from "./styles.css";
4
-
5
- import { cn } from "@SH_UI_UTILS@";
6
- type WithStringClassName<T> = Omit<T, "className"> & { className?: string };
7
-
8
-
9
- /** 여러 Tooltip이 공통 delay를 공유하도록 묶는다. 앱 루트에 한 번 두는 것을 권장. */
10
- export const TooltipProvider = BaseTooltip.Provider;
11
-
12
- /** Tooltip 루트. Trigger + Content를 자식으로 갖는다. */
13
- export const Tooltip = BaseTooltip.Root;
14
-
15
- /** 호버/포커스로 tooltip을 표시할 엘리먼트를 감싼다. render prop으로 Button 등과 결합. */
16
- export const TooltipTrigger = BaseTooltip.Trigger;
17
-
18
- export interface TooltipContentProps
19
- extends WithStringClassName<
20
- React.ComponentPropsWithoutRef<typeof BaseTooltip.Popup>
21
- > {
22
- /**
23
- * Trigger 기준 배치 방향. 공간 부족 시 자동으로 반대편으로 뒤집힌다.
24
- * @default "top"
25
- */
26
- side?: "top" | "right" | "bottom" | "left";
27
- /**
28
- * 트리거 축에서의 정렬.
29
- * @default "center"
30
- */
31
- align?: "start" | "center" | "end";
32
- /**
33
- * Trigger와 Popup 사이 간격(px).
34
- * @default 6
35
- */
36
- sideOffset?: number;
37
- /**
38
- * Trigger를 가리키는 화살표 표시 여부.
39
- * @default false
40
- */
41
- showArrow?: boolean;
42
- /**
43
- * Portal이 마운트될 DOM 노드.
44
- * @default document.body
45
- */
46
- container?: React.ComponentPropsWithoutRef<
47
- typeof BaseTooltip.Portal
48
- >["container"];
49
- }
50
-
51
- /**
52
- * Tooltip의 본문. portal로 마운트되어 트리거 옆에 자동 위치 조정된다.
53
- * 내용은 짧게 — 긴 설명이 필요하면 Popover를 사용할 것.
54
- */
55
- export const TooltipContent = React.forwardRef<
56
- HTMLDivElement,
57
- TooltipContentProps
58
- >(function TooltipContent(
59
- { className, children, side, align, sideOffset = 6, showArrow, container, ...props },
60
- ref,
61
- ) {
62
- return (
63
- <BaseTooltip.Portal container={container}>
64
- <BaseTooltip.Positioner
65
- className={tooltip__positioner}
66
- side={side}
67
- align={align}
68
- sideOffset={sideOffset}
69
- >
70
- <BaseTooltip.Popup
71
- ref={ref}
72
- className={cn(tooltip__content, className)}
73
- {...props}
74
- >
75
- {showArrow && (
76
- <BaseTooltip.Arrow className={tooltip__arrow} />
77
- )}
78
- {children}
79
- </BaseTooltip.Popup>
80
- </BaseTooltip.Positioner>
81
- </BaseTooltip.Portal>
82
- );
83
- });
@@ -1,59 +0,0 @@
1
- import { style } from "@vanilla-extract/css";
2
-
3
- export const tooltip__positioner = style({
4
- zIndex: "var(--z-tooltip, var(--z-popover))",
5
- outline: "none",
6
- });
7
-
8
- export const tooltip__content = style({
9
- padding: "0.375rem 0.625rem",
10
- background: "var(--foreground)",
11
- color: "var(--background)",
12
- borderRadius: "calc(var(--radius) - 2px)",
13
- fontSize: "var(--text-xs)",
14
- lineHeight: 1.4,
15
- maxWidth: "20rem",
16
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.12)",
17
- transformOrigin: "var(--transform-origin)",
18
- outline: "none",
19
- transition: "opacity 120ms ease,\n transform 120ms ease",
20
- selectors: {
21
- "&[data-starting-style]": {
22
- opacity: 0,
23
- transform: "scale(0.96)",
24
- },
25
- "&[data-ending-style]": {
26
- opacity: 0,
27
- transform: "scale(0.96)",
28
- },
29
- },
30
- "@media": {
31
- "(prefers-reduced-motion: reduce)": {
32
- transition: "none",
33
- selectors: {
34
- "&[data-starting-style]": {
35
- transform: "none",
36
- },
37
- "&[data-ending-style]": {
38
- transform: "none",
39
- },
40
- },
41
- },
42
- },
43
- });
44
-
45
- export const tooltip__arrow = style({
46
- color: "var(--foreground)",
47
- selectors: {
48
- "& svg": {
49
- display: "block",
50
- },
51
- },
52
- });
53
-
54
- /** 동적 키로 클래스 참조용 — `byKey[\`badge--${variant}\`]` 같은 패턴 지원. */
55
- export const byKey: Record<string, string> = {
56
- "tooltip__positioner": tooltip__positioner,
57
- "tooltip__content": tooltip__content,
58
- "tooltip__arrow": tooltip__arrow,
59
- };