2026-01-13 14:49:19 +01:00

109 lines
3.4 KiB
TypeScript

import { useMemo, useState } from 'react'
import { getWordSuggestions } from '@/lib/keyManagementBIP39'
import { decideAutocompleteKeyAction } from './autocompleteKeyDecision'
export interface WordAutocompleteState {
suggestions: string[]
showSuggestions: boolean
setShowSuggestions: (value: boolean) => void
selectedIndex: number
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void
handleKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void
applySuggestion: (suggestion: string) => void
}
export function useWordAutocomplete(params: {
value: string
onChange: (value: string) => void
inputRef: React.RefObject<HTMLInputElement | null>
}): WordAutocompleteState {
const [showSuggestions, setShowSuggestions] = useState(false)
const [selectedIndex, setSelectedIndex] = useState(-1)
const suggestions = useWordSuggestions(params.value)
const applySuggestion = (suggestion: string): void => {
applySuggestionImpl({ suggestion, onChange: params.onChange, setShowSuggestions, inputRef: params.inputRef })
}
const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
handleChangeImpl({ event, onChange: params.onChange, setShowSuggestions, setSelectedIndex })
}
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
handleKeyDownImpl({
event,
suggestions,
selectedIndex,
setSelectedIndex,
setShowSuggestions,
inputRef: params.inputRef,
applySuggestion,
})
}
return { suggestions, showSuggestions, setShowSuggestions, selectedIndex, handleChange, handleKeyDown, applySuggestion }
}
function useWordSuggestions(value: string): string[] {
return useMemo((): string[] => {
if (value.length === 0) {
return []
}
return getWordSuggestions(value, 5)
}, [value])
}
function applySuggestionImpl(params: {
suggestion: string
onChange: (value: string) => void
setShowSuggestions: (value: boolean) => void
inputRef: React.RefObject<HTMLInputElement | null>
}): void {
params.onChange(params.suggestion)
params.setShowSuggestions(false)
params.inputRef.current?.blur()
}
function handleChangeImpl(params: {
event: React.ChangeEvent<HTMLInputElement>
onChange: (value: string) => void
setShowSuggestions: (value: boolean) => void
setSelectedIndex: (value: number) => void
}): void {
const newValue = params.event.target.value.trim().toLowerCase()
params.setSelectedIndex(-1)
params.setShowSuggestions(newValue.length > 0)
params.onChange(newValue)
}
function handleKeyDownImpl(params: {
event: React.KeyboardEvent<HTMLInputElement>
suggestions: string[]
selectedIndex: number
setSelectedIndex: (value: number) => void
setShowSuggestions: (value: boolean) => void
inputRef: React.RefObject<HTMLInputElement | null>
applySuggestion: (suggestion: string) => void
}): void {
const decision = decideAutocompleteKeyAction({
key: params.event.key,
selectedIndex: params.selectedIndex,
suggestionsCount: params.suggestions.length,
})
if (decision.action === 'none') {
return
}
params.event.preventDefault()
if (decision.action === 'move') {
params.setSelectedIndex(decision.nextIndex)
return
}
if (decision.action === 'escape') {
params.setShowSuggestions(false)
params.inputRef.current?.blur()
return
}
const suggestion = params.suggestions[decision.index]
if (suggestion) {
params.applySuggestion(suggestion)
}
}