fix(ui): smooth reasoning collapse animation

This commit is contained in:
Bohdan Triapitsyn
2026-05-17 14:51:25 +03:00
parent fec4846ce5
commit 8900b8f0f2
8 changed files with 44 additions and 45 deletions
@@ -209,7 +209,7 @@ export const ReasoningTimelineBlock: React.FC<ReasoningTimelineBlockProps> = ({
{isStreaming ? ( {isStreaming ? (
<span className="flex items-center gap-1 typography-meta font-medium" style={{ color: 'var(--tools-title)' }}> <span className="flex items-center gap-1 typography-meta font-medium" style={{ color: 'var(--tools-title)' }}>
<span>{t('chat.reasoningTrace.reasoning')}</span> <span>{t(variant === 'justification' ? 'chat.reasoningTrace.justification' : 'chat.reasoningTrace.thinking')}</span>
<BusyDots /> <BusyDots />
</span> </span>
) : isExpanded ? ( ) : isExpanded ? (
@@ -244,45 +244,51 @@ export const ReasoningTimelineBlock: React.FC<ReasoningTimelineBlockProps> = ({
</div> </div>
</div> </div>
{/* Expanded content — left border matching ToolPart */} {/* Expanded content — keep mounted so auto-collapse can animate smoothly. */}
{isExpanded && ( <div
<div id={contentId}
id={contentId} aria-hidden={!isExpanded}
className="relative ml-2 pl-3 pb-1 pt-0.5" className={cn(
> 'grid transition-[grid-template-rows,opacity] duration-[350ms] ease-out motion-reduce:transition-none',
<span isExpanded ? 'grid-rows-[1fr] opacity-100' : 'grid-rows-[0fr] opacity-0',
aria-hidden="true" )}
className="pointer-events-none absolute left-0 top-0 bottom-0 w-px" >
style={{ backgroundColor: 'var(--tools-border)' }} <div className="min-h-0 overflow-hidden">
/> <div className="relative ml-2 pl-3 pb-1 pt-0.5">
<ScrollableOverlay <span
ref={scrollRef} aria-hidden="true"
as="div" className="pointer-events-none absolute left-0 top-0 bottom-0 w-px"
outerClassName="max-h-80" style={{ backgroundColor: 'var(--tools-border)' }}
className="p-0" />
useScrollShadow <ScrollableOverlay
scrollShadowSize={36} ref={scrollRef}
userIntentOnly as="div"
> outerClassName="max-h-80"
<div data-message-text-export-source="true"> className="p-0"
<MarkdownRenderer useScrollShadow
content={text} scrollShadowSize={36}
messageId={blockId} userIntentOnly
isAnimated={false} >
isStreaming={isStreaming} <div data-message-text-export-source="true">
variant="reasoning" <MarkdownRenderer
/> content={text}
</div> messageId={blockId}
{actions ? ( isAnimated={false}
<div className="mt-2 mb-1 flex items-center justify-start gap-1.5" data-message-actions="true"> isStreaming={isStreaming}
<div className="flex items-center gap-1.5" data-message-action-group="true"> variant="reasoning"
{actions} />
</div>
</div> </div>
) : null} {actions ? (
</ScrollableOverlay> <div className="mt-2 mb-1 flex items-center justify-start gap-1.5" data-message-actions="true">
<div className="flex items-center gap-1.5" data-message-action-group="true">
{actions}
</div>
</div>
) : null}
</ScrollableOverlay>
</div>
</div> </div>
)} </div>
</div> </div>
); );
}; };
-1
View File
@@ -1687,7 +1687,6 @@ export const dict = {
'chat.modelControls.modeValue.all': 'All', 'chat.modelControls.modeValue.all': 'All',
'chat.modelControls.modeValue.none': '—', 'chat.modelControls.modeValue.none': '—',
'chat.reasoningTrace.thinking': 'Thinking', 'chat.reasoningTrace.thinking': 'Thinking',
'chat.reasoningTrace.reasoning': 'Reasoning',
'chat.reasoningTrace.justification': 'Justification', 'chat.reasoningTrace.justification': 'Justification',
'chat.reasoningTrace.expandAria': 'Expand reasoning trace', 'chat.reasoningTrace.expandAria': 'Expand reasoning trace',
'chat.reasoningTrace.collapseAria': 'Collapse reasoning trace', 'chat.reasoningTrace.collapseAria': 'Collapse reasoning trace',
-1
View File
@@ -1653,7 +1653,6 @@ export const dict: Record<I18nKey, string> = {
"chat.modelControls.modeValue.all": "Todos", "chat.modelControls.modeValue.all": "Todos",
"chat.modelControls.modeValue.none": "—", "chat.modelControls.modeValue.none": "—",
"chat.reasoningTrace.thinking": "Pensando", "chat.reasoningTrace.thinking": "Pensando",
"chat.reasoningTrace.reasoning": "Razonando",
"chat.reasoningTrace.justification": "Justificación", "chat.reasoningTrace.justification": "Justificación",
"chat.reasoningTrace.expandAria": "Expandir traza de razonamiento", "chat.reasoningTrace.expandAria": "Expandir traza de razonamiento",
"chat.reasoningTrace.collapseAria": "Contraer traza de razonamiento", "chat.reasoningTrace.collapseAria": "Contraer traza de razonamiento",
-1
View File
@@ -1687,7 +1687,6 @@ export const dict: Record<I18nKey, string> = {
'chat.modelControls.modeValue.all': '전체', 'chat.modelControls.modeValue.all': '전체',
'chat.modelControls.modeValue.none': '—', 'chat.modelControls.modeValue.none': '—',
'chat.reasoningTrace.thinking': '추론', 'chat.reasoningTrace.thinking': '추론',
'chat.reasoningTrace.reasoning': '추론 중',
'chat.reasoningTrace.justification': '근거', 'chat.reasoningTrace.justification': '근거',
'chat.reasoningTrace.expandAria': '추론 트레이스 펼치기', 'chat.reasoningTrace.expandAria': '추론 트레이스 펼치기',
'chat.reasoningTrace.collapseAria': '추론 트레이스 접기', 'chat.reasoningTrace.collapseAria': '추론 트레이스 접기',
-1
View File
@@ -890,7 +890,6 @@ export const dict: Record<I18nKey, string> = {
'chat.messageBody.subtask.showPrompt': 'Pokaż prompt', 'chat.messageBody.subtask.showPrompt': 'Pokaż prompt',
'chat.messageBody.subtask.title': 'Zadanie delegowane', 'chat.messageBody.subtask.title': 'Zadanie delegowane',
'chat.reasoningTrace.thinking': 'Myślenie', 'chat.reasoningTrace.thinking': 'Myślenie',
'chat.reasoningTrace.reasoning': 'Rozumowanie',
'chat.reasoningTrace.justification': 'Uzasadnienie', 'chat.reasoningTrace.justification': 'Uzasadnienie',
'chat.reasoningTrace.expandAria': 'Rozwiń ślad rozumowania', 'chat.reasoningTrace.expandAria': 'Rozwiń ślad rozumowania',
'chat.reasoningTrace.collapseAria': 'Zwiń ślad rozumowania', 'chat.reasoningTrace.collapseAria': 'Zwiń ślad rozumowania',
@@ -1653,7 +1653,6 @@ export const dict: Record<I18nKey, string> = {
"chat.modelControls.modeValue.all": "Todos", "chat.modelControls.modeValue.all": "Todos",
"chat.modelControls.modeValue.none": "—", "chat.modelControls.modeValue.none": "—",
"chat.reasoningTrace.thinking": "Pensando", "chat.reasoningTrace.thinking": "Pensando",
"chat.reasoningTrace.reasoning": "Raciocinando",
"chat.reasoningTrace.justification": "Justificativa", "chat.reasoningTrace.justification": "Justificativa",
"chat.reasoningTrace.expandAria": "Expandir rastro de raciocínio", "chat.reasoningTrace.expandAria": "Expandir rastro de raciocínio",
"chat.reasoningTrace.collapseAria": "Recolher rastro de raciocínio", "chat.reasoningTrace.collapseAria": "Recolher rastro de raciocínio",
-1
View File
@@ -1653,7 +1653,6 @@ export const dict: Record<I18nKey, string> = {
"chat.modelControls.modeValue.all": "всі", "chat.modelControls.modeValue.all": "всі",
"chat.modelControls.modeValue.none": "—", "chat.modelControls.modeValue.none": "—",
"chat.reasoningTrace.thinking": "Міркування", "chat.reasoningTrace.thinking": "Міркування",
"chat.reasoningTrace.reasoning": "Міркую",
"chat.reasoningTrace.justification": "Обґрунтування", "chat.reasoningTrace.justification": "Обґрунтування",
"chat.reasoningTrace.expandAria": "Розгорнути слід міркування", "chat.reasoningTrace.expandAria": "Розгорнути слід міркування",
"chat.reasoningTrace.collapseAria": "Згорнути слід міркування", "chat.reasoningTrace.collapseAria": "Згорнути слід міркування",
@@ -1653,7 +1653,6 @@ export const dict: Record<I18nKey, string> = {
'chat.modelControls.modeValue.all': '全部', 'chat.modelControls.modeValue.all': '全部',
'chat.modelControls.modeValue.none': '—', 'chat.modelControls.modeValue.none': '—',
'chat.reasoningTrace.thinking': '思考', 'chat.reasoningTrace.thinking': '思考',
'chat.reasoningTrace.reasoning': '推理',
'chat.reasoningTrace.justification': '理由', 'chat.reasoningTrace.justification': '理由',
'chat.reasoningTrace.expandAria': '展开推理轨迹', 'chat.reasoningTrace.expandAria': '展开推理轨迹',
'chat.reasoningTrace.collapseAria': '折叠推理轨迹', 'chat.reasoningTrace.collapseAria': '折叠推理轨迹',