@mieweb/ui 0.9.0-dev.0 → 0.9.0-dev.1

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