diff --git a/apps/web/src/components/auto-complete-input.tsx b/apps/web/src/components/auto-complete-input.tsx
index 24c86d8..3c698fd 100644
--- a/apps/web/src/components/auto-complete-input.tsx
+++ b/apps/web/src/components/auto-complete-input.tsx
@@ -1,26 +1,22 @@
+'use client'
+
import * as React from 'react'
-import { CheckIcon, ChevronsUpDownIcon, SearchIcon } from 'lucide-react'
+import { CheckIcon } from 'lucide-react'
-import { Button } from '@cfdm/ui/components/button'
-import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
-} from '@cfdm/ui/components/command'
-import {
- Popover,
- PopoverContent,
- PopoverTrigger,
-} from '@cfdm/ui/components/popover'
import { cn } from '@cfdm/ui/lib/utils'
+import {
+ Autocomplete,
+ AutocompleteContent,
+ AutocompleteEmpty,
+ AutocompleteInput,
+ AutocompleteItem,
+ AutocompleteList,
+} from '@/components/reui/autocomplete'
export interface AutoCompleteOption {
value: string
label: string
- /** Левый префикс (например эмодзи-флаг). */
+ /** Левый префикс (например флаг страны). */
leading?: React.ReactNode
}
@@ -33,7 +29,7 @@ interface AutoCompleteInputProps {
searchPlaceholder?: string
emptyText?: string
className?: string
- /** Показывать ли выбранный leading в триггере (например флаг). */
+ /** Показывать ли выбранный leading в поле (например флаг). */
showLeadingInInput?: boolean
/** Разрешать ли произвольный ввод (не только из списка). По умолчанию true. */
allowFreeText?: boolean
@@ -45,107 +41,88 @@ export function AutoCompleteInput({
onChange,
options,
placeholder = 'Выбрать…',
- searchPlaceholder = 'Поиск…',
+ searchPlaceholder,
emptyText = 'Ничего не найдено',
className,
showLeadingInInput = true,
allowFreeText = true,
}: AutoCompleteInputProps) {
- const [open, setOpen] = React.useState(false)
- const [query, setQuery] = React.useState('')
+ const trimmedValue = value.trim()
- const filtered = React.useMemo(() => {
- const q = query.trim().toLowerCase()
- if (!q) return options
- return options.filter(
- (o) => o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q),
- )
- }, [options, query])
-
- const selected = options.find(
- (o) => o.value.toLowerCase() === value.trim().toLowerCase(),
+ const selected = React.useMemo(
+ () => options.find((o) => o.value.toLowerCase() === trimmedValue.toLowerCase()),
+ [options, trimmedValue],
)
- const displayLabel = selected?.label ?? value
const leading = showLeadingInInput ? selected?.leading : undefined
- const handleSelect = (next: string) => {
- onChange(next)
- setQuery('')
- setOpen(false)
- }
+ const inputPlaceholder = searchPlaceholder ?? placeholder
+
+ const handleValueChange = React.useCallback(
+ (inputVal: string) => {
+ const q = inputVal.trim()
+ const match = options.find(
+ (o) =>
+ o.label.toLowerCase() === q.toLowerCase() ||
+ o.value.toLowerCase() === q.toLowerCase(),
+ )
+ if (match) {
+ onChange(match.value)
+ return
+ }
+ if (allowFreeText) {
+ onChange(inputVal)
+ }
+ },
+ [options, onChange, allowFreeText],
+ )
return (
-