Files
srbhr--resume-matcher/apps/frontend/components/ui/toggle-switch.tsx
T
wehub-resource-sync 5bdf4cc89a
Publish Docker Image / publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:36 +08:00

81 lines
2.1 KiB
TypeScript

'use client';
import * as React from 'react';
import { cn } from '@/lib/utils';
/**
* Swiss International Style Toggle Switch Component
*
* Design Principles:
* - Square corners (rounded-none on container, pill shape for toggle)
* - High contrast states
* - Clear label and description
*/
export interface ToggleSwitchProps {
checked: boolean;
onCheckedChange: (checked: boolean) => void;
label: string;
description?: string;
disabled?: boolean;
className?: string;
}
export const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
checked,
onCheckedChange,
label,
description,
disabled = false,
className,
}) => {
const labelId = React.useId();
const handleToggle = () => {
if (!disabled) {
onCheckedChange(!checked);
}
};
return (
<div
className={cn(
'flex items-center justify-between p-4 border border-black bg-white',
'shadow-sw-sm',
disabled && 'opacity-50 cursor-not-allowed',
className
)}
>
<div className="flex-1 mr-4">
<div id={labelId} className="font-mono text-sm font-bold uppercase tracking-wider">
{label}
</div>
{description && <div className="font-sans text-xs text-steel-grey mt-1">{description}</div>}
</div>
<button
type="button"
role="switch"
aria-checked={checked}
aria-labelledby={labelId}
disabled={disabled}
onClick={handleToggle}
className={cn(
'relative inline-flex h-6 w-12 shrink-0 cursor-pointer items-center',
'border-2 border-black transition-colors',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-700 focus-visible:ring-offset-2',
'disabled:cursor-not-allowed',
checked ? 'bg-blue-700' : 'bg-paper-tint'
)}
>
<span
className={cn(
'pointer-events-none block h-4 w-4 bg-white border border-black',
'transition-transform duration-200',
checked ? 'translate-x-6' : 'translate-x-1'
)}
/>
</button>
</div>
);
};