@ctrl-ui/react 0.9.5 → 0.9.6
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/README.md +2 -2
- package/dist/action-bar.js +16 -8
- package/dist/activity.d.ts +1 -1
- package/dist/activity.js +3 -1
- package/dist/audio-visualizer.js +1 -1
- package/dist/blocks/agent-run-clock.d.ts +5 -0
- package/dist/blocks/agent-run-clock.js +52 -0
- package/dist/blocks/agent-run-sidebar.d.ts +13 -0
- package/dist/blocks/agent-run-sidebar.js +100 -0
- package/dist/blocks/agent-run-status.d.ts +32 -0
- package/dist/blocks/agent-run-status.js +27 -0
- package/dist/blocks/agent-run.d.ts +80 -0
- package/dist/blocks/agent-run.js +254 -0
- package/dist/blocks/coding-agent.d.ts +1 -1
- package/dist/blocks/design-canvas-data.d.ts +1 -1
- package/dist/blocks/design-canvas.d.ts +2 -1
- package/dist/blocks/design-canvas.js +15 -8
- package/dist/chat-message.js +33 -39
- package/dist/knob-contracts/infinite-canvas-knobs.d.ts +1 -1
- package/dist/knob-contracts/infinite-canvas-knobs.js +1 -7
- package/dist/knob-contracts/swap-knobs.d.ts +4 -0
- package/dist/knob-contracts/swap-knobs.js +9 -0
- package/dist/knob-contracts/timeline-knobs.d.ts +1 -1
- package/dist/knob-contracts/timeline-knobs.js +1 -0
- package/dist/knob-contracts/tool-approval-knobs.d.ts +4 -0
- package/dist/knob-contracts/tool-approval-knobs.js +32 -0
- package/dist/lib/infinite-canvas-camera-store.d.ts +65 -0
- package/dist/lib/infinite-canvas-camera-store.js +233 -0
- package/dist/lib/infinite-canvas-camera.d.ts +33 -0
- package/dist/lib/infinite-canvas-camera.js +98 -0
- package/dist/lib/infinite-canvas-navigation.d.ts +19 -0
- package/dist/lib/infinite-canvas-navigation.js +395 -0
- package/dist/markdown-editor/bubble-menu.d.ts +6 -0
- package/dist/markdown-editor/bubble-menu.js +45 -0
- package/dist/markdown-editor/toolbar.d.ts +17 -1
- package/dist/markdown-editor/toolbar.js +103 -81
- package/dist/styles/index.css +10 -8
- package/dist/styles/recipes/activity.css +8 -0
- package/dist/styles/recipes/button-group.css +12 -6
- package/dist/styles/recipes/button.css +12 -2
- package/dist/styles/recipes/chat-message-edit.css +6 -21
- package/dist/styles/recipes/infinite-canvas.css +17 -57
- package/dist/styles/recipes/markdown-editor.css +12 -0
- package/dist/styles/recipes/swap.css +143 -0
- package/dist/styles/recipes/timeline.css +11 -0
- package/dist/styles/recipes/tool-approval.css +267 -0
- package/dist/styles/recipes/track-highlight.css +19 -6
- package/dist/styles/theme.css +6 -5
- package/dist/styles/type-scale.css +1 -1
- package/dist/tool-approval.d.ts +49 -0
- package/dist/tool-approval.js +260 -0
- package/dist/ui/code.js +13 -3
- package/dist/ui/command.js +1 -0
- package/dist/ui/infinite-canvas.d.ts +19 -22
- package/dist/ui/infinite-canvas.js +264 -325
- package/dist/ui/rich-tooltip.d.ts +2 -1
- package/dist/ui/rich-tooltip.js +32 -29
- package/dist/ui/swap.d.ts +14 -0
- package/dist/ui/swap.js +69 -0
- package/dist/ui/timeline.d.ts +1 -1
- package/dist/ui/timeline.js +1 -1
- package/dist/user-ask.js +1 -1
- package/lint/no-raw-type-classes.grit +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,10 +47,10 @@ const twMerge = extendTailwindMerge({ extend: { classGroups: { "font-size": [{ t
|
|
|
47
47
|
|
|
48
48
|
Controls size their own text: pick the control's `size`, or set its `--cui-*-font-size` knob in your theme, rather than wrapping the label in a `text-*` span.
|
|
49
49
|
|
|
50
|
-
With Biome, the shipped GritQL plugin
|
|
50
|
+
With Biome, the shipped GritQL plugin errors on text sizes in `className`: the type rungs, Tailwind's `text-xs`…`text-9xl`, and arbitrary `text-[13px]`. Adopt it folder by folder through `overrides` while you migrate:
|
|
51
51
|
|
|
52
52
|
```json
|
|
53
|
-
{ "plugins": ["./node_modules/@ctrl-ui/react/lint/no-raw-type-classes.grit"] }
|
|
53
|
+
{ "overrides": [{ "includes": ["src/features/**"], "plugins": ["./node_modules/@ctrl-ui/react/lint/no-raw-type-classes.grit"] }] }
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
## Customize
|
package/dist/action-bar.js
CHANGED
|
@@ -3,6 +3,7 @@ import { useCopyToClipboard } from "./hooks/use-copy-to-clipboard.js";
|
|
|
3
3
|
import { cn } from "./lib/cn.js";
|
|
4
4
|
import { Button } from "./ui/button.js";
|
|
5
5
|
import { LiveStatus } from "./ui/live-status.js";
|
|
6
|
+
import { Swap, SwapItem } from "./ui/swap.js";
|
|
6
7
|
import { Toolbar } from "@base-ui/react/toolbar";
|
|
7
8
|
import { createContext, useContext } from "react";
|
|
8
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -66,21 +67,28 @@ function ActionBarCopy({ value, children = "Copy", copiedChildren = "Copied", co
|
|
|
66
67
|
onCopyError?.(error);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
70
|
+
const copied = status === "copied";
|
|
69
71
|
let copyStatus = "";
|
|
70
|
-
if (
|
|
72
|
+
if (copied) copyStatus = copiedAriaLabel;
|
|
71
73
|
else if (status === "failed") copyStatus = copyFailedLabel;
|
|
72
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */
|
|
74
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(ActionBarItem, {
|
|
73
75
|
disabled: disabled ?? !copyValue,
|
|
74
76
|
onClick: handleClick,
|
|
75
77
|
...props,
|
|
76
|
-
children:
|
|
77
|
-
"
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
children: [/* @__PURE__ */ jsxs(Swap, {
|
|
79
|
+
value: copied ? "copied" : "idle",
|
|
80
|
+
children: [/* @__PURE__ */ jsx(SwapItem, {
|
|
81
|
+
value: "idle",
|
|
82
|
+
children
|
|
83
|
+
}), /* @__PURE__ */ jsx(SwapItem, {
|
|
84
|
+
value: "copied",
|
|
85
|
+
"aria-hidden": "true",
|
|
86
|
+
children: copiedChildren
|
|
87
|
+
})]
|
|
88
|
+
}), copied ? /* @__PURE__ */ jsx("span", {
|
|
81
89
|
className: "sr-only",
|
|
82
90
|
children
|
|
83
|
-
})
|
|
91
|
+
}) : null]
|
|
84
92
|
}), /* @__PURE__ */ jsx(LiveStatus, { message: copyStatus })] });
|
|
85
93
|
}
|
|
86
94
|
function ActionBarEdit({ value, children = "Edit", disabled, onClick, ...props }) {
|
package/dist/activity.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ScrollAreaProps } from "./ui/scroll-area.js";
|
|
|
4
4
|
import { CSSProperties, ComponentProps, ReactNode } from "react";
|
|
5
5
|
import { ChevronRight } from "lucide-react";
|
|
6
6
|
//#region src/activity.d.ts
|
|
7
|
-
export type ActivityState = "pending" | "running" | "success" | "error";
|
|
7
|
+
export type ActivityState = "pending" | "running" | "waiting" | "success" | "error";
|
|
8
8
|
export type ActivityKind = "default" | "tool" | "reasoning" | "signal";
|
|
9
9
|
export type ActivityDetailFormat = "text" | "code";
|
|
10
10
|
export type ActivityProps = Omit<CollapsibleProps, "children" | "style"> & {
|
package/dist/activity.js
CHANGED
|
@@ -5,17 +5,19 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collap
|
|
|
5
5
|
import { ScrollArea } from "./ui/scroll-area.js";
|
|
6
6
|
import { createContext, useContext } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { Check, ChevronRight, CircleAlert, CircleDashed, LoaderCircle } from "lucide-react";
|
|
8
|
+
import { Check, ChevronRight, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
|
|
9
9
|
//#region src/activity.tsx
|
|
10
10
|
const activityStatusLabels = {
|
|
11
11
|
pending: "Pending",
|
|
12
12
|
running: "Running",
|
|
13
|
+
waiting: "Waiting",
|
|
13
14
|
success: "Complete",
|
|
14
15
|
error: "Failed"
|
|
15
16
|
};
|
|
16
17
|
const activityStatusIcons = {
|
|
17
18
|
pending: CircleDashed,
|
|
18
19
|
running: LoaderCircle,
|
|
20
|
+
waiting: CirclePause,
|
|
19
21
|
success: Check,
|
|
20
22
|
error: CircleAlert
|
|
21
23
|
};
|
package/dist/audio-visualizer.js
CHANGED
|
@@ -61,7 +61,7 @@ function AudioVisualizer({ levels, points, active = true, className, style, ...p
|
|
|
61
61
|
const visibleLevel = MIN_VISIBLE_LEVEL + perceptualLevel * .96;
|
|
62
62
|
const levelStyle = {
|
|
63
63
|
"--_audio-visualizer-level-opacity": `${.48 + perceptualLevel * .52}`,
|
|
64
|
-
clipPath: `inset(${(1 - visibleLevel) * 50}% 0 round var(--cui-audio-visualizer-bar-radius))`
|
|
64
|
+
clipPath: `inset(${((1 - visibleLevel) * 50).toFixed(3)}% 0 round var(--cui-audio-visualizer-bar-radius))`
|
|
65
65
|
};
|
|
66
66
|
return /* @__PURE__ */ jsx("span", {
|
|
67
67
|
ref: key === "bar-0" ? firstBarRef : void 0,
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
//#region src/blocks/agent-run-clock.ts
|
|
3
|
+
const TICK_MS = 1e3;
|
|
4
|
+
let now = null;
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
let interval;
|
|
7
|
+
function tick() {
|
|
8
|
+
if (document.hidden) return;
|
|
9
|
+
now = Date.now();
|
|
10
|
+
for (const listener of listeners) listener();
|
|
11
|
+
}
|
|
12
|
+
function onVisibilityChange() {
|
|
13
|
+
if (!document.hidden) tick();
|
|
14
|
+
}
|
|
15
|
+
function subscribeToRunClock(listener) {
|
|
16
|
+
listeners.add(listener);
|
|
17
|
+
if (listeners.size === 1) {
|
|
18
|
+
now = Date.now();
|
|
19
|
+
interval = setInterval(tick, TICK_MS);
|
|
20
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
21
|
+
}
|
|
22
|
+
return () => {
|
|
23
|
+
listeners.delete(listener);
|
|
24
|
+
if (listeners.size > 0) return;
|
|
25
|
+
clearInterval(interval);
|
|
26
|
+
interval = void 0;
|
|
27
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const subscribeToNothing = () => () => {};
|
|
31
|
+
function useRunClock(active) {
|
|
32
|
+
return useSyncExternalStore(active ? subscribeToRunClock : subscribeToNothing, () => now, () => null);
|
|
33
|
+
}
|
|
34
|
+
function splitElapsed(ms) {
|
|
35
|
+
const totalSeconds = Math.floor(Math.max(0, ms) / 1e3);
|
|
36
|
+
return {
|
|
37
|
+
hours: Math.floor(totalSeconds / 3600),
|
|
38
|
+
minutes: Math.floor(totalSeconds % 3600 / 60),
|
|
39
|
+
seconds: totalSeconds % 60
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const pad2 = (value) => String(value).padStart(2, "0");
|
|
43
|
+
function formatElapsed(ms) {
|
|
44
|
+
const { hours, minutes, seconds } = splitElapsed(ms);
|
|
45
|
+
return hours > 0 ? `${hours}:${pad2(minutes)}:${pad2(seconds)}` : `${minutes}:${pad2(seconds)}`;
|
|
46
|
+
}
|
|
47
|
+
function elapsedIsoDuration(ms) {
|
|
48
|
+
const { hours, minutes, seconds } = splitElapsed(ms);
|
|
49
|
+
return `PT${hours ? `${hours}H` : ""}${minutes ? `${minutes}M` : ""}${seconds}S`;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { elapsedIsoDuration, formatElapsed, useRunClock };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AgentRunSummary } from "./agent-run-status.js";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
//#region src/blocks/agent-run-sidebar.d.ts
|
|
4
|
+
export declare function AgentRunSidebar({ appName, brand, runs, activeRunId, sidebarFooter, onRunSelect, onNewRun }: {
|
|
5
|
+
appName: string;
|
|
6
|
+
brand?: ReactNode;
|
|
7
|
+
runs: readonly AgentRunSummary[];
|
|
8
|
+
activeRunId?: string;
|
|
9
|
+
sidebarFooter?: ReactNode;
|
|
10
|
+
onRunSelect?: (run: AgentRunSummary) => void;
|
|
11
|
+
onNewRun?: () => void;
|
|
12
|
+
}): import("react").JSX.Element;
|
|
13
|
+
//#endregion
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Text } from "../ui/typography.js";
|
|
3
|
+
import { useSidebar } from "../ui/sidebar-provider.js";
|
|
4
|
+
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
5
|
+
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarRail } from "../ui/sidebar.js";
|
|
6
|
+
import { agentRunStatusLabels } from "./agent-run-status.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { BotIcon, Check, CircleAlert, CircleDashed, CirclePause, CircleSlash, LoaderCircle, PlusIcon } from "lucide-react";
|
|
9
|
+
//#region src/blocks/agent-run-sidebar.tsx
|
|
10
|
+
const runStatusIcons = {
|
|
11
|
+
running: /* @__PURE__ */ jsx(LoaderCircle, {
|
|
12
|
+
className: "size-3.5 shrink-0 motion-safe:animate-spin",
|
|
13
|
+
"aria-hidden": "true"
|
|
14
|
+
}),
|
|
15
|
+
waiting: /* @__PURE__ */ jsx(CirclePause, {
|
|
16
|
+
className: "size-3.5 shrink-0 text-warning-text",
|
|
17
|
+
"aria-hidden": "true"
|
|
18
|
+
}),
|
|
19
|
+
success: /* @__PURE__ */ jsx(Check, {
|
|
20
|
+
className: "size-3.5 shrink-0 text-success-text",
|
|
21
|
+
"aria-hidden": "true"
|
|
22
|
+
}),
|
|
23
|
+
error: /* @__PURE__ */ jsx(CircleAlert, {
|
|
24
|
+
className: "size-3.5 shrink-0 text-destructive-text",
|
|
25
|
+
"aria-hidden": "true"
|
|
26
|
+
}),
|
|
27
|
+
cancelled: /* @__PURE__ */ jsx(CircleSlash, {
|
|
28
|
+
className: "size-3.5 shrink-0 text-muted-foreground",
|
|
29
|
+
"aria-hidden": "true"
|
|
30
|
+
}),
|
|
31
|
+
pending: /* @__PURE__ */ jsx(CircleDashed, {
|
|
32
|
+
className: "size-3.5 shrink-0 text-muted-foreground",
|
|
33
|
+
"aria-hidden": "true"
|
|
34
|
+
})
|
|
35
|
+
};
|
|
36
|
+
function AgentRunSidebar({ appName, brand, runs, activeRunId, sidebarFooter, onRunSelect, onNewRun }) {
|
|
37
|
+
const { setOpenMobile } = useSidebar();
|
|
38
|
+
return /* @__PURE__ */ jsxs(Sidebar, {
|
|
39
|
+
collapsible: "offcanvas",
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsxs(SidebarHeader, {
|
|
42
|
+
className: "gap-1.5 border-b border-sidebar-border px-2 pb-2 pt-3",
|
|
43
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
44
|
+
className: "flex min-w-0 items-center gap-2 px-1 py-1",
|
|
45
|
+
children: [brand ?? /* @__PURE__ */ jsx("span", {
|
|
46
|
+
className: "flex size-6 shrink-0 items-center justify-center rounded-md bg-foreground text-background",
|
|
47
|
+
children: /* @__PURE__ */ jsx(BotIcon, {
|
|
48
|
+
className: "size-3.5",
|
|
49
|
+
"aria-hidden": "true"
|
|
50
|
+
})
|
|
51
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
52
|
+
size: "label",
|
|
53
|
+
weight: "semibold",
|
|
54
|
+
className: "truncate",
|
|
55
|
+
title: appName,
|
|
56
|
+
children: appName
|
|
57
|
+
})]
|
|
58
|
+
}), onNewRun ? /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
|
|
59
|
+
size: "sm",
|
|
60
|
+
onClick: () => {
|
|
61
|
+
onNewRun();
|
|
62
|
+
setOpenMobile(false);
|
|
63
|
+
},
|
|
64
|
+
children: [/* @__PURE__ */ jsx(PlusIcon, {}), /* @__PURE__ */ jsx("span", { children: "New run" })]
|
|
65
|
+
}) }) }) : null]
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ jsx(SidebarContent, { children: /* @__PURE__ */ jsxs(SidebarGroup, {
|
|
68
|
+
className: "gap-1 pt-1",
|
|
69
|
+
children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: "Runs" }), runs.length === 0 ? /* @__PURE__ */ jsx(Text, {
|
|
70
|
+
size: "caption",
|
|
71
|
+
tone: "muted",
|
|
72
|
+
className: "px-2",
|
|
73
|
+
children: "No runs yet"
|
|
74
|
+
}) : /* @__PURE__ */ jsx(SidebarMenu, { children: runs.map((run) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
|
|
75
|
+
size: "sm",
|
|
76
|
+
isActive: run.id === activeRunId,
|
|
77
|
+
onClick: () => {
|
|
78
|
+
onRunSelect?.(run);
|
|
79
|
+
setOpenMobile(false);
|
|
80
|
+
},
|
|
81
|
+
children: [
|
|
82
|
+
runStatusIcons[run.status],
|
|
83
|
+
/* @__PURE__ */ jsx("span", {
|
|
84
|
+
className: "truncate",
|
|
85
|
+
children: run.title
|
|
86
|
+
}),
|
|
87
|
+
/* @__PURE__ */ jsxs("span", {
|
|
88
|
+
className: "sr-only",
|
|
89
|
+
children: [", ", agentRunStatusLabels[run.status]]
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
}) }, run.id)) })]
|
|
93
|
+
}) }),
|
|
94
|
+
sidebarFooter ? /* @__PURE__ */ jsx(SidebarFooter, { children: sidebarFooter }) : null,
|
|
95
|
+
/* @__PURE__ */ jsx(SidebarRail, {})
|
|
96
|
+
]
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { AgentRunSidebar };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/blocks/agent-run-status.d.ts
|
|
2
|
+
export type AgentRunStatus = "pending" | "running" | "waiting" | "success" | "error" | "cancelled";
|
|
3
|
+
export type AgentRunSummary = {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: AgentRunStatus;
|
|
7
|
+
};
|
|
8
|
+
export declare const agentRunStatusLabels: {
|
|
9
|
+
pending: string;
|
|
10
|
+
running: string;
|
|
11
|
+
waiting: string;
|
|
12
|
+
success: string;
|
|
13
|
+
error: string;
|
|
14
|
+
cancelled: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const agentRunStatusColors: {
|
|
17
|
+
pending: "neutral";
|
|
18
|
+
running: "blue";
|
|
19
|
+
waiting: "yellow";
|
|
20
|
+
success: "green";
|
|
21
|
+
error: "red";
|
|
22
|
+
cancelled: "neutral";
|
|
23
|
+
};
|
|
24
|
+
export declare const agentRunStepLabels: {
|
|
25
|
+
neutral: string;
|
|
26
|
+
pending: string;
|
|
27
|
+
running: string;
|
|
28
|
+
waiting: string;
|
|
29
|
+
success: string;
|
|
30
|
+
error: string;
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/blocks/agent-run-status.ts
|
|
2
|
+
const agentRunStatusLabels = {
|
|
3
|
+
pending: "Queued",
|
|
4
|
+
running: "Running",
|
|
5
|
+
waiting: "Needs approval",
|
|
6
|
+
success: "Done",
|
|
7
|
+
error: "Failed",
|
|
8
|
+
cancelled: "Cancelled"
|
|
9
|
+
};
|
|
10
|
+
const agentRunStatusColors = {
|
|
11
|
+
pending: "neutral",
|
|
12
|
+
running: "blue",
|
|
13
|
+
waiting: "yellow",
|
|
14
|
+
success: "green",
|
|
15
|
+
error: "red",
|
|
16
|
+
cancelled: "neutral"
|
|
17
|
+
};
|
|
18
|
+
const agentRunStepLabels = {
|
|
19
|
+
neutral: "Step",
|
|
20
|
+
pending: "Pending",
|
|
21
|
+
running: "Running",
|
|
22
|
+
waiting: "Waiting for approval",
|
|
23
|
+
success: "Done",
|
|
24
|
+
error: "Failed"
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { agentRunStatusColors, agentRunStatusLabels, agentRunStepLabels };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ActivityProps } from "../activity.js";
|
|
2
|
+
import { AgentRunStatus, AgentRunSummary } from "./agent-run-status.js";
|
|
3
|
+
import { Card } from "../ui/card.js";
|
|
4
|
+
import { SidebarProviderProps } from "../ui/sidebar-provider.js";
|
|
5
|
+
import "../ui/sidebar.js";
|
|
6
|
+
import { TimelineItemProps } from "../ui/timeline.js";
|
|
7
|
+
import { ComponentProps, ReactNode } from "react";
|
|
8
|
+
//#region src/blocks/agent-run.d.ts
|
|
9
|
+
type AgentRunLayout = "viewport" | "contained";
|
|
10
|
+
export type AgentRunBlockProps = Omit<ComponentProps<"div">, "children"> & Pick<SidebarProviderProps, "persistOpen" | "keyboardShortcut"> & {
|
|
11
|
+
appName?: string;
|
|
12
|
+
brand?: ReactNode;
|
|
13
|
+
runs: readonly AgentRunSummary[];
|
|
14
|
+
activeRunId?: string;
|
|
15
|
+
onRunSelect?: (run: AgentRunSummary) => void;
|
|
16
|
+
onNewRun?: () => void;
|
|
17
|
+
sidebarFooter?: ReactNode;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
layout?: AgentRunLayout;
|
|
20
|
+
};
|
|
21
|
+
export declare function AgentRunBlock({ appName, brand, runs, activeRunId, onRunSelect, onNewRun, sidebarFooter, children, layout, className, style, ...props }: AgentRunBlockProps): import("react").JSX.Element;
|
|
22
|
+
export type AgentRunElapsedProps = Omit<ComponentProps<"time">, "dateTime" | "children"> & {
|
|
23
|
+
startedAt: number;
|
|
24
|
+
endedAt?: number;
|
|
25
|
+
};
|
|
26
|
+
export declare function AgentRunElapsed({ startedAt, endedAt, className, ...props }: AgentRunElapsedProps): import("react").JSX.Element;
|
|
27
|
+
export type AgentRunHeaderProps = Omit<ComponentProps<"header">, "title"> & {
|
|
28
|
+
title: string;
|
|
29
|
+
status: AgentRunStatus;
|
|
30
|
+
startedAt?: number;
|
|
31
|
+
endedAt?: number;
|
|
32
|
+
actions?: ReactNode;
|
|
33
|
+
};
|
|
34
|
+
export declare function AgentRunHeader({ title, status, startedAt, endedAt, actions, className, ...props }: AgentRunHeaderProps): import("react").JSX.Element;
|
|
35
|
+
export type AgentRunBodyProps = ComponentProps<"div"> & {
|
|
36
|
+
aside?: ReactNode;
|
|
37
|
+
};
|
|
38
|
+
export declare function AgentRunBody({ aside, className, children, ...props }: AgentRunBodyProps): import("react").JSX.Element;
|
|
39
|
+
export type AgentRunPlanProps = Omit<ComponentProps<"section">, "title"> & {
|
|
40
|
+
title?: ReactNode;
|
|
41
|
+
description?: ReactNode;
|
|
42
|
+
};
|
|
43
|
+
export declare function AgentRunPlan({ title, description, className, children, ...props }: AgentRunPlanProps): import("react").JSX.Element;
|
|
44
|
+
export type AgentRunStepProps = Omit<TimelineItemProps, "title"> & {
|
|
45
|
+
title: ReactNode;
|
|
46
|
+
detail?: ReactNode;
|
|
47
|
+
startedAt?: number;
|
|
48
|
+
endedAt?: number;
|
|
49
|
+
actions?: ReactNode;
|
|
50
|
+
};
|
|
51
|
+
export declare function AgentRunStep({ title, detail, startedAt, endedAt, actions, state, children, ...props }: AgentRunStepProps): import("react").JSX.Element;
|
|
52
|
+
export type AgentRunToolCallProps = Omit<ActivityProps, "kind" | "name" | "children"> & {
|
|
53
|
+
name: string;
|
|
54
|
+
summary?: ReactNode;
|
|
55
|
+
icon?: ReactNode;
|
|
56
|
+
input?: unknown;
|
|
57
|
+
output?: unknown;
|
|
58
|
+
errorText?: string;
|
|
59
|
+
startedAt?: number;
|
|
60
|
+
endedAt?: number;
|
|
61
|
+
};
|
|
62
|
+
export declare function AgentRunToolCall({ name, summary, icon, input, output, errorText, startedAt, endedAt, ...props }: AgentRunToolCallProps): import("react").JSX.Element;
|
|
63
|
+
export type AgentRunAsideProps = ComponentProps<"aside">;
|
|
64
|
+
export declare function AgentRunAside({ className, ...props }: AgentRunAsideProps): import("react").JSX.Element;
|
|
65
|
+
export type AgentRunSectionProps = Omit<ComponentProps<typeof Card>, "title"> & {
|
|
66
|
+
title: ReactNode;
|
|
67
|
+
actions?: ReactNode;
|
|
68
|
+
};
|
|
69
|
+
export declare function AgentRunSection({ title, actions, children, ...props }: AgentRunSectionProps): import("react").JSX.Element;
|
|
70
|
+
export type AgentRunDetail = {
|
|
71
|
+
label: string;
|
|
72
|
+
value: ReactNode;
|
|
73
|
+
};
|
|
74
|
+
export type AgentRunDetailsProps = Omit<AgentRunSectionProps, "title" | "children"> & {
|
|
75
|
+
title?: ReactNode;
|
|
76
|
+
items: readonly AgentRunDetail[];
|
|
77
|
+
};
|
|
78
|
+
export declare function AgentRunDetails({ title, items, ...props }: AgentRunDetailsProps): import("react").JSX.Element | null;
|
|
79
|
+
//#endregion
|
|
80
|
+
export type { AgentRunStatus, AgentRunSummary };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { LiveStatus } from "../ui/live-status.js";
|
|
4
|
+
import { Activity, ActivityContent, ActivityDetail, ActivityDetailContent, ActivityDetailLabel, ActivityIcon, ActivityRow, ActivityStatus, ActivityTitle, ActivityTrigger } from "../activity.js";
|
|
5
|
+
import { Heading, Text } from "../ui/typography.js";
|
|
6
|
+
import { Badge } from "../ui/badge.js";
|
|
7
|
+
import { elapsedIsoDuration, formatElapsed, useRunClock } from "./agent-run-clock.js";
|
|
8
|
+
import { SidebarProvider } from "../ui/sidebar-provider.js";
|
|
9
|
+
import { SidebarInset, SidebarTrigger } from "../ui/sidebar.js";
|
|
10
|
+
import { agentRunStatusColors, agentRunStatusLabels, agentRunStepLabels } from "./agent-run-status.js";
|
|
11
|
+
import { AgentRunSidebar } from "./agent-run-sidebar.js";
|
|
12
|
+
import { Card, CardAction, CardContent, CardHeader } from "../ui/card.js";
|
|
13
|
+
import { Timeline, TimelineContent, TimelineDescription, TimelineIndicator, TimelineItem, TimelineMeta, TimelineSeparator, TimelineTitle } from "../ui/timeline.js";
|
|
14
|
+
import { createContext, useContext, useId } from "react";
|
|
15
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
+
import { Check, Circle, CircleAlert, CircleDashed, CirclePause, LoaderCircle } from "lucide-react";
|
|
17
|
+
//#region src/blocks/agent-run.tsx
|
|
18
|
+
const AgentRunLayoutContext = createContext("viewport");
|
|
19
|
+
function useHeadingLevels() {
|
|
20
|
+
return useContext(AgentRunLayoutContext) === "contained" ? {
|
|
21
|
+
title: 2,
|
|
22
|
+
section: 3
|
|
23
|
+
} : {
|
|
24
|
+
title: 1,
|
|
25
|
+
section: 2
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function AgentRunBlock({ appName = "Agents", brand, runs, activeRunId, onRunSelect, onNewRun, sidebarFooter, children, layout = "viewport", className, style, ...props }) {
|
|
29
|
+
const providerStyle = {
|
|
30
|
+
"--sidebar-width": "16rem",
|
|
31
|
+
...style
|
|
32
|
+
};
|
|
33
|
+
return /* @__PURE__ */ jsxs(SidebarProvider, {
|
|
34
|
+
layout,
|
|
35
|
+
className: cn("bg-background text-foreground", layout === "viewport" && "h-svh overflow-hidden", className),
|
|
36
|
+
style: providerStyle,
|
|
37
|
+
...props,
|
|
38
|
+
children: [/* @__PURE__ */ jsx(AgentRunSidebar, {
|
|
39
|
+
appName,
|
|
40
|
+
brand,
|
|
41
|
+
runs,
|
|
42
|
+
activeRunId,
|
|
43
|
+
sidebarFooter,
|
|
44
|
+
onRunSelect,
|
|
45
|
+
onNewRun
|
|
46
|
+
}), /* @__PURE__ */ jsx(SidebarInset, {
|
|
47
|
+
className: "@container/agent-run flex h-full min-h-0 min-w-0 flex-col overflow-hidden",
|
|
48
|
+
children: /* @__PURE__ */ jsx(AgentRunLayoutContext.Provider, {
|
|
49
|
+
value: layout,
|
|
50
|
+
children
|
|
51
|
+
})
|
|
52
|
+
})]
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function AgentRunElapsed({ startedAt, endedAt, className, ...props }) {
|
|
56
|
+
const now = useRunClock(endedAt === void 0);
|
|
57
|
+
const end = endedAt ?? now;
|
|
58
|
+
const ms = end === null ? null : Math.max(0, end - startedAt);
|
|
59
|
+
return /* @__PURE__ */ jsx("time", {
|
|
60
|
+
dateTime: ms === null ? void 0 : elapsedIsoDuration(ms),
|
|
61
|
+
className: cn("text-label tabular-nums text-muted-foreground", className),
|
|
62
|
+
...props,
|
|
63
|
+
children: ms === null ? "" : formatElapsed(ms)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function AgentRunHeader({ title, status, startedAt, endedAt, actions, className, ...props }) {
|
|
67
|
+
const levels = useHeadingLevels();
|
|
68
|
+
return /* @__PURE__ */ jsxs("header", {
|
|
69
|
+
className: cn("flex h-12 shrink-0 items-center gap-2 border-b border-border/70 px-3", className),
|
|
70
|
+
...props,
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsx(SidebarTrigger, {
|
|
73
|
+
size: "xs",
|
|
74
|
+
className: "lg:hidden"
|
|
75
|
+
}),
|
|
76
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
77
|
+
level: levels.title,
|
|
78
|
+
size: "label",
|
|
79
|
+
weight: "medium",
|
|
80
|
+
className: "min-w-0 truncate",
|
|
81
|
+
title,
|
|
82
|
+
children: title
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ jsx(Badge, {
|
|
85
|
+
size: "sm",
|
|
86
|
+
color: agentRunStatusColors[status],
|
|
87
|
+
children: agentRunStatusLabels[status]
|
|
88
|
+
}),
|
|
89
|
+
startedAt === void 0 ? null : /* @__PURE__ */ jsx(AgentRunElapsed, {
|
|
90
|
+
startedAt,
|
|
91
|
+
endedAt,
|
|
92
|
+
className: "text-body"
|
|
93
|
+
}),
|
|
94
|
+
/* @__PURE__ */ jsx("div", {
|
|
95
|
+
className: "ms-auto flex shrink-0 items-center gap-1",
|
|
96
|
+
children: actions
|
|
97
|
+
}),
|
|
98
|
+
/* @__PURE__ */ jsx(LiveStatus, { message: `${title}: ${agentRunStatusLabels[status]}` })
|
|
99
|
+
]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
function AgentRunBody({ aside, className, children, ...props }) {
|
|
103
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
104
|
+
className: cn("grid min-h-0 flex-1 content-start overflow-y-auto @3xl/agent-run:grid-cols-[minmax(0,1fr)_minmax(18rem,22rem)] @3xl/agent-run:content-stretch @3xl/agent-run:overflow-hidden", className),
|
|
105
|
+
...props,
|
|
106
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
107
|
+
className: "min-w-0 px-4 py-5 @lg/agent-run:px-6 @3xl/agent-run:overflow-y-auto",
|
|
108
|
+
children
|
|
109
|
+
}), aside]
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function AgentRunPlan({ title = "Plan", description, className, children, ...props }) {
|
|
113
|
+
const levels = useHeadingLevels();
|
|
114
|
+
const headingId = useId();
|
|
115
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
116
|
+
"aria-labelledby": headingId,
|
|
117
|
+
className: cn("min-w-0", className),
|
|
118
|
+
...props,
|
|
119
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsx(Heading, {
|
|
121
|
+
id: headingId,
|
|
122
|
+
level: levels.section,
|
|
123
|
+
size: "label",
|
|
124
|
+
weight: "medium",
|
|
125
|
+
children: title
|
|
126
|
+
}),
|
|
127
|
+
description ? /* @__PURE__ */ jsx(Text, {
|
|
128
|
+
size: "caption",
|
|
129
|
+
tone: "muted",
|
|
130
|
+
children: description
|
|
131
|
+
}) : null,
|
|
132
|
+
/* @__PURE__ */ jsx(Timeline, {
|
|
133
|
+
className: "mt-3",
|
|
134
|
+
children
|
|
135
|
+
})
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const stepIcons = {
|
|
140
|
+
neutral: /* @__PURE__ */ jsx(Circle, { "aria-hidden": "true" }),
|
|
141
|
+
pending: /* @__PURE__ */ jsx(CircleDashed, { "aria-hidden": "true" }),
|
|
142
|
+
running: /* @__PURE__ */ jsx(LoaderCircle, {
|
|
143
|
+
className: "motion-safe:animate-spin",
|
|
144
|
+
"aria-hidden": "true"
|
|
145
|
+
}),
|
|
146
|
+
waiting: /* @__PURE__ */ jsx(CirclePause, { "aria-hidden": "true" }),
|
|
147
|
+
success: /* @__PURE__ */ jsx(Check, { "aria-hidden": "true" }),
|
|
148
|
+
error: /* @__PURE__ */ jsx(CircleAlert, { "aria-hidden": "true" })
|
|
149
|
+
};
|
|
150
|
+
function AgentRunStep({ title, detail, startedAt, endedAt, actions, state = "pending", children, ...props }) {
|
|
151
|
+
const hasMeta = startedAt !== void 0 || actions !== void 0;
|
|
152
|
+
return /* @__PURE__ */ jsxs(TimelineItem, {
|
|
153
|
+
state,
|
|
154
|
+
...props,
|
|
155
|
+
children: [
|
|
156
|
+
/* @__PURE__ */ jsx(TimelineIndicator, {
|
|
157
|
+
"aria-label": agentRunStepLabels[state],
|
|
158
|
+
children: stepIcons[state]
|
|
159
|
+
}),
|
|
160
|
+
/* @__PURE__ */ jsx(TimelineSeparator, {}),
|
|
161
|
+
/* @__PURE__ */ jsxs(TimelineContent, { children: [
|
|
162
|
+
/* @__PURE__ */ jsx(TimelineTitle, { children: title }),
|
|
163
|
+
detail ? /* @__PURE__ */ jsx(TimelineDescription, { children: detail }) : null,
|
|
164
|
+
hasMeta ? /* @__PURE__ */ jsxs(TimelineMeta, { children: [startedAt === void 0 ? null : /* @__PURE__ */ jsx(AgentRunElapsed, {
|
|
165
|
+
startedAt,
|
|
166
|
+
endedAt
|
|
167
|
+
}), actions] }) : null,
|
|
168
|
+
children ? /* @__PURE__ */ jsx("div", {
|
|
169
|
+
className: "mt-2 grid gap-2",
|
|
170
|
+
children
|
|
171
|
+
}) : null
|
|
172
|
+
] })
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
function formatToolValue(value) {
|
|
177
|
+
return typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
178
|
+
}
|
|
179
|
+
function AgentRunToolCall({ name, summary, icon, input, output, errorText, startedAt, endedAt, ...props }) {
|
|
180
|
+
const hasDetails = input !== void 0 || output !== void 0 || errorText !== void 0;
|
|
181
|
+
const Row = hasDetails ? ActivityTrigger : ActivityRow;
|
|
182
|
+
return /* @__PURE__ */ jsxs(Activity, {
|
|
183
|
+
kind: "tool",
|
|
184
|
+
name,
|
|
185
|
+
...props,
|
|
186
|
+
children: [/* @__PURE__ */ jsxs(Row, { children: [
|
|
187
|
+
icon ? /* @__PURE__ */ jsx(ActivityIcon, { children: icon }) : /* @__PURE__ */ jsx(ActivityIcon, {}),
|
|
188
|
+
/* @__PURE__ */ jsxs(ActivityTitle, { children: [name, summary ? /* @__PURE__ */ jsxs("span", {
|
|
189
|
+
className: "text-muted-foreground",
|
|
190
|
+
children: [" · ", summary]
|
|
191
|
+
}) : null] }),
|
|
192
|
+
startedAt === void 0 ? null : /* @__PURE__ */ jsx(AgentRunElapsed, {
|
|
193
|
+
startedAt,
|
|
194
|
+
endedAt,
|
|
195
|
+
className: "ms-2"
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ jsx(ActivityStatus, { className: "sr-only" })
|
|
198
|
+
] }), hasDetails ? /* @__PURE__ */ jsxs(ActivityContent, { children: [
|
|
199
|
+
input === void 0 ? null : /* @__PURE__ */ jsxs(ActivityDetail, { children: [/* @__PURE__ */ jsx(ActivityDetailLabel, { children: "Input" }), /* @__PURE__ */ jsx(ActivityDetailContent, {
|
|
200
|
+
format: "code",
|
|
201
|
+
children: formatToolValue(input)
|
|
202
|
+
})] }),
|
|
203
|
+
output === void 0 ? null : /* @__PURE__ */ jsxs(ActivityDetail, { children: [/* @__PURE__ */ jsx(ActivityDetailLabel, { children: "Output" }), /* @__PURE__ */ jsx(ActivityDetailContent, {
|
|
204
|
+
format: "code",
|
|
205
|
+
children: formatToolValue(output)
|
|
206
|
+
})] }),
|
|
207
|
+
errorText === void 0 ? null : /* @__PURE__ */ jsxs(ActivityDetail, { children: [/* @__PURE__ */ jsx(ActivityDetailLabel, { children: "Error" }), /* @__PURE__ */ jsx(ActivityDetailContent, {
|
|
208
|
+
className: "text-destructive-text",
|
|
209
|
+
children: errorText
|
|
210
|
+
})] })
|
|
211
|
+
] }) : null]
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function AgentRunAside({ className, ...props }) {
|
|
215
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
216
|
+
"aria-label": "Run output",
|
|
217
|
+
className: cn("grid content-start gap-4 border-t border-border/70 px-4 py-5 @lg/agent-run:px-6 @3xl/agent-run:overflow-y-auto @3xl/agent-run:border-t-0 @3xl/agent-run:border-s", className),
|
|
218
|
+
...props
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
function AgentRunSection({ title, actions, children, ...props }) {
|
|
222
|
+
const levels = useHeadingLevels();
|
|
223
|
+
return /* @__PURE__ */ jsxs(Card, {
|
|
224
|
+
...props,
|
|
225
|
+
children: [/* @__PURE__ */ jsxs(CardHeader, { children: [/* @__PURE__ */ jsx(Heading, {
|
|
226
|
+
level: levels.section,
|
|
227
|
+
size: "label",
|
|
228
|
+
weight: "medium",
|
|
229
|
+
children: title
|
|
230
|
+
}), actions ? /* @__PURE__ */ jsx(CardAction, { children: actions }) : null] }), /* @__PURE__ */ jsx(CardContent, { children })]
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function AgentRunDetails({ title = "Details", items, ...props }) {
|
|
234
|
+
if (items.length === 0) return null;
|
|
235
|
+
return /* @__PURE__ */ jsx(AgentRunSection, {
|
|
236
|
+
title,
|
|
237
|
+
...props,
|
|
238
|
+
children: /* @__PURE__ */ jsx("dl", {
|
|
239
|
+
className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 gap-y-2 text-body",
|
|
240
|
+
children: items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
241
|
+
className: "contents",
|
|
242
|
+
children: [/* @__PURE__ */ jsx("dt", {
|
|
243
|
+
className: "text-muted-foreground",
|
|
244
|
+
children: item.label
|
|
245
|
+
}), /* @__PURE__ */ jsx("dd", {
|
|
246
|
+
className: "min-w-0 break-words",
|
|
247
|
+
children: item.value
|
|
248
|
+
})]
|
|
249
|
+
}, item.label))
|
|
250
|
+
})
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
//#endregion
|
|
254
|
+
export { AgentRunAside, AgentRunBlock, AgentRunBody, AgentRunDetails, AgentRunElapsed, AgentRunHeader, AgentRunPlan, AgentRunSection, AgentRunStep, AgentRunToolCall };
|