@mzc-fe/design-system 0.0.6 → 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.
- package/components/accordion/accordion.tsx +114 -0
- package/components/accordion/index.ts +1 -0
- package/components/alert/alert.tsx +97 -0
- package/components/alert/index.ts +1 -0
- package/components/alert-dialog/alert-dialog.tsx +190 -0
- package/components/alert-dialog/index.ts +1 -0
- package/components/aspect-ratio/aspect-ratio.tsx +23 -0
- package/components/aspect-ratio/index.ts +1 -0
- package/components/avatar/avatar.tsx +62 -0
- package/components/avatar/index.ts +1 -0
- package/components/badge/badge.tsx +58 -0
- package/components/badge/index.ts +1 -0
- package/components/breadcrumb/breadcrumb.tsx +132 -0
- package/components/breadcrumb/index.ts +1 -0
- package/components/button/button.tsx +77 -0
- package/components/button/index.ts +1 -0
- package/components/button-group/button-group.tsx +99 -0
- package/components/button-group/index.ts +1 -0
- package/components/calendar/calendar.tsx +235 -0
- package/components/calendar/index.ts +1 -0
- package/components/card/card.tsx +107 -0
- package/components/card/index.ts +1 -0
- package/components/carousel/carousel.tsx +263 -0
- package/components/carousel/index.ts +1 -0
- package/components/chart/chart.tsx +377 -0
- package/components/chart/index.ts +1 -0
- package/components/checkbox/checkbox.tsx +41 -0
- package/components/checkbox/index.ts +1 -0
- package/components/collapsible/collapsible.tsx +44 -0
- package/components/collapsible/index.ts +1 -0
- package/components/command/command.tsx +201 -0
- package/components/command/index.ts +1 -0
- package/components/context-menu/context-menu.tsx +270 -0
- package/components/context-menu/index.ts +1 -0
- package/components/dialog/dialog.tsx +166 -0
- package/components/dialog/index.ts +1 -0
- package/components/drawer/drawer.tsx +154 -0
- package/components/drawer/index.ts +1 -0
- package/components/dropdown-menu/dropdown-menu.tsx +276 -0
- package/components/dropdown-menu/index.ts +1 -0
- package/components/empty/empty.tsx +129 -0
- package/components/empty/index.ts +1 -0
- package/components/field/field.tsx +272 -0
- package/components/field/index.ts +1 -0
- package/components/form/form.tsx +197 -0
- package/components/form/index.ts +1 -0
- package/components/hover-card/hover-card.tsx +57 -0
- package/components/hover-card/index.ts +1 -0
- package/components/input/index.ts +1 -0
- package/components/input/input.tsx +31 -0
- package/components/input-group/index.ts +1 -0
- package/components/input-group/input-group.tsx +189 -0
- package/components/input-otp/index.ts +1 -0
- package/components/input-otp/input-otp.tsx +99 -0
- package/components/item/index.ts +1 -0
- package/components/item/item.tsx +225 -0
- package/components/kbd/index.ts +1 -0
- package/components/kbd/kbd.tsx +38 -0
- package/components/label/index.ts +1 -0
- package/components/label/label.tsx +33 -0
- package/components/menubar/index.ts +1 -0
- package/components/menubar/menubar.tsx +299 -0
- package/components/navigation-menu/index.ts +1 -0
- package/components/navigation-menu/navigation-menu.tsx +194 -0
- package/components/pagination/index.ts +1 -0
- package/components/pagination/pagination.tsx +153 -0
- package/components/popover/index.ts +1 -0
- package/components/popover/popover.tsx +106 -0
- package/components/progress/index.ts +1 -0
- package/components/progress/progress.tsx +39 -0
- package/components/radio-group/index.ts +1 -0
- package/components/radio-group/radio-group.tsx +57 -0
- package/components/resizable/index.ts +1 -0
- package/components/resizable/resizable.tsx +73 -0
- package/components/scroll-area/index.ts +1 -0
- package/components/scroll-area/scroll-area.tsx +72 -0
- package/components/select/index.ts +1 -0
- package/components/select/select.tsx +213 -0
- package/components/separator/index.ts +1 -0
- package/components/separator/separator.tsx +39 -0
- package/components/sheet/index.ts +1 -0
- package/components/sheet/sheet.tsx +160 -0
- package/components/sidebar/index.ts +1 -0
- package/components/sidebar/sidebar.tsx +776 -0
- package/components/skeleton/index.ts +1 -0
- package/components/skeleton/skeleton.tsx +21 -0
- package/components/slider/index.ts +1 -0
- package/components/slider/slider.tsx +75 -0
- package/components/sonner/index.ts +2 -0
- package/components/sonner/sonner.tsx +52 -0
- package/components/spinner/index.ts +1 -0
- package/components/spinner/spinner.tsx +26 -0
- package/components/switch/index.ts +1 -0
- package/components/switch/switch.tsx +39 -0
- package/components/table/index.ts +1 -0
- package/components/table/table.tsx +140 -0
- package/components/tabs/index.ts +1 -0
- package/components/tabs/tabs.tsx +94 -0
- package/components/textarea/index.ts +1 -0
- package/components/textarea/textarea.tsx +26 -0
- package/components/toggle/index.ts +1 -0
- package/components/toggle/toggle.tsx +58 -0
- package/components/toggle-group/index.ts +1 -0
- package/components/toggle-group/toggle-group.tsx +97 -0
- package/components/tooltip/index.ts +1 -0
- package/components/tooltip/tooltip.tsx +82 -0
- package/dist/components/accordion/accordion.d.ts +50 -0
- package/dist/components/alert/alert.d.ts +31 -0
- package/dist/components/alert-dialog/alert-dialog.d.ts +35 -0
- package/dist/components/aspect-ratio/aspect-ratio.d.ts +12 -0
- package/dist/components/avatar/avatar.d.ts +11 -0
- package/dist/components/badge/badge.d.ts +12 -0
- package/dist/components/breadcrumb/breadcrumb.d.ts +23 -0
- package/dist/components/button/button.d.ts +15 -0
- package/dist/components/button-group/button-group.d.ts +16 -0
- package/dist/components/calendar/calendar.d.ts +15 -0
- package/dist/components/card/card.d.ts +15 -0
- package/dist/components/carousel/carousel.d.ts +24 -0
- package/dist/components/chart/chart.d.ts +20 -0
- package/dist/components/checkbox/checkbox.d.ts +9 -0
- package/dist/components/collapsible/collapsible.d.ts +13 -0
- package/dist/components/command/command.d.ts +18 -0
- package/dist/components/context-menu/context-menu.d.ts +18 -0
- package/dist/components/dialog/dialog.d.ts +25 -0
- package/dist/components/drawer/drawer.d.ts +18 -0
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +21 -0
- package/dist/components/empty/empty.d.ts +25 -0
- package/dist/components/field/field.d.ts +26 -0
- package/dist/components/form/form.d.ts +30 -1
- package/dist/components/hover-card/hover-card.d.ts +13 -0
- package/dist/components/input/input.d.ts +10 -0
- package/dist/components/input-group/input-group.d.ts +19 -0
- package/dist/components/input-otp/input-otp.d.ts +23 -0
- package/dist/components/item/item.d.ts +33 -1
- package/dist/components/kbd/kbd.d.ts +10 -0
- package/dist/components/label/label.d.ts +9 -0
- package/dist/components/menubar/menubar.d.ts +25 -0
- package/dist/components/navigation-menu/navigation-menu.d.ts +26 -0
- package/dist/components/pagination/pagination.d.ts +26 -0
- package/dist/components/popover/popover.d.ts +17 -0
- package/dist/components/progress/progress.d.ts +10 -0
- package/dist/components/radio-group/radio-group.d.ts +12 -0
- package/dist/components/resizable/resizable.d.ts +19 -0
- package/dist/components/scroll-area/scroll-area.d.ts +14 -0
- package/dist/components/select/select.d.ts +25 -0
- package/dist/components/separator/separator.d.ts +11 -0
- package/dist/components/sheet/sheet.d.ts +23 -0
- package/dist/components/sidebar/sidebar.d.ts +50 -0
- package/dist/components/skeleton/skeleton.d.ts +8 -0
- package/dist/components/slider/slider.d.ts +12 -0
- package/dist/components/sonner/sonner.d.ts +14 -0
- package/dist/components/spinner/spinner.d.ts +9 -0
- package/dist/components/switch/switch.d.ts +8 -0
- package/dist/components/table/table.d.ts +26 -0
- package/dist/components/tabs/tabs.d.ts +16 -6
- package/dist/components/textarea/textarea.d.ts +8 -0
- package/dist/components/toggle/toggle.d.ts +13 -0
- package/dist/components/toggle-group/toggle-group.d.ts +1 -0
- package/dist/components/tooltip/tooltip.d.ts +21 -0
- package/dist/design-system.css +1 -1
- package/dist/design-system.es.js +3481 -28494
- package/dist/design-system.umd.js +4 -257
- package/foundations/ThemeProvider.tsx +77 -0
- package/foundations/color.css +232 -0
- package/foundations/palette.css +249 -0
- package/foundations/spacing.css +8 -0
- package/foundations/typography.css +143 -0
- package/hooks/use-mobile.ts +19 -0
- package/index.css +173 -0
- package/index.ts +339 -0
- package/lib/utils.ts +6 -0
- package/package.json +40 -19
- package/README.md +0 -184
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
3
|
+
import { ChevronDownIcon } from "lucide-react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 접을 수 있는 콘텐츠 섹션을 제공하는 아코디언 컴포넌트입니다.
|
|
9
|
+
* Radix UI의 Accordion primitive를 기반으로 합니다.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Accordion type="single" collapsible>
|
|
14
|
+
* <AccordionItem value="item-1">
|
|
15
|
+
* <AccordionTrigger>제목</AccordionTrigger>
|
|
16
|
+
* <AccordionContent>내용</AccordionContent>
|
|
17
|
+
* </AccordionItem>
|
|
18
|
+
* </Accordion>
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @param props - Radix UI Accordion.Root props
|
|
22
|
+
* @param props.type - 'single'은 하나의 아이템만, 'multiple'은 여러 아이템을 동시에 열 수 있습니다
|
|
23
|
+
* @param props.collapsible - type이 'single'일 때, 열린 아이템을 다시 클릭하여 닫을 수 있게 합니다
|
|
24
|
+
* @param props.defaultValue - 초기에 열려있을 아이템의 value
|
|
25
|
+
* @param props.value - 제어 모드에서 열려있는 아이템의 value
|
|
26
|
+
* @param props.onValueChange - 열린 아이템이 변경될 때 호출되는 콜백
|
|
27
|
+
* @param props.disabled - 모든 아이템을 비활성화합니다
|
|
28
|
+
*/
|
|
29
|
+
function Accordion({
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Root>) {
|
|
32
|
+
return <AccordionPrimitive.Root data-slot="accordion" {...props} />
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 아코디언의 개별 아이템을 나타내는 컴포넌트입니다.
|
|
37
|
+
* 각 아이템은 고유한 value를 가져야 합니다.
|
|
38
|
+
*
|
|
39
|
+
* @param props - Radix UI Accordion.Item props
|
|
40
|
+
* @param props.value - 아이템의 고유 식별자 (필수)
|
|
41
|
+
* @param props.disabled - 이 아이템만 비활성화합니다
|
|
42
|
+
* @param props.className - 추가 CSS 클래스
|
|
43
|
+
*/
|
|
44
|
+
function AccordionItem({
|
|
45
|
+
className,
|
|
46
|
+
...props
|
|
47
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Item>) {
|
|
48
|
+
return (
|
|
49
|
+
<AccordionPrimitive.Item
|
|
50
|
+
data-slot="accordion-item"
|
|
51
|
+
className={cn("border-b last:border-b-0", className)}
|
|
52
|
+
{...props}
|
|
53
|
+
/>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 아코디언 아이템을 열고 닫는 트리거 버튼입니다.
|
|
59
|
+
* 클릭하면 해당 아이템의 콘텐츠가 펼쳐지거나 접힙니다.
|
|
60
|
+
* 우측에 화살표 아이콘이 표시되며, 열린 상태에서는 회전합니다.
|
|
61
|
+
*
|
|
62
|
+
* @param props - Radix UI Accordion.Trigger props
|
|
63
|
+
* @param props.children - 트리거에 표시될 텍스트 또는 요소
|
|
64
|
+
* @param props.className - 추가 CSS 클래스
|
|
65
|
+
* @param props.disabled - 트리거를 비활성화합니다
|
|
66
|
+
*/
|
|
67
|
+
function AccordionTrigger({
|
|
68
|
+
className,
|
|
69
|
+
children,
|
|
70
|
+
...props
|
|
71
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
|
|
72
|
+
return (
|
|
73
|
+
<AccordionPrimitive.Header className="flex">
|
|
74
|
+
<AccordionPrimitive.Trigger
|
|
75
|
+
data-slot="accordion-trigger"
|
|
76
|
+
className={cn(
|
|
77
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
|
|
78
|
+
className
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
{children}
|
|
83
|
+
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
|
|
84
|
+
</AccordionPrimitive.Trigger>
|
|
85
|
+
</AccordionPrimitive.Header>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 아코디언 아이템의 접히는 콘텐츠 영역입니다.
|
|
91
|
+
* 트리거를 클릭하면 애니메이션과 함께 펼쳐지거나 접힙니다.
|
|
92
|
+
*
|
|
93
|
+
* @param props - Radix UI Accordion.Content props
|
|
94
|
+
* @param props.children - 콘텐츠 영역에 표시될 내용
|
|
95
|
+
* @param props.className - 내부 콘텐츠 래퍼에 적용될 추가 CSS 클래스
|
|
96
|
+
* @param props.forceMount - 닫힌 상태에서도 DOM에 마운트 유지 (애니메이션용)
|
|
97
|
+
*/
|
|
98
|
+
function AccordionContent({
|
|
99
|
+
className,
|
|
100
|
+
children,
|
|
101
|
+
...props
|
|
102
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Content>) {
|
|
103
|
+
return (
|
|
104
|
+
<AccordionPrimitive.Content
|
|
105
|
+
data-slot="accordion-content"
|
|
106
|
+
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
|
|
107
|
+
{...props}
|
|
108
|
+
>
|
|
109
|
+
<div className={cn("pt-0 pb-4", className)}>{children}</div>
|
|
110
|
+
</AccordionPrimitive.Content>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./accordion";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Alert 컴포넌트의 스타일 변형을 정의합니다.
|
|
8
|
+
*/
|
|
9
|
+
const alertVariants = cva(
|
|
10
|
+
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: "bg-card text-card-foreground",
|
|
15
|
+
destructive:
|
|
16
|
+
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: "default",
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 사용자에게 중요한 정보를 전달하는 알림 컴포넌트입니다.
|
|
27
|
+
* 아이콘, 제목, 설명을 포함할 수 있습니다.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* <Alert variant="default">
|
|
32
|
+
* <InfoIcon />
|
|
33
|
+
* <AlertTitle>알림</AlertTitle>
|
|
34
|
+
* <AlertDescription>중요한 정보입니다.</AlertDescription>
|
|
35
|
+
* </Alert>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @param props.variant - 'default' | 'destructive' 스타일 변형
|
|
39
|
+
* @param props.className - 추가 CSS 클래스
|
|
40
|
+
*/
|
|
41
|
+
function Alert({
|
|
42
|
+
className,
|
|
43
|
+
variant,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
data-slot="alert"
|
|
49
|
+
role="alert"
|
|
50
|
+
className={cn(alertVariants({ variant }), className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Alert의 제목을 표시하는 컴포넌트입니다.
|
|
58
|
+
*
|
|
59
|
+
* @param props.className - 추가 CSS 클래스
|
|
60
|
+
* @param props.children - 제목 텍스트
|
|
61
|
+
*/
|
|
62
|
+
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
63
|
+
return (
|
|
64
|
+
<div
|
|
65
|
+
data-slot="alert-title"
|
|
66
|
+
className={cn(
|
|
67
|
+
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
|
|
68
|
+
className
|
|
69
|
+
)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Alert의 상세 설명을 표시하는 컴포넌트입니다.
|
|
77
|
+
*
|
|
78
|
+
* @param props.className - 추가 CSS 클래스
|
|
79
|
+
* @param props.children - 설명 내용
|
|
80
|
+
*/
|
|
81
|
+
function AlertDescription({
|
|
82
|
+
className,
|
|
83
|
+
...props
|
|
84
|
+
}: React.ComponentProps<"div">) {
|
|
85
|
+
return (
|
|
86
|
+
<div
|
|
87
|
+
data-slot="alert-description"
|
|
88
|
+
className={cn(
|
|
89
|
+
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
|
|
90
|
+
className
|
|
91
|
+
)}
|
|
92
|
+
{...props}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { Alert, AlertTitle, AlertDescription }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./alert";
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
import { buttonVariants } from "@/components/button";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 사용자의 확인이 필요한 중요한 작업에 대한 모달 다이얼로그입니다.
|
|
9
|
+
* 일반 Dialog와 달리 배경 클릭이나 Escape로 닫히지 않습니다.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <AlertDialog>
|
|
14
|
+
* <AlertDialogTrigger asChild>
|
|
15
|
+
* <Button>삭제</Button>
|
|
16
|
+
* </AlertDialogTrigger>
|
|
17
|
+
* <AlertDialogContent>
|
|
18
|
+
* <AlertDialogHeader>
|
|
19
|
+
* <AlertDialogTitle>정말 삭제하시겠습니까?</AlertDialogTitle>
|
|
20
|
+
* <AlertDialogDescription>이 작업은 취소할 수 없습니다.</AlertDialogDescription>
|
|
21
|
+
* </AlertDialogHeader>
|
|
22
|
+
* <AlertDialogFooter>
|
|
23
|
+
* <AlertDialogCancel>취소</AlertDialogCancel>
|
|
24
|
+
* <AlertDialogAction>삭제</AlertDialogAction>
|
|
25
|
+
* </AlertDialogFooter>
|
|
26
|
+
* </AlertDialogContent>
|
|
27
|
+
* </AlertDialog>
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function AlertDialog({
|
|
31
|
+
...props
|
|
32
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
|
|
33
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function AlertDialogTrigger({
|
|
37
|
+
...props
|
|
38
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
|
|
39
|
+
return (
|
|
40
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function AlertDialogPortal({
|
|
45
|
+
...props
|
|
46
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
|
|
47
|
+
return (
|
|
48
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function AlertDialogOverlay({
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
55
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
|
|
56
|
+
return (
|
|
57
|
+
<AlertDialogPrimitive.Overlay
|
|
58
|
+
data-slot="alert-dialog-overlay"
|
|
59
|
+
className={cn(
|
|
60
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
61
|
+
className
|
|
62
|
+
)}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* AlertDialog의 메인 콘텐츠 영역입니다.
|
|
70
|
+
* 자동으로 Overlay와 Portal을 포함합니다.
|
|
71
|
+
*/
|
|
72
|
+
function AlertDialogContent({
|
|
73
|
+
className,
|
|
74
|
+
...props
|
|
75
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
|
|
76
|
+
return (
|
|
77
|
+
<AlertDialogPortal>
|
|
78
|
+
<AlertDialogOverlay />
|
|
79
|
+
<AlertDialogPrimitive.Content
|
|
80
|
+
data-slot="alert-dialog-content"
|
|
81
|
+
className={cn(
|
|
82
|
+
"bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
83
|
+
className
|
|
84
|
+
)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
</AlertDialogPortal>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function AlertDialogHeader({
|
|
92
|
+
className,
|
|
93
|
+
...props
|
|
94
|
+
}: React.ComponentProps<"div">) {
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
data-slot="alert-dialog-header"
|
|
98
|
+
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function AlertDialogFooter({
|
|
105
|
+
className,
|
|
106
|
+
...props
|
|
107
|
+
}: React.ComponentProps<"div">) {
|
|
108
|
+
return (
|
|
109
|
+
<div
|
|
110
|
+
data-slot="alert-dialog-footer"
|
|
111
|
+
className={cn(
|
|
112
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
113
|
+
className
|
|
114
|
+
)}
|
|
115
|
+
{...props}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function AlertDialogTitle({
|
|
121
|
+
className,
|
|
122
|
+
...props
|
|
123
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
124
|
+
return (
|
|
125
|
+
<AlertDialogPrimitive.Title
|
|
126
|
+
data-slot="alert-dialog-title"
|
|
127
|
+
className={cn("text-lg font-semibold", className)}
|
|
128
|
+
{...props}
|
|
129
|
+
/>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function AlertDialogDescription({
|
|
134
|
+
className,
|
|
135
|
+
...props
|
|
136
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
137
|
+
return (
|
|
138
|
+
<AlertDialogPrimitive.Description
|
|
139
|
+
data-slot="alert-dialog-description"
|
|
140
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* AlertDialog의 확인 버튼입니다.
|
|
148
|
+
* 클릭 시 다이얼로그가 닫히고 지정된 액션이 실행됩니다.
|
|
149
|
+
*/
|
|
150
|
+
function AlertDialogAction({
|
|
151
|
+
className,
|
|
152
|
+
...props
|
|
153
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
|
|
154
|
+
return (
|
|
155
|
+
<AlertDialogPrimitive.Action
|
|
156
|
+
className={cn(buttonVariants(), className)}
|
|
157
|
+
{...props}
|
|
158
|
+
/>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* AlertDialog의 취소 버튼입니다.
|
|
164
|
+
* 클릭 시 다이얼로그가 닫히고 아무 작업도 수행하지 않습니다.
|
|
165
|
+
*/
|
|
166
|
+
function AlertDialogCancel({
|
|
167
|
+
className,
|
|
168
|
+
...props
|
|
169
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
|
|
170
|
+
return (
|
|
171
|
+
<AlertDialogPrimitive.Cancel
|
|
172
|
+
className={cn(buttonVariants({ variant: "outline" }), className)}
|
|
173
|
+
{...props}
|
|
174
|
+
/>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export {
|
|
179
|
+
AlertDialog,
|
|
180
|
+
AlertDialogPortal,
|
|
181
|
+
AlertDialogOverlay,
|
|
182
|
+
AlertDialogTrigger,
|
|
183
|
+
AlertDialogContent,
|
|
184
|
+
AlertDialogHeader,
|
|
185
|
+
AlertDialogFooter,
|
|
186
|
+
AlertDialogTitle,
|
|
187
|
+
AlertDialogDescription,
|
|
188
|
+
AlertDialogAction,
|
|
189
|
+
AlertDialogCancel,
|
|
190
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./alert-dialog";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 지정된 비율로 콘텐츠 영역을 유지하는 컴포넌트입니다.
|
|
7
|
+
*
|
|
8
|
+
* @param props.ratio - 가로:세로 비율 (예: 16/9, 4/3, 1)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <AspectRatio ratio={16/9}>
|
|
13
|
+
* <img src="image.jpg" className="object-cover" />
|
|
14
|
+
* </AspectRatio>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function AspectRatio({
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof AspectRatioPrimitive.Root>) {
|
|
20
|
+
return <AspectRatioPrimitive.Root data-slot="aspect-ratio" {...props} />
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { AspectRatio }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./aspect-ratio";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as AvatarPrimitive from "@radix-ui/react-avatar"
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 사용자의 프로필 이미지나 이니셜을 표시하는 아바타 컴포넌트입니다.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <Avatar>
|
|
12
|
+
* <AvatarImage src="/profile.jpg" alt="사용자" />
|
|
13
|
+
* <AvatarFallback>AB</AvatarFallback>
|
|
14
|
+
* </Avatar>
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function Avatar({
|
|
18
|
+
className,
|
|
19
|
+
...props
|
|
20
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
|
|
21
|
+
return (
|
|
22
|
+
<AvatarPrimitive.Root
|
|
23
|
+
data-slot="avatar"
|
|
24
|
+
className={cn(
|
|
25
|
+
"relative flex size-8 shrink-0 overflow-hidden rounded-full",
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
/>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function AvatarImage({
|
|
34
|
+
className,
|
|
35
|
+
...props
|
|
36
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
|
|
37
|
+
return (
|
|
38
|
+
<AvatarPrimitive.Image
|
|
39
|
+
data-slot="avatar-image"
|
|
40
|
+
className={cn("aspect-square size-full", className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function AvatarFallback({
|
|
47
|
+
className,
|
|
48
|
+
...props
|
|
49
|
+
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
|
|
50
|
+
return (
|
|
51
|
+
<AvatarPrimitive.Fallback
|
|
52
|
+
data-slot="avatar-fallback"
|
|
53
|
+
className={cn(
|
|
54
|
+
"bg-muted flex size-full items-center justify-center rounded-full",
|
|
55
|
+
className
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export { Avatar, AvatarImage, AvatarFallback }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./avatar";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
14
|
+
secondary:
|
|
15
|
+
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
16
|
+
destructive:
|
|
17
|
+
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
18
|
+
outline:
|
|
19
|
+
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "default",
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 상태, 카테고리, 카운트 등을 표시하는 뱃지 컴포넌트입니다.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <Badge variant="default">New</Badge>
|
|
34
|
+
* <Badge variant="destructive">Error</Badge>
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @param props.variant - 'default' | 'secondary' | 'destructive' | 'outline'
|
|
38
|
+
* @param props.asChild - true면 자식 요소로 렌더링 (링크 등)
|
|
39
|
+
*/
|
|
40
|
+
function Badge({
|
|
41
|
+
className,
|
|
42
|
+
variant,
|
|
43
|
+
asChild = false,
|
|
44
|
+
...props
|
|
45
|
+
}: React.ComponentProps<"span"> &
|
|
46
|
+
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
47
|
+
const Comp = asChild ? Slot : "span"
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Comp
|
|
51
|
+
data-slot="badge"
|
|
52
|
+
className={cn(badgeVariants({ variant }), className)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./badge";
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { ChevronRight, MoreHorizontal } from "lucide-react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 현재 페이지의 경로를 계층적으로 보여주는 브레드크럼 컴포넌트입니다.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* <Breadcrumb>
|
|
13
|
+
* <BreadcrumbList>
|
|
14
|
+
* <BreadcrumbItem>
|
|
15
|
+
* <BreadcrumbLink href="/">홈</BreadcrumbLink>
|
|
16
|
+
* </BreadcrumbItem>
|
|
17
|
+
* <BreadcrumbSeparator />
|
|
18
|
+
* <BreadcrumbItem>
|
|
19
|
+
* <BreadcrumbPage>현재 페이지</BreadcrumbPage>
|
|
20
|
+
* </BreadcrumbItem>
|
|
21
|
+
* </BreadcrumbList>
|
|
22
|
+
* </Breadcrumb>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
|
|
26
|
+
return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** 브레드크럼 아이템들을 감싸는 리스트입니다. */
|
|
30
|
+
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
|
|
31
|
+
return (
|
|
32
|
+
<ol
|
|
33
|
+
data-slot="breadcrumb-list"
|
|
34
|
+
className={cn(
|
|
35
|
+
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 브레드크럼 개별 아이템입니다. */
|
|
44
|
+
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
45
|
+
return (
|
|
46
|
+
<li
|
|
47
|
+
data-slot="breadcrumb-item"
|
|
48
|
+
className={cn("inline-flex items-center gap-1.5", className)}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 클릭 가능한 브레드크럼 링크입니다. */
|
|
55
|
+
function BreadcrumbLink({
|
|
56
|
+
asChild,
|
|
57
|
+
className,
|
|
58
|
+
...props
|
|
59
|
+
}: React.ComponentProps<"a"> & {
|
|
60
|
+
asChild?: boolean
|
|
61
|
+
}) {
|
|
62
|
+
const Comp = asChild ? Slot : "a"
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Comp
|
|
66
|
+
data-slot="breadcrumb-link"
|
|
67
|
+
className={cn("hover:text-foreground transition-colors", className)}
|
|
68
|
+
{...props}
|
|
69
|
+
/>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 현재 페이지를 나타내는 비활성 텍스트입니다. */
|
|
74
|
+
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
|
75
|
+
return (
|
|
76
|
+
<span
|
|
77
|
+
data-slot="breadcrumb-page"
|
|
78
|
+
role="link"
|
|
79
|
+
aria-disabled="true"
|
|
80
|
+
aria-current="page"
|
|
81
|
+
className={cn("text-foreground font-normal", className)}
|
|
82
|
+
{...props}
|
|
83
|
+
/>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 아이템 사이의 구분자입니다. */
|
|
88
|
+
function BreadcrumbSeparator({
|
|
89
|
+
children,
|
|
90
|
+
className,
|
|
91
|
+
...props
|
|
92
|
+
}: React.ComponentProps<"li">) {
|
|
93
|
+
return (
|
|
94
|
+
<li
|
|
95
|
+
data-slot="breadcrumb-separator"
|
|
96
|
+
role="presentation"
|
|
97
|
+
aria-hidden="true"
|
|
98
|
+
className={cn("[&>svg]:size-3.5", className)}
|
|
99
|
+
{...props}
|
|
100
|
+
>
|
|
101
|
+
{children ?? <ChevronRight />}
|
|
102
|
+
</li>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function BreadcrumbEllipsis({
|
|
107
|
+
className,
|
|
108
|
+
...props
|
|
109
|
+
}: React.ComponentProps<"span">) {
|
|
110
|
+
return (
|
|
111
|
+
<span
|
|
112
|
+
data-slot="breadcrumb-ellipsis"
|
|
113
|
+
role="presentation"
|
|
114
|
+
aria-hidden="true"
|
|
115
|
+
className={cn("flex size-9 items-center justify-center", className)}
|
|
116
|
+
{...props}
|
|
117
|
+
>
|
|
118
|
+
<MoreHorizontal className="size-4" />
|
|
119
|
+
<span className="sr-only">More</span>
|
|
120
|
+
</span>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export {
|
|
125
|
+
Breadcrumb,
|
|
126
|
+
BreadcrumbList,
|
|
127
|
+
BreadcrumbItem,
|
|
128
|
+
BreadcrumbLink,
|
|
129
|
+
BreadcrumbPage,
|
|
130
|
+
BreadcrumbSeparator,
|
|
131
|
+
BreadcrumbEllipsis,
|
|
132
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./breadcrumb";
|