@hua-labs/ui 1.0.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +363 -0
  3. package/dist/components/Accordion.d.ts +39 -0
  4. package/dist/components/Accordion.d.ts.map +1 -0
  5. package/dist/components/Accordion.js +84 -0
  6. package/dist/components/Alert.d.ts +17 -0
  7. package/dist/components/Alert.d.ts.map +1 -0
  8. package/dist/components/Alert.js +61 -0
  9. package/dist/components/Avatar.d.ts +13 -0
  10. package/dist/components/Avatar.d.ts.map +1 -0
  11. package/dist/components/Avatar.js +18 -0
  12. package/dist/components/Badge.d.ts +7 -0
  13. package/dist/components/Badge.d.ts.map +1 -0
  14. package/dist/components/Badge.js +15 -0
  15. package/dist/components/BottomSheet.d.ts +29 -0
  16. package/dist/components/BottomSheet.d.ts.map +1 -0
  17. package/dist/components/BottomSheet.js +96 -0
  18. package/dist/components/Breadcrumb.d.ts +27 -0
  19. package/dist/components/Breadcrumb.d.ts.map +1 -0
  20. package/dist/components/Breadcrumb.js +47 -0
  21. package/dist/components/Button.d.ts +9 -0
  22. package/dist/components/Button.d.ts.map +1 -0
  23. package/dist/components/Button.js +23 -0
  24. package/dist/components/Card.d.ts +21 -0
  25. package/dist/components/Card.d.ts.map +1 -0
  26. package/dist/components/Card.js +18 -0
  27. package/dist/components/ChatMessage.d.ts +35 -0
  28. package/dist/components/ChatMessage.d.ts.map +1 -0
  29. package/dist/components/ChatMessage.js +59 -0
  30. package/dist/components/Checkbox.d.ts +12 -0
  31. package/dist/components/Checkbox.d.ts.map +1 -0
  32. package/dist/components/Checkbox.js +30 -0
  33. package/dist/components/Command.d.ts +36 -0
  34. package/dist/components/Command.d.ts.map +1 -0
  35. package/dist/components/Command.js +119 -0
  36. package/dist/components/ConfirmModal.d.ts +26 -0
  37. package/dist/components/ConfirmModal.d.ts.map +1 -0
  38. package/dist/components/ConfirmModal.js +53 -0
  39. package/dist/components/Container.d.ts +10 -0
  40. package/dist/components/Container.d.ts.map +1 -0
  41. package/dist/components/Container.js +23 -0
  42. package/dist/components/ContextMenu.d.ts +26 -0
  43. package/dist/components/ContextMenu.d.ts.map +1 -0
  44. package/dist/components/ContextMenu.js +110 -0
  45. package/dist/components/Divider.d.ts +11 -0
  46. package/dist/components/Divider.d.ts.map +1 -0
  47. package/dist/components/Divider.js +39 -0
  48. package/dist/components/Drawer.d.ts +32 -0
  49. package/dist/components/Drawer.d.ts.map +1 -0
  50. package/dist/components/Drawer.js +79 -0
  51. package/dist/components/Dropdown.d.ts +28 -0
  52. package/dist/components/Dropdown.d.ts.map +1 -0
  53. package/dist/components/Dropdown.js +174 -0
  54. package/dist/components/EmotionAnalysis.d.ts +25 -0
  55. package/dist/components/EmotionAnalysis.d.ts.map +1 -0
  56. package/dist/components/EmotionAnalysis.js +40 -0
  57. package/dist/components/EmotionButton.d.ts +9 -0
  58. package/dist/components/EmotionButton.d.ts.map +1 -0
  59. package/dist/components/EmotionButton.js +16 -0
  60. package/dist/components/EmotionMeter.d.ts +10 -0
  61. package/dist/components/EmotionMeter.d.ts.map +1 -0
  62. package/dist/components/EmotionMeter.js +21 -0
  63. package/dist/components/EmotionSelector.d.ts +20 -0
  64. package/dist/components/EmotionSelector.d.ts.map +1 -0
  65. package/dist/components/EmotionSelector.js +46 -0
  66. package/dist/components/Grid.d.ts +11 -0
  67. package/dist/components/Grid.d.ts.map +1 -0
  68. package/dist/components/Grid.js +44 -0
  69. package/dist/components/Icon.d.ts +26 -0
  70. package/dist/components/Icon.d.ts.map +1 -0
  71. package/dist/components/Icon.js +48 -0
  72. package/dist/components/Input.d.ts +12 -0
  73. package/dist/components/Input.d.ts.map +1 -0
  74. package/dist/components/Input.js +25 -0
  75. package/dist/components/LanguageToggle.d.ts +17 -0
  76. package/dist/components/LanguageToggle.d.ts.map +1 -0
  77. package/dist/components/LanguageToggle.js +61 -0
  78. package/dist/components/LoadingSpinner.d.ts +10 -0
  79. package/dist/components/LoadingSpinner.d.ts.map +1 -0
  80. package/dist/components/LoadingSpinner.js +37 -0
  81. package/dist/components/Menu.d.ts +29 -0
  82. package/dist/components/Menu.d.ts.map +1 -0
  83. package/dist/components/Menu.js +122 -0
  84. package/dist/components/Modal.d.ts +15 -0
  85. package/dist/components/Modal.d.ts.map +1 -0
  86. package/dist/components/Modal.js +62 -0
  87. package/dist/components/PageTransition.d.ts +18 -0
  88. package/dist/components/PageTransition.d.ts.map +1 -0
  89. package/dist/components/PageTransition.js +39 -0
  90. package/dist/components/Pagination.d.ts +21 -0
  91. package/dist/components/Pagination.d.ts.map +1 -0
  92. package/dist/components/Pagination.js +87 -0
  93. package/dist/components/Popover.d.ts +16 -0
  94. package/dist/components/Popover.d.ts.map +1 -0
  95. package/dist/components/Popover.js +159 -0
  96. package/dist/components/Progress.d.ts +23 -0
  97. package/dist/components/Progress.d.ts.map +1 -0
  98. package/dist/components/Progress.js +51 -0
  99. package/dist/components/Radio.d.ts +12 -0
  100. package/dist/components/Radio.d.ts.map +1 -0
  101. package/dist/components/Radio.js +29 -0
  102. package/dist/components/ScrollArea.d.ts +16 -0
  103. package/dist/components/ScrollArea.d.ts.map +1 -0
  104. package/dist/components/ScrollArea.js +42 -0
  105. package/dist/components/ScrollIndicator.d.ts +17 -0
  106. package/dist/components/ScrollIndicator.d.ts.map +1 -0
  107. package/dist/components/ScrollIndicator.js +60 -0
  108. package/dist/components/ScrollProgress.d.ts +12 -0
  109. package/dist/components/ScrollProgress.d.ts.map +1 -0
  110. package/dist/components/ScrollProgress.js +39 -0
  111. package/dist/components/ScrollToTop.d.ts +15 -0
  112. package/dist/components/ScrollToTop.d.ts.map +1 -0
  113. package/dist/components/ScrollToTop.js +46 -0
  114. package/dist/components/Select.d.ts +17 -0
  115. package/dist/components/Select.d.ts.map +1 -0
  116. package/dist/components/Select.js +29 -0
  117. package/dist/components/Skeleton.d.ts +19 -0
  118. package/dist/components/Skeleton.d.ts.map +1 -0
  119. package/dist/components/Skeleton.js +71 -0
  120. package/dist/components/Stack.d.ts +11 -0
  121. package/dist/components/Stack.d.ts.map +1 -0
  122. package/dist/components/Stack.js +34 -0
  123. package/dist/components/Switch.d.ts +12 -0
  124. package/dist/components/Switch.d.ts.map +1 -0
  125. package/dist/components/Switch.js +29 -0
  126. package/dist/components/Tabs.d.ts +36 -0
  127. package/dist/components/Tabs.d.ts.map +1 -0
  128. package/dist/components/Tabs.js +117 -0
  129. package/dist/components/Textarea.d.ts +11 -0
  130. package/dist/components/Textarea.d.ts.map +1 -0
  131. package/dist/components/Textarea.js +31 -0
  132. package/dist/components/ThemeProvider.d.ts +19 -0
  133. package/dist/components/ThemeProvider.d.ts.map +1 -0
  134. package/dist/components/ThemeProvider.js +76 -0
  135. package/dist/components/ThemeToggle.d.ts +14 -0
  136. package/dist/components/ThemeToggle.d.ts.map +1 -0
  137. package/dist/components/ThemeToggle.js +49 -0
  138. package/dist/components/Toast.d.ts +32 -0
  139. package/dist/components/Toast.d.ts.map +1 -0
  140. package/dist/components/Toast.js +138 -0
  141. package/dist/components/Tooltip.d.ts +14 -0
  142. package/dist/components/Tooltip.d.ts.map +1 -0
  143. package/dist/components/Tooltip.js +102 -0
  144. package/dist/index.d.ts +50 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +49 -0
  147. package/dist/lib/icons.d.ts +43 -0
  148. package/dist/lib/icons.d.ts.map +1 -0
  149. package/dist/lib/icons.js +321 -0
  150. package/dist/lib/utils.d.ts +3 -0
  151. package/dist/lib/utils.d.ts.map +1 -0
  152. package/dist/lib/utils.js +5 -0
  153. package/package.json +67 -0
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ interface BottomSheetProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ children: React.ReactNode;
6
+ className?: string;
7
+ height?: "sm" | "md" | "lg" | "xl" | "full";
8
+ showBackdrop?: boolean;
9
+ closeOnBackdropClick?: boolean;
10
+ closeOnEscape?: boolean;
11
+ showDragHandle?: boolean;
12
+ snapPoints?: number[];
13
+ defaultSnap?: number;
14
+ }
15
+ declare const BottomSheet: React.ForwardRefExoticComponent<BottomSheetProps & React.RefAttributes<HTMLDivElement>>;
16
+ interface BottomSheetHeaderProps {
17
+ children: React.ReactNode;
18
+ className?: string;
19
+ showCloseButton?: boolean;
20
+ onClose?: () => void;
21
+ }
22
+ declare const BottomSheetHeader: React.ForwardRefExoticComponent<BottomSheetHeaderProps & React.RefAttributes<HTMLDivElement>>;
23
+ interface BottomSheetContentProps {
24
+ children: React.ReactNode;
25
+ className?: string;
26
+ }
27
+ declare const BottomSheetContent: React.ForwardRefExoticComponent<BottomSheetContentProps & React.RefAttributes<HTMLDivElement>>;
28
+ export { BottomSheet, BottomSheetHeader, BottomSheetContent };
29
+ //# sourceMappingURL=BottomSheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BottomSheet.d.ts","sourceRoot":"","sources":["../../src/components/BottomSheet.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,UAAU,gBAAgB;IACxB,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAA;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,QAAA,MAAM,WAAW,yFA4IhB,CAAA;AAGD,UAAU,sBAAsB;IAC9B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,QAAA,MAAM,iBAAiB,+FAoBtB,CAAA;AAGD,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,QAAA,MAAM,kBAAkB,gGAYvB,CAAA;AAGD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAA"}
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Icon } from "./Icon";
6
+ const BottomSheet = React.forwardRef(({ open, onOpenChange, children, className, height = "md", showBackdrop = true, closeOnBackdropClick = true, closeOnEscape = true, showDragHandle = true, snapPoints = [25, 50, 75, 100], defaultSnap = 50, ...props }, ref) => {
7
+ const [isVisible, setIsVisible] = React.useState(false);
8
+ const [isAnimating, setIsAnimating] = React.useState(false);
9
+ const [currentHeight, setCurrentHeight] = React.useState(defaultSnap);
10
+ const [isDragging, setIsDragging] = React.useState(false);
11
+ const [startY, setStartY] = React.useState(0);
12
+ const [currentY, setCurrentY] = React.useState(0);
13
+ const heightClasses = {
14
+ sm: "h-64",
15
+ md: "h-96",
16
+ lg: "h-[32rem]",
17
+ xl: "h-[40rem]",
18
+ full: "h-full"
19
+ };
20
+ React.useEffect(() => {
21
+ if (open) {
22
+ setIsVisible(true);
23
+ setIsAnimating(true);
24
+ const timer = setTimeout(() => setIsAnimating(false), 50);
25
+ return () => clearTimeout(timer);
26
+ }
27
+ else {
28
+ setIsAnimating(true);
29
+ const timer = setTimeout(() => {
30
+ setIsVisible(false);
31
+ setIsAnimating(false);
32
+ }, 300);
33
+ return () => clearTimeout(timer);
34
+ }
35
+ }, [open]);
36
+ React.useEffect(() => {
37
+ if (!closeOnEscape)
38
+ return;
39
+ const handleEscape = (e) => {
40
+ if (e.key === "Escape" && open) {
41
+ onOpenChange(false);
42
+ }
43
+ };
44
+ if (open) {
45
+ document.addEventListener("keydown", handleEscape);
46
+ document.body.style.overflow = "hidden";
47
+ }
48
+ return () => {
49
+ document.removeEventListener("keydown", handleEscape);
50
+ document.body.style.overflow = "";
51
+ };
52
+ }, [open, closeOnEscape, onOpenChange]);
53
+ const handleTouchStart = (e) => {
54
+ setIsDragging(true);
55
+ setStartY(e.touches[0].clientY);
56
+ setCurrentY(e.touches[0].clientY);
57
+ };
58
+ const handleTouchMove = (e) => {
59
+ if (!isDragging)
60
+ return;
61
+ setCurrentY(e.touches[0].clientY);
62
+ };
63
+ const handleTouchEnd = () => {
64
+ if (!isDragging)
65
+ return;
66
+ setIsDragging(false);
67
+ const deltaY = currentY - startY;
68
+ const threshold = 100;
69
+ if (deltaY > threshold) {
70
+ // 아래로 드래그 - 닫기
71
+ onOpenChange(false);
72
+ }
73
+ else if (deltaY < -threshold) {
74
+ // 위로 드래그 - 다음 스냅 포인트
75
+ const currentIndex = snapPoints.indexOf(currentHeight);
76
+ const nextIndex = Math.min(currentIndex + 1, snapPoints.length - 1);
77
+ setCurrentHeight(snapPoints[nextIndex]);
78
+ }
79
+ };
80
+ if (!isVisible)
81
+ return null;
82
+ return (_jsxs("div", { className: "fixed inset-0 z-50", children: [showBackdrop && (_jsx("div", { className: cn("absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300", isAnimating ? (open ? "opacity-100" : "opacity-0") : ""), onClick: closeOnBackdropClick ? () => onOpenChange(false) : undefined })), _jsxs("div", { ref: ref, className: cn("absolute bottom-0 left-0 right-0 bg-white/95 dark:!bg-gray-800/95 backdrop-blur-xl border-t border-gray-200/50 dark:!border-gray-600/50 shadow-2xl rounded-t-2xl transition-transform duration-300 ease-out", heightClasses[height], isAnimating ? (open ? "translate-y-0" : "translate-y-full") : "", className), style: {
83
+ height: `${currentHeight}%`,
84
+ transform: isDragging ? `translateY(${currentY - startY}px)` : undefined
85
+ }, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, ...props, children: [showDragHandle && (_jsx("div", { className: "flex justify-center pt-3 pb-2", children: _jsx("div", { className: "w-12 h-1.5 bg-gray-300 dark:bg-gray-600 rounded-full" }) })), children] })] }));
86
+ });
87
+ BottomSheet.displayName = "BottomSheet";
88
+ const BottomSheetHeader = React.forwardRef(({ children, className, showCloseButton = true, onClose, ...props }, ref) => {
89
+ return (_jsxs("div", { ref: ref, className: cn("flex items-center justify-between px-6 py-4", className), ...props, children: [_jsx("div", { className: "flex-1", children: children }), showCloseButton && (_jsx("button", { onClick: onClose, className: "p-2 rounded-lg hover:bg-gray-100/80 dark:hover:bg-gray-800/80 transition-colors", children: _jsx(Icon, { name: "x", size: 20 }) }))] }));
90
+ });
91
+ BottomSheetHeader.displayName = "BottomSheetHeader";
92
+ const BottomSheetContent = React.forwardRef(({ children, className, ...props }, ref) => {
93
+ return (_jsx("div", { ref: ref, className: cn("flex-1 px-6 pb-6 overflow-y-auto", className), ...props, children: children }));
94
+ });
95
+ BottomSheetContent.displayName = "BottomSheetContent";
96
+ export { BottomSheet, BottomSheetHeader, BottomSheetContent };
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+ interface BreadcrumbItem {
3
+ label: string;
4
+ href?: string;
5
+ icon?: string;
6
+ onClick?: () => void;
7
+ }
8
+ interface BreadcrumbProps {
9
+ items: BreadcrumbItem[];
10
+ separator?: React.ReactNode;
11
+ className?: string;
12
+ maxItems?: number;
13
+ showHomeIcon?: boolean;
14
+ homeLabel?: string;
15
+ homeHref?: string;
16
+ }
17
+ declare const Breadcrumb: React.ForwardRefExoticComponent<BreadcrumbProps & React.RefAttributes<HTMLDivElement>>;
18
+ interface BreadcrumbItemProps {
19
+ children: React.ReactNode;
20
+ className?: string;
21
+ href?: string;
22
+ onClick?: () => void;
23
+ isActive?: boolean;
24
+ }
25
+ declare const BreadcrumbItem: React.ForwardRefExoticComponent<BreadcrumbItemProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
26
+ export { Breadcrumb, BreadcrumbItem };
27
+ //# sourceMappingURL=Breadcrumb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Breadcrumb.d.ts","sourceRoot":"","sources":["../../src/components/Breadcrumb.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,UAAU,eAAe;IACvB,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,QAAA,MAAM,UAAU,wFA0Gf,CAAA;AAGD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,cAAc,mHAsBnB,CAAA;AAGD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,47 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Icon } from "./Icon";
6
+ const Breadcrumb = React.forwardRef(({ items, separator = _jsx(Icon, { name: "chevron-right", size: 16, className: "text-gray-400 dark:text-gray-500" }), className, maxItems, showHomeIcon = true, homeLabel = "홈", homeHref = "/", ...props }, ref) => {
7
+ const [isExpanded, setIsExpanded] = React.useState(false);
8
+ // 홈 아이템 추가
9
+ const allItems = [
10
+ {
11
+ label: homeLabel,
12
+ href: homeHref,
13
+ icon: showHomeIcon ? "home" : undefined
14
+ },
15
+ ...items
16
+ ];
17
+ // 최대 아이템 수 제한
18
+ const displayItems = maxItems && allItems.length > maxItems && !isExpanded
19
+ ? [
20
+ ...allItems.slice(0, 1),
21
+ { label: "...", href: undefined },
22
+ ...allItems.slice(-maxItems + 2)
23
+ ]
24
+ : allItems;
25
+ const renderItem = (item, index) => {
26
+ const isLast = index === displayItems.length - 1;
27
+ const isClickable = item.href || item.onClick;
28
+ const itemContent = (_jsxs("div", { className: "flex items-center gap-2", children: [item.icon && _jsx(Icon, { name: item.icon, size: 16 }), _jsx("span", { className: "truncate", children: item.label })] }));
29
+ if (isLast) {
30
+ return (_jsx("span", { className: "text-gray-900 dark:text-gray-400 font-medium truncate", children: itemContent }, index));
31
+ }
32
+ if (isClickable) {
33
+ return (_jsx("a", { href: item.href, onClick: item.onClick, className: "text-gray-600 dark:text-gray-500 hover:text-gray-900 dark:hover:text-gray-300 transition-colors truncate hover:underline", children: itemContent }, index));
34
+ }
35
+ return (_jsx("span", { className: "text-gray-500 dark:text-gray-500 truncate cursor-default", children: itemContent }, index));
36
+ };
37
+ return (_jsxs("nav", { ref: ref, className: cn("flex items-center gap-2 text-sm", className), "aria-label": "Breadcrumb", ...props, children: [displayItems.map((item, index) => (_jsxs(React.Fragment, { children: [renderItem(item, index), index < displayItems.length - 1 && (_jsx("span", { className: "flex-shrink-0", "aria-hidden": "true", children: separator }))] }, index))), maxItems && allItems.length > maxItems && (_jsx("button", { onClick: () => setIsExpanded(!isExpanded), className: "ml-2 text-blue-600 dark:text-blue-400 hover:underline text-xs", children: isExpanded ? "접기" : "펼치기" }))] }));
38
+ });
39
+ Breadcrumb.displayName = "Breadcrumb";
40
+ const BreadcrumbItem = React.forwardRef(({ children, className, href, onClick, isActive = false, ...props }, ref) => {
41
+ const Component = href ? "a" : "button";
42
+ return (_jsx(Component, { ref: ref, href: href, onClick: onClick, className: cn("flex items-center gap-2 text-sm transition-colors", isActive
43
+ ? "text-gray-900 dark:text-gray-400 font-medium"
44
+ : "text-gray-600 dark:text-gray-500 hover:text-gray-900 dark:hover:text-gray-300", className), ...props, children: children }));
45
+ });
46
+ BreadcrumbItem.displayName = "BreadcrumbItem";
47
+ export { Breadcrumb, BreadcrumbItem };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ variant?: "default" | "primary" | "secondary" | "outline" | "ghost" | "destructive";
4
+ size?: "sm" | "md" | "lg" | "icon";
5
+ asChild?: boolean;
6
+ }
7
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
8
+ export { Button };
9
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,WAAW,WAAY,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IAChF,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAA;IACnF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAA;IAClC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,QAAA,MAAM,MAAM,uFA+BX,CAAA;AAGD,OAAO,EAAE,MAAM,EAAE,CAAA"}
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Button = React.forwardRef(({ className, variant = "default", size = "md", asChild = false, ...props }, ref) => {
6
+ const variantClasses = {
7
+ default: "bg-gray-900 text-white hover:bg-gray-800 dark:bg-gray-50 dark:text-gray-900 dark:hover:bg-gray-100",
8
+ primary: "bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600",
9
+ secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700",
10
+ outline: "border border-gray-200 bg-white hover:bg-gray-50 dark:border-gray-800 dark:bg-gray-950 dark:hover:bg-gray-800",
11
+ ghost: "hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-gray-800 dark:hover:text-gray-100",
12
+ destructive: "bg-red-500 text-white hover:bg-red-600 dark:bg-red-600 dark:hover:bg-red-700"
13
+ };
14
+ const sizeClasses = {
15
+ sm: "h-10 px-4 py-3 text-sm", // 더 넉넉한 여백
16
+ md: "h-12 px-6 py-4 text-base", // 더 넉넉한 여백
17
+ lg: "h-14 px-8 py-5 text-lg", // 더 넉넉한 여백
18
+ icon: "h-12 w-12" // 더 넉넉한 아이콘 버튼
19
+ };
20
+ return (_jsx("button", { className: cn("inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", variantClasses[variant], sizeClasses[size], className), ref: ref, ...props }));
21
+ });
22
+ Button.displayName = "Button";
23
+ export { Button };
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ }
4
+ export interface CardHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ }
6
+ export interface CardTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
7
+ }
8
+ export interface CardDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
9
+ }
10
+ export interface CardContentProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ }
12
+ export interface CardFooterProps extends React.HTMLAttributes<HTMLDivElement> {
13
+ }
14
+ declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
15
+ declare const CardHeader: React.ForwardRefExoticComponent<CardHeaderProps & React.RefAttributes<HTMLDivElement>>;
16
+ declare const CardTitle: React.ForwardRefExoticComponent<CardTitleProps & React.RefAttributes<HTMLHeadingElement>>;
17
+ declare const CardDescription: React.ForwardRefExoticComponent<CardDescriptionProps & React.RefAttributes<HTMLParagraphElement>>;
18
+ declare const CardContent: React.ForwardRefExoticComponent<CardContentProps & React.RefAttributes<HTMLDivElement>>;
19
+ declare const CardFooter: React.ForwardRefExoticComponent<CardFooterProps & React.RefAttributes<HTMLDivElement>>;
20
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
21
+ //# sourceMappingURL=Card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAE1E,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEhF,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC;CAAG;AAEnF,MAAM,WAAW,oBAAqB,SAAQ,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC;CAAG;AAE3F,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEjF,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEhF,QAAA,MAAM,IAAI,kFAWT,CAAA;AAGD,QAAA,MAAM,UAAU,wFAQf,CAAA;AAGD,QAAA,MAAM,SAAS,2FAWd,CAAA;AAGD,QAAA,MAAM,eAAe,mGAQpB,CAAA;AAGD,QAAA,MAAM,WAAW,yFAIhB,CAAA;AAGD,QAAA,MAAM,UAAU,wFAQf,CAAA;AAGD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Card = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className), ...props })));
6
+ Card.displayName = "Card";
7
+ const CardHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex flex-col space-y-2 p-8", className), ...props })));
8
+ CardHeader.displayName = "CardHeader";
9
+ const CardTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx("h3", { ref: ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })));
10
+ CardTitle.displayName = "CardTitle";
11
+ const CardDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx("p", { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
12
+ CardDescription.displayName = "CardDescription";
13
+ const CardContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("p-8 pt-0", className), ...props }) // 더 넉넉한 여백
14
+ ));
15
+ CardContent.displayName = "CardContent";
16
+ const CardFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex items-center p-8 pt-0", className), ...props })));
17
+ CardFooter.displayName = "CardFooter";
18
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
@@ -0,0 +1,35 @@
1
+ import * as React from "react";
2
+ interface ChatMessageProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ message: {
4
+ id: string;
5
+ content: string;
6
+ role: "user" | "assistant" | "system";
7
+ timestamp: Date;
8
+ emotion?: string;
9
+ intensity?: number;
10
+ isTyping?: boolean;
11
+ };
12
+ user?: {
13
+ name?: string;
14
+ avatar?: string;
15
+ color?: string;
16
+ };
17
+ assistant?: {
18
+ name?: string;
19
+ avatar?: string;
20
+ color?: string;
21
+ };
22
+ showAvatar?: boolean;
23
+ showTimestamp?: boolean;
24
+ showEmotion?: boolean;
25
+ variant?: "default" | "compact" | "bubble";
26
+ theme?: {
27
+ userBubbleBg?: string;
28
+ userBubbleText?: string;
29
+ aiBubbleBg?: string;
30
+ aiBubbleText?: string;
31
+ };
32
+ }
33
+ declare const ChatMessage: React.ForwardRefExoticComponent<ChatMessageProps & React.RefAttributes<HTMLDivElement>>;
34
+ export { ChatMessage };
35
+ //# sourceMappingURL=ChatMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/components/ChatMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,UAAU,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;QACrC,SAAS,EAAE,IAAI,CAAA;QACf,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB,CAAA;IACD,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,KAAK,CAAC,EAAE;QACN,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED,QAAA,MAAM,WAAW,yFA2PhB,CAAA;AAID,OAAO,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Avatar, AvatarImage, AvatarFallback } from "./Avatar";
6
+ import { Badge } from "./Badge";
7
+ import { Card, CardContent } from "./Card";
8
+ const ChatMessage = React.forwardRef(({ className, message, user = { name: "사용자", color: "#3b82f6" }, assistant = { name: "AI", color: "#10b981" }, showAvatar = true, showTimestamp = true, showEmotion = true, variant = "default", theme = {
9
+ userBubbleBg: "#3b82f6",
10
+ userBubbleText: "#ffffff",
11
+ aiBubbleBg: "#f3f4f6",
12
+ aiBubbleText: "#1f2937"
13
+ }, ...props }, ref) => {
14
+ const isUser = message.role === "user";
15
+ const isAssistant = message.role === "assistant";
16
+ const isSystem = message.role === "system";
17
+ const getEmotionColor = (emotion) => {
18
+ if (!emotion)
19
+ return "bg-gray-100";
20
+ const emotionColors = {
21
+ joy: "bg-yellow-100 text-yellow-800",
22
+ sadness: "bg-blue-100 text-blue-800",
23
+ anger: "bg-red-100 text-red-800",
24
+ calm: "bg-green-100 text-green-800",
25
+ excitement: "bg-pink-100 text-pink-800",
26
+ worry: "bg-gray-100 text-gray-800",
27
+ gratitude: "bg-purple-100 text-purple-800",
28
+ loneliness: "bg-indigo-100 text-indigo-800"
29
+ };
30
+ return emotionColors[emotion] || "bg-gray-100 text-gray-800";
31
+ };
32
+ const formatTime = (date) => {
33
+ return date.toLocaleTimeString('ko-KR', {
34
+ hour: '2-digit',
35
+ minute: '2-digit'
36
+ });
37
+ };
38
+ if (variant === "bubble") {
39
+ return (_jsx("div", { ref: ref, className: cn("flex w-full", isUser ? "justify-end" : "justify-start", className), ...props, children: _jsxs("div", { className: cn("flex max-w-[80%] space-x-2", isUser ? "flex-row-reverse space-x-reverse" : "flex-row"), children: [showAvatar && (_jsxs(Avatar, { className: "w-8 h-8 flex-shrink-0", children: [_jsx(AvatarImage, { src: isUser ? user.avatar : assistant.avatar, alt: isUser ? user.name : assistant.name }), _jsx(AvatarFallback, { style: {
40
+ backgroundColor: isUser ? user.color : assistant.color
41
+ }, children: (isUser ? user.name : assistant.name)?.charAt(0) })] })), _jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: cn("px-4 py-2 rounded-2xl max-w-full break-words", isUser
42
+ ? "rounded-br-md"
43
+ : "rounded-bl-md"), style: {
44
+ backgroundColor: isUser ? theme.userBubbleBg : theme.aiBubbleBg,
45
+ color: isUser ? theme.userBubbleText : theme.aiBubbleText
46
+ }, children: message.isTyping ? (_jsxs("div", { className: "flex space-x-1", children: [_jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce" }), _jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce delay-100" }), _jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce delay-200" })] })) : (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })) }), _jsxs("div", { className: cn("flex items-center space-x-2 text-xs text-muted-foreground", isUser ? "justify-end" : "justify-start"), children: [showTimestamp && (_jsx("span", { children: formatTime(message.timestamp) })), showEmotion && message.emotion && (_jsx(Badge, { variant: "secondary", className: cn("text-xs", getEmotionColor(message.emotion)), children: message.emotion }))] })] })] }) }));
47
+ }
48
+ if (variant === "compact") {
49
+ return (_jsxs("div", { ref: ref, className: cn("flex items-start space-x-3 py-2", className), ...props, children: [showAvatar && (_jsxs(Avatar, { className: "w-6 h-6 flex-shrink-0", children: [_jsx(AvatarImage, { src: isUser ? user.avatar : assistant.avatar, alt: isUser ? user.name : assistant.name }), _jsx(AvatarFallback, { style: {
50
+ backgroundColor: isUser ? user.color : assistant.color
51
+ }, children: (isUser ? user.name : assistant.name)?.charAt(0) })] })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center space-x-2 mb-1", children: [_jsx("span", { className: "text-sm font-medium", children: isUser ? user.name : assistant.name }), showTimestamp && (_jsx("span", { className: "text-xs text-muted-foreground", children: formatTime(message.timestamp) })), showEmotion && message.emotion && (_jsx(Badge, { variant: "secondary", className: cn("text-xs", getEmotionColor(message.emotion)), children: message.emotion }))] }), _jsx("div", { className: "text-sm", children: message.isTyping ? (_jsxs("div", { className: "flex space-x-1", children: [_jsx("div", { className: "w-1.5 h-1.5 bg-muted-foreground rounded-full animate-bounce" }), _jsx("div", { className: "w-1.5 h-1.5 bg-muted-foreground rounded-full animate-bounce delay-100" }), _jsx("div", { className: "w-1.5 h-1.5 bg-muted-foreground rounded-full animate-bounce delay-200" })] })) : (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })) })] })] }));
52
+ }
53
+ // default variant
54
+ return (_jsxs("div", { ref: ref, className: cn("flex items-start space-x-3 py-4", className), ...props, children: [showAvatar && (_jsxs(Avatar, { className: "w-10 h-10 flex-shrink-0", children: [_jsx(AvatarImage, { src: isUser ? user.avatar : assistant.avatar, alt: isUser ? user.name : assistant.name }), _jsx(AvatarFallback, { style: {
55
+ backgroundColor: isUser ? user.color : assistant.color
56
+ }, children: (isUser ? user.name : assistant.name)?.charAt(0) })] })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center space-x-2 mb-2", children: [_jsx("span", { className: "font-medium", children: isUser ? user.name : assistant.name }), showTimestamp && (_jsx("span", { className: "text-sm text-muted-foreground", children: formatTime(message.timestamp) })), showEmotion && message.emotion && (_jsx(Badge, { variant: "secondary", className: cn("text-xs", getEmotionColor(message.emotion)), children: message.emotion }))] }), _jsx(Card, { className: cn("inline-block", isUser ? "bg-primary text-primary-foreground" : "bg-muted"), children: _jsx(CardContent, { className: "p-3", children: message.isTyping ? (_jsxs("div", { className: "flex space-x-1", children: [_jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce" }), _jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce delay-100" }), _jsx("div", { className: "w-2 h-2 bg-current rounded-full animate-bounce delay-200" })] })) : (_jsx("div", { className: "whitespace-pre-wrap", children: message.content })) }) })] })] }));
57
+ });
58
+ ChatMessage.displayName = "ChatMessage";
59
+ export { ChatMessage };
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
3
+ variant?: "default" | "outline" | "filled";
4
+ size?: "sm" | "md" | "lg";
5
+ error?: boolean;
6
+ success?: boolean;
7
+ label?: string;
8
+ description?: string;
9
+ }
10
+ declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
11
+ export { Checkbox };
12
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../src/components/Checkbox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC9F,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;IAC1C,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,QAAA,MAAM,QAAQ,wFAkFb,CAAA;AAGD,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Icon } from "./Icon";
6
+ const Checkbox = React.forwardRef(({ className, variant = "default", size = "md", error = false, success = false, label, description, ...props }, ref) => {
7
+ const sizeClasses = {
8
+ sm: "w-4 h-4",
9
+ md: "w-5 h-5",
10
+ lg: "w-6 h-6"
11
+ };
12
+ const iconSizes = {
13
+ sm: 12,
14
+ md: 14,
15
+ lg: 16
16
+ };
17
+ const variantClasses = {
18
+ default: "border-gray-300 bg-white text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:focus:ring-blue-400",
19
+ outline: "border-2 border-gray-200 bg-transparent text-blue-600 focus:ring-blue-500 dark:border-gray-700 dark:focus:ring-blue-400",
20
+ filled: "border-transparent bg-gray-50 text-blue-600 focus:bg-white focus:ring-blue-500 dark:bg-gray-700 dark:focus:bg-gray-800 dark:focus:ring-blue-400"
21
+ };
22
+ const stateClasses = error
23
+ ? "border-red-500 focus:ring-red-500 dark:border-red-400 dark:focus:ring-red-400"
24
+ : success
25
+ ? "border-green-500 focus:ring-green-500 dark:border-green-400 dark:focus:ring-green-400"
26
+ : "";
27
+ return (_jsxs("div", { className: "flex items-start space-x-3", children: [_jsxs("div", { className: "relative", children: [_jsx("input", { type: "checkbox", className: cn("peer sr-only", className), ref: ref, ...props }), _jsx("div", { className: cn("flex items-center justify-center rounded border transition-all duration-200 cursor-pointer", "peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-offset-2", "peer-disabled:cursor-not-allowed peer-disabled:opacity-50", sizeClasses[size], variantClasses[variant], stateClasses, "peer-checked:bg-blue-600 peer-checked:border-blue-600 dark:peer-checked:bg-blue-500 dark:peer-checked:border-blue-500"), children: _jsx(Icon, { name: "check", size: iconSizes[size], className: "text-white opacity-0 peer-checked:opacity-100 transition-opacity duration-200" }) })] }), (label || description) && (_jsxs("div", { className: "flex flex-col", children: [label && (_jsx("label", { className: "text-sm font-medium text-gray-900 dark:text-white cursor-pointer", children: label })), description && (_jsx("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: description }))] }))] }));
28
+ });
29
+ Checkbox.displayName = "Checkbox";
30
+ export { Checkbox };
@@ -0,0 +1,36 @@
1
+ import * as React from "react";
2
+ export interface CommandProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ children: React.ReactNode;
4
+ open?: boolean;
5
+ onOpenChange?: (open: boolean) => void;
6
+ placeholder?: string;
7
+ searchValue?: string;
8
+ onSearchChange?: (value: string) => void;
9
+ disabled?: boolean;
10
+ }
11
+ declare const Command: React.ForwardRefExoticComponent<CommandProps & React.RefAttributes<HTMLDivElement>>;
12
+ export interface CommandInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
13
+ }
14
+ declare const CommandInput: React.ForwardRefExoticComponent<CommandInputProps & React.RefAttributes<HTMLInputElement>>;
15
+ export interface CommandListProps extends React.HTMLAttributes<HTMLDivElement> {
16
+ }
17
+ declare const CommandList: React.ForwardRefExoticComponent<CommandListProps & React.RefAttributes<HTMLDivElement>>;
18
+ export interface CommandItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
19
+ icon?: React.ReactNode;
20
+ selected?: boolean;
21
+ onSelect?: () => void;
22
+ }
23
+ declare const CommandItem: React.ForwardRefExoticComponent<CommandItemProps & React.RefAttributes<HTMLButtonElement>>;
24
+ export interface CommandGroupProps extends React.HTMLAttributes<HTMLDivElement> {
25
+ heading?: React.ReactNode;
26
+ }
27
+ declare const CommandGroup: React.ForwardRefExoticComponent<CommandGroupProps & React.RefAttributes<HTMLDivElement>>;
28
+ export interface CommandSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {
29
+ }
30
+ declare const CommandSeparator: React.ForwardRefExoticComponent<CommandSeparatorProps & React.RefAttributes<HTMLDivElement>>;
31
+ export interface CommandEmptyProps extends React.HTMLAttributes<HTMLDivElement> {
32
+ }
33
+ declare const CommandEmpty: React.ForwardRefExoticComponent<CommandEmptyProps & React.RefAttributes<HTMLDivElement>>;
34
+ export declare const CommandDialog: React.ForwardRefExoticComponent<CommandProps & React.RefAttributes<HTMLDivElement>>;
35
+ export { Command, CommandInput, CommandList, CommandItem, CommandGroup, CommandSeparator, CommandEmpty };
36
+ //# sourceMappingURL=Command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Command.d.ts","sourceRoot":"","sources":["../../src/components/Command.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,YAAa,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACxE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,OAAO,qFAyJZ,CAAA;AAGD,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC;CAAG;AAEzF,QAAA,MAAM,YAAY,4FAajB,CAAA;AAGD,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEjF,QAAA,MAAM,WAAW,yFAQhB,CAAA;AAGD,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrF,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED,QAAA,MAAM,WAAW,4FAmChB,CAAA;AAGD,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC7E,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,QAAA,MAAM,YAAY,0FAajB,CAAA;AAGD,MAAM,WAAW,qBAAsB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAEtF,QAAA,MAAM,gBAAgB,8FAQrB,CAAA;AAGD,MAAM,WAAW,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;CAAG;AAElF,QAAA,MAAM,YAAY,0FAajB,CAAA;AAID,eAAO,MAAM,aAAa,qFAIzB,CAAA;AAGD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAA"}
@@ -0,0 +1,119 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ const Command = React.forwardRef(({ className, children, open: controlledOpen, onOpenChange, placeholder = "명령어를 검색하세요...", searchValue: controlledSearchValue, onSearchChange, disabled = false, ...props }, ref) => {
6
+ const [internalOpen, setInternalOpen] = React.useState(false);
7
+ const [internalSearchValue, setInternalSearchValue] = React.useState("");
8
+ const [selectedIndex, setSelectedIndex] = React.useState(0);
9
+ const commandRef = React.useRef(null);
10
+ const inputRef = React.useRef(null);
11
+ const listRef = React.useRef(null);
12
+ const isControlled = controlledOpen !== undefined;
13
+ const isOpen = isControlled ? controlledOpen : internalOpen;
14
+ const searchValue = controlledSearchValue !== undefined ? controlledSearchValue : internalSearchValue;
15
+ const handleOpenChange = (newOpen) => {
16
+ if (disabled)
17
+ return;
18
+ if (!isControlled) {
19
+ setInternalOpen(newOpen);
20
+ }
21
+ onOpenChange?.(newOpen);
22
+ };
23
+ const handleSearchChange = (value) => {
24
+ if (!isControlled) {
25
+ setInternalSearchValue(value);
26
+ }
27
+ onSearchChange?.(value);
28
+ setSelectedIndex(0);
29
+ };
30
+ const handleKeyDown = (event) => {
31
+ if (disabled)
32
+ return;
33
+ const items = listRef.current?.querySelectorAll('[data-command-item]');
34
+ const itemCount = items?.length || 0;
35
+ switch (event.key) {
36
+ case 'ArrowDown':
37
+ event.preventDefault();
38
+ setSelectedIndex((prev) => (prev + 1) % itemCount);
39
+ break;
40
+ case 'ArrowUp':
41
+ event.preventDefault();
42
+ setSelectedIndex((prev) => (prev - 1 + itemCount) % itemCount);
43
+ break;
44
+ case 'Enter':
45
+ event.preventDefault();
46
+ const selectedItem = items?.[selectedIndex];
47
+ selectedItem?.click();
48
+ break;
49
+ case 'Escape':
50
+ event.preventDefault();
51
+ handleOpenChange(false);
52
+ break;
53
+ }
54
+ };
55
+ React.useEffect(() => {
56
+ if (isOpen) {
57
+ inputRef.current?.focus();
58
+ setSelectedIndex(0);
59
+ }
60
+ }, [isOpen]);
61
+ React.useEffect(() => {
62
+ const handleKeyDown = (event) => {
63
+ if (event.key === 'k' && (event.metaKey || event.ctrlKey)) {
64
+ event.preventDefault();
65
+ handleOpenChange(!isOpen);
66
+ }
67
+ };
68
+ document.addEventListener('keydown', handleKeyDown);
69
+ return () => {
70
+ document.removeEventListener('keydown', handleKeyDown);
71
+ };
72
+ }, [isOpen]);
73
+ React.useEffect(() => {
74
+ const selectedItem = listRef.current?.querySelector(`[data-command-item]:nth-child(${selectedIndex + 1})`);
75
+ selectedItem?.scrollIntoView({ block: 'nearest' });
76
+ }, [selectedIndex]);
77
+ return (_jsx("div", { ref: ref, className: cn("relative", className), ...props, children: isOpen && (_jsx("div", { ref: commandRef, className: cn("fixed inset-0 z-50 bg-black/50 backdrop-blur-sm", // 50% 투명도
78
+ "flex items-start justify-center pt-16" // 64px 상단 여백
79
+ ), onClick: () => handleOpenChange(false), children: _jsxs("div", { className: cn("w-full max-w-2xl mx-4 bg-white dark:bg-gray-800 rounded-lg shadow-2xl", // 보더 대신 섀도우
80
+ "border-0 overflow-hidden" // 보더 제거
81
+ ), onClick: (e) => e.stopPropagation(), style: {
82
+ boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
83
+ }, children: [_jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700", children: [" ", _jsx("input", { ref: inputRef, type: "text", placeholder: placeholder, value: searchValue, onChange: (e) => handleSearchChange(e.target.value), onKeyDown: handleKeyDown, className: cn("w-full bg-transparent text-lg font-medium outline-none", // 18px 텍스트
84
+ "placeholder:text-gray-500 dark:placeholder:text-gray-400", "text-gray-900 dark:text-gray-100") })] }), _jsx("div", { ref: listRef, className: "max-h-96 overflow-y-auto py-2" // 384px 최대 높이, 8px 패딩
85
+ , children: React.Children.map(children, (child, index) => {
86
+ if (React.isValidElement(child)) {
87
+ return React.cloneElement(child, {
88
+ selected: index === selectedIndex,
89
+ onSelect: () => {
90
+ child.props?.onSelect?.();
91
+ handleOpenChange(false);
92
+ }
93
+ });
94
+ }
95
+ return child;
96
+ }) })] }) })) }));
97
+ });
98
+ Command.displayName = "Command";
99
+ const CommandInput = React.forwardRef(({ className, ...props }, ref) => (_jsx("input", { ref: ref, className: cn("flex h-10 w-full rounded-md bg-transparent px-3 py-2 text-sm outline-none", // 40px 높이, 12px, 8px 패딩
100
+ "placeholder:text-gray-500 dark:placeholder:text-gray-400", "disabled:cursor-not-allowed disabled:opacity-50", className), ...props })));
101
+ CommandInput.displayName = "CommandInput";
102
+ const CommandList = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("max-h-96 overflow-y-auto py-2", className), ...props })));
103
+ CommandList.displayName = "CommandList";
104
+ const CommandItem = React.forwardRef(({ className, icon, selected = false, onSelect, children, ...props }, ref) => {
105
+ return (_jsxs("button", { ref: ref, "data-command-item": true, className: cn("relative flex w-full items-center gap-3 rounded-sm px-4 py-3 text-sm", // 16px, 12px 패딩
106
+ "text-gray-700 dark:text-gray-300", "hover:bg-gray-100 dark:hover:bg-gray-700", "focus:bg-gray-100 dark:focus:bg-gray-700", "focus:outline-none", selected && "bg-gray-100 dark:bg-gray-700", "transition-colors", className), onClick: onSelect, ...props, children: [icon && (_jsx("div", { className: "flex-shrink-0 w-4 h-4 text-gray-500 dark:text-gray-400", children: icon })), _jsx("span", { className: "flex-1 text-left", children: children })] }));
107
+ });
108
+ CommandItem.displayName = "CommandItem";
109
+ const CommandGroup = React.forwardRef(({ className, heading, children, ...props }, ref) => (_jsxs("div", { ref: ref, className: cn("py-2", className), ...props, children: [" ", heading && (_jsxs("div", { className: "px-4 py-2 text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wide", children: [" ", heading] })), _jsxs("div", { className: "space-y-1", children: [" ", children] })] })));
110
+ CommandGroup.displayName = "CommandGroup";
111
+ const CommandSeparator = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("h-px bg-gray-200 dark:bg-gray-700 my-2", className), ...props })));
112
+ CommandSeparator.displayName = "CommandSeparator";
113
+ const CommandEmpty = React.forwardRef(({ className, children = "결과가 없습니다.", ...props }, ref) => (_jsx("div", { ref: ref, className: cn("py-8 text-center text-sm text-gray-500 dark:text-gray-400", // 32px 패딩
114
+ className), ...props, children: children })));
115
+ CommandEmpty.displayName = "CommandEmpty";
116
+ // 편의 컴포넌트들
117
+ export const CommandDialog = React.forwardRef(({ className, ...props }, ref) => (_jsx(Command, { ref: ref, className: className, ...props })));
118
+ CommandDialog.displayName = "CommandDialog";
119
+ export { Command, CommandInput, CommandList, CommandItem, CommandGroup, CommandSeparator, CommandEmpty };