|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
import clsx from 'clsx';
|
|
|
|
|
import type { InputHTMLAttributes } from 'react';
|
|
|
|
|
import { Fragment, useState } from 'react';
|
|
|
|
|
import { Combobox, Transition } from '@headlessui/react';
|
|
|
|
|
import { ChevronDownIcon } from '@heroicons/react/20/solid';
|
|
|
|
@ -10,8 +11,18 @@ export type TypeaheadOption = Readonly<{
|
|
|
|
|
value: string;
|
|
|
|
|
}>;
|
|
|
|
|
|
|
|
|
|
type Attributes = Pick<
|
|
|
|
|
InputHTMLAttributes<HTMLInputElement>,
|
|
|
|
|
| 'disabled'
|
|
|
|
|
| 'name'
|
|
|
|
|
| 'onBlur'
|
|
|
|
|
| 'onFocus'
|
|
|
|
|
| 'pattern'
|
|
|
|
|
| 'placeholder'
|
|
|
|
|
| 'required'
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
type Props = Readonly<{
|
|
|
|
|
disabled?: boolean;
|
|
|
|
|
isLabelHidden?: boolean;
|
|
|
|
|
label: string;
|
|
|
|
|
noResultsMessage?: string;
|
|
|
|
@ -22,9 +33,9 @@ type Props = Readonly<{
|
|
|
|
|
) => void;
|
|
|
|
|
onSelect: (option: TypeaheadOption) => void;
|
|
|
|
|
options: ReadonlyArray<TypeaheadOption>;
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
value?: TypeaheadOption;
|
|
|
|
|
}>;
|
|
|
|
|
}> &
|
|
|
|
|
Readonly<Attributes>;
|
|
|
|
|
|
|
|
|
|
export default function Typeahead({
|
|
|
|
|
disabled = false,
|
|
|
|
@ -34,9 +45,10 @@ export default function Typeahead({
|
|
|
|
|
nullable = false,
|
|
|
|
|
options,
|
|
|
|
|
onQueryChange,
|
|
|
|
|
required,
|
|
|
|
|
value,
|
|
|
|
|
onSelect,
|
|
|
|
|
placeholder,
|
|
|
|
|
...props
|
|
|
|
|
}: Props) {
|
|
|
|
|
const [query, setQuery] = useState('');
|
|
|
|
|
return (
|
|
|
|
@ -68,6 +80,12 @@ export default function Typeahead({
|
|
|
|
|
: 'mb-1 block text-sm font-medium text-slate-700',
|
|
|
|
|
)}>
|
|
|
|
|
{label}
|
|
|
|
|
{required && (
|
|
|
|
|
<span aria-hidden="true" className="text-danger-500">
|
|
|
|
|
{' '}
|
|
|
|
|
*
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</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 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 sm:text-sm">
|
|
|
|
@ -79,11 +97,12 @@ export default function Typeahead({
|
|
|
|
|
displayValue={(option) =>
|
|
|
|
|
(option as unknown as TypeaheadOption)?.label
|
|
|
|
|
}
|
|
|
|
|
placeholder={placeholder}
|
|
|
|
|
required={required}
|
|
|
|
|
onChange={(event) => {
|
|
|
|
|
setQuery(event.target.value);
|
|
|
|
|
onQueryChange(event.target.value, event);
|
|
|
|
|
}}
|
|
|
|
|
{...props}
|
|
|
|
|
/>
|
|
|
|
|
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
|
|
|
|
|
<ChevronDownIcon
|
|
|
|
|