@arbidocs/react 0.3.100 → 0.3.101

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.cjs CHANGED
@@ -1,14 +1,47 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var React = require('react');
4
4
  var browser = require('@arbidocs/sdk/browser');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var reactQuery = require('@tanstack/react-query');
7
+ var reactDom = require('react-dom');
8
+ var clsx = require('clsx');
9
+ var tailwindMerge = require('tailwind-merge');
10
+ var AvatarPrimitive = require('@radix-ui/react-avatar');
11
+ var classVarianceAuthority = require('class-variance-authority');
12
+ var reactSlot = require('@radix-ui/react-slot');
13
+ var HoverCardPrimitive = require('@radix-ui/react-hover-card');
14
+ var lucideReact = require('lucide-react');
15
+ var agGridReact = require('ag-grid-react');
16
+ var agGridCommunity = require('ag-grid-community');
17
+ var zustand = require('zustand');
18
+
19
+ function _interopNamespace(e) {
20
+ if (e && e.__esModule) return e;
21
+ var n = Object.create(null);
22
+ if (e) {
23
+ Object.keys(e).forEach(function (k) {
24
+ if (k !== 'default') {
25
+ var d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: function () { return e[k]; }
29
+ });
30
+ }
31
+ });
32
+ }
33
+ n.default = e;
34
+ return Object.freeze(n);
35
+ }
36
+
37
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
38
+ var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
39
+ var HoverCardPrimitive__namespace = /*#__PURE__*/_interopNamespace(HoverCardPrimitive);
7
40
 
8
41
  // src/ArbiProvider.tsx
9
- var ArbiContext = react.createContext(null);
42
+ var ArbiContext = React.createContext(null);
10
43
  function ArbiProvider({ children, ...options }) {
11
- const arbi = react.useMemo(
44
+ const arbi = React.useMemo(
12
45
  () => new browser.Arbi(options),
13
46
  // Stable on url + deploymentDomain — re-creating the instance on every render would be wrong
14
47
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -340,7 +373,7 @@ function agentStatusStyle(theme) {
340
373
  };
341
374
  }
342
375
  function useArbi() {
343
- const arbi = react.useContext(ArbiContext);
376
+ const arbi = React.useContext(ArbiContext);
344
377
  if (!arbi) {
345
378
  throw new Error("useArbi() must be used within an <ArbiProvider>");
346
379
  }
@@ -348,16 +381,16 @@ function useArbi() {
348
381
  }
349
382
  function AuthScreen({ theme, labels, onLogin }) {
350
383
  const arbi = useArbi();
351
- const [mode, setMode] = react.useState("login");
352
- const [step, setStep] = react.useState("email");
353
- const [email, setEmail] = react.useState("");
354
- const [password, setPassword] = react.useState("");
355
- const [confirmPw, setConfirmPw] = react.useState("");
356
- const [code, setCode] = react.useState("");
357
- const [firstName, setFirstName] = react.useState("");
358
- const [lastName, setLastName] = react.useState("");
359
- const [loading, setLoading] = react.useState(false);
360
- const [error, setError] = react.useState("");
384
+ const [mode, setMode] = React.useState("login");
385
+ const [step, setStep] = React.useState("email");
386
+ const [email, setEmail] = React.useState("");
387
+ const [password, setPassword] = React.useState("");
388
+ const [confirmPw, setConfirmPw] = React.useState("");
389
+ const [code, setCode] = React.useState("");
390
+ const [firstName, setFirstName] = React.useState("");
391
+ const [lastName, setLastName] = React.useState("");
392
+ const [loading, setLoading] = React.useState(false);
393
+ const [error, setError] = React.useState("");
361
394
  const resetForm = () => {
362
395
  setPassword("");
363
396
  setConfirmPw("");
@@ -664,11 +697,11 @@ function useHealth(options) {
664
697
  function WorkspaceScreen({ theme, labels, onSelect }) {
665
698
  const arbi = useArbi();
666
699
  const { data: workspaces, isLoading } = useWorkspaces();
667
- const [mode, setMode] = react.useState("select");
668
- const [selected, setSelected] = react.useState("");
669
- const [newName, setNewName] = react.useState("");
670
- const [loading, setLoading] = react.useState(false);
671
- const [error, setError] = react.useState("");
700
+ const [mode, setMode] = React.useState("select");
701
+ const [selected, setSelected] = React.useState("");
702
+ const [newName, setNewName] = React.useState("");
703
+ const [loading, setLoading] = React.useState(false);
704
+ const [error, setError] = React.useState("");
672
705
  if (isLoading) {
673
706
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingContainerStyle(), children: "Loading workspaces..." });
674
707
  }
@@ -823,7 +856,7 @@ function renderWithCitations(text, theme, onCiteClick) {
823
856
  return nodes.length > 0 ? nodes : [text];
824
857
  }
825
858
  function MessageBubble({ message, theme }) {
826
- const [expandedCite, setExpandedCite] = react.useState(null);
859
+ const [expandedCite, setExpandedCite] = React.useState(null);
827
860
  const hasCitations = message.role === "assistant" && message.metadata && CITE_RE.test(message.text);
828
861
  CITE_RE.lastIndex = 0;
829
862
  const resolved = hasCitations ? browser.resolveCitations(message.metadata) : [];
@@ -903,22 +936,22 @@ function ChatView({ workspaceId, theme, labels }) {
903
936
  const arbi = useArbi();
904
937
  const { data: docs, refetch: refetchDocs } = useDocuments(workspaceId);
905
938
  const mutation = useAssistantQuery();
906
- const [messages, setMessages] = react.useState([]);
907
- const [input, setInput] = react.useState("");
908
- const [streaming, setStreaming] = react.useState("");
909
- const [agentStatus, setAgentStatus] = react.useState("");
910
- const [selectedDocs, setSelectedDocs] = react.useState([]);
911
- const [docsExpanded, setDocsExpanded] = react.useState(false);
912
- const [previousResponseId, setPreviousResponseId] = react.useState(null);
913
- const [uploading, setUploading] = react.useState(false);
914
- const messagesEndRef = react.useRef(null);
915
- const fileInputRef = react.useRef(null);
916
- react.useEffect(() => {
939
+ const [messages, setMessages] = React.useState([]);
940
+ const [input, setInput] = React.useState("");
941
+ const [streaming, setStreaming] = React.useState("");
942
+ const [agentStatus, setAgentStatus] = React.useState("");
943
+ const [selectedDocs, setSelectedDocs] = React.useState([]);
944
+ const [docsExpanded, setDocsExpanded] = React.useState(false);
945
+ const [previousResponseId, setPreviousResponseId] = React.useState(null);
946
+ const [uploading, setUploading] = React.useState(false);
947
+ const messagesEndRef = React.useRef(null);
948
+ const fileInputRef = React.useRef(null);
949
+ React.useEffect(() => {
917
950
  if (docs && docs.length > 0 && selectedDocs.length === 0) {
918
951
  setSelectedDocs(docs.map((d) => d.external_id));
919
952
  }
920
953
  }, [docs, selectedDocs.length]);
921
- react.useEffect(() => {
954
+ React.useEffect(() => {
922
955
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
923
956
  }, [messages, streaming, agentStatus]);
924
957
  const toggleDoc = (docId) => {
@@ -926,7 +959,7 @@ function ChatView({ workspaceId, theme, labels }) {
926
959
  (prev) => prev.includes(docId) ? prev.filter((id) => id !== docId) : [...prev, docId]
927
960
  );
928
961
  };
929
- const handleUpload = react.useCallback(
962
+ const handleUpload = React.useCallback(
930
963
  async (e) => {
931
964
  const files = e.target.files;
932
965
  if (!files || files.length === 0) return;
@@ -947,7 +980,7 @@ function ChatView({ workspaceId, theme, labels }) {
947
980
  },
948
981
  [arbi, refetchDocs]
949
982
  );
950
- const handleSubmit = react.useCallback(
983
+ const handleSubmit = React.useCallback(
951
984
  (e) => {
952
985
  e.preventDefault();
953
986
  const question = input.trim();
@@ -1078,25 +1111,30 @@ function ChatView({ workspaceId, theme, labels }) {
1078
1111
  }
1079
1112
  function ChatWidget({ theme, labels, initialWorkspaceId, width, height }) {
1080
1113
  const arbi = useArbi();
1081
- const [screen, setScreen] = react.useState("auth");
1082
- const [workspaceId, setWorkspaceId] = react.useState(initialWorkspaceId);
1083
- const handleLogin = react.useCallback(async () => {
1114
+ const [screen, setScreen] = React.useState("auth");
1115
+ const [workspaceId, setWorkspaceId] = React.useState(initialWorkspaceId);
1116
+ const resolveWorkspace = React.useCallback(async () => {
1084
1117
  if (initialWorkspaceId) {
1085
1118
  try {
1086
1119
  await arbi.selectWorkspace(initialWorkspaceId);
1087
1120
  setScreen("chat");
1121
+ return;
1088
1122
  } catch {
1089
1123
  setScreen("workspace");
1124
+ return;
1090
1125
  }
1091
- } else {
1092
- setScreen("workspace");
1093
1126
  }
1127
+ setScreen("workspace");
1094
1128
  }, [arbi, initialWorkspaceId]);
1095
- const handleWorkspaceSelect = react.useCallback((id) => {
1129
+ const handleLogin = React.useCallback(() => resolveWorkspace(), [resolveWorkspace]);
1130
+ React.useEffect(() => {
1131
+ if (arbi.isLoggedIn) void resolveWorkspace();
1132
+ }, [arbi, resolveWorkspace]);
1133
+ const handleWorkspaceSelect = React.useCallback((id) => {
1096
1134
  setWorkspaceId(id);
1097
1135
  setScreen("chat");
1098
1136
  }, []);
1099
- const handleChangeWorkspace = react.useCallback(() => {
1137
+ const handleChangeWorkspace = React.useCallback(() => {
1100
1138
  setScreen("workspace");
1101
1139
  }, []);
1102
1140
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: containerStyle(theme, width, height), children: [
@@ -1125,6 +1163,26 @@ function ChatWidget({ theme, labels, initialWorkspaceId, width, height }) {
1125
1163
  ] })
1126
1164
  ] });
1127
1165
  }
1166
+ function ArbiChatPanel({
1167
+ workspaceId,
1168
+ theme: themeOverrides,
1169
+ labels: labelOverrides,
1170
+ width = "100%",
1171
+ height = "100%"
1172
+ }) {
1173
+ const theme = React.useMemo(() => getTheme(themeOverrides), [themeOverrides]);
1174
+ const labels = React.useMemo(() => getLabels(labelOverrides), [labelOverrides]);
1175
+ return /* @__PURE__ */ jsxRuntime.jsx(
1176
+ ChatWidget,
1177
+ {
1178
+ theme,
1179
+ labels,
1180
+ initialWorkspaceId: workspaceId,
1181
+ width,
1182
+ height
1183
+ }
1184
+ );
1185
+ }
1128
1186
  function ArbiChat({
1129
1187
  url,
1130
1188
  workspaceId,
@@ -1133,7 +1191,7 @@ function ArbiChat({
1133
1191
  width = "400px",
1134
1192
  height = "600px"
1135
1193
  }) {
1136
- const queryClient = react.useMemo(
1194
+ const queryClient = React.useMemo(
1137
1195
  () => new reactQuery.QueryClient({
1138
1196
  defaultOptions: {
1139
1197
  queries: { retry: 1, refetchOnWindowFocus: false },
@@ -1142,19 +1200,1262 @@ function ArbiChat({
1142
1200
  }),
1143
1201
  []
1144
1202
  );
1145
- const theme = react.useMemo(() => getTheme(themeOverrides), [themeOverrides]);
1146
- const labels = react.useMemo(() => getLabels(labelOverrides), [labelOverrides]);
1147
1203
  return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(ArbiProvider, { url, children: /* @__PURE__ */ jsxRuntime.jsx(
1148
- ChatWidget,
1204
+ ArbiChatPanel,
1149
1205
  {
1150
- theme,
1151
- labels,
1152
- initialWorkspaceId: workspaceId,
1206
+ workspaceId,
1207
+ theme: themeOverrides,
1208
+ labels: labelOverrides,
1153
1209
  width,
1154
1210
  height
1155
1211
  }
1156
1212
  ) }) });
1157
1213
  }
1214
+ function cn(...inputs) {
1215
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
1216
+ }
1217
+ var TooltipContext = React__namespace.createContext(null);
1218
+ var TooltipProvider = ({ children }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1219
+ function Tooltip({ children, delayDuration = 300 }) {
1220
+ const [open, setOpen] = React__namespace.useState(false);
1221
+ const triggerRef = React__namespace.useRef(null);
1222
+ const timer = React__namespace.useRef(null);
1223
+ const contentId = React__namespace.useId();
1224
+ const clearTimer = () => {
1225
+ if (timer.current) {
1226
+ clearTimeout(timer.current);
1227
+ timer.current = null;
1228
+ }
1229
+ };
1230
+ const show = React__namespace.useCallback(() => {
1231
+ clearTimer();
1232
+ timer.current = setTimeout(() => setOpen(true), delayDuration);
1233
+ }, [delayDuration]);
1234
+ const hide = React__namespace.useCallback(() => {
1235
+ clearTimer();
1236
+ setOpen(false);
1237
+ }, []);
1238
+ const setTrigger = React__namespace.useCallback((el) => {
1239
+ triggerRef.current = el;
1240
+ }, []);
1241
+ React__namespace.useEffect(() => () => clearTimer(), []);
1242
+ const value = React__namespace.useMemo(
1243
+ () => ({ open, show, hide, setTrigger, triggerRef, contentId }),
1244
+ [open, show, hide, setTrigger, contentId]
1245
+ );
1246
+ return /* @__PURE__ */ jsxRuntime.jsx(TooltipContext.Provider, { value, children });
1247
+ }
1248
+ function TooltipTrigger({ asChild, children, ...props }) {
1249
+ const ctx = React__namespace.useContext(TooltipContext);
1250
+ if (!ctx) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1251
+ const triggerHandlers = {
1252
+ onPointerEnter: (e) => {
1253
+ props.onPointerEnter?.(e);
1254
+ ctx.show();
1255
+ },
1256
+ onPointerLeave: (e) => {
1257
+ props.onPointerLeave?.(e);
1258
+ ctx.hide();
1259
+ },
1260
+ onFocus: (e) => {
1261
+ props.onFocus?.(e);
1262
+ ctx.show();
1263
+ },
1264
+ onBlur: (e) => {
1265
+ props.onBlur?.(e);
1266
+ ctx.hide();
1267
+ },
1268
+ "aria-describedby": ctx.open ? ctx.contentId : void 0,
1269
+ "data-state": ctx.open ? "open" : "closed"
1270
+ };
1271
+ if (asChild && React__namespace.isValidElement(children)) {
1272
+ const child = children;
1273
+ return React__namespace.cloneElement(child, {
1274
+ ...props,
1275
+ ...triggerHandlers,
1276
+ ref: ctx.setTrigger
1277
+ });
1278
+ }
1279
+ return /* @__PURE__ */ jsxRuntime.jsx(
1280
+ "button",
1281
+ {
1282
+ type: "button",
1283
+ ...props,
1284
+ ...triggerHandlers,
1285
+ ref: ctx.setTrigger,
1286
+ children
1287
+ }
1288
+ );
1289
+ }
1290
+ var TRANSFORM_BY_SIDE = {
1291
+ top: "translate(-50%, -100%)",
1292
+ bottom: "translate(-50%, 0)",
1293
+ left: "translate(-100%, -50%)",
1294
+ right: "translate(0, -50%)"
1295
+ };
1296
+ var TooltipContent = React__namespace.forwardRef(
1297
+ ({ className, side = "top", sideOffset = 4, style, ...props }, ref) => {
1298
+ const ctx = React__namespace.useContext(TooltipContext);
1299
+ const innerRef = React__namespace.useRef(null);
1300
+ const [coords, setCoords] = React__namespace.useState(null);
1301
+ React__namespace.useLayoutEffect(() => {
1302
+ if (!ctx?.open || !ctx.triggerRef.current) {
1303
+ setCoords(null);
1304
+ return;
1305
+ }
1306
+ const r = ctx.triggerRef.current.getBoundingClientRect();
1307
+ const c = innerRef.current?.getBoundingClientRect();
1308
+ const ch = c?.height ?? 0;
1309
+ const cw = c?.width ?? 0;
1310
+ const vh = window.innerHeight;
1311
+ const vw = window.innerWidth;
1312
+ let s = side;
1313
+ if (s === "top" && r.top - sideOffset - ch < 0) s = "bottom";
1314
+ else if (s === "bottom" && r.bottom + sideOffset + ch > vh) s = "top";
1315
+ else if (s === "left" && r.left - sideOffset - cw < 0) s = "right";
1316
+ else if (s === "right" && r.right + sideOffset + cw > vw) s = "left";
1317
+ setCoords({
1318
+ top: s === "top" ? r.top - sideOffset : s === "bottom" ? r.bottom + sideOffset : r.top + r.height / 2,
1319
+ left: s === "left" ? r.left - sideOffset : s === "right" ? r.right + sideOffset : r.left + r.width / 2,
1320
+ transform: TRANSFORM_BY_SIDE[s]
1321
+ });
1322
+ }, [ctx?.open, side, sideOffset, ctx?.triggerRef]);
1323
+ if (!ctx?.open) return null;
1324
+ const setRefs = (node) => {
1325
+ innerRef.current = node;
1326
+ if (typeof ref === "function") ref(node);
1327
+ else if (ref) ref.current = node;
1328
+ };
1329
+ return reactDom.createPortal(
1330
+ /* @__PURE__ */ jsxRuntime.jsx(
1331
+ "div",
1332
+ {
1333
+ ref: setRefs,
1334
+ id: ctx.contentId,
1335
+ role: "tooltip",
1336
+ className: cn("tooltip-content pointer-events-none", className),
1337
+ style: {
1338
+ position: "fixed",
1339
+ top: coords?.top ?? -9999,
1340
+ left: coords?.left ?? -9999,
1341
+ transform: coords?.transform ?? TRANSFORM_BY_SIDE[side],
1342
+ opacity: coords ? void 0 : 0,
1343
+ zIndex: 9999,
1344
+ ...style
1345
+ },
1346
+ ...props
1347
+ }
1348
+ ),
1349
+ document.body
1350
+ );
1351
+ }
1352
+ );
1353
+ TooltipContent.displayName = "TooltipContent";
1354
+ var Avatar = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1355
+ AvatarPrimitive__namespace.Root,
1356
+ {
1357
+ ref,
1358
+ className: cn("relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full", className),
1359
+ ...props
1360
+ }
1361
+ ));
1362
+ Avatar.displayName = AvatarPrimitive__namespace.Root.displayName;
1363
+ var AvatarImage = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1364
+ AvatarPrimitive__namespace.Image,
1365
+ {
1366
+ ref,
1367
+ className: cn("aspect-square h-full w-full", className),
1368
+ ...props
1369
+ }
1370
+ ));
1371
+ AvatarImage.displayName = AvatarPrimitive__namespace.Image.displayName;
1372
+ var AvatarFallback = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1373
+ AvatarPrimitive__namespace.Fallback,
1374
+ {
1375
+ ref,
1376
+ className: cn(
1377
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
1378
+ className
1379
+ ),
1380
+ ...props
1381
+ }
1382
+ ));
1383
+ AvatarFallback.displayName = AvatarPrimitive__namespace.Fallback.displayName;
1384
+ var badgeVariants = classVarianceAuthority.cva(
1385
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-sm font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
1386
+ {
1387
+ variants: {
1388
+ variant: {
1389
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
1390
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
1391
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
1392
+ outline: "text-foreground"
1393
+ }
1394
+ },
1395
+ defaultVariants: {
1396
+ variant: "default"
1397
+ }
1398
+ }
1399
+ );
1400
+ function Badge({ className, variant, ...props }) {
1401
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
1402
+ }
1403
+ var buttonVariants = classVarianceAuthority.cva(
1404
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1405
+ {
1406
+ variants: {
1407
+ variant: {
1408
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
1409
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
1410
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
1411
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
1412
+ ghost: "hover:bg-accent hover:text-accent-foreground",
1413
+ link: "text-primary underline-offset-4 hover:underline"
1414
+ },
1415
+ size: {
1416
+ default: "h-9 px-4 py-2",
1417
+ sm: "h-8 rounded-md px-3",
1418
+ lg: "h-10 rounded-md px-8",
1419
+ icon: "h-9 w-9"
1420
+ }
1421
+ },
1422
+ defaultVariants: {
1423
+ variant: "default",
1424
+ size: "default"
1425
+ }
1426
+ }
1427
+ );
1428
+ var Button = React__namespace.forwardRef(
1429
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
1430
+ const Comp = asChild ? reactSlot.Slot : "button";
1431
+ return /* @__PURE__ */ jsxRuntime.jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref, ...props });
1432
+ }
1433
+ );
1434
+ Button.displayName = "Button";
1435
+ var HoverCard = HoverCardPrimitive__namespace.Root;
1436
+ var HoverCardTrigger = HoverCardPrimitive__namespace.Trigger;
1437
+ var HoverCardContent = React__namespace.forwardRef(({ className, align = "center", sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(HoverCardPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1438
+ HoverCardPrimitive__namespace.Content,
1439
+ {
1440
+ ref,
1441
+ align,
1442
+ sideOffset,
1443
+ className: cn(
1444
+ "z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-hover-card-content-transform-origin]",
1445
+ className
1446
+ ),
1447
+ ...props
1448
+ }
1449
+ ) }));
1450
+ HoverCardContent.displayName = HoverCardPrimitive__namespace.Content.displayName;
1451
+
1452
+ // src/icons/colors.ts
1453
+ var NEUTRAL_GRAY = "#64748b";
1454
+ var FILE_TYPE_COLORS = {
1455
+ pdf: "#ef4444",
1456
+ // red
1457
+ img: "#8b5cf6",
1458
+ // violet-500 (images)
1459
+ vid: "#10b981",
1460
+ // emerald-500 (video)
1461
+ aud: "#f59e0b",
1462
+ // amber-500 (audio)
1463
+ eml: "#0d9488",
1464
+ // teal-600 (email)
1465
+ generic: NEUTRAL_GRAY,
1466
+ // gray (unknown)
1467
+ white: "#ffffff"
1468
+ // for strokes/text on colored backgrounds
1469
+ };
1470
+ var PdfIcon = ({ size = 16, className = "" }) => {
1471
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1472
+ "svg",
1473
+ {
1474
+ width: size,
1475
+ height: size,
1476
+ viewBox: "0 0 24 24",
1477
+ fill: "none",
1478
+ xmlns: "http://www.w3.org/2000/svg",
1479
+ className,
1480
+ children: [
1481
+ /* @__PURE__ */ jsxRuntime.jsx(
1482
+ "path",
1483
+ {
1484
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1485
+ fill: FILE_TYPE_COLORS.pdf,
1486
+ stroke: FILE_TYPE_COLORS.pdf,
1487
+ strokeWidth: "1",
1488
+ strokeLinecap: "round",
1489
+ strokeLinejoin: "round"
1490
+ }
1491
+ ),
1492
+ /* @__PURE__ */ jsxRuntime.jsx(
1493
+ "path",
1494
+ {
1495
+ d: "M14 2v6h6",
1496
+ fill: "none",
1497
+ stroke: FILE_TYPE_COLORS.white,
1498
+ strokeWidth: "1",
1499
+ strokeLinecap: "round",
1500
+ strokeLinejoin: "round"
1501
+ }
1502
+ ),
1503
+ /* @__PURE__ */ jsxRuntime.jsx(
1504
+ "text",
1505
+ {
1506
+ x: "12",
1507
+ y: "16",
1508
+ fontSize: "6",
1509
+ fill: "white",
1510
+ textAnchor: "middle",
1511
+ fontWeight: "bold",
1512
+ fontFamily: "Arial, sans-serif",
1513
+ children: "PDF"
1514
+ }
1515
+ )
1516
+ ]
1517
+ }
1518
+ );
1519
+ };
1520
+ var AudIcon = ({ size = 16, className = "" }) => {
1521
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1522
+ "svg",
1523
+ {
1524
+ width: size,
1525
+ height: size,
1526
+ viewBox: "0 0 24 24",
1527
+ fill: "none",
1528
+ xmlns: "http://www.w3.org/2000/svg",
1529
+ className,
1530
+ children: [
1531
+ /* @__PURE__ */ jsxRuntime.jsx(
1532
+ "path",
1533
+ {
1534
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1535
+ fill: FILE_TYPE_COLORS.aud,
1536
+ stroke: FILE_TYPE_COLORS.aud,
1537
+ strokeWidth: "1",
1538
+ strokeLinecap: "round",
1539
+ strokeLinejoin: "round"
1540
+ }
1541
+ ),
1542
+ /* @__PURE__ */ jsxRuntime.jsx(
1543
+ "path",
1544
+ {
1545
+ d: "M14 2v6h6",
1546
+ fill: "none",
1547
+ stroke: FILE_TYPE_COLORS.white,
1548
+ strokeWidth: "1",
1549
+ strokeLinecap: "round",
1550
+ strokeLinejoin: "round"
1551
+ }
1552
+ ),
1553
+ /* @__PURE__ */ jsxRuntime.jsx(
1554
+ "text",
1555
+ {
1556
+ x: "12",
1557
+ y: "16",
1558
+ fontSize: "6",
1559
+ fill: "white",
1560
+ textAnchor: "middle",
1561
+ fontWeight: "bold",
1562
+ fontFamily: "Arial, sans-serif",
1563
+ children: "AUD"
1564
+ }
1565
+ )
1566
+ ]
1567
+ }
1568
+ );
1569
+ };
1570
+ var ImgIcon = ({ size = 16, className = "" }) => {
1571
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1572
+ "svg",
1573
+ {
1574
+ width: size,
1575
+ height: size,
1576
+ viewBox: "0 0 24 24",
1577
+ fill: "none",
1578
+ xmlns: "http://www.w3.org/2000/svg",
1579
+ className,
1580
+ children: [
1581
+ /* @__PURE__ */ jsxRuntime.jsx(
1582
+ "path",
1583
+ {
1584
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1585
+ fill: FILE_TYPE_COLORS.img,
1586
+ stroke: FILE_TYPE_COLORS.img,
1587
+ strokeWidth: "1",
1588
+ strokeLinecap: "round",
1589
+ strokeLinejoin: "round"
1590
+ }
1591
+ ),
1592
+ /* @__PURE__ */ jsxRuntime.jsx(
1593
+ "path",
1594
+ {
1595
+ d: "M14 2v6h6",
1596
+ fill: "none",
1597
+ stroke: FILE_TYPE_COLORS.white,
1598
+ strokeWidth: "1",
1599
+ strokeLinecap: "round",
1600
+ strokeLinejoin: "round"
1601
+ }
1602
+ ),
1603
+ /* @__PURE__ */ jsxRuntime.jsx(
1604
+ "text",
1605
+ {
1606
+ x: "12",
1607
+ y: "16",
1608
+ fontSize: "6",
1609
+ fill: "white",
1610
+ textAnchor: "middle",
1611
+ fontWeight: "bold",
1612
+ fontFamily: "Arial, sans-serif",
1613
+ children: "IMG"
1614
+ }
1615
+ )
1616
+ ]
1617
+ }
1618
+ );
1619
+ };
1620
+ var VidIcon = ({ size = 16, className = "" }) => {
1621
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1622
+ "svg",
1623
+ {
1624
+ width: size,
1625
+ height: size,
1626
+ viewBox: "0 0 24 24",
1627
+ fill: "none",
1628
+ xmlns: "http://www.w3.org/2000/svg",
1629
+ className,
1630
+ children: [
1631
+ /* @__PURE__ */ jsxRuntime.jsx(
1632
+ "path",
1633
+ {
1634
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1635
+ fill: FILE_TYPE_COLORS.vid,
1636
+ stroke: FILE_TYPE_COLORS.vid,
1637
+ strokeWidth: "1",
1638
+ strokeLinecap: "round",
1639
+ strokeLinejoin: "round"
1640
+ }
1641
+ ),
1642
+ /* @__PURE__ */ jsxRuntime.jsx(
1643
+ "path",
1644
+ {
1645
+ d: "M14 2v6h6",
1646
+ fill: "none",
1647
+ stroke: FILE_TYPE_COLORS.white,
1648
+ strokeWidth: "1",
1649
+ strokeLinecap: "round",
1650
+ strokeLinejoin: "round"
1651
+ }
1652
+ ),
1653
+ /* @__PURE__ */ jsxRuntime.jsx(
1654
+ "text",
1655
+ {
1656
+ x: "12",
1657
+ y: "16",
1658
+ fontSize: "6",
1659
+ fill: "white",
1660
+ textAnchor: "middle",
1661
+ fontWeight: "bold",
1662
+ fontFamily: "Arial, sans-serif",
1663
+ children: "VID"
1664
+ }
1665
+ )
1666
+ ]
1667
+ }
1668
+ );
1669
+ };
1670
+ var EmlIcon = ({ size = 16, className = "" }) => {
1671
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1672
+ "svg",
1673
+ {
1674
+ width: size,
1675
+ height: size,
1676
+ viewBox: "0 0 24 24",
1677
+ fill: "none",
1678
+ xmlns: "http://www.w3.org/2000/svg",
1679
+ className,
1680
+ children: [
1681
+ /* @__PURE__ */ jsxRuntime.jsx(
1682
+ "path",
1683
+ {
1684
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1685
+ fill: FILE_TYPE_COLORS.eml,
1686
+ stroke: FILE_TYPE_COLORS.eml,
1687
+ strokeWidth: "1",
1688
+ strokeLinecap: "round",
1689
+ strokeLinejoin: "round"
1690
+ }
1691
+ ),
1692
+ /* @__PURE__ */ jsxRuntime.jsx(
1693
+ "path",
1694
+ {
1695
+ d: "M14 2v6h6",
1696
+ fill: "none",
1697
+ stroke: FILE_TYPE_COLORS.white,
1698
+ strokeWidth: "1",
1699
+ strokeLinecap: "round",
1700
+ strokeLinejoin: "round"
1701
+ }
1702
+ ),
1703
+ /* @__PURE__ */ jsxRuntime.jsx(
1704
+ "rect",
1705
+ {
1706
+ x: "7",
1707
+ y: "12",
1708
+ width: "10",
1709
+ height: "7",
1710
+ rx: "1",
1711
+ fill: "none",
1712
+ stroke: "white",
1713
+ strokeWidth: "1.2"
1714
+ }
1715
+ ),
1716
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 13l5 3 5-3", fill: "none", stroke: "white", strokeWidth: "1.2", strokeLinejoin: "round" })
1717
+ ]
1718
+ }
1719
+ );
1720
+ };
1721
+ var FileIcon = ({ size = 16, className = "" }) => {
1722
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1723
+ "svg",
1724
+ {
1725
+ width: size,
1726
+ height: size,
1727
+ viewBox: "0 0 24 24",
1728
+ fill: "none",
1729
+ xmlns: "http://www.w3.org/2000/svg",
1730
+ className,
1731
+ children: [
1732
+ /* @__PURE__ */ jsxRuntime.jsx(
1733
+ "path",
1734
+ {
1735
+ d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z",
1736
+ fill: FILE_TYPE_COLORS.generic,
1737
+ stroke: FILE_TYPE_COLORS.generic,
1738
+ strokeWidth: "1",
1739
+ strokeLinecap: "round",
1740
+ strokeLinejoin: "round"
1741
+ }
1742
+ ),
1743
+ /* @__PURE__ */ jsxRuntime.jsx(
1744
+ "path",
1745
+ {
1746
+ d: "M14 2v6h6",
1747
+ fill: "none",
1748
+ stroke: FILE_TYPE_COLORS.white,
1749
+ strokeWidth: "1",
1750
+ strokeLinecap: "round",
1751
+ strokeLinejoin: "round"
1752
+ }
1753
+ ),
1754
+ /* @__PURE__ */ jsxRuntime.jsx(
1755
+ "text",
1756
+ {
1757
+ x: "12",
1758
+ y: "17",
1759
+ fontSize: "10",
1760
+ fill: "white",
1761
+ textAnchor: "middle",
1762
+ fontWeight: "bold",
1763
+ fontFamily: "Arial, sans-serif",
1764
+ children: "?"
1765
+ }
1766
+ )
1767
+ ]
1768
+ }
1769
+ );
1770
+ };
1771
+ var EntityPill = React.forwardRef(function EntityPill2({
1772
+ icon,
1773
+ label,
1774
+ secondaryText,
1775
+ size = "sm",
1776
+ shape = "rounded",
1777
+ className,
1778
+ labelMaxWidth = "max-w-[320px]",
1779
+ fullWidth = false,
1780
+ highlight = false,
1781
+ onClick,
1782
+ onIconClick,
1783
+ onMoreClick,
1784
+ moreContent,
1785
+ href,
1786
+ disabled = false,
1787
+ tooltipContent,
1788
+ tooltipSide = "bottom",
1789
+ "data-testid": testId
1790
+ }, ref) {
1791
+ const shapeClass = shape === "pill" ? "rounded-full" : "rounded-md";
1792
+ const sizeClasses = size === "base" ? "gap-1.5 px-1.5 py-0.5" : "gap-1 px-1";
1793
+ const textSizeClass = size === "base" ? "text-base" : "text-sm";
1794
+ const baseClasses = cn(
1795
+ "group/pill items-center",
1796
+ fullWidth ? "flex w-full" : "inline-flex",
1797
+ sizeClasses,
1798
+ shapeClass,
1799
+ "bg-muted",
1800
+ "border border-border",
1801
+ "transition-all",
1802
+ className
1803
+ );
1804
+ const interactiveClasses = "cursor-pointer hover:bg-muted/80";
1805
+ const disabledClasses = "cursor-default opacity-60";
1806
+ const highlightClasses = "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground";
1807
+ const mainContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1808
+ onIconClick ? /* @__PURE__ */ jsxRuntime.jsx(
1809
+ "span",
1810
+ {
1811
+ role: "button",
1812
+ tabIndex: 0,
1813
+ className: "flex-shrink-0 cursor-pointer hover:opacity-70 transition-opacity",
1814
+ onClick: (e) => {
1815
+ e.stopPropagation();
1816
+ onIconClick(e);
1817
+ },
1818
+ children: icon
1819
+ }
1820
+ ) : icon,
1821
+ /* @__PURE__ */ jsxRuntime.jsx(
1822
+ "span",
1823
+ {
1824
+ className: cn(textSizeClass, "font-medium truncate leading-tight min-w-0", labelMaxWidth),
1825
+ children: label
1826
+ }
1827
+ ),
1828
+ secondaryText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground flex-shrink-0 leading-none", children: secondaryText })
1829
+ ] });
1830
+ const tooltipWrap = (content, tip, side = tooltipSide, triggerClassName, triggerProps) => /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
1831
+ /* @__PURE__ */ jsxRuntime.jsx(
1832
+ TooltipTrigger,
1833
+ {
1834
+ onFocusCapture: (e) => e.stopPropagation(),
1835
+ className: triggerClassName,
1836
+ ...triggerProps,
1837
+ children: content
1838
+ }
1839
+ ),
1840
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side, className: "p-2", children: tip })
1841
+ ] });
1842
+ const mainAreaClass = cn("inline-flex items-center gap-1", fullWidth && "min-w-0 flex-1");
1843
+ if (onMoreClick || moreContent) {
1844
+ let mainArea;
1845
+ if (tooltipContent) {
1846
+ mainArea = tooltipWrap(
1847
+ mainContent,
1848
+ tooltipContent,
1849
+ tooltipSide,
1850
+ cn(mainAreaClass, disabled && "opacity-60"),
1851
+ {
1852
+ type: "button",
1853
+ onClick: href ? onClick : disabled ? void 0 : onClick,
1854
+ disabled: disabled || void 0
1855
+ }
1856
+ );
1857
+ } else if (href) {
1858
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx(
1859
+ "a",
1860
+ {
1861
+ href,
1862
+ target: "_blank",
1863
+ rel: "noopener noreferrer",
1864
+ className: mainAreaClass,
1865
+ onClick,
1866
+ children: mainContent
1867
+ }
1868
+ );
1869
+ } else if (onClick) {
1870
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx(
1871
+ "button",
1872
+ {
1873
+ type: "button",
1874
+ onClick: disabled ? void 0 : onClick,
1875
+ disabled,
1876
+ className: cn("inline-flex items-center gap-1", disabled && "opacity-60"),
1877
+ children: mainContent
1878
+ }
1879
+ );
1880
+ } else {
1881
+ mainArea = /* @__PURE__ */ jsxRuntime.jsx("span", { className: mainAreaClass, children: mainContent });
1882
+ }
1883
+ const moreArea = moreContent ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 leading-none", children: moreContent }) : tooltipWrap(
1884
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { className: "w-3.5 h-3.5" }),
1885
+ "Click for more",
1886
+ tooltipSide,
1887
+ "flex-shrink-0 leading-none text-muted-foreground hover:text-foreground",
1888
+ {
1889
+ type: "button",
1890
+ onClick: (e) => {
1891
+ e.stopPropagation();
1892
+ onMoreClick?.(e);
1893
+ }
1894
+ }
1895
+ );
1896
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1897
+ "span",
1898
+ {
1899
+ ref,
1900
+ className: cn(
1901
+ baseClasses,
1902
+ (onClick || href) && !disabled && interactiveClasses,
1903
+ highlight && highlightClasses
1904
+ ),
1905
+ "data-testid": testId,
1906
+ children: [
1907
+ mainArea,
1908
+ moreArea
1909
+ ]
1910
+ }
1911
+ );
1912
+ }
1913
+ if (tooltipContent) {
1914
+ if (href) {
1915
+ return tooltipWrap(
1916
+ /* @__PURE__ */ jsxRuntime.jsx(
1917
+ "a",
1918
+ {
1919
+ href,
1920
+ target: "_blank",
1921
+ rel: "noopener noreferrer",
1922
+ className: mainAreaClass,
1923
+ onClick,
1924
+ children: mainContent
1925
+ }
1926
+ ),
1927
+ tooltipContent,
1928
+ tooltipSide,
1929
+ cn(baseClasses, interactiveClasses),
1930
+ { "data-testid": testId }
1931
+ );
1932
+ }
1933
+ return tooltipWrap(
1934
+ mainContent,
1935
+ tooltipContent,
1936
+ tooltipSide,
1937
+ cn(
1938
+ baseClasses,
1939
+ onClick && !disabled ? interactiveClasses : "",
1940
+ disabled ? disabledClasses : "",
1941
+ highlight && highlightClasses
1942
+ ),
1943
+ {
1944
+ type: "button",
1945
+ ref,
1946
+ onClick: onClick && !disabled ? onClick : void 0,
1947
+ disabled: disabled || void 0,
1948
+ "data-testid": testId
1949
+ }
1950
+ );
1951
+ }
1952
+ if (href) {
1953
+ return /* @__PURE__ */ jsxRuntime.jsx(
1954
+ "a",
1955
+ {
1956
+ ref,
1957
+ href,
1958
+ target: "_blank",
1959
+ rel: "noopener noreferrer",
1960
+ className: cn(baseClasses, interactiveClasses),
1961
+ "data-testid": testId,
1962
+ onClick,
1963
+ children: mainContent
1964
+ }
1965
+ );
1966
+ }
1967
+ if (onClick) {
1968
+ return /* @__PURE__ */ jsxRuntime.jsx(
1969
+ "button",
1970
+ {
1971
+ ref,
1972
+ type: "button",
1973
+ onClick: disabled ? void 0 : onClick,
1974
+ disabled,
1975
+ className: cn(
1976
+ baseClasses,
1977
+ disabled ? disabledClasses : interactiveClasses,
1978
+ highlight && highlightClasses
1979
+ ),
1980
+ "data-testid": testId,
1981
+ children: mainContent
1982
+ }
1983
+ );
1984
+ }
1985
+ return /* @__PURE__ */ jsxRuntime.jsx(
1986
+ "span",
1987
+ {
1988
+ ref,
1989
+ className: cn(baseClasses, highlight && highlightClasses),
1990
+ "data-testid": testId,
1991
+ children: mainContent
1992
+ }
1993
+ );
1994
+ });
1995
+ function getDocumentTitle(document2, defaultValue = "") {
1996
+ if (!document2) return defaultValue;
1997
+ return document2.doc_metadata?.title || document2.file_name || defaultValue;
1998
+ }
1999
+ var MAX_LABEL_CHARS = 30;
2000
+ function clampLabel(text) {
2001
+ return text.length > MAX_LABEL_CHARS ? `${text.slice(0, MAX_LABEL_CHARS).trimEnd()}\u2026` : text;
2002
+ }
2003
+ var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp"]);
2004
+ var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set(["mp4", "mpeg", "mpg", "webm", "mov", "avi", "mkv"]);
2005
+ var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "wav", "m4a", "aac", "ogg", "flac"]);
2006
+ var EMAIL_EXTENSIONS = /* @__PURE__ */ new Set(["eml", "msg"]);
2007
+ function getDocIcon(fileName, iconSize = 14) {
2008
+ const ext = fileName?.split(".").pop()?.toLowerCase();
2009
+ if (ext && VIDEO_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(VidIcon, { size: iconSize, className: "flex-shrink-0" });
2010
+ if (ext && AUDIO_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(AudIcon, { size: iconSize, className: "flex-shrink-0" });
2011
+ if (ext && IMAGE_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(ImgIcon, { size: iconSize, className: "flex-shrink-0" });
2012
+ if (ext && EMAIL_EXTENSIONS.has(ext)) return /* @__PURE__ */ jsxRuntime.jsx(EmlIcon, { size: iconSize, className: "flex-shrink-0" });
2013
+ return /* @__PURE__ */ jsxRuntime.jsx(PdfIcon, { size: iconSize, className: "flex-shrink-0" });
2014
+ }
2015
+ function DocumentEntity({
2016
+ doc,
2017
+ icon,
2018
+ size = "sm",
2019
+ labelMaxWidth,
2020
+ onClick,
2021
+ onIconClick,
2022
+ showHoverEye,
2023
+ viewing,
2024
+ iconBadge,
2025
+ actions,
2026
+ tooltipContent,
2027
+ className,
2028
+ fullWidth
2029
+ }) {
2030
+ const title = getDocumentTitle(doc);
2031
+ const ext = doc.file_name?.split(".").pop()?.toLowerCase();
2032
+ const iconSize = size === "base" ? 16 : 14;
2033
+ const eyeSizeClass = size === "base" ? "h-4 w-4" : "h-3.5 w-3.5";
2034
+ const baseIcon = icon ?? getDocIcon(doc.file_name, iconSize);
2035
+ const showEye = showHoverEye || viewing;
2036
+ const displayIcon = showEye || iconBadge ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex flex-shrink-0 items-center justify-center", children: [
2037
+ showEye ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2038
+ /* @__PURE__ */ jsxRuntime.jsx(
2039
+ "span",
2040
+ {
2041
+ className: cn(
2042
+ "transition-opacity",
2043
+ viewing ? "opacity-0" : "group-hover/pill:opacity-0 group-has-[[data-state=open]]/pill:opacity-0"
2044
+ ),
2045
+ children: baseIcon
2046
+ }
2047
+ ),
2048
+ /* @__PURE__ */ jsxRuntime.jsx(
2049
+ lucideReact.Eye,
2050
+ {
2051
+ className: cn(
2052
+ "absolute inset-0 m-auto transition-opacity",
2053
+ eyeSizeClass,
2054
+ viewing ? "text-primary-foreground opacity-100" : "text-primary opacity-0 group-hover/pill:opacity-100 group-has-[[data-state=open]]/pill:opacity-100"
2055
+ )
2056
+ }
2057
+ )
2058
+ ] }) : baseIcon,
2059
+ iconBadge
2060
+ ] }) : baseIcon;
2061
+ const defaultTooltip = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 text-xs max-w-[300px]", children: [
2062
+ doc.folder && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 text-muted-foreground", children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FolderOpen, { className: "h-3 w-3 text-yellow-600 shrink-0" }),
2064
+ doc.folder.split("/").map((part, i, arr) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-0.5 shrink-0", children: [
2065
+ i > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/50 mx-0.5", children: "/" }),
2066
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: i < arr.length - 1 ? "text-muted-foreground/70" : "", children: part })
2067
+ ] }, i))
2068
+ ] }),
2069
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium break-words", children: [
2070
+ title,
2071
+ ext ? `.${ext}` : ""
2072
+ ] })
2073
+ ] });
2074
+ return /* @__PURE__ */ jsxRuntime.jsx(
2075
+ EntityPill,
2076
+ {
2077
+ icon: displayIcon,
2078
+ size,
2079
+ label: fullWidth ? title : clampLabel(title),
2080
+ labelMaxWidth: labelMaxWidth ?? "max-w-[140px]",
2081
+ fullWidth,
2082
+ onClick,
2083
+ onIconClick,
2084
+ moreContent: actions,
2085
+ className,
2086
+ highlight: viewing,
2087
+ tooltipContent: tooltipContent ?? defaultTooltip
2088
+ }
2089
+ );
2090
+ }
2091
+ var BASE_COLORS = {
2092
+ "0": "#10b981",
2093
+ "1": "#3b82f6",
2094
+ "2": "#8b5cf6",
2095
+ "3": "#f43f5e",
2096
+ "4": "#f59e0b",
2097
+ "5": "#84cc16",
2098
+ "6": "#a855f7",
2099
+ "7": "#06b6d4",
2100
+ "8": "#f97316",
2101
+ "9": "#14b8a6",
2102
+ a: "#ef4444",
2103
+ b: "#6366f1",
2104
+ c: "#ec4899",
2105
+ d: "#22c55e",
2106
+ e: "#eab308",
2107
+ f: "#0ea5e9"
2108
+ };
2109
+ function getEntityColor(entityId) {
2110
+ return BASE_COLORS[entityId[4]] || BASE_COLORS["0"];
2111
+ }
2112
+ var TAG_TYPE_LABELS = {
2113
+ checkbox: "Checkbox",
2114
+ select: "Select",
2115
+ number: "Number",
2116
+ text: "Text",
2117
+ folder: "Folder",
2118
+ search: "Saved Search",
2119
+ date: "Date",
2120
+ assistant: "AI Assistant"
2121
+ };
2122
+ var TAG_TYPE_ICONS = {
2123
+ checkbox: lucideReact.SquareCheckBig,
2124
+ select: lucideReact.List,
2125
+ number: lucideReact.Hash,
2126
+ text: lucideReact.StickyNote,
2127
+ folder: lucideReact.Folder,
2128
+ search: lucideReact.Search,
2129
+ date: lucideReact.Calendar,
2130
+ assistant: lucideReact.Bot
2131
+ };
2132
+ function TagEntity({
2133
+ tag,
2134
+ size = "md",
2135
+ className = "",
2136
+ onClick,
2137
+ showTooltip = true
2138
+ }) {
2139
+ const tagType = tag.tag_type?.type ?? "text";
2140
+ const iconSize = size === "sm" ? 12 : size === "md" ? 14 : 16;
2141
+ const Icon = TAG_TYPE_ICONS[tagType] || lucideReact.StickyNote;
2142
+ const sizeClasses = {
2143
+ sm: "p-0.5",
2144
+ md: "p-1",
2145
+ lg: "p-1.5"
2146
+ };
2147
+ const tagColor = tag.color ?? getEntityColor(tag.external_id);
2148
+ const iconElement = /* @__PURE__ */ jsxRuntime.jsx(
2149
+ "span",
2150
+ {
2151
+ className: `inline-flex items-center justify-center rounded-md text-white flex-shrink-0 ${sizeClasses[size]}`,
2152
+ style: { backgroundColor: tagColor },
2153
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: "flex-shrink-0" })
2154
+ }
2155
+ );
2156
+ const pillSize = size === "lg" ? "base" : "sm";
2157
+ const tooltipContent = showTooltip ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
2158
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2159
+ /* @__PURE__ */ jsxRuntime.jsx(
2160
+ "span",
2161
+ {
2162
+ className: "inline-flex items-center justify-center rounded-md text-white p-1",
2163
+ style: { backgroundColor: tagColor },
2164
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 16 })
2165
+ }
2166
+ ),
2167
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-sm", children: tag.name })
2168
+ ] }),
2169
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5 text-sm", children: [
2170
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2171
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Type:" }),
2172
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: TAG_TYPE_LABELS[tagType] || tagType })
2173
+ ] }),
2174
+ tag.doctag_count != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
2175
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Documents:" }),
2176
+ /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "secondary", className: "h-5 min-w-[20px] justify-center", children: tag.doctag_count ?? 0 })
2177
+ ] }),
2178
+ tag.shared != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: tag.shared ? "Shared" : "Private" }) })
2179
+ ] })
2180
+ ] }) : void 0;
2181
+ return /* @__PURE__ */ jsxRuntime.jsx(
2182
+ EntityPill,
2183
+ {
2184
+ icon: iconElement,
2185
+ label: tag.name,
2186
+ size: pillSize,
2187
+ shape: "rounded",
2188
+ labelMaxWidth: "max-w-[180px]",
2189
+ tooltipContent,
2190
+ onClick,
2191
+ className,
2192
+ "data-testid": `tag-entity-${tag.external_id}`
2193
+ }
2194
+ );
2195
+ }
2196
+ var VARIANT_STYLES = {
2197
+ "mine-paid": {
2198
+ pill: "bg-primary text-primary-foreground border-transparent",
2199
+ icon: "text-primary-foreground"
2200
+ },
2201
+ other: {
2202
+ pill: "bg-secondary text-secondary-foreground border-transparent",
2203
+ icon: "text-secondary-foreground"
2204
+ },
2205
+ "mine-free": {
2206
+ pill: "bg-muted-foreground text-background border-transparent",
2207
+ icon: "text-background"
2208
+ },
2209
+ common: {
2210
+ pill: "",
2211
+ icon: "text-muted-foreground"
2212
+ }
2213
+ };
2214
+ function resolveVariant(relation, paid, hasCollaborators) {
2215
+ if (relation === "common") return "common";
2216
+ if (relation === "other") return "other";
2217
+ if (relation === "mine") return paid ? "mine-paid" : "mine-free";
2218
+ if (paid) return hasCollaborators ? "other" : "mine-paid";
2219
+ return "mine-free";
2220
+ }
2221
+ function ProjectEntity({
2222
+ name,
2223
+ label,
2224
+ icon,
2225
+ subscription = "none",
2226
+ hasCollaborators = false,
2227
+ size = "sm",
2228
+ className,
2229
+ onClick,
2230
+ relation,
2231
+ isPaid,
2232
+ tooltipContent
2233
+ }) {
2234
+ const paid = isPaid ?? (subscription === "active" || subscription === "past_due" || subscription === "dev");
2235
+ const variant = resolveVariant(relation, paid, hasCollaborators);
2236
+ const { pill, icon: iconClass } = VARIANT_STYLES[variant];
2237
+ const iconSizeClass = size === "base" ? "h-4 w-4" : "h-3.5 w-3.5";
2238
+ const iconNode = icon ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Package, { className: cn(iconSizeClass, iconClass) });
2239
+ return /* @__PURE__ */ jsxRuntime.jsx(
2240
+ EntityPill,
2241
+ {
2242
+ icon: iconNode,
2243
+ label: label ?? name,
2244
+ size,
2245
+ shape: "pill",
2246
+ className: cn(pill, className),
2247
+ onClick,
2248
+ tooltipContent
2249
+ }
2250
+ );
2251
+ }
2252
+ var useArbiUiStore = zustand.create((set) => ({
2253
+ selectedDocIds: [],
2254
+ setSelectedDocIds: (ids) => set({ selectedDocIds: ids }),
2255
+ viewingDocId: null,
2256
+ setViewingDocId: (id) => set({ viewingDocId: id })
2257
+ }));
2258
+ agGridCommunity.ModuleRegistry.registerModules([agGridCommunity.AllCommunityModule]);
2259
+ function formatBytes(bytes) {
2260
+ if (bytes == null || Number.isNaN(bytes)) return "\u2014";
2261
+ if (bytes < 1024) return `${bytes} B`;
2262
+ const units = ["KB", "MB", "GB", "TB"];
2263
+ let value = bytes / 1024;
2264
+ let i = 0;
2265
+ while (value >= 1024 && i < units.length - 1) {
2266
+ value /= 1024;
2267
+ i++;
2268
+ }
2269
+ return `${value.toFixed(value >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
2270
+ }
2271
+ var STATUS_VARIANTS = {
2272
+ completed: "default",
2273
+ empty: "secondary",
2274
+ "low-content": "secondary",
2275
+ processing: "outline",
2276
+ queued: "outline",
2277
+ failed: "destructive",
2278
+ skipped: "destructive"
2279
+ };
2280
+ function DocumentTable({
2281
+ workspaceId,
2282
+ documents,
2283
+ onOpenDocument,
2284
+ selectedIds,
2285
+ onSelectionChange,
2286
+ height = 480,
2287
+ className
2288
+ }) {
2289
+ const query = useDocuments(workspaceId, { enabled: !documents });
2290
+ const rows = documents ?? query.data ?? [];
2291
+ const isLoading = !documents && query.isLoading;
2292
+ const tagsQuery = useTags(workspaceId);
2293
+ const tagNameById = React__namespace.default.useMemo(() => {
2294
+ const map = /* @__PURE__ */ new Map();
2295
+ for (const t of tagsQuery.data ?? []) {
2296
+ if (t.external_id) map.set(t.external_id, t.name ?? t.external_id.slice(0, 8));
2297
+ }
2298
+ return map;
2299
+ }, [tagsQuery.data]);
2300
+ const storeSelected = useArbiUiStore((s) => s.selectedDocIds);
2301
+ const storeSetSelected = useArbiUiStore((s) => s.setSelectedDocIds);
2302
+ const viewingDocId = useArbiUiStore((s) => s.viewingDocId);
2303
+ const setViewingDocId = useArbiUiStore((s) => s.setViewingDocId);
2304
+ const effectiveSelected = selectedIds ?? storeSelected;
2305
+ const emitSelection = onSelectionChange ?? storeSetSelected;
2306
+ const gridApiRef = React__namespace.default.useRef(null);
2307
+ const openDocument = React__namespace.default.useCallback(
2308
+ (id) => {
2309
+ setViewingDocId(id);
2310
+ onOpenDocument?.(id);
2311
+ },
2312
+ [onOpenDocument, setViewingDocId]
2313
+ );
2314
+ const applySelection = React__namespace.default.useCallback(() => {
2315
+ const api = gridApiRef.current;
2316
+ if (!api) return;
2317
+ const wanted = new Set(effectiveSelected);
2318
+ api.forEachNode((node) => {
2319
+ const id = node.data?.external_id;
2320
+ const shouldSelect = !!id && wanted.has(id);
2321
+ if (node.isSelected() !== shouldSelect) node.setSelected(shouldSelect);
2322
+ });
2323
+ }, [effectiveSelected]);
2324
+ React__namespace.default.useEffect(() => {
2325
+ applySelection();
2326
+ }, [applySelection]);
2327
+ const columnDefs = React__namespace.default.useMemo(
2328
+ () => [
2329
+ {
2330
+ colId: "select",
2331
+ headerName: "",
2332
+ width: 44,
2333
+ pinned: "left",
2334
+ checkboxSelection: true,
2335
+ headerCheckboxSelection: true,
2336
+ sortable: false,
2337
+ filter: false,
2338
+ resizable: false,
2339
+ suppressMovable: true
2340
+ },
2341
+ {
2342
+ colId: "title",
2343
+ headerName: "Document Name",
2344
+ flex: 3,
2345
+ minWidth: 240,
2346
+ sortable: true,
2347
+ valueGetter: (p) => p.data?.doc_metadata?.title || p.data?.file_name || "",
2348
+ cellRenderer: (p) => {
2349
+ const doc = p.data;
2350
+ if (!doc) return null;
2351
+ return /* @__PURE__ */ jsxRuntime.jsx(
2352
+ DocumentEntity,
2353
+ {
2354
+ doc,
2355
+ size: "base",
2356
+ fullWidth: true,
2357
+ showHoverEye: true,
2358
+ viewing: viewingDocId === doc.external_id,
2359
+ onClick: (e) => {
2360
+ e.stopPropagation();
2361
+ if (doc.external_id) openDocument(doc.external_id);
2362
+ }
2363
+ }
2364
+ );
2365
+ }
2366
+ },
2367
+ {
2368
+ colId: "status",
2369
+ headerName: "Status",
2370
+ width: 140,
2371
+ sortable: true,
2372
+ field: "status",
2373
+ cellRenderer: (p) => {
2374
+ const status = p.data?.status;
2375
+ if (!status) return null;
2376
+ return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: STATUS_VARIANTS[status.toLowerCase()] ?? "secondary", children: status });
2377
+ }
2378
+ },
2379
+ {
2380
+ colId: "all_tags",
2381
+ headerName: "Labels",
2382
+ flex: 1,
2383
+ minWidth: 160,
2384
+ sortable: false,
2385
+ filter: false,
2386
+ cellRenderer: (p) => {
2387
+ const doctags = p.data?.doctags ?? [];
2388
+ if (doctags.length === 0) return null;
2389
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1 py-1", children: doctags.map((dt) => /* @__PURE__ */ jsxRuntime.jsx(
2390
+ TagEntity,
2391
+ {
2392
+ size: "sm",
2393
+ tag: {
2394
+ external_id: dt.tag_ext_id,
2395
+ name: tagNameById.get(dt.tag_ext_id) ?? dt.tag_ext_id.slice(0, 8)
2396
+ }
2397
+ },
2398
+ dt.tag_ext_id
2399
+ )) });
2400
+ }
2401
+ },
2402
+ {
2403
+ colId: "file_size",
2404
+ headerName: "Size",
2405
+ width: 110,
2406
+ sortable: true,
2407
+ field: "file_size",
2408
+ valueFormatter: (p) => formatBytes(p.value)
2409
+ },
2410
+ {
2411
+ colId: "folder",
2412
+ headerName: "Folder",
2413
+ flex: 1,
2414
+ minWidth: 140,
2415
+ sortable: true,
2416
+ field: "folder",
2417
+ valueFormatter: (p) => p.value || "\u2014"
2418
+ }
2419
+ ],
2420
+ [openDocument, viewingDocId, tagNameById]
2421
+ );
2422
+ const handleGridReady = (e) => {
2423
+ gridApiRef.current = e.api;
2424
+ applySelection();
2425
+ };
2426
+ const handleSelectionChanged = (e) => {
2427
+ const ids = e.api.getSelectedRows().map((r) => r.external_id).filter((id) => !!id);
2428
+ emitSelection(ids);
2429
+ };
2430
+ const handleRowClicked = (e) => {
2431
+ const id = e.data?.external_id;
2432
+ if (id) openDocument(id);
2433
+ };
2434
+ const getRowId = React__namespace.default.useCallback((params) => params.data.external_id, []);
2435
+ const autoHeight = height === "auto";
2436
+ const style = autoHeight ? {} : { height: typeof height === "number" ? `${height}px` : height, width: "100%" };
2437
+ if (isLoading) {
2438
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-8 text-sm text-muted-foreground", children: "Loading documents\u2026" }) });
2439
+ }
2440
+ if (rows.length === 0) {
2441
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-8 text-sm text-muted-foreground", children: "No documents" }) });
2442
+ }
2443
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children: /* @__PURE__ */ jsxRuntime.jsx(
2444
+ agGridReact.AgGridReact,
2445
+ {
2446
+ columnDefs,
2447
+ rowData: rows,
2448
+ getRowId,
2449
+ rowSelection: "multiple",
2450
+ suppressRowClickSelection: true,
2451
+ domLayout: autoHeight ? "autoHeight" : "normal",
2452
+ rowHeight: 44,
2453
+ onGridReady: handleGridReady,
2454
+ onSelectionChanged: handleSelectionChanged,
2455
+ onRowClicked: handleRowClicked
2456
+ }
2457
+ ) });
2458
+ }
1158
2459
 
1159
2460
  Object.defineProperty(exports, "Arbi", {
1160
2461
  enumerable: true,
@@ -1165,10 +2466,39 @@ Object.defineProperty(exports, "ArbiError", {
1165
2466
  get: function () { return browser.ArbiError; }
1166
2467
  });
1167
2468
  exports.ArbiChat = ArbiChat;
2469
+ exports.ArbiChatPanel = ArbiChatPanel;
1168
2470
  exports.ArbiProvider = ArbiProvider;
2471
+ exports.AudIcon = AudIcon;
2472
+ exports.Avatar = Avatar;
2473
+ exports.AvatarFallback = AvatarFallback;
2474
+ exports.AvatarImage = AvatarImage;
2475
+ exports.Badge = Badge;
2476
+ exports.Button = Button;
2477
+ exports.DocumentEntity = DocumentEntity;
2478
+ exports.DocumentTable = DocumentTable;
2479
+ exports.EmlIcon = EmlIcon;
2480
+ exports.EntityPill = EntityPill;
2481
+ exports.FILE_TYPE_COLORS = FILE_TYPE_COLORS;
2482
+ exports.FileIcon = FileIcon;
2483
+ exports.HoverCard = HoverCard;
2484
+ exports.HoverCardContent = HoverCardContent;
2485
+ exports.HoverCardTrigger = HoverCardTrigger;
2486
+ exports.ImgIcon = ImgIcon;
2487
+ exports.PdfIcon = PdfIcon;
2488
+ exports.ProjectEntity = ProjectEntity;
2489
+ exports.TagEntity = TagEntity;
2490
+ exports.Tooltip = Tooltip;
2491
+ exports.TooltipContent = TooltipContent;
2492
+ exports.TooltipProvider = TooltipProvider;
2493
+ exports.TooltipTrigger = TooltipTrigger;
2494
+ exports.VidIcon = VidIcon;
1169
2495
  exports.arbiQueryKeys = arbiQueryKeys;
2496
+ exports.badgeVariants = badgeVariants;
2497
+ exports.buttonVariants = buttonVariants;
2498
+ exports.cn = cn;
1170
2499
  exports.useAgents = useAgents;
1171
2500
  exports.useArbi = useArbi;
2501
+ exports.useArbiUiStore = useArbiUiStore;
1172
2502
  exports.useAssistantQuery = useAssistantQuery;
1173
2503
  exports.useConversations = useConversations;
1174
2504
  exports.useDeleteAgents = useDeleteAgents;