@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.d.mts +888 -192
- package/dist/index.d.ts +888 -192
- package/dist/index.js +2236 -355
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2147 -284
- package/dist/index.mjs.map +1 -1
- package/dist/styles/theme.css +20 -2
- package/llms.md +29 -6
- package/package.json +5 -3
- package/scripts/eslint.mjs +10 -1
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
|
|
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/
|
|
1073
|
+
// src/components/FileChip.tsx
|
|
1074
1074
|
import React14 from "react";
|
|
1075
|
-
|
|
1076
|
-
|
|
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__ */
|
|
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
|
|
1093
|
-
var HelperText =
|
|
1233
|
+
import React17 from "react";
|
|
1234
|
+
var HelperText = React17.forwardRef(
|
|
1094
1235
|
({ className, error, children, ...rest }, ref) => {
|
|
1095
|
-
return /* @__PURE__ */
|
|
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
|
|
1110
|
-
var Textarea =
|
|
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__ */
|
|
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
|
|
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 =
|
|
1271
|
+
var Select = React19.forwardRef(
|
|
1131
1272
|
({ error = false, className, disabled, options, children, ...rest }, ref) => {
|
|
1132
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1274
|
-
var Switch =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1500
|
-
var InputGroup =
|
|
1640
|
+
import React24 from "react";
|
|
1641
|
+
var InputGroup = React24.forwardRef(
|
|
1501
1642
|
({ className, children, ...props }, ref) => {
|
|
1502
|
-
return /* @__PURE__ */
|
|
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 =
|
|
1655
|
+
var InputLeftAddon = React24.forwardRef(
|
|
1515
1656
|
({ className, children, ...props }, ref) => {
|
|
1516
|
-
return /* @__PURE__ */
|
|
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 =
|
|
1673
|
+
var InputRightAddon = React24.forwardRef(
|
|
1533
1674
|
({ className, children, ...props }, ref) => {
|
|
1534
|
-
return /* @__PURE__ */
|
|
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 =
|
|
1691
|
+
var InputLeftElement = React24.forwardRef(
|
|
1551
1692
|
({ className, children, ...props }, ref) => {
|
|
1552
|
-
return /* @__PURE__ */
|
|
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 =
|
|
1709
|
+
var InputRightElement = React24.forwardRef(
|
|
1569
1710
|
({ className, children, ...props }, ref) => {
|
|
1570
|
-
return /* @__PURE__ */
|
|
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 =
|
|
1726
|
+
var InputWrapper = React24.forwardRef(
|
|
1586
1727
|
({ className, children, ...props }, ref) => {
|
|
1587
|
-
return /* @__PURE__ */
|
|
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
|
|
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 =
|
|
1756
|
+
var Alert = React25.forwardRef(
|
|
1616
1757
|
({ variant = "info", title, children, className, ...rest }, ref) => {
|
|
1617
1758
|
const Icon = icons[variant];
|
|
1618
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
1631
|
-
/* @__PURE__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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
|
|
1661
|
-
var Skeleton =
|
|
1801
|
+
import React27 from "react";
|
|
1802
|
+
var Skeleton = React27.forwardRef(
|
|
1662
1803
|
({ className, ...rest }, ref) => {
|
|
1663
|
-
return /* @__PURE__ */
|
|
1804
|
+
return /* @__PURE__ */ React27.createElement(
|
|
1664
1805
|
"div",
|
|
1665
1806
|
{
|
|
1666
1807
|
ref,
|
|
1667
|
-
className: cx("animate-pulse bg-ash
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1818
|
-
error: /* @__PURE__ */
|
|
1819
|
-
warning: /* @__PURE__ */
|
|
1820
|
-
info: /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
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
|
|
2004
|
+
import React30, { useEffect as useEffect2, useState as useState4 } from "react";
|
|
1864
2005
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1865
|
-
import { X as
|
|
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__ */
|
|
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__ */
|
|
1907
|
-
/* @__PURE__ */
|
|
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
|
|
2055
|
+
import React31, { useEffect as useEffect3, useState as useState5 } from "react";
|
|
1915
2056
|
import { createPortal as createPortal3 } from "react-dom";
|
|
1916
|
-
import { X as
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2040
|
-
/* @__PURE__ */
|
|
2180
|
+
/* @__PURE__ */ React31.createElement(X4, { className: "h-5 w-5" }),
|
|
2181
|
+
/* @__PURE__ */ React31.createElement("span", { className: "sr-only" }, "Close")
|
|
2041
2182
|
)),
|
|
2042
|
-
/* @__PURE__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
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] =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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 =
|
|
2416
|
+
var TabList = React34.forwardRef(
|
|
2276
2417
|
({ children, className, ...props }, ref) => {
|
|
2277
|
-
return /* @__PURE__ */
|
|
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 =
|
|
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__ */
|
|
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 =
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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 =
|
|
2551
|
+
var AccordionItem = React35.forwardRef(
|
|
2411
2552
|
({ value, disabled = false, children, className, ...props }, ref) => {
|
|
2412
|
-
return /* @__PURE__ */
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
2457
|
-
/* @__PURE__ */
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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__ */
|
|
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__ */
|
|
2684
|
+
/* @__PURE__ */ React36.createElement("div", { className: "relative inline-block" }, children)
|
|
2544
2685
|
);
|
|
2545
2686
|
};
|
|
2546
2687
|
Menu.displayName = "Menu";
|
|
2547
|
-
var MenuTrigger =
|
|
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__ */
|
|
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 =
|
|
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__ */
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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 =
|
|
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 =
|
|
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
|
|
2691
|
-
var Navbar =
|
|
2831
|
+
import React37 from "react";
|
|
2832
|
+
var Navbar = React37.forwardRef(
|
|
2692
2833
|
({ fixed = false, bordered = true, className, children, ...props }, ref) => {
|
|
2693
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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 =
|
|
2851
|
+
var NavbarBrand = React37.forwardRef(
|
|
2711
2852
|
({ className, children, ...props }, ref) => {
|
|
2712
|
-
return /* @__PURE__ */
|
|
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 =
|
|
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__ */
|
|
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 =
|
|
2888
|
+
var NavbarItem = React37.forwardRef(
|
|
2748
2889
|
({ active = false, className, children, ...props }, ref) => {
|
|
2749
|
-
return /* @__PURE__ */
|
|
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 =
|
|
2905
|
+
var NavbarLink = React37.forwardRef(
|
|
2765
2906
|
({ active = false, className, children, ...props }, ref) => {
|
|
2766
|
-
return /* @__PURE__ */
|
|
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 =
|
|
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
|
|
2934
|
+
import React38 from "react";
|
|
2794
2935
|
import { ChevronRight } from "lucide-react";
|
|
2795
|
-
var Breadcrumb =
|
|
2936
|
+
var Breadcrumb = React38.forwardRef(
|
|
2796
2937
|
({ separator, className, children, ...props }, ref) => {
|
|
2797
|
-
const items =
|
|
2798
|
-
const defaultSeparator = /* @__PURE__ */
|
|
2799
|
-
return /* @__PURE__ */
|
|
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 =
|
|
2944
|
+
var BreadcrumbItem = React38.forwardRef(
|
|
2804
2945
|
({ current = false, className, children, ...props }, ref) => {
|
|
2805
|
-
return /* @__PURE__ */
|
|
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 =
|
|
2963
|
+
var BreadcrumbLink = React38.forwardRef(
|
|
2823
2964
|
({ className, children, ...props }, ref) => {
|
|
2824
|
-
return /* @__PURE__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
3046
|
+
/* @__PURE__ */ React39.createElement(ChevronLeft, { className: "h-4 w-4" })
|
|
2906
3047
|
),
|
|
2907
3048
|
pages.map(
|
|
2908
|
-
(pageNum, index) => pageNum === "ellipsis" ? /* @__PURE__ */
|
|
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__ */
|
|
2915
|
-
) : /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
3093
|
+
import React40 from "react";
|
|
2953
3094
|
import { Check as Check2 } from "lucide-react";
|
|
2954
|
-
var Stepper =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
2988
|
-
), /* @__PURE__ */
|
|
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__ */
|
|
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
|
|
3157
|
+
import React42, { useState as useState10, useEffect as useEffect6, useRef as useRef5 } from "react";
|
|
3017
3158
|
|
|
3018
3159
|
// src/components/MarkdownContent.tsx
|
|
3019
|
-
import
|
|
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
|
|
3099
|
-
|
|
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
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
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
|
|
3123
|
-
var StreamingCursor =
|
|
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__ */
|
|
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/
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
};
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
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
|
-
|
|
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__ */
|
|
3167
|
-
|
|
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
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
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
|
-
|
|
3678
|
+
ThinkingIndicator.displayName = "ThinkingIndicator";
|
|
3178
3679
|
|
|
3179
|
-
// src/components/
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
3218
|
-
import
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
return
|
|
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
|
-
"
|
|
3233
|
-
|
|
3234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4177
|
+
ChatInput.displayName = "ChatInput";
|
|
3244
4178
|
|
|
3245
|
-
// src/components/
|
|
3246
|
-
import
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
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(
|
|
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__ */
|
|
3257
|
-
"
|
|
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
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
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__ */
|
|
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-
|
|
4449
|
+
"relative bg-obsidian overflow-hidden",
|
|
3374
4450
|
mediaClassName
|
|
3375
4451
|
),
|
|
3376
4452
|
style: { aspectRatio: resolveAspectRatio2(aspectRatio) }
|
|
3377
4453
|
},
|
|
3378
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
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 =
|
|
5249
|
+
var SectionHeading = React56.forwardRef(
|
|
3412
5250
|
({ level = "h2", children, className, ...rest }, ref) => {
|
|
3413
5251
|
const Component = level;
|
|
3414
|
-
return /* @__PURE__ */
|
|
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
|
-
|
|
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
|
};
|