|
|
|
@ -10,6 +10,7 @@ export type TypeaheadOption = Readonly<{
|
|
|
|
|
label: string;
|
|
|
|
|
value: string;
|
|
|
|
|
}>;
|
|
|
|
|
export type TypeaheadTextSize = 'default' | 'inherit';
|
|
|
|
|
|
|
|
|
|
type Attributes = Pick<
|
|
|
|
|
InputHTMLAttributes<HTMLInputElement>,
|
|
|
|
@ -33,10 +34,16 @@ type Props = Readonly<{
|
|
|
|
|
) => void;
|
|
|
|
|
onSelect: (option: TypeaheadOption) => void;
|
|
|
|
|
options: ReadonlyArray<TypeaheadOption>;
|
|
|
|
|
textSize?: TypeaheadTextSize;
|
|
|
|
|
value?: TypeaheadOption;
|
|
|
|
|
}> &
|
|
|
|
|
Readonly<Attributes>;
|
|
|
|
|
|
|
|
|
|
const textSizes: Record<TypeaheadTextSize, string> = {
|
|
|
|
|
default: 'text-sm',
|
|
|
|
|
inherit: '',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default function Typeahead({
|
|
|
|
|
disabled = false,
|
|
|
|
|
isLabelHidden,
|
|
|
|
@ -46,12 +53,14 @@ export default function Typeahead({
|
|
|
|
|
options,
|
|
|
|
|
onQueryChange,
|
|
|
|
|
required,
|
|
|
|
|
textSize = 'default',
|
|
|
|
|
value,
|
|
|
|
|
onSelect,
|
|
|
|
|
...props
|
|
|
|
|
}: Props) {
|
|
|
|
|
const [query, setQuery] = useState('');
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<Combobox
|
|
|
|
|
by="id"
|
|
|
|
|
disabled={disabled}
|
|
|
|
@ -77,7 +86,10 @@ export default function Typeahead({
|
|
|
|
|
className={clsx(
|
|
|
|
|
isLabelHidden
|
|
|
|
|
? 'sr-only'
|
|
|
|
|
: 'mb-1 block text-sm font-medium text-slate-700',
|
|
|
|
|
: clsx(
|
|
|
|
|
'mb-1 block font-medium text-slate-700',
|
|
|
|
|
textSizes[textSize],
|
|
|
|
|
),
|
|
|
|
|
)}>
|
|
|
|
|
{label}
|
|
|
|
|
{required && (
|
|
|
|
@ -88,10 +100,15 @@ export default function Typeahead({
|
|
|
|
|
)}
|
|
|
|
|
</Combobox.Label>
|
|
|
|
|
<div className="relative">
|
|
|
|
|
<div className="focus-visible:ring-offset-primary-300 relative w-full cursor-default overflow-hidden rounded-lg border border-slate-300 bg-white text-left text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2">
|
|
|
|
|
<div
|
|
|
|
|
className={clsx(
|
|
|
|
|
'focus-visible:ring-offset-primary-300 relative w-full cursor-default overflow-hidden rounded-lg border border-slate-300 bg-white text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2',
|
|
|
|
|
textSizes[textSize],
|
|
|
|
|
)}>
|
|
|
|
|
<Combobox.Input
|
|
|
|
|
className={clsx(
|
|
|
|
|
'w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-slate-900 focus:ring-0',
|
|
|
|
|
'w-full border-none py-2 pl-3 pr-10 leading-5 text-slate-900 focus:ring-0',
|
|
|
|
|
textSizes[textSize],
|
|
|
|
|
disabled && 'pointer-events-none select-none bg-slate-100',
|
|
|
|
|
)}
|
|
|
|
|
displayValue={(option) =>
|
|
|
|
@ -117,7 +134,11 @@ export default function Typeahead({
|
|
|
|
|
leave="transition ease-in duration-100"
|
|
|
|
|
leaveFrom="opacity-100"
|
|
|
|
|
leaveTo="opacity-0">
|
|
|
|
|
<Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
|
|
|
|
<Combobox.Options
|
|
|
|
|
className={clsx(
|
|
|
|
|
'absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none',
|
|
|
|
|
textSizes[textSize],
|
|
|
|
|
)}>
|
|
|
|
|
{options.length === 0 && query !== '' ? (
|
|
|
|
|
<div className="relative cursor-default select-none py-2 px-4 text-slate-700">
|
|
|
|
|
{noResultsMessage}
|
|
|
|
@ -149,5 +170,6 @@ export default function Typeahead({
|
|
|
|
|
</Transition>
|
|
|
|
|
</div>
|
|
|
|
|
</Combobox>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|