77 lines
2.5 KiB
React
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>
|
|
);
|
|
}
|