@infomind-ux/infoux-mcp 0.1.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.
Files changed (53) hide show
  1. package/README.md +81 -0
  2. package/bin/server.js +331 -0
  3. package/data/contract.md +215 -0
  4. package/data/manifest.json +286 -0
  5. package/data/references/accessibility.md +243 -0
  6. package/data/references/forbidden-patterns.md +462 -0
  7. package/data/references/guide-import.md +93 -0
  8. package/data/references/html-semantics.md +475 -0
  9. package/data/references/krds-components.md +1426 -0
  10. package/data/references/krds-source.md +1125 -0
  11. package/data/references/krds-tokens.md +201 -0
  12. package/data/references/project-profiles.md +99 -0
  13. package/data/references/snippet-template.md +185 -0
  14. package/data/references/tailwind-mapping.md +53 -0
  15. package/data/rules.json +780 -0
  16. package/data/snippets/accordion.md +49 -0
  17. package/data/snippets/alert.md +37 -0
  18. package/data/snippets/badge.md +29 -0
  19. package/data/snippets/boilerplate.md +125 -0
  20. package/data/snippets/breadcrumb.md +26 -0
  21. package/data/snippets/btn.md +63 -0
  22. package/data/snippets/calendar.md +64 -0
  23. package/data/snippets/card.md +50 -0
  24. package/data/snippets/carousel.md +43 -0
  25. package/data/snippets/check-radio.md +55 -0
  26. package/data/snippets/disclosure.md +44 -0
  27. package/data/snippets/file-upload.md +34 -0
  28. package/data/snippets/form.md +68 -0
  29. package/data/snippets/header.md +56 -0
  30. package/data/snippets/list.md +64 -0
  31. package/data/snippets/main-menu.md +49 -0
  32. package/data/snippets/modal.md +54 -0
  33. package/data/snippets/pagination.md +41 -0
  34. package/data/snippets/progress.md +30 -0
  35. package/data/snippets/select.md +34 -0
  36. package/data/snippets/side-panel.md +57 -0
  37. package/data/snippets/spinner.md +24 -0
  38. package/data/snippets/step-indicator.md +38 -0
  39. package/data/snippets/switch.md +32 -0
  40. package/data/snippets/tab.md +52 -0
  41. package/data/snippets/table.md +63 -0
  42. package/data/snippets/tag.md +42 -0
  43. package/data/snippets/toast.md +48 -0
  44. package/data/snippets/tooltip.md +38 -0
  45. package/data/tokens.css +390 -0
  46. package/data/workflows/change-token.md +20 -0
  47. package/data/workflows/create-component.md +71 -0
  48. package/data/workflows/design-form.md +20 -0
  49. package/data/workflows/design-page.md +22 -0
  50. package/data/workflows/design-widget.md +19 -0
  51. package/data/workflows/init-project.md +68 -0
  52. package/data/workflows/review-ui.md +14 -0
  53. package/package.json +34 -0
@@ -0,0 +1,49 @@
1
+ # 아코디언 (Accordion) — KRDS
2
+
3
+ native `<details>`/`<summary>` 활용 — JS 없이 동작.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <div class="accordion">
9
+ <details class="accordion__item">
10
+ <summary class="accordion__summary">자주 묻는 질문 1</summary>
11
+ <div class="accordion__panel">
12
+ <p>답변 1 내용</p>
13
+ </div>
14
+ </details>
15
+ <details class="accordion__item">
16
+ <summary class="accordion__summary">자주 묻는 질문 2</summary>
17
+ <div class="accordion__panel">
18
+ <p>답변 2 내용</p>
19
+ </div>
20
+ </details>
21
+ <details class="accordion__item" open>
22
+ <summary class="accordion__summary">기본 열린 항목</summary>
23
+ <div class="accordion__panel">
24
+ <p><code>open</code> 속성으로 초기 열림 상태</p>
25
+ </div>
26
+ </details>
27
+ </div>
28
+ ```
29
+
30
+ ## 단일 열림 (한 번에 하나만)
31
+
32
+ `<details name="group">`을 같은 `name`으로 묶으면 한 번에 하나만 열림 (모던 브라우저).
33
+
34
+ ```html
35
+ <div class="accordion">
36
+ <details class="accordion__item" name="faq"><summary class="accordion__summary">Q1</summary>...</details>
37
+ <details class="accordion__item" name="faq"><summary class="accordion__summary">Q2</summary>...</details>
38
+ </div>
39
+ ```
40
+
41
+ ## 접근성
42
+
43
+ - native `<details>`/`<summary>` 사용 시 키보드/스크린리더 자동 지원
44
+ - `<summary>`는 자동으로 button role + aria-expanded 처리됨 — 별도 ARIA 불필요
45
+ - 최소 터치 영역 보장: `--touch-target-min` (44px)
46
+
47
+ ## 출처
48
+
49
+ - CSS: `src/styles/6-components/accordion.css`
@@ -0,0 +1,37 @@
1
+ # 알림 (Alert / Critical Alerts) — KRDS
2
+
3
+ 페이지에 고정 노출되는 정보/경고/오류 메시지.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <div class="alert alert--info" role="alert">
9
+ <div class="alert__icon" aria-hidden="true">ℹ</div>
10
+ <div class="alert__body">
11
+ <p class="alert__title">신청 기간 안내</p>
12
+ <p class="alert__message">2026년 5월 1일부터 31일까지 신청 가능합니다.</p>
13
+ </div>
14
+ <button type="button" class="alert__close" aria-label="닫기">×</button>
15
+ </div>
16
+ ```
17
+
18
+ ## Variant
19
+
20
+ | Variant | 클래스 | 용도 |
21
+ |---------|--------|------|
22
+ | Info | `.alert--info` | 일반 정보 |
23
+ | Success | `.alert--success` | 성공 알림 |
24
+ | Warning | `.alert--warning` | 주의 |
25
+ | Danger / Critical | `.alert--danger` 또는 `.alert--critical` | 오류·긴급 |
26
+
27
+ ## 접근성
28
+
29
+ - 일반 알림: `role="alert"` (즉시 안내) 또는 `role="status"` (정중한 안내)
30
+ - 긴급(Critical)은 `role="alert"` + `aria-live="assertive"`
31
+ - 일반 정보성은 `role="status"` + `aria-live="polite"` 권장
32
+ - 아이콘은 장식용 — `aria-hidden="true"` (텍스트가 의미 전달)
33
+ - 닫기 버튼 `aria-label="닫기"` 필수
34
+
35
+ ## 출처
36
+
37
+ - CSS: `src/styles/6-components/alert.css`
@@ -0,0 +1,29 @@
1
+ # 배지 (Badge) — KRDS
2
+
3
+ 작은 알림 표시기 (카운트 / 상태 / 새 항목).
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <!-- 숫자 배지 -->
9
+ <button class="btn btn--text">
10
+ 알림 <span class="badge">3</span>
11
+ </button>
12
+
13
+ <!-- 점만 (dot 변형) -->
14
+ <span class="badge badge--dot" aria-label="새 알림 있음"></span>
15
+ ```
16
+
17
+ ## Variant
18
+
19
+ - `.badge` (기본 — danger 빨강) / `.badge--primary` / `.badge--info` / `.badge--success` / `.badge--warning` / `.badge--gray`
20
+ - `.badge--dot` — 숫자 없는 단순 점 (8×8)
21
+
22
+ ## 접근성
23
+
24
+ - 숫자 배지: 텍스트로 의미 전달됨 (별도 ARIA 불필요)
25
+ - Dot 배지: 시각만 — `aria-label="새 알림 있음"` 필수
26
+
27
+ ## 출처
28
+
29
+ - CSS: `src/styles/6-components/badge.css`
@@ -0,0 +1,125 @@
1
+ # HTML 보일러플레이트 (Boilerplate)
2
+
3
+ ## 기본 마크업
4
+
5
+ 기본 마크업은 일반사이트, 공공서비스, 공공기관, CMS·관리자, 커머스·예약 모두에 적용 가능한 공통 골격이다. 공식 배너, 정부 상징, 운영기관 식별자, 공공 푸터 필수 링크는 사이트 유형 판정에서 적용 대상이 확인된 경우에만 추가한다.
6
+
7
+ ```html
8
+ <!DOCTYPE html>
9
+ <html lang="ko">
10
+ <head>
11
+ <meta charset="UTF-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
+ <title>페이지 제목</title>
14
+ <link rel="stylesheet" href="../../dist/css/style.css">
15
+ </head>
16
+ <body>
17
+ <a href="#main" class="skip-to-content">본문 바로가기</a>
18
+
19
+ <header id="header" class="site-header">
20
+ <div class="container">
21
+ <!-- 브랜드, GNB, 유틸리티 -->
22
+ </div>
23
+ </header>
24
+
25
+ <main id="main">
26
+ <section class="section section--content" aria-labelledby="section-title">
27
+ <div class="container">
28
+ <h1 id="section-title">페이지 제목</h1>
29
+ <!-- 페이지 콘텐츠 -->
30
+ </div>
31
+ </section>
32
+ </main>
33
+
34
+ <footer id="footer" class="site-footer">
35
+ <div class="container">
36
+ <!-- 로고, 연락처, 저작권, 주요 링크 -->
37
+ </div>
38
+ </footer>
39
+ </body>
40
+ </html>
41
+ ```
42
+
43
+ ## 필수 요소 체크리스트
44
+
45
+ | 요소 | 코드 | 용도 |
46
+ |------|------|------|
47
+ | 문서 언어 | `lang="ko"` | 스크린리더 언어 설정 |
48
+ | 뷰포트 | `<meta name="viewport" content="width=device-width, initial-scale=1.0">` | 반응형 대응 |
49
+ | 본문 바로가기 | `<a href="#main" class="skip-to-content">본문 바로가기</a>` | 키보드/스크린리더 사용자 편의 |
50
+ | Header 랜드마크 | `<header id="header">` | 페이지 헤더 영역 |
51
+ | Main 랜드마크 | `<main id="main">` | 주요 콘텐츠 영역 (skip-to-content 타겟) |
52
+ | Footer 랜드마크 | `<footer id="footer">` | 페이지 푸터 영역 |
53
+ | 콘텐츠 래퍼 | `.container` | 최대 너비 제한 + 중앙 정렬 |
54
+ | Section 이름 | `aria-labelledby` 또는 heading | 섹션의 접근 가능한 이름 |
55
+
56
+ ## Page Shell 계약
57
+
58
+ 에이전트가 페이지 HTML을 새로 만들 때는 아래 순서로 구조를 잡는다.
59
+
60
+ 1. 사이트 유형을 먼저 판정한다.
61
+ 2. `body` 첫 요소로 `.skip-to-content`를 둔다.
62
+ 3. 큰 랜드마크는 `header#header`, `main#main`, `footer#footer`만 사용한다.
63
+ 4. `main`의 직계 자식은 `section`으로 둔다.
64
+ 5. 각 `section`은 `.container`를 직접 포함하고, heading 또는 `aria-labelledby`/`aria-label`로 접근 가능한 이름을 가진다.
65
+ 6. 페이지 전체를 컴포넌트화하지 않고 `main` 내부 section 단위로 분리한다.
66
+
67
+ ### Section archetype
68
+
69
+ | Archetype | 클래스 | 용도 |
70
+ |-----------|--------|------|
71
+ | 도입 | `.section--intro` | 브랜드, 대표 메시지, 핵심 CTA |
72
+ | 본문 | `.section--content` | 일반 콘텐츠, 소개, 상세 설명 |
73
+ | 목록 | `.section--list` | 카드, 뉴스, 게시물, 링크 목록 |
74
+ | 폼 | `.section--form` | 신청, 문의, 검색 입력 |
75
+ | 데이터 | `.section--data` | 표, 통계, 현황 |
76
+ | 검색 | `.section--search` | 검색/필터 영역 |
77
+ | 절차 | `.section--process` | 단계, 이용 방법, 신청 흐름 |
78
+ | 안내 | `.section--notice` | 공지, 알림, 유의사항 |
79
+
80
+ ## 프로젝트 유형별 추가 요소
81
+
82
+ | 유형 | 추가 검토 요소 |
83
+ |------|----------------|
84
+ | 일반사이트 | 브랜드 로고, 주요 링크, 연락처, 개인정보처리방침 등 자체 운영 정보 |
85
+ | 공공서비스 | 민원/신청/조회/정책/참여 흐름, 서비스 안내, 로그인/인증, 공공 푸터 필수 링크 검토 |
86
+ | 공공기관 | 기관 CI/BI, 기관 소개, 공지, 정보공개, 운영기관 정보. 공식 배너와 정부 상징은 요구 확인 후 |
87
+ | CMS·관리자 | 서비스명, 사용자 메뉴, 로그아웃, 업무 내비게이션. 정부 아이덴티티 요소 제외 |
88
+ | 커머스·예약 | 상품/예약/결제 흐름, 약관/환불/개인정보 링크, 전환 CTA |
89
+
90
+ ## 레이아웃 크기 기준
91
+
92
+ | 영역 | 모바일 | 태블릿 | PC |
93
+ |------|--------|--------|-----|
94
+ | 헤더 높이 | 최소 56px | 최소 64px | **최소 100px** |
95
+ | 푸터 높이 | 자동 | 자동 | 자동 |
96
+ | 컨테이너 max-width | 100% | 100% | 1200px |
97
+ | 컨테이너 좌우 패딩 | 16px | 24px | 40px |
98
+
99
+ ```css
100
+ .site-header {
101
+ min-height: 5.6rem; // 모바일 56px
102
+
103
+ @media (min-width: 768px) {
104
+ min-height: 6.4rem; // 태블릿 64px
105
+ }
106
+
107
+ @media (min-width: 1280px) {
108
+ min-height: 10rem; // PC 100px
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## 접근성 주의사항
114
+
115
+ - `skip-to-content` 링크: `<body>` 바로 뒤 첫 번째 요소로 배치. 평소 화면에서 숨겨지고 포커스 시 표시
116
+ - `header/main/footer`는 암묵적 랜드마크가 있으므로 기본적으로 role을 중복 작성하지 않는다
117
+ - `id="main"`: 본문 바로가기 링크의 타겟
118
+ - 페이지당 `<main>` 태그는 1개만 사용
119
+ - `main` 안의 `section`은 제목을 갖거나 `aria-labelledby`/`aria-label`로 이름을 제공
120
+ - `lang="ko"` 필수: 스크린리더가 한국어로 콘텐츠를 읽도록 설정
121
+ - 페이지 `<title>`은 고유하고 설명적인 텍스트 사용
122
+
123
+ ## 참고 파일
124
+
125
+ 미리보기: `src/playground/boilerplate.html`
@@ -0,0 +1,26 @@
1
+ # 브레드크럼 (Breadcrumb) — KRDS
2
+
3
+ 페이지 경로 표시. 사용자의 현재 위치를 보여주고 상위 페이지로 빠르게 이동할 수 있게 한다.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <nav class="breadcrumb" aria-label="페이지 경로">
9
+ <ol class="breadcrumb__list">
10
+ <li class="breadcrumb__item"><a href="/">홈</a></li>
11
+ <li class="breadcrumb__item"><a href="/services">서비스</a></li>
12
+ <li class="breadcrumb__item" aria-current="page">신청하기</li>
13
+ </ol>
14
+ </nav>
15
+ ```
16
+
17
+ ## 접근성
18
+
19
+ - `<nav aria-label="페이지 경로">` 필수 (스크린리더용 식별자)
20
+ - `<ol>` 사용 — 순서가 의미를 가짐
21
+ - 현재 페이지: `aria-current="page"` + `<a>` 없이 텍스트만 (링크 아님)
22
+ - 구분자(`›`)는 CSS `::before`로 그려서 스크린리더에 노출 안 됨 (불필요한 읽기 방지)
23
+
24
+ ## 출처
25
+
26
+ - CSS: `src/styles/6-components/breadcrumb.css`
@@ -0,0 +1,63 @@
1
+ # 버튼 (Button) — KRDS
2
+
3
+ ## 기본 마크업
4
+
5
+ ```html
6
+ <button type="button" class="btn btn--primary">버튼 텍스트</button>
7
+ ```
8
+
9
+ ## Variant (KRDS 정의 — 4종)
10
+
11
+ | Variant | 클래스 | 용도 |
12
+ |---------|--------|------|
13
+ | Primary | `.btn--primary` | 메인 CTA (저장, 제출, 확인) |
14
+ | Secondary | `.btn--secondary` | 보조 액션 (primary 톤 옅은 채움 + primary border) |
15
+ | Tertiary | `.btn--tertiary` | 약한 액션 (투명 + gray border) |
16
+ | Text | `.btn--text` | 텍스트 링크형 (배경/border 없음) |
17
+
18
+ ## Size (KRDS 정의 — 5종)
19
+
20
+ | Size | 클래스 | 높이 | padding-x | 사용 권장 |
21
+ |------|--------|------|-----------|----------|
22
+ | xsmall | `.btn--xsmall` | 32px | 10px | 데스크탑 dense UI 한정 |
23
+ | small | `.btn--small` | 40px | 12px | 데스크탑 보조 액션 |
24
+ | medium | (기본 — 클래스 없음) | 48px | 16px | **모바일·기본 권장** |
25
+ | large | `.btn--large` | 56px | 20px | 강조 CTA |
26
+ | xlarge | `.btn--xlarge` | 64px | 24px | 히어로/랜딩 CTA |
27
+
28
+ > **모바일 환경에선 medium(48px) 이상 사용.** xsmall(32) · small(40)은 WCAG 권장 터치 영역(44px)보다 작아 모바일 부적합.
29
+
30
+ ## 조합 예시
31
+
32
+ ```html
33
+ <!-- 기본(medium) -->
34
+ <button type="button" class="btn btn--primary">저장</button>
35
+ <button type="button" class="btn btn--secondary">취소</button>
36
+ <button type="button" class="btn btn--tertiary">더보기</button>
37
+ <button type="button" class="btn btn--text">자세히 보기</button>
38
+
39
+ <!-- 사이즈 조합 -->
40
+ <button type="button" class="btn btn--primary btn--small">작게</button>
41
+ <button type="button" class="btn btn--primary btn--large">크게</button>
42
+
43
+ <!-- 비활성 -->
44
+ <button type="button" class="btn btn--primary" disabled>비활성</button>
45
+
46
+ <!-- Block (full width) -->
47
+ <button type="button" class="btn btn--primary btn--block">제출</button>
48
+ ```
49
+
50
+ ## 접근성 (KRDS + WCAG 2.1 AA)
51
+
52
+ - `<button type="button">` 태그 사용 필수. `<a>` 태그를 버튼 용도로 쓰지 않는다
53
+ - 아이콘만 있는 버튼은 `aria-label` 필수: `<button class="btn" aria-label="메뉴 열기">...</button>`
54
+ - 비활성은 `disabled` 속성 (또는 `aria-disabled="true"`)
55
+ - 포커스 outline은 `reset.css`에서 전역 관리 (4px primary 외곽선) — 컴포넌트에서 제거 금지
56
+ - `prefers-reduced-motion` 대응: 모션 감소 설정 시 transition 자동 비활성 (Phase 6에서 추가)
57
+
58
+ ## 출처
59
+
60
+ - KRDS 버튼 명세: https://www.krds.go.kr/html/site/component/component_summary.html
61
+ - 색상: `--color-button-*`, `--color-text-*`
62
+ - 크기/간격/반경: CSS/Tailwind 직접값
63
+ - CSS: `src/styles/6-components/btn.css`
@@ -0,0 +1,64 @@
1
+ # 달력 (Calendar) — KRDS
2
+
3
+ 날짜 선택 그리드. 단독 사용 또는 date input의 팝업으로 사용.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <div class="calendar" role="application" aria-label="날짜 선택">
9
+ <div class="calendar__head">
10
+ <button type="button" class="calendar__nav" aria-label="이전 달">‹</button>
11
+ <h2 class="calendar__title" aria-live="polite">2026년 4월</h2>
12
+ <button type="button" class="calendar__nav" aria-label="다음 달">›</button>
13
+ </div>
14
+
15
+ <table class="calendar__grid" role="grid">
16
+ <thead>
17
+ <tr>
18
+ <th scope="col" abbr="일요일">일</th>
19
+ <th scope="col" abbr="월요일">월</th>
20
+ <th scope="col" abbr="화요일">화</th>
21
+ <th scope="col" abbr="수요일">수</th>
22
+ <th scope="col" abbr="목요일">목</th>
23
+ <th scope="col" abbr="금요일">금</th>
24
+ <th scope="col" abbr="토요일">토</th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <tr role="row">
29
+ <td role="gridcell">
30
+ <button type="button" class="calendar__day calendar__day--other-month" aria-label="2026년 3월 30일">30</button>
31
+ </td>
32
+ <td role="gridcell">
33
+ <button type="button" class="calendar__day" aria-label="2026년 4월 1일">1</button>
34
+ </td>
35
+ <td role="gridcell">
36
+ <button type="button" class="calendar__day calendar__day--today" aria-label="2026년 4월 2일 (오늘)">2</button>
37
+ </td>
38
+ <td role="gridcell">
39
+ <button type="button" class="calendar__day calendar__day--selected" aria-selected="true" aria-label="2026년 4월 3일 (선택됨)">3</button>
40
+ </td>
41
+ </tr>
42
+ </tbody>
43
+ </table>
44
+ </div>
45
+ ```
46
+
47
+ ## 상태 클래스
48
+
49
+ - `.calendar__day--today` — 오늘 (primary 테두리)
50
+ - `.calendar__day--selected` 또는 `aria-selected="true"` — 선택됨 (primary 채움)
51
+ - `.calendar__day--other-month` — 다른 달 날짜 (희미)
52
+ - `:disabled` — 선택 불가
53
+
54
+ ## 접근성
55
+
56
+ - 컨테이너 `role="application"` + `aria-label`
57
+ - `<table role="grid">` 그리드 ARIA
58
+ - 일자 버튼은 전체 날짜 컨텍스트로 `aria-label="YYYY년 M월 D일"` (그래야 스크린리더가 "1"이 아닌 "4월 1일"로 읽음)
59
+ - 선택 상태: `aria-selected="true"`
60
+ - 키보드: 화살표(일 단위), Page Up/Down(월), Home/End(주 시작/끝)
61
+
62
+ ## 출처
63
+
64
+ - CSS: `src/styles/6-components/calendar.css`
@@ -0,0 +1,50 @@
1
+ # 카드 (Card) — KRDS
2
+
3
+ ## 기본 마크업
4
+
5
+ ```html
6
+ <article class="card">
7
+ <header class="card__header">
8
+ <h3 class="card__title">카드 제목</h3>
9
+ </header>
10
+ <div class="card__body">
11
+ <p>카드 본문 내용</p>
12
+ </div>
13
+ <footer class="card__footer">
14
+ <button type="button" class="btn btn--text btn--small">자세히</button>
15
+ </footer>
16
+ </article>
17
+ ```
18
+
19
+ ## 사이즈 (KRDS 정의 — 4종, 반응형)
20
+
21
+ | 사이즈 | 클래스 | Mobile padding | PC padding |
22
+ |--------|--------|---------------|-----------|
23
+ | xsmall | `.card--xsmall` | 12px | 16px |
24
+ | small | `.card--small` | 20px | 24px |
25
+ | medium | (기본) | 24px | 32px |
26
+ | large | `.card--large` | 24px | 40px |
27
+
28
+ ## Variant
29
+
30
+ - `.card` — 기본 (border-light + 흰 배경)
31
+ - `.card--inverse` — 다크 배경 + 흰 텍스트
32
+ - `.card--elevated` — border 없이 그림자만 (`--shadow-2`)
33
+ - `.card--link` 또는 `<a class="card">` — 호버 시 floating
34
+
35
+ ```html
36
+ <a class="card card--link" href="/article/1">
37
+ <div class="card__body">호버 시 그림자 + 살짝 위로 이동</div>
38
+ </a>
39
+ ```
40
+
41
+ ## 접근성
42
+
43
+ - 시맨틱 컨테이너: `<article>` (독립 콘텐츠) / `<section>` (관련 섹션) / `<div>` (장식)
44
+ - 카드 전체가 링크면 `<a class="card">` 또는 카드 내부 `<a>`만 링크 (이중 링크 금지)
45
+ - 카드 내 인터랙티브 요소는 `aria-label`로 컨텍스트 명시 권장
46
+
47
+ ## 출처
48
+
49
+ - 카드 padding/반경은 프로젝트 밀도에 맞는 CSS/Tailwind 직접값 사용
50
+ - CSS: `src/styles/6-components/card.css`
@@ -0,0 +1,43 @@
1
+ # 캐러셀 (Carousel) — KRDS
2
+
3
+ 스크롤 스냅 기반 슬라이드 컨테이너.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <div class="carousel" aria-roledescription="carousel" aria-label="추천 항목">
9
+ <div class="carousel__viewport">
10
+ <ol class="carousel__track">
11
+ <li class="carousel__slide" aria-roledescription="slide" aria-label="1 / 3">
12
+ <img src="/img1.jpg" alt="설명">
13
+ </li>
14
+ <li class="carousel__slide" aria-roledescription="slide" aria-label="2 / 3">
15
+ <img src="/img2.jpg" alt="설명">
16
+ </li>
17
+ <li class="carousel__slide" aria-roledescription="slide" aria-label="3 / 3">
18
+ <img src="/img3.jpg" alt="설명">
19
+ </li>
20
+ </ol>
21
+ </div>
22
+
23
+ <button type="button" class="carousel__nav carousel__nav--prev" aria-label="이전 슬라이드">‹</button>
24
+ <button type="button" class="carousel__nav carousel__nav--next" aria-label="다음 슬라이드">›</button>
25
+
26
+ <div class="carousel__indicators" role="tablist">
27
+ <button type="button" class="carousel__dot" role="tab" aria-selected="true" aria-label="1번 슬라이드"></button>
28
+ <button type="button" class="carousel__dot" role="tab" aria-selected="false" aria-label="2번 슬라이드"></button>
29
+ <button type="button" class="carousel__dot" role="tab" aria-selected="false" aria-label="3번 슬라이드"></button>
30
+ </div>
31
+ </div>
32
+ ```
33
+
34
+ ## 접근성 (WCAG 2.2 + KRDS)
35
+
36
+ - 자동 재생은 **기본 OFF** 권장 — 사용자 통제권 (WCAG 2.2.2)
37
+ - 자동 재생 시: 일시정지 버튼 필수 + `prefers-reduced-motion: reduce` 시 자동 비활성
38
+ - 인디케이터는 키보드 작동 가능
39
+ - 슬라이드별 `aria-label="N / 총수"`로 위치 안내
40
+
41
+ ## 출처
42
+
43
+ - CSS: `src/styles/6-components/carousel.css`
@@ -0,0 +1,55 @@
1
+ # 체크박스 & 라디오 — KRDS Form check
2
+
3
+ ## 기본 마크업
4
+
5
+ ### 체크박스
6
+
7
+ ```html
8
+ <label class="check">
9
+ <input type="checkbox" name="agree" value="true">
10
+ <span class="check__box" aria-hidden="true"></span>
11
+ <span class="check__label">개인정보 수집·이용에 동의합니다</span>
12
+ </label>
13
+ ```
14
+
15
+ ### 라디오
16
+
17
+ ```html
18
+ <fieldset>
19
+ <legend class="form-field__label">결제 수단</legend>
20
+ <label class="radio">
21
+ <input type="radio" name="pay" value="card" checked>
22
+ <span class="radio__box" aria-hidden="true"></span>
23
+ <span class="radio__label">신용카드</span>
24
+ </label>
25
+ <label class="radio">
26
+ <input type="radio" name="pay" value="bank">
27
+ <span class="radio__box" aria-hidden="true"></span>
28
+ <span class="radio__label">계좌이체</span>
29
+ </label>
30
+ </fieldset>
31
+ ```
32
+
33
+ ## 시맨틱 구조
34
+
35
+ - **Root 태그**: `<label class="check">` 또는 `<label class="radio">` (input을 감쌈)
36
+ - **자식**: `<input type="checkbox|radio">` → `<span __box aria-hidden="true">` (시각 박스) → `<span __label>` (텍스트)
37
+ - **그룹**: 라디오는 `<fieldset>` + `<legend>` 필수
38
+ - **필수 ARIA**: 시각 박스에 `aria-hidden="true"` — native input이 정보를 담당
39
+ - 상세: `skill/references/html-semantics.md#check-radio`
40
+
41
+ ## 사양
42
+
43
+ - 박스 크기: 24×24
44
+ - 컨테이너 최소 높이: `--touch-target-min` (44px)
45
+ - native `<input>`은 시각적으로 숨김 (sr-only) — 키보드/스크린리더는 정상 작동
46
+
47
+ ## 접근성
48
+
49
+ - `<label>`로 input + box + 텍스트를 묶어 클릭 영역 전체 확보
50
+ - 라디오 그룹은 `<fieldset><legend>`로 묶기
51
+ - 시각 박스(`__box`)는 `aria-hidden="true"` (스크린리더는 native input만 인식)
52
+
53
+ ## 출처
54
+
55
+ - CSS: `src/styles/6-components/check-radio.css`
@@ -0,0 +1,44 @@
1
+ # 디스클로저 (Disclosure) — KRDS
2
+
3
+ 단일 "더보기/접기" 토글. Accordion(다중 그룹)과 달리 단독 토글에 사용.
4
+
5
+ ## 기본 마크업
6
+
7
+ ```html
8
+ <button type="button" class="disclosure" aria-expanded="false" aria-controls="more-info">
9
+ 자세히 보기
10
+ </button>
11
+ <div id="more-info" class="disclosure__panel" hidden>
12
+ <p>접혀 있던 추가 정보</p>
13
+ </div>
14
+ ```
15
+
16
+ ## 동작 (JS — 별도 구현)
17
+
18
+ ```js
19
+ const trigger = document.querySelector('.disclosure')
20
+ const panel = document.getElementById(trigger.getAttribute('aria-controls'))
21
+ trigger.addEventListener('click', () => {
22
+ const expanded = trigger.getAttribute('aria-expanded') === 'true'
23
+ trigger.setAttribute('aria-expanded', !expanded)
24
+ panel.hidden = expanded
25
+ })
26
+ ```
27
+
28
+ ## Accordion vs Disclosure
29
+
30
+ | | Accordion | Disclosure |
31
+ |---|-----------|-----------|
32
+ | 용도 | FAQ, 그룹화된 다중 항목 | 단일 "더보기" 토글 |
33
+ | 구조 | `<details>` 그룹 | `<button>` + 패널 |
34
+ | 시각 | 아이템 사이 구분선 | 인라인 버튼 |
35
+
36
+ ## 접근성
37
+
38
+ - `aria-expanded` 상태값 필수 (열림/닫힘)
39
+ - `aria-controls`로 패널 id 연결
40
+ - 패널 `hidden` 속성 또는 CSS `display: none` 사용 (레이아웃에서 완전 제거)
41
+
42
+ ## 출처
43
+
44
+ - CSS: `src/styles/6-components/disclosure.css`
@@ -0,0 +1,34 @@
1
+ # 파일 업로드 (File Upload) — KRDS
2
+
3
+ ## 기본 마크업
4
+
5
+ ```html
6
+ <label class="file-upload">
7
+ <input type="file" id="file" accept="image/*">
8
+ <span class="file-upload__trigger">파일 선택</span>
9
+ <span class="file-upload__filename" aria-live="polite">선택된 파일 없음</span>
10
+ </label>
11
+ ```
12
+
13
+ > 파일명 표시는 JS로 갱신 — `input.files[0].name`을 `.file-upload__filename`에 채워 넣는다.
14
+
15
+ ## 다중 선택
16
+
17
+ ```html
18
+ <label class="file-upload">
19
+ <input type="file" id="docs" multiple accept=".pdf,.doc,.docx">
20
+ <span class="file-upload__trigger">문서 선택</span>
21
+ <span class="file-upload__filename">선택된 파일 없음</span>
22
+ </label>
23
+ ```
24
+
25
+ ## 접근성
26
+
27
+ - `<label>`로 input과 트리거를 묶어 키보드 포커스 시 트리거 외곽선 노출
28
+ - `aria-live="polite"`로 파일명 변경을 스크린리더에 안내
29
+ - `accept` 속성으로 허용 파일 타입 명시 (브라우저 필터링 + 사용자 안내)
30
+ - 업로드 진행률은 별도 `<progress>` 또는 토스트로 표시
31
+
32
+ ## 출처
33
+
34
+ - CSS: `src/styles/6-components/file-upload.css`