@melony/react 0.1.12 → 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,7 +63,7 @@ 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
69
  var MelonyClientProvider = ({
@@ -72,20 +71,20 @@ var MelonyClientProvider = ({
72
71
  client,
73
72
  initialEvents
74
73
  }) => {
75
- const [state, setState] = React9.useState(client.getState());
76
- React9.useEffect(() => {
74
+ const [state, setState] = React10.useState(client.getState());
75
+ React10.useEffect(() => {
77
76
  if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
78
77
  client.reset(initialEvents);
79
78
  }
80
79
  }, [client, initialEvents]);
81
- React9.useEffect(() => {
80
+ React10.useEffect(() => {
82
81
  setState(client.getState());
83
82
  const unsubscribe = client.subscribe(setState);
84
83
  return () => {
85
84
  unsubscribe();
86
85
  };
87
86
  }, [client]);
88
- const sendEvent = React9.useCallback(
87
+ const sendEvent = React10.useCallback(
89
88
  async (event, options) => {
90
89
  const generator = client.sendEvent(event, options);
91
90
  for await (const _ of generator) {
@@ -93,11 +92,11 @@ var MelonyClientProvider = ({
93
92
  },
94
93
  [client]
95
94
  );
96
- const reset = React9.useCallback(
95
+ const reset = React10.useCallback(
97
96
  (events) => client.reset(events),
98
97
  [client]
99
98
  );
100
- const value = React9.useMemo(
99
+ const value = React10.useMemo(
101
100
  () => ({
102
101
  ...state,
103
102
  messages: groupEventsToMessages(state.events),
@@ -109,16 +108,16 @@ var MelonyClientProvider = ({
109
108
  );
110
109
  return /* @__PURE__ */ jsxRuntime.jsx(MelonyContext.Provider, { value, children });
111
110
  };
112
- var AuthContext = React9.createContext(
111
+ var AuthContext = React10.createContext(
113
112
  void 0
114
113
  );
115
114
  var AuthProvider = ({
116
115
  children,
117
116
  service
118
117
  }) => {
119
- const [user, setUser] = React9.useState(null);
120
- const [isLoading, setIsLoading] = React9.useState(true);
121
- 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 () => {
122
121
  setIsLoading(true);
123
122
  try {
124
123
  const userData = await service.getMe();
@@ -130,13 +129,13 @@ var AuthProvider = ({
130
129
  setIsLoading(false);
131
130
  }
132
131
  }, [service]);
133
- React9.useEffect(() => {
132
+ React10.useEffect(() => {
134
133
  fetchMe();
135
134
  }, [fetchMe]);
136
- const login = React9.useCallback(() => {
135
+ const login = React10.useCallback(() => {
137
136
  service.login();
138
137
  }, [service]);
139
- const logout = React9.useCallback(async () => {
138
+ const logout = React10.useCallback(async () => {
140
139
  try {
141
140
  await service.logout();
142
141
  setUser(null);
@@ -172,7 +171,7 @@ var AuthProvider = ({
172
171
  }
173
172
  return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value, children });
174
173
  };
175
- var ThreadContext = React9.createContext(
174
+ var ThreadContext = React10.createContext(
176
175
  void 0
177
176
  );
178
177
  var ThreadProvider = ({
@@ -180,17 +179,17 @@ var ThreadProvider = ({
180
179
  service,
181
180
  initialThreadId: providedInitialThreadId
182
181
  }) => {
183
- const defaultInitialThreadId = React9.useMemo(() => client.generateId(), []);
182
+ const defaultInitialThreadId = React10.useMemo(() => client.generateId(), []);
184
183
  const initialThreadId = providedInitialThreadId || defaultInitialThreadId;
185
- const [threads, setThreads] = React9.useState([]);
186
- const [activeThreadId, setActiveThreadId] = React9.useState(
184
+ const [threads, setThreads] = React10.useState([]);
185
+ const [activeThreadId, setActiveThreadId] = React10.useState(
187
186
  initialThreadId
188
187
  );
189
- const [isLoading, setIsLoading] = React9.useState(true);
190
- const [error, setError] = React9.useState(null);
191
- const [threadEvents, setThreadEvents] = React9.useState([]);
192
- const [isLoadingEvents, setIsLoadingEvents] = React9.useState(false);
193
- 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 () => {
194
193
  setIsLoading(true);
195
194
  setError(null);
196
195
  try {
@@ -204,13 +203,13 @@ var ThreadProvider = ({
204
203
  setIsLoading(false);
205
204
  }
206
205
  }, [service]);
207
- React9.useEffect(() => {
206
+ React10.useEffect(() => {
208
207
  fetchThreads();
209
208
  }, [fetchThreads]);
210
- const selectThread = React9.useCallback((threadId) => {
209
+ const selectThread = React10.useCallback((threadId) => {
211
210
  setActiveThreadId(threadId);
212
211
  }, []);
213
- const createThread = React9.useCallback(async () => {
212
+ const createThread = React10.useCallback(async () => {
214
213
  const newId = service.createThread ? await service.createThread() : client.generateId();
215
214
  const newThread = {
216
215
  id: newId,
@@ -220,7 +219,7 @@ var ThreadProvider = ({
220
219
  setActiveThreadId(newId);
221
220
  return newId;
222
221
  }, [service]);
223
- const deleteThread = React9.useCallback(
222
+ const deleteThread = React10.useCallback(
224
223
  async (threadId) => {
225
224
  try {
226
225
  await service.deleteThread(threadId);
@@ -242,10 +241,10 @@ var ThreadProvider = ({
242
241
  },
243
242
  [service]
244
243
  );
245
- const refreshThreads = React9.useCallback(async () => {
244
+ const refreshThreads = React10.useCallback(async () => {
246
245
  await fetchThreads();
247
246
  }, [fetchThreads]);
248
- React9.useEffect(() => {
247
+ React10.useEffect(() => {
249
248
  if (!activeThreadId) {
250
249
  setThreadEvents([]);
251
250
  setIsLoadingEvents(false);
@@ -275,7 +274,7 @@ var ThreadProvider = ({
275
274
  cancelled = true;
276
275
  };
277
276
  }, [activeThreadId, service]);
278
- const value = React9.useMemo(
277
+ const value = React10.useMemo(
279
278
  () => ({
280
279
  threads,
281
280
  activeThreadId,
@@ -303,14 +302,66 @@ var ThreadProvider = ({
303
302
  );
304
303
  return /* @__PURE__ */ jsxRuntime.jsx(ThreadContext.Provider, { value, children });
305
304
  };
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
+ }
306
357
  var useMelony = (options) => {
307
- const context = React9.useContext(MelonyContext);
358
+ const context = React10.useContext(MelonyContext);
308
359
  if (context === void 0) {
309
360
  throw new Error("useMelony must be used within a MelonyClientProvider");
310
361
  }
311
362
  const { client, reset } = context;
312
363
  const { initialEvents } = options || {};
313
- React9.useEffect(() => {
364
+ React10.useEffect(() => {
314
365
  if (initialEvents && initialEvents.length > 0 && client.getState().events.length === 0) {
315
366
  reset(initialEvents);
316
367
  }
@@ -318,19 +369,116 @@ var useMelony = (options) => {
318
369
  return context;
319
370
  };
320
371
  var useAuth = () => {
321
- const context = React9.useContext(AuthContext);
372
+ const context = React10.useContext(AuthContext);
322
373
  if (context === void 0) {
323
374
  throw new Error("useAuth must be used within an AuthProvider");
324
375
  }
325
376
  return context;
326
377
  };
327
378
  var useThreads = () => {
328
- const context = React9.useContext(ThreadContext);
379
+ const context = React10.useContext(ThreadContext);
329
380
  if (context === void 0) {
330
381
  throw new Error("useThreads must be used within a ThreadProvider");
331
382
  }
332
383
  return context;
333
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
+ }
334
482
  function Card({
335
483
  className,
336
484
  size = "default",
@@ -399,7 +547,7 @@ var Card2 = ({
399
547
  return /* @__PURE__ */ jsxRuntime.jsxs(
400
548
  Card,
401
549
  {
402
- className: cn("w-full max-w-2xl shadow-sm", className),
550
+ className: cn("min-w-96", className),
403
551
  style,
404
552
  children: [
405
553
  (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "pb-3", children: [
@@ -721,8 +869,8 @@ var Image = ({
721
869
  className,
722
870
  style
723
871
  }) => {
724
- const [hasError, setHasError] = React9.useState(false);
725
- const [isLoading, setIsLoading] = React9.useState(true);
872
+ const [hasError, setHasError] = React10.useState(false);
873
+ const [isLoading, setIsLoading] = React10.useState(true);
726
874
  const sizes = {
727
875
  sm: "h-11 w-11",
728
876
  md: "h-22 w-22",
@@ -875,7 +1023,7 @@ var Chart = ({
875
1023
  className,
876
1024
  style
877
1025
  }) => {
878
- const [tooltip, setTooltip] = React9.useState(null);
1026
+ const [tooltip, setTooltip] = React10.useState(null);
879
1027
  if (!Array.isArray(data)) {
880
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" });
881
1029
  }
@@ -1220,19 +1368,6 @@ var Input2 = ({
1220
1368
  )
1221
1369
  ] });
1222
1370
  };
1223
- function Textarea({ className, ...props }) {
1224
- return /* @__PURE__ */ jsxRuntime.jsx(
1225
- "textarea",
1226
- {
1227
- "data-slot": "textarea",
1228
- className: cn(
1229
- "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",
1230
- className
1231
- ),
1232
- ...props
1233
- }
1234
- );
1235
- }
1236
1371
  var Textarea2 = ({
1237
1372
  placeholder,
1238
1373
  defaultValue,
@@ -1604,50 +1739,6 @@ var RadioGroup = ({
1604
1739
  )
1605
1740
  ] });
1606
1741
  };
1607
- var buttonVariants = classVarianceAuthority.cva(
1608
- "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",
1609
- {
1610
- variants: {
1611
- variant: {
1612
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
1613
- outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
1614
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
1615
- ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
1616
- 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",
1617
- link: "text-primary underline-offset-4 hover:underline"
1618
- },
1619
- size: {
1620
- default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
1621
- 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",
1622
- sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
1623
- lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
1624
- icon: "size-9",
1625
- "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
1626
- "icon-sm": "size-8",
1627
- "icon-lg": "size-10"
1628
- }
1629
- },
1630
- defaultVariants: {
1631
- variant: "default",
1632
- size: "default"
1633
- }
1634
- }
1635
- );
1636
- function Button({
1637
- className,
1638
- variant = "default",
1639
- size = "default",
1640
- ...props
1641
- }) {
1642
- return /* @__PURE__ */ jsxRuntime.jsx(
1643
- button.Button,
1644
- {
1645
- "data-slot": "button",
1646
- className: cn(buttonVariants({ variant, size, className })),
1647
- ...props
1648
- }
1649
- );
1650
- }
1651
1742
  var Button2 = ({
1652
1743
  label,
1653
1744
  variant = "primary",
@@ -1664,6 +1755,8 @@ var Button2 = ({
1664
1755
  secondary: "secondary",
1665
1756
  danger: "destructive",
1666
1757
  outline: "outline",
1758
+ ghost: "ghost",
1759
+ link: "link",
1667
1760
  success: "default"
1668
1761
  // Success doesn't have a direct shadcn mapping in base variant, default is usually primary
1669
1762
  };
@@ -1686,7 +1779,7 @@ var Button2 = ({
1686
1779
  };
1687
1780
  var Form = ({ children, onSubmitAction, className, style }) => {
1688
1781
  const { sendEvent } = useMelony();
1689
- const [isSubmitted, setIsSubmitted] = React9.useState(false);
1782
+ const [isSubmitted, setIsSubmitted] = React10.useState(false);
1690
1783
  const handleSubmit = (e) => {
1691
1784
  e.preventDefault();
1692
1785
  if (isSubmitted) return;
@@ -1732,6 +1825,32 @@ var Form = ({ children, onSubmitAction, className, style }) => {
1732
1825
  }
1733
1826
  );
1734
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
+ }
1735
1854
  function UIRenderer({ node }) {
1736
1855
  const { type, props, children } = node;
1737
1856
  const typeMap = {
@@ -1770,46 +1889,57 @@ function UIRenderer({ node }) {
1770
1889
  const componentProps = { ...props };
1771
1890
  return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...componentProps, children: renderedChildren });
1772
1891
  }
1773
- function Composer({
1774
- value,
1775
- onChange,
1776
- onSubmit,
1777
- placeholder = "Type a message...",
1778
- isLoading,
1779
- className
1780
- }) {
1781
- const handleKeyDown = (e) => {
1782
- if (e.key === "Enter" && !e.shiftKey) {
1783
- e.preventDefault();
1784
- 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);
1785
1896
  }
1786
- };
1787
- 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: [
1788
- /* @__PURE__ */ jsxRuntime.jsx(
1789
- Textarea,
1790
- {
1791
- value,
1792
- onChange: (e) => onChange(e.target.value),
1793
- onKeyDown: handleKeyDown,
1794
- placeholder,
1795
- 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"
1796
- }
1797
- ),
1798
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-end items-center px-2 pb-0.5", children: /* @__PURE__ */ jsxRuntime.jsx(
1799
- Button,
1800
- {
1801
- type: "submit",
1802
- disabled: !value.trim() && !isLoading || isLoading,
1803
- size: "icon",
1804
- onClick: () => onSubmit(),
1805
- className: cn(
1806
- "h-8 w-8 rounded-full transition-all shrink-0",
1807
- value.trim() ? "bg-foreground text-background hover:bg-foreground/90" : "bg-muted-foreground/20 text-muted-foreground/40"
1808
- ),
1809
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowUp, { className: "h-5 w-5" })
1810
- }
1811
- ) })
1812
- ] }) });
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
+ ] });
1813
1943
  }
1814
1944
  function Thread({
1815
1945
  className,
@@ -1818,9 +1948,9 @@ function Thread({
1818
1948
  onStarterPromptClick
1819
1949
  }) {
1820
1950
  const { messages, isLoading, error, sendEvent } = useMelony();
1821
- const [input, setInput] = React9.useState("");
1822
- const messagesEndRef = React9.useRef(null);
1823
- React9.useEffect(() => {
1951
+ const [input, setInput] = React10.useState("");
1952
+ const messagesEndRef = React10.useRef(null);
1953
+ React10.useEffect(() => {
1824
1954
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1825
1955
  }, [messages]);
1826
1956
  const handleSubmit = async (e, overrideInput) => {
@@ -1841,57 +1971,38 @@ function Thread({
1841
1971
  handleSubmit(void 0, prompt);
1842
1972
  }
1843
1973
  };
1844
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full bg-background", className), children: [
1845
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
1846
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto w-full", children: [
1847
- 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: [
1848
- /* @__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?" }) }),
1849
- /* @__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(
1850
- "button",
1851
- {
1852
- onClick: () => handleStarterPromptClick(item.prompt),
1853
- className: "flex items-center gap-3 p-4 rounded-xl border bg-card hover:bg-muted/50 transition-all text-left group",
1854
- children: [
1855
- item.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 rounded-lg bg-muted group-hover:bg-background transition-colors", children: item.icon }),
1856
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: item.label })
1857
- ]
1858
- },
1859
- i
1860
- )) })
1861
- ] }),
1862
- messages.map((message, i) => /* @__PURE__ */ jsxRuntime.jsx(
1863
- "div",
1864
- {
1865
- className: cn(
1866
- "flex flex-col",
1867
- 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
+ }
1868
1991
  ),
1869
- children: /* @__PURE__ */ jsxRuntime.jsx(
1870
- "div",
1992
+ /* @__PURE__ */ jsxRuntime.jsx(
1993
+ MessageList,
1871
1994
  {
1872
- className: cn(
1873
- "max-w-[85%] rounded-2xl px-4 py-2 space-y-2",
1874
- message.role === "user" ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
1875
- ),
1876
- children: message.content.map((event, j) => {
1877
- if (event.type === "text-delta")
1878
- return /* @__PURE__ */ jsxRuntime.jsx("span", { children: event.data?.delta }, j);
1879
- if (event.type === "text")
1880
- return /* @__PURE__ */ jsxRuntime.jsx("p", { children: event.data?.content || event.data?.text }, j);
1881
- if (event.ui) return /* @__PURE__ */ jsxRuntime.jsx(UIRenderer, { node: event.ui }, j);
1882
- return null;
1883
- })
1995
+ messages,
1996
+ isLoading,
1997
+ error
1884
1998
  }
1885
1999
  )
1886
- },
1887
- i
1888
- )),
1889
- isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." }),
1890
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message })
1891
- ] }),
2000
+ ]
2001
+ }
2002
+ ),
1892
2003
  /* @__PURE__ */ jsxRuntime.jsx("div", { ref: messagesEndRef })
1893
2004
  ] }),
1894
- /* @__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(
1895
2006
  Composer,
1896
2007
  {
1897
2008
  value: input,
@@ -1903,18 +2014,34 @@ function Thread({
1903
2014
  ) }) })
1904
2015
  ] });
1905
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
+ }
1906
2039
  var ThreadList = ({
1907
2040
  className,
1908
2041
  emptyState,
1909
2042
  onThreadSelect
1910
2043
  }) => {
1911
- const {
1912
- threads,
1913
- activeThreadId,
1914
- selectThread,
1915
- createThread,
1916
- deleteThread
1917
- } = useThreads();
2044
+ const { threads, activeThreadId, selectThread, createThread, deleteThread } = useThreads();
1918
2045
  const handleThreadClick = (threadId) => {
1919
2046
  if (threadId !== activeThreadId) {
1920
2047
  selectThread(threadId);
@@ -1952,10 +2079,10 @@ var ThreadList = ({
1952
2079
  return d.toLocaleDateString();
1953
2080
  };
1954
2081
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full", className), children: [
1955
- /* @__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(
1956
2083
  Button,
1957
2084
  {
1958
- variant: "outline",
2085
+ variant: "ghost",
1959
2086
  size: "sm",
1960
2087
  onClick: handleNewThread,
1961
2088
  className: "w-full justify-start",
@@ -1976,31 +2103,13 @@ var ThreadList = ({
1976
2103
  {
1977
2104
  onClick: () => handleThreadClick(thread.id),
1978
2105
  className: cn(
1979
- "group relative flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors",
1980
- 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"
1981
2108
  ),
1982
2109
  children: [
1983
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: [
1984
- /* @__PURE__ */ jsxRuntime.jsx(
1985
- "p",
1986
- {
1987
- className: cn(
1988
- "text-sm font-medium truncate",
1989
- isActive && "text-primary-foreground"
1990
- ),
1991
- children: thread.title || `Thread ${thread.id.slice(0, 8)}`
1992
- }
1993
- ),
1994
- thread.updatedAt && /* @__PURE__ */ jsxRuntime.jsx(
1995
- "span",
1996
- {
1997
- className: cn(
1998
- "text-xs shrink-0",
1999
- isActive ? "text-primary-foreground/70" : "text-muted-foreground"
2000
- ),
2001
- children: formatDate(thread.updatedAt)
2002
- }
2003
- )
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) })
2004
2113
  ] }) }),
2005
2114
  /* @__PURE__ */ jsxRuntime.jsx(
2006
2115
  Button,
@@ -2026,10 +2135,11 @@ function ChatPopup({
2026
2135
  title = "Chat",
2027
2136
  placeholder = "Message the AI",
2028
2137
  starterPrompts,
2029
- defaultOpen = false
2138
+ defaultOpen = false,
2139
+ headerProps
2030
2140
  }) {
2031
- const [isOpen, setIsOpen] = React9.useState(defaultOpen);
2032
- const [view, setView] = React9.useState("chat");
2141
+ const [isOpen, setIsOpen] = React10.useState(defaultOpen);
2142
+ const [view, setView] = React10.useState("chat");
2033
2143
  const { createThread } = useThreads();
2034
2144
  const handleNewChat = async () => {
2035
2145
  try {
@@ -2041,9 +2151,11 @@ function ChatPopup({
2041
2151
  };
2042
2152
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 font-sans", children: [
2043
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: [
2044
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "p-4 border-b flex flex-row items-center justify-between space-y-0 h-14 shrink-0", children: [
2045
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2046
- 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(
2047
2159
  Button,
2048
2160
  {
2049
2161
  variant: "ghost",
@@ -2052,44 +2164,44 @@ function ChatPopup({
2052
2164
  className: "text-muted-foreground hover:text-foreground",
2053
2165
  children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconArrowLeft, { className: "size-4" })
2054
2166
  }
2055
- ),
2056
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-sm font-semibold", children: view === "history" ? "History" : title })
2057
- ] }),
2058
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
2059
- view === "chat" && /* @__PURE__ */ jsxRuntime.jsx(
2060
- Button,
2061
- {
2062
- variant: "ghost",
2063
- size: "icon-xs",
2064
- onClick: () => setView("history"),
2065
- className: "text-muted-foreground hover:text-foreground",
2066
- title: "History",
2067
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconHistory, { className: "size-4" })
2068
- }
2069
- ),
2070
- /* @__PURE__ */ jsxRuntime.jsx(
2071
- Button,
2072
- {
2073
- variant: "ghost",
2074
- size: "icon-xs",
2075
- onClick: handleNewChat,
2076
- className: "text-muted-foreground hover:text-foreground",
2077
- title: "New Chat",
2078
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconPlus, { className: "size-4" })
2079
- }
2080
- ),
2081
- /* @__PURE__ */ jsxRuntime.jsx(
2082
- Button,
2083
- {
2084
- variant: "ghost",
2085
- size: "icon-xs",
2086
- onClick: () => setIsOpen(false),
2087
- className: "text-muted-foreground hover:text-foreground",
2088
- children: /* @__PURE__ */ jsxRuntime.jsx(ICONS.IconX, { className: "size-4" })
2089
- }
2090
- )
2091
- ] })
2092
- ] }),
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
+ ),
2093
2205
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: view === "chat" ? /* @__PURE__ */ jsxRuntime.jsx(
2094
2206
  Thread,
2095
2207
  {
@@ -2123,10 +2235,11 @@ function ChatSidebar({
2123
2235
  title = "Chat",
2124
2236
  placeholder = "Message the AI",
2125
2237
  starterPrompts,
2126
- className
2238
+ className,
2239
+ headerProps
2127
2240
  }) {
2128
2241
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2129
- /* @__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 }),
2130
2243
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
2131
2244
  Thread,
2132
2245
  {
@@ -2141,11 +2254,122 @@ function ChatFull({
2141
2254
  title = "Chat",
2142
2255
  placeholder = "Message the AI",
2143
2256
  starterPrompts,
2144
- 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
2145
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
+ };
2146
2294
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
2147
- 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 }) }),
2148
- /* @__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
+ ] })
2149
2373
  ] });
2150
2374
  }
2151
2375
  function AlertDialog({ ...props }) {
@@ -2289,8 +2513,8 @@ var AccountDialog = ({
2289
2513
  size
2290
2514
  }) => {
2291
2515
  const { isLoading, isAuthenticated, login, logout } = useAuth();
2292
- const [open, setOpen] = React9__namespace.useState(false);
2293
- const [error, setError] = React9__namespace.useState(null);
2516
+ const [open, setOpen] = React10__namespace.useState(false);
2517
+ const [error, setError] = React10__namespace.useState(null);
2294
2518
  const handleGoogleSignIn = async () => {
2295
2519
  login();
2296
2520
  };
@@ -2365,23 +2589,63 @@ var AccountDialog = ({
2365
2589
  ] }) })
2366
2590
  ] });
2367
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
+ }
2368
2627
 
2369
2628
  exports.AccountDialog = AccountDialog;
2370
2629
  exports.AuthContext = AuthContext;
2371
2630
  exports.AuthProvider = AuthProvider;
2372
2631
  exports.ChatFull = ChatFull;
2632
+ exports.ChatHeader = ChatHeader;
2373
2633
  exports.ChatPopup = ChatPopup;
2374
2634
  exports.ChatSidebar = ChatSidebar;
2375
2635
  exports.Composer = Composer;
2376
2636
  exports.MelonyClientProvider = MelonyClientProvider;
2377
2637
  exports.MelonyContext = MelonyContext;
2638
+ exports.ThemeProvider = ThemeProvider;
2639
+ exports.ThemeToggle = ThemeToggle;
2378
2640
  exports.Thread = Thread;
2379
2641
  exports.ThreadContext = ThreadContext;
2380
2642
  exports.ThreadList = ThreadList;
2381
2643
  exports.ThreadProvider = ThreadProvider;
2382
2644
  exports.UIRenderer = UIRenderer;
2645
+ exports.groupEventsToMessages = groupEventsToMessages;
2383
2646
  exports.useAuth = useAuth;
2384
2647
  exports.useMelony = useMelony;
2648
+ exports.useTheme = useTheme;
2385
2649
  exports.useThreads = useThreads;
2386
2650
  //# sourceMappingURL=index.cjs.map
2387
2651
  //# sourceMappingURL=index.cjs.map