@melony/react 0.1.25 → 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.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var React11 = require('react');
3
+ var React12 = require('react');
4
4
  var react = require('nuqs/adapters/react');
5
5
  var reactQuery = require('@tanstack/react-query');
6
6
  var jsxRuntime = require('react/jsx-runtime');
@@ -40,7 +40,7 @@ function _interopNamespace(e) {
40
40
  return Object.freeze(n);
41
41
  }
42
42
 
43
- var React11__namespace = /*#__PURE__*/_interopNamespace(React11);
43
+ var React12__namespace = /*#__PURE__*/_interopNamespace(React12);
44
44
  var ICONS__namespace = /*#__PURE__*/_interopNamespace(ICONS);
45
45
 
46
46
  // src/providers/melony-provider.tsx
@@ -69,7 +69,7 @@ function groupEventsToMessages(events) {
69
69
  }
70
70
  return messages;
71
71
  }
72
- var MelonyContext = React11.createContext(
72
+ var MelonyContext = React12.createContext(
73
73
  void 0
74
74
  );
75
75
  var defaultQueryClient = new reactQuery.QueryClient({
@@ -86,29 +86,29 @@ var MelonyContextProviderInner = ({
86
86
  initialEvents,
87
87
  setContextValue
88
88
  }) => {
89
- const [state, setState] = React11.useState(client.getState());
89
+ const [state, setState] = React12.useState(client.getState());
90
90
  const { data: config } = reactQuery.useQuery({
91
91
  queryKey: ["melony-config", client.url],
92
92
  queryFn: () => client.getConfig(),
93
93
  staleTime: Infinity
94
94
  });
95
- React11.useEffect(() => {
95
+ React12.useEffect(() => {
96
96
  if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
97
97
  client.reset(initialEvents);
98
98
  }
99
99
  }, [client, initialEvents]);
100
- React11.useEffect(() => {
100
+ React12.useEffect(() => {
101
101
  setState(client.getState());
102
102
  const unsubscribe = client.subscribe(setState);
103
103
  return () => {
104
104
  unsubscribe();
105
105
  };
106
106
  }, [client]);
107
- const reset = React11.useCallback(
107
+ const reset = React12.useCallback(
108
108
  (events) => client.reset(events),
109
109
  [client]
110
110
  );
111
- const dispatchClientAction = React11.useCallback(
111
+ const dispatchClientAction = React12.useCallback(
112
112
  async (event) => {
113
113
  if (!event.type.startsWith("client:")) return false;
114
114
  switch (event.type) {
@@ -144,7 +144,7 @@ var MelonyContextProviderInner = ({
144
144
  },
145
145
  [client, reset]
146
146
  );
147
- const sendEvent = React11.useCallback(
147
+ const sendEvent = React12.useCallback(
148
148
  async (event, options) => {
149
149
  const handled = await dispatchClientAction(event);
150
150
  if (handled) return;
@@ -155,7 +155,7 @@ var MelonyContextProviderInner = ({
155
155
  },
156
156
  [client, dispatchClientAction]
157
157
  );
158
- const value = React11.useMemo(
158
+ const value = React12.useMemo(
159
159
  () => ({
160
160
  ...state,
161
161
  messages: groupEventsToMessages(state.events),
@@ -166,7 +166,7 @@ var MelonyContextProviderInner = ({
166
166
  }),
167
167
  [state, sendEvent, reset, client, config]
168
168
  );
169
- React11.useEffect(() => {
169
+ React12.useEffect(() => {
170
170
  setContextValue(value);
171
171
  }, [value, setContextValue]);
172
172
  return /* @__PURE__ */ jsxRuntime.jsx(react.NuqsAdapter, { children });
@@ -177,7 +177,7 @@ var MelonyClientProvider = ({
177
177
  initialEvents,
178
178
  queryClient = defaultQueryClient
179
179
  }) => {
180
- const [contextValue, setContextValue] = React11.useState(void 0);
180
+ const [contextValue, setContextValue] = React12.useState(void 0);
181
181
  return /* @__PURE__ */ jsxRuntime.jsx(MelonyContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(
182
182
  MelonyContextProviderInner,
183
183
  {
@@ -188,16 +188,16 @@ var MelonyClientProvider = ({
188
188
  }
189
189
  ) }) });
190
190
  };
191
- var AuthContext = React11.createContext(
191
+ var AuthContext = React12.createContext(
192
192
  void 0
193
193
  );
194
194
  var AuthProvider = ({
195
195
  children,
196
196
  service
197
197
  }) => {
198
- const [user, setUser] = React11.useState(null);
199
- const [isLoading, setIsLoading] = React11.useState(true);
200
- const fetchMe = React11.useCallback(async () => {
198
+ const [user, setUser] = React12.useState(null);
199
+ const [isLoading, setIsLoading] = React12.useState(true);
200
+ const fetchMe = React12.useCallback(async () => {
201
201
  setIsLoading(true);
202
202
  try {
203
203
  const userData = await service.getMe();
@@ -209,13 +209,13 @@ var AuthProvider = ({
209
209
  setIsLoading(false);
210
210
  }
211
211
  }, [service]);
212
- React11.useEffect(() => {
212
+ React12.useEffect(() => {
213
213
  fetchMe();
214
214
  }, [fetchMe]);
215
- const login = React11.useCallback(() => {
215
+ const login = React12.useCallback(() => {
216
216
  service.login();
217
217
  }, [service]);
218
- const logout = React11.useCallback(async () => {
218
+ const logout = React12.useCallback(async () => {
219
219
  try {
220
220
  await service.logout();
221
221
  setUser(null);
@@ -251,7 +251,7 @@ var AuthProvider = ({
251
251
  }
252
252
  return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
253
253
  };
254
- var ThreadContext = React11.createContext(
254
+ var ThreadContext = React12.createContext(
255
255
  void 0
256
256
  );
257
257
  var ThreadProvider = ({
@@ -260,7 +260,7 @@ var ThreadProvider = ({
260
260
  initialThreadId: providedInitialThreadId
261
261
  }) => {
262
262
  const queryClient = reactQuery.useQueryClient();
263
- const defaultInitialThreadId = React11.useMemo(() => client.generateId(), []);
263
+ const defaultInitialThreadId = React12.useMemo(() => client.generateId(), []);
264
264
  const initialThreadId = providedInitialThreadId || defaultInitialThreadId;
265
265
  const [activeThreadId, setActiveThreadId] = nuqs.useQueryState(
266
266
  "threadId",
@@ -301,22 +301,22 @@ var ThreadProvider = ({
301
301
  }
302
302
  }
303
303
  });
304
- const selectThread = React11.useCallback(
304
+ const selectThread = React12.useCallback(
305
305
  (threadId) => {
306
306
  setActiveThreadId(threadId);
307
307
  },
308
308
  [setActiveThreadId]
309
309
  );
310
- const createThread = React11.useCallback(async () => {
310
+ const createThread = React12.useCallback(async () => {
311
311
  return createMutation.mutateAsync();
312
312
  }, [createMutation]);
313
- const deleteThread = React11.useCallback(
313
+ const deleteThread = React12.useCallback(
314
314
  async (threadId) => {
315
315
  return deleteMutation.mutateAsync(threadId);
316
316
  },
317
317
  [deleteMutation]
318
318
  );
319
- const value = React11.useMemo(
319
+ const value = React12.useMemo(
320
320
  () => ({
321
321
  threads,
322
322
  activeThreadId,
@@ -346,11 +346,11 @@ var ThreadProvider = ({
346
346
  );
347
347
  return /* @__PURE__ */ jsxRuntime.jsx(ThreadContext.Provider, { value, children });
348
348
  };
349
- var ThemeContext = React11.createContext(void 0);
349
+ var ThemeContext = React12.createContext(void 0);
350
350
  function ThemeProvider({ children }) {
351
- const [theme, setThemeState] = React11.useState("system");
352
- const [resolvedTheme, setResolvedTheme] = React11.useState("light");
353
- React11.useEffect(() => {
351
+ const [theme, setThemeState] = React12.useState("system");
352
+ const [resolvedTheme, setResolvedTheme] = React12.useState("light");
353
+ React12.useEffect(() => {
354
354
  if (typeof window !== "undefined") {
355
355
  const stored = localStorage.getItem("theme");
356
356
  if (stored) {
@@ -358,7 +358,7 @@ function ThemeProvider({ children }) {
358
358
  }
359
359
  }
360
360
  }, []);
361
- React11.useEffect(() => {
361
+ React12.useEffect(() => {
362
362
  if (typeof window !== "undefined") {
363
363
  if (theme === "system") {
364
364
  const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
@@ -373,7 +373,7 @@ function ThemeProvider({ children }) {
373
373
  }
374
374
  }
375
375
  }, [theme]);
376
- React11.useEffect(() => {
376
+ React12.useEffect(() => {
377
377
  if (typeof window !== "undefined") {
378
378
  const root = document.documentElement;
379
379
  if (resolvedTheme === "dark") {
@@ -392,21 +392,21 @@ function ThemeProvider({ children }) {
392
392
  return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: { theme, setTheme, resolvedTheme }, children });
393
393
  }
394
394
  function useTheme() {
395
- const context = React11.useContext(ThemeContext);
395
+ const context = React12.useContext(ThemeContext);
396
396
  if (context === void 0) {
397
397
  throw new Error("useTheme must be used within a ThemeProvider");
398
398
  }
399
399
  return context;
400
400
  }
401
401
  var useMelony = (options) => {
402
- const context = React11.useContext(MelonyContext);
402
+ const context = React12.useContext(MelonyContext);
403
403
  if (context === void 0) {
404
404
  throw new Error("useMelony must be used within a MelonyClientProvider");
405
405
  }
406
406
  const { client, reset } = context;
407
407
  const { initialEvents } = options || {};
408
- const prevInitialEventsRef = React11.useRef(void 0);
409
- React11.useEffect(() => {
408
+ const prevInitialEventsRef = React12.useRef(void 0);
409
+ React12.useEffect(() => {
410
410
  const currentSerialized = initialEvents ? JSON.stringify(initialEvents) : void 0;
411
411
  if (currentSerialized !== prevInitialEventsRef.current) {
412
412
  if (initialEvents) {
@@ -420,21 +420,21 @@ var useMelony = (options) => {
420
420
  return context;
421
421
  };
422
422
  var useAuth = () => {
423
- const context = React11.useContext(AuthContext);
423
+ const context = React12.useContext(AuthContext);
424
424
  if (context === void 0) {
425
425
  throw new Error("useAuth must be used within an AuthProvider");
426
426
  }
427
427
  return context;
428
428
  };
429
429
  var useThreads = () => {
430
- const context = React11.useContext(ThreadContext);
430
+ const context = React12.useContext(ThreadContext);
431
431
  if (context === void 0) {
432
432
  throw new Error("useThreads must be used within a ThreadProvider");
433
433
  }
434
434
  return context;
435
435
  };
436
436
  function useScreenSize(mobileBreakpoint = 768, tabletBreakpoint = 1024) {
437
- const [screenSize, setScreenSize] = React11.useState(() => {
437
+ const [screenSize, setScreenSize] = React12.useState(() => {
438
438
  if (typeof window === "undefined") {
439
439
  return {
440
440
  width: 1024,
@@ -453,7 +453,7 @@ function useScreenSize(mobileBreakpoint = 768, tabletBreakpoint = 1024) {
453
453
  isDesktop: width >= tabletBreakpoint
454
454
  };
455
455
  });
456
- React11.useEffect(() => {
456
+ React12.useEffect(() => {
457
457
  if (typeof window === "undefined") return;
458
458
  const updateScreenSize = () => {
459
459
  const width = window.innerWidth;
@@ -706,11 +706,11 @@ function Composer({
706
706
  const accept = fileAttachments?.accept;
707
707
  const maxFiles = fileAttachments?.maxFiles ?? 10;
708
708
  const maxFileSize = fileAttachments?.maxFileSize ?? 10 * 1024 * 1024;
709
- const [selectedOptions, setSelectedOptions] = React11__namespace.default.useState(
709
+ const [selectedOptions, setSelectedOptions] = React12__namespace.default.useState(
710
710
  () => new Set(defaultSelectedIds)
711
711
  );
712
- const [attachedFiles, setAttachedFiles] = React11__namespace.default.useState([]);
713
- const fileInputRef = React11__namespace.default.useRef(null);
712
+ const [attachedFiles, setAttachedFiles] = React12__namespace.default.useState([]);
713
+ const fileInputRef = React12__namespace.default.useRef(null);
714
714
  const toggleOption = (id, groupOptions, type = "multiple") => {
715
715
  const next = new Set(selectedOptions);
716
716
  if (type === "single") {
@@ -1501,9 +1501,9 @@ var Image = ({
1501
1501
  className,
1502
1502
  style
1503
1503
  }) => {
1504
- const [hasError, setHasError] = React11.useState(false);
1505
- const [isLoading, setIsLoading] = React11.useState(true);
1506
- const [open, setOpen] = React11.useState(false);
1504
+ const [hasError, setHasError] = React12.useState(false);
1505
+ const [isLoading, setIsLoading] = React12.useState(true);
1506
+ const [open, setOpen] = React12.useState(false);
1507
1507
  const sizes = {
1508
1508
  sm: "h-11",
1509
1509
  md: "h-22",
@@ -1662,7 +1662,7 @@ var Chart = ({
1662
1662
  className,
1663
1663
  style
1664
1664
  }) => {
1665
- const [tooltip, setTooltip] = React11.useState(null);
1665
+ const [tooltip, setTooltip] = React12.useState(null);
1666
1666
  if (!Array.isArray(data)) {
1667
1667
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-destructive border border-destructive/20 rounded-md bg-destructive/5", children: "Error: Chart data must be an array" });
1668
1668
  }
@@ -2408,7 +2408,7 @@ var Button2 = ({
2408
2408
  };
2409
2409
  var Form = ({ children, onSubmitAction, className, style }) => {
2410
2410
  const { sendEvent } = useMelony();
2411
- const [isSubmitted, setIsSubmitted] = React11.useState(false);
2411
+ const [isSubmitted, setIsSubmitted] = React12.useState(false);
2412
2412
  const handleSubmit = (e) => {
2413
2413
  e.preventDefault();
2414
2414
  if (isSubmitted) return;
@@ -2555,7 +2555,7 @@ function MessageBubble({ message }) {
2555
2555
  );
2556
2556
  }
2557
2557
  function LoadingIndicator({ status }) {
2558
- const [isExpanded, setIsExpanded] = React11.useState(false);
2558
+ const [isExpanded, setIsExpanded] = React12.useState(false);
2559
2559
  const message = status?.message || "Processing...";
2560
2560
  const details = status?.details;
2561
2561
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
@@ -2587,7 +2587,7 @@ function MessageList({
2587
2587
  if (messages.length === 0) {
2588
2588
  return null;
2589
2589
  }
2590
- const isTextStreaming = React11.useMemo(() => {
2590
+ const isTextStreaming = React12.useMemo(() => {
2591
2591
  if (messages.length === 0 || !isLoading) return false;
2592
2592
  const lastMessage = messages[messages.length - 1];
2593
2593
  return lastMessage.content.some((event) => event.type === "text-delta");
@@ -2615,7 +2615,7 @@ function Thread({
2615
2615
  const starterPrompts = localStarterPrompts ?? config?.starterPrompts;
2616
2616
  const options = localOptions ?? config?.options;
2617
2617
  const fileAttachments = config?.fileAttachments;
2618
- const allDefaultSelectedIds = React11.useMemo(() => {
2618
+ const allDefaultSelectedIds = React12.useMemo(() => {
2619
2619
  const defaultSelectedIdsFromOptions = options?.flatMap((group) => group.defaultSelectedIds ?? []) ?? [];
2620
2620
  return [
2621
2621
  .../* @__PURE__ */ new Set([
@@ -2624,9 +2624,9 @@ function Thread({
2624
2624
  ])
2625
2625
  ];
2626
2626
  }, [options, defaultSelectedIds]);
2627
- const [input, setInput] = React11.useState("");
2628
- const messagesEndRef = React11.useRef(null);
2629
- React11.useEffect(() => {
2627
+ const [input, setInput] = React12.useState("");
2628
+ const messagesEndRef = React12.useRef(null);
2629
+ React12.useEffect(() => {
2630
2630
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
2631
2631
  }, [messages]);
2632
2632
  const handleSubmit = async (state, overrideInput) => {
@@ -2749,14 +2749,20 @@ var ThreadList = ({
2749
2749
  deleteThread,
2750
2750
  isLoading
2751
2751
  } = useThreads();
2752
+ const sortedThreads = React12__namespace.useMemo(() => {
2753
+ return [...threads].sort((a, b) => {
2754
+ const dateA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
2755
+ const dateB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
2756
+ return dateB - dateA;
2757
+ });
2758
+ }, [threads]);
2752
2759
  const handleThreadClick = (threadId) => {
2753
2760
  if (threadId !== activeThreadId) {
2754
2761
  selectThread(threadId);
2755
2762
  }
2756
2763
  onThreadSelect?.(threadId);
2757
2764
  };
2758
- const handleDelete = async (e, threadId) => {
2759
- e.stopPropagation();
2765
+ const handleDelete = async (threadId) => {
2760
2766
  try {
2761
2767
  await deleteThread(threadId);
2762
2768
  } catch (error) {
@@ -2770,58 +2776,75 @@ var ThreadList = ({
2770
2776
  console.error("Failed to create thread:", error);
2771
2777
  }
2772
2778
  };
2773
- const formatDate = (date) => {
2774
- if (!date) return "";
2775
- const d = typeof date === "string" ? new Date(date) : date;
2776
- if (isNaN(d.getTime())) return "";
2777
- const now = /* @__PURE__ */ new Date();
2778
- const diffMs = now.getTime() - d.getTime();
2779
- const diffMins = Math.floor(diffMs / 6e4);
2780
- const diffHours = Math.floor(diffMs / 36e5);
2781
- const diffDays = Math.floor(diffMs / 864e5);
2782
- if (diffMins < 1) return "Just now";
2783
- if (diffMins < 60) return `${diffMins}m ago`;
2784
- if (diffHours < 24) return `${diffHours}h ago`;
2785
- if (diffDays < 7) return `${diffDays}d ago`;
2786
- return d.toLocaleDateString();
2787
- };
2788
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading && threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) }) : threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2789
- /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconMessage, { className: "size-8 mx-auto opacity-50" }),
2790
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "No threads yet" }),
2791
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
2792
- ] }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 space-y-1", children: threads.map((thread) => {
2793
- const isActive = thread.id === activeThreadId;
2794
- return /* @__PURE__ */ jsxRuntime.jsxs(
2795
- "div",
2779
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full", className), children: [
2780
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
2781
+ Button,
2796
2782
  {
2797
- onClick: () => handleThreadClick(thread.id),
2798
- className: cn(
2799
- "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2800
- isActive ? "bg-muted" : "hover:bg-muted"
2801
- ),
2783
+ variant: "outline",
2784
+ className: "w-full justify-start gap-2 h-9 px-3 border-dashed hover:border-solid transition-all",
2785
+ onClick: handleNewThread,
2802
2786
  children: [
2803
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
2804
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm font-medium truncate"), children: thread.title || `Thread ${thread.id.slice(0, 8)}` }),
2805
- thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs shrink-0"), children: formatDate(thread.updatedAt) })
2806
- ] }) }),
2807
- /* @__PURE__ */ jsxRuntime.jsx(
2808
- Button,
2809
- {
2810
- variant: "ghost",
2811
- size: "icon-xs",
2812
- onClick: (e) => handleDelete(e, thread.id),
2813
- className: cn(
2814
- "opacity-0 group-hover:opacity-100 transition-opacity shrink-0",
2815
- isActive && "hover:bg-primary-foreground/20"
2816
- ),
2817
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconTrash, { className: "size-3" })
2818
- }
2819
- )
2787
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" }),
2788
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "New chat" })
2820
2789
  ]
2821
- },
2822
- thread.id
2823
- );
2824
- }) }) }) });
2790
+ }
2791
+ ) }),
2792
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading && threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) }) : threads.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2793
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconMessage, { className: "size-8 mx-auto opacity-50" }),
2794
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm", children: "No threads yet" }),
2795
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
2796
+ ] }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 space-y-1", children: sortedThreads.map((thread) => {
2797
+ const isActive = thread.id === activeThreadId;
2798
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2799
+ "div",
2800
+ {
2801
+ onClick: () => handleThreadClick(thread.id),
2802
+ className: cn(
2803
+ "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2804
+ isActive ? "bg-muted text-foreground" : "hover:bg-muted/50 text-muted-foreground hover:text-foreground"
2805
+ ),
2806
+ children: [
2807
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: thread.title || `Thread ${thread.id.slice(0, 8)}` }) }),
2808
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
2809
+ /* @__PURE__ */ jsxRuntime.jsx(
2810
+ DropdownMenuTrigger,
2811
+ {
2812
+ render: (props) => /* @__PURE__ */ jsxRuntime.jsx(
2813
+ Button,
2814
+ {
2815
+ variant: "ghost",
2816
+ size: "icon-xs",
2817
+ ...props,
2818
+ onClick: (e) => {
2819
+ e.stopPropagation();
2820
+ props.onClick?.(e);
2821
+ },
2822
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconDotsVertical, { className: "size-3.5" })
2823
+ }
2824
+ )
2825
+ }
2826
+ ),
2827
+ /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "start", className: "w-32", children: /* @__PURE__ */ jsxRuntime.jsxs(
2828
+ DropdownMenuItem,
2829
+ {
2830
+ variant: "destructive",
2831
+ onClick: (e) => {
2832
+ e.stopPropagation();
2833
+ handleDelete(thread.id);
2834
+ },
2835
+ children: [
2836
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconTrash, { className: "size-4 mr-2" }),
2837
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delete" })
2838
+ ]
2839
+ }
2840
+ ) })
2841
+ ] }) })
2842
+ ]
2843
+ },
2844
+ thread.id
2845
+ );
2846
+ }) }) })
2847
+ ] });
2825
2848
  };
2826
2849
  function ChatPopup({
2827
2850
  title = "Chat",
@@ -2832,8 +2855,8 @@ function ChatPopup({
2832
2855
  headerProps,
2833
2856
  defaultSelectedIds
2834
2857
  }) {
2835
- const [isOpen, setIsOpen] = React11.useState(defaultOpen);
2836
- const [view, setView] = React11.useState("chat");
2858
+ const [isOpen, setIsOpen] = React12.useState(defaultOpen);
2859
+ const [view, setView] = React12.useState("chat");
2837
2860
  const { createThread } = useThreads();
2838
2861
  const handleNewChat = async () => {
2839
2862
  try {
@@ -2950,19 +2973,144 @@ function ChatSidebar({
2950
2973
  ) })
2951
2974
  ] });
2952
2975
  }
2953
- var ChatSidebarContext = React11.createContext(
2976
+ var ChatSidebarContext = React12.createContext(
2954
2977
  void 0
2955
2978
  );
2956
2979
  function useChatSidebar() {
2957
- const context = React11.useContext(ChatSidebarContext);
2980
+ const context = React12.useContext(ChatSidebarContext);
2958
2981
  if (context === void 0) {
2959
2982
  throw new Error("useChatSidebar must be used within a ChatSidebarProvider");
2960
2983
  }
2961
2984
  return context;
2962
2985
  }
2986
+ function WelcomeScreen({
2987
+ title = "Welcome to Melony",
2988
+ description = "The most powerful AI agent framework for building modern applications. Connect your tools, build your brain, and ship faster.",
2989
+ features = [
2990
+ {
2991
+ title: "Context Aware",
2992
+ description: "Built-in state management for complex LLM flows."
2993
+ },
2994
+ {
2995
+ title: "Extensible",
2996
+ description: "Plugin architecture for easy integrations."
2997
+ },
2998
+ {
2999
+ title: "Real-time",
3000
+ description: "Streaming responses and live state updates."
3001
+ },
3002
+ {
3003
+ title: "Tool-ready",
3004
+ description: "Ready-to-use actions for common tasks."
3005
+ }
3006
+ ],
3007
+ className,
3008
+ onLoginClick,
3009
+ termsUrl = "#",
3010
+ privacyUrl = "#",
3011
+ imageUrl,
3012
+ imageAlt = "Product screenshot"
3013
+ }) {
3014
+ const { login, isLoading } = useAuth();
3015
+ const handleLogin = () => {
3016
+ if (onLoginClick) {
3017
+ onLoginClick();
3018
+ } else {
3019
+ login();
3020
+ }
3021
+ };
3022
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3023
+ "div",
3024
+ {
3025
+ className: cn(
3026
+ "flex min-h-[600px] h-full w-full flex-col md:flex-row bg-background overflow-hidden",
3027
+ className
3028
+ ),
3029
+ children: [
3030
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col bg-sidebar text-foreground relative overflow-hidden", children: [
3031
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-24 -left-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3032
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -bottom-24 -right-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3033
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "max-w-xl mx-auto w-full", children: [
3034
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mb-6 text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl text-foreground", children: title }),
3035
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-12 text-lg text-muted-foreground md:text-xl leading-relaxed", children: description }),
3036
+ imageUrl && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-12 relative group", children: [
3037
+ /* @__PURE__ */ jsxRuntime.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" }),
3038
+ /* @__PURE__ */ jsxRuntime.jsx(
3039
+ "img",
3040
+ {
3041
+ src: imageUrl,
3042
+ alt: imageAlt,
3043
+ className: "relative rounded-xl border border-border/50 shadow-2xl transition-transform duration-500 hover:scale-[1.02] w-full"
3044
+ }
3045
+ )
3046
+ ] }),
3047
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-x-8 gap-y-10 sm:grid-cols-2", children: features.map((feature, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3048
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-bold text-lg text-foreground", children: feature.title }),
3049
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: feature.description })
3050
+ ] }, i)) })
3051
+ ] }) })
3052
+ ] }),
3053
+ /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-sm space-y-8", children: [
3054
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 text-center md:text-left", children: [
3055
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: "Get Started" }),
3056
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-lg", children: "Sign in to your account to continue" })
3057
+ ] }),
3058
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
3059
+ /* @__PURE__ */ jsxRuntime.jsxs(
3060
+ Button,
3061
+ {
3062
+ size: "lg",
3063
+ variant: "outline",
3064
+ 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",
3065
+ onClick: handleLogin,
3066
+ disabled: isLoading,
3067
+ children: [
3068
+ /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconBrandGoogle, { className: "size-6" }),
3069
+ isLoading ? "Signing in..." : "Continue with Google"
3070
+ ]
3071
+ }
3072
+ ),
3073
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative py-4", children: [
3074
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-full border-t border-border" }) }),
3075
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-background px-3 text-muted-foreground tracking-widest font-medium", children: "Secure access" }) })
3076
+ ] })
3077
+ ] }),
3078
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed text-center md:text-left", children: [
3079
+ "By continuing, you agree to our ",
3080
+ /* @__PURE__ */ jsxRuntime.jsx("br", { className: "hidden md:block" }),
3081
+ /* @__PURE__ */ jsxRuntime.jsx(
3082
+ "a",
3083
+ {
3084
+ href: termsUrl,
3085
+ target: "_blank",
3086
+ rel: "noopener noreferrer",
3087
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3088
+ children: "Terms of Service"
3089
+ }
3090
+ ),
3091
+ " ",
3092
+ "and",
3093
+ " ",
3094
+ /* @__PURE__ */ jsxRuntime.jsx(
3095
+ "a",
3096
+ {
3097
+ href: privacyUrl,
3098
+ target: "_blank",
3099
+ rel: "noopener noreferrer",
3100
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3101
+ children: "Privacy Policy"
3102
+ }
3103
+ ),
3104
+ "."
3105
+ ] })
3106
+ ] }) })
3107
+ ]
3108
+ }
3109
+ );
3110
+ }
2963
3111
  function ChatFull({
2964
3112
  title = "Chat",
2965
- placeholder = "Message the AI",
3113
+ placeholder,
2966
3114
  starterPrompts,
2967
3115
  options,
2968
3116
  className,
@@ -2972,23 +3120,26 @@ function ChatFull({
2972
3120
  leftSidebarClassName,
2973
3121
  rightSidebarClassName,
2974
3122
  autoFocus = false,
2975
- defaultSelectedIds
3123
+ defaultSelectedIds,
3124
+ showWelcomeScreen = false,
3125
+ welcomeScreenProps
2976
3126
  }) {
2977
3127
  const { isMobile, isTablet } = useScreenSize();
3128
+ const { isAuthenticated, isLoading } = useAuth();
2978
3129
  const isSmallScreen = isMobile || isTablet;
2979
- const [internalLeftCollapsed, setInternalLeftCollapsed] = React11.useState(() => {
3130
+ const [internalLeftCollapsed, setInternalLeftCollapsed] = React12.useState(() => {
2980
3131
  if (typeof window !== "undefined") {
2981
3132
  return window.innerWidth < 1024;
2982
3133
  }
2983
3134
  return false;
2984
3135
  });
2985
- const [internalRightCollapsed, setInternalRightCollapsed] = React11.useState(() => {
3136
+ const [internalRightCollapsed, setInternalRightCollapsed] = React12.useState(() => {
2986
3137
  if (typeof window !== "undefined") {
2987
3138
  return window.innerWidth < 1024;
2988
3139
  }
2989
3140
  return false;
2990
3141
  });
2991
- React11.useEffect(() => {
3142
+ React12.useEffect(() => {
2992
3143
  if (isSmallScreen) {
2993
3144
  setInternalLeftCollapsed(true);
2994
3145
  setInternalRightCollapsed(true);
@@ -2996,13 +3147,13 @@ function ChatFull({
2996
3147
  }, [isSmallScreen]);
2997
3148
  const leftCollapsed = internalLeftCollapsed;
2998
3149
  const rightCollapsed = internalRightCollapsed;
2999
- const handleLeftToggle = React11.useCallback((collapsed) => {
3150
+ const handleLeftToggle = React12.useCallback((collapsed) => {
3000
3151
  setInternalLeftCollapsed(collapsed);
3001
3152
  }, []);
3002
- const handleRightToggle = React11.useCallback((collapsed) => {
3153
+ const handleRightToggle = React12.useCallback((collapsed) => {
3003
3154
  setInternalRightCollapsed(collapsed);
3004
3155
  }, []);
3005
- const contextValue = React11.useMemo(
3156
+ const contextValue = React12.useMemo(
3006
3157
  () => ({
3007
3158
  leftCollapsed,
3008
3159
  rightCollapsed,
@@ -3013,6 +3164,9 @@ function ChatFull({
3013
3164
  }),
3014
3165
  [leftCollapsed, rightCollapsed, handleLeftToggle, handleRightToggle]
3015
3166
  );
3167
+ if (showWelcomeScreen && !isAuthenticated && !isLoading) {
3168
+ return /* @__PURE__ */ jsxRuntime.jsx(WelcomeScreen, { ...welcomeScreenProps });
3169
+ }
3016
3170
  return /* @__PURE__ */ jsxRuntime.jsx(ChatSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
3017
3171
  "div",
3018
3172
  {
@@ -3094,11 +3248,11 @@ function SidebarToggle({ side, className }) {
3094
3248
  }
3095
3249
  return null;
3096
3250
  }
3097
- var PopoverContext = React11__namespace.createContext(
3251
+ var PopoverContext = React12__namespace.createContext(
3098
3252
  void 0
3099
3253
  );
3100
3254
  function usePopoverContext() {
3101
- const context = React11__namespace.useContext(PopoverContext);
3255
+ const context = React12__namespace.useContext(PopoverContext);
3102
3256
  if (!context) {
3103
3257
  throw new Error("Popover components must be used within a Popover");
3104
3258
  }
@@ -3110,10 +3264,10 @@ function Popover({
3110
3264
  open: controlledOpen,
3111
3265
  onOpenChange
3112
3266
  }) {
3113
- const [internalOpen, setInternalOpen] = React11__namespace.useState(defaultOpen);
3114
- const triggerRef = React11__namespace.useRef(null);
3267
+ const [internalOpen, setInternalOpen] = React12__namespace.useState(defaultOpen);
3268
+ const triggerRef = React12__namespace.useRef(null);
3115
3269
  const open = controlledOpen ?? internalOpen;
3116
- const setOpen = React11__namespace.useCallback(
3270
+ const setOpen = React12__namespace.useCallback(
3117
3271
  (newOpen) => {
3118
3272
  if (controlledOpen === void 0) {
3119
3273
  setInternalOpen(newOpen);
@@ -3122,7 +3276,7 @@ function Popover({
3122
3276
  },
3123
3277
  [controlledOpen, onOpenChange]
3124
3278
  );
3125
- const value = React11__namespace.useMemo(
3279
+ const value = React12__namespace.useMemo(
3126
3280
  () => ({
3127
3281
  open,
3128
3282
  setOpen,
@@ -3132,15 +3286,15 @@ function Popover({
3132
3286
  );
3133
3287
  return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value, children });
3134
3288
  }
3135
- var PopoverTrigger = React11__namespace.forwardRef(
3289
+ var PopoverTrigger = React12__namespace.forwardRef(
3136
3290
  ({ asChild, className, children, ...props }, ref) => {
3137
3291
  const { setOpen, triggerRef } = usePopoverContext();
3138
3292
  const handleClick = (e) => {
3139
3293
  setOpen(true);
3140
3294
  props.onClick?.(e);
3141
3295
  };
3142
- if (asChild && React11__namespace.isValidElement(children)) {
3143
- return React11__namespace.cloneElement(children, {
3296
+ if (asChild && React12__namespace.isValidElement(children)) {
3297
+ return React12__namespace.cloneElement(children, {
3144
3298
  ref: (node) => {
3145
3299
  triggerRef.current = node;
3146
3300
  if (typeof children.ref === "function") {
@@ -3172,7 +3326,7 @@ var PopoverTrigger = React11__namespace.forwardRef(
3172
3326
  }
3173
3327
  );
3174
3328
  PopoverTrigger.displayName = "PopoverTrigger";
3175
- var PopoverContent = React11__namespace.forwardRef(
3329
+ var PopoverContent = React12__namespace.forwardRef(
3176
3330
  ({
3177
3331
  className,
3178
3332
  side = "bottom",
@@ -3183,9 +3337,9 @@ var PopoverContent = React11__namespace.forwardRef(
3183
3337
  ...props
3184
3338
  }, ref) => {
3185
3339
  const { open, setOpen, triggerRef } = usePopoverContext();
3186
- const [position, setPosition] = React11__namespace.useState({ top: 0, left: 0 });
3187
- const contentRef = React11__namespace.useRef(null);
3188
- React11__namespace.useEffect(() => {
3340
+ const [position, setPosition] = React12__namespace.useState({ top: 0, left: 0 });
3341
+ const contentRef = React12__namespace.useRef(null);
3342
+ React12__namespace.useEffect(() => {
3189
3343
  if (!open || !triggerRef.current) return;
3190
3344
  const updatePosition = () => {
3191
3345
  if (!triggerRef.current || !contentRef.current) return;
@@ -3246,7 +3400,7 @@ var PopoverContent = React11__namespace.forwardRef(
3246
3400
  window.removeEventListener("scroll", updatePosition, true);
3247
3401
  };
3248
3402
  }, [open, side, align, sideOffset, alignOffset, triggerRef]);
3249
- React11__namespace.useEffect(() => {
3403
+ React12__namespace.useEffect(() => {
3250
3404
  if (!open) return;
3251
3405
  const handleClickOutside = (event) => {
3252
3406
  if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
@@ -3302,7 +3456,7 @@ var ThreadPopover = ({
3302
3456
  emptyState,
3303
3457
  onThreadSelect
3304
3458
  }) => {
3305
- const [isOpen, setIsOpen] = React11__namespace.useState(false);
3459
+ const [isOpen, setIsOpen] = React12__namespace.useState(false);
3306
3460
  reactHotkeysHook.useHotkeys(
3307
3461
  "h",
3308
3462
  (e) => {
@@ -3357,7 +3511,7 @@ var CreateThreadButton = ({
3357
3511
  onThreadCreated
3358
3512
  }) => {
3359
3513
  const { createThread } = useThreads();
3360
- const [isCreating, setIsCreating] = React11__namespace.useState(false);
3514
+ const [isCreating, setIsCreating] = React12__namespace.useState(false);
3361
3515
  const handleCreateThread = async () => {
3362
3516
  if (isCreating) return;
3363
3517
  try {
@@ -3483,10 +3637,10 @@ var AccountDialog = ({
3483
3637
  size
3484
3638
  }) => {
3485
3639
  const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3486
- const [open, setOpen] = React11__namespace.useState(false);
3487
- const [accountInfoOpen, setAccountInfoOpen] = React11__namespace.useState(false);
3488
- const [error, setError] = React11__namespace.useState(null);
3489
- const initials = React11__namespace.useMemo(() => {
3640
+ const [open, setOpen] = React12__namespace.useState(false);
3641
+ const [accountInfoOpen, setAccountInfoOpen] = React12__namespace.useState(false);
3642
+ const [error, setError] = React12__namespace.useState(null);
3643
+ const initials = React12__namespace.useMemo(() => {
3490
3644
  const name = user?.displayName || user?.name;
3491
3645
  if (!name) return "";
3492
3646
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
@@ -3701,6 +3855,7 @@ exports.ThreadList = ThreadList;
3701
3855
  exports.ThreadPopover = ThreadPopover;
3702
3856
  exports.ThreadProvider = ThreadProvider;
3703
3857
  exports.UIRenderer = UIRenderer;
3858
+ exports.WelcomeScreen = WelcomeScreen;
3704
3859
  exports.groupEventsToMessages = groupEventsToMessages;
3705
3860
  exports.useAuth = useAuth;
3706
3861
  exports.useChatSidebar = useChatSidebar;