'use client';
import { ChevronDown } from 'lucide-react';
import React from 'react';
import {
Select as AriaSelect,
SelectProps as AriaSelectProps,
Button,
ListBox,
ListBoxItemProps,
SelectValue,
ValidationResult
} from 'react-aria-components';
import { tv } from 'tailwind-variants';
import { Description, FieldError, Label } from '@/registry/react-aria/ui/Field';
import { DropdownItem, DropdownSection, DropdownSectionProps } from '@/registry/react-aria/ui/ListBox';
import { Popover } from '@/registry/react-aria/ui/Popover';
import { composeTailwindRenderProps, focusRing } from '@/registry/react-aria/lib/react-aria-utils';
const styles = tv({
extend: focusRing,
base: 'flex items-center text-start gap-4 w-full font-sans border border-black/10 dark:border-white/10 cursor-default rounded-lg pl-3 pr-2 h-9 min-w-[180px] transition bg-neutral-50 dark:bg-neutral-700 [-webkit-tap-highlight-color:transparent]',
variants: {
isDisabled: {
false: 'text-neutral-800 dark:text-neutral-300 hover:bg-neutral-100 pressed:bg-neutral-200 dark:hover:bg-neutral-600 dark:pressed:bg-neutral-500 group-invalid:outline group-invalid:outline-red-600 forced-colors:group-invalid:outline-[Mark]',
true: 'border-transparent dark:border-transparent text-neutral-200 dark:text-neutral-600 forced-colors:text-[GrayText] bg-neutral-100 dark:bg-neutral-800'
}
}
});
export interface SelectProps<T extends object> extends Omit<AriaSelectProps<T>, 'children'> {
label?: string;
description?: string;
errorMessage?: string | ((validation: ValidationResult) => string);
items?: Iterable<T>;
children: React.ReactNode | ((item: T) => React.ReactNode);
}
export function Select<T extends object>(
{ label, description, errorMessage, children, items, ...props }: SelectProps<T>
) {
return (
<AriaSelect {...props} className={composeTailwindRenderProps(props.className, 'group flex flex-col gap-1 relative font-sans')}>
{label && <Label>{label}</Label>}
<Button className={styles}>
<SelectValue className="flex-1 text-sm">
{({selectedText, defaultChildren}) => selectedText || defaultChildren}
</SelectValue>
<ChevronDown aria-hidden className="w-4 h-4 text-neutral-600 dark:text-neutral-400 forced-colors:text-[ButtonText] group-disabled:text-neutral-200 dark:group-disabled:text-neutral-600 forced-colors:group-disabled:text-[GrayText]" />
</Button>
{description && <Description>{description}</Description>}
<FieldError>{errorMessage}</FieldError>
<Popover className="min-w-(--trigger-width)">
<ListBox items={items} className="outline-hidden box-border p-1 max-h-[inherit] overflow-auto [clip-path:inset(0_0_0_0_round_.75rem)]">
{children}
</ListBox>
</Popover>
</AriaSelect>
);
}
export function SelectItem(props: ListBoxItemProps) {
return <DropdownItem {...props} />;
}
export function SelectSection<T extends object>(props: DropdownSectionProps<T>) {
return <DropdownSection {...props} />;
}