@j-solution/components 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/USAGE_GUIDE.md +1068 -61
  2. package/assets/jwms-portal-frontend-D8DdrheA.css +1 -0
  3. package/assets/styles/j-components.css +1 -1
  4. package/components/atoms/JEditor.vue.cjs +7 -0
  5. package/components/atoms/JEditor.vue.cjs.map +1 -0
  6. package/components/atoms/JEditor.vue.js +13 -0
  7. package/components/atoms/JEditor.vue.js.map +1 -0
  8. package/components/atoms/JEditor.vue2.cjs +2 -0
  9. package/components/atoms/JEditor.vue2.cjs.map +1 -0
  10. package/components/atoms/JEditor.vue2.js +43 -0
  11. package/components/atoms/JEditor.vue2.js.map +1 -0
  12. package/components/atoms/JPreview.vue.cjs +7 -0
  13. package/components/atoms/JPreview.vue.cjs.map +1 -0
  14. package/components/atoms/JPreview.vue.js +13 -0
  15. package/components/atoms/JPreview.vue.js.map +1 -0
  16. package/components/atoms/JPreview.vue2.cjs +2 -0
  17. package/components/atoms/JPreview.vue2.cjs.map +1 -0
  18. package/components/atoms/JPreview.vue2.js +121 -0
  19. package/components/atoms/JPreview.vue2.js.map +1 -0
  20. package/components/molecules/JAlert.vue.cjs +1 -1
  21. package/components/molecules/JAlert.vue.cjs.map +1 -1
  22. package/components/molecules/JAlert.vue.js +24 -19
  23. package/components/molecules/JAlert.vue.js.map +1 -1
  24. package/components/molecules/JFormField.vue.cjs +1 -1
  25. package/components/molecules/JFormField.vue.cjs.map +1 -1
  26. package/components/molecules/JFormField.vue.js +7 -2
  27. package/components/molecules/JFormField.vue.js.map +1 -1
  28. package/components/molecules/JTitlebar.vue.cjs +1 -1
  29. package/components/molecules/JTitlebar.vue.cjs.map +1 -1
  30. package/components/molecules/JTitlebar.vue.js +20 -15
  31. package/components/molecules/JTitlebar.vue.js.map +1 -1
  32. package/components/organisms/JDynamicForm.vue2.cjs +1 -1
  33. package/components/organisms/JDynamicForm.vue2.cjs.map +1 -1
  34. package/components/organisms/JDynamicForm.vue2.js +7 -2
  35. package/components/organisms/JDynamicForm.vue2.js.map +1 -1
  36. package/components/organisms/JFormModal.vue.cjs +1 -1
  37. package/components/organisms/JFormModal.vue.cjs.map +1 -1
  38. package/components/organisms/JFormModal.vue.js +20 -15
  39. package/components/organisms/JFormModal.vue.js.map +1 -1
  40. package/components/organisms/JModal.vue.cjs +1 -1
  41. package/components/organisms/JModal.vue.cjs.map +1 -1
  42. package/components/organisms/JModal.vue.js +7 -2
  43. package/components/organisms/JModal.vue.js.map +1 -1
  44. package/components/organisms/JSearchPanel.vue2.cjs +1 -1
  45. package/components/organisms/JSearchPanel.vue2.cjs.map +1 -1
  46. package/components/organisms/JSearchPanel.vue2.js +31 -26
  47. package/components/organisms/JSearchPanel.vue2.js.map +1 -1
  48. package/index.cjs +1 -1
  49. package/index.js +82 -78
  50. package/package.json +3 -1
  51. package/tailwind.config.js +2 -1
  52. package/types/index.d.ts +137 -89
  53. package/assets/jwms-portal-frontend-BqyV9oqF.css +0 -1
@@ -0,0 +1,7 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./JEditor.vue2.cjs");;/* empty css */const t = (t_comp, t_opts) => {
2
+ const t_merged = t_comp.__vccOpts || t_comp;
3
+ for (const [t_key, t_val] of t_opts)
4
+ t_merged[t_key] = t_val;
5
+ return t_merged;
6
+ };,u=t(e.default,[["__scopeId","data-v-8cd2903a"]]);exports.default=u;
7
+ //# sourceMappingURL=JEditor.vue.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JEditor.vue.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import o from "./JEditor.vue2.js";
2
+ /* empty css */
3
+ const t = (t_comp, t_opts) => {
4
+ const t_merged = t_comp.__vccOpts || t_comp;
5
+ for (const [t_key, t_val] of t_opts)
6
+ t_merged[t_key] = t_val;
7
+ return t_merged;
8
+ };
9
+ const p = /* @__PURE__ */ t(o, [["__scopeId", "data-v-8cd2903a"]]);
10
+ export {
11
+ p as default
12
+ };
13
+ //# sourceMappingURL=JEditor.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JEditor.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const l=require("vue"),i=require("md-editor-v3");;/* empty css */const s=l.defineComponent({__name:"JEditor",props:{modelValue:{default:""},placeholder:{default:"마크다운을 입력하세요..."},disabled:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},height:{default:500},theme:{default:"light"},class:{}},emits:["update:modelValue","change","save"],setup(e,{emit:d}){const o=e,t=d,n=a=>{t("update:modelValue",a),t("change",a)},r=a=>{t("save",a)};return(a,u)=>(l.openBlock(),l.createElementBlock("div",{class:l.normalizeClass(["j-editor-wrapper",o.class])},[l.createVNode(l.unref(i.MdEditor),{"model-value":e.modelValue,placeholder:e.placeholder,disabled:e.disabled,readonly:e.readonly,"editor-class-name":"j-editor","preview-class-name":"j-editor-preview",height:e.height,theme:e.theme,"onUpdate:modelValue":n,onOnSave:r},null,8,["model-value","placeholder","disabled","readonly","height","theme"])],2))}});exports.default=s;
2
+ //# sourceMappingURL=JEditor.vue2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JEditor.vue2.cjs","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport { MdEditor } from 'md-editor-v3'\r\nimport 'md-editor-v3/lib/style.css'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 마크다운 내용 (v-model) */\r\n modelValue?: string\r\n /** 플레이스홀더 텍스트 */\r\n placeholder?: string\r\n /** 비활성화 상태 */\r\n disabled?: boolean\r\n /** 읽기 전용 상태 */\r\n readonly?: boolean\r\n /** 에디터 높이 */\r\n height?: string | number\r\n /** 테마 (light/dark) */\r\n theme?: 'light' | 'dark'\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n }>(),\r\n {\r\n modelValue: '',\r\n placeholder: '마크다운을 입력하세요...',\r\n disabled: false,\r\n readonly: false,\r\n height: 500,\r\n theme: 'light',\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n 'update:modelValue': [value: string]\r\n 'change': [value: string]\r\n 'save': [value: string]\r\n}>()\r\n\r\nconst handleChange = (value: string) => {\r\n emit('update:modelValue', value)\r\n emit('change', value)\r\n}\r\n\r\nconst handleSave = (value: string) => {\r\n emit('save', value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['j-editor-wrapper', props.class]\">\r\n <MdEditor\r\n :model-value=\"modelValue\"\r\n :placeholder=\"placeholder\"\r\n :disabled=\"disabled\"\r\n :readonly=\"readonly\"\r\n :editor-class-name=\"'j-editor'\"\r\n :preview-class-name=\"'j-editor-preview'\"\r\n :height=\"height\"\r\n :theme=\"theme\"\r\n @update:model-value=\"handleChange\"\r\n @on-save=\"handleSave\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.j-editor-wrapper {\r\n @apply w-full;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor"],"mappings":"0kBAKA,MAAMA,EAAQC,EA2BRC,EAAOC,EAMPC,EAAgBC,GAAkB,CACtCH,EAAK,oBAAqBG,CAAK,EAC/BH,EAAK,SAAUG,CAAK,CACtB,EAEMC,EAAcD,GAAkB,CACpCH,EAAK,OAAQG,CAAK,CACpB,8BAIEE,EAAAA,mBAaM,MAAA,CAbA,MAAKC,EAAAA,eAAA,CAAA,mBAAuBR,EAAM,KAAK,CAAA,CAAA,GAC3CS,cAWEC,EAAAA,MAAAC,EAAAA,QAAA,EAAA,CAVC,cAAaV,EAAA,WACb,YAAaA,EAAA,YACb,SAAUA,EAAA,SACV,SAAUA,EAAA,SACV,oBAAmB,WACnB,qBAAoB,mBACpB,OAAQA,EAAA,OACR,MAAOA,EAAA,MACP,sBAAoBG,EACpB,SAASE,CAAA"}
@@ -0,0 +1,43 @@
1
+ import { defineComponent as r, createElementBlock as i, openBlock as m, normalizeClass as s, createVNode as c, unref as h } from "vue";
2
+ import { MdEditor as u } from "md-editor-v3";
3
+ /* empty css */
4
+ const y = /* @__PURE__ */ r({
5
+ __name: "JEditor",
6
+ props: {
7
+ modelValue: { default: "" },
8
+ placeholder: { default: "마크다운을 입력하세요..." },
9
+ disabled: { type: Boolean, default: !1 },
10
+ readonly: { type: Boolean, default: !1 },
11
+ height: { default: 500 },
12
+ theme: { default: "light" },
13
+ class: {}
14
+ },
15
+ emits: ["update:modelValue", "change", "save"],
16
+ setup(e, { emit: t }) {
17
+ const d = e, l = t, o = (a) => {
18
+ l("update:modelValue", a), l("change", a);
19
+ }, n = (a) => {
20
+ l("save", a);
21
+ };
22
+ return (a, f) => (m(), i("div", {
23
+ class: s(["j-editor-wrapper", d.class])
24
+ }, [
25
+ c(h(u), {
26
+ "model-value": e.modelValue,
27
+ placeholder: e.placeholder,
28
+ disabled: e.disabled,
29
+ readonly: e.readonly,
30
+ "editor-class-name": "j-editor",
31
+ "preview-class-name": "j-editor-preview",
32
+ height: e.height,
33
+ theme: e.theme,
34
+ "onUpdate:modelValue": o,
35
+ onOnSave: n
36
+ }, null, 8, ["model-value", "placeholder", "disabled", "readonly", "height", "theme"])
37
+ ], 2));
38
+ }
39
+ });
40
+ export {
41
+ y as default
42
+ };
43
+ //# sourceMappingURL=JEditor.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JEditor.vue2.js","sources":["../../../../src/components/atoms/JEditor.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport { MdEditor } from 'md-editor-v3'\r\nimport 'md-editor-v3/lib/style.css'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 마크다운 내용 (v-model) */\r\n modelValue?: string\r\n /** 플레이스홀더 텍스트 */\r\n placeholder?: string\r\n /** 비활성화 상태 */\r\n disabled?: boolean\r\n /** 읽기 전용 상태 */\r\n readonly?: boolean\r\n /** 에디터 높이 */\r\n height?: string | number\r\n /** 테마 (light/dark) */\r\n theme?: 'light' | 'dark'\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n }>(),\r\n {\r\n modelValue: '',\r\n placeholder: '마크다운을 입력하세요...',\r\n disabled: false,\r\n readonly: false,\r\n height: 500,\r\n theme: 'light',\r\n },\r\n)\r\n\r\nconst emit = defineEmits<{\r\n 'update:modelValue': [value: string]\r\n 'change': [value: string]\r\n 'save': [value: string]\r\n}>()\r\n\r\nconst handleChange = (value: string) => {\r\n emit('update:modelValue', value)\r\n emit('change', value)\r\n}\r\n\r\nconst handleSave = (value: string) => {\r\n emit('save', value)\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['j-editor-wrapper', props.class]\">\r\n <MdEditor\r\n :model-value=\"modelValue\"\r\n :placeholder=\"placeholder\"\r\n :disabled=\"disabled\"\r\n :readonly=\"readonly\"\r\n :editor-class-name=\"'j-editor'\"\r\n :preview-class-name=\"'j-editor-preview'\"\r\n :height=\"height\"\r\n :theme=\"theme\"\r\n @update:model-value=\"handleChange\"\r\n @on-save=\"handleSave\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.j-editor-wrapper {\r\n @apply w-full;\r\n}\r\n</style>\r\n"],"names":["props","__props","emit","__emit","handleChange","value","handleSave","_createElementBlock","_normalizeClass","_createVNode","_unref","MdEditor"],"mappings":";;;;;;;;;;;;;;;;AAKA,UAAMA,IAAQC,GA2BRC,IAAOC,GAMPC,IAAe,CAACC,MAAkB;AACtC,MAAAH,EAAK,qBAAqBG,CAAK,GAC/BH,EAAK,UAAUG,CAAK;AAAA,IACtB,GAEMC,IAAa,CAACD,MAAkB;AACpC,MAAAH,EAAK,QAAQG,CAAK;AAAA,IACpB;2BAIEE,EAaM,OAAA;AAAA,MAbA,OAAKC,EAAA,CAAA,oBAAuBR,EAAM,KAAK,CAAA;AAAA,IAAA;MAC3CS,EAWEC,EAAAC,CAAA,GAAA;AAAA,QAVC,eAAaV,EAAA;AAAA,QACb,aAAaA,EAAA;AAAA,QACb,UAAUA,EAAA;AAAA,QACV,UAAUA,EAAA;AAAA,QACV,qBAAmB;AAAA,QACnB,sBAAoB;AAAA,QACpB,QAAQA,EAAA;AAAA,QACR,OAAOA,EAAA;AAAA,QACP,uBAAoBG;AAAA,QACpB,UAASE;AAAA,MAAA;;;;"}
@@ -0,0 +1,7 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./JPreview.vue2.cjs");;/* empty css */const t = (t_comp, t_opts) => {
2
+ const t_merged = t_comp.__vccOpts || t_comp;
3
+ for (const [t_key, t_val] of t_opts)
4
+ t_merged[t_key] = t_val;
5
+ return t_merged;
6
+ };,u=t(e.default,[["__scopeId","data-v-5129bb96"]]);exports.default=u;
7
+ //# sourceMappingURL=JPreview.vue.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JPreview.vue.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import o from "./JPreview.vue2.js";
2
+ /* empty css */
3
+ const r = (r_comp, r_opts) => {
4
+ const r_merged = r_comp.__vccOpts || r_comp;
5
+ for (const [r_key, r_val] of r_opts)
6
+ r_merged[r_key] = r_val;
7
+ return r_merged;
8
+ };
9
+ const p = /* @__PURE__ */ r(o, [["__scopeId", "data-v-5129bb96"]]);
10
+ export {
11
+ p as default
12
+ };
13
+ //# sourceMappingURL=JPreview.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JPreview.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),o=require("md-editor-v3");;/* empty css */const m=require("dompurify"),c=["innerHTML"],u=e.defineComponent({__name:"JPreview",props:{modelValue:{default:""},theme:{default:"light"},class:{}},setup(l){const r=l;function i(s){const t=s.trim();return t.startsWith("<!DOCTYPE html")||t.startsWith("<!doctype html")||t.startsWith("<!DOCTYPE HTML")||t.startsWith("<!DOCTYPE Html")||t.startsWith("<html")||t.startsWith("<HTML")||t.startsWith("<Html")?"html":"markdown"}const a=e.computed(()=>i(r.modelValue||"")),n=e.computed(()=>a.value==="html"?m.sanitize(r.modelValue||"",{ALLOWED_TAGS:["p","br","strong","em","u","s","h1","h2","h3","h4","h5","h6","ul","ol","li","blockquote","pre","code","a","img","table","thead","tbody","tr","th","td","div","span","hr","blockquote","del","ins","sub","sup","kbd","mark","abbr","dfn","cite","q","samp","var","time","b","i","small","big","center","font","strike","tt","html","head","body","title","meta","link","style","script","noscript"],ALLOWED_ATTR:["href","src","alt","title","width","height","class","id","style","target","rel","type","charset","name","content","http-equiv","lang"],ALLOW_DATA_ATTR:!1}):"");return(s,t)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["j-preview-wrapper",r.class])},[a.value==="html"?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["j-preview-html",l.theme==="dark"?"dark":""]),innerHTML:n.value},null,10,c)):(e.openBlock(),e.createBlock(e.unref(o.MdPreview),{key:1,"model-value":l.modelValue,theme:l.theme,"preview-class-name":"j-preview-markdown"},null,8,["model-value","theme"]))],2))}});exports.default=u;
2
+ //# sourceMappingURL=JPreview.vue2.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JPreview.vue2.cjs","sources":["../../../../src/components/atoms/JPreview.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport { MdPreview } from 'md-editor-v3'\r\nimport 'md-editor-v3/lib/style.css'\r\nimport DOMPurify from 'dompurify'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 마크다운 또는 HTML 내용 */\r\n modelValue?: string\r\n /** 테마 (light/dark) */\r\n theme?: 'light' | 'dark'\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n }>(),\r\n {\r\n modelValue: '',\r\n theme: 'light',\r\n },\r\n)\r\n\r\n/**\r\n * 콘텐츠 타입 자동 감지\r\n */\r\nfunction detectContentType(content: string): 'markdown' | 'html' {\r\n const trimmed = content.trim()\r\n \r\n // HTML 문서 시작 태그 확인\r\n if (\r\n trimmed.startsWith('<!DOCTYPE html') ||\r\n trimmed.startsWith('<!doctype html') ||\r\n trimmed.startsWith('<!DOCTYPE HTML') ||\r\n trimmed.startsWith('<!DOCTYPE Html') ||\r\n trimmed.startsWith('<html') ||\r\n trimmed.startsWith('<HTML') ||\r\n trimmed.startsWith('<Html')\r\n ) {\r\n return 'html'\r\n }\r\n \r\n return 'markdown'\r\n}\r\n\r\nconst contentType = computed(() => detectContentType(props.modelValue || ''))\r\n\r\nconst sanitizedHtml = computed(() => {\r\n if (contentType.value === 'html') {\r\n return DOMPurify.sanitize(props.modelValue || '', {\r\n ALLOWED_TAGS: [\r\n 'p', 'br', 'strong', 'em', 'u', 's', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\r\n 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'a', 'img', 'table', 'thead',\r\n 'tbody', 'tr', 'th', 'td', 'div', 'span', 'hr', 'blockquote', 'del', 'ins',\r\n 'sub', 'sup', 'kbd', 'mark', 'abbr', 'dfn', 'cite', 'q', 'samp', 'var',\r\n 'time', 'b', 'i', 'small', 'big', 'center', 'font', 'strike', 'tt',\r\n 'html', 'head', 'body', 'title', 'meta', 'link', 'style', 'script', 'noscript'\r\n ],\r\n ALLOWED_ATTR: [\r\n 'href', 'src', 'alt', 'title', 'width', 'height', 'class', 'id', 'style',\r\n 'target', 'rel', 'type', 'charset', 'name', 'content', 'http-equiv', 'lang'\r\n ],\r\n ALLOW_DATA_ATTR: false,\r\n })\r\n }\r\n return ''\r\n})\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['j-preview-wrapper', props.class]\">\r\n <!-- HTML 렌더링 -->\r\n <div\r\n v-if=\"contentType === 'html'\"\r\n :class=\"['j-preview-html', theme === 'dark' ? 'dark' : '']\"\r\n v-html=\"sanitizedHtml\"\r\n />\r\n \r\n <!-- 마크다운 렌더링 -->\r\n <MdPreview\r\n v-else\r\n :model-value=\"modelValue\"\r\n :theme=\"theme\"\r\n :preview-class-name=\"'j-preview-markdown'\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.j-preview-wrapper {\r\n @apply w-full;\r\n}\r\n\r\n.j-preview-html {\r\n @apply prose prose-slate max-w-none;\r\n}\r\n\r\n.j-preview-html.dark {\r\n @apply prose-invert;\r\n}\r\n\r\n:deep(.j-preview-markdown) {\r\n @apply w-full;\r\n}\r\n</style>\r\n"],"names":["props","__props","detectContentType","content","trimmed","contentType","computed","sanitizedHtml","DOMPurify","_createElementBlock","_normalizeClass","_createBlock","_unref","MdPreview"],"mappings":"2bAMA,MAAMA,EAAQC,EAkBd,SAASC,EAAkBC,EAAsC,CAC/D,MAAMC,EAAUD,EAAQ,KAAA,EAGxB,OACEC,EAAQ,WAAW,gBAAgB,GACnCA,EAAQ,WAAW,gBAAgB,GACnCA,EAAQ,WAAW,gBAAgB,GACnCA,EAAQ,WAAW,gBAAgB,GACnCA,EAAQ,WAAW,OAAO,GAC1BA,EAAQ,WAAW,OAAO,GAC1BA,EAAQ,WAAW,OAAO,EAEnB,OAGF,UACT,CAEA,MAAMC,EAAcC,EAAAA,SAAS,IAAMJ,EAAkBF,EAAM,YAAc,EAAE,CAAC,EAEtEO,EAAgBD,EAAAA,SAAS,IACzBD,EAAY,QAAU,OACjBG,EAAU,SAASR,EAAM,YAAc,GAAI,CAChD,aAAc,CACZ,IAAK,KAAM,SAAU,KAAM,IAAK,IAAK,KAAM,KAAM,KAAM,KAAM,KAAM,KACnE,KAAM,KAAM,KAAM,aAAc,MAAO,OAAQ,IAAK,MAAO,QAAS,QACpE,QAAS,KAAM,KAAM,KAAM,MAAO,OAAQ,KAAM,aAAc,MAAO,MACrE,MAAO,MAAO,MAAO,OAAQ,OAAQ,MAAO,OAAQ,IAAK,OAAQ,MACjE,OAAQ,IAAK,IAAK,QAAS,MAAO,SAAU,OAAQ,SAAU,KAC9D,OAAQ,OAAQ,OAAQ,QAAS,OAAQ,OAAQ,QAAS,SAAU,UAAA,EAEtE,aAAc,CACZ,OAAQ,MAAO,MAAO,QAAS,QAAS,SAAU,QAAS,KAAM,QACjE,SAAU,MAAO,OAAQ,UAAW,OAAQ,UAAW,aAAc,MAAA,EAEvE,gBAAiB,EAAA,CAClB,EAEI,EACR,8BAICS,EAAAA,mBAeM,MAAA,CAfA,MAAKC,EAAAA,eAAA,CAAA,oBAAwBV,EAAM,KAAK,CAAA,CAAA,GAGpCK,EAAA,QAAW,sBADnBI,EAAAA,mBAIE,MAAA,OAFC,yCAA0BR,EAAA,QAAK,OAAA,OAAA,EAAA,CAAA,EAChC,UAAQM,EAAA,KAAA,6BAIVI,EAAAA,YAKEC,QAAAC,EAAAA,SAAA,EAAA,OAHC,cAAaZ,EAAA,WACb,MAAOA,EAAA,MACP,qBAAoB,oBAAA"}
@@ -0,0 +1,121 @@
1
+ import { defineComponent as c, computed as i, createElementBlock as n, openBlock as r, normalizeClass as m, createBlock as d, unref as u } from "vue";
2
+ import { MdPreview as p } from "md-editor-v3";
3
+ /* empty css */
4
+ import f from "dompurify";
5
+ const v = ["innerHTML"], w = /* @__PURE__ */ c({
6
+ __name: "JPreview",
7
+ props: {
8
+ modelValue: { default: "" },
9
+ theme: { default: "light" },
10
+ class: {}
11
+ },
12
+ setup(e) {
13
+ const l = e;
14
+ function o(s) {
15
+ const t = s.trim();
16
+ return t.startsWith("<!DOCTYPE html") || t.startsWith("<!doctype html") || t.startsWith("<!DOCTYPE HTML") || t.startsWith("<!DOCTYPE Html") || t.startsWith("<html") || t.startsWith("<HTML") || t.startsWith("<Html") ? "html" : "markdown";
17
+ }
18
+ const a = i(() => o(l.modelValue || "")), h = i(() => a.value === "html" ? f.sanitize(l.modelValue || "", {
19
+ ALLOWED_TAGS: [
20
+ "p",
21
+ "br",
22
+ "strong",
23
+ "em",
24
+ "u",
25
+ "s",
26
+ "h1",
27
+ "h2",
28
+ "h3",
29
+ "h4",
30
+ "h5",
31
+ "h6",
32
+ "ul",
33
+ "ol",
34
+ "li",
35
+ "blockquote",
36
+ "pre",
37
+ "code",
38
+ "a",
39
+ "img",
40
+ "table",
41
+ "thead",
42
+ "tbody",
43
+ "tr",
44
+ "th",
45
+ "td",
46
+ "div",
47
+ "span",
48
+ "hr",
49
+ "blockquote",
50
+ "del",
51
+ "ins",
52
+ "sub",
53
+ "sup",
54
+ "kbd",
55
+ "mark",
56
+ "abbr",
57
+ "dfn",
58
+ "cite",
59
+ "q",
60
+ "samp",
61
+ "var",
62
+ "time",
63
+ "b",
64
+ "i",
65
+ "small",
66
+ "big",
67
+ "center",
68
+ "font",
69
+ "strike",
70
+ "tt",
71
+ "html",
72
+ "head",
73
+ "body",
74
+ "title",
75
+ "meta",
76
+ "link",
77
+ "style",
78
+ "script",
79
+ "noscript"
80
+ ],
81
+ ALLOWED_ATTR: [
82
+ "href",
83
+ "src",
84
+ "alt",
85
+ "title",
86
+ "width",
87
+ "height",
88
+ "class",
89
+ "id",
90
+ "style",
91
+ "target",
92
+ "rel",
93
+ "type",
94
+ "charset",
95
+ "name",
96
+ "content",
97
+ "http-equiv",
98
+ "lang"
99
+ ],
100
+ ALLOW_DATA_ATTR: !1
101
+ }) : "");
102
+ return (s, t) => (r(), n("div", {
103
+ class: m(["j-preview-wrapper", l.class])
104
+ }, [
105
+ a.value === "html" ? (r(), n("div", {
106
+ key: 0,
107
+ class: m(["j-preview-html", e.theme === "dark" ? "dark" : ""]),
108
+ innerHTML: h.value
109
+ }, null, 10, v)) : (r(), d(u(p), {
110
+ key: 1,
111
+ "model-value": e.modelValue,
112
+ theme: e.theme,
113
+ "preview-class-name": "j-preview-markdown"
114
+ }, null, 8, ["model-value", "theme"]))
115
+ ], 2));
116
+ }
117
+ });
118
+ export {
119
+ w as default
120
+ };
121
+ //# sourceMappingURL=JPreview.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JPreview.vue2.js","sources":["../../../../src/components/atoms/JPreview.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport { computed } from 'vue'\r\nimport { MdPreview } from 'md-editor-v3'\r\nimport 'md-editor-v3/lib/style.css'\r\nimport DOMPurify from 'dompurify'\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** 마크다운 또는 HTML 내용 */\r\n modelValue?: string\r\n /** 테마 (light/dark) */\r\n theme?: 'light' | 'dark'\r\n /** 추가 CSS 클래스 */\r\n class?: string\r\n }>(),\r\n {\r\n modelValue: '',\r\n theme: 'light',\r\n },\r\n)\r\n\r\n/**\r\n * 콘텐츠 타입 자동 감지\r\n */\r\nfunction detectContentType(content: string): 'markdown' | 'html' {\r\n const trimmed = content.trim()\r\n \r\n // HTML 문서 시작 태그 확인\r\n if (\r\n trimmed.startsWith('<!DOCTYPE html') ||\r\n trimmed.startsWith('<!doctype html') ||\r\n trimmed.startsWith('<!DOCTYPE HTML') ||\r\n trimmed.startsWith('<!DOCTYPE Html') ||\r\n trimmed.startsWith('<html') ||\r\n trimmed.startsWith('<HTML') ||\r\n trimmed.startsWith('<Html')\r\n ) {\r\n return 'html'\r\n }\r\n \r\n return 'markdown'\r\n}\r\n\r\nconst contentType = computed(() => detectContentType(props.modelValue || ''))\r\n\r\nconst sanitizedHtml = computed(() => {\r\n if (contentType.value === 'html') {\r\n return DOMPurify.sanitize(props.modelValue || '', {\r\n ALLOWED_TAGS: [\r\n 'p', 'br', 'strong', 'em', 'u', 's', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\r\n 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'a', 'img', 'table', 'thead',\r\n 'tbody', 'tr', 'th', 'td', 'div', 'span', 'hr', 'blockquote', 'del', 'ins',\r\n 'sub', 'sup', 'kbd', 'mark', 'abbr', 'dfn', 'cite', 'q', 'samp', 'var',\r\n 'time', 'b', 'i', 'small', 'big', 'center', 'font', 'strike', 'tt',\r\n 'html', 'head', 'body', 'title', 'meta', 'link', 'style', 'script', 'noscript'\r\n ],\r\n ALLOWED_ATTR: [\r\n 'href', 'src', 'alt', 'title', 'width', 'height', 'class', 'id', 'style',\r\n 'target', 'rel', 'type', 'charset', 'name', 'content', 'http-equiv', 'lang'\r\n ],\r\n ALLOW_DATA_ATTR: false,\r\n })\r\n }\r\n return ''\r\n})\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['j-preview-wrapper', props.class]\">\r\n <!-- HTML 렌더링 -->\r\n <div\r\n v-if=\"contentType === 'html'\"\r\n :class=\"['j-preview-html', theme === 'dark' ? 'dark' : '']\"\r\n v-html=\"sanitizedHtml\"\r\n />\r\n \r\n <!-- 마크다운 렌더링 -->\r\n <MdPreview\r\n v-else\r\n :model-value=\"modelValue\"\r\n :theme=\"theme\"\r\n :preview-class-name=\"'j-preview-markdown'\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.j-preview-wrapper {\r\n @apply w-full;\r\n}\r\n\r\n.j-preview-html {\r\n @apply prose prose-slate max-w-none;\r\n}\r\n\r\n.j-preview-html.dark {\r\n @apply prose-invert;\r\n}\r\n\r\n:deep(.j-preview-markdown) {\r\n @apply w-full;\r\n}\r\n</style>\r\n"],"names":["props","__props","detectContentType","content","trimmed","contentType","computed","sanitizedHtml","DOMPurify","_createElementBlock","_normalizeClass","_createBlock","_unref","MdPreview"],"mappings":";;;;;;;;;;;;AAMA,UAAMA,IAAQC;AAkBd,aAASC,EAAkBC,GAAsC;AAC/D,YAAMC,IAAUD,EAAQ,KAAA;AAGxB,aACEC,EAAQ,WAAW,gBAAgB,KACnCA,EAAQ,WAAW,gBAAgB,KACnCA,EAAQ,WAAW,gBAAgB,KACnCA,EAAQ,WAAW,gBAAgB,KACnCA,EAAQ,WAAW,OAAO,KAC1BA,EAAQ,WAAW,OAAO,KAC1BA,EAAQ,WAAW,OAAO,IAEnB,SAGF;AAAA,IACT;AAEA,UAAMC,IAAcC,EAAS,MAAMJ,EAAkBF,EAAM,cAAc,EAAE,CAAC,GAEtEO,IAAgBD,EAAS,MACzBD,EAAY,UAAU,SACjBG,EAAU,SAASR,EAAM,cAAc,IAAI;AAAA,MAChD,cAAc;AAAA,QACZ;AAAA,QAAK;AAAA,QAAM;AAAA,QAAU;AAAA,QAAM;AAAA,QAAK;AAAA,QAAK;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QACnE;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QAAc;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAK;AAAA,QAAO;AAAA,QAAS;AAAA,QACpE;AAAA,QAAS;AAAA,QAAM;AAAA,QAAM;AAAA,QAAM;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAM;AAAA,QAAc;AAAA,QAAO;AAAA,QACrE;AAAA,QAAO;AAAA,QAAO;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAQ;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAK;AAAA,QAAQ;AAAA,QACjE;AAAA,QAAQ;AAAA,QAAK;AAAA,QAAK;AAAA,QAAS;AAAA,QAAO;AAAA,QAAU;AAAA,QAAQ;AAAA,QAAU;AAAA,QAC9D;AAAA,QAAQ;AAAA,QAAQ;AAAA,QAAQ;AAAA,QAAS;AAAA,QAAQ;AAAA,QAAQ;AAAA,QAAS;AAAA,QAAU;AAAA,MAAA;AAAA,MAEtE,cAAc;AAAA,QACZ;AAAA,QAAQ;AAAA,QAAO;AAAA,QAAO;AAAA,QAAS;AAAA,QAAS;AAAA,QAAU;AAAA,QAAS;AAAA,QAAM;AAAA,QACjE;AAAA,QAAU;AAAA,QAAO;AAAA,QAAQ;AAAA,QAAW;AAAA,QAAQ;AAAA,QAAW;AAAA,QAAc;AAAA,MAAA;AAAA,MAEvE,iBAAiB;AAAA,IAAA,CAClB,IAEI,EACR;2BAICS,EAeM,OAAA;AAAA,MAfA,OAAKC,EAAA,CAAA,qBAAwBV,EAAM,KAAK,CAAA;AAAA,IAAA;MAGpCK,EAAA,UAAW,eADnBI,EAIE,OAAA;AAAA;QAFC,4BAA0BR,EAAA,UAAK,SAAA,SAAA,EAAA,CAAA;AAAA,QAChC,WAAQM,EAAA;AAAA,MAAA,yBAIVI,EAKEC,EAAAC,CAAA,GAAA;AAAA;QAHC,eAAaZ,EAAA;AAAA,QACb,OAAOA,EAAA;AAAA,QACP,sBAAoB;AAAA,MAAA;;;;"}
@@ -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 a=require("../atoms/JButton.vue.cjs");require("lucide-vue-next");const l=require("../../lib/utils.cjs");require("@internationalized/date");require("../shadcn/badge-variants.cjs");require("@vueuse/core");require("reka-ui");;/* empty css */require("../shadcn/avatar-variants.cjs");require("ag-grid-vue3");require("ag-grid-community");require("ag-grid-enterprise");;/* empty css */;/* empty css */;/* empty css */;/* empty css */require("vue-sonner");const s=require("../shadcn/Alert.vue.cjs"),c=require("../shadcn/AlertTitle.vue.cjs"),d=require("../shadcn/AlertDescription.vue.cjs"),f={key:1,class:"mt-4 flex justify-end gap-2"},_=e.defineComponent({__name:"JAlert",props:{class:{},variant:{default:"default"},title:{},description:{},buttonText:{default:"확인"},onConfirm:{},showFooter:{type:Boolean,default:!0}},emits:["confirm"],setup(t,{emit:i}){const r=t,n=i,o=()=>{r.onConfirm?.(),n("confirm")};return(u,q)=>(e.openBlock(),e.createBlock(e.unref(s.default),{variant:r.variant,class:e.normalizeClass(e.unref(l.cn)(r.class))},{default:e.withCtx(()=>[t.title?(e.openBlock(),e.createBlock(e.unref(c.default),{key:0},{default:e.withCtx(()=>[e.renderSlot(u.$slots,"header",{},()=>[e.createTextVNode(e.toDisplayString(t.title),1)])]),_:3})):e.createCommentVNode("",!0),e.createVNode(e.unref(d.default),null,{default:e.withCtx(()=>[e.renderSlot(u.$slots,"default",{},()=>[e.createTextVNode(e.toDisplayString(t.description),1)])]),_:3}),t.showFooter?(e.openBlock(),e.createElementBlock("div",f,[e.renderSlot(u.$slots,"footer",{},()=>[e.createVNode(e.unref(a.default),{variant:t.variant==="destructive"?"secondary":"default",size:"sm",onClick:o},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(t.buttonText),1)]),_:1},8,["variant"])])])):e.createCommentVNode("",!0)]),_:3},8,["variant","class"]))}});exports.default=_;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");const a=require("../atoms/JButton.vue.cjs");require("lucide-vue-next");const l=require("../../lib/utils.cjs");require("@internationalized/date");require("md-editor-v3");;/* empty css */;/* empty css */require("../shadcn/badge-variants.cjs");require("@vueuse/core");require("reka-ui");;/* empty css */require("../shadcn/avatar-variants.cjs");require("dompurify");;/* empty css */require("ag-grid-vue3");require("ag-grid-community");require("ag-grid-enterprise");;/* empty css */;/* empty css */;/* empty css */;/* empty css */require("vue-sonner");const s=require("../shadcn/Alert.vue.cjs"),c=require("../shadcn/AlertTitle.vue.cjs"),d=require("../shadcn/AlertDescription.vue.cjs"),f={key:1,class:"mt-4 flex justify-end gap-2"},q=e.defineComponent({__name:"JAlert",props:{class:{},variant:{default:"default"},title:{},description:{},buttonText:{default:"확인"},onConfirm:{},showFooter:{type:Boolean,default:!0}},emits:["confirm"],setup(t,{emit:i}){const r=t,n=i,o=()=>{r.onConfirm?.(),n("confirm")};return(u,_)=>(e.openBlock(),e.createBlock(e.unref(s.default),{variant:r.variant,class:e.normalizeClass(e.unref(l.cn)(r.class))},{default:e.withCtx(()=>[t.title?(e.openBlock(),e.createBlock(e.unref(c.default),{key:0},{default:e.withCtx(()=>[e.renderSlot(u.$slots,"header",{},()=>[e.createTextVNode(e.toDisplayString(t.title),1)])]),_:3})):e.createCommentVNode("",!0),e.createVNode(e.unref(d.default),null,{default:e.withCtx(()=>[e.renderSlot(u.$slots,"default",{},()=>[e.createTextVNode(e.toDisplayString(t.description),1)])]),_:3}),t.showFooter?(e.openBlock(),e.createElementBlock("div",f,[e.renderSlot(u.$slots,"footer",{},()=>[e.createVNode(e.unref(a.default),{variant:t.variant==="destructive"?"secondary":"default",size:"sm",onClick:o},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(t.buttonText),1)]),_:1},8,["variant"])])])):e.createCommentVNode("",!0)]),_:3},8,["variant","class"]))}});exports.default=q;
2
2
  //# sourceMappingURL=JAlert.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"JAlert.vue.cjs","sources":["../../../../src/components/molecules/JAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { Alert, AlertTitle, AlertDescription } from '@/components/shadcn'\r\nimport { JButton } from '@/components/atoms'\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** Alert 자체의 클래스 */\r\n class?: HTMLAttributes[\"class\"]\r\n /** Alert variant 스타일 */\r\n variant?: \"default\" | \"destructive\"\r\n /** Alert 제목 (Header) */\r\n title?: string\r\n /** Alert 설명/내용 (Body) */\r\n description?: string\r\n /** Footer에 표시할 버튼 텍스트 */\r\n buttonText?: string\r\n /** Footer 버튼 클릭 핸들러 */\r\n onConfirm?: () => void\r\n /** Footer 표시 여부 */\r\n showFooter?: boolean\r\n }>(),\r\n {\r\n variant: \"default\",\r\n showFooter: true,\r\n buttonText: \"확인\"\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n confirm: []\r\n}>()\r\n\r\nconst handleConfirm = () => {\r\n props.onConfirm?.()\r\n emit('confirm')\r\n}\r\n</script>\r\n\r\n<template>\r\n <Alert :variant=\"props.variant\" :class=\"cn(props.class)\">\r\n <!-- Header -->\r\n <AlertTitle v-if=\"title\">\r\n <slot name=\"header\">{{ title }}</slot>\r\n </AlertTitle>\r\n \r\n <!-- Body -->\r\n <AlertDescription>\r\n <slot>{{ description }}</slot>\r\n </AlertDescription>\r\n \r\n <!-- Footer -->\r\n <div v-if=\"showFooter\" class=\"mt-4 flex justify-end gap-2\">\r\n <slot name=\"footer\">\r\n <JButton \r\n :variant=\"variant === 'destructive' ? 'secondary' : 'default'\"\r\n size=\"sm\"\r\n @click=\"handleConfirm\"\r\n >\r\n {{ buttonText }}\r\n </JButton>\r\n </slot>\r\n </div>\r\n </Alert>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","handleConfirm","_createBlock","_unref","Alert","_normalizeClass","cn","AlertTitle","_renderSlot","_ctx","_createVNode","AlertDescription","_openBlock","_createElementBlock","_hoisted_1","JButton"],"mappings":"g2CAMA,MAAMA,EAAQC,EAwBRC,EAAOC,EAIPC,EAAgB,IAAM,CAC1BJ,EAAM,YAAA,EACNE,EAAK,SAAS,CAChB,8BAIEG,EAAAA,YAuBQC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CAvBA,QAASP,EAAM,QAAU,MAAKQ,EAAAA,eAAEF,EAAAA,MAAAG,EAAAA,EAAA,EAAGT,EAAM,KAAK,CAAA,CAAA,qBAEpD,IAEa,CAFKC,EAAA,qBAAlBI,EAAAA,YAEaC,QAAAI,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBADX,IAAsC,CAAtCC,EAAAA,WAAsCC,qBAAtC,IAAsC,qCAAfX,EAAA,KAAK,EAAA,CAAA,CAAA,wCAI9BY,EAAAA,YAEmBP,EAAAA,MAAAQ,SAAA,EAAA,KAAA,mBADjB,IAA8B,CAA9BH,EAAAA,WAA8BC,sBAA9B,IAA8B,qCAArBX,EAAA,WAAW,EAAA,CAAA,CAAA,WAIXA,EAAA,YAAXc,EAAAA,UAAA,EAAAC,EAAAA,mBAUM,MAVNC,EAUM,CATJN,EAAAA,WAQOC,qBARP,IAQO,CAPLC,cAMUP,EAAAA,MAAAY,EAAAA,OAAA,EAAA,CALP,QAASjB,EAAA,UAAO,cAAA,YAAA,UACjB,KAAK,KACJ,QAAOG,CAAA,qBAER,IAAgB,qCAAbH,EAAA,UAAU,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"JAlert.vue.cjs","sources":["../../../../src/components/molecules/JAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { Alert, AlertTitle, AlertDescription } from '@/components/shadcn'\r\nimport { JButton } from '@/components/atoms'\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** Alert 자체의 클래스 */\r\n class?: HTMLAttributes[\"class\"]\r\n /** Alert variant 스타일 */\r\n variant?: \"default\" | \"destructive\"\r\n /** Alert 제목 (Header) */\r\n title?: string\r\n /** Alert 설명/내용 (Body) */\r\n description?: string\r\n /** Footer에 표시할 버튼 텍스트 */\r\n buttonText?: string\r\n /** Footer 버튼 클릭 핸들러 */\r\n onConfirm?: () => void\r\n /** Footer 표시 여부 */\r\n showFooter?: boolean\r\n }>(),\r\n {\r\n variant: \"default\",\r\n showFooter: true,\r\n buttonText: \"확인\"\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n confirm: []\r\n}>()\r\n\r\nconst handleConfirm = () => {\r\n props.onConfirm?.()\r\n emit('confirm')\r\n}\r\n</script>\r\n\r\n<template>\r\n <Alert :variant=\"props.variant\" :class=\"cn(props.class)\">\r\n <!-- Header -->\r\n <AlertTitle v-if=\"title\">\r\n <slot name=\"header\">{{ title }}</slot>\r\n </AlertTitle>\r\n \r\n <!-- Body -->\r\n <AlertDescription>\r\n <slot>{{ description }}</slot>\r\n </AlertDescription>\r\n \r\n <!-- Footer -->\r\n <div v-if=\"showFooter\" class=\"mt-4 flex justify-end gap-2\">\r\n <slot name=\"footer\">\r\n <JButton \r\n :variant=\"variant === 'destructive' ? 'secondary' : 'default'\"\r\n size=\"sm\"\r\n @click=\"handleConfirm\"\r\n >\r\n {{ buttonText }}\r\n </JButton>\r\n </slot>\r\n </div>\r\n </Alert>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","handleConfirm","_createBlock","_unref","Alert","_normalizeClass","cn","AlertTitle","_renderSlot","_ctx","_createVNode","AlertDescription","_openBlock","_createElementBlock","_hoisted_1","JButton"],"mappings":"wlDAMA,MAAMA,EAAQC,EAwBRC,EAAOC,EAIPC,EAAgB,IAAM,CAC1BJ,EAAM,YAAA,EACNE,EAAK,SAAS,CAChB,8BAIEG,EAAAA,YAuBQC,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CAvBA,QAASP,EAAM,QAAU,MAAKQ,EAAAA,eAAEF,EAAAA,MAAAG,EAAAA,EAAA,EAAGT,EAAM,KAAK,CAAA,CAAA,qBAEpD,IAEa,CAFKC,EAAA,qBAAlBI,EAAAA,YAEaC,QAAAI,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBADX,IAAsC,CAAtCC,EAAAA,WAAsCC,qBAAtC,IAAsC,qCAAfX,EAAA,KAAK,EAAA,CAAA,CAAA,wCAI9BY,EAAAA,YAEmBP,EAAAA,MAAAQ,SAAA,EAAA,KAAA,mBADjB,IAA8B,CAA9BH,EAAAA,WAA8BC,sBAA9B,IAA8B,qCAArBX,EAAA,WAAW,EAAA,CAAA,CAAA,WAIXA,EAAA,YAAXc,EAAAA,UAAA,EAAAC,EAAAA,mBAUM,MAVNC,EAUM,CATJN,EAAAA,WAQOC,qBARP,IAQO,CAPLC,cAMUP,EAAAA,MAAAY,EAAAA,OAAA,EAAA,CALP,QAASjB,EAAA,UAAO,cAAA,YAAA,UACjB,KAAK,KACJ,QAAOG,CAAA,qBAER,IAAgB,qCAAbH,EAAA,UAAU,EAAA,CAAA,CAAA"}
@@ -1,14 +1,19 @@
1
- import { defineComponent as v, createBlock as l, openBlock as a, unref as e, normalizeClass as C, withCtx as o, createCommentVNode as f, createVNode as c, createElementBlock as h, renderSlot as m, createTextVNode as n, toDisplayString as s } from "vue";
1
+ import { defineComponent as v, createBlock as l, openBlock as m, unref as o, normalizeClass as C, withCtx as e, createCommentVNode as f, createVNode as c, createElementBlock as h, renderSlot as a, createTextVNode as n, toDisplayString as s } from "vue";
2
2
  import "../shadcn/index.js";
3
3
  import $ from "../atoms/JButton.vue.js";
4
4
  import "lucide-vue-next";
5
5
  import { cn as k } from "../../lib/utils.js";
6
6
  import "@internationalized/date";
7
+ import "md-editor-v3";
8
+ /* empty css */
9
+ /* empty css */
7
10
  import "../shadcn/badge-variants.js";
8
11
  import "@vueuse/core";
9
12
  import "reka-ui";
10
13
  /* empty css */
11
14
  import "../shadcn/avatar-variants.js";
15
+ import "dompurify";
16
+ /* empty css */
12
17
  import "ag-grid-vue3";
13
18
  import "ag-grid-community";
14
19
  import "ag-grid-enterprise";
@@ -23,7 +28,7 @@ import x from "../shadcn/AlertDescription.vue.js";
23
28
  const B = {
24
29
  key: 1,
25
30
  class: "mt-4 flex justify-end gap-2"
26
- }, Q = /* @__PURE__ */ v({
31
+ }, Y = /* @__PURE__ */ v({
27
32
  __name: "JAlert",
28
33
  props: {
29
34
  class: {},
@@ -35,39 +40,39 @@ const B = {
35
40
  showFooter: { type: Boolean, default: !0 }
36
41
  },
37
42
  emits: ["confirm"],
38
- setup(t, { emit: d }) {
39
- const r = t, p = d, u = () => {
40
- r.onConfirm?.(), p("confirm");
43
+ setup(t, { emit: p }) {
44
+ const r = t, d = p, u = () => {
45
+ r.onConfirm?.(), d("confirm");
41
46
  };
42
- return (i, w) => (a(), l(e(y), {
47
+ return (i, w) => (m(), l(o(y), {
43
48
  variant: r.variant,
44
- class: C(e(k)(r.class))
49
+ class: C(o(k)(r.class))
45
50
  }, {
46
- default: o(() => [
47
- t.title ? (a(), l(e(_), { key: 0 }, {
48
- default: o(() => [
49
- m(i.$slots, "header", {}, () => [
51
+ default: e(() => [
52
+ t.title ? (m(), l(o(_), { key: 0 }, {
53
+ default: e(() => [
54
+ a(i.$slots, "header", {}, () => [
50
55
  n(s(t.title), 1)
51
56
  ])
52
57
  ]),
53
58
  _: 3
54
59
  })) : f("", !0),
55
- c(e(x), null, {
56
- default: o(() => [
57
- m(i.$slots, "default", {}, () => [
60
+ c(o(x), null, {
61
+ default: e(() => [
62
+ a(i.$slots, "default", {}, () => [
58
63
  n(s(t.description), 1)
59
64
  ])
60
65
  ]),
61
66
  _: 3
62
67
  }),
63
- t.showFooter ? (a(), h("div", B, [
64
- m(i.$slots, "footer", {}, () => [
65
- c(e($), {
68
+ t.showFooter ? (m(), h("div", B, [
69
+ a(i.$slots, "footer", {}, () => [
70
+ c(o($), {
66
71
  variant: t.variant === "destructive" ? "secondary" : "default",
67
72
  size: "sm",
68
73
  onClick: u
69
74
  }, {
70
- default: o(() => [
75
+ default: e(() => [
71
76
  n(s(t.buttonText), 1)
72
77
  ]),
73
78
  _: 1
@@ -80,6 +85,6 @@ const B = {
80
85
  }
81
86
  });
82
87
  export {
83
- Q as default
88
+ Y as default
84
89
  };
85
90
  //# sourceMappingURL=JAlert.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"JAlert.vue.js","sources":["../../../../src/components/molecules/JAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { Alert, AlertTitle, AlertDescription } from '@/components/shadcn'\r\nimport { JButton } from '@/components/atoms'\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** Alert 자체의 클래스 */\r\n class?: HTMLAttributes[\"class\"]\r\n /** Alert variant 스타일 */\r\n variant?: \"default\" | \"destructive\"\r\n /** Alert 제목 (Header) */\r\n title?: string\r\n /** Alert 설명/내용 (Body) */\r\n description?: string\r\n /** Footer에 표시할 버튼 텍스트 */\r\n buttonText?: string\r\n /** Footer 버튼 클릭 핸들러 */\r\n onConfirm?: () => void\r\n /** Footer 표시 여부 */\r\n showFooter?: boolean\r\n }>(),\r\n {\r\n variant: \"default\",\r\n showFooter: true,\r\n buttonText: \"확인\"\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n confirm: []\r\n}>()\r\n\r\nconst handleConfirm = () => {\r\n props.onConfirm?.()\r\n emit('confirm')\r\n}\r\n</script>\r\n\r\n<template>\r\n <Alert :variant=\"props.variant\" :class=\"cn(props.class)\">\r\n <!-- Header -->\r\n <AlertTitle v-if=\"title\">\r\n <slot name=\"header\">{{ title }}</slot>\r\n </AlertTitle>\r\n \r\n <!-- Body -->\r\n <AlertDescription>\r\n <slot>{{ description }}</slot>\r\n </AlertDescription>\r\n \r\n <!-- Footer -->\r\n <div v-if=\"showFooter\" class=\"mt-4 flex justify-end gap-2\">\r\n <slot name=\"footer\">\r\n <JButton \r\n :variant=\"variant === 'destructive' ? 'secondary' : 'default'\"\r\n size=\"sm\"\r\n @click=\"handleConfirm\"\r\n >\r\n {{ buttonText }}\r\n </JButton>\r\n </slot>\r\n </div>\r\n </Alert>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","handleConfirm","_createBlock","_unref","Alert","_normalizeClass","cn","AlertTitle","_renderSlot","_ctx","_createVNode","AlertDescription","_openBlock","_createElementBlock","_hoisted_1","JButton"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,UAAMA,IAAQC,GAwBRC,IAAOC,GAIPC,IAAgB,MAAM;AAC1B,MAAAJ,EAAM,YAAA,GACNE,EAAK,SAAS;AAAA,IAChB;2BAIEG,EAuBQC,EAAAC,CAAA,GAAA;AAAA,MAvBA,SAASP,EAAM;AAAA,MAAU,OAAKQ,EAAEF,EAAAG,CAAA,EAAGT,EAAM,KAAK,CAAA;AAAA,IAAA;iBAEpD,MAEa;AAAA,QAFKC,EAAA,cAAlBI,EAEaC,EAAAI,CAAA,GAAA,EAAA,KAAA,KAAA;AAAA,qBADX,MAAsC;AAAA,YAAtCC,EAAsCC,wBAAtC,MAAsC;AAAA,kBAAfX,EAAA,KAAK,GAAA,CAAA;AAAA,YAAA;;;;QAI9BY,EAEmBP,EAAAQ,CAAA,GAAA,MAAA;AAAA,qBADjB,MAA8B;AAAA,YAA9BH,EAA8BC,yBAA9B,MAA8B;AAAA,kBAArBX,EAAA,WAAW,GAAA,CAAA;AAAA,YAAA;;;;QAIXA,EAAA,cAAXc,EAAA,GAAAC,EAUM,OAVNC,GAUM;AAAA,UATJN,EAQOC,wBARP,MAQO;AAAA,YAPLC,EAMUP,EAAAY,CAAA,GAAA;AAAA,cALP,SAASjB,EAAA,YAAO,gBAAA,cAAA;AAAA,cACjB,MAAK;AAAA,cACJ,SAAOG;AAAA,YAAA;yBAER,MAAgB;AAAA,oBAAbH,EAAA,UAAU,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;"}
1
+ {"version":3,"file":"JAlert.vue.js","sources":["../../../../src/components/molecules/JAlert.vue"],"sourcesContent":["<script setup lang=\"ts\">\r\nimport type { HTMLAttributes } from \"vue\"\r\nimport { Alert, AlertTitle, AlertDescription } from '@/components/shadcn'\r\nimport { JButton } from '@/components/atoms'\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n /** Alert 자체의 클래스 */\r\n class?: HTMLAttributes[\"class\"]\r\n /** Alert variant 스타일 */\r\n variant?: \"default\" | \"destructive\"\r\n /** Alert 제목 (Header) */\r\n title?: string\r\n /** Alert 설명/내용 (Body) */\r\n description?: string\r\n /** Footer에 표시할 버튼 텍스트 */\r\n buttonText?: string\r\n /** Footer 버튼 클릭 핸들러 */\r\n onConfirm?: () => void\r\n /** Footer 표시 여부 */\r\n showFooter?: boolean\r\n }>(),\r\n {\r\n variant: \"default\",\r\n showFooter: true,\r\n buttonText: \"확인\"\r\n }\r\n)\r\n\r\nconst emit = defineEmits<{\r\n confirm: []\r\n}>()\r\n\r\nconst handleConfirm = () => {\r\n props.onConfirm?.()\r\n emit('confirm')\r\n}\r\n</script>\r\n\r\n<template>\r\n <Alert :variant=\"props.variant\" :class=\"cn(props.class)\">\r\n <!-- Header -->\r\n <AlertTitle v-if=\"title\">\r\n <slot name=\"header\">{{ title }}</slot>\r\n </AlertTitle>\r\n \r\n <!-- Body -->\r\n <AlertDescription>\r\n <slot>{{ description }}</slot>\r\n </AlertDescription>\r\n \r\n <!-- Footer -->\r\n <div v-if=\"showFooter\" class=\"mt-4 flex justify-end gap-2\">\r\n <slot name=\"footer\">\r\n <JButton \r\n :variant=\"variant === 'destructive' ? 'secondary' : 'default'\"\r\n size=\"sm\"\r\n @click=\"handleConfirm\"\r\n >\r\n {{ buttonText }}\r\n </JButton>\r\n </slot>\r\n </div>\r\n </Alert>\r\n</template>\r\n"],"names":["props","__props","emit","__emit","handleConfirm","_createBlock","_unref","Alert","_normalizeClass","cn","AlertTitle","_renderSlot","_ctx","_createVNode","AlertDescription","_openBlock","_createElementBlock","_hoisted_1","JButton"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,UAAMA,IAAQC,GAwBRC,IAAOC,GAIPC,IAAgB,MAAM;AAC1B,MAAAJ,EAAM,YAAA,GACNE,EAAK,SAAS;AAAA,IAChB;2BAIEG,EAuBQC,EAAAC,CAAA,GAAA;AAAA,MAvBA,SAASP,EAAM;AAAA,MAAU,OAAKQ,EAAEF,EAAAG,CAAA,EAAGT,EAAM,KAAK,CAAA;AAAA,IAAA;iBAEpD,MAEa;AAAA,QAFKC,EAAA,cAAlBI,EAEaC,EAAAI,CAAA,GAAA,EAAA,KAAA,KAAA;AAAA,qBADX,MAAsC;AAAA,YAAtCC,EAAsCC,wBAAtC,MAAsC;AAAA,kBAAfX,EAAA,KAAK,GAAA,CAAA;AAAA,YAAA;;;;QAI9BY,EAEmBP,EAAAQ,CAAA,GAAA,MAAA;AAAA,qBADjB,MAA8B;AAAA,YAA9BH,EAA8BC,yBAA9B,MAA8B;AAAA,kBAArBX,EAAA,WAAW,GAAA,CAAA;AAAA,YAAA;;;;QAIXA,EAAA,cAAXc,EAAA,GAAAC,EAUM,OAVNC,GAUM;AAAA,UATJN,EAQOC,wBARP,MAQO;AAAA,YAPLC,EAMUP,EAAAY,CAAA,GAAA;AAAA,cALP,SAASjB,EAAA,YAAO,gBAAA,cAAA;AAAA,cACjB,MAAK;AAAA,cACJ,SAAOG;AAAA,YAAA;yBAER,MAAgB;AAAA,oBAAbH,EAAA,UAAU,GAAA,CAAA;AAAA,cAAA;;;;;;;;;;"}
@@ -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");require("lucide-vue-next");const h=require("../atoms/JInput.vue.cjs"),F=require("../atoms/JTextarea.vue.cjs"),N=require("../atoms/JCheckbox.vue.cjs"),z=require("../atoms/JCombo.vue.cjs"),T=require("../atoms/JSearchCombo.vue.cjs"),S=require("../atoms/JRadio.vue.cjs"),J=require("../atoms/JSwitch.vue.cjs"),M=require("../atoms/JDatepicker.vue.cjs");require("clsx");require("tailwind-merge");require("../shadcn/badge-variants.cjs");require("@vueuse/core");require("reka-ui");;/* empty css */require("../shadcn/avatar-variants.cjs");require("ag-grid-vue3");require("ag-grid-community");require("ag-grid-enterprise");;/* empty css */;/* empty css */;/* empty css */;/* empty css */require("vue-sonner");const i=require("../shadcn/FieldGroup.vue.cjs"),g=require("../shadcn/Field.vue.cjs"),k=require("../shadcn/FieldLabel.vue.cjs"),C=require("../shadcn/FieldContent.vue.cjs"),P=require("../shadcn/FieldDescription.vue.cjs"),E=require("../shadcn/FieldError.vue.cjs"),L={key:0,class:"text-destructive ml-1"},j=e.defineComponent({__name:"JFormField",props:{label:{},description:{},errorMsg:{},type:{default:"input"},inlineLabel:{},orientation:{default:"vertical"},labelAlign:{default:"left"},labelWidth:{default:"8rem"},id:{},modelValue:{},placeholder:{},disabled:{type:Boolean},readonly:{type:Boolean},required:{type:Boolean},name:{},styleType:{},inputType:{},options:{},multiple:{type:Boolean},radioDirection:{default:"horizontal"}},emits:["update:modelValue","change","focus","blur"],setup(r,{expose:x,emit:b}){const q=["label","description","errorMsg","type","inlineLabel","orientation","labelAlign","labelWidth","radioDirection"],l=r,u=b,o=e.ref(""),c=e.computed(()=>l.errorMsg||o.value),s=e.computed(()=>{const t={},a=l;for(const n in a)q.includes(n)||(t[n]=a[n]);if(l.inputType&&l.type==="input"&&(t.type=l.inputType,delete t.inputType,!l.placeholder)){const n={text:"텍스트를 입력하세요",email:"이메일을 입력하세요",password:"비밀번호를 입력하세요",tel:"전화번호를 입력하세요",url:"URL을 입력하세요",number:"숫자를 입력하세요",search:"검색어를 입력하세요",date:"날짜를 선택하세요",time:"시간을 선택하세요","datetime-local":"날짜와 시간을 선택하세요",month:"월을 선택하세요",week:"주를 선택하세요"};t.placeholder=n[l.inputType]||"입력하세요"}return l.radioDirection&&l.type==="radio"&&(t.styletype=l.radioDirection,delete t.radioDirection),t}),d=t=>{if(!l.required)return;o.value="";const a=t!==void 0?t:l.modelValue;l.type==="checkbox"||l.type==="switch"?a!=="Y"&&(o.value="필수 항목입니다."):(a==null||a==="")&&(o.value="필수 입력 항목입니다.")},B=e.computed(()=>!(l.modelValue!==null&&l.modelValue!==void 0&&l.modelValue!=="")),p=t=>{u("update:modelValue",t),d(t)},f=t=>{u("change",t),d(t)},_=t=>{u("focus",t)},m=t=>{B.value&&d(),u("blur",t)},V=e.computed(()=>{const t={left:"justify-start",middle:"justify-center",right:"justify-end"},a={left:"text-left",middle:"text-center",right:"text-right"};return l.orientation==="horizontal"?t[l.labelAlign]:a[l.labelAlign]}),w=e.computed(()=>{switch(l.styleType){case"sm":return"form-density-sm";case"lg":return"form-density-lg";default:return"form-density-md"}}),v=e.computed(()=>{const t="h-[var(--ctl-h)] leading-[var(--ctl-h)]";return l.type==="datepicker"?`${t} max-w-xs`:l.type==="radio"&&l.radioDirection==="vertical"?"":t}),D={input:h.default,textarea:F.default,checkbox:N.default,switch:J.default,combo:z.default,radio:S.default,searchCombo:T.default,datepicker:M.default},y=e.computed(()=>D[l.type]||h.default);return x({clearError:()=>{o.value=""}}),(t,a)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["space-y-2",w.value])},[e.createVNode(e.unref(i.default),null,{default:e.withCtx(()=>[e.createVNode(e.unref(g.default),{class:e.normalizeClass([r.orientation==="horizontal"?"grid grid-cols-[var(--label-w,8rem)_1fr] items-start space-y-0 gap-2":"space-y-1 gap-1"]),style:e.normalizeStyle(r.orientation==="horizontal"?`--label-w:${r.labelWidth};`:"")},{default:e.withCtx(()=>[e.createVNode(e.unref(k.default),{for:r.id,class:e.normalizeClass([r.orientation==="horizontal"?"flex items-center h-[var(--ctl-h)] w-full":"flex items-center",V.value])},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(r.label)+" ",1),r.required?(e.openBlock(),e.createElementBlock("span",L,"*")):e.createCommentVNode("",!0)]),_:1},8,["for","class"]),e.createVNode(e.unref(C.default),{class:e.normalizeClass([r.orientation==="horizontal"?"min-h-[var(--ctl-h)] flex flex-col justify-start gap-0.5 mt-0":"space-y-2 gap-0"])},{default:e.withCtx(()=>[r.type==="checkbox"||r.type==="switch"?(e.openBlock(),e.createBlock(e.unref(i.default),{key:0,"data-slot":"checkbox-group"},{default:e.withCtx(()=>[e.createVNode(e.unref(g.default),{orientation:"horizontal",class:"flex gap-2 space-y-0 h-[var(--ctl-h)] leading-[var(--ctl-h)] items-center"},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m}),null,16)),r.inlineLabel?(e.openBlock(),e.createBlock(e.unref(k.default),{key:0,for:r.id,class:"font-normal m-0 h-[var(--ctl-h)] leading-[var(--ctl-h)]"},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(r.inlineLabel),1)]),_:1},8,["for"])):e.createCommentVNode("",!0)]),_:1})]),_:1})):r.type==="radio"?(e.openBlock(),e.createBlock(e.unref(i.default),{key:1},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m,class:v.value}),null,16,["class"]))]),_:1})):(e.openBlock(),e.createBlock(e.unref(i.default),{key:2},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m,class:v.value}),null,16,["class"]))]),_:1})),r.description||c.value?(e.openBlock(),e.createBlock(e.unref(C.default),{key:3},{default:e.withCtx(()=>[r.description?(e.openBlock(),e.createBlock(e.unref(P.default),{key:0},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(r.description),1)]),_:1})):e.createCommentVNode("",!0),c.value?(e.openBlock(),e.createBlock(e.unref(E.default),{key:1},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(c.value),1)]),_:1})):e.createCommentVNode("",!0)]),_:1})):e.createCommentVNode("",!0)]),_:1},8,["class"])]),_:1},8,["class","style"])]),_:1})],2))}});exports.default=j;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue");require("../shadcn/index.cjs");require("lucide-vue-next");const h=require("../atoms/JInput.vue.cjs"),F=require("../atoms/JTextarea.vue.cjs"),N=require("../atoms/JCheckbox.vue.cjs"),z=require("../atoms/JCombo.vue.cjs"),T=require("../atoms/JSearchCombo.vue.cjs"),S=require("../atoms/JRadio.vue.cjs"),J=require("../atoms/JSwitch.vue.cjs"),M=require("../atoms/JDatepicker.vue.cjs");require("md-editor-v3");;/* empty css */;/* empty css */require("clsx");require("tailwind-merge");require("../shadcn/badge-variants.cjs");require("@vueuse/core");require("reka-ui");;/* empty css */require("../shadcn/avatar-variants.cjs");require("dompurify");;/* empty css */require("ag-grid-vue3");require("ag-grid-community");require("ag-grid-enterprise");;/* empty css */;/* empty css */;/* empty css */;/* empty css */require("vue-sonner");const i=require("../shadcn/FieldGroup.vue.cjs"),g=require("../shadcn/Field.vue.cjs"),k=require("../shadcn/FieldLabel.vue.cjs"),q=require("../shadcn/FieldContent.vue.cjs"),P=require("../shadcn/FieldDescription.vue.cjs"),E=require("../shadcn/FieldError.vue.cjs"),L={key:0,class:"text-destructive ml-1"},j=e.defineComponent({__name:"JFormField",props:{label:{},description:{},errorMsg:{},type:{default:"input"},inlineLabel:{},orientation:{default:"vertical"},labelAlign:{default:"left"},labelWidth:{default:"8rem"},id:{},modelValue:{},placeholder:{},disabled:{type:Boolean},readonly:{type:Boolean},required:{type:Boolean},name:{},styleType:{},inputType:{},options:{},multiple:{type:Boolean},radioDirection:{default:"horizontal"}},emits:["update:modelValue","change","focus","blur"],setup(l,{expose:C,emit:x}){const b=["label","description","errorMsg","type","inlineLabel","orientation","labelAlign","labelWidth","radioDirection"],r=l,n=x,o=e.ref(""),c=e.computed(()=>r.errorMsg||o.value),s=e.computed(()=>{const t={},a=r;for(const u in a)b.includes(u)||(t[u]=a[u]);if(r.inputType&&r.type==="input"&&(t.type=r.inputType,delete t.inputType,!r.placeholder)){const u={text:"텍스트를 입력하세요",email:"이메일을 입력하세요",password:"비밀번호를 입력하세요",tel:"전화번호를 입력하세요",url:"URL을 입력하세요",number:"숫자를 입력하세요",search:"검색어를 입력하세요",date:"날짜를 선택하세요",time:"시간을 선택하세요","datetime-local":"날짜와 시간을 선택하세요",month:"월을 선택하세요",week:"주를 선택하세요"};t.placeholder=u[r.inputType]||"입력하세요"}return r.radioDirection&&r.type==="radio"&&(t.styletype=r.radioDirection,delete t.radioDirection),t}),d=t=>{if(!r.required)return;o.value="";const a=t!==void 0?t:r.modelValue;r.type==="checkbox"||r.type==="switch"?a!=="Y"&&(o.value="필수 항목입니다."):(a==null||a==="")&&(o.value="필수 입력 항목입니다.")},B=e.computed(()=>!(r.modelValue!==null&&r.modelValue!==void 0&&r.modelValue!=="")),p=t=>{n("update:modelValue",t),d(t)},f=t=>{n("change",t),d(t)},_=t=>{n("focus",t)},m=t=>{B.value&&d(),n("blur",t)},V=e.computed(()=>{const t={left:"justify-start",middle:"justify-center",right:"justify-end"},a={left:"text-left",middle:"text-center",right:"text-right"};return r.orientation==="horizontal"?t[r.labelAlign]:a[r.labelAlign]}),w=e.computed(()=>{switch(r.styleType){case"sm":return"form-density-sm";case"lg":return"form-density-lg";default:return"form-density-md"}}),v=e.computed(()=>{const t="h-[var(--ctl-h)] leading-[var(--ctl-h)]";return r.type==="datepicker"?`${t} max-w-xs`:r.type==="radio"&&r.radioDirection==="vertical"?"":t}),D={input:h.default,textarea:F.default,checkbox:N.default,switch:J.default,combo:z.default,radio:S.default,searchCombo:T.default,datepicker:M.default},y=e.computed(()=>D[r.type]||h.default);return C({clearError:()=>{o.value=""}}),(t,a)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["space-y-2",w.value])},[e.createVNode(e.unref(i.default),null,{default:e.withCtx(()=>[e.createVNode(e.unref(g.default),{class:e.normalizeClass([l.orientation==="horizontal"?"grid grid-cols-[var(--label-w,8rem)_1fr] items-start space-y-0 gap-2":"space-y-1 gap-1"]),style:e.normalizeStyle(l.orientation==="horizontal"?`--label-w:${l.labelWidth};`:"")},{default:e.withCtx(()=>[e.createVNode(e.unref(k.default),{for:l.id,class:e.normalizeClass([l.orientation==="horizontal"?"flex items-center h-[var(--ctl-h)] w-full":"flex items-center",V.value])},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(l.label)+" ",1),l.required?(e.openBlock(),e.createElementBlock("span",L,"*")):e.createCommentVNode("",!0)]),_:1},8,["for","class"]),e.createVNode(e.unref(q.default),{class:e.normalizeClass([l.orientation==="horizontal"?"min-h-[var(--ctl-h)] flex flex-col justify-start gap-0.5 mt-0":"space-y-2 gap-0"])},{default:e.withCtx(()=>[l.type==="checkbox"||l.type==="switch"?(e.openBlock(),e.createBlock(e.unref(i.default),{key:0,"data-slot":"checkbox-group"},{default:e.withCtx(()=>[e.createVNode(e.unref(g.default),{orientation:"horizontal",class:"flex gap-2 space-y-0 h-[var(--ctl-h)] leading-[var(--ctl-h)] items-center"},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m}),null,16)),l.inlineLabel?(e.openBlock(),e.createBlock(e.unref(k.default),{key:0,for:l.id,class:"font-normal m-0 h-[var(--ctl-h)] leading-[var(--ctl-h)]"},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(l.inlineLabel),1)]),_:1},8,["for"])):e.createCommentVNode("",!0)]),_:1})]),_:1})):l.type==="radio"?(e.openBlock(),e.createBlock(e.unref(i.default),{key:1},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m,class:v.value}),null,16,["class"]))]),_:1})):(e.openBlock(),e.createBlock(e.unref(i.default),{key:2},{default:e.withCtx(()=>[(e.openBlock(),e.createBlock(e.resolveDynamicComponent(y.value),e.mergeProps(s.value,{"onUpdate:modelValue":p,onChange:f,onFocus:_,onBlur:m,class:v.value}),null,16,["class"]))]),_:1})),l.description||c.value?(e.openBlock(),e.createBlock(e.unref(q.default),{key:3},{default:e.withCtx(()=>[l.description?(e.openBlock(),e.createBlock(e.unref(P.default),{key:0},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(l.description),1)]),_:1})):e.createCommentVNode("",!0),c.value?(e.openBlock(),e.createBlock(e.unref(E.default),{key:1},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(c.value),1)]),_:1})):e.createCommentVNode("",!0)]),_:1})):e.createCommentVNode("",!0)]),_:1},8,["class"])]),_:1},8,["class","style"])]),_:1})],2))}});exports.default=j;
2
2
  //# sourceMappingURL=JFormField.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"JFormField.vue.cjs","sources":["../../../../src/components/molecules/JFormField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Field, FieldContent, FieldLabel, FieldDescription, FieldError, FieldGroup } from '@/components/shadcn'\nimport { JInput, JTextarea, JCheckbox, JSwitch, JCombo, JRadio, JSearchCombo, JDatepicker } from '@/components/atoms'\n\n// 컴포넌트 타입 정의\ntype ComponentType = 'input' | 'textarea' | 'checkbox' | 'switch' | 'combo' | 'radio' | 'searchCombo' | 'datepicker'\n\n// FormField 자체의 props (레이아웃 관련)\nconst FORM_FIELD_PROPS = [\n 'label',\n 'description',\n 'errorMsg',\n 'type',\n 'inlineLabel',\n 'orientation',\n 'labelAlign',\n 'labelWidth',\n 'radioDirection',\n] as const\n\nconst props = withDefaults(\n defineProps<{\n // ============ FormField 자체 props (레이아웃만) ============\n /** 필드 레이블 */\n label?: string\n /** 필드 설명 (레이블 아래 표시) */\n description?: string\n /** 에러 메시지 */\n errorMsg?: string\n /** 컴포넌트 타입 (렌더링할 컴포넌트 지정) */\n type?: ComponentType\n /** 체크박스/스위치 타입일 때만 사용하는 옆 라벨 */\n inlineLabel?: string\n /** 레이블과 컨트롤의 배치 방향 */\n orientation?: 'vertical' | 'horizontal' | 'responsive'\n /** 레이블 텍스트 정렬 */\n labelAlign?: 'left' | 'middle' | 'right'\n /** 레이블 영역 너비 (horizontal orientation일 때만 적용) */\n labelWidth?: string\n\n // ============ 내부 컴포넌트로 전달할 공통 props ============\n /** Input 요소의 id (label for와 연결) */\n id?: string\n /** v-model로 양방향 데이터 바인딩 */\n modelValue?: any\n /** 입력 전 표시되는 안내문 (Input/Textarea/Select/Combobox) */\n placeholder?: string\n /** 비활성화 상태 (전체) */\n disabled?: boolean\n /** 읽기 전용 상태 (Input/Textarea) */\n readonly?: boolean\n /** 필수 입력/선택 여부 (전체) */\n required?: boolean\n /** form 데이터 전송 시 키 이름 (전체) */\n name?: string\n /** 스타일 테마 지정 (J-prefixed 컴포넌트의 styleType) */\n styleType?: string\n\n // ============ Input 전용 props ============\n /** Input 타입 (text, email, password 등) */\n inputType?: string\n\n\n // ============ Select/Combobox/Radio 전용 props ============\n /** 선택 가능한 항목 배열 */\n options?: Array<{ label: string; value: string | number; disabled?: boolean }>\n \n // ============ Select/Combobox 전용 props ============\n /** 다중 선택 허용 여부 */\n multiple?: boolean\n\n\n // ============ Radio 전용 props ============\n /** Radio 옵션 나열 방향 */\n radioDirection?: 'horizontal' | 'vertical'\n }>(),\n {\n type: 'input',\n orientation: 'vertical',\n labelAlign: 'left',\n labelWidth: '8rem',\n radioDirection: 'horizontal',\n }\n)\n\n// 이벤트 정의\nconst emit = defineEmits<{\n 'update:modelValue': [value: any]\n 'change': [value: any]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n// 내부 에러 상태 (props.error가 없을 때만 사용)\nconst internalError = ref<string>('')\n\n// 최종 에러 메시지 (외부 errorMsg가 우선)\nconst finalError = computed(() => props.errorMsg || internalError.value)\n\n// FormField 자체 props와 내부 컴포넌트 props 분리\nconst controlProps = computed(() => {\n const result: Record<string, any> = {}\n const propsObj = props as Record<string, any>\n \n for (const key in propsObj) {\n // FormField 자체 props는 제외\n if (!FORM_FIELD_PROPS.includes(key as any)) {\n result[key] = propsObj[key]\n }\n }\n \n // inputType을 type으로 변환 (JInput 컴포넌트에서 사용)\n if (props.inputType && props.type === 'input') {\n result.type = props.inputType\n delete result.inputType // inputType은 제거\n \n // placeholder가 없으면 inputType에 따라 기본값 설정\n if (!props.placeholder) {\n const defaultPlaceholders: Record<string, string> = {\n 'text': '텍스트를 입력하세요',\n 'email': '이메일을 입력하세요',\n 'password': '비밀번호를 입력하세요',\n 'tel': '전화번호를 입력하세요',\n 'url': 'URL을 입력하세요',\n 'number': '숫자를 입력하세요',\n 'search': '검색어를 입력하세요',\n 'date': '날짜를 선택하세요',\n 'time': '시간을 선택하세요',\n 'datetime-local': '날짜와 시간을 선택하세요',\n 'month': '월을 선택하세요',\n 'week': '주를 선택하세요',\n }\n \n result.placeholder = defaultPlaceholders[props.inputType] || '입력하세요'\n }\n }\n \n // radioDirection을 styletype으로 변환 (JRadio 컴포넌트에서 사용)\n if (props.radioDirection && props.type === 'radio') {\n result.styletype = props.radioDirection\n delete result.radioDirection // radioDirection은 제거\n }\n \n return result\n})\n\n // Built-in validation\n const validateField = (currentValue?: any) => {\n if (!props.required) return\n\n internalError.value = ''\n\n // 현재 값 또는 props.modelValue 사용\n const value = currentValue !== undefined ? currentValue : props.modelValue\n\n // Required 체크\n if (props.type === 'checkbox' || props.type === 'switch') {\n if (value !== 'Y') {\n internalError.value = '필수 항목입니다.'\n }\n } else {\n if (value === null || value === undefined || value === '') {\n internalError.value = '필수 입력 항목입니다.'\n }\n }\n }\n\n // 초기 로드 시 validation 실행 (blur 이벤트에서만)\n const shouldValidateOnMount = computed(() => {\n // Storybook에서 초기값이 있는 경우 validation 스킵\n if (props.modelValue !== null && props.modelValue !== undefined && props.modelValue !== '') {\n return false\n }\n return true\n })\n\n// 이벤트 핸들러\nconst handleUpdateModelValue = (value: any) => {\n emit('update:modelValue', value)\n \n // 값이 변경되면 즉시 validation 실행 (현재 값 전달)\n validateField(value)\n}\n\nconst handleChange = (value: any) => {\n emit('change', value)\n \n // change 이벤트에서도 validation 실행 (현재 값 전달)\n validateField(value)\n}\n\nconst handleFocus = (event: FocusEvent) => {\n emit('focus', event)\n}\n\n const handleBlur = (event: FocusEvent) => {\n // blur 시에만 validation 실행 (초기 로드 시에는 실행하지 않음)\n if (shouldValidateOnMount.value) {\n validateField()\n }\n emit('blur', event)\n }\n\n// 레이블 정렬 클래스 (레이블 영역 내에서 레이블의 위치 제어)\nconst labelAlignClass = computed(() => {\n // horizontal일 때는 레이블 영역 내에서 레이블의 위치를 제어\n const mapHorizontal = { \n left: 'justify-start', // 레이블 영역의 왼쪽에 레이블 위치\n middle: 'justify-center', // 레이블 영역의 가운데에 레이블 위치\n right: 'justify-end' // 레이블 영역의 오른쪽에 레이블 위치 (input과 가까이)\n }\n // vertical일 때는 텍스트 정렬만 제어\n const mapVertical = { left: 'text-left', middle: 'text-center', right: 'text-right' }\n return props.orientation === 'horizontal' ? mapHorizontal[props.labelAlign] : mapVertical[props.labelAlign]\n})\n\n/** 행높이 토큰 클래스 매핑 */\nconst densityClass = computed(() => {\n switch (props.styleType) {\n case 'sm': return 'form-density-sm'\n case 'lg': return 'form-density-lg'\n default: return 'form-density-md'\n }\n})\n\n/** 컨트롤 클래스 (datepicker는 최대 너비 제한, radio vertical은 높이 제한 없음) */\nconst controlClass = computed(() => {\n const baseClass = 'h-[var(--ctl-h)] leading-[var(--ctl-h)]'\n \n if (props.type === 'datepicker') {\n return `${baseClass} max-w-xs`\n }\n \n // Radio vertical일 때는 높이 제한 없음\n if (props.type === 'radio' && props.radioDirection === 'vertical') {\n return ''\n }\n \n return baseClass\n})\n\n// 컴포넌트 매핑\nconst componentMap: Record<ComponentType, any> = {\n input: JInput,\n textarea: JTextarea,\n checkbox: JCheckbox,\n switch: JSwitch,\n combo: JCombo,\n radio: JRadio,\n searchCombo: JSearchCombo,\n datepicker: JDatepicker,\n}\n\n// type에 따라 렌더링할 컴포넌트 결정\nconst resolvedComponent = computed(() => {\n return componentMap[props.type!] || JInput\n})\n\n// 외부에서 수동으로 에러 클리어 가능하도록 expose\ndefineExpose({\n clearError: () => { internalError.value = '' }\n})\n</script>\n\n<template>\n <div :class=\"['space-y-2', densityClass]\">\n <FieldGroup >\n <Field :class=\"[\n orientation === 'horizontal'\n ? 'grid grid-cols-[var(--label-w,8rem)_1fr] items-start space-y-0 gap-2'\n : 'space-y-1 gap-1'\n ]\"\n :style=\"orientation === 'horizontal' ? `--label-w:${labelWidth};` : ''\"\n >\n <!-- 메인 라벨 (필수표기 포함) -->\n <FieldLabel \n :for=\"id\" \n :class=\"[\n orientation === 'horizontal'\n ? 'flex items-center h-[var(--ctl-h)] w-full'\n : 'flex items-center',\n labelAlignClass\n ]\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"text-destructive ml-1\">*</span>\n </FieldLabel>\n\n <FieldContent \n :class=\"[\n orientation === 'horizontal'\n ? 'min-h-[var(--ctl-h)] flex flex-col justify-start gap-0.5 mt-0'\n : 'space-y-2 gap-0'\n ]\"\n >\n <!-- 체크박스/스위치: 항상 가로 정렬로 컨트롤 + 인라인 라벨 묶기 -->\n <FieldGroup v-if=\"type === 'checkbox' || type === 'switch'\" data-slot=\"checkbox-group\">\n <!-- 부모 orientation과 무관하게 수평 정렬 고정 -->\n <Field orientation=\"horizontal\" class=\"flex gap-2 space-y-0 h-[var(--ctl-h)] leading-[var(--ctl-h)] items-center\">\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n />\n <FieldLabel\n v-if=\"inlineLabel\"\n :for=\"id\"\n class=\"font-normal m-0 h-[var(--ctl-h)] leading-[var(--ctl-h)]\"\n >\n {{ inlineLabel }}\n </FieldLabel>\n </Field>\n </FieldGroup>\n\n <!-- Radio 버튼: radioDirection에 따라 분기 처리 -->\n <FieldGroup v-else-if=\"type === 'radio'\">\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n :class=\"controlClass\"\n />\n </FieldGroup>\n\n <!-- 그 외 컨트롤: orientation 규칙 그대로 따름 -->\n <FieldGroup v-else>\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n :class=\"controlClass\"\n />\n </FieldGroup>\n \n <!-- 설명/에러: 항상 컨트롤 '바로 아래'에 표시 -->\n <FieldContent v-if=\"description || finalError\">\n <FieldDescription v-if=\"description\">\n {{ description }}\n </FieldDescription>\n <FieldError v-if=\"finalError\">\n {{ finalError }}\n </FieldError>\n </FieldContent>\n </FieldContent>\n </Field>\n </FieldGroup>\n </div>\n</template>\n\n\n\n<style>\n/* ⬇⬇ 높이 토큰(밀도) — 프로젝트 전역/레이아웃에 한 번 정의해두고 재사용하세요 */\n.form-density-sm { --ctl-h: 2rem; /* 32px */ }\n.form-density-md { --ctl-h: 2.25rem; /* 36px (shadcn 기본에 근접) */ }\n.form-density-lg { --ctl-h: 2.5rem; /* 40px */ }\n</style>"],"names":["FORM_FIELD_PROPS","props","__props","emit","__emit","internalError","ref","finalError","computed","controlProps","result","propsObj","key","defaultPlaceholders","validateField","currentValue","value","shouldValidateOnMount","handleUpdateModelValue","handleChange","handleFocus","event","handleBlur","labelAlignClass","mapHorizontal","mapVertical","densityClass","controlClass","baseClass","componentMap","JInput","JTextarea","JCheckbox","JSwitch","JCombo","JRadio","JSearchCombo","JDatepicker","resolvedComponent","__expose","_createElementBlock","_createVNode","_unref","FieldGroup","Field","_normalizeClass","_normalizeStyle","FieldLabel","_createTextVNode","_toDisplayString","_hoisted_1","FieldContent","_createBlock","_openBlock","_resolveDynamicComponent","_mergeProps","FieldDescription","FieldError"],"mappings":"6+DASA,MAAMA,EAAmB,CACvB,QACA,cACA,WACA,OACA,cACA,cACA,aACA,aACA,gBAAA,EAGIC,EAAQC,EAkERC,EAAOC,EAQPC,EAAgBC,EAAAA,IAAY,EAAE,EAG9BC,EAAaC,EAAAA,SAAS,IAAMP,EAAM,UAAYI,EAAc,KAAK,EAGjEI,EAAeD,EAAAA,SAAS,IAAM,CAClC,MAAME,EAA8B,CAAA,EAC9BC,EAAWV,EAEjB,UAAWW,KAAOD,EAEXX,EAAiB,SAASY,CAAU,IACvCF,EAAOE,CAAG,EAAID,EAASC,CAAG,GAK9B,GAAIX,EAAM,WAAaA,EAAM,OAAS,UACpCS,EAAO,KAAOT,EAAM,UACpB,OAAOS,EAAO,UAGV,CAACT,EAAM,aAAa,CACtB,MAAMY,EAA8C,CAClD,KAAQ,aACR,MAAS,aACT,SAAY,cACZ,IAAO,cACP,IAAO,aACP,OAAU,YACV,OAAU,aACV,KAAQ,YACR,KAAQ,YACR,iBAAkB,gBAClB,MAAS,WACT,KAAQ,UAAA,EAGVH,EAAO,YAAcG,EAAoBZ,EAAM,SAAS,GAAK,OAC/D,CAIF,OAAIA,EAAM,gBAAkBA,EAAM,OAAS,UACzCS,EAAO,UAAYT,EAAM,eACzB,OAAOS,EAAO,gBAGTA,CACT,CAAC,EAGOI,EAAiBC,GAAuB,CAC5C,GAAI,CAACd,EAAM,SAAU,OAErBI,EAAc,MAAQ,GAGtB,MAAMW,EAAQD,IAAiB,OAAYA,EAAed,EAAM,WAG5DA,EAAM,OAAS,YAAcA,EAAM,OAAS,SAC1Ce,IAAU,MACZX,EAAc,MAAQ,cAGpBW,GAAU,MAA+BA,IAAU,MACrDX,EAAc,MAAQ,eAG5B,EAGMY,EAAwBT,EAAAA,SAAS,IAEjC,EAAAP,EAAM,aAAe,MAAQA,EAAM,aAAe,QAAaA,EAAM,aAAe,GAIzF,EAGGiB,EAA0BF,GAAe,CAC7Cb,EAAK,oBAAqBa,CAAK,EAG/BF,EAAcE,CAAK,CACrB,EAEMG,EAAgBH,GAAe,CACnCb,EAAK,SAAUa,CAAK,EAGpBF,EAAcE,CAAK,CACrB,EAEMI,EAAeC,GAAsB,CACzClB,EAAK,QAASkB,CAAK,CACrB,EAEQC,EAAcD,GAAsB,CAEpCJ,EAAsB,OACxBH,EAAA,EAEFX,EAAK,OAAQkB,CAAK,CACpB,EAGIE,EAAkBf,EAAAA,SAAS,IAAM,CAErC,MAAMgB,EAAgB,CACpB,KAAM,gBACN,OAAQ,iBACR,MAAO,aAAA,EAGHC,EAAc,CAAE,KAAM,YAAa,OAAQ,cAAe,MAAO,YAAA,EACvE,OAAOxB,EAAM,cAAgB,aAAeuB,EAAcvB,EAAM,UAAU,EAAIwB,EAAYxB,EAAM,UAAU,CAC5G,CAAC,EAGKyB,EAAelB,EAAAA,SAAS,IAAM,CAClC,OAAQP,EAAM,UAAA,CACZ,IAAK,KAAM,MAAO,kBAClB,IAAK,KAAM,MAAO,kBAClB,QAAW,MAAO,iBAAA,CAEtB,CAAC,EAGK0B,EAAenB,EAAAA,SAAS,IAAM,CAClC,MAAMoB,EAAY,0CAElB,OAAI3B,EAAM,OAAS,aACV,GAAG2B,CAAS,YAIjB3B,EAAM,OAAS,SAAWA,EAAM,iBAAmB,WAC9C,GAGF2B,CACT,CAAC,EAGKC,EAA2C,CAC/C,MAAOC,EAAAA,QACP,SAAUC,EAAAA,QACV,SAAUC,EAAAA,QACV,OAAQC,EAAAA,QACR,MAAOC,EAAAA,QACP,MAAOC,EAAAA,QACP,YAAaC,EAAAA,QACb,WAAYC,EAAAA,OAAA,EAIRC,EAAoB9B,EAAAA,SAAS,IAC1BqB,EAAa5B,EAAM,IAAK,GAAK6B,EAAAA,OACrC,EAGD,OAAAS,EAAa,CACX,WAAY,IAAM,CAAElC,EAAc,MAAQ,EAAG,CAAA,CAC9C,wBAICmC,EAAAA,mBA0FM,MAAA,CA1FA,oCAAqBd,EAAA,KAAY,CAAA,CAAA,GACrCe,EAAAA,YAwFaC,EAAAA,MAAAC,SAAA,EAAA,KAAA,mBAvFX,IAsFQ,CAtFRF,cAsFQC,EAAAA,MAAAE,EAAAA,OAAA,EAAA,CAtFA,MAAKC,EAAAA,eAAA,CAAc3C,EAAA,cAAW,wGAKnC,MAAK4C,EAAAA,eAAE5C,EAAA,cAAW,aAAA,aAAiCA,EAAA,UAAU,IAAA,EAAA,CAAA,qBAG9D,IAWa,CAXbuC,cAWaC,EAAAA,MAAAK,EAAAA,OAAA,EAAA,CAVV,IAAK7C,EAAA,GACL,MAAK2C,EAAAA,eAAA,CAAgB3C,EAAA,cAAW,6EAA+HqB,EAAA,KAAA,uBAOhK,IAAW,CAARyB,EAAAA,gBAAAC,EAAAA,gBAAA/C,EAAA,KAAK,EAAG,IACX,CAAA,EAAYA,EAAA,wBAAZsC,qBAA4D,OAA5DU,EAAoD,GAAC,yDAGvDT,cAgEeC,EAAAA,MAAAS,EAAAA,OAAA,EAAA,CA/DZ,MAAKN,EAAAA,eAAA,CAAgB3C,EAAA,cAAW,qHAOjC,IAmBa,CAnBKA,EAAA,mBAAuBA,EAAA,OAAI,wBAA7CkD,EAAAA,YAmBaV,EAAAA,MAAAC,EAAAA,OAAA,EAAA,OAnB+C,YAAU,gBAAA,qBAEpE,IAgBQ,CAhBRF,cAgBQC,EAAAA,MAAAE,EAAAA,OAAA,EAAA,CAhBD,YAAY,aAAa,MAAM,2EAAA,qBACpC,IAOE,EAPFS,YAAA,EAAAD,EAAAA,YAOEE,0BANKhB,EAAA,KAAiB,EADxBiB,EAAAA,WAEU9C,EAKR,MALoB,CACnB,sBAAmBS,EACnB,SAAQC,EACR,QAAOC,EACP,OAAME,CAAA,aAGDpB,EAAA,2BADRkD,EAAAA,YAMaV,EAAAA,MAAAK,EAAAA,OAAA,EAAA,OAJV,IAAK7C,EAAA,GACN,MAAM,yDAAA,qBAEN,IAAiB,qCAAdA,EAAA,WAAW,EAAA,CAAA,CAAA,iEAMGA,EAAA,OAAI,uBAA3BkD,cAUaV,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBATX,IAQE,EARFU,YAAA,EAAAD,EAAAA,YAQEE,0BAPKhB,EAAA,KAAiB,EADxBiB,EAAAA,WAEU9C,EAMR,MANoB,CACnB,sBAAmBS,EACnB,SAAQC,EACR,QAAOC,EACP,OAAME,EACN,MAAOK,EAAA,KAAA,+CAKZyB,cAUaV,EAAAA,MAAAC,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBATX,IAQE,EARFU,YAAA,EAAAD,EAAAA,YAQEE,0BAPKhB,EAAA,KAAiB,EADxBiB,EAAAA,WAEU9C,EAMR,MANoB,CACnB,sBAAmBS,EACnB,SAAQC,EACR,QAAOC,EACP,OAAME,EACN,MAAOK,EAAA,KAAA,gCAKQzB,EAAA,aAAeK,EAAA,qBAAnC6C,cAOeV,EAAAA,MAAAS,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBANb,IAEmB,CAFKjD,EAAA,2BAAxBkD,EAAAA,YAEmBV,QAAAc,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBADjB,IAAiB,qCAAdtD,EAAA,WAAW,EAAA,CAAA,CAAA,sCAEEK,EAAA,qBAAlB6C,EAAAA,YAEaV,QAAAe,EAAAA,OAAA,EAAA,CAAA,IAAA,GAAA,mBADX,IAAgB,qCAAblD,EAAA,KAAU,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"JFormField.vue.cjs","sources":["../../../../src/components/molecules/JFormField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { Field, FieldContent, FieldLabel, FieldDescription, FieldError, FieldGroup } from '@/components/shadcn'\nimport { JInput, JTextarea, JCheckbox, JSwitch, JCombo, JRadio, JSearchCombo, JDatepicker } from '@/components/atoms'\n\n// 컴포넌트 타입 정의\ntype ComponentType = 'input' | 'textarea' | 'checkbox' | 'switch' | 'combo' | 'radio' | 'searchCombo' | 'datepicker'\n\n// FormField 자체의 props (레이아웃 관련)\nconst FORM_FIELD_PROPS = [\n 'label',\n 'description',\n 'errorMsg',\n 'type',\n 'inlineLabel',\n 'orientation',\n 'labelAlign',\n 'labelWidth',\n 'radioDirection',\n] as const\n\nconst props = withDefaults(\n defineProps<{\n // ============ FormField 자체 props (레이아웃만) ============\n /** 필드 레이블 */\n label?: string\n /** 필드 설명 (레이블 아래 표시) */\n description?: string\n /** 에러 메시지 */\n errorMsg?: string\n /** 컴포넌트 타입 (렌더링할 컴포넌트 지정) */\n type?: ComponentType\n /** 체크박스/스위치 타입일 때만 사용하는 옆 라벨 */\n inlineLabel?: string\n /** 레이블과 컨트롤의 배치 방향 */\n orientation?: 'vertical' | 'horizontal' | 'responsive'\n /** 레이블 텍스트 정렬 */\n labelAlign?: 'left' | 'middle' | 'right'\n /** 레이블 영역 너비 (horizontal orientation일 때만 적용) */\n labelWidth?: string\n\n // ============ 내부 컴포넌트로 전달할 공통 props ============\n /** Input 요소의 id (label for와 연결) */\n id?: string\n /** v-model로 양방향 데이터 바인딩 */\n modelValue?: any\n /** 입력 전 표시되는 안내문 (Input/Textarea/Select/Combobox) */\n placeholder?: string\n /** 비활성화 상태 (전체) */\n disabled?: boolean\n /** 읽기 전용 상태 (Input/Textarea) */\n readonly?: boolean\n /** 필수 입력/선택 여부 (전체) */\n required?: boolean\n /** form 데이터 전송 시 키 이름 (전체) */\n name?: string\n /** 스타일 테마 지정 (J-prefixed 컴포넌트의 styleType) */\n styleType?: string\n\n // ============ Input 전용 props ============\n /** Input 타입 (text, email, password 등) */\n inputType?: string\n\n\n // ============ Select/Combobox/Radio 전용 props ============\n /** 선택 가능한 항목 배열 */\n options?: Array<{ label: string; value: string | number; disabled?: boolean }>\n \n // ============ Select/Combobox 전용 props ============\n /** 다중 선택 허용 여부 */\n multiple?: boolean\n\n\n // ============ Radio 전용 props ============\n /** Radio 옵션 나열 방향 */\n radioDirection?: 'horizontal' | 'vertical'\n }>(),\n {\n type: 'input',\n orientation: 'vertical',\n labelAlign: 'left',\n labelWidth: '8rem',\n radioDirection: 'horizontal',\n }\n)\n\n// 이벤트 정의\nconst emit = defineEmits<{\n 'update:modelValue': [value: any]\n 'change': [value: any]\n 'focus': [event: FocusEvent]\n 'blur': [event: FocusEvent]\n}>()\n\n// 내부 에러 상태 (props.error가 없을 때만 사용)\nconst internalError = ref<string>('')\n\n// 최종 에러 메시지 (외부 errorMsg가 우선)\nconst finalError = computed(() => props.errorMsg || internalError.value)\n\n// FormField 자체 props와 내부 컴포넌트 props 분리\nconst controlProps = computed(() => {\n const result: Record<string, any> = {}\n const propsObj = props as Record<string, any>\n \n for (const key in propsObj) {\n // FormField 자체 props는 제외\n if (!FORM_FIELD_PROPS.includes(key as any)) {\n result[key] = propsObj[key]\n }\n }\n \n // inputType을 type으로 변환 (JInput 컴포넌트에서 사용)\n if (props.inputType && props.type === 'input') {\n result.type = props.inputType\n delete result.inputType // inputType은 제거\n \n // placeholder가 없으면 inputType에 따라 기본값 설정\n if (!props.placeholder) {\n const defaultPlaceholders: Record<string, string> = {\n 'text': '텍스트를 입력하세요',\n 'email': '이메일을 입력하세요',\n 'password': '비밀번호를 입력하세요',\n 'tel': '전화번호를 입력하세요',\n 'url': 'URL을 입력하세요',\n 'number': '숫자를 입력하세요',\n 'search': '검색어를 입력하세요',\n 'date': '날짜를 선택하세요',\n 'time': '시간을 선택하세요',\n 'datetime-local': '날짜와 시간을 선택하세요',\n 'month': '월을 선택하세요',\n 'week': '주를 선택하세요',\n }\n \n result.placeholder = defaultPlaceholders[props.inputType] || '입력하세요'\n }\n }\n \n // radioDirection을 styletype으로 변환 (JRadio 컴포넌트에서 사용)\n if (props.radioDirection && props.type === 'radio') {\n result.styletype = props.radioDirection\n delete result.radioDirection // radioDirection은 제거\n }\n \n return result\n})\n\n // Built-in validation\n const validateField = (currentValue?: any) => {\n if (!props.required) return\n\n internalError.value = ''\n\n // 현재 값 또는 props.modelValue 사용\n const value = currentValue !== undefined ? currentValue : props.modelValue\n\n // Required 체크\n if (props.type === 'checkbox' || props.type === 'switch') {\n if (value !== 'Y') {\n internalError.value = '필수 항목입니다.'\n }\n } else {\n if (value === null || value === undefined || value === '') {\n internalError.value = '필수 입력 항목입니다.'\n }\n }\n }\n\n // 초기 로드 시 validation 실행 (blur 이벤트에서만)\n const shouldValidateOnMount = computed(() => {\n // Storybook에서 초기값이 있는 경우 validation 스킵\n if (props.modelValue !== null && props.modelValue !== undefined && props.modelValue !== '') {\n return false\n }\n return true\n })\n\n// 이벤트 핸들러\nconst handleUpdateModelValue = (value: any) => {\n emit('update:modelValue', value)\n \n // 값이 변경되면 즉시 validation 실행 (현재 값 전달)\n validateField(value)\n}\n\nconst handleChange = (value: any) => {\n emit('change', value)\n \n // change 이벤트에서도 validation 실행 (현재 값 전달)\n validateField(value)\n}\n\nconst handleFocus = (event: FocusEvent) => {\n emit('focus', event)\n}\n\n const handleBlur = (event: FocusEvent) => {\n // blur 시에만 validation 실행 (초기 로드 시에는 실행하지 않음)\n if (shouldValidateOnMount.value) {\n validateField()\n }\n emit('blur', event)\n }\n\n// 레이블 정렬 클래스 (레이블 영역 내에서 레이블의 위치 제어)\nconst labelAlignClass = computed(() => {\n // horizontal일 때는 레이블 영역 내에서 레이블의 위치를 제어\n const mapHorizontal = { \n left: 'justify-start', // 레이블 영역의 왼쪽에 레이블 위치\n middle: 'justify-center', // 레이블 영역의 가운데에 레이블 위치\n right: 'justify-end' // 레이블 영역의 오른쪽에 레이블 위치 (input과 가까이)\n }\n // vertical일 때는 텍스트 정렬만 제어\n const mapVertical = { left: 'text-left', middle: 'text-center', right: 'text-right' }\n return props.orientation === 'horizontal' ? mapHorizontal[props.labelAlign] : mapVertical[props.labelAlign]\n})\n\n/** 행높이 토큰 클래스 매핑 */\nconst densityClass = computed(() => {\n switch (props.styleType) {\n case 'sm': return 'form-density-sm'\n case 'lg': return 'form-density-lg'\n default: return 'form-density-md'\n }\n})\n\n/** 컨트롤 클래스 (datepicker는 최대 너비 제한, radio vertical은 높이 제한 없음) */\nconst controlClass = computed(() => {\n const baseClass = 'h-[var(--ctl-h)] leading-[var(--ctl-h)]'\n \n if (props.type === 'datepicker') {\n return `${baseClass} max-w-xs`\n }\n \n // Radio vertical일 때는 높이 제한 없음\n if (props.type === 'radio' && props.radioDirection === 'vertical') {\n return ''\n }\n \n return baseClass\n})\n\n// 컴포넌트 매핑\nconst componentMap: Record<ComponentType, any> = {\n input: JInput,\n textarea: JTextarea,\n checkbox: JCheckbox,\n switch: JSwitch,\n combo: JCombo,\n radio: JRadio,\n searchCombo: JSearchCombo,\n datepicker: JDatepicker,\n}\n\n// type에 따라 렌더링할 컴포넌트 결정\nconst resolvedComponent = computed(() => {\n return componentMap[props.type!] || JInput\n})\n\n// 외부에서 수동으로 에러 클리어 가능하도록 expose\ndefineExpose({\n clearError: () => { internalError.value = '' }\n})\n</script>\n\n<template>\n <div :class=\"['space-y-2', densityClass]\">\n <FieldGroup >\n <Field :class=\"[\n orientation === 'horizontal'\n ? 'grid grid-cols-[var(--label-w,8rem)_1fr] items-start space-y-0 gap-2'\n : 'space-y-1 gap-1'\n ]\"\n :style=\"orientation === 'horizontal' ? `--label-w:${labelWidth};` : ''\"\n >\n <!-- 메인 라벨 (필수표기 포함) -->\n <FieldLabel \n :for=\"id\" \n :class=\"[\n orientation === 'horizontal'\n ? 'flex items-center h-[var(--ctl-h)] w-full'\n : 'flex items-center',\n labelAlignClass\n ]\"\n >\n {{ label }}\n <span v-if=\"required\" class=\"text-destructive ml-1\">*</span>\n </FieldLabel>\n\n <FieldContent \n :class=\"[\n orientation === 'horizontal'\n ? 'min-h-[var(--ctl-h)] flex flex-col justify-start gap-0.5 mt-0'\n : 'space-y-2 gap-0'\n ]\"\n >\n <!-- 체크박스/스위치: 항상 가로 정렬로 컨트롤 + 인라인 라벨 묶기 -->\n <FieldGroup v-if=\"type === 'checkbox' || type === 'switch'\" data-slot=\"checkbox-group\">\n <!-- 부모 orientation과 무관하게 수평 정렬 고정 -->\n <Field orientation=\"horizontal\" class=\"flex gap-2 space-y-0 h-[var(--ctl-h)] leading-[var(--ctl-h)] items-center\">\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n />\n <FieldLabel\n v-if=\"inlineLabel\"\n :for=\"id\"\n class=\"font-normal m-0 h-[var(--ctl-h)] leading-[var(--ctl-h)]\"\n >\n {{ inlineLabel }}\n </FieldLabel>\n </Field>\n </FieldGroup>\n\n <!-- Radio 버튼: radioDirection에 따라 분기 처리 -->\n <FieldGroup v-else-if=\"type === 'radio'\">\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n :class=\"controlClass\"\n />\n </FieldGroup>\n\n <!-- 그 외 컨트롤: orientation 규칙 그대로 따름 -->\n <FieldGroup v-else>\n <component\n :is=\"resolvedComponent\"\n v-bind=\"controlProps\"\n @update:modelValue=\"handleUpdateModelValue\"\n @change=\"handleChange\"\n @focus=\"handleFocus\"\n @blur=\"handleBlur\"\n :class=\"controlClass\"\n />\n </FieldGroup>\n \n <!-- 설명/에러: 항상 컨트롤 '바로 아래'에 표시 -->\n <FieldContent v-if=\"description || finalError\">\n <FieldDescription v-if=\"description\">\n {{ description }}\n </FieldDescription>\n <FieldError v-if=\"finalError\">\n {{ finalError }}\n </FieldError>\n </FieldContent>\n </FieldContent>\n </Field>\n </FieldGroup>\n </div>\n</template>\n\n\n\n<style>\n/* ⬇⬇ 높이 토큰(밀도) — 프로젝트 전역/레이아웃에 한 번 정의해두고 재사용하세요 */\n.form-density-sm { --ctl-h: 2rem; /* 32px */ }\n.form-density-md { --ctl-h: 2.25rem; /* 36px (shadcn 기본에 근접) */ }\n.form-density-lg { --ctl-h: 2.5rem; /* 40px */ }\n</style>"],"names":["FORM_FIELD_PROPS","props","__props","emit","__emit","internalError","ref","finalError","computed","controlProps","result","propsObj","key","defaultPlaceholders","validateField","currentValue","value","shouldValidateOnMount","handleUpdateModelValue","handleChange","handleFocus","event","handleBlur","labelAlignClass","mapHorizontal","mapVertical","densityClass","controlClass","baseClass","componentMap","JInput","JTextarea","JCheckbox","JSwitch","JCombo","JRadio","JSearchCombo","JDatepicker","resolvedComponent","__expose","_createElementBlock","_createVNode","_unref","FieldGroup","Field","_normalizeClass","_normalizeStyle","FieldLabel","_createTextVNode","_toDisplayString","_hoisted_1","FieldContent","_createBlock","_openBlock","_resolveDynamicComponent","_mergeProps","FieldDescription","FieldError"],"mappings":"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"}