{"version":3,"file":"JSidebarSimple.vue2.cjs","sources":["../../../../src/components/organisms/JSidebarSimple.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\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\r\n/**\r\n * JSidebarSimple - 간단한 사이드바 컴포넌트\r\n * Simple Sidebar Component\r\n * \r\n * @description\r\n * 다단계 메뉴 구조를 지원하는 기본 사이드바 컴포넌트입니다.\r\n * 권한 체크, 메뉴 검색 등의 기능을 제공합니다.\r\n * \r\n * @example\r\n * ```vue\r\n * <JSidebarSimple\r\n *   :menu-items=\"menuItems\"\r\n *   :permissions=\"userPermissions\"\r\n *   @menu-click=\"handleMenuClick\"\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\": \"L\",\r\n *         \"menuKey\": 22,\r\n *         \"path\": \"/inventory/receiving\"\r\n *       }\r\n *     ]\r\n *   }\r\n * ]\r\n * ```\r\n */\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    searchQuery?: 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    searchQuery: '',\r\n    styletype: 'default',\r\n    width: '250px',\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\r\n// vue-router가 설정되지 않은 경우를 대비 (Storybook에서 router가 제공됨)\r\nconst route = useRoute()\r\n\r\n/**\r\n * 현재 활성화된 경로\r\n */\r\nconst activePath = computed(() => route.path)\r\n\r\n/**\r\n * 확장된 메뉴 키 목록 (Set)\r\n */\r\nconst expandedKeys = ref<Set<number | string>>(new Set())\r\n\r\n/**\n * 검색어로 필터링된 메뉴 아이템\n * 재귀적으로 children까지 검색\n */\nconst filteredMenuItems = computed(() => {\n  return filterMenuItems(props.menuItems, props.searchQuery || '')\n})\n\r\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\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/**\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\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      <div :class=\"cn(preset.menuPaddingClass, 'space-y-0.5')\">\n        <JDynamicMenuItem\r\n          v-for=\"(item, index) in filteredMenuItems\"\r\n          :key=\"item.menuKey || item.label || index\"\r\n          :item=\"item\"\r\n          :level=\"0\"\r\n          :permissions=\"permissions\"\r\n          :active-path=\"activePath\"\r\n          :expanded-keys=\"expandedKeys\"\r\n          :styletype=\"styletype\"\r\n          @menu-click=\"handleMenuClick\"\r\n          @expand-change=\"handleExpandChange\"\r\n        />\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","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"}