@ncds/ui-admin-mcp 1.0.0-alpha.13 → 1.0.0-alpha.14
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/definitions/js-api.json +73 -8
- package/bin/server.d.ts +5 -0
- package/bin/server.js +21 -15
- package/bin/tools/external/editor.d.ts +17 -0
- package/bin/tools/external/editor.js +88 -0
- package/bin/tools/renderToHtml.d.ts +7 -7
- package/bin/tools/renderToHtml.js +222 -10
- package/bin/types.d.ts +10 -0
- package/data/badge-group.json +3 -3
- package/data/badge.json +2 -2
- package/data/bread-crumb.json +1 -1
- package/data/button-group.json +10 -0
- package/data/button.json +2 -2
- package/data/combo-box.json +3 -3
- package/data/date-picker.json +1 -1
- package/data/dropdown.json +4 -4
- package/data/empty-state.json +3 -3
- package/data/featured-icon.json +1 -1
- package/data/file-input.json +5 -0
- package/data/horizontal-tab.json +4 -4
- package/data/image-file-input.json +5 -0
- package/data/modal.json +50 -6
- package/data/notification.json +6 -22
- package/data/progress-bar.json +1 -1
- package/data/range-date-picker-with-buttons.json +4 -4
- package/data/range-date-picker.json +4 -4
- package/data/select-box.json +3 -3
- package/data/select.json +7 -2
- package/data/table.json +3 -1
- package/data/tag.json +1 -1
- package/data/vertical-tab.json +4 -4
- package/package.json +2 -1
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderToHtml = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* render_to_html tool — 컴포넌트 속성을 전달하면 정확한 HTML + React 매핑을 반환 (순수 함수)
|
|
6
|
+
*
|
|
7
|
+
* DOM 환경과 React/ReactDOM은 server.ts에서 초기화하고 파라미터로 전달한다.
|
|
8
|
+
* 이 파일에는 fs, path, require, let이 없다.
|
|
9
|
+
*/
|
|
10
|
+
// biome-ignore-all lint/complexity/noExcessiveCognitiveComplexity: 기존 spec-walk 함수 복잡도 (Story 5.8 scope 외, 별도 refactor 스토리)
|
|
11
|
+
// biome-ignore-all lint/style/useExportsLast: RenderToHtmlParams export interface 상단 위치 (파일 관행)
|
|
12
|
+
// biome-ignore-all lint/style/noNonNullAssertion: 기존 fallback 패턴 (Story 5.8 scope 외)
|
|
13
|
+
// biome-ignore-all lint/style/noNestedTernary: 기존 reactElementToJsx의 type 판정 로직 (Story 5.8 scope 외)
|
|
14
|
+
// biome-ignore-all lint/style/useTemplate: 기존 attrsPrefix 문자열 결합 (Story 5.8 scope 외)
|
|
15
|
+
const lodash_1 = require("lodash");
|
|
4
16
|
const response_js_1 = require("../utils/response.js");
|
|
5
17
|
// ── 상수 ──────────────────────────────────────────────────────────
|
|
6
18
|
/** React 특수 props 차단 — injection 방지 */
|
|
@@ -19,7 +31,7 @@ const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
|
19
31
|
const resolveSimpleComponent = (name, ctx) => {
|
|
20
32
|
const normalized = (0, response_js_1.normalizeName)(name);
|
|
21
33
|
const childData = ctx.componentMap.get(normalized);
|
|
22
|
-
const Component = childData?.exportName ? ctx.bundle[childData.exportName] ?? null : null;
|
|
34
|
+
const Component = childData?.exportName ? (ctx.bundle[childData.exportName] ?? null) : null;
|
|
23
35
|
return { Component, propsSpec: childData?.props };
|
|
24
36
|
};
|
|
25
37
|
/** compound component resolve: "modal.header" → { Component: bundle.Modal.Header, propsSpec: subComponents["Modal.Header"].props } */
|
|
@@ -331,6 +343,176 @@ const correctMissingRequired = (userProps, propsSpec) => {
|
|
|
331
343
|
}
|
|
332
344
|
return corrected;
|
|
333
345
|
};
|
|
346
|
+
// ── CDN init 패턴 (Story 5.8) ─────────────────────────────────────
|
|
347
|
+
/**
|
|
348
|
+
* CDN 호출 패턴은 `js-api.json`의 `cdnPattern` 필드(A/B/C)로 단일 관리한다.
|
|
349
|
+
* 컴포넌트 추가 시 js-api.json 한 곳에만 패턴을 명시하면 자동 인식된다.
|
|
350
|
+
*/
|
|
351
|
+
/** options를 안전하게 직렬화 — script 블록 탈출 방지(`</script>` 이스케이프) */
|
|
352
|
+
const serializeCdnOptions = (options) => JSON.stringify(options).replace(/<\/script/gi, '<\\/script');
|
|
353
|
+
/** 패턴 A: `new ncua.X(wrapper, options)` */
|
|
354
|
+
const buildPatternA = (id, className, options) => [
|
|
355
|
+
`<div id="${id}"></div>`,
|
|
356
|
+
'<script>',
|
|
357
|
+
" document.addEventListener('DOMContentLoaded', function () {",
|
|
358
|
+
` const wrapper = document.querySelector('#${id}');`,
|
|
359
|
+
` new ncua.${className}(wrapper, ${serializeCdnOptions(options)});`,
|
|
360
|
+
' });',
|
|
361
|
+
'</script>',
|
|
362
|
+
].join('\n');
|
|
363
|
+
/** 패턴 B: `new ncua.X({...options, container: id})` — container 자동 주입 */
|
|
364
|
+
const buildPatternB = (id, className, options) => [
|
|
365
|
+
`<div id="${id}"></div>`,
|
|
366
|
+
'<script>',
|
|
367
|
+
" document.addEventListener('DOMContentLoaded', function () {",
|
|
368
|
+
` new ncua.${className}(${serializeCdnOptions({ ...options, container: id })});`,
|
|
369
|
+
' });',
|
|
370
|
+
'</script>',
|
|
371
|
+
].join('\n');
|
|
372
|
+
/** 패턴 C: `new ncua.X(options)` + `getElement()` + 수동 append */
|
|
373
|
+
const buildPatternC = (id, className, options) => [
|
|
374
|
+
`<div id="${id}"></div>`,
|
|
375
|
+
'<script>',
|
|
376
|
+
" document.addEventListener('DOMContentLoaded', function () {",
|
|
377
|
+
` const wrapper = document.querySelector('#${id}');`,
|
|
378
|
+
` const inst = new ncua.${className}(${serializeCdnOptions(options)});`,
|
|
379
|
+
' wrapper.appendChild(inst.getElement());',
|
|
380
|
+
' });',
|
|
381
|
+
'</script>',
|
|
382
|
+
].join('\n');
|
|
383
|
+
/**
|
|
384
|
+
* CDN init 스크립트 생성. 패턴은 `jsApi.cdnPattern` (A/B/C)으로 결정한다.
|
|
385
|
+
* 호출자는 `cdnPattern` 부재 시 isCdnInput=false로 분기하여 React renderToStaticMarkup 경로를 사용한다.
|
|
386
|
+
*/
|
|
387
|
+
const buildCdnInitScript = (pattern, componentName, instanceId, className, options) => {
|
|
388
|
+
const id = `ncua-${componentName}-${instanceId}`;
|
|
389
|
+
if (pattern === 'A')
|
|
390
|
+
return buildPatternA(id, className, options);
|
|
391
|
+
if (pattern === 'B')
|
|
392
|
+
return buildPatternB(id, className, options);
|
|
393
|
+
return buildPatternC(id, className, options);
|
|
394
|
+
};
|
|
395
|
+
/** options 키 중 `jsApi.constructorParams`에 없는 키를 warning 메시지로 변환.
|
|
396
|
+
* constructorParams의 키는 `config.options` 같은 dot 표기 — 마지막 segment만 추출해 비교. */
|
|
397
|
+
const checkUnknownCdnKeys = (options, jsApi) => {
|
|
398
|
+
if (Object.keys(jsApi.constructorParams).length === 0)
|
|
399
|
+
return [];
|
|
400
|
+
const allowedKeys = new Set();
|
|
401
|
+
for (const param of Object.keys(jsApi.constructorParams)) {
|
|
402
|
+
const lastDot = param.lastIndexOf('.');
|
|
403
|
+
allowedKeys.add(lastDot >= 0 ? param.slice(lastDot + 1) : param);
|
|
404
|
+
}
|
|
405
|
+
return Object.keys(options)
|
|
406
|
+
.filter((key) => !allowedKeys.has(key))
|
|
407
|
+
.map((key) => `Unknown CDN option key '${key}' for component '${jsApi.className}'. Passed through as-is. Verify against constructorParams.`);
|
|
408
|
+
};
|
|
409
|
+
/** SelectBox/ComboBox `options` 배열 요소 키 정규화.
|
|
410
|
+
* 공식 docs는 `{id, label}` 또는 `{id, text}` 허용. React 매칭은 `label`만 받으므로
|
|
411
|
+
* 통일된 `{id, label}`로 정규화. `{value, text}`는 비표준 alias(HTML `<option>` 컨벤션
|
|
412
|
+
* 오용)이며 함께 변환. 정규화 발생 시 warning 기록(에이전트 학습용). */
|
|
413
|
+
const normalizeCdnInputProps = (componentName, cdnConfig) => {
|
|
414
|
+
if (componentName !== 'select-box' && componentName !== 'combo-box') {
|
|
415
|
+
return { normalized: cdnConfig, warnings: [] };
|
|
416
|
+
}
|
|
417
|
+
const { options } = cdnConfig;
|
|
418
|
+
if (!Array.isArray(options))
|
|
419
|
+
return { normalized: cdnConfig, warnings: [] };
|
|
420
|
+
const aliasesUsed = new Set();
|
|
421
|
+
const normalizedOptions = options.map((opt) => {
|
|
422
|
+
if (opt === null || typeof opt !== 'object')
|
|
423
|
+
return opt;
|
|
424
|
+
const item = { ...opt };
|
|
425
|
+
if (item.id === undefined && item.value !== undefined) {
|
|
426
|
+
item.id = item.value;
|
|
427
|
+
delete item.value;
|
|
428
|
+
aliasesUsed.add('value');
|
|
429
|
+
}
|
|
430
|
+
if (item.label === undefined && item.text !== undefined) {
|
|
431
|
+
item.label = item.text;
|
|
432
|
+
delete item.text;
|
|
433
|
+
aliasesUsed.add('text');
|
|
434
|
+
}
|
|
435
|
+
return item;
|
|
436
|
+
});
|
|
437
|
+
const warnings = [];
|
|
438
|
+
if (aliasesUsed.has('value')) {
|
|
439
|
+
warnings.push(`Option key 'value' normalized to 'id' for component '${componentName}'. Canonical form is {id, label}.`);
|
|
440
|
+
}
|
|
441
|
+
if (aliasesUsed.has('text')) {
|
|
442
|
+
warnings.push(`Option key 'text' normalized to 'label' for component '${componentName}'. Canonical form is {id, label}.`);
|
|
443
|
+
}
|
|
444
|
+
return { normalized: { ...cdnConfig, options: normalizedOptions }, warnings };
|
|
445
|
+
};
|
|
446
|
+
/** Story 5.9: 사용자 props 에서 함수 prop 재귀 제거 (JSON 직렬화·deep merge 안전).
|
|
447
|
+
* cdnDefaults 는 JSON 이라 함수 없음 → 사용자 props 만 정리 */
|
|
448
|
+
const stripFunctionProps = (obj) => {
|
|
449
|
+
if (typeof obj === 'function')
|
|
450
|
+
return undefined;
|
|
451
|
+
if (Array.isArray(obj)) {
|
|
452
|
+
return obj.map((item) => stripFunctionProps(item)).filter((item) => item !== undefined);
|
|
453
|
+
}
|
|
454
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
455
|
+
return Object.fromEntries(Object.entries(obj)
|
|
456
|
+
.filter(([, value]) => typeof value !== 'function')
|
|
457
|
+
.map(([key, value]) => [key, stripFunctionProps(value)]));
|
|
458
|
+
}
|
|
459
|
+
return obj;
|
|
460
|
+
};
|
|
461
|
+
/** Story 5.9: cdnDefaults 와 사용자 props 를 deep merge.
|
|
462
|
+
* - 사용자 값 우선 (lodash merge 의 두 번째 인자가 우선)
|
|
463
|
+
* - 함수 prop 은 사용자 props 에서 stripFunctionProps 로 사전 제거
|
|
464
|
+
* - DatePicker `datePickerOptions` 배열 한정: 각 항목의 `options` 에 cdnDefaults 의 첫 항목 options 를 per-element 부분 merge
|
|
465
|
+
* - 다른 배열(`buttons` 등) 은 사용자 값 그대로
|
|
466
|
+
* 반환: { merged, defaultsApplied } — defaultsApplied 는 cdnDefaults 에 있고 사용자 props 에 없는 top-level 키 (defaultsUsed 응답용) */
|
|
467
|
+
const mergeCdnDefaults = (componentName, cdnDefaults, userProps) => {
|
|
468
|
+
if (!cdnDefaults)
|
|
469
|
+
return { merged: userProps, defaultsApplied: [] };
|
|
470
|
+
const userPropsClean = stripFunctionProps(userProps);
|
|
471
|
+
const baseMerged = (0, lodash_1.merge)((0, lodash_1.cloneDeep)(cdnDefaults), userPropsClean);
|
|
472
|
+
const merged = componentName === 'date-picker' && Array.isArray(userPropsClean.datePickerOptions)
|
|
473
|
+
? {
|
|
474
|
+
...baseMerged,
|
|
475
|
+
datePickerOptions: userPropsClean.datePickerOptions.map((item) => {
|
|
476
|
+
const baseOptions = cdnDefaults.datePickerOptions?.[0]?.options ?? {};
|
|
477
|
+
return {
|
|
478
|
+
...item,
|
|
479
|
+
options: (0, lodash_1.merge)((0, lodash_1.cloneDeep)(baseOptions), item.options ?? {}),
|
|
480
|
+
};
|
|
481
|
+
}),
|
|
482
|
+
}
|
|
483
|
+
: baseMerged;
|
|
484
|
+
const defaultsApplied = Object.keys(cdnDefaults).filter((key) => !(key in userPropsClean));
|
|
485
|
+
return { merged, defaultsApplied };
|
|
486
|
+
};
|
|
487
|
+
/** CDN config(에이전트 입력) → React props (buildReactOutput 입력) 번역.
|
|
488
|
+
* 단순 컴포넌트는 identity, 차이가 있는 컴포넌트는 별도 룰. */
|
|
489
|
+
const translateCdnToReactProps = (componentName, cdnConfig) => {
|
|
490
|
+
// SelectBox/ComboBox: options → optionItems, value(원시) → value(객체) (배열에서 매칭해 wrap)
|
|
491
|
+
if (componentName === 'select-box' || componentName === 'combo-box') {
|
|
492
|
+
const { options, value, ...rest } = cdnConfig;
|
|
493
|
+
const result = { ...rest };
|
|
494
|
+
if (options !== undefined)
|
|
495
|
+
result.optionItems = options;
|
|
496
|
+
if (value !== undefined) {
|
|
497
|
+
if ((typeof value === 'string' || typeof value === 'number') && Array.isArray(options)) {
|
|
498
|
+
const matched = options.find((opt) => typeof opt === 'object' && opt !== null && opt.id === value);
|
|
499
|
+
result.value = matched !== undefined ? matched : value;
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
result.value = value;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return result;
|
|
506
|
+
}
|
|
507
|
+
// FileInput/ImageFileInput: container 키는 React props에 없음 → 제거
|
|
508
|
+
if (componentName === 'file-input' || componentName === 'image-file-input') {
|
|
509
|
+
const result = { ...cdnConfig };
|
|
510
|
+
delete result.container;
|
|
511
|
+
return result;
|
|
512
|
+
}
|
|
513
|
+
// 그 외: identity (Slider, DatePicker, Tooltip, Notification, ProgressBar, Tag — key 동일 가정)
|
|
514
|
+
return cdnConfig;
|
|
515
|
+
};
|
|
334
516
|
// ── 응답 조립 ──────────────────────────────────────────────────────
|
|
335
517
|
/** componentMap의 props 스펙에서 defaultsUsed를 자동 계산 */
|
|
336
518
|
const calcDefaultsUsed = (propsSpec, userProps) => Object.fromEntries(Object.entries(propsSpec)
|
|
@@ -391,9 +573,9 @@ const reactElementToJsx = (node, ctx) => {
|
|
|
391
573
|
const name = typeof el.type === 'string'
|
|
392
574
|
? el.type
|
|
393
575
|
: typeof el.type === 'function'
|
|
394
|
-
? el.type.displayName
|
|
395
|
-
|
|
396
|
-
|
|
576
|
+
? el.type.displayName ||
|
|
577
|
+
el.type.name ||
|
|
578
|
+
'Component'
|
|
397
579
|
: 'Component';
|
|
398
580
|
const { children: childChildren, ...restProps } = el.props || {};
|
|
399
581
|
const attrs = Object.entries(restProps)
|
|
@@ -464,7 +646,7 @@ const buildJsField = (componentData, jsApiMap) => {
|
|
|
464
646
|
// ── 진입점 ────────────────────────────────────────────────────────
|
|
465
647
|
/** render_to_html tool — props로 React 컴포넌트를 렌더링하여 HTML + React 매핑 반환 */
|
|
466
648
|
const renderToHtml = (params) => {
|
|
467
|
-
const { componentMap, bundle, iconBundle, cdnMeta, iconMeta, reactRuntime, jsApiMap, name, props } = params;
|
|
649
|
+
const { componentMap, bundle, iconBundle, cdnMeta, iconMeta, reactRuntime, jsApiMap, name, props, instanceId } = params;
|
|
468
650
|
const normalized = (0, response_js_1.normalizeName)(name);
|
|
469
651
|
const componentData = componentMap.get(normalized);
|
|
470
652
|
if (!componentData)
|
|
@@ -478,29 +660,59 @@ const renderToHtml = (params) => {
|
|
|
478
660
|
return (0, response_js_1.errorResponse)('COMPONENT_NOT_IN_BUNDLE', `'${normalized}' (${exportName}) 컴포넌트가 번들에 없습니다.`, '번들을 재빌드해주세요 (pnpm build:bundle).');
|
|
479
661
|
}
|
|
480
662
|
try {
|
|
481
|
-
|
|
663
|
+
// Story 5.8: jsRequired + js-api 정의 + jsApi.cdnPattern 등록 → CDN-input 모드
|
|
664
|
+
const jsApi = jsApiMap.get(exportName);
|
|
665
|
+
const isCdnInput = componentData.jsRequired && jsApi !== undefined && jsApi.cdnPattern !== undefined;
|
|
666
|
+
// CDN-input은 입력이 CDN config 스키마 → 옵션 배열 키 정규화 → React 파이프라인을 위해 React props로 번역
|
|
667
|
+
const cdnNormalization = isCdnInput
|
|
668
|
+
? normalizeCdnInputProps(normalized, props ?? {})
|
|
669
|
+
: { normalized: props ?? {}, warnings: [] };
|
|
670
|
+
const normalizedCdnProps = cdnNormalization.normalized;
|
|
671
|
+
// Story 5.9: cdnDefaults 와 deep merge (사용자 props 우선, 함수 prop skip, datePickerOptions per-element 부분 merge)
|
|
672
|
+
const cdnMergeResult = isCdnInput && jsApi
|
|
673
|
+
? mergeCdnDefaults(normalized, jsApi.cdnDefaults, normalizedCdnProps)
|
|
674
|
+
: { merged: normalizedCdnProps, defaultsApplied: [] };
|
|
675
|
+
const mergedCdnProps = cdnMergeResult.merged;
|
|
676
|
+
const reactInput = isCdnInput ? translateCdnToReactProps(normalized, mergedCdnProps) : mergedCdnProps;
|
|
677
|
+
const safeProps = removeBlockedProps(reactInput);
|
|
482
678
|
const sanitized = componentData.props ? sanitizeProps(safeProps, componentData.props) : safeProps;
|
|
483
679
|
const enumWarnings = componentData.props ? validateProps(sanitized, componentData.props) : [];
|
|
484
680
|
const enumCorrected = componentData.props ? correctInvalidEnums(sanitized, componentData.props) : sanitized;
|
|
485
681
|
const corrected = componentData.props ? correctMissingRequired(enumCorrected, componentData.props) : enumCorrected;
|
|
486
682
|
const postWarnings = componentData.props ? validateProps(corrected, componentData.props) : [];
|
|
487
|
-
const
|
|
683
|
+
const cdnKeyWarnings = isCdnInput && jsApi ? checkUnknownCdnKeys(normalizedCdnProps, jsApi) : [];
|
|
684
|
+
const warnings = [
|
|
685
|
+
...enumWarnings,
|
|
686
|
+
...postWarnings.filter((w) => !enumWarnings.includes(w)),
|
|
687
|
+
...cdnKeyWarnings,
|
|
688
|
+
...cdnNormalization.warnings,
|
|
689
|
+
];
|
|
488
690
|
const resolvedProps = resolveIconProps(corrected, iconBundle, componentData.props);
|
|
489
691
|
// children이 컴포넌트 descriptor면 React element로 변환
|
|
490
692
|
if (resolvedProps.children !== undefined) {
|
|
491
693
|
const ctx = { bundle, iconBundle, componentMap, reactRuntime };
|
|
492
694
|
resolvedProps.children = resolveChildren(resolvedProps.children, ctx, 0);
|
|
493
695
|
}
|
|
494
|
-
|
|
495
|
-
const
|
|
696
|
+
// HTML 출력: CDN-input은 init script, 그 외는 React 정적 HTML (renderToStaticMarkup은 필요할 때만 호출)
|
|
697
|
+
const cdnInitScript = isCdnInput && jsApi?.cdnPattern
|
|
698
|
+
? buildCdnInitScript(jsApi.cdnPattern, normalized, instanceId, jsApi.className, removeBlockedProps(mergedCdnProps))
|
|
699
|
+
: null;
|
|
700
|
+
const html = cdnInitScript !== null
|
|
701
|
+
? cdnInitScript
|
|
702
|
+
: `<!-- ncua:${normalized} start -->\n${reactRuntime.renderToStaticMarkup(reactRuntime.createElement(Component, resolvedProps))}\n<!-- ncua:${normalized} end -->`;
|
|
496
703
|
const hasDefaults = componentData.props ? calcDefaultsUsed(componentData.props, corrected) : {};
|
|
704
|
+
// Story 5.9: cdnDefaults 적용된 키도 defaultsUsed 에 노출 (에이전트 학습용)
|
|
705
|
+
const cdnDefaultsApplied = isCdnInput && jsApi?.cdnDefaults
|
|
706
|
+
? Object.fromEntries(cdnMergeResult.defaultsApplied.map((key) => [key, jsApi.cdnDefaults?.[key]]))
|
|
707
|
+
: {};
|
|
708
|
+
const finalDefaultsUsed = { ...hasDefaults, ...cdnDefaultsApplied };
|
|
497
709
|
return (0, response_js_1.successResponse)({
|
|
498
710
|
html,
|
|
499
711
|
component: normalized,
|
|
500
712
|
exportName,
|
|
501
713
|
importPath: componentData.importPath,
|
|
502
714
|
appliedProps: corrected,
|
|
503
|
-
...(Object.keys(
|
|
715
|
+
...(Object.keys(finalDefaultsUsed).length > 0 && { defaultsUsed: finalDefaultsUsed }),
|
|
504
716
|
...(warnings.length > 0 && { warnings }),
|
|
505
717
|
js: buildJsField(componentData, jsApiMap),
|
|
506
718
|
cdn: cdnMeta ?? undefined,
|
package/bin/types.d.ts
CHANGED
|
@@ -85,6 +85,16 @@ export interface JsApiInfo {
|
|
|
85
85
|
methods: string[];
|
|
86
86
|
staticMethods?: string[];
|
|
87
87
|
example: string;
|
|
88
|
+
/** Story 5.9: CDN init script 생성 시 사용자 props 와 deep merge 되는 default 옵션. JSON-serializable 만 (함수 prop 없음). */
|
|
89
|
+
cdnDefaults?: Record<string, unknown>;
|
|
90
|
+
/**
|
|
91
|
+
* CDN 호출 패턴.
|
|
92
|
+
* - A: `new ncua.X(element, options)` — element가 곧 컨테이너
|
|
93
|
+
* - B: `new ncua.X(options)` — options.container로 자동 append
|
|
94
|
+
* - C: `new ncua.X(options)` — getElement() + 수동 append
|
|
95
|
+
* 부재 시 React 정적 HTML 경로로 fallback.
|
|
96
|
+
*/
|
|
97
|
+
cdnPattern?: 'A' | 'B' | 'C';
|
|
88
98
|
}
|
|
89
99
|
export interface ComplianceRuleHint {
|
|
90
100
|
attr: string;
|
package/data/badge-group.json
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"groupIcon": {
|
|
60
60
|
"type": "object",
|
|
61
61
|
"required": false,
|
|
62
|
-
"rawType": "import(\"/Users/
|
|
62
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
63
63
|
"properties": {
|
|
64
64
|
"type": {
|
|
65
65
|
"type": "string",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"leadingIcon": {
|
|
135
135
|
"type": "object",
|
|
136
136
|
"required": false,
|
|
137
|
-
"rawType": "import(\"/Users/
|
|
137
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
138
138
|
"properties": {
|
|
139
139
|
"type": {
|
|
140
140
|
"type": "string",
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
"trailingIcon": {
|
|
212
212
|
"type": "object",
|
|
213
213
|
"required": false,
|
|
214
|
-
"rawType": "import(\"/Users/
|
|
214
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
215
215
|
"properties": {
|
|
216
216
|
"type": {
|
|
217
217
|
"type": "string",
|
package/data/badge.json
CHANGED
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"leadingIcon": {
|
|
82
82
|
"type": "object",
|
|
83
83
|
"required": false,
|
|
84
|
-
"rawType": "import(\"/Users/
|
|
84
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
85
85
|
"properties": {
|
|
86
86
|
"type": {
|
|
87
87
|
"type": "string",
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
"trailingIcon": {
|
|
155
155
|
"type": "object",
|
|
156
156
|
"required": false,
|
|
157
|
-
"rawType": "import(\"/Users/
|
|
157
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
158
158
|
"properties": {
|
|
159
159
|
"type": {
|
|
160
160
|
"type": "string",
|
package/data/bread-crumb.json
CHANGED
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"items": {
|
|
58
58
|
"type": "object",
|
|
59
59
|
"required": true,
|
|
60
|
-
"rawType": "import(\"/Users/
|
|
60
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/bread-crumb/BreadCrumb\").BreadcrumbItemProps[]",
|
|
61
61
|
"properties": {
|
|
62
62
|
"href": {
|
|
63
63
|
"type": "string",
|
package/data/button-group.json
CHANGED
|
@@ -89,6 +89,16 @@
|
|
|
89
89
|
"required": false,
|
|
90
90
|
"default": false
|
|
91
91
|
},
|
|
92
|
+
"fullWidth": {
|
|
93
|
+
"type": "boolean",
|
|
94
|
+
"required": false,
|
|
95
|
+
"default": false
|
|
96
|
+
},
|
|
97
|
+
"hasBorder": {
|
|
98
|
+
"type": "boolean",
|
|
99
|
+
"required": false,
|
|
100
|
+
"default": true
|
|
101
|
+
},
|
|
92
102
|
"icon": {
|
|
93
103
|
"type": "string",
|
|
94
104
|
"required": false,
|
package/data/button.json
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"leadingIcon": {
|
|
78
78
|
"type": "object",
|
|
79
79
|
"required": false,
|
|
80
|
-
"rawType": "import(\"/Users/
|
|
80
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
81
81
|
"properties": {
|
|
82
82
|
"type": {
|
|
83
83
|
"type": "string",
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"trailingIcon": {
|
|
159
159
|
"type": "object",
|
|
160
160
|
"required": false,
|
|
161
|
-
"rawType": "import(\"/Users/
|
|
161
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
162
162
|
"properties": {
|
|
163
163
|
"type": {
|
|
164
164
|
"type": "string",
|
package/data/combo-box.json
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"optionItems": {
|
|
93
93
|
"type": "object",
|
|
94
94
|
"required": false,
|
|
95
|
-
"rawType": "import(\"/Users/
|
|
95
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/dropdown/option\").OptionType[] | undefined",
|
|
96
96
|
"properties": {
|
|
97
97
|
"id": {
|
|
98
98
|
"type": "string",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"register": {
|
|
120
120
|
"type": "object",
|
|
121
121
|
"required": false,
|
|
122
|
-
"rawType": "import(\"/Users/
|
|
122
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/node_modules/.pnpm/react-hook-form@7.72.0_react@18.2.0/node_modules/react-hook-form/dist/types/form\").UseFormRegisterReturn | undefined"
|
|
123
123
|
},
|
|
124
124
|
"required": {
|
|
125
125
|
"type": "boolean",
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
"value": {
|
|
149
149
|
"type": "object",
|
|
150
150
|
"required": false,
|
|
151
|
-
"rawType": "import(\"/Users/
|
|
151
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/dropdown/option\").OptionValue | undefined"
|
|
152
152
|
}
|
|
153
153
|
},
|
|
154
154
|
"html": {},
|
package/data/date-picker.json
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"datePickerOptions": {
|
|
63
63
|
"type": "object",
|
|
64
64
|
"required": false,
|
|
65
|
-
"rawType": "Partial<import(\"/Users/
|
|
65
|
+
"rawType": "Partial<import(\"/Users/nhncommerce/Desktop/project/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
|
|
66
66
|
},
|
|
67
67
|
"destructive": {
|
|
68
68
|
"type": "string",
|
package/data/dropdown.json
CHANGED
|
@@ -117,12 +117,12 @@
|
|
|
117
117
|
"groups": {
|
|
118
118
|
"type": "object",
|
|
119
119
|
"required": true,
|
|
120
|
-
"rawType": "import(\"/Users/
|
|
120
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownGroup[]",
|
|
121
121
|
"properties": {
|
|
122
122
|
"items": {
|
|
123
123
|
"type": "object",
|
|
124
124
|
"required": true,
|
|
125
|
-
"rawType": "import(\"/Users/
|
|
125
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownItemType[]",
|
|
126
126
|
"properties": {
|
|
127
127
|
"id": {
|
|
128
128
|
"type": "string",
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
"header": {
|
|
169
169
|
"type": "object",
|
|
170
170
|
"required": false,
|
|
171
|
-
"rawType": "import(\"/Users/
|
|
171
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownHeaderType | undefined",
|
|
172
172
|
"properties": {
|
|
173
173
|
"type": {
|
|
174
174
|
"type": "string",
|
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
"trigger": {
|
|
198
198
|
"type": "object",
|
|
199
199
|
"required": true,
|
|
200
|
-
"rawType": "import(\"/Users/
|
|
200
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").AvatarTrigger | import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").ButtonTrigger | import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").IconTrigger | import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").CustomTrigger",
|
|
201
201
|
"properties": {
|
|
202
202
|
"type": {
|
|
203
203
|
"type": "string",
|
package/data/empty-state.json
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"buttons": {
|
|
38
38
|
"type": "object",
|
|
39
39
|
"required": false,
|
|
40
|
-
"rawType": "import(\"/Users/
|
|
40
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/empty-state/EmptyState\").ButtonOptions | import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/empty-state/EmptyState\").ButtonOptions[] | undefined",
|
|
41
41
|
"properties": {
|
|
42
42
|
"label": {
|
|
43
43
|
"type": "string",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"leadingIcon": {
|
|
80
80
|
"type": "object",
|
|
81
81
|
"required": false,
|
|
82
|
-
"rawType": "import(\"/Users/
|
|
82
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
83
83
|
"properties": {
|
|
84
84
|
"type": {
|
|
85
85
|
"type": "string",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"trailingIcon": {
|
|
143
143
|
"type": "object",
|
|
144
144
|
"required": false,
|
|
145
|
-
"rawType": "import(\"/Users/
|
|
145
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
146
146
|
"properties": {
|
|
147
147
|
"type": {
|
|
148
148
|
"type": "string",
|
package/data/featured-icon.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"importPath": "@ncds/ui-admin",
|
|
5
5
|
"jsRequired": true,
|
|
6
6
|
"category": "icon",
|
|
7
|
-
"description": "FeaturedIcon은 상태(Status), 결과(Result), 중요 액션(Action)을 시각적으로 강조하기 위한 아이콘 강조
|
|
7
|
+
"description": "FeaturedIcon은 상태(Status), 결과(Result), 중요 액션(Action)을 시각적으로 강조하기 위한 아이콘 강조 컴포넌트입니다.",
|
|
8
8
|
"aliases": [
|
|
9
9
|
"FeaturedIcon",
|
|
10
10
|
"피처드아이콘",
|
package/data/file-input.json
CHANGED
package/data/horizontal-tab.json
CHANGED
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"menus": {
|
|
61
61
|
"type": "object",
|
|
62
62
|
"required": false,
|
|
63
|
-
"rawType": "import(\"/Users/
|
|
63
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/tab/TabButton\").TabButtonProps[] | undefined",
|
|
64
64
|
"properties": {
|
|
65
65
|
"id": {
|
|
66
66
|
"type": "string",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"badgeInfo": {
|
|
98
98
|
"type": "object",
|
|
99
99
|
"required": false,
|
|
100
|
-
"rawType": "import(\"/Users/
|
|
100
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/components/badge/Badge\").BadgeProps | undefined",
|
|
101
101
|
"properties": {
|
|
102
102
|
"label": {
|
|
103
103
|
"type": "string",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"leadingIcon": {
|
|
132
132
|
"type": "object",
|
|
133
133
|
"required": false,
|
|
134
|
-
"rawType": "import(\"/Users/
|
|
134
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
135
135
|
"properties": {
|
|
136
136
|
"type": {
|
|
137
137
|
"type": "string",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"trailingIcon": {
|
|
195
195
|
"type": "object",
|
|
196
196
|
"required": false,
|
|
197
|
-
"rawType": "import(\"/Users/
|
|
197
|
+
"rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
|
|
198
198
|
"properties": {
|
|
199
199
|
"type": {
|
|
200
200
|
"type": "string",
|