diff --git a/packages/ai/src/ChatComposer.tsx b/packages/ai/src/ChatComposer.tsx index e3380ef..4a961f2 100644 --- a/packages/ai/src/ChatComposer.tsx +++ b/packages/ai/src/ChatComposer.tsx @@ -10,7 +10,7 @@ import { usePopover, } from "@spacedrive/primitives"; import {AnimatePresence, motion} from "framer-motion"; -import {type ReactNode} from "react"; +import {type KeyboardEvent, type ReactNode} from "react"; import {ModelSelector} from "./ModelSelector"; import type {ModelOption} from "./types"; @@ -45,6 +45,11 @@ export interface ChatComposerProps { onOpenVoice?: () => void; /** Optional content rendered at the far right of the toolbar (before send) */ toolbarExtra?: ReactNode; + /** + * If true (default), Enter sends and Shift+Enter inserts a newline. + * If false, Enter inserts a newline and Cmd/Ctrl/Alt+Enter sends. + */ + enterToSubmit?: boolean; } /** @@ -62,9 +67,24 @@ export function ChatComposer({ modelSelector, onOpenVoice, toolbarExtra, + enterToSubmit = true, }: ChatComposerProps) { const canSend = !isSending && draft.trim().length > 0; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key !== "Enter" || event.nativeEvent.isComposing) return; + const hasSubmitModifier = event.metaKey || event.ctrlKey || event.altKey; + if (enterToSubmit) { + if (event.shiftKey) return; + event.preventDefault(); + if (canSend) onSend(); + } else if (hasSubmitModifier) { + if (!canSend) return; + event.preventDefault(); + onSend(); + } + }; + return ( <> {heading && ( @@ -80,12 +100,7 @@ export function ChatComposer({