@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.
- package/README.md +81 -0
- package/bin/server.js +331 -0
- package/data/contract.md +215 -0
- package/data/manifest.json +286 -0
- package/data/references/accessibility.md +243 -0
- package/data/references/forbidden-patterns.md +462 -0
- package/data/references/guide-import.md +93 -0
- package/data/references/html-semantics.md +475 -0
- package/data/references/krds-components.md +1426 -0
- package/data/references/krds-source.md +1125 -0
- package/data/references/krds-tokens.md +201 -0
- package/data/references/project-profiles.md +99 -0
- package/data/references/snippet-template.md +185 -0
- package/data/references/tailwind-mapping.md +53 -0
- package/data/rules.json +780 -0
- package/data/snippets/accordion.md +49 -0
- package/data/snippets/alert.md +37 -0
- package/data/snippets/badge.md +29 -0
- package/data/snippets/boilerplate.md +125 -0
- package/data/snippets/breadcrumb.md +26 -0
- package/data/snippets/btn.md +63 -0
- package/data/snippets/calendar.md +64 -0
- package/data/snippets/card.md +50 -0
- package/data/snippets/carousel.md +43 -0
- package/data/snippets/check-radio.md +55 -0
- package/data/snippets/disclosure.md +44 -0
- package/data/snippets/file-upload.md +34 -0
- package/data/snippets/form.md +68 -0
- package/data/snippets/header.md +56 -0
- package/data/snippets/list.md +64 -0
- package/data/snippets/main-menu.md +49 -0
- package/data/snippets/modal.md +54 -0
- package/data/snippets/pagination.md +41 -0
- package/data/snippets/progress.md +30 -0
- package/data/snippets/select.md +34 -0
- package/data/snippets/side-panel.md +57 -0
- package/data/snippets/spinner.md +24 -0
- package/data/snippets/step-indicator.md +38 -0
- package/data/snippets/switch.md +32 -0
- package/data/snippets/tab.md +52 -0
- package/data/snippets/table.md +63 -0
- package/data/snippets/tag.md +42 -0
- package/data/snippets/toast.md +48 -0
- package/data/snippets/tooltip.md +38 -0
- package/data/tokens.css +390 -0
- package/data/workflows/change-token.md +20 -0
- package/data/workflows/create-component.md +71 -0
- package/data/workflows/design-form.md +20 -0
- package/data/workflows/design-page.md +22 -0
- package/data/workflows/design-widget.md +19 -0
- package/data/workflows/init-project.md +68 -0
- package/data/workflows/review-ui.md +14 -0
- package/package.json +34 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 폼 필드 (Form Field) — KRDS
|
|
2
|
+
|
|
3
|
+
KRDS 입력폼 구성: **레이블 → 보조설명 → 입력박스 → 시스템메시지** (요소 간 8px gap)
|
|
4
|
+
|
|
5
|
+
## 기본 마크업 (텍스트 입력)
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="form-field">
|
|
9
|
+
<label for="name" class="form-field__label">
|
|
10
|
+
이름<span class="form-field__required" aria-label="필수">*</span>
|
|
11
|
+
</label>
|
|
12
|
+
<p class="form-field__hint">사업자등록증에 기재된 대표자명</p>
|
|
13
|
+
<input type="text" id="name" class="input" placeholder="홍길동" required>
|
|
14
|
+
<p class="form-field__message">최대 20자까지 입력 가능합니다</p>
|
|
15
|
+
</div>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 에러 상태
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<div class="form-field">
|
|
22
|
+
<label for="email" class="form-field__label">이메일</label>
|
|
23
|
+
<input type="email" id="email" class="input input--error" aria-invalid="true" aria-describedby="email-error" value="invalid">
|
|
24
|
+
<p id="email-error" class="form-field__message form-field__message--error">올바른 이메일 형식이 아닙니다</p>
|
|
25
|
+
</div>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Textarea
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<div class="form-field">
|
|
32
|
+
<label for="memo" class="form-field__label">메모</label>
|
|
33
|
+
<textarea id="memo" class="textarea" rows="4" placeholder="내용을 입력하세요"></textarea>
|
|
34
|
+
</div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Input 사이즈
|
|
38
|
+
|
|
39
|
+
| Size | 클래스 | 높이 |
|
|
40
|
+
|------|--------|------|
|
|
41
|
+
| small | `.input--small` | 40px |
|
|
42
|
+
| medium | (기본) | 48px |
|
|
43
|
+
| large | `.input--large` | 56px |
|
|
44
|
+
|
|
45
|
+
## Input type
|
|
46
|
+
|
|
47
|
+
`type="text|email|password|number|tel|url|search|date|time|datetime-local"` 모두 동일 스타일 적용.
|
|
48
|
+
|
|
49
|
+
## 상태
|
|
50
|
+
|
|
51
|
+
- 기본 — `border: 1px solid var(--color-input-border)`
|
|
52
|
+
- focus — `border-color: var(--color-input-border-active)` (primary)
|
|
53
|
+
- disabled — 회색 배경 + disabled 텍스트, `cursor: not-allowed`
|
|
54
|
+
- read-only — `:read-only`로 자동 처리
|
|
55
|
+
- error — `.input--error` 또는 `aria-invalid="true"`
|
|
56
|
+
|
|
57
|
+
## 접근성
|
|
58
|
+
|
|
59
|
+
- `<label for="id">` + `<input id="id">` 연결 필수
|
|
60
|
+
- 필수 항목은 `required` 속성 + 시각 표시(`*`)
|
|
61
|
+
- 에러는 `aria-invalid="true"` + `aria-describedby="에러메시지id"`
|
|
62
|
+
- 보조설명은 `aria-describedby`로 연결 권장
|
|
63
|
+
- placeholder만으로 레이블 대체 금지
|
|
64
|
+
|
|
65
|
+
## 출처
|
|
66
|
+
|
|
67
|
+
- KRDS 입력 명세: https://www.krds.go.kr/html/site/component/component_summary.html
|
|
68
|
+
- CSS: `src/styles/6-components/form.css`
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# 사이트 헤더 (Site Header)
|
|
2
|
+
|
|
3
|
+
사이트 유형과 무관하게 사용할 수 있는 공통 헤더 패턴. 브랜드 + 주 메뉴 + 액션 영역을 기본으로 하며, 공식 배너·정부 상징·운영기관 식별자는 공공서비스/공공기관에서 적용 대상이 확인된 경우에만 별도 추가한다.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<header id="header" class="site-header">
|
|
9
|
+
<div class="container site-header__inner">
|
|
10
|
+
<a class="site-header__brand" href="/">
|
|
11
|
+
<img src="/logo.svg" alt="기관명">
|
|
12
|
+
<span class="site-header__brand-name">기관명</span>
|
|
13
|
+
</a>
|
|
14
|
+
|
|
15
|
+
<nav class="site-header__nav" aria-label="주 메뉴">
|
|
16
|
+
<ul class="site-header__menu">
|
|
17
|
+
<li><a href="/about">소개</a></li>
|
|
18
|
+
<li><a href="/services" aria-current="page">서비스</a></li>
|
|
19
|
+
<li><a href="/notice">공지</a></li>
|
|
20
|
+
</ul>
|
|
21
|
+
</nav>
|
|
22
|
+
|
|
23
|
+
<div class="site-header__actions">
|
|
24
|
+
<button type="button" class="btn btn--text btn--small">로그인</button>
|
|
25
|
+
<button type="button" class="site-header__toggle" aria-label="메뉴 열기" aria-expanded="false">☰</button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</header>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 동작
|
|
32
|
+
|
|
33
|
+
- 모바일/태블릿 (< 1280px): 주 메뉴 숨김 + 햄버거 토글 노출
|
|
34
|
+
- PC (≥ 1280px): 주 메뉴 노출 + 햄버거 숨김
|
|
35
|
+
- `position: sticky` 적용 (스크롤 시에도 상단 유지)
|
|
36
|
+
|
|
37
|
+
## 접근성
|
|
38
|
+
|
|
39
|
+
- `<header id="header">` 시맨틱 태그 사용 (페이지당 하나)
|
|
40
|
+
- 주 메뉴는 `<nav aria-label="주 메뉴">` (페이지에 nav가 여러 개면 label 필수)
|
|
41
|
+
- 현재 페이지 메뉴: `aria-current="page"`
|
|
42
|
+
- 모바일 토글: `aria-label="메뉴 열기/닫기"` + `aria-expanded` 상태 토글
|
|
43
|
+
- 로고 `<img>` `alt` 텍스트 필수 (KRDS R-09)
|
|
44
|
+
|
|
45
|
+
## 조건부 공공/정부 요소
|
|
46
|
+
|
|
47
|
+
아래 요소는 모든 사이트의 기본값이 아니다.
|
|
48
|
+
|
|
49
|
+
- 공식 배너: 공공서비스 중 정부 상징 사용이 명시되었거나 과업에서 요구된 경우만 생성
|
|
50
|
+
- 정부 상징 로고: 정부 상징 사용 대상 서비스에서만 생성
|
|
51
|
+
- 운영기관 식별자: 상위 운영기관 표시가 과업에 포함된 경우만 생성
|
|
52
|
+
- 일반사이트, CMS·관리자, 커머스·예약에서는 위 항목을 생성하지 않고 체크리스트에서 N/A 처리
|
|
53
|
+
|
|
54
|
+
## 출처
|
|
55
|
+
|
|
56
|
+
- CSS: `src/styles/6-components/header.css`
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# 목록 (List) — KRDS Text list / Structured list
|
|
2
|
+
|
|
3
|
+
두 가지 변형 — 텍스트 목록과 구조화 목록(정의 목록).
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
### 텍스트 목록 (List — Text)
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<!-- 글머리표 -->
|
|
11
|
+
<ul class="list--text">
|
|
12
|
+
<li>첫 번째 항목</li>
|
|
13
|
+
<li>두 번째 항목
|
|
14
|
+
<ul>
|
|
15
|
+
<li>중첩 항목</li>
|
|
16
|
+
</ul>
|
|
17
|
+
</li>
|
|
18
|
+
</ul>
|
|
19
|
+
|
|
20
|
+
<!-- 번호 -->
|
|
21
|
+
<ol class="list--text list--ordered">
|
|
22
|
+
<li>1단계</li>
|
|
23
|
+
<li>2단계</li>
|
|
24
|
+
</ol>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 구조화 목록 (List — Structured / Definition)
|
|
28
|
+
|
|
29
|
+
KRDS 정의 목록 패턴. 라벨 + 값 쌍 (예: 사양, 상세 정보).
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<dl class="list--structured">
|
|
33
|
+
<div class="list__row">
|
|
34
|
+
<dt>제품명</dt>
|
|
35
|
+
<dd>예시 제품</dd>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="list__row">
|
|
38
|
+
<dt>출시일</dt>
|
|
39
|
+
<dd>2026년 4월 30일</dd>
|
|
40
|
+
</div>
|
|
41
|
+
<div class="list__row">
|
|
42
|
+
<dt>가격</dt>
|
|
43
|
+
<dd>10,000원</dd>
|
|
44
|
+
</div>
|
|
45
|
+
</dl>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 시맨틱 구조
|
|
49
|
+
|
|
50
|
+
- **Root 태그**: `<ul>` (순서 무관) / `<ol>` (순서 의미) / `<dl>` (정의 목록)
|
|
51
|
+
- **자식**: `<li>` (ul/ol) 또는 `<dt>` + `<dd>` (dl)
|
|
52
|
+
- **변형 클래스**: `.list--text` · `.list--ordered` · `.list--structured`
|
|
53
|
+
- **필수 ARIA**: — (시맨틱 태그만으로 충분)
|
|
54
|
+
- 상세: `skill/references/html-semantics.md#list`
|
|
55
|
+
|
|
56
|
+
## 접근성
|
|
57
|
+
|
|
58
|
+
- 순서 의미 — `<ol>` (있음) / `<ul>` (없음)
|
|
59
|
+
- 정의 목록 — `<dl>/<dt>/<dd>` 시맨틱 사용
|
|
60
|
+
- 모바일에선 정의 목록이 자동으로 1열로 변환
|
|
61
|
+
|
|
62
|
+
## 출처
|
|
63
|
+
|
|
64
|
+
- CSS: `src/styles/6-components/list.css`
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 주 메뉴 (Main Menu) — KRDS
|
|
2
|
+
|
|
3
|
+
드롭다운형 주 내비게이션. 헤더 안에서 사용.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<nav class="main-menu" aria-label="주 메뉴">
|
|
9
|
+
<ul class="main-menu__list">
|
|
10
|
+
<li class="main-menu__item">
|
|
11
|
+
<a class="main-menu__link" href="/about">소개</a>
|
|
12
|
+
</li>
|
|
13
|
+
|
|
14
|
+
<li class="main-menu__item">
|
|
15
|
+
<button type="button" class="main-menu__link" aria-haspopup="true" aria-expanded="false" aria-controls="submenu-services">
|
|
16
|
+
서비스
|
|
17
|
+
</button>
|
|
18
|
+
<ul id="submenu-services" class="main-menu__submenu" hidden>
|
|
19
|
+
<li><a href="/services/a">서비스 A</a></li>
|
|
20
|
+
<li><a href="/services/b">서비스 B</a></li>
|
|
21
|
+
<li><a href="/services/c" aria-current="page">서비스 C</a></li>
|
|
22
|
+
</ul>
|
|
23
|
+
</li>
|
|
24
|
+
|
|
25
|
+
<li class="main-menu__item">
|
|
26
|
+
<a class="main-menu__link" href="/contact">문의</a>
|
|
27
|
+
</li>
|
|
28
|
+
</ul>
|
|
29
|
+
</nav>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 동작 (JS)
|
|
33
|
+
|
|
34
|
+
- 드롭다운 토글: `aria-haspopup` 가진 `<button>` 클릭 → 해당 `aria-controls` 서브메뉴 hidden 토글 + `aria-expanded` 토글
|
|
35
|
+
- 외부 클릭 시 닫기
|
|
36
|
+
- ESC 키로 닫기 + 트리거 버튼으로 포커스 복귀
|
|
37
|
+
- 키보드: 화살표로 항목 이동, Enter/Space로 선택
|
|
38
|
+
|
|
39
|
+
## 접근성
|
|
40
|
+
|
|
41
|
+
- 서브메뉴 트리거는 `<button>` 권장 (`<a>` 아님 — 링크가 아니므로)
|
|
42
|
+
- `aria-haspopup="true"` + `aria-expanded` 상태값
|
|
43
|
+
- `aria-controls`로 서브메뉴 id 연결
|
|
44
|
+
- 서브메뉴 `<ul>`은 `hidden` 속성으로 노출 제어
|
|
45
|
+
- 현재 페이지: `aria-current="page"`
|
|
46
|
+
|
|
47
|
+
## 출처
|
|
48
|
+
|
|
49
|
+
- CSS: `src/styles/6-components/main-menu.css`
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 모달 (Modal / Dialog) — KRDS
|
|
2
|
+
|
|
3
|
+
## 기본 마크업
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title" hidden>
|
|
7
|
+
<div class="modal__overlay"></div>
|
|
8
|
+
<div class="modal__content modal__content--medium">
|
|
9
|
+
<header class="modal__header">
|
|
10
|
+
<h2 id="modal-title" class="modal__title">제목</h2>
|
|
11
|
+
<button type="button" class="modal__close" aria-label="닫기">×</button>
|
|
12
|
+
</header>
|
|
13
|
+
<div class="modal__body">
|
|
14
|
+
<p>모달 본문 내용</p>
|
|
15
|
+
</div>
|
|
16
|
+
<footer class="modal__footer">
|
|
17
|
+
<button type="button" class="btn btn--tertiary">취소</button>
|
|
18
|
+
<button type="button" class="btn btn--primary">확인</button>
|
|
19
|
+
</footer>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 사이즈
|
|
25
|
+
|
|
26
|
+
| 사이즈 | 클래스 | max-width |
|
|
27
|
+
|--------|--------|-----------|
|
|
28
|
+
| small | `.modal__content--small` | 400px |
|
|
29
|
+
| medium | (기본) | 560px |
|
|
30
|
+
| large | `.modal__content--large` | 800px |
|
|
31
|
+
| xlarge | `.modal__content--xlarge` | 1000px |
|
|
32
|
+
|
|
33
|
+
## 동작 (JS — 별도 구현)
|
|
34
|
+
|
|
35
|
+
- 열기: `modal.removeAttribute('hidden')` + 포커스를 모달 내부 첫 요소로 이동
|
|
36
|
+
- 닫기: `modal.setAttribute('hidden', '')` + 포커스를 트리거 버튼으로 복귀
|
|
37
|
+
- ESC 키 닫기, overlay 클릭 닫기, Tab 트랩 (포커스 가두기)
|
|
38
|
+
- 열려 있는 동안 `<body>`에 `overflow: hidden` 적용
|
|
39
|
+
|
|
40
|
+
## 접근성 (KRDS + WAI-ARIA)
|
|
41
|
+
|
|
42
|
+
- `role="dialog"` + `aria-modal="true"` 필수
|
|
43
|
+
- `aria-labelledby="제목id"`로 모달 제목 연결 (또는 `aria-label`)
|
|
44
|
+
- 본문 설명이 길면 `aria-describedby`도 추가
|
|
45
|
+
- 닫기 버튼은 `aria-label="닫기"` 필수
|
|
46
|
+
- 첫 포커스는 모달 내부 첫 인터랙티브 요소 (또는 닫기 버튼)
|
|
47
|
+
- ESC 키로 닫기 가능
|
|
48
|
+
- 백드롭은 `--color-bg-dim`
|
|
49
|
+
|
|
50
|
+
## 출처
|
|
51
|
+
|
|
52
|
+
- Shape 값은 프로젝트 밀도에 맞는 CSS/Tailwind 직접값 사용
|
|
53
|
+
- Shadow: `--shadow-3` (KRDS modal-wrap-shadow 추상화)
|
|
54
|
+
- CSS: `src/styles/6-components/modal.css`
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 페이지네이션 (Pagination) — KRDS
|
|
2
|
+
|
|
3
|
+
목록을 여러 페이지로 나눠 탐색.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<nav class="pagination" aria-label="페이지 내비게이션">
|
|
9
|
+
<button type="button" class="pagination__nav" aria-label="이전 페이지">‹</button>
|
|
10
|
+
<ol class="pagination__list">
|
|
11
|
+
<li><a class="pagination__item" href="?p=1">1</a></li>
|
|
12
|
+
<li><a class="pagination__item pagination__item--current" href="?p=2" aria-current="page">2</a></li>
|
|
13
|
+
<li><a class="pagination__item" href="?p=3">3</a></li>
|
|
14
|
+
<li><a class="pagination__item" href="?p=4">4</a></li>
|
|
15
|
+
<li><a class="pagination__item" href="?p=5">5</a></li>
|
|
16
|
+
</ol>
|
|
17
|
+
<button type="button" class="pagination__nav" aria-label="다음 페이지">›</button>
|
|
18
|
+
</nav>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 사이즈
|
|
22
|
+
|
|
23
|
+
- `.pagination` — 48px (기본)
|
|
24
|
+
- `.pagination--small` — 40px
|
|
25
|
+
|
|
26
|
+
## 비활성 (첫/마지막 페이지)
|
|
27
|
+
|
|
28
|
+
```html
|
|
29
|
+
<button class="pagination__nav" aria-label="이전 페이지" aria-disabled="true" disabled>‹</button>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 접근성
|
|
33
|
+
|
|
34
|
+
- `<nav aria-label="페이지 내비게이션">` 필수
|
|
35
|
+
- 현재 페이지: `aria-current="page"`
|
|
36
|
+
- 이전/다음 버튼: `aria-label="이전 페이지"` / `aria-label="다음 페이지"` 필수
|
|
37
|
+
- `aria-disabled="true"` + `disabled` 같이 사용 (첫/마지막 페이지)
|
|
38
|
+
|
|
39
|
+
## 출처
|
|
40
|
+
|
|
41
|
+
- CSS: `src/styles/6-components/pagination.css`
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 진행률 (Progress) — KRDS
|
|
2
|
+
|
|
3
|
+
native `<progress>` + 시각 커스텀.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="progress">
|
|
9
|
+
<div class="progress__label">
|
|
10
|
+
<span>업로드 중</span>
|
|
11
|
+
<span>60%</span>
|
|
12
|
+
</div>
|
|
13
|
+
<progress class="progress__bar" value="60" max="100" aria-label="업로드 진행률 60%">60%</progress>
|
|
14
|
+
</div>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Variant
|
|
18
|
+
|
|
19
|
+
- 기본 (primary)
|
|
20
|
+
- `.progress--success` / `.progress--warning` / `.progress--danger`
|
|
21
|
+
|
|
22
|
+
## 접근성
|
|
23
|
+
|
|
24
|
+
- native `<progress>` 사용 — 자동 ARIA 처리
|
|
25
|
+
- `aria-label` 또는 `aria-labelledby`로 진행 항목 명시
|
|
26
|
+
- 무한 로딩(불확정 시간)은 `<progress>` 대신 `.spinner` 사용
|
|
27
|
+
|
|
28
|
+
## 출처
|
|
29
|
+
|
|
30
|
+
- CSS: `src/styles/6-components/progress.css`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 셀렉트 (Select) — KRDS
|
|
2
|
+
|
|
3
|
+
native `<select>` 기반. input과 동일 사이즈/패딩 토큰.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="form-field">
|
|
9
|
+
<label for="category" class="form-field__label">카테고리</label>
|
|
10
|
+
<select id="category" class="select">
|
|
11
|
+
<option value="">선택하세요</option>
|
|
12
|
+
<option value="a">옵션 A</option>
|
|
13
|
+
<option value="b">옵션 B</option>
|
|
14
|
+
</select>
|
|
15
|
+
</div>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 사이즈
|
|
19
|
+
|
|
20
|
+
- `.select--small` (40px) / 기본 medium (48px) / `.select--large` (56px)
|
|
21
|
+
|
|
22
|
+
## 상태
|
|
23
|
+
|
|
24
|
+
- 기본 / hover / focus / disabled / error (`.select--error` 또는 `aria-invalid="true"`)
|
|
25
|
+
|
|
26
|
+
## 접근성
|
|
27
|
+
|
|
28
|
+
- 첫 옵션은 `<option value="">선택하세요</option>` 같은 placeholder 권장
|
|
29
|
+
- `<label for>` + `<select id>` 연결 필수
|
|
30
|
+
- 옵션 텍스트는 명확하고 간결하게
|
|
31
|
+
|
|
32
|
+
## 출처
|
|
33
|
+
|
|
34
|
+
- CSS: `src/styles/6-components/select.css`
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# 사이드 패널 (Side Panel) — KRDS Help panel 응용
|
|
2
|
+
|
|
3
|
+
우측에서 슬라이드 인하는 보조 패널. 모달과 달리 본문 스크롤을 차단하지 않는다.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<aside class="side-panel" role="dialog" aria-labelledby="panel-title" aria-hidden="true">
|
|
9
|
+
<header class="side-panel__header">
|
|
10
|
+
<h2 id="panel-title" class="side-panel__title">상세 정보</h2>
|
|
11
|
+
<button type="button" class="side-panel__close" aria-label="닫기">×</button>
|
|
12
|
+
</header>
|
|
13
|
+
<div class="side-panel__body">
|
|
14
|
+
<p>패널 본문 내용</p>
|
|
15
|
+
</div>
|
|
16
|
+
<footer class="side-panel__footer">
|
|
17
|
+
<button type="button" class="btn btn--tertiary">닫기</button>
|
|
18
|
+
<button type="button" class="btn btn--primary">저장</button>
|
|
19
|
+
</footer>
|
|
20
|
+
</aside>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 사이즈
|
|
24
|
+
|
|
25
|
+
| 사이즈 | 클래스 | max-width |
|
|
26
|
+
|--------|--------|-----------|
|
|
27
|
+
| small | `.side-panel--small` | 360px |
|
|
28
|
+
| medium | (기본) | 480px |
|
|
29
|
+
| large | `.side-panel--large` | 640px |
|
|
30
|
+
|
|
31
|
+
## 동작 (JS)
|
|
32
|
+
|
|
33
|
+
- 열기: `panel.setAttribute('aria-hidden', 'false')` (또는 `.side-panel--open` 추가)
|
|
34
|
+
- 닫기: `panel.setAttribute('aria-hidden', 'true')`
|
|
35
|
+
- transform 트랜지션으로 슬라이드 인/아웃
|
|
36
|
+
|
|
37
|
+
## Modal vs Side Panel
|
|
38
|
+
|
|
39
|
+
| | Modal | Side Panel |
|
|
40
|
+
|---|-------|-----------|
|
|
41
|
+
| 위치 | 화면 중앙 | 화면 우측 (또는 좌측) |
|
|
42
|
+
| 본문 차단 | 차단 (overlay) | 차단 안 함 |
|
|
43
|
+
| 용도 | 결정 강제 (확인/취소) | 보조 정보, 편집 폼 |
|
|
44
|
+
| 그림자 | shadow-3 (deep) | shadow-2 (medium) |
|
|
45
|
+
|
|
46
|
+
## 접근성
|
|
47
|
+
|
|
48
|
+
- `role="dialog"` + `aria-labelledby`
|
|
49
|
+
- 닫기 버튼 `aria-label="닫기"` 필수
|
|
50
|
+
- ESC 키 닫기 권장
|
|
51
|
+
- 포커스 트랩은 선택 (모달과 달리 본문 인터랙션 허용)
|
|
52
|
+
- `aria-hidden` 토글로 스크린리더 노출 제어
|
|
53
|
+
|
|
54
|
+
## 출처
|
|
55
|
+
|
|
56
|
+
- Shadow: `--shadow-2` (KRDS help-panel-shadow 추상화)
|
|
57
|
+
- CSS: `src/styles/6-components/side-panel.css`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 스피너 (Spinner) — KRDS
|
|
2
|
+
|
|
3
|
+
로딩 표시기. 진행 시간을 알 수 없을 때 사용.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<span class="spinner" role="status" aria-label="로딩 중"></span>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 사이즈
|
|
12
|
+
|
|
13
|
+
- `.spinner--small` (16×16)
|
|
14
|
+
- 기본 (24×24)
|
|
15
|
+
- `.spinner--large` (40×40)
|
|
16
|
+
|
|
17
|
+
## 접근성
|
|
18
|
+
|
|
19
|
+
- `role="status"` + `aria-label="로딩 중"` 필수
|
|
20
|
+
- `prefers-reduced-motion: reduce` 자동 대응 (회전 속도 절반으로)
|
|
21
|
+
|
|
22
|
+
## 출처
|
|
23
|
+
|
|
24
|
+
- CSS: `src/styles/6-components/spinner.css`
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 단계 표시기 (Step Indicator) — KRDS
|
|
2
|
+
|
|
3
|
+
다단계 폼/프로세스의 현재 단계 표시.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<ol class="step-indicator" aria-label="진행 단계">
|
|
9
|
+
<li class="step-indicator__item step-indicator__item--done">
|
|
10
|
+
<span class="step-indicator__num" aria-hidden="true">1</span>
|
|
11
|
+
<span class="step-indicator__label">정보 입력</span>
|
|
12
|
+
</li>
|
|
13
|
+
<li class="step-indicator__item step-indicator__item--current" aria-current="step">
|
|
14
|
+
<span class="step-indicator__num" aria-hidden="true">2</span>
|
|
15
|
+
<span class="step-indicator__label">확인</span>
|
|
16
|
+
</li>
|
|
17
|
+
<li class="step-indicator__item">
|
|
18
|
+
<span class="step-indicator__num" aria-hidden="true">3</span>
|
|
19
|
+
<span class="step-indicator__label">완료</span>
|
|
20
|
+
</li>
|
|
21
|
+
</ol>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 상태 클래스
|
|
25
|
+
|
|
26
|
+
- `.step-indicator__item--done` — 완료 (primary 채움)
|
|
27
|
+
- `.step-indicator__item--current` — 현재 (primary 테두리)
|
|
28
|
+
- (없음) — 예정 (회색)
|
|
29
|
+
|
|
30
|
+
## 접근성
|
|
31
|
+
|
|
32
|
+
- `<ol>` 사용 — 순서 의미 보존
|
|
33
|
+
- 현재 단계: `aria-current="step"`
|
|
34
|
+
- 번호는 시각만 — `aria-hidden="true"` (레이블이 텍스트로 의미 전달)
|
|
35
|
+
|
|
36
|
+
## 출처
|
|
37
|
+
|
|
38
|
+
- CSS: `src/styles/6-components/step-indicator.css`
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# 토글 스위치 (Switch) — KRDS
|
|
2
|
+
|
|
3
|
+
## 기본 마크업
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<label class="switch">
|
|
7
|
+
<input type="checkbox" name="notify" role="switch">
|
|
8
|
+
<span class="switch__track" aria-hidden="true"></span>
|
|
9
|
+
<span class="switch__label">알림 받기</span>
|
|
10
|
+
</label>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 사양
|
|
14
|
+
|
|
15
|
+
- 트랙: 44×24, 핸들: 20×20
|
|
16
|
+
- 컨테이너 최소 높이: `--touch-target-min` (44px)
|
|
17
|
+
- ON/OFF 즉시 반영되는 설정에 사용 (저장 버튼 없이 즉시 토글)
|
|
18
|
+
|
|
19
|
+
## 체크박스 vs 스위치 사용 기준
|
|
20
|
+
|
|
21
|
+
- **체크박스**: 옵션 선택, 동의(약관), 폼 제출과 함께 저장
|
|
22
|
+
- **스위치**: 즉시 효과 발생하는 ON/OFF 설정 (알림 ON/OFF, 다크모드 등)
|
|
23
|
+
|
|
24
|
+
## 접근성
|
|
25
|
+
|
|
26
|
+
- `role="switch"` 권장 — 스크린리더가 "스위치"로 안내
|
|
27
|
+
- 시각 트랙(`__track`)은 `aria-hidden="true"`
|
|
28
|
+
- 상태 변경은 native `:checked`만으로 충분 (별도 aria-checked 불필요)
|
|
29
|
+
|
|
30
|
+
## 출처
|
|
31
|
+
|
|
32
|
+
- CSS: `src/styles/6-components/switch.css`
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 탭 (Tab) — KRDS
|
|
2
|
+
|
|
3
|
+
## 기본 마크업 (WAI-ARIA tabs pattern)
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<div class="tab">
|
|
7
|
+
<div class="tab__list" role="tablist" aria-label="섹션">
|
|
8
|
+
<button class="tab__item" role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">
|
|
9
|
+
개요
|
|
10
|
+
</button>
|
|
11
|
+
<button class="tab__item" role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2" tabindex="-1">
|
|
12
|
+
상세
|
|
13
|
+
</button>
|
|
14
|
+
<button class="tab__item" role="tab" aria-selected="false" aria-controls="panel-3" id="tab-3" tabindex="-1">
|
|
15
|
+
후기
|
|
16
|
+
</button>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="tab__panel" role="tabpanel" id="panel-1" aria-labelledby="tab-1">
|
|
19
|
+
개요 내용
|
|
20
|
+
</div>
|
|
21
|
+
<div class="tab__panel" role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
|
|
22
|
+
상세 내용
|
|
23
|
+
</div>
|
|
24
|
+
<div class="tab__panel" role="tabpanel" id="panel-3" aria-labelledby="tab-3" hidden>
|
|
25
|
+
후기 내용
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 사이즈
|
|
31
|
+
|
|
32
|
+
- `.tab__list--small` (40px height) — 보조 컨텍스트
|
|
33
|
+
- 기본 (48px) — 표준
|
|
34
|
+
- `.tab__list--large` (56px height) — 강조
|
|
35
|
+
|
|
36
|
+
## 동작 (JS — 별도 구현)
|
|
37
|
+
|
|
38
|
+
- 탭 클릭 → 모든 `aria-selected="false"` + 클릭한 탭만 `aria-selected="true"`
|
|
39
|
+
- 모든 패널 `hidden` + 활성 탭의 `aria-controls` 패널만 `hidden` 제거
|
|
40
|
+
- 키보드 — 좌/우 화살표로 탭 이동, Home/End로 처음/마지막
|
|
41
|
+
- 비활성 탭은 `tabindex="-1"`로 Tab 키에서 제외 (활성 탭만 `tabindex` 없음)
|
|
42
|
+
|
|
43
|
+
## 접근성 (KRDS + WAI-ARIA)
|
|
44
|
+
|
|
45
|
+
- `role="tablist"` + 각 탭에 `role="tab"`, 패널에 `role="tabpanel"`
|
|
46
|
+
- 탭 ↔ 패널 연결: `aria-controls` (탭 → 패널 id), `aria-labelledby` (패널 → 탭 id)
|
|
47
|
+
- 활성 표시는 `aria-selected="true"` (시각 인디케이터는 CSS가 자동 처리)
|
|
48
|
+
- `aria-label` 또는 `aria-labelledby`로 탭 그룹의 목적 명시 권장
|
|
49
|
+
|
|
50
|
+
## 출처
|
|
51
|
+
|
|
52
|
+
- CSS: `src/styles/6-components/tab.css`
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 표 (Table) — KRDS
|
|
2
|
+
|
|
3
|
+
데이터 표. 모바일에서는 가로 스크롤 컨테이너로 감싸서 사용.
|
|
4
|
+
|
|
5
|
+
## 기본 마크업
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<div class="table-wrap">
|
|
9
|
+
<table class="table">
|
|
10
|
+
<caption class="table__caption">2026년 1분기 신청 현황</caption>
|
|
11
|
+
<thead>
|
|
12
|
+
<tr>
|
|
13
|
+
<th scope="col">번호</th>
|
|
14
|
+
<th scope="col">신청자</th>
|
|
15
|
+
<th scope="col">신청일</th>
|
|
16
|
+
<th scope="col">상태</th>
|
|
17
|
+
</tr>
|
|
18
|
+
</thead>
|
|
19
|
+
<tbody>
|
|
20
|
+
<tr>
|
|
21
|
+
<td>1</td>
|
|
22
|
+
<td>홍길동</td>
|
|
23
|
+
<td>2026-04-01</td>
|
|
24
|
+
<td><span class="tag tag--success">완료</span></td>
|
|
25
|
+
</tr>
|
|
26
|
+
</tbody>
|
|
27
|
+
</table>
|
|
28
|
+
</div>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Variant
|
|
32
|
+
|
|
33
|
+
- 기본
|
|
34
|
+
- `.table--hover` — 행 호버 강조
|
|
35
|
+
- `.table--striped` — 줄무늬 (짝수 행 회색)
|
|
36
|
+
- `.table--compact` — 좁은 패딩 (8px 12px)
|
|
37
|
+
- `.table--comfortable` — 넓은 패딩 (20px)
|
|
38
|
+
|
|
39
|
+
## 정렬 가능한 헤더
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<th scope="col" aria-sort="ascending">
|
|
43
|
+
<button type="button">신청일</button>
|
|
44
|
+
</th>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 선택된 행
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<tr aria-selected="true">...</tr>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## 접근성
|
|
54
|
+
|
|
55
|
+
- `<th scope="col">` 또는 `scope="row">` 필수
|
|
56
|
+
- `<caption>`으로 표 제목 명시
|
|
57
|
+
- 정렬 헤더는 `aria-sort="ascending|descending|none"`
|
|
58
|
+
- 선택 행은 `aria-selected="true"`
|
|
59
|
+
- 모바일 가로 스크롤은 `<div class="table-wrap">` 래퍼로 감싸기
|
|
60
|
+
|
|
61
|
+
## 출처
|
|
62
|
+
|
|
63
|
+
- CSS: `src/styles/6-components/table.css`
|