102 lines
2.3 KiB
TypeScript
102 lines
2.3 KiB
TypeScript
import { useState } from "react";
|
|
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
|
|
export interface DropdownSelectorOption<T extends string> {
|
|
value: T;
|
|
label: string;
|
|
}
|
|
|
|
interface DropdownSelectorProps<T extends string> {
|
|
value: T;
|
|
options: DropdownSelectorOption<T>[];
|
|
onChange: (value: T) => void;
|
|
triggerClassName?: string;
|
|
contentClassName?: string;
|
|
}
|
|
|
|
function ChevronDownIcon() {
|
|
return (
|
|
<svg
|
|
width="10"
|
|
height="6"
|
|
viewBox="0 0 10 6"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
d="M0.75 0.75L4.75 4.75L8.75 0.75"
|
|
stroke="#666666"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
function ChevronUpIcon() {
|
|
return (
|
|
<svg
|
|
width="10"
|
|
height="6"
|
|
viewBox="0 0 10 6"
|
|
fill="none"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
d="M0.75 4.75L4.75 0.75L8.75 4.75"
|
|
stroke="#666666"
|
|
strokeWidth="1.5"
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
/>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
export function DropdownSelector<T extends string>({
|
|
value,
|
|
options,
|
|
onChange,
|
|
triggerClassName,
|
|
contentClassName,
|
|
}: DropdownSelectorProps<T>) {
|
|
const selectedOption = options.find((opt) => opt.value === value);
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
return (
|
|
<DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
|
|
<DropdownMenuTrigger
|
|
className={
|
|
triggerClassName ??
|
|
"border-none bg-transparent shadow-none select-none focus:outline-none"
|
|
}
|
|
>
|
|
<span className="flex items-center gap-1">
|
|
{selectedOption?.label ?? value}
|
|
{isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
|
</span>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent className={contentClassName}>
|
|
<DropdownMenuRadioGroup
|
|
value={value}
|
|
onValueChange={(v) => onChange(v as T)}
|
|
>
|
|
{options.map((option) => (
|
|
<DropdownMenuRadioItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</DropdownMenuRadioItem>
|
|
))}
|
|
</DropdownMenuRadioGroup>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|