[ui][typeahead] add required field

pull/385/head
Yangshun Tay 2 years ago
parent 44f4454d96
commit d38f997701

@ -20,6 +20,9 @@ export default {
placeholder: {
control: 'text',
},
required: {
control: 'boolean',
},
},
component: Typeahead,
parameters: {
@ -80,3 +83,39 @@ Basic.args = {
isLabelHidden: false,
label: 'Author',
};
export function Required() {
const people = [
{ id: '1', label: 'Wade Cooper', value: '1' },
{ id: '2', label: 'Arlene Mccoy', value: '2' },
{ id: '3', label: 'Devon Webb', value: '3' },
{ id: '4', label: 'Tom Cook', value: '4' },
{ id: '5', label: 'Tanya Fox', value: '5' },
{ id: '6', label: 'Hellen Schmidt', value: '6' },
];
const [selectedEntry, setSelectedEntry] = useState<TypeaheadOption>(
people[0],
);
const [query, setQuery] = useState('');
const filteredPeople =
query === ''
? people
: people.filter((person) =>
person.label
.toLowerCase()
.replace(/\s+/g, '')
.includes(query.toLowerCase().replace(/\s+/g, '')),
);
return (
<Typeahead
label="Author"
options={filteredPeople}
required={true}
value={selectedEntry}
onQueryChange={setQuery}
onSelect={setSelectedEntry}
/>
);
}

@ -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

Loading…
Cancel
Save