@monoharada/wcf-mcp 0.5.0 → 0.7.0

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.
@@ -0,0 +1,102 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "categories": [
4
+ {
5
+ "key": "Form",
6
+ "label": "フォーム入力",
7
+ "description": "User input, selection, and form control components",
8
+ "components": [
9
+ { "id": "input-text", "tagName": "dads-input-text", "useCase": "Single-line text input (name, email, phone, etc.)" },
10
+ { "id": "textarea", "tagName": "dads-textarea", "useCase": "Multi-line text input (comments, descriptions, notes)" },
11
+ { "id": "select", "tagName": "dads-select", "useCase": "Dropdown selection from predefined options" },
12
+ { "id": "checkbox", "tagName": "dads-checkbox", "useCase": "Boolean toggle or multi-select checkboxes" },
13
+ { "id": "radio", "tagName": "dads-radio", "useCase": "Single selection from mutually exclusive options" },
14
+ { "id": "switch", "tagName": "dads-switch", "useCase": "On/off toggle for settings or preferences" },
15
+ { "id": "combobox", "tagName": "dads-combobox", "useCase": "Text input with autocomplete/suggestion dropdown" },
16
+ { "id": "date-picker", "tagName": "dads-date-picker", "useCase": "Date selection with calendar interface" },
17
+ { "id": "file-upload", "tagName": "dads-file-upload", "useCase": "File attachment and upload" },
18
+ { "id": "fieldset", "tagName": "dads-fieldset", "useCase": "Group related form fields with legend" },
19
+ { "id": "search-box", "tagName": "dads-search-box", "useCase": "Search input with clear/submit actions" },
20
+ { "id": "calendar", "tagName": "dads-calendar", "useCase": "Calendar date picker component" }
21
+ ]
22
+ },
23
+ {
24
+ "key": "Actions",
25
+ "label": "アクション",
26
+ "description": "Interactive elements that trigger actions or reveal content",
27
+ "components": [
28
+ { "id": "button", "tagName": "dads-button", "useCase": "Primary action trigger (submit, save, cancel, delete)" },
29
+ { "id": "dialog", "tagName": "dads-dialog", "useCase": "Modal dialog for confirmations, alerts, or focused tasks" },
30
+ { "id": "drawer", "tagName": "dads-drawer", "useCase": "Slide-out panel for secondary content or navigation" },
31
+ { "id": "disclosure", "tagName": "dads-disclosure", "useCase": "Expandable content section (show/hide)" },
32
+ { "id": "accordion-details", "tagName": "dads-accordion-details", "useCase": "Accordion container for collapsible FAQ or grouped content" },
33
+ { "id": "accordion-item-details", "tagName": "dads-accordion-item-details", "useCase": "Individual accordion item within an accordion group" }
34
+ ]
35
+ },
36
+ {
37
+ "key": "Navigation",
38
+ "label": "ナビゲーション",
39
+ "description": "Page navigation, breadcrumbs, tabs, and menu components",
40
+ "components": [
41
+ { "id": "breadcrumb", "tagName": "dads-breadcrumb", "useCase": "Hierarchical page location indicator" },
42
+ { "id": "page-navigation", "tagName": "dads-page-navigation", "useCase": "Pagination for multi-page content (tables, search results)" },
43
+ { "id": "step-navigation", "tagName": "dads-step-navigation", "useCase": "Step-by-step wizard progress indicator" },
44
+ { "id": "menu-list", "tagName": "dads-menu-list", "useCase": "Vertical navigation menu list" },
45
+ { "id": "tab", "tagName": "dads-tab", "useCase": "Tab interface for switching between related content panels" },
46
+ { "id": "global-menu", "tagName": "dads-global-menu", "useCase": "Site-wide header navigation menu" },
47
+ { "id": "language-selector", "tagName": "dads-language-selector", "useCase": "Language/locale switcher" },
48
+ { "id": "hamburger-menu-button", "tagName": "dads-hamburger-menu-button", "useCase": "Mobile menu toggle button" },
49
+ { "id": "utility-link", "tagName": "dads-utility-link", "useCase": "Utility navigation link (login, settings, help)" },
50
+ { "id": "mobile-menu", "tagName": "dads-mobile-menu", "useCase": "Mobile-optimized navigation menu" }
51
+ ]
52
+ },
53
+ {
54
+ "key": "Content",
55
+ "label": "コンテンツ表示",
56
+ "description": "Text, list, table, and structured content display",
57
+ "components": [
58
+ { "id": "card", "tagName": "dads-card", "useCase": "Contained content block (article preview, info card)" },
59
+ { "id": "heading", "tagName": "dads-heading", "useCase": "Section heading with proper hierarchy (h1-h6)" },
60
+ { "id": "text", "tagName": "dads-text", "useCase": "Styled text block with typography tokens" },
61
+ { "id": "blockquote", "tagName": "dads-blockquote", "useCase": "Quoted text or citation block" },
62
+ { "id": "code-block", "tagName": "dads-code-block", "useCase": "Code snippet display with syntax styling" },
63
+ { "id": "divider", "tagName": "dads-divider", "useCase": "Visual separator between content sections" },
64
+ { "id": "list", "tagName": "dads-list", "useCase": "Ordered or unordered list" },
65
+ { "id": "description-list", "tagName": "dads-description-list", "useCase": "Key-value pair list (terms and definitions)" },
66
+ { "id": "resource-list", "tagName": "dads-resource-list", "useCase": "List of downloadable resources or links" },
67
+ { "id": "table", "tagName": "dads-table", "useCase": "Data table with sortable columns" },
68
+ { "id": "table-control", "tagName": "dads-table-control", "useCase": "Table toolbar with filters and actions" }
69
+ ]
70
+ },
71
+ {
72
+ "key": "Display",
73
+ "label": "表示・フィードバック",
74
+ "description": "Visual indicators, status displays, and feedback elements",
75
+ "components": [
76
+ { "id": "avatar", "tagName": "dads-avatar", "useCase": "User profile image or initials" },
77
+ { "id": "icon", "tagName": "dads-icon", "useCase": "SVG icon display" },
78
+ { "id": "chip-label", "tagName": "dads-chip-label", "useCase": "Label chip for categories or tags" },
79
+ { "id": "chip-tag", "tagName": "dads-chip-tag", "useCase": "Interactive tag chip (filterable, removable)" },
80
+ { "id": "notification-banner", "tagName": "dads-notification-banner", "useCase": "Page-level notification or info banner" },
81
+ { "id": "emergency-banner", "tagName": "dads-emergency-banner", "useCase": "Critical alert banner (system-wide)" },
82
+ { "id": "carousel", "tagName": "dads-carousel", "useCase": "Image or content carousel/slider" },
83
+ { "id": "device-mock", "tagName": "dads-device-mock", "useCase": "Device frame mockup for previews" },
84
+ { "id": "progress-indicator", "tagName": "dads-progress-indicator", "useCase": "Progress display (determinate or indeterminate)" },
85
+ { "id": "spinner", "tagName": "dads-spinner", "useCase": "Loading spinner for async operations" },
86
+ { "id": "progress-bar", "tagName": "dads-progress-bar", "useCase": "Linear progress bar" },
87
+ { "id": "loading-icon", "tagName": "dads-loading-icon", "useCase": "Inline loading indicator" }
88
+ ]
89
+ },
90
+ {
91
+ "key": "Layout",
92
+ "label": "レイアウト",
93
+ "description": "Page layout containers and structural components",
94
+ "components": [
95
+ { "id": "layout-shell", "tagName": "dads-layout-shell", "useCase": "Page-level layout container (website, app-shell, master-detail)" },
96
+ { "id": "layout-sidebar", "tagName": "dads-layout-sidebar", "useCase": "Sidebar navigation panel for app layouts" },
97
+ { "id": "layout-aside", "tagName": "dads-layout-aside", "useCase": "Aside panel for detail/supplementary content" },
98
+ { "id": "header-container", "tagName": "dads-header-container", "useCase": "Header area container with slots" }
99
+ ]
100
+ }
101
+ ]
102
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.2.0",
3
- "extractedAt": "2026-03-02T05:22:54.308Z",
3
+ "extractedAt": "2026-03-03T05:48:06.856Z",
4
4
  "themes": {
5
5
  "default": "light",
6
6
  "available": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.1.0",
3
- "indexedAt": "2026-03-02T05:22:54.736Z",
3
+ "indexedAt": "2026-03-03T05:48:07.276Z",
4
4
  "documents": [
5
5
  {
6
6
  "id": ".claude/skills/css-writing-rules/references/core-principles.md",
@@ -6,121 +6,240 @@
6
6
  "id": "search-form",
7
7
  "title": "検索フォーム(最小)",
8
8
  "description": "見出し + 検索フォーム(検索語 + ボタン)",
9
- "requires": ["heading", "search-box", "button"],
9
+ "requires": [
10
+ "heading",
11
+ "search-box",
12
+ "button"
13
+ ],
10
14
  "stability": "stable",
11
15
  "contractVersion": "1.0",
12
- "entryHints": ["boot", "@wcf", "index"],
13
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">検索</dads-heading>\n <form id=\"search-form\">\n <dads-search-box aria-label=\"検索\"></dads-search-box>\n <dads-button type=\"submit\">検索</dads-button>\n </form>\n</main>\n"
16
+ "entryHints": [
17
+ "boot",
18
+ "@wcf",
19
+ "index"
20
+ ],
21
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">検索</dads-heading>\n <form id=\"search-form\">\n <dads-search-box aria-label=\"検索\"></dads-search-box>\n <dads-button type=\"submit\">検索</dads-button>\n </form>\n</main>\n",
22
+ "behavior": "document.querySelector(\"#search-form\").addEventListener(\"submit\", (e) => {\n e.preventDefault();\n const query = e.target.querySelector(\"dads-search-box\").value;\n console.log(\"Search:\", query);\n});"
14
23
  },
15
24
  "search-results": {
16
25
  "id": "search-results",
17
26
  "title": "検索結果一覧",
18
27
  "description": "見出し + 検索フォーム + 結果カード + ページネーション",
19
- "requires": ["heading", "search-box", "card", "page-navigation"],
28
+ "requires": [
29
+ "heading",
30
+ "search-box",
31
+ "card",
32
+ "page-navigation"
33
+ ],
20
34
  "stability": "stable",
21
35
  "contractVersion": "1.0",
22
- "entryHints": ["boot", "@wcf", "index"],
23
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">検索</dads-heading>\n <form id=\"search-form\">\n <dads-search-box aria-label=\"検索\"></dads-search-box>\n </form>\n <h2>結果</h2>\n <ul>\n <li><dads-card>ダミー結果 1</dads-card></li>\n <li><dads-card>ダミー結果 2</dads-card></li>\n <li><dads-card>ダミー結果 3</dads-card></li>\n </ul>\n <dads-page-navigation current=\"1\" total=\"1\"></dads-page-navigation>\n</main>\n"
36
+ "entryHints": [
37
+ "boot",
38
+ "@wcf",
39
+ "index"
40
+ ],
41
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">検索</dads-heading>\n <form id=\"search-form\">\n <dads-search-box aria-label=\"検索\"></dads-search-box>\n </form>\n <h2>結果</h2>\n <ul>\n <li><dads-card>ダミー結果 1</dads-card></li>\n <li><dads-card>ダミー結果 2</dads-card></li>\n <li><dads-card>ダミー結果 3</dads-card></li>\n </ul>\n <dads-page-navigation current=\"1\" total=\"1\"></dads-page-navigation>\n</main>\n",
42
+ "behavior": "document.querySelector(\"#search-form\").addEventListener(\"submit\", (e) => {\n e.preventDefault();\n const query = e.target.querySelector(\"dads-search-box\").value;\n // Fetch results and update the list\n console.log(\"Search:\", query);\n});"
24
43
  },
25
44
  "table-with-pagination": {
26
45
  "id": "table-with-pagination",
27
46
  "title": "テーブル + ページネーション",
28
47
  "description": "テーブル一覧とページネーションの基本構成",
29
- "requires": ["heading", "table", "page-navigation"],
48
+ "requires": [
49
+ "heading",
50
+ "table",
51
+ "page-navigation"
52
+ ],
30
53
  "stability": "stable",
31
54
  "contractVersion": "1.0",
32
- "entryHints": ["boot", "@wcf", "index"],
33
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">一覧</dads-heading>\n <dads-table>\n <table>\n <thead>\n <tr><th>項目</th><th>値</th></tr>\n </thead>\n <tbody>\n <tr><td>サンプル</td><td>1</td></tr>\n </tbody>\n </table>\n </dads-table>\n <dads-page-navigation current=\"1\" total=\"3\"></dads-page-navigation>\n</main>\n"
55
+ "entryHints": [
56
+ "boot",
57
+ "@wcf",
58
+ "index"
59
+ ],
60
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">一覧</dads-heading>\n <dads-table>\n <table>\n <thead>\n <tr><th>項目</th><th>値</th></tr>\n </thead>\n <tbody>\n <tr><td>サンプル</td><td>1</td></tr>\n </tbody>\n </table>\n </dads-table>\n <dads-page-navigation current=\"1\" total=\"3\"></dads-page-navigation>\n</main>\n",
61
+ "behavior": "document.querySelector(\"dads-page-navigation\").addEventListener(\"page-change\", (e) => {\n console.log(\"Page:\", e.detail.page);\n // Fetch and render table rows for the new page\n});"
34
62
  },
35
63
  "card-grid": {
36
64
  "id": "card-grid",
37
65
  "title": "カードグリッド",
38
66
  "description": "カードで一覧表示する基本レイアウト",
39
- "requires": ["heading", "card", "button"],
67
+ "requires": [
68
+ "heading",
69
+ "card",
70
+ "button"
71
+ ],
40
72
  "stability": "stable",
41
73
  "contractVersion": "1.0",
42
- "entryHints": ["boot", "@wcf", "index"],
43
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">お知らせ</dads-heading>\n <section>\n <dads-card>\n <h2>カード1</h2>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n <dads-card>\n <h2>カード2</h2>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n </section>\n</main>\n"
74
+ "entryHints": [
75
+ "boot",
76
+ "@wcf",
77
+ "index"
78
+ ],
79
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">お知らせ</dads-heading>\n <section>\n <dads-card>\n <h2>カード1</h2>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n <dads-card>\n <h2>カード2</h2>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n </section>\n</main>\n",
80
+ "behavior": "document.querySelectorAll(\"dads-button\").forEach((btn) => {\n btn.addEventListener(\"click\", () => {\n console.log(\"Card detail clicked\");\n });\n});"
44
81
  },
45
82
  "layout-website-hero-section-footer": {
46
83
  "id": "layout-website-hero-section-footer",
47
84
  "title": "レイアウト(Website: Hero + Section + Footer)",
48
85
  "description": "コンテンツ主導の1カラムサイト向けレイアウト。",
49
- "requires": ["layout-shell", "heading", "card", "button"],
86
+ "requires": [
87
+ "layout-shell",
88
+ "heading",
89
+ "card",
90
+ "button"
91
+ ],
50
92
  "stability": "stable",
51
93
  "contractVersion": "1.0",
52
- "entryHints": ["boot", "@wcf", "index"],
53
- "html": "<dads-layout-shell data-dads-typeset pattern=\"website\" mode=\"auto\">\n <header slot=\"header\">\n <dads-heading level=\"1\">くらしの手続きポータル</dads-heading>\n <p>必要な手続きを1つの画面で確認できます。</p>\n </header>\n <section>\n <dads-card>\n <dads-heading level=\"2\">はじめての方へ</dads-heading>\n <p>制度の概要と申請までの流れを案内します。</p>\n <dads-button variant=\"outlined\">詳しく見る</dads-button>\n </dads-card>\n </section>\n <footer slot=\"footer\">© Digital Service</footer>\n</dads-layout-shell>\n"
94
+ "entryHints": [
95
+ "boot",
96
+ "@wcf",
97
+ "index"
98
+ ],
99
+ "html": "<dads-layout-shell data-dads-typeset pattern=\"website\" mode=\"auto\">\n <header slot=\"header\">\n <dads-heading level=\"1\">くらしの手続きポータル</dads-heading>\n <p>必要な手続きを1つの画面で確認できます。</p>\n </header>\n <section>\n <dads-card>\n <dads-heading level=\"2\">はじめての方へ</dads-heading>\n <p>制度の概要と申請までの流れを案内します。</p>\n <dads-button variant=\"outlined\">詳しく見る</dads-button>\n </dads-card>\n </section>\n <footer slot=\"footer\">© Digital Service</footer>\n</dads-layout-shell>\n",
100
+ "behavior": "// Responsive: layout-shell handles mode automatically via mode=\"auto\""
54
101
  },
55
102
  "layout-app-shell": {
56
103
  "id": "layout-app-shell",
57
104
  "title": "レイアウト(App/SaaS: Header + Sidebar + Main)",
58
105
  "description": "業務アプリ向けの標準App Shellレイアウト。",
59
- "requires": ["layout-shell", "layout-sidebar", "heading", "card"],
106
+ "requires": [
107
+ "layout-shell",
108
+ "layout-sidebar",
109
+ "heading",
110
+ "card"
111
+ ],
60
112
  "stability": "stable",
61
113
  "contractVersion": "1.0",
62
- "entryHints": ["boot", "@wcf", "index"],
63
- "html": "<dads-layout-shell data-dads-typeset pattern=\"app-shell\" mode=\"auto\">\n <div slot=\"header\">\n <dads-heading level=\"2\">業務ダッシュボード</dads-heading>\n </div>\n <dads-layout-sidebar slot=\"sidebar\">\n <ul>\n <li>案件一覧</li>\n <li>承認待ち</li>\n <li>設定</li>\n </ul>\n </dads-layout-sidebar>\n <section>\n <dads-card>\n <dads-heading level=\"3\">進捗サマリー</dads-heading>\n <p>主要KPIを表示します。</p>\n </dads-card>\n </section>\n</dads-layout-shell>\n"
114
+ "entryHints": [
115
+ "boot",
116
+ "@wcf",
117
+ "index"
118
+ ],
119
+ "html": "<dads-layout-shell data-dads-typeset pattern=\"app-shell\" mode=\"auto\">\n <div slot=\"header\">\n <dads-heading level=\"2\">業務ダッシュボード</dads-heading>\n </div>\n <dads-layout-sidebar slot=\"sidebar\">\n <ul>\n <li>案件一覧</li>\n <li>承認待ち</li>\n <li>設定</li>\n </ul>\n </dads-layout-sidebar>\n <section>\n <dads-card>\n <dads-heading level=\"3\">進捗サマリー</dads-heading>\n <p>主要KPIを表示します。</p>\n </dads-card>\n </section>\n</dads-layout-shell>\n",
120
+ "behavior": "// layout-shell + layout-sidebar handle responsive behavior via mode=\"auto\""
64
121
  },
65
122
  "layout-master-detail": {
66
123
  "id": "layout-master-detail",
67
124
  "title": "レイアウト(Master-Detail: Main + Aside)",
68
125
  "description": "一覧 + 詳細を同時表示する2カラムレイアウト。",
69
- "requires": ["layout-shell", "layout-aside", "heading", "table"],
126
+ "requires": [
127
+ "layout-shell",
128
+ "layout-aside",
129
+ "heading",
130
+ "table"
131
+ ],
70
132
  "stability": "stable",
71
133
  "contractVersion": "1.0",
72
- "entryHints": ["boot", "@wcf", "index"],
73
- "html": "<dads-layout-shell data-dads-typeset pattern=\"master-detail\" mode=\"auto\">\n <section>\n <dads-heading level=\"2\">申請一覧</dads-heading>\n <dads-table>\n <table>\n <thead>\n <tr><th scope=\"col\">申請ID</th><th scope=\"col\">状態</th></tr>\n </thead>\n <tbody>\n <tr><td>A-1001</td><td>審査中</td></tr>\n <tr><td>A-1002</td><td>差戻し</td></tr>\n </tbody>\n </table>\n </dads-table>\n </section>\n <dads-layout-aside slot=\"aside\">\n <dads-heading level=\"3\">詳細情報</dads-heading>\n <p>選択中レコードの詳細を表示します。</p>\n </dads-layout-aside>\n</dads-layout-shell>\n"
134
+ "entryHints": [
135
+ "boot",
136
+ "@wcf",
137
+ "index"
138
+ ],
139
+ "html": "<dads-layout-shell data-dads-typeset pattern=\"master-detail\" mode=\"auto\">\n <section>\n <dads-heading level=\"2\">申請一覧</dads-heading>\n <dads-table>\n <table>\n <thead>\n <tr><th scope=\"col\">申請ID</th><th scope=\"col\">状態</th></tr>\n </thead>\n <tbody>\n <tr><td>A-1001</td><td>審査中</td></tr>\n <tr><td>A-1002</td><td>差戻し</td></tr>\n </tbody>\n </table>\n </dads-table>\n </section>\n <dads-layout-aside slot=\"aside\">\n <dads-heading level=\"3\">詳細情報</dads-heading>\n <p>選択中レコードの詳細を表示します。</p>\n </dads-layout-aside>\n</dads-layout-shell>\n",
140
+ "behavior": "// Master row click updates aside detail\ndocument.querySelector(\"dads-table\").addEventListener(\"row-select\", (e) => {\n const aside = document.querySelector(\"dads-layout-aside\");\n aside.textContent = \"Selected: \" + e.detail.id;\n});"
74
141
  },
75
142
  "application-form-single-validation": {
76
143
  "id": "application-form-single-validation",
77
144
  "title": "申請フォーム(1ページ・検証エラー)",
78
145
  "description": "必須項目を含む1ページ申請フォームとバリデーションエラー表示",
79
- "requires": ["heading", "fieldset", "input-text", "select", "textarea", "button"],
146
+ "requires": [
147
+ "heading",
148
+ "fieldset",
149
+ "input-text",
150
+ "select",
151
+ "textarea",
152
+ "button"
153
+ ],
80
154
  "stability": "experimental",
81
155
  "contractVersion": "1.0",
82
- "entryHints": ["boot", "@wcf", "index"],
83
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">申請フォーム</dads-heading>\n <form id=\"application-form-single\">\n <dads-fieldset>\n <legend>申請情報</legend>\n <dads-input-text name=\"name\" required error error-text=\"氏名は必須です\"></dads-input-text>\n <dads-select name=\"type\" required></dads-select>\n <dads-textarea name=\"reason\" required></dads-textarea>\n </dads-fieldset>\n <dads-button type=\"submit\">送信</dads-button>\n </form>\n</main>\n"
156
+ "entryHints": [
157
+ "boot",
158
+ "@wcf",
159
+ "index"
160
+ ],
161
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">申請フォーム</dads-heading>\n <form id=\"application-form-single\">\n <dads-fieldset>\n <legend>申請情報</legend>\n <dads-input-text label=\"氏名\" name=\"name\" required error error-text=\"氏名は必須です\"></dads-input-text>\n <dads-select label=\"種別\" name=\"type\" required></dads-select>\n <dads-textarea label=\"理由\" name=\"reason\" required></dads-textarea>\n </dads-fieldset>\n <dads-button type=\"submit\">送信</dads-button>\n </form>\n</main>\n",
162
+ "behavior": "document.querySelector(\"#application-form-single\").addEventListener(\"submit\", (e) => {\n e.preventDefault();\n const form = e.target;\n let valid = true;\n form.querySelectorAll(\"[required]\").forEach((el) => {\n if (!el.value) { el.setAttribute(\"error\", \"\"); valid = false; }\n else { el.removeAttribute(\"error\"); }\n });\n if (valid) console.log(\"Submit OK\");\n});"
84
163
  },
85
164
  "application-form-step-validation": {
86
165
  "id": "application-form-step-validation",
87
166
  "title": "申請フォーム(ステップ・検証エラー)",
88
167
  "description": "ステップナビゲーション付き申請フォームと検証エラー表示",
89
- "requires": ["heading", "step-navigation", "fieldset", "input-text", "button"],
168
+ "requires": [
169
+ "heading",
170
+ "step-navigation",
171
+ "fieldset",
172
+ "input-text",
173
+ "button"
174
+ ],
90
175
  "stability": "experimental",
91
176
  "contractVersion": "1.0",
92
- "entryHints": ["boot", "@wcf", "index"],
93
- "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">申請フォーム(ステップ)</dads-heading>\n <dads-step-navigation></dads-step-navigation>\n <form id=\"application-form-step\">\n <dads-fieldset>\n <legend>ステップ1: 申請者情報</legend>\n <dads-input-text name=\"name\" required error error-text=\"氏名は必須です\"></dads-input-text>\n </dads-fieldset>\n <dads-button type=\"submit\">次へ</dads-button>\n </form>\n</main>\n"
177
+ "entryHints": [
178
+ "boot",
179
+ "@wcf",
180
+ "index"
181
+ ],
182
+ "html": "<main data-dads-typeset>\n <dads-heading level=\"1\">申請フォーム(ステップ)</dads-heading>\n <dads-step-navigation></dads-step-navigation>\n <form id=\"application-form-step\">\n <dads-fieldset>\n <legend>ステップ1: 申請者情報</legend>\n <dads-input-text label=\"氏名\" name=\"name\" required error error-text=\"氏名は必須です\"></dads-input-text>\n </dads-fieldset>\n <dads-button type=\"submit\">次へ</dads-button>\n </form>\n</main>\n",
183
+ "behavior": "let step = 0;\ndocument.querySelector(\"#application-form-step\").addEventListener(\"submit\", (e) => {\n e.preventDefault();\n // Validate current step, advance step++\n console.log(\"Step\", step, \"validated\");\n});"
94
184
  },
95
185
  "mockup-website": {
96
186
  "id": "mockup-website",
97
187
  "title": "モックアップ(Website)",
98
188
  "description": "Webサイト向けのヒーロー + セクション構成を device-mock で確認するモックアップ。",
99
- "requires": ["device-mock", "layout-shell", "heading", "card", "button"],
189
+ "requires": [
190
+ "device-mock",
191
+ "layout-shell",
192
+ "heading",
193
+ "card",
194
+ "button"
195
+ ],
100
196
  "stability": "stable",
101
197
  "contractVersion": "1.0",
102
- "entryHints": ["boot"],
103
- "html": "<section data-dads-typeset>\n <dads-device-mock device=\"desktop\">\n <dads-layout-shell pattern=\"website\" mode=\"desktop\">\n <header slot=\"header\">\n <dads-heading level=\"1\">公共サービス ポータル</dads-heading>\n <p>申請・確認・問い合わせを1つの画面で行えます。</p>\n </header>\n <section>\n <dads-card>\n <dads-heading level=\"2\">新着のお知らせ</dads-heading>\n <p>重要なお知らせを確認してください。</p>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n </section>\n <footer slot=\"footer\">© Digital Service</footer>\n </dads-layout-shell>\n </dads-device-mock>\n</section>\n"
198
+ "entryHints": [
199
+ "boot"
200
+ ],
201
+ "html": "<section data-dads-typeset>\n <dads-device-mock device=\"desktop\">\n <dads-layout-shell pattern=\"website\" mode=\"desktop\">\n <header slot=\"header\">\n <dads-heading level=\"1\">公共サービス ポータル</dads-heading>\n <p>申請・確認・問い合わせを1つの画面で行えます。</p>\n </header>\n <section>\n <dads-card>\n <dads-heading level=\"2\">新着のお知らせ</dads-heading>\n <p>重要なお知らせを確認してください。</p>\n <dads-button variant=\"outlined\">詳細</dads-button>\n </dads-card>\n </section>\n <footer slot=\"footer\">© Digital Service</footer>\n </dads-layout-shell>\n </dads-device-mock>\n</section>\n",
202
+ "behavior": "// Mockups are visual-only; no runtime behavior needed."
104
203
  },
105
204
  "mockup-app-shell": {
106
205
  "id": "mockup-app-shell",
107
206
  "title": "モックアップ(App Shell)",
108
207
  "description": "業務画面向けのヘッダー + サイドバー + メイン領域を device-mock で再現するモックアップ。",
109
- "requires": ["device-mock", "layout-shell", "layout-sidebar", "heading", "card"],
208
+ "requires": [
209
+ "device-mock",
210
+ "layout-shell",
211
+ "layout-sidebar",
212
+ "heading",
213
+ "card"
214
+ ],
110
215
  "stability": "stable",
111
216
  "contractVersion": "1.0",
112
- "entryHints": ["boot"],
113
- "html": "<section data-dads-typeset>\n <dads-device-mock device=\"desktop\">\n <dads-layout-shell pattern=\"app-shell\" mode=\"desktop\">\n <div slot=\"header\">\n <dads-heading level=\"2\">申請管理ダッシュボード</dads-heading>\n </div>\n <dads-layout-sidebar slot=\"sidebar\">\n <ul>\n <li>一覧</li>\n <li>承認待ち</li>\n <li>設定</li>\n </ul>\n </dads-layout-sidebar>\n <section>\n <dads-card>\n <dads-heading level=\"3\">本日の処理件数</dads-heading>\n <p>処理済み 128 件 / 未処理 24 件</p>\n </dads-card>\n </section>\n </dads-layout-shell>\n </dads-device-mock>\n</section>\n"
217
+ "entryHints": [
218
+ "boot"
219
+ ],
220
+ "html": "<section data-dads-typeset>\n <dads-device-mock device=\"desktop\">\n <dads-layout-shell pattern=\"app-shell\" mode=\"desktop\">\n <div slot=\"header\">\n <dads-heading level=\"2\">申請管理ダッシュボード</dads-heading>\n </div>\n <dads-layout-sidebar slot=\"sidebar\">\n <ul>\n <li>一覧</li>\n <li>承認待ち</li>\n <li>設定</li>\n </ul>\n </dads-layout-sidebar>\n <section>\n <dads-card>\n <dads-heading level=\"3\">本日の処理件数</dads-heading>\n <p>処理済み 128 件 / 未処理 24 件</p>\n </dads-card>\n </section>\n </dads-layout-shell>\n </dads-device-mock>\n</section>\n",
221
+ "behavior": "// Mockups are visual-only; no runtime behavior needed."
114
222
  },
115
223
  "mockup-mobile-form": {
116
224
  "id": "mockup-mobile-form",
117
225
  "title": "モックアップ(Mobile Form)",
118
226
  "description": "モバイル端末上で入力フォームの配置と余白を確認するモックアップ。",
119
- "requires": ["device-mock", "heading", "fieldset", "input-text", "select", "textarea", "button"],
227
+ "requires": [
228
+ "device-mock",
229
+ "heading",
230
+ "fieldset",
231
+ "input-text",
232
+ "select",
233
+ "textarea",
234
+ "button"
235
+ ],
120
236
  "stability": "stable",
121
237
  "contractVersion": "1.0",
122
- "entryHints": ["boot"],
123
- "html": "<section data-dads-typeset>\n <dads-device-mock device=\"mobile\" visible-height=\"560px\">\n <main>\n <dads-heading level=\"2\">申請フォーム</dads-heading>\n <form>\n <dads-fieldset>\n <legend>基本情報</legend>\n <dads-input-text name=\"name\" required></dads-input-text>\n <dads-select name=\"type\" required></dads-select>\n <dads-textarea name=\"detail\" required></dads-textarea>\n </dads-fieldset>\n <dads-button type=\"submit\">確認へ進む</dads-button>\n </form>\n </main>\n </dads-device-mock>\n</section>\n"
238
+ "entryHints": [
239
+ "boot"
240
+ ],
241
+ "html": "<section data-dads-typeset>\n <dads-device-mock device=\"mobile\" visible-height=\"560px\">\n <main>\n <dads-heading level=\"2\">申請フォーム</dads-heading>\n <form>\n <dads-fieldset>\n <legend>基本情報</legend>\n <dads-input-text label=\"氏名\" name=\"name\" required></dads-input-text>\n <dads-select label=\"種別\" name=\"type\" required></dads-select>\n <dads-textarea label=\"詳細\" name=\"detail\" required></dads-textarea>\n </dads-fieldset>\n <dads-button type=\"submit\">確認へ進む</dads-button>\n </form>\n </main>\n </dads-device-mock>\n</section>\n",
242
+ "behavior": "// Mockups are visual-only; no runtime behavior needed."
124
243
  }
125
244
  }
126
245
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoharada/wcf-mcp",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "MCP server for the web-components-factory design system. Provides component discovery, validation, and pattern-based UI composition without cloning the repository.",
5
5
  "type": "module",
6
6
  "bin": {
package/server.mjs CHANGED
@@ -21,6 +21,7 @@ const REPO_FILE_MAP = {
21
21
  'custom-elements.json': 'custom-elements.json',
22
22
  'install-registry.json': 'registry/install-registry.json',
23
23
  'pattern-registry.json': 'registry/pattern-registry.json',
24
+ 'component-selector-guide.json': 'registry/component-selector-guide.json',
24
25
  'design-tokens.json': 'design-tokens.json',
25
26
  'guidelines-index.json': 'guidelines-index.json',
26
27
  'llms-full.txt': 'llms-full.txt',
package/validator.mjs CHANGED
@@ -471,12 +471,14 @@ export function detectTokenMisuseInInlineStyles({
471
471
  * filePath?: string;
472
472
  * text: string;
473
473
  * severity?: string;
474
+ * cemTagNames?: Set<string>;
474
475
  * }} params
475
476
  */
476
477
  export function detectAccessibilityMisuseInMarkup({
477
478
  filePath = '<input>',
478
479
  text,
479
480
  severity = 'warning',
481
+ cemTagNames,
480
482
  }) {
481
483
  const diagnostics = [];
482
484
  const lineStarts = computeLineIndex(text);
@@ -508,7 +510,9 @@ export function detectAccessibilityMisuseInMarkup({
508
510
  });
509
511
  }
510
512
 
511
- const roleAttr = parseAttributes(attrChunk).find(({ name }) => String(name ?? '').toLowerCase() === 'role');
513
+ const parsedAttrs = parseAttributes(attrChunk);
514
+
515
+ const roleAttr = parsedAttrs.find(({ name }) => String(name ?? '').toLowerCase() === 'role');
512
516
  const roleValue = String(roleAttr?.value ?? '').trim().toLowerCase();
513
517
  if (roleAttr && roleValue === 'alert') {
514
518
  const attrName = 'role';
@@ -527,6 +531,35 @@ export function detectAccessibilityMisuseInMarkup({
527
531
  hint: 'Replace role=\"alert\" with non-live text associated to the control.',
528
532
  });
529
533
  }
534
+
535
+ // Empty label / aria-label detection (v0.4.0, DD-26)
536
+ // Only check CEM-registered custom elements to avoid false positives on third-party elements
537
+ const isCemElement = cemTagNames ? cemTagNames.has(tag) : tag.includes('-');
538
+ if (isCemElement) {
539
+ const EMPTY_LABEL_CHECKS = [
540
+ { attr: 'label', code: 'emptyLabel', hint: 'Set label to a descriptive text, e.g. label="氏名".', msg: (t) => `Empty label attribute on <${t}>. Provide a meaningful label for accessibility.` },
541
+ { attr: 'aria-label', code: 'emptyAriaLabel', hint: 'Set aria-label to descriptive text or use a visible <label> element instead.', msg: (t) => `Empty aria-label attribute on <${t}>. Provide a meaningful label for accessibility.` },
542
+ ];
543
+ for (const { name, offset, value } of parsedAttrs) {
544
+ const attrLower = String(name ?? '').toLowerCase();
545
+ if (typeof value !== 'string' || value.trim() !== '') continue;
546
+ const check = EMPTY_LABEL_CHECKS.find((c) => c.attr === attrLower);
547
+ if (!check) continue;
548
+ const startIndex = rawAttrsStart + offset;
549
+ const endIndex = startIndex + name.length;
550
+ const range = makeRange(lineStarts, startIndex, endIndex);
551
+ diagnostics.push({
552
+ file: filePath,
553
+ range,
554
+ severity,
555
+ code: check.code,
556
+ message: check.msg(tag),
557
+ tagName: tag,
558
+ attrName: check.attr,
559
+ hint: check.hint,
560
+ });
561
+ }
562
+ }
530
563
  }
531
564
 
532
565
  return diagnostics;
@@ -643,9 +676,18 @@ const PARENT_CHILD_CONSTRAINTS = new Map([
643
676
  ['dads-menu-list-item', 'dads-menu-list'],
644
677
  ]);
645
678
 
679
+ /**
680
+ * HTML void elements that never have a closing tag.
681
+ */
682
+ const HTML_VOID_ELEMENTS = new Set([
683
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
684
+ 'link', 'meta', 'source', 'track', 'wbr',
685
+ ]);
686
+
646
687
  /**
647
688
  * Detect orphaned child components (child appears without expected parent).
648
- * Uses regex/text scan (DIG-13) lower confidence, severity: warning.
689
+ * Uses a lightweight tag-stack approach: only prefix-matching tags (e.g. dads-*)
690
+ * are tracked on the stack; all other HTML elements are ignored.
649
691
  * @param {{
650
692
  * filePath?: string;
651
693
  * text: string;
@@ -664,7 +706,7 @@ export function detectOrphanedChildComponents({
664
706
  const p = prefix.toLowerCase();
665
707
  const canonicalPrefix = 'dads';
666
708
 
667
- // Build prefix-aware constraint map
709
+ // Build prefix-aware constraint map (child → parent)
668
710
  const constraints = new Map();
669
711
  for (const [child, parent] of PARENT_CHILD_CONSTRAINTS.entries()) {
670
712
  const mappedChild = p !== canonicalPrefix ? child.replace(canonicalPrefix, p) : child;
@@ -672,36 +714,56 @@ export function detectOrphanedChildComponents({
672
714
  constraints.set(mappedChild, mappedParent);
673
715
  }
674
716
 
675
- const textLower = text.toLowerCase();
717
+ const prefixDash = `${p}-`;
718
+ // Stack of currently open prefix-matching tags
719
+ const stack = [];
676
720
 
677
- const tagRe = /<([a-z][a-z0-9-]*)\b([^<>]*?)>/gi;
721
+ // Regex matches opening tags, closing tags, and self-closing tags
722
+ const tagRe = /<\/?([a-z][a-z0-9-]*)\b[^<>]*?\/?>/gi;
678
723
  let m;
679
724
 
680
725
  while ((m = tagRe.exec(text))) {
726
+ const fullMatch = m[0];
681
727
  const tag = String(m[1] ?? '').toLowerCase();
682
- const expectedParent = constraints.get(tag);
683
- if (!expectedParent) continue;
684
-
685
- // Check if the expected parent tag appears before this child in the text
686
- const precedingText = textLower.slice(0, m.index);
687
- const parentOpenPattern = `<${expectedParent}`;
688
- const parentClosePattern = `</${expectedParent}`;
728
+ const isClosing = fullMatch.startsWith('</');
729
+ const isSelfClosing = fullMatch.endsWith('/>');
730
+
731
+ // Only track prefix-matching tags on the stack
732
+ if (!tag.startsWith(prefixDash)) continue;
733
+
734
+ if (isClosing) {
735
+ // Pop the matching opening tag from the stack (search from top)
736
+ for (let i = stack.length - 1; i >= 0; i--) {
737
+ if (stack[i] === tag) {
738
+ stack.splice(i, 1);
739
+ break;
740
+ }
741
+ }
742
+ continue;
743
+ }
689
744
 
690
- const lastParentOpen = precedingText.lastIndexOf(parentOpenPattern);
691
- const lastParentClose = precedingText.lastIndexOf(parentClosePattern);
745
+ // Check if this is a child that needs a parent
746
+ const expectedParent = constraints.get(tag);
747
+ if (expectedParent) {
748
+ const hasParent = stack.includes(expectedParent);
749
+ if (!hasParent) {
750
+ const tagOffset = m.index + 1;
751
+ const range = makeRange(lineStarts, tagOffset, tagOffset + tag.length);
752
+ diagnostics.push({
753
+ file: filePath,
754
+ range,
755
+ severity,
756
+ code: 'orphanedChildComponent',
757
+ message: `<${tag}> should be a child of <${expectedParent}>.`,
758
+ tagName: tag,
759
+ hint: `Wrap <${tag}> inside <${expectedParent}>...</${expectedParent}>.`,
760
+ });
761
+ }
762
+ }
692
763
 
693
- if (lastParentOpen === -1 || lastParentClose > lastParentOpen) {
694
- const tagOffset = m.index + 1;
695
- const range = makeRange(lineStarts, tagOffset, tagOffset + tag.length);
696
- diagnostics.push({
697
- file: filePath,
698
- range,
699
- severity,
700
- code: 'orphanedChildComponent',
701
- message: `<${tag}> should be a child of <${expectedParent}>.`,
702
- tagName: tag,
703
- hint: `Wrap <${tag}> inside <${expectedParent}>...</${expectedParent}>.`,
704
- });
764
+ // Push opening tag to stack (skip void elements and self-closing)
765
+ if (!isSelfClosing && !HTML_VOID_ELEMENTS.has(tag)) {
766
+ stack.push(tag);
705
767
  }
706
768
  }
707
769