({
className,
error,
label,
onChange,
shouldFilter,
setFilter,
isFetching,
users,
value,
}: InnerAutocompleteProps<T>)
| 138 | }; |
| 139 | |
| 140 | const InnerAutocomplete = <T extends SelectedUser>({ |
| 141 | className, |
| 142 | error, |
| 143 | label, |
| 144 | onChange, |
| 145 | shouldFilter, |
| 146 | setFilter, |
| 147 | isFetching, |
| 148 | users, |
| 149 | value, |
| 150 | }: InnerAutocompleteProps<T>) => { |
| 151 | const DEBOUNCE_MS = 750; |
| 152 | |
| 153 | const [open, setOpen] = useState(false); |
| 154 | const [inputValue, setInputValue] = useState(""); |
| 155 | const id = useId(); |
| 156 | const debouncedInputValue = useDebouncedValue(inputValue, DEBOUNCE_MS); |
| 157 | const { debounced: debouncedSetFilter, cancelDebounce } = |
| 158 | useDebouncedFunction((nextFilter: string) => { |
| 159 | setFilter(nextFilter); |
| 160 | }, DEBOUNCE_MS); |
| 161 | |
| 162 | const selectedInputValue = value?.email ?? value?.username ?? ""; |
| 163 | const selectedFilterValue = value?.username ?? ""; |
| 164 | // Keep spinner only while typing away from the selected value. |
| 165 | const isLoadingOptions = |
| 166 | selectedInputValue !== inputValue && |
| 167 | ((inputValue !== "" && debouncedInputValue !== inputValue) || isFetching); |
| 168 | |
| 169 | const handleOpenChange = (nextOpen: boolean) => { |
| 170 | setOpen(nextOpen); |
| 171 | cancelDebounce(); |
| 172 | if (nextOpen) { |
| 173 | setInputValue(selectedInputValue); |
| 174 | setFilter(selectedFilterValue); |
| 175 | return; |
| 176 | } |
| 177 | setInputValue(""); |
| 178 | setFilter(undefined); |
| 179 | }; |
| 180 | |
| 181 | return ( |
| 182 | <div className={cn("flex flex-col gap-2", className)}> |
| 183 | {label && <Label htmlFor={id}>{label}</Label>} |
| 184 | <Combobox |
| 185 | value={value?.username} |
| 186 | onValueChange={(newValue) => { |
| 187 | if (!newValue) { |
| 188 | onChange(null); |
| 189 | return; |
| 190 | } |
| 191 | onChange(users?.find((user) => user.username === newValue) ?? null); |
| 192 | }} |
| 193 | open={open} |
| 194 | onOpenChange={handleOpenChange} |
| 195 | > |
| 196 | <ComboboxTrigger asChild> |
| 197 | <Button variant="outline"> |
nothing calls this directly
no test coverage detected