import { Combobox } from '@headlessui/react' import Fuse from 'fuse.js' import { useCommandsContext } from 'hooks/useCommandsContext' import { Command } from 'lib/commandTypes' import { useEffect, useState } from 'react' import { CustomIcon } from './CustomIcon' import { getActorNextEvents } from 'lib/utils' import { sortCommands } from 'lib/commandUtils' function CommandComboBox({ options, placeholder, }: { options: Command[] placeholder?: string }) { const { commandBarSend } = useCommandsContext() const [query, setQuery] = useState('') const [filteredOptions, setFilteredOptions] = useState() const defaultOption = options.find((o) => 'isCurrent' in o && o.isCurrent) || null // sort disabled commands to the bottom const sortedOptions = options .map((command) => ({ command, disabled: optionIsDisabled(command), })) .sort(sortCommands) .map(({ command }) => command) const fuse = new Fuse(sortedOptions, { keys: ['displayName', 'name', 'description'], threshold: 0.3, ignoreLocation: true, }) useEffect(() => { const results = fuse.search(query).map((result) => result.item) setFilteredOptions(query.length > 0 ? results : sortedOptions) }, [query]) function handleSelection(command: Command) { commandBarSend({ type: 'Select command', data: { command } }) } return (
setQuery(event.target.value)} className="w-full bg-transparent focus:outline-none selection:bg-primary/20 dark:selection:bg-primary/40 dark:focus:outline-none" onKeyDown={(event) => { if ( (event.metaKey && event.key === 'k') || (event.key === 'Backspace' && !event.currentTarget.value) ) { event.preventDefault() commandBarSend({ type: 'Close' }) } }} placeholder={ (defaultOption && defaultOption.name) || placeholder || 'Search commands' } autoCapitalize="off" autoComplete="off" autoCorrect="off" spellCheck="false" autoFocus />
{filteredOptions?.map((option) => ( {'icon' in option && option.icon && ( )}

{option.displayName || option.name}{' '}

{option.description && (

{option.description}

)}
))}
) } export default CommandComboBox function optionIsDisabled(option: Command): boolean { return ( 'machineActor' in option && option.machineActor !== undefined && !getActorNextEvents(option.machineActor.getSnapshot()).includes(option.name) ) }