@arbidocs/react 0.3.174 → 0.3.176

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.js CHANGED
@@ -1,13 +1,13 @@
1
- import { useArbi, ArbiProvider, AudioViewer } from './chunk-Q6XAXIT3.js';
2
- export { ArbiProvider, useArbi } from './chunk-Q6XAXIT3.js';
3
- import { cn, Avatar, AvatarFallback, AvatarImage, Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverTrigger, PopoverContent, AiMarkdown, Card, Button, Badge, MarkdownRenderer, Input, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, ScrollArea, DropdownMenuItem, Textarea, Slider, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DropdownMenuLabel, DropdownMenuSeparator, Checkbox, useAudioRecorder, MicWaveformIndicator, IconToggle } from './chunk-QZAXTBVW.js';
4
- export { AiMarkdown, Avatar, AvatarFallback, AvatarImage, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, InlineMicButton, Input, Label, MarkdownRenderer, MarkdownStreamingContext, MicRecordingOverlay, MicWaveformIndicator, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cardVariants, cn, formatElapsed, markdownBaseComponents, splitMarkdownBlocks, toggleVariants, useAudioRecorder } from './chunk-QZAXTBVW.js';
1
+ import { cn, Avatar, AvatarFallback, AvatarImage, Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverTrigger, PopoverContent, AiMarkdown, Card, Button, Badge, MarkdownRenderer, Input, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, ScrollArea, Textarea, Slider, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DropdownMenuLabel, DropdownMenuSeparator, Checkbox, useAudioRecorder, MicWaveformIndicator, IconToggle, classifyMediaError, formatElapsed } from './chunk-I256BUCX.js';
2
+ export { AiMarkdown, Avatar, AvatarFallback, AvatarImage, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DictateProvider, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, HoverCard, HoverCardContent, HoverCardTrigger, IconToggle, InlineMicButton, Input, Label, MarkdownRenderer, MarkdownStreamingContext, MicRecordingOverlay, MicWaveformIndicator, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Slider, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cardVariants, cn, formatElapsed, markdownBaseComponents, splitMarkdownBlocks, toggleVariants, useAudioRecorder } from './chunk-I256BUCX.js';
3
+ import { useArbi, ArbiProvider, AudioViewer, ImageViewer, VideoViewer } from './chunk-JKO3NR5L.js';
4
+ export { ArbiProvider, useArbi } from './chunk-JKO3NR5L.js';
5
5
  import React2, { memo, useState, createContext, forwardRef, useMemo, useCallback, useId, useRef, useContext, useEffect, Fragment as Fragment$1 } from 'react';
6
6
  import { useQuery, useMutation, useQueries, QueryClient, QueryClientProvider, useQueryClient } from '@tanstack/react-query';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { connectWithReconnect, resolveCitations, summarizeCitations } from '@arbidocs/sdk/browser';
9
9
  export { Arbi, ArbiError } from '@arbidocs/sdk/browser';
10
- import { Link, Trash2, CheckCheck, Check, MessageCircleMore, MoreVertical, MessageSquareLock, Info, FileQuestion, BookOpen, Upload, LogOut, LayoutGrid, Bell, MessageSquare, CircleUserRound, Wrench, CreditCard, ClipboardList, UserPlus, UserStar, Settings2, Users, User, NotebookPen, NotebookText, StickyNote, FolderPlus, Hash, EyeOff, Eye, CaptionsOff, FolderOpen, MessageSquareMore, MessageSquarePlus, MessageSquareText, MessageSquareOff, MessagesSquare, Columns3Cog, SquarePlus, SquareM, ChevronsDown, Bot, Calendar, Search, Folder, List, SquareCheckBig, Loader2, AlertTriangle, ShieldCheck, Copy, Sparkles, FileText, GitCompareArrows, Download, Image as Image$1, CornerDownLeft, X, ArrowLeft, Send, Tags, Crown, Activity, Gauge, Gift, PartyPopper, UserCheck, FileX2, FileCheck2, Pencil, SquareArrowOutUpRight, BellOff, XCircle, CheckCircle2, ArrowRight, ChevronDown, MoreHorizontal, SquarePen, Mic, Pause, Play, Square, RotateCcw, FileX, SkipForward, CheckCircle } from 'lucide-react';
10
+ import { Link, Trash2, CheckCheck, Check, MessageCircleMore, MoreVertical, MessageSquareLock, Info, FileQuestion, BookOpen, Upload, LogOut, LayoutGrid, Bell, MessageSquare, CircleUserRound, Wrench, CreditCard, ClipboardList, UserPlus, UserStar, Settings2, Users, User, NotebookPen, NotebookText, StickyNote, FolderPlus, Hash, EyeOff, Eye, CaptionsOff, FolderOpen, MessageSquareMore, MessageSquarePlus, MessageSquareText, MessageSquareOff, MessagesSquare, Columns3Cog, SquarePlus, SquareM, ChevronsDown, Bot, Calendar, Search, Folder, List, SquareCheckBig, Loader2, AlertTriangle, ShieldCheck, Copy, Sparkles, FileText, GitCompareArrows, Download, Image as Image$1, CornerDownLeft, X, ArrowLeft, Send, Tags, Crown, Activity, Gauge, Gift, PartyPopper, UserCheck, FileX2, FileCheck2, Pencil, SquareArrowOutUpRight, BellOff, XCircle, CheckCircle2, ArrowRight, ChevronDown, MoreHorizontal, SquarePen, Mic, Pause, Play, Square, RotateCcw, Camera, Circle, FileX, SkipForward, CheckCircle } from 'lucide-react';
11
11
  import { isMessageType } from '@arbidocs/client';
12
12
  export { isMessageType } from '@arbidocs/client';
13
13
  import { create } from 'zustand';
@@ -5394,6 +5394,15 @@ function NotificationBell({
5394
5394
  "data-testid": `${testId}-mute`,
5395
5395
  children: /* @__PURE__ */ jsx(BellOff, { className: "size-3.5" })
5396
5396
  }
5397
+ ),
5398
+ /* @__PURE__ */ jsx(
5399
+ DropdownMenuItem,
5400
+ {
5401
+ className: "flex size-6 items-center justify-center rounded-md p-0 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus:bg-accent",
5402
+ "aria-label": "Close notifications",
5403
+ "data-testid": `${testId}-close`,
5404
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
5405
+ }
5397
5406
  )
5398
5407
  ] })
5399
5408
  ] }),
@@ -6469,8 +6478,18 @@ function UserMenu({
6469
6478
  sideOffset: 8,
6470
6479
  collisionPadding: 12,
6471
6480
  className: "w-56 rounded-lg border-border/60 shadow-lg",
6481
+ "data-testid": "user-menu-panel",
6472
6482
  children: [
6473
- /* @__PURE__ */ jsxs(DropdownMenuLabel, { children: [
6483
+ /* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "relative pr-8", children: [
6484
+ /* @__PURE__ */ jsx(
6485
+ DropdownMenuItem,
6486
+ {
6487
+ className: "absolute right-1 top-1 flex size-6 items-center justify-center rounded-md p-0 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus:bg-accent",
6488
+ "aria-label": "Close account menu",
6489
+ "data-testid": "user-menu-close",
6490
+ children: /* @__PURE__ */ jsx(X, { className: "size-3.5" })
6491
+ }
6492
+ ),
6474
6493
  /* @__PURE__ */ jsx("div", { className: "font-medium text-foreground", children: user.name }),
6475
6494
  user.email && /* @__PURE__ */ jsx("div", { className: "text-xs font-normal text-muted-foreground", children: user.email }),
6476
6495
  status && /* @__PURE__ */ jsxs(
@@ -7349,6 +7368,337 @@ function DraftTitleControls({
7349
7368
  )
7350
7369
  ] });
7351
7370
  }
7371
+ function useCameraStream(constraints = { video: true, audio: false }) {
7372
+ const [stream, setStream] = useState(null);
7373
+ const [isStarting, setIsStarting] = useState(false);
7374
+ const [error, setError] = useState(null);
7375
+ const streamRef = useRef(null);
7376
+ const stop = useCallback(() => {
7377
+ streamRef.current?.getTracks().forEach((t) => t.stop());
7378
+ streamRef.current = null;
7379
+ setStream(null);
7380
+ }, []);
7381
+ const constraintsRef = useRef(constraints);
7382
+ constraintsRef.current = constraints;
7383
+ const start = useCallback(async () => {
7384
+ if (streamRef.current) return;
7385
+ setError(null);
7386
+ setIsStarting(true);
7387
+ try {
7388
+ const media = await navigator.mediaDevices.getUserMedia(constraintsRef.current);
7389
+ streamRef.current = media;
7390
+ setStream(media);
7391
+ } catch (err) {
7392
+ setError(classifyMediaError(err, "camera"));
7393
+ } finally {
7394
+ setIsStarting(false);
7395
+ }
7396
+ }, []);
7397
+ useEffect(() => () => stop(), [stop]);
7398
+ return { stream, isStarting, error, start, stop };
7399
+ }
7400
+ var ELAPSED_TICK_MS = 200;
7401
+ function useVideoRecorder(stream) {
7402
+ const [state, setState] = useState("idle");
7403
+ const [elapsedMs, setElapsedMs] = useState(0);
7404
+ const [blob, setBlob] = useState(null);
7405
+ const [mimeType, setMimeType] = useState(null);
7406
+ const mediaRecorderRef = useRef(null);
7407
+ const chunksRef = useRef([]);
7408
+ const startedAtRef = useRef(0);
7409
+ const tickRef = useRef(null);
7410
+ const stateRef = useRef("idle");
7411
+ stateRef.current = state;
7412
+ const stopTicking = useCallback(() => {
7413
+ if (tickRef.current !== null) clearInterval(tickRef.current);
7414
+ tickRef.current = null;
7415
+ }, []);
7416
+ useEffect(() => stopTicking, [stopTicking]);
7417
+ const start = useCallback(() => {
7418
+ if (!stream || stateRef.current === "recording") return;
7419
+ const mt = MediaRecorder.isTypeSupported("video/webm") ? "video/webm" : "video/mp4";
7420
+ const recorder = new MediaRecorder(stream, { mimeType: mt });
7421
+ chunksRef.current = [];
7422
+ recorder.ondataavailable = (e) => {
7423
+ if (e.data.size > 0) chunksRef.current.push(e.data);
7424
+ };
7425
+ mediaRecorderRef.current = recorder;
7426
+ setMimeType(mt);
7427
+ setBlob(null);
7428
+ startedAtRef.current = performance.now();
7429
+ setElapsedMs(0);
7430
+ recorder.start();
7431
+ setState("recording");
7432
+ tickRef.current = setInterval(() => {
7433
+ setElapsedMs(performance.now() - startedAtRef.current);
7434
+ }, ELAPSED_TICK_MS);
7435
+ }, [stream]);
7436
+ const stop = useCallback(() => {
7437
+ const recorder = mediaRecorderRef.current;
7438
+ if (!recorder || recorder.state === "inactive") return;
7439
+ const finalElapsed = performance.now() - startedAtRef.current;
7440
+ stopTicking();
7441
+ recorder.onstop = () => {
7442
+ const finalBlob = chunksRef.current.length ? new Blob(chunksRef.current, { type: recorder.mimeType }) : null;
7443
+ setBlob(finalBlob);
7444
+ setElapsedMs(finalElapsed);
7445
+ setState("stopped");
7446
+ };
7447
+ recorder.stop();
7448
+ }, [stopTicking]);
7449
+ const reset = useCallback(() => {
7450
+ setState("idle");
7451
+ setBlob(null);
7452
+ setElapsedMs(0);
7453
+ setMimeType(null);
7454
+ }, []);
7455
+ return { state, elapsedMs, blob, mimeType, start, stop, reset };
7456
+ }
7457
+
7458
+ // src/documents/capture-frame.ts
7459
+ function captureFrameAsBlob(video, mimeType = "image/png") {
7460
+ return new Promise((resolve, reject) => {
7461
+ const canvas = document.createElement("canvas");
7462
+ canvas.width = video.videoWidth;
7463
+ canvas.height = video.videoHeight;
7464
+ const ctx = canvas.getContext("2d");
7465
+ if (!ctx) {
7466
+ reject(new Error("Canvas 2D context is not available"));
7467
+ return;
7468
+ }
7469
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
7470
+ canvas.toBlob((blob) => {
7471
+ if (blob) resolve(blob);
7472
+ else reject(new Error("Failed to capture the photo"));
7473
+ }, mimeType);
7474
+ });
7475
+ }
7476
+ function PhotoCapture({ onSave, onDiscard, onError, isSaving = false }) {
7477
+ const camera = useCameraStream({ video: true, audio: false });
7478
+ const videoRef = useRef(null);
7479
+ const [capturedBlob, setCapturedBlob] = useState(null);
7480
+ const [captureError, setCaptureError] = useState(null);
7481
+ useEffect(() => {
7482
+ void camera.start();
7483
+ }, []);
7484
+ useEffect(() => {
7485
+ if (camera.error) onError?.(camera.error);
7486
+ }, [camera.error]);
7487
+ useEffect(() => {
7488
+ const video = videoRef.current;
7489
+ if (!video) return;
7490
+ video.srcObject = camera.stream;
7491
+ if (camera.stream) void video.play().catch(() => {
7492
+ });
7493
+ }, [camera.stream]);
7494
+ const handleShutter = () => {
7495
+ const video = videoRef.current;
7496
+ if (!video) return;
7497
+ setCaptureError(null);
7498
+ captureFrameAsBlob(video).then(setCapturedBlob).catch((err) => {
7499
+ const message = err instanceof Error ? err.message : "Failed to capture the photo";
7500
+ setCaptureError(message);
7501
+ onError?.(message);
7502
+ });
7503
+ };
7504
+ const handleRetake = () => setCapturedBlob(null);
7505
+ const handleSave = () => {
7506
+ if (!capturedBlob) return;
7507
+ void onSave(capturedBlob, "image/png");
7508
+ };
7509
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6 p-8", children: [
7510
+ !capturedBlob && /* @__PURE__ */ jsxs(Fragment, { children: [
7511
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md overflow-hidden rounded-lg bg-muted/30", children: /* @__PURE__ */ jsx(
7512
+ "video",
7513
+ {
7514
+ ref: videoRef,
7515
+ autoPlay: true,
7516
+ muted: true,
7517
+ playsInline: true,
7518
+ className: "w-full max-h-[60vh] object-contain",
7519
+ "data-testid": "photo-capture-preview"
7520
+ }
7521
+ ) }),
7522
+ /* @__PURE__ */ jsx(
7523
+ Button,
7524
+ {
7525
+ type: "button",
7526
+ size: "lg",
7527
+ className: "h-16 w-16 rounded-full p-0",
7528
+ onClick: handleShutter,
7529
+ disabled: !camera.stream,
7530
+ "data-testid": "photo-capture-shutter-button",
7531
+ children: /* @__PURE__ */ jsx(Camera, { className: "h-6 w-6" })
7532
+ }
7533
+ ),
7534
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: camera.isStarting ? "Starting camera\u2026" : camera.stream ? "Press to take a photo" : "Waiting for camera access\u2026" }),
7535
+ captureError && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-text", children: captureError })
7536
+ ] }),
7537
+ capturedBlob && /* @__PURE__ */ jsxs(Fragment, { children: [
7538
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx(ImageViewer, { blob: capturedBlob, alt: "Captured photo" }) }),
7539
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7540
+ /* @__PURE__ */ jsxs(
7541
+ Button,
7542
+ {
7543
+ type: "button",
7544
+ variant: "outline",
7545
+ onClick: onDiscard,
7546
+ disabled: isSaving,
7547
+ "data-testid": "photo-capture-discard-button",
7548
+ children: [
7549
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-4 w-4" }),
7550
+ "Discard"
7551
+ ]
7552
+ }
7553
+ ),
7554
+ /* @__PURE__ */ jsxs(
7555
+ Button,
7556
+ {
7557
+ type: "button",
7558
+ variant: "outline",
7559
+ onClick: handleRetake,
7560
+ disabled: isSaving,
7561
+ "data-testid": "photo-capture-retake-button",
7562
+ children: [
7563
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-1.5 h-4 w-4" }),
7564
+ "Retake"
7565
+ ]
7566
+ }
7567
+ ),
7568
+ /* @__PURE__ */ jsxs(
7569
+ Button,
7570
+ {
7571
+ type: "button",
7572
+ onClick: handleSave,
7573
+ disabled: isSaving,
7574
+ "data-testid": "photo-capture-save-button",
7575
+ children: [
7576
+ isSaving ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Check, { className: "mr-1.5 h-4 w-4" }),
7577
+ isSaving ? "Saving\u2026" : "Save"
7578
+ ]
7579
+ }
7580
+ )
7581
+ ] })
7582
+ ] })
7583
+ ] });
7584
+ }
7585
+ function VideoCapture({ onSave, onDiscard, onError, isSaving = false }) {
7586
+ const camera = useCameraStream({ video: true, audio: true });
7587
+ const recorder = useVideoRecorder(camera.stream);
7588
+ const videoRef = useRef(null);
7589
+ useEffect(() => {
7590
+ void camera.start();
7591
+ }, []);
7592
+ useEffect(() => {
7593
+ if (camera.error) onError?.(camera.error);
7594
+ }, [camera.error]);
7595
+ useEffect(() => {
7596
+ const video = videoRef.current;
7597
+ if (!video || recorder.state === "stopped") return;
7598
+ video.srcObject = camera.stream;
7599
+ if (camera.stream) void video.play().catch(() => {
7600
+ });
7601
+ }, [camera.stream, recorder.state]);
7602
+ const handleRetake = () => {
7603
+ recorder.reset();
7604
+ };
7605
+ const handleSave = () => {
7606
+ if (!recorder.blob) return;
7607
+ void onSave(recorder.blob, recorder.mimeType);
7608
+ };
7609
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6 p-8", children: [
7610
+ recorder.state !== "stopped" && /* @__PURE__ */ jsxs(Fragment, { children: [
7611
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md overflow-hidden rounded-lg bg-muted/30", children: /* @__PURE__ */ jsx(
7612
+ "video",
7613
+ {
7614
+ ref: videoRef,
7615
+ autoPlay: true,
7616
+ muted: true,
7617
+ playsInline: true,
7618
+ className: "w-full max-h-[60vh] object-contain",
7619
+ "data-testid": "video-capture-preview"
7620
+ }
7621
+ ) }),
7622
+ recorder.state === "recording" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", "data-testid": "video-capture-rec-indicator", children: [
7623
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
7624
+ /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75" }),
7625
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-red-500" })
7626
+ ] }),
7627
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-red-500", children: "Rec" }),
7628
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs tabular-nums text-muted-foreground", children: formatElapsed(recorder.elapsedMs) })
7629
+ ] }),
7630
+ recorder.state === "recording" ? /* @__PURE__ */ jsx(
7631
+ Button,
7632
+ {
7633
+ type: "button",
7634
+ size: "lg",
7635
+ className: "h-16 w-16 rounded-full p-0",
7636
+ onClick: recorder.stop,
7637
+ "data-testid": "video-capture-stop-button",
7638
+ children: /* @__PURE__ */ jsx(Square, { className: "h-5 w-5 fill-current" })
7639
+ }
7640
+ ) : /* @__PURE__ */ jsx(
7641
+ Button,
7642
+ {
7643
+ type: "button",
7644
+ size: "lg",
7645
+ className: "h-16 w-16 rounded-full p-0",
7646
+ onClick: recorder.start,
7647
+ disabled: !camera.stream,
7648
+ "data-testid": "video-capture-record-button",
7649
+ children: /* @__PURE__ */ jsx(Circle, { className: "h-6 w-6 fill-current" })
7650
+ }
7651
+ ),
7652
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: recorder.state === "recording" ? "Tap to stop recording" : camera.isStarting ? "Starting camera\u2026" : camera.stream ? "Tap to start recording" : "Waiting for camera access\u2026" })
7653
+ ] }),
7654
+ recorder.state === "stopped" && recorder.blob && /* @__PURE__ */ jsxs(Fragment, { children: [
7655
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx(VideoViewer, { blob: recorder.blob, title: "Captured video" }) }),
7656
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7657
+ /* @__PURE__ */ jsxs(
7658
+ Button,
7659
+ {
7660
+ type: "button",
7661
+ variant: "outline",
7662
+ onClick: onDiscard,
7663
+ disabled: isSaving,
7664
+ "data-testid": "video-capture-discard-button",
7665
+ children: [
7666
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-4 w-4" }),
7667
+ "Discard"
7668
+ ]
7669
+ }
7670
+ ),
7671
+ /* @__PURE__ */ jsxs(
7672
+ Button,
7673
+ {
7674
+ type: "button",
7675
+ variant: "outline",
7676
+ onClick: handleRetake,
7677
+ disabled: isSaving,
7678
+ "data-testid": "video-capture-retake-button",
7679
+ children: [
7680
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-1.5 h-4 w-4" }),
7681
+ "Record again"
7682
+ ]
7683
+ }
7684
+ ),
7685
+ /* @__PURE__ */ jsxs(
7686
+ Button,
7687
+ {
7688
+ type: "button",
7689
+ onClick: handleSave,
7690
+ disabled: isSaving,
7691
+ "data-testid": "video-capture-save-button",
7692
+ children: [
7693
+ isSaving ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Check, { className: "mr-1.5 h-4 w-4" }),
7694
+ isSaving ? "Saving\u2026" : "Save"
7695
+ ]
7696
+ }
7697
+ )
7698
+ ] })
7699
+ ] })
7700
+ ] });
7701
+ }
7352
7702
 
7353
7703
  // src/documents/has-video-track.ts
7354
7704
  function hasVideoTrack(blob) {
@@ -7374,6 +7724,6 @@ function hasVideoTrack(blob) {
7374
7724
  });
7375
7725
  }
7376
7726
 
7377
- export { ActivityFeed, AgentBadge, AiActionCard, AiAnswer, AppleIcon, ArbiBotHeadIcon, ArbiBotIcon, ArbiChat, ArbiChatPanel, ArbiIcon, ArbiWebSocketProvider, ArtifactCanvas, AudIcon, BASE_COLORS2 as BASE_COLORS, ChatBubble, CitationRenderer, ClaudeIcon, CommandPalette, CommandPaletteProvider, ConversationList, DEFAULT_ASPECT_OPTIONS, DEFAULT_NOTIFY_TONE, DateSeparator, DirectMessages, DmAvatar, DmComposer, DocIcon, DocQaPanel, DocSearch, DocumentCard, DocumentCardMenu, DocumentEntity, DocumentGallery, DocumentReview, DocumentTable, DraftTitleControls, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, FileIcon, FireworksIcon, GeminiIcon, GitHubIcon, GoogleIcon, HtmlIcon, ImageCropModal, ImageCropper, ImgIcon, LinkedInIcon, MessageArtifactCard, MessageBubble2 as MessageBubble, MessageThread, NEUTRAL_GRAY2 as NEUTRAL_GRAY, NotificationBell, OpenAIIcon, PLACEHOLDER_COLOR, PassageCard, PdfIcon, PresenceLabel, ProjectEntity, ProviderIcon, RUN_WINDOW_MS, RagDot, RelevanceDot, SemanticSearch, StatusPill, TAG_TYPE_ICONS, TAG_TYPE_LABELS, TagEntity, Toaster, TxtIcon, TypingIndicator, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VisibilityIcon, VoiceNoteRecorder, XlsIcon, annotateThread, arbiQueryKeys, configureEntityRegistry, configureRagLabels, configureStatusRegistry, cropImage, dayKey, describeActivity, formatRelativeTime, getDocIcon, getEntityColor2 as getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getNotificationTypeMeta, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceActionText, getWorkspaceColor, getWorkspaceSentPhrase, hasVideoTrack, isWorkspaceNotificationType, notify, parseActivityContent, redlineStats, seedNotifications, selectUnread, textToArtifact, toRedlineMarkdown, useActivity, useAgents, useAiTask, useArbiConnected, useArbiDocumentSync, useArbiUiStore, useArbiWebSocket, useArbiWsContext, useArbiWsMessage, useArbiWsStatus, useArbiWsStore, useArbiWsTask, useArbiWsTasks, useAssistantQuery, useCommandPalette, useConfigs, useConversations, useDeleteAgents, useDirectMessages, useDocuments, useFacts, useHealth, useNotify, useParsedDocument, useProjectInvoices, useProjectUsage, useProjects, useProjectsUsage, useSemanticSearch, useSessions, useTags, useTasks, useThumbnails, useUserUsageToday, useWorkspaceDocs, useWorkspaces, userDisplayName, userInitials };
7727
+ export { ActivityFeed, AgentBadge, AiActionCard, AiAnswer, AppleIcon, ArbiBotHeadIcon, ArbiBotIcon, ArbiChat, ArbiChatPanel, ArbiIcon, ArbiWebSocketProvider, ArtifactCanvas, AudIcon, BASE_COLORS2 as BASE_COLORS, ChatBubble, CitationRenderer, ClaudeIcon, CommandPalette, CommandPaletteProvider, ConversationList, DEFAULT_ASPECT_OPTIONS, DEFAULT_NOTIFY_TONE, DateSeparator, DirectMessages, DmAvatar, DmComposer, DocIcon, DocQaPanel, DocSearch, DocumentCard, DocumentCardMenu, DocumentEntity, DocumentGallery, DocumentReview, DocumentTable, DraftTitleControls, ENTITY_MAPPINGS, EmlIcon, EntityIcon, EntityPill, FILE_TYPE_COLORS, FileIcon, FireworksIcon, GeminiIcon, GitHubIcon, GoogleIcon, HtmlIcon, ImageCropModal, ImageCropper, ImgIcon, LinkedInIcon, MessageArtifactCard, MessageBubble2 as MessageBubble, MessageThread, NEUTRAL_GRAY2 as NEUTRAL_GRAY, NotificationBell, OpenAIIcon, PLACEHOLDER_COLOR, PassageCard, PdfIcon, PhotoCapture, PresenceLabel, ProjectEntity, ProviderIcon, RUN_WINDOW_MS, RagDot, RelevanceDot, SemanticSearch, StatusPill, TAG_TYPE_ICONS, TAG_TYPE_LABELS, TagEntity, Toaster, TxtIcon, TypingIndicator, UserEntity, UserMenu, VISIBILITY_ICONS, VidIcon, VideoCapture, VisibilityIcon, VoiceNoteRecorder, XlsIcon, annotateThread, arbiQueryKeys, captureFrameAsBlob, configureEntityRegistry, configureRagLabels, configureStatusRegistry, cropImage, dayKey, describeActivity, formatRelativeTime, getDocIcon, getEntityColor2 as getEntityColor, getEntityColorStyles, getEntityIcon, getEntityLabel, getNotificationTypeMeta, getStatusVariant, getTagTypeIcon, getTagTypeLabel, getWorkspaceActionText, getWorkspaceColor, getWorkspaceSentPhrase, hasVideoTrack, isWorkspaceNotificationType, notify, parseActivityContent, redlineStats, seedNotifications, selectUnread, textToArtifact, toRedlineMarkdown, useActivity, useAgents, useAiTask, useArbiConnected, useArbiDocumentSync, useArbiUiStore, useArbiWebSocket, useArbiWsContext, useArbiWsMessage, useArbiWsStatus, useArbiWsStore, useArbiWsTask, useArbiWsTasks, useAssistantQuery, useCameraStream, useCommandPalette, useConfigs, useConversations, useDeleteAgents, useDirectMessages, useDocuments, useFacts, useHealth, useNotify, useParsedDocument, useProjectInvoices, useProjectUsage, useProjects, useProjectsUsage, useSemanticSearch, useSessions, useTags, useTasks, useThumbnails, useUserUsageToday, useVideoRecorder, useWorkspaceDocs, useWorkspaces, userDisplayName, userInitials };
7378
7728
  //# sourceMappingURL=index.js.map
7379
7729
  //# sourceMappingURL=index.js.map