import * as React from "react" import { SearchIcon, XIcon } from "lucide-react" import { cn } from "../core/cn" interface CommandItem { value: string label: string description?: string icon?: React.ReactNode disabled?: boolean group?: string } interface CommandProps { items: CommandItem[] value?: string onValueChange?: (value: string) => void placeholder?: string emptyMessage?: string className?: string inputClassName?: string listClassName?: string } function Command({ className, ...props }: React.ComponentPropsWithoutRef<"div">) { return (
) } function CommandInput({ className, ...props }: React.ComponentPropsWithoutRef<"input">) { return (
) } function CommandList({ className, ...props }: React.ComponentPropsWithoutRef<"div">) { return (
) } function CommandEmpty({ className, ...props }: React.ComponentPropsWithoutRef<"div">) { return (
) } function CommandGroup({ className, heading, ...props }: React.ComponentPropsWithoutRef<"div"> & { heading?: string }) { return (
{heading && (
{heading}
)}
) } function CommandSeparator({ className, ...props }: React.ComponentPropsWithoutRef<"div">) { return (
) } interface CommandItemProps extends React.ComponentPropsWithoutRef<"div"> { selected?: boolean disabled?: boolean onSelect?: () => void } function CommandItem({ className, selected, disabled, onSelect, ...props }: CommandItemProps) { return (
) } function CommandShortcut({ className, ...props }: React.ComponentPropsWithoutRef<"span">) { return ( ) } function CommandSearch({ items, value, onValueChange, placeholder = "Search...", emptyMessage = "No results found.", className, }: CommandProps) { const [query, setQuery] = React.useState("") const [selectedValue, setSelectedValue] = React.useState(value ?? "") const filtered = React.useMemo(() => { if (!query) return items const q = query.toLowerCase() return items.filter( (item) => item.label.toLowerCase().includes(q) || item.description?.toLowerCase().includes(q) || item.value.toLowerCase().includes(q) ) }, [items, query]) const groups = React.useMemo(() => { const map = new Map() for (const item of filtered) { const key = item.group ?? "" if (!map.has(key)) map.set(key, []) map.get(key)!.push(item) } return map }, [filtered]) const handleSelect = (val: string) => { setSelectedValue(val) onValueChange?.(val) } return ( setQuery(e.target.value)} placeholder={placeholder} /> {filtered.length === 0 ? ( {emptyMessage} ) : ( Array.from(groups.entries()).map(([group, groupItems]) => ( {groupItems.map((item) => ( handleSelect(item.value)} > {item.icon && {item.icon}} {item.label} {item.description && ( {item.description} )} ))} )) )} ) } export { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSearch, CommandSeparator, CommandShortcut } export type { CommandItem, CommandProps }