deerflow2/frontend/src/components/ui/dropdown-selector.tsx

109 lines
2.6 KiB
TypeScript

import { useState } from "react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn, truncateMiddle } from "@/lib/utils";
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 ??
"flex w-full justify-center overflow-hidden border-none bg-transparent text-ellipsis whitespace-nowrap shadow-none select-none focus:outline-none"
}
>
<span className="flex w-full items-center justify-center gap-1">
{truncateMiddle(selectedOption?.label ?? value, 30)}
{isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
</span>
</DropdownMenuTrigger>
<DropdownMenuContent
className={cn(contentClassName, "max-w-80 p-[20px]")}
>
<DropdownMenuRadioGroup
value={value}
onValueChange={(v) => onChange(v as T)}
>
{options.map((option) => (
<DropdownMenuRadioItem
key={option.value}
value={option.value}
title={option.label}
>
{truncateMiddle(option.label)}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
);
}