@j-solution/components 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +23 -22
  2. package/README.md +370 -81
  3. package/UPDATE_GUIDE.md +441 -441
  4. package/USAGE_GUIDE.md +1 -1
  5. package/assets/jwms-portal-frontend-BqyV9oqF.css +1 -0
  6. package/assets/styles/j-components.css +1 -1
  7. package/assets/styles/main.css +29 -0
  8. package/components/atoms/JToast.vue.cjs +2 -0
  9. package/components/atoms/JToast.vue.cjs.map +1 -0
  10. package/components/atoms/JToast.vue.js +37 -0
  11. package/components/atoms/JToast.vue.js.map +1 -0
  12. package/components/atoms/JToast.vue2.cjs +2 -0
  13. package/components/atoms/JToast.vue2.cjs.map +1 -0
  14. package/components/atoms/JToast.vue2.js +5 -0
  15. package/components/atoms/JToast.vue2.js.map +1 -0
  16. package/components/molecules/JAccordion.vue.cjs.map +1 -1
  17. package/components/molecules/JAccordion.vue.js.map +1 -1
  18. package/components/molecules/JButtonGroup.vue.cjs.map +1 -1
  19. package/components/molecules/JButtonGroup.vue.js.map +1 -1
  20. package/components/organisms/JHeader.vue.cjs.map +1 -1
  21. package/components/organisms/JHeader.vue.js.map +1 -1
  22. package/components/organisms/JSearchPanel.vue.cjs +1 -1
  23. package/components/organisms/JSearchPanel.vue.js +2 -2
  24. package/components/organisms/JSearchPanel.vue2.cjs.map +1 -1
  25. package/components/organisms/JSearchPanel.vue2.js.map +1 -1
  26. package/components/shadcn/Toaster.vue.cjs +2 -0
  27. package/components/shadcn/Toaster.vue.cjs.map +1 -0
  28. package/components/shadcn/Toaster.vue.js +36 -0
  29. package/components/shadcn/Toaster.vue.js.map +1 -0
  30. package/components/shadcn/Toaster.vue2.cjs +2 -0
  31. package/components/shadcn/Toaster.vue2.cjs.map +1 -0
  32. package/components/shadcn/Toaster.vue2.js +5 -0
  33. package/components/shadcn/Toaster.vue2.js.map +1 -0
  34. package/components/shadcn/index.cjs +1 -1
  35. package/components/shadcn/index.cjs.map +1 -1
  36. package/components/shadcn/index.js +1 -0
  37. package/components/shadcn/index.js.map +1 -1
  38. package/index.cjs +1 -1
  39. package/index.js +89 -86
  40. package/package.json +2 -1
  41. package/types/index.d.ts +8 -0
  42. package/assets/jwms-portal-frontend-DjoLgoaO.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"JHeader.vue.js","sources":["../../../../src/components/organisms/JHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport JAvatar from '@/components/atoms/JAvatar.vue'\r\nimport JButton from '@/components/atoms/JButton.vue'\r\nimport JPopover from '@/components/atoms/JPopover.vue'\r\nimport { cn } from '@/lib/utils'\r\nimport type { ContextMenuItem, ContextMenuGroup } from '@/types/context-menu.types'\r\nimport {\r\n detectThemeClasses,\r\n ensureDefaultTheme,\r\n validateThemeExists,\r\n getDefaultTheme,\r\n getStoredTheme,\r\n setStoredTheme,\r\n applyTheme,\r\n} from '@/lib/theme-utils'\r\n\r\n// Fallback 로고 이미지 import (logo prop이 없거나 로드 실패 시 사용)\r\nimport logoFallback from '@/assets/images/logo-fallback.png'\r\n\r\n/**\r\n * JHeader - 상단 헤더 컴포넌트 (organisms)\r\n * Header Component\r\n * \r\n * @description\r\n * 애플리케이션의 상단 헤더 영역을 담당하는 컴포넌트입니다.\r\n * 로고, 네비게이션, 검색, 알림, 사용자 메뉴 등을 포함할 수 있습니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JHeader\r\n * logo=\"/logo.png\"\r\n * :user-menu-items=\"userMenuItems\"\r\n * @logo-click=\"handleLogoClick\"\r\n * />\r\n * ```\r\n */\r\n\r\nexport type HeaderNavItem = {\r\n /** 라벨 */\r\n label: string\r\n /** 링크 URL */\r\n href?: string\r\n /** 아이콘 */\r\n icon?: string\r\n /** 활성 상태 */\r\n active?: boolean\r\n /** 클릭 핸들러 */\r\n onClick?: () => void\r\n}\r\n\r\nexport type NotificationItem = {\r\n /** 알림 ID */\r\n id: string\r\n /** 알림 제목 */\r\n title: string\r\n /** 알림 내용 */\r\n message?: string\r\n /** 알림 시간 */\r\n time?: string\r\n /** 읽음 상태 */\r\n read?: boolean\r\n /** 아이콘 */\r\n icon?: string\r\n /** 클릭 핸들러 */\r\n onClick?: () => void\r\n}\r\n\r\ntype StyleType =\r\n | 'default' // 기본 스타일\r\n | 'minimal' // 최소 스타일\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 로고 이미지 URL */\r\n logo?: string\r\n /** 로고 텍스트 (기본값, 이미지가 없을 때) */\r\n logoText?: string\r\n /** 네비게이션 아이템 목록 */\r\n navItems?: HeaderNavItem[]\r\n /** 알림 표시 여부 */\r\n showNotifications?: boolean\r\n /** 알림 목록 */\r\n notifications?: NotificationItem[]\r\n /** 사용자 아바타 이미지 */\r\n userAvatar?: string\r\n /** 사용자 이름 */\r\n userName?: string\r\n /** 로그인 상태 */\r\n isLoggedIn?: boolean\r\n /** 사용자 이메일 */\r\n userEmail?: string\r\n /** 사용자 ID */\r\n userId?: string\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 사이드바 토글 버튼 표시 여부 */\r\n showSidebarToggle?: boolean\r\n /** 사이드바 열림 상태 */\r\n isSidebarOpen?: boolean\r\n /** 테마 선택기 표시 여부 */\r\n showThemeSelector?: boolean\r\n /** 초기 테마 (기본값: 'default' 또는 저장된 테마) */\r\n defaultTheme?: string\r\n /** 선택 가능한 테마 목록 (지정하지 않으면 모든 감지된 테마 사용) */\r\n availableThemes?: string[]\r\n }>(),\r\n {\r\n logoText: 'JWMS Portal', // 기본값: 텍스트 로고\r\n showNotifications: false,\r\n notifications: () => [],\r\n styletype: 'default',\r\n showSidebarToggle: true,\r\n isSidebarOpen: true,\r\n showThemeSelector: true,\r\n defaultTheme: undefined,\r\n availableThemes: undefined,\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 로고 클릭 이벤트 */\r\n logoClick: []\r\n /** 네비게이션 아이템 클릭 이벤트 */\r\n navClick: [item: HeaderNavItem, index: number]\r\n /** 알림 클릭 이벤트 */\r\n notificationClick: [item: NotificationItem]\r\n /** 사용자 메뉴 아이템 선택 이벤트 */\r\n userMenuSelect: [itemId: string]\r\n /** 사이드바 토글 이벤트 */\r\n sidebarToggle: []\r\n /** 로그인 버튼 클릭 이벤트 */\r\n login: []\r\n}>()\r\n\r\n/**\r\n * 스타일 프리셋\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, {\r\n containerClass: string\r\n navItemClass: string\r\n navItemActiveClass: string\r\n}> = {\r\n default: {\r\n containerClass: 'h-14 px-4 border-b border-border bg-background',\r\n navItemClass: 'text-sm text-muted-foreground hover:text-foreground transition-colors px-3 py-2 rounded-md hover:bg-accent',\r\n navItemActiveClass: 'text-foreground font-medium bg-accent',\r\n },\r\n minimal: {\r\n containerClass: 'h-12 px-3 border-b border-border bg-background',\r\n navItemClass: 'text-xs text-muted-foreground hover:text-foreground transition-colors px-2 py-1 rounded-md hover:bg-accent',\r\n navItemActiveClass: 'text-foreground font-medium bg-accent',\r\n },\r\n}\r\n\r\nconst preset = computed(() => {\r\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\r\n})\r\n\r\n/**\r\n * 로고 이미지 로드 에러 상태\r\n * 0: 에러 없음, 1: 첫 번째 이미지(logo) 에러, 2: fallback 이미지도 에러\r\n */\r\nconst logoImageError = ref(0)\r\n\r\n/**\r\n * 로고 이미지 경로 계산\r\n */\r\nconst logoImageSrc = computed(() => {\r\n // props.logo가 있으면 사용\r\n if (props.logo) {\r\n return props.logo\r\n }\r\n return undefined\r\n})\r\n\r\n/**\r\n * 실제 표시할 로고 이미지 경로\r\n * 1. props.logo가 있으면 사용\r\n * 2. logo 에러 시 fallback 이미지\r\n * 3. fallback도 에러면 undefined (텍스트로 대체)\r\n */\r\nconst displayLogoImage = computed(() => {\r\n // logo prop이 없으면 이미지 표시 안함 (텍스트 사용)\r\n if (!props.logo) {\r\n return undefined\r\n }\r\n \r\n // logo 에러가 발생했으면 fallback 사용\r\n if (logoImageError.value >= 1 && logoFallback) {\r\n return logoFallback\r\n }\r\n \r\n // 정상적으로 logo 사용\r\n return logoImageSrc.value\r\n})\r\n\r\n/**\r\n * 로고 이미지 로드 에러 핸들러\r\n */\r\nconst handleLogoError = () => {\r\n // 첫 번째 이미지(logo) 에러\r\n if (logoImageError.value === 0) {\r\n logoImageError.value = 1\r\n }\r\n // fallback 이미지도 에러면 2로 설정 (텍스트로 대체)\r\n else if (logoImageError.value === 1) {\r\n logoImageError.value = 2\r\n }\r\n}\r\n\r\n/**\r\n * 읽지 않은 알림 개수\r\n */\r\nconst unreadCount = computed(() => {\r\n return props.notifications?.filter(n => !n.read).length || 0\r\n})\r\n\r\n/**\r\n * 고정 사용자 메뉴 아이템\r\n */\r\nconst fixedUserMenuItems: ContextMenuItem[] = [\r\n { id: 'profile', label: '프로필', icon: 'user' },\r\n { id: 'settings', label: '설정', icon: 'settings' },\r\n { id: 'separator', label: '', separator: true },\r\n { id: 'logout', label: '로그아웃', icon: 'logOut' },\r\n]\r\n\r\n/**\r\n * 사용자 메뉴 아이템을 ContextMenuGroup 형식으로 변환\r\n */\r\nconst userMenuGroups = computed<ContextMenuGroup[]>(() => {\r\n return [{\r\n items: fixedUserMenuItems\r\n }]\r\n})\r\n\r\n/**\r\n * 로고 클릭 핸들러\r\n */\r\nconst handleLogoClick = () => {\r\n emit('logoClick')\r\n}\r\n\r\n/**\r\n * 네비게이션 아이템 클릭 핸들러\r\n */\r\nconst handleNavClick = (item: HeaderNavItem, index: number) => {\r\n item.onClick?.()\r\n emit('navClick', item, index)\r\n}\r\n\r\n/**\r\n * 알림 클릭 핸들러\r\n */\r\nconst handleNotificationClick = (item: NotificationItem) => {\r\n item.onClick?.()\r\n emit('notificationClick', item)\r\n}\r\n\r\n/**\r\n * 사용자 메뉴 선택 핸들러\r\n */\r\nconst handleUserMenuSelect = (itemId: string) => {\r\n emit('userMenuSelect', itemId)\r\n}\r\n\r\n/**\r\n * 로그인 버튼 클릭 핸들러\r\n */\r\nconst handleLogin = () => {\r\n emit('login')\r\n}\r\n\r\n/**\r\n * 사이드바 토글 핸들러\r\n */\r\nconst handleSidebarToggle = () => {\r\n emit('sidebarToggle')\r\n}\r\n\r\n/**\r\n * tweakcn 테마 타입 정의 (동적 감지 지원)\r\n */\r\ntype ThemeName = string\r\n\r\n/**\r\n * 다크모드 상태를 추적하는 반응형 변수\r\n * - false: 라이트 모드\r\n * - true: 다크 모드\r\n * 초기값은 false(라이트 모드)이며, 컴포넌트 마운트 시 실제 테마로 업데이트됩니다.\r\n */\r\nconst isDarkMode = ref(false)\r\n\r\n/**\r\n * 현재 선택된 tweakcn 테마 (디폴트 테마로 초기화)\r\n */\r\nconst currentTheme = ref<ThemeName>(getDefaultTheme())\r\n\r\n/**\r\n * 테마 옵션 목록 (동적으로 감지)\r\n */\r\nconst themeOptions = ref<ThemeName[]>([])\r\n\r\n/**\r\n * 내부 업데이트 플래그\r\n * - true: 컴포넌트 내부에서 테마를 변경 중 (MutationObserver가 무시해야 함)\r\n * - false: 외부에서 테마가 변경됨 (MutationObserver가 동기화해야 함)\r\n */\r\nlet isInternalUpdate = false\r\n\r\n/**\r\n * MutationObserver 인스턴스\r\n */\r\nlet themeObserver: MutationObserver | null = null\r\nlet styleObserver: MutationObserver | null = null\r\n\r\n/**\r\n * Storybook 환경인지 확인하는 함수\r\n * \r\n * @returns Storybook 환경이면 true, 아니면 false\r\n */\r\nconst isStorybook = (): boolean => {\r\n if (typeof window === 'undefined') return false\r\n return !!(\r\n window.location?.href?.includes('storybook') ||\r\n (window as any).__STORYBOOK_GLOBALS__\r\n )\r\n}\r\n\r\n/**\r\n * 테마 목록을 동적으로 감지하고 업데이트합니다.\r\n */\r\nconst updateThemeOptions = () => {\r\n const detectedThemes = detectThemeClasses()\r\n const ensuredThemes = ensureDefaultTheme(detectedThemes)\r\n \r\n // availableThemes prop이 지정되면 필터링\r\n if (props.availableThemes && props.availableThemes.length > 0) {\r\n const filtered = ensuredThemes.filter(theme => props.availableThemes!.includes(theme))\r\n // default는 항상 포함\r\n themeOptions.value = ensureDefaultTheme(filtered)\r\n } else {\r\n themeOptions.value = ensuredThemes\r\n }\r\n}\r\n\r\n/**\r\n * localStorage에서 저장된 다크모드 테마를 읽어오는 함수\r\n * \r\n * 우선순위:\r\n * 1. localStorage에 저장된 'theme' 값 (사용자가 이전에 선택한 테마)\r\n * 2. 시스템 설정 (OS의 다크모드 설정)\r\n * 3. 기본값 'light' (라이트 모드)\r\n * \r\n * @returns 'light' | 'dark' - 적용할 테마\r\n */\r\nconst getStoredDarkModeTheme = (): 'light' | 'dark' => {\r\n if (typeof window === 'undefined') return 'light'\r\n \r\n const stored = localStorage.getItem('theme')\r\n if (stored === 'dark' || stored === 'light') {\r\n return stored\r\n }\r\n \r\n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {\r\n return 'dark'\r\n }\r\n \r\n return 'light'\r\n}\r\n\r\n/**\r\n * 다크모드 테마를 HTML 문서에 적용하는 함수\r\n * \r\n * @param theme - 적용할 테마 ('light' 또는 'dark')\r\n */\r\nconst applyDarkModeTheme = (theme: 'light' | 'dark') => {\r\n isInternalUpdate = true\r\n \r\n const root = document.documentElement\r\n \r\n if (theme === 'dark') {\r\n root.classList.add('dark')\r\n isDarkMode.value = true\r\n } else {\r\n root.classList.remove('dark')\r\n isDarkMode.value = false\r\n }\r\n \r\n localStorage.setItem('theme', theme)\r\n \r\n isInternalUpdate = false\r\n}\r\n\r\n/**\r\n * 테마 토글 버튼 클릭 시 호출되는 핸들러 함수\r\n */\r\nconst handleThemeToggle = () => {\r\n const newTheme = isDarkMode.value ? 'light' : 'dark'\r\n applyDarkModeTheme(newTheme)\r\n}\r\n\r\n/**\r\n * 저장된 tweakcn 테마를 가져와서 적용합니다.\r\n */\r\nconst getStoredTweakcnTheme = (): ThemeName => {\r\n // defaultTheme prop이 지정되면 우선 사용\r\n if (props.defaultTheme) {\r\n const validated = validateThemeExists(props.defaultTheme)\r\n return validated\r\n }\r\n \r\n const stored = getStoredTheme('tweakcn-theme')\r\n if (!stored) {\r\n return getDefaultTheme()\r\n }\r\n \r\n // 저장된 테마가 유효한지 검증\r\n const validated = validateThemeExists(stored)\r\n return validated\r\n}\r\n\r\n/**\r\n * tweakcn 테마를 HTML 문서에 적용하는 함수\r\n */\r\nconst applyTweakcnTheme = (theme: ThemeName): boolean => {\r\n isInternalUpdate = true\r\n \r\n const validatedTheme = validateThemeExists(theme)\r\n const success = applyTheme(validatedTheme)\r\n \r\n if (success) {\r\n currentTheme.value = validatedTheme\r\n setStoredTheme(validatedTheme, 'tweakcn-theme')\r\n \r\n // 스토리북 환경에서만 전역 상태 동기화\r\n if (isStorybook()) {\r\n try {\r\n const storybookGlobals = (window as any).__STORYBOOK_GLOBALS__\r\n if (storybookGlobals) {\r\n storybookGlobals.theme = validatedTheme\r\n }\r\n } catch (e) {\r\n // 무시\r\n }\r\n }\r\n } else {\r\n // 실패 시 디폴트 테마로 폴백\r\n const defaultTheme = getDefaultTheme()\r\n applyTheme(defaultTheme)\r\n currentTheme.value = defaultTheme\r\n setStoredTheme(defaultTheme, 'tweakcn-theme')\r\n }\r\n \r\n isInternalUpdate = false\r\n return success\r\n}\r\n\r\n/**\r\n * 테마 변경 핸들러\r\n */\r\nconst handleThemeChange = (theme: ThemeName | string | number) => {\r\n applyTweakcnTheme(String(theme))\r\n}\r\n\r\n/**\r\n * 현재 테마에 따라 표시할 아이콘을 계산하는 computed 속성\r\n */\r\nconst themeIcon = computed(() => {\r\n return isDarkMode.value ? 'sun' : 'moon'\r\n})\r\n\r\n/**\r\n * 초기화: 저장된 테마 적용 및 테마 목록 감지\r\n */\r\nonMounted(() => {\r\n // 테마 목록 초기 감지\r\n updateThemeOptions()\r\n \r\n // 저장된 다크모드 테마 적용\r\n const darkModeTheme = getStoredDarkModeTheme()\r\n applyDarkModeTheme(darkModeTheme)\r\n \r\n // 저장된 tweakcn 테마 적용\r\n const storedTheme = getStoredTweakcnTheme()\r\n applyTweakcnTheme(storedTheme)\r\n \r\n // HTML의 dark 클래스 변경을 감지하여 헤더 컴포넌트 상태를 동기화\r\n const root = document.documentElement\r\n \r\n // 현재 dark 클래스 상태로 초기화\r\n isDarkMode.value = root.classList.contains('dark')\r\n \r\n // MutationObserver로 동적 테마 클래스 감지\r\n themeObserver = new MutationObserver(() => {\r\n if (isInternalUpdate) return\r\n \r\n // 다크모드 클래스 변경 감지\r\n const hasDarkClass = root.classList.contains('dark')\r\n if (hasDarkClass !== isDarkMode.value) {\r\n isDarkMode.value = hasDarkClass\r\n localStorage.setItem('theme', hasDarkClass ? 'dark' : 'light')\r\n }\r\n \r\n // 테마 목록 업데이트\r\n updateThemeOptions()\r\n \r\n // 현재 적용된 tweakcn 테마 확인\r\n const currentThemeClass = Array.from(root.classList).find(cls => cls.startsWith('theme-'))\r\n if (currentThemeClass) {\r\n const themeName = currentThemeClass.replace('theme-', '')\r\n if (themeOptions.value.includes(themeName)) {\r\n currentTheme.value = themeName\r\n }\r\n }\r\n })\r\n \r\n // document.documentElement의 클래스 변경 감지\r\n themeObserver.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class'],\r\n })\r\n \r\n // 스타일시트 변경 감지 (동적으로 추가된 테마 감지)\r\n styleObserver = new MutationObserver(() => {\r\n updateThemeOptions()\r\n })\r\n \r\n styleObserver.observe(document.head, {\r\n childList: true,\r\n subtree: true,\r\n })\r\n \r\n // 스토리북 환경에서만 다크모드 및 테마 변경 감지 (추가 보완)\r\n let intervalId: ReturnType<typeof setInterval> | null = null\r\n \r\n if (isStorybook()) {\r\n const checkStorybookGlobals = () => {\r\n try {\r\n const storybookGlobals = (window as any).__STORYBOOK_GLOBALS__\r\n if (storybookGlobals) {\r\n // 다크모드 동기화\r\n if (typeof storybookGlobals.darkMode !== 'undefined') {\r\n const storybookDarkMode = storybookGlobals.darkMode\r\n if (storybookDarkMode !== isDarkMode.value) {\r\n applyDarkModeTheme(storybookDarkMode ? 'dark' : 'light')\r\n }\r\n }\r\n \r\n // tweakcn 테마 동기화\r\n if (storybookGlobals.theme && storybookGlobals.theme !== currentTheme.value) {\r\n const storybookTheme = String(storybookGlobals.theme)\r\n if (themeOptions.value.includes(storybookTheme)) {\r\n applyTweakcnTheme(storybookTheme)\r\n }\r\n }\r\n }\r\n } catch (e) {\r\n // 무시\r\n }\r\n }\r\n \r\n // 초기 확인\r\n checkStorybookGlobals()\r\n \r\n // 주기적으로 확인 (스토리북이 직접 이벤트를 제공하지 않는 경우)\r\n intervalId = setInterval(checkStorybookGlobals, 500)\r\n }\r\n \r\n // 컴포넌트 언마운트 시 정리\r\n onUnmounted(() => {\r\n if (themeObserver) {\r\n themeObserver.disconnect()\r\n themeObserver = null\r\n }\r\n if (styleObserver) {\r\n styleObserver.disconnect()\r\n styleObserver = null\r\n }\r\n if (intervalId) {\r\n clearInterval(intervalId)\r\n }\r\n })\r\n})\r\n</script>\r\n\r\n<template>\r\n <header :class=\"cn('flex items-center justify-between w-full', preset.containerClass)\">\r\n <!-- 왼쪽: 햄버거 메뉴 + 로고 + 네비게이션 -->\r\n <div class=\"flex items-center gap-6 flex-1\">\r\n <!-- 햄버거 메뉴 버튼 (사이드바 토글) -->\r\n <JButton\r\n v-if=\"showSidebarToggle\"\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"flex-shrink-0\"\r\n aria-label=\"사이드바 토글\"\r\n @click=\"handleSidebarToggle\"\r\n >\r\n <JIcon name=\"menu\" size=\"md\" />\r\n </JButton>\r\n\r\n <!-- 로고 -->\r\n <div\r\n v-if=\"displayLogoImage || logoText\"\r\n class=\"flex items-center cursor-pointer\"\r\n @click=\"handleLogoClick\"\r\n >\r\n <!-- 로고 이미지 (logo prop이 있고 에러가 2 미만일 때) -->\r\n <img\r\n v-if=\"displayLogoImage && logoImageError < 2\"\r\n :src=\"displayLogoImage\"\r\n alt=\"로고\"\r\n class=\"h-8 w-auto\"\r\n @error=\"handleLogoError\"\r\n />\r\n <!-- 로고 텍스트 (기본 또는 모든 이미지 실패 시) -->\r\n <span\r\n v-else-if=\"logoText\"\r\n class=\"text-lg font-bold text-foreground\"\r\n >\r\n {{ logoText }}\r\n </span>\r\n </div>\r\n\r\n <!-- 네비게이션 -->\r\n <nav\r\n v-if=\"navItems && navItems.length > 0\"\r\n class=\"flex items-center gap-1\"\r\n >\r\n <JButton\r\n v-for=\"(item, index) in navItems\"\r\n :key=\"index\"\r\n variant=\"ghost\"\r\n :class=\"cn(\r\n preset.navItemClass,\r\n item.active && preset.navItemActiveClass\r\n )\"\r\n @click=\"handleNavClick(item, index)\"\r\n >\r\n <JIcon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n size=\"sm\"\r\n class=\"mr-1.5\"\r\n />\r\n {{ item.label }}\r\n </JButton>\r\n </nav>\r\n </div>\r\n\r\n <!-- 오른쪽: 테마 선택기 + 알림 + 다크모드 토글 + 사용자 메뉴 -->\r\n <div class=\"flex items-center gap-3\">\r\n <!-- tweakcn 테마 선택기 -->\r\n <JPopover\r\n v-if=\"showThemeSelector\"\r\n position=\"bottom\"\r\n align=\"end\"\r\n styletype=\"default-sm\"\r\n >\r\n <template #trigger>\r\n <JButton\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n aria-label=\"테마 선택\"\r\n >\r\n <JIcon name=\"palette\" size=\"md\" />\r\n </JButton>\r\n </template>\r\n <div class=\"p-2 min-w-[200px]\">\r\n <div class=\"text-xs font-medium text-muted-foreground px-2 py-1.5 mb-1\">\r\n 테마 선택\r\n </div>\r\n <div class=\"space-y-1\">\r\n <button\r\n v-for=\"theme in themeOptions\"\r\n :key=\"theme\"\r\n :class=\"cn(\r\n 'w-full flex items-center gap-2 px-2 py-1.5 text-sm rounded-md transition-colors',\r\n 'hover:bg-accent hover:text-accent-foreground',\r\n 'border-0 outline-none text-left',\r\n currentTheme === theme && 'bg-accent text-accent-foreground font-medium'\r\n )\"\r\n @click=\"handleThemeChange(theme)\"\r\n >\r\n <JIcon\r\n v-if=\"currentTheme === theme\"\r\n name=\"check\"\r\n size=\"sm\"\r\n class=\"flex-shrink-0\"\r\n />\r\n <span v-else class=\"w-4\" />\r\n <span class=\"flex-1 capitalize\">{{ theme }}</span>\r\n </button>\r\n </div>\r\n </div>\r\n </JPopover>\r\n\r\n <!-- 알림 -->\r\n <JPopover\r\n v-if=\"showNotifications\"\r\n position=\"bottom\"\r\n align=\"end\"\r\n styletype=\"default-sm\"\r\n >\r\n <template #trigger>\r\n <JButton\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n class=\"relative\"\r\n aria-label=\"알림\"\r\n >\r\n <JIcon name=\"circleAlert\" size=\"md\" />\r\n <span\r\n v-if=\"unreadCount > 0\"\r\n class=\"absolute top-0 right-0 h-4 w-4 rounded-full bg-destructive text-destructive-foreground text-xs flex items-center justify-center\"\r\n >\r\n {{ unreadCount > 9 ? '9+' : unreadCount }}\r\n </span>\r\n </JButton>\r\n </template>\r\n <div class=\"p-2\">\r\n <div\r\n v-if=\"notifications && notifications.length > 0\"\r\n class=\"max-h-96 overflow-y-auto space-y-1\"\r\n >\r\n <div\r\n v-for=\"notification in notifications\"\r\n :key=\"notification.id\"\r\n :class=\"cn(\r\n 'p-3 rounded-md cursor-pointer transition-colors',\r\n !notification.read ? 'bg-accent' : 'hover:bg-accent/50'\r\n )\"\r\n @click=\"handleNotificationClick(notification)\"\r\n >\r\n <div class=\"flex items-start gap-2\">\r\n <JIcon\r\n v-if=\"notification.icon\"\r\n :name=\"notification.icon\"\r\n size=\"sm\"\r\n class=\"mt-0.5 flex-shrink-0\"\r\n />\r\n <div class=\"flex-1 min-w-0\">\r\n <p class=\"text-sm font-medium text-foreground\">\r\n {{ notification.title }}\r\n </p>\r\n <p\r\n v-if=\"notification.message\"\r\n class=\"text-xs text-muted-foreground mt-1\"\r\n >\r\n {{ notification.message }}\r\n </p>\r\n <p\r\n v-if=\"notification.time\"\r\n class=\"text-xs text-muted-foreground/60 mt-1\"\r\n >\r\n {{ notification.time }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div\r\n v-else\r\n class=\"p-4 text-center text-sm text-muted-foreground\"\r\n >\r\n 알림이 없습니다.\r\n </div>\r\n </div>\r\n </JPopover>\r\n\r\n <!-- 다크모드 토글 버튼 -->\r\n <JButton\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n :aria-label=\"isDarkMode ? '라이트 모드로 전환' : '다크 모드로 전환'\"\r\n @click=\"handleThemeToggle\"\r\n >\r\n <JIcon :name=\"themeIcon\" size=\"md\" />\r\n </JButton>\r\n\r\n <!-- 사용자 메뉴 (userName이 있으면 표시) -->\r\n <JPopover\r\n v-if=\"userName\"\r\n position=\"bottom\"\r\n align=\"end\"\r\n styletype=\"default-sm\"\r\n >\r\n <template #trigger>\r\n <div class=\"flex items-center gap-2 cursor-pointer hover:opacity-80 transition-opacity\">\r\n <JAvatar\r\n :src=\"userAvatar\"\r\n :fallback=\"userName ? userName[0] : 'U'\"\r\n size=\"sm\"\r\n />\r\n <span\r\n class=\"text-sm text-foreground hidden sm:inline\"\r\n >\r\n {{ userName }}\r\n </span>\r\n <JIcon name=\"chevronDown\" size=\"sm\" class=\"text-muted-foreground hidden sm:inline\" />\r\n </div>\r\n </template>\r\n <div class=\"w-full rounded-md overflow-hidden\">\r\n <!-- 프로필 정보 영역 -->\r\n <div class=\"px-3 py-2 border-b border-border\">\r\n <p class=\"text-sm font-medium text-foreground\">{{ userName }}</p>\r\n <p\r\n v-if=\"userEmail\"\r\n class=\"text-xs text-muted-foreground mt-0.5\"\r\n >\r\n {{ userEmail }}\r\n </p>\r\n </div>\r\n \r\n <!-- 메뉴 아이템 -->\r\n <template v-for=\"(group, groupIndex) in userMenuGroups\" :key=\"groupIndex\">\r\n <template v-for=\"(item, itemIndex) in group.items\" :key=\"item.id\">\r\n <button\r\n v-if=\"!item.separator\"\r\n :disabled=\"item.disabled\"\r\n :class=\"cn(\r\n 'w-full flex items-center gap-2 px-3 py-1.5 text-sm transition-colors',\r\n item.id === 'logout' \r\n ? 'text-destructive hover:bg-destructive/10 hover:text-destructive' \r\n : 'hover:bg-accent hover:text-accent-foreground',\r\n 'disabled:opacity-50 disabled:pointer-events-none',\r\n 'border-0 outline-none',\r\n group.items[itemIndex + 1]?.separator && 'border-b-0'\r\n )\"\r\n @click=\"handleUserMenuSelect(item.id)\"\r\n >\r\n <JIcon\r\n v-if=\"item.icon\"\r\n :name=\"item.icon\"\r\n size=\"sm\"\r\n :class=\"cn(\r\n 'flex-shrink-0',\r\n item.id === 'logout' && 'text-destructive'\r\n )\"\r\n />\r\n <span class=\"flex-1 text-left truncate\">{{ item.label }}</span>\r\n </button>\r\n <div\r\n v-else-if=\"item.separator && itemIndex > 0\"\r\n class=\"h-px bg-muted my-1\"\r\n />\r\n </template>\r\n <div\r\n v-if=\"groupIndex < userMenuGroups.length - 1\"\r\n class=\"h-px bg-muted my-1\"\r\n />\r\n </template>\r\n </div>\r\n </JPopover>\r\n\r\n <!-- 로그인 버튼 (userName이 없으면 표시) -->\r\n <JButton\r\n v-else\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n aria-label=\"로그인\"\r\n @click=\"handleLogin\"\r\n >\r\n <JIcon name=\"logIn\" size=\"sm\" class=\"sm:mr-1.5\" />\r\n <span class=\"hidden sm:inline\">로그인</span>\r\n </JButton>\r\n\r\n <!-- 커스텀 슬롯 -->\r\n <slot name=\"actions\" />\r\n </div>\r\n </header>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","STYLE_PRESETS","preset","computed","logoImageError","ref","logoImageSrc","displayLogoImage","logoFallback","handleLogoError","unreadCount","n","fixedUserMenuItems","userMenuGroups","handleLogoClick","handleNavClick","item","index","handleNotificationClick","handleUserMenuSelect","itemId","handleLogin","handleSidebarToggle","isDarkMode","currentTheme","getDefaultTheme","themeOptions","isInternalUpdate","themeObserver","styleObserver","isStorybook","updateThemeOptions","detectedThemes","detectThemeClasses","ensuredThemes","ensureDefaultTheme","filtered","theme","getStoredDarkModeTheme","stored","applyDarkModeTheme","root","handleThemeToggle","newTheme","getStoredTweakcnTheme","validateThemeExists","getStoredTheme","applyTweakcnTheme","validatedTheme","success","applyTheme","setStoredTheme","storybookGlobals","defaultTheme","handleThemeChange","themeIcon","onMounted","darkModeTheme","storedTheme","hasDarkClass","currentThemeClass","cls","themeName","intervalId","checkStorybookGlobals","storybookDarkMode","storybookTheme","onUnmounted","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_hoisted_1","_createBlock","JButton","_createVNode","JIcon","_hoisted_3","_toDisplayString","_openBlock","_hoisted_4","_Fragment","_renderList","$event","_hoisted_5","JPopover","_hoisted_6","_cache","_hoisted_7","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","notification","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","JAvatar","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","group","groupIndex","itemIndex","_hoisted_29","_hoisted_28","_hoisted_30","_renderSlot","_ctx"],"mappings":"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"}
1
+ {"version":3,"file":"JHeader.vue.js","sources":["../../../../src/components/organisms/JHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\nimport JIcon from '@/components/atoms/JIcon.vue'\nimport JAvatar from '@/components/atoms/JAvatar.vue'\nimport JButton from '@/components/atoms/JButton.vue'\nimport JPopover from '@/components/atoms/JPopover.vue'\nimport { cn } from '@/lib/utils'\nimport type { ContextMenuItem, ContextMenuGroup } from '@/types/context-menu.types'\nimport {\n detectThemeClasses,\n ensureDefaultTheme,\n validateThemeExists,\n getDefaultTheme,\n getStoredTheme,\n setStoredTheme,\n applyTheme,\n} from '@/lib/theme-utils'\n\n// Fallback 로고 이미지 import (logo prop이 없거나 로드 실패 시 사용)\nimport logoFallback from '@/assets/images/logo-fallback.png'\n\n/**\n * JHeader - 상단 헤더 컴포넌트 (organisms)\n * Header Component\n * \n * @description\n * 애플리케이션의 상단 헤더 영역을 담당하는 컴포넌트입니다.\n * 로고, 네비게이션, 검색, 알림, 사용자 메뉴 등을 포함할 수 있습니다.\n * \n * @example\n * ```vue\n * <JHeader\n * logo=\"/logo.png\"\n * :user-menu-items=\"userMenuItems\"\n * @logo-click=\"handleLogoClick\"\n * />\n * ```\n */\n\nexport type HeaderNavItem = {\n /** 라벨 */\n label: string\n /** 링크 URL */\n href?: string\n /** 아이콘 */\n icon?: string\n /** 활성 상태 */\n active?: boolean\n /** 클릭 핸들러 */\n onClick?: () => void\n}\n\nexport type NotificationItem = {\n /** 알림 ID */\n id: string\n /** 알림 제목 */\n title: string\n /** 알림 내용 */\n message?: string\n /** 알림 시간 */\n time?: string\n /** 읽음 상태 */\n read?: boolean\n /** 아이콘 */\n icon?: string\n /** 클릭 핸들러 */\n onClick?: () => void\n}\n\ntype StyleType =\n | 'default' // 기본 스타일\n | 'minimal' // 최소 스타일\n\nconst props = withDefaults(\n defineProps<{\n /** 로고 이미지 URL */\n logo?: string\n /** 로고 텍스트 (기본값, 이미지가 없을 때) */\n logoText?: string\n /** 네비게이션 아이템 목록 */\n navItems?: HeaderNavItem[]\n /** 알림 표시 여부 */\n showNotifications?: boolean\n /** 알림 목록 */\n notifications?: NotificationItem[]\n /** 사용자 아바타 이미지 */\n userAvatar?: string\n /** 사용자 이름 */\n userName?: string\n /** 로그인 상태 */\n isLoggedIn?: boolean\n /** 사용자 이메일 */\n userEmail?: string\n /** 사용자 ID */\n userId?: string\n /** 스타일 타입 */\n styletype?: StyleType\n /** 사이드바 토글 버튼 표시 여부 */\n showSidebarToggle?: boolean\n /** 사이드바 열림 상태 */\n isSidebarOpen?: boolean\n /** 테마 선택기 표시 여부 */\n showThemeSelector?: boolean\n /** 초기 테마 (기본값: 'default' 또는 저장된 테마) */\n defaultTheme?: string\n /** 선택 가능한 테마 목록 (지정하지 않으면 모든 감지된 테마 사용) */\n availableThemes?: string[]\n }>(),\n {\n logoText: 'JWMS Portal', // 기본값: 텍스트 로고\n showNotifications: false,\n notifications: () => [],\n styletype: 'default',\n showSidebarToggle: true,\n isSidebarOpen: true,\n showThemeSelector: true,\n defaultTheme: undefined,\n availableThemes: undefined,\n }\n)\n\nconst emit = defineEmits<{\n /** 로고 클릭 이벤트 */\n logoClick: []\n /** 네비게이션 아이템 클릭 이벤트 */\n navClick: [item: HeaderNavItem, index: number]\n /** 알림 클릭 이벤트 */\n notificationClick: [item: NotificationItem]\n /** 사용자 메뉴 아이템 선택 이벤트 */\n userMenuSelect: [itemId: string]\n /** 사이드바 토글 이벤트 */\n sidebarToggle: []\n /** 로그인 버튼 클릭 이벤트 */\n login: []\n}>()\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n navItemClass: string\n navItemActiveClass: string\n}> = {\n default: {\n containerClass: 'h-14 px-4 border-b border-border bg-background',\n navItemClass: 'text-sm text-muted-foreground hover:text-foreground transition-colors px-3 py-2 rounded-md hover:bg-accent',\n navItemActiveClass: 'text-foreground font-medium bg-accent',\n },\n minimal: {\n containerClass: 'h-12 px-3 border-b border-border bg-background',\n navItemClass: 'text-xs text-muted-foreground hover:text-foreground transition-colors px-2 py-1 rounded-md hover:bg-accent',\n navItemActiveClass: 'text-foreground font-medium bg-accent',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * 로고 이미지 로드 에러 상태\n * 0: 에러 없음, 1: 첫 번째 이미지(logo) 에러, 2: fallback 이미지도 에러\n */\nconst logoImageError = ref(0)\n\n/**\n * 로고 이미지 경로 계산\n */\nconst logoImageSrc = computed(() => {\n // props.logo가 있으면 사용\n if (props.logo) {\n return props.logo\n }\n return undefined\n})\n\n/**\n * 실제 표시할 로고 이미지 경로\n * 1. props.logo가 있으면 사용\n * 2. logo 에러 시 fallback 이미지\n * 3. fallback도 에러면 undefined (텍스트로 대체)\n */\nconst displayLogoImage = computed(() => {\n // logo prop이 없으면 이미지 표시 안함 (텍스트 사용)\n if (!props.logo) {\n return undefined\n }\n \n // logo 에러가 발생했으면 fallback 사용\n if (logoImageError.value >= 1 && logoFallback) {\n return logoFallback\n }\n \n // 정상적으로 logo 사용\n return logoImageSrc.value\n})\n\n/**\n * 로고 이미지 로드 에러 핸들러\n */\nconst handleLogoError = () => {\n // 첫 번째 이미지(logo) 에러\n if (logoImageError.value === 0) {\n logoImageError.value = 1\n }\n // fallback 이미지도 에러면 2로 설정 (텍스트로 대체)\n else if (logoImageError.value === 1) {\n logoImageError.value = 2\n }\n}\n\n/**\n * 읽지 않은 알림 개수\n */\nconst unreadCount = computed(() => {\n return props.notifications?.filter(n => !n.read).length || 0\n})\n\n/**\n * 고정 사용자 메뉴 아이템\n */\nconst fixedUserMenuItems: ContextMenuItem[] = [\n { id: 'profile', label: '프로필', icon: 'user' },\n { id: 'settings', label: '설정', icon: 'settings' },\n { id: 'separator', label: '', separator: true },\n { id: 'logout', label: '로그아웃', icon: 'logOut' },\n]\n\n/**\n * 사용자 메뉴 아이템을 ContextMenuGroup 형식으로 변환\n */\nconst userMenuGroups = computed<ContextMenuGroup[]>(() => {\n return [{\n items: fixedUserMenuItems\n }]\n})\n\n/**\n * 로고 클릭 핸들러\n */\nconst handleLogoClick = () => {\n emit('logoClick')\n}\n\n/**\n * 네비게이션 아이템 클릭 핸들러\n */\nconst handleNavClick = (item: HeaderNavItem, index: number) => {\n item.onClick?.()\n emit('navClick', item, index)\n}\n\n/**\n * 알림 클릭 핸들러\n */\nconst handleNotificationClick = (item: NotificationItem) => {\n item.onClick?.()\n emit('notificationClick', item)\n}\n\n/**\n * 사용자 메뉴 선택 핸들러\n */\nconst handleUserMenuSelect = (itemId: string) => {\n emit('userMenuSelect', itemId)\n}\n\n/**\n * 로그인 버튼 클릭 핸들러\n */\nconst handleLogin = () => {\n emit('login')\n}\n\n/**\n * 사이드바 토글 핸들러\n */\nconst handleSidebarToggle = () => {\n emit('sidebarToggle')\n}\n\n/**\n * tweakcn 테마 타입 정의 (동적 감지 지원)\n */\ntype ThemeName = string\n\n/**\n * 다크모드 상태를 추적하는 반응형 변수\n * - false: 라이트 모드\n * - true: 다크 모드\n * 초기값은 false(라이트 모드)이며, 컴포넌트 마운트 시 실제 테마로 업데이트됩니다.\n */\nconst isDarkMode = ref(false)\n\n/**\n * 현재 선택된 tweakcn 테마 (디폴트 테마로 초기화)\n */\nconst currentTheme = ref<ThemeName>(getDefaultTheme())\n\n/**\n * 테마 옵션 목록 (동적으로 감지)\n */\nconst themeOptions = ref<ThemeName[]>([])\n\n/**\n * 내부 업데이트 플래그\n * - true: 컴포넌트 내부에서 테마를 변경 중 (MutationObserver가 무시해야 함)\n * - false: 외부에서 테마가 변경됨 (MutationObserver가 동기화해야 함)\n */\nlet isInternalUpdate = false\n\n/**\n * MutationObserver 인스턴스\n */\nlet themeObserver: MutationObserver | null = null\nlet styleObserver: MutationObserver | null = null\n\n/**\n * Storybook 환경인지 확인하는 함수\n * \n * @returns Storybook 환경이면 true, 아니면 false\n */\nconst isStorybook = (): boolean => {\n if (typeof window === 'undefined') return false\n return !!(\n window.location?.href?.includes('storybook') ||\n (window as any).__STORYBOOK_GLOBALS__\n )\n}\n\n/**\n * 테마 목록을 동적으로 감지하고 업데이트합니다.\n */\nconst updateThemeOptions = () => {\n const detectedThemes = detectThemeClasses()\n const ensuredThemes = ensureDefaultTheme(detectedThemes)\n \n // availableThemes prop이 지정되면 필터링\n if (props.availableThemes && props.availableThemes.length > 0) {\n const filtered = ensuredThemes.filter(theme => props.availableThemes!.includes(theme))\n // default는 항상 포함\n themeOptions.value = ensureDefaultTheme(filtered)\n } else {\n themeOptions.value = ensuredThemes\n }\n}\n\n/**\n * localStorage에서 저장된 다크모드 테마를 읽어오는 함수\n * \n * 우선순위:\n * 1. localStorage에 저장된 'theme' 값 (사용자가 이전에 선택한 테마)\n * 2. 시스템 설정 (OS의 다크모드 설정)\n * 3. 기본값 'light' (라이트 모드)\n * \n * @returns 'light' | 'dark' - 적용할 테마\n */\nconst getStoredDarkModeTheme = (): 'light' | 'dark' => {\n if (typeof window === 'undefined') return 'light'\n \n const stored = localStorage.getItem('theme')\n if (stored === 'dark' || stored === 'light') {\n return stored\n }\n \n if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {\n return 'dark'\n }\n \n return 'light'\n}\n\n/**\n * 다크모드 테마를 HTML 문서에 적용하는 함수\n * \n * @param theme - 적용할 테마 ('light' 또는 'dark')\n */\nconst applyDarkModeTheme = (theme: 'light' | 'dark') => {\n isInternalUpdate = true\n \n const root = document.documentElement\n \n if (theme === 'dark') {\n root.classList.add('dark')\n isDarkMode.value = true\n } else {\n root.classList.remove('dark')\n isDarkMode.value = false\n }\n \n localStorage.setItem('theme', theme)\n \n isInternalUpdate = false\n}\n\n/**\n * 테마 토글 버튼 클릭 시 호출되는 핸들러 함수\n */\nconst handleThemeToggle = () => {\n const newTheme = isDarkMode.value ? 'light' : 'dark'\n applyDarkModeTheme(newTheme)\n}\n\n/**\n * 저장된 tweakcn 테마를 가져와서 적용합니다.\n */\nconst getStoredTweakcnTheme = (): ThemeName => {\n // defaultTheme prop이 지정되면 우선 사용\n if (props.defaultTheme) {\n const validated = validateThemeExists(props.defaultTheme)\n return validated\n }\n \n const stored = getStoredTheme('tweakcn-theme')\n if (!stored) {\n return getDefaultTheme()\n }\n \n // 저장된 테마가 유효한지 검증\n const validated = validateThemeExists(stored)\n return validated\n}\n\n/**\n * tweakcn 테마를 HTML 문서에 적용하는 함수\n */\nconst applyTweakcnTheme = (theme: ThemeName): boolean => {\n isInternalUpdate = true\n \n const validatedTheme = validateThemeExists(theme)\n const success = applyTheme(validatedTheme)\n \n if (success) {\n currentTheme.value = validatedTheme\n setStoredTheme(validatedTheme, 'tweakcn-theme')\n \n // 스토리북 환경에서만 전역 상태 동기화\n if (isStorybook()) {\n try {\n const storybookGlobals = (window as any).__STORYBOOK_GLOBALS__\n if (storybookGlobals) {\n storybookGlobals.theme = validatedTheme\n }\n } catch (e) {\n // 무시\n }\n }\n } else {\n // 실패 시 디폴트 테마로 폴백\n const defaultTheme = getDefaultTheme()\n applyTheme(defaultTheme)\n currentTheme.value = defaultTheme\n setStoredTheme(defaultTheme, 'tweakcn-theme')\n }\n \n isInternalUpdate = false\n return success\n}\n\n/**\n * 테마 변경 핸들러\n */\nconst handleThemeChange = (theme: ThemeName | string | number) => {\n applyTweakcnTheme(String(theme))\n}\n\n/**\n * 현재 테마에 따라 표시할 아이콘을 계산하는 computed 속성\n */\nconst themeIcon = computed(() => {\n return isDarkMode.value ? 'sun' : 'moon'\n})\n\n/**\n * 초기화: 저장된 테마 적용 및 테마 목록 감지\n */\nonMounted(() => {\n // 테마 목록 초기 감지\n updateThemeOptions()\n \n // 저장된 다크모드 테마 적용\n const darkModeTheme = getStoredDarkModeTheme()\n applyDarkModeTheme(darkModeTheme)\n \n // 저장된 tweakcn 테마 적용\n const storedTheme = getStoredTweakcnTheme()\n applyTweakcnTheme(storedTheme)\n \n // HTML의 dark 클래스 변경을 감지하여 헤더 컴포넌트 상태를 동기화\n const root = document.documentElement\n \n // 현재 dark 클래스 상태로 초기화\n isDarkMode.value = root.classList.contains('dark')\n \n // MutationObserver로 동적 테마 클래스 감지\n themeObserver = new MutationObserver(() => {\n if (isInternalUpdate) return\n \n // 다크모드 클래스 변경 감지\n const hasDarkClass = root.classList.contains('dark')\n if (hasDarkClass !== isDarkMode.value) {\n isDarkMode.value = hasDarkClass\n localStorage.setItem('theme', hasDarkClass ? 'dark' : 'light')\n }\n \n // 테마 목록 업데이트\n updateThemeOptions()\n \n // 현재 적용된 tweakcn 테마 확인\n const currentThemeClass = Array.from(root.classList).find(cls => cls.startsWith('theme-'))\n if (currentThemeClass) {\n const themeName = currentThemeClass.replace('theme-', '')\n if (themeOptions.value.includes(themeName)) {\n currentTheme.value = themeName\n }\n }\n })\n \n // document.documentElement의 클래스 변경 감지\n themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n })\n \n // 스타일시트 변경 감지 (동적으로 추가된 테마 감지)\n styleObserver = new MutationObserver(() => {\n updateThemeOptions()\n })\n \n styleObserver.observe(document.head, {\n childList: true,\n subtree: true,\n })\n \n // 스토리북 환경에서만 다크모드 및 테마 변경 감지 (추가 보완)\n let intervalId: ReturnType<typeof setInterval> | null = null\n \n if (isStorybook()) {\n const checkStorybookGlobals = () => {\n try {\n const storybookGlobals = (window as any).__STORYBOOK_GLOBALS__\n if (storybookGlobals) {\n // 다크모드 동기화\n if (typeof storybookGlobals.darkMode !== 'undefined') {\n const storybookDarkMode = storybookGlobals.darkMode\n if (storybookDarkMode !== isDarkMode.value) {\n applyDarkModeTheme(storybookDarkMode ? 'dark' : 'light')\n }\n }\n \n // tweakcn 테마 동기화\n if (storybookGlobals.theme && storybookGlobals.theme !== currentTheme.value) {\n const storybookTheme = String(storybookGlobals.theme)\n if (themeOptions.value.includes(storybookTheme)) {\n applyTweakcnTheme(storybookTheme)\n }\n }\n }\n } catch (e) {\n // 무시\n }\n }\n \n // 초기 확인\n checkStorybookGlobals()\n \n // 주기적으로 확인 (스토리북이 직접 이벤트를 제공하지 않는 경우)\n intervalId = setInterval(checkStorybookGlobals, 500)\n }\n \n // 컴포넌트 언마운트 시 정리\n onUnmounted(() => {\n if (themeObserver) {\n themeObserver.disconnect()\n themeObserver = null\n }\n if (styleObserver) {\n styleObserver.disconnect()\n styleObserver = null\n }\n if (intervalId) {\n clearInterval(intervalId)\n }\n })\n})\n</script>\n\n<template>\n <header :class=\"cn('flex items-center justify-between w-full', preset.containerClass)\">\n <!-- 왼쪽: 햄버거 메뉴 + 로고 + 네비게이션 -->\n <div class=\"flex items-center gap-6 flex-1\">\n <!-- 햄버거 메뉴 버튼 (사이드바 토글) -->\n <JButton\n v-if=\"showSidebarToggle\"\n variant=\"ghost\"\n size=\"icon\"\n class=\"flex-shrink-0\"\n aria-label=\"사이드바 토글\"\n @click=\"handleSidebarToggle\"\n >\n <JIcon name=\"menu\" size=\"md\" />\n </JButton>\n\n <!-- 로고 -->\n <div\n v-if=\"displayLogoImage || logoText\"\n class=\"flex items-center cursor-pointer\"\n @click=\"handleLogoClick\"\n >\n <!-- 로고 이미지 (logo prop이 있고 에러가 2 미만일 때) -->\n <img\n v-if=\"displayLogoImage && logoImageError < 2\"\n :src=\"displayLogoImage\"\n alt=\"로고\"\n class=\"h-8 w-auto\"\n @error=\"handleLogoError\"\n />\n <!-- 로고 텍스트 (기본 또는 모든 이미지 실패 시) -->\n <span\n v-else-if=\"logoText\"\n class=\"text-lg font-bold text-foreground\"\n >\n {{ logoText }}\n </span>\n </div>\n\n <!-- 네비게이션 -->\n <nav\n v-if=\"navItems && navItems.length > 0\"\n class=\"flex items-center gap-1\"\n >\n <JButton\n v-for=\"(item, index) in navItems\"\n :key=\"index\"\n variant=\"ghost\"\n :class=\"cn(\n preset.navItemClass,\n item.active && preset.navItemActiveClass\n )\"\n @click=\"handleNavClick(item, index)\"\n >\n <JIcon\n v-if=\"item.icon\"\n :name=\"item.icon\"\n size=\"sm\"\n class=\"mr-1.5\"\n />\n {{ item.label }}\n </JButton>\n </nav>\n </div>\n\n <!-- 오른쪽: 테마 선택기 + 알림 + 다크모드 토글 + 사용자 메뉴 -->\n <div class=\"flex items-center gap-3\">\n <!-- tweakcn 테마 선택기 -->\n <JPopover\n v-if=\"showThemeSelector\"\n position=\"bottom\"\n align=\"end\"\n styletype=\"default-sm\"\n >\n <template #trigger>\n <JButton\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"테마 선택\"\n >\n <JIcon name=\"palette\" size=\"md\" />\n </JButton>\n </template>\n <div class=\"p-2 min-w-[200px]\">\n <div class=\"text-xs font-medium text-muted-foreground px-2 py-1.5 mb-1\">\n 테마 선택\n </div>\n <div class=\"space-y-1\">\n <button\n v-for=\"theme in themeOptions\"\n :key=\"theme\"\n :class=\"cn(\n 'w-full flex items-center gap-2 px-2 py-1.5 text-sm rounded-md transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n 'border-0 outline-none text-left',\n currentTheme === theme && 'bg-accent text-accent-foreground font-medium'\n )\"\n @click=\"handleThemeChange(theme)\"\n >\n <JIcon\n v-if=\"currentTheme === theme\"\n name=\"check\"\n size=\"sm\"\n class=\"flex-shrink-0\"\n />\n <span v-else class=\"w-4\" />\n <span class=\"flex-1 capitalize\">{{ theme }}</span>\n </button>\n </div>\n </div>\n </JPopover>\n\n <!-- 알림 -->\n <JPopover\n v-if=\"showNotifications\"\n position=\"bottom\"\n align=\"end\"\n styletype=\"default-sm\"\n >\n <template #trigger>\n <JButton\n variant=\"ghost\"\n size=\"icon\"\n class=\"relative\"\n aria-label=\"알림\"\n >\n <JIcon name=\"circleAlert\" size=\"md\" />\n <span\n v-if=\"unreadCount > 0\"\n class=\"absolute top-0 right-0 h-4 w-4 rounded-full bg-destructive text-destructive-foreground text-xs flex items-center justify-center\"\n >\n {{ unreadCount > 9 ? '9+' : unreadCount }}\n </span>\n </JButton>\n </template>\n <div class=\"p-2\">\n <div\n v-if=\"notifications && notifications.length > 0\"\n class=\"max-h-96 overflow-y-auto space-y-1\"\n >\n <div\n v-for=\"notification in notifications\"\n :key=\"notification.id\"\n :class=\"cn(\n 'p-3 rounded-md cursor-pointer transition-colors',\n !notification.read ? 'bg-accent' : 'hover:bg-accent/50'\n )\"\n @click=\"handleNotificationClick(notification)\"\n >\n <div class=\"flex items-start gap-2\">\n <JIcon\n v-if=\"notification.icon\"\n :name=\"notification.icon\"\n size=\"sm\"\n class=\"mt-0.5 flex-shrink-0\"\n />\n <div class=\"flex-1 min-w-0\">\n <p class=\"text-sm font-medium text-foreground\">\n {{ notification.title }}\n </p>\n <p\n v-if=\"notification.message\"\n class=\"text-xs text-muted-foreground mt-1\"\n >\n {{ notification.message }}\n </p>\n <p\n v-if=\"notification.time\"\n class=\"text-xs text-muted-foreground/60 mt-1\"\n >\n {{ notification.time }}\n </p>\n </div>\n </div>\n </div>\n </div>\n <div\n v-else\n class=\"p-4 text-center text-sm text-muted-foreground\"\n >\n 알림이 없습니다.\n </div>\n </div>\n </JPopover>\n\n <!-- 다크모드 토글 버튼 -->\n <JButton\n variant=\"ghost\"\n size=\"icon\"\n :aria-label=\"isDarkMode ? '라이트 모드로 전환' : '다크 모드로 전환'\"\n @click=\"handleThemeToggle\"\n >\n <JIcon :name=\"themeIcon\" size=\"md\" />\n </JButton>\n\n <!-- 사용자 메뉴 (userName이 있으면 표시) -->\n <JPopover\n v-if=\"userName\"\n position=\"bottom\"\n align=\"end\"\n styletype=\"default-sm\"\n >\n <template #trigger>\n <div class=\"flex items-center gap-2 cursor-pointer hover:opacity-80 transition-opacity\">\n <JAvatar\n :src=\"userAvatar\"\n :fallback=\"userName ? userName[0] : 'U'\"\n size=\"sm\"\n />\n <span\n class=\"text-sm text-foreground hidden sm:inline\"\n >\n {{ userName }}\n </span>\n <JIcon name=\"chevronDown\" size=\"sm\" class=\"text-muted-foreground hidden sm:inline\" />\n </div>\n </template>\n <div class=\"w-full rounded-md overflow-hidden\">\n <!-- 프로필 정보 영역 -->\n <div class=\"px-3 py-2 border-b border-border\">\n <p class=\"text-sm font-medium text-foreground\">{{ userName }}</p>\n <p\n v-if=\"userEmail\"\n class=\"text-xs text-muted-foreground mt-0.5\"\n >\n {{ userEmail }}\n </p>\n </div>\n \n <!-- 메뉴 아이템 -->\n <template v-for=\"(group, groupIndex) in userMenuGroups\" :key=\"groupIndex\">\n <template v-for=\"(item, itemIndex) in group.items\" :key=\"item.id\">\n <button\n v-if=\"!item.separator\"\n :disabled=\"item.disabled\"\n :class=\"cn(\n 'w-full flex items-center gap-2 px-3 py-1.5 text-sm transition-colors',\n item.id === 'logout' \n ? 'text-destructive hover:bg-destructive/10 hover:text-destructive' \n : 'hover:bg-accent hover:text-accent-foreground',\n 'disabled:opacity-50 disabled:pointer-events-none',\n 'border-0 outline-none',\n group.items[itemIndex + 1]?.separator && 'border-b-0'\n )\"\n @click=\"handleUserMenuSelect(item.id)\"\n >\n <JIcon\n v-if=\"item.icon\"\n :name=\"item.icon\"\n size=\"sm\"\n :class=\"cn(\n 'flex-shrink-0',\n item.id === 'logout' && 'text-destructive'\n )\"\n />\n <span class=\"flex-1 text-left truncate\">{{ item.label }}</span>\n </button>\n <div\n v-else-if=\"item.separator && itemIndex > 0\"\n class=\"h-px bg-muted my-1\"\n />\n </template>\n <div\n v-if=\"groupIndex < userMenuGroups.length - 1\"\n class=\"h-px bg-muted my-1\"\n />\n </template>\n </div>\n </JPopover>\n\n <!-- 로그인 버튼 (userName이 없으면 표시) -->\n <JButton\n v-else\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"로그인\"\n @click=\"handleLogin\"\n >\n <JIcon name=\"logIn\" size=\"sm\" class=\"sm:mr-1.5\" />\n <span class=\"hidden sm:inline\">로그인</span>\n </JButton>\n\n <!-- 커스텀 슬롯 -->\n <slot name=\"actions\" />\n </div>\n </header>\n</template>\n"],"names":["props","__props","emit","__emit","STYLE_PRESETS","preset","computed","logoImageError","ref","logoImageSrc","displayLogoImage","logoFallback","handleLogoError","unreadCount","n","fixedUserMenuItems","userMenuGroups","handleLogoClick","handleNavClick","item","index","handleNotificationClick","handleUserMenuSelect","itemId","handleLogin","handleSidebarToggle","isDarkMode","currentTheme","getDefaultTheme","themeOptions","isInternalUpdate","themeObserver","styleObserver","isStorybook","updateThemeOptions","detectedThemes","detectThemeClasses","ensuredThemes","ensureDefaultTheme","filtered","theme","getStoredDarkModeTheme","stored","applyDarkModeTheme","root","handleThemeToggle","newTheme","getStoredTweakcnTheme","validateThemeExists","getStoredTheme","applyTweakcnTheme","validatedTheme","success","applyTheme","setStoredTheme","storybookGlobals","defaultTheme","handleThemeChange","themeIcon","onMounted","darkModeTheme","storedTheme","hasDarkClass","currentThemeClass","cls","themeName","intervalId","checkStorybookGlobals","storybookDarkMode","storybookTheme","onUnmounted","_createElementBlock","_normalizeClass","_unref","cn","_createElementVNode","_hoisted_1","_createBlock","JButton","_createVNode","JIcon","_hoisted_3","_toDisplayString","_openBlock","_hoisted_4","_Fragment","_renderList","$event","_hoisted_5","JPopover","_hoisted_6","_cache","_hoisted_7","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","notification","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","JAvatar","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","group","groupIndex","itemIndex","_hoisted_29","_hoisted_28","_hoisted_30","_renderSlot","_ctx"],"mappings":"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"}
@@ -3,5 +3,5 @@
3
3
  for (const [t_key, t_val] of t_opts)
4
4
  t_merged[t_key] = t_val;
5
5
  return t_merged;
6
- };,u=t(e.default,[["__scopeId","data-v-7651c855"]]);exports.default=u;
6
+ };,u=t(e.default,[["__scopeId","data-v-89051622"]]);exports.default=u;
7
7
  //# sourceMappingURL=JSearchPanel.vue.cjs.map
@@ -6,8 +6,8 @@ const r = (r_comp, r_opts) => {
6
6
  r_merged[r_key] = r_val;
7
7
  return r_merged;
8
8
  };
9
- const e = /* @__PURE__ */ r(o, [["__scopeId", "data-v-7651c855"]]);
9
+ const m = /* @__PURE__ */ r(o, [["__scopeId", "data-v-89051622"]]);
10
10
  export {
11
- e as default
11
+ m as default
12
12
  };
13
13
  //# sourceMappingURL=JSearchPanel.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"JSearchPanel.vue2.cjs","sources":["../../../../src/components/organisms/JSearchPanel.vue"],"sourcesContent":["<template>\r\n <Card class=\"w-full\">\r\n <!-- 헤더: 제목, Badge 목록, 초기화 버튼 -->\r\n <CardHeader class=\"pt-4 pb-3 px-6\">\r\n <div class=\"flex items-center justify-between\">\r\n <div class=\"flex items-center gap-3 flex-1\">\r\n <button\r\n v-if=\"collapsible\"\r\n type=\"button\"\r\n @click=\"isExpanded = !isExpanded\"\r\n class=\"flex items-center gap-2 font-semibold hover:text-primary transition-colors\"\r\n >\r\n <ChevronDown\r\n :class=\"['h-4 w-4 transition-transform', isExpanded ? 'rotate-0' : '-rotate-90']\"\r\n />\r\n {{ title }}\r\n </button>\r\n <CardTitle v-else class=\"mb-0\">{{ title }}</CardTitle>\r\n \r\n <!-- 조건 Badge 목록 -->\r\n <div v-if=\"conditionBadges.length > 0\" class=\"flex flex-wrap items-center gap-2 ml-2\">\r\n <JBadge\r\n v-for=\"badge in conditionBadges\"\r\n :key=\"badge.fieldName\"\r\n variant=\"secondary\"\r\n size=\"sm\"\r\n class=\"flex items-center gap-1.5 pr-1\"\r\n >\r\n <span>{{ badge.label }}: {{ badge.value }}</span>\r\n <button\r\n type=\"button\"\r\n @click.stop=\"handleFieldReset(badge.fieldName)\"\r\n class=\"h-4 w-4 rounded-full hover:bg-destructive/20 hover:text-destructive transition-colors flex items-center justify-center\"\r\n :aria-label=\"`${badge.label} 조건 제거`\"\r\n >\r\n <X class=\"h-3 w-3\" />\r\n </button>\r\n </JBadge>\r\n </div>\r\n </div>\r\n \r\n <JButton\r\n variant=\"outline\"\r\n size=\"sm\"\r\n @click.stop=\"handleReset\"\r\n >\r\n 초기화\r\n </JButton>\r\n </div>\r\n </CardHeader>\r\n \r\n <!-- 폼 내용 -->\r\n <CardContent v-show=\"isExpanded || !collapsible\" class=\"px-6 pb-6 pt-0\">\r\n <JDynamicForm\r\n ref=\"dynamicFormRef\"\r\n :schema=\"schema\"\r\n :model-value=\"localModelValue\"\r\n @update:model-value=\"handleFormValueUpdate\"\r\n @submit=\"handleSubmit\"\r\n />\r\n </CardContent>\r\n </Card>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, reactive, watch } from 'vue'\r\nimport { ChevronDown, X } from 'lucide-vue-next'\r\nimport { Card, CardHeader, CardTitle, CardContent } from '@/components/shadcn'\r\nimport { JButton, JBadge } from '@/components/atoms'\r\nimport JDynamicForm from './JDynamicForm.vue'\r\nimport type { FormSchema, DynamicFormField } from '@/types/dynamic-form'\r\nimport type { ComponentPublicInstance } from 'vue'\r\n\r\ninterface ConditionBadge {\r\n fieldName: string\r\n label: string\r\n value: string\r\n}\r\n\r\nexport interface JSearchPanelProps {\r\n /** 패널 제목 */\r\n title?: string\r\n /** JDynamicForm에 전달할 FormSchema */\r\n schema: FormSchema\r\n /** JDynamicForm의 v-model 값 */\r\n modelValue?: Record<string, any>\r\n /** 기본 접힘 상태 */\r\n defaultCollapsed?: boolean\r\n /** 접기/펼치기 가능 여부 */\r\n collapsible?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<JSearchPanelProps>(), {\r\n title: '조회조건',\r\n defaultCollapsed: false,\r\n collapsible: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:modelValue': [value: Record<string, any>]\r\n 'submit': [values: Record<string, any>]\r\n 'reset': []\r\n}>()\r\n\r\nconst dynamicFormRef = ref<ComponentPublicInstance & { reset: () => void } | null>(null)\r\nconst isExpanded = ref(!props.defaultCollapsed)\r\n\r\n// 로컬 modelValue - reactive로 관리하여 양방향 바인딩\r\nconst localModelValue = reactive<Record<string, any>>(props.modelValue ? { ...props.modelValue } : {})\r\n\r\n// 내부 변경인지 외부 변경인지 구분하는 플래그\r\nlet isInternalUpdate = false\r\n\r\n// props.modelValue 변경 시 localModelValue 동기화 (외부 변경)\r\nwatch(\r\n () => props.modelValue,\r\n (newValue) => {\r\n if (newValue && !isInternalUpdate) {\r\n // 기존 키 중 새 값에 없는 것은 삭제\r\n Object.keys(localModelValue).forEach(key => {\r\n if (!(key in newValue)) {\r\n delete localModelValue[key]\r\n }\r\n })\r\n // 새 값으로 업데이트\r\n Object.assign(localModelValue, newValue)\r\n }\r\n isInternalUpdate = false\r\n },\r\n { deep: true, immediate: true }\r\n)\r\n\r\n// JDynamicForm에서 값이 변경되었을 때 처리\r\nfunction handleFormValueUpdate(value: Record<string, any>) {\r\n // JDynamicForm에서 emit된 값을 localModelValue에 반영\r\n isInternalUpdate = true\r\n Object.assign(localModelValue, value)\r\n // 상위로 emit\r\n emit('update:modelValue', { ...value })\r\n}\r\n\r\n// 모든 필드 가져오기\r\nconst allFields = computed((): DynamicFormField[] => {\r\n if (!props.schema) return []\r\n \r\n const fields: DynamicFormField[] = []\r\n if (props.schema.type === 'simple' && props.schema.fields) {\r\n fields.push(...props.schema.fields)\r\n } else if (props.schema.type === 'sectioned' && props.schema.sections) {\r\n props.schema.sections.forEach(section => {\r\n if (section.fields) fields.push(...section.fields)\r\n })\r\n } else if (props.schema.type === 'wizard' && props.schema.steps) {\r\n props.schema.steps.forEach(step => {\r\n if (step.fields) fields.push(...step.fields)\r\n })\r\n }\r\n return fields\r\n})\r\n\r\n// 조건 Badge 목록 생성\r\nconst conditionBadges = computed((): ConditionBadge[] => {\r\n if (!localModelValue || !props.schema) {\r\n return []\r\n }\r\n\r\n const badges: ConditionBadge[] = []\r\n const formState = localModelValue\r\n\r\n allFields.value.forEach((field) => {\r\n const value = formState[field.controlName]\r\n \r\n // 빈 값 체크 (빈 문자열, null, undefined, 'ALL', 'SELECT' 제외)\r\n if (\r\n value === undefined ||\r\n value === null ||\r\n value === '' ||\r\n value === 'ALL' ||\r\n value === 'SELECT' ||\r\n (field.type === 'checkbox' && value === 'N') ||\r\n (field.type === 'switch' && value === 'N')\r\n ) {\r\n return\r\n }\r\n\r\n // 필드 타입에 따라 값 표시\r\n let displayValue = String(value)\r\n\r\n // 콤보/검색콤보인 경우 옵션의 label 찾기\r\n if ((field.type === 'combo' || field.type === 'searchcombo') && field.options) {\r\n const option = field.options.find(opt => opt.value === value)\r\n if (option) {\r\n displayValue = option.label\r\n }\r\n }\r\n\r\n // 체크박스/스위치는 'Y'일 때만 표시\r\n if (field.type === 'checkbox' || field.type === 'switch') {\r\n if (value === 'Y') {\r\n badges.push({\r\n fieldName: field.controlName,\r\n label: field.label,\r\n value: field.inlineLabel || field.label\r\n })\r\n }\r\n } else {\r\n badges.push({\r\n fieldName: field.controlName,\r\n label: field.label,\r\n value: displayValue\r\n })\r\n }\r\n })\r\n\r\n return badges\r\n})\r\n\r\n// submit 핸들러\r\nfunction handleSubmit(values: Record<string, any>) {\r\n emit('submit', values)\r\n}\r\n\r\n// 전체 초기화 핸들러\r\nfunction handleReset() {\r\n if (dynamicFormRef.value) {\r\n dynamicFormRef.value.reset()\r\n emit('reset')\r\n }\r\n}\r\n\r\n// 필드별 초기화 핸들러\r\nfunction handleFieldReset(fieldName: string) {\r\n if (!localModelValue || !props.schema) return\r\n \r\n const field = allFields.value.find(f => f.controlName === fieldName)\r\n \r\n if (field) {\r\n // 필드 타입에 따라 초기값 설정 - reactive 객체 직접 수정\r\n if (field.type === 'checkbox' || field.type === 'switch') {\r\n localModelValue[fieldName] = 'N'\r\n } else {\r\n localModelValue[fieldName] = ''\r\n }\r\n \r\n // localModelValue 변경 후 상위로 emit하여 JDynamicForm에도 반영\r\n isInternalUpdate = true\r\n emit('update:modelValue', { ...localModelValue })\r\n }\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n/* 필요시 스타일 추가 */\r\n</style>\r\n\r\n"],"names":["props","__props","emit","__emit","dynamicFormRef","ref","isExpanded","localModelValue","reactive","isInternalUpdate","watch","newValue","key","handleFormValueUpdate","value","allFields","computed","fields","section","step","conditionBadges","badges","formState","field","displayValue","option","opt","handleSubmit","values","handleReset","handleFieldReset","fieldName","f","_createBlock","_unref","Card","_createVNode","CardHeader","_createElementVNode","_hoisted_1","_hoisted_2","_createElementBlock","_cache","$event","ChevronDown","_createTextVNode","CardTitle","_openBlock","_hoisted_3","_Fragment","_renderList","badge","JBadge","_toDisplayString","_withModifiers","X","JButton","CardContent","JDynamicForm","_vShow"],"mappings":"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"}
1
+ {"version":3,"file":"JSearchPanel.vue2.cjs","sources":["../../../../src/components/organisms/JSearchPanel.vue"],"sourcesContent":["<template>\n <Card class=\"w-full\">\n <!-- 헤더: 제목, Badge 목록, 초기화 버튼 -->\n <CardHeader class=\"pt-4 pb-3 px-6\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center gap-3 flex-1\">\n <button\n v-if=\"collapsible\"\n type=\"button\"\n @click=\"isExpanded = !isExpanded\"\n class=\"flex items-center gap-2 font-semibold hover:text-primary transition-colors\"\n >\n <ChevronDown\n :class=\"['h-4 w-4 transition-transform', isExpanded ? 'rotate-0' : '-rotate-90']\"\n />\n {{ title }}\n </button>\n <CardTitle v-else class=\"mb-0\">{{ title }}</CardTitle>\n \n <!-- 조건 Badge 목록 -->\n <div v-if=\"conditionBadges.length > 0\" class=\"flex flex-wrap items-center gap-2 ml-2\">\n <JBadge\n v-for=\"badge in conditionBadges\"\n :key=\"badge.fieldName\"\n variant=\"secondary\"\n size=\"sm\"\n class=\"flex items-center gap-1.5 pr-1\"\n >\n <span>{{ badge.label }}: {{ badge.value }}</span>\n <button\n type=\"button\"\n @click.stop=\"handleFieldReset(badge.fieldName)\"\n class=\"h-4 w-4 rounded-full hover:bg-destructive/20 hover:text-destructive transition-colors flex items-center justify-center\"\n :aria-label=\"`${badge.label} 조건 제거`\"\n >\n <X class=\"h-3 w-3\" />\n </button>\n </JBadge>\n </div>\n </div>\n \n <JButton\n variant=\"outline\"\n size=\"sm\"\n @click.stop=\"handleReset\"\n >\n 초기화\n </JButton>\n </div>\n </CardHeader>\n \n <!-- 폼 내용 -->\n <CardContent v-show=\"isExpanded || !collapsible\" class=\"px-6 pb-6 pt-0\">\n <JDynamicForm\n ref=\"dynamicFormRef\"\n :schema=\"schema\"\n :model-value=\"localModelValue\"\n @update:model-value=\"handleFormValueUpdate\"\n @submit=\"handleSubmit\"\n />\n </CardContent>\n </Card>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, reactive, watch } from 'vue'\nimport { ChevronDown, X } from 'lucide-vue-next'\nimport { Card, CardHeader, CardTitle, CardContent } from '@/components/shadcn'\nimport { JButton, JBadge } from '@/components/atoms'\nimport JDynamicForm from './JDynamicForm.vue'\nimport type { FormSchema, DynamicFormField } from '@/types/dynamic-form'\nimport type { ComponentPublicInstance } from 'vue'\n\ninterface ConditionBadge {\n fieldName: string\n label: string\n value: string\n}\n\nexport interface JSearchPanelProps {\n /** 패널 제목 */\n title?: string\n /** JDynamicForm에 전달할 FormSchema */\n schema: FormSchema\n /** JDynamicForm의 v-model 값 */\n modelValue?: Record<string, any>\n /** 기본 접힘 상태 */\n defaultCollapsed?: boolean\n /** 접기/펼치기 가능 여부 */\n collapsible?: boolean\n}\n\nconst props = withDefaults(defineProps<JSearchPanelProps>(), {\n title: '조회조건',\n defaultCollapsed: false,\n collapsible: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: Record<string, any>]\n 'submit': [values: Record<string, any>]\n 'reset': []\n}>()\n\nconst dynamicFormRef = ref<ComponentPublicInstance & { reset: () => void } | null>(null)\nconst isExpanded = ref(!props.defaultCollapsed)\n\n// 로컬 modelValue - reactive로 관리하여 양방향 바인딩\nconst localModelValue = reactive<Record<string, any>>(props.modelValue ? { ...props.modelValue } : {})\n\n// 내부 변경인지 외부 변경인지 구분하는 플래그\nlet isInternalUpdate = false\n\n// props.modelValue 변경 시 localModelValue 동기화 (외부 변경)\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue && !isInternalUpdate) {\n // 기존 키 중 새 값에 없는 것은 삭제\n Object.keys(localModelValue).forEach(key => {\n if (!(key in newValue)) {\n delete localModelValue[key]\n }\n })\n // 새 값으로 업데이트\n Object.assign(localModelValue, newValue)\n }\n isInternalUpdate = false\n },\n { deep: true, immediate: true }\n)\n\n// JDynamicForm에서 값이 변경되었을 때 처리\nfunction handleFormValueUpdate(value: Record<string, any>) {\n // JDynamicForm에서 emit된 값을 localModelValue에 반영\n isInternalUpdate = true\n Object.assign(localModelValue, value)\n // 상위로 emit\n emit('update:modelValue', { ...value })\n}\n\n// 모든 필드 가져오기\nconst allFields = computed((): DynamicFormField[] => {\n if (!props.schema) return []\n \n const fields: DynamicFormField[] = []\n if (props.schema.type === 'simple' && props.schema.fields) {\n fields.push(...props.schema.fields)\n } else if (props.schema.type === 'sectioned' && props.schema.sections) {\n props.schema.sections.forEach(section => {\n if (section.fields) fields.push(...section.fields)\n })\n } else if (props.schema.type === 'wizard' && props.schema.steps) {\n props.schema.steps.forEach(step => {\n if (step.fields) fields.push(...step.fields)\n })\n }\n return fields\n})\n\n// 조건 Badge 목록 생성\nconst conditionBadges = computed((): ConditionBadge[] => {\n if (!localModelValue || !props.schema) {\n return []\n }\n\n const badges: ConditionBadge[] = []\n const formState = localModelValue\n\n allFields.value.forEach((field) => {\n const value = formState[field.controlName]\n \n // 빈 값 체크 (빈 문자열, null, undefined, 'ALL', 'SELECT' 제외)\n if (\n value === undefined ||\n value === null ||\n value === '' ||\n value === 'ALL' ||\n value === 'SELECT' ||\n (field.type === 'checkbox' && value === 'N') ||\n (field.type === 'switch' && value === 'N')\n ) {\n return\n }\n\n // 필드 타입에 따라 값 표시\n let displayValue = String(value)\n\n // 콤보/검색콤보인 경우 옵션의 label 찾기\n if ((field.type === 'combo' || field.type === 'searchcombo') && field.options) {\n const option = field.options.find(opt => opt.value === value)\n if (option) {\n displayValue = option.label\n }\n }\n\n // 체크박스/스위치는 'Y'일 때만 표시\n if (field.type === 'checkbox' || field.type === 'switch') {\n if (value === 'Y') {\n badges.push({\n fieldName: field.controlName,\n label: field.label,\n value: field.inlineLabel || field.label\n })\n }\n } else {\n badges.push({\n fieldName: field.controlName,\n label: field.label,\n value: displayValue\n })\n }\n })\n\n return badges\n})\n\n// submit 핸들러\nfunction handleSubmit(values: Record<string, any>) {\n emit('submit', values)\n}\n\n// 전체 초기화 핸들러\nfunction handleReset() {\n if (dynamicFormRef.value) {\n dynamicFormRef.value.reset()\n emit('reset')\n }\n}\n\n// 필드별 초기화 핸들러\nfunction handleFieldReset(fieldName: string) {\n if (!localModelValue || !props.schema) return\n \n const field = allFields.value.find(f => f.controlName === fieldName)\n \n if (field) {\n // 필드 타입에 따라 초기값 설정 - reactive 객체 직접 수정\n if (field.type === 'checkbox' || field.type === 'switch') {\n localModelValue[fieldName] = 'N'\n } else {\n localModelValue[fieldName] = ''\n }\n \n // localModelValue 변경 후 상위로 emit하여 JDynamicForm에도 반영\n isInternalUpdate = true\n emit('update:modelValue', { ...localModelValue })\n }\n}\n</script>\n\n<style scoped>\n/* 필요시 스타일 추가 */\n</style>\n\n"],"names":["props","__props","emit","__emit","dynamicFormRef","ref","isExpanded","localModelValue","reactive","isInternalUpdate","watch","newValue","key","handleFormValueUpdate","value","allFields","computed","fields","section","step","conditionBadges","badges","formState","field","displayValue","option","opt","handleSubmit","values","handleReset","handleFieldReset","fieldName","f","_createBlock","_unref","Card","_createVNode","CardHeader","_createElementVNode","_hoisted_1","_hoisted_2","_createElementBlock","_cache","$event","ChevronDown","_createTextVNode","CardTitle","_openBlock","_hoisted_3","_Fragment","_renderList","badge","JBadge","_toDisplayString","_withModifiers","X","JButton","CardContent","JDynamicForm","_vShow"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"JSearchPanel.vue2.js","sources":["../../../../src/components/organisms/JSearchPanel.vue"],"sourcesContent":["<template>\r\n <Card class=\"w-full\">\r\n <!-- 헤더: 제목, Badge 목록, 초기화 버튼 -->\r\n <CardHeader class=\"pt-4 pb-3 px-6\">\r\n <div class=\"flex items-center justify-between\">\r\n <div class=\"flex items-center gap-3 flex-1\">\r\n <button\r\n v-if=\"collapsible\"\r\n type=\"button\"\r\n @click=\"isExpanded = !isExpanded\"\r\n class=\"flex items-center gap-2 font-semibold hover:text-primary transition-colors\"\r\n >\r\n <ChevronDown\r\n :class=\"['h-4 w-4 transition-transform', isExpanded ? 'rotate-0' : '-rotate-90']\"\r\n />\r\n {{ title }}\r\n </button>\r\n <CardTitle v-else class=\"mb-0\">{{ title }}</CardTitle>\r\n \r\n <!-- 조건 Badge 목록 -->\r\n <div v-if=\"conditionBadges.length > 0\" class=\"flex flex-wrap items-center gap-2 ml-2\">\r\n <JBadge\r\n v-for=\"badge in conditionBadges\"\r\n :key=\"badge.fieldName\"\r\n variant=\"secondary\"\r\n size=\"sm\"\r\n class=\"flex items-center gap-1.5 pr-1\"\r\n >\r\n <span>{{ badge.label }}: {{ badge.value }}</span>\r\n <button\r\n type=\"button\"\r\n @click.stop=\"handleFieldReset(badge.fieldName)\"\r\n class=\"h-4 w-4 rounded-full hover:bg-destructive/20 hover:text-destructive transition-colors flex items-center justify-center\"\r\n :aria-label=\"`${badge.label} 조건 제거`\"\r\n >\r\n <X class=\"h-3 w-3\" />\r\n </button>\r\n </JBadge>\r\n </div>\r\n </div>\r\n \r\n <JButton\r\n variant=\"outline\"\r\n size=\"sm\"\r\n @click.stop=\"handleReset\"\r\n >\r\n 초기화\r\n </JButton>\r\n </div>\r\n </CardHeader>\r\n \r\n <!-- 폼 내용 -->\r\n <CardContent v-show=\"isExpanded || !collapsible\" class=\"px-6 pb-6 pt-0\">\r\n <JDynamicForm\r\n ref=\"dynamicFormRef\"\r\n :schema=\"schema\"\r\n :model-value=\"localModelValue\"\r\n @update:model-value=\"handleFormValueUpdate\"\r\n @submit=\"handleSubmit\"\r\n />\r\n </CardContent>\r\n </Card>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { computed, ref, reactive, watch } from 'vue'\r\nimport { ChevronDown, X } from 'lucide-vue-next'\r\nimport { Card, CardHeader, CardTitle, CardContent } from '@/components/shadcn'\r\nimport { JButton, JBadge } from '@/components/atoms'\r\nimport JDynamicForm from './JDynamicForm.vue'\r\nimport type { FormSchema, DynamicFormField } from '@/types/dynamic-form'\r\nimport type { ComponentPublicInstance } from 'vue'\r\n\r\ninterface ConditionBadge {\r\n fieldName: string\r\n label: string\r\n value: string\r\n}\r\n\r\nexport interface JSearchPanelProps {\r\n /** 패널 제목 */\r\n title?: string\r\n /** JDynamicForm에 전달할 FormSchema */\r\n schema: FormSchema\r\n /** JDynamicForm의 v-model 값 */\r\n modelValue?: Record<string, any>\r\n /** 기본 접힘 상태 */\r\n defaultCollapsed?: boolean\r\n /** 접기/펼치기 가능 여부 */\r\n collapsible?: boolean\r\n}\r\n\r\nconst props = withDefaults(defineProps<JSearchPanelProps>(), {\r\n title: '조회조건',\r\n defaultCollapsed: false,\r\n collapsible: true,\r\n})\r\n\r\nconst emit = defineEmits<{\r\n 'update:modelValue': [value: Record<string, any>]\r\n 'submit': [values: Record<string, any>]\r\n 'reset': []\r\n}>()\r\n\r\nconst dynamicFormRef = ref<ComponentPublicInstance & { reset: () => void } | null>(null)\r\nconst isExpanded = ref(!props.defaultCollapsed)\r\n\r\n// 로컬 modelValue - reactive로 관리하여 양방향 바인딩\r\nconst localModelValue = reactive<Record<string, any>>(props.modelValue ? { ...props.modelValue } : {})\r\n\r\n// 내부 변경인지 외부 변경인지 구분하는 플래그\r\nlet isInternalUpdate = false\r\n\r\n// props.modelValue 변경 시 localModelValue 동기화 (외부 변경)\r\nwatch(\r\n () => props.modelValue,\r\n (newValue) => {\r\n if (newValue && !isInternalUpdate) {\r\n // 기존 키 중 새 값에 없는 것은 삭제\r\n Object.keys(localModelValue).forEach(key => {\r\n if (!(key in newValue)) {\r\n delete localModelValue[key]\r\n }\r\n })\r\n // 새 값으로 업데이트\r\n Object.assign(localModelValue, newValue)\r\n }\r\n isInternalUpdate = false\r\n },\r\n { deep: true, immediate: true }\r\n)\r\n\r\n// JDynamicForm에서 값이 변경되었을 때 처리\r\nfunction handleFormValueUpdate(value: Record<string, any>) {\r\n // JDynamicForm에서 emit된 값을 localModelValue에 반영\r\n isInternalUpdate = true\r\n Object.assign(localModelValue, value)\r\n // 상위로 emit\r\n emit('update:modelValue', { ...value })\r\n}\r\n\r\n// 모든 필드 가져오기\r\nconst allFields = computed((): DynamicFormField[] => {\r\n if (!props.schema) return []\r\n \r\n const fields: DynamicFormField[] = []\r\n if (props.schema.type === 'simple' && props.schema.fields) {\r\n fields.push(...props.schema.fields)\r\n } else if (props.schema.type === 'sectioned' && props.schema.sections) {\r\n props.schema.sections.forEach(section => {\r\n if (section.fields) fields.push(...section.fields)\r\n })\r\n } else if (props.schema.type === 'wizard' && props.schema.steps) {\r\n props.schema.steps.forEach(step => {\r\n if (step.fields) fields.push(...step.fields)\r\n })\r\n }\r\n return fields\r\n})\r\n\r\n// 조건 Badge 목록 생성\r\nconst conditionBadges = computed((): ConditionBadge[] => {\r\n if (!localModelValue || !props.schema) {\r\n return []\r\n }\r\n\r\n const badges: ConditionBadge[] = []\r\n const formState = localModelValue\r\n\r\n allFields.value.forEach((field) => {\r\n const value = formState[field.controlName]\r\n \r\n // 빈 값 체크 (빈 문자열, null, undefined, 'ALL', 'SELECT' 제외)\r\n if (\r\n value === undefined ||\r\n value === null ||\r\n value === '' ||\r\n value === 'ALL' ||\r\n value === 'SELECT' ||\r\n (field.type === 'checkbox' && value === 'N') ||\r\n (field.type === 'switch' && value === 'N')\r\n ) {\r\n return\r\n }\r\n\r\n // 필드 타입에 따라 값 표시\r\n let displayValue = String(value)\r\n\r\n // 콤보/검색콤보인 경우 옵션의 label 찾기\r\n if ((field.type === 'combo' || field.type === 'searchcombo') && field.options) {\r\n const option = field.options.find(opt => opt.value === value)\r\n if (option) {\r\n displayValue = option.label\r\n }\r\n }\r\n\r\n // 체크박스/스위치는 'Y'일 때만 표시\r\n if (field.type === 'checkbox' || field.type === 'switch') {\r\n if (value === 'Y') {\r\n badges.push({\r\n fieldName: field.controlName,\r\n label: field.label,\r\n value: field.inlineLabel || field.label\r\n })\r\n }\r\n } else {\r\n badges.push({\r\n fieldName: field.controlName,\r\n label: field.label,\r\n value: displayValue\r\n })\r\n }\r\n })\r\n\r\n return badges\r\n})\r\n\r\n// submit 핸들러\r\nfunction handleSubmit(values: Record<string, any>) {\r\n emit('submit', values)\r\n}\r\n\r\n// 전체 초기화 핸들러\r\nfunction handleReset() {\r\n if (dynamicFormRef.value) {\r\n dynamicFormRef.value.reset()\r\n emit('reset')\r\n }\r\n}\r\n\r\n// 필드별 초기화 핸들러\r\nfunction handleFieldReset(fieldName: string) {\r\n if (!localModelValue || !props.schema) return\r\n \r\n const field = allFields.value.find(f => f.controlName === fieldName)\r\n \r\n if (field) {\r\n // 필드 타입에 따라 초기값 설정 - reactive 객체 직접 수정\r\n if (field.type === 'checkbox' || field.type === 'switch') {\r\n localModelValue[fieldName] = 'N'\r\n } else {\r\n localModelValue[fieldName] = ''\r\n }\r\n \r\n // localModelValue 변경 후 상위로 emit하여 JDynamicForm에도 반영\r\n isInternalUpdate = true\r\n emit('update:modelValue', { ...localModelValue })\r\n }\r\n}\r\n</script>\r\n\r\n<style scoped>\r\n/* 필요시 스타일 추가 */\r\n</style>\r\n\r\n"],"names":["props","__props","emit","__emit","dynamicFormRef","ref","isExpanded","localModelValue","reactive","isInternalUpdate","watch","newValue","key","handleFormValueUpdate","value","allFields","computed","fields","section","step","conditionBadges","badges","formState","field","displayValue","option","opt","handleSubmit","values","handleReset","handleFieldReset","fieldName","f","_createBlock","_unref","Card","_createVNode","CardHeader","_createElementVNode","_hoisted_1","_hoisted_2","_createElementBlock","_cache","$event","ChevronDown","_createTextVNode","CardTitle","_openBlock","_hoisted_3","_Fragment","_renderList","badge","JBadge","_toDisplayString","_withModifiers","X","JButton","CardContent","JDynamicForm","_vShow"],"mappings":"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"}
1
+ {"version":3,"file":"JSearchPanel.vue2.js","sources":["../../../../src/components/organisms/JSearchPanel.vue"],"sourcesContent":["<template>\n <Card class=\"w-full\">\n <!-- 헤더: 제목, Badge 목록, 초기화 버튼 -->\n <CardHeader class=\"pt-4 pb-3 px-6\">\n <div class=\"flex items-center justify-between\">\n <div class=\"flex items-center gap-3 flex-1\">\n <button\n v-if=\"collapsible\"\n type=\"button\"\n @click=\"isExpanded = !isExpanded\"\n class=\"flex items-center gap-2 font-semibold hover:text-primary transition-colors\"\n >\n <ChevronDown\n :class=\"['h-4 w-4 transition-transform', isExpanded ? 'rotate-0' : '-rotate-90']\"\n />\n {{ title }}\n </button>\n <CardTitle v-else class=\"mb-0\">{{ title }}</CardTitle>\n \n <!-- 조건 Badge 목록 -->\n <div v-if=\"conditionBadges.length > 0\" class=\"flex flex-wrap items-center gap-2 ml-2\">\n <JBadge\n v-for=\"badge in conditionBadges\"\n :key=\"badge.fieldName\"\n variant=\"secondary\"\n size=\"sm\"\n class=\"flex items-center gap-1.5 pr-1\"\n >\n <span>{{ badge.label }}: {{ badge.value }}</span>\n <button\n type=\"button\"\n @click.stop=\"handleFieldReset(badge.fieldName)\"\n class=\"h-4 w-4 rounded-full hover:bg-destructive/20 hover:text-destructive transition-colors flex items-center justify-center\"\n :aria-label=\"`${badge.label} 조건 제거`\"\n >\n <X class=\"h-3 w-3\" />\n </button>\n </JBadge>\n </div>\n </div>\n \n <JButton\n variant=\"outline\"\n size=\"sm\"\n @click.stop=\"handleReset\"\n >\n 초기화\n </JButton>\n </div>\n </CardHeader>\n \n <!-- 폼 내용 -->\n <CardContent v-show=\"isExpanded || !collapsible\" class=\"px-6 pb-6 pt-0\">\n <JDynamicForm\n ref=\"dynamicFormRef\"\n :schema=\"schema\"\n :model-value=\"localModelValue\"\n @update:model-value=\"handleFormValueUpdate\"\n @submit=\"handleSubmit\"\n />\n </CardContent>\n </Card>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, reactive, watch } from 'vue'\nimport { ChevronDown, X } from 'lucide-vue-next'\nimport { Card, CardHeader, CardTitle, CardContent } from '@/components/shadcn'\nimport { JButton, JBadge } from '@/components/atoms'\nimport JDynamicForm from './JDynamicForm.vue'\nimport type { FormSchema, DynamicFormField } from '@/types/dynamic-form'\nimport type { ComponentPublicInstance } from 'vue'\n\ninterface ConditionBadge {\n fieldName: string\n label: string\n value: string\n}\n\nexport interface JSearchPanelProps {\n /** 패널 제목 */\n title?: string\n /** JDynamicForm에 전달할 FormSchema */\n schema: FormSchema\n /** JDynamicForm의 v-model 값 */\n modelValue?: Record<string, any>\n /** 기본 접힘 상태 */\n defaultCollapsed?: boolean\n /** 접기/펼치기 가능 여부 */\n collapsible?: boolean\n}\n\nconst props = withDefaults(defineProps<JSearchPanelProps>(), {\n title: '조회조건',\n defaultCollapsed: false,\n collapsible: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: Record<string, any>]\n 'submit': [values: Record<string, any>]\n 'reset': []\n}>()\n\nconst dynamicFormRef = ref<ComponentPublicInstance & { reset: () => void } | null>(null)\nconst isExpanded = ref(!props.defaultCollapsed)\n\n// 로컬 modelValue - reactive로 관리하여 양방향 바인딩\nconst localModelValue = reactive<Record<string, any>>(props.modelValue ? { ...props.modelValue } : {})\n\n// 내부 변경인지 외부 변경인지 구분하는 플래그\nlet isInternalUpdate = false\n\n// props.modelValue 변경 시 localModelValue 동기화 (외부 변경)\nwatch(\n () => props.modelValue,\n (newValue) => {\n if (newValue && !isInternalUpdate) {\n // 기존 키 중 새 값에 없는 것은 삭제\n Object.keys(localModelValue).forEach(key => {\n if (!(key in newValue)) {\n delete localModelValue[key]\n }\n })\n // 새 값으로 업데이트\n Object.assign(localModelValue, newValue)\n }\n isInternalUpdate = false\n },\n { deep: true, immediate: true }\n)\n\n// JDynamicForm에서 값이 변경되었을 때 처리\nfunction handleFormValueUpdate(value: Record<string, any>) {\n // JDynamicForm에서 emit된 값을 localModelValue에 반영\n isInternalUpdate = true\n Object.assign(localModelValue, value)\n // 상위로 emit\n emit('update:modelValue', { ...value })\n}\n\n// 모든 필드 가져오기\nconst allFields = computed((): DynamicFormField[] => {\n if (!props.schema) return []\n \n const fields: DynamicFormField[] = []\n if (props.schema.type === 'simple' && props.schema.fields) {\n fields.push(...props.schema.fields)\n } else if (props.schema.type === 'sectioned' && props.schema.sections) {\n props.schema.sections.forEach(section => {\n if (section.fields) fields.push(...section.fields)\n })\n } else if (props.schema.type === 'wizard' && props.schema.steps) {\n props.schema.steps.forEach(step => {\n if (step.fields) fields.push(...step.fields)\n })\n }\n return fields\n})\n\n// 조건 Badge 목록 생성\nconst conditionBadges = computed((): ConditionBadge[] => {\n if (!localModelValue || !props.schema) {\n return []\n }\n\n const badges: ConditionBadge[] = []\n const formState = localModelValue\n\n allFields.value.forEach((field) => {\n const value = formState[field.controlName]\n \n // 빈 값 체크 (빈 문자열, null, undefined, 'ALL', 'SELECT' 제외)\n if (\n value === undefined ||\n value === null ||\n value === '' ||\n value === 'ALL' ||\n value === 'SELECT' ||\n (field.type === 'checkbox' && value === 'N') ||\n (field.type === 'switch' && value === 'N')\n ) {\n return\n }\n\n // 필드 타입에 따라 값 표시\n let displayValue = String(value)\n\n // 콤보/검색콤보인 경우 옵션의 label 찾기\n if ((field.type === 'combo' || field.type === 'searchcombo') && field.options) {\n const option = field.options.find(opt => opt.value === value)\n if (option) {\n displayValue = option.label\n }\n }\n\n // 체크박스/스위치는 'Y'일 때만 표시\n if (field.type === 'checkbox' || field.type === 'switch') {\n if (value === 'Y') {\n badges.push({\n fieldName: field.controlName,\n label: field.label,\n value: field.inlineLabel || field.label\n })\n }\n } else {\n badges.push({\n fieldName: field.controlName,\n label: field.label,\n value: displayValue\n })\n }\n })\n\n return badges\n})\n\n// submit 핸들러\nfunction handleSubmit(values: Record<string, any>) {\n emit('submit', values)\n}\n\n// 전체 초기화 핸들러\nfunction handleReset() {\n if (dynamicFormRef.value) {\n dynamicFormRef.value.reset()\n emit('reset')\n }\n}\n\n// 필드별 초기화 핸들러\nfunction handleFieldReset(fieldName: string) {\n if (!localModelValue || !props.schema) return\n \n const field = allFields.value.find(f => f.controlName === fieldName)\n \n if (field) {\n // 필드 타입에 따라 초기값 설정 - reactive 객체 직접 수정\n if (field.type === 'checkbox' || field.type === 'switch') {\n localModelValue[fieldName] = 'N'\n } else {\n localModelValue[fieldName] = ''\n }\n \n // localModelValue 변경 후 상위로 emit하여 JDynamicForm에도 반영\n isInternalUpdate = true\n emit('update:modelValue', { ...localModelValue })\n }\n}\n</script>\n\n<style scoped>\n/* 필요시 스타일 추가 */\n</style>\n\n"],"names":["props","__props","emit","__emit","dynamicFormRef","ref","isExpanded","localModelValue","reactive","isInternalUpdate","watch","newValue","key","handleFormValueUpdate","value","allFields","computed","fields","section","step","conditionBadges","badges","formState","field","displayValue","option","opt","handleSubmit","values","handleReset","handleFieldReset","fieldName","f","_createBlock","_unref","Card","_createVNode","CardHeader","_createElementVNode","_hoisted_1","_hoisted_2","_createElementBlock","_cache","$event","ChevronDown","_createTextVNode","CardTitle","_openBlock","_hoisted_3","_Fragment","_renderList","badge","JBadge","_toDisplayString","_withModifiers","X","JButton","CardContent","JDynamicForm","_vShow"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),n=require("vue-sonner"),r=e.defineComponent({__name:"Toaster",props:{id:{},invert:{type:Boolean},theme:{},position:{default:"top-center"},closeButtonPosition:{},hotkey:{},richColors:{type:Boolean,default:!0},expand:{type:Boolean,default:!0},duration:{},gap:{},visibleToasts:{},closeButton:{type:Boolean,default:!1},toastOptions:{},class:{},style:{},offset:{},mobileOffset:{},dir:{},swipeDirections:{},icons:{},containerAriaLabel:{}},setup(t){const o=t;return(s,a)=>(e.openBlock(),e.createBlock(e.unref(n.Toaster),e.normalizeProps(e.guardReactiveProps(o)),null,16))}});exports.default=r;
2
+ //# sourceMappingURL=Toaster.vue.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toaster.vue.cjs","sources":["../../../../src/components/shadcn/Toaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { Toaster as Sonner } from 'vue-sonner'\r\nimport type { ToasterProps } from 'vue-sonner'\r\n\r\nconst props = withDefaults(\r\n defineProps<ToasterProps>(),\r\n {\r\n position: 'top-center',\r\n expand: true,\r\n richColors: true,\r\n closeButton: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <Sonner v-bind=\"props\" />\r\n</template>\r\n\r\n"],"names":["props","__props","_openBlock","_createBlock","_unref"],"mappings":"6jBAIA,MAAMA,EAAQC,gBAYZC,YAAA,EAAAC,cAAyBC,EAAAA,uDAATJ,CAAK,CAAA,EAAA,KAAA,EAAA"}
@@ -0,0 +1,36 @@
1
+ import { defineComponent as t, createBlock as n, openBlock as r, unref as s, normalizeProps as a, guardReactiveProps as i } from "vue";
2
+ import { Toaster as l } from "vue-sonner";
3
+ const d = /* @__PURE__ */ t({
4
+ __name: "Toaster",
5
+ props: {
6
+ id: {},
7
+ invert: { type: Boolean },
8
+ theme: {},
9
+ position: { default: "top-center" },
10
+ closeButtonPosition: {},
11
+ hotkey: {},
12
+ richColors: { type: Boolean, default: !0 },
13
+ expand: { type: Boolean, default: !0 },
14
+ duration: {},
15
+ gap: {},
16
+ visibleToasts: {},
17
+ closeButton: { type: Boolean, default: !1 },
18
+ toastOptions: {},
19
+ class: {},
20
+ style: {},
21
+ offset: {},
22
+ mobileOffset: {},
23
+ dir: {},
24
+ swipeDirections: {},
25
+ icons: {},
26
+ containerAriaLabel: {}
27
+ },
28
+ setup(e) {
29
+ const o = e;
30
+ return (p, c) => (r(), n(s(l), a(i(o)), null, 16));
31
+ }
32
+ });
33
+ export {
34
+ d as default
35
+ };
36
+ //# sourceMappingURL=Toaster.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toaster.vue.js","sources":["../../../../src/components/shadcn/Toaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { Toaster as Sonner } from 'vue-sonner'\r\nimport type { ToasterProps } from 'vue-sonner'\r\n\r\nconst props = withDefaults(\r\n defineProps<ToasterProps>(),\r\n {\r\n position: 'top-center',\r\n expand: true,\r\n richColors: true,\r\n closeButton: false,\r\n },\r\n)\r\n</script>\r\n\r\n<template>\r\n <Sonner v-bind=\"props\" />\r\n</template>\r\n\r\n"],"names":["props","__props","_openBlock","_createBlock","_unref"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,UAAMA,IAAQC;sBAYZC,EAAA,GAAAC,EAAyBC,UAATJ,CAAK,CAAA,GAAA,MAAA,EAAA;AAAA;;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./Toaster.vue.cjs");exports.default=e.default;
2
+ //# sourceMappingURL=Toaster.vue2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toaster.vue2.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import f from "./Toaster.vue.js";
2
+ export {
3
+ f as default
4
+ };
5
+ //# sourceMappingURL=Toaster.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toaster.vue2.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("class-variance-authority");require("vue");require("reka-ui");require("@vueuse/core");require("clsx");require("tailwind-merge");require("lucide-vue-next");require("./alert-variants.cjs");require("./avatar-variants.cjs");require("./badge-variants.cjs");require("./button-group-variants.cjs");const r=e.cva("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}});exports.buttonVariants=r;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("class-variance-authority");require("vue");require("reka-ui");require("@vueuse/core");require("clsx");require("tailwind-merge");require("lucide-vue-next");require("./alert-variants.cjs");require("./avatar-variants.cjs");require("./badge-variants.cjs");require("./button-group-variants.cjs");require("vue-sonner");const r=e.cva("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}});exports.buttonVariants=r;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../src/components/shadcn/index.ts"],"sourcesContent":["// Button variants\r\nimport type { VariantProps } from \"class-variance-authority\"\r\nimport { cva } from \"class-variance-authority\"\r\n\r\nexport const buttonVariants = cva(\r\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\r\n outline:\r\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-10 px-4 py-2\",\r\n sm: \"h-9 rounded-md px-3\",\r\n lg: \"h-11 rounded-md px-8\",\r\n icon: \"h-10 w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n },\r\n)\r\n\r\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\r\n\r\n// Accordion\r\nexport { default as Accordion } from \"./Accordion.vue\"\r\nexport { default as AccordionContent } from \"./AccordionContent.vue\"\r\nexport { default as AccordionItem } from \"./AccordionItem.vue\"\r\nexport { default as AccordionTrigger } from \"./AccordionTrigger.vue\"\r\n\r\n// Alert\r\nexport { default as Alert } from \"./Alert.vue\"\r\nexport { default as AlertDescription } from \"./AlertDescription.vue\"\r\nexport { default as AlertTitle } from \"./AlertTitle.vue\"\r\n\r\n// Avatar\r\nexport { default as Avatar } from \"./Avatar.vue\"\r\nexport { default as AvatarFallback } from \"./AvatarFallback.vue\"\r\nexport { default as AvatarImage } from \"./AvatarImage.vue\"\r\n\r\n// Badge\r\nexport { default as Badge } from \"./Badge.vue\"\r\n\r\n// Calendar\r\nexport { default as Calendar } from \"./Calendar.vue\"\r\nexport { default as CalendarCell } from \"./CalendarCell.vue\"\r\nexport { default as CalendarCellTrigger } from \"./CalendarCellTrigger.vue\"\r\nexport { default as CalendarGrid } from \"./CalendarGrid.vue\"\r\nexport { default as CalendarGridBody } from \"./CalendarGridBody.vue\"\r\nexport { default as CalendarGridHead } from \"./CalendarGridHead.vue\"\r\nexport { default as CalendarGridRow } from \"./CalendarGridRow.vue\"\r\nexport { default as CalendarHeadCell } from \"./CalendarHeadCell.vue\"\r\nexport { default as CalendarHeader } from \"./CalendarHeader.vue\"\r\nexport { default as CalendarHeading } from \"./CalendarHeading.vue\"\r\nexport { default as CalendarNextButton } from \"./CalendarNextButton.vue\"\r\nexport { default as CalendarPrevButton } from \"./CalendarPrevButton.vue\"\r\n\r\n// Card\r\nexport { default as Card } from \"./Card.vue\"\r\nexport { default as CardContent } from \"./CardContent.vue\"\r\nexport { default as CardDescription } from \"./CardDescription.vue\"\r\nexport { default as CardFooter } from \"./CardFooter.vue\"\r\nexport { default as CardHeader } from \"./CardHeader.vue\"\r\nexport { default as CardTitle } from \"./CardTitle.vue\"\r\n\r\n// Checkbox\r\nexport { default as Checkbox } from \"./Checkbox.vue\"\r\n\r\n// Combobox\r\nexport { default as Combobox } from \"./Combobox.vue\"\r\nexport { default as ComboboxAnchor } from \"./ComboboxAnchor.vue\"\r\nexport { default as ComboboxEmpty } from \"./ComboboxEmpty.vue\"\r\nexport { default as ComboboxGroup } from \"./ComboboxGroup.vue\"\r\nexport { default as ComboboxInput } from \"./ComboboxInput.vue\"\r\nexport { default as ComboboxItem } from \"./ComboboxItem.vue\"\r\nexport { default as ComboboxList } from \"./ComboboxList.vue\"\r\nexport { default as ComboboxSeparator } from \"./ComboboxSeparator.vue\"\r\nexport { default as ComboboxTrigger } from \"./ComboboxTrigger.vue\"\r\n\r\n// ContextMenu\r\nexport { default as ContextMenu } from \"./ContextMenu.vue\"\r\nexport { default as ContextMenuCheckboxItem } from \"./ContextMenuCheckboxItem.vue\"\r\nexport { default as ContextMenuContent } from \"./ContextMenuContent.vue\"\r\nexport { default as ContextMenuGroup } from \"./ContextMenuGroup.vue\"\r\nexport { default as ContextMenuItem } from \"./ContextMenuItem.vue\"\r\nexport { default as ContextMenuLabel } from \"./ContextMenuLabel.vue\"\r\nexport { default as ContextMenuPortal } from \"./ContextMenuPortal.vue\"\r\nexport { default as ContextMenuRadioGroup } from \"./ContextMenuRadioGroup.vue\"\r\nexport { default as ContextMenuRadioItem } from \"./ContextMenuRadioItem.vue\"\r\nexport { default as ContextMenuSeparator } from \"./ContextMenuSeparator.vue\"\r\nexport { default as ContextMenuShortcut } from \"./ContextMenuShortcut.vue\"\r\nexport { default as ContextMenuSub } from \"./ContextMenuSub.vue\"\r\nexport { default as ContextMenuSubContent } from \"./ContextMenuSubContent.vue\"\r\nexport { default as ContextMenuSubTrigger } from \"./ContextMenuSubTrigger.vue\"\r\nexport { default as ContextMenuTrigger } from \"./ContextMenuTrigger.vue\"\r\n\r\n// Dialog\r\nexport { default as Dialog } from \"./Dialog.vue\"\r\nexport { default as DialogBody } from \"./DialogBody.vue\"\r\nexport { default as DialogContent } from \"./DialogContent.vue\"\r\nexport { default as DialogDescription } from \"./DialogDescription.vue\"\r\nexport { default as DialogFooter } from \"./DialogFooter.vue\"\r\nexport { default as DialogHeader } from \"./DialogHeader.vue\"\r\nexport { default as DialogTitle } from \"./DialogTitle.vue\"\r\n\r\n// Field\r\nexport { default as Field } from \"./Field.vue\"\r\nexport { default as FieldContent } from \"./FieldContent.vue\"\r\nexport { default as FieldDescription } from \"./FieldDescription.vue\"\r\nexport { default as FieldError } from \"./FieldError.vue\"\r\nexport { default as FieldGroup } from \"./FieldGroup.vue\"\r\nexport { default as FieldLabel } from \"./FieldLabel.vue\"\r\nexport { default as FieldLegend } from \"./FieldLegend.vue\"\r\nexport { default as FieldSeparator } from \"./FieldSeparator.vue\"\r\nexport { default as FieldSet } from \"./FieldSet.vue\"\r\nexport { default as FieldTitle } from \"./FieldTitle.vue\"\r\n\r\n// ButtonGroup\r\nexport { default as ButtonGroup } from \"./ButtonGroup.vue\"\r\nexport { default as ButtonGroupSeparator } from \"./ButtonGroupSeparator.vue\"\r\nexport { default as ButtonGroupText } from \"./ButtonGroupText.vue\"\r\n\r\n// Input\r\nexport { default as Button } from \"./Button.vue\"\r\nexport { default as Input } from \"./Input.vue\"\r\n\r\n// Kbd\r\nexport { default as Kbd } from \"./Kbd.vue\"\r\nexport { default as KbdGroup } from \"./KbdGroup.vue\"\r\n\r\n// Label\r\nexport { default as Label } from \"./Label.vue\"\r\n\r\n// Popover\r\nexport { default as Popover } from \"./Popover.vue\"\r\nexport { default as PopoverContent } from \"./PopoverContent.vue\"\r\nexport { default as PopoverTrigger } from \"./PopoverTrigger.vue\"\r\n\r\n// Progress\r\nexport { default as Progress } from \"./Progress.vue\"\r\n\r\n// Radio\r\nexport { default as RadioGroup } from \"./RadioGroup.vue\"\r\nexport { default as RadioGroupItem } from \"./RadioGroupItem.vue\"\r\n\r\n// Select\r\nexport { default as Select } from \"./Select.vue\"\r\nexport { default as SelectContent } from \"./SelectContent.vue\"\r\nexport { default as SelectGroup } from \"./SelectGroup.vue\"\r\nexport { default as SelectItem } from \"./SelectItem.vue\"\r\nexport { default as SelectItemText } from \"./SelectItemText.vue\"\r\nexport { default as SelectLabel } from \"./SelectLabel.vue\"\r\nexport { default as SelectScrollDownButton } from \"./SelectScrollDownButton.vue\"\r\nexport { default as SelectScrollUpButton } from \"./SelectScrollUpButton.vue\"\r\nexport { default as SelectSeparator } from \"./SelectSeparator.vue\"\r\nexport { default as SelectTrigger } from \"./SelectTrigger.vue\"\r\nexport { default as SelectValue } from \"./SelectValue.vue\"\r\n\r\n// Separator\r\nexport { default as Separator } from \"./Separator.vue\"\r\n\r\n// Spinner\r\nexport { default as Spinner } from \"./Spinner.vue\"\r\n\r\n// Switch\r\nexport { default as Switch } from \"./Switch.vue\"\r\n\r\n// Tabs\r\nexport { default as Tabs } from \"./Tabs.vue\"\r\nexport { default as TabsContent } from \"./TabsContent.vue\"\r\nexport { default as TabsList } from \"./TabsList.vue\"\r\nexport { default as TabsTrigger } from \"./TabsTrigger.vue\"\r\n\r\n// Textarea\r\nexport { default as Textarea } from \"./Textarea.vue\"\r\n\r\n\r\n// Tooltip\r\nexport { default as Tooltip } from \"./Tooltip.vue\"\r\nexport { default as TooltipContent } from \"./TooltipContent.vue\"\r\nexport { default as TooltipProvider } from \"./TooltipProvider.vue\"\r\nexport { default as TooltipTrigger } from \"./TooltipTrigger.vue\"\r\n"],"names":["buttonVariants","cva"],"mappings":"mYAIO,MAAMA,EAAiBC,EAAAA,IAC5B,yRACA,CACE,SAAU,CACR,QAAS,CACP,QAAS,yDACT,YACE,qEACF,QACE,iFACF,UACE,+DACF,MAAO,+CACP,KAAM,iDAAA,EAER,KAAM,CACJ,QAAS,iBACT,GAAI,sBACJ,GAAI,uBACJ,KAAM,WAAA,CACR,EAEF,gBAAiB,CACf,QAAS,UACT,KAAM,SAAA,CACR,CAEJ"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/components/shadcn/index.ts"],"sourcesContent":["// Button variants\r\nimport type { VariantProps } from \"class-variance-authority\"\r\nimport { cva } from \"class-variance-authority\"\r\n\r\nexport const buttonVariants = cva(\r\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\r\n outline:\r\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-10 px-4 py-2\",\r\n sm: \"h-9 rounded-md px-3\",\r\n lg: \"h-11 rounded-md px-8\",\r\n icon: \"h-10 w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n },\r\n)\r\n\r\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\r\n\r\n// Accordion\r\nexport { default as Accordion } from \"./Accordion.vue\"\r\nexport { default as AccordionContent } from \"./AccordionContent.vue\"\r\nexport { default as AccordionItem } from \"./AccordionItem.vue\"\r\nexport { default as AccordionTrigger } from \"./AccordionTrigger.vue\"\r\n\r\n// Alert\r\nexport { default as Alert } from \"./Alert.vue\"\r\nexport { default as AlertDescription } from \"./AlertDescription.vue\"\r\nexport { default as AlertTitle } from \"./AlertTitle.vue\"\r\n\r\n// Avatar\r\nexport { default as Avatar } from \"./Avatar.vue\"\r\nexport { default as AvatarFallback } from \"./AvatarFallback.vue\"\r\nexport { default as AvatarImage } from \"./AvatarImage.vue\"\r\n\r\n// Badge\r\nexport { default as Badge } from \"./Badge.vue\"\r\n\r\n// Calendar\r\nexport { default as Calendar } from \"./Calendar.vue\"\r\nexport { default as CalendarCell } from \"./CalendarCell.vue\"\r\nexport { default as CalendarCellTrigger } from \"./CalendarCellTrigger.vue\"\r\nexport { default as CalendarGrid } from \"./CalendarGrid.vue\"\r\nexport { default as CalendarGridBody } from \"./CalendarGridBody.vue\"\r\nexport { default as CalendarGridHead } from \"./CalendarGridHead.vue\"\r\nexport { default as CalendarGridRow } from \"./CalendarGridRow.vue\"\r\nexport { default as CalendarHeadCell } from \"./CalendarHeadCell.vue\"\r\nexport { default as CalendarHeader } from \"./CalendarHeader.vue\"\r\nexport { default as CalendarHeading } from \"./CalendarHeading.vue\"\r\nexport { default as CalendarNextButton } from \"./CalendarNextButton.vue\"\r\nexport { default as CalendarPrevButton } from \"./CalendarPrevButton.vue\"\r\n\r\n// Card\r\nexport { default as Card } from \"./Card.vue\"\r\nexport { default as CardContent } from \"./CardContent.vue\"\r\nexport { default as CardDescription } from \"./CardDescription.vue\"\r\nexport { default as CardFooter } from \"./CardFooter.vue\"\r\nexport { default as CardHeader } from \"./CardHeader.vue\"\r\nexport { default as CardTitle } from \"./CardTitle.vue\"\r\n\r\n// Checkbox\r\nexport { default as Checkbox } from \"./Checkbox.vue\"\r\n\r\n// Combobox\r\nexport { default as Combobox } from \"./Combobox.vue\"\r\nexport { default as ComboboxAnchor } from \"./ComboboxAnchor.vue\"\r\nexport { default as ComboboxEmpty } from \"./ComboboxEmpty.vue\"\r\nexport { default as ComboboxGroup } from \"./ComboboxGroup.vue\"\r\nexport { default as ComboboxInput } from \"./ComboboxInput.vue\"\r\nexport { default as ComboboxItem } from \"./ComboboxItem.vue\"\r\nexport { default as ComboboxList } from \"./ComboboxList.vue\"\r\nexport { default as ComboboxSeparator } from \"./ComboboxSeparator.vue\"\r\nexport { default as ComboboxTrigger } from \"./ComboboxTrigger.vue\"\r\n\r\n// ContextMenu\r\nexport { default as ContextMenu } from \"./ContextMenu.vue\"\r\nexport { default as ContextMenuCheckboxItem } from \"./ContextMenuCheckboxItem.vue\"\r\nexport { default as ContextMenuContent } from \"./ContextMenuContent.vue\"\r\nexport { default as ContextMenuGroup } from \"./ContextMenuGroup.vue\"\r\nexport { default as ContextMenuItem } from \"./ContextMenuItem.vue\"\r\nexport { default as ContextMenuLabel } from \"./ContextMenuLabel.vue\"\r\nexport { default as ContextMenuPortal } from \"./ContextMenuPortal.vue\"\r\nexport { default as ContextMenuRadioGroup } from \"./ContextMenuRadioGroup.vue\"\r\nexport { default as ContextMenuRadioItem } from \"./ContextMenuRadioItem.vue\"\r\nexport { default as ContextMenuSeparator } from \"./ContextMenuSeparator.vue\"\r\nexport { default as ContextMenuShortcut } from \"./ContextMenuShortcut.vue\"\r\nexport { default as ContextMenuSub } from \"./ContextMenuSub.vue\"\r\nexport { default as ContextMenuSubContent } from \"./ContextMenuSubContent.vue\"\r\nexport { default as ContextMenuSubTrigger } from \"./ContextMenuSubTrigger.vue\"\r\nexport { default as ContextMenuTrigger } from \"./ContextMenuTrigger.vue\"\r\n\r\n// Dialog\r\nexport { default as Dialog } from \"./Dialog.vue\"\r\nexport { default as DialogBody } from \"./DialogBody.vue\"\r\nexport { default as DialogContent } from \"./DialogContent.vue\"\r\nexport { default as DialogDescription } from \"./DialogDescription.vue\"\r\nexport { default as DialogFooter } from \"./DialogFooter.vue\"\r\nexport { default as DialogHeader } from \"./DialogHeader.vue\"\r\nexport { default as DialogTitle } from \"./DialogTitle.vue\"\r\n\r\n// Field\r\nexport { default as Field } from \"./Field.vue\"\r\nexport { default as FieldContent } from \"./FieldContent.vue\"\r\nexport { default as FieldDescription } from \"./FieldDescription.vue\"\r\nexport { default as FieldError } from \"./FieldError.vue\"\r\nexport { default as FieldGroup } from \"./FieldGroup.vue\"\r\nexport { default as FieldLabel } from \"./FieldLabel.vue\"\r\nexport { default as FieldLegend } from \"./FieldLegend.vue\"\r\nexport { default as FieldSeparator } from \"./FieldSeparator.vue\"\r\nexport { default as FieldSet } from \"./FieldSet.vue\"\r\nexport { default as FieldTitle } from \"./FieldTitle.vue\"\r\n\r\n// ButtonGroup\r\nexport { default as ButtonGroup } from \"./ButtonGroup.vue\"\r\nexport { default as ButtonGroupSeparator } from \"./ButtonGroupSeparator.vue\"\r\nexport { default as ButtonGroupText } from \"./ButtonGroupText.vue\"\r\n\r\n// Input\r\nexport { default as Button } from \"./Button.vue\"\r\nexport { default as Input } from \"./Input.vue\"\r\n\r\n// Kbd\r\nexport { default as Kbd } from \"./Kbd.vue\"\r\nexport { default as KbdGroup } from \"./KbdGroup.vue\"\r\n\r\n// Label\r\nexport { default as Label } from \"./Label.vue\"\r\n\r\n// Popover\r\nexport { default as Popover } from \"./Popover.vue\"\r\nexport { default as PopoverContent } from \"./PopoverContent.vue\"\r\nexport { default as PopoverTrigger } from \"./PopoverTrigger.vue\"\r\n\r\n// Progress\r\nexport { default as Progress } from \"./Progress.vue\"\r\n\r\n// Radio\r\nexport { default as RadioGroup } from \"./RadioGroup.vue\"\r\nexport { default as RadioGroupItem } from \"./RadioGroupItem.vue\"\r\n\r\n// Select\r\nexport { default as Select } from \"./Select.vue\"\r\nexport { default as SelectContent } from \"./SelectContent.vue\"\r\nexport { default as SelectGroup } from \"./SelectGroup.vue\"\r\nexport { default as SelectItem } from \"./SelectItem.vue\"\r\nexport { default as SelectItemText } from \"./SelectItemText.vue\"\r\nexport { default as SelectLabel } from \"./SelectLabel.vue\"\r\nexport { default as SelectScrollDownButton } from \"./SelectScrollDownButton.vue\"\r\nexport { default as SelectScrollUpButton } from \"./SelectScrollUpButton.vue\"\r\nexport { default as SelectSeparator } from \"./SelectSeparator.vue\"\r\nexport { default as SelectTrigger } from \"./SelectTrigger.vue\"\r\nexport { default as SelectValue } from \"./SelectValue.vue\"\r\n\r\n// Separator\r\nexport { default as Separator } from \"./Separator.vue\"\r\n\r\n// Spinner\r\nexport { default as Spinner } from \"./Spinner.vue\"\r\n\r\n// Switch\r\nexport { default as Switch } from \"./Switch.vue\"\r\n\r\n// Tabs\r\nexport { default as Tabs } from \"./Tabs.vue\"\r\nexport { default as TabsContent } from \"./TabsContent.vue\"\r\nexport { default as TabsList } from \"./TabsList.vue\"\r\nexport { default as TabsTrigger } from \"./TabsTrigger.vue\"\r\n\r\n// Textarea\r\nexport { default as Textarea } from \"./Textarea.vue\"\r\n\r\n\r\n// Tooltip\r\nexport { default as Tooltip } from \"./Tooltip.vue\"\r\nexport { default as TooltipContent } from \"./TooltipContent.vue\"\r\nexport { default as TooltipProvider } from \"./TooltipProvider.vue\"\r\nexport { default as TooltipTrigger } from \"./TooltipTrigger.vue\"\r\n\r\n// Toaster\r\nexport { default as Toaster } from \"./Toaster.vue\""],"names":["buttonVariants","cva"],"mappings":"yZAIO,MAAMA,EAAiBC,EAAAA,IAC5B,yRACA,CACE,SAAU,CACR,QAAS,CACP,QAAS,yDACT,YACE,qEACF,QACE,iFACF,UACE,+DACF,MAAO,+CACP,KAAM,iDAAA,EAER,KAAM,CACJ,QAAS,iBACT,GAAI,sBACJ,GAAI,uBACJ,KAAM,WAAA,CACR,EAEF,gBAAiB,CACf,QAAS,UACT,KAAM,SAAA,CACR,CAEJ"}
@@ -9,6 +9,7 @@ import "./alert-variants.js";
9
9
  import "./avatar-variants.js";
10
10
  import "./badge-variants.js";
11
11
  import "./button-group-variants.js";
12
+ import "vue-sonner";
12
13
  const f = e(
13
14
  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
14
15
  {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/components/shadcn/index.ts"],"sourcesContent":["// Button variants\r\nimport type { VariantProps } from \"class-variance-authority\"\r\nimport { cva } from \"class-variance-authority\"\r\n\r\nexport const buttonVariants = cva(\r\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\r\n outline:\r\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-10 px-4 py-2\",\r\n sm: \"h-9 rounded-md px-3\",\r\n lg: \"h-11 rounded-md px-8\",\r\n icon: \"h-10 w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n },\r\n)\r\n\r\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\r\n\r\n// Accordion\r\nexport { default as Accordion } from \"./Accordion.vue\"\r\nexport { default as AccordionContent } from \"./AccordionContent.vue\"\r\nexport { default as AccordionItem } from \"./AccordionItem.vue\"\r\nexport { default as AccordionTrigger } from \"./AccordionTrigger.vue\"\r\n\r\n// Alert\r\nexport { default as Alert } from \"./Alert.vue\"\r\nexport { default as AlertDescription } from \"./AlertDescription.vue\"\r\nexport { default as AlertTitle } from \"./AlertTitle.vue\"\r\n\r\n// Avatar\r\nexport { default as Avatar } from \"./Avatar.vue\"\r\nexport { default as AvatarFallback } from \"./AvatarFallback.vue\"\r\nexport { default as AvatarImage } from \"./AvatarImage.vue\"\r\n\r\n// Badge\r\nexport { default as Badge } from \"./Badge.vue\"\r\n\r\n// Calendar\r\nexport { default as Calendar } from \"./Calendar.vue\"\r\nexport { default as CalendarCell } from \"./CalendarCell.vue\"\r\nexport { default as CalendarCellTrigger } from \"./CalendarCellTrigger.vue\"\r\nexport { default as CalendarGrid } from \"./CalendarGrid.vue\"\r\nexport { default as CalendarGridBody } from \"./CalendarGridBody.vue\"\r\nexport { default as CalendarGridHead } from \"./CalendarGridHead.vue\"\r\nexport { default as CalendarGridRow } from \"./CalendarGridRow.vue\"\r\nexport { default as CalendarHeadCell } from \"./CalendarHeadCell.vue\"\r\nexport { default as CalendarHeader } from \"./CalendarHeader.vue\"\r\nexport { default as CalendarHeading } from \"./CalendarHeading.vue\"\r\nexport { default as CalendarNextButton } from \"./CalendarNextButton.vue\"\r\nexport { default as CalendarPrevButton } from \"./CalendarPrevButton.vue\"\r\n\r\n// Card\r\nexport { default as Card } from \"./Card.vue\"\r\nexport { default as CardContent } from \"./CardContent.vue\"\r\nexport { default as CardDescription } from \"./CardDescription.vue\"\r\nexport { default as CardFooter } from \"./CardFooter.vue\"\r\nexport { default as CardHeader } from \"./CardHeader.vue\"\r\nexport { default as CardTitle } from \"./CardTitle.vue\"\r\n\r\n// Checkbox\r\nexport { default as Checkbox } from \"./Checkbox.vue\"\r\n\r\n// Combobox\r\nexport { default as Combobox } from \"./Combobox.vue\"\r\nexport { default as ComboboxAnchor } from \"./ComboboxAnchor.vue\"\r\nexport { default as ComboboxEmpty } from \"./ComboboxEmpty.vue\"\r\nexport { default as ComboboxGroup } from \"./ComboboxGroup.vue\"\r\nexport { default as ComboboxInput } from \"./ComboboxInput.vue\"\r\nexport { default as ComboboxItem } from \"./ComboboxItem.vue\"\r\nexport { default as ComboboxList } from \"./ComboboxList.vue\"\r\nexport { default as ComboboxSeparator } from \"./ComboboxSeparator.vue\"\r\nexport { default as ComboboxTrigger } from \"./ComboboxTrigger.vue\"\r\n\r\n// ContextMenu\r\nexport { default as ContextMenu } from \"./ContextMenu.vue\"\r\nexport { default as ContextMenuCheckboxItem } from \"./ContextMenuCheckboxItem.vue\"\r\nexport { default as ContextMenuContent } from \"./ContextMenuContent.vue\"\r\nexport { default as ContextMenuGroup } from \"./ContextMenuGroup.vue\"\r\nexport { default as ContextMenuItem } from \"./ContextMenuItem.vue\"\r\nexport { default as ContextMenuLabel } from \"./ContextMenuLabel.vue\"\r\nexport { default as ContextMenuPortal } from \"./ContextMenuPortal.vue\"\r\nexport { default as ContextMenuRadioGroup } from \"./ContextMenuRadioGroup.vue\"\r\nexport { default as ContextMenuRadioItem } from \"./ContextMenuRadioItem.vue\"\r\nexport { default as ContextMenuSeparator } from \"./ContextMenuSeparator.vue\"\r\nexport { default as ContextMenuShortcut } from \"./ContextMenuShortcut.vue\"\r\nexport { default as ContextMenuSub } from \"./ContextMenuSub.vue\"\r\nexport { default as ContextMenuSubContent } from \"./ContextMenuSubContent.vue\"\r\nexport { default as ContextMenuSubTrigger } from \"./ContextMenuSubTrigger.vue\"\r\nexport { default as ContextMenuTrigger } from \"./ContextMenuTrigger.vue\"\r\n\r\n// Dialog\r\nexport { default as Dialog } from \"./Dialog.vue\"\r\nexport { default as DialogBody } from \"./DialogBody.vue\"\r\nexport { default as DialogContent } from \"./DialogContent.vue\"\r\nexport { default as DialogDescription } from \"./DialogDescription.vue\"\r\nexport { default as DialogFooter } from \"./DialogFooter.vue\"\r\nexport { default as DialogHeader } from \"./DialogHeader.vue\"\r\nexport { default as DialogTitle } from \"./DialogTitle.vue\"\r\n\r\n// Field\r\nexport { default as Field } from \"./Field.vue\"\r\nexport { default as FieldContent } from \"./FieldContent.vue\"\r\nexport { default as FieldDescription } from \"./FieldDescription.vue\"\r\nexport { default as FieldError } from \"./FieldError.vue\"\r\nexport { default as FieldGroup } from \"./FieldGroup.vue\"\r\nexport { default as FieldLabel } from \"./FieldLabel.vue\"\r\nexport { default as FieldLegend } from \"./FieldLegend.vue\"\r\nexport { default as FieldSeparator } from \"./FieldSeparator.vue\"\r\nexport { default as FieldSet } from \"./FieldSet.vue\"\r\nexport { default as FieldTitle } from \"./FieldTitle.vue\"\r\n\r\n// ButtonGroup\r\nexport { default as ButtonGroup } from \"./ButtonGroup.vue\"\r\nexport { default as ButtonGroupSeparator } from \"./ButtonGroupSeparator.vue\"\r\nexport { default as ButtonGroupText } from \"./ButtonGroupText.vue\"\r\n\r\n// Input\r\nexport { default as Button } from \"./Button.vue\"\r\nexport { default as Input } from \"./Input.vue\"\r\n\r\n// Kbd\r\nexport { default as Kbd } from \"./Kbd.vue\"\r\nexport { default as KbdGroup } from \"./KbdGroup.vue\"\r\n\r\n// Label\r\nexport { default as Label } from \"./Label.vue\"\r\n\r\n// Popover\r\nexport { default as Popover } from \"./Popover.vue\"\r\nexport { default as PopoverContent } from \"./PopoverContent.vue\"\r\nexport { default as PopoverTrigger } from \"./PopoverTrigger.vue\"\r\n\r\n// Progress\r\nexport { default as Progress } from \"./Progress.vue\"\r\n\r\n// Radio\r\nexport { default as RadioGroup } from \"./RadioGroup.vue\"\r\nexport { default as RadioGroupItem } from \"./RadioGroupItem.vue\"\r\n\r\n// Select\r\nexport { default as Select } from \"./Select.vue\"\r\nexport { default as SelectContent } from \"./SelectContent.vue\"\r\nexport { default as SelectGroup } from \"./SelectGroup.vue\"\r\nexport { default as SelectItem } from \"./SelectItem.vue\"\r\nexport { default as SelectItemText } from \"./SelectItemText.vue\"\r\nexport { default as SelectLabel } from \"./SelectLabel.vue\"\r\nexport { default as SelectScrollDownButton } from \"./SelectScrollDownButton.vue\"\r\nexport { default as SelectScrollUpButton } from \"./SelectScrollUpButton.vue\"\r\nexport { default as SelectSeparator } from \"./SelectSeparator.vue\"\r\nexport { default as SelectTrigger } from \"./SelectTrigger.vue\"\r\nexport { default as SelectValue } from \"./SelectValue.vue\"\r\n\r\n// Separator\r\nexport { default as Separator } from \"./Separator.vue\"\r\n\r\n// Spinner\r\nexport { default as Spinner } from \"./Spinner.vue\"\r\n\r\n// Switch\r\nexport { default as Switch } from \"./Switch.vue\"\r\n\r\n// Tabs\r\nexport { default as Tabs } from \"./Tabs.vue\"\r\nexport { default as TabsContent } from \"./TabsContent.vue\"\r\nexport { default as TabsList } from \"./TabsList.vue\"\r\nexport { default as TabsTrigger } from \"./TabsTrigger.vue\"\r\n\r\n// Textarea\r\nexport { default as Textarea } from \"./Textarea.vue\"\r\n\r\n\r\n// Tooltip\r\nexport { default as Tooltip } from \"./Tooltip.vue\"\r\nexport { default as TooltipContent } from \"./TooltipContent.vue\"\r\nexport { default as TooltipProvider } from \"./TooltipProvider.vue\"\r\nexport { default as TooltipTrigger } from \"./TooltipTrigger.vue\"\r\n"],"names":["buttonVariants","cva"],"mappings":";;;;;;;;;;;AAIO,MAAMA,IAAiBC;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,QACF,SACE;AAAA,QACF,WACE;AAAA,QACF,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/components/shadcn/index.ts"],"sourcesContent":["// Button variants\r\nimport type { VariantProps } from \"class-variance-authority\"\r\nimport { cva } from \"class-variance-authority\"\r\n\r\nexport const buttonVariants = cva(\r\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\r\n outline:\r\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-10 px-4 py-2\",\r\n sm: \"h-9 rounded-md px-3\",\r\n lg: \"h-11 rounded-md px-8\",\r\n icon: \"h-10 w-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n },\r\n)\r\n\r\nexport type ButtonVariants = VariantProps<typeof buttonVariants>\r\n\r\n// Accordion\r\nexport { default as Accordion } from \"./Accordion.vue\"\r\nexport { default as AccordionContent } from \"./AccordionContent.vue\"\r\nexport { default as AccordionItem } from \"./AccordionItem.vue\"\r\nexport { default as AccordionTrigger } from \"./AccordionTrigger.vue\"\r\n\r\n// Alert\r\nexport { default as Alert } from \"./Alert.vue\"\r\nexport { default as AlertDescription } from \"./AlertDescription.vue\"\r\nexport { default as AlertTitle } from \"./AlertTitle.vue\"\r\n\r\n// Avatar\r\nexport { default as Avatar } from \"./Avatar.vue\"\r\nexport { default as AvatarFallback } from \"./AvatarFallback.vue\"\r\nexport { default as AvatarImage } from \"./AvatarImage.vue\"\r\n\r\n// Badge\r\nexport { default as Badge } from \"./Badge.vue\"\r\n\r\n// Calendar\r\nexport { default as Calendar } from \"./Calendar.vue\"\r\nexport { default as CalendarCell } from \"./CalendarCell.vue\"\r\nexport { default as CalendarCellTrigger } from \"./CalendarCellTrigger.vue\"\r\nexport { default as CalendarGrid } from \"./CalendarGrid.vue\"\r\nexport { default as CalendarGridBody } from \"./CalendarGridBody.vue\"\r\nexport { default as CalendarGridHead } from \"./CalendarGridHead.vue\"\r\nexport { default as CalendarGridRow } from \"./CalendarGridRow.vue\"\r\nexport { default as CalendarHeadCell } from \"./CalendarHeadCell.vue\"\r\nexport { default as CalendarHeader } from \"./CalendarHeader.vue\"\r\nexport { default as CalendarHeading } from \"./CalendarHeading.vue\"\r\nexport { default as CalendarNextButton } from \"./CalendarNextButton.vue\"\r\nexport { default as CalendarPrevButton } from \"./CalendarPrevButton.vue\"\r\n\r\n// Card\r\nexport { default as Card } from \"./Card.vue\"\r\nexport { default as CardContent } from \"./CardContent.vue\"\r\nexport { default as CardDescription } from \"./CardDescription.vue\"\r\nexport { default as CardFooter } from \"./CardFooter.vue\"\r\nexport { default as CardHeader } from \"./CardHeader.vue\"\r\nexport { default as CardTitle } from \"./CardTitle.vue\"\r\n\r\n// Checkbox\r\nexport { default as Checkbox } from \"./Checkbox.vue\"\r\n\r\n// Combobox\r\nexport { default as Combobox } from \"./Combobox.vue\"\r\nexport { default as ComboboxAnchor } from \"./ComboboxAnchor.vue\"\r\nexport { default as ComboboxEmpty } from \"./ComboboxEmpty.vue\"\r\nexport { default as ComboboxGroup } from \"./ComboboxGroup.vue\"\r\nexport { default as ComboboxInput } from \"./ComboboxInput.vue\"\r\nexport { default as ComboboxItem } from \"./ComboboxItem.vue\"\r\nexport { default as ComboboxList } from \"./ComboboxList.vue\"\r\nexport { default as ComboboxSeparator } from \"./ComboboxSeparator.vue\"\r\nexport { default as ComboboxTrigger } from \"./ComboboxTrigger.vue\"\r\n\r\n// ContextMenu\r\nexport { default as ContextMenu } from \"./ContextMenu.vue\"\r\nexport { default as ContextMenuCheckboxItem } from \"./ContextMenuCheckboxItem.vue\"\r\nexport { default as ContextMenuContent } from \"./ContextMenuContent.vue\"\r\nexport { default as ContextMenuGroup } from \"./ContextMenuGroup.vue\"\r\nexport { default as ContextMenuItem } from \"./ContextMenuItem.vue\"\r\nexport { default as ContextMenuLabel } from \"./ContextMenuLabel.vue\"\r\nexport { default as ContextMenuPortal } from \"./ContextMenuPortal.vue\"\r\nexport { default as ContextMenuRadioGroup } from \"./ContextMenuRadioGroup.vue\"\r\nexport { default as ContextMenuRadioItem } from \"./ContextMenuRadioItem.vue\"\r\nexport { default as ContextMenuSeparator } from \"./ContextMenuSeparator.vue\"\r\nexport { default as ContextMenuShortcut } from \"./ContextMenuShortcut.vue\"\r\nexport { default as ContextMenuSub } from \"./ContextMenuSub.vue\"\r\nexport { default as ContextMenuSubContent } from \"./ContextMenuSubContent.vue\"\r\nexport { default as ContextMenuSubTrigger } from \"./ContextMenuSubTrigger.vue\"\r\nexport { default as ContextMenuTrigger } from \"./ContextMenuTrigger.vue\"\r\n\r\n// Dialog\r\nexport { default as Dialog } from \"./Dialog.vue\"\r\nexport { default as DialogBody } from \"./DialogBody.vue\"\r\nexport { default as DialogContent } from \"./DialogContent.vue\"\r\nexport { default as DialogDescription } from \"./DialogDescription.vue\"\r\nexport { default as DialogFooter } from \"./DialogFooter.vue\"\r\nexport { default as DialogHeader } from \"./DialogHeader.vue\"\r\nexport { default as DialogTitle } from \"./DialogTitle.vue\"\r\n\r\n// Field\r\nexport { default as Field } from \"./Field.vue\"\r\nexport { default as FieldContent } from \"./FieldContent.vue\"\r\nexport { default as FieldDescription } from \"./FieldDescription.vue\"\r\nexport { default as FieldError } from \"./FieldError.vue\"\r\nexport { default as FieldGroup } from \"./FieldGroup.vue\"\r\nexport { default as FieldLabel } from \"./FieldLabel.vue\"\r\nexport { default as FieldLegend } from \"./FieldLegend.vue\"\r\nexport { default as FieldSeparator } from \"./FieldSeparator.vue\"\r\nexport { default as FieldSet } from \"./FieldSet.vue\"\r\nexport { default as FieldTitle } from \"./FieldTitle.vue\"\r\n\r\n// ButtonGroup\r\nexport { default as ButtonGroup } from \"./ButtonGroup.vue\"\r\nexport { default as ButtonGroupSeparator } from \"./ButtonGroupSeparator.vue\"\r\nexport { default as ButtonGroupText } from \"./ButtonGroupText.vue\"\r\n\r\n// Input\r\nexport { default as Button } from \"./Button.vue\"\r\nexport { default as Input } from \"./Input.vue\"\r\n\r\n// Kbd\r\nexport { default as Kbd } from \"./Kbd.vue\"\r\nexport { default as KbdGroup } from \"./KbdGroup.vue\"\r\n\r\n// Label\r\nexport { default as Label } from \"./Label.vue\"\r\n\r\n// Popover\r\nexport { default as Popover } from \"./Popover.vue\"\r\nexport { default as PopoverContent } from \"./PopoverContent.vue\"\r\nexport { default as PopoverTrigger } from \"./PopoverTrigger.vue\"\r\n\r\n// Progress\r\nexport { default as Progress } from \"./Progress.vue\"\r\n\r\n// Radio\r\nexport { default as RadioGroup } from \"./RadioGroup.vue\"\r\nexport { default as RadioGroupItem } from \"./RadioGroupItem.vue\"\r\n\r\n// Select\r\nexport { default as Select } from \"./Select.vue\"\r\nexport { default as SelectContent } from \"./SelectContent.vue\"\r\nexport { default as SelectGroup } from \"./SelectGroup.vue\"\r\nexport { default as SelectItem } from \"./SelectItem.vue\"\r\nexport { default as SelectItemText } from \"./SelectItemText.vue\"\r\nexport { default as SelectLabel } from \"./SelectLabel.vue\"\r\nexport { default as SelectScrollDownButton } from \"./SelectScrollDownButton.vue\"\r\nexport { default as SelectScrollUpButton } from \"./SelectScrollUpButton.vue\"\r\nexport { default as SelectSeparator } from \"./SelectSeparator.vue\"\r\nexport { default as SelectTrigger } from \"./SelectTrigger.vue\"\r\nexport { default as SelectValue } from \"./SelectValue.vue\"\r\n\r\n// Separator\r\nexport { default as Separator } from \"./Separator.vue\"\r\n\r\n// Spinner\r\nexport { default as Spinner } from \"./Spinner.vue\"\r\n\r\n// Switch\r\nexport { default as Switch } from \"./Switch.vue\"\r\n\r\n// Tabs\r\nexport { default as Tabs } from \"./Tabs.vue\"\r\nexport { default as TabsContent } from \"./TabsContent.vue\"\r\nexport { default as TabsList } from \"./TabsList.vue\"\r\nexport { default as TabsTrigger } from \"./TabsTrigger.vue\"\r\n\r\n// Textarea\r\nexport { default as Textarea } from \"./Textarea.vue\"\r\n\r\n\r\n// Tooltip\r\nexport { default as Tooltip } from \"./Tooltip.vue\"\r\nexport { default as TooltipContent } from \"./TooltipContent.vue\"\r\nexport { default as TooltipProvider } from \"./TooltipProvider.vue\"\r\nexport { default as TooltipTrigger } from \"./TooltipTrigger.vue\"\r\n\r\n// Toaster\r\nexport { default as Toaster } from \"./Toaster.vue\""],"names":["buttonVariants","cva"],"mappings":";;;;;;;;;;;;AAIO,MAAMA,IAAiBC;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,QACF,SACE;AAAA,QACF,WACE;AAAA,QACF,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,MAER,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;"}