From 2e91fbf0a2a2a244d0155218700ed59089585520 Mon Sep 17 00:00:00 2001 From: brendandebeasi Date: Tue, 12 May 2026 19:20:54 -0700 Subject: [PATCH 1/2] feat(ai): add enterToSubmit prop to ChatComposer Lets consumers opt into modifier-based send (Enter for newline, Cmd/Ctrl/Alt+Enter to send) instead of Enter-to-send. Defaults to true so existing usage is unchanged. Also guards against IME composition events. --- packages/ai/src/ChatComposer.tsx | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/ai/src/ChatComposer.tsx b/packages/ai/src/ChatComposer.tsx index e3380ef..5ffc13d 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,23 @@ 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(); + onSend(); + } else if (hasSubmitModifier) { + event.preventDefault(); + onSend(); + } + }; + return ( <> {heading && ( @@ -80,12 +99,7 @@ export function ChatComposer({