@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,129 @@
1
+ ---
2
+ id: INPUT-18
3
+ component: TextField
4
+ version: 0.0.3
5
+ status: draft
6
+ figma.componentKey: b7abe3753ce5d9aa134c43fe28cd3c769b6f92b4
7
+ ---
8
+
9
+ # 18. TextField
10
+
11
+ **개정 이력**
12
+
13
+ - v0.0.1 (2026.09.28): 초안 작성
14
+ - v0.0.2 (2026.10.01): 프론트매터 추가, Properties를 코드(`TextFieldProps`)·스토리북 기준으로 정리, Error Text 위치 정정(Supporting Text와 별도 줄), Error Text·Supporting Text 동시 표시 규칙을 "함께 표시"로 변경(코드·피그마 기준), 여러 줄 입력 안내를 Textarea로 정정, "나중"을 `Z. 미결`로 분리
15
+ - v0.0.3 (2026.10.02): Properties 안내 문구 통일, `value` · `onChange` · `onBlur` · `name` · `className` · `testId` 추가 (#1295 리뷰 반영)
16
+
17
+ ## A. Anatomy
18
+
19
+ TextField는 **Container** 안에 입력 텍스트와 보조 요소들이 가로로 놓이고, 그 아래에 **Supporting Text** 줄이 붙는 구조입니다.
20
+
21
+ | 요소 | 필수 여부 | 설명 |
22
+ | --- | --- | --- |
23
+ | Container | 필수 | 배경·테두리·패딩을 담당. 클릭/포커스 영역의 기준 |
24
+ | Label | 조건부 | `variant = label`일 때 필드 **안쪽 상단**에 얹히는 항목명 |
25
+ | Placeholder / Text | 필수 | 입력 전에는 Placeholder, 입력 중에는 입력값 |
26
+ | Leading Icon | 선택 | 입력값 앞 아이콘 |
27
+ | Measure (단위) | 선택 | 입력값 뒤에 붙는 **단위 텍스트** (`원`, `명`) |
28
+ | Trailing Icon | 선택 | 우측 아이콘. 안내·비밀번호 보기 등 |
29
+ | Error Text | 조건부 | 오류 문구. 필드 하단, **Supporting Text 위에 별도 줄**로 표시 |
30
+ | Supporting Text | 선택 | 필드 하단 좌측의 도움말 |
31
+ | Max Length | 선택 | 필드 하단 우측의 글자 수 (`0/20`) |
32
+
33
+ ## B. Description
34
+
35
+ ### 1. 정의
36
+
37
+ 사용자가 텍스트 입력 및 확인 시 사용되는 컴포넌트입니다.
38
+
39
+ ### 2. 사용 시점
40
+
41
+ - 사용자가 **자유롭게 값을 입력**해야 할 때 사용합니다. (이름, 금액, 메모)
42
+ - 항목이 여러 개인 폼에서 **어떤 값을 넣는 칸인지 계속 보여야** 한다면 `variant = label`을 사용합니다.
43
+ - 항목명이 필드 바깥에 이미 있다면 `variant = default`로 사용합니다.
44
+ - 타이핑이 아니라 **클릭해서 모달·패널을 여는 필드**라면 **TextFieldTrigger**를 사용합니다.
45
+ - 입력하는 동안 제안 목록을 띄워 고르게 한다면 **Autocomplete**를 사용합니다.
46
+ - 검색어를 입력해 결과를 찾는 것이라면 **SearchField**를 사용합니다.
47
+ - 여러 줄을 입력받아야 한다면 **Textarea**를 사용합니다. (댓글·답글 작성은 **CommentArea**)
48
+
49
+ **유형**
50
+
51
+ | 유형 | 설명 |
52
+ | --- | --- |
53
+ | **Default** | 가장 기본적인 TextField입니다. Placeholder를 통해 입력 힌트를 제공하며, 간단한 텍스트 입력에 적합합니다. |
54
+ | **Fixed Label** | 고정 라벨이 있는 TextField입니다. **Placeholder가 있을 때** 라벨이 위쪽에 고정되어 표시됩니다. 라벨과 Placeholder를 모두 표시하여 명확한 안내가 필요한 경우에 사용하세요. |
55
+ | **Label** | 라벨이 플로팅되는 TextField입니다. **Placeholder가 없을 때** 라벨이 입력 필드 안에 위치하다가, 입력을 시작하면 위로 이동하여 애니메이션 효과를 제공합니다. |
56
+ | **Error State** | 에러 메시지를 표시하여 사용자에게 오류를 알립니다. |
57
+ | **Disabled** | 사용자가 입력할 수 없는 상태입니다. |
58
+
59
+ > Fixed Label과 Label은 별도 값이 아니라 **`variant = label` + Placeholder 유무**로 자동으로 갈립니다.
60
+
61
+ ### 3. 키워드
62
+
63
+ TextField, 텍스트 필드, 입력, 입력창, Input, 폼, 레이블, Label, 플로팅 라벨
64
+
65
+ ### 4. 에러 문구
66
+
67
+ - 에러 텍스트는 **`하세요`로 끝맺습니다.** (`이메일 형식을 확인하세요`)
68
+ - 무엇이 잘못됐는지가 아니라 **무엇을 하면 되는지**를 적습니다.
69
+ - 행동 지시형으로 간결하게 작성합니다. (`휴대폰 번호 10-11자리로 입력해 주세요`)
70
+
71
+ ### 5. Do / Don't
72
+
73
+ **Do**
74
+
75
+ - Placeholder에는 **입력 형식의 예시**를 적습니다. (`010-0000-0000`)
76
+ - Supporting Text는 **최대 2줄**까지만 보이게 하고, 더 긴 메시지는 말줄임(`…`)으로 축약합니다. Error Text도 같습니다.
77
+ - 한 폼 안에서 Text Field와 Label Text Field를 섞지 않습니다.
78
+ - **Min + Max 모두 있는 경우**: 서포팅 텍스트에는 최소 글자 수, 입력 제한에는 최대 글자 수를 표시합니다.
79
+ - **Max 값만 있는 경우**: 서포팅 텍스트와 입력 제한 모두 동일하게 표시합니다.
80
+ - **Min 값만 있는 경우**: 서포팅 텍스트에 최소 글자 수를 표시합니다.
81
+ - **Error Text와 Supporting Text가 동시에 있으면 둘 다 표시합니다.** Error Text를 위에, Supporting Text를 아래에 둡니다. 오류가 났다고 도움말을 지우지 않습니다.
82
+
83
+ **Don't**
84
+
85
+ - Leading Icon과 Measure를 동시에 쓰지 않습니다.
86
+ - Placeholder를 항목명 대신 쓰지 않습니다. 입력을 시작하면 사라집니다.
87
+ - 입력값을 2줄로 표시하지 않습니다.
88
+ - `type = password`에 Trailing Icon을 추가하지 않습니다. 비밀번호 보기(눈 아이콘)가 자동으로 붙습니다.
89
+
90
+ ## C. Properties
91
+
92
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`IsError` → `isError`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 쪽 상태를 함께 적었습니다.
93
+
94
+ | Property | Type | Values | 비고 |
95
+ | --- | --- | --- | --- |
96
+ | Variant | Variant | `default` / `label` | 피그마는 **별도 컴포넌트 2개**(Text Field / Label Text Field)로 나뉘어 있음 (Z-1) |
97
+ | Type | Variant | `text` / `password` / `email` / `number` | 피그마에 없음 · 추가 필요 |
98
+ | Placeholder | String | | 피그마 추가 |
99
+ | Label | String | | `variant = label`일 때 사용 |
100
+ | Disabled | Boolean | True / False | 피그마 Label Text Field는 **State의 값**으로 되어 있음 → Boolean으로 통일 |
101
+ | IsError | Boolean | True / False | 오류 테두리. 피그마 `Is Error` |
102
+ | ErrorMessage | String | | 오류 문구. 필드 하단 Supporting Text **위**에 표시 |
103
+ | SupportMessage | String | | 도움말 문구 · 피그마 `Supporting Text`(Boolean) → 이름·타입 통일 필요 |
104
+ | MaxLength | Number | | 값을 넣으면 하단 우측에 글자 수(`0/20`) 표시 · 피그마는 Boolean → 숫자로 변경 필요 |
105
+ | Measure | String | | 단위 텍스트(`원`, `명`) · 피그마 `Caret` → **`Measure`로 개명 필요** |
106
+ | LeadingIcon | Instance | System Icon 이름 (Medium) | 피그마는 Boolean → Instance로 변경 필요 |
107
+ | TrailingIcon | Instance | System Icon 이름 (Medium) | 피그마는 Boolean → Instance로 변경 필요 |
108
+ | Value | String | | 입력값 |
109
+ | OnChange | Function | | 입력값이 바뀔 때 호출 · 동작용 |
110
+ | OnBlur | Function | | 입력 칸에서 벗어날 때 호출 · 동작용 |
111
+ | Name | String | | 폼 전송용 이름 · 개발용 |
112
+ | ClassName | String | | 개발용 스타일 지정 |
113
+ | TestId | String | | 테스트용 ID · 개발용 |
114
+
115
+ > 피그마의 `Variant`(Empty / Placeholder / Text)와 `State`(Enabled / Hovered / Focused)는 **코드에 따로 넣는 값이 없고 자동으로** 정해집니다. Empty·Placeholder·Text는 입력 내용에 따라, Hovered·Focused는 마우스·입력 상태에 따라 바뀝니다.
116
+ >
117
+ > ```tsx
118
+ > <TextField variant="label" label="예산" measure="원" maxLength={20}
119
+ > supportMessage="숫자만 입력하세요" isError={!!error} errorMessage={error}
120
+ > value={value} onChange={onChange} />
121
+ > ```
122
+
123
+ ## Z. 미결 (구현하지 말 것)
124
+
125
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
126
+
127
+ 1. **피그마 컴포넌트 통합**: 피그마는 Text Field와 Label Text Field가 별도 컴포넌트입니다. 코드처럼 하나로 합치고 `Variant = default / label`로 둘지 결정
128
+ 2. **Leading Icon은 양쪽 모두 가질 수 있습니다**: 스토리북은 `variant`와 무관하게 `leadingIcon`을 지원합니다. 피그마의 Label Text Field에만 없는 것은 그리지 않았기 때문으로 보입니다 → 피그마 추가 검토
129
+ 3. **피그마 오타**: Label Text Field Anatomy에 `Lable Text` 오타가 있습니다
@@ -0,0 +1,123 @@
1
+ ---
2
+ id: INPUT-22
3
+ component: TextFieldDropdown
4
+ version: 0.0.2
5
+ status: draft
6
+ ---
7
+
8
+ # 22. TextFieldDropdown
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.10.02): 초안 작성
13
+ - v0.0.2 (2026.10.16): `variant = label`의 트리거 높이(66)·목록 간격(6px) 추가, 선택된 항목 표시를 코드에 맞춤 — 색만 바뀌고 굵기는 그대로 (#1299 리뷰 반영)
14
+
15
+ ## A. Anatomy
16
+
17
+ TextFieldDropdown은 TextField와 같은 모양의 **Text Field**(트리거)와, 트리거를 누르면 그 아래로 열리는 **List**로 구성됩니다. 트리거 아래에는 TextField와 같은 **Error Text · Supporting Text** 줄이 붙습니다.
18
+
19
+ | 요소 | 필수 여부 | 설명 |
20
+ | --- | --- | --- |
21
+ | Container | 필수 | 모서리 12, 테두리 `w-gray-200`. 누르면 목록이 열리는 영역. 높이는 아래 표 |
22
+ | Label | 조건부 | `variant = label`일 때 필드 **안쪽 상단**에 얹히는 항목명 |
23
+ | Placeholder / Text | 필수 | 고르기 전에는 Placeholder, 고른 뒤에는 선택한 항목 텍스트 |
24
+ | Arrow Icon | 필수 | 우측 `medium_arrow_down`(16). 목록이 열리면 위로 돌아감 |
25
+ | List | 조건부 | 트리거를 눌렀을 때만 표시. 너비는 트리거와 같고(최소 220), **최대 높이 240** 넘으면 스크롤 |
26
+ | List Item | 필수 | 목록의 선택지. 텍스트 + 선택적 Leading Icon(Medium 16) |
27
+ | Error Text | 조건부 | 오류 문구. 필드 하단, **Supporting Text 위에 별도 줄**로 표시 |
28
+ | Supporting Text | 선택 | 필드 하단 좌측의 도움말 |
29
+
30
+ **Variant별 크기**
31
+
32
+ | Variant | 트리거 높이 | 트리거와 목록 사이 |
33
+ | --- | --- | --- |
34
+ | `default` (기본값) | 50 | 4px |
35
+ | `label` | 66 | 6px |
36
+
37
+ **상태별 표시**
38
+
39
+ | 상태 | 테두리 | 배경 | 텍스트 |
40
+ | --- | --- | --- | --- |
41
+ | 기본 | `w-gray-200` | `w-white` | Placeholder `w-gray-300` / 선택값 `w-gray-600` |
42
+ | Hover · 목록 열림 | `primary-500` | `w-white` | 기본과 같음 |
43
+ | Error | `w-red-500` (Hover·열림에도 유지) | `w-white` | 기본과 같음 |
44
+ | Disabled | `w-gray-200` | `w-gray-10` | Placeholder `w-gray-200` / 선택값 `w-gray-300`, 아이콘 `w-gray-300` |
45
+
46
+ 목록 항목의 선택·Hover 표시는 **List** 컴포넌트와 같습니다. (선택됨 = 텍스트 `primary-500`, 굵기는 그대로 Regular · Hover·키보드 포커스 = 배경 `primary-10`)
47
+
48
+ ## B. Description
49
+
50
+ ### 1. 정의
51
+
52
+ 사용자가 리스트에서 직접 항목을 선택할 수 있도록 설계된 컴포넌트입니다. 생김새는 TextField와 같고, 타이핑 대신 목록에서 하나를 골라 값을 채웁니다.
53
+
54
+ ### 2. 사용 시점
55
+
56
+ - 폼에서 **정해진 선택지 중 하나**를 값으로 받을 때 사용합니다. (업종, 직무, 지역)
57
+ - 선택지가 많아 화면에 다 펼칠 수 없을 때 사용합니다.
58
+ - 선택지가 2~5개로 적다면 펼쳐 두는 **Radio**나 **ChoiceChip**을 사용합니다.
59
+ - 여러 개를 골라야 한다면 **Checkbox** 계열을 사용합니다. 이 컴포넌트는 하나만 고릅니다.
60
+ - 입력하면서 목록을 걸러 고르게 한다면 **Autocomplete**를 사용합니다.
61
+ - 폼이 아니라 목록 상단의 정렬·보기 전환이라면 **TextButtonDropdown**이나 **IconButtonDropdown**을 사용합니다.
62
+ - 누르면 목록이 아니라 **모달·패널**이 열려야 한다면 **TextFieldTrigger**를 사용합니다.
63
+
64
+ **유형**
65
+
66
+ 유형(Default · Fixed Label · Label)은 **TextField와 같습니다.** 같은 폼에서 TextField와 나란히 쓸 때 `variant`를 맞춥니다.
67
+
68
+ ### 3. 키워드
69
+
70
+ TextFieldDropdown, 드롭다운, Dropdown, 셀렉트, Select, 셀렉트 박스, Select Box, 단일 선택
71
+
72
+ ### 4. Do / Don't
73
+
74
+ **Do**
75
+
76
+ - Placeholder에는 **무엇을 고르는 칸인지**를 적습니다. (`업종을 선택해주세요`)
77
+ - 항목 텍스트는 짧은 한 줄로 씁니다. 선택하면 그 텍스트가 그대로 필드에 들어갑니다.
78
+ - **Error Text와 Supporting Text가 동시에 있으면 둘 다 표시합니다.** Error Text를 위에, Supporting Text를 아래에 둡니다. (TextField와 같음)
79
+
80
+ **Don't**
81
+
82
+ - 항목을 고르자마자 화면 이동·저장이 일어나게 만들지 않습니다. 폼 값을 채우는 컴포넌트입니다.
83
+ - Placeholder를 항목명 대신 쓰지 않습니다. 항목을 고르면 사라집니다.
84
+ - 테두리 색상만으로 오류를 알리지 않습니다. Error Text를 함께 씁니다.
85
+
86
+ ## C. Properties
87
+
88
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`IsError` → `isError`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 쪽 상태를 함께 적었습니다.
89
+
90
+ | Property | Type | Values | 비고 |
91
+ | --- | --- | --- | --- |
92
+ | Items | Array | `{ key, value, leadingIcon? }` 목록 | **필수.** `value` = 항목 텍스트, `leadingIcon` = System Icon 이름 (Medium) |
93
+ | SelectedItem | Object | Items 중 하나 | 선택된 항목. 값이 있으면 필드에 텍스트로 표시되고 목록에서 강조됨 · 피그마 `Variant = Text`가 이 상태 |
94
+ | Variant | Variant | `default` / `label` | 기본값 `default`. TextField와 같은 의미. 트리거 높이가 달라짐(A. Variant별 크기) · 피그마에 `label` 없음 (Z-2) |
95
+ | Label | String | | `variant = label`일 때 사용 |
96
+ | Placeholder | String | | 고르기 전 안내 문구 |
97
+ | Disabled | Boolean | True / False | 피그마 `Disabled` |
98
+ | IsError | Boolean | True / False | 오류 테두리. 피그마 `Is Error` |
99
+ | ErrorMessage | String | | 오류 문구. 필드 하단 Supporting Text **위**에 표시 · 피그마는 Error Text가 `Is Error`에 묶여 있음 |
100
+ | SupportMessage | String | | 도움말 문구 · 피그마에 없음 (Z-3) |
101
+ | PanelWidth | Variant | `trigger` / `viewport` | 기본값 `trigger`. 화면 크기별 값도 가능 `{ base, tablet, desktop }` · 피그마에 없음 |
102
+ | PanelGutter | Number | | 기본값 `20`. `viewport`일 때 목록과 화면 좌우 끝 사이 여백(px) |
103
+ | OnItemClick | Function | | **필수.** 항목을 고를 때 호출 · 동작용 |
104
+ | ClassName | String | | 개발용 스타일 지정 (트리거에 적용) |
105
+ | State | Variant | Enabled / Hovered / Focused | 피그마에만 존재. Focused = 목록이 열린 모습 · 코드는 마우스·클릭으로 자동 처리 (Z-1) |
106
+
107
+ > 피그마의 `Variant`(Placeholder / Text)는 **코드에 따로 넣는 값이 없고** `selectedItem` 유무로 자동으로 정해집니다. 코드의 `variant`(default / label)와는 다른 것입니다.
108
+ >
109
+ > ```tsx
110
+ > <TextFieldDropdown variant="label" label="업종" items={items}
111
+ > selectedItem={selected} onItemClick={setSelected}
112
+ > isError={!!error} errorMessage={error} />
113
+ > ```
114
+
115
+ ## Z. 미결 (구현하지 말 것)
116
+
117
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
118
+
119
+ 1. **State · Variant 이름 정리**: 피그마 `State = Focused`는 목록이 열린 모습이고, 피그마 `Variant`(Placeholder / Text)는 선택 여부입니다. 둘 다 코드에는 넣는 값이 없고, 특히 `Variant`는 코드의 `variant`(default / label)와 이름이 겹칩니다 → 피그마 속성 이름을 바꿀지 검토 (예: `Open`, `Selected`)
120
+ 2. **Label 트리거 누락**: 코드는 `variant = label`(TextField의 Label / Fixed Label과 같은 모양)을 지원하지만 피그마에는 Default만 있습니다 → 피그마 추가 검토. 추가할 때 트리거 높이 66 · 목록 간격 6px로 그립니다 (A. Variant별 크기)
121
+ 3. **Supporting Text 누락**: 코드는 `supportMessage`를 받지만 피그마에는 Error Text만 있습니다 → 피그마 추가 검토
122
+ 4. **선택한 항목의 아이콘**: 항목에 Leading Icon이 있어도 고른 뒤 필드에는 텍스트만 표시됩니다. 코드는 아이콘을 넘기지만 트리거가 그리지 않고, 피그마도 텍스트만 있습니다 → 필드에도 아이콘을 보여줄지 결정
123
+ 5. **선택 취소**: 한 번 고르면 빈 값으로 되돌릴 방법이 없습니다. 필수가 아닌 항목이라면 `선택 안 함` 같은 항목을 넣을지, 컴포넌트에 비우기를 넣을지 결정
@@ -0,0 +1,154 @@
1
+ ---
2
+ id: INPUT-19
3
+ component: Textarea
4
+ version: 0.0.3
5
+ status: draft
6
+ ---
7
+
8
+ # 19. Textarea
9
+
10
+ **개정 이력**
11
+
12
+ - v0.0.1 (2026.09.28): 초안 작성
13
+ - v0.0.2 (2026.10.01): 프론트매터 추가, 이름을 코드 기준 `Textarea`로 통일, Properties를 코드(`TextareaProps`)·스토리북 기준으로 정리(`resize` · `supportText` · `errorText`, Size `full` 추가), Error Text·Supporting Text "함께 표시"로 변경(TextField와 동일), 피그마 ↔ 코드 대응표 추가, "나중확인"을 `Z. 미결`로 분리
14
+ - v0.0.3 (2026.10.02): Anatomy의 Scrollbar를 "항상 표시"로 정정, Properties 안내 문구 통일, `value` · `onChange` · `onBlur` · `name` 추가, Z절 색 표기를 코드 토큰명으로 (#1295 리뷰 반영)
15
+
16
+ ## A. Anatomy
17
+
18
+ Textarea는 **Container** 안에 여러 줄 입력 영역이 있고, 그 아래에 **Supporting Text** 줄이 붙는 구조입니다.
19
+
20
+ | 요소 | 필수 여부 | 설명 |
21
+ | --- | --- | --- |
22
+ | Container | 필수 | 배경·테두리·패딩을 담당. 클릭/포커스 영역의 기준 |
23
+ | Placeholder / Text | 필수 | 입력 전에는 Placeholder, 입력 중에는 입력값 |
24
+ | Scrollbar | 필수 | 입력 영역 우측의 스크롤 표시. 내용 양과 관계없이 **항상** 표시됩니다 |
25
+ | Resizer | 선택 | 우측 하단의 크기 조절 손잡이 |
26
+ | Error Text | 조건부 | 오류 문구. 필드 하단, **Supporting Text 위에 별도 줄**로 표시 |
27
+ | Supporting Text | 선택 | 필드 하단 좌측의 도움말 |
28
+ | Max Length | 선택 | 필드 하단 우측의 글자 수 (`0/20`) |
29
+
30
+ ## B. Description
31
+
32
+ ### 1. 정의
33
+
34
+ 사용자가 여러 줄의 텍스트를 길게 작성할 때 사용하는 컴포넌트입니다.
35
+
36
+ ### 2. 사용 시점
37
+
38
+ - 사용자가 **여러 줄에 걸쳐 긴 글**을 써야 할 때 사용합니다. (소개, 요청 사항, 상세 설명)
39
+ - 입력 길이를 **미리 가늠할 수 없을 때** 사용합니다.
40
+ - 한 줄이면 충분한 값이라면 **TextField**를 사용합니다.
41
+ - 게시물에 대한 **의견·답글**을 남기는 자리라면 **CommentArea**를 사용합니다.
42
+ - 검색어를 입력해 결과를 찾는 것이라면 **SearchField**를 사용합니다.
43
+
44
+ ### 3. 키워드
45
+
46
+ Textarea, 텍스트 에어리어, 여러 줄 입력, 장문 입력, 본문 입력, TextArea
47
+
48
+ ### 4. Size
49
+
50
+ Size는 **입력 영역의 높이**만 다릅니다. 그 외 규격은 모두 같습니다.
51
+
52
+ | Size | 코드 값 | 입력 영역 Height | 전체 Height (Supporting 포함) | 전체 Height (Error 포함) |
53
+ | --- | --- | --- | --- | --- |
54
+ | **Small** | `sm` | 120 | 152 | 184 |
55
+ | **Medium** (기본) | `md` | 240 | 272 | 304 |
56
+ | **Large** | `lg` | 360 | 392 | 424 |
57
+ | **Full** | `full` | 부모 높이를 꽉 채움 | — | — |
58
+
59
+ ### 4-1. Size 선택 기준
60
+
61
+ | Size | 사용 상황 |
62
+ | --- | --- |
63
+ | **Small** | 한두 문장 정도의 짧은 보충 설명 |
64
+ | **Medium** | 한 문단 분량의 일반적인 장문 입력 |
65
+ | **Large** | 여러 문단을 쓰는 본문 성격의 입력 (프로젝트 상세 설명 등) |
66
+ | **Full** | 화면·패널의 남은 높이를 모두 입력 영역으로 쓸 때 (에디터형 화면) |
67
+
68
+ - Size는 **예상 입력량**에 맞춰 고릅니다. 화면 여백을 채우려고 키우지 않습니다.
69
+ - 한 폼 안에서는 같은 Size로 통일합니다.
70
+ - 입력 내용이 영역을 넘으면 **스크롤을 반드시 노출**합니다. 내용이 더 있다는 것을 사용자가 알 수 있어야 합니다.
71
+
72
+ 1. Resizer는 **세로 방향 확대만** 허용합니다.
73
+ 2. Resizer를 끄는 경우, Size 선택만으로 충분한 높이가 확보되는지 확인합니다.
74
+ 3. `Full`과 Resizer를 함께 쓰면 부모 영역에 최소 높이가 정해져 있어야 합니다 (개발 시 grid + min-height 필요).
75
+
76
+ ### 4-2. Width
77
+
78
+ - Textarea는 **부모 컨테이너 너비를 100% 채웁니다.** Figma의 `400`은 예시 값입니다.
79
+ - 가로 스크롤은 사용하지 않습니다. 긴 줄은 자동 줄바꿈합니다.
80
+
81
+ ### 4-3. Supporting Text · Max Length · Error Text
82
+
83
+ 1. Supporting Text는 **최대 2줄**까지만 보이고, 더 긴 메시지는 **말줄임(`…`)** 처리합니다.
84
+ 2. Error Text도 영역을 초과하면 말줄임으로 축약합니다.
85
+ 3. Max Length는 항상 **우측 정렬**하며 `현재/최대` 형식으로 표기합니다. (`0/20`)
86
+ 4. **입력 글자 수는 5000자까지만 사용합니다.** 자동 제한이 없으므로 `maxLength`를 `5000` 이하로 반드시 지정합니다.
87
+ 5. Supporting Text 자리는 오류 여부와 무관하게 **항상 확보**합니다.
88
+ 6. **Error Text와 Supporting Text가 동시에 있으면 둘 다 표시합니다.** Error Text를 위에, Supporting Text를 아래에 둡니다. (TextField와 동일)
89
+
90
+ ### 5. Do / Don't
91
+
92
+ **Do**
93
+
94
+ - Placeholder에는 **무엇을 쓰는 칸인지** 적습니다. (`프로젝트 내용을 자세히 적어주세요`)
95
+ - 입력 내용이 영역을 넘으면 스크롤을 노출합니다.
96
+ - 예상 입력량에 맞는 Size를 고릅니다.
97
+ - 글자 수 제한이 있으면 Max Length를 함께 노출합니다.
98
+
99
+ **Don't**
100
+
101
+ - 한 줄이면 충분한 값에 Textarea를 쓰지 않습니다.
102
+ - 입력 내용에 따라 높이를 무한정 늘리지 않습니다. 스크롤로 처리합니다.
103
+ - 가로 스크롤을 만들지 않습니다.
104
+ - 5000자를 넘는 입력을 허용하지 않습니다.
105
+
106
+ ## C. Properties
107
+
108
+ 스토리북(코드) 이름 기준입니다. 표의 Property는 읽기 쉽게 첫 글자를 대문자로 적었고, **코드에서는 첫 글자가 소문자**입니다 (`IsError` → `isError`). 화면에 보이는 속성뿐 아니라 **동작용(`on…`)·개발용 prop도 적습니다.** 비고에 피그마 이름을 함께 적었습니다.
109
+
110
+ | Property | Type | Values | 비고 |
111
+ | --- | --- | --- | --- |
112
+ | Placeholder | String | | 피그마 추가 |
113
+ | Size | Variant | `sm` / `md` / `lg` / `full` | 기본값 `md` · 피그마는 **Small / Medium / Large 세 컴포넌트로 분리**되어 있고 `full`이 없음 (Z-1) |
114
+ | MaxLength | Number | | 최대 글자 수 (5000 이하) · 피그마는 Boolean → 숫자로 변경 필요 |
115
+ | IsLengthVisible | Boolean | True / False | 글자 수(`0/20`) 표시 여부 (동작 주의: Z-4) |
116
+ | IsError | Boolean | True / False | 오류 테두리 |
117
+ | ErrorText | String | | 오류 문구 · 피그마 `Error Text`(Boolean) → 텍스트 속성 추가 |
118
+ | SupportText | String | | 도움말 문구 · 피그마 `Supporting Text`(Boolean) → 텍스트 속성 추가 |
119
+ | Resize | Boolean | True / False | 세로 크기 조절 + Resizer 아이콘 표시. 기본값 False · 피그마 `resizer` |
120
+ | Disabled | Boolean | True / False | 피그마는 **State의 값** → TextField와 맞춰 Boolean으로 분리 검토 |
121
+ | Value | String | | 입력값. 글자 수(`현재/최대`) 계산에도 쓰입니다 |
122
+ | OnChange | Function | | 입력값이 바뀔 때 호출 · 동작용 |
123
+ | OnBlur | Function | | 입력 칸에서 벗어날 때 호출 · 동작용 |
124
+ | Name | String | | 폼 전송용 이름 · 개발용 |
125
+
126
+ **피그마 ↔ 코드 대응**
127
+
128
+ 피그마의 `Variant`·`State`·`Scrollbar`는 코드에 따로 넣는 값이 없고, **자동으로** 정해집니다.
129
+
130
+ | 피그마 | 코드 | 모습 |
131
+ | --- | --- | --- |
132
+ | `Variant = Empty / Placeholder / Text` | 입력 내용에 따라 자동 | 빈 칸 / 회색 안내 문구 / 입력값 |
133
+ | `State = Enabled` | 기본 | 회색 테두리 |
134
+ | `State = Hovered` | 마우스 hover (자동) | Primary 테두리 |
135
+ | `State = Focused` | 입력 중 (자동) | Primary 테두리 |
136
+ | `State = Disabled` | `disabled` | 회색 배경, 입력·크기 조절 불가 |
137
+ | `Is Error = True` | `isError` | Red 테두리 |
138
+ | `Scrollbar` | 항상 표시 | 입력 영역 우측 |
139
+
140
+ > ```tsx
141
+ > <Textarea size="lg" placeholder="프로젝트 내용을 자세히 적어주세요" resize
142
+ > maxLength={5000} isLengthVisible supportText="최대 5000자"
143
+ > isError={!!error} errorText={error} value={value} onChange={onChange} />
144
+ > ```
145
+
146
+ ## Z. 미결 (구현하지 말 것)
147
+
148
+ > 아래는 **결정되지 않은 제안**입니다. 구현 기준은 위 A~C입니다. 결정되면 본문으로 옮기고 여기서 지웁니다.
149
+
150
+ 1. **피그마 컴포넌트 통합**: 피그마는 Text Area (Small / Medium / Large)가 별도 컴포넌트입니다. 하나로 합치고 `Size` 속성으로 둘지, 코드의 `full`을 피그마에 추가할지 결정
151
+ 2. **Disabled 텍스트 색 불일치 (피그마)**: Textarea는 **`w-gray-200`(`#E0E0E0`)**, TextField는 `w-gray-300`(`#BDBDBD`). 한쪽으로 통일 (`w-gray-300` 권장 — 너무 흐리면 읽히지 않음)
152
+ 3. **Disabled의 패딩 구조가 다름 (피그마)**: 다른 변형은 `좌 16 / 우 8 / 상하 10`, Disabled는 `좌우 17 / 상하 11`. Disabled만 이전 구조로 남아 있음 — 통일 필요
153
+ 4. **글자 수 표시 동작 (개발팀 전달)**: `isLengthVisible`을 꺼도 `supportText`와 `maxLength`가 있으면 글자 수가 보이고, `supportText`가 없으면 `maxLength`만으로는 보이지 않습니다. 이름과 실제 동작이 맞지 않습니다
154
+ 5. **prop 이름 불일치 (개발팀 전달)**: TextField는 `supportMessage` · `errorMessage`, Textarea는 `supportText` · `errorText`를 씁니다. 통일하려면 코드 이름을 바꿔야 하므로(사용처가 깨지는 변경) 개발팀과 결정