pswui/packages/cli/src/components/SearchBox.tsx
p-sw f16a2c9564 refactor(cli): optimize SearchBox setState calls
State setting logic for SearchBox in the CLI package has been streamlined. Redundant setState calls have been eliminated while others are more appropriately placed for better state management. This refactor focuses on the selected and queryMode states. Improved handling of selection state enhances component efficiency.
2024-06-08 05:05:20 +09:00

104 lines
2.9 KiB
TypeScript

import React, {useEffect, useState} from 'react'
import {getSuggestion} from '../helpers/search.js'
import Input from 'ink-text-input'
import {Divider} from './Divider.js'
import {Box, Text, useInput, useApp, type Key} from 'ink'
export function SearchBox<T extends {key: string; displayName: string}>({
components,
helper,
initialQuery,
onKeyDown,
onChange,
onSubmit,
}: {
components: T[]
helper: string
initialQuery?: string
onKeyDown?: (i: string, k: Key, app: ReturnType<typeof useApp>) => void
onChange?: (item: T) => void
onSubmit?: (item: T) => void
}) {
const [query, setQuery] = useState<string>(initialQuery ?? '')
const [queryMode, setQueryMode] = useState<boolean>(true)
const [isLoading, setLoading] = useState<boolean>(false)
const [suggestions, setSuggestions] = useState<string[]>([])
const [selected, setSelected] = useState<number>(-1)
useEffect(() => {
if (queryMode) {
setLoading(true)
getSuggestion(
components.map(({key}) => key),
query,
).then((result) => {
setSuggestions(result)
setSelected(-1)
})
}
}, [query, queryMode])
useEffect(() => {
if (onChange) {
const found = components.find(({key}) => key === suggestions[selected])
found && onChange(found)
}
}, [selected, suggestions, onChange])
const app = useApp()
useInput((i, k) => {
if (k.downArrow) {
setSelected((p) => (p >= suggestions.length - 1 ? 0 : p + 1))
setQueryMode(false)
}
if (k.upArrow) {
setSelected((p) => (p <= 0 ? suggestions.length - 1 : p - 1))
setQueryMode(false)
}
onKeyDown?.(i, k, app)
})
useEffect(() => {
if (!queryMode && suggestions[selected]) {
setQuery(suggestions[selected])
}
}, [queryMode, selected])
return (
<Box width={50} display={'flex'} flexDirection={'column'}>
<Text color={'gray'}>{helper}</Text>
<Box display={'flex'} flexDirection={'row'}>
<Box marginRight={1} display={'flex'} flexDirection={'row'}>
<Text color={'greenBright'}>Search?</Text>
</Box>
<Input
value={query}
onChange={(v) => {
setQueryMode(true)
setQuery(v)
}}
showCursor
placeholder={' query'}
onSubmit={() => {
const found = components.find(({key}) => key === suggestions[selected])
found && onSubmit?.(found)
}}
/>
</Box>
<Divider title={isLoading ? 'Loading...' : `${suggestions.length} components found.`} />
<Box display={'flex'} flexDirection={'column'}>
{suggestions.map((name, index) => {
return (
<Box key={name}>
<Text color={selected === index ? undefined : 'gray'}>
{components[components.findIndex(({key}) => key === name)].displayName}
</Text>
</Box>
)
})}
</Box>
</Box>
)
}