@lukeashford/aurelius 3.9.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -92,6 +92,147 @@ Input.displayName = "Input";
92
92
  import React4, { createContext, useContext } from "react";
93
93
  import { Check } from "lucide-react";
94
94
 
95
+ // src/utils/clipboard.ts
96
+ async function copyToClipboard(text) {
97
+ if (typeof navigator !== "undefined" && navigator.clipboard) {
98
+ try {
99
+ await navigator.clipboard.writeText(text);
100
+ return true;
101
+ } catch {
102
+ }
103
+ }
104
+ if (typeof document === "undefined") {
105
+ return false;
106
+ }
107
+ const textArea = document.createElement("textarea");
108
+ textArea.value = text;
109
+ textArea.setAttribute("readonly", "");
110
+ textArea.setAttribute("aria-hidden", "true");
111
+ textArea.style.position = "fixed";
112
+ textArea.style.opacity = "0";
113
+ textArea.style.pointerEvents = "none";
114
+ document.body.appendChild(textArea);
115
+ try {
116
+ textArea.select();
117
+ return document.execCommand("copy");
118
+ } catch {
119
+ return false;
120
+ } finally {
121
+ document.body.removeChild(textArea);
122
+ }
123
+ }
124
+
125
+ // src/utils/hooks.ts
126
+ import { useCallback, useEffect, useRef, useState } from "react";
127
+ function composeRefs(...refs) {
128
+ return (node) => {
129
+ for (const ref of refs) {
130
+ if (!ref) {
131
+ continue;
132
+ }
133
+ if (typeof ref === "function") {
134
+ ref(node);
135
+ } else {
136
+ ;
137
+ ref.current = node;
138
+ }
139
+ }
140
+ };
141
+ }
142
+ var scrollLockCount = 0;
143
+ var scrollLockOriginalOverflow = null;
144
+ var scrollLockOriginalPaddingRight = null;
145
+ function useScrollLock(isLocked) {
146
+ useEffect(() => {
147
+ if (!isLocked || typeof document === "undefined") {
148
+ return;
149
+ }
150
+ if (scrollLockCount === 0) {
151
+ scrollLockOriginalOverflow = document.body.style.overflow;
152
+ scrollLockOriginalPaddingRight = document.body.style.paddingRight;
153
+ const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
154
+ document.body.style.overflow = "hidden";
155
+ if (scrollbarWidth > 0) {
156
+ document.body.style.paddingRight = `${scrollbarWidth}px`;
157
+ }
158
+ }
159
+ scrollLockCount++;
160
+ return () => {
161
+ scrollLockCount--;
162
+ if (scrollLockCount === 0) {
163
+ document.body.style.overflow = scrollLockOriginalOverflow ?? "";
164
+ document.body.style.paddingRight = scrollLockOriginalPaddingRight ?? "";
165
+ scrollLockOriginalOverflow = null;
166
+ scrollLockOriginalPaddingRight = null;
167
+ }
168
+ };
169
+ }, [isLocked]);
170
+ }
171
+ function useEscapeKey(onEscape, isActive = true) {
172
+ useEffect(() => {
173
+ if (!isActive || typeof window === "undefined") {
174
+ return;
175
+ }
176
+ const handler = (e) => {
177
+ if (e.key === "Escape") {
178
+ onEscape();
179
+ }
180
+ };
181
+ window.addEventListener("keydown", handler);
182
+ return () => window.removeEventListener("keydown", handler);
183
+ }, [onEscape, isActive]);
184
+ }
185
+ function useClickOutside(ref, handler, isActive = true) {
186
+ useEffect(() => {
187
+ if (!isActive || typeof document === "undefined") {
188
+ return;
189
+ }
190
+ const listener = (event) => {
191
+ const node = ref.current;
192
+ if (node && !node.contains(event.target)) {
193
+ handler(event);
194
+ }
195
+ };
196
+ document.addEventListener("mousedown", listener);
197
+ return () => document.removeEventListener("mousedown", listener);
198
+ }, [ref, handler, isActive]);
199
+ }
200
+ function useCopyToClipboard(resetMs = 2e3) {
201
+ const [copied, setCopied] = useState(false);
202
+ const timerRef = useRef(null);
203
+ const mountedRef = useRef(true);
204
+ useEffect(() => {
205
+ mountedRef.current = true;
206
+ return () => {
207
+ mountedRef.current = false;
208
+ if (timerRef.current !== null) {
209
+ clearTimeout(timerRef.current);
210
+ timerRef.current = null;
211
+ }
212
+ };
213
+ }, []);
214
+ const copy = useCallback(async (text) => {
215
+ const ok = await copyToClipboard(text);
216
+ if (!mountedRef.current) {
217
+ return ok;
218
+ }
219
+ if (ok) {
220
+ setCopied(true);
221
+ if (timerRef.current !== null) {
222
+ clearTimeout(timerRef.current);
223
+ }
224
+ timerRef.current = setTimeout(() => {
225
+ timerRef.current = null;
226
+ if (mountedRef.current) {
227
+ setCopied(false);
228
+ }
229
+ }, resetMs);
230
+ }
231
+ return ok;
232
+ }, [resetMs]);
233
+ return { copied, copy };
234
+ }
235
+
95
236
  // src/components/Skeleton.tsx
96
237
  import React3 from "react";
97
238
  var Skeleton = React3.forwardRef(
@@ -116,8 +257,7 @@ function slotLoading(loading, path) {
116
257
  return false;
117
258
  }
118
259
  if (Array.isArray(path)) {
119
- const [section, field] = path;
120
- return !!loading[section]?.[field];
260
+ return !!loading.header?.[path[1]];
121
261
  }
122
262
  return !!loading[path];
123
263
  }
@@ -1393,29 +1533,28 @@ var Select = React20.forwardRef(
1393
1533
  Select.displayName = "Select";
1394
1534
 
1395
1535
  // src/components/Checkbox.tsx
1396
- import React21, { useCallback } from "react";
1536
+ import React21, { useCallback as useCallback2, useId } from "react";
1397
1537
  var checkmarkSvg = `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%231A1A1A' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")`;
1398
1538
  var Checkbox = React21.forwardRef(
1399
- ({ className, label, id, ...rest }, ref) => {
1400
- const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1401
- const setRef = useCallback((node) => {
1402
- if (node) {
1403
- if (node.checked) {
1404
- node.style.backgroundImage = checkmarkSvg;
1405
- }
1539
+ ({ className, label, id, onChange, ...rest }, ref) => {
1540
+ const generatedId = useId();
1541
+ const inputId = id || rest.name || generatedId;
1542
+ const initBackground = useCallback2((node) => {
1543
+ if (node && node.checked) {
1544
+ node.style.backgroundImage = checkmarkSvg;
1406
1545
  }
1407
- if (typeof ref === "function") {
1408
- ref(node);
1409
- } else if (ref) {
1410
- ref.current = node;
1411
- }
1412
- }, [ref]);
1546
+ }, []);
1547
+ const handleChange = useCallback2((e) => {
1548
+ e.currentTarget.style.backgroundImage = e.currentTarget.checked ? checkmarkSvg : "none";
1549
+ onChange?.(e);
1550
+ }, [onChange]);
1413
1551
  return /* @__PURE__ */ React21.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React21.createElement(
1414
1552
  "input",
1415
1553
  {
1554
+ ...rest,
1416
1555
  type: "checkbox",
1417
1556
  id: inputId,
1418
- ref: setRef,
1557
+ ref: composeRefs(initBackground, ref),
1419
1558
  className: cx(
1420
1559
  "appearance-none h-4 w-4 border border-ash bg-graphite",
1421
1560
  "checked:bg-gold checked:border-gold",
@@ -1429,16 +1568,7 @@ var Checkbox = React21.forwardRef(
1429
1568
  backgroundSize: "contain",
1430
1569
  backgroundRepeat: "no-repeat"
1431
1570
  },
1432
- onChange: (e) => {
1433
- const input = e.currentTarget;
1434
- if (input.checked) {
1435
- input.style.backgroundImage = checkmarkSvg;
1436
- } else {
1437
- input.style.backgroundImage = "none";
1438
- }
1439
- rest.onChange?.(e);
1440
- },
1441
- ...rest
1571
+ onChange: handleChange
1442
1572
  }
1443
1573
  ), label && /* @__PURE__ */ React21.createElement(
1444
1574
  "label",
@@ -1453,29 +1583,44 @@ var Checkbox = React21.forwardRef(
1453
1583
  Checkbox.displayName = "Checkbox";
1454
1584
 
1455
1585
  // src/components/Radio.tsx
1456
- import React22, { useCallback as useCallback2 } from "react";
1586
+ import React22, { useCallback as useCallback3, useId as useId2 } from "react";
1457
1587
  var radioDotSvg = `url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='%231A1A1A' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")`;
1458
1588
  var Radio = React22.forwardRef(
1459
- ({ className, label, id, ...rest }, ref) => {
1460
- const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1461
- const setRef = useCallback2((node) => {
1462
- if (node) {
1463
- if (node.checked) {
1464
- node.style.backgroundImage = radioDotSvg;
1465
- }
1589
+ ({ className, label, id, onChange, ...rest }, ref) => {
1590
+ const generatedId = useId2();
1591
+ const inputId = id || rest.name || generatedId;
1592
+ const initBackground = useCallback3((node) => {
1593
+ if (node && node.checked) {
1594
+ node.style.backgroundImage = radioDotSvg;
1466
1595
  }
1467
- if (typeof ref === "function") {
1468
- ref(node);
1469
- } else if (ref) {
1470
- ref.current = node;
1596
+ }, []);
1597
+ const handleChange = useCallback3((e) => {
1598
+ const input = e.currentTarget;
1599
+ if (input.checked) {
1600
+ input.style.backgroundImage = radioDotSvg;
1601
+ if (input.name) {
1602
+ const escaped = typeof CSS !== "undefined" && typeof CSS.escape === "function" ? CSS.escape(input.name) : input.name.replace(/["\\\]]/g, "\\$&");
1603
+ const radios = input.ownerDocument.querySelectorAll(
1604
+ `input[type="radio"][name="${escaped}"]`
1605
+ );
1606
+ radios.forEach((radio) => {
1607
+ if (radio !== input) {
1608
+ radio.style.backgroundImage = "none";
1609
+ }
1610
+ });
1611
+ }
1612
+ } else {
1613
+ input.style.backgroundImage = "none";
1471
1614
  }
1472
- }, [ref]);
1615
+ onChange?.(e);
1616
+ }, [onChange]);
1473
1617
  return /* @__PURE__ */ React22.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React22.createElement(
1474
1618
  "input",
1475
1619
  {
1620
+ ...rest,
1476
1621
  type: "radio",
1477
1622
  id: inputId,
1478
- ref: setRef,
1623
+ ref: composeRefs(initBackground, ref),
1479
1624
  className: cx(
1480
1625
  "appearance-none h-4 w-4 border border-ash rounded-full bg-graphite",
1481
1626
  "checked:bg-gold checked:border-gold",
@@ -1489,26 +1634,7 @@ var Radio = React22.forwardRef(
1489
1634
  backgroundSize: "contain",
1490
1635
  backgroundRepeat: "no-repeat"
1491
1636
  },
1492
- onChange: (e) => {
1493
- const input = e.currentTarget;
1494
- if (input.checked) {
1495
- input.style.backgroundImage = radioDotSvg;
1496
- if (input.name) {
1497
- const radios = document.querySelectorAll(
1498
- `input[type="radio"][name="${input.name}"]`
1499
- );
1500
- radios.forEach((radio) => {
1501
- if (radio !== input) {
1502
- radio.style.backgroundImage = "none";
1503
- }
1504
- });
1505
- }
1506
- } else {
1507
- input.style.backgroundImage = "none";
1508
- }
1509
- rest.onChange?.(e);
1510
- },
1511
- ...rest
1637
+ onChange: handleChange
1512
1638
  }
1513
1639
  ), label && /* @__PURE__ */ React22.createElement(
1514
1640
  "label",
@@ -1523,7 +1649,7 @@ var Radio = React22.forwardRef(
1523
1649
  Radio.displayName = "Radio";
1524
1650
 
1525
1651
  // src/components/Switch.tsx
1526
- import React23, { useCallback as useCallback3, useRef, useState } from "react";
1652
+ import React23, { useCallback as useCallback4, useRef as useRef2, useState as useState2 } from "react";
1527
1653
  var Switch = React23.forwardRef(
1528
1654
  ({
1529
1655
  checked: controlledChecked,
@@ -1534,11 +1660,11 @@ var Switch = React23.forwardRef(
1534
1660
  label,
1535
1661
  ...rest
1536
1662
  }, ref) => {
1537
- const [internalChecked, setInternalChecked] = useState(defaultChecked);
1663
+ const [internalChecked, setInternalChecked] = useState2(defaultChecked);
1538
1664
  const isControlled = controlledChecked !== void 0;
1539
1665
  const checked = isControlled ? controlledChecked : internalChecked;
1540
- const buttonRef = useRef(null);
1541
- const setRefs = useCallback3(
1666
+ const buttonRef = useRef2(null);
1667
+ const setRefs = useCallback4(
1542
1668
  (node) => {
1543
1669
  buttonRef.current = node;
1544
1670
  if (typeof ref === "function") {
@@ -1608,7 +1734,7 @@ var Switch = React23.forwardRef(
1608
1734
  Switch.displayName = "Switch";
1609
1735
 
1610
1736
  // src/components/Slider.tsx
1611
- import React24, { useCallback as useCallback4, useRef as useRef2, useState as useState2 } from "react";
1737
+ import React24, { useCallback as useCallback5, useRef as useRef3, useState as useState3 } from "react";
1612
1738
  var SIZE_TRACK = {
1613
1739
  sm: "h-1",
1614
1740
  md: "h-2",
@@ -1635,13 +1761,13 @@ var Slider = React24.forwardRef(
1635
1761
  className,
1636
1762
  ...props
1637
1763
  }, ref) => {
1638
- const [internalValue, setInternalValue] = useState2(defaultValue);
1639
- const [isDragging, setIsDragging] = useState2(false);
1640
- const trackRef = useRef2(null);
1764
+ const [internalValue, setInternalValue] = useState3(defaultValue);
1765
+ const [isDragging, setIsDragging] = useState3(false);
1766
+ const trackRef = useRef3(null);
1641
1767
  const isControlled = controlledValue !== void 0;
1642
1768
  const value = isControlled ? controlledValue : internalValue;
1643
1769
  const percentage = (value - min) / (max - min) * 100;
1644
- const updateValue = useCallback4(
1770
+ const updateValue = useCallback5(
1645
1771
  (clientX) => {
1646
1772
  if (!trackRef.current || disabled) {
1647
1773
  return;
@@ -1997,16 +2123,21 @@ var Progress = React28.forwardRef(
1997
2123
  Progress.displayName = "Progress";
1998
2124
 
1999
2125
  // src/components/Toast.tsx
2000
- import React29, { createContext as createContext2, useCallback as useCallback5, useContext as useContext2, useEffect, useState as useState3 } from "react";
2126
+ import React29, { createContext as createContext2, useCallback as useCallback6, useContext as useContext2, useEffect as useEffect2, useState as useState4 } from "react";
2001
2127
  import { createPortal } from "react-dom";
2002
2128
  import { AlertCircle, AlertTriangle as AlertTriangle2, CheckCircle as CheckCircle2, Info as Info2, X as X2 } from "lucide-react";
2129
+ var toastCounter = 0;
2130
+ function createToastId() {
2131
+ toastCounter += 1;
2132
+ return `toast-${Date.now().toString(36)}-${toastCounter}`;
2133
+ }
2003
2134
  var ToastContext = createContext2(null);
2004
2135
  function useToast() {
2005
2136
  const context = useContext2(ToastContext);
2006
2137
  if (!context) {
2007
2138
  throw new Error("useToast must be used within a ToastProvider");
2008
2139
  }
2009
- const toast = useCallback5(
2140
+ const toast = useCallback6(
2010
2141
  (options) => {
2011
2142
  return context.addToast(options);
2012
2143
  },
@@ -2022,14 +2153,14 @@ var ToastProvider = ({
2022
2153
  position = "bottom-right",
2023
2154
  defaultDuration = 5e3
2024
2155
  }) => {
2025
- const [toasts, setToasts] = useState3([]);
2026
- const [mounted, setMounted] = useState3(false);
2027
- useEffect(() => {
2156
+ const [toasts, setToasts] = useState4([]);
2157
+ const [mounted, setMounted] = useState4(false);
2158
+ useEffect2(() => {
2028
2159
  setMounted(true);
2029
2160
  }, []);
2030
- const addToast = useCallback5(
2161
+ const addToast = useCallback6(
2031
2162
  (toast) => {
2032
- const id = Math.random().toString(36).substr(2, 9);
2163
+ const id = createToastId();
2033
2164
  const newToast = {
2034
2165
  ...toast,
2035
2166
  id,
@@ -2040,33 +2171,33 @@ var ToastProvider = ({
2040
2171
  },
2041
2172
  [defaultDuration]
2042
2173
  );
2043
- const removeToast = useCallback5((id) => {
2174
+ const removeToast = useCallback6((id) => {
2044
2175
  setToasts((prev) => prev.filter((t) => t.id !== id));
2045
2176
  }, []);
2046
2177
  return /* @__PURE__ */ React29.createElement(ToastContext.Provider, { value: { toasts, addToast, removeToast, position } }, children, mounted && /* @__PURE__ */ React29.createElement(ToastViewport, null));
2047
2178
  };
2048
2179
  ToastProvider.displayName = "ToastProvider";
2180
+ var POSITION_CLASSES = {
2181
+ "top-right": "top-4 right-4",
2182
+ "top-left": "top-4 left-4",
2183
+ "bottom-right": "bottom-4 right-4",
2184
+ "bottom-left": "bottom-4 left-4",
2185
+ "top-center": "top-4 left-1/2 -translate-x-1/2",
2186
+ "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
2187
+ };
2049
2188
  var ToastViewport = () => {
2050
2189
  const context = useContext2(ToastContext);
2051
2190
  if (!context) {
2052
2191
  return null;
2053
2192
  }
2054
2193
  const { toasts, position } = context;
2055
- const positionClasses = {
2056
- "top-right": "top-4 right-4",
2057
- "top-left": "top-4 left-4",
2058
- "bottom-right": "bottom-4 right-4",
2059
- "bottom-left": "bottom-4 left-4",
2060
- "top-center": "top-4 left-1/2 -translate-x-1/2",
2061
- "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
2062
- };
2063
2194
  return createPortal(
2064
2195
  /* @__PURE__ */ React29.createElement(
2065
2196
  "div",
2066
2197
  {
2067
2198
  className: cx(
2068
2199
  "fixed z-50 flex flex-col gap-2 pointer-events-none",
2069
- positionClasses[position]
2200
+ POSITION_CLASSES[position]
2070
2201
  )
2071
2202
  },
2072
2203
  toasts.map((toast) => /* @__PURE__ */ React29.createElement(Toast, { key: toast.id, ...toast }))
@@ -2097,7 +2228,7 @@ var Toast = ({
2097
2228
  action
2098
2229
  }) => {
2099
2230
  const context = useContext2(ToastContext);
2100
- useEffect(() => {
2231
+ useEffect2(() => {
2101
2232
  if (duration && duration > 0) {
2102
2233
  const timer = setTimeout(() => {
2103
2234
  context?.removeToast(id);
@@ -2129,41 +2260,17 @@ var Toast = ({
2129
2260
  Toast.displayName = "Toast";
2130
2261
 
2131
2262
  // src/components/Modal.tsx
2132
- import React30, { useEffect as useEffect2, useState as useState4 } from "react";
2263
+ import React30, { useEffect as useEffect3, useState as useState5 } from "react";
2133
2264
  import { createPortal as createPortal2 } from "react-dom";
2134
2265
  import { X as X3 } from "lucide-react";
2135
2266
  var Modal = ({ isOpen, onClose, title, children, className }) => {
2136
- const [mounted, setMounted] = useState4(false);
2137
- useEffect2(() => {
2267
+ const [mounted, setMounted] = useState5(false);
2268
+ useEffect3(() => {
2138
2269
  setMounted(true);
2139
2270
  }, []);
2140
- useEffect2(() => {
2141
- if (isOpen) {
2142
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
2143
- document.body.style.overflow = "hidden";
2144
- document.body.style.paddingRight = `${scrollbarWidth}px`;
2145
- } else {
2146
- document.body.style.overflow = "unset";
2147
- document.body.style.paddingRight = "0px";
2148
- }
2149
- return () => {
2150
- document.body.style.overflow = "unset";
2151
- document.body.style.paddingRight = "0px";
2152
- };
2153
- }, [isOpen]);
2154
- useEffect2(() => {
2155
- const handleEsc = (e) => {
2156
- if (e.key === "Escape") {
2157
- onClose();
2158
- }
2159
- };
2160
- window.addEventListener("keydown", handleEsc);
2161
- return () => window.removeEventListener("keydown", handleEsc);
2162
- }, [onClose]);
2163
- if (!mounted) {
2164
- return null;
2165
- }
2166
- if (!isOpen) {
2271
+ useScrollLock(isOpen);
2272
+ useEscapeKey(onClose, isOpen);
2273
+ if (!mounted || !isOpen) {
2167
2274
  return null;
2168
2275
  }
2169
2276
  const content = /* @__PURE__ */ React30.createElement(
@@ -2202,7 +2309,7 @@ var Modal = ({ isOpen, onClose, title, children, className }) => {
2202
2309
  Modal.displayName = "Modal";
2203
2310
 
2204
2311
  // src/components/Drawer.tsx
2205
- import React31, { useEffect as useEffect3, useState as useState5 } from "react";
2312
+ import React31, { useEffect as useEffect4, useState as useState6 } from "react";
2206
2313
  import { createPortal as createPortal3 } from "react-dom";
2207
2314
  import { X as X4 } from "lucide-react";
2208
2315
  var SIZE_MAP2 = {
@@ -2237,7 +2344,7 @@ var SIZE_MAP2 = {
2237
2344
  bottom: "h-full"
2238
2345
  }
2239
2346
  };
2240
- var POSITION_CLASSES = {
2347
+ var POSITION_CLASSES2 = {
2241
2348
  left: "left-0 top-0 h-full",
2242
2349
  right: "right-0 top-0 h-full",
2243
2350
  top: "top-0 left-0 w-full",
@@ -2258,33 +2365,12 @@ var Drawer = ({
2258
2365
  children,
2259
2366
  className
2260
2367
  }) => {
2261
- const [mounted, setMounted] = useState5(false);
2262
- useEffect3(() => {
2368
+ const [mounted, setMounted] = useState6(false);
2369
+ useEffect4(() => {
2263
2370
  setMounted(true);
2264
2371
  }, []);
2265
- useEffect3(() => {
2266
- if (isOpen) {
2267
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
2268
- document.body.style.overflow = "hidden";
2269
- document.body.style.paddingRight = `${scrollbarWidth}px`;
2270
- } else {
2271
- document.body.style.overflow = "unset";
2272
- document.body.style.paddingRight = "0px";
2273
- }
2274
- return () => {
2275
- document.body.style.overflow = "unset";
2276
- document.body.style.paddingRight = "0px";
2277
- };
2278
- }, [isOpen]);
2279
- useEffect3(() => {
2280
- const handleEsc = (e) => {
2281
- if (e.key === "Escape") {
2282
- onClose();
2283
- }
2284
- };
2285
- window.addEventListener("keydown", handleEsc);
2286
- return () => window.removeEventListener("keydown", handleEsc);
2287
- }, [onClose]);
2372
+ useScrollLock(isOpen);
2373
+ useEscapeKey(onClose, isOpen);
2288
2374
  if (!mounted) {
2289
2375
  return null;
2290
2376
  }
@@ -2315,7 +2401,7 @@ var Drawer = ({
2315
2401
  className: cx(
2316
2402
  "fixed bg-charcoal border-ash shadow-2xl flex flex-col",
2317
2403
  "transition-transform duration-300 ease-out",
2318
- POSITION_CLASSES[position],
2404
+ POSITION_CLASSES2[position],
2319
2405
  SIZE_MAP2[size][position],
2320
2406
  position === "left" && "border-r",
2321
2407
  position === "right" && "border-l",
@@ -2342,8 +2428,8 @@ var Drawer = ({
2342
2428
  Drawer.displayName = "Drawer";
2343
2429
 
2344
2430
  // src/components/Popover.tsx
2345
- import React32, { useCallback as useCallback6, useEffect as useEffect4, useId, useRef as useRef3, useState as useState6 } from "react";
2346
- var POSITION_CLASSES2 = {
2431
+ import React32, { useCallback as useCallback7, useId as useId3, useRef as useRef4, useState as useState7 } from "react";
2432
+ var POSITION_CLASSES3 = {
2347
2433
  top: {
2348
2434
  start: "bottom-full left-0 mb-2",
2349
2435
  center: "bottom-full left-1/2 -translate-x-1/2 mb-2",
@@ -2374,12 +2460,12 @@ var Popover = ({
2374
2460
  onOpenChange,
2375
2461
  closeOnClickOutside = true
2376
2462
  }) => {
2377
- const [internalOpen, setInternalOpen] = useState6(false);
2463
+ const [internalOpen, setInternalOpen] = useState7(false);
2378
2464
  const isControlled = controlledOpen !== void 0;
2379
2465
  const isOpen = isControlled ? controlledOpen : internalOpen;
2380
- const containerRef = useRef3(null);
2381
- const baseId = useId();
2382
- const setIsOpen = useCallback6(
2466
+ const containerRef = useRef4(null);
2467
+ const baseId = useId3();
2468
+ const setIsOpen = useCallback7(
2383
2469
  (newOpen) => {
2384
2470
  if (!isControlled) {
2385
2471
  setInternalOpen(newOpen);
@@ -2388,30 +2474,9 @@ var Popover = ({
2388
2474
  },
2389
2475
  [isControlled, onOpenChange]
2390
2476
  );
2391
- useEffect4(() => {
2392
- if (!isOpen || !closeOnClickOutside) {
2393
- return;
2394
- }
2395
- const handleClickOutside = (e) => {
2396
- if (containerRef.current && !containerRef.current.contains(e.target)) {
2397
- setIsOpen(false);
2398
- }
2399
- };
2400
- document.addEventListener("mousedown", handleClickOutside);
2401
- return () => document.removeEventListener("mousedown", handleClickOutside);
2402
- }, [isOpen, closeOnClickOutside, setIsOpen]);
2403
- useEffect4(() => {
2404
- if (!isOpen) {
2405
- return;
2406
- }
2407
- const handleEscape = (e) => {
2408
- if (e.key === "Escape") {
2409
- setIsOpen(false);
2410
- }
2411
- };
2412
- document.addEventListener("keydown", handleEscape);
2413
- return () => document.removeEventListener("keydown", handleEscape);
2414
- }, [isOpen, setIsOpen]);
2477
+ const close = useCallback7(() => setIsOpen(false), [setIsOpen]);
2478
+ useClickOutside(containerRef, close, isOpen && closeOnClickOutside);
2479
+ useEscapeKey(close, isOpen);
2415
2480
  const handleTriggerClick = () => {
2416
2481
  setIsOpen(!isOpen);
2417
2482
  };
@@ -2432,7 +2497,7 @@ var Popover = ({
2432
2497
  "absolute z-50 min-w-48 p-4",
2433
2498
  "bg-charcoal border border-ash shadow-lg",
2434
2499
  "animate-fade-in",
2435
- POSITION_CLASSES2[position][align]
2500
+ POSITION_CLASSES3[position][align]
2436
2501
  )
2437
2502
  },
2438
2503
  children
@@ -2441,7 +2506,7 @@ var Popover = ({
2441
2506
  Popover.displayName = "Popover";
2442
2507
 
2443
2508
  // src/components/Dialog.tsx
2444
- import React33, { useCallback as useCallback7 } from "react";
2509
+ import React33, { useCallback as useCallback8 } from "react";
2445
2510
  var ConfirmDialog = ({
2446
2511
  title = "Confirm",
2447
2512
  description,
@@ -2454,11 +2519,11 @@ var ConfirmDialog = ({
2454
2519
  isLoading = false,
2455
2520
  ...props
2456
2521
  }) => {
2457
- const handleCancel = useCallback7(() => {
2522
+ const handleCancel = useCallback8(() => {
2458
2523
  onCancel?.();
2459
2524
  onClose();
2460
2525
  }, [onCancel, onClose]);
2461
- const handleConfirm = useCallback7(async () => {
2526
+ const handleConfirm = useCallback8(async () => {
2462
2527
  await onConfirm();
2463
2528
  onClose();
2464
2529
  }, [onConfirm, onClose]);
@@ -2502,11 +2567,11 @@ var PromptDialog = ({
2502
2567
  ...props
2503
2568
  }) => {
2504
2569
  const [value, setValue] = React33.useState(defaultValue);
2505
- const handleCancel = useCallback7(() => {
2570
+ const handleCancel = useCallback8(() => {
2506
2571
  onCancel?.();
2507
2572
  onClose();
2508
2573
  }, [onCancel, onClose]);
2509
- const handleSubmit = useCallback7(
2574
+ const handleSubmit = useCallback8(
2510
2575
  async (e) => {
2511
2576
  e.preventDefault();
2512
2577
  await onSubmit(value);
@@ -2543,7 +2608,7 @@ var PromptDialog = ({
2543
2608
  PromptDialog.displayName = "PromptDialog";
2544
2609
 
2545
2610
  // src/components/Tabs.tsx
2546
- import React34, { createContext as createContext3, useCallback as useCallback8, useContext as useContext3, useId as useId2, useState as useState7 } from "react";
2611
+ import React34, { createContext as createContext3, useCallback as useCallback9, useContext as useContext3, useId as useId4, useState as useState8 } from "react";
2547
2612
  var TabsContext = createContext3(null);
2548
2613
  function useTabsContext() {
2549
2614
  const context = useContext3(TabsContext);
@@ -2554,11 +2619,11 @@ function useTabsContext() {
2554
2619
  }
2555
2620
  var Tabs = React34.forwardRef(
2556
2621
  ({ defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2557
- const [internalValue, setInternalValue] = useState7(defaultValue ?? "");
2622
+ const [internalValue, setInternalValue] = useState8(defaultValue ?? "");
2558
2623
  const isControlled = value !== void 0;
2559
2624
  const activeTab = isControlled ? value : internalValue;
2560
- const baseId = useId2();
2561
- const setActiveTab = useCallback8(
2625
+ const baseId = useId4();
2626
+ const setActiveTab = useCallback9(
2562
2627
  (id) => {
2563
2628
  if (!isControlled) {
2564
2629
  setInternalValue(id);
@@ -2654,7 +2719,7 @@ var TabPanel = React34.forwardRef(
2654
2719
  TabPanel.displayName = "TabPanel";
2655
2720
 
2656
2721
  // src/components/Accordion.tsx
2657
- import React35, { createContext as createContext4, useCallback as useCallback9, useContext as useContext4, useId as useId3, useState as useState8 } from "react";
2722
+ import React35, { createContext as createContext4, useCallback as useCallback10, useContext as useContext4, useId as useId5, useState as useState9 } from "react";
2658
2723
  import { ChevronDown } from "lucide-react";
2659
2724
  var AccordionContext = createContext4(null);
2660
2725
  function useAccordionContext() {
@@ -2666,7 +2731,7 @@ function useAccordionContext() {
2666
2731
  }
2667
2732
  var Accordion = React35.forwardRef(
2668
2733
  ({ type = "single", defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2669
- const [internalValue, setInternalValue] = useState8(() => {
2734
+ const [internalValue, setInternalValue] = useState9(() => {
2670
2735
  if (defaultValue) {
2671
2736
  return new Set(Array.isArray(defaultValue) ? defaultValue : [defaultValue]);
2672
2737
  }
@@ -2674,7 +2739,7 @@ var Accordion = React35.forwardRef(
2674
2739
  });
2675
2740
  const isControlled = value !== void 0;
2676
2741
  const expandedItems = isControlled ? new Set(Array.isArray(value) ? value : [value]) : internalValue;
2677
- const toggleItem = useCallback9(
2742
+ const toggleItem = useCallback10(
2678
2743
  (id) => {
2679
2744
  const newSet = new Set(expandedItems);
2680
2745
  if (newSet.has(id)) {
@@ -2725,7 +2790,7 @@ var AccordionTrigger = React35.forwardRef(
2725
2790
  ({ children, className, ...props }, ref) => {
2726
2791
  const { expandedItems, toggleItem } = useAccordionContext();
2727
2792
  const itemContext = useContext4(AccordionItemContext);
2728
- const baseId = useId3();
2793
+ const baseId = useId5();
2729
2794
  if (!itemContext) {
2730
2795
  throw new Error("AccordionTrigger must be used within an AccordionItem");
2731
2796
  }
@@ -2770,7 +2835,7 @@ var AccordionContent = React35.forwardRef(
2770
2835
  ({ children, className, ...props }, ref) => {
2771
2836
  const { expandedItems } = useAccordionContext();
2772
2837
  const itemContext = useContext4(AccordionItemContext);
2773
- const baseId = useId3();
2838
+ const baseId = useId5();
2774
2839
  if (!itemContext) {
2775
2840
  throw new Error("AccordionContent must be used within an AccordionItem");
2776
2841
  }
@@ -2800,12 +2865,12 @@ AccordionContent.displayName = "AccordionContent";
2800
2865
  // src/components/Menu.tsx
2801
2866
  import React36, {
2802
2867
  createContext as createContext5,
2803
- useCallback as useCallback10,
2868
+ useCallback as useCallback11,
2804
2869
  useContext as useContext5,
2805
2870
  useEffect as useEffect5,
2806
- useId as useId4,
2807
- useRef as useRef4,
2808
- useState as useState9
2871
+ useId as useId6,
2872
+ useRef as useRef5,
2873
+ useState as useState10
2809
2874
  } from "react";
2810
2875
  var MenuContext = createContext5(null);
2811
2876
  function useMenuContext() {
@@ -2816,11 +2881,11 @@ function useMenuContext() {
2816
2881
  return context;
2817
2882
  }
2818
2883
  var Menu = ({ children, open, onOpenChange }) => {
2819
- const [internalOpen, setInternalOpen] = useState9(false);
2884
+ const [internalOpen, setInternalOpen] = useState10(false);
2820
2885
  const isControlled = open !== void 0;
2821
2886
  const isOpen = isControlled ? open : internalOpen;
2822
- const baseId = useId4();
2823
- const setIsOpen = useCallback10(
2887
+ const baseId = useId6();
2888
+ const setIsOpen = useCallback11(
2824
2889
  (newOpen) => {
2825
2890
  if (!isControlled) {
2826
2891
  setInternalOpen(newOpen);
@@ -2872,55 +2937,42 @@ var MenuTrigger = React36.forwardRef(
2872
2937
  }
2873
2938
  );
2874
2939
  MenuTrigger.displayName = "MenuTrigger";
2940
+ var MENU_ALIGN_CLASSES = {
2941
+ start: "left-0",
2942
+ center: "left-1/2 -translate-x-1/2",
2943
+ end: "right-0"
2944
+ };
2945
+ var MENU_SIDE_CLASSES = {
2946
+ top: "bottom-full mb-1",
2947
+ bottom: "top-full mt-1"
2948
+ };
2875
2949
  var MenuContent = React36.forwardRef(
2876
2950
  ({ children, className, align = "start", side = "bottom", ...props }, ref) => {
2877
2951
  const { isOpen, setIsOpen, triggerId, menuId } = useMenuContext();
2878
- const menuRef = useRef4(null);
2952
+ const menuRef = useRef5(null);
2953
+ const close = useCallback11(() => setIsOpen(false), [setIsOpen]);
2954
+ useEscapeKey(close, isOpen);
2879
2955
  useEffect5(() => {
2880
2956
  if (!isOpen) {
2881
2957
  return;
2882
2958
  }
2883
2959
  const handleClickOutside = (e) => {
2960
+ const target = e.target;
2884
2961
  const trigger = document.getElementById(triggerId);
2885
- if (menuRef.current && !menuRef.current.contains(e.target) && trigger && !trigger.contains(e.target)) {
2886
- setIsOpen(false);
2887
- }
2888
- };
2889
- const handleEscape = (e) => {
2890
- if (e.key === "Escape") {
2962
+ if (menuRef.current && !menuRef.current.contains(target) && !trigger?.contains(target)) {
2891
2963
  setIsOpen(false);
2892
2964
  }
2893
2965
  };
2894
2966
  document.addEventListener("mousedown", handleClickOutside);
2895
- document.addEventListener("keydown", handleEscape);
2896
- return () => {
2897
- document.removeEventListener("mousedown", handleClickOutside);
2898
- document.removeEventListener("keydown", handleEscape);
2899
- };
2967
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2900
2968
  }, [isOpen, setIsOpen, triggerId]);
2901
2969
  if (!isOpen) {
2902
2970
  return null;
2903
2971
  }
2904
- const alignmentClasses = {
2905
- start: "left-0",
2906
- center: "left-1/2 -translate-x-1/2",
2907
- end: "right-0"
2908
- };
2909
- const sideClasses = {
2910
- top: "bottom-full mb-1",
2911
- bottom: "top-full mt-1"
2912
- };
2913
2972
  return /* @__PURE__ */ React36.createElement(
2914
2973
  "div",
2915
2974
  {
2916
- ref: (node) => {
2917
- menuRef.current = node;
2918
- if (typeof ref === "function") {
2919
- ref(node);
2920
- } else if (ref) {
2921
- ref.current = node;
2922
- }
2923
- },
2975
+ ref: composeRefs(menuRef, ref),
2924
2976
  id: menuId,
2925
2977
  role: "menu",
2926
2978
  "aria-labelledby": triggerId,
@@ -2928,8 +2980,8 @@ var MenuContent = React36.forwardRef(
2928
2980
  "absolute z-50 min-w-40 py-1",
2929
2981
  "bg-charcoal border border-ash shadow-lg",
2930
2982
  "animate-fade-in",
2931
- alignmentClasses[align],
2932
- sideClasses[side],
2983
+ MENU_ALIGN_CLASSES[align],
2984
+ MENU_SIDE_CLASSES[side],
2933
2985
  className
2934
2986
  ),
2935
2987
  ...props
@@ -3653,12 +3705,19 @@ function SquareLoaderIcon({ className, ...props }) {
3653
3705
  }
3654
3706
 
3655
3707
  // src/components/Message.tsx
3656
- import React55, { useEffect as useEffect6, useRef as useRef5, useState as useState10 } from "react";
3708
+ import React55, { useCallback as useCallback12, useEffect as useEffect6, useRef as useRef6, useState as useState11 } from "react";
3709
+ import { Check as Check3, ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, Copy, GitBranch, Pencil, RotateCcw, Send, X as X5 } from "lucide-react";
3657
3710
 
3658
3711
  // src/components/MarkdownContent.tsx
3659
3712
  import React54, { useMemo } from "react";
3660
3713
  import DOMPurify from "dompurify";
3661
3714
  import { marked } from "marked";
3715
+ DOMPurify.addHook("afterSanitizeAttributes", (node) => {
3716
+ if (node.tagName === "A") {
3717
+ node.setAttribute("target", "_blank");
3718
+ node.setAttribute("rel", "noopener noreferrer");
3719
+ }
3720
+ });
3662
3721
  var DEFAULT_SANITIZE_CONFIG = {
3663
3722
  ALLOWED_TAGS: [
3664
3723
  "h1",
@@ -3726,16 +3785,6 @@ var DEFAULT_SANITIZE_CONFIG = {
3726
3785
  ADD_ATTR: ["target", "rel"],
3727
3786
  ALLOWED_URI_REGEXP: /^(?:(?:https?|mailto|tel):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i
3728
3787
  };
3729
- function useDOMPurifySetup() {
3730
- useMemo(() => {
3731
- DOMPurify.addHook("afterSanitizeAttributes", (node) => {
3732
- if (node.tagName === "A") {
3733
- node.setAttribute("target", "_blank");
3734
- node.setAttribute("rel", "noopener noreferrer");
3735
- }
3736
- });
3737
- }, []);
3738
- }
3739
3788
  var CURSOR_BASE_CLASSES = "inline-block bg-current animate-cursor-blink w-0.5 h-cursor translate-y-cursor-offset";
3740
3789
  function injectStreamingCursor(html, cursorClassName) {
3741
3790
  if (!html.trim()) {
@@ -3765,7 +3814,6 @@ function injectStreamingCursor(html, cursorClassName) {
3765
3814
  }
3766
3815
  var MarkdownContent = React54.forwardRef(
3767
3816
  ({ className, content, isMarkdown = true, sanitizeConfig, isStreaming, cursorClassName, ...rest }, ref) => {
3768
- useDOMPurifySetup();
3769
3817
  const sanitizedHtml = useMemo(() => {
3770
3818
  if (!content && !isStreaming) {
3771
3819
  return "";
@@ -3787,7 +3835,7 @@ var MarkdownContent = React54.forwardRef(
3787
3835
  return injectStreamingCursor(sanitized, cursorClassName);
3788
3836
  }
3789
3837
  return sanitized;
3790
- }, [content, sanitizeConfig, isStreaming, cursorClassName]);
3838
+ }, [content, isMarkdown, sanitizeConfig, isStreaming, cursorClassName]);
3791
3839
  return /* @__PURE__ */ React54.createElement(
3792
3840
  "div",
3793
3841
  {
@@ -3802,162 +3850,32 @@ var MarkdownContent = React54.forwardRef(
3802
3850
  MarkdownContent.displayName = "MarkdownContent";
3803
3851
 
3804
3852
  // src/components/Message.tsx
3805
- var variantStyles2 = {
3853
+ var VARIANT_STYLES3 = {
3806
3854
  user: "bg-gold text-obsidian ml-auto",
3807
3855
  assistant: "bg-charcoal border border-ash text-white mr-auto"
3808
3856
  };
3809
- var ActionButton = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React55.createElement(
3810
- "button",
3811
- {
3812
- type: "button",
3813
- onClick,
3814
- disabled,
3815
- className: cx(
3816
- "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
3817
- "hover:bg-white/5",
3818
- "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
3819
- className
3820
- ),
3821
- "aria-label": label
3822
- },
3823
- children
3824
- );
3825
- var CopyIcon = () => /* @__PURE__ */ React55.createElement(
3826
- "svg",
3827
- {
3828
- xmlns: "http://www.w3.org/2000/svg",
3829
- viewBox: "0 0 24 24",
3830
- fill: "none",
3831
- stroke: "currentColor",
3832
- strokeWidth: "2",
3833
- strokeLinecap: "round",
3834
- strokeLinejoin: "round",
3835
- className: "w-3.5 h-3.5"
3836
- },
3837
- /* @__PURE__ */ React55.createElement("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
3838
- /* @__PURE__ */ React55.createElement("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
3839
- );
3840
- var CheckIcon = () => /* @__PURE__ */ React55.createElement(
3841
- "svg",
3842
- {
3843
- xmlns: "http://www.w3.org/2000/svg",
3844
- viewBox: "0 0 24 24",
3845
- fill: "none",
3846
- stroke: "currentColor",
3847
- strokeWidth: "2",
3848
- strokeLinecap: "round",
3849
- strokeLinejoin: "round",
3850
- className: "w-3.5 h-3.5 text-success"
3851
- },
3852
- /* @__PURE__ */ React55.createElement("polyline", { points: "20 6 9 17 4 12" })
3853
- );
3854
- var PencilIcon = () => /* @__PURE__ */ React55.createElement(
3855
- "svg",
3856
- {
3857
- xmlns: "http://www.w3.org/2000/svg",
3858
- viewBox: "0 0 24 24",
3859
- fill: "none",
3860
- stroke: "currentColor",
3861
- strokeWidth: "2",
3862
- strokeLinecap: "round",
3863
- strokeLinejoin: "round",
3864
- className: "w-3.5 h-3.5"
3865
- },
3866
- /* @__PURE__ */ React55.createElement("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
3867
- /* @__PURE__ */ React55.createElement("path", { d: "m15 5 4 4" })
3857
+ var ACTION_BUTTON_CLASSES = cx(
3858
+ "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
3859
+ "hover:bg-white/5",
3860
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent"
3868
3861
  );
3869
- var RetryIcon = () => /* @__PURE__ */ React55.createElement(
3870
- "svg",
3871
- {
3872
- xmlns: "http://www.w3.org/2000/svg",
3873
- viewBox: "0 0 24 24",
3874
- fill: "none",
3875
- stroke: "currentColor",
3876
- strokeWidth: "2",
3877
- strokeLinecap: "round",
3878
- strokeLinejoin: "round",
3879
- className: "w-3.5 h-3.5"
3880
- },
3881
- /* @__PURE__ */ React55.createElement("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
3882
- /* @__PURE__ */ React55.createElement("path", { d: "M21 3v5h-5" }),
3883
- /* @__PURE__ */ React55.createElement("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
3884
- /* @__PURE__ */ React55.createElement("path", { d: "M8 16H3v5" })
3885
- );
3886
- var ChevronLeftIcon2 = () => /* @__PURE__ */ React55.createElement(
3887
- "svg",
3888
- {
3889
- xmlns: "http://www.w3.org/2000/svg",
3890
- viewBox: "0 0 24 24",
3891
- fill: "none",
3892
- stroke: "currentColor",
3893
- strokeWidth: "2",
3894
- strokeLinecap: "round",
3895
- strokeLinejoin: "round",
3896
- className: "w-3 h-3"
3897
- },
3898
- /* @__PURE__ */ React55.createElement("path", { d: "m15 18-6-6 6-6" })
3899
- );
3900
- var ChevronRightIcon2 = () => /* @__PURE__ */ React55.createElement(
3901
- "svg",
3902
- {
3903
- xmlns: "http://www.w3.org/2000/svg",
3904
- viewBox: "0 0 24 24",
3905
- fill: "none",
3906
- stroke: "currentColor",
3907
- strokeWidth: "2",
3908
- strokeLinecap: "round",
3909
- strokeLinejoin: "round",
3910
- className: "w-3 h-3"
3911
- },
3912
- /* @__PURE__ */ React55.createElement("path", { d: "m9 18 6-6-6-6" })
3913
- );
3914
- var GitBranchIcon = () => /* @__PURE__ */ React55.createElement(
3915
- "svg",
3916
- {
3917
- xmlns: "http://www.w3.org/2000/svg",
3918
- viewBox: "0 0 24 24",
3919
- fill: "none",
3920
- stroke: "currentColor",
3921
- strokeWidth: "2",
3922
- strokeLinecap: "round",
3923
- strokeLinejoin: "round",
3924
- className: "w-3 h-3 mr-0.5 text-silver/50"
3925
- },
3926
- /* @__PURE__ */ React55.createElement("line", { x1: "6", x2: "6", y1: "3", y2: "15" }),
3927
- /* @__PURE__ */ React55.createElement("circle", { cx: "18", cy: "6", r: "3" }),
3928
- /* @__PURE__ */ React55.createElement("circle", { cx: "6", cy: "18", r: "3" }),
3929
- /* @__PURE__ */ React55.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" })
3930
- );
3931
- var XIcon = () => /* @__PURE__ */ React55.createElement(
3932
- "svg",
3933
- {
3934
- xmlns: "http://www.w3.org/2000/svg",
3935
- viewBox: "0 0 24 24",
3936
- fill: "none",
3937
- stroke: "currentColor",
3938
- strokeWidth: "2",
3939
- strokeLinecap: "round",
3940
- strokeLinejoin: "round",
3941
- className: "w-4 h-4"
3942
- },
3943
- /* @__PURE__ */ React55.createElement("path", { d: "M18 6 6 18" }),
3944
- /* @__PURE__ */ React55.createElement("path", { d: "m6 6 12 12" })
3945
- );
3946
- var SendIcon = () => /* @__PURE__ */ React55.createElement(
3947
- "svg",
3948
- {
3949
- xmlns: "http://www.w3.org/2000/svg",
3950
- viewBox: "0 0 24 24",
3951
- fill: "none",
3952
- stroke: "currentColor",
3953
- strokeWidth: "2",
3954
- strokeLinecap: "round",
3955
- strokeLinejoin: "round",
3956
- className: "w-4 h-4"
3957
- },
3958
- /* @__PURE__ */ React55.createElement("path", { d: "m22 2-7 20-4-9-9-4Z" }),
3959
- /* @__PURE__ */ React55.createElement("path", { d: "M22 2 11 13" })
3862
+ var BRANCH_BUTTON_CLASSES = cx(
3863
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
3864
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
3960
3865
  );
3866
+ function ActionButton({ onClick, label, children, disabled }) {
3867
+ return /* @__PURE__ */ React55.createElement(
3868
+ "button",
3869
+ {
3870
+ type: "button",
3871
+ onClick,
3872
+ disabled,
3873
+ className: ACTION_BUTTON_CLASSES,
3874
+ "aria-label": label
3875
+ },
3876
+ children
3877
+ );
3878
+ }
3961
3879
  var Message = React55.forwardRef(
3962
3880
  ({
3963
3881
  variant = "assistant",
@@ -3970,10 +3888,10 @@ var Message = React55.forwardRef(
3970
3888
  ...rest
3971
3889
  }, ref) => {
3972
3890
  const isUser = variant === "user";
3973
- const [copied, setCopied] = useState10(false);
3974
- const [isEditing, setIsEditing] = useState10(false);
3975
- const [editValue, setEditValue] = useState10(typeof content === "string" ? content : "");
3976
- const textareaRef = useRef5(null);
3891
+ const { copied, copy } = useCopyToClipboard();
3892
+ const [isEditing, setIsEditing] = useState11(false);
3893
+ const [editValue, setEditValue] = useState11(typeof content === "string" ? content : "");
3894
+ const textareaRef = useRef6(null);
3977
3895
  const showBranchNav = branchInfo && branchInfo.total > 1;
3978
3896
  const showActions = actions && !hideActions && !isStreaming;
3979
3897
  useEffect6(() => {
@@ -3985,25 +3903,11 @@ var Message = React55.forwardRef(
3985
3903
  textarea.setSelectionRange(textarea.value.length, textarea.value.length);
3986
3904
  }
3987
3905
  }, [isEditing]);
3988
- const handleCopy = async () => {
3989
- if (typeof content !== "string") {
3990
- return;
3991
- }
3992
- try {
3993
- await navigator.clipboard.writeText(content);
3994
- setCopied(true);
3995
- setTimeout(() => setCopied(false), 2e3);
3996
- } catch {
3997
- const textArea = document.createElement("textarea");
3998
- textArea.value = content;
3999
- document.body.appendChild(textArea);
4000
- textArea.select();
4001
- document.execCommand("copy");
4002
- document.body.removeChild(textArea);
4003
- setCopied(true);
4004
- setTimeout(() => setCopied(false), 2e3);
3906
+ const handleCopy = useCallback12(() => {
3907
+ if (typeof content === "string") {
3908
+ void copy(content);
4005
3909
  }
4006
- };
3910
+ }, [copy, content]);
4007
3911
  const handleStartEdit = () => {
4008
3912
  if (typeof content === "string") {
4009
3913
  setEditValue(content);
@@ -4066,7 +3970,7 @@ var Message = React55.forwardRef(
4066
3970
  className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors",
4067
3971
  "aria-label": "Cancel edit"
4068
3972
  },
4069
- /* @__PURE__ */ React55.createElement(XIcon, null)
3973
+ /* @__PURE__ */ React55.createElement(X5, { className: "w-4 h-4" })
4070
3974
  ), /* @__PURE__ */ React55.createElement(
4071
3975
  "button",
4072
3976
  {
@@ -4076,13 +3980,13 @@ var Message = React55.forwardRef(
4076
3980
  className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors disabled:opacity-30",
4077
3981
  "aria-label": "Submit edit"
4078
3982
  },
4079
- /* @__PURE__ */ React55.createElement(SendIcon, null)
3983
+ /* @__PURE__ */ React55.createElement(Send, { className: "w-4 h-4" })
4080
3984
  )))) : /* @__PURE__ */ React55.createElement(
4081
3985
  "div",
4082
3986
  {
4083
3987
  className: cx(
4084
3988
  "px-3 py-2 w-fit max-w-11/12",
4085
- variantStyles2[variant]
3989
+ VARIANT_STYLES3[variant]
4086
3990
  )
4087
3991
  },
4088
3992
  typeof content === "string" ? /* @__PURE__ */ React55.createElement(
@@ -4104,33 +4008,27 @@ var Message = React55.forwardRef(
4104
4008
  onClick: handleCopy,
4105
4009
  label: copied ? "Copied!" : "Copy message"
4106
4010
  },
4107
- copied ? /* @__PURE__ */ React55.createElement(CheckIcon, null) : /* @__PURE__ */ React55.createElement(CopyIcon, null)
4108
- ), isUser && actions.onEdit && typeof content === "string" && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React55.createElement(PencilIcon, null)), !isUser && actions.onRetry && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: actions.onRetry, label: "Regenerate response" }, /* @__PURE__ */ React55.createElement(RetryIcon, null)), showBranchNav && /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement("div", { className: "w-px h-4 bg-ash/40 mx-1" }), /* @__PURE__ */ React55.createElement("div", { className: "flex items-center gap-0.5 text-silver/70" }, /* @__PURE__ */ React55.createElement(GitBranchIcon, null), /* @__PURE__ */ React55.createElement(
4011
+ copied ? /* @__PURE__ */ React55.createElement(Check3, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React55.createElement(Copy, { className: "w-3.5 h-3.5" })
4012
+ ), isUser && actions.onEdit && typeof content === "string" && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React55.createElement(Pencil, { className: "w-3.5 h-3.5" })), !isUser && actions.onRetry && /* @__PURE__ */ React55.createElement(ActionButton, { onClick: actions.onRetry, label: "Regenerate response" }, /* @__PURE__ */ React55.createElement(RotateCcw, { className: "w-3.5 h-3.5" })), showBranchNav && /* @__PURE__ */ React55.createElement(React55.Fragment, null, /* @__PURE__ */ React55.createElement("div", { className: "w-px h-4 bg-ash/40 mx-1" }), /* @__PURE__ */ React55.createElement("div", { className: "flex items-center gap-0.5 text-silver/70" }, /* @__PURE__ */ React55.createElement(GitBranch, { className: "w-3 h-3 mr-0.5 text-silver/50" }), /* @__PURE__ */ React55.createElement(
4109
4013
  "button",
4110
4014
  {
4111
4015
  type: "button",
4112
4016
  onClick: branchInfo.onPrevious,
4113
4017
  disabled: branchInfo.current <= 1,
4114
- className: cx(
4115
- "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4116
- "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4117
- ),
4018
+ className: BRANCH_BUTTON_CLASSES,
4118
4019
  "aria-label": "Previous branch"
4119
4020
  },
4120
- /* @__PURE__ */ React55.createElement(ChevronLeftIcon2, null)
4021
+ /* @__PURE__ */ React55.createElement(ChevronLeft2, { className: "w-3 h-3" })
4121
4022
  ), /* @__PURE__ */ React55.createElement("span", { className: "text-xs tabular-nums min-w-6 text-center" }, branchInfo.current, "/", branchInfo.total), /* @__PURE__ */ React55.createElement(
4122
4023
  "button",
4123
4024
  {
4124
4025
  type: "button",
4125
4026
  onClick: branchInfo.onNext,
4126
4027
  disabled: branchInfo.current >= branchInfo.total,
4127
- className: cx(
4128
- "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
4129
- "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
4130
- ),
4028
+ className: BRANCH_BUTTON_CLASSES,
4131
4029
  "aria-label": "Next branch"
4132
4030
  },
4133
- /* @__PURE__ */ React55.createElement(ChevronRightIcon2, null)
4031
+ /* @__PURE__ */ React55.createElement(ChevronRight3, { className: "w-3 h-3" })
4134
4032
  ))))
4135
4033
  );
4136
4034
  }
@@ -4141,7 +4039,7 @@ Message.displayName = "Message";
4141
4039
  import React56 from "react";
4142
4040
  var StreamingCursor = React56.forwardRef(
4143
4041
  ({ className, variant = "line", ...rest }, ref) => {
4144
- const variantStyles3 = {
4042
+ const variantStyles2 = {
4145
4043
  block: "w-2.5 h-cursor translate-y-cursor-offset",
4146
4044
  line: "w-0.5 h-cursor translate-y-cursor-offset",
4147
4045
  underscore: "w-2.5 h-0.5 self-end mb-0.5"
@@ -4152,7 +4050,7 @@ var StreamingCursor = React56.forwardRef(
4152
4050
  ref,
4153
4051
  className: cx(
4154
4052
  "inline-block bg-current animate-cursor-blink",
4155
- variantStyles3[variant],
4053
+ variantStyles2[variant],
4156
4054
  className
4157
4055
  ),
4158
4056
  "aria-hidden": "true",
@@ -4164,18 +4062,18 @@ var StreamingCursor = React56.forwardRef(
4164
4062
  StreamingCursor.displayName = "StreamingCursor";
4165
4063
 
4166
4064
  // src/components/chat/ChatInterface.tsx
4167
- import React74, { useCallback as useCallback20, useEffect as useEffect16, useMemo as useMemo5, useRef as useRef14, useState as useState21 } from "react";
4065
+ import React74, { useCallback as useCallback22, useEffect as useEffect16, useMemo as useMemo5, useRef as useRef15, useState as useState22 } from "react";
4168
4066
 
4169
4067
  // src/components/chat/ChatView.tsx
4170
4068
  import React58, { useEffect as useEffect9 } from "react";
4171
4069
 
4172
4070
  // src/components/chat/hooks/useScrollAnchor.ts
4173
- import { useCallback as useCallback11, useRef as useRef6 } from "react";
4071
+ import { useCallback as useCallback13, useRef as useRef7 } from "react";
4174
4072
  function useScrollAnchor(options = {}) {
4175
4073
  const { behavior = "smooth", block = "start" } = options;
4176
- const containerRef = useRef6(null);
4177
- const anchorRef = useRef6(null);
4178
- const scrollToAnchor = useCallback11(() => {
4074
+ const containerRef = useRef7(null);
4075
+ const anchorRef = useRef7(null);
4076
+ const scrollToAnchor = useCallback13(() => {
4179
4077
  const el = anchorRef.current;
4180
4078
  if (!el) {
4181
4079
  return;
@@ -4186,7 +4084,7 @@ function useScrollAnchor(options = {}) {
4186
4084
  });
4187
4085
  });
4188
4086
  }, [behavior, block]);
4189
- const scrollToBottom = useCallback11(() => {
4087
+ const scrollToBottom = useCallback13(() => {
4190
4088
  const container = containerRef.current;
4191
4089
  if (!container) {
4192
4090
  return;
@@ -4197,7 +4095,7 @@ function useScrollAnchor(options = {}) {
4197
4095
  container.scrollTop = container.scrollHeight;
4198
4096
  }
4199
4097
  }, [behavior]);
4200
- const isScrolledToBottom = useCallback11(() => {
4098
+ const isScrolledToBottom = useCallback13(() => {
4201
4099
  const container = containerRef.current;
4202
4100
  if (!container) {
4203
4101
  return true;
@@ -4216,15 +4114,15 @@ function useScrollAnchor(options = {}) {
4216
4114
  }
4217
4115
 
4218
4116
  // src/components/chat/hooks/useAdaptiveSpacer.ts
4219
- import { useCallback as useCallback12, useEffect as useEffect7, useRef as useRef7, useState as useState11 } from "react";
4117
+ import { useCallback as useCallback14, useEffect as useEffect7, useRef as useRef8, useState as useState12 } from "react";
4220
4118
  function useAdaptiveSpacer(options = {}) {
4221
4119
  const { minHeight = 0, containerRef: externalContainerRef, anchorRef } = options;
4222
- const internalContainerRef = useRef7(null);
4120
+ const internalContainerRef = useRef8(null);
4223
4121
  const containerRef = externalContainerRef ?? internalContainerRef;
4224
- const contentRef = useRef7(null);
4225
- const spacerRef = useRef7(null);
4226
- const [spacerHeight, setSpacerHeight] = useState11(0);
4227
- const recalculate = useCallback12(() => {
4122
+ const contentRef = useRef8(null);
4123
+ const spacerRef = useRef8(null);
4124
+ const [spacerHeight, setSpacerHeight] = useState12(0);
4125
+ const recalculate = useCallback14(() => {
4228
4126
  const container = containerRef.current;
4229
4127
  const content = contentRef.current;
4230
4128
  if (!container || !content) {
@@ -4283,7 +4181,7 @@ function useAdaptiveSpacer(options = {}) {
4283
4181
  }
4284
4182
 
4285
4183
  // src/components/chat/ThinkingIndicator.tsx
4286
- import React57, { useEffect as useEffect8, useState as useState12 } from "react";
4184
+ import React57, { useEffect as useEffect8, useState as useState13 } from "react";
4287
4185
  var THINKING_PHRASES = [
4288
4186
  "Consulting the ancient tomes...",
4289
4187
  "Parsing the ineffable...",
@@ -4307,22 +4205,29 @@ var ThinkingIndicator = React57.forwardRef(
4307
4205
  className,
4308
4206
  ...rest
4309
4207
  }, ref) => {
4310
- const [currentIndex, setCurrentIndex] = useState12(
4208
+ const [currentIndex, setCurrentIndex] = useState13(
4311
4209
  () => Math.floor(Math.random() * phrases.length)
4312
4210
  );
4313
- const [isTransitioning, setIsTransitioning] = useState12(false);
4211
+ const [isTransitioning, setIsTransitioning] = useState13(false);
4314
4212
  useEffect8(() => {
4315
4213
  if (!isVisible || phrases.length <= 1) {
4316
4214
  return;
4317
4215
  }
4216
+ let fadeTimeout = null;
4318
4217
  const interval = setInterval(() => {
4319
4218
  setIsTransitioning(true);
4320
- setTimeout(() => {
4219
+ fadeTimeout = setTimeout(() => {
4321
4220
  setCurrentIndex((prev) => (prev + 1) % phrases.length);
4322
4221
  setIsTransitioning(false);
4222
+ fadeTimeout = null;
4323
4223
  }, 200);
4324
4224
  }, phraseInterval);
4325
- return () => clearInterval(interval);
4225
+ return () => {
4226
+ clearInterval(interval);
4227
+ if (fadeTimeout !== null) {
4228
+ clearTimeout(fadeTimeout);
4229
+ }
4230
+ };
4326
4231
  }, [isVisible, phrases.length, phraseInterval]);
4327
4232
  if (!isVisible) {
4328
4233
  return null;
@@ -4401,15 +4306,7 @@ var ChatView = React58.forwardRef(
4401
4306
  return /* @__PURE__ */ React58.createElement(
4402
4307
  "div",
4403
4308
  {
4404
- ref: (node) => {
4405
- ;
4406
- containerRef.current = node;
4407
- if (typeof ref === "function") {
4408
- ref(node);
4409
- } else if (ref) {
4410
- ref.current = node;
4411
- }
4412
- },
4309
+ ref: composeRefs(containerRef, ref),
4413
4310
  onScroll,
4414
4311
  className: cx(
4415
4312
  "flex flex-col w-full h-full overflow-y-auto scroll-smooth",
@@ -4467,8 +4364,8 @@ var ChatView = React58.forwardRef(
4467
4364
  ChatView.displayName = "ChatView";
4468
4365
 
4469
4366
  // src/components/chat/ChatInput.tsx
4470
- import React59, { useCallback as useCallback13, useEffect as useEffect10, useRef as useRef8, useState as useState13 } from "react";
4471
- import { Paperclip, Send, Square, X as X5 } from "lucide-react";
4367
+ import React59, { useCallback as useCallback15, useEffect as useEffect10, useRef as useRef9, useState as useState14 } from "react";
4368
+ import { Paperclip, Send as Send2, Square, X as X6 } from "lucide-react";
4472
4369
 
4473
4370
  // src/components/chat/types.ts
4474
4371
  function isImageFile(file) {
@@ -4480,13 +4377,11 @@ function createPreviewUrl(file) {
4480
4377
  }
4481
4378
  return void 0;
4482
4379
  }
4483
- function revokePreviewUrl(url) {
4484
- if (url) {
4485
- URL.revokeObjectURL(url);
4486
- }
4487
- }
4488
4380
  function generateId() {
4489
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
4381
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
4382
+ return crypto.randomUUID();
4383
+ }
4384
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
4490
4385
  }
4491
4386
  function createEmptyTree() {
4492
4387
  return {
@@ -4656,13 +4551,13 @@ var ChatInput = React59.forwardRef(
4656
4551
  className,
4657
4552
  ...rest
4658
4553
  }, ref) => {
4659
- const [value, setValue] = useState13(initialInputValue);
4660
- const [localAttachments, setLocalAttachments] = useState13([]);
4661
- const [isDragOver, setIsDragOver] = useState13(false);
4662
- const textareaRef = useRef8(null);
4663
- const fileInputRef = useRef8(null);
4554
+ const [value, setValue] = useState14(initialInputValue);
4555
+ const [localAttachments, setLocalAttachments] = useState14([]);
4556
+ const [isDragOver, setIsDragOver] = useState14(false);
4557
+ const textareaRef = useRef9(null);
4558
+ const fileInputRef = useRef9(null);
4664
4559
  const attachments = controlledAttachments ?? localAttachments;
4665
- const setAttachments = useCallback13(
4560
+ const setAttachments = useCallback15(
4666
4561
  (newAttachments) => {
4667
4562
  if (onAttachmentsChange) {
4668
4563
  if (typeof newAttachments === "function") {
@@ -4676,7 +4571,7 @@ var ChatInput = React59.forwardRef(
4676
4571
  },
4677
4572
  [attachments, onAttachmentsChange]
4678
4573
  );
4679
- const handleSubmit = useCallback13(() => {
4574
+ const handleSubmit = useCallback15(() => {
4680
4575
  const trimmed = value.trim();
4681
4576
  if (!trimmed || disabled || isStreaming) {
4682
4577
  return;
@@ -4688,7 +4583,7 @@ var ChatInput = React59.forwardRef(
4688
4583
  textareaRef.current.style.height = "auto";
4689
4584
  }
4690
4585
  }, [value, disabled, isStreaming, onSubmit, attachments, setAttachments]);
4691
- const handleKeyDown = useCallback13(
4586
+ const handleKeyDown = useCallback15(
4692
4587
  (e) => {
4693
4588
  if (e.key === "Enter" && !e.shiftKey) {
4694
4589
  e.preventDefault();
@@ -4697,7 +4592,7 @@ var ChatInput = React59.forwardRef(
4697
4592
  },
4698
4593
  [handleSubmit]
4699
4594
  );
4700
- const handleChange = useCallback13((e) => {
4595
+ const handleChange = useCallback15((e) => {
4701
4596
  setValue(e.target.value);
4702
4597
  onInputChange?.(e.target.value);
4703
4598
  const textarea = e.target;
@@ -4709,7 +4604,7 @@ var ChatInput = React59.forwardRef(
4709
4604
  textareaRef.current.focus();
4710
4605
  }
4711
4606
  }, [disabled, isStreaming, autoFocus]);
4712
- const addFiles = useCallback13(
4607
+ const addFiles = useCallback15(
4713
4608
  (files) => {
4714
4609
  const newAttachments = Array.from(files).map((file) => ({
4715
4610
  id: generateId(),
@@ -4721,7 +4616,7 @@ var ChatInput = React59.forwardRef(
4721
4616
  },
4722
4617
  [setAttachments]
4723
4618
  );
4724
- const handleFileSelect = useCallback13(
4619
+ const handleFileSelect = useCallback15(
4725
4620
  (e) => {
4726
4621
  const files = e.target.files;
4727
4622
  if (files && files.length > 0) {
@@ -4731,7 +4626,7 @@ var ChatInput = React59.forwardRef(
4731
4626
  },
4732
4627
  [addFiles]
4733
4628
  );
4734
- const handleRemoveAttachment = useCallback13(
4629
+ const handleRemoveAttachment = useCallback15(
4735
4630
  (id) => {
4736
4631
  const attachment = attachments.find((a) => a.id === id);
4737
4632
  if (attachment && onAttachmentRemove) {
@@ -4747,23 +4642,23 @@ var ChatInput = React59.forwardRef(
4747
4642
  },
4748
4643
  [attachments, onAttachmentRemove, setAttachments]
4749
4644
  );
4750
- const handleDragEnter = useCallback13((e) => {
4645
+ const handleDragEnter = useCallback15((e) => {
4751
4646
  e.preventDefault();
4752
4647
  e.stopPropagation();
4753
4648
  setIsDragOver(true);
4754
4649
  }, []);
4755
- const handleDragLeave = useCallback13((e) => {
4650
+ const handleDragLeave = useCallback15((e) => {
4756
4651
  e.preventDefault();
4757
4652
  e.stopPropagation();
4758
4653
  if (!e.currentTarget.contains(e.relatedTarget)) {
4759
4654
  setIsDragOver(false);
4760
4655
  }
4761
4656
  }, []);
4762
- const handleDragOver = useCallback13((e) => {
4657
+ const handleDragOver = useCallback15((e) => {
4763
4658
  e.preventDefault();
4764
4659
  e.stopPropagation();
4765
4660
  }, []);
4766
- const handleDrop = useCallback13(
4661
+ const handleDrop = useCallback15(
4767
4662
  (e) => {
4768
4663
  e.preventDefault();
4769
4664
  e.stopPropagation();
@@ -4807,7 +4702,7 @@ var ChatInput = React59.forwardRef(
4807
4702
  notice.variant === "warning" ? "text-gold" : "text-error"
4808
4703
  )
4809
4704
  },
4810
- /* @__PURE__ */ React59.createElement(X5, { className: "w-3 h-3" })
4705
+ /* @__PURE__ */ React59.createElement(X6, { className: "w-3 h-3" })
4811
4706
  )),
4812
4707
  /* @__PURE__ */ React59.createElement(
4813
4708
  "div",
@@ -4906,7 +4801,7 @@ var ChatInput = React59.forwardRef(
4906
4801
  ),
4907
4802
  "aria-label": "Send message"
4908
4803
  },
4909
- /* @__PURE__ */ React59.createElement(Send, { className: "w-5 h-5" })
4804
+ /* @__PURE__ */ React59.createElement(Send2, { className: "w-5 h-5" })
4910
4805
  ))
4911
4806
  )
4912
4807
  );
@@ -4915,7 +4810,8 @@ var ChatInput = React59.forwardRef(
4915
4810
  ChatInput.displayName = "ChatInput";
4916
4811
 
4917
4812
  // src/components/chat/ArtifactsPanel.tsx
4918
- import React69, { useCallback as useCallback15, useEffect as useEffect12, useRef as useRef10, useState as useState16 } from "react";
4813
+ import React69, { useCallback as useCallback17, useEffect as useEffect12, useRef as useRef11, useState as useState17 } from "react";
4814
+ import { Image } from "lucide-react";
4919
4815
 
4920
4816
  // src/components/ArtifactCard.tsx
4921
4817
  import React66 from "react";
@@ -5119,15 +5015,7 @@ var AudioCard = React62.forwardRef(
5119
5015
  loop,
5120
5016
  width: "100%",
5121
5017
  height,
5122
- style: { backgroundColor: "transparent" },
5123
- config: {
5124
- file: {
5125
- forceAudio: true,
5126
- attributes: {
5127
- style: { width: "100%", height }
5128
- }
5129
- }
5130
- },
5018
+ style: { backgroundColor: "transparent", width: "100%", height },
5131
5019
  ...playerProps
5132
5020
  }
5133
5021
  ))),
@@ -5411,8 +5299,10 @@ var ArtifactCard = React66.forwardRef(
5411
5299
  )
5412
5300
  }
5413
5301
  );
5414
- default:
5415
- return null;
5302
+ default: {
5303
+ const _exhaustive = artifact.type;
5304
+ return _exhaustive;
5305
+ }
5416
5306
  }
5417
5307
  };
5418
5308
  const isCardExpandable = !!onExpand && (artifact.type === "IMAGE" || artifact.type === "PDF" || artifact.type === "SCRIPT" || artifact.type === "TEXT");
@@ -5449,7 +5339,7 @@ var ArtifactCard = React66.forwardRef(
5449
5339
  ArtifactCard.displayName = "ArtifactCard";
5450
5340
 
5451
5341
  // src/components/ArtifactGroup.tsx
5452
- import React67, { useEffect as useEffect11, useRef as useRef9, useState as useState14 } from "react";
5342
+ import React67, { useEffect as useEffect11, useRef as useRef10, useState as useState15 } from "react";
5453
5343
  var LAYER_OFFSET = "8px";
5454
5344
  var LAYER_OFFSET_2X = "16px";
5455
5345
  var ArtifactGroup = React67.forwardRef(
@@ -5457,8 +5347,8 @@ var ArtifactGroup = React67.forwardRef(
5457
5347
  const children = node.children;
5458
5348
  const count = children.length;
5459
5349
  const frontChild = children[0];
5460
- const prevCountRef = useRef9(count);
5461
- const [badgePing, setBadgePing] = useState14(false);
5350
+ const prevCountRef = useRef10(count);
5351
+ const [badgePing, setBadgePing] = useState15(false);
5462
5352
  useEffect11(() => {
5463
5353
  if (count !== prevCountRef.current) {
5464
5354
  prevCountRef.current = count;
@@ -5579,9 +5469,9 @@ var ArtifactVariantStack = React68.forwardRef(
5579
5469
  ArtifactVariantStack.displayName = "ArtifactVariantStack";
5580
5470
 
5581
5471
  // src/components/chat/hooks/useArtifactTreeNavigation.ts
5582
- import { useCallback as useCallback14, useMemo as useMemo2, useState as useState15 } from "react";
5472
+ import { useCallback as useCallback16, useMemo as useMemo2, useState as useState16 } from "react";
5583
5473
  function useArtifactTreeNavigation(rootNodes) {
5584
- const [stack, setStack] = useState15([]);
5474
+ const [stack, setStack] = useState16([]);
5585
5475
  const currentNodes = useMemo2(() => {
5586
5476
  if (stack.length === 0) return rootNodes;
5587
5477
  return stack[stack.length - 1].children;
@@ -5594,13 +5484,13 @@ function useArtifactTreeNavigation(rootNodes) {
5594
5484
  return entries;
5595
5485
  }, [stack]);
5596
5486
  const isAtRoot = stack.length === 0;
5597
- const navigateInto = useCallback14((node) => {
5487
+ const navigateInto = useCallback16((node) => {
5598
5488
  setStack((prev) => [...prev, node]);
5599
5489
  }, []);
5600
- const navigateTo = useCallback14((index) => {
5490
+ const navigateTo = useCallback16((index) => {
5601
5491
  setStack((prev) => prev.slice(0, index));
5602
5492
  }, []);
5603
- const navigateBack = useCallback14(() => {
5493
+ const navigateBack = useCallback16(() => {
5604
5494
  setStack((prev) => prev.slice(0, -1));
5605
5495
  }, []);
5606
5496
  return {
@@ -5619,16 +5509,8 @@ function ArtifactModal({
5619
5509
  artifact,
5620
5510
  onClose
5621
5511
  }) {
5622
- useEffect12(() => {
5623
- const handleKeyDown = (e) => {
5624
- if (e.key === "Escape") {
5625
- onClose();
5626
- }
5627
- };
5628
- document.addEventListener("keydown", handleKeyDown);
5629
- return () => document.removeEventListener("keydown", handleKeyDown);
5630
- }, [onClose]);
5631
- const handleBackdropClick = useCallback15((e) => {
5512
+ useEscapeKey(onClose);
5513
+ const handleBackdropClick = useCallback17((e) => {
5632
5514
  if (e.target === e.currentTarget) {
5633
5515
  onClose();
5634
5516
  }
@@ -5747,25 +5629,25 @@ var ArtifactsPanel = React69.forwardRef(
5747
5629
  className,
5748
5630
  ...rest
5749
5631
  }, ref) => {
5750
- const [expandedArtifact, setExpandedArtifact] = useState16(null);
5751
- const [zoomIndex, setZoomIndex] = useState16(ZOOM_LEVELS.length - 1);
5632
+ const [expandedArtifact, setExpandedArtifact] = useState17(null);
5633
+ const [zoomIndex, setZoomIndex] = useState17(ZOOM_LEVELS.length - 1);
5752
5634
  const treeNav = useArtifactTreeNavigation(nodes || []);
5753
5635
  const hasNodes = !!nodes && nodes.length > 0;
5754
- const handleExpandArtifact = useCallback15((artifact) => {
5636
+ const handleExpandArtifact = useCallback17((artifact) => {
5755
5637
  setExpandedArtifact(artifact);
5756
5638
  }, []);
5757
- const handleGroupClick = useCallback15((node) => {
5639
+ const handleGroupClick = useCallback17((node) => {
5758
5640
  treeNav.navigateInto(node);
5759
5641
  }, [treeNav]);
5760
- const zoomIn = useCallback15(() => {
5642
+ const zoomIn = useCallback17(() => {
5761
5643
  setZoomIndex((prev) => Math.min(prev + 1, ZOOM_LEVELS.length - 1));
5762
5644
  }, []);
5763
- const zoomOut = useCallback15(() => {
5645
+ const zoomOut = useCallback17(() => {
5764
5646
  setZoomIndex((prev) => Math.max(prev - 1, 0));
5765
5647
  }, []);
5766
5648
  const currentZoom = ZOOM_LEVELS[zoomIndex];
5767
- const contentRef = useRef10(null);
5768
- const [contentHeight, setContentHeight] = useState16(void 0);
5649
+ const contentRef = useRef11(null);
5650
+ const [contentHeight, setContentHeight] = useState17(void 0);
5769
5651
  useEffect12(() => {
5770
5652
  const el = contentRef.current;
5771
5653
  if (!el) return;
@@ -5911,23 +5793,7 @@ var ArtifactsPanelToggle = React69.forwardRef(({ artifactCount = 0, onExpand, cl
5911
5793
  "aria-label": "Expand artifacts panel",
5912
5794
  ...rest
5913
5795
  },
5914
- /* @__PURE__ */ React69.createElement(
5915
- "svg",
5916
- {
5917
- xmlns: "http://www.w3.org/2000/svg",
5918
- viewBox: "0 0 20 20",
5919
- fill: "currentColor",
5920
- className: "w-5 h-5"
5921
- },
5922
- /* @__PURE__ */ React69.createElement(
5923
- "path",
5924
- {
5925
- fillRule: "evenodd",
5926
- d: "M2 4.5A1.5 1.5 0 013.5 3h13A1.5 1.5 0 0118 4.5v11a1.5 1.5 0 01-1.5 1.5h-13A1.5 1.5 0 012 15.5v-11zM4 5v1h1V5H4zm2 0v1h1V5H6zm7 0v1h1V5h-1zm2 0v1h1V5h-1zM4 14v1h1v-1H4zm2 0v1h1v-1H6zm7 0v1h1v-1h-1zm2 0v1h1v-1h-1zM8 8.118a.5.5 0 01.757-.429l4 2.382a.5.5 0 010 .858l-4 2.382A.5.5 0 018 12.882V8.118z",
5927
- clipRule: "evenodd"
5928
- }
5929
- )
5930
- ),
5796
+ /* @__PURE__ */ React69.createElement(Image, { className: "w-5 h-5", "aria-hidden": true }),
5931
5797
  artifactCount > 0 && /* @__PURE__ */ React69.createElement(
5932
5798
  "span",
5933
5799
  {
@@ -5940,7 +5806,8 @@ var ArtifactsPanelToggle = React69.forwardRef(({ artifactCount = 0, onExpand, cl
5940
5806
  ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
5941
5807
 
5942
5808
  // src/components/chat/HistoryPanel.tsx
5943
- import React70, { useCallback as useCallback16, useEffect as useEffect13, useMemo as useMemo3, useRef as useRef11, useState as useState17 } from "react";
5809
+ import React70, { useCallback as useCallback18, useEffect as useEffect13, useMemo as useMemo3, useRef as useRef12, useState as useState18 } from "react";
5810
+ import { ChevronDown as ChevronDown2, Pencil as Pencil2 } from "lucide-react";
5944
5811
  function parseTimestamp(ts) {
5945
5812
  if (ts == null) {
5946
5813
  return null;
@@ -5976,64 +5843,16 @@ function groupConversations(conversations) {
5976
5843
  { key: "older", label: "Older", conversations: olderList }
5977
5844
  ].filter((g) => g.conversations.length > 0);
5978
5845
  }
5979
- function ChevronDownIcon({ className }) {
5980
- return /* @__PURE__ */ React70.createElement(
5981
- "svg",
5982
- {
5983
- xmlns: "http://www.w3.org/2000/svg",
5984
- viewBox: "0 0 20 20",
5985
- fill: "currentColor",
5986
- className,
5987
- "aria-hidden": "true"
5988
- },
5989
- /* @__PURE__ */ React70.createElement(
5990
- "path",
5991
- {
5992
- fillRule: "evenodd",
5993
- d: "M5.23 7.21a.75.75 0 011.06.02L10 11.06l3.71-3.83a.75.75 0 111.08 1.04l-4.25 4.39a.75.75 0 01-1.08 0L5.21 8.27a.75.75 0 01.02-1.06z",
5994
- clipRule: "evenodd"
5995
- }
5996
- )
5997
- );
5998
- }
5999
- function PencilIcon2({ className }) {
6000
- return /* @__PURE__ */ React70.createElement(
6001
- "svg",
6002
- {
6003
- xmlns: "http://www.w3.org/2000/svg",
6004
- viewBox: "0 0 20 20",
6005
- fill: "currentColor",
6006
- className,
6007
- "aria-hidden": "true"
6008
- },
6009
- /* @__PURE__ */ React70.createElement(
6010
- "path",
6011
- {
6012
- d: "M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"
6013
- }
6014
- )
6015
- );
6016
- }
6017
5846
  function ProjectFilter({
6018
5847
  projects,
6019
5848
  value,
6020
5849
  onChange,
6021
5850
  className
6022
5851
  }) {
6023
- const [open, setOpen] = useState17(false);
6024
- const ref = useRef11(null);
6025
- useEffect13(() => {
6026
- if (!open) {
6027
- return;
6028
- }
6029
- const handler = (e) => {
6030
- if (ref.current && !ref.current.contains(e.target)) {
6031
- setOpen(false);
6032
- }
6033
- };
6034
- document.addEventListener("mousedown", handler);
6035
- return () => document.removeEventListener("mousedown", handler);
6036
- }, [open]);
5852
+ const [open, setOpen] = useState18(false);
5853
+ const ref = useRef12(null);
5854
+ const closeFilter = useCallback18(() => setOpen(false), []);
5855
+ useClickOutside(ref, closeFilter, open);
6037
5856
  const label = value ?? "All projects";
6038
5857
  return /* @__PURE__ */ React70.createElement("div", { className: cx("relative min-w-0", className), ref }, /* @__PURE__ */ React70.createElement(
6039
5858
  "button",
@@ -6052,7 +5871,7 @@ function ProjectFilter({
6052
5871
  )
6053
5872
  },
6054
5873
  /* @__PURE__ */ React70.createElement("span", { className: "truncate" }, label),
6055
- /* @__PURE__ */ React70.createElement(ChevronDownIcon, { className: "w-3 h-3 shrink-0" })
5874
+ /* @__PURE__ */ React70.createElement(ChevronDown2, { className: "w-3 h-3 shrink-0", "aria-hidden": true })
6056
5875
  ), open && /* @__PURE__ */ React70.createElement(
6057
5876
  "div",
6058
5877
  {
@@ -6107,28 +5926,28 @@ function ConversationRow({
6107
5926
  onSelect,
6108
5927
  onRename
6109
5928
  }) {
6110
- const [isEditing, setIsEditing] = useState17(false);
6111
- const [draft, setDraft] = useState17(conversation.title);
6112
- const inputRef = useRef11(null);
5929
+ const [isEditing, setIsEditing] = useState18(false);
5930
+ const [draft, setDraft] = useState18(conversation.title);
5931
+ const inputRef = useRef12(null);
6113
5932
  useEffect13(() => {
6114
5933
  if (isEditing && inputRef.current) {
6115
5934
  inputRef.current.focus();
6116
5935
  inputRef.current.select();
6117
5936
  }
6118
5937
  }, [isEditing]);
6119
- const startEdit = useCallback16((e) => {
5938
+ const startEdit = useCallback18((e) => {
6120
5939
  e.stopPropagation();
6121
5940
  setDraft(conversation.title);
6122
5941
  setIsEditing(true);
6123
5942
  }, [conversation.title]);
6124
- const commit = useCallback16(() => {
5943
+ const commit = useCallback18(() => {
6125
5944
  const trimmed = draft.trim();
6126
5945
  if (trimmed && trimmed !== conversation.title) {
6127
5946
  onRename?.(conversation.id, trimmed);
6128
5947
  }
6129
5948
  setIsEditing(false);
6130
5949
  }, [draft, conversation.id, conversation.title, onRename]);
6131
- const cancel = useCallback16(() => {
5950
+ const cancel = useCallback18(() => {
6132
5951
  setDraft(conversation.title);
6133
5952
  setIsEditing(false);
6134
5953
  }, [conversation.title]);
@@ -6203,7 +6022,7 @@ function ConversationRow({
6203
6022
  "transition-opacity duration-150"
6204
6023
  )
6205
6024
  },
6206
- /* @__PURE__ */ React70.createElement(PencilIcon2, { className: "w-3.5 h-3.5" })
6025
+ /* @__PURE__ */ React70.createElement(Pencil2, { className: "w-3.5 h-3.5", "aria-hidden": true })
6207
6026
  ));
6208
6027
  }
6209
6028
  function HistoryPanel({
@@ -6212,7 +6031,7 @@ function HistoryPanel({
6212
6031
  onNewChat,
6213
6032
  onRenameConversation
6214
6033
  }) {
6215
- const [projectFilter, setProjectFilter] = useState17(null);
6034
+ const [projectFilter, setProjectFilter] = useState18(null);
6216
6035
  const projects = useMemo3(() => {
6217
6036
  const set = /* @__PURE__ */ new Set();
6218
6037
  for (const c of conversations) {
@@ -6278,7 +6097,7 @@ function HistoryPanel({
6278
6097
  }
6279
6098
 
6280
6099
  // src/components/chat/TodosList.tsx
6281
- import React71, { useCallback as useCallback17, useMemo as useMemo4, useState as useState18 } from "react";
6100
+ import React71, { useCallback as useCallback19, useMemo as useMemo4, useState as useState19 } from "react";
6282
6101
  import { Loader2 as Loader22, Square as Square2 } from "lucide-react";
6283
6102
  var TASK_STATUSES = {
6284
6103
  PENDING: "pending",
@@ -6357,8 +6176,8 @@ function hasInProgressTask(tasks) {
6357
6176
  var TodosList = React71.forwardRef(
6358
6177
  ({ tasks, title = "Tasks", onStopAllTasks, className, ...rest }, ref) => {
6359
6178
  const sortedTasks = useMemo4(() => sortTasks(tasks), [tasks]);
6360
- const [isStopping, setIsStopping] = useState18(false);
6361
- const handleStopClick = useCallback17(async () => {
6179
+ const [isStopping, setIsStopping] = useState19(false);
6180
+ const handleStopClick = useCallback19(async () => {
6362
6181
  if (!onStopAllTasks || isStopping) {
6363
6182
  return;
6364
6183
  }
@@ -6483,7 +6302,7 @@ var ToolSidebar = React72.forwardRef(
6483
6302
  ToolSidebar.displayName = "ToolSidebar";
6484
6303
 
6485
6304
  // src/components/chat/ToolPanelContainer.tsx
6486
- import React73, { useCallback as useCallback18, useEffect as useEffect14, useRef as useRef12, useState as useState19 } from "react";
6305
+ import React73, { useCallback as useCallback20, useEffect as useEffect14, useRef as useRef13, useState as useState20 } from "react";
6487
6306
  var ToolPanelContainer = React73.forwardRef(
6488
6307
  ({
6489
6308
  topContent,
@@ -6495,21 +6314,21 @@ var ToolPanelContainer = React73.forwardRef(
6495
6314
  initialTopPercent = 60,
6496
6315
  ...rest
6497
6316
  }, ref) => {
6498
- const [topPercent, setTopPercent] = useState19(initialTopPercent);
6499
- const [isResizingHeight, setIsResizingHeight] = useState19(false);
6500
- const containerRef = useRef12(null);
6501
- const lastY = useRef12(null);
6317
+ const [topPercent, setTopPercent] = useState20(initialTopPercent);
6318
+ const [isResizingHeight, setIsResizingHeight] = useState20(false);
6319
+ const containerRef = useRef13(null);
6320
+ const lastY = useRef13(null);
6502
6321
  const hasBoth = topContent !== null && bottomContent !== null;
6503
- const startHeightResize = useCallback18((e) => {
6322
+ const startHeightResize = useCallback20((e) => {
6504
6323
  e.preventDefault();
6505
6324
  setIsResizingHeight(true);
6506
6325
  lastY.current = e.clientY;
6507
6326
  }, []);
6508
- const stopHeightResize = useCallback18(() => {
6327
+ const stopHeightResize = useCallback20(() => {
6509
6328
  setIsResizingHeight(false);
6510
6329
  lastY.current = null;
6511
6330
  }, []);
6512
- const resizeHeight = useCallback18(
6331
+ const resizeHeight = useCallback20(
6513
6332
  (e) => {
6514
6333
  if (!isResizingHeight || lastY.current === null || !containerRef.current) {
6515
6334
  return;
@@ -6550,14 +6369,7 @@ var ToolPanelContainer = React73.forwardRef(
6550
6369
  return /* @__PURE__ */ React73.createElement(
6551
6370
  "div",
6552
6371
  {
6553
- ref: (node) => {
6554
- containerRef.current = node;
6555
- if (typeof ref === "function") {
6556
- ref(node);
6557
- } else if (ref) {
6558
- ref.current = node;
6559
- }
6560
- },
6372
+ ref: composeRefs(containerRef, ref),
6561
6373
  className: cx(
6562
6374
  "h-full bg-charcoal/50 flex flex-col relative shrink-0",
6563
6375
  side === "left" ? "border-r border-ash/40" : "border-l border-ash/40",
@@ -6611,26 +6423,26 @@ var ToolPanelContainer = React73.forwardRef(
6611
6423
  ToolPanelContainer.displayName = "ToolPanelContainer";
6612
6424
 
6613
6425
  // src/components/chat/hooks/useResizable.ts
6614
- import { useCallback as useCallback19, useEffect as useEffect15, useRef as useRef13, useState as useState20 } from "react";
6426
+ import { useCallback as useCallback21, useEffect as useEffect15, useRef as useRef14, useState as useState21 } from "react";
6615
6427
  function useResizable({
6616
6428
  initialWidthPercent,
6617
6429
  minWidthPercent,
6618
6430
  maxWidthPercent,
6619
6431
  direction
6620
6432
  }) {
6621
- const [widthPercent, setWidthPercent] = useState20(initialWidthPercent);
6622
- const [isResizing, setIsResizing] = useState20(false);
6623
- const lastX = useRef13(null);
6624
- const startResizing = useCallback19((e) => {
6433
+ const [widthPercent, setWidthPercent] = useState21(initialWidthPercent);
6434
+ const [isResizing, setIsResizing] = useState21(false);
6435
+ const lastX = useRef14(null);
6436
+ const startResizing = useCallback21((e) => {
6625
6437
  e.preventDefault();
6626
6438
  setIsResizing(true);
6627
6439
  lastX.current = e.clientX;
6628
6440
  }, []);
6629
- const stopResizing = useCallback19(() => {
6441
+ const stopResizing = useCallback21(() => {
6630
6442
  setIsResizing(false);
6631
6443
  lastX.current = null;
6632
6444
  }, []);
6633
- const resize = useCallback19(
6445
+ const resize = useCallback21(
6634
6446
  (e) => {
6635
6447
  if (!isResizing || lastX.current === null) {
6636
6448
  return;
@@ -6707,15 +6519,15 @@ var ChatInterface = React74.forwardRef(
6707
6519
  className,
6708
6520
  ...rest
6709
6521
  }, ref) => {
6710
- const prevArtifactNodesRef = useRef14([]);
6711
- const prevTasksRef = useRef14([]);
6712
- const [internalTools, setInternalTools] = useState21({
6522
+ const prevArtifactNodesRef = useRef15([]);
6523
+ const prevTasksRef = useRef15([]);
6524
+ const [internalTools, setInternalTools] = useState22({
6713
6525
  "top-left": "history",
6714
6526
  "bottom-left": null,
6715
6527
  "top-right": null,
6716
6528
  "bottom-right": null
6717
6529
  });
6718
- const dismissedToolsRef = useRef14(/* @__PURE__ */ new Set());
6530
+ const dismissedToolsRef = useRef15(/* @__PURE__ */ new Set());
6719
6531
  const isPanelControlled = isArtifactsPanelOpen !== void 0;
6720
6532
  const activeTools = useMemo5(() => {
6721
6533
  if (isPanelControlled) {
@@ -6761,7 +6573,7 @@ var ChatInterface = React74.forwardRef(
6761
6573
  const external = externalTools.map(({ content: _content, ...def }) => def);
6762
6574
  return [...builtIn, ...external];
6763
6575
  }, [allSettled, externalTools]);
6764
- const toggleTool = useCallback20((toolId) => {
6576
+ const toggleTool = useCallback22((toolId) => {
6765
6577
  const toolDef = allToolDefinitions.find((t) => t.id === toolId);
6766
6578
  if (!toolDef) {
6767
6579
  return;
@@ -6830,7 +6642,7 @@ var ChatInterface = React74.forwardRef(
6830
6642
  prevArtifactNodesRef.current = nodes;
6831
6643
  prevTasksRef.current = tasks;
6832
6644
  }, [artifactNodes, tasks, isPanelControlled]);
6833
- const handleBranchSwitch = useCallback20(
6645
+ const handleBranchSwitch = useCallback22(
6834
6646
  (nodeId, direction) => {
6835
6647
  if (!isTreeMode || !conversationTree || !onTreeChange) {
6836
6648
  return;
@@ -6883,7 +6695,7 @@ var ChatInterface = React74.forwardRef(
6883
6695
  onRetryMessage,
6884
6696
  handleBranchSwitch
6885
6697
  ]);
6886
- const handleSubmit = useCallback20(
6698
+ const handleSubmit = useCallback22(
6887
6699
  (message, attachments) => {
6888
6700
  onMessageSubmit?.(message, attachments);
6889
6701
  },
@@ -7038,8 +6850,8 @@ var ChatInterface = React74.forwardRef(
7038
6850
  ChatInterface.displayName = "ChatInterface";
7039
6851
 
7040
6852
  // src/components/chat/MessageActions.tsx
7041
- import React75, { useCallback as useCallback21, useState as useState22 } from "react";
7042
- import { Check as Check3, Copy, Pencil, RotateCcw, Send as Send2, X as X6 } from "lucide-react";
6853
+ import React75, { useCallback as useCallback23, useState as useState23 } from "react";
6854
+ import { Check as Check4, Copy as Copy2, Pencil as Pencil3, RotateCcw as RotateCcw2, Send as Send3, X as X7 } from "lucide-react";
7043
6855
  var ActionButton2 = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React75.createElement(
7044
6856
  "button",
7045
6857
  {
@@ -7068,12 +6880,12 @@ var MessageActions = React75.forwardRef(
7068
6880
  className,
7069
6881
  ...rest
7070
6882
  }, ref) => {
7071
- const [localIsEditing, setLocalIsEditing] = useState22(false);
7072
- const [localEditValue, setLocalEditValue] = useState22(content);
7073
- const [copied, setCopied] = useState22(false);
6883
+ const [localIsEditing, setLocalIsEditing] = useState23(false);
6884
+ const [localEditValue, setLocalEditValue] = useState23(content);
6885
+ const { copied, copy } = useCopyToClipboard();
7074
6886
  const isEditing = controlledIsEditing ?? localIsEditing;
7075
6887
  const editValue = controlledEditValue ?? localEditValue;
7076
- const setIsEditing = useCallback21(
6888
+ const setIsEditing = useCallback23(
7077
6889
  (value) => {
7078
6890
  if (onEditingChange) {
7079
6891
  onEditingChange(value);
@@ -7083,41 +6895,28 @@ var MessageActions = React75.forwardRef(
7083
6895
  },
7084
6896
  [onEditingChange]
7085
6897
  );
7086
- const setEditValue = useCallback21((value) => {
6898
+ const setEditValue = useCallback23((value) => {
7087
6899
  setLocalEditValue(value);
7088
6900
  }, []);
7089
- const handleCopy = useCallback21(async () => {
7090
- try {
7091
- await navigator.clipboard.writeText(content);
7092
- setCopied(true);
7093
- setTimeout(() => setCopied(false), 2e3);
7094
- } catch {
7095
- const textArea = document.createElement("textarea");
7096
- textArea.value = content;
7097
- document.body.appendChild(textArea);
7098
- textArea.select();
7099
- document.execCommand("copy");
7100
- document.body.removeChild(textArea);
7101
- setCopied(true);
7102
- setTimeout(() => setCopied(false), 2e3);
7103
- }
7104
- }, [content]);
7105
- const handleStartEdit = useCallback21(() => {
6901
+ const handleCopy = useCallback23(() => {
6902
+ void copy(content);
6903
+ }, [copy, content]);
6904
+ const handleStartEdit = useCallback23(() => {
7106
6905
  setLocalEditValue(content);
7107
6906
  setIsEditing(true);
7108
6907
  }, [content, setIsEditing]);
7109
- const handleCancelEdit = useCallback21(() => {
6908
+ const handleCancelEdit = useCallback23(() => {
7110
6909
  setIsEditing(false);
7111
6910
  setLocalEditValue(content);
7112
6911
  }, [content, setIsEditing]);
7113
- const handleSubmitEdit = useCallback21(() => {
6912
+ const handleSubmitEdit = useCallback23(() => {
7114
6913
  const trimmed = editValue.trim();
7115
6914
  if (trimmed && trimmed !== content) {
7116
6915
  onEdit?.(trimmed);
7117
6916
  }
7118
6917
  setIsEditing(false);
7119
6918
  }, [editValue, content, onEdit, setIsEditing]);
7120
- const handleEditKeyDown = useCallback21(
6919
+ const handleEditKeyDown = useCallback23(
7121
6920
  (e) => {
7122
6921
  if (e.key === "Enter" && !e.shiftKey) {
7123
6922
  e.preventDefault();
@@ -7160,7 +6959,7 @@ var MessageActions = React75.forwardRef(
7160
6959
  label: "Cancel edit",
7161
6960
  className: "text-silver/60 hover:text-error"
7162
6961
  },
7163
- /* @__PURE__ */ React75.createElement(X6, { className: "w-4 h-4" })
6962
+ /* @__PURE__ */ React75.createElement(X7, { className: "w-4 h-4" })
7164
6963
  ), /* @__PURE__ */ React75.createElement(
7165
6964
  ActionButton2,
7166
6965
  {
@@ -7169,7 +6968,7 @@ var MessageActions = React75.forwardRef(
7169
6968
  className: "text-silver/60 hover:text-gold",
7170
6969
  disabled: !editValue.trim() || editValue.trim() === content
7171
6970
  },
7172
- /* @__PURE__ */ React75.createElement(Send2, { className: "w-4 h-4" })
6971
+ /* @__PURE__ */ React75.createElement(Send3, { className: "w-4 h-4" })
7173
6972
  ))
7174
6973
  ),
7175
6974
  /* @__PURE__ */ React75.createElement("p", { className: "text-xs text-silver/50 mt-1" }, "Press Enter to submit, Esc to cancel. This will create a new branch.")
@@ -7186,9 +6985,9 @@ var MessageActions = React75.forwardRef(
7186
6985
  ),
7187
6986
  ...rest
7188
6987
  },
7189
- /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React75.createElement(Check3, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React75.createElement(Copy, { className: "w-3.5 h-3.5" })),
7190
- isUser && onEdit && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React75.createElement(Pencil, { className: "w-3.5 h-3.5" })),
7191
- !isUser && onRetry && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: onRetry, label: "Regenerate response" }, /* @__PURE__ */ React75.createElement(RotateCcw, { className: "w-3.5 h-3.5" }))
6988
+ /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React75.createElement(Check4, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React75.createElement(Copy2, { className: "w-3.5 h-3.5" })),
6989
+ isUser && onEdit && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React75.createElement(Pencil3, { className: "w-3.5 h-3.5" })),
6990
+ !isUser && onRetry && /* @__PURE__ */ React75.createElement(ActionButton2, { onClick: onRetry, label: "Regenerate response" }, /* @__PURE__ */ React75.createElement(RotateCcw2, { className: "w-3.5 h-3.5" }))
7192
6991
  );
7193
6992
  }
7194
6993
  );
@@ -7196,7 +6995,7 @@ MessageActions.displayName = "MessageActions";
7196
6995
 
7197
6996
  // src/components/chat/BranchNavigator.tsx
7198
6997
  import React76 from "react";
7199
- import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, GitBranch } from "lucide-react";
6998
+ import { ChevronLeft as ChevronLeft3, ChevronRight as ChevronRight4, GitBranch as GitBranch2 } from "lucide-react";
7200
6999
  var BranchNavigator = React76.forwardRef(
7201
7000
  ({
7202
7001
  current,
@@ -7228,7 +7027,7 @@ var BranchNavigator = React76.forwardRef(
7228
7027
  "aria-label": "Branch navigation",
7229
7028
  ...rest
7230
7029
  },
7231
- showIcon && /* @__PURE__ */ React76.createElement(GitBranch, { className: cx(iconSize, "mr-0.5 text-silver/50"), "aria-hidden": "true" }),
7030
+ showIcon && /* @__PURE__ */ React76.createElement(GitBranch2, { className: cx(iconSize, "mr-0.5 text-silver/50"), "aria-hidden": "true" }),
7232
7031
  /* @__PURE__ */ React76.createElement(
7233
7032
  "button",
7234
7033
  {
@@ -7242,7 +7041,7 @@ var BranchNavigator = React76.forwardRef(
7242
7041
  ),
7243
7042
  "aria-label": "Previous branch"
7244
7043
  },
7245
- /* @__PURE__ */ React76.createElement(ChevronLeft2, { className: iconSize })
7044
+ /* @__PURE__ */ React76.createElement(ChevronLeft3, { className: iconSize })
7246
7045
  ),
7247
7046
  /* @__PURE__ */ React76.createElement("span", { className: cx(textSize, "tabular-nums min-w-6 text-center") }, current, "/", total),
7248
7047
  /* @__PURE__ */ React76.createElement(
@@ -7258,7 +7057,7 @@ var BranchNavigator = React76.forwardRef(
7258
7057
  ),
7259
7058
  "aria-label": "Next branch"
7260
7059
  },
7261
- /* @__PURE__ */ React76.createElement(ChevronRight3, { className: iconSize })
7060
+ /* @__PURE__ */ React76.createElement(ChevronRight4, { className: iconSize })
7262
7061
  )
7263
7062
  );
7264
7063
  }
@@ -7476,14 +7275,11 @@ export {
7476
7275
  addMessageToTree,
7477
7276
  areAllTasksSettled,
7478
7277
  createEmptyTree,
7479
- createPreviewUrl,
7480
7278
  generateId,
7481
7279
  getActivePathMessages,
7482
7280
  getSiblingInfo,
7483
7281
  isBranchPoint,
7484
- isImageFile,
7485
7282
  messagesToTree,
7486
- revokePreviewUrl,
7487
7283
  switchBranch,
7488
7284
  updateNodeContent,
7489
7285
  useArtifactTreeNavigation,