@melony/react 0.1.24 → 0.1.25

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 React11 from 'react';
2
+ import React11__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, IconTrash, IconHistory, IconArrowLeft, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconUser, IconLogout, IconBrandGoogle, 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] = React11__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] = React11__default.useState([]);
692
+ const fileInputRef = React11__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,
@@ -2625,58 +2764,43 @@ var ThreadList = ({
2625
2764
  if (diffDays < 7) return `${diffDays}d ago`;
2626
2765
  return d.toLocaleDateString();
2627
2766
  };
2628
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full", className), children: [
2629
- /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs(
2630
- Button,
2767
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col h-full", className), children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading && threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) }) : threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2768
+ /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
2769
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" }),
2770
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
2771
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: threads.map((thread) => {
2772
+ const isActive = thread.id === activeThreadId;
2773
+ return /* @__PURE__ */ jsxs(
2774
+ "div",
2631
2775
  {
2632
- variant: "ghost",
2633
- size: "sm",
2634
- onClick: handleNewThread,
2635
- className: "w-full justify-start",
2776
+ onClick: () => handleThreadClick(thread.id),
2777
+ className: cn(
2778
+ "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2779
+ isActive ? "bg-muted" : "hover:bg-muted"
2780
+ ),
2636
2781
  children: [
2637
- /* @__PURE__ */ jsx(IconPlus, { className: "mr-2 size-4" }),
2638
- "New Thread"
2782
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2783
+ /* @__PURE__ */ jsx("p", { className: cn("text-sm font-medium truncate"), children: thread.title || `Thread ${thread.id.slice(0, 8)}` }),
2784
+ thread.updatedAt && /* @__PURE__ */ jsx("span", { className: cn("text-xs shrink-0"), children: formatDate(thread.updatedAt) })
2785
+ ] }) }),
2786
+ /* @__PURE__ */ jsx(
2787
+ Button,
2788
+ {
2789
+ variant: "ghost",
2790
+ size: "icon-xs",
2791
+ onClick: (e) => handleDelete(e, thread.id),
2792
+ className: cn(
2793
+ "opacity-0 group-hover:opacity-100 transition-opacity shrink-0",
2794
+ isActive && "hover:bg-primary-foreground/20"
2795
+ ),
2796
+ children: /* @__PURE__ */ jsx(IconTrash, { className: "size-3" })
2797
+ }
2798
+ )
2639
2799
  ]
2640
- }
2641
- ) }),
2642
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading && threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) }) : threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2643
- /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
2644
- /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" }),
2645
- /* @__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) => {
2647
- const isActive = thread.id === activeThreadId;
2648
- return /* @__PURE__ */ jsxs(
2649
- "div",
2650
- {
2651
- onClick: () => handleThreadClick(thread.id),
2652
- className: cn(
2653
- "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"
2655
- ),
2656
- 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
- )
2674
- ]
2675
- },
2676
- thread.id
2677
- );
2678
- }) }) })
2679
- ] });
2800
+ },
2801
+ thread.id
2802
+ );
2803
+ }) }) }) });
2680
2804
  };
2681
2805
  function ChatPopup({
2682
2806
  title = "Chat",
@@ -2805,6 +2929,16 @@ function ChatSidebar({
2805
2929
  ) })
2806
2930
  ] });
2807
2931
  }
2932
+ var ChatSidebarContext = createContext(
2933
+ void 0
2934
+ );
2935
+ function useChatSidebar() {
2936
+ const context = useContext(ChatSidebarContext);
2937
+ if (context === void 0) {
2938
+ throw new Error("useChatSidebar must be used within a ChatSidebarProvider");
2939
+ }
2940
+ return context;
2941
+ }
2808
2942
  function ChatFull({
2809
2943
  title = "Chat",
2810
2944
  placeholder = "Message the AI",
@@ -2816,134 +2950,134 @@ function ChatFull({
2816
2950
  rightSidebar,
2817
2951
  leftSidebarClassName,
2818
2952
  rightSidebarClassName,
2819
- leftSidebarCollapsible = false,
2820
- rightSidebarCollapsible = false,
2821
- defaultLeftSidebarCollapsed = false,
2822
- defaultRightSidebarCollapsed = false,
2823
- leftSidebarCollapsed: controlledLeftCollapsed,
2824
- rightSidebarCollapsed: controlledRightCollapsed,
2825
- onLeftSidebarCollapseChange,
2826
- onRightSidebarCollapseChange,
2827
2953
  autoFocus = false,
2828
2954
  defaultSelectedIds
2829
2955
  }) {
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);
2956
+ const { isMobile, isTablet } = useScreenSize();
2957
+ const isSmallScreen = isMobile || isTablet;
2958
+ const [internalLeftCollapsed, setInternalLeftCollapsed] = useState(() => {
2959
+ if (typeof window !== "undefined") {
2960
+ return window.innerWidth < 1024;
2842
2961
  }
2843
- onLeftSidebarCollapseChange?.(newCollapsed);
2844
- };
2845
- const handleRightToggle = () => {
2846
- const newCollapsed = !rightCollapsed;
2847
- if (controlledRightCollapsed === void 0) {
2848
- setInternalRightCollapsed(newCollapsed);
2962
+ return false;
2963
+ });
2964
+ const [internalRightCollapsed, setInternalRightCollapsed] = useState(() => {
2965
+ if (typeof window !== "undefined") {
2966
+ return window.innerWidth < 1024;
2849
2967
  }
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
- ] });
2968
+ return false;
2969
+ });
2970
+ useEffect(() => {
2971
+ if (isSmallScreen) {
2972
+ setInternalLeftCollapsed(true);
2973
+ setInternalRightCollapsed(true);
2974
+ }
2975
+ }, [isSmallScreen]);
2976
+ const leftCollapsed = internalLeftCollapsed;
2977
+ const rightCollapsed = internalRightCollapsed;
2978
+ const handleLeftToggle = useCallback((collapsed) => {
2979
+ setInternalLeftCollapsed(collapsed);
2980
+ }, []);
2981
+ const handleRightToggle = useCallback((collapsed) => {
2982
+ setInternalRightCollapsed(collapsed);
2983
+ }, []);
2984
+ const contextValue = useMemo(
2985
+ () => ({
2986
+ leftCollapsed,
2987
+ rightCollapsed,
2988
+ setLeftCollapsed: handleLeftToggle,
2989
+ setRightCollapsed: handleRightToggle,
2990
+ leftCollapsible: true,
2991
+ rightCollapsible: true
2992
+ }),
2993
+ [leftCollapsed, rightCollapsed, handleLeftToggle, handleRightToggle]
2994
+ );
2995
+ return /* @__PURE__ */ jsx(ChatSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
2996
+ "div",
2997
+ {
2998
+ className: cn("flex flex-col h-full w-full bg-background", className),
2999
+ children: [
3000
+ title && /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
3001
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
3002
+ leftSidebar && /* @__PURE__ */ jsx(
3003
+ "div",
3004
+ {
3005
+ className: cn(
3006
+ "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3007
+ leftCollapsed ? "w-0 border-r-0 min-w-0" : "",
3008
+ !leftCollapsed && leftSidebarClassName
3009
+ ),
3010
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
3011
+ }
3012
+ ),
3013
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
3014
+ Thread,
3015
+ {
3016
+ placeholder,
3017
+ starterPrompts,
3018
+ options,
3019
+ autoFocus,
3020
+ defaultSelectedIds
3021
+ }
3022
+ ) }),
3023
+ rightSidebar && /* @__PURE__ */ jsx(
3024
+ "div",
3025
+ {
3026
+ className: cn(
3027
+ "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3028
+ rightCollapsed ? "w-0 border-l-0 min-w-0" : "",
3029
+ !rightCollapsed && rightSidebarClassName
3030
+ ),
3031
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
3032
+ }
3033
+ )
3034
+ ] })
3035
+ ]
3036
+ }
3037
+ ) });
3038
+ }
3039
+ function SidebarToggle({ side, className }) {
3040
+ const {
3041
+ leftCollapsed,
3042
+ rightCollapsed,
3043
+ setLeftCollapsed,
3044
+ setRightCollapsed,
3045
+ leftCollapsible,
3046
+ rightCollapsible
3047
+ } = useChatSidebar();
3048
+ if (side === "left") {
3049
+ if (!leftCollapsible) return null;
3050
+ return /* @__PURE__ */ jsx(
3051
+ Button,
3052
+ {
3053
+ variant: "ghost",
3054
+ onClick: () => setLeftCollapsed(!leftCollapsed),
3055
+ "aria-label": leftCollapsed ? "Expand left sidebar" : "Collapse left sidebar",
3056
+ className: cn("", className),
3057
+ children: leftCollapsed ? /* @__PURE__ */ jsx(IconLayoutSidebarLeftExpand, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(IconLayoutSidebarLeftCollapse, { className: "h-4 w-4" })
3058
+ }
3059
+ );
3060
+ }
3061
+ if (side === "right") {
3062
+ if (!rightCollapsible) return null;
3063
+ return /* @__PURE__ */ jsx(
3064
+ Button,
3065
+ {
3066
+ variant: "ghost",
3067
+ onClick: () => setRightCollapsed(!rightCollapsed),
3068
+ "aria-label": rightCollapsed ? "Expand right sidebar" : "Collapse right sidebar",
3069
+ className: cn("", className),
3070
+ children: rightCollapsed ? /* @__PURE__ */ jsx(IconLayoutSidebarRightExpand, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(IconLayoutSidebarRightCollapse, { className: "h-4 w-4" })
3071
+ }
3072
+ );
3073
+ }
3074
+ return null;
2941
3075
  }
2942
- var PopoverContext = React10.createContext(
3076
+ var PopoverContext = React11.createContext(
2943
3077
  void 0
2944
3078
  );
2945
3079
  function usePopoverContext() {
2946
- const context = React10.useContext(PopoverContext);
3080
+ const context = React11.useContext(PopoverContext);
2947
3081
  if (!context) {
2948
3082
  throw new Error("Popover components must be used within a Popover");
2949
3083
  }
@@ -2955,10 +3089,10 @@ function Popover({
2955
3089
  open: controlledOpen,
2956
3090
  onOpenChange
2957
3091
  }) {
2958
- const [internalOpen, setInternalOpen] = React10.useState(defaultOpen);
2959
- const triggerRef = React10.useRef(null);
3092
+ const [internalOpen, setInternalOpen] = React11.useState(defaultOpen);
3093
+ const triggerRef = React11.useRef(null);
2960
3094
  const open = controlledOpen ?? internalOpen;
2961
- const setOpen = React10.useCallback(
3095
+ const setOpen = React11.useCallback(
2962
3096
  (newOpen) => {
2963
3097
  if (controlledOpen === void 0) {
2964
3098
  setInternalOpen(newOpen);
@@ -2967,7 +3101,7 @@ function Popover({
2967
3101
  },
2968
3102
  [controlledOpen, onOpenChange]
2969
3103
  );
2970
- const value = React10.useMemo(
3104
+ const value = React11.useMemo(
2971
3105
  () => ({
2972
3106
  open,
2973
3107
  setOpen,
@@ -2977,15 +3111,15 @@ function Popover({
2977
3111
  );
2978
3112
  return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
2979
3113
  }
2980
- var PopoverTrigger = React10.forwardRef(
3114
+ var PopoverTrigger = React11.forwardRef(
2981
3115
  ({ asChild, className, children, ...props }, ref) => {
2982
3116
  const { setOpen, triggerRef } = usePopoverContext();
2983
3117
  const handleClick = (e) => {
2984
3118
  setOpen(true);
2985
3119
  props.onClick?.(e);
2986
3120
  };
2987
- if (asChild && React10.isValidElement(children)) {
2988
- return React10.cloneElement(children, {
3121
+ if (asChild && React11.isValidElement(children)) {
3122
+ return React11.cloneElement(children, {
2989
3123
  ref: (node) => {
2990
3124
  triggerRef.current = node;
2991
3125
  if (typeof children.ref === "function") {
@@ -3017,7 +3151,7 @@ var PopoverTrigger = React10.forwardRef(
3017
3151
  }
3018
3152
  );
3019
3153
  PopoverTrigger.displayName = "PopoverTrigger";
3020
- var PopoverContent = React10.forwardRef(
3154
+ var PopoverContent = React11.forwardRef(
3021
3155
  ({
3022
3156
  className,
3023
3157
  side = "bottom",
@@ -3028,9 +3162,9 @@ var PopoverContent = React10.forwardRef(
3028
3162
  ...props
3029
3163
  }, ref) => {
3030
3164
  const { open, setOpen, triggerRef } = usePopoverContext();
3031
- const [position, setPosition] = React10.useState({ top: 0, left: 0 });
3032
- const contentRef = React10.useRef(null);
3033
- React10.useEffect(() => {
3165
+ const [position, setPosition] = React11.useState({ top: 0, left: 0 });
3166
+ const contentRef = React11.useRef(null);
3167
+ React11.useEffect(() => {
3034
3168
  if (!open || !triggerRef.current) return;
3035
3169
  const updatePosition = () => {
3036
3170
  if (!triggerRef.current || !contentRef.current) return;
@@ -3091,7 +3225,7 @@ var PopoverContent = React10.forwardRef(
3091
3225
  window.removeEventListener("scroll", updatePosition, true);
3092
3226
  };
3093
3227
  }, [open, side, align, sideOffset, alignOffset, triggerRef]);
3094
- React10.useEffect(() => {
3228
+ React11.useEffect(() => {
3095
3229
  if (!open) return;
3096
3230
  const handleClickOutside = (event) => {
3097
3231
  if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
@@ -3147,7 +3281,7 @@ var ThreadPopover = ({
3147
3281
  emptyState,
3148
3282
  onThreadSelect
3149
3283
  }) => {
3150
- const [isOpen, setIsOpen] = React10.useState(false);
3284
+ const [isOpen, setIsOpen] = React11.useState(false);
3151
3285
  useHotkeys(
3152
3286
  "h",
3153
3287
  (e) => {
@@ -3202,7 +3336,7 @@ var CreateThreadButton = ({
3202
3336
  onThreadCreated
3203
3337
  }) => {
3204
3338
  const { createThread } = useThreads();
3205
- const [isCreating, setIsCreating] = React10.useState(false);
3339
+ const [isCreating, setIsCreating] = React11.useState(false);
3206
3340
  const handleCreateThread = async () => {
3207
3341
  if (isCreating) return;
3208
3342
  try {
@@ -3328,10 +3462,10 @@ var AccountDialog = ({
3328
3462
  size
3329
3463
  }) => {
3330
3464
  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(() => {
3465
+ const [open, setOpen] = React11.useState(false);
3466
+ const [accountInfoOpen, setAccountInfoOpen] = React11.useState(false);
3467
+ const [error, setError] = React11.useState(null);
3468
+ const initials = React11.useMemo(() => {
3335
3469
  const name = user?.displayName || user?.name;
3336
3470
  if (!name) return "";
3337
3471
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
@@ -3504,6 +3638,6 @@ function ThemeToggle() {
3504
3638
  );
3505
3639
  }
3506
3640
 
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 };
3641
+ 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, groupEventsToMessages, useAuth, useChatSidebar, useMelony, useScreenSize, useTheme, useThreads };
3508
3642
  //# sourceMappingURL=index.js.map
3509
3643
  //# sourceMappingURL=index.js.map