@j-solution/components 1.6.1 → 1.7.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 (187) hide show
  1. package/README.md +8 -6
  2. package/assets/jwms-portal-frontend-CwxPfHfa.css +1 -0
  3. package/assets/styles/j-components.css +1 -1
  4. package/assets/styles/themes.css +107 -0
  5. package/components/atoms/JAvatar.vue.cjs +1 -1
  6. package/components/atoms/JAvatar.vue.cjs.map +1 -1
  7. package/components/atoms/JAvatar.vue.js +10 -7
  8. package/components/atoms/JAvatar.vue.js.map +1 -1
  9. package/components/atoms/JBadge.vue.cjs +1 -1
  10. package/components/atoms/JBadge.vue.cjs.map +1 -1
  11. package/components/atoms/JBadge.vue.js +7 -6
  12. package/components/atoms/JBadge.vue.js.map +1 -1
  13. package/components/atoms/JButton.vue.cjs +1 -1
  14. package/components/atoms/JButton.vue.cjs.map +1 -1
  15. package/components/atoms/JButton.vue.js +5 -5
  16. package/components/atoms/JButton.vue.js.map +1 -1
  17. package/components/atoms/JDatepicker.vue.cjs +1 -1
  18. package/components/atoms/JDatepicker.vue.cjs.map +1 -1
  19. package/components/atoms/JDatepicker.vue.js +10 -10
  20. package/components/atoms/JDatepicker.vue.js.map +1 -1
  21. package/components/atoms/JEditor.vue.cjs +1 -1
  22. package/components/atoms/JEditor.vue.js +1 -1
  23. package/components/atoms/JEditor.vue2.cjs +1 -1
  24. package/components/atoms/JEditor.vue2.cjs.map +1 -1
  25. package/components/atoms/JEditor.vue2.js +31 -17
  26. package/components/atoms/JEditor.vue2.js.map +1 -1
  27. package/components/atoms/JGrid.vue.cjs +1 -1
  28. package/components/atoms/JGrid.vue.js +2 -2
  29. package/components/atoms/JGrid.vue2.cjs +1 -1
  30. package/components/atoms/JGrid.vue2.cjs.map +1 -1
  31. package/components/atoms/JGrid.vue2.js +45 -33
  32. package/components/atoms/JGrid.vue2.js.map +1 -1
  33. package/components/atoms/JIcon.vue.cjs +1 -1
  34. package/components/atoms/JIcon.vue.cjs.map +1 -1
  35. package/components/atoms/JIcon.vue.js +14 -13
  36. package/components/atoms/JIcon.vue.js.map +1 -1
  37. package/components/atoms/JKbd.vue.cjs +1 -1
  38. package/components/atoms/JKbd.vue.cjs.map +1 -1
  39. package/components/atoms/JKbd.vue.js +13 -10
  40. package/components/atoms/JKbd.vue.js.map +1 -1
  41. package/components/atoms/JLabel.vue.cjs +1 -1
  42. package/components/atoms/JLabel.vue.cjs.map +1 -1
  43. package/components/atoms/JLabel.vue.js +4 -4
  44. package/components/atoms/JLabel.vue.js.map +1 -1
  45. package/components/atoms/JLink.vue.cjs +1 -1
  46. package/components/atoms/JLink.vue.cjs.map +1 -1
  47. package/components/atoms/JLink.vue.js +5 -5
  48. package/components/atoms/JLink.vue.js.map +1 -1
  49. package/components/atoms/JPreview.vue.cjs +1 -1
  50. package/components/atoms/JPreview.vue.js +2 -2
  51. package/components/atoms/JPreview.vue2.cjs +1 -1
  52. package/components/atoms/JPreview.vue2.cjs.map +1 -1
  53. package/components/atoms/JPreview.vue2.js +33 -20
  54. package/components/atoms/JPreview.vue2.js.map +1 -1
  55. package/components/atoms/JProgress.vue.cjs +1 -1
  56. package/components/atoms/JProgress.vue.cjs.map +1 -1
  57. package/components/atoms/JProgress.vue.js +15 -9
  58. package/components/atoms/JProgress.vue.js.map +1 -1
  59. package/components/atoms/JRadio.vue.cjs +1 -1
  60. package/components/atoms/JRadio.vue.cjs.map +1 -1
  61. package/components/atoms/JRadio.vue.js +1 -1
  62. package/components/atoms/JRadio.vue.js.map +1 -1
  63. package/components/atoms/JSearchCombo.vue.cjs +1 -1
  64. package/components/atoms/JSearchCombo.vue.cjs.map +1 -1
  65. package/components/atoms/JSearchCombo.vue.js +38 -37
  66. package/components/atoms/JSearchCombo.vue.js.map +1 -1
  67. package/components/atoms/JSpinner.vue.cjs +1 -1
  68. package/components/atoms/JSpinner.vue.cjs.map +1 -1
  69. package/components/atoms/JSpinner.vue.js +8 -7
  70. package/components/atoms/JSpinner.vue.js.map +1 -1
  71. package/components/atoms/JSplitter.vue.cjs +1 -1
  72. package/components/atoms/JSplitter.vue.cjs.map +1 -1
  73. package/components/atoms/JSplitter.vue.js +32 -27
  74. package/components/atoms/JSplitter.vue.js.map +1 -1
  75. package/components/atoms/JTooltip.vue.cjs +1 -1
  76. package/components/atoms/JTooltip.vue.cjs.map +1 -1
  77. package/components/atoms/JTooltip.vue.js +18 -15
  78. package/components/atoms/JTooltip.vue.js.map +1 -1
  79. package/components/examples/ExampleCrudPage.vue.cjs +1 -1
  80. package/components/examples/ExampleCrudPage.vue.cjs.map +1 -1
  81. package/components/examples/ExampleCrudPage.vue.js +162 -108
  82. package/components/examples/ExampleCrudPage.vue.js.map +1 -1
  83. package/components/examples/ExampleTabMappingPage.vue.cjs +1 -1
  84. package/components/examples/ExampleTabMappingPage.vue.cjs.map +1 -1
  85. package/components/examples/ExampleTabMappingPage.vue.js +162 -119
  86. package/components/examples/ExampleTabMappingPage.vue.js.map +1 -1
  87. package/components/molecules/JBreadcrumb.vue.cjs +1 -1
  88. package/components/molecules/JBreadcrumb.vue.cjs.map +1 -1
  89. package/components/molecules/JBreadcrumb.vue.js +3 -3
  90. package/components/molecules/JBreadcrumb.vue.js.map +1 -1
  91. package/components/molecules/JFormField.vue.cjs +1 -1
  92. package/components/molecules/JFormField.vue.cjs.map +1 -1
  93. package/components/molecules/JFormField.vue.js +26 -24
  94. package/components/molecules/JFormField.vue.js.map +1 -1
  95. package/components/molecules/JTabs.vue.cjs +1 -1
  96. package/components/molecules/JTabs.vue.js +1 -1
  97. package/components/molecules/JTabs.vue2.cjs +1 -1
  98. package/components/molecules/JTabs.vue2.cjs.map +1 -1
  99. package/components/molecules/JTabs.vue2.js +7 -7
  100. package/components/molecules/JTabs.vue2.js.map +1 -1
  101. package/components/molecules/JTitlebar.vue.cjs +1 -1
  102. package/components/molecules/JTitlebar.vue.cjs.map +1 -1
  103. package/components/molecules/JTitlebar.vue.js +35 -36
  104. package/components/molecules/JTitlebar.vue.js.map +1 -1
  105. package/components/organisms/JFilterBar.vue.cjs +1 -1
  106. package/components/organisms/JFilterBar.vue.cjs.map +1 -1
  107. package/components/organisms/JFilterBar.vue.js +5 -5
  108. package/components/organisms/JFilterBar.vue.js.map +1 -1
  109. package/components/organisms/JHeader.vue.cjs +1 -1
  110. package/components/organisms/JHeader.vue.cjs.map +1 -1
  111. package/components/organisms/JHeader.vue.js +25 -23
  112. package/components/organisms/JHeader.vue.js.map +1 -1
  113. package/components/organisms/JModal.vue.cjs +1 -1
  114. package/components/organisms/JModal.vue.cjs.map +1 -1
  115. package/components/organisms/JModal.vue.js +30 -27
  116. package/components/organisms/JModal.vue.js.map +1 -1
  117. package/components/organisms/JSidebarAdvanced.vue.cjs +1 -1
  118. package/components/organisms/JSidebarAdvanced.vue.js +7 -7
  119. package/components/organisms/JSidebarAdvanced.vue2.cjs +1 -1
  120. package/components/organisms/JSidebarAdvanced.vue2.cjs.map +1 -1
  121. package/components/organisms/JSidebarAdvanced.vue2.js +40 -40
  122. package/components/organisms/JSidebarAdvanced.vue2.js.map +1 -1
  123. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs +1 -1
  124. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.cjs.map +1 -1
  125. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js +83 -63
  126. package/components/organisms/JSidebarSimple/JDynamicMenuItem.vue.js.map +1 -1
  127. package/components/organisms/JSidebarSimple.vue.cjs +1 -1
  128. package/components/organisms/JSidebarSimple.vue.js +2 -2
  129. package/components/organisms/JSidebarSimple.vue2.cjs +1 -1
  130. package/components/organisms/JSidebarSimple.vue2.cjs.map +1 -1
  131. package/components/organisms/JSidebarSimple.vue2.js +2 -2
  132. package/components/organisms/JSidebarSimple.vue2.js.map +1 -1
  133. package/components/shadcn/AccordionTrigger.vue.cjs +1 -1
  134. package/components/shadcn/AccordionTrigger.vue.cjs.map +1 -1
  135. package/components/shadcn/AccordionTrigger.vue.js +3 -3
  136. package/components/shadcn/AccordionTrigger.vue.js.map +1 -1
  137. package/components/shadcn/CardContent.vue.cjs +1 -1
  138. package/components/shadcn/CardContent.vue.cjs.map +1 -1
  139. package/components/shadcn/CardContent.vue.js +1 -1
  140. package/components/shadcn/CardContent.vue.js.map +1 -1
  141. package/components/shadcn/CardDescription.vue.cjs +1 -1
  142. package/components/shadcn/CardDescription.vue.cjs.map +1 -1
  143. package/components/shadcn/CardDescription.vue.js +1 -1
  144. package/components/shadcn/CardDescription.vue.js.map +1 -1
  145. package/components/shadcn/CardFooter.vue.cjs +1 -1
  146. package/components/shadcn/CardFooter.vue.cjs.map +1 -1
  147. package/components/shadcn/CardFooter.vue.js +7 -7
  148. package/components/shadcn/CardFooter.vue.js.map +1 -1
  149. package/components/shadcn/CardHeader.vue.cjs +1 -1
  150. package/components/shadcn/CardHeader.vue.cjs.map +1 -1
  151. package/components/shadcn/CardHeader.vue.js +8 -8
  152. package/components/shadcn/CardHeader.vue.js.map +1 -1
  153. package/components/shadcn/CardTitle.vue.cjs +1 -1
  154. package/components/shadcn/CardTitle.vue.cjs.map +1 -1
  155. package/components/shadcn/CardTitle.vue.js +5 -5
  156. package/components/shadcn/CardTitle.vue.js.map +1 -1
  157. package/components/shadcn/Input.vue.cjs +1 -1
  158. package/components/shadcn/Input.vue.cjs.map +1 -1
  159. package/components/shadcn/Input.vue.js +1 -1
  160. package/components/shadcn/Input.vue.js.map +1 -1
  161. package/components/shadcn/SelectTrigger.vue.cjs +1 -1
  162. package/components/shadcn/SelectTrigger.vue.cjs.map +1 -1
  163. package/components/shadcn/SelectTrigger.vue.js +2 -2
  164. package/components/shadcn/SelectTrigger.vue.js.map +1 -1
  165. package/components/shadcn/Switch.vue.cjs +1 -1
  166. package/components/shadcn/Switch.vue.cjs.map +1 -1
  167. package/components/shadcn/Switch.vue.js +2 -2
  168. package/components/shadcn/Switch.vue.js.map +1 -1
  169. package/components/shadcn/TabsList.vue.cjs +1 -1
  170. package/components/shadcn/TabsList.vue.cjs.map +1 -1
  171. package/components/shadcn/TabsList.vue.js +1 -1
  172. package/components/shadcn/TabsList.vue.js.map +1 -1
  173. package/components/shadcn/TabsTrigger.vue.cjs +1 -1
  174. package/components/shadcn/TabsTrigger.vue.cjs.map +1 -1
  175. package/components/shadcn/TabsTrigger.vue.js +4 -4
  176. package/components/shadcn/TabsTrigger.vue.js.map +1 -1
  177. package/components/shadcn/Textarea.vue.cjs +1 -1
  178. package/components/shadcn/Textarea.vue.cjs.map +1 -1
  179. package/components/shadcn/Textarea.vue.js +2 -2
  180. package/components/shadcn/Textarea.vue.js.map +1 -1
  181. package/components/shadcn/index.cjs +1 -1
  182. package/components/shadcn/index.cjs.map +1 -1
  183. package/components/shadcn/index.js +8 -7
  184. package/components/shadcn/index.js.map +1 -1
  185. package/package.json +1 -1
  186. package/types/index.d.ts +131 -15
  187. package/assets/jwms-portal-frontend-DntSIcYt.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"JTooltip.vue.cjs","sources":["../../../../src/components/atoms/JTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\r\nimport Tooltip from '@/components/shadcn/Tooltip.vue'\r\nimport TooltipContent from '@/components/shadcn/TooltipContent.vue'\r\nimport TooltipProvider from '@/components/shadcn/TooltipProvider.vue'\r\nimport TooltipTrigger from '@/components/shadcn/TooltipTrigger.vue'\r\n\r\ntype StyleType =\r\n | 'default' // 기본 스타일\r\n | 'primary' // 강조 스타일 (파랑)\r\n | 'success' // 성공 스타일 (초록)\r\n | 'warning' // 경고 스타일 (주황)\r\n | 'danger' // 위험 스타일 (빨강)\r\n\r\ntype Size = 'sm' | 'md' | 'lg'\r\n\r\ntype Trigger = 'hover' | 'focus' | 'click' | 'manual'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n class?: string\r\n /** 스타일 프리셋 */\r\n styletype?: StyleType\r\n /** 툴팁 크기 */\r\n size?: Size\r\n /** 툴팁 비활성화 */\r\n disabled?: boolean\r\n /** 표시 지연 시간 (ms) */\r\n delay?: number\r\n /** 툴팁 최대 너비 */\r\n maxWidth?: string | number\r\n /** 툴팁 트리거 타입 */\r\n trigger?: Trigger\r\n }>(),\r\n {\r\n side: 'top',\r\n align: 'center',\r\n styletype: 'default',\r\n size: 'md',\r\n disabled: false,\r\n delay: 200,\r\n maxWidth: '200px',\r\n trigger: 'hover',\r\n },\r\n)\r\n\r\n/**\r\n * styletype -> class 매핑\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\r\n default: { class: '' },\r\n primary: { \r\n class: 'bg-blue-500 text-white border-blue-600',\r\n },\r\n success: { \r\n class: 'bg-green-500 text-white border-green-600',\r\n },\r\n warning: { \r\n class: 'bg-amber-500 text-white border-amber-600',\r\n },\r\n danger: { \r\n class: 'bg-red-500 text-white border-red-600',\r\n },\r\n}\r\n\r\n/**\r\n * size -> class 매핑\r\n */\r\nconst SIZE_PRESETS: Record<Size, { class: string }> = {\r\n sm: { \r\n class: 'text-xs px-2 py-1',\r\n },\r\n md: { \r\n class: 'text-sm px-3 py-1.5',\r\n },\r\n lg: { \r\n class: 'text-base px-4 py-2',\r\n },\r\n}\r\n\r\n// click과 manual 트리거를 위한 상태 관리\r\nconst isOpen = ref(false)\r\n\r\n// 각 트리거 타입별 핸들러\r\nconst handleClick = (event: MouseEvent) => {\r\n console.log('Click handler called, trigger:', props.trigger)\r\n if (props.trigger === 'click') {\r\n console.log('Toggling tooltip, current state:', isOpen.value)\r\n isOpen.value = !isOpen.value\r\n console.log('New state:', isOpen.value)\r\n } else if (props.trigger === 'focus') {\r\n // focus 트리거에서는 클릭 이벤트 무시\r\n event.preventDefault()\r\n event.stopPropagation()\r\n }\r\n}\r\n\r\n// delay를 위한 타이머 관리\r\nlet hoverTimer: number | null = null\r\n\r\nconst handleMouseEnter = () => {\r\n if (props.trigger === 'hover') {\r\n // 기존 타이머가 있으면 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n // delay 적용\r\n hoverTimer = setTimeout(() => {\r\n isOpen.value = true\r\n }, props.delay)\r\n }\r\n}\r\n\r\nconst handleMouseLeave = () => {\r\n if (props.trigger === 'hover') {\r\n // 타이머 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n hoverTimer = null\r\n }\r\n isOpen.value = false\r\n }\r\n}\r\n\r\nconst handleFocus = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst handleBlur = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 트리거 타입에 따른 Tooltip 설정 계산\r\nconst tooltipConfig = computed(() => {\r\n const config: any = {\r\n disabled: props.disabled,\r\n }\r\n \r\n // 모든 트리거 타입에 대해 수동 제어\r\n config.open = isOpen.value\r\n \r\n return config\r\n})\r\n\r\n// 외부 클릭 감지를 위한 핸들러\r\nconst handleOutsideClick = (event: Event) => {\r\n if (props.trigger === 'hover' && isOpen.value) {\r\n const target = event.target as HTMLElement\r\n const tooltipElement = document.querySelector('[data-tooltip-trigger]')\r\n if (tooltipElement && !tooltipElement.contains(target)) {\r\n isOpen.value = false\r\n }\r\n }\r\n}\r\n\r\n// manual 트리거를 위한 메서드들\r\nconst showTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst hideTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 외부에서 사용할 수 있도록 expose\r\ndefineExpose({\r\n showTooltip,\r\n hideTooltip,\r\n})\r\n\r\n// 외부 클릭 감지를 위한 이벤트 리스너 등록/해제\r\nonMounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.addEventListener('click', handleOutsideClick)\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.removeEventListener('click', handleOutsideClick)\r\n }\r\n \r\n // 타이머 정리\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n})\r\n\r\n/** 최종 바인딩: 직접 넘긴 class가 있으면 styletype과 size 기본값과 병합 */\r\nconst mapped = computed(() => {\r\n const stylePreset = STYLE_PRESETS[props.styletype!]\r\n const sizePreset = SIZE_PRESETS[props.size!]\r\n const finalClass = [stylePreset.class, sizePreset.class, props.class].filter(Boolean).join(' ')\r\n \r\n // maxWidth 스타일 처리\r\n const maxWidthStyle = typeof props.maxWidth === 'number' \r\n ? `${props.maxWidth}px` \r\n : props.maxWidth\r\n \r\n return {\r\n side: props.side,\r\n align: props.align,\r\n class: finalClass,\r\n style: {\r\n maxWidth: maxWidthStyle,\r\n },\r\n }\r\n})\r\n</script>\r\n\r\n<template>\r\n <TooltipProvider :delayDuration=\"props.delay\">\r\n <Tooltip v-bind=\"tooltipConfig\">\r\n <TooltipTrigger \r\n as-child\r\n :data-tooltip-trigger=\"true\"\r\n @click=\"handleClick\"\r\n @mouseenter=\"handleMouseEnter\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n >\r\n <slot name=\"trigger\" />\r\n </TooltipTrigger>\r\n <TooltipContent v-bind=\"mapped\">\r\n {{ props.content }}\r\n </TooltipContent>\r\n </Tooltip>\r\n </TooltipProvider>\r\n</template>\r\n"],"names":["props","__props","STYLE_PRESETS","SIZE_PRESETS","isOpen","ref","handleClick","event","hoverTimer","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","tooltipConfig","computed","config","handleOutsideClick","target","tooltipElement","__expose","onMounted","onUnmounted","mapped","stylePreset","sizePreset","finalClass","maxWidthStyle","_createBlock","TooltipProvider","_createVNode","Tooltip","TooltipTrigger","_renderSlot","_ctx","TooltipContent","_createTextVNode","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"JTooltip.vue.cjs","sources":["../../../../src/components/atoms/JTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\r\nimport Tooltip from '@/components/shadcn/Tooltip.vue'\r\nimport TooltipContent from '@/components/shadcn/TooltipContent.vue'\r\nimport TooltipProvider from '@/components/shadcn/TooltipProvider.vue'\r\nimport TooltipTrigger from '@/components/shadcn/TooltipTrigger.vue'\r\n\r\ntype StyleType =\r\n | 'default' // 기본 스타일\r\n | 'primary' // 강조 스타일 (파랑)\r\n | 'success' // 성공 스타일 (초록)\r\n | 'warning' // 경고 스타일 (주황)\r\n | 'danger' // 위험 스타일 (빨강)\r\n\r\ntype Size = 'xs' | 'sm' | 'md' | 'lg'\n\r\ntype Trigger = 'hover' | 'focus' | 'click' | 'manual'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n class?: string\r\n /** 스타일 프리셋 */\r\n styletype?: StyleType\r\n /** 툴팁 크기 */\r\n size?: Size\r\n /** 툴팁 비활성화 */\r\n disabled?: boolean\r\n /** 표시 지연 시간 (ms) */\r\n delay?: number\r\n /** 툴팁 최대 너비 */\r\n maxWidth?: string | number\r\n /** 툴팁 트리거 타입 */\r\n trigger?: Trigger\r\n }>(),\r\n {\n side: 'top',\n align: 'center',\n styletype: 'default',\n size: 'sm',\n disabled: false,\n delay: 200,\n maxWidth: '200px',\n trigger: 'hover',\r\n },\r\n)\r\n\r\n/**\r\n * styletype -> class 매핑\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\r\n default: { class: '' },\r\n primary: { \r\n class: 'bg-blue-500 text-white border-blue-600',\r\n },\r\n success: { \r\n class: 'bg-green-500 text-white border-green-600',\r\n },\r\n warning: { \r\n class: 'bg-amber-500 text-white border-amber-600',\r\n },\r\n danger: { \r\n class: 'bg-red-500 text-white border-red-600',\r\n },\r\n}\r\n\r\n/**\r\n * size -> class 매핑\r\n */\r\nconst SIZE_PRESETS: Record<Size, { class: string }> = {\n xs: { \n class: 'text-[10px] px-1.5 py-0.5 max-w-40',\n },\n sm: { \n class: 'text-xs px-2 py-1 max-w-48',\n },\n md: { \n class: 'text-xs px-2.5 py-1 max-w-56',\n },\n lg: { \n class: 'text-sm px-3 py-1.5 max-w-64',\n },\n}\n\r\n// click과 manual 트리거를 위한 상태 관리\r\nconst isOpen = ref(false)\r\n\r\n// 각 트리거 타입별 핸들러\r\nconst handleClick = (event: MouseEvent) => {\r\n console.log('Click handler called, trigger:', props.trigger)\r\n if (props.trigger === 'click') {\r\n console.log('Toggling tooltip, current state:', isOpen.value)\r\n isOpen.value = !isOpen.value\r\n console.log('New state:', isOpen.value)\r\n } else if (props.trigger === 'focus') {\r\n // focus 트리거에서는 클릭 이벤트 무시\r\n event.preventDefault()\r\n event.stopPropagation()\r\n }\r\n}\r\n\r\n// delay를 위한 타이머 관리\r\nlet hoverTimer: number | null = null\r\n\r\nconst handleMouseEnter = () => {\r\n if (props.trigger === 'hover') {\r\n // 기존 타이머가 있으면 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n // delay 적용\r\n hoverTimer = setTimeout(() => {\r\n isOpen.value = true\r\n }, props.delay)\r\n }\r\n}\r\n\r\nconst handleMouseLeave = () => {\r\n if (props.trigger === 'hover') {\r\n // 타이머 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n hoverTimer = null\r\n }\r\n isOpen.value = false\r\n }\r\n}\r\n\r\nconst handleFocus = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst handleBlur = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 트리거 타입에 따른 Tooltip 설정 계산\r\nconst tooltipConfig = computed(() => {\r\n const config: any = {\r\n disabled: props.disabled,\r\n }\r\n \r\n // 모든 트리거 타입에 대해 수동 제어\r\n config.open = isOpen.value\r\n \r\n return config\r\n})\r\n\r\n// 외부 클릭 감지를 위한 핸들러\r\nconst handleOutsideClick = (event: Event) => {\r\n if (props.trigger === 'hover' && isOpen.value) {\r\n const target = event.target as HTMLElement\r\n const tooltipElement = document.querySelector('[data-tooltip-trigger]')\r\n if (tooltipElement && !tooltipElement.contains(target)) {\r\n isOpen.value = false\r\n }\r\n }\r\n}\r\n\r\n// manual 트리거를 위한 메서드들\r\nconst showTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst hideTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 외부에서 사용할 수 있도록 expose\r\ndefineExpose({\r\n showTooltip,\r\n hideTooltip,\r\n})\r\n\r\n// 외부 클릭 감지를 위한 이벤트 리스너 등록/해제\r\nonMounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.addEventListener('click', handleOutsideClick)\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.removeEventListener('click', handleOutsideClick)\r\n }\r\n \r\n // 타이머 정리\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n})\r\n\r\n/** 최종 바인딩: 직접 넘긴 class가 있으면 styletype과 size 기본값과 병합 */\r\nconst mapped = computed(() => {\r\n const stylePreset = STYLE_PRESETS[props.styletype!]\r\n const sizePreset = SIZE_PRESETS[props.size!]\r\n const finalClass = [stylePreset.class, sizePreset.class, props.class].filter(Boolean).join(' ')\r\n \r\n // maxWidth 스타일 처리\r\n const maxWidthStyle = typeof props.maxWidth === 'number' \r\n ? `${props.maxWidth}px` \r\n : props.maxWidth\r\n \r\n return {\r\n side: props.side,\r\n align: props.align,\r\n class: finalClass,\r\n style: {\r\n maxWidth: maxWidthStyle,\r\n },\r\n }\r\n})\r\n</script>\r\n\r\n<template>\r\n <TooltipProvider :delayDuration=\"props.delay\">\r\n <Tooltip v-bind=\"tooltipConfig\">\r\n <TooltipTrigger \r\n as-child\r\n :data-tooltip-trigger=\"true\"\r\n @click=\"handleClick\"\r\n @mouseenter=\"handleMouseEnter\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n >\r\n <slot name=\"trigger\" />\r\n </TooltipTrigger>\r\n <TooltipContent v-bind=\"mapped\">\r\n {{ props.content }}\r\n </TooltipContent>\r\n </Tooltip>\r\n </TooltipProvider>\r\n</template>\r\n"],"names":["props","__props","STYLE_PRESETS","SIZE_PRESETS","isOpen","ref","handleClick","event","hoverTimer","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","tooltipConfig","computed","config","handleOutsideClick","target","tooltipElement","__expose","onMounted","onUnmounted","mapped","stylePreset","sizePreset","finalClass","maxWidthStyle","_createBlock","TooltipProvider","_createVNode","Tooltip","TooltipTrigger","_renderSlot","_ctx","TooltipContent","_createTextVNode","_toDisplayString"],"mappings":"wlBAkBA,MAAMA,EAAQC,EAkCRC,EAAsD,CAC1D,QAAS,CAAE,MAAO,EAAA,EAClB,QAAS,CACP,MAAO,wCAAA,EAET,QAAS,CACP,MAAO,0CAAA,EAET,QAAS,CACP,MAAO,0CAAA,EAET,OAAQ,CACN,MAAO,sCAAA,CACT,EAMIC,EAAgD,CACpD,GAAI,CACF,MAAO,oCAAA,EAET,GAAI,CACF,MAAO,4BAAA,EAET,GAAI,CACF,MAAO,8BAAA,EAET,GAAI,CACF,MAAO,8BAAA,CACT,EAIIC,EAASC,EAAAA,IAAI,EAAK,EAGlBC,EAAeC,GAAsB,CACzC,QAAQ,IAAI,iCAAkCP,EAAM,OAAO,EACvDA,EAAM,UAAY,SACpB,QAAQ,IAAI,mCAAoCI,EAAO,KAAK,EAC5DA,EAAO,MAAQ,CAACA,EAAO,MACvB,QAAQ,IAAI,aAAcA,EAAO,KAAK,GAC7BJ,EAAM,UAAY,UAE3BO,EAAM,eAAA,EACNA,EAAM,gBAAA,EAEV,EAGA,IAAIC,EAA4B,KAEhC,MAAMC,EAAmB,IAAM,CACzBT,EAAM,UAAY,UAEhBQ,GACF,aAAaA,CAAU,EAGzBA,EAAa,WAAW,IAAM,CAC5BJ,EAAO,MAAQ,EACjB,EAAGJ,EAAM,KAAK,EAElB,EAEMU,EAAmB,IAAM,CACzBV,EAAM,UAAY,UAEhBQ,IACF,aAAaA,CAAU,EACvBA,EAAa,MAEfJ,EAAO,MAAQ,GAEnB,EAEMO,EAAc,IAAM,CACpBX,EAAM,UAAY,UACpBI,EAAO,MAAQ,GAEnB,EAEMQ,EAAa,IAAM,CACnBZ,EAAM,UAAY,UACpBI,EAAO,MAAQ,GAEnB,EAGMS,EAAgBC,EAAAA,SAAS,IAAM,CACnC,MAAMC,EAAc,CAClB,SAAUf,EAAM,QAAA,EAIlB,OAAAe,EAAO,KAAOX,EAAO,MAEdW,CACT,CAAC,EAGKC,EAAsBT,GAAiB,CAC3C,GAAIP,EAAM,UAAY,SAAWI,EAAO,MAAO,CAC7C,MAAMa,EAASV,EAAM,OACfW,EAAiB,SAAS,cAAc,wBAAwB,EAClEA,GAAkB,CAACA,EAAe,SAASD,CAAM,IACnDb,EAAO,MAAQ,GAEnB,CACF,EAgBAe,EAAa,CACX,YAdkB,IAAM,CACpBnB,EAAM,UAAY,WACpBI,EAAO,MAAQ,GAEnB,EAWE,YATkB,IAAM,CACpBJ,EAAM,UAAY,WACpBI,EAAO,MAAQ,GAEnB,CAKE,CACD,EAGDgB,EAAAA,UAAU,IAAM,CACVpB,EAAM,UAAY,SACpB,SAAS,iBAAiB,QAASgB,CAAkB,CAEzD,CAAC,EAEDK,EAAAA,YAAY,IAAM,CACZrB,EAAM,UAAY,SACpB,SAAS,oBAAoB,QAASgB,CAAkB,EAItDR,GACF,aAAaA,CAAU,CAE3B,CAAC,EAGD,MAAMc,EAASR,EAAAA,SAAS,IAAM,CAC5B,MAAMS,EAAcrB,EAAcF,EAAM,SAAU,EAC5CwB,EAAarB,EAAaH,EAAM,IAAK,EACrCyB,EAAa,CAACF,EAAY,MAAOC,EAAW,MAAOxB,EAAM,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAGxF0B,EAAgB,OAAO1B,EAAM,UAAa,SAC5C,GAAGA,EAAM,QAAQ,KACjBA,EAAM,SAEV,MAAO,CACL,KAAMA,EAAM,KACZ,MAAOA,EAAM,MACb,MAAOyB,EACP,MAAO,CACL,SAAUC,CAAA,CACZ,CAEJ,CAAC,8BAICC,EAAAA,YAiBkBC,UAAA,CAjBA,cAAe5B,EAAM,KAAA,qBACrC,IAeU,CAfV6B,EAAAA,YAeUC,EAAAA,8CAfOjB,EAAA,KAAa,CAAA,EAAA,mBAC5B,IAUiB,CAVjBgB,EAAAA,YAUiBE,EAAAA,QAAA,CATf,WAAA,GACC,uBAAsB,GACtB,QAAOzB,EACP,aAAYG,EACZ,aAAYC,EACZ,QAAOC,EACP,OAAMC,CAAA,qBAEP,IAAuB,CAAvBoB,aAAuBC,EAAA,OAAA,SAAA,CAAA,SAEzBJ,EAAAA,YAEiBK,EAAAA,8CAFOZ,EAAA,KAAM,CAAA,EAAA,mBAC5B,IAAmB,CAAhBa,EAAAA,gBAAAC,EAAAA,gBAAApC,EAAM,OAAO,EAAA,CAAA,CAAA"}
@@ -1,9 +1,9 @@
1
- import { defineComponent as S, ref as k, computed as c, onMounted as w, onUnmounted as C, createBlock as P, openBlock as B, withCtx as s, createVNode as i, normalizeProps as u, guardReactiveProps as d, renderSlot as W, createTextVNode as $, toDisplayString as M } from "vue";
1
+ import { defineComponent as E, ref as S, computed as c, onMounted as k, onUnmounted as C, createBlock as P, openBlock as B, withCtx as s, createVNode as i, normalizeProps as u, guardReactiveProps as d, renderSlot as W, createTextVNode as $, toDisplayString as M } from "vue";
2
2
  import z from "../shadcn/Tooltip.vue.js";
3
3
  import D from "../shadcn/TooltipContent.vue.js";
4
4
  import L from "../shadcn/TooltipProvider.vue.js";
5
5
  import N from "../shadcn/TooltipTrigger.vue.js";
6
- const J = /* @__PURE__ */ S({
6
+ const J = /* @__PURE__ */ E({
7
7
  __name: "JTooltip",
8
8
  props: {
9
9
  content: {},
@@ -11,7 +11,7 @@ const J = /* @__PURE__ */ S({
11
11
  align: { default: "center" },
12
12
  class: {},
13
13
  styletype: { default: "default" },
14
- size: { default: "md" },
14
+ size: { default: "sm" },
15
15
  disabled: { type: Boolean, default: !1 },
16
16
  delay: { default: 200 },
17
17
  maxWidth: { default: "200px" },
@@ -33,24 +33,27 @@ const J = /* @__PURE__ */ S({
33
33
  class: "bg-red-500 text-white border-red-600"
34
34
  }
35
35
  }, m = {
36
+ xs: {
37
+ class: "text-[10px] px-1.5 py-0.5 max-w-40"
38
+ },
36
39
  sm: {
37
- class: "text-xs px-2 py-1"
40
+ class: "text-xs px-2 py-1 max-w-48"
38
41
  },
39
42
  md: {
40
- class: "text-sm px-3 py-1.5"
43
+ class: "text-xs px-2.5 py-1 max-w-56"
41
44
  },
42
45
  lg: {
43
- class: "text-base px-4 py-2"
46
+ class: "text-sm px-3 py-1.5 max-w-64"
44
47
  }
45
- }, t = k(!1), h = (o) => {
48
+ }, t = S(!1), x = (o) => {
46
49
  console.log("Click handler called, trigger:", e.trigger), e.trigger === "click" ? (console.log("Toggling tooltip, current state:", t.value), t.value = !t.value, console.log("New state:", t.value)) : e.trigger === "focus" && (o.preventDefault(), o.stopPropagation());
47
50
  };
48
51
  let l = null;
49
- const v = () => {
52
+ const h = () => {
50
53
  e.trigger === "hover" && (l && clearTimeout(l), l = setTimeout(() => {
51
54
  t.value = !0;
52
55
  }, e.delay));
53
- }, x = () => {
56
+ }, v = () => {
54
57
  e.trigger === "hover" && (l && (clearTimeout(l), l = null), t.value = !1);
55
58
  }, y = () => {
56
59
  e.trigger === "focus" && (t.value = !0);
@@ -74,19 +77,19 @@ const J = /* @__PURE__ */ S({
74
77
  hideTooltip: () => {
75
78
  e.trigger === "manual" && (t.value = !1);
76
79
  }
77
- }), w(() => {
80
+ }), k(() => {
78
81
  e.trigger === "hover" && document.addEventListener("click", n);
79
82
  }), C(() => {
80
83
  e.trigger === "hover" && document.removeEventListener("click", n), l && clearTimeout(l);
81
84
  });
82
85
  const T = c(() => {
83
- const o = p[e.styletype], a = m[e.size], r = [o.class, a.class, e.class].filter(Boolean).join(" "), E = typeof e.maxWidth == "number" ? `${e.maxWidth}px` : e.maxWidth;
86
+ const o = p[e.styletype], a = m[e.size], r = [o.class, a.class, e.class].filter(Boolean).join(" "), w = typeof e.maxWidth == "number" ? `${e.maxWidth}px` : e.maxWidth;
84
87
  return {
85
88
  side: e.side,
86
89
  align: e.align,
87
90
  class: r,
88
91
  style: {
89
- maxWidth: E
92
+ maxWidth: w
90
93
  }
91
94
  };
92
95
  });
@@ -99,9 +102,9 @@ const J = /* @__PURE__ */ S({
99
102
  i(N, {
100
103
  "as-child": "",
101
104
  "data-tooltip-trigger": !0,
102
- onClick: h,
103
- onMouseenter: v,
104
- onMouseleave: x,
105
+ onClick: x,
106
+ onMouseenter: h,
107
+ onMouseleave: v,
105
108
  onFocus: y,
106
109
  onBlur: _
107
110
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"JTooltip.vue.js","sources":["../../../../src/components/atoms/JTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\r\nimport Tooltip from '@/components/shadcn/Tooltip.vue'\r\nimport TooltipContent from '@/components/shadcn/TooltipContent.vue'\r\nimport TooltipProvider from '@/components/shadcn/TooltipProvider.vue'\r\nimport TooltipTrigger from '@/components/shadcn/TooltipTrigger.vue'\r\n\r\ntype StyleType =\r\n | 'default' // 기본 스타일\r\n | 'primary' // 강조 스타일 (파랑)\r\n | 'success' // 성공 스타일 (초록)\r\n | 'warning' // 경고 스타일 (주황)\r\n | 'danger' // 위험 스타일 (빨강)\r\n\r\ntype Size = 'sm' | 'md' | 'lg'\r\n\r\ntype Trigger = 'hover' | 'focus' | 'click' | 'manual'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n class?: string\r\n /** 스타일 프리셋 */\r\n styletype?: StyleType\r\n /** 툴팁 크기 */\r\n size?: Size\r\n /** 툴팁 비활성화 */\r\n disabled?: boolean\r\n /** 표시 지연 시간 (ms) */\r\n delay?: number\r\n /** 툴팁 최대 너비 */\r\n maxWidth?: string | number\r\n /** 툴팁 트리거 타입 */\r\n trigger?: Trigger\r\n }>(),\r\n {\r\n side: 'top',\r\n align: 'center',\r\n styletype: 'default',\r\n size: 'md',\r\n disabled: false,\r\n delay: 200,\r\n maxWidth: '200px',\r\n trigger: 'hover',\r\n },\r\n)\r\n\r\n/**\r\n * styletype -> class 매핑\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\r\n default: { class: '' },\r\n primary: { \r\n class: 'bg-blue-500 text-white border-blue-600',\r\n },\r\n success: { \r\n class: 'bg-green-500 text-white border-green-600',\r\n },\r\n warning: { \r\n class: 'bg-amber-500 text-white border-amber-600',\r\n },\r\n danger: { \r\n class: 'bg-red-500 text-white border-red-600',\r\n },\r\n}\r\n\r\n/**\r\n * size -> class 매핑\r\n */\r\nconst SIZE_PRESETS: Record<Size, { class: string }> = {\r\n sm: { \r\n class: 'text-xs px-2 py-1',\r\n },\r\n md: { \r\n class: 'text-sm px-3 py-1.5',\r\n },\r\n lg: { \r\n class: 'text-base px-4 py-2',\r\n },\r\n}\r\n\r\n// click과 manual 트리거를 위한 상태 관리\r\nconst isOpen = ref(false)\r\n\r\n// 각 트리거 타입별 핸들러\r\nconst handleClick = (event: MouseEvent) => {\r\n console.log('Click handler called, trigger:', props.trigger)\r\n if (props.trigger === 'click') {\r\n console.log('Toggling tooltip, current state:', isOpen.value)\r\n isOpen.value = !isOpen.value\r\n console.log('New state:', isOpen.value)\r\n } else if (props.trigger === 'focus') {\r\n // focus 트리거에서는 클릭 이벤트 무시\r\n event.preventDefault()\r\n event.stopPropagation()\r\n }\r\n}\r\n\r\n// delay를 위한 타이머 관리\r\nlet hoverTimer: number | null = null\r\n\r\nconst handleMouseEnter = () => {\r\n if (props.trigger === 'hover') {\r\n // 기존 타이머가 있으면 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n // delay 적용\r\n hoverTimer = setTimeout(() => {\r\n isOpen.value = true\r\n }, props.delay)\r\n }\r\n}\r\n\r\nconst handleMouseLeave = () => {\r\n if (props.trigger === 'hover') {\r\n // 타이머 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n hoverTimer = null\r\n }\r\n isOpen.value = false\r\n }\r\n}\r\n\r\nconst handleFocus = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst handleBlur = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 트리거 타입에 따른 Tooltip 설정 계산\r\nconst tooltipConfig = computed(() => {\r\n const config: any = {\r\n disabled: props.disabled,\r\n }\r\n \r\n // 모든 트리거 타입에 대해 수동 제어\r\n config.open = isOpen.value\r\n \r\n return config\r\n})\r\n\r\n// 외부 클릭 감지를 위한 핸들러\r\nconst handleOutsideClick = (event: Event) => {\r\n if (props.trigger === 'hover' && isOpen.value) {\r\n const target = event.target as HTMLElement\r\n const tooltipElement = document.querySelector('[data-tooltip-trigger]')\r\n if (tooltipElement && !tooltipElement.contains(target)) {\r\n isOpen.value = false\r\n }\r\n }\r\n}\r\n\r\n// manual 트리거를 위한 메서드들\r\nconst showTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst hideTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 외부에서 사용할 수 있도록 expose\r\ndefineExpose({\r\n showTooltip,\r\n hideTooltip,\r\n})\r\n\r\n// 외부 클릭 감지를 위한 이벤트 리스너 등록/해제\r\nonMounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.addEventListener('click', handleOutsideClick)\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.removeEventListener('click', handleOutsideClick)\r\n }\r\n \r\n // 타이머 정리\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n})\r\n\r\n/** 최종 바인딩: 직접 넘긴 class가 있으면 styletype과 size 기본값과 병합 */\r\nconst mapped = computed(() => {\r\n const stylePreset = STYLE_PRESETS[props.styletype!]\r\n const sizePreset = SIZE_PRESETS[props.size!]\r\n const finalClass = [stylePreset.class, sizePreset.class, props.class].filter(Boolean).join(' ')\r\n \r\n // maxWidth 스타일 처리\r\n const maxWidthStyle = typeof props.maxWidth === 'number' \r\n ? `${props.maxWidth}px` \r\n : props.maxWidth\r\n \r\n return {\r\n side: props.side,\r\n align: props.align,\r\n class: finalClass,\r\n style: {\r\n maxWidth: maxWidthStyle,\r\n },\r\n }\r\n})\r\n</script>\r\n\r\n<template>\r\n <TooltipProvider :delayDuration=\"props.delay\">\r\n <Tooltip v-bind=\"tooltipConfig\">\r\n <TooltipTrigger \r\n as-child\r\n :data-tooltip-trigger=\"true\"\r\n @click=\"handleClick\"\r\n @mouseenter=\"handleMouseEnter\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n >\r\n <slot name=\"trigger\" />\r\n </TooltipTrigger>\r\n <TooltipContent v-bind=\"mapped\">\r\n {{ props.content }}\r\n </TooltipContent>\r\n </Tooltip>\r\n </TooltipProvider>\r\n</template>\r\n"],"names":["props","__props","STYLE_PRESETS","SIZE_PRESETS","isOpen","ref","handleClick","event","hoverTimer","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","tooltipConfig","computed","config","handleOutsideClick","target","tooltipElement","__expose","onMounted","onUnmounted","mapped","stylePreset","sizePreset","finalClass","maxWidthStyle","_createBlock","TooltipProvider","_createVNode","Tooltip","TooltipTrigger","_renderSlot","_ctx","TooltipContent","_createTextVNode","_toDisplayString"],"mappings":"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"}
1
+ {"version":3,"file":"JTooltip.vue.js","sources":["../../../../src/components/atoms/JTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\r\nimport Tooltip from '@/components/shadcn/Tooltip.vue'\r\nimport TooltipContent from '@/components/shadcn/TooltipContent.vue'\r\nimport TooltipProvider from '@/components/shadcn/TooltipProvider.vue'\r\nimport TooltipTrigger from '@/components/shadcn/TooltipTrigger.vue'\r\n\r\ntype StyleType =\r\n | 'default' // 기본 스타일\r\n | 'primary' // 강조 스타일 (파랑)\r\n | 'success' // 성공 스타일 (초록)\r\n | 'warning' // 경고 스타일 (주황)\r\n | 'danger' // 위험 스타일 (빨강)\r\n\r\ntype Size = 'xs' | 'sm' | 'md' | 'lg'\n\r\ntype Trigger = 'hover' | 'focus' | 'click' | 'manual'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n content?: string\r\n side?: 'top' | 'right' | 'bottom' | 'left'\r\n align?: 'start' | 'center' | 'end'\r\n class?: string\r\n /** 스타일 프리셋 */\r\n styletype?: StyleType\r\n /** 툴팁 크기 */\r\n size?: Size\r\n /** 툴팁 비활성화 */\r\n disabled?: boolean\r\n /** 표시 지연 시간 (ms) */\r\n delay?: number\r\n /** 툴팁 최대 너비 */\r\n maxWidth?: string | number\r\n /** 툴팁 트리거 타입 */\r\n trigger?: Trigger\r\n }>(),\r\n {\n side: 'top',\n align: 'center',\n styletype: 'default',\n size: 'sm',\n disabled: false,\n delay: 200,\n maxWidth: '200px',\n trigger: 'hover',\r\n },\r\n)\r\n\r\n/**\r\n * styletype -> class 매핑\r\n */\r\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\r\n default: { class: '' },\r\n primary: { \r\n class: 'bg-blue-500 text-white border-blue-600',\r\n },\r\n success: { \r\n class: 'bg-green-500 text-white border-green-600',\r\n },\r\n warning: { \r\n class: 'bg-amber-500 text-white border-amber-600',\r\n },\r\n danger: { \r\n class: 'bg-red-500 text-white border-red-600',\r\n },\r\n}\r\n\r\n/**\r\n * size -> class 매핑\r\n */\r\nconst SIZE_PRESETS: Record<Size, { class: string }> = {\n xs: { \n class: 'text-[10px] px-1.5 py-0.5 max-w-40',\n },\n sm: { \n class: 'text-xs px-2 py-1 max-w-48',\n },\n md: { \n class: 'text-xs px-2.5 py-1 max-w-56',\n },\n lg: { \n class: 'text-sm px-3 py-1.5 max-w-64',\n },\n}\n\r\n// click과 manual 트리거를 위한 상태 관리\r\nconst isOpen = ref(false)\r\n\r\n// 각 트리거 타입별 핸들러\r\nconst handleClick = (event: MouseEvent) => {\r\n console.log('Click handler called, trigger:', props.trigger)\r\n if (props.trigger === 'click') {\r\n console.log('Toggling tooltip, current state:', isOpen.value)\r\n isOpen.value = !isOpen.value\r\n console.log('New state:', isOpen.value)\r\n } else if (props.trigger === 'focus') {\r\n // focus 트리거에서는 클릭 이벤트 무시\r\n event.preventDefault()\r\n event.stopPropagation()\r\n }\r\n}\r\n\r\n// delay를 위한 타이머 관리\r\nlet hoverTimer: number | null = null\r\n\r\nconst handleMouseEnter = () => {\r\n if (props.trigger === 'hover') {\r\n // 기존 타이머가 있으면 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n // delay 적용\r\n hoverTimer = setTimeout(() => {\r\n isOpen.value = true\r\n }, props.delay)\r\n }\r\n}\r\n\r\nconst handleMouseLeave = () => {\r\n if (props.trigger === 'hover') {\r\n // 타이머 취소\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n hoverTimer = null\r\n }\r\n isOpen.value = false\r\n }\r\n}\r\n\r\nconst handleFocus = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst handleBlur = () => {\r\n if (props.trigger === 'focus') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 트리거 타입에 따른 Tooltip 설정 계산\r\nconst tooltipConfig = computed(() => {\r\n const config: any = {\r\n disabled: props.disabled,\r\n }\r\n \r\n // 모든 트리거 타입에 대해 수동 제어\r\n config.open = isOpen.value\r\n \r\n return config\r\n})\r\n\r\n// 외부 클릭 감지를 위한 핸들러\r\nconst handleOutsideClick = (event: Event) => {\r\n if (props.trigger === 'hover' && isOpen.value) {\r\n const target = event.target as HTMLElement\r\n const tooltipElement = document.querySelector('[data-tooltip-trigger]')\r\n if (tooltipElement && !tooltipElement.contains(target)) {\r\n isOpen.value = false\r\n }\r\n }\r\n}\r\n\r\n// manual 트리거를 위한 메서드들\r\nconst showTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = true\r\n }\r\n}\r\n\r\nconst hideTooltip = () => {\r\n if (props.trigger === 'manual') {\r\n isOpen.value = false\r\n }\r\n}\r\n\r\n// 외부에서 사용할 수 있도록 expose\r\ndefineExpose({\r\n showTooltip,\r\n hideTooltip,\r\n})\r\n\r\n// 외부 클릭 감지를 위한 이벤트 리스너 등록/해제\r\nonMounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.addEventListener('click', handleOutsideClick)\r\n }\r\n})\r\n\r\nonUnmounted(() => {\r\n if (props.trigger === 'hover') {\r\n document.removeEventListener('click', handleOutsideClick)\r\n }\r\n \r\n // 타이머 정리\r\n if (hoverTimer) {\r\n clearTimeout(hoverTimer)\r\n }\r\n})\r\n\r\n/** 최종 바인딩: 직접 넘긴 class가 있으면 styletype과 size 기본값과 병합 */\r\nconst mapped = computed(() => {\r\n const stylePreset = STYLE_PRESETS[props.styletype!]\r\n const sizePreset = SIZE_PRESETS[props.size!]\r\n const finalClass = [stylePreset.class, sizePreset.class, props.class].filter(Boolean).join(' ')\r\n \r\n // maxWidth 스타일 처리\r\n const maxWidthStyle = typeof props.maxWidth === 'number' \r\n ? `${props.maxWidth}px` \r\n : props.maxWidth\r\n \r\n return {\r\n side: props.side,\r\n align: props.align,\r\n class: finalClass,\r\n style: {\r\n maxWidth: maxWidthStyle,\r\n },\r\n }\r\n})\r\n</script>\r\n\r\n<template>\r\n <TooltipProvider :delayDuration=\"props.delay\">\r\n <Tooltip v-bind=\"tooltipConfig\">\r\n <TooltipTrigger \r\n as-child\r\n :data-tooltip-trigger=\"true\"\r\n @click=\"handleClick\"\r\n @mouseenter=\"handleMouseEnter\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @focus=\"handleFocus\"\r\n @blur=\"handleBlur\"\r\n >\r\n <slot name=\"trigger\" />\r\n </TooltipTrigger>\r\n <TooltipContent v-bind=\"mapped\">\r\n {{ props.content }}\r\n </TooltipContent>\r\n </Tooltip>\r\n </TooltipProvider>\r\n</template>\r\n"],"names":["props","__props","STYLE_PRESETS","SIZE_PRESETS","isOpen","ref","handleClick","event","hoverTimer","handleMouseEnter","handleMouseLeave","handleFocus","handleBlur","tooltipConfig","computed","config","handleOutsideClick","target","tooltipElement","__expose","onMounted","onUnmounted","mapped","stylePreset","sizePreset","finalClass","maxWidthStyle","_createBlock","TooltipProvider","_createVNode","Tooltip","TooltipTrigger","_renderSlot","_ctx","TooltipContent","_createTextVNode","_toDisplayString"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),i=require("../molecules/JFormField.vue.cjs");;/* empty css */require("../shadcn/index.cjs");require("@vueuse/core");require("reka-ui");require("clsx");require("tailwind-merge");require("lucide-vue-next");;/* empty css */;/* empty css */;/* empty css */const n=require("../atoms/JButton.vue.cjs");require("@internationalized/date");require("md-editor-v3");;/* empty css */;/* empty css */require("../shadcn/badge-variants.cjs");;/* empty css */require("../shadcn/avatar-variants.cjs");require("dompurify");;/* empty css */const C=require("../atoms/JGrid.vue.cjs"),A=require("../atoms/JSplitter.vue.cjs");require("vue-sonner");const w=require("../molecules/JTitlebar.vue.cjs");;/* empty css */;/* empty css */const h=require("../organisms/JFilterBar.vue.cjs");require("vue-router");;/* empty css */;/* empty css */const B={class:"flex flex-col h-full gap-4 bg-background text-foreground"},Y={class:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"},z={class:"h-full overflow-auto bg-background"},E={class:"h-full flex flex-col gap-4 overflow-y-auto p-4 border-l rounded-lg bg-card"},U={class:"text-lg font-semibold mb-2"},T={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},J={class:"grid grid-cols-1 md:grid-cols-2 gap-4"},S={class:"flex justify-end gap-2 mt-4"},R=e.defineComponent({__name:"ExampleCrudPage",setup($,{expose:c}){const d=e.ref(!1),a=e.ref({isActive:"",keyword:""}),f={isActive:{label:"활성여부",displayValue:r=>r==="Y"?"Y:활성":r==="N"?"N:비활성":""},keyword:{label:"검색어"}},m=[{value:"Y",label:"Y:활성"},{value:"N",label:"N:비활성"}],v=[{value:"A",label:"A등급"},{value:"B",label:"B등급"},{value:"C",label:"C등급"}],s=e.ref(),p=e.ref([{code:"C001",name:"제이솔루션",category:"A",isActive:"Y",remark:"주력 고객사"},{code:"C002",name:"ABC물류",category:"B",isActive:"Y",remark:""},{code:"C003",name:"XYZ유통",category:"A",isActive:"N",remark:"비활성"},{code:"C004",name:"대한물류",category:"B",isActive:"Y",remark:""},{code:"C005",name:"글로벌이커머스",category:"A",isActive:"Y",remark:"신규 고객사"}]),g=e.ref([{field:"code",headerName:"코드",width:120},{field:"name",headerName:"이름",width:200},{field:"category",headerName:"분류",width:100},{field:"isActive",headerName:"활성",width:100,cellRenderer:r=>r.value==="Y"?"✓":""},{field:"remark",headerName:"비고",flex:1}]),V=[{icon:"pencil",label:"수정",tooltip:"편집",onClick:r=>{u.value=!1,t.value={code:r.code,name:r.name,category:r.category,isActive:r.isActive,remark:r.remark}}},{icon:"trash2",label:"삭제",tooltip:"삭제",styletype:"danger",onClick:r=>{confirm(`${r.name}을(를) 삭제하시겠습니까?`)&&(console.log("삭제:",r.code),alert(`삭제되었습니다: ${r.name}`))}}],u=e.ref(!1),t=e.ref({code:"",name:"",category:"",isActive:"Y",remark:""});function y(r){u.value=!1;const l=r.data;t.value={code:l.code,name:l.name,category:l.category,isActive:l.isActive,remark:l.remark}}function _(){u.value=!0,t.value={code:"",name:"",category:"",isActive:"Y",remark:""}}function N(){console.log("저장:",t.value),alert(`저장되었습니다: ${t.value.name}`)}function k(){confirm(`${t.value.name}을(를) 삭제하시겠습니까?`)&&(console.log("삭제:",t.value.code),alert(`삭제되었습니다: ${t.value.name}`))}function b(){a.value={isActive:"",keyword:""},console.log("필터 초기화")}function q(){console.log("조회 조건:",a.value)}function x(){alert("고객사 관리 페이지 도움말")}return c({gridRef:s}),(r,l)=>(e.openBlock(),e.createElementBlock("div",B,[e.createVNode(e.unref(w.default),{icon:"building",title:"고객사 관리",description:"고객사 정보를 조회하고 관리합니다",showHelp:!0,onHelp:x}),e.createVNode(e.unref(h.default),{collapsed:d.value,"onUpdate:collapsed":l[2]||(l[2]=o=>d.value=o),filterValues:a.value,"onUpdate:filterValues":l[3]||(l[3]=o=>a.value=o),filterDisplay:f,collapsible:!0,title:"고객사 목록"},{actions:e.withCtx(()=>[e.createVNode(e.unref(n.default),{size:"sm",variant:"outline",onClick:b},{default:e.withCtx(()=>[...l[9]||(l[9]=[e.createTextVNode("초기화",-1)])]),_:1}),e.createVNode(e.unref(n.default),{size:"sm",styletype:"primary",onClick:q},{default:e.withCtx(()=>[...l[10]||(l[10]=[e.createTextVNode("조회",-1)])]),_:1}),e.createVNode(e.unref(n.default),{size:"sm",styletype:"primary",onClick:_},{default:e.withCtx(()=>[...l[11]||(l[11]=[e.createTextVNode("신규",-1)])]),_:1})]),filters:e.withCtx(()=>[e.createElementVNode("div",Y,[e.createVNode(e.unref(i.default),{type:"combo",label:"활성여부",modelValue:a.value.isActive,"onUpdate:modelValue":l[0]||(l[0]=o=>a.value.isActive=o),options:m},null,8,["modelValue"]),e.createVNode(e.unref(i.default),{type:"input",label:"검색어",modelValue:a.value.keyword,"onUpdate:modelValue":l[1]||(l[1]=o=>a.value.keyword=o)},null,8,["modelValue"])])]),_:1},8,["collapsed","filterValues"]),e.createVNode(e.unref(A.default),{direction:"horizontal","default-size":60,"min-size":30,"second-min-size":20,"second-max-size":60,class:"flex-1"},{left:e.withCtx(()=>[e.createElementVNode("div",z,[e.createVNode(e.unref(C.default),{ref_key:"gridRef",ref:s,columnDefs:g.value,rowData:p.value,"action-buttons":V,onRowClicked:y},null,8,["columnDefs","rowData"])])]),right:e.withCtx(()=>[e.createElementVNode("div",E,[e.createElementVNode("h3",U,e.toDisplayString(u.value?"신규 등록":"상세 정보"),1),e.createElementVNode("div",T,[e.createVNode(e.unref(i.default),{type:"input",label:"코드",modelValue:t.value.code,"onUpdate:modelValue":l[4]||(l[4]=o=>t.value.code=o),readonly:!u.value,placeholder:"고객사 코드"},null,8,["modelValue","readonly"]),e.createVNode(e.unref(i.default),{type:"input",label:"이름",modelValue:t.value.name,"onUpdate:modelValue":l[5]||(l[5]=o=>t.value.name=o),placeholder:"고객사 이름"},null,8,["modelValue"])]),e.createElementVNode("div",J,[e.createVNode(e.unref(i.default),{type:"combo",label:"분류",modelValue:t.value.category,"onUpdate:modelValue":l[6]||(l[6]=o=>t.value.category=o),options:v},null,8,["modelValue"]),e.createVNode(e.unref(i.default),{type:"checkbox",label:"활성여부",modelValue:t.value.isActive,"onUpdate:modelValue":l[7]||(l[7]=o=>t.value.isActive=o),inlineLabel:"활성"},null,8,["modelValue"])]),e.createVNode(e.unref(i.default),{type:"textarea",label:"비고",modelValue:t.value.remark,"onUpdate:modelValue":l[8]||(l[8]=o=>t.value.remark=o),placeholder:"비고"},null,8,["modelValue"]),e.createElementVNode("div",S,[e.createVNode(e.unref(n.default),{styletype:"primary",size:"sm",onClick:N},{default:e.withCtx(()=>[...l[12]||(l[12]=[e.createTextVNode("저장",-1)])]),_:1}),u.value?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(e.unref(n.default),{key:0,variant:"outline",size:"sm",onClick:k},{default:e.withCtx(()=>[...l[13]||(l[13]=[e.createTextVNode("삭제",-1)])]),_:1}))])])]),_:1})]))}});exports.default=R;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),u=require("../molecules/JFormField.vue.cjs");;/* empty css */require("../shadcn/index.cjs");require("@vueuse/core");require("reka-ui");require("clsx");require("tailwind-merge");require("lucide-vue-next");;/* empty css */;/* empty css */;/* empty css */const w=require("../molecules/JCard.vue.cjs"),n=require("../atoms/JButton.vue.cjs");require("@internationalized/date");require("md-editor-v3");;/* empty css */;/* empty css */require("../shadcn/badge-variants.cjs");;/* empty css */require("../shadcn/avatar-variants.cjs");require("dompurify");;/* empty css */const x=require("../atoms/JGrid.vue.cjs"),A=require("../atoms/JSplitter.vue.cjs");require("vue-sonner");const h=require("../molecules/JTitlebar.vue.cjs");;/* empty css */;/* empty css */const z=require("../organisms/JFilterBar.vue.cjs");require("vue-router");;/* empty css */;/* empty css */const B={class:"flex flex-col h-full gap-2 bg-background text-foreground"},Y={class:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2"},E={class:"h-full overflow-auto bg-background"},U={class:"h-full overflow-y-auto border-l bg-muted/30"},P={class:"grid grid-cols-1 md:grid-cols-2 gap-2 mt-2"},T={class:"grid grid-cols-1 md:grid-cols-2 gap-2 mt-2"},J={class:"grid grid-cols-1 gap-2 mt-2"},R={class:"flex justify-end gap-2"},S=e.defineComponent({__name:"ExampleCrudPage",setup(G,{expose:c}){const d=e.ref(!1),o=e.ref({isActive:"",keyword:""}),f={isActive:{label:"활성여부",displayValue:r=>r==="Y"?"Y:활성":r==="N"?"N:비활성":""},keyword:{label:"검색어"}},m=[{value:"Y",label:"Y:활성"},{value:"N",label:"N:비활성"}],v=[{value:"A",label:"A등급"},{value:"B",label:"B등급"},{value:"C",label:"C등급"}],s=e.ref(),p=e.ref([{code:"C001",name:"제이솔루션",category:"A",isActive:"Y",remark:"주력 고객사"},{code:"C002",name:"ABC물류",category:"B",isActive:"Y",remark:""},{code:"C003",name:"XYZ유통",category:"A",isActive:"N",remark:"비활성"},{code:"C004",name:"대한물류",category:"B",isActive:"Y",remark:""},{code:"C005",name:"글로벌이커머스",category:"A",isActive:"Y",remark:"신규 고객사"}]),g=e.ref([{field:"code",headerName:"코드",width:120,enableValue:!0},{field:"name",headerName:"이름",width:200,enableValue:!0},{field:"category",headerName:"분류",width:100,enableRowGroup:!0,enablePivot:!0},{field:"isActive",headerName:"활성",width:100,cellRenderer:r=>r.value==="Y"?"✓":"",enableRowGroup:!0,enablePivot:!0},{field:"remark",headerName:"비고",flex:1,enableValue:!0}]),V=[{icon:"pencil",label:"수정",tooltip:"편집",onClick:r=>{i.value=!1,t.value={code:r.code,name:r.name,category:r.category,isActive:r.isActive,remark:r.remark}}},{icon:"trash2",label:"삭제",tooltip:"삭제",styletype:"danger",onClick:r=>{confirm(`${r.name}을(를) 삭제하시겠습니까?`)&&(console.log("삭제:",r.code),alert(`삭제되었습니다: ${r.name}`))}}],i=e.ref(!1),t=e.ref({code:"",name:"",category:"",isActive:"Y",remark:""});function y(r){i.value=!1;const l=r.data;t.value={code:l.code,name:l.name,category:l.category,isActive:l.isActive,remark:l.remark}}function _(){i.value=!0,t.value={code:"",name:"",category:"",isActive:"Y",remark:""}}function b(){console.log("저장:",t.value),alert(`저장되었습니다: ${t.value.name}`)}function N(){confirm(`${t.value.name}을(를) 삭제하시겠습니까?`)&&(console.log("삭제:",t.value.code),alert(`삭제되었습니다: ${t.value.name}`))}function k(){o.value={isActive:"",keyword:""},console.log("필터 초기화")}function q(){console.log("조회 조건:",o.value)}function C(){alert("고객사 관리 페이지 도움말")}return c({gridRef:s}),(r,l)=>(e.openBlock(),e.createElementBlock("div",B,[e.createVNode(e.unref(h.default),{icon:"building",title:"고객사 관리",description:"고객사 정보를 조회하고 관리합니다",showHelp:!0,onHelp:C}),e.createVNode(e.unref(z.default),{collapsed:d.value,"onUpdate:collapsed":l[2]||(l[2]=a=>d.value=a),filterValues:o.value,"onUpdate:filterValues":l[3]||(l[3]=a=>o.value=a),filterDisplay:f,collapsible:!0,title:"고객사 목록"},{actions:e.withCtx(()=>[e.createVNode(e.unref(n.default),{size:"sm",variant:"outline",onClick:k},{default:e.withCtx(()=>[...l[9]||(l[9]=[e.createTextVNode("초기화",-1)])]),_:1}),e.createVNode(e.unref(n.default),{size:"sm",styletype:"primary",onClick:q},{default:e.withCtx(()=>[...l[10]||(l[10]=[e.createTextVNode("조회",-1)])]),_:1}),e.createVNode(e.unref(n.default),{size:"sm",styletype:"primary",onClick:_},{default:e.withCtx(()=>[...l[11]||(l[11]=[e.createTextVNode("신규",-1)])]),_:1})]),filters:e.withCtx(()=>[e.createElementVNode("div",Y,[e.createVNode(e.unref(u.default),{type:"combo",label:"활성여부",modelValue:o.value.isActive,"onUpdate:modelValue":l[0]||(l[0]=a=>o.value.isActive=a),options:m,orientation:"horizontal",labelWidth:"30%"},null,8,["modelValue"]),e.createVNode(e.unref(u.default),{type:"input",label:"검색어",modelValue:o.value.keyword,"onUpdate:modelValue":l[1]||(l[1]=a=>o.value.keyword=a),orientation:"horizontal",labelWidth:"30%"},null,8,["modelValue"])])]),_:1},8,["collapsed","filterValues"]),e.createVNode(e.unref(A.default),{direction:"horizontal","default-size":60,"min-size":30,"second-min-size":20,"second-max-size":60,gap:2,class:"flex-1"},{left:e.withCtx(()=>[e.createElementVNode("div",E,[e.createVNode(e.unref(x.default),{ref_key:"gridRef",ref:s,columnDefs:g.value,rowData:p.value,"action-buttons":V,enableGrouping:!0,enablePivot:!0,enableColumnsToolPanel:!0,rowGroupPanelShow:"always",pivotPanelShow:"always",groupDefaultExpanded:1,compactFooter:!0,onRowClicked:y},null,8,["columnDefs","rowData"])])]),right:e.withCtx(()=>[e.createElementVNode("div",U,[e.createVNode(e.unref(w.default),{class:"h-full",title:i.value?"신규 등록":"상세 정보"},{footer:e.withCtx(()=>[e.createElementVNode("div",R,[e.createVNode(e.unref(n.default),{styletype:"primary",size:"sm",onClick:b},{default:e.withCtx(()=>[...l[12]||(l[12]=[e.createTextVNode("저장",-1)])]),_:1}),i.value?e.createCommentVNode("",!0):(e.openBlock(),e.createBlock(e.unref(n.default),{key:0,variant:"outline",size:"sm",onClick:N},{default:e.withCtx(()=>[...l[13]||(l[13]=[e.createTextVNode("삭제",-1)])]),_:1}))])]),default:e.withCtx(()=>[e.createElementVNode("div",P,[e.createVNode(e.unref(u.default),{type:"input",label:"코드",modelValue:t.value.code,"onUpdate:modelValue":l[4]||(l[4]=a=>t.value.code=a),readonly:!i.value,placeholder:"고객사 코드"},null,8,["modelValue","readonly"]),e.createVNode(e.unref(u.default),{type:"input",label:"이름",modelValue:t.value.name,"onUpdate:modelValue":l[5]||(l[5]=a=>t.value.name=a),placeholder:"고객사 이름"},null,8,["modelValue"])]),e.createElementVNode("div",T,[e.createVNode(e.unref(u.default),{type:"combo",label:"분류",modelValue:t.value.category,"onUpdate:modelValue":l[6]||(l[6]=a=>t.value.category=a),options:v},null,8,["modelValue"]),e.createVNode(e.unref(u.default),{type:"checkbox",label:"활성여부",modelValue:t.value.isActive,"onUpdate:modelValue":l[7]||(l[7]=a=>t.value.isActive=a),inlineLabel:"활성"},null,8,["modelValue"])]),e.createElementVNode("div",J,[e.createVNode(e.unref(u.default),{type:"textarea",label:"비고",modelValue:t.value.remark,"onUpdate:modelValue":l[8]||(l[8]=a=>t.value.remark=a),placeholder:"비고"},null,8,["modelValue"])])]),_:1},8,["title"])])]),_:1})]))}});exports.default=S;
2
2
  //# sourceMappingURL=ExampleCrudPage.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExampleCrudPage.vue.cjs","sources":["../../../../src/components/examples/ExampleCrudPage.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col h-full gap-4 bg-background text-foreground\">\n <!-- ==================== 타이틀바 ==================== -->\n <JTitlebar \n icon=\"building\" \n title=\"고객사 관리\" \n description=\"고객사 정보를 조회하고 관리합니다\"\n :showHelp=\"true\" \n @help=\"onHelp\" \n />\n\n <!-- ==================== 필터바 ==================== -->\n <JFilterBar\n v-model:collapsed=\"filterCollapsed\"\n v-model:filterValues=\"filterValues\"\n :filterDisplay=\"filterDisplay\"\n :collapsible=\"true\"\n title=\"고객사 목록\"\n >\n <!-- 액션 버튼 -->\n <template #actions>\n <JButton size=\"sm\" variant=\"outline\" @click=\"onReset\">초기화</JButton>\n <JButton size=\"sm\" styletype=\"primary\" @click=\"onSearch\">조회</JButton>\n <JButton size=\"sm\" styletype=\"primary\" @click=\"onNew\">신규</JButton>\n </template>\n\n <!-- 필터 필드 - 다중 열 배치 -->\n <template #filters>\n <div class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4\">\n <JFormField\n type=\"combo\"\n label=\"활성여부\"\n v-model=\"filterValues.isActive\"\n :options=\"activeOptions\"\n />\n <JFormField type=\"input\" label=\"검색어\" v-model=\"filterValues.keyword\" />\n </div>\n </template>\n </JFilterBar>\n\n <!-- ==================== 그리드 + 상세 영역 (Resizable) ==================== -->\n <JSplitter\n direction=\"horizontal\"\n :default-size=\"60\"\n :min-size=\"30\"\n :second-min-size=\"20\"\n :second-max-size=\"60\"\n class=\"flex-1\"\n >\n <!-- 좌측: 그리드 -->\n <template #left>\n <div class=\"h-full overflow-auto bg-background\">\n <JGrid\n ref=\"gridRef\"\n :columnDefs=\"columnDefs\"\n :rowData=\"rowData\"\n :action-buttons=\"actionButtons\"\n @row-clicked=\"onRowClicked\"\n />\n </div>\n </template>\n\n <!-- 우측: 상세 영역 -->\n <template #right>\n <div class=\"h-full flex flex-col gap-4 overflow-y-auto p-4 border-l rounded-lg bg-card\">\n <h3 class=\"text-lg font-semibold mb-2\">{{ isNew ? '신규 등록' : '상세 정보' }}</h3>\n\n <!-- 2열 그리드: 코드, 이름 -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <JFormField\n type=\"input\"\n label=\"코드\"\n v-model=\"detail.code\"\n :readonly=\"!isNew\"\n placeholder=\"고객사 코드\"\n />\n <JFormField\n type=\"input\"\n label=\"이름\"\n v-model=\"detail.name\"\n placeholder=\"고객사 이름\"\n />\n </div>\n\n <!-- 2열 그리드: 분류, 활성여부 -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <JFormField\n type=\"combo\"\n label=\"분류\"\n v-model=\"detail.category\"\n :options=\"categoryOptions\"\n />\n <JFormField\n type=\"checkbox\"\n label=\"활성여부\"\n v-model=\"detail.isActive\"\n inlineLabel=\"활성\"\n />\n </div>\n\n <!-- 전체 너비: 비고 -->\n <JFormField type=\"textarea\" label=\"비고\" v-model=\"detail.remark\" placeholder=\"비고\" />\n\n <!-- 액션 버튼 -->\n <div class=\"flex justify-end gap-2 mt-4\">\n <JButton styletype=\"primary\" size=\"sm\" @click=\"onSave\">저장</JButton>\n <JButton variant=\"outline\" size=\"sm\" @click=\"onDelete\" v-if=\"!isNew\">삭제</JButton>\n </div>\n </div>\n </template>\n </JSplitter>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { JTitlebar } from '@/components/molecules'\nimport { JFilterBar } from '@/components/organisms'\nimport { JGrid, JButton, JSplitter, type ActionButton } from '@/components/atoms'\nimport { JFormField } from '@/components/molecules'\n\n// ==================== 필터 상태 ====================\nconst filterCollapsed = ref(false)\n\n// 필터 값 (v-model:filterValues)\nconst filterValues = ref({\n isActive: '',\n keyword: '',\n})\n\n// 필터 표시 설정 (배지에 표시될 라벨 및 값 변환 함수)\nconst filterDisplay = {\n isActive: {\n label: '활성여부',\n displayValue: (val: unknown) => {\n if (val === 'Y') return 'Y:활성'\n if (val === 'N') return 'N:비활성'\n return ''\n },\n },\n keyword: {\n label: '검색어',\n },\n}\n\n// ==================== 옵션 데이터 ====================\nconst activeOptions = [\n { value: 'Y', label: 'Y:활성' },\n { value: 'N', label: 'N:비활성' },\n]\n\nconst categoryOptions = [\n { value: 'A', label: 'A등급' },\n { value: 'B', label: 'B등급' },\n { value: 'C', label: 'C등급' },\n]\n\n// ==================== 그리드 설정 ====================\nconst gridRef = ref()\n\n// Mock 데이터 - 실제 백엔드 응답 구조\nconst rowData = ref([\n { code: 'C001', name: '제이솔루션', category: 'A', isActive: 'Y', remark: '주력 고객사' },\n { code: 'C002', name: 'ABC물류', category: 'B', isActive: 'Y', remark: '' },\n { code: 'C003', name: 'XYZ유통', category: 'A', isActive: 'N', remark: '비활성' },\n { code: 'C004', name: '대한물류', category: 'B', isActive: 'Y', remark: '' },\n { code: 'C005', name: '글로벌이커머스', category: 'A', isActive: 'Y', remark: '신규 고객사' },\n])\n\nconst columnDefs = ref([\n { field: 'code', headerName: '코드', width: 120 },\n { field: 'name', headerName: '이름', width: 200 },\n { field: 'category', headerName: '분류', width: 100 },\n {\n field: 'isActive',\n headerName: '활성',\n width: 100,\n cellRenderer: (params: any) => (params.value === 'Y' ? '✓' : ''),\n },\n { field: 'remark', headerName: '비고', flex: 1 },\n])\n\n// 행별 액션 버튼\nconst actionButtons: ActionButton[] = [\n {\n icon: 'pencil',\n label: '수정',\n tooltip: '편집',\n onClick: (rowData: any) => {\n isNew.value = false\n detail.value = {\n code: rowData.code,\n name: rowData.name,\n category: rowData.category,\n isActive: rowData.isActive,\n remark: rowData.remark,\n }\n },\n },\n {\n icon: 'trash2',\n label: '삭제',\n tooltip: '삭제',\n styletype: 'danger',\n onClick: (rowData: any) => {\n if (confirm(`${rowData.name}을(를) 삭제하시겠습니까?`)) {\n console.log('삭제:', rowData.code)\n alert(`삭제되었습니다: ${rowData.name}`)\n }\n },\n },\n]\n\n// ==================== 상세 영역 상태 ====================\nconst isNew = ref(false)\nconst detail = ref({\n code: '',\n name: '',\n category: '',\n isActive: 'Y',\n remark: '',\n})\n\n// ==================== 이벤트 핸들러 ====================\n\n/**\n * 그리드 행 클릭 핸들러\n */\nfunction onRowClicked(event: any) {\n isNew.value = false\n const rowData = event.data\n\n // 선택된 행 데이터를 상세 영역에 바인딩\n detail.value = {\n code: rowData.code,\n name: rowData.name,\n category: rowData.category,\n isActive: rowData.isActive,\n remark: rowData.remark,\n }\n}\n\n/**\n * 신규 버튼 클릭\n */\nfunction onNew() {\n isNew.value = true\n // 상세 영역 초기화\n detail.value = {\n code: '',\n name: '',\n category: '',\n isActive: 'Y',\n remark: '',\n }\n}\n\n/**\n * 저장 버튼 클릭\n */\nfunction onSave() {\n console.log('저장:', detail.value)\n // TODO: 실제 구현 시 API 호출로 대체\n // if (isNew.value) {\n // await api.createCustomer(detail.value)\n // } else {\n // await api.updateCustomer(detail.value.code, detail.value)\n // }\n // 성공 시 그리드 데이터 갱신\n alert(`저장되었습니다: ${detail.value.name}`)\n}\n\n/**\n * 삭제 버튼 클릭\n */\nfunction onDelete() {\n if (confirm(`${detail.value.name}을(를) 삭제하시겠습니까?`)) {\n console.log('삭제:', detail.value.code)\n // TODO: 실제 구현 시 API 호출로 대체\n // await api.deleteCustomer(detail.value.code)\n // 성공 시 그리드에서 해당 행 제거\n alert(`삭제되었습니다: ${detail.value.name}`)\n }\n}\n\n/**\n * 초기화 버튼 클릭\n */\nfunction onReset() {\n filterValues.value = {\n isActive: '',\n keyword: '',\n }\n console.log('필터 초기화')\n}\n\n/**\n * 조회 버튼 클릭\n */\nfunction onSearch() {\n console.log('조회 조건:', filterValues.value)\n // TODO: 실제 구현 시 API 호출로 대체\n // const result = await api.searchCustomers(filterValues.value)\n // rowData.value = result.data\n}\n\n/**\n * 도움말 아이콘 클릭\n */\nfunction onHelp() {\n alert('고객사 관리 페이지 도움말')\n}\n\ndefineExpose({ gridRef })\n</script>\n"],"names":["filterCollapsed","ref","filterValues","filterDisplay","val","activeOptions","categoryOptions","gridRef","rowData","columnDefs","params","actionButtons","isNew","detail","onRowClicked","event","onNew","onSave","onDelete","onReset","onSearch","onHelp","__expose","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","JTitlebar","JFilterBar","$event","JButton","_cache","_createElementVNode","_hoisted_2","JFormField","JSplitter","_hoisted_3","JGrid","_hoisted_4","_hoisted_5","_toDisplayString","_hoisted_6","_hoisted_7","_hoisted_8","_createBlock"],"mappings":"o1DA0HA,MAAMA,EAAkBC,EAAAA,IAAI,EAAK,EAG3BC,EAAeD,EAAAA,IAAI,CACvB,SAAU,GACV,QAAS,EAAA,CACV,EAGKE,EAAgB,CACpB,SAAU,CACR,MAAO,OACP,aAAeC,GACTA,IAAQ,IAAY,OACpBA,IAAQ,IAAY,QACjB,EACT,EAEF,QAAS,CACP,MAAO,KAAA,CACT,EAIIC,EAAgB,CACpB,CAAE,MAAO,IAAK,MAAO,MAAA,EACrB,CAAE,MAAO,IAAK,MAAO,OAAA,CAAQ,EAGzBC,EAAkB,CACtB,CAAE,MAAO,IAAK,MAAO,KAAA,EACrB,CAAE,MAAO,IAAK,MAAO,KAAA,EACrB,CAAE,MAAO,IAAK,MAAO,KAAA,CAAM,EAIvBC,EAAUN,EAAAA,IAAA,EAGVO,EAAUP,EAAAA,IAAI,CAClB,CAAE,KAAM,OAAQ,KAAM,QAAS,SAAU,IAAK,SAAU,IAAK,OAAQ,QAAA,EACrE,CAAE,KAAM,OAAQ,KAAM,QAAS,SAAU,IAAK,SAAU,IAAK,OAAQ,EAAA,EACrE,CAAE,KAAM,OAAQ,KAAM,QAAS,SAAU,IAAK,SAAU,IAAK,OAAQ,KAAA,EACrE,CAAE,KAAM,OAAQ,KAAM,OAAQ,SAAU,IAAK,SAAU,IAAK,OAAQ,EAAA,EACpE,CAAE,KAAM,OAAQ,KAAM,UAAW,SAAU,IAAK,SAAU,IAAK,OAAQ,QAAA,CAAS,CACjF,EAEKQ,EAAaR,EAAAA,IAAI,CACrB,CAAE,MAAO,OAAQ,WAAY,KAAM,MAAO,GAAA,EAC1C,CAAE,MAAO,OAAQ,WAAY,KAAM,MAAO,GAAA,EAC1C,CAAE,MAAO,WAAY,WAAY,KAAM,MAAO,GAAA,EAC9C,CACE,MAAO,WACP,WAAY,KACZ,MAAO,IACP,aAAeS,GAAiBA,EAAO,QAAU,IAAM,IAAM,EAAA,EAE/D,CAAE,MAAO,SAAU,WAAY,KAAM,KAAM,CAAA,CAAE,CAC9C,EAGKC,EAAgC,CACpC,CACE,KAAM,SACN,MAAO,KACP,QAAS,KACT,QAAUH,GAAiB,CACzBI,EAAM,MAAQ,GACdC,EAAO,MAAQ,CACb,KAAML,EAAQ,KACd,KAAMA,EAAQ,KACd,SAAUA,EAAQ,SAClB,SAAUA,EAAQ,SAClB,OAAQA,EAAQ,MAAA,CAEpB,CAAA,EAEF,CACE,KAAM,SACN,MAAO,KACP,QAAS,KACT,UAAW,SACX,QAAUA,GAAiB,CACrB,QAAQ,GAAGA,EAAQ,IAAI,gBAAgB,IACzC,QAAQ,IAAI,MAAOA,EAAQ,IAAI,EAC/B,MAAM,YAAYA,EAAQ,IAAI,EAAE,EAEpC,CAAA,CACF,EAIII,EAAQX,EAAAA,IAAI,EAAK,EACjBY,EAASZ,EAAAA,IAAI,CACjB,KAAM,GACN,KAAM,GACN,SAAU,GACV,SAAU,IACV,OAAQ,EAAA,CACT,EAOD,SAASa,EAAaC,EAAY,CAChCH,EAAM,MAAQ,GACd,MAAMJ,EAAUO,EAAM,KAGtBF,EAAO,MAAQ,CACb,KAAML,EAAQ,KACd,KAAMA,EAAQ,KACd,SAAUA,EAAQ,SAClB,SAAUA,EAAQ,SAClB,OAAQA,EAAQ,MAAA,CAEpB,CAKA,SAASQ,GAAQ,CACfJ,EAAM,MAAQ,GAEdC,EAAO,MAAQ,CACb,KAAM,GACN,KAAM,GACN,SAAU,GACV,SAAU,IACV,OAAQ,EAAA,CAEZ,CAKA,SAASI,GAAS,CAChB,QAAQ,IAAI,MAAOJ,EAAO,KAAK,EAQ/B,MAAM,YAAYA,EAAO,MAAM,IAAI,EAAE,CACvC,CAKA,SAASK,GAAW,CACd,QAAQ,GAAGL,EAAO,MAAM,IAAI,gBAAgB,IAC9C,QAAQ,IAAI,MAAOA,EAAO,MAAM,IAAI,EAIpC,MAAM,YAAYA,EAAO,MAAM,IAAI,EAAE,EAEzC,CAKA,SAASM,GAAU,CACjBjB,EAAa,MAAQ,CACnB,SAAU,GACV,QAAS,EAAA,EAEX,QAAQ,IAAI,QAAQ,CACtB,CAKA,SAASkB,GAAW,CAClB,QAAQ,IAAI,SAAUlB,EAAa,KAAK,CAI1C,CAKA,SAASmB,GAAS,CAChB,MAAM,gBAAgB,CACxB,CAEA,OAAAC,EAAa,CAAE,QAAAf,EAAS,UAxTtBgB,YAAA,EAAAC,qBA8GM,MA9GNC,EA8GM,CA5GJC,cAMEC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CALA,KAAK,WACL,MAAM,SACN,YAAY,qBACX,SAAU,GACV,OAAAP,CAAA,GAIHK,cA0BaC,EAAAA,MAAAE,EAAAA,OAAA,EAAA,CAzBH,UAAW7B,EAAA,0CAAAA,EAAe,MAAA8B,GAC1B,aAAc5B,EAAA,6CAAAA,EAAY,MAAA4B,GACjC,cAAA3B,EACA,YAAa,GACd,MAAM,QAAA,GAGK,kBACT,IAAmE,CAAnEuB,cAAmEC,EAAAA,MAAAI,EAAAA,OAAA,EAAA,CAA1D,KAAK,KAAK,QAAQ,UAAW,QAAOZ,CAAA,qBAAS,IAAG,CAAA,GAAAa,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAA,mBAAH,MAAG,EAAA,CAAA,WACzDN,cAAqEC,EAAAA,MAAAI,EAAAA,OAAA,EAAA,CAA5D,KAAK,KAAK,UAAU,UAAW,QAAOX,CAAA,qBAAU,IAAE,CAAA,GAAAY,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAA,mBAAF,KAAE,EAAA,CAAA,WAC3DN,cAAkEC,EAAAA,MAAAI,EAAAA,OAAA,EAAA,CAAzD,KAAK,KAAK,UAAU,UAAW,QAAOf,CAAA,qBAAO,IAAE,CAAA,GAAAgB,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAA,mBAAF,KAAE,EAAA,CAAA,aAI/C,kBACT,IAQM,CARNC,EAAAA,mBAQM,MARNC,EAQM,CAPJR,cAKEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAJA,KAAK,QACL,MAAM,OACG,WAAAjC,EAAA,MAAa,SAAb,sBAAA8B,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAA5B,EAAA,MAAa,SAAQ4B,GAC7B,QAASzB,CAAA,yBAEZqB,cAAsEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAA1D,KAAK,QAAQ,MAAM,MAAe,WAAAjC,EAAA,MAAa,QAAb,sBAAA8B,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAA5B,EAAA,MAAa,QAAO4B,EAAA,kEAMxEJ,cAqEYC,EAAAA,MAAAS,EAAAA,OAAA,EAAA,CApEV,UAAU,aACT,eAAc,GACd,WAAU,GACV,kBAAiB,GACjB,kBAAiB,GAClB,MAAM,QAAA,GAGK,eACT,IAQM,CARNH,EAAAA,mBAQM,MARNI,EAQM,CAPJX,cAMEC,EAAAA,MAAAW,EAAAA,OAAA,EAAA,SALI,UAAJ,IAAI/B,EACH,WAAYE,EAAA,MACZ,QAASD,EAAA,MACT,iBAAgBG,EAChB,aAAAG,CAAA,uCAMI,gBACT,IA4CM,CA5CNmB,EAAAA,mBA4CM,MA5CNM,EA4CM,CA3CJN,qBAA2E,KAA3EO,EAA2EC,kBAAjC7B,EAAA,MAAK,QAAA,OAAA,EAAA,CAAA,EAG/CqB,EAAAA,mBAcM,MAdNS,EAcM,CAbJhB,cAMEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CALA,KAAK,QACL,MAAM,KACG,WAAAtB,EAAA,MAAO,KAAP,sBAAAmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAAjB,EAAA,MAAO,KAAIiB,GACnB,UAAWlB,EAAA,MACZ,YAAY,QAAA,oCAEdc,cAKEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAJA,KAAK,QACL,MAAM,KACG,WAAAtB,EAAA,MAAO,KAAP,sBAAAmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAAjB,EAAA,MAAO,KAAIiB,GACpB,YAAY,QAAA,2BAKhBG,EAAAA,mBAaM,MAbNU,EAaM,CAZJjB,cAKEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAJA,KAAK,QACL,MAAM,KACG,WAAAtB,EAAA,MAAO,SAAP,sBAAAmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAAjB,EAAA,MAAO,SAAQiB,GACvB,QAASxB,CAAA,yBAEZoB,cAKEC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAJA,KAAK,WACL,MAAM,OACG,WAAAtB,EAAA,MAAO,SAAP,sBAAAmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAAjB,EAAA,MAAO,SAAQiB,GACxB,YAAY,IAAA,2BAKhBJ,cAAkFC,EAAAA,MAAAQ,EAAAA,OAAA,EAAA,CAAtE,KAAK,WAAW,MAAM,KAAc,WAAAtB,EAAA,MAAO,OAAP,sBAAAmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAF,GAAAjB,EAAA,MAAO,OAAMiB,GAAE,YAAY,IAAA,yBAG3EG,EAAAA,mBAGM,MAHNW,EAGM,CAFJlB,cAAmEC,EAAAA,MAAAI,EAAAA,OAAA,EAAA,CAA1D,UAAU,UAAU,KAAK,KAAM,QAAOd,CAAA,qBAAQ,IAAE,CAAA,GAAAe,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAA,mBAAF,KAAE,EAAA,CAAA,WACKpB,EAAA,iDAA9DiC,EAAAA,YAAiFlB,EAAAA,MAAAI,EAAAA,OAAA,EAAA,OAAxE,QAAQ,UAAU,KAAK,KAAM,QAAOb,CAAA,qBAAwB,IAAE,CAAA,GAAAc,EAAA,EAAA,IAAAA,EAAA,EAAA,EAAA,mBAAF,KAAE,EAAA,CAAA"}
1
+ {"version":3,"file":"ExampleCrudPage.vue.cjs","sources":["../../../../src/components/examples/ExampleCrudPage.vue"],"sourcesContent":["<template>\n <div class=\"flex flex-col h-full gap-2 bg-background text-foreground\">\n <!-- ==================== 타이틀바 ==================== -->\n <JTitlebar \n icon=\"building\" \n title=\"고객사 관리\" \n description=\"고객사 정보를 조회하고 관리합니다\"\n :showHelp=\"true\" \n @help=\"onHelp\" \n />\n\n <!-- ==================== 필터바 ==================== -->\n <JFilterBar\n v-model:collapsed=\"filterCollapsed\"\n v-model:filterValues=\"filterValues\"\n :filterDisplay=\"filterDisplay\"\n :collapsible=\"true\"\n title=\"고객사 목록\"\n >\n <!-- 액션 버튼 -->\n <template #actions>\n <JButton size=\"sm\" variant=\"outline\" @click=\"onReset\">초기화</JButton>\n <JButton size=\"sm\" styletype=\"primary\" @click=\"onSearch\">조회</JButton>\n <JButton size=\"sm\" styletype=\"primary\" @click=\"onNew\">신규</JButton>\n </template>\n\n <!-- 필터 필드 - 다중 열 배치 -->\n <template #filters>\n <div class=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2\">\n <JFormField\n type=\"combo\"\n label=\"활성여부\"\n v-model=\"filterValues.isActive\"\n :options=\"activeOptions\"\n orientation=\"horizontal\"\n labelWidth=\"30%\"\n />\n <JFormField type=\"input\" label=\"검색어\" v-model=\"filterValues.keyword\"\n orientation=\"horizontal\"\n labelWidth=\"30%\" />\n </div>\n </template>\n </JFilterBar>\n\n <!-- ==================== 그리드 + 상세 영역 (Resizable) ==================== -->\n <JSplitter\n direction=\"horizontal\"\n :default-size=\"60\"\n :min-size=\"30\"\n :second-min-size=\"20\"\n :second-max-size=\"60\"\n :gap=\"2\"\n class=\"flex-1\"\n >\n <!-- 좌측: 그리드 -->\n <template #left>\n <div class=\"h-full overflow-auto bg-background\">\n <JGrid\n ref=\"gridRef\"\n :columnDefs=\"columnDefs\"\n :rowData=\"rowData\"\n :action-buttons=\"actionButtons\"\n :enableGrouping=\"true\"\n :enablePivot=\"true\"\n :enableColumnsToolPanel=\"true\"\n rowGroupPanelShow=\"always\"\n pivotPanelShow=\"always\"\n :groupDefaultExpanded=\"1\"\n :compactFooter=\"true\"\n @row-clicked=\"onRowClicked\"\n />\n </div>\n </template>\n\n <!-- 우측: 상세 영역 -->\n <template #right>\n <div class=\"h-full overflow-y-auto border-l bg-muted/30\">\n <JCard class=\"h-full\" :title=\"isNew ? '신규 등록' : '상세 정보'\">\n\n <!-- 2열 그리드: 코드, 이름 -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-2 mt-2\">\n <JFormField\n type=\"input\"\n label=\"코드\"\n v-model=\"detail.code\"\n :readonly=\"!isNew\"\n placeholder=\"고객사 코드\"\n />\n <JFormField\n type=\"input\"\n label=\"이름\"\n v-model=\"detail.name\"\n placeholder=\"고객사 이름\"\n />\n </div>\n\n <!-- 2열 그리드: 분류, 활성여부 -->\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-2 mt-2\">\n <JFormField\n type=\"combo\"\n label=\"분류\"\n v-model=\"detail.category\"\n :options=\"categoryOptions\"\n />\n <JFormField\n type=\"checkbox\"\n label=\"활성여부\"\n v-model=\"detail.isActive\"\n inlineLabel=\"활성\"\n />\n </div>\n <div class=\"grid grid-cols-1 gap-2 mt-2\">\n <!-- 전체 너비: 비고 -->\n <JFormField type=\"textarea\" label=\"비고\" v-model=\"detail.remark\" placeholder=\"비고\" />\n\n </div>\n\n \n <!-- 액션 버튼 -->\n <template #footer>\n <div class=\"flex justify-end gap-2\">\n <JButton styletype=\"primary\" size=\"sm\" @click=\"onSave\">저장</JButton>\n <JButton variant=\"outline\" size=\"sm\" @click=\"onDelete\" v-if=\"!isNew\">삭제</JButton>\n </div>\n </template>\n </JCard>\n </div>\n </template>\n </JSplitter>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport { JTitlebar, JCard } from '@/components/molecules'\nimport { JFilterBar } from '@/components/organisms'\nimport { JGrid, JButton, JSplitter, type ActionButton } from '@/components/atoms'\nimport { JFormField } from '@/components/molecules'\n\n// ==================== 필터 상태 ====================\nconst filterCollapsed = ref(false)\n\n// 필터 값 (v-model:filterValues)\nconst filterValues = ref({\n isActive: '',\n keyword: '',\n})\n\n// 필터 표시 설정 (배지에 표시될 라벨 및 값 변환 함수)\nconst filterDisplay = {\n isActive: {\n label: '활성여부',\n displayValue: (val: unknown) => {\n if (val === 'Y') return 'Y:활성'\n if (val === 'N') return 'N:비활성'\n return ''\n },\n },\n keyword: {\n label: '검색어',\n },\n}\n\n// ==================== 옵션 데이터 ====================\nconst activeOptions = [\n { value: 'Y', label: 'Y:활성' },\n { value: 'N', label: 'N:비활성' },\n]\n\nconst categoryOptions = [\n { value: 'A', label: 'A등급' },\n { value: 'B', label: 'B등급' },\n { value: 'C', label: 'C등급' },\n]\n\n// ==================== 그리드 설정 ====================\nconst gridRef = ref()\n\n// Mock 데이터 - 실제 백엔드 응답 구조\nconst rowData = ref([\n { code: 'C001', name: '제이솔루션', category: 'A', isActive: 'Y', remark: '주력 고객사' },\n { code: 'C002', name: 'ABC물류', category: 'B', isActive: 'Y', remark: '' },\n { code: 'C003', name: 'XYZ유통', category: 'A', isActive: 'N', remark: '비활성' },\n { code: 'C004', name: '대한물류', category: 'B', isActive: 'Y', remark: '' },\n { code: 'C005', name: '글로벌이커머스', category: 'A', isActive: 'Y', remark: '신규 고객사' },\n])\n\nconst columnDefs = ref([\n { \n field: 'code', \n headerName: '코드', \n width: 120,\n enableValue: true, // 집계 가능 (count)\n },\n { \n field: 'name', \n headerName: '이름', \n width: 200,\n enableValue: true, // 집계 가능 (count)\n },\n { \n field: 'category', \n headerName: '분류', \n width: 100,\n enableRowGroup: true, // Row Group으로 사용 가능\n enablePivot: true, // Pivot Column으로 사용 가능\n },\n {\n field: 'isActive',\n headerName: '활성',\n width: 100,\n cellRenderer: (params: any) => (params.value === 'Y' ? '✓' : ''),\n enableRowGroup: true, // Row Group으로 사용 가능\n enablePivot: true, // Pivot Column으로 사용 가능\n },\n { \n field: 'remark', \n headerName: '비고', \n flex: 1,\n enableValue: true, // 집계 가능 (count)\n },\n])\n\n// 행별 액션 버튼\nconst actionButtons: ActionButton[] = [\n {\n icon: 'pencil',\n label: '수정',\n tooltip: '편집',\n onClick: (rowData: any) => {\n isNew.value = false\n detail.value = {\n code: rowData.code,\n name: rowData.name,\n category: rowData.category,\n isActive: rowData.isActive,\n remark: rowData.remark,\n }\n },\n },\n {\n icon: 'trash2',\n label: '삭제',\n tooltip: '삭제',\n styletype: 'danger',\n onClick: (rowData: any) => {\n if (confirm(`${rowData.name}을(를) 삭제하시겠습니까?`)) {\n console.log('삭제:', rowData.code)\n alert(`삭제되었습니다: ${rowData.name}`)\n }\n },\n },\n]\n\n// ==================== 상세 영역 상태 ====================\nconst isNew = ref(false)\nconst detail = ref({\n code: '',\n name: '',\n category: '',\n isActive: 'Y',\n remark: '',\n})\n\n// ==================== 이벤트 핸들러 ====================\n\n/**\n * 그리드 행 클릭 핸들러\n */\nfunction onRowClicked(event: any) {\n isNew.value = false\n const rowData = event.data\n\n // 선택된 행 데이터를 상세 영역에 바인딩\n detail.value = {\n code: rowData.code,\n name: rowData.name,\n category: rowData.category,\n isActive: rowData.isActive,\n remark: rowData.remark,\n }\n}\n\n/**\n * 신규 버튼 클릭\n */\nfunction onNew() {\n isNew.value = true\n // 상세 영역 초기화\n detail.value = {\n code: '',\n name: '',\n category: '',\n isActive: 'Y',\n remark: '',\n }\n}\n\n/**\n * 저장 버튼 클릭\n */\nfunction onSave() {\n console.log('저장:', detail.value)\n // TODO: 실제 구현 시 API 호출로 대체\n // if (isNew.value) {\n // await api.createCustomer(detail.value)\n // } else {\n // await api.updateCustomer(detail.value.code, detail.value)\n // }\n // 성공 시 그리드 데이터 갱신\n alert(`저장되었습니다: ${detail.value.name}`)\n}\n\n/**\n * 삭제 버튼 클릭\n */\nfunction onDelete() {\n if (confirm(`${detail.value.name}을(를) 삭제하시겠습니까?`)) {\n console.log('삭제:', detail.value.code)\n // TODO: 실제 구현 시 API 호출로 대체\n // await api.deleteCustomer(detail.value.code)\n // 성공 시 그리드에서 해당 행 제거\n alert(`삭제되었습니다: ${detail.value.name}`)\n }\n}\n\n/**\n * 초기화 버튼 클릭\n */\nfunction onReset() {\n filterValues.value = {\n isActive: '',\n keyword: '',\n }\n console.log('필터 초기화')\n}\n\n/**\n * 조회 버튼 클릭\n */\nfunction onSearch() {\n console.log('조회 조건:', filterValues.value)\n // TODO: 실제 구현 시 API 호출로 대체\n // const result = await api.searchCustomers(filterValues.value)\n // rowData.value = result.data\n}\n\n/**\n * 도움말 아이콘 클릭\n */\nfunction onHelp() {\n alert('고객사 관리 페이지 도움말')\n}\n\ndefineExpose({ gridRef })\n</script>\n"],"names":["filterCollapsed","ref","filterValues","filterDisplay","val","activeOptions","categoryOptions","gridRef","rowData","columnDefs","params","actionButtons","isNew","detail","onRowClicked","event","onNew","onSave","onDelete","onReset","onSearch","onHelp","__expose","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","JTitlebar","JFilterBar","$event","JButton","_cache","_createElementVNode","_hoisted_2","JFormField","JSplitter","_hoisted_3","JGrid","_hoisted_4","JCard","_hoisted_8","_createBlock","_hoisted_5","_hoisted_6","_hoisted_7"],"mappings":"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"}