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

77 lines
2.5 KiB
React

import React from "react";
/**
* Styled select built on a native <select> for accessibility.
*/
export function Select({
label,
value,
onChange,
options = [],
disabled = false,
size = "md",
fullWidth = true,
style = {},
...rest
}) {
const [focus, setFocus] = React.useState(false);
const height = size === "sm" ? "var(--control-h-sm)" : "var(--control-h)";
const opts = options.map((o) => (typeof o === "string" ? { value: o, label: o } : o));
return (
<label style={{ display: "block", width: fullWidth ? "100%" : "auto" }}>
{label && (
<span style={{ display: "block", marginBottom: "6px", font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)", color: "var(--text-secondary)" }}>
{label}
</span>
)}
<span
style={{
position: "relative",
display: "flex",
alignItems: "center",
height,
background: "var(--ctv-bg-sunken)",
border: `1px solid ${focus ? "var(--action-primary)" : "var(--border-control)"}`,
borderRadius: "var(--radius-sm)",
boxShadow: focus ? "0 0 0 3px var(--focus-ring)" : "none",
transition: "border-color var(--dur-fast), box-shadow var(--dur-fast)",
opacity: disabled ? 0.5 : 1,
...style,
}}
>
<select
value={value}
onChange={onChange}
disabled={disabled}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
style={{
appearance: "none",
WebkitAppearance: "none",
flex: 1,
height: "100%",
padding: "0 30px 0 10px",
background: "transparent",
border: "none",
outline: "none",
color: "var(--text-primary)",
font: "var(--weight-normal) var(--text-sm)/1 var(--font-sans)",
cursor: disabled ? "not-allowed" : "pointer",
}}
{...rest}
>
{opts.map((o) => (
<option key={o.value} value={o.value} style={{ background: "var(--ctv-surface-2)", color: "var(--text-primary)" }}>
{o.label}
</option>
))}
</select>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" style={{ position: "absolute", right: 9, pointerEvents: "none", color: "var(--text-disabled)" }}>
<path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</label>
);
}