@corbits/react-ui 0.1.0 → 0.3.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 +257 -19
- package/dist/test/render-hook.js +11 -12
- package/dist/theme.css +92 -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 +21 -4
- package/dist/ui/avatar.js +40 -49
- 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 +85 -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 +96 -535
package/dist/ui/profile-card.js
CHANGED
|
@@ -8,117 +8,13 @@ import { Button } from "./button.js";
|
|
|
8
8
|
* Canvas profile card: hero identity, status, action chips, shared
|
|
9
9
|
* channels, and pinned skills. Deep-links are plain hrefs so the host
|
|
10
10
|
* router owns navigation.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
className: cn("flex flex-col gap-4 border border-border bg-card p-4", className),
|
|
15
|
-
children: [
|
|
16
|
-
/*#__PURE__*/ _jsxs("header", {
|
|
17
|
-
className: "flex items-start gap-3",
|
|
18
|
-
children: [
|
|
19
|
-
/*#__PURE__*/ _jsx(Avatar, {
|
|
20
|
-
initials: initials,
|
|
21
|
-
label: name,
|
|
22
|
-
tone: avatarTone,
|
|
23
|
-
size: "lg",
|
|
24
|
-
...tenantMonogram === undefined ? {} : {
|
|
25
|
-
tenantMonogram
|
|
26
|
-
}
|
|
27
|
-
}),
|
|
28
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
29
|
-
className: "min-w-0 flex-1",
|
|
30
|
-
children: [
|
|
31
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
32
|
-
className: "flex flex-wrap items-center gap-2",
|
|
33
|
-
children: [
|
|
34
|
-
/*#__PURE__*/ _jsx("h2", {
|
|
35
|
-
className: "truncate text-base font-semibold",
|
|
36
|
-
children: name
|
|
37
|
-
}),
|
|
38
|
-
statusLabel === undefined ? null : /*#__PURE__*/ _jsx(Badge, {
|
|
39
|
-
tone: statusTone,
|
|
40
|
-
children: statusLabel
|
|
41
|
-
})
|
|
42
|
-
]
|
|
43
|
-
}),
|
|
44
|
-
subtitle === undefined ? null : /*#__PURE__*/ _jsx("p", {
|
|
45
|
-
className: "truncate text-xs text-muted-foreground",
|
|
46
|
-
children: subtitle
|
|
47
|
-
})
|
|
48
|
-
]
|
|
49
|
-
})
|
|
50
|
-
]
|
|
51
|
-
}),
|
|
52
|
-
actions.length === 0 ? null : /*#__PURE__*/ _jsx("div", {
|
|
53
|
-
className: "flex flex-wrap gap-1.5",
|
|
54
|
-
children: actions.map((action)=>/*#__PURE__*/ _jsx(Button, {
|
|
55
|
-
type: "button",
|
|
56
|
-
size: "sm",
|
|
57
|
-
variant: action.tone === "primary" ? "primary" : "outline",
|
|
58
|
-
onClick: action.onClick,
|
|
59
|
-
children: action.label
|
|
60
|
-
}, action.id))
|
|
61
|
-
}),
|
|
62
|
-
sharedChannels.length === 0 ? null : /*#__PURE__*/ _jsxs("section", {
|
|
63
|
-
className: "flex flex-col gap-1.5",
|
|
64
|
-
children: [
|
|
65
|
-
/*#__PURE__*/ _jsx("h3", {
|
|
66
|
-
className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground",
|
|
67
|
-
children: "Shared channels"
|
|
68
|
-
}),
|
|
69
|
-
/*#__PURE__*/ _jsx("ul", {
|
|
70
|
-
className: "flex flex-col gap-1",
|
|
71
|
-
children: sharedChannels.map((channel)=>{
|
|
11
|
+
*/
|
|
12
|
+
export function ProfileCard({ name, initials, subtitle, statusLabel, statusTone = "neutral", avatarTone = "neutral", tenantMonogram, actions = [], sharedChannels = [], pinnedSkills = [], footer, className, }) {
|
|
13
|
+
return (_jsxs("article", { "data-slot": "profile-card", className: cn("flex flex-col gap-4 border border-border bg-card p-4", className), children: [_jsxs("header", { className: "flex items-start gap-3", children: [_jsx(Avatar, { initials: initials, label: name, tone: avatarTone, size: "lg", ...(tenantMonogram === undefined ? {} : { tenantMonogram }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h2", { className: "truncate text-base font-semibold", children: name }), statusLabel === undefined ? null : (_jsx(Badge, { tone: statusTone, children: statusLabel }))] }), subtitle === undefined ? null : (_jsx("p", { className: "truncate text-xs text-muted-foreground", children: subtitle }))] })] }), actions.length === 0 ? null : (_jsx("div", { className: "flex flex-wrap gap-1.5", children: actions.map((action) => (_jsx(Button, { type: "button", size: "sm", variant: action.tone === "primary" ? "primary" : "outline", onClick: action.onClick, children: action.label }, action.id))) })), sharedChannels.length === 0 ? null : (_jsxs("section", { className: "flex flex-col gap-1.5", children: [_jsx("h3", { className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground", children: "Shared channels" }), _jsx("ul", { className: "flex flex-col gap-1", children: sharedChannels.map((channel) => {
|
|
72
14
|
const href = toSafeHref(channel.href);
|
|
73
|
-
return
|
|
74
|
-
|
|
75
|
-
className: "text-sm",
|
|
76
|
-
children: [
|
|
77
|
-
"#",
|
|
78
|
-
channel.name
|
|
79
|
-
]
|
|
80
|
-
}) : /*#__PURE__*/ _jsxs("a", {
|
|
81
|
-
href: href,
|
|
82
|
-
className: "text-sm text-foreground hover:underline",
|
|
83
|
-
children: [
|
|
84
|
-
"#",
|
|
85
|
-
channel.name
|
|
86
|
-
]
|
|
87
|
-
})
|
|
88
|
-
}, channel.id);
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
]
|
|
92
|
-
}),
|
|
93
|
-
pinnedSkills.length === 0 ? null : /*#__PURE__*/ _jsxs("section", {
|
|
94
|
-
className: "flex flex-col gap-1.5",
|
|
95
|
-
children: [
|
|
96
|
-
/*#__PURE__*/ _jsx("h3", {
|
|
97
|
-
className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground",
|
|
98
|
-
children: "Pinned skills"
|
|
99
|
-
}),
|
|
100
|
-
/*#__PURE__*/ _jsx("ul", {
|
|
101
|
-
className: "flex flex-wrap gap-1.5",
|
|
102
|
-
children: pinnedSkills.map((skill)=>{
|
|
15
|
+
return (_jsx("li", { children: href === undefined ? (_jsxs("span", { className: "text-sm", children: ["#", channel.name] })) : (_jsxs("a", { href: href, className: "text-sm text-foreground hover:underline", children: ["#", channel.name] })) }, channel.id));
|
|
16
|
+
}) })] })), pinnedSkills.length === 0 ? null : (_jsxs("section", { className: "flex flex-col gap-1.5", children: [_jsx("h3", { className: "text-[10.5px] font-bold uppercase tracking-[0.06em] text-muted-foreground", children: "Pinned skills" }), _jsx("ul", { className: "flex flex-wrap gap-1.5", children: pinnedSkills.map((skill) => {
|
|
103
17
|
const href = toSafeHref(skill.href);
|
|
104
|
-
return href === undefined ?
|
|
105
|
-
|
|
106
|
-
children: skill.name
|
|
107
|
-
}, skill.id) : /*#__PURE__*/ _jsx("a", {
|
|
108
|
-
href: href,
|
|
109
|
-
children: /*#__PURE__*/ _jsx(Badge, {
|
|
110
|
-
tone: "neutral",
|
|
111
|
-
children: skill.name
|
|
112
|
-
})
|
|
113
|
-
}, skill.id);
|
|
114
|
-
})
|
|
115
|
-
})
|
|
116
|
-
]
|
|
117
|
-
}),
|
|
118
|
-
footer === undefined ? null : /*#__PURE__*/ _jsx("footer", {
|
|
119
|
-
className: "border-t border-border pt-3",
|
|
120
|
-
children: footer
|
|
121
|
-
})
|
|
122
|
-
]
|
|
123
|
-
});
|
|
18
|
+
return href === undefined ? (_jsx(Badge, { tone: "neutral", children: skill.name }, skill.id)) : (_jsx("a", { href: href, children: _jsx(Badge, { tone: "neutral", children: skill.name }) }, skill.id));
|
|
19
|
+
}) })] })), footer === undefined ? null : (_jsx("footer", { className: "border-t border-border pt-3", children: footer }))] }));
|
|
124
20
|
}
|
|
@@ -6,7 +6,7 @@ const STATUS_LABEL = {
|
|
|
6
6
|
pending: "Not started",
|
|
7
7
|
running: "In progress",
|
|
8
8
|
done: "Done",
|
|
9
|
-
failed: "Failed"
|
|
9
|
+
failed: "Failed",
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* A list of steps and how far along they are — a long operation reporting
|
|
@@ -19,52 +19,14 @@ const STATUS_LABEL = {
|
|
|
19
19
|
*
|
|
20
20
|
* The whole list is `aria-live="polite"`, so steps completing are announced as
|
|
21
21
|
* they happen without stealing focus from wherever the user actually is.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
});
|
|
22
|
+
*/
|
|
23
|
+
export function ProgressChecklist({ steps, label = "Progress", className, }) {
|
|
24
|
+
if (steps.length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
return (_jsx("ol", { "aria-label": label, "aria-live": "polite", className: cn("flex flex-col gap-2.5", className), children: steps.map((step, index) => (_jsxs("li", { className: "flex items-start gap-3", children: [_jsx("span", { "aria-hidden": true, className: cn("mt-0.5 grid size-5 shrink-0 place-items-center rounded-full border text-[10px] font-semibold", step.status === "done" &&
|
|
27
|
+
"border-transparent bg-success text-success-foreground", step.status === "failed" &&
|
|
28
|
+
"border-transparent bg-destructive text-destructive-foreground", step.status === "running" &&
|
|
29
|
+
"border-primary-emphasis text-primary-emphasis", step.status === "pending" && "border-input text-muted-foreground"), children: step.status === "done" ? (_jsx(Check, { className: "size-3" })) : step.status === "failed" ? (_jsx(X, { className: "size-3" })) : step.status === "running" ? (_jsx(StatusDot, { label: "", live: true, tone: "emphasis" })) : (index + 1) }), _jsxs("div", { className: "flex min-w-0 flex-col gap-0.5", children: [_jsxs("p", { className: cn("text-sm leading-snug", step.status === "pending"
|
|
30
|
+
? "text-muted-foreground"
|
|
31
|
+
: "text-foreground"), children: [step.label, " ", _jsxs("span", { className: "text-xs text-muted-foreground", children: ["\u00B7 ", STATUS_LABEL[step.status]] })] }), step.detail === undefined ? null : (_jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: step.detail }))] })] }, step.id))) }));
|
|
70
32
|
}
|
|
@@ -14,10 +14,10 @@ export type ProviderMarkProps = {
|
|
|
14
14
|
*/
|
|
15
15
|
readonly logo?: ReactNode;
|
|
16
16
|
readonly size?: "sm" | "md";
|
|
17
|
-
readonly className?: string;
|
|
17
|
+
readonly className?: string | undefined;
|
|
18
18
|
};
|
|
19
19
|
/** Which service an action goes through. */
|
|
20
|
-
export declare function ProviderMark({ provider, logo, size, className }: ProviderMarkProps): import("react").JSX.Element;
|
|
20
|
+
export declare function ProviderMark({ provider, logo, size, className, }: ProviderMarkProps): import("react").JSX.Element;
|
|
21
21
|
/**
|
|
22
22
|
* The provider marker for a tool call in a transcript.
|
|
23
23
|
*
|
package/dist/ui/provider-mark.js
CHANGED
|
@@ -2,17 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
3
|
const SIZE_CLASS = {
|
|
4
4
|
sm: "size-4 text-[8px]",
|
|
5
|
-
md: "size-6 text-[10px]"
|
|
5
|
+
md: "size-6 text-[10px]",
|
|
6
6
|
};
|
|
7
|
-
/** Which service an action goes through. */
|
|
7
|
+
/** Which service an action goes through. */
|
|
8
|
+
export function ProviderMark({ provider, logo, size = "sm", className, }) {
|
|
8
9
|
const label = provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
9
|
-
return
|
|
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
|
-
});
|
|
10
|
+
return (_jsx("span", { role: "img", "aria-label": label, title: label, className: cn("inline-grid shrink-0 place-items-center overflow-hidden rounded-sm bg-muted font-semibold text-muted-foreground", SIZE_CLASS[size], className), children: logo ?? provider.slice(0, 2).toUpperCase() }));
|
|
16
11
|
}
|
|
17
12
|
/**
|
|
18
13
|
* The provider marker for a tool call in a transcript.
|
|
@@ -20,12 +15,10 @@ const SIZE_CLASS = {
|
|
|
20
15
|
* The provider is read off the tool id's `provider__operation` prefix — the
|
|
21
16
|
* same convention `toolLabel` uses — so a tool with no prefix is local and gets
|
|
22
17
|
* no marker rather than a guessed one.
|
|
23
|
-
*/
|
|
18
|
+
*/
|
|
19
|
+
export function ToolProviderMark({ part, logo, className, }) {
|
|
24
20
|
const [provider, ...rest] = part.toolName.split("__");
|
|
25
|
-
if (rest.length === 0 || provider === undefined || provider === "")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
logo: logo,
|
|
29
|
-
className: className
|
|
30
|
-
});
|
|
21
|
+
if (rest.length === 0 || provider === undefined || provider === "")
|
|
22
|
+
return null;
|
|
23
|
+
return _jsx(ProviderMark, { provider: provider, logo: logo, className: className });
|
|
31
24
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
3
4
|
/**
|
|
@@ -7,18 +8,9 @@ import { cn } from "../lib/utils.js";
|
|
|
7
8
|
*
|
|
8
9
|
* Sending is the host's job: this reports which chip was chosen and lets the
|
|
9
10
|
* host decide whether that fills the composer or sends immediately.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
});
|
|
11
|
+
*/
|
|
12
|
+
export function QuickReplyChips({ replies, onSelect, className, }) {
|
|
13
|
+
if (replies.length === 0)
|
|
14
|
+
return null;
|
|
15
|
+
return (_jsx("ul", { "aria-label": "Suggested replies", className: cn("flex flex-wrap gap-2", className), children: replies.map((reply) => (_jsx("li", { children: _jsx("button", { type: "button", onClick: () => onSelect(reply), 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", children: reply.label }) }, reply.id))) }));
|
|
24
16
|
}
|
package/dist/ui/quote-card.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { useState } from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
/**
|
|
@@ -21,9 +22,11 @@ import { cn } from "../lib/utils.js";
|
|
|
21
22
|
* `<blockquote>` and `<cite>`, because that is what this is. The quotation and
|
|
22
23
|
* its attribution are related in the markup rather than being two adjacent
|
|
23
24
|
* strings that happen to sit near each other.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
*/
|
|
26
|
+
export function QuoteCard({ quotes, storageKey, className }) {
|
|
27
|
+
const [index] = useState(() => {
|
|
28
|
+
if (storageKey === undefined || quotes.length === 0)
|
|
29
|
+
return 0;
|
|
27
30
|
try {
|
|
28
31
|
const raw = window.localStorage.getItem(storageKey);
|
|
29
32
|
const parsed = raw === null ? -1 : Number.parseInt(raw, 10);
|
|
@@ -31,36 +34,13 @@ import { cn } from "../lib/utils.js";
|
|
|
31
34
|
const next = (last + 1) % quotes.length;
|
|
32
35
|
window.localStorage.setItem(storageKey, String(next));
|
|
33
36
|
return next;
|
|
34
|
-
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
35
39
|
return 0;
|
|
36
40
|
}
|
|
37
41
|
});
|
|
38
42
|
const quote = quotes[index % Math.max(quotes.length, 1)];
|
|
39
|
-
if (quote === undefined)
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
});
|
|
43
|
+
if (quote === undefined)
|
|
44
|
+
return null;
|
|
45
|
+
return (_jsxs("figure", { className: cn("w-full max-w-xs rounded-xl border border-border bg-card/90 p-6 backdrop-blur-sm", className), children: [_jsxs("blockquote", { className: "text-base leading-relaxed whitespace-pre-line text-card-foreground", children: ["\u201C", quote.text, "\u201D"] }), quote.author === undefined ? null : (_jsxs("figcaption", { className: "mt-4 flex items-center gap-3", children: [_jsx("span", { "aria-hidden": true, className: "h-px flex-1 bg-border" }), _jsx("cite", { className: "text-xs text-muted-foreground not-italic", children: quote.author })] }))] }));
|
|
66
46
|
}
|
|
@@ -8,7 +8,7 @@ export type ReasoningBlockProps = {
|
|
|
8
8
|
/** Summary once idle when no `durationLabel` is supplied. Defaults to "Thinking". */
|
|
9
9
|
readonly idleLabel?: string;
|
|
10
10
|
/** e.g. "Thought for 4s". Becomes the summary once reasoning has stopped streaming. */
|
|
11
|
-
readonly durationLabel?: string;
|
|
11
|
+
readonly durationLabel?: string | undefined;
|
|
12
12
|
readonly defaultOpen?: boolean;
|
|
13
13
|
/**
|
|
14
14
|
* Controlled open state. Pair with `onOpenChange` to lift it to a parent —
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { ChevronRight } from "lucide-react";
|
|
3
4
|
import { useControllableState } from "../hooks/use-controllable-state.js";
|
|
@@ -12,49 +13,29 @@ import { cn } from "../lib/utils.js";
|
|
|
12
13
|
* A native `<details>`, not a div with state: it gets the disclosure
|
|
13
14
|
* semantics, keyboard behaviour and find-in-page expansion from the browser,
|
|
14
15
|
* and those are three things a hand-rolled version gets wrong.
|
|
15
|
-
*/
|
|
16
|
+
*/
|
|
17
|
+
export function ReasoningBlock({ text, streaming = false, streamingLabel = "Thinking…", idleLabel = "Thinking", durationLabel, defaultOpen = false, open: openProp, onOpenChange, className, }) {
|
|
16
18
|
const [open, setOpen] = useControllableState({
|
|
17
19
|
value: openProp,
|
|
18
20
|
defaultValue: defaultOpen,
|
|
19
21
|
onChange: onOpenChange,
|
|
20
|
-
name: "ReasoningBlock"
|
|
22
|
+
name: "ReasoningBlock",
|
|
21
23
|
});
|
|
22
|
-
if (text.trim().length === 0)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
open: open,
|
|
24
|
+
if (text.trim().length === 0)
|
|
25
|
+
return null;
|
|
26
|
+
const summary = streaming ? streamingLabel : (durationLabel ?? idleLabel);
|
|
27
|
+
return (_jsxs("details", { "data-slot": "reasoning-block", open: open,
|
|
27
28
|
// The browser fires `toggle` for any `open` attribute change — prop-driven
|
|
28
29
|
// ones included — so a bare setOpen would echo the parent's own commands
|
|
29
30
|
// back through onOpenChange. Reporting only divergence means exactly one
|
|
30
31
|
// callback per user activation, and none when a parent drives `open`.
|
|
31
|
-
onToggle: (event)=>{
|
|
32
|
+
onToggle: (event) => {
|
|
32
33
|
const domOpen = event.currentTarget.open;
|
|
33
|
-
if (domOpen !== open)
|
|
34
|
-
|
|
35
|
-
className: cn("text-xs", className),
|
|
36
|
-
|
|
37
|
-
/*#__PURE__*/ _jsxs("summary", {
|
|
38
|
-
className: cn(// `relative` plus the `::after` pseudo-element extends the
|
|
34
|
+
if (domOpen !== open)
|
|
35
|
+
setOpen(domOpen);
|
|
36
|
+
}, className: cn("text-xs", className), children: [_jsxs("summary", { className: cn(
|
|
37
|
+
// `relative` plus the `::after` pseudo-element extends the
|
|
39
38
|
// effective hit area to 40px tall without changing the row's own
|
|
40
39
|
// 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
|
-
});
|
|
40
|
+
"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"), children: [_jsx(ChevronRight, { className: cn("size-3.5 shrink-0 transition-transform duration-200 ease-out", open && "rotate-90"), "aria-hidden": true }), _jsx("span", { "aria-live": "polite", children: summary })] }), _jsx("p", { "aria-busy": streaming, 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]", children: text }, open ? "open" : "closed")] }));
|
|
60
41
|
}
|