Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
File size: 1,838 Bytes
5ae37d4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | "use client";
interface Option {
id: string;
label: string;
}
interface Props {
value: string;
options: Option[];
onChange: (id: string) => void;
/** matches the 40px display type of the surrounding sentence */
size?: "display" | "inline";
ariaLabel: string;
}
/**
* A dropdown that reads as part of a sentence. The native <select> is layered
* transparently over the rendered text so it stays keyboard and screen-reader
* navigable while looking like body copy.
*/
export default function SentenceSelect({
value,
options,
onChange,
size = "display",
ariaLabel,
}: Props) {
const current = options.find((o) => o.id === value) ?? options[0];
const display = size === "display";
return (
<span
className={`relative inline-flex items-center gap-2.5 rounded-md bg-paper ring-raised ${
display ? "h-[52px] px-3.5" : "h-9 px-3"
}`}
>
<span
className={
display
? "text-[40px] font-medium leading-[44px] tracking-[-0.04em] text-obsidian"
: "font-mono text-[13px] text-obsidian"
}
>
{current.label}
</span>
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
aria-hidden
className="shrink-0"
>
<path
d="M3 4.5L6 7.5L9 4.5"
stroke="#8f8f8f"
strokeWidth="1.4"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<select
aria-label={ariaLabel}
value={value}
onChange={(e) => onChange(e.target.value)}
className="absolute inset-0 cursor-pointer opacity-0"
>
{options.map((o) => (
<option key={o.id} value={o.id}>
{o.label}
</option>
))}
</select>
</span>
);
}
|