'use client' import { ComponentPropsWithoutRef, ElementRef, createRef, forwardRef, useEffect, useRef, } from 'react' import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from './../../ui/src/components/shadcn/ui/command' import { Popover, PopoverAnchor, PopoverContent } from './../../ui/src/components/shadcn/ui/popover' import { cn } from './../../ui/src/lib/utils/cn' const AssistantCommandsPopover = forwardRef< ElementRef, ComponentPropsWithoutRef & { /* The children to render - this is where the AssistantChatForm should be placed */ children: React.ReactNode /* The ref for the textarea - used with the AssistantChatForm */ textAreaRef: React.RefObject /* The function to handle the value change */ setValue: (value: string) => void /* The value of the textarea */ value: string /* Whether the popover is open */ open: boolean /* The function to handle the popover open state */ setOpen: (value: boolean) => void /* The suggestions to display in the popover */ suggestions?: string[] /* Whether an icon is being used in the AssistantChatForm */ usingIcon?: boolean /* Available commands in suggestions popover */ commands?: string[] } >( ( { children, textAreaRef, setValue, value, open, setOpen, suggestions, usingIcon = false, commands = ['fix', 'improve', 'explain', 'help'], ...props }, ref ) => { const popoverContentRef = createRef() const commandWidth = popoverContentRef.current?.clientWidth const targetInputRef = useRef(null) useEffect(() => { // Attach the event listener when the component mounts if (textAreaRef.current) { textAreaRef.current.addEventListener('keydown', handleKeyPress) } // Detach the event listener when the component unmounts return () => { if (textAreaRef.current) { textAreaRef.current.removeEventListener('keydown', handleKeyPress) } // Detach the event listener when the component unmounts } }, []) // Empty dependency array means this effect runs once when the component mounts const handleKeyPress = (event: KeyboardEvent) => { if (event.key === '/' && !value) { // Add your action here setOpen(true) if (textAreaRef) textAreaRef?.current?.focus() } else if (event.key === 'Escape') { // Add your action here setOpen(false) } else if (event.key === 'Backspace') { // Add your action here setOpen(false) } else { if (event.key === 'ArrowUp' || event.key === 'ArrowDown' || event.key === 'Enter') { // Forward the event to the target input if (targetInputRef.current) { const keyboardEvent = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, composed: true, key: event.key, code: event.code, }) targetInputRef.current.dispatchEvent(keyboardEvent) // Schedule focus on the original input using requestAnimationFrame requestAnimationFrame(() => { if (textAreaRef.current) { textAreaRef.current.focus() } }) // Prevent the default behavior for ArrowUp, ArrowDown, and Enter event.preventDefault() } } } } const resultArray = value.split(/(\s+)/).filter(Boolean) return ( <> { setOpen(!open) if (textAreaRef) textAreaRef?.current?.focus() }} {...props} > <>
{resultArray.map((item, i) => ( {item === ' ' ? '\u00A0' : item} ))}
{children}
{ event.preventDefault() }} > No results found. {suggestions?.map((suggestion, idx) => ( { setValue(`${suggestion}`) // closing of the popover is handled by the keydown event in AssistantChatForm }} > {suggestion} ))} {commands.map((command, idx) => ( { setValue(`/${command} `) // closing of the popover is handled by the keydown event in AssistantChatForm }} > / {command} ))}
) } ) export { AssistantCommandsPopover }