"use client"; import { useChatActions, useChatId } from "@ai-sdk-tools/store"; import { AnimatedSizeContainer } from "@midday/ui/animated-size-container"; import { cn } from "@midday/ui/cn"; import { Icons } from "@midday/ui/icons"; import { type RefObject, useEffect, useRef } from "react"; import { useOnClickOutside } from "usehooks-ts"; import { useChatInterface } from "@/hooks/use-chat-interface"; import { useChatStore } from "@/store/chat"; export function CommandMenu() { const commandListRef = useRef(null); const { filteredCommands, selectedCommandIndex, showCommands, handleCommandSelect, resetCommandState, setInput, setShowCommands, } = useChatStore(); const { sendMessage } = useChatActions(); const chatId = useChatId(); const { setChatId } = useChatInterface(); // Close command menu when clicking outside (but not on the toggle button or input toolbar buttons) useOnClickOutside(commandListRef as RefObject, (event) => { if (showCommands) { const target = event.target as Element; const isToggleButton = target.closest("[data-suggested-actions-toggle]"); // Don't close if clicking on buttons within the PromptInput toolbar // Check if the clicked element is a button or inside a button const clickedButton = target.closest("button"); const isToolbarButton = clickedButton !== null && (clickedButton.closest("form") !== null || clickedButton.type === "button" || clickedButton.type === "submit"); // Only close if it's not the toggle button or toolbar buttons if (!isToggleButton && !isToolbarButton) { setShowCommands(false); } } }); const handleCommandExecution = (command: any) => { if (!chatId) return; setChatId(chatId); sendMessage({ role: "user", parts: [{ type: "text", text: command.title }], metadata: { toolCall: { toolName: command.toolName, toolParams: command.toolParams, }, }, }); setInput(""); resetCommandState(); }; // Scroll selected command into view useEffect(() => { if (commandListRef.current && showCommands) { const selectedElement = commandListRef.current.querySelector( `[data-index="${selectedCommandIndex}"]`, ); if (selectedElement) { selectedElement.scrollIntoView({ block: "nearest" }); } } }, [selectedCommandIndex, showCommands]); if (!showCommands || filteredCommands.length === 0) return null; return (
{filteredCommands.map((command, index) => { const isActive = selectedCommandIndex === index; return (
{ // Prevent input from losing focus when clicking on command e.preventDefault(); }} onClick={() => handleCommandExecution(command)} data-index={index} >
{command.title}
{isActive && ( )}
); })}
); }