@mieweb/ui 0.9.0-dev.5 → 0.9.0-dev.6

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.
Files changed (33) hide show
  1. package/dist/{chunk-QWJGEDHV.js → chunk-22CYDCXA.js} +13 -1183
  2. package/dist/chunk-22CYDCXA.js.map +1 -0
  3. package/dist/chunk-3SD7PDCV.js +1878 -0
  4. package/dist/chunk-3SD7PDCV.js.map +1 -0
  5. package/dist/{chunk-PL6TFCYR.js → chunk-NORSXAXL.js} +374 -300
  6. package/dist/chunk-NORSXAXL.js.map +1 -0
  7. package/dist/chunk-T6PTKWM6.cjs +1912 -0
  8. package/dist/chunk-T6PTKWM6.cjs.map +1 -0
  9. package/dist/{chunk-XJUIZA4G.cjs → chunk-WIAQQNFU.cjs} +12 -1184
  10. package/dist/chunk-WIAQQNFU.cjs.map +1 -0
  11. package/dist/{chunk-ZXRVVNT5.cjs → chunk-XCNDZNY7.cjs} +384 -309
  12. package/dist/chunk-XCNDZNY7.cjs.map +1 -0
  13. package/dist/components/SuperChat/index.cjs +8 -8
  14. package/dist/components/SuperChat/index.js +2 -2
  15. package/dist/components/SuperChat/plugins/index.cjs +10 -3
  16. package/dist/components/SuperChat/plugins/index.cjs.map +1 -1
  17. package/dist/components/SuperChat/plugins/index.js +9 -2
  18. package/dist/components/SuperChat/plugins/index.js.map +1 -1
  19. package/dist/index.cjs +92 -120
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +38 -4
  22. package/dist/index.d.ts +38 -4
  23. package/dist/index.js +17 -48
  24. package/dist/index.js.map +1 -1
  25. package/package.json +1 -1
  26. package/dist/chunk-H3GRO43Z.cjs +0 -735
  27. package/dist/chunk-H3GRO43Z.cjs.map +0 -1
  28. package/dist/chunk-MD3ZY4UO.js +0 -705
  29. package/dist/chunk-MD3ZY4UO.js.map +0 -1
  30. package/dist/chunk-PL6TFCYR.js.map +0 -1
  31. package/dist/chunk-QWJGEDHV.js.map +0 -1
  32. package/dist/chunk-XJUIZA4G.cjs.map +0 -1
  33. package/dist/chunk-ZXRVVNT5.cjs.map +0 -1
@@ -1,16 +1,8 @@
1
- import { useMentionAutocomplete, validateFile, getFileType, generateAttachmentId, AttachmentPreviewItem, MentionMenu, DragDropZone } from './chunk-MD3ZY4UO.js';
2
- import { Dropdown, DropdownItem, DropdownSeparator } from './chunk-TZX76ZNZ.js';
3
1
  import { AudioPlayer } from './chunk-VVDE4CHU.js';
4
- import { AlertTriangle, X2, Paperclip, Plus, Mic, Square, Loader2, ArrowUp, Check, Bot, ChevronUp } from './chunk-BKSPDTX4.js';
5
2
  import { cn } from './chunk-TQONQSJO.js';
6
- import { useEscapeKey } from './chunk-T4ME7QCT.js';
7
- import { useClickOutside } from './chunk-62ZOA6PX.js';
8
- import { useAnchoredPosition } from './chunk-WSNMQQ4P.js';
9
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
- import * as React3 from 'react';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+ import * as React2 from 'react';
11
5
  import { cva } from 'class-variance-authority';
12
- import { createPortal } from 'react-dom';
13
- import { ChevronUp as ChevronUp$1, Check as Check$1, ChevronRight, ChevronLeft } from 'lucide-react';
14
6
 
15
7
  var sizeClasses = {
16
8
  sm: "h-4 w-4",
@@ -223,9 +215,9 @@ function CollapsiblePill({
223
215
  children
224
216
  }) {
225
217
  const hasContent = Boolean(children);
226
- const [isOpen, setIsOpen] = React3.useState(defaultOpen);
227
- const contentId = React3.useId();
228
- React3.useEffect(() => {
218
+ const [isOpen, setIsOpen] = React2.useState(defaultOpen);
219
+ const contentId = React2.useId();
220
+ React2.useEffect(() => {
229
221
  setIsOpen(defaultOpen);
230
222
  }, [defaultOpen]);
231
223
  const toggle = () => {
@@ -1082,10 +1074,10 @@ function ThinkingBlock({
1082
1074
  streaming,
1083
1075
  defaultCollapsed = false
1084
1076
  }) {
1085
- const startedAt = React3.useRef(Date.now());
1086
- const [elapsed, setElapsed] = React3.useState(null);
1087
- const prevStreaming = React3.useRef(streaming);
1088
- React3.useEffect(() => {
1077
+ const startedAt = React2.useRef(Date.now());
1078
+ const [elapsed, setElapsed] = React2.useState(null);
1079
+ const prevStreaming = React2.useRef(streaming);
1080
+ React2.useEffect(() => {
1089
1081
  if (prevStreaming.current && !streaming) {
1090
1082
  setElapsed(Math.round((Date.now() - startedAt.current) / 1e3));
1091
1083
  }
@@ -1289,7 +1281,7 @@ var bubbleVariants = cva("rounded-2xl px-4 py-2.5 w-fit max-w-[85%]", {
1289
1281
  variant: "assistant"
1290
1282
  }
1291
1283
  });
1292
- var ChatBubble = React3.forwardRef(
1284
+ var ChatBubble = React2.forwardRef(
1293
1285
  ({ className, variant, hasError, accent, style, children, ...props }, ref) => {
1294
1286
  return /* @__PURE__ */ jsx(
1295
1287
  "div",
@@ -1405,1169 +1397,7 @@ function AIMessageDisplay({
1405
1397
  }
1406
1398
  );
1407
1399
  }
1408
- var MENU_OFFSET_PX = 6;
1409
- var MENU_MAX_HEIGHT_PX = 320;
1410
- function optionKey(option) {
1411
- return `${option.provider}\0${option.model}`;
1412
- }
1413
- function renderedOptionKey(option, index) {
1414
- return `${option.id ?? optionKey(option)}\0${index}`;
1415
- }
1416
- function groupByProvider(models) {
1417
- const groups = /* @__PURE__ */ new Map();
1418
- for (const model of models) {
1419
- const group = groups.get(model.provider);
1420
- if (group) {
1421
- group.push(model);
1422
- } else {
1423
- groups.set(model.provider, [model]);
1424
- }
1425
- }
1426
- return Array.from(groups, ([provider, options]) => ({ provider, options }));
1427
- }
1428
- function getProviderLabel(models, provider) {
1429
- return models.find((model) => model.provider === provider && model.providerLabel)?.providerLabel ?? provider;
1430
- }
1431
- function ComposerModelSelector({
1432
- models,
1433
- value,
1434
- providerFilter,
1435
- onProviderFilterChange,
1436
- onChange,
1437
- disabled = false,
1438
- variant = "default",
1439
- className,
1440
- boundaryRef,
1441
- placeholder = "Model",
1442
- anyLabel = "Any",
1443
- emptyLabel = "No models",
1444
- ariaLabel = "Model",
1445
- effortOptions,
1446
- effort = null,
1447
- defaultEffort,
1448
- onEffortChange,
1449
- effortLabel = "Effort",
1450
- effortHint,
1451
- defaultBadgeLabel = "Default",
1452
- backLabel = "Back"
1453
- }) {
1454
- const [open, setOpen] = React3.useState(false);
1455
- const [view, setView] = React3.useState("models");
1456
- const [effortHighlight, setEffortHighlight] = React3.useState(0);
1457
- const [internalProviderFilter, setInternalProviderFilter] = React3.useState(null);
1458
- const [highlightedIndex, setHighlightedIndex] = React3.useState(0);
1459
- const listRef = React3.useRef(null);
1460
- const effortListRef = React3.useRef(null);
1461
- const menuId = React3.useId();
1462
- const {
1463
- anchorRef: triggerRef,
1464
- floatingRef: menuRef,
1465
- style: menuStyle
1466
- } = useAnchoredPosition({
1467
- open,
1468
- placement: "top-start",
1469
- offset: MENU_OFFSET_PX,
1470
- matchMinWidth: true,
1471
- maxHeight: MENU_MAX_HEIGHT_PX,
1472
- allowFlip: false,
1473
- boundaryRef
1474
- });
1475
- const activeProviderFilter = providerFilter === void 0 ? internalProviderFilter : providerFilter;
1476
- const selectedKey = value ? optionKey(value) : null;
1477
- const selectedOption = models.find(
1478
- (model) => optionKey(model) === selectedKey
1479
- );
1480
- const providers = React3.useMemo(
1481
- () => Array.from(new Set(models.map((model) => model.provider))),
1482
- [models]
1483
- );
1484
- const providerLabels = React3.useMemo(
1485
- () => new Map(
1486
- providers.map((provider) => [
1487
- provider,
1488
- getProviderLabel(models, provider)
1489
- ])
1490
- ),
1491
- [models, providers]
1492
- );
1493
- const filteredModels = React3.useMemo(
1494
- () => activeProviderFilter === null ? models : models.filter((model) => model.provider === activeProviderFilter),
1495
- [activeProviderFilter, models]
1496
- );
1497
- const groupedModels = React3.useMemo(
1498
- () => groupByProvider(filteredModels),
1499
- [filteredModels]
1500
- );
1501
- const groupedRenderedModels = React3.useMemo(() => {
1502
- let index = 0;
1503
- return groupedModels.map((group) => ({
1504
- provider: group.provider,
1505
- options: group.options.map((option) => {
1506
- const rendered = {
1507
- option,
1508
- index,
1509
- key: renderedOptionKey(option, index)
1510
- };
1511
- index += 1;
1512
- return rendered;
1513
- })
1514
- }));
1515
- }, [groupedModels]);
1516
- const renderedModels = React3.useMemo(
1517
- () => groupedRenderedModels.flatMap((group) => group.options),
1518
- [groupedRenderedModels]
1519
- );
1520
- const getOptionId = React3.useCallback(
1521
- (index) => `${menuId}-option-${index}`,
1522
- [menuId]
1523
- );
1524
- const getEffortOptionId = React3.useCallback(
1525
- (index) => `${menuId}-effort-option-${index}`,
1526
- [menuId]
1527
- );
1528
- const activeOptionId = open && renderedModels[highlightedIndex] ? getOptionId(highlightedIndex) : void 0;
1529
- const selectedRenderedIndex = React3.useMemo(
1530
- () => selectedKey ? renderedModels.findIndex(
1531
- (renderedModel) => optionKey(renderedModel.option) === selectedKey
1532
- ) : -1,
1533
- [renderedModels, selectedKey]
1534
- );
1535
- const setProvider = React3.useCallback(
1536
- (provider) => {
1537
- if (providerFilter === void 0) {
1538
- setInternalProviderFilter(provider);
1539
- }
1540
- onProviderFilterChange?.(provider);
1541
- },
1542
- [onProviderFilterChange, providerFilter]
1543
- );
1544
- const close = React3.useCallback(
1545
- (restoreFocus = true) => {
1546
- setOpen(false);
1547
- if (restoreFocus) {
1548
- triggerRef.current?.focus({ preventScroll: true });
1549
- }
1550
- },
1551
- [triggerRef]
1552
- );
1553
- const selectModel = React3.useCallback(
1554
- (model) => {
1555
- onChange({ provider: model.provider, model: model.model });
1556
- close();
1557
- },
1558
- [close, onChange]
1559
- );
1560
- const efforts = React3.useMemo(() => effortOptions ?? [], [effortOptions]);
1561
- const activeEffortOptionId = open && efforts[effortHighlight] ? getEffortOptionId(effortHighlight) : void 0;
1562
- const selectedEffortOption = efforts.find(
1563
- (option) => option.value === effort
1564
- );
1565
- const selectEffort = React3.useCallback(
1566
- (value2) => {
1567
- onEffortChange?.(value2);
1568
- close();
1569
- },
1570
- [close, onEffortChange]
1571
- );
1572
- const handleEffortKeyDown = (event) => {
1573
- if (efforts.length === 0) return;
1574
- if (event.key === "ArrowDown") {
1575
- event.preventDefault();
1576
- setEffortHighlight((current) => (current + 1) % efforts.length);
1577
- }
1578
- if (event.key === "ArrowUp") {
1579
- event.preventDefault();
1580
- setEffortHighlight(
1581
- (current) => (current - 1 + efforts.length) % efforts.length
1582
- );
1583
- }
1584
- if (event.key === "Home") {
1585
- event.preventDefault();
1586
- setEffortHighlight(0);
1587
- }
1588
- if (event.key === "End") {
1589
- event.preventDefault();
1590
- setEffortHighlight(efforts.length - 1);
1591
- }
1592
- if (event.key === "ArrowLeft" || event.key === "Backspace") {
1593
- event.preventDefault();
1594
- setView("models");
1595
- }
1596
- if (event.key === "Enter" || event.key === " ") {
1597
- event.preventDefault();
1598
- const highlighted = efforts[effortHighlight];
1599
- if (highlighted) selectEffort(highlighted.value);
1600
- }
1601
- };
1602
- const outsideRefs = React3.useMemo(
1603
- () => [triggerRef, menuRef],
1604
- [triggerRef, menuRef]
1605
- );
1606
- useClickOutside(outsideRefs, () => close(false), open);
1607
- useEscapeKey(close, open);
1608
- React3.useEffect(() => {
1609
- if (!open) return;
1610
- setHighlightedIndex(selectedRenderedIndex >= 0 ? selectedRenderedIndex : 0);
1611
- }, [activeProviderFilter, open, selectedRenderedIndex]);
1612
- React3.useEffect(() => {
1613
- if (!open) return;
1614
- setView("models");
1615
- }, [open]);
1616
- React3.useEffect(() => {
1617
- if (!open) return;
1618
- const current = efforts.findIndex((option) => option.value === effort);
1619
- setEffortHighlight(current >= 0 ? current : 0);
1620
- }, [effort, efforts, open]);
1621
- React3.useEffect(() => {
1622
- if (!open) return;
1623
- setHighlightedIndex(
1624
- (current) => Math.min(current, Math.max(renderedModels.length - 1, 0))
1625
- );
1626
- }, [open, renderedModels.length]);
1627
- React3.useEffect(() => {
1628
- if (!open) return;
1629
- requestAnimationFrame(() => {
1630
- const target = view === "effort" ? effortListRef.current : listRef.current;
1631
- target?.focus({ preventScroll: true });
1632
- });
1633
- }, [open, view]);
1634
- const handleTriggerKeyDown = (event) => {
1635
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1636
- event.preventDefault();
1637
- setOpen(true);
1638
- }
1639
- };
1640
- const handleMenuKeyDown = (event) => {
1641
- if (renderedModels.length === 0) return;
1642
- if (event.key === "ArrowDown") {
1643
- event.preventDefault();
1644
- setHighlightedIndex((current) => (current + 1) % renderedModels.length);
1645
- }
1646
- if (event.key === "ArrowUp") {
1647
- event.preventDefault();
1648
- setHighlightedIndex(
1649
- (current) => (current - 1 + renderedModels.length) % renderedModels.length
1650
- );
1651
- }
1652
- if (event.key === "Home") {
1653
- event.preventDefault();
1654
- setHighlightedIndex(0);
1655
- }
1656
- if (event.key === "End") {
1657
- event.preventDefault();
1658
- setHighlightedIndex(renderedModels.length - 1);
1659
- }
1660
- if (event.key === "Enter" || event.key === " ") {
1661
- event.preventDefault();
1662
- const highlightedModel = renderedModels[highlightedIndex]?.option;
1663
- if (highlightedModel) {
1664
- selectModel(highlightedModel);
1665
- }
1666
- }
1667
- };
1668
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1669
- /* @__PURE__ */ jsxs(
1670
- "button",
1671
- {
1672
- ref: triggerRef,
1673
- type: "button",
1674
- disabled,
1675
- "aria-haspopup": "listbox",
1676
- "aria-expanded": open,
1677
- "aria-controls": open ? menuId : void 0,
1678
- onClick: () => setOpen((current) => !current),
1679
- onKeyDown: handleTriggerKeyDown,
1680
- "data-slot": "composer-model-selector-trigger",
1681
- className: cn(
1682
- variant === "ghost" ? [
1683
- "inline-flex max-w-full min-w-0 items-center gap-1 rounded-md px-2 py-1 text-xs",
1684
- "text-neutral-600 dark:text-neutral-400",
1685
- "transition-colors duration-150",
1686
- "hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-700 dark:hover:text-white",
1687
- "focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none",
1688
- "disabled:pointer-events-none disabled:opacity-40"
1689
- ] : [
1690
- "inline-flex h-8 max-w-full items-center gap-1.5 rounded-full border px-2.5 text-sm font-medium",
1691
- "border-border bg-background text-foreground shadow-sm",
1692
- "hover:bg-muted/50",
1693
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
1694
- "disabled:cursor-not-allowed disabled:opacity-50"
1695
- ],
1696
- className
1697
- ),
1698
- children: [
1699
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: selectedOption?.label ?? selectedOption?.model ?? placeholder }),
1700
- selectedEffortOption && /* @__PURE__ */ jsx(
1701
- "span",
1702
- {
1703
- "data-slot": "composer-model-selector-trigger-effort",
1704
- className: "text-muted-foreground min-w-0 truncate font-normal",
1705
- children: selectedEffortOption.label
1706
- }
1707
- ),
1708
- /* @__PURE__ */ jsx(
1709
- ChevronUp$1,
1710
- {
1711
- "aria-hidden": "true",
1712
- className: cn(
1713
- "shrink-0",
1714
- variant === "ghost" ? "h-3 w-3" : "h-3.5 w-3.5"
1715
- )
1716
- }
1717
- )
1718
- ]
1719
- }
1720
- ),
1721
- open && createPortal(
1722
- /* @__PURE__ */ jsxs(
1723
- "div",
1724
- {
1725
- ref: menuRef,
1726
- style: menuStyle,
1727
- "data-slot": "composer-model-selector-menu",
1728
- className: cn(
1729
- "border-border bg-card text-card-foreground flex w-80 max-w-full flex-col rounded-lg border shadow-lg",
1730
- "animate-in fade-in overflow-hidden duration-100"
1731
- ),
1732
- children: [
1733
- view === "models" && /* @__PURE__ */ jsxs(Fragment, { children: [
1734
- /* @__PURE__ */ jsx(
1735
- "div",
1736
- {
1737
- "data-slot": "composer-model-selector-provider-filter",
1738
- className: "border-border flex min-h-9 items-center gap-1 overflow-x-auto overflow-y-hidden border-b p-2",
1739
- children: [null, ...providers].map((provider) => {
1740
- const selected = activeProviderFilter === provider;
1741
- return /* @__PURE__ */ jsx(
1742
- "button",
1743
- {
1744
- type: "button",
1745
- "aria-pressed": selected,
1746
- onMouseDown: (event) => event.preventDefault(),
1747
- onClick: () => setProvider(provider),
1748
- className: cn(
1749
- "inline-flex h-6 shrink-0 items-center justify-center rounded-full px-2.5 text-xs font-medium whitespace-nowrap transition-colors",
1750
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
1751
- selected ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"
1752
- ),
1753
- children: provider === null ? anyLabel : providerLabels.get(provider) ?? provider
1754
- },
1755
- provider ?? "all-providers"
1756
- );
1757
- })
1758
- }
1759
- ),
1760
- /* @__PURE__ */ jsx(
1761
- "div",
1762
- {
1763
- ref: listRef,
1764
- id: menuId,
1765
- role: "listbox",
1766
- "aria-label": ariaLabel,
1767
- "aria-activedescendant": activeOptionId,
1768
- tabIndex: -1,
1769
- onKeyDown: handleMenuKeyDown,
1770
- className: "min-h-0 flex-1 overflow-y-auto p-1",
1771
- children: groupedModels.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground px-3 py-4 text-center text-sm", children: emptyLabel }) : groupedRenderedModels.map((group) => /* @__PURE__ */ jsxs(
1772
- "div",
1773
- {
1774
- role: "group",
1775
- "aria-label": providerLabels.get(group.provider) ?? group.provider,
1776
- children: [
1777
- /* @__PURE__ */ jsx("div", { className: "text-muted-foreground px-3 py-1.5 text-xs font-semibold uppercase", children: providerLabels.get(group.provider) ?? group.provider }),
1778
- group.options.map((renderedModel) => {
1779
- const { index, key, option: model } = renderedModel;
1780
- const selected = optionKey(model) === selectedKey;
1781
- const highlighted = index === highlightedIndex;
1782
- return /* @__PURE__ */ jsxs(
1783
- "button",
1784
- {
1785
- id: getOptionId(index),
1786
- type: "button",
1787
- role: "option",
1788
- "aria-selected": selected,
1789
- onMouseDown: (event) => event.preventDefault(),
1790
- onClick: () => selectModel(model),
1791
- onMouseEnter: () => setHighlightedIndex(index),
1792
- className: cn(
1793
- "flex w-full items-center gap-2 rounded-md px-3 py-2 text-start text-sm",
1794
- "focus-visible:ring-ring transition-colors focus-visible:ring-2 focus-visible:outline-none",
1795
- highlighted && "bg-muted",
1796
- selected && "bg-primary/10 text-primary"
1797
- ),
1798
- children: [
1799
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: model.label ?? model.model }),
1800
- selected && /* @__PURE__ */ jsx(
1801
- Check$1,
1802
- {
1803
- "aria-hidden": "true",
1804
- className: "text-primary h-4 w-4 shrink-0"
1805
- }
1806
- )
1807
- ]
1808
- },
1809
- key
1810
- );
1811
- })
1812
- ]
1813
- },
1814
- group.provider
1815
- ))
1816
- }
1817
- ),
1818
- efforts.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-border border-t p-1", children: /* @__PURE__ */ jsxs(
1819
- "button",
1820
- {
1821
- type: "button",
1822
- "data-slot": "composer-model-selector-effort-row",
1823
- "aria-haspopup": "listbox",
1824
- onMouseDown: (event) => event.preventDefault(),
1825
- onClick: () => setView("effort"),
1826
- className: cn(
1827
- "flex w-full items-center gap-2 rounded-md px-3 py-2 text-start text-sm",
1828
- "hover:bg-muted transition-colors",
1829
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none"
1830
- ),
1831
- children: [
1832
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: effortLabel }),
1833
- selectedEffortOption && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground min-w-0 truncate", children: selectedEffortOption.label }),
1834
- /* @__PURE__ */ jsx(
1835
- ChevronRight,
1836
- {
1837
- "aria-hidden": "true",
1838
- className: "text-muted-foreground h-4 w-4 shrink-0 rtl:-scale-x-100"
1839
- }
1840
- )
1841
- ]
1842
- }
1843
- ) })
1844
- ] }),
1845
- view === "effort" && /* @__PURE__ */ jsxs(Fragment, { children: [
1846
- /* @__PURE__ */ jsx("div", { className: "border-border flex items-center gap-1 border-b p-2", children: /* @__PURE__ */ jsxs(
1847
- "button",
1848
- {
1849
- type: "button",
1850
- "data-slot": "composer-model-selector-effort-back",
1851
- "aria-label": backLabel,
1852
- onMouseDown: (event) => event.preventDefault(),
1853
- onClick: () => setView("models"),
1854
- className: cn(
1855
- "inline-flex h-6 shrink-0 items-center gap-1 rounded-full px-2 text-xs font-medium",
1856
- "text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
1857
- "focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none"
1858
- ),
1859
- children: [
1860
- /* @__PURE__ */ jsx(
1861
- ChevronLeft,
1862
- {
1863
- "aria-hidden": "true",
1864
- className: "h-3.5 w-3.5 rtl:-scale-x-100"
1865
- }
1866
- ),
1867
- effortLabel
1868
- ]
1869
- }
1870
- ) }),
1871
- effortHint && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground px-3 pt-2 text-xs", children: effortHint }),
1872
- /* @__PURE__ */ jsx(
1873
- "div",
1874
- {
1875
- ref: effortListRef,
1876
- id: menuId,
1877
- role: "listbox",
1878
- "aria-label": effortLabel,
1879
- "aria-activedescendant": activeEffortOptionId,
1880
- tabIndex: -1,
1881
- onKeyDown: handleEffortKeyDown,
1882
- className: "min-h-0 flex-1 overflow-y-auto p-1",
1883
- children: efforts.map((option, index) => {
1884
- const selected = option.value === effort;
1885
- const highlighted = index === effortHighlight;
1886
- return /* @__PURE__ */ jsxs(
1887
- "button",
1888
- {
1889
- id: getEffortOptionId(index),
1890
- type: "button",
1891
- role: "option",
1892
- "aria-selected": selected,
1893
- onMouseDown: (event) => event.preventDefault(),
1894
- onClick: () => selectEffort(option.value),
1895
- onMouseEnter: () => setEffortHighlight(index),
1896
- className: cn(
1897
- "flex w-full items-center gap-2 rounded-md px-3 py-2 text-start text-sm",
1898
- "focus-visible:ring-ring transition-colors focus-visible:ring-2 focus-visible:outline-none",
1899
- highlighted && "bg-muted",
1900
- selected && "bg-primary/10 text-primary"
1901
- ),
1902
- children: [
1903
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
1904
- /* @__PURE__ */ jsx("span", { className: "block truncate", children: option.label }),
1905
- option.description && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground block truncate text-xs", children: option.description })
1906
- ] }),
1907
- option.value === defaultEffort && /* @__PURE__ */ jsx("span", { className: "bg-muted text-muted-foreground shrink-0 rounded px-1.5 py-0.5 text-xs", children: defaultBadgeLabel }),
1908
- selected && /* @__PURE__ */ jsx(
1909
- Check$1,
1910
- {
1911
- "aria-hidden": "true",
1912
- className: "text-primary h-4 w-4 shrink-0"
1913
- }
1914
- )
1915
- ]
1916
- },
1917
- option.value
1918
- );
1919
- })
1920
- }
1921
- )
1922
- ] })
1923
- ]
1924
- }
1925
- ),
1926
- document.body
1927
- )
1928
- ] });
1929
- }
1930
- ComposerModelSelector.displayName = "ComposerModelSelector";
1931
- var iconButtonClasses = cn(
1932
- "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg",
1933
- "text-neutral-500 dark:text-neutral-400",
1934
- "transition-colors duration-150",
1935
- "hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-700 dark:hover:text-white",
1936
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500",
1937
- "disabled:pointer-events-none disabled:opacity-40"
1938
- );
1939
- var selectorTriggerClasses = cn(
1940
- "flex min-w-0 items-center gap-1 rounded-md px-2 py-1 text-xs",
1941
- "text-neutral-600 dark:text-neutral-400",
1942
- "transition-colors duration-150",
1943
- "hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-700 dark:hover:text-white",
1944
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500",
1945
- "disabled:pointer-events-none disabled:opacity-40"
1946
- );
1947
- var MAX_INPUT_HEIGHT = 160;
1948
- var ChatComposer = React3.forwardRef(function ChatComposer2({
1949
- onSend,
1950
- value: controlledValue,
1951
- onValueChange,
1952
- placeholder = "Type a message\u2026",
1953
- disabled = false,
1954
- isSending = false,
1955
- autoFocus = false,
1956
- maxLength,
1957
- showCharacterCount = false,
1958
- canSendWhenEmpty = false,
1959
- maxHeight = MAX_INPUT_HEIGHT,
1960
- textareaProps,
1961
- addMenuItems,
1962
- allowAttachments = true,
1963
- acceptedFileTypes,
1964
- maxFileSize,
1965
- maxAttachments = 10,
1966
- mentionOptions,
1967
- replyTo = null,
1968
- onCancelReply,
1969
- showMic = false,
1970
- onMicClick,
1971
- micSlot,
1972
- micBehavior = "always",
1973
- isStreaming = false,
1974
- onStop,
1975
- showAgentSelector = false,
1976
- agents = [],
1977
- selectedAgent = null,
1978
- onAgentChange,
1979
- showModelSelector = false,
1980
- modelSelectorProps,
1981
- readOnly = false,
1982
- readOnlyMessage = "You have read-only access and cannot send messages.",
1983
- onError,
1984
- attachmentLimitLabel,
1985
- sendFailedLabel = "Failed to send message",
1986
- sendingLabel = "Sending message\u2026",
1987
- inputLabel = "Message input",
1988
- addMenuLabel = "Add to message",
1989
- attachFilesLabel = "Attach files",
1990
- micLabel = "Start voice input",
1991
- sendLabel = "Send message",
1992
- stopLabel = "Stop generating",
1993
- agentSelectorLabel = "Select agent",
1994
- mentionListLabel = "Mention",
1995
- dropFilesLabel = "Drop files here",
1996
- replyingToLabel = "Replying to",
1997
- cancelReplyLabel = "Cancel reply",
1998
- className
1999
- }, ref) {
2000
- const [internalValue, setInternalValue] = React3.useState("");
2001
- const isControlled = controlledValue !== void 0;
2002
- const value = isControlled ? controlledValue : internalValue;
2003
- const [attachments, setAttachments] = React3.useState([]);
2004
- const attachmentsRef = React3.useRef(attachments);
2005
- attachmentsRef.current = attachments;
2006
- const textareaRef = React3.useRef(null);
2007
- const fileInputRef = React3.useRef(null);
2008
- const [addMenuOpen, setAddMenuOpen] = React3.useState(false);
2009
- const [agentMenuOpen, setAgentMenuOpen] = React3.useState(false);
2010
- const replyToId = replyTo?.id;
2011
- React3.useEffect(() => {
2012
- if (replyToId !== void 0) {
2013
- textareaRef.current?.focus();
2014
- }
2015
- }, [replyToId]);
2016
- const hasText = value.trim().length > 0;
2017
- const hasContent = hasText || attachments.length > 0;
2018
- const isOverLimit = maxLength !== void 0 && value.length > maxLength;
2019
- const canSend = (hasContent || canSendWhenEmpty) && onSend !== void 0 && !disabled && !isSending && !isStreaming && !isOverLimit;
2020
- const setValue = React3.useCallback(
2021
- (next) => {
2022
- if (!isControlled) setInternalValue(next);
2023
- onValueChange?.(next);
2024
- },
2025
- [isControlled, onValueChange]
2026
- );
2027
- const mention = useMentionAutocomplete({
2028
- options: mentionOptions,
2029
- value,
2030
- setValue,
2031
- textareaRef
2032
- });
2033
- const resizeTextarea = React3.useCallback(() => {
2034
- const textarea = textareaRef.current;
2035
- if (!textarea) return;
2036
- textarea.style.height = "auto";
2037
- if (textarea.scrollHeight === 0) return;
2038
- textarea.style.height = `${textarea.scrollHeight}px`;
2039
- }, []);
2040
- React3.useLayoutEffect(resizeTextarea, [resizeTextarea, value]);
2041
- React3.useEffect(() => {
2042
- const textarea = textareaRef.current;
2043
- if (!textarea || typeof ResizeObserver === "undefined") return;
2044
- let frame = 0;
2045
- const observer = new ResizeObserver(() => {
2046
- cancelAnimationFrame(frame);
2047
- frame = requestAnimationFrame(resizeTextarea);
2048
- });
2049
- observer.observe(textarea);
2050
- return () => {
2051
- cancelAnimationFrame(frame);
2052
- observer.disconnect();
2053
- };
2054
- }, [resizeTextarea]);
2055
- const addFiles = React3.useCallback(
2056
- (files) => {
2057
- if (!allowAttachments || files.length === 0) return;
2058
- const limitMessage = attachmentLimitLabel ?? `Attachment limit reached (max ${maxAttachments})`;
2059
- const room = maxAttachments - attachmentsRef.current.length;
2060
- if (files.length > room) {
2061
- onError?.(limitMessage, { reason: "attachment-limit" });
2062
- if (room <= 0) return;
2063
- }
2064
- const staged = [];
2065
- for (const file of files.slice(0, Math.max(room, 0))) {
2066
- const typeCheck = validateFile(file, acceptedFileTypes, void 0);
2067
- if (!typeCheck.valid) {
2068
- onError?.(`${file.name}: ${typeCheck.error}`, {
2069
- reason: "file-type",
2070
- file
2071
- });
2072
- continue;
2073
- }
2074
- const sizeCheck = validateFile(file, void 0, maxFileSize);
2075
- if (!sizeCheck.valid) {
2076
- onError?.(`${file.name}: ${sizeCheck.error}`, {
2077
- reason: "file-size",
2078
- file
2079
- });
2080
- continue;
2081
- }
2082
- const type = getFileType(file.type);
2083
- staged.push({
2084
- id: generateAttachmentId(),
2085
- file,
2086
- type,
2087
- previewUrl: type === "image" || type === "video" ? URL.createObjectURL(file) : void 0
2088
- });
2089
- }
2090
- if (staged.length > 0) {
2091
- attachmentsRef.current = [...attachmentsRef.current, ...staged];
2092
- setAttachments((current) => [...current, ...staged]);
2093
- }
2094
- },
2095
- [
2096
- allowAttachments,
2097
- maxAttachments,
2098
- acceptedFileTypes,
2099
- maxFileSize,
2100
- onError,
2101
- attachmentLimitLabel
2102
- ]
2103
- );
2104
- const removeAttachment = React3.useCallback((id) => {
2105
- const target = attachmentsRef.current.find(
2106
- (attachment) => attachment.id === id
2107
- );
2108
- if (target?.previewUrl) URL.revokeObjectURL(target.previewUrl);
2109
- attachmentsRef.current = attachmentsRef.current.filter(
2110
- (attachment) => attachment.id !== id
2111
- );
2112
- setAttachments(
2113
- (current) => current.filter((attachment) => attachment.id !== id)
2114
- );
2115
- }, []);
2116
- React3.useEffect(() => {
2117
- return () => {
2118
- for (const attachment of attachmentsRef.current) {
2119
- if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl);
2120
- }
2121
- };
2122
- }, []);
2123
- const handleFileInputChange = (event) => {
2124
- const files = Array.from(event.target.files ?? []);
2125
- addFiles(files);
2126
- event.target.value = "";
2127
- };
2128
- const handlePaste = (event) => {
2129
- if (!allowAttachments) return;
2130
- const files = Array.from(event.clipboardData.files);
2131
- if (files.length > 0) {
2132
- event.preventDefault();
2133
- addFiles(files);
2134
- }
2135
- };
2136
- React3.useImperativeHandle(
2137
- ref,
2138
- () => ({
2139
- addFiles,
2140
- focus: () => textareaRef.current?.focus(),
2141
- getTextarea: () => textareaRef.current
2142
- }),
2143
- [addFiles]
2144
- );
2145
- const handleSend = () => {
2146
- if (!canSend || !onSend) return;
2147
- const message = {
2148
- content: value.trim(),
2149
- attachments: attachments.map((attachment) => attachment.file),
2150
- // Only add the key when replying — hosts may key-check the payload.
2151
- ...replyTo ? { replyToId: replyTo.id } : {}
2152
- };
2153
- for (const attachment of attachments) {
2154
- if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl);
2155
- }
2156
- attachmentsRef.current = [];
2157
- setAttachments([]);
2158
- setValue("");
2159
- try {
2160
- Promise.resolve(onSend(message)).catch(() => {
2161
- onError?.(sendFailedLabel, { reason: "send-failed" });
2162
- });
2163
- } catch {
2164
- onError?.(sendFailedLabel, { reason: "send-failed" });
2165
- }
2166
- textareaRef.current?.focus();
2167
- };
2168
- const handleKeyDown = (event) => {
2169
- if (mention.handleKeyDown(event)) return;
2170
- if (event.key === "Enter" && !event.shiftKey) {
2171
- event.preventDefault();
2172
- handleSend();
2173
- }
2174
- };
2175
- if (readOnly) {
2176
- return /* @__PURE__ */ jsxs(
2177
- "div",
2178
- {
2179
- "data-slot": "chat-composer",
2180
- role: "status",
2181
- className: cn(
2182
- "flex items-center gap-2 rounded-xl border px-4 py-3 text-sm",
2183
- "border-amber-300 bg-amber-50 text-amber-900",
2184
- "dark:border-amber-700 dark:bg-amber-950 dark:text-amber-200",
2185
- className
2186
- ),
2187
- children: [
2188
- /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }),
2189
- /* @__PURE__ */ jsx("span", { "data-slot": "chat-composer-readonly", children: readOnlyMessage })
2190
- ]
2191
- }
2192
- );
2193
- }
2194
- const showAddMenu = allowAttachments || addMenuItems && addMenuItems.length > 0;
2195
- const micVisible = (showMic || onMicClick !== void 0 || micSlot !== void 0) && (micBehavior === "always" || !hasContent);
2196
- const showSelectorRow = showAgentSelector || showModelSelector;
2197
- const selectedAgentOption = agents.find((agent) => agent.id === selectedAgent) ?? null;
2198
- const cells = {
2199
- input: "col-span-3 col-start-1 row-start-1 px-1 pt-1 md:col-span-1 md:col-start-2 md:self-end md:px-0 md:py-1.5",
2200
- textarea: "px-2 pt-2 pb-1 md:py-1.5",
2201
- add: "col-start-1 row-start-2 pb-2 ps-2 md:row-start-1 md:self-end md:p-1.5 md:pe-0.5",
2202
- actions: "col-start-3 row-start-2 flex items-center gap-1 pb-2 pe-2 md:row-start-1 md:self-end md:gap-0.5 md:p-1.5 md:ps-0.5"
2203
- };
2204
- const composerCard = /* @__PURE__ */ jsxs(Fragment, { children: [
2205
- replyTo && /* @__PURE__ */ jsxs(
2206
- "div",
2207
- {
2208
- "data-slot": "chat-composer-reply-preview",
2209
- className: cn(
2210
- "flex items-center gap-2 rounded-t-2xl px-4 py-2",
2211
- "bg-neutral-50 dark:bg-neutral-800/50",
2212
- "border-b border-neutral-200 dark:border-neutral-700",
2213
- "border-s-primary-500 border-s-4"
2214
- ),
2215
- children: [
2216
- /* @__PURE__ */ jsxs("div", { role: "status", className: "min-w-0 flex-1", children: [
2217
- /* @__PURE__ */ jsxs("span", { className: "text-primary-800 dark:text-primary-400 block text-xs font-medium", children: [
2218
- replyingToLabel,
2219
- " ",
2220
- replyTo.senderName
2221
- ] }),
2222
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm text-neutral-600 dark:text-neutral-300", children: replyTo.content })
2223
- ] }),
2224
- /* @__PURE__ */ jsx(
2225
- "button",
2226
- {
2227
- type: "button",
2228
- "data-slot": "chat-composer-cancel-reply",
2229
- "aria-label": cancelReplyLabel,
2230
- disabled,
2231
- onClick: onCancelReply,
2232
- className: iconButtonClasses,
2233
- children: /* @__PURE__ */ jsx(X2, { className: "h-4 w-4", "aria-hidden": "true" })
2234
- }
2235
- )
2236
- ]
2237
- }
2238
- ),
2239
- attachments.length > 0 && /* @__PURE__ */ jsx(
2240
- "div",
2241
- {
2242
- "data-slot": "chat-composer-attachments",
2243
- className: "flex flex-wrap gap-2 px-3 pt-3",
2244
- children: attachments.map((attachment) => /* @__PURE__ */ jsx(
2245
- AttachmentPreviewItem,
2246
- {
2247
- attachment: { ...attachment, state: "pending" },
2248
- onRemove: () => removeAttachment(attachment.id),
2249
- disabled
2250
- },
2251
- attachment.id
2252
- ))
2253
- }
2254
- ),
2255
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[auto_minmax(0,1fr)_auto]", children: [
2256
- /* @__PURE__ */ jsxs("div", { className: cells.input, ref: mention.anchorRef, children: [
2257
- /* @__PURE__ */ jsx(
2258
- MentionMenu,
2259
- {
2260
- mention,
2261
- label: mentionListLabel,
2262
- dataSlot: "chat-composer-mention-list"
2263
- }
2264
- ),
2265
- /* @__PURE__ */ jsx(
2266
- "textarea",
2267
- {
2268
- ...textareaProps,
2269
- ref: textareaRef,
2270
- "data-slot": "chat-composer-input",
2271
- value,
2272
- onChange: (event) => {
2273
- textareaProps?.onChange?.(event);
2274
- setValue(event.target.value);
2275
- mention.sync(
2276
- event.target.value,
2277
- event.target.selectionStart ?? event.target.value.length
2278
- );
2279
- },
2280
- onKeyDown: (event) => {
2281
- textareaProps?.onKeyDown?.(event);
2282
- if (event.defaultPrevented) return;
2283
- handleKeyDown(event);
2284
- },
2285
- onClick: (event) => {
2286
- textareaProps?.onClick?.(event);
2287
- if (event.defaultPrevented) return;
2288
- const el = event.currentTarget;
2289
- mention.sync(el.value, el.selectionStart ?? el.value.length);
2290
- },
2291
- onPaste: (event) => {
2292
- textareaProps?.onPaste?.(event);
2293
- if (event.defaultPrevented) return;
2294
- handlePaste(event);
2295
- },
2296
- placeholder,
2297
- disabled,
2298
- autoFocus,
2299
- rows: 1,
2300
- "aria-label": inputLabel,
2301
- ...mention.inputProps,
2302
- style: {
2303
- ...textareaProps?.style,
2304
- maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight
2305
- },
2306
- className: cn(
2307
- "block w-full resize-none bg-transparent",
2308
- "rounded-lg text-sm",
2309
- cells.textarea,
2310
- "text-neutral-900 placeholder:text-neutral-400 dark:text-white dark:placeholder:text-neutral-500",
2311
- // Ring the input itself on focus rather than the whole shell.
2312
- "focus:ring-primary-500 focus:ring-1 focus:outline-none",
2313
- "disabled:cursor-not-allowed",
2314
- textareaProps?.className
2315
- )
2316
- }
2317
- )
2318
- ] }),
2319
- showAddMenu && /* @__PURE__ */ jsx("div", { className: cells.add, children: /* @__PURE__ */ jsxs(
2320
- Dropdown,
2321
- {
2322
- placement: "top-start",
2323
- open: addMenuOpen,
2324
- onOpenChange: setAddMenuOpen,
2325
- trigger: /* @__PURE__ */ jsx(
2326
- "button",
2327
- {
2328
- type: "button",
2329
- "data-slot": "chat-composer-add-button",
2330
- "aria-label": addMenuLabel,
2331
- disabled,
2332
- className: iconButtonClasses,
2333
- children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4", "aria-hidden": "true" })
2334
- }
2335
- ),
2336
- children: [
2337
- allowAttachments && /* @__PURE__ */ jsx(
2338
- DropdownItem,
2339
- {
2340
- icon: /* @__PURE__ */ jsx(Paperclip, { className: "h-4 w-4", "aria-hidden": "true" }),
2341
- onClick: () => {
2342
- setAddMenuOpen(false);
2343
- fileInputRef.current?.click();
2344
- },
2345
- children: attachFilesLabel
2346
- }
2347
- ),
2348
- allowAttachments && addMenuItems && addMenuItems.length > 0 && /* @__PURE__ */ jsx(DropdownSeparator, {}),
2349
- addMenuItems?.map((item) => /* @__PURE__ */ jsx(
2350
- DropdownItem,
2351
- {
2352
- icon: item.icon,
2353
- disabled: item.disabled,
2354
- variant: item.variant,
2355
- checked: item.checked,
2356
- onClick: () => {
2357
- setAddMenuOpen(false);
2358
- item.onSelect?.();
2359
- },
2360
- children: /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: item.label })
2361
- },
2362
- item.id
2363
- ))
2364
- ]
2365
- }
2366
- ) }),
2367
- allowAttachments && /* @__PURE__ */ jsx(
2368
- "input",
2369
- {
2370
- ref: fileInputRef,
2371
- type: "file",
2372
- multiple: true,
2373
- accept: acceptedFileTypes?.join(","),
2374
- onChange: handleFileInputChange,
2375
- className: "hidden",
2376
- "aria-hidden": "true",
2377
- tabIndex: -1
2378
- }
2379
- ),
2380
- /* @__PURE__ */ jsxs("div", { className: cells.actions, children: [
2381
- showCharacterCount && maxLength !== void 0 && /* @__PURE__ */ jsxs(
2382
- "span",
2383
- {
2384
- "data-slot": "chat-composer-char-count",
2385
- "aria-live": "polite",
2386
- className: cn(
2387
- "pe-1 text-xs tabular-nums",
2388
- isOverLimit ? "font-medium text-red-700 dark:text-red-400" : "text-neutral-500 dark:text-neutral-400"
2389
- ),
2390
- children: [
2391
- value.length,
2392
- "/",
2393
- maxLength
2394
- ]
2395
- }
2396
- ),
2397
- micVisible && (micSlot != null ? (
2398
- // Normalize slot content (e.g. a RecordButton) to the 32px
2399
- // control row: taller content overflow-centers instead of
2400
- // inflating the pill and pushing the other cells apart. A div
2401
- // so block-level slot content stays valid HTML.
2402
- /* @__PURE__ */ jsx(
2403
- "div",
2404
- {
2405
- "data-slot": "chat-composer-mic-slot",
2406
- className: "flex h-8 shrink-0 items-center",
2407
- children: micSlot
2408
- }
2409
- )
2410
- ) : /* @__PURE__ */ jsx(
2411
- "button",
2412
- {
2413
- type: "button",
2414
- "data-slot": "chat-composer-mic-button",
2415
- "aria-label": micLabel,
2416
- disabled,
2417
- onClick: onMicClick,
2418
- className: iconButtonClasses,
2419
- children: /* @__PURE__ */ jsx(Mic, { className: "h-4 w-4", "aria-hidden": "true" })
2420
- }
2421
- )),
2422
- isStreaming && onStop ? /* @__PURE__ */ jsx(
2423
- "button",
2424
- {
2425
- type: "button",
2426
- "data-slot": "chat-composer-stop-button",
2427
- "aria-label": stopLabel,
2428
- disabled,
2429
- onClick: onStop,
2430
- className: cn(
2431
- iconButtonClasses,
2432
- "text-neutral-700 dark:text-neutral-200"
2433
- ),
2434
- children: /* @__PURE__ */ jsx(
2435
- Square,
2436
- {
2437
- className: "h-3.5 w-3.5 fill-current",
2438
- "aria-hidden": "true"
2439
- }
2440
- )
2441
- }
2442
- ) : /* @__PURE__ */ jsx(
2443
- "button",
2444
- {
2445
- type: "button",
2446
- "data-slot": "chat-composer-send-button",
2447
- "aria-label": isSending ? sendingLabel : sendLabel,
2448
- "aria-busy": isSending || void 0,
2449
- disabled: !canSend,
2450
- onClick: handleSend,
2451
- className: cn(
2452
- iconButtonClasses,
2453
- canSend && "bg-primary-800 hover:bg-primary-700 dark:bg-primary-600 dark:hover:bg-primary-500 text-white hover:text-white dark:hover:text-white"
2454
- ),
2455
- children: isSending ? /* @__PURE__ */ jsx(
2456
- Loader2,
2457
- {
2458
- className: "h-4 w-4 animate-spin",
2459
- "aria-hidden": "true"
2460
- }
2461
- ) : /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4", "aria-hidden": "true" })
2462
- }
2463
- )
2464
- ] })
2465
- ] })
2466
- ] });
2467
- const selectorsRow = showSelectorRow && /* @__PURE__ */ jsxs(
2468
- "div",
2469
- {
2470
- "data-slot": "chat-composer-selectors",
2471
- className: "flex items-center justify-between gap-2 px-2 pt-1",
2472
- children: [
2473
- showAgentSelector ? /* @__PURE__ */ jsx(
2474
- Dropdown,
2475
- {
2476
- placement: "top-start",
2477
- open: agentMenuOpen,
2478
- onOpenChange: setAgentMenuOpen,
2479
- trigger: /* @__PURE__ */ jsxs(
2480
- "button",
2481
- {
2482
- type: "button",
2483
- "data-slot": "chat-composer-agent-trigger",
2484
- "aria-label": selectedAgentOption ? `${agentSelectorLabel}: ${selectedAgentOption.label}` : agentSelectorLabel,
2485
- disabled,
2486
- className: selectorTriggerClasses,
2487
- children: [
2488
- selectedAgentOption?.icon ?? /* @__PURE__ */ jsx(Bot, { className: "h-3.5 w-3.5", "aria-hidden": "true" }),
2489
- /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: selectedAgentOption?.label ?? agentSelectorLabel }),
2490
- /* @__PURE__ */ jsx(ChevronUp, { className: "h-3 w-3 shrink-0", "aria-hidden": "true" })
2491
- ]
2492
- }
2493
- ),
2494
- children: agents.map((agent) => /* @__PURE__ */ jsx(
2495
- DropdownItem,
2496
- {
2497
- icon: agent.icon,
2498
- role: "menuitemradio",
2499
- "aria-checked": agent.id === selectedAgent,
2500
- onClick: () => {
2501
- setAgentMenuOpen(false);
2502
- onAgentChange?.(agent.id);
2503
- },
2504
- children: /* @__PURE__ */ jsxs("span", { className: "flex w-full items-center justify-between gap-2", children: [
2505
- /* @__PURE__ */ jsxs("span", { className: "min-w-0", children: [
2506
- /* @__PURE__ */ jsx("span", { className: "block truncate", children: agent.label }),
2507
- agent.description && /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-neutral-500 dark:text-neutral-400", children: agent.description })
2508
- ] }),
2509
- agent.id === selectedAgent && /* @__PURE__ */ jsx(
2510
- Check,
2511
- {
2512
- className: "text-primary-600 dark:text-primary-400 h-4 w-4 shrink-0",
2513
- "aria-hidden": "true"
2514
- }
2515
- )
2516
- ] })
2517
- },
2518
- agent.id
2519
- ))
2520
- }
2521
- ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true" }),
2522
- showModelSelector && modelSelectorProps && /* @__PURE__ */ jsx(
2523
- ComposerModelSelector,
2524
- {
2525
- variant: "ghost",
2526
- ...modelSelectorProps,
2527
- disabled: disabled || modelSelectorProps.disabled
2528
- }
2529
- )
2530
- ]
2531
- }
2532
- );
2533
- const card = /* @__PURE__ */ jsx(
2534
- "div",
2535
- {
2536
- "data-slot": "chat-composer-card",
2537
- className: cn(
2538
- "rounded-2xl border border-neutral-200 bg-white shadow-sm",
2539
- "dark:border-[#2e2e30] dark:bg-[#1c1c1e]"
2540
- ),
2541
- children: composerCard
2542
- }
2543
- );
2544
- return /* @__PURE__ */ jsxs(
2545
- "div",
2546
- {
2547
- "data-slot": "chat-composer",
2548
- className: cn(
2549
- "flex w-full flex-col",
2550
- disabled && "opacity-60",
2551
- className
2552
- ),
2553
- children: [
2554
- allowAttachments ? /* @__PURE__ */ jsx(
2555
- DragDropZone,
2556
- {
2557
- onFilesDropped: addFiles,
2558
- maxFiles: Number.MAX_SAFE_INTEGER,
2559
- disabled,
2560
- overlayLabel: dropFilesLabel,
2561
- children: card
2562
- }
2563
- ) : card,
2564
- selectorsRow
2565
- ]
2566
- }
2567
- );
2568
- });
2569
- ChatComposer.displayName = "ChatComposer";
2570
1400
 
2571
- export { AILogoIcon, AIMessageDisplay, AITypingIndicator, ChatBubble, ChatComposer, ChevronIcon, CloseIcon, CollapsiblePill, ComposerModelSelector, MCPToolCallDisplay, MessageAvatar, RefreshIcon, ResourceLink, SendIcon, SparklesIcon, SpinnerIcon, ToolStatusIcon, getToolIcon };
2572
- //# sourceMappingURL=chunk-QWJGEDHV.js.map
2573
- //# sourceMappingURL=chunk-QWJGEDHV.js.map
1401
+ export { AILogoIcon, AIMessageDisplay, AITypingIndicator, ChatBubble, ChevronIcon, CloseIcon, CollapsiblePill, MCPToolCallDisplay, MessageAvatar, RefreshIcon, ResourceLink, SendIcon, SparklesIcon, SpinnerIcon, ToolStatusIcon, getToolIcon };
1402
+ //# sourceMappingURL=chunk-22CYDCXA.js.map
1403
+ //# sourceMappingURL=chunk-22CYDCXA.js.map