@j-solution/components 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +6 -14
  2. package/USAGE_GUIDE.md +772 -1480
  3. package/assets/jwms-portal-frontend-Cs1trVbC.css +1 -0
  4. package/assets/styles/j-components.css +1 -1
  5. package/components/atoms/JEditor.vue.cjs +1 -1
  6. package/components/atoms/JEditor.vue.js +2 -2
  7. package/components/atoms/JEditor.vue2.cjs +1 -1
  8. package/components/atoms/JEditor.vue2.cjs.map +1 -1
  9. package/components/atoms/JEditor.vue2.js +1 -0
  10. package/components/atoms/JEditor.vue2.js.map +1 -1
  11. package/components/atoms/JPreview.vue.cjs +1 -1
  12. package/components/atoms/JPreview.vue.js +1 -1
  13. package/components/atoms/JPreview.vue2.cjs +1 -1
  14. package/components/atoms/JPreview.vue2.cjs.map +1 -1
  15. package/components/atoms/JPreview.vue2.js +2 -1
  16. package/components/atoms/JPreview.vue2.js.map +1 -1
  17. package/components/molecules/JFormField.vue.cjs +1 -1
  18. package/components/molecules/JFormField.vue.cjs.map +1 -1
  19. package/components/molecules/JFormField.vue.js +1 -1
  20. package/components/molecules/JFormField.vue.js.map +1 -1
  21. package/components/organisms/JFilterBar.vue.cjs +2 -0
  22. package/components/organisms/JFilterBar.vue.cjs.map +1 -0
  23. package/components/organisms/JFilterBar.vue.js +51 -0
  24. package/components/organisms/JFilterBar.vue.js.map +1 -0
  25. package/components/organisms/JFilterBar.vue2.cjs +2 -0
  26. package/components/organisms/JFilterBar.vue2.cjs.map +1 -0
  27. package/components/organisms/JFilterBar.vue2.js +5 -0
  28. package/components/organisms/JFilterBar.vue2.js.map +1 -0
  29. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs +1 -1
  30. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs.map +1 -1
  31. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js +45 -40
  32. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js.map +1 -1
  33. package/components/organisms/JSidebarSimple.vue.cjs +1 -1
  34. package/components/organisms/JSidebarSimple.vue.js +2 -2
  35. package/components/organisms/JSidebarSimple.vue2.cjs +1 -1
  36. package/components/organisms/JSidebarSimple.vue2.cjs.map +1 -1
  37. package/components/organisms/JSidebarSimple.vue2.js +40 -70
  38. package/components/organisms/JSidebarSimple.vue2.js.map +1 -1
  39. package/components/organisms/JTree.vue.cjs +2 -0
  40. package/components/organisms/JTree.vue.cjs.map +1 -0
  41. package/components/organisms/JTree.vue.js +83 -0
  42. package/components/organisms/JTree.vue.js.map +1 -0
  43. package/components/organisms/JTree.vue2.cjs +2 -0
  44. package/components/organisms/JTree.vue2.cjs.map +1 -0
  45. package/components/organisms/JTree.vue2.js +5 -0
  46. package/components/organisms/JTree.vue2.js.map +1 -0
  47. package/index.cjs +1 -1
  48. package/index.js +37 -33
  49. package/lib/menu-utils.cjs +2 -0
  50. package/lib/menu-utils.cjs.map +1 -0
  51. package/lib/menu-utils.js +33 -0
  52. package/lib/menu-utils.js.map +1 -0
  53. package/package.json +1 -1
  54. package/types/index.d.ts +156 -34
  55. package/assets/jwms-portal-frontend-D8DdrheA.css +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JTree.vue.cjs","sources":["../../../../src/components/organisms/JTree.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\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 * JTree - 트리 뷰 컴포넌트\n * Tree View Component\n *\n * @description\n * 계층 데이터를 조회/탐색하는 읽기 전용 트리 컴포넌트입니다.\n * JDynamicMenuItem을 재귀적으로 렌더링하며, 네비게이션 기능을 비활성화하고\n * nodeClick 이벤트로 선택을 처리합니다.\n *\n * @example\n * ```vue\n * <JTree\n * :items=\"treeData\"\n * v-model:expanded-keys=\"expandedKeys\"\n * v-model:active-key=\"activeKey\"\n * @node-click=\"handleNodeClick\"\n * />\n * ```\n *\n * @example JSON 트리 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"프로그램 관리\",\n * \"icon\": \"folder\",\n * \"menuType\": \"F\",\n * \"menuKey\": 1,\n * \"children\": [\n * {\n * \"label\": \"시스템 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 11\n * },\n * {\n * \"label\": \"사용자 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 12\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 트리 노드 데이터 */\n items: SidebarMenuItem[]\n /** 펼쳐진 노드 키 목록 (v-model 지원, 배열) */\n expandedKeys?: (number | string)[]\n /** 현재 선택(하이라이트)된 노드의 menuKey (v-model 지원) */\n activeKey?: number | string | null\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 최대 깊이 제한 (무한 루프 방지) */\n maxDepth?: number\n /** 스타일 타입 */\n styletype?: StyleType\n /** 검색어 (노드 필터링) */\n searchQuery?: string\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n expandedKeys: () => [],\n activeKey: null,\n permissions: () => [],\n maxDepth: 10,\n styletype: 'minimal',\n searchQuery: '',\n },\n)\n\nconst emit = defineEmits<{\n /** 노드 클릭 이벤트 */\n nodeClick: [event: MenuClickEvent]\n /** 확장 상태 변경 이벤트 */\n expandChange: [menuKey: number | string | undefined, expanded: boolean]\n /** expandedKeys v-model 업데이트 */\n 'update:expandedKeys': [keys: (number | string)[]]\n /** activeKey v-model 업데이트 */\n 'update:activeKey': [key: number | string | null]\n}>()\n\n/**\n * 내부 확장 키 관리 (Set으로 변환하여 사용)\n */\nconst internalExpandedKeys = ref<Set<number | string>>(new Set(props.expandedKeys))\n\n/**\n * 검색어로 필터링된 트리 아이템\n */\nconst filteredTreeItems = computed(() => {\n return filterMenuItems(props.items, props.searchQuery || '')\n})\n\n/**\n * 검색 결과에 따라 부모 노드 자동 확장\n */\nwatch(\n () => filteredTreeItems.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 internalExpandedKeys.value.add(key)\n })\n\n // v-model 업데이트\n emit('update:expandedKeys', [...internalExpandedKeys.value])\n },\n { immediate: false }\n)\n\n/**\n * expandedKeys prop 변경 감지\n */\nwatch(\n () => props.expandedKeys,\n (newKeys) => {\n internalExpandedKeys.value = new Set(newKeys)\n },\n { deep: true }\n)\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n // 새로운 Set 생성 (reactivity 보장)\n const newKeys = new Set(internalExpandedKeys.value)\n\n if (expanded) {\n newKeys.add(menuKey)\n } else {\n newKeys.delete(menuKey)\n }\n\n internalExpandedKeys.value = newKeys\n\n // v-model 업데이트 및 이벤트 발생\n emit('update:expandedKeys', [...newKeys])\n emit('expandChange', menuKey, expanded)\n}\n\n/**\n * 노드 클릭 핸들러\n */\nconst handleNodeClick = (event: MenuClickEvent) => {\n // activeKey 업데이트\n const menuKey = event.menuItem.menuKey\n if (menuKey !== undefined) {\n emit('update:activeKey', menuKey)\n }\n\n // nodeClick 이벤트 발생\n emit('nodeClick', event)\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'w-full',\n menuPaddingClass: 'space-y-1',\n },\n minimal: {\n containerClass: 'w-full',\n menuPaddingClass: '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 <div :class=\"rootClasses\">\n <div :class=\"preset.menuPaddingClass\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredTreeItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :max-depth=\"maxDepth\"\n :permissions=\"permissions\"\n :expanded-keys=\"internalExpandedKeys\"\n :styletype=\"styletype\"\n :disable-navigation=\"true\"\n :active-key=\"activeKey\"\n @menu-click=\"handleNodeClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","internalExpandedKeys","ref","filteredTreeItems","computed","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","newKeys","handleExpandChange","menuKey","expanded","handleNodeClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createElementBlock","_createElementVNode","_normalizeClass","_openBlock","_Fragment","_renderList","item","index","_createBlock","JDynamicMenuItem"],"mappings":"8jBAqDA,MAAMA,EAAQC,EA6BRC,EAAOC,EAcPC,EAAuBC,EAAAA,IAA0B,IAAI,IAAIL,EAAM,YAAY,CAAC,EAK5EM,EAAoBC,EAAAA,SAAS,IAC1BC,EAAAA,gBAAgBR,EAAM,MAAOA,EAAM,aAAe,EAAE,CAC5D,EAKDS,EAAAA,MACE,IAAMH,EAAkB,MACvBI,GAAa,CACZ,GAAI,CAACV,EAAM,aAAeA,EAAM,YAAY,KAAA,IAAW,GACrD,OAImBW,EAAAA,yBAAyBD,CAAQ,EACzC,QAAQE,GAAO,CAC1BR,EAAqB,MAAM,IAAIQ,CAAG,CACpC,CAAC,EAGDV,EAAK,sBAAuB,CAAC,GAAGE,EAAqB,KAAK,CAAC,CAC7D,EACA,CAAE,UAAW,EAAA,CAAM,EAMrBK,EAAAA,MACE,IAAMT,EAAM,aACXa,GAAY,CACXT,EAAqB,MAAQ,IAAI,IAAIS,CAAO,CAC9C,EACA,CAAE,KAAM,EAAA,CAAK,EAMf,MAAMC,EAAqB,CAACC,EAAsCC,IAAsB,CACtF,GAAI,CAACD,EAAS,OAGd,MAAMF,EAAU,IAAI,IAAIT,EAAqB,KAAK,EAE9CY,EACFH,EAAQ,IAAIE,CAAO,EAEnBF,EAAQ,OAAOE,CAAO,EAGxBX,EAAqB,MAAQS,EAG7BX,EAAK,sBAAuB,CAAC,GAAGW,CAAO,CAAC,EACxCX,EAAK,eAAgBa,EAASC,CAAQ,CACxC,EAKMC,EAAmBC,GAA0B,CAEjD,MAAMH,EAAUG,EAAM,SAAS,QAC3BH,IAAY,QACdb,EAAK,mBAAoBa,CAAO,EAIlCb,EAAK,YAAagB,CAAK,CACzB,EAKMC,EAGD,CACH,QAAS,CACP,eAAgB,SAChB,iBAAkB,WAAA,EAEpB,QAAS,CACP,eAAgB,SAChB,iBAAkB,aAAA,CACpB,EAGIC,EAASb,EAAAA,SAAS,IACfY,EAAcnB,EAAM,SAAS,GAAKmB,EAAc,OACxD,EAKKE,EAAcd,EAAAA,SAAS,IACpBe,EAAAA,GACLF,EAAO,MAAM,eACbpB,EAAM,KAAA,CAET,8BAICuB,EAAAA,mBAiBM,MAAA,CAjBA,uBAAOF,EAAA,KAAW,CAAA,GACtBG,EAAAA,mBAeM,MAAA,CAfA,MAAKC,EAAAA,eAAEL,EAAA,MAAO,gBAAgB,CAAA,IAClCM,EAAAA,UAAA,EAAA,EAAAH,EAAAA,mBAaEI,WAAA,KAAAC,EAAAA,WAZwBtB,EAAA,MAAiB,CAAjCuB,EAAMC,mBADhBC,EAAAA,YAaEC,UAAA,CAXC,IAAKH,EAAK,SAAWA,EAAK,OAASC,EACnC,KAAAD,EACA,MAAO,EACP,YAAW5B,EAAA,SACX,YAAaA,EAAA,YACb,gBAAeG,EAAA,MACf,UAAWH,EAAA,UACX,qBAAoB,GACpB,aAAYA,EAAA,UACZ,YAAYgB,EACZ,eAAeH,CAAA"}
@@ -0,0 +1,83 @@
1
+ import { defineComponent as k, ref as K, computed as r, watch as m, createElementBlock as p, openBlock as i, normalizeClass as y, createElementVNode as E, Fragment as g, renderList as w, createBlock as S } from "vue";
2
+ import T from "./JSidebarSimple/JDynamicMenuItem.vue.js";
3
+ import { cn as P } from "../../lib/utils.js";
4
+ import { filterMenuItems as Q, getExpandedKeysForSearch as B } from "../../lib/menu-utils.js";
5
+ const L = /* @__PURE__ */ k({
6
+ __name: "JTree",
7
+ props: {
8
+ items: {},
9
+ expandedKeys: { default: () => [] },
10
+ activeKey: { default: null },
11
+ permissions: { default: () => [] },
12
+ maxDepth: { default: 10 },
13
+ styletype: { default: "minimal" },
14
+ searchQuery: { default: "" },
15
+ class: {}
16
+ },
17
+ emits: ["nodeClick", "expandChange", "update:expandedKeys", "update:activeKey"],
18
+ setup(l, { emit: f }) {
19
+ const t = l, d = f, s = K(new Set(t.expandedKeys)), u = r(() => Q(t.items, t.searchQuery || ""));
20
+ m(
21
+ () => u.value,
22
+ (e) => {
23
+ if (!t.searchQuery || t.searchQuery.trim() === "")
24
+ return;
25
+ B(e).forEach((a) => {
26
+ s.value.add(a);
27
+ }), d("update:expandedKeys", [...s.value]);
28
+ },
29
+ { immediate: !1 }
30
+ ), m(
31
+ () => t.expandedKeys,
32
+ (e) => {
33
+ s.value = new Set(e);
34
+ },
35
+ { deep: !0 }
36
+ );
37
+ const v = (e, n) => {
38
+ if (!e) return;
39
+ const a = new Set(s.value);
40
+ n ? a.add(e) : a.delete(e), s.value = a, d("update:expandedKeys", [...a]), d("expandChange", e, n);
41
+ }, x = (e) => {
42
+ const n = e.menuItem.menuKey;
43
+ n !== void 0 && d("update:activeKey", n), d("nodeClick", e);
44
+ }, c = {
45
+ default: {
46
+ containerClass: "w-full",
47
+ menuPaddingClass: "space-y-1"
48
+ },
49
+ minimal: {
50
+ containerClass: "w-full",
51
+ menuPaddingClass: "space-y-0.5"
52
+ }
53
+ }, o = r(() => c[t.styletype] ?? c.default), h = r(() => P(
54
+ o.value.containerClass,
55
+ t.class
56
+ ));
57
+ return (e, n) => (i(), p("div", {
58
+ class: y(h.value)
59
+ }, [
60
+ E("div", {
61
+ class: y(o.value.menuPaddingClass)
62
+ }, [
63
+ (i(!0), p(g, null, w(u.value, (a, C) => (i(), S(T, {
64
+ key: a.menuKey || a.label || C,
65
+ item: a,
66
+ level: 0,
67
+ "max-depth": l.maxDepth,
68
+ permissions: l.permissions,
69
+ "expanded-keys": s.value,
70
+ styletype: l.styletype,
71
+ "disable-navigation": !0,
72
+ "active-key": l.activeKey,
73
+ onMenuClick: x,
74
+ onExpandChange: v
75
+ }, null, 8, ["item", "max-depth", "permissions", "expanded-keys", "styletype", "active-key"]))), 128))
76
+ ], 2)
77
+ ], 2));
78
+ }
79
+ });
80
+ export {
81
+ L as default
82
+ };
83
+ //# sourceMappingURL=JTree.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JTree.vue.js","sources":["../../../../src/components/organisms/JTree.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch } from 'vue'\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 * JTree - 트리 뷰 컴포넌트\n * Tree View Component\n *\n * @description\n * 계층 데이터를 조회/탐색하는 읽기 전용 트리 컴포넌트입니다.\n * JDynamicMenuItem을 재귀적으로 렌더링하며, 네비게이션 기능을 비활성화하고\n * nodeClick 이벤트로 선택을 처리합니다.\n *\n * @example\n * ```vue\n * <JTree\n * :items=\"treeData\"\n * v-model:expanded-keys=\"expandedKeys\"\n * v-model:active-key=\"activeKey\"\n * @node-click=\"handleNodeClick\"\n * />\n * ```\n *\n * @example JSON 트리 데이터 예시\n * ```json\n * [\n * {\n * \"label\": \"프로그램 관리\",\n * \"icon\": \"folder\",\n * \"menuType\": \"F\",\n * \"menuKey\": 1,\n * \"children\": [\n * {\n * \"label\": \"시스템 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 11\n * },\n * {\n * \"label\": \"사용자 관리\",\n * \"menuType\": \"L\",\n * \"menuKey\": 12\n * }\n * ]\n * }\n * ]\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(\n defineProps<{\n /** 트리 노드 데이터 */\n items: SidebarMenuItem[]\n /** 펼쳐진 노드 키 목록 (v-model 지원, 배열) */\n expandedKeys?: (number | string)[]\n /** 현재 선택(하이라이트)된 노드의 menuKey (v-model 지원) */\n activeKey?: number | string | null\n /** 권한 목록 */\n permissions?: MenuPermission[]\n /** 최대 깊이 제한 (무한 루프 방지) */\n maxDepth?: number\n /** 스타일 타입 */\n styletype?: StyleType\n /** 검색어 (노드 필터링) */\n searchQuery?: string\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n expandedKeys: () => [],\n activeKey: null,\n permissions: () => [],\n maxDepth: 10,\n styletype: 'minimal',\n searchQuery: '',\n },\n)\n\nconst emit = defineEmits<{\n /** 노드 클릭 이벤트 */\n nodeClick: [event: MenuClickEvent]\n /** 확장 상태 변경 이벤트 */\n expandChange: [menuKey: number | string | undefined, expanded: boolean]\n /** expandedKeys v-model 업데이트 */\n 'update:expandedKeys': [keys: (number | string)[]]\n /** activeKey v-model 업데이트 */\n 'update:activeKey': [key: number | string | null]\n}>()\n\n/**\n * 내부 확장 키 관리 (Set으로 변환하여 사용)\n */\nconst internalExpandedKeys = ref<Set<number | string>>(new Set(props.expandedKeys))\n\n/**\n * 검색어로 필터링된 트리 아이템\n */\nconst filteredTreeItems = computed(() => {\n return filterMenuItems(props.items, props.searchQuery || '')\n})\n\n/**\n * 검색 결과에 따라 부모 노드 자동 확장\n */\nwatch(\n () => filteredTreeItems.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 internalExpandedKeys.value.add(key)\n })\n\n // v-model 업데이트\n emit('update:expandedKeys', [...internalExpandedKeys.value])\n },\n { immediate: false }\n)\n\n/**\n * expandedKeys prop 변경 감지\n */\nwatch(\n () => props.expandedKeys,\n (newKeys) => {\n internalExpandedKeys.value = new Set(newKeys)\n },\n { deep: true }\n)\n\n/**\n * 확장 상태 변경 핸들러\n */\nconst handleExpandChange = (menuKey: number | string | undefined, expanded: boolean) => {\n if (!menuKey) return\n\n // 새로운 Set 생성 (reactivity 보장)\n const newKeys = new Set(internalExpandedKeys.value)\n\n if (expanded) {\n newKeys.add(menuKey)\n } else {\n newKeys.delete(menuKey)\n }\n\n internalExpandedKeys.value = newKeys\n\n // v-model 업데이트 및 이벤트 발생\n emit('update:expandedKeys', [...newKeys])\n emit('expandChange', menuKey, expanded)\n}\n\n/**\n * 노드 클릭 핸들러\n */\nconst handleNodeClick = (event: MenuClickEvent) => {\n // activeKey 업데이트\n const menuKey = event.menuItem.menuKey\n if (menuKey !== undefined) {\n emit('update:activeKey', menuKey)\n }\n\n // nodeClick 이벤트 발생\n emit('nodeClick', event)\n}\n\n/**\n * 스타일 프리셋\n */\nconst STYLE_PRESETS: Record<StyleType, {\n containerClass: string\n menuPaddingClass: string\n}> = {\n default: {\n containerClass: 'w-full',\n menuPaddingClass: 'space-y-1',\n },\n minimal: {\n containerClass: 'w-full',\n menuPaddingClass: '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 <div :class=\"rootClasses\">\n <div :class=\"preset.menuPaddingClass\">\n <JDynamicMenuItem\n v-for=\"(item, index) in filteredTreeItems\"\n :key=\"item.menuKey || item.label || index\"\n :item=\"item\"\n :level=\"0\"\n :max-depth=\"maxDepth\"\n :permissions=\"permissions\"\n :expanded-keys=\"internalExpandedKeys\"\n :styletype=\"styletype\"\n :disable-navigation=\"true\"\n :active-key=\"activeKey\"\n @menu-click=\"handleNodeClick\"\n @expand-change=\"handleExpandChange\"\n />\n </div>\n </div>\n</template>\n"],"names":["props","__props","emit","__emit","internalExpandedKeys","ref","filteredTreeItems","computed","filterMenuItems","watch","filtered","getExpandedKeysForSearch","key","newKeys","handleExpandChange","menuKey","expanded","handleNodeClick","event","STYLE_PRESETS","preset","rootClasses","cn","_createElementBlock","_createElementVNode","_normalizeClass","_openBlock","_Fragment","_renderList","item","index","_createBlock","JDynamicMenuItem"],"mappings":";;;;;;;;;;;;;;;;;;AAqDA,UAAMA,IAAQC,GA6BRC,IAAOC,GAcPC,IAAuBC,EAA0B,IAAI,IAAIL,EAAM,YAAY,CAAC,GAK5EM,IAAoBC,EAAS,MAC1BC,EAAgBR,EAAM,OAAOA,EAAM,eAAe,EAAE,CAC5D;AAKD,IAAAS;AAAA,MACE,MAAMH,EAAkB;AAAA,MACxB,CAACI,MAAa;AACZ,YAAI,CAACV,EAAM,eAAeA,EAAM,YAAY,KAAA,MAAW;AACrD;AAKF,QADqBW,EAAyBD,CAAQ,EACzC,QAAQ,CAAAE,MAAO;AAC1B,UAAAR,EAAqB,MAAM,IAAIQ,CAAG;AAAA,QACpC,CAAC,GAGDV,EAAK,uBAAuB,CAAC,GAAGE,EAAqB,KAAK,CAAC;AAAA,MAC7D;AAAA,MACA,EAAE,WAAW,GAAA;AAAA,IAAM,GAMrBK;AAAA,MACE,MAAMT,EAAM;AAAA,MACZ,CAACa,MAAY;AACX,QAAAT,EAAqB,QAAQ,IAAI,IAAIS,CAAO;AAAA,MAC9C;AAAA,MACA,EAAE,MAAM,GAAA;AAAA,IAAK;AAMf,UAAMC,IAAqB,CAACC,GAAsCC,MAAsB;AACtF,UAAI,CAACD,EAAS;AAGd,YAAMF,IAAU,IAAI,IAAIT,EAAqB,KAAK;AAElD,MAAIY,IACFH,EAAQ,IAAIE,CAAO,IAEnBF,EAAQ,OAAOE,CAAO,GAGxBX,EAAqB,QAAQS,GAG7BX,EAAK,uBAAuB,CAAC,GAAGW,CAAO,CAAC,GACxCX,EAAK,gBAAgBa,GAASC,CAAQ;AAAA,IACxC,GAKMC,IAAkB,CAACC,MAA0B;AAEjD,YAAMH,IAAUG,EAAM,SAAS;AAC/B,MAAIH,MAAY,UACdb,EAAK,oBAAoBa,CAAO,GAIlCb,EAAK,aAAagB,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,IAASb,EAAS,MACfY,EAAcnB,EAAM,SAAS,KAAKmB,EAAc,OACxD,GAKKE,IAAcd,EAAS,MACpBe;AAAA,MACLF,EAAO,MAAM;AAAA,MACbpB,EAAM;AAAA,IAAA,CAET;2BAICuB,EAiBM,OAAA;AAAA,MAjBA,SAAOF,EAAA,KAAW;AAAA,IAAA;MACtBG,EAeM,OAAA;AAAA,QAfA,OAAKC,EAAEL,EAAA,MAAO,gBAAgB;AAAA,MAAA;SAClCM,EAAA,EAAA,GAAAH,EAaEI,GAAA,MAAAC,EAZwBtB,EAAA,OAAiB,CAAjCuB,GAAMC,YADhBC,EAaEC,GAAA;AAAA,UAXC,KAAKH,EAAK,WAAWA,EAAK,SAASC;AAAA,UACnC,MAAAD;AAAA,UACA,OAAO;AAAA,UACP,aAAW5B,EAAA;AAAA,UACX,aAAaA,EAAA;AAAA,UACb,iBAAeG,EAAA;AAAA,UACf,WAAWH,EAAA;AAAA,UACX,sBAAoB;AAAA,UACpB,cAAYA,EAAA;AAAA,UACZ,aAAYgB;AAAA,UACZ,gBAAeH;AAAA,QAAA;;;;;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./JTree.vue.cjs");exports.default=e.default;
2
+ //# sourceMappingURL=JTree.vue2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JTree.vue2.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import f from "./JTree.vue.js";
2
+ export {
3
+ f as default
4
+ };
5
+ //# sourceMappingURL=JTree.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JTree.vue2.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
package/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
1
  require('./assets/styles/j-components.css');
2
2
  require('./assets/styles/themes.css');
3
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});;/* empty css */;/* empty css */;/* empty css */const e=require("./components/atoms/JButton.vue.cjs"),t=require("./components/atoms/JInput.vue.cjs"),u=require("./components/atoms/JTextarea.vue.cjs"),_=require("./components/atoms/JCheckbox.vue.cjs"),r=require("./components/atoms/JCombo.vue.cjs"),a=require("./components/atoms/JSearchCombo.vue.cjs"),s=require("./components/atoms/JRadio.vue.cjs"),i=require("./components/atoms/JSwitch.vue.cjs"),p=require("./components/atoms/JDatepicker.vue.cjs"),n=require("./components/atoms/JDivider.vue.cjs"),o=require("./components/atoms/JEditor.vue.cjs"),c=require("./components/atoms/JLink.vue.cjs"),l=require("./components/atoms/JImage.vue.cjs"),J=require("./components/atoms/JBadge.vue.cjs"),d=require("./components/atoms/JProgress.vue.cjs");;/* empty css */const v=require("./components/atoms/JSpinner.vue.cjs"),q=require("./components/atoms/JAvatar.vue.cjs"),y=require("./components/atoms/JKbd.vue.cjs"),f=require("./components/atoms/JTooltip.vue.cjs"),g=require("./components/atoms/JIcon.vue.cjs"),b=require("./components/atoms/JLabel.vue.cjs"),m=require("./components/atoms/JPopover.vue.cjs"),S=require("./components/atoms/JPreview.vue.cjs"),C=require("./components/atoms/JGrid.vue.cjs"),T=require("vue-sonner"),A=require("./components/atoms/JToast.vue.cjs"),P=require("./components/molecules/JFormField.vue.cjs");;/* empty css */const h=require("./components/molecules/JGroupCombo.vue.cjs"),L=require("./components/molecules/JTabs.vue.cjs"),B=require("./components/molecules/JSearchAddr.vue.cjs"),D=require("./components/molecules/JContextMenu.vue.cjs"),F=require("./components/molecules/JCard.vue.cjs"),M=require("./components/molecules/JAlert.vue.cjs"),k=require("./components/molecules/JAccordion.vue.cjs"),x=require("./components/molecules/JTitlebar.vue.cjs"),G=require("./components/molecules/JButtonGroup.vue.cjs"),I=require("./components/molecules/JBreadcrumb.vue.cjs"),w=require("./components/organisms/JDynamicTabs.vue.cjs"),j=require("./components/organisms/JModal.vue.cjs"),E=require("./components/organisms/JFormModal.vue.cjs"),H=require("./components/organisms/JDynamicForm.vue.cjs"),K=require("./components/organisms/JSearchPanel.vue.cjs"),O=require("./components/organisms/JHeader.vue.cjs"),R=require("./components/organisms/JSidebarSimple.vue.cjs"),z=require("./components/organisms/JSidebarAdvanced.vue.cjs"),N=require("./components/organisms/JPageContainer.vue.cjs"),Q=require("./components/templates/JLayout.vue.cjs"),U=require("./components/templates/JLayoutSimple.vue.cjs"),V=require("./components/templates/JLayoutAdvanced.vue.cjs");exports.JButton=e.default;exports.JInput=t.default;exports.JTextarea=u.default;exports.JCheckbox=_.default;exports.JCombo=r.default;exports.JSearchCombo=a.default;exports.JRadio=s.default;exports.JSwitch=i.default;exports.JDatepicker=p.default;exports.JDivider=n.default;exports.JEditor=o.default;exports.JLink=c.default;exports.JImage=l.default;exports.JBadge=J.default;exports.JProgress=d.default;exports.JSpinner=v.default;exports.JAvatar=q.default;exports.JKbd=y.default;exports.JTooltip=f.default;exports.JIcon=g.default;exports.JLabel=b.default;exports.JPopover=m.default;exports.JPreview=S.default;exports.JGrid=C.default;Object.defineProperty(exports,"JToast",{enumerable:!0,get:()=>T.toast});exports.JToaster=A.default;exports.JFormField=P.default;exports.JGroupCombo=h.default;exports.JTabs=L.default;exports.JSearchAddr=B.default;exports.JContextMenu=D.default;exports.JCard=F.default;exports.JAlert=M.default;exports.JAccordion=k.default;exports.JTitlebar=x.default;exports.JButtonGroup=G.default;exports.JBreadcrumb=I.default;exports.JDynamicTabs=w.default;exports.JModal=j.default;exports.JFormModal=E.default;exports.JDynamicForm=H.default;exports.JSearchPanel=K.default;exports.JHeader=O.default;exports.JSidebarSimple=R.default;exports.JSidebarAdvanced=z.default;exports.JPageContainer=N.default;exports.JLayout=Q.default;exports.JLayoutSimple=U.default;exports.JLayoutAdvanced=V.default;
3
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});;/* empty css */;/* empty css */;/* empty css */const e=require("./components/atoms/JButton.vue.cjs"),t=require("./components/atoms/JInput.vue.cjs"),u=require("./components/atoms/JTextarea.vue.cjs"),_=require("./components/atoms/JCheckbox.vue.cjs"),r=require("./components/atoms/JCombo.vue.cjs"),a=require("./components/atoms/JSearchCombo.vue.cjs"),s=require("./components/atoms/JRadio.vue.cjs"),i=require("./components/atoms/JSwitch.vue.cjs"),p=require("./components/atoms/JDatepicker.vue.cjs"),n=require("./components/atoms/JDivider.vue.cjs"),o=require("./components/atoms/JEditor.vue.cjs"),c=require("./components/atoms/JLink.vue.cjs"),l=require("./components/atoms/JImage.vue.cjs"),J=require("./components/atoms/JBadge.vue.cjs"),d=require("./components/atoms/JProgress.vue.cjs");;/* empty css */const v=require("./components/atoms/JSpinner.vue.cjs"),q=require("./components/atoms/JAvatar.vue.cjs"),y=require("./components/atoms/JKbd.vue.cjs"),f=require("./components/atoms/JTooltip.vue.cjs"),g=require("./components/atoms/JIcon.vue.cjs"),b=require("./components/atoms/JLabel.vue.cjs"),m=require("./components/atoms/JPopover.vue.cjs"),S=require("./components/atoms/JPreview.vue.cjs"),T=require("./components/atoms/JGrid.vue.cjs"),C=require("vue-sonner"),A=require("./components/atoms/JToast.vue.cjs"),P=require("./components/molecules/JFormField.vue.cjs");;/* empty css */const h=require("./components/molecules/JGroupCombo.vue.cjs"),B=require("./components/molecules/JTabs.vue.cjs"),F=require("./components/molecules/JSearchAddr.vue.cjs"),L=require("./components/molecules/JContextMenu.vue.cjs"),D=require("./components/molecules/JCard.vue.cjs"),M=require("./components/molecules/JAlert.vue.cjs"),k=require("./components/molecules/JAccordion.vue.cjs"),x=require("./components/molecules/JTitlebar.vue.cjs"),G=require("./components/molecules/JButtonGroup.vue.cjs"),I=require("./components/molecules/JBreadcrumb.vue.cjs"),w=require("./components/organisms/JDynamicTabs.vue.cjs"),j=require("./components/organisms/JModal.vue.cjs"),E=require("./components/organisms/JFormModal.vue.cjs"),H=require("./components/organisms/JDynamicForm.vue.cjs"),K=require("./components/organisms/JSearchPanel.vue.cjs"),O=require("./components/organisms/JFilterBar.vue.cjs"),R=require("./components/organisms/JHeader.vue.cjs"),z=require("./components/organisms/JSidebarSimple.vue.cjs"),N=require("./components/organisms/JSidebarAdvanced.vue.cjs"),Q=require("./components/organisms/JPageContainer.vue.cjs"),U=require("./components/organisms/JTree.vue.cjs"),V=require("./components/templates/JLayout.vue.cjs"),W=require("./components/templates/JLayoutSimple.vue.cjs"),X=require("./components/templates/JLayoutAdvanced.vue.cjs");exports.JButton=e.default;exports.JInput=t.default;exports.JTextarea=u.default;exports.JCheckbox=_.default;exports.JCombo=r.default;exports.JSearchCombo=a.default;exports.JRadio=s.default;exports.JSwitch=i.default;exports.JDatepicker=p.default;exports.JDivider=n.default;exports.JEditor=o.default;exports.JLink=c.default;exports.JImage=l.default;exports.JBadge=J.default;exports.JProgress=d.default;exports.JSpinner=v.default;exports.JAvatar=q.default;exports.JKbd=y.default;exports.JTooltip=f.default;exports.JIcon=g.default;exports.JLabel=b.default;exports.JPopover=m.default;exports.JPreview=S.default;exports.JGrid=T.default;Object.defineProperty(exports,"JToast",{enumerable:!0,get:()=>C.toast});exports.JToaster=A.default;exports.JFormField=P.default;exports.JGroupCombo=h.default;exports.JTabs=B.default;exports.JSearchAddr=F.default;exports.JContextMenu=L.default;exports.JCard=D.default;exports.JAlert=M.default;exports.JAccordion=k.default;exports.JTitlebar=x.default;exports.JButtonGroup=G.default;exports.JBreadcrumb=I.default;exports.JDynamicTabs=w.default;exports.JModal=j.default;exports.JFormModal=E.default;exports.JDynamicForm=H.default;exports.JSearchPanel=K.default;exports.JFilterBar=O.default;exports.JHeader=R.default;exports.JSidebarSimple=z.default;exports.JSidebarAdvanced=N.default;exports.JPageContainer=Q.default;exports.JTree=U.default;exports.JLayout=V.default;exports.JLayoutSimple=W.default;exports.JLayoutAdvanced=X.default;
4
4
  //# sourceMappingURL=index.cjs.map
package/index.js CHANGED
@@ -9,12 +9,12 @@ import { default as s } from "./components/atoms/JTextarea.vue.js";
9
9
  import { default as J } from "./components/atoms/JCheckbox.vue.js";
10
10
  import { default as n } from "./components/atoms/JCombo.vue.js";
11
11
  import { default as b } from "./components/atoms/JSearchCombo.vue.js";
12
- import { default as C } from "./components/atoms/JRadio.vue.js";
12
+ import { default as T } from "./components/atoms/JRadio.vue.js";
13
13
  import { default as v } from "./components/atoms/JSwitch.vue.js";
14
14
  import { default as h } from "./components/atoms/JDatepicker.vue.js";
15
- import { default as L } from "./components/atoms/JDivider.vue.js";
16
- import { default as g } from "./components/atoms/JEditor.vue.js";
17
- import { default as D } from "./components/atoms/JLink.vue.js";
15
+ import { default as B } from "./components/atoms/JDivider.vue.js";
16
+ import { default as L } from "./components/atoms/JEditor.vue.js";
17
+ import { default as g } from "./components/atoms/JLink.vue.js";
18
18
  import { default as k } from "./components/atoms/JImage.vue.js";
19
19
  import { default as I } from "./components/atoms/JBadge.vue.js";
20
20
  import { default as w } from "./components/atoms/JProgress.vue.js";
@@ -29,7 +29,7 @@ import { default as X } from "./components/atoms/JPopover.vue.js";
29
29
  import { default as Z } from "./components/atoms/JPreview.vue.js";
30
30
  import { default as $ } from "./components/atoms/JGrid.vue.js";
31
31
  import { toast as ro } from "vue-sonner";
32
- import { default as eo } from "./components/atoms/JToast.vue.js";
32
+ import { default as ao } from "./components/atoms/JToast.vue.js";
33
33
  import { default as fo } from "./components/molecules/JFormField.vue.js";
34
34
  /* empty css */
35
35
  import { default as po } from "./components/molecules/JGroupCombo.vue.js";
@@ -38,28 +38,30 @@ import { default as xo } from "./components/molecules/JSearchAddr.vue.js";
38
38
  import { default as io } from "./components/molecules/JContextMenu.vue.js";
39
39
  import { default as co } from "./components/molecules/JCard.vue.js";
40
40
  import { default as So } from "./components/molecules/JAlert.vue.js";
41
- import { default as To } from "./components/molecules/JAccordion.vue.js";
41
+ import { default as Co } from "./components/molecules/JAccordion.vue.js";
42
42
  import { default as Ao } from "./components/molecules/JTitlebar.vue.js";
43
43
  import { default as yo } from "./components/molecules/JButtonGroup.vue.js";
44
- import { default as Po } from "./components/molecules/JBreadcrumb.vue.js";
45
- import { default as Bo } from "./components/organisms/JDynamicTabs.vue.js";
46
- import { default as Fo } from "./components/organisms/JModal.vue.js";
44
+ import { default as Fo } from "./components/molecules/JBreadcrumb.vue.js";
45
+ import { default as Po } from "./components/organisms/JDynamicTabs.vue.js";
46
+ import { default as Do } from "./components/organisms/JModal.vue.js";
47
47
  import { default as Go } from "./components/organisms/JFormModal.vue.js";
48
48
  import { default as Mo } from "./components/organisms/JDynamicForm.vue.js";
49
49
  import { default as Eo } from "./components/organisms/JSearchPanel.vue.js";
50
- import { default as Ko } from "./components/organisms/JHeader.vue.js";
51
- import { default as jo } from "./components/organisms/JSidebarSimple.vue.js";
52
- import { default as zo } from "./components/organisms/JSidebarAdvanced.vue.js";
53
- import { default as Oo } from "./components/organisms/JPageContainer.vue.js";
54
- import { default as Uo } from "./components/templates/JLayout.vue.js";
55
- import { default as Wo } from "./components/templates/JLayoutSimple.vue.js";
56
- import { default as Yo } from "./components/templates/JLayoutAdvanced.vue.js";
50
+ import { default as Ko } from "./components/organisms/JFilterBar.vue.js";
51
+ import { default as jo } from "./components/organisms/JHeader.vue.js";
52
+ import { default as zo } from "./components/organisms/JSidebarSimple.vue.js";
53
+ import { default as Oo } from "./components/organisms/JSidebarAdvanced.vue.js";
54
+ import { default as Uo } from "./components/organisms/JPageContainer.vue.js";
55
+ import { default as Wo } from "./components/organisms/JTree.vue.js";
56
+ import { default as Yo } from "./components/templates/JLayout.vue.js";
57
+ import { default as _o } from "./components/templates/JLayoutSimple.vue.js";
58
+ import { default as or } from "./components/templates/JLayoutAdvanced.vue.js";
57
59
  export {
58
- To as JAccordion,
60
+ Co as JAccordion,
59
61
  So as JAlert,
60
62
  R as JAvatar,
61
63
  I as JBadge,
62
- Po as JBreadcrumb,
64
+ Fo as JBreadcrumb,
63
65
  m as JButton,
64
66
  yo as JButtonGroup,
65
67
  co as JCard,
@@ -67,42 +69,44 @@ export {
67
69
  n as JCombo,
68
70
  io as JContextMenu,
69
71
  h as JDatepicker,
70
- L as JDivider,
72
+ B as JDivider,
71
73
  Mo as JDynamicForm,
72
- Bo as JDynamicTabs,
73
- g as JEditor,
74
+ Po as JDynamicTabs,
75
+ L as JEditor,
76
+ Ko as JFilterBar,
74
77
  fo as JFormField,
75
78
  Go as JFormModal,
76
79
  $ as JGrid,
77
80
  po as JGroupCombo,
78
- Ko as JHeader,
81
+ jo as JHeader,
79
82
  Q as JIcon,
80
83
  k as JImage,
81
84
  l as JInput,
82
85
  q as JKbd,
83
86
  V as JLabel,
84
- Uo as JLayout,
85
- Yo as JLayoutAdvanced,
86
- Wo as JLayoutSimple,
87
- D as JLink,
88
- Fo as JModal,
89
- Oo as JPageContainer,
87
+ Yo as JLayout,
88
+ or as JLayoutAdvanced,
89
+ _o as JLayoutSimple,
90
+ g as JLink,
91
+ Do as JModal,
92
+ Uo as JPageContainer,
90
93
  X as JPopover,
91
94
  Z as JPreview,
92
95
  w as JProgress,
93
- C as JRadio,
96
+ T as JRadio,
94
97
  xo as JSearchAddr,
95
98
  b as JSearchCombo,
96
99
  Eo as JSearchPanel,
97
- zo as JSidebarAdvanced,
98
- jo as JSidebarSimple,
100
+ Oo as JSidebarAdvanced,
101
+ zo as JSidebarSimple,
99
102
  H as JSpinner,
100
103
  v as JSwitch,
101
104
  uo as JTabs,
102
105
  s as JTextarea,
103
106
  Ao as JTitlebar,
104
107
  ro as JToast,
105
- eo as JToaster,
106
- N as JTooltip
108
+ ao as JToaster,
109
+ N as JTooltip,
110
+ Wo as JTree
107
111
  };
108
112
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function o(n,e){if(!Array.isArray(n)||n.length===0)return[];if(!e||e.trim()==="")return n;const i=e.toLowerCase().trim(),t=[];for(const r of n){const a=r.label?.toLowerCase().includes(i)??!1;let l;r.children&&Array.isArray(r.children)&&r.children.length>0&&(l=o(r.children,e)),(a||Array.isArray(l)&&l.length>0)&&t.push({...r,children:l})}return t}function c(n){const e=new Set,i=t=>{if(Array.isArray(t)){for(const r of t)if(r.children&&Array.isArray(r.children)&&r.children.length>0){const a=r.menuKey||r.label;e.add(a),i(r.children)}}};return i(n),e}exports.filterMenuItems=o;exports.getExpandedKeysForSearch=c;
2
+ //# sourceMappingURL=menu-utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu-utils.cjs","sources":["../../../src/lib/menu-utils.ts"],"sourcesContent":["/**\n * 메뉴 유틸리티 함수\n * Menu Utility Functions\n */\n\nimport type { SidebarMenuItem } from '@/types/sidebar-menu.types'\n\n/**\n * 검색어로 메뉴 아이템을 재귀적으로 필터링\n * Recursively filters menu items by search query\n * \n * @param items - 필터링할 메뉴 아이템 배열\n * @param query - 검색어\n * @returns 필터링된 메뉴 아이템 배열\n */\nexport function filterMenuItems(\n items: SidebarMenuItem[],\n query: string\n): SidebarMenuItem[] {\n if (!Array.isArray(items) || items.length === 0) {\n return []\n }\n\n if (!query || query.trim() === '') {\n return items\n }\n\n const normalizedQuery = query.toLowerCase().trim()\n const result: SidebarMenuItem[] = []\n\n for (const item of items) {\n const matchesLabel = item.label?.toLowerCase().includes(normalizedQuery) ?? false\n\n // 하위 메뉴 검색\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n filteredChildren = filterMenuItems(item.children, query)\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/**\n * 검색 결과에서 매칭된 하위 메뉴가 있는 부모 메뉴의 키를 추출\n * Extracts keys of parent menus that have matching children in search results\n * \n * @param items - 검색 결과 메뉴 아이템 배열\n * @returns 확장해야 할 메뉴 키 Set\n */\nexport function getExpandedKeysForSearch(\n items: SidebarMenuItem[]\n): 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/**\n * 메뉴 아이템 배열을 평탄화하여 모든 아이템을 추출\n * Flattens menu items array to extract all items\n * \n * @param items - 메뉴 아이템 배열\n * @returns 평탄화된 메뉴 아이템 배열\n */\nexport function flattenMenuItems(items: SidebarMenuItem[]): SidebarMenuItem[] {\n const result: SidebarMenuItem[] = []\n\n const traverse = (menuItems: SidebarMenuItem[]): void => {\n if (!Array.isArray(menuItems)) {\n return\n }\n\n for (const item of menuItems) {\n result.push(item)\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n traverse(item.children)\n }\n }\n }\n\n traverse(items)\n return result\n}\n\n/**\n * menuKey로 메뉴 아이템 찾기\n * Find menu item by menuKey\n * \n * @param items - 메뉴 아이템 배열\n * @param menuKey - 찾을 메뉴 키\n * @returns 찾은 메뉴 아이템 또는 undefined\n */\nexport function findMenuItemByKey(\n items: SidebarMenuItem[],\n menuKey: number | string\n): SidebarMenuItem | undefined {\n const flatItems = flattenMenuItems(items)\n return flatItems.find(item => item.menuKey === menuKey)\n}\n"],"names":["filterMenuItems","items","query","normalizedQuery","result","item","matchesLabel","filteredChildren","getExpandedKeysForSearch","keysToExpand","traverse","menuItems","key"],"mappings":"gFAeO,SAASA,EACdC,EACAC,EACmB,CACnB,GAAI,CAAC,MAAM,QAAQD,CAAK,GAAKA,EAAM,SAAW,EAC5C,MAAO,CAAA,EAGT,GAAI,CAACC,GAASA,EAAM,KAAA,IAAW,GAC7B,OAAOD,EAGT,MAAME,EAAkBD,EAAM,YAAA,EAAc,KAAA,EACtCE,EAA4B,CAAA,EAElC,UAAWC,KAAQJ,EAAO,CACxB,MAAMK,EAAeD,EAAK,OAAO,cAAc,SAASF,CAAe,GAAK,GAG5E,IAAII,EACAF,EAAK,UAAY,MAAM,QAAQA,EAAK,QAAQ,GAAKA,EAAK,SAAS,OAAS,IAC1EE,EAAmBP,EAAgBK,EAAK,SAAUH,CAAK,IAIrDI,GAAiB,MAAM,QAAQC,CAAgB,GAAKA,EAAiB,OAAS,IAChFH,EAAO,KAAK,CACV,GAAGC,EACH,SAAUE,CAAA,CACX,CAEL,CAEA,OAAOH,CACT,CASO,SAASI,EACdP,EACsB,CACtB,MAAMQ,MAAmB,IAEnBC,EAAYC,GAAuC,CACvD,GAAK,MAAM,QAAQA,CAAS,GAI5B,UAAWN,KAAQM,EACjB,GAAIN,EAAK,UAAY,MAAM,QAAQA,EAAK,QAAQ,GAAKA,EAAK,SAAS,OAAS,EAAG,CAC7E,MAAMO,EAAMP,EAAK,SAAWA,EAAK,MACjCI,EAAa,IAAIG,CAAG,EACpBF,EAASL,EAAK,QAAQ,CACxB,EAEJ,EAEA,OAAAK,EAAST,CAAK,EACPQ,CACT"}
@@ -0,0 +1,33 @@
1
+ function o(n, e) {
2
+ if (!Array.isArray(n) || n.length === 0)
3
+ return [];
4
+ if (!e || e.trim() === "")
5
+ return n;
6
+ const i = e.toLowerCase().trim(), t = [];
7
+ for (const r of n) {
8
+ const a = r.label?.toLowerCase().includes(i) ?? !1;
9
+ let l;
10
+ r.children && Array.isArray(r.children) && r.children.length > 0 && (l = o(r.children, e)), (a || Array.isArray(l) && l.length > 0) && t.push({
11
+ ...r,
12
+ children: l
13
+ });
14
+ }
15
+ return t;
16
+ }
17
+ function c(n) {
18
+ const e = /* @__PURE__ */ new Set(), i = (t) => {
19
+ if (Array.isArray(t)) {
20
+ for (const r of t)
21
+ if (r.children && Array.isArray(r.children) && r.children.length > 0) {
22
+ const a = r.menuKey || r.label;
23
+ e.add(a), i(r.children);
24
+ }
25
+ }
26
+ };
27
+ return i(n), e;
28
+ }
29
+ export {
30
+ o as filterMenuItems,
31
+ c as getExpandedKeysForSearch
32
+ };
33
+ //# sourceMappingURL=menu-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu-utils.js","sources":["../../../src/lib/menu-utils.ts"],"sourcesContent":["/**\n * 메뉴 유틸리티 함수\n * Menu Utility Functions\n */\n\nimport type { SidebarMenuItem } from '@/types/sidebar-menu.types'\n\n/**\n * 검색어로 메뉴 아이템을 재귀적으로 필터링\n * Recursively filters menu items by search query\n * \n * @param items - 필터링할 메뉴 아이템 배열\n * @param query - 검색어\n * @returns 필터링된 메뉴 아이템 배열\n */\nexport function filterMenuItems(\n items: SidebarMenuItem[],\n query: string\n): SidebarMenuItem[] {\n if (!Array.isArray(items) || items.length === 0) {\n return []\n }\n\n if (!query || query.trim() === '') {\n return items\n }\n\n const normalizedQuery = query.toLowerCase().trim()\n const result: SidebarMenuItem[] = []\n\n for (const item of items) {\n const matchesLabel = item.label?.toLowerCase().includes(normalizedQuery) ?? false\n\n // 하위 메뉴 검색\n let filteredChildren: SidebarMenuItem[] | undefined = undefined\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n filteredChildren = filterMenuItems(item.children, query)\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/**\n * 검색 결과에서 매칭된 하위 메뉴가 있는 부모 메뉴의 키를 추출\n * Extracts keys of parent menus that have matching children in search results\n * \n * @param items - 검색 결과 메뉴 아이템 배열\n * @returns 확장해야 할 메뉴 키 Set\n */\nexport function getExpandedKeysForSearch(\n items: SidebarMenuItem[]\n): 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/**\n * 메뉴 아이템 배열을 평탄화하여 모든 아이템을 추출\n * Flattens menu items array to extract all items\n * \n * @param items - 메뉴 아이템 배열\n * @returns 평탄화된 메뉴 아이템 배열\n */\nexport function flattenMenuItems(items: SidebarMenuItem[]): SidebarMenuItem[] {\n const result: SidebarMenuItem[] = []\n\n const traverse = (menuItems: SidebarMenuItem[]): void => {\n if (!Array.isArray(menuItems)) {\n return\n }\n\n for (const item of menuItems) {\n result.push(item)\n if (item.children && Array.isArray(item.children) && item.children.length > 0) {\n traverse(item.children)\n }\n }\n }\n\n traverse(items)\n return result\n}\n\n/**\n * menuKey로 메뉴 아이템 찾기\n * Find menu item by menuKey\n * \n * @param items - 메뉴 아이템 배열\n * @param menuKey - 찾을 메뉴 키\n * @returns 찾은 메뉴 아이템 또는 undefined\n */\nexport function findMenuItemByKey(\n items: SidebarMenuItem[],\n menuKey: number | string\n): SidebarMenuItem | undefined {\n const flatItems = flattenMenuItems(items)\n return flatItems.find(item => item.menuKey === menuKey)\n}\n"],"names":["filterMenuItems","items","query","normalizedQuery","result","item","matchesLabel","filteredChildren","getExpandedKeysForSearch","keysToExpand","traverse","menuItems","key"],"mappings":"AAeO,SAASA,EACdC,GACAC,GACmB;AACnB,MAAI,CAAC,MAAM,QAAQD,CAAK,KAAKA,EAAM,WAAW;AAC5C,WAAO,CAAA;AAGT,MAAI,CAACC,KAASA,EAAM,KAAA,MAAW;AAC7B,WAAOD;AAGT,QAAME,IAAkBD,EAAM,YAAA,EAAc,KAAA,GACtCE,IAA4B,CAAA;AAElC,aAAWC,KAAQJ,GAAO;AACxB,UAAMK,IAAeD,EAAK,OAAO,cAAc,SAASF,CAAe,KAAK;AAG5E,QAAII;AACJ,IAAIF,EAAK,YAAY,MAAM,QAAQA,EAAK,QAAQ,KAAKA,EAAK,SAAS,SAAS,MAC1EE,IAAmBP,EAAgBK,EAAK,UAAUH,CAAK,KAIrDI,KAAiB,MAAM,QAAQC,CAAgB,KAAKA,EAAiB,SAAS,MAChFH,EAAO,KAAK;AAAA,MACV,GAAGC;AAAA,MACH,UAAUE;AAAA,IAAA,CACX;AAAA,EAEL;AAEA,SAAOH;AACT;AASO,SAASI,EACdP,GACsB;AACtB,QAAMQ,wBAAmB,IAAA,GAEnBC,IAAW,CAACC,MAAuC;AACvD,QAAK,MAAM,QAAQA,CAAS;AAI5B,iBAAWN,KAAQM;AACjB,YAAIN,EAAK,YAAY,MAAM,QAAQA,EAAK,QAAQ,KAAKA,EAAK,SAAS,SAAS,GAAG;AAC7E,gBAAMO,IAAMP,EAAK,WAAWA,EAAK;AACjC,UAAAI,EAAa,IAAIG,CAAG,GACpBF,EAASL,EAAK,QAAQ;AAAA,QACxB;AAAA;AAAA,EAEJ;AAEA,SAAAK,EAAST,CAAK,GACPQ;AACT;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@j-solution/components",
3
3
  "description": "Vue 3 Atomic Design component kit for enterprise dashboards",
4
- "version": "1.2.1",
4
+ "version": "1.4.0",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",
7
7
  "module": "./index.js",