feat(web): searchable combobox (Base UI) for term/authority options (#27)
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function ComboboxRoot<Value>(props: ComboboxPrimitive.Root.Props<Value>) {
|
||||
return <ComboboxPrimitive.Root data-slot="combobox" {...props} />;
|
||||
}
|
||||
|
||||
function ComboboxInputGroup({ className, ...props }: ComboboxPrimitive.InputGroup.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.InputGroup
|
||||
data-slot="combobox-input-group"
|
||||
className={cn("relative flex items-center", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxInput({ className, ...props }: ComboboxPrimitive.Input.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Input
|
||||
data-slot="combobox-input"
|
||||
className={cn("w-full rounded border px-2 py-1 pr-12 text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Clear
|
||||
data-slot="combobox-clear"
|
||||
className={cn(
|
||||
"absolute right-6 text-neutral-400 hover:text-neutral-700",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxTrigger({ className, ...props }: ComboboxPrimitive.Trigger.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Trigger
|
||||
data-slot="combobox-trigger"
|
||||
className={cn("absolute right-1 text-neutral-500", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxPopup({ className, ...props }: ComboboxPrimitive.Popup.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Portal>
|
||||
<ComboboxPrimitive.Positioner sideOffset={4} className="z-50">
|
||||
<ComboboxPrimitive.Popup
|
||||
data-slot="combobox-popup"
|
||||
className={cn(
|
||||
"max-h-64 min-w-48 overflow-auto rounded border bg-white p-1 text-sm shadow-md",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</ComboboxPrimitive.Positioner>
|
||||
</ComboboxPrimitive.Portal>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.List
|
||||
data-slot="combobox-list"
|
||||
className={cn("flex flex-col gap-0.5", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxItem({ className, ...props }: ComboboxPrimitive.Item.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Item
|
||||
data-slot="combobox-item"
|
||||
className={cn(
|
||||
"flex cursor-default items-center gap-2 rounded px-2 py-1 data-[highlighted]:bg-indigo-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxItemIndicator({ className, ...props }: ComboboxPrimitive.ItemIndicator.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.ItemIndicator
|
||||
data-slot="combobox-item-indicator"
|
||||
className={cn("invisible data-[highlighted]:invisible [[data-selected]_&]:visible", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) {
|
||||
return (
|
||||
<ComboboxPrimitive.Empty
|
||||
data-slot="combobox-empty"
|
||||
className={cn("px-2 py-1 text-neutral-500", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
ComboboxRoot,
|
||||
ComboboxInputGroup,
|
||||
ComboboxInput,
|
||||
ComboboxClear,
|
||||
ComboboxTrigger,
|
||||
ComboboxPopup,
|
||||
ComboboxList,
|
||||
ComboboxItem,
|
||||
ComboboxItemIndicator,
|
||||
ComboboxEmpty,
|
||||
};
|
||||
Reference in New Issue
Block a user