veza/apps/web/src/components/ui/switch.tsx
senke 27107245a6 ui(components): migrate Switch, Toast, LoadingSpinner to design system
Switch:
- w-[44px] h-[24px] → w-11 h-6 (exact Tailwind equivalents)
- bg-kodo-cyan/kodo-steel → bg-primary/bg-muted (design system tokens)
- ring-kodo-cyan/kodo-void → ring-ring/ring-offset-background

Toast:
- min-w-[300px] → min-w-72 (288px, closest Tailwind value)

LoadingSpinner:
- min-h-[200px] → min-h-48 (192px)
- border-t-blue-600 → border-t-primary (design system token)
- border-kodo-steel → border-muted

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 22:56:36 +01:00

100 lines
2.6 KiB
TypeScript

import * as React from 'react';
import { cn } from '@/lib/utils';
/**
* SwitchProps - Propriétés du composant Switch
*
* @interface SwitchProps
* @extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>
*/
export interface SwitchProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
/**
* État checked du switch
*
* @example
* ```tsx
* <Switch checked={isEnabled} onCheckedChange={setIsEnabled} />
* ```
*/
checked?: boolean;
/**
* Fonction appelée lorsque l'état checked change
*
* @param {boolean} checked - Nouvel état checked
*
* @example
* ```tsx
* <Switch onCheckedChange={(checked) => console.log('Switch:', checked)} />
* ```
*/
onCheckedChange?: (checked: boolean) => void;
}
/**
* Switch - Composant d'interrupteur avec design system Kodo
*
* Composant d'interrupteur (toggle) pour activer/désactiver une option.
* Utilise le design system Kodo avec une animation de transition fluide.
*
* @example
* ```tsx
* // Switch simple
* <Switch />
*
* // Switch contrôlé
* <Switch
* checked={isEnabled}
* onCheckedChange={setIsEnabled}
* />
*
* // Switch désactivé
* <Switch disabled />
* ```
*
* @component
* @param {SwitchProps} props - Propriétés du composant
* @returns {JSX.Element} Élément label contenant un switch stylisé
*/
const Switch = React.forwardRef<HTMLInputElement, SwitchProps>(
({ className, checked, onCheckedChange, disabled, ...props }, ref) => {
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (onCheckedChange) {
onCheckedChange(e.target.checked);
}
};
return (
<label
className={cn(
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors',
'focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background',
'disabled:cursor-not-allowed disabled:opacity-50',
checked ? 'bg-primary' : 'bg-muted',
className,
)}
>
<input
ref={ref}
type="checkbox"
className="sr-only"
checked={checked}
onChange={handleChange}
disabled={disabled}
{...props}
/>
<span
className={cn(
'pointer-events-none block h-5 w-5 rounded-full bg-white shadow-lg ring-0 transition-transform',
checked ? 'translate-x-5' : 'translate-x-0',
)}
/>
</label>
);
},
);
Switch.displayName = 'Switch';
export { Switch };