@j-solution/components 2.0.4 → 2.0.5

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");const g=require("../shadcn/Select.vue.cjs"),v=require("../shadcn/SelectTrigger.vue.cjs"),y=require("../shadcn/SelectValue.vue.cjs"),b=require("../shadcn/SelectContent.vue.cjs"),V=require("../shadcn/SelectItem.vue.cjs"),d="__EMPTY_STRING__",x=e.defineComponent({__name:"JCombo",props:{modelValue:{},options:{default:()=>[]},placeholder:{default:"선택하세요"},disabled:{type:Boolean,default:!1},required:{type:Boolean,default:!1},name:{},id:{},multiple:{type:Boolean,default:!1},class:{},styletype:{default:"default"}},emits:["update:modelValue","change","focus","blur"],setup(r,{emit:c}){const a=r,s=c,n={default:{class:""},error:{class:"border-destructive focus:ring-destructive"},success:{class:"border-green-500 focus:ring-green-500"},warning:{class:"border-amber-500 focus:ring-amber-500"},sm:{class:"h-7 text-xs px-2"},lg:{class:"h-12 text-base px-4"}},i=e.computed(()=>{const t=a.styletype||"default";return[(n[t]??n.default)?.class,a.class].filter(Boolean).join(" ")}),o=t=>t===""||t===void 0?d:String(t),f=t=>t===d?"":t,_=e.computed(()=>a.options.map(t=>({...t,value:o(t.value)}))),p=e.computed(()=>o(a.modelValue)),m=t=>{const l=f(t);s("update:modelValue",l),s("change",l)};return(t,l)=>(e.openBlock(),e.createBlock(e.unref(g.default),{"model-value":p.value,disabled:r.disabled,required:r.required,name:r.name,"onUpdate:modelValue":l[0]||(l[0]=u=>m(u)),onFocus:l[1]||(l[1]=u=>s("focus",u)),onBlur:l[2]||(l[2]=u=>s("blur",u))},{default:e.withCtx(()=>[e.createVNode(e.unref(v.default),{id:r.id,class:e.normalizeClass(i.value)},{default:e.withCtx(()=>[e.createVNode(e.unref(y.default),{placeholder:r.placeholder},null,8,["placeholder"])]),_:1},8,["id","class"]),e.createVNode(e.unref(b.default),null,{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(_.value,u=>(e.openBlock(),e.createBlock(e.unref(V.default),{key:u.value,value:u.value},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(u.label),1)]),_:2},1032,["value"]))),128))]),_:1})]),_:1},8,["model-value","disabled","required","name"]))}});exports.default=x;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");const g=require("../shadcn/Select.vue.cjs"),v=require("../shadcn/SelectTrigger.vue.cjs"),y=require("../shadcn/SelectValue.vue.cjs"),b=require("../shadcn/SelectContent.vue.cjs"),V=require("../shadcn/SelectItem.vue.cjs"),d="__EMPTY_STRING__",x=e.defineComponent({__name:"JCombo",props:{modelValue:{},options:{default:()=>[]},placeholder:{default:""},disabled:{type:Boolean,default:!1},required:{type:Boolean,default:!1},name:{},id:{},multiple:{type:Boolean,default:!1},class:{},styletype:{default:"default"}},emits:["update:modelValue","change","focus","blur"],setup(r,{emit:c}){const a=r,s=c,n={default:{class:""},error:{class:"border-destructive focus:ring-destructive"},success:{class:"border-green-500 focus:ring-green-500"},warning:{class:"border-amber-500 focus:ring-amber-500"},sm:{class:"h-7 text-xs px-2"},lg:{class:"h-12 text-base px-4"}},i=e.computed(()=>{const t=a.styletype||"default";return[(n[t]??n.default)?.class,a.class].filter(Boolean).join(" ")}),o=t=>t===""||t===void 0?d:String(t),f=t=>t===d?"":t,_=e.computed(()=>a.options.map(t=>({...t,value:o(t.value)}))),p=e.computed(()=>o(a.modelValue)),m=t=>{const l=f(t);s("update:modelValue",l),s("change",l)};return(t,l)=>(e.openBlock(),e.createBlock(e.unref(g.default),{"model-value":p.value,disabled:r.disabled,required:r.required,name:r.name,"onUpdate:modelValue":l[0]||(l[0]=u=>m(u)),onFocus:l[1]||(l[1]=u=>s("focus",u)),onBlur:l[2]||(l[2]=u=>s("blur",u))},{default:e.withCtx(()=>[e.createVNode(e.unref(v.default),{id:r.id,class:e.normalizeClass(i.value)},{default:e.withCtx(()=>[e.createVNode(e.unref(y.default),{placeholder:r.placeholder},null,8,["placeholder"])]),_:1},8,["id","class"]),e.createVNode(e.unref(b.default),null,{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(_.value,u=>(e.openBlock(),e.createBlock(e.unref(V.default),{key:u.value,value:u.value},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(u.label),1)]),_:2},1032,["value"]))),128))]),_:1})]),_:1},8,["model-value","disabled","required","name"]))}});exports.default=x;
2
2
  //# sourceMappingURL=JCombo.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"JCombo.vue.cjs","sources":["../../../../src/components/atoms/JCombo.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shadcn'\n\n// 빈 문자열 value를 위한 내부 플레이스홀더\n// reka-ui SelectItem이 빈 문자열을 처리하지 못하는 버그 우회\nconst EMPTY_VALUE_PLACEHOLDER = '__EMPTY_STRING__'\n\nexport interface Option {\n value: string | number\n label: string\n}\n\ntype StyleType =\n | 'default' // 기본 스타일\n | 'error' // 에러 상태\n | 'success' // 성공 상태\n | 'warning' // 경고 상태\n | 'sm' // 작은 크기\n | 'lg' // 큰 크기\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | number\n options?: Option[]\n placeholder?: string\n disabled?: boolean\n required?: boolean\n name?: string\n id?: string\n multiple?: boolean\n class?: string\n /** 스타일 프리셋 */\n styletype?: StyleType\n }>(),\n {\n options: () => [],\n placeholder: '선택하세요',\n disabled: false,\n required: false,\n multiple: false,\n styletype: 'default',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n 'change': [value: string | number]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n/**\n * styletype -> class 매핑\n */\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\n default: { class: '' },\n error: { \n class: 'border-destructive focus:ring-destructive',\n },\n success: { \n class: 'border-green-500 focus:ring-green-500',\n },\n warning: { \n class: 'border-amber-500 focus:ring-amber-500',\n },\n sm: { \n class: 'h-7 text-xs px-2',\n },\n lg: { \n class: 'h-12 text-base px-4',\n },\n}\n\nconst triggerClass = computed(() => {\n const styleKey = props.styletype || 'default'\n const preset = STYLE_PRESETS[styleKey] ?? STYLE_PRESETS.default\n return [preset?.class, props.class].filter(Boolean).join(' ')\n})\n\n/**\n * 외부 value를 내부 value로 변환\n * 빈 문자열 -> __EMPTY_STRING__\n */\nconst toInternalValue = (value: string | number | undefined): string => {\n if (value === '' || value === undefined) {\n return EMPTY_VALUE_PLACEHOLDER\n }\n return String(value)\n}\n\n/**\n * 내부 value를 외부 value로 변환\n * __EMPTY_STRING__ -> ''\n */\nconst toExternalValue = (value: string): string | number => {\n if (value === EMPTY_VALUE_PLACEHOLDER) {\n return ''\n }\n return value\n}\n\n/**\n * 옵션의 value를 내부 형식으로 변환\n * 빈 문자열 value를 가진 옵션 -> __EMPTY_STRING__으로 변환\n */\nconst processedOptions = computed(() => {\n return props.options.map((option) => ({\n ...option,\n value: toInternalValue(option.value),\n }))\n})\n\n/**\n * 현재 modelValue를 내부 형식으로 변환\n */\nconst internalModelValue = computed(() => toInternalValue(props.modelValue))\n\nconst handleChange = (internalValue: string) => {\n const externalValue = toExternalValue(internalValue)\n emit('update:modelValue', externalValue)\n emit('change', externalValue)\n}\n</script>\n\n<template>\n <Select\n :model-value=\"internalModelValue\"\n :disabled=\"disabled\"\n :required=\"required\"\n :name=\"name\"\n @update:model-value=\"(value) => handleChange(value as string)\"\n @focus=\"emit('focus', $event as FocusEvent)\"\n @blur=\"emit('blur', $event as FocusEvent)\"\n >\n <SelectTrigger :id=\"id\" :class=\"triggerClass\">\n <SelectValue :placeholder=\"placeholder\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem\n v-for=\"option in processedOptions\"\n :key=\"option.value\"\n :value=\"option.value\"\n >\n {{ option.label }}\n </SelectItem>\n </SelectContent>\n </Select>\n</template>\n"],"names":["EMPTY_VALUE_PLACEHOLDER","props","__props","emit","__emit","STYLE_PRESETS","triggerClass","computed","styleKey","toInternalValue","value","toExternalValue","processedOptions","option","internalModelValue","handleChange","internalValue","externalValue","_createBlock","_unref","Select","_cache","$event","_createVNode","SelectTrigger","SelectValue","SelectContent","_createElementBlock","_Fragment","_renderList","SelectItem","_createTextVNode","_toDisplayString"],"mappings":"6XAMMA,EAA0B,yWAehC,MAAMC,EAAQC,EAwBRC,EAAOC,EAUPC,EAAsD,CAC1D,QAAS,CAAE,MAAO,EAAA,EAClB,MAAO,CACL,MAAO,2CAAA,EAET,QAAS,CACP,MAAO,uCAAA,EAET,QAAS,CACP,MAAO,uCAAA,EAET,GAAI,CACF,MAAO,kBAAA,EAET,GAAI,CACF,MAAO,qBAAA,CACT,EAGIC,EAAeC,EAAAA,SAAS,IAAM,CAClC,MAAMC,EAAWP,EAAM,WAAa,UAEpC,MAAO,EADQI,EAAcG,CAAQ,GAAKH,EAAc,UACxC,MAAOJ,EAAM,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAC9D,CAAC,EAMKQ,EAAmBC,GACnBA,IAAU,IAAMA,IAAU,OACrBV,EAEF,OAAOU,CAAK,EAOfC,EAAmBD,GACnBA,IAAUV,EACL,GAEFU,EAOHE,EAAmBL,EAAAA,SAAS,IACzBN,EAAM,QAAQ,IAAKY,IAAY,CACpC,GAAGA,EACH,MAAOJ,EAAgBI,EAAO,KAAK,CAAA,EACnC,CACH,EAKKC,EAAqBP,EAAAA,SAAS,IAAME,EAAgBR,EAAM,UAAU,CAAC,EAErEc,EAAgBC,GAA0B,CAC9C,MAAMC,EAAgBN,EAAgBK,CAAa,EACnDb,EAAK,oBAAqBc,CAAa,EACvCd,EAAK,SAAUc,CAAa,CAC9B,8BAIEC,EAAAA,YAqBSC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CApBN,cAAaN,EAAA,MACb,SAAUZ,EAAA,SACV,SAAUA,EAAA,SACV,KAAMA,EAAA,KACN,sBAAkBmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAGX,GAAUK,EAAaL,CAAK,GACjD,QAAKW,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEnB,EAAI,QAAUmB,CAAM,GAC3B,OAAID,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEnB,EAAI,OAASmB,CAAM,EAAA,qBAE1B,IAEgB,CAFhBC,cAEgBJ,EAAAA,MAAAK,EAAAA,OAAA,EAAA,CAFA,GAAItB,EAAA,GAAK,uBAAOI,EAAA,KAAY,CAAA,qBAC1C,IAA0C,CAA1CiB,EAAAA,YAA0CJ,EAAAA,MAAAM,SAAA,EAAA,CAA5B,YAAavB,EAAA,aAAW,KAAA,EAAA,CAAA,aAAA,CAAA,CAAA,0BAExCqB,EAAAA,YAQgBJ,EAAAA,MAAAO,SAAA,EAAA,KAAA,mBANZ,IAAkC,kBADpCC,EAAAA,mBAMaC,EAAAA,SAAA,KAAAC,EAAAA,WALMjB,EAAA,MAAVC,kBADTK,EAAAA,YAMaC,EAAAA,MAAAW,EAAAA,OAAA,EAAA,CAJV,IAAKjB,EAAO,MACZ,MAAOA,EAAO,KAAA,qBAEf,IAAkB,CAAfkB,EAAAA,gBAAAC,EAAAA,gBAAAnB,EAAO,KAAK,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"JCombo.vue.cjs","sources":["../../../../src/components/atoms/JCombo.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shadcn'\n\n// 빈 문자열 value를 위한 내부 플레이스홀더\n// reka-ui SelectItem이 빈 문자열을 처리하지 못하는 버그 우회\nconst EMPTY_VALUE_PLACEHOLDER = '__EMPTY_STRING__'\n\nexport interface Option {\n value: string | number\n label: string\n}\n\ntype StyleType =\n | 'default' // 기본 스타일\n | 'error' // 에러 상태\n | 'success' // 성공 상태\n | 'warning' // 경고 상태\n | 'sm' // 작은 크기\n | 'lg' // 큰 크기\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | number\n options?: Option[]\n placeholder?: string\n disabled?: boolean\n required?: boolean\n name?: string\n id?: string\n multiple?: boolean\n class?: string\n /** 스타일 프리셋 */\n styletype?: StyleType\n }>(),\n {\n options: () => [],\n placeholder: '',\n disabled: false,\n required: false,\n multiple: false,\n styletype: 'default',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n 'change': [value: string | number]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n/**\n * styletype -> class 매핑\n */\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\n default: { class: '' },\n error: { \n class: 'border-destructive focus:ring-destructive',\n },\n success: { \n class: 'border-green-500 focus:ring-green-500',\n },\n warning: { \n class: 'border-amber-500 focus:ring-amber-500',\n },\n sm: { \n class: 'h-7 text-xs px-2',\n },\n lg: { \n class: 'h-12 text-base px-4',\n },\n}\n\nconst triggerClass = computed(() => {\n const styleKey = props.styletype || 'default'\n const preset = STYLE_PRESETS[styleKey] ?? STYLE_PRESETS.default\n return [preset?.class, props.class].filter(Boolean).join(' ')\n})\n\n/**\n * 외부 value를 내부 value로 변환\n * 빈 문자열 -> __EMPTY_STRING__\n */\nconst toInternalValue = (value: string | number | undefined): string => {\n if (value === '' || value === undefined) {\n return EMPTY_VALUE_PLACEHOLDER\n }\n return String(value)\n}\n\n/**\n * 내부 value를 외부 value로 변환\n * __EMPTY_STRING__ -> ''\n */\nconst toExternalValue = (value: string): string | number => {\n if (value === EMPTY_VALUE_PLACEHOLDER) {\n return ''\n }\n return value\n}\n\n/**\n * 옵션의 value를 내부 형식으로 변환\n * 빈 문자열 value를 가진 옵션 -> __EMPTY_STRING__으로 변환\n */\nconst processedOptions = computed(() => {\n return props.options.map((option) => ({\n ...option,\n value: toInternalValue(option.value),\n }))\n})\n\n/**\n * 현재 modelValue를 내부 형식으로 변환\n */\nconst internalModelValue = computed(() => toInternalValue(props.modelValue))\n\nconst handleChange = (internalValue: string) => {\n const externalValue = toExternalValue(internalValue)\n emit('update:modelValue', externalValue)\n emit('change', externalValue)\n}\n</script>\n\n<template>\n <Select\n :model-value=\"internalModelValue\"\n :disabled=\"disabled\"\n :required=\"required\"\n :name=\"name\"\n @update:model-value=\"(value) => handleChange(value as string)\"\n @focus=\"emit('focus', $event as FocusEvent)\"\n @blur=\"emit('blur', $event as FocusEvent)\"\n >\n <SelectTrigger :id=\"id\" :class=\"triggerClass\">\n <SelectValue :placeholder=\"placeholder\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem\n v-for=\"option in processedOptions\"\n :key=\"option.value\"\n :value=\"option.value\"\n >\n {{ option.label }}\n </SelectItem>\n </SelectContent>\n </Select>\n</template>\n"],"names":["EMPTY_VALUE_PLACEHOLDER","props","__props","emit","__emit","STYLE_PRESETS","triggerClass","computed","styleKey","toInternalValue","value","toExternalValue","processedOptions","option","internalModelValue","handleChange","internalValue","externalValue","_createBlock","_unref","Select","_cache","$event","_createVNode","SelectTrigger","SelectValue","SelectContent","_createElementBlock","_Fragment","_renderList","SelectItem","_createTextVNode","_toDisplayString"],"mappings":"6XAMMA,EAA0B,oWAehC,MAAMC,EAAQC,EAwBRC,EAAOC,EAUPC,EAAsD,CAC1D,QAAS,CAAE,MAAO,EAAA,EAClB,MAAO,CACL,MAAO,2CAAA,EAET,QAAS,CACP,MAAO,uCAAA,EAET,QAAS,CACP,MAAO,uCAAA,EAET,GAAI,CACF,MAAO,kBAAA,EAET,GAAI,CACF,MAAO,qBAAA,CACT,EAGIC,EAAeC,EAAAA,SAAS,IAAM,CAClC,MAAMC,EAAWP,EAAM,WAAa,UAEpC,MAAO,EADQI,EAAcG,CAAQ,GAAKH,EAAc,UACxC,MAAOJ,EAAM,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CAC9D,CAAC,EAMKQ,EAAmBC,GACnBA,IAAU,IAAMA,IAAU,OACrBV,EAEF,OAAOU,CAAK,EAOfC,EAAmBD,GACnBA,IAAUV,EACL,GAEFU,EAOHE,EAAmBL,EAAAA,SAAS,IACzBN,EAAM,QAAQ,IAAKY,IAAY,CACpC,GAAGA,EACH,MAAOJ,EAAgBI,EAAO,KAAK,CAAA,EACnC,CACH,EAKKC,EAAqBP,EAAAA,SAAS,IAAME,EAAgBR,EAAM,UAAU,CAAC,EAErEc,EAAgBC,GAA0B,CAC9C,MAAMC,EAAgBN,EAAgBK,CAAa,EACnDb,EAAK,oBAAqBc,CAAa,EACvCd,EAAK,SAAUc,CAAa,CAC9B,8BAIEC,EAAAA,YAqBSC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CApBN,cAAaN,EAAA,MACb,SAAUZ,EAAA,SACV,SAAUA,EAAA,SACV,KAAMA,EAAA,KACN,sBAAkBmB,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAGX,GAAUK,EAAaL,CAAK,GACjD,QAAKW,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEnB,EAAI,QAAUmB,CAAM,GAC3B,OAAID,EAAA,CAAA,IAAAA,EAAA,CAAA,EAAAC,GAAEnB,EAAI,OAASmB,CAAM,EAAA,qBAE1B,IAEgB,CAFhBC,cAEgBJ,EAAAA,MAAAK,EAAAA,OAAA,EAAA,CAFA,GAAItB,EAAA,GAAK,uBAAOI,EAAA,KAAY,CAAA,qBAC1C,IAA0C,CAA1CiB,EAAAA,YAA0CJ,EAAAA,MAAAM,SAAA,EAAA,CAA5B,YAAavB,EAAA,aAAW,KAAA,EAAA,CAAA,aAAA,CAAA,CAAA,0BAExCqB,EAAAA,YAQgBJ,EAAAA,MAAAO,SAAA,EAAA,KAAA,mBANZ,IAAkC,kBADpCC,EAAAA,mBAMaC,EAAAA,SAAA,KAAAC,EAAAA,WALMjB,EAAA,MAAVC,kBADTK,EAAAA,YAMaC,EAAAA,MAAAW,EAAAA,OAAA,EAAA,CAJV,IAAKjB,EAAO,MACZ,MAAOA,EAAO,KAAA,qBAEf,IAAkB,CAAfkB,EAAAA,gBAAAC,EAAAA,gBAAAnB,EAAO,KAAK,EAAA,CAAA,CAAA"}
@@ -10,7 +10,7 @@ const p = "__EMPTY_STRING__", F = /* @__PURE__ */ y({
10
10
  props: {
11
11
  modelValue: {},
12
12
  options: { default: () => [] },
13
- placeholder: { default: "선택하세요" },
13
+ placeholder: { default: "" },
14
14
  disabled: { type: Boolean, default: !1 },
15
15
  required: { type: Boolean, default: !1 },
16
16
  name: {},
@@ -1 +1 @@
1
- {"version":3,"file":"JCombo.vue.js","sources":["../../../../src/components/atoms/JCombo.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shadcn'\n\n// 빈 문자열 value를 위한 내부 플레이스홀더\n// reka-ui SelectItem이 빈 문자열을 처리하지 못하는 버그 우회\nconst EMPTY_VALUE_PLACEHOLDER = '__EMPTY_STRING__'\n\nexport interface Option {\n value: string | number\n label: string\n}\n\ntype StyleType =\n | 'default' // 기본 스타일\n | 'error' // 에러 상태\n | 'success' // 성공 상태\n | 'warning' // 경고 상태\n | 'sm' // 작은 크기\n | 'lg' // 큰 크기\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | number\n options?: Option[]\n placeholder?: string\n disabled?: boolean\n required?: boolean\n name?: string\n id?: string\n multiple?: boolean\n class?: string\n /** 스타일 프리셋 */\n styletype?: StyleType\n }>(),\n {\n options: () => [],\n placeholder: '선택하세요',\n disabled: false,\n required: false,\n multiple: false,\n styletype: 'default',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n 'change': [value: string | number]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n/**\n * styletype -> class 매핑\n */\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\n default: { class: '' },\n error: { \n class: 'border-destructive focus:ring-destructive',\n },\n success: { \n class: 'border-green-500 focus:ring-green-500',\n },\n warning: { \n class: 'border-amber-500 focus:ring-amber-500',\n },\n sm: { \n class: 'h-7 text-xs px-2',\n },\n lg: { \n class: 'h-12 text-base px-4',\n },\n}\n\nconst triggerClass = computed(() => {\n const styleKey = props.styletype || 'default'\n const preset = STYLE_PRESETS[styleKey] ?? STYLE_PRESETS.default\n return [preset?.class, props.class].filter(Boolean).join(' ')\n})\n\n/**\n * 외부 value를 내부 value로 변환\n * 빈 문자열 -> __EMPTY_STRING__\n */\nconst toInternalValue = (value: string | number | undefined): string => {\n if (value === '' || value === undefined) {\n return EMPTY_VALUE_PLACEHOLDER\n }\n return String(value)\n}\n\n/**\n * 내부 value를 외부 value로 변환\n * __EMPTY_STRING__ -> ''\n */\nconst toExternalValue = (value: string): string | number => {\n if (value === EMPTY_VALUE_PLACEHOLDER) {\n return ''\n }\n return value\n}\n\n/**\n * 옵션의 value를 내부 형식으로 변환\n * 빈 문자열 value를 가진 옵션 -> __EMPTY_STRING__으로 변환\n */\nconst processedOptions = computed(() => {\n return props.options.map((option) => ({\n ...option,\n value: toInternalValue(option.value),\n }))\n})\n\n/**\n * 현재 modelValue를 내부 형식으로 변환\n */\nconst internalModelValue = computed(() => toInternalValue(props.modelValue))\n\nconst handleChange = (internalValue: string) => {\n const externalValue = toExternalValue(internalValue)\n emit('update:modelValue', externalValue)\n emit('change', externalValue)\n}\n</script>\n\n<template>\n <Select\n :model-value=\"internalModelValue\"\n :disabled=\"disabled\"\n :required=\"required\"\n :name=\"name\"\n @update:model-value=\"(value) => handleChange(value as string)\"\n @focus=\"emit('focus', $event as FocusEvent)\"\n @blur=\"emit('blur', $event as FocusEvent)\"\n >\n <SelectTrigger :id=\"id\" :class=\"triggerClass\">\n <SelectValue :placeholder=\"placeholder\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem\n v-for=\"option in processedOptions\"\n :key=\"option.value\"\n :value=\"option.value\"\n >\n {{ option.label }}\n </SelectItem>\n </SelectContent>\n </Select>\n</template>\n"],"names":["EMPTY_VALUE_PLACEHOLDER","props","__props","emit","__emit","STYLE_PRESETS","triggerClass","computed","styleKey","toInternalValue","value","toExternalValue","processedOptions","option","internalModelValue","handleChange","internalValue","externalValue","_createBlock","_unref","Select","_cache","$event","_createVNode","SelectTrigger","SelectValue","SelectContent","_createElementBlock","_Fragment","_renderList","SelectItem","_createTextVNode","_toDisplayString"],"mappings":";;;;;;;AAMA,MAAMA,IAA0B;;;;;;;;;;;;;;;;AAehC,UAAMC,IAAQC,GAwBRC,IAAOC,GAUPC,IAAsD;AAAA,MAC1D,SAAS,EAAE,OAAO,GAAA;AAAA,MAClB,OAAO;AAAA,QACL,OAAO;AAAA,MAAA;AAAA,MAET,SAAS;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,MAET,SAAS;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,MAET,IAAI;AAAA,QACF,OAAO;AAAA,MAAA;AAAA,MAET,IAAI;AAAA,QACF,OAAO;AAAA,MAAA;AAAA,IACT,GAGIC,IAAeC,EAAS,MAAM;AAClC,YAAMC,IAAWP,EAAM,aAAa;AAEpC,aAAO,EADQI,EAAcG,CAAQ,KAAKH,EAAc,UACxC,OAAOJ,EAAM,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC9D,CAAC,GAMKQ,IAAkB,CAACC,MACnBA,MAAU,MAAMA,MAAU,SACrBV,IAEF,OAAOU,CAAK,GAOfC,IAAkB,CAACD,MACnBA,MAAUV,IACL,KAEFU,GAOHE,IAAmBL,EAAS,MACzBN,EAAM,QAAQ,IAAI,CAACY,OAAY;AAAA,MACpC,GAAGA;AAAA,MACH,OAAOJ,EAAgBI,EAAO,KAAK;AAAA,IAAA,EACnC,CACH,GAKKC,IAAqBP,EAAS,MAAME,EAAgBR,EAAM,UAAU,CAAC,GAErEc,IAAe,CAACC,MAA0B;AAC9C,YAAMC,IAAgBN,EAAgBK,CAAa;AACnD,MAAAb,EAAK,qBAAqBc,CAAa,GACvCd,EAAK,UAAUc,CAAa;AAAA,IAC9B;2BAIEC,EAqBSC,EAAAC,CAAA,GAAA;AAAA,MApBN,eAAaN,EAAA;AAAA,MACb,UAAUZ,EAAA;AAAA,MACV,UAAUA,EAAA;AAAA,MACV,MAAMA,EAAA;AAAA,MACN,uBAAkBmB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGX,MAAUK,EAAaL,CAAK;AAAA,MACjD,SAAKW,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEnB,EAAI,SAAUmB,CAAM;AAAA,MAC3B,QAAID,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEnB,EAAI,QAASmB,CAAM;AAAA,IAAA;iBAE1B,MAEgB;AAAA,QAFhBC,EAEgBJ,EAAAK,CAAA,GAAA;AAAA,UAFA,IAAItB,EAAA;AAAA,UAAK,SAAOI,EAAA,KAAY;AAAA,QAAA;qBAC1C,MAA0C;AAAA,YAA1CiB,EAA0CJ,EAAAM,CAAA,GAAA,EAA5B,aAAavB,EAAA,eAAW,MAAA,GAAA,CAAA,aAAA,CAAA;AAAA,UAAA;;;QAExCqB,EAQgBJ,EAAAO,CAAA,GAAA,MAAA;AAAA,qBANZ,MAAkC;AAAA,oBADpCC,EAMaC,GAAA,MAAAC,EALMjB,EAAA,OAAgB,CAA1BC,YADTK,EAMaC,EAAAW,CAAA,GAAA;AAAA,cAJV,KAAKjB,EAAO;AAAA,cACZ,OAAOA,EAAO;AAAA,YAAA;yBAEf,MAAkB;AAAA,gBAAfkB,EAAAC,EAAAnB,EAAO,KAAK,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;;"}
1
+ {"version":3,"file":"JCombo.vue.js","sources":["../../../../src/components/atoms/JCombo.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/shadcn'\n\n// 빈 문자열 value를 위한 내부 플레이스홀더\n// reka-ui SelectItem이 빈 문자열을 처리하지 못하는 버그 우회\nconst EMPTY_VALUE_PLACEHOLDER = '__EMPTY_STRING__'\n\nexport interface Option {\n value: string | number\n label: string\n}\n\ntype StyleType =\n | 'default' // 기본 스타일\n | 'error' // 에러 상태\n | 'success' // 성공 상태\n | 'warning' // 경고 상태\n | 'sm' // 작은 크기\n | 'lg' // 큰 크기\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | number\n options?: Option[]\n placeholder?: string\n disabled?: boolean\n required?: boolean\n name?: string\n id?: string\n multiple?: boolean\n class?: string\n /** 스타일 프리셋 */\n styletype?: StyleType\n }>(),\n {\n options: () => [],\n placeholder: '',\n disabled: false,\n required: false,\n multiple: false,\n styletype: 'default',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | number]\n 'change': [value: string | number]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n/**\n * styletype -> class 매핑\n */\nconst STYLE_PRESETS: Record<StyleType, { class: string }> = {\n default: { class: '' },\n error: { \n class: 'border-destructive focus:ring-destructive',\n },\n success: { \n class: 'border-green-500 focus:ring-green-500',\n },\n warning: { \n class: 'border-amber-500 focus:ring-amber-500',\n },\n sm: { \n class: 'h-7 text-xs px-2',\n },\n lg: { \n class: 'h-12 text-base px-4',\n },\n}\n\nconst triggerClass = computed(() => {\n const styleKey = props.styletype || 'default'\n const preset = STYLE_PRESETS[styleKey] ?? STYLE_PRESETS.default\n return [preset?.class, props.class].filter(Boolean).join(' ')\n})\n\n/**\n * 외부 value를 내부 value로 변환\n * 빈 문자열 -> __EMPTY_STRING__\n */\nconst toInternalValue = (value: string | number | undefined): string => {\n if (value === '' || value === undefined) {\n return EMPTY_VALUE_PLACEHOLDER\n }\n return String(value)\n}\n\n/**\n * 내부 value를 외부 value로 변환\n * __EMPTY_STRING__ -> ''\n */\nconst toExternalValue = (value: string): string | number => {\n if (value === EMPTY_VALUE_PLACEHOLDER) {\n return ''\n }\n return value\n}\n\n/**\n * 옵션의 value를 내부 형식으로 변환\n * 빈 문자열 value를 가진 옵션 -> __EMPTY_STRING__으로 변환\n */\nconst processedOptions = computed(() => {\n return props.options.map((option) => ({\n ...option,\n value: toInternalValue(option.value),\n }))\n})\n\n/**\n * 현재 modelValue를 내부 형식으로 변환\n */\nconst internalModelValue = computed(() => toInternalValue(props.modelValue))\n\nconst handleChange = (internalValue: string) => {\n const externalValue = toExternalValue(internalValue)\n emit('update:modelValue', externalValue)\n emit('change', externalValue)\n}\n</script>\n\n<template>\n <Select\n :model-value=\"internalModelValue\"\n :disabled=\"disabled\"\n :required=\"required\"\n :name=\"name\"\n @update:model-value=\"(value) => handleChange(value as string)\"\n @focus=\"emit('focus', $event as FocusEvent)\"\n @blur=\"emit('blur', $event as FocusEvent)\"\n >\n <SelectTrigger :id=\"id\" :class=\"triggerClass\">\n <SelectValue :placeholder=\"placeholder\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem\n v-for=\"option in processedOptions\"\n :key=\"option.value\"\n :value=\"option.value\"\n >\n {{ option.label }}\n </SelectItem>\n </SelectContent>\n </Select>\n</template>\n"],"names":["EMPTY_VALUE_PLACEHOLDER","props","__props","emit","__emit","STYLE_PRESETS","triggerClass","computed","styleKey","toInternalValue","value","toExternalValue","processedOptions","option","internalModelValue","handleChange","internalValue","externalValue","_createBlock","_unref","Select","_cache","$event","_createVNode","SelectTrigger","SelectValue","SelectContent","_createElementBlock","_Fragment","_renderList","SelectItem","_createTextVNode","_toDisplayString"],"mappings":";;;;;;;AAMA,MAAMA,IAA0B;;;;;;;;;;;;;;;;AAehC,UAAMC,IAAQC,GAwBRC,IAAOC,GAUPC,IAAsD;AAAA,MAC1D,SAAS,EAAE,OAAO,GAAA;AAAA,MAClB,OAAO;AAAA,QACL,OAAO;AAAA,MAAA;AAAA,MAET,SAAS;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,MAET,SAAS;AAAA,QACP,OAAO;AAAA,MAAA;AAAA,MAET,IAAI;AAAA,QACF,OAAO;AAAA,MAAA;AAAA,MAET,IAAI;AAAA,QACF,OAAO;AAAA,MAAA;AAAA,IACT,GAGIC,IAAeC,EAAS,MAAM;AAClC,YAAMC,IAAWP,EAAM,aAAa;AAEpC,aAAO,EADQI,EAAcG,CAAQ,KAAKH,EAAc,UACxC,OAAOJ,EAAM,KAAK,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,IAC9D,CAAC,GAMKQ,IAAkB,CAACC,MACnBA,MAAU,MAAMA,MAAU,SACrBV,IAEF,OAAOU,CAAK,GAOfC,IAAkB,CAACD,MACnBA,MAAUV,IACL,KAEFU,GAOHE,IAAmBL,EAAS,MACzBN,EAAM,QAAQ,IAAI,CAACY,OAAY;AAAA,MACpC,GAAGA;AAAA,MACH,OAAOJ,EAAgBI,EAAO,KAAK;AAAA,IAAA,EACnC,CACH,GAKKC,IAAqBP,EAAS,MAAME,EAAgBR,EAAM,UAAU,CAAC,GAErEc,IAAe,CAACC,MAA0B;AAC9C,YAAMC,IAAgBN,EAAgBK,CAAa;AACnD,MAAAb,EAAK,qBAAqBc,CAAa,GACvCd,EAAK,UAAUc,CAAa;AAAA,IAC9B;2BAIEC,EAqBSC,EAAAC,CAAA,GAAA;AAAA,MApBN,eAAaN,EAAA;AAAA,MACb,UAAUZ,EAAA;AAAA,MACV,UAAUA,EAAA;AAAA,MACV,MAAMA,EAAA;AAAA,MACN,uBAAkBmB,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAGX,MAAUK,EAAaL,CAAK;AAAA,MACjD,SAAKW,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEnB,EAAI,SAAUmB,CAAM;AAAA,MAC3B,QAAID,EAAA,CAAA,MAAAA,EAAA,CAAA,IAAA,CAAAC,MAAEnB,EAAI,QAASmB,CAAM;AAAA,IAAA;iBAE1B,MAEgB;AAAA,QAFhBC,EAEgBJ,EAAAK,CAAA,GAAA;AAAA,UAFA,IAAItB,EAAA;AAAA,UAAK,SAAOI,EAAA,KAAY;AAAA,QAAA;qBAC1C,MAA0C;AAAA,YAA1CiB,EAA0CJ,EAAAM,CAAA,GAAA,EAA5B,aAAavB,EAAA,eAAW,MAAA,GAAA,CAAA,aAAA,CAAA;AAAA,UAAA;;;QAExCqB,EAQgBJ,EAAAO,CAAA,GAAA,MAAA;AAAA,qBANZ,MAAkC;AAAA,oBADpCC,EAMaC,GAAA,MAAAC,EALMjB,EAAA,OAAgB,CAA1BC,YADTK,EAMaC,EAAAW,CAAA,GAAA;AAAA,cAJV,KAAKjB,EAAO;AAAA,cACZ,OAAOA,EAAO;AAAA,YAAA;yBAEf,MAAkB;AAAA,gBAAfkB,EAAAC,EAAAnB,EAAO,KAAK,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;;"}
@@ -3,5 +3,5 @@
3
3
  for (const [t_key, t_val] of t_opts)
4
4
  t_merged[t_key] = t_val;
5
5
  return t_merged;
6
- };,u=t(e.default,[["__scopeId","data-v-f2b1f27c"]]);exports.default=u;
6
+ };,u=t(e.default,[["__scopeId","data-v-0b947eae"]]);exports.default=u;
7
7
  //# sourceMappingURL=JEditor.vue.cjs.map
@@ -6,8 +6,8 @@ const t = (t_comp, t_opts) => {
6
6
  t_merged[t_key] = t_val;
7
7
  return t_merged;
8
8
  };
9
- const p = /* @__PURE__ */ t(o, [["__scopeId", "data-v-f2b1f27c"]]);
9
+ const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-0b947eae"]]);
10
10
  export {
11
- p as default
11
+ m as default
12
12
  };
13
13
  //# sourceMappingURL=JEditor.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"JEditor.vue2.cjs","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport { MdEditor } from 'md-editor-v3'\nimport 'md-editor-v3/lib/style.css'\n\nconst props = withDefaults(\n defineProps<{\n /** 마크다운 내용 (v-model) */\n modelValue?: string\n /** 플레이스홀더 텍스트 */\n placeholder?: string\n /** 비활성화 상태 */\n disabled?: boolean\n /** 읽기 전용 상태 */\n readonly?: boolean\n /** 에디터 높이 */\n height?: string | number\n /** 테마 (light/dark) - 설정하지 않으면 자동으로 다크모드 감지 */\n theme?: 'light' | 'dark'\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n modelValue: '',\n placeholder: '마크다운을 입력하세요...',\n disabled: false,\n readonly: false,\n height: '300px',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'change': [value: string]\n 'save': [value: string]\n}>()\n\n// 다크모드 상태\nconst isDarkMode = ref(false)\n\n// 다크모드 감지 함수\nconst detectDarkMode = () => {\n isDarkMode.value = document.documentElement.classList.contains('dark')\n}\n\n// 현재 테마 계산 (props.theme이 있으면 그것 사용, 없으면 자동 감지)\nconst currentTheme = computed(() => {\n if (props.theme) {\n return props.theme\n }\n return isDarkMode.value ? 'dark' : 'light'\n})\n\n// MutationObserver로 다크모드 변경 감지\nlet darkModeObserver: MutationObserver | null = null\n\nonMounted(() => {\n // 초기 다크모드 상태 감지\n detectDarkMode()\n \n // MutationObserver로 class 변경 감지\n darkModeObserver = new MutationObserver(() => {\n detectDarkMode()\n })\n \n darkModeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n })\n})\n\nonUnmounted(() => {\n if (darkModeObserver) {\n darkModeObserver.disconnect()\n }\n})\n\nconst handleChange = (value: string) => {\n emit('update:modelValue', value)\n emit('change', value)\n}\n\nconst handleSave = (value: string) => {\n emit('save', value)\n}\n</script>\n\n<template>\n <div :class=\"['j-editor-wrapper', props.class]\">\n <MdEditor\n :model-value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :read-only=\"readonly\"\n :editor-class-name=\"'j-editor'\"\n :preview-class-name=\"'j-editor-preview'\"\n :style=\"{ height: typeof height === 'number' ? `${height}px` : height }\"\n :theme=\"currentTheme\"\n language=\"en-US\"\n @update:model-value=\"handleChange\"\n @on-save=\"handleSave\"\n />\n </div>\n</template>\n\n<style scoped>\n.j-editor-wrapper {\n @apply w-full;\n}\n</style>\n"],"names":["props","__props","emit","__emit","isDarkMode","ref","detectDarkMode","currentTheme","computed","darkModeObserver","onMounted","onUnmounted","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor","_normalizeStyle"],"mappings":"+jBAKA,MAAMA,EAAQC,EA0BRC,EAAOC,EAOPC,EAAaC,EAAAA,IAAI,EAAK,EAGtBC,EAAiB,IAAM,CAC3BF,EAAW,MAAQ,SAAS,gBAAgB,UAAU,SAAS,MAAM,CACvE,EAGMG,EAAeC,EAAAA,SAAS,IACxBR,EAAM,MACDA,EAAM,MAERI,EAAW,MAAQ,OAAS,OACpC,EAGD,IAAIK,EAA4C,KAEhDC,EAAAA,UAAU,IAAM,CAEdJ,EAAA,EAGAG,EAAmB,IAAI,iBAAiB,IAAM,CAC5CH,EAAA,CACF,CAAC,EAEDG,EAAiB,QAAQ,SAAS,gBAAiB,CACjD,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAAA,CAC1B,CACH,CAAC,EAEDE,EAAAA,YAAY,IAAM,CACZF,GACFA,EAAiB,WAAA,CAErB,CAAC,EAED,MAAMG,EAAgBC,GAAkB,CACtCX,EAAK,oBAAqBW,CAAK,EAC/BX,EAAK,SAAUW,CAAK,CACtB,EAEMC,EAAcD,GAAkB,CACpCX,EAAK,OAAQW,CAAK,CACpB,8BAIEE,EAAAA,mBAcM,MAAA,CAdA,MAAKC,EAAAA,eAAA,CAAA,mBAAuBhB,EAAM,KAAK,CAAA,CAAA,GAC3CiB,cAYEC,EAAAA,MAAAC,EAAAA,QAAA,EAAA,CAXC,cAAalB,EAAA,WACb,YAAaA,EAAA,YACb,SAAUA,EAAA,SACV,YAAWA,EAAA,SACX,oBAAmB,WACnB,qBAAoB,mBACpB,MAAKmB,EAAAA,eAAA,CAAA,OAAA,OAAmBnB,EAAA,QAAM,SAAA,GAAmBA,EAAA,MAAM,KAAOA,EAAA,OAAM,EACpE,MAAOM,EAAA,MACR,SAAS,QACR,sBAAoBK,EACpB,SAASE,CAAA"}
1
+ {"version":3,"file":"JEditor.vue2.cjs","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport { MdEditor } from 'md-editor-v3'\nimport 'md-editor-v3/lib/style.css'\n\nconst props = withDefaults(\n defineProps<{\n /** 마크다운 내용 (v-model) */\n modelValue?: string\n /** 플레이스홀더 텍스트 */\n placeholder?: string\n /** 비활성화 상태 */\n disabled?: boolean\n /** 읽기 전용 상태 */\n readonly?: boolean\n /** 에디터 높이 */\n height?: string | number\n /** 테마 (light/dark) - 설정하지 않으면 자동으로 다크모드 감지 */\n theme?: 'light' | 'dark'\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n modelValue: '',\n placeholder: '마크다운을 입력하세요...',\n disabled: false,\n readonly: false,\n height: '300px',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'change': [value: string]\n 'save': [value: string]\n}>()\n\n// 다크모드 상태\nconst isDarkMode = ref(false)\n\n// 다크모드 감지 함수\nconst detectDarkMode = () => {\n isDarkMode.value = document.documentElement.classList.contains('dark')\n}\n\n// 현재 테마 계산 (props.theme이 있으면 그것 사용, 없으면 자동 감지)\nconst currentTheme = computed(() => {\n if (props.theme) {\n return props.theme\n }\n return isDarkMode.value ? 'dark' : 'light'\n})\n\n// MutationObserver로 다크모드 변경 감지\nlet darkModeObserver: MutationObserver | null = null\n\nonMounted(() => {\n // 초기 다크모드 상태 감지\n detectDarkMode()\n \n // MutationObserver로 class 변경 감지\n darkModeObserver = new MutationObserver(() => {\n detectDarkMode()\n })\n \n darkModeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n })\n})\n\nonUnmounted(() => {\n if (darkModeObserver) {\n darkModeObserver.disconnect()\n }\n})\n\nconst handleChange = (value: string) => {\n emit('update:modelValue', value)\n emit('change', value)\n}\n\nconst handleSave = (value: string) => {\n emit('save', value)\n}\n</script>\n\n<template>\n <div :class=\"['j-editor-wrapper', props.class]\">\n <MdEditor\n :model-value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :read-only=\"readonly\"\n :editor-class-name=\"'j-editor'\"\n :preview-class-name=\"'j-editor-preview'\"\n :style=\"{ height: typeof height === 'number' ? `${height}px` : height }\"\n :theme=\"currentTheme\"\n language=\"en-US\"\n @update:model-value=\"handleChange\"\n @on-save=\"handleSave\"\n />\n </div>\n</template>\n\n<style scoped>\n.j-editor-wrapper {\n @apply w-full h-full;\n}\n</style>\n"],"names":["props","__props","emit","__emit","isDarkMode","ref","detectDarkMode","currentTheme","computed","darkModeObserver","onMounted","onUnmounted","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor","_normalizeStyle"],"mappings":"+jBAKA,MAAMA,EAAQC,EA0BRC,EAAOC,EAOPC,EAAaC,EAAAA,IAAI,EAAK,EAGtBC,EAAiB,IAAM,CAC3BF,EAAW,MAAQ,SAAS,gBAAgB,UAAU,SAAS,MAAM,CACvE,EAGMG,EAAeC,EAAAA,SAAS,IACxBR,EAAM,MACDA,EAAM,MAERI,EAAW,MAAQ,OAAS,OACpC,EAGD,IAAIK,EAA4C,KAEhDC,EAAAA,UAAU,IAAM,CAEdJ,EAAA,EAGAG,EAAmB,IAAI,iBAAiB,IAAM,CAC5CH,EAAA,CACF,CAAC,EAEDG,EAAiB,QAAQ,SAAS,gBAAiB,CACjD,WAAY,GACZ,gBAAiB,CAAC,OAAO,CAAA,CAC1B,CACH,CAAC,EAEDE,EAAAA,YAAY,IAAM,CACZF,GACFA,EAAiB,WAAA,CAErB,CAAC,EAED,MAAMG,EAAgBC,GAAkB,CACtCX,EAAK,oBAAqBW,CAAK,EAC/BX,EAAK,SAAUW,CAAK,CACtB,EAEMC,EAAcD,GAAkB,CACpCX,EAAK,OAAQW,CAAK,CACpB,8BAIEE,EAAAA,mBAcM,MAAA,CAdA,MAAKC,EAAAA,eAAA,CAAA,mBAAuBhB,EAAM,KAAK,CAAA,CAAA,GAC3CiB,cAYEC,EAAAA,MAAAC,EAAAA,QAAA,EAAA,CAXC,cAAalB,EAAA,WACb,YAAaA,EAAA,YACb,SAAUA,EAAA,SACV,YAAWA,EAAA,SACX,oBAAmB,WACnB,qBAAoB,mBACpB,MAAKmB,EAAAA,eAAA,CAAA,OAAA,OAAmBnB,EAAA,QAAM,SAAA,GAAmBA,EAAA,MAAM,KAAOA,EAAA,OAAM,EACpE,MAAOM,EAAA,MACR,SAAS,QACR,sBAAoBK,EACpB,SAASE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"JEditor.vue2.js","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport { MdEditor } from 'md-editor-v3'\nimport 'md-editor-v3/lib/style.css'\n\nconst props = withDefaults(\n defineProps<{\n /** 마크다운 내용 (v-model) */\n modelValue?: string\n /** 플레이스홀더 텍스트 */\n placeholder?: string\n /** 비활성화 상태 */\n disabled?: boolean\n /** 읽기 전용 상태 */\n readonly?: boolean\n /** 에디터 높이 */\n height?: string | number\n /** 테마 (light/dark) - 설정하지 않으면 자동으로 다크모드 감지 */\n theme?: 'light' | 'dark'\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n modelValue: '',\n placeholder: '마크다운을 입력하세요...',\n disabled: false,\n readonly: false,\n height: '300px',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'change': [value: string]\n 'save': [value: string]\n}>()\n\n// 다크모드 상태\nconst isDarkMode = ref(false)\n\n// 다크모드 감지 함수\nconst detectDarkMode = () => {\n isDarkMode.value = document.documentElement.classList.contains('dark')\n}\n\n// 현재 테마 계산 (props.theme이 있으면 그것 사용, 없으면 자동 감지)\nconst currentTheme = computed(() => {\n if (props.theme) {\n return props.theme\n }\n return isDarkMode.value ? 'dark' : 'light'\n})\n\n// MutationObserver로 다크모드 변경 감지\nlet darkModeObserver: MutationObserver | null = null\n\nonMounted(() => {\n // 초기 다크모드 상태 감지\n detectDarkMode()\n \n // MutationObserver로 class 변경 감지\n darkModeObserver = new MutationObserver(() => {\n detectDarkMode()\n })\n \n darkModeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n })\n})\n\nonUnmounted(() => {\n if (darkModeObserver) {\n darkModeObserver.disconnect()\n }\n})\n\nconst handleChange = (value: string) => {\n emit('update:modelValue', value)\n emit('change', value)\n}\n\nconst handleSave = (value: string) => {\n emit('save', value)\n}\n</script>\n\n<template>\n <div :class=\"['j-editor-wrapper', props.class]\">\n <MdEditor\n :model-value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :read-only=\"readonly\"\n :editor-class-name=\"'j-editor'\"\n :preview-class-name=\"'j-editor-preview'\"\n :style=\"{ height: typeof height === 'number' ? `${height}px` : height }\"\n :theme=\"currentTheme\"\n language=\"en-US\"\n @update:model-value=\"handleChange\"\n @on-save=\"handleSave\"\n />\n </div>\n</template>\n\n<style scoped>\n.j-editor-wrapper {\n @apply w-full;\n}\n</style>\n"],"names":["props","__props","emit","__emit","isDarkMode","ref","detectDarkMode","currentTheme","computed","darkModeObserver","onMounted","onUnmounted","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor","_normalizeStyle"],"mappings":";;;;;;;;;;;;;;;;AAKA,UAAMA,IAAQC,GA0BRC,IAAOC,GAOPC,IAAaC,EAAI,EAAK,GAGtBC,IAAiB,MAAM;AAC3B,MAAAF,EAAW,QAAQ,SAAS,gBAAgB,UAAU,SAAS,MAAM;AAAA,IACvE,GAGMG,IAAeC,EAAS,MACxBR,EAAM,QACDA,EAAM,QAERI,EAAW,QAAQ,SAAS,OACpC;AAGD,QAAIK,IAA4C;AAEhD,IAAAC,EAAU,MAAM;AAEd,MAAAJ,EAAA,GAGAG,IAAmB,IAAI,iBAAiB,MAAM;AAC5C,QAAAH,EAAA;AAAA,MACF,CAAC,GAEDG,EAAiB,QAAQ,SAAS,iBAAiB;AAAA,QACjD,YAAY;AAAA,QACZ,iBAAiB,CAAC,OAAO;AAAA,MAAA,CAC1B;AAAA,IACH,CAAC,GAEDE,EAAY,MAAM;AAChB,MAAIF,KACFA,EAAiB,WAAA;AAAA,IAErB,CAAC;AAED,UAAMG,IAAe,CAACC,MAAkB;AACtC,MAAAX,EAAK,qBAAqBW,CAAK,GAC/BX,EAAK,UAAUW,CAAK;AAAA,IACtB,GAEMC,IAAa,CAACD,MAAkB;AACpC,MAAAX,EAAK,QAAQW,CAAK;AAAA,IACpB;2BAIEE,EAcM,OAAA;AAAA,MAdA,OAAKC,EAAA,CAAA,oBAAuBhB,EAAM,KAAK,CAAA;AAAA,IAAA;MAC3CiB,EAYEC,EAAAC,CAAA,GAAA;AAAA,QAXC,eAAalB,EAAA;AAAA,QACb,aAAaA,EAAA;AAAA,QACb,UAAUA,EAAA;AAAA,QACV,aAAWA,EAAA;AAAA,QACX,qBAAmB;AAAA,QACnB,sBAAoB;AAAA,QACpB,OAAKmB,EAAA,EAAA,QAAA,OAAmBnB,EAAA,UAAM,WAAA,GAAmBA,EAAA,MAAM,OAAOA,EAAA,QAAM;AAAA,QACpE,OAAOM,EAAA;AAAA,QACR,UAAS;AAAA,QACR,uBAAoBK;AAAA,QACpB,UAASE;AAAA,MAAA;;;;"}
1
+ {"version":3,"file":"JEditor.vue2.js","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, onMounted, onUnmounted } from 'vue'\nimport { MdEditor } from 'md-editor-v3'\nimport 'md-editor-v3/lib/style.css'\n\nconst props = withDefaults(\n defineProps<{\n /** 마크다운 내용 (v-model) */\n modelValue?: string\n /** 플레이스홀더 텍스트 */\n placeholder?: string\n /** 비활성화 상태 */\n disabled?: boolean\n /** 읽기 전용 상태 */\n readonly?: boolean\n /** 에디터 높이 */\n height?: string | number\n /** 테마 (light/dark) - 설정하지 않으면 자동으로 다크모드 감지 */\n theme?: 'light' | 'dark'\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n modelValue: '',\n placeholder: '마크다운을 입력하세요...',\n disabled: false,\n readonly: false,\n height: '300px',\n },\n)\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n 'change': [value: string]\n 'save': [value: string]\n}>()\n\n// 다크모드 상태\nconst isDarkMode = ref(false)\n\n// 다크모드 감지 함수\nconst detectDarkMode = () => {\n isDarkMode.value = document.documentElement.classList.contains('dark')\n}\n\n// 현재 테마 계산 (props.theme이 있으면 그것 사용, 없으면 자동 감지)\nconst currentTheme = computed(() => {\n if (props.theme) {\n return props.theme\n }\n return isDarkMode.value ? 'dark' : 'light'\n})\n\n// MutationObserver로 다크모드 변경 감지\nlet darkModeObserver: MutationObserver | null = null\n\nonMounted(() => {\n // 초기 다크모드 상태 감지\n detectDarkMode()\n \n // MutationObserver로 class 변경 감지\n darkModeObserver = new MutationObserver(() => {\n detectDarkMode()\n })\n \n darkModeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n })\n})\n\nonUnmounted(() => {\n if (darkModeObserver) {\n darkModeObserver.disconnect()\n }\n})\n\nconst handleChange = (value: string) => {\n emit('update:modelValue', value)\n emit('change', value)\n}\n\nconst handleSave = (value: string) => {\n emit('save', value)\n}\n</script>\n\n<template>\n <div :class=\"['j-editor-wrapper', props.class]\">\n <MdEditor\n :model-value=\"modelValue\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :read-only=\"readonly\"\n :editor-class-name=\"'j-editor'\"\n :preview-class-name=\"'j-editor-preview'\"\n :style=\"{ height: typeof height === 'number' ? `${height}px` : height }\"\n :theme=\"currentTheme\"\n language=\"en-US\"\n @update:model-value=\"handleChange\"\n @on-save=\"handleSave\"\n />\n </div>\n</template>\n\n<style scoped>\n.j-editor-wrapper {\n @apply w-full h-full;\n}\n</style>\n"],"names":["props","__props","emit","__emit","isDarkMode","ref","detectDarkMode","currentTheme","computed","darkModeObserver","onMounted","onUnmounted","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor","_normalizeStyle"],"mappings":";;;;;;;;;;;;;;;;AAKA,UAAMA,IAAQC,GA0BRC,IAAOC,GAOPC,IAAaC,EAAI,EAAK,GAGtBC,IAAiB,MAAM;AAC3B,MAAAF,EAAW,QAAQ,SAAS,gBAAgB,UAAU,SAAS,MAAM;AAAA,IACvE,GAGMG,IAAeC,EAAS,MACxBR,EAAM,QACDA,EAAM,QAERI,EAAW,QAAQ,SAAS,OACpC;AAGD,QAAIK,IAA4C;AAEhD,IAAAC,EAAU,MAAM;AAEd,MAAAJ,EAAA,GAGAG,IAAmB,IAAI,iBAAiB,MAAM;AAC5C,QAAAH,EAAA;AAAA,MACF,CAAC,GAEDG,EAAiB,QAAQ,SAAS,iBAAiB;AAAA,QACjD,YAAY;AAAA,QACZ,iBAAiB,CAAC,OAAO;AAAA,MAAA,CAC1B;AAAA,IACH,CAAC,GAEDE,EAAY,MAAM;AAChB,MAAIF,KACFA,EAAiB,WAAA;AAAA,IAErB,CAAC;AAED,UAAMG,IAAe,CAACC,MAAkB;AACtC,MAAAX,EAAK,qBAAqBW,CAAK,GAC/BX,EAAK,UAAUW,CAAK;AAAA,IACtB,GAEMC,IAAa,CAACD,MAAkB;AACpC,MAAAX,EAAK,QAAQW,CAAK;AAAA,IACpB;2BAIEE,EAcM,OAAA;AAAA,MAdA,OAAKC,EAAA,CAAA,oBAAuBhB,EAAM,KAAK,CAAA;AAAA,IAAA;MAC3CiB,EAYEC,EAAAC,CAAA,GAAA;AAAA,QAXC,eAAalB,EAAA;AAAA,QACb,aAAaA,EAAA;AAAA,QACb,UAAUA,EAAA;AAAA,QACV,aAAWA,EAAA;AAAA,QACX,qBAAmB;AAAA,QACnB,sBAAoB;AAAA,QACpB,OAAKmB,EAAA,EAAA,QAAA,OAAmBnB,EAAA,UAAM,WAAA,GAAmBA,EAAA,MAAM,OAAOA,EAAA,QAAM;AAAA,QACpE,OAAOM,EAAA;AAAA,QACR,UAAS;AAAA,QACR,uBAAoBK;AAAA,QACpB,UAASE;AAAA,MAAA;;;;"}
@@ -3,5 +3,5 @@
3
3
  for (const [t_key, t_val] of t_opts)
4
4
  t_merged[t_key] = t_val;
5
5
  return t_merged;
6
- };,u=t(e.default,[["__scopeId","data-v-25c4d908"]]);exports.default=u;
6
+ };,u=t(e.default,[["__scopeId","data-v-393b9055"]]);exports.default=u;
7
7
  //# sourceMappingURL=JSplitter.vue.cjs.map
@@ -6,7 +6,7 @@ const o = (o_comp, o_opts) => {
6
6
  o_merged[o_key] = o_val;
7
7
  return o_merged;
8
8
  };
9
- const _ = /* @__PURE__ */ o(t, [["__scopeId", "data-v-25c4d908"]]);
9
+ const _ = /* @__PURE__ */ o(t, [["__scopeId", "data-v-393b9055"]]);
10
10
  export {
11
11
  _ as default
12
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"JSplitter.vue2.cjs","sources":["../../../../src/components/atoms/JSplitter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { cn } from '@/lib/utils'\nimport {\n ResizablePanelGroup,\n ResizablePanel,\n ResizableHandle,\n} from '@/components/shadcn/resizable'\n\ntype Orientation = 'horizontal' | 'vertical'\n\nconst props = withDefaults(\n defineProps<{\n /** 분할 방향 (horizontal: 좌우, vertical: 상하) */\n direction?: Orientation\n /** 첫 번째 패널의 기본 크기 (%) */\n defaultSize?: number\n /** 첫 번째 패널의 최소 크기 (%) */\n minSize?: number\n /** 첫 번째 패널의 최대 크기 (%) */\n maxSize?: number\n /** 두 번째 패널의 최소 크기 (%) */\n secondMinSize?: number\n /** 두 번째 패널의 최대 크기 (%) */\n secondMaxSize?: number\n /** ResizableHandle에 grip 아이콘 표시 여부 */\n withHandle?: boolean\n /** 패널 간 여백 (px) */\n gap?: number\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n direction: 'horizontal',\n defaultSize: 40,\n minSize: 20,\n withHandle: false,\n gap: 2,\n },\n)\n\n// 두 번째 패널의 기본 크기 계산\nconst secondDefaultSize = computed(() => 100 - props.defaultSize)\n</script>\n\n<template>\n <ResizablePanelGroup :direction=\"direction\" :class=\"cn('jsplitter-group min-h-0 min-w-0', $props.class)\">\n <!-- 첫 번째 패널 (좌측/상단) -->\n <ResizablePanel \n :default-size=\"defaultSize\" \n :min-size=\"minSize\" \n :max-size=\"maxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pr-[calc(var(--gap)/2)]' : 'pb-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"first\" />\n <!-- direction=\"horizontal\"일 때 left, vertical일 때 top으로도 사용 가능 -->\n <slot name=\"left\" />\n <slot name=\"top\" />\n </ResizablePanel>\n\n <!-- 크기 조정 핸들 -->\n <ResizableHandle :with-handle=\"withHandle\" class=\"jsplitter-handle\" />\n\n <!-- 두 번째 패널 (우측/하단) -->\n <ResizablePanel\n :default-size=\"secondDefaultSize\"\n :min-size=\"secondMinSize\"\n :max-size=\"secondMaxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pl-[calc(var(--gap)/2)]' : 'pt-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"second\" />\n <!-- direction=\"horizontal\"일 때 right, vertical일 때 bottom으로도 사용 가능 -->\n <slot name=\"right\" />\n <slot name=\"bottom\" />\n </ResizablePanel>\n </ResizablePanelGroup>\n</template>\n\n<style scoped>\n/* ── overflow 보호 ──────────────────────────────────────────────────── */\n:deep(.jsplitter-group [data-panel]) {\n min-width: 0;\n min-height: 0;\n}\n\n/* ── horizontal 핸들: 8px 히트영역 ─────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"horizontal\"]) {\n width: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── vertical 핸들: 8px 히트영역 ───────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]) {\n height: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── 시각선: 1px (after:w-1 override) ──────────────────────────────── */\n:deep(.jsplitter-handle::after) {\n width: 1px !important;\n background: hsl(var(--border)) !important;\n transition: background 0.15s ease, width 0.12s ease !important;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::after) {\n height: 1px !important;\n width: 100% !important;\n}\n\n/* ── 그립 도트 인디케이터 (::before) ───────────────────────────────── */\n:deep(.jsplitter-handle::before) {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 20px;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n background-size: 3px 6px;\n background-repeat: repeat-y;\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.15s ease;\n pointer-events: none;\n z-index: 4;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::before) {\n width: 20px;\n height: 3px;\n background-size: 6px 3px;\n background-repeat: repeat-x;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n}\n\n/* ── hover ──────────────────────────────────────────────────────────── */\n:deep(.jsplitter-handle:hover) {\n background: hsl(var(--primary) / 0.04) !important;\n}\n\n:deep(.jsplitter-handle:hover::after) {\n width: 2px !important;\n background: hsl(var(--primary) / 0.55) !important;\n}\n\n:deep(.jsplitter-handle:hover::before) {\n opacity: 1;\n}\n\n/* ── drag / active ──────────────────────────────────────────────────── */\n:deep(.jsplitter-handle[data-state=\"drag\"]),\n:deep(.jsplitter-handle:active) {\n background: hsl(var(--primary) / 0.06) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::after),\n:deep(.jsplitter-handle:active::after) {\n width: 2px !important;\n background: hsl(var(--primary)) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::before),\n:deep(.jsplitter-handle:active::before) {\n opacity: 1;\n background-image: radial-gradient(circle, hsl(var(--primary) / 0.65) 1px, transparent 1px);\n}\n</style>\n"],"names":["props","__props","secondDefaultSize","computed","_createBlock","_unref","ResizablePanelGroup","_normalizeClass","cn","$props","_createVNode","ResizablePanel","_normalizeStyle","_renderSlot","_ctx","ResizableHandle"],"mappings":"kiBAWA,MAAMA,EAAQC,EA+BRC,EAAoBC,EAAAA,SAAS,IAAM,IAAMH,EAAM,WAAW,8BAI9DI,EAAAA,YA+BsBC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CA/BA,UAAWL,EAAA,UAAY,MAAKM,EAAAA,eAAEF,EAAAA,MAAAG,EAAAA,EAAA,EAAE,kCAAoCC,EAAAA,OAAO,KAAK,CAAA,CAAA,qBAEpG,IAWiB,CAXjBC,cAWiBL,EAAAA,MAAAM,EAAAA,aAAA,EAAA,CAVd,eAAcV,EAAA,YACd,WAAUA,EAAA,QACV,WAAUA,EAAA,QACV,MAAKM,EAAAA,eAAEN,EAAA,IAAG,EAAQA,EAAA,YAAS,aAAA,0BAAA,0BAAA,EAAA,EAC3B,MAAKW,EAAAA,eAAEX,EAAA,IAAG,EAAA,CAAA,QAAA,GAAqBA,EAAA,GAAG,IAAA,EAAA,CAAA,CAAA,CAAA,qBAEnC,IAAqB,CAArBY,EAAAA,WAAqBC,EAAA,OAAA,QAAA,CAAA,EAAA,OAAA,EAAA,EAErBD,EAAAA,WAAoBC,EAAA,OAAA,OAAA,CAAA,EAAA,OAAA,EAAA,EACpBD,EAAAA,WAAmBC,EAAA,OAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,kEAIrBJ,cAAsEL,EAAAA,MAAAU,EAAAA,OAAA,EAAA,CAApD,cAAad,EAAA,WAAY,MAAM,kBAAA,0BAGjDS,cAWiBL,EAAAA,MAAAM,EAAAA,aAAA,EAAA,CAVd,eAAcT,EAAA,MACd,WAAUD,EAAA,cACV,WAAUA,EAAA,cACV,MAAKM,EAAAA,eAAEN,EAAA,IAAG,EAAQA,EAAA,YAAS,aAAA,0BAAA,0BAAA,EAAA,EAC3B,MAAKW,EAAAA,eAAEX,EAAA,IAAG,EAAA,CAAA,QAAA,GAAqBA,EAAA,GAAG,IAAA,EAAA,CAAA,CAAA,CAAA,qBAEnC,IAAsB,CAAtBY,EAAAA,WAAsBC,EAAA,OAAA,SAAA,CAAA,EAAA,OAAA,EAAA,EAEtBD,EAAAA,WAAqBC,EAAA,OAAA,QAAA,CAAA,EAAA,OAAA,EAAA,EACrBD,EAAAA,WAAsBC,EAAA,OAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA"}
1
+ {"version":3,"file":"JSplitter.vue2.cjs","sources":["../../../../src/components/atoms/JSplitter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { cn } from '@/lib/utils'\nimport {\n ResizablePanelGroup,\n ResizablePanel,\n ResizableHandle,\n} from '@/components/shadcn/resizable'\n\ntype Orientation = 'horizontal' | 'vertical'\n\nconst props = withDefaults(\n defineProps<{\n /** 분할 방향 (horizontal: 좌우, vertical: 상하) */\n direction?: Orientation\n /** 첫 번째 패널의 기본 크기 (%) */\n defaultSize?: number\n /** 첫 번째 패널의 최소 크기 (%) */\n minSize?: number\n /** 첫 번째 패널의 최대 크기 (%) */\n maxSize?: number\n /** 두 번째 패널의 최소 크기 (%) */\n secondMinSize?: number\n /** 두 번째 패널의 최대 크기 (%) */\n secondMaxSize?: number\n /** ResizableHandle에 grip 아이콘 표시 여부 */\n withHandle?: boolean\n /** 패널 간 여백 (px) */\n gap?: number\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n direction: 'horizontal',\n defaultSize: 40,\n minSize: 20,\n withHandle: false,\n gap: 2,\n },\n)\n\n// 두 번째 패널의 기본 크기 계산\nconst secondDefaultSize = computed(() => 100 - props.defaultSize)\n</script>\n\n<template>\n <ResizablePanelGroup :direction=\"direction\" :class=\"cn('jsplitter-group min-h-0 min-w-0', $props.class)\">\n <!-- 첫 번째 패널 (좌측/상단) -->\n <ResizablePanel \n :default-size=\"defaultSize\" \n :min-size=\"minSize\" \n :max-size=\"maxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pr-[calc(var(--gap)/2)]' : 'pb-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"first\" />\n <!-- direction=\"horizontal\"일 때 left, vertical일 때 top으로도 사용 가능 -->\n <slot name=\"left\" />\n <slot name=\"top\" />\n </ResizablePanel>\n\n <!-- 크기 조정 핸들 -->\n <ResizableHandle :with-handle=\"withHandle\" class=\"jsplitter-handle\" />\n\n <!-- 두 번째 패널 (우측/하단) -->\n <ResizablePanel\n :default-size=\"secondDefaultSize\"\n :min-size=\"secondMinSize\"\n :max-size=\"secondMaxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pl-[calc(var(--gap)/2)]' : 'pt-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"second\" />\n <!-- direction=\"horizontal\"일 때 right, vertical일 때 bottom으로도 사용 가능 -->\n <slot name=\"right\" />\n <slot name=\"bottom\" />\n </ResizablePanel>\n </ResizablePanelGroup>\n</template>\n\n<style scoped>\n/* ── overflow 보호 ──────────────────────────────────────────────────── */\n:deep(.jsplitter-group [data-panel]) {\n min-width: 0;\n min-height: 0;\n}\n\n/* ── horizontal 핸들: 8px 히트영역 ─────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"horizontal\"]) {\n width: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── vertical 핸들: 8px 히트영역 ───────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]) {\n height: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── 시각선: 1px (after:w-1 override) ──────────────────────────────── */\n:deep(.jsplitter-handle::after) {\n width: 1px !important;\n background: hsl(var(--border)) !important;\n transition: background 0.15s ease, width 0.12s ease !important;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::after) {\n height: 1px !important;\n width: 100% !important;\n}\n\n/* ── 그립 도트 인디케이터 (::before) ───────────────────────────────── */\n:deep(.jsplitter-handle::before) {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 20px;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n background-size: 3px 6px;\n background-repeat: repeat-y;\n border-radius: 2px;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n pointer-events: none;\n z-index: 4;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::before) {\n width: 20px;\n height: 3px;\n background-size: 6px 3px;\n background-repeat: repeat-x;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n}\n\n/* ── hover ──────────────────────────────────────────────────────────── */\n:deep(.jsplitter-handle:hover) {\n background: hsl(var(--primary) / 0.04) !important;\n}\n\n:deep(.jsplitter-handle:hover::after) {\n width: 2px !important;\n background: hsl(var(--primary) / 0.55) !important;\n}\n\n:deep(.jsplitter-handle:hover::before) {\n opacity: 1;\n}\n\n/* ── drag / active ──────────────────────────────────────────────────── */\n:deep(.jsplitter-handle[data-state=\"drag\"]),\n:deep(.jsplitter-handle:active) {\n background: hsl(var(--primary) / 0.06) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::after),\n:deep(.jsplitter-handle:active::after) {\n width: 2px !important;\n background: hsl(var(--primary)) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::before),\n:deep(.jsplitter-handle:active::before) {\n opacity: 1;\n background-image: radial-gradient(circle, hsl(var(--primary) / 0.65) 1px, transparent 1px);\n}\n</style>\n"],"names":["props","__props","secondDefaultSize","computed","_createBlock","_unref","ResizablePanelGroup","_normalizeClass","cn","$props","_createVNode","ResizablePanel","_normalizeStyle","_renderSlot","_ctx","ResizableHandle"],"mappings":"kiBAWA,MAAMA,EAAQC,EA+BRC,EAAoBC,EAAAA,SAAS,IAAM,IAAMH,EAAM,WAAW,8BAI9DI,EAAAA,YA+BsBC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CA/BA,UAAWL,EAAA,UAAY,MAAKM,EAAAA,eAAEF,EAAAA,MAAAG,EAAAA,EAAA,EAAE,kCAAoCC,EAAAA,OAAO,KAAK,CAAA,CAAA,qBAEpG,IAWiB,CAXjBC,cAWiBL,EAAAA,MAAAM,EAAAA,aAAA,EAAA,CAVd,eAAcV,EAAA,YACd,WAAUA,EAAA,QACV,WAAUA,EAAA,QACV,MAAKM,EAAAA,eAAEN,EAAA,IAAG,EAAQA,EAAA,YAAS,aAAA,0BAAA,0BAAA,EAAA,EAC3B,MAAKW,EAAAA,eAAEX,EAAA,IAAG,EAAA,CAAA,QAAA,GAAqBA,EAAA,GAAG,IAAA,EAAA,CAAA,CAAA,CAAA,qBAEnC,IAAqB,CAArBY,EAAAA,WAAqBC,EAAA,OAAA,QAAA,CAAA,EAAA,OAAA,EAAA,EAErBD,EAAAA,WAAoBC,EAAA,OAAA,OAAA,CAAA,EAAA,OAAA,EAAA,EACpBD,EAAAA,WAAmBC,EAAA,OAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,kEAIrBJ,cAAsEL,EAAAA,MAAAU,EAAAA,OAAA,EAAA,CAApD,cAAad,EAAA,WAAY,MAAM,kBAAA,0BAGjDS,cAWiBL,EAAAA,MAAAM,EAAAA,aAAA,EAAA,CAVd,eAAcT,EAAA,MACd,WAAUD,EAAA,cACV,WAAUA,EAAA,cACV,MAAKM,EAAAA,eAAEN,EAAA,IAAG,EAAQA,EAAA,YAAS,aAAA,0BAAA,0BAAA,EAAA,EAC3B,MAAKW,EAAAA,eAAEX,EAAA,IAAG,EAAA,CAAA,QAAA,GAAqBA,EAAA,GAAG,IAAA,EAAA,CAAA,CAAA,CAAA,qBAEnC,IAAsB,CAAtBY,EAAAA,WAAsBC,EAAA,OAAA,SAAA,CAAA,EAAA,OAAA,EAAA,EAEtBD,EAAAA,WAAqBC,EAAA,OAAA,QAAA,CAAA,EAAA,OAAA,EAAA,EACrBD,EAAAA,WAAsBC,EAAA,OAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"JSplitter.vue2.js","sources":["../../../../src/components/atoms/JSplitter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { cn } from '@/lib/utils'\nimport {\n ResizablePanelGroup,\n ResizablePanel,\n ResizableHandle,\n} from '@/components/shadcn/resizable'\n\ntype Orientation = 'horizontal' | 'vertical'\n\nconst props = withDefaults(\n defineProps<{\n /** 분할 방향 (horizontal: 좌우, vertical: 상하) */\n direction?: Orientation\n /** 첫 번째 패널의 기본 크기 (%) */\n defaultSize?: number\n /** 첫 번째 패널의 최소 크기 (%) */\n minSize?: number\n /** 첫 번째 패널의 최대 크기 (%) */\n maxSize?: number\n /** 두 번째 패널의 최소 크기 (%) */\n secondMinSize?: number\n /** 두 번째 패널의 최대 크기 (%) */\n secondMaxSize?: number\n /** ResizableHandle에 grip 아이콘 표시 여부 */\n withHandle?: boolean\n /** 패널 간 여백 (px) */\n gap?: number\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n direction: 'horizontal',\n defaultSize: 40,\n minSize: 20,\n withHandle: false,\n gap: 2,\n },\n)\n\n// 두 번째 패널의 기본 크기 계산\nconst secondDefaultSize = computed(() => 100 - props.defaultSize)\n</script>\n\n<template>\n <ResizablePanelGroup :direction=\"direction\" :class=\"cn('jsplitter-group min-h-0 min-w-0', $props.class)\">\n <!-- 첫 번째 패널 (좌측/상단) -->\n <ResizablePanel \n :default-size=\"defaultSize\" \n :min-size=\"minSize\" \n :max-size=\"maxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pr-[calc(var(--gap)/2)]' : 'pb-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"first\" />\n <!-- direction=\"horizontal\"일 때 left, vertical일 때 top으로도 사용 가능 -->\n <slot name=\"left\" />\n <slot name=\"top\" />\n </ResizablePanel>\n\n <!-- 크기 조정 핸들 -->\n <ResizableHandle :with-handle=\"withHandle\" class=\"jsplitter-handle\" />\n\n <!-- 두 번째 패널 (우측/하단) -->\n <ResizablePanel\n :default-size=\"secondDefaultSize\"\n :min-size=\"secondMinSize\"\n :max-size=\"secondMaxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pl-[calc(var(--gap)/2)]' : 'pt-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"second\" />\n <!-- direction=\"horizontal\"일 때 right, vertical일 때 bottom으로도 사용 가능 -->\n <slot name=\"right\" />\n <slot name=\"bottom\" />\n </ResizablePanel>\n </ResizablePanelGroup>\n</template>\n\n<style scoped>\n/* ── overflow 보호 ──────────────────────────────────────────────────── */\n:deep(.jsplitter-group [data-panel]) {\n min-width: 0;\n min-height: 0;\n}\n\n/* ── horizontal 핸들: 8px 히트영역 ─────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"horizontal\"]) {\n width: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── vertical 핸들: 8px 히트영역 ───────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]) {\n height: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── 시각선: 1px (after:w-1 override) ──────────────────────────────── */\n:deep(.jsplitter-handle::after) {\n width: 1px !important;\n background: hsl(var(--border)) !important;\n transition: background 0.15s ease, width 0.12s ease !important;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::after) {\n height: 1px !important;\n width: 100% !important;\n}\n\n/* ── 그립 도트 인디케이터 (::before) ───────────────────────────────── */\n:deep(.jsplitter-handle::before) {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 20px;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n background-size: 3px 6px;\n background-repeat: repeat-y;\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.15s ease;\n pointer-events: none;\n z-index: 4;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::before) {\n width: 20px;\n height: 3px;\n background-size: 6px 3px;\n background-repeat: repeat-x;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n}\n\n/* ── hover ──────────────────────────────────────────────────────────── */\n:deep(.jsplitter-handle:hover) {\n background: hsl(var(--primary) / 0.04) !important;\n}\n\n:deep(.jsplitter-handle:hover::after) {\n width: 2px !important;\n background: hsl(var(--primary) / 0.55) !important;\n}\n\n:deep(.jsplitter-handle:hover::before) {\n opacity: 1;\n}\n\n/* ── drag / active ──────────────────────────────────────────────────── */\n:deep(.jsplitter-handle[data-state=\"drag\"]),\n:deep(.jsplitter-handle:active) {\n background: hsl(var(--primary) / 0.06) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::after),\n:deep(.jsplitter-handle:active::after) {\n width: 2px !important;\n background: hsl(var(--primary)) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::before),\n:deep(.jsplitter-handle:active::before) {\n opacity: 1;\n background-image: radial-gradient(circle, hsl(var(--primary) / 0.65) 1px, transparent 1px);\n}\n</style>\n"],"names":["props","__props","secondDefaultSize","computed","_createBlock","_unref","ResizablePanelGroup","_normalizeClass","cn","$props","_createVNode","ResizablePanel","_normalizeStyle","_renderSlot","_ctx","ResizableHandle"],"mappings":";;;;;;;;;;;;;;;;;;;AAWA,UAAMA,IAAQC,GA+BRC,IAAoBC,EAAS,MAAM,MAAMH,EAAM,WAAW;2BAI9DI,EA+BsBC,EAAAC,CAAA,GAAA;AAAA,MA/BA,WAAWL,EAAA;AAAA,MAAY,OAAKM,EAAEF,EAAAG,CAAA,EAAE,mCAAoCC,EAAAA,OAAO,KAAK,CAAA;AAAA,IAAA;iBAEpG,MAWiB;AAAA,QAXjBC,EAWiBL,EAAAM,CAAA,GAAA;AAAA,UAVd,gBAAcV,EAAA;AAAA,UACd,YAAUA,EAAA;AAAA,UACV,YAAUA,EAAA;AAAA,UACV,OAAKM,EAAEN,EAAA,MAAG,IAAQA,EAAA,cAAS,eAAA,4BAAA,4BAAA,EAAA;AAAA,UAC3B,OAAKW,EAAEX,EAAA,MAAG,IAAA,EAAA,SAAA,GAAqBA,EAAA,GAAG,KAAA,IAAA,CAAA,CAAA;AAAA,QAAA;qBAEnC,MAAqB;AAAA,YAArBY,EAAqBC,EAAA,QAAA,SAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YAErBD,EAAoBC,EAAA,QAAA,QAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YACpBD,EAAmBC,EAAA,QAAA,OAAA,CAAA,GAAA,QAAA,EAAA;AAAA,UAAA;;;QAIrBJ,EAAsEL,EAAAU,CAAA,GAAA;AAAA,UAApD,eAAad,EAAA;AAAA,UAAY,OAAM;AAAA,QAAA;QAGjDS,EAWiBL,EAAAM,CAAA,GAAA;AAAA,UAVd,gBAAcT,EAAA;AAAA,UACd,YAAUD,EAAA;AAAA,UACV,YAAUA,EAAA;AAAA,UACV,OAAKM,EAAEN,EAAA,MAAG,IAAQA,EAAA,cAAS,eAAA,4BAAA,4BAAA,EAAA;AAAA,UAC3B,OAAKW,EAAEX,EAAA,MAAG,IAAA,EAAA,SAAA,GAAqBA,EAAA,GAAG,KAAA,IAAA,CAAA,CAAA;AAAA,QAAA;qBAEnC,MAAsB;AAAA,YAAtBY,EAAsBC,EAAA,QAAA,UAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YAEtBD,EAAqBC,EAAA,QAAA,SAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YACrBD,EAAsBC,EAAA,QAAA,UAAA,CAAA,GAAA,QAAA,EAAA;AAAA,UAAA;;;;;;;;"}
1
+ {"version":3,"file":"JSplitter.vue2.js","sources":["../../../../src/components/atoms/JSplitter.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { cn } from '@/lib/utils'\nimport {\n ResizablePanelGroup,\n ResizablePanel,\n ResizableHandle,\n} from '@/components/shadcn/resizable'\n\ntype Orientation = 'horizontal' | 'vertical'\n\nconst props = withDefaults(\n defineProps<{\n /** 분할 방향 (horizontal: 좌우, vertical: 상하) */\n direction?: Orientation\n /** 첫 번째 패널의 기본 크기 (%) */\n defaultSize?: number\n /** 첫 번째 패널의 최소 크기 (%) */\n minSize?: number\n /** 첫 번째 패널의 최대 크기 (%) */\n maxSize?: number\n /** 두 번째 패널의 최소 크기 (%) */\n secondMinSize?: number\n /** 두 번째 패널의 최대 크기 (%) */\n secondMaxSize?: number\n /** ResizableHandle에 grip 아이콘 표시 여부 */\n withHandle?: boolean\n /** 패널 간 여백 (px) */\n gap?: number\n /** 추가 CSS 클래스 */\n class?: string\n }>(),\n {\n direction: 'horizontal',\n defaultSize: 40,\n minSize: 20,\n withHandle: false,\n gap: 2,\n },\n)\n\n// 두 번째 패널의 기본 크기 계산\nconst secondDefaultSize = computed(() => 100 - props.defaultSize)\n</script>\n\n<template>\n <ResizablePanelGroup :direction=\"direction\" :class=\"cn('jsplitter-group min-h-0 min-w-0', $props.class)\">\n <!-- 첫 번째 패널 (좌측/상단) -->\n <ResizablePanel \n :default-size=\"defaultSize\" \n :min-size=\"minSize\" \n :max-size=\"maxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pr-[calc(var(--gap)/2)]' : 'pb-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"first\" />\n <!-- direction=\"horizontal\"일 때 left, vertical일 때 top으로도 사용 가능 -->\n <slot name=\"left\" />\n <slot name=\"top\" />\n </ResizablePanel>\n\n <!-- 크기 조정 핸들 -->\n <ResizableHandle :with-handle=\"withHandle\" class=\"jsplitter-handle\" />\n\n <!-- 두 번째 패널 (우측/하단) -->\n <ResizablePanel\n :default-size=\"secondDefaultSize\"\n :min-size=\"secondMinSize\"\n :max-size=\"secondMaxSize\"\n :class=\"gap > 0 ? (direction === 'horizontal' ? 'pl-[calc(var(--gap)/2)]' : 'pt-[calc(var(--gap)/2)]') : ''\"\n :style=\"gap > 0 ? { '--gap': `${gap}px` } : {}\"\n >\n <slot name=\"second\" />\n <!-- direction=\"horizontal\"일 때 right, vertical일 때 bottom으로도 사용 가능 -->\n <slot name=\"right\" />\n <slot name=\"bottom\" />\n </ResizablePanel>\n </ResizablePanelGroup>\n</template>\n\n<style scoped>\n/* ── overflow 보호 ──────────────────────────────────────────────────── */\n:deep(.jsplitter-group [data-panel]) {\n min-width: 0;\n min-height: 0;\n}\n\n/* ── horizontal 핸들: 8px 히트영역 ─────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"horizontal\"]) {\n width: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── vertical 핸들: 8px 히트영역 ───────────────────────────────────── */\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]) {\n height: 8px !important;\n background: transparent !important;\n position: relative;\n z-index: 3;\n transition: background 0.15s ease;\n}\n\n/* ── 시각선: 1px (after:w-1 override) ──────────────────────────────── */\n:deep(.jsplitter-handle::after) {\n width: 1px !important;\n background: hsl(var(--border)) !important;\n transition: background 0.15s ease, width 0.12s ease !important;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::after) {\n height: 1px !important;\n width: 100% !important;\n}\n\n/* ── 그립 도트 인디케이터 (::before) ───────────────────────────────── */\n:deep(.jsplitter-handle::before) {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 3px;\n height: 20px;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n background-size: 3px 6px;\n background-repeat: repeat-y;\n border-radius: 2px;\n opacity: 0.5;\n transition: opacity 0.15s ease;\n pointer-events: none;\n z-index: 4;\n}\n\n:deep(.jsplitter-handle[data-orientation=\"vertical\"]::before) {\n width: 20px;\n height: 3px;\n background-size: 6px 3px;\n background-repeat: repeat-x;\n background-image: radial-gradient(circle, hsl(var(--muted-foreground) / 0.5) 1px, transparent 1px);\n}\n\n/* ── hover ──────────────────────────────────────────────────────────── */\n:deep(.jsplitter-handle:hover) {\n background: hsl(var(--primary) / 0.04) !important;\n}\n\n:deep(.jsplitter-handle:hover::after) {\n width: 2px !important;\n background: hsl(var(--primary) / 0.55) !important;\n}\n\n:deep(.jsplitter-handle:hover::before) {\n opacity: 1;\n}\n\n/* ── drag / active ──────────────────────────────────────────────────── */\n:deep(.jsplitter-handle[data-state=\"drag\"]),\n:deep(.jsplitter-handle:active) {\n background: hsl(var(--primary) / 0.06) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::after),\n:deep(.jsplitter-handle:active::after) {\n width: 2px !important;\n background: hsl(var(--primary)) !important;\n}\n\n:deep(.jsplitter-handle[data-state=\"drag\"]::before),\n:deep(.jsplitter-handle:active::before) {\n opacity: 1;\n background-image: radial-gradient(circle, hsl(var(--primary) / 0.65) 1px, transparent 1px);\n}\n</style>\n"],"names":["props","__props","secondDefaultSize","computed","_createBlock","_unref","ResizablePanelGroup","_normalizeClass","cn","$props","_createVNode","ResizablePanel","_normalizeStyle","_renderSlot","_ctx","ResizableHandle"],"mappings":";;;;;;;;;;;;;;;;;;;AAWA,UAAMA,IAAQC,GA+BRC,IAAoBC,EAAS,MAAM,MAAMH,EAAM,WAAW;2BAI9DI,EA+BsBC,EAAAC,CAAA,GAAA;AAAA,MA/BA,WAAWL,EAAA;AAAA,MAAY,OAAKM,EAAEF,EAAAG,CAAA,EAAE,mCAAoCC,EAAAA,OAAO,KAAK,CAAA;AAAA,IAAA;iBAEpG,MAWiB;AAAA,QAXjBC,EAWiBL,EAAAM,CAAA,GAAA;AAAA,UAVd,gBAAcV,EAAA;AAAA,UACd,YAAUA,EAAA;AAAA,UACV,YAAUA,EAAA;AAAA,UACV,OAAKM,EAAEN,EAAA,MAAG,IAAQA,EAAA,cAAS,eAAA,4BAAA,4BAAA,EAAA;AAAA,UAC3B,OAAKW,EAAEX,EAAA,MAAG,IAAA,EAAA,SAAA,GAAqBA,EAAA,GAAG,KAAA,IAAA,CAAA,CAAA;AAAA,QAAA;qBAEnC,MAAqB;AAAA,YAArBY,EAAqBC,EAAA,QAAA,SAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YAErBD,EAAoBC,EAAA,QAAA,QAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YACpBD,EAAmBC,EAAA,QAAA,OAAA,CAAA,GAAA,QAAA,EAAA;AAAA,UAAA;;;QAIrBJ,EAAsEL,EAAAU,CAAA,GAAA;AAAA,UAApD,eAAad,EAAA;AAAA,UAAY,OAAM;AAAA,QAAA;QAGjDS,EAWiBL,EAAAM,CAAA,GAAA;AAAA,UAVd,gBAAcT,EAAA;AAAA,UACd,YAAUD,EAAA;AAAA,UACV,YAAUA,EAAA;AAAA,UACV,OAAKM,EAAEN,EAAA,MAAG,IAAQA,EAAA,cAAS,eAAA,4BAAA,4BAAA,EAAA;AAAA,UAC3B,OAAKW,EAAEX,EAAA,MAAG,IAAA,EAAA,SAAA,GAAqBA,EAAA,GAAG,KAAA,IAAA,CAAA,CAAA;AAAA,QAAA;qBAEnC,MAAsB;AAAA,YAAtBY,EAAsBC,EAAA,QAAA,UAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YAEtBD,EAAqBC,EAAA,QAAA,SAAA,CAAA,GAAA,QAAA,EAAA;AAAA,YACrBD,EAAsBC,EAAA,QAAA,UAAA,CAAA,GAAA,QAAA,EAAA;AAAA,UAAA;;;;;;;;"}
@@ -3,5 +3,5 @@
3
3
  for (const [t_key, t_val] of t_opts)
4
4
  t_merged[t_key] = t_val;
5
5
  return t_merged;
6
- };,u=t(e.default,[["__scopeId","data-v-3c2c8047"]]);exports.default=u;
6
+ };,u=t(e.default,[["__scopeId","data-v-0ac3efe9"]]);exports.default=u;
7
7
  //# sourceMappingURL=JTabs.vue.cjs.map
@@ -6,8 +6,8 @@ const t = (t_comp, t_opts) => {
6
6
  t_merged[t_key] = t_val;
7
7
  return t_merged;
8
8
  };
9
- const m = /* @__PURE__ */ t(o, [["__scopeId", "data-v-3c2c8047"]]);
9
+ const f = /* @__PURE__ */ t(o, [["__scopeId", "data-v-0ac3efe9"]]);
10
10
  export {
11
- m as default
11
+ f as default
12
12
  };
13
13
  //# sourceMappingURL=JTabs.vue.js.map
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");const y=require("lucide-vue-next"),u=require("../../lib/utils.cjs"),C=require("../atoms/JIcon.vue.cjs"),T=require("../shadcn/Tabs.vue.cjs"),B=require("../shadcn/TabsList.vue.cjs"),w=require("../shadcn/TabsTrigger.vue.cjs"),E=require("../shadcn/TabsContent.vue.cjs"),j={class:"flex-1 truncate"},q=["aria-label","onClick"],S={key:1,class:"p-4"},V={class:"text-muted-foreground"},N=e.defineComponent({__name:"JTabs",props:{tabs:{},activeTabId:{},class:{},listClass:{},styletype:{default:"default"}},emits:["tabChange","tabClose","update:activeTabId"],setup(p,{emit:m}){const n=p,s=m,i=e.computed(()=>Array.isArray(n.tabs)?n.tabs:[]),r=e.ref(n.activeTabId||(i.value.length>0?i.value[0]?.id:"")||"");let l=!1;e.watch(()=>n.activeTabId,t=>{t!==void 0&&t!==r.value&&(r.value=t)},{immediate:!0}),e.watch(i,t=>{!n.activeTabId&&t.length>0&&!t.find(o=>o.id===r.value)&&t[0]&&(r.value=t[0].id)});const f=t=>{if(l)return;const o=String(t);o!==r.value&&(l=!0,r.value=o,s("update:activeTabId",o),s("tabChange",o),e.nextTick(()=>{l=!1}))},b=t=>{l||t===r.value||(l=!0,r.value=t,s("update:activeTabId",t),s("tabChange",t),e.nextTick(()=>{l=!1}))},g=(t,o)=>{t.stopPropagation(),s("tabClose",o)},d={default:{list:"w-full justify-start gap-1 px-1 bg-muted/30 border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]",trigger:["relative px-3 py-1.5 text-xs font-medium","rounded-t-md rounded-b-none","border border-transparent border-b-0","transition-all duration-150","flex items-center gap-2"].join(" "),active:["data-[state=active]:bg-background","data-[state=active]:text-foreground","data-[state=active]:font-medium","data-[state=active]:border-border","data-[state=active]:border-t-primary","data-[state=active]:border-t-2","data-[state=active]:shadow-sm","data-[state=active]:z-10","data-[state=active]:-mb-px"].join(" "),inactive:["data-[state=inactive]:bg-muted/20","data-[state=inactive]:text-muted-foreground","data-[state=inactive]:border-border/40","data-[state=inactive]:hover:bg-muted/40","data-[state=inactive]:hover:text-foreground"].join(" "),content:"border border-border border-t-0 bg-background rounded-b-md"},minimal:{list:"w-full justify-start gap-0.5 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]",trigger:["relative px-2.5 py-1 text-xs font-medium","rounded-none border-b-2 border-transparent","transition-all duration-150","flex items-center gap-2"].join(" "),active:["data-[state=active]:text-primary","data-[state=active]:border-b-primary","data-[state=active]:bg-transparent","data-[state=active]:shadow-none"].join(" "),inactive:["data-[state=inactive]:text-muted-foreground","data-[state=inactive]:bg-transparent","data-[state=inactive]:hover:text-foreground","data-[state=inactive]:hover:border-b-border"].join(" "),content:""}},c=e.computed(()=>d[n.styletype]??d.default),_=e.computed(()=>u.cn("flex flex-col w-full h-full",n.class)),h=e.computed(()=>u.cn(c.value.list,n.listClass)),x=e.computed(()=>u.cn(c.value.trigger,c.value.active,c.value.inactive)),k=e.computed(()=>u.cn("flex-1 w-full overflow-auto",c.value.content));return(t,o)=>(e.openBlock(),e.createBlock(e.unref(T.default),{"model-value":r.value,"onUpdate:modelValue":f,orientation:"horizontal",class:e.normalizeClass(_.value)},{default:e.withCtx(()=>[e.createVNode(e.unref(B.default),{class:e.normalizeClass(h.value)},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,a=>(e.openBlock(),e.createBlock(e.unref(w.default),{key:a.id,value:a.id,onClick:v=>b(a.id),class:e.normalizeClass(x.value)},{default:e.withCtx(()=>[a.icon?(e.openBlock(),e.createBlock(C.default,{key:0,name:a.icon,size:"sm",class:"flex-shrink-0"},null,8,["name"])):e.createCommentVNode("",!0),e.createElementVNode("span",j,e.toDisplayString(a.label),1),a.closable?(e.openBlock(),e.createElementBlock("button",{key:1,type:"button",class:"flex-shrink-0 h-3.5 w-3.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors focus:outline-none focus:ring-2 focus:ring-ring flex items-center justify-center","aria-label":`${a.label} 탭 닫기`,onClick:v=>g(v,a.id)},[e.createVNode(e.unref(y.X),{class:"h-2.5 w-2.5"})],8,q)):e.createCommentVNode("",!0)]),_:2},1032,["value","onClick","class"]))),128))]),_:1},8,["class"]),e.createElementVNode("div",{class:e.normalizeClass(k.value)},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,a=>(e.openBlock(),e.createBlock(e.unref(E.default),{key:`content-${a.id}`,value:a.id,class:"h-full mt-0 data-[state=active]:flex data-[state=active]:flex-col data-[state=active]:animate-tab-fade-in"},{default:e.withCtx(()=>[e.renderSlot(t.$slots,`content-${a.id}`,{tab:a},()=>[a.component?(e.openBlock(),e.createBlock(e.resolveDynamicComponent(a.component),e.mergeProps({key:0,ref_for:!0},a.props||{}),null,16)):(e.openBlock(),e.createElementBlock("div",S,[e.createElementVNode("p",V,e.toDisplayString(a.label)+" 콘텐츠",1)]))],!0)]),_:2},1032,["value"]))),128))],2)]),_:3},8,["model-value","class"]))}});exports.default=N;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");const y=require("lucide-vue-next"),u=require("../../lib/utils.cjs"),C=require("../atoms/JIcon.vue.cjs"),T=require("../shadcn/Tabs.vue.cjs"),B=require("../shadcn/TabsList.vue.cjs"),w=require("../shadcn/TabsTrigger.vue.cjs"),E=require("../shadcn/TabsContent.vue.cjs"),j={class:"flex-1 truncate"},q=["aria-label","onClick"],S={key:1,class:"p-4"},V={class:"text-muted-foreground"},N=e.defineComponent({__name:"JTabs",props:{tabs:{},activeTabId:{},class:{},listClass:{},styletype:{default:"default"}},emits:["tabChange","tabClose","update:activeTabId"],setup(p,{emit:f}){const o=p,s=f,i=e.computed(()=>Array.isArray(o.tabs)?o.tabs:[]),r=e.ref(o.activeTabId||(i.value.length>0?i.value[0]?.id:"")||"");let l=!1;e.watch(()=>o.activeTabId,t=>{t!==void 0&&t!==r.value&&(r.value=t)},{immediate:!0}),e.watch(i,t=>{!o.activeTabId&&t.length>0&&!t.find(n=>n.id===r.value)&&t[0]&&(r.value=t[0].id)});const m=t=>{if(l)return;const n=String(t);n!==r.value&&(l=!0,r.value=n,s("update:activeTabId",n),s("tabChange",n),e.nextTick(()=>{l=!1}))},_=t=>{l||t===r.value||(l=!0,r.value=t,s("update:activeTabId",t),s("tabChange",t),e.nextTick(()=>{l=!1}))},g=(t,n)=>{t.stopPropagation(),s("tabClose",n)},d={default:{list:"w-full justify-start gap-0 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]",trigger:["relative px-3 py-2 text-xs font-medium","rounded-none border-b-2 border-transparent -mb-px","transition-all duration-200","flex items-center gap-2"].join(" "),active:["data-[state=active]:text-foreground","data-[state=active]:border-b-primary","data-[state=active]:bg-transparent","data-[state=active]:shadow-none"].join(" "),inactive:["data-[state=inactive]:text-muted-foreground","data-[state=inactive]:bg-transparent","data-[state=inactive]:hover:text-foreground","data-[state=inactive]:hover:border-b-muted-foreground/30"].join(" "),content:""},minimal:{list:"w-full justify-start gap-0 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[1.75rem]",trigger:["relative px-2 py-1.5 text-xs font-medium","rounded-none border-b-2 border-transparent -mb-px","transition-all duration-200","flex items-center gap-1.5"].join(" "),active:["data-[state=active]:text-foreground","data-[state=active]:border-b-primary","data-[state=active]:bg-transparent","data-[state=active]:shadow-none"].join(" "),inactive:["data-[state=inactive]:text-muted-foreground","data-[state=inactive]:bg-transparent","data-[state=inactive]:hover:text-foreground","data-[state=inactive]:hover:border-b-muted-foreground/30"].join(" "),content:""}},c=e.computed(()=>d[o.styletype]??d.default),b=e.computed(()=>u.cn("flex flex-col w-full h-full",o.class)),h=e.computed(()=>u.cn(c.value.list,o.listClass)),x=e.computed(()=>u.cn(c.value.trigger,c.value.active,c.value.inactive)),k=e.computed(()=>u.cn("flex-1 w-full overflow-auto",c.value.content));return(t,n)=>(e.openBlock(),e.createBlock(e.unref(T.default),{"model-value":r.value,"onUpdate:modelValue":m,orientation:"horizontal",class:e.normalizeClass(b.value)},{default:e.withCtx(()=>[e.createVNode(e.unref(B.default),{class:e.normalizeClass(h.value)},{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,a=>(e.openBlock(),e.createBlock(e.unref(w.default),{key:a.id,value:a.id,onClick:v=>_(a.id),class:e.normalizeClass(x.value)},{default:e.withCtx(()=>[a.icon?(e.openBlock(),e.createBlock(C.default,{key:0,name:a.icon,size:"sm",class:"flex-shrink-0"},null,8,["name"])):e.createCommentVNode("",!0),e.createElementVNode("span",j,e.toDisplayString(a.label),1),a.closable?(e.openBlock(),e.createElementBlock("button",{key:1,type:"button",class:"flex-shrink-0 h-3.5 w-3.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors focus:outline-none focus:ring-2 focus:ring-ring flex items-center justify-center","aria-label":`${a.label} 탭 닫기`,onClick:v=>g(v,a.id)},[e.createVNode(e.unref(y.X),{class:"h-2.5 w-2.5"})],8,q)):e.createCommentVNode("",!0)]),_:2},1032,["value","onClick","class"]))),128))]),_:1},8,["class"]),e.createElementVNode("div",{class:e.normalizeClass(k.value)},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,a=>(e.openBlock(),e.createBlock(e.unref(E.default),{key:`content-${a.id}`,value:a.id,class:"h-full mt-0 data-[state=active]:flex data-[state=active]:flex-col data-[state=active]:animate-tab-fade-in"},{default:e.withCtx(()=>[e.renderSlot(t.$slots,`content-${a.id}`,{tab:a},()=>[a.component?(e.openBlock(),e.createBlock(e.resolveDynamicComponent(a.component),e.mergeProps({key:0,ref_for:!0},a.props||{}),null,16)):(e.openBlock(),e.createElementBlock("div",S,[e.createElementVNode("p",V,e.toDisplayString(a.label)+" 콘텐츠",1)]))],!0)]),_:2},1032,["value"]))),128))],2)]),_:3},8,["model-value","class"]))}});exports.default=N;
2
2
  //# sourceMappingURL=JTabs.vue2.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"JTabs.vue2.cjs","sources":["../../../../src/components/molecules/JTabs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick } from 'vue'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/shadcn'\nimport type { JTabsProps, JTabsEmits } from '@/types/dynamic-tabs.types'\nimport { X } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport JIcon from '@/components/atoms/JIcon.vue'\n\n/**\n * JTabs - 기본 탭 UI 컴포넌트 (molecules)\n * Basic Tabs UI Component\n *\n * @description\n * 정적인 탭 목록을 렌더링하는 기본 탭 컴포넌트입니다.\n * 닫기 버튼, 아이콘 등을 지원합니다.\n *\n * @example\n * ```vue\n * <JTabs\n * :tabs=\"tabs\"\n * :active-tab-id=\"activeId\"\n * @tab-change=\"handleChange\"\n * @tab-close=\"handleClose\"\n * />\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(defineProps<JTabsProps>(), {\n styletype: 'default',\n})\n\nconst emit = defineEmits<JTabsEmits>()\n\n/**\n * 안전한 tabs 배열 (undefined/null 체크)\n * Safe tabs array (undefined/null check)\n */\nconst safeTabs = computed(() => {\n return Array.isArray(props.tabs) ? props.tabs : []\n})\n\n/**\n * 현재 활성화된 탭 ID (내부 상태)\n * Current active tab ID (internal state)\n */\nconst internalActiveId = ref<string>(\n props.activeTabId || (safeTabs.value.length > 0 ? safeTabs.value[0]?.id : '') || ''\n)\n\n/**\n * 이벤트 처리 중 플래그 (중복 이벤트 방지)\n * Flag to prevent duplicate events\n */\nlet isHandlingEvent = false\n\n/**\n * props.activeTabId가 변경되면 내부 상태 동기화\n * Sync internal state when props.activeTabId changes\n */\nwatch(() => props.activeTabId, (newValue) => {\n if (newValue !== undefined && newValue !== internalActiveId.value) {\n internalActiveId.value = newValue\n }\n}, { immediate: true })\n\n/**\n * props.tabs가 변경되고 activeTabId가 없으면 첫 번째 탭 활성화\n * Activate first tab when tabs change and no activeTabId\n */\nwatch(safeTabs, (newTabs) => {\n if (!props.activeTabId && newTabs.length > 0 && !newTabs.find(t => t.id === internalActiveId.value) && newTabs[0]) {\n internalActiveId.value = newTabs[0].id\n }\n})\n\n/**\n * 탭 값 변경 핸들러 (reka-ui TabsRoot에서 직접 호출됨)\n * Tab value change handler (called directly from reka-ui TabsRoot)\n */\nconst handleTabValueChange = (value: string | number) => {\n if (isHandlingEvent) return\n\n const stringValue = String(value)\n if (stringValue !== internalActiveId.value) {\n isHandlingEvent = true\n internalActiveId.value = stringValue\n emit('update:activeTabId', stringValue)\n emit('tabChange', stringValue)\n nextTick(() => {\n isHandlingEvent = false\n })\n }\n}\n\n/**\n * 탭 클릭 핸들러 (백업 방안 - reka-ui 이벤트가 작동하지 않을 경우)\n * Tab click handler (backup - in case reka-ui events don't work)\n */\nconst handleTabClick = (tabId: string) => {\n if (isHandlingEvent || tabId === internalActiveId.value) return\n\n isHandlingEvent = true\n internalActiveId.value = tabId\n emit('update:activeTabId', tabId)\n emit('tabChange', tabId)\n nextTick(() => {\n isHandlingEvent = false\n })\n}\n\n/**\n * 탭 닫기 핸들러\n * Tab close handler\n */\nconst handleCloseTab = (e: Event, tabId: string) => {\n e.stopPropagation()\n emit('tabClose', tabId)\n}\n\n// ── Style Presets ──────────────────────────────────────────────────\nconst STYLE_PRESETS: Record<StyleType, {\n list: string\n trigger: string\n active: string\n inactive: string\n content: string\n}> = {\n // Default: Bordered/Card 스타일 (엔터프라이즈)\n // 상단 primary accent + 탭↔콘텐츠 시각적 연결\n default: {\n list: 'w-full justify-start gap-1 px-1 bg-muted/30 border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]',\n trigger: [\n 'relative px-3 py-1.5 text-xs font-medium',\n 'rounded-t-md rounded-b-none',\n 'border border-transparent border-b-0',\n 'transition-all duration-150',\n 'flex items-center gap-2',\n ].join(' '),\n active: [\n 'data-[state=active]:bg-background',\n 'data-[state=active]:text-foreground',\n 'data-[state=active]:font-medium',\n 'data-[state=active]:border-border',\n 'data-[state=active]:border-t-primary',\n 'data-[state=active]:border-t-2',\n 'data-[state=active]:shadow-sm',\n 'data-[state=active]:z-10',\n 'data-[state=active]:-mb-px',\n ].join(' '),\n inactive: [\n 'data-[state=inactive]:bg-muted/20',\n 'data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:border-border/40',\n 'data-[state=inactive]:hover:bg-muted/40',\n 'data-[state=inactive]:hover:text-foreground',\n ].join(' '),\n content: 'border border-border border-t-0 bg-background rounded-b-md',\n },\n\n // Minimal: Underline 스타일 (심플/사이드바용)\n // 하단 indicator 바만 표시, 테두리 없음\n minimal: {\n list: 'w-full justify-start gap-0.5 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]',\n trigger: [\n 'relative px-2.5 py-1 text-xs font-medium',\n 'rounded-none border-b-2 border-transparent',\n 'transition-all duration-150',\n 'flex items-center gap-2',\n ].join(' '),\n active: [\n 'data-[state=active]:text-primary',\n 'data-[state=active]:border-b-primary',\n 'data-[state=active]:bg-transparent',\n 'data-[state=active]:shadow-none',\n ].join(' '),\n inactive: [\n 'data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:bg-transparent',\n 'data-[state=inactive]:hover:text-foreground',\n 'data-[state=inactive]:hover:border-b-border',\n ].join(' '),\n content: '',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n// ── Computed Classes ──────────────────────────────────────────────\nconst rootClasses = computed(() => {\n return cn('flex flex-col w-full h-full', props.class)\n})\n\nconst listClasses = computed(() => {\n return cn(preset.value.list, props.listClass)\n})\n\nconst triggerClasses = computed(() => {\n return cn(\n preset.value.trigger,\n preset.value.active,\n preset.value.inactive,\n )\n})\n\nconst contentWrapperClasses = computed(() => {\n return cn('flex-1 w-full overflow-auto', preset.value.content)\n})\n</script>\n\n<template>\n <Tabs\n :model-value=\"internalActiveId\"\n @update:model-value=\"handleTabValueChange\"\n orientation=\"horizontal\"\n :class=\"rootClasses\"\n >\n <!-- 탭 헤더 영역 / Tab Headers -->\n <TabsList :class=\"listClasses\">\n <TabsTrigger\n v-for=\"tab in safeTabs\"\n :key=\"tab.id\"\n :value=\"tab.id\"\n @click=\"handleTabClick(tab.id)\"\n :class=\"triggerClasses\"\n >\n <!-- 탭 아이콘 / Tab Icon -->\n <JIcon\n v-if=\"tab.icon\"\n :name=\"tab.icon\"\n size=\"sm\"\n class=\"flex-shrink-0\"\n />\n\n <!-- 탭 레이블 / Tab Label -->\n <span class=\"flex-1 truncate\">{{ tab.label }}</span>\n\n <!-- 닫기 버튼 / Close Button -->\n <button\n v-if=\"tab.closable\"\n type=\"button\"\n class=\"flex-shrink-0 h-3.5 w-3.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors focus:outline-none focus:ring-2 focus:ring-ring flex items-center justify-center\"\n :aria-label=\"`${tab.label} 탭 닫기`\"\n @click=\"(e) => handleCloseTab(e, tab.id)\"\n >\n <X class=\"h-2.5 w-2.5\" />\n </button>\n </TabsTrigger>\n </TabsList>\n\n <!-- 탭 콘텐츠 영역 / Tab Contents -->\n <div :class=\"contentWrapperClasses\">\n <TabsContent\n v-for=\"tab in safeTabs\"\n :key=\"`content-${tab.id}`\"\n :value=\"tab.id\"\n class=\"h-full mt-0 data-[state=active]:flex data-[state=active]:flex-col data-[state=active]:animate-tab-fade-in\"\n >\n <slot :name=\"`content-${tab.id}`\" :tab=\"tab\">\n <component\n v-if=\"tab.component\"\n :is=\"tab.component\"\n v-bind=\"tab.props || {}\"\n />\n <div v-else class=\"p-4\">\n <p class=\"text-muted-foreground\">{{ tab.label }} 콘텐츠</p>\n </div>\n </slot>\n </TabsContent>\n </div>\n </Tabs>\n</template>\n\n<style scoped>\n/* ── 스크롤바: Tailwind으로 불가능한 pseudo-element만 `:deep()` 사용 ── */\n:deep([role=\"tablist\"]) {\n scrollbar-width: thin;\n scrollbar-color: hsl(var(--border)) transparent;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar) {\n height: 4px;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-track) {\n background: transparent;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-thumb) {\n background-color: hsl(var(--border));\n border-radius: 2px;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-thumb:hover) {\n background-color: hsl(var(--muted-foreground) / 0.4);\n}\n\n/* ── 콘텐츠 전환 애니메이션 ── */\n@keyframes tab-fade-in {\n from {\n opacity: 0;\n transform: translateY(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n:deep(.animate-tab-fade-in) {\n animation: tab-fade-in 0.15s ease-out;\n}\n</style>\n"],"names":["props","__props","emit","__emit","safeTabs","computed","internalActiveId","ref","isHandlingEvent","watch","newValue","newTabs","t","handleTabValueChange","value","stringValue","nextTick","handleTabClick","tabId","handleCloseTab","e","STYLE_PRESETS","preset","rootClasses","cn","listClasses","triggerClasses","contentWrapperClasses","_createBlock","_unref","Tabs","_createVNode","TabsList","_createElementBlock","_Fragment","_renderList","tab","TabsTrigger","$event","JIcon","_createElementVNode","_hoisted_1","_toDisplayString","X","TabsContent","_renderSlot","_ctx","_openBlock","_resolveDynamicComponent","_mergeProps","_hoisted_3","_hoisted_4"],"mappings":"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"}
1
+ {"version":3,"file":"JTabs.vue2.cjs","sources":["../../../../src/components/molecules/JTabs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch, nextTick } from 'vue'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/shadcn'\nimport type { JTabsProps, JTabsEmits } from '@/types/dynamic-tabs.types'\nimport { X } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport JIcon from '@/components/atoms/JIcon.vue'\n\n/**\n * JTabs - 기본 탭 UI 컴포넌트 (molecules)\n * Basic Tabs UI Component\n *\n * @description\n * 정적인 탭 목록을 렌더링하는 기본 탭 컴포넌트입니다.\n * 닫기 버튼, 아이콘 등을 지원합니다.\n *\n * @example\n * ```vue\n * <JTabs\n * :tabs=\"tabs\"\n * :active-tab-id=\"activeId\"\n * @tab-change=\"handleChange\"\n * @tab-close=\"handleClose\"\n * />\n * ```\n */\n\ntype StyleType = 'default' | 'minimal'\n\nconst props = withDefaults(defineProps<JTabsProps>(), {\n styletype: 'default',\n})\n\nconst emit = defineEmits<JTabsEmits>()\n\n/**\n * 안전한 tabs 배열 (undefined/null 체크)\n * Safe tabs array (undefined/null check)\n */\nconst safeTabs = computed(() => {\n return Array.isArray(props.tabs) ? props.tabs : []\n})\n\n/**\n * 현재 활성화된 탭 ID (내부 상태)\n * Current active tab ID (internal state)\n */\nconst internalActiveId = ref<string>(\n props.activeTabId || (safeTabs.value.length > 0 ? safeTabs.value[0]?.id : '') || ''\n)\n\n/**\n * 이벤트 처리 중 플래그 (중복 이벤트 방지)\n * Flag to prevent duplicate events\n */\nlet isHandlingEvent = false\n\n/**\n * props.activeTabId가 변경되면 내부 상태 동기화\n * Sync internal state when props.activeTabId changes\n */\nwatch(() => props.activeTabId, (newValue) => {\n if (newValue !== undefined && newValue !== internalActiveId.value) {\n internalActiveId.value = newValue\n }\n}, { immediate: true })\n\n/**\n * props.tabs가 변경되고 activeTabId가 없으면 첫 번째 탭 활성화\n * Activate first tab when tabs change and no activeTabId\n */\nwatch(safeTabs, (newTabs) => {\n if (!props.activeTabId && newTabs.length > 0 && !newTabs.find(t => t.id === internalActiveId.value) && newTabs[0]) {\n internalActiveId.value = newTabs[0].id\n }\n})\n\n/**\n * 탭 값 변경 핸들러 (reka-ui TabsRoot에서 직접 호출됨)\n * Tab value change handler (called directly from reka-ui TabsRoot)\n */\nconst handleTabValueChange = (value: string | number) => {\n if (isHandlingEvent) return\n\n const stringValue = String(value)\n if (stringValue !== internalActiveId.value) {\n isHandlingEvent = true\n internalActiveId.value = stringValue\n emit('update:activeTabId', stringValue)\n emit('tabChange', stringValue)\n nextTick(() => {\n isHandlingEvent = false\n })\n }\n}\n\n/**\n * 탭 클릭 핸들러 (백업 방안 - reka-ui 이벤트가 작동하지 않을 경우)\n * Tab click handler (backup - in case reka-ui events don't work)\n */\nconst handleTabClick = (tabId: string) => {\n if (isHandlingEvent || tabId === internalActiveId.value) return\n\n isHandlingEvent = true\n internalActiveId.value = tabId\n emit('update:activeTabId', tabId)\n emit('tabChange', tabId)\n nextTick(() => {\n isHandlingEvent = false\n })\n}\n\n/**\n * 탭 닫기 핸들러\n * Tab close handler\n */\nconst handleCloseTab = (e: Event, tabId: string) => {\n e.stopPropagation()\n emit('tabClose', tabId)\n}\n\n// ── Style Presets ──────────────────────────────────────────────────\nconst STYLE_PRESETS: Record<StyleType, {\n list: string\n trigger: string\n active: string\n inactive: string\n content: string\n}> = {\n // Default: Modern Underline 스타일 (Linear/Stripe/GitHub 패턴)\n // 하단 primary indicator + 텍스트 색상 전환 + 플랫 디자인\n default: {\n list: 'w-full justify-start gap-0 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[2rem]',\n trigger: [\n 'relative px-3 py-2 text-xs font-medium',\n 'rounded-none border-b-2 border-transparent -mb-px',\n 'transition-all duration-200',\n 'flex items-center gap-2',\n ].join(' '),\n active: [\n 'data-[state=active]:text-foreground',\n 'data-[state=active]:border-b-primary',\n 'data-[state=active]:bg-transparent',\n 'data-[state=active]:shadow-none',\n ].join(' '),\n inactive: [\n 'data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:bg-transparent',\n 'data-[state=inactive]:hover:text-foreground',\n 'data-[state=inactive]:hover:border-b-muted-foreground/30',\n ].join(' '),\n content: '',\n },\n\n // Minimal: 컴팩트 Underline (사이드바/중첩 탭용)\n // 더 작은 패딩, 밀도 높은 배치\n minimal: {\n list: 'w-full justify-start gap-0 px-0 bg-transparent border-b border-border overflow-x-auto overflow-y-hidden h-auto min-h-[1.75rem]',\n trigger: [\n 'relative px-2 py-1.5 text-xs font-medium',\n 'rounded-none border-b-2 border-transparent -mb-px',\n 'transition-all duration-200',\n 'flex items-center gap-1.5',\n ].join(' '),\n active: [\n 'data-[state=active]:text-foreground',\n 'data-[state=active]:border-b-primary',\n 'data-[state=active]:bg-transparent',\n 'data-[state=active]:shadow-none',\n ].join(' '),\n inactive: [\n 'data-[state=inactive]:text-muted-foreground',\n 'data-[state=inactive]:bg-transparent',\n 'data-[state=inactive]:hover:text-foreground',\n 'data-[state=inactive]:hover:border-b-muted-foreground/30',\n ].join(' '),\n content: '',\n },\n}\n\nconst preset = computed(() => {\n return STYLE_PRESETS[props.styletype] ?? STYLE_PRESETS.default\n})\n\n// ── Computed Classes ──────────────────────────────────────────────\nconst rootClasses = computed(() => {\n return cn('flex flex-col w-full h-full', props.class)\n})\n\nconst listClasses = computed(() => {\n return cn(preset.value.list, props.listClass)\n})\n\nconst triggerClasses = computed(() => {\n return cn(\n preset.value.trigger,\n preset.value.active,\n preset.value.inactive,\n )\n})\n\nconst contentWrapperClasses = computed(() => {\n return cn('flex-1 w-full overflow-auto', preset.value.content)\n})\n</script>\n\n<template>\n <Tabs\n :model-value=\"internalActiveId\"\n @update:model-value=\"handleTabValueChange\"\n orientation=\"horizontal\"\n :class=\"rootClasses\"\n >\n <!-- 탭 헤더 영역 / Tab Headers -->\n <TabsList :class=\"listClasses\">\n <TabsTrigger\n v-for=\"tab in safeTabs\"\n :key=\"tab.id\"\n :value=\"tab.id\"\n @click=\"handleTabClick(tab.id)\"\n :class=\"triggerClasses\"\n >\n <!-- 탭 아이콘 / Tab Icon -->\n <JIcon\n v-if=\"tab.icon\"\n :name=\"tab.icon\"\n size=\"sm\"\n class=\"flex-shrink-0\"\n />\n\n <!-- 탭 레이블 / Tab Label -->\n <span class=\"flex-1 truncate\">{{ tab.label }}</span>\n\n <!-- 닫기 버튼 / Close Button -->\n <button\n v-if=\"tab.closable\"\n type=\"button\"\n class=\"flex-shrink-0 h-3.5 w-3.5 rounded-sm hover:bg-destructive/10 hover:text-destructive transition-colors focus:outline-none focus:ring-2 focus:ring-ring flex items-center justify-center\"\n :aria-label=\"`${tab.label} 탭 닫기`\"\n @click=\"(e) => handleCloseTab(e, tab.id)\"\n >\n <X class=\"h-2.5 w-2.5\" />\n </button>\n </TabsTrigger>\n </TabsList>\n\n <!-- 탭 콘텐츠 영역 / Tab Contents -->\n <div :class=\"contentWrapperClasses\">\n <TabsContent\n v-for=\"tab in safeTabs\"\n :key=\"`content-${tab.id}`\"\n :value=\"tab.id\"\n class=\"h-full mt-0 data-[state=active]:flex data-[state=active]:flex-col data-[state=active]:animate-tab-fade-in\"\n >\n <slot :name=\"`content-${tab.id}`\" :tab=\"tab\">\n <component\n v-if=\"tab.component\"\n :is=\"tab.component\"\n v-bind=\"tab.props || {}\"\n />\n <div v-else class=\"p-4\">\n <p class=\"text-muted-foreground\">{{ tab.label }} 콘텐츠</p>\n </div>\n </slot>\n </TabsContent>\n </div>\n </Tabs>\n</template>\n\n<style scoped>\n/* ── 스크롤바: Tailwind으로 불가능한 pseudo-element만 `:deep()` 사용 ── */\n:deep([role=\"tablist\"]) {\n scrollbar-width: thin;\n scrollbar-color: hsl(var(--border)) transparent;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar) {\n height: 4px;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-track) {\n background: transparent;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-thumb) {\n background-color: hsl(var(--border));\n border-radius: 2px;\n}\n\n:deep([role=\"tablist\"]::-webkit-scrollbar-thumb:hover) {\n background-color: hsl(var(--muted-foreground) / 0.4);\n}\n\n/* ── 콘텐츠 전환 애니메이션 ── */\n@keyframes tab-fade-in {\n from {\n opacity: 0;\n transform: translateY(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n:deep(.animate-tab-fade-in) {\n animation: tab-fade-in 0.15s ease-out;\n}\n</style>\n"],"names":["props","__props","emit","__emit","safeTabs","computed","internalActiveId","ref","isHandlingEvent","watch","newValue","newTabs","t","handleTabValueChange","value","stringValue","nextTick","handleTabClick","tabId","handleCloseTab","e","STYLE_PRESETS","preset","rootClasses","cn","listClasses","triggerClasses","contentWrapperClasses","_createBlock","_unref","Tabs","_createVNode","TabsList","_createElementBlock","_Fragment","_renderList","tab","TabsTrigger","$event","JIcon","_createElementVNode","_hoisted_1","_toDisplayString","X","TabsContent","_renderSlot","_ctx","_openBlock","_resolveDynamicComponent","_mergeProps","_hoisted_3","_hoisted_4"],"mappings":"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"}