@melony/react 0.1.45 → 0.1.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as React11 from 'react';
2
- import React11__default, { createContext, useContext, useRef, useEffect, useState, useCallback, useMemo } from 'react';
1
+ import * as React3 from 'react';
2
+ import React3__default, { createContext, useContext, useRef, useEffect, useState, useCallback, useMemo } from 'react';
3
3
  import { convertEventsToMessages } from 'melony';
4
4
  import { NuqsAdapter } from 'nuqs/adapters/react';
5
5
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
@@ -8,17 +8,17 @@ import { clsx } from 'clsx';
8
8
  import { twMerge } from 'tailwind-merge';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
10
  import * as ICONS from '@tabler/icons-react';
11
- import { IconX, IconChevronLeft, IconChevronRight, IconUser, IconLogout, IconBrandGoogle, IconFileText, IconFile, IconPaperclip, IconChevronDown, IconLoader2, IconArrowUp, IconDotsVertical, IconTrash, IconHistory, IconPlus, IconArrowLeft, IconMessage, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconDeviceDesktop, IconMoon, IconSun, IconSelector, IconCheck, IconChevronUp } from '@tabler/icons-react';
11
+ import { IconX, IconChevronLeft, IconChevronRight, IconLoader2, IconCheck, IconUpload, IconUser, IconLogout, IconBrandGoogle, IconFileText, IconFile, IconPaperclip, IconChevronDown, IconArrowUp, IconDotsVertical, IconTrash, IconHistory, IconPlus, IconArrowLeft, IconMessage, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconDeviceDesktop, IconMoon, IconSun, IconSelector, IconChevronUp } from '@tabler/icons-react';
12
12
  import { Separator as Separator$1 } from '@base-ui/react/separator';
13
13
  import { mergeProps } from '@base-ui/react/merge-props';
14
14
  import { useRender } from '@base-ui/react/use-render';
15
15
  import { cva } from 'class-variance-authority';
16
16
  import { Input as Input$1 } from '@base-ui/react/input';
17
17
  import { Select as Select$1 } from '@base-ui/react/select';
18
+ import { createPortal } from 'react-dom';
18
19
  import { Button as Button$1 } from '@base-ui/react/button';
19
20
  import { Menu } from '@base-ui/react/menu';
20
21
  import { useQueryState, parseAsString } from 'nuqs';
21
- import { createPortal } from 'react-dom';
22
22
  import { useHotkeys } from 'react-hotkeys-hook';
23
23
 
24
24
  // src/providers/melony-provider.tsx
@@ -534,7 +534,6 @@ var Image = ({
534
534
  src,
535
535
  alt,
536
536
  size = "sm",
537
- groupId,
538
537
  className,
539
538
  style
540
539
  }) => {
@@ -1423,6 +1422,324 @@ var Checkbox = ({
1423
1422
  )
1424
1423
  ] });
1425
1424
  };
1425
+ var Hidden = ({ name, value }) => {
1426
+ return /* @__PURE__ */ jsx("input", { type: "hidden", name, value });
1427
+ };
1428
+ var PopoverContext = React3.createContext(
1429
+ void 0
1430
+ );
1431
+ function usePopoverContext() {
1432
+ const context = React3.useContext(PopoverContext);
1433
+ if (!context) {
1434
+ throw new Error("Popover components must be used within a Popover");
1435
+ }
1436
+ return context;
1437
+ }
1438
+ function Popover({
1439
+ children,
1440
+ defaultOpen = false,
1441
+ open: controlledOpen,
1442
+ onOpenChange
1443
+ }) {
1444
+ const [internalOpen, setInternalOpen] = React3.useState(defaultOpen);
1445
+ const triggerRef = React3.useRef(null);
1446
+ const open = controlledOpen ?? internalOpen;
1447
+ const setOpen = React3.useCallback(
1448
+ (newOpen) => {
1449
+ if (controlledOpen === void 0) {
1450
+ setInternalOpen(newOpen);
1451
+ }
1452
+ onOpenChange?.(newOpen);
1453
+ },
1454
+ [controlledOpen, onOpenChange]
1455
+ );
1456
+ const value = React3.useMemo(
1457
+ () => ({
1458
+ open,
1459
+ setOpen,
1460
+ triggerRef
1461
+ }),
1462
+ [open, setOpen]
1463
+ );
1464
+ return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
1465
+ }
1466
+ var PopoverTrigger = React3.forwardRef(
1467
+ ({ asChild, className, children, ...props }, ref) => {
1468
+ const { setOpen, triggerRef } = usePopoverContext();
1469
+ const handleClick = (e) => {
1470
+ setOpen(true);
1471
+ props.onClick?.(e);
1472
+ };
1473
+ if (asChild && React3.isValidElement(children)) {
1474
+ return React3.cloneElement(children, {
1475
+ ref: (node) => {
1476
+ triggerRef.current = node;
1477
+ if (typeof children.ref === "function") {
1478
+ children.ref(node);
1479
+ } else if (children.ref) {
1480
+ children.ref.current = node;
1481
+ }
1482
+ },
1483
+ onClick: handleClick
1484
+ });
1485
+ }
1486
+ return /* @__PURE__ */ jsx(
1487
+ "button",
1488
+ {
1489
+ ref: (node) => {
1490
+ triggerRef.current = node;
1491
+ if (typeof ref === "function") {
1492
+ ref(node);
1493
+ } else if (ref) {
1494
+ ref.current = node;
1495
+ }
1496
+ },
1497
+ className,
1498
+ onClick: handleClick,
1499
+ ...props,
1500
+ children
1501
+ }
1502
+ );
1503
+ }
1504
+ );
1505
+ PopoverTrigger.displayName = "PopoverTrigger";
1506
+ var PopoverContent = React3.forwardRef(
1507
+ ({
1508
+ className,
1509
+ side = "bottom",
1510
+ align = "start",
1511
+ sideOffset = 4,
1512
+ alignOffset = 0,
1513
+ children,
1514
+ ...props
1515
+ }, ref) => {
1516
+ const { open, setOpen, triggerRef } = usePopoverContext();
1517
+ const [position, setPosition] = React3.useState({ top: 0, left: 0 });
1518
+ const contentRef = React3.useRef(null);
1519
+ React3.useEffect(() => {
1520
+ if (!open || !triggerRef.current) return;
1521
+ const updatePosition = () => {
1522
+ if (!triggerRef.current || !contentRef.current) return;
1523
+ const triggerRect = triggerRef.current.getBoundingClientRect();
1524
+ const contentRect = contentRef.current.getBoundingClientRect();
1525
+ const scrollX = window.scrollX;
1526
+ const scrollY = window.scrollY;
1527
+ let top = 0;
1528
+ let left = 0;
1529
+ switch (side) {
1530
+ case "bottom":
1531
+ top = triggerRect.bottom + sideOffset + scrollY;
1532
+ break;
1533
+ case "top":
1534
+ top = triggerRect.top - contentRect.height - sideOffset + scrollY;
1535
+ break;
1536
+ case "right":
1537
+ top = triggerRect.top + scrollY;
1538
+ left = triggerRect.right + sideOffset + scrollX;
1539
+ break;
1540
+ case "left":
1541
+ top = triggerRect.top + scrollY;
1542
+ left = triggerRect.left - contentRect.width - sideOffset + scrollX;
1543
+ break;
1544
+ }
1545
+ switch (align) {
1546
+ case "start":
1547
+ if (side === "top" || side === "bottom") {
1548
+ left = triggerRect.left + scrollX + alignOffset;
1549
+ } else {
1550
+ top += alignOffset;
1551
+ }
1552
+ break;
1553
+ case "center":
1554
+ if (side === "top" || side === "bottom") {
1555
+ left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2 + scrollX + alignOffset;
1556
+ } else {
1557
+ top += triggerRect.height / 2 - contentRect.height / 2 + alignOffset;
1558
+ }
1559
+ break;
1560
+ case "end":
1561
+ if (side === "top" || side === "bottom") {
1562
+ left = triggerRect.left + triggerRect.width - contentRect.width + scrollX + alignOffset;
1563
+ } else {
1564
+ top += triggerRect.height - contentRect.height + alignOffset;
1565
+ }
1566
+ break;
1567
+ }
1568
+ setPosition({ top, left });
1569
+ };
1570
+ requestAnimationFrame(() => {
1571
+ updatePosition();
1572
+ });
1573
+ window.addEventListener("resize", updatePosition);
1574
+ window.addEventListener("scroll", updatePosition, true);
1575
+ return () => {
1576
+ window.removeEventListener("resize", updatePosition);
1577
+ window.removeEventListener("scroll", updatePosition, true);
1578
+ };
1579
+ }, [open, side, align, sideOffset, alignOffset, triggerRef]);
1580
+ React3.useEffect(() => {
1581
+ if (!open) return;
1582
+ const handleClickOutside = (event) => {
1583
+ if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
1584
+ setOpen(false);
1585
+ }
1586
+ };
1587
+ const handleEscape = (event) => {
1588
+ if (event.key === "Escape") {
1589
+ setOpen(false);
1590
+ }
1591
+ };
1592
+ document.addEventListener("mousedown", handleClickOutside);
1593
+ document.addEventListener("keydown", handleEscape);
1594
+ return () => {
1595
+ document.removeEventListener("mousedown", handleClickOutside);
1596
+ document.removeEventListener("keydown", handleEscape);
1597
+ };
1598
+ }, [open, setOpen, triggerRef]);
1599
+ if (!open) return null;
1600
+ const content = /* @__PURE__ */ jsx(
1601
+ "div",
1602
+ {
1603
+ ref: (node) => {
1604
+ contentRef.current = node;
1605
+ if (typeof ref === "function") {
1606
+ ref(node);
1607
+ } else if (ref) {
1608
+ ref.current = node;
1609
+ }
1610
+ },
1611
+ className: cn(
1612
+ "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 ring-foreground/5 rounded-2xl shadow-2xl ring-1 z-50 min-w-48 max-h-96 overflow-hidden",
1613
+ className
1614
+ ),
1615
+ style: {
1616
+ position: "absolute",
1617
+ top: `${position.top}px`,
1618
+ left: `${position.left}px`
1619
+ },
1620
+ ...props,
1621
+ children
1622
+ }
1623
+ );
1624
+ return createPortal(content, document.body);
1625
+ }
1626
+ );
1627
+ PopoverContent.displayName = "PopoverContent";
1628
+ var PRESET_COLORS = [
1629
+ "#000000",
1630
+ "#ffffff",
1631
+ "#f44336",
1632
+ "#e91e63",
1633
+ "#9c27b0",
1634
+ "#673ab7",
1635
+ "#3f51b5",
1636
+ "#2196f3",
1637
+ "#03a9f4",
1638
+ "#00bcd4",
1639
+ "#009688",
1640
+ "#4caf50",
1641
+ "#8bc34a",
1642
+ "#cddc39",
1643
+ "#ffeb3b",
1644
+ "#ffc107",
1645
+ "#ff9800",
1646
+ "#ff5722",
1647
+ "#795548",
1648
+ "#9e9e9e",
1649
+ "#607d8b"
1650
+ ];
1651
+ var ColorPicker = ({
1652
+ name,
1653
+ label,
1654
+ defaultValue = "#000000",
1655
+ value: controlledValue,
1656
+ onChangeAction,
1657
+ disabled,
1658
+ className,
1659
+ style
1660
+ }) => {
1661
+ const { sendEvent } = useMelony();
1662
+ const [color, setColor] = useState(controlledValue || defaultValue);
1663
+ useEffect(() => {
1664
+ if (controlledValue !== void 0) {
1665
+ setColor(controlledValue);
1666
+ }
1667
+ }, [controlledValue]);
1668
+ const handleColorChange = (newColor) => {
1669
+ setColor(newColor);
1670
+ if (onChangeAction) {
1671
+ sendEvent({
1672
+ ...onChangeAction,
1673
+ data: {
1674
+ name: name || "",
1675
+ value: newColor
1676
+ }
1677
+ });
1678
+ }
1679
+ };
1680
+ return /* @__PURE__ */ jsxs(Field, { className: cn("w-full", className), style, children: [
1681
+ label && /* @__PURE__ */ jsx(FieldTitle, { children: label }),
1682
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1683
+ /* @__PURE__ */ jsxs(Popover, { children: [
1684
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1685
+ "button",
1686
+ {
1687
+ type: "button",
1688
+ disabled,
1689
+ className: cn(
1690
+ "w-10 h-10 rounded-lg border border-border shadow-sm transition-transform hover:scale-105 active:scale-95 disabled:opacity-50 disabled:hover:scale-100",
1691
+ "flex items-center justify-center p-1"
1692
+ ),
1693
+ children: /* @__PURE__ */ jsx(
1694
+ "div",
1695
+ {
1696
+ className: "w-full h-full rounded-md",
1697
+ style: { backgroundColor: color }
1698
+ }
1699
+ )
1700
+ }
1701
+ ) }),
1702
+ /* @__PURE__ */ jsx(PopoverContent, { className: "p-3 w-64", side: "bottom", align: "start", children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1703
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 gap-1", children: PRESET_COLORS.map((preset) => /* @__PURE__ */ jsx(
1704
+ "button",
1705
+ {
1706
+ type: "button",
1707
+ className: cn(
1708
+ "w-6 h-6 rounded-md border border-border transition-transform hover:scale-110 active:scale-90",
1709
+ color === preset && "ring-2 ring-primary ring-offset-1"
1710
+ ),
1711
+ style: { backgroundColor: preset },
1712
+ onClick: () => handleColorChange(preset)
1713
+ },
1714
+ preset
1715
+ )) }),
1716
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1717
+ /* @__PURE__ */ jsx(
1718
+ "input",
1719
+ {
1720
+ type: "color",
1721
+ value: color,
1722
+ onChange: (e) => handleColorChange(e.target.value),
1723
+ className: "w-8 h-8 rounded border-none p-0 cursor-pointer"
1724
+ }
1725
+ ),
1726
+ /* @__PURE__ */ jsx(
1727
+ "input",
1728
+ {
1729
+ type: "text",
1730
+ value: color,
1731
+ onChange: (e) => handleColorChange(e.target.value),
1732
+ className: "flex-1 h-8 px-2 text-xs font-mono border border-border rounded uppercase focus:outline-none focus:ring-1 focus:ring-primary"
1733
+ }
1734
+ )
1735
+ ] })
1736
+ ] }) })
1737
+ ] }),
1738
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-mono uppercase text-muted-foreground", children: color })
1739
+ ] }),
1740
+ /* @__PURE__ */ jsx("input", { type: "hidden", name, value: color })
1741
+ ] });
1742
+ };
1426
1743
  var RadioGroup = ({
1427
1744
  name,
1428
1745
  options,
@@ -1582,6 +1899,119 @@ var Button2 = ({
1582
1899
  }
1583
1900
  );
1584
1901
  };
1902
+ var Upload = ({
1903
+ label = "Upload",
1904
+ multiple = false,
1905
+ accept,
1906
+ onUploadAction,
1907
+ className,
1908
+ style,
1909
+ initialFiles,
1910
+ mode = "append"
1911
+ }) => {
1912
+ const { sendEvent, events } = useMelony();
1913
+ const fileInputRef = useRef(null);
1914
+ const [isUploading, setIsUploading] = useState(false);
1915
+ const [status, setStatus] = useState("idle");
1916
+ const uploadedFilesEvents = events.filter(
1917
+ (event) => event.type === "uploaded-files"
1918
+ );
1919
+ const displayEvents = mode === "replace" && uploadedFilesEvents.length > 0 ? [uploadedFilesEvents[uploadedFilesEvents.length - 1]] : uploadedFilesEvents;
1920
+ const showInitialFiles = mode === "replace" ? displayEvents.length === 0 : true;
1921
+ const handleFileChange = async (e) => {
1922
+ const files = Array.from(e.target.files || []);
1923
+ if (files.length === 0) return;
1924
+ setIsUploading(true);
1925
+ setStatus("idle");
1926
+ try {
1927
+ const filePromises = files.map((file) => {
1928
+ return new Promise((resolve, reject) => {
1929
+ const reader = new FileReader();
1930
+ reader.onload = () => {
1931
+ try {
1932
+ const base64 = reader.result;
1933
+ if (!base64) {
1934
+ reject(new Error("FileReader returned empty result"));
1935
+ return;
1936
+ }
1937
+ resolve({
1938
+ name: file.name,
1939
+ type: file.type,
1940
+ size: file.size,
1941
+ data: base64
1942
+ });
1943
+ } catch (error) {
1944
+ reject(error);
1945
+ }
1946
+ };
1947
+ reader.onerror = (error) => {
1948
+ reject(new Error(`Failed to read file ${file.name}: ${error}`));
1949
+ };
1950
+ reader.readAsDataURL(file);
1951
+ });
1952
+ });
1953
+ const convertedFiles = await Promise.all(filePromises);
1954
+ if (onUploadAction) {
1955
+ if (typeof onUploadAction === "function") {
1956
+ await sendEvent(onUploadAction({ files: convertedFiles }));
1957
+ } else {
1958
+ await sendEvent({
1959
+ ...onUploadAction,
1960
+ data: {
1961
+ ...onUploadAction.data,
1962
+ files: convertedFiles
1963
+ }
1964
+ });
1965
+ }
1966
+ }
1967
+ setStatus("success");
1968
+ setTimeout(() => setStatus("idle"), 3e3);
1969
+ } catch (error) {
1970
+ console.error("Upload failed:", error);
1971
+ setStatus("error");
1972
+ setTimeout(() => setStatus("idle"), 3e3);
1973
+ } finally {
1974
+ setIsUploading(false);
1975
+ if (fileInputRef.current) {
1976
+ fileInputRef.current.value = "";
1977
+ }
1978
+ }
1979
+ };
1980
+ return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-block", className), style, children: [
1981
+ /* @__PURE__ */ jsx(
1982
+ "input",
1983
+ {
1984
+ type: "file",
1985
+ ref: fileInputRef,
1986
+ onChange: handleFileChange,
1987
+ multiple,
1988
+ accept,
1989
+ className: "hidden",
1990
+ disabled: isUploading
1991
+ }
1992
+ ),
1993
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2 mb-2 items-center", children: [
1994
+ showInitialFiles && initialFiles?.map((file, index) => /* @__PURE__ */ jsx(Image, { src: file.url, alt: file.name, size: "md" }, index)),
1995
+ displayEvents.map(
1996
+ (event, index) => event.ui ? /* @__PURE__ */ jsx(UIRenderer, { node: event.ui }, index) : null
1997
+ ),
1998
+ /* @__PURE__ */ jsxs(
1999
+ Button,
2000
+ {
2001
+ type: "button",
2002
+ disabled: isUploading,
2003
+ onClick: () => fileInputRef.current?.click(),
2004
+ className: "gap-2",
2005
+ variant: status === "error" ? "destructive" : status === "success" ? "outline" : "default",
2006
+ children: [
2007
+ isUploading ? /* @__PURE__ */ jsx(IconLoader2, { className: "h-4 w-4 animate-spin" }) : status === "success" ? /* @__PURE__ */ jsx(IconCheck, { className: "h-4 w-4 text-green-500" }) : status === "error" ? /* @__PURE__ */ jsx(IconX, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(IconUpload, { className: "h-4 w-4" }),
2008
+ status === "success" ? "Uploaded" : status === "error" ? "Failed" : label
2009
+ ]
2010
+ }
2011
+ )
2012
+ ] })
2013
+ ] });
2014
+ };
1585
2015
  var Form = ({
1586
2016
  children,
1587
2017
  onSubmitAction,
@@ -1643,10 +2073,12 @@ function UIRenderer({ node }) {
1643
2073
  heading: Heading,
1644
2074
  badge: Badge2,
1645
2075
  input: Input2,
2076
+ hidden: Hidden,
1646
2077
  textarea: Textarea2,
1647
2078
  select: Select2,
1648
2079
  checkbox: Checkbox,
1649
2080
  radioGroup: RadioGroup,
2081
+ colorPicker: ColorPicker,
1650
2082
  spacer: Spacer,
1651
2083
  divider: Divider,
1652
2084
  box: Box,
@@ -1656,7 +2088,8 @@ function UIRenderer({ node }) {
1656
2088
  listItem: ListItem,
1657
2089
  form: Form,
1658
2090
  chart: Chart,
1659
- label: Label2
2091
+ label: Label2,
2092
+ upload: Upload
1660
2093
  };
1661
2094
  const Component = typeMap[type];
1662
2095
  if (!Component) {
@@ -1963,10 +2396,10 @@ var AccountButton = ({
1963
2396
  size
1964
2397
  }) => {
1965
2398
  const { isLoading, isAuthenticated, user, login, logout } = useAuth();
1966
- const [open, setOpen] = React11.useState(false);
1967
- const [accountInfoOpen, setAccountInfoOpen] = React11.useState(false);
1968
- const [error, setError] = React11.useState(null);
1969
- const initials = React11.useMemo(() => {
2399
+ const [open, setOpen] = React3.useState(false);
2400
+ const [accountInfoOpen, setAccountInfoOpen] = React3.useState(false);
2401
+ const [error, setError] = React3.useState(null);
2402
+ const initials = React3.useMemo(() => {
1970
2403
  const name = user?.displayName || user?.name;
1971
2404
  if (!name) return "";
1972
2405
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
@@ -2542,13 +2975,13 @@ function Composer({
2542
2975
  const accept = fileAttachments?.accept;
2543
2976
  const maxFiles = fileAttachments?.maxFiles ?? 10;
2544
2977
  const maxFileSize = fileAttachments?.maxFileSize ?? 10 * 1024 * 1024;
2545
- const [selectedOptions, setSelectedOptions] = React11__default.useState(
2978
+ const [selectedOptions, setSelectedOptions] = React3__default.useState(
2546
2979
  () => new Set(defaultSelectedIds)
2547
2980
  );
2548
- const [attachedFiles, setAttachedFiles] = React11__default.useState([]);
2549
- const [previews, setPreviews] = React11__default.useState([]);
2550
- const fileInputRef = React11__default.useRef(null);
2551
- React11__default.useEffect(() => {
2981
+ const [attachedFiles, setAttachedFiles] = React3__default.useState([]);
2982
+ const [previews, setPreviews] = React3__default.useState([]);
2983
+ const fileInputRef = React3__default.useRef(null);
2984
+ React3__default.useEffect(() => {
2552
2985
  const newPreviews = attachedFiles.map((file) => ({
2553
2986
  name: file.name,
2554
2987
  type: file.type,
@@ -2831,7 +3264,7 @@ function StarterPrompts({
2831
3264
  }
2832
3265
  return /* @__PURE__ */ 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: [
2833
3266
  /* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight", children: "What can I help with today?" }) }),
2834
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 w-full", children: prompts.map((item, index) => /* @__PURE__ */ jsx(
3267
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 w-full", children: prompts.map((item, index) => /* @__PURE__ */ jsx(
2835
3268
  Button2,
2836
3269
  {
2837
3270
  label: item.label,
@@ -3119,7 +3552,7 @@ var Dropdown = ({
3119
3552
  };
3120
3553
  var ThreadList = ({ className }) => {
3121
3554
  const { threads, activeThreadId, deleteThread } = useThreads();
3122
- const sortedThreads = React11.useMemo(() => {
3555
+ const sortedThreads = React3.useMemo(() => {
3123
3556
  return [...threads].sort((a, b) => {
3124
3557
  const dateA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
3125
3558
  const dateB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
@@ -3280,7 +3713,7 @@ function Sidebar({ side, children, className }) {
3280
3713
  collapsed ? "w-0 border-r-0 border-l-0 min-w-0" : "",
3281
3714
  !collapsed && className
3282
3715
  ),
3283
- children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children })
3716
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0 flex flex-col", children })
3284
3717
  }
3285
3718
  );
3286
3719
  }
@@ -3347,206 +3780,6 @@ function SidebarToggle({ side, className }) {
3347
3780
  }
3348
3781
  return null;
3349
3782
  }
3350
- var PopoverContext = React11.createContext(
3351
- void 0
3352
- );
3353
- function usePopoverContext() {
3354
- const context = React11.useContext(PopoverContext);
3355
- if (!context) {
3356
- throw new Error("Popover components must be used within a Popover");
3357
- }
3358
- return context;
3359
- }
3360
- function Popover({
3361
- children,
3362
- defaultOpen = false,
3363
- open: controlledOpen,
3364
- onOpenChange
3365
- }) {
3366
- const [internalOpen, setInternalOpen] = React11.useState(defaultOpen);
3367
- const triggerRef = React11.useRef(null);
3368
- const open = controlledOpen ?? internalOpen;
3369
- const setOpen = React11.useCallback(
3370
- (newOpen) => {
3371
- if (controlledOpen === void 0) {
3372
- setInternalOpen(newOpen);
3373
- }
3374
- onOpenChange?.(newOpen);
3375
- },
3376
- [controlledOpen, onOpenChange]
3377
- );
3378
- const value = React11.useMemo(
3379
- () => ({
3380
- open,
3381
- setOpen,
3382
- triggerRef
3383
- }),
3384
- [open, setOpen]
3385
- );
3386
- return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
3387
- }
3388
- var PopoverTrigger = React11.forwardRef(
3389
- ({ asChild, className, children, ...props }, ref) => {
3390
- const { setOpen, triggerRef } = usePopoverContext();
3391
- const handleClick = (e) => {
3392
- setOpen(true);
3393
- props.onClick?.(e);
3394
- };
3395
- if (asChild && React11.isValidElement(children)) {
3396
- return React11.cloneElement(children, {
3397
- ref: (node) => {
3398
- triggerRef.current = node;
3399
- if (typeof children.ref === "function") {
3400
- children.ref(node);
3401
- } else if (children.ref) {
3402
- children.ref.current = node;
3403
- }
3404
- },
3405
- onClick: handleClick
3406
- });
3407
- }
3408
- return /* @__PURE__ */ jsx(
3409
- "button",
3410
- {
3411
- ref: (node) => {
3412
- triggerRef.current = node;
3413
- if (typeof ref === "function") {
3414
- ref(node);
3415
- } else if (ref) {
3416
- ref.current = node;
3417
- }
3418
- },
3419
- className,
3420
- onClick: handleClick,
3421
- ...props,
3422
- children
3423
- }
3424
- );
3425
- }
3426
- );
3427
- PopoverTrigger.displayName = "PopoverTrigger";
3428
- var PopoverContent = React11.forwardRef(
3429
- ({
3430
- className,
3431
- side = "bottom",
3432
- align = "start",
3433
- sideOffset = 4,
3434
- alignOffset = 0,
3435
- children,
3436
- ...props
3437
- }, ref) => {
3438
- const { open, setOpen, triggerRef } = usePopoverContext();
3439
- const [position, setPosition] = React11.useState({ top: 0, left: 0 });
3440
- const contentRef = React11.useRef(null);
3441
- React11.useEffect(() => {
3442
- if (!open || !triggerRef.current) return;
3443
- const updatePosition = () => {
3444
- if (!triggerRef.current || !contentRef.current) return;
3445
- const triggerRect = triggerRef.current.getBoundingClientRect();
3446
- const contentRect = contentRef.current.getBoundingClientRect();
3447
- const scrollX = window.scrollX;
3448
- const scrollY = window.scrollY;
3449
- let top = 0;
3450
- let left = 0;
3451
- switch (side) {
3452
- case "bottom":
3453
- top = triggerRect.bottom + sideOffset + scrollY;
3454
- break;
3455
- case "top":
3456
- top = triggerRect.top - contentRect.height - sideOffset + scrollY;
3457
- break;
3458
- case "right":
3459
- top = triggerRect.top + scrollY;
3460
- left = triggerRect.right + sideOffset + scrollX;
3461
- break;
3462
- case "left":
3463
- top = triggerRect.top + scrollY;
3464
- left = triggerRect.left - contentRect.width - sideOffset + scrollX;
3465
- break;
3466
- }
3467
- switch (align) {
3468
- case "start":
3469
- if (side === "top" || side === "bottom") {
3470
- left = triggerRect.left + scrollX + alignOffset;
3471
- } else {
3472
- top += alignOffset;
3473
- }
3474
- break;
3475
- case "center":
3476
- if (side === "top" || side === "bottom") {
3477
- left = triggerRect.left + triggerRect.width / 2 - contentRect.width / 2 + scrollX + alignOffset;
3478
- } else {
3479
- top += triggerRect.height / 2 - contentRect.height / 2 + alignOffset;
3480
- }
3481
- break;
3482
- case "end":
3483
- if (side === "top" || side === "bottom") {
3484
- left = triggerRect.left + triggerRect.width - contentRect.width + scrollX + alignOffset;
3485
- } else {
3486
- top += triggerRect.height - contentRect.height + alignOffset;
3487
- }
3488
- break;
3489
- }
3490
- setPosition({ top, left });
3491
- };
3492
- requestAnimationFrame(() => {
3493
- updatePosition();
3494
- });
3495
- window.addEventListener("resize", updatePosition);
3496
- window.addEventListener("scroll", updatePosition, true);
3497
- return () => {
3498
- window.removeEventListener("resize", updatePosition);
3499
- window.removeEventListener("scroll", updatePosition, true);
3500
- };
3501
- }, [open, side, align, sideOffset, alignOffset, triggerRef]);
3502
- React11.useEffect(() => {
3503
- if (!open) return;
3504
- const handleClickOutside = (event) => {
3505
- if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
3506
- setOpen(false);
3507
- }
3508
- };
3509
- const handleEscape = (event) => {
3510
- if (event.key === "Escape") {
3511
- setOpen(false);
3512
- }
3513
- };
3514
- document.addEventListener("mousedown", handleClickOutside);
3515
- document.addEventListener("keydown", handleEscape);
3516
- return () => {
3517
- document.removeEventListener("mousedown", handleClickOutside);
3518
- document.removeEventListener("keydown", handleEscape);
3519
- };
3520
- }, [open, setOpen, triggerRef]);
3521
- if (!open) return null;
3522
- const content = /* @__PURE__ */ jsx(
3523
- "div",
3524
- {
3525
- ref: (node) => {
3526
- contentRef.current = node;
3527
- if (typeof ref === "function") {
3528
- ref(node);
3529
- } else if (ref) {
3530
- ref.current = node;
3531
- }
3532
- },
3533
- className: cn(
3534
- "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 ring-foreground/5 rounded-2xl shadow-2xl ring-1 z-50 min-w-48 max-h-96 overflow-hidden",
3535
- className
3536
- ),
3537
- style: {
3538
- position: "absolute",
3539
- top: `${position.top}px`,
3540
- left: `${position.left}px`
3541
- },
3542
- ...props,
3543
- children
3544
- }
3545
- );
3546
- return createPortal(content, document.body);
3547
- }
3548
- );
3549
- PopoverContent.displayName = "PopoverContent";
3550
3783
  var ThreadPopover = ({
3551
3784
  className,
3552
3785
  buttonClassName,
@@ -3554,7 +3787,7 @@ var ThreadPopover = ({
3554
3787
  buttonSize = "icon",
3555
3788
  emptyState
3556
3789
  }) => {
3557
- const [isOpen, setIsOpen] = React11.useState(false);
3790
+ const [isOpen, setIsOpen] = React3.useState(false);
3558
3791
  useHotkeys(
3559
3792
  "h",
3560
3793
  (e) => {
@@ -3597,7 +3830,7 @@ var CreateThreadButton = ({
3597
3830
  onThreadCreated
3598
3831
  }) => {
3599
3832
  const { createThread } = useThreads();
3600
- const [isCreating, setIsCreating] = React11.useState(false);
3833
+ const [isCreating, setIsCreating] = React3.useState(false);
3601
3834
  const handleCreateThread = async () => {
3602
3835
  if (isCreating) return;
3603
3836
  try {
@@ -3679,7 +3912,7 @@ var CreateThreadListItem = ({
3679
3912
  className
3680
3913
  }) => {
3681
3914
  const { createThread } = useThreads();
3682
- const [isCreating, setIsCreating] = React11.useState(false);
3915
+ const [isCreating, setIsCreating] = React3.useState(false);
3683
3916
  const handleCreateThread = async () => {
3684
3917
  if (isCreating) return;
3685
3918
  try {
@@ -3722,6 +3955,6 @@ var CreateThreadListItem = ({
3722
3955
  );
3723
3956
  };
3724
3957
 
3725
- export { AccountButton, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatHeader, Checkbox, Col, Composer, CreateThreadButton, CreateThreadListItem, Divider, Dropdown, Form, FullChat, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyContext, MelonyProvider, PopupChat, RadioGroup, Row, Select2 as Select, Sidebar, SidebarContext, SidebarProvider, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, WelcomeScreen, useAuth, useMelony, useScreenSize, useSidebar, useTheme, useThreads };
3958
+ export { AccountButton, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatHeader, Checkbox, Col, Composer, CreateThreadButton, CreateThreadListItem, Divider, Dropdown, Form, FullChat, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyContext, MelonyProvider, PopupChat, RadioGroup, Row, Select2 as Select, Sidebar, SidebarContext, SidebarProvider, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, Upload, WelcomeScreen, useAuth, useMelony, useScreenSize, useSidebar, useTheme, useThreads };
3726
3959
  //# sourceMappingURL=index.js.map
3727
3960
  //# sourceMappingURL=index.js.map