@ncds/ui-admin-mcp 1.0.0-alpha.20 → 1.0.0-alpha.22
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/README.md +3 -3
- package/bin/components.bundle.js +21 -8
- package/bin/definitions/instructions.md +6 -3
- package/bin/definitions/js-api.json +80 -0
- package/bin/definitions/rules.json +8 -4
- package/bin/overrides/composition.json +337 -61
- package/bin/server.js +6 -3
- package/bin/tools/renderToHtml.js +2 -1
- package/bin/types.d.ts +2 -0
- package/bin/utils/tokenValidator.js +33 -3
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/data/badge-group.json +8 -8
- package/data/badge.json +18 -14
- package/data/bread-crumb.json +1 -0
- package/data/combo-box.json +5 -0
- package/data/dropdown.json +2 -0
- package/data/file-input.json +4 -2
- package/data/horizontal-tab.json +3 -1
- package/data/image-file-input.json +5 -2
- package/data/notification.json +1 -0
- package/data/page-title.json +1 -0
- package/data/progress-bar.json +1 -0
- package/data/range-date-picker-with-buttons.json +3 -2
- package/data/range-date-picker.json +1 -1
- package/data/select-box.json +5 -0
- package/data/select.json +1 -0
- package/data/table.json +4 -2
- package/data/tooltip.json +4 -0
- package/data/vertical-tab.json +3 -1
- package/package.json +2 -2
- package/templates/README.md +1 -1
|
@@ -31,16 +31,19 @@ You are an agent that builds UI using NCUA (NCDS UI Admin) design system compone
|
|
|
31
31
|
### Step 1: Component Discovery
|
|
32
32
|
|
|
33
33
|
- Call **list_components** first to see all available components and their categories. This prevents reinventing components that already exist.
|
|
34
|
-
-
|
|
34
|
+
- Call **list_composition_overrides** to see which components have canonical examples and composition constraints. Components with `coverageScore ≥ 0.7` have ready-to-use scenarios — always check these before rendering. This call is MANDATORY before Step 3.
|
|
35
|
+
- Use **search_component** with Korean/English keywords to find the right component.
|
|
35
36
|
- Example: "비밀번호" → password-input, "모달" → modal
|
|
37
|
+
- If icons are needed, use **search_icon** or **list_icons** at this stage — NEVER write SVG manually.
|
|
36
38
|
- **IMPORTANT**: input is for plain text only. For passwords, always use password-input.
|
|
37
39
|
|
|
38
|
-
### Step 2: Props Check
|
|
40
|
+
### Step 2: Props & Token Check
|
|
39
41
|
|
|
40
42
|
- Use **get_component_props** to see available properties BEFORE calling render_to_html.
|
|
41
43
|
- Pass all required props. Choose enum values only from the allowed list.
|
|
42
44
|
- Check `type: "object"` props carefully — they often expect arrays or structured objects. Read the `rawType` field for the actual TypeScript type.
|
|
43
45
|
- For icon props (`leadingIcon`, `trailingIcon`, `icon`), pass `{ type: "icon", icon: "IconName" }` where IconName is a PascalCase name from search_icon.
|
|
46
|
+
- If the page has custom areas (non-NCUA elements), call **get_design_tokens** NOW — before rendering — to get available tokens for colors, spacing, and typography. Do NOT hardcode hex/px values.
|
|
44
47
|
|
|
45
48
|
### Step 3: HTML Generation
|
|
46
49
|
|
|
@@ -83,7 +86,7 @@ Example: DatePicker with JS initialization:
|
|
|
83
86
|
|
|
84
87
|
- Combine render_to_html results to build the final page
|
|
85
88
|
- Do NOT modify NCUA component styles
|
|
86
|
-
- Apply spacing between components using NCUA design tokens
|
|
89
|
+
- Apply spacing between components using NCUA design tokens fetched in Step 2 (e.g. var(--spacing-4), var(--spacing-8)). If you skipped Step 2, call **get_design_tokens** now before writing any custom CSS.
|
|
87
90
|
- When deciding component size or hierarchy, document your reasoning in an HTML comment (e.g. `<!-- size:sm chosen for compact sidebar layout -->`)
|
|
88
91
|
- If a commerce-rag MCP server is available, query it for page layout patterns and spacing guidelines specific to the project
|
|
89
92
|
|
|
@@ -93,6 +93,86 @@
|
|
|
93
93
|
]
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
|
+
"RangeDatePicker": {
|
|
97
|
+
"className": "DatePicker",
|
|
98
|
+
"cdnPattern": "A",
|
|
99
|
+
"constructor": "new window.ncua.DatePicker(wrapper, options)",
|
|
100
|
+
"constructorParams": {
|
|
101
|
+
"wrapper": "HTMLElement — container element",
|
|
102
|
+
"options.size": "'xs' | 'sm'",
|
|
103
|
+
"options.datePickerOptions": "Array<{ element: string, attrName?: string, placeholder?: string, options: FlatpickrOptions }> — 각 요소의 options.static:true 필수(누락 시 flatpickr-wrapper 미생성으로 레이아웃 파괴). options: { mode:'range', static:true, dateFormat:'Y-m-d', clickOpens:true, allowInvalidPreload:true, locale:'ko' }",
|
|
104
|
+
"options.buttons": "Array<{ text: string, period: number, unit: 'days'|'weeks'|'months'|'years', isCurrent: boolean }>",
|
|
105
|
+
"options.onValidationError": "(error: ValidationError) => void",
|
|
106
|
+
"options.autoComplete": "'on' | 'off'"
|
|
107
|
+
},
|
|
108
|
+
"methods": ["getDates()", "setDate(dates: string[])", "setMultipleDates(dates: string[])"],
|
|
109
|
+
"example": "const dp = new window.ncua.DatePicker(document.getElementById('my-range-dp'), {\n size: 'xs',\n datePickerOptions: [\n { element: 'start-date', placeholder: '시작일', options: { dateFormat: 'Y-m-d', locale: 'ko' } },\n { element: 'end-date', placeholder: '종료일', options: { dateFormat: 'Y-m-d', locale: 'ko' } }\n ]\n});",
|
|
110
|
+
"cdnDefaults": {
|
|
111
|
+
"size": "xs",
|
|
112
|
+
"datePickerOptions": [
|
|
113
|
+
{
|
|
114
|
+
"options": {
|
|
115
|
+
"mode": "range",
|
|
116
|
+
"static": true,
|
|
117
|
+
"dateFormat": "Y-m-d",
|
|
118
|
+
"clickOpens": true,
|
|
119
|
+
"allowInvalidPreload": true,
|
|
120
|
+
"locale": "ko"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"options": {
|
|
125
|
+
"mode": "range",
|
|
126
|
+
"static": true,
|
|
127
|
+
"dateFormat": "Y-m-d",
|
|
128
|
+
"clickOpens": true,
|
|
129
|
+
"allowInvalidPreload": true,
|
|
130
|
+
"locale": "ko"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"RangeDatePickerWithButtons": {
|
|
137
|
+
"className": "DatePicker",
|
|
138
|
+
"cdnPattern": "A",
|
|
139
|
+
"constructor": "new window.ncua.DatePicker(wrapper, options)",
|
|
140
|
+
"constructorParams": {
|
|
141
|
+
"wrapper": "HTMLElement — container element",
|
|
142
|
+
"options.size": "'xs' | 'sm'",
|
|
143
|
+
"options.datePickerOptions": "Array<{ element: string, attrName?: string, placeholder?: string, options: FlatpickrOptions }> — 각 요소의 options.static:true 필수(누락 시 flatpickr-wrapper 미생성으로 레이아웃 파괴). options: { mode:'range', static:true, dateFormat:'Y-m-d', clickOpens:true, allowInvalidPreload:true, locale:'ko' }",
|
|
144
|
+
"options.buttons": "Array<{ text: string, period: number, unit: 'days'|'weeks'|'months'|'years', isCurrent: boolean }> — 권장 세트: 오늘(period:0,unit:days)/7일/15일/1개월(unit:months)/3개월/1년(unit:years). ENTIRE·1주일(unit:weeks) CDN 미지원 제외.",
|
|
145
|
+
"options.onValidationError": "(error: ValidationError) => void",
|
|
146
|
+
"options.autoComplete": "'on' | 'off'"
|
|
147
|
+
},
|
|
148
|
+
"methods": ["getDates()", "setDate(dates: string[])", "setMultipleDates(dates: string[])"],
|
|
149
|
+
"example": "const dp = new window.ncua.DatePicker(document.getElementById('my-range-dp'), {\n size: 'xs',\n datePickerOptions: [\n { element: 'start-date', placeholder: '시작일', options: { dateFormat: 'Y-m-d', locale: 'ko' } },\n { element: 'end-date', placeholder: '종료일', options: { dateFormat: 'Y-m-d', locale: 'ko' } }\n ],\n buttons: [\n { text: '오늘', period: 0, unit: 'days', isCurrent: false },\n { text: '7일', period: 7, unit: 'days', isCurrent: false },\n { text: '15일', period: 15, unit: 'days', isCurrent: false },\n { text: '1개월', period: 1, unit: 'months', isCurrent: false },\n { text: '3개월', period: 3, unit: 'months', isCurrent: false },\n { text: '1년', period: 1, unit: 'years', isCurrent: false }\n ]\n});",
|
|
150
|
+
"cdnDefaults": {
|
|
151
|
+
"size": "xs",
|
|
152
|
+
"datePickerOptions": [
|
|
153
|
+
{
|
|
154
|
+
"options": {
|
|
155
|
+
"mode": "range",
|
|
156
|
+
"static": true,
|
|
157
|
+
"dateFormat": "Y-m-d",
|
|
158
|
+
"clickOpens": true,
|
|
159
|
+
"allowInvalidPreload": true,
|
|
160
|
+
"locale": "ko"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"options": {
|
|
165
|
+
"mode": "range",
|
|
166
|
+
"static": true,
|
|
167
|
+
"dateFormat": "Y-m-d",
|
|
168
|
+
"clickOpens": true,
|
|
169
|
+
"allowInvalidPreload": true,
|
|
170
|
+
"locale": "ko"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
},
|
|
96
176
|
"Slider": {
|
|
97
177
|
"className": "Slider",
|
|
98
178
|
"cdnPattern": "A",
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"workflow": [
|
|
3
|
+
"Tool call order (strictly follow): Phase 0 — ping (once per session). Phase 1 — list_components + list_composition_overrides + search_component (+ search_icon if icons needed). Phase 2 — get_component_props + get_design_tokens (if custom areas exist). Phase 3 — render_to_html_batch or render_to_html. Phase 4 — validate_html (loop until score=1.0).",
|
|
3
4
|
"You MUST generate component HTML using the render_to_html tool. Never write HTML/CSS manually.",
|
|
4
5
|
"Use the HTML returned by render_to_html as-is. Do NOT modify class names, structure, or attributes.",
|
|
6
|
+
"MANDATORY in Phase 1: call list_composition_overrides before any render_to_html call. Components with coverageScore >= 0.7 have canonical examples — read them and use the matching scenario. Skipping this call is the leading cause of page-prefix BEM mimicry and placeholder-only output.",
|
|
5
7
|
"Use search_component to find the right component by Korean/English keywords before building any UI.",
|
|
6
8
|
"Use list_components to browse available components by category and choose the appropriate one.",
|
|
7
|
-
"When building a page with multiple components, use render_to_html_batch to render them all in one call instead of calling render_to_html repeatedly."
|
|
9
|
+
"When building a page with multiple components, use render_to_html_batch to render them all in one call instead of calling render_to_html repeatedly.",
|
|
10
|
+
"Call get_design_tokens in Phase 2 (before rendering), not after. Custom area CSS written without tokens first leads to hardcoded hex/px values that violate design system rules."
|
|
8
11
|
],
|
|
9
12
|
"componentSelection": [
|
|
10
13
|
"For password fields, you MUST use password-input. The input component is for plain text only.",
|
|
@@ -45,14 +48,14 @@
|
|
|
45
48
|
"composition": [
|
|
46
49
|
"Vertical Table row labels MUST use Table.Cell with isHeader=true (renders <th scope='row' class='ncua-table__cell'>). Do NOT use Table.HeaderCell in Vertical Table — that class (ncua-table__header-cell) is exclusively for Horizontal Table column headers inside <thead>. Pick the correct scenario from canonicalExamples: 'vertical-form-label' for form layouts, 'horizontal-with-header-cell' for data lists.",
|
|
47
50
|
"For required field labels in Vertical Table, use the official NCDS element <span class='ncua-table__required'>*</span> prepended INSIDE the <th scope='row'> cell, BEFORE the label text. Do NOT invent page-prefix variants like sgr-label__required / form-required / etc. — ncua-table__required is the canonical required-mark element. See canonicalExamples key 'vertical-form-label-with-required'.",
|
|
48
|
-
"For page-level title/breadcrumb/action area, ALWAYS use the NCUA 'page-title' component (PageTitle) via render_to_html — props: breadcrumbItems, title, primaryAction, secondaryAction, guideButton, onBack, variant (default/detail/fixed). Do NOT invent page-prefix custom classes like sgr-page-title, page-header, gd-page-title — page-title is in the catalog (list_components → category=layout). Output BEM is ncua-page-title__page-header / __title-container / __title-row / __title / __action-area / __breadcrumb-item etc. Pick the right canonicalExamples scenario (default/with-guide-button/detail-with-back/fixed-on-scroll) and modify only the values, not the props shape.",
|
|
51
|
+
"For page-level title/breadcrumb/action area, ALWAYS use the NCUA 'page-title' component (PageTitle) via render_to_html — props: breadcrumbItems, title, primaryAction, secondaryAction, guideButton, onBack, variant (default/detail/fixed). Do NOT invent page-prefix custom classes like sgr-page-title, page-header, gd-page-title — page-title is in the catalog (list_components → category=layout). Output BEM is ncua-page-title__page-header / __title-container / __title-row / __title / __action-area / __breadcrumb-item etc. Pick the right canonicalExamples scenario (default/with-guide-button/detail-with-back/fixed-on-scroll) and modify only the values, not the props shape. ⚠️ P20 — ReactNode props(primaryAction / secondaryAction / guideButton)는 반드시 {component: 'button', props: {...}} 형태로 전달. {label:..., size:..., hierarchy:...} raw 객체를 직접 넘기면 'Objects are not valid as a React child' 오류로 render_to_html 전체 실패(breadcrumb 포함). 모든 canonicalExamples 가 {component, props} 패턴임을 확인하고 그대로 따를 것.",
|
|
49
52
|
"For tooltips on form fields, ALWAYS use the NCUA 'tooltip' component via render_to_html('tooltip', props={...}). Do NOT invent custom classes like tooltip-custom-code, tooltip-helper, sgr-tooltip — tooltip is in the catalog and supports content/title/iconStyle/iconType/position/size/tooltipType/type props. See canonicalExamples 'icon-help-form-field' / 'with-title-and-body' / 'alert-warning'.",
|
|
50
53
|
"NCDS does NOT provide RadioGroup or CheckboxGroup wrapper components. When grouping multiple radio/checkbox items, wrap them with a PAGE-PREFIX class (e.g. <div class='sgr-radio-group'> or <div class='order-form__check-group'>) — NEVER use inline style attribute (e.g. style='display:flex;gap:16px') and NEVER reuse ncua- prefix for the wrapper. Define wrapper CSS in page-level SCSS using NCDS spacing/color tokens (var(--spacing-md), var(--gray-100)) — no hardcoded hex/px values.",
|
|
51
54
|
"⚠️ React props ≠ CDN JS options. The component's React props (in get_component_props.props) and CDN JS constructor options (in render_to_html response's js.api.constructorParams) ARE DIFFERENT. React-only props that do NOT appear in js.api.constructorParams MUST NOT be passed as CDN options. Concrete example: Tooltip.iconStyle exists as React prop ('help-circle' | 'alert-circle') but is NOT a CDN option (allowed CDN options: position / type / tooltipType / iconType / size / hideArrow / zIndex / useShadowDOM / className). When generating CDN HTML mode code, copy js.api.example AS-IS from render_to_html response — do NOT mix React props into CDN options.",
|
|
52
55
|
"⚠️ When js.api.cdnPattern is 'C' (Tooltip / Notification / Slider etc.), the component uses a STATIC FACTORY, NOT new Component(options). Use exactly the signature shown in js.api.constructor (e.g. window.ncua.Tooltip.createShort(title, content, options)). Never write `new ncua.Tooltip({title, content, ...options})` — that pattern is wrong because title/content are positional arguments, not options. Always reference render_to_html response's js.api.example and copy verbatim.",
|
|
53
56
|
"⚠️ P13 — Vertical form layouts MUST be rendered by render_to_html('table', { type: 'vertical', ... }). The same 'table' component handles BOTH horizontal (data grid) AND vertical (form layout) modes via the `type` prop. Do NOT compose vertical table HTML from scratch. Do NOT use <th class='ncua-table__header-cell'> for vertical labels — that class is horizontal-only. For vertical labels, render_to_html outputs <th scope='row' class='ncua-table__cell'> (Table.Cell with isHeader=true). The required mark in vertical is <span class='ncua-table__required'>*</span> prepended inside the <th> — NOT a page-prefix span like gp-required / sgr-required / pw-required / form-required.",
|
|
54
57
|
"For form layouts (label-value rows), ALWAYS call get_component_props('table') first and read canonicalExamples 'vertical-form-label' / 'vertical-form-label-with-required'. Search keywords that resolve to 'table' component: vertical-table, form-table, form-layout, label-value, 폼 레이아웃, 라벨-입력, 세로 테이블. Do NOT compose vertical table HTML by hand.",
|
|
55
|
-
"⚠️ P14 — BlockContainer 의 본문은 반드시 BlockContainer.Body (component descriptor: 'block-container.body') 로 wrap. 직접 <section class='ncua-block-container'> 아래에 table/data-grid 를 자식으로 넣으면 ncua-block-container__body 패딩(16px 24px) 누락 — 시각적 호흡 사라짐. 표준 구조: BlockContainer > BlockHeader + BlockContainer.Body > [실제 컨텐츠]. canonicalExamples 'form-block' / 'data-block' / 'info-block' 참고.",
|
|
58
|
+
"⚠️ P14 — BlockContainer 의 본문은 반드시 BlockContainer.Body (component descriptor: 'block-container.body') 로 wrap. 직접 <section class='ncua-block-container'> 아래에 table/data-grid 를 자식으로 넣으면 ncua-block-container__body 패딩(16px 24px) 누락 — 시각적 호흡 사라짐. 표준 구조: BlockContainer > BlockHeader + BlockContainer.Body > [실제 컨텐츠]. canonicalExamples 'form-block' / 'data-block' / 'info-block' 참고. ⚠️ 페이지 고유 prefix를 붙인 커스텀 block wrapper({page}-block / {page}-section / {page}-panel 등 어떤 이름이든) 생성 절대 금지 — 모두 block-container 로 대체 가능.",
|
|
56
59
|
"⚠️ P15 — horizontal-tab / carousel components are Swiper.js based. Their internal markup is `.ncua-horizontal-tab > .swiper > .swiper-wrapper > .swiper-slide.ncua-horizontal-tab__item > .ncua-tab-button`. Active tab uses `.ncua-tab-button.is-active`. NEVER hand-write markup with invented classes like `.ncua-horizontal-tab__menu` or `.ncua-horizontal-tab__menu--active` — those classes DO NOT EXIST. Always call render_to_html('horizontal-tab', { menus, activeTab, ... }) — pass menus as a data array, never as JSX children. The CDN JS auto-initializes the swiper instance.",
|
|
57
60
|
"⚠️ P15 — JS-instantiated components (those with js.required=true and a cdnPattern, e.g. image-file-input / tooltip / notification / slider / pagination) return a placeholder `<div id> + <script>` from render_to_html. The visible markup appears EMPTY until DOMContentLoaded fires and the CDN JS populates it. This is CORRECT behavior — do NOT replace the placeholder with hand-written `<div class='ncua-image-file-input'>...<button class='ncua-btn'>파일 찾기</button>...</div>` markup because it 'looks empty in the wireframe'. The hand-written version diverges from the actual CDN runtime output. Use the placeholder + script as-is.",
|
|
58
61
|
"⚠️ P16 — Vertical Table 라벨 옆 안내 아이콘은 반드시 Table.Cell 의 `tooltip` prop (TooltipProps) 으로 전달. Cell 내부에서 `ncua-table__cell-inner` / `ncua-table__cell-label` / `.ncua-tooltip` 구조로 자동 wrapping 되고 `ncua-table__cell--with-tooltip` modifier 가 부착된다. 라벨 셀 외부에 별도 Tooltip 컴포넌트를 배치하거나 페이지 prefix wrapper (예: page-vlabel, sgr-tooltip-wrapper, gd-label-with-help) 로 라벨과 아이콘을 묶지 말 것 — 정렬 어긋남 + 발명 클래스 hallucination 의 주원인. canonicalExamples 'vertical-form-label-with-tooltip' 시나리오 참고.",
|
|
@@ -70,8 +73,9 @@
|
|
|
70
73
|
"Custom areas MUST use ONLY existing NCUA design tokens (CSS variables from CDN) for colors, fonts, spacing, and shadows. Do NOT hardcode hex values like #5B5BD6 or rgb values.",
|
|
71
74
|
"Do NOT invent token names. If no exact token exists, choose the closest available token. Never fall back to raw color/size values.",
|
|
72
75
|
"Before writing custom CSS, call get_design_tokens to see available tokens. Filter by category (color, typography, spacing, shadow) to reduce response size.",
|
|
76
|
+
"⚠️ P26 — Spacing token naming is single/double-letter suffixes, NOT Bootstrap/Tailwind-style. Correct NCDS spacing tokens: --spacing-xs(4px) / --spacing-s(8px) / --spacing-m(16px) / --spacing-l(24px) / --spacing-xl(32px) / --spacing-xxl(40px). --spacing-sm and --spacing-md DO NOT EXIST in NCDS (those are Bootstrap/Tailwind conventions that collide). validate_html will report invalid_token with get_design_tokens('spacing') suggestion when these are detected. Always call get_design_tokens('spacing') to verify token names before writing CSS.",
|
|
73
77
|
"For spacing, use spacing tokens (--spacing-xs through --spacing-xxl) instead of hardcoded px values. Follow the principle: inner-block spacing < between-block spacing.",
|
|
74
|
-
"Even inside inline `style=` attributes, spacing properties (gap / padding / margin / min-width / max-width / width / height) MUST use NCDS tokens via `var(--spacing-xs|
|
|
78
|
+
"Even inside inline `style=` attributes, spacing properties (gap / padding / margin / min-width / max-width / width / height) MUST use NCDS tokens via `var(--spacing-xs|s|m|l|xl|xxl)`. Raw px values like `gap:8px`, `padding:40px`, `min-width:280px` are forbidden in inline style as well. Pure layout properties (display:flex, flex-direction, align-items, justify-content, position) are allowed inline since they have no token equivalent. If a wrapper needs styling beyond pure layout, move it to a page-prefix CSS class in your stylesheet and reference tokens there.",
|
|
75
79
|
"⚠️ P24 — Custom area (sgr-* / page-prefix) 가 텍스트를 노출하면 font-family 도 NCDS 표준(CommerceSans) 으로 명시. CDN CSS 는 ncua-* 컴포넌트에만 폰트를 깔아주므로 custom area 는 inheritance 가 끊길 수 있다. 표준 표기: `font-family: var(--font-families-commerce-sans);` (권장) 또는 풀 스택 `CommerceSans, 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif`. 자세한 금지/허용 패턴은 fontFamily 섹션 P14/P15/P24 참고."
|
|
76
80
|
],
|
|
77
81
|
"compliance": [
|