@melony/react 0.1.24 → 0.1.26

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 React10__default, { createContext, useState, useCallback, useEffect, useMemo, useContext, useRef } from 'react';
1
+ import * as React12 from 'react';
2
+ import React12__default, { createContext, useState, useCallback, useEffect, useMemo, useContext, useRef } from 'react';
3
3
  import { NuqsAdapter } from 'nuqs/adapters/react';
4
4
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -9,13 +9,13 @@ import { clsx } from 'clsx';
9
9
  import { twMerge } from 'tailwind-merge';
10
10
  import { Button as Button$1 } from '@base-ui/react/button';
11
11
  import { cva } from 'class-variance-authority';
12
+ import { mergeProps } from '@base-ui/react/merge-props';
13
+ import { useRender } from '@base-ui/react/use-render';
12
14
  import * as ICONS from '@tabler/icons-react';
13
- import { IconX, IconPaperclip, IconChevronDown, IconLoader2, IconArrowUp, IconPlus, IconMessage, IconTrash, IconHistory, IconArrowLeft, IconChevronLeft, IconChevronRight, IconUser, IconLogout, IconBrandGoogle, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconChevronUp, IconSelector } from '@tabler/icons-react';
15
+ import { IconPaperclip, IconX, IconPlus, IconChevronDown, IconLoader2, IconArrowUp, IconMessage, IconDotsVertical, IconTrash, IconHistory, IconArrowLeft, IconBrandGoogle, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconUser, IconLogout, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconSelector, IconChevronUp } from '@tabler/icons-react';
14
16
  import { Menu } from '@base-ui/react/menu';
15
17
  import { Separator as Separator$1 } from '@base-ui/react/separator';
16
18
  import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
17
- import { mergeProps } from '@base-ui/react/merge-props';
18
- import { useRender } from '@base-ui/react/use-render';
19
19
  import { Input as Input$1 } from '@base-ui/react/input';
20
20
  import { Select as Select$1 } from '@base-ui/react/select';
21
21
  import { createPortal } from 'react-dom';
@@ -63,14 +63,12 @@ var MelonyContextProviderInner = ({
63
63
  children,
64
64
  client,
65
65
  initialEvents,
66
- configApi,
67
66
  setContextValue
68
67
  }) => {
69
68
  const [state, setState] = useState(client.getState());
70
69
  const { data: config } = useQuery({
71
- queryKey: ["melony-config", configApi],
72
- queryFn: () => client.getConfig(configApi),
73
- enabled: !!configApi,
70
+ queryKey: ["melony-config", client.url],
71
+ queryFn: () => client.getConfig(),
74
72
  staleTime: Infinity
75
73
  });
76
74
  useEffect(() => {
@@ -85,17 +83,56 @@ var MelonyContextProviderInner = ({
85
83
  unsubscribe();
86
84
  };
87
85
  }, [client]);
86
+ const reset = useCallback(
87
+ (events) => client.reset(events),
88
+ [client]
89
+ );
90
+ const dispatchClientAction = useCallback(
91
+ async (event) => {
92
+ if (!event.type.startsWith("client:")) return false;
93
+ switch (event.type) {
94
+ case "client:navigate": {
95
+ const url = event.data?.url;
96
+ if (url) {
97
+ window.history.pushState(null, "", url);
98
+ window.dispatchEvent(new PopStateEvent("popstate"));
99
+ }
100
+ return true;
101
+ }
102
+ case "client:open-url": {
103
+ const { url, target = "_blank" } = event.data || {};
104
+ if (url) {
105
+ window.open(url, target);
106
+ }
107
+ return true;
108
+ }
109
+ case "client:copy": {
110
+ const { text } = event.data || {};
111
+ if (text) {
112
+ await navigator.clipboard.writeText(text);
113
+ }
114
+ return true;
115
+ }
116
+ case "client:reset": {
117
+ reset([]);
118
+ return true;
119
+ }
120
+ default:
121
+ return false;
122
+ }
123
+ },
124
+ [client, reset]
125
+ );
88
126
  const sendEvent = useCallback(
89
127
  async (event, options) => {
128
+ const handled = await dispatchClientAction(event);
129
+ if (handled) return;
90
130
  const generator = client.sendEvent(event, options);
91
- for await (const _ of generator) {
131
+ for await (const incomingEvent of generator) {
132
+ await dispatchClientAction(incomingEvent);
92
133
  }
93
134
  },
94
- [client]
95
- );
96
- const reset = useCallback(
97
- (events) => client.reset(events),
98
- [client]
135
+ [client, dispatchClientAction]
99
136
  );
100
137
  const value = useMemo(
101
138
  () => ({
@@ -117,8 +154,7 @@ var MelonyClientProvider = ({
117
154
  children,
118
155
  client,
119
156
  initialEvents,
120
- queryClient = defaultQueryClient,
121
- configApi
157
+ queryClient = defaultQueryClient
122
158
  }) => {
123
159
  const [contextValue, setContextValue] = useState(void 0);
124
160
  return /* @__PURE__ */ jsx(MelonyContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(
@@ -126,7 +162,6 @@ var MelonyClientProvider = ({
126
162
  {
127
163
  client,
128
164
  initialEvents,
129
- configApi,
130
165
  setContextValue,
131
166
  children
132
167
  }
@@ -377,6 +412,47 @@ var useThreads = () => {
377
412
  }
378
413
  return context;
379
414
  };
415
+ function useScreenSize(mobileBreakpoint = 768, tabletBreakpoint = 1024) {
416
+ const [screenSize, setScreenSize] = useState(() => {
417
+ if (typeof window === "undefined") {
418
+ return {
419
+ width: 1024,
420
+ height: 768,
421
+ isMobile: false,
422
+ isTablet: false,
423
+ isDesktop: true
424
+ };
425
+ }
426
+ const width = window.innerWidth;
427
+ return {
428
+ width,
429
+ height: window.innerHeight,
430
+ isMobile: width < mobileBreakpoint,
431
+ isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
432
+ isDesktop: width >= tabletBreakpoint
433
+ };
434
+ });
435
+ useEffect(() => {
436
+ if (typeof window === "undefined") return;
437
+ const updateScreenSize = () => {
438
+ const width = window.innerWidth;
439
+ const height = window.innerHeight;
440
+ setScreenSize({
441
+ width,
442
+ height,
443
+ isMobile: width < mobileBreakpoint,
444
+ isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
445
+ isDesktop: width >= tabletBreakpoint
446
+ });
447
+ };
448
+ updateScreenSize();
449
+ window.addEventListener("resize", updateScreenSize);
450
+ return () => {
451
+ window.removeEventListener("resize", updateScreenSize);
452
+ };
453
+ }, [mobileBreakpoint, tabletBreakpoint]);
454
+ return screenSize;
455
+ }
380
456
  function cn(...inputs) {
381
457
  return twMerge(clsx(inputs));
382
458
  }
@@ -437,6 +513,45 @@ function Textarea({ className, ...props }) {
437
513
  }
438
514
  );
439
515
  }
516
+ var badgeVariants = cva(
517
+ "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
518
+ {
519
+ variants: {
520
+ variant: {
521
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
522
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
523
+ destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
524
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/30",
525
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
526
+ link: "text-primary underline-offset-4 hover:underline"
527
+ }
528
+ },
529
+ defaultVariants: {
530
+ variant: "default"
531
+ }
532
+ }
533
+ );
534
+ function Badge({
535
+ className,
536
+ variant = "default",
537
+ render,
538
+ ...props
539
+ }) {
540
+ return useRender({
541
+ defaultTagName: "span",
542
+ props: mergeProps(
543
+ {
544
+ className: cn(badgeVariants({ className, variant }))
545
+ },
546
+ props
547
+ ),
548
+ render,
549
+ state: {
550
+ slot: "badge",
551
+ variant
552
+ }
553
+ });
554
+ }
440
555
  function DropdownMenu({ ...props }) {
441
556
  return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
442
557
  }
@@ -564,21 +679,17 @@ function Composer({
564
679
  options = [],
565
680
  autoFocus = false,
566
681
  defaultSelectedIds = [],
567
- fileAttachments,
568
- // Legacy props for backward compatibility
569
- accept: legacyAccept,
570
- maxFiles: legacyMaxFiles,
571
- maxFileSize: legacyMaxFileSize
682
+ fileAttachments
572
683
  }) {
573
- const enabled = fileAttachments?.enabled !== false;
574
- const accept = fileAttachments?.accept ?? legacyAccept;
575
- const maxFiles = fileAttachments?.maxFiles ?? legacyMaxFiles ?? 10;
576
- const maxFileSize = fileAttachments?.maxFileSize ?? legacyMaxFileSize ?? 10 * 1024 * 1024;
577
- const [selectedOptions, setSelectedOptions] = React10__default.useState(
684
+ const enabled = fileAttachments?.enabled || false;
685
+ const accept = fileAttachments?.accept;
686
+ const maxFiles = fileAttachments?.maxFiles ?? 10;
687
+ const maxFileSize = fileAttachments?.maxFileSize ?? 10 * 1024 * 1024;
688
+ const [selectedOptions, setSelectedOptions] = React12__default.useState(
578
689
  () => new Set(defaultSelectedIds)
579
690
  );
580
- const [attachedFiles, setAttachedFiles] = React10__default.useState([]);
581
- const fileInputRef = React10__default.useRef(null);
691
+ const [attachedFiles, setAttachedFiles] = React12__default.useState([]);
692
+ const fileInputRef = React12__default.useRef(null);
582
693
  const toggleOption = (id, groupOptions, type = "multiple") => {
583
694
  const next = new Set(selectedOptions);
584
695
  if (type === "single") {
@@ -602,7 +713,9 @@ function Composer({
602
713
  const files = Array.from(e.target.files || []);
603
714
  const validFiles = files.filter((file) => {
604
715
  if (file.size > maxFileSize) {
605
- console.warn(`File ${file.name} exceeds maximum size of ${maxFileSize} bytes`);
716
+ console.warn(
717
+ `File ${file.name} exceeds maximum size of ${maxFileSize} bytes`
718
+ );
606
719
  return false;
607
720
  }
608
721
  return true;
@@ -610,7 +723,9 @@ function Composer({
610
723
  const remainingSlots = maxFiles - attachedFiles.length;
611
724
  const filesToAdd = validFiles.slice(0, remainingSlots);
612
725
  if (filesToAdd.length < validFiles.length) {
613
- console.warn(`Only ${filesToAdd.length} files can be added (max: ${maxFiles})`);
726
+ console.warn(
727
+ `Only ${filesToAdd.length} files can be added (max: ${maxFiles})`
728
+ );
614
729
  }
615
730
  setAttachedFiles((prev) => [...prev, ...filesToAdd]);
616
731
  if (fileInputRef.current) {
@@ -653,12 +768,11 @@ function Composer({
653
768
  reject(new Error("FileReader returned empty result"));
654
769
  return;
655
770
  }
656
- const base64Data = base64.includes(",") ? base64.split(",")[1] : base64;
657
771
  resolve({
658
772
  name: file.name,
659
773
  type: file.type,
660
774
  size: file.size,
661
- data: base64Data
775
+ data: base64
662
776
  });
663
777
  } catch (error) {
664
778
  reject(error);
@@ -691,129 +805,189 @@ function Composer({
691
805
  handleInternalSubmit().catch(console.error);
692
806
  }
693
807
  };
694
- return /* @__PURE__ */ jsxs("div", { className: cn("relative flex flex-col w-full", className), children: [
695
- enabled && attachedFiles.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-2 flex flex-wrap gap-2", children: attachedFiles.map((file, index) => /* @__PURE__ */ jsxs(
696
- "div",
808
+ 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: [
809
+ /* @__PURE__ */ jsx(
810
+ Textarea,
697
811
  {
698
- className: "flex items-center gap-2 px-3 py-1.5 bg-muted rounded-lg text-sm",
699
- children: [
700
- /* @__PURE__ */ jsx("span", { className: "truncate max-w-[200px]", title: file.name, children: file.name }),
701
- /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: formatFileSize(file.size) }),
812
+ value,
813
+ onChange: (e) => onChange(e.target.value),
814
+ onKeyDown: handleKeyDown,
815
+ placeholder,
816
+ 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",
817
+ autoFocus
818
+ }
819
+ ),
820
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center px-1", children: [
821
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
822
+ enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
702
823
  /* @__PURE__ */ jsx(
703
- "button",
824
+ "input",
825
+ {
826
+ ref: fileInputRef,
827
+ type: "file",
828
+ multiple: true,
829
+ accept,
830
+ onChange: handleFileSelect,
831
+ className: "hidden",
832
+ disabled: isLoading || attachedFiles.length >= maxFiles
833
+ }
834
+ ),
835
+ attachedFiles.length === 0 ? /* @__PURE__ */ jsx(
836
+ Button,
704
837
  {
705
838
  type: "button",
706
- onClick: () => handleRemoveFile(index),
707
- className: "ml-1 hover:bg-muted-foreground/20 rounded p-0.5 transition-colors",
708
- "aria-label": "Remove file",
709
- children: /* @__PURE__ */ jsx(IconX, { className: "h-3.5 w-3.5" })
839
+ variant: "ghost",
840
+ size: "sm",
841
+ onClick: () => fileInputRef.current?.click(),
842
+ disabled: isLoading,
843
+ className: "text-muted-foreground",
844
+ title: "Attach file",
845
+ children: /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" })
710
846
  }
711
- )
712
- ]
713
- },
714
- index
715
- )) }),
716
- /* @__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: [
717
- /* @__PURE__ */ jsx(
718
- Textarea,
719
- {
720
- value,
721
- onChange: (e) => onChange(e.target.value),
722
- onKeyDown: handleKeyDown,
723
- placeholder,
724
- 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",
725
- autoFocus
726
- }
727
- ),
728
- /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center px-1", children: [
729
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
730
- enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
847
+ ) : /* @__PURE__ */ jsxs(DropdownMenu, { children: [
731
848
  /* @__PURE__ */ jsx(
732
- "input",
849
+ DropdownMenuTrigger,
733
850
  {
734
- ref: fileInputRef,
735
- type: "file",
736
- multiple: true,
737
- accept,
738
- onChange: handleFileSelect,
739
- className: "hidden",
740
- disabled: isLoading || attachedFiles.length >= maxFiles
851
+ render: /* @__PURE__ */ jsxs(
852
+ Button,
853
+ {
854
+ type: "button",
855
+ variant: "ghost",
856
+ size: "sm",
857
+ className: "text-muted-foreground gap-2",
858
+ title: `${attachedFiles.length} files attached`,
859
+ children: [
860
+ /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" }),
861
+ /* @__PURE__ */ jsx(Badge, { className: "h-[18px] min-w-[18px] px-1.5 text-[10px]", children: attachedFiles.length })
862
+ ]
863
+ }
864
+ )
741
865
  }
742
866
  ),
743
- /* @__PURE__ */ jsx(
744
- Button,
745
- {
746
- type: "button",
747
- variant: "ghost",
748
- size: "sm",
749
- onClick: () => fileInputRef.current?.click(),
750
- disabled: isLoading || attachedFiles.length >= maxFiles,
751
- className: "text-muted-foreground",
752
- title: attachedFiles.length >= maxFiles ? `Maximum ${maxFiles} files allowed` : "Attach file",
753
- children: /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" })
754
- }
755
- )
756
- ] }),
757
- options.map((group) => {
758
- const selectedInGroup = group.options.filter(
759
- (o) => selectedOptions.has(o.id)
760
- );
761
- const label = selectedInGroup.length === 0 ? group.label : selectedInGroup.length === 1 ? selectedInGroup[0].label : `${group.label} (${selectedInGroup.length})`;
762
- const isSingle = group.type === "single";
763
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
764
- /* @__PURE__ */ jsx(
765
- DropdownMenuTrigger,
766
- {
767
- render: /* @__PURE__ */ jsxs(
768
- Button,
769
- {
770
- variant: "ghost",
771
- size: "sm",
772
- className: cn(
773
- selectedInGroup.length > 0 ? "text-foreground bg-muted/50" : "text-muted-foreground"
774
- ),
775
- children: [
776
- label,
777
- /* @__PURE__ */ jsx(IconChevronDown, { className: "h-3 w-3 opacity-50" })
778
- ]
779
- }
780
- )
781
- }
782
- ),
783
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-56", children: /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
784
- /* @__PURE__ */ jsx(DropdownMenuLabel, { children: group.label }),
867
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-64", children: [
868
+ /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
869
+ /* @__PURE__ */ jsxs(DropdownMenuLabel, { children: [
870
+ "Attached Files (",
871
+ attachedFiles.length,
872
+ "/",
873
+ maxFiles,
874
+ ")"
875
+ ] }),
785
876
  /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
786
- group.options.map((option) => /* @__PURE__ */ jsx(
787
- DropdownMenuCheckboxItem,
877
+ attachedFiles.map((file, index) => /* @__PURE__ */ jsxs(
878
+ DropdownMenuItem,
788
879
  {
789
- checked: selectedOptions.has(option.id),
790
- onCheckedChange: () => toggleOption(
791
- option.id,
792
- group.options,
793
- isSingle ? "single" : "multiple"
794
- ),
880
+ className: "flex items-center justify-between group",
795
881
  onSelect: (e) => e.preventDefault(),
796
- children: option.label
882
+ children: [
883
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
884
+ /* @__PURE__ */ jsx(
885
+ "span",
886
+ {
887
+ className: "truncate text-sm",
888
+ title: file.name,
889
+ children: file.name
890
+ }
891
+ ),
892
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatFileSize(file.size) })
893
+ ] }),
894
+ /* @__PURE__ */ jsx(
895
+ Button,
896
+ {
897
+ type: "button",
898
+ variant: "ghost",
899
+ size: "icon",
900
+ className: "h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity",
901
+ onClick: () => handleRemoveFile(index),
902
+ children: /* @__PURE__ */ jsx(IconX, { className: "h-3 w-3" })
903
+ }
904
+ )
905
+ ]
797
906
  },
798
- option.id
907
+ index
799
908
  ))
800
- ] }) })
801
- ] }, group.id);
802
- })
909
+ ] }),
910
+ attachedFiles.length < maxFiles && /* @__PURE__ */ jsxs(Fragment, { children: [
911
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
912
+ /* @__PURE__ */ jsxs(
913
+ DropdownMenuItem,
914
+ {
915
+ onSelect: (e) => {
916
+ e.preventDefault();
917
+ fileInputRef.current?.click();
918
+ },
919
+ className: "text-primary focus:text-primary",
920
+ children: [
921
+ /* @__PURE__ */ jsx(IconPlus, { className: "mr-2 h-4 w-4" }),
922
+ /* @__PURE__ */ jsx("span", { children: "Add more files" })
923
+ ]
924
+ }
925
+ )
926
+ ] })
927
+ ] })
928
+ ] })
803
929
  ] }),
804
- /* @__PURE__ */ jsx(
805
- Button,
806
- {
807
- type: "submit",
808
- disabled: !value.trim() && attachedFiles.length === 0 && !isLoading || isLoading,
809
- size: "icon-lg",
810
- onClick: () => handleInternalSubmit().catch(console.error),
811
- children: isLoading ? /* @__PURE__ */ jsx(IconLoader2, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
812
- }
813
- )
814
- ] })
930
+ options.map((group) => {
931
+ const selectedInGroup = group.options.filter(
932
+ (o) => selectedOptions.has(o.id)
933
+ );
934
+ const label = selectedInGroup.length === 0 ? group.label : selectedInGroup.length === 1 ? selectedInGroup[0].label : group.label;
935
+ const isSingle = group.type === "single";
936
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
937
+ /* @__PURE__ */ jsx(
938
+ DropdownMenuTrigger,
939
+ {
940
+ render: /* @__PURE__ */ jsxs(
941
+ Button,
942
+ {
943
+ variant: "ghost",
944
+ size: "sm",
945
+ className: cn(
946
+ "gap-2",
947
+ selectedInGroup.length > 0 ? "text-foreground bg-muted/50" : "text-muted-foreground"
948
+ ),
949
+ children: [
950
+ label,
951
+ selectedInGroup.length > 1 && /* @__PURE__ */ jsx(Badge, { className: "h-[18px] min-w-[18px] px-1.5 text-[10px]", children: selectedInGroup.length }),
952
+ /* @__PURE__ */ jsx(IconChevronDown, { className: "h-3 w-3 opacity-50" })
953
+ ]
954
+ }
955
+ )
956
+ }
957
+ ),
958
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-56", children: /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
959
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: group.label }),
960
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
961
+ group.options.map((option) => /* @__PURE__ */ jsx(
962
+ DropdownMenuCheckboxItem,
963
+ {
964
+ checked: selectedOptions.has(option.id),
965
+ onCheckedChange: () => toggleOption(
966
+ option.id,
967
+ group.options,
968
+ isSingle ? "single" : "multiple"
969
+ ),
970
+ onSelect: (e) => e.preventDefault(),
971
+ children: option.label
972
+ },
973
+ option.id
974
+ ))
975
+ ] }) })
976
+ ] }, group.id);
977
+ })
978
+ ] }),
979
+ /* @__PURE__ */ jsx(
980
+ Button,
981
+ {
982
+ type: "submit",
983
+ disabled: !value.trim() && attachedFiles.length === 0 && !isLoading || isLoading,
984
+ size: "icon-lg",
985
+ onClick: () => handleInternalSubmit().catch(console.error),
986
+ children: isLoading ? /* @__PURE__ */ jsx(IconLoader2, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
987
+ }
988
+ )
815
989
  ] })
816
- ] });
990
+ ] }) });
817
991
  }
818
992
  function Card({
819
993
  className,
@@ -945,8 +1119,6 @@ var Col = ({
945
1119
  gap = "sm",
946
1120
  align = "start",
947
1121
  justify = "start",
948
- wrap = "nowrap",
949
- flex = 1,
950
1122
  width,
951
1123
  height,
952
1124
  padding,
@@ -996,13 +1168,11 @@ var Col = ({
996
1168
  gapClasses[gap] || "gap-2",
997
1169
  alignClasses[align] || "items-start",
998
1170
  justifyClasses[justify] || "justify-start",
999
- wrap === "wrap" ? "flex-wrap" : "flex-nowrap",
1000
1171
  overflow && overflowClasses[overflow],
1001
1172
  position && positionClasses[position],
1002
1173
  className
1003
1174
  ),
1004
1175
  style: {
1005
- flex,
1006
1176
  width,
1007
1177
  height,
1008
1178
  padding,
@@ -1436,45 +1606,6 @@ var Icon = ({
1436
1606
  }
1437
1607
  );
1438
1608
  };
1439
- var badgeVariants = cva(
1440
- "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
1441
- {
1442
- variants: {
1443
- variant: {
1444
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
1445
- secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
1446
- destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
1447
- outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/30",
1448
- ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
1449
- link: "text-primary underline-offset-4 hover:underline"
1450
- }
1451
- },
1452
- defaultVariants: {
1453
- variant: "default"
1454
- }
1455
- }
1456
- );
1457
- function Badge({
1458
- className,
1459
- variant = "default",
1460
- render,
1461
- ...props
1462
- }) {
1463
- return useRender({
1464
- defaultTagName: "span",
1465
- props: mergeProps(
1466
- {
1467
- className: cn(badgeVariants({ className, variant }))
1468
- },
1469
- props
1470
- ),
1471
- render,
1472
- state: {
1473
- slot: "badge",
1474
- variant
1475
- }
1476
- });
1477
- }
1478
1609
  var Badge2 = ({
1479
1610
  label,
1480
1611
  variant = "primary",
@@ -2063,9 +2194,9 @@ var Select2 = ({
2063
2194
  defaultValue,
2064
2195
  value,
2065
2196
  disabled,
2066
- onValueChange: handleValueChange,
2197
+ onValueChange: (value2) => handleValueChange(value2 || ""),
2067
2198
  children: [
2068
- /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder || "Select an option" }) }),
2199
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
2069
2200
  /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
2070
2201
  ]
2071
2202
  }
@@ -2095,7 +2226,6 @@ var Label2 = ({
2095
2226
  var Checkbox = ({
2096
2227
  label,
2097
2228
  name,
2098
- value = "on",
2099
2229
  checked,
2100
2230
  defaultChecked,
2101
2231
  disabled,
@@ -2110,46 +2240,37 @@ var Checkbox = ({
2110
2240
  ...onChangeAction,
2111
2241
  data: {
2112
2242
  name: name || "",
2113
- value,
2114
2243
  checked: e.target.checked
2115
2244
  }
2116
2245
  });
2117
2246
  }
2118
2247
  };
2119
- return /* @__PURE__ */ jsxs(
2120
- "div",
2121
- {
2122
- className: cn("flex items-center gap-2", className),
2123
- style,
2124
- children: [
2125
- /* @__PURE__ */ jsx(
2126
- "input",
2127
- {
2128
- type: "checkbox",
2129
- name,
2130
- id: name,
2131
- value,
2132
- checked,
2133
- defaultChecked,
2134
- disabled,
2135
- onChange: handleChange,
2136
- className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
2137
- }
2138
- ),
2139
- label && /* @__PURE__ */ jsx(
2140
- Label2,
2141
- {
2142
- htmlFor: name,
2143
- value: label,
2144
- className: cn(
2145
- "cursor-pointer select-none text-sm font-medium leading-none",
2146
- disabled && "cursor-not-allowed opacity-50"
2147
- )
2148
- }
2248
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", className), style, children: [
2249
+ /* @__PURE__ */ jsx(
2250
+ "input",
2251
+ {
2252
+ type: "checkbox",
2253
+ name,
2254
+ id: name,
2255
+ checked,
2256
+ defaultChecked,
2257
+ disabled,
2258
+ onChange: handleChange,
2259
+ className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
2260
+ }
2261
+ ),
2262
+ label && /* @__PURE__ */ jsx(
2263
+ Label2,
2264
+ {
2265
+ htmlFor: name,
2266
+ value: label,
2267
+ className: cn(
2268
+ "cursor-pointer select-none text-sm font-medium leading-none",
2269
+ disabled && "cursor-not-allowed opacity-50"
2149
2270
  )
2150
- ]
2151
- }
2152
- );
2271
+ }
2272
+ )
2273
+ ] });
2153
2274
  };
2154
2275
  var RadioGroup = ({
2155
2276
  name,
@@ -2472,12 +2593,14 @@ function Thread({
2472
2593
  });
2473
2594
  const starterPrompts = localStarterPrompts ?? config?.starterPrompts;
2474
2595
  const options = localOptions ?? config?.options;
2596
+ const fileAttachments = config?.fileAttachments;
2475
2597
  const allDefaultSelectedIds = useMemo(() => {
2476
- const defaultSelectedIdsFromOptions = options?.flatMap(
2477
- (group) => group.defaultSelectedIds ?? []
2478
- ) ?? [];
2598
+ const defaultSelectedIdsFromOptions = options?.flatMap((group) => group.defaultSelectedIds ?? []) ?? [];
2479
2599
  return [
2480
- .../* @__PURE__ */ new Set([...defaultSelectedIdsFromOptions, ...defaultSelectedIds ?? []])
2600
+ .../* @__PURE__ */ new Set([
2601
+ ...defaultSelectedIdsFromOptions,
2602
+ ...defaultSelectedIds ?? []
2603
+ ])
2481
2604
  ];
2482
2605
  }, [options, defaultSelectedIds]);
2483
2606
  const [input, setInput] = useState("");
@@ -2553,7 +2676,7 @@ function Thread({
2553
2676
  options,
2554
2677
  autoFocus,
2555
2678
  defaultSelectedIds: allDefaultSelectedIds,
2556
- fileAttachments: config?.fileAttachments
2679
+ fileAttachments
2557
2680
  }
2558
2681
  ) }) })
2559
2682
  ]
@@ -2561,20 +2684,36 @@ function Thread({
2561
2684
  );
2562
2685
  }
2563
2686
  function ChatHeader({
2564
- title,
2565
2687
  leftContent,
2566
2688
  rightContent,
2567
2689
  className,
2568
- titleClassName,
2569
2690
  children
2570
2691
  }) {
2571
2692
  if (children) {
2572
- return /* @__PURE__ */ jsx("div", { className: cn("p-4 border-b border-border h-14 flex items-center shrink-0", className), children });
2693
+ return /* @__PURE__ */ jsx(
2694
+ "div",
2695
+ {
2696
+ className: cn(
2697
+ "px-2 border-b border-border h-14 flex items-center shrink-0",
2698
+ className
2699
+ ),
2700
+ children
2701
+ }
2702
+ );
2573
2703
  }
2574
- return /* @__PURE__ */ jsxs("div", { className: cn("p-4 border-b border-border h-14 flex items-center justify-between shrink-0", className), children: [
2575
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: leftContent }),
2576
- rightContent && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: rightContent })
2577
- ] });
2704
+ return /* @__PURE__ */ jsxs(
2705
+ "div",
2706
+ {
2707
+ className: cn(
2708
+ "px-2 border-b border-border h-14 flex items-center justify-between shrink-0",
2709
+ className
2710
+ ),
2711
+ children: [
2712
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: leftContent }),
2713
+ rightContent && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: rightContent })
2714
+ ]
2715
+ }
2716
+ );
2578
2717
  }
2579
2718
  var ThreadList = ({
2580
2719
  className,
@@ -2589,14 +2728,20 @@ var ThreadList = ({
2589
2728
  deleteThread,
2590
2729
  isLoading
2591
2730
  } = useThreads();
2731
+ const sortedThreads = React12.useMemo(() => {
2732
+ return [...threads].sort((a, b) => {
2733
+ const dateA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
2734
+ const dateB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
2735
+ return dateB - dateA;
2736
+ });
2737
+ }, [threads]);
2592
2738
  const handleThreadClick = (threadId) => {
2593
2739
  if (threadId !== activeThreadId) {
2594
2740
  selectThread(threadId);
2595
2741
  }
2596
2742
  onThreadSelect?.(threadId);
2597
2743
  };
2598
- const handleDelete = async (e, threadId) => {
2599
- e.stopPropagation();
2744
+ const handleDelete = async (threadId) => {
2600
2745
  try {
2601
2746
  await deleteThread(threadId);
2602
2747
  } catch (error) {
@@ -2610,32 +2755,16 @@ var ThreadList = ({
2610
2755
  console.error("Failed to create thread:", error);
2611
2756
  }
2612
2757
  };
2613
- const formatDate = (date) => {
2614
- if (!date) return "";
2615
- const d = typeof date === "string" ? new Date(date) : date;
2616
- if (isNaN(d.getTime())) return "";
2617
- const now = /* @__PURE__ */ new Date();
2618
- const diffMs = now.getTime() - d.getTime();
2619
- const diffMins = Math.floor(diffMs / 6e4);
2620
- const diffHours = Math.floor(diffMs / 36e5);
2621
- const diffDays = Math.floor(diffMs / 864e5);
2622
- if (diffMins < 1) return "Just now";
2623
- if (diffMins < 60) return `${diffMins}m ago`;
2624
- if (diffHours < 24) return `${diffHours}h ago`;
2625
- if (diffDays < 7) return `${diffDays}d ago`;
2626
- return d.toLocaleDateString();
2627
- };
2628
2758
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full", className), children: [
2629
2759
  /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs(
2630
2760
  Button,
2631
2761
  {
2632
- variant: "ghost",
2633
- size: "sm",
2762
+ variant: "outline",
2763
+ className: "w-full justify-start gap-2 h-9 px-3 border-dashed hover:border-solid transition-all",
2634
2764
  onClick: handleNewThread,
2635
- className: "w-full justify-start",
2636
2765
  children: [
2637
- /* @__PURE__ */ jsx(IconPlus, { className: "mr-2 size-4" }),
2638
- "New Thread"
2766
+ /* @__PURE__ */ jsx(IconPlus, { className: "size-4" }),
2767
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "New chat" })
2639
2768
  ]
2640
2769
  }
2641
2770
  ) }),
@@ -2643,7 +2772,7 @@ var ThreadList = ({
2643
2772
  /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
2644
2773
  /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" }),
2645
2774
  /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
2646
- ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: threads.map((thread) => {
2775
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: sortedThreads.map((thread) => {
2647
2776
  const isActive = thread.id === activeThreadId;
2648
2777
  return /* @__PURE__ */ jsxs(
2649
2778
  "div",
@@ -2651,26 +2780,44 @@ var ThreadList = ({
2651
2780
  onClick: () => handleThreadClick(thread.id),
2652
2781
  className: cn(
2653
2782
  "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2654
- isActive ? "bg-muted" : "hover:bg-muted"
2783
+ isActive ? "bg-muted text-foreground" : "hover:bg-muted/50 text-muted-foreground hover:text-foreground"
2655
2784
  ),
2656
2785
  children: [
2657
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2658
- /* @__PURE__ */ jsx("p", { className: cn("text-sm font-medium truncate"), children: thread.title || `Thread ${thread.id.slice(0, 8)}` }),
2659
- thread.updatedAt && /* @__PURE__ */ jsx("span", { className: cn("text-xs shrink-0"), children: formatDate(thread.updatedAt) })
2660
- ] }) }),
2661
- /* @__PURE__ */ jsx(
2662
- Button,
2663
- {
2664
- variant: "ghost",
2665
- size: "icon-xs",
2666
- onClick: (e) => handleDelete(e, thread.id),
2667
- className: cn(
2668
- "opacity-0 group-hover:opacity-100 transition-opacity shrink-0",
2669
- isActive && "hover:bg-primary-foreground/20"
2670
- ),
2671
- children: /* @__PURE__ */ jsx(IconTrash, { className: "size-3" })
2672
- }
2673
- )
2786
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: thread.title || `Thread ${thread.id.slice(0, 8)}` }) }),
2787
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2788
+ /* @__PURE__ */ jsx(
2789
+ DropdownMenuTrigger,
2790
+ {
2791
+ render: (props) => /* @__PURE__ */ jsx(
2792
+ Button,
2793
+ {
2794
+ variant: "ghost",
2795
+ size: "icon-xs",
2796
+ ...props,
2797
+ onClick: (e) => {
2798
+ e.stopPropagation();
2799
+ props.onClick?.(e);
2800
+ },
2801
+ children: /* @__PURE__ */ jsx(IconDotsVertical, { className: "size-3.5" })
2802
+ }
2803
+ )
2804
+ }
2805
+ ),
2806
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-32", children: /* @__PURE__ */ jsxs(
2807
+ DropdownMenuItem,
2808
+ {
2809
+ variant: "destructive",
2810
+ onClick: (e) => {
2811
+ e.stopPropagation();
2812
+ handleDelete(thread.id);
2813
+ },
2814
+ children: [
2815
+ /* @__PURE__ */ jsx(IconTrash, { className: "size-4 mr-2" }),
2816
+ /* @__PURE__ */ jsx("span", { children: "Delete" })
2817
+ ]
2818
+ }
2819
+ ) })
2820
+ ] }) })
2674
2821
  ]
2675
2822
  },
2676
2823
  thread.id
@@ -2805,9 +2952,144 @@ function ChatSidebar({
2805
2952
  ) })
2806
2953
  ] });
2807
2954
  }
2955
+ var ChatSidebarContext = createContext(
2956
+ void 0
2957
+ );
2958
+ function useChatSidebar() {
2959
+ const context = useContext(ChatSidebarContext);
2960
+ if (context === void 0) {
2961
+ throw new Error("useChatSidebar must be used within a ChatSidebarProvider");
2962
+ }
2963
+ return context;
2964
+ }
2965
+ function WelcomeScreen({
2966
+ title = "Welcome to Melony",
2967
+ description = "The most powerful AI agent framework for building modern applications. Connect your tools, build your brain, and ship faster.",
2968
+ features = [
2969
+ {
2970
+ title: "Context Aware",
2971
+ description: "Built-in state management for complex LLM flows."
2972
+ },
2973
+ {
2974
+ title: "Extensible",
2975
+ description: "Plugin architecture for easy integrations."
2976
+ },
2977
+ {
2978
+ title: "Real-time",
2979
+ description: "Streaming responses and live state updates."
2980
+ },
2981
+ {
2982
+ title: "Tool-ready",
2983
+ description: "Ready-to-use actions for common tasks."
2984
+ }
2985
+ ],
2986
+ className,
2987
+ onLoginClick,
2988
+ termsUrl = "#",
2989
+ privacyUrl = "#",
2990
+ imageUrl,
2991
+ imageAlt = "Product screenshot"
2992
+ }) {
2993
+ const { login, isLoading } = useAuth();
2994
+ const handleLogin = () => {
2995
+ if (onLoginClick) {
2996
+ onLoginClick();
2997
+ } else {
2998
+ login();
2999
+ }
3000
+ };
3001
+ return /* @__PURE__ */ jsxs(
3002
+ "div",
3003
+ {
3004
+ className: cn(
3005
+ "flex min-h-[600px] h-full w-full flex-col md:flex-row bg-background overflow-hidden",
3006
+ className
3007
+ ),
3008
+ children: [
3009
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col bg-sidebar text-foreground relative overflow-hidden", children: [
3010
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-24 -left-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3011
+ /* @__PURE__ */ jsx("div", { className: "absolute -bottom-24 -right-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3012
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overflow-x-hidden relative z-10 flex flex-col p-8 md:p-12 lg:p-20", children: /* @__PURE__ */ jsxs("div", { className: "max-w-xl mx-auto w-full", children: [
3013
+ /* @__PURE__ */ jsx("h1", { className: "mb-6 text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl text-foreground", children: title }),
3014
+ /* @__PURE__ */ jsx("p", { className: "mb-12 text-lg text-muted-foreground md:text-xl leading-relaxed", children: description }),
3015
+ imageUrl && /* @__PURE__ */ jsxs("div", { className: "mb-12 relative group", children: [
3016
+ /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-gradient-to-r from-primary/20 to-primary/10 rounded-xl blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200" }),
3017
+ /* @__PURE__ */ jsx(
3018
+ "img",
3019
+ {
3020
+ src: imageUrl,
3021
+ alt: imageAlt,
3022
+ className: "relative rounded-xl border border-border/50 shadow-2xl transition-transform duration-500 hover:scale-[1.02] w-full"
3023
+ }
3024
+ )
3025
+ ] }),
3026
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-x-8 gap-y-10 sm:grid-cols-2", children: features.map((feature, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3027
+ /* @__PURE__ */ jsx("h3", { className: "font-bold text-lg text-foreground", children: feature.title }),
3028
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: feature.description })
3029
+ ] }, i)) })
3030
+ ] }) })
3031
+ ] }),
3032
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center justify-center p-8 md:p-12 lg:p-20 bg-background transition-colors duration-300", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-8", children: [
3033
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3 text-center md:text-left", children: [
3034
+ /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: "Get Started" }),
3035
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-lg", children: "Sign in to your account to continue" })
3036
+ ] }),
3037
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3038
+ /* @__PURE__ */ jsxs(
3039
+ Button,
3040
+ {
3041
+ size: "lg",
3042
+ variant: "outline",
3043
+ className: "w-full h-16 text-lg shadow-sm hover:shadow-md transition-all flex items-center justify-center gap-3 border-2 font-medium bg-background text-foreground hover:bg-accent",
3044
+ onClick: handleLogin,
3045
+ disabled: isLoading,
3046
+ children: [
3047
+ /* @__PURE__ */ jsx(IconBrandGoogle, { className: "size-6" }),
3048
+ isLoading ? "Signing in..." : "Continue with Google"
3049
+ ]
3050
+ }
3051
+ ),
3052
+ /* @__PURE__ */ jsxs("div", { className: "relative py-4", children: [
3053
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx("span", { className: "w-full border-t border-border" }) }),
3054
+ /* @__PURE__ */ jsx("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ jsx("span", { className: "bg-background px-3 text-muted-foreground tracking-widest font-medium", children: "Secure access" }) })
3055
+ ] })
3056
+ ] }),
3057
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed text-center md:text-left", children: [
3058
+ "By continuing, you agree to our ",
3059
+ /* @__PURE__ */ jsx("br", { className: "hidden md:block" }),
3060
+ /* @__PURE__ */ jsx(
3061
+ "a",
3062
+ {
3063
+ href: termsUrl,
3064
+ target: "_blank",
3065
+ rel: "noopener noreferrer",
3066
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3067
+ children: "Terms of Service"
3068
+ }
3069
+ ),
3070
+ " ",
3071
+ "and",
3072
+ " ",
3073
+ /* @__PURE__ */ jsx(
3074
+ "a",
3075
+ {
3076
+ href: privacyUrl,
3077
+ target: "_blank",
3078
+ rel: "noopener noreferrer",
3079
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3080
+ children: "Privacy Policy"
3081
+ }
3082
+ ),
3083
+ "."
3084
+ ] })
3085
+ ] }) })
3086
+ ]
3087
+ }
3088
+ );
3089
+ }
2808
3090
  function ChatFull({
2809
3091
  title = "Chat",
2810
- placeholder = "Message the AI",
3092
+ placeholder,
2811
3093
  starterPrompts,
2812
3094
  options,
2813
3095
  className,
@@ -2816,134 +3098,140 @@ function ChatFull({
2816
3098
  rightSidebar,
2817
3099
  leftSidebarClassName,
2818
3100
  rightSidebarClassName,
2819
- leftSidebarCollapsible = false,
2820
- rightSidebarCollapsible = false,
2821
- defaultLeftSidebarCollapsed = false,
2822
- defaultRightSidebarCollapsed = false,
2823
- leftSidebarCollapsed: controlledLeftCollapsed,
2824
- rightSidebarCollapsed: controlledRightCollapsed,
2825
- onLeftSidebarCollapseChange,
2826
- onRightSidebarCollapseChange,
2827
3101
  autoFocus = false,
2828
- defaultSelectedIds
3102
+ defaultSelectedIds,
3103
+ showWelcomeScreen = false,
3104
+ welcomeScreenProps
2829
3105
  }) {
2830
- const [internalLeftCollapsed, setInternalLeftCollapsed] = useState(
2831
- defaultLeftSidebarCollapsed
2832
- );
2833
- const [internalRightCollapsed, setInternalRightCollapsed] = useState(
2834
- defaultRightSidebarCollapsed
2835
- );
2836
- const leftCollapsed = controlledLeftCollapsed !== void 0 ? controlledLeftCollapsed : internalLeftCollapsed;
2837
- const rightCollapsed = controlledRightCollapsed !== void 0 ? controlledRightCollapsed : internalRightCollapsed;
2838
- const handleLeftToggle = () => {
2839
- const newCollapsed = !leftCollapsed;
2840
- if (controlledLeftCollapsed === void 0) {
2841
- setInternalLeftCollapsed(newCollapsed);
3106
+ const { isMobile, isTablet } = useScreenSize();
3107
+ const { isAuthenticated, isLoading } = useAuth();
3108
+ const isSmallScreen = isMobile || isTablet;
3109
+ const [internalLeftCollapsed, setInternalLeftCollapsed] = useState(() => {
3110
+ if (typeof window !== "undefined") {
3111
+ return window.innerWidth < 1024;
2842
3112
  }
2843
- onLeftSidebarCollapseChange?.(newCollapsed);
2844
- };
2845
- const handleRightToggle = () => {
2846
- const newCollapsed = !rightCollapsed;
2847
- if (controlledRightCollapsed === void 0) {
2848
- setInternalRightCollapsed(newCollapsed);
3113
+ return false;
3114
+ });
3115
+ const [internalRightCollapsed, setInternalRightCollapsed] = useState(() => {
3116
+ if (typeof window !== "undefined") {
3117
+ return window.innerWidth < 1024;
2849
3118
  }
2850
- onRightSidebarCollapseChange?.(newCollapsed);
2851
- };
2852
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
2853
- title && /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
2854
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
2855
- leftSidebar && /* @__PURE__ */ jsxs(Fragment, { children: [
2856
- /* @__PURE__ */ jsx(
2857
- "div",
2858
- {
2859
- className: cn(
2860
- "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2861
- leftCollapsed && leftSidebarCollapsible ? "w-0 border-r-0 min-w-0" : "",
2862
- !leftCollapsed && leftSidebarClassName
2863
- ),
2864
- children: !leftCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
2865
- leftSidebarCollapsible && /* @__PURE__ */ jsx("div", { className: "flex justify-end p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsx(
2866
- Button,
2867
- {
2868
- variant: "ghost",
2869
- size: "icon-sm",
2870
- onClick: handleLeftToggle,
2871
- "aria-label": "Collapse left sidebar",
2872
- className: "h-8 w-8",
2873
- children: /* @__PURE__ */ jsx(IconChevronLeft, { className: "h-4 w-4" })
2874
- }
2875
- ) }),
2876
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
2877
- ] })
2878
- }
2879
- ),
2880
- leftSidebarCollapsible && leftCollapsed && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 border-r border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsx(
2881
- Button,
2882
- {
2883
- variant: "ghost",
2884
- size: "icon-sm",
2885
- onClick: handleLeftToggle,
2886
- "aria-label": "Expand left sidebar",
2887
- className: "h-8 w-8",
2888
- children: /* @__PURE__ */ jsx(IconChevronRight, { className: "h-4 w-4" })
2889
- }
2890
- ) })
2891
- ] }),
2892
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
2893
- Thread,
2894
- {
2895
- placeholder,
2896
- starterPrompts,
2897
- options,
2898
- autoFocus,
2899
- defaultSelectedIds
2900
- }
2901
- ) }),
2902
- rightSidebar && /* @__PURE__ */ jsxs(Fragment, { children: [
2903
- 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(
2904
- Button,
2905
- {
2906
- variant: "ghost",
2907
- size: "icon-sm",
2908
- onClick: handleRightToggle,
2909
- "aria-label": "Expand right sidebar",
2910
- className: "h-8 w-8",
2911
- children: /* @__PURE__ */ jsx(IconChevronLeft, { className: "h-4 w-4" })
2912
- }
2913
- ) }),
2914
- /* @__PURE__ */ jsx(
2915
- "div",
2916
- {
2917
- className: cn(
2918
- "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2919
- rightCollapsed && rightSidebarCollapsible ? "w-0 border-l-0 min-w-0" : "",
2920
- !rightCollapsed && rightSidebarClassName
2921
- ),
2922
- children: !rightCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
2923
- rightSidebarCollapsible && /* @__PURE__ */ jsx("div", { className: "flex justify-start p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsx(
2924
- Button,
2925
- {
2926
- variant: "ghost",
2927
- size: "icon-sm",
2928
- onClick: handleRightToggle,
2929
- "aria-label": "Collapse right sidebar",
2930
- className: "h-8 w-8",
2931
- children: /* @__PURE__ */ jsx(IconChevronRight, { className: "h-4 w-4" })
2932
- }
2933
- ) }),
2934
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
2935
- ] })
2936
- }
2937
- )
2938
- ] })
2939
- ] })
2940
- ] });
3119
+ return false;
3120
+ });
3121
+ useEffect(() => {
3122
+ if (isSmallScreen) {
3123
+ setInternalLeftCollapsed(true);
3124
+ setInternalRightCollapsed(true);
3125
+ }
3126
+ }, [isSmallScreen]);
3127
+ const leftCollapsed = internalLeftCollapsed;
3128
+ const rightCollapsed = internalRightCollapsed;
3129
+ const handleLeftToggle = useCallback((collapsed) => {
3130
+ setInternalLeftCollapsed(collapsed);
3131
+ }, []);
3132
+ const handleRightToggle = useCallback((collapsed) => {
3133
+ setInternalRightCollapsed(collapsed);
3134
+ }, []);
3135
+ const contextValue = useMemo(
3136
+ () => ({
3137
+ leftCollapsed,
3138
+ rightCollapsed,
3139
+ setLeftCollapsed: handleLeftToggle,
3140
+ setRightCollapsed: handleRightToggle,
3141
+ leftCollapsible: true,
3142
+ rightCollapsible: true
3143
+ }),
3144
+ [leftCollapsed, rightCollapsed, handleLeftToggle, handleRightToggle]
3145
+ );
3146
+ if (showWelcomeScreen && !isAuthenticated && !isLoading) {
3147
+ return /* @__PURE__ */ jsx(WelcomeScreen, { ...welcomeScreenProps });
3148
+ }
3149
+ return /* @__PURE__ */ jsx(ChatSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
3150
+ "div",
3151
+ {
3152
+ className: cn("flex flex-col h-full w-full bg-background", className),
3153
+ children: [
3154
+ title && /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
3155
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
3156
+ leftSidebar && /* @__PURE__ */ jsx(
3157
+ "div",
3158
+ {
3159
+ className: cn(
3160
+ "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3161
+ leftCollapsed ? "w-0 border-r-0 min-w-0" : "",
3162
+ !leftCollapsed && leftSidebarClassName
3163
+ ),
3164
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
3165
+ }
3166
+ ),
3167
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
3168
+ Thread,
3169
+ {
3170
+ placeholder,
3171
+ starterPrompts,
3172
+ options,
3173
+ autoFocus,
3174
+ defaultSelectedIds
3175
+ }
3176
+ ) }),
3177
+ rightSidebar && /* @__PURE__ */ jsx(
3178
+ "div",
3179
+ {
3180
+ className: cn(
3181
+ "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3182
+ rightCollapsed ? "w-0 border-l-0 min-w-0" : "",
3183
+ !rightCollapsed && rightSidebarClassName
3184
+ ),
3185
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
3186
+ }
3187
+ )
3188
+ ] })
3189
+ ]
3190
+ }
3191
+ ) });
3192
+ }
3193
+ function SidebarToggle({ side, className }) {
3194
+ const {
3195
+ leftCollapsed,
3196
+ rightCollapsed,
3197
+ setLeftCollapsed,
3198
+ setRightCollapsed,
3199
+ leftCollapsible,
3200
+ rightCollapsible
3201
+ } = useChatSidebar();
3202
+ if (side === "left") {
3203
+ if (!leftCollapsible) return null;
3204
+ return /* @__PURE__ */ jsx(
3205
+ Button,
3206
+ {
3207
+ variant: "ghost",
3208
+ onClick: () => setLeftCollapsed(!leftCollapsed),
3209
+ "aria-label": leftCollapsed ? "Expand left sidebar" : "Collapse left sidebar",
3210
+ className: cn("", className),
3211
+ children: leftCollapsed ? /* @__PURE__ */ jsx(IconLayoutSidebarLeftExpand, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(IconLayoutSidebarLeftCollapse, { className: "h-4 w-4" })
3212
+ }
3213
+ );
3214
+ }
3215
+ if (side === "right") {
3216
+ if (!rightCollapsible) return null;
3217
+ return /* @__PURE__ */ jsx(
3218
+ Button,
3219
+ {
3220
+ variant: "ghost",
3221
+ onClick: () => setRightCollapsed(!rightCollapsed),
3222
+ "aria-label": rightCollapsed ? "Expand right sidebar" : "Collapse right sidebar",
3223
+ className: cn("", className),
3224
+ children: rightCollapsed ? /* @__PURE__ */ jsx(IconLayoutSidebarRightExpand, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(IconLayoutSidebarRightCollapse, { className: "h-4 w-4" })
3225
+ }
3226
+ );
3227
+ }
3228
+ return null;
2941
3229
  }
2942
- var PopoverContext = React10.createContext(
3230
+ var PopoverContext = React12.createContext(
2943
3231
  void 0
2944
3232
  );
2945
3233
  function usePopoverContext() {
2946
- const context = React10.useContext(PopoverContext);
3234
+ const context = React12.useContext(PopoverContext);
2947
3235
  if (!context) {
2948
3236
  throw new Error("Popover components must be used within a Popover");
2949
3237
  }
@@ -2955,10 +3243,10 @@ function Popover({
2955
3243
  open: controlledOpen,
2956
3244
  onOpenChange
2957
3245
  }) {
2958
- const [internalOpen, setInternalOpen] = React10.useState(defaultOpen);
2959
- const triggerRef = React10.useRef(null);
3246
+ const [internalOpen, setInternalOpen] = React12.useState(defaultOpen);
3247
+ const triggerRef = React12.useRef(null);
2960
3248
  const open = controlledOpen ?? internalOpen;
2961
- const setOpen = React10.useCallback(
3249
+ const setOpen = React12.useCallback(
2962
3250
  (newOpen) => {
2963
3251
  if (controlledOpen === void 0) {
2964
3252
  setInternalOpen(newOpen);
@@ -2967,7 +3255,7 @@ function Popover({
2967
3255
  },
2968
3256
  [controlledOpen, onOpenChange]
2969
3257
  );
2970
- const value = React10.useMemo(
3258
+ const value = React12.useMemo(
2971
3259
  () => ({
2972
3260
  open,
2973
3261
  setOpen,
@@ -2977,15 +3265,15 @@ function Popover({
2977
3265
  );
2978
3266
  return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
2979
3267
  }
2980
- var PopoverTrigger = React10.forwardRef(
3268
+ var PopoverTrigger = React12.forwardRef(
2981
3269
  ({ asChild, className, children, ...props }, ref) => {
2982
3270
  const { setOpen, triggerRef } = usePopoverContext();
2983
3271
  const handleClick = (e) => {
2984
3272
  setOpen(true);
2985
3273
  props.onClick?.(e);
2986
3274
  };
2987
- if (asChild && React10.isValidElement(children)) {
2988
- return React10.cloneElement(children, {
3275
+ if (asChild && React12.isValidElement(children)) {
3276
+ return React12.cloneElement(children, {
2989
3277
  ref: (node) => {
2990
3278
  triggerRef.current = node;
2991
3279
  if (typeof children.ref === "function") {
@@ -3017,7 +3305,7 @@ var PopoverTrigger = React10.forwardRef(
3017
3305
  }
3018
3306
  );
3019
3307
  PopoverTrigger.displayName = "PopoverTrigger";
3020
- var PopoverContent = React10.forwardRef(
3308
+ var PopoverContent = React12.forwardRef(
3021
3309
  ({
3022
3310
  className,
3023
3311
  side = "bottom",
@@ -3028,9 +3316,9 @@ var PopoverContent = React10.forwardRef(
3028
3316
  ...props
3029
3317
  }, ref) => {
3030
3318
  const { open, setOpen, triggerRef } = usePopoverContext();
3031
- const [position, setPosition] = React10.useState({ top: 0, left: 0 });
3032
- const contentRef = React10.useRef(null);
3033
- React10.useEffect(() => {
3319
+ const [position, setPosition] = React12.useState({ top: 0, left: 0 });
3320
+ const contentRef = React12.useRef(null);
3321
+ React12.useEffect(() => {
3034
3322
  if (!open || !triggerRef.current) return;
3035
3323
  const updatePosition = () => {
3036
3324
  if (!triggerRef.current || !contentRef.current) return;
@@ -3091,7 +3379,7 @@ var PopoverContent = React10.forwardRef(
3091
3379
  window.removeEventListener("scroll", updatePosition, true);
3092
3380
  };
3093
3381
  }, [open, side, align, sideOffset, alignOffset, triggerRef]);
3094
- React10.useEffect(() => {
3382
+ React12.useEffect(() => {
3095
3383
  if (!open) return;
3096
3384
  const handleClickOutside = (event) => {
3097
3385
  if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
@@ -3147,7 +3435,7 @@ var ThreadPopover = ({
3147
3435
  emptyState,
3148
3436
  onThreadSelect
3149
3437
  }) => {
3150
- const [isOpen, setIsOpen] = React10.useState(false);
3438
+ const [isOpen, setIsOpen] = React12.useState(false);
3151
3439
  useHotkeys(
3152
3440
  "h",
3153
3441
  (e) => {
@@ -3202,7 +3490,7 @@ var CreateThreadButton = ({
3202
3490
  onThreadCreated
3203
3491
  }) => {
3204
3492
  const { createThread } = useThreads();
3205
- const [isCreating, setIsCreating] = React10.useState(false);
3493
+ const [isCreating, setIsCreating] = React12.useState(false);
3206
3494
  const handleCreateThread = async () => {
3207
3495
  if (isCreating) return;
3208
3496
  try {
@@ -3328,10 +3616,10 @@ var AccountDialog = ({
3328
3616
  size
3329
3617
  }) => {
3330
3618
  const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3331
- const [open, setOpen] = React10.useState(false);
3332
- const [accountInfoOpen, setAccountInfoOpen] = React10.useState(false);
3333
- const [error, setError] = React10.useState(null);
3334
- const initials = React10.useMemo(() => {
3619
+ const [open, setOpen] = React12.useState(false);
3620
+ const [accountInfoOpen, setAccountInfoOpen] = React12.useState(false);
3621
+ const [error, setError] = React12.useState(null);
3622
+ const initials = React12.useMemo(() => {
3335
3623
  const name = user?.displayName || user?.name;
3336
3624
  if (!name) return "";
3337
3625
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
@@ -3504,6 +3792,6 @@ function ThemeToggle() {
3504
3792
  );
3505
3793
  }
3506
3794
 
3507
- 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 };
3795
+ export { AccountDialog, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatFull, ChatHeader, ChatPopup, ChatSidebar, ChatSidebarContext, Checkbox, Col, Composer, CreateThreadButton, Divider, Form, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyClientProvider, MelonyContext, RadioGroup, Row, Select2 as Select, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, WelcomeScreen, groupEventsToMessages, useAuth, useChatSidebar, useMelony, useScreenSize, useTheme, useThreads };
3508
3796
  //# sourceMappingURL=index.js.map
3509
3797
  //# sourceMappingURL=index.js.map