ux: improve stop button visibility and streamline error handling (#10696)

* Restores the send button in the message edit mode

* Makes the stop button more prominent
This commit is contained in:
Bruno Bergher 2026-01-13 18:14:08 +00:00 committed by GitHub
parent 749026a44b
commit 83037104c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,7 +1,7 @@
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
import { useEvent } from "react-use"
import DynamicTextArea from "react-textarea-autosize"
import { VolumeX, Image, WandSparkles, SendHorizontal, MessageSquareX, ListEnd, Square } from "lucide-react"
import { VolumeX, Image, WandSparkles, SendHorizontal, X, ListEnd, Square } from "lucide-react"
import type { ExtensionMessage } from "@roo-code/types"
@ -1148,30 +1148,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
<Image className="w-4 h-4" />
</button>
</StandardTooltip>
<StandardTooltip content={t("chat:enhancePrompt")}>
<button
aria-label={t("chat:enhancePrompt")}
disabled={false}
onClick={handleEnhancePrompt}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-md min-w-[28px] min-h-[28px]",
"text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-1000",
"cursor-pointer",
hasInputContent
? "opacity-50 hover:opacity-100 delay-750 pointer-events-auto"
: "opacity-0 pointer-events-none duration-200 delay-0",
hasInputContent &&
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
hasInputContent && "active:bg-[rgba(255,255,255,0.1)]",
)}>
<WandSparkles className={cn("w-4 h-4", isEnhancingPrompt && "animate-spin")} />
</button>
</StandardTooltip>
{isEditMode && (
{isEditMode ? (
<StandardTooltip content={t("chat:cancel.title")}>
<button
aria-label={t("chat:cancel.title")}
@ -1188,7 +1165,33 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
"active:bg-[rgba(255,255,255,0.1)]",
"cursor-pointer",
)}>
<MessageSquareX className="w-4 h-4" />
<X className="w-4 h-4" />
</button>
</StandardTooltip>
) : (
<StandardTooltip content={t("chat:enhancePrompt")}>
<button
aria-label={t("chat:enhancePrompt")}
disabled={false}
onClick={handleEnhancePrompt}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-md min-w-[28px] min-h-[28px]",
"text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-1000",
"cursor-pointer",
hasInputContent
? "opacity-50 hover:opacity-100 delay-750 pointer-events-auto"
: "opacity-0 pointer-events-none duration-200 delay-0",
hasInputContent &&
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
hasInputContent && "active:bg-[rgba(255,255,255,0.1)]",
)}>
<WandSparkles
className={cn("w-4 h-4", isEnhancingPrompt && "animate-spin")}
/>
</button>
</StandardTooltip>
)}
@ -1215,45 +1218,50 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
</button>
</StandardTooltip>
)}
{/* Send/Stop button - morphs based on streaming state */}
{!isEditMode && (
<StandardTooltip
content={
isStreaming
{/* Send/Stop button - morphs based on streaming state, always visible in edit mode */}
<StandardTooltip
content={
isEditMode
? t("chat:pressToSend", { keyCombination: sendKeyCombination })
: isStreaming
? t("chat:stop.title")
: t("chat:pressToSend", { keyCombination: sendKeyCombination })
}>
<button
aria-label={
isStreaming
}>
<button
aria-label={
isEditMode
? t("chat:pressToSend", { keyCombination: sendKeyCombination })
: isStreaming
? t("chat:stop.title")
: t("chat:pressToSend", { keyCombination: sendKeyCombination })
}
disabled={false}
onClick={isStreaming ? onStop : onSend}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-md min-w-[28px] min-h-[28px]",
"text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-200",
isStreaming || hasInputContent
? "opacity-100 hover:opacity-100 pointer-events-auto"
: "opacity-0 pointer-events-none",
(isStreaming || hasInputContent) &&
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
(isStreaming || hasInputContent) && "active:bg-[rgba(255,255,255,0.1)]",
(isStreaming || hasInputContent) && "cursor-pointer",
)}>
{isStreaming ? (
<Square className="size-4 fill-vscode-descriptionForeground" />
) : (
<SendHorizontal className="size-4" />
)}
</button>
</StandardTooltip>
)}
}
disabled={false}
onClick={isStreaming ? onStop : onSend}
className={cn(
"relative inline-flex items-center justify-center",
"bg-transparent border-none p-1.5",
"rounded-full min-w-[28px] min-h-[28px]",
"text-vscode-descriptionForeground hover:text-vscode-foreground",
"transition-all duration-200",
isEditMode || isStreaming || hasInputContent
? "opacity-100 hover:opacity-100 pointer-events-auto"
: "opacity-0 pointer-events-none",
(isEditMode || isStreaming || hasInputContent) &&
"hover:bg-[rgba(255,255,255,0.03)] hover:border-[rgba(255,255,255,0.15)]",
"focus:outline-none focus-visible:ring-1 focus-visible:ring-vscode-focusBorder",
(isEditMode || isStreaming || hasInputContent) &&
"active:bg-[rgba(255,255,255,0.1)]",
(isEditMode || isStreaming || hasInputContent) && "cursor-pointer",
isStreaming &&
"bg-vscode-button-background hover:bg-vscode-button-background",
)}>
{isStreaming ? (
<Square className="size-4 stroke-none fill-vscode-button-foreground" />
) : (
<SendHorizontal className="size-4" />
)}
</button>
</StandardTooltip>
</div>
{!inputValue && (