@wishket/design-system 3.6.0 → 3.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,74 @@
1
+ ---
2
+ id: INPUT-02
3
+ component: FilterList
4
+ version: 0.0.1
5
+ status: draft
6
+ ---
7
+
8
+ # 2. FilterList
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.22): 초안 작성
13
+
14
+ ## A. Anatomy
15
+
16
+ FilterList는 **Container** 안에 **Title**과 **Checkbox List**, 하단 **Button 영역(Reset / Apply)** 으로 구성됩니다. 필요에 따라 **Select All**, **View Only**를 추가합니다.
17
+
18
+ | 요소 | 필수 여부 | 설명 |
19
+ | --- | --- | --- |
20
+ | Container | 필수 | 배경·모서리·그림자를 담당하는 영역. 팝오버/드롭다운으로 띄우는 기준 |
21
+ | Title | 필수 | 필터 그룹의 이름. 무엇을 거르는지 알려줍니다 |
22
+ | Checkbox List | 필수 | 선택 가능한 필터 조건 목록 |
23
+ | View Only | 선택 | `선택한 카테고리만 보기`. 목록을 선택된 항목만으로 줄이는 보조 옵션 |
24
+ | Select All | 선택 | Title 우측의 `전체 선택` / `선택 해제` 토글 |
25
+ | Reset Button | 필수 | 선택을 초기 상태로 되돌립니다 |
26
+ | Apply Button | 필수 | 선택한 조건을 실제 결과에 반영합니다 |
27
+
28
+ ## B. Description
29
+
30
+ ### 1. 정의
31
+
32
+ 사용자가 여러 조건을 선택하거나 해제하여, 원하는 기준으로 필터링할 수 있도록 돕는 컴포넌트입니다.
33
+
34
+ ### 2. 사용 시점
35
+
36
+ - 조건을 **여러 개 동시에** 선택해야 할 때 사용합니다.
37
+ - 조건을 고르는 즉시 반영하지 않고 **Apply로 한 번에 적용**해야 할 때 사용합니다. (결과 재조회 비용이 클 때)
38
+ - 조건이 1개만 선택되는 단일 선택이라면 **Select**를 사용합니다.
39
+ - 조건 수가 적고(대략 5개 이하) 즉시 반영해도 된다면 **Chip / Tab**을 사용합니다.
40
+ - 조건을 텍스트로 검색해 찾아야 한다면 **Autocomplete**를 사용합니다.
41
+
42
+ ### 3. 키워드
43
+
44
+ FilterList, 필터, 필터링, 조건 선택, 다중 선택, Checkbox Filter, 필터 팝오버
45
+
46
+ ### 4. Size
47
+
48
+ - 기본 너비는 **360**입니다.
49
+ - 트리거(필터 버튼) 너비와 무관하게 **FilterList 자체 너비를 유지**합니다.
50
+ - 모바일에서는 바텀시트로 전환하고 화면 너비를 100% 채웁니다.
51
+
52
+ ### 5. Do / Don't
53
+
54
+ **Do**
55
+
56
+ - Title에는 필터 그룹의 이름을 명사로 적습니다. (`카테고리`, `근무 형태`)
57
+ - 선택 항목은 사용 빈도 또는 가나다순 등 **예측 가능한 순서**로 정렬합니다.
58
+ - Apply를 누르기 전까지 결과를 바꾸지 않습니다.
59
+ - Reset은 **초기 상태**로 되돌립니다. 전체 해제가 아닙니다. (기본 선택값이 있다면 그 값으로 복원)
60
+
61
+ **Don't**
62
+
63
+ - 체크할 때마다 결과를 즉시 갱신하지 않습니다. (즉시 반영이 목적이면 Chip을 사용)
64
+ - 조건이 2~3개뿐인데 FilterList를 쓰지 않습니다.
65
+ - Apply 버튼을 비활성화한 채로 두지 않습니다. 변경이 없으면 닫기로 동작시킵니다.
66
+ - Reset과 Apply의 위치를 바꾸지 않습니다. (좌 Reset · 우 Apply 고정)
67
+
68
+ ## C. Properties
69
+
70
+ | Property | Type | Values | 비고 |
71
+ | --- | --- | --- | --- |
72
+ | Variant | Text | Label | 피그마 삭제 |
73
+ | **isAllSelected** | Boolean | True / False | 피그마 수정 |
74
+ | **isViewOnly** | Boolean | True / False | 피그마 수정 |
@@ -0,0 +1,89 @@
1
+ ---
2
+ id: INPUT-07
3
+ component: IconButton
4
+ version: 0.0.3
5
+ status: draft
6
+ ---
7
+
8
+ # 7. IconButton
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.22): 초안 작성
13
+ - v0.0.2 (2026.09.30): New Badge 색상을 토큰명으로 표기 (#1293 리뷰 반영)
14
+ - v0.0.3 (2026.10.02): Properties를 코드(`IconButtonProps`)와 일치시킴 — `Outlined` → `outline`, Icon 행 제거(children 사용), Disabled 추가 (#1292 리뷰 반영)
15
+
16
+ ## A. Anatomy
17
+
18
+ IconButton은 **Icon**을 감싸는 **Container**로 구성되며, 선택적으로 **New Badge**를 가집니다.
19
+
20
+ | 요소 | 필수 여부 | 설명 |
21
+ | --- | --- | --- |
22
+ | Container | 필수 | 배경·테두리·모서리를 담당하는 영역. 터치/클릭 영역의 기준 |
23
+ | Icon | 필수 | 액션을 의미하는 아이콘. 라벨이 없으므로 의미를 단독으로 전달해야 함 |
24
+ | New Badge | 선택 | 우측 상단의 점 표시. 확인하지 않은 변화가 있음을 알림 |
25
+
26
+ ## B. Description
27
+
28
+ ### 1. 정의
29
+
30
+ 사용자가 아이콘만으로 기능을 확인할 수 있으며, 직관적이고 빠른 인터랙션을 제공하는 컴포넌트입니다.
31
+
32
+ ### 2. 사용 시점
33
+
34
+ - 아이콘만으로 **의미가 분명하게 통하는 액션**일 때 사용합니다. (좋아요, 닫기, 공유, 더보기)
35
+ - 공간이 좁아 라벨을 넣을 수 없는 자리에 사용합니다. (툴바, 카드 우측 상단, 테이블 행, 모달 닫기)
36
+ - 의미가 아이콘만으로 통하지 않으면 **Button(Leading Icon 포함)** 을 사용합니다.
37
+ - 화면의 주요 액션(Primary)에는 사용하지 않습니다. 라벨이 있는 Button을 사용합니다.
38
+ - 의미가 즉시 통하지 않는 아이콘에는 **Tooltip을 반드시 함께** 제공합니다.
39
+
40
+ | Variant | 형태 | 사용 상황 |
41
+ | --- | --- | --- |
42
+ | **Outlined** | 흰 배경 + 1px 테두리 | 버튼임을 분명히 알려야 할 때. 카드·리스트 위의 독립 액션 |
43
+ | **Filled** | 배경·테두리 없이 아이콘만 | 이미 버튼임이 문맥으로 드러날 때. 툴바, 모달 닫기 |
44
+
45
+ ### 3. 키워드
46
+
47
+ IconButton, 아이콘 버튼, 아이콘, Icon, 뱃지, Badge, Icon Only
48
+
49
+ ### 4. Size
50
+
51
+ - Container는 **항상 정사각형**입니다. 아이콘 길이에 따라 너비가 달라지지 않습니다.
52
+ - New Badge는 **4 × 4**, `w-orange-500` 입니다.
53
+
54
+ ### 5. Do / Don't
55
+
56
+ **Do**
57
+
58
+ - 보편적으로 통용되는 아이콘만 사용합니다. (× 닫기, ⋯ 더보기, ♡ 좋아요)
59
+ - 한 화면에서 같은 아이콘은 **항상 같은 동작**을 하게 합니다.
60
+ - 대체 텍스트를 반드시 제공합니다.
61
+ - 나란히 놓이는 IconButton은 동일한 Size·Variant로 맞춥니다.
62
+ - IconButton과 Plain Tooltip을 함께 사용하는 경우, 시각적 조화를 위해 **상·하·좌·우 8 간격으로 정렬**하여 배치합니다.
63
+
64
+ **Don't**
65
+
66
+ - 의미가 모호한 아이콘을 라벨 없이 쓰지 않습니다.
67
+ - New Badge를 장식이나 강조 용도로 쓰지 않습니다. **확인하지 않은 변화**가 있을 때만 사용합니다.
68
+ - 아이콘 안에 텍스트를 넣지 않습니다.
69
+ - Container를 직사각형으로 늘리지 않습니다.
70
+
71
+ ## C. Properties
72
+
73
+ 표의 이름이 코드와 다르면 비고에 코드 이름을 적었습니다.
74
+
75
+ | Property | Type | Values | 비고 |
76
+ | --- | --- | --- | --- |
77
+ | Size | Variant | `sm` / `md` / `lg` | 코드 `size` (24 / 36 / 50) · 피그마 Small / Medium / Large 로 수정 |
78
+ | Outline | Boolean | True / False | 코드 **`outline`** (`Outlined` 아님) · 피그마 수정 |
79
+ | HasNew | Boolean | True / False | 코드 `hasNew`. New Badge 표시 · 피그마 이름 **New Badge** 와 통일 필요 |
80
+ | Disabled | Boolean | True / False | 코드 `disabled` |
81
+ | State | Variant | Enabled / Hovered / Pressed / Disabled | 피그마에만 존재. Hovered·Pressed는 마우스 동작으로 자동 처리 |
82
+
83
+ > **아이콘은 prop이 아닙니다.** `icon` 같은 prop은 코드에 없습니다. 아이콘은 **children으로** 넣습니다.
84
+ >
85
+ > ```tsx
86
+ > <IconButton size="md" outline aria-label="닫기">
87
+ > <SystemIcon name="medium_delete" />
88
+ > </IconButton>
89
+ > ```
@@ -0,0 +1,94 @@
1
+ ---
2
+ id: INPUT-15
3
+ component: InputChip
4
+ version: 0.0.3
5
+ status: draft
6
+ ---
7
+
8
+ # 15. InputChip
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.23): 초안 작성
13
+ - v0.0.2 (2026.10.01): 프론트매터 추가, Properties를 코드(`InputChipProps`)·스토리북 기준으로 정리, Size(높이 24·최대 너비·말줄임, 피그마 Hug/Fixed 대응) 추가, Chip 3종 비교표의 FilterChip 선택 상태 정정, 미결 항목을 `Z. 미결`로 분리
14
+ - v0.0.3 (2026.10.02): Properties 안내 문구 추가, `DeleteLabel` 기본값 예외(문자가 아닐 때 `"삭제"`) 명시, `className` 추가 (#1295 리뷰 반영)
15
+
16
+ ## A. Anatomy
17
+
18
+ InputChip은 **Container**와 **Text**, **Delete**로 구성됩니다.
19
+
20
+ | 요소 | 필수 여부 | 설명 |
21
+ | --- | --- | --- |
22
+ | Container | 필수 | 배경·모서리를 담당하는 영역 |
23
+ | Text | 필수 | 사용자가 입력하거나 선택한 값 |
24
+ | Delete | 조건부 | 값을 제거하는 × 아이콘. 삭제 동작(`onDelete`)을 연결했을 때만 나타납니다 |
25
+
26
+ ## B. Description
27
+
28
+ ### 1. 정의
29
+
30
+ 사용자가 직접 입력한 텍스트 값이 텍스트로 표시되며, 필요 시 삭제 버튼을 통해 제거할 수 있는 컴포넌트입니다.
31
+
32
+ ### 2. 사용 시점
33
+
34
+ - 사용자가 **입력하거나 선택한 값이 누적**될 때, 그 값을 하나씩 보여주기 위해 사용합니다.
35
+ - 각 값을 **개별적으로 지울 수 있어야** 할 때 사용합니다.
36
+ - **Autocomplete의 입력 필드 안**에서 선택된 항목을 표시하는 용도가 대표적입니다.
37
+ - 선택지를 **고르게 하는 것**이 목적이라면 **ChoiceChip**을 사용합니다. InputChip은 이미 정해진 값을 보여줄 뿐 선택 기능이 없습니다.
38
+ - 지울 수 없는 읽기 전용 표시라면 **Badge / Label**을 사용합니다.
39
+ - InputChip은 세 Chip 중 **가장 낮은 시각 위계**를 가집니다. 값을 보여주는 것이 목적이지 누르라고 있는 요소가 아닙니다.
40
+
41
+ **Chip 3종 비교**
42
+
43
+ | | InputChip | ChoiceChip | FilterChip |
44
+ | --- | --- | --- | --- |
45
+ | 역할 | 입력·선택된 값 **표시** | 선택지 **고르기** | 필터 목록 **열기** |
46
+ | 상호작용 | 삭제만 | 선택 / 해제 | 클릭 시 FilterList |
47
+ | 선택 상태 | 없음 | 있음 (`checked`) | 있음 (`badgeCount`가 0보다 클 때) |
48
+ | 높이 | 24 (Z-2) | 40 | 40 |
49
+
50
+ ### 3. 키워드
51
+
52
+ InputChip, 인풋칩, 칩, Chip, 태그, 입력값, 선택값, 삭제
53
+
54
+ ### 4. Size
55
+
56
+ - 높이는 **24**입니다.
57
+ - 너비는 **콘텐츠에 맞춰 늘어나며(Hug), 최대 100**입니다.
58
+ - 최대 너비를 넘는 값은 **너비 100에 고정(Fixed)** 되고 **1줄로 말줄임(`…`)** 처리합니다. 줄바꿈하지 않습니다.
59
+
60
+ > 피그마의 `Variant = Hug / Fixed`는 코드에 따로 넣는 값이 없습니다. 값이 짧으면 Hug, 100을 넘으면 Fixed가 **자동으로** 됩니다.
61
+
62
+ ### 5. Do / Don't
63
+
64
+ **Do**
65
+
66
+ - 값은 사용자가 **입력·선택한 그대로** 보여줍니다. 임의로 줄이거나 바꾸지 않습니다. (최대 너비를 넘을 때의 말줄임은 예외)
67
+ - 삭제할 수 있는 칩이라면 삭제 아이콘을 **항상 노출**합니다. Hover에만 보이게 하지 않습니다.
68
+
69
+ **Don't**
70
+
71
+ - Chip 안에 두 개 이상의 액션을 넣지 않습니다.
72
+
73
+ ## C. Properties
74
+
75
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`OnDelete` → `onDelete`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
76
+
77
+ | Property | Type | Values | 비고 |
78
+ | --- | --- | --- | --- |
79
+ | Children | ReactNode | | 칩에 표시할 값 · 피그마 `Label` → `Children`으로 이름 통일 |
80
+ | OnDelete | Function | | 연결하면 Delete(×) 아이콘이 나타납니다. 없으면 삭제 아이콘 없는 칩 |
81
+ | DeleteLabel | String | | 삭제 버튼을 스크린리더가 읽는 이름. 비우면 `Children`이 **문자·숫자일 때** `"{값} 삭제"`, **그 외(아이콘 등 요소)일 때** `"삭제"` · 코드에만 존재(시각 변화 없음) |
82
+ | DeleteButtonProps | Object | | 여러 칩을 방향키로 이동하게 만들 때 쓰는 개발용 값 · 코드에만 존재 |
83
+ | ClassName | String | | 개발용 스타일 지정 |
84
+
85
+ > ```tsx
86
+ > <InputChip onDelete={() => remove('React')}>React</InputChip>
87
+ > ```
88
+
89
+ ## Z. 미결 (구현하지 말 것)
90
+
91
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
92
+
93
+ 1. **Hovered 상태**: 피그마·코드 모두 없습니다(초안 비고 "스토리북 추가 / 피그마에 없음"). 추가할지 검토
94
+ 2. **높이 26 vs 24 (피그마 수정)**: 피그마 Input Chip은 높이 **26**, 코드는 **24**(`h-6`)입니다. 이 레포는 코드가 기준이라 문서는 24로 적었습니다. 피그마를 24로 맞출지, 26이 의도라면 디자인 변경 요청 이슈로 코드를 바꿀지 결정
@@ -0,0 +1,103 @@
1
+ ---
2
+ id: INPUT-03
3
+ component: List
4
+ version: 0.0.2
5
+ status: draft
6
+ ---
7
+
8
+ # 3. List
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.22): 초안 작성
13
+ - v0.0.2 (2026.10.02): Properties를 코드(`ListRootProps` · `ListItemProps`)와 일치시킴 — Root / Item 표 분리, `LeadingIcon` 타입 정정, `Checked` → `selected`, `text` · `canceled` · `isFocused` 추가, FilterList 속성(`isAllSelected` · `isViewOnly`) 제거 (#1292 리뷰 반영)
14
+
15
+ ## A. Anatomy
16
+
17
+ List는 **Item**을 담는 **Container**로 구성되며, 목록이 길어질 때 **Scrollbar**를 함께 사용합니다.
18
+
19
+ | 요소 | 필수 여부 | 설명 |
20
+ | --- | --- | --- |
21
+ | Container | 필수 | 배경·모서리·그림자를 담당하는 영역. 항목을 담는 기준 |
22
+ | Item | 필수 | 선택 가능한 개별 항목. Leading Icon과 Label로 구성 |
23
+ | Scrollbar | 선택 | Scrollable 유형에서 현재 위치를 알려주는 표시 |
24
+
25
+ ## B. Description
26
+
27
+ ### 1. 정의
28
+
29
+ 여러 항목을 일관된 구조로 정렬하여, 정보를 효율적으로 탐색하고 선택할 수 있도록 돕는 컴포넌트입니다.
30
+
31
+ ### 2. 사용 시점
32
+
33
+ - 같은 성격의 항목을 **동일한 구조로 나열**하고, 그중 하나를 고르게 할 때 사용합니다.
34
+ - 항목 수가 정해져 있고 전부 보여줘도 될 때는 **Fixed**, 항목이 많아 영역을 넘길 때는 **Scrollable**을 사용합니다.
35
+ - 조건을 여러 개 동시에 켜고 꺼야 한다면 **FilterList**를 사용합니다.
36
+
37
+ ### 3. 키워드
38
+
39
+ List, 리스트, 목록, 항목 목록, Option List, 선택 목록, Menu List
40
+
41
+ ### 4. Size
42
+
43
+ ### 4-1. Width
44
+
45
+ - List는 **부모 컨테이너 너비를 100% 채웁니다.**
46
+ - Item도 Container 너비를 채우며, 개별 항목의 길이에 따라 너비가 달라지지 않습니다.
47
+
48
+ ### 4-2. Overflow (라벨이 넘칠 때)
49
+
50
+ 1. Item 라벨은 **1줄로 고정**하고 넘치면 말줄임(`…`) 처리합니다.
51
+ 2. 말줄임된 항목은 **툴팁으로 전체 문구**를 제공합니다.
52
+ 3. 항목 이름이 구조적으로 길 수밖에 없다면(경로·주소 등) 말줄임 대신 List 너비를 넓히는 것을 먼저 검토합니다.
53
+
54
+ ### 5. Do / Don't
55
+
56
+ **Do**
57
+
58
+ - 항목은 가나다순·사용 빈도 등 **예측 가능한 순서**로 정렬합니다.
59
+ - Leading Icon은 항목의 **성격을 구분해야 할 때만** 사용하고, 쓸 경우 모든 항목에 동일하게 적용합니다.
60
+ - 선택된 항목(Checked)은 목록을 닫은 뒤에도 알아볼 수 있게 유지합니다.
61
+ - 선택 불가한 항목은 숨기지 말고 **Disabled로 남겨** 왜 고를 수 없는지 알 수 있게 합니다.
62
+
63
+ **Don't**
64
+
65
+ - 한 목록 안에서 아이콘이 있는 항목과 없는 항목을 섞지 않습니다.
66
+ - Item 안에 버튼·체크박스 등 별도 조작 요소를 넣지 않습니다.
67
+ - 항목 라벨을 2줄로 표시하지 않습니다.
68
+ - 항목이 3개 이하인데 Scrollable을 쓰지 않습니다.
69
+
70
+ ## C. Properties
71
+
72
+ List는 **`List.Root`(목록 컨테이너)** 와 **`List.Item`(항목)** 두 부분으로 씁니다. 표의 이름이 코드와 다르면 비고에 코드 이름을 적었습니다.
73
+
74
+ ### C-1. List.Root
75
+
76
+ | Property | Type | Values | 비고 |
77
+ | --- | --- | --- | --- |
78
+ | DisableScroll | Boolean | True / False | 코드 `disableScroll`. True면 Fixed(스크롤 없음), False면 Scrollable · 피그마 `Variant = Scrollable / Fixed`에 해당 → Boolean으로 피그마 수정 |
79
+
80
+ ### C-2. List.Item
81
+
82
+ | Property | Type | Values | 비고 |
83
+ | --- | --- | --- | --- |
84
+ | Text | String | | 코드 `text`. 항목 라벨 · 피그마 추가 |
85
+ | LeadingIcon | Instance | System Icon 이름 | 코드 `leadingIcon`. 켜고 끄는 값이 아니라 **아이콘 이름**을 넣습니다 |
86
+ | Selected | Boolean | True / False | 코드 `selected`. 선택된 항목 · 피그마 `Checked` → `Selected`로 수정 |
87
+ | Disabled | Boolean | True / False | 코드 `disabled` |
88
+ | Canceled | Boolean | True / False | 코드 `canceled`. 텍스트가 Red로 바뀜 · 피그마 `Errored`에 해당하는 것으로 보임 (Z-1) |
89
+ | IsFocused | Boolean | True / False | 코드 `isFocused`. 키보드 등으로 지목된 항목에 연한 Primary 배경 · 코드에만 존재 |
90
+ | State | Variant | Enabled / Hovered | 피그마에만 존재. Hovered는 마우스 hover로 자동 처리 |
91
+
92
+ > ```tsx
93
+ > <List.Root>
94
+ > <List.Item text="최신순" leadingIcon="medium_check" selected />
95
+ > <List.Item text="인기순" />
96
+ > </List.Root>
97
+ > ```
98
+
99
+ ## Z. 미결 (구현하지 말 것)
100
+
101
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
102
+
103
+ 1. **피그마 `Errored`와 코드 `canceled`**: 둘 다 텍스트를 Red로 표시하는 상태로 보입니다. 같은 것이라면 이름을 하나로 맞출지 결정
@@ -0,0 +1,86 @@
1
+ ---
2
+ id: INPUT-04
3
+ component: MultiColumnList
4
+ version: 0.0.1
5
+ status: draft
6
+ ---
7
+
8
+ # 4. MultiColumnList
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.22): 초안 작성
13
+
14
+ ## A. Anatomy
15
+
16
+ MultiColumnList는 하나의 **Container** 안에 두 개의 컬럼을 Divider로 나눠 배치합니다. 왼쪽은 대분류를 고르는 **Item** 목록, 오른쪽은 선택된 대분류에 속한 **Radio List**입니다.
17
+
18
+ | 요소 | 필수 여부 | 설명 |
19
+ | --- | --- | --- |
20
+ | Container | 필수 | 테두리·모서리를 담당하는 영역. 두 컬럼을 감싸는 기준 |
21
+ | Item | 필수 | 왼쪽 컬럼의 대분류 항목. 선택하면 오른쪽 컬럼의 내용이 바뀝니다 |
22
+ | Divider | 필수 | 두 컬럼을 나누는 세로 구분선 |
23
+ | Title | 조건부 | 오른쪽 컬럼에서 항목을 묶는 그룹명. `Recommend` 유형에서만 사용 |
24
+ | Radio List | 필수 | 오른쪽 컬럼의 최종 선택 항목. 단일 선택 |
25
+ | Scrollbar | 선택 | 각 컬럼의 스크롤 위치 표시. 컬럼마다 독립적으로 동작 |
26
+
27
+ > 왼쪽 컬럼의 Item은 **List 문서의 Item과 동일한 컴포넌트**이며, `Leading Icon = False`로 사용합니다.
28
+ >
29
+
30
+ ## B. Description
31
+
32
+ ### 1. 정의
33
+
34
+ 계층형 데이터나 복잡한 카테고리 구조를 리스트 형태로 표시하여 탐색과 선택을 지원하는 컴포넌트입니다.
35
+
36
+ ### 2. 사용 시점
37
+
38
+ - 선택지가 **2단계 계층**으로 나뉘고, 대분류를 고른 뒤 그 안에서 하나를 고르게 할 때 사용합니다.
39
+ - 소분류 항목이 많아 한 번에 나열하면 훑기 어려울 때 사용합니다.
40
+ - 계층이 없는 단일 목록이라면 **List**를 사용합니다.
41
+ - 조건을 여러 개 동시에 선택해야 한다면 **FilterList**를 사용합니다.
42
+
43
+ ### 3. 키워드
44
+
45
+ MultiColumnList, 멀티컬럼, 2단 리스트, 계층 선택, 카테고리 선택, 대분류·소분류, Miller Column
46
+
47
+ ### 4. Do / Don't
48
+
49
+ **Do**
50
+
51
+ - 왼쪽 컬럼에는 **항상 하나의 항목이 선택되어 있게** 합니다. 처음 열릴 때는 첫 번째 항목을 선택합니다.
52
+ - 오른쪽 컬럼에서 선택한 값이 바뀌어도 왼쪽 선택은 유지합니다.
53
+ - 왼쪽 대분류 이름은 짧은 명사로 통일합니다.
54
+ - 선택 불가한 항목은 숨기지 말고 Disabled로 남깁니다.
55
+
56
+ **Don't**
57
+
58
+ - 오른쪽 컬럼에서 여러 개를 선택하게 하지 않습니다. (다중 선택이 필요하면 FilterList)
59
+ - 왼쪽 항목을 클릭했을 때 오른쪽이 비어 있게 두지 않습니다.
60
+ - 컬럼을 3개 이상으로 늘리지 않습니다.
61
+
62
+ ## C. Properties
63
+
64
+ | Property | Type | Values | 비고 |
65
+ | --- | --- | --- | --- |
66
+ | Variant | Variant | Recommend/General ↔ Default/WithRecommendations | 피그마 수정 or 스토리북 수정 |
67
+ | Scrollbar | Boolean | True / False | |
68
+
69
+ ### Item (왼쪽 컬럼)
70
+
71
+ | Property | Type | Values | 비고 |
72
+ | --- | --- | --- | --- |
73
+ | Checked | Boolean | True / False | 피그마 `Checked` → **`Selected`** 로 수정 |
74
+ | Disabled | Boolean | True / False | |
75
+ | State | Variant | Enabled / Hovered | |
76
+ | Leading Icon | Boolean | True / False | MultiColumnList에서는 False 고정 |
77
+
78
+ ### Radio List (오른쪽 컬럼)
79
+
80
+ | Property | Type | Values | 비고 |
81
+ | --- | --- | --- | --- |
82
+ | Checked | Boolean | True / False | |
83
+ | Disabled | Boolean | True / False | |
84
+ | State | Variant | Enabled | |
85
+ | Is Error | Boolean | True / False | MultiColumnList에서는 미사용 |
86
+ | Title | Boolean | True / False | 그룹 타이틀 노출 여부 · 피그마 추가 |
@@ -0,0 +1,116 @@
1
+ ---
2
+ id: INPUT-17
3
+ component: SearchField
4
+ version: 0.0.3
5
+ status: draft
6
+ ---
7
+
8
+ # 17. SearchField
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.28): 초안 작성
13
+ - v0.0.2 (2026.10.01): 프론트매터 추가, Properties를 코드(`SearchFieldProps`)·스토리북 기준으로 정리, 피그마 ↔ 코드 상태 대응표·Size 추가, 미결 항목을 `Z. 미결`로 분리
14
+ - v0.0.3 (2026.10.02): Properties 안내 문구 통일, `value` · `onChange` · `className` 추가, `Filters` 안의 `alignRight` 명시, 형식 정리 (#1295 리뷰 반영)
15
+
16
+ ## A. Anatomy
17
+
18
+ SearchField는 **Container** 안에 검색어를 입력하는 **Text**와 우측의 **Search Icon**으로 구성되며, 좌측에 검색 범위를 고르는 **Text Button Dropdown**을 둘 수 있습니다.
19
+
20
+ | 요소 | 필수 여부 | 설명 |
21
+ | --- | --- | --- |
22
+ | Container | 필수 | 배경·테두리·패딩을 담당하는 영역. 클릭/포커스 영역의 기준 |
23
+ | Text Button Dropdown | 선택 | 좌측에서 **검색 범위·조건**을 고르는 드롭다운 |
24
+ | Placeholder / Text | 필수 | 입력 전에는 Placeholder, 입력 중에는 검색어 |
25
+ | Search Icon | 필수 | 우측의 돋보기 아이콘. 검색 실행. **Enter 키로도 실행**됩니다 |
26
+
27
+ ## B. Description
28
+
29
+ ### 1. 정의
30
+
31
+ 사용자가 원하는 특정 항목을 찾아야 할 때 사용합니다.
32
+
33
+ ### 2. 사용 시점
34
+
35
+ - 목록이나 페이지에서 **검색어로 결과를 좁힐 때** 사용합니다.
36
+ - 검색 대상을 **범위별로 나눠야** 할 때 `Text Button Dropdown`을 함께 사용합니다. (`전체`, `프로젝트명`, `작성자`)
37
+ - 입력하는 동안 **제안 목록을 띄워 고르게** 하는 것이 목적이라면 **Autocomplete**를 사용합니다.
38
+ - 검색이 아니라 값을 입력받는 것이라면 **Input(Text Field)** 을 사용합니다.
39
+
40
+ ### 3. 키워드
41
+
42
+ SearchField, 검색, 검색창, 검색 필드, Search, 검색어 입력, 돋보기
43
+
44
+ ### 4. Size
45
+
46
+ - SearchField는 **부모 컨테이너 너비를 100% 채웁니다.** Figma의 `240`은 예시 값입니다.
47
+ - 높이는 **50**입니다.
48
+ - 검색어·Placeholder는 **1줄로 고정**합니다. 넘치면 줄바꿈하지 않고 가려집니다.
49
+
50
+ ### 5. Do / Don't
51
+
52
+ **Do**
53
+
54
+ - Placeholder에는 **무엇으로 검색할 수 있는지** 적습니다. (`프로젝트명으로 검색`)
55
+ - Dropdown 라벨은 현재 선택된 범위를 그대로 보여줍니다.
56
+ - 검색 결과가 없을 때의 안내를 함께 설계합니다.
57
+
58
+ **Don't**
59
+
60
+ - 검색어를 2줄로 표시하지 않습니다.
61
+ - Search Icon 자리에 다른 액션(초기화 등)을 겹쳐 넣지 않습니다.
62
+ - Dropdown 라벨을 문장으로 쓰지 않습니다.
63
+ - 입력할 때마다 결과 페이지로 이동시키지 않습니다.
64
+
65
+ ## C. Properties
66
+
67
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`OnSearch` → `onSearch`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
68
+
69
+ | Property | Type | Values | 비고 |
70
+ | --- | --- | --- | --- |
71
+ | OnSearch | Function | | **필수.** 검색 실행 동작(Search Icon 클릭 또는 Enter 시 호출) · 동작용, 시각 변화 없음 |
72
+ | Placeholder | String | | 입력 전 안내 문구. 피그마 `Variant = Placeholder`에 해당 |
73
+ | Value | String | | 입력한 검색어 |
74
+ | OnChange | Function | | 검색어가 바뀔 때 호출 · 동작용 |
75
+ | Disabled | Boolean | True / False | 입력·드롭다운·검색 모두 비활성. 피그마 `State = Disabled`에 해당 |
76
+ | Filters | Object | 아래 표 | **값을 넣으면 Text Button Dropdown이 나타납니다.** 켜고 끄는 Boolean이 아닙니다 · 피그마 `TextButtonDropdown`에 해당 (이름 변경 제안은 Z-4) |
77
+ | ClassName | String | | 개발용 스타일 지정 |
78
+
79
+ **`Filters` 안에 넣는 값**
80
+
81
+ | 값 | Type | 비고 |
82
+ | --- | --- | --- |
83
+ | Items | 항목 목록 | **필수.** 드롭다운 항목. 항목 하나는 `{ key, value }` (`value`가 화면에 보이는 글자) |
84
+ | SelectedItem | 항목 | **필수.** 지금 선택된 항목. 라벨에 이 값이 표시됩니다 |
85
+ | OnItemClick | Function | **필수.** 항목을 골랐을 때 호출 · 동작용 |
86
+ | AlignRight | Boolean | 드롭다운 목록을 **오른쪽 기준으로** 펼칩니다. 기본은 왼쪽 기준 |
87
+
88
+ **피그마 ↔ 코드 대응**
89
+
90
+ 피그마의 `Variant`와 `State`는 코드에 따로 넣는 값이 없고, **자동으로** 정해집니다.
91
+
92
+ | 피그마 | 코드 | 모습 |
93
+ | --- | --- | --- |
94
+ | `Variant = Empty` | 값·Placeholder 없음 | 빈 입력 영역 |
95
+ | `Variant = Placeholder` | `placeholder`만 있음 | 회색 안내 문구 |
96
+ | `Variant = Text` | 입력값 있음 | 검정 검색어 |
97
+ | `State = Enabled` | 기본 | 회색 테두리 |
98
+ | `State = Hovered` | 마우스 hover (자동) | Primary 테두리 |
99
+ | `State = Focused` | 입력 중 (자동) | Primary 테두리 |
100
+ | `State = Disabled` | `disabled` | 회색 배경, 글자·아이콘 흐리게 |
101
+
102
+ > ```tsx
103
+ > <SearchField placeholder="프로젝트명으로 검색" onSearch={search}
104
+ > value={keyword} onChange={e => setKeyword(e.target.value)}
105
+ > filters={{ items: [{ key: 'all', value: '전체' }, { key: 'title', value: '프로젝트명' }],
106
+ > selectedItem, onItemClick: setSelectedItem }} />
107
+ > ```
108
+
109
+ ## Z. 미결 (구현하지 말 것)
110
+
111
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
112
+
113
+ 1. **피그마 시안의 2줄 텍스트**: 드롭다운이 있는 변형에서 "플레이스 홀더"·"입력한 텍스트"가 2줄로 꺾여 있어, 이 문서의 Don't("검색어를 2줄로 표시하지 않습니다")와 어긋납니다. 피그마 텍스트를 1줄 고정으로 수정 필요
114
+ 2. **피그마 드롭다운 켜고 끄기**: 피그마 변형 12종이 모두 드롭다운이 있는 모습입니다. 드롭다운 없는 SearchField를 피그마에서 어떻게 표현하는지(Boolean 속성 유무) 확인 필요
115
+ 3. **스토리북 예시 (개발팀 전달)**: 스토리북 예시의 드롭다운 항목이 정렬 기준("기본 정렬 순", "금액 높은 순" …)이라 가이드(검색 범위: `전체`, `프로젝트명`, `작성자`)와 다릅니다. 또 `SearchField.tsx` 주석 예시가 `label` · `{ label, value }` 형태를 쓰는데 실제 타입은 `{ key, value }` · `selectedItem` · `onItemClick`입니다
116
+ 4. **`Filters` 이름 변경 제안**: 스토리북 `filters`와 피그마 `TextButtonDropdown`을 **`withFilter`** 로 통일하자는 제안. 코드 prop 이름을 바꾸는 일이라 개발팀과 결정 필요
@@ -0,0 +1,111 @@
1
+ ---
2
+ id: INPUT-08
3
+ component: TextButton
4
+ version: 0.0.1
5
+ status: draft
6
+ ---
7
+
8
+ # 8. TextButton
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.22): 초안 작성
13
+
14
+ ## A. Anatomy
15
+
16
+ TextButton은 **Text**로 구성되며, 선택적으로 **Leading Icon**과 **Trailing Icon**을 가집니다. 배경과 테두리가 없습니다.
17
+
18
+ | 요소 | 필수 여부 | 설명 |
19
+ | --- | --- | --- |
20
+ | Text | 필수 | 액션을 설명하는 텍스트. 이 컴포넌트의 클릭 영역 기준 |
21
+ | Leading Icon | 선택 | 텍스트 앞 아이콘. 액션의 **의미를 보조** |
22
+ | Trailing Icon | 선택 | 텍스트 뒤 아이콘. Chevron 등 **방향·이동을 보조** |
23
+
24
+ > Container가 없어 **텍스트 크기가 곧 클릭 영역**입니다. 별도의 패딩을 갖지 않습니다.
25
+ >
26
+
27
+ ## B. Description
28
+
29
+ ### 1. 정의
30
+
31
+ 클릭 시 이벤트가 발생하는 경우에 사용되는 컴포넌트로, 보조 액션 또는 행동 트리거에 적합한 텍스트형 버튼입니다.
32
+
33
+ ### 2. 사용 시점
34
+
35
+ - 부가적이지만 **강조가 필요한 행동**에 사용합니다. (`수정`, `삭제`, `더보기`)
36
+ - 페이지 내에서 액션이 일어나는 경우, **Link 대신** TextButton을 사용합니다. Link는 페이지 이동에만 씁니다.
37
+ - 화면의 주요 액션(Primary)에는 사용하지 않습니다. 배경이 있는 **Button**을 사용합니다.
38
+ - 테이블 행·카드 하단처럼 여러 액션을 좁은 공간에 나열해야 할 때 적합합니다.
39
+ - 아이콘만으로 의미가 통하고 공간이 없다면 **IconButton**을 사용합니다.
40
+ - 아이콘 색상은 텍스트 색상을 따릅니다.
41
+ - **밑줄은 텍스트에만** 적용하고 아이콘에는 적용하지 않습니다.
42
+ - Hovered에서 색상은 바뀌지 않습니다. 밑줄만 추가됩니다.
43
+
44
+ > TextButton은 Button보다 **낮은 시각 위계**를 가집니다. 한 화면에서 Button과 TextButton이 함께 있으면 Button이 주요 액션입니다.
45
+ >
46
+
47
+ ### 3. 키워드
48
+
49
+ TextButton, 텍스트버튼, 버튼, Btn, txt, 텍스트 링크, Primary Text Button
50
+
51
+ ### 4. Size
52
+
53
+ | Size | Font | Icon | Icon–Text Gap | 높이 |
54
+ | --- | --- | --- | --- | --- |
55
+ | **Small** | Body 14 / Medium (14 · line-height 24) | 14 | 2 | 24 |
56
+ | **Medium** | Body 16 / Medium (16 · line-height 26) | 16 | 4 | 26 |
57
+ - 두 Size 모두 텍스트 굵기는 **Medium**입니다. 본문과 구분되도록 하는 장치입니다.
58
+ - 주변 본문의 폰트 크기에 맞춰 Size를 고릅니다. 본문이 16이면 Medium, 14면 Small을 씁니다.
59
+
60
+ ### 4-1. Color
61
+
62
+ | Color | 사용 상황 |
63
+ | --- | --- |
64
+ | **Primary** | 주요 행동을 유도하는 경우 |
65
+ | **Gray** | 보조 행동 |
66
+ - 한 묶음 안에서 **주요 행동 하나만 Primary**로 두고 나머지는 Gray로 둡니다. (`수정` Primary · `삭제` Gray)
67
+ - 삭제·취소 같은 부정적 액션을 Primary로 강조하지 않습니다.
68
+
69
+ ### 4-2. 나란히 배치할 때
70
+
71
+ - 여러 TextButton을 나란히 둘 때는 **Divider(1 × 16)** 로 구분하고, Divider 좌우에 **각각 12 간격**을 둡니다.
72
+ - 같은 묶음 안에서는 Size를 통일합니다.
73
+
74
+ ### 4-3. 클릭·터치 영역
75
+
76
+ 1. 텍스트 크기가 그대로 클릭 영역이므로 **모바일에서는 투명 여백을 더해 최소 44 × 44**를 확보합니다.
77
+ 2. 여백을 더해도 **텍스트의 정렬선은 유지**합니다. 좌측 정렬된 문단 안에서 들여쓰기가 생기면 안 됩니다.
78
+
79
+ ### 4-4. Overflow
80
+
81
+ 1. 라벨은 **1줄로 고정**하며 줄바꿈하지 않습니다.
82
+ 2. 너비를 초과하면 말줄임이 아니라 **라벨 자체를 짧게 고쳐 쓰는 것이 원칙**입니다.
83
+
84
+ ### 5. Do / Don't
85
+
86
+ **Do**
87
+
88
+ - 라벨은 동사 중심으로 짧게 작성합니다. (`수정`, `더보기`)
89
+ - 시각적 힌트가 필요한 경우에만 아이콘을 추가합니다.
90
+ - 같은 묶음의 TextButton은 Size와 정렬을 맞춥니다.
91
+ - 페이지 내 액션에는 Link 대신 TextButton을 사용합니다.
92
+
93
+ **Don't**
94
+
95
+ - 라벨 앞뒤에 아이콘을 동시에 넣지 않습니다.
96
+ - 본문 문장 중간에 끼워 넣지 않습니다. 그 경우는 Link입니다.
97
+ - 한 묶음에서 Primary를 두 개 이상 쓰지 않습니다.
98
+ - 밑줄을 기본 상태에 상시 적용하지 않습니다. 밑줄은 Hovered의 표현입니다.
99
+
100
+ ## C. Properties
101
+
102
+ | Property | Type | Values | 비고 |
103
+ | --- | --- | --- | --- |
104
+ | Text | String | | 피그마 추가 |
105
+ | Size | Variant | Small / Medium | 스토리북 `IsTextSmall` → **`Size`** 로 네이밍 통일 |
106
+ | IsGray | Boolean | True / False | 피그마 수정 |
107
+ | State | Variant | Enabled / Hovered | **Pressed·Focused 추가 필요** |
108
+ | isUnderline | Boolean | True / False | 피그마 수정 or 스토리북 수정>State추가(Hovered상태) |
109
+ | Disabled | Boolean | True / False | |
110
+ | LeadingIcon | Instance | | 아이콘 교체가 필요하면 **Instance로 변경** (피그마 수정) |
111
+ | TrailingIcon | Instance | | 아이콘 교체가 필요하면 **Instance로 변경** (피그마 수정) |