49 lines
1.6 KiB
React
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>
|
|
);
|
|
}
|