@tangle-network/ui 11.51.13 → 11.51.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/dist/hooks.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/primitives/expandable-panel.d.ts +19 -0
- package/dist/primitives/expandable-panel.js +69 -0
- package/dist/primitives.d.ts +2 -1
- package/dist/primitives.js +2 -1
- package/dist/run/run-row-shell.d.ts +0 -13
- package/dist/run/run-row-shell.js +3 -15
- package/dist/run.d.ts +2 -3
- package/dist/run.js +2 -3
- package/package.json +1 -1
- package/src/primitives/control-presentation.test.tsx +0 -92
- package/src/primitives/expandable-panel.stories.tsx +36 -0
- package/src/primitives/expandable-panel.test.tsx +49 -0
- package/src/primitives/expandable-panel.tsx +108 -0
- package/src/primitives/index.ts +3 -0
- package/src/primitives/metric-strip.test.tsx +0 -45
- package/src/run/index.ts +0 -2
- package/src/run/run-row-shell.tsx +4 -20
- package/dist/run/run-item-primitives.d.ts +0 -3
- package/dist/run/run-item-primitives.js +0 -12
- package/src/primitives/switch.test.tsx +0 -39
- package/src/primitives/toolbar.test.tsx +0 -103
- package/src/run/run-item-primitives.tsx +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 11.51.15
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- ab4348b: Restore `isOpen` (`@tangle-network/ui/run`) and `formatCost` and `formatCount` (`@tangle-network/ui/utils`). 11.51.14 removed them as unused, but the Discovery viewer imports them, so the removal broke a public API in a patch release.
|
|
6
|
+
|
|
7
|
+
## 11.51.14
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 40a98a3: Add `ExpandablePanel` to `@tangle-network/ui/primitives`: any panel can fill the screen in place, keeping its subtree, and Escape closes the top-most one after inner popovers, menus and dialogs.
|
|
12
|
+
|
|
1
13
|
## 11.51.13
|
|
2
14
|
|
|
3
15
|
### Patch Changes
|
|
@@ -551,7 +563,7 @@
|
|
|
551
563
|
|
|
552
564
|
### Patch Changes
|
|
553
565
|
|
|
554
|
-
- 11fbba5: Chat text renders at the 15px body size. The user bubble, assistant prose, legacy `ChatMessage` and thinking timer wrote their size tokens as `text-[var(--font-size
|
|
566
|
+
- 11fbba5: Chat text renders at the 15px body size. The user bubble, assistant prose, legacy `ChatMessage` and thinking timer wrote their size tokens as `text-[var(--font-size-…)]`, which Tailwind compiles to a color, so assistant prose fell back to the Markdown default of 14px and the user bubble inherited 16px. They now use `text-[length:var(...)]`, and the dist check fails on the untyped form.
|
|
555
567
|
|
|
556
568
|
The streaming caret follows the last word instead of starting a new line. A code block that scrolls sideways takes keyboard focus as a named region (axe `scrollable-region-focusable`). The Show more toggle under a tool's output or error sits inside the card's inset instead of against its edge.
|
|
557
569
|
|
package/dist/hooks.js
CHANGED
|
@@ -2,8 +2,8 @@ import { useRunGroups } from "./hooks/use-run-groups.js";
|
|
|
2
2
|
import { useRunCollapseState } from "./hooks/use-run-collapse-state.js";
|
|
3
3
|
import { useFollowTail } from "./hooks/use-follow-tail.js";
|
|
4
4
|
import { useAutoScroll } from "./hooks/use-auto-scroll.js";
|
|
5
|
-
import { useLiveTime, useRunNow } from "./hooks/use-live-time.js";
|
|
6
5
|
import { useDropdownMenu } from "./hooks/use-dropdown-menu.js";
|
|
6
|
+
import { useLiveTime, useRunNow } from "./hooks/use-live-time.js";
|
|
7
7
|
import { useToolCallStream } from "./hooks/use-tool-call-stream.js";
|
|
8
8
|
import { createAuthFetcher, useApiKey, useAuth } from "./hooks/use-auth.js";
|
|
9
9
|
import { RealtimeSessionRegistry, useRealtimeSession } from "./hooks/use-realtime-session.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -110,13 +110,13 @@ import { PeriodDelta, SeriesExtent, SeriesPoint, SeriesPointInput, SeriesScale,
|
|
|
110
110
|
import { SeriesSparkline, SeriesSparklineProps } from "./primitives/series-sparkline.js";
|
|
111
111
|
import { ChartReferenceLine, MetricChart, MetricChartProps } from "./primitives/metric-chart.js";
|
|
112
112
|
import { FilterField, FilterFieldProps, Toolbar, ToolbarProps } from "./primitives/toolbar.js";
|
|
113
|
+
import { ExpandablePanel, ExpandablePanelProps } from "./primitives/expandable-panel.js";
|
|
113
114
|
import { Logo, LogoProps, TangleKnot } from "./primitives.js";
|
|
114
115
|
import { RunGroup, RunGroupProps } from "./run/run-group.js";
|
|
115
|
-
import { RunRowShell, RunRowShellProps, RunRowStatus
|
|
116
|
+
import { RunRowShell, RunRowShellProps, RunRowStatus } from "./run/run-row-shell.js";
|
|
116
117
|
import { InlineToolItem, InlineToolItemProps } from "./run/inline-tool-item.js";
|
|
117
118
|
import { InlineThinkingItem, InlineThinkingItemProps } from "./run/inline-thinking-item.js";
|
|
118
119
|
import { ExpandedToolDetail, ExpandedToolDetailProps } from "./run/expanded-tool-detail.js";
|
|
119
|
-
import { LiveDuration } from "./run/run-item-primitives.js";
|
|
120
120
|
import { TaskList, TaskListItem, TaskListProps, TaskStatus, showsTaskPriority, taskProgress, taskStatus } from "./run/task-list.js";
|
|
121
121
|
import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep } from "./run/approval-card.js";
|
|
122
122
|
import { RunPhase, RunPhaseList } from "./run/run-phase-list.js";
|
|
@@ -147,4 +147,4 @@ import { QuestionPreview, QuestionPreviewProps } from "./tool-previews/question-
|
|
|
147
147
|
import { DiffPreview, DiffPreviewProps } from "./tool-previews/diff-preview.js";
|
|
148
148
|
import { RedactedDocSegment, RedactedDocument, RedactedDocumentData, RedactedDocumentProps, RevealResult } from "./redaction/redacted-document.js";
|
|
149
149
|
import "./redaction.js";
|
|
150
|
-
export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineFoldItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, type EventStreamHandlers, type EventStreamOpener, type EventStreamSource, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LiveDuration, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunRowStatusDot, RunStats, type RunStatus, RunStatusIcon, type RunStatusIconProps, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsNote, type SettingsNoteProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, type Speaker, SpeakerHeader, type SpeakerHeaderProps, type SpeakerPart, type SpeakerSection, type SpeakerState, StatCard, type StatCardProps, type StatusMeta, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, foldSummary, formatAxisDuration, formatBytes, formatCalendarDate, formatClock, formatCompact, formatCost, formatCount, formatSpanDuration as formatDuration, formatSpanDuration, formatSpanDuration as formatUptime, formatUtcTime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isOpen, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, partitionBySpeaker, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, runStatus, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, statusMeta, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useEventStream, useFollowTail, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useRunNow, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
|
150
|
+
export { ActiveProjectActivity, ActiveSessionActivityOptions, ActiveSessionConnectionOptions, ActiveSessionConnectionState, ActiveSessionReconnectState, ActiveSessionRecord, ActiveSessionStatus, ActiveSessionTransportMode, ActiveSessionsState, AgentBranding, AgentStreamEvent, AgentTimeline, type AgentTimelineArtifactItem, AgentTimelineColumn, type AgentTimelineCustomItem, type AgentTimelineFoldItem, type AgentTimelineItem, type AgentTimelineMessageItem, type AgentTimelineProps, type AgentTimelineStatusItem, AgentTimelineStep, type AgentTimelineStepKind, type AgentTimelineStepProps, type AgentTimelineTone, type AgentTimelineToolGroupItem, type AgentTimelineToolItem, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ApiSchema, type ApiSchemaProps, AppendUserMessageOptions, ApplySdkEventOptions, ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ArtifactPane, type ArtifactPaneProps, AuthHeader, type AuthHeaderProps, AuthUser, AutomationStreamEvent, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, BeginAssistantMessageOptions, BotStreamEvent, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, ChatAuthor, ChatContainer, type ChatContainerProps, ChatMessage, type ChatMessageProps, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, type CommandPreviewProps, CompleteAssistantMessageOptions, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ConnectionState, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, CustomToolRenderer, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, type DiffPreviewProps, DisplayVariant, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, type EventStreamHandlers, type EventStreamOpener, type EventStreamSource, ExpandablePanel, type ExpandablePanelProps, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, Field, type FieldProps, FileArtifactPane, type FileArtifactPaneProps, FileCard, type FileCardProps, type FileDetails, type FileFormat, FileList, type FileListItem, type FileListProps, type FileNode, FilePreview, type FilePreviewKind, type FilePreviewProps, type FileTabData, FileTabs, type FileTabsProps, FileTree, type FileTreeProps, type FileTreeVisibilityOptions, type FileUploader, FilterField, type FilterFieldProps, FinalTextPart, GitHubLoginButton, type GitHubLoginButtonProps, GlobResultsPreview, type GlobResultsPreviewProps, GrepResultsPreview, type GrepResultsPreviewProps, GroupedMessage, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, Input, type InputProps, Label, LoginLayout, type LoginLayoutProps, Logo, type LogoProps, Markdown, type MarkdownLinkChip, type MarkdownLinkChipResolver, type MarkdownProps, MessageAuthor, type MessageAuthorProps, MessageList, type MessageListProps, type MessageRole, MessageRun, MessageUser, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, type OpenUIAction, type OpenUIActionsNode, OpenUIArtifactRenderer, type OpenUIArtifactRendererProps, type OpenUIBadgeNode, type OpenUICardNode, type OpenUICodeNode, type OpenUIComponentNode, type OpenUIGridNode, type OpenUIHeadingNode, type OpenUIKeyValueNode, type OpenUIMarkdownNode, type OpenUIPrimitive, type OpenUISchemaIssue, type OpenUISchemaValidation, type OpenUISeparatorNode, type OpenUIStackNode, type OpenUIStatNode, type OpenUITableNode, type OpenUITextNode, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, PdfViewer, type PdfViewerConfig, type PdfViewerProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, type QuestionPreviewProps, RadioGroup, RadioGroupItem, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, ReasoningPart, type RedactedDocSegment, RedactedDocument, type RedactedDocumentData, type RedactedDocumentProps, RegisterActiveSessionOptions, type RevealResult, RichFileTree, type RichFileTreeGitEntry, type RichFileTreeGitStatus, type RichFileTreeProps, type RichFileTreeThemeVars, Run, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, RunStats, type RunStatus, RunStatusIcon, type RunStatusIconProps, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SessionMessage, SessionPart, SessionProjectKey, type SessionUser, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsNote, type SettingsNoteProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, type Speaker, SpeakerHeader, type SpeakerHeaderProps, type SpeakerPart, type SpeakerSection, type SpeakerState, StatCard, type StatCardProps, type StatusMeta, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, TaskStreamEvent, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TerminalStreamEvent, TextPart, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, ThinkingIndicator, type ThinkingIndicatorProps, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, ToolCategory, ToolDisplayMetadata, ToolPart, ToolState, ToolStatus, ToolTime, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, UserMenu, type UserMenuProps, UserMessage, type UserMessageProps, WebSearchPreview, type WebSearchPreviewProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, WriteFilePreview, type WriteFilePreviewProps, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, foldSummary, formatAxisDuration, formatBytes, formatCalendarDate, formatClock, formatCompact, formatCost, formatCount, formatSpanDuration as formatDuration, formatSpanDuration, formatSpanDuration as formatUptime, formatUtcTime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isOpen, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, partitionBySpeaker, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, runStatus, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, statusMeta, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useEventStream, useFollowTail, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useRunNow, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,7 @@ import { normalizeSeries, periodDelta, seriesAreaPath, seriesExtent, seriesLineP
|
|
|
66
66
|
import { SeriesSparkline } from "./primitives/series-sparkline.js";
|
|
67
67
|
import { MetricChart } from "./primitives/metric-chart.js";
|
|
68
68
|
import { FilterField, Toolbar } from "./primitives/toolbar.js";
|
|
69
|
+
import { ExpandablePanel } from "./primitives/expandable-panel.js";
|
|
69
70
|
import { Logo, TangleKnot } from "./primitives.js";
|
|
70
71
|
import { TOOL_CATEGORY_ICONS, getToolCategory, getToolDisplayMetadata, getToolErrorText } from "./utils/tool-display.js";
|
|
71
72
|
import { useRunGroups } from "./hooks/use-run-groups.js";
|
|
@@ -82,7 +83,7 @@ import { QuestionPreview } from "./tool-previews/question-preview.js";
|
|
|
82
83
|
import { DiffPreview } from "./tool-previews/diff-preview.js";
|
|
83
84
|
import { RunStatusIcon, isOpen, runStatus, statusMeta } from "./run/status-meta.js";
|
|
84
85
|
import { ExpandedToolDetail } from "./run/expanded-tool-detail.js";
|
|
85
|
-
import { RunRowShell
|
|
86
|
+
import { RunRowShell } from "./run/run-row-shell.js";
|
|
86
87
|
import { InlineToolItem } from "./run/inline-tool-item.js";
|
|
87
88
|
import { fenceInfo } from "./markdown/code-meta.js";
|
|
88
89
|
import { numericColumns, tableCsv } from "./markdown/markdown-table.js";
|
|
@@ -101,8 +102,6 @@ import { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, agentTimelineSte
|
|
|
101
102
|
import { ChatContainer } from "./chat/chat-container.js";
|
|
102
103
|
import { ChatMessage } from "./chat/chat-message.js";
|
|
103
104
|
import { SpeakerHeader, partitionBySpeaker } from "./chat/speaker.js";
|
|
104
|
-
import { useLiveTime, useRunNow } from "./hooks/use-live-time.js";
|
|
105
|
-
import { LiveDuration } from "./run/run-item-primitives.js";
|
|
106
105
|
import { ToolCallFeed, parseToolEvent } from "./run/tool-call-feed.js";
|
|
107
106
|
import { TaskList, showsTaskPriority, taskProgress, taskStatus } from "./run/task-list.js";
|
|
108
107
|
import { ApprovalCard, ApprovalDiffSummary } from "./run/approval-card.js";
|
|
@@ -120,6 +119,7 @@ import { ApiSchema } from "./markdown/api-schema.js";
|
|
|
120
119
|
import { AuthHeader, GitHubLoginButton, UserMenu } from "./auth/auth.js";
|
|
121
120
|
import { LoginLayout } from "./auth/login-layout.js";
|
|
122
121
|
import { useDropdownMenu } from "./hooks/use-dropdown-menu.js";
|
|
122
|
+
import { useLiveTime, useRunNow } from "./hooks/use-live-time.js";
|
|
123
123
|
import { useToolCallStream } from "./hooks/use-tool-call-stream.js";
|
|
124
124
|
import { createAuthFetcher, useApiKey, useAuth } from "./hooks/use-auth.js";
|
|
125
125
|
import { activeSessionsAtom, bumpActiveSessionActivity, getActiveSession, getAllActiveSessions, getAllProjectActivity, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getTotalRunningSessionCount, hasBackgroundRunningSessions, registerActiveSession, resetActiveSessions, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, unregisterActiveSession, updateActiveSessionMeta, useActiveSession, useActiveSessions, useActiveSessionsState, useHasBackgroundRunningSessions, useNavbarSessions, useProjectActivity, useProjectSessions, useSessionsByActivity, useTotalRunningSessions } from "./stores/active-sessions-store.js";
|
|
@@ -131,4 +131,4 @@ import { addMessage, addParts, clearChat, isStreamingAtom, messagesAtom, partMap
|
|
|
131
131
|
import { copyText } from "./utils/copy-text.js";
|
|
132
132
|
import { timeAgo } from "./utils/time-ago.js";
|
|
133
133
|
import { RedactedDocument } from "./redaction/redacted-document.js";
|
|
134
|
-
export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label,
|
|
134
|
+
export { AgentTimeline, AgentTimelineColumn, AgentTimelineStep, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ApiSchema, ApprovalCard, ApprovalDiffSummary, ArtifactPane, AuthHeader, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, CSV_PREVIEW_ROW_LIMIT, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatContainer, ChatMessage, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, CommandPreview, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffPreview, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandablePanel, ExpandedToolDetail, Field, FileArtifactPane, FileCard, FileList, FilePreview, FileTabs, FileTree, FilterField, GitHubLoginButton, GlobResultsPreview, GrepResultsPreview, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, InlineThinkingItem, InlineToolItem, Input, Label, LoginLayout, Logo, Markdown, MessageAuthor, MessageList, Metric, MetricChart, MetricStrip, OPENUI_NODE_JSON_SCHEMA, OPENUI_NODE_TYPES, OpenUIArtifactRenderer, PageHeader, PageShell, Pagination, PdfViewer, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, QuestionPreview, RadioGroup, RadioGroupItem, RealtimeSessionRegistry, RedactedDocument, RichFileTree, RunGroup, RunPhaseList, RunRowShell, RunStatusIcon, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsNote, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, SpeakerHeader, StatCard, StatusPill, Switch, TONE_CLASSES, TOOL_CATEGORY_ICONS, TRANSCRIPT_TEXT, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TaskList, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, ThinkingIndicator, TimeSelect, ToastContainer, ToastProvider, ToolCallFeed, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, UserMenu, UserMessage, WebSearchPreview, Wizard, WizardStep, WriteFilePreview, activeSessionsAtom, addMessage, addParts, agentTimelineStepKind, badgeVariants, bumpActiveSessionActivity, buttonVariants, clearChat, cn, codeBlockGrammar, configurePdfViewer, copyText, createAuthFetcher, detectFileFormat, fenceInfo, fieldMessageId, fileExtension, filterFileTree, findUnsupportedOpenUINode, focusField, focusFieldInvalid, focusFieldWithin, focusRing, focusRingInset, foldSummary, formatAxisDuration, formatBytes, formatCalendarDate, formatClock, formatCompact, formatCost, formatCount, formatSpanDuration as formatDuration, formatSpanDuration, formatSpanDuration as formatUptime, formatUtcTime, getActiveSession, getAllActiveSessions, getAllProjectActivity, getCodeLanguage, getFormatLabel, getSanitizedMarkdownHeadingIdFromRawFragment, getSessionsByActivity, getSessionsForNavbar, getSessionsForProject, getSyntaxLanguage, getToolCategory, getToolDisplayMetadata, getToolErrorText, getTotalRunningSessionCount, hasBackgroundRunningSessions, initialsOf, isOpen, isStreamingAtom, isViewerMessage, ixControl, ixControlAfter, ixControlSoft, ixField, ixRow, ixSelected, ixTabUnderline, localToday, messagesAtom, normalizeSeries, numericColumns, parseCalendarDate, parseCsv, parseToolEvent, partMapAtom, partitionBySpeaker, periodDelta, plainTextFromMarkdown, registerActiveSession, resetActiveSessions, resolveFilePreviewKind, runStatus, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, setActiveSessionAttention, setActiveSessionConnection, setActiveSessionError, setActiveSessionRunning, setForegroundActiveSession, showsTaskPriority, statusMeta, tableCsv, taskProgress, taskStatus, timeAgo, toneFor, truncateText, unregisterActiveSession, updateActiveSessionMeta, updatePart, useActiveSession, useActiveSessions, useActiveSessionsState, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useEventStream, useFollowTail, useHasBackgroundRunningSessions, useLiveTime, useNavbarSessions, useProjectActivity, useProjectSessions, useRealtimeSession, useRunCollapseState, useRunGroups, useRunNow, useSSEStream, useSdkSession, useSessionsByActivity, useTheme, useToast, useToolCallStream, useTotalRunningSessions, validateOpenUIJsonArtifact, validateOpenUIJsonNode };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ExpandablePanelProps {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
/** Accessible name: the toggle reads "Expand <label>" and "Close full screen <label>". */
|
|
5
|
+
label: string;
|
|
6
|
+
expanded?: boolean;
|
|
7
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
8
|
+
className?: string;
|
|
9
|
+
actions?: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A panel that fills the viewport in place and returns on Escape. The subtree
|
|
13
|
+
* never moves (no portal), so chart, canvas and conversation state and scroll
|
|
14
|
+
* survive the switch. Radix popovers, menus and dialogs inside take Escape
|
|
15
|
+
* first: they prevent its default, which this panel respects. An ancestor
|
|
16
|
+
* with a transform or filter would contain the fixed panel, so avoid one.
|
|
17
|
+
*/
|
|
18
|
+
declare function ExpandablePanel({ children, label, expanded: expandedProp, onExpandedChange, className, actions }: ExpandablePanelProps): React.JSX.Element;
|
|
19
|
+
export { ExpandablePanel };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { Button } from "./button.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { Maximize2, Minimize2 } from "lucide-react";
|
|
7
|
+
// src/primitives/expandable-panel.tsx
|
|
8
|
+
const openPanels = [];
|
|
9
|
+
let bodyOverflow = "";
|
|
10
|
+
/**
|
|
11
|
+
* A panel that fills the viewport in place and returns on Escape. The subtree
|
|
12
|
+
* never moves (no portal), so chart, canvas and conversation state and scroll
|
|
13
|
+
* survive the switch. Radix popovers, menus and dialogs inside take Escape
|
|
14
|
+
* first: they prevent its default, which this panel respects. An ancestor
|
|
15
|
+
* with a transform or filter would contain the fixed panel, so avoid one.
|
|
16
|
+
*/
|
|
17
|
+
function ExpandablePanel({ children, label, expanded: expandedProp, onExpandedChange, className, actions }) {
|
|
18
|
+
const [expandedState, setExpandedState] = React.useState(false);
|
|
19
|
+
const expanded = expandedProp ?? expandedState;
|
|
20
|
+
const toggleRef = React.useRef(null);
|
|
21
|
+
const panelRef = React.useRef(null);
|
|
22
|
+
const wasExpanded = React.useRef(expanded);
|
|
23
|
+
const setExpanded = (next) => {
|
|
24
|
+
if (expandedProp === void 0) setExpandedState(next);
|
|
25
|
+
onExpandedChange?.(next);
|
|
26
|
+
};
|
|
27
|
+
const setExpandedRef = React.useRef(setExpanded);
|
|
28
|
+
setExpandedRef.current = setExpanded;
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
if (wasExpanded.current && !expanded) toggleRef.current?.focus();
|
|
31
|
+
wasExpanded.current = expanded;
|
|
32
|
+
const id = panelRef.current;
|
|
33
|
+
if (!expanded || !id) return;
|
|
34
|
+
if (openPanels.length === 0) bodyOverflow = document.body.style.overflow;
|
|
35
|
+
openPanels.push(id);
|
|
36
|
+
document.body.style.overflow = "hidden";
|
|
37
|
+
const onKeyDown = (event) => {
|
|
38
|
+
const top = openPanels.filter((p) => !openPanels.some((q) => q !== p && p.contains(q))).pop();
|
|
39
|
+
if (event.key !== "Escape" || event.defaultPrevented || top !== id) return;
|
|
40
|
+
event.preventDefault();
|
|
41
|
+
setExpandedRef.current(false);
|
|
42
|
+
};
|
|
43
|
+
document.addEventListener("keydown", onKeyDown);
|
|
44
|
+
return () => {
|
|
45
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
46
|
+
openPanels.splice(openPanels.indexOf(id), 1);
|
|
47
|
+
if (openPanels.length === 0) document.body.style.overflow = bodyOverflow;
|
|
48
|
+
};
|
|
49
|
+
}, [expanded]);
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
ref: panelRef,
|
|
52
|
+
"data-expandable-panel": "",
|
|
53
|
+
"data-expanded": expanded ? "" : void 0,
|
|
54
|
+
className: cn("group/expandable relative flex min-h-0 flex-col", className, expanded && "fixed inset-0 z-50 m-0 size-auto min-h-0 min-w-0 max-h-none max-w-none rounded-none transform-none bg-background"),
|
|
55
|
+
children: [children, /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
className: cn("absolute right-2 top-2 z-10 flex items-center gap-1 transition-opacity", expanded ? "opacity-100" : "opacity-0 group-hover/expandable:opacity-100 group-focus-within/expandable:opacity-100 pointer-coarse:opacity-100"),
|
|
57
|
+
children: [actions, /* @__PURE__ */ jsx(Button, {
|
|
58
|
+
ref: toggleRef,
|
|
59
|
+
type: "button",
|
|
60
|
+
variant: "ghost",
|
|
61
|
+
size: "icon-sm",
|
|
62
|
+
"aria-label": `${expanded ? "Close full screen" : "Expand"} ${label}`,
|
|
63
|
+
onClick: () => setExpanded(!expanded),
|
|
64
|
+
children: expanded ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": true }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": true })
|
|
65
|
+
})]
|
|
66
|
+
})]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export { ExpandablePanel };
|
package/dist/primitives.d.ts
CHANGED
|
@@ -61,5 +61,6 @@ import { PeriodDelta, SeriesExtent, SeriesPoint, SeriesPointInput, SeriesScale,
|
|
|
61
61
|
import { SeriesSparkline, SeriesSparklineProps } from "./primitives/series-sparkline.js";
|
|
62
62
|
import { ChartReferenceLine, MetricChart, MetricChartProps } from "./primitives/metric-chart.js";
|
|
63
63
|
import { FilterField, FilterFieldProps, Toolbar, ToolbarProps } from "./primitives/toolbar.js";
|
|
64
|
+
import { ExpandablePanel, ExpandablePanelProps } from "./primitives/expandable-panel.js";
|
|
64
65
|
import { Logo, LogoProps, TangleKnot } from "@tangle-network/brand";
|
|
65
|
-
export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ArtifactPane, type ArtifactPaneProps, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, Field, type FieldProps, FilterField, type FilterFieldProps, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, Input, type InputProps, Label, Logo, type LogoProps, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsNote, type SettingsNoteProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, badgeVariants, buttonVariants, fieldMessageId, formatCalendarDate, initialsOf, localToday, normalizeSeries, parseCalendarDate, periodDelta, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, toneFor, useTheme, useToast };
|
|
66
|
+
export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, type AlertProps, AlertTitle, type AlertTone, ArtifactPane, type ArtifactPaneProps, Avatar, AvatarFallback, AvatarImage, type AvatarProps, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, CATEGORY_TONES, Calendar, type CalendarDate, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type CardTitleProps, type CategoryTone, type ChartReferenceLine, Checkbox, Chip, type ChipProps, CodeBlock, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, ComplianceBadge, type ComplianceBadgeProps, type ComplianceProduct, type ComplianceStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, ExpandablePanel, type ExpandablePanelProps, Field, type FieldProps, FilterField, type FilterFieldProps, Heading, type HeadingProps, type HeadingVariant, HelpText, type HelpTextProps, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, type IconTileProps, InlineCode, type InlineCodeProps, Input, type InputProps, Label, Logo, type LogoProps, Metric, MetricChart, type MetricChartProps, type MetricProps, MetricStrip, type MetricStripProps, PageHeader, type PageHeaderProps, PageShell, type PageShellProps, Pagination, type PaginationProps, type PeriodDelta, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, type SegmentedControlOption, type SegmentedControlProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, type SeriesExtent, type SeriesPoint, type SeriesPointInput, type SeriesScale, SeriesSparkline, type SeriesSparklineProps, SettingsList, type SettingsListAction, type SettingsListColumns, SettingsListItem, type SettingsListItemProps, type SettingsListMenuItem, type SettingsListProps, SettingsNote, type SettingsNoteProps, SettingsRow, type SettingsRowLayout, type SettingsRowProps, SettingsSection, type SettingsSectionProps, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, type SidebarDropZoneProps, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, type StatCardProps, StatusPill, type StatusPillProps, type StatusTone, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, type TextShimmerProps, Textarea, type TextareaProps, ThemeToggle, TimeSelect, type TimeSelectProps, type Toast, ToastContainer, ToastProvider, type Tone, type ToneClasses, Toolbar, type ToolbarProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, UploadProgress, type UploadProgressProps, Wizard, type WizardProps, WizardStep, type WizardStepProps, badgeVariants, buttonVariants, fieldMessageId, formatCalendarDate, initialsOf, localToday, normalizeSeries, parseCalendarDate, periodDelta, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, toneFor, useTheme, useToast };
|
package/dist/primitives.js
CHANGED
|
@@ -61,5 +61,6 @@ import { normalizeSeries, periodDelta, seriesAreaPath, seriesExtent, seriesLineP
|
|
|
61
61
|
import { SeriesSparkline } from "./primitives/series-sparkline.js";
|
|
62
62
|
import { MetricChart } from "./primitives/metric-chart.js";
|
|
63
63
|
import { FilterField, Toolbar } from "./primitives/toolbar.js";
|
|
64
|
+
import { ExpandablePanel } from "./primitives/expandable-panel.js";
|
|
64
65
|
import { Logo, TangleKnot } from "@tangle-network/brand";
|
|
65
|
-
export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ArtifactPane, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, Field, FilterField, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, Input, Label, Logo, Metric, MetricChart, MetricStrip, PageHeader, PageShell, Pagination, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsNote, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, TimeSelect, ToastContainer, ToastProvider, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, Wizard, WizardStep, badgeVariants, buttonVariants, fieldMessageId, formatCalendarDate, initialsOf, localToday, normalizeSeries, parseCalendarDate, periodDelta, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, toneFor, useTheme, useToast };
|
|
66
|
+
export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, ArtifactPane, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CATEGORY_TONES, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Chip, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, ComplianceBadge, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, ExpandablePanel, Field, FilterField, Heading, HelpText, HoverCard, HoverCardContent, HoverCardDescription, HoverCardHeader, HoverCardTitle, HoverCardTrigger, IconTile, InlineCode, Input, Label, Logo, Metric, MetricChart, MetricStrip, PageHeader, PageShell, Pagination, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeriesSparkline, SettingsList, SettingsListItem, SettingsNote, SettingsRow, SettingsSection, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarDropZone, Skeleton, SkeletonCard, SkeletonTable, Slider, StatCard, StatusPill, Switch, TONE_CLASSES, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, TextShimmer, Textarea, ThemeToggle, TimeSelect, ToastContainer, ToastProvider, Toolbar, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UploadProgress, Wizard, WizardStep, badgeVariants, buttonVariants, fieldMessageId, formatCalendarDate, initialsOf, localToday, normalizeSeries, parseCalendarDate, periodDelta, seriesAreaPath, seriesExtent, seriesLinePath, seriesMean, seriesScale, toneFor, useTheme, useToast };
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
export type RunRowStatus = "running" | "success" | "error" | "idle";
|
|
3
|
-
/**
|
|
4
|
-
* A red dot for a failed row, for rows composed outside the shell. The shell
|
|
5
|
-
* itself marks a failure on the row's own glyph, beside its name, never at the
|
|
6
|
-
* far edge. Success is silence, and a running row carries its state in the
|
|
7
|
-
* title — a `TextShimmer` sweep.
|
|
8
|
-
*/
|
|
9
|
-
export declare function RunRowStatusDot({ status }: {
|
|
10
|
-
status: RunRowStatus;
|
|
11
|
-
}): import("react").JSX.Element | null;
|
|
12
3
|
export interface RunRowShellProps {
|
|
13
4
|
/** Semantic lead glyph (14px). At rest it is the row's only ornament; on
|
|
14
5
|
* hover and while open the expand chevron takes its slot. */
|
|
@@ -22,10 +13,6 @@ export interface RunRowShellProps {
|
|
|
22
13
|
/** Render the description in mono (tools) vs prose (reasoning). */
|
|
23
14
|
descriptionMono?: boolean;
|
|
24
15
|
status?: RunRowStatus;
|
|
25
|
-
/** @deprecated The shell no longer ticks a live duration while running; the
|
|
26
|
-
* running state lives in the title (`TextShimmer`). Accepted and ignored so
|
|
27
|
-
* existing callers keep compiling. */
|
|
28
|
-
startTime?: number;
|
|
29
16
|
/** Static duration, revealed on hover once the row is no longer running. */
|
|
30
17
|
durationMs?: number;
|
|
31
18
|
/** Radius shaping when rows are stacked into a group. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { focusRingInset } from "../lib/focus.js";
|
|
1
2
|
import { cn } from "../lib/utils.js";
|
|
2
3
|
import { formatDuration as formatSpanDuration } from "../utils/format.js";
|
|
3
4
|
import { useState } from "react";
|
|
@@ -5,19 +6,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
5
6
|
import { ChevronRight } from "lucide-react";
|
|
6
7
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
7
8
|
// src/run/run-row-shell.tsx
|
|
8
|
-
/**
|
|
9
|
-
* A red dot for a failed row, for rows composed outside the shell. The shell
|
|
10
|
-
* itself marks a failure on the row's own glyph, beside its name, never at the
|
|
11
|
-
* far edge. Success is silence, and a running row carries its state in the
|
|
12
|
-
* title — a `TextShimmer` sweep.
|
|
13
|
-
*/
|
|
14
|
-
function RunRowStatusDot({ status }) {
|
|
15
|
-
if (status !== "error") return null;
|
|
16
|
-
return /* @__PURE__ */ jsx("span", {
|
|
17
|
-
"data-run-row-status": "error",
|
|
18
|
-
className: "h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]"
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
9
|
const SHAPE_CLASS = {
|
|
22
10
|
single: "rounded-[var(--radius-lg)]",
|
|
23
11
|
first: "rounded-t-[var(--radius-lg)] rounded-b-[var(--radius-sm)]",
|
|
@@ -58,7 +46,7 @@ function RunRowShell({ icon, title, description, descriptionMono = false, status
|
|
|
58
46
|
disabled: !expandable,
|
|
59
47
|
children: /* @__PURE__ */ jsxs("button", {
|
|
60
48
|
type: "button",
|
|
61
|
-
className: cn("group flex w-full items-center gap-2 text-left", HEADER_INSET, expandable ? "cursor-pointer" : "cursor-default"),
|
|
49
|
+
className: cn(focusRingInset, "group flex w-full items-center gap-2 text-left", HEADER_INSET, expandable ? "cursor-pointer" : "cursor-default"),
|
|
62
50
|
children: [
|
|
63
51
|
/* @__PURE__ */ jsxs("span", {
|
|
64
52
|
"aria-hidden": true,
|
|
@@ -109,4 +97,4 @@ function RunRowShell({ icon, title, description, descriptionMono = false, status
|
|
|
109
97
|
})
|
|
110
98
|
});
|
|
111
99
|
}
|
|
112
|
-
export { RunRowShell
|
|
100
|
+
export { RunRowShell };
|
package/dist/run.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { ToolCallStatus, ToolCallType } from "./run/tool-call-step.js";
|
|
2
2
|
import { FeedSegment, ToolCallData, ToolCallFeed, ToolCallFeedProps, parseToolEvent } from "./run/tool-call-feed.js";
|
|
3
3
|
import { RunGroup, RunGroupProps } from "./run/run-group.js";
|
|
4
|
-
import { RunRowShell, RunRowShellProps, RunRowStatus
|
|
4
|
+
import { RunRowShell, RunRowShellProps, RunRowStatus } from "./run/run-row-shell.js";
|
|
5
5
|
import { InlineToolItem, InlineToolItemProps } from "./run/inline-tool-item.js";
|
|
6
6
|
import { InlineThinkingItem, InlineThinkingItemProps } from "./run/inline-thinking-item.js";
|
|
7
7
|
import { ExpandedToolDetail, ExpandedToolDetailProps } from "./run/expanded-tool-detail.js";
|
|
8
|
-
import { LiveDuration } from "./run/run-item-primitives.js";
|
|
9
8
|
import { TaskList, TaskListItem, TaskListProps, TaskStatus, showsTaskPriority, taskProgress, taskStatus } from "./run/task-list.js";
|
|
10
9
|
import { ApprovalCard, ApprovalCardProps, ApprovalDiffFile, ApprovalDiffSummary, ApprovalPlanStep } from "./run/approval-card.js";
|
|
11
10
|
import { RunPhase, RunPhaseList } from "./run/run-phase-list.js";
|
|
12
11
|
import { RunStatus, RunStatusIcon, RunStatusIconProps, StatusMeta, isOpen, runStatus, statusMeta } from "./run/status-meta.js";
|
|
13
|
-
export { ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps,
|
|
12
|
+
export { ApprovalCard, type ApprovalCardProps, type ApprovalDiffFile, ApprovalDiffSummary, type ApprovalPlanStep, ExpandedToolDetail, type ExpandedToolDetailProps, type FeedSegment, InlineThinkingItem, type InlineThinkingItemProps, InlineToolItem, type InlineToolItemProps, RunGroup, type RunGroupProps, type RunPhase, RunPhaseList, RunRowShell, type RunRowShellProps, type RunRowStatus, type RunStatus, RunStatusIcon, type RunStatusIconProps, type StatusMeta, TaskList, type TaskListItem, type TaskListProps, type TaskStatus, type ToolCallData, ToolCallFeed, type ToolCallFeedProps, type ToolCallStatus, type ToolCallType, isOpen, parseToolEvent, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus };
|
package/dist/run.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { RunStatusIcon, isOpen, runStatus, statusMeta } from "./run/status-meta.js";
|
|
2
2
|
import { ExpandedToolDetail } from "./run/expanded-tool-detail.js";
|
|
3
|
-
import { RunRowShell
|
|
3
|
+
import { RunRowShell } from "./run/run-row-shell.js";
|
|
4
4
|
import { InlineToolItem } from "./run/inline-tool-item.js";
|
|
5
5
|
import { InlineThinkingItem } from "./run/inline-thinking-item.js";
|
|
6
6
|
import { RunGroup } from "./run/run-group.js";
|
|
7
|
-
import { LiveDuration } from "./run/run-item-primitives.js";
|
|
8
7
|
import { ToolCallFeed, parseToolEvent } from "./run/tool-call-feed.js";
|
|
9
8
|
import { TaskList, showsTaskPriority, taskProgress, taskStatus } from "./run/task-list.js";
|
|
10
9
|
import { ApprovalCard, ApprovalDiffSummary } from "./run/approval-card.js";
|
|
11
10
|
import { RunPhaseList } from "./run/run-phase-list.js";
|
|
12
|
-
export { ApprovalCard, ApprovalDiffSummary, ExpandedToolDetail, InlineThinkingItem, InlineToolItem,
|
|
11
|
+
export { ApprovalCard, ApprovalDiffSummary, ExpandedToolDetail, InlineThinkingItem, InlineToolItem, RunGroup, RunPhaseList, RunRowShell, RunStatusIcon, TaskList, ToolCallFeed, isOpen, parseToolEvent, runStatus, showsTaskPriority, statusMeta, taskProgress, taskStatus };
|
package/package.json
CHANGED
|
@@ -1,81 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { cleanup, render, screen } from "@testing-library/react";
|
|
3
3
|
import { afterEach, describe, expect, it } from "vitest";
|
|
4
|
-
import { controlHeight, controlText, fieldPresentation } from "../lib/control-presentation";
|
|
5
4
|
import { HelpText } from "./help-text";
|
|
6
5
|
import { Label } from "./label";
|
|
7
|
-
import { Button, buttonVariants } from "./button";
|
|
8
6
|
import { Input, Textarea } from "./input";
|
|
9
7
|
import { Select, SelectTrigger, SelectValue } from "./select";
|
|
10
8
|
|
|
11
9
|
afterEach(cleanup);
|
|
12
10
|
|
|
13
11
|
describe("shared control presentation", () => {
|
|
14
|
-
it("uses the field well, not the border/track alias, with scoped foreground", () => {
|
|
15
|
-
// The well is the brand's --well context variable; Toolbar can still pick the fill.
|
|
16
|
-
expect(fieldPresentation).toContain("bg-[var(--field-surface,var(--well))]");
|
|
17
|
-
expect(fieldPresentation.split(" ")).not.toContain("bg-input");
|
|
18
|
-
expect(fieldPresentation.split(" ")).not.toContain("bg-card");
|
|
19
|
-
// ixField's --field-border replaces focusField's resting border-border.
|
|
20
|
-
expect(fieldPresentation.split(" ")).toContain("border-[var(--field-border)]");
|
|
21
|
-
expect(fieldPresentation.split(" ")).not.toContain("border-border");
|
|
22
|
-
expect(fieldPresentation).toContain("text-foreground");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("puts Button, Input, Textarea and SelectTrigger on one height and text scale", () => {
|
|
26
|
-
const classes = (name: string) => screen.getByLabelText(name).className.split(" ");
|
|
27
|
-
const { rerender } = render(<><Input aria-label="Input" /><Textarea aria-label="Textarea" /><Button aria-label="Action">Action</Button><Select><SelectTrigger aria-label="Select"><SelectValue /></SelectTrigger></Select></>);
|
|
28
|
-
// The default is md for every control: one 36px height, one 14px text size, one corner.
|
|
29
|
-
for (const name of ["Input", "Action", "Select"]) {
|
|
30
|
-
expect(classes(name)).toContain(controlHeight.md);
|
|
31
|
-
expect(classes(name)).toContain(controlText.md);
|
|
32
|
-
expect(classes(name)).toContain("rounded-lg");
|
|
33
|
-
}
|
|
34
|
-
expect(classes("Textarea")).toContain(controlText.md);
|
|
35
|
-
expect(screen.getByLabelText("Textarea").className).toContain("min-h-[120px]");
|
|
36
|
-
for (const size of ["sm", "md", "lg"] as const) {
|
|
37
|
-
rerender(<><Input size={size} aria-label="Input" /><Textarea size={size} aria-label="Textarea" /><Button size={size} aria-label="Action">Action</Button><Select><SelectTrigger size={size} aria-label="Select"><SelectValue /></SelectTrigger></Select></>);
|
|
38
|
-
for (const name of ["Input", "Action", "Select"]) {
|
|
39
|
-
expect(classes(name), `${name} ${size}`).toContain(controlHeight[size]);
|
|
40
|
-
expect(classes(name), `${name} ${size}`).toContain(controlText[size]);
|
|
41
|
-
expect(classes(name), `${name} ${size}`).toContain(size === "sm" ? "rounded-md" : "rounded-lg");
|
|
42
|
-
expect(screen.getByLabelText(name)).not.toHaveAttribute("size");
|
|
43
|
-
}
|
|
44
|
-
expect(classes("Textarea")).toContain(controlText[size]);
|
|
45
|
-
}
|
|
46
|
-
// Fields never drop below 16px on a coarse pointer (iOS zooms on focus otherwise).
|
|
47
|
-
for (const name of ["Input", "Textarea", "Select"]) expect(classes(name)).toContain("pointer-coarse:text-base");
|
|
48
|
-
expect(classes("Action")).not.toContain("pointer-coarse:text-base");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("keeps the explicit compact and touch sizes", () => {
|
|
52
|
-
const { rerender } = render(<><Input size="compact" aria-label="Input" /><Button size="compact">Action</Button><Select><SelectTrigger size="compact" aria-label="Select"><SelectValue /></SelectTrigger></Select></>);
|
|
53
|
-
for (const size of ["compact", "touch"] as const) {
|
|
54
|
-
rerender(<><Input size={size} aria-label="Input" /><Textarea size={size} aria-label="Textarea" /><Button size={size}>Action</Button><Select><SelectTrigger size={size} aria-label="Select"><SelectValue /></SelectTrigger></Select></>);
|
|
55
|
-
for (const name of ["Input", "Select"]) {
|
|
56
|
-
expect(screen.getByLabelText(name).className).toContain(size === "compact" ? "h-[var(--control-height)]" : "min-h-11");
|
|
57
|
-
expect(screen.getByLabelText(name).className.split(" ")).toContain("rounded-lg");
|
|
58
|
-
expect(screen.getByLabelText(name)).not.toHaveAttribute("size");
|
|
59
|
-
}
|
|
60
|
-
expect(screen.getByText("Action").className).toContain(size === "compact" ? "h-[var(--control-height)]" : "min-h-11");
|
|
61
|
-
expect(screen.getByLabelText("Textarea")).not.toHaveAttribute("size");
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("lets a file input's selector button take the field's text size", () => {
|
|
66
|
-
render(<Input type="file" size="lg" aria-label="Upload" />);
|
|
67
|
-
const classes = screen.getByLabelText("Upload").className.split(" ");
|
|
68
|
-
expect(classes).toContain("text-[length:var(--control-text-lg,1rem)]");
|
|
69
|
-
expect(classes.filter((name) => name.startsWith("file:text-"))).toEqual([]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it("gives icon buttons squares on the same heights", () => {
|
|
73
|
-
render(<><Button size="icon-sm" aria-label="Small" /><Button size="icon" aria-label="Medium" /><Button size="icon-lg" aria-label="Large" /></>);
|
|
74
|
-
expect(screen.getByLabelText("Small").className).toContain("size-[var(--control-height-sm,2rem)]");
|
|
75
|
-
expect(screen.getByLabelText("Medium").className).toContain("size-[var(--control-height,2.25rem)]");
|
|
76
|
-
expect(screen.getByLabelText("Large").className).toContain("size-[var(--control-height-lg,2.75rem)]");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
12
|
it("renders labels and help text at one size each, and wires hint and error to the field", () => {
|
|
80
13
|
render(<><Label htmlFor="x">Name</Label><HelpText>Plain</HelpText><Input label="Email" hint="We never share it" error="Enter an address" /></>);
|
|
81
14
|
expect(screen.getByText("Name").className).toContain("text-[length:var(--font-size-label,0.875rem)]");
|
|
@@ -105,29 +38,4 @@ describe("shared control presentation", () => {
|
|
|
105
38
|
expect(trigger.current).toBeDisabled();
|
|
106
39
|
expect(trigger.current!.className.split(" ")).toContain("h-12");
|
|
107
40
|
});
|
|
108
|
-
|
|
109
|
-
it("uses accent ink for link actions while retaining filled action foregrounds and scale motion", () => {
|
|
110
|
-
expect(buttonVariants({ variant: "link" })).toContain("text-[var(--accent-text)]");
|
|
111
|
-
expect(buttonVariants({ variant: "default" })).toContain("text-primary-foreground");
|
|
112
|
-
expect(buttonVariants({ variant: "destructive" })).toContain("text-destructive-foreground");
|
|
113
|
-
expect(buttonVariants({ variant: "sandbox" })).toContain("text-[var(--btn-primary-text)]");
|
|
114
|
-
expect(buttonVariants()).not.toContain("transition-all");
|
|
115
|
-
expect(buttonVariants()).toContain("motion-reduce:active:scale-100");
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe("SelectTrigger with a value longer than the trigger", () => {
|
|
120
|
-
it("ends the value in an ellipsis with a gap before the chevron", () => {
|
|
121
|
-
const value = "Luna — ReCenter Guest Concierge & Practitioner Desk";
|
|
122
|
-
render(<Select value="concierge"><SelectTrigger aria-label="Agent" className="w-40"><SelectValue>{value}</SelectValue></SelectTrigger></Select>);
|
|
123
|
-
const trigger = screen.getByLabelText("Agent");
|
|
124
|
-
const classes = trigger.className.split(" ");
|
|
125
|
-
// line-clamp cannot ellipsize a nowrap line: it clipped mid-glyph under the chevron.
|
|
126
|
-
expect(trigger.className).not.toContain("line-clamp");
|
|
127
|
-
expect(classes).toContain("[&>span]:truncate");
|
|
128
|
-
expect(classes).toContain("[&>span]:min-w-0");
|
|
129
|
-
expect(classes).toContain("gap-2");
|
|
130
|
-
// The rule targets the value span, which Radix renders as the trigger's direct child.
|
|
131
|
-
expect(trigger.querySelector(":scope > span")?.textContent).toBe(value);
|
|
132
|
-
});
|
|
133
41
|
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { Button } from './button'
|
|
3
|
+
import { ExpandablePanel } from './expandable-panel'
|
|
4
|
+
import { MetricChart } from './metric-chart'
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from './popover'
|
|
6
|
+
|
|
7
|
+
const meta: Meta = {
|
|
8
|
+
title: 'Primitives/ExpandablePanel',
|
|
9
|
+
parameters: { layout: 'padded', backgrounds: { default: 'dark' } },
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default meta
|
|
13
|
+
type Story = StoryObj
|
|
14
|
+
|
|
15
|
+
const t0 = Date.parse('2026-08-24T07:00:00.000Z')
|
|
16
|
+
const points = Array.from({ length: 24 }, (_, i) => ({ at: t0 + i * 3_600_000, value: 40 + Math.round(20 * Math.sin(i / 3)) + i }))
|
|
17
|
+
|
|
18
|
+
// Hover or focus the panel for the toggle; Escape closes the open popover first, then the panel.
|
|
19
|
+
export const ChartPanel: Story = {
|
|
20
|
+
render: () => (
|
|
21
|
+
<ExpandablePanel
|
|
22
|
+
label="Throughput chart"
|
|
23
|
+
className="h-72 w-[560px] rounded-xl border border-border bg-card p-4"
|
|
24
|
+
actions={
|
|
25
|
+
<Popover>
|
|
26
|
+
<PopoverTrigger asChild>
|
|
27
|
+
<Button variant="ghost" size="sm">Range</Button>
|
|
28
|
+
</PopoverTrigger>
|
|
29
|
+
<PopoverContent className="w-48 text-sm">Last 24 hours</PopoverContent>
|
|
30
|
+
</Popover>
|
|
31
|
+
}
|
|
32
|
+
>
|
|
33
|
+
<MetricChart title="Throughput" unit="req/s" points={points} className="min-h-0 flex-1" />
|
|
34
|
+
</ExpandablePanel>
|
|
35
|
+
),
|
|
36
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
2
|
+
import userEvent from "@testing-library/user-event";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { ExpandablePanel } from "./expandable-panel";
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
|
|
6
|
+
|
|
7
|
+
describe("ExpandablePanel", () => {
|
|
8
|
+
// The journey a run view needs: expand in place, let an inner popover take the
|
|
9
|
+
// first Escape, close the top-most panel on the next, and hand focus back.
|
|
10
|
+
it("expands in place and closes the top-most panel on Escape after inner layers", async () => {
|
|
11
|
+
const user = userEvent.setup();
|
|
12
|
+
render(
|
|
13
|
+
<ExpandablePanel label="Run">
|
|
14
|
+
<p data-testid="content">chart</p>
|
|
15
|
+
<ExpandablePanel label="Chart">
|
|
16
|
+
<Popover>
|
|
17
|
+
<PopoverTrigger>Range</PopoverTrigger>
|
|
18
|
+
<PopoverContent>Last 24 hours</PopoverContent>
|
|
19
|
+
</Popover>
|
|
20
|
+
</ExpandablePanel>
|
|
21
|
+
</ExpandablePanel>,
|
|
22
|
+
);
|
|
23
|
+
const content = screen.getByTestId("content"), outer = content.parentElement!;
|
|
24
|
+
|
|
25
|
+
await user.click(screen.getByRole("button", { name: "Expand Run" }));
|
|
26
|
+
expect(outer).toHaveAttribute("data-expanded");
|
|
27
|
+
expect(outer.className).toContain("fixed");
|
|
28
|
+
expect(screen.getByTestId("content")).toBe(content);
|
|
29
|
+
expect(document.body.style.overflow).toBe("hidden");
|
|
30
|
+
|
|
31
|
+
await user.click(screen.getByRole("button", { name: "Expand Chart" }));
|
|
32
|
+
await user.click(screen.getByRole("button", { name: "Range" }));
|
|
33
|
+
expect(await screen.findByText("Last 24 hours")).toBeInTheDocument();
|
|
34
|
+
|
|
35
|
+
await user.keyboard("{Escape}");
|
|
36
|
+
await waitFor(() => expect(screen.queryByText("Last 24 hours")).not.toBeInTheDocument());
|
|
37
|
+
expect(screen.getByRole("button", { name: "Close full screen Chart" })).toBeInTheDocument();
|
|
38
|
+
|
|
39
|
+
await user.keyboard("{Escape}");
|
|
40
|
+
expect(screen.getByRole("button", { name: "Expand Chart" })).toHaveFocus();
|
|
41
|
+
expect(outer).toHaveAttribute("data-expanded");
|
|
42
|
+
expect(document.body.style.overflow).toBe("hidden");
|
|
43
|
+
|
|
44
|
+
await user.keyboard("{Escape}");
|
|
45
|
+
expect(outer).not.toHaveAttribute("data-expanded");
|
|
46
|
+
expect(screen.getByRole("button", { name: "Expand Run" })).toHaveFocus();
|
|
47
|
+
expect(document.body.style.overflow).toBe("");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Maximize2, Minimize2 } from "lucide-react";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
|
|
8
|
+
export interface ExpandablePanelProps {
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
/** Accessible name: the toggle reads "Expand <label>" and "Close full screen <label>". */
|
|
11
|
+
label: string;
|
|
12
|
+
expanded?: boolean;
|
|
13
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
14
|
+
className?: string;
|
|
15
|
+
actions?: React.ReactNode; // controls shown beside the toggle
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Expanded panels in opening order. Escape closes the last one that holds no other.
|
|
19
|
+
const openPanels: HTMLElement[] = [];
|
|
20
|
+
let bodyOverflow = "";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A panel that fills the viewport in place and returns on Escape. The subtree
|
|
24
|
+
* never moves (no portal), so chart, canvas and conversation state and scroll
|
|
25
|
+
* survive the switch. Radix popovers, menus and dialogs inside take Escape
|
|
26
|
+
* first: they prevent its default, which this panel respects. An ancestor
|
|
27
|
+
* with a transform or filter would contain the fixed panel, so avoid one.
|
|
28
|
+
*/
|
|
29
|
+
function ExpandablePanel({
|
|
30
|
+
children,
|
|
31
|
+
label,
|
|
32
|
+
expanded: expandedProp,
|
|
33
|
+
onExpandedChange,
|
|
34
|
+
className,
|
|
35
|
+
actions,
|
|
36
|
+
}: ExpandablePanelProps) {
|
|
37
|
+
const [expandedState, setExpandedState] = React.useState(false);
|
|
38
|
+
const expanded = expandedProp ?? expandedState;
|
|
39
|
+
const toggleRef = React.useRef<HTMLButtonElement>(null);
|
|
40
|
+
const panelRef = React.useRef<HTMLDivElement>(null);
|
|
41
|
+
const wasExpanded = React.useRef(expanded);
|
|
42
|
+
const setExpanded = (next: boolean) => {
|
|
43
|
+
if (expandedProp === undefined) setExpandedState(next);
|
|
44
|
+
onExpandedChange?.(next);
|
|
45
|
+
};
|
|
46
|
+
// A ref, so a new onExpandedChange never re-registers and reorders the open stack.
|
|
47
|
+
const setExpandedRef = React.useRef(setExpanded);
|
|
48
|
+
setExpandedRef.current = setExpanded;
|
|
49
|
+
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
if (wasExpanded.current && !expanded) toggleRef.current?.focus();
|
|
52
|
+
wasExpanded.current = expanded;
|
|
53
|
+
const id = panelRef.current;
|
|
54
|
+
if (!expanded || !id) return;
|
|
55
|
+
if (openPanels.length === 0) bodyOverflow = document.body.style.overflow;
|
|
56
|
+
openPanels.push(id);
|
|
57
|
+
document.body.style.overflow = "hidden";
|
|
58
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
59
|
+
const top = openPanels.filter((p) => !openPanels.some((q) => q !== p && p.contains(q))).pop();
|
|
60
|
+
if (event.key !== "Escape" || event.defaultPrevented || top !== id) return;
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
setExpandedRef.current(false);
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener("keydown", onKeyDown);
|
|
65
|
+
return () => {
|
|
66
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
67
|
+
openPanels.splice(openPanels.indexOf(id), 1);
|
|
68
|
+
if (openPanels.length === 0) document.body.style.overflow = bodyOverflow;
|
|
69
|
+
};
|
|
70
|
+
}, [expanded]);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
ref={panelRef}
|
|
75
|
+
data-expandable-panel=""
|
|
76
|
+
data-expanded={expanded ? "" : undefined}
|
|
77
|
+
className={cn(
|
|
78
|
+
"group/expandable relative flex min-h-0 flex-col",
|
|
79
|
+
className, // before the expanded classes, so a caller's size cannot shrink it
|
|
80
|
+
expanded && "fixed inset-0 z-50 m-0 size-auto min-h-0 min-w-0 max-h-none max-w-none rounded-none transform-none bg-background",
|
|
81
|
+
)}
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
<div
|
|
85
|
+
className={cn(
|
|
86
|
+
"absolute right-2 top-2 z-10 flex items-center gap-1 transition-opacity",
|
|
87
|
+
expanded
|
|
88
|
+
? "opacity-100"
|
|
89
|
+
: "opacity-0 group-hover/expandable:opacity-100 group-focus-within/expandable:opacity-100 pointer-coarse:opacity-100",
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
{actions}
|
|
93
|
+
<Button
|
|
94
|
+
ref={toggleRef}
|
|
95
|
+
type="button"
|
|
96
|
+
variant="ghost"
|
|
97
|
+
size="icon-sm"
|
|
98
|
+
aria-label={`${expanded ? "Close full screen" : "Expand"} ${label}`}
|
|
99
|
+
onClick={() => setExpanded(!expanded)}
|
|
100
|
+
>
|
|
101
|
+
{expanded ? <Minimize2 aria-hidden /> : <Maximize2 aria-hidden />}
|
|
102
|
+
</Button>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export { ExpandablePanel };
|
package/src/primitives/index.ts
CHANGED
|
@@ -279,3 +279,6 @@ export type {
|
|
|
279
279
|
|
|
280
280
|
export { Toolbar, FilterField } from "./toolbar";
|
|
281
281
|
export type { ToolbarProps, FilterFieldProps } from "./toolbar";
|
|
282
|
+
|
|
283
|
+
export { ExpandablePanel } from "./expandable-panel";
|
|
284
|
+
export type { ExpandablePanelProps } from "./expandable-panel";
|
|
@@ -52,51 +52,6 @@ describe("MetricStrip", () => {
|
|
|
52
52
|
expect(screen.getByText("$0.00").className).not.toContain("--surface-danger-text");
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
it("retains the default two / sm:four grid", () => {
|
|
56
|
-
const { container } = render(<MetricStrip><Metric label="Runs" value={0} /></MetricStrip>);
|
|
57
|
-
const dl = container.querySelector("dl")!;
|
|
58
|
-
expect(dl.className.split(" ")).toEqual(expect.arrayContaining(["grid-cols-2", "sm:grid-cols-4"]));
|
|
59
|
-
expect(dl.className).not.toContain("lg:grid-cols");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it.each([3, 4, 5, 6] as const)("owns the grid and all nonoverlapping row-start guards for %i columns", (columns) => {
|
|
63
|
-
const { container } = render(
|
|
64
|
-
<MetricStrip columns={columns}>
|
|
65
|
-
{Array.from({ length: columns }, (_, i) => <Metric key={i} label={`Metric ${i}`} value={i} />)}
|
|
66
|
-
</MetricStrip>,
|
|
67
|
-
);
|
|
68
|
-
const dl = container.querySelector("dl")!;
|
|
69
|
-
expect(dl).not.toHaveAttribute("columns");
|
|
70
|
-
expect(dl.className).toContain("max-sm:[&>div:not(:nth-child(2n+1))]:border-l");
|
|
71
|
-
if (columns <= 4) {
|
|
72
|
-
expect(dl.className).toContain(`sm:grid-cols-${columns}`);
|
|
73
|
-
expect(dl.className).toContain(`sm:[&>div:not(:nth-child(${columns}n+1))]:border-l`);
|
|
74
|
-
} else {
|
|
75
|
-
expect(dl.className).toContain("sm:grid-cols-3");
|
|
76
|
-
expect(dl.className).toContain("sm:max-lg:[&>div:not(:nth-child(3n+1))]:border-l");
|
|
77
|
-
expect(dl.className).toContain(`lg:grid-cols-${columns}`);
|
|
78
|
-
expect(dl.className).toContain(`lg:[&>div:not(:nth-child(${columns}n+1))]:border-l`);
|
|
79
|
-
}
|
|
80
|
-
expect(dl.className).not.toContain("border-l-0");
|
|
81
|
-
for (const item of Array.from(dl.children)) expect(item.className).not.toContain("nth-child");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("does not give a standalone Metric a strip divider", () => {
|
|
85
|
-
const { container } = render(<Metric label="Runs" value={0} />);
|
|
86
|
-
expect(container.firstElementChild!.className).not.toContain("border-l");
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("wraps full labels, values and qualifiers without relying on a mouse title", () => {
|
|
90
|
-
render(<MetricStrip><Metric label="Very long account label without loss" value="$1,284,003.10" hint="Personal wallet (0x1234abcd5678efgh)" /></MetricStrip>);
|
|
91
|
-
for (const text of ["Very long account label without loss", "$1,284,003.10", "Personal wallet (0x1234abcd5678efgh)"]) {
|
|
92
|
-
const node = screen.getByText(text);
|
|
93
|
-
expect(node.className).toContain("[overflow-wrap:anywhere]");
|
|
94
|
-
expect(node.className).not.toContain("truncate");
|
|
95
|
-
}
|
|
96
|
-
expect(screen.getByText("$1,284,003.10")).toHaveAttribute("title", "$1,284,003.10");
|
|
97
|
-
expect(screen.getByText("Personal wallet (0x1234abcd5678efgh)")).toHaveAttribute("title", "Personal wallet (0x1234abcd5678efgh)");
|
|
98
|
-
});
|
|
99
|
-
|
|
100
55
|
it("preserves refs, attributes, caller classes and fragment/conditional DOM order", () => {
|
|
101
56
|
const strip = React.createRef<HTMLDListElement>();
|
|
102
57
|
const item = React.createRef<HTMLDivElement>();
|
package/src/run/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { RunGroup, type RunGroupProps } from "./run-group";
|
|
2
2
|
export {
|
|
3
3
|
RunRowShell,
|
|
4
|
-
RunRowStatusDot,
|
|
5
4
|
type RunRowShellProps,
|
|
6
5
|
type RunRowStatus,
|
|
7
6
|
} from "./run-row-shell";
|
|
@@ -14,7 +13,6 @@ export {
|
|
|
14
13
|
ExpandedToolDetail,
|
|
15
14
|
type ExpandedToolDetailProps,
|
|
16
15
|
} from "./expanded-tool-detail";
|
|
17
|
-
export { LiveDuration } from "./run-item-primitives";
|
|
18
16
|
// ToolCallStep/ToolCallGroup are internal adapters over InlineToolItem (used by
|
|
19
17
|
// AgentTimeline + ToolCallFeed); only their status/type vocabulary is public
|
|
20
18
|
// because ToolCallData references it.
|
|
@@ -1,27 +1,12 @@
|
|
|
1
1
|
import { useState, type ReactNode } from "react";
|
|
2
2
|
import * as Collapsible from "@radix-ui/react-collapsible";
|
|
3
3
|
import { ChevronRight } from "lucide-react";
|
|
4
|
+
import { focusRingInset } from "../lib/focus";
|
|
4
5
|
import { cn } from "../lib/utils";
|
|
5
6
|
import { formatDuration } from "../utils/format";
|
|
6
7
|
|
|
7
8
|
export type RunRowStatus = "running" | "success" | "error" | "idle";
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
* A red dot for a failed row, for rows composed outside the shell. The shell
|
|
11
|
-
* itself marks a failure on the row's own glyph, beside its name, never at the
|
|
12
|
-
* far edge. Success is silence, and a running row carries its state in the
|
|
13
|
-
* title — a `TextShimmer` sweep.
|
|
14
|
-
*/
|
|
15
|
-
export function RunRowStatusDot({ status }: { status: RunRowStatus }) {
|
|
16
|
-
if (status !== "error") return null;
|
|
17
|
-
return (
|
|
18
|
-
<span
|
|
19
|
-
data-run-row-status="error"
|
|
20
|
-
className="h-1.5 w-1.5 shrink-0 rounded-full bg-[var(--surface-danger-text)]"
|
|
21
|
-
/>
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
10
|
export interface RunRowShellProps {
|
|
26
11
|
/** Semantic lead glyph (14px). At rest it is the row's only ornament; on
|
|
27
12
|
* hover and while open the expand chevron takes its slot. */
|
|
@@ -35,10 +20,6 @@ export interface RunRowShellProps {
|
|
|
35
20
|
/** Render the description in mono (tools) vs prose (reasoning). */
|
|
36
21
|
descriptionMono?: boolean;
|
|
37
22
|
status?: RunRowStatus;
|
|
38
|
-
/** @deprecated The shell no longer ticks a live duration while running; the
|
|
39
|
-
* running state lives in the title (`TextShimmer`). Accepted and ignored so
|
|
40
|
-
* existing callers keep compiling. */
|
|
41
|
-
startTime?: number;
|
|
42
23
|
/** Static duration, revealed on hover once the row is no longer running. */
|
|
43
24
|
durationMs?: number;
|
|
44
25
|
/** Radius shaping when rows are stacked into a group. */
|
|
@@ -128,7 +109,10 @@ export function RunRowShell({
|
|
|
128
109
|
// The header is the hover group, not the whole card: rows nested in an
|
|
129
110
|
// open row (a fold's steps) keep their own glyphs while the
|
|
130
111
|
// pointer is over them.
|
|
112
|
+
// Inset focus ring: the row clips overflow, so the shared ring
|
|
113
|
+
// must draw inside the trigger instead of around it.
|
|
131
114
|
className={cn(
|
|
115
|
+
focusRingInset,
|
|
132
116
|
"group flex w-full items-center gap-2 text-left",
|
|
133
117
|
HEADER_INSET,
|
|
134
118
|
expandable ? "cursor-pointer" : "cursor-default",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { formatDuration as formatSpanDuration } from "../utils/format.js";
|
|
2
|
-
import { useLiveTime } from "../hooks/use-live-time.js";
|
|
3
|
-
import { jsx } from "react/jsx-runtime";
|
|
4
|
-
// src/run/run-item-primitives.tsx
|
|
5
|
-
function LiveDuration({ startTime }) {
|
|
6
|
-
const elapsed = useLiveTime(100) - startTime;
|
|
7
|
-
return /* @__PURE__ */ jsx("span", {
|
|
8
|
-
className: "text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums",
|
|
9
|
-
children: formatSpanDuration(elapsed)
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
export { LiveDuration };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { Switch } from "./switch";
|
|
4
|
-
|
|
5
|
-
afterEach(cleanup);
|
|
6
|
-
|
|
7
|
-
/** The classes that apply in a state: unprefixed ones, plus that state's variant. */
|
|
8
|
-
function stateClasses(el: Element, state: "checked" | "unchecked"): string[] {
|
|
9
|
-
return (el.getAttribute("class") ?? "")
|
|
10
|
-
.split(/\s+/)
|
|
11
|
-
.filter((c) => !c.startsWith("data-[") || c.startsWith(`data-[state=${state}]:`))
|
|
12
|
-
.map((c) => c.replace(`data-[state=${state}]:`, ""));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe("Switch", () => {
|
|
16
|
-
it("draws its off state in muted-foreground, so an unchecked switch is visible on a card or the canvas", () => {
|
|
17
|
-
render(<Switch aria-label="Reminders" />);
|
|
18
|
-
const track = screen.getByRole("switch", { name: "Reminders" });
|
|
19
|
-
const thumb = track.firstElementChild as Element;
|
|
20
|
-
expect(track).toHaveAttribute("data-state", "unchecked");
|
|
21
|
-
expect(stateClasses(track, "unchecked")).toContain("border-muted-foreground");
|
|
22
|
-
expect(stateClasses(track, "unchecked")).not.toContain("bg-input");
|
|
23
|
-
expect(stateClasses(thumb, "unchecked")).toContain("bg-muted-foreground");
|
|
24
|
-
expect(stateClasses(thumb, "unchecked")).not.toContain("bg-background");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("draws its on state as an accent-text track with a card thumb, so a checked switch clears 3:1 in every theme", () => {
|
|
28
|
-
render(<Switch aria-label="Reminders" />);
|
|
29
|
-
const track = screen.getByRole("switch", { name: "Reminders" });
|
|
30
|
-
fireEvent.click(track);
|
|
31
|
-
expect(track).toHaveAttribute("data-state", "checked");
|
|
32
|
-
const thumb = track.firstElementChild as Element;
|
|
33
|
-
expect(stateClasses(track, "checked")).toContain("bg-[var(--accent-text)]");
|
|
34
|
-
expect(stateClasses(track, "checked")).toContain("border-transparent");
|
|
35
|
-
expect(stateClasses(track, "checked")).not.toContain("bg-primary");
|
|
36
|
-
expect(stateClasses(thumb, "checked")).toContain("bg-card");
|
|
37
|
-
expect(stateClasses(thumb, "checked")).not.toContain("bg-background");
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { render, screen } from "@testing-library/react";
|
|
2
|
-
import { describe, expect, it } from "vitest";
|
|
3
|
-
import { FilterField, Toolbar } from "./toolbar";
|
|
4
|
-
|
|
5
|
-
describe("Toolbar", () => {
|
|
6
|
-
it("renders each slot it is given", () => {
|
|
7
|
-
render(
|
|
8
|
-
<Toolbar
|
|
9
|
-
actions={<button type="button">Export</button>}
|
|
10
|
-
filters={<span>Product</span>}
|
|
11
|
-
search={<input aria-label="Search" type="search" />}
|
|
12
|
-
/>,
|
|
13
|
-
);
|
|
14
|
-
expect(screen.getByLabelText("Search")).toBeInTheDocument();
|
|
15
|
-
expect(screen.getByText("Product")).toBeInTheDocument();
|
|
16
|
-
expect(screen.getByRole("button", { name: "Export" })).toBeInTheDocument();
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it("omits a slot's wrapper entirely when it is not given", () => {
|
|
20
|
-
const { container } = render(
|
|
21
|
-
<Toolbar search={<input aria-label="Search" type="search" />} />,
|
|
22
|
-
);
|
|
23
|
-
const row = container.firstElementChild as HTMLElement;
|
|
24
|
-
expect(row.children).toHaveLength(1);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
// Filters keep their content width while it fits and shrink (scrolling) only
|
|
28
|
-
// once search reaches its 16rem floor; an even split clipped a third filter at
|
|
29
|
-
// 1440px, and no floor left search 89px wide in an 832px toolbar.
|
|
30
|
-
it("keeps filters at content width above a search floor, actions at content width", () => {
|
|
31
|
-
const { container } = render(
|
|
32
|
-
<Toolbar
|
|
33
|
-
actions={<button type="button">Export</button>}
|
|
34
|
-
filters={<span>Product</span>}
|
|
35
|
-
search={<input aria-label="Search" type="search" />}
|
|
36
|
-
/>,
|
|
37
|
-
);
|
|
38
|
-
const [searchSlot, filterSlot, actionsSlot] = Array.from(
|
|
39
|
-
(container.firstElementChild as HTMLElement).children,
|
|
40
|
-
) as HTMLElement[];
|
|
41
|
-
const search = searchSlot.className.split(" ");
|
|
42
|
-
const filters = filterSlot.className.split(" ");
|
|
43
|
-
expect(search).toEqual(expect.arrayContaining(["lg:flex-1", "lg:min-w-64", "lg:max-w-sm", "min-w-0"]));
|
|
44
|
-
expect(filters).toEqual(expect.arrayContaining(["lg:flex-initial", "min-w-0", "lg:overflow-x-auto"]));
|
|
45
|
-
expect(filters).not.toContain("lg:flex-1");
|
|
46
|
-
expect(actionsSlot.className).toContain("shrink-0");
|
|
47
|
-
expect(actionsSlot.className).not.toContain("flex-1");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("wraps the filters on a phone and scrolls one line from lg up", () => {
|
|
51
|
-
const { container } = render(<Toolbar filters={<span>Product</span>} />);
|
|
52
|
-
const filterSlot = (container.firstElementChild as HTMLElement)
|
|
53
|
-
.children[0] as HTMLElement;
|
|
54
|
-
const classes = filterSlot.className.split(" ");
|
|
55
|
-
expect(classes).toContain("flex-wrap");
|
|
56
|
-
expect(classes).not.toContain("overflow-x-auto");
|
|
57
|
-
expect(classes).toContain("lg:flex-nowrap");
|
|
58
|
-
expect(classes).toContain("lg:overflow-x-auto");
|
|
59
|
-
expect(classes).toContain("min-w-0");
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// A free child would render as a bare flex item with none of the slots'
|
|
63
|
-
// guards, so it would size off its content and push the row into overflow.
|
|
64
|
-
it("renders nothing for a stray child", () => {
|
|
65
|
-
const { container } = render(
|
|
66
|
-
// @ts-expect-error children is deliberately not part of the API
|
|
67
|
-
<Toolbar>
|
|
68
|
-
<span>stray</span>
|
|
69
|
-
</Toolbar>,
|
|
70
|
-
);
|
|
71
|
-
expect(screen.queryByText("stray")).toBeNull();
|
|
72
|
-
expect((container.firstElementChild as HTMLElement).children).toHaveLength(
|
|
73
|
-
0,
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe("FilterField", () => {
|
|
79
|
-
it("labels the control visibly rather than by placeholder", () => {
|
|
80
|
-
render(
|
|
81
|
-
<FilterField htmlFor="product" label="Product">
|
|
82
|
-
<select id="product">
|
|
83
|
-
<option>All products</option>
|
|
84
|
-
</select>
|
|
85
|
-
</FilterField>,
|
|
86
|
-
);
|
|
87
|
-
expect(screen.getByText("Product")).toBeInTheDocument();
|
|
88
|
-
expect(screen.getByLabelText("Product")).toBe(
|
|
89
|
-
screen.getByRole("combobox"),
|
|
90
|
-
);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("sets its label on the 14px step of the shared scale, never smaller", () => {
|
|
94
|
-
render(
|
|
95
|
-
<FilterField htmlFor="status" label="Status">
|
|
96
|
-
<select id="status" />
|
|
97
|
-
</FilterField>,
|
|
98
|
-
);
|
|
99
|
-
const label = screen.getByText("Status");
|
|
100
|
-
expect(label.className).toMatch(/\btext-sm\b/);
|
|
101
|
-
expect(label.className).not.toMatch(/\btext-xs\b|text-\[/);
|
|
102
|
-
});
|
|
103
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { useLiveTime } from "../hooks/use-live-time";
|
|
2
|
-
import { formatDuration } from "../utils/format";
|
|
3
|
-
|
|
4
|
-
export function LiveDuration({ startTime }: { startTime: number }) {
|
|
5
|
-
const elapsed = useLiveTime(100) - startTime;
|
|
6
|
-
|
|
7
|
-
return (
|
|
8
|
-
<span className="text-xs font-mono text-neutral-400 dark:text-neutral-500 tabular-nums">
|
|
9
|
-
{formatDuration(elapsed)}
|
|
10
|
-
</span>
|
|
11
|
-
);
|
|
12
|
-
}
|