#1 feat: add configurable Enter key behavior for message input

- Add enterKeyBehavior setting to config schema (shift-enter-send | enter-send)
- Implement Enter key behavior toggle in SettingsControls component
- Update ChatInput to respect user's Enter key preference
- Support IME composition to prevent accidental sends during Japanese input
- Add dynamic placeholder text based on selected behavior

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nepula_h_okuyama
2025-09-11 22:48:01 +09:00
parent 1e6030bd52
commit e37ca87887
5 changed files with 76 additions and 5 deletions

View File

@@ -2,6 +2,7 @@ import { AlertCircleIcon, LoaderIcon, SendIcon } from "lucide-react";
import { type FC, useCallback, useId, useRef, useState } from "react";
import { Button } from "../../../../../components/ui/button";
import { Textarea } from "../../../../../components/ui/textarea";
import { useConfig } from "../../../../hooks/useConfig";
import type { CommandCompletionRef } from "./CommandCompletion";
import type { FileCompletionRef } from "./FileCompletion";
import { InlineCompletion } from "./InlineCompletion";
@@ -42,6 +43,7 @@ export const ChatInput: FC<ChatInputProps> = ({
const commandCompletionRef = useRef<CommandCompletionRef>(null);
const fileCompletionRef = useRef<FileCompletionRef>(null);
const helpId = useId();
const { config } = useConfig();
const handleSubmit = async () => {
if (!message.trim()) return;
@@ -58,9 +60,19 @@ export const ChatInput: FC<ChatInputProps> = ({
return;
}
if (e.key === "Enter" && e.shiftKey) {
e.preventDefault();
handleSubmit();
// IMEで変換中の場合は送信しない
if (e.key === "Enter" && !e.nativeEvent.isComposing) {
const isEnterSend = config?.enterKeyBehavior === "enter-send";
if (isEnterSend && !e.shiftKey) {
// Enter: Send mode
e.preventDefault();
handleSubmit();
} else if (!isEnterSend && e.shiftKey) {
// Shift+Enter: Send mode (default)
e.preventDefault();
handleSubmit();
}
}
};

View File

@@ -1,4 +1,5 @@
import type { FC } from "react";
import { useConfig } from "../../../../hooks/useConfig";
import { ChatInput, useNewChatMutation } from "../chatForm";
export const NewChat: FC<{
@@ -6,18 +7,27 @@ export const NewChat: FC<{
onSuccess?: () => void;
}> = ({ projectId, onSuccess }) => {
const startNewChat = useNewChatMutation(projectId, onSuccess);
const { config } = useConfig();
const handleSubmit = async (message: string) => {
await startNewChat.mutateAsync({ message });
};
const getPlaceholder = () => {
const isEnterSend = config?.enterKeyBehavior === "enter-send";
if (isEnterSend) {
return "Type your message here... (Start with / for commands, @ for files, Enter to send)";
}
return "Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)";
};
return (
<ChatInput
projectId={projectId}
onSubmit={handleSubmit}
isPending={startNewChat.isPending}
error={startNewChat.error}
placeholder="Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)"
placeholder={getPlaceholder()}
buttonText="Start Chat"
minHeight="min-h-[200px]"
containerClassName="space-y-4"

View File

@@ -1,4 +1,5 @@
import type { FC } from "react";
import { useConfig } from "../../../../../../hooks/useConfig";
import {
ChatInput,
useResumeChatMutation,
@@ -11,6 +12,7 @@ export const ResumeChat: FC<{
isRunningTask: boolean;
}> = ({ projectId, sessionId, isPausedTask, isRunningTask }) => {
const resumeChat = useResumeChatMutation(projectId, sessionId);
const { config } = useConfig();
const handleSubmit = async (message: string) => {
await resumeChat.mutateAsync({ message });
@@ -23,6 +25,14 @@ export const ResumeChat: FC<{
return "Resume";
};
const getPlaceholder = () => {
const isEnterSend = config?.enterKeyBehavior === "enter-send";
if (isEnterSend) {
return "Type your message... (Start with / for commands, Enter to send)";
}
return "Type your message... (Start with / for commands, Shift+Enter to send)";
};
return (
<div className="border-t border-border/50 bg-muted/20 p-4 mt-6">
<ChatInput
@@ -30,7 +40,7 @@ export const ResumeChat: FC<{
onSubmit={handleSubmit}
isPending={resumeChat.isPending}
error={resumeChat.error}
placeholder="Type your message... (Start with / for commands, Shift+Enter to send)"
placeholder={getPlaceholder()}
buttonText={getButtonText()}
minHeight="min-h-[100px]"
containerClassName="space-y-2"