@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.
@@ -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
- || el.type.name
396
- || 'Component'
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
- const safeProps = removeBlockedProps(props ?? {});
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 warnings = [...enumWarnings, ...postWarnings.filter((w) => !enumWarnings.includes(w))];
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
- const rawHtml = reactRuntime.renderToStaticMarkup(reactRuntime.createElement(Component, resolvedProps));
495
- const html = `<!-- ncua:${normalized} start -->\n${rawHtml}\n<!-- ncua:${normalized} end -->`;
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(hasDefaults).length > 0 && { defaultsUsed: hasDefaults }),
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;
@@ -59,7 +59,7 @@
59
59
  "groupIcon": {
60
60
  "type": "object",
61
61
  "required": false,
62
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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",
@@ -57,7 +57,7 @@
57
57
  "items": {
58
58
  "type": "object",
59
59
  "required": true,
60
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/bread-crumb/BreadCrumb\").BreadcrumbItemProps[]",
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",
@@ -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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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",
@@ -92,7 +92,7 @@
92
92
  "optionItems": {
93
93
  "type": "object",
94
94
  "required": false,
95
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/types/dropdown/option\").OptionType[] | undefined",
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/nhn/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"
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/nhn/Project/ncds/packages/ui-admin/src/types/dropdown/option\").OptionValue | undefined"
151
+ "rawType": "import(\"/Users/nhncommerce/Desktop/project/ncds/packages/ui-admin/src/types/dropdown/option\").OptionValue | undefined"
152
152
  }
153
153
  },
154
154
  "html": {},
@@ -62,7 +62,7 @@
62
62
  "datePickerOptions": {
63
63
  "type": "object",
64
64
  "required": false,
65
- "rawType": "Partial<import(\"/Users/nhn/Project/ncds/node_modules/.pnpm/flatpickr@4.6.13/node_modules/flatpickr/dist/types/options\").BaseOptions> | undefined"
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",
@@ -117,12 +117,12 @@
117
117
  "groups": {
118
118
  "type": "object",
119
119
  "required": true,
120
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownGroup[]",
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/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownItemType[]",
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/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").DropdownHeaderType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").AvatarTrigger | import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").ButtonTrigger | import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").IconTrigger | import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/dropdown/Dropdown\").CustomTrigger",
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",
@@ -37,7 +37,7 @@
37
37
  "buttons": {
38
38
  "type": "object",
39
39
  "required": false,
40
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/empty-state/EmptyState\").ButtonOptions | import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/empty-state/EmptyState\").ButtonOptions[] | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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",
@@ -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
  "피처드아이콘",
@@ -167,6 +167,11 @@
167
167
  "type": "number",
168
168
  "required": false
169
169
  },
170
+ "multiple": {
171
+ "type": "boolean",
172
+ "required": false,
173
+ "default": false
174
+ },
170
175
  "onChange": {
171
176
  "type": "function",
172
177
  "required": false
@@ -60,7 +60,7 @@
60
60
  "menus": {
61
61
  "type": "object",
62
62
  "required": false,
63
- "rawType": "import(\"/Users/nhn/Project/ncds/packages/ui-admin/src/components/tab/TabButton\").TabButtonProps[] | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/components/badge/Badge\").BadgeProps | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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/nhn/Project/ncds/packages/ui-admin/src/types/side-slot\").SideSlotType | undefined",
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",
@@ -175,6 +175,11 @@
175
175
  "type": "number",
176
176
  "required": false
177
177
  },
178
+ "multiple": {
179
+ "type": "boolean",
180
+ "required": false,
181
+ "default": false
182
+ },
178
183
  "onChange": {
179
184
  "type": "function",
180
185
  "required": false