From d3031380a382de059490623160d27e579db82a34 Mon Sep 17 00:00:00 2001 From: Merge Resolver Date: Thu, 21 Aug 2025 17:08:26 -0600 Subject: [PATCH] fix(webview-ui): accessible DisclosureHeader and refactor error/diff_error headers (aria, keyboard, chevron consistency) --- webview-ui/src/components/chat/ChatRow.tsx | 147 +++++------------- .../src/components/chat/DisclosureHeader.tsx | 73 +++++++++ 2 files changed, 115 insertions(+), 105 deletions(-) create mode 100644 webview-ui/src/components/chat/DisclosureHeader.tsx diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index 919530749c..32b61be08d 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -33,7 +33,8 @@ import MarkdownBlock from "../common/MarkdownBlock" import { ReasoningBlock } from "./ReasoningBlock" import Thumbnails from "../common/Thumbnails" import McpResourceRow from "../mcp/McpResourceRow" -import { IconButton } from "./IconButton" + +import { DisclosureHeader } from "./DisclosureHeader" import { Mention } from "./Mention" import { CheckpointSaved } from "./checkpoints/CheckpointSaved" @@ -864,60 +865,29 @@ export const ChatRowContent = ({ overflow: "hidden", marginBottom: "8px", }}> -
{t("chat:diffError.title")}} + expanded={isDiffErrorExpanded} + onToggle={() => setIsDiffErrorExpanded(!isDiffErrorExpanded)} + onCopy={() => { + copyWithFeedback(message.text || "").then((success) => { + if (success) { + setShowCopySuccess(true) + setTimeout(() => { + setShowCopySuccess(false) + }, 1000) + } + }) }} - onClick={() => setIsDiffErrorExpanded(!isDiffErrorExpanded)}> -
- - {t("chat:diffError.title")} -
-
- { - e.stopPropagation() - copyWithFeedback(message.text || "").then((success) => { - if (success) { - setShowCopySuccess(true) - setTimeout(() => { - setShowCopySuccess(false) - }, 1000) - } - }) - }} - style={{ marginRight: "4px" }} - /> - -
-
+ copyTitle={t("chat:codeblock.tooltips.copy_code")} + copyIconClass={showCopySuccess ? "codicon-check" : "codicon-copy"} + /> {isDiffErrorExpanded && (
-
{t("chat:error")}} + expanded={isErrorExpanded} + onToggle={() => setIsErrorExpanded(!isErrorExpanded)} + onCopy={() => { + copyWithFeedback(message.text || "").then((success) => { + if (success) { + setShowErrorCopySuccess(true) + setTimeout(() => { + setShowErrorCopySuccess(false) + }, 1000) + } + }) }} - onClick={() => setIsErrorExpanded(!isErrorExpanded)}> -
- - - {t("chat:error")} - -
-
- { - e.stopPropagation() - copyWithFeedback(message.text || "").then((success) => { - if (success) { - setShowErrorCopySuccess(true) - setTimeout(() => { - setShowErrorCopySuccess(false) - }, 1000) - } - }) - }} - style={{ marginRight: "4px" }} - /> - -
-
+ copyTitle={t("chat:codeblock.tooltips.copy_code")} + copyIconClass={showErrorCopySuccess ? "codicon-check" : "codicon-copy"} + /> {isErrorExpanded && (
void + onCopy?: (e: React.MouseEvent) => void + copyTitle?: string + copyIconClass?: string // e.g. "codicon-copy" | "codicon-check" + className?: string +} + +export const DisclosureHeader: React.FC = ({ + contentId, + iconClass, + iconStyle, + title, + expanded, + onToggle, + onCopy, + copyTitle, + copyIconClass, + className, +}) => { + return ( +
+ + + {onCopy && ( + { + e.stopPropagation() + onCopy(e) + }} + style={{ marginLeft: 4 }} + /> + )} +
+ ) +}