@upbound/monarch-blocks 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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/cel-filter-bar.d.ts +187 -0
  4. package/dist/cel-filter-bar.js +1850 -0
  5. package/dist/cel-filter-bar.js.map +1 -0
  6. package/dist/chart.d.ts +52 -0
  7. package/dist/chart.js +332 -0
  8. package/dist/chart.js.map +1 -0
  9. package/dist/chat-interface.d.ts +143 -0
  10. package/dist/chat-interface.js +676 -0
  11. package/dist/chat-interface.js.map +1 -0
  12. package/dist/code-block.d.ts +21 -0
  13. package/dist/code-block.js +201 -0
  14. package/dist/code-block.js.map +1 -0
  15. package/dist/data-table.d.ts +505 -0
  16. package/dist/data-table.js +4725 -0
  17. package/dist/data-table.js.map +1 -0
  18. package/dist/filter-bar.d.ts +80 -0
  19. package/dist/filter-bar.js +590 -0
  20. package/dist/filter-bar.js.map +1 -0
  21. package/dist/floating-widget.d.ts +36 -0
  22. package/dist/floating-widget.js +218 -0
  23. package/dist/floating-widget.js.map +1 -0
  24. package/dist/index.d.ts +18 -0
  25. package/dist/index.js +6217 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/page-header.d.ts +12 -0
  28. package/dist/page-header.js +120 -0
  29. package/dist/page-header.js.map +1 -0
  30. package/dist/relative-time.d.ts +60 -0
  31. package/dist/relative-time.js +328 -0
  32. package/dist/relative-time.js.map +1 -0
  33. package/dist/section-header.d.ts +11 -0
  34. package/dist/section-header.js +123 -0
  35. package/dist/section-header.js.map +1 -0
  36. package/dist/section-nav.d.ts +50 -0
  37. package/dist/section-nav.js +143 -0
  38. package/dist/section-nav.js.map +1 -0
  39. package/dist/timeline.d.ts +8 -0
  40. package/dist/timeline.js +95 -0
  41. package/dist/timeline.js.map +1 -0
  42. package/dist/types-BULiU2qC.d.ts +170 -0
  43. package/package.json +58 -0
@@ -0,0 +1,676 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
33
+
34
+ // src/chat-interface.tsx
35
+ import * as React2 from "react";
36
+
37
+ // src/lib/utils.ts
38
+ import { clsx } from "clsx";
39
+ import { extendTailwindMerge } from "tailwind-merge";
40
+ var twMerge = extendTailwindMerge({
41
+ extend: {
42
+ classGroups: {
43
+ "font-size": [
44
+ {
45
+ text: [
46
+ "display-hero",
47
+ "display-kpi-sm",
48
+ "display-kpi",
49
+ "display-kpi-lg",
50
+ "display-feature",
51
+ "h1",
52
+ "h2",
53
+ "h3",
54
+ "h4",
55
+ "body-lg",
56
+ "body",
57
+ "body-sm",
58
+ "caption",
59
+ "eyebrow"
60
+ ]
61
+ }
62
+ ]
63
+ }
64
+ }
65
+ });
66
+ function cn(...inputs) {
67
+ return twMerge(clsx(inputs));
68
+ }
69
+
70
+ // src/chat-interface.tsx
71
+ import { Badge } from "@upbound/monarch-core";
72
+ import { Bubble, BubbleContent } from "@upbound/monarch-core";
73
+ import { Button } from "@upbound/monarch-core";
74
+ import { Message, MessageContent } from "@upbound/monarch-core";
75
+ import {
76
+ DropdownMenu,
77
+ DropdownMenuContent,
78
+ DropdownMenuItem,
79
+ DropdownMenuSeparator,
80
+ DropdownMenuTrigger
81
+ } from "@upbound/monarch-core";
82
+ import { InputGroup, InputGroupAddon, InputGroupTextarea } from "@upbound/monarch-core";
83
+ import { Item, ItemActions, ItemContent, ItemGroup, ItemTitle } from "@upbound/monarch-core";
84
+ import { Kbd } from "@upbound/monarch-core";
85
+ import {
86
+ MessageScrollerProvider,
87
+ MessageScroller,
88
+ MessageScrollerViewport,
89
+ MessageScrollerContent,
90
+ MessageScrollerItem,
91
+ MessageScrollerButton
92
+ } from "@upbound/monarch-core";
93
+ import { Icon } from "@upbound/monarch-core";
94
+
95
+ // src/section-nav.tsx
96
+ import { Slot } from "radix-ui";
97
+ import { jsx } from "react/jsx-runtime";
98
+ function SectionNav(_a) {
99
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
100
+ return /* @__PURE__ */ jsx("nav", __spreadValues({ "data-slot": "section-nav", className: cn("flex flex-col gap-4", className) }, props));
101
+ }
102
+ function SectionNavList(_a) {
103
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
104
+ return /* @__PURE__ */ jsx("ul", __spreadValues({ "data-slot": "section-nav-list", className: cn("flex flex-col gap-px", className) }, props));
105
+ }
106
+ function SectionNavItem(_a) {
107
+ var _b = _a, { className, isActive, asChild, children } = _b, props = __objRest(_b, ["className", "isActive", "asChild", "children"]);
108
+ const Comp = asChild ? Slot.Root : "a";
109
+ return /* @__PURE__ */ jsx("li", { "data-slot": "section-nav-item", children: /* @__PURE__ */ jsx(
110
+ Comp,
111
+ __spreadProps(__spreadValues({
112
+ "data-active": isActive || void 0,
113
+ "aria-current": isActive ? "page" : void 0,
114
+ className: cn(
115
+ "group/section-nav-item text-body text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-accent-foreground flex w-full items-center gap-2 rounded-md px-3 py-1.5 font-medium outline-hidden motion-safe:transition-colors [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-(--icon-default) [&_svg:not([class*='size-'])]:w-(--icon-default)!",
116
+ className
117
+ )
118
+ }, props), {
119
+ children
120
+ })
121
+ ) });
122
+ }
123
+
124
+ // src/relative-time.tsx
125
+ import * as React from "react";
126
+
127
+ // src/hooks/use-mounted.ts
128
+ import { useSyncExternalStore } from "react";
129
+ function subscribe() {
130
+ return () => {
131
+ };
132
+ }
133
+ function useMounted() {
134
+ return useSyncExternalStore(
135
+ subscribe,
136
+ () => true,
137
+ () => false
138
+ );
139
+ }
140
+
141
+ // src/relative-time.tsx
142
+ import { jsx as jsx2 } from "react/jsx-runtime";
143
+ function absoluteTitle(date, locale) {
144
+ return date.toLocaleString(locale, {
145
+ weekday: "long",
146
+ year: "numeric",
147
+ month: "long",
148
+ day: "numeric",
149
+ hour: "numeric",
150
+ minute: "2-digit",
151
+ timeZoneName: "short"
152
+ });
153
+ }
154
+ function formatAmPm(date, options, locale) {
155
+ const parts = new Intl.DateTimeFormat(locale, options).formatToParts(date);
156
+ let result = "";
157
+ for (const part of parts) {
158
+ if (part.type === "dayPeriod") {
159
+ result += part.value.toLowerCase().replace(/\./g, "");
160
+ } else {
161
+ result += part.value;
162
+ }
163
+ }
164
+ return result;
165
+ }
166
+ function formatAbsolute(date, variant, end, locale) {
167
+ var _a, _b;
168
+ switch (variant) {
169
+ case "deadline": {
170
+ const weekday = date.toLocaleDateString(locale, { weekday: "short" });
171
+ const datePart = date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
172
+ const timePart = formatAmPm(date, { hour: "numeric", minute: "2-digit" }, locale);
173
+ const tz = (_a = date.toLocaleTimeString(locale, { timeZoneName: "short" }).split(" ").pop()) != null ? _a : "";
174
+ return `${weekday}, ${datePart} \xB7 ${timePart} ${tz}`;
175
+ }
176
+ case "log": {
177
+ const datePart = date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
178
+ const timePart = formatAmPm(date, { hour: "numeric", minute: "2-digit" }, locale);
179
+ const tz = (_b = date.toLocaleTimeString(locale, { timeZoneName: "short" }).split(" ").pop()) != null ? _b : "";
180
+ return `${datePart}, ${timePart} ${tz}`;
181
+ }
182
+ case "range": {
183
+ if (!end) return date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
184
+ const startYear = date.getFullYear();
185
+ const endYear = end.getFullYear();
186
+ if (startYear === endYear) {
187
+ const start2 = date.toLocaleDateString(locale, { month: "short", day: "numeric" });
188
+ const endStr2 = end.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
189
+ return `${start2} \u2013 ${endStr2}`;
190
+ }
191
+ const start = date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
192
+ const endStr = end.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
193
+ return `${start} \u2013 ${endStr}`;
194
+ }
195
+ case "date":
196
+ default:
197
+ return date.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" });
198
+ }
199
+ }
200
+ function AbsoluteTimestamp(_a) {
201
+ var _b = _a, { date, variant = "date", end, className } = _b, props = __objRest(_b, ["date", "variant", "end", "className"]);
202
+ const d = React.useMemo(() => new Date(date), [date]);
203
+ const e = React.useMemo(() => end ? new Date(end) : void 0, [end]);
204
+ const mounted = useMounted();
205
+ const locale = mounted ? void 0 : "en-US";
206
+ return /* @__PURE__ */ jsx2(
207
+ "time",
208
+ __spreadProps(__spreadValues({
209
+ dateTime: d.toISOString(),
210
+ title: absoluteTitle(d, locale),
211
+ className: cn("tabular-nums", className)
212
+ }, props), {
213
+ children: formatAbsolute(d, variant, e, locale)
214
+ })
215
+ );
216
+ }
217
+
218
+ // src/chat-interface.tsx
219
+ import { Marker, MarkerContent, MarkerIcon } from "@upbound/monarch-core";
220
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@upbound/monarch-core";
221
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
222
+ function formatRelativeTime(iso) {
223
+ const diffMs = Date.now() - new Date(iso).getTime();
224
+ const s = Math.round(diffMs / 1e3);
225
+ if (s < 60) return "now";
226
+ const m = Math.round(s / 60);
227
+ if (m < 60) return `${m}m ago`;
228
+ const h = Math.round(m / 60);
229
+ if (h < 24) return `${h}h ago`;
230
+ const d = Math.round(h / 24);
231
+ if (d < 7) return `${d}d ago`;
232
+ const w = Math.round(d / 7);
233
+ if (w < 5) return `${w}w ago`;
234
+ const mo = Math.round(d / 30);
235
+ if (mo < 12) return `${mo}mo ago`;
236
+ const y = Math.round(d / 365);
237
+ return `${y}y ago`;
238
+ }
239
+ function formatExactTime(iso) {
240
+ return new Date(iso).toLocaleString(void 0, {
241
+ weekday: "short",
242
+ month: "short",
243
+ day: "numeric",
244
+ year: "numeric",
245
+ hour: "numeric",
246
+ minute: "2-digit"
247
+ });
248
+ }
249
+ function ChatSessionList({ sessions, activeSessionId, onSelectSession, className }) {
250
+ return /* @__PURE__ */ jsx3("div", { className: cn("bg-background flex h-full flex-col", className), children: /* @__PURE__ */ jsx3("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx3(ItemGroup, { className: "gap-1 p-2", children: sessions.map((session) => {
251
+ const isActive = session.id === activeSessionId;
252
+ return /* @__PURE__ */ jsxs(
253
+ Item,
254
+ {
255
+ role: "button",
256
+ tabIndex: 0,
257
+ "aria-pressed": isActive,
258
+ "data-active": isActive || void 0,
259
+ onClick: () => onSelectSession(session.id),
260
+ onKeyDown: (e) => {
261
+ if (e.key === "Enter" || e.key === " ") {
262
+ e.preventDefault();
263
+ onSelectSession(session.id);
264
+ }
265
+ },
266
+ className: cn(
267
+ "group/session-item hover:bg-muted/50 data-[active=true]:bg-accent data-[active=true]:text-accent-foreground cursor-pointer flex-nowrap"
268
+ ),
269
+ children: [
270
+ /* @__PURE__ */ jsxs(ItemContent, { className: "min-w-0", children: [
271
+ /* @__PURE__ */ jsx3(ItemTitle, { className: "truncate", children: session.title }),
272
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
273
+ session.surface && /* @__PURE__ */ jsx3(Badge, { variant: "outline", className: "text-[10px]", children: session.surface }),
274
+ session.messageCount != null && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-[10px]", children: [
275
+ session.messageCount,
276
+ " msgs"
277
+ ] }),
278
+ session.updatedAt && /* @__PURE__ */ jsx3(
279
+ AbsoluteTimestamp,
280
+ {
281
+ date: session.updatedAt,
282
+ variant: "date",
283
+ className: "text-muted-foreground text-[10px]"
284
+ }
285
+ )
286
+ ] })
287
+ ] }),
288
+ /* @__PURE__ */ jsx3(ItemActions, { className: "opacity-0 group-hover/session-item:opacity-100 has-data-[state=open]:opacity-100 motion-safe:transition-opacity", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
289
+ /* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
290
+ Button,
291
+ {
292
+ variant: "outline",
293
+ size: "icon-sm",
294
+ "aria-label": `More actions for ${session.title}`,
295
+ onClick: (e) => e.stopPropagation(),
296
+ children: /* @__PURE__ */ jsx3(Icon, { name: "ellipsis" })
297
+ }
298
+ ) }),
299
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
300
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Pin" }),
301
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Rename" }),
302
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Share" }),
303
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Archive" }),
304
+ /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
305
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { variant: "destructive", children: "Delete" })
306
+ ] })
307
+ ] }) })
308
+ ]
309
+ },
310
+ session.id
311
+ );
312
+ }) }) }) });
313
+ }
314
+ function ChatMessageBubble({
315
+ message,
316
+ userName: _userName,
317
+ assistantName = "Upbound AI"
318
+ }) {
319
+ const isUser = message.role === "user";
320
+ const messageFooter = /* @__PURE__ */ jsxs(
321
+ "div",
322
+ {
323
+ className: cn(
324
+ "mt-1 flex items-center gap-1 opacity-0 group-hover/chat-message:opacity-100 motion-safe:transition-opacity",
325
+ isUser && "justify-end"
326
+ ),
327
+ children: [
328
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
329
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
330
+ Button,
331
+ {
332
+ variant: "ghost",
333
+ size: "icon-xs",
334
+ onClick: () => navigator.clipboard.writeText(message.content),
335
+ "aria-label": "Copy message",
336
+ children: /* @__PURE__ */ jsx3(Icon, { name: "copy" })
337
+ }
338
+ ) }),
339
+ /* @__PURE__ */ jsx3(TooltipContent, { children: "Copy" })
340
+ ] }),
341
+ message.timestamp && /* @__PURE__ */ jsxs(Tooltip, { children: [
342
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3("span", { className: "text-caption text-muted-foreground", children: formatRelativeTime(message.timestamp) }) }),
343
+ /* @__PURE__ */ jsx3(TooltipContent, { children: formatExactTime(message.timestamp) })
344
+ ] })
345
+ ]
346
+ }
347
+ );
348
+ if (isUser) {
349
+ return /* @__PURE__ */ jsx3(Message, { align: "end", className: "group/chat-message", children: /* @__PURE__ */ jsxs(MessageContent, { className: "max-w-2xl", children: [
350
+ /* @__PURE__ */ jsx3(Bubble, { variant: "default", align: "end", children: /* @__PURE__ */ jsx3(BubbleContent, { className: "whitespace-pre-wrap", children: message.content }) }),
351
+ messageFooter
352
+ ] }) });
353
+ }
354
+ return /* @__PURE__ */ jsx3(Message, { align: "start", className: "group/chat-message", children: /* @__PURE__ */ jsxs(MessageContent, { className: "max-w-2xl", children: [
355
+ /* @__PURE__ */ jsxs("div", { className: "text-body text-foreground mb-2 flex items-center gap-1.5 font-semibold", children: [
356
+ /* @__PURE__ */ jsx3(Icon, { name: "sparkles", size: "default", className: "text-primary" }),
357
+ assistantName
358
+ ] }),
359
+ message.toolCalls && message.toolCalls.length > 0 && /* @__PURE__ */ jsx3("div", { className: "mb-3 space-y-1.5", children: message.toolCalls.map((tc, i) => /* @__PURE__ */ jsxs("div", { className: "bg-muted/50 text-body-sm flex items-start gap-2 rounded border px-3 py-2", children: [
360
+ /* @__PURE__ */ jsx3(Icon, { name: "wrench", size: "sm", className: "text-muted-foreground mt-0.5 shrink-0" }),
361
+ /* @__PURE__ */ jsxs("div", { children: [
362
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
363
+ /* @__PURE__ */ jsx3("span", { className: "font-medium", children: tc.name }),
364
+ tc.isNew && /* @__PURE__ */ jsx3(Badge, { variant: "secondary", className: "text-[10px]", children: "New API" })
365
+ ] }),
366
+ tc.description && /* @__PURE__ */ jsx3("div", { className: "text-muted-foreground mt-0.5 font-mono text-[10px]", children: tc.description }),
367
+ tc.apiUsed && /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground mt-0.5", children: [
368
+ "via ",
369
+ tc.apiUsed
370
+ ] })
371
+ ] })
372
+ ] }, i)) }),
373
+ /* @__PURE__ */ jsx3("div", { className: "text-body text-foreground leading-relaxed whitespace-pre-wrap", children: message.content }),
374
+ messageFooter
375
+ ] }) });
376
+ }
377
+ function ChatThinkingIndicator() {
378
+ return /* @__PURE__ */ jsx3(Marker, { children: /* @__PURE__ */ jsx3(MarkerContent, { className: "shimmer", children: "Thinking\u2026" }) });
379
+ }
380
+ function ChatInput({
381
+ onSend,
382
+ placeholder = "Ask about your infrastructure...",
383
+ routines,
384
+ onSelectRoutine,
385
+ onManageRoutines,
386
+ usePageAsContext = false,
387
+ onUsePageAsContext,
388
+ onAttach,
389
+ className
390
+ }) {
391
+ const [value, setValue] = React2.useState("");
392
+ function handleSend() {
393
+ if (!value.trim()) return;
394
+ onSend == null ? void 0 : onSend(value.trim());
395
+ setValue("");
396
+ }
397
+ return /* @__PURE__ */ jsx3("div", { className: cn("shrink-0 p-3", className), children: /* @__PURE__ */ jsxs(InputGroup, { className: "has-[[data-slot=input-group-control]:focus-visible]:border-input! has-[[data-slot=input-group-control]:focus-visible]:ring-0!", children: [
398
+ /* @__PURE__ */ jsx3(
399
+ InputGroupTextarea,
400
+ {
401
+ autoFocus: true,
402
+ value,
403
+ onChange: (e) => setValue(e.target.value),
404
+ onKeyDown: (e) => {
405
+ if (e.key === "Enter" && !e.shiftKey) {
406
+ e.preventDefault();
407
+ handleSend();
408
+ }
409
+ },
410
+ placeholder,
411
+ rows: 1
412
+ }
413
+ ),
414
+ /* @__PURE__ */ jsxs(InputGroupAddon, { align: "block-end", children: [
415
+ routines !== void 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
416
+ /* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", children: [
417
+ /* @__PURE__ */ jsx3(Icon, { name: "wand-magic-sparkles", "data-icon": "inline-start" }),
418
+ "Workflows",
419
+ /* @__PURE__ */ jsx3(Icon, { name: "chevron-down", "data-icon": "inline-end" })
420
+ ] }) }),
421
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", children: [
422
+ /* @__PURE__ */ jsx3("div", { className: "max-h-64 overflow-y-auto", children: routines.length === 0 ? /* @__PURE__ */ jsx3(DropdownMenuItem, { disabled: true, children: "No workflows yet" }) : routines.map((w) => /* @__PURE__ */ jsx3(DropdownMenuItem, { onSelect: () => onSelectRoutine == null ? void 0 : onSelectRoutine(w.id), children: w.name }, w.id)) }),
423
+ /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
424
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: onManageRoutines, children: [
425
+ /* @__PURE__ */ jsx3(Icon, { name: "gear" }),
426
+ "Manage workflows"
427
+ ] })
428
+ ] })
429
+ ] }),
430
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
431
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(
432
+ Button,
433
+ {
434
+ variant: "ghost",
435
+ size: "icon-sm",
436
+ className: cn(
437
+ "ml-auto",
438
+ usePageAsContext && "bg-primary/10 text-primary hover:bg-primary/15 hover:text-primary"
439
+ ),
440
+ onClick: onUsePageAsContext,
441
+ "aria-label": "Use page as context",
442
+ "aria-pressed": usePageAsContext,
443
+ children: /* @__PURE__ */ jsx3(Icon, { name: "expand" })
444
+ }
445
+ ) }),
446
+ /* @__PURE__ */ jsx3(TooltipContent, { children: usePageAsContext ? "Using page as context" : "Use page as context" })
447
+ ] }),
448
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
449
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(Button, { variant: "ghost", size: "icon-sm", onClick: onAttach, "aria-label": "Attach image, file, or video", children: /* @__PURE__ */ jsx3(Icon, { name: "paperclip" }) }) }),
450
+ /* @__PURE__ */ jsx3(TooltipContent, { children: "Attach image, file, or video" })
451
+ ] }),
452
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
453
+ /* @__PURE__ */ jsx3(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(Button, { variant: "outline", size: "icon-sm", onClick: handleSend, "aria-label": "Send message", children: /* @__PURE__ */ jsx3(Icon, { name: "arrow-up" }) }) }),
454
+ /* @__PURE__ */ jsxs(TooltipContent, { children: [
455
+ "Send message",
456
+ /* @__PURE__ */ jsx3(Kbd, { children: "\u23CE" })
457
+ ] })
458
+ ] })
459
+ ] })
460
+ ] }) });
461
+ }
462
+ function ChatThread({
463
+ messages,
464
+ onSend,
465
+ title,
466
+ subtitle,
467
+ placeholder,
468
+ suggestions,
469
+ assistantName,
470
+ userName,
471
+ routines,
472
+ onSelectRoutine,
473
+ onManageRoutines,
474
+ usePageAsContext,
475
+ onUsePageAsContext,
476
+ onAttach,
477
+ callout,
478
+ headerActions,
479
+ className,
480
+ isThinking
481
+ }) {
482
+ return (
483
+ // `bg-muted/30` lives on the root so messages area and input area share
484
+ // the same backdrop — the input then floats on the muted bg instead of
485
+ // sitting in its own white-bordered footer container.
486
+ /* @__PURE__ */ jsxs("div", { className: cn("bg-muted/30 flex h-full flex-col", className), children: [
487
+ (title || headerActions) && /* @__PURE__ */ jsxs("div", { className: "bg-background flex shrink-0 items-center justify-between border-b px-6 py-3", children: [
488
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
489
+ title && /* @__PURE__ */ jsx3("div", { className: "text-h4 truncate", children: title }),
490
+ subtitle && /* @__PURE__ */ jsx3("div", { className: "text-body-sm text-muted-foreground truncate", children: subtitle })
491
+ ] }),
492
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
493
+ title && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
494
+ /* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx3(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Session actions", children: /* @__PURE__ */ jsx3(Icon, { name: "ellipsis" }) }) }),
495
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
496
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Pin" }),
497
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Rename" }),
498
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Share" }),
499
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { children: "Archive" }),
500
+ /* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
501
+ /* @__PURE__ */ jsx3(DropdownMenuItem, { variant: "destructive", children: "Delete" })
502
+ ] })
503
+ ] }),
504
+ headerActions
505
+ ] })
506
+ ] }),
507
+ /* @__PURE__ */ jsx3(MessageScrollerProvider, { autoScroll: true, defaultScrollPosition: "end", children: /* @__PURE__ */ jsxs(MessageScroller, { className: "min-h-0 flex-1", children: [
508
+ /* @__PURE__ */ jsx3(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, { className: "gap-4 px-6 py-4", children: [
509
+ callout,
510
+ messages.length === 0 && suggestions && suggestions.length > 0 ? (
511
+ // Starting state — shown when no messages yet AND suggestions
512
+ // are provided. Disappears the moment the user sends anything
513
+ // (either via the input or by clicking a suggestion card).
514
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 pt-2", children: [
515
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
516
+ /* @__PURE__ */ jsxs("div", { className: "text-h4", children: [
517
+ "\u{1F44B} Hi, I'm ",
518
+ assistantName != null ? assistantName : "your AI assistant"
519
+ ] }),
520
+ /* @__PURE__ */ jsx3("div", { className: "text-body-sm text-muted-foreground", children: "Pick a prompt to get started, or ask me anything." })
521
+ ] }),
522
+ /* @__PURE__ */ jsx3("div", { className: "flex flex-col items-start gap-2", children: suggestions.map((s, i) => /* @__PURE__ */ jsx3(
523
+ Button,
524
+ {
525
+ variant: "outline",
526
+ onClick: () => onSend == null ? void 0 : onSend(s),
527
+ className: "text-body-sm h-auto max-w-full justify-start py-2 text-left whitespace-normal",
528
+ children: s
529
+ },
530
+ i
531
+ )) })
532
+ ] })
533
+ ) : null,
534
+ messages.map((msg) => /* @__PURE__ */ jsxs(React2.Fragment, { children: [
535
+ /* @__PURE__ */ jsx3(MessageScrollerItem, { messageId: msg.id, scrollAnchor: msg.role === "user", children: /* @__PURE__ */ jsx3(ChatMessageBubble, { message: msg, userName, assistantName }) }),
536
+ msg.role === "user" && msg.pageContext && /* @__PURE__ */ jsx3(MessageScrollerItem, { messageId: `${msg.id}-ctx`, children: /* @__PURE__ */ jsxs(Marker, { children: [
537
+ /* @__PURE__ */ jsx3(MarkerIcon, { children: /* @__PURE__ */ jsx3(Icon, { name: "expand" }) }),
538
+ /* @__PURE__ */ jsxs(MarkerContent, { children: [
539
+ "Sent with page context: ",
540
+ msg.pageContext
541
+ ] })
542
+ ] }) })
543
+ ] }, msg.id)),
544
+ isThinking && /* @__PURE__ */ jsx3(ChatThinkingIndicator, {})
545
+ ] }) }),
546
+ /* @__PURE__ */ jsx3(MessageScrollerButton, { direction: "end", children: /* @__PURE__ */ jsx3(Icon, { name: "arrow-down" }) })
547
+ ] }) }),
548
+ /* @__PURE__ */ jsx3(
549
+ ChatInput,
550
+ {
551
+ onSend,
552
+ placeholder,
553
+ routines,
554
+ onSelectRoutine,
555
+ onManageRoutines,
556
+ usePageAsContext,
557
+ onUsePageAsContext,
558
+ onAttach
559
+ }
560
+ )
561
+ ] })
562
+ );
563
+ }
564
+ function ChatNavRail({ onNewSession, onOpenRoutines, onOpenConnectors, onOpenCustomize }) {
565
+ return /* @__PURE__ */ jsx3(SectionNav, { className: "border-b p-3", children: /* @__PURE__ */ jsxs(SectionNavList, { children: [
566
+ /* @__PURE__ */ jsxs(
567
+ SectionNavItem,
568
+ {
569
+ href: "#",
570
+ onClick: (e) => {
571
+ e.preventDefault();
572
+ onNewSession == null ? void 0 : onNewSession();
573
+ },
574
+ children: [
575
+ /* @__PURE__ */ jsx3(Icon, { name: "plus" }),
576
+ "New session"
577
+ ]
578
+ }
579
+ ),
580
+ /* @__PURE__ */ jsxs(
581
+ SectionNavItem,
582
+ {
583
+ href: "#",
584
+ onClick: (e) => {
585
+ e.preventDefault();
586
+ onOpenRoutines == null ? void 0 : onOpenRoutines();
587
+ },
588
+ children: [
589
+ /* @__PURE__ */ jsx3(Icon, { name: "bolt" }),
590
+ "Workflows"
591
+ ]
592
+ }
593
+ ),
594
+ /* @__PURE__ */ jsxs(
595
+ SectionNavItem,
596
+ {
597
+ href: "#",
598
+ onClick: (e) => {
599
+ e.preventDefault();
600
+ onOpenConnectors == null ? void 0 : onOpenConnectors();
601
+ },
602
+ children: [
603
+ /* @__PURE__ */ jsx3(Icon, { name: "plug" }),
604
+ "Connectors"
605
+ ]
606
+ }
607
+ ),
608
+ /* @__PURE__ */ jsxs(
609
+ SectionNavItem,
610
+ {
611
+ href: "#",
612
+ onClick: (e) => {
613
+ e.preventDefault();
614
+ onOpenCustomize == null ? void 0 : onOpenCustomize();
615
+ },
616
+ children: [
617
+ /* @__PURE__ */ jsx3(Icon, { name: "toolbox" }),
618
+ "Customize"
619
+ ]
620
+ }
621
+ )
622
+ ] }) });
623
+ }
624
+ function ChatInterface(_a) {
625
+ var _b = _a, {
626
+ sessions,
627
+ activeSessionId,
628
+ onSelectSession,
629
+ onNewSession,
630
+ onOpenRoutines,
631
+ onOpenConnectors,
632
+ onOpenCustomize,
633
+ className
634
+ } = _b, threadProps = __objRest(_b, [
635
+ "sessions",
636
+ "activeSessionId",
637
+ "onSelectSession",
638
+ "onNewSession",
639
+ "onOpenRoutines",
640
+ "onOpenConnectors",
641
+ "onOpenCustomize",
642
+ "className"
643
+ ]);
644
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex h-full", className), children: [
645
+ /* @__PURE__ */ jsxs("div", { className: "bg-background flex w-72 shrink-0 flex-col border-r", children: [
646
+ /* @__PURE__ */ jsx3(
647
+ ChatNavRail,
648
+ {
649
+ onNewSession,
650
+ onOpenRoutines,
651
+ onOpenConnectors,
652
+ onOpenCustomize
653
+ }
654
+ ),
655
+ /* @__PURE__ */ jsx3(
656
+ ChatSessionList,
657
+ {
658
+ sessions,
659
+ activeSessionId,
660
+ onSelectSession: onSelectSession != null ? onSelectSession : (() => {
661
+ }),
662
+ className: "flex-1"
663
+ }
664
+ )
665
+ ] }),
666
+ /* @__PURE__ */ jsx3(ChatThread, __spreadProps(__spreadValues({}, threadProps), { className: "flex-1" }))
667
+ ] });
668
+ }
669
+ export {
670
+ ChatInput,
671
+ ChatInterface,
672
+ ChatMessageBubble,
673
+ ChatSessionList,
674
+ ChatThread
675
+ };
676
+ //# sourceMappingURL=chat-interface.js.map