@melony/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2334 @@
1
+ import * as React9 from 'react';
2
+ import { createContext, useState, useEffect, useCallback, useMemo, useContext, useRef } from 'react';
3
+ import { clsx } from 'clsx';
4
+ import { twMerge } from 'tailwind-merge';
5
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
+ import { generateId } from 'melony/client';
7
+ import { Separator as Separator$1 } from '@base-ui/react/separator';
8
+ import * as ICONS from '@tabler/icons-react';
9
+ import { IconArrowUp, IconPlus, IconMessage, IconTrash, IconArrowLeft, IconHistory, IconX, IconUser, IconLogout, IconBrandGoogle, IconSelector, IconCheck, IconChevronUp, IconChevronDown } from '@tabler/icons-react';
10
+ import { mergeProps } from '@base-ui/react/merge-props';
11
+ import { useRender } from '@base-ui/react/use-render';
12
+ import { cva } from 'class-variance-authority';
13
+ import { Input as Input$1 } from '@base-ui/react/input';
14
+ import { Select as Select$1 } from '@base-ui/react/select';
15
+ import { Button as Button$1 } from '@base-ui/react/button';
16
+ import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
17
+ import { Menu } from '@base-ui/react/menu';
18
+
19
+ // src/providers/melony-provider.tsx
20
+ function cn(...inputs) {
21
+ return twMerge(clsx(inputs));
22
+ }
23
+ function groupEventsToMessages(events) {
24
+ if (events.length === 0) return [];
25
+ const messages = [];
26
+ let currentMessage = null;
27
+ for (const event of events) {
28
+ const role = event.role || "assistant";
29
+ const runId = event.runId;
30
+ if (!currentMessage || currentMessage.role !== role || runId && currentMessage.runId && runId !== currentMessage.runId) {
31
+ currentMessage = {
32
+ role,
33
+ content: [event],
34
+ runId
35
+ };
36
+ messages.push(currentMessage);
37
+ } else {
38
+ currentMessage.content.push(event);
39
+ if (!currentMessage.runId && runId) {
40
+ currentMessage.runId = runId;
41
+ }
42
+ }
43
+ }
44
+ return messages;
45
+ }
46
+ var MelonyContext = createContext(void 0);
47
+ var MelonyProvider = ({
48
+ children,
49
+ client
50
+ }) => {
51
+ const [state, setState] = useState(client.getState());
52
+ useEffect(() => {
53
+ setState(client.getState());
54
+ return () => {
55
+ client.subscribe(setState);
56
+ };
57
+ }, [client]);
58
+ const sendEvent = useCallback(
59
+ async (event, options) => {
60
+ const generator = client.sendEvent(event, options);
61
+ for await (const _ of generator) {
62
+ }
63
+ },
64
+ [client]
65
+ );
66
+ const clear = useCallback(() => client.clear(), [client]);
67
+ const value = useMemo(
68
+ () => ({
69
+ ...state,
70
+ messages: groupEventsToMessages(state.events),
71
+ sendEvent,
72
+ clear,
73
+ client
74
+ }),
75
+ [state, sendEvent, clear, client]
76
+ );
77
+ return /* @__PURE__ */ jsx(MelonyContext.Provider, { value, children });
78
+ };
79
+ var AuthContext = createContext(
80
+ void 0
81
+ );
82
+ var AuthProvider = ({
83
+ children,
84
+ service
85
+ }) => {
86
+ const [user, setUser] = useState(null);
87
+ const [isLoading, setIsLoading] = useState(true);
88
+ const fetchMe = useCallback(async () => {
89
+ setIsLoading(true);
90
+ try {
91
+ const userData = await service.getMe();
92
+ setUser(userData);
93
+ } catch (error) {
94
+ console.error("Failed to fetch user:", error);
95
+ setUser(null);
96
+ } finally {
97
+ setIsLoading(false);
98
+ }
99
+ }, [service]);
100
+ useEffect(() => {
101
+ fetchMe();
102
+ }, [fetchMe]);
103
+ const login = useCallback(() => {
104
+ service.login();
105
+ }, [service]);
106
+ const logout = useCallback(async () => {
107
+ try {
108
+ await service.logout();
109
+ setUser(null);
110
+ } catch (error) {
111
+ console.error("Failed to logout:", error);
112
+ }
113
+ }, [service]);
114
+ const value = {
115
+ user,
116
+ isAuthenticated: !!user,
117
+ isLoading,
118
+ login,
119
+ logout,
120
+ getToken: service.getToken
121
+ };
122
+ if (isLoading) {
123
+ return /* @__PURE__ */ jsx(
124
+ "div",
125
+ {
126
+ style: {
127
+ height: "100vh",
128
+ width: "100vw",
129
+ display: "flex",
130
+ justifyContent: "center",
131
+ alignItems: "center",
132
+ fontSize: "0.875rem",
133
+ letterSpacing: "0.01em"
134
+ },
135
+ className: "text-muted-foreground animate-pulse",
136
+ children: "Loading..."
137
+ }
138
+ );
139
+ }
140
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
141
+ };
142
+ var ThreadContext = createContext(void 0);
143
+ var ThreadProvider = ({
144
+ children,
145
+ service,
146
+ initialThreadId: providedInitialThreadId
147
+ }) => {
148
+ const defaultInitialThreadId = useMemo(() => generateId(), []);
149
+ const initialThreadId = providedInitialThreadId || defaultInitialThreadId;
150
+ const [threads, setThreads] = useState([]);
151
+ const [activeThreadId, setActiveThreadId] = useState(
152
+ initialThreadId
153
+ );
154
+ const [isLoading, setIsLoading] = useState(true);
155
+ const [error, setError] = useState(null);
156
+ const [threadEvents, setThreadEvents] = useState([]);
157
+ const [isLoadingEvents, setIsLoadingEvents] = useState(false);
158
+ const fetchThreads = useCallback(async () => {
159
+ setIsLoading(true);
160
+ setError(null);
161
+ try {
162
+ const processedThreads = await service.getThreads();
163
+ setThreads(processedThreads);
164
+ } catch (err) {
165
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch threads");
166
+ setError(error2);
167
+ console.error("Failed to fetch threads:", error2);
168
+ } finally {
169
+ setIsLoading(false);
170
+ }
171
+ }, [service]);
172
+ useEffect(() => {
173
+ fetchThreads();
174
+ }, [fetchThreads]);
175
+ const selectThread = useCallback((threadId) => {
176
+ setActiveThreadId(threadId);
177
+ }, []);
178
+ const createThread = useCallback(async () => {
179
+ const newId = service.createThread ? await service.createThread() : generateId();
180
+ const newThread = {
181
+ id: newId,
182
+ updatedAt: /* @__PURE__ */ new Date()
183
+ };
184
+ setThreads((prev) => [newThread, ...prev]);
185
+ setActiveThreadId(newId);
186
+ return newId;
187
+ }, [service]);
188
+ const deleteThread = useCallback(
189
+ async (threadId) => {
190
+ try {
191
+ await service.deleteThread(threadId);
192
+ setThreads((prev) => {
193
+ const remainingThreads = prev.filter((t) => t.id !== threadId);
194
+ setActiveThreadId((current) => {
195
+ if (current === threadId) {
196
+ return remainingThreads.length > 0 ? remainingThreads[0].id : null;
197
+ }
198
+ return current;
199
+ });
200
+ return remainingThreads;
201
+ });
202
+ } catch (err) {
203
+ const error2 = err instanceof Error ? err : new Error("Failed to delete thread");
204
+ setError(error2);
205
+ throw error2;
206
+ }
207
+ },
208
+ [service]
209
+ );
210
+ const refreshThreads = useCallback(async () => {
211
+ await fetchThreads();
212
+ }, [fetchThreads]);
213
+ const threadMessages = useMemo(() => {
214
+ return groupEventsToMessages(threadEvents);
215
+ }, [threadEvents]);
216
+ useEffect(() => {
217
+ if (!activeThreadId) {
218
+ setThreadEvents([]);
219
+ setIsLoadingEvents(false);
220
+ return;
221
+ }
222
+ let cancelled = false;
223
+ const fetchEvents = async () => {
224
+ setIsLoadingEvents(true);
225
+ try {
226
+ const events = await service.getEvents(activeThreadId);
227
+ if (!cancelled) {
228
+ setThreadEvents(events);
229
+ }
230
+ } catch (err) {
231
+ if (!cancelled) {
232
+ console.error("Failed to fetch events:", err);
233
+ setThreadEvents([]);
234
+ }
235
+ } finally {
236
+ if (!cancelled) {
237
+ setIsLoadingEvents(false);
238
+ }
239
+ }
240
+ };
241
+ fetchEvents();
242
+ return () => {
243
+ cancelled = true;
244
+ };
245
+ }, [activeThreadId, service]);
246
+ const value = useMemo(
247
+ () => ({
248
+ threads,
249
+ activeThreadId,
250
+ isLoading,
251
+ error,
252
+ selectThread,
253
+ createThread,
254
+ deleteThread,
255
+ refreshThreads,
256
+ threadEvents,
257
+ threadMessages,
258
+ isLoadingEvents
259
+ }),
260
+ [
261
+ threads,
262
+ activeThreadId,
263
+ isLoading,
264
+ error,
265
+ selectThread,
266
+ createThread,
267
+ deleteThread,
268
+ refreshThreads,
269
+ threadEvents,
270
+ threadMessages,
271
+ isLoadingEvents
272
+ ]
273
+ );
274
+ return /* @__PURE__ */ jsx(ThreadContext.Provider, { value, children });
275
+ };
276
+ var useMelony = () => {
277
+ const context = useContext(MelonyContext);
278
+ if (context === void 0) {
279
+ throw new Error("useMelony must be used within a MelonyProvider");
280
+ }
281
+ return context;
282
+ };
283
+ var useAuth = () => {
284
+ const context = useContext(AuthContext);
285
+ if (context === void 0) {
286
+ throw new Error("useAuth must be used within an AuthProvider");
287
+ }
288
+ return context;
289
+ };
290
+ var useThreads = () => {
291
+ const context = useContext(ThreadContext);
292
+ if (context === void 0) {
293
+ throw new Error("useThreads must be used within a ThreadProvider");
294
+ }
295
+ return context;
296
+ };
297
+ function Card({
298
+ className,
299
+ size = "default",
300
+ ...props
301
+ }) {
302
+ return /* @__PURE__ */ jsx(
303
+ "div",
304
+ {
305
+ "data-slot": "card",
306
+ "data-size": size,
307
+ className: cn("ring-foreground/10 bg-card text-card-foreground gap-6 overflow-hidden rounded-2xl py-6 text-sm ring-1 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl group/card flex flex-col", className),
308
+ ...props
309
+ }
310
+ );
311
+ }
312
+ function CardHeader({ className, ...props }) {
313
+ return /* @__PURE__ */ jsx(
314
+ "div",
315
+ {
316
+ "data-slot": "card-header",
317
+ className: cn(
318
+ "gap-2 rounded-t-xl px-6 group-data-[size=sm]/card:px-4 [.border-b]:pb-6 group-data-[size=sm]/card:[.border-b]:pb-4 group/card-header @container/card-header grid auto-rows-min items-start has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto]",
319
+ className
320
+ ),
321
+ ...props
322
+ }
323
+ );
324
+ }
325
+ function CardTitle({ className, ...props }) {
326
+ return /* @__PURE__ */ jsx(
327
+ "div",
328
+ {
329
+ "data-slot": "card-title",
330
+ className: cn("text-base font-medium", className),
331
+ ...props
332
+ }
333
+ );
334
+ }
335
+ function CardDescription({ className, ...props }) {
336
+ return /* @__PURE__ */ jsx(
337
+ "div",
338
+ {
339
+ "data-slot": "card-description",
340
+ className: cn("text-muted-foreground text-sm", className),
341
+ ...props
342
+ }
343
+ );
344
+ }
345
+ function CardContent({ className, ...props }) {
346
+ return /* @__PURE__ */ jsx(
347
+ "div",
348
+ {
349
+ "data-slot": "card-content",
350
+ className: cn("px-6 group-data-[size=sm]/card:px-4", className),
351
+ ...props
352
+ }
353
+ );
354
+ }
355
+ var Card2 = ({
356
+ children,
357
+ title,
358
+ subtitle,
359
+ className,
360
+ style
361
+ }) => {
362
+ return /* @__PURE__ */ jsxs(
363
+ Card,
364
+ {
365
+ className: cn("w-full max-w-2xl shadow-sm", className),
366
+ style,
367
+ children: [
368
+ (title || subtitle) && /* @__PURE__ */ jsxs(CardHeader, { className: "pb-3", children: [
369
+ title && /* @__PURE__ */ jsx(CardTitle, { className: "text-lg", children: title }),
370
+ subtitle && /* @__PURE__ */ jsx(CardDescription, { children: subtitle })
371
+ ] }),
372
+ /* @__PURE__ */ jsx(CardContent, { className: "flex flex-col gap-4", children })
373
+ ]
374
+ }
375
+ );
376
+ };
377
+ var Row = ({
378
+ children,
379
+ gap = "md",
380
+ align = "start",
381
+ justify = "start",
382
+ wrap = false,
383
+ className,
384
+ style
385
+ }) => {
386
+ const gapClasses = {
387
+ xs: "gap-0",
388
+ sm: "gap-1",
389
+ md: "gap-2",
390
+ lg: "gap-4",
391
+ xl: "gap-6"
392
+ };
393
+ const alignClasses = {
394
+ start: "items-start",
395
+ center: "items-center",
396
+ end: "items-end",
397
+ stretch: "items-stretch"
398
+ };
399
+ const justifyClasses = {
400
+ start: "justify-start",
401
+ center: "justify-center",
402
+ end: "justify-end",
403
+ between: "justify-between",
404
+ around: "justify-around"
405
+ };
406
+ return /* @__PURE__ */ jsx(
407
+ "div",
408
+ {
409
+ className: cn(
410
+ "flex flex-row w-full",
411
+ gapClasses[gap] || "gap-4",
412
+ alignClasses[align] || "items-start",
413
+ justifyClasses[justify] || "justify-start",
414
+ wrap ? "flex-wrap" : "flex-nowrap",
415
+ className
416
+ ),
417
+ style,
418
+ children
419
+ }
420
+ );
421
+ };
422
+ var Col = ({
423
+ children,
424
+ gap = "sm",
425
+ align = "start",
426
+ justify = "start",
427
+ wrap = "nowrap",
428
+ flex = 1,
429
+ width,
430
+ height,
431
+ padding,
432
+ overflow,
433
+ position = "static",
434
+ className,
435
+ style
436
+ }) => {
437
+ const gapClasses = {
438
+ xs: "gap-1",
439
+ sm: "gap-2",
440
+ md: "gap-4",
441
+ lg: "gap-6",
442
+ xl: "gap-8"
443
+ };
444
+ const alignClasses = {
445
+ start: "items-start",
446
+ center: "items-center",
447
+ end: "items-end",
448
+ stretch: "items-stretch"
449
+ };
450
+ const justifyClasses = {
451
+ start: "justify-start",
452
+ center: "justify-center",
453
+ end: "justify-end",
454
+ between: "justify-between",
455
+ around: "justify-around"
456
+ };
457
+ const overflowClasses = {
458
+ auto: "overflow-auto",
459
+ hidden: "overflow-hidden",
460
+ scroll: "overflow-scroll",
461
+ visible: "overflow-visible"
462
+ };
463
+ const positionClasses = {
464
+ static: "static",
465
+ relative: "relative",
466
+ absolute: "absolute",
467
+ fixed: "fixed",
468
+ sticky: "sticky"
469
+ };
470
+ return /* @__PURE__ */ jsx(
471
+ "div",
472
+ {
473
+ className: cn(
474
+ "flex flex-col",
475
+ gapClasses[gap] || "gap-2",
476
+ alignClasses[align] || "items-start",
477
+ justifyClasses[justify] || "justify-start",
478
+ wrap === "wrap" ? "flex-wrap" : "flex-nowrap",
479
+ overflow && overflowClasses[overflow],
480
+ position && positionClasses[position],
481
+ className
482
+ ),
483
+ style: {
484
+ flex,
485
+ width,
486
+ height,
487
+ padding,
488
+ ...style
489
+ },
490
+ children
491
+ }
492
+ );
493
+ };
494
+ var Box = ({
495
+ children,
496
+ padding = "md",
497
+ margin,
498
+ background,
499
+ border = false,
500
+ borderRadius,
501
+ width,
502
+ height,
503
+ overflow = "visible",
504
+ className,
505
+ style
506
+ }) => {
507
+ const paddingClasses = {
508
+ xs: "p-1",
509
+ sm: "p-2",
510
+ md: "p-4",
511
+ lg: "p-6",
512
+ xl: "p-8"
513
+ };
514
+ const overflowClasses = {
515
+ auto: "overflow-auto",
516
+ hidden: "overflow-hidden",
517
+ scroll: "overflow-scroll",
518
+ visible: "overflow-visible"
519
+ };
520
+ return /* @__PURE__ */ jsx(
521
+ "div",
522
+ {
523
+ className: cn(
524
+ paddingClasses[padding] || "p-4",
525
+ border && "border rounded-md",
526
+ overflowClasses[overflow],
527
+ className
528
+ ),
529
+ style: {
530
+ margin,
531
+ background: background ?? void 0,
532
+ borderRadius,
533
+ width,
534
+ height,
535
+ ...style
536
+ },
537
+ children
538
+ }
539
+ );
540
+ };
541
+ var Spacer = ({
542
+ size = "md",
543
+ direction = "vertical",
544
+ className,
545
+ style
546
+ }) => {
547
+ const sizeClasses = {
548
+ xs: "p-0.5",
549
+ sm: "p-1",
550
+ md: "p-2",
551
+ lg: "p-4",
552
+ xl: "p-8"
553
+ };
554
+ return /* @__PURE__ */ jsx(
555
+ "div",
556
+ {
557
+ className: cn(
558
+ direction === "vertical" ? "w-full" : "h-full",
559
+ sizeClasses[size] || "p-2",
560
+ className
561
+ ),
562
+ style
563
+ }
564
+ );
565
+ };
566
+ function Separator({
567
+ className,
568
+ orientation = "horizontal",
569
+ ...props
570
+ }) {
571
+ return /* @__PURE__ */ jsx(
572
+ Separator$1,
573
+ {
574
+ "data-slot": "separator",
575
+ orientation,
576
+ className: cn(
577
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch",
578
+ className
579
+ ),
580
+ ...props
581
+ }
582
+ );
583
+ }
584
+ var Divider = ({
585
+ orientation = "horizontal",
586
+ className,
587
+ style
588
+ }) => {
589
+ return /* @__PURE__ */ jsx(
590
+ Separator,
591
+ {
592
+ orientation,
593
+ className: cn("my-4", className),
594
+ style
595
+ }
596
+ );
597
+ };
598
+ var List = ({ children, width, className, style }) => {
599
+ return /* @__PURE__ */ jsx(
600
+ "div",
601
+ {
602
+ className: cn("flex flex-col list-none p-0 m-0", className),
603
+ style: {
604
+ width,
605
+ ...style
606
+ },
607
+ children
608
+ }
609
+ );
610
+ };
611
+ var ListItem = ({
612
+ children,
613
+ orientation = "horizontal",
614
+ gap = "md",
615
+ align,
616
+ justify = "start",
617
+ onClickAction,
618
+ width,
619
+ padding = "md",
620
+ className,
621
+ style
622
+ }) => {
623
+ const { sendEvent } = useMelony();
624
+ const paddingClasses = {
625
+ xs: "px-1.5 py-1",
626
+ sm: "px-2 py-1.5",
627
+ md: "px-3 py-2",
628
+ lg: "px-4 py-3",
629
+ xl: "px-6 py-4"
630
+ };
631
+ const isInteractive = !!onClickAction;
632
+ const gapClasses = {
633
+ xs: "gap-1",
634
+ sm: "gap-2",
635
+ md: "gap-3",
636
+ lg: "gap-4",
637
+ xl: "gap-6"
638
+ };
639
+ const resolvedAlign = align ?? (orientation === "vertical" ? "start" : "center");
640
+ const alignClasses = {
641
+ start: "items-start",
642
+ center: "items-center",
643
+ end: "items-end",
644
+ stretch: "items-stretch"
645
+ };
646
+ const justifyClasses = {
647
+ start: "justify-start",
648
+ center: "justify-center",
649
+ end: "justify-end",
650
+ between: "justify-between",
651
+ around: "justify-around"
652
+ };
653
+ const handleClick = () => {
654
+ if (onClickAction) {
655
+ sendEvent(onClickAction);
656
+ }
657
+ };
658
+ return /* @__PURE__ */ jsx(
659
+ "div",
660
+ {
661
+ onClick: isInteractive ? handleClick : void 0,
662
+ className: cn(
663
+ "flex rounded-md transition-colors",
664
+ orientation === "horizontal" ? "flex-row" : "flex-col",
665
+ gapClasses[gap] || "gap-3",
666
+ alignClasses[resolvedAlign],
667
+ justifyClasses[justify],
668
+ paddingClasses[padding] || "px-3 py-2",
669
+ isInteractive ? "cursor-pointer hover:bg-muted" : "cursor-default",
670
+ className
671
+ ),
672
+ style: {
673
+ width,
674
+ ...style
675
+ },
676
+ children
677
+ }
678
+ );
679
+ };
680
+ var Image = ({
681
+ src,
682
+ alt,
683
+ size = "sm",
684
+ className,
685
+ style
686
+ }) => {
687
+ const [hasError, setHasError] = useState(false);
688
+ const [isLoading, setIsLoading] = useState(true);
689
+ const sizes = {
690
+ sm: "h-11 w-11",
691
+ md: "h-22 w-22",
692
+ lg: "h-44 w-44"
693
+ };
694
+ const handleError = () => {
695
+ setHasError(true);
696
+ setIsLoading(false);
697
+ };
698
+ const handleLoad = () => {
699
+ setIsLoading(false);
700
+ };
701
+ if (hasError) {
702
+ return /* @__PURE__ */ jsx(
703
+ "div",
704
+ {
705
+ className: cn(
706
+ "flex items-center justify-center rounded-md border bg-muted text-muted-foreground",
707
+ sizes[size] || "h-11 w-11",
708
+ className
709
+ ),
710
+ style,
711
+ children: /* @__PURE__ */ jsx("span", { className: "text-[10px]", children: "Error" })
712
+ }
713
+ );
714
+ }
715
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative overflow-hidden rounded-md border", className), style, children: [
716
+ /* @__PURE__ */ jsx(
717
+ "img",
718
+ {
719
+ src,
720
+ alt,
721
+ onError: handleError,
722
+ onLoad: handleLoad,
723
+ className: cn(
724
+ "block h-auto w-full transition-opacity duration-200",
725
+ isLoading ? "opacity-0" : "opacity-100",
726
+ sizes[size]
727
+ )
728
+ }
729
+ ),
730
+ isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-muted animate-pulse" })
731
+ ] });
732
+ };
733
+ var Icon = ({
734
+ name,
735
+ size,
736
+ color,
737
+ className,
738
+ style
739
+ }) => {
740
+ const IconComponent = ICONS[name];
741
+ if (!IconComponent) return null;
742
+ const sizeMap = {
743
+ xs: 12,
744
+ sm: 16,
745
+ md: 20,
746
+ lg: 24,
747
+ xl: 28,
748
+ xxl: 32
749
+ };
750
+ const resolvedSize = typeof size === "string" && size in sizeMap ? sizeMap[size] : typeof size === "number" ? size : 20;
751
+ return /* @__PURE__ */ jsx(
752
+ "div",
753
+ {
754
+ className: cn("inline-flex items-center justify-center", className),
755
+ style,
756
+ children: /* @__PURE__ */ jsx(
757
+ IconComponent,
758
+ {
759
+ size: resolvedSize,
760
+ color: color || "currentColor",
761
+ strokeWidth: 1.5
762
+ }
763
+ )
764
+ }
765
+ );
766
+ };
767
+ var badgeVariants = cva(
768
+ "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
769
+ {
770
+ variants: {
771
+ variant: {
772
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
773
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
774
+ destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
775
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/30",
776
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
777
+ link: "text-primary underline-offset-4 hover:underline"
778
+ }
779
+ },
780
+ defaultVariants: {
781
+ variant: "default"
782
+ }
783
+ }
784
+ );
785
+ function Badge({
786
+ className,
787
+ variant = "default",
788
+ render,
789
+ ...props
790
+ }) {
791
+ return useRender({
792
+ defaultTagName: "span",
793
+ props: mergeProps(
794
+ {
795
+ className: cn(badgeVariants({ className, variant }))
796
+ },
797
+ props
798
+ ),
799
+ render,
800
+ state: {
801
+ slot: "badge",
802
+ variant
803
+ }
804
+ });
805
+ }
806
+ var Badge2 = ({
807
+ label,
808
+ variant = "primary",
809
+ className,
810
+ style
811
+ }) => {
812
+ const variantMap = {
813
+ primary: "default",
814
+ secondary: "secondary",
815
+ danger: "destructive",
816
+ success: "default",
817
+ // Mapping success to default/primary
818
+ warning: "secondary"
819
+ // Mapping warning to secondary
820
+ };
821
+ return /* @__PURE__ */ jsx(
822
+ Badge,
823
+ {
824
+ variant: variantMap[variant] || "default",
825
+ className,
826
+ style,
827
+ children: label
828
+ }
829
+ );
830
+ };
831
+ var Chart = ({
832
+ data,
833
+ chartType = "bar",
834
+ size = "md",
835
+ showValues = false,
836
+ showGrid = false,
837
+ showTooltips = true,
838
+ className,
839
+ style
840
+ }) => {
841
+ const [tooltip, setTooltip] = useState(null);
842
+ if (!Array.isArray(data)) {
843
+ return /* @__PURE__ */ jsx("div", { className: "p-4 text-destructive border border-destructive/20 rounded-md bg-destructive/5", children: "Error: Chart data must be an array" });
844
+ }
845
+ const maxValue = Math.max(...data.map((d) => d.value), 1);
846
+ const padding = { top: 40, right: 20, bottom: 40, left: 20 };
847
+ const chartWidth = size === "sm" ? 300 : size === "md" ? 450 : size === "lg" ? 600 : 800;
848
+ const chartHeight = size === "sm" ? 150 : size === "md" ? 250 : size === "lg" ? 350 : 450;
849
+ const defaultColors = [
850
+ "hsl(var(--primary))",
851
+ "hsl(var(--chart-1, 217 91% 60%))",
852
+ "hsl(var(--chart-2, 142 71% 45%))",
853
+ "hsl(var(--chart-3, 31 92% 55%))",
854
+ "hsl(var(--chart-4, 346 84% 61%))",
855
+ "hsl(var(--chart-5, 271 81% 56%))"
856
+ ];
857
+ const getColor = (index, color) => {
858
+ if (color) return color;
859
+ return defaultColors[index % defaultColors.length];
860
+ };
861
+ const renderGrid = () => {
862
+ if (!showGrid) return null;
863
+ return [0, 0.25, 0.5, 0.75, 1].map((fraction, i) => /* @__PURE__ */ jsx(
864
+ "line",
865
+ {
866
+ x1: padding.left,
867
+ y1: padding.top + chartHeight * (1 - fraction),
868
+ x2: chartWidth - padding.right,
869
+ y2: padding.top + chartHeight * (1 - fraction),
870
+ stroke: "currentColor",
871
+ className: "text-border",
872
+ strokeDasharray: "4,4",
873
+ strokeOpacity: 0.5
874
+ },
875
+ i
876
+ ));
877
+ };
878
+ const renderTooltip = () => {
879
+ if (!tooltip || !tooltip.visible) return null;
880
+ return /* @__PURE__ */ jsxs("g", { className: "pointer-events-none", children: [
881
+ /* @__PURE__ */ jsx(
882
+ "rect",
883
+ {
884
+ x: tooltip.x - 40,
885
+ y: tooltip.y - 45,
886
+ width: 80,
887
+ height: 40,
888
+ fill: "hsl(var(--popover))",
889
+ stroke: "hsl(var(--border))",
890
+ strokeWidth: 1,
891
+ rx: 6,
892
+ className: "shadow-md"
893
+ }
894
+ ),
895
+ /* @__PURE__ */ jsx(
896
+ "text",
897
+ {
898
+ x: tooltip.x,
899
+ y: tooltip.y - 28,
900
+ textAnchor: "middle",
901
+ className: "fill-popover-foreground text-[10px] font-semibold",
902
+ children: tooltip.value
903
+ }
904
+ ),
905
+ /* @__PURE__ */ jsx(
906
+ "text",
907
+ {
908
+ x: tooltip.x,
909
+ y: tooltip.y - 14,
910
+ textAnchor: "middle",
911
+ className: "fill-muted-foreground text-[9px]",
912
+ children: tooltip.label
913
+ }
914
+ )
915
+ ] });
916
+ };
917
+ const renderBarChart = () => {
918
+ const totalBarSpace = chartWidth - padding.left - padding.right;
919
+ const barSpacing = data.length > 1 ? totalBarSpace * 0.1 / data.length : 0;
920
+ const actualBarWidth = (totalBarSpace - barSpacing * (data.length + 1)) / data.length;
921
+ return /* @__PURE__ */ jsxs("svg", { width: chartWidth, height: chartHeight + padding.bottom, className: "overflow-visible", children: [
922
+ renderGrid(),
923
+ data.map((item, index) => {
924
+ const barHeight = item.value / maxValue * chartHeight;
925
+ const x = padding.left + barSpacing + index * (actualBarWidth + barSpacing);
926
+ const y = padding.top + chartHeight - barHeight;
927
+ return /* @__PURE__ */ jsxs("g", { children: [
928
+ /* @__PURE__ */ jsx(
929
+ "rect",
930
+ {
931
+ x,
932
+ y,
933
+ width: actualBarWidth,
934
+ height: barHeight,
935
+ fill: getColor(index, item.color),
936
+ rx: 4,
937
+ onMouseEnter: () => showTooltips && setTooltip({ visible: true, x: x + actualBarWidth / 2, y: y - 5, label: item.label, value: item.value }),
938
+ onMouseLeave: () => setTooltip({ visible: false, x: 0, y: 0, label: "", value: 0 }),
939
+ className: "transition-all hover:opacity-80 cursor-pointer"
940
+ }
941
+ ),
942
+ /* @__PURE__ */ jsx(
943
+ "text",
944
+ {
945
+ x: x + actualBarWidth / 2,
946
+ y: padding.top + chartHeight + 20,
947
+ textAnchor: "middle",
948
+ className: "fill-muted-foreground text-[10px]",
949
+ children: item.label
950
+ }
951
+ )
952
+ ] }, index);
953
+ }),
954
+ showTooltips && renderTooltip()
955
+ ] });
956
+ };
957
+ const renderLineChart = () => {
958
+ const points = data.map((item, index) => ({
959
+ x: padding.left + index / Math.max(data.length - 1, 1) * (chartWidth - padding.left - padding.right),
960
+ y: padding.top + chartHeight - item.value / maxValue * chartHeight,
961
+ ...item
962
+ }));
963
+ const pathData = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
964
+ return /* @__PURE__ */ jsxs("svg", { width: chartWidth, height: chartHeight + padding.bottom, className: "overflow-visible", children: [
965
+ renderGrid(),
966
+ /* @__PURE__ */ jsx("path", { d: pathData, fill: "none", stroke: getColor(0), strokeWidth: 3, className: "transition-all" }),
967
+ points.map((point, index) => /* @__PURE__ */ jsxs("g", { children: [
968
+ /* @__PURE__ */ jsx(
969
+ "circle",
970
+ {
971
+ cx: point.x,
972
+ cy: point.y,
973
+ r: 5,
974
+ fill: getColor(index, point.color),
975
+ stroke: "hsl(var(--background))",
976
+ strokeWidth: 2,
977
+ onMouseEnter: () => showTooltips && setTooltip({ visible: true, x: point.x, y: point.y - 5, label: point.label, value: point.value }),
978
+ onMouseLeave: () => setTooltip({ visible: false, x: 0, y: 0, label: "", value: 0 }),
979
+ className: "hover:r-6 transition-all cursor-pointer"
980
+ }
981
+ ),
982
+ /* @__PURE__ */ jsx(
983
+ "text",
984
+ {
985
+ x: point.x,
986
+ y: padding.top + chartHeight + 20,
987
+ textAnchor: "middle",
988
+ className: "fill-muted-foreground text-[10px]",
989
+ children: point.label
990
+ }
991
+ )
992
+ ] }, index)),
993
+ showTooltips && renderTooltip()
994
+ ] });
995
+ };
996
+ const renderChart = () => {
997
+ switch (chartType) {
998
+ case "line":
999
+ return renderLineChart();
1000
+ case "bar":
1001
+ default:
1002
+ return renderBarChart();
1003
+ }
1004
+ };
1005
+ return /* @__PURE__ */ jsx("div", { className: cn("py-4 overflow-x-auto", className), style, children: renderChart() });
1006
+ };
1007
+ var Text = ({
1008
+ value,
1009
+ size = "md",
1010
+ weight = "normal",
1011
+ align = "start",
1012
+ className,
1013
+ style
1014
+ }) => {
1015
+ const sizeClasses = {
1016
+ xs: "text-xs",
1017
+ sm: "text-sm",
1018
+ md: "text-base",
1019
+ lg: "text-lg",
1020
+ xl: "text-xl"
1021
+ };
1022
+ const weightClasses = {
1023
+ light: "font-light",
1024
+ normal: "font-normal",
1025
+ medium: "font-medium",
1026
+ semibold: "font-semibold",
1027
+ bold: "font-bold"
1028
+ };
1029
+ const alignClasses = {
1030
+ start: "text-left",
1031
+ center: "text-center",
1032
+ end: "text-right",
1033
+ stretch: "text-justify"
1034
+ };
1035
+ return /* @__PURE__ */ jsx(
1036
+ "span",
1037
+ {
1038
+ className: cn(
1039
+ sizeClasses[size] || "text-base",
1040
+ weightClasses[weight] || "font-normal",
1041
+ alignClasses[align] || "text-left",
1042
+ className
1043
+ ),
1044
+ style,
1045
+ children: value
1046
+ }
1047
+ );
1048
+ };
1049
+ var Heading = ({
1050
+ value,
1051
+ level = 2,
1052
+ className,
1053
+ style
1054
+ }) => {
1055
+ const Tag = `h${level}`;
1056
+ const levelClasses = {
1057
+ h1: "text-3xl font-bold tracking-tight",
1058
+ h2: "text-2xl font-semibold tracking-tight",
1059
+ h3: "text-xl font-semibold tracking-tight",
1060
+ h4: "text-lg font-semibold tracking-tight",
1061
+ h5: "text-base font-semibold",
1062
+ h6: "text-sm font-semibold"
1063
+ };
1064
+ return /* @__PURE__ */ jsx(
1065
+ Tag,
1066
+ {
1067
+ className: cn(
1068
+ levelClasses[Tag] || levelClasses.h2,
1069
+ "text-foreground",
1070
+ className
1071
+ ),
1072
+ style,
1073
+ children: value
1074
+ }
1075
+ );
1076
+ };
1077
+ function Input({ className, type, ...props }) {
1078
+ return /* @__PURE__ */ jsx(
1079
+ Input$1,
1080
+ {
1081
+ type,
1082
+ "data-slot": "input",
1083
+ className: cn(
1084
+ "bg-input/30 border-input 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 h-9 rounded-4xl border px-3 py-1 text-base transition-colors file:h-7 file:text-sm file:font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
1085
+ className
1086
+ ),
1087
+ ...props
1088
+ }
1089
+ );
1090
+ }
1091
+ function Label({ className, ...props }) {
1092
+ return /* @__PURE__ */ jsx(
1093
+ "label",
1094
+ {
1095
+ "data-slot": "label",
1096
+ className: cn(
1097
+ "gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
1098
+ className
1099
+ ),
1100
+ ...props
1101
+ }
1102
+ );
1103
+ }
1104
+ var fieldVariants = cva("data-[invalid=true]:text-destructive gap-3 group/field flex w-full", {
1105
+ variants: {
1106
+ orientation: {
1107
+ vertical: "flex-col [&>*]:w-full [&>.sr-only]:w-auto",
1108
+ horizontal: "flex-row items-center [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
1109
+ responsive: "flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
1110
+ }
1111
+ },
1112
+ defaultVariants: {
1113
+ orientation: "vertical"
1114
+ }
1115
+ });
1116
+ function Field({
1117
+ className,
1118
+ orientation = "vertical",
1119
+ ...props
1120
+ }) {
1121
+ return /* @__PURE__ */ jsx(
1122
+ "div",
1123
+ {
1124
+ role: "group",
1125
+ "data-slot": "field",
1126
+ "data-orientation": orientation,
1127
+ className: cn(fieldVariants({ orientation }), className),
1128
+ ...props
1129
+ }
1130
+ );
1131
+ }
1132
+ function FieldTitle({ className, ...props }) {
1133
+ return /* @__PURE__ */ jsx(
1134
+ "div",
1135
+ {
1136
+ "data-slot": "field-label",
1137
+ className: cn(
1138
+ "gap-2 text-sm font-medium group-data-[disabled=true]/field:opacity-50 flex w-fit items-center leading-snug",
1139
+ className
1140
+ ),
1141
+ ...props
1142
+ }
1143
+ );
1144
+ }
1145
+ var Input2 = ({
1146
+ inputType = "text",
1147
+ placeholder,
1148
+ defaultValue,
1149
+ value,
1150
+ label,
1151
+ name,
1152
+ disabled,
1153
+ onChangeAction,
1154
+ className,
1155
+ style
1156
+ }) => {
1157
+ const { sendEvent } = useMelony();
1158
+ const handleChange = (e) => {
1159
+ if (onChangeAction) {
1160
+ sendEvent({
1161
+ ...onChangeAction,
1162
+ data: {
1163
+ name: name || "",
1164
+ value: e.target.value
1165
+ }
1166
+ });
1167
+ }
1168
+ };
1169
+ return /* @__PURE__ */ jsxs(Field, { className: cn("w-full", className), style, children: [
1170
+ label && /* @__PURE__ */ jsx(FieldTitle, { children: label }),
1171
+ /* @__PURE__ */ jsx(
1172
+ Input,
1173
+ {
1174
+ type: inputType,
1175
+ name,
1176
+ id: name,
1177
+ placeholder,
1178
+ defaultValue,
1179
+ value,
1180
+ disabled,
1181
+ onChange: handleChange
1182
+ }
1183
+ )
1184
+ ] });
1185
+ };
1186
+ function Textarea({ className, ...props }) {
1187
+ return /* @__PURE__ */ jsx(
1188
+ "textarea",
1189
+ {
1190
+ "data-slot": "textarea",
1191
+ className: cn(
1192
+ "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",
1193
+ className
1194
+ ),
1195
+ ...props
1196
+ }
1197
+ );
1198
+ }
1199
+ var Textarea2 = ({
1200
+ placeholder,
1201
+ defaultValue,
1202
+ value,
1203
+ label,
1204
+ name,
1205
+ disabled,
1206
+ rows,
1207
+ onChangeAction,
1208
+ className,
1209
+ style
1210
+ }) => {
1211
+ const { sendEvent } = useMelony();
1212
+ const handleChange = (e) => {
1213
+ if (onChangeAction) {
1214
+ sendEvent({
1215
+ ...onChangeAction,
1216
+ data: {
1217
+ name: name || "",
1218
+ value: e.target.value
1219
+ }
1220
+ });
1221
+ }
1222
+ };
1223
+ return /* @__PURE__ */ jsxs(Field, { className: cn("w-full", className), style, children: [
1224
+ label && /* @__PURE__ */ jsx(FieldTitle, { children: label }),
1225
+ /* @__PURE__ */ jsx(
1226
+ Textarea,
1227
+ {
1228
+ name,
1229
+ id: name,
1230
+ placeholder,
1231
+ defaultValue,
1232
+ value,
1233
+ disabled,
1234
+ rows,
1235
+ onChange: handleChange
1236
+ }
1237
+ )
1238
+ ] });
1239
+ };
1240
+ var Select = Select$1.Root;
1241
+ function SelectValue({ className, ...props }) {
1242
+ return /* @__PURE__ */ jsx(
1243
+ Select$1.Value,
1244
+ {
1245
+ "data-slot": "select-value",
1246
+ className: cn("flex flex-1 text-left", className),
1247
+ ...props
1248
+ }
1249
+ );
1250
+ }
1251
+ function SelectTrigger({
1252
+ className,
1253
+ size = "default",
1254
+ children,
1255
+ ...props
1256
+ }) {
1257
+ return /* @__PURE__ */ jsxs(
1258
+ Select$1.Trigger,
1259
+ {
1260
+ "data-slot": "select-trigger",
1261
+ "data-size": size,
1262
+ className: cn(
1263
+ "border-input data-[placeholder]:text-muted-foreground bg-input/30 dark:hover:bg-input/50 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 gap-1.5 rounded-4xl border px-3 py-2 text-sm transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:flex *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
1264
+ className
1265
+ ),
1266
+ ...props,
1267
+ children: [
1268
+ children,
1269
+ /* @__PURE__ */ jsx(
1270
+ Select$1.Icon,
1271
+ {
1272
+ render: /* @__PURE__ */ jsx(IconSelector, { className: "text-muted-foreground size-4 pointer-events-none" })
1273
+ }
1274
+ )
1275
+ ]
1276
+ }
1277
+ );
1278
+ }
1279
+ function SelectContent({
1280
+ className,
1281
+ children,
1282
+ side = "bottom",
1283
+ sideOffset = 4,
1284
+ align = "center",
1285
+ alignOffset = 0,
1286
+ alignItemWithTrigger = true,
1287
+ ...props
1288
+ }) {
1289
+ return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsx(
1290
+ Select$1.Positioner,
1291
+ {
1292
+ side,
1293
+ sideOffset,
1294
+ align,
1295
+ alignOffset,
1296
+ alignItemWithTrigger,
1297
+ className: "isolate z-50",
1298
+ children: /* @__PURE__ */ jsxs(
1299
+ Select$1.Popup,
1300
+ {
1301
+ "data-slot": "select-content",
1302
+ className: cn("bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 min-w-36 rounded-2xl shadow-2xl ring-1 duration-100 relative isolate z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto", className),
1303
+ ...props,
1304
+ children: [
1305
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
1306
+ /* @__PURE__ */ jsx(Select$1.List, { children }),
1307
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
1308
+ ]
1309
+ }
1310
+ )
1311
+ }
1312
+ ) });
1313
+ }
1314
+ function SelectItem({
1315
+ className,
1316
+ children,
1317
+ ...props
1318
+ }) {
1319
+ return /* @__PURE__ */ jsxs(
1320
+ Select$1.Item,
1321
+ {
1322
+ "data-slot": "select-item",
1323
+ className: cn(
1324
+ "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1325
+ className
1326
+ ),
1327
+ ...props,
1328
+ children: [
1329
+ /* @__PURE__ */ jsx(Select$1.ItemText, { className: "flex flex-1 gap-2 shrink-0 whitespace-nowrap", children }),
1330
+ /* @__PURE__ */ jsx(
1331
+ Select$1.ItemIndicator,
1332
+ {
1333
+ render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
1334
+ children: /* @__PURE__ */ jsx(IconCheck, { className: "pointer-events-none" })
1335
+ }
1336
+ )
1337
+ ]
1338
+ }
1339
+ );
1340
+ }
1341
+ function SelectScrollUpButton({
1342
+ className,
1343
+ ...props
1344
+ }) {
1345
+ return /* @__PURE__ */ jsx(
1346
+ Select$1.ScrollUpArrow,
1347
+ {
1348
+ "data-slot": "select-scroll-up-button",
1349
+ className: cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full", className),
1350
+ ...props,
1351
+ children: /* @__PURE__ */ jsx(
1352
+ IconChevronUp,
1353
+ {}
1354
+ )
1355
+ }
1356
+ );
1357
+ }
1358
+ function SelectScrollDownButton({
1359
+ className,
1360
+ ...props
1361
+ }) {
1362
+ return /* @__PURE__ */ jsx(
1363
+ Select$1.ScrollDownArrow,
1364
+ {
1365
+ "data-slot": "select-scroll-down-button",
1366
+ className: cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full", className),
1367
+ ...props,
1368
+ children: /* @__PURE__ */ jsx(
1369
+ IconChevronDown,
1370
+ {}
1371
+ )
1372
+ }
1373
+ );
1374
+ }
1375
+ var Select2 = ({
1376
+ options,
1377
+ defaultValue,
1378
+ value,
1379
+ label,
1380
+ name,
1381
+ disabled,
1382
+ placeholder,
1383
+ onChangeAction,
1384
+ className,
1385
+ style
1386
+ }) => {
1387
+ const { sendEvent } = useMelony();
1388
+ const handleValueChange = (val) => {
1389
+ if (onChangeAction) {
1390
+ sendEvent({
1391
+ ...onChangeAction,
1392
+ data: {
1393
+ name: name || "",
1394
+ value: val
1395
+ }
1396
+ });
1397
+ }
1398
+ };
1399
+ return /* @__PURE__ */ jsxs(Field, { className: cn("w-full", className), style, children: [
1400
+ label && /* @__PURE__ */ jsx(FieldTitle, { children: label }),
1401
+ /* @__PURE__ */ jsxs(
1402
+ Select,
1403
+ {
1404
+ defaultValue,
1405
+ value,
1406
+ disabled,
1407
+ onValueChange: handleValueChange,
1408
+ children: [
1409
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-full", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder || "Select an option" }) }),
1410
+ /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
1411
+ ]
1412
+ }
1413
+ )
1414
+ ] });
1415
+ };
1416
+ var Label2 = ({
1417
+ value,
1418
+ htmlFor,
1419
+ required,
1420
+ className,
1421
+ style
1422
+ }) => {
1423
+ return /* @__PURE__ */ jsxs(
1424
+ Label,
1425
+ {
1426
+ htmlFor,
1427
+ className: cn("flex items-center gap-1", className),
1428
+ style,
1429
+ children: [
1430
+ value,
1431
+ required && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "*" })
1432
+ ]
1433
+ }
1434
+ );
1435
+ };
1436
+ var Checkbox = ({
1437
+ label,
1438
+ name,
1439
+ value = "on",
1440
+ checked,
1441
+ defaultChecked,
1442
+ disabled,
1443
+ onChangeAction,
1444
+ className,
1445
+ style
1446
+ }) => {
1447
+ const { sendEvent } = useMelony();
1448
+ const handleChange = (e) => {
1449
+ if (onChangeAction) {
1450
+ sendEvent({
1451
+ ...onChangeAction,
1452
+ data: {
1453
+ name: name || "",
1454
+ value,
1455
+ checked: e.target.checked
1456
+ }
1457
+ });
1458
+ }
1459
+ };
1460
+ return /* @__PURE__ */ jsxs(
1461
+ "div",
1462
+ {
1463
+ className: cn("flex items-center gap-2", className),
1464
+ style,
1465
+ children: [
1466
+ /* @__PURE__ */ jsx(
1467
+ "input",
1468
+ {
1469
+ type: "checkbox",
1470
+ name,
1471
+ id: name,
1472
+ value,
1473
+ checked,
1474
+ defaultChecked,
1475
+ disabled,
1476
+ onChange: handleChange,
1477
+ className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
1478
+ }
1479
+ ),
1480
+ label && /* @__PURE__ */ jsx(
1481
+ Label2,
1482
+ {
1483
+ htmlFor: name,
1484
+ value: label,
1485
+ className: cn(
1486
+ "cursor-pointer select-none text-sm font-medium leading-none",
1487
+ disabled && "cursor-not-allowed opacity-50"
1488
+ )
1489
+ }
1490
+ )
1491
+ ]
1492
+ }
1493
+ );
1494
+ };
1495
+ var RadioGroup = ({
1496
+ name,
1497
+ options,
1498
+ defaultValue,
1499
+ value,
1500
+ label,
1501
+ disabled,
1502
+ orientation = "vertical",
1503
+ onChangeAction,
1504
+ className,
1505
+ style
1506
+ }) => {
1507
+ const { sendEvent } = useMelony();
1508
+ const handleChange = (e) => {
1509
+ if (onChangeAction) {
1510
+ sendEvent({
1511
+ ...onChangeAction,
1512
+ data: {
1513
+ name,
1514
+ value: e.target.value
1515
+ }
1516
+ });
1517
+ }
1518
+ };
1519
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-3", className), style, children: [
1520
+ label && /* @__PURE__ */ jsx(Label2, { value: label, className: "text-sm font-semibold" }),
1521
+ /* @__PURE__ */ jsx(
1522
+ "div",
1523
+ {
1524
+ className: cn(
1525
+ "flex",
1526
+ orientation === "horizontal" ? "flex-row gap-4" : "flex-col gap-2"
1527
+ ),
1528
+ children: options.map((option, index) => {
1529
+ const radioId = `${name}-${index}`;
1530
+ const isDisabled = disabled || option.disabled;
1531
+ return /* @__PURE__ */ jsxs(
1532
+ "div",
1533
+ {
1534
+ className: "flex items-center gap-2",
1535
+ children: [
1536
+ /* @__PURE__ */ jsx(
1537
+ "input",
1538
+ {
1539
+ type: "radio",
1540
+ name,
1541
+ id: radioId,
1542
+ value: option.value,
1543
+ defaultChecked: defaultValue === option.value ? true : void 0,
1544
+ checked: value === option.value,
1545
+ disabled: isDisabled,
1546
+ onChange: handleChange,
1547
+ className: "h-4 w-4 border-gray-300 text-primary focus:ring-primary disabled:cursor-not-allowed disabled:opacity-50"
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ jsx(
1551
+ Label2,
1552
+ {
1553
+ htmlFor: radioId,
1554
+ value: option.label,
1555
+ className: cn(
1556
+ "cursor-pointer select-none text-sm font-medium leading-none",
1557
+ isDisabled && "cursor-not-allowed opacity-50"
1558
+ )
1559
+ }
1560
+ )
1561
+ ]
1562
+ },
1563
+ index
1564
+ );
1565
+ })
1566
+ }
1567
+ )
1568
+ ] });
1569
+ };
1570
+ var buttonVariants = cva(
1571
+ "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",
1572
+ {
1573
+ variants: {
1574
+ variant: {
1575
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
1576
+ outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
1577
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
1578
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
1579
+ 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",
1580
+ link: "text-primary underline-offset-4 hover:underline"
1581
+ },
1582
+ size: {
1583
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
1584
+ 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",
1585
+ sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
1586
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
1587
+ icon: "size-9",
1588
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
1589
+ "icon-sm": "size-8",
1590
+ "icon-lg": "size-10"
1591
+ }
1592
+ },
1593
+ defaultVariants: {
1594
+ variant: "default",
1595
+ size: "default"
1596
+ }
1597
+ }
1598
+ );
1599
+ function Button({
1600
+ className,
1601
+ variant = "default",
1602
+ size = "default",
1603
+ ...props
1604
+ }) {
1605
+ return /* @__PURE__ */ jsx(
1606
+ Button$1,
1607
+ {
1608
+ "data-slot": "button",
1609
+ className: cn(buttonVariants({ variant, size, className })),
1610
+ ...props
1611
+ }
1612
+ );
1613
+ }
1614
+ var Button2 = ({
1615
+ label,
1616
+ variant = "primary",
1617
+ size = "default",
1618
+ disabled = false,
1619
+ fullWidth = false,
1620
+ onClickAction,
1621
+ className,
1622
+ style
1623
+ }) => {
1624
+ const { sendEvent } = useMelony();
1625
+ const variantMap = {
1626
+ primary: "default",
1627
+ secondary: "secondary",
1628
+ danger: "destructive",
1629
+ outline: "outline",
1630
+ success: "default"
1631
+ // Success doesn't have a direct shadcn mapping in base variant, default is usually primary
1632
+ };
1633
+ return /* @__PURE__ */ jsx(
1634
+ Button,
1635
+ {
1636
+ variant: variantMap[variant] || "default",
1637
+ size: size === "md" ? "default" : size,
1638
+ disabled,
1639
+ className: cn(fullWidth ? "w-full" : void 0, className),
1640
+ style,
1641
+ onClick: () => {
1642
+ if (onClickAction) {
1643
+ sendEvent(onClickAction);
1644
+ }
1645
+ },
1646
+ children: label
1647
+ }
1648
+ );
1649
+ };
1650
+ var Form = ({ children, onSubmitAction, className, style }) => {
1651
+ const { sendEvent } = useMelony();
1652
+ const [isSubmitted, setIsSubmitted] = useState(false);
1653
+ const handleSubmit = (e) => {
1654
+ e.preventDefault();
1655
+ if (isSubmitted) return;
1656
+ const formData = new FormData(e.currentTarget);
1657
+ const data = {};
1658
+ formData.forEach((value, key) => {
1659
+ data[key] = value;
1660
+ });
1661
+ if (onSubmitAction) {
1662
+ setIsSubmitted(true);
1663
+ sendEvent({
1664
+ ...onSubmitAction,
1665
+ data: {
1666
+ ...onSubmitAction.data || {},
1667
+ ...data
1668
+ }
1669
+ });
1670
+ }
1671
+ };
1672
+ return /* @__PURE__ */ jsx(
1673
+ "form",
1674
+ {
1675
+ onSubmit: handleSubmit,
1676
+ className: cn("w-full", className),
1677
+ style,
1678
+ children: /* @__PURE__ */ jsx(
1679
+ "fieldset",
1680
+ {
1681
+ disabled: isSubmitted,
1682
+ className: "m-0 border-0 p-0",
1683
+ children: /* @__PURE__ */ jsx(
1684
+ "div",
1685
+ {
1686
+ className: cn(
1687
+ "flex flex-col gap-4 transition-opacity",
1688
+ isSubmitted && "opacity-60 pointer-events-none"
1689
+ ),
1690
+ children
1691
+ }
1692
+ )
1693
+ }
1694
+ )
1695
+ }
1696
+ );
1697
+ };
1698
+ function UIRenderer({ node }) {
1699
+ const { type, props, children } = node;
1700
+ const typeMap = {
1701
+ card: Card2,
1702
+ button: Button2,
1703
+ row: Row,
1704
+ col: Col,
1705
+ text: Text,
1706
+ heading: Heading,
1707
+ badge: Badge2,
1708
+ input: Input2,
1709
+ textarea: Textarea2,
1710
+ select: Select2,
1711
+ checkbox: Checkbox,
1712
+ radioGroup: RadioGroup,
1713
+ spacer: Spacer,
1714
+ divider: Divider,
1715
+ box: Box,
1716
+ image: Image,
1717
+ icon: Icon,
1718
+ list: List,
1719
+ listItem: ListItem,
1720
+ form: Form,
1721
+ chart: Chart,
1722
+ label: Label2
1723
+ };
1724
+ const Component = typeMap[type];
1725
+ if (!Component) {
1726
+ return /* @__PURE__ */ jsxs("div", { className: "text-destructive italic text-sm p-2 border border-dashed rounded border-destructive/50 bg-destructive/5", children: [
1727
+ "[Unknown component: ",
1728
+ type,
1729
+ "]"
1730
+ ] });
1731
+ }
1732
+ const renderedChildren = children?.map((child, i) => /* @__PURE__ */ jsx(UIRenderer, { node: child }, i));
1733
+ const componentProps = { ...props };
1734
+ return /* @__PURE__ */ jsx(Component, { ...componentProps, children: renderedChildren });
1735
+ }
1736
+ function Composer({
1737
+ value,
1738
+ onChange,
1739
+ onSubmit,
1740
+ placeholder = "Type a message...",
1741
+ isLoading,
1742
+ className
1743
+ }) {
1744
+ const handleKeyDown = (e) => {
1745
+ if (e.key === "Enter" && !e.shiftKey) {
1746
+ e.preventDefault();
1747
+ onSubmit();
1748
+ }
1749
+ };
1750
+ return /* @__PURE__ */ jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
1751
+ /* @__PURE__ */ jsx(
1752
+ Textarea,
1753
+ {
1754
+ value,
1755
+ onChange: (e) => onChange(e.target.value),
1756
+ onKeyDown: handleKeyDown,
1757
+ placeholder,
1758
+ 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"
1759
+ }
1760
+ ),
1761
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end items-center px-2 pb-0.5", children: /* @__PURE__ */ jsx(
1762
+ Button,
1763
+ {
1764
+ type: "submit",
1765
+ disabled: !value.trim() && !isLoading || isLoading,
1766
+ size: "icon",
1767
+ onClick: () => onSubmit(),
1768
+ className: cn(
1769
+ "h-8 w-8 rounded-full transition-all shrink-0",
1770
+ value.trim() ? "bg-foreground text-background hover:bg-foreground/90" : "bg-muted-foreground/20 text-muted-foreground/40"
1771
+ ),
1772
+ children: /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
1773
+ }
1774
+ ) })
1775
+ ] }) });
1776
+ }
1777
+ function Thread({
1778
+ className,
1779
+ placeholder = "Type a message...",
1780
+ starterPrompts,
1781
+ onStarterPromptClick
1782
+ }) {
1783
+ const { messages, isLoading, error, sendEvent } = useMelony();
1784
+ const [input, setInput] = useState("");
1785
+ const messagesEndRef = useRef(null);
1786
+ useEffect(() => {
1787
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1788
+ }, [messages]);
1789
+ const handleSubmit = async (e, overrideInput) => {
1790
+ e?.preventDefault();
1791
+ const text = (overrideInput ?? input).trim();
1792
+ if (!text || isLoading) return;
1793
+ if (!overrideInput) setInput("");
1794
+ await sendEvent({
1795
+ type: "text",
1796
+ role: "user",
1797
+ data: { content: text }
1798
+ });
1799
+ };
1800
+ const handleStarterPromptClick = (prompt) => {
1801
+ if (onStarterPromptClick) {
1802
+ onStarterPromptClick(prompt);
1803
+ } else {
1804
+ handleSubmit(void 0, prompt);
1805
+ }
1806
+ };
1807
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full bg-background", className), children: [
1808
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
1809
+ /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto w-full", children: [
1810
+ messages.length === 0 && starterPrompts && starterPrompts.length > 0 && /* @__PURE__ */ 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: [
1811
+ /* @__PURE__ */ jsx("div", { className: "text-center space-y-2", children: /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
1812
+ /* @__PURE__ */ 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__ */ jsxs(
1813
+ "button",
1814
+ {
1815
+ onClick: () => handleStarterPromptClick(item.prompt),
1816
+ className: "flex items-center gap-3 p-4 rounded-xl border bg-card hover:bg-muted/50 transition-all text-left group",
1817
+ children: [
1818
+ item.icon && /* @__PURE__ */ jsx("div", { className: "p-2 rounded-lg bg-muted group-hover:bg-background transition-colors", children: item.icon }),
1819
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: item.label })
1820
+ ]
1821
+ },
1822
+ i
1823
+ )) })
1824
+ ] }),
1825
+ messages.map((message, i) => /* @__PURE__ */ jsx(
1826
+ "div",
1827
+ {
1828
+ className: cn(
1829
+ "flex flex-col",
1830
+ message.role === "user" ? "items-end" : "items-start"
1831
+ ),
1832
+ children: /* @__PURE__ */ jsx(
1833
+ "div",
1834
+ {
1835
+ className: cn(
1836
+ "max-w-[85%] rounded-2xl px-4 py-2 space-y-2",
1837
+ message.role === "user" ? "bg-primary text-primary-foreground" : "px-0 py-0 text-foreground"
1838
+ ),
1839
+ children: message.content.map((event, j) => {
1840
+ if (event.type === "text-delta")
1841
+ return /* @__PURE__ */ jsx("span", { children: event.data?.delta }, j);
1842
+ if (event.type === "text")
1843
+ return /* @__PURE__ */ jsx("p", { children: event.data?.content || event.data?.text }, j);
1844
+ if (event.ui) return /* @__PURE__ */ jsx(UIRenderer, { node: event.ui }, j);
1845
+ return null;
1846
+ })
1847
+ }
1848
+ )
1849
+ },
1850
+ i
1851
+ )),
1852
+ isLoading && /* @__PURE__ */ jsx("div", { className: "text-muted-foreground animate-pulse", children: "Thinking..." }),
1853
+ error && /* @__PURE__ */ jsx("div", { className: "text-destructive p-2 border border-destructive rounded-md bg-destructive/10", children: error.message })
1854
+ ] }),
1855
+ /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
1856
+ ] }),
1857
+ /* @__PURE__ */ jsx("div", { className: "p-4 border-t w-full", children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto", children: /* @__PURE__ */ jsx(
1858
+ Composer,
1859
+ {
1860
+ value: input,
1861
+ onChange: setInput,
1862
+ onSubmit: handleSubmit,
1863
+ placeholder,
1864
+ isLoading
1865
+ }
1866
+ ) }) })
1867
+ ] });
1868
+ }
1869
+ var ThreadList = ({
1870
+ className,
1871
+ emptyState,
1872
+ onThreadSelect
1873
+ }) => {
1874
+ const {
1875
+ threads,
1876
+ activeThreadId,
1877
+ selectThread,
1878
+ createThread,
1879
+ deleteThread
1880
+ } = useThreads();
1881
+ const handleThreadClick = (threadId) => {
1882
+ if (threadId !== activeThreadId) {
1883
+ selectThread(threadId);
1884
+ }
1885
+ onThreadSelect?.(threadId);
1886
+ };
1887
+ const handleDelete = async (e, threadId) => {
1888
+ e.stopPropagation();
1889
+ try {
1890
+ await deleteThread(threadId);
1891
+ } catch (error) {
1892
+ console.error("Failed to delete thread:", error);
1893
+ }
1894
+ };
1895
+ const handleNewThread = async () => {
1896
+ try {
1897
+ await createThread();
1898
+ } catch (error) {
1899
+ console.error("Failed to create thread:", error);
1900
+ }
1901
+ };
1902
+ const formatDate = (date) => {
1903
+ if (!date) return "";
1904
+ const d = typeof date === "string" ? new Date(date) : date;
1905
+ if (isNaN(d.getTime())) return "";
1906
+ const now = /* @__PURE__ */ new Date();
1907
+ const diffMs = now.getTime() - d.getTime();
1908
+ const diffMins = Math.floor(diffMs / 6e4);
1909
+ const diffHours = Math.floor(diffMs / 36e5);
1910
+ const diffDays = Math.floor(diffMs / 864e5);
1911
+ if (diffMins < 1) return "Just now";
1912
+ if (diffMins < 60) return `${diffMins}m ago`;
1913
+ if (diffHours < 24) return `${diffHours}h ago`;
1914
+ if (diffDays < 7) return `${diffDays}d ago`;
1915
+ return d.toLocaleDateString();
1916
+ };
1917
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full", className), children: [
1918
+ /* @__PURE__ */ jsx("div", { className: "p-2 border-b", children: /* @__PURE__ */ jsxs(
1919
+ Button,
1920
+ {
1921
+ variant: "outline",
1922
+ size: "sm",
1923
+ onClick: handleNewThread,
1924
+ className: "w-full justify-start",
1925
+ children: [
1926
+ /* @__PURE__ */ jsx(IconPlus, { className: "mr-2 size-4" }),
1927
+ "New Thread"
1928
+ ]
1929
+ }
1930
+ ) }),
1931
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1932
+ /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
1933
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" }),
1934
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
1935
+ ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: threads.map((thread) => {
1936
+ const isActive = thread.id === activeThreadId;
1937
+ return /* @__PURE__ */ jsxs(
1938
+ "div",
1939
+ {
1940
+ onClick: () => handleThreadClick(thread.id),
1941
+ className: cn(
1942
+ "group relative flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors",
1943
+ isActive ? "bg-primary text-primary-foreground" : "hover:bg-muted"
1944
+ ),
1945
+ children: [
1946
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
1947
+ /* @__PURE__ */ jsx(
1948
+ "p",
1949
+ {
1950
+ className: cn(
1951
+ "text-sm font-medium truncate",
1952
+ isActive && "text-primary-foreground"
1953
+ ),
1954
+ children: thread.title || `Thread ${thread.id.slice(0, 8)}`
1955
+ }
1956
+ ),
1957
+ thread.updatedAt && /* @__PURE__ */ jsx(
1958
+ "span",
1959
+ {
1960
+ className: cn(
1961
+ "text-xs shrink-0",
1962
+ isActive ? "text-primary-foreground/70" : "text-muted-foreground"
1963
+ ),
1964
+ children: formatDate(thread.updatedAt)
1965
+ }
1966
+ )
1967
+ ] }) }),
1968
+ /* @__PURE__ */ jsx(
1969
+ Button,
1970
+ {
1971
+ variant: "ghost",
1972
+ size: "icon-xs",
1973
+ onClick: (e) => handleDelete(e, thread.id),
1974
+ className: cn(
1975
+ "opacity-0 group-hover:opacity-100 transition-opacity shrink-0",
1976
+ isActive && "hover:bg-primary-foreground/20"
1977
+ ),
1978
+ children: /* @__PURE__ */ jsx(IconTrash, { className: "size-3" })
1979
+ }
1980
+ )
1981
+ ]
1982
+ },
1983
+ thread.id
1984
+ );
1985
+ }) }) })
1986
+ ] });
1987
+ };
1988
+ function ChatPopup({
1989
+ title = "Chat",
1990
+ placeholder = "Message the AI",
1991
+ starterPrompts,
1992
+ defaultOpen = false
1993
+ }) {
1994
+ const [isOpen, setIsOpen] = useState(defaultOpen);
1995
+ const [view, setView] = useState("chat");
1996
+ const { createThread } = useThreads();
1997
+ const handleNewChat = async () => {
1998
+ try {
1999
+ await createThread();
2000
+ setView("chat");
2001
+ } catch (error) {
2002
+ console.error("Failed to create new chat:", error);
2003
+ }
2004
+ };
2005
+ return /* @__PURE__ */ jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex flex-col items-end gap-4 font-sans", children: [
2006
+ isOpen && /* @__PURE__ */ 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: [
2007
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-4 border-b flex flex-row items-center justify-between space-y-0 h-14 shrink-0", children: [
2008
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2009
+ view === "history" && /* @__PURE__ */ jsx(
2010
+ Button,
2011
+ {
2012
+ variant: "ghost",
2013
+ size: "icon-xs",
2014
+ onClick: () => setView("chat"),
2015
+ className: "text-muted-foreground hover:text-foreground",
2016
+ children: /* @__PURE__ */ jsx(IconArrowLeft, { className: "size-4" })
2017
+ }
2018
+ ),
2019
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-sm font-semibold", children: view === "history" ? "History" : title })
2020
+ ] }),
2021
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2022
+ view === "chat" && /* @__PURE__ */ jsx(
2023
+ Button,
2024
+ {
2025
+ variant: "ghost",
2026
+ size: "icon-xs",
2027
+ onClick: () => setView("history"),
2028
+ className: "text-muted-foreground hover:text-foreground",
2029
+ title: "History",
2030
+ children: /* @__PURE__ */ jsx(IconHistory, { className: "size-4" })
2031
+ }
2032
+ ),
2033
+ /* @__PURE__ */ jsx(
2034
+ Button,
2035
+ {
2036
+ variant: "ghost",
2037
+ size: "icon-xs",
2038
+ onClick: handleNewChat,
2039
+ className: "text-muted-foreground hover:text-foreground",
2040
+ title: "New Chat",
2041
+ children: /* @__PURE__ */ jsx(IconPlus, { className: "size-4" })
2042
+ }
2043
+ ),
2044
+ /* @__PURE__ */ jsx(
2045
+ Button,
2046
+ {
2047
+ variant: "ghost",
2048
+ size: "icon-xs",
2049
+ onClick: () => setIsOpen(false),
2050
+ className: "text-muted-foreground hover:text-foreground",
2051
+ children: /* @__PURE__ */ jsx(IconX, { className: "size-4" })
2052
+ }
2053
+ )
2054
+ ] })
2055
+ ] }),
2056
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: view === "chat" ? /* @__PURE__ */ jsx(
2057
+ Thread,
2058
+ {
2059
+ placeholder,
2060
+ starterPrompts,
2061
+ className: "h-full"
2062
+ }
2063
+ ) : /* @__PURE__ */ jsx(
2064
+ ThreadList,
2065
+ {
2066
+ onThreadSelect: () => setView("chat"),
2067
+ className: "h-full"
2068
+ }
2069
+ ) })
2070
+ ] }),
2071
+ /* @__PURE__ */ jsx(
2072
+ Button,
2073
+ {
2074
+ size: "icon-lg",
2075
+ className: cn(
2076
+ "h-14 w-14 rounded-full shadow-2xl transition-all hover:scale-105 active:scale-95",
2077
+ isOpen ? "bg-muted text-muted-foreground hover:bg-muted/80" : "bg-primary text-primary-foreground"
2078
+ ),
2079
+ onClick: () => setIsOpen(!isOpen),
2080
+ children: isOpen ? /* @__PURE__ */ jsx(IconX, { className: "size-6" }) : /* @__PURE__ */ jsx(IconMessage, { className: "size-6" })
2081
+ }
2082
+ )
2083
+ ] });
2084
+ }
2085
+ function ChatSidebar({
2086
+ title = "Chat",
2087
+ placeholder = "Message the AI",
2088
+ starterPrompts,
2089
+ className
2090
+ }) {
2091
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2092
+ /* @__PURE__ */ jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2093
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
2094
+ Thread,
2095
+ {
2096
+ placeholder,
2097
+ starterPrompts,
2098
+ className: "h-full"
2099
+ }
2100
+ ) })
2101
+ ] });
2102
+ }
2103
+ function ChatFull({
2104
+ title = "Chat",
2105
+ placeholder = "Message the AI",
2106
+ starterPrompts,
2107
+ className
2108
+ }) {
2109
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
2110
+ title && /* @__PURE__ */ jsx("div", { className: "p-4 border-b h-14 flex items-center shrink-0", children: /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold", children: title }) }),
2111
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(Thread, { placeholder, starterPrompts }) })
2112
+ ] });
2113
+ }
2114
+ function AlertDialog({ ...props }) {
2115
+ return /* @__PURE__ */ jsx(AlertDialog$1.Root, { "data-slot": "alert-dialog", ...props });
2116
+ }
2117
+ function AlertDialogPortal({ ...props }) {
2118
+ return /* @__PURE__ */ jsx(AlertDialog$1.Portal, { "data-slot": "alert-dialog-portal", ...props });
2119
+ }
2120
+ function AlertDialogOverlay({
2121
+ className,
2122
+ ...props
2123
+ }) {
2124
+ return /* @__PURE__ */ jsx(
2125
+ AlertDialog$1.Backdrop,
2126
+ {
2127
+ "data-slot": "alert-dialog-overlay",
2128
+ className: cn(
2129
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50",
2130
+ className
2131
+ ),
2132
+ ...props
2133
+ }
2134
+ );
2135
+ }
2136
+ function AlertDialogContent({
2137
+ className,
2138
+ size = "default",
2139
+ ...props
2140
+ }) {
2141
+ return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
2142
+ /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
2143
+ /* @__PURE__ */ jsx(
2144
+ AlertDialog$1.Popup,
2145
+ {
2146
+ "data-slot": "alert-dialog-content",
2147
+ "data-size": size,
2148
+ className: cn(
2149
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/5 gap-6 rounded-4xl p-6 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none",
2150
+ className
2151
+ ),
2152
+ ...props
2153
+ }
2154
+ )
2155
+ ] });
2156
+ }
2157
+ function AlertDialogHeader({
2158
+ className,
2159
+ ...props
2160
+ }) {
2161
+ return /* @__PURE__ */ jsx(
2162
+ "div",
2163
+ {
2164
+ "data-slot": "alert-dialog-header",
2165
+ className: cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className),
2166
+ ...props
2167
+ }
2168
+ );
2169
+ }
2170
+ function AlertDialogTitle({
2171
+ className,
2172
+ ...props
2173
+ }) {
2174
+ return /* @__PURE__ */ jsx(
2175
+ AlertDialog$1.Title,
2176
+ {
2177
+ "data-slot": "alert-dialog-title",
2178
+ className: cn("text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className),
2179
+ ...props
2180
+ }
2181
+ );
2182
+ }
2183
+ function AlertDialogDescription({
2184
+ className,
2185
+ ...props
2186
+ }) {
2187
+ return /* @__PURE__ */ jsx(
2188
+ AlertDialog$1.Description,
2189
+ {
2190
+ "data-slot": "alert-dialog-description",
2191
+ className: cn("text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className),
2192
+ ...props
2193
+ }
2194
+ );
2195
+ }
2196
+ function DropdownMenu({ ...props }) {
2197
+ return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
2198
+ }
2199
+ function DropdownMenuTrigger({ ...props }) {
2200
+ return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
2201
+ }
2202
+ function DropdownMenuContent({
2203
+ align = "start",
2204
+ alignOffset = 0,
2205
+ side = "bottom",
2206
+ sideOffset = 4,
2207
+ className,
2208
+ ...props
2209
+ }) {
2210
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
2211
+ Menu.Positioner,
2212
+ {
2213
+ className: "isolate z-50 outline-none",
2214
+ align,
2215
+ alignOffset,
2216
+ side,
2217
+ sideOffset,
2218
+ children: /* @__PURE__ */ jsx(
2219
+ Menu.Popup,
2220
+ {
2221
+ "data-slot": "dropdown-menu-content",
2222
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 bg-popover text-popover-foreground min-w-48 rounded-2xl p-1 shadow-2xl ring-1 duration-100 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden", className),
2223
+ ...props
2224
+ }
2225
+ )
2226
+ }
2227
+ ) });
2228
+ }
2229
+ function DropdownMenuItem({
2230
+ className,
2231
+ inset,
2232
+ variant = "default",
2233
+ ...props
2234
+ }) {
2235
+ return /* @__PURE__ */ jsx(
2236
+ Menu.Item,
2237
+ {
2238
+ "data-slot": "dropdown-menu-item",
2239
+ "data-inset": inset,
2240
+ "data-variant": variant,
2241
+ className: cn(
2242
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
2243
+ className
2244
+ ),
2245
+ ...props
2246
+ }
2247
+ );
2248
+ }
2249
+ var AccountDialog = ({
2250
+ className,
2251
+ variant,
2252
+ size
2253
+ }) => {
2254
+ const { isLoading, isAuthenticated, login, logout } = useAuth();
2255
+ const [open, setOpen] = React9.useState(false);
2256
+ const [error, setError] = React9.useState(null);
2257
+ const handleGoogleSignIn = async () => {
2258
+ login();
2259
+ };
2260
+ if (isAuthenticated) {
2261
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2262
+ /* @__PURE__ */ jsx(
2263
+ DropdownMenuTrigger,
2264
+ {
2265
+ render: (props) => /* @__PURE__ */ jsxs(
2266
+ Button,
2267
+ {
2268
+ variant,
2269
+ size,
2270
+ ...props,
2271
+ className,
2272
+ children: [
2273
+ /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
2274
+ "Account"
2275
+ ]
2276
+ }
2277
+ )
2278
+ }
2279
+ ),
2280
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { children: [
2281
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { children: [
2282
+ /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
2283
+ "Account"
2284
+ ] }),
2285
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: logout, children: [
2286
+ /* @__PURE__ */ jsx(IconLogout, { className: "mr-2 size-4" }),
2287
+ "Logout"
2288
+ ] })
2289
+ ] })
2290
+ ] });
2291
+ }
2292
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2293
+ /* @__PURE__ */ jsxs(
2294
+ Button,
2295
+ {
2296
+ variant,
2297
+ size,
2298
+ onClick: () => setOpen(true),
2299
+ className,
2300
+ children: [
2301
+ /* @__PURE__ */ jsx(IconBrandGoogle, { className: "mr-2 size-4" }),
2302
+ "Sign in with Google"
2303
+ ]
2304
+ }
2305
+ ),
2306
+ /* @__PURE__ */ jsx(AlertDialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(AlertDialogContent, { className: "sm:max-w-md", children: [
2307
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
2308
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: "Sign in to continue" }),
2309
+ /* @__PURE__ */ jsx(AlertDialogDescription, { children: "Choose your preferred sign-in method to access your account." })
2310
+ ] }),
2311
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 py-4", children: [
2312
+ error && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-destructive/10 p-3 text-sm text-destructive", children: error }),
2313
+ /* @__PURE__ */ jsxs(
2314
+ Button,
2315
+ {
2316
+ onClick: handleGoogleSignIn,
2317
+ disabled: isLoading,
2318
+ variant: "outline",
2319
+ className: "w-full",
2320
+ size: "lg",
2321
+ children: [
2322
+ /* @__PURE__ */ jsx(IconBrandGoogle, { className: "mr-2 size-5" }),
2323
+ isLoading ? "Signing in..." : "Continue with Google"
2324
+ ]
2325
+ }
2326
+ )
2327
+ ] })
2328
+ ] }) })
2329
+ ] });
2330
+ };
2331
+
2332
+ export { AccountDialog, AuthContext, AuthProvider, ChatFull, ChatPopup, ChatSidebar, Composer, MelonyContext, MelonyProvider, Thread, ThreadContext, ThreadList, ThreadProvider, UIRenderer, useAuth, useMelony, useThreads };
2333
+ //# sourceMappingURL=index.js.map
2334
+ //# sourceMappingURL=index.js.map