# Field

글자를 입력하는 칸이다. 이름(라벨), 안내 문구, 오류 문구, 비밀번호 보기와 지우기 버튼을 포함한다.

- 분류: 입력과 선택
- 가져오기: `import { Field } from '@/ui/Field'`
- 코드 위치: `apps/mobile/src/ui/Field.tsx:11` (Mordy 저장소 60df633)
- 웹 페이지: https://developers.moring.co/tds/components/field

## 미리보기

실제 컴포넌트를 그린 화면은 https://developers.moring.co/tds/components/field 에서 볼 수 있다. 서비스 색 선택기로 Mordy, Morit 색을 바꿔 볼 수 있다.

## 언제 쓰는가

### 쓴다
- 이메일, 이름, 메모처럼 짧은 글자를 한 줄로 받을 때 쓴다.
- 입력 칸마다 `label`을 반드시 쓴다. 안내 문구(`placeholder`)로 이름을 대신하지 않는다.
- 값이 틀렸을 때 `error`에 이유를 쓴다. 칸의 테두리가 `danger` 색이 되고 문구가 아래에 나온다.

### 쓰지 않는다
- 여러 줄 글을 받을 때 쓰지 않는다. `multiline`을 넘길 수는 있지만 높이는 최소 52로 한 줄 기준이다.
- 여러 보기 중 고르는 데 쓰지 않는다. `ChoiceCard`나 `OptionSheet`를 쓴다.
- `error`와 `helper`를 동시에 보여 주지 않는다. `error`가 있으면 `helper`는 가려진다.

## 종류

| 이름 | 설명 |
| --- | --- |
| 기본 | `field` 배경의 채워진 칸. 포커스를 받으면 `surface` 배경과 `primary` 테두리로 바뀐다. 이름 글자는 `smallStrong`. |
| outline | `outline`이 `true`다. 흰 면에 `line` 테두리, 더 큰 칸(최소 56)과 큰 글자(17, SemiBold). 이름 글자는 `bodyStrong`. 로그인처럼 칸이 화면의 주인공일 때 쓴다. |

## 크기

| 이름 | 값 | 설명 |
| --- | --- | --- |
| 기본 | 최소 높이 52 | 글자가 커지면 칸도 커진다(`minHeight`). |
| outline | 최소 높이 56 |  |

## 상태

| 상태 | 모습과 동작 |
| --- | --- |
| 비어 있음 | 안내 문구(`placeholder`)가 `textTertiary` 색으로 보인다. |
| 포커스 | 테두리가 `primary`(1.2px), 배경이 `surface`. |
| 입력됨 | 글자가 `text` 색. `clearable`이면 지우기 버튼이 나온다. |
| 오류 | 테두리가 `danger`, 아래에 `danger` 색 오류 문구(`caption`). |
| 비활성 | 입력할 수 없다. 앱의 `Field`에는 비활성 전용 스타일이 없고 React Native의 `editable={false}`를 따른다. |

## 사용 방법

### 기본

```tsx
import { Field } from '@/ui/Field';

<Field label="닉네임" value={name} onChangeText={setName} placeholder="2~10자" helper="나중에 바꿀 수 있어요" />
```

### 오류와 지우기

```tsx
<Field
  label="이메일"
  value={email}
  onChangeText={setEmail}
  keyboardType="email-address"
  autoCapitalize="none"
  clearable
  error={valid ? null : '이메일 형식이 올바르지 않아요'}
/>
```

### 비밀번호

```tsx
<Field label="비밀번호" outline secure value={pw} onChangeText={setPw} />
```

### 속성(props)

| 이름 | 타입 | 기본값 | 필수 | 설명 |
| --- | --- | --- | --- | --- |
| `label` | `string` | — | 필수 | 칸 위에 쓰는 이름. 화면 읽기 프로그램의 이름도 이것이다. |
| `error` | `string \| null` | — | 선택 | 오류 문구. 있으면 테두리가 `danger`가 되고 문구가 아래에 나온다. `null`이면 오류가 없다. |
| `helper` | `string` | — | 선택 | 칸 아래의 안내 문구(`textSecondary`). `error`가 있으면 보이지 않는다. |
| `secure` | `boolean` | — | 선택 | `true`이면 입력을 점으로 가리고 오른쪽에 보기·숨기기 버튼을 둔다. |
| `clearable` | `boolean` | — | 선택 | `true`이고 값이 있으면 오른쪽에 지우기(×) 버튼을 둔다. |
| `outline` | `boolean` | — | 선택 | `true`이면 outline 모양(흰 면, 큰 칸)이다. |
| `prefix` | `string` | — | 선택 | 입력 앞에 붙는 고정 글자. `textTertiary` 색. 예: "@". |
| `status` | `ReactNode` | — | 선택 | 입력 오른쪽에 놓을 요소(사용 가능 표시 등). |
| `style` | `(React Native)` | — | 선택 | 입력 글자(`TextInput`)에 적용할 스타일. |

나머지 속성은 `TextInputProps`를 그대로 받는다.

위에 적지 않은 속성(`value`, `onChangeText`, `placeholder`, `keyboardType`, `autoCapitalize` 등)은 React Native `TextInput`의 속성을 그대로 받는다.

## 치수와 토큰

| 항목 | 값 |
| --- | --- |
| 칸 | 최소 높이 52, 모서리 `radius.md`(12), 좌우 안쪽 여백 16, 안쪽 요소 사이 8 |
| 배경과 테두리 | `field` 배경, 1.2px `field` 테두리. 포커스 시 `surface` 배경, `primary` 테두리. 오류 시 `danger` 테두리 |
| 입력 글자 | Pretendard Medium 15, 색 `text`. 안내 문구 `textTertiary` |
| 이름과 칸 사이 | 6 (outline은 10) |
| outline | 최소 높이 56, 모서리 16, 배경 `surface`, 테두리 `line`, 좌우 18, 입력 글자 17 SemiBold |
| 보기·지우기 버튼 | 아이콘 20px, 색 `textTertiary`, `hitSlop` 10 |

## 접근성

- 이름(`accessibilityLabel`)이 `label`로, 힌트가 `error` 또는 `helper`로 지정된다.
- 비밀번호 보기 버튼의 이름은 "비밀번호 보기" 또는 "비밀번호 숨기기", 지우기 버튼은 "{label} 지우기"다.
- 오류는 글자(`error`)로도 알린다. 테두리 색만으로 알리지 않는다.
- `placeholder`(`textTertiary`)는 대비가 낮으므로 이름 역할을 맡기지 않는다.
- 앱은 터치 화면이라 마우스 올림(hover)이 없다. 웹에서는 포커스 링(2.5px 실선, 바깥 3px)을 직접 그린다. 이 문서의 미리보기에는 포커스 링이 그려져 있다.

### 글자 색 대비

| 쓰임 | 글자색 | 바탕 | Mordy 라이트 | Mordy 다크 | Morit 라이트 | Morit 다크 | 기준 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 입력 글자 | `text` | `field` | 15.96:1 통과 | 14.08:1 통과 | 14.95:1 통과 | 9.62:1 통과 | 4.5:1 |
| 오류 문구 (11.5px) | `danger` | `surface` | 4.55:1 통과 | 5.76:1 통과 | 5.04:1 통과 | 7.11:1 통과 | 4.5:1 |
| 안내 문구 `placeholder` | `textTertiary` | `field` | 2.36:1 미달 | 3.23:1 미달 | 2.75:1 미달 | 3.92:1 미달 | 4.5:1 |

## 잘한 예와 잘못한 예

- 잘한 예: 이름(`label`)과 이유가 있는 오류 문구를 함께 쓴다.
- 잘못한 예: 안내 문구만 있고 이름이 없다. 입력을 시작하면 안내가 사라져 무엇을 적는 칸인지 알 수 없다.

## 함께 보는 컴포넌트

- [OptionRow](https://developers.moring.co/tds/components/option-row.md): 퀴즈 보기 한 줄이다. 고르기 전, 고른 뒤, 채점 뒤(정답, 오답)의 모습이 정해져 있다.
- [ChoiceCard](https://developers.moring.co/tds/components/choice-card.md): 카드 모양의 선택지다. 고르면 테두리가 굵어지고 체크 표시가 붙는다. 온보딩의 과목·알림 선택에 쓴다.
- [Notice](https://developers.moring.co/tds/components/notice.md): 화면 안에 끼워 넣는 한 줄 안내 상자다. 안내(파랑), 주의(주황), 오류(빨강) 세 가지 톤이 있다.
