@lukeashford/aurelius 2.9.0 → 2.10.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
@@ -860,7 +860,7 @@ var Tooltip = ({ content, children, open = false, side = "top" }) => {
860
860
  {
861
861
  role: "tooltip",
862
862
  className: cx(
863
- "pointer-events-none absolute z-50 whitespace-nowrap rounded-md border border-ash bg-graphite px-3 py-1.5 text-sm text-white shadow-lg transition-opacity duration-200 ease-out",
863
+ "pointer-events-none absolute z-50 whitespace-nowrap border border-ash bg-graphite px-3 py-1.5 text-sm text-white shadow-lg transition-opacity duration-200 ease-out",
864
864
  open ? "opacity-100" : "opacity-0",
865
865
  side === "top" && "left-1/2 -translate-x-1/2 -top-2 -translate-y-full",
866
866
  side === "bottom" && "left-1/2 -translate-x-1/2 -bottom-2 translate-y-full",
@@ -1070,11 +1070,152 @@ var ListSubheader = React13.forwardRef(
1070
1070
  );
1071
1071
  ListSubheader.displayName = "ListSubheader";
1072
1072
 
1073
- // src/components/Label.tsx
1073
+ // src/components/FileChip.tsx
1074
1074
  import React14 from "react";
1075
- var Label = React14.forwardRef(
1076
- ({ className, required, children, ...rest }, ref) => {
1075
+ import { File, FileImage, FileVideo, FileAudio, FileText, FileCode, FileArchive, X, Loader2 } from "lucide-react";
1076
+ function formatBytes(bytes) {
1077
+ if (bytes === 0) return "0 B";
1078
+ const k = 1024;
1079
+ const sizes = ["B", "KB", "MB", "GB"];
1080
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
1081
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
1082
+ }
1083
+ function getFileIcon(type) {
1084
+ if (!type) return File;
1085
+ if (type.startsWith("image/")) return FileImage;
1086
+ if (type.startsWith("video/")) return FileVideo;
1087
+ if (type.startsWith("audio/")) return FileAudio;
1088
+ if (type.startsWith("text/")) return FileText;
1089
+ if (type.includes("javascript") || type.includes("typescript") || type.includes("json") || type.includes("xml")) {
1090
+ return FileCode;
1091
+ }
1092
+ if (type.includes("zip") || type.includes("rar") || type.includes("tar") || type.includes("gz")) {
1093
+ return FileArchive;
1094
+ }
1095
+ return File;
1096
+ }
1097
+ var statusStyles = {
1098
+ pending: "border-silver/30",
1099
+ uploading: "border-gold/50",
1100
+ complete: "border-success/50",
1101
+ error: "border-error/50"
1102
+ };
1103
+ var FileChip = React14.forwardRef(
1104
+ ({
1105
+ name,
1106
+ size,
1107
+ type,
1108
+ status = "complete",
1109
+ previewUrl,
1110
+ onRemove,
1111
+ removable = true,
1112
+ error,
1113
+ className,
1114
+ ...rest
1115
+ }, ref) => {
1116
+ const Icon = getFileIcon(type);
1117
+ const isImage = type?.startsWith("image/");
1118
+ const showPreview = isImage && previewUrl;
1077
1119
  return /* @__PURE__ */ React14.createElement(
1120
+ "div",
1121
+ {
1122
+ ref,
1123
+ className: cx(
1124
+ "group relative inline-flex items-center gap-2 px-2 py-1.5",
1125
+ "bg-charcoal border text-sm text-white",
1126
+ "transition-colors duration-150",
1127
+ statusStyles[status],
1128
+ status === "error" && "bg-error/10",
1129
+ className
1130
+ ),
1131
+ role: "listitem",
1132
+ ...rest
1133
+ },
1134
+ showPreview ? /* @__PURE__ */ React14.createElement("div", { className: "w-8 h-8 flex-shrink-0 overflow-hidden bg-slate" }, /* @__PURE__ */ React14.createElement(
1135
+ "img",
1136
+ {
1137
+ src: previewUrl,
1138
+ alt: "",
1139
+ className: "w-full h-full object-cover"
1140
+ }
1141
+ )) : /* @__PURE__ */ React14.createElement(Icon, { className: cx(
1142
+ "w-4 h-4 flex-shrink-0",
1143
+ status === "error" ? "text-error" : "text-silver"
1144
+ ) }),
1145
+ /* @__PURE__ */ React14.createElement("div", { className: "flex flex-col min-w-0 flex-1" }, /* @__PURE__ */ React14.createElement("span", { className: "truncate max-w-40", title: name }, name), size !== void 0 && status !== "error" && /* @__PURE__ */ React14.createElement("span", { className: "text-xs text-silver/60" }, formatBytes(size)), status === "error" && error && /* @__PURE__ */ React14.createElement("span", { className: "text-xs text-error truncate", title: error }, error)),
1146
+ status === "uploading" && /* @__PURE__ */ React14.createElement(Loader2, { className: "w-3.5 h-3.5 text-gold animate-spin flex-shrink-0" }),
1147
+ status === "pending" && /* @__PURE__ */ React14.createElement("div", { className: "w-2 h-2 rounded-full bg-silver/50 flex-shrink-0" }),
1148
+ removable && onRemove && /* @__PURE__ */ React14.createElement(
1149
+ "button",
1150
+ {
1151
+ type: "button",
1152
+ onClick: (e) => {
1153
+ e.stopPropagation();
1154
+ onRemove();
1155
+ },
1156
+ className: cx(
1157
+ "p-0.5 text-silver/40 hover:text-white transition-colors",
1158
+ "hover:bg-white/10",
1159
+ "opacity-0 group-hover:opacity-100",
1160
+ "focus:opacity-100"
1161
+ ),
1162
+ "aria-label": `Remove ${name}`
1163
+ },
1164
+ /* @__PURE__ */ React14.createElement(X, { className: "w-3.5 h-3.5" })
1165
+ )
1166
+ );
1167
+ }
1168
+ );
1169
+ FileChip.displayName = "FileChip";
1170
+
1171
+ // src/components/AttachmentPreview.tsx
1172
+ import React15 from "react";
1173
+ var AttachmentPreview = React15.forwardRef(
1174
+ ({
1175
+ attachments,
1176
+ onRemove,
1177
+ removable = true,
1178
+ maxVisible,
1179
+ className,
1180
+ ...rest
1181
+ }, ref) => {
1182
+ if (attachments.length === 0) return null;
1183
+ const visibleAttachments = maxVisible && maxVisible > 0 ? attachments.slice(0, maxVisible) : attachments;
1184
+ const hiddenCount = maxVisible && maxVisible > 0 ? Math.max(0, attachments.length - maxVisible) : 0;
1185
+ return /* @__PURE__ */ React15.createElement(
1186
+ "div",
1187
+ {
1188
+ ref,
1189
+ className: cx("flex flex-wrap gap-2", className),
1190
+ role: "list",
1191
+ "aria-label": "Attached files",
1192
+ ...rest
1193
+ },
1194
+ visibleAttachments.map((attachment) => /* @__PURE__ */ React15.createElement(
1195
+ FileChip,
1196
+ {
1197
+ key: attachment.id,
1198
+ name: attachment.file.name,
1199
+ size: attachment.file.size,
1200
+ type: attachment.file.type,
1201
+ status: attachment.status,
1202
+ previewUrl: attachment.previewUrl,
1203
+ error: attachment.error,
1204
+ removable,
1205
+ onRemove: onRemove ? () => onRemove(attachment.id) : void 0
1206
+ }
1207
+ )),
1208
+ hiddenCount > 0 && /* @__PURE__ */ React15.createElement("div", { className: "inline-flex items-center px-2 py-1.5 bg-charcoal border border-silver/30 text-sm text-silver" }, "+", hiddenCount, " more")
1209
+ );
1210
+ }
1211
+ );
1212
+ AttachmentPreview.displayName = "AttachmentPreview";
1213
+
1214
+ // src/components/Label.tsx
1215
+ import React16 from "react";
1216
+ var Label = React16.forwardRef(
1217
+ ({ className, required, children, ...rest }, ref) => {
1218
+ return /* @__PURE__ */ React16.createElement(
1078
1219
  "label",
1079
1220
  {
1080
1221
  ref,
@@ -1082,17 +1223,17 @@ var Label = React14.forwardRef(
1082
1223
  ...rest
1083
1224
  },
1084
1225
  children,
1085
- required && /* @__PURE__ */ React14.createElement("span", { className: "text-error ml-1" }, "*")
1226
+ required && /* @__PURE__ */ React16.createElement("span", { className: "text-error ml-1" }, "*")
1086
1227
  );
1087
1228
  }
1088
1229
  );
1089
1230
  Label.displayName = "Label";
1090
1231
 
1091
1232
  // src/components/HelperText.tsx
1092
- import React15 from "react";
1093
- var HelperText = React15.forwardRef(
1233
+ import React17 from "react";
1234
+ var HelperText = React17.forwardRef(
1094
1235
  ({ className, error, children, ...rest }, ref) => {
1095
- return /* @__PURE__ */ React15.createElement(
1236
+ return /* @__PURE__ */ React17.createElement(
1096
1237
  "p",
1097
1238
  {
1098
1239
  ref,
@@ -1106,12 +1247,12 @@ var HelperText = React15.forwardRef(
1106
1247
  HelperText.displayName = "HelperText";
1107
1248
 
1108
1249
  // src/components/Textarea.tsx
1109
- import React16 from "react";
1110
- var Textarea = React16.forwardRef(
1250
+ import React18 from "react";
1251
+ var Textarea = React18.forwardRef(
1111
1252
  ({ error = false, className, disabled, ...rest }, ref) => {
1112
1253
  const base = "w-full px-3 py-2 bg-graphite border border-ash rounded-none text-white placeholder:text-zinc min-h-[80px] transition-all duration-fast focus:border-gold focus:ring-1 focus:ring-gold focus:outline-none disabled:bg-slate disabled:text-dim disabled:cursor-not-allowed";
1113
1254
  const errorCls = error ? "border-error focus:border-error focus:ring-error" : "";
1114
- return /* @__PURE__ */ React16.createElement(
1255
+ return /* @__PURE__ */ React18.createElement(
1115
1256
  "textarea",
1116
1257
  {
1117
1258
  ref,
@@ -1125,11 +1266,11 @@ var Textarea = React16.forwardRef(
1125
1266
  Textarea.displayName = "Textarea";
1126
1267
 
1127
1268
  // src/components/Select.tsx
1128
- import React17 from "react";
1269
+ import React19 from "react";
1129
1270
  var selectBgImage = `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%23C9A227' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`;
1130
- var Select = React17.forwardRef(
1271
+ var Select = React19.forwardRef(
1131
1272
  ({ error = false, className, disabled, options, children, ...rest }, ref) => {
1132
- return /* @__PURE__ */ React17.createElement(
1273
+ return /* @__PURE__ */ React19.createElement(
1133
1274
  "select",
1134
1275
  {
1135
1276
  ref,
@@ -1149,16 +1290,16 @@ var Select = React17.forwardRef(
1149
1290
  disabled,
1150
1291
  ...rest
1151
1292
  },
1152
- options ? options.map((opt) => /* @__PURE__ */ React17.createElement("option", { key: opt.value, value: opt.value }, opt.label)) : children
1293
+ options ? options.map((opt) => /* @__PURE__ */ React19.createElement("option", { key: opt.value, value: opt.value }, opt.label)) : children
1153
1294
  );
1154
1295
  }
1155
1296
  );
1156
1297
  Select.displayName = "Select";
1157
1298
 
1158
1299
  // src/components/Checkbox.tsx
1159
- import React18, { useCallback } from "react";
1300
+ import React20, { useCallback } from "react";
1160
1301
  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")`;
1161
- var Checkbox = React18.forwardRef(
1302
+ var Checkbox = React20.forwardRef(
1162
1303
  ({ className, label, id, ...rest }, ref) => {
1163
1304
  const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1164
1305
  const setRef = useCallback((node) => {
@@ -1173,14 +1314,14 @@ var Checkbox = React18.forwardRef(
1173
1314
  ref.current = node;
1174
1315
  }
1175
1316
  }, [ref]);
1176
- return /* @__PURE__ */ React18.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React18.createElement(
1317
+ return /* @__PURE__ */ React20.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React20.createElement(
1177
1318
  "input",
1178
1319
  {
1179
1320
  type: "checkbox",
1180
1321
  id: inputId,
1181
1322
  ref: setRef,
1182
1323
  className: cx(
1183
- "appearance-none h-4 w-4 border border-ash rounded-sm bg-graphite",
1324
+ "appearance-none h-4 w-4 border border-ash bg-graphite",
1184
1325
  "checked:bg-gold checked:border-gold",
1185
1326
  "focus:ring-1 focus:ring-gold focus:ring-offset-1 focus:ring-offset-obsidian",
1186
1327
  "transition duration-200 ease-in-out cursor-pointer",
@@ -1203,15 +1344,15 @@ var Checkbox = React18.forwardRef(
1203
1344
  },
1204
1345
  ...rest
1205
1346
  }
1206
- ), label && /* @__PURE__ */ React18.createElement("label", { htmlFor: inputId, className: "ml-2 text-sm text-silver cursor-pointer select-none" }, label));
1347
+ ), label && /* @__PURE__ */ React20.createElement("label", { htmlFor: inputId, className: "ml-2 text-sm text-silver cursor-pointer select-none" }, label));
1207
1348
  }
1208
1349
  );
1209
1350
  Checkbox.displayName = "Checkbox";
1210
1351
 
1211
1352
  // src/components/Radio.tsx
1212
- import React19, { useCallback as useCallback2 } from "react";
1353
+ import React21, { useCallback as useCallback2 } from "react";
1213
1354
  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")`;
1214
- var Radio = React19.forwardRef(
1355
+ var Radio = React21.forwardRef(
1215
1356
  ({ className, label, id, ...rest }, ref) => {
1216
1357
  const inputId = id || rest.name || Math.random().toString(36).substr(2, 9);
1217
1358
  const setRef = useCallback2((node) => {
@@ -1226,7 +1367,7 @@ var Radio = React19.forwardRef(
1226
1367
  ref.current = node;
1227
1368
  }
1228
1369
  }, [ref]);
1229
- return /* @__PURE__ */ React19.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React19.createElement(
1370
+ return /* @__PURE__ */ React21.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React21.createElement(
1230
1371
  "input",
1231
1372
  {
1232
1373
  type: "radio",
@@ -1264,14 +1405,14 @@ var Radio = React19.forwardRef(
1264
1405
  },
1265
1406
  ...rest
1266
1407
  }
1267
- ), label && /* @__PURE__ */ React19.createElement("label", { htmlFor: inputId, className: "ml-2 text-sm text-silver cursor-pointer select-none" }, label));
1408
+ ), label && /* @__PURE__ */ React21.createElement("label", { htmlFor: inputId, className: "ml-2 text-sm text-silver cursor-pointer select-none" }, label));
1268
1409
  }
1269
1410
  );
1270
1411
  Radio.displayName = "Radio";
1271
1412
 
1272
1413
  // src/components/Switch.tsx
1273
- import React20, { useCallback as useCallback3, useRef, useState } from "react";
1274
- var Switch = React20.forwardRef(
1414
+ import React22, { useCallback as useCallback3, useRef, useState } from "react";
1415
+ var Switch = React22.forwardRef(
1275
1416
  ({ checked: controlledChecked, defaultChecked = false, onCheckedChange, disabled, className, label, ...rest }, ref) => {
1276
1417
  const [internalChecked, setInternalChecked] = useState(defaultChecked);
1277
1418
  const isControlled = controlledChecked !== void 0;
@@ -1297,7 +1438,7 @@ var Switch = React20.forwardRef(
1297
1438
  onCheckedChange?.(newChecked);
1298
1439
  rest.onClick?.(e);
1299
1440
  };
1300
- return /* @__PURE__ */ React20.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React20.createElement(
1441
+ return /* @__PURE__ */ React22.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React22.createElement(
1301
1442
  "button",
1302
1443
  {
1303
1444
  type: "button",
@@ -1317,7 +1458,7 @@ var Switch = React20.forwardRef(
1317
1458
  ),
1318
1459
  ...rest
1319
1460
  },
1320
- /* @__PURE__ */ React20.createElement(
1461
+ /* @__PURE__ */ React22.createElement(
1321
1462
  "span",
1322
1463
  {
1323
1464
  className: cx(
@@ -1327,7 +1468,7 @@ var Switch = React20.forwardRef(
1327
1468
  )
1328
1469
  }
1329
1470
  )
1330
- ), label && /* @__PURE__ */ React20.createElement(
1471
+ ), label && /* @__PURE__ */ React22.createElement(
1331
1472
  "span",
1332
1473
  {
1333
1474
  className: "text-sm text-silver cursor-pointer",
@@ -1343,7 +1484,7 @@ var Switch = React20.forwardRef(
1343
1484
  Switch.displayName = "Switch";
1344
1485
 
1345
1486
  // src/components/Slider.tsx
1346
- import React21, { useState as useState2, useRef as useRef2, useCallback as useCallback4 } from "react";
1487
+ import React23, { useState as useState2, useRef as useRef2, useCallback as useCallback4 } from "react";
1347
1488
  var SIZE_TRACK = {
1348
1489
  sm: "h-1",
1349
1490
  md: "h-2",
@@ -1354,7 +1495,7 @@ var SIZE_THUMB = {
1354
1495
  md: "h-4 w-4",
1355
1496
  lg: "h-5 w-5"
1356
1497
  };
1357
- var Slider = React21.forwardRef(
1498
+ var Slider = React23.forwardRef(
1358
1499
  ({
1359
1500
  value: controlledValue,
1360
1501
  defaultValue = 0,
@@ -1442,14 +1583,14 @@ var Slider = React21.forwardRef(
1442
1583
  onChange?.(newValue);
1443
1584
  onChangeEnd?.(newValue);
1444
1585
  };
1445
- return /* @__PURE__ */ React21.createElement(
1586
+ return /* @__PURE__ */ React23.createElement(
1446
1587
  "div",
1447
1588
  {
1448
1589
  ref,
1449
1590
  className: cx("relative w-full py-2", disabled && "opacity-50", className),
1450
1591
  ...props
1451
1592
  },
1452
- /* @__PURE__ */ React21.createElement(
1593
+ /* @__PURE__ */ React23.createElement(
1453
1594
  "div",
1454
1595
  {
1455
1596
  ref: trackRef,
@@ -1459,14 +1600,14 @@ var Slider = React21.forwardRef(
1459
1600
  ),
1460
1601
  onMouseDown: handleMouseDown
1461
1602
  },
1462
- /* @__PURE__ */ React21.createElement(
1603
+ /* @__PURE__ */ React23.createElement(
1463
1604
  "div",
1464
1605
  {
1465
1606
  className: cx("absolute inset-y-0 left-0 bg-gold", SIZE_TRACK[size]),
1466
1607
  style: { width: `${percentage}%` }
1467
1608
  }
1468
1609
  ),
1469
- /* @__PURE__ */ React21.createElement(
1610
+ /* @__PURE__ */ React23.createElement(
1470
1611
  "div",
1471
1612
  {
1472
1613
  role: "slider",
@@ -1487,7 +1628,7 @@ var Slider = React21.forwardRef(
1487
1628
  ),
1488
1629
  style: { left: `${percentage}%` }
1489
1630
  },
1490
- showTooltip && isDragging && /* @__PURE__ */ React21.createElement("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-graphite border border-ash text-xs text-white whitespace-nowrap" }, formatValue(value))
1631
+ showTooltip && isDragging && /* @__PURE__ */ React23.createElement("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-graphite border border-ash text-xs text-white whitespace-nowrap" }, formatValue(value))
1491
1632
  )
1492
1633
  )
1493
1634
  );
@@ -1496,10 +1637,10 @@ var Slider = React21.forwardRef(
1496
1637
  Slider.displayName = "Slider";
1497
1638
 
1498
1639
  // src/components/InputGroup.tsx
1499
- import React22 from "react";
1500
- var InputGroup = React22.forwardRef(
1640
+ import React24 from "react";
1641
+ var InputGroup = React24.forwardRef(
1501
1642
  ({ className, children, ...props }, ref) => {
1502
- return /* @__PURE__ */ React22.createElement(
1643
+ return /* @__PURE__ */ React24.createElement(
1503
1644
  "div",
1504
1645
  {
1505
1646
  ref,
@@ -1511,9 +1652,9 @@ var InputGroup = React22.forwardRef(
1511
1652
  }
1512
1653
  );
1513
1654
  InputGroup.displayName = "InputGroup";
1514
- var InputLeftAddon = React22.forwardRef(
1655
+ var InputLeftAddon = React24.forwardRef(
1515
1656
  ({ className, children, ...props }, ref) => {
1516
- return /* @__PURE__ */ React22.createElement(
1657
+ return /* @__PURE__ */ React24.createElement(
1517
1658
  "div",
1518
1659
  {
1519
1660
  ref,
@@ -1529,9 +1670,9 @@ var InputLeftAddon = React22.forwardRef(
1529
1670
  }
1530
1671
  );
1531
1672
  InputLeftAddon.displayName = "InputLeftAddon";
1532
- var InputRightAddon = React22.forwardRef(
1673
+ var InputRightAddon = React24.forwardRef(
1533
1674
  ({ className, children, ...props }, ref) => {
1534
- return /* @__PURE__ */ React22.createElement(
1675
+ return /* @__PURE__ */ React24.createElement(
1535
1676
  "div",
1536
1677
  {
1537
1678
  ref,
@@ -1547,9 +1688,9 @@ var InputRightAddon = React22.forwardRef(
1547
1688
  }
1548
1689
  );
1549
1690
  InputRightAddon.displayName = "InputRightAddon";
1550
- var InputLeftElement = React22.forwardRef(
1691
+ var InputLeftElement = React24.forwardRef(
1551
1692
  ({ className, children, ...props }, ref) => {
1552
- return /* @__PURE__ */ React22.createElement(
1693
+ return /* @__PURE__ */ React24.createElement(
1553
1694
  "div",
1554
1695
  {
1555
1696
  ref,
@@ -1565,9 +1706,9 @@ var InputLeftElement = React22.forwardRef(
1565
1706
  }
1566
1707
  );
1567
1708
  InputLeftElement.displayName = "InputLeftElement";
1568
- var InputRightElement = React22.forwardRef(
1709
+ var InputRightElement = React24.forwardRef(
1569
1710
  ({ className, children, ...props }, ref) => {
1570
- return /* @__PURE__ */ React22.createElement(
1711
+ return /* @__PURE__ */ React24.createElement(
1571
1712
  "div",
1572
1713
  {
1573
1714
  ref,
@@ -1582,9 +1723,9 @@ var InputRightElement = React22.forwardRef(
1582
1723
  }
1583
1724
  );
1584
1725
  InputRightElement.displayName = "InputRightElement";
1585
- var InputWrapper = React22.forwardRef(
1726
+ var InputWrapper = React24.forwardRef(
1586
1727
  ({ className, children, ...props }, ref) => {
1587
- return /* @__PURE__ */ React22.createElement(
1728
+ return /* @__PURE__ */ React24.createElement(
1588
1729
  "div",
1589
1730
  {
1590
1731
  ref,
@@ -1598,7 +1739,7 @@ var InputWrapper = React22.forwardRef(
1598
1739
  InputWrapper.displayName = "InputWrapper";
1599
1740
 
1600
1741
  // src/components/Alert.tsx
1601
- import React23 from "react";
1742
+ import React25 from "react";
1602
1743
  import { Info, CheckCircle, AlertTriangle, XCircle } from "lucide-react";
1603
1744
  var icons = {
1604
1745
  info: Info,
@@ -1612,10 +1753,10 @@ var variantStyles = {
1612
1753
  warning: "bg-warning/10 border-warning text-warning",
1613
1754
  error: "bg-error/10 border-error text-error"
1614
1755
  };
1615
- var Alert = React23.forwardRef(
1756
+ var Alert = React25.forwardRef(
1616
1757
  ({ variant = "info", title, children, className, ...rest }, ref) => {
1617
1758
  const Icon = icons[variant];
1618
- return /* @__PURE__ */ React23.createElement(
1759
+ return /* @__PURE__ */ React25.createElement(
1619
1760
  "div",
1620
1761
  {
1621
1762
  ref,
@@ -1627,18 +1768,18 @@ var Alert = React23.forwardRef(
1627
1768
  ),
1628
1769
  ...rest
1629
1770
  },
1630
- /* @__PURE__ */ React23.createElement(Icon, { className: "h-5 w-5 shrink-0" }),
1631
- /* @__PURE__ */ React23.createElement("div", { className: "flex-1" }, title && /* @__PURE__ */ React23.createElement("h5", { className: "mb-1 font-medium leading-none tracking-tight text-current" }, title), /* @__PURE__ */ React23.createElement("div", { className: "text-sm opacity-90" }, children))
1771
+ /* @__PURE__ */ React25.createElement(Icon, { className: "h-5 w-5 shrink-0" }),
1772
+ /* @__PURE__ */ React25.createElement("div", { className: "flex-1" }, title && /* @__PURE__ */ React25.createElement("h5", { className: "mb-1 font-medium leading-none tracking-tight text-current" }, title), /* @__PURE__ */ React25.createElement("div", { className: "text-sm opacity-90" }, children))
1632
1773
  );
1633
1774
  }
1634
1775
  );
1635
1776
  Alert.displayName = "Alert";
1636
1777
 
1637
1778
  // src/components/Spinner.tsx
1638
- import React24 from "react";
1779
+ import React26 from "react";
1639
1780
  var Spinner = ({ className, size = "md", ...rest }) => {
1640
1781
  const sizeClass = size === "sm" ? "h-4 w-4" : size === "lg" ? "h-8 w-8" : "h-6 w-6";
1641
- return /* @__PURE__ */ React24.createElement(
1782
+ return /* @__PURE__ */ React26.createElement(
1642
1783
  "svg",
1643
1784
  {
1644
1785
  xmlns: "http://www.w3.org/2000/svg",
@@ -1651,20 +1792,20 @@ var Spinner = ({ className, size = "md", ...rest }) => {
1651
1792
  className: cx("animate-spin text-gold", sizeClass, className),
1652
1793
  ...rest
1653
1794
  },
1654
- /* @__PURE__ */ React24.createElement("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
1795
+ /* @__PURE__ */ React26.createElement("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
1655
1796
  );
1656
1797
  };
1657
1798
  Spinner.displayName = "Spinner";
1658
1799
 
1659
1800
  // src/components/Skeleton.tsx
1660
- import React25 from "react";
1661
- var Skeleton = React25.forwardRef(
1801
+ import React27 from "react";
1802
+ var Skeleton = React27.forwardRef(
1662
1803
  ({ className, ...rest }, ref) => {
1663
- return /* @__PURE__ */ React25.createElement(
1804
+ return /* @__PURE__ */ React27.createElement(
1664
1805
  "div",
1665
1806
  {
1666
1807
  ref,
1667
- className: cx("animate-pulse bg-ash rounded-sm", className),
1808
+ className: cx("animate-pulse bg-ash", className),
1668
1809
  ...rest
1669
1810
  }
1670
1811
  );
@@ -1673,7 +1814,7 @@ var Skeleton = React25.forwardRef(
1673
1814
  Skeleton.displayName = "Skeleton";
1674
1815
 
1675
1816
  // src/components/Progress.tsx
1676
- import React26 from "react";
1817
+ import React28 from "react";
1677
1818
  var SIZE_MAP = {
1678
1819
  sm: "h-1",
1679
1820
  md: "h-2",
@@ -1685,7 +1826,7 @@ var VARIANT_MAP2 = {
1685
1826
  warning: "bg-warning",
1686
1827
  error: "bg-error"
1687
1828
  };
1688
- var Progress = React26.forwardRef(
1829
+ var Progress = React28.forwardRef(
1689
1830
  ({
1690
1831
  value = 0,
1691
1832
  max = 100,
@@ -1699,7 +1840,7 @@ var Progress = React26.forwardRef(
1699
1840
  }, ref) => {
1700
1841
  const percentage = Math.min(100, Math.max(0, value / max * 100));
1701
1842
  const displayValue = formatValue ? formatValue(value, max) : `${Math.round(percentage)}%`;
1702
- return /* @__PURE__ */ React26.createElement("div", { ref, className: cx("w-full", className), ...props }, showValue && /* @__PURE__ */ React26.createElement("div", { className: "flex justify-between mb-1" }, /* @__PURE__ */ React26.createElement("span", { className: "text-sm text-silver" }, "Progress"), /* @__PURE__ */ React26.createElement("span", { className: "text-sm text-white font-medium" }, displayValue)), /* @__PURE__ */ React26.createElement(
1843
+ return /* @__PURE__ */ React28.createElement("div", { ref, className: cx("w-full", className), ...props }, showValue && /* @__PURE__ */ React28.createElement("div", { className: "flex justify-between mb-1" }, /* @__PURE__ */ React28.createElement("span", { className: "text-sm text-silver" }, "Progress"), /* @__PURE__ */ React28.createElement("span", { className: "text-sm text-white font-medium" }, displayValue)), /* @__PURE__ */ React28.createElement(
1703
1844
  "div",
1704
1845
  {
1705
1846
  className: cx(
@@ -1711,7 +1852,7 @@ var Progress = React26.forwardRef(
1711
1852
  "aria-valuemin": 0,
1712
1853
  "aria-valuemax": max
1713
1854
  },
1714
- /* @__PURE__ */ React26.createElement(
1855
+ /* @__PURE__ */ React28.createElement(
1715
1856
  "div",
1716
1857
  {
1717
1858
  className: cx(
@@ -1730,9 +1871,9 @@ var Progress = React26.forwardRef(
1730
1871
  Progress.displayName = "Progress";
1731
1872
 
1732
1873
  // src/components/Toast.tsx
1733
- import React27, { createContext, useContext, useState as useState3, useCallback as useCallback5, useEffect } from "react";
1874
+ import React29, { createContext, useContext, useState as useState3, useCallback as useCallback5, useEffect } from "react";
1734
1875
  import { createPortal } from "react-dom";
1735
- import { X, CheckCircle as CheckCircle2, AlertCircle, AlertTriangle as AlertTriangle2, Info as Info2 } from "lucide-react";
1876
+ import { X as X2, CheckCircle as CheckCircle2, AlertCircle, AlertTriangle as AlertTriangle2, Info as Info2 } from "lucide-react";
1736
1877
  var ToastContext = createContext(null);
1737
1878
  function useToast() {
1738
1879
  const context = useContext(ToastContext);
@@ -1776,7 +1917,7 @@ var ToastProvider = ({
1776
1917
  const removeToast = useCallback5((id) => {
1777
1918
  setToasts((prev) => prev.filter((t) => t.id !== id));
1778
1919
  }, []);
1779
- return /* @__PURE__ */ React27.createElement(ToastContext.Provider, { value: { toasts, addToast, removeToast, position } }, children, mounted && /* @__PURE__ */ React27.createElement(ToastViewport, null));
1920
+ return /* @__PURE__ */ React29.createElement(ToastContext.Provider, { value: { toasts, addToast, removeToast, position } }, children, mounted && /* @__PURE__ */ React29.createElement(ToastViewport, null));
1780
1921
  };
1781
1922
  ToastProvider.displayName = "ToastProvider";
1782
1923
  var ToastViewport = () => {
@@ -1792,7 +1933,7 @@ var ToastViewport = () => {
1792
1933
  "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
1793
1934
  };
1794
1935
  return createPortal(
1795
- /* @__PURE__ */ React27.createElement(
1936
+ /* @__PURE__ */ React29.createElement(
1796
1937
  "div",
1797
1938
  {
1798
1939
  className: cx(
@@ -1800,7 +1941,7 @@ var ToastViewport = () => {
1800
1941
  positionClasses[position]
1801
1942
  )
1802
1943
  },
1803
- toasts.map((toast) => /* @__PURE__ */ React27.createElement(Toast, { key: toast.id, ...toast }))
1944
+ toasts.map((toast) => /* @__PURE__ */ React29.createElement(Toast, { key: toast.id, ...toast }))
1804
1945
  ),
1805
1946
  document.body
1806
1947
  );
@@ -1814,10 +1955,10 @@ var VARIANT_STYLES2 = {
1814
1955
  };
1815
1956
  var VARIANT_ICONS = {
1816
1957
  default: null,
1817
- success: /* @__PURE__ */ React27.createElement(CheckCircle2, { className: "h-5 w-5 text-success" }),
1818
- error: /* @__PURE__ */ React27.createElement(AlertCircle, { className: "h-5 w-5 text-error" }),
1819
- warning: /* @__PURE__ */ React27.createElement(AlertTriangle2, { className: "h-5 w-5 text-warning" }),
1820
- info: /* @__PURE__ */ React27.createElement(Info2, { className: "h-5 w-5 text-info" })
1958
+ success: /* @__PURE__ */ React29.createElement(CheckCircle2, { className: "h-5 w-5 text-success" }),
1959
+ error: /* @__PURE__ */ React29.createElement(AlertCircle, { className: "h-5 w-5 text-error" }),
1960
+ warning: /* @__PURE__ */ React29.createElement(AlertTriangle2, { className: "h-5 w-5 text-warning" }),
1961
+ info: /* @__PURE__ */ React29.createElement(Info2, { className: "h-5 w-5 text-info" })
1821
1962
  };
1822
1963
  var Toast = ({
1823
1964
  id,
@@ -1837,7 +1978,7 @@ var Toast = ({
1837
1978
  }
1838
1979
  }, [id, duration, context]);
1839
1980
  const icon = VARIANT_ICONS[variant];
1840
- return /* @__PURE__ */ React27.createElement(
1981
+ return /* @__PURE__ */ React29.createElement(
1841
1982
  "div",
1842
1983
  {
1843
1984
  role: "alert",
@@ -1846,23 +1987,23 @@ var Toast = ({
1846
1987
  VARIANT_STYLES2[variant]
1847
1988
  )
1848
1989
  },
1849
- /* @__PURE__ */ React27.createElement("div", { className: "flex gap-3" }, icon && /* @__PURE__ */ React27.createElement("div", { className: "shrink-0 mt-0.5" }, icon), /* @__PURE__ */ React27.createElement("div", { className: "flex-1 min-w-0" }, title && /* @__PURE__ */ React27.createElement("p", { className: "text-sm font-medium text-white" }, title), description && /* @__PURE__ */ React27.createElement("p", { className: "text-sm text-silver mt-1" }, description), action && /* @__PURE__ */ React27.createElement("div", { className: "mt-3" }, action)), /* @__PURE__ */ React27.createElement(
1990
+ /* @__PURE__ */ React29.createElement("div", { className: "flex gap-3" }, icon && /* @__PURE__ */ React29.createElement("div", { className: "shrink-0 mt-0.5" }, icon), /* @__PURE__ */ React29.createElement("div", { className: "flex-1 min-w-0" }, title && /* @__PURE__ */ React29.createElement("p", { className: "text-sm font-medium text-white" }, title), description && /* @__PURE__ */ React29.createElement("p", { className: "text-sm text-silver mt-1" }, description), action && /* @__PURE__ */ React29.createElement("div", { className: "mt-3" }, action)), /* @__PURE__ */ React29.createElement(
1850
1991
  "button",
1851
1992
  {
1852
1993
  onClick: () => context?.removeToast(id),
1853
1994
  className: "shrink-0 text-silver hover:text-white transition-colors"
1854
1995
  },
1855
- /* @__PURE__ */ React27.createElement(X, { className: "h-4 w-4" }),
1856
- /* @__PURE__ */ React27.createElement("span", { className: "sr-only" }, "Dismiss")
1996
+ /* @__PURE__ */ React29.createElement(X2, { className: "h-4 w-4" }),
1997
+ /* @__PURE__ */ React29.createElement("span", { className: "sr-only" }, "Dismiss")
1857
1998
  ))
1858
1999
  );
1859
2000
  };
1860
2001
  Toast.displayName = "Toast";
1861
2002
 
1862
2003
  // src/components/Modal.tsx
1863
- import React28, { useEffect as useEffect2, useState as useState4 } from "react";
2004
+ import React30, { useEffect as useEffect2, useState as useState4 } from "react";
1864
2005
  import { createPortal as createPortal2 } from "react-dom";
1865
- import { X as X2 } from "lucide-react";
2006
+ import { X as X3 } from "lucide-react";
1866
2007
  var Modal = ({ isOpen, onClose, title, children, className }) => {
1867
2008
  const [mounted, setMounted] = useState4(false);
1868
2009
  useEffect2(() => {
@@ -1891,7 +2032,7 @@ var Modal = ({ isOpen, onClose, title, children, className }) => {
1891
2032
  }, [onClose]);
1892
2033
  if (!mounted) return null;
1893
2034
  if (!isOpen) return null;
1894
- const content = /* @__PURE__ */ React28.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6", onClick: onClose }, /* @__PURE__ */ React28.createElement("div", { className: "fixed inset-0 z-40 bg-obsidian/80 backdrop-blur-sm", "aria-hidden": "true" }), /* @__PURE__ */ React28.createElement(
2035
+ const content = /* @__PURE__ */ React30.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 sm:p-6", onClick: onClose }, /* @__PURE__ */ React30.createElement("div", { className: "fixed inset-0 z-40 bg-obsidian/80 backdrop-blur-sm", "aria-hidden": "true" }), /* @__PURE__ */ React30.createElement(
1895
2036
  "div",
1896
2037
  {
1897
2038
  role: "dialog",
@@ -1903,17 +2044,17 @@ var Modal = ({ isOpen, onClose, title, children, className }) => {
1903
2044
  "data-state": "open",
1904
2045
  onClick: (e) => e.stopPropagation()
1905
2046
  },
1906
- /* @__PURE__ */ React28.createElement("div", { className: "flex items-center justify-between mb-2" }, title ? /* @__PURE__ */ React28.createElement("h3", { className: "text-xl font-semibold text-white m-0" }, title) : /* @__PURE__ */ React28.createElement("div", null), /* @__PURE__ */ React28.createElement("button", { onClick: onClose, className: "text-silver hover:text-white transition-colors ml-auto" }, /* @__PURE__ */ React28.createElement(X2, { className: "h-5 w-5" }), /* @__PURE__ */ React28.createElement("span", { className: "sr-only" }, "Close"))),
1907
- /* @__PURE__ */ React28.createElement("div", null, children)
2047
+ /* @__PURE__ */ React30.createElement("div", { className: "flex items-center justify-between mb-2" }, title ? /* @__PURE__ */ React30.createElement("h3", { className: "text-xl font-semibold text-white m-0" }, title) : /* @__PURE__ */ React30.createElement("div", null), /* @__PURE__ */ React30.createElement("button", { onClick: onClose, className: "text-silver hover:text-white transition-colors ml-auto" }, /* @__PURE__ */ React30.createElement(X3, { className: "h-5 w-5" }), /* @__PURE__ */ React30.createElement("span", { className: "sr-only" }, "Close"))),
2048
+ /* @__PURE__ */ React30.createElement("div", null, children)
1908
2049
  ));
1909
2050
  return createPortal2(content, document.body);
1910
2051
  };
1911
2052
  Modal.displayName = "Modal";
1912
2053
 
1913
2054
  // src/components/Drawer.tsx
1914
- import React29, { useEffect as useEffect3, useState as useState5 } from "react";
2055
+ import React31, { useEffect as useEffect3, useState as useState5 } from "react";
1915
2056
  import { createPortal as createPortal3 } from "react-dom";
1916
- import { X as X3 } from "lucide-react";
2057
+ import { X as X4 } from "lucide-react";
1917
2058
  var SIZE_MAP2 = {
1918
2059
  sm: {
1919
2060
  left: "w-64",
@@ -1993,7 +2134,7 @@ var Drawer = ({
1993
2134
  return () => window.removeEventListener("keydown", handleEsc);
1994
2135
  }, [onClose]);
1995
2136
  if (!mounted) return null;
1996
- const content = /* @__PURE__ */ React29.createElement(
2137
+ const content = /* @__PURE__ */ React31.createElement(
1997
2138
  "div",
1998
2139
  {
1999
2140
  className: cx(
@@ -2001,7 +2142,7 @@ var Drawer = ({
2001
2142
  isOpen ? "pointer-events-auto" : "pointer-events-none"
2002
2143
  )
2003
2144
  },
2004
- /* @__PURE__ */ React29.createElement(
2145
+ /* @__PURE__ */ React31.createElement(
2005
2146
  "div",
2006
2147
  {
2007
2148
  className: cx(
@@ -2012,7 +2153,7 @@ var Drawer = ({
2012
2153
  "aria-hidden": "true"
2013
2154
  }
2014
2155
  ),
2015
- /* @__PURE__ */ React29.createElement(
2156
+ /* @__PURE__ */ React31.createElement(
2016
2157
  "div",
2017
2158
  {
2018
2159
  role: "dialog",
@@ -2030,16 +2171,16 @@ var Drawer = ({
2030
2171
  className
2031
2172
  )
2032
2173
  },
2033
- /* @__PURE__ */ React29.createElement("div", { className: "flex items-center justify-between px-4 py-3 border-b border-ash" }, title ? /* @__PURE__ */ React29.createElement("h2", { className: "text-lg font-semibold text-white m-0" }, title) : /* @__PURE__ */ React29.createElement("div", null), /* @__PURE__ */ React29.createElement(
2174
+ /* @__PURE__ */ React31.createElement("div", { className: "flex items-center justify-between px-4 py-3 border-b border-ash" }, title ? /* @__PURE__ */ React31.createElement("h2", { className: "text-lg font-semibold text-white m-0" }, title) : /* @__PURE__ */ React31.createElement("div", null), /* @__PURE__ */ React31.createElement(
2034
2175
  "button",
2035
2176
  {
2036
2177
  onClick: onClose,
2037
2178
  className: "text-silver hover:text-white transition-colors"
2038
2179
  },
2039
- /* @__PURE__ */ React29.createElement(X3, { className: "h-5 w-5" }),
2040
- /* @__PURE__ */ React29.createElement("span", { className: "sr-only" }, "Close")
2180
+ /* @__PURE__ */ React31.createElement(X4, { className: "h-5 w-5" }),
2181
+ /* @__PURE__ */ React31.createElement("span", { className: "sr-only" }, "Close")
2041
2182
  )),
2042
- /* @__PURE__ */ React29.createElement("div", { className: "flex-1 overflow-auto p-4" }, children)
2183
+ /* @__PURE__ */ React31.createElement("div", { className: "flex-1 overflow-auto p-4" }, children)
2043
2184
  )
2044
2185
  );
2045
2186
  return createPortal3(content, document.body);
@@ -2047,7 +2188,7 @@ var Drawer = ({
2047
2188
  Drawer.displayName = "Drawer";
2048
2189
 
2049
2190
  // src/components/Popover.tsx
2050
- import React30, { useState as useState6, useRef as useRef3, useEffect as useEffect4, useCallback as useCallback6, useId } from "react";
2191
+ import React32, { useState as useState6, useRef as useRef3, useEffect as useEffect4, useCallback as useCallback6, useId } from "react";
2051
2192
  var POSITION_CLASSES2 = {
2052
2193
  top: {
2053
2194
  start: "bottom-full left-0 mb-2",
@@ -2116,14 +2257,14 @@ var Popover = ({
2116
2257
  const handleTriggerClick = () => {
2117
2258
  setIsOpen(!isOpen);
2118
2259
  };
2119
- const triggerElement = React30.cloneElement(trigger, {
2260
+ const triggerElement = React32.cloneElement(trigger, {
2120
2261
  onClick: handleTriggerClick,
2121
2262
  "aria-haspopup": "dialog",
2122
2263
  "aria-expanded": isOpen,
2123
2264
  "aria-controls": `${baseId}-popover`,
2124
2265
  id: `${baseId}-trigger`
2125
2266
  });
2126
- return /* @__PURE__ */ React30.createElement("div", { ref: containerRef, className: "relative inline-block" }, triggerElement, isOpen && /* @__PURE__ */ React30.createElement(
2267
+ return /* @__PURE__ */ React32.createElement("div", { ref: containerRef, className: "relative inline-block" }, triggerElement, isOpen && /* @__PURE__ */ React32.createElement(
2127
2268
  "div",
2128
2269
  {
2129
2270
  id: `${baseId}-popover`,
@@ -2142,7 +2283,7 @@ var Popover = ({
2142
2283
  Popover.displayName = "Popover";
2143
2284
 
2144
2285
  // src/components/Dialog.tsx
2145
- import React31, { useCallback as useCallback7 } from "react";
2286
+ import React33, { useCallback as useCallback7 } from "react";
2146
2287
  var ConfirmDialog = ({
2147
2288
  title = "Confirm",
2148
2289
  description,
@@ -2163,7 +2304,7 @@ var ConfirmDialog = ({
2163
2304
  await onConfirm();
2164
2305
  onClose();
2165
2306
  }, [onConfirm, onClose]);
2166
- return /* @__PURE__ */ React31.createElement(Modal, { title, onClose, ...props }, description && /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-silver mb-6" }, description), /* @__PURE__ */ React31.createElement("div", { className: "flex justify-end gap-3" }, /* @__PURE__ */ React31.createElement(Button, { variant: "outlined", onClick: handleCancel, disabled: isLoading }, cancelText), /* @__PURE__ */ React31.createElement(
2307
+ return /* @__PURE__ */ React33.createElement(Modal, { title, onClose, ...props }, description && /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-silver mb-6" }, description), /* @__PURE__ */ React33.createElement("div", { className: "flex justify-end gap-3" }, /* @__PURE__ */ React33.createElement(Button, { variant: "outlined", onClick: handleCancel, disabled: isLoading }, cancelText), /* @__PURE__ */ React33.createElement(
2167
2308
  Button,
2168
2309
  {
2169
2310
  variant: confirmVariant,
@@ -2186,7 +2327,7 @@ var AlertDialog = ({
2186
2327
  variant === "warning" && "text-warning",
2187
2328
  variant === "error" && "text-error"
2188
2329
  );
2189
- return /* @__PURE__ */ React31.createElement(Modal, { onClose, ...props }, /* @__PURE__ */ React31.createElement("h3", { className: cx("text-xl font-semibold mb-2", titleClass) }, title), description && /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-silver mb-6" }, description), /* @__PURE__ */ React31.createElement("div", { className: "flex justify-end" }, /* @__PURE__ */ React31.createElement(Button, { variant: "primary", onClick: onClose }, acknowledgeText)));
2330
+ return /* @__PURE__ */ React33.createElement(Modal, { onClose, ...props }, /* @__PURE__ */ React33.createElement("h3", { className: cx("text-xl font-semibold mb-2", titleClass) }, title), description && /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-silver mb-6" }, description), /* @__PURE__ */ React33.createElement("div", { className: "flex justify-end" }, /* @__PURE__ */ React33.createElement(Button, { variant: "primary", onClick: onClose }, acknowledgeText)));
2190
2331
  };
2191
2332
  AlertDialog.displayName = "AlertDialog";
2192
2333
  var PromptDialog = ({
@@ -2202,7 +2343,7 @@ var PromptDialog = ({
2202
2343
  isLoading = false,
2203
2344
  ...props
2204
2345
  }) => {
2205
- const [value, setValue] = React31.useState(defaultValue);
2346
+ const [value, setValue] = React33.useState(defaultValue);
2206
2347
  const handleCancel = useCallback7(() => {
2207
2348
  onCancel?.();
2208
2349
  onClose();
@@ -2215,7 +2356,7 @@ var PromptDialog = ({
2215
2356
  },
2216
2357
  [onSubmit, value, onClose]
2217
2358
  );
2218
- return /* @__PURE__ */ React31.createElement(Modal, { title, onClose, ...props }, /* @__PURE__ */ React31.createElement("form", { onSubmit: handleSubmit }, description && /* @__PURE__ */ React31.createElement("p", { className: "text-sm text-silver mb-4" }, description), /* @__PURE__ */ React31.createElement(
2359
+ return /* @__PURE__ */ React33.createElement(Modal, { title, onClose, ...props }, /* @__PURE__ */ React33.createElement("form", { onSubmit: handleSubmit }, description && /* @__PURE__ */ React33.createElement("p", { className: "text-sm text-silver mb-4" }, description), /* @__PURE__ */ React33.createElement(
2219
2360
  "input",
2220
2361
  {
2221
2362
  type: "text",
@@ -2230,7 +2371,7 @@ var PromptDialog = ({
2230
2371
  ),
2231
2372
  autoFocus: true
2232
2373
  }
2233
- ), /* @__PURE__ */ React31.createElement("div", { className: "flex justify-end gap-3" }, /* @__PURE__ */ React31.createElement(
2374
+ ), /* @__PURE__ */ React33.createElement("div", { className: "flex justify-end gap-3" }, /* @__PURE__ */ React33.createElement(
2234
2375
  Button,
2235
2376
  {
2236
2377
  type: "button",
@@ -2239,12 +2380,12 @@ var PromptDialog = ({
2239
2380
  disabled: isLoading
2240
2381
  },
2241
2382
  cancelText
2242
- ), /* @__PURE__ */ React31.createElement(Button, { type: "submit", variant: "important", loading: isLoading }, submitText))));
2383
+ ), /* @__PURE__ */ React33.createElement(Button, { type: "submit", variant: "important", loading: isLoading }, submitText))));
2243
2384
  };
2244
2385
  PromptDialog.displayName = "PromptDialog";
2245
2386
 
2246
2387
  // src/components/Tabs.tsx
2247
- import React32, { createContext as createContext2, useContext as useContext2, useState as useState7, useCallback as useCallback8, useId as useId2 } from "react";
2388
+ import React34, { createContext as createContext2, useContext as useContext2, useState as useState7, useCallback as useCallback8, useId as useId2 } from "react";
2248
2389
  var TabsContext = createContext2(null);
2249
2390
  function useTabsContext() {
2250
2391
  const context = useContext2(TabsContext);
@@ -2253,7 +2394,7 @@ function useTabsContext() {
2253
2394
  }
2254
2395
  return context;
2255
2396
  }
2256
- var Tabs = React32.forwardRef(
2397
+ var Tabs = React34.forwardRef(
2257
2398
  ({ defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2258
2399
  const [internalValue, setInternalValue] = useState7(defaultValue ?? "");
2259
2400
  const isControlled = value !== void 0;
@@ -2268,13 +2409,13 @@ var Tabs = React32.forwardRef(
2268
2409
  },
2269
2410
  [isControlled, onValueChange]
2270
2411
  );
2271
- return /* @__PURE__ */ React32.createElement(TabsContext.Provider, { value: { activeTab, setActiveTab, baseId } }, /* @__PURE__ */ React32.createElement("div", { ref, className: cx("w-full", className), ...props }, children));
2412
+ return /* @__PURE__ */ React34.createElement(TabsContext.Provider, { value: { activeTab, setActiveTab, baseId } }, /* @__PURE__ */ React34.createElement("div", { ref, className: cx("w-full", className), ...props }, children));
2272
2413
  }
2273
2414
  );
2274
2415
  Tabs.displayName = "Tabs";
2275
- var TabList = React32.forwardRef(
2416
+ var TabList = React34.forwardRef(
2276
2417
  ({ children, className, ...props }, ref) => {
2277
- return /* @__PURE__ */ React32.createElement(
2418
+ return /* @__PURE__ */ React34.createElement(
2278
2419
  "div",
2279
2420
  {
2280
2421
  ref,
@@ -2290,13 +2431,13 @@ var TabList = React32.forwardRef(
2290
2431
  }
2291
2432
  );
2292
2433
  TabList.displayName = "TabList";
2293
- var Tab = React32.forwardRef(
2434
+ var Tab = React34.forwardRef(
2294
2435
  ({ value, children, className, disabled, ...props }, ref) => {
2295
2436
  const { activeTab, setActiveTab, baseId } = useTabsContext();
2296
2437
  const isActive = activeTab === value;
2297
2438
  const panelId = `${baseId}-panel-${value}`;
2298
2439
  const tabId = `${baseId}-tab-${value}`;
2299
- return /* @__PURE__ */ React32.createElement(
2440
+ return /* @__PURE__ */ React34.createElement(
2300
2441
  "button",
2301
2442
  {
2302
2443
  ref,
@@ -2323,7 +2464,7 @@ var Tab = React32.forwardRef(
2323
2464
  }
2324
2465
  );
2325
2466
  Tab.displayName = "Tab";
2326
- var TabPanel = React32.forwardRef(
2467
+ var TabPanel = React34.forwardRef(
2327
2468
  ({ value, forceMount = false, children, className, ...props }, ref) => {
2328
2469
  const { activeTab, baseId } = useTabsContext();
2329
2470
  const isActive = activeTab === value;
@@ -2332,7 +2473,7 @@ var TabPanel = React32.forwardRef(
2332
2473
  if (!isActive && !forceMount) {
2333
2474
  return null;
2334
2475
  }
2335
- return /* @__PURE__ */ React32.createElement(
2476
+ return /* @__PURE__ */ React34.createElement(
2336
2477
  "div",
2337
2478
  {
2338
2479
  ref,
@@ -2355,7 +2496,7 @@ var TabPanel = React32.forwardRef(
2355
2496
  TabPanel.displayName = "TabPanel";
2356
2497
 
2357
2498
  // src/components/Accordion.tsx
2358
- import React33, { createContext as createContext3, useContext as useContext3, useState as useState8, useCallback as useCallback9, useId as useId3 } from "react";
2499
+ import React35, { createContext as createContext3, useContext as useContext3, useState as useState8, useCallback as useCallback9, useId as useId3 } from "react";
2359
2500
  import { ChevronDown } from "lucide-react";
2360
2501
  var AccordionContext = createContext3(null);
2361
2502
  function useAccordionContext() {
@@ -2365,7 +2506,7 @@ function useAccordionContext() {
2365
2506
  }
2366
2507
  return context;
2367
2508
  }
2368
- var Accordion = React33.forwardRef(
2509
+ var Accordion = React35.forwardRef(
2369
2510
  ({ type = "single", defaultValue, value, onValueChange, children, className, ...props }, ref) => {
2370
2511
  const [internalValue, setInternalValue] = useState8(() => {
2371
2512
  if (defaultValue) {
@@ -2394,7 +2535,7 @@ var Accordion = React33.forwardRef(
2394
2535
  },
2395
2536
  [expandedItems, type, isControlled, onValueChange]
2396
2537
  );
2397
- return /* @__PURE__ */ React33.createElement(AccordionContext.Provider, { value: { expandedItems, toggleItem, type } }, /* @__PURE__ */ React33.createElement(
2538
+ return /* @__PURE__ */ React35.createElement(AccordionContext.Provider, { value: { expandedItems, toggleItem, type } }, /* @__PURE__ */ React35.createElement(
2398
2539
  "div",
2399
2540
  {
2400
2541
  ref,
@@ -2407,9 +2548,9 @@ var Accordion = React33.forwardRef(
2407
2548
  );
2408
2549
  Accordion.displayName = "Accordion";
2409
2550
  var AccordionItemContext = createContext3(null);
2410
- var AccordionItem = React33.forwardRef(
2551
+ var AccordionItem = React35.forwardRef(
2411
2552
  ({ value, disabled = false, children, className, ...props }, ref) => {
2412
- return /* @__PURE__ */ React33.createElement(AccordionItemContext.Provider, { value: { value, disabled } }, /* @__PURE__ */ React33.createElement(
2553
+ return /* @__PURE__ */ React35.createElement(AccordionItemContext.Provider, { value: { value, disabled } }, /* @__PURE__ */ React35.createElement(
2413
2554
  "div",
2414
2555
  {
2415
2556
  ref,
@@ -2422,7 +2563,7 @@ var AccordionItem = React33.forwardRef(
2422
2563
  }
2423
2564
  );
2424
2565
  AccordionItem.displayName = "AccordionItem";
2425
- var AccordionTrigger = React33.forwardRef(
2566
+ var AccordionTrigger = React35.forwardRef(
2426
2567
  ({ children, className, ...props }, ref) => {
2427
2568
  const { expandedItems, toggleItem } = useAccordionContext();
2428
2569
  const itemContext = useContext3(AccordionItemContext);
@@ -2432,7 +2573,7 @@ var AccordionTrigger = React33.forwardRef(
2432
2573
  }
2433
2574
  const { value, disabled } = itemContext;
2434
2575
  const isExpanded = expandedItems.has(value);
2435
- return /* @__PURE__ */ React33.createElement("h3", { className: "m-0" }, /* @__PURE__ */ React33.createElement(
2576
+ return /* @__PURE__ */ React35.createElement("h3", { className: "m-0" }, /* @__PURE__ */ React35.createElement(
2436
2577
  "button",
2437
2578
  {
2438
2579
  ref,
@@ -2453,8 +2594,8 @@ var AccordionTrigger = React33.forwardRef(
2453
2594
  ),
2454
2595
  ...props
2455
2596
  },
2456
- /* @__PURE__ */ React33.createElement("span", null, children),
2457
- /* @__PURE__ */ React33.createElement(
2597
+ /* @__PURE__ */ React35.createElement("span", null, children),
2598
+ /* @__PURE__ */ React35.createElement(
2458
2599
  ChevronDown,
2459
2600
  {
2460
2601
  className: cx(
@@ -2467,7 +2608,7 @@ var AccordionTrigger = React33.forwardRef(
2467
2608
  }
2468
2609
  );
2469
2610
  AccordionTrigger.displayName = "AccordionTrigger";
2470
- var AccordionContent = React33.forwardRef(
2611
+ var AccordionContent = React35.forwardRef(
2471
2612
  ({ children, className, ...props }, ref) => {
2472
2613
  const { expandedItems } = useAccordionContext();
2473
2614
  const itemContext = useContext3(AccordionItemContext);
@@ -2477,7 +2618,7 @@ var AccordionContent = React33.forwardRef(
2477
2618
  }
2478
2619
  const { value } = itemContext;
2479
2620
  const isExpanded = expandedItems.has(value);
2480
- return /* @__PURE__ */ React33.createElement(
2621
+ return /* @__PURE__ */ React35.createElement(
2481
2622
  "div",
2482
2623
  {
2483
2624
  ref,
@@ -2492,14 +2633,14 @@ var AccordionContent = React33.forwardRef(
2492
2633
  ),
2493
2634
  ...props
2494
2635
  },
2495
- /* @__PURE__ */ React33.createElement("div", { className: "px-4 pb-4 text-sm text-silver" }, children)
2636
+ /* @__PURE__ */ React35.createElement("div", { className: "px-4 pb-4 text-sm text-silver" }, children)
2496
2637
  );
2497
2638
  }
2498
2639
  );
2499
2640
  AccordionContent.displayName = "AccordionContent";
2500
2641
 
2501
2642
  // src/components/Menu.tsx
2502
- import React34, {
2643
+ import React36, {
2503
2644
  createContext as createContext4,
2504
2645
  useContext as useContext4,
2505
2646
  useState as useState9,
@@ -2530,7 +2671,7 @@ var Menu = ({ children, open, onOpenChange }) => {
2530
2671
  },
2531
2672
  [isControlled, onOpenChange]
2532
2673
  );
2533
- return /* @__PURE__ */ React34.createElement(
2674
+ return /* @__PURE__ */ React36.createElement(
2534
2675
  MenuContext.Provider,
2535
2676
  {
2536
2677
  value: {
@@ -2540,11 +2681,11 @@ var Menu = ({ children, open, onOpenChange }) => {
2540
2681
  menuId: `${baseId}-menu`
2541
2682
  }
2542
2683
  },
2543
- /* @__PURE__ */ React34.createElement("div", { className: "relative inline-block" }, children)
2684
+ /* @__PURE__ */ React36.createElement("div", { className: "relative inline-block" }, children)
2544
2685
  );
2545
2686
  };
2546
2687
  Menu.displayName = "Menu";
2547
- var MenuTrigger = React34.forwardRef(
2688
+ var MenuTrigger = React36.forwardRef(
2548
2689
  ({ children, className, asChild, ...props }, ref) => {
2549
2690
  const { isOpen, setIsOpen, triggerId, menuId } = useMenuContext();
2550
2691
  const handleClick = (e) => {
@@ -2552,7 +2693,7 @@ var MenuTrigger = React34.forwardRef(
2552
2693
  setIsOpen(!isOpen);
2553
2694
  props.onClick?.(e);
2554
2695
  };
2555
- return /* @__PURE__ */ React34.createElement(
2696
+ return /* @__PURE__ */ React36.createElement(
2556
2697
  "button",
2557
2698
  {
2558
2699
  ref,
@@ -2573,7 +2714,7 @@ var MenuTrigger = React34.forwardRef(
2573
2714
  }
2574
2715
  );
2575
2716
  MenuTrigger.displayName = "MenuTrigger";
2576
- var MenuContent = React34.forwardRef(
2717
+ var MenuContent = React36.forwardRef(
2577
2718
  ({ children, className, align = "start", side = "bottom", ...props }, ref) => {
2578
2719
  const { isOpen, setIsOpen, triggerId, menuId } = useMenuContext();
2579
2720
  const menuRef = useRef4(null);
@@ -2607,7 +2748,7 @@ var MenuContent = React34.forwardRef(
2607
2748
  top: "bottom-full mb-1",
2608
2749
  bottom: "top-full mt-1"
2609
2750
  };
2610
- return /* @__PURE__ */ React34.createElement(
2751
+ return /* @__PURE__ */ React36.createElement(
2611
2752
  "div",
2612
2753
  {
2613
2754
  ref: (node) => {
@@ -2633,7 +2774,7 @@ var MenuContent = React34.forwardRef(
2633
2774
  }
2634
2775
  );
2635
2776
  MenuContent.displayName = "MenuContent";
2636
- var MenuItem = React34.forwardRef(
2777
+ var MenuItem = React36.forwardRef(
2637
2778
  ({ children, className, icon, destructive, disabled, onClick, ...props }, ref) => {
2638
2779
  const { setIsOpen } = useMenuContext();
2639
2780
  const handleClick = (e) => {
@@ -2641,7 +2782,7 @@ var MenuItem = React34.forwardRef(
2641
2782
  onClick?.(e);
2642
2783
  setIsOpen(false);
2643
2784
  };
2644
- return /* @__PURE__ */ React34.createElement(
2785
+ return /* @__PURE__ */ React36.createElement(
2645
2786
  "button",
2646
2787
  {
2647
2788
  ref,
@@ -2659,13 +2800,13 @@ var MenuItem = React34.forwardRef(
2659
2800
  ),
2660
2801
  ...props
2661
2802
  },
2662
- icon && /* @__PURE__ */ React34.createElement("span", { className: "w-4 h-4 shrink-0" }, icon),
2803
+ icon && /* @__PURE__ */ React36.createElement("span", { className: "w-4 h-4 shrink-0" }, icon),
2663
2804
  children
2664
2805
  );
2665
2806
  }
2666
2807
  );
2667
2808
  MenuItem.displayName = "MenuItem";
2668
- var MenuSeparator = React34.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React34.createElement(
2809
+ var MenuSeparator = React36.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React36.createElement(
2669
2810
  "div",
2670
2811
  {
2671
2812
  ref,
@@ -2675,7 +2816,7 @@ var MenuSeparator = React34.forwardRef(({ className, ...props }, ref) => /* @__P
2675
2816
  }
2676
2817
  ));
2677
2818
  MenuSeparator.displayName = "MenuSeparator";
2678
- var MenuLabel = React34.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ React34.createElement(
2819
+ var MenuLabel = React36.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ React36.createElement(
2679
2820
  "div",
2680
2821
  {
2681
2822
  ref,
@@ -2687,10 +2828,10 @@ var MenuLabel = React34.forwardRef(({ className, children, ...props }, ref) => /
2687
2828
  MenuLabel.displayName = "MenuLabel";
2688
2829
 
2689
2830
  // src/components/Navbar.tsx
2690
- import React35 from "react";
2691
- var Navbar = React35.forwardRef(
2831
+ import React37 from "react";
2832
+ var Navbar = React37.forwardRef(
2692
2833
  ({ fixed = false, bordered = true, className, children, ...props }, ref) => {
2693
- return /* @__PURE__ */ React35.createElement(
2834
+ return /* @__PURE__ */ React37.createElement(
2694
2835
  "nav",
2695
2836
  {
2696
2837
  ref,
@@ -2702,14 +2843,14 @@ var Navbar = React35.forwardRef(
2702
2843
  ),
2703
2844
  ...props
2704
2845
  },
2705
- /* @__PURE__ */ React35.createElement("div", { className: "flex items-center justify-between" }, children)
2846
+ /* @__PURE__ */ React37.createElement("div", { className: "flex items-center justify-between" }, children)
2706
2847
  );
2707
2848
  }
2708
2849
  );
2709
2850
  Navbar.displayName = "Navbar";
2710
- var NavbarBrand = React35.forwardRef(
2851
+ var NavbarBrand = React37.forwardRef(
2711
2852
  ({ className, children, ...props }, ref) => {
2712
- return /* @__PURE__ */ React35.createElement(
2853
+ return /* @__PURE__ */ React37.createElement(
2713
2854
  "div",
2714
2855
  {
2715
2856
  ref,
@@ -2721,14 +2862,14 @@ var NavbarBrand = React35.forwardRef(
2721
2862
  }
2722
2863
  );
2723
2864
  NavbarBrand.displayName = "NavbarBrand";
2724
- var NavbarContent = React35.forwardRef(
2865
+ var NavbarContent = React37.forwardRef(
2725
2866
  ({ position = "center", className, children, ...props }, ref) => {
2726
2867
  const positionClasses = {
2727
2868
  start: "mr-auto",
2728
2869
  center: "mx-auto",
2729
2870
  end: "ml-auto"
2730
2871
  };
2731
- return /* @__PURE__ */ React35.createElement(
2872
+ return /* @__PURE__ */ React37.createElement(
2732
2873
  "div",
2733
2874
  {
2734
2875
  ref,
@@ -2744,9 +2885,9 @@ var NavbarContent = React35.forwardRef(
2744
2885
  }
2745
2886
  );
2746
2887
  NavbarContent.displayName = "NavbarContent";
2747
- var NavbarItem = React35.forwardRef(
2888
+ var NavbarItem = React37.forwardRef(
2748
2889
  ({ active = false, className, children, ...props }, ref) => {
2749
- return /* @__PURE__ */ React35.createElement(
2890
+ return /* @__PURE__ */ React37.createElement(
2750
2891
  "div",
2751
2892
  {
2752
2893
  ref,
@@ -2761,9 +2902,9 @@ var NavbarItem = React35.forwardRef(
2761
2902
  }
2762
2903
  );
2763
2904
  NavbarItem.displayName = "NavbarItem";
2764
- var NavbarLink = React35.forwardRef(
2905
+ var NavbarLink = React37.forwardRef(
2765
2906
  ({ active = false, className, children, ...props }, ref) => {
2766
- return /* @__PURE__ */ React35.createElement(
2907
+ return /* @__PURE__ */ React37.createElement(
2767
2908
  "a",
2768
2909
  {
2769
2910
  ref,
@@ -2779,7 +2920,7 @@ var NavbarLink = React35.forwardRef(
2779
2920
  }
2780
2921
  );
2781
2922
  NavbarLink.displayName = "NavbarLink";
2782
- var NavbarDivider = React35.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React35.createElement(
2923
+ var NavbarDivider = React37.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React37.createElement(
2783
2924
  "div",
2784
2925
  {
2785
2926
  ref,
@@ -2790,19 +2931,19 @@ var NavbarDivider = React35.forwardRef(({ className, ...props }, ref) => /* @__P
2790
2931
  NavbarDivider.displayName = "NavbarDivider";
2791
2932
 
2792
2933
  // src/components/Breadcrumb.tsx
2793
- import React36 from "react";
2934
+ import React38 from "react";
2794
2935
  import { ChevronRight } from "lucide-react";
2795
- var Breadcrumb = React36.forwardRef(
2936
+ var Breadcrumb = React38.forwardRef(
2796
2937
  ({ separator, className, children, ...props }, ref) => {
2797
- const items = React36.Children.toArray(children);
2798
- const defaultSeparator = /* @__PURE__ */ React36.createElement(ChevronRight, { className: "h-4 w-4 text-ash" });
2799
- return /* @__PURE__ */ React36.createElement("nav", { ref, "aria-label": "Breadcrumb", className, ...props }, /* @__PURE__ */ React36.createElement("ol", { className: "flex items-center gap-2" }, items.map((child, index) => /* @__PURE__ */ React36.createElement("li", { key: index, className: "flex items-center gap-2" }, child, index < items.length - 1 && /* @__PURE__ */ React36.createElement("span", { "aria-hidden": "true" }, separator ?? defaultSeparator)))));
2938
+ const items = React38.Children.toArray(children);
2939
+ const defaultSeparator = /* @__PURE__ */ React38.createElement(ChevronRight, { className: "h-4 w-4 text-ash" });
2940
+ return /* @__PURE__ */ React38.createElement("nav", { ref, "aria-label": "Breadcrumb", className, ...props }, /* @__PURE__ */ React38.createElement("ol", { className: "flex items-center gap-2" }, items.map((child, index) => /* @__PURE__ */ React38.createElement("li", { key: index, className: "flex items-center gap-2" }, child, index < items.length - 1 && /* @__PURE__ */ React38.createElement("span", { "aria-hidden": "true" }, separator ?? defaultSeparator)))));
2800
2941
  }
2801
2942
  );
2802
2943
  Breadcrumb.displayName = "Breadcrumb";
2803
- var BreadcrumbItem = React36.forwardRef(
2944
+ var BreadcrumbItem = React38.forwardRef(
2804
2945
  ({ current = false, className, children, ...props }, ref) => {
2805
- return /* @__PURE__ */ React36.createElement(
2946
+ return /* @__PURE__ */ React38.createElement(
2806
2947
  "span",
2807
2948
  {
2808
2949
  ref,
@@ -2819,9 +2960,9 @@ var BreadcrumbItem = React36.forwardRef(
2819
2960
  }
2820
2961
  );
2821
2962
  BreadcrumbItem.displayName = "BreadcrumbItem";
2822
- var BreadcrumbLink = React36.forwardRef(
2963
+ var BreadcrumbLink = React38.forwardRef(
2823
2964
  ({ className, children, ...props }, ref) => {
2824
- return /* @__PURE__ */ React36.createElement(
2965
+ return /* @__PURE__ */ React38.createElement(
2825
2966
  "a",
2826
2967
  {
2827
2968
  ref,
@@ -2838,7 +2979,7 @@ var BreadcrumbLink = React36.forwardRef(
2838
2979
  BreadcrumbLink.displayName = "BreadcrumbLink";
2839
2980
 
2840
2981
  // src/components/Pagination.tsx
2841
- import React37 from "react";
2982
+ import React39 from "react";
2842
2983
  import { ChevronLeft, ChevronRight as ChevronRight2, MoreHorizontal } from "lucide-react";
2843
2984
  function generatePagination(currentPage, totalPages, siblingCount) {
2844
2985
  const totalSlots = siblingCount * 2 + 5;
@@ -2868,7 +3009,7 @@ function generatePagination(currentPage, totalPages, siblingCount) {
2868
3009
  );
2869
3010
  return [1, "ellipsis", ...middleRange, "ellipsis", totalPages];
2870
3011
  }
2871
- var Pagination = React37.forwardRef(
3012
+ var Pagination = React39.forwardRef(
2872
3013
  ({
2873
3014
  page,
2874
3015
  totalPages,
@@ -2880,7 +3021,7 @@ var Pagination = React37.forwardRef(
2880
3021
  }, ref) => {
2881
3022
  const pages = generatePagination(page, totalPages, siblingCount);
2882
3023
  const buttonBaseClass = "flex items-center justify-center h-8 min-w-8 px-2 text-sm border border-ash transition-colors duration-fast focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gold";
2883
- return /* @__PURE__ */ React37.createElement(
3024
+ return /* @__PURE__ */ React39.createElement(
2884
3025
  "nav",
2885
3026
  {
2886
3027
  ref,
@@ -2889,7 +3030,7 @@ var Pagination = React37.forwardRef(
2889
3030
  className: cx("flex items-center gap-1", className),
2890
3031
  ...props
2891
3032
  },
2892
- /* @__PURE__ */ React37.createElement(
3033
+ /* @__PURE__ */ React39.createElement(
2893
3034
  "button",
2894
3035
  {
2895
3036
  type: "button",
@@ -2902,17 +3043,17 @@ var Pagination = React37.forwardRef(
2902
3043
  page <= 1 && "opacity-50 cursor-not-allowed hover:border-ash"
2903
3044
  )
2904
3045
  },
2905
- /* @__PURE__ */ React37.createElement(ChevronLeft, { className: "h-4 w-4" })
3046
+ /* @__PURE__ */ React39.createElement(ChevronLeft, { className: "h-4 w-4" })
2906
3047
  ),
2907
3048
  pages.map(
2908
- (pageNum, index) => pageNum === "ellipsis" ? /* @__PURE__ */ React37.createElement(
3049
+ (pageNum, index) => pageNum === "ellipsis" ? /* @__PURE__ */ React39.createElement(
2909
3050
  "span",
2910
3051
  {
2911
3052
  key: `ellipsis-${index}`,
2912
3053
  className: "flex items-center justify-center h-8 w-8 text-silver"
2913
3054
  },
2914
- /* @__PURE__ */ React37.createElement(MoreHorizontal, { className: "h-4 w-4" })
2915
- ) : /* @__PURE__ */ React37.createElement(
3055
+ /* @__PURE__ */ React39.createElement(MoreHorizontal, { className: "h-4 w-4" })
3056
+ ) : /* @__PURE__ */ React39.createElement(
2916
3057
  "button",
2917
3058
  {
2918
3059
  key: pageNum,
@@ -2928,7 +3069,7 @@ var Pagination = React37.forwardRef(
2928
3069
  pageNum
2929
3070
  )
2930
3071
  ),
2931
- /* @__PURE__ */ React37.createElement(
3072
+ /* @__PURE__ */ React39.createElement(
2932
3073
  "button",
2933
3074
  {
2934
3075
  type: "button",
@@ -2941,7 +3082,7 @@ var Pagination = React37.forwardRef(
2941
3082
  page >= totalPages && "opacity-50 cursor-not-allowed hover:border-ash"
2942
3083
  )
2943
3084
  },
2944
- /* @__PURE__ */ React37.createElement(ChevronRight2, { className: "h-4 w-4" })
3085
+ /* @__PURE__ */ React39.createElement(ChevronRight2, { className: "h-4 w-4" })
2945
3086
  )
2946
3087
  );
2947
3088
  }
@@ -2949,9 +3090,9 @@ var Pagination = React37.forwardRef(
2949
3090
  Pagination.displayName = "Pagination";
2950
3091
 
2951
3092
  // src/components/Stepper.tsx
2952
- import React38 from "react";
3093
+ import React40 from "react";
2953
3094
  import { Check as Check2 } from "lucide-react";
2954
- var Stepper = React38.forwardRef(
3095
+ var Stepper = React40.forwardRef(
2955
3096
  ({ steps, currentStep, status, className, ...rest }, ref) => {
2956
3097
  const currentIndex = steps.findIndex((step) => step.id === currentStep);
2957
3098
  const getStepState = (index) => {
@@ -2963,7 +3104,7 @@ var Stepper = React38.forwardRef(
2963
3104
  }
2964
3105
  return "future";
2965
3106
  };
2966
- return /* @__PURE__ */ React38.createElement(
3107
+ return /* @__PURE__ */ React40.createElement(
2967
3108
  "div",
2968
3109
  {
2969
3110
  ref,
@@ -2973,7 +3114,7 @@ var Stepper = React38.forwardRef(
2973
3114
  steps.map((step, index) => {
2974
3115
  const state = getStepState(index);
2975
3116
  const isLast = index === steps.length - 1;
2976
- return /* @__PURE__ */ React38.createElement(React38.Fragment, { key: step.id }, /* @__PURE__ */ React38.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React38.createElement(
3117
+ return /* @__PURE__ */ React40.createElement(React40.Fragment, { key: step.id }, /* @__PURE__ */ React40.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React40.createElement(
2977
3118
  "div",
2978
3119
  {
2979
3120
  className: cx(
@@ -2984,8 +3125,8 @@ var Stepper = React38.forwardRef(
2984
3125
  state === "future" && "bg-charcoal border-ash text-silver"
2985
3126
  )
2986
3127
  },
2987
- state === "complete" ? /* @__PURE__ */ React38.createElement(Check2, { className: "h-5 w-5" }) : /* @__PURE__ */ React38.createElement("span", null, index + 1)
2988
- ), /* @__PURE__ */ React38.createElement(
3128
+ state === "complete" ? /* @__PURE__ */ React40.createElement(Check2, { className: "h-5 w-5" }) : /* @__PURE__ */ React40.createElement("span", null, index + 1)
3129
+ ), /* @__PURE__ */ React40.createElement(
2989
3130
  "span",
2990
3131
  {
2991
3132
  className: cx(
@@ -2997,7 +3138,7 @@ var Stepper = React38.forwardRef(
2997
3138
  )
2998
3139
  },
2999
3140
  step.label
3000
- )), !isLast && /* @__PURE__ */ React38.createElement(
3141
+ )), !isLast && /* @__PURE__ */ React40.createElement(
3001
3142
  "div",
3002
3143
  {
3003
3144
  className: cx(
@@ -3013,10 +3154,10 @@ var Stepper = React38.forwardRef(
3013
3154
  Stepper.displayName = "Stepper";
3014
3155
 
3015
3156
  // src/components/Message.tsx
3016
- import React41 from "react";
3157
+ import React42, { useState as useState10, useEffect as useEffect6, useRef as useRef5 } from "react";
3017
3158
 
3018
3159
  // src/components/MarkdownContent.tsx
3019
- import React39, { useMemo } from "react";
3160
+ import React41, { useMemo } from "react";
3020
3161
  import DOMPurify from "dompurify";
3021
3162
  var DEFAULT_SANITIZE_CONFIG = {
3022
3163
  ALLOWED_TAGS: [
@@ -3095,17 +3236,45 @@ function useDOMPurifySetup() {
3095
3236
  });
3096
3237
  }, []);
3097
3238
  }
3098
- var MarkdownContent = React39.forwardRef(
3099
- ({ className, content, sanitizeConfig, ...rest }, ref) => {
3239
+ var CURSOR_BASE_CLASSES = "inline-block bg-current animate-cursor-blink w-0.5 h-cursor translate-y-cursor-offset";
3240
+ function injectStreamingCursor(html, cursorClassName) {
3241
+ if (!html.trim()) {
3242
+ return `<span class="${cx(CURSOR_BASE_CLASSES, cursorClassName)}" aria-hidden="true"></span>`;
3243
+ }
3244
+ const cursorHtml = `<span class="${cx(CURSOR_BASE_CLASSES, cursorClassName)}" aria-hidden="true"></span>`;
3245
+ const parser = new DOMParser();
3246
+ const doc = parser.parseFromString(`<div>${html}</div>`, "text/html");
3247
+ const container = doc.body.firstChild;
3248
+ if (!container) {
3249
+ return html + cursorHtml;
3250
+ }
3251
+ let target = container;
3252
+ while (target.lastElementChild) {
3253
+ const lastChild = target.lastElementChild;
3254
+ const tagName = lastChild.tagName.toLowerCase();
3255
+ if (["code", "a", "strong", "em", "b", "i", "span", "mark", "del", "s"].includes(tagName)) {
3256
+ break;
3257
+ }
3258
+ target = lastChild;
3259
+ }
3260
+ target.insertAdjacentHTML("beforeend", cursorHtml);
3261
+ return container.innerHTML;
3262
+ }
3263
+ var MarkdownContent = React41.forwardRef(
3264
+ ({ className, content, sanitizeConfig, isStreaming, cursorClassName, ...rest }, ref) => {
3100
3265
  useDOMPurifySetup();
3101
3266
  const sanitizedHtml = useMemo(() => {
3102
- if (!content) {
3267
+ if (!content && !isStreaming) {
3103
3268
  return "";
3104
3269
  }
3105
3270
  const config = sanitizeConfig ?? DEFAULT_SANITIZE_CONFIG;
3106
- return DOMPurify.sanitize(content, config);
3107
- }, [content, sanitizeConfig]);
3108
- return /* @__PURE__ */ React39.createElement(
3271
+ const sanitized = content ? DOMPurify.sanitize(content, config) : "";
3272
+ if (isStreaming) {
3273
+ return injectStreamingCursor(sanitized, cursorClassName);
3274
+ }
3275
+ return sanitized;
3276
+ }, [content, sanitizeConfig, isStreaming, cursorClassName]);
3277
+ return /* @__PURE__ */ React41.createElement(
3109
3278
  "div",
3110
3279
  {
3111
3280
  ref,
@@ -3118,16 +3287,202 @@ var MarkdownContent = React39.forwardRef(
3118
3287
  );
3119
3288
  MarkdownContent.displayName = "MarkdownContent";
3120
3289
 
3290
+ // src/components/Message.tsx
3291
+ var variantStyles2 = {
3292
+ user: "bg-gold text-obsidian ml-auto",
3293
+ assistant: "bg-charcoal border border-ash text-white mr-auto"
3294
+ };
3295
+ var ActionButton = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React42.createElement(
3296
+ "button",
3297
+ {
3298
+ type: "button",
3299
+ onClick,
3300
+ disabled,
3301
+ className: cx(
3302
+ "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
3303
+ "hover:bg-white/5",
3304
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
3305
+ className
3306
+ ),
3307
+ "aria-label": label
3308
+ },
3309
+ children
3310
+ );
3311
+ var CopyIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3.5 h-3.5" }, /* @__PURE__ */ React42.createElement("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }), /* @__PURE__ */ React42.createElement("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" }));
3312
+ var CheckIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3.5 h-3.5 text-success" }, /* @__PURE__ */ React42.createElement("polyline", { points: "20 6 9 17 4 12" }));
3313
+ var PencilIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3.5 h-3.5" }, /* @__PURE__ */ React42.createElement("path", { d: "M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }), /* @__PURE__ */ React42.createElement("path", { d: "m15 5 4 4" }));
3314
+ var RetryIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3.5 h-3.5" }, /* @__PURE__ */ React42.createElement("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }), /* @__PURE__ */ React42.createElement("path", { d: "M21 3v5h-5" }), /* @__PURE__ */ React42.createElement("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }), /* @__PURE__ */ React42.createElement("path", { d: "M8 16H3v5" }));
3315
+ var ChevronLeftIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3 h-3" }, /* @__PURE__ */ React42.createElement("path", { d: "m15 18-6-6 6-6" }));
3316
+ var ChevronRightIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3 h-3" }, /* @__PURE__ */ React42.createElement("path", { d: "m9 18 6-6-6-6" }));
3317
+ var GitBranchIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-3 h-3 mr-0.5 text-silver/50" }, /* @__PURE__ */ React42.createElement("line", { x1: "6", x2: "6", y1: "3", y2: "15" }), /* @__PURE__ */ React42.createElement("circle", { cx: "18", cy: "6", r: "3" }), /* @__PURE__ */ React42.createElement("circle", { cx: "6", cy: "18", r: "3" }), /* @__PURE__ */ React42.createElement("path", { d: "M18 9a9 9 0 0 1-9 9" }));
3318
+ var XIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-4 h-4" }, /* @__PURE__ */ React42.createElement("path", { d: "M18 6 6 18" }), /* @__PURE__ */ React42.createElement("path", { d: "m6 6 12 12" }));
3319
+ var SendIcon = () => /* @__PURE__ */ React42.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "w-4 h-4" }, /* @__PURE__ */ React42.createElement("path", { d: "m22 2-7 20-4-9-9-4Z" }), /* @__PURE__ */ React42.createElement("path", { d: "M22 2 11 13" }));
3320
+ var Message = React42.forwardRef(
3321
+ ({ variant = "assistant", className, content, isStreaming, branchInfo, actions, hideActions, ...rest }, ref) => {
3322
+ const isUser = variant === "user";
3323
+ const [copied, setCopied] = useState10(false);
3324
+ const [isEditing, setIsEditing] = useState10(false);
3325
+ const [editValue, setEditValue] = useState10(content);
3326
+ const textareaRef = useRef5(null);
3327
+ const showBranchNav = branchInfo && branchInfo.total > 1;
3328
+ const showActions = actions && !hideActions && !isStreaming;
3329
+ useEffect6(() => {
3330
+ if (isEditing && textareaRef.current) {
3331
+ const textarea = textareaRef.current;
3332
+ textarea.style.height = "auto";
3333
+ textarea.style.height = `${textarea.scrollHeight}px`;
3334
+ textarea.focus();
3335
+ textarea.setSelectionRange(textarea.value.length, textarea.value.length);
3336
+ }
3337
+ }, [isEditing]);
3338
+ const handleCopy = async () => {
3339
+ try {
3340
+ await navigator.clipboard.writeText(content);
3341
+ setCopied(true);
3342
+ setTimeout(() => setCopied(false), 2e3);
3343
+ } catch {
3344
+ const textArea = document.createElement("textarea");
3345
+ textArea.value = content;
3346
+ document.body.appendChild(textArea);
3347
+ textArea.select();
3348
+ document.execCommand("copy");
3349
+ document.body.removeChild(textArea);
3350
+ setCopied(true);
3351
+ setTimeout(() => setCopied(false), 2e3);
3352
+ }
3353
+ };
3354
+ const handleStartEdit = () => {
3355
+ setEditValue(content);
3356
+ setIsEditing(true);
3357
+ };
3358
+ const handleCancelEdit = () => {
3359
+ setIsEditing(false);
3360
+ setEditValue(content);
3361
+ };
3362
+ const handleSubmitEdit = () => {
3363
+ const trimmed = editValue.trim();
3364
+ if (trimmed && trimmed !== content) {
3365
+ actions?.onEdit?.(trimmed);
3366
+ }
3367
+ setIsEditing(false);
3368
+ };
3369
+ const handleEditKeyDown = (e) => {
3370
+ if (e.key === "Enter" && !e.shiftKey) {
3371
+ e.preventDefault();
3372
+ handleSubmitEdit();
3373
+ } else if (e.key === "Escape") {
3374
+ handleCancelEdit();
3375
+ }
3376
+ };
3377
+ const handleEditChange = (e) => {
3378
+ setEditValue(e.target.value);
3379
+ const textarea = e.target;
3380
+ textarea.style.height = "auto";
3381
+ textarea.style.height = `${textarea.scrollHeight}px`;
3382
+ };
3383
+ return /* @__PURE__ */ React42.createElement(
3384
+ "div",
3385
+ {
3386
+ ref,
3387
+ className: cx(
3388
+ "flex flex-col",
3389
+ isUser ? "items-end" : "items-start",
3390
+ className
3391
+ ),
3392
+ ...rest
3393
+ },
3394
+ isUser && isEditing ? /* @__PURE__ */ React42.createElement("div", { className: "w-full max-w-11/12" }, /* @__PURE__ */ React42.createElement("div", { className: "relative bg-gold" }, /* @__PURE__ */ React42.createElement(
3395
+ "textarea",
3396
+ {
3397
+ ref: textareaRef,
3398
+ value: editValue,
3399
+ onChange: handleEditChange,
3400
+ onKeyDown: handleEditKeyDown,
3401
+ className: "w-full bg-transparent text-obsidian px-3 py-2 pr-20 resize-none outline-none min-h-10 text-sm",
3402
+ rows: 1
3403
+ }
3404
+ ), /* @__PURE__ */ React42.createElement("div", { className: "absolute right-1 top-1/2 -translate-y-1/2 flex gap-0.5" }, /* @__PURE__ */ React42.createElement(
3405
+ "button",
3406
+ {
3407
+ type: "button",
3408
+ onClick: handleCancelEdit,
3409
+ className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors",
3410
+ "aria-label": "Cancel edit"
3411
+ },
3412
+ /* @__PURE__ */ React42.createElement(XIcon, null)
3413
+ ), /* @__PURE__ */ React42.createElement(
3414
+ "button",
3415
+ {
3416
+ type: "button",
3417
+ onClick: handleSubmitEdit,
3418
+ disabled: !editValue.trim() || editValue.trim() === content,
3419
+ className: "p-1.5 text-obsidian/60 hover:text-obsidian transition-colors disabled:opacity-30",
3420
+ "aria-label": "Submit edit"
3421
+ },
3422
+ /* @__PURE__ */ React42.createElement(SendIcon, null)
3423
+ )))) : /* @__PURE__ */ React42.createElement(
3424
+ "div",
3425
+ {
3426
+ className: cx(
3427
+ "px-3 py-2 w-fit max-w-11/12",
3428
+ variantStyles2[variant]
3429
+ )
3430
+ },
3431
+ /* @__PURE__ */ React42.createElement(
3432
+ MarkdownContent,
3433
+ {
3434
+ content,
3435
+ className: cx("prose-sm", isUser ? "prose-inherit" : "prose-invert"),
3436
+ isStreaming,
3437
+ cursorClassName: "ml-0.5"
3438
+ }
3439
+ )
3440
+ ),
3441
+ showActions && !isEditing && /* @__PURE__ */ React42.createElement("div", { className: cx(
3442
+ "flex items-center gap-0.5 mt-1",
3443
+ isUser ? "mr-1" : "ml-1"
3444
+ ) }, actions.showCopy !== false && /* @__PURE__ */ React42.createElement(ActionButton, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React42.createElement(CheckIcon, null) : /* @__PURE__ */ React42.createElement(CopyIcon, null)), isUser && actions.onEdit && /* @__PURE__ */ React42.createElement(ActionButton, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React42.createElement(PencilIcon, null)), !isUser && actions.onRetry && /* @__PURE__ */ React42.createElement(ActionButton, { onClick: actions.onRetry, label: "Regenerate response" }, /* @__PURE__ */ React42.createElement(RetryIcon, null)), showBranchNav && /* @__PURE__ */ React42.createElement(React42.Fragment, null, /* @__PURE__ */ React42.createElement("div", { className: "w-px h-4 bg-ash/40 mx-1" }), /* @__PURE__ */ React42.createElement("div", { className: "flex items-center gap-0.5 text-silver/70" }, /* @__PURE__ */ React42.createElement(GitBranchIcon, null), /* @__PURE__ */ React42.createElement(
3445
+ "button",
3446
+ {
3447
+ type: "button",
3448
+ onClick: branchInfo.onPrevious,
3449
+ disabled: branchInfo.current <= 1,
3450
+ className: cx(
3451
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
3452
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
3453
+ ),
3454
+ "aria-label": "Previous branch"
3455
+ },
3456
+ /* @__PURE__ */ React42.createElement(ChevronLeftIcon, null)
3457
+ ), /* @__PURE__ */ React42.createElement("span", { className: "text-xs tabular-nums min-w-6 text-center" }, branchInfo.current, "/", branchInfo.total), /* @__PURE__ */ React42.createElement(
3458
+ "button",
3459
+ {
3460
+ type: "button",
3461
+ onClick: branchInfo.onNext,
3462
+ disabled: branchInfo.current >= branchInfo.total,
3463
+ className: cx(
3464
+ "p-0.5 hover:text-white hover:bg-white/10 transition-colors",
3465
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
3466
+ ),
3467
+ "aria-label": "Next branch"
3468
+ },
3469
+ /* @__PURE__ */ React42.createElement(ChevronRightIcon, null)
3470
+ ))))
3471
+ );
3472
+ }
3473
+ );
3474
+ Message.displayName = "Message";
3475
+
3121
3476
  // src/components/StreamingCursor.tsx
3122
- import React40 from "react";
3123
- var StreamingCursor = React40.forwardRef(
3477
+ import React43 from "react";
3478
+ var StreamingCursor = React43.forwardRef(
3124
3479
  ({ className, variant = "line", ...rest }, ref) => {
3125
3480
  const variantStyles3 = {
3126
3481
  block: "w-2.5 h-cursor translate-y-cursor-offset",
3127
3482
  line: "w-0.5 h-cursor translate-y-cursor-offset",
3128
3483
  underscore: "w-2.5 h-0.5 self-end mb-0.5"
3129
3484
  };
3130
- return /* @__PURE__ */ React40.createElement(
3485
+ return /* @__PURE__ */ React43.createElement(
3131
3486
  "span",
3132
3487
  {
3133
3488
  ref,
@@ -3144,131 +3499,852 @@ var StreamingCursor = React40.forwardRef(
3144
3499
  );
3145
3500
  StreamingCursor.displayName = "StreamingCursor";
3146
3501
 
3147
- // src/components/Message.tsx
3148
- var variantStyles2 = {
3149
- user: "bg-gold text-obsidian ml-auto",
3150
- assistant: "bg-charcoal border border-ash text-white mr-auto"
3151
- };
3152
- var Message = React41.forwardRef(
3153
- ({ variant = "assistant", className, content, isStreaming, ...rest }, ref) => {
3154
- const isUser = variant === "user";
3155
- return /* @__PURE__ */ React41.createElement(
3502
+ // src/components/chat/ChatInterface.tsx
3503
+ import React51, { useCallback as useCallback14, useMemo as useMemo3, useState as useState15 } from "react";
3504
+
3505
+ // src/components/chat/ChatView.tsx
3506
+ import React45, { useEffect as useEffect9 } from "react";
3507
+
3508
+ // src/components/chat/hooks/useScrollAnchor.ts
3509
+ import { useCallback as useCallback11, useRef as useRef6 } from "react";
3510
+ function useScrollAnchor(options = {}) {
3511
+ const { behavior = "smooth", block = "start" } = options;
3512
+ const containerRef = useRef6(null);
3513
+ const anchorRef = useRef6(null);
3514
+ const scrollToAnchor = useCallback11(() => {
3515
+ const el = anchorRef.current;
3516
+ if (!el) return;
3517
+ requestAnimationFrame(() => {
3518
+ requestAnimationFrame(() => {
3519
+ el.scrollIntoView({ behavior, block });
3520
+ });
3521
+ });
3522
+ }, [behavior, block]);
3523
+ const scrollToBottom = useCallback11(() => {
3524
+ const container = containerRef.current;
3525
+ if (!container) return;
3526
+ if (typeof container.scrollTo === "function") {
3527
+ container.scrollTo({ top: container.scrollHeight, behavior });
3528
+ } else {
3529
+ container.scrollTop = container.scrollHeight;
3530
+ }
3531
+ }, [behavior]);
3532
+ const isScrolledToBottom = useCallback11(() => {
3533
+ const container = containerRef.current;
3534
+ if (!container) return true;
3535
+ const threshold = 50;
3536
+ const { scrollTop, scrollHeight, clientHeight } = container;
3537
+ return scrollHeight - scrollTop - clientHeight < threshold;
3538
+ }, []);
3539
+ return {
3540
+ containerRef,
3541
+ anchorRef,
3542
+ scrollToAnchor,
3543
+ scrollToBottom,
3544
+ isScrolledToBottom
3545
+ };
3546
+ }
3547
+
3548
+ // src/components/chat/hooks/useAdaptiveSpacer.ts
3549
+ import { useCallback as useCallback12, useEffect as useEffect7, useRef as useRef7, useState as useState11 } from "react";
3550
+ function useAdaptiveSpacer(options = {}) {
3551
+ const { minHeight = 0, containerRef: externalContainerRef, anchorRef } = options;
3552
+ const internalContainerRef = useRef7(null);
3553
+ const containerRef = externalContainerRef ?? internalContainerRef;
3554
+ const contentRef = useRef7(null);
3555
+ const spacerRef = useRef7(null);
3556
+ const [spacerHeight, setSpacerHeight] = useState11(0);
3557
+ const recalculate = useCallback12(() => {
3558
+ const container = containerRef.current;
3559
+ const content = contentRef.current;
3560
+ if (!container || !content) return;
3561
+ const style = getComputedStyle(container);
3562
+ const paddingTop = parseFloat(style.paddingTop) || 0;
3563
+ const paddingBottom = parseFloat(style.paddingBottom) || 0;
3564
+ const availableHeight = container.clientHeight - paddingTop - paddingBottom;
3565
+ let heightFromAnchorToBottom;
3566
+ const anchor = anchorRef?.current;
3567
+ if (anchor && content.contains(anchor)) {
3568
+ const anchorTop = anchor.offsetTop;
3569
+ heightFromAnchorToBottom = content.scrollHeight - anchorTop;
3570
+ } else {
3571
+ heightFromAnchorToBottom = content.scrollHeight;
3572
+ }
3573
+ const newSpacerHeight = Math.max(minHeight, availableHeight - heightFromAnchorToBottom);
3574
+ if (spacerRef.current) {
3575
+ spacerRef.current.style.height = `${newSpacerHeight}px`;
3576
+ }
3577
+ setSpacerHeight(newSpacerHeight);
3578
+ }, [minHeight, anchorRef]);
3579
+ useEffect7(() => {
3580
+ const container = containerRef.current;
3581
+ const content = contentRef.current;
3582
+ if (!container || !content) return;
3583
+ recalculate();
3584
+ const resizeObserver = new ResizeObserver(() => {
3585
+ recalculate();
3586
+ });
3587
+ resizeObserver.observe(container);
3588
+ resizeObserver.observe(content);
3589
+ const mutationObserver = new MutationObserver(() => {
3590
+ requestAnimationFrame(recalculate);
3591
+ });
3592
+ mutationObserver.observe(content, {
3593
+ childList: true,
3594
+ subtree: true,
3595
+ characterData: true
3596
+ });
3597
+ return () => {
3598
+ resizeObserver.disconnect();
3599
+ mutationObserver.disconnect();
3600
+ };
3601
+ }, [recalculate]);
3602
+ return {
3603
+ containerRef,
3604
+ contentRef,
3605
+ spacerRef,
3606
+ spacerHeight,
3607
+ recalculate
3608
+ };
3609
+ }
3610
+
3611
+ // src/components/chat/ThinkingIndicator.tsx
3612
+ import React44, { useState as useState12, useEffect as useEffect8 } from "react";
3613
+ var THINKING_PHRASES = [
3614
+ "Consulting the ancient tomes...",
3615
+ "Parsing the ineffable...",
3616
+ "Traversing the manifold of possibilities...",
3617
+ "Genuflecting before the oracle...",
3618
+ "Distilling quintessence...",
3619
+ "Communing with the machine spirits...",
3620
+ "Unfolding higher dimensions...",
3621
+ "Perturbing the probability matrix...",
3622
+ "Invoking the categorical imperative...",
3623
+ "Reticulating splines...",
3624
+ "Brewing a fresh batch of tokens...",
3625
+ "Consulting my inner monologue...",
3626
+ "Summoning the muse..."
3627
+ ];
3628
+ var ThinkingIndicator = React44.forwardRef(
3629
+ ({
3630
+ isVisible = true,
3631
+ phraseInterval = 2500,
3632
+ phrases = THINKING_PHRASES,
3633
+ className,
3634
+ ...rest
3635
+ }, ref) => {
3636
+ const [currentIndex, setCurrentIndex] = useState12(() => Math.floor(Math.random() * phrases.length));
3637
+ const [isTransitioning, setIsTransitioning] = useState12(false);
3638
+ useEffect8(() => {
3639
+ if (!isVisible || phrases.length <= 1) return;
3640
+ const interval = setInterval(() => {
3641
+ setIsTransitioning(true);
3642
+ setTimeout(() => {
3643
+ setCurrentIndex((prev) => (prev + 1) % phrases.length);
3644
+ setIsTransitioning(false);
3645
+ }, 200);
3646
+ }, phraseInterval);
3647
+ return () => clearInterval(interval);
3648
+ }, [isVisible, phrases.length, phraseInterval]);
3649
+ if (!isVisible) return null;
3650
+ return /* @__PURE__ */ React44.createElement(
3156
3651
  "div",
3157
3652
  {
3158
3653
  ref,
3159
3654
  className: cx(
3160
- "px-3 py-2 w-fit",
3161
- variantStyles2[variant],
3655
+ "flex items-center gap-2 px-3 py-2 w-fit",
3656
+ "bg-charcoal border border-ash text-silver",
3657
+ "mr-auto",
3162
3658
  className
3163
3659
  ),
3660
+ role: "status",
3661
+ "aria-live": "polite",
3164
3662
  ...rest
3165
3663
  },
3166
- /* @__PURE__ */ React41.createElement(
3167
- MarkdownContent,
3664
+ /* @__PURE__ */ React44.createElement("div", { className: "flex gap-1", "aria-hidden": "true" }, /* @__PURE__ */ React44.createElement("span", { className: "w-1.5 h-1.5 bg-gold/60 rounded-full animate-pulse", style: { animationDelay: "0ms" } }), /* @__PURE__ */ React44.createElement("span", { className: "w-1.5 h-1.5 bg-gold/60 rounded-full animate-pulse", style: { animationDelay: "150ms" } }), /* @__PURE__ */ React44.createElement("span", { className: "w-1.5 h-1.5 bg-gold/60 rounded-full animate-pulse", style: { animationDelay: "300ms" } })),
3665
+ /* @__PURE__ */ React44.createElement(
3666
+ "span",
3168
3667
  {
3169
- content,
3170
- className: cx("prose-sm", isUser ? "prose-inherit" : "prose-invert")
3171
- }
3172
- ),
3173
- isStreaming && /* @__PURE__ */ React41.createElement(StreamingCursor, { className: "ml-0.5" })
3668
+ className: cx(
3669
+ "text-sm italic transition-opacity duration-200",
3670
+ isTransitioning ? "opacity-0" : "opacity-100"
3671
+ )
3672
+ },
3673
+ phrases[currentIndex]
3674
+ )
3174
3675
  );
3175
3676
  }
3176
3677
  );
3177
- Message.displayName = "Message";
3678
+ ThinkingIndicator.displayName = "ThinkingIndicator";
3178
3679
 
3179
- // src/components/ChatHistory.tsx
3180
- import React42, { useEffect as useEffect6, useRef as useRef5 } from "react";
3181
- var ChatHistory = ({ messages, className, ...rest }) => {
3182
- const innerRef = useRef5(null);
3183
- useEffect6(() => {
3184
- const el = innerRef.current;
3185
- if (!el) {
3186
- return;
3187
- }
3188
- if (typeof el.scrollTo === "function") {
3189
- el.scrollTo({ top: el.scrollHeight, behavior: "smooth" });
3190
- } else {
3191
- el.scrollTop = el.scrollHeight;
3192
- }
3193
- }, [messages]);
3194
- return /* @__PURE__ */ React42.createElement(
3195
- "div",
3196
- {
3197
- ref: innerRef,
3198
- className: cx(
3199
- "flex flex-col gap-3 justify-end w-full h-96 bg-charcoal/50 border border-ash/40 p-4 overflow-y-auto",
3200
- className
3201
- ),
3202
- ...rest
3203
- },
3204
- messages.map(({ id, variant, className: messageClassName, ...messageProps }, index) => /* @__PURE__ */ React42.createElement(
3205
- Message,
3680
+ // src/components/chat/ChatView.tsx
3681
+ var ChatView = React45.forwardRef(
3682
+ ({ messages, latestUserMessageIndex, isStreaming, isThinking, onScroll, className, ...rest }, ref) => {
3683
+ const { containerRef, anchorRef, scrollToAnchor } = useScrollAnchor({
3684
+ behavior: "smooth",
3685
+ block: "start"
3686
+ });
3687
+ const { contentRef, spacerRef, spacerHeight } = useAdaptiveSpacer({
3688
+ containerRef,
3689
+ anchorRef
3690
+ });
3691
+ useEffect9(() => {
3692
+ if (latestUserMessageIndex !== void 0 && latestUserMessageIndex >= 0) {
3693
+ scrollToAnchor();
3694
+ }
3695
+ }, [latestUserMessageIndex, scrollToAnchor]);
3696
+ const latestUserIdx = latestUserMessageIndex ?? messages.reduceRight((found, msg, idx) => {
3697
+ if (found === -1 && msg.variant === "user") {
3698
+ return idx;
3699
+ }
3700
+ return found;
3701
+ }, -1);
3702
+ const showThinking = isThinking && messages.length > 0 && messages[messages.length - 1]?.variant === "user";
3703
+ return /* @__PURE__ */ React45.createElement(
3704
+ "div",
3206
3705
  {
3207
- key: id ?? index,
3706
+ ref: (node) => {
3707
+ ;
3708
+ containerRef.current = node;
3709
+ if (typeof ref === "function") {
3710
+ ref(node);
3711
+ } else if (ref) {
3712
+ ref.current = node;
3713
+ }
3714
+ },
3715
+ onScroll,
3716
+ className: cx(
3717
+ "flex flex-col w-full h-full overflow-y-auto scroll-smooth",
3718
+ "px-4 py-6 overscroll-contain",
3719
+ className
3720
+ ),
3721
+ ...rest
3722
+ },
3723
+ /* @__PURE__ */ React45.createElement("div", { ref: contentRef, className: "relative flex flex-col gap-3" }, messages.map(({
3724
+ id,
3208
3725
  variant,
3209
3726
  className: messageClassName,
3727
+ branchInfo,
3728
+ actions,
3729
+ isStreaming: nodeIsStreaming,
3210
3730
  ...messageProps
3211
- }
3212
- ))
3213
- );
3214
- };
3215
- ChatHistory.displayName = "ChatHistory";
3731
+ }, index) => {
3732
+ const isAnchor = index === latestUserIdx;
3733
+ const isLastMessage = index === messages.length - 1;
3734
+ const showStreaming = isLastMessage && isStreaming && variant === "assistant";
3735
+ const isMessageStreaming = showStreaming || !!nodeIsStreaming;
3736
+ return /* @__PURE__ */ React45.createElement(
3737
+ "div",
3738
+ {
3739
+ key: id ?? `msg-${index}`,
3740
+ ref: isAnchor ? anchorRef : void 0,
3741
+ className: isAnchor ? "scroll-mt-4" : void 0
3742
+ },
3743
+ /* @__PURE__ */ React45.createElement(
3744
+ Message,
3745
+ {
3746
+ variant,
3747
+ isStreaming: isMessageStreaming,
3748
+ className: messageClassName,
3749
+ branchInfo,
3750
+ actions,
3751
+ hideActions: isMessageStreaming,
3752
+ ...messageProps
3753
+ }
3754
+ )
3755
+ );
3756
+ }), showThinking && /* @__PURE__ */ React45.createElement(ThinkingIndicator, { isVisible: true })),
3757
+ /* @__PURE__ */ React45.createElement(
3758
+ "div",
3759
+ {
3760
+ ref: spacerRef,
3761
+ className: "shrink-0 pointer-events-none",
3762
+ style: { height: spacerHeight },
3763
+ "aria-hidden": "true"
3764
+ }
3765
+ )
3766
+ );
3767
+ }
3768
+ );
3769
+ ChatView.displayName = "ChatView";
3216
3770
 
3217
- // src/components/BrandIcon.tsx
3218
- import React43 from "react";
3219
- var sizeMap2 = {
3220
- sm: "h-8 w-8 text-sm",
3221
- md: "h-12 w-12 text-base",
3222
- lg: "h-16 w-16 text-lg"
3223
- };
3224
- var BrandIcon = React43.forwardRef(
3225
- ({ size = "md", variant = "solid", children, className, ...rest }, ref) => {
3226
- const variantClasses = variant === "solid" ? "bg-gold text-obsidian border-2 border-gold" : "bg-transparent text-gold border-2 border-gold";
3227
- return /* @__PURE__ */ React43.createElement(
3771
+ // src/components/chat/ChatInput.tsx
3772
+ import React46, { useCallback as useCallback13, useEffect as useEffect10, useRef as useRef8, useState as useState13 } from "react";
3773
+ import { Paperclip, Send, Square } from "lucide-react";
3774
+
3775
+ // src/components/chat/types.ts
3776
+ function isImageFile(file) {
3777
+ return file.type.startsWith("image/");
3778
+ }
3779
+ function createPreviewUrl(file) {
3780
+ if (isImageFile(file)) {
3781
+ return URL.createObjectURL(file);
3782
+ }
3783
+ return void 0;
3784
+ }
3785
+ function revokePreviewUrl(url) {
3786
+ if (url) {
3787
+ URL.revokeObjectURL(url);
3788
+ }
3789
+ }
3790
+ function generateId() {
3791
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3792
+ }
3793
+ function createEmptyTree() {
3794
+ return {
3795
+ nodes: {},
3796
+ rootIds: [],
3797
+ activeLeafId: null
3798
+ };
3799
+ }
3800
+ function addMessageToTree(tree, message, parentId = null) {
3801
+ const newNodes = { ...tree.nodes };
3802
+ const newRootIds = [...tree.rootIds];
3803
+ let branchIndex = 0;
3804
+ if (parentId && newNodes[parentId]) {
3805
+ branchIndex = newNodes[parentId].children.length;
3806
+ } else if (!parentId) {
3807
+ branchIndex = newRootIds.length;
3808
+ }
3809
+ const newNode = {
3810
+ ...message,
3811
+ parentId,
3812
+ children: [],
3813
+ branchIndex,
3814
+ createdAt: message.createdAt ?? Date.now()
3815
+ };
3816
+ newNodes[message.id] = newNode;
3817
+ if (parentId && newNodes[parentId]) {
3818
+ newNodes[parentId] = {
3819
+ ...newNodes[parentId],
3820
+ children: [...newNodes[parentId].children, message.id]
3821
+ };
3822
+ } else {
3823
+ newRootIds.push(message.id);
3824
+ }
3825
+ return {
3826
+ nodes: newNodes,
3827
+ rootIds: newRootIds,
3828
+ activeLeafId: message.id
3829
+ };
3830
+ }
3831
+ function getActivePathMessages(tree) {
3832
+ if (!tree.activeLeafId) return [];
3833
+ const path = [];
3834
+ let currentId = tree.activeLeafId;
3835
+ while (currentId) {
3836
+ const node = tree.nodes[currentId];
3837
+ if (!node) break;
3838
+ path.unshift(node);
3839
+ currentId = node.parentId;
3840
+ }
3841
+ return path;
3842
+ }
3843
+ function getSiblingInfo(tree, nodeId) {
3844
+ const node = tree.nodes[nodeId];
3845
+ if (!node) return { total: 1, current: 1 };
3846
+ if (node.parentId) {
3847
+ const parent = tree.nodes[node.parentId];
3848
+ if (parent) {
3849
+ const index = parent.children.indexOf(nodeId);
3850
+ return {
3851
+ total: parent.children.length,
3852
+ current: index + 1
3853
+ };
3854
+ }
3855
+ } else {
3856
+ const index = tree.rootIds.indexOf(nodeId);
3857
+ return {
3858
+ total: tree.rootIds.length,
3859
+ current: index + 1
3860
+ };
3861
+ }
3862
+ return { total: 1, current: 1 };
3863
+ }
3864
+ function switchBranch(tree, nodeId, direction) {
3865
+ const node = tree.nodes[nodeId];
3866
+ if (!node) return tree;
3867
+ let siblings;
3868
+ let currentIndex;
3869
+ if (node.parentId) {
3870
+ const parent = tree.nodes[node.parentId];
3871
+ if (!parent) return tree;
3872
+ siblings = parent.children;
3873
+ currentIndex = siblings.indexOf(nodeId);
3874
+ } else {
3875
+ siblings = tree.rootIds;
3876
+ currentIndex = siblings.indexOf(nodeId);
3877
+ }
3878
+ if (siblings.length <= 1) return tree;
3879
+ const newIndex = direction === "next" ? (currentIndex + 1) % siblings.length : (currentIndex - 1 + siblings.length) % siblings.length;
3880
+ const newNodeId = siblings[newIndex];
3881
+ let leafId = newNodeId;
3882
+ let currentNode = tree.nodes[leafId];
3883
+ while (currentNode && currentNode.children.length > 0) {
3884
+ leafId = currentNode.children[0];
3885
+ currentNode = tree.nodes[leafId];
3886
+ }
3887
+ return {
3888
+ ...tree,
3889
+ activeLeafId: leafId
3890
+ };
3891
+ }
3892
+ function updateNodeContent(tree, nodeId, content, isStreaming) {
3893
+ const node = tree.nodes[nodeId];
3894
+ if (!node) return tree;
3895
+ return {
3896
+ ...tree,
3897
+ nodes: {
3898
+ ...tree.nodes,
3899
+ [nodeId]: {
3900
+ ...node,
3901
+ content,
3902
+ isStreaming: isStreaming ?? node.isStreaming
3903
+ }
3904
+ }
3905
+ };
3906
+ }
3907
+ function messagesToTree(messages) {
3908
+ let tree = createEmptyTree();
3909
+ for (const msg of messages) {
3910
+ const parentId = tree.activeLeafId;
3911
+ tree = addMessageToTree(tree, {
3912
+ id: msg.id,
3913
+ role: msg.role,
3914
+ content: msg.content,
3915
+ parentId,
3916
+ isStreaming: msg.isStreaming
3917
+ }, parentId);
3918
+ }
3919
+ return tree;
3920
+ }
3921
+ function isBranchPoint(tree, nodeId) {
3922
+ const node = tree.nodes[nodeId];
3923
+ return node ? node.children.length > 1 : false;
3924
+ }
3925
+
3926
+ // src/components/chat/ChatInput.tsx
3927
+ var ChatInput = React46.forwardRef(
3928
+ ({
3929
+ position = "bottom",
3930
+ placeholder = "Send a message...",
3931
+ helperText,
3932
+ onSubmit,
3933
+ disabled = false,
3934
+ animate = true,
3935
+ isStreaming = false,
3936
+ onStop,
3937
+ attachments: controlledAttachments,
3938
+ onAttachmentsChange,
3939
+ showAttachmentButton = true,
3940
+ acceptedFileTypes,
3941
+ className,
3942
+ ...rest
3943
+ }, ref) => {
3944
+ const [value, setValue] = useState13("");
3945
+ const [localAttachments, setLocalAttachments] = useState13([]);
3946
+ const [isDragOver, setIsDragOver] = useState13(false);
3947
+ const textareaRef = useRef8(null);
3948
+ const fileInputRef = useRef8(null);
3949
+ const attachments = controlledAttachments ?? localAttachments;
3950
+ const setAttachments = useCallback13(
3951
+ (newAttachments) => {
3952
+ if (onAttachmentsChange) {
3953
+ if (typeof newAttachments === "function") {
3954
+ onAttachmentsChange(newAttachments(attachments));
3955
+ } else {
3956
+ onAttachmentsChange(newAttachments);
3957
+ }
3958
+ } else {
3959
+ setLocalAttachments(newAttachments);
3960
+ }
3961
+ },
3962
+ [attachments, onAttachmentsChange]
3963
+ );
3964
+ const handleSubmit = useCallback13(() => {
3965
+ const trimmed = value.trim();
3966
+ if (!trimmed || disabled || isStreaming) {
3967
+ return;
3968
+ }
3969
+ onSubmit?.(trimmed, attachments.length > 0 ? attachments : void 0);
3970
+ setValue("");
3971
+ setAttachments([]);
3972
+ if (textareaRef.current) {
3973
+ textareaRef.current.style.height = "auto";
3974
+ }
3975
+ }, [value, disabled, isStreaming, onSubmit, attachments, setAttachments]);
3976
+ const handleKeyDown = useCallback13(
3977
+ (e) => {
3978
+ if (e.key === "Enter" && !e.shiftKey) {
3979
+ e.preventDefault();
3980
+ handleSubmit();
3981
+ }
3982
+ },
3983
+ [handleSubmit]
3984
+ );
3985
+ const handleChange = useCallback13((e) => {
3986
+ setValue(e.target.value);
3987
+ const textarea = e.target;
3988
+ textarea.style.height = "auto";
3989
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 200)}px`;
3990
+ }, []);
3991
+ useEffect10(() => {
3992
+ if (!disabled && !isStreaming && textareaRef.current) {
3993
+ textareaRef.current.focus();
3994
+ }
3995
+ }, [disabled, isStreaming]);
3996
+ const addFiles = useCallback13(
3997
+ (files) => {
3998
+ const newAttachments = Array.from(files).map((file) => ({
3999
+ id: generateId(),
4000
+ file,
4001
+ previewUrl: isImageFile(file) ? createPreviewUrl(file) : void 0,
4002
+ status: "pending"
4003
+ }));
4004
+ setAttachments((prev) => [...prev, ...newAttachments]);
4005
+ },
4006
+ [setAttachments]
4007
+ );
4008
+ const handleFileSelect = useCallback13(
4009
+ (e) => {
4010
+ const files = e.target.files;
4011
+ if (files && files.length > 0) {
4012
+ addFiles(files);
4013
+ }
4014
+ e.target.value = "";
4015
+ },
4016
+ [addFiles]
4017
+ );
4018
+ const handleRemoveAttachment = useCallback13(
4019
+ (id) => {
4020
+ setAttachments((prev) => {
4021
+ const attachment = prev.find((a) => a.id === id);
4022
+ if (attachment?.previewUrl) {
4023
+ URL.revokeObjectURL(attachment.previewUrl);
4024
+ }
4025
+ return prev.filter((a) => a.id !== id);
4026
+ });
4027
+ },
4028
+ [setAttachments]
4029
+ );
4030
+ const handleDragEnter = useCallback13((e) => {
4031
+ e.preventDefault();
4032
+ e.stopPropagation();
4033
+ setIsDragOver(true);
4034
+ }, []);
4035
+ const handleDragLeave = useCallback13((e) => {
4036
+ e.preventDefault();
4037
+ e.stopPropagation();
4038
+ if (!e.currentTarget.contains(e.relatedTarget)) {
4039
+ setIsDragOver(false);
4040
+ }
4041
+ }, []);
4042
+ const handleDragOver = useCallback13((e) => {
4043
+ e.preventDefault();
4044
+ e.stopPropagation();
4045
+ }, []);
4046
+ const handleDrop = useCallback13(
4047
+ (e) => {
4048
+ e.preventDefault();
4049
+ e.stopPropagation();
4050
+ setIsDragOver(false);
4051
+ const files = e.dataTransfer.files;
4052
+ if (files && files.length > 0) {
4053
+ addFiles(files);
4054
+ }
4055
+ },
4056
+ [addFiles]
4057
+ );
4058
+ const isCentered = position === "centered";
4059
+ const hasAttachments = attachments.length > 0;
4060
+ const canSubmit = value.trim() && !disabled && !isStreaming;
4061
+ return /* @__PURE__ */ React46.createElement(
3228
4062
  "div",
3229
4063
  {
3230
4064
  ref,
3231
4065
  className: cx(
3232
- "inline-flex items-center justify-center rounded-none font-bold select-none overflow-hidden",
3233
- sizeMap2[size],
3234
- variantClasses,
4066
+ "w-full",
4067
+ isCentered && "flex flex-col items-center justify-center",
4068
+ animate && "transition-all duration-300 ease-out",
3235
4069
  className
3236
4070
  ),
3237
4071
  ...rest
3238
4072
  },
3239
- children
4073
+ isCentered && helperText && /* @__PURE__ */ React46.createElement("p", { className: "text-silver text-sm mb-4 text-center" }, helperText),
4074
+ /* @__PURE__ */ React46.createElement(
4075
+ "div",
4076
+ {
4077
+ className: cx(
4078
+ "relative w-full bg-charcoal border",
4079
+ isDragOver ? "border-gold ring-1 ring-gold/30" : "border-ash/60",
4080
+ "focus-within:border-gold/60 focus-within:ring-1 focus-within:ring-gold/20",
4081
+ "transition-colors duration-200",
4082
+ isCentered && "max-w-lg"
4083
+ ),
4084
+ onDragEnter: showAttachmentButton ? handleDragEnter : void 0,
4085
+ onDragLeave: showAttachmentButton ? handleDragLeave : void 0,
4086
+ onDragOver: showAttachmentButton ? handleDragOver : void 0,
4087
+ onDrop: showAttachmentButton ? handleDrop : void 0
4088
+ },
4089
+ hasAttachments && /* @__PURE__ */ React46.createElement("div", { className: "px-3 pt-3 pb-1" }, /* @__PURE__ */ React46.createElement(
4090
+ AttachmentPreview,
4091
+ {
4092
+ attachments,
4093
+ onRemove: handleRemoveAttachment,
4094
+ removable: !isStreaming
4095
+ }
4096
+ )),
4097
+ isDragOver && /* @__PURE__ */ React46.createElement(
4098
+ "div",
4099
+ {
4100
+ className: "absolute inset-0 bg-gold/10 flex items-center justify-center z-10 pointer-events-none"
4101
+ },
4102
+ /* @__PURE__ */ React46.createElement("span", { className: "text-gold text-sm font-medium" }, "Drop files here")
4103
+ ),
4104
+ /* @__PURE__ */ React46.createElement("div", { className: "flex items-end" }, showAttachmentButton && /* @__PURE__ */ React46.createElement(React46.Fragment, null, /* @__PURE__ */ React46.createElement(
4105
+ "button",
4106
+ {
4107
+ type: "button",
4108
+ onClick: () => fileInputRef.current?.click(),
4109
+ disabled: disabled || isStreaming,
4110
+ className: cx(
4111
+ "p-3 text-silver/60 hover:text-silver transition-colors",
4112
+ "disabled:opacity-50 disabled:cursor-not-allowed"
4113
+ ),
4114
+ "aria-label": "Attach file"
4115
+ },
4116
+ /* @__PURE__ */ React46.createElement(Paperclip, { className: "w-5 h-5" })
4117
+ ), /* @__PURE__ */ React46.createElement(
4118
+ "input",
4119
+ {
4120
+ ref: fileInputRef,
4121
+ type: "file",
4122
+ multiple: true,
4123
+ accept: acceptedFileTypes,
4124
+ onChange: handleFileSelect,
4125
+ className: "hidden",
4126
+ "aria-hidden": "true"
4127
+ }
4128
+ )), /* @__PURE__ */ React46.createElement(
4129
+ "textarea",
4130
+ {
4131
+ ref: textareaRef,
4132
+ value,
4133
+ onChange: handleChange,
4134
+ onKeyDown: handleKeyDown,
4135
+ placeholder,
4136
+ disabled: disabled || isStreaming,
4137
+ rows: 1,
4138
+ className: cx(
4139
+ "flex-1 bg-transparent text-white placeholder:text-silver/60",
4140
+ "py-3 pr-12 resize-none outline-none min-h-12",
4141
+ !showAttachmentButton && "pl-4",
4142
+ (disabled || isStreaming) && "opacity-50 cursor-not-allowed"
4143
+ ),
4144
+ style: { maxHeight: 200 }
4145
+ }
4146
+ ), isStreaming ? /* @__PURE__ */ React46.createElement(
4147
+ "button",
4148
+ {
4149
+ type: "button",
4150
+ onClick: onStop,
4151
+ className: cx(
4152
+ "absolute right-2 bottom-2 p-2",
4153
+ "text-error hover:bg-error/10 transition-colors duration-200"
4154
+ ),
4155
+ "aria-label": "Stop generation"
4156
+ },
4157
+ /* @__PURE__ */ React46.createElement(Square, { className: "w-5 h-5 fill-current" })
4158
+ ) : /* @__PURE__ */ React46.createElement(
4159
+ "button",
4160
+ {
4161
+ type: "button",
4162
+ onClick: handleSubmit,
4163
+ disabled: !canSubmit,
4164
+ className: cx(
4165
+ "absolute right-2 bottom-2 p-2",
4166
+ "transition-colors duration-200",
4167
+ canSubmit ? "text-gold hover:bg-gold/10" : "text-silver/40 cursor-not-allowed"
4168
+ ),
4169
+ "aria-label": "Send message"
4170
+ },
4171
+ /* @__PURE__ */ React46.createElement(Send, { className: "w-5 h-5" })
4172
+ ))
4173
+ )
3240
4174
  );
3241
4175
  }
3242
4176
  );
3243
- BrandIcon.displayName = "BrandIcon";
4177
+ ChatInput.displayName = "ChatInput";
3244
4178
 
3245
- // src/components/ColorSwatch.tsx
3246
- import React44 from "react";
3247
- var ColorSwatch = React44.forwardRef(
3248
- ({ color, label, className, ...rest }, ref) => {
3249
- return /* @__PURE__ */ React44.createElement(
4179
+ // src/components/chat/ConversationSidebar.tsx
4180
+ import React47 from "react";
4181
+ function HistoryIcon({ className }) {
4182
+ return /* @__PURE__ */ React47.createElement(
4183
+ "svg",
4184
+ {
4185
+ xmlns: "http://www.w3.org/2000/svg",
4186
+ viewBox: "0 0 20 20",
4187
+ fill: "currentColor",
4188
+ className
4189
+ },
4190
+ /* @__PURE__ */ React47.createElement(
4191
+ "path",
4192
+ {
4193
+ fillRule: "evenodd",
4194
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 000-1.5h-3.25V5z",
4195
+ clipRule: "evenodd"
4196
+ }
4197
+ )
4198
+ );
4199
+ }
4200
+ function ChevronLeftIcon2({ className }) {
4201
+ return /* @__PURE__ */ React47.createElement(
4202
+ "svg",
4203
+ {
4204
+ xmlns: "http://www.w3.org/2000/svg",
4205
+ viewBox: "0 0 20 20",
4206
+ fill: "currentColor",
4207
+ className
4208
+ },
4209
+ /* @__PURE__ */ React47.createElement(
4210
+ "path",
4211
+ {
4212
+ fillRule: "evenodd",
4213
+ d: "M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z",
4214
+ clipRule: "evenodd"
4215
+ }
4216
+ )
4217
+ );
4218
+ }
4219
+ var ConversationSidebar = React47.forwardRef(
4220
+ ({
4221
+ conversations,
4222
+ isCollapsed = false,
4223
+ onSelectConversation,
4224
+ onNewChat,
4225
+ onToggleCollapse,
4226
+ className,
4227
+ ...rest
4228
+ }, ref) => {
4229
+ if (isCollapsed) {
4230
+ return /* @__PURE__ */ React47.createElement(
4231
+ "div",
4232
+ {
4233
+ ref,
4234
+ className: cx(
4235
+ "h-full bg-charcoal/80 border-r border-ash/40 flex flex-col items-center py-3",
4236
+ "w-12 flex-shrink-0",
4237
+ className
4238
+ ),
4239
+ ...rest
4240
+ },
4241
+ /* @__PURE__ */ React47.createElement(
4242
+ "button",
4243
+ {
4244
+ onClick: onToggleCollapse,
4245
+ className: cx(
4246
+ "p-2",
4247
+ "text-silver hover:text-white hover:bg-ash/20",
4248
+ "transition-colors duration-150"
4249
+ ),
4250
+ "aria-label": "Expand sidebar"
4251
+ },
4252
+ /* @__PURE__ */ React47.createElement(HistoryIcon, { className: "w-5 h-5" })
4253
+ )
4254
+ );
4255
+ }
4256
+ return /* @__PURE__ */ React47.createElement(
3250
4257
  "div",
3251
4258
  {
3252
4259
  ref,
3253
- className: cx("flex flex-col items-center gap-2", className),
4260
+ className: cx(
4261
+ "h-full bg-charcoal/80 border-r border-ash/40 flex flex-col",
4262
+ "w-64 flex-shrink-0",
4263
+ className
4264
+ ),
3254
4265
  ...rest
3255
4266
  },
3256
- /* @__PURE__ */ React44.createElement(
3257
- "div",
4267
+ /* @__PURE__ */ React47.createElement("div", { className: "p-3 border-b border-ash/40 flex-shrink-0 flex items-center gap-2" }, /* @__PURE__ */ React47.createElement(
4268
+ "button",
3258
4269
  {
3259
- className: "h-16 w-16 border-2 border-ash rounded-none shadow-sm",
3260
- style: { backgroundColor: color },
3261
- "aria-label": label || color
3262
- }
3263
- ),
3264
- label && /* @__PURE__ */ React44.createElement("span", { className: "text-xs text-silver font-medium" }, label)
4270
+ onClick: onToggleCollapse,
4271
+ className: cx(
4272
+ "p-1.5",
4273
+ "text-silver hover:text-white hover:bg-ash/20",
4274
+ "transition-colors duration-150"
4275
+ ),
4276
+ "aria-label": "Collapse sidebar"
4277
+ },
4278
+ /* @__PURE__ */ React47.createElement(ChevronLeftIcon2, { className: "w-5 h-5" })
4279
+ ), /* @__PURE__ */ React47.createElement(
4280
+ "button",
4281
+ {
4282
+ onClick: onNewChat,
4283
+ className: cx(
4284
+ "flex-1 px-3 py-2",
4285
+ "bg-gold/10 hover:bg-gold/20 text-gold",
4286
+ "border border-gold/30",
4287
+ "flex items-center justify-center gap-2",
4288
+ "transition-colors duration-200"
4289
+ )
4290
+ },
4291
+ /* @__PURE__ */ React47.createElement(
4292
+ "svg",
4293
+ {
4294
+ xmlns: "http://www.w3.org/2000/svg",
4295
+ viewBox: "0 0 20 20",
4296
+ fill: "currentColor",
4297
+ className: "w-4 h-4"
4298
+ },
4299
+ /* @__PURE__ */ React47.createElement("path", { d: "M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z" })
4300
+ ),
4301
+ /* @__PURE__ */ React47.createElement("span", { className: "text-sm font-medium" }, "New Chat")
4302
+ )),
4303
+ /* @__PURE__ */ React47.createElement("div", { className: "flex-1 overflow-y-auto py-2" }, conversations.length === 0 ? /* @__PURE__ */ React47.createElement("p", { className: "px-4 py-2 text-sm text-silver/60" }, "No conversations yet") : /* @__PURE__ */ React47.createElement("div", { className: "space-y-1 px-2" }, conversations.map((conversation) => /* @__PURE__ */ React47.createElement(
4304
+ "button",
4305
+ {
4306
+ key: conversation.id,
4307
+ onClick: () => onSelectConversation?.(conversation.id),
4308
+ className: cx(
4309
+ "w-full px-3 py-2 text-left",
4310
+ "transition-colors duration-150",
4311
+ conversation.isActive ? "bg-ash/40 text-white" : "text-silver hover:bg-ash/20 hover:text-white"
4312
+ )
4313
+ },
4314
+ /* @__PURE__ */ React47.createElement("p", { className: "text-sm font-medium truncate" }, conversation.title),
4315
+ conversation.preview && /* @__PURE__ */ React47.createElement("p", { className: "text-xs text-silver/60 truncate mt-0.5" }, conversation.preview),
4316
+ conversation.timestamp && /* @__PURE__ */ React47.createElement("p", { className: "text-xs text-silver/40 mt-1" }, conversation.timestamp)
4317
+ ))))
3265
4318
  );
3266
4319
  }
3267
4320
  );
3268
- ColorSwatch.displayName = "ColorSwatch";
4321
+ ConversationSidebar.displayName = "ConversationSidebar";
4322
+ var CollapsedSidebarToggle = React47.forwardRef(({ onExpand, className, ...rest }, ref) => {
4323
+ return /* @__PURE__ */ React47.createElement(
4324
+ "button",
4325
+ {
4326
+ ref,
4327
+ onClick: onExpand,
4328
+ className: cx(
4329
+ "p-2",
4330
+ "bg-charcoal/80 border border-ash/40",
4331
+ "text-silver hover:text-white hover:bg-ash/20",
4332
+ "transition-colors duration-150",
4333
+ className
4334
+ ),
4335
+ "aria-label": "Expand sidebar",
4336
+ ...rest
4337
+ },
4338
+ /* @__PURE__ */ React47.createElement(HistoryIcon, { className: "w-5 h-5" })
4339
+ );
4340
+ });
4341
+ CollapsedSidebarToggle.displayName = "CollapsedSidebarToggle";
4342
+
4343
+ // src/components/chat/ArtifactsPanel.tsx
4344
+ import React50, { useState as useState14, useEffect as useEffect11 } from "react";
3269
4345
 
3270
4346
  // src/components/ImageCard.tsx
3271
- import React45 from "react";
4347
+ import React48 from "react";
3272
4348
  var ASPECT_RATIO_PRESETS = {
3273
4349
  landscape: "3 / 2",
3274
4350
  portrait: "2 / 3",
@@ -3280,7 +4356,7 @@ function resolveAspectRatio(ratio) {
3280
4356
  }
3281
4357
  return ratio.replace("/", " / ");
3282
4358
  }
3283
- var ImageCard = React45.forwardRef(
4359
+ var ImageCard = React48.forwardRef(
3284
4360
  ({
3285
4361
  src,
3286
4362
  alt,
@@ -3297,7 +4373,7 @@ var ImageCard = React45.forwardRef(
3297
4373
  }, ref) => {
3298
4374
  const hasAspectRatio = aspectRatio !== void 0;
3299
4375
  const isContain = objectFit === "contain";
3300
- return /* @__PURE__ */ React45.createElement(Card, { ref, className: cx("p-0 overflow-hidden group w-fit", className), ...props }, /* @__PURE__ */ React45.createElement(
4376
+ return /* @__PURE__ */ React48.createElement(Card, { ref, className: cx("p-0 overflow-hidden group w-fit", className), ...props }, /* @__PURE__ */ React48.createElement(
3301
4377
  "div",
3302
4378
  {
3303
4379
  className: cx(
@@ -3307,7 +4383,7 @@ var ImageCard = React45.forwardRef(
3307
4383
  ),
3308
4384
  style: hasAspectRatio ? { aspectRatio: resolveAspectRatio(aspectRatio) } : void 0
3309
4385
  },
3310
- /* @__PURE__ */ React45.createElement(
4386
+ /* @__PURE__ */ React48.createElement(
3311
4387
  "img",
3312
4388
  {
3313
4389
  src,
@@ -3320,20 +4396,20 @@ var ImageCard = React45.forwardRef(
3320
4396
  )
3321
4397
  }
3322
4398
  ),
3323
- overlay && /* @__PURE__ */ React45.createElement(
4399
+ overlay && /* @__PURE__ */ React48.createElement(
3324
4400
  "div",
3325
4401
  {
3326
4402
  className: "absolute inset-0 bg-obsidian/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 flex items-center justify-center"
3327
4403
  },
3328
4404
  overlay
3329
4405
  )
3330
- ), (title || subtitle || children) && /* @__PURE__ */ React45.createElement("div", { className: cx("px-4 py-4", contentClassName) }, title && /* @__PURE__ */ React45.createElement("h4", { className: "text-lg font-semibold leading-tight" }, title), subtitle && /* @__PURE__ */ React45.createElement("p", { className: "text-sm text-silver leading-normal" }, subtitle), children));
4406
+ ), (title || subtitle || children) && /* @__PURE__ */ React48.createElement("div", { className: cx("px-4 py-4", contentClassName) }, title && /* @__PURE__ */ React48.createElement("h4", { className: "text-lg font-semibold leading-tight" }, title), subtitle && /* @__PURE__ */ React48.createElement("p", { className: "text-sm text-silver leading-normal" }, subtitle), children));
3331
4407
  }
3332
4408
  );
3333
4409
  ImageCard.displayName = "ImageCard";
3334
4410
 
3335
4411
  // src/components/VideoCard.tsx
3336
- import React46 from "react";
4412
+ import React49 from "react";
3337
4413
  import ReactPlayer2 from "react-player";
3338
4414
  var ASPECT_RATIO_PRESETS2 = {
3339
4415
  video: "16 / 9",
@@ -3346,7 +4422,7 @@ function resolveAspectRatio2(ratio) {
3346
4422
  }
3347
4423
  return ratio.replace("/", " / ");
3348
4424
  }
3349
- var VideoCard = React46.forwardRef(
4425
+ var VideoCard = React49.forwardRef(
3350
4426
  ({
3351
4427
  src,
3352
4428
  title,
@@ -3366,16 +4442,16 @@ var VideoCard = React46.forwardRef(
3366
4442
  ...props
3367
4443
  }, ref) => {
3368
4444
  const hasAspectRatio = aspectRatio !== void 0;
3369
- return /* @__PURE__ */ React46.createElement(Card, { ref, className: cx("p-0 overflow-hidden group w-full", className), ...props }, /* @__PURE__ */ React46.createElement(
4445
+ return /* @__PURE__ */ React49.createElement(Card, { ref, className: cx("p-0 overflow-hidden group w-full", className), ...props }, /* @__PURE__ */ React49.createElement(
3370
4446
  "div",
3371
4447
  {
3372
4448
  className: cx(
3373
- "relative bg-black overflow-hidden",
4449
+ "relative bg-obsidian overflow-hidden",
3374
4450
  mediaClassName
3375
4451
  ),
3376
4452
  style: { aspectRatio: resolveAspectRatio2(aspectRatio) }
3377
4453
  },
3378
- /* @__PURE__ */ React46.createElement(
4454
+ /* @__PURE__ */ React49.createElement(
3379
4455
  ReactPlayer2,
3380
4456
  {
3381
4457
  src,
@@ -3391,7 +4467,7 @@ var VideoCard = React46.forwardRef(
3391
4467
  ...playerProps
3392
4468
  }
3393
4469
  )
3394
- ), (title || subtitle || children) && /* @__PURE__ */ React46.createElement("div", { className: cx("px-4 py-4", contentClassName) }, title && /* @__PURE__ */ React46.createElement("h4", { className: "text-lg font-semibold leading-tight" }, title), subtitle && /* @__PURE__ */ React46.createElement(
4470
+ ), (title || subtitle || children) && /* @__PURE__ */ React49.createElement("div", { className: cx("px-4 py-4", contentClassName) }, title && /* @__PURE__ */ React49.createElement("h4", { className: "text-lg font-semibold leading-tight" }, title), subtitle && /* @__PURE__ */ React49.createElement(
3395
4471
  "p",
3396
4472
  {
3397
4473
  className: "text-sm text-silver leading-normal mt-1"
@@ -3402,16 +4478,778 @@ var VideoCard = React46.forwardRef(
3402
4478
  );
3403
4479
  VideoCard.displayName = "VideoCard";
3404
4480
 
4481
+ // src/components/chat/ArtifactsPanel.tsx
4482
+ function LayersIcon({ className }) {
4483
+ return /* @__PURE__ */ React50.createElement(
4484
+ "svg",
4485
+ {
4486
+ xmlns: "http://www.w3.org/2000/svg",
4487
+ viewBox: "0 0 20 20",
4488
+ fill: "currentColor",
4489
+ className
4490
+ },
4491
+ /* @__PURE__ */ React50.createElement("path", { d: "M3.196 12.87l-.825.483a.75.75 0 000 1.294l7.25 4.25a.75.75 0 00.758 0l7.25-4.25a.75.75 0 000-1.294l-.825-.484-5.666 3.322a2.25 2.25 0 01-2.276 0L3.196 12.87z" }),
4492
+ /* @__PURE__ */ React50.createElement("path", { d: "M3.196 8.87l-.825.483a.75.75 0 000 1.294l7.25 4.25a.75.75 0 00.758 0l7.25-4.25a.75.75 0 000-1.294l-.825-.484-5.666 3.322a2.25 2.25 0 01-2.276 0L3.196 8.87z" }),
4493
+ /* @__PURE__ */ React50.createElement("path", { d: "M10.38 1.103a.75.75 0 00-.76 0l-7.25 4.25a.75.75 0 000 1.294l7.25 4.25a.75.75 0 00.76 0l7.25-4.25a.75.75 0 000-1.294l-7.25-4.25z" })
4494
+ );
4495
+ }
4496
+ function ChevronRightIcon2({ className }) {
4497
+ return /* @__PURE__ */ React50.createElement(
4498
+ "svg",
4499
+ {
4500
+ xmlns: "http://www.w3.org/2000/svg",
4501
+ viewBox: "0 0 20 20",
4502
+ fill: "currentColor",
4503
+ className
4504
+ },
4505
+ /* @__PURE__ */ React50.createElement(
4506
+ "path",
4507
+ {
4508
+ fillRule: "evenodd",
4509
+ d: "M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z",
4510
+ clipRule: "evenodd"
4511
+ }
4512
+ )
4513
+ );
4514
+ }
4515
+ function ArtifactSkeleton({ type }) {
4516
+ if (type === "image") {
4517
+ return /* @__PURE__ */ React50.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ React50.createElement(Skeleton, { className: "w-full h-48" }), /* @__PURE__ */ React50.createElement("div", { className: "p-4 bg-charcoal border border-ash/40 border-t-0" }, /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-5 w-3/4 mb-2" }), /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-4 w-1/2" })));
4518
+ }
4519
+ if (type === "video") {
4520
+ return /* @__PURE__ */ React50.createElement("div", { className: "overflow-hidden" }, /* @__PURE__ */ React50.createElement(Skeleton, { className: "w-full aspect-video" }), /* @__PURE__ */ React50.createElement("div", { className: "p-4 bg-charcoal border border-ash/40 border-t-0" }, /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-5 w-3/4 mb-2" }), /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-4 w-1/2" })));
4521
+ }
4522
+ return /* @__PURE__ */ React50.createElement("div", { className: "p-4 bg-charcoal border border-ash/40 space-y-2" }, /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-5 w-1/2" }), /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-4 w-full" }), /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-4 w-full" }), /* @__PURE__ */ React50.createElement(Skeleton, { className: "h-4 w-3/4" }));
4523
+ }
4524
+ function ArtifactRenderer({ artifact, isLoading }) {
4525
+ const [imageLoaded, setImageLoaded] = useState14(false);
4526
+ const [minDelayPassed, setMinDelayPassed] = useState14(false);
4527
+ useEffect11(() => {
4528
+ setImageLoaded(false);
4529
+ setMinDelayPassed(false);
4530
+ const timer = setTimeout(() => {
4531
+ setMinDelayPassed(true);
4532
+ }, 800);
4533
+ return () => clearTimeout(timer);
4534
+ }, [artifact.src, artifact.id]);
4535
+ if (isLoading || artifact.isPending) {
4536
+ return /* @__PURE__ */ React50.createElement(ArtifactSkeleton, { type: artifact.type });
4537
+ }
4538
+ const showContent = imageLoaded && minDelayPassed;
4539
+ switch (artifact.type) {
4540
+ case "image":
4541
+ return /* @__PURE__ */ React50.createElement("div", { className: "relative" }, !showContent && /* @__PURE__ */ React50.createElement(ArtifactSkeleton, { type: "image" }), /* @__PURE__ */ React50.createElement(
4542
+ ImageCard,
4543
+ {
4544
+ src: artifact.src || "",
4545
+ alt: artifact.alt || "Artifact image",
4546
+ title: artifact.title,
4547
+ subtitle: artifact.subtitle,
4548
+ aspectRatio: "landscape",
4549
+ className: cx(
4550
+ "w-full transition-opacity duration-300",
4551
+ showContent ? "opacity-100" : "opacity-0 absolute inset-0"
4552
+ ),
4553
+ onLoad: () => setImageLoaded(true)
4554
+ }
4555
+ ));
4556
+ case "video":
4557
+ return /* @__PURE__ */ React50.createElement(
4558
+ VideoCard,
4559
+ {
4560
+ src: artifact.src || "",
4561
+ title: artifact.title,
4562
+ subtitle: artifact.subtitle,
4563
+ aspectRatio: "video",
4564
+ controls: true,
4565
+ className: "w-full"
4566
+ }
4567
+ );
4568
+ case "text":
4569
+ return /* @__PURE__ */ React50.createElement("div", { className: "p-4 bg-charcoal border border-ash/40" }, artifact.title && /* @__PURE__ */ React50.createElement("h4", { className: "text-lg font-semibold text-white mb-2" }, artifact.title), /* @__PURE__ */ React50.createElement(
4570
+ MarkdownContent,
4571
+ {
4572
+ content: artifact.content || "",
4573
+ className: "prose-sm prose-invert"
4574
+ }
4575
+ ));
4576
+ default:
4577
+ return null;
4578
+ }
4579
+ }
4580
+ var ArtifactsPanel = React50.forwardRef(
4581
+ ({ artifacts, isOpen = false, onClose, isLoading = false, className, ...rest }, ref) => {
4582
+ if (!isOpen) {
4583
+ return /* @__PURE__ */ React50.createElement(
4584
+ "div",
4585
+ {
4586
+ ref,
4587
+ className: cx(
4588
+ "h-full bg-charcoal/80 border-l border-ash/40 flex flex-col items-center py-3",
4589
+ "w-12 flex-shrink-0",
4590
+ className
4591
+ ),
4592
+ ...rest
4593
+ },
4594
+ /* @__PURE__ */ React50.createElement(
4595
+ "button",
4596
+ {
4597
+ onClick: onClose,
4598
+ className: cx(
4599
+ "p-2",
4600
+ "text-silver hover:text-white hover:bg-ash/20",
4601
+ "transition-colors duration-150",
4602
+ "relative"
4603
+ ),
4604
+ "aria-label": "Expand artifacts panel"
4605
+ },
4606
+ /* @__PURE__ */ React50.createElement(LayersIcon, { className: "w-5 h-5" }),
4607
+ artifacts.length > 0 && /* @__PURE__ */ React50.createElement("span", { className: "absolute -top-1 -right-1 w-4 h-4 bg-gold text-obsidian text-xs font-medium flex items-center justify-center rounded-full" }, artifacts.length)
4608
+ )
4609
+ );
4610
+ }
4611
+ return /* @__PURE__ */ React50.createElement(
4612
+ "div",
4613
+ {
4614
+ ref,
4615
+ className: cx(
4616
+ "h-full bg-charcoal/50 border-l border-ash/40 flex flex-col",
4617
+ "w-96 flex-shrink-0",
4618
+ className
4619
+ ),
4620
+ ...rest
4621
+ },
4622
+ /* @__PURE__ */ React50.createElement("div", { className: "flex items-center justify-between p-4 border-b border-ash/40 flex-shrink-0" }, /* @__PURE__ */ React50.createElement("h3", { className: "text-lg font-semibold text-white" }, "Artifacts"), /* @__PURE__ */ React50.createElement(
4623
+ "button",
4624
+ {
4625
+ onClick: onClose,
4626
+ className: cx(
4627
+ "p-1.5",
4628
+ "text-silver hover:text-white hover:bg-ash/20",
4629
+ "transition-colors duration-150"
4630
+ ),
4631
+ "aria-label": "Collapse artifacts panel"
4632
+ },
4633
+ /* @__PURE__ */ React50.createElement(ChevronRightIcon2, { className: "w-5 h-5" })
4634
+ )),
4635
+ /* @__PURE__ */ React50.createElement("div", { className: "flex-1 overflow-y-auto p-4 space-y-4" }, artifacts.length === 0 && !isLoading ? /* @__PURE__ */ React50.createElement("p", { className: "text-sm text-silver/60 text-center py-8" }, "No artifacts to display") : artifacts.map((artifact) => /* @__PURE__ */ React50.createElement(
4636
+ ArtifactRenderer,
4637
+ {
4638
+ key: artifact.id,
4639
+ artifact,
4640
+ isLoading
4641
+ }
4642
+ )))
4643
+ );
4644
+ }
4645
+ );
4646
+ ArtifactsPanel.displayName = "ArtifactsPanel";
4647
+ var ArtifactsPanelToggle = React50.forwardRef(({ artifactCount = 0, onExpand, className, ...rest }, ref) => {
4648
+ return /* @__PURE__ */ React50.createElement(
4649
+ "button",
4650
+ {
4651
+ ref,
4652
+ onClick: onExpand,
4653
+ className: cx(
4654
+ "p-2",
4655
+ "bg-charcoal/80 border border-ash/40",
4656
+ "text-silver hover:text-white hover:bg-ash/20",
4657
+ "transition-colors duration-150",
4658
+ "flex items-center gap-2",
4659
+ "relative",
4660
+ className
4661
+ ),
4662
+ "aria-label": "Expand artifacts panel",
4663
+ ...rest
4664
+ },
4665
+ /* @__PURE__ */ React50.createElement(LayersIcon, { className: "w-5 h-5" }),
4666
+ artifactCount > 0 && /* @__PURE__ */ React50.createElement("span", { className: "absolute -top-1 -right-1 w-4 h-4 bg-gold text-obsidian text-xs font-medium flex items-center justify-center rounded-full" }, artifactCount)
4667
+ );
4668
+ });
4669
+ ArtifactsPanelToggle.displayName = "ArtifactsPanelToggle";
4670
+
4671
+ // src/components/chat/hooks/useArtifactParser.ts
4672
+ import { useMemo as useMemo2 } from "react";
4673
+ var COMPLETE_ARTIFACT_REGEX = /:::artifact\{([^}]+)\}(?:([^:]*?))?:::/gs;
4674
+ var ARTIFACT_START_REGEX = /:::artifact\{/;
4675
+ function parseAttributes(attrString) {
4676
+ const attrs = {};
4677
+ const regex = /(\w+)="([^"]*)"/g;
4678
+ let match;
4679
+ while ((match = regex.exec(attrString)) !== null) {
4680
+ attrs[match[1]] = match[2];
4681
+ }
4682
+ return attrs;
4683
+ }
4684
+ function generateStableArtifactId(type, identifier) {
4685
+ const str = `${type}:${identifier}`;
4686
+ let hash = 0;
4687
+ for (let i = 0; i < str.length; i++) {
4688
+ const char = str.charCodeAt(i);
4689
+ hash = (hash << 5) - hash + char;
4690
+ hash = hash & hash;
4691
+ }
4692
+ return `artifact-${Math.abs(hash).toString(36)}`;
4693
+ }
4694
+ function useArtifactParser(content) {
4695
+ return useMemo2(() => {
4696
+ if (!content) {
4697
+ return { cleanContent: "", artifacts: [], hasPendingArtifact: false };
4698
+ }
4699
+ const artifacts = [];
4700
+ let workingContent = content;
4701
+ let artifactIndex = 0;
4702
+ workingContent = workingContent.replace(COMPLETE_ARTIFACT_REGEX, (_, attrString, innerContent) => {
4703
+ const attrs = parseAttributes(attrString);
4704
+ const type = attrs.type || "text";
4705
+ const identifier = attrs.src || attrs.content || innerContent || `idx-${artifactIndex++}`;
4706
+ const id = generateStableArtifactId(type, identifier);
4707
+ const artifact = {
4708
+ id,
4709
+ type,
4710
+ title: attrs.title,
4711
+ subtitle: attrs.subtitle
4712
+ };
4713
+ if (type === "text") {
4714
+ artifact.content = innerContent?.trim() || attrs.content;
4715
+ } else if (type === "image") {
4716
+ artifact.src = attrs.src;
4717
+ artifact.alt = attrs.alt || "Image";
4718
+ } else if (type === "video") {
4719
+ artifact.src = attrs.src;
4720
+ }
4721
+ artifacts.push(artifact);
4722
+ return "";
4723
+ });
4724
+ const startMatch = workingContent.match(ARTIFACT_START_REGEX);
4725
+ let hasPendingArtifact = false;
4726
+ if (startMatch && startMatch.index !== void 0) {
4727
+ workingContent = workingContent.substring(0, startMatch.index);
4728
+ hasPendingArtifact = true;
4729
+ artifacts.push({
4730
+ id: "artifact-pending",
4731
+ type: "image",
4732
+ // Default to image for skeleton
4733
+ isPending: true
4734
+ });
4735
+ }
4736
+ return {
4737
+ cleanContent: workingContent.trim(),
4738
+ artifacts,
4739
+ hasPendingArtifact
4740
+ };
4741
+ }, [content]);
4742
+ }
4743
+
4744
+ // src/components/chat/ChatInterface.tsx
4745
+ var ChatInterface = React51.forwardRef(
4746
+ ({
4747
+ messages = [],
4748
+ conversationTree,
4749
+ onTreeChange,
4750
+ conversations = [],
4751
+ onMessageSubmit,
4752
+ onEditMessage,
4753
+ onRetryMessage,
4754
+ onStop,
4755
+ onSelectConversation,
4756
+ onNewChat,
4757
+ isStreaming = false,
4758
+ isThinking = false,
4759
+ placeholder = "Send a message...",
4760
+ emptyStateHelper = "Type anything to start a conversation",
4761
+ initialSidebarCollapsed = false,
4762
+ emptyState,
4763
+ showAttachmentButton = true,
4764
+ enableMessageActions = true,
4765
+ attachments: propsAttachments,
4766
+ onAttachmentsChange,
4767
+ className,
4768
+ ...rest
4769
+ }, ref) => {
4770
+ const [sidebarCollapsed, setSidebarCollapsed] = useState15(initialSidebarCollapsed);
4771
+ const [artifactsPanelOpen, setArtifactsPanelOpen] = useState15(false);
4772
+ const isTreeMode = !!conversationTree;
4773
+ const effectiveMessages = useMemo3(() => {
4774
+ if (isTreeMode && conversationTree) {
4775
+ const pathNodes = getActivePathMessages(conversationTree);
4776
+ return pathNodes.map((node) => ({
4777
+ id: node.id,
4778
+ variant: node.role,
4779
+ content: node.content,
4780
+ isStreaming: node.isStreaming
4781
+ }));
4782
+ }
4783
+ return messages;
4784
+ }, [isTreeMode, conversationTree, messages]);
4785
+ const latestUserMessageIndex = useMemo3(() => {
4786
+ for (let i = effectiveMessages.length - 1; i >= 0; i--) {
4787
+ if (effectiveMessages[i].variant === "user") {
4788
+ return i;
4789
+ }
4790
+ }
4791
+ return -1;
4792
+ }, [effectiveMessages]);
4793
+ const allAssistantContent = useMemo3(() => {
4794
+ return effectiveMessages.filter((msg) => msg.variant === "assistant").map((msg) => msg.content).join("\n\n");
4795
+ }, [effectiveMessages]);
4796
+ const { artifacts, hasPendingArtifact } = useArtifactParser(allAssistantContent);
4797
+ const currentStreamingCleanContent = useMemo3(() => {
4798
+ if (!isStreaming || effectiveMessages.length === 0) {
4799
+ return null;
4800
+ }
4801
+ const lastMessage = effectiveMessages[effectiveMessages.length - 1];
4802
+ if (lastMessage.variant === "assistant") {
4803
+ const content = lastMessage.content;
4804
+ let clean = content.replace(/:::artifact\{[^}]+}(?:[^:]*?)?:::/gs, "");
4805
+ const startMatch = clean.match(/:::artifact\{/);
4806
+ if (startMatch && startMatch.index !== void 0) {
4807
+ clean = clean.substring(0, startMatch.index);
4808
+ }
4809
+ return clean.trim();
4810
+ }
4811
+ return null;
4812
+ }, [effectiveMessages, isStreaming]);
4813
+ React51.useEffect(() => {
4814
+ if ((artifacts.length > 0 || hasPendingArtifact) && !artifactsPanelOpen) {
4815
+ setArtifactsPanelOpen(true);
4816
+ }
4817
+ }, [artifacts.length, hasPendingArtifact, artifactsPanelOpen]);
4818
+ const handleBranchSwitch = useCallback14(
4819
+ (nodeId, direction) => {
4820
+ if (!isTreeMode || !conversationTree || !onTreeChange) {
4821
+ return;
4822
+ }
4823
+ const newTree = switchBranch(conversationTree, nodeId, direction);
4824
+ onTreeChange(newTree);
4825
+ },
4826
+ [isTreeMode, conversationTree, onTreeChange]
4827
+ );
4828
+ const displayMessages = useMemo3(() => {
4829
+ return effectiveMessages.map((msg, idx) => {
4830
+ let cleanContent = msg.content;
4831
+ if (msg.variant === "assistant") {
4832
+ if (isStreaming && idx === effectiveMessages.length - 1 && currentStreamingCleanContent !== null) {
4833
+ cleanContent = currentStreamingCleanContent;
4834
+ } else {
4835
+ let clean = msg.content.replace(/:::artifact\{[^}]+}(?:[^:]*?)?:::/gs, "");
4836
+ const startMatch = clean.match(/:::artifact\{/);
4837
+ if (startMatch && startMatch.index !== void 0) {
4838
+ clean = clean.substring(0, startMatch.index);
4839
+ }
4840
+ cleanContent = clean.trim();
4841
+ }
4842
+ }
4843
+ let branchInfo = void 0;
4844
+ if (isTreeMode && conversationTree) {
4845
+ const siblingInfo = getSiblingInfo(conversationTree, msg.id);
4846
+ if (siblingInfo.total > 1) {
4847
+ branchInfo = {
4848
+ current: siblingInfo.current,
4849
+ total: siblingInfo.total,
4850
+ onPrevious: () => handleBranchSwitch(msg.id, "prev"),
4851
+ onNext: () => handleBranchSwitch(msg.id, "next")
4852
+ };
4853
+ }
4854
+ }
4855
+ const actions = enableMessageActions ? {
4856
+ showCopy: true,
4857
+ onEdit: msg.variant === "user" && onEditMessage ? (newContent) => onEditMessage(msg.id, newContent) : void 0,
4858
+ onRetry: msg.variant === "assistant" && onRetryMessage ? () => onRetryMessage(msg.id) : void 0
4859
+ } : void 0;
4860
+ return {
4861
+ ...msg,
4862
+ content: cleanContent,
4863
+ branchInfo,
4864
+ actions
4865
+ };
4866
+ });
4867
+ }, [
4868
+ effectiveMessages,
4869
+ isStreaming,
4870
+ currentStreamingCleanContent,
4871
+ isTreeMode,
4872
+ conversationTree,
4873
+ enableMessageActions,
4874
+ onEditMessage,
4875
+ onRetryMessage,
4876
+ handleBranchSwitch
4877
+ ]);
4878
+ const allArtifacts = useMemo3(() => {
4879
+ return artifacts;
4880
+ }, [artifacts]);
4881
+ const handleSubmit = useCallback14(
4882
+ (message, attachments) => {
4883
+ onMessageSubmit?.(message, attachments);
4884
+ },
4885
+ [onMessageSubmit]
4886
+ );
4887
+ const toggleSidebar = useCallback14(() => {
4888
+ setSidebarCollapsed((prev) => !prev);
4889
+ }, []);
4890
+ const toggleArtifactsPanel = useCallback14(() => {
4891
+ setArtifactsPanelOpen((prev) => !prev);
4892
+ }, []);
4893
+ const isEmpty = effectiveMessages.length === 0;
4894
+ return /* @__PURE__ */ React51.createElement(
4895
+ "div",
4896
+ {
4897
+ ref,
4898
+ className: cx("flex h-full w-full bg-obsidian overflow-hidden", className),
4899
+ ...rest
4900
+ },
4901
+ /* @__PURE__ */ React51.createElement(
4902
+ ConversationSidebar,
4903
+ {
4904
+ conversations,
4905
+ isCollapsed: sidebarCollapsed,
4906
+ onSelectConversation,
4907
+ onNewChat,
4908
+ onToggleCollapse: toggleSidebar
4909
+ }
4910
+ ),
4911
+ /* @__PURE__ */ React51.createElement("div", { className: "flex-1 flex flex-col min-w-0 relative" }, /* @__PURE__ */ React51.createElement("div", { className: cx(
4912
+ "flex-1 flex flex-col min-h-0 relative transition-all duration-500",
4913
+ isEmpty ? "justify-center" : "justify-start"
4914
+ ) }, /* @__PURE__ */ React51.createElement("div", { className: cx(
4915
+ "transition-all duration-500 ease-in-out",
4916
+ isEmpty ? "flex-1" : "flex-zero"
4917
+ ) }), /* @__PURE__ */ React51.createElement("div", { className: cx(
4918
+ "transition-all duration-500 ease-in-out overflow-hidden flex flex-col",
4919
+ isEmpty ? "flex-zero opacity-0" : "flex-1 opacity-100"
4920
+ ) }, /* @__PURE__ */ React51.createElement(
4921
+ ChatView,
4922
+ {
4923
+ messages: displayMessages,
4924
+ latestUserMessageIndex,
4925
+ isStreaming,
4926
+ isThinking,
4927
+ className: "flex-1"
4928
+ }
4929
+ )), /* @__PURE__ */ React51.createElement("div", { className: cx(
4930
+ "transition-all duration-500 ease-in-out z-10 w-full",
4931
+ isEmpty ? "p-4" : "shrink-0 p-4 border-t border-ash/40 bg-obsidian"
4932
+ ) }, isEmpty && emptyState ? /* @__PURE__ */ React51.createElement("div", { className: "flex justify-center" }, emptyState) : /* @__PURE__ */ React51.createElement(
4933
+ ChatInput,
4934
+ {
4935
+ position: isEmpty ? "centered" : "bottom",
4936
+ placeholder,
4937
+ helperText: isEmpty ? emptyStateHelper : void 0,
4938
+ onSubmit: handleSubmit,
4939
+ disabled: isEmpty ? isStreaming : isStreaming && !onStop,
4940
+ isStreaming,
4941
+ onStop,
4942
+ showAttachmentButton,
4943
+ attachments: propsAttachments,
4944
+ onAttachmentsChange
4945
+ }
4946
+ )), /* @__PURE__ */ React51.createElement("div", { className: cx(
4947
+ "transition-all duration-500 ease-in-out",
4948
+ isEmpty ? "flex-1" : "flex-zero"
4949
+ ) }))),
4950
+ /* @__PURE__ */ React51.createElement(
4951
+ ArtifactsPanel,
4952
+ {
4953
+ artifacts: allArtifacts,
4954
+ isOpen: artifactsPanelOpen,
4955
+ onClose: toggleArtifactsPanel,
4956
+ isLoading: isStreaming && hasPendingArtifact
4957
+ }
4958
+ )
4959
+ );
4960
+ }
4961
+ );
4962
+ ChatInterface.displayName = "ChatInterface";
4963
+
4964
+ // src/components/chat/MessageActions.tsx
4965
+ import React52, { useState as useState16, useCallback as useCallback15 } from "react";
4966
+ import {
4967
+ Copy,
4968
+ Check as Check3,
4969
+ Pencil,
4970
+ RotateCcw,
4971
+ X as X5,
4972
+ Send as Send2
4973
+ } from "lucide-react";
4974
+ var ActionButton2 = ({ onClick, label, children, className, disabled }) => /* @__PURE__ */ React52.createElement(
4975
+ "button",
4976
+ {
4977
+ type: "button",
4978
+ onClick,
4979
+ disabled,
4980
+ className: cx(
4981
+ "p-1.5 text-silver/60 hover:text-silver transition-colors duration-150",
4982
+ "hover:bg-white/5 ",
4983
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent",
4984
+ className
4985
+ ),
4986
+ "aria-label": label
4987
+ },
4988
+ children
4989
+ );
4990
+ var MessageActions = React52.forwardRef(
4991
+ ({
4992
+ variant,
4993
+ content,
4994
+ onEdit,
4995
+ onRetry,
4996
+ isEditing: controlledIsEditing,
4997
+ onEditingChange,
4998
+ editValue: controlledEditValue,
4999
+ className,
5000
+ ...rest
5001
+ }, ref) => {
5002
+ const [localIsEditing, setLocalIsEditing] = useState16(false);
5003
+ const [localEditValue, setLocalEditValue] = useState16(content);
5004
+ const [copied, setCopied] = useState16(false);
5005
+ const isEditing = controlledIsEditing ?? localIsEditing;
5006
+ const editValue = controlledEditValue ?? localEditValue;
5007
+ const setIsEditing = useCallback15(
5008
+ (value) => {
5009
+ if (onEditingChange) {
5010
+ onEditingChange(value);
5011
+ } else {
5012
+ setLocalIsEditing(value);
5013
+ }
5014
+ },
5015
+ [onEditingChange]
5016
+ );
5017
+ const setEditValue = useCallback15((value) => {
5018
+ setLocalEditValue(value);
5019
+ }, []);
5020
+ const handleCopy = useCallback15(async () => {
5021
+ try {
5022
+ await navigator.clipboard.writeText(content);
5023
+ setCopied(true);
5024
+ setTimeout(() => setCopied(false), 2e3);
5025
+ } catch {
5026
+ const textArea = document.createElement("textarea");
5027
+ textArea.value = content;
5028
+ document.body.appendChild(textArea);
5029
+ textArea.select();
5030
+ document.execCommand("copy");
5031
+ document.body.removeChild(textArea);
5032
+ setCopied(true);
5033
+ setTimeout(() => setCopied(false), 2e3);
5034
+ }
5035
+ }, [content]);
5036
+ const handleStartEdit = useCallback15(() => {
5037
+ setLocalEditValue(content);
5038
+ setIsEditing(true);
5039
+ }, [content, setIsEditing]);
5040
+ const handleCancelEdit = useCallback15(() => {
5041
+ setIsEditing(false);
5042
+ setLocalEditValue(content);
5043
+ }, [content, setIsEditing]);
5044
+ const handleSubmitEdit = useCallback15(() => {
5045
+ const trimmed = editValue.trim();
5046
+ if (trimmed && trimmed !== content) {
5047
+ onEdit?.(trimmed);
5048
+ }
5049
+ setIsEditing(false);
5050
+ }, [editValue, content, onEdit, setIsEditing]);
5051
+ const handleEditKeyDown = useCallback15(
5052
+ (e) => {
5053
+ if (e.key === "Enter" && !e.shiftKey) {
5054
+ e.preventDefault();
5055
+ handleSubmitEdit();
5056
+ } else if (e.key === "Escape") {
5057
+ handleCancelEdit();
5058
+ }
5059
+ },
5060
+ [handleSubmitEdit, handleCancelEdit]
5061
+ );
5062
+ const isUser = variant === "user";
5063
+ if (isUser && isEditing) {
5064
+ return /* @__PURE__ */ React52.createElement(
5065
+ "div",
5066
+ {
5067
+ ref,
5068
+ className: cx("mt-2", className),
5069
+ ...rest
5070
+ },
5071
+ /* @__PURE__ */ React52.createElement("div", { className: "relative bg-charcoal border border-ash/60 focus-within:border-gold/60 focus-within:ring-1 focus-within:ring-gold/20" }, /* @__PURE__ */ React52.createElement(
5072
+ "textarea",
5073
+ {
5074
+ value: editValue,
5075
+ onChange: (e) => setEditValue(e.target.value),
5076
+ onKeyDown: handleEditKeyDown,
5077
+ className: "w-full bg-transparent text-white px-3 py-2 pr-20 resize-none outline-none min-h-16 text-sm",
5078
+ autoFocus: true,
5079
+ rows: 2
5080
+ }
5081
+ ), /* @__PURE__ */ React52.createElement("div", { className: "absolute right-2 bottom-2 flex gap-1" }, /* @__PURE__ */ React52.createElement(
5082
+ ActionButton2,
5083
+ {
5084
+ onClick: handleCancelEdit,
5085
+ label: "Cancel edit",
5086
+ className: "text-silver/60 hover:text-error"
5087
+ },
5088
+ /* @__PURE__ */ React52.createElement(X5, { className: "w-4 h-4" })
5089
+ ), /* @__PURE__ */ React52.createElement(
5090
+ ActionButton2,
5091
+ {
5092
+ onClick: handleSubmitEdit,
5093
+ label: "Submit edit",
5094
+ className: "text-silver/60 hover:text-gold",
5095
+ disabled: !editValue.trim() || editValue.trim() === content
5096
+ },
5097
+ /* @__PURE__ */ React52.createElement(Send2, { className: "w-4 h-4" })
5098
+ ))),
5099
+ /* @__PURE__ */ React52.createElement("p", { className: "text-xs text-silver/50 mt-1" }, "Press Enter to submit, Esc to cancel. This will create a new branch.")
5100
+ );
5101
+ }
5102
+ return /* @__PURE__ */ React52.createElement(
5103
+ "div",
5104
+ {
5105
+ ref,
5106
+ className: cx(
5107
+ "flex items-center gap-0.5 mt-1",
5108
+ isUser ? "justify-end" : "justify-start",
5109
+ className
5110
+ ),
5111
+ ...rest
5112
+ },
5113
+ /* @__PURE__ */ React52.createElement(ActionButton2, { onClick: handleCopy, label: copied ? "Copied!" : "Copy message" }, copied ? /* @__PURE__ */ React52.createElement(Check3, { className: "w-3.5 h-3.5 text-success" }) : /* @__PURE__ */ React52.createElement(Copy, { className: "w-3.5 h-3.5" })),
5114
+ isUser && onEdit && /* @__PURE__ */ React52.createElement(ActionButton2, { onClick: handleStartEdit, label: "Edit message" }, /* @__PURE__ */ React52.createElement(Pencil, { className: "w-3.5 h-3.5" })),
5115
+ !isUser && onRetry && /* @__PURE__ */ React52.createElement(ActionButton2, { onClick: onRetry, label: "Regenerate response" }, /* @__PURE__ */ React52.createElement(RotateCcw, { className: "w-3.5 h-3.5" }))
5116
+ );
5117
+ }
5118
+ );
5119
+ MessageActions.displayName = "MessageActions";
5120
+
5121
+ // src/components/chat/BranchNavigator.tsx
5122
+ import React53 from "react";
5123
+ import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight3, GitBranch } from "lucide-react";
5124
+ var BranchNavigator = React53.forwardRef(
5125
+ ({
5126
+ current,
5127
+ total,
5128
+ onPrevious,
5129
+ onNext,
5130
+ size = "sm",
5131
+ showIcon = true,
5132
+ className,
5133
+ ...rest
5134
+ }, ref) => {
5135
+ if (total <= 1) return null;
5136
+ const isFirst = current <= 1;
5137
+ const isLast = current >= total;
5138
+ const buttonSize = size === "sm" ? "p-0.5" : "p-1";
5139
+ const iconSize = size === "sm" ? "w-3 h-3" : "w-4 h-4";
5140
+ const textSize = size === "sm" ? "text-xs" : "text-sm";
5141
+ return /* @__PURE__ */ React53.createElement(
5142
+ "div",
5143
+ {
5144
+ ref,
5145
+ className: cx(
5146
+ "inline-flex items-center gap-0.5 text-silver/70",
5147
+ className
5148
+ ),
5149
+ role: "navigation",
5150
+ "aria-label": "Branch navigation",
5151
+ ...rest
5152
+ },
5153
+ showIcon && /* @__PURE__ */ React53.createElement(GitBranch, { className: cx(iconSize, "mr-0.5 text-silver/50"), "aria-hidden": "true" }),
5154
+ /* @__PURE__ */ React53.createElement(
5155
+ "button",
5156
+ {
5157
+ type: "button",
5158
+ onClick: onPrevious,
5159
+ disabled: isFirst,
5160
+ className: cx(
5161
+ buttonSize,
5162
+ "hover:text-white hover:bg-white/10 transition-colors",
5163
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
5164
+ ),
5165
+ "aria-label": "Previous branch"
5166
+ },
5167
+ /* @__PURE__ */ React53.createElement(ChevronLeft2, { className: iconSize })
5168
+ ),
5169
+ /* @__PURE__ */ React53.createElement("span", { className: cx(textSize, "tabular-nums min-w-6 text-center") }, current, "/", total),
5170
+ /* @__PURE__ */ React53.createElement(
5171
+ "button",
5172
+ {
5173
+ type: "button",
5174
+ onClick: onNext,
5175
+ disabled: isLast,
5176
+ className: cx(
5177
+ buttonSize,
5178
+ "hover:text-white hover:bg-white/10 transition-colors",
5179
+ "disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent disabled:hover:text-silver/70"
5180
+ ),
5181
+ "aria-label": "Next branch"
5182
+ },
5183
+ /* @__PURE__ */ React53.createElement(ChevronRight3, { className: iconSize })
5184
+ )
5185
+ );
5186
+ }
5187
+ );
5188
+ BranchNavigator.displayName = "BranchNavigator";
5189
+
5190
+ // src/components/BrandIcon.tsx
5191
+ import React54 from "react";
5192
+ var sizeMap2 = {
5193
+ sm: "h-8 w-8 text-sm",
5194
+ md: "h-12 w-12 text-base",
5195
+ lg: "h-16 w-16 text-lg"
5196
+ };
5197
+ var BrandIcon = React54.forwardRef(
5198
+ ({ size = "md", variant = "solid", children, className, ...rest }, ref) => {
5199
+ const variantClasses = variant === "solid" ? "bg-gold text-obsidian border-2 border-gold" : "bg-transparent text-gold border-2 border-gold";
5200
+ return /* @__PURE__ */ React54.createElement(
5201
+ "div",
5202
+ {
5203
+ ref,
5204
+ className: cx(
5205
+ "inline-flex items-center justify-center rounded-none font-bold select-none overflow-hidden",
5206
+ sizeMap2[size],
5207
+ variantClasses,
5208
+ className
5209
+ ),
5210
+ ...rest
5211
+ },
5212
+ children
5213
+ );
5214
+ }
5215
+ );
5216
+ BrandIcon.displayName = "BrandIcon";
5217
+
5218
+ // src/components/ColorSwatch.tsx
5219
+ import React55 from "react";
5220
+ var ColorSwatch = React55.forwardRef(
5221
+ ({ color, label, className, ...rest }, ref) => {
5222
+ return /* @__PURE__ */ React55.createElement(
5223
+ "div",
5224
+ {
5225
+ ref,
5226
+ className: cx("flex flex-col items-center gap-2", className),
5227
+ ...rest
5228
+ },
5229
+ /* @__PURE__ */ React55.createElement(
5230
+ "div",
5231
+ {
5232
+ className: "h-16 w-16 border-2 border-ash rounded-none shadow-sm",
5233
+ style: { backgroundColor: color },
5234
+ "aria-label": label || color
5235
+ }
5236
+ ),
5237
+ label && /* @__PURE__ */ React55.createElement("span", { className: "text-xs text-silver font-medium" }, label)
5238
+ );
5239
+ }
5240
+ );
5241
+ ColorSwatch.displayName = "ColorSwatch";
5242
+
3405
5243
  // src/components/SectionHeading.tsx
3406
- import React47 from "react";
5244
+ import React56 from "react";
3407
5245
  var levelStyles = {
3408
5246
  h2: "text-2xl mb-4",
3409
5247
  h3: "text-xl mb-3"
3410
5248
  };
3411
- var SectionHeading = React47.forwardRef(
5249
+ var SectionHeading = React56.forwardRef(
3412
5250
  ({ level = "h2", children, className, ...rest }, ref) => {
3413
5251
  const Component = level;
3414
- return /* @__PURE__ */ React47.createElement(
5252
+ return /* @__PURE__ */ React56.createElement(
3415
5253
  Component,
3416
5254
  {
3417
5255
  ref,
@@ -3437,22 +5275,31 @@ export {
3437
5275
  AccordionTrigger,
3438
5276
  Alert,
3439
5277
  AlertDialog,
5278
+ ArtifactsPanel,
5279
+ ArtifactsPanelToggle,
5280
+ AttachmentPreview,
3440
5281
  Avatar,
3441
5282
  Badge,
5283
+ BranchNavigator,
3442
5284
  BrandIcon,
3443
5285
  Breadcrumb,
3444
5286
  BreadcrumbItem,
3445
5287
  BreadcrumbLink,
3446
5288
  Button,
3447
5289
  Card,
3448
- ChatHistory,
5290
+ ChatInput,
5291
+ ChatInterface,
5292
+ ChatView,
3449
5293
  Checkbox,
3450
5294
  Col,
5295
+ CollapsedSidebarToggle,
3451
5296
  ColorSwatch,
3452
5297
  ConfirmDialog,
3453
5298
  Container,
5299
+ ConversationSidebar,
3454
5300
  Divider,
3455
5301
  Drawer,
5302
+ FileChip,
3456
5303
  HelperText,
3457
5304
  ImageCard,
3458
5305
  Input,
@@ -3475,6 +5322,7 @@ export {
3475
5322
  MenuSeparator,
3476
5323
  MenuTrigger,
3477
5324
  Message,
5325
+ MessageActions,
3478
5326
  Modal,
3479
5327
  Navbar,
3480
5328
  NavbarBrand,
@@ -3510,9 +5358,24 @@ export {
3510
5358
  TableRow,
3511
5359
  Tabs,
3512
5360
  Textarea,
5361
+ ThinkingIndicator,
3513
5362
  ToastProvider,
3514
5363
  Tooltip,
3515
5364
  VideoCard,
5365
+ addMessageToTree,
5366
+ createEmptyTree,
5367
+ createPreviewUrl,
5368
+ generateId,
5369
+ getActivePathMessages,
5370
+ getSiblingInfo,
5371
+ isBranchPoint,
5372
+ isImageFile,
5373
+ messagesToTree,
5374
+ revokePreviewUrl,
5375
+ switchBranch,
5376
+ updateNodeContent,
5377
+ useArtifactParser,
5378
+ useScrollAnchor,
3516
5379
  useToast,
3517
5380
  version
3518
5381
  };