diff --git a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx index 85d1b00b4b..44d646fcd8 100644 --- a/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/Reasoning.tsx @@ -1,4 +1,4 @@ -import { memo, useMemo, useState, useCallback, useRef } from 'react'; +import { memo, useMemo, useState, useCallback, useRef, useId } from 'react'; import { useAtom } from 'jotai'; import type { MouseEvent, FocusEvent } from 'react'; import { ContentTypes } from 'librechat-data-provider'; @@ -36,6 +36,7 @@ type ReasoningProps = { * For legacy text-based messages, see Thinking.tsx component. */ const Reasoning = memo(({ reasoning, isLast }: ReasoningProps) => { + const contentId = useId(); const localize = useLocalize(); const [showThinking] = useAtom(showThinkingAtom); const [isExpanded, setIsExpanded] = useState(showThinking); @@ -104,9 +105,14 @@ const Reasoning = memo(({ reasoning, isLast }: ReasoningProps) => { onClick={handleClick} label={label} content={reasoningText} + contentId={contentId} />
{ isExpanded={isExpanded} onClick={handleClick} content={reasoningText} + contentId={contentId} />
diff --git a/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx b/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx index 0c5992f4ab..7641738c15 100644 --- a/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/Thinking.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, memo, useCallback, useRef, type MouseEvent } from 'react'; +import { useState, useMemo, memo, useCallback, useRef, useId, type MouseEvent } from 'react'; import { useAtomValue } from 'jotai'; import { Clipboard, CheckMark, TooltipAnchor } from '@librechat/client'; import { Lightbulb, ChevronDown, ChevronUp } from 'lucide-react'; @@ -35,12 +35,14 @@ export const ThinkingButton = memo( onClick, label, content, + contentId, showCopyButton = true, }: { isExpanded: boolean; onClick: (e: MouseEvent) => void; label: string; content?: string; + contentId: string; showCopyButton?: boolean; }) => { const localize = useLocalize(); @@ -66,6 +68,7 @@ export const ThinkingButton = memo( type="button" onClick={onClick} aria-expanded={isExpanded} + aria-controls={contentId} className={cn( 'group/button flex flex-1 items-center justify-start rounded-lg leading-[18px]', fontSize, @@ -132,11 +135,13 @@ export const FloatingThinkingBar = memo( isExpanded, onClick, content, + contentId, }: { isVisible: boolean; isExpanded: boolean; onClick: (e: MouseEvent) => void; content?: string; + contentId: string; }) => { const localize = useLocalize(); const [isCopied, setIsCopied] = useState(false); @@ -176,6 +181,8 @@ export const FloatingThinkingBar = memo( tabIndex={isVisible ? 0 : -1} onClick={onClick} aria-label={collapseTooltip} + aria-expanded={isExpanded} + aria-controls={contentId} className={cn( 'flex items-center justify-center rounded-lg bg-surface-secondary p-1.5 text-text-secondary-alt shadow-sm', 'hover:bg-surface-hover hover:text-text-primary', @@ -240,6 +247,7 @@ const Thinking: React.ElementType = memo(({ children }: { children: React.ReactN const [isExpanded, setIsExpanded] = useState(showThinking); const [isBarVisible, setIsBarVisible] = useState(false); const containerRef = useRef(null); + const contentId = useId(); const handleClick = useCallback((e: MouseEvent) => { e.preventDefault(); @@ -295,9 +303,14 @@ const Thinking: React.ElementType = memo(({ children }: { children: React.ReactN onClick={handleClick} label={label} content={textContent} + contentId={contentId} />
@@ -322,4 +336,4 @@ ThinkingContent.displayName = 'ThinkingContent'; FloatingThinkingBar.displayName = 'FloatingThinkingBar'; Thinking.displayName = 'Thinking'; -export default memo(Thinking); +export default Thinking;