@j-solution/components 1.9.0 → 1.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/assets/{jwms-portal-frontend-Ct2Tc7yj.css → jwms-portal-frontend-DQAXe8y7.css} +1 -1
- package/assets/styles/j-components.css +1 -1
- package/assets/styles/main.css +29 -29
- package/components/atoms/JAvatar.vue.cjs.map +1 -1
- package/components/atoms/JAvatar.vue.js.map +1 -1
- package/components/atoms/JBadge.vue.cjs.map +1 -1
- package/components/atoms/JBadge.vue.js.map +1 -1
- package/components/atoms/JCombo.vue.cjs.map +1 -1
- package/components/atoms/JCombo.vue.js.map +1 -1
- package/components/atoms/JDatepicker.vue.cjs.map +1 -1
- package/components/atoms/JDatepicker.vue.js.map +1 -1
- package/components/atoms/JDivider.vue.cjs.map +1 -1
- package/components/atoms/JDivider.vue.js.map +1 -1
- package/components/atoms/JEditor.vue.cjs +1 -1
- package/components/atoms/JEditor.vue.js +2 -2
- package/components/atoms/JEditor.vue2.cjs.map +1 -1
- package/components/atoms/JEditor.vue2.js.map +1 -1
- package/components/atoms/JGrid.vue.cjs +1 -1
- package/components/atoms/JGrid.vue.js +1 -1
- package/components/atoms/JGrid.vue2.cjs +1 -1
- package/components/atoms/JGrid.vue2.cjs.map +1 -1
- package/components/atoms/JGrid.vue2.js +81 -85
- package/components/atoms/JGrid.vue2.js.map +1 -1
- package/components/atoms/JIcon.vue.cjs.map +1 -1
- package/components/atoms/JIcon.vue.js.map +1 -1
- package/components/atoms/JImage.vue.cjs.map +1 -1
- package/components/atoms/JImage.vue.js.map +1 -1
- package/components/atoms/JKbd.vue.cjs.map +1 -1
- package/components/atoms/JKbd.vue.js.map +1 -1
- package/components/atoms/JPreview.vue.cjs +1 -1
- package/components/atoms/JPreview.vue.js +7 -7
- package/components/atoms/JPreview.vue2.cjs.map +1 -1
- package/components/atoms/JPreview.vue2.js.map +1 -1
- package/components/atoms/JProgress.vue.cjs.map +1 -1
- package/components/atoms/JProgress.vue.js.map +1 -1
- package/components/atoms/JRadio.vue.cjs.map +1 -1
- package/components/atoms/JRadio.vue.js.map +1 -1
- package/components/atoms/JSearchCombo.vue.cjs.map +1 -1
- package/components/atoms/JSearchCombo.vue.js.map +1 -1
- package/components/atoms/JSectionTitle.vue2.cjs +1 -1
- package/components/atoms/JSectionTitle.vue2.cjs.map +1 -1
- package/components/atoms/JSectionTitle.vue2.js +5 -8
- package/components/atoms/JSectionTitle.vue2.js.map +1 -1
- package/components/atoms/JSpinner.vue.cjs.map +1 -1
- package/components/atoms/JSpinner.vue.js.map +1 -1
- package/components/atoms/JToast.vue.cjs.map +1 -1
- package/components/atoms/JToast.vue.js.map +1 -1
- package/components/atoms/JTooltip.vue.cjs.map +1 -1
- package/components/atoms/JTooltip.vue.js.map +1 -1
- package/components/molecules/JAlert.vue.cjs +1 -1
- package/components/molecules/JAlert.vue.cjs.map +1 -1
- package/components/molecules/JAlert.vue.js +2 -5
- package/components/molecules/JAlert.vue.js.map +1 -1
- package/components/molecules/JBreadcrumb.vue.cjs.map +1 -1
- package/components/molecules/JBreadcrumb.vue.js.map +1 -1
- package/components/molecules/JEmptyState.vue2.cjs +1 -1
- package/components/molecules/JEmptyState.vue2.cjs.map +1 -1
- package/components/molecules/JEmptyState.vue2.js +15 -18
- package/components/molecules/JEmptyState.vue2.js.map +1 -1
- package/components/molecules/JFormField.vue2.cjs +1 -1
- package/components/molecules/JFormField.vue2.cjs.map +1 -1
- package/components/molecules/JFormField.vue2.js +2 -5
- package/components/molecules/JFormField.vue2.js.map +1 -1
- package/components/molecules/JTitlebar.vue.cjs +1 -1
- package/components/molecules/JTitlebar.vue.cjs.map +1 -1
- package/components/molecules/JTitlebar.vue.js +16 -19
- package/components/molecules/JTitlebar.vue.js.map +1 -1
- package/components/organisms/JDynamicForm.vue2.cjs +1 -1
- package/components/organisms/JDynamicForm.vue2.cjs.map +1 -1
- package/components/organisms/JDynamicForm.vue2.js +2 -5
- package/components/organisms/JDynamicForm.vue2.js.map +1 -1
- package/components/organisms/JFilterBar.vue.cjs +1 -1
- package/components/organisms/JFilterBar.vue.js +2 -2
- package/components/organisms/JFilterBar.vue2.cjs.map +1 -1
- package/components/organisms/JFilterBar.vue2.js.map +1 -1
- package/components/organisms/JFormModal.vue.cjs +1 -1
- package/components/organisms/JFormModal.vue.cjs.map +1 -1
- package/components/organisms/JFormModal.vue.js +14 -17
- package/components/organisms/JFormModal.vue.js.map +1 -1
- package/components/organisms/JModal.vue.cjs +1 -1
- package/components/organisms/JModal.vue.cjs.map +1 -1
- package/components/organisms/JModal.vue.js +2 -5
- package/components/organisms/JModal.vue.js.map +1 -1
- package/components/organisms/JSearchPanel.vue2.cjs +1 -1
- package/components/organisms/JSearchPanel.vue2.cjs.map +1 -1
- package/components/organisms/JSearchPanel.vue2.js +20 -23
- package/components/organisms/JSearchPanel.vue2.js.map +1 -1
- package/components/organisms/JSidebar/JSidebar.vue.cjs.map +1 -1
- package/components/organisms/JSidebar/JSidebar.vue.js.map +1 -1
- package/components/organisms/JSidebar/JSidebarGroup.vue.cjs.map +1 -1
- package/components/organisms/JSidebar/JSidebarGroup.vue.js.map +1 -1
- package/components/organisms/JSidebar/JSidebarItem.vue.cjs.map +1 -1
- package/components/organisms/JSidebar/JSidebarItem.vue.js.map +1 -1
- package/components/organisms/JSidebarAdvanced.vue.cjs +1 -1
- package/components/organisms/JSidebarAdvanced.vue.js +7 -7
- package/components/organisms/JSidebarAdvanced.vue2.cjs.map +1 -1
- package/components/organisms/JSidebarAdvanced.vue2.js.map +1 -1
- package/components/organisms/JSidebarSimple.vue.cjs +1 -1
- package/components/organisms/JSidebarSimple.vue.js +2 -2
- package/components/organisms/JSidebarSimple.vue2.cjs.map +1 -1
- package/components/organisms/JSidebarSimple.vue2.js.map +1 -1
- package/components/shadcn/AccordionTrigger.vue.cjs.map +1 -1
- package/components/shadcn/AccordionTrigger.vue.js.map +1 -1
- package/components/shadcn/CardDescription.vue.cjs.map +1 -1
- package/components/shadcn/CardDescription.vue.js.map +1 -1
- package/components/shadcn/CardFooter.vue.cjs.map +1 -1
- package/components/shadcn/CardFooter.vue.js.map +1 -1
- package/components/shadcn/CardTitle.vue.cjs.map +1 -1
- package/components/shadcn/CardTitle.vue.js.map +1 -1
- package/components/shadcn/Checkbox.vue.cjs.map +1 -1
- package/components/shadcn/Checkbox.vue.js.map +1 -1
- package/components/shadcn/Combobox.vue.cjs.map +1 -1
- package/components/shadcn/Combobox.vue.js.map +1 -1
- package/components/shadcn/ComboboxAnchor.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxAnchor.vue.js.map +1 -1
- package/components/shadcn/ComboboxEmpty.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxEmpty.vue.js.map +1 -1
- package/components/shadcn/ComboboxGroup.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxGroup.vue.js.map +1 -1
- package/components/shadcn/ComboboxInput.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxInput.vue.js.map +1 -1
- package/components/shadcn/ComboboxItem.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxItem.vue.js.map +1 -1
- package/components/shadcn/ComboboxList.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxList.vue.js.map +1 -1
- package/components/shadcn/ComboboxTrigger.vue.cjs.map +1 -1
- package/components/shadcn/ComboboxTrigger.vue.js.map +1 -1
- package/components/shadcn/ContextMenu.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenu.vue.js.map +1 -1
- package/components/shadcn/ContextMenuContent.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuContent.vue.js.map +1 -1
- package/components/shadcn/ContextMenuGroup.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuGroup.vue.js.map +1 -1
- package/components/shadcn/ContextMenuItem.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuItem.vue.js.map +1 -1
- package/components/shadcn/ContextMenuLabel.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuLabel.vue.js.map +1 -1
- package/components/shadcn/ContextMenuSeparator.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuSeparator.vue.js.map +1 -1
- package/components/shadcn/ContextMenuSub.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuSub.vue.js.map +1 -1
- package/components/shadcn/ContextMenuSubContent.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuSubContent.vue.js.map +1 -1
- package/components/shadcn/ContextMenuSubTrigger.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuSubTrigger.vue.js.map +1 -1
- package/components/shadcn/ContextMenuTrigger.vue.cjs.map +1 -1
- package/components/shadcn/ContextMenuTrigger.vue.js.map +1 -1
- package/components/shadcn/Field.vue.cjs.map +1 -1
- package/components/shadcn/Field.vue.js.map +1 -1
- package/components/shadcn/FieldContent.vue.cjs.map +1 -1
- package/components/shadcn/FieldContent.vue.js.map +1 -1
- package/components/shadcn/FieldDescription.vue.cjs.map +1 -1
- package/components/shadcn/FieldDescription.vue.js.map +1 -1
- package/components/shadcn/FieldError.vue.cjs.map +1 -1
- package/components/shadcn/FieldError.vue.js.map +1 -1
- package/components/shadcn/FieldGroup.vue.cjs.map +1 -1
- package/components/shadcn/FieldGroup.vue.js.map +1 -1
- package/components/shadcn/FieldLabel.vue.cjs.map +1 -1
- package/components/shadcn/FieldLabel.vue.js.map +1 -1
- package/components/shadcn/Label.vue.cjs.map +1 -1
- package/components/shadcn/Label.vue.js.map +1 -1
- package/components/shadcn/RadioGroup.vue.cjs.map +1 -1
- package/components/shadcn/RadioGroup.vue.js.map +1 -1
- package/components/shadcn/RadioGroupItem.vue.cjs.map +1 -1
- package/components/shadcn/RadioGroupItem.vue.js.map +1 -1
- package/components/shadcn/Select.vue.cjs.map +1 -1
- package/components/shadcn/Select.vue.js.map +1 -1
- package/components/shadcn/SelectContent.vue.cjs.map +1 -1
- package/components/shadcn/SelectContent.vue.js.map +1 -1
- package/components/shadcn/SelectGroup.vue.cjs.map +1 -1
- package/components/shadcn/SelectGroup.vue.js.map +1 -1
- package/components/shadcn/SelectItem.vue.cjs.map +1 -1
- package/components/shadcn/SelectItem.vue.js.map +1 -1
- package/components/shadcn/SelectLabel.vue.cjs.map +1 -1
- package/components/shadcn/SelectLabel.vue.js.map +1 -1
- package/components/shadcn/SelectScrollDownButton.vue2.cjs.map +1 -1
- package/components/shadcn/SelectScrollDownButton.vue2.js.map +1 -1
- package/components/shadcn/SelectScrollUpButton.vue2.cjs.map +1 -1
- package/components/shadcn/SelectScrollUpButton.vue2.js.map +1 -1
- package/components/shadcn/SelectValue.vue.cjs.map +1 -1
- package/components/shadcn/SelectValue.vue.js.map +1 -1
- package/components/shadcn/Separator.vue.cjs.map +1 -1
- package/components/shadcn/Separator.vue.js.map +1 -1
- package/components/shadcn/Switch.vue.cjs.map +1 -1
- package/components/shadcn/Switch.vue.js.map +1 -1
- package/components/shadcn/Tabs.vue.cjs.map +1 -1
- package/components/shadcn/Tabs.vue.js.map +1 -1
- package/components/shadcn/TabsTrigger.vue.cjs.map +1 -1
- package/components/shadcn/TabsTrigger.vue.js.map +1 -1
- package/components/shadcn/Toaster.vue.cjs.map +1 -1
- package/components/shadcn/Toaster.vue.js.map +1 -1
- package/components/shadcn/resizable/ResizableHandle.vue.cjs.map +1 -1
- package/components/shadcn/resizable/ResizableHandle.vue.js.map +1 -1
- package/components/shadcn/resizable/ResizablePanelGroup.vue.cjs.map +1 -1
- package/components/shadcn/resizable/ResizablePanelGroup.vue.js.map +1 -1
- package/lib/styleTypePreset.cjs.map +1 -1
- package/lib/styleTypePreset.js.map +1 -1
- package/lib/theme-utils.cjs.map +1 -1
- package/lib/theme-utils.js.map +1 -1
- package/package.json +1 -1
- package/tailwind.config.js +81 -81
- package/types/index.d.ts +46 -46
- package/types/sidebar.types.cjs.map +1 -1
- package/types/sidebar.types.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarAdvanced.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useRoute } from 'vue-router'\r\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\r\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\r\nimport JInput from '@/components/atoms/JInput.vue'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport { cn } from '@/lib/utils'\r\n\r\n/**\r\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\r\n * Advanced Sidebar Component\r\n * \r\n * @description\r\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\r\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarAdvanced\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * :favorites=\"favoriteMenuKeys\"\r\n * @menu-click=\"handleMenuClick\"\r\n * @favorite-change=\"handleFavoriteChange\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 22,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"입고 등록\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 221,\r\n * \"path\": \"/inventory/receiving/register\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype TabType = 'menu' | 'favorites'\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 즐겨찾기 메뉴 키 목록 */\r\n favorites?: (number | string)[]\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n favorites: () => [],\r\n styletype: 'minimal',\r\n width: '280px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n /** 즐겨찾기 변경 이벤트 */\r\n favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성 탭\r\n */\r\nconst activeTab = ref<TabType>('menu')\r\n\r\n/**\r\n * 검색어\r\n */\r\nconst searchQuery = ref('')\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\r\n * 즐겨찾기 메뉴 아이템 목록\r\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\r\n */\r\nconst favoriteMenuItems = computed(() => {\r\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\r\n return []\r\n }\r\n\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\r\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\r\n * menuType L(Link)만 포함하고 F(Folder)는 제외\r\n */\r\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\r\n\r\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\r\n if (isFavorite && item.menuType === 'L') {\r\n result.push({\r\n ...item,\r\n children: undefined, // children 제거하여 1단계로만 표시\r\n })\r\n }\r\n\r\n // 하위 메뉴도 재귀적으로 탐색\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const childFavorites = flattenFavorites(item.children)\r\n result.push(...childFavorites)\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return flattenFavorites(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색어로 필터링된 메뉴 아이템\r\n * 재귀적으로 children까지 검색\r\n */\r\nconst filteredMenuItems = computed(() => {\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return props.menuItems\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 검색\r\n */\r\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\r\n\r\n // 하위 메뉴 검색\r\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n filteredChildren = searchInMenu(item.children)\r\n }\r\n\r\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\r\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\r\n result.push({\r\n ...item,\r\n children: filteredChildren,\r\n })\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return searchInMenu(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색 결과에 따라 부모 메뉴 자동 확장\r\n * computed 외부에서 watch를 통해 처리\r\n */\r\nwatch(\r\n () => filteredMenuItems.value,\r\n (filtered) => {\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return\r\n }\r\n\r\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\r\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\r\n const keysToExpand = new Set<number | string>()\r\n\r\n const traverse = (menuItems: SidebarMenuItem[]): void => {\r\n if (!Array.isArray(menuItems)) {\r\n return\r\n }\r\n\r\n for (const item of menuItems) {\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const key = item.menuKey || item.label\r\n keysToExpand.add(key)\r\n traverse(item.children)\r\n }\r\n }\r\n }\r\n\r\n traverse(items)\r\n return keysToExpand\r\n }\r\n\r\n const keysToExpand = findParentsWithMatches(filtered)\r\n keysToExpand.forEach(key => {\r\n expandedKeys.value.add(key)\r\n })\r\n },\r\n { immediate: false }\r\n)\r\n\r\n/**\r\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\r\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\r\n */\r\nconst filteredFavoriteItems = computed(() => {\r\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return favoriteMenuItems.value\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\r\n return favoriteMenuItems.value.filter((item) =>\r\n item.label?.toLowerCase().includes(query) ?? false\r\n )\r\n})\r\n\r\n\r\n/**\r\n * 탭 변경 핸들러\r\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\r\n */\r\nconst handleTabChange = (tab: TabType) => {\r\n if (activeTab.value !== tab) {\r\n activeTab.value = tab\r\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\r\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\r\n searchQuery.value = ''\r\n }\r\n}\r\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\r\n * 즐겨찾기 토글 핸들러\r\n */\r\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\r\n if (!menuKey) return\r\n\r\n const isFavorite = props.favorites?.includes(menuKey) ?? false\r\n emit('favoriteChange', menuKey, !isFavorite)\r\n}\r\n\r\n/**\r\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\r\n */\r\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n if (key === targetKey) {\r\n return item\r\n }\r\n if (item.children && item.children.length > 0) {\r\n const found = findMenuItemByKey(item.children, targetKey)\r\n if (found) return found\r\n }\r\n }\r\n return null\r\n}\r\n\r\n/**\r\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\r\n */\r\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\r\n if (!menuKey) return false\r\n if (!props.favorites?.includes(menuKey)) return false\r\n \r\n // menuType이 L인 경우만 즐겨찾기로 인정\r\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\r\n return menuItem?.menuType === 'L'\r\n}\r\n\r\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n tabContainerClass: string\n tabButtonClass: string\n searchContainerClass: string\n menuContainerClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50',\n searchContainerClass: 'p-1.5 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1.5 space-y-0.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2',\n searchContainerClass: 'p-1 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-0.5',\n },\n}\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 */\r\nconst rootClasses = computed(() => {\r\n return cn(\r\n preset.value.containerClass,\r\n props.class\r\n )\r\n})\r\n</script>\r\n\r\n<template>\r\n <Transition name=\"slide\">\r\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\r\n <!-- 탭 헤더 -->\r\n <div :class=\"preset.tabContainerClass\">\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'menu'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('menu')\"\r\n >\r\n 기본메뉴\r\n </button>\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'favorites'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('favorites')\"\r\n >\r\n 즐겨찾기\r\n </button>\r\n </div>\r\n\r\n <!-- 검색 영역 -->\r\n <div :class=\"preset.searchContainerClass\">\r\n <div class=\"relative\">\r\n <JIcon\r\n name=\"search\"\r\n size=\"sm\"\r\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\r\n />\r\n <JInput\r\n v-model=\"searchQuery\"\r\n placeholder=\"메뉴 검색...\"\r\n :class=\"cn(\r\n 'pl-8',\r\n props.styletype === 'minimal' && 'h-8 text-xs'\r\n )\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 메뉴 목록 -->\r\n <div :class=\"preset.menuContainerClass\">\r\n <template v-if=\"activeTab === 'menu'\">\r\n <template v-if=\"filteredMenuItems.length > 0\">\r\n <div\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n class=\"flex items-center group\"\r\n >\r\n <JDynamicMenuItem\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :favorites=\"favorites\"\r\n :on-favorite-toggle=\"handleFavoriteToggle\"\r\n :is-favorite=\"isFavorite\"\r\n :styletype=\"styletype\"\r\n class=\"flex-1\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">검색 결과가 없습니다.</p>\n </div>\n </template>\n\n <template v-else>\n <template v-if=\"filteredFavoriteItems.length > 0\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredFavoriteItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">즐겨찾기가 없습니다.</p>\n </div>\n </template>\r\n </div>\r\n </aside>\r\n </Transition>\r\n</template>\r\n\r\n<style scoped>\r\n.slide-enter-active,\r\n.slide-leave-active {\r\n transition: transform 0.3s ease, opacity 0.3s ease;\r\n}\r\n\r\n.slide-enter-from,\r\n.slide-leave-to {\r\n transform: translateX(-100%);\r\n opacity: 0;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","route","useRoute","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JSidebarAdvanced.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport JInput from '@/components/atoms/JInput.vue'\nimport JIcon from '@/components/atoms/JIcon.vue'\nimport { cn } from '@/lib/utils'\n\n/**\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\n * Advanced Sidebar Component\n * \n * @description\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\n * \n * @example\n * ```vue\n * <JSidebarAdvanced\n * :menu-items=\"menuItems\"\n * :permissions=\"userPermissions\"\n * :favorites=\"favoriteMenuKeys\"\n * @menu-click=\"handleMenuClick\"\n * @favorite-change=\"handleFavoriteChange\"\n * />\n * ```\n * \n * @example JSON 메뉴 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"대시보드\",\n * \"icon\": \"house\",\n * \"menuType\": \"L\",\n * \"menuKey\": 1,\n * \"path\": \"/dashboard\"\n * },\n * {\n * \"label\": \"재고 관리\",\n * \"icon\": \"package\",\n * \"menuType\": \"F\",\n * \"menuKey\": 2,\n * \"children\": [\n * {\n * \"label\": \"재고 현황\",\n * \"menuType\": \"L\",\n * \"menuKey\": 21,\n * \"path\": \"/inventory/status\"\n * },\n * {\n * \"label\": \"입고 관리\",\n * \"menuType\": \"F\",\n * \"menuKey\": 22,\n * \"children\": [\n * {\n * \"label\": \"입고 등록\",\n * \"menuType\": \"L\",\n * \"menuKey\": 221,\n * \"path\": \"/inventory/receiving/register\"\n * }\n * ]\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype TabType = 'menu' | 'favorites'\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 메뉴 아이템 목록 */\n menuItems: SidebarMenuItem[]\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 즐겨찾기 메뉴 키 목록 */\n favorites?: (number | string)[]\n /** 스타일 타입 */\n styletype?: StyleType\n /** 추가 CSS 클래스 */\n class?: string\n /** 너비 */\n width?: string\n /** 표시 여부 */\n isVisible?: boolean\n }>(),\n {\n permissions: () => [],\n favorites: () => [],\n styletype: 'minimal',\n width: '280px',\n isVisible: true,\n },\n)\n\nconst emit = defineEmits<{\n /** 메뉴 클릭 이벤트 */\n menuClick: [event: MenuClickEvent]\n /** 즐겨찾기 변경 이벤트 */\n favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\n}>()\n\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\nconst route = useRoute()\n\n/**\n * 현재 활성 탭\n */\nconst activeTab = ref<TabType>('menu')\n\n/**\n * 검색어\n */\nconst searchQuery = ref('')\n\n/**\n * 현재 활성화된 경로\n */\nconst activePath = computed(() => route.path)\n\n/**\n * 확장된 메뉴 키 목록\n */\nconst expandedKeys = ref<Set<number | string>>(new Set())\n\n/**\n * 즐겨찾기 메뉴 아이템 목록\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\n */\nconst favoriteMenuItems = computed(() => {\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\n return []\n }\n\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\n return []\n }\n\n /**\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\n * menuType L(Link)만 포함하고 F(Folder)는 제외\n */\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\n const result: SidebarMenuItem[] = []\n\n if (!Array.isArray(items)) {\n return result\n }\n\n for (const item of items) {\n const key = item.menuKey || item.label\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\n\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\n if (isFavorite && item.menuType === 'L') {\n result.push({\n ...item,\n children: undefined, // children 제거하여 1단계로만 표시\n })\n }\n\n // 하위 메뉴도 재귀적으로 탐색\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n const childFavorites = flattenFavorites(item.children)\n result.push(...childFavorites)\n }\n }\n\n return result\n }\n\n return flattenFavorites(props.menuItems)\n})\n\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\n return []\n }\n\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return props.menuItems\n }\n\n const query = searchQuery.value.toLowerCase().trim()\n\n /**\n * 메뉴 아이템을 재귀적으로 검색\n */\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\n const result: SidebarMenuItem[] = []\n\n if (!Array.isArray(items)) {\n return result\n }\n\n for (const item of items) {\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\n\n // 하위 메뉴 검색\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n filteredChildren = searchInMenu(item.children)\n }\n\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\n result.push({\n ...item,\n children: filteredChildren,\n })\n }\n }\n\n return result\n }\n\n return searchInMenu(props.menuItems)\n})\n\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\n const keysToExpand = new Set<number | string>()\n\n const traverse = (menuItems: SidebarMenuItem[]): void => {\n if (!Array.isArray(menuItems)) {\n return\n }\n\n for (const item of menuItems) {\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n const key = item.menuKey || item.label\n keysToExpand.add(key)\n traverse(item.children)\n }\n }\n }\n\n traverse(items)\n return keysToExpand\n }\n\n const keysToExpand = findParentsWithMatches(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\n/**\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\n */\nconst filteredFavoriteItems = computed(() => {\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\n return []\n }\n\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return favoriteMenuItems.value\n }\n\n const query = searchQuery.value.toLowerCase().trim()\n\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\n return favoriteMenuItems.value.filter((item) =>\n item.label?.toLowerCase().includes(query) ?? false\n )\n})\n\n\n/**\n * 탭 변경 핸들러\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\n */\nconst handleTabChange = (tab: TabType) => {\n if (activeTab.value !== tab) {\n activeTab.value = tab\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\n searchQuery.value = ''\n }\n}\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n if (expanded) {\n expandedKeys.value.add(menuKey)\n } else {\n expandedKeys.value.delete(menuKey)\n }\n}\n\n/**\n * 메뉴 클릭 핸들러\n */\nconst handleMenuClick = (event: MenuClickEvent) => {\n emit('menuClick', event)\n}\n\n/**\n * 즐겨찾기 토글 핸들러\n */\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\n if (!menuKey) return\n\n const isFavorite = props.favorites?.includes(menuKey) ?? false\n emit('favoriteChange', menuKey, !isFavorite)\n}\n\n/**\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\n */\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\n for (const item of items) {\n const key = item.menuKey || item.label\n if (key === targetKey) {\n return item\n }\n if (item.children && item.children.length > 0) {\n const found = findMenuItemByKey(item.children, targetKey)\n if (found) return found\n }\n }\n return null\n}\n\n/**\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\n */\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\n if (!menuKey) return false\n if (!props.favorites?.includes(menuKey)) return false\n \n // menuType이 L인 경우만 즐겨찾기로 인정\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\n return menuItem?.menuType === 'L'\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n tabContainerClass: string\n tabButtonClass: string\n searchContainerClass: string\n menuContainerClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50',\n searchContainerClass: 'p-1.5 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1.5 space-y-0.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2',\n searchContainerClass: 'p-1 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-0.5',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * 루트 클래스\n */\nconst rootClasses = computed(() => {\n return cn(\n preset.value.containerClass,\n props.class\n )\n})\n</script>\n\n<template>\n <Transition name=\"slide\">\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\n <!-- 탭 헤더 -->\n <div :class=\"preset.tabContainerClass\">\n <button\n :class=\"cn(\n preset.tabButtonClass,\n activeTab === 'menu'\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n )\"\n @click=\"handleTabChange('menu')\"\n >\n 기본메뉴\n </button>\n <button\n :class=\"cn(\n preset.tabButtonClass,\n activeTab === 'favorites'\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n )\"\n @click=\"handleTabChange('favorites')\"\n >\n 즐겨찾기\n </button>\n </div>\n\n <!-- 검색 영역 -->\n <div :class=\"preset.searchContainerClass\">\n <div class=\"relative\">\n <JIcon\n name=\"search\"\n size=\"sm\"\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <JInput\n v-model=\"searchQuery\"\n placeholder=\"메뉴 검색...\"\n :class=\"cn(\n 'pl-8',\n props.styletype === 'minimal' && 'h-8 text-xs'\n )\"\n />\n </div>\n </div>\n\n <!-- 메뉴 목록 -->\n <div :class=\"preset.menuContainerClass\">\n <template v-if=\"activeTab === 'menu'\">\n <template v-if=\"filteredMenuItems.length > 0\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.menuKey || item.label || index\"\n class=\"flex items-center group\"\n >\n <JDynamicMenuItem\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :favorites=\"favorites\"\n :on-favorite-toggle=\"handleFavoriteToggle\"\n :is-favorite=\"isFavorite\"\n :styletype=\"styletype\"\n class=\"flex-1\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">검색 결과가 없습니다.</p>\n </div>\n </template>\n\n <template v-else>\n <template v-if=\"filteredFavoriteItems.length > 0\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredFavoriteItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">즐겨찾기가 없습니다.</p>\n </div>\n </template>\n </div>\n </aside>\n </Transition>\n</template>\n\n<style scoped>\n.slide-enter-active,\n.slide-leave-active {\n transition: transform 0.3s ease, opacity 0.3s ease;\n}\n\n.slide-enter-from,\n.slide-leave-to {\n transform: translateX(-100%);\n opacity: 0;\n}\n</style>\n"],"names":["props","__props","emit","__emit","route","useRoute","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarAdvanced.vue2.js","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { ref, computed, watch } from 'vue'\r\nimport { useRoute } from 'vue-router'\r\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\r\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\r\nimport JInput from '@/components/atoms/JInput.vue'\r\nimport JIcon from '@/components/atoms/JIcon.vue'\r\nimport { cn } from '@/lib/utils'\r\n\r\n/**\r\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\r\n * Advanced Sidebar Component\r\n * \r\n * @description\r\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\r\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarAdvanced\r\n * :menu-items=\"menuItems\"\r\n * :permissions=\"userPermissions\"\r\n * :favorites=\"favoriteMenuKeys\"\r\n * @menu-click=\"handleMenuClick\"\r\n * @favorite-change=\"handleFavoriteChange\"\r\n * />\r\n * ```\r\n * \r\n * @example JSON 메뉴 데이터 예시\r\n * ```json\r\n * [\r\n * {\r\n * \"label\": \"대시보드\",\r\n * \"icon\": \"house\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 1,\r\n * \"path\": \"/dashboard\"\r\n * },\r\n * {\r\n * \"label\": \"재고 관리\",\r\n * \"icon\": \"package\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 2,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"재고 현황\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 21,\r\n * \"path\": \"/inventory/status\"\r\n * },\r\n * {\r\n * \"label\": \"입고 관리\",\r\n * \"menuType\": \"F\",\r\n * \"menuKey\": 22,\r\n * \"children\": [\r\n * {\r\n * \"label\": \"입고 등록\",\r\n * \"menuType\": \"L\",\r\n * \"menuKey\": 221,\r\n * \"path\": \"/inventory/receiving/register\"\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * }\r\n * ]\r\n * ```\r\n */\r\n\r\ntype TabType = 'menu' | 'favorites'\r\n\r\ntype StyleType = 'default' | 'minimal'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 메뉴 아이템 목록 */\r\n menuItems: SidebarMenuItem[]\r\n /** 권한 목록 */\r\n permissions?: MenuPermission[]\r\n /** 즐겨찾기 메뉴 키 목록 */\r\n favorites?: (number | string)[]\r\n /** 스타일 타입 */\r\n styletype?: StyleType\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n /** 너비 */\r\n width?: string\r\n /** 표시 여부 */\r\n isVisible?: boolean\r\n }>(),\r\n {\r\n permissions: () => [],\r\n favorites: () => [],\r\n styletype: 'minimal',\r\n width: '280px',\r\n isVisible: true,\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n /** 메뉴 클릭 이벤트 */\r\n menuClick: [event: MenuClickEvent]\r\n /** 즐겨찾기 변경 이벤트 */\r\n favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\r\n}>()\r\n\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성 탭\r\n */\r\nconst activeTab = ref<TabType>('menu')\r\n\r\n/**\r\n * 검색어\r\n */\r\nconst searchQuery = ref('')\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\r\n * 즐겨찾기 메뉴 아이템 목록\r\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\r\n */\r\nconst favoriteMenuItems = computed(() => {\r\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\r\n return []\r\n }\r\n\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\r\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\r\n * menuType L(Link)만 포함하고 F(Folder)는 제외\r\n */\r\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\r\n\r\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\r\n if (isFavorite && item.menuType === 'L') {\r\n result.push({\r\n ...item,\r\n children: undefined, // children 제거하여 1단계로만 표시\r\n })\r\n }\r\n\r\n // 하위 메뉴도 재귀적으로 탐색\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const childFavorites = flattenFavorites(item.children)\r\n result.push(...childFavorites)\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return flattenFavorites(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색어로 필터링된 메뉴 아이템\r\n * 재귀적으로 children까지 검색\r\n */\r\nconst filteredMenuItems = computed(() => {\r\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return props.menuItems\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n /**\r\n * 메뉴 아이템을 재귀적으로 검색\r\n */\r\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\r\n const result: SidebarMenuItem[] = []\r\n\r\n if (!Array.isArray(items)) {\r\n return result\r\n }\r\n\r\n for (const item of items) {\r\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\r\n\r\n // 하위 메뉴 검색\r\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n filteredChildren = searchInMenu(item.children)\r\n }\r\n\r\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\r\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\r\n result.push({\r\n ...item,\r\n children: filteredChildren,\r\n })\r\n }\r\n }\r\n\r\n return result\r\n }\r\n\r\n return searchInMenu(props.menuItems)\r\n})\r\n\r\n/**\r\n * 검색 결과에 따라 부모 메뉴 자동 확장\r\n * computed 외부에서 watch를 통해 처리\r\n */\r\nwatch(\r\n () => filteredMenuItems.value,\r\n (filtered) => {\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return\r\n }\r\n\r\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\r\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\r\n const keysToExpand = new Set<number | string>()\r\n\r\n const traverse = (menuItems: SidebarMenuItem[]): void => {\r\n if (!Array.isArray(menuItems)) {\r\n return\r\n }\r\n\r\n for (const item of menuItems) {\r\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\r\n const key = item.menuKey || item.label\r\n keysToExpand.add(key)\r\n traverse(item.children)\r\n }\r\n }\r\n }\r\n\r\n traverse(items)\r\n return keysToExpand\r\n }\r\n\r\n const keysToExpand = findParentsWithMatches(filtered)\r\n keysToExpand.forEach(key => {\r\n expandedKeys.value.add(key)\r\n })\r\n },\r\n { immediate: false }\r\n)\r\n\r\n/**\r\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\r\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\r\n */\r\nconst filteredFavoriteItems = computed(() => {\r\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\r\n return []\r\n }\r\n\r\n if (!searchQuery.value || searchQuery.value.trim() === '') {\r\n return favoriteMenuItems.value\r\n }\r\n\r\n const query = searchQuery.value.toLowerCase().trim()\r\n\r\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\r\n return favoriteMenuItems.value.filter((item) =>\r\n item.label?.toLowerCase().includes(query) ?? false\r\n )\r\n})\r\n\r\n\r\n/**\r\n * 탭 변경 핸들러\r\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\r\n */\r\nconst handleTabChange = (tab: TabType) => {\r\n if (activeTab.value !== tab) {\r\n activeTab.value = tab\r\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\r\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\r\n searchQuery.value = ''\r\n }\r\n}\r\n\r\n/**\r\n * 확장 상태 변경 핸들러\r\n */\r\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\r\n if (!menuKey) return\r\n\r\n if (expanded) {\r\n expandedKeys.value.add(menuKey)\r\n } else {\r\n expandedKeys.value.delete(menuKey)\r\n }\r\n}\r\n\r\n/**\r\n * 메뉴 클릭 핸들러\r\n */\r\nconst handleMenuClick = (event: MenuClickEvent) => {\r\n emit('menuClick', event)\r\n}\r\n\r\n/**\r\n * 즐겨찾기 토글 핸들러\r\n */\r\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\r\n if (!menuKey) return\r\n\r\n const isFavorite = props.favorites?.includes(menuKey) ?? false\r\n emit('favoriteChange', menuKey, !isFavorite)\r\n}\r\n\r\n/**\r\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\r\n */\r\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\r\n for (const item of items) {\r\n const key = item.menuKey || item.label\r\n if (key === targetKey) {\r\n return item\r\n }\r\n if (item.children && item.children.length > 0) {\r\n const found = findMenuItemByKey(item.children, targetKey)\r\n if (found) return found\r\n }\r\n }\r\n return null\r\n}\r\n\r\n/**\r\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\r\n */\r\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\r\n if (!menuKey) return false\r\n if (!props.favorites?.includes(menuKey)) return false\r\n \r\n // menuType이 L인 경우만 즐겨찾기로 인정\r\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\r\n return menuItem?.menuType === 'L'\r\n}\r\n\r\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n tabContainerClass: string\n tabButtonClass: string\n searchContainerClass: string\n menuContainerClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50',\n searchContainerClass: 'p-1.5 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1.5 space-y-0.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2',\n searchContainerClass: 'p-1 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-0.5',\n },\n}\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 */\r\nconst rootClasses = computed(() => {\r\n return cn(\r\n preset.value.containerClass,\r\n props.class\r\n )\r\n})\r\n</script>\r\n\r\n<template>\r\n <Transition name=\"slide\">\r\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\r\n <!-- 탭 헤더 -->\r\n <div :class=\"preset.tabContainerClass\">\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'menu'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('menu')\"\r\n >\r\n 기본메뉴\r\n </button>\r\n <button\r\n :class=\"cn(\r\n preset.tabButtonClass,\r\n activeTab === 'favorites'\r\n ? 'border-primary text-primary'\r\n : 'border-transparent text-muted-foreground hover:text-foreground'\r\n )\"\r\n @click=\"handleTabChange('favorites')\"\r\n >\r\n 즐겨찾기\r\n </button>\r\n </div>\r\n\r\n <!-- 검색 영역 -->\r\n <div :class=\"preset.searchContainerClass\">\r\n <div class=\"relative\">\r\n <JIcon\r\n name=\"search\"\r\n size=\"sm\"\r\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\r\n />\r\n <JInput\r\n v-model=\"searchQuery\"\r\n placeholder=\"메뉴 검색...\"\r\n :class=\"cn(\r\n 'pl-8',\r\n props.styletype === 'minimal' && 'h-8 text-xs'\r\n )\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <!-- 메뉴 목록 -->\r\n <div :class=\"preset.menuContainerClass\">\r\n <template v-if=\"activeTab === 'menu'\">\r\n <template v-if=\"filteredMenuItems.length > 0\">\r\n <div\r\n v-for=\"(item, index) in filteredMenuItems\"\r\n :key=\"item.menuKey || item.label || index\"\r\n class=\"flex items-center group\"\r\n >\r\n <JDynamicMenuItem\r\n :item=\"item\"\r\n :level=\"0\"\r\n :permissions=\"permissions\"\r\n :active-path=\"activePath\"\r\n :expanded-keys=\"expandedKeys\"\r\n :favorites=\"favorites\"\r\n :on-favorite-toggle=\"handleFavoriteToggle\"\r\n :is-favorite=\"isFavorite\"\r\n :styletype=\"styletype\"\r\n class=\"flex-1\"\r\n @menu-click=\"handleMenuClick\"\r\n @expand-change=\"handleExpandChange\"\r\n />\r\n </div>\r\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">검색 결과가 없습니다.</p>\n </div>\n </template>\n\n <template v-else>\n <template v-if=\"filteredFavoriteItems.length > 0\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredFavoriteItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">즐겨찾기가 없습니다.</p>\n </div>\n </template>\r\n </div>\r\n </aside>\r\n </Transition>\r\n</template>\r\n\r\n<style scoped>\r\n.slide-enter-active,\r\n.slide-leave-active {\r\n transition: transform 0.3s ease, opacity 0.3s ease;\r\n}\r\n\r\n.slide-enter-from,\r\n.slide-leave-to {\r\n transform: translateX(-100%);\r\n opacity: 0;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","route","useRoute","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyEA,UAAMA,IAAQC,GA0BRC,IAAOC,GAQPC,IAAQC,EAAA,GAKRC,IAAYC,EAAa,MAAM,GAK/BC,IAAcD,EAAI,EAAE,GAKpBE,IAAaC,EAAS,MAAMN,EAAM,IAAI,GAKtCO,IAAeJ,EAA0B,oBAAI,KAAK,GAMlDK,IAAoBF,EAAS,MAAM;AACvC,UAAI,CAAC,MAAM,QAAQV,EAAM,SAAS,KAAKA,EAAM,UAAU,WAAW;AAChE,eAAO,CAAA;AAGT,UAAI,CAAC,MAAM,QAAQA,EAAM,SAAS,KAAKA,EAAM,UAAU,WAAW;AAChE,eAAO,CAAA;AAQT,YAAMa,IAAmB,CAACC,MAAgD;AACxE,cAAMC,IAA4B,CAAA;AAElC,YAAI,CAAC,MAAM,QAAQD,CAAK;AACtB,iBAAOC;AAGT,mBAAWC,KAAQF,GAAO;AACxB,gBAAMG,IAAMD,EAAK,WAAWA,EAAK;AAYjC,cAXmB,MAAM,QAAQhB,EAAM,SAAS,KAAKA,EAAM,UAAU,SAASiB,CAAG,KAG/DD,EAAK,aAAa,OAClCD,EAAO,KAAK;AAAA,YACV,GAAGC;AAAA,YACH,UAAU;AAAA;AAAA,UAAA,CACX,GAICA,EAAK,YAAY,MAAM,QAAQA,EAAK,QAAQ,KAAKA,EAAK,SAAS,SAAS,GAAG;AAC7E,kBAAME,IAAiBL,EAAiBG,EAAK,QAAQ;AACrD,YAAAD,EAAO,KAAK,GAAGG,CAAc;AAAA,UAC/B;AAAA,QACF;AAEA,eAAOH;AAAA,MACT;AAEA,aAAOF,EAAiBb,EAAM,SAAS;AAAA,IACzC,CAAC,GAMKmB,IAAoBT,EAAS,MAAM;AACvC,UAAI,CAAC,MAAM,QAAQV,EAAM,SAAS,KAAKA,EAAM,UAAU,WAAW;AAChE,eAAO,CAAA;AAGT,UAAI,CAACQ,EAAY,SAASA,EAAY,MAAM,KAAA,MAAW;AACrD,eAAOR,EAAM;AAGf,YAAMoB,IAAQZ,EAAY,MAAM,YAAA,EAAc,KAAA,GAKxCa,IAAe,CAACP,MAAgD;AACpE,cAAMC,IAA4B,CAAA;AAElC,YAAI,CAAC,MAAM,QAAQD,CAAK;AACtB,iBAAOC;AAGT,mBAAWC,KAAQF,GAAO;AACxB,gBAAMQ,IAAeN,EAAK,OAAO,cAAc,SAASI,CAAK,KAAK;AAGlE,cAAIG;AACJ,UAAIP,EAAK,YAAY,MAAM,QAAQA,EAAK,QAAQ,KAAKA,EAAK,SAAS,SAAS,MAC1EO,IAAmBF,EAAaL,EAAK,QAAQ,KAI3CM,KAAiB,MAAM,QAAQC,CAAgB,KAAKA,EAAiB,SAAS,MAChFR,EAAO,KAAK;AAAA,YACV,GAAGC;AAAA,YACH,UAAUO;AAAA,UAAA,CACX;AAAA,QAEL;AAEA,eAAOR;AAAA,MACT;AAEA,aAAOM,EAAarB,EAAM,SAAS;AAAA,IACrC,CAAC;AAMD,IAAAwB;AAAA,MACE,MAAML,EAAkB;AAAA,MACxB,CAACM,MAAa;AACZ,YAAI,CAACjB,EAAY,SAASA,EAAY,MAAM,KAAA,MAAW;AACrD;AA0BF,SAtB+B,CAACM,MAAmD;AACjF,gBAAMY,wBAAmB,IAAA,GAEnBC,IAAW,CAACC,MAAuC;AACvD,gBAAK,MAAM,QAAQA,CAAS;AAI5B,yBAAWZ,KAAQY;AACjB,oBAAIZ,EAAK,YAAY,MAAM,QAAQA,EAAK,QAAQ,KAAKA,EAAK,SAAS,SAAS,GAAG;AAC7E,wBAAMC,IAAMD,EAAK,WAAWA,EAAK;AACjCU,kBAAAA,EAAa,IAAIT,CAAG,GACpBU,EAASX,EAAK,QAAQ;AAAA,gBACxB;AAAA;AAAA,UAEJ;AAEA,iBAAAW,EAASb,CAAK,GACPY;AAAAA,QACT,GAE4CD,CAAQ,EACvC,QAAQ,CAAAR,MAAO;AAC1B,UAAAN,EAAa,MAAM,IAAIM,CAAG;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAM;AAOrB,UAAMY,IAAwBnB,EAAS,MAAM;AAC3C,UAAI,CAAC,MAAM,QAAQE,EAAkB,KAAK,KAAKA,EAAkB,MAAM,WAAW;AAChF,eAAO,CAAA;AAGT,UAAI,CAACJ,EAAY,SAASA,EAAY,MAAM,KAAA,MAAW;AACrD,eAAOI,EAAkB;AAG3B,YAAMQ,IAAQZ,EAAY,MAAM,YAAA,EAAc,KAAA;AAG9C,aAAOI,EAAkB,MAAM;AAAA,QAAO,CAACI,MACrCA,EAAK,OAAO,cAAc,SAASI,CAAK,KAAK;AAAA,MAAA;AAAA,IAEjD,CAAC,GAOKU,IAAkB,CAACC,MAAiB;AACxC,MAAIzB,EAAU,UAAUyB,MACtBzB,EAAU,QAAQyB,GAGlBvB,EAAY,QAAQ;AAAA,IAExB,GAKMwB,IAAqB,CAACC,GAAsCC,MAAsB;AACtF,MAAKD,MAEDC,IACFvB,EAAa,MAAM,IAAIsB,CAAO,IAE9BtB,EAAa,MAAM,OAAOsB,CAAO;AAAA,IAErC,GAKME,IAAkB,CAACC,MAA0B;AACjD,MAAAlC,EAAK,aAAakC,CAAK;AAAA,IACzB,GAKMC,IAAuB,CAACJ,MAAyC;AACrE,UAAI,CAACA,EAAS;AAEd,YAAMK,IAAatC,EAAM,WAAW,SAASiC,CAAO,KAAK;AACzD,MAAA/B,EAAK,kBAAkB+B,GAAS,CAACK,CAAU;AAAA,IAC7C,GAKMC,IAAoB,CAACzB,GAA0B0B,MAAuD;AAC1G,iBAAWxB,KAAQF,GAAO;AAExB,aADYE,EAAK,WAAWA,EAAK,WACrBwB;AACV,iBAAOxB;AAET,YAAIA,EAAK,YAAYA,EAAK,SAAS,SAAS,GAAG;AAC7C,gBAAMyB,IAAQF,EAAkBvB,EAAK,UAAUwB,CAAS;AACxD,cAAIC,EAAO,QAAOA;AAAA,QACpB;AAAA,MACF;AACA,aAAO;AAAA,IACT,GAKMH,IAAa,CAACL,MACd,CAACA,KACD,CAACjC,EAAM,WAAW,SAASiC,CAAO,IAAU,KAG/BM,EAAkBvC,EAAM,WAAWiC,CAAO,GAC1C,aAAa,KAM1BS,IAMD;AAAA,MACH,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,QACnB,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QACtB,oBAAoB;AAAA,MAAA;AAAA,MAEtB,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,QACnB,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QACtB,oBAAoB;AAAA,MAAA;AAAA,IACtB,GAGIC,IAASjC,EAAS,MACfgC,EAAc1C,EAAM,SAAS,KAAK0C,EAAc,OACxD,GAKKE,IAAclC,EAAS,MACpBmC;AAAA,MACLF,EAAO,MAAM;AAAA,MACb3C,EAAM;AAAA,IAAA,CAET;2BAIC8C,EAkGaC,GAAA,EAlGD,MAAK,WAAO;AAAA,iBACtB,MAgGM;AAAA,UAhGNC,EAgGM,SAAA;AAAA,UAhG2B,SAAOJ,EAAA,KAAW;AAAA,UAAG,kBAAS3C,EAAA,OAAK;AAAA,QAAA;UAEpE+C,EAuBM,OAAA;AAAA,YAvBA,OAAKC,EAAEN,EAAA,MAAO,iBAAiB;AAAA,UAAA;YACnCK,EAUS,UAAA;AAAA,cATN,SAAOE,EAAAL,CAAA;AAAA,gBAAeF,EAAA,MAAO;AAAA,gBAA2BrC,EAAA,UAAS;;cAMjE,gCAAOwB,EAAe,MAAA;AAAA,YAAA,GACxB,UAED,CAAA;AAAA,YACAkB,EAUS,UAAA;AAAA,cATN,SAAOE,EAAAL,CAAA;AAAA,gBAAeF,EAAA,MAAO;AAAA,gBAA2BrC,EAAA,UAAS;;cAMjE,gCAAOwB,EAAe,WAAA;AAAA,YAAA,GACxB,UAED,CAAA;AAAA,UAAA;UAIFkB,EAgBM,OAAA;AAAA,YAhBA,OAAKC,EAAEN,EAAA,MAAO,oBAAoB;AAAA,UAAA;YACtCK,EAcM,OAdNG,GAcM;AAAA,cAbJC,EAIEC,GAAA;AAAA,gBAHA,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,OAAM;AAAA,cAAA;cAERD,EAOEE,GAAA;AAAA,4BANS9C,EAAA;AAAA,8DAAAA,EAAW,QAAA+C;AAAA,gBACpB,aAAY;AAAA,gBACX,SAAOL,EAAAL,CAAA;AAAA;kBAAsC7C,EAAM,cAAS,aAAA;AAAA,gBAAA;;;;UASnEgD,EAgDM,OAAA;AAAA,YAhDA,OAAKC,EAAEN,EAAA,MAAO,kBAAkB;AAAA,UAAA;YACpBrC,EAAA,UAAS,eAAzBkD,EA0BWC,GAAA,EAAA,KAAA,KAAA;AAAA,cAzBOtC,EAAA,MAAkB,SAAM,KACtCuC,EAAA,EAAA,GAAAF,EAmBMC,GAAA,EAAA,KAAA,KAAAE,EAlBoBxC,EAAA,OAAiB,CAAjCH,GAAM4C,YADhBJ,EAmBM,OAAA;AAAA,gBAjBH,KAAKxC,EAAK,WAAWA,EAAK,SAAS4C;AAAA,gBACpC,OAAM;AAAA,cAAA;gBAENR,EAaES,GAAA;AAAA,kBAZC,MAAA7C;AAAA,kBACA,OAAO;AAAA,kBACP,aAAaf,EAAA;AAAA,kBACb,eAAaQ,EAAA;AAAA,kBACb,iBAAeE,EAAA;AAAA,kBACf,WAAWV,EAAA;AAAA,kBACX,sBAAoBoC;AAAA,kBACpB,eAAaC;AAAA,kBACb,WAAWrC,EAAA;AAAA,kBACZ,OAAM;AAAA,kBACL,aAAYkC;AAAA,kBACZ,gBAAeH;AAAA,gBAAA;6BAItB0B,EAAA,GAAAF,EAEM,OAFNM,IAEM,CAAA,GAAAC,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,gBADJf,EAAmC,KAAA,EAAhC,OAAM,UAAA,GAAU,gBAAY,EAAA;AAAA,cAAA;4BAInCQ,EAkBWC,GAAA,EAAA,KAAA,KAAA;AAAA,cAjBO5B,EAAA,MAAsB,SAAM,KAC1C6B,EAAA,EAAA,GAAAF,EAWEC,GAAA,EAAA,KAAA,KAAAE,EAVwB9B,EAAA,OAAqB,CAArCb,GAAM4C,YADhBd,EAWEe,GAAA;AAAA,gBATC,KAAK7C,EAAK,WAAWA,EAAK,SAAS4C;AAAA,gBACnC,MAAA5C;AAAA,gBACA,OAAO;AAAA,gBACP,aAAaf,EAAA;AAAA,gBACb,eAAaQ,EAAA;AAAA,gBACb,iBAAeE,EAAA;AAAA,gBACf,WAAWV,EAAA;AAAA,gBACX,aAAYkC;AAAA,gBACZ,gBAAeH;AAAA,cAAA,8FAGpB0B,EAAA,GAAAF,EAEM,OAFNQ,IAEM,CAAA,GAAAD,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA;AAAA,gBADJf,EAAkC,KAAA,EAA/B,OAAM,UAAA,GAAU,eAAW,EAAA;AAAA,cAAA;;;;UA5FrB,CAAAiB,GAAAjE,EAAM,SAAS;AAAA,QAAA;;;;;;"}
|
|
1
|
+
{"version":3,"file":"JSidebarAdvanced.vue2.js","sources":["../../../../src/components/organisms/JSidebarAdvanced.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport JInput from '@/components/atoms/JInput.vue'\nimport JIcon from '@/components/atoms/JIcon.vue'\nimport { cn } from '@/lib/utils'\n\n/**\n * JSidebarAdvanced - 고급 사이드바 컴포넌트\n * Advanced Sidebar Component\n * \n * @description\n * 검색, 즐겨찾기, 다단계 메뉴를 지원하는 고급 사이드바 컴포넌트입니다.\n * 기본 메뉴와 즐겨찾기 탭을 제공합니다.\n * \n * @example\n * ```vue\n * <JSidebarAdvanced\n * :menu-items=\"menuItems\"\n * :permissions=\"userPermissions\"\n * :favorites=\"favoriteMenuKeys\"\n * @menu-click=\"handleMenuClick\"\n * @favorite-change=\"handleFavoriteChange\"\n * />\n * ```\n * \n * @example JSON 메뉴 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"대시보드\",\n * \"icon\": \"house\",\n * \"menuType\": \"L\",\n * \"menuKey\": 1,\n * \"path\": \"/dashboard\"\n * },\n * {\n * \"label\": \"재고 관리\",\n * \"icon\": \"package\",\n * \"menuType\": \"F\",\n * \"menuKey\": 2,\n * \"children\": [\n * {\n * \"label\": \"재고 현황\",\n * \"menuType\": \"L\",\n * \"menuKey\": 21,\n * \"path\": \"/inventory/status\"\n * },\n * {\n * \"label\": \"입고 관리\",\n * \"menuType\": \"F\",\n * \"menuKey\": 22,\n * \"children\": [\n * {\n * \"label\": \"입고 등록\",\n * \"menuType\": \"L\",\n * \"menuKey\": 221,\n * \"path\": \"/inventory/receiving/register\"\n * }\n * ]\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype TabType = 'menu' | 'favorites'\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 메뉴 아이템 목록 */\n menuItems: SidebarMenuItem[]\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 즐겨찾기 메뉴 키 목록 */\n favorites?: (number | string)[]\n /** 스타일 타입 */\n styletype?: StyleType\n /** 추가 CSS 클래스 */\n class?: string\n /** 너비 */\n width?: string\n /** 표시 여부 */\n isVisible?: boolean\n }>(),\n {\n permissions: () => [],\n favorites: () => [],\n styletype: 'minimal',\n width: '280px',\n isVisible: true,\n },\n)\n\nconst emit = defineEmits<{\n /** 메뉴 클릭 이벤트 */\n menuClick: [event: MenuClickEvent]\n /** 즐겨찾기 변경 이벤트 */\n favoriteChange: [menuKey: number | string | undefined, isFavorite: boolean]\n}>()\n\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\nconst route = useRoute()\n\n/**\n * 현재 활성 탭\n */\nconst activeTab = ref<TabType>('menu')\n\n/**\n * 검색어\n */\nconst searchQuery = ref('')\n\n/**\n * 현재 활성화된 경로\n */\nconst activePath = computed(() => route.path)\n\n/**\n * 확장된 메뉴 키 목록\n */\nconst expandedKeys = ref<Set<number | string>>(new Set())\n\n/**\n * 즐겨찾기 메뉴 아이템 목록\n * 즐겨찾기는 dept 없이 1단계로만 평탄화하여 표시\n */\nconst favoriteMenuItems = computed(() => {\n if (!Array.isArray(props.favorites) || props.favorites.length === 0) {\n return []\n }\n\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\n return []\n }\n\n /**\n * 메뉴 아이템을 재귀적으로 순회하며 즐겨찾기만 추출\n * 즐겨찾기에서는 dept 없이 1단계로만 평탄화\n * menuType L(Link)만 포함하고 F(Folder)는 제외\n */\n const flattenFavorites = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\n const result: SidebarMenuItem[] = []\n\n if (!Array.isArray(items)) {\n return result\n }\n\n for (const item of items) {\n const key = item.menuKey || item.label\n const isFavorite = Array.isArray(props.favorites) && props.favorites.includes(key)\n\n // 즐겨찾기이고 menuType이 L(Link)인 경우만 추가 (F는 제외)\n if (isFavorite && item.menuType === 'L') {\n result.push({\n ...item,\n children: undefined, // children 제거하여 1단계로만 표시\n })\n }\n\n // 하위 메뉴도 재귀적으로 탐색\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n const childFavorites = flattenFavorites(item.children)\n result.push(...childFavorites)\n }\n }\n\n return result\n }\n\n return flattenFavorites(props.menuItems)\n})\n\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n if (!Array.isArray(props.menuItems) || props.menuItems.length === 0) {\n return []\n }\n\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return props.menuItems\n }\n\n const query = searchQuery.value.toLowerCase().trim()\n\n /**\n * 메뉴 아이템을 재귀적으로 검색\n */\n const searchInMenu = (items: SidebarMenuItem[]): SidebarMenuItem[] => {\n const result: SidebarMenuItem[] = []\n\n if (!Array.isArray(items)) {\n return result\n }\n\n for (const item of items) {\n const matchesLabel = item.label?.toLowerCase().includes(query) ?? false\n\n // 하위 메뉴 검색\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n filteredChildren = searchInMenu(item.children)\n }\n\n // 현재 메뉴나 하위 메뉴 중 하나라도 매칭되면 포함\n if (matchesLabel || (Array.isArray(filteredChildren) && filteredChildren.length > 0)) {\n result.push({\n ...item,\n children: filteredChildren,\n })\n }\n }\n\n return result\n }\n\n return searchInMenu(props.menuItems)\n})\n\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const findParentsWithMatches = (items: SidebarMenuItem[]): Set<number | string> => {\n const keysToExpand = new Set<number | string>()\n\n const traverse = (menuItems: SidebarMenuItem[]): void => {\n if (!Array.isArray(menuItems)) {\n return\n }\n\n for (const item of menuItems) {\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n const key = item.menuKey || item.label\n keysToExpand.add(key)\n traverse(item.children)\n }\n }\n }\n\n traverse(items)\n return keysToExpand\n }\n\n const keysToExpand = findParentsWithMatches(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\n/**\n * 검색어로 필터링된 즐겨찾기 메뉴 아이템\n * 즐겨찾기는 이미 평탄화되어 있으므로 단순 필터링만 수행\n */\nconst filteredFavoriteItems = computed(() => {\n if (!Array.isArray(favoriteMenuItems.value) || favoriteMenuItems.value.length === 0) {\n return []\n }\n\n if (!searchQuery.value || searchQuery.value.trim() === '') {\n return favoriteMenuItems.value\n }\n\n const query = searchQuery.value.toLowerCase().trim()\n\n // 즐겨찾기는 이미 평탄화되어 1단계이므로 단순 필터링만 수행\n return favoriteMenuItems.value.filter((item) =>\n item.label?.toLowerCase().includes(query) ?? false\n )\n})\n\n\n/**\n * 탭 변경 핸들러\n * 탭 전환 시 검색 쿼리를 초기화하여 각 탭의 독립적인 검색 상태 유지\n */\nconst handleTabChange = (tab: TabType) => {\n if (activeTab.value !== tab) {\n activeTab.value = tab\n // 탭 전환 시 검색 쿼리 초기화 (선택적 - UX 고려)\n // 검색 쿼리를 유지하려면 아래 라인을 제거하세요\n searchQuery.value = ''\n }\n}\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n if (expanded) {\n expandedKeys.value.add(menuKey)\n } else {\n expandedKeys.value.delete(menuKey)\n }\n}\n\n/**\n * 메뉴 클릭 핸들러\n */\nconst handleMenuClick = (event: MenuClickEvent) => {\n emit('menuClick', event)\n}\n\n/**\n * 즐겨찾기 토글 핸들러\n */\nconst handleFavoriteToggle = (menuKey: number | string | undefined) => {\n if (!menuKey) return\n\n const isFavorite = props.favorites?.includes(menuKey) ?? false\n emit('favoriteChange', menuKey, !isFavorite)\n}\n\n/**\n * 메뉴 아이템에서 특정 menuKey를 찾는 헬퍼 함수\n */\nconst findMenuItemByKey = (items: SidebarMenuItem[], targetKey: number | string): SidebarMenuItem | null => {\n for (const item of items) {\n const key = item.menuKey || item.label\n if (key === targetKey) {\n return item\n }\n if (item.children && item.children.length > 0) {\n const found = findMenuItemByKey(item.children, targetKey)\n if (found) return found\n }\n }\n return null\n}\n\n/**\n * 메뉴가 즐겨찾기인지 확인 (L 타입만 즐겨찾기 가능)\n */\nconst isFavorite = (menuKey: number | string | undefined): boolean => {\n if (!menuKey) return false\n if (!props.favorites?.includes(menuKey)) return false\n \n // menuType이 L인 경우만 즐겨찾기로 인정\n const menuItem = findMenuItemByKey(props.menuItems, menuKey)\n return menuItem?.menuType === 'L'\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n tabContainerClass: string\n tabButtonClass: string\n searchContainerClass: string\n menuContainerClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-3 py-1.5 text-xs font-medium transition-colors border-b-2 hover:bg-accent/50',\n searchContainerClass: 'p-1.5 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1.5 space-y-0.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border flex flex-col',\n tabContainerClass: 'flex border-b border-border',\n tabButtonClass: 'flex-1 px-2 py-1 text-xs font-medium transition-colors border-b-2',\n searchContainerClass: 'p-1 border-b border-border',\n menuContainerClass: 'flex-1 overflow-y-auto p-1 space-y-0.5',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * 루트 클래스\n */\nconst rootClasses = computed(() => {\n return cn(\n preset.value.containerClass,\n props.class\n )\n})\n</script>\n\n<template>\n <Transition name=\"slide\">\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\n <!-- 탭 헤더 -->\n <div :class=\"preset.tabContainerClass\">\n <button\n :class=\"cn(\n preset.tabButtonClass,\n activeTab === 'menu'\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n )\"\n @click=\"handleTabChange('menu')\"\n >\n 기본메뉴\n </button>\n <button\n :class=\"cn(\n preset.tabButtonClass,\n activeTab === 'favorites'\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n )\"\n @click=\"handleTabChange('favorites')\"\n >\n 즐겨찾기\n </button>\n </div>\n\n <!-- 검색 영역 -->\n <div :class=\"preset.searchContainerClass\">\n <div class=\"relative\">\n <JIcon\n name=\"search\"\n size=\"sm\"\n class=\"absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground\"\n />\n <JInput\n v-model=\"searchQuery\"\n placeholder=\"메뉴 검색...\"\n :class=\"cn(\n 'pl-8',\n props.styletype === 'minimal' && 'h-8 text-xs'\n )\"\n />\n </div>\n </div>\n\n <!-- 메뉴 목록 -->\n <div :class=\"preset.menuContainerClass\">\n <template v-if=\"activeTab === 'menu'\">\n <template v-if=\"filteredMenuItems.length > 0\">\n <div\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.menuKey || item.label || index\"\n class=\"flex items-center group\"\n >\n <JDynamicMenuItem\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :favorites=\"favorites\"\n :on-favorite-toggle=\"handleFavoriteToggle\"\n :is-favorite=\"isFavorite\"\n :styletype=\"styletype\"\n class=\"flex-1\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">검색 결과가 없습니다.</p>\n </div>\n </template>\n\n <template v-else>\n <template v-if=\"filteredFavoriteItems.length > 0\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredFavoriteItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </template>\n <div v-else class=\"text-center py-8 text-muted-foreground\">\n <p class=\"text-xs\">즐겨찾기가 없습니다.</p>\n </div>\n </template>\n </div>\n </aside>\n </Transition>\n</template>\n\n<style scoped>\n.slide-enter-active,\n.slide-leave-active {\n transition: transform 0.3s ease, opacity 0.3s ease;\n}\n\n.slide-enter-from,\n.slide-leave-to {\n transform: translateX(-100%);\n opacity: 0;\n}\n</style>\n"],"names":["props","__props","emit","__emit","route","useRoute","activeTab","ref","searchQuery","activePath","computed","expandedKeys","favoriteMenuItems","flattenFavorites","items","result","item","key","childFavorites","filteredMenuItems","query","searchInMenu","matchesLabel","filteredChildren","watch","filtered","keysToExpand","traverse","menuItems","filteredFavoriteItems","handleTabChange","tab","handleExpandChange","menuKey","expanded","handleMenuClick","event","handleFavoriteToggle","isFavorite","findMenuItemByKey","targetKey","found","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_hoisted_1","_createVNode","JIcon","JInput","$event","_createElementBlock","_Fragment","_openBlock","_renderList","index","JDynamicMenuItem","_hoisted_2","_cache","_hoisted_3","_vShow"],"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-
|
|
6
|
+
};,u=t(e.default,[["__scopeId","data-v-88c10bb4"]]);exports.default=u;
|
|
7
7
|
//# sourceMappingURL=JSidebarSimple.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
|
|
9
|
+
const a = /* @__PURE__ */ r(o, [["__scopeId", "data-v-88c10bb4"]]);
|
|
10
10
|
export {
|
|
11
|
-
|
|
11
|
+
a as default
|
|
12
12
|
};
|
|
13
13
|
//# sourceMappingURL=JSidebarSimple.vue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarSimple.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"JSidebarSimple.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\n/**\n * JSidebarSimple - 간단한 사이드바 컴포넌트\n * Simple Sidebar Component\n * \n * @description\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\n * \n * @example\n * ```vue\n * <JSidebarSimple\n * :menu-items=\"menuItems\"\n * :permissions=\"userPermissions\"\n * @menu-click=\"handleMenuClick\"\n * />\n * ```\n * \n * @example JSON 메뉴 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"대시보드\",\n * \"icon\": \"house\",\n * \"menuType\": \"L\",\n * \"menuKey\": 1,\n * \"path\": \"/dashboard\"\n * },\n * {\n * \"label\": \"재고 관리\",\n * \"icon\": \"package\",\n * \"menuType\": \"F\",\n * \"menuKey\": 2,\n * \"children\": [\n * {\n * \"label\": \"재고 현황\",\n * \"menuType\": \"L\",\n * \"menuKey\": 21,\n * \"path\": \"/inventory/status\"\n * },\n * {\n * \"label\": \"입고 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 22,\n * \"path\": \"/inventory/receiving\"\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 메뉴 아이템 목록 */\n menuItems: SidebarMenuItem[]\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 검색어 */\n searchQuery?: string\n /** 스타일 타입 */\n styletype?: StyleType\n /** 추가 CSS 클래스 */\n class?: string\n /** 너비 */\n width?: string\n /** 표시 여부 */\n isVisible?: boolean\n }>(),\n {\n permissions: () => [],\n searchQuery: '',\n styletype: 'default',\n width: '250px',\n isVisible: true,\n },\n)\n\nconst emit = defineEmits<{\n /** 메뉴 클릭 이벤트 */\n menuClick: [event: MenuClickEvent]\n}>()\n\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\nconst route = useRoute()\n\n/**\n * 현재 활성화된 경로\n */\nconst activePath = computed(() => route.path)\n\n/**\n * 확장된 메뉴 키 목록 (Set)\n */\nconst expandedKeys = ref<Set<number | string>>(new Set())\n\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n if (expanded) {\n expandedKeys.value.add(menuKey)\n } else {\n expandedKeys.value.delete(menuKey)\n }\n}\n\n/**\n * 메뉴 클릭 핸들러\n */\nconst handleMenuClick = (event: MenuClickEvent) => {\n emit('menuClick', event)\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * 루트 클래스\n */\nconst rootClasses = computed(() => {\n return cn(\n preset.value.containerClass,\n props.class\n )\n})\n</script>\n\n<template>\n <Transition name=\"slide\">\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\n <div :class=\"cn(preset.menuPaddingClass, 'space-y-0.5')\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </aside>\n </Transition>\n</template>\n\n<style scoped>\n.slide-enter-active,\n.slide-leave-active {\n transition: transform 0.3s ease, opacity 0.3s ease;\n}\n\n.slide-enter-from,\n.slide-leave-to {\n transform: translateX(-100%);\n opacity: 0;\n}\n</style>\n"],"names":["props","__props","emit","__emit","route","useRoute","activePath","computed","expandedKeys","ref","filteredMenuItems","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","handleExpandChange","menuKey","expanded","handleMenuClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_openBlock","_createElementBlock","_Fragment","_renderList","item","index","JDynamicMenuItem","_vShow"],"mappings":"0hBA6DA,MAAMA,EAAQC,EA0BRC,EAAOC,EAMPC,EAAQC,EAAAA,SAAA,EAKRC,EAAaC,EAAAA,SAAS,IAAMH,EAAM,IAAI,EAKtCI,EAAeC,EAAAA,IAA0B,IAAI,GAAK,EAMlDC,EAAoBH,EAAAA,SAAS,IAC1BI,EAAAA,gBAAgBX,EAAM,UAAWA,EAAM,aAAe,EAAE,CAChE,EAMDY,EAAAA,MACE,IAAMF,EAAkB,MACvBG,GAAa,CACZ,GAAI,CAACb,EAAM,aAAeA,EAAM,YAAY,KAAA,IAAW,GACrD,OAImBc,EAAAA,yBAAyBD,CAAQ,EACzC,QAAQE,GAAO,CAC1BP,EAAa,MAAM,IAAIO,CAAG,CAC5B,CAAC,CACH,EACA,CAAE,UAAW,EAAA,CAAM,EAMrB,MAAMC,EAAqB,CAACC,EAAsCC,IAAsB,CACjFD,IAEDC,EACFV,EAAa,MAAM,IAAIS,CAAO,EAE9BT,EAAa,MAAM,OAAOS,CAAO,EAErC,EAKME,EAAmBC,GAA0B,CACjDlB,EAAK,YAAakB,CAAK,CACzB,EAKMC,EAGD,CACH,QAAS,CACP,eAAgB,8DAChB,iBAAkB,OAAA,EAEpB,QAAS,CACP,eAAgB,8DAChB,iBAAkB,KAAA,CACpB,EAGIC,EAASf,EAAAA,SAAS,IACfc,EAAcrB,EAAM,SAAS,GAAKqB,EAAc,OACxD,EAKKE,EAAchB,EAAAA,SAAS,IACpBiB,EAAAA,GACLF,EAAO,MAAM,eACbtB,EAAM,KAAA,CAET,8BAICyB,EAAAA,YAiBaC,EAAAA,WAAA,CAjBD,KAAK,SAAO,mBACtB,IAeQ,kBAfRC,EAAAA,mBAeQ,QAAA,CAfyB,uBAAOJ,EAAA,KAAW,EAAG,8BAAStB,EAAA,MAAK,CAAA,GAClE0B,EAAAA,mBAaM,MAAA,CAbA,MAAKC,EAAAA,eAAEC,EAAAA,MAAAL,EAAAA,EAAA,EAAGF,EAAA,MAAO,iBAAgB,aAAA,CAAA,CAAA,IACrCQ,EAAAA,UAAA,EAAA,EAAAC,EAAAA,mBAWEC,WAAA,KAAAC,EAAAA,WAVwBvB,EAAA,MAAiB,CAAjCwB,EAAMC,mBADhBV,EAAAA,YAWEW,UAAA,CATC,IAAKF,EAAK,SAAWA,EAAK,OAASC,EACnC,KAAAD,EACA,MAAO,EACP,YAAajC,EAAA,YACb,cAAaK,EAAA,MACb,gBAAeE,EAAA,MACf,UAAWP,EAAA,UACX,YAAYkB,EACZ,eAAeH,CAAA,4FAZP,CAAAqB,EAAAA,MAAArC,EAAM,SAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSidebarSimple.vue2.js","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"JSidebarSimple.vue2.js","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\nimport { useRoute } from 'vue-router'\nimport type { SidebarMenuItem, MenuPermission, MenuClickEvent } from '@/types/sidebar-menu.types'\nimport JDynamicMenuItem from './JSidebarSimple/JDynamicMenuItem.vue'\nimport { cn } from '@/lib/utils'\nimport { filterMenuItems, getExpandedKeysForSearch } from '@/lib/menu-utils'\n\n/**\n * JSidebarSimple - 간단한 사이드바 컴포넌트\n * Simple Sidebar Component\n * \n * @description\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\n * \n * @example\n * ```vue\n * <JSidebarSimple\n * :menu-items=\"menuItems\"\n * :permissions=\"userPermissions\"\n * @menu-click=\"handleMenuClick\"\n * />\n * ```\n * \n * @example JSON 메뉴 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"대시보드\",\n * \"icon\": \"house\",\n * \"menuType\": \"L\",\n * \"menuKey\": 1,\n * \"path\": \"/dashboard\"\n * },\n * {\n * \"label\": \"재고 관리\",\n * \"icon\": \"package\",\n * \"menuType\": \"F\",\n * \"menuKey\": 2,\n * \"children\": [\n * {\n * \"label\": \"재고 현황\",\n * \"menuType\": \"L\",\n * \"menuKey\": 21,\n * \"path\": \"/inventory/status\"\n * },\n * {\n * \"label\": \"입고 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 22,\n * \"path\": \"/inventory/receiving\"\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 메뉴 아이템 목록 */\n menuItems: SidebarMenuItem[]\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 검색어 */\n searchQuery?: string\n /** 스타일 타입 */\n styletype?: StyleType\n /** 추가 CSS 클래스 */\n class?: string\n /** 너비 */\n width?: string\n /** 표시 여부 */\n isVisible?: boolean\n }>(),\n {\n permissions: () => [],\n searchQuery: '',\n styletype: 'default',\n width: '250px',\n isVisible: true,\n },\n)\n\nconst emit = defineEmits<{\n /** 메뉴 클릭 이벤트 */\n menuClick: [event: MenuClickEvent]\n}>()\n\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\nconst route = useRoute()\n\n/**\n * 현재 활성화된 경로\n */\nconst activePath = computed(() => route.path)\n\n/**\n * 확장된 메뉴 키 목록 (Set)\n */\nconst expandedKeys = ref<Set<number | string>>(new Set())\n\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\n/**\n * 검색 결과에 따라 부모 메뉴 자동 확장\n * computed 외부에서 watch를 통해 처리\n */\nwatch(\n () => filteredMenuItems.value,\n (filtered) => {\n if (!props.searchQuery || props.searchQuery.trim() === '') {\n return\n }\n\n // 검색 결과에서 매칭된 하위 메뉴가 있는 부모를 찾아 확장\n const keysToExpand = getExpandedKeysForSearch(filtered)\n keysToExpand.forEach(key => {\n expandedKeys.value.add(key)\n })\n },\n { immediate: false }\n)\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n if (expanded) {\n expandedKeys.value.add(menuKey)\n } else {\n expandedKeys.value.delete(menuKey)\n }\n}\n\n/**\n * 메뉴 클릭 핸들러\n */\nconst handleMenuClick = (event: MenuClickEvent) => {\n emit('menuClick', event)\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1.5',\n },\n minimal: {\n containerClass: 'h-full bg-background border-r border-border overflow-y-auto',\n menuPaddingClass: 'p-1',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n/**\n * 루트 클래스\n */\nconst rootClasses = computed(() => {\n return cn(\n preset.value.containerClass,\n props.class\n )\n})\n</script>\n\n<template>\n <Transition name=\"slide\">\n <aside v-show=\"props.isVisible\" :class=\"rootClasses\" :style=\"{ width }\">\n <div :class=\"cn(preset.menuPaddingClass, 'space-y-0.5')\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredMenuItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :permissions=\"permissions\"\n :active-path=\"activePath\"\n :expanded-keys=\"expandedKeys\"\n :styletype=\"styletype\"\n @menu-click=\"handleMenuClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </aside>\n </Transition>\n</template>\n\n<style scoped>\n.slide-enter-active,\n.slide-leave-active {\n transition: transform 0.3s ease, opacity 0.3s ease;\n}\n\n.slide-enter-from,\n.slide-leave-to {\n transform: translateX(-100%);\n opacity: 0;\n}\n</style>\n"],"names":["props","__props","emit","__emit","route","useRoute","activePath","computed","expandedKeys","ref","filteredMenuItems","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","handleExpandChange","menuKey","expanded","handleMenuClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createBlock","_Transition","_createElementVNode","_normalizeClass","_unref","_openBlock","_createElementBlock","_Fragment","_renderList","item","index","JDynamicMenuItem","_vShow"],"mappings":";;;;;;;;;;;;;;;;;;AA6DA,UAAMA,IAAQC,GA0BRC,IAAOC,GAMPC,IAAQC,EAAA,GAKRC,IAAaC,EAAS,MAAMH,EAAM,IAAI,GAKtCI,IAAeC,EAA0B,oBAAI,KAAK,GAMlDC,IAAoBH,EAAS,MAC1BI,EAAgBX,EAAM,WAAWA,EAAM,eAAe,EAAE,CAChE;AAMD,IAAAY;AAAA,MACE,MAAMF,EAAkB;AAAA,MACxB,CAACG,MAAa;AACZ,YAAI,CAACb,EAAM,eAAeA,EAAM,YAAY,KAAA,MAAW;AACrD;AAKF,QADqBc,EAAyBD,CAAQ,EACzC,QAAQ,CAAAE,MAAO;AAC1B,UAAAP,EAAa,MAAM,IAAIO,CAAG;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAM;AAMrB,UAAMC,IAAqB,CAACC,GAAsCC,MAAsB;AACtF,MAAKD,MAEDC,IACFV,EAAa,MAAM,IAAIS,CAAO,IAE9BT,EAAa,MAAM,OAAOS,CAAO;AAAA,IAErC,GAKME,IAAkB,CAACC,MAA0B;AACjD,MAAAlB,EAAK,aAAakB,CAAK;AAAA,IACzB,GAKMC,IAGD;AAAA,MACH,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,MAAA;AAAA,MAEpB,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,MAAA;AAAA,IACpB,GAGIC,IAASf,EAAS,MACfc,EAAcrB,EAAM,SAAS,KAAKqB,EAAc,OACxD,GAKKE,IAAchB,EAAS,MACpBiB;AAAA,MACLF,EAAO,MAAM;AAAA,MACbtB,EAAM;AAAA,IAAA,CAET;2BAICyB,EAiBaC,GAAA,EAjBD,MAAK,WAAO;AAAA,iBACtB,MAeQ;AAAA,UAfRC,EAeQ,SAAA;AAAA,UAfyB,SAAOJ,EAAA,KAAW;AAAA,UAAG,kBAAStB,EAAA,OAAK;AAAA,QAAA;UAClE0B,EAaM,OAAA;AAAA,YAbA,OAAKC,EAAEC,EAAAL,CAAA,EAAGF,EAAA,MAAO,kBAAgB,aAAA,CAAA;AAAA,UAAA;aACrCQ,EAAA,EAAA,GAAAC,EAWEC,GAAA,MAAAC,EAVwBvB,EAAA,OAAiB,CAAjCwB,GAAMC,YADhBV,EAWEW,GAAA;AAAA,cATC,KAAKF,EAAK,WAAWA,EAAK,SAASC;AAAA,cACnC,MAAAD;AAAA,cACA,OAAO;AAAA,cACP,aAAajC,EAAA;AAAA,cACb,eAAaK,EAAA;AAAA,cACb,iBAAeE,EAAA;AAAA,cACf,WAAWP,EAAA;AAAA,cACX,aAAYkB;AAAA,cACZ,gBAAeH;AAAA,YAAA;;;UAZP,CAAAqB,GAAArC,EAAM,SAAS;AAAA,QAAA;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.vue.cjs","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.vue.cjs","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { AccordionTriggerProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ChevronDown } from \"lucide-vue-next\"\nimport {\n AccordionHeader,\n AccordionTrigger,\n\n} from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <AccordionHeader class=\"flex\">\n <AccordionTrigger\n v-bind=\"delegatedProps\"\n :class=\"\n cn(\n 'flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',\n props.class,\n )\n \"\n >\n <slot />\n <slot name=\"icon\">\n <ChevronDown\n class=\"h-3.5 w-3.5 shrink-0 transition-transform duration-200\"\n />\n </slot>\n </AccordionTrigger>\n </AccordionHeader>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","AccordionHeader","_createVNode","AccordionTrigger","_mergeProps","cn","_renderSlot","_ctx","ChevronDown"],"mappings":"sVAYA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAiBkBC,EAAAA,MAAAC,EAAAA,eAAA,EAAA,CAjBD,MAAM,QAAM,mBAC3B,IAemB,CAfnBC,EAAAA,YAemBF,EAAAA,MAAAG,EAAAA,gBAAA,EAfnBC,EAAAA,WAemBJ,EAAAA,MAAAH,CAAA,EAdK,CACrB,MAAgBG,EAAAA,MAAAK,IAAA,yIAAgKV,EAAM,KAAA,uBAOvL,IAAQ,CAARW,aAAQC,EAAA,OAAA,SAAA,EACRD,EAAAA,WAIOC,mBAJP,IAIO,CAHLL,EAAAA,YAEEF,EAAAA,MAAAQ,EAAAA,WAAA,EAAA,CADA,MAAM,yDAAwD,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.vue.js","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.vue.js","sources":["../../../../src/components/shadcn/AccordionTrigger.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { AccordionTriggerProps } from \"reka-ui\"\nimport type { HTMLAttributes } from \"vue\"\nimport { reactiveOmit } from \"@vueuse/core\"\nimport { ChevronDown } from \"lucide-vue-next\"\nimport {\n AccordionHeader,\n AccordionTrigger,\n\n} from \"reka-ui\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<AccordionTriggerProps & { class?: HTMLAttributes[\"class\"] }>()\n\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <AccordionHeader class=\"flex\">\n <AccordionTrigger\n v-bind=\"delegatedProps\"\n :class=\"\n cn(\n 'flex flex-1 items-center justify-between py-2 text-xs font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',\n props.class,\n )\n \"\n >\n <slot />\n <slot name=\"icon\">\n <ChevronDown\n class=\"h-3.5 w-3.5 shrink-0 transition-transform duration-200\"\n />\n </slot>\n </AccordionTrigger>\n </AccordionHeader>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","AccordionHeader","_createVNode","AccordionTrigger","_mergeProps","cn","_renderSlot","_ctx","ChevronDown"],"mappings":";;;;;;;;;;;;;AAYA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAiBkBC,EAAAC,CAAA,GAAA,EAjBD,OAAM,UAAM;AAAA,iBAC3B,MAemB;AAAA,QAfnBC,EAemBF,EAAAG,CAAA,GAfnBC,EAemBJ,EAAAH,CAAA,GAdK;AAAA,UACrB,OAAgBG,EAAAK,CAAA;AAAA;YAAgKV,EAAM;AAAA,UAAA;AAAA;qBAOvL,MAAQ;AAAA,YAARW,EAAQC,EAAA,QAAA,SAAA;AAAA,YACRD,EAIOC,sBAJP,MAIO;AAAA,cAHLL,EAEEF,EAAAQ,CAAA,GAAA,EADA,OAAM,0DAAwD;AAAA,YAAA;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardDescription.vue.cjs","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardDescription.vue.cjs","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <p :class=\"cn('text-xs text-muted-foreground', props.class)\">\n <slot />\n </p>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"4OAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBAEI,IAAA,CAFA,MAAKC,EAAAA,eAAEC,QAAAC,EAAAA,EAAA,EAAE,gCAAkCL,EAAM,KAAK,CAAA,CAAA,GACxDM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardDescription.vue.js","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardDescription.vue.js","sources":["../../../../src/components/shadcn/CardDescription.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <p :class=\"cn('text-xs text-muted-foreground', props.class)\">\n <slot />\n </p>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;AAIA,UAAMA,IAAQC;2BAMZC,EAEI,KAAA;AAAA,MAFA,OAAKC,EAAEC,EAAAC,CAAA,EAAE,iCAAkCL,EAAM,KAAK,CAAA;AAAA,IAAA;MACxDM,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardFooter.vue.cjs","sources":["../../../../src/components/shadcn/CardFooter.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardFooter.vue.cjs","sources":["../../../../src/components/shadcn/CardFooter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <div :class=\"cn('flex items-center gap-2 p-3 pt-2 border-t border-border bg-muted/60 dark:bg-[hsl(var(--border))] text-xs', props.class)\">\n <slot />\n </div>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"uOAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBAEM,MAAA,CAFA,MAAKC,EAAAA,eAAEC,QAAAC,EAAAA,EAAA,EAAE,2GAA6GL,EAAM,KAAK,CAAA,CAAA,GACrIM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardFooter.vue.js","sources":["../../../../src/components/shadcn/CardFooter.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardFooter.vue.js","sources":["../../../../src/components/shadcn/CardFooter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <div :class=\"cn('flex items-center gap-2 p-3 pt-2 border-t border-border bg-muted/60 dark:bg-[hsl(var(--border))] text-xs', props.class)\">\n <slot />\n </div>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;AAIA,UAAMA,IAAQC;2BAMZC,EAEM,OAAA;AAAA,MAFA,OAAKC,EAAEC,EAAAC,CAAA,EAAE,4GAA6GL,EAAM,KAAK,CAAA;AAAA,IAAA;MACrIM,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardTitle.vue.cjs","sources":["../../../../src/components/shadcn/CardTitle.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardTitle.vue.cjs","sources":["../../../../src/components/shadcn/CardTitle.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <h3\n :class=\"\n cn('text-sm font-semibold leading-none tracking-tight', props.class)\n \"\n >\n <slot />\n </h3>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":"sOAIA,MAAMA,EAAQC,8BAMZC,EAAAA,mBAMK,KAAA,CALF,MAAKC,EAAAA,eAASC,EAAAA,MAAAC,EAAAA,EAAA,EAAE,oDAAsDL,EAAM,KAAK,CAAA,IAIlFM,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardTitle.vue.js","sources":["../../../../src/components/shadcn/CardTitle.vue"],"sourcesContent":["<script setup lang=\"ts\">\
|
|
1
|
+
{"version":3,"file":"CardTitle.vue.js","sources":["../../../../src/components/shadcn/CardTitle.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { HTMLAttributes } from \"vue\"\nimport { cn } from \"@/lib/utils\"\n\nconst props = defineProps<{\n class?: HTMLAttributes[\"class\"]\n}>()\n</script>\n\n<template>\n <h3\n :class=\"\n cn('text-sm font-semibold leading-none tracking-tight', props.class)\n \"\n >\n <slot />\n </h3>\n</template>\n"],"names":["props","__props","_createElementBlock","_normalizeClass","_unref","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;AAIA,UAAMA,IAAQC;2BAMZC,EAMK,MAAA;AAAA,MALF,OAAKC;AAAAA,QAASC,EAAAC,CAAA,EAAE,qDAAsDL,EAAM,KAAK;AAAA,MAAA;AAAA;MAIlFM,EAAQC,EAAA,QAAA,SAAA;AAAA,IAAA;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.vue.cjs","sources":["../../../../src/components/shadcn/Checkbox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { Check } from \"lucide-vue-next\"\r\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<CheckboxRootProps & { class?: HTMLAttributes[\"class\"] }>()\r\nconst emits = defineEmits<CheckboxRootEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n props.class)\"\n >\n <CheckboxIndicator class=\"grid place-content-center text-current\">\n <slot>\n <Check class=\"h-4 w-4\" />\n </slot>\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","CheckboxRoot","_mergeProps","cn","_createVNode","CheckboxIndicator","_renderSlot","_ctx","Check"],"mappings":"ugBAQA,MAAMA,EAAQC,EACRC,EAAQC,EAERC,EAAiBC,EAAAA,aAAaL,EAAO,OAAO,EAE5CM,EAAYC,EAAAA,qBAAqBH,EAAgBF,CAAK,8BAI1DM,EAAAA,YAWeC,EAAAA,MAAAC,EAAAA,YAAA,EAXfC,EAAAA,WAWeF,QAAAH,CAAA,EAVI,CAChB,
|
|
1
|
+
{"version":3,"file":"Checkbox.vue.cjs","sources":["../../../../src/components/shadcn/Checkbox.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { CheckboxRootEmits, CheckboxRootProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { Check } from \"lucide-vue-next\"\r\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<CheckboxRootProps & { class?: HTMLAttributes[\"class\"] }>()\r\nconst emits = defineEmits<CheckboxRootEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\r\n</script>\r\n\r\n<template>\r\n <CheckboxRoot\r\n v-bind=\"forwarded\"\r\n :class=\"\r\n cn('grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\r\n props.class)\"\r\n >\r\n <CheckboxIndicator class=\"grid place-content-center text-current\">\r\n <slot>\r\n <Check class=\"h-4 w-4\" />\r\n </slot>\r\n </CheckboxIndicator>\r\n </CheckboxRoot>\r\n</template>\r\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","CheckboxRoot","_mergeProps","cn","_createVNode","CheckboxIndicator","_renderSlot","_ctx","Check"],"mappings":"ugBAQA,MAAMA,EAAQC,EACRC,EAAQC,EAERC,EAAiBC,EAAAA,aAAaL,EAAO,OAAO,EAE5CM,EAAYC,EAAAA,qBAAqBH,EAAgBF,CAAK,8BAI1DM,EAAAA,YAWeC,EAAAA,MAAAC,EAAAA,YAAA,EAXfC,EAAAA,WAWeF,QAAAH,CAAA,EAVI,CAChB,MAAeG,EAAAA,MAAAG,IAAA,EAAE,2UAAuVZ,EAAM,KAAA,CAAK,sBAIpX,IAIoB,CAJpBa,EAAAA,YAIoBJ,EAAAA,MAAAK,EAAAA,iBAAA,EAAA,CAJD,MAAM,0CAAwC,mBAC/D,IAEO,CAFPC,EAAAA,WAEOC,sBAFP,IAEO,CADLH,EAAAA,YAAyBJ,EAAAA,MAAAQ,EAAAA,KAAA,EAAA,CAAlB,MAAM,UAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.vue.js","sources":["../../../../src/components/shadcn/Checkbox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { CheckboxRootEmits, CheckboxRootProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { Check } from \"lucide-vue-next\"\r\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<CheckboxRootProps & { class?: HTMLAttributes[\"class\"] }>()\r\nconst emits = defineEmits<CheckboxRootEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <CheckboxRoot\n v-bind=\"forwarded\"\n :class=\"\n cn('grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\n props.class)\"\n >\n <CheckboxIndicator class=\"grid place-content-center text-current\">\n <slot>\n <Check class=\"h-4 w-4\" />\n </slot>\n </CheckboxIndicator>\n </CheckboxRoot>\n</template>\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","CheckboxRoot","_mergeProps","cn","_createVNode","CheckboxIndicator","_renderSlot","_ctx","Check"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAMA,IAAQC,GACRC,IAAQC,GAERC,IAAiBC,EAAaL,GAAO,OAAO,GAE5CM,IAAYC,EAAqBH,GAAgBF,CAAK;2BAI1DM,EAWeC,EAAAC,CAAA,GAXfC,EAWeF,EAAAH,CAAA,GAVI;AAAA,MAChB,
|
|
1
|
+
{"version":3,"file":"Checkbox.vue.js","sources":["../../../../src/components/shadcn/Checkbox.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { CheckboxRootEmits, CheckboxRootProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { Check } from \"lucide-vue-next\"\r\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<CheckboxRootProps & { class?: HTMLAttributes[\"class\"] }>()\r\nconst emits = defineEmits<CheckboxRootEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\r\n</script>\r\n\r\n<template>\r\n <CheckboxRoot\r\n v-bind=\"forwarded\"\r\n :class=\"\r\n cn('grid place-content-center peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',\r\n props.class)\"\r\n >\r\n <CheckboxIndicator class=\"grid place-content-center text-current\">\r\n <slot>\r\n <Check class=\"h-4 w-4\" />\r\n </slot>\r\n </CheckboxIndicator>\r\n </CheckboxRoot>\r\n</template>\r\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","CheckboxRoot","_mergeProps","cn","_createVNode","CheckboxIndicator","_renderSlot","_ctx","Check"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAQA,UAAMA,IAAQC,GACRC,IAAQC,GAERC,IAAiBC,EAAaL,GAAO,OAAO,GAE5CM,IAAYC,EAAqBH,GAAgBF,CAAK;2BAI1DM,EAWeC,EAAAC,CAAA,GAXfC,EAWeF,EAAAH,CAAA,GAVI;AAAA,MAChB,OAAeG,EAAAG,CAAA;AAAA,QAAE;AAAA,QAAuVZ,EAAM;AAAA,MAAA;AAAA,IAAK;iBAIpX,MAIoB;AAAA,QAJpBa,EAIoBJ,EAAAK,CAAA,GAAA,EAJD,OAAM,4CAAwC;AAAA,qBAC/D,MAEO;AAAA,YAFPC,EAEOC,yBAFP,MAEO;AAAA,cADLH,EAAyBJ,EAAAQ,CAAA,GAAA,EAAlB,OAAM,WAAS;AAAA,YAAA;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.vue.cjs","sources":["../../../../src/components/shadcn/Combobox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from \"reka-ui\"\r\nimport { ComboboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\n\r\nconst props = defineProps<ComboboxRootProps>()\r\nconst emits = defineEmits<ComboboxRootEmits>()\r\n\r\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <ComboboxRoot v-bind=\"forwarded\">\n <slot />\n </ComboboxRoot>\n</template>\n"],"names":["props","__props","emits","__emit","forwarded","useForwardPropsEmits","_openBlock","_createBlock","_unref","_renderSlot","_ctx"],"mappings":"gtBAIA,MAAMA,EAAQC,EACRC,EAAQC,EAERC,EAAYC,EAAAA,qBAAqBL,EAAOE,CAAK,gBAIjDI,YAAA,EAAAC,cAEeC,EAAAA,4DAFOA,EAAAA,MAAAJ,CAAA,CAAS,CAAA,EAAA,mBAC7B,IAAQ,CAARK,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"Combobox.vue.cjs","sources":["../../../../src/components/shadcn/Combobox.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxRootEmits, ComboboxRootProps } from \"reka-ui\"\r\nimport { ComboboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\n\r\nconst props = defineProps<ComboboxRootProps>()\r\nconst emits = defineEmits<ComboboxRootEmits>()\r\n\r\nconst forwarded = useForwardPropsEmits(props, emits)\r\n</script>\r\n\r\n<template>\r\n <ComboboxRoot v-bind=\"forwarded\">\r\n <slot />\r\n </ComboboxRoot>\r\n</template>\r\n"],"names":["props","__props","emits","__emit","forwarded","useForwardPropsEmits","_openBlock","_createBlock","_unref","_renderSlot","_ctx"],"mappings":"gtBAIA,MAAMA,EAAQC,EACRC,EAAQC,EAERC,EAAYC,EAAAA,qBAAqBL,EAAOE,CAAK,gBAIjDI,YAAA,EAAAC,cAEeC,EAAAA,4DAFOA,EAAAA,MAAAJ,CAAA,CAAS,CAAA,EAAA,mBAC7B,IAAQ,CAARK,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.vue.js","sources":["../../../../src/components/shadcn/Combobox.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxRootEmits, ComboboxRootProps } from \"reka-ui\"\r\nimport { ComboboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\n\r\nconst props = defineProps<ComboboxRootProps>()\r\nconst emits = defineEmits<ComboboxRootEmits>()\r\n\r\nconst forwarded = useForwardPropsEmits(props, emits)\n</script>\n\n<template>\n <ComboboxRoot v-bind=\"forwarded\">\n <slot />\n </ComboboxRoot>\n</template>\n"],"names":["forwarded","useForwardPropsEmits","__props","__emit","_openBlock","_createBlock","_unref","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,UAAMA,IAAYC,EAHJC,GACAC,CAEqC;sBAIjDC,EAAA,GAAAC,EAEeC,UAFOA,EAAAN,CAAA,CAAS,CAAA,GAAA;AAAA,iBAC7B,MAAQ;AAAA,QAARO,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"Combobox.vue.js","sources":["../../../../src/components/shadcn/Combobox.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxRootEmits, ComboboxRootProps } from \"reka-ui\"\r\nimport { ComboboxRoot, useForwardPropsEmits } from \"reka-ui\"\r\n\r\nconst props = defineProps<ComboboxRootProps>()\r\nconst emits = defineEmits<ComboboxRootEmits>()\r\n\r\nconst forwarded = useForwardPropsEmits(props, emits)\r\n</script>\r\n\r\n<template>\r\n <ComboboxRoot v-bind=\"forwarded\">\r\n <slot />\r\n </ComboboxRoot>\r\n</template>\r\n"],"names":["forwarded","useForwardPropsEmits","__props","__emit","_openBlock","_createBlock","_unref","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,UAAMA,IAAYC,EAHJC,GACAC,CAEqC;sBAIjDC,EAAA,GAAAC,EAEeC,UAFOA,EAAAN,CAAA,CAAS,CAAA,GAAA;AAAA,iBAC7B,MAAQ;AAAA,QAARO,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxAnchor.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxAnchor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxAnchorProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxAnchor, useForwardProps } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxAnchorProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ComboboxAnchor\n v-bind=\"forwarded\"\n :class=\"cn('w-[200px]', props.class)\"\n >\n <slot />\n </ComboboxAnchor>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","forwarded","useForwardProps","_createBlock","_unref","ComboboxAnchor","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"oUAOA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,EAE5CI,EAAYC,EAAAA,gBAAgBH,CAAc,8BAI9CI,EAAAA,YAKiBC,EAAAA,MAAAC,EAAAA,cAAA,EALjBC,EAAAA,WAKiBF,QAAAH,CAAA,EAJE,CAChB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,YAAcV,EAAM,KAAK,CAAA,sBAEnC,IAAQ,CAARW,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ComboboxAnchor.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxAnchor.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxAnchorProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxAnchor, useForwardProps } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxAnchorProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardProps(delegatedProps)\r\n</script>\r\n\r\n<template>\r\n <ComboboxAnchor\r\n v-bind=\"forwarded\"\r\n :class=\"cn('w-[200px]', props.class)\"\r\n >\r\n <slot />\r\n </ComboboxAnchor>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","forwarded","useForwardProps","_createBlock","_unref","ComboboxAnchor","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"oUAOA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,EAE5CI,EAAYC,EAAAA,gBAAgBH,CAAc,8BAI9CI,EAAAA,YAKiBC,EAAAA,MAAAC,EAAAA,cAAA,EALjBC,EAAAA,WAKiBF,QAAAH,CAAA,EAJE,CAChB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,YAAcV,EAAM,KAAK,CAAA,sBAEnC,IAAQ,CAARW,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxAnchor.vue.js","sources":["../../../../src/components/shadcn/ComboboxAnchor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxAnchorProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxAnchor, useForwardProps } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxAnchorProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardProps(delegatedProps)\n</script>\n\n<template>\n <ComboboxAnchor\n v-bind=\"forwarded\"\n :class=\"cn('w-[200px]', props.class)\"\n >\n <slot />\n </ComboboxAnchor>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","forwarded","useForwardProps","_createBlock","_unref","ComboboxAnchor","_mergeProps","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO,GAE5CI,IAAYC,EAAgBH,CAAc;2BAI9CI,EAKiBC,EAAAC,CAAA,GALjBC,EAKiBF,EAAAH,CAAA,GAJE;AAAA,MAChB,OAAOG,EAAAG,CAAA,EAAE,aAAcV,EAAM,KAAK;AAAA,IAAA;iBAEnC,MAAQ;AAAA,QAARW,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"ComboboxAnchor.vue.js","sources":["../../../../src/components/shadcn/ComboboxAnchor.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxAnchorProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxAnchor, useForwardProps } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxAnchorProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardProps(delegatedProps)\r\n</script>\r\n\r\n<template>\r\n <ComboboxAnchor\r\n v-bind=\"forwarded\"\r\n :class=\"cn('w-[200px]', props.class)\"\r\n >\r\n <slot />\r\n </ComboboxAnchor>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","forwarded","useForwardProps","_createBlock","_unref","ComboboxAnchor","_mergeProps","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO,GAE5CI,IAAYC,EAAgBH,CAAc;2BAI9CI,EAKiBC,EAAAC,CAAA,GALjBC,EAKiBF,EAAAH,CAAA,GAJE;AAAA,MAChB,OAAOG,EAAAG,CAAA,EAAE,aAAcV,EAAM,KAAK;AAAA,IAAA;iBAEnC,MAAQ;AAAA,QAARW,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxEmpty.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxEmpty.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxEmpty } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxEmpty","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"sTAOA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAEgBC,EAAAA,MAAAC,EAAAA,aAAA,EAFhBC,EAAAA,WAEgBF,QAAAH,CAAA,EAFqB,CAAG,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,2BAA6BR,EAAM,KAAK,CAAA,sBACvF,IAAQ,CAARS,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ComboboxEmpty.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxEmpty.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxEmptyProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxEmpty } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\r\n <slot />\r\n </ComboboxEmpty>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxEmpty","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"sTAOA,MAAMA,EAAQC,EAERC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAEgBC,EAAAA,MAAAC,EAAAA,aAAA,EAFhBC,EAAAA,WAEgBF,QAAAH,CAAA,EAFqB,CAAG,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,2BAA6BR,EAAM,KAAK,CAAA,sBACvF,IAAQ,CAARS,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxEmpty.vue.js","sources":["../../../../src/components/shadcn/ComboboxEmpty.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxEmptyProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxEmpty } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\n <slot />\n </ComboboxEmpty>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxEmpty","_mergeProps","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAEgBC,EAAAC,CAAA,GAFhBC,EAEgBF,EAAAH,CAAA,GAFqB;AAAA,MAAG,OAAOG,EAAAG,CAAA,EAAE,4BAA6BR,EAAM,KAAK;AAAA,IAAA;iBACvF,MAAQ;AAAA,QAARS,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"ComboboxEmpty.vue.js","sources":["../../../../src/components/shadcn/ComboboxEmpty.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxEmptyProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxEmpty } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxEmptyProps & { class?: HTMLAttributes[\"class\"] }>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <ComboboxEmpty v-bind=\"delegatedProps\" :class=\"cn('py-6 text-center text-sm', props.class)\">\r\n <slot />\r\n </ComboboxEmpty>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxEmpty","_mergeProps","cn","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAERC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAEgBC,EAAAC,CAAA,GAFhBC,EAEgBF,EAAAH,CAAA,GAFqB;AAAA,MAAG,OAAOG,EAAAG,CAAA,EAAE,4BAA6BR,EAAM,KAAK;AAAA,IAAA;iBACvF,MAAQ;AAAA,QAARS,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxGroup.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxGroup, ComboboxLabel } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxGroupProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n heading?: string\r\n}>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxGroup","_mergeProps","cn","ComboboxLabel","_renderSlot","_ctx"],"mappings":"iUAOA,MAAMA,EAAQC,EAKRC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAQgBC,EAAAA,MAAAC,EAAAA,aAAA,EARhBC,EAAAA,WAQgBF,QAAAH,CAAA,EAPQ,CACrB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,yNAA2NR,EAAM,KAAK,CAAA,sBAEhP,IAEgB,CAFKC,EAAA,uBAArBG,EAAAA,YAEgBC,EAAAA,MAAAI,EAAAA,aAAA,EAAA,OAFc,MAAM,uDAAA,qBAClC,IAAa,qCAAVR,EAAA,OAAO,EAAA,CAAA,CAAA,sCAEZS,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ComboboxGroup.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxGroupProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxGroup, ComboboxLabel } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxGroupProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n heading?: string\r\n}>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <ComboboxGroup\r\n v-bind=\"delegatedProps\"\r\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\r\n >\r\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\r\n {{ heading }}\r\n </ComboboxLabel>\r\n <slot />\r\n </ComboboxGroup>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxGroup","_mergeProps","cn","ComboboxLabel","_renderSlot","_ctx"],"mappings":"iUAOA,MAAMA,EAAQC,EAKRC,EAAiBC,EAAAA,aAAaH,EAAO,OAAO,8BAIhDI,EAAAA,YAQgBC,EAAAA,MAAAC,EAAAA,aAAA,EARhBC,EAAAA,WAQgBF,QAAAH,CAAA,EAPQ,CACrB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,yNAA2NR,EAAM,KAAK,CAAA,sBAEhP,IAEgB,CAFKC,EAAA,uBAArBG,EAAAA,YAEgBC,EAAAA,MAAAI,EAAAA,aAAA,EAAA,OAFc,MAAM,uDAAA,qBAClC,IAAa,qCAAVR,EAAA,OAAO,EAAA,CAAA,CAAA,sCAEZS,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxGroup.vue.js","sources":["../../../../src/components/shadcn/ComboboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxGroupProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxGroup, ComboboxLabel } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxGroupProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n heading?: string\r\n}>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\n</script>\n\n<template>\n <ComboboxGroup\n v-bind=\"delegatedProps\"\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\n >\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\n {{ heading }}\n </ComboboxLabel>\n <slot />\n </ComboboxGroup>\n</template>\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxGroup","_mergeProps","cn","ComboboxLabel","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAKRC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAQgBC,EAAAC,CAAA,GARhBC,EAQgBF,EAAAH,CAAA,GAPQ;AAAA,MACrB,OAAOG,EAAAG,CAAA,EAAE,0NAA2NR,EAAM,KAAK;AAAA,IAAA;iBAEhP,MAEgB;AAAA,QAFKC,EAAA,gBAArBG,EAEgBC,EAAAI,CAAA,GAAA;AAAA;UAFc,OAAM;AAAA,QAAA;qBAClC,MAAa;AAAA,gBAAVR,EAAA,OAAO,GAAA,CAAA;AAAA,UAAA;;;QAEZS,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
1
|
+
{"version":3,"file":"ComboboxGroup.vue.js","sources":["../../../../src/components/shadcn/ComboboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxGroupProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxGroup, ComboboxLabel } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxGroupProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n heading?: string\r\n}>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n</script>\r\n\r\n<template>\r\n <ComboboxGroup\r\n v-bind=\"delegatedProps\"\r\n :class=\"cn('overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', props.class)\"\r\n >\r\n <ComboboxLabel v-if=\"heading\" class=\"px-2 py-1.5 text-xs font-medium text-muted-foreground\">\r\n {{ heading }}\r\n </ComboboxLabel>\r\n <slot />\r\n </ComboboxGroup>\r\n</template>\r\n"],"names":["props","__props","delegatedProps","reactiveOmit","_createBlock","_unref","ComboboxGroup","_mergeProps","cn","ComboboxLabel","_renderSlot","_ctx"],"mappings":";;;;;;;;;;;;;AAOA,UAAMA,IAAQC,GAKRC,IAAiBC,EAAaH,GAAO,OAAO;2BAIhDI,EAQgBC,EAAAC,CAAA,GARhBC,EAQgBF,EAAAH,CAAA,GAPQ;AAAA,MACrB,OAAOG,EAAAG,CAAA,EAAE,0NAA2NR,EAAM,KAAK;AAAA,IAAA;iBAEhP,MAEgB;AAAA,QAFKC,EAAA,gBAArBG,EAEgBC,EAAAI,CAAA,GAAA;AAAA;UAFc,OAAM;AAAA,QAAA;qBAClC,MAAa;AAAA,gBAAVR,EAAA,OAAO,GAAA,CAAA;AAAA,UAAA;;;QAEZS,EAAQC,EAAA,QAAA,SAAA;AAAA,MAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComboboxInput.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ComboboxInputEmits, ComboboxInputProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxInput, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxInputProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n\r\nconst emits = defineEmits<ComboboxInputEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n</script>\n\n<template>\n <ComboboxInput\n v-bind=\"forwarded\"\n :class=\"cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\n >\n <slot />\n </ComboboxInput>\n</template>\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","ComboboxInput","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"ubAOA,MAAMA,EAAQC,EAIRC,EAAQC,EAERC,EAAiBC,EAAAA,aAAaL,EAAO,OAAO,EAE5CM,EAAYC,EAAAA,qBAAqBH,EAAgBF,CAAK,8BAI1DM,EAAAA,YAKgBC,EAAAA,MAAAC,EAAAA,aAAA,EALhBC,EAAAA,WAKgBF,QAAAH,CAAA,EAJG,CAChB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,wUAA0UZ,EAAM,KAAK,CAAA,sBAE/V,IAAQ,CAARa,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"ComboboxInput.vue.cjs","sources":["../../../../src/components/shadcn/ComboboxInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { ComboboxInputEmits, ComboboxInputProps } from \"reka-ui\"\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { reactiveOmit } from \"@vueuse/core\"\r\nimport { ComboboxInput, useForwardPropsEmits } from \"reka-ui\"\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = defineProps<ComboboxInputProps & {\r\n class?: HTMLAttributes[\"class\"]\r\n}>()\r\n\r\nconst emits = defineEmits<ComboboxInputEmits>()\r\n\r\nconst delegatedProps = reactiveOmit(props, \"class\")\r\n\r\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\r\n</script>\r\n\r\n<template>\r\n <ComboboxInput\r\n v-bind=\"forwarded\"\r\n :class=\"cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', props.class)\"\r\n >\r\n <slot />\r\n </ComboboxInput>\r\n</template>\r\n"],"names":["props","__props","emits","__emit","delegatedProps","reactiveOmit","forwarded","useForwardPropsEmits","_createBlock","_unref","ComboboxInput","_mergeProps","cn","_renderSlot","_ctx"],"mappings":"ubAOA,MAAMA,EAAQC,EAIRC,EAAQC,EAERC,EAAiBC,EAAAA,aAAaL,EAAO,OAAO,EAE5CM,EAAYC,EAAAA,qBAAqBH,EAAgBF,CAAK,8BAI1DM,EAAAA,YAKgBC,EAAAA,MAAAC,EAAAA,aAAA,EALhBC,EAAAA,WAKgBF,QAAAH,CAAA,EAJG,CAChB,MAAOG,EAAAA,MAAAG,EAAAA,EAAA,EAAE,wUAA0UZ,EAAM,KAAK,CAAA,sBAE/V,IAAQ,CAARa,aAAQC,EAAA,OAAA,SAAA,CAAA"}
|