@wishket/design-system 3.6.0 → 3.8.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 (33) hide show
  1. package/dist/ai/components/AutoCompleteList.md +86 -0
  2. package/dist/ai/components/Autocomplete.md +83 -0
  3. package/dist/ai/components/Button.md +205 -0
  4. package/dist/ai/components/Calendar.md +91 -0
  5. package/dist/ai/components/Checkbox.md +96 -0
  6. package/dist/ai/components/CheckboxCard.md +116 -0
  7. package/dist/ai/components/CheckboxList.md +102 -0
  8. package/dist/ai/components/ChoiceChip.md +127 -0
  9. package/dist/ai/components/CommentArea.md +112 -0
  10. package/dist/ai/components/FileUploader.md +146 -0
  11. package/dist/ai/components/FilterChip.md +133 -0
  12. package/dist/ai/components/FilterList.md +75 -0
  13. package/dist/ai/components/IconButton.md +97 -0
  14. package/dist/ai/components/IconButtonDropdown.md +103 -0
  15. package/dist/ai/components/InputChip.md +95 -0
  16. package/dist/ai/components/List.md +104 -0
  17. package/dist/ai/components/MultiColumnList.md +87 -0
  18. package/dist/ai/components/Radio.md +140 -0
  19. package/dist/ai/components/RadioCard.md +134 -0
  20. package/dist/ai/components/RadioList.md +150 -0
  21. package/dist/ai/components/RangeSlider.md +139 -0
  22. package/dist/ai/components/SearchField.md +117 -0
  23. package/dist/ai/components/SegmentedControl.md +131 -0
  24. package/dist/ai/components/Switch.md +114 -0
  25. package/dist/ai/components/TextButton.md +123 -0
  26. package/dist/ai/components/TextButtonDropdown.md +101 -0
  27. package/dist/ai/components/TextField.md +129 -0
  28. package/dist/ai/components/TextFieldDropdown.md +123 -0
  29. package/dist/ai/components/Textarea.md +154 -0
  30. package/dist/ai/components/index.json +324 -0
  31. package/dist/ai/tokens.json +1 -1
  32. package/dist/config/tailwind.config.js +15 -15
  33. package/package.json +5 -2
@@ -0,0 +1,117 @@
1
+ ---
2
+ id: INPUT-17
3
+ component: SearchField
4
+ version: 0.0.3
5
+ status: draft
6
+ figma.componentKey: 891b93a624445312daea6efc719271f1073972f7
7
+ ---
8
+
9
+ # 17. SearchField
10
+
11
+ **개정 이력**
12
+
13
+ - v0.0.1 (2026.09.28): 초안 작성
14
+ - v0.0.2 (2026.10.01): 프론트매터 추가, Properties를 코드(`SearchFieldProps`)·스토리북 기준으로 정리, 피그마 ↔ 코드 상태 대응표·Size 추가, 미결 항목을 `Z. 미결`로 분리
15
+ - v0.0.3 (2026.10.02): Properties 안내 문구 통일, `value` · `onChange` · `className` 추가, `Filters` 안의 `alignRight` 명시, 형식 정리 (#1295 리뷰 반영)
16
+
17
+ ## A. Anatomy
18
+
19
+ SearchField는 **Container** 안에 검색어를 입력하는 **Text**와 우측의 **Search Icon**으로 구성되며, 좌측에 검색 범위를 고르는 **Text Button Dropdown**을 둘 수 있습니다.
20
+
21
+ | 요소 | 필수 여부 | 설명 |
22
+ | --- | --- | --- |
23
+ | Container | 필수 | 배경·테두리·패딩을 담당하는 영역. 클릭/포커스 영역의 기준 |
24
+ | Text Button Dropdown | 선택 | 좌측에서 **검색 범위·조건**을 고르는 드롭다운 |
25
+ | Placeholder / Text | 필수 | 입력 전에는 Placeholder, 입력 중에는 검색어 |
26
+ | Search Icon | 필수 | 우측의 돋보기 아이콘. 검색 실행. **Enter 키로도 실행**됩니다 |
27
+
28
+ ## B. Description
29
+
30
+ ### 1. 정의
31
+
32
+ 사용자가 원하는 특정 항목을 찾아야 할 때 사용합니다.
33
+
34
+ ### 2. 사용 시점
35
+
36
+ - 목록이나 페이지에서 **검색어로 결과를 좁힐 때** 사용합니다.
37
+ - 검색 대상을 **범위별로 나눠야** 할 때 `Text Button Dropdown`을 함께 사용합니다. (`전체`, `프로젝트명`, `작성자`)
38
+ - 입력하는 동안 **제안 목록을 띄워 고르게** 하는 것이 목적이라면 **Autocomplete**를 사용합니다.
39
+ - 검색이 아니라 값을 입력받는 것이라면 **Input(Text Field)** 을 사용합니다.
40
+
41
+ ### 3. 키워드
42
+
43
+ SearchField, 검색, 검색창, 검색 필드, Search, 검색어 입력, 돋보기
44
+
45
+ ### 4. Size
46
+
47
+ - SearchField는 **부모 컨테이너 너비를 100% 채웁니다.** Figma의 `240`은 예시 값입니다.
48
+ - 높이는 **50**입니다.
49
+ - 검색어·Placeholder는 **1줄로 고정**합니다. 넘치면 줄바꿈하지 않고 가려집니다.
50
+
51
+ ### 5. Do / Don't
52
+
53
+ **Do**
54
+
55
+ - Placeholder에는 **무엇으로 검색할 수 있는지** 적습니다. (`프로젝트명으로 검색`)
56
+ - Dropdown 라벨은 현재 선택된 범위를 그대로 보여줍니다.
57
+ - 검색 결과가 없을 때의 안내를 함께 설계합니다.
58
+
59
+ **Don't**
60
+
61
+ - 검색어를 2줄로 표시하지 않습니다.
62
+ - Search Icon 자리에 다른 액션(초기화 등)을 겹쳐 넣지 않습니다.
63
+ - Dropdown 라벨을 문장으로 쓰지 않습니다.
64
+ - 입력할 때마다 결과 페이지로 이동시키지 않습니다.
65
+
66
+ ## C. Properties
67
+
68
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`OnSearch` → `onSearch`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
69
+
70
+ | Property | Type | Values | 비고 |
71
+ | --- | --- | --- | --- |
72
+ | OnSearch | Function | | **필수.** 검색 실행 동작(Search Icon 클릭 또는 Enter 시 호출) · 동작용, 시각 변화 없음 |
73
+ | Placeholder | String | | 입력 전 안내 문구. 피그마 `Variant = Placeholder`에 해당 |
74
+ | Value | String | | 입력한 검색어 |
75
+ | OnChange | Function | | 검색어가 바뀔 때 호출 · 동작용 |
76
+ | Disabled | Boolean | True / False | 입력·드롭다운·검색 모두 비활성. 피그마 `State = Disabled`에 해당 |
77
+ | Filters | Object | 아래 표 | **값을 넣으면 Text Button Dropdown이 나타납니다.** 켜고 끄는 Boolean이 아닙니다 · 피그마 `TextButtonDropdown`에 해당 (이름 변경 제안은 Z-4) |
78
+ | ClassName | String | | 개발용 스타일 지정 |
79
+
80
+ **`Filters` 안에 넣는 값**
81
+
82
+ | 값 | Type | 비고 |
83
+ | --- | --- | --- |
84
+ | Items | 항목 목록 | **필수.** 드롭다운 항목. 항목 하나는 `{ key, value }` (`value`가 화면에 보이는 글자) |
85
+ | SelectedItem | 항목 | **필수.** 지금 선택된 항목. 라벨에 이 값이 표시됩니다 |
86
+ | OnItemClick | Function | **필수.** 항목을 골랐을 때 호출 · 동작용 |
87
+ | AlignRight | Boolean | 드롭다운 목록을 **오른쪽 기준으로** 펼칩니다. 기본은 왼쪽 기준 |
88
+
89
+ **피그마 ↔ 코드 대응**
90
+
91
+ 피그마의 `Variant`와 `State`는 코드에 따로 넣는 값이 없고, **자동으로** 정해집니다.
92
+
93
+ | 피그마 | 코드 | 모습 |
94
+ | --- | --- | --- |
95
+ | `Variant = Empty` | 값·Placeholder 없음 | 빈 입력 영역 |
96
+ | `Variant = Placeholder` | `placeholder`만 있음 | 회색 안내 문구 |
97
+ | `Variant = Text` | 입력값 있음 | 검정 검색어 |
98
+ | `State = Enabled` | 기본 | 회색 테두리 |
99
+ | `State = Hovered` | 마우스 hover (자동) | Primary 테두리 |
100
+ | `State = Focused` | 입력 중 (자동) | Primary 테두리 |
101
+ | `State = Disabled` | `disabled` | 회색 배경, 글자·아이콘 흐리게 |
102
+
103
+ > ```tsx
104
+ > <SearchField placeholder="프로젝트명으로 검색" onSearch={search}
105
+ > value={keyword} onChange={e => setKeyword(e.target.value)}
106
+ > filters={{ items: [{ key: 'all', value: '전체' }, { key: 'title', value: '프로젝트명' }],
107
+ > selectedItem, onItemClick: setSelectedItem }} />
108
+ > ```
109
+
110
+ ## Z. 미결 (구현하지 말 것)
111
+
112
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
113
+
114
+ 1. **피그마 시안의 2줄 텍스트**: 드롭다운이 있는 변형에서 "플레이스 홀더"·"입력한 텍스트"가 2줄로 꺾여 있어, 이 문서의 Don't("검색어를 2줄로 표시하지 않습니다")와 어긋납니다. 피그마 텍스트를 1줄 고정으로 수정 필요
115
+ 2. **피그마 드롭다운 켜고 끄기**: 피그마 변형 12종이 모두 드롭다운이 있는 모습입니다. 드롭다운 없는 SearchField를 피그마에서 어떻게 표현하는지(Boolean 속성 유무) 확인 필요
116
+ 3. **스토리북 예시 (개발팀 전달)**: 스토리북 예시의 드롭다운 항목이 정렬 기준("기본 정렬 순", "금액 높은 순" …)이라 가이드(검색 범위: `전체`, `프로젝트명`, `작성자`)와 다릅니다. 또 `SearchField.tsx` 주석 예시가 `label` · `{ label, value }` 형태를 쓰는데 실제 타입은 `{ key, value }` · `selectedItem` · `onItemClick`입니다
117
+ 4. **`Filters` 이름 변경 제안**: 스토리북 `filters`와 피그마 `TextButtonDropdown`을 **`withFilter`** 로 통일하자는 제안. 코드 prop 이름을 바꾸는 일이라 개발팀과 결정 필요
@@ -0,0 +1,131 @@
1
+ ---
2
+ id: INPUT-28
3
+ component: SegmentedControl
4
+ version: 0.0.2
5
+ status: draft
6
+ ---
7
+
8
+ # 28. SegmentedControl
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.10.06): 초안 작성
13
+ - v0.0.2 (2026.10.16): 터치 영역을 코드에 맞춤 — Item 영역만 눌리고, 줄의 남는 공간은 눌리지 않음 (#1299 리뷰 반영)
14
+
15
+ ## A. Anatomy
16
+
17
+ SegmentedControl은 **Item**을 가로로 붙여 놓은 한 줄입니다. 그중 하나만 선택되고, 선택된 Item에만 테두리가 생깁니다.
18
+
19
+ | 요소 | 필수 여부 | 설명 |
20
+ | --- | --- | --- |
21
+ | Container | 필수 | Item을 간격 없이 가로로 붙임. 양 끝 모서리 12 |
22
+ | Item | 필수 | 선택지 하나. 텍스트만 들어감. 너비는 텍스트에 맞춤(좌우 16) |
23
+
24
+ > 피그마의 Item `Variant`(Start / Middle / End)는 **위치에 따른 모서리 모양**입니다. 코드는 첫·마지막 Item에 자동으로 모서리를 넣습니다.
25
+
26
+ **크기별**
27
+
28
+ | Size | 높이 | 텍스트 | 여백 |
29
+ | --- | --- | --- | --- |
30
+ | Small (`sm`) | 40 | Body 14 (선택 시 Medium) | 상하 8 · 좌우 16 |
31
+ | Medium (`md`, 기본값) | 50 | Body 16 Regular | 상하 12 · 좌우 16 |
32
+
33
+ **상태별 표시**
34
+
35
+ | 상태 | 테두리 | 배경 | 텍스트 |
36
+ | --- | --- | --- | --- |
37
+ | 선택되지 않음 | 없음 | `w-gray-50` | `w-gray-300` |
38
+ | 선택됨 | `primary-500` 1px | `primary-10` | `primary-500` |
39
+
40
+ > **Hover · 키보드 포커스 상태는 추가해야 합니다.** 지금은 코드·피그마 모두 없어, 피그마에 모습을 정하고 코드 수정을 요청해야 합니다. Disabled는 미정입니다. (Z-1)
41
+
42
+ ## B. Description
43
+
44
+ ### 1. 정의
45
+
46
+ 동일 화면 안에서 짧은 필터·보기 전환을 빠르게 제공할 때 사용합니다. 최대 4~5개의 짧은 라벨을 쓰고, 콘텐츠는 탭 바로 아래에서 즉시 바뀌는 상황에 적합합니다.
47
+
48
+ ### 2. 사용 시점
49
+
50
+ - 같은 내용을 **보는 방식·기간·조건을 바꿀 때** 사용합니다. (`일간` / `주간` / `월간`, `전체` / `진행 중` / `완료`)
51
+ - 선택지가 **2~5개**로 적고, 모두 한 줄에 들어갈 때 사용합니다.
52
+ - 폼에서 값을 고르고 나중에 저장하는 것이라면 **Radio** · **RadioList**를 사용합니다.
53
+ - 선택지가 많거나 길다면 **TextButtonDropdown**을 사용합니다.
54
+ - 화면의 다른 영역(다른 콘텐츠)으로 이동하는 것이라면 **TextTab** · **BoxTab**을 사용합니다.
55
+ - 켜고 끄는 선택 하나라면 **Switch**를 사용합니다.
56
+
57
+ **SegmentedControl · ChoiceChip · Radio**
58
+
59
+ | 기준 | SegmentedControl | ChoiceChip | Radio |
60
+ | --- | --- | --- | --- |
61
+ | 선택 개수 | 하나만 | 하나 또는 여러 개 | 하나만 |
62
+ | 반영 | 고르면 바로 | 고르면 바로(필터) 또는 저장 시 | 보통 저장 시 |
63
+ | 모양 | 붙어 있는 한 줄 | 떨어진 칩 여러 개 | 세로 목록 |
64
+ | 선택 해제 | 불가 (항상 하나 선택) | 가능 | 불가 |
65
+ | 예시 | 일간 / 주간 / 월간 | 기술 스택, 관심 분야 | 결제 수단, 사업자 유형 |
66
+
67
+ ### 3. 키워드
68
+
69
+ SegmentedControl, 세그먼트 컨트롤, 세그먼트, Segment, 토글, 보기 전환, 기간 선택, 단일 선택
70
+
71
+ ### 4. 터치 영역
72
+
73
+ **Item 하나하나**가 눌리는 영역입니다. 텍스트만이 아니라 Item의 여백까지 눌러도 선택됩니다. Item끼리는 간격 없이 붙어 있어 Item 사이에 빈틈은 없습니다.
74
+
75
+ 다만 Item은 **텍스트 너비만큼만** 차지합니다. 컴포넌트 줄이 Item들보다 넓으면 **마지막 Item 오른쪽에 남는 공간은 눌리지 않습니다.** (줄을 꽉 채우는 배치는 Z-5)
76
+
77
+ ### 5. 가이드라인 (Do / Don't)
78
+
79
+ **선택지는 2~5개**
80
+
81
+ - Do: 선택지는 2~5개로 둡니다. 한 줄에 다 들어가야 비교하며 고를 수 있습니다.
82
+ - Don't: 선택지가 많아 줄이 넘치거나 줄바꿈되게 두지 않습니다. 그럴 때는 **TextButtonDropdown**을 씁니다.
83
+
84
+ **텍스트는 짧고 길이를 비슷하게**
85
+
86
+ - Do: 한두 단어의 짧은 말로, Item끼리 길이를 비슷하게 씁니다. Item 너비가 텍스트에 맞춰지므로 길이가 다르면 칸 크기가 들쭉날쭉해집니다.
87
+
88
+ **처음부터 하나를 선택해 두기**
89
+
90
+ - Do: 항상 하나가 선택된 상태로 시작합니다. (예: `전체`, 가장 많이 보는 기간) 선택 해제는 되지 않습니다.
91
+
92
+ **바로 반영되는 전환에만**
93
+
94
+ - Do: 고르면 아래 내용이 곧바로 바뀌는 곳에 씁니다.
95
+ - Don't: 저장 버튼을 눌러야 반영되는 폼 값에 쓰지 않습니다. 그 경우는 **Radio**입니다.
96
+
97
+ **그 밖에**
98
+
99
+ - 한 화면에 SegmentedControl을 여러 개 둘 때는 각각 `name`을 다르게 줍니다. (C. Properties · Z-2)
100
+ - 한 화면에서 Small과 Medium을 섞지 않습니다.
101
+
102
+ ## C. Properties
103
+
104
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`SelectedValue` → `selectedValue`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
105
+
106
+ | Property | Type | Values | 비고 |
107
+ | --- | --- | --- | --- |
108
+ | ValueList | Array | `{ key, name }` 목록 | **필수.** `name` = Item에 보이는 텍스트, `key` = 값 · 피그마는 Item을 직접 배치 |
109
+ | SelectedValue | String | | **필수.** 선택된 Item의 `key` · 피그마 Item `Is Selected` |
110
+ | Size | Variant | `sm` / `md` | 기본값 `md`. 피그마 `Size` (Small / Medium) · 피그마 기본값은 Small |
111
+ | OnChange | Function | | **필수.** 선택이 바뀔 때 고른 `key`를 넘김 · 동작용 |
112
+ | Name | String | | 기본값 `segmented-control`. 안의 라디오 묶음 이름 · 개발용. 한 화면에 여러 개면 다르게 줌 (Z-2) |
113
+ | Variant (Item) | Variant | Start / Middle / End | 피그마에만 존재. 위치에 따른 모서리 · 코드는 첫·마지막 Item에 자동 적용 |
114
+
115
+ > `Disabled` · `ClassName` · `TestId`는 이 컴포넌트에 **없습니다.**
116
+ >
117
+ > ```tsx
118
+ > <SegmentedControl size="sm" name="period"
119
+ > valueList={[{ key: 'day', name: '일간' }, { key: 'week', name: '주간' }, { key: 'month', name: '월간' }]}
120
+ > selectedValue={period} onChange={setPeriod} />
121
+ > ```
122
+
123
+ ## Z. 미결 (구현하지 말 것)
124
+
125
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
126
+
127
+ 1. **Disabled 없음**: 코드·피그마 모두 전체 또는 Item 하나를 비활성으로 만드는 상태가 없습니다 → 필요한 화면이 있는지 확인하고 추가할지 결정
128
+ 2. **`name` 기본값이 고정됨 (코드 확인 필요)**: `name`을 안 넣으면 모두 `segmented-control`이 됩니다. 한 화면에 두 개 이상 두면 안의 라디오가 한 묶음으로 잡혀 키보드 이동·폼 전송이 꼬일 수 있습니다 → 컴포넌트마다 자동으로 다른 이름을 주도록 개발팀에 요청
129
+ 3. **무엇을 고르는지 스크린리더에 알릴 수 없음 (코드 확인 필요)**: 묶음의 설명이 `segmented control`로 고정돼 있어 "기간 선택"처럼 용도를 알려줄 수 없습니다 → 바꿀 수 있게 할지 개발팀에 요청
130
+ 4. **기본 크기 차이**: 코드 기본값은 `md`, 피그마 기본값은 Small입니다 → 피그마 기본값을 Medium으로 맞출지 검토
131
+ 5. **너비를 꽉 채우는 배치**: 지금은 Item이 텍스트 너비에 맞춰지고, 남는 공간은 비어 있고 눌리지도 않습니다. 모바일처럼 줄 전체를 Item이 같은 너비로 나눠 채우는 배치가 필요한지 결정
@@ -0,0 +1,114 @@
1
+ ---
2
+ id: INPUT-29
3
+ component: Switch
4
+ version: 0.0.2
5
+ status: draft
6
+ ---
7
+
8
+ # 29. Switch
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.10.06): 초안 작성
13
+ - v0.0.2 (2026.10.16): `className`이 적용되는 자리를 코드에 맞춤 — 바깥 영역이 아니라 트랙 (#1299 리뷰 반영)
14
+
15
+ ## A. Anatomy
16
+
17
+ Switch는 가로로 긴 **Container**(트랙) 위를 **Handle**(동그라미)이 좌우로 움직이는 구조입니다. 켜지면 Handle이 오른쪽, 꺼지면 왼쪽에 있습니다. **Label은 컴포넌트에 포함돼 있지 않습니다.**
18
+
19
+ | 요소 | 필수 여부 | 설명 |
20
+ | --- | --- | --- |
21
+ | Container | 필수 | 32×16 트랙. 모서리 완전히 둥글게. 켜짐/꺼짐을 색으로 표시 |
22
+ | Handle | 필수 | 20×20 흰 원, 테두리 1px. 트랙보다 살짝 커서 양쪽으로 2~4px 밖에 나옴. 전환 시 미끄러지듯 이동 |
23
+
24
+ > 보이는 전체 크기는 **36×20**입니다 (피그마와 같음). 크기는 하나뿐입니다.
25
+
26
+ **상태별 표시**
27
+
28
+ | 상태 | Container | Handle |
29
+ | --- | --- | --- |
30
+ | 꺼짐 | `w-gray-300` | 흰색 · 왼쪽 |
31
+ | 켜짐 | `primary-500` | 흰색 · 오른쪽 |
32
+ | Disabled + 꺼짐 | `w-gray-100` | 흰색 · 왼쪽 |
33
+ | Disabled + 켜짐 | `primary-100` | 흰색 · 오른쪽 |
34
+
35
+ > Hover · 키보드 포커스 상태는 코드·피그마 모두 없습니다.
36
+
37
+ ## B. Description
38
+
39
+ ### 1. 정의
40
+
41
+ 사용자가 두 가지 상태를 빠르게 전환할 수 있도록 제공되는 토글형 컴포넌트입니다. 켜거나 끄면 **저장 없이 바로 적용**됩니다.
42
+
43
+ ### 2. 사용 시점
44
+
45
+ - 설정을 **켜고 끄면 즉시 반영**될 때 사용합니다. (알림 받기, 프로필 공개, 자동 연장)
46
+ - 저장하기를 눌러야 반영되는 폼 항목이라면 **Checkbox**를 사용합니다.
47
+
48
+ **Switch와 Checkbox**
49
+
50
+ | 속성 | Switch | Checkbox |
51
+ | --- | --- | --- |
52
+ | 값 적용 | 별도 액션 없이 즉시 | 저장하기 등 액션을 해야 저장 |
53
+ | 항목 구성 | 개별 항목으로 구성 | 한 카테고리에 여러 항목 나열 가능 |
54
+ | 하위 항목 | 부모·하위 관계 없음 | 부모가 하위 항목을 모두 선택·해제 |
55
+
56
+ > Checkbox 문서의 비교표와 같은 내용입니다.
57
+
58
+ ### 3. 키워드
59
+
60
+ Switch, 스위치, 토글, Toggle, On/Off, 켜기/끄기, 설정
61
+
62
+ ### 4. 가이드라인 (Do / Don't)
63
+
64
+ **즉시 반영되는 곳에만**
65
+
66
+ - Do: 켜고 끄는 순간 바로 적용되는 설정에 씁니다.
67
+ - Don't: 저장·확인을 눌러야 반영되는 곳에 쓰지 않습니다. 그 경우는 **Checkbox**입니다.
68
+
69
+ **항목마다 독립적으로**
70
+
71
+ - Do: 하나의 Switch는 하나의 설정만 켭니다.
72
+ - Don't: "전체 켜기"처럼 다른 Switch들을 한꺼번에 제어하는 부모·하위 구조에 쓰지 않습니다. 그 경우는 **Checkbox**입니다.
73
+
74
+ **Label과 함께, 무엇을 켜는지 알 수 있게**
75
+
76
+ - Do: Switch 옆에 무엇을 켜는지 Label을 두고, Label을 눌러도 켜지게 연결합니다.
77
+ - Do: Label은 항목 이름으로 짧게 씁니다. (`마케팅 정보 수신 동의`, `댓글 알림`) 필요하면 아래에 설명을 한 줄 더합니다.
78
+
79
+ **Disabled는 Label까지**
80
+
81
+ - Do: Switch를 Disabled로 두면 옆의 Label도 비활성 색(`w-gray-300`)으로 바꿉니다.
82
+ - Don't: Switch만 흐리게 하고 Label은 그대로 두지 않습니다. 항목 전체가 못 쓰는 상태인지 알 수 없습니다.
83
+
84
+ **그 밖에**
85
+
86
+ - 설정 목록에서는 Label을 왼쪽, Switch를 오른쪽 끝에 정렬합니다.
87
+ - 바로 적용되므로, 결과가 크거나 되돌리기 어려운 설정은 켜기 전에 확인 **Dialog**를 띄웁니다.
88
+
89
+ ## C. Properties
90
+
91
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`OnChange` → `onChange`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
92
+
93
+ | Property | Type | Values | 비고 |
94
+ | --- | --- | --- | --- |
95
+ | Checked | Boolean | True / False | 켜짐 여부 · 피그마 `Checked` |
96
+ | Disabled | Boolean | True / False | 피그마 `Disabled` |
97
+ | OnChange | Function | | 켜거나 끌 때 호출 · 동작용 |
98
+ | Id | String | | Label과 연결할 때 사용 (`<label htmlFor>`) · 개발용 |
99
+ | Name | String | | 폼 전송용 이름 · 개발용 |
100
+ | ClassName | String | | 개발용 스타일 지정. **스위치 트랙에 적용**됩니다 — 바깥 영역이 아니라서 여백(`mt-4` 등)을 주면 트랙만 움직입니다. 위치는 감싼 요소에서 잡습니다 |
101
+ | State | Variant | Enabled | 피그마에만 존재. 값이 하나뿐이라 의미 없음 |
102
+
103
+ > 이 외에도 일반 `<input type="checkbox">`의 속성(`aria-*` 등)을 그대로 받습니다. `Label` · `Size`는 없습니다.
104
+ >
105
+ > ```tsx
106
+ > <label htmlFor="noti">알림 받기</label>
107
+ > <Switch id="noti" checked={on} onChange={() => setOn(!on)} />
108
+ > ```
109
+
110
+ ## Z. 미결 (구현하지 말 것)
111
+
112
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
113
+
114
+ 1. **Handle 테두리 색 토큰 (코드 확인 필요)**: 코드가 디자인 시스템 토큰 `w-gray-200`이 아니라 Tailwind 기본 `gray-200`을 씁니다. 두 색이 다를 수 있습니다 → `w-gray-200`으로 바꾸도록 개발팀에 요청
@@ -0,0 +1,123 @@
1
+ ---
2
+ id: INPUT-08
3
+ component: TextButton
4
+ version: 0.0.2
5
+ status: draft
6
+ figma.componentKey: 3eee8fa20aa4f3bb067ce717749cf42223042f16
7
+ ---
8
+
9
+ # 8. TextButton
10
+
11
+ **개정 이력**
12
+
13
+ - v0.0.1 (2026.09.22): 초안 작성
14
+ - v0.0.2 (2026.10.16): Property 이름을 소문자로 통일 (피그마 전용 속성 포함)
15
+
16
+ ## A. Anatomy
17
+
18
+ TextButton은 **Text**로 구성되며, 선택적으로 **Leading Icon**과 **Trailing Icon**을 가집니다. 배경과 테두리가 없습니다.
19
+
20
+
21
+ | 요소 | 필수 여부 | 설명 |
22
+ | ------------- | ----- | ---------------------------------- |
23
+ | Text | 필수 | 액션을 설명하는 텍스트. 이 컴포넌트의 클릭 영역 기준 |
24
+ | Leading Icon | 선택 | 텍스트 앞 아이콘. 액션의 **의미를 보조** |
25
+ | Trailing Icon | 선택 | 텍스트 뒤 아이콘. Chevron 등 **방향·이동을 보조** |
26
+
27
+
28
+ > Container가 없어 **텍스트 크기가 곧 클릭 영역**입니다. 별도의 패딩을 갖지 않습니다.
29
+
30
+ ## B. Description
31
+
32
+ ### 1. 정의
33
+
34
+ 클릭 시 이벤트가 발생하는 경우에 사용되는 컴포넌트로, 보조 액션 또는 행동 트리거에 적합한 텍스트형 버튼입니다.
35
+
36
+ ### 2. 사용 시점
37
+
38
+ - 부가적이지만 **강조가 필요한 행동**에 사용합니다. (`수정`, `삭제`, `더보기`)
39
+ - 페이지 내에서 액션이 일어나는 경우, **Link 대신** TextButton을 사용합니다. Link는 페이지 이동에만 씁니다.
40
+ - 화면의 주요 액션(Primary)에는 사용하지 않습니다. 배경이 있는 **Button**을 사용합니다.
41
+ - 테이블 행·카드 하단처럼 여러 액션을 좁은 공간에 나열해야 할 때 적합합니다.
42
+ - 아이콘만으로 의미가 통하고 공간이 없다면 **IconButton**을 사용합니다.
43
+ - 아이콘 색상은 텍스트 색상을 따릅니다.
44
+ - **밑줄은 텍스트에만** 적용하고 아이콘에는 적용하지 않습니다.
45
+ - Hovered에서 색상은 바뀌지 않습니다. 밑줄만 추가됩니다.
46
+
47
+ > TextButton은 Button보다 **낮은 시각 위계**를 가집니다. 한 화면에서 Button과 TextButton이 함께 있으면 Button이 주요 액션입니다.
48
+
49
+ ### 3. 키워드
50
+
51
+ TextButton, 텍스트버튼, 버튼, Btn, txt, 텍스트 링크, Primary Text Button
52
+
53
+ ### 4. Size
54
+
55
+
56
+ | Size | Font | Icon | Icon–Text Gap | 높이 |
57
+ | ---------- | -------------------------------------- | ---- | ------------- | --- |
58
+ | **Small** | Body 14 / Medium (14 · line-height 24) | 14 | 2 | 24 |
59
+ | **Medium** | Body 16 / Medium (16 · line-height 26) | 16 | 4 | 26 |
60
+
61
+
62
+ - 두 Size 모두 텍스트 굵기는 **Medium**입니다. 본문과 구분되도록 하는 장치입니다.
63
+ - 주변 본문의 폰트 크기에 맞춰 Size를 고릅니다. 본문이 16이면 Medium, 14면 Small을 씁니다.
64
+
65
+ ### 4-1. Color
66
+
67
+
68
+ | Color | 사용 상황 |
69
+ | ----------- | -------------- |
70
+ | **Primary** | 주요 행동을 유도하는 경우 |
71
+ | **Gray** | 보조 행동 |
72
+
73
+
74
+ - 한 묶음 안에서 **주요 행동 하나만 Primary**로 두고 나머지는 Gray로 둡니다. (`수정` Primary · `삭제` Gray)
75
+ - 삭제·취소 같은 부정적 액션을 Primary로 강조하지 않습니다.
76
+
77
+ ### 4-2. 나란히 배치할 때
78
+
79
+ - 여러 TextButton을 나란히 둘 때는 **Divider(1 × 16)** 로 구분하고, Divider 좌우에 **각각 12 간격**을 둡니다.
80
+ - 같은 묶음 안에서는 Size를 통일합니다.
81
+
82
+ ### 4-3. 클릭·터치 영역
83
+
84
+ 1. 텍스트 크기가 그대로 클릭 영역이므로 **모바일에서는 투명 여백을 더해 최소 44 × 44**를 확보합니다.
85
+ 2. 여백을 더해도 **텍스트의 정렬선은 유지**합니다. 좌측 정렬된 문단 안에서 들여쓰기가 생기면 안 됩니다.
86
+
87
+ ### 4-4. Overflow
88
+
89
+ 1. 라벨은 **1줄로 고정**하며 줄바꿈하지 않습니다.
90
+ 2. 너비를 초과하면 말줄임이 아니라 **라벨 자체를 짧게 고쳐 쓰는 것이 원칙**입니다.
91
+
92
+ ### 5. Do / Don't
93
+
94
+ **Do**
95
+
96
+ - 라벨은 동사 중심으로 짧게 작성합니다. (`수정`, `더보기`)
97
+ - 시각적 힌트가 필요한 경우에만 아이콘을 추가합니다.
98
+ - 같은 묶음의 TextButton은 Size와 정렬을 맞춥니다.
99
+ - 페이지 내 액션에는 Link 대신 TextButton을 사용합니다.
100
+
101
+ **Don't**
102
+
103
+ - 라벨 앞뒤에 아이콘을 동시에 넣지 않습니다.
104
+ - 본문 문장 중간에 끼워 넣지 않습니다. 그 경우는 Link입니다.
105
+ - 한 묶음에서 Primary를 두 개 이상 쓰지 않습니다.
106
+ - 밑줄을 기본 상태에 상시 적용하지 않습니다. 밑줄은 Hovered의 표현입니다.
107
+
108
+ ## C. Properties
109
+
110
+ Property 이름은 **소문자로 시작**하게 적었습니다. 피그마에만 있는 속성도 같은 방식으로 적고, 비고에 `피그마에만 존재`라고 표시했습니다.
111
+
112
+ | Property | Type | Values | 비고 |
113
+ | --- | --- | --- | --- |
114
+ | text | String | | 피그마 추가 |
115
+ | size | Variant | Small / Medium | 스토리북 `isTextSmall` → `size` 로 네이밍 통일 |
116
+ | isGray | Boolean | True / False | 피그마 수정 |
117
+ | state | Variant | Enabled / Hovered | 피그마에만 존재 |
118
+ | isUnderline | Boolean | True / False | 스토리북 수정 → `state`로 추가 (Hovered 상태) |
119
+ | disabled | Boolean | True / False | |
120
+ | leadingIcon | Instance | | 아이콘 교체가 필요하면 **Instance로 변경** (피그마 수정) |
121
+ | trailingIcon | Instance | | 아이콘 교체가 필요하면 **Instance로 변경** (피그마 수정) |
122
+
123
+
@@ -0,0 +1,101 @@
1
+ ---
2
+ id: INPUT-23
3
+ component: TextButtonDropdown
4
+ version: 0.0.2
5
+ status: draft
6
+ ---
7
+
8
+ # 23. TextButtonDropdown
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.10.02): 초안 작성
13
+ - v0.0.2 (2026.10.16): 목록에서 선택된 항목 표시를 코드에 맞춤 — 색만 바뀌고 굵기는 그대로 (#1299 리뷰 반영)
14
+
15
+ ## A. Anatomy
16
+
17
+ TextButtonDropdown은 **현재 선택값을 보여주는** **Text Button**과, 버튼을 누르면 그 아래 8px 간격으로 열리는 **List**로 구성됩니다.
18
+
19
+ | 요소 | 필수 여부 | 설명 |
20
+ | --- | --- | --- |
21
+ | Text Button | 필수 | 목록을 여는 버튼. 텍스트 + 우측 화살표, 사이 간격 8px (피그마 4px → 8px로 수정 필요) |
22
+ | Text | 필수 | **선택된 항목의 텍스트**가 그대로 표시됨. Body 16 Regular (피그마 Medium → Regular로 수정 필요) / `w-gray-600` |
23
+ | Arrow Icon | 필수 | `medium_arrow_down`(16). 목록이 열리면 위로 돌아감 |
24
+ | List | 조건부 | 버튼을 눌렀을 때만 표시. 최소 너비 160, 버튼 사이 간격 8px |
25
+ | List Item | 필수 | 목록의 선택지. 텍스트 + 선택적 Leading Icon(Medium 16) |
26
+
27
+ **상태별 표시**
28
+
29
+ | 상태 | 텍스트 · 아이콘 |
30
+ | --- | --- |
31
+ | 기본 | `w-gray-600` |
32
+ | 목록 열림 | `w-gray-600`, 화살표가 위로 |
33
+ | Disabled | `w-gray-300` |
34
+
35
+ 목록 항목의 선택·Hover 표시는 **List** 컴포넌트와 같습니다. (선택됨 = 텍스트 `primary-500`, 굵기는 그대로 Regular · Hover·키보드 포커스 = 배경 `primary-10`)
36
+
37
+ ## B. Description
38
+
39
+ ### 1. 정의
40
+
41
+ 버튼 클릭 시 리스트 형태의 옵션을 표시해 사용자가 원하는 항목을 선택할 수 있도록 돕는 컴포넌트입니다. 버튼에 **현재 선택값이 텍스트로 보여서**, 무엇이 적용돼 있는지 바로 알 수 있습니다.
42
+
43
+ ### 2. 사용 시점
44
+
45
+ - 목록 상단에서 **정렬 기준·보기 방식**을 바꿀 때 사용합니다. (`기본 정렬 순`, `금액 높은 순`)
46
+ - 항목을 고르면 **즉시 반영**되고 목록이 닫힙니다.
47
+ - 공간이 좁아 텍스트를 둘 수 없다면 **IconButtonDropdown**을 사용합니다.
48
+ - 폼에서 값을 고르게 한다면 **TextFieldDropdown**을 사용합니다.
49
+
50
+ **유형**
51
+
52
+ | 유형 | 설명 |
53
+ | --- | --- |
54
+ | **Left** | 목록의 왼쪽 끝을 버튼 왼쪽에 맞춥니다. 기본값. |
55
+ | **Right** | 목록의 오른쪽 끝을 버튼 오른쪽에 맞춥니다. 화면·카드 오른쪽 끝에 놓인 버튼에 써서 목록이 밖으로 잘리지 않게 합니다. |
56
+ | **Disabled** | 버튼을 눌러도 목록이 열리지 않고, 텍스트·아이콘이 `w-gray-300`으로 표시됩니다. 키보드(`Tab` · `Enter`)로도 열리지 않습니다. |
57
+
58
+ ### 3. 키워드
59
+
60
+ TextButtonDropdown, 텍스트 버튼 드롭다운, 드롭다운, Dropdown, 정렬, Sort
61
+
62
+ ### 4. Do / Don't
63
+
64
+ **Do**
65
+
66
+ - 항목 텍스트는 짧은 한 줄로 씁니다. 고른 텍스트가 그대로 버튼에 표시됩니다.
67
+ - 처음부터 기본값 하나를 선택해 둡니다. (`기본 정렬 순`)
68
+ - 버튼이 화면·카드의 오른쪽 끝에 있으면 `alignRight`를 씁니다.
69
+
70
+ **Don't**
71
+
72
+ - 항목을 너무 많이 넣지 않습니다. 목록에 높이 제한과 스크롤이 없어 항목 수만큼 길어집니다. (Z-2)
73
+ - 폼 값을 받는 데 쓰지 않습니다. 그 경우는 **TextFieldDropdown**입니다.
74
+ - 더보기·삭제 같은 동작 메뉴에 쓰지 않습니다. 버튼 텍스트가 고른 동작 이름으로 바뀝니다.
75
+
76
+ ## C. Properties
77
+
78
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`AlignRight` → `alignRight`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
79
+
80
+ | Property | Type | Values | 비고 |
81
+ | --- | --- | --- | --- |
82
+ | Items | Array | `{ key, value, leadingIcon? }` 목록 | **필수.** `value` = 항목 텍스트, `leadingIcon` = System Icon 이름 (Medium) |
83
+ | SelectedItem | Object | Items 중 하나 | **필수.** 이 항목의 텍스트가 버튼에 표시되고 목록에서 강조됨 · 피그마는 버튼 텍스트를 직접 입력(`텍스트 버튼`) |
84
+ | AlignRight | Boolean | True / False | 기본값 False(왼쪽 정렬). 피그마 `Variant` (Left / Right) · IconButtonDropdown은 `align = left / right` → 이름 다름 (Z-1) |
85
+ | Disabled | Boolean | True / False | 피그마 `Disabled` · 키보드로도 열리면 안 됨. **현재 코드는 Tab 포커스 후 `Enter`로 열림 → 수정 요청 필요** |
86
+ | OnItemClick | Function | | **필수.** 항목을 고를 때 호출 · 동작용 |
87
+ | State | Variant | Enabled / Focused | 피그마에만 존재. Focused = 목록이 열린 모습 · 코드는 클릭으로 자동 처리 |
88
+
89
+ > `ClassName` · `TestId`는 이 컴포넌트에 **없습니다.**
90
+ >
91
+ > ```tsx
92
+ > <TextButtonDropdown items={items} selectedItem={selected}
93
+ > onItemClick={setSelected} alignRight />
94
+ > ```
95
+
96
+ ## Z. 미결 (구현하지 말 것)
97
+
98
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
99
+
100
+ 1. **정렬 prop 이름**: 이 컴포넌트는 `alignRight`(Boolean), IconButtonDropdown은 `align = left / right`, 피그마는 둘 다 `Variant = Left / Right`입니다 → 하나로 통일할지 검토 (코드 prop을 바꾸면 breaking change)
101
+ 2. **목록 최대 높이 지정 필요**: List 기본값(최대 240, 스크롤)을 이 컴포넌트가 끄고 있어 항목 수만큼 길어집니다. 최대 높이는 지정하기로 했고, 값(List 기본 240을 따를지 등)은 미정 (IconButtonDropdown과 같은 문제)