@melony/react 0.1.14 → 0.1.16

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.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as React10 from 'react';
2
- import { createContext, useState, useEffect, useCallback, useMemo, useContext, useRef } from 'react';
1
+ import * as React11 from 'react';
2
+ import React11__default, { createContext, useState, useEffect, useCallback, useMemo, useContext, useRef } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { generateId } from 'melony/client';
5
5
  import { clsx } from 'clsx';
@@ -7,14 +7,17 @@ import { twMerge } from 'tailwind-merge';
7
7
  import { Button as Button$1 } from '@base-ui/react/button';
8
8
  import { cva } from 'class-variance-authority';
9
9
  import * as ICONS from '@tabler/icons-react';
10
- import { IconArrowUp, IconPlus, IconMessage, IconTrash, IconHistory, IconX, IconArrowLeft, IconChevronLeft, IconChevronRight, IconUser, IconLogout, IconBrandGoogle, IconDeviceDesktop, IconMoon, IconSun, IconSelector, IconCheck, IconChevronUp, IconChevronDown } from '@tabler/icons-react';
10
+ import { IconChevronDown, IconLoader2, IconArrowUp, IconPlus, IconMessage, IconTrash, IconHistory, IconX, IconArrowLeft, IconChevronLeft, IconChevronRight, IconUser, IconLogout, IconBrandGoogle, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconSelector, IconChevronUp } from '@tabler/icons-react';
11
+ import { Menu } from '@base-ui/react/menu';
11
12
  import { Separator as Separator$1 } from '@base-ui/react/separator';
13
+ import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
12
14
  import { mergeProps } from '@base-ui/react/merge-props';
13
15
  import { useRender } from '@base-ui/react/use-render';
14
16
  import { Input as Input$1 } from '@base-ui/react/input';
15
17
  import { Select as Select$1 } from '@base-ui/react/select';
18
+ import { createPortal } from 'react-dom';
19
+ import { useHotkeys } from 'react-hotkeys-hook';
16
20
  import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
17
- import { Menu } from '@base-ui/react/menu';
18
21
 
19
22
  // src/providers/melony-provider.tsx
20
23
 
@@ -421,18 +424,179 @@ function Textarea({ className, ...props }) {
421
424
  }
422
425
  );
423
426
  }
427
+ function DropdownMenu({ ...props }) {
428
+ return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
429
+ }
430
+ function DropdownMenuTrigger({ ...props }) {
431
+ return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
432
+ }
433
+ function DropdownMenuContent({
434
+ align = "start",
435
+ alignOffset = 0,
436
+ side = "bottom",
437
+ sideOffset = 4,
438
+ className,
439
+ ...props
440
+ }) {
441
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
442
+ Menu.Positioner,
443
+ {
444
+ className: "isolate z-50 outline-none",
445
+ align,
446
+ alignOffset,
447
+ side,
448
+ sideOffset,
449
+ children: /* @__PURE__ */ jsx(
450
+ Menu.Popup,
451
+ {
452
+ "data-slot": "dropdown-menu-content",
453
+ 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),
454
+ ...props
455
+ }
456
+ )
457
+ }
458
+ ) });
459
+ }
460
+ function DropdownMenuGroup({ ...props }) {
461
+ return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
462
+ }
463
+ function DropdownMenuLabel({
464
+ className,
465
+ inset,
466
+ ...props
467
+ }) {
468
+ return /* @__PURE__ */ jsx(
469
+ Menu.GroupLabel,
470
+ {
471
+ "data-slot": "dropdown-menu-label",
472
+ "data-inset": inset,
473
+ className: cn("text-muted-foreground px-3 py-2.5 text-xs data-[inset]:pl-8", className),
474
+ ...props
475
+ }
476
+ );
477
+ }
478
+ function DropdownMenuItem({
479
+ className,
480
+ inset,
481
+ variant = "default",
482
+ ...props
483
+ }) {
484
+ return /* @__PURE__ */ jsx(
485
+ Menu.Item,
486
+ {
487
+ "data-slot": "dropdown-menu-item",
488
+ "data-inset": inset,
489
+ "data-variant": variant,
490
+ className: cn(
491
+ "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",
492
+ className
493
+ ),
494
+ ...props
495
+ }
496
+ );
497
+ }
498
+ function DropdownMenuCheckboxItem({
499
+ className,
500
+ children,
501
+ checked,
502
+ ...props
503
+ }) {
504
+ return /* @__PURE__ */ jsxs(
505
+ Menu.CheckboxItem,
506
+ {
507
+ "data-slot": "dropdown-menu-checkbox-item",
508
+ className: cn(
509
+ "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",
510
+ className
511
+ ),
512
+ checked,
513
+ ...props,
514
+ children: [
515
+ /* @__PURE__ */ jsx(
516
+ "span",
517
+ {
518
+ className: "pointer-events-none absolute right-2 flex items-center justify-center pointer-events-none",
519
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
520
+ children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(
521
+ IconCheck,
522
+ {}
523
+ ) })
524
+ }
525
+ ),
526
+ children
527
+ ]
528
+ }
529
+ );
530
+ }
531
+ function DropdownMenuSeparator({
532
+ className,
533
+ ...props
534
+ }) {
535
+ return /* @__PURE__ */ jsx(
536
+ Menu.Separator,
537
+ {
538
+ "data-slot": "dropdown-menu-separator",
539
+ className: cn("bg-border/50 -mx-1 my-1 h-px", className),
540
+ ...props
541
+ }
542
+ );
543
+ }
424
544
  function Composer({
425
545
  value,
426
546
  onChange,
427
547
  onSubmit,
428
548
  placeholder = "Type a message...",
429
549
  isLoading,
430
- className
550
+ className,
551
+ options = [],
552
+ autoFocus = false,
553
+ defaultSelectedIds = []
431
554
  }) {
555
+ const [selectedOptions, setSelectedOptions] = React11__default.useState(
556
+ () => new Set(defaultSelectedIds)
557
+ );
558
+ const toggleOption = (id, groupOptions, type = "multiple") => {
559
+ const next = new Set(selectedOptions);
560
+ if (type === "single") {
561
+ const isAlreadySelected = next.has(id);
562
+ if (groupOptions) {
563
+ groupOptions.forEach((o) => next.delete(o.id));
564
+ }
565
+ if (!isAlreadySelected) {
566
+ next.add(id);
567
+ }
568
+ } else {
569
+ if (next.has(id)) {
570
+ next.delete(id);
571
+ } else {
572
+ next.add(id);
573
+ }
574
+ }
575
+ setSelectedOptions(next);
576
+ };
577
+ const handleInternalSubmit = () => {
578
+ const state = {};
579
+ options.forEach((group) => {
580
+ const selectedInGroup = group.options.filter(
581
+ (o) => selectedOptions.has(o.id)
582
+ );
583
+ if (selectedInGroup.length > 0) {
584
+ if (group.type === "single") {
585
+ state[group.id] = selectedInGroup[0].value;
586
+ } else {
587
+ state[group.id] = selectedInGroup.map((o) => ({
588
+ id: o.id,
589
+ value: o.value
590
+ }));
591
+ }
592
+ }
593
+ });
594
+ onSubmit(state);
595
+ };
432
596
  const handleKeyDown = (e) => {
433
597
  if (e.key === "Enter" && !e.shiftKey) {
434
598
  e.preventDefault();
435
- onSubmit();
599
+ handleInternalSubmit();
436
600
  }
437
601
  };
438
602
  return /* @__PURE__ */ jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ 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: [
@@ -443,19 +607,68 @@ function Composer({
443
607
  onChange: (e) => onChange(e.target.value),
444
608
  onKeyDown: handleKeyDown,
445
609
  placeholder,
446
- 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"
610
+ 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",
611
+ autoFocus
447
612
  }
448
613
  ),
449
- /* @__PURE__ */ jsx("div", { className: "flex justify-end items-center", children: /* @__PURE__ */ jsx(
450
- Button,
451
- {
452
- type: "submit",
453
- disabled: !value.trim() && !isLoading || isLoading,
454
- size: "icon-lg",
455
- onClick: () => onSubmit(),
456
- children: /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
457
- }
458
- ) })
614
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center px-1", children: [
615
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: options.map((group) => {
616
+ const selectedInGroup = group.options.filter(
617
+ (o) => selectedOptions.has(o.id)
618
+ );
619
+ const label = selectedInGroup.length === 0 ? group.label : selectedInGroup.length === 1 ? selectedInGroup[0].label : `${group.label} (${selectedInGroup.length})`;
620
+ const isSingle = group.type === "single";
621
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
622
+ /* @__PURE__ */ jsx(
623
+ DropdownMenuTrigger,
624
+ {
625
+ render: /* @__PURE__ */ jsxs(
626
+ Button,
627
+ {
628
+ variant: "ghost",
629
+ size: "sm",
630
+ className: cn(
631
+ selectedInGroup.length > 0 ? "text-foreground bg-muted/50" : "text-muted-foreground"
632
+ ),
633
+ children: [
634
+ label,
635
+ /* @__PURE__ */ jsx(IconChevronDown, { className: "h-3 w-3 opacity-50" })
636
+ ]
637
+ }
638
+ )
639
+ }
640
+ ),
641
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-56", children: /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
642
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: group.label }),
643
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
644
+ group.options.map((option) => /* @__PURE__ */ jsx(
645
+ DropdownMenuCheckboxItem,
646
+ {
647
+ checked: selectedOptions.has(option.id),
648
+ onCheckedChange: () => toggleOption(
649
+ option.id,
650
+ group.options,
651
+ isSingle ? "single" : "multiple"
652
+ ),
653
+ onSelect: (e) => e.preventDefault(),
654
+ children: option.label
655
+ },
656
+ option.id
657
+ ))
658
+ ] }) })
659
+ ] }, group.id);
660
+ }) }),
661
+ /* @__PURE__ */ jsx(
662
+ Button,
663
+ {
664
+ type: "submit",
665
+ disabled: !value.trim() && !isLoading || isLoading,
666
+ size: "icon-lg",
667
+ onClick: handleInternalSubmit,
668
+ children: isLoading ? /* @__PURE__ */ jsx(IconLoader2, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
669
+ }
670
+ )
671
+ ] })
459
672
  ] }) });
460
673
  }
461
674
  function Card({
@@ -841,6 +1054,111 @@ var ListItem = ({
841
1054
  }
842
1055
  );
843
1056
  };
1057
+ function Dialog({ ...props }) {
1058
+ return /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
1059
+ }
1060
+ function DialogTrigger({ ...props }) {
1061
+ return /* @__PURE__ */ jsx(Dialog$1.Trigger, { "data-slot": "dialog-trigger", ...props });
1062
+ }
1063
+ function DialogPortal({ ...props }) {
1064
+ return /* @__PURE__ */ jsx(Dialog$1.Portal, { "data-slot": "dialog-portal", ...props });
1065
+ }
1066
+ function DialogOverlay({
1067
+ className,
1068
+ ...props
1069
+ }) {
1070
+ return /* @__PURE__ */ jsx(
1071
+ Dialog$1.Backdrop,
1072
+ {
1073
+ "data-slot": "dialog-overlay",
1074
+ className: cn(
1075
+ "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",
1076
+ className
1077
+ ),
1078
+ ...props
1079
+ }
1080
+ );
1081
+ }
1082
+ function DialogContent({
1083
+ className,
1084
+ ...props
1085
+ }) {
1086
+ return /* @__PURE__ */ jsxs(DialogPortal, { children: [
1087
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
1088
+ /* @__PURE__ */ jsx(
1089
+ Dialog$1.Popup,
1090
+ {
1091
+ "data-slot": "dialog-content",
1092
+ className: cn(
1093
+ "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",
1094
+ className
1095
+ ),
1096
+ ...props
1097
+ }
1098
+ )
1099
+ ] });
1100
+ }
1101
+ function DialogClose({
1102
+ className,
1103
+ ...props
1104
+ }) {
1105
+ return /* @__PURE__ */ jsx(
1106
+ Dialog$1.Close,
1107
+ {
1108
+ "data-slot": "dialog-close",
1109
+ className: cn(
1110
+ "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",
1111
+ className
1112
+ ),
1113
+ ...props
1114
+ }
1115
+ );
1116
+ }
1117
+ function DialogHeader({
1118
+ className,
1119
+ ...props
1120
+ }) {
1121
+ return /* @__PURE__ */ jsx(
1122
+ "div",
1123
+ {
1124
+ "data-slot": "dialog-header",
1125
+ className: cn(
1126
+ "flex flex-col space-y-1.5 text-center sm:text-left",
1127
+ className
1128
+ ),
1129
+ ...props
1130
+ }
1131
+ );
1132
+ }
1133
+ function DialogTitle({
1134
+ className,
1135
+ ...props
1136
+ }) {
1137
+ return /* @__PURE__ */ jsx(
1138
+ Dialog$1.Title,
1139
+ {
1140
+ "data-slot": "dialog-title",
1141
+ className: cn(
1142
+ "text-lg font-semibold leading-none tracking-tight",
1143
+ className
1144
+ ),
1145
+ ...props
1146
+ }
1147
+ );
1148
+ }
1149
+ function DialogDescription({
1150
+ className,
1151
+ ...props
1152
+ }) {
1153
+ return /* @__PURE__ */ jsx(
1154
+ Dialog$1.Description,
1155
+ {
1156
+ "data-slot": "dialog-description",
1157
+ className: cn("text-sm text-muted-foreground", className),
1158
+ ...props
1159
+ }
1160
+ );
1161
+ }
844
1162
  var Image = ({
845
1163
  src,
846
1164
  alt,
@@ -850,10 +1168,11 @@ var Image = ({
850
1168
  }) => {
851
1169
  const [hasError, setHasError] = useState(false);
852
1170
  const [isLoading, setIsLoading] = useState(true);
1171
+ const [open, setOpen] = useState(false);
853
1172
  const sizes = {
854
- sm: "h-11 w-11",
855
- md: "h-22 w-22",
856
- lg: "h-44 w-44"
1173
+ sm: "h-11",
1174
+ md: "h-22",
1175
+ lg: "h-44"
857
1176
  };
858
1177
  const handleError = () => {
859
1178
  setHasError(true);
@@ -876,22 +1195,67 @@ var Image = ({
876
1195
  }
877
1196
  );
878
1197
  }
879
- return /* @__PURE__ */ jsxs("div", { className: cn("relative overflow-hidden rounded-md border", className), style, children: [
1198
+ return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: setOpen, children: [
1199
+ /* @__PURE__ */ jsx(DialogTrigger, { children: /* @__PURE__ */ jsxs(
1200
+ "div",
1201
+ {
1202
+ className: cn("relative overflow-hidden rounded-md border cursor-pointer", className),
1203
+ style,
1204
+ children: [
1205
+ /* @__PURE__ */ jsx(
1206
+ "img",
1207
+ {
1208
+ src,
1209
+ alt,
1210
+ onError: handleError,
1211
+ onLoad: handleLoad,
1212
+ className: cn(
1213
+ "block h-auto w-full transition-opacity duration-200 hover:opacity-90",
1214
+ isLoading ? "opacity-0" : "opacity-100",
1215
+ sizes[size]
1216
+ )
1217
+ }
1218
+ ),
1219
+ isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-muted animate-pulse" })
1220
+ ]
1221
+ }
1222
+ ) }),
880
1223
  /* @__PURE__ */ jsx(
881
- "img",
1224
+ DialogContent,
882
1225
  {
883
- src,
884
- alt,
885
- onError: handleError,
886
- onLoad: handleLoad,
887
- className: cn(
888
- "block h-auto w-full transition-opacity duration-200",
889
- isLoading ? "opacity-0" : "opacity-100",
890
- sizes[size]
891
- )
1226
+ className: "max-w-[90vw] max-h-[90vh] p-0 bg-transparent border-none shadow-none",
1227
+ onClick: (e) => e.stopPropagation(),
1228
+ children: /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
1229
+ /* @__PURE__ */ 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__ */ jsx(
1230
+ "svg",
1231
+ {
1232
+ xmlns: "http://www.w3.org/2000/svg",
1233
+ className: "h-5 w-5",
1234
+ fill: "none",
1235
+ viewBox: "0 0 24 24",
1236
+ stroke: "currentColor",
1237
+ children: /* @__PURE__ */ jsx(
1238
+ "path",
1239
+ {
1240
+ strokeLinecap: "round",
1241
+ strokeLinejoin: "round",
1242
+ strokeWidth: 2,
1243
+ d: "M6 18L18 6M6 6l12 12"
1244
+ }
1245
+ )
1246
+ }
1247
+ ) }),
1248
+ /* @__PURE__ */ jsx(
1249
+ "img",
1250
+ {
1251
+ src,
1252
+ alt: alt || "Enlarged image",
1253
+ className: "max-w-full max-h-[90vh] object-contain rounded-lg"
1254
+ }
1255
+ )
1256
+ ] })
892
1257
  }
893
- ),
894
- isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-muted animate-pulse" })
1258
+ )
895
1259
  ] });
896
1260
  };
897
1261
  var Icon = ({
@@ -1904,19 +2268,42 @@ function MessageBubble({ message }) {
1904
2268
  }
1905
2269
  );
1906
2270
  }
1907
- function LoadingIndicator() {
1908
- return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." });
2271
+ function LoadingIndicator({ status }) {
2272
+ const [isExpanded, setIsExpanded] = useState(false);
2273
+ const message = status?.message || "Processing...";
2274
+ const details = status?.details;
2275
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2276
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground group", children: [
2277
+ /* @__PURE__ */ jsx(IconLoader2, { className: "size-3.5 animate-spin" }),
2278
+ /* @__PURE__ */ jsx("div", { className: "animate-pulse", children: message }),
2279
+ details && /* @__PURE__ */ jsx(
2280
+ "button",
2281
+ {
2282
+ onClick: () => setIsExpanded(!isExpanded),
2283
+ className: "p-0.5 hover:bg-muted rounded-sm transition-colors flex items-center justify-center",
2284
+ title: isExpanded ? "Hide details" : "Show details",
2285
+ children: isExpanded ? /* @__PURE__ */ jsx(IconChevronUp, { className: "size-3.5 opacity-50 group-hover:opacity-100" }) : /* @__PURE__ */ jsx(IconChevronDown, { className: "size-3.5 opacity-50 group-hover:opacity-100" })
2286
+ }
2287
+ )
2288
+ ] }),
2289
+ isExpanded && details && /* @__PURE__ */ 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 })
2290
+ ] });
1909
2291
  }
1910
2292
  function ErrorDisplay({ error }) {
1911
2293
  return /* @__PURE__ */ jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message });
1912
2294
  }
1913
- function MessageList({ messages, isLoading, error }) {
2295
+ function MessageList({ messages, isLoading, error, loadingStatus }) {
1914
2296
  if (messages.length === 0) {
1915
2297
  return null;
1916
2298
  }
2299
+ const isTextStreaming = useMemo(() => {
2300
+ if (messages.length === 0 || !isLoading) return false;
2301
+ const lastMessage = messages[messages.length - 1];
2302
+ return lastMessage.content.some((event) => event.type === "text-delta");
2303
+ }, [messages, isLoading]);
1917
2304
  return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1918
2305
  messages.map((message, index) => /* @__PURE__ */ jsx(MessageBubble, { message }, index)),
1919
- isLoading && /* @__PURE__ */ jsx(LoadingIndicator, {}),
2306
+ isLoading && !isTextStreaming && /* @__PURE__ */ jsx(LoadingIndicator, { status: loadingStatus }),
1920
2307
  error && /* @__PURE__ */ jsx(ErrorDisplay, { error })
1921
2308
  ] });
1922
2309
  }
@@ -1924,24 +2311,29 @@ function Thread({
1924
2311
  className,
1925
2312
  placeholder = "Type a message...",
1926
2313
  starterPrompts,
1927
- onStarterPromptClick
2314
+ onStarterPromptClick,
2315
+ options,
2316
+ autoFocus = false,
2317
+ defaultSelectedIds
1928
2318
  }) {
1929
- const { messages, isLoading, error, sendEvent } = useMelony();
2319
+ const { messages, isLoading, error, sendEvent, loadingStatus } = useMelony();
1930
2320
  const [input, setInput] = useState("");
1931
2321
  const messagesEndRef = useRef(null);
1932
2322
  useEffect(() => {
1933
2323
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1934
2324
  }, [messages]);
1935
- const handleSubmit = async (e, overrideInput) => {
1936
- e?.preventDefault();
2325
+ const handleSubmit = async (state, overrideInput) => {
1937
2326
  const text = (overrideInput ?? input).trim();
1938
2327
  if (!text || isLoading) return;
1939
2328
  if (!overrideInput) setInput("");
1940
- await sendEvent({
1941
- type: "text",
1942
- role: "user",
1943
- data: { content: text }
1944
- });
2329
+ await sendEvent(
2330
+ {
2331
+ type: "text",
2332
+ role: "user",
2333
+ data: { content: text }
2334
+ },
2335
+ { state }
2336
+ );
1945
2337
  };
1946
2338
  const handleStarterPromptClick = (prompt) => {
1947
2339
  if (onStarterPromptClick) {
@@ -1951,47 +2343,57 @@ function Thread({
1951
2343
  }
1952
2344
  };
1953
2345
  const showStarterPrompts = messages.length === 0 && starterPrompts && starterPrompts.length > 0;
1954
- return /* @__PURE__ */ jsxs("div", { className: cn("relative flex flex-col h-full bg-background", className), children: [
1955
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 pb-36", children: [
1956
- /* @__PURE__ */ jsxs(
1957
- "div",
1958
- {
1959
- className: cn(
1960
- "max-w-4xl mx-auto w-full p-4",
1961
- showStarterPrompts && "min-h-full flex flex-col"
2346
+ return /* @__PURE__ */ jsxs(
2347
+ "div",
2348
+ {
2349
+ className: cn("relative flex flex-col h-full bg-background", className),
2350
+ children: [
2351
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 pb-36", children: [
2352
+ /* @__PURE__ */ jsxs(
2353
+ "div",
2354
+ {
2355
+ className: cn(
2356
+ "max-w-4xl mx-auto w-full p-4",
2357
+ showStarterPrompts && "min-h-full flex flex-col"
2358
+ ),
2359
+ children: [
2360
+ showStarterPrompts && /* @__PURE__ */ jsx(
2361
+ StarterPrompts,
2362
+ {
2363
+ prompts: starterPrompts,
2364
+ onPromptClick: handleStarterPromptClick
2365
+ }
2366
+ ),
2367
+ /* @__PURE__ */ jsx(
2368
+ MessageList,
2369
+ {
2370
+ messages,
2371
+ isLoading,
2372
+ error,
2373
+ loadingStatus
2374
+ }
2375
+ )
2376
+ ]
2377
+ }
1962
2378
  ),
1963
- children: [
1964
- showStarterPrompts && /* @__PURE__ */ jsx(
1965
- StarterPrompts,
1966
- {
1967
- prompts: starterPrompts,
1968
- onPromptClick: handleStarterPromptClick
1969
- }
1970
- ),
1971
- /* @__PURE__ */ jsx(
1972
- MessageList,
1973
- {
1974
- messages,
1975
- isLoading,
1976
- error
1977
- }
1978
- )
1979
- ]
1980
- }
1981
- ),
1982
- /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
1983
- ] }),
1984
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 p-4 w-full", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsx(
1985
- Composer,
1986
- {
1987
- value: input,
1988
- onChange: setInput,
1989
- onSubmit: handleSubmit,
1990
- placeholder,
1991
- isLoading
1992
- }
1993
- ) }) })
1994
- ] });
2379
+ /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
2380
+ ] }),
2381
+ /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 p-4 w-full", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsx(
2382
+ Composer,
2383
+ {
2384
+ value: input,
2385
+ onChange: setInput,
2386
+ onSubmit: handleSubmit,
2387
+ placeholder,
2388
+ isLoading,
2389
+ options,
2390
+ autoFocus,
2391
+ defaultSelectedIds
2392
+ }
2393
+ ) }) })
2394
+ ]
2395
+ }
2396
+ );
1995
2397
  }
1996
2398
  function ChatHeader({
1997
2399
  title,
@@ -2005,13 +2407,7 @@ function ChatHeader({
2005
2407
  return /* @__PURE__ */ jsx("div", { className: cn("p-4 border-b border-border h-14 flex items-center shrink-0", className), children });
2006
2408
  }
2007
2409
  return /* @__PURE__ */ jsxs("div", { className: cn("p-4 border-b border-border h-14 flex items-center justify-between shrink-0", className), children: [
2008
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
2009
- leftContent,
2010
- title && /* @__PURE__ */ jsx("div", { className: cn(
2011
- "text-sm font-semibold truncate",
2012
- typeof title === "string" ? titleClassName : ""
2013
- ), children: title })
2014
- ] }),
2410
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: leftContent }),
2015
2411
  rightContent && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: rightContent })
2016
2412
  ] });
2017
2413
  }
@@ -2114,8 +2510,10 @@ function ChatPopup({
2114
2510
  title = "Chat",
2115
2511
  placeholder = "Message the AI",
2116
2512
  starterPrompts,
2513
+ options,
2117
2514
  defaultOpen = false,
2118
- headerProps
2515
+ headerProps,
2516
+ defaultSelectedIds
2119
2517
  }) {
2120
2518
  const [isOpen, setIsOpen] = useState(defaultOpen);
2121
2519
  const [view, setView] = useState("chat");
@@ -2129,7 +2527,7 @@ function ChatPopup({
2129
2527
  }
2130
2528
  };
2131
2529
  return /* @__PURE__ */ jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 font-sans", children: [
2132
- isOpen && /* @__PURE__ */ 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: [
2530
+ isOpen && /* @__PURE__ */ 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: [
2133
2531
  /* @__PURE__ */ jsx(
2134
2532
  ChatHeader,
2135
2533
  {
@@ -2186,7 +2584,9 @@ function ChatPopup({
2186
2584
  {
2187
2585
  placeholder,
2188
2586
  starterPrompts,
2189
- className: "h-full"
2587
+ options,
2588
+ className: "h-full",
2589
+ defaultSelectedIds
2190
2590
  }
2191
2591
  ) : /* @__PURE__ */ jsx(
2192
2592
  ThreadList,
@@ -2214,8 +2614,10 @@ function ChatSidebar({
2214
2614
  title = "Chat",
2215
2615
  placeholder = "Message the AI",
2216
2616
  starterPrompts,
2617
+ options,
2217
2618
  className,
2218
- headerProps
2619
+ headerProps,
2620
+ defaultSelectedIds
2219
2621
  }) {
2220
2622
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2221
2623
  /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
@@ -2224,7 +2626,9 @@ function ChatSidebar({
2224
2626
  {
2225
2627
  placeholder,
2226
2628
  starterPrompts,
2227
- className: "h-full"
2629
+ options,
2630
+ className: "h-full",
2631
+ defaultSelectedIds
2228
2632
  }
2229
2633
  ) })
2230
2634
  ] });
@@ -2233,6 +2637,7 @@ function ChatFull({
2233
2637
  title = "Chat",
2234
2638
  placeholder = "Message the AI",
2235
2639
  starterPrompts,
2640
+ options,
2236
2641
  className,
2237
2642
  headerProps,
2238
2643
  leftSidebar,
@@ -2246,7 +2651,9 @@ function ChatFull({
2246
2651
  leftSidebarCollapsed: controlledLeftCollapsed,
2247
2652
  rightSidebarCollapsed: controlledRightCollapsed,
2248
2653
  onLeftSidebarCollapseChange,
2249
- onRightSidebarCollapseChange
2654
+ onRightSidebarCollapseChange,
2655
+ autoFocus = false,
2656
+ defaultSelectedIds
2250
2657
  }) {
2251
2658
  const [internalLeftCollapsed, setInternalLeftCollapsed] = useState(
2252
2659
  defaultLeftSidebarCollapsed
@@ -2310,7 +2717,16 @@ function ChatFull({
2310
2717
  }
2311
2718
  ) })
2312
2719
  ] }),
2313
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(Thread, { placeholder, starterPrompts }) }),
2720
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
2721
+ Thread,
2722
+ {
2723
+ placeholder,
2724
+ starterPrompts,
2725
+ options,
2726
+ autoFocus,
2727
+ defaultSelectedIds
2728
+ }
2729
+ ) }),
2314
2730
  rightSidebar && /* @__PURE__ */ jsxs(Fragment, { children: [
2315
2731
  rightSidebarCollapsible && rightCollapsed && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 border-l border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsx(
2316
2732
  Button,
@@ -2351,6 +2767,307 @@ function ChatFull({
2351
2767
  ] })
2352
2768
  ] });
2353
2769
  }
2770
+ var PopoverContext = React11.createContext(
2771
+ void 0
2772
+ );
2773
+ function usePopoverContext() {
2774
+ const context = React11.useContext(PopoverContext);
2775
+ if (!context) {
2776
+ throw new Error("Popover components must be used within a Popover");
2777
+ }
2778
+ return context;
2779
+ }
2780
+ function Popover({
2781
+ children,
2782
+ defaultOpen = false,
2783
+ open: controlledOpen,
2784
+ onOpenChange
2785
+ }) {
2786
+ const [internalOpen, setInternalOpen] = React11.useState(defaultOpen);
2787
+ const triggerRef = React11.useRef(null);
2788
+ const open = controlledOpen ?? internalOpen;
2789
+ const setOpen = React11.useCallback(
2790
+ (newOpen) => {
2791
+ if (controlledOpen === void 0) {
2792
+ setInternalOpen(newOpen);
2793
+ }
2794
+ onOpenChange?.(newOpen);
2795
+ },
2796
+ [controlledOpen, onOpenChange]
2797
+ );
2798
+ const value = React11.useMemo(
2799
+ () => ({
2800
+ open,
2801
+ setOpen,
2802
+ triggerRef
2803
+ }),
2804
+ [open, setOpen]
2805
+ );
2806
+ return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
2807
+ }
2808
+ var PopoverTrigger = React11.forwardRef(
2809
+ ({ asChild, className, children, ...props }, ref) => {
2810
+ const { setOpen, triggerRef } = usePopoverContext();
2811
+ const handleClick = (e) => {
2812
+ setOpen(true);
2813
+ props.onClick?.(e);
2814
+ };
2815
+ if (asChild && React11.isValidElement(children)) {
2816
+ return React11.cloneElement(children, {
2817
+ ref: (node) => {
2818
+ triggerRef.current = node;
2819
+ if (typeof children.ref === "function") {
2820
+ children.ref(node);
2821
+ } else if (children.ref) {
2822
+ children.ref.current = node;
2823
+ }
2824
+ },
2825
+ onClick: handleClick
2826
+ });
2827
+ }
2828
+ return /* @__PURE__ */ jsx(
2829
+ "button",
2830
+ {
2831
+ ref: (node) => {
2832
+ triggerRef.current = node;
2833
+ if (typeof ref === "function") {
2834
+ ref(node);
2835
+ } else if (ref) {
2836
+ ref.current = node;
2837
+ }
2838
+ },
2839
+ className,
2840
+ onClick: handleClick,
2841
+ ...props,
2842
+ children
2843
+ }
2844
+ );
2845
+ }
2846
+ );
2847
+ PopoverTrigger.displayName = "PopoverTrigger";
2848
+ var PopoverContent = React11.forwardRef(
2849
+ ({
2850
+ className,
2851
+ side = "bottom",
2852
+ align = "start",
2853
+ sideOffset = 4,
2854
+ alignOffset = 0,
2855
+ children,
2856
+ ...props
2857
+ }, ref) => {
2858
+ const { open, setOpen, triggerRef } = usePopoverContext();
2859
+ const [position, setPosition] = React11.useState({ top: 0, left: 0 });
2860
+ const contentRef = React11.useRef(null);
2861
+ React11.useEffect(() => {
2862
+ if (!open || !triggerRef.current) return;
2863
+ const updatePosition = () => {
2864
+ if (!triggerRef.current || !contentRef.current) return;
2865
+ const triggerRect = triggerRef.current.getBoundingClientRect();
2866
+ const contentRect = contentRef.current.getBoundingClientRect();
2867
+ const scrollX = window.scrollX;
2868
+ const scrollY = window.scrollY;
2869
+ let top = 0;
2870
+ let left = 0;
2871
+ switch (side) {
2872
+ case "bottom":
2873
+ top = triggerRect.bottom + sideOffset + scrollY;
2874
+ break;
2875
+ case "top":
2876
+ top = triggerRect.top - contentRect.height - sideOffset + scrollY;
2877
+ break;
2878
+ case "right":
2879
+ top = triggerRect.top + scrollY;
2880
+ left = triggerRect.right + sideOffset + scrollX;
2881
+ break;
2882
+ case "left":
2883
+ top = triggerRect.top + scrollY;
2884
+ left = triggerRect.left - contentRect.width - sideOffset + scrollX;
2885
+ break;
2886
+ }
2887
+ switch (align) {
2888
+ case "start":
2889
+ if (side === "top" || side === "bottom") {
2890
+ left = triggerRect.left + scrollX + alignOffset;
2891
+ } else {
2892
+ top += alignOffset;
2893
+ }
2894
+ break;
2895
+ case "center":
2896
+ if (side === "top" || side === "bottom") {
2897
+ left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2 + scrollX + alignOffset;
2898
+ } else {
2899
+ top += triggerRect.height / 2 - contentRect.height / 2 + alignOffset;
2900
+ }
2901
+ break;
2902
+ case "end":
2903
+ if (side === "top" || side === "bottom") {
2904
+ left = triggerRect.left + triggerRect.width - contentRect.width + scrollX + alignOffset;
2905
+ } else {
2906
+ top += triggerRect.height - contentRect.height + alignOffset;
2907
+ }
2908
+ break;
2909
+ }
2910
+ setPosition({ top, left });
2911
+ };
2912
+ requestAnimationFrame(() => {
2913
+ updatePosition();
2914
+ });
2915
+ window.addEventListener("resize", updatePosition);
2916
+ window.addEventListener("scroll", updatePosition, true);
2917
+ return () => {
2918
+ window.removeEventListener("resize", updatePosition);
2919
+ window.removeEventListener("scroll", updatePosition, true);
2920
+ };
2921
+ }, [open, side, align, sideOffset, alignOffset, triggerRef]);
2922
+ React11.useEffect(() => {
2923
+ if (!open) return;
2924
+ const handleClickOutside = (event) => {
2925
+ if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
2926
+ setOpen(false);
2927
+ }
2928
+ };
2929
+ const handleEscape = (event) => {
2930
+ if (event.key === "Escape") {
2931
+ setOpen(false);
2932
+ }
2933
+ };
2934
+ document.addEventListener("mousedown", handleClickOutside);
2935
+ document.addEventListener("keydown", handleEscape);
2936
+ return () => {
2937
+ document.removeEventListener("mousedown", handleClickOutside);
2938
+ document.removeEventListener("keydown", handleEscape);
2939
+ };
2940
+ }, [open, setOpen, triggerRef]);
2941
+ if (!open) return null;
2942
+ const content = /* @__PURE__ */ jsx(
2943
+ "div",
2944
+ {
2945
+ ref: (node) => {
2946
+ contentRef.current = node;
2947
+ if (typeof ref === "function") {
2948
+ ref(node);
2949
+ } else if (ref) {
2950
+ ref.current = node;
2951
+ }
2952
+ },
2953
+ className: cn(
2954
+ "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",
2955
+ className
2956
+ ),
2957
+ style: {
2958
+ position: "absolute",
2959
+ top: `${position.top}px`,
2960
+ left: `${position.left}px`
2961
+ },
2962
+ ...props,
2963
+ children
2964
+ }
2965
+ );
2966
+ return createPortal(content, document.body);
2967
+ }
2968
+ );
2969
+ PopoverContent.displayName = "PopoverContent";
2970
+ var ThreadPopover = ({
2971
+ className,
2972
+ buttonClassName,
2973
+ buttonVariant = "ghost",
2974
+ buttonSize = "icon",
2975
+ emptyState,
2976
+ onThreadSelect
2977
+ }) => {
2978
+ const [isOpen, setIsOpen] = React11.useState(false);
2979
+ useHotkeys(
2980
+ "h",
2981
+ (e) => {
2982
+ e.preventDefault();
2983
+ setIsOpen((prev) => !prev);
2984
+ },
2985
+ {
2986
+ enableOnFormTags: false,
2987
+ // Don't trigger when typing in form inputs
2988
+ enableOnContentEditable: false
2989
+ // Don't trigger in contenteditable elements
2990
+ }
2991
+ );
2992
+ const handleThreadSelect = (threadId) => {
2993
+ setIsOpen(false);
2994
+ onThreadSelect?.(threadId);
2995
+ };
2996
+ return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
2997
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2998
+ Button,
2999
+ {
3000
+ variant: buttonVariant,
3001
+ size: buttonSize,
3002
+ className: cn(buttonClassName),
3003
+ children: /* @__PURE__ */ jsx(IconHistory, { className: "size-4" })
3004
+ }
3005
+ ) }),
3006
+ /* @__PURE__ */ jsx(
3007
+ PopoverContent,
3008
+ {
3009
+ className: cn("w-80 p-0", className),
3010
+ side: "bottom",
3011
+ align: "start",
3012
+ sideOffset: 8,
3013
+ children: /* @__PURE__ */ jsx("div", { className: "flex flex-col h-[400px]", children: /* @__PURE__ */ jsx(
3014
+ ThreadList,
3015
+ {
3016
+ emptyState,
3017
+ onThreadSelect: handleThreadSelect,
3018
+ className: "h-full"
3019
+ }
3020
+ ) })
3021
+ }
3022
+ )
3023
+ ] });
3024
+ };
3025
+ var CreateThreadButton = ({
3026
+ className,
3027
+ variant = "ghost",
3028
+ size = "icon",
3029
+ children,
3030
+ onThreadCreated
3031
+ }) => {
3032
+ const { createThread } = useThreads();
3033
+ const [isCreating, setIsCreating] = React11.useState(false);
3034
+ const handleCreateThread = async () => {
3035
+ if (isCreating) return;
3036
+ try {
3037
+ setIsCreating(true);
3038
+ const threadId = await createThread();
3039
+ onThreadCreated?.(threadId);
3040
+ } catch (error) {
3041
+ console.error("Failed to create thread:", error);
3042
+ } finally {
3043
+ setIsCreating(false);
3044
+ }
3045
+ };
3046
+ useHotkeys(
3047
+ "n",
3048
+ (e) => {
3049
+ e.preventDefault();
3050
+ handleCreateThread();
3051
+ },
3052
+ {
3053
+ enableOnFormTags: false,
3054
+ // Don't trigger when typing in form inputs
3055
+ enableOnContentEditable: false
3056
+ // Don't trigger in contenteditable elements
3057
+ }
3058
+ );
3059
+ return /* @__PURE__ */ jsx(
3060
+ Button,
3061
+ {
3062
+ variant,
3063
+ size,
3064
+ onClick: handleCreateThread,
3065
+ disabled: isCreating,
3066
+ className: cn(className),
3067
+ children: /* @__PURE__ */ jsx(IconPlus, { className: "size-4" })
3068
+ }
3069
+ );
3070
+ };
2354
3071
  function AlertDialog({ ...props }) {
2355
3072
  return /* @__PURE__ */ jsx(AlertDialog$1.Root, { "data-slot": "alert-dialog", ...props });
2356
3073
  }
@@ -2433,100 +3150,111 @@ function AlertDialogDescription({
2433
3150
  }
2434
3151
  );
2435
3152
  }
2436
- function DropdownMenu({ ...props }) {
2437
- return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
2438
- }
2439
- function DropdownMenuTrigger({ ...props }) {
2440
- return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
2441
- }
2442
- function DropdownMenuContent({
2443
- align = "start",
2444
- alignOffset = 0,
2445
- side = "bottom",
2446
- sideOffset = 4,
2447
- className,
2448
- ...props
2449
- }) {
2450
- return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
2451
- Menu.Positioner,
2452
- {
2453
- className: "isolate z-50 outline-none",
2454
- align,
2455
- alignOffset,
2456
- side,
2457
- sideOffset,
2458
- children: /* @__PURE__ */ jsx(
2459
- Menu.Popup,
2460
- {
2461
- "data-slot": "dropdown-menu-content",
2462
- 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),
2463
- ...props
2464
- }
2465
- )
2466
- }
2467
- ) });
2468
- }
2469
- function DropdownMenuItem({
2470
- className,
2471
- inset,
2472
- variant = "default",
2473
- ...props
2474
- }) {
2475
- return /* @__PURE__ */ jsx(
2476
- Menu.Item,
2477
- {
2478
- "data-slot": "dropdown-menu-item",
2479
- "data-inset": inset,
2480
- "data-variant": variant,
2481
- className: cn(
2482
- "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",
2483
- className
2484
- ),
2485
- ...props
2486
- }
2487
- );
2488
- }
2489
3153
  var AccountDialog = ({
2490
3154
  className,
2491
- variant,
3155
+ variant = "outline",
2492
3156
  size
2493
3157
  }) => {
2494
- const { isLoading, isAuthenticated, login, logout } = useAuth();
2495
- const [open, setOpen] = React10.useState(false);
2496
- const [error, setError] = React10.useState(null);
3158
+ const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3159
+ const [open, setOpen] = React11.useState(false);
3160
+ const [accountInfoOpen, setAccountInfoOpen] = React11.useState(false);
3161
+ const [error, setError] = React11.useState(null);
3162
+ const initials = React11.useMemo(() => {
3163
+ const name = user?.displayName || user?.name;
3164
+ if (!name) return "";
3165
+ return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
3166
+ }, [user?.displayName, user?.name]);
2497
3167
  const handleGoogleSignIn = async () => {
2498
3168
  login();
2499
3169
  };
2500
3170
  if (isAuthenticated) {
2501
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2502
- /* @__PURE__ */ jsx(
2503
- DropdownMenuTrigger,
2504
- {
2505
- render: (props) => /* @__PURE__ */ jsxs(
2506
- Button,
2507
- {
2508
- variant,
2509
- size,
2510
- ...props,
2511
- className,
2512
- children: [
2513
- /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
2514
- "Account"
2515
- ]
2516
- }
2517
- )
2518
- }
2519
- ),
2520
- /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
2521
- /* @__PURE__ */ jsxs(DropdownMenuItem, { children: [
2522
- /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
2523
- "Account"
3171
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3172
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
3173
+ /* @__PURE__ */ jsx(
3174
+ DropdownMenuTrigger,
3175
+ {
3176
+ render: (props) => /* @__PURE__ */ jsx(
3177
+ Button,
3178
+ {
3179
+ variant,
3180
+ size: "icon",
3181
+ ...props,
3182
+ className: cn("rounded-full", className),
3183
+ children: user?.picture ? /* @__PURE__ */ jsx(
3184
+ "img",
3185
+ {
3186
+ src: user.picture,
3187
+ alt: user.displayName || user.name,
3188
+ className: "size-7 rounded-full object-cover"
3189
+ }
3190
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-7 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) })
3191
+ }
3192
+ )
3193
+ }
3194
+ ),
3195
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
3196
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2", children: [
3197
+ user?.picture ? /* @__PURE__ */ jsx(
3198
+ "img",
3199
+ {
3200
+ src: user.picture,
3201
+ alt: user.displayName || user.name,
3202
+ className: "size-8 rounded-full object-cover"
3203
+ }
3204
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) }),
3205
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-0.5 overflow-hidden", children: [
3206
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: user?.displayName || user?.name }),
3207
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: user?.email })
3208
+ ] })
3209
+ ] }),
3210
+ /* @__PURE__ */ jsx(Separator, { className: "my-1" }),
3211
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setAccountInfoOpen(true), children: [
3212
+ /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
3213
+ "Account Settings"
3214
+ ] }),
3215
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: logout, className: "text-destructive", children: [
3216
+ /* @__PURE__ */ jsx(IconLogout, { className: "mr-2 size-4" }),
3217
+ "Logout"
3218
+ ] })
3219
+ ] })
3220
+ ] }),
3221
+ /* @__PURE__ */ jsx(Dialog, { open: accountInfoOpen, onOpenChange: setAccountInfoOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
3222
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
3223
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Account Information" }),
3224
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Your account details and settings." })
2524
3225
  ] }),
2525
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: logout, children: [
2526
- /* @__PURE__ */ jsx(IconLogout, { className: "mr-2 size-4" }),
2527
- "Logout"
3226
+ /* @__PURE__ */ jsxs(DialogClose, { children: [
3227
+ /* @__PURE__ */ jsx(IconX, { className: "size-4" }),
3228
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
3229
+ ] }),
3230
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 py-4", children: [
3231
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
3232
+ user?.picture ? /* @__PURE__ */ jsx(
3233
+ "img",
3234
+ {
3235
+ src: user.picture,
3236
+ alt: user.displayName || user.name,
3237
+ className: "size-16 rounded-full object-cover"
3238
+ }
3239
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-muted text-xl font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-8 text-muted-foreground" }) }),
3240
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3241
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: user?.displayName || user?.name }),
3242
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: user?.email })
3243
+ ] })
3244
+ ] }),
3245
+ /* @__PURE__ */ jsx(Separator, {}),
3246
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
3247
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
3248
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "User ID" }),
3249
+ /* @__PURE__ */ jsx("p", { className: "font-mono text-xs truncate", children: user?.uid || user?.id })
3250
+ ] }),
3251
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
3252
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Created At" }),
3253
+ /* @__PURE__ */ jsx("p", { className: "text-xs", children: user?.createdAt || "N/A" })
3254
+ ] })
3255
+ ] })
2528
3256
  ] })
2529
- ] })
3257
+ ] }) })
2530
3258
  ] });
2531
3259
  }
2532
3260
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2604,6 +3332,6 @@ function ThemeToggle() {
2604
3332
  );
2605
3333
  }
2606
3334
 
2607
- export { AccountDialog, AuthContext, AuthProvider, ChatFull, ChatHeader, ChatPopup, ChatSidebar, Composer, MelonyClientProvider, MelonyContext, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadProvider, UIRenderer, groupEventsToMessages, useAuth, useMelony, useTheme, useThreads };
3335
+ export { AccountDialog, AuthContext, AuthProvider, ChatFull, ChatHeader, ChatPopup, ChatSidebar, Composer, CreateThreadButton, MelonyClientProvider, MelonyContext, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, groupEventsToMessages, useAuth, useMelony, useTheme, useThreads };
2608
3336
  //# sourceMappingURL=index.js.map
2609
3337
  //# sourceMappingURL=index.js.map