@hua-labs/ui 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -67
- package/dist/{Switch-O4TpMKfQ.d.mts → Switch-Dzm5TLR3.d.mts} +1 -1
- package/dist/advanced/dashboard.d.ts.map +1 -1
- package/dist/advanced-dashboard.js +1 -1
- package/dist/advanced-dashboard.js.map +1 -1
- package/dist/advanced-dashboard.mjs +1 -1
- package/dist/advanced-motion.js +5 -5
- package/dist/advanced-motion.js.map +1 -1
- package/dist/advanced-motion.mjs +1 -1
- package/dist/advanced.js +7 -7
- package/dist/advanced.js.map +1 -1
- package/dist/advanced.mjs +1 -1
- package/dist/{chunk-ECLIPN34.mjs → chunk-COR6CDMA.mjs} +3 -3
- package/dist/{chunk-ECLIPN34.mjs.map → chunk-COR6CDMA.mjs.map} +1 -1
- package/dist/chunk-HN5LSP6L.mjs +3 -0
- package/dist/chunk-HN5LSP6L.mjs.map +1 -0
- package/dist/{chunk-T3GU5BJ3.mjs → chunk-LOYAJIWO.mjs} +2 -2
- package/dist/{chunk-T3GU5BJ3.mjs.map → chunk-LOYAJIWO.mjs.map} +1 -1
- package/dist/{chunk-TOANBEPN.mjs → chunk-NBJUE7NR.mjs} +2 -2
- package/dist/{chunk-TOANBEPN.mjs.map → chunk-NBJUE7NR.mjs.map} +1 -1
- package/dist/{chunk-PQ3DBOMK.mjs → chunk-QQCELXFD.mjs} +2 -2
- package/dist/{chunk-PQ3DBOMK.mjs.map → chunk-QQCELXFD.mjs.map} +1 -1
- package/dist/{chunk-OI66ZLUB.mjs → chunk-UWHCM3S6.mjs} +2 -2
- package/dist/{chunk-OI66ZLUB.mjs.map → chunk-UWHCM3S6.mjs.map} +1 -1
- package/dist/{chunk-MYFMKCYX.mjs → chunk-XV3Y7QVU.mjs} +2 -2
- package/dist/{chunk-MYFMKCYX.mjs.map → chunk-XV3Y7QVU.mjs.map} +1 -1
- package/dist/components/Avatar.d.ts +1 -1
- package/dist/components/Avatar.d.ts.map +1 -1
- package/dist/components/Badge.d.ts +1 -1
- package/dist/components/Badge.d.ts.map +1 -1
- package/dist/components/Button.variants.d.ts +1 -1
- package/dist/components/Button.variants.d.ts.map +1 -1
- package/dist/components/Card.d.ts +1 -1
- package/dist/components/Card.d.ts.map +1 -1
- package/dist/components/CodeBlock.d.ts +1 -1
- package/dist/components/Container.d.ts +1 -1
- package/dist/components/Container.d.ts.map +1 -1
- package/dist/components/Grid.d.ts +1 -1
- package/dist/components/Grid.d.ts.map +1 -1
- package/dist/components/Icon/Icon.d.ts.map +1 -1
- package/dist/components/Input.d.ts +1 -1
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/Label.d.ts +1 -1
- package/dist/components/Label.d.ts.map +1 -1
- package/dist/components/Link.d.ts +1 -1
- package/dist/components/Link.d.ts.map +1 -1
- package/dist/components/Panel.d.ts +1 -1
- package/dist/components/Panel.d.ts.map +1 -1
- package/dist/components/Progress.d.ts +2 -2
- package/dist/components/Progress.d.ts.map +1 -1
- package/dist/components/Select.d.ts +1 -1
- package/dist/components/Select.d.ts.map +1 -1
- package/dist/components/Skeleton.d.ts +1 -1
- package/dist/components/Skeleton.d.ts.map +1 -1
- package/dist/components/Stack.d.ts +1 -1
- package/dist/components/Stack.d.ts.map +1 -1
- package/dist/components/Textarea.d.ts +1 -1
- package/dist/components/Textarea.d.ts.map +1 -1
- package/dist/components/icons/essential.d.ts +68 -0
- package/dist/components/icons/essential.d.ts.map +1 -0
- package/dist/components/icons-bold/essential.d.ts +68 -0
- package/dist/components/icons-bold/essential.d.ts.map +1 -0
- package/dist/data.d.mts +1 -1
- package/dist/data.js.map +1 -1
- package/dist/data.mjs.map +1 -1
- package/dist/form.d.mts +1 -1
- package/dist/form.js +1 -1
- package/dist/form.js.map +1 -1
- package/dist/form.mjs +1 -1
- package/dist/iconsax-extended.d.ts +19 -0
- package/dist/iconsax-extended.d.ts.map +1 -0
- package/dist/iconsax-extended.js +3 -0
- package/dist/iconsax-extended.js.map +1 -0
- package/dist/iconsax-extended.mjs +4 -0
- package/dist/iconsax-extended.mjs.map +1 -0
- package/dist/iconsax.d.ts +10 -11
- package/dist/iconsax.d.ts.map +1 -1
- package/dist/iconsax.js +2 -2
- package/dist/iconsax.js.map +1 -1
- package/dist/iconsax.mjs +2 -2
- package/dist/iconsax.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/interactive.js +1 -1
- package/dist/interactive.js.map +1 -1
- package/dist/interactive.mjs +1 -1
- package/dist/lib/iconsax-loader.d.ts +15 -45
- package/dist/lib/iconsax-loader.d.ts.map +1 -1
- package/dist/navigation.js +2 -2
- package/dist/navigation.js.map +1 -1
- package/dist/navigation.mjs +1 -1
- package/dist/overlay.js +1 -1
- package/dist/overlay.js.map +1 -1
- package/dist/overlay.mjs +1 -1
- package/dist/sdui.js +3 -3
- package/dist/sdui.js.map +1 -1
- package/dist/sdui.mjs +1 -1
- package/package.json +18 -7
- package/src/components/icons/essential.ts +195 -0
- package/src/components/icons-bold/essential.ts +195 -0
- package/LICENSE +0 -21
- package/dist/chunk-AANHUMJ2.mjs +0 -3
- package/dist/chunk-AANHUMJ2.mjs.map +0 -1
- package/dist/components/icons/Frame2.d.ts +0 -4
- package/dist/components/icons/Frame2.d.ts.map +0 -1
- package/dist/components/icons/Group.d.ts +0 -4
- package/dist/components/icons/Group.d.ts.map +0 -1
- package/dist/components/icons/Group1.d.ts +0 -4
- package/dist/components/icons/Group1.d.ts.map +0 -1
- package/dist/components/icons/GroupCopy.d.ts +0 -4
- package/dist/components/icons/GroupCopy.d.ts.map +0 -1
- package/dist/iconsax.d.mts +0 -160
- package/src/components/icons/Frame2.tsx +0 -28
- package/src/components/icons/Group.tsx +0 -35
- package/src/components/icons/Group1.tsx +0 -21
- package/src/components/icons/GroupCopy.tsx +0 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Dropdown.tsx","../src/components/Drawer.tsx"],"names":["Dropdown","React","className","trigger","children","controlledOpen","onOpenChange","placement","align","offset","disabled","showArrow","props","ref","internalOpen","setInternalOpen","coords","setCoords","triggerRef","dropdownRef","isControlled","isOpen","handleOpenChange","newOpen","handleTriggerClick","updatePosition","triggerRect","dropdownRect","viewportWidth","viewportHeight","x","y","handleClickOutside","event","getPlacementClasses","getArrowClasses","jsxs","merge","jsx","DropdownItem","icon","variant","DropdownSeparator","DropdownLabel","DropdownMenu","DropdownGroup","Drawer","onClose","side","size","showBackdrop","backdropClassName","closeOnBackdropClick","closeOnEscape","closable","_isOpen","handleClose","isVisible","setIsVisible","isAnimating","setIsAnimating","timer","handleEscapeKey","e","sizeClasses","sideClasses","transformClasses","DrawerHeader","showCloseButton","Icon","DrawerContent","DrawerFooter"],"mappings":"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","file":"chunk-PQ3DBOMK.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\n\n/**\n * Dropdown 컴포넌트의 props / Dropdown component props\n * @typedef {Object} DropdownProps\n * @property {React.ReactNode} trigger - Dropdown을 열기 위한 트리거 요소 / Trigger element to open dropdown\n * @property {React.ReactNode} children - Dropdown 내용 / Dropdown content\n * @property {boolean} [open] - 제어 모드에서 열림/닫힘 상태 / Open/close state in controlled mode\n * @property {(open: boolean) => void} [onOpenChange] - 상태 변경 콜백 / State change callback\n * @property {\"top\" | \"bottom\" | \"left\" | \"right\"} [placement=\"bottom\"] - Dropdown 표시 위치 / Dropdown display position\n * @property {\"start\" | \"center\" | \"end\"} [align=\"start\"] - Dropdown 정렬 / Dropdown alignment\n * @property {number} [offset=8] - 트리거와 Dropdown 사이 간격 (px) / Spacing between trigger and dropdown (px)\n * @property {boolean} [disabled=false] - Dropdown 비활성화 여부 / Disable dropdown\n * @property {boolean} [showArrow=true] - 화살표 표시 여부 / Show arrow\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface DropdownProps extends React.HTMLAttributes<HTMLDivElement> {\n trigger: React.ReactNode\n children: React.ReactNode\n open?: boolean\n onOpenChange?: (open: boolean) => void\n placement?: \"top\" | \"bottom\" | \"left\" | \"right\"\n align?: \"start\" | \"center\" | \"end\"\n offset?: number\n disabled?: boolean\n showArrow?: boolean\n}\n\n/**\n * Dropdown 컴포넌트 / Dropdown component\n * \n * 트리거 요소를 클릭하면 표시되는 드롭다운 메뉴 컴포넌트입니다.\n * 외부 클릭 시 자동으로 닫히며, 뷰포트 경계를 자동으로 감지하여 위치를 조정합니다.\n * \n * Dropdown menu component that appears when the trigger element is clicked.\n * Automatically closes on outside click and adjusts position by detecting viewport boundaries.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Dropdown trigger={<Button>메뉴</Button>}>\n * <Menu>\n * <MenuItem>항목 1</MenuItem>\n * <MenuItem>항목 2</MenuItem>\n * </Menu>\n * </Dropdown>\n * \n * @example\n * // 제어 모드, 화살표 없음 / Controlled mode, no arrow\n * const [open, setOpen] = useState(false)\n * <Dropdown \n * open={open}\n * onOpenChange={setOpen}\n * trigger={<Button>제어 모드</Button>}\n * placement=\"top\"\n * showArrow={false}\n * >\n * <div className=\"p-4\">내용</div>\n * </Dropdown>\n * \n * @param {DropdownProps} props - Dropdown 컴포넌트의 props / Dropdown component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Dropdown 컴포넌트 / Dropdown component\n */\nconst Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(\n ({ \n className, \n trigger,\n children,\n open: controlledOpen,\n onOpenChange,\n placement = \"bottom\",\n align = \"start\",\n offset = 8,\n disabled = false,\n showArrow = true,\n ...props \n }, ref) => {\n const [internalOpen, setInternalOpen] = React.useState(false)\n const [coords, setCoords] = React.useState({ x: 0, y: 0 })\n const triggerRef = React.useRef<HTMLDivElement>(null)\n const dropdownRef = React.useRef<HTMLDivElement>(null)\n const isControlled = controlledOpen !== undefined\n const isOpen = isControlled ? controlledOpen : internalOpen\n\n const handleOpenChange = React.useCallback((newOpen: boolean) => {\n if (disabled) return\n\n if (!isControlled) {\n setInternalOpen(newOpen)\n }\n onOpenChange?.(newOpen)\n }, [disabled, isControlled, onOpenChange])\n\n const handleTriggerClick = () => {\n handleOpenChange(!isOpen)\n }\n\n const updatePosition = React.useCallback(() => {\n if (!triggerRef.current || !dropdownRef.current) return\n\n const triggerRect = triggerRef.current.getBoundingClientRect()\n const dropdownRect = dropdownRef.current.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n let x = 0\n let y = 0\n\n // 기본 위치 계산\n switch (placement) {\n case \"top\":\n x = triggerRect.left\n y = triggerRect.top - offset\n break\n case \"bottom\":\n x = triggerRect.left\n y = triggerRect.bottom + offset\n break\n case \"left\":\n x = triggerRect.left - offset\n y = triggerRect.top\n break\n case \"right\":\n x = triggerRect.right + offset\n y = triggerRect.top\n break\n }\n\n // 정렬 조정\n switch (align) {\n case \"center\":\n if (placement === \"top\" || placement === \"bottom\") {\n x = triggerRect.left + triggerRect.width / 2 - dropdownRect.width / 2\n } else {\n y = triggerRect.top + triggerRect.height / 2 - dropdownRect.height / 2\n }\n break\n case \"end\":\n if (placement === \"top\" || placement === \"bottom\") {\n x = triggerRect.right - dropdownRect.width\n } else {\n y = triggerRect.bottom - dropdownRect.height\n }\n break\n case \"start\":\n default:\n // 기본값은 이미 start 정렬\n break\n }\n\n // 뷰포트 경계 확인 및 조정\n if (x < 8) x = 8 // 8px 여백\n if (x + dropdownRect.width > viewportWidth - 8) {\n x = viewportWidth - dropdownRect.width - 8 // 8px 여백\n }\n if (y < 8) y = 8 // 8px 여백\n if (y + dropdownRect.height > viewportHeight - 8) {\n y = viewportHeight - dropdownRect.height - 8 // 8px 여백\n }\n\n setCoords({ x, y })\n }, [placement, align, offset])\n\n React.useEffect(() => {\n if (isOpen) {\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition)\n \n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition)\n }\n }\n }, [isOpen, updatePosition])\n\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n triggerRef.current &&\n dropdownRef.current &&\n !triggerRef.current.contains(event.target as Node) &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n handleOpenChange(false)\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }\n }, [isOpen, handleOpenChange])\n\n const getPlacementClasses = () => {\n switch (placement) {\n case \"top\":\n return \"bottom-full left-0 mb-2\" // 8px 간격\n case \"bottom\":\n return \"top-full left-0 mt-2\" // 8px 간격\n case \"left\":\n return \"right-full top-0 mr-2\" // 8px 간격\n case \"right\":\n return \"left-full top-0 ml-2\" // 8px 간격\n default:\n return \"top-full left-0 mt-2\"\n }\n }\n\n const getArrowClasses = () => {\n switch (placement) {\n case \"top\":\n return \"top-full left-4 -translate-x-1/2 border-t-gray-100 dark:border-t-gray-800\"\n case \"bottom\":\n return \"bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800\"\n case \"left\":\n return \"left-full top-4 -translate-y-1/2 border-l-gray-100 dark:border-l-gray-800\"\n case \"right\":\n return \"right-full top-4 -translate-y-1/2 border-r-gray-100 dark:border-r-gray-800\"\n default:\n return \"bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800\"\n }\n }\n\n return (\n <div ref={ref} className={merge(\"relative\", className)} {...props}>\n {/* 트리거 */}\n <div\n ref={triggerRef}\n onClick={handleTriggerClick}\n className=\"inline-block cursor-pointer\"\n >\n {trigger}\n </div>\n\n {/* 드롭다운 */}\n {/* CSS 변수 기반 배경색 (Tailwind v4 dark: + bg-* 충돌 우회) */}\n {isOpen && (\n <div\n ref={dropdownRef}\n className={merge(\n \"absolute z-50 bg-[var(--dropdown-bg)] rounded-lg shadow-xl backdrop-blur-sm\",\n \"min-w-[200px] py-2\",\n getPlacementClasses()\n )}\n style={{\n transform: `translate(${coords.x}px, ${coords.y}px)`,\n boxShadow: \"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)\"\n }}\n >\n {/* 화살표 */}\n {showArrow && (\n <div\n className={merge(\n \"absolute w-0 h-0 border-4 border-transparent\",\n getArrowClasses()\n )}\n />\n )}\n \n {/* 내용 */}\n <div className=\"relative z-10\">\n {children}\n </div>\n </div>\n )}\n </div>\n )\n }\n)\nDropdown.displayName = \"Dropdown\"\n\n// 드롭다운 아이템 컴포넌트들\nexport interface DropdownItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon?: React.ReactNode\n variant?: \"default\" | \"destructive\" | \"disabled\"\n}\n\nconst DropdownItem = React.forwardRef<HTMLButtonElement, DropdownItemProps>(\n ({ \n className, \n icon,\n variant = \"default\",\n children,\n disabled,\n ...props \n }, ref) => {\n const getVariantClasses = () => {\n switch (variant) {\n case \"destructive\":\n return \"text-destructive hover:bg-destructive/10\"\n case \"disabled\":\n return \"text-muted-foreground cursor-not-allowed\"\n default:\n return \"text-foreground hover:bg-muted\"\n }\n }\n\n return (\n <button\n ref={ref}\n className={merge(\n \"w-full flex items-center gap-3 px-4 py-3 text-sm font-medium transition-colors duration-200 ease-in-out focus-visible:outline-none focus-visible:bg-muted\", // 16px, 12px 패딩\n getVariantClasses(),\n className\n )}\n disabled={disabled || variant === \"disabled\"}\n {...props}\n >\n {icon && (\n <div className=\"flex-shrink-0 w-4 h-4\">\n {icon}\n </div>\n )}\n <span className=\"flex-1 text-left\">{children}</span>\n </button>\n )\n }\n)\nDropdownItem.displayName = \"DropdownItem\"\n\nexport interface DropdownSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownSeparator = React.forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"h-px bg-border my-2\", className)} // 8px 여백\n {...props}\n />\n )\n)\nDropdownSeparator.displayName = \"DropdownSeparator\"\n\nexport interface DropdownLabelProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownLabel = React.forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"px-4 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wide\", className)} // 16px, 8px 패딩\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownLabel.displayName = \"DropdownLabel\"\n\n// 편의 컴포넌트들\nconst DropdownMenu = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"py-1\", className)} // 4px 패딩\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownMenu.displayName = \"DropdownMenu\"\n\nconst DropdownGroup = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"space-y-1\", className)} // 4px 간격\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownGroup.displayName = \"DropdownGroup\"\n\nexport { Dropdown, DropdownItem, DropdownSeparator, DropdownLabel, DropdownMenu, DropdownGroup } ","\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Drawer 컴포넌트의 props / Drawer component props\n * @typedef {Object} DrawerProps\n * @property {boolean} open - Drawer 열림/닫힘 상태 / Drawer open/close state\n * @property {(open: boolean) => void} onOpenChange - 상태 변경 콜백 / State change callback\n * @property {React.ReactNode} children - Drawer 내용 / Drawer content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {\"left\" | \"right\" | \"top\" | \"bottom\"} [side=\"right\"] - Drawer 표시 위치 / Drawer display position\n * @property {\"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\"} [size=\"md\"] - Drawer 크기 / Drawer size\n * @property {boolean} [showBackdrop=true] - 배경 오버레이 표시 여부 / Show backdrop overlay\n * @property {string} [backdropClassName] - 배경 오버레이 추가 CSS 클래스 / Backdrop overlay additional CSS class\n * @property {boolean} [closeOnBackdropClick=true] - 배경 클릭 시 닫기 여부 / Close on backdrop click\n * @property {boolean} [closeOnEscape=true] - ESC 키로 닫기 여부 / Close on ESC key\n */\ninterface DrawerProps {\n /** Drawer 열림/닫힘 상태 / Drawer open/close state */\n isOpen?: boolean\n /** Drawer 닫기 콜백 / Drawer close callback */\n onClose?: () => void\n /** Drawer 내용 / Drawer content */\n children: React.ReactNode\n /** 추가 CSS 클래스 / Additional CSS class */\n className?: string\n /** Drawer 표시 위치 / Drawer display position */\n side?: \"left\" | \"right\" | \"top\" | \"bottom\"\n /** Drawer 크기 / Drawer size */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\"\n /** 배경 오버레이 표시 여부 / Show backdrop overlay */\n showBackdrop?: boolean\n /** 배경 오버레이 추가 CSS 클래스 / Backdrop overlay additional CSS class */\n backdropClassName?: string\n /** 배경 클릭 시 닫기 여부 / Close on backdrop click */\n closeOnBackdropClick?: boolean\n /** ESC 키로 닫기 여부 / Close on ESC key */\n closeOnEscape?: boolean\n /** 닫기 버튼 표시 여부 / Show close button */\n closable?: boolean\n}\n\n/**\n * Drawer 컴포넌트 / Drawer component\n * \n * 사이드에서 슬라이드되는 패널 컴포넌트입니다.\n * Modal과 유사하지만 특정 방향에서 슬라이드되는 애니메이션을 제공합니다.\n * ESC 키로 닫기, 배경 클릭으로 닫기 기능을 지원합니다.\n * \n * Panel component that slides from the side.\n * Similar to Modal but provides slide animation from a specific direction.\n * Supports closing with ESC key and backdrop click.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * const [open, setOpen] = useState(false)\n * \n * <Drawer open={open} onOpenChange={setOpen}>\n * <DrawerHeader>제목</DrawerHeader>\n * <DrawerContent>내용</DrawerContent>\n * <DrawerFooter>\n * <Button onClick={() => setOpen(false)}>닫기</Button>\n * </DrawerFooter>\n * </Drawer>\n * \n * @example\n * // 왼쪽에서 열기 / Open from left\n * <Drawer open={open} onOpenChange={setOpen} side=\"left\" size=\"lg\">\n * <DrawerContent>사이드바 내용</DrawerContent>\n * </Drawer>\n * \n * @param {DrawerProps} props - Drawer 컴포넌트의 props / Drawer component props\n * @param {React.Ref<HTMLDivElement>} ref - Drawer 컨테이너 ref / Drawer container ref\n * @returns {JSX.Element} Drawer 컴포넌트 / Drawer component\n * \n * @todo 접근성 개선: role=\"dialog\", aria-modal=\"true\" 추가 필요 / Accessibility: Add role=\"dialog\", aria-modal=\"true\"\n * @todo 접근성 개선: aria-labelledby, aria-describedby 연결 필요 / Accessibility: Connect aria-labelledby, aria-describedby\n */\nconst Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(\n ({\n isOpen,\n onClose,\n children,\n className,\n side = \"right\",\n size = \"md\",\n showBackdrop = true,\n backdropClassName,\n closeOnBackdropClick = true,\n closeOnEscape = true,\n closable = true,\n ...props\n }, ref) => {\n const _isOpen = isOpen ?? false\n const handleClose = () => {\n onClose?.()\n }\n\n const [isVisible, setIsVisible] = React.useState(false)\n const [isAnimating, setIsAnimating] = React.useState(false)\n\n React.useEffect(() => {\n if (_isOpen) {\n setIsVisible(true)\n setIsAnimating(true)\n // 애니메이션 시작을 위한 지연\n const timer = setTimeout(() => setIsAnimating(false), 50)\n return () => clearTimeout(timer)\n } else {\n setIsAnimating(true)\n const timer = setTimeout(() => {\n setIsVisible(false)\n setIsAnimating(false)\n }, 300) // 애니메이션 완료 후 숨김\n return () => clearTimeout(timer)\n }\n }, [_isOpen])\n\n React.useEffect(() => {\n if (!closeOnEscape) return\n\n const handleEscapeKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && _isOpen) {\n handleClose()\n }\n }\n\n if (_isOpen) {\n document.addEventListener(\"keydown\", handleEscapeKey)\n document.body.style.overflow = \"hidden\"\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscapeKey)\n document.body.style.overflow = \"\"\n }\n }, [_isOpen, closeOnEscape])\n\n if (!isVisible) return null\n\n const sizeClasses = {\n sm: side === \"left\" || side === \"right\" ? \"w-80\" : \"h-64\",\n md: side === \"left\" || side === \"right\" ? \"w-96\" : \"h-96\",\n lg: side === \"left\" || side === \"right\" ? \"w-[28rem]\" : \"h-[32rem]\",\n xl: side === \"left\" || side === \"right\" ? \"w-[32rem]\" : \"h-[40rem]\",\n full: side === \"left\" || side === \"right\" ? \"w-full\" : \"h-full\"\n }\n\n const sideClasses = {\n left: \"left-0 top-0 h-full\",\n right: \"right-0 top-0 h-full\",\n top: \"top-0 left-0 w-full\",\n bottom: \"bottom-0 left-0 w-full\"\n }\n\n // Transform: _isOpen=true -> visible position, _isOpen=false -> hidden position\n const transformClasses = {\n left: _isOpen ? \"translate-x-0\" : \"-translate-x-full\",\n right: _isOpen ? \"translate-x-0\" : \"translate-x-full\",\n top: _isOpen ? \"translate-y-0\" : \"-translate-y-full\",\n bottom: _isOpen ? \"translate-y-0\" : \"translate-y-full\"\n }\n\n return (\n <div className=\"fixed inset-0 z-50\">\n {/* Backdrop */}\n {showBackdrop && (\n <div\n className={merge(\n \"absolute inset-0 bg-black/60 backdrop-blur-md transition-opacity duration-300\",\n isAnimating ? (_isOpen ? \"opacity-100\" : \"opacity-0\") : \"\",\n backdropClassName\n )}\n onClick={closeOnBackdropClick ? handleClose : undefined}\n />\n )}\n\n {/* Drawer Content */}\n <div\n ref={ref}\n className={merge(\n \"absolute bg-background/95 backdrop-blur-xl border border-border/50 shadow-2xl transition-transform duration-300 ease-out\",\n sizeClasses[size],\n sideClasses[side],\n transformClasses[side],\n className\n )}\n {...props}\n >\n {children}\n </div>\n </div>\n )\n }\n)\nDrawer.displayName = \"Drawer\"\n\n/**\n * DrawerHeader 컴포넌트의 props / DrawerHeader component props\n * @typedef {Object} DrawerHeaderProps\n * @property {React.ReactNode} children - 헤더 내용 / Header content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {boolean} [showCloseButton=true] - 닫기 버튼 표시 여부 / Show close button\n * @property {() => void} [onClose] - 닫기 버튼 클릭 콜백 / Close button click callback\n */\ninterface DrawerHeaderProps {\n children: React.ReactNode\n className?: string\n showCloseButton?: boolean\n onClose?: () => void\n}\n\n/**\n * DrawerHeader 컴포넌트 / DrawerHeader component\n * Drawer의 헤더 영역을 표시합니다.\n * Displays the header area of a Drawer.\n * \n * @component\n * @param {DrawerHeaderProps} props - DrawerHeader 컴포넌트의 props / DrawerHeader component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerHeader 컴포넌트 / DrawerHeader component\n */\nconst DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ children, className, showCloseButton = true, onClose, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex items-center justify-between p-6 border-b border-border/50\", className)}\n {...props}\n >\n <div className=\"flex-1\">{children}</div>\n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"p-2 rounded-lg hover:bg-muted transition-colors\"\n >\n <Icon name=\"close\" size={20} />\n </button>\n )}\n </div>\n )\n }\n)\nDrawerHeader.displayName = \"DrawerHeader\"\n\n/**\n * DrawerContent 컴포넌트의 props / DrawerContent component props\n * @typedef {Object} DrawerContentProps\n * @property {React.ReactNode} children - 콘텐츠 / Content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n */\ninterface DrawerContentProps {\n children: React.ReactNode\n className?: string\n}\n\n/**\n * DrawerContent 컴포넌트 / DrawerContent component\n * Drawer의 메인 콘텐츠 영역을 표시합니다.\n * Displays the main content area of a Drawer.\n * \n * @component\n * @param {DrawerContentProps} props - DrawerContent 컴포넌트의 props / DrawerContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerContent 컴포넌트 / DrawerContent component\n */\nconst DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(\n ({ children, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex-1 p-6 overflow-y-auto\", className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nDrawerContent.displayName = \"DrawerContent\"\n\n/**\n * DrawerFooter 컴포넌트의 props / DrawerFooter component props\n * @typedef {Object} DrawerFooterProps\n * @property {React.ReactNode} children - 푸터 내용 / Footer content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n */\ninterface DrawerFooterProps {\n children: React.ReactNode\n className?: string\n}\n\n/**\n * DrawerFooter 컴포넌트 / DrawerFooter component\n * Drawer의 푸터 영역을 표시합니다. 주로 액션 버튼을 배치합니다.\n * Displays the footer area of a Drawer. Typically used for action buttons.\n * \n * @component\n * @param {DrawerFooterProps} props - DrawerFooter 컴포넌트의 props / DrawerFooter component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerFooter 컴포넌트 / DrawerFooter component\n */\nconst DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ children, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex items-center justify-end gap-3 p-6 border-t border-border/50\", className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nDrawerFooter.displayName = \"DrawerFooter\"\n\nexport { Drawer, DrawerHeader, DrawerContent, DrawerFooter } "]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Dropdown.tsx","../src/components/Drawer.tsx"],"names":["Dropdown","React","className","trigger","children","controlledOpen","onOpenChange","placement","align","offset","disabled","showArrow","props","ref","internalOpen","setInternalOpen","coords","setCoords","triggerRef","dropdownRef","isControlled","isOpen","handleOpenChange","newOpen","handleTriggerClick","updatePosition","triggerRect","dropdownRect","viewportWidth","viewportHeight","x","y","handleClickOutside","event","getPlacementClasses","getArrowClasses","jsxs","merge","jsx","DropdownItem","icon","variant","DropdownSeparator","DropdownLabel","DropdownMenu","DropdownGroup","Drawer","onClose","side","size","showBackdrop","backdropClassName","closeOnBackdropClick","closeOnEscape","closable","_isOpen","handleClose","isVisible","setIsVisible","isAnimating","setIsAnimating","timer","handleEscapeKey","e","sizeClasses","sideClasses","transformClasses","DrawerHeader","showCloseButton","Icon","DrawerContent","DrawerFooter"],"mappings":"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","file":"chunk-QQCELXFD.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\n\n/**\n * Dropdown 컴포넌트의 props / Dropdown component props\n * @typedef {Object} DropdownProps\n * @property {React.ReactNode} trigger - Dropdown을 열기 위한 트리거 요소 / Trigger element to open dropdown\n * @property {React.ReactNode} children - Dropdown 내용 / Dropdown content\n * @property {boolean} [open] - 제어 모드에서 열림/닫힘 상태 / Open/close state in controlled mode\n * @property {(open: boolean) => void} [onOpenChange] - 상태 변경 콜백 / State change callback\n * @property {\"top\" | \"bottom\" | \"left\" | \"right\"} [placement=\"bottom\"] - Dropdown 표시 위치 / Dropdown display position\n * @property {\"start\" | \"center\" | \"end\"} [align=\"start\"] - Dropdown 정렬 / Dropdown alignment\n * @property {number} [offset=8] - 트리거와 Dropdown 사이 간격 (px) / Spacing between trigger and dropdown (px)\n * @property {boolean} [disabled=false] - Dropdown 비활성화 여부 / Disable dropdown\n * @property {boolean} [showArrow=true] - 화살표 표시 여부 / Show arrow\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface DropdownProps extends React.HTMLAttributes<HTMLDivElement> {\n trigger: React.ReactNode\n children: React.ReactNode\n open?: boolean\n onOpenChange?: (open: boolean) => void\n placement?: \"top\" | \"bottom\" | \"left\" | \"right\"\n align?: \"start\" | \"center\" | \"end\"\n offset?: number\n disabled?: boolean\n showArrow?: boolean\n}\n\n/**\n * Dropdown 컴포넌트 / Dropdown component\n * \n * 트리거 요소를 클릭하면 표시되는 드롭다운 메뉴 컴포넌트입니다.\n * 외부 클릭 시 자동으로 닫히며, 뷰포트 경계를 자동으로 감지하여 위치를 조정합니다.\n * \n * Dropdown menu component that appears when the trigger element is clicked.\n * Automatically closes on outside click and adjusts position by detecting viewport boundaries.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Dropdown trigger={<Button>메뉴</Button>}>\n * <Menu>\n * <MenuItem>항목 1</MenuItem>\n * <MenuItem>항목 2</MenuItem>\n * </Menu>\n * </Dropdown>\n * \n * @example\n * // 제어 모드, 화살표 없음 / Controlled mode, no arrow\n * const [open, setOpen] = useState(false)\n * <Dropdown \n * open={open}\n * onOpenChange={setOpen}\n * trigger={<Button>제어 모드</Button>}\n * placement=\"top\"\n * showArrow={false}\n * >\n * <div className=\"p-4\">내용</div>\n * </Dropdown>\n * \n * @param {DropdownProps} props - Dropdown 컴포넌트의 props / Dropdown component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Dropdown 컴포넌트 / Dropdown component\n */\nconst Dropdown = React.forwardRef<HTMLDivElement, DropdownProps>(\n ({ \n className, \n trigger,\n children,\n open: controlledOpen,\n onOpenChange,\n placement = \"bottom\",\n align = \"start\",\n offset = 8,\n disabled = false,\n showArrow = true,\n ...props \n }, ref) => {\n const [internalOpen, setInternalOpen] = React.useState(false)\n const [coords, setCoords] = React.useState({ x: 0, y: 0 })\n const triggerRef = React.useRef<HTMLDivElement>(null)\n const dropdownRef = React.useRef<HTMLDivElement>(null)\n const isControlled = controlledOpen !== undefined\n const isOpen = isControlled ? controlledOpen : internalOpen\n\n const handleOpenChange = React.useCallback((newOpen: boolean) => {\n if (disabled) return\n\n if (!isControlled) {\n setInternalOpen(newOpen)\n }\n onOpenChange?.(newOpen)\n }, [disabled, isControlled, onOpenChange])\n\n const handleTriggerClick = () => {\n handleOpenChange(!isOpen)\n }\n\n const updatePosition = React.useCallback(() => {\n if (!triggerRef.current || !dropdownRef.current) return\n\n const triggerRect = triggerRef.current.getBoundingClientRect()\n const dropdownRect = dropdownRef.current.getBoundingClientRect()\n const viewportWidth = window.innerWidth\n const viewportHeight = window.innerHeight\n\n let x = 0\n let y = 0\n\n // 기본 위치 계산\n switch (placement) {\n case \"top\":\n x = triggerRect.left\n y = triggerRect.top - offset\n break\n case \"bottom\":\n x = triggerRect.left\n y = triggerRect.bottom + offset\n break\n case \"left\":\n x = triggerRect.left - offset\n y = triggerRect.top\n break\n case \"right\":\n x = triggerRect.right + offset\n y = triggerRect.top\n break\n }\n\n // 정렬 조정\n switch (align) {\n case \"center\":\n if (placement === \"top\" || placement === \"bottom\") {\n x = triggerRect.left + triggerRect.width / 2 - dropdownRect.width / 2\n } else {\n y = triggerRect.top + triggerRect.height / 2 - dropdownRect.height / 2\n }\n break\n case \"end\":\n if (placement === \"top\" || placement === \"bottom\") {\n x = triggerRect.right - dropdownRect.width\n } else {\n y = triggerRect.bottom - dropdownRect.height\n }\n break\n case \"start\":\n default:\n // 기본값은 이미 start 정렬\n break\n }\n\n // 뷰포트 경계 확인 및 조정\n if (x < 8) x = 8 // 8px 여백\n if (x + dropdownRect.width > viewportWidth - 8) {\n x = viewportWidth - dropdownRect.width - 8 // 8px 여백\n }\n if (y < 8) y = 8 // 8px 여백\n if (y + dropdownRect.height > viewportHeight - 8) {\n y = viewportHeight - dropdownRect.height - 8 // 8px 여백\n }\n\n setCoords({ x, y })\n }, [placement, align, offset])\n\n React.useEffect(() => {\n if (isOpen) {\n updatePosition()\n window.addEventListener('resize', updatePosition)\n window.addEventListener('scroll', updatePosition)\n \n return () => {\n window.removeEventListener('resize', updatePosition)\n window.removeEventListener('scroll', updatePosition)\n }\n }\n }, [isOpen, updatePosition])\n\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n triggerRef.current &&\n dropdownRef.current &&\n !triggerRef.current.contains(event.target as Node) &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n handleOpenChange(false)\n }\n }\n\n if (isOpen) {\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }\n }, [isOpen, handleOpenChange])\n\n const getPlacementClasses = () => {\n switch (placement) {\n case \"top\":\n return \"bottom-full left-0 mb-2\" // 8px 간격\n case \"bottom\":\n return \"top-full left-0 mt-2\" // 8px 간격\n case \"left\":\n return \"right-full top-0 mr-2\" // 8px 간격\n case \"right\":\n return \"left-full top-0 ml-2\" // 8px 간격\n default:\n return \"top-full left-0 mt-2\"\n }\n }\n\n const getArrowClasses = () => {\n switch (placement) {\n case \"top\":\n return \"top-full left-4 -translate-x-1/2 border-t-gray-100 dark:border-t-gray-800\"\n case \"bottom\":\n return \"bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800\"\n case \"left\":\n return \"left-full top-4 -translate-y-1/2 border-l-gray-100 dark:border-l-gray-800\"\n case \"right\":\n return \"right-full top-4 -translate-y-1/2 border-r-gray-100 dark:border-r-gray-800\"\n default:\n return \"bottom-full left-4 -translate-x-1/2 border-b-gray-100 dark:border-b-gray-800\"\n }\n }\n\n return (\n <div ref={ref} className={merge(\"relative\", className)} {...props}>\n {/* 트리거 */}\n <div\n ref={triggerRef}\n onClick={handleTriggerClick}\n className=\"inline-block cursor-pointer\"\n >\n {trigger}\n </div>\n\n {/* 드롭다운 */}\n {/* CSS 변수 기반 배경색 (Tailwind v4 dark: + bg-* 충돌 우회) */}\n {isOpen && (\n <div\n ref={dropdownRef}\n className={merge(\n \"absolute z-50 bg-[var(--dropdown-bg)] rounded-lg shadow-xl backdrop-blur-sm\",\n \"min-w-[200px] py-2\",\n getPlacementClasses()\n )}\n style={{\n transform: `translate(${coords.x}px, ${coords.y}px)`,\n boxShadow: \"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)\"\n }}\n >\n {/* 화살표 */}\n {showArrow && (\n <div\n className={merge(\n \"absolute w-0 h-0 border-4 border-transparent\",\n getArrowClasses()\n )}\n />\n )}\n \n {/* 내용 */}\n <div className=\"relative z-10\">\n {children}\n </div>\n </div>\n )}\n </div>\n )\n }\n)\nDropdown.displayName = \"Dropdown\"\n\n// 드롭다운 아이템 컴포넌트들\nexport interface DropdownItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon?: React.ReactNode\n variant?: \"default\" | \"destructive\" | \"disabled\"\n}\n\nconst DropdownItem = React.forwardRef<HTMLButtonElement, DropdownItemProps>(\n ({ \n className, \n icon,\n variant = \"default\",\n children,\n disabled,\n ...props \n }, ref) => {\n const getVariantClasses = () => {\n switch (variant) {\n case \"destructive\":\n return \"text-destructive hover:bg-destructive/10\"\n case \"disabled\":\n return \"text-muted-foreground cursor-not-allowed\"\n default:\n return \"text-foreground hover:bg-muted\"\n }\n }\n\n return (\n <button\n ref={ref}\n className={merge(\n \"w-full flex items-center gap-3 px-4 py-3 text-sm font-medium transition-colors duration-200 ease-in-out focus-visible:outline-none focus-visible:bg-muted\", // 16px, 12px 패딩\n getVariantClasses(),\n className\n )}\n disabled={disabled || variant === \"disabled\"}\n {...props}\n >\n {icon && (\n <div className=\"flex-shrink-0 w-4 h-4\">\n {icon}\n </div>\n )}\n <span className=\"flex-1 text-left\">{children}</span>\n </button>\n )\n }\n)\nDropdownItem.displayName = \"DropdownItem\"\n\nexport interface DropdownSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownSeparator = React.forwardRef<HTMLDivElement, DropdownSeparatorProps>(\n ({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"h-px bg-border my-2\", className)} // 8px 여백\n {...props}\n />\n )\n)\nDropdownSeparator.displayName = \"DropdownSeparator\"\n\nexport interface DropdownLabelProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst DropdownLabel = React.forwardRef<HTMLDivElement, DropdownLabelProps>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"px-4 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wide\", className)} // 16px, 8px 패딩\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownLabel.displayName = \"DropdownLabel\"\n\n// 편의 컴포넌트들\nconst DropdownMenu = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"py-1\", className)} // 4px 패딩\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownMenu.displayName = \"DropdownMenu\"\n\nconst DropdownGroup = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, children, ...props }, ref) => (\n <div\n ref={ref}\n className={merge(\"space-y-1\", className)} // 4px 간격\n {...props}\n >\n {children}\n </div>\n )\n)\nDropdownGroup.displayName = \"DropdownGroup\"\n\nexport { Dropdown, DropdownItem, DropdownSeparator, DropdownLabel, DropdownMenu, DropdownGroup } ","\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Drawer 컴포넌트의 props / Drawer component props\n * @typedef {Object} DrawerProps\n * @property {boolean} open - Drawer 열림/닫힘 상태 / Drawer open/close state\n * @property {(open: boolean) => void} onOpenChange - 상태 변경 콜백 / State change callback\n * @property {React.ReactNode} children - Drawer 내용 / Drawer content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {\"left\" | \"right\" | \"top\" | \"bottom\"} [side=\"right\"] - Drawer 표시 위치 / Drawer display position\n * @property {\"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\"} [size=\"md\"] - Drawer 크기 / Drawer size\n * @property {boolean} [showBackdrop=true] - 배경 오버레이 표시 여부 / Show backdrop overlay\n * @property {string} [backdropClassName] - 배경 오버레이 추가 CSS 클래스 / Backdrop overlay additional CSS class\n * @property {boolean} [closeOnBackdropClick=true] - 배경 클릭 시 닫기 여부 / Close on backdrop click\n * @property {boolean} [closeOnEscape=true] - ESC 키로 닫기 여부 / Close on ESC key\n */\ninterface DrawerProps {\n /** Drawer 열림/닫힘 상태 / Drawer open/close state */\n isOpen?: boolean\n /** Drawer 닫기 콜백 / Drawer close callback */\n onClose?: () => void\n /** Drawer 내용 / Drawer content */\n children: React.ReactNode\n /** 추가 CSS 클래스 / Additional CSS class */\n className?: string\n /** Drawer 표시 위치 / Drawer display position */\n side?: \"left\" | \"right\" | \"top\" | \"bottom\"\n /** Drawer 크기 / Drawer size */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"full\"\n /** 배경 오버레이 표시 여부 / Show backdrop overlay */\n showBackdrop?: boolean\n /** 배경 오버레이 추가 CSS 클래스 / Backdrop overlay additional CSS class */\n backdropClassName?: string\n /** 배경 클릭 시 닫기 여부 / Close on backdrop click */\n closeOnBackdropClick?: boolean\n /** ESC 키로 닫기 여부 / Close on ESC key */\n closeOnEscape?: boolean\n /** 닫기 버튼 표시 여부 / Show close button */\n closable?: boolean\n}\n\n/**\n * Drawer 컴포넌트 / Drawer component\n * \n * 사이드에서 슬라이드되는 패널 컴포넌트입니다.\n * Modal과 유사하지만 특정 방향에서 슬라이드되는 애니메이션을 제공합니다.\n * ESC 키로 닫기, 배경 클릭으로 닫기 기능을 지원합니다.\n * \n * Panel component that slides from the side.\n * Similar to Modal but provides slide animation from a specific direction.\n * Supports closing with ESC key and backdrop click.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * const [open, setOpen] = useState(false)\n * \n * <Drawer open={open} onOpenChange={setOpen}>\n * <DrawerHeader>제목</DrawerHeader>\n * <DrawerContent>내용</DrawerContent>\n * <DrawerFooter>\n * <Button onClick={() => setOpen(false)}>닫기</Button>\n * </DrawerFooter>\n * </Drawer>\n * \n * @example\n * // 왼쪽에서 열기 / Open from left\n * <Drawer open={open} onOpenChange={setOpen} side=\"left\" size=\"lg\">\n * <DrawerContent>사이드바 내용</DrawerContent>\n * </Drawer>\n * \n * @param {DrawerProps} props - Drawer 컴포넌트의 props / Drawer component props\n * @param {React.Ref<HTMLDivElement>} ref - Drawer 컨테이너 ref / Drawer container ref\n * @returns {JSX.Element} Drawer 컴포넌트 / Drawer component\n * \n * @todo 접근성 개선: role=\"dialog\", aria-modal=\"true\" 추가 필요 / Accessibility: Add role=\"dialog\", aria-modal=\"true\"\n * @todo 접근성 개선: aria-labelledby, aria-describedby 연결 필요 / Accessibility: Connect aria-labelledby, aria-describedby\n */\nconst Drawer = React.forwardRef<HTMLDivElement, DrawerProps>(\n ({\n isOpen,\n onClose,\n children,\n className,\n side = \"right\",\n size = \"md\",\n showBackdrop = true,\n backdropClassName,\n closeOnBackdropClick = true,\n closeOnEscape = true,\n closable = true,\n ...props\n }, ref) => {\n const _isOpen = isOpen ?? false\n const handleClose = () => {\n onClose?.()\n }\n\n const [isVisible, setIsVisible] = React.useState(false)\n const [isAnimating, setIsAnimating] = React.useState(false)\n\n React.useEffect(() => {\n if (_isOpen) {\n setIsVisible(true)\n setIsAnimating(true)\n // 애니메이션 시작을 위한 지연\n const timer = setTimeout(() => setIsAnimating(false), 50)\n return () => clearTimeout(timer)\n } else {\n setIsAnimating(true)\n const timer = setTimeout(() => {\n setIsVisible(false)\n setIsAnimating(false)\n }, 300) // 애니메이션 완료 후 숨김\n return () => clearTimeout(timer)\n }\n }, [_isOpen])\n\n React.useEffect(() => {\n if (!closeOnEscape) return\n\n const handleEscapeKey = (e: KeyboardEvent) => {\n if (e.key === \"Escape\" && _isOpen) {\n handleClose()\n }\n }\n\n if (_isOpen) {\n document.addEventListener(\"keydown\", handleEscapeKey)\n document.body.style.overflow = \"hidden\"\n }\n\n return () => {\n document.removeEventListener(\"keydown\", handleEscapeKey)\n document.body.style.overflow = \"\"\n }\n }, [_isOpen, closeOnEscape])\n\n if (!isVisible) return null\n\n const sizeClasses = {\n sm: side === \"left\" || side === \"right\" ? \"w-80\" : \"h-64\",\n md: side === \"left\" || side === \"right\" ? \"w-96\" : \"h-96\",\n lg: side === \"left\" || side === \"right\" ? \"w-[28rem]\" : \"h-[32rem]\",\n xl: side === \"left\" || side === \"right\" ? \"w-[32rem]\" : \"h-[40rem]\",\n full: side === \"left\" || side === \"right\" ? \"w-full\" : \"h-full\"\n }\n\n const sideClasses = {\n left: \"left-0 top-0 h-full\",\n right: \"right-0 top-0 h-full\",\n top: \"top-0 left-0 w-full\",\n bottom: \"bottom-0 left-0 w-full\"\n }\n\n // Transform: _isOpen=true -> visible position, _isOpen=false -> hidden position\n const transformClasses = {\n left: _isOpen ? \"translate-x-0\" : \"-translate-x-full\",\n right: _isOpen ? \"translate-x-0\" : \"translate-x-full\",\n top: _isOpen ? \"translate-y-0\" : \"-translate-y-full\",\n bottom: _isOpen ? \"translate-y-0\" : \"translate-y-full\"\n }\n\n return (\n <div className=\"fixed inset-0 z-50\">\n {/* Backdrop */}\n {showBackdrop && (\n <div\n className={merge(\n \"absolute inset-0 bg-black/60 backdrop-blur-md transition-opacity duration-300\",\n isAnimating ? (_isOpen ? \"opacity-100\" : \"opacity-0\") : \"\",\n backdropClassName\n )}\n onClick={closeOnBackdropClick ? handleClose : undefined}\n />\n )}\n\n {/* Drawer Content */}\n <div\n ref={ref}\n className={merge(\n \"absolute bg-background/95 backdrop-blur-xl border border-border/50 shadow-2xl transition-transform duration-300 ease-out\",\n sizeClasses[size],\n sideClasses[side],\n transformClasses[side],\n className\n )}\n {...props}\n >\n {children}\n </div>\n </div>\n )\n }\n)\nDrawer.displayName = \"Drawer\"\n\n/**\n * DrawerHeader 컴포넌트의 props / DrawerHeader component props\n * @typedef {Object} DrawerHeaderProps\n * @property {React.ReactNode} children - 헤더 내용 / Header content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {boolean} [showCloseButton=true] - 닫기 버튼 표시 여부 / Show close button\n * @property {() => void} [onClose] - 닫기 버튼 클릭 콜백 / Close button click callback\n */\ninterface DrawerHeaderProps {\n children: React.ReactNode\n className?: string\n showCloseButton?: boolean\n onClose?: () => void\n}\n\n/**\n * DrawerHeader 컴포넌트 / DrawerHeader component\n * Drawer의 헤더 영역을 표시합니다.\n * Displays the header area of a Drawer.\n * \n * @component\n * @param {DrawerHeaderProps} props - DrawerHeader 컴포넌트의 props / DrawerHeader component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerHeader 컴포넌트 / DrawerHeader component\n */\nconst DrawerHeader = React.forwardRef<HTMLDivElement, DrawerHeaderProps>(\n ({ children, className, showCloseButton = true, onClose, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex items-center justify-between p-6 border-b border-border/50\", className)}\n {...props}\n >\n <div className=\"flex-1\">{children}</div>\n {showCloseButton && (\n <button\n onClick={onClose}\n className=\"p-2 rounded-lg hover:bg-muted transition-colors\"\n >\n <Icon name=\"close\" size={20} />\n </button>\n )}\n </div>\n )\n }\n)\nDrawerHeader.displayName = \"DrawerHeader\"\n\n/**\n * DrawerContent 컴포넌트의 props / DrawerContent component props\n * @typedef {Object} DrawerContentProps\n * @property {React.ReactNode} children - 콘텐츠 / Content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n */\ninterface DrawerContentProps {\n children: React.ReactNode\n className?: string\n}\n\n/**\n * DrawerContent 컴포넌트 / DrawerContent component\n * Drawer의 메인 콘텐츠 영역을 표시합니다.\n * Displays the main content area of a Drawer.\n * \n * @component\n * @param {DrawerContentProps} props - DrawerContent 컴포넌트의 props / DrawerContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerContent 컴포넌트 / DrawerContent component\n */\nconst DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(\n ({ children, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex-1 p-6 overflow-y-auto\", className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nDrawerContent.displayName = \"DrawerContent\"\n\n/**\n * DrawerFooter 컴포넌트의 props / DrawerFooter component props\n * @typedef {Object} DrawerFooterProps\n * @property {React.ReactNode} children - 푸터 내용 / Footer content\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n */\ninterface DrawerFooterProps {\n children: React.ReactNode\n className?: string\n}\n\n/**\n * DrawerFooter 컴포넌트 / DrawerFooter component\n * Drawer의 푸터 영역을 표시합니다. 주로 액션 버튼을 배치합니다.\n * Displays the footer area of a Drawer. Typically used for action buttons.\n * \n * @component\n * @param {DrawerFooterProps} props - DrawerFooter 컴포넌트의 props / DrawerFooter component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} DrawerFooter 컴포넌트 / DrawerFooter component\n */\nconst DrawerFooter = React.forwardRef<HTMLDivElement, DrawerFooterProps>(\n ({ children, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={merge(\"flex items-center justify-end gap-3 p-6 border-t border-border/50\", className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nDrawerFooter.displayName = \"DrawerFooter\"\n\nexport { Drawer, DrawerHeader, DrawerContent, DrawerFooter } "]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {a as a$1}from'./chunk-SGEP3CQE.mjs';import {l}from'./chunk-
|
|
3
|
-
//# sourceMappingURL=chunk-
|
|
2
|
+
import {a as a$1}from'./chunk-SGEP3CQE.mjs';import {l}from'./chunk-HN5LSP6L.mjs';import {a}from'./chunk-UUHAXGMO.mjs';import w from'react';import {cva}from'class-variance-authority';import {jsx,jsxs}from'react/jsx-runtime';var L=cva("flex w-full rounded-md border transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-offset-2 hover:border-accent-foreground hover:shadow-sm disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-muted-foreground",{variants:{variant:{default:"border-input bg-background text-foreground focus:border-ring focus:ring-ring",outline:"border-2 border-input bg-transparent text-foreground focus:border-ring focus:ring-ring",filled:"border-transparent bg-secondary/50 text-foreground focus:bg-background focus:border-ring focus:ring-ring",ghost:"border-transparent bg-transparent text-foreground focus:bg-muted focus:border-border focus:ring-muted-foreground",glass:"border-white/30 bg-white/10 backdrop-blur-sm text-white placeholder:text-white/60 focus:border-ring/50 focus:ring-ring/20 focus:bg-white/20"},size:{sm:"px-3 py-2 text-sm min-h-[80px]",md:"px-4 py-3 text-base min-h-[100px]",lg:"px-4 py-3 text-lg min-h-[120px]"},resize:{none:"resize-none",vertical:"resize-y",horizontal:"resize-x",both:"resize"}},defaultVariants:{variant:"default",size:"md",resize:"vertical"}}),O=w.forwardRef(({className:l,variant:c="default",size:i="md",error:a$2=false,success:u=false,resize:r="vertical",...t},f)=>{let e=t["aria-invalid"],g=a$2||(e!==void 0?e:false);return jsx("textarea",{className:a(L({variant:c,size:i,resize:r}),a$2&&a$1.error,u&&a$1.success,l),ref:f,"aria-invalid":g||void 0,...t})});O.displayName="Textarea";var E=w.forwardRef(({className:l$1,variant:c="default",size:i="md",error:a$1=false,success:u=false,label:r,description:t,id:f,...e},g)=>{var h,v;let k=w.useId(),s=f||k,p=r?`${s}-label`:void 0,x=t?`${s}-description`:void 0,z={sm:"w-4 h-4",md:"w-5 h-5",lg:"w-6 h-6"},T={sm:12,md:14,lg:16},C={default:"border-input bg-background text-primary focus:ring-ring",outline:"border-2 border-input bg-transparent text-primary focus:ring-ring",filled:"border-transparent bg-muted text-primary focus:bg-background focus:ring-ring",glass:"border-white/30 bg-white/10 backdrop-blur-sm text-white focus:ring-ring/50 focus:bg-white/20"},I=a$1?"border-destructive focus:ring-destructive":u?"border-green-500 focus:ring-green-500":"",N=e.checked!==void 0,d=(v=(h=e.checked)!=null?h:e.defaultChecked)!=null?v:false,R=N&&!e.onChange&&!e.readOnly;return jsxs("div",{className:"flex items-start space-x-3",children:[jsxs("div",{className:"relative",children:[jsx("input",{type:"checkbox",id:s,className:a("peer absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10",l$1),ref:g,"aria-checked":d,"aria-invalid":a$1,"aria-label":r?void 0:e["aria-label"],"aria-labelledby":r?p:void 0,"aria-describedby":x,role:"checkbox",readOnly:R||e.readOnly,...e}),jsx("div",{className:a("flex items-center justify-center rounded border transition-all duration-200 cursor-pointer relative","peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-offset-2","peer-hover:border-accent-foreground peer-hover:shadow-sm","peer-disabled:cursor-not-allowed peer-disabled:opacity-50",z[i],C[c],I,d&&"bg-primary border-primary shadow-md shadow-primary/20",!d&&"bg-background"),children:jsx(l,{name:"check",size:T[i],className:a("text-white transition-all duration-200",d?"opacity-100 scale-100":"opacity-0 scale-0")})})]}),(r||t)&&jsxs("div",{className:"flex flex-col",children:[r&&jsx("label",{htmlFor:s,id:p,className:"text-sm font-medium text-foreground cursor-pointer",children:r}),t&&jsx("p",{id:x,className:"text-sm text-muted-foreground",children:t})]})]})});E.displayName="Checkbox";export{O as a,E as b};//# sourceMappingURL=chunk-UWHCM3S6.mjs.map
|
|
3
|
+
//# sourceMappingURL=chunk-UWHCM3S6.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Textarea.tsx","../src/components/Checkbox.tsx"],"names":["textareaVariants","cva","Textarea","React","className","variant","size","error","success","resize","props","ref","ariaInvalid","isInvalid","jsx","merge","FORM_STATE","Checkbox","label","description","id","_a","_b","generatedId","checkboxId","labelId","descriptionId","sizeClasses","iconSizes","variantClasses","stateClasses","isControlled","isChecked","needsReadOnly","jsxs","Icon"],"mappings":"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","file":"chunk-OI66ZLUB.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { cva } from \"class-variance-authority\"\nimport { merge } from \"../lib/utils\"\nimport { FORM_STATE } from \"../lib/styles/cva-base\"\n\nexport const textareaVariants = cva(\n \"flex w-full rounded-md border transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-offset-2 hover:border-accent-foreground hover:shadow-sm disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-muted-foreground\",\n {\n variants: {\n variant: {\n default: \"border-input bg-background text-foreground focus:border-ring focus:ring-ring\",\n outline: \"border-2 border-input bg-transparent text-foreground focus:border-ring focus:ring-ring\",\n filled: \"border-transparent bg-secondary/50 text-foreground focus:bg-background focus:border-ring focus:ring-ring\",\n ghost: \"border-transparent bg-transparent text-foreground focus:bg-muted focus:border-border focus:ring-muted-foreground\",\n glass: \"border-white/30 bg-white/10 backdrop-blur-sm text-white placeholder:text-white/60 focus:border-ring/50 focus:ring-ring/20 focus:bg-white/20\",\n },\n size: {\n sm: \"px-3 py-2 text-sm min-h-[80px]\",\n md: \"px-4 py-3 text-base min-h-[100px]\",\n lg: \"px-4 py-3 text-lg min-h-[120px]\",\n },\n resize: {\n none: \"resize-none\",\n vertical: \"resize-y\",\n horizontal: \"resize-x\",\n both: \"resize\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n resize: \"vertical\",\n },\n }\n)\n\n/**\n * Textarea 컴포넌트의 props / Textarea component props\n */\nexport interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n variant?: \"default\" | \"outline\" | \"filled\" | \"ghost\" | \"glass\"\n size?: \"sm\" | \"md\" | \"lg\"\n error?: boolean\n success?: boolean\n resize?: \"none\" | \"vertical\" | \"horizontal\" | \"both\"\n}\n\n/**\n * Textarea 컴포넌트 / Textarea component\n * \n * 여러 줄 텍스트 입력을 위한 텍스트 영역 컴포넌트입니다.\n * 다양한 스타일 변형과 크기를 지원하며, 접근성 속성을 포함합니다.\n * \n * Text area component for multi-line text input.\n * Supports various style variants and sizes, includes accessibility attributes.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Textarea placeholder=\"내용을 입력하세요\" />\n * \n * @example\n * // 에러 상태 / Error state\n * <Textarea \n * error\n * placeholder=\"에러가 발생했습니다\"\n * aria-label=\"설명 입력\"\n * />\n * \n * @example\n * // 크기 조절 비활성화 / Disable resize\n * <Textarea \n * resize=\"none\"\n * rows={5}\n * placeholder=\"고정 크기 텍스트 영역\"\n * />\n * \n * @param {TextareaProps} props - Textarea 컴포넌트의 props / Textarea component props\n * @param {React.Ref<HTMLTextAreaElement>} ref - textarea 요소 ref / textarea element ref\n * @returns {JSX.Element} Textarea 컴포넌트 / Textarea component\n * \n * @todo 접근성 개선: aria-invalid 속성 자동 추가 필요 / Accessibility improvement: auto-add aria-invalid attribute\n */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ \n className, \n variant = \"default\",\n size = \"md\",\n error = false,\n success = false,\n resize = \"vertical\",\n ...props \n }, ref) => {\n const ariaInvalid = props['aria-invalid' as keyof typeof props] as boolean | undefined\n const isInvalid = error || (ariaInvalid !== undefined ? ariaInvalid : false)\n\n return (\n <textarea\n className={merge(\n textareaVariants({ variant, size, resize }),\n error && FORM_STATE.error,\n success && FORM_STATE.success,\n className\n )}\n ref={ref}\n aria-invalid={isInvalid || undefined}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = \"Textarea\"\n\nexport { Textarea } ","\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Checkbox 컴포넌트의 props / Checkbox component props\n * @typedef {Object} CheckboxProps\n * @property {\"default\" | \"outline\" | \"filled\" | \"glass\"} [variant=\"default\"] - Checkbox 스타일 변형 / Checkbox style variant\n * @property {\"sm\" | \"md\" | \"lg\"} [size=\"md\"] - Checkbox 크기 / Checkbox size\n * @property {boolean} [error=false] - 에러 상태 표시 / Error state\n * @property {boolean} [success=false] - 성공 상태 표시 / Success state\n * @property {string} [label] - 체크박스 레이블 텍스트 / Checkbox label text\n * @property {string} [description] - 체크박스 설명 텍스트 / Checkbox description text\n * @extends {Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>}\n */\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n variant?: \"default\" | \"outline\" | \"filled\" | \"glass\"\n size?: \"sm\" | \"md\" | \"lg\"\n error?: boolean\n success?: boolean\n label?: string\n description?: string\n}\n\n/**\n * Checkbox 컴포넌트 / Checkbox component\n * \n * 체크박스 입력 필드를 제공하는 컴포넌트입니다.\n * ARIA 속성을 자동으로 설정하여 접근성을 지원합니다.\n * \n * Checkbox input field component.\n * Automatically sets ARIA attributes for accessibility support.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Checkbox label=\"이용약관에 동의합니다\" />\n * \n * @example\n * // 에러 상태와 설명 / Error state with description\n * <Checkbox \n * label=\"필수 항목\"\n * description=\"이 항목은 필수입니다\"\n * error\n * />\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [checked, setChecked] = useState(false)\n * <Checkbox \n * checked={checked}\n * onChange={(e) => setChecked(e.target.checked)}\n * label=\"동의\"\n * />\n * \n * @param {CheckboxProps} props - Checkbox 컴포넌트의 props / Checkbox component props\n * @param {React.Ref<HTMLInputElement>} ref - input 요소 ref / input element ref\n * @returns {JSX.Element} Checkbox 컴포넌트 / Checkbox component\n */\nconst Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ \n className, \n variant = \"default\",\n size = \"md\",\n error = false,\n success = false,\n label,\n description,\n id,\n ...props \n }, ref) => {\n const generatedId = React.useId()\n const checkboxId = id || generatedId\n const labelId = label ? `${checkboxId}-label` : undefined\n const descriptionId = description ? `${checkboxId}-description` : undefined\n const sizeClasses = {\n sm: \"w-4 h-4\",\n md: \"w-5 h-5\",\n lg: \"w-6 h-6\"\n }\n\n const iconSizes = {\n sm: 12,\n md: 14,\n lg: 16\n }\n\n const variantClasses = {\n default: \"border-input bg-background text-primary focus:ring-ring\",\n outline: \"border-2 border-input bg-transparent text-primary focus:ring-ring\",\n filled: \"border-transparent bg-muted text-primary focus:bg-background focus:ring-ring\",\n glass: \"border-white/30 bg-white/10 backdrop-blur-sm text-white focus:ring-ring/50 focus:bg-white/20\",\n }\n\n const stateClasses = error\n ? \"border-destructive focus:ring-destructive\"\n : success\n ? \"border-green-500 focus:ring-green-500\"\n : \"\"\n\n // Support both controlled and uncontrolled modes\n const isControlled = props.checked !== undefined;\n const isChecked = props.checked ?? props.defaultChecked ?? false;\n // Add readOnly if controlled without onChange to suppress React warning\n const needsReadOnly = isControlled && !props.onChange && !props.readOnly;\n\n return (\n <div className=\"flex items-start space-x-3\">\n <div className=\"relative\">\n <input\n type=\"checkbox\"\n id={checkboxId}\n className={merge(\n \"peer absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10\",\n className\n )}\n ref={ref}\n aria-checked={isChecked}\n aria-invalid={error}\n aria-label={!label ? props['aria-label'] : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-describedby={descriptionId}\n role=\"checkbox\"\n readOnly={needsReadOnly || props.readOnly}\n {...props}\n />\n <div\n className={merge(\n \"flex items-center justify-center rounded border transition-all duration-200 cursor-pointer relative\",\n \"peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-offset-2\",\n \"peer-hover:border-accent-foreground peer-hover:shadow-sm\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n sizeClasses[size],\n variantClasses[variant],\n stateClasses,\n isChecked && \"bg-primary border-primary shadow-md shadow-primary/20\",\n !isChecked && \"bg-background\"\n )}\n >\n {/* 체크 아이콘으로 개선 */}\n <Icon \n name=\"check\" \n size={iconSizes[size]} \n className={merge(\n \"text-white transition-all duration-200\",\n isChecked ? \"opacity-100 scale-100\" : \"opacity-0 scale-0\"\n )}\n />\n </div>\n </div>\n {(label || description) && (\n <div className=\"flex flex-col\">\n {label && (\n <label htmlFor={checkboxId} id={labelId} className=\"text-sm font-medium text-foreground cursor-pointer\">\n {label}\n </label>\n )}\n {description && (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n )}\n </div>\n )\n }\n)\nCheckbox.displayName = \"Checkbox\"\n\nexport { Checkbox } "]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Textarea.tsx","../src/components/Checkbox.tsx"],"names":["textareaVariants","cva","Textarea","React","className","variant","size","error","success","resize","props","ref","ariaInvalid","isInvalid","jsx","merge","FORM_STATE","Checkbox","label","description","id","_a","_b","generatedId","checkboxId","labelId","descriptionId","sizeClasses","iconSizes","variantClasses","stateClasses","isControlled","isChecked","needsReadOnly","jsxs","Icon"],"mappings":"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","file":"chunk-UWHCM3S6.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { cva } from \"class-variance-authority\"\nimport { merge } from \"../lib/utils\"\nimport { FORM_STATE } from \"../lib/styles/cva-base\"\n\nexport const textareaVariants = cva(\n \"flex w-full rounded-md border transition-all duration-200 focus:outline-none focus:ring-1 focus:ring-offset-2 hover:border-accent-foreground hover:shadow-sm disabled:cursor-not-allowed disabled:opacity-50 placeholder:text-muted-foreground\",\n {\n variants: {\n variant: {\n default: \"border-input bg-background text-foreground focus:border-ring focus:ring-ring\",\n outline: \"border-2 border-input bg-transparent text-foreground focus:border-ring focus:ring-ring\",\n filled: \"border-transparent bg-secondary/50 text-foreground focus:bg-background focus:border-ring focus:ring-ring\",\n ghost: \"border-transparent bg-transparent text-foreground focus:bg-muted focus:border-border focus:ring-muted-foreground\",\n glass: \"border-white/30 bg-white/10 backdrop-blur-sm text-white placeholder:text-white/60 focus:border-ring/50 focus:ring-ring/20 focus:bg-white/20\",\n },\n size: {\n sm: \"px-3 py-2 text-sm min-h-[80px]\",\n md: \"px-4 py-3 text-base min-h-[100px]\",\n lg: \"px-4 py-3 text-lg min-h-[120px]\",\n },\n resize: {\n none: \"resize-none\",\n vertical: \"resize-y\",\n horizontal: \"resize-x\",\n both: \"resize\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n resize: \"vertical\",\n },\n }\n)\n\n/**\n * Textarea 컴포넌트의 props / Textarea component props\n */\nexport interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\n variant?: \"default\" | \"outline\" | \"filled\" | \"ghost\" | \"glass\"\n size?: \"sm\" | \"md\" | \"lg\"\n error?: boolean\n success?: boolean\n resize?: \"none\" | \"vertical\" | \"horizontal\" | \"both\"\n}\n\n/**\n * Textarea 컴포넌트 / Textarea component\n * \n * 여러 줄 텍스트 입력을 위한 텍스트 영역 컴포넌트입니다.\n * 다양한 스타일 변형과 크기를 지원하며, 접근성 속성을 포함합니다.\n * \n * Text area component for multi-line text input.\n * Supports various style variants and sizes, includes accessibility attributes.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Textarea placeholder=\"내용을 입력하세요\" />\n * \n * @example\n * // 에러 상태 / Error state\n * <Textarea \n * error\n * placeholder=\"에러가 발생했습니다\"\n * aria-label=\"설명 입력\"\n * />\n * \n * @example\n * // 크기 조절 비활성화 / Disable resize\n * <Textarea \n * resize=\"none\"\n * rows={5}\n * placeholder=\"고정 크기 텍스트 영역\"\n * />\n * \n * @param {TextareaProps} props - Textarea 컴포넌트의 props / Textarea component props\n * @param {React.Ref<HTMLTextAreaElement>} ref - textarea 요소 ref / textarea element ref\n * @returns {JSX.Element} Textarea 컴포넌트 / Textarea component\n * \n * @todo 접근성 개선: aria-invalid 속성 자동 추가 필요 / Accessibility improvement: auto-add aria-invalid attribute\n */\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ \n className, \n variant = \"default\",\n size = \"md\",\n error = false,\n success = false,\n resize = \"vertical\",\n ...props \n }, ref) => {\n const ariaInvalid = props['aria-invalid' as keyof typeof props] as boolean | undefined\n const isInvalid = error || (ariaInvalid !== undefined ? ariaInvalid : false)\n\n return (\n <textarea\n className={merge(\n textareaVariants({ variant, size, resize }),\n error && FORM_STATE.error,\n success && FORM_STATE.success,\n className\n )}\n ref={ref}\n aria-invalid={isInvalid || undefined}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = \"Textarea\"\n\nexport { Textarea } ","\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Checkbox 컴포넌트의 props / Checkbox component props\n * @typedef {Object} CheckboxProps\n * @property {\"default\" | \"outline\" | \"filled\" | \"glass\"} [variant=\"default\"] - Checkbox 스타일 변형 / Checkbox style variant\n * @property {\"sm\" | \"md\" | \"lg\"} [size=\"md\"] - Checkbox 크기 / Checkbox size\n * @property {boolean} [error=false] - 에러 상태 표시 / Error state\n * @property {boolean} [success=false] - 성공 상태 표시 / Success state\n * @property {string} [label] - 체크박스 레이블 텍스트 / Checkbox label text\n * @property {string} [description] - 체크박스 설명 텍스트 / Checkbox description text\n * @extends {Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>}\n */\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {\n variant?: \"default\" | \"outline\" | \"filled\" | \"glass\"\n size?: \"sm\" | \"md\" | \"lg\"\n error?: boolean\n success?: boolean\n label?: string\n description?: string\n}\n\n/**\n * Checkbox 컴포넌트 / Checkbox component\n * \n * 체크박스 입력 필드를 제공하는 컴포넌트입니다.\n * ARIA 속성을 자동으로 설정하여 접근성을 지원합니다.\n * \n * Checkbox input field component.\n * Automatically sets ARIA attributes for accessibility support.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Checkbox label=\"이용약관에 동의합니다\" />\n * \n * @example\n * // 에러 상태와 설명 / Error state with description\n * <Checkbox \n * label=\"필수 항목\"\n * description=\"이 항목은 필수입니다\"\n * error\n * />\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [checked, setChecked] = useState(false)\n * <Checkbox \n * checked={checked}\n * onChange={(e) => setChecked(e.target.checked)}\n * label=\"동의\"\n * />\n * \n * @param {CheckboxProps} props - Checkbox 컴포넌트의 props / Checkbox component props\n * @param {React.Ref<HTMLInputElement>} ref - input 요소 ref / input element ref\n * @returns {JSX.Element} Checkbox 컴포넌트 / Checkbox component\n */\nconst Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n ({ \n className, \n variant = \"default\",\n size = \"md\",\n error = false,\n success = false,\n label,\n description,\n id,\n ...props \n }, ref) => {\n const generatedId = React.useId()\n const checkboxId = id || generatedId\n const labelId = label ? `${checkboxId}-label` : undefined\n const descriptionId = description ? `${checkboxId}-description` : undefined\n const sizeClasses = {\n sm: \"w-4 h-4\",\n md: \"w-5 h-5\",\n lg: \"w-6 h-6\"\n }\n\n const iconSizes = {\n sm: 12,\n md: 14,\n lg: 16\n }\n\n const variantClasses = {\n default: \"border-input bg-background text-primary focus:ring-ring\",\n outline: \"border-2 border-input bg-transparent text-primary focus:ring-ring\",\n filled: \"border-transparent bg-muted text-primary focus:bg-background focus:ring-ring\",\n glass: \"border-white/30 bg-white/10 backdrop-blur-sm text-white focus:ring-ring/50 focus:bg-white/20\",\n }\n\n const stateClasses = error\n ? \"border-destructive focus:ring-destructive\"\n : success\n ? \"border-green-500 focus:ring-green-500\"\n : \"\"\n\n // Support both controlled and uncontrolled modes\n const isControlled = props.checked !== undefined;\n const isChecked = props.checked ?? props.defaultChecked ?? false;\n // Add readOnly if controlled without onChange to suppress React warning\n const needsReadOnly = isControlled && !props.onChange && !props.readOnly;\n\n return (\n <div className=\"flex items-start space-x-3\">\n <div className=\"relative\">\n <input\n type=\"checkbox\"\n id={checkboxId}\n className={merge(\n \"peer absolute inset-0 w-full h-full opacity-0 cursor-pointer z-10\",\n className\n )}\n ref={ref}\n aria-checked={isChecked}\n aria-invalid={error}\n aria-label={!label ? props['aria-label'] : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-describedby={descriptionId}\n role=\"checkbox\"\n readOnly={needsReadOnly || props.readOnly}\n {...props}\n />\n <div\n className={merge(\n \"flex items-center justify-center rounded border transition-all duration-200 cursor-pointer relative\",\n \"peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-offset-2\",\n \"peer-hover:border-accent-foreground peer-hover:shadow-sm\",\n \"peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n sizeClasses[size],\n variantClasses[variant],\n stateClasses,\n isChecked && \"bg-primary border-primary shadow-md shadow-primary/20\",\n !isChecked && \"bg-background\"\n )}\n >\n {/* 체크 아이콘으로 개선 */}\n <Icon \n name=\"check\" \n size={iconSizes[size]} \n className={merge(\n \"text-white transition-all duration-200\",\n isChecked ? \"opacity-100 scale-100\" : \"opacity-0 scale-0\"\n )}\n />\n </div>\n </div>\n {(label || description) && (\n <div className=\"flex flex-col\">\n {label && (\n <label htmlFor={checkboxId} id={labelId} className=\"text-sm font-medium text-foreground cursor-pointer\">\n {label}\n </label>\n )}\n {description && (\n <p id={descriptionId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n )}\n </div>\n )}\n </div>\n )\n }\n)\nCheckbox.displayName = \"Checkbox\"\n\nexport { Checkbox } "]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {l}from'./chunk-
|
|
3
|
-
//# sourceMappingURL=chunk-
|
|
2
|
+
import {l}from'./chunk-HN5LSP6L.mjs';import {a}from'./chunk-UUHAXGMO.mjs';import f from'react';import {jsx,jsxs}from'react/jsx-runtime';var M=f.forwardRef(({children:s,className:r,type:o="single",defaultValue:a$1,value:n,onValueChange:c,collapsible:u=false,...v},m)=>{let[l,d]=f.useState(n?Array.isArray(n)?n:[n]:a$1?Array.isArray(a$1)?a$1:[a$1]:[]);f.useEffect(()=>{n!==void 0&&d(Array.isArray(n)?n:[n]);},[n]);let y=e=>{let t;o==="single"?l.includes(e)?t=u?[]:l:t=[e]:l.includes(e)?t=l.filter(i=>i!==e):t=[...l,e],d(t),c==null||c(o==="single"?t[0]||"":t);},p=f.useMemo(()=>{let e=[];return f.Children.forEach(s,t=>{if(f.isValidElement(t)){let i=t.props;i.value&&e.push(i.value);}}),e},[s]),h=e=>{var D;let t=e.target;if(!t.hasAttribute("data-accordion-trigger"))return;let i=t.getAttribute("data-accordion-value");if(!i)return;let x=p.indexOf(i);if(x===-1)return;let T=x;if(e.key==="ArrowDown"?(e.preventDefault(),T=x<p.length-1?x+1:0):e.key==="ArrowUp"?(e.preventDefault(),T=x>0?x-1:p.length-1):e.key==="Home"?(e.preventDefault(),T=0):e.key==="End"&&(e.preventDefault(),T=p.length-1),T!==x&&p[T]){let P=(D=t.closest("[data-accordion-item]"))==null?void 0:D.querySelector(`[data-accordion-value="${p[T]}"]`);P==null||P.focus();}};return jsx("div",{ref:m,className:a("space-y-2",r),onKeyDown:h,...v,children:f.Children.map(s,e=>f.isValidElement(e)?f.cloneElement(e,{openItems:l,onToggle:y}):e)})});M.displayName="Accordion";var k=f.forwardRef(({value:s,children:r,className:o,disabled:a$1=false,openItems:n=[],onToggle:c,...u},v)=>{let m=n.includes(s);return jsx("div",{ref:v,"data-accordion-item":true,className:a("border border-border/50 rounded-lg overflow-hidden",a$1&&"opacity-50 pointer-events-none",o),...u,children:f.Children.map(r,l=>f.isValidElement(l)?f.cloneElement(l,{value:s,isOpen:m,disabled:a$1,onToggle:()=>c==null?void 0:c(s),"data-accordion-value":s}):l)})});k.displayName="AccordionItem";var I=f.forwardRef(({children:s,className:r,icon:o,iconPosition:a$1="right",value:n,isOpen:c=false,disabled:u=false,onToggle:v,...m},l$1)=>{let d=jsx(l,{name:"chevronDown",size:20,className:a("transition-transform duration-300 ease-out text-muted-foreground",c&&"rotate-180")}),y=`accordion-content-${n}`,p=`accordion-trigger-${n}`;return jsxs("button",{ref:l$1,id:p,"data-accordion-trigger":true,"data-accordion-value":n,"aria-expanded":c,"aria-controls":y,onClick:v,disabled:u,className:a("flex w-full items-center justify-between px-6 py-4 text-left font-medium transition-all hover:bg-muted/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",r),...m,children:[jsxs("div",{className:"flex items-center gap-3 flex-1",children:[a$1==="left"&&(o||d),jsx("span",{className:"flex-1",children:s})]}),a$1==="right"&&(o||d)]})});I.displayName="AccordionTrigger";var C=f.forwardRef(({children:s,className:r,isOpen:o=false,value:a$1,"data-accordion-value":n,...c},u)=>{let[v,m]=f.useState(0),l=f.useRef(null),d=a$1||n||"unknown";f.useEffect(()=>{l.current&&m(o?l.current.scrollHeight:0);},[o,s]);let y=`accordion-trigger-${d}`,p=`accordion-content-${d}`;return jsx("div",{ref:u,id:p,role:"region","aria-labelledby":y,hidden:!o,className:"overflow-hidden transition-all duration-300 ease-out",style:{height:`${v}px`},...c,children:jsx("div",{ref:l,className:a("px-6 pt-2 pb-4",r),children:s})})});C.displayName="AccordionContent";var L=f.forwardRef(({className:s,value:r,active:o,children:a$1,...n},c)=>o===false?null:jsx("div",{ref:c,role:"tabpanel",id:`tabpanel-${r}`,"aria-labelledby":`tab-${r}`,hidden:!o,className:a("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2",s),...n,children:a$1}));L.displayName="TabsContent";var A=f.forwardRef(({className:s,value:r,defaultValue:o,onValueChange:a$1,orientation:n="horizontal",variant:c="default",size:u="md",children:v,...m},l)=>{let[d,y]=f.useState(r||o||""),p=r!==void 0,h=p?r:d,e=t=>{p||y(t),a$1==null||a$1(t);};return f.useEffect(()=>{r!==void 0&&y(r);},[r]),jsx("div",{ref:l,className:a("w-full",n==="vertical"&&"flex",s),...m,children:f.Children.map(v,t=>{if(f.isValidElement(t)){if(t.type===L){let i=t.props;return f.cloneElement(t,{active:i.value===h})}if(t.type===N)return f.cloneElement(t,{value:h,onValueChange:e,orientation:n,variant:c,size:u});if(typeof t.type!="string")return f.cloneElement(t,{value:h,onValueChange:e,orientation:n,variant:c,size:u})}return t})})});A.displayName="Tabs";var N=f.forwardRef(({className:s,value:r,onValueChange:o,orientation:a$1="horizontal",variant:n="default",size:c="md",children:u,...v},m)=>{let l=f.useRef(null);f.useImperativeHandle(m,()=>l.current);let d=f.useMemo(()=>{let e=[];return f.Children.forEach(u,t=>{if(f.isValidElement(t)){let i=t.props;i.value&&e.push(i.value);}}),e},[u]),y=e=>{var x;if(!r||d.length===0)return;let t=d.indexOf(r);if(t===-1)return;let i=t;if(a$1==="horizontal"?e.key==="ArrowLeft"?(e.preventDefault(),i=t>0?t-1:d.length-1):e.key==="ArrowRight"?(e.preventDefault(),i=t<d.length-1?t+1:0):e.key==="Home"?(e.preventDefault(),i=0):e.key==="End"&&(e.preventDefault(),i=d.length-1):e.key==="ArrowUp"?(e.preventDefault(),i=t>0?t-1:d.length-1):e.key==="ArrowDown"?(e.preventDefault(),i=t<d.length-1?t+1:0):e.key==="Home"?(e.preventDefault(),i=0):e.key==="End"&&(e.preventDefault(),i=d.length-1),i!==t&&d[i]){o==null||o(d[i]);let T=(x=l.current)==null?void 0:x.querySelector(`[data-tab-value="${d[i]}"]`);T==null||T.focus();}},p=()=>{switch(n){case "pills":return "bg-muted p-3 rounded-xl border border-border/50";case "underline":return "border-b border-border";case "cards":return "bg-muted/80 p-3 rounded-xl border border-border/50";default:return "bg-muted p-3 rounded-xl border border-border/50"}},h=()=>{switch(c){case "sm":return "h-12";case "lg":return "h-16";default:return "h-14"}};return jsx("div",{ref:l,role:"tablist","aria-orientation":a$1,onKeyDown:y,className:a("flex items-center justify-center",a$1==="vertical"&&"flex-col",p(),h(),s),...v,children:f.Children.map(u,e=>{if(f.isValidElement(e)){if(typeof e.type=="string")return e;let t=e.props;return f.cloneElement(e,{onValueChange:o,orientation:a$1,variant:n,size:c,active:t.value===r})}return e})})});N.displayName="TabsList";var z=f.forwardRef(({className:s,value:r,onValueChange:o,orientation:a$1="horizontal",variant:n="default",size:c="md",active:u=false,children:v,...m},l)=>{let d=()=>{switch(n){case "pills":return a("inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",u?"bg-background text-foreground shadow-md":"text-muted-foreground hover:text-foreground hover:bg-muted");case "underline":return a("inline-flex items-center justify-center whitespace-nowrap border-b-2 px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",u?"border-primary text-primary":"border-transparent text-muted-foreground hover:text-foreground");case "cards":return a("inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",u?"bg-background text-foreground shadow-md":"text-muted-foreground hover:text-foreground hover:bg-muted");default:return a("inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",u?"bg-background text-foreground shadow-md":"text-muted-foreground hover:text-foreground hover:bg-muted")}},y=()=>{switch(c){case "sm":return "h-10 px-4 py-2 text-xs";case "lg":return "h-14 px-6 py-3 text-base";default:return "h-12 px-5 py-2.5 text-sm"}},p=()=>{o&&o(r);};return jsx("button",{ref:l,role:"tab","aria-selected":u,"aria-controls":`tabpanel-${r}`,id:`tab-${r}`,"data-tab-value":r,tabIndex:u?0:-1,className:a(d(),y(),s),onClick:p,type:"button",...m,children:v})});z.displayName="TabsTrigger";var $=f.forwardRef((s,r)=>jsx(A,{ref:r,variant:"pills",...s}));$.displayName="TabsPills";var S=f.forwardRef((s,r)=>jsx(A,{ref:r,variant:"underline",...s}));S.displayName="TabsUnderline";var K=f.forwardRef((s,r)=>jsx(A,{ref:r,variant:"cards",...s}));K.displayName="TabsCards";export{M as a,k as b,I as c,C as d,L as e,A as f,N as g,z as h,$ as i,S as j,K as k};//# sourceMappingURL=chunk-XV3Y7QVU.mjs.map
|
|
3
|
+
//# sourceMappingURL=chunk-XV3Y7QVU.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Accordion.tsx","../src/components/Tabs.tsx"],"names":["Accordion","React","children","className","type","defaultValue","value","onValueChange","collapsible","props","ref","openItems","setOpenItems","handleItemToggle","itemValue","newOpenItems","item","itemValues","values","child","childProps","handleKeyDown","_a","target","currentValue","currentIndex","newIndex","triggerElement","jsx","merge","AccordionItem","disabled","onToggle","isOpen","AccordionTrigger","icon","iconPosition","defaultIcon","Icon","contentId","triggerId","jsxs","AccordionContent","dataValue","height","setHeight","contentRef","TabsContent","active","Tabs","orientation","variant","size","activeTab","setActiveTab","isControlled","handleTabChange","newValue","TabsList","listRef","tabValues","getVariantClasses","getSizeClasses","TabsTrigger","_orientation","handleClick","TabsPills","TabsUnderline","TabsCards"],"mappings":"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","file":"chunk-MYFMKCYX.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Accordion 컴포넌트의 props / Accordion component props\n * @typedef {Object} AccordionProps\n * @property {React.ReactNode} children - AccordionItem 컴포넌트들 / AccordionItem components\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {\"single\" | \"multiple\"} [type=\"single\"] - 단일 또는 다중 아이템 열기 허용 / Allow single or multiple items to be open\n * @property {string | string[]} [defaultValue] - 초기 열린 아이템 값 (비제어 컴포넌트) / Initial open item value (uncontrolled component)\n * @property {string | string[]} [value] - 현재 열린 아이템 값 (제어 컴포넌트) / Current open item value (controlled component)\n * @property {(value: string | string[]) => void} [onValueChange] - 아이템 열림/닫힘 콜백 / Item open/close callback\n * @property {boolean} [collapsible=false] - 단일 모드에서 열린 아이템을 닫을 수 있는지 여부 / Whether open item can be closed in single mode\n */\ninterface AccordionProps {\n children: React.ReactNode\n className?: string\n type?: \"single\" | \"multiple\"\n defaultValue?: string | string[]\n value?: string | string[]\n onValueChange?: (value: string | string[]) => void\n collapsible?: boolean\n}\n\n/**\n * Accordion 컴포넌트 / Accordion component\n * \n * 접을 수 있는 콘텐츠 섹션을 제공하는 컴포넌트입니다.\n * 키보드 네비게이션(Arrow keys, Home/End)을 지원하며, ARIA 속성을 자동으로 설정합니다.\n * \n * Component that provides collapsible content sections.\n * Supports keyboard navigation (Arrow keys, Home/End) and automatically sets ARIA attributes.\n * \n * @component\n * @example\n * // 기본 사용 (단일 열기) / Basic usage (single open)\n * <Accordion type=\"single\">\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목 1</AccordionTrigger>\n * <AccordionContent>내용 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item2\">\n * <AccordionTrigger>제목 2</AccordionTrigger>\n * <AccordionContent>내용 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @example\n * // 다중 열기 / Multiple open\n * <Accordion type=\"multiple\" defaultValue={[\"item1\", \"item2\"]}>\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목 1</AccordionTrigger>\n * <AccordionContent>내용 1</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [openItems, setOpenItems] = useState<string[]>([])\n * <Accordion type=\"multiple\" value={openItems} onValueChange={setOpenItems}>\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목</AccordionTrigger>\n * <AccordionContent>내용</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @param {AccordionProps} props - Accordion 컴포넌트의 props / Accordion component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Accordion 컴포넌트 / Accordion component\n */\nconst Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(\n ({ \n children, \n className,\n type = \"single\",\n defaultValue,\n value,\n onValueChange,\n collapsible = false,\n ...props \n }, ref) => {\n const [openItems, setOpenItems] = React.useState<string[]>(\n value ? (Array.isArray(value) ? value : [value]) : \n defaultValue ? (Array.isArray(defaultValue) ? defaultValue : [defaultValue]) : []\n )\n\n React.useEffect(() => {\n if (value !== undefined) {\n setOpenItems(Array.isArray(value) ? value : [value])\n }\n }, [value])\n\n const handleItemToggle = (itemValue: string) => {\n let newOpenItems: string[]\n\n if (type === \"single\") {\n if (openItems.includes(itemValue)) {\n newOpenItems = collapsible ? [] : openItems\n } else {\n newOpenItems = [itemValue]\n }\n } else {\n if (openItems.includes(itemValue)) {\n newOpenItems = openItems.filter(item => item !== itemValue)\n } else {\n newOpenItems = [...openItems, itemValue]\n }\n }\n\n setOpenItems(newOpenItems)\n onValueChange?.(type === \"single\" ? newOpenItems[0] || \"\" : newOpenItems)\n }\n\n // 모든 아이템의 value를 수집\n const itemValues = React.useMemo(() => {\n const values: string[] = []\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const childProps = child.props as { value?: string }\n if (childProps.value) {\n values.push(childProps.value)\n }\n }\n })\n return values\n }, [children])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement\n if (!target.hasAttribute('data-accordion-trigger')) return\n\n const currentValue = target.getAttribute('data-accordion-value')\n if (!currentValue) return\n\n const currentIndex = itemValues.indexOf(currentValue)\n if (currentIndex === -1) return\n\n let newIndex = currentIndex\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault()\n newIndex = currentIndex < itemValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : itemValues.length - 1\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = itemValues.length - 1\n }\n\n if (newIndex !== currentIndex && itemValues[newIndex]) {\n const triggerElement = target.closest('[data-accordion-item]')?.querySelector(\n `[data-accordion-value=\"${itemValues[newIndex]}\"]`\n ) as HTMLElement\n triggerElement?.focus()\n }\n }\n\n return (\n <div\n ref={ref}\n className={merge(\"space-y-2\", className)}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n openItems,\n onToggle: handleItemToggle\n } as Partial<AccordionItemProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nAccordion.displayName = \"Accordion\"\n\n/**\n * AccordionItem 컴포넌트의 props / AccordionItem component props\n * @typedef {Object} AccordionItemProps\n * @property {string} value - 아이템의 고유 값 / Item unique value\n * @property {React.ReactNode} children - AccordionTrigger와 AccordionContent / AccordionTrigger and AccordionContent\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {boolean} [disabled=false] - 아이템 비활성화 여부 / Item disabled state\n * @property {string[]} [openItems] - 열린 아이템 목록 (Accordion에서 자동 전달) / Open items list (auto-passed from Accordion)\n * @property {(value: string) => void} [onToggle] - 토글 콜백 (Accordion에서 자동 전달) / Toggle callback (auto-passed from Accordion)\n */\ninterface AccordionItemProps {\n value: string\n children: React.ReactNode\n className?: string\n disabled?: boolean\n openItems?: string[]\n onToggle?: (value: string) => void\n}\n\n/**\n * AccordionItem 컴포넌트 / AccordionItem component\n * 아코디언의 개별 아이템을 감싸는 컨테이너입니다.\n * Container that wraps an individual accordion item.\n * \n * @component\n * @param {AccordionItemProps} props - AccordionItem 컴포넌트의 props / AccordionItem component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} AccordionItem 컴포넌트 / AccordionItem component\n */\nconst AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(\n ({ \n value, \n children, \n className,\n disabled = false,\n openItems = [],\n onToggle,\n ...props \n }, ref) => {\n const isOpen = openItems.includes(value)\n\n return (\n <div\n ref={ref}\n data-accordion-item\n className={merge(\n \"border border-border/50 rounded-lg overflow-hidden\",\n disabled && \"opacity-50 pointer-events-none\",\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n value,\n isOpen,\n disabled,\n onToggle: () => onToggle?.(value),\n 'data-accordion-value': value\n } as Partial<AccordionTriggerProps | AccordionContentProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nAccordionItem.displayName = \"AccordionItem\"\n\ninterface AccordionTriggerProps {\n children: React.ReactNode\n className?: string\n icon?: React.ReactNode\n iconPosition?: \"left\" | \"right\"\n value?: string // Optional: AccordionItem에서 자동으로 전달됨 / Optional: Auto-passed from AccordionItem\n isOpen?: boolean\n disabled?: boolean\n onToggle?: () => void\n}\n\nconst AccordionTrigger = React.forwardRef<HTMLButtonElement, AccordionTriggerProps>(\n ({ \n children, \n className,\n icon,\n iconPosition = \"right\",\n value,\n isOpen = false,\n disabled = false,\n onToggle,\n ...props \n }, ref) => {\n const defaultIcon = (\n <Icon \n name=\"chevronDown\" \n size={20} \n className={merge(\n \"transition-transform duration-300 ease-out text-muted-foreground\",\n isOpen && \"rotate-180\"\n )} \n />\n )\n\n const contentId = `accordion-content-${value}`\n const triggerId = `accordion-trigger-${value}`\n\n return (\n <button\n ref={ref}\n id={triggerId}\n data-accordion-trigger\n data-accordion-value={value}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={onToggle}\n disabled={disabled}\n className={merge(\n \"flex w-full items-center justify-between px-6 py-4 text-left font-medium transition-all hover:bg-muted/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <div className=\"flex items-center gap-3 flex-1\">\n {iconPosition === \"left\" && (icon || defaultIcon)}\n <span className=\"flex-1\">{children}</span>\n </div>\n {iconPosition === \"right\" && (icon || defaultIcon)}\n </button>\n )\n }\n)\nAccordionTrigger.displayName = \"AccordionTrigger\"\n\n/**\n * AccordionTrigger 컴포넌트 / AccordionTrigger component\n * 아코디언 아이템을 열고 닫는 트리거 버튼입니다.\n * Button that opens and closes an accordion item.\n * \n * @component\n * @param {AccordionTriggerProps} props - AccordionTrigger 컴포넌트의 props / AccordionTrigger component props\n * @param {React.Ref<HTMLButtonElement>} ref - button 요소 ref / button element ref\n * @returns {JSX.Element} AccordionTrigger 컴포넌트 / AccordionTrigger component\n */\n\n/**\n * AccordionContent 컴포넌트의 props\n * @typedef {Object} AccordionContentProps\n * @property {React.ReactNode} children - 콘텐츠\n * @property {string} [className] - 추가 CSS 클래스\n * @property {boolean} [isOpen] - 열림 상태 (AccordionItem에서 자동 전달)\n * @property {string} [value] - 아이템 값 (AccordionItem에서 자동 전달)\n * @property {string} ['data-accordion-value'] - 아이템 값 (내부 사용)\n */\ninterface AccordionContentProps {\n children: React.ReactNode\n className?: string\n isOpen?: boolean\n value?: string\n 'data-accordion-value'?: string\n}\n\n/**\n * AccordionContent 컴포넌트 / AccordionContent component\n * 아코디언 아이템의 콘텐츠를 표시합니다.\n * Displays the content of an accordion item.\n * \n * @component\n * @param {AccordionContentProps} props - AccordionContent 컴포넌트의 props / AccordionContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} AccordionContent 컴포넌트 / AccordionContent component\n */\nconst AccordionContent = React.forwardRef<HTMLDivElement, AccordionContentProps>(\n ({ children, className, isOpen = false, value, 'data-accordion-value': dataValue, ...props }, ref) => {\n const [height, setHeight] = React.useState(0)\n const contentRef = React.useRef<HTMLDivElement>(null)\n const itemValue = value || dataValue || 'unknown'\n\n React.useEffect(() => {\n if (contentRef.current) {\n if (isOpen) {\n setHeight(contentRef.current.scrollHeight)\n } else {\n setHeight(0)\n }\n }\n }, [isOpen, children])\n\n const triggerId = `accordion-trigger-${itemValue}`\n const contentId = `accordion-content-${itemValue}`\n\n return (\n <div\n ref={ref}\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className=\"overflow-hidden transition-all duration-300 ease-out\"\n style={{ height: `${height}px` }}\n {...props}\n >\n <div\n ref={contentRef}\n className={merge(\"px-6 pt-2 pb-4\", className)}\n >\n {children}\n </div>\n </div>\n )\n }\n)\nAccordionContent.displayName = \"AccordionContent\"\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } ","\"use client\"\n\nimport React from 'react'\nimport { merge } from '../lib/utils'\n\n/**\n * TabsContent 컴포넌트의 props / TabsContent component props\n * @typedef {Object} TabsContentProps\n * @property {string} value - 탭 패널의 고유 값 (TabsTrigger의 value와 일치해야 함) / Unique value for tab panel (must match TabsTrigger value)\n * @property {boolean} [active] - 탭 패널 활성화 상태 (자동 설정됨) / Tab panel active state (auto-set)\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {\n value: string\n active?: boolean\n}\n\n/**\n * TabsContent 컴포넌트 / TabsContent component\n * 탭의 콘텐츠 패널을 표시합니다. Tabs 컴포넌트 내부에서 사용됩니다.\n * Displays the tab content panel. Used inside Tabs component.\n * \n * @component\n * @param {TabsContentProps} props - TabsContent 컴포넌트의 props / TabsContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} TabsContent 컴포넌트 / TabsContent component\n */\nconst TabsContent = React.forwardRef<HTMLDivElement, TabsContentProps>(\n ({ className, value, active, children, ...props }, ref) => {\n // active prop이 명시적으로 false로 설정된 경우에만 숨김\n if (active === false) return null\n\n return (\n <div\n ref={ref}\n role=\"tabpanel\"\n id={`tabpanel-${value}`}\n aria-labelledby={`tab-${value}`}\n hidden={!active}\n className={merge(\n \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nTabsContent.displayName = \"TabsContent\"\n\n/**\n * Tabs 컴포넌트의 props / Tabs component props\n * @typedef {Object} TabsProps\n * @property {string} [value] - 현재 활성화된 탭 값 (제어 컴포넌트) / Currently active tab value (controlled component)\n * @property {string} [defaultValue] - 초기 활성화된 탭 값 (비제어 컴포넌트) / Initial active tab value (uncontrolled component)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 시 호출되는 콜백 / Callback when tab changes\n * @property {\"horizontal\" | \"vertical\"} [orientation=\"horizontal\"] - 탭 방향 / Tab orientation\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant=\"default\"] - 탭 스타일 변형 / Tab style variant\n * @property {\"sm\" | \"md\" | \"lg\"} [size=\"md\"] - 탭 크기 / Tab size\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n}\n\n/**\n * Tabs 컴포넌트 / Tabs component\n * \n * 탭 네비게이션을 제공하는 컴포넌트입니다.\n * 키보드 네비게이션(Arrow keys, Home/End)을 지원하며, ARIA 속성을 자동으로 설정합니다.\n * \n * Component that provides tab navigation.\n * Supports keyboard navigation (Arrow keys, Home/End) and automatically sets ARIA attributes.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">탭 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">탭 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">탭 1 내용</TabsContent>\n * <TabsContent value=\"tab2\">탭 2 내용</TabsContent>\n * </Tabs>\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [activeTab, setActiveTab] = useState(\"tab1\")\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"tab1\">탭 1</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">내용</TabsContent>\n * </Tabs>\n * \n * @example\n * // 다양한 변형 / Various variants\n * <Tabs variant=\"pills\" size=\"lg\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Pills 스타일</TabsTrigger>\n * </TabsList>\n * </Tabs>\n * \n * @param {TabsProps} props - Tabs 컴포넌트의 props / Tabs component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Tabs 컴포넌트 / Tabs component\n */\nconst Tabs = React.forwardRef<HTMLDivElement, TabsProps>(\n ({ \n className, \n value,\n defaultValue,\n onValueChange,\n orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n children,\n ...props \n }, ref) => {\n const [activeTab, setActiveTab] = React.useState(value || defaultValue || \"\")\n const isControlled = value !== undefined\n const currentValue = isControlled ? value : activeTab\n\n const handleTabChange = (newValue: string) => {\n if (!isControlled) {\n setActiveTab(newValue)\n }\n onValueChange?.(newValue)\n }\n\n React.useEffect(() => {\n if (value !== undefined) {\n setActiveTab(value)\n }\n }, [value])\n\n return (\n <div\n ref={ref}\n className={merge(\n \"w-full\",\n orientation === \"vertical\" && \"flex\",\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n // TabsContent인 경우 active prop만 설정 (value는 원래 값 유지)\n if (child.type === TabsContent) {\n const childProps = child.props as TabsContentProps\n return React.cloneElement(child, {\n active: childProps.value === currentValue\n } as Partial<TabsContentProps>)\n }\n // TabsList인 경우에만 onValueChange 전달\n if (child.type === TabsList) {\n return React.cloneElement(child, {\n value: currentValue,\n onValueChange: handleTabChange,\n orientation,\n variant,\n size\n } as Partial<TabsListProps>)\n }\n // 다른 React 컴포넌트들 (다른 custom wrapper 등)\n // HTML 요소가 아닌 경우에만 props 전달\n if (typeof child.type !== 'string') {\n return React.cloneElement(child, {\n value: currentValue,\n onValueChange: handleTabChange,\n orientation,\n variant,\n size\n } as Record<string, unknown>)\n }\n }\n return child\n })}\n </div>\n )\n }\n)\nTabs.displayName = \"Tabs\"\n\n/**\n * TabsList 컴포넌트의 props / TabsList component props\n * @typedef {Object} TabsListProps\n * @property {string} [value] - 현재 활성화된 탭 값 (Tabs에서 자동 전달) / Currently active tab value (auto-passed from Tabs)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 콜백 (Tabs에서 자동 전달) / Tab change callback (auto-passed from Tabs)\n * @property {\"horizontal\" | \"vertical\"} [orientation] - 탭 방향 (Tabs에서 자동 전달) / Tab orientation (auto-passed from Tabs)\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant] - 탭 스타일 (Tabs에서 자동 전달) / Tab style (auto-passed from Tabs)\n * @property {\"sm\" | \"md\" | \"lg\"} [size] - 탭 크기 (Tabs에서 자동 전달) / Tab size (auto-passed from Tabs)\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n}\n\n/**\n * TabsList 컴포넌트 / TabsList component\n * 탭 트리거 목록을 표시합니다. Tabs 컴포넌트 내부에서 사용됩니다.\n * Displays the list of tab triggers. Used inside Tabs component.\n * \n * @component\n * @param {TabsListProps} props - TabsList 컴포넌트의 props / TabsList component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} TabsList 컴포넌트 / TabsList component\n */\nconst TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(\n ({ \n className, \n value,\n onValueChange,\n orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n children,\n ...props \n }, ref) => {\n const listRef = React.useRef<HTMLDivElement>(null)\n React.useImperativeHandle(ref, () => listRef.current as HTMLDivElement)\n \n // 모든 탭 트리거의 value를 수집\n const tabValues = React.useMemo(() => {\n const values: string[] = []\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const childProps = child.props as { value?: string }\n if (childProps.value) {\n values.push(childProps.value)\n }\n }\n })\n return values\n }, [children])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!value || tabValues.length === 0) return\n\n const currentIndex = tabValues.indexOf(value)\n if (currentIndex === -1) return\n\n let newIndex = currentIndex\n\n if (orientation === \"horizontal\") {\n if (e.key === \"ArrowLeft\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : tabValues.length - 1\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault()\n newIndex = currentIndex < tabValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = tabValues.length - 1\n }\n } else {\n if (e.key === \"ArrowUp\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : tabValues.length - 1\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault()\n newIndex = currentIndex < tabValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = tabValues.length - 1\n }\n }\n\n if (newIndex !== currentIndex && tabValues[newIndex]) {\n onValueChange?.(tabValues[newIndex])\n // 포커스 이동\n const triggerElement = listRef.current?.querySelector(\n `[data-tab-value=\"${tabValues[newIndex]}\"]`\n ) as HTMLElement\n triggerElement?.focus()\n }\n }\n const getVariantClasses = () => {\n switch (variant) {\n case \"pills\":\n return \"bg-muted p-3 rounded-xl border border-border/50\"\n case \"underline\":\n return \"border-b border-border\"\n case \"cards\":\n return \"bg-muted/80 p-3 rounded-xl border border-border/50\"\n default:\n return \"bg-muted p-3 rounded-xl border border-border/50\"\n }\n }\n\n const getSizeClasses = () => {\n switch (size) {\n case \"sm\":\n return \"h-12\"\n case \"lg\":\n return \"h-16\"\n default:\n return \"h-14\"\n }\n }\n\n return (\n <div\n ref={listRef}\n role=\"tablist\"\n aria-orientation={orientation}\n onKeyDown={handleKeyDown}\n className={merge(\n \"flex items-center justify-center\",\n orientation === \"vertical\" && \"flex-col\",\n getVariantClasses(),\n getSizeClasses(),\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n // Only pass tab props to non-HTML elements (React components)\n if (typeof child.type === 'string') {\n return child\n }\n const childProps = child.props as { value?: string }\n return React.cloneElement(child, {\n onValueChange,\n orientation,\n variant,\n size,\n active: childProps.value === value\n } as Partial<TabsTriggerProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nTabsList.displayName = \"TabsList\"\n\n/**\n * TabsTrigger 컴포넌트의 props\n * @typedef {Object} TabsTriggerProps\n * @property {string} value - 탭 트리거의 고유 값 (TabsContent의 value와 일치해야 함)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 콜백 (TabsList에서 자동 전달)\n * @property {\"horizontal\" | \"vertical\"} [orientation] - 탭 방향 (TabsList에서 자동 전달)\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant] - 탭 스타일 (TabsList에서 자동 전달)\n * @property {\"sm\" | \"md\" | \"lg\"} [size] - 탭 크기 (TabsList에서 자동 전달)\n * @property {boolean} [active] - 탭 활성화 상태 (자동 설정됨)\n * @extends {React.ButtonHTMLAttributes<HTMLButtonElement>}\n */\nexport interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n value: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n active?: boolean\n}\n\n/**\n * TabsTrigger 컴포넌트 / TabsTrigger component\n * 탭을 활성화하는 버튼입니다. TabsList 컴포넌트 내부에서 사용됩니다.\n * Button that activates a tab. Used inside TabsList component.\n * \n * @component\n * @param {TabsTriggerProps} props - TabsTrigger 컴포넌트의 props / TabsTrigger component props\n * @param {React.Ref<HTMLButtonElement>} ref - button 요소 ref / button element ref\n * @returns {JSX.Element} TabsTrigger 컴포넌트 / TabsTrigger component\n */\nconst TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(\n ({ \n className,\n value,\n onValueChange,\n orientation: _orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n active = false,\n children,\n ...props\n }, ref) => {\n const getVariantClasses = () => {\n switch (variant) {\n case \"pills\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n case \"underline\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap border-b-2 px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"border-primary text-primary\"\n : \"border-transparent text-muted-foreground hover:text-foreground\"\n )\n case \"cards\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n default:\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n }\n }\n\n const getSizeClasses = () => {\n switch (size) {\n case \"sm\":\n return \"h-10 px-4 py-2 text-xs\"\n case \"lg\":\n return \"h-14 px-6 py-3 text-base\"\n default:\n return \"h-12 px-5 py-2.5 text-sm\"\n }\n }\n\n const handleClick = () => {\n if (onValueChange) {\n onValueChange(value)\n }\n }\n\n return (\n <button\n ref={ref}\n role=\"tab\"\n aria-selected={active}\n aria-controls={`tabpanel-${value}`}\n id={`tab-${value}`}\n data-tab-value={value}\n tabIndex={active ? 0 : -1}\n className={merge(\n getVariantClasses(),\n getSizeClasses(),\n className\n )}\n onClick={handleClick}\n type=\"button\"\n {...props}\n >\n {children}\n </button>\n )\n }\n)\nTabsTrigger.displayName = \"TabsTrigger\"\n\n// 편의 컴포넌트들\nconst TabsPills = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"pills\" {...props} />\n)\nTabsPills.displayName = \"TabsPills\"\n\nconst TabsUnderline = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"underline\" {...props} />\n)\nTabsUnderline.displayName = \"TabsUnderline\"\n\nconst TabsCards = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"cards\" {...props} />\n)\nTabsCards.displayName = \"TabsCards\"\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, TabsPills, TabsUnderline, TabsCards } "]}
|
|
1
|
+
{"version":3,"sources":["../src/components/Accordion.tsx","../src/components/Tabs.tsx"],"names":["Accordion","React","children","className","type","defaultValue","value","onValueChange","collapsible","props","ref","openItems","setOpenItems","handleItemToggle","itemValue","newOpenItems","item","itemValues","values","child","childProps","handleKeyDown","_a","target","currentValue","currentIndex","newIndex","triggerElement","jsx","merge","AccordionItem","disabled","onToggle","isOpen","AccordionTrigger","icon","iconPosition","defaultIcon","Icon","contentId","triggerId","jsxs","AccordionContent","dataValue","height","setHeight","contentRef","TabsContent","active","Tabs","orientation","variant","size","activeTab","setActiveTab","isControlled","handleTabChange","newValue","TabsList","listRef","tabValues","getVariantClasses","getSizeClasses","TabsTrigger","_orientation","handleClick","TabsPills","TabsUnderline","TabsCards"],"mappings":"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","file":"chunk-XV3Y7QVU.mjs","sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { merge } from \"../lib/utils\"\nimport { Icon } from \"./Icon\"\n\n/**\n * Accordion 컴포넌트의 props / Accordion component props\n * @typedef {Object} AccordionProps\n * @property {React.ReactNode} children - AccordionItem 컴포넌트들 / AccordionItem components\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {\"single\" | \"multiple\"} [type=\"single\"] - 단일 또는 다중 아이템 열기 허용 / Allow single or multiple items to be open\n * @property {string | string[]} [defaultValue] - 초기 열린 아이템 값 (비제어 컴포넌트) / Initial open item value (uncontrolled component)\n * @property {string | string[]} [value] - 현재 열린 아이템 값 (제어 컴포넌트) / Current open item value (controlled component)\n * @property {(value: string | string[]) => void} [onValueChange] - 아이템 열림/닫힘 콜백 / Item open/close callback\n * @property {boolean} [collapsible=false] - 단일 모드에서 열린 아이템을 닫을 수 있는지 여부 / Whether open item can be closed in single mode\n */\ninterface AccordionProps {\n children: React.ReactNode\n className?: string\n type?: \"single\" | \"multiple\"\n defaultValue?: string | string[]\n value?: string | string[]\n onValueChange?: (value: string | string[]) => void\n collapsible?: boolean\n}\n\n/**\n * Accordion 컴포넌트 / Accordion component\n * \n * 접을 수 있는 콘텐츠 섹션을 제공하는 컴포넌트입니다.\n * 키보드 네비게이션(Arrow keys, Home/End)을 지원하며, ARIA 속성을 자동으로 설정합니다.\n * \n * Component that provides collapsible content sections.\n * Supports keyboard navigation (Arrow keys, Home/End) and automatically sets ARIA attributes.\n * \n * @component\n * @example\n * // 기본 사용 (단일 열기) / Basic usage (single open)\n * <Accordion type=\"single\">\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목 1</AccordionTrigger>\n * <AccordionContent>내용 1</AccordionContent>\n * </AccordionItem>\n * <AccordionItem value=\"item2\">\n * <AccordionTrigger>제목 2</AccordionTrigger>\n * <AccordionContent>내용 2</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @example\n * // 다중 열기 / Multiple open\n * <Accordion type=\"multiple\" defaultValue={[\"item1\", \"item2\"]}>\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목 1</AccordionTrigger>\n * <AccordionContent>내용 1</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [openItems, setOpenItems] = useState<string[]>([])\n * <Accordion type=\"multiple\" value={openItems} onValueChange={setOpenItems}>\n * <AccordionItem value=\"item1\">\n * <AccordionTrigger>제목</AccordionTrigger>\n * <AccordionContent>내용</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * \n * @param {AccordionProps} props - Accordion 컴포넌트의 props / Accordion component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Accordion 컴포넌트 / Accordion component\n */\nconst Accordion = React.forwardRef<HTMLDivElement, AccordionProps>(\n ({ \n children, \n className,\n type = \"single\",\n defaultValue,\n value,\n onValueChange,\n collapsible = false,\n ...props \n }, ref) => {\n const [openItems, setOpenItems] = React.useState<string[]>(\n value ? (Array.isArray(value) ? value : [value]) : \n defaultValue ? (Array.isArray(defaultValue) ? defaultValue : [defaultValue]) : []\n )\n\n React.useEffect(() => {\n if (value !== undefined) {\n setOpenItems(Array.isArray(value) ? value : [value])\n }\n }, [value])\n\n const handleItemToggle = (itemValue: string) => {\n let newOpenItems: string[]\n\n if (type === \"single\") {\n if (openItems.includes(itemValue)) {\n newOpenItems = collapsible ? [] : openItems\n } else {\n newOpenItems = [itemValue]\n }\n } else {\n if (openItems.includes(itemValue)) {\n newOpenItems = openItems.filter(item => item !== itemValue)\n } else {\n newOpenItems = [...openItems, itemValue]\n }\n }\n\n setOpenItems(newOpenItems)\n onValueChange?.(type === \"single\" ? newOpenItems[0] || \"\" : newOpenItems)\n }\n\n // 모든 아이템의 value를 수집\n const itemValues = React.useMemo(() => {\n const values: string[] = []\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const childProps = child.props as { value?: string }\n if (childProps.value) {\n values.push(childProps.value)\n }\n }\n })\n return values\n }, [children])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n const target = e.target as HTMLElement\n if (!target.hasAttribute('data-accordion-trigger')) return\n\n const currentValue = target.getAttribute('data-accordion-value')\n if (!currentValue) return\n\n const currentIndex = itemValues.indexOf(currentValue)\n if (currentIndex === -1) return\n\n let newIndex = currentIndex\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault()\n newIndex = currentIndex < itemValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : itemValues.length - 1\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = itemValues.length - 1\n }\n\n if (newIndex !== currentIndex && itemValues[newIndex]) {\n const triggerElement = target.closest('[data-accordion-item]')?.querySelector(\n `[data-accordion-value=\"${itemValues[newIndex]}\"]`\n ) as HTMLElement\n triggerElement?.focus()\n }\n }\n\n return (\n <div\n ref={ref}\n className={merge(\"space-y-2\", className)}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n openItems,\n onToggle: handleItemToggle\n } as Partial<AccordionItemProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nAccordion.displayName = \"Accordion\"\n\n/**\n * AccordionItem 컴포넌트의 props / AccordionItem component props\n * @typedef {Object} AccordionItemProps\n * @property {string} value - 아이템의 고유 값 / Item unique value\n * @property {React.ReactNode} children - AccordionTrigger와 AccordionContent / AccordionTrigger and AccordionContent\n * @property {string} [className] - 추가 CSS 클래스 / Additional CSS class\n * @property {boolean} [disabled=false] - 아이템 비활성화 여부 / Item disabled state\n * @property {string[]} [openItems] - 열린 아이템 목록 (Accordion에서 자동 전달) / Open items list (auto-passed from Accordion)\n * @property {(value: string) => void} [onToggle] - 토글 콜백 (Accordion에서 자동 전달) / Toggle callback (auto-passed from Accordion)\n */\ninterface AccordionItemProps {\n value: string\n children: React.ReactNode\n className?: string\n disabled?: boolean\n openItems?: string[]\n onToggle?: (value: string) => void\n}\n\n/**\n * AccordionItem 컴포넌트 / AccordionItem component\n * 아코디언의 개별 아이템을 감싸는 컨테이너입니다.\n * Container that wraps an individual accordion item.\n * \n * @component\n * @param {AccordionItemProps} props - AccordionItem 컴포넌트의 props / AccordionItem component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} AccordionItem 컴포넌트 / AccordionItem component\n */\nconst AccordionItem = React.forwardRef<HTMLDivElement, AccordionItemProps>(\n ({ \n value, \n children, \n className,\n disabled = false,\n openItems = [],\n onToggle,\n ...props \n }, ref) => {\n const isOpen = openItems.includes(value)\n\n return (\n <div\n ref={ref}\n data-accordion-item\n className={merge(\n \"border border-border/50 rounded-lg overflow-hidden\",\n disabled && \"opacity-50 pointer-events-none\",\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n value,\n isOpen,\n disabled,\n onToggle: () => onToggle?.(value),\n 'data-accordion-value': value\n } as Partial<AccordionTriggerProps | AccordionContentProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nAccordionItem.displayName = \"AccordionItem\"\n\ninterface AccordionTriggerProps {\n children: React.ReactNode\n className?: string\n icon?: React.ReactNode\n iconPosition?: \"left\" | \"right\"\n value?: string // Optional: AccordionItem에서 자동으로 전달됨 / Optional: Auto-passed from AccordionItem\n isOpen?: boolean\n disabled?: boolean\n onToggle?: () => void\n}\n\nconst AccordionTrigger = React.forwardRef<HTMLButtonElement, AccordionTriggerProps>(\n ({ \n children, \n className,\n icon,\n iconPosition = \"right\",\n value,\n isOpen = false,\n disabled = false,\n onToggle,\n ...props \n }, ref) => {\n const defaultIcon = (\n <Icon \n name=\"chevronDown\" \n size={20} \n className={merge(\n \"transition-transform duration-300 ease-out text-muted-foreground\",\n isOpen && \"rotate-180\"\n )} \n />\n )\n\n const contentId = `accordion-content-${value}`\n const triggerId = `accordion-trigger-${value}`\n\n return (\n <button\n ref={ref}\n id={triggerId}\n data-accordion-trigger\n data-accordion-value={value}\n aria-expanded={isOpen}\n aria-controls={contentId}\n onClick={onToggle}\n disabled={disabled}\n className={merge(\n \"flex w-full items-center justify-between px-6 py-4 text-left font-medium transition-all hover:bg-muted/80 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n className\n )}\n {...props}\n >\n <div className=\"flex items-center gap-3 flex-1\">\n {iconPosition === \"left\" && (icon || defaultIcon)}\n <span className=\"flex-1\">{children}</span>\n </div>\n {iconPosition === \"right\" && (icon || defaultIcon)}\n </button>\n )\n }\n)\nAccordionTrigger.displayName = \"AccordionTrigger\"\n\n/**\n * AccordionTrigger 컴포넌트 / AccordionTrigger component\n * 아코디언 아이템을 열고 닫는 트리거 버튼입니다.\n * Button that opens and closes an accordion item.\n * \n * @component\n * @param {AccordionTriggerProps} props - AccordionTrigger 컴포넌트의 props / AccordionTrigger component props\n * @param {React.Ref<HTMLButtonElement>} ref - button 요소 ref / button element ref\n * @returns {JSX.Element} AccordionTrigger 컴포넌트 / AccordionTrigger component\n */\n\n/**\n * AccordionContent 컴포넌트의 props\n * @typedef {Object} AccordionContentProps\n * @property {React.ReactNode} children - 콘텐츠\n * @property {string} [className] - 추가 CSS 클래스\n * @property {boolean} [isOpen] - 열림 상태 (AccordionItem에서 자동 전달)\n * @property {string} [value] - 아이템 값 (AccordionItem에서 자동 전달)\n * @property {string} ['data-accordion-value'] - 아이템 값 (내부 사용)\n */\ninterface AccordionContentProps {\n children: React.ReactNode\n className?: string\n isOpen?: boolean\n value?: string\n 'data-accordion-value'?: string\n}\n\n/**\n * AccordionContent 컴포넌트 / AccordionContent component\n * 아코디언 아이템의 콘텐츠를 표시합니다.\n * Displays the content of an accordion item.\n * \n * @component\n * @param {AccordionContentProps} props - AccordionContent 컴포넌트의 props / AccordionContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} AccordionContent 컴포넌트 / AccordionContent component\n */\nconst AccordionContent = React.forwardRef<HTMLDivElement, AccordionContentProps>(\n ({ children, className, isOpen = false, value, 'data-accordion-value': dataValue, ...props }, ref) => {\n const [height, setHeight] = React.useState(0)\n const contentRef = React.useRef<HTMLDivElement>(null)\n const itemValue = value || dataValue || 'unknown'\n\n React.useEffect(() => {\n if (contentRef.current) {\n if (isOpen) {\n setHeight(contentRef.current.scrollHeight)\n } else {\n setHeight(0)\n }\n }\n }, [isOpen, children])\n\n const triggerId = `accordion-trigger-${itemValue}`\n const contentId = `accordion-content-${itemValue}`\n\n return (\n <div\n ref={ref}\n id={contentId}\n role=\"region\"\n aria-labelledby={triggerId}\n hidden={!isOpen}\n className=\"overflow-hidden transition-all duration-300 ease-out\"\n style={{ height: `${height}px` }}\n {...props}\n >\n <div\n ref={contentRef}\n className={merge(\"px-6 pt-2 pb-4\", className)}\n >\n {children}\n </div>\n </div>\n )\n }\n)\nAccordionContent.displayName = \"AccordionContent\"\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } ","\"use client\"\n\nimport React from 'react'\nimport { merge } from '../lib/utils'\n\n/**\n * TabsContent 컴포넌트의 props / TabsContent component props\n * @typedef {Object} TabsContentProps\n * @property {string} value - 탭 패널의 고유 값 (TabsTrigger의 value와 일치해야 함) / Unique value for tab panel (must match TabsTrigger value)\n * @property {boolean} [active] - 탭 패널 활성화 상태 (자동 설정됨) / Tab panel active state (auto-set)\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {\n value: string\n active?: boolean\n}\n\n/**\n * TabsContent 컴포넌트 / TabsContent component\n * 탭의 콘텐츠 패널을 표시합니다. Tabs 컴포넌트 내부에서 사용됩니다.\n * Displays the tab content panel. Used inside Tabs component.\n * \n * @component\n * @param {TabsContentProps} props - TabsContent 컴포넌트의 props / TabsContent component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} TabsContent 컴포넌트 / TabsContent component\n */\nconst TabsContent = React.forwardRef<HTMLDivElement, TabsContentProps>(\n ({ className, value, active, children, ...props }, ref) => {\n // active prop이 명시적으로 false로 설정된 경우에만 숨김\n if (active === false) return null\n\n return (\n <div\n ref={ref}\n role=\"tabpanel\"\n id={`tabpanel-${value}`}\n aria-labelledby={`tab-${value}`}\n hidden={!active}\n className={merge(\n \"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2\",\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nTabsContent.displayName = \"TabsContent\"\n\n/**\n * Tabs 컴포넌트의 props / Tabs component props\n * @typedef {Object} TabsProps\n * @property {string} [value] - 현재 활성화된 탭 값 (제어 컴포넌트) / Currently active tab value (controlled component)\n * @property {string} [defaultValue] - 초기 활성화된 탭 값 (비제어 컴포넌트) / Initial active tab value (uncontrolled component)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 시 호출되는 콜백 / Callback when tab changes\n * @property {\"horizontal\" | \"vertical\"} [orientation=\"horizontal\"] - 탭 방향 / Tab orientation\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant=\"default\"] - 탭 스타일 변형 / Tab style variant\n * @property {\"sm\" | \"md\" | \"lg\"} [size=\"md\"] - 탭 크기 / Tab size\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n}\n\n/**\n * Tabs 컴포넌트 / Tabs component\n * \n * 탭 네비게이션을 제공하는 컴포넌트입니다.\n * 키보드 네비게이션(Arrow keys, Home/End)을 지원하며, ARIA 속성을 자동으로 설정합니다.\n * \n * Component that provides tab navigation.\n * Supports keyboard navigation (Arrow keys, Home/End) and automatically sets ARIA attributes.\n * \n * @component\n * @example\n * // 기본 사용 / Basic usage\n * <Tabs defaultValue=\"tab1\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">탭 1</TabsTrigger>\n * <TabsTrigger value=\"tab2\">탭 2</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">탭 1 내용</TabsContent>\n * <TabsContent value=\"tab2\">탭 2 내용</TabsContent>\n * </Tabs>\n * \n * @example\n * // 제어 컴포넌트 / Controlled component\n * const [activeTab, setActiveTab] = useState(\"tab1\")\n * <Tabs value={activeTab} onValueChange={setActiveTab}>\n * <TabsList>\n * <TabsTrigger value=\"tab1\">탭 1</TabsTrigger>\n * </TabsList>\n * <TabsContent value=\"tab1\">내용</TabsContent>\n * </Tabs>\n * \n * @example\n * // 다양한 변형 / Various variants\n * <Tabs variant=\"pills\" size=\"lg\">\n * <TabsList>\n * <TabsTrigger value=\"tab1\">Pills 스타일</TabsTrigger>\n * </TabsList>\n * </Tabs>\n * \n * @param {TabsProps} props - Tabs 컴포넌트의 props / Tabs component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} Tabs 컴포넌트 / Tabs component\n */\nconst Tabs = React.forwardRef<HTMLDivElement, TabsProps>(\n ({ \n className, \n value,\n defaultValue,\n onValueChange,\n orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n children,\n ...props \n }, ref) => {\n const [activeTab, setActiveTab] = React.useState(value || defaultValue || \"\")\n const isControlled = value !== undefined\n const currentValue = isControlled ? value : activeTab\n\n const handleTabChange = (newValue: string) => {\n if (!isControlled) {\n setActiveTab(newValue)\n }\n onValueChange?.(newValue)\n }\n\n React.useEffect(() => {\n if (value !== undefined) {\n setActiveTab(value)\n }\n }, [value])\n\n return (\n <div\n ref={ref}\n className={merge(\n \"w-full\",\n orientation === \"vertical\" && \"flex\",\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n // TabsContent인 경우 active prop만 설정 (value는 원래 값 유지)\n if (child.type === TabsContent) {\n const childProps = child.props as TabsContentProps\n return React.cloneElement(child, {\n active: childProps.value === currentValue\n } as Partial<TabsContentProps>)\n }\n // TabsList인 경우에만 onValueChange 전달\n if (child.type === TabsList) {\n return React.cloneElement(child, {\n value: currentValue,\n onValueChange: handleTabChange,\n orientation,\n variant,\n size\n } as Partial<TabsListProps>)\n }\n // 다른 React 컴포넌트들 (다른 custom wrapper 등)\n // HTML 요소가 아닌 경우에만 props 전달\n if (typeof child.type !== 'string') {\n return React.cloneElement(child, {\n value: currentValue,\n onValueChange: handleTabChange,\n orientation,\n variant,\n size\n } as Record<string, unknown>)\n }\n }\n return child\n })}\n </div>\n )\n }\n)\nTabs.displayName = \"Tabs\"\n\n/**\n * TabsList 컴포넌트의 props / TabsList component props\n * @typedef {Object} TabsListProps\n * @property {string} [value] - 현재 활성화된 탭 값 (Tabs에서 자동 전달) / Currently active tab value (auto-passed from Tabs)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 콜백 (Tabs에서 자동 전달) / Tab change callback (auto-passed from Tabs)\n * @property {\"horizontal\" | \"vertical\"} [orientation] - 탭 방향 (Tabs에서 자동 전달) / Tab orientation (auto-passed from Tabs)\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant] - 탭 스타일 (Tabs에서 자동 전달) / Tab style (auto-passed from Tabs)\n * @property {\"sm\" | \"md\" | \"lg\"} [size] - 탭 크기 (Tabs에서 자동 전달) / Tab size (auto-passed from Tabs)\n * @extends {React.HTMLAttributes<HTMLDivElement>}\n */\nexport interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n}\n\n/**\n * TabsList 컴포넌트 / TabsList component\n * 탭 트리거 목록을 표시합니다. Tabs 컴포넌트 내부에서 사용됩니다.\n * Displays the list of tab triggers. Used inside Tabs component.\n * \n * @component\n * @param {TabsListProps} props - TabsList 컴포넌트의 props / TabsList component props\n * @param {React.Ref<HTMLDivElement>} ref - div 요소 ref / div element ref\n * @returns {JSX.Element} TabsList 컴포넌트 / TabsList component\n */\nconst TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(\n ({ \n className, \n value,\n onValueChange,\n orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n children,\n ...props \n }, ref) => {\n const listRef = React.useRef<HTMLDivElement>(null)\n React.useImperativeHandle(ref, () => listRef.current as HTMLDivElement)\n \n // 모든 탭 트리거의 value를 수집\n const tabValues = React.useMemo(() => {\n const values: string[] = []\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child)) {\n const childProps = child.props as { value?: string }\n if (childProps.value) {\n values.push(childProps.value)\n }\n }\n })\n return values\n }, [children])\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!value || tabValues.length === 0) return\n\n const currentIndex = tabValues.indexOf(value)\n if (currentIndex === -1) return\n\n let newIndex = currentIndex\n\n if (orientation === \"horizontal\") {\n if (e.key === \"ArrowLeft\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : tabValues.length - 1\n } else if (e.key === \"ArrowRight\") {\n e.preventDefault()\n newIndex = currentIndex < tabValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = tabValues.length - 1\n }\n } else {\n if (e.key === \"ArrowUp\") {\n e.preventDefault()\n newIndex = currentIndex > 0 ? currentIndex - 1 : tabValues.length - 1\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault()\n newIndex = currentIndex < tabValues.length - 1 ? currentIndex + 1 : 0\n } else if (e.key === \"Home\") {\n e.preventDefault()\n newIndex = 0\n } else if (e.key === \"End\") {\n e.preventDefault()\n newIndex = tabValues.length - 1\n }\n }\n\n if (newIndex !== currentIndex && tabValues[newIndex]) {\n onValueChange?.(tabValues[newIndex])\n // 포커스 이동\n const triggerElement = listRef.current?.querySelector(\n `[data-tab-value=\"${tabValues[newIndex]}\"]`\n ) as HTMLElement\n triggerElement?.focus()\n }\n }\n const getVariantClasses = () => {\n switch (variant) {\n case \"pills\":\n return \"bg-muted p-3 rounded-xl border border-border/50\"\n case \"underline\":\n return \"border-b border-border\"\n case \"cards\":\n return \"bg-muted/80 p-3 rounded-xl border border-border/50\"\n default:\n return \"bg-muted p-3 rounded-xl border border-border/50\"\n }\n }\n\n const getSizeClasses = () => {\n switch (size) {\n case \"sm\":\n return \"h-12\"\n case \"lg\":\n return \"h-16\"\n default:\n return \"h-14\"\n }\n }\n\n return (\n <div\n ref={listRef}\n role=\"tablist\"\n aria-orientation={orientation}\n onKeyDown={handleKeyDown}\n className={merge(\n \"flex items-center justify-center\",\n orientation === \"vertical\" && \"flex-col\",\n getVariantClasses(),\n getSizeClasses(),\n className\n )}\n {...props}\n >\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n // Only pass tab props to non-HTML elements (React components)\n if (typeof child.type === 'string') {\n return child\n }\n const childProps = child.props as { value?: string }\n return React.cloneElement(child, {\n onValueChange,\n orientation,\n variant,\n size,\n active: childProps.value === value\n } as Partial<TabsTriggerProps>)\n }\n return child\n })}\n </div>\n )\n }\n)\nTabsList.displayName = \"TabsList\"\n\n/**\n * TabsTrigger 컴포넌트의 props\n * @typedef {Object} TabsTriggerProps\n * @property {string} value - 탭 트리거의 고유 값 (TabsContent의 value와 일치해야 함)\n * @property {(value: string) => void} [onValueChange] - 탭 변경 콜백 (TabsList에서 자동 전달)\n * @property {\"horizontal\" | \"vertical\"} [orientation] - 탭 방향 (TabsList에서 자동 전달)\n * @property {\"default\" | \"pills\" | \"underline\" | \"cards\"} [variant] - 탭 스타일 (TabsList에서 자동 전달)\n * @property {\"sm\" | \"md\" | \"lg\"} [size] - 탭 크기 (TabsList에서 자동 전달)\n * @property {boolean} [active] - 탭 활성화 상태 (자동 설정됨)\n * @extends {React.ButtonHTMLAttributes<HTMLButtonElement>}\n */\nexport interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n value: string\n onValueChange?: (value: string) => void\n orientation?: \"horizontal\" | \"vertical\"\n variant?: \"default\" | \"pills\" | \"underline\" | \"cards\"\n size?: \"sm\" | \"md\" | \"lg\"\n active?: boolean\n}\n\n/**\n * TabsTrigger 컴포넌트 / TabsTrigger component\n * 탭을 활성화하는 버튼입니다. TabsList 컴포넌트 내부에서 사용됩니다.\n * Button that activates a tab. Used inside TabsList component.\n * \n * @component\n * @param {TabsTriggerProps} props - TabsTrigger 컴포넌트의 props / TabsTrigger component props\n * @param {React.Ref<HTMLButtonElement>} ref - button 요소 ref / button element ref\n * @returns {JSX.Element} TabsTrigger 컴포넌트 / TabsTrigger component\n */\nconst TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(\n ({ \n className,\n value,\n onValueChange,\n orientation: _orientation = \"horizontal\",\n variant = \"default\",\n size = \"md\",\n active = false,\n children,\n ...props\n }, ref) => {\n const getVariantClasses = () => {\n switch (variant) {\n case \"pills\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n case \"underline\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap border-b-2 px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"border-primary text-primary\"\n : \"border-transparent text-muted-foreground hover:text-foreground\"\n )\n case \"cards\":\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n default:\n return merge(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2.5 text-sm font-medium ring-offset-background transition-all duration-200 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n active\n ? \"bg-background text-foreground shadow-md\"\n : \"text-muted-foreground hover:text-foreground hover:bg-muted\"\n )\n }\n }\n\n const getSizeClasses = () => {\n switch (size) {\n case \"sm\":\n return \"h-10 px-4 py-2 text-xs\"\n case \"lg\":\n return \"h-14 px-6 py-3 text-base\"\n default:\n return \"h-12 px-5 py-2.5 text-sm\"\n }\n }\n\n const handleClick = () => {\n if (onValueChange) {\n onValueChange(value)\n }\n }\n\n return (\n <button\n ref={ref}\n role=\"tab\"\n aria-selected={active}\n aria-controls={`tabpanel-${value}`}\n id={`tab-${value}`}\n data-tab-value={value}\n tabIndex={active ? 0 : -1}\n className={merge(\n getVariantClasses(),\n getSizeClasses(),\n className\n )}\n onClick={handleClick}\n type=\"button\"\n {...props}\n >\n {children}\n </button>\n )\n }\n)\nTabsTrigger.displayName = \"TabsTrigger\"\n\n// 편의 컴포넌트들\nconst TabsPills = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"pills\" {...props} />\n)\nTabsPills.displayName = \"TabsPills\"\n\nconst TabsUnderline = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"underline\" {...props} />\n)\nTabsUnderline.displayName = \"TabsUnderline\"\n\nconst TabsCards = React.forwardRef<HTMLDivElement, TabsProps>(\n (props, ref) => <Tabs ref={ref} variant=\"cards\" {...props} />\n)\nTabsCards.displayName = \"TabsCards\"\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, TabsPills, TabsUnderline, TabsCards } "]}
|