@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/chat-input.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { ArrowUp, Paperclip, Square, X } from "lucide-react";
|
|
3
4
|
import { useEffect, useRef } from "react";
|
|
@@ -18,121 +19,40 @@ const MAX_ROWS_PX = 200;
|
|
|
18
19
|
* The textarea grows with its content up to a cap, then scrolls. It is measured
|
|
19
20
|
* rather than counted in rows, because a wrapped long line takes more height
|
|
20
21
|
* than its newline count implies.
|
|
21
|
-
*/
|
|
22
|
+
*/
|
|
23
|
+
export function ChatInput({ value, onValueChange, onSend, onStop, working = false, placeholder = "Send a message…", disabled = false, attachments = [], onAttach, onRemoveAttachment, textareaRef: externalTextareaRef, className, }) {
|
|
22
24
|
const internalTextareaRef = useRef(null);
|
|
23
25
|
const textareaRef = externalTextareaRef ?? internalTextareaRef;
|
|
24
26
|
const fileRef = useRef(null);
|
|
25
|
-
useEffect(()=>{
|
|
27
|
+
useEffect(() => {
|
|
26
28
|
const node = textareaRef.current;
|
|
27
|
-
if (node === null)
|
|
29
|
+
if (node === null)
|
|
30
|
+
return;
|
|
28
31
|
node.style.height = "auto";
|
|
29
32
|
node.style.height = `${Math.min(node.scrollHeight, MAX_ROWS_PX)}px`;
|
|
30
|
-
}, [
|
|
31
|
-
value
|
|
32
|
-
]);
|
|
33
|
+
}, [value]);
|
|
33
34
|
const canSend = value.trim().length > 0 && !disabled;
|
|
34
35
|
const showStop = working && onStop !== undefined;
|
|
35
|
-
const submit = ()=>{
|
|
36
|
-
if (!canSend)
|
|
36
|
+
const submit = () => {
|
|
37
|
+
if (!canSend)
|
|
38
|
+
return;
|
|
37
39
|
onSend();
|
|
38
40
|
};
|
|
39
|
-
return
|
|
40
|
-
className: cn("flex flex-col gap-2 rounded-lg border border-input bg-background p-2", className),
|
|
41
|
-
onSubmit: (event)=>{
|
|
41
|
+
return (_jsxs("form", { className: cn("flex flex-col gap-2 rounded-lg border border-input bg-background p-2", className), onSubmit: (event) => {
|
|
42
42
|
event.preventDefault();
|
|
43
43
|
submit();
|
|
44
|
-
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"aria-label": "Attachments",
|
|
48
|
-
className: "flex flex-wrap gap-1.5",
|
|
49
|
-
children: attachments.map((attachment)=>/*#__PURE__*/ _jsxs("li", {
|
|
50
|
-
className: "flex items-center gap-1.5 rounded-md bg-muted py-1 pr-1 pl-2 text-xs",
|
|
51
|
-
children: [
|
|
52
|
-
/*#__PURE__*/ _jsx("span", {
|
|
53
|
-
className: "max-w-40 truncate",
|
|
54
|
-
children: attachment.name
|
|
55
|
-
}),
|
|
56
|
-
onRemoveAttachment === undefined ? null : /*#__PURE__*/ _jsx("button", {
|
|
57
|
-
type: "button",
|
|
58
|
-
onClick: ()=>onRemoveAttachment(attachment),
|
|
59
|
-
"aria-label": `Remove ${attachment.name}`,
|
|
60
|
-
className: "grid size-5 place-items-center rounded-sm text-muted-foreground hover:text-foreground",
|
|
61
|
-
children: /*#__PURE__*/ _jsx(X, {
|
|
62
|
-
className: "size-3",
|
|
63
|
-
"aria-hidden": true
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
]
|
|
67
|
-
}, attachment.id))
|
|
68
|
-
}),
|
|
69
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
70
|
-
className: "flex items-end gap-2",
|
|
71
|
-
children: [
|
|
72
|
-
onAttach === undefined ? null : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
73
|
-
children: [
|
|
74
|
-
/*#__PURE__*/ _jsx("input", {
|
|
75
|
-
ref: fileRef,
|
|
76
|
-
type: "file",
|
|
77
|
-
multiple: true,
|
|
78
|
-
className: "sr-only",
|
|
79
|
-
onChange: (event)=>{
|
|
80
|
-
if (event.target.files !== null) onAttach(event.target.files);
|
|
44
|
+
}, children: [attachments.length === 0 ? null : (_jsx("ul", { "aria-label": "Attachments", className: "flex flex-wrap gap-1.5", children: attachments.map((attachment) => (_jsxs("li", { className: "flex items-center gap-1.5 rounded-md bg-muted py-1 pr-1 pl-2 text-xs", children: [_jsx("span", { className: "max-w-40 truncate", children: attachment.name }), onRemoveAttachment === undefined ? null : (_jsx("button", { type: "button", onClick: () => onRemoveAttachment(attachment), "aria-label": `Remove ${attachment.name}`, className: "grid size-5 place-items-center rounded-sm text-muted-foreground hover:text-foreground", children: _jsx(X, { className: "size-3", "aria-hidden": true }) }))] }, attachment.id))) })), _jsxs("div", { className: "flex items-end gap-2", children: [onAttach === undefined ? null : (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileRef, type: "file", multiple: true, className: "sr-only", onChange: (event) => {
|
|
45
|
+
if (event.target.files !== null)
|
|
46
|
+
onAttach(event.target.files);
|
|
81
47
|
event.target.value = "";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
type: "button",
|
|
86
|
-
onClick: ()=>fileRef.current?.click(),
|
|
87
|
-
disabled: disabled,
|
|
88
|
-
"aria-label": "Attach files",
|
|
89
|
-
className: "grid size-9 shrink-0 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
90
|
-
children: /*#__PURE__*/ _jsx(Paperclip, {
|
|
91
|
-
className: "size-4",
|
|
92
|
-
"aria-hidden": true
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
]
|
|
96
|
-
}),
|
|
97
|
-
/*#__PURE__*/ _jsx("textarea", {
|
|
98
|
-
ref: textareaRef,
|
|
99
|
-
value: value,
|
|
100
|
-
rows: 1,
|
|
101
|
-
disabled: disabled,
|
|
102
|
-
placeholder: placeholder,
|
|
103
|
-
"aria-label": "Message",
|
|
104
|
-
onChange: (event)=>onValueChange(event.target.value),
|
|
105
|
-
onKeyDown: (event)=>{
|
|
106
|
-
if (event.key !== "Enter" || event.shiftKey) return;
|
|
48
|
+
} }), _jsx("button", { type: "button", onClick: () => fileRef.current?.click(), disabled: disabled, "aria-label": "Attach files", className: "grid size-9 shrink-0 place-items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50", children: _jsx(Paperclip, { className: "size-4", "aria-hidden": true }) })] })), _jsx("textarea", { ref: textareaRef, value: value, rows: 1, disabled: disabled, placeholder: placeholder, "aria-label": "Message", onChange: (event) => onValueChange(event.target.value), onKeyDown: (event) => {
|
|
49
|
+
if (event.key !== "Enter" || event.shiftKey)
|
|
50
|
+
return;
|
|
107
51
|
// `isComposing` is the IME guard — without it, committing a
|
|
108
52
|
// Japanese or Chinese candidate sends the message instead.
|
|
109
|
-
if (event.nativeEvent.isComposing)
|
|
53
|
+
if (event.nativeEvent.isComposing)
|
|
54
|
+
return;
|
|
110
55
|
event.preventDefault();
|
|
111
56
|
submit();
|
|
112
|
-
},
|
|
113
|
-
className: "max-h-50 min-h-9 flex-1 resize-none bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground disabled:opacity-50"
|
|
114
|
-
}),
|
|
115
|
-
showStop ? /*#__PURE__*/ _jsx("button", {
|
|
116
|
-
type: "button",
|
|
117
|
-
onClick: onStop,
|
|
118
|
-
"aria-label": "Stop generating",
|
|
119
|
-
className: "grid size-9 shrink-0 place-items-center rounded-md bg-muted text-foreground transition-colors hover:bg-secondary",
|
|
120
|
-
children: /*#__PURE__*/ _jsx(Square, {
|
|
121
|
-
className: "size-3.5 fill-current",
|
|
122
|
-
"aria-hidden": true
|
|
123
|
-
})
|
|
124
|
-
}) : /*#__PURE__*/ _jsx("button", {
|
|
125
|
-
type: "submit",
|
|
126
|
-
disabled: !canSend,
|
|
127
|
-
"aria-label": "Send message",
|
|
128
|
-
className: "grid size-9 shrink-0 place-items-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary-active disabled:opacity-40",
|
|
129
|
-
children: /*#__PURE__*/ _jsx(ArrowUp, {
|
|
130
|
-
className: "size-4",
|
|
131
|
-
"aria-hidden": true
|
|
132
|
-
})
|
|
133
|
-
})
|
|
134
|
-
]
|
|
135
|
-
})
|
|
136
|
-
]
|
|
137
|
-
});
|
|
57
|
+
}, className: "max-h-50 min-h-9 flex-1 resize-none bg-transparent py-2 text-sm outline-none placeholder:text-muted-foreground disabled:opacity-50" }), showStop ? (_jsx("button", { type: "button", onClick: onStop, "aria-label": "Stop generating", className: "grid size-9 shrink-0 place-items-center rounded-md bg-muted text-foreground transition-colors hover:bg-secondary", children: _jsx(Square, { className: "size-3.5 fill-current", "aria-hidden": true }) })) : (_jsx("button", { type: "submit", disabled: !canSend, "aria-label": "Send message", className: "grid size-9 shrink-0 place-items-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary-active disabled:opacity-40", children: _jsx(ArrowUp, { className: "size-4", "aria-hidden": true }) }))] })] }));
|
|
138
58
|
}
|
package/dist/ui/chat-panel.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare function ChatPanelHeader({ identity, children, className, ...prop
|
|
|
14
14
|
identity: AgentIdentity;
|
|
15
15
|
}): import("react").JSX.Element;
|
|
16
16
|
/** The composer area: quick replies, the input, anything else pinned to the bottom. */
|
|
17
|
-
export declare function ChatPanelFooter({ className, children }: {
|
|
17
|
+
export declare function ChatPanelFooter({ className, children, }: {
|
|
18
18
|
className?: string;
|
|
19
19
|
children: ReactNode;
|
|
20
20
|
}): import("react").JSX.Element;
|
package/dist/ui/chat-panel.js
CHANGED
|
@@ -9,48 +9,14 @@ import { cn } from "../lib/utils.js";
|
|
|
9
9
|
* frame carries a full-page conversation, a docked bar and a floating panel,
|
|
10
10
|
* and each wants something different in the header — a thread switcher here, a
|
|
11
11
|
* close button there. Composition is what makes one frame serve three shells.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
className: cn("flex min-h-0 flex-1 flex-col bg-background text-foreground", className),
|
|
16
|
-
...props
|
|
17
|
-
});
|
|
12
|
+
*/
|
|
13
|
+
export function ChatPanel({ className, ...props }) {
|
|
14
|
+
return (_jsx("div", { "data-slot": "chat-panel", className: cn("flex min-h-0 flex-1 flex-col bg-background text-foreground", className), ...props }));
|
|
18
15
|
}
|
|
19
16
|
export function ChatPanelHeader({ identity, children, className, ...props }) {
|
|
20
|
-
return
|
|
21
|
-
"data-slot": "chat-panel-header",
|
|
22
|
-
className: cn("flex shrink-0 items-center gap-2.5 border-b border-border px-4 py-3", className),
|
|
23
|
-
...props,
|
|
24
|
-
children: [
|
|
25
|
-
/*#__PURE__*/ _jsx("span", {
|
|
26
|
-
"aria-hidden": true,
|
|
27
|
-
className: "grid size-8 shrink-0 place-items-center rounded-full bg-secondary text-[11px] font-bold text-secondary-foreground",
|
|
28
|
-
children: agentInitials(identity)
|
|
29
|
-
}),
|
|
30
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
31
|
-
className: "flex min-w-0 flex-col",
|
|
32
|
-
children: [
|
|
33
|
-
/*#__PURE__*/ _jsx("p", {
|
|
34
|
-
className: "truncate text-sm font-semibold",
|
|
35
|
-
children: identity.name
|
|
36
|
-
}),
|
|
37
|
-
identity.tagline === undefined ? null : /*#__PURE__*/ _jsx("p", {
|
|
38
|
-
className: "truncate text-xs text-muted-foreground",
|
|
39
|
-
children: identity.tagline
|
|
40
|
-
})
|
|
41
|
-
]
|
|
42
|
-
}),
|
|
43
|
-
/*#__PURE__*/ _jsx("div", {
|
|
44
|
-
className: "ml-auto flex shrink-0 items-center gap-1",
|
|
45
|
-
children: children
|
|
46
|
-
})
|
|
47
|
-
]
|
|
48
|
-
});
|
|
17
|
+
return (_jsxs("header", { "data-slot": "chat-panel-header", className: cn("flex shrink-0 items-center gap-2.5 border-b border-border px-4 py-3", className), ...props, children: [_jsx("span", { "aria-hidden": true, className: "grid size-8 shrink-0 place-items-center rounded-full bg-secondary text-[11px] font-bold text-secondary-foreground", children: agentInitials(identity) }), _jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx("p", { className: "truncate text-sm font-semibold", children: identity.name }), identity.tagline === undefined ? null : (_jsx("p", { className: "truncate text-xs text-muted-foreground", children: identity.tagline }))] }), _jsx("div", { className: "ml-auto flex shrink-0 items-center gap-1", children: children })] }));
|
|
49
18
|
}
|
|
50
|
-
/** The composer area: quick replies, the input, anything else pinned to the bottom. */
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
className: cn("flex shrink-0 flex-col gap-2 border-t border-border p-3", className),
|
|
54
|
-
children: children
|
|
55
|
-
});
|
|
19
|
+
/** The composer area: quick replies, the input, anything else pinned to the bottom. */
|
|
20
|
+
export function ChatPanelFooter({ className, children, }) {
|
|
21
|
+
return (_jsx("div", { "data-slot": "chat-panel-footer", className: cn("flex shrink-0 flex-col gap-2 border-t border-border p-3", className), children: children }));
|
|
56
22
|
}
|
package/dist/ui/chat-thread.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { useEffect, useRef } from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -16,46 +17,27 @@ import { MessageBubble } from "./message-bubble.js";
|
|
|
16
17
|
* It pins to the bottom only when the user is already there. Yanking someone
|
|
17
18
|
* back down while they are reading earlier context is the single most common
|
|
18
19
|
* way chat scrolling goes wrong.
|
|
19
|
-
*/
|
|
20
|
+
*/
|
|
21
|
+
export function ChatThread({ messages, identity, renderBody, onRetry, empty, now, className, }) {
|
|
20
22
|
const scrollRef = useRef(null);
|
|
21
23
|
const pinnedRef = useRef(true);
|
|
22
|
-
useEffect(()=>{
|
|
24
|
+
useEffect(() => {
|
|
23
25
|
const node = scrollRef.current;
|
|
24
|
-
if (node === null || !pinnedRef.current)
|
|
26
|
+
if (node === null || !pinnedRef.current)
|
|
27
|
+
return;
|
|
25
28
|
node.scrollTop = node.scrollHeight;
|
|
26
|
-
}, [
|
|
27
|
-
messages
|
|
28
|
-
]);
|
|
29
|
+
}, [messages]);
|
|
29
30
|
if (messages.length === 0 && empty !== undefined) {
|
|
30
|
-
return
|
|
31
|
-
className: cn("flex min-h-0 flex-1 items-center justify-center p-6", className),
|
|
32
|
-
children: empty
|
|
33
|
-
});
|
|
31
|
+
return (_jsx("div", { className: cn("flex min-h-0 flex-1 items-center justify-center p-6", className), children: empty }));
|
|
34
32
|
}
|
|
35
|
-
return
|
|
36
|
-
ref: scrollRef,
|
|
37
|
-
onScroll: (event)=>{
|
|
33
|
+
return (_jsx("div", { ref: scrollRef, onScroll: (event) => {
|
|
38
34
|
const node = event.currentTarget;
|
|
39
35
|
// A few pixels of slack: sub-pixel layout means an exact comparison is
|
|
40
36
|
// false on plenty of screens that are, visually, at the bottom.
|
|
41
|
-
pinnedRef.current =
|
|
42
|
-
|
|
37
|
+
pinnedRef.current =
|
|
38
|
+
node.scrollHeight - node.scrollTop - node.clientHeight < 32;
|
|
39
|
+
},
|
|
43
40
|
// `log` + polite: new turns are announced without interrupting, which is
|
|
44
41
|
// what an arriving reply is.
|
|
45
|
-
role: "log",
|
|
46
|
-
"aria-live": "polite",
|
|
47
|
-
"aria-label": "Conversation",
|
|
48
|
-
className: cn("flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto p-4", className),
|
|
49
|
-
children: messages.map((message)=>message.role === "agent" ? /*#__PURE__*/ _jsx(AgentTurn, {
|
|
50
|
-
message: message,
|
|
51
|
-
identity: identity,
|
|
52
|
-
now: now,
|
|
53
|
-
children: renderBody?.(message)
|
|
54
|
-
}, message.id) : /*#__PURE__*/ _jsx(MessageBubble, {
|
|
55
|
-
message: message,
|
|
56
|
-
now: now,
|
|
57
|
-
onRetry: onRetry === undefined ? undefined : ()=>onRetry(message),
|
|
58
|
-
children: renderBody?.(message)
|
|
59
|
-
}, message.id))
|
|
60
|
-
});
|
|
42
|
+
role: "log", "aria-live": "polite", "aria-label": "Conversation", className: cn("flex min-h-0 flex-1 flex-col gap-5 overflow-y-auto p-4", className), children: messages.map((message) => message.role === "agent" ? (_jsx(AgentTurn, { message: message, identity: identity, now: now, children: renderBody?.(message) }, message.id)) : (_jsx(MessageBubble, { message: message, now: now, onRetry: onRetry === undefined ? undefined : () => onRetry(message), children: renderBody?.(message) }, message.id))) }));
|
|
61
43
|
}
|
package/dist/ui/checkbox.js
CHANGED
|
@@ -1,63 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { Check, Minus } from "lucide-react";
|
|
3
4
|
import { useEffect, useId, useRef } from "react";
|
|
4
5
|
import { cn } from "../lib/utils.js";
|
|
5
6
|
const CONTROL_CLASS = "relative mt-0.5 flex size-4 shrink-0 items-center justify-center";
|
|
6
|
-
export function Checkbox({ checked, onCheckedChange, label, description, indeterminate = false, id, disabled = false, invalid = false, describedBy, className }) {
|
|
7
|
+
export function Checkbox({ checked, onCheckedChange, label, description, indeterminate = false, id, disabled = false, invalid = false, describedBy, className, }) {
|
|
7
8
|
const generatedId = useId();
|
|
8
9
|
const checkboxId = id ?? generatedId;
|
|
9
10
|
const descriptionId = description === undefined ? undefined : `${checkboxId}-description`;
|
|
10
11
|
const ref = useRef(null);
|
|
11
12
|
const isBare = label === undefined;
|
|
12
|
-
useEffect(()=>{
|
|
13
|
-
if (ref.current)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
]);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/*#__PURE__*/ _jsx("input", {
|
|
21
|
-
ref: ref,
|
|
22
|
-
type: "checkbox",
|
|
23
|
-
id: checkboxId,
|
|
24
|
-
checked: checked,
|
|
25
|
-
disabled: disabled,
|
|
26
|
-
"aria-describedby": isBare ? describedBy : descriptionId,
|
|
27
|
-
"aria-invalid": invalid,
|
|
28
|
-
onChange: (event)=>onCheckedChange(event.target.checked),
|
|
29
|
-
className: cn("peer size-4 shrink-0 appearance-none rounded-sm border border-input bg-card shadow-xs transition-colors", "checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary", "aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50")
|
|
30
|
-
}),
|
|
31
|
-
/*#__PURE__*/ _jsx(Check, {
|
|
32
|
-
"aria-hidden": true,
|
|
33
|
-
className: "pointer-events-none absolute size-3 scale-0 text-primary-foreground transition-transform peer-checked:scale-100"
|
|
34
|
-
}),
|
|
35
|
-
/*#__PURE__*/ _jsx(Minus, {
|
|
36
|
-
"aria-hidden": true,
|
|
37
|
-
className: "pointer-events-none absolute size-3 scale-0 text-primary-foreground transition-transform peer-indeterminate:scale-100 peer-checked:scale-0"
|
|
38
|
-
})
|
|
39
|
-
]
|
|
40
|
-
});
|
|
41
|
-
if (isBare) return control;
|
|
42
|
-
return /*#__PURE__*/ _jsxs("label", {
|
|
43
|
-
htmlFor: checkboxId,
|
|
44
|
-
className: cn("flex items-start gap-2", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className),
|
|
45
|
-
children: [
|
|
46
|
-
control,
|
|
47
|
-
/*#__PURE__*/ _jsxs("span", {
|
|
48
|
-
className: "flex flex-col gap-0.5",
|
|
49
|
-
children: [
|
|
50
|
-
/*#__PURE__*/ _jsx("span", {
|
|
51
|
-
className: "text-sm font-medium",
|
|
52
|
-
children: label
|
|
53
|
-
}),
|
|
54
|
-
description === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
55
|
-
id: descriptionId,
|
|
56
|
-
className: "text-xs leading-relaxed text-muted-foreground",
|
|
57
|
-
children: description
|
|
58
|
-
})
|
|
59
|
-
]
|
|
60
|
-
})
|
|
61
|
-
]
|
|
62
|
-
});
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (ref.current)
|
|
15
|
+
ref.current.indeterminate = indeterminate;
|
|
16
|
+
}, [indeterminate]);
|
|
17
|
+
const control = (_jsxs("div", { className: cn(CONTROL_CLASS, isBare && className), children: [_jsx("input", { ref: ref, type: "checkbox", id: checkboxId, checked: checked, disabled: disabled, "aria-describedby": isBare ? describedBy : descriptionId, "aria-invalid": invalid, onChange: (event) => onCheckedChange(event.target.checked), className: cn("peer size-4 shrink-0 appearance-none rounded-sm border border-input bg-card shadow-xs transition-colors", "checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary", "aria-invalid:border-destructive disabled:cursor-not-allowed disabled:opacity-50") }), _jsx(Check, { "aria-hidden": true, className: "pointer-events-none absolute size-3 scale-0 text-primary-foreground transition-transform peer-checked:scale-100" }), _jsx(Minus, { "aria-hidden": true, className: "pointer-events-none absolute size-3 scale-0 text-primary-foreground transition-transform peer-indeterminate:scale-100 peer-checked:scale-0" })] }));
|
|
18
|
+
if (isBare)
|
|
19
|
+
return control;
|
|
20
|
+
return (_jsxs("label", { htmlFor: checkboxId, className: cn("flex items-start gap-2", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className), children: [control, _jsxs("span", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-sm font-medium", children: label }), description === undefined ? null : (_jsx("span", { id: descriptionId, className: "text-xs leading-relaxed text-muted-foreground", children: description }))] })] }));
|
|
63
21
|
}
|