# Switch

## Introduction

Switch 컴포넌트는 사용자가 옵션을 켜고 끌 수 있는 토글 형태의 입력 요소입니다. Joy UI의 Switch를 기반으로 하며, 다양한 크기, 색상, 장식 요소를 지원합니다. 설정 화면, 기능 활성화/비활성화, 모드 전환 등에 주로 사용됩니다.

```tsx
<Switch />
```

| Field          | Description | Default |
| -------------- | ----------- | ------- |
| variant        | —           | —       |
| color          | —           | —       |
| size           | —           | —       |
| startDecorator | —           | —       |
| endDecorator   | —           | —       |
| checked        | —           | —       |

## Usage

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

function MyComponent() {
  const [enabled, setEnabled] = useState(false);

  return <Switch checked={enabled} onChange={(e) => setEnabled(e.target.checked)} />;
}
```

## Examples

### Basic Usage

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

```tsx
<Switch />
```

### With Labels

라벨과 함께 사용하는 Switch입니다. 폼 컨트롤 내에서 설명과 함께 사용할 수 있습니다.

```tsx
<FormControl orientation="horizontal" sx={{
  width: 300,
  justifyContent: 'space-between'
}}>
<div>
  <FormLabel>Show captions</FormLabel>
  <FormHelperText sx={{
    mt: 0
  }}>All languages available.</FormHelperText>
</div>
<Switch checked={checked} onChange={e => setChecked(e.target.checked)} color={checked ? 'success' : 'neutral'} variant={checked ? 'solid' : 'outlined'} endDecorator={checked ? 'On' : 'Off'} slotProps={{
  endDecorator: {
    sx: {
      minWidth: 24
    }
  }
}} />
</FormControl>
```

### Inline Labels

인라인 형태로 텍스트와 함께 사용할 수 있습니다.

```tsx
<Typography component="label" endDecorator={<Switch sx={{
  ml: 1
}} />}>
Turn alarm on
</Typography>
```

### With Decorators

아이콘이나 다른 요소를 장식으로 추가할 수 있습니다.

```tsx
<Switch color={dark ? 'primary' : 'danger'} slotProps={{
  input: {
    'aria-label': 'dark mode'
  }
}} startDecorator={<LightModeIcon sx={theme => ({
  color: dark ? 'currentColor' : 'var(--ceed-palette-danger-solidBg)'
})} />} endDecorator={<DarkModeIcon sx={theme => ({
  color: dark ? 'var(--ceed-palette-primary-solidBg)' : 'currentColor'
})} />} checked={dark} onChange={event => setDark(event.target.checked)} />
```

### Track Children

트랙 내부에 텍스트나 다른 요소를 표시할 수 있습니다.

```tsx
<Stack direction="row" spacing={4}>
  <Switch {...args} slotProps={{
    track: {
      children: <React.Fragment>
      <Typography component="span" level="inherit" sx={{
        ml: '10px'
      }}>
      On
    </Typography>
    <Typography component="span" level="inherit" sx={{
      mr: '8px'
    }}>
    Off
  </Typography>
</React.Fragment>
}
}} sx={{
  '--Switch-thumbSize': '27px',
  '--Switch-trackWidth': '64px',
  '--Switch-trackHeight': '31px'
}} />
<Switch color="success" slotProps={{
  track: {
    children: <React.Fragment>
    <span>I</span>
    <span>0</span>
  </React.Fragment>,
  sx: {
    justifyContent: 'space-around'
  }
}
}} sx={{
  '--Switch-thumbSize': '27px',
  '--Switch-trackWidth': '52px',
  '--Switch-trackHeight': '31px'
}} />
</Stack>
```

### Thumb Children

썸(토글 버튼) 내부에 아이콘을 표시할 수 있습니다.

```tsx
<Switch size="lg" slotProps={{
  input: {
    'aria-label': 'Dark mode'
  },
  thumb: {
    children: <DarkModeIcon fontSize="inherit" />
  }
}} sx={{
  '--Switch-thumbSize': '16px'
}} />
```

## Common Use Cases

### Settings Panel

설정 패널에서 기능을 활성화/비활성화할 때 사용합니다.

```tsx
<Stack spacing={3}>
  <FormControl orientation="horizontal" sx={{ width: 400, justifyContent: 'space-between' }}>
    <div>
      <FormLabel>알림 받기</FormLabel>
      <FormHelperText sx={{ mt: 0 }}>새로운 메시지가 도착했을 때 알림을 받습니다.</FormHelperText>
    </div>
    <Switch checked={notifications} onChange={(e) => setNotifications(e.target.checked)} color="success" />
  </FormControl>

  <FormControl orientation="horizontal" sx={{ width: 400, justifyContent: 'space-between' }}>
    <div>
      <FormLabel>자동 저장</FormLabel>
      <FormHelperText sx={{ mt: 0 }}>작업 내용을 자동으로 저장합니다.</FormHelperText>
    </div>
    <Switch checked={autoSave} onChange={(e) => setAutoSave(e.target.checked)} />
  </FormControl>
</Stack>
```

### Theme Toggle

다크 모드/라이트 모드 전환에 자주 사용됩니다.

```tsx
function ThemeToggle() {
  const [darkMode, setDarkMode] = useState(false);

  return (
    <Switch
      checked={darkMode}
      onChange={(e) => setDarkMode(e.target.checked)}
      color={darkMode ? 'primary' : 'danger'}
      startDecorator={<LightModeIcon />}
      endDecorator={<DarkModeIcon />}
      slotProps={{
        input: { 'aria-label': '다크 모드 토글' },
      }}
    />
  );
}
```

### Feature Flags

기능의 활성화/비활성화를 제어할 때 사용합니다.

```tsx
<Card>
  <CardContent>
    <Typography level="title-md" sx={{ mb: 2 }}>
      실험적 기능
    </Typography>

    <Stack spacing={2}>
      <FormControl orientation="horizontal" sx={{ justifyContent: 'space-between' }}>
        <FormLabel>베타 기능 활성화</FormLabel>
        <Switch
          checked={betaFeatures}
          onChange={(e) => setBetaFeatures(e.target.checked)}
          color="warning"
          endDecorator={betaFeatures ? 'On' : 'Off'}
        />
      </FormControl>

      <FormControl orientation="horizontal" sx={{ justifyContent: 'space-between' }}>
        <FormLabel>고급 모드</FormLabel>
        <Switch checked={advancedMode} onChange={(e) => setAdvancedMode(e.target.checked)} disabled={!betaFeatures} />
      </FormControl>
    </Stack>
  </CardContent>
</Card>
```

### List Items with Switches

목록 아이템에서 각 항목을 개별적으로 제어할 때 사용합니다.

```tsx
<List>
  {permissions.map((permission) => (
    <ListItem
      key={permission.id}
      endAction={
        <Switch
          checked={permission.enabled}
          onChange={(e) => handlePermissionToggle(permission.id, e.target.checked)}
          size="sm"
          color={permission.enabled ? 'success' : 'neutral'}
        />
      }
    >
      <ListItemContent>
        <Typography level="title-sm">{permission.name}</Typography>
        <Typography level="body-sm" color="neutral">
          {permission.description}
        </Typography>
      </ListItemContent>
    </ListItem>
  ))}
</List>
```

### Controlled Form

폼 상태 관리와 함께 사용하는 예제입니다.

```tsx
function UserPreferences() {
  const [preferences, setPreferences] = useState({
    emailNotifications: true,
    smsNotifications: false,
    pushNotifications: true,
    darkMode: false,
  });

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

  return (
    <form onSubmit={handleSubmit}>
      <Stack spacing={3}>
        <Typography level="h4">알림 설정</Typography>

        <Stack spacing={2}>
          <Typography
            component="label"
            endDecorator={
              <Switch
                checked={preferences.emailNotifications}
                onChange={handleToggle('emailNotifications')}
                sx={{ ml: 1 }}
              />
            }
          >
            이메일 알림
          </Typography>

          <Typography
            component="label"
            endDecorator={
              <Switch
                checked={preferences.smsNotifications}
                onChange={handleToggle('smsNotifications')}
                sx={{ ml: 1 }}
              />
            }
          >
            SMS 알림
          </Typography>

          <Typography
            component="label"
            endDecorator={
              <Switch
                checked={preferences.pushNotifications}
                onChange={handleToggle('pushNotifications')}
                sx={{ ml: 1 }}
              />
            }
          >
            푸시 알림
          </Typography>
        </Stack>

        <Divider />

        <Typography
          component="label"
          endDecorator={
            <Switch
              checked={preferences.darkMode}
              onChange={handleToggle('darkMode')}
              startDecorator={<LightModeIcon />}
              endDecorator={<DarkModeIcon />}
              sx={{ ml: 1 }}
            />
          }
        >
          다크 모드
        </Typography>

        <Button type="submit">설정 저장</Button>
      </Stack>
    </form>
  );
}
```

## Props and Customization

### Colors

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

```tsx
<Stack direction="row" spacing={2}>
  <Switch color="primary" checked />
  <Switch color="success" checked />
  <Switch color="warning" checked />
  <Switch color="danger" checked />
  <Switch color="neutral" checked />
</Stack>
```

### Sizes

스위치의 크기를 조절할 수 있습니다.

```tsx
<Stack direction="row" spacing={2} alignItems="center">
  <Switch size="sm" checked />
  <Switch size="md" checked />
  <Switch size="lg" checked />
</Stack>
```

### Variants

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

```tsx
<Stack direction="row" spacing={2}>
  <Switch variant="solid" checked />
  <Switch variant="soft" checked />
  <Switch variant="outlined" checked />
  <Switch variant="plain" checked />
</Stack>
```

### Custom Styling

CSS 변수를 통해 세밀한 커스터마이징이 가능합니다.

```tsx
<Switch
  checked={customSwitch}
  onChange={(e) => setCustomSwitch(e.target.checked)}
  sx={{
    '--Switch-thumbSize': '24px',
    '--Switch-trackWidth': '60px',
    '--Switch-trackHeight': '32px',
    '--Switch-trackRadius': '16px',
    '--Switch-thumbRadius': '12px',
  }}
/>
```

## States

### Disabled State

비활성 상태의 스위치입니다.

```tsx
<Stack direction="row" spacing={2}>
  <Switch disabled />
  <Switch disabled checked />
</Stack>
```

### Loading/Processing State

처리 중일 때의 시각적 피드백을 제공할 수 있습니다.

```tsx
function ProcessingSwitch() {
  const [processing, setProcessing] = useState(false);
  const [enabled, setEnabled] = useState(false);

  const handleToggle = async (event: React.ChangeEvent<HTMLInputElement>) => {
    setProcessing(true);
    try {
      // API 호출 시뮬레이션
      await new Promise((resolve) => setTimeout(resolve, 1000));
      setEnabled(event.target.checked);
    } finally {
      setProcessing(false);
    }
  };

  return (
    <Switch
      checked={enabled}
      onChange={handleToggle}
      disabled={processing}
      endDecorator={processing ? 'Processing...' : enabled ? 'On' : 'Off'}
    />
  );
}
```

## Best Practices

1. **명확한 라벨**: 스위치가 무엇을 제어하는지 명확하게 표시하세요.

```tsx
// ✅ 명확한 라벨
<Typography component="label" endDecorator={<Switch />}>
  이메일 알림 받기
</Typography>

// ❌ 모호한 라벨
<Typography component="label" endDecorator={<Switch />}>
  설정
</Typography>
```

2. **즉시 효과**: 스위치 토글은 즉시 효과가 나타나야 합니다.

3. **적절한 색상 사용**:
   - 일반적인 기능: `primary` 또는 기본 색상
   - 성공/활성화: `success`
   - 주의사항: `warning`
   - 위험한 기능: `danger`

4. **상태 표시**: 현재 상태를 명확히 보여주는 장식 요소를 활용하세요.

```tsx
<Switch
  checked={enabled}
  onChange={handleChange}
  endDecorator={enabled ? '켜짐' : '꺼짐'}
  color={enabled ? 'success' : 'neutral'}
/>
```

5. **그룹화**: 관련된 스위치들은 논리적으로 그룹화하세요.

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

## Accessibility

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

### 키보드 탐색

- **Tab**: 스위치로 포커스 이동
- **Space**: 스위치 토글
- **Enter**: 스위치 토글 (라벨이 연결된 경우)

### ARIA 속성

- `role="switch"`: 스위치 역할 정의
- `aria-checked`: 현재 상태 표시
- `aria-label` 또는 `aria-labelledby`: 접근 가능한 이름 제공

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

```tsx
<Switch
  slotProps={{
    input: {
      'aria-label': '다크 모드 활성화',
      'aria-describedby': 'dark-mode-description',
    },
  }}
/>
<FormHelperText id="dark-mode-description">
  화면을 어둡게 표시하여 눈의 피로를 줄입니다.
</FormHelperText>
```

### 색상 대비 및 시각적 표시

```tsx
// 색상에만 의존하지 않고 텍스트 표시도 함께 제공
<Switch
  checked={enabled}
  onChange={handleChange}
  endDecorator={
    <Typography level="body-xs" sx={{ minWidth: 32 }}>
      {enabled ? 'ON' : 'OFF'}
    </Typography>
  }
/>
```

## Performance Considerations

1. **상태 최적화**: 불필요한 리렌더링을 방지하기 위해 상태를 적절히 관리하세요.

```tsx
// ✅ 개별 상태 관리
const [emailNotify, setEmailNotify] = useState(false);
const [smsNotify, setSmsNotify] = useState(false);

// ❌ 전체 객체 업데이트로 인한 불필요한 리렌더링
const [settings, setSettings] = useState({ email: false, sms: false });
```

2. **비동기 처리**: API 호출이 필요한 경우 적절한 로딩 상태를 제공하세요.

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

Switch는 직관적이고 접근 가능한 토글 인터페이스를 제공하는 핵심 입력 컴포넌트입니다. 적절한 라벨링과 시각적 피드백을 통해 사용자 친화적인 설정 및 제어 인터페이스를 만들 수 있습니다.
