pswui/packages/cli/src/components/SearchBox.tsx
p-sw 12b1d530c4 refactor(cli): change onSubmit typing in SearchBox
The onSubmit function typing in the SearchBox component was changed from handling a string to handling a generic T type object. Also, the onSubmit function now uses the found item in components based on the selected suggestion to submit instead of submitting directly.
2024-06-08 02:51:27 +09:00

103 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>(0)
useEffect(() => {
if (queryMode) {
setLoading(true)
getSuggestion(
components.map(({key}) => key),
query,
).then((result) => {
setSuggestions(result)
setLoading(false)
if (result.length <= selected) {
setSelected(result.length - 1)
}
})
}
}, [query, queryMode])
useEffect(() => {
if (onChange) {
const found = components.find(({key}) => key === suggestions[selected])
found && onChange(found)
}
if (suggestions[selected]) {
setQueryMode(false)
setQuery(suggestions[selected] ?? '')
}
}, [selected, suggestions, onChange])
const app = useApp()
useInput((i, k) => {
if (k.downArrow) {
setSelected((p) => (p >= suggestions.length - 1 ? 0 : p + 1))
}
if (k.upArrow) {
setSelected((p) => (p <= 0 ? suggestions.length - 1 : p - 1))
}
onKeyDown?.(i, k, app)
})
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>
)
}