@epicbagel/saas-kit 1.20.0 → 1.21.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.
@@ -0,0 +1,204 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
+ "use client";
3
+
4
+
5
+
6
+ var _chunk4YJ6DGPLcjs = require('../chunk-4YJ6DGPL.cjs');
7
+ require('../chunk-2BTDBZYN.cjs');
8
+ require('../chunk-PH2TV7XI.cjs');
9
+ require('../chunk-YMI3X2YL.cjs');
10
+ require('../chunk-M4V7OJNF.cjs');
11
+ require('../chunk-B765DSRG.cjs');
12
+ require('../chunk-23IETCLV.cjs');
13
+ require('../chunk-DMPSKGFM.cjs');
14
+ require('../chunk-NWDPH2Z7.cjs');
15
+ require('../chunk-Z2H4LJVG.cjs');
16
+ require('../chunk-7LDJAXRX.cjs');
17
+ require('../chunk-2HV2KKOE.cjs');
18
+ require('../chunk-ZLEM2SAU.cjs');
19
+ require('../chunk-KENBU3NV.cjs');
20
+ require('../chunk-ELPV44S6.cjs');
21
+ require('../chunk-2BHI5ZWJ.cjs');
22
+ require('../chunk-ZAITUDYD.cjs');
23
+ require('../chunk-U2NES7VR.cjs');
24
+ require('../chunk-V4YWTRLD.cjs');
25
+ require('../chunk-373W6VAD.cjs');
26
+ require('../chunk-W5HPHEE7.cjs');
27
+ require('../chunk-FYRQFEU4.cjs');
28
+ require('../chunk-2KFZQJH5.cjs');
29
+ require('../chunk-PQUSJEXL.cjs');
30
+ require('../chunk-WABCLRBR.cjs');
31
+ require('../chunk-NKWHDI4C.cjs');
32
+
33
+
34
+ var _chunkJDEXZGIYcjs = require('../chunk-JDEXZGIY.cjs');
35
+
36
+
37
+ var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
38
+ require('../chunk-2BSFYU22.cjs');
39
+ require('../chunk-4LXN6GLZ.cjs');
40
+ require('../chunk-7Q4EFCUI.cjs');
41
+ require('../chunk-R35FT53G.cjs');
42
+ require('../chunk-H2UFRLLN.cjs');
43
+
44
+ // src/primitives/workflow-assistant.tsx
45
+ var _react = require('react');
46
+ var _lucidereact = require('lucide-react');
47
+ var _jsxruntime = require('react/jsx-runtime');
48
+ var SESSION_LABELS = {
49
+ disconnected: "Voice chat",
50
+ connecting: "Connecting\u2026",
51
+ listening: "Listening\u2026",
52
+ thinking: "Thinking\u2026",
53
+ speaking: "Speaking",
54
+ reconnecting: "Reconnecting\u2026",
55
+ error: "Voice chat unavailable"
56
+ };
57
+ var WorkflowAssistant = _react.forwardRef.call(void 0, function WorkflowAssistant2({
58
+ open,
59
+ onOpenChange,
60
+ expanded = false,
61
+ onExpandedChange,
62
+ title = "Voice review",
63
+ context,
64
+ description,
65
+ messages,
66
+ value,
67
+ onChange,
68
+ onSend,
69
+ voiceSession,
70
+ pending,
71
+ disabled,
72
+ error,
73
+ placeholder = "Describe an action\u2026",
74
+ besideCornerAction = false,
75
+ labels,
76
+ className
77
+ }, ref) {
78
+ const titleId = _react.useId.call(void 0, );
79
+ const statusId = _react.useId.call(void 0, );
80
+ const launcher = _react.useRef.call(void 0, null);
81
+ const heading = _react.useRef.call(void 0, null);
82
+ const moveFocus = _react.useRef.call(void 0, false);
83
+ _react.useEffect.call(void 0, () => {
84
+ if (!moveFocus.current) return;
85
+ moveFocus.current = false;
86
+ _optionalChain([(open ? heading.current : launcher.current), 'optionalAccess', _ => _.focus, 'call', _2 => _2()]);
87
+ }, [open]);
88
+ const toggle = (next) => {
89
+ moveFocus.current = true;
90
+ onOpenChange(next);
91
+ };
92
+ const startDisabled = pending || disabled || _optionalChain([voiceSession, 'optionalAccess', _3 => _3.disabled]);
93
+ const active = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
94
+ const status = voiceSession && (voiceSession.muted && voiceSession.state === "listening" ? _nullishCoalesce(_optionalChain([voiceSession, 'access', _4 => _4.labels, 'optionalAccess', _5 => _5.muted]), () => ( "Microphone muted")) : _nullishCoalesce(_optionalChain([voiceSession, 'access', _6 => _6.labels, 'optionalAccess', _7 => _7[voiceSession.state]]), () => ( SESSION_LABELS[voiceSession.state])));
95
+ if (!open) return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
96
+ "aside",
97
+ {
98
+ ref,
99
+ "data-slot": "workflow-assistant-launcher",
100
+ "aria-label": title,
101
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "fixed bottom-[calc(1.5rem+env(safe-area-inset-bottom))] z-40 flex max-w-[calc(100vw-9rem)] items-center gap-1", besideCornerAction ? "right-32 md:right-36" : "right-6 md:right-8", className),
102
+ children: [
103
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
104
+ _chunkJDEXZGIYcjs.Button,
105
+ {
106
+ ref: launcher,
107
+ type: "button",
108
+ shape: "pill",
109
+ className: "min-h-12 min-w-12 max-w-full gap-2 shadow-lg",
110
+ disabled: startDisabled && !active,
111
+ "aria-label": active ? title : _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _8 => _8.start]), () => ( "Start voice review")),
112
+ "aria-expanded": false,
113
+ "aria-describedby": active ? statusId : void 0,
114
+ onClick: () => {
115
+ toggle(true);
116
+ if (!active && !startDisabled) _optionalChain([voiceSession, 'optionalAccess', _9 => _9.onStart, 'call', _10 => _10()]);
117
+ },
118
+ children: [
119
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.AudioLines, { "aria-hidden": "true", className: "shrink-0" }),
120
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { id: statusId, role: active ? "status" : void 0, className: "truncate", children: active ? status : title })
121
+ ]
122
+ }
123
+ ),
124
+ active && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
125
+ _chunkJDEXZGIYcjs.Button,
126
+ {
127
+ type: "button",
128
+ variant: "outline",
129
+ shape: "circle",
130
+ size: "icon",
131
+ className: "min-h-12 min-w-12 bg-background shadow-lg",
132
+ onClick: () => {
133
+ _optionalChain([launcher, 'access', _11 => _11.current, 'optionalAccess', _12 => _12.focus, 'call', _13 => _13()]);
134
+ voiceSession.onEnd();
135
+ },
136
+ "aria-label": _nullishCoalesce(_nullishCoalesce(_optionalChain([labels, 'optionalAccess', _14 => _14.end]), () => ( _optionalChain([voiceSession, 'access', _15 => _15.labels, 'optionalAccess', _16 => _16.end]))), () => ( "End voice chat")),
137
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Square, { "aria-hidden": "true" })
138
+ }
139
+ )
140
+ ]
141
+ }
142
+ );
143
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
144
+ "aside",
145
+ {
146
+ ref,
147
+ "data-slot": "workflow-assistant",
148
+ "aria-labelledby": titleId,
149
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
150
+ "fixed inset-x-2 bottom-[calc(1rem+env(safe-area-inset-bottom))] z-40 flex min-h-0 flex-col overflow-y-auto overscroll-contain rounded-2xl border bg-background shadow-xl sm:inset-x-auto sm:right-6 sm:w-[28rem] md:right-8",
151
+ expanded ? "h-[calc(100dvh-6rem)]" : "max-h-[min(36rem,70dvh)]",
152
+ className
153
+ ),
154
+ children: [
155
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "sticky top-0 z-10 flex shrink-0 items-start gap-2 border-b bg-background p-3", children: [
156
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1", children: [
157
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { ref: heading, tabIndex: -1, id: titleId, className: "text-sm font-semibold", children: title }),
158
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { title: context, className: "mt-1 truncate text-xs text-muted-foreground", children: context })
159
+ ] }),
160
+ onExpandedChange && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
161
+ _chunkJDEXZGIYcjs.Button,
162
+ {
163
+ type: "button",
164
+ variant: "ghost",
165
+ size: "icon",
166
+ "aria-label": expanded ? _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _17 => _17.collapse]), () => ( "Reduce panel")) : _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _18 => _18.expand]), () => ( "Expand panel")),
167
+ onClick: () => onExpandedChange(!expanded),
168
+ children: expanded ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Minimize2, { "aria-hidden": "true" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Maximize2, { "aria-hidden": "true" })
169
+ }
170
+ ),
171
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "ghost", size: "icon", "aria-label": _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _19 => _19.minimize]), () => ( "Minimize voice review")), onClick: () => toggle(false), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronDown, { "aria-hidden": "true" }) })
172
+ ] }),
173
+ description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "shrink-0 px-4 py-2 text-xs text-muted-foreground", children: description }),
174
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
175
+ _chunk4YJ6DGPLcjs.ChatThread,
176
+ {
177
+ messages,
178
+ pending,
179
+ maxHeight: expanded ? "60dvh" : "32dvh",
180
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex-1 px-3", messages.length > 0 || pending ? "min-h-24" : "min-h-0")
181
+ }
182
+ ),
183
+ error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "shrink-0 px-4 py-2 text-sm text-destructive", children: error }),
184
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "shrink-0 p-2", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
185
+ _chunk4YJ6DGPLcjs.ChatInput,
186
+ {
187
+ value,
188
+ onChange,
189
+ onSend,
190
+ disabled,
191
+ pending,
192
+ placeholder,
193
+ size: "sm",
194
+ voice: false,
195
+ voiceSession
196
+ }
197
+ ) })
198
+ ]
199
+ }
200
+ );
201
+ });
202
+
203
+
204
+ exports.WorkflowAssistant = WorkflowAssistant;
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { ChatMessage } from './chat.cjs';
4
+ import { VoiceSessionControlsProps } from './voice-session-controls.cjs';
5
+ import 'react/jsx-runtime';
6
+ import './markdown.cjs';
7
+ import 'react-markdown';
8
+ import './rich-text.cjs';
9
+
10
+ interface WorkflowAssistantProps {
11
+ open: boolean;
12
+ onOpenChange: (open: boolean) => void;
13
+ expanded?: boolean;
14
+ onExpandedChange?: (expanded: boolean) => void;
15
+ title?: string;
16
+ /** Current host-owned scope. Keep it visible while the transcript scrolls. */
17
+ context: string;
18
+ description?: ReactNode;
19
+ messages: ChatMessage[];
20
+ value: string;
21
+ onChange: (value: string) => void;
22
+ onSend: (value: string) => void;
23
+ /** Minimizing preserves this host-owned session; only End calls onEnd. */
24
+ voiceSession?: VoiceSessionControlsProps;
25
+ pending?: boolean;
26
+ disabled?: boolean;
27
+ error?: string | null;
28
+ placeholder?: string;
29
+ /** Leave room for an existing corner action such as New. */
30
+ besideCornerAction?: boolean;
31
+ labels?: {
32
+ start?: string;
33
+ minimize?: string;
34
+ expand?: string;
35
+ collapse?: string;
36
+ end?: string;
37
+ };
38
+ className?: string;
39
+ }
40
+ /** A non-modal workflow conversation: the underlying list stays usable.
41
+ * The host owns scope, authorization, persistence and the voice connection. */
42
+ declare const WorkflowAssistant: React.ForwardRefExoticComponent<WorkflowAssistantProps & React.RefAttributes<HTMLElement>>;
43
+
44
+ export { WorkflowAssistant, type WorkflowAssistantProps };
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { ReactNode } from 'react';
3
+ import { ChatMessage } from './chat.js';
4
+ import { VoiceSessionControlsProps } from './voice-session-controls.js';
5
+ import 'react/jsx-runtime';
6
+ import './markdown.js';
7
+ import 'react-markdown';
8
+ import './rich-text.js';
9
+
10
+ interface WorkflowAssistantProps {
11
+ open: boolean;
12
+ onOpenChange: (open: boolean) => void;
13
+ expanded?: boolean;
14
+ onExpandedChange?: (expanded: boolean) => void;
15
+ title?: string;
16
+ /** Current host-owned scope. Keep it visible while the transcript scrolls. */
17
+ context: string;
18
+ description?: ReactNode;
19
+ messages: ChatMessage[];
20
+ value: string;
21
+ onChange: (value: string) => void;
22
+ onSend: (value: string) => void;
23
+ /** Minimizing preserves this host-owned session; only End calls onEnd. */
24
+ voiceSession?: VoiceSessionControlsProps;
25
+ pending?: boolean;
26
+ disabled?: boolean;
27
+ error?: string | null;
28
+ placeholder?: string;
29
+ /** Leave room for an existing corner action such as New. */
30
+ besideCornerAction?: boolean;
31
+ labels?: {
32
+ start?: string;
33
+ minimize?: string;
34
+ expand?: string;
35
+ collapse?: string;
36
+ end?: string;
37
+ };
38
+ className?: string;
39
+ }
40
+ /** A non-modal workflow conversation: the underlying list stays usable.
41
+ * The host owns scope, authorization, persistence and the voice connection. */
42
+ declare const WorkflowAssistant: React.ForwardRefExoticComponent<WorkflowAssistantProps & React.RefAttributes<HTMLElement>>;
43
+
44
+ export { WorkflowAssistant, type WorkflowAssistantProps };
@@ -0,0 +1,204 @@
1
+ "use client";
2
+ "use client";
3
+ import {
4
+ ChatInput,
5
+ ChatThread
6
+ } from "../chunk-C23Q4FRM.js";
7
+ import "../chunk-Z45YKVAM.js";
8
+ import "../chunk-ZGTPNSR7.js";
9
+ import "../chunk-KF4X37DP.js";
10
+ import "../chunk-IJG2B3Y2.js";
11
+ import "../chunk-IW4ZIXXG.js";
12
+ import "../chunk-OUZSIA5G.js";
13
+ import "../chunk-36LNA4WM.js";
14
+ import "../chunk-H4XH2PPU.js";
15
+ import "../chunk-GA5SX7FE.js";
16
+ import "../chunk-QTPPNK6F.js";
17
+ import "../chunk-6FC65AZQ.js";
18
+ import "../chunk-WHDHUYS6.js";
19
+ import "../chunk-VY5U4VGV.js";
20
+ import "../chunk-INNGGLMZ.js";
21
+ import "../chunk-4HWCNRK4.js";
22
+ import "../chunk-V4LE2HWP.js";
23
+ import "../chunk-ZRLUUZHK.js";
24
+ import "../chunk-F366BHWH.js";
25
+ import "../chunk-EIY5LLSP.js";
26
+ import "../chunk-NBUWGRQO.js";
27
+ import "../chunk-CYDICVH2.js";
28
+ import "../chunk-42RTTHND.js";
29
+ import "../chunk-QMA3WVB7.js";
30
+ import "../chunk-3OWGL4Q2.js";
31
+ import "../chunk-5OF6D3GH.js";
32
+ import {
33
+ Button
34
+ } from "../chunk-W326GKML.js";
35
+ import {
36
+ cn
37
+ } from "../chunk-G6SRSWXB.js";
38
+ import "../chunk-GJ7S3L6R.js";
39
+ import "../chunk-ZWZAAGQF.js";
40
+ import "../chunk-RPSRCB5O.js";
41
+ import "../chunk-PIU5SSUV.js";
42
+ import "../chunk-CS7DM3NV.js";
43
+
44
+ // src/primitives/workflow-assistant.tsx
45
+ import { forwardRef, useEffect, useId, useRef } from "react";
46
+ import { AudioLines, ChevronDown, Maximize2, Minimize2, Square } from "lucide-react";
47
+ import { jsx, jsxs } from "react/jsx-runtime";
48
+ var SESSION_LABELS = {
49
+ disconnected: "Voice chat",
50
+ connecting: "Connecting\u2026",
51
+ listening: "Listening\u2026",
52
+ thinking: "Thinking\u2026",
53
+ speaking: "Speaking",
54
+ reconnecting: "Reconnecting\u2026",
55
+ error: "Voice chat unavailable"
56
+ };
57
+ var WorkflowAssistant = forwardRef(function WorkflowAssistant2({
58
+ open,
59
+ onOpenChange,
60
+ expanded = false,
61
+ onExpandedChange,
62
+ title = "Voice review",
63
+ context,
64
+ description,
65
+ messages,
66
+ value,
67
+ onChange,
68
+ onSend,
69
+ voiceSession,
70
+ pending,
71
+ disabled,
72
+ error,
73
+ placeholder = "Describe an action\u2026",
74
+ besideCornerAction = false,
75
+ labels,
76
+ className
77
+ }, ref) {
78
+ const titleId = useId();
79
+ const statusId = useId();
80
+ const launcher = useRef(null);
81
+ const heading = useRef(null);
82
+ const moveFocus = useRef(false);
83
+ useEffect(() => {
84
+ if (!moveFocus.current) return;
85
+ moveFocus.current = false;
86
+ (open ? heading.current : launcher.current)?.focus();
87
+ }, [open]);
88
+ const toggle = (next) => {
89
+ moveFocus.current = true;
90
+ onOpenChange(next);
91
+ };
92
+ const startDisabled = pending || disabled || voiceSession?.disabled;
93
+ const active = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
94
+ const status = voiceSession && (voiceSession.muted && voiceSession.state === "listening" ? voiceSession.labels?.muted ?? "Microphone muted" : voiceSession.labels?.[voiceSession.state] ?? SESSION_LABELS[voiceSession.state]);
95
+ if (!open) return /* @__PURE__ */ jsxs(
96
+ "aside",
97
+ {
98
+ ref,
99
+ "data-slot": "workflow-assistant-launcher",
100
+ "aria-label": title,
101
+ className: cn("fixed bottom-[calc(1.5rem+env(safe-area-inset-bottom))] z-40 flex max-w-[calc(100vw-9rem)] items-center gap-1", besideCornerAction ? "right-32 md:right-36" : "right-6 md:right-8", className),
102
+ children: [
103
+ /* @__PURE__ */ jsxs(
104
+ Button,
105
+ {
106
+ ref: launcher,
107
+ type: "button",
108
+ shape: "pill",
109
+ className: "min-h-12 min-w-12 max-w-full gap-2 shadow-lg",
110
+ disabled: startDisabled && !active,
111
+ "aria-label": active ? title : labels?.start ?? "Start voice review",
112
+ "aria-expanded": false,
113
+ "aria-describedby": active ? statusId : void 0,
114
+ onClick: () => {
115
+ toggle(true);
116
+ if (!active && !startDisabled) voiceSession?.onStart();
117
+ },
118
+ children: [
119
+ /* @__PURE__ */ jsx(AudioLines, { "aria-hidden": "true", className: "shrink-0" }),
120
+ /* @__PURE__ */ jsx("span", { id: statusId, role: active ? "status" : void 0, className: "truncate", children: active ? status : title })
121
+ ]
122
+ }
123
+ ),
124
+ active && /* @__PURE__ */ jsx(
125
+ Button,
126
+ {
127
+ type: "button",
128
+ variant: "outline",
129
+ shape: "circle",
130
+ size: "icon",
131
+ className: "min-h-12 min-w-12 bg-background shadow-lg",
132
+ onClick: () => {
133
+ launcher.current?.focus();
134
+ voiceSession.onEnd();
135
+ },
136
+ "aria-label": labels?.end ?? voiceSession.labels?.end ?? "End voice chat",
137
+ children: /* @__PURE__ */ jsx(Square, { "aria-hidden": "true" })
138
+ }
139
+ )
140
+ ]
141
+ }
142
+ );
143
+ return /* @__PURE__ */ jsxs(
144
+ "aside",
145
+ {
146
+ ref,
147
+ "data-slot": "workflow-assistant",
148
+ "aria-labelledby": titleId,
149
+ className: cn(
150
+ "fixed inset-x-2 bottom-[calc(1rem+env(safe-area-inset-bottom))] z-40 flex min-h-0 flex-col overflow-y-auto overscroll-contain rounded-2xl border bg-background shadow-xl sm:inset-x-auto sm:right-6 sm:w-[28rem] md:right-8",
151
+ expanded ? "h-[calc(100dvh-6rem)]" : "max-h-[min(36rem,70dvh)]",
152
+ className
153
+ ),
154
+ children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 z-10 flex shrink-0 items-start gap-2 border-b bg-background p-3", children: [
156
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
157
+ /* @__PURE__ */ jsx("h2", { ref: heading, tabIndex: -1, id: titleId, className: "text-sm font-semibold", children: title }),
158
+ /* @__PURE__ */ jsx("p", { title: context, className: "mt-1 truncate text-xs text-muted-foreground", children: context })
159
+ ] }),
160
+ onExpandedChange && /* @__PURE__ */ jsx(
161
+ Button,
162
+ {
163
+ type: "button",
164
+ variant: "ghost",
165
+ size: "icon",
166
+ "aria-label": expanded ? labels?.collapse ?? "Reduce panel" : labels?.expand ?? "Expand panel",
167
+ onClick: () => onExpandedChange(!expanded),
168
+ children: expanded ? /* @__PURE__ */ jsx(Minimize2, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Maximize2, { "aria-hidden": "true" })
169
+ }
170
+ ),
171
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": labels?.minimize ?? "Minimize voice review", onClick: () => toggle(false), children: /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) })
172
+ ] }),
173
+ description && /* @__PURE__ */ jsx("div", { className: "shrink-0 px-4 py-2 text-xs text-muted-foreground", children: description }),
174
+ /* @__PURE__ */ jsx(
175
+ ChatThread,
176
+ {
177
+ messages,
178
+ pending,
179
+ maxHeight: expanded ? "60dvh" : "32dvh",
180
+ className: cn("flex-1 px-3", messages.length > 0 || pending ? "min-h-24" : "min-h-0")
181
+ }
182
+ ),
183
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "shrink-0 px-4 py-2 text-sm text-destructive", children: error }),
184
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 p-2", children: /* @__PURE__ */ jsx(
185
+ ChatInput,
186
+ {
187
+ value,
188
+ onChange,
189
+ onSend,
190
+ disabled,
191
+ pending,
192
+ placeholder,
193
+ size: "sm",
194
+ voice: false,
195
+ voiceSession
196
+ }
197
+ ) })
198
+ ]
199
+ }
200
+ );
201
+ });
202
+ export {
203
+ WorkflowAssistant
204
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicbagel/saas-kit",
3
- "version": "1.20.0",
3
+ "version": "1.21.0",
4
4
  "description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1290,6 +1290,16 @@
1290
1290
  "default": "./dist/primitives/voice-session-controls.cjs"
1291
1291
  }
1292
1292
  },
1293
+ "./primitives/workflow-assistant": {
1294
+ "import": {
1295
+ "types": "./dist/primitives/workflow-assistant.d.ts",
1296
+ "default": "./dist/primitives/workflow-assistant.js"
1297
+ },
1298
+ "require": {
1299
+ "types": "./dist/primitives/workflow-assistant.d.cts",
1300
+ "default": "./dist/primitives/workflow-assistant.cjs"
1301
+ }
1302
+ },
1293
1303
  "./hooks/use-agent-audio-visualizer-bar": {
1294
1304
  "import": {
1295
1305
  "types": "./dist/hooks/use-agent-audio-visualizer-bar.d.ts",