@corbits/react-ui 0.1.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 +501 -0
- package/README.md +125 -0
- package/dist/blocks/login/auth-layout.d.ts +38 -0
- package/dist/blocks/login/auth-layout.js +52 -0
- package/dist/blocks/login/login-form.d.ts +60 -0
- package/dist/blocks/login/login-form.js +151 -0
- package/dist/hooks/use-command-palette-navigation.d.ts +25 -0
- package/dist/hooks/use-command-palette-navigation.js +52 -0
- package/dist/hooks/use-controllable-state.d.ts +28 -0
- package/dist/hooks/use-controllable-state.js +44 -0
- package/dist/hooks/use-delayed-autofocus.d.ts +9 -0
- package/dist/hooks/use-delayed-autofocus.js +20 -0
- package/dist/hooks/use-dismissable-popover.d.ts +37 -0
- package/dist/hooks/use-dismissable-popover.js +64 -0
- package/dist/hooks/use-list-selection.d.ts +66 -0
- package/dist/hooks/use-list-selection.js +147 -0
- package/dist/hooks/use-prefers-reduced-motion.d.ts +13 -0
- package/dist/hooks/use-prefers-reduced-motion.js +28 -0
- package/dist/hooks/use-scroll-current-into-view.d.ts +19 -0
- package/dist/hooks/use-scroll-current-into-view.js +33 -0
- package/dist/index.d.ts +122 -0
- package/dist/index.js +131 -0
- package/dist/lib/artifact.d.ts +72 -0
- package/dist/lib/artifact.js +67 -0
- package/dist/lib/chart-geometry.d.ts +62 -0
- package/dist/lib/chart-geometry.js +86 -0
- package/dist/lib/chart-palette.d.ts +76 -0
- package/dist/lib/chart-palette.js +92 -0
- package/dist/lib/chat-message.d.ts +115 -0
- package/dist/lib/chat-message.js +41 -0
- package/dist/lib/chat-parts.d.ts +64 -0
- package/dist/lib/chat-parts.js +16 -0
- package/dist/lib/csv.d.ts +60 -0
- package/dist/lib/csv.js +108 -0
- package/dist/lib/metrics.d.ts +70 -0
- package/dist/lib/metrics.js +101 -0
- package/dist/lib/now-item.d.ts +65 -0
- package/dist/lib/now-item.js +59 -0
- package/dist/lib/relative-time.d.ts +9 -0
- package/dist/lib/relative-time.js +47 -0
- package/dist/lib/theme.d.ts +30 -0
- package/dist/lib/theme.js +77 -0
- package/dist/lib/url.d.ts +26 -0
- package/dist/lib/url.js +37 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/lib/workflow-display-flow.d.ts +83 -0
- package/dist/lib/workflow-display-flow.js +104 -0
- package/dist/lib/workflow-registry.d.ts +90 -0
- package/dist/lib/workflow-registry.js +56 -0
- package/dist/lib/workflow-run-error.d.ts +31 -0
- package/dist/lib/workflow-run-error.js +105 -0
- package/dist/lib/workflow-run-progress.d.ts +97 -0
- package/dist/lib/workflow-run-progress.js +135 -0
- package/dist/lib/workflow-run.d.ts +43 -0
- package/dist/lib/workflow-run.js +56 -0
- package/dist/styles.css +3080 -0
- package/dist/test/render-hook.d.ts +14 -0
- package/dist/test/render-hook.js +38 -0
- package/dist/theme.css +628 -0
- package/dist/ui/agent-turn.d.ts +26 -0
- package/dist/ui/agent-turn.js +60 -0
- package/dist/ui/animated-number.d.ts +25 -0
- package/dist/ui/animated-number.js +63 -0
- package/dist/ui/approval-card.d.ts +46 -0
- package/dist/ui/approval-card.js +116 -0
- package/dist/ui/artifact-body.d.ts +26 -0
- package/dist/ui/artifact-body.js +170 -0
- package/dist/ui/artifact-notice.d.ts +21 -0
- package/dist/ui/artifact-notice.js +36 -0
- package/dist/ui/avatar.d.ts +37 -0
- package/dist/ui/avatar.js +73 -0
- package/dist/ui/badge.d.ts +10 -0
- package/dist/ui/badge.js +35 -0
- package/dist/ui/bar-chart.d.ts +38 -0
- package/dist/ui/bar-chart.js +118 -0
- package/dist/ui/block-card.d.ts +29 -0
- package/dist/ui/block-card.js +66 -0
- package/dist/ui/boot-screen.d.ts +23 -0
- package/dist/ui/boot-screen.js +49 -0
- package/dist/ui/bulk-action-bar.d.ts +37 -0
- package/dist/ui/bulk-action-bar.js +64 -0
- package/dist/ui/button.d.ts +12 -0
- package/dist/ui/button.js +73 -0
- package/dist/ui/card.d.ts +6 -0
- package/dist/ui/card.js +37 -0
- package/dist/ui/category-bars.d.ts +20 -0
- package/dist/ui/category-bars.js +69 -0
- package/dist/ui/chart-frame.d.ts +54 -0
- package/dist/ui/chart-frame.js +108 -0
- package/dist/ui/chat-composer.d.ts +24 -0
- package/dist/ui/chat-composer.js +32 -0
- package/dist/ui/chat-dock-timing.d.ts +15 -0
- package/dist/ui/chat-dock-timing.js +11 -0
- package/dist/ui/chat-input.d.ts +38 -0
- package/dist/ui/chat-input.js +138 -0
- package/dist/ui/chat-panel.d.ts +20 -0
- package/dist/ui/chat-panel.js +56 -0
- package/dist/ui/chat-thread.d.ts +28 -0
- package/dist/ui/chat-thread.js +61 -0
- package/dist/ui/checkbox.d.ts +25 -0
- package/dist/ui/checkbox.js +63 -0
- package/dist/ui/command-palette.d.ts +100 -0
- package/dist/ui/command-palette.js +341 -0
- package/dist/ui/compare-body.d.ts +52 -0
- package/dist/ui/compare-body.js +140 -0
- package/dist/ui/confirm-button.d.ts +29 -0
- package/dist/ui/confirm-button.js +41 -0
- package/dist/ui/corbits-mark.d.ts +29 -0
- package/dist/ui/corbits-mark.js +33 -0
- package/dist/ui/csv-table.d.ts +22 -0
- package/dist/ui/csv-table.js +85 -0
- package/dist/ui/dialog.d.ts +37 -0
- package/dist/ui/dialog.js +105 -0
- package/dist/ui/dictation-status-line.d.ts +20 -0
- package/dist/ui/dictation-status-line.js +38 -0
- package/dist/ui/dither-canvas.d.ts +31 -0
- package/dist/ui/dither-canvas.js +169 -0
- package/dist/ui/embed-body.d.ts +30 -0
- package/dist/ui/embed-body.js +92 -0
- package/dist/ui/empty-state.d.ts +26 -0
- package/dist/ui/empty-state.js +42 -0
- package/dist/ui/file-input.d.ts +25 -0
- package/dist/ui/file-input.js +66 -0
- package/dist/ui/filter-bar.d.ts +42 -0
- package/dist/ui/filter-bar.js +95 -0
- package/dist/ui/filter-chip.d.ts +14 -0
- package/dist/ui/filter-chip.js +23 -0
- package/dist/ui/gate-block.d.ts +16 -0
- package/dist/ui/gate-block.js +37 -0
- package/dist/ui/horizontal-stepper.d.ts +13 -0
- package/dist/ui/horizontal-stepper.js +65 -0
- package/dist/ui/input.d.ts +2 -0
- package/dist/ui/input.js +14 -0
- package/dist/ui/inspector-shell.d.ts +47 -0
- package/dist/ui/inspector-shell.js +98 -0
- package/dist/ui/intake-form.d.ts +39 -0
- package/dist/ui/intake-form.js +119 -0
- package/dist/ui/kind-card-grid.d.ts +23 -0
- package/dist/ui/kind-card-grid.js +43 -0
- package/dist/ui/library-page-header.d.ts +20 -0
- package/dist/ui/library-page-header.js +43 -0
- package/dist/ui/list-detail.d.ts +28 -0
- package/dist/ui/list-detail.js +55 -0
- package/dist/ui/live-run-banner.d.ts +13 -0
- package/dist/ui/live-run-banner.js +23 -0
- package/dist/ui/live-status-line.d.ts +22 -0
- package/dist/ui/live-status-line.js +37 -0
- package/dist/ui/menu.d.ts +18 -0
- package/dist/ui/menu.js +45 -0
- package/dist/ui/message-bubble.d.ts +24 -0
- package/dist/ui/message-bubble.js +64 -0
- package/dist/ui/mic-button.d.ts +35 -0
- package/dist/ui/mic-button.js +61 -0
- package/dist/ui/mic-permission-dialog.d.ts +20 -0
- package/dist/ui/mic-permission-dialog.js +50 -0
- package/dist/ui/notifications-bell.d.ts +28 -0
- package/dist/ui/notifications-bell.js +69 -0
- package/dist/ui/now-cards.d.ts +37 -0
- package/dist/ui/now-cards.js +116 -0
- package/dist/ui/page-panel.d.ts +37 -0
- package/dist/ui/page-panel.js +23 -0
- package/dist/ui/page-shell.d.ts +21 -0
- package/dist/ui/page-shell.js +26 -0
- package/dist/ui/parts-renderer.d.ts +22 -0
- package/dist/ui/parts-renderer.js +234 -0
- package/dist/ui/profile-card.d.ts +39 -0
- package/dist/ui/profile-card.js +124 -0
- package/dist/ui/progress-checklist.d.ts +25 -0
- package/dist/ui/progress-checklist.js +70 -0
- package/dist/ui/provider-mark.d.ts +32 -0
- package/dist/ui/provider-mark.js +31 -0
- package/dist/ui/quick-reply-chips.d.ts +14 -0
- package/dist/ui/quick-reply-chips.js +24 -0
- package/dist/ui/quote-card.d.ts +39 -0
- package/dist/ui/quote-card.js +66 -0
- package/dist/ui/reasoning-block.d.ts +35 -0
- package/dist/ui/reasoning-block.js +60 -0
- package/dist/ui/research-body.d.ts +70 -0
- package/dist/ui/research-body.js +270 -0
- package/dist/ui/rich-empty-state.d.ts +35 -0
- package/dist/ui/rich-empty-state.js +65 -0
- package/dist/ui/run-now-button.d.ts +23 -0
- package/dist/ui/run-now-button.js +42 -0
- package/dist/ui/section.d.ts +20 -0
- package/dist/ui/section.js +48 -0
- package/dist/ui/select.d.ts +2 -0
- package/dist/ui/select.js +22 -0
- package/dist/ui/selection-checkbox.d.ts +42 -0
- package/dist/ui/selection-checkbox.js +54 -0
- package/dist/ui/settings-panel.d.ts +35 -0
- package/dist/ui/settings-panel.js +68 -0
- package/dist/ui/shimmer-text.d.ts +19 -0
- package/dist/ui/shimmer-text.js +20 -0
- package/dist/ui/sidebar-item-row.d.ts +40 -0
- package/dist/ui/sidebar-item-row.js +64 -0
- package/dist/ui/sidebar-panel.d.ts +25 -0
- package/dist/ui/sidebar-panel.js +56 -0
- package/dist/ui/sidebar.d.ts +46 -0
- package/dist/ui/sidebar.js +111 -0
- package/dist/ui/skeleton.d.ts +13 -0
- package/dist/ui/skeleton.js +20 -0
- package/dist/ui/sortable-table.d.ts +43 -0
- package/dist/ui/sortable-table.js +103 -0
- package/dist/ui/sparkline.d.ts +27 -0
- package/dist/ui/sparkline.js +68 -0
- package/dist/ui/stat-grid.d.ts +55 -0
- package/dist/ui/stat-grid.js +87 -0
- package/dist/ui/status-dot.d.ts +13 -0
- package/dist/ui/status-dot.js +51 -0
- package/dist/ui/step-list.d.ts +21 -0
- package/dist/ui/step-list.js +77 -0
- package/dist/ui/switch.d.ts +23 -0
- package/dist/ui/switch.js +29 -0
- package/dist/ui/table.d.ts +8 -0
- package/dist/ui/table.js +48 -0
- package/dist/ui/tabs.d.ts +44 -0
- package/dist/ui/tabs.js +101 -0
- package/dist/ui/textarea.d.ts +8 -0
- package/dist/ui/textarea.js +32 -0
- package/dist/ui/theme-provider.d.ts +36 -0
- package/dist/ui/theme-provider.js +126 -0
- package/dist/ui/theme-toggle.d.ts +11 -0
- package/dist/ui/theme-toggle.js +32 -0
- package/dist/ui/thinking-indicator.d.ts +7 -0
- package/dist/ui/thinking-indicator.js +19 -0
- package/dist/ui/thinking-label.d.ts +19 -0
- package/dist/ui/thinking-label.js +54 -0
- package/dist/ui/thinking-mark.d.ts +10 -0
- package/dist/ui/thinking-mark.js +153 -0
- package/dist/ui/time-series-chart.d.ts +55 -0
- package/dist/ui/time-series-chart.js +249 -0
- package/dist/ui/toast.d.ts +16 -0
- package/dist/ui/toast.js +41 -0
- package/dist/ui/token-mosaic.d.ts +22 -0
- package/dist/ui/token-mosaic.js +65 -0
- package/dist/ui/tool-block.d.ts +54 -0
- package/dist/ui/tool-block.js +170 -0
- package/dist/ui/tool-narrative.d.ts +22 -0
- package/dist/ui/tool-narrative.js +77 -0
- package/dist/ui/tool-picker.d.ts +44 -0
- package/dist/ui/tool-picker.js +200 -0
- package/dist/ui/tooltip.d.ts +21 -0
- package/dist/ui/tooltip.js +48 -0
- package/dist/ui/top-bar.d.ts +53 -0
- package/dist/ui/top-bar.js +98 -0
- package/dist/ui/trace-waterfall.d.ts +38 -0
- package/dist/ui/trace-waterfall.js +121 -0
- package/dist/ui/typing-indicator.d.ts +9 -0
- package/dist/ui/typing-indicator.js +25 -0
- package/dist/ui/view-toggle.d.ts +17 -0
- package/dist/ui/view-toggle.js +46 -0
- package/dist/ui/voice-waveform.d.ts +16 -0
- package/dist/ui/voice-waveform.js +23 -0
- package/package.json +583 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ChecklistStepStatus = "pending" | "running" | "done" | "failed";
|
|
2
|
+
export type ChecklistStep = {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly label: string;
|
|
5
|
+
readonly status: ChecklistStepStatus;
|
|
6
|
+
/** Why it failed, or what it found. Shown under the label. */
|
|
7
|
+
readonly detail?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A list of steps and how far along they are — a long operation reporting
|
|
11
|
+
* itself while the user waits.
|
|
12
|
+
*
|
|
13
|
+
* Each row states its status in text, not only by icon or colour. A checklist
|
|
14
|
+
* where "done" is conveyed by a green tick alone is unreadable to anyone who
|
|
15
|
+
* cannot distinguish it from the grey one, and the status word costs a line of
|
|
16
|
+
* markup.
|
|
17
|
+
*
|
|
18
|
+
* The whole list is `aria-live="polite"`, so steps completing are announced as
|
|
19
|
+
* they happen without stealing focus from wherever the user actually is.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ProgressChecklist({ steps, label, className, }: {
|
|
22
|
+
steps: readonly ChecklistStep[];
|
|
23
|
+
label?: string;
|
|
24
|
+
className?: string;
|
|
25
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Check, X } from "lucide-react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { StatusDot } from "./status-dot.js";
|
|
5
|
+
const STATUS_LABEL = {
|
|
6
|
+
pending: "Not started",
|
|
7
|
+
running: "In progress",
|
|
8
|
+
done: "Done",
|
|
9
|
+
failed: "Failed"
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* A list of steps and how far along they are — a long operation reporting
|
|
13
|
+
* itself while the user waits.
|
|
14
|
+
*
|
|
15
|
+
* Each row states its status in text, not only by icon or colour. A checklist
|
|
16
|
+
* where "done" is conveyed by a green tick alone is unreadable to anyone who
|
|
17
|
+
* cannot distinguish it from the grey one, and the status word costs a line of
|
|
18
|
+
* markup.
|
|
19
|
+
*
|
|
20
|
+
* The whole list is `aria-live="polite"`, so steps completing are announced as
|
|
21
|
+
* they happen without stealing focus from wherever the user actually is.
|
|
22
|
+
*/ export function ProgressChecklist({ steps, label = "Progress", className }) {
|
|
23
|
+
if (steps.length === 0) return null;
|
|
24
|
+
return /*#__PURE__*/ _jsx("ol", {
|
|
25
|
+
"aria-label": label,
|
|
26
|
+
"aria-live": "polite",
|
|
27
|
+
className: cn("flex flex-col gap-2.5", className),
|
|
28
|
+
children: steps.map((step, index)=>/*#__PURE__*/ _jsxs("li", {
|
|
29
|
+
className: "flex items-start gap-3",
|
|
30
|
+
children: [
|
|
31
|
+
/*#__PURE__*/ _jsx("span", {
|
|
32
|
+
"aria-hidden": true,
|
|
33
|
+
className: cn("mt-0.5 grid size-5 shrink-0 place-items-center rounded-full border text-[10px] font-semibold", step.status === "done" && "border-transparent bg-success text-success-foreground", step.status === "failed" && "border-transparent bg-destructive text-destructive-foreground", step.status === "running" && "border-primary-emphasis text-primary-emphasis", step.status === "pending" && "border-input text-muted-foreground"),
|
|
34
|
+
children: step.status === "done" ? /*#__PURE__*/ _jsx(Check, {
|
|
35
|
+
className: "size-3"
|
|
36
|
+
}) : step.status === "failed" ? /*#__PURE__*/ _jsx(X, {
|
|
37
|
+
className: "size-3"
|
|
38
|
+
}) : step.status === "running" ? /*#__PURE__*/ _jsx(StatusDot, {
|
|
39
|
+
label: "",
|
|
40
|
+
live: true,
|
|
41
|
+
tone: "emphasis"
|
|
42
|
+
}) : index + 1
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
45
|
+
className: "flex min-w-0 flex-col gap-0.5",
|
|
46
|
+
children: [
|
|
47
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
48
|
+
className: cn("text-sm leading-snug", step.status === "pending" ? "text-muted-foreground" : "text-foreground"),
|
|
49
|
+
children: [
|
|
50
|
+
step.label,
|
|
51
|
+
" ",
|
|
52
|
+
/*#__PURE__*/ _jsxs("span", {
|
|
53
|
+
className: "text-xs text-muted-foreground",
|
|
54
|
+
children: [
|
|
55
|
+
"· ",
|
|
56
|
+
STATUS_LABEL[step.status]
|
|
57
|
+
]
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
}),
|
|
61
|
+
step.detail === undefined ? null : /*#__PURE__*/ _jsx("p", {
|
|
62
|
+
className: "text-xs leading-relaxed text-muted-foreground",
|
|
63
|
+
children: step.detail
|
|
64
|
+
})
|
|
65
|
+
]
|
|
66
|
+
})
|
|
67
|
+
]
|
|
68
|
+
}, step.id))
|
|
69
|
+
});
|
|
70
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ToolPart } from "../lib/chat-message.js";
|
|
3
|
+
export type ProviderMarkProps = {
|
|
4
|
+
/** Provider key: `slack`, `linear`, `github`. Shown as a monogram if no logo. */
|
|
5
|
+
readonly provider: string;
|
|
6
|
+
/**
|
|
7
|
+
* The provider's brand mark, supplied by the host.
|
|
8
|
+
*
|
|
9
|
+
* This registry ships no third-party logos. Trademarks are not ours to
|
|
10
|
+
* redistribute, and an app that wants real marks has its own source for them
|
|
11
|
+
* — a brand API, a licensed icon set, its own SVGs. So the slot is here and
|
|
12
|
+
* the artwork is not, and the monogram means the fallback is never a blank
|
|
13
|
+
* square.
|
|
14
|
+
*/
|
|
15
|
+
readonly logo?: ReactNode;
|
|
16
|
+
readonly size?: "sm" | "md";
|
|
17
|
+
readonly className?: string;
|
|
18
|
+
};
|
|
19
|
+
/** Which service an action goes through. */
|
|
20
|
+
export declare function ProviderMark({ provider, logo, size, className }: ProviderMarkProps): import("react").JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* The provider marker for a tool call in a transcript.
|
|
23
|
+
*
|
|
24
|
+
* The provider is read off the tool id's `provider__operation` prefix — the
|
|
25
|
+
* same convention `toolLabel` uses — so a tool with no prefix is local and gets
|
|
26
|
+
* no marker rather than a guessed one.
|
|
27
|
+
*/
|
|
28
|
+
export declare function ToolProviderMark({ part, logo, className, }: {
|
|
29
|
+
part: ToolPart;
|
|
30
|
+
logo?: ReactNode;
|
|
31
|
+
className?: string;
|
|
32
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
const SIZE_CLASS = {
|
|
4
|
+
sm: "size-4 text-[8px]",
|
|
5
|
+
md: "size-6 text-[10px]"
|
|
6
|
+
};
|
|
7
|
+
/** Which service an action goes through. */ export function ProviderMark({ provider, logo, size = "sm", className }) {
|
|
8
|
+
const label = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
9
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
10
|
+
role: "img",
|
|
11
|
+
"aria-label": label,
|
|
12
|
+
title: label,
|
|
13
|
+
className: cn("inline-grid shrink-0 place-items-center overflow-hidden rounded-sm bg-muted font-semibold text-muted-foreground", SIZE_CLASS[size], className),
|
|
14
|
+
children: logo ?? provider.slice(0, 2).toUpperCase()
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The provider marker for a tool call in a transcript.
|
|
19
|
+
*
|
|
20
|
+
* The provider is read off the tool id's `provider__operation` prefix — the
|
|
21
|
+
* same convention `toolLabel` uses — so a tool with no prefix is local and gets
|
|
22
|
+
* no marker rather than a guessed one.
|
|
23
|
+
*/ export function ToolProviderMark({ part, logo, className }) {
|
|
24
|
+
const [provider, ...rest] = part.toolName.split("__");
|
|
25
|
+
if (rest.length === 0 || provider === undefined || provider === "") return null;
|
|
26
|
+
return /*#__PURE__*/ _jsx(ProviderMark, {
|
|
27
|
+
provider: provider,
|
|
28
|
+
logo: logo,
|
|
29
|
+
className: className
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { QuickReply } from "../lib/chat-message.js";
|
|
2
|
+
/**
|
|
3
|
+
* Suggested replies. A list, not a row of loose buttons, so a screen reader
|
|
4
|
+
* announces how many suggestions there are before reading them — otherwise the
|
|
5
|
+
* user has to arrow through to find out.
|
|
6
|
+
*
|
|
7
|
+
* Sending is the host's job: this reports which chip was chosen and lets the
|
|
8
|
+
* host decide whether that fills the composer or sends immediately.
|
|
9
|
+
*/
|
|
10
|
+
export declare function QuickReplyChips({ replies, onSelect, className, }: {
|
|
11
|
+
replies: readonly QuickReply[];
|
|
12
|
+
onSelect: (reply: QuickReply) => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* Suggested replies. A list, not a row of loose buttons, so a screen reader
|
|
5
|
+
* announces how many suggestions there are before reading them — otherwise the
|
|
6
|
+
* user has to arrow through to find out.
|
|
7
|
+
*
|
|
8
|
+
* Sending is the host's job: this reports which chip was chosen and lets the
|
|
9
|
+
* host decide whether that fills the composer or sends immediately.
|
|
10
|
+
*/ export function QuickReplyChips({ replies, onSelect, className }) {
|
|
11
|
+
if (replies.length === 0) return null;
|
|
12
|
+
return /*#__PURE__*/ _jsx("ul", {
|
|
13
|
+
"aria-label": "Suggested replies",
|
|
14
|
+
className: cn("flex flex-wrap gap-2", className),
|
|
15
|
+
children: replies.map((reply)=>/*#__PURE__*/ _jsx("li", {
|
|
16
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
17
|
+
type: "button",
|
|
18
|
+
onClick: ()=>onSelect(reply),
|
|
19
|
+
className: "rounded-full border border-border bg-muted px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-background hover:text-foreground",
|
|
20
|
+
children: reply.label
|
|
21
|
+
})
|
|
22
|
+
}, reply.id))
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type Quote = {
|
|
2
|
+
readonly text: string;
|
|
3
|
+
readonly author?: string;
|
|
4
|
+
};
|
|
5
|
+
export type QuoteCardProps = {
|
|
6
|
+
/** Yours. This registry ships no copy — a component with opinions about what
|
|
7
|
+
* your product says is a component you have to edit before you can use it. */
|
|
8
|
+
readonly quotes: readonly Quote[];
|
|
9
|
+
/**
|
|
10
|
+
* A key in `localStorage` for the last-shown index, so the card advances once
|
|
11
|
+
* per visit instead of showing the same line forever. Omit it and the card
|
|
12
|
+
* picks the first quote every time, which is the right behaviour when there
|
|
13
|
+
* is only one.
|
|
14
|
+
*/
|
|
15
|
+
readonly storageKey?: string;
|
|
16
|
+
readonly className?: string;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* A quote, rotated once per page load.
|
|
20
|
+
*
|
|
21
|
+
* Once per *load*, not on a timer. Text that swaps itself while someone is
|
|
22
|
+
* reading it is the pattern WCAG 2.2.2 exists to prohibit, and a marquee of
|
|
23
|
+
* clever lines on a sign-in page is exactly the case it had in mind. Advancing
|
|
24
|
+
* on load gives the same variety with none of that.
|
|
25
|
+
*
|
|
26
|
+
* The index is chosen during the initial `useState` and persisted in a mount
|
|
27
|
+
* effect, so the first paint already has its quote — deriving it in an effect
|
|
28
|
+
* would render quote zero and then swap it, which is the flicker this avoids.
|
|
29
|
+
*
|
|
30
|
+
* Every `localStorage` touch is wrapped: it throws outright in some private
|
|
31
|
+
* browsing modes, and a decorative card must not be able to take down the page
|
|
32
|
+
* it decorates. Losing the rotation is the correct failure — the card still
|
|
33
|
+
* renders, just from the top.
|
|
34
|
+
*
|
|
35
|
+
* `<blockquote>` and `<cite>`, because that is what this is. The quotation and
|
|
36
|
+
* its attribution are related in the markup rather than being two adjacent
|
|
37
|
+
* strings that happen to sit near each other.
|
|
38
|
+
*/
|
|
39
|
+
export declare function QuoteCard({ quotes, storageKey, className }: QuoteCardProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* A quote, rotated once per page load.
|
|
6
|
+
*
|
|
7
|
+
* Once per *load*, not on a timer. Text that swaps itself while someone is
|
|
8
|
+
* reading it is the pattern WCAG 2.2.2 exists to prohibit, and a marquee of
|
|
9
|
+
* clever lines on a sign-in page is exactly the case it had in mind. Advancing
|
|
10
|
+
* on load gives the same variety with none of that.
|
|
11
|
+
*
|
|
12
|
+
* The index is chosen during the initial `useState` and persisted in a mount
|
|
13
|
+
* effect, so the first paint already has its quote — deriving it in an effect
|
|
14
|
+
* would render quote zero and then swap it, which is the flicker this avoids.
|
|
15
|
+
*
|
|
16
|
+
* Every `localStorage` touch is wrapped: it throws outright in some private
|
|
17
|
+
* browsing modes, and a decorative card must not be able to take down the page
|
|
18
|
+
* it decorates. Losing the rotation is the correct failure — the card still
|
|
19
|
+
* renders, just from the top.
|
|
20
|
+
*
|
|
21
|
+
* `<blockquote>` and `<cite>`, because that is what this is. The quotation and
|
|
22
|
+
* its attribution are related in the markup rather than being two adjacent
|
|
23
|
+
* strings that happen to sit near each other.
|
|
24
|
+
*/ export function QuoteCard({ quotes, storageKey, className }) {
|
|
25
|
+
const [index] = useState(()=>{
|
|
26
|
+
if (storageKey === undefined || quotes.length === 0) return 0;
|
|
27
|
+
try {
|
|
28
|
+
const raw = window.localStorage.getItem(storageKey);
|
|
29
|
+
const parsed = raw === null ? -1 : Number.parseInt(raw, 10);
|
|
30
|
+
const last = Number.isInteger(parsed) && parsed >= 0 ? parsed : -1;
|
|
31
|
+
const next = (last + 1) % quotes.length;
|
|
32
|
+
window.localStorage.setItem(storageKey, String(next));
|
|
33
|
+
return next;
|
|
34
|
+
} catch {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const quote = quotes[index % Math.max(quotes.length, 1)];
|
|
39
|
+
if (quote === undefined) return null;
|
|
40
|
+
return /*#__PURE__*/ _jsxs("figure", {
|
|
41
|
+
className: cn("w-full max-w-xs rounded-xl border border-border bg-card/90 p-6 backdrop-blur-sm", className),
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ _jsxs("blockquote", {
|
|
44
|
+
className: "text-base leading-relaxed whitespace-pre-line text-card-foreground",
|
|
45
|
+
children: [
|
|
46
|
+
"“",
|
|
47
|
+
quote.text,
|
|
48
|
+
"”"
|
|
49
|
+
]
|
|
50
|
+
}),
|
|
51
|
+
quote.author === undefined ? null : /*#__PURE__*/ _jsxs("figcaption", {
|
|
52
|
+
className: "mt-4 flex items-center gap-3",
|
|
53
|
+
children: [
|
|
54
|
+
/*#__PURE__*/ _jsx("span", {
|
|
55
|
+
"aria-hidden": true,
|
|
56
|
+
className: "h-px flex-1 bg-border"
|
|
57
|
+
}),
|
|
58
|
+
/*#__PURE__*/ _jsx("cite", {
|
|
59
|
+
className: "text-xs text-muted-foreground not-italic",
|
|
60
|
+
children: quote.author
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type ReasoningBlockProps = {
|
|
2
|
+
/** The agent's thinking. Rendered as text — it is not markup. */
|
|
3
|
+
readonly text: string;
|
|
4
|
+
/** Still streaming. Changes the summary wording and marks the body busy. */
|
|
5
|
+
readonly streaming?: boolean;
|
|
6
|
+
/** Summary while streaming. Defaults to "Thinking…". */
|
|
7
|
+
readonly streamingLabel?: string;
|
|
8
|
+
/** Summary once idle when no `durationLabel` is supplied. Defaults to "Thinking". */
|
|
9
|
+
readonly idleLabel?: string;
|
|
10
|
+
/** e.g. "Thought for 4s". Becomes the summary once reasoning has stopped streaming. */
|
|
11
|
+
readonly durationLabel?: string;
|
|
12
|
+
readonly defaultOpen?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Controlled open state. Pair with `onOpenChange` to lift it to a parent —
|
|
15
|
+
* and honor it: a controlled `<details>` that ignores `onOpenChange` leaves
|
|
16
|
+
* the DOM attribute and React state diverged (the browser mutates `open`
|
|
17
|
+
* without React's knowledge), so the block can sit visibly open while the
|
|
18
|
+
* prop says closed.
|
|
19
|
+
*/
|
|
20
|
+
readonly open?: boolean;
|
|
21
|
+
readonly onOpenChange?: (open: boolean) => void;
|
|
22
|
+
readonly className?: string;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The agent's thinking, folded away.
|
|
26
|
+
*
|
|
27
|
+
* Collapsed by default, including while streaming: reasoning is context for a
|
|
28
|
+
* reader who wants it and noise for one who does not, and a block that
|
|
29
|
+
* expands itself mid-stream makes the transcript jump under the reader.
|
|
30
|
+
*
|
|
31
|
+
* A native `<details>`, not a div with state: it gets the disclosure
|
|
32
|
+
* semantics, keyboard behaviour and find-in-page expansion from the browser,
|
|
33
|
+
* and those are three things a hand-rolled version gets wrong.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ReasoningBlock({ text, streaming, streamingLabel, idleLabel, durationLabel, defaultOpen, open: openProp, onOpenChange, className, }: ReasoningBlockProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronRight } from "lucide-react";
|
|
3
|
+
import { useControllableState } from "../hooks/use-controllable-state.js";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
/**
|
|
6
|
+
* The agent's thinking, folded away.
|
|
7
|
+
*
|
|
8
|
+
* Collapsed by default, including while streaming: reasoning is context for a
|
|
9
|
+
* reader who wants it and noise for one who does not, and a block that
|
|
10
|
+
* expands itself mid-stream makes the transcript jump under the reader.
|
|
11
|
+
*
|
|
12
|
+
* A native `<details>`, not a div with state: it gets the disclosure
|
|
13
|
+
* semantics, keyboard behaviour and find-in-page expansion from the browser,
|
|
14
|
+
* and those are three things a hand-rolled version gets wrong.
|
|
15
|
+
*/ export function ReasoningBlock({ text, streaming = false, streamingLabel = "Thinking…", idleLabel = "Thinking", durationLabel, defaultOpen = false, open: openProp, onOpenChange, className }) {
|
|
16
|
+
const [open, setOpen] = useControllableState({
|
|
17
|
+
value: openProp,
|
|
18
|
+
defaultValue: defaultOpen,
|
|
19
|
+
onChange: onOpenChange,
|
|
20
|
+
name: "ReasoningBlock"
|
|
21
|
+
});
|
|
22
|
+
if (text.trim().length === 0) return null;
|
|
23
|
+
const summary = streaming ? streamingLabel : durationLabel ?? idleLabel;
|
|
24
|
+
return /*#__PURE__*/ _jsxs("details", {
|
|
25
|
+
"data-slot": "reasoning-block",
|
|
26
|
+
open: open,
|
|
27
|
+
// The browser fires `toggle` for any `open` attribute change — prop-driven
|
|
28
|
+
// ones included — so a bare setOpen would echo the parent's own commands
|
|
29
|
+
// back through onOpenChange. Reporting only divergence means exactly one
|
|
30
|
+
// callback per user activation, and none when a parent drives `open`.
|
|
31
|
+
onToggle: (event)=>{
|
|
32
|
+
const domOpen = event.currentTarget.open;
|
|
33
|
+
if (domOpen !== open) setOpen(domOpen);
|
|
34
|
+
},
|
|
35
|
+
className: cn("text-xs", className),
|
|
36
|
+
children: [
|
|
37
|
+
/*#__PURE__*/ _jsxs("summary", {
|
|
38
|
+
className: cn(// `relative` plus the `::after` pseudo-element extends the
|
|
39
|
+
// effective hit area to 40px tall without changing the row's own
|
|
40
|
+
// padding/density — see design-engineering.md's hit-area pattern.
|
|
41
|
+
"relative flex cursor-pointer list-none items-center gap-1.5 rounded-md px-2 py-1.5 text-muted-foreground transition-colors after:absolute after:inset-x-0 after:top-1/2 after:h-10 after:-translate-y-1/2 hover:bg-muted hover:text-foreground", "[&::-webkit-details-marker]:hidden"),
|
|
42
|
+
children: [
|
|
43
|
+
/*#__PURE__*/ _jsx(ChevronRight, {
|
|
44
|
+
className: cn("size-3.5 shrink-0 transition-transform duration-200 ease-out", open && "rotate-90"),
|
|
45
|
+
"aria-hidden": true
|
|
46
|
+
}),
|
|
47
|
+
/*#__PURE__*/ _jsx("span", {
|
|
48
|
+
"aria-live": "polite",
|
|
49
|
+
children: summary
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
}),
|
|
53
|
+
/*#__PURE__*/ _jsx("p", {
|
|
54
|
+
"aria-busy": streaming,
|
|
55
|
+
className: "mt-1 ml-4 border-l border-border pl-3 leading-relaxed whitespace-pre-wrap text-muted-foreground [animation:corbits-rail-block-in_200ms_var(--ease-out)_both]",
|
|
56
|
+
children: text
|
|
57
|
+
}, open ? "open" : "closed")
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type ResearchSource = {
|
|
2
|
+
readonly url: string;
|
|
3
|
+
readonly title?: string;
|
|
4
|
+
/** Where it came from — a publication, a forum, a feed name. */
|
|
5
|
+
readonly source: string;
|
|
6
|
+
};
|
|
7
|
+
export type ResearchCluster = {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly summary?: string;
|
|
11
|
+
/** Source names this cluster drew on. */
|
|
12
|
+
readonly sources?: readonly string[];
|
|
13
|
+
readonly items?: readonly ResearchSource[];
|
|
14
|
+
};
|
|
15
|
+
export type ResearchQuote = {
|
|
16
|
+
readonly quote: string;
|
|
17
|
+
readonly author?: string;
|
|
18
|
+
readonly source: string;
|
|
19
|
+
readonly url?: string;
|
|
20
|
+
};
|
|
21
|
+
export type ResearchBrief = {
|
|
22
|
+
readonly topic: string;
|
|
23
|
+
readonly sourceCount: number;
|
|
24
|
+
readonly itemCount: number;
|
|
25
|
+
/** Human-readable coverage window, e.g. "Jan 1 – Mar 31". Pre-formatted. */
|
|
26
|
+
readonly range?: string;
|
|
27
|
+
/** The one sentence someone reads if they read nothing else. */
|
|
28
|
+
readonly leadInsight?: string;
|
|
29
|
+
readonly clusters?: readonly ResearchCluster[];
|
|
30
|
+
readonly quotes?: readonly ResearchQuote[];
|
|
31
|
+
readonly citations?: readonly ResearchSource[];
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Reads a brief (and its optional prose report) out of an artifact payload.
|
|
35
|
+
*
|
|
36
|
+
* Checks only `topic` and the two counts — the fields the header renders
|
|
37
|
+
* unconditionally and the ones whose absence would print "undefined sources".
|
|
38
|
+
* Everything below the header is already guarded by a presence check at its own
|
|
39
|
+
* render site, so validating it here would only reject briefs this component
|
|
40
|
+
* draws correctly.
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseResearchArtifact(json: string): {
|
|
43
|
+
brief: ResearchBrief;
|
|
44
|
+
body?: string;
|
|
45
|
+
} | null;
|
|
46
|
+
/**
|
|
47
|
+
* A structured research brief: what was found, grouped, quoted and cited.
|
|
48
|
+
*
|
|
49
|
+
* The layout is an argument in order — headline stat line, the lead insight,
|
|
50
|
+
* then clusters, then evidence, then citations. A reader who stops after the
|
|
51
|
+
* first screen should still have the finding; a reader who wants to audit it
|
|
52
|
+
* can walk down to the sources without leaving the page.
|
|
53
|
+
*
|
|
54
|
+
* `body` is the prose report when the producer wrote one. Given both, the prose
|
|
55
|
+
* is the deliverable and the structured data becomes supporting evidence behind
|
|
56
|
+
* a `<details>` — collapsed rather than removed, because "show me your working"
|
|
57
|
+
* is the second question every reader of a generated report asks. `<details>` is
|
|
58
|
+
* a native disclosure: keyboard-operable and announced as expandable with no JS
|
|
59
|
+
* and no ARIA of our own.
|
|
60
|
+
*
|
|
61
|
+
* Prose is rendered as pre-wrapped text, not parsed as Markdown. The registry
|
|
62
|
+
* ships no Markdown dependency, and adding ~40kB of parser that a consumer then
|
|
63
|
+
* owns is not something a component should decide on their behalf. Wrap the
|
|
64
|
+
* `body` slot in your own renderer if you have one.
|
|
65
|
+
*/
|
|
66
|
+
export declare function ResearchBody({ brief, body, className, }: {
|
|
67
|
+
readonly brief: ResearchBrief;
|
|
68
|
+
readonly body?: string;
|
|
69
|
+
readonly className?: string;
|
|
70
|
+
}): import("react").JSX.Element;
|