@melony/react 0.1.11 → 0.1.14

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,18 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var React9 = require('react');
3
+ var React10 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var client = require('melony/client');
4
6
  var clsx = require('clsx');
5
7
  var tailwindMerge = require('tailwind-merge');
6
- var jsxRuntime = require('react/jsx-runtime');
7
- var client = require('@melony/core/client');
8
- var separator = require('@base-ui/react/separator');
8
+ var button = require('@base-ui/react/button');
9
+ var classVarianceAuthority = require('class-variance-authority');
9
10
  var ICONS = require('@tabler/icons-react');
11
+ var separator = require('@base-ui/react/separator');
10
12
  var mergeProps = require('@base-ui/react/merge-props');
11
13
  var useRender = require('@base-ui/react/use-render');
12
- var classVarianceAuthority = require('class-variance-authority');
13
14
  var input = require('@base-ui/react/input');
14
15
  var select = require('@base-ui/react/select');
15
- var button = require('@base-ui/react/button');
16
16
  var alertDialog = require('@base-ui/react/alert-dialog');
17
17
  var menu = require('@base-ui/react/menu');
18
18
 
@@ -34,13 +34,12 @@ function _interopNamespace(e) {
34
34
  return Object.freeze(n);
35
35
  }
36
36
 
37
- var React9__namespace = /*#__PURE__*/_interopNamespace(React9);
37
+ var React10__namespace = /*#__PURE__*/_interopNamespace(React10);
38
38
  var ICONS__namespace = /*#__PURE__*/_interopNamespace(ICONS);
39
39
 
40
40
  // src/providers/melony-provider.tsx
41
- function cn(...inputs) {
42
- return tailwindMerge.twMerge(clsx.clsx(inputs));
43
- }
41
+
42
+ // src/lib/group-events-to-messages.ts
44
43
  function groupEventsToMessages(events) {
45
44
  if (events.length === 0) return [];
46
45
  const messages = [];
@@ -64,21 +63,28 @@ function groupEventsToMessages(events) {
64
63
  }
65
64
  return messages;
66
65
  }
67
- var MelonyContext = React9.createContext(
66
+ var MelonyContext = React10.createContext(
68
67
  void 0
69
68
  );
70
- var MelonyProvider = ({
69
+ var MelonyClientProvider = ({
71
70
  children,
72
- client
71
+ client,
72
+ initialEvents
73
73
  }) => {
74
- const [state, setState] = React9.useState(client.getState());
75
- React9.useEffect(() => {
74
+ const [state, setState] = React10.useState(client.getState());
75
+ React10.useEffect(() => {
76
+ if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
77
+ client.reset(initialEvents);
78
+ }
79
+ }, [client, initialEvents]);
80
+ React10.useEffect(() => {
76
81
  setState(client.getState());
82
+ const unsubscribe = client.subscribe(setState);
77
83
  return () => {
78
- client.subscribe(setState);
84
+ unsubscribe();
79
85
  };
80
86
  }, [client]);
81
- const sendEvent = React9.useCallback(
87
+ const sendEvent = React10.useCallback(
82
88
  async (event, options) => {
83
89
  const generator = client.sendEvent(event, options);
84
90
  for await (const _ of generator) {
@@ -86,29 +92,32 @@ var MelonyProvider = ({
86
92
  },
87
93
  [client]
88
94
  );
89
- const clear = React9.useCallback(() => client.clear(), [client]);
90
- const value = React9.useMemo(
95
+ const reset = React10.useCallback(
96
+ (events) => client.reset(events),
97
+ [client]
98
+ );
99
+ const value = React10.useMemo(
91
100
  () => ({
92
101
  ...state,
93
102
  messages: groupEventsToMessages(state.events),
94
103
  sendEvent,
95
- clear,
104
+ reset,
96
105
  client
97
106
  }),
98
- [state, sendEvent, clear, client]
107
+ [state, sendEvent, reset, client]
99
108
  );
100
109
  return /* @__PURE__ */ jsxRuntime.jsx(MelonyContext.Provider, { value, children });
101
110
  };
102
- var AuthContext = React9.createContext(
111
+ var AuthContext = React10.createContext(
103
112
  void 0
104
113
  );
105
114
  var AuthProvider = ({
106
115
  children,
107
116
  service
108
117
  }) => {
109
- const [user, setUser] = React9.useState(null);
110
- const [isLoading, setIsLoading] = React9.useState(true);
111
- const fetchMe = React9.useCallback(async () => {
118
+ const [user, setUser] = React10.useState(null);
119
+ const [isLoading, setIsLoading] = React10.useState(true);
120
+ const fetchMe = React10.useCallback(async () => {
112
121
  setIsLoading(true);
113
122
  try {
114
123
  const userData = await service.getMe();
@@ -120,13 +129,13 @@ var AuthProvider = ({
120
129
  setIsLoading(false);
121
130
  }
122
131
  }, [service]);
123
- React9.useEffect(() => {
132
+ React10.useEffect(() => {
124
133
  fetchMe();
125
134
  }, [fetchMe]);
126
- const login = React9.useCallback(() => {
135
+ const login = React10.useCallback(() => {
127
136
  service.login();
128
137
  }, [service]);
129
- const logout = React9.useCallback(async () => {
138
+ const logout = React10.useCallback(async () => {
130
139
  try {
131
140
  await service.logout();
132
141
  setUser(null);
@@ -162,23 +171,25 @@ var AuthProvider = ({
162
171
  }
163
172
  return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
164
173
  };
165
- var ThreadContext = React9.createContext(void 0);
174
+ var ThreadContext = React10.createContext(
175
+ void 0
176
+ );
166
177
  var ThreadProvider = ({
167
178
  children,
168
179
  service,
169
180
  initialThreadId: providedInitialThreadId
170
181
  }) => {
171
- const defaultInitialThreadId = React9.useMemo(() => client.generateId(), []);
182
+ const defaultInitialThreadId = React10.useMemo(() => client.generateId(), []);
172
183
  const initialThreadId = providedInitialThreadId || defaultInitialThreadId;
173
- const [threads, setThreads] = React9.useState([]);
174
- const [activeThreadId, setActiveThreadId] = React9.useState(
184
+ const [threads, setThreads] = React10.useState([]);
185
+ const [activeThreadId, setActiveThreadId] = React10.useState(
175
186
  initialThreadId
176
187
  );
177
- const [isLoading, setIsLoading] = React9.useState(true);
178
- const [error, setError] = React9.useState(null);
179
- const [threadEvents, setThreadEvents] = React9.useState([]);
180
- const [isLoadingEvents, setIsLoadingEvents] = React9.useState(false);
181
- const fetchThreads = React9.useCallback(async () => {
188
+ const [isLoading, setIsLoading] = React10.useState(true);
189
+ const [error, setError] = React10.useState(null);
190
+ const [threadEvents, setThreadEvents] = React10.useState([]);
191
+ const [isLoadingEvents, setIsLoadingEvents] = React10.useState(false);
192
+ const fetchThreads = React10.useCallback(async () => {
182
193
  setIsLoading(true);
183
194
  setError(null);
184
195
  try {
@@ -192,13 +203,13 @@ var ThreadProvider = ({
192
203
  setIsLoading(false);
193
204
  }
194
205
  }, [service]);
195
- React9.useEffect(() => {
206
+ React10.useEffect(() => {
196
207
  fetchThreads();
197
208
  }, [fetchThreads]);
198
- const selectThread = React9.useCallback((threadId) => {
209
+ const selectThread = React10.useCallback((threadId) => {
199
210
  setActiveThreadId(threadId);
200
211
  }, []);
201
- const createThread = React9.useCallback(async () => {
212
+ const createThread = React10.useCallback(async () => {
202
213
  const newId = service.createThread ? await service.createThread() : client.generateId();
203
214
  const newThread = {
204
215
  id: newId,
@@ -208,7 +219,7 @@ var ThreadProvider = ({
208
219
  setActiveThreadId(newId);
209
220
  return newId;
210
221
  }, [service]);
211
- const deleteThread = React9.useCallback(
222
+ const deleteThread = React10.useCallback(
212
223
  async (threadId) => {
213
224
  try {
214
225
  await service.deleteThread(threadId);
@@ -230,13 +241,10 @@ var ThreadProvider = ({
230
241
  },
231
242
  [service]
232
243
  );
233
- const refreshThreads = React9.useCallback(async () => {
244
+ const refreshThreads = React10.useCallback(async () => {
234
245
  await fetchThreads();
235
246
  }, [fetchThreads]);
236
- const threadMessages = React9.useMemo(() => {
237
- return groupEventsToMessages(threadEvents);
238
- }, [threadEvents]);
239
- React9.useEffect(() => {
247
+ React10.useEffect(() => {
240
248
  if (!activeThreadId) {
241
249
  setThreadEvents([]);
242
250
  setIsLoadingEvents(false);
@@ -266,7 +274,7 @@ var ThreadProvider = ({
266
274
  cancelled = true;
267
275
  };
268
276
  }, [activeThreadId, service]);
269
- const value = React9.useMemo(
277
+ const value = React10.useMemo(
270
278
  () => ({
271
279
  threads,
272
280
  activeThreadId,
@@ -277,7 +285,6 @@ var ThreadProvider = ({
277
285
  deleteThread,
278
286
  refreshThreads,
279
287
  threadEvents,
280
- threadMessages,
281
288
  isLoadingEvents
282
289
  }),
283
290
  [
@@ -290,33 +297,188 @@ var ThreadProvider = ({
290
297
  deleteThread,
291
298
  refreshThreads,
292
299
  threadEvents,
293
- threadMessages,
294
300
  isLoadingEvents
295
301
  ]
296
302
  );
297
303
  return /* @__PURE__ */ jsxRuntime.jsx(ThreadContext.Provider, { value, children });
298
304
  };
299
- var useMelony = () => {
300
- const context = React9.useContext(MelonyContext);
305
+ var ThemeContext = React10.createContext(void 0);
306
+ function ThemeProvider({ children }) {
307
+ const [theme, setThemeState] = React10.useState("system");
308
+ const [resolvedTheme, setResolvedTheme] = React10.useState("light");
309
+ React10.useEffect(() => {
310
+ if (typeof window !== "undefined") {
311
+ const stored = localStorage.getItem("theme");
312
+ if (stored) {
313
+ setThemeState(stored);
314
+ }
315
+ }
316
+ }, []);
317
+ React10.useEffect(() => {
318
+ if (typeof window !== "undefined") {
319
+ if (theme === "system") {
320
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
321
+ const updateResolvedTheme = () => {
322
+ setResolvedTheme(mediaQuery.matches ? "dark" : "light");
323
+ };
324
+ updateResolvedTheme();
325
+ mediaQuery.addEventListener("change", updateResolvedTheme);
326
+ return () => mediaQuery.removeEventListener("change", updateResolvedTheme);
327
+ } else {
328
+ setResolvedTheme(theme);
329
+ }
330
+ }
331
+ }, [theme]);
332
+ React10.useEffect(() => {
333
+ if (typeof window !== "undefined") {
334
+ const root = document.documentElement;
335
+ if (resolvedTheme === "dark") {
336
+ root.classList.add("dark");
337
+ } else {
338
+ root.classList.remove("dark");
339
+ }
340
+ }
341
+ }, [resolvedTheme]);
342
+ const setTheme = (newTheme) => {
343
+ setThemeState(newTheme);
344
+ if (typeof window !== "undefined") {
345
+ localStorage.setItem("theme", newTheme);
346
+ }
347
+ };
348
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: { theme, setTheme, resolvedTheme }, children });
349
+ }
350
+ function useTheme() {
351
+ const context = React10.useContext(ThemeContext);
352
+ if (context === void 0) {
353
+ throw new Error("useTheme must be used within a ThemeProvider");
354
+ }
355
+ return context;
356
+ }
357
+ var useMelony = (options) => {
358
+ const context = React10.useContext(MelonyContext);
301
359
  if (context === void 0) {
302
- throw new Error("useMelony must be used within a MelonyProvider");
360
+ throw new Error("useMelony must be used within a MelonyClientProvider");
303
361
  }
362
+ const { client, reset } = context;
363
+ const { initialEvents } = options || {};
364
+ React10.useEffect(() => {
365
+ if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
366
+ reset(initialEvents);
367
+ }
368
+ }, [client, initialEvents, reset]);
304
369
  return context;
305
370
  };
306
371
  var useAuth = () => {
307
- const context = React9.useContext(AuthContext);
372
+ const context = React10.useContext(AuthContext);
308
373
  if (context === void 0) {
309
374
  throw new Error("useAuth must be used within an AuthProvider");
310
375
  }
311
376
  return context;
312
377
  };
313
378
  var useThreads = () => {
314
- const context = React9.useContext(ThreadContext);
379
+ const context = React10.useContext(ThreadContext);
315
380
  if (context === void 0) {
316
381
  throw new Error("useThreads must be used within a ThreadProvider");
317
382
  }
318
383
  return context;
319
384
  };
385
+ function cn(...inputs) {
386
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
387
+ }
388
+ var buttonVariants = classVarianceAuthority.cva(
389
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
390
+ {
391
+ variants: {
392
+ variant: {
393
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
394
+ outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
395
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
396
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
397
+ destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
398
+ link: "text-primary underline-offset-4 hover:underline"
399
+ },
400
+ size: {
401
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
402
+ xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
403
+ sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
404
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
405
+ icon: "size-9",
406
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
407
+ "icon-sm": "size-8",
408
+ "icon-lg": "size-10"
409
+ }
410
+ },
411
+ defaultVariants: {
412
+ variant: "default",
413
+ size: "default"
414
+ }
415
+ }
416
+ );
417
+ function Button({
418
+ className,
419
+ variant = "default",
420
+ size = "default",
421
+ ...props
422
+ }) {
423
+ return /* @__PURE__ */ jsxRuntime.jsx(
424
+ button.Button,
425
+ {
426
+ "data-slot": "button",
427
+ className: cn(buttonVariants({ variant, size, className })),
428
+ ...props
429
+ }
430
+ );
431
+ }
432
+ function Textarea({ className, ...props }) {
433
+ return /* @__PURE__ */ jsxRuntime.jsx(
434
+ "textarea",
435
+ {
436
+ "data-slot": "textarea",
437
+ className: cn(
438
+ "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
439
+ className
440
+ ),
441
+ ...props
442
+ }
443
+ );
444
+ }
445
+ function Composer({
446
+ value,
447
+ onChange,
448
+ onSubmit,
449
+ placeholder = "Type a message...",
450
+ isLoading,
451
+ className
452
+ }) {
453
+ const handleKeyDown = (e) => {
454
+ if (e.key === "Enter" && !e.shiftKey) {
455
+ e.preventDefault();
456
+ onSubmit();
457
+ }
458
+ };
459
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
460
+ /* @__PURE__ */ jsxRuntime.jsx(
461
+ Textarea,
462
+ {
463
+ value,
464
+ onChange: (e) => onChange(e.target.value),
465
+ onKeyDown: handleKeyDown,
466
+ placeholder,
467
+ 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"
468
+ }
469
+ ),
470
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
471
+ Button,
472
+ {
473
+ type: "submit",
474
+ disabled: !value.trim() && !isLoading || isLoading,
475
+ size: "icon-lg",
476
+ onClick: () => onSubmit(),
477
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowUp, { className: "h-5 w-5" })
478
+ }
479
+ ) })
480
+ ] }) });
481
+ }
320
482
  function Card({
321
483
  className,
322
484
  size = "default",
@@ -385,7 +547,7 @@ var Card2 = ({
385
547
  return /* @__PURE__ */ jsxRuntime.jsxs(
386
548
  Card,
387
549
  {
388
- className: cn("w-full max-w-2xl shadow-sm", className),
550
+ className: cn("min-w-96", className),
389
551
  style,
390
552
  children: [
391
553
  (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "pb-3", children: [
@@ -707,8 +869,8 @@ var Image = ({
707
869
  className,
708
870
  style
709
871
  }) => {
710
- const [hasError, setHasError] = React9.useState(false);
711
- const [isLoading, setIsLoading] = React9.useState(true);
872
+ const [hasError, setHasError] = React10.useState(false);
873
+ const [isLoading, setIsLoading] = React10.useState(true);
712
874
  const sizes = {
713
875
  sm: "h-11 w-11",
714
876
  md: "h-22 w-22",
@@ -861,7 +1023,7 @@ var Chart = ({
861
1023
  className,
862
1024
  style
863
1025
  }) => {
864
- const [tooltip, setTooltip] = React9.useState(null);
1026
+ const [tooltip, setTooltip] = React10.useState(null);
865
1027
  if (!Array.isArray(data)) {
866
1028
  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" });
867
1029
  }
@@ -1206,19 +1368,6 @@ var Input2 = ({
1206
1368
  )
1207
1369
  ] });
1208
1370
  };
1209
- function Textarea({ className, ...props }) {
1210
- return /* @__PURE__ */ jsxRuntime.jsx(
1211
- "textarea",
1212
- {
1213
- "data-slot": "textarea",
1214
- className: cn(
1215
- "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
1216
- className
1217
- ),
1218
- ...props
1219
- }
1220
- );
1221
- }
1222
1371
  var Textarea2 = ({
1223
1372
  placeholder,
1224
1373
  defaultValue,
@@ -1590,50 +1739,6 @@ var RadioGroup = ({
1590
1739
  )
1591
1740
  ] });
1592
1741
  };
1593
- var buttonVariants = classVarianceAuthority.cva(
1594
- "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
1595
- {
1596
- variants: {
1597
- variant: {
1598
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
1599
- outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
1600
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
1601
- ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
1602
- destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
1603
- link: "text-primary underline-offset-4 hover:underline"
1604
- },
1605
- size: {
1606
- default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
1607
- xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
1608
- sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
1609
- lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
1610
- icon: "size-9",
1611
- "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
1612
- "icon-sm": "size-8",
1613
- "icon-lg": "size-10"
1614
- }
1615
- },
1616
- defaultVariants: {
1617
- variant: "default",
1618
- size: "default"
1619
- }
1620
- }
1621
- );
1622
- function Button({
1623
- className,
1624
- variant = "default",
1625
- size = "default",
1626
- ...props
1627
- }) {
1628
- return /* @__PURE__ */ jsxRuntime.jsx(
1629
- button.Button,
1630
- {
1631
- "data-slot": "button",
1632
- className: cn(buttonVariants({ variant, size, className })),
1633
- ...props
1634
- }
1635
- );
1636
- }
1637
1742
  var Button2 = ({
1638
1743
  label,
1639
1744
  variant = "primary",
@@ -1650,6 +1755,8 @@ var Button2 = ({
1650
1755
  secondary: "secondary",
1651
1756
  danger: "destructive",
1652
1757
  outline: "outline",
1758
+ ghost: "ghost",
1759
+ link: "link",
1653
1760
  success: "default"
1654
1761
  // Success doesn't have a direct shadcn mapping in base variant, default is usually primary
1655
1762
  };
@@ -1672,7 +1779,7 @@ var Button2 = ({
1672
1779
  };
1673
1780
  var Form = ({ children, onSubmitAction, className, style }) => {
1674
1781
  const { sendEvent } = useMelony();
1675
- const [isSubmitted, setIsSubmitted] = React9.useState(false);
1782
+ const [isSubmitted, setIsSubmitted] = React10.useState(false);
1676
1783
  const handleSubmit = (e) => {
1677
1784
  e.preventDefault();
1678
1785
  if (isSubmitted) return;
@@ -1718,6 +1825,32 @@ var Form = ({ children, onSubmitAction, className, style }) => {
1718
1825
  }
1719
1826
  );
1720
1827
  };
1828
+ function StarterPrompts({
1829
+ prompts,
1830
+ onPromptClick
1831
+ }) {
1832
+ if (!prompts || prompts.length === 0) {
1833
+ return null;
1834
+ }
1835
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-4 animate-in fade-in slide-in-from-bottom-4 duration-500 mt-auto max-w-2xl", children: [
1836
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
1837
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2 w-full", children: prompts.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1838
+ Button2,
1839
+ {
1840
+ label: item.label,
1841
+ variant: "ghost",
1842
+ size: "lg",
1843
+ onClickAction: {
1844
+ type: "text",
1845
+ role: "user",
1846
+ data: { content: item.prompt }
1847
+ },
1848
+ className: "w-full justify-start"
1849
+ },
1850
+ index
1851
+ )) })
1852
+ ] });
1853
+ }
1721
1854
  function UIRenderer({ node }) {
1722
1855
  const { type, props, children } = node;
1723
1856
  const typeMap = {
@@ -1756,46 +1889,57 @@ function UIRenderer({ node }) {
1756
1889
  const componentProps = { ...props };
1757
1890
  return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...componentProps, children: renderedChildren });
1758
1891
  }
1759
- function Composer({
1760
- value,
1761
- onChange,
1762
- onSubmit,
1763
- placeholder = "Type a message...",
1764
- isLoading,
1765
- className
1766
- }) {
1767
- const handleKeyDown = (e) => {
1768
- if (e.key === "Enter" && !e.shiftKey) {
1769
- e.preventDefault();
1770
- onSubmit();
1892
+ function MessageContent({ events }) {
1893
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: events.map((event, index) => {
1894
+ if (event.type === "text-delta") {
1895
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.data?.delta }, index);
1771
1896
  }
1772
- };
1773
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
1774
- /* @__PURE__ */ jsxRuntime.jsx(
1775
- Textarea,
1776
- {
1777
- value,
1778
- onChange: (e) => onChange(e.target.value),
1779
- onKeyDown: handleKeyDown,
1780
- placeholder,
1781
- 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"
1782
- }
1783
- ),
1784
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end items-center px-2 pb-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
1785
- Button,
1786
- {
1787
- type: "submit",
1788
- disabled: !value.trim() && !isLoading || isLoading,
1789
- size: "icon",
1790
- onClick: () => onSubmit(),
1791
- className: cn(
1792
- "h-8 w-8 rounded-full transition-all shrink-0",
1793
- value.trim() ? "bg-foreground text-background hover:bg-foreground/90" : "bg-muted-foreground/20 text-muted-foreground/40"
1794
- ),
1795
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowUp, { className: "h-5 w-5" })
1796
- }
1797
- ) })
1798
- ] }) });
1897
+ if (event.type === "text") {
1898
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { children: event.data?.content || event.data?.text }, index);
1899
+ }
1900
+ if (event.ui) {
1901
+ return /* @__PURE__ */ jsxRuntime.jsx(UIRenderer, { node: event.ui }, index);
1902
+ }
1903
+ return null;
1904
+ }) });
1905
+ }
1906
+ function MessageBubble({ message }) {
1907
+ const isUser = message.role === "user";
1908
+ return /* @__PURE__ */ jsxRuntime.jsx(
1909
+ "div",
1910
+ {
1911
+ className: cn(
1912
+ "flex flex-col",
1913
+ isUser ? "items-end" : "items-start"
1914
+ ),
1915
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1916
+ "div",
1917
+ {
1918
+ className: cn(
1919
+ "flex flex-col items-start max-w-[85%] rounded-2xl px-4 py-2 space-y-4 whitespace-pre-wrap",
1920
+ isUser ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
1921
+ ),
1922
+ children: /* @__PURE__ */ jsxRuntime.jsx(MessageContent, { events: message.content })
1923
+ }
1924
+ )
1925
+ }
1926
+ );
1927
+ }
1928
+ function LoadingIndicator() {
1929
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." });
1930
+ }
1931
+ function ErrorDisplay({ error }) {
1932
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message });
1933
+ }
1934
+ function MessageList({ messages, isLoading, error }) {
1935
+ if (messages.length === 0) {
1936
+ return null;
1937
+ }
1938
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1939
+ messages.map((message, index) => /* @__PURE__ */ jsxRuntime.jsx(MessageBubble, { message }, index)),
1940
+ isLoading && /* @__PURE__ */ jsxRuntime.jsx(LoadingIndicator, {}),
1941
+ error && /* @__PURE__ */ jsxRuntime.jsx(ErrorDisplay, { error })
1942
+ ] });
1799
1943
  }
1800
1944
  function Thread({
1801
1945
  className,
@@ -1804,9 +1948,9 @@ function Thread({
1804
1948
  onStarterPromptClick
1805
1949
  }) {
1806
1950
  const { messages, isLoading, error, sendEvent } = useMelony();
1807
- const [input, setInput] = React9.useState("");
1808
- const messagesEndRef = React9.useRef(null);
1809
- React9.useEffect(() => {
1951
+ const [input, setInput] = React10.useState("");
1952
+ const messagesEndRef = React10.useRef(null);
1953
+ React10.useEffect(() => {
1810
1954
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1811
1955
  }, [messages]);
1812
1956
  const handleSubmit = async (e, overrideInput) => {
@@ -1827,57 +1971,38 @@ function Thread({
1827
1971
  handleSubmit(void 0, prompt);
1828
1972
  }
1829
1973
  };
1830
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full bg-background", className), children: [
1831
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
1832
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto w-full", children: [
1833
- messages.length === 0 && starterPrompts && starterPrompts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center min-h-[300px] space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-500", children: [
1834
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center space-y-2", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
1835
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3 w-full max-w-2xl px-4", children: starterPrompts.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(
1836
- "button",
1837
- {
1838
- onClick: () => handleStarterPromptClick(item.prompt),
1839
- className: "flex items-center gap-3 p-4 rounded-xl border bg-card hover:bg-muted/50 transition-all text-left group",
1840
- children: [
1841
- item.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 rounded-lg bg-muted group-hover:bg-background transition-colors", children: item.icon }),
1842
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: item.label })
1843
- ]
1844
- },
1845
- i
1846
- )) })
1847
- ] }),
1848
- messages.map((message, i) => /* @__PURE__ */ jsxRuntime.jsx(
1849
- "div",
1850
- {
1851
- className: cn(
1852
- "flex flex-col",
1853
- message.role === "user" ? "items-end" : "items-start"
1974
+ const showStarterPrompts = messages.length === 0 && starterPrompts && starterPrompts.length > 0;
1975
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative flex flex-col h-full bg-background", className), children: [
1976
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 pb-36", children: [
1977
+ /* @__PURE__ */ jsxRuntime.jsxs(
1978
+ "div",
1979
+ {
1980
+ className: cn(
1981
+ "max-w-4xl mx-auto w-full p-4",
1982
+ showStarterPrompts && "min-h-full flex flex-col"
1983
+ ),
1984
+ children: [
1985
+ showStarterPrompts && /* @__PURE__ */ jsxRuntime.jsx(
1986
+ StarterPrompts,
1987
+ {
1988
+ prompts: starterPrompts,
1989
+ onPromptClick: handleStarterPromptClick
1990
+ }
1854
1991
  ),
1855
- children: /* @__PURE__ */ jsxRuntime.jsx(
1856
- "div",
1992
+ /* @__PURE__ */ jsxRuntime.jsx(
1993
+ MessageList,
1857
1994
  {
1858
- className: cn(
1859
- "max-w-[85%] rounded-2xl px-4 py-2 space-y-2",
1860
- message.role === "user" ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
1861
- ),
1862
- children: message.content.map((event, j) => {
1863
- if (event.type === "text-delta")
1864
- return /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.data?.delta }, j);
1865
- if (event.type === "text")
1866
- return /* @__PURE__ */ jsxRuntime.jsx("p", { children: event.data?.content || event.data?.text }, j);
1867
- if (event.ui) return /* @__PURE__ */ jsxRuntime.jsx(UIRenderer, { node: event.ui }, j);
1868
- return null;
1869
- })
1995
+ messages,
1996
+ isLoading,
1997
+ error
1870
1998
  }
1871
1999
  )
1872
- },
1873
- i
1874
- )),
1875
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." }),
1876
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message })
1877
- ] }),
2000
+ ]
2001
+ }
2002
+ ),
1878
2003
  /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1879
2004
  ] }),
1880
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-t w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
2005
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 p-4 w-full", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
1881
2006
  Composer,
1882
2007
  {
1883
2008
  value: input,
@@ -1889,18 +2014,34 @@ function Thread({
1889
2014
  ) }) })
1890
2015
  ] });
1891
2016
  }
2017
+ function ChatHeader({
2018
+ title,
2019
+ leftContent,
2020
+ rightContent,
2021
+ className,
2022
+ titleClassName,
2023
+ children
2024
+ }) {
2025
+ if (children) {
2026
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("p-4 border-b border-border h-14 flex items-center shrink-0", className), children });
2027
+ }
2028
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("p-4 border-b border-border h-14 flex items-center justify-between shrink-0", className), children: [
2029
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [
2030
+ leftContent,
2031
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(
2032
+ "text-sm font-semibold truncate",
2033
+ typeof title === "string" ? titleClassName : ""
2034
+ ), children: title })
2035
+ ] }),
2036
+ rightContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 shrink-0 ml-2", children: rightContent })
2037
+ ] });
2038
+ }
1892
2039
  var ThreadList = ({
1893
2040
  className,
1894
2041
  emptyState,
1895
2042
  onThreadSelect
1896
2043
  }) => {
1897
- const {
1898
- threads,
1899
- activeThreadId,
1900
- selectThread,
1901
- createThread,
1902
- deleteThread
1903
- } = useThreads();
2044
+ const { threads, activeThreadId, selectThread, createThread, deleteThread } = useThreads();
1904
2045
  const handleThreadClick = (threadId) => {
1905
2046
  if (threadId !== activeThreadId) {
1906
2047
  selectThread(threadId);
@@ -1938,10 +2079,10 @@ var ThreadList = ({
1938
2079
  return d.toLocaleDateString();
1939
2080
  };
1940
2081
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full", className), children: [
1941
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 border-b", children: /* @__PURE__ */ jsxRuntime.jsxs(
2082
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
1942
2083
  Button,
1943
2084
  {
1944
- variant: "outline",
2085
+ variant: "ghost",
1945
2086
  size: "sm",
1946
2087
  onClick: handleNewThread,
1947
2088
  className: "w-full justify-start",
@@ -1962,31 +2103,13 @@ var ThreadList = ({
1962
2103
  {
1963
2104
  onClick: () => handleThreadClick(thread.id),
1964
2105
  className: cn(
1965
- "group relative flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors",
1966
- isActive ? "bg-primary text-primary-foreground" : "hover:bg-muted"
2106
+ "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2107
+ isActive ? "bg-muted" : "hover:bg-muted"
1967
2108
  ),
1968
2109
  children: [
1969
2110
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1970
- /* @__PURE__ */ jsxRuntime.jsx(
1971
- "p",
1972
- {
1973
- className: cn(
1974
- "text-sm font-medium truncate",
1975
- isActive && "text-primary-foreground"
1976
- ),
1977
- children: thread.title || `Thread ${thread.id.slice(0, 8)}`
1978
- }
1979
- ),
1980
- thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx(
1981
- "span",
1982
- {
1983
- className: cn(
1984
- "text-xs shrink-0",
1985
- isActive ? "text-primary-foreground/70" : "text-muted-foreground"
1986
- ),
1987
- children: formatDate(thread.updatedAt)
1988
- }
1989
- )
2111
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-sm font-medium truncate"), children: thread.title || `Thread ${thread.id.slice(0, 8)}` }),
2112
+ thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs shrink-0"), children: formatDate(thread.updatedAt) })
1990
2113
  ] }) }),
1991
2114
  /* @__PURE__ */ jsxRuntime.jsx(
1992
2115
  Button,
@@ -2012,10 +2135,11 @@ function ChatPopup({
2012
2135
  title = "Chat",
2013
2136
  placeholder = "Message the AI",
2014
2137
  starterPrompts,
2015
- defaultOpen = false
2138
+ defaultOpen = false,
2139
+ headerProps
2016
2140
  }) {
2017
- const [isOpen, setIsOpen] = React9.useState(defaultOpen);
2018
- const [view, setView] = React9.useState("chat");
2141
+ const [isOpen, setIsOpen] = React10.useState(defaultOpen);
2142
+ const [view, setView] = React10.useState("chat");
2019
2143
  const { createThread } = useThreads();
2020
2144
  const handleNewChat = async () => {
2021
2145
  try {
@@ -2027,9 +2151,11 @@ function ChatPopup({
2027
2151
  };
2028
2152
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 font-sans", children: [
2029
2153
  isOpen && /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "py-0 w-[440px] h-[640px] flex flex-col overflow-hidden border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60 shadow-2xl animate-in fade-in zoom-in-95 duration-200 origin-bottom-right", children: [
2030
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "p-4 border-b flex flex-row items-center justify-between space-y-0 h-14 shrink-0", children: [
2031
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2032
- view === "history" && /* @__PURE__ */ jsxRuntime.jsx(
2154
+ /* @__PURE__ */ jsxRuntime.jsx(
2155
+ ChatHeader,
2156
+ {
2157
+ title: view === "history" ? "History" : title,
2158
+ leftContent: view === "history" ? /* @__PURE__ */ jsxRuntime.jsx(
2033
2159
  Button,
2034
2160
  {
2035
2161
  variant: "ghost",
@@ -2038,44 +2164,44 @@ function ChatPopup({
2038
2164
  className: "text-muted-foreground hover:text-foreground",
2039
2165
  children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowLeft, { className: "size-4" })
2040
2166
  }
2041
- ),
2042
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-sm font-semibold", children: view === "history" ? "History" : title })
2043
- ] }),
2044
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2045
- view === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
2046
- Button,
2047
- {
2048
- variant: "ghost",
2049
- size: "icon-xs",
2050
- onClick: () => setView("history"),
2051
- className: "text-muted-foreground hover:text-foreground",
2052
- title: "History",
2053
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
2054
- }
2055
- ),
2056
- /* @__PURE__ */ jsxRuntime.jsx(
2057
- Button,
2058
- {
2059
- variant: "ghost",
2060
- size: "icon-xs",
2061
- onClick: handleNewChat,
2062
- className: "text-muted-foreground hover:text-foreground",
2063
- title: "New Chat",
2064
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
2065
- }
2066
- ),
2067
- /* @__PURE__ */ jsxRuntime.jsx(
2068
- Button,
2069
- {
2070
- variant: "ghost",
2071
- size: "icon-xs",
2072
- onClick: () => setIsOpen(false),
2073
- className: "text-muted-foreground hover:text-foreground",
2074
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" })
2075
- }
2076
- )
2077
- ] })
2078
- ] }),
2167
+ ) : void 0,
2168
+ rightContent: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2169
+ view === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
2170
+ Button,
2171
+ {
2172
+ variant: "ghost",
2173
+ size: "icon-xs",
2174
+ onClick: () => setView("history"),
2175
+ className: "text-muted-foreground hover:text-foreground",
2176
+ title: "History",
2177
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
2178
+ }
2179
+ ),
2180
+ /* @__PURE__ */ jsxRuntime.jsx(
2181
+ Button,
2182
+ {
2183
+ variant: "ghost",
2184
+ size: "icon-xs",
2185
+ onClick: handleNewChat,
2186
+ className: "text-muted-foreground hover:text-foreground",
2187
+ title: "New Chat",
2188
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
2189
+ }
2190
+ ),
2191
+ /* @__PURE__ */ jsxRuntime.jsx(
2192
+ Button,
2193
+ {
2194
+ variant: "ghost",
2195
+ size: "icon-xs",
2196
+ onClick: () => setIsOpen(false),
2197
+ className: "text-muted-foreground hover:text-foreground",
2198
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" })
2199
+ }
2200
+ )
2201
+ ] }),
2202
+ ...headerProps
2203
+ }
2204
+ ),
2079
2205
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: view === "chat" ? /* @__PURE__ */ jsxRuntime.jsx(
2080
2206
  Thread,
2081
2207
  {
@@ -2109,10 +2235,11 @@ function ChatSidebar({
2109
2235
  title = "Chat",
2110
2236
  placeholder = "Message the AI",
2111
2237
  starterPrompts,
2112
- className
2238
+ className,
2239
+ headerProps
2113
2240
  }) {
2114
2241
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2115
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2242
+ /* @__PURE__ */ jsxRuntime.jsx(ChatHeader, { title, ...headerProps }),
2116
2243
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
2117
2244
  Thread,
2118
2245
  {
@@ -2127,11 +2254,122 @@ function ChatFull({
2127
2254
  title = "Chat",
2128
2255
  placeholder = "Message the AI",
2129
2256
  starterPrompts,
2130
- className
2257
+ className,
2258
+ headerProps,
2259
+ leftSidebar,
2260
+ rightSidebar,
2261
+ leftSidebarClassName,
2262
+ rightSidebarClassName,
2263
+ leftSidebarCollapsible = false,
2264
+ rightSidebarCollapsible = false,
2265
+ defaultLeftSidebarCollapsed = false,
2266
+ defaultRightSidebarCollapsed = false,
2267
+ leftSidebarCollapsed: controlledLeftCollapsed,
2268
+ rightSidebarCollapsed: controlledRightCollapsed,
2269
+ onLeftSidebarCollapseChange,
2270
+ onRightSidebarCollapseChange
2131
2271
  }) {
2272
+ const [internalLeftCollapsed, setInternalLeftCollapsed] = React10.useState(
2273
+ defaultLeftSidebarCollapsed
2274
+ );
2275
+ const [internalRightCollapsed, setInternalRightCollapsed] = React10.useState(
2276
+ defaultRightSidebarCollapsed
2277
+ );
2278
+ const leftCollapsed = controlledLeftCollapsed !== void 0 ? controlledLeftCollapsed : internalLeftCollapsed;
2279
+ const rightCollapsed = controlledRightCollapsed !== void 0 ? controlledRightCollapsed : internalRightCollapsed;
2280
+ const handleLeftToggle = () => {
2281
+ const newCollapsed = !leftCollapsed;
2282
+ if (controlledLeftCollapsed === void 0) {
2283
+ setInternalLeftCollapsed(newCollapsed);
2284
+ }
2285
+ onLeftSidebarCollapseChange?.(newCollapsed);
2286
+ };
2287
+ const handleRightToggle = () => {
2288
+ const newCollapsed = !rightCollapsed;
2289
+ if (controlledRightCollapsed === void 0) {
2290
+ setInternalRightCollapsed(newCollapsed);
2291
+ }
2292
+ onRightSidebarCollapseChange?.(newCollapsed);
2293
+ };
2132
2294
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
2133
- title && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2134
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(Thread, { placeholder, starterPrompts }) })
2295
+ title && /* @__PURE__ */ jsxRuntime.jsx(ChatHeader, { title, ...headerProps }),
2296
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
2297
+ leftSidebar && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2298
+ /* @__PURE__ */ jsxRuntime.jsx(
2299
+ "div",
2300
+ {
2301
+ className: cn(
2302
+ "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2303
+ leftCollapsed && leftSidebarCollapsible ? "w-0 border-r-0 min-w-0" : "",
2304
+ !leftCollapsed && leftSidebarClassName
2305
+ ),
2306
+ children: !leftCollapsed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2307
+ leftSidebarCollapsible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2308
+ Button,
2309
+ {
2310
+ variant: "ghost",
2311
+ size: "icon-sm",
2312
+ onClick: handleLeftToggle,
2313
+ "aria-label": "Collapse left sidebar",
2314
+ className: "h-8 w-8",
2315
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronLeft, { className: "h-4 w-4" })
2316
+ }
2317
+ ) }),
2318
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
2319
+ ] })
2320
+ }
2321
+ ),
2322
+ leftSidebarCollapsible && leftCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 border-r border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
2323
+ Button,
2324
+ {
2325
+ variant: "ghost",
2326
+ size: "icon-sm",
2327
+ onClick: handleLeftToggle,
2328
+ "aria-label": "Expand left sidebar",
2329
+ className: "h-8 w-8",
2330
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronRight, { className: "h-4 w-4" })
2331
+ }
2332
+ ) })
2333
+ ] }),
2334
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(Thread, { placeholder, starterPrompts }) }),
2335
+ rightSidebar && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2336
+ rightSidebarCollapsible && rightCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 border-l border-border bg-background flex items-center justify-center w-10", children: /* @__PURE__ */ jsxRuntime.jsx(
2337
+ Button,
2338
+ {
2339
+ variant: "ghost",
2340
+ size: "icon-sm",
2341
+ onClick: handleRightToggle,
2342
+ "aria-label": "Expand right sidebar",
2343
+ className: "h-8 w-8",
2344
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronLeft, { className: "h-4 w-4" })
2345
+ }
2346
+ ) }),
2347
+ /* @__PURE__ */ jsxRuntime.jsx(
2348
+ "div",
2349
+ {
2350
+ className: cn(
2351
+ "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
2352
+ rightCollapsed && rightSidebarCollapsible ? "w-0 border-l-0 min-w-0" : "",
2353
+ !rightCollapsed && rightSidebarClassName
2354
+ ),
2355
+ children: !rightCollapsed && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2356
+ rightSidebarCollapsible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-start p-2 border-b border-border shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
2357
+ Button,
2358
+ {
2359
+ variant: "ghost",
2360
+ size: "icon-sm",
2361
+ onClick: handleRightToggle,
2362
+ "aria-label": "Collapse right sidebar",
2363
+ className: "h-8 w-8",
2364
+ children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconChevronRight, { className: "h-4 w-4" })
2365
+ }
2366
+ ) }),
2367
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
2368
+ ] })
2369
+ }
2370
+ )
2371
+ ] })
2372
+ ] })
2135
2373
  ] });
2136
2374
  }
2137
2375
  function AlertDialog({ ...props }) {
@@ -2275,8 +2513,8 @@ var AccountDialog = ({
2275
2513
  size
2276
2514
  }) => {
2277
2515
  const { isLoading, isAuthenticated, login, logout } = useAuth();
2278
- const [open, setOpen] = React9__namespace.useState(false);
2279
- const [error, setError] = React9__namespace.useState(null);
2516
+ const [open, setOpen] = React10__namespace.useState(false);
2517
+ const [error, setError] = React10__namespace.useState(null);
2280
2518
  const handleGoogleSignIn = async () => {
2281
2519
  login();
2282
2520
  };
@@ -2351,23 +2589,63 @@ var AccountDialog = ({
2351
2589
  ] }) })
2352
2590
  ] });
2353
2591
  };
2592
+ function ThemeToggle() {
2593
+ const { theme, setTheme, resolvedTheme } = useTheme();
2594
+ const cycleTheme = () => {
2595
+ if (theme === "light") {
2596
+ setTheme("dark");
2597
+ } else if (theme === "dark") {
2598
+ setTheme("system");
2599
+ } else {
2600
+ setTheme("light");
2601
+ }
2602
+ };
2603
+ const getIcon = () => {
2604
+ if (theme === "system") {
2605
+ return /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconDeviceDesktop, { className: "h-4 w-4" });
2606
+ }
2607
+ return resolvedTheme === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconMoon, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconSun, { className: "h-4 w-4" });
2608
+ };
2609
+ const getLabel = () => {
2610
+ if (theme === "system") {
2611
+ return "System";
2612
+ }
2613
+ return resolvedTheme === "dark" ? "Dark" : "Light";
2614
+ };
2615
+ return /* @__PURE__ */ jsxRuntime.jsx(
2616
+ Button,
2617
+ {
2618
+ variant: "ghost",
2619
+ size: "icon",
2620
+ onClick: cycleTheme,
2621
+ "aria-label": `Toggle theme (current: ${getLabel()})`,
2622
+ title: `Current: ${getLabel()}. Click to cycle: Light \u2192 Dark \u2192 System`,
2623
+ children: getIcon()
2624
+ }
2625
+ );
2626
+ }
2354
2627
 
2355
2628
  exports.AccountDialog = AccountDialog;
2356
2629
  exports.AuthContext = AuthContext;
2357
2630
  exports.AuthProvider = AuthProvider;
2358
2631
  exports.ChatFull = ChatFull;
2632
+ exports.ChatHeader = ChatHeader;
2359
2633
  exports.ChatPopup = ChatPopup;
2360
2634
  exports.ChatSidebar = ChatSidebar;
2361
2635
  exports.Composer = Composer;
2636
+ exports.MelonyClientProvider = MelonyClientProvider;
2362
2637
  exports.MelonyContext = MelonyContext;
2363
- exports.MelonyProvider = MelonyProvider;
2638
+ exports.ThemeProvider = ThemeProvider;
2639
+ exports.ThemeToggle = ThemeToggle;
2364
2640
  exports.Thread = Thread;
2365
2641
  exports.ThreadContext = ThreadContext;
2366
2642
  exports.ThreadList = ThreadList;
2367
2643
  exports.ThreadProvider = ThreadProvider;
2368
2644
  exports.UIRenderer = UIRenderer;
2645
+ exports.groupEventsToMessages = groupEventsToMessages;
2369
2646
  exports.useAuth = useAuth;
2370
2647
  exports.useMelony = useMelony;
2648
+ exports.useTheme = useTheme;
2371
2649
  exports.useThreads = useThreads;
2372
2650
  //# sourceMappingURL=index.cjs.map
2373
2651
  //# sourceMappingURL=index.cjs.map