@mzc-fe/design-system 0.0.5 → 0.0.7-rc.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 (174) hide show
  1. package/components/accordion/accordion.tsx +114 -0
  2. package/components/accordion/index.ts +1 -0
  3. package/components/alert/alert.tsx +97 -0
  4. package/components/alert/index.ts +1 -0
  5. package/components/alert-dialog/alert-dialog.tsx +190 -0
  6. package/components/alert-dialog/index.ts +1 -0
  7. package/components/aspect-ratio/aspect-ratio.tsx +23 -0
  8. package/components/aspect-ratio/index.ts +1 -0
  9. package/components/avatar/avatar.tsx +62 -0
  10. package/components/avatar/index.ts +1 -0
  11. package/components/badge/badge.tsx +58 -0
  12. package/components/badge/index.ts +1 -0
  13. package/components/breadcrumb/breadcrumb.tsx +132 -0
  14. package/components/breadcrumb/index.ts +1 -0
  15. package/components/button/button.tsx +77 -0
  16. package/components/button/index.ts +1 -0
  17. package/components/button-group/button-group.tsx +99 -0
  18. package/components/button-group/index.ts +1 -0
  19. package/components/calendar/calendar.tsx +235 -0
  20. package/components/calendar/index.ts +1 -0
  21. package/components/card/card.tsx +107 -0
  22. package/components/card/index.ts +1 -0
  23. package/components/carousel/carousel.tsx +263 -0
  24. package/components/carousel/index.ts +1 -0
  25. package/components/chart/chart.tsx +377 -0
  26. package/components/chart/index.ts +1 -0
  27. package/components/checkbox/checkbox.tsx +41 -0
  28. package/components/checkbox/index.ts +1 -0
  29. package/components/collapsible/collapsible.tsx +44 -0
  30. package/components/collapsible/index.ts +1 -0
  31. package/components/command/command.tsx +201 -0
  32. package/components/command/index.ts +1 -0
  33. package/components/context-menu/context-menu.tsx +270 -0
  34. package/components/context-menu/index.ts +1 -0
  35. package/components/dialog/dialog.tsx +166 -0
  36. package/components/dialog/index.ts +1 -0
  37. package/components/drawer/drawer.tsx +154 -0
  38. package/components/drawer/index.ts +1 -0
  39. package/components/dropdown-menu/dropdown-menu.tsx +276 -0
  40. package/components/dropdown-menu/index.ts +1 -0
  41. package/components/empty/empty.tsx +129 -0
  42. package/components/empty/index.ts +1 -0
  43. package/components/field/field.tsx +272 -0
  44. package/components/field/index.ts +1 -0
  45. package/components/form/form.tsx +197 -0
  46. package/components/form/index.ts +1 -0
  47. package/components/hover-card/hover-card.tsx +57 -0
  48. package/components/hover-card/index.ts +1 -0
  49. package/components/input/index.ts +1 -0
  50. package/components/input/input.tsx +31 -0
  51. package/components/input-group/index.ts +1 -0
  52. package/components/input-group/input-group.tsx +189 -0
  53. package/components/input-otp/index.ts +1 -0
  54. package/components/input-otp/input-otp.tsx +99 -0
  55. package/components/item/index.ts +1 -0
  56. package/components/item/item.tsx +225 -0
  57. package/components/kbd/index.ts +1 -0
  58. package/components/kbd/kbd.tsx +38 -0
  59. package/components/label/index.ts +1 -0
  60. package/components/label/label.tsx +33 -0
  61. package/components/menubar/index.ts +1 -0
  62. package/components/menubar/menubar.tsx +299 -0
  63. package/components/navigation-menu/index.ts +1 -0
  64. package/components/navigation-menu/navigation-menu.tsx +194 -0
  65. package/components/pagination/index.ts +1 -0
  66. package/components/pagination/pagination.tsx +153 -0
  67. package/components/popover/index.ts +1 -0
  68. package/components/popover/popover.tsx +106 -0
  69. package/components/progress/index.ts +1 -0
  70. package/components/progress/progress.tsx +39 -0
  71. package/components/radio-group/index.ts +1 -0
  72. package/components/radio-group/radio-group.tsx +57 -0
  73. package/components/resizable/index.ts +1 -0
  74. package/components/resizable/resizable.tsx +73 -0
  75. package/components/scroll-area/index.ts +1 -0
  76. package/components/scroll-area/scroll-area.tsx +72 -0
  77. package/components/select/index.ts +1 -0
  78. package/components/select/select.tsx +213 -0
  79. package/components/separator/index.ts +1 -0
  80. package/components/separator/separator.tsx +39 -0
  81. package/components/sheet/index.ts +1 -0
  82. package/components/sheet/sheet.tsx +160 -0
  83. package/components/sidebar/index.ts +1 -0
  84. package/components/sidebar/sidebar.tsx +776 -0
  85. package/components/skeleton/index.ts +1 -0
  86. package/components/skeleton/skeleton.tsx +21 -0
  87. package/components/slider/index.ts +1 -0
  88. package/components/slider/slider.tsx +75 -0
  89. package/components/sonner/index.ts +2 -0
  90. package/components/sonner/sonner.tsx +52 -0
  91. package/components/spinner/index.ts +1 -0
  92. package/components/spinner/spinner.tsx +26 -0
  93. package/components/switch/index.ts +1 -0
  94. package/components/switch/switch.tsx +39 -0
  95. package/components/table/index.ts +1 -0
  96. package/components/table/table.tsx +140 -0
  97. package/components/tabs/index.ts +1 -0
  98. package/components/tabs/tabs.tsx +94 -0
  99. package/components/textarea/index.ts +1 -0
  100. package/components/textarea/textarea.tsx +26 -0
  101. package/components/toggle/index.ts +1 -0
  102. package/components/toggle/toggle.tsx +58 -0
  103. package/components/toggle-group/index.ts +1 -0
  104. package/components/toggle-group/toggle-group.tsx +97 -0
  105. package/components/tooltip/index.ts +1 -0
  106. package/components/tooltip/tooltip.tsx +82 -0
  107. package/dist/components/accordion/accordion.d.ts +50 -0
  108. package/dist/components/alert/alert.d.ts +31 -0
  109. package/dist/components/alert-dialog/alert-dialog.d.ts +35 -0
  110. package/dist/components/aspect-ratio/aspect-ratio.d.ts +12 -0
  111. package/dist/components/avatar/avatar.d.ts +11 -0
  112. package/dist/components/badge/badge.d.ts +12 -0
  113. package/dist/components/breadcrumb/breadcrumb.d.ts +23 -0
  114. package/dist/components/button/button.d.ts +15 -0
  115. package/dist/components/button-group/button-group.d.ts +16 -0
  116. package/dist/components/calendar/calendar.d.ts +15 -0
  117. package/dist/components/card/card.d.ts +15 -0
  118. package/dist/components/carousel/carousel.d.ts +24 -0
  119. package/dist/components/chart/chart.d.ts +20 -0
  120. package/dist/components/checkbox/checkbox.d.ts +9 -0
  121. package/dist/components/collapsible/collapsible.d.ts +13 -0
  122. package/dist/components/command/command.d.ts +18 -0
  123. package/dist/components/context-menu/context-menu.d.ts +18 -0
  124. package/dist/components/dialog/dialog.d.ts +25 -0
  125. package/dist/components/drawer/drawer.d.ts +18 -0
  126. package/dist/components/dropdown-menu/dropdown-menu.d.ts +21 -0
  127. package/dist/components/empty/empty.d.ts +25 -0
  128. package/dist/components/field/field.d.ts +26 -0
  129. package/dist/components/form/form.d.ts +30 -1
  130. package/dist/components/hover-card/hover-card.d.ts +13 -0
  131. package/dist/components/input/input.d.ts +10 -0
  132. package/dist/components/input-group/input-group.d.ts +19 -0
  133. package/dist/components/input-otp/input-otp.d.ts +23 -0
  134. package/dist/components/item/item.d.ts +33 -1
  135. package/dist/components/kbd/kbd.d.ts +10 -0
  136. package/dist/components/label/label.d.ts +9 -0
  137. package/dist/components/menubar/menubar.d.ts +25 -0
  138. package/dist/components/navigation-menu/navigation-menu.d.ts +26 -0
  139. package/dist/components/pagination/pagination.d.ts +26 -0
  140. package/dist/components/popover/popover.d.ts +17 -0
  141. package/dist/components/progress/progress.d.ts +10 -0
  142. package/dist/components/radio-group/radio-group.d.ts +12 -0
  143. package/dist/components/resizable/resizable.d.ts +19 -0
  144. package/dist/components/scroll-area/scroll-area.d.ts +14 -0
  145. package/dist/components/select/select.d.ts +25 -0
  146. package/dist/components/separator/separator.d.ts +11 -0
  147. package/dist/components/sheet/sheet.d.ts +23 -0
  148. package/dist/components/sidebar/sidebar.d.ts +50 -0
  149. package/dist/components/skeleton/skeleton.d.ts +8 -0
  150. package/dist/components/slider/slider.d.ts +12 -0
  151. package/dist/components/sonner/sonner.d.ts +14 -0
  152. package/dist/components/spinner/spinner.d.ts +9 -0
  153. package/dist/components/switch/switch.d.ts +8 -0
  154. package/dist/components/table/table.d.ts +26 -0
  155. package/dist/components/tabs/tabs.d.ts +16 -6
  156. package/dist/components/textarea/textarea.d.ts +8 -0
  157. package/dist/components/toggle/toggle.d.ts +13 -0
  158. package/dist/components/toggle-group/toggle-group.d.ts +1 -0
  159. package/dist/components/tooltip/tooltip.d.ts +21 -0
  160. package/dist/design-system.css +1 -1
  161. package/dist/design-system.es.js +3493 -28470
  162. package/dist/design-system.umd.js +4 -257
  163. package/dist/index.d.ts +1 -1
  164. package/foundations/ThemeProvider.tsx +77 -0
  165. package/foundations/color.css +232 -0
  166. package/foundations/palette.css +249 -0
  167. package/foundations/spacing.css +8 -0
  168. package/foundations/typography.css +143 -0
  169. package/hooks/use-mobile.ts +19 -0
  170. package/index.css +173 -0
  171. package/index.ts +339 -0
  172. package/lib/utils.ts +6 -0
  173. package/package.json +40 -19
  174. package/README.md +0 -184
@@ -0,0 +1,106 @@
1
+ "use client"
2
+
3
+ import { Popover as PopoverPrimitive } from "radix-ui"
4
+ import * as React from "react"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ /**
9
+ * 트리거 요소 근처에 팝업 콘텐츠를 표시하는 팝오버 컴포넌트입니다.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <Popover>
14
+ * <PopoverTrigger>열기</PopoverTrigger>
15
+ * <PopoverContent>팝오버 내용</PopoverContent>
16
+ * </Popover>
17
+ * ```
18
+ */
19
+ function Popover({
20
+ ...props
21
+ }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
22
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
23
+ }
24
+
25
+ /** 팝오버를 열기 위한 트리거 요소입니다. */
26
+ function PopoverTrigger({
27
+ ...props
28
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
29
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
30
+ }
31
+
32
+ /**
33
+ * 팝오버의 콘텐츠 영역입니다.
34
+ * @param props.align - 정렬 방식 ('start' | 'center' | 'end')
35
+ * @param props.sideOffset - 트리거와의 간격 (기본값: 4)
36
+ */
37
+ function PopoverContent({
38
+ className,
39
+ align = "center",
40
+ sideOffset = 4,
41
+ ...props
42
+ }: React.ComponentProps<typeof PopoverPrimitive.Content>) {
43
+ return (
44
+ <PopoverPrimitive.Portal>
45
+ <PopoverPrimitive.Content
46
+ data-slot="popover-content"
47
+ align={align}
48
+ sideOffset={sideOffset}
49
+ className={cn(
50
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 flex flex-col gap-2.5 rounded-lg p-2.5 text-sm shadow-md ring-1 duration-100 z-50 w-72 origin-(--radix-popover-content-transform-origin) outline-hidden",
51
+ className
52
+ )}
53
+ {...props}
54
+ />
55
+ </PopoverPrimitive.Portal>
56
+ )
57
+ }
58
+
59
+ function PopoverAnchor({
60
+ ...props
61
+ }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
62
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
63
+ }
64
+
65
+ function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
66
+ return (
67
+ <div
68
+ data-slot="popover-header"
69
+ className={cn("flex flex-col gap-0.5 text-sm", className)}
70
+ {...props}
71
+ />
72
+ )
73
+ }
74
+
75
+ function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) {
76
+ return (
77
+ <div
78
+ data-slot="popover-title"
79
+ className={cn("font-medium", className)}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ function PopoverDescription({
86
+ className,
87
+ ...props
88
+ }: React.ComponentProps<"p">) {
89
+ return (
90
+ <p
91
+ data-slot="popover-description"
92
+ className={cn("text-muted-foreground", className)}
93
+ {...props}
94
+ />
95
+ )
96
+ }
97
+
98
+ export {
99
+ Popover,
100
+ PopoverAnchor,
101
+ PopoverContent,
102
+ PopoverDescription,
103
+ PopoverHeader,
104
+ PopoverTitle,
105
+ PopoverTrigger
106
+ }
@@ -0,0 +1 @@
1
+ export * from "./progress";
@@ -0,0 +1,39 @@
1
+ import * as React from "react"
2
+ import * as ProgressPrimitive from "@radix-ui/react-progress"
3
+
4
+ import { cn } from "@/lib/utils"
5
+
6
+ /**
7
+ * 작업 진행 상태를 시각적으로 표시하는 프로그레스 바 컴포넌트입니다.
8
+ *
9
+ * @param props.value - 진행률 (0-100)
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <Progress value={45} />
14
+ * ```
15
+ */
16
+ function Progress({
17
+ className,
18
+ value,
19
+ ...props
20
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
21
+ return (
22
+ <ProgressPrimitive.Root
23
+ data-slot="progress"
24
+ className={cn(
25
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
26
+ className
27
+ )}
28
+ {...props}
29
+ >
30
+ <ProgressPrimitive.Indicator
31
+ data-slot="progress-indicator"
32
+ className="bg-primary h-full w-full flex-1 transition-all"
33
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
34
+ />
35
+ </ProgressPrimitive.Root>
36
+ )
37
+ }
38
+
39
+ export { Progress }
@@ -0,0 +1 @@
1
+ export * from "./radio-group";
@@ -0,0 +1,57 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
5
+ import { CircleIcon } from "lucide-react"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ /**
10
+ * 여러 옵션 중 하나를 선택하는 라디오 그룹 컴포넌트입니다.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <RadioGroup defaultValue="option1">
15
+ * <RadioGroupItem value="option1" />
16
+ * <RadioGroupItem value="option2" />
17
+ * </RadioGroup>
18
+ * ```
19
+ */
20
+ function RadioGroup({
21
+ className,
22
+ ...props
23
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
24
+ return (
25
+ <RadioGroupPrimitive.Root
26
+ data-slot="radio-group"
27
+ className={cn("grid gap-3", className)}
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ /** 라디오 그룹의 개별 옵션 아이템입니다. */
34
+ function RadioGroupItem({
35
+ className,
36
+ ...props
37
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
38
+ return (
39
+ <RadioGroupPrimitive.Item
40
+ data-slot="radio-group-item"
41
+ className={cn(
42
+ "border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <RadioGroupPrimitive.Indicator
48
+ data-slot="radio-group-indicator"
49
+ className="relative flex items-center justify-center"
50
+ >
51
+ <CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
52
+ </RadioGroupPrimitive.Indicator>
53
+ </RadioGroupPrimitive.Item>
54
+ )
55
+ }
56
+
57
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1 @@
1
+ export * from "./resizable";
@@ -0,0 +1,73 @@
1
+ import * as React from "react"
2
+ import { GripVerticalIcon } from "lucide-react"
3
+ import * as ResizablePrimitive from "react-resizable-panels"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ /**
8
+ * 크기 조절 가능한 패널 그룹 컴포넌트입니다.
9
+ *
10
+ * @param props.direction - 패널 방향 ('horizontal' | 'vertical')
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <ResizablePanelGroup direction="horizontal">
15
+ * <ResizablePanel>패널 1</ResizablePanel>
16
+ * <ResizableHandle />
17
+ * <ResizablePanel>패널 2</ResizablePanel>
18
+ * </ResizablePanelGroup>
19
+ * ```
20
+ */
21
+ function ResizablePanelGroup({
22
+ className,
23
+ ...props
24
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {
25
+ return (
26
+ <ResizablePrimitive.PanelGroup
27
+ data-slot="resizable-panel-group"
28
+ className={cn(
29
+ "flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
30
+ className
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ /** 크기 조절 가능한 패널입니다. */
38
+ function ResizablePanel({
39
+ ...props
40
+ }: React.ComponentProps<typeof ResizablePrimitive.Panel>) {
41
+ return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
42
+ }
43
+
44
+ /**
45
+ * 패널 크기 조절 핸들입니다.
46
+ * @param props.withHandle - 드래그 핸들 아이콘 표시 여부
47
+ */
48
+ function ResizableHandle({
49
+ withHandle,
50
+ className,
51
+ ...props
52
+ }: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
53
+ withHandle?: boolean
54
+ }) {
55
+ return (
56
+ <ResizablePrimitive.PanelResizeHandle
57
+ data-slot="resizable-handle"
58
+ className={cn(
59
+ "bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ {withHandle && (
65
+ <div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
66
+ <GripVerticalIcon className="size-2.5" />
67
+ </div>
68
+ )}
69
+ </ResizablePrimitive.PanelResizeHandle>
70
+ )
71
+ }
72
+
73
+ export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
@@ -0,0 +1 @@
1
+ export * from "./scroll-area";
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ /**
9
+ * 커스텀 스크롤바를 제공하는 스크롤 영역 컴포넌트입니다.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <ScrollArea className="h-[200px]">
14
+ * <div>스크롤 가능한 콘텐츠</div>
15
+ * </ScrollArea>
16
+ * ```
17
+ */
18
+ function ScrollArea({
19
+ className,
20
+ children,
21
+ ...props
22
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
23
+ return (
24
+ <ScrollAreaPrimitive.Root
25
+ data-slot="scroll-area"
26
+ className={cn("relative", className)}
27
+ {...props}
28
+ >
29
+ <ScrollAreaPrimitive.Viewport
30
+ data-slot="scroll-area-viewport"
31
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
32
+ >
33
+ {children}
34
+ </ScrollAreaPrimitive.Viewport>
35
+ <ScrollBar />
36
+ <ScrollAreaPrimitive.Corner />
37
+ </ScrollAreaPrimitive.Root>
38
+ )
39
+ }
40
+
41
+ /**
42
+ * 스크롤바 컴포넌트입니다.
43
+ * @param props.orientation - 스크롤바 방향 ('vertical' | 'horizontal')
44
+ */
45
+ function ScrollBar({
46
+ className,
47
+ orientation = "vertical",
48
+ ...props
49
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
50
+ return (
51
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
52
+ data-slot="scroll-area-scrollbar"
53
+ orientation={orientation}
54
+ className={cn(
55
+ "flex touch-none p-px transition-colors select-none",
56
+ orientation === "vertical" &&
57
+ "h-full w-2.5 border-l border-l-transparent",
58
+ orientation === "horizontal" &&
59
+ "h-2.5 flex-col border-t border-t-transparent",
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ <ScrollAreaPrimitive.ScrollAreaThumb
65
+ data-slot="scroll-area-thumb"
66
+ className="bg-border relative flex-1 rounded-full"
67
+ />
68
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
69
+ )
70
+ }
71
+
72
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1 @@
1
+ export * from "./select";
@@ -0,0 +1,213 @@
1
+ import * as React from "react"
2
+ import * as SelectPrimitive from "@radix-ui/react-select"
3
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ /**
8
+ * 옵션 목록에서 하나의 값을 선택하는 셀렉트 컴포넌트입니다.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * <Select>
13
+ * <SelectTrigger>
14
+ * <SelectValue placeholder="선택하세요" />
15
+ * </SelectTrigger>
16
+ * <SelectContent>
17
+ * <SelectItem value="1">옵션 1</SelectItem>
18
+ * <SelectItem value="2">옵션 2</SelectItem>
19
+ * </SelectContent>
20
+ * </Select>
21
+ * ```
22
+ */
23
+ function Select({
24
+ ...props
25
+ }: React.ComponentProps<typeof SelectPrimitive.Root>) {
26
+ return <SelectPrimitive.Root data-slot="select" {...props} />
27
+ }
28
+
29
+ function SelectGroup({
30
+ ...props
31
+ }: React.ComponentProps<typeof SelectPrimitive.Group>) {
32
+ return <SelectPrimitive.Group data-slot="select-group" {...props} />
33
+ }
34
+
35
+ function SelectValue({
36
+ ...props
37
+ }: React.ComponentProps<typeof SelectPrimitive.Value>) {
38
+ return <SelectPrimitive.Value data-slot="select-value" {...props} />
39
+ }
40
+
41
+ /**
42
+ * 셀렉트 트리거 버튼입니다.
43
+ * @param props.size - 크기 ('sm' | 'default')
44
+ */
45
+ function SelectTrigger({
46
+ className,
47
+ size = "default",
48
+ children,
49
+ ...props
50
+ }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
51
+ size?: "sm" | "default"
52
+ }) {
53
+ return (
54
+ <SelectPrimitive.Trigger
55
+ data-slot="select-trigger"
56
+ data-size={size}
57
+ className={cn(
58
+ "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
59
+ className
60
+ )}
61
+ {...props}
62
+ >
63
+ {children}
64
+ <SelectPrimitive.Icon asChild>
65
+ <ChevronDownIcon className="size-4 opacity-50" />
66
+ </SelectPrimitive.Icon>
67
+ </SelectPrimitive.Trigger>
68
+ )
69
+ }
70
+
71
+ /**
72
+ * 셀렉트 옵션 목록 콘텐츠입니다.
73
+ * @param props.position - 위치 정렬 방식 ('item-aligned' | 'popper')
74
+ */
75
+ function SelectContent({
76
+ className,
77
+ children,
78
+ position = "item-aligned",
79
+ align = "center",
80
+ ...props
81
+ }: React.ComponentProps<typeof SelectPrimitive.Content>) {
82
+ return (
83
+ <SelectPrimitive.Portal>
84
+ <SelectPrimitive.Content
85
+ data-slot="select-content"
86
+ className={cn(
87
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
88
+ position === "popper" &&
89
+ "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
90
+ className
91
+ )}
92
+ position={position}
93
+ align={align}
94
+ {...props}
95
+ >
96
+ <SelectScrollUpButton />
97
+ <SelectPrimitive.Viewport
98
+ className={cn(
99
+ "p-1",
100
+ position === "popper" &&
101
+ "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
102
+ )}
103
+ >
104
+ {children}
105
+ </SelectPrimitive.Viewport>
106
+ <SelectScrollDownButton />
107
+ </SelectPrimitive.Content>
108
+ </SelectPrimitive.Portal>
109
+ )
110
+ }
111
+
112
+ function SelectLabel({
113
+ className,
114
+ ...props
115
+ }: React.ComponentProps<typeof SelectPrimitive.Label>) {
116
+ return (
117
+ <SelectPrimitive.Label
118
+ data-slot="select-label"
119
+ className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
120
+ {...props}
121
+ />
122
+ )
123
+ }
124
+
125
+ /** 셀렉트 옵션 아이템입니다. */
126
+ function SelectItem({
127
+ className,
128
+ children,
129
+ ...props
130
+ }: React.ComponentProps<typeof SelectPrimitive.Item>) {
131
+ return (
132
+ <SelectPrimitive.Item
133
+ data-slot="select-item"
134
+ className={cn(
135
+ "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
136
+ className
137
+ )}
138
+ {...props}
139
+ >
140
+ <span
141
+ data-slot="select-item-indicator"
142
+ className="absolute right-2 flex size-3.5 items-center justify-center"
143
+ >
144
+ <SelectPrimitive.ItemIndicator>
145
+ <CheckIcon className="size-4" />
146
+ </SelectPrimitive.ItemIndicator>
147
+ </span>
148
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
149
+ </SelectPrimitive.Item>
150
+ )
151
+ }
152
+
153
+ function SelectSeparator({
154
+ className,
155
+ ...props
156
+ }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
157
+ return (
158
+ <SelectPrimitive.Separator
159
+ data-slot="select-separator"
160
+ className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
161
+ {...props}
162
+ />
163
+ )
164
+ }
165
+
166
+ function SelectScrollUpButton({
167
+ className,
168
+ ...props
169
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
170
+ return (
171
+ <SelectPrimitive.ScrollUpButton
172
+ data-slot="select-scroll-up-button"
173
+ className={cn(
174
+ "flex cursor-default items-center justify-center py-1",
175
+ className
176
+ )}
177
+ {...props}
178
+ >
179
+ <ChevronUpIcon className="size-4" />
180
+ </SelectPrimitive.ScrollUpButton>
181
+ )
182
+ }
183
+
184
+ function SelectScrollDownButton({
185
+ className,
186
+ ...props
187
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
188
+ return (
189
+ <SelectPrimitive.ScrollDownButton
190
+ data-slot="select-scroll-down-button"
191
+ className={cn(
192
+ "flex cursor-default items-center justify-center py-1",
193
+ className
194
+ )}
195
+ {...props}
196
+ >
197
+ <ChevronDownIcon className="size-4" />
198
+ </SelectPrimitive.ScrollDownButton>
199
+ )
200
+ }
201
+
202
+ export {
203
+ Select,
204
+ SelectContent,
205
+ SelectGroup,
206
+ SelectItem,
207
+ SelectLabel,
208
+ SelectScrollDownButton,
209
+ SelectScrollUpButton,
210
+ SelectSeparator,
211
+ SelectTrigger,
212
+ SelectValue,
213
+ }
@@ -0,0 +1 @@
1
+ export * from "./separator";
@@ -0,0 +1,39 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as SeparatorPrimitive from "@radix-ui/react-separator"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ /**
9
+ * 콘텐츠를 시각적으로 분리하는 구분선 컴포넌트입니다.
10
+ *
11
+ * @param props.orientation - 방향 ('horizontal' | 'vertical')
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <Separator />
16
+ * <Separator orientation="vertical" />
17
+ * ```
18
+ */
19
+ function Separator({
20
+ className,
21
+ orientation = "horizontal",
22
+ decorative = true,
23
+ ...props
24
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
25
+ return (
26
+ <SeparatorPrimitive.Root
27
+ data-slot="separator"
28
+ decorative={decorative}
29
+ orientation={orientation}
30
+ className={cn(
31
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
32
+ className
33
+ )}
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ export { Separator }
@@ -0,0 +1 @@
1
+ export * from "./sheet";