@melony/react 0.1.12 → 0.1.15

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/dist/index.cjs CHANGED
@@ -1,20 +1,23 @@
1
1
  'use strict';
2
2
 
3
- var React9 = require('react');
3
+ var React11 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var client = require('melony/client');
4
6
  var clsx = require('clsx');
5
7
  var tailwindMerge = require('tailwind-merge');
6
- var jsxRuntime = require('react/jsx-runtime');
7
- var client = require('@melony/core/client');
8
- var separator = require('@base-ui/react/separator');
8
+ var button = require('@base-ui/react/button');
9
+ var classVarianceAuthority = require('class-variance-authority');
9
10
  var ICONS = require('@tabler/icons-react');
11
+ var menu = require('@base-ui/react/menu');
12
+ var separator = require('@base-ui/react/separator');
13
+ var dialog = require('@base-ui/react/dialog');
10
14
  var mergeProps = require('@base-ui/react/merge-props');
11
15
  var useRender = require('@base-ui/react/use-render');
12
- var classVarianceAuthority = require('class-variance-authority');
13
16
  var input = require('@base-ui/react/input');
14
17
  var select = require('@base-ui/react/select');
15
- var button = require('@base-ui/react/button');
18
+ var reactDom = require('react-dom');
19
+ var reactHotkeysHook = require('react-hotkeys-hook');
16
20
  var alertDialog = require('@base-ui/react/alert-dialog');
17
- var menu = require('@base-ui/react/menu');
18
21
 
19
22
  function _interopNamespace(e) {
20
23
  if (e && e.__esModule) return e;
@@ -34,13 +37,12 @@ function _interopNamespace(e) {
34
37
  return Object.freeze(n);
35
38
  }
36
39
 
37
- var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
40
+ var React11__namespace = /*#__PURE__*/_interopNamespace(React11);
38
41
  var ICONS__namespace = /*#__PURE__*/_interopNamespace(ICONS);
39
42
 
40
43
  // src/providers/melony-provider.tsx
41
- function cn(...inputs) {
42
- return tailwindMerge.twMerge(clsx.clsx(inputs));
43
- }
44
+
45
+ // src/lib/group-events-to-messages.ts
44
46
  function groupEventsToMessages(events) {
45
47
  if (events.length === 0) return [];
46
48
  const messages = [];
@@ -64,7 +66,7 @@ function groupEventsToMessages(events) {
64
66
  }
65
67
  return messages;
66
68
  }
67
- var MelonyContext = React9.createContext(
69
+ var MelonyContext = React11.createContext(
68
70
  void 0
69
71
  );
70
72
  var MelonyClientProvider = ({
@@ -72,20 +74,20 @@ var MelonyClientProvider = ({
72
74
  client,
73
75
  initialEvents
74
76
  }) => {
75
- const [state, setState] = React9.useState(client.getState());
76
- React9.useEffect(() => {
77
+ const [state, setState] = React11.useState(client.getState());
78
+ React11.useEffect(() => {
77
79
  if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
78
80
  client.reset(initialEvents);
79
81
  }
80
82
  }, [client, initialEvents]);
81
- React9.useEffect(() => {
83
+ React11.useEffect(() => {
82
84
  setState(client.getState());
83
85
  const unsubscribe = client.subscribe(setState);
84
86
  return () => {
85
87
  unsubscribe();
86
88
  };
87
89
  }, [client]);
88
- const sendEvent = React9.useCallback(
90
+ const sendEvent = React11.useCallback(
89
91
  async (event, options) => {
90
92
  const generator = client.sendEvent(event, options);
91
93
  for await (const _ of generator) {
@@ -93,11 +95,11 @@ var MelonyClientProvider = ({
93
95
  },
94
96
  [client]
95
97
  );
96
- const reset = React9.useCallback(
98
+ const reset = React11.useCallback(
97
99
  (events) => client.reset(events),
98
100
  [client]
99
101
  );
100
- const value = React9.useMemo(
102
+ const value = React11.useMemo(
101
103
  () => ({
102
104
  ...state,
103
105
  messages: groupEventsToMessages(state.events),
@@ -109,16 +111,16 @@ var MelonyClientProvider = ({
109
111
  );
110
112
  return /* @__PURE__ */ jsxRuntime.jsx(MelonyContext.Provider, { value, children });
111
113
  };
112
- var AuthContext = React9.createContext(
114
+ var AuthContext = React11.createContext(
113
115
  void 0
114
116
  );
115
117
  var AuthProvider = ({
116
118
  children,
117
119
  service
118
120
  }) => {
119
- const [user, setUser] = React9.useState(null);
120
- const [isLoading, setIsLoading] = React9.useState(true);
121
- const fetchMe = React9.useCallback(async () => {
121
+ const [user, setUser] = React11.useState(null);
122
+ const [isLoading, setIsLoading] = React11.useState(true);
123
+ const fetchMe = React11.useCallback(async () => {
122
124
  setIsLoading(true);
123
125
  try {
124
126
  const userData = await service.getMe();
@@ -130,13 +132,13 @@ var AuthProvider = ({
130
132
  setIsLoading(false);
131
133
  }
132
134
  }, [service]);
133
- React9.useEffect(() => {
135
+ React11.useEffect(() => {
134
136
  fetchMe();
135
137
  }, [fetchMe]);
136
- const login = React9.useCallback(() => {
138
+ const login = React11.useCallback(() => {
137
139
  service.login();
138
140
  }, [service]);
139
- const logout = React9.useCallback(async () => {
141
+ const logout = React11.useCallback(async () => {
140
142
  try {
141
143
  await service.logout();
142
144
  setUser(null);
@@ -172,7 +174,7 @@ var AuthProvider = ({
172
174
  }
173
175
  return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
174
176
  };
175
- var ThreadContext = React9.createContext(
177
+ var ThreadContext = React11.createContext(
176
178
  void 0
177
179
  );
178
180
  var ThreadProvider = ({
@@ -180,17 +182,17 @@ var ThreadProvider = ({
180
182
  service,
181
183
  initialThreadId: providedInitialThreadId
182
184
  }) => {
183
- const defaultInitialThreadId = React9.useMemo(() => client.generateId(), []);
185
+ const defaultInitialThreadId = React11.useMemo(() => client.generateId(), []);
184
186
  const initialThreadId = providedInitialThreadId || defaultInitialThreadId;
185
- const [threads, setThreads] = React9.useState([]);
186
- const [activeThreadId, setActiveThreadId] = React9.useState(
187
+ const [threads, setThreads] = React11.useState([]);
188
+ const [activeThreadId, setActiveThreadId] = React11.useState(
187
189
  initialThreadId
188
190
  );
189
- const [isLoading, setIsLoading] = React9.useState(true);
190
- const [error, setError] = React9.useState(null);
191
- const [threadEvents, setThreadEvents] = React9.useState([]);
192
- const [isLoadingEvents, setIsLoadingEvents] = React9.useState(false);
193
- const fetchThreads = React9.useCallback(async () => {
191
+ const [isLoading, setIsLoading] = React11.useState(true);
192
+ const [error, setError] = React11.useState(null);
193
+ const [threadEvents, setThreadEvents] = React11.useState([]);
194
+ const [isLoadingEvents, setIsLoadingEvents] = React11.useState(false);
195
+ const fetchThreads = React11.useCallback(async () => {
194
196
  setIsLoading(true);
195
197
  setError(null);
196
198
  try {
@@ -204,13 +206,13 @@ var ThreadProvider = ({
204
206
  setIsLoading(false);
205
207
  }
206
208
  }, [service]);
207
- React9.useEffect(() => {
209
+ React11.useEffect(() => {
208
210
  fetchThreads();
209
211
  }, [fetchThreads]);
210
- const selectThread = React9.useCallback((threadId) => {
212
+ const selectThread = React11.useCallback((threadId) => {
211
213
  setActiveThreadId(threadId);
212
214
  }, []);
213
- const createThread = React9.useCallback(async () => {
215
+ const createThread = React11.useCallback(async () => {
214
216
  const newId = service.createThread ? await service.createThread() : client.generateId();
215
217
  const newThread = {
216
218
  id: newId,
@@ -220,7 +222,7 @@ var ThreadProvider = ({
220
222
  setActiveThreadId(newId);
221
223
  return newId;
222
224
  }, [service]);
223
- const deleteThread = React9.useCallback(
225
+ const deleteThread = React11.useCallback(
224
226
  async (threadId) => {
225
227
  try {
226
228
  await service.deleteThread(threadId);
@@ -242,10 +244,10 @@ var ThreadProvider = ({
242
244
  },
243
245
  [service]
244
246
  );
245
- const refreshThreads = React9.useCallback(async () => {
247
+ const refreshThreads = React11.useCallback(async () => {
246
248
  await fetchThreads();
247
249
  }, [fetchThreads]);
248
- React9.useEffect(() => {
250
+ React11.useEffect(() => {
249
251
  if (!activeThreadId) {
250
252
  setThreadEvents([]);
251
253
  setIsLoadingEvents(false);
@@ -275,7 +277,7 @@ var ThreadProvider = ({
275
277
  cancelled = true;
276
278
  };
277
279
  }, [activeThreadId, service]);
278
- const value = React9.useMemo(
280
+ const value = React11.useMemo(
279
281
  () => ({
280
282
  threads,
281
283
  activeThreadId,
@@ -303,14 +305,66 @@ var ThreadProvider = ({
303
305
  );
304
306
  return /* @__PURE__ */ jsxRuntime.jsx(ThreadContext.Provider, { value, children });
305
307
  };
308
+ var ThemeContext = React11.createContext(void 0);
309
+ function ThemeProvider({ children }) {
310
+ const [theme, setThemeState] = React11.useState("system");
311
+ const [resolvedTheme, setResolvedTheme] = React11.useState("light");
312
+ React11.useEffect(() => {
313
+ if (typeof window !== "undefined") {
314
+ const stored = localStorage.getItem("theme");
315
+ if (stored) {
316
+ setThemeState(stored);
317
+ }
318
+ }
319
+ }, []);
320
+ React11.useEffect(() => {
321
+ if (typeof window !== "undefined") {
322
+ if (theme === "system") {
323
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
324
+ const updateResolvedTheme = () => {
325
+ setResolvedTheme(mediaQuery.matches ? "dark" : "light");
326
+ };
327
+ updateResolvedTheme();
328
+ mediaQuery.addEventListener("change", updateResolvedTheme);
329
+ return () => mediaQuery.removeEventListener("change", updateResolvedTheme);
330
+ } else {
331
+ setResolvedTheme(theme);
332
+ }
333
+ }
334
+ }, [theme]);
335
+ React11.useEffect(() => {
336
+ if (typeof window !== "undefined") {
337
+ const root = document.documentElement;
338
+ if (resolvedTheme === "dark") {
339
+ root.classList.add("dark");
340
+ } else {
341
+ root.classList.remove("dark");
342
+ }
343
+ }
344
+ }, [resolvedTheme]);
345
+ const setTheme = (newTheme) => {
346
+ setThemeState(newTheme);
347
+ if (typeof window !== "undefined") {
348
+ localStorage.setItem("theme", newTheme);
349
+ }
350
+ };
351
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: { theme, setTheme, resolvedTheme }, children });
352
+ }
353
+ function useTheme() {
354
+ const context = React11.useContext(ThemeContext);
355
+ if (context === void 0) {
356
+ throw new Error("useTheme must be used within a ThemeProvider");
357
+ }
358
+ return context;
359
+ }
306
360
  var useMelony = (options) => {
307
- const context = React9.useContext(MelonyContext);
361
+ const context = React11.useContext(MelonyContext);
308
362
  if (context === void 0) {
309
363
  throw new Error("useMelony must be used within a MelonyClientProvider");
310
364
  }
311
365
  const { client, reset } = context;
312
366
  const { initialEvents } = options || {};
313
- React9.useEffect(() => {
367
+ React11.useEffect(() => {
314
368
  if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
315
369
  reset(initialEvents);
316
370
  }
@@ -318,19 +372,326 @@ var useMelony = (options) => {
318
372
  return context;
319
373
  };
320
374
  var useAuth = () => {
321
- const context = React9.useContext(AuthContext);
375
+ const context = React11.useContext(AuthContext);
322
376
  if (context === void 0) {
323
377
  throw new Error("useAuth must be used within an AuthProvider");
324
378
  }
325
379
  return context;
326
380
  };
327
381
  var useThreads = () => {
328
- const context = React9.useContext(ThreadContext);
382
+ const context = React11.useContext(ThreadContext);
329
383
  if (context === void 0) {
330
384
  throw new Error("useThreads must be used within a ThreadProvider");
331
385
  }
332
386
  return context;
333
387
  };
388
+ function cn(...inputs) {
389
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
390
+ }
391
+ var buttonVariants = classVarianceAuthority.cva(
392
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
393
+ {
394
+ variants: {
395
+ variant: {
396
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
397
+ outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
398
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
399
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
400
+ destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
401
+ link: "text-primary underline-offset-4 hover:underline"
402
+ },
403
+ size: {
404
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
405
+ xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
406
+ sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
407
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
408
+ icon: "size-9",
409
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
410
+ "icon-sm": "size-8",
411
+ "icon-lg": "size-10"
412
+ }
413
+ },
414
+ defaultVariants: {
415
+ variant: "default",
416
+ size: "default"
417
+ }
418
+ }
419
+ );
420
+ function Button({
421
+ className,
422
+ variant = "default",
423
+ size = "default",
424
+ ...props
425
+ }) {
426
+ return /* @__PURE__ */ jsxRuntime.jsx(
427
+ button.Button,
428
+ {
429
+ "data-slot": "button",
430
+ className: cn(buttonVariants({ variant, size, className })),
431
+ ...props
432
+ }
433
+ );
434
+ }
435
+ function Textarea({ className, ...props }) {
436
+ return /* @__PURE__ */ jsxRuntime.jsx(
437
+ "textarea",
438
+ {
439
+ "data-slot": "textarea",
440
+ className: cn(
441
+ "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
442
+ className
443
+ ),
444
+ ...props
445
+ }
446
+ );
447
+ }
448
+ function DropdownMenu({ ...props }) {
449
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
450
+ }
451
+ function DropdownMenuTrigger({ ...props }) {
452
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
453
+ }
454
+ function DropdownMenuContent({
455
+ align = "start",
456
+ alignOffset = 0,
457
+ side = "bottom",
458
+ sideOffset = 4,
459
+ className,
460
+ ...props
461
+ }) {
462
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
463
+ menu.Menu.Positioner,
464
+ {
465
+ className: "isolate z-50 outline-none",
466
+ align,
467
+ alignOffset,
468
+ side,
469
+ sideOffset,
470
+ children: /* @__PURE__ */ jsxRuntime.jsx(
471
+ menu.Menu.Popup,
472
+ {
473
+ "data-slot": "dropdown-menu-content",
474
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 bg-popover text-popover-foreground min-w-48 rounded-2xl p-1 shadow-2xl ring-1 duration-100 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden", className),
475
+ ...props
476
+ }
477
+ )
478
+ }
479
+ ) });
480
+ }
481
+ function DropdownMenuGroup({ ...props }) {
482
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
483
+ }
484
+ function DropdownMenuLabel({
485
+ className,
486
+ inset,
487
+ ...props
488
+ }) {
489
+ return /* @__PURE__ */ jsxRuntime.jsx(
490
+ menu.Menu.GroupLabel,
491
+ {
492
+ "data-slot": "dropdown-menu-label",
493
+ "data-inset": inset,
494
+ className: cn("text-muted-foreground px-3 py-2.5 text-xs data-[inset]:pl-8", className),
495
+ ...props
496
+ }
497
+ );
498
+ }
499
+ function DropdownMenuItem({
500
+ className,
501
+ inset,
502
+ variant = "default",
503
+ ...props
504
+ }) {
505
+ return /* @__PURE__ */ jsxRuntime.jsx(
506
+ menu.Menu.Item,
507
+ {
508
+ "data-slot": "dropdown-menu-item",
509
+ "data-inset": inset,
510
+ "data-variant": variant,
511
+ className: cn(
512
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
513
+ className
514
+ ),
515
+ ...props
516
+ }
517
+ );
518
+ }
519
+ function DropdownMenuCheckboxItem({
520
+ className,
521
+ children,
522
+ checked,
523
+ ...props
524
+ }) {
525
+ return /* @__PURE__ */ jsxRuntime.jsxs(
526
+ menu.Menu.CheckboxItem,
527
+ {
528
+ "data-slot": "dropdown-menu-checkbox-item",
529
+ className: cn(
530
+ "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-xl py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
531
+ className
532
+ ),
533
+ checked,
534
+ ...props,
535
+ children: [
536
+ /* @__PURE__ */ jsxRuntime.jsx(
537
+ "span",
538
+ {
539
+ className: "pointer-events-none absolute right-2 flex items-center justify-center pointer-events-none",
540
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
541
+ children: /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(
542
+ ICONS.IconCheck,
543
+ {}
544
+ ) })
545
+ }
546
+ ),
547
+ children
548
+ ]
549
+ }
550
+ );
551
+ }
552
+ function DropdownMenuSeparator({
553
+ className,
554
+ ...props
555
+ }) {
556
+ return /* @__PURE__ */ jsxRuntime.jsx(
557
+ menu.Menu.Separator,
558
+ {
559
+ "data-slot": "dropdown-menu-separator",
560
+ className: cn("bg-border/50 -mx-1 my-1 h-px", className),
561
+ ...props
562
+ }
563
+ );
564
+ }
565
+ function Composer({
566
+ value,
567
+ onChange,
568
+ onSubmit,
569
+ placeholder = "Type a message...",
570
+ isLoading,
571
+ className,
572
+ options = [],
573
+ autoFocus = false,
574
+ defaultSelectedIds = []
575
+ }) {
576
+ const [selectedOptions, setSelectedOptions] = React11__namespace.default.useState(
577
+ () => new Set(defaultSelectedIds)
578
+ );
579
+ const toggleOption = (id, groupOptions, type = "multiple") => {
580
+ const next = new Set(selectedOptions);
581
+ if (type === "single") {
582
+ const isAlreadySelected = next.has(id);
583
+ if (groupOptions) {
584
+ groupOptions.forEach((o) => next.delete(o.id));
585
+ }
586
+ if (!isAlreadySelected) {
587
+ next.add(id);
588
+ }
589
+ } else {
590
+ if (next.has(id)) {
591
+ next.delete(id);
592
+ } else {
593
+ next.add(id);
594
+ }
595
+ }
596
+ setSelectedOptions(next);
597
+ };
598
+ const handleInternalSubmit = () => {
599
+ const state = {};
600
+ options.forEach((group) => {
601
+ const selectedInGroup = group.options.filter(
602
+ (o) => selectedOptions.has(o.id)
603
+ );
604
+ if (selectedInGroup.length > 0) {
605
+ if (group.type === "single") {
606
+ state[group.id] = selectedInGroup[0].value;
607
+ } else {
608
+ state[group.id] = selectedInGroup.map((o) => ({
609
+ id: o.id,
610
+ value: o.value
611
+ }));
612
+ }
613
+ }
614
+ });
615
+ onSubmit(state);
616
+ };
617
+ const handleKeyDown = (e) => {
618
+ if (e.key === "Enter" && !e.shiftKey) {
619
+ e.preventDefault();
620
+ handleInternalSubmit();
621
+ }
622
+ };
623
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
624
+ /* @__PURE__ */ jsxRuntime.jsx(
625
+ Textarea,
626
+ {
627
+ value,
628
+ onChange: (e) => onChange(e.target.value),
629
+ onKeyDown: handleKeyDown,
630
+ placeholder,
631
+ className: "min-h-[44px] max-h-[200px] border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-3 py-2 text-[15px] resize-none",
632
+ autoFocus
633
+ }
634
+ ),
635
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center px-1", children: [
636
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: options.map((group) => {
637
+ const selectedInGroup = group.options.filter(
638
+ (o) => selectedOptions.has(o.id)
639
+ );
640
+ const label = selectedInGroup.length === 0 ? group.label : selectedInGroup.length === 1 ? selectedInGroup[0].label : `${group.label} (${selectedInGroup.length})`;
641
+ const isSingle = group.type === "single";
642
+ return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx(
644
+ DropdownMenuTrigger,
645
+ {
646
+ render: /* @__PURE__ */ jsxRuntime.jsxs(
647
+ Button,
648
+ {
649
+ variant: "ghost",
650
+ size: "sm",
651
+ className: cn(
652
+ selectedInGroup.length > 0 ? "text-foreground bg-muted/50" : "text-muted-foreground"
653
+ ),
654
+ children: [
655
+ label,
656
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronDown, { className: "h-3 w-3 opacity-50" })
657
+ ]
658
+ }
659
+ )
660
+ }
661
+ ),
662
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "start", className: "w-56", children: /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuGroup, { children: [
663
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuLabel, { children: group.label }),
664
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuSeparator, {}),
665
+ group.options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
666
+ DropdownMenuCheckboxItem,
667
+ {
668
+ checked: selectedOptions.has(option.id),
669
+ onCheckedChange: () => toggleOption(
670
+ option.id,
671
+ group.options,
672
+ isSingle ? "single" : "multiple"
673
+ ),
674
+ onSelect: (e) => e.preventDefault(),
675
+ children: option.label
676
+ },
677
+ option.id
678
+ ))
679
+ ] }) })
680
+ ] }, group.id);
681
+ }) }),
682
+ /* @__PURE__ */ jsxRuntime.jsx(
683
+ Button,
684
+ {
685
+ type: "submit",
686
+ disabled: !value.trim() && !isLoading || isLoading,
687
+ size: "icon-lg",
688
+ onClick: handleInternalSubmit,
689
+ children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLoader2, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowUp, { className: "h-5 w-5" })
690
+ }
691
+ )
692
+ ] })
693
+ ] }) });
694
+ }
334
695
  function Card({
335
696
  className,
336
697
  size = "default",
@@ -399,7 +760,7 @@ var Card2 = ({
399
760
  return /* @__PURE__ */ jsxRuntime.jsxs(
400
761
  Card,
401
762
  {
402
- className: cn("w-full max-w-2xl shadow-sm", className),
763
+ className: cn("min-w-96", className),
403
764
  style,
404
765
  children: [
405
766
  (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "pb-3", children: [
@@ -714,31 +1075,137 @@ var ListItem = ({
714
1075
  }
715
1076
  );
716
1077
  };
717
- var Image = ({
718
- src,
719
- alt,
720
- size = "sm",
1078
+ function Dialog({ ...props }) {
1079
+ return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Root, { "data-slot": "dialog", ...props });
1080
+ }
1081
+ function DialogTrigger({ ...props }) {
1082
+ return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Trigger, { "data-slot": "dialog-trigger", ...props });
1083
+ }
1084
+ function DialogPortal({ ...props }) {
1085
+ return /* @__PURE__ */ jsxRuntime.jsx(dialog.Dialog.Portal, { "data-slot": "dialog-portal", ...props });
1086
+ }
1087
+ function DialogOverlay({
721
1088
  className,
722
- style
723
- }) => {
724
- const [hasError, setHasError] = React9.useState(false);
725
- const [isLoading, setIsLoading] = React9.useState(true);
726
- const sizes = {
727
- sm: "h-11 w-11",
728
- md: "h-22 w-22",
729
- lg: "h-44 w-44"
730
- };
731
- const handleError = () => {
732
- setHasError(true);
733
- setIsLoading(false);
734
- };
735
- const handleLoad = () => {
736
- setIsLoading(false);
737
- };
738
- if (hasError) {
739
- return /* @__PURE__ */ jsxRuntime.jsx(
740
- "div",
741
- {
1089
+ ...props
1090
+ }) {
1091
+ return /* @__PURE__ */ jsxRuntime.jsx(
1092
+ dialog.Dialog.Backdrop,
1093
+ {
1094
+ "data-slot": "dialog-overlay",
1095
+ className: cn(
1096
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-200 supports-backdrop-filter:backdrop-blur-sm fixed inset-0 isolate z-50",
1097
+ className
1098
+ ),
1099
+ ...props
1100
+ }
1101
+ );
1102
+ }
1103
+ function DialogContent({
1104
+ className,
1105
+ ...props
1106
+ }) {
1107
+ return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1108
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1109
+ /* @__PURE__ */ jsxRuntime.jsx(
1110
+ dialog.Dialog.Popup,
1111
+ {
1112
+ "data-slot": "dialog-content",
1113
+ className: cn(
1114
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg outline-none",
1115
+ className
1116
+ ),
1117
+ ...props
1118
+ }
1119
+ )
1120
+ ] });
1121
+ }
1122
+ function DialogClose({
1123
+ className,
1124
+ ...props
1125
+ }) {
1126
+ return /* @__PURE__ */ jsxRuntime.jsx(
1127
+ dialog.Dialog.Close,
1128
+ {
1129
+ "data-slot": "dialog-close",
1130
+ className: cn(
1131
+ "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
1132
+ className
1133
+ ),
1134
+ ...props
1135
+ }
1136
+ );
1137
+ }
1138
+ function DialogHeader({
1139
+ className,
1140
+ ...props
1141
+ }) {
1142
+ return /* @__PURE__ */ jsxRuntime.jsx(
1143
+ "div",
1144
+ {
1145
+ "data-slot": "dialog-header",
1146
+ className: cn(
1147
+ "flex flex-col space-y-1.5 text-center sm:text-left",
1148
+ className
1149
+ ),
1150
+ ...props
1151
+ }
1152
+ );
1153
+ }
1154
+ function DialogTitle({
1155
+ className,
1156
+ ...props
1157
+ }) {
1158
+ return /* @__PURE__ */ jsxRuntime.jsx(
1159
+ dialog.Dialog.Title,
1160
+ {
1161
+ "data-slot": "dialog-title",
1162
+ className: cn(
1163
+ "text-lg font-semibold leading-none tracking-tight",
1164
+ className
1165
+ ),
1166
+ ...props
1167
+ }
1168
+ );
1169
+ }
1170
+ function DialogDescription({
1171
+ className,
1172
+ ...props
1173
+ }) {
1174
+ return /* @__PURE__ */ jsxRuntime.jsx(
1175
+ dialog.Dialog.Description,
1176
+ {
1177
+ "data-slot": "dialog-description",
1178
+ className: cn("text-sm text-muted-foreground", className),
1179
+ ...props
1180
+ }
1181
+ );
1182
+ }
1183
+ var Image = ({
1184
+ src,
1185
+ alt,
1186
+ size = "sm",
1187
+ className,
1188
+ style
1189
+ }) => {
1190
+ const [hasError, setHasError] = React11.useState(false);
1191
+ const [isLoading, setIsLoading] = React11.useState(true);
1192
+ const [open, setOpen] = React11.useState(false);
1193
+ const sizes = {
1194
+ sm: "h-11",
1195
+ md: "h-22",
1196
+ lg: "h-44"
1197
+ };
1198
+ const handleError = () => {
1199
+ setHasError(true);
1200
+ setIsLoading(false);
1201
+ };
1202
+ const handleLoad = () => {
1203
+ setIsLoading(false);
1204
+ };
1205
+ if (hasError) {
1206
+ return /* @__PURE__ */ jsxRuntime.jsx(
1207
+ "div",
1208
+ {
742
1209
  className: cn(
743
1210
  "flex items-center justify-center rounded-md border bg-muted text-muted-foreground",
744
1211
  sizes[size] || "h-11 w-11",
@@ -749,22 +1216,67 @@ var Image = ({
749
1216
  }
750
1217
  );
751
1218
  }
752
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative overflow-hidden rounded-md border", className), style, children: [
1219
+ return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open, onOpenChange: setOpen, children: [
1220
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTrigger, { children: /* @__PURE__ */ jsxRuntime.jsxs(
1221
+ "div",
1222
+ {
1223
+ className: cn("relative overflow-hidden rounded-md border cursor-pointer", className),
1224
+ style,
1225
+ children: [
1226
+ /* @__PURE__ */ jsxRuntime.jsx(
1227
+ "img",
1228
+ {
1229
+ src,
1230
+ alt,
1231
+ onError: handleError,
1232
+ onLoad: handleLoad,
1233
+ className: cn(
1234
+ "block h-auto w-full transition-opacity duration-200 hover:opacity-90",
1235
+ isLoading ? "opacity-0" : "opacity-100",
1236
+ sizes[size]
1237
+ )
1238
+ }
1239
+ ),
1240
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-muted animate-pulse" })
1241
+ ]
1242
+ }
1243
+ ) }),
753
1244
  /* @__PURE__ */ jsxRuntime.jsx(
754
- "img",
1245
+ DialogContent,
755
1246
  {
756
- src,
757
- alt,
758
- onError: handleError,
759
- onLoad: handleLoad,
760
- className: cn(
761
- "block h-auto w-full transition-opacity duration-200",
762
- isLoading ? "opacity-0" : "opacity-100",
763
- sizes[size]
764
- )
1247
+ className: "max-w-[90vw] max-h-[90vh] p-0 bg-transparent border-none shadow-none",
1248
+ onClick: (e) => e.stopPropagation(),
1249
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center", children: [
1250
+ /* @__PURE__ */ jsxRuntime.jsx(DialogClose, { className: "absolute -top-10 right-0 text-white hover:text-gray-300 transition-colors z-10 bg-black/50 rounded-full p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
1251
+ "svg",
1252
+ {
1253
+ xmlns: "http://www.w3.org/2000/svg",
1254
+ className: "h-5 w-5",
1255
+ fill: "none",
1256
+ viewBox: "0 0 24 24",
1257
+ stroke: "currentColor",
1258
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1259
+ "path",
1260
+ {
1261
+ strokeLinecap: "round",
1262
+ strokeLinejoin: "round",
1263
+ strokeWidth: 2,
1264
+ d: "M6 18L18 6M6 6l12 12"
1265
+ }
1266
+ )
1267
+ }
1268
+ ) }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx(
1270
+ "img",
1271
+ {
1272
+ src,
1273
+ alt: alt || "Enlarged image",
1274
+ className: "max-w-full max-h-[90vh] object-contain rounded-lg"
1275
+ }
1276
+ )
1277
+ ] })
765
1278
  }
766
- ),
767
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-muted animate-pulse" })
1279
+ )
768
1280
  ] });
769
1281
  };
770
1282
  var Icon = ({
@@ -875,7 +1387,7 @@ var Chart = ({
875
1387
  className,
876
1388
  style
877
1389
  }) => {
878
- const [tooltip, setTooltip] = React9.useState(null);
1390
+ const [tooltip, setTooltip] = React11.useState(null);
879
1391
  if (!Array.isArray(data)) {
880
1392
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-destructive border border-destructive/20 rounded-md bg-destructive/5", children: "Error: Chart data must be an array" });
881
1393
  }
@@ -1220,19 +1732,6 @@ var Input2 = ({
1220
1732
  )
1221
1733
  ] });
1222
1734
  };
1223
- function Textarea({ className, ...props }) {
1224
- return /* @__PURE__ */ jsxRuntime.jsx(
1225
- "textarea",
1226
- {
1227
- "data-slot": "textarea",
1228
- className: cn(
1229
- "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
1230
- className
1231
- ),
1232
- ...props
1233
- }
1234
- );
1235
- }
1236
1735
  var Textarea2 = ({
1237
1736
  placeholder,
1238
1737
  defaultValue,
@@ -1604,50 +2103,6 @@ var RadioGroup = ({
1604
2103
  )
1605
2104
  ] });
1606
2105
  };
1607
- var buttonVariants = classVarianceAuthority.cva(
1608
- "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
1609
- {
1610
- variants: {
1611
- variant: {
1612
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
1613
- outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
1614
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
1615
- ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
1616
- destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
1617
- link: "text-primary underline-offset-4 hover:underline"
1618
- },
1619
- size: {
1620
- default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
1621
- xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
1622
- sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
1623
- lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
1624
- icon: "size-9",
1625
- "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
1626
- "icon-sm": "size-8",
1627
- "icon-lg": "size-10"
1628
- }
1629
- },
1630
- defaultVariants: {
1631
- variant: "default",
1632
- size: "default"
1633
- }
1634
- }
1635
- );
1636
- function Button({
1637
- className,
1638
- variant = "default",
1639
- size = "default",
1640
- ...props
1641
- }) {
1642
- return /* @__PURE__ */ jsxRuntime.jsx(
1643
- button.Button,
1644
- {
1645
- "data-slot": "button",
1646
- className: cn(buttonVariants({ variant, size, className })),
1647
- ...props
1648
- }
1649
- );
1650
- }
1651
2106
  var Button2 = ({
1652
2107
  label,
1653
2108
  variant = "primary",
@@ -1664,6 +2119,8 @@ var Button2 = ({
1664
2119
  secondary: "secondary",
1665
2120
  danger: "destructive",
1666
2121
  outline: "outline",
2122
+ ghost: "ghost",
2123
+ link: "link",
1667
2124
  success: "default"
1668
2125
  // Success doesn't have a direct shadcn mapping in base variant, default is usually primary
1669
2126
  };
@@ -1686,7 +2143,7 @@ var Button2 = ({
1686
2143
  };
1687
2144
  var Form = ({ children, onSubmitAction, className, style }) => {
1688
2145
  const { sendEvent } = useMelony();
1689
- const [isSubmitted, setIsSubmitted] = React9.useState(false);
2146
+ const [isSubmitted, setIsSubmitted] = React11.useState(false);
1690
2147
  const handleSubmit = (e) => {
1691
2148
  e.preventDefault();
1692
2149
  if (isSubmitted) return;
@@ -1732,6 +2189,32 @@ var Form = ({ children, onSubmitAction, className, style }) => {
1732
2189
  }
1733
2190
  );
1734
2191
  };
2192
+ function StarterPrompts({
2193
+ prompts,
2194
+ onPromptClick
2195
+ }) {
2196
+ if (!prompts || prompts.length === 0) {
2197
+ return null;
2198
+ }
2199
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-4 animate-in fade-in slide-in-from-bottom-4 duration-500 mt-auto max-w-2xl", children: [
2200
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
2201
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2 w-full", children: prompts.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
2202
+ Button2,
2203
+ {
2204
+ label: item.label,
2205
+ variant: "ghost",
2206
+ size: "lg",
2207
+ onClickAction: {
2208
+ type: "text",
2209
+ role: "user",
2210
+ data: { content: item.prompt }
2211
+ },
2212
+ className: "w-full justify-start"
2213
+ },
2214
+ index
2215
+ )) })
2216
+ ] });
2217
+ }
1735
2218
  function UIRenderer({ node }) {
1736
2219
  const { type, props, children } = node;
1737
2220
  const typeMap = {
@@ -1770,69 +2253,108 @@ function UIRenderer({ node }) {
1770
2253
  const componentProps = { ...props };
1771
2254
  return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...componentProps, children: renderedChildren });
1772
2255
  }
1773
- function Composer({
1774
- value,
1775
- onChange,
1776
- onSubmit,
1777
- placeholder = "Type a message...",
1778
- isLoading,
1779
- className
1780
- }) {
1781
- const handleKeyDown = (e) => {
1782
- if (e.key === "Enter" && !e.shiftKey) {
1783
- e.preventDefault();
1784
- onSubmit();
2256
+ function MessageContent({ events }) {
2257
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: events.map((event, index) => {
2258
+ if (event.type === "text-delta") {
2259
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.data?.delta }, index);
1785
2260
  }
1786
- };
1787
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
1788
- /* @__PURE__ */ jsxRuntime.jsx(
1789
- Textarea,
1790
- {
1791
- value,
1792
- onChange: (e) => onChange(e.target.value),
1793
- onKeyDown: handleKeyDown,
1794
- placeholder,
1795
- className: "min-h-[44px] max-h-[200px] border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-3 py-2 text-[15px] resize-none"
1796
- }
1797
- ),
1798
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end items-center px-2 pb-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
1799
- Button,
1800
- {
1801
- type: "submit",
1802
- disabled: !value.trim() && !isLoading || isLoading,
1803
- size: "icon",
1804
- onClick: () => onSubmit(),
1805
- className: cn(
1806
- "h-8 w-8 rounded-full transition-all shrink-0",
1807
- value.trim() ? "bg-foreground text-background hover:bg-foreground/90" : "bg-muted-foreground/20 text-muted-foreground/40"
1808
- ),
1809
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowUp, { className: "h-5 w-5" })
1810
- }
1811
- ) })
1812
- ] }) });
2261
+ if (event.type === "text") {
2262
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: event.data?.content || event.data?.text }, index);
2263
+ }
2264
+ if (event.ui) {
2265
+ return /* @__PURE__ */ jsxRuntime.jsx(UIRenderer, { node: event.ui }, index);
2266
+ }
2267
+ return null;
2268
+ }) });
2269
+ }
2270
+ function MessageBubble({ message }) {
2271
+ const isUser = message.role === "user";
2272
+ return /* @__PURE__ */ jsxRuntime.jsx(
2273
+ "div",
2274
+ {
2275
+ className: cn(
2276
+ "flex flex-col",
2277
+ isUser ? "items-end" : "items-start"
2278
+ ),
2279
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2280
+ "div",
2281
+ {
2282
+ className: cn(
2283
+ "flex flex-col items-start max-w-[85%] rounded-2xl px-4 py-2 space-y-4 whitespace-pre-wrap",
2284
+ isUser ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
2285
+ ),
2286
+ children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { events: message.content })
2287
+ }
2288
+ )
2289
+ }
2290
+ );
2291
+ }
2292
+ function LoadingIndicator({ status }) {
2293
+ const [isExpanded, setIsExpanded] = React11.useState(false);
2294
+ const message = status?.message || "Processing...";
2295
+ const details = status?.details;
2296
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
2297
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-muted-foreground group", children: [
2298
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLoader2, { className: "size-3.5 animate-spin" }),
2299
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "animate-pulse", children: message }),
2300
+ details && /* @__PURE__ */ jsxRuntime.jsx(
2301
+ "button",
2302
+ {
2303
+ onClick: () => setIsExpanded(!isExpanded),
2304
+ className: "p-0.5 hover:bg-muted rounded-sm transition-colors flex items-center justify-center",
2305
+ title: isExpanded ? "Hide details" : "Show details",
2306
+ children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronUp, { className: "size-3.5 opacity-50 group-hover:opacity-100" }) : /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronDown, { className: "size-3.5 opacity-50 group-hover:opacity-100" })
2307
+ }
2308
+ )
2309
+ ] }),
2310
+ isExpanded && details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[10px] leading-relaxed font-mono bg-muted/30 p-2.5 rounded border border-border/50 max-h-64 overflow-y-auto whitespace-pre-wrap text-muted-foreground shadow-sm", children: details })
2311
+ ] });
2312
+ }
2313
+ function ErrorDisplay({ error }) {
2314
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message });
2315
+ }
2316
+ function MessageList({ messages, isLoading, error, loadingStatus }) {
2317
+ if (messages.length === 0) {
2318
+ return null;
2319
+ }
2320
+ const isTextStreaming = React11.useMemo(() => {
2321
+ if (messages.length === 0 || !isLoading) return false;
2322
+ const lastMessage = messages[messages.length - 1];
2323
+ return lastMessage.content.some((event) => event.type === "text-delta");
2324
+ }, [messages, isLoading]);
2325
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
2326
+ messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { message }, index)),
2327
+ isLoading && !isTextStreaming && /* @__PURE__ */ jsxRuntime.jsx(LoadingIndicator, { status: loadingStatus }),
2328
+ error && /* @__PURE__ */ jsxRuntime.jsx(ErrorDisplay, { error })
2329
+ ] });
1813
2330
  }
1814
2331
  function Thread({
1815
2332
  className,
1816
2333
  placeholder = "Type a message...",
1817
2334
  starterPrompts,
1818
- onStarterPromptClick
2335
+ onStarterPromptClick,
2336
+ options,
2337
+ autoFocus = false,
2338
+ defaultSelectedIds
1819
2339
  }) {
1820
- const { messages, isLoading, error, sendEvent } = useMelony();
1821
- const [input, setInput] = React9.useState("");
1822
- const messagesEndRef = React9.useRef(null);
1823
- React9.useEffect(() => {
2340
+ const { messages, isLoading, error, sendEvent, loadingStatus } = useMelony();
2341
+ const [input, setInput] = React11.useState("");
2342
+ const messagesEndRef = React11.useRef(null);
2343
+ React11.useEffect(() => {
1824
2344
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1825
2345
  }, [messages]);
1826
- const handleSubmit = async (e, overrideInput) => {
1827
- e?.preventDefault();
2346
+ const handleSubmit = async (state, overrideInput) => {
1828
2347
  const text = (overrideInput ?? input).trim();
1829
2348
  if (!text || isLoading) return;
1830
2349
  if (!overrideInput) setInput("");
1831
- await sendEvent({
1832
- type: "text",
1833
- role: "user",
1834
- data: { content: text }
1835
- });
2350
+ await sendEvent(
2351
+ {
2352
+ type: "text",
2353
+ role: "user",
2354
+ data: { content: text }
2355
+ },
2356
+ { state }
2357
+ );
1836
2358
  };
1837
2359
  const handleStarterPromptClick = (prompt) => {
1838
2360
  if (onStarterPromptClick) {
@@ -1841,66 +2363,73 @@ function Thread({
1841
2363
  handleSubmit(void 0, prompt);
1842
2364
  }
1843
2365
  };
1844
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full bg-background", className), children: [
1845
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
1846
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto w-full", children: [
1847
- messages.length === 0 && starterPrompts && starterPrompts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[300px] space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
1848
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
1849
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 w-full max-w-2xl px-4", children: starterPrompts.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1850
- "button",
2366
+ const showStarterPrompts = messages.length === 0 && starterPrompts && starterPrompts.length > 0;
2367
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2368
+ "div",
2369
+ {
2370
+ className: cn("relative flex flex-col h-full bg-background", className),
2371
+ children: [
2372
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 pb-36", children: [
2373
+ /* @__PURE__ */ jsxRuntime.jsxs(
2374
+ "div",
1851
2375
  {
1852
- onClick: () => handleStarterPromptClick(item.prompt),
1853
- className: "flex items-center gap-3 p-4 rounded-xl border bg-card hover:bg-muted/50 transition-all text-left group",
2376
+ className: cn(
2377
+ "max-w-4xl mx-auto w-full p-4",
2378
+ showStarterPrompts && "min-h-full flex flex-col"
2379
+ ),
1854
2380
  children: [
1855
- item.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 rounded-lg bg-muted group-hover:bg-background transition-colors", children: item.icon }),
1856
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: item.label })
2381
+ showStarterPrompts && /* @__PURE__ */ jsxRuntime.jsx(
2382
+ StarterPrompts,
2383
+ {
2384
+ prompts: starterPrompts,
2385
+ onPromptClick: handleStarterPromptClick
2386
+ }
2387
+ ),
2388
+ /* @__PURE__ */ jsxRuntime.jsx(
2389
+ MessageList,
2390
+ {
2391
+ messages,
2392
+ isLoading,
2393
+ error,
2394
+ loadingStatus
2395
+ }
2396
+ )
1857
2397
  ]
1858
- },
1859
- i
1860
- )) })
2398
+ }
2399
+ ),
2400
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1861
2401
  ] }),
1862
- messages.map((message, i) => /* @__PURE__ */ jsxRuntime.jsx(
1863
- "div",
2402
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 p-4 w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
2403
+ Composer,
1864
2404
  {
1865
- className: cn(
1866
- "flex flex-col",
1867
- message.role === "user" ? "items-end" : "items-start"
1868
- ),
1869
- children: /* @__PURE__ */ jsxRuntime.jsx(
1870
- "div",
1871
- {
1872
- className: cn(
1873
- "max-w-[85%] rounded-2xl px-4 py-2 space-y-2",
1874
- message.role === "user" ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
1875
- ),
1876
- children: message.content.map((event, j) => {
1877
- if (event.type === "text-delta")
1878
- return /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.data?.delta }, j);
1879
- if (event.type === "text")
1880
- return /* @__PURE__ */ jsxRuntime.jsx("p", { children: event.data?.content || event.data?.text }, j);
1881
- if (event.ui) return /* @__PURE__ */ jsxRuntime.jsx(UIRenderer, { node: event.ui }, j);
1882
- return null;
1883
- })
1884
- }
1885
- )
1886
- },
1887
- i
1888
- )),
1889
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." }),
1890
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message })
1891
- ] }),
1892
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1893
- ] }),
1894
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-t w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
1895
- Composer,
1896
- {
1897
- value: input,
1898
- onChange: setInput,
1899
- onSubmit: handleSubmit,
1900
- placeholder,
1901
- isLoading
1902
- }
1903
- ) }) })
2405
+ value: input,
2406
+ onChange: setInput,
2407
+ onSubmit: handleSubmit,
2408
+ placeholder,
2409
+ isLoading,
2410
+ options,
2411
+ autoFocus,
2412
+ defaultSelectedIds
2413
+ }
2414
+ ) }) })
2415
+ ]
2416
+ }
2417
+ );
2418
+ }
2419
+ function ChatHeader({
2420
+ title,
2421
+ leftContent,
2422
+ rightContent,
2423
+ className,
2424
+ titleClassName,
2425
+ children
2426
+ }) {
2427
+ if (children) {
2428
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-4 border-b border-border h-14 flex items-center shrink-0", className), children });
2429
+ }
2430
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("p-4 border-b border-border h-14 flex items-center justify-between shrink-0", className), children: [
2431
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: leftContent }),
2432
+ rightContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: rightContent })
1904
2433
  ] });
1905
2434
  }
1906
2435
  var ThreadList = ({
@@ -1908,13 +2437,7 @@ var ThreadList = ({
1908
2437
  emptyState,
1909
2438
  onThreadSelect
1910
2439
  }) => {
1911
- const {
1912
- threads,
1913
- activeThreadId,
1914
- selectThread,
1915
- createThread,
1916
- deleteThread
1917
- } = useThreads();
2440
+ const { threads, activeThreadId, selectThread, createThread, deleteThread } = useThreads();
1918
2441
  const handleThreadClick = (threadId) => {
1919
2442
  if (threadId !== activeThreadId) {
1920
2443
  selectThread(threadId);
@@ -1952,10 +2475,10 @@ var ThreadList = ({
1952
2475
  return d.toLocaleDateString();
1953
2476
  };
1954
2477
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full", className), children: [
1955
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs(
2478
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
1956
2479
  Button,
1957
2480
  {
1958
- variant: "outline",
2481
+ variant: "ghost",
1959
2482
  size: "sm",
1960
2483
  onClick: handleNewThread,
1961
2484
  className: "w-full justify-start",
@@ -1976,31 +2499,13 @@ var ThreadList = ({
1976
2499
  {
1977
2500
  onClick: () => handleThreadClick(thread.id),
1978
2501
  className: cn(
1979
- "group relative flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors",
1980
- isActive ? "bg-primary text-primary-foreground" : "hover:bg-muted"
2502
+ "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2503
+ isActive ? "bg-muted" : "hover:bg-muted"
1981
2504
  ),
1982
2505
  children: [
1983
2506
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1984
- /* @__PURE__ */ jsxRuntime.jsx(
1985
- "p",
1986
- {
1987
- className: cn(
1988
- "text-sm font-medium truncate",
1989
- isActive && "text-primary-foreground"
1990
- ),
1991
- children: thread.title || `Thread ${thread.id.slice(0, 8)}`
1992
- }
1993
- ),
1994
- thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx(
1995
- "span",
1996
- {
1997
- className: cn(
1998
- "text-xs shrink-0",
1999
- isActive ? "text-primary-foreground/70" : "text-muted-foreground"
2000
- ),
2001
- children: formatDate(thread.updatedAt)
2002
- }
2003
- )
2507
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm font-medium truncate"), children: thread.title || `Thread ${thread.id.slice(0, 8)}` }),
2508
+ thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs shrink-0"), children: formatDate(thread.updatedAt) })
2004
2509
  ] }) }),
2005
2510
  /* @__PURE__ */ jsxRuntime.jsx(
2006
2511
  Button,
@@ -2026,10 +2531,13 @@ function ChatPopup({
2026
2531
  title = "Chat",
2027
2532
  placeholder = "Message the AI",
2028
2533
  starterPrompts,
2029
- defaultOpen = false
2534
+ options,
2535
+ defaultOpen = false,
2536
+ headerProps,
2537
+ defaultSelectedIds
2030
2538
  }) {
2031
- const [isOpen, setIsOpen] = React9.useState(defaultOpen);
2032
- const [view, setView] = React9.useState("chat");
2539
+ const [isOpen, setIsOpen] = React11.useState(defaultOpen);
2540
+ const [view, setView] = React11.useState("chat");
2033
2541
  const { createThread } = useThreads();
2034
2542
  const handleNewChat = async () => {
2035
2543
  try {
@@ -2040,10 +2548,12 @@ function ChatPopup({
2040
2548
  }
2041
2549
  };
2042
2550
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 font-sans", children: [
2043
- isOpen && /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "py-0 w-[440px] h-[640px] flex flex-col overflow-hidden border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60 shadow-2xl animate-in fade-in zoom-in-95 duration-200 origin-bottom-right", children: [
2044
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "p-4 border-b flex flex-row items-center justify-between space-y-0 h-14 shrink-0", children: [
2045
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2046
- view === "history" && /* @__PURE__ */ jsxRuntime.jsx(
2551
+ isOpen && /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "py-0 w-[440px] h-[640px] gap-0 flex flex-col overflow-hidden border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60 shadow-2xl animate-in fade-in zoom-in-95 duration-200 origin-bottom-right", children: [
2552
+ /* @__PURE__ */ jsxRuntime.jsx(
2553
+ ChatHeader,
2554
+ {
2555
+ title: view === "history" ? "History" : title,
2556
+ leftContent: view === "history" ? /* @__PURE__ */ jsxRuntime.jsx(
2047
2557
  Button,
2048
2558
  {
2049
2559
  variant: "ghost",
@@ -2052,50 +2562,52 @@ function ChatPopup({
2052
2562
  className: "text-muted-foreground hover:text-foreground",
2053
2563
  children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowLeft, { className: "size-4" })
2054
2564
  }
2055
- ),
2056
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-sm font-semibold", children: view === "history" ? "History" : title })
2057
- ] }),
2058
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2059
- view === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
2060
- Button,
2061
- {
2062
- variant: "ghost",
2063
- size: "icon-xs",
2064
- onClick: () => setView("history"),
2065
- className: "text-muted-foreground hover:text-foreground",
2066
- title: "History",
2067
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
2068
- }
2069
- ),
2070
- /* @__PURE__ */ jsxRuntime.jsx(
2071
- Button,
2072
- {
2073
- variant: "ghost",
2074
- size: "icon-xs",
2075
- onClick: handleNewChat,
2076
- className: "text-muted-foreground hover:text-foreground",
2077
- title: "New Chat",
2078
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
2079
- }
2080
- ),
2081
- /* @__PURE__ */ jsxRuntime.jsx(
2082
- Button,
2083
- {
2084
- variant: "ghost",
2085
- size: "icon-xs",
2086
- onClick: () => setIsOpen(false),
2087
- className: "text-muted-foreground hover:text-foreground",
2088
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" })
2089
- }
2090
- )
2091
- ] })
2092
- ] }),
2565
+ ) : void 0,
2566
+ rightContent: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2567
+ view === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
2568
+ Button,
2569
+ {
2570
+ variant: "ghost",
2571
+ size: "icon-xs",
2572
+ onClick: () => setView("history"),
2573
+ className: "text-muted-foreground hover:text-foreground",
2574
+ title: "History",
2575
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
2576
+ }
2577
+ ),
2578
+ /* @__PURE__ */ jsxRuntime.jsx(
2579
+ Button,
2580
+ {
2581
+ variant: "ghost",
2582
+ size: "icon-xs",
2583
+ onClick: handleNewChat,
2584
+ className: "text-muted-foreground hover:text-foreground",
2585
+ title: "New Chat",
2586
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
2587
+ }
2588
+ ),
2589
+ /* @__PURE__ */ jsxRuntime.jsx(
2590
+ Button,
2591
+ {
2592
+ variant: "ghost",
2593
+ size: "icon-xs",
2594
+ onClick: () => setIsOpen(false),
2595
+ className: "text-muted-foreground hover:text-foreground",
2596
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" })
2597
+ }
2598
+ )
2599
+ ] }),
2600
+ ...headerProps
2601
+ }
2602
+ ),
2093
2603
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: view === "chat" ? /* @__PURE__ */ jsxRuntime.jsx(
2094
2604
  Thread,
2095
2605
  {
2096
2606
  placeholder,
2097
2607
  starterPrompts,
2098
- className: "h-full"
2608
+ options,
2609
+ className: "h-full",
2610
+ defaultSelectedIds
2099
2611
  }
2100
2612
  ) : /* @__PURE__ */ jsxRuntime.jsx(
2101
2613
  ThreadList,
@@ -2123,16 +2635,21 @@ function ChatSidebar({
2123
2635
  title = "Chat",
2124
2636
  placeholder = "Message the AI",
2125
2637
  starterPrompts,
2126
- className
2638
+ options,
2639
+ className,
2640
+ headerProps,
2641
+ defaultSelectedIds
2127
2642
  }) {
2128
2643
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2129
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2644
+ /* @__PURE__ */ jsxRuntime.jsx(ChatHeader, { title, ...headerProps }),
2130
2645
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
2131
2646
  Thread,
2132
2647
  {
2133
2648
  placeholder,
2134
2649
  starterPrompts,
2135
- className: "h-full"
2650
+ options,
2651
+ className: "h-full",
2652
+ defaultSelectedIds
2136
2653
  }
2137
2654
  ) })
2138
2655
  ] });
@@ -2141,13 +2658,437 @@ function ChatFull({
2141
2658
  title = "Chat",
2142
2659
  placeholder = "Message the AI",
2143
2660
  starterPrompts,
2144
- className
2661
+ options,
2662
+ className,
2663
+ headerProps,
2664
+ leftSidebar,
2665
+ rightSidebar,
2666
+ leftSidebarClassName,
2667
+ rightSidebarClassName,
2668
+ leftSidebarCollapsible = false,
2669
+ rightSidebarCollapsible = false,
2670
+ defaultLeftSidebarCollapsed = false,
2671
+ defaultRightSidebarCollapsed = false,
2672
+ leftSidebarCollapsed: controlledLeftCollapsed,
2673
+ rightSidebarCollapsed: controlledRightCollapsed,
2674
+ onLeftSidebarCollapseChange,
2675
+ onRightSidebarCollapseChange,
2676
+ autoFocus = false,
2677
+ defaultSelectedIds
2145
2678
  }) {
2679
+ const [internalLeftCollapsed, setInternalLeftCollapsed] = React11.useState(
2680
+ defaultLeftSidebarCollapsed
2681
+ );
2682
+ const [internalRightCollapsed, setInternalRightCollapsed] = React11.useState(
2683
+ defaultRightSidebarCollapsed
2684
+ );
2685
+ const leftCollapsed = controlledLeftCollapsed !== void 0 ? controlledLeftCollapsed : internalLeftCollapsed;
2686
+ const rightCollapsed = controlledRightCollapsed !== void 0 ? controlledRightCollapsed : internalRightCollapsed;
2687
+ const handleLeftToggle = () => {
2688
+ const newCollapsed = !leftCollapsed;
2689
+ if (controlledLeftCollapsed === void 0) {
2690
+ setInternalLeftCollapsed(newCollapsed);
2691
+ }
2692
+ onLeftSidebarCollapseChange?.(newCollapsed);
2693
+ };
2694
+ const handleRightToggle = () => {
2695
+ const newCollapsed = !rightCollapsed;
2696
+ if (controlledRightCollapsed === void 0) {
2697
+ setInternalRightCollapsed(newCollapsed);
2698
+ }
2699
+ onRightSidebarCollapseChange?.(newCollapsed);
2700
+ };
2146
2701
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
2147
- title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2148
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(Thread, { placeholder, starterPrompts }) })
2702
+ title && /* @__PURE__ */ jsxRuntime.jsx(ChatHeader, { title, ...headerProps }),
2703
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
2704
+ leftSidebar && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2705
+ /* @__PURE__ */ jsxRuntime.jsx(
2706
+ "div",
2707
+ {
2708
+ className: cn(
2709
+ "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2710
+ leftCollapsed && leftSidebarCollapsible ? "w-0 border-r-0 min-w-0" : "",
2711
+ !leftCollapsed && leftSidebarClassName
2712
+ ),
2713
+ children: !leftCollapsed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2714
+ leftSidebarCollapsible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2715
+ Button,
2716
+ {
2717
+ variant: "ghost",
2718
+ size: "icon-sm",
2719
+ onClick: handleLeftToggle,
2720
+ "aria-label": "Collapse left sidebar",
2721
+ className: "h-8 w-8",
2722
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronLeft, { className: "h-4 w-4" })
2723
+ }
2724
+ ) }),
2725
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
2726
+ ] })
2727
+ }
2728
+ ),
2729
+ leftSidebarCollapsible && leftCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 border-r border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
2730
+ Button,
2731
+ {
2732
+ variant: "ghost",
2733
+ size: "icon-sm",
2734
+ onClick: handleLeftToggle,
2735
+ "aria-label": "Expand left sidebar",
2736
+ className: "h-8 w-8",
2737
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronRight, { className: "h-4 w-4" })
2738
+ }
2739
+ ) })
2740
+ ] }),
2741
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2742
+ Thread,
2743
+ {
2744
+ placeholder,
2745
+ starterPrompts,
2746
+ options,
2747
+ autoFocus,
2748
+ defaultSelectedIds
2749
+ }
2750
+ ) }),
2751
+ rightSidebar && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2752
+ rightSidebarCollapsible && rightCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 border-l border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
2753
+ Button,
2754
+ {
2755
+ variant: "ghost",
2756
+ size: "icon-sm",
2757
+ onClick: handleRightToggle,
2758
+ "aria-label": "Expand right sidebar",
2759
+ className: "h-8 w-8",
2760
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronLeft, { className: "h-4 w-4" })
2761
+ }
2762
+ ) }),
2763
+ /* @__PURE__ */ jsxRuntime.jsx(
2764
+ "div",
2765
+ {
2766
+ className: cn(
2767
+ "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2768
+ rightCollapsed && rightSidebarCollapsible ? "w-0 border-l-0 min-w-0" : "",
2769
+ !rightCollapsed && rightSidebarClassName
2770
+ ),
2771
+ children: !rightCollapsed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2772
+ rightSidebarCollapsible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-start p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2773
+ Button,
2774
+ {
2775
+ variant: "ghost",
2776
+ size: "icon-sm",
2777
+ onClick: handleRightToggle,
2778
+ "aria-label": "Collapse right sidebar",
2779
+ className: "h-8 w-8",
2780
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronRight, { className: "h-4 w-4" })
2781
+ }
2782
+ ) }),
2783
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
2784
+ ] })
2785
+ }
2786
+ )
2787
+ ] })
2788
+ ] })
2149
2789
  ] });
2150
2790
  }
2791
+ var PopoverContext = React11__namespace.createContext(
2792
+ void 0
2793
+ );
2794
+ function usePopoverContext() {
2795
+ const context = React11__namespace.useContext(PopoverContext);
2796
+ if (!context) {
2797
+ throw new Error("Popover components must be used within a Popover");
2798
+ }
2799
+ return context;
2800
+ }
2801
+ function Popover({
2802
+ children,
2803
+ defaultOpen = false,
2804
+ open: controlledOpen,
2805
+ onOpenChange
2806
+ }) {
2807
+ const [internalOpen, setInternalOpen] = React11__namespace.useState(defaultOpen);
2808
+ const triggerRef = React11__namespace.useRef(null);
2809
+ const open = controlledOpen ?? internalOpen;
2810
+ const setOpen = React11__namespace.useCallback(
2811
+ (newOpen) => {
2812
+ if (controlledOpen === void 0) {
2813
+ setInternalOpen(newOpen);
2814
+ }
2815
+ onOpenChange?.(newOpen);
2816
+ },
2817
+ [controlledOpen, onOpenChange]
2818
+ );
2819
+ const value = React11__namespace.useMemo(
2820
+ () => ({
2821
+ open,
2822
+ setOpen,
2823
+ triggerRef
2824
+ }),
2825
+ [open, setOpen]
2826
+ );
2827
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value, children });
2828
+ }
2829
+ var PopoverTrigger = React11__namespace.forwardRef(
2830
+ ({ asChild, className, children, ...props }, ref) => {
2831
+ const { setOpen, triggerRef } = usePopoverContext();
2832
+ const handleClick = (e) => {
2833
+ setOpen(true);
2834
+ props.onClick?.(e);
2835
+ };
2836
+ if (asChild && React11__namespace.isValidElement(children)) {
2837
+ return React11__namespace.cloneElement(children, {
2838
+ ref: (node) => {
2839
+ triggerRef.current = node;
2840
+ if (typeof children.ref === "function") {
2841
+ children.ref(node);
2842
+ } else if (children.ref) {
2843
+ children.ref.current = node;
2844
+ }
2845
+ },
2846
+ onClick: handleClick
2847
+ });
2848
+ }
2849
+ return /* @__PURE__ */ jsxRuntime.jsx(
2850
+ "button",
2851
+ {
2852
+ ref: (node) => {
2853
+ triggerRef.current = node;
2854
+ if (typeof ref === "function") {
2855
+ ref(node);
2856
+ } else if (ref) {
2857
+ ref.current = node;
2858
+ }
2859
+ },
2860
+ className,
2861
+ onClick: handleClick,
2862
+ ...props,
2863
+ children
2864
+ }
2865
+ );
2866
+ }
2867
+ );
2868
+ PopoverTrigger.displayName = "PopoverTrigger";
2869
+ var PopoverContent = React11__namespace.forwardRef(
2870
+ ({
2871
+ className,
2872
+ side = "bottom",
2873
+ align = "start",
2874
+ sideOffset = 4,
2875
+ alignOffset = 0,
2876
+ children,
2877
+ ...props
2878
+ }, ref) => {
2879
+ const { open, setOpen, triggerRef } = usePopoverContext();
2880
+ const [position, setPosition] = React11__namespace.useState({ top: 0, left: 0 });
2881
+ const contentRef = React11__namespace.useRef(null);
2882
+ React11__namespace.useEffect(() => {
2883
+ if (!open || !triggerRef.current) return;
2884
+ const updatePosition = () => {
2885
+ if (!triggerRef.current || !contentRef.current) return;
2886
+ const triggerRect = triggerRef.current.getBoundingClientRect();
2887
+ const contentRect = contentRef.current.getBoundingClientRect();
2888
+ const scrollX = window.scrollX;
2889
+ const scrollY = window.scrollY;
2890
+ let top = 0;
2891
+ let left = 0;
2892
+ switch (side) {
2893
+ case "bottom":
2894
+ top = triggerRect.bottom + sideOffset + scrollY;
2895
+ break;
2896
+ case "top":
2897
+ top = triggerRect.top - contentRect.height - sideOffset + scrollY;
2898
+ break;
2899
+ case "right":
2900
+ top = triggerRect.top + scrollY;
2901
+ left = triggerRect.right + sideOffset + scrollX;
2902
+ break;
2903
+ case "left":
2904
+ top = triggerRect.top + scrollY;
2905
+ left = triggerRect.left - contentRect.width - sideOffset + scrollX;
2906
+ break;
2907
+ }
2908
+ switch (align) {
2909
+ case "start":
2910
+ if (side === "top" || side === "bottom") {
2911
+ left = triggerRect.left + scrollX + alignOffset;
2912
+ } else {
2913
+ top += alignOffset;
2914
+ }
2915
+ break;
2916
+ case "center":
2917
+ if (side === "top" || side === "bottom") {
2918
+ left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2 + scrollX + alignOffset;
2919
+ } else {
2920
+ top += triggerRect.height / 2 - contentRect.height / 2 + alignOffset;
2921
+ }
2922
+ break;
2923
+ case "end":
2924
+ if (side === "top" || side === "bottom") {
2925
+ left = triggerRect.left + triggerRect.width - contentRect.width + scrollX + alignOffset;
2926
+ } else {
2927
+ top += triggerRect.height - contentRect.height + alignOffset;
2928
+ }
2929
+ break;
2930
+ }
2931
+ setPosition({ top, left });
2932
+ };
2933
+ requestAnimationFrame(() => {
2934
+ updatePosition();
2935
+ });
2936
+ window.addEventListener("resize", updatePosition);
2937
+ window.addEventListener("scroll", updatePosition, true);
2938
+ return () => {
2939
+ window.removeEventListener("resize", updatePosition);
2940
+ window.removeEventListener("scroll", updatePosition, true);
2941
+ };
2942
+ }, [open, side, align, sideOffset, alignOffset, triggerRef]);
2943
+ React11__namespace.useEffect(() => {
2944
+ if (!open) return;
2945
+ const handleClickOutside = (event) => {
2946
+ if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
2947
+ setOpen(false);
2948
+ }
2949
+ };
2950
+ const handleEscape = (event) => {
2951
+ if (event.key === "Escape") {
2952
+ setOpen(false);
2953
+ }
2954
+ };
2955
+ document.addEventListener("mousedown", handleClickOutside);
2956
+ document.addEventListener("keydown", handleEscape);
2957
+ return () => {
2958
+ document.removeEventListener("mousedown", handleClickOutside);
2959
+ document.removeEventListener("keydown", handleEscape);
2960
+ };
2961
+ }, [open, setOpen, triggerRef]);
2962
+ if (!open) return null;
2963
+ const content = /* @__PURE__ */ jsxRuntime.jsx(
2964
+ "div",
2965
+ {
2966
+ ref: (node) => {
2967
+ contentRef.current = node;
2968
+ if (typeof ref === "function") {
2969
+ ref(node);
2970
+ } else if (ref) {
2971
+ ref.current = node;
2972
+ }
2973
+ },
2974
+ className: cn(
2975
+ "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/5 rounded-2xl shadow-2xl ring-1 z-50 min-w-48 max-h-96 overflow-hidden",
2976
+ className
2977
+ ),
2978
+ style: {
2979
+ position: "absolute",
2980
+ top: `${position.top}px`,
2981
+ left: `${position.left}px`
2982
+ },
2983
+ ...props,
2984
+ children
2985
+ }
2986
+ );
2987
+ return reactDom.createPortal(content, document.body);
2988
+ }
2989
+ );
2990
+ PopoverContent.displayName = "PopoverContent";
2991
+ var ThreadPopover = ({
2992
+ className,
2993
+ buttonClassName,
2994
+ buttonVariant = "ghost",
2995
+ buttonSize = "icon",
2996
+ emptyState,
2997
+ onThreadSelect
2998
+ }) => {
2999
+ const [isOpen, setIsOpen] = React11__namespace.useState(false);
3000
+ reactHotkeysHook.useHotkeys(
3001
+ "h",
3002
+ (e) => {
3003
+ e.preventDefault();
3004
+ setIsOpen((prev) => !prev);
3005
+ },
3006
+ {
3007
+ enableOnFormTags: false,
3008
+ // Don't trigger when typing in form inputs
3009
+ enableOnContentEditable: false
3010
+ // Don't trigger in contenteditable elements
3011
+ }
3012
+ );
3013
+ const handleThreadSelect = (threadId) => {
3014
+ setIsOpen(false);
3015
+ onThreadSelect?.(threadId);
3016
+ };
3017
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
3018
+ /* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3019
+ Button,
3020
+ {
3021
+ variant: buttonVariant,
3022
+ size: buttonSize,
3023
+ className: cn(buttonClassName),
3024
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
3025
+ }
3026
+ ) }),
3027
+ /* @__PURE__ */ jsxRuntime.jsx(
3028
+ PopoverContent,
3029
+ {
3030
+ className: cn("w-80 p-0", className),
3031
+ side: "bottom",
3032
+ align: "start",
3033
+ sideOffset: 8,
3034
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col h-[400px]", children: /* @__PURE__ */ jsxRuntime.jsx(
3035
+ ThreadList,
3036
+ {
3037
+ emptyState,
3038
+ onThreadSelect: handleThreadSelect,
3039
+ className: "h-full"
3040
+ }
3041
+ ) })
3042
+ }
3043
+ )
3044
+ ] });
3045
+ };
3046
+ var CreateThreadButton = ({
3047
+ className,
3048
+ variant = "ghost",
3049
+ size = "icon",
3050
+ children,
3051
+ onThreadCreated
3052
+ }) => {
3053
+ const { createThread } = useThreads();
3054
+ const [isCreating, setIsCreating] = React11__namespace.useState(false);
3055
+ const handleCreateThread = async () => {
3056
+ if (isCreating) return;
3057
+ try {
3058
+ setIsCreating(true);
3059
+ const threadId = await createThread();
3060
+ onThreadCreated?.(threadId);
3061
+ } catch (error) {
3062
+ console.error("Failed to create thread:", error);
3063
+ } finally {
3064
+ setIsCreating(false);
3065
+ }
3066
+ };
3067
+ reactHotkeysHook.useHotkeys(
3068
+ "n",
3069
+ (e) => {
3070
+ e.preventDefault();
3071
+ handleCreateThread();
3072
+ },
3073
+ {
3074
+ enableOnFormTags: false,
3075
+ // Don't trigger when typing in form inputs
3076
+ enableOnContentEditable: false
3077
+ // Don't trigger in contenteditable elements
3078
+ }
3079
+ );
3080
+ return /* @__PURE__ */ jsxRuntime.jsx(
3081
+ Button,
3082
+ {
3083
+ variant,
3084
+ size,
3085
+ onClick: handleCreateThread,
3086
+ disabled: isCreating,
3087
+ className: cn(className),
3088
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
3089
+ }
3090
+ );
3091
+ };
2151
3092
  function AlertDialog({ ...props }) {
2152
3093
  return /* @__PURE__ */ jsxRuntime.jsx(alertDialog.AlertDialog.Root, { "data-slot": "alert-dialog", ...props });
2153
3094
  }
@@ -2230,100 +3171,111 @@ function AlertDialogDescription({
2230
3171
  }
2231
3172
  );
2232
3173
  }
2233
- function DropdownMenu({ ...props }) {
2234
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
2235
- }
2236
- function DropdownMenuTrigger({ ...props }) {
2237
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
2238
- }
2239
- function DropdownMenuContent({
2240
- align = "start",
2241
- alignOffset = 0,
2242
- side = "bottom",
2243
- sideOffset = 4,
2244
- className,
2245
- ...props
2246
- }) {
2247
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2248
- menu.Menu.Positioner,
2249
- {
2250
- className: "isolate z-50 outline-none",
2251
- align,
2252
- alignOffset,
2253
- side,
2254
- sideOffset,
2255
- children: /* @__PURE__ */ jsxRuntime.jsx(
2256
- menu.Menu.Popup,
2257
- {
2258
- "data-slot": "dropdown-menu-content",
2259
- className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 bg-popover text-popover-foreground min-w-48 rounded-2xl p-1 shadow-2xl ring-1 duration-100 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden", className),
2260
- ...props
2261
- }
2262
- )
2263
- }
2264
- ) });
2265
- }
2266
- function DropdownMenuItem({
2267
- className,
2268
- inset,
2269
- variant = "default",
2270
- ...props
2271
- }) {
2272
- return /* @__PURE__ */ jsxRuntime.jsx(
2273
- menu.Menu.Item,
2274
- {
2275
- "data-slot": "dropdown-menu-item",
2276
- "data-inset": inset,
2277
- "data-variant": variant,
2278
- className: cn(
2279
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
2280
- className
2281
- ),
2282
- ...props
2283
- }
2284
- );
2285
- }
2286
3174
  var AccountDialog = ({
2287
3175
  className,
2288
- variant,
3176
+ variant = "outline",
2289
3177
  size
2290
3178
  }) => {
2291
- const { isLoading, isAuthenticated, login, logout } = useAuth();
2292
- const [open, setOpen] = React9__namespace.useState(false);
2293
- const [error, setError] = React9__namespace.useState(null);
3179
+ const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3180
+ const [open, setOpen] = React11__namespace.useState(false);
3181
+ const [accountInfoOpen, setAccountInfoOpen] = React11__namespace.useState(false);
3182
+ const [error, setError] = React11__namespace.useState(null);
3183
+ const initials = React11__namespace.useMemo(() => {
3184
+ const name = user?.displayName || user?.name;
3185
+ if (!name) return "";
3186
+ return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
3187
+ }, [user?.displayName, user?.name]);
2294
3188
  const handleGoogleSignIn = async () => {
2295
3189
  login();
2296
3190
  };
2297
3191
  if (isAuthenticated) {
2298
- return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
2299
- /* @__PURE__ */ jsxRuntime.jsx(
2300
- DropdownMenuTrigger,
2301
- {
2302
- render: (props) => /* @__PURE__ */ jsxRuntime.jsxs(
2303
- Button,
2304
- {
2305
- variant,
2306
- size,
2307
- ...props,
2308
- className,
2309
- children: [
2310
- /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "mr-2 size-4" }),
2311
- "Account"
2312
- ]
2313
- }
2314
- )
2315
- }
2316
- ),
2317
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { children: [
2318
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { children: [
2319
- /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "mr-2 size-4" }),
2320
- "Account"
3192
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3193
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
3194
+ /* @__PURE__ */ jsxRuntime.jsx(
3195
+ DropdownMenuTrigger,
3196
+ {
3197
+ render: (props) => /* @__PURE__ */ jsxRuntime.jsx(
3198
+ Button,
3199
+ {
3200
+ variant,
3201
+ size: "icon",
3202
+ ...props,
3203
+ className: cn("rounded-full", className),
3204
+ children: user?.picture ? /* @__PURE__ */ jsxRuntime.jsx(
3205
+ "img",
3206
+ {
3207
+ src: user.picture,
3208
+ alt: user.displayName || user.name,
3209
+ className: "size-7 rounded-full object-cover"
3210
+ }
3211
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-7 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "size-4" }) })
3212
+ }
3213
+ )
3214
+ }
3215
+ ),
3216
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
3217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2", children: [
3218
+ user?.picture ? /* @__PURE__ */ jsxRuntime.jsx(
3219
+ "img",
3220
+ {
3221
+ src: user.picture,
3222
+ alt: user.displayName || user.name,
3223
+ className: "size-8 rounded-full object-cover"
3224
+ }
3225
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "size-4" }) }),
3226
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-0.5 overflow-hidden", children: [
3227
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium", children: user?.displayName || user?.name }),
3228
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-xs text-muted-foreground", children: user?.email })
3229
+ ] })
3230
+ ] }),
3231
+ /* @__PURE__ */ jsxRuntime.jsx(Separator, { className: "my-1" }),
3232
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onClick: () => setAccountInfoOpen(true), children: [
3233
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "mr-2 size-4" }),
3234
+ "Account Settings"
3235
+ ] }),
3236
+ /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onClick: logout, className: "text-destructive", children: [
3237
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLogout, { className: "mr-2 size-4" }),
3238
+ "Logout"
3239
+ ] })
3240
+ ] })
3241
+ ] }),
3242
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: accountInfoOpen, onOpenChange: setAccountInfoOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-md", children: [
3243
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
3244
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Account Information" }),
3245
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Your account details and settings." })
2321
3246
  ] }),
2322
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenuItem, { onClick: logout, children: [
2323
- /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLogout, { className: "mr-2 size-4" }),
2324
- "Logout"
3247
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogClose, { children: [
3248
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" }),
3249
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
3250
+ ] }),
3251
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 py-4", children: [
3252
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
3253
+ user?.picture ? /* @__PURE__ */ jsxRuntime.jsx(
3254
+ "img",
3255
+ {
3256
+ src: user.picture,
3257
+ alt: user.displayName || user.name,
3258
+ className: "size-16 rounded-full object-cover"
3259
+ }
3260
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-muted text-xl font-bold", children: initials || /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconUser, { className: "size-8 text-muted-foreground" }) }),
3261
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
3262
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold", children: user?.displayName || user?.name }),
3263
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: user?.email })
3264
+ ] })
3265
+ ] }),
3266
+ /* @__PURE__ */ jsxRuntime.jsx(Separator, {}),
3267
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
3268
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
3269
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "User ID" }),
3270
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-mono text-xs truncate", children: user?.uid || user?.id })
3271
+ ] }),
3272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
3273
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Created At" }),
3274
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: user?.createdAt || "N/A" })
3275
+ ] })
3276
+ ] })
2325
3277
  ] })
2326
- ] })
3278
+ ] }) })
2327
3279
  ] });
2328
3280
  }
2329
3281
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -2365,23 +3317,65 @@ var AccountDialog = ({
2365
3317
  ] }) })
2366
3318
  ] });
2367
3319
  };
3320
+ function ThemeToggle() {
3321
+ const { theme, setTheme, resolvedTheme } = useTheme();
3322
+ const cycleTheme = () => {
3323
+ if (theme === "light") {
3324
+ setTheme("dark");
3325
+ } else if (theme === "dark") {
3326
+ setTheme("system");
3327
+ } else {
3328
+ setTheme("light");
3329
+ }
3330
+ };
3331
+ const getIcon = () => {
3332
+ if (theme === "system") {
3333
+ return /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconDeviceDesktop, { className: "h-4 w-4" });
3334
+ }
3335
+ return resolvedTheme === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconMoon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconSun, { className: "h-4 w-4" });
3336
+ };
3337
+ const getLabel = () => {
3338
+ if (theme === "system") {
3339
+ return "System";
3340
+ }
3341
+ return resolvedTheme === "dark" ? "Dark" : "Light";
3342
+ };
3343
+ return /* @__PURE__ */ jsxRuntime.jsx(
3344
+ Button,
3345
+ {
3346
+ variant: "ghost",
3347
+ size: "icon",
3348
+ onClick: cycleTheme,
3349
+ "aria-label": `Toggle theme (current: ${getLabel()})`,
3350
+ title: `Current: ${getLabel()}. Click to cycle: Light \u2192 Dark \u2192 System`,
3351
+ children: getIcon()
3352
+ }
3353
+ );
3354
+ }
2368
3355
 
2369
3356
  exports.AccountDialog = AccountDialog;
2370
3357
  exports.AuthContext = AuthContext;
2371
3358
  exports.AuthProvider = AuthProvider;
2372
3359
  exports.ChatFull = ChatFull;
3360
+ exports.ChatHeader = ChatHeader;
2373
3361
  exports.ChatPopup = ChatPopup;
2374
3362
  exports.ChatSidebar = ChatSidebar;
2375
3363
  exports.Composer = Composer;
3364
+ exports.CreateThreadButton = CreateThreadButton;
2376
3365
  exports.MelonyClientProvider = MelonyClientProvider;
2377
3366
  exports.MelonyContext = MelonyContext;
3367
+ exports.ThemeProvider = ThemeProvider;
3368
+ exports.ThemeToggle = ThemeToggle;
2378
3369
  exports.Thread = Thread;
2379
3370
  exports.ThreadContext = ThreadContext;
2380
3371
  exports.ThreadList = ThreadList;
3372
+ exports.ThreadPopover = ThreadPopover;
2381
3373
  exports.ThreadProvider = ThreadProvider;
2382
3374
  exports.UIRenderer = UIRenderer;
3375
+ exports.groupEventsToMessages = groupEventsToMessages;
2383
3376
  exports.useAuth = useAuth;
2384
3377
  exports.useMelony = useMelony;
3378
+ exports.useTheme = useTheme;
2385
3379
  exports.useThreads = useThreads;
2386
3380
  //# sourceMappingURL=index.cjs.map
2387
3381
  //# sourceMappingURL=index.cjs.map