@ncds/ui-admin-mcp 1.0.0-alpha.2 → 1.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/bin/components.bundle.js +15 -19
  2. package/bin/definitions/external/editor.d.ts +50 -0
  3. package/bin/definitions/external/editor.js +53 -0
  4. package/bin/definitions/external/step-guide.d.ts +61 -0
  5. package/bin/definitions/external/step-guide.js +52 -0
  6. package/bin/definitions/instructions.md +194 -10
  7. package/bin/definitions/js-api.json +352 -0
  8. package/bin/definitions/rules.json +36 -4
  9. package/bin/definitions/tool-definitions.json +33 -9
  10. package/bin/overrides/composition.json +2500 -0
  11. package/bin/server.d.ts +5 -0
  12. package/bin/server.js +97 -33
  13. package/bin/server.mjs +0 -0
  14. package/bin/tools/external/editor.d.ts +18 -0
  15. package/bin/tools/external/editor.js +88 -0
  16. package/bin/tools/external/step-guide.d.ts +19 -0
  17. package/bin/tools/external/step-guide.js +79 -0
  18. package/bin/tools/getComponentProps.d.ts +3 -0
  19. package/bin/tools/getComponentProps.js +12 -3
  20. package/bin/tools/listCompositionOverrides.d.ts +61 -0
  21. package/bin/tools/listCompositionOverrides.js +156 -0
  22. package/bin/tools/ping.d.ts +1 -1
  23. package/bin/tools/renderToHtml.d.ts +38 -7
  24. package/bin/tools/renderToHtml.js +785 -110
  25. package/bin/tools/searchComponent.d.ts +5 -0
  26. package/bin/tools/searchComponent.js +3 -3
  27. package/bin/tools/validateHtml.d.ts +8 -6
  28. package/bin/tools/validateHtml.js +74 -6
  29. package/bin/types.d.ts +60 -1
  30. package/bin/utils/bemValidator.d.ts +16 -8
  31. package/bin/utils/bemValidator.js +16 -4
  32. package/bin/utils/compliance.d.ts +7 -6
  33. package/bin/utils/compliance.js +8 -4
  34. package/bin/utils/dataLoader.d.ts +43 -14
  35. package/bin/utils/dataLoader.js +125 -22
  36. package/bin/utils/domEnvironment.js +51 -0
  37. package/bin/utils/fuzzyMatch.d.ts +4 -0
  38. package/bin/utils/fuzzyMatch.js +13 -3
  39. package/bin/utils/logger.d.ts +5 -5
  40. package/bin/utils/logger.js +5 -5
  41. package/bin/utils/response.d.ts +4 -2
  42. package/bin/utils/response.js +15 -4
  43. package/bin/utils/tokenValidator.d.ts +4 -3
  44. package/bin/utils/tokenValidator.js +13 -11
  45. package/bin/version.d.ts +4 -2
  46. package/bin/version.js +4 -2
  47. package/data/_icons.json +357 -2
  48. package/data/_meta.json +4 -5
  49. package/data/_tokens.json +8 -8
  50. package/data/badge-group.json +181 -4
  51. package/data/badge.json +146 -14
  52. package/data/block-container.json +95 -0
  53. package/data/block-header.json +208 -0
  54. package/data/bread-crumb.json +38 -2
  55. package/data/button-group.json +59 -0
  56. package/data/button.json +124 -1
  57. package/data/carousel-arrow.json +6 -11
  58. package/data/carousel-number-group.json +2 -12
  59. package/data/checkbox.json +1 -1
  60. package/data/combo-box.json +32 -8
  61. package/data/data-grid.json +240 -0
  62. package/data/date-picker.json +22 -2
  63. package/data/divider.json +1 -1
  64. package/data/dot.json +2 -2
  65. package/data/dropdown.json +187 -20
  66. package/data/editor.json +85 -0
  67. package/data/empty-state.json +168 -3
  68. package/data/featured-icon.json +20 -5
  69. package/data/file-input.json +176 -10
  70. package/data/horizontal-tab.json +219 -3
  71. package/data/image-file-input.json +176 -10
  72. package/data/input-base.json +165 -4
  73. package/data/modal.json +266 -5
  74. package/data/notification.json +56 -40
  75. package/data/number-input.json +164 -4
  76. package/data/page-title.json +135 -0
  77. package/data/pagination.json +8 -4
  78. package/data/password-input.json +252 -13
  79. package/data/progress-bar.json +28 -8
  80. package/data/progress-circle.json +9 -6
  81. package/data/radio.json +4 -3
  82. package/data/range-date-picker-with-buttons.json +187 -7
  83. package/data/range-date-picker.json +186 -6
  84. package/data/select-box.json +48 -16
  85. package/data/select.json +35 -25
  86. package/data/slider.json +1 -1
  87. package/data/spinner.json +3 -4
  88. package/data/step-guide.json +130 -0
  89. package/data/switch.json +66 -6
  90. package/data/table.json +293 -0
  91. package/data/tag.json +68 -6
  92. package/data/textarea.json +1 -1
  93. package/data/toggle.json +2 -2
  94. package/data/tooltip.json +16 -3
  95. package/data/vertical-tab.json +220 -3
  96. package/package.json +27 -25
  97. package/bin/instructions.d.ts +0 -1
  98. package/bin/instructions.js +0 -14
  99. package/bin/tools/getComponentHtml.d.ts +0 -3
  100. package/bin/tools/getComponentHtml.js +0 -30
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Story 5.10: editor 외부 분기 정의
3
+ *
4
+ * froala 기반 에디터(`@ncds/editor-html`)의 응답 메타·CDN URL·props·cdnDefaults·methods.
5
+ * `tools/external/editor.ts` 의 `buildEditorResponse` 가 본 정의를 읽어 응답 조립.
6
+ * (json 대신 ts — tsconfig `module: Node16` 환경에서 import 단순화. 빌드 시 자동 포함.)
7
+ */
8
+ export declare const editorDefinition: {
9
+ readonly name: "editor";
10
+ readonly className: "NcdsEditor";
11
+ readonly category: "form";
12
+ readonly description: "froala 기반 WYSIWYG 에디터. textarea 를 in-place 변환.";
13
+ readonly cdn: {
14
+ readonly version: "0.0";
15
+ readonly css: "https://fe-sdk.cdn-nhncommerce.com/@ncds/editor/0.0/ncds-editor.css";
16
+ readonly js: "https://fe-sdk.cdn-nhncommerce.com/@ncds/editor/0.0/ncds-editor.js";
17
+ };
18
+ readonly props: readonly [{
19
+ readonly name: "heightMin";
20
+ readonly type: "number";
21
+ readonly default: 300;
22
+ readonly description: "최소 높이 (px)";
23
+ }, {
24
+ readonly name: "heightMax";
25
+ readonly type: "number";
26
+ readonly default: 600;
27
+ readonly description: "최대 높이 (px)";
28
+ }, {
29
+ readonly name: "heightResize";
30
+ readonly type: "boolean";
31
+ readonly default: false;
32
+ readonly description: "높이 조정 가능 여부";
33
+ }, {
34
+ readonly name: "placeholderText";
35
+ readonly type: "string";
36
+ readonly default: "내용을 입력하세요.";
37
+ readonly description: "플레이스홀더 텍스트";
38
+ }, {
39
+ readonly name: "imageUploadCallback";
40
+ readonly type: "function";
41
+ readonly description: "이미지 업로드 콜백 함수명 (전역 함수). 외부 분기에서 stripFunctionProps 로 자동 제외 — data-* 직렬화 대상 아님";
42
+ }];
43
+ readonly cdnDefaults: {
44
+ heightMin: number;
45
+ heightMax: number;
46
+ heightResize: boolean;
47
+ placeholderText: string;
48
+ };
49
+ readonly methods: readonly ["getHTML()", "setHTML(html)", "getText()", "focus()", "blur()", "enable()", "disable()", "destroy()", "insertImage(src, alt, link)", "insertLink(href, text)", "insertTable(rows, cols)", "on(event, handler)", "off(event)"];
50
+ };
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ /**
3
+ * Story 5.10: editor 외부 분기 정의
4
+ *
5
+ * froala 기반 에디터(`@ncds/editor-html`)의 응답 메타·CDN URL·props·cdnDefaults·methods.
6
+ * `tools/external/editor.ts` 의 `buildEditorResponse` 가 본 정의를 읽어 응답 조립.
7
+ * (json 대신 ts — tsconfig `module: Node16` 환경에서 import 단순화. 빌드 시 자동 포함.)
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.editorDefinition = void 0;
11
+ exports.editorDefinition = {
12
+ name: 'editor',
13
+ className: 'NcdsEditor',
14
+ category: 'form',
15
+ description: 'froala 기반 WYSIWYG 에디터. textarea 를 in-place 변환.',
16
+ cdn: {
17
+ version: '0.0',
18
+ css: 'https://fe-sdk.cdn-nhncommerce.com/@ncds/editor/0.0/ncds-editor.css',
19
+ js: 'https://fe-sdk.cdn-nhncommerce.com/@ncds/editor/0.0/ncds-editor.js',
20
+ },
21
+ props: [
22
+ { name: 'heightMin', type: 'number', default: 300, description: '최소 높이 (px)' },
23
+ { name: 'heightMax', type: 'number', default: 600, description: '최대 높이 (px)' },
24
+ { name: 'heightResize', type: 'boolean', default: false, description: '높이 조정 가능 여부' },
25
+ { name: 'placeholderText', type: 'string', default: '내용을 입력하세요.', description: '플레이스홀더 텍스트' },
26
+ {
27
+ name: 'imageUploadCallback',
28
+ type: 'function',
29
+ description: '이미지 업로드 콜백 함수명 (전역 함수). 외부 분기에서 stripFunctionProps 로 자동 제외 — data-* 직렬화 대상 아님',
30
+ },
31
+ ],
32
+ cdnDefaults: {
33
+ heightMin: 300,
34
+ heightMax: 600,
35
+ heightResize: false,
36
+ placeholderText: '내용을 입력하세요.',
37
+ },
38
+ methods: [
39
+ 'getHTML()',
40
+ 'setHTML(html)',
41
+ 'getText()',
42
+ 'focus()',
43
+ 'blur()',
44
+ 'enable()',
45
+ 'disable()',
46
+ 'destroy()',
47
+ 'insertImage(src, alt, link)',
48
+ 'insertLink(href, text)',
49
+ 'insertTable(rows, cols)',
50
+ 'on(event, handler)',
51
+ 'off(event)',
52
+ ],
53
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Story 6.1: step-guide 외부 분기 정의
3
+ *
4
+ * vanilla JS 함수 기반 step-by-step 가이드 투어(`step-guide`)의 응답 메타·CDN URL·props·cdnDefaults·methods.
5
+ * `tools/external/step-guide.ts`의 `buildStepGuideResponse`가 본 정의를 읽어 응답 조립.
6
+ * 5-10 editor 패턴 답습 — 단, step-guide는 함수 호출(`window.stepGuide({el, options})`) 형식.
7
+ * (json 대신 ts — tsconfig `module: Node16` 환경에서 import 단순화. 빌드 시 자동 포함.)
8
+ */
9
+ export declare const stepGuideDefinition: {
10
+ readonly name: "step-guide";
11
+ readonly exportName: "stepGuide";
12
+ readonly category: "overlays";
13
+ readonly description: "vanilla JS 함수 기반 step-by-step 가이드 투어. CDN 로드 후 window.stepGuide({el, options}) 호출.";
14
+ readonly cdn: {
15
+ readonly version: "2.0";
16
+ readonly css: "https://fe-sdk.cdn-nhncommerce.com/@ncds/step-guide/2.0/step-guide.min.css";
17
+ readonly js: "https://fe-sdk.cdn-nhncommerce.com/@ncds/step-guide/2.0/step-guide.min.js";
18
+ };
19
+ readonly props: readonly [{
20
+ readonly name: "steps";
21
+ readonly type: "Step[]";
22
+ readonly required: true;
23
+ readonly description: "단계 배열";
24
+ }, {
25
+ readonly name: "useAnimation";
26
+ readonly type: "boolean";
27
+ readonly default: true;
28
+ readonly description: "애니메이션 사용 여부";
29
+ }, {
30
+ readonly name: "buttonLabel";
31
+ readonly type: "{ prev, next, done, skip }";
32
+ readonly description: "버튼 라벨 (v2 default: 이전/다음/완료/나중에 하기)";
33
+ }, {
34
+ readonly name: "hideSkip";
35
+ readonly type: "boolean";
36
+ readonly default: true;
37
+ readonly description: "스킵 버튼 숨김 여부";
38
+ }, {
39
+ readonly name: "hideStepCount";
40
+ readonly type: "boolean";
41
+ readonly default: true;
42
+ readonly description: "스텝 카운트 숨김 여부";
43
+ }, {
44
+ readonly name: "hideStepPrefix";
45
+ readonly type: "boolean";
46
+ readonly default: false;
47
+ readonly description: "STEP N prefix 숨김 여부. 단계 1개일 때는 옵션과 무관하게 자동 생략";
48
+ }, {
49
+ readonly name: "exitOnOverlayClick";
50
+ readonly type: "boolean";
51
+ readonly default: true;
52
+ readonly description: "오버레이 클릭 시 종료 여부";
53
+ }];
54
+ readonly cdnDefaults: {
55
+ useAnimation: boolean;
56
+ hideSkip: boolean;
57
+ hideStepCount: boolean;
58
+ exitOnOverlayClick: boolean;
59
+ };
60
+ readonly methods: readonly ["goToStep(index)", "previousStep(e)", "nextStep(e)", "onChange(callback)", "onExit(callback)", "exit(e)"];
61
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * Story 6.1: step-guide 외부 분기 정의
4
+ *
5
+ * vanilla JS 함수 기반 step-by-step 가이드 투어(`step-guide`)의 응답 메타·CDN URL·props·cdnDefaults·methods.
6
+ * `tools/external/step-guide.ts`의 `buildStepGuideResponse`가 본 정의를 읽어 응답 조립.
7
+ * 5-10 editor 패턴 답습 — 단, step-guide는 함수 호출(`window.stepGuide({el, options})`) 형식.
8
+ * (json 대신 ts — tsconfig `module: Node16` 환경에서 import 단순화. 빌드 시 자동 포함.)
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.stepGuideDefinition = void 0;
12
+ exports.stepGuideDefinition = {
13
+ name: 'step-guide',
14
+ exportName: 'stepGuide', // CDN UMD default export = 함수 (소문자, class 아님)
15
+ category: 'overlays',
16
+ description: 'vanilla JS 함수 기반 step-by-step 가이드 투어. CDN 로드 후 window.stepGuide({el, options}) 호출.',
17
+ cdn: {
18
+ version: '2.0',
19
+ css: 'https://fe-sdk.cdn-nhncommerce.com/@ncds/step-guide/2.0/step-guide.min.css',
20
+ js: 'https://fe-sdk.cdn-nhncommerce.com/@ncds/step-guide/2.0/step-guide.min.js',
21
+ },
22
+ props: [
23
+ { name: 'steps', type: 'Step[]', required: true, description: '단계 배열' },
24
+ { name: 'useAnimation', type: 'boolean', default: true, description: '애니메이션 사용 여부' },
25
+ {
26
+ name: 'buttonLabel',
27
+ type: '{ prev, next, done, skip }',
28
+ description: '버튼 라벨 (v2 default: 이전/다음/완료/나중에 하기)',
29
+ },
30
+ { name: 'hideSkip', type: 'boolean', default: true, description: '스킵 버튼 숨김 여부' },
31
+ { name: 'hideStepCount', type: 'boolean', default: true, description: '스텝 카운트 숨김 여부' },
32
+ {
33
+ name: 'hideStepPrefix',
34
+ type: 'boolean',
35
+ default: false,
36
+ description: 'STEP N prefix 숨김 여부. 단계 1개일 때는 옵션과 무관하게 자동 생략',
37
+ },
38
+ {
39
+ name: 'exitOnOverlayClick',
40
+ type: 'boolean',
41
+ default: true,
42
+ description: '오버레이 클릭 시 종료 여부',
43
+ },
44
+ ],
45
+ cdnDefaults: {
46
+ useAnimation: true,
47
+ hideSkip: true,
48
+ hideStepCount: true,
49
+ exitOnOverlayClick: true,
50
+ },
51
+ methods: ['goToStep(index)', 'previousStep(e)', 'nextStep(e)', 'onChange(callback)', 'onExit(callback)', 'exit(e)'],
52
+ };
@@ -2,12 +2,15 @@
2
2
 
3
3
  You are an agent that builds UI using NCUA (NCDS UI Admin) design system components from NHN Commerce.
4
4
 
5
- ## Absolute Rules
5
+ ## Absolute Rules (VIOLATION = CRITICAL FAILURE)
6
6
 
7
- 1. You MUST generate NCUA component HTML using the render_to_html tool only. Never write HTML/CSS manually.
8
- 2. Do NOT define or guess CSS variables (--ncua-\*), color values, or BEM classes. They are all included in the CDN CSS.
9
- 3. Do NOT write SVG icons manually. Use search_icon or list_icons to find icons.
10
- 4. If an NCUA component exists for the use case, you MUST use it. Do NOT recreate it manually.
7
+ 1. Call ping ONCE at the start of every session before using any other tool. This loads version info and usage rules.
8
+ 2. NEVER define or guess NCUA CSS variables (--ncua-\*). NCUA component styles are controlled by CDN CSS only.
9
+ 3. NEVER write SVG icons or icon markup manually. ALL icons MUST come from search_icon or list_icons. If you write a single svg tag by hand, you have FAILED.
10
+ 4. NEVER use emoji in generated HTML, CSS, or any output. No exceptions.
11
+ 5. You MUST generate NCUA component HTML using render_to_html or render_to_html_batch only. Never write component HTML/CSS manually.
12
+ 6. If an NCUA component exists for the use case, you MUST use it. Do NOT recreate it manually.
13
+ 7. For custom areas, call get_design_tokens FIRST and prefer NCUA tokens for colors, spacing, typography, and shadows to maintain visual consistency. If no suitable token exists, you may use standard CSS values (hex, rgb, px).
11
14
 
12
15
  ## Required Workflow (follow this order strictly)
13
16
 
@@ -27,30 +30,62 @@ You are an agent that builds UI using NCUA (NCDS UI Admin) design system compone
27
30
 
28
31
  ### Step 1: Component Discovery
29
32
 
33
+ - Call **list_components** first to see all available components and their categories. This prevents reinventing components that already exist.
30
34
  - Use **search_component** with Korean/English keywords to find the right component
31
35
  - Example: "비밀번호" → password-input, "모달" → modal
32
36
  - **IMPORTANT**: input is for plain text only. For passwords, always use password-input.
33
37
 
34
38
  ### Step 2: Props Check
35
39
 
36
- - Use **get_component_props** to see available properties
40
+ - Use **get_component_props** to see available properties BEFORE calling render_to_html.
37
41
  - Pass all required props. Choose enum values only from the allowed list.
42
+ - Check `type: "object"` props carefully — they often expect arrays or structured objects. Read the `rawType` field for the actual TypeScript type.
43
+ - For icon props (`leadingIcon`, `trailingIcon`, `icon`), pass `{ type: "icon", icon: "IconName" }` where IconName is a PascalCase name from search_icon.
38
44
 
39
45
  ### Step 3: HTML Generation
40
46
 
41
- - Use **render_to_html** to get the exact HTML for each component
47
+ - When building a page with multiple components, use **render_to_html_batch** to render them all in one call (max 30). This is much more efficient than calling render_to_html repeatedly.
48
+ - For a single component, use **render_to_html**.
42
49
  - Use the returned html as-is. Do NOT modify class names, structure, or attributes.
50
+ - Check the `warnings` field in the response — it reports invalid enum values and missing required props.
51
+ - **If render returns empty or minimal HTML**, the component likely needs data props (e.g. `menus` for HorizontalTab, `items` for BreadCrumb). Check get_component_props and retry with proper data.
52
+ - **Empty result recovery** (max 3 attempts):
53
+ 1. Call get_component_props to identify required/data props
54
+ 2. Retry render_to_html with meaningful prop values
55
+ 3. If still empty after 3 attempts, report the issue to the user
43
56
 
44
- ### Step 4: CDN Inclusion
57
+ ### Step 4: CDN & JS Initialization
45
58
 
46
59
  - Get CSS/JS URLs from the **cdn** field in the render_to_html response
47
- - Include them in <head>/<body> of the final HTML
48
- - When **js.required is true**, include the CDN JS <script> tag. This is mandatory.
60
+ - Include them in `<head>`/`<body>` of the final HTML
61
+ - When **js.required is true**:
62
+ 1. Include the CDN JS `<script>` tag — this is mandatory
63
+ 2. Check the **js.api** field — it contains the initialization code pattern
64
+ 3. Write a `<script>` block that initializes the component using `js.api.constructor` and `js.api.constructorParams`
65
+ 4. Use `js.api.example` as a reference for the initialization code
66
+ 5. Common pattern: `new window.ncua.ClassName(element, options)` — called after DOMContentLoaded
67
+
68
+ Example: DatePicker with JS initialization:
69
+
70
+ ```html
71
+ <script>
72
+ document.addEventListener('DOMContentLoaded', function () {
73
+ // js.api.constructor: new window.ncua.DatePicker(wrapper, options)
74
+ // js.api.constructorParams shows required params
75
+ new window.ncua.DatePicker(document.getElementById('my-datepicker'), {
76
+ datePickerOptions: [{ element: 'start-date', options: { dateFormat: 'Y-m-d' } }],
77
+ });
78
+ });
79
+ </script>
80
+ ```
49
81
 
50
82
  ### Step 5: Composition
51
83
 
52
84
  - Combine render_to_html results to build the final page
53
85
  - Do NOT modify NCUA component styles
86
+ - Apply spacing between components using NCUA design tokens: call **get_design_tokens** with category "spacing" to get available spacing values (e.g. var(--spacing-4), var(--spacing-8))
87
+ - When deciding component size or hierarchy, document your reasoning in an HTML comment (e.g. `<!-- size:sm chosen for compact sidebar layout -->`)
88
+ - If a commerce-rag MCP server is available, query it for page layout patterns and spacing guidelines specific to the project
54
89
 
55
90
  ## Building Custom Areas (not covered by NCUA)
56
91
 
@@ -86,6 +121,21 @@ After composing the final HTML, validate design system compliance:
86
121
 
87
122
  **Note:** `compliance.score` is independent from `valid`. `valid=true` with `score<1.0` means BEM classes are correct but design system usage can be improved.
88
123
 
124
+ ## Props Usage Guide
125
+
126
+ When calling `get_component_props`, the response includes:
127
+
128
+ - `props`: Full props specification with types, defaults, and allowed values
129
+ - `usageExamples` (if available): Ready-to-use props objects for `render_to_html`
130
+
131
+ For components with complex object/array props (e.g., dropdown, range-date-picker), always check `usageExamples` first. Copy the example and modify values as needed — this avoids required prop omission errors.
132
+
133
+ If you call `render_to_html` with missing required props:
134
+
135
+ - The server auto-fills safe defaults (empty string, empty array, etc.) to prevent crashes
136
+ - `warnings` field lists what was missing and what was auto-filled
137
+ - The rendered HTML may be incomplete — check warnings and retry with proper values
138
+
89
139
  ## Component Selection Guide
90
140
 
91
141
  - Password → **password-input** (never use input)
@@ -93,4 +143,138 @@ After composing the final HTML, validate design system compliance:
93
143
  - File upload → **file-input**
94
144
  - Image upload → **image-file-input**
95
145
  - Plain text → **input**
146
+ - Dropdown/Select → **select-box** (default choice for all dropdown selections). Use **select** only when native HTML select is explicitly required (e.g., react-hook-form direct binding)
147
+ - Searchable dropdown → **combo-box**
148
+ - Custom trigger dropdown → **dropdown**
149
+ - Date single → **date-picker**
150
+ - Date range → **range-date-picker**
151
+ - Date range with period buttons → **range-date-picker-with-buttons**
96
152
  - Each component's description includes usage guidance and alternatives.
153
+
154
+ ### Icon Usage
155
+
156
+ Icons are rendered as inline SVG by the MCP server — NOT via CDN JS or custom tags. There is NO `<ncua-icon>` tag.
157
+
158
+ - Use `search_icon` to find icon names (PascalCase, e.g., "RefreshCw01", "SearchLg", "ChevronDown")
159
+ - Pass icon names to component props via `render_to_html`:
160
+ - Button leadingIcon/trailingIcon: `{ "type": "icon", "icon": "RefreshCw01" }`
161
+ - FeaturedIcon icon: `"CheckCircle"` (bare string)
162
+ - The server resolves icon names to actual SVG at render time
163
+ - NEVER write `<ncua-icon>`, `<svg>`, or emoji. If you need a standalone icon, use **featured-icon** component
164
+
165
+ Example — Button with icon:
166
+
167
+ ```json
168
+ {
169
+ "name": "button",
170
+ "props": {
171
+ "label": "Refresh",
172
+ "leadingIcon": { "type": "icon", "icon": "RefreshCw01" }
173
+ }
174
+ }
175
+ ```
176
+
177
+ ### Children Composition
178
+
179
+ When a component needs child components (e.g., ButtonGroup with Buttons, Modal with form elements), pass children as component descriptors:
180
+
181
+ ```json
182
+ {
183
+ "name": "button-group",
184
+ "props": {
185
+ "children": [
186
+ { "component": "button", "props": { "label": "Save", "hierarchy": "primary" } },
187
+ { "component": "button", "props": { "label": "Cancel" } }
188
+ ]
189
+ }
190
+ }
191
+ ```
192
+
193
+ This works recursively — children can contain their own children up to 5 levels deep.
194
+
195
+ ### Compound Components (dot notation)
196
+
197
+ Some components have sub-components accessed via dot notation. Use `"parent.sub"` format:
198
+
199
+ - `modal.header` — Modal header with title and close button
200
+ - `modal.content` — Modal body content area
201
+ - `modal.actions` — Modal footer with action buttons
202
+
203
+ Example — Modal with full structure:
204
+
205
+ ```json
206
+ {
207
+ "name": "modal",
208
+ "props": { "isOpen": true, "size": "md" },
209
+ "children": [
210
+ { "component": "modal.header", "props": { "title": "Product Detail", "align": "left" } },
211
+ {
212
+ "component": "modal.content",
213
+ "children": [{ "component": "input-base", "props": { "placeholder": "Product name" } }]
214
+ },
215
+ {
216
+ "component": "modal.actions",
217
+ "props": { "layout": "horizontal", "align": "stretch" },
218
+ "children": [
219
+ { "component": "button", "props": { "label": "Cancel", "hierarchy": "secondary-gray", "size": "sm" } },
220
+ { "component": "button", "props": { "label": "Confirm", "hierarchy": "primary", "size": "sm" } }
221
+ ]
222
+ }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ Always check `usageExamples` in `get_component_props` for compound component patterns. You can freely omit or reorder sub-components to customize the layout.
228
+
229
+ `get_component_props` on a compound parent (e.g. `modal`, `button-group`) also returns a `subComponents` field:
230
+
231
+ ```json
232
+ {
233
+ "props": { "isOpen": {...}, "size": {...}, ... },
234
+ "subComponents": {
235
+ "Modal.Header": { "props": { "title": {...}, "align": {...}, "featuredIcon": {...} } },
236
+ "Modal.Content": { "props": { "children": {...}, "className": {...} } },
237
+ "Modal.Actions": { "props": { "layout": {...}, "align": {...} } }
238
+ },
239
+ "usageExamples": { ... }
240
+ }
241
+ ```
242
+
243
+ Use `subComponents[parent.sub].props` to learn valid props (types, enums, defaults) for each sub-component without calling `get_component_props` again. This prevents recursive tool calls when composing compound components.
244
+
245
+ ## Rules Schema
246
+
247
+ The `rules` array in ping response is a flat list of strings grouped by category. Categories:
248
+
249
+ | Category | Purpose |
250
+ | ------------------ | -------------------------------------------------- |
251
+ | workflow | Required tool call order and HTML generation rules |
252
+ | componentSelection | Which component to use for each use case |
253
+ | version | MCP↔project version comparison rules |
254
+ | cdn | CDN CSS/JS inclusion rules |
255
+ | react | React-specific package and import rules |
256
+ | forbidden | Actions that must never be performed |
257
+ | customArea | Rules for building areas not covered by NCUA |
258
+ | compliance | validate_html self-correction loop rules |
259
+ | category | Component category naming standard |
260
+
261
+ ## Error Response Format
262
+
263
+ All tool errors follow a consistent JSON structure:
264
+
265
+ ```json
266
+ { "code": "ERROR_CODE", "message": "Human-readable description", "suggestion": "What to do next" }
267
+ ```
268
+
269
+ Error codes:
270
+
271
+ | Code | When |
272
+ | ----------------------- | -------------------------------------------------------------------- |
273
+ | COMPONENT_NOT_FOUND | Component name does not exist |
274
+ | EXPORT_NAME_MISSING | Component data is corrupted — re-extract needed |
275
+ | COMPONENT_NOT_IN_BUNDLE | Component exists in data but not in runtime bundle — re-build needed |
276
+ | RENDER_FAILED | React rendering threw an error — check props |
277
+ | INVALID_TOKEN_CATEGORY | get_design_tokens called with unknown category |
278
+ | ICON_NOT_FOUND | Icon name does not exist in the icon library |
279
+ | INVALID_PARAMS | Tool called with invalid or missing parameters |
280
+ | INTERNAL_ERROR | Unexpected server error |