@ncds/ui-admin-mcp 1.0.0-alpha.27 → 1.0.0-alpha.29
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.
- package/bin/components.bundle.js +8 -8
- package/bin/definitions/external/step-guide.d.ts +5 -1
- package/bin/definitions/external/step-guide.js +1 -1
- package/bin/overrides/composition.json +208 -181
- package/bin/tools/renderToHtml.js +1 -1
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/data/_tokens.json +1 -1
- package/data/file-input.json +11 -2
- package/data/image-file-input.json +21 -0
- package/data/modal.json +34 -0
- package/data/select.json +2 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.renderToHtml=exports.buildJsField=exports.mergeCdnDefaults=exports.stripFunctionProps=void 0;const e=require("lodash"),n=require("../utils/response.js"),t=require("./external/editor.js"),r=require("./external/step-guide.js"),o=new Set(["dangerouslySetInnerHTML","ref","__self","__source"]),i=5,s=30,p=6,c=e=>"object"==typeof e&&null!==e&&"string"==typeof e.component,a=e=>e.charAt(0).toUpperCase()+e.slice(1),u=e=>e.split("-").map(a).join(""),l=e=>e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),d=(e,t)=>{const r=(0,n.normalizeName)(e),o=t.componentMap.get(r);return{Component:o?.exportName?t.bundle[o.exportName]??null:null,propsSpec:o?.props,compoundKey:null}},f=(e,n,t)=>{const r=e.slice(0,n).toLowerCase(),o=e.slice(n+1),i=t.componentMap.get(r),s=i?.exportName;if(!s)return{Component:null,propsSpec:void 0,compoundKey:null};const p=t.bundle[s],c=u(o),a=p?.[c]??null,l=`${s}.${c}`,d=i?.subComponents?.[l]?.props;return{Component:a,propsSpec:d,compoundKey:l}},m=(e,n,t)=>{const r=t?.allowedChildren?.[e];if(!r||Array.isArray(r))return null;const o=r.forbiddenInContext;if(!o)return null;const i=o[n];return i?{reason:"forbidden_in_context",message:i}:null},y=(e,n,t)=>{if(t>5)return null;if("string"==typeof e||"number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e)){const r=e.slice(0,s),o=[];return r.forEach((e,r)=>{const i={...n,path:`${n.path}[${r}]`},s=y(e,i,t);null!=s&&o.push(s)}),o}if(c(e)){const r=e.component.trim(),o=r.indexOf("."),i=o>0?f(r,o,n):d(r,n),{Component:s,propsSpec:p,compoundKey:c}=i;if(s&&c&&n.parentKey){const e=n.parentKey.split(".")[0],t=l(e),o=n.componentMap.get(t),i=m(n.parentKey,c,o);if(i)return n.disallowedChildren.push({path:n.path,parent:n.parentKey,child:c,reason:i.reason,message:i.message}),n.warnings.push(`${r} 은(는) ${n.parentKey} 안에서 사용할 수 없음: ${i.message}`),null}if(!s){const e=o>0?"unknown_subcomponent":"unknown_component";return n.unknownChildren.push({path:n.path,component:r,reason:e}),n.warnings.push("unknown_subcomponent"===e?`'${r}' 은(는) 알 수 없는 sub-component. get_component_props 로 subComponents 확인 후 정정.`:`'${r}' 은(는) 알 수 없는 component. list_components 로 정식 이름 확인 후 정정.`),null}const a=e.props??{},u=$(a),g=p?b(u,p):u,j=void 0!==e.children?e.children:g.children;if(void 0!==j){const e={...n,parentKey:c??n.parentKey,path:`${n.path}>${r}`};g.children=y(j,e,t+1)}const O=h(g,n.iconBundle,p);return n.reactRuntime.createElement(s,O)}return e},$=e=>Object.fromEntries(Object.entries(e).filter(([e])=>!o.has(e))),b=(e,n)=>{const t=new Set([...Object.keys(n),"children"]);return Object.fromEntries(Object.entries(e).filter(([e])=>t.has(e)))},g=(e,n,t,r=0)=>{if(r>6)return e;if(!n)return e;if("icon-component"===n.semantic&&"string"==typeof e){const n=t[e];return"function"==typeof n?n:e}if(n.rawType?.includes("[]")&&n.properties&&Array.isArray(e))return e.map(e=>{if(e&&"object"==typeof e&&!Array.isArray(e)){const o={...e};for(const[e,i]of Object.entries(n.properties))e in o&&(o[e]=g(o[e],i,t,r+1));return o}return e});if(n.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const o={...e};for(const[e,i]of Object.entries(n.properties))e in o&&(o[e]=g(o[e],i,t,r+1));return o}return e},h=(e,n,t)=>{if(!t)return e;const r={...e};for(const[e,o]of Object.entries(t))e in r&&(r[e]=g(r[e],o,n));return r},j=e=>e.replace(/"/g,"""),O=(e,n,t=0)=>{if(t>6)return JSON.stringify(e);if("icon-component"===n?.semantic&&"string"==typeof e)return e;if(n?.rawType?.includes("[]")&&n.properties&&Array.isArray(e))return`[${e.map(e=>{if(e&&"object"==typeof e&&!Array.isArray(e)){const r=e;return`{ ${Object.entries(r).map(([e,r])=>{const o=n.properties?.[e];return`${e}: ${O(r,o,t+1)}`}).join(", ")} }`}return JSON.stringify(e)}).join(", ")}]`;if(n?.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const r=e;return`{ ${Object.entries(r).map(([e,r])=>{const o=n.properties?.[e];return`${e}: ${O(r,o,t+1)}`}).join(", ")} }`}return JSON.stringify(e)},v=(e,n,t)=>"boolean"==typeof n&&n?e:"icon-component"===t?.semantic&&"string"==typeof n?`${e}={${n}}`:t?.rawType?.includes("[]")&&t.properties&&Array.isArray(n)||t?.properties&&n&&"object"==typeof n&&!Array.isArray(n)?`${e}={${O(n,t)}}`:"string"==typeof n?`${e}="${j(n)}"`:"number"==typeof n?`${e}={${n}}`:"enum"===t?.type||"string"===t?.type?`${e}="${String(n)}"`:`${e}={${JSON.stringify(n)}}`,w=(e,n)=>Object.entries(e).filter(([e])=>"children"!==e).map(([e,t])=>v(e,t,n[e])).join(" "),A=(e,n,t,r=0)=>{if(!(r>6)&&n)if("icon-component"===n.semantic&&"string"==typeof e&&e.length>0)t.add(e);else if(n.rawType?.includes("[]")&&n.properties&&Array.isArray(e)){for(const o of e)if(o&&"object"==typeof o&&!Array.isArray(o)){const e=o;for(const[o,i]of Object.entries(n.properties))o in e&&A(e[o],i,t,r+1)}}else if(n.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const o=e;for(const[e,i]of Object.entries(n.properties))e in o&&A(o[e],i,t,r+1)}},x=(e,n)=>{if(!n)return[];const t=new Set;for(const[r,o]of Object.entries(n))r in e&&A(e[r],o,t);return[...t]},N=(e,n,t)=>{const r=t.values??[];return`Invalid enum value '${n}' for prop '${e}'.${void 0!==t.default?` Corrected to default '${t.default}'.`:" Removed (no default)."} Allowed: ${r.join(", ")}.`},C=(e,n)=>[...Object.entries(n).filter(([n,t])=>t.required&&!(n in e)).map(([e])=>`Required prop '${e}' is missing.`),...Object.entries(e).filter(([e,t])=>{const r=n[e];return"enum"===r?.type&&r.values&&"string"==typeof t&&!r.values.includes(t)}).map(([e,t])=>N(e,t,n[e])),...Object.entries(n).filter(([n,t])=>t.rawType?.includes("[]")&&!(n in e)).map(([e])=>`Array prop '${e}' is missing. Filled with empty array []. Pass data for meaningful rendering.`)],k=(e,n)=>{const t={...e};for(const[e,r]of Object.entries(t)){const o=n[e];"enum"===o?.type&&o.values&&"string"==typeof r&&(o.values.includes(r)||(void 0!==o.default?t[e]=o.default:delete t[e]))}return t},S=(e,n)=>{const t={...e};for(const[e,r]of Object.entries(n)){if(r.rawType?.includes("[]")&&(!(e in t)||!Array.isArray(t[e]))){t[e]=[];continue}if(!r.required||e in t)continue;if(void 0!==r.default){t[e]=r.default;continue}if("icon-component"===r.semantic){t[e]=()=>null;continue}if("function"===r.type||"ReactNode"===r.type)continue;const n={string:"",object:{},boolean:!1,number:0,enum:r.values?.[0]??""};r.type in n&&(t[e]=n[r.type])}return t},P=e=>JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),E=(e,n,t)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const wrapper = document.querySelector('#${e}');`,` new ncua.${n}(wrapper, ${P(t)});`," });","<\/script>"].join("\n"),_=(e,n,t)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` new ncua.${n}(${P({...t,container:e})});`," });","<\/script>"].join("\n"),M=(e,n,t)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const wrapper = document.querySelector('#${e}');`,` const inst = new ncua.${n}(${P(t)});`," wrapper.appendChild(inst.getElement());"," });","<\/script>"].join("\n"),D=(e,n,t)=>[`<div id="${e}">`,n,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const tbody = document.querySelector('#${e} tbody');`,` if (tbody) new window.ncua.${t}(tbody, {`," onDrop: function(fromId, toId, edge) {"," // TODO: 순서 업데이트 처리 (fromId 행을 toId 행의 edge 방향으로 이동)"," }"," });"," });","<\/script>","</div>"].join("\n"),R=(e,n,t,r,o)=>{const i=`ncua-${n}-${t}`;return"A"===e?E(i,r,o):"B"===e?_(i,r,o):M(i,r,o)},q=(e,n)=>{if(0===Object.keys(n.constructorParams).length)return[];const t=new Set;for(const e of Object.keys(n.constructorParams)){const n=e.lastIndexOf(".");t.add(n>=0?e.slice(n+1):e)}return Object.keys(e).filter(e=>!t.has(e)).map(e=>`Unknown CDN option key '${e}' for component '${n.className}'. Passed through as-is. Verify against constructorParams.`)},I=(e,n)=>{if("select-box"!==e&&"combo-box"!==e)return{normalized:n,warnings:[]};const{options:t}=n;if(!Array.isArray(t))return{normalized:n,warnings:[]};const r=new Set,o=t.map(e=>{if(null===e||"object"!=typeof e)return e;const n={...e};return void 0===n.id&&void 0!==n.value&&(n.id=n.value,delete n.value,r.add("value")),void 0===n.label&&void 0!==n.text&&(n.label=n.text,delete n.text,r.add("text")),n}),i=[];return r.has("value")&&i.push(`Option key 'value' normalized to 'id' for component '${e}'. Canonical form is {id, label}.`),r.has("text")&&i.push(`Option key 'text' normalized to 'label' for component '${e}'. Canonical form is {id, label}.`),{normalized:{...n,options:o},warnings:i}},L=e=>{if("function"!=typeof e)return Array.isArray(e)?e.map(e=>(0,exports.stripFunctionProps)(e)).filter(e=>void 0!==e):"object"==typeof e&&null!==e?Object.fromEntries(Object.entries(e).filter(([,e])=>"function"!=typeof e).map(([e,n])=>[e,(0,exports.stripFunctionProps)(n)])):e};exports.stripFunctionProps=L;const T=(n,t,r)=>{if(!t)return{merged:r,defaultsApplied:[]};const o=(0,exports.stripFunctionProps)(r),i=(0,e.merge)((0,e.cloneDeep)(t),o);return{merged:["date-picker","range-date-picker","range-date-picker-with-buttons"].includes(n)&&Array.isArray(o.datePickerOptions)?{...i,datePickerOptions:o.datePickerOptions.map(n=>{const r=t.datePickerOptions?.[0]?.options??{};return{...n,options:(0,e.merge)((0,e.cloneDeep)(r),n.options??{})}})}:i,defaultsApplied:Object.keys(t).filter(e=>!(e in o))}};exports.mergeCdnDefaults=T;const z=(e,n)=>{if("select-box"===e||"combo-box"===e){const{options:e,value:t,...r}=n,o={...r};if(void 0!==e&&(o.optionItems=e),void 0!==t)if("string"!=typeof t&&"number"!=typeof t||!Array.isArray(e))o.value=t;else{const n=e.find(e=>"object"==typeof e&&null!==e&&e.id===t);o.value=void 0!==n?n:t}return o}if("file-input"===e||"image-file-input"===e){const e={...n};return delete e.container,e}return n},K=(e,n)=>Object.fromEntries(Object.entries(e).filter(([e,t])=>void 0!==t.default&&!(e in n)).map(([e,n])=>[e,n.default])),F=(e,t)=>{const r=e.indexOf(".");if(r>0){const n=e.slice(0,r).toLowerCase(),o=e.slice(r+1),i=t.get(n);if(!i?.exportName)return;const s=`${i.exportName}.${u(o)}`;return i.subComponents?.[s]?.props}return t.get((0,n.normalizeName)(e))?.props},J=(e,n)=>{if(null==e)return"";if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e)return String(e);if(Array.isArray(e))return e.map(e=>J(e,n)).join("\n");if("object"==typeof e&&"component"in e){const t=e,r=t.component.trim(),o=r.split(".").map(u).join("."),i=F(r,n.componentMap);if(i&&t.props)for(const[e,r]of Object.entries(i))e in t.props&&A(t.props[e],r,n.iconNames);const{children:s,...p}=t.props||{},c=Object.entries(p).filter(([,e])=>void 0!==e).map(([e,n])=>v(e,n,i?.[e])).join(" "),a=c?` ${c}`:"",l=t.children??s;return null!=l?`<${o}${a}>${J(l,n)}</${o}>`:`<${o}${a} />`}if("object"==typeof e&&"type"in e){const t=e,r="string"==typeof t.type?t.type:"function"==typeof t.type&&(t.type.displayName||t.type.name)||"Component",{children:o,...i}=t.props||{},s=Object.entries(i).filter(([,e])=>void 0!==e).map(([e,n])=>"boolean"==typeof n&&n?e:"string"==typeof n?`${e}="${n}"`:`${e}={${JSON.stringify(n)}}`).join(" "),p=s?` ${s}`:"";return null!=o?`<${r}${p}>${J(o,n)}</${r}>`:`<${r}${p} />`}return String(e)},B=(e,n,t,r)=>{const{exportName:o,importPath:i,props:s}=e,p=[i],c=new Set(x(n,s)),a=s?w(n,s):"",u=a?" "+a:"",l=n.children,d=l?`<${o}${u}>${J(l,{componentMap:r,iconNames:c})}</${o}>`:`<${o}${u} />`,f=[`import { ${o} } from '${i}';`];return c.size>0&&t&&(f.push(`import { ${[...c].join(", ")} } from '${t.packageName}';`),p.includes(t.packageName)||p.push(t.packageName)),{imports:f,jsx:d,cssImport:`import '${i}/style.css';`,dependencies:p}},U=(e,n)=>({...e&&{"@ncds/ui-admin":e.version},...n&&{[n.packageName]:n.version}}),G=(e,n)=>{if(!e.jsRequired)return{required:!1};const t=n.get(e.exportName);return{required:!0,description:"이 컴포넌트는 인터랙션을 위해 CDN JS가 필요합니다",...t&&{api:{className:t.className,constructor:t.constructor,constructorParams:t.constructorParams,methods:t.methods,example:t.example}}}};exports.buildJsField=G;const H=e=>{const{componentMap:o,bundle:i,iconBundle:s,cdnMeta:p,iconMeta:c,reactRuntime:a,jsApiMap:u,name:l,props:d,instanceId:f}=e,m=(0,n.normalizeName)(l);if((0,t.isEditorAlias)(m))return(0,t.buildEditorResponse)(d??{},f);if((0,r.isStepGuideAlias)(m))return(0,r.buildStepGuideResponse)(d??{},f);const g=o.get(m);if(!g)return(0,n.componentNotFoundResponse)(m);const j=g.exportName;if(!j)return(0,n.errorResponse)("EXPORT_NAME_MISSING",`'${m}' 컴포넌트에 exportName이 없습니다.`,"데이터를 재추출해주세요 (pnpm extract).");const O=i[j]??null;if(!O)return(0,n.errorResponse)("COMPONENT_NOT_IN_BUNDLE",`'${m}' (${j}) 컴포넌트가 번들에 없습니다.`,"번들을 재빌드해주세요 (pnpm build:bundle).");try{const e=u.get(j),t=g.jsRequired&&void 0!==e&&void 0!==e.cdnPattern,r=t?I(m,d??{}):{normalized:d??{},warnings:[]},l=r.normalized,v=t&&e?(0,exports.mergeCdnDefaults)(m,e.cdnDefaults,l):{merged:l,defaultsApplied:[]},w=v.merged,A=t?z(m,w):w,x=$(A),N=g.props?b(x,g.props):x,P=g.props?C(N,g.props):[],E=g.props?k(N,g.props):N,_=g.props?S(E,g.props):E,M=g.props?C(_,g.props):[],L=t&&e?q(l,e):[],T=[...P,...M.filter(e=>!P.includes(e)),...L,...r.warnings],F=h(_,s,g.props),J={bundle:i,iconBundle:s,componentMap:o,reactRuntime:a,warnings:[],unknownChildren:[],disallowedChildren:[],parentKey:j,path:m};if((void 0!==F.children||g.props)&&(void 0!==F.children&&(F.children=y(F.children,J,0)),g.props))for(const[e,n]of Object.entries(g.props)){if("children"===e)continue;if("ReactNode"!==n.type)continue;const t=F[e];null!=t&&"string"!=typeof t&&"number"!=typeof t&&"boolean"!=typeof t&&(F[e]=y(t,J,0))}const G="D"===e?.cdnPattern,H=t&&e?.cdnPattern&&!G?R(e.cdnPattern,m,f,e.className,$(w)):null,V=()=>`\x3c!-- ncua:${m} start --\x3e\n${a.renderToStaticMarkup(a.createElement(O,F))}\n\x3c!-- ncua:${m} end --\x3e`,X=null!==H?H:G&&e?D(`ncua-${m}-${f}`,V(),e.className):V(),Z=!0!==g.jsRequired&&g.props?K(g.props,_):{},Q=t&&e?.cdnDefaults?Object.fromEntries(v.defaultsApplied.map(n=>[n,e.cdnDefaults?.[n]])):{},W={...Z,...Q},Y=[...T,...J.warnings];return(0,n.successResponse)({html:X,component:m,exportName:j,importPath:g.importPath,appliedProps:_,...Object.keys(W).length>0&&{defaultsUsed:W},...Y.length>0&&{warnings:Y},...J.unknownChildren.length>0&&{unknownChildren:J.unknownChildren},...J.disallowedChildren.length>0&&{disallowedChildren:J.disallowedChildren},js:(0,exports.buildJsField)(g,u),cdn:p??void 0,dataVersion:U(p,c),react:B(g,_,c,o)})}catch(e){const t=g.props?C(d??{},g.props):[],r=g.usageExamples?"get_component_props로 usageExamples를 확인하고 해당 props로 재시도하세요.":"사용 가능한 속성을 확인하려면 get_component_props를 사용하세요.";return(0,n.errorResponse)("RENDER_FAILED",`'${m}' 렌더링 실패: ${(0,n.toErrorMessage)(e)}`,r,t.length>0?t:void 0)}};exports.renderToHtml=H;
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.renderToHtml=exports.buildJsField=exports.mergeCdnDefaults=exports.stripFunctionProps=void 0;const e=require("lodash"),t=require("../utils/response.js"),n=require("./external/editor.js"),r=require("./external/step-guide.js"),o=new Set(["dangerouslySetInnerHTML","ref","__self","__source"]),i=5,s=30,p=new Set(["div","span","section","article","aside","header","footer","main","nav","ul","ol","li","dl","dt","dd","p","h1","h2","h3","h4","h5","h6","figure","figcaption","blockquote","strong","em","small","time","abbr","mark"]),a=new Set(["className","id","role","title","lang","dir","dateTime","start"]),c=["aria-","data-"],l=6,u=e=>"object"==typeof e&&null!==e&&"string"==typeof e.component,d=e=>e.charAt(0).toUpperCase()+e.slice(1),f=e=>e.split("-").map(d).join(""),m=e=>e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),y=(e,n)=>{const r=(0,t.normalizeName)(e),o=n.componentMap.get(r);return{Component:o?.exportName?n.bundle[o.exportName]??null:null,propsSpec:o?.props,compoundKey:null}},$=(e,t,n)=>{const r=e.slice(0,t).toLowerCase(),o=e.slice(t+1),i=n.componentMap.get(r),s=i?.exportName;if(!s)return{Component:null,propsSpec:void 0,compoundKey:null};const p=n.bundle[s],a=f(o),c=p?.[a]??null,l=`${s}.${a}`,u=i?.subComponents?.[l]?.props;return{Component:c,propsSpec:u,compoundKey:l}},b=(e,t,n)=>{const r=n?.allowedChildren?.[e];if(!r||Array.isArray(r))return null;const o=r.forbiddenInContext;if(!o)return null;const i=o[t];return i?{reason:"forbidden_in_context",message:i}:null},g=(e,t,n)=>{if(n>5)return null;if("string"==typeof e||"number"==typeof e||"boolean"==typeof e)return e;if(Array.isArray(e)){const r=e.slice(0,s),o=[];return r.forEach((e,r)=>{const i={...t,path:`${t.path}[${r}]`},s=g(e,i,n);null!=s&&o.push(s)}),o}if(u(e)){const r=e.component.trim();if(p.has(r)){const o=e.props??{},i=h(o),s=v(i,r,t.warnings),p=void 0!==e.children?e.children:s.children,a={...s};if(delete a.children,void 0!==p){const e={...t,path:`${t.path}>${r}`};a.children=g(p,e,n+1)}return t.reactRuntime.createElement(r,a)}const o=r.indexOf("."),i=o>0?$(r,o,t):y(r,t),{Component:s,propsSpec:a,compoundKey:c}=i;if(s&&c&&t.parentKey){const e=t.parentKey.split(".")[0],n=m(e),o=t.componentMap.get(n),i=b(t.parentKey,c,o);if(i)return t.disallowedChildren.push({path:t.path,parent:t.parentKey,child:c,reason:i.reason,message:i.message}),t.warnings.push(`${r} 은(는) ${t.parentKey} 안에서 사용할 수 없음: ${i.message}`),null}if(!s){const e=o>0?"unknown_subcomponent":"unknown_component";return t.unknownChildren.push({path:t.path,component:r,reason:e}),t.warnings.push("unknown_subcomponent"===e?`'${r}' 은(는) 알 수 없는 sub-component. get_component_props 로 subComponents 확인 후 정정.`:`'${r}' 은(는) 알 수 없는 component. list_components 로 정식 이름 확인 후 정정.`),null}const l=e.props??{},u=h(l),d=a?j(u,a):u,f=void 0!==e.children?e.children:d.children;if(void 0!==f){const e={...t,parentKey:c??t.parentKey,path:`${t.path}>${r}`};d.children=g(f,e,n+1)}const O=A(d,t.iconBundle,a);return t.reactRuntime.createElement(s,O)}return e},h=e=>Object.fromEntries(Object.entries(e).filter(([e])=>!o.has(e))),j=(e,t)=>{const n=new Set([...Object.keys(t),"children"]);return Object.fromEntries(Object.entries(e).filter(([e])=>n.has(e)))},O=e=>"children"===e||a.has(e)||c.some(t=>e.startsWith(t)),v=(e,t,n)=>{const r=Object.keys(e).filter(e=>!O(e));return r.length>0&&n.push(`<${t}> 의 prop ${r.map(e=>`'${e}'`).join(", ")} 은(는) 허용되지 않아 제거됨 — 네이티브 태그는 className/id/role/title/lang/dir/aria-*/data-* 만 허용한다. 레이아웃·스타일은 ncua-* BEM 클래스로 지정하고, 동작이 필요하면 NCDS 컴포넌트를 사용할 것.`),Object.fromEntries(Object.entries(e).filter(([e])=>O(e)))},w=(e,t,n,r=0)=>{if(r>6)return e;if(!t)return e;if("icon-component"===t.semantic&&"string"==typeof e){const t=n[e];return"function"==typeof t?t:e}if(t.rawType?.includes("[]")&&t.properties&&Array.isArray(e))return e.map(e=>{if(e&&"object"==typeof e&&!Array.isArray(e)){const o={...e};for(const[e,i]of Object.entries(t.properties))e in o&&(o[e]=w(o[e],i,n,r+1));return o}return e});if(t.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const o={...e};for(const[e,i]of Object.entries(t.properties))e in o&&(o[e]=w(o[e],i,n,r+1));return o}return e},A=(e,t,n)=>{if(!n)return e;const r={...e};for(const[e,o]of Object.entries(n))e in r&&(r[e]=w(r[e],o,t));return r},x=e=>e.replace(/"/g,"""),N=(e,t,n=0)=>{if(n>6)return JSON.stringify(e);if("icon-component"===t?.semantic&&"string"==typeof e)return e;if(t?.rawType?.includes("[]")&&t.properties&&Array.isArray(e))return`[${e.map(e=>{if(e&&"object"==typeof e&&!Array.isArray(e)){const r=e;return`{ ${Object.entries(r).map(([e,r])=>{const o=t.properties?.[e];return`${e}: ${N(r,o,n+1)}`}).join(", ")} }`}return JSON.stringify(e)}).join(", ")}]`;if(t?.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const r=e;return`{ ${Object.entries(r).map(([e,r])=>{const o=t.properties?.[e];return`${e}: ${N(r,o,n+1)}`}).join(", ")} }`}return JSON.stringify(e)},C=(e,t,n)=>"boolean"==typeof t&&t?e:"icon-component"===n?.semantic&&"string"==typeof t?`${e}={${t}}`:n?.rawType?.includes("[]")&&n.properties&&Array.isArray(t)||n?.properties&&t&&"object"==typeof t&&!Array.isArray(t)?`${e}={${N(t,n)}}`:"string"==typeof t?`${e}="${x(t)}"`:"number"==typeof t?`${e}={${t}}`:"enum"===n?.type||"string"===n?.type?`${e}="${String(t)}"`:`${e}={${JSON.stringify(t)}}`,k=(e,t)=>Object.entries(e).filter(([e])=>"children"!==e).map(([e,n])=>C(e,n,t[e])).join(" "),S=(e,t,n,r=0)=>{if(!(r>6)&&t)if("icon-component"===t.semantic&&"string"==typeof e&&e.length>0)n.add(e);else if(t.rawType?.includes("[]")&&t.properties&&Array.isArray(e)){for(const o of e)if(o&&"object"==typeof o&&!Array.isArray(o)){const e=o;for(const[o,i]of Object.entries(t.properties))o in e&&S(e[o],i,n,r+1)}}else if(t.properties&&e&&"object"==typeof e&&!Array.isArray(e)){const o=e;for(const[e,i]of Object.entries(t.properties))e in o&&S(o[e],i,n,r+1)}},E=(e,t)=>{if(!t)return[];const n=new Set;for(const[r,o]of Object.entries(t))r in e&&S(e[r],o,n);return[...n]},P=(e,t,n)=>{const r=n.values??[];return`Invalid enum value '${t}' for prop '${e}'.${void 0!==n.default?` Corrected to default '${n.default}'.`:" Removed (no default)."} Allowed: ${r.join(", ")}.`},_=(e,t)=>[...Object.entries(t).filter(([t,n])=>n.required&&!(t in e)).map(([e])=>`Required prop '${e}' is missing.`),...Object.entries(e).filter(([e,n])=>{const r=t[e];return"enum"===r?.type&&r.values&&"string"==typeof n&&!r.values.includes(n)}).map(([e,n])=>P(e,n,t[e])),...Object.entries(t).filter(([t,n])=>n.rawType?.includes("[]")&&!(t in e)).map(([e])=>`Array prop '${e}' is missing. Filled with empty array []. Pass data for meaningful rendering.`)],M=(e,t)=>{const n={...e};for(const[e,r]of Object.entries(n)){const o=t[e];"enum"===o?.type&&o.values&&"string"==typeof r&&(o.values.includes(r)||(void 0!==o.default?n[e]=o.default:delete n[e]))}return n},D=(e,t)=>{const n={...e};for(const[e,r]of Object.entries(t)){if(r.rawType?.includes("[]")&&(!(e in n)||!Array.isArray(n[e]))){n[e]=[];continue}if(!r.required||e in n)continue;if(void 0!==r.default){n[e]=r.default;continue}if("icon-component"===r.semantic){n[e]=()=>null;continue}if("function"===r.type||"ReactNode"===r.type)continue;const t={string:"",object:{},boolean:!1,number:0,enum:r.values?.[0]??""};r.type in t&&(n[e]=t[r.type])}return n},R=e=>JSON.stringify(e).replace(/<\/script/gi,"<\\/script"),q=(e,t,n)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const wrapper = document.querySelector('#${e}');`,` new ncua.${t}(wrapper, ${R(n)});`," });","<\/script>"].join("\n"),I=(e,t,n)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` new ncua.${t}(${R({...n,container:e})});`," });","<\/script>"].join("\n"),T=(e,t,n)=>[`<div id="${e}"></div>`,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const wrapper = document.querySelector('#${e}');`,` const inst = new ncua.${t}(${R(n)});`," wrapper.appendChild(inst.getElement());"," });","<\/script>"].join("\n"),L=(e,t,n)=>[`<div id="${e}">`,t,"<script>"," document.addEventListener('DOMContentLoaded', function () {",` const tbody = document.querySelector('#${e} tbody');`,` if (tbody) new window.ncua.${n}(tbody, {`," onDrop: function(fromId, toId, edge) {"," // TODO: 순서 업데이트 처리 (fromId 행을 toId 행의 edge 방향으로 이동)"," }"," });"," });","<\/script>","</div>"].join("\n"),z=(e,t,n,r,o)=>{const i=`ncua-${t}-${n}`;return"A"===e?q(i,r,o):"B"===e?I(i,r,o):T(i,r,o)},K=(e,t)=>{if(0===Object.keys(t.constructorParams).length)return[];const n=new Set;for(const e of Object.keys(t.constructorParams)){const t=e.lastIndexOf(".");n.add(t>=0?e.slice(t+1):e)}return Object.keys(e).filter(e=>!n.has(e)).map(e=>`Unknown CDN option key '${e}' for component '${t.className}'. Passed through as-is. Verify against constructorParams.`)},F=(e,t)=>{if("select-box"!==e&&"combo-box"!==e)return{normalized:t,warnings:[]};const{options:n}=t;if(!Array.isArray(n))return{normalized:t,warnings:[]};const r=new Set,o=n.map(e=>{if(null===e||"object"!=typeof e)return e;const t={...e};return void 0===t.id&&void 0!==t.value&&(t.id=t.value,delete t.value,r.add("value")),void 0===t.label&&void 0!==t.text&&(t.label=t.text,delete t.text,r.add("text")),t}),i=[];return r.has("value")&&i.push(`Option key 'value' normalized to 'id' for component '${e}'. Canonical form is {id, label}.`),r.has("text")&&i.push(`Option key 'text' normalized to 'label' for component '${e}'. Canonical form is {id, label}.`),{normalized:{...t,options:o},warnings:i}},J=e=>{if("function"!=typeof e)return Array.isArray(e)?e.map(e=>(0,exports.stripFunctionProps)(e)).filter(e=>void 0!==e):"object"==typeof e&&null!==e?Object.fromEntries(Object.entries(e).filter(([,e])=>"function"!=typeof e).map(([e,t])=>[e,(0,exports.stripFunctionProps)(t)])):e};exports.stripFunctionProps=J;const B=(t,n,r)=>{if(!n)return{merged:r,defaultsApplied:[]};const o=(0,exports.stripFunctionProps)(r),i=(0,e.merge)((0,e.cloneDeep)(n),o);return{merged:["date-picker","range-date-picker","range-date-picker-with-buttons"].includes(t)&&Array.isArray(o.datePickerOptions)?{...i,datePickerOptions:o.datePickerOptions.map(t=>{const r=n.datePickerOptions?.[0]?.options??{};return{...t,options:(0,e.merge)((0,e.cloneDeep)(r),t.options??{})}})}:i,defaultsApplied:Object.keys(n).filter(e=>!(e in o))}};exports.mergeCdnDefaults=B;const U=(e,t)=>{if("select-box"===e||"combo-box"===e){const{options:e,value:n,...r}=t,o={...r};if(void 0!==e&&(o.optionItems=e),void 0!==n)if("string"!=typeof n&&"number"!=typeof n||!Array.isArray(e))o.value=n;else{const t=e.find(e=>"object"==typeof e&&null!==e&&e.id===n);o.value=void 0!==t?t:n}return o}if("file-input"===e||"image-file-input"===e){const e={...t};return delete e.container,e}return t},G=(e,t)=>Object.fromEntries(Object.entries(e).filter(([e,n])=>void 0!==n.default&&!(e in t)).map(([e,t])=>[e,t.default])),H=(e,n)=>{const r=e.indexOf(".");if(r>0){const t=e.slice(0,r).toLowerCase(),o=e.slice(r+1),i=n.get(t);if(!i?.exportName)return;const s=`${i.exportName}.${f(o)}`;return i.subComponents?.[s]?.props}return n.get((0,t.normalizeName)(e))?.props},V=(e,t)=>{if(null==e)return"";if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e)return String(e);if(Array.isArray(e))return e.map(e=>V(e,t)).join("\n");if("object"==typeof e&&"component"in e){const n=e,r=n.component.trim(),o=p.has(r),i=o?r:r.split(".").map(f).join("."),s=H(r,t.componentMap);if(s&&n.props)for(const[e,r]of Object.entries(s))e in n.props&&S(n.props[e],r,t.iconNames);const{children:a,...c}=n.props||{},l=o?Object.fromEntries(Object.entries(c).filter(([e])=>O(e))):c,u=Object.entries(l).filter(([,e])=>void 0!==e).map(([e,t])=>C(e,t,s?.[e])).join(" "),d=u?` ${u}`:"",m=n.children??a;return null!=m?`<${i}${d}>${V(m,t)}</${i}>`:`<${i}${d} />`}if("object"==typeof e&&"type"in e){const n=e,r="string"==typeof n.type?n.type:"function"==typeof n.type&&(n.type.displayName||n.type.name)||"Component",{children:o,...i}=n.props||{},s=Object.entries(i).filter(([,e])=>void 0!==e).map(([e,t])=>"boolean"==typeof t&&t?e:"string"==typeof t?`${e}="${t}"`:`${e}={${JSON.stringify(t)}}`).join(" "),p=s?` ${s}`:"";return null!=o?`<${r}${p}>${V(o,t)}</${r}>`:`<${r}${p} />`}return String(e)},W=(e,t,n,r)=>{const{exportName:o,importPath:i,props:s}=e,p=[i],a=new Set(E(t,s)),c=s?k(t,s):"",l=c?" "+c:"",u=t.children,d=u?`<${o}${l}>${V(u,{componentMap:r,iconNames:a})}</${o}>`:`<${o}${l} />`,f=[`import { ${o} } from '${i}';`];return a.size>0&&n&&(f.push(`import { ${[...a].join(", ")} } from '${n.packageName}';`),p.includes(n.packageName)||p.push(n.packageName)),{imports:f,jsx:d,cssImport:`import '${i}/style.css';`,dependencies:p}},X=(e,t)=>({...e&&{"@ncds/ui-admin":e.version},...t&&{[t.packageName]:t.version}}),Z=(e,t)=>{if(!e.jsRequired)return{required:!1};const n=t.get(e.exportName);return{required:!0,description:"이 컴포넌트는 인터랙션을 위해 CDN JS가 필요합니다",...n&&{api:{className:n.className,constructor:n.constructor,constructorParams:n.constructorParams,methods:n.methods,example:n.example}}}};exports.buildJsField=Z;const Q=e=>{const{componentMap:o,bundle:i,iconBundle:s,cdnMeta:p,iconMeta:a,reactRuntime:c,jsApiMap:l,name:u,props:d,instanceId:f}=e,m=(0,t.normalizeName)(u);if((0,n.isEditorAlias)(m))return(0,n.buildEditorResponse)(d??{},f);if((0,r.isStepGuideAlias)(m))return(0,r.buildStepGuideResponse)(d??{},f);const y=o.get(m);if(!y)return(0,t.componentNotFoundResponse)(m);const $=y.exportName;if(!$)return(0,t.errorResponse)("EXPORT_NAME_MISSING",`'${m}' 컴포넌트에 exportName이 없습니다.`,"데이터를 재추출해주세요 (pnpm extract).");const b=i[$]??null;if(!b)return(0,t.errorResponse)("COMPONENT_NOT_IN_BUNDLE",`'${m}' (${$}) 컴포넌트가 번들에 없습니다.`,"번들을 재빌드해주세요 (pnpm build:bundle).");try{const e=l.get($),n=y.jsRequired&&void 0!==e&&void 0!==e.cdnPattern,r=n?F(m,d??{}):{normalized:d??{},warnings:[]},u=r.normalized,O=n&&e?(0,exports.mergeCdnDefaults)(m,e.cdnDefaults,u):{merged:u,defaultsApplied:[]},v=O.merged,w=n?U(m,v):v,x=h(w),N=y.props?j(x,y.props):x,C=y.props?_(N,y.props):[],k=y.props?M(N,y.props):N,S=y.props?D(k,y.props):k,E=y.props?_(S,y.props):[],P=n&&e?K(u,e):[],R=[...C,...E.filter(e=>!C.includes(e)),...P,...r.warnings],q=A(S,s,y.props),I={bundle:i,iconBundle:s,componentMap:o,reactRuntime:c,warnings:[],unknownChildren:[],disallowedChildren:[],parentKey:$,path:m};if((void 0!==q.children||y.props)&&(void 0!==q.children&&(q.children=g(q.children,I,0)),y.props))for(const[e,t]of Object.entries(y.props)){if("children"===e)continue;if("ReactNode"!==t.type)continue;const n=q[e];null!=n&&"string"!=typeof n&&"number"!=typeof n&&"boolean"!=typeof n&&(q[e]=g(n,I,0))}const T="D"===e?.cdnPattern,J=n&&e?.cdnPattern&&!T?z(e.cdnPattern,m,f,e.className,h(v)):null,B=()=>`\x3c!-- ncua:${m} start --\x3e\n${c.renderToStaticMarkup(c.createElement(b,q))}\n\x3c!-- ncua:${m} end --\x3e`,H=null!==J?J:T&&e?L(`ncua-${m}-${f}`,B(),e.className):B(),V=!0!==y.jsRequired&&y.props?G(y.props,S):{},Z=n&&e?.cdnDefaults?Object.fromEntries(O.defaultsApplied.map(t=>[t,e.cdnDefaults?.[t]])):{},Q={...V,...Z},Y=[...R,...I.warnings];return(0,t.successResponse)({html:H,component:m,exportName:$,importPath:y.importPath,appliedProps:S,...Object.keys(Q).length>0&&{defaultsUsed:Q},...Y.length>0&&{warnings:Y},...I.unknownChildren.length>0&&{unknownChildren:I.unknownChildren},...I.disallowedChildren.length>0&&{disallowedChildren:I.disallowedChildren},js:(0,exports.buildJsField)(y,l),cdn:p??void 0,dataVersion:X(p,a),react:W(y,S,a,o)})}catch(e){const n=y.props?_(d??{},y.props):[],r=y.usageExamples?"get_component_props로 usageExamples를 확인하고 해당 props로 재시도하세요.":"사용 가능한 속성을 확인하려면 get_component_props를 사용하세요.";return(0,t.errorResponse)("RENDER_FAILED",`'${m}' 렌더링 실패: ${(0,t.toErrorMessage)(e)}`,r,n.length>0?n:void 0)}};exports.renderToHtml=Q;
|
package/bin/version.d.ts
CHANGED
package/bin/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.VERSION=void 0,exports.VERSION="1.8.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.VERSION=void 0,exports.VERSION="1.8.17";
|
package/data/_tokens.json
CHANGED
package/data/file-input.json
CHANGED
|
@@ -21,18 +21,22 @@
|
|
|
21
21
|
"hintText",
|
|
22
22
|
"hintItems",
|
|
23
23
|
"destructive",
|
|
24
|
+
"showFileTags",
|
|
25
|
+
"파일목록직접렌더링",
|
|
24
26
|
"NCDS"
|
|
25
27
|
],
|
|
26
28
|
"hasChildren": false,
|
|
27
29
|
"whenToUse": [
|
|
28
|
-
"FileInput은 제한 정책 안내문을 항상 노출하며, 파일명 텍스트 중심 UI를 기본으로 하고, 삭제 기능을 필수 제공합니다"
|
|
30
|
+
"FileInput은 제한 정책 안내문을 항상 노출하며, 파일명 텍스트 중심 UI를 기본으로 하고, 삭제 기능을 필수 제공합니다",
|
|
31
|
+
"파일 목록 UI를 직접 렌더링해야 할 때만 showFileTags={false}로 내장 목록을 끕니다. 이때 파일명 표시와 삭제 수단은 직접 제공해야 합니다"
|
|
29
32
|
],
|
|
30
33
|
"forbiddenRules": [
|
|
31
34
|
"제한 정책 안내 없이 업로드 허용 금지",
|
|
32
35
|
"최대 등록 수 초과 시 무반응 처리 금지",
|
|
33
36
|
"파일명 34자 초과 그대로 노출 금지",
|
|
34
37
|
"단일 파일 영역에서 다중 파일 누적 금지",
|
|
35
|
-
"삭제 기능 없는 업로드 UI 제공 금지"
|
|
38
|
+
"삭제 기능 없는 업로드 UI 제공 금지",
|
|
39
|
+
"showFileTags={false}로 내장 목록을 끈 뒤 파일명·삭제 UI를 대체 제공하지 않는 것 금지"
|
|
36
40
|
],
|
|
37
41
|
"seeAlso": [
|
|
38
42
|
"button",
|
|
@@ -190,6 +194,11 @@
|
|
|
190
194
|
"type": "boolean",
|
|
191
195
|
"required": false
|
|
192
196
|
},
|
|
197
|
+
"showFileTags": {
|
|
198
|
+
"type": "boolean",
|
|
199
|
+
"required": false,
|
|
200
|
+
"default": true
|
|
201
|
+
},
|
|
193
202
|
"showHelpIcon": {
|
|
194
203
|
"type": "boolean",
|
|
195
204
|
"required": false
|
|
@@ -194,6 +194,10 @@
|
|
|
194
194
|
"type": "function",
|
|
195
195
|
"required": false
|
|
196
196
|
},
|
|
197
|
+
"onUploadedFilesChange": {
|
|
198
|
+
"type": "function",
|
|
199
|
+
"required": false
|
|
200
|
+
},
|
|
197
201
|
"required": {
|
|
198
202
|
"type": "boolean",
|
|
199
203
|
"required": false
|
|
@@ -316,6 +320,23 @@
|
|
|
316
320
|
}
|
|
317
321
|
}
|
|
318
322
|
},
|
|
323
|
+
"uploadedFiles": {
|
|
324
|
+
"type": "object",
|
|
325
|
+
"required": false,
|
|
326
|
+
"rawType": "import(\"/home/runner/_work/ncds/ncds/packages/ui-admin/src/components/forms-and-input/image-file-input/ImageFileInput\").ImageUploadedFile[] | undefined",
|
|
327
|
+
"isArray": true,
|
|
328
|
+
"properties": {
|
|
329
|
+
"fileName": {
|
|
330
|
+
"type": "string",
|
|
331
|
+
"required": true
|
|
332
|
+
},
|
|
333
|
+
"fileImageUrl": {
|
|
334
|
+
"type": "string",
|
|
335
|
+
"required": true
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
"default": "[]"
|
|
339
|
+
},
|
|
319
340
|
"validation": {
|
|
320
341
|
"type": "boolean",
|
|
321
342
|
"required": false
|
package/data/modal.json
CHANGED
|
@@ -135,6 +135,40 @@
|
|
|
135
135
|
]
|
|
136
136
|
}
|
|
137
137
|
]
|
|
138
|
+
},
|
|
139
|
+
"alert": {
|
|
140
|
+
"isOpen": true,
|
|
141
|
+
"size": "sm",
|
|
142
|
+
"children": [
|
|
143
|
+
{
|
|
144
|
+
"component": "modal.header",
|
|
145
|
+
"props": {
|
|
146
|
+
"title": "저장 완료",
|
|
147
|
+
"align": "center"
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"component": "modal.content",
|
|
152
|
+
"children": "변경 사항이 저장되었습니다."
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"component": "modal.actions",
|
|
156
|
+
"props": {
|
|
157
|
+
"layout": "horizontal",
|
|
158
|
+
"align": "right"
|
|
159
|
+
},
|
|
160
|
+
"children": [
|
|
161
|
+
{
|
|
162
|
+
"component": "button",
|
|
163
|
+
"props": {
|
|
164
|
+
"label": "확인",
|
|
165
|
+
"hierarchy": "primary",
|
|
166
|
+
"size": "sm"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
]
|
|
138
172
|
}
|
|
139
173
|
},
|
|
140
174
|
"props": {
|
package/data/select.json
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"hasChildren": true,
|
|
16
16
|
"whenToUse": [
|
|
17
17
|
"네이티브 HTML select가 명시적으로 필요한 경우만",
|
|
18
|
-
"react-hook-form 등 폼 라이브러리와 직접 연동이 필요한 경우"
|
|
18
|
+
"react-hook-form 등 폼 라이브러리와 직접 연동이 필요한 경우",
|
|
19
|
+
"스크립트 없이 마크업만 보여주는 정적 예제(MCP canonicalExample 등) — select-box는 jsRequired라 옵션이 렌더되지 않는다. 실제 구현물에서는 select-box 사용"
|
|
19
20
|
],
|
|
20
21
|
"forbiddenRules": [
|
|
21
22
|
"옵션 2개(반대 의미)이면 Switch 우선",
|