supermemory/packages/ui/shadcn/combobox.tsx
2024-08-12 12:40:28 -07:00

120 lines
2.9 KiB
TypeScript

"use client";
import { useState } from "react";
import { Button } from "./button";
import {
Command,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "./command";
import { cn } from "../lib/utils";
interface Option {
value: string;
label: string;
}
interface ComboboxWithCreateProps {
options: Option[];
onSelect: (value: string) => void;
onSubmit: (newName: string) => void;
selectedSpaces: number[];
setSelectedSpaces: React.Dispatch<React.SetStateAction<number[]>>;
className?: string;
placeholder?: string;
}
const ComboboxWithCreate = ({
options,
onSelect,
onSubmit,
selectedSpaces,
setSelectedSpaces,
className,
placeholder,
}: ComboboxWithCreateProps) => {
const [inputValue, setInputValue] = useState("");
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (
e.key === "Backspace" &&
inputValue === "" &&
selectedSpaces.length > 0
) {
setSelectedSpaces((prev) => prev.slice(0, -1));
}
};
const filteredOptions = options.filter(
(option) => !selectedSpaces.includes(parseInt(option.value)),
);
return (
<Command
className={cn(
`group flex bg-[#2F353C] h-min rounded-md ${selectedSpaces.length > 0 && "p-2"} transition-all mt-4 mb-4`,
className,
)}
>
<div className="inline-flex flex-wrap gap-1">
{selectedSpaces.map((spaceId) => (
<button
key={spaceId}
type="button"
onClick={() =>
setSelectedSpaces((prev) => prev.filter((id) => id !== spaceId))
}
className="relative group rounded-md py-1 px-2 bg-[#3C464D] max-w-32"
>
<p className="line-clamp-1">
{options.find((opt) => opt.value === spaceId.toString())?.label}
</p>
</button>
))}
</div>
<CommandInput
onChangeCapture={handleInputChange}
onKeyDown={handleKeyDown}
placeholder={placeholder}
value={inputValue}
/>
<CommandList
className={`z-10 translate-x-5 opacity-0 transition-all absolute group-focus-within:opacity-100 bg-secondary p-2 rounded-b-xl max-w-64 ${selectedSpaces.length > 0 ? "translate-y-20" : "translate-y-12"}`}
>
<CommandGroup className="hidden group-focus-within:block">
{filteredOptions.map((option) => (
<CommandItem
key={option.value}
onSelect={() => onSelect(option.value)}
>
{option.label}
</CommandItem>
))}
{!options.map((opt) => opt.label).includes(inputValue) && (
<Button
className="px-1"
type="button"
onClick={() => onSubmit(inputValue)}
variant="link"
disabled={inputValue.length < 1}
>
{inputValue.length > 0 ? (
<>Create - "{inputValue}"</>
) : (
<>Type to create a new space</>
)}
</Button>
)}
</CommandGroup>
</CommandList>
</Command>
);
};
export default ComboboxWithCreate;