onRemove(attachment.id)} />
@@ -244,7 +245,7 @@ function NativeChatImageThumbnail({
{isPending ? (
<>
-
+
{pendingLabel}
>
) : (
diff --git a/src/renderer/src/components/native-chat/NativeChatLoadingCue.tsx b/src/renderer/src/components/native-chat/NativeChatLoadingCue.tsx
index fcefa2f4555..102cff72f74 100644
--- a/src/renderer/src/components/native-chat/NativeChatLoadingCue.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatLoadingCue.tsx
@@ -1,5 +1,5 @@
-import { Loader2 } from 'lucide-react'
import { translate } from '@/i18n/i18n'
+import { LoadingSpinner } from '@/components/LoadingSpinner'
/** The structured chat's pane while its first read runs. No visible text, and a CSS animation
* delay keeps it invisible unless the read lasts, so a quick read paints nothing. */
@@ -11,7 +11,7 @@ export function NativeChatLoadingCue(): React.JSX.Element {
data-native-chat-loading-cue="true"
className="flex h-full w-full items-center justify-center animate-in fade-in delay-250 [--tw-animation-fill-mode:backwards]"
>
-
+
)
}
diff --git a/src/renderer/src/components/native-chat/NativeChatMessageList.turn-indicator.test.tsx b/src/renderer/src/components/native-chat/NativeChatMessageList.turn-indicator.test.tsx
index d0433241160..5887b9a929e 100644
--- a/src/renderer/src/components/native-chat/NativeChatMessageList.turn-indicator.test.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatMessageList.turn-indicator.test.tsx
@@ -92,7 +92,7 @@ describe('NativeChatMessageList turn indicator', () => {
const row = activity.closest('[data-native-chat-turn-activity]')
const spinner = row?.querySelector('svg')
expect(activity).not.toHaveClass('animate-pulse', 'animate-spin')
- expect(spinner).toHaveClass('size-4', 'animate-spin', 'motion-reduce:animate-none')
+ expect(spinner).toHaveClass('size-4', 'animate-spin', 'motion-reduce:hidden')
expect(row).toHaveAttribute('aria-live', 'polite')
expect(screen.getByText('The answer is still streaming.').compareDocumentPosition(row!)).toBe(
Node.DOCUMENT_POSITION_FOLLOWING
@@ -137,7 +137,7 @@ describe('NativeChatMessageList turn indicator', () => {
expect(activity).not.toHaveTextContent('pnpm test')
const spinner = activity.closest('[data-native-chat-turn-activity]')?.querySelector('svg')
expect(activity).not.toHaveClass('animate-pulse', 'animate-spin')
- expect(spinner).toHaveClass('animate-spin', 'motion-reduce:animate-none')
+ expect(spinner).toHaveClass('animate-spin', 'motion-reduce:hidden')
})
it('hides foreground turn activity without settling live tool state', () => {
diff --git a/src/renderer/src/components/native-chat/NativeChatMessageRail.tsx b/src/renderer/src/components/native-chat/NativeChatMessageRail.tsx
index 8a8a794ecc4..dbf39b57bda 100644
--- a/src/renderer/src/components/native-chat/NativeChatMessageRail.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatMessageRail.tsx
@@ -194,9 +194,10 @@ export const NativeChatMessageRail = memo(function NativeChatMessageRail({
diff --git a/src/renderer/src/components/native-chat/NativeChatQueuedMessageCard.tsx b/src/renderer/src/components/native-chat/NativeChatQueuedMessageCard.tsx
index 827e825268e..0dca5bff26a 100644
--- a/src/renderer/src/components/native-chat/NativeChatQueuedMessageCard.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatQueuedMessageCard.tsx
@@ -347,7 +347,12 @@ function QueuedMessageExpandToggle({
aria-controls={controls}
onClick={onToggle}
>
-
+
diff --git a/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx b/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx
index d78e370619c..b48227cc70c 100644
--- a/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatSubagentRun.tsx
@@ -129,7 +129,7 @@ export function NativeChatSubagentEntries({
diff --git a/src/renderer/src/components/native-chat/NativeChatSubagentSectionHead.tsx b/src/renderer/src/components/native-chat/NativeChatSubagentSectionHead.tsx
index 400b839d471..80c1b6a8f57 100644
--- a/src/renderer/src/components/native-chat/NativeChatSubagentSectionHead.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatSubagentSectionHead.tsx
@@ -29,7 +29,10 @@ export function NativeChatSubagentSectionHead({
>
{state === null ? null : }
diff --git a/src/renderer/src/components/native-chat/NativeChatToolLine.tsx b/src/renderer/src/components/native-chat/NativeChatToolLine.tsx
index 049f9106e53..d4d610101f4 100644
--- a/src/renderer/src/components/native-chat/NativeChatToolLine.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatToolLine.tsx
@@ -184,7 +184,7 @@ export function NativeChatToolLine({
{hasDetail ? (
diff --git a/src/renderer/src/components/native-chat/NativeChatTranscriptChrome.tsx b/src/renderer/src/components/native-chat/NativeChatTranscriptChrome.tsx
index d70724f557e..db450f148c6 100644
--- a/src/renderer/src/components/native-chat/NativeChatTranscriptChrome.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatTranscriptChrome.tsx
@@ -327,7 +327,9 @@ export function ProviderFrameRow({
return (
- ›
+
+ ›
+
{frame.provider}
{summary ?? nativeChatProviderFrameSummary(block)}
{frame.payload.truncated ? (
diff --git a/src/renderer/src/components/native-chat/NativeChatTurnActivityLine.tsx b/src/renderer/src/components/native-chat/NativeChatTurnActivityLine.tsx
index af523d43d02..f94040e415e 100644
--- a/src/renderer/src/components/native-chat/NativeChatTurnActivityLine.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatTurnActivityLine.tsx
@@ -1,5 +1,4 @@
import { useId } from 'react'
-import { Loader2 } from 'lucide-react'
import type { CommentMarkdownLinkClickHandler } from '@/components/sidebar/CommentMarkdown'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import { translate } from '@/i18n/i18n'
@@ -14,6 +13,7 @@ import {
NativeChatReasoningChevron
} from './NativeChatReasoningDisclosure'
import { useNativeChatDisclosure } from './native-chat-disclosure-store'
+import { LoadingSpinner } from '@/components/LoadingSpinner'
// Literal keys with literal fallbacks: a dynamic key registers no catalog reference.
function statusLabel(key: Extract['key']): string {
@@ -63,7 +63,7 @@ export function NativeChatTurnActivityLine({
aria-live="polite"
aria-atomic="true"
>
-
+
{label}
diff --git a/src/renderer/src/components/native-chat/NativeChatWorkingStatus.tsx b/src/renderer/src/components/native-chat/NativeChatWorkingStatus.tsx
index c82befed7c4..5ee916ec405 100644
--- a/src/renderer/src/components/native-chat/NativeChatWorkingStatus.tsx
+++ b/src/renderer/src/components/native-chat/NativeChatWorkingStatus.tsx
@@ -73,7 +73,10 @@ export function NativeChatWorkingStatus({
const caret =
workedSeconds != null && onToggleExpanded ? (
) : null
diff --git a/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap b/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap
index 342897ca5a4..41c97165560 100644
--- a/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap
+++ b/src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap
@@ -1,8 +1,8 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-exports[`chat strip rows from a legacy background-task roster > render exactly as before 1`] = `" "`;
+exports[`chat strip rows from a legacy background-task roster > render exactly as before 1`] = `" "`;
-exports[`chat strip rows from a legacy background-task roster > render exactly as before 2`] = `" "`;
+exports[`chat strip rows from a legacy background-task roster > render exactly as before 2`] = `" "`;
exports[`sidebar child rows from a legacy subagents snapshot > render a stale parent and a lost transport exactly as before 1`] = `
[
diff --git a/src/renderer/src/components/ui/dropdown-menu.tsx b/src/renderer/src/components/ui/dropdown-menu.tsx
index c02282d8abb..1fe367c360e 100644
--- a/src/renderer/src/components/ui/dropdown-menu.tsx
+++ b/src/renderer/src/components/ui/dropdown-menu.tsx
@@ -33,7 +33,7 @@ function DropdownMenuContent({
data-slot="dropdown-menu-content"
sideOffset={sideOffset}
className={cn(
- 'z-[70] max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:duration-150 data-[state=open]:zoom-in-[0.98]',
+ 'z-[70] max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto scrollbar-sleek rounded-[11px] border border-black/14 bg-[rgba(255,255,255,0.82)] p-[4px] text-black dark:text-white shadow-[0_12px_28px_rgba(0,0,0,0.22),inset_0_1px_0_rgba(255,255,255,0.14)] backdrop-blur-2xl dark:border-white/14 dark:bg-[rgba(0,0,0,0.72)] dark:shadow-[0_16px_34px_rgba(0,0,0,0.40),inset_0_1px_0_rgba(255,255,255,0.04)] data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in motion-reduce:data-[state=open]:animate-none motion-reduce:data-[state=closed]:animate-none data-[state=open]:fade-in-0 data-[state=open]:duration-150 data-[state=open]:zoom-in-[0.98]',
className
)}
// Why: Electron's -webkit-app-region: drag on the titlebar captures
@@ -213,7 +213,7 @@ function DropdownMenuSubContent({