# Checkbox

## Introduction

Checkbox 컴포넌트는 사용자가 여러 옵션 중에서 하나 또는 여러 개를 선택할 수 있는 입력 요소입니다. Joy UI의 Checkbox를 기반으로 하며, Framer Motion 애니메이션 지원이 추가되었습니다. 설정 화면, 폼, 필터링, 다중 선택 목록 등에서 널리 사용됩니다.

```tsx
<Checkbox />
```

| Field    | Description | Default |
| -------- | ----------- | ------- |
| checked  | —           | —       |
| disabled | —           | —       |
| label    | —           | —       |
| variant  | —           | —       |
| color    | —           | —       |
| size     | —           | —       |

## Usage

```tsx
import { Checkbox } from '@ceed/cds';

function MyComponent() {
  const [checked, setChecked] = useState(false);

  return <Checkbox label="동의합니다" checked={checked} onChange={(e) => setChecked(e.target.checked)} />;
}
```

## Examples

### Basic Usage

가장 기본적인 Checkbox 사용법입니다.

```tsx
<Checkbox label="Label" />
```

### With Labels

체크박스에 라벨을 추가할 수 있습니다.

```tsx
<Checkbox />
```

## Common Use Cases

### Terms and Conditions

이용약관 동의에 체크박스를 사용하는 예제입니다.

```tsx
function TermsForm() {
  const [agreements, setAgreements] = useState({
    terms: false,
    privacy: false,
    marketing: false,
  });

  const handleChange = (key: keyof typeof agreements) => (event: React.ChangeEvent<HTMLInputElement>) => {
    setAgreements((prev) => ({
      ...prev,
      [key]: event.target.checked,
    }));
  };

  return (
    <Stack spacing={2}>
      <Typography level="title-md">약관 동의</Typography>

      <Checkbox
        label={
          <Typography>
            <strong>(필수)</strong> 이용약관에 동의합니다.
            <Link href="/terms" target="_blank" sx={{ ml: 1 }}>
              약관 보기
            </Link>
          </Typography>
        }
        checked={agreements.terms}
        onChange={handleChange('terms')}
        required
      />

      <Checkbox
        label={
          <Typography>
            <strong>(필수)</strong> 개인정보 처리방침에 동의합니다.
            <Link href="/privacy" target="_blank" sx={{ ml: 1 }}>
              방침 보기
            </Link>
          </Typography>
        }
        checked={agreements.privacy}
        onChange={handleChange('privacy')}
        required
      />

      <Checkbox
        label="(선택) 마케팅 정보 수신에 동의합니다."
        checked={agreements.marketing}
        onChange={handleChange('marketing')}
        color="neutral"
      />

      <Button disabled={!agreements.terms || !agreements.privacy} sx={{ mt: 2 }}>
        가입하기
      </Button>
    </Stack>
  );
}
```

### Multi-Select List

목록에서 여러 항목을 선택할 때 사용합니다.

```tsx
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: '회의 준비하기', completed: false },
    { id: 2, text: '보고서 작성하기', completed: true },
    { id: 3, text: '이메일 답장하기', completed: false },
  ]);

  const handleToggle = (id: number) => {
    setTodos((prev) => prev.map((todo) => (todo.id === id ? { ...todo, completed: !todo.completed } : todo)));
  };

  return (
    <Stack spacing={1}>
      <Typography level="title-md">할 일 목록</Typography>
      {todos.map((todo) => (
        <Checkbox
          key={todo.id}
          label={
            <Typography
              sx={{
                textDecoration: todo.completed ? 'line-through' : 'none',
                color: todo.completed ? 'neutral.500' : 'inherit',
              }}
            >
              {todo.text}
            </Typography>
          }
          checked={todo.completed}
          onChange={() => handleToggle(todo.id)}
          color={todo.completed ? 'success' : 'primary'}
        />
      ))}
    </Stack>
  );
}
```

### Filter Options

필터링 옵션에서 체크박스를 사용하는 예제입니다.

```tsx
function ProductFilter() {
  const [filters, setFilters] = useState({
    categories: [] as string[],
    priceRanges: [] as string[],
    brands: [] as string[],
  });

  const handleCategoryChange = (category: string) => (event: React.ChangeEvent<HTMLInputElement>) => {
    setFilters((prev) => ({
      ...prev,
      categories: event.target.checked ? [...prev.categories, category] : prev.categories.filter((c) => c !== category),
    }));
  };

  return (
    <Stack spacing={3}>
      <Stack spacing={2}>
        <Typography level="title-sm">카테고리</Typography>
        <Stack spacing={1} sx={{ pl: 1 }}>
          <Checkbox
            label="전자제품"
            checked={filters.categories.includes('electronics')}
            onChange={handleCategoryChange('electronics')}
            size="sm"
          />
          <Checkbox
            label="의류"
            checked={filters.categories.includes('clothing')}
            onChange={handleCategoryChange('clothing')}
            size="sm"
          />
          <Checkbox
            label="도서"
            checked={filters.categories.includes('books')}
            onChange={handleCategoryChange('books')}
            size="sm"
          />
        </Stack>
      </Stack>

      <Stack spacing={2}>
        <Typography level="title-sm">가격대</Typography>
        <Stack spacing={1} sx={{ pl: 1 }}>
          <Checkbox label="10만원 이하" size="sm" />
          <Checkbox label="10-50만원" size="sm" />
          <Checkbox label="50만원 이상" size="sm" />
        </Stack>
      </Stack>
    </Stack>
  );
}
```

### Select All Pattern

전체 선택/해제 패턴을 구현하는 예제입니다.

```tsx
function SelectAllExample() {
  const [items, setItems] = useState([
    { id: 1, name: '항목 1', selected: false },
    { id: 2, name: '항목 2', selected: true },
    { id: 3, name: '항목 3', selected: false },
    { id: 4, name: '항목 4', selected: false },
  ]);

  const selectedCount = items.filter((item) => item.selected).length;
  const isAllSelected = selectedCount === items.length;
  const isIndeterminate = selectedCount > 0 && selectedCount < items.length;

  const handleSelectAll = (event: React.ChangeEvent<HTMLInputElement>) => {
    setItems((prev) =>
      prev.map((item) => ({
        ...item,
        selected: event.target.checked,
      })),
    );
  };

  const handleItemToggle = (id: number) => {
    setItems((prev) => prev.map((item) => (item.id === id ? { ...item, selected: !item.selected } : item)));
  };

  return (
    <Stack spacing={2}>
      <Checkbox
        label={`전체 선택 (${selectedCount}/${items.length})`}
        checked={isAllSelected}
        indeterminate={isIndeterminate}
        onChange={handleSelectAll}
        variant="outlined"
        sx={{ fontWeight: 'bold' }}
      />

      <Divider />

      <Stack spacing={1} sx={{ pl: 2 }}>
        {items.map((item) => (
          <Checkbox
            key={item.id}
            label={item.name}
            checked={item.selected}
            onChange={() => handleItemToggle(item.id)}
            size="sm"
          />
        ))}
      </Stack>
    </Stack>
  );
}
```

### Form with Validation

폼 검증과 함께 사용하는 체크박스 예제입니다.

```tsx
function RegistrationForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    agreeToTerms: false,
    subscribeNewsletter: false,
  });

  const [errors, setErrors] = useState<Record<string, string>>({});

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault();

    const newErrors: Record<string, string> = {};

    if (!formData.name) {
      newErrors.name = '이름을 입력해주세요';
    }

    if (!formData.email) {
      newErrors.email = '이메일을 입력해주세요';
    }

    if (!formData.agreeToTerms) {
      newErrors.agreeToTerms = '이용약관에 동의해주세요';
    }

    setErrors(newErrors);

    if (Object.keys(newErrors).length === 0) {
      console.log('폼 제출:', formData);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <Stack spacing={3}>
        <Input
          placeholder="이름"
          value={formData.name}
          onChange={(e) => setFormData((prev) => ({ ...prev, name: e.target.value }))}
          error={!!errors.name}
        />
        {errors.name && (
          <Typography level="body-xs" color="danger">
            {errors.name}
          </Typography>
        )}

        <Input
          placeholder="이메일"
          type="email"
          value={formData.email}
          onChange={(e) => setFormData((prev) => ({ ...prev, email: e.target.value }))}
          error={!!errors.email}
        />
        {errors.email && (
          <Typography level="body-xs" color="danger">
            {errors.email}
          </Typography>
        )}

        <FormControl error={!!errors.agreeToTerms}>
          <Checkbox
            label="이용약관 및 개인정보처리방침에 동의합니다"
            checked={formData.agreeToTerms}
            onChange={(e) => setFormData((prev) => ({ ...prev, agreeToTerms: e.target.checked }))}
            required
          />
          {errors.agreeToTerms && (
            <FormHelperText>
              <InfoOutlinedIcon />
              {errors.agreeToTerms}
            </FormHelperText>
          )}
        </FormControl>

        <Checkbox
          label="뉴스레터 구독하기"
          checked={formData.subscribeNewsletter}
          onChange={(e) => setFormData((prev) => ({ ...prev, subscribeNewsletter: e.target.checked }))}
          color="success"
          variant="soft"
        />

        <Button type="submit">가입하기</Button>
      </Stack>
    </form>
  );
}
```

### Data Table Row Selection

데이터 테이블에서 행 선택에 사용하는 예제입니다.

```tsx
function DataTableWithSelection() {
  const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());

  const users = [
    { id: 1, name: '김철수', email: 'kim@example.com', role: '관리자' },
    { id: 2, name: '이영희', email: 'lee@example.com', role: '사용자' },
    { id: 3, name: '박민수', email: 'park@example.com', role: '사용자' },
  ];

  const handleRowSelect = (id: number) => {
    const newSelected = new Set(selectedRows);
    if (newSelected.has(id)) {
      newSelected.delete(id);
    } else {
      newSelected.add(id);
    }
    setSelectedRows(newSelected);
  };

  const handleSelectAll = (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.checked) {
      setSelectedRows(new Set(users.map((user) => user.id)));
    } else {
      setSelectedRows(new Set());
    }
  };

  return (
    <Stack spacing={2}>
      {selectedRows.size > 0 && (
        <Alert color="primary">
          {selectedRows.size}개 항목이 선택되었습니다.
          <Button size="sm" variant="soft" sx={{ ml: 2 }}>
            선택 항목 삭제
          </Button>
        </Alert>
      )}

      <Table>
        <thead>
          <tr>
            <th style={{ width: 48 }}>
              <Checkbox
                size="sm"
                checked={selectedRows.size === users.length}
                indeterminate={selectedRows.size > 0 && selectedRows.size < users.length}
                onChange={handleSelectAll}
              />
            </th>
            <th>이름</th>
            <th>이메일</th>
            <th>역할</th>
          </tr>
        </thead>
        <tbody>
          {users.map((user) => (
            <tr key={user.id}>
              <td>
                <Checkbox size="sm" checked={selectedRows.has(user.id)} onChange={() => handleRowSelect(user.id)} />
              </td>
              <td>{user.name}</td>
              <td>{user.email}</td>
              <td>{user.role}</td>
            </tr>
          ))}
        </tbody>
      </Table>
    </Stack>
  );
}
```

## Props and Customization

### Colors

다양한 색상을 적용할 수 있습니다.

```tsx
<Stack spacing={2}>
  <Checkbox label="Primary" color="primary" checked />
  <Checkbox label="Success" color="success" checked />
  <Checkbox label="Warning" color="warning" checked />
  <Checkbox label="Danger" color="danger" checked />
  <Checkbox label="Neutral" color="neutral" checked />
</Stack>
```

### Sizes

체크박스의 크기를 조절할 수 있습니다.

```tsx
<Stack direction="row" spacing={2} alignItems="center">
  <Checkbox label="Small" size="sm" checked />
  <Checkbox label="Medium" size="md" checked />
  <Checkbox label="Large" size="lg" checked />
</Stack>
```

### Variants

다양한 시각적 스타일을 적용할 수 있습니다.

```tsx
<Stack spacing={2}>
  <Checkbox label="Solid" variant="solid" checked />
  <Checkbox label="Soft" variant="soft" checked />
  <Checkbox label="Outlined" variant="outlined" checked />
  <Checkbox label="Plain" variant="plain" checked />
</Stack>
```

## States

### Indeterminate State

부분적으로 선택된 상태를 나타낼 때 사용합니다.

```tsx
<Checkbox label="부분 선택됨" indeterminate={true} onChange={handleChange} />
```

### Disabled State

비활성 상태의 체크박스입니다.

```tsx
<Stack spacing={1}>
  <Checkbox label="비활성 (선택 안됨)" disabled />
  <Checkbox label="비활성 (선택됨)" disabled checked />
  <Checkbox label="비활성 (부분 선택)" disabled indeterminate />
</Stack>
```

### Error State

오류 상태를 표시할 때 사용합니다.

```tsx
<FormControl error>
  <Checkbox label="필수 동의 항목" required onChange={handleChange} />
  <FormHelperText>
    <InfoOutlinedIcon />이 항목은 필수로 선택해야 합니다.
  </FormHelperText>
</FormControl>
```

## Best Practices

1. **명확한 라벨**: 체크박스가 무엇을 의미하는지 명확하게 표시하세요.

```tsx
// ✅ 명확한 라벨
<Checkbox label="마케팅 정보 수신에 동의합니다" />

// ❌ 모호한 라벨
<Checkbox label="동의" />
```

2. **적절한 그룹화**: 관련된 체크박스들은 논리적으로 그룹화하세요.

```tsx
<Stack spacing={3}>
  <Typography level="title-md">알림 설정</Typography>
  <Stack spacing={1} sx={{ pl: 1 }}>
    <Checkbox label="이메일 알림" />
    <Checkbox label="SMS 알림" />
    <Checkbox label="푸시 알림" />
  </Stack>
</Stack>
```

3. **필수/선택 구분**: 필수 선택 항목과 선택사항을 명확히 구분하세요.

```tsx
<Checkbox
  label={<><strong>(필수)</strong> 이용약관에 동의</>}
  required
/>
<Checkbox
  label="(선택) 뉴스레터 구독"
  color="neutral"
/>
```

4. **상태 피드백**: 사용자가 선택한 내용을 명확히 보여주세요.

```tsx
{
  selectedCount > 0 && (
    <Typography level="body-sm" color="primary">
      {selectedCount}개 항목이 선택되었습니다.
    </Typography>
  );
}
```

## Accessibility

Checkbox 컴포넌트는 다음과 같은 접근성 기능을 제공합니다:

### 키보드 탐색

- **Tab**: 체크박스로 포커스 이동
- **Space**: 체크박스 선택/해제
- **Enter**: 링크나 버튼 라벨이 있는 경우 활성화

### ARIA 속성

- `role="checkbox"`: 체크박스 역할 정의
- `aria-checked`: 현재 선택 상태 표시
- `aria-describedby`: 추가 설명과 연결

### 추가 접근성 고려사항

```tsx
<Checkbox
  label="마케팅 정보 수신 동의"
  aria-describedby="marketing-description"
/>
<FormHelperText id="marketing-description">
  새로운 제품이나 할인 정보를 이메일로 받아보실 수 있습니다.
</FormHelperText>
```

## Performance Considerations

1. **상태 최적화**: 큰 목록에서는 상태 관리를 효율적으로 하세요.

```tsx
// ✅ Set을 사용한 효율적인 선택 관리
const [selected, setSelected] = useState(new Set<number>());

// ❌ 배열로 관리하는 비효율적 방법
const [selected, setSelected] = useState<number[]>([]);
```

2. **메모이제이션**: 복잡한 핸들러는 useCallback으로 메모이제이션하세요.

3. **가상화**: 매우 긴 목록에서는 가상화를 고려하세요.

Checkbox는 사용자가 다중 선택을 할 수 있는 직관적인 인터페이스를 제공하는 핵심 입력 컴포넌트입니다. 적절한 라벨링과 그룹화를 통해 명확하고 사용하기 쉬운 선택 인터페이스를 만들 수 있습니다.
