Skip to content

D-15: ToolCallCardView — generic card with lifecycle animations #265

@kirich1409

Description

@kirich1409

Description

Implement the generic ToolCallCardView — the shell that renders any tool call (Read / Edit / Bash / MCP / etc.) with consistent lifecycle animations (pending → in_progress → completed / failed). Specialized content per tool kind is injected via a slot (see D-16).

Spec: Epic #250 §6 (UI concept — tool-call level live feel).

Scope

File

MacApp/Packages/AgentChatUI/Sources/AgentChatUI/ToolCall/ToolCallCardView.swift

Structure

```swift
public struct ToolCallCardView<Content: View>: View {
public init(
toolCall: ToolCall,
@ViewBuilder content: @escaping (ToolCall) -> Content
)
}
```

  • Uses Card(style: .emphasized) from DS.
  • Header row: icon (per ToolKind) + tool name + StatusIndicator(kind:) (per status) + optional live duration ("2s").
  • Body: injected via content builder (specialized widget for this tool).
  • Collapsible — default state: pending/in_progress expanded, completed/failed collapsed (click to expand).
  • Animations (all accessibilityReduceMotion-guarded):
    • pending: shimmer skeleton (placeholder content);
    • in_progress: subtle pill opacity pulse (opacity 0.7 ↔ 1.0, 0.8s cycle);
    • completed: checkmark spring (scale 0.8 → 1.0, DS.Motion.fast);
    • failed: shake (horizontal offset ±4pt, DS.Motion.fast, 2 cycles), red border.

Live duration

While status == .inProgress(startedAt:):

  • TimelineView(.periodic(from: .now, by: 1)) updates a "2s / 10s / 1m 3s" label in the header every second.
  • Stops when status transitions.

Error presentation

.failed(at:reason:) — red DS.Color.destructive border, warning SF Symbol in status indicator, reason string in body.

Accessibility

  • .accessibilityLabel: "Tool call: {tool_name}, status {status.description}".
  • .accessibilityValue: status + duration.
  • Live region announce on status transitions (pending → in_progress → completed / failed).
  • Shake animation for .failed — guarded by reduceMotion (skip animation, only red border remains).

Acceptance Criteria

  • ToolCallCardView implemented with generic content slot.
  • All four status states render distinctly (pending / in_progress / completed / failed).
  • Live duration counter ticks accurately (verified with unit test on TimelineView).
  • Animations wrapped in accessibilityReduceMotion — under reduceMotion: no pulse, no shake, no spring (fade only).
  • Collapse/expand: pending/in_progress expanded by default; completed/failed collapsed by default; click toggles.
  • .textSelection(.enabled) on content (user can copy tool output).
  • VoiceOver announces status changes; reads "completed" / "failed" accurately.
  • Snapshot tests — all 4 statuses × 4 appearances (light / dark / HCR / reduceTransparency).
  • No hardcoded values — DS tokens only.

Relationships

Metadata

Metadata

Assignees

No one assigned

    Labels

    a11yAccessibility: VoiceOver, Dynamic Type, Reduce Motion, etc.complexity:MdialogueDialogue feature — structured chat UI for agent sessionsfrontendwave-3

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions