Files
ersatztv/design-system/components/forms/Switch.jsx
T
2026-07-02 07:37:00 +02:00

49 lines
1.6 KiB
React

import React from "react";
/**
* On/off toggle switch.
*/
export function Switch({ checked = false, onChange, disabled = false, label, size = "md", style = {} }) {
const w = size === "sm" ? 30 : 36;
const h = size === "sm" ? 17 : 20;
const knob = h - 5;
const toggle = () => { if (!disabled && onChange) onChange(!checked); };
return (
<label style={{ display: "inline-flex", alignItems: "center", gap: "9px", cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1, ...style }}>
<span
role="switch"
aria-checked={checked}
onClick={toggle}
style={{
position: "relative",
width: w,
height: h,
flex: "0 0 auto",
borderRadius: "var(--radius-pill)",
background: checked ? "var(--action-primary)" : "var(--ctv-surface-3)",
border: `1px solid ${checked ? "transparent" : "var(--border-control)"}`,
transition: "background var(--dur-base) var(--ease-standard)",
}}
>
<span
style={{
position: "absolute",
top: "50%",
left: checked ? `calc(100% - ${knob + 2}px)` : "2px",
transform: "translateY(-50%)",
width: knob,
height: knob,
borderRadius: "50%",
background: "#fff",
boxShadow: "0 1px 2px rgba(0,0,0,0.5)",
transition: "left var(--dur-base) var(--ease-out)",
}}
/>
</span>
{label && <span style={{ font: "var(--text-sm)/1 var(--font-sans)", color: "var(--text-primary)" }}>{label}</span>}
</label>
);
}