# Sheet

화면 아래에서 올라오는 시트다. 위쪽 두 모서리가 둥글고, 손잡이와 제목 줄, 닫기 버튼이 있다.

- 분류: 알림과 안내
- 가져오기: `import { Sheet } from '@/ui/feedback'`
- 코드 위치: `apps/mobile/src/ui/feedback.tsx:80` (Mordy 저장소 60df633)
- 웹 페이지: https://developers.moring.co/tds/components/sheet

## 미리보기

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

## 언제 쓰는가

### 쓴다
- 짧은 선택, 한 가지 입력, 작은 양식을 현재 화면 위에서 처리할 때 쓴다.
- 제목(`title`)을 주면 제목 줄과 ✕ 닫기가 생긴다. 모든 시트의 제목 줄은 같은 모양이다.
- 아래로 끌거나 바깥을 누르거나 뒤로 가기를 눌러 닫는다.

### 쓰지 않는다
- 긴 양식이나 여러 단계에는 쓰지 않는다. 전체 화면으로 만든다.
- 꼭 답해야 하는 확인에는 쓰지 않는다. `dialog`를 쓴다.
- 시트 위에 시트를 겹치지 않는다.

## 종류

| 이름 | 설명 |
| --- | --- |
| 제목 있음 | 제목 `headline` 20과 ✕ 버튼(36 원, `well` 바탕). |
| 제목 없음 | 손잡이만 있다. 내용이 스스로 제목을 가질 때. |

## 크기

| 이름 | 값 | 설명 |
| --- | --- | --- |
| 기본 | 폭 전체, 높이는 내용 | 좌우 20(`gutter`), 아래는 안전 영역과 16 중 큰 값. 모서리 `radius.sheet`(24). |

## 상태

| 상태 | 모습과 동작 |
| --- | --- |
| 열림 | 어둠막이 나타나고(`scrim`) 시트가 240ms 동안 올라온다. |
| 닫힘 | 180ms 동안 내려간다. |
| 끄는 중 | 손잡이 줄을 아래로 끌면 따라 내려간다. 100 넘게 끌거나 빠르게(속도 900 초과) 끌고 놓으면 닫힌다. 아니면 160ms 동안 제자리로 돌아온다. |
| 위로 끄는 중 | `onPullUp`을 넘겼을 때만 가능하다. 위로 끌고 놓으면 `onPullUp`이 호출되고, 짧게 끌면 제자리로 돌아온다. |
| 키보드 | 키보드가 올라오면 시트가 그 위로 올라간다. |

## 사용 방법

### 기본

```tsx
import { Sheet } from '@/ui/feedback';

<Sheet visible={open} onClose={() => setOpen(false)} title="시험 선택">
  {/* 내용 */}
</Sheet>
```

### 속성(props)

| 이름 | 타입 | 기본값 | 필수 | 설명 |
| --- | --- | --- | --- | --- |
| `visible` | `boolean` | — | 필수 | 열려 있는지. |
| `onClose` | `() => void` | — | 필수 | 닫을 때 호출된다(끌기, 바깥 누르기, 뒤로 가기, ✕). |
| `children` | `ReactNode` | — | 필수 | 시트 안의 내용. |
| `title` | `string` | — | 선택 | 제목. 있으면 제목 줄과 ✕가 생긴다. |
| `onPullUp` | `() => void` | — | 선택 | 손잡이 줄을 위로 70 넘게(또는 빠르게) 끌고 놓으면 호출된다. 더 큰 화면(전체 화면 편집기)을 여는 데 쓴다. 넘기면 시트가 위로도 최대 160까지 따라 올라간다(위 방향은 40%만 따라온다). |

## 치수와 토큰

| 항목 | 값 |
| --- | --- |
| 시트 | `surface`, 위쪽 모서리 24, 좌우 20, 아래 max(안전 영역, 16) |
| 손잡이 | 40 × 4, 모서리 2, `lineStrong`, 아래 12 |
| 제목 줄 | 제목 `headline` 20, ✕ 36 원(`well`), 아래 16 |
| 어둠막 | `scrim` |
| 움직임 | 열림 240ms(out), 닫힘 180ms(in), 되돌림 160ms |

## 접근성

- 시트는 모달이라 뒤 내용은 읽히지 않는다(`accessibilityViewIsModal`).
- 바깥 눌림 영역과 ✕의 이름은 "닫기"다.
- 웹에서는 시트가 열리면 초점이 시트 안으로 들어가고 Esc로 닫혀야 한다.

## 잘한 예와 잘못한 예

- 잘한 예: 제목을 주면 무엇을 고르는 시트인지 알 수 있다.
- 잘못한 예: 긴 양식을 시트에 넣지 않는다. 전체 화면으로 만든다.

## 함께 보는 컴포넌트

- [OptionSheet](https://developers.moring.co/tds/components/option-sheet.md): 시트 안에서 목록 중 하나를 고르는 컴포넌트다. 행마다 라디오 표시가 있고, 고르면 바로 닫힌다.
- [dialog](https://developers.moring.co/tds/components/dialog.md): 화면 가운데 뜨는 확인 대화상자와 아래에서 올라오는 메뉴를 함수 호출 하나로 여는 도구다. 결과(눌린 버튼)를 약속(Promise)으로 돌려준다.
- [TimeSheet](https://developers.moring.co/tds/components/time-sheet.md): 아래에서 올라오는 시트에서 시각을 고른다. 오전/오후, 시, 분(5분 단위) 세 줄 바퀴를 돌려서 고른다.
