@corbits/react-ui 0.1.0 → 0.2.0
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/LICENSE +174 -499
- package/README.md +228 -85
- package/dist/blocks/login/auth-layout.d.ts +1 -1
- package/dist/blocks/login/auth-layout.js +3 -33
- package/dist/blocks/login/login-form.js +6 -119
- package/dist/hooks/use-command-palette-navigation.js +18 -17
- package/dist/hooks/use-controllable-state.d.ts +2 -2
- package/dist/hooks/use-controllable-state.js +23 -15
- package/dist/hooks/use-delayed-autofocus.js +10 -11
- package/dist/hooks/use-dismissable-popover.d.ts +2 -2
- package/dist/hooks/use-dismissable-popover.js +21 -29
- package/dist/hooks/use-list-selection.js +54 -85
- package/dist/hooks/use-prefers-reduced-motion.js +8 -4
- package/dist/hooks/use-scroll-current-into-view.js +5 -7
- package/dist/index.d.ts +0 -11
- package/dist/index.js +10 -19
- package/dist/lib/artifact.js +16 -35
- package/dist/lib/chart-geometry.js +33 -20
- package/dist/lib/chart-palette.js +17 -31
- package/dist/lib/chat-message.js +32 -13
- package/dist/lib/chat-parts.js +2 -1
- package/dist/lib/csv.js +42 -26
- package/dist/lib/metrics.js +30 -48
- package/dist/lib/now-item.js +26 -25
- package/dist/lib/relative-time.js +14 -29
- package/dist/lib/theme.js +32 -30
- package/dist/lib/url.js +9 -8
- package/dist/lib/workflow-display-flow.js +37 -33
- package/dist/lib/workflow-registry.d.ts +0 -41
- package/dist/lib/workflow-registry.js +13 -23
- package/dist/lib/workflow-run-error.js +16 -20
- package/dist/lib/workflow-run-progress.js +94 -52
- package/dist/lib/workflow-run.js +17 -13
- package/dist/styles.css +11 -11
- package/dist/test/render-hook.js +11 -12
- package/dist/theme.css +51 -14
- package/dist/ui/agent-turn.d.ts +1 -1
- package/dist/ui/agent-turn.js +4 -37
- package/dist/ui/animated-number.js +15 -28
- package/dist/ui/approval-card.js +5 -90
- package/dist/ui/artifact-body.js +47 -125
- package/dist/ui/artifact-notice.d.ts +1 -1
- package/dist/ui/artifact-notice.js +9 -16
- package/dist/ui/avatar.d.ts +1 -1
- package/dist/ui/avatar.js +11 -48
- package/dist/ui/badge.js +4 -12
- package/dist/ui/bar-chart.d.ts +1 -1
- package/dist/ui/bar-chart.js +22 -74
- package/dist/ui/block-card.js +7 -45
- package/dist/ui/boot-screen.d.ts +1 -1
- package/dist/ui/boot-screen.js +4 -33
- package/dist/ui/bulk-action-bar.d.ts +1 -1
- package/dist/ui/bulk-action-bar.js +14 -33
- package/dist/ui/button.js +10 -24
- package/dist/ui/card.js +5 -25
- package/dist/ui/category-bars.js +14 -59
- package/dist/ui/chart-frame.d.ts +2 -2
- package/dist/ui/chart-frame.js +6 -85
- package/dist/ui/chat-composer.js +4 -16
- package/dist/ui/chat-dock-timing.js +7 -3
- package/dist/ui/chat-input.js +20 -100
- package/dist/ui/chat-panel.d.ts +1 -1
- package/dist/ui/chat-panel.js +7 -41
- package/dist/ui/chat-thread.js +13 -31
- package/dist/ui/checkbox.js +10 -52
- package/dist/ui/command-palette.js +71 -246
- package/dist/ui/compare-body.d.ts +1 -1
- package/dist/ui/compare-body.js +28 -98
- package/dist/ui/confirm-button.js +8 -15
- package/dist/ui/corbits-mark.js +7 -16
- package/dist/ui/csv-table.d.ts +1 -1
- package/dist/ui/csv-table.js +8 -50
- package/dist/ui/dialog.d.ts +1 -1
- package/dist/ui/dialog.js +32 -62
- package/dist/ui/dictation-status-line.js +7 -25
- package/dist/ui/dither-canvas.d.ts +1 -1
- package/dist/ui/dither-canvas.js +31 -56
- package/dist/ui/embed-body.d.ts +1 -1
- package/dist/ui/embed-body.js +7 -56
- package/dist/ui/empty-state.d.ts +1 -1
- package/dist/ui/empty-state.js +3 -26
- package/dist/ui/file-input.js +17 -37
- package/dist/ui/filter-bar.d.ts +1 -1
- package/dist/ui/filter-bar.js +11 -71
- package/dist/ui/filter-chip.d.ts +1 -1
- package/dist/ui/filter-chip.js +7 -15
- package/dist/ui/gate-block.d.ts +2 -1
- package/dist/ui/gate-block.js +4 -29
- package/dist/ui/horizontal-stepper.d.ts +1 -1
- package/dist/ui/horizontal-stepper.js +18 -45
- package/dist/ui/input.js +1 -6
- package/dist/ui/inspector-shell.d.ts +5 -5
- package/dist/ui/inspector-shell.js +14 -81
- package/dist/ui/intake-form.d.ts +1 -1
- package/dist/ui/intake-form.js +21 -97
- package/dist/ui/kind-card-grid.js +9 -31
- package/dist/ui/library-page-header.js +4 -32
- package/dist/ui/list-detail.js +5 -35
- package/dist/ui/live-run-banner.d.ts +1 -1
- package/dist/ui/live-run-banner.js +5 -15
- package/dist/ui/live-status-line.js +6 -24
- package/dist/ui/menu.js +7 -24
- package/dist/ui/message-bubble.d.ts +3 -3
- package/dist/ui/message-bubble.js +5 -44
- package/dist/ui/mic-button.d.ts +1 -1
- package/dist/ui/mic-button.js +15 -21
- package/dist/ui/mic-permission-dialog.js +5 -41
- package/dist/ui/notifications-bell.js +9 -43
- package/dist/ui/now-cards.d.ts +2 -2
- package/dist/ui/now-cards.js +16 -94
- package/dist/ui/page-panel.js +11 -11
- package/dist/ui/page-shell.js +4 -11
- package/dist/ui/parts-renderer.js +51 -149
- package/dist/ui/profile-card.js +7 -111
- package/dist/ui/progress-checklist.js +11 -49
- package/dist/ui/provider-mark.d.ts +2 -2
- package/dist/ui/provider-mark.js +9 -16
- package/dist/ui/quick-reply-chips.js +6 -14
- package/dist/ui/quote-card.js +12 -32
- package/dist/ui/reasoning-block.d.ts +1 -1
- package/dist/ui/reasoning-block.js +14 -33
- package/dist/ui/research-body.js +32 -213
- package/dist/ui/rich-empty-state.js +6 -48
- package/dist/ui/run-now-button.js +14 -15
- package/dist/ui/section.d.ts +1 -1
- package/dist/ui/section.js +4 -40
- package/dist/ui/select.js +1 -15
- package/dist/ui/selection-checkbox.d.ts +1 -1
- package/dist/ui/selection-checkbox.js +11 -29
- package/dist/ui/settings-panel.js +7 -50
- package/dist/ui/shimmer-text.js +3 -6
- package/dist/ui/sidebar-item-row.d.ts +1 -1
- package/dist/ui/sidebar-item-row.js +9 -39
- package/dist/ui/sidebar-panel.js +15 -40
- package/dist/ui/sidebar.js +15 -76
- package/dist/ui/skeleton.js +3 -7
- package/dist/ui/sortable-table.js +29 -72
- package/dist/ui/sparkline.js +14 -38
- package/dist/ui/stat-grid.js +17 -52
- package/dist/ui/status-dot.d.ts +1 -1
- package/dist/ui/status-dot.js +8 -20
- package/dist/ui/step-list.d.ts +1 -0
- package/dist/ui/step-list.js +11 -50
- package/dist/ui/switch.js +4 -16
- package/dist/ui/table.js +7 -32
- package/dist/ui/tabs.js +39 -54
- package/dist/ui/textarea.js +10 -19
- package/dist/ui/theme-provider.js +54 -78
- package/dist/ui/theme-toggle.js +13 -16
- package/dist/ui/thinking-indicator.js +3 -15
- package/dist/ui/thinking-label.js +16 -35
- package/dist/ui/thinking-mark.d.ts +1 -1
- package/dist/ui/thinking-mark.js +4 -145
- package/dist/ui/time-series-chart.js +43 -174
- package/dist/ui/toast.js +12 -20
- package/dist/ui/token-mosaic.js +5 -43
- package/dist/ui/tool-block.js +18 -70
- package/dist/ui/tool-narrative.d.ts +1 -1
- package/dist/ui/tool-narrative.js +10 -57
- package/dist/ui/tool-picker.js +57 -145
- package/dist/ui/tooltip.d.ts +1 -1
- package/dist/ui/tooltip.js +4 -33
- package/dist/ui/top-bar.js +14 -72
- package/dist/ui/trace-waterfall.d.ts +1 -1
- package/dist/ui/trace-waterfall.js +21 -93
- package/dist/ui/typing-indicator.d.ts +1 -1
- package/dist/ui/typing-indicator.js +4 -18
- package/dist/ui/view-toggle.js +10 -29
- package/dist/ui/voice-waveform.js +3 -11
- package/package.json +94 -535
package/dist/ui/approval-card.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { useState } from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -17,100 +18,14 @@ const LONG_VALUE = 140;
|
|
|
17
18
|
* Every argument the action will run with is shown. A card that hides them
|
|
18
19
|
* behind "details" is asking for approval of something the user cannot see, so
|
|
19
20
|
* long values clamp rather than disappear.
|
|
20
|
-
*/
|
|
21
|
+
*/
|
|
22
|
+
export function ApprovalCard({ request, onApprove, onReject, onAllowAlways, state = "idle", error = null, className, children, }) {
|
|
21
23
|
const busy = state !== "idle";
|
|
22
24
|
const canAllowAlways = onAllowAlways !== undefined && request.actionKey !== undefined;
|
|
23
|
-
return
|
|
24
|
-
"aria-label": `Approval requested: ${request.headline}`,
|
|
25
|
-
className: cn("flex flex-col gap-3 rounded-lg border border-primary-emphasis bg-card p-4", className),
|
|
26
|
-
children: [
|
|
27
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
28
|
-
className: "flex flex-wrap items-center gap-2",
|
|
29
|
-
children: [
|
|
30
|
-
/*#__PURE__*/ _jsx(Badge, {
|
|
31
|
-
tone: "accent",
|
|
32
|
-
children: "Needs your approval"
|
|
33
|
-
}),
|
|
34
|
-
/*#__PURE__*/ _jsxs("span", {
|
|
35
|
-
className: "text-xs text-muted-foreground",
|
|
36
|
-
children: [
|
|
37
|
-
"Requested by ",
|
|
38
|
-
request.requestedBy
|
|
39
|
-
]
|
|
40
|
-
})
|
|
41
|
-
]
|
|
42
|
-
}),
|
|
43
|
-
/*#__PURE__*/ _jsx("p", {
|
|
44
|
-
className: "text-sm font-semibold",
|
|
45
|
-
children: request.headline
|
|
46
|
-
}),
|
|
47
|
-
request.details === undefined || request.details.length === 0 ? null : /*#__PURE__*/ _jsx("dl", {
|
|
48
|
-
className: "flex flex-col gap-1.5 rounded-md bg-muted p-3 text-xs",
|
|
49
|
-
children: request.details.map((detail)=>/*#__PURE__*/ _jsx(ApprovalDetailRow, {
|
|
50
|
-
detail: detail
|
|
51
|
-
}, detail.label))
|
|
52
|
-
}),
|
|
53
|
-
children,
|
|
54
|
-
error === null ? null : /*#__PURE__*/ _jsx("p", {
|
|
55
|
-
role: "alert",
|
|
56
|
-
className: "text-sm text-destructive",
|
|
57
|
-
children: error
|
|
58
|
-
}),
|
|
59
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
60
|
-
className: "flex flex-wrap items-center gap-2",
|
|
61
|
-
children: [
|
|
62
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
63
|
-
size: "sm",
|
|
64
|
-
onClick: onApprove,
|
|
65
|
-
disabled: busy,
|
|
66
|
-
children: state === "approving" ? "Approving…" : "Approve"
|
|
67
|
-
}),
|
|
68
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
69
|
-
variant: "outline",
|
|
70
|
-
size: "sm",
|
|
71
|
-
onClick: onReject,
|
|
72
|
-
disabled: busy,
|
|
73
|
-
children: state === "rejecting" ? "Rejecting…" : "Reject"
|
|
74
|
-
}),
|
|
75
|
-
canAllowAlways ? /*#__PURE__*/ _jsx(Button, {
|
|
76
|
-
variant: "ghost",
|
|
77
|
-
size: "sm",
|
|
78
|
-
onClick: ()=>onAllowAlways(request.actionKey),
|
|
79
|
-
disabled: busy,
|
|
80
|
-
className: "ml-auto",
|
|
81
|
-
children: state === "allowing-always" ? "Saving…" : "Always allow this"
|
|
82
|
-
}) : null
|
|
83
|
-
]
|
|
84
|
-
})
|
|
85
|
-
]
|
|
86
|
-
});
|
|
25
|
+
return (_jsxs("section", { "aria-label": `Approval requested: ${request.headline}`, className: cn("flex flex-col gap-3 rounded-lg border border-primary-emphasis bg-card p-4", className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { tone: "accent", children: "Needs your approval" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Requested by ", request.requestedBy] })] }), _jsx("p", { className: "text-sm font-semibold", children: request.headline }), request.details === undefined || request.details.length === 0 ? null : (_jsx("dl", { className: "flex flex-col gap-1.5 rounded-md bg-muted p-3 text-xs", children: request.details.map((detail) => (_jsx(ApprovalDetailRow, { detail: detail }, detail.label))) })), children, error === null ? null : (_jsx("p", { role: "alert", className: "text-sm text-destructive", children: error })), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Button, { size: "sm", onClick: onApprove, disabled: busy, children: state === "approving" ? "Approving…" : "Approve" }), _jsx(Button, { variant: "outline", size: "sm", onClick: onReject, disabled: busy, children: state === "rejecting" ? "Rejecting…" : "Reject" }), canAllowAlways ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => onAllowAlways(request.actionKey), disabled: busy, className: "ml-auto", children: state === "allowing-always" ? "Saving…" : "Always allow this" })) : null] })] }));
|
|
87
26
|
}
|
|
88
27
|
function ApprovalDetailRow({ detail }) {
|
|
89
28
|
const [expanded, setExpanded] = useState(false);
|
|
90
29
|
const long = detail.value.length > LONG_VALUE;
|
|
91
|
-
return
|
|
92
|
-
className: "grid grid-cols-[minmax(0,8rem)_1fr] gap-2",
|
|
93
|
-
children: [
|
|
94
|
-
/*#__PURE__*/ _jsx("dt", {
|
|
95
|
-
className: "truncate text-muted-foreground",
|
|
96
|
-
children: detail.label
|
|
97
|
-
}),
|
|
98
|
-
/*#__PURE__*/ _jsxs("dd", {
|
|
99
|
-
className: "min-w-0",
|
|
100
|
-
children: [
|
|
101
|
-
/*#__PURE__*/ _jsx("span", {
|
|
102
|
-
className: cn("block break-words whitespace-pre-wrap", long && !expanded && "line-clamp-2"),
|
|
103
|
-
children: detail.value
|
|
104
|
-
}),
|
|
105
|
-
long ? /*#__PURE__*/ _jsx("button", {
|
|
106
|
-
type: "button",
|
|
107
|
-
onClick: ()=>setExpanded((value)=>!value),
|
|
108
|
-
"aria-expanded": expanded,
|
|
109
|
-
className: "mt-0.5 text-primary-emphasis hover:underline",
|
|
110
|
-
children: expanded ? "Show less" : "Show more"
|
|
111
|
-
}) : null
|
|
112
|
-
]
|
|
113
|
-
})
|
|
114
|
-
]
|
|
115
|
-
});
|
|
30
|
+
return (_jsxs("div", { className: "grid grid-cols-[minmax(0,8rem)_1fr] gap-2", children: [_jsx("dt", { className: "truncate text-muted-foreground", children: detail.label }), _jsxs("dd", { className: "min-w-0", children: [_jsx("span", { className: cn("block break-words whitespace-pre-wrap", long && !expanded && "line-clamp-2"), children: detail.value }), long ? (_jsx("button", { type: "button", onClick: () => setExpanded((value) => !value), "aria-expanded": expanded, className: "mt-0.5 text-primary-emphasis hover:underline", children: expanded ? "Show less" : "Show more" })) : null] })] }));
|
|
116
31
|
}
|
package/dist/ui/artifact-body.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Download } from "lucide-react";
|
|
3
|
-
import { artifactForm } from "../lib/artifact.js";
|
|
3
|
+
import { artifactForm, } from "../lib/artifact.js";
|
|
4
4
|
import { toSafeHref } from "../lib/url.js";
|
|
5
5
|
import { cn } from "../lib/utils.js";
|
|
6
6
|
import { ArtifactNotice } from "./artifact-notice.js";
|
|
@@ -22,133 +22,57 @@ import { ResearchBody, parseResearchArtifact } from "./research-body.js";
|
|
|
22
22
|
* "empty" is a real state here — artifacts are frequently rendered while they
|
|
23
23
|
* are still being written — and each form's own empty rendering (a table with
|
|
24
24
|
* no rows, a frame with no src) reads as a fault rather than as progress.
|
|
25
|
-
*/
|
|
25
|
+
*/
|
|
26
|
+
export function ArtifactBody({ artifact, form, className }) {
|
|
26
27
|
const resolved = form ?? artifactForm(artifact.kind);
|
|
27
28
|
const content = artifact.content;
|
|
28
29
|
const blank = content.trim() === "";
|
|
29
|
-
return
|
|
30
|
-
className: cn("w-full", className),
|
|
31
|
-
children: body()
|
|
32
|
-
});
|
|
30
|
+
return _jsx("div", { className: cn("w-full", className), children: body() });
|
|
33
31
|
function body() {
|
|
34
|
-
switch(resolved){
|
|
35
|
-
case "image":
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
src: src,
|
|
48
|
-
alt: artifact.title,
|
|
49
|
-
className: "max-h-[480px] max-w-full rounded-lg border border-border"
|
|
50
|
-
}),
|
|
51
|
-
blank ? null : /*#__PURE__*/ _jsx("figcaption", {
|
|
52
|
-
className: "text-xs text-muted-foreground",
|
|
53
|
-
children: content
|
|
54
|
-
})
|
|
55
|
-
]
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
case "download":
|
|
59
|
-
{
|
|
60
|
-
const downloadUrl = toSafeHref(artifact.downloadUrl);
|
|
61
|
-
if (downloadUrl === undefined) {
|
|
62
|
-
return /*#__PURE__*/ _jsx(ArtifactNotice, {
|
|
63
|
-
message: "This file has no download location, so it cannot be retrieved."
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return /*#__PURE__*/ _jsxs("a", {
|
|
67
|
-
href: downloadUrl,
|
|
68
|
-
download: true,
|
|
69
|
-
className: buttonVariants({
|
|
70
|
-
variant: "outline",
|
|
71
|
-
size: "sm"
|
|
72
|
-
}),
|
|
73
|
-
children: [
|
|
74
|
-
/*#__PURE__*/ _jsx(Download, {
|
|
75
|
-
"aria-hidden": true
|
|
76
|
-
}),
|
|
77
|
-
"Download ",
|
|
78
|
-
artifact.title
|
|
79
|
-
]
|
|
80
|
-
});
|
|
32
|
+
switch (resolved) {
|
|
33
|
+
case "image": {
|
|
34
|
+
// The thumbnail URL, not the content: an image artifact's bytes live
|
|
35
|
+
// behind a route, and `content` for one is either empty or a caption.
|
|
36
|
+
const src = toSafeHref(artifact.thumbnailUrl ?? artifact.downloadUrl);
|
|
37
|
+
if (src === undefined)
|
|
38
|
+
return _jsx(ArtifactNotice, { pending: artifact.pending });
|
|
39
|
+
return (_jsxs("figure", { className: "flex flex-col gap-3", children: [_jsx("img", { src: src, alt: artifact.title, className: "max-h-[480px] max-w-full rounded-lg border border-border" }), blank ? null : (_jsx("figcaption", { className: "text-xs text-muted-foreground", children: content }))] }));
|
|
40
|
+
}
|
|
41
|
+
case "download": {
|
|
42
|
+
const downloadUrl = toSafeHref(artifact.downloadUrl);
|
|
43
|
+
if (downloadUrl === undefined) {
|
|
44
|
+
return (_jsx(ArtifactNotice, { message: "This file has no download location, so it cannot be retrieved." }));
|
|
81
45
|
}
|
|
46
|
+
return (_jsxs("a", { href: downloadUrl, download: true, className: buttonVariants({ variant: "outline", size: "sm" }), children: [_jsx(Download, { "aria-hidden": true }), "Download ", artifact.title] }));
|
|
47
|
+
}
|
|
82
48
|
case "embed":
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (blank) return /*#__PURE__*/ _jsx(ArtifactNotice, {
|
|
93
|
-
pending: artifact.pending
|
|
94
|
-
});
|
|
95
|
-
const downloadUrl = toSafeHref(artifact.downloadUrl);
|
|
96
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
97
|
-
className: "flex flex-col gap-3",
|
|
98
|
-
children: [
|
|
99
|
-
downloadUrl === undefined ? null : /*#__PURE__*/ _jsxs("a", {
|
|
100
|
-
href: downloadUrl,
|
|
101
|
-
download: true,
|
|
102
|
-
className: cn(buttonVariants({
|
|
103
|
-
variant: "outline",
|
|
104
|
-
size: "sm"
|
|
105
|
-
}), "self-start"),
|
|
106
|
-
children: [
|
|
107
|
-
/*#__PURE__*/ _jsx(Download, {
|
|
108
|
-
"aria-hidden": true
|
|
109
|
-
}),
|
|
110
|
-
"Download"
|
|
111
|
-
]
|
|
112
|
-
}),
|
|
113
|
-
/*#__PURE__*/ _jsx(CsvTable, {
|
|
114
|
-
text: content,
|
|
115
|
-
caption: artifact.title
|
|
116
|
-
})
|
|
117
|
-
]
|
|
118
|
-
});
|
|
119
|
-
}
|
|
49
|
+
return (_jsx(EmbedBody, { url: content.trim(), title: artifact.title, ...(artifact.downloadUrl === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { downloadUrl: artifact.downloadUrl }) }));
|
|
52
|
+
case "table": {
|
|
53
|
+
if (blank)
|
|
54
|
+
return _jsx(ArtifactNotice, { pending: artifact.pending });
|
|
55
|
+
const downloadUrl = toSafeHref(artifact.downloadUrl);
|
|
56
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [downloadUrl === undefined ? null : (_jsxs("a", { href: downloadUrl, download: true, className: cn(buttonVariants({ variant: "outline", size: "sm" }), "self-start"), children: [_jsx(Download, { "aria-hidden": true }), "Download"] })), _jsx(CsvTable, { text: content, caption: artifact.title })] }));
|
|
57
|
+
}
|
|
120
58
|
case "comparison":
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// still the artifact, so fall through to prose and let it be read.
|
|
135
|
-
if (parsed === null) return /*#__PURE__*/ _jsx(Prose, {
|
|
136
|
-
text: content
|
|
137
|
-
});
|
|
138
|
-
return /*#__PURE__*/ _jsx(ResearchBody, {
|
|
139
|
-
brief: parsed.brief,
|
|
140
|
-
...parsed.body === undefined ? {} : {
|
|
141
|
-
body: parsed.body
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
59
|
+
return (_jsx(CompareBodyFromJson, { content: content, ...(artifact.pending === undefined
|
|
60
|
+
? {}
|
|
61
|
+
: { pending: artifact.pending }) }));
|
|
62
|
+
case "research": {
|
|
63
|
+
if (blank)
|
|
64
|
+
return _jsx(ArtifactNotice, { pending: artifact.pending });
|
|
65
|
+
const parsed = parseResearchArtifact(content);
|
|
66
|
+
// Unparseable is not a failure worth an error card — the payload is
|
|
67
|
+
// still the artifact, so fall through to prose and let it be read.
|
|
68
|
+
if (parsed === null)
|
|
69
|
+
return _jsx(Prose, { text: content });
|
|
70
|
+
return (_jsx(ResearchBody, { brief: parsed.brief, ...(parsed.body === undefined ? {} : { body: parsed.body }) }));
|
|
71
|
+
}
|
|
145
72
|
case "prose":
|
|
146
|
-
if (blank)
|
|
147
|
-
pending: artifact.pending
|
|
148
|
-
});
|
|
149
|
-
return /*#__PURE__*/ _jsx(Prose, {
|
|
150
|
-
text: content
|
|
151
|
-
});
|
|
73
|
+
if (blank)
|
|
74
|
+
return _jsx(ArtifactNotice, { pending: artifact.pending });
|
|
75
|
+
return _jsx(Prose, { text: content });
|
|
152
76
|
}
|
|
153
77
|
}
|
|
154
78
|
}
|
|
@@ -162,9 +86,7 @@ import { ResearchBody, parseResearchArtifact } from "./research-body.js";
|
|
|
162
86
|
*
|
|
163
87
|
* `max-w-prose` caps the measure at roughly 65 characters. Full-bleed body text
|
|
164
88
|
* on a wide screen is unreadable regardless of how good the type is.
|
|
165
|
-
*/
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
children: text
|
|
169
|
-
});
|
|
89
|
+
*/
|
|
90
|
+
function Prose({ text }) {
|
|
91
|
+
return (_jsx("div", { className: "max-w-prose text-sm leading-relaxed whitespace-pre-wrap", children: text }));
|
|
170
92
|
}
|
|
@@ -16,6 +16,6 @@ export declare function ArtifactNotice({
|
|
|
16
16
|
pending,
|
|
17
17
|
/** Overrides the pending/empty wording — use for a specific failure. */
|
|
18
18
|
message, }: {
|
|
19
|
-
readonly pending?: boolean;
|
|
19
|
+
readonly pending?: boolean | undefined;
|
|
20
20
|
readonly message?: string;
|
|
21
21
|
}): import("react").JSX.Element;
|
|
@@ -13,24 +13,17 @@ import { EmptyState } from "./empty-state.js";
|
|
|
13
13
|
* artifact means the producer has not finished writing; an empty payload on a
|
|
14
14
|
* settled one means there is genuinely nothing. Same markup, opposite message,
|
|
15
15
|
* and getting it backwards makes a working system look broken.
|
|
16
|
-
*/
|
|
16
|
+
*/
|
|
17
|
+
export function ArtifactNotice({
|
|
18
|
+
/** The producer is still writing. Changes the message, not the layout. */
|
|
19
|
+
pending = false,
|
|
20
|
+
/** Overrides the pending/empty wording — use for a specific failure. */
|
|
21
|
+
message, }) {
|
|
17
22
|
if (message !== undefined) {
|
|
18
|
-
return
|
|
19
|
-
icon: /*#__PURE__*/ _jsx(FileWarning, {}),
|
|
20
|
-
title: "Nothing to preview",
|
|
21
|
-
description: message
|
|
22
|
-
});
|
|
23
|
+
return (_jsx(EmptyState, { icon: _jsx(FileWarning, {}), title: "Nothing to preview", description: message }));
|
|
23
24
|
}
|
|
24
25
|
if (pending) {
|
|
25
|
-
return
|
|
26
|
-
icon: /*#__PURE__*/ _jsx(Loader2, {}),
|
|
27
|
-
title: "Still being produced",
|
|
28
|
-
description: "This artifact has no content yet — check back shortly."
|
|
29
|
-
});
|
|
26
|
+
return (_jsx(EmptyState, { icon: _jsx(Loader2, {}), title: "Still being produced", description: "This artifact has no content yet \u2014 check back shortly." }));
|
|
30
27
|
}
|
|
31
|
-
return
|
|
32
|
-
icon: /*#__PURE__*/ _jsx(FileWarning, {}),
|
|
33
|
-
title: "No content",
|
|
34
|
-
description: "This artifact is empty."
|
|
35
|
-
});
|
|
28
|
+
return (_jsx(EmptyState, { icon: _jsx(FileWarning, {}), title: "No content", description: "This artifact is empty." }));
|
|
36
29
|
}
|
package/dist/ui/avatar.d.ts
CHANGED
|
@@ -33,5 +33,5 @@ export type AvatarStackProps = {
|
|
|
33
33
|
/**
|
|
34
34
|
* Overlapping avatar stack for thread participants and channel members.
|
|
35
35
|
*/
|
|
36
|
-
export declare function AvatarStack({ items, max, size, className }: AvatarStackProps): import("react").JSX.Element;
|
|
36
|
+
export declare function AvatarStack({ items, max, size, className, }: AvatarStackProps): import("react").JSX.Element;
|
|
37
37
|
export type AvatarStackSlot = ReactNode;
|
package/dist/ui/avatar.js
CHANGED
|
@@ -3,71 +3,34 @@ import { cn } from "../lib/utils.js";
|
|
|
3
3
|
const SIZE_CLASS = {
|
|
4
4
|
sm: "size-6 text-[10px]",
|
|
5
5
|
md: "size-8 text-xs",
|
|
6
|
-
lg: "size-10 text-sm"
|
|
6
|
+
lg: "size-10 text-sm",
|
|
7
7
|
};
|
|
8
8
|
const TONE_CLASS = {
|
|
9
9
|
neutral: "bg-muted text-muted-foreground",
|
|
10
10
|
agent: "bg-primary text-primary-foreground",
|
|
11
11
|
agent2: "bg-accent text-accent-foreground",
|
|
12
|
-
agent3: "bg-success text-success-foreground"
|
|
12
|
+
agent3: "bg-success text-success-foreground",
|
|
13
13
|
};
|
|
14
14
|
const BADGE_SIZE = {
|
|
15
15
|
sm: "size-3 text-[7px]",
|
|
16
16
|
md: "size-3.5 text-[8px]",
|
|
17
|
-
lg: "size-4 text-[9px]"
|
|
17
|
+
lg: "size-4 text-[9px]",
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Initials avatar with optional tenant monogram badge. Images are
|
|
21
21
|
* intentionally unsupported here: identity headers should not flash or
|
|
22
22
|
* depend on third-party avatar hosts.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"aria-label": label,
|
|
27
|
-
className: cn("relative inline-flex shrink-0 items-center justify-center font-bold uppercase", SIZE_CLASS[size], TONE_CLASS[tone], className),
|
|
28
|
-
children: [
|
|
29
|
-
/*#__PURE__*/ _jsx("span", {
|
|
30
|
-
"aria-hidden": true,
|
|
31
|
-
children: initials.slice(0, 2)
|
|
32
|
-
}),
|
|
33
|
-
tenantMonogram === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
34
|
-
"aria-hidden": true,
|
|
35
|
-
className: cn("absolute -right-0.5 -bottom-0.5 inline-flex items-center justify-center border border-background bg-muted font-bold uppercase text-muted-foreground", BADGE_SIZE[size]),
|
|
36
|
-
children: tenantMonogram.slice(0, 1)
|
|
37
|
-
})
|
|
38
|
-
]
|
|
39
|
-
});
|
|
23
|
+
*/
|
|
24
|
+
export function Avatar({ initials, label, tone = "neutral", size = "md", tenantMonogram, className, }) {
|
|
25
|
+
return (_jsxs("span", { role: "img", "aria-label": label, className: cn("relative inline-flex shrink-0 items-center justify-center font-bold uppercase", SIZE_CLASS[size], TONE_CLASS[tone], className), children: [_jsx("span", { "aria-hidden": true, children: initials.slice(0, 2) }), tenantMonogram === undefined ? null : (_jsx("span", { "aria-hidden": true, className: cn("absolute -right-0.5 -bottom-0.5 inline-flex items-center justify-center border border-background bg-muted font-bold uppercase text-muted-foreground", BADGE_SIZE[size]), children: tenantMonogram.slice(0, 1) }))] }));
|
|
40
26
|
}
|
|
41
27
|
/**
|
|
42
28
|
* Overlapping avatar stack for thread participants and channel members.
|
|
43
|
-
*/
|
|
29
|
+
*/
|
|
30
|
+
export function AvatarStack({ items, max = 4, size = "sm", className, }) {
|
|
44
31
|
const visible = items.slice(0, max);
|
|
45
32
|
const overflow = items.length - visible.length;
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"aria-label": "Participants",
|
|
50
|
-
children: [
|
|
51
|
-
visible.map((item, index)=>/*#__PURE__*/ _jsx(Avatar, {
|
|
52
|
-
initials: item.initials,
|
|
53
|
-
label: item.label,
|
|
54
|
-
...item.tone === undefined ? {} : {
|
|
55
|
-
tone: item.tone
|
|
56
|
-
},
|
|
57
|
-
...item.tenantMonogram === undefined ? {} : {
|
|
58
|
-
tenantMonogram: item.tenantMonogram
|
|
59
|
-
},
|
|
60
|
-
size: size,
|
|
61
|
-
className: cn("ring-1 ring-background", index > 0 && "-ml-1.5")
|
|
62
|
-
}, item.id)),
|
|
63
|
-
overflow <= 0 ? null : /*#__PURE__*/ _jsxs("span", {
|
|
64
|
-
className: cn("inline-flex items-center justify-center bg-muted font-mono font-semibold text-muted-foreground ring-1 ring-background", SIZE_CLASS[size], visible.length > 0 && "-ml-1.5"),
|
|
65
|
-
"aria-label": `${overflow} more`,
|
|
66
|
-
children: [
|
|
67
|
-
"+",
|
|
68
|
-
overflow
|
|
69
|
-
]
|
|
70
|
-
})
|
|
71
|
-
]
|
|
72
|
-
});
|
|
33
|
+
return (_jsxs("span", { className: cn("inline-flex items-center", className), role: "group", "aria-label": "Participants", children: [visible.map((item, index) => (_jsx(Avatar, { initials: item.initials, label: item.label, ...(item.tone === undefined ? {} : { tone: item.tone }), ...(item.tenantMonogram === undefined
|
|
34
|
+
? {}
|
|
35
|
+
: { tenantMonogram: item.tenantMonogram }), size: size, className: cn("ring-1 ring-background", index > 0 && "-ml-1.5") }, item.id))), overflow <= 0 ? null : (_jsxs("span", { className: cn("inline-flex items-center justify-center bg-muted font-mono font-semibold text-muted-foreground ring-1 ring-background", SIZE_CLASS[size], visible.length > 0 && "-ml-1.5"), "aria-label": `${overflow} more`, children: ["+", overflow] }))] }));
|
|
73
36
|
}
|
package/dist/ui/badge.js
CHANGED
|
@@ -16,20 +16,12 @@ const badgeVariants = cva("inline-flex items-center gap-1 rounded-sm border px-1
|
|
|
16
16
|
warning: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis",
|
|
17
17
|
danger: "border-destructive bg-destructive text-destructive-foreground",
|
|
18
18
|
shared: "border-accent bg-accent text-accent-foreground",
|
|
19
|
-
access: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis"
|
|
20
|
-
}
|
|
19
|
+
access: "border-primary-emphasis/40 bg-primary/10 text-primary-emphasis",
|
|
20
|
+
},
|
|
21
21
|
},
|
|
22
|
-
defaultVariants: {
|
|
23
|
-
tone: "neutral"
|
|
24
|
-
}
|
|
22
|
+
defaultVariants: { tone: "neutral" },
|
|
25
23
|
});
|
|
26
24
|
export function Badge({ className, tone, ...props }) {
|
|
27
|
-
return
|
|
28
|
-
"data-slot": "badge",
|
|
29
|
-
className: cn(badgeVariants({
|
|
30
|
-
tone
|
|
31
|
-
}), className),
|
|
32
|
-
...props
|
|
33
|
-
});
|
|
25
|
+
return (_jsx("span", { "data-slot": "badge", className: cn(badgeVariants({ tone }), className), ...props }));
|
|
34
26
|
}
|
|
35
27
|
export { badgeVariants };
|
package/dist/ui/bar-chart.d.ts
CHANGED
|
@@ -35,4 +35,4 @@ export type BarChartProps = {
|
|
|
35
35
|
* the exact values — which is what anyone reading non-visually wants — are in
|
|
36
36
|
* the table, in order, with headers.
|
|
37
37
|
*/
|
|
38
|
-
export declare function BarChart({ title, description, data, valueLabel, format, className }: BarChartProps): import("react").JSX.Element;
|
|
38
|
+
export declare function BarChart({ title, description, data, valueLabel, format, className, }: BarChartProps): import("react").JSX.Element;
|
package/dist/ui/bar-chart.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { formatCompact, niceTicks, scaleLinear } from "../lib/chart-geometry.js";
|
|
2
|
+
import { formatCompact, niceTicks, scaleLinear, } from "../lib/chart-geometry.js";
|
|
3
3
|
import { seriesColor } from "../lib/chart-palette.js";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
5
|
import { ChartFrame } from "./chart-frame.js";
|
|
@@ -30,89 +30,37 @@ const RADIUS = 4;
|
|
|
30
30
|
* numbers. An SVG full of `<rect>` elements announced individually is noise, and
|
|
31
31
|
* the exact values — which is what anyone reading non-visually wants — are in
|
|
32
32
|
* the table, in order, with headers.
|
|
33
|
-
*/
|
|
34
|
-
|
|
33
|
+
*/
|
|
34
|
+
export function BarChart({ title, description, data, valueLabel = "Value", format = formatCompact, className, }) {
|
|
35
|
+
const max = Math.max(0, ...data.map((datum) => datum.value));
|
|
35
36
|
const ticks = niceTicks(max);
|
|
36
37
|
const axisMax = ticks[ticks.length - 1] ?? 1;
|
|
37
38
|
const plotWidth = 320;
|
|
38
39
|
const height = data.length * ROW_HEIGHT;
|
|
39
40
|
const width = LABEL_WIDTH + plotWidth + VALUE_WIDTH;
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
table: {
|
|
46
|
-
columns: [
|
|
47
|
-
"Category",
|
|
48
|
-
valueLabel
|
|
49
|
-
],
|
|
50
|
-
rows: data.map((datum)=>[
|
|
51
|
-
datum.label,
|
|
52
|
-
format(datum.value)
|
|
53
|
-
])
|
|
54
|
-
},
|
|
55
|
-
className: className,
|
|
56
|
-
children: [
|
|
57
|
-
/*#__PURE__*/ _jsxs("svg", {
|
|
58
|
-
viewBox: `0 0 ${width} ${height}`,
|
|
41
|
+
return (_jsxs(ChartFrame, { title: title, ...(description === undefined ? {} : { description }), table: {
|
|
42
|
+
columns: ["Category", valueLabel],
|
|
43
|
+
rows: data.map((datum) => [datum.label, format(datum.value)]),
|
|
44
|
+
}, className: className, children: [_jsxs("svg", { viewBox: `0 0 ${width} ${height}`,
|
|
59
45
|
// Scales to the container's width; the row rhythm is what must stay
|
|
60
46
|
// fixed, and it is expressed in the viewBox.
|
|
61
|
-
className: "h-auto w-full",
|
|
62
|
-
"aria-hidden": true,
|
|
63
|
-
focusable: "false",
|
|
64
|
-
children: [
|
|
65
|
-
ticks.map((tick)=>{
|
|
47
|
+
className: "h-auto w-full", "aria-hidden": true, focusable: "false", children: [ticks.map((tick) => {
|
|
66
48
|
const x = LABEL_WIDTH + scaleLinear(tick, axisMax, plotWidth);
|
|
67
|
-
return(
|
|
49
|
+
return (
|
|
50
|
+
// Hairline, solid, one step off the surface: present enough to
|
|
68
51
|
// measure against, quiet enough that the bars stay the loud thing.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
y1: 0,
|
|
72
|
-
x2: x,
|
|
73
|
-
y2: height,
|
|
74
|
-
stroke: "var(--border)",
|
|
75
|
-
strokeWidth: 1
|
|
76
|
-
}, tick));
|
|
77
|
-
}),
|
|
78
|
-
data.map((datum, index)=>{
|
|
52
|
+
_jsx("line", { x1: x, y1: 0, x2: x, y2: height, stroke: "var(--border)", strokeWidth: 1 }, tick));
|
|
53
|
+
}), data.map((datum, index) => {
|
|
79
54
|
const y = index * ROW_HEIGHT + (ROW_HEIGHT - BAR_HEIGHT) / 2;
|
|
80
55
|
const length = scaleLinear(datum.value, axisMax, plotWidth);
|
|
81
56
|
const radius = Math.min(RADIUS, length / 2);
|
|
82
|
-
return
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}),
|
|
92
|
-
/*#__PURE__*/ _jsx("path", {
|
|
93
|
-
d: length <= 0 ? "" : `M${LABEL_WIDTH} ${y}` + `H${LABEL_WIDTH + length - radius}` + `a${radius} ${radius} 0 0 1 ${radius} ${radius}` + `V${y + BAR_HEIGHT - radius}` + `a${radius} ${radius} 0 0 1 ${-radius} ${radius}` + `H${LABEL_WIDTH}Z`,
|
|
94
|
-
fill: seriesColor(0)
|
|
95
|
-
}),
|
|
96
|
-
/*#__PURE__*/ _jsx("text", {
|
|
97
|
-
x: LABEL_WIDTH + length + 8,
|
|
98
|
-
y: index * ROW_HEIGHT + ROW_HEIGHT / 2,
|
|
99
|
-
dominantBaseline: "middle",
|
|
100
|
-
className: "fill-foreground text-[11px] tabular-nums",
|
|
101
|
-
children: format(datum.value)
|
|
102
|
-
})
|
|
103
|
-
]
|
|
104
|
-
}, datum.label);
|
|
105
|
-
})
|
|
106
|
-
]
|
|
107
|
-
}),
|
|
108
|
-
/*#__PURE__*/ _jsxs("p", {
|
|
109
|
-
className: cn("text-xs text-muted-foreground"),
|
|
110
|
-
children: [
|
|
111
|
-
"Axis to ",
|
|
112
|
-
format(axisMax),
|
|
113
|
-
", from zero."
|
|
114
|
-
]
|
|
115
|
-
})
|
|
116
|
-
]
|
|
117
|
-
});
|
|
57
|
+
return (_jsxs("g", { children: [_jsx("text", { x: LABEL_WIDTH - 8, y: index * ROW_HEIGHT + ROW_HEIGHT / 2, textAnchor: "end", dominantBaseline: "middle", className: "fill-muted-foreground text-[11px]", children: datum.label }), _jsx("path", { d: length <= 0
|
|
58
|
+
? ""
|
|
59
|
+
: `M${LABEL_WIDTH} ${y}` +
|
|
60
|
+
`H${LABEL_WIDTH + length - radius}` +
|
|
61
|
+
`a${radius} ${radius} 0 0 1 ${radius} ${radius}` +
|
|
62
|
+
`V${y + BAR_HEIGHT - radius}` +
|
|
63
|
+
`a${radius} ${radius} 0 0 1 ${-radius} ${radius}` +
|
|
64
|
+
`H${LABEL_WIDTH}Z`, fill: seriesColor(0) }), _jsx("text", { x: LABEL_WIDTH + length + 8, y: index * ROW_HEIGHT + ROW_HEIGHT / 2, dominantBaseline: "middle", className: "fill-foreground text-[11px] tabular-nums", children: format(datum.value) })] }, datum.label));
|
|
65
|
+
})] }), _jsxs("p", { className: cn("text-xs text-muted-foreground"), children: ["Axis to ", format(axisMax), ", from zero."] })] }));
|
|
118
66
|
}
|