@arbidocs/react 0.3.174 → 0.3.175

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, ScrollArea, DropdownMenuItem, 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';
@@ -7349,6 +7349,337 @@ function DraftTitleControls({
7349
7349
  )
7350
7350
  ] });
7351
7351
  }
7352
+ function useCameraStream(constraints = { video: true, audio: false }) {
7353
+ const [stream, setStream] = useState(null);
7354
+ const [isStarting, setIsStarting] = useState(false);
7355
+ const [error, setError] = useState(null);
7356
+ const streamRef = useRef(null);
7357
+ const stop = useCallback(() => {
7358
+ streamRef.current?.getTracks().forEach((t) => t.stop());
7359
+ streamRef.current = null;
7360
+ setStream(null);
7361
+ }, []);
7362
+ const constraintsRef = useRef(constraints);
7363
+ constraintsRef.current = constraints;
7364
+ const start = useCallback(async () => {
7365
+ if (streamRef.current) return;
7366
+ setError(null);
7367
+ setIsStarting(true);
7368
+ try {
7369
+ const media = await navigator.mediaDevices.getUserMedia(constraintsRef.current);
7370
+ streamRef.current = media;
7371
+ setStream(media);
7372
+ } catch (err) {
7373
+ setError(classifyMediaError(err, "camera"));
7374
+ } finally {
7375
+ setIsStarting(false);
7376
+ }
7377
+ }, []);
7378
+ useEffect(() => () => stop(), [stop]);
7379
+ return { stream, isStarting, error, start, stop };
7380
+ }
7381
+ var ELAPSED_TICK_MS = 200;
7382
+ function useVideoRecorder(stream) {
7383
+ const [state, setState] = useState("idle");
7384
+ const [elapsedMs, setElapsedMs] = useState(0);
7385
+ const [blob, setBlob] = useState(null);
7386
+ const [mimeType, setMimeType] = useState(null);
7387
+ const mediaRecorderRef = useRef(null);
7388
+ const chunksRef = useRef([]);
7389
+ const startedAtRef = useRef(0);
7390
+ const tickRef = useRef(null);
7391
+ const stateRef = useRef("idle");
7392
+ stateRef.current = state;
7393
+ const stopTicking = useCallback(() => {
7394
+ if (tickRef.current !== null) clearInterval(tickRef.current);
7395
+ tickRef.current = null;
7396
+ }, []);
7397
+ useEffect(() => stopTicking, [stopTicking]);
7398
+ const start = useCallback(() => {
7399
+ if (!stream || stateRef.current === "recording") return;
7400
+ const mt = MediaRecorder.isTypeSupported("video/webm") ? "video/webm" : "video/mp4";
7401
+ const recorder = new MediaRecorder(stream, { mimeType: mt });
7402
+ chunksRef.current = [];
7403
+ recorder.ondataavailable = (e) => {
7404
+ if (e.data.size > 0) chunksRef.current.push(e.data);
7405
+ };
7406
+ mediaRecorderRef.current = recorder;
7407
+ setMimeType(mt);
7408
+ setBlob(null);
7409
+ startedAtRef.current = performance.now();
7410
+ setElapsedMs(0);
7411
+ recorder.start();
7412
+ setState("recording");
7413
+ tickRef.current = setInterval(() => {
7414
+ setElapsedMs(performance.now() - startedAtRef.current);
7415
+ }, ELAPSED_TICK_MS);
7416
+ }, [stream]);
7417
+ const stop = useCallback(() => {
7418
+ const recorder = mediaRecorderRef.current;
7419
+ if (!recorder || recorder.state === "inactive") return;
7420
+ const finalElapsed = performance.now() - startedAtRef.current;
7421
+ stopTicking();
7422
+ recorder.onstop = () => {
7423
+ const finalBlob = chunksRef.current.length ? new Blob(chunksRef.current, { type: recorder.mimeType }) : null;
7424
+ setBlob(finalBlob);
7425
+ setElapsedMs(finalElapsed);
7426
+ setState("stopped");
7427
+ };
7428
+ recorder.stop();
7429
+ }, [stopTicking]);
7430
+ const reset = useCallback(() => {
7431
+ setState("idle");
7432
+ setBlob(null);
7433
+ setElapsedMs(0);
7434
+ setMimeType(null);
7435
+ }, []);
7436
+ return { state, elapsedMs, blob, mimeType, start, stop, reset };
7437
+ }
7438
+
7439
+ // src/documents/capture-frame.ts
7440
+ function captureFrameAsBlob(video, mimeType = "image/png") {
7441
+ return new Promise((resolve, reject) => {
7442
+ const canvas = document.createElement("canvas");
7443
+ canvas.width = video.videoWidth;
7444
+ canvas.height = video.videoHeight;
7445
+ const ctx = canvas.getContext("2d");
7446
+ if (!ctx) {
7447
+ reject(new Error("Canvas 2D context is not available"));
7448
+ return;
7449
+ }
7450
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
7451
+ canvas.toBlob((blob) => {
7452
+ if (blob) resolve(blob);
7453
+ else reject(new Error("Failed to capture the photo"));
7454
+ }, mimeType);
7455
+ });
7456
+ }
7457
+ function PhotoCapture({ onSave, onDiscard, onError, isSaving = false }) {
7458
+ const camera = useCameraStream({ video: true, audio: false });
7459
+ const videoRef = useRef(null);
7460
+ const [capturedBlob, setCapturedBlob] = useState(null);
7461
+ const [captureError, setCaptureError] = useState(null);
7462
+ useEffect(() => {
7463
+ void camera.start();
7464
+ }, []);
7465
+ useEffect(() => {
7466
+ if (camera.error) onError?.(camera.error);
7467
+ }, [camera.error]);
7468
+ useEffect(() => {
7469
+ const video = videoRef.current;
7470
+ if (!video) return;
7471
+ video.srcObject = camera.stream;
7472
+ if (camera.stream) void video.play().catch(() => {
7473
+ });
7474
+ }, [camera.stream]);
7475
+ const handleShutter = () => {
7476
+ const video = videoRef.current;
7477
+ if (!video) return;
7478
+ setCaptureError(null);
7479
+ captureFrameAsBlob(video).then(setCapturedBlob).catch((err) => {
7480
+ const message = err instanceof Error ? err.message : "Failed to capture the photo";
7481
+ setCaptureError(message);
7482
+ onError?.(message);
7483
+ });
7484
+ };
7485
+ const handleRetake = () => setCapturedBlob(null);
7486
+ const handleSave = () => {
7487
+ if (!capturedBlob) return;
7488
+ void onSave(capturedBlob, "image/png");
7489
+ };
7490
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6 p-8", children: [
7491
+ !capturedBlob && /* @__PURE__ */ jsxs(Fragment, { children: [
7492
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md overflow-hidden rounded-lg bg-muted/30", children: /* @__PURE__ */ jsx(
7493
+ "video",
7494
+ {
7495
+ ref: videoRef,
7496
+ autoPlay: true,
7497
+ muted: true,
7498
+ playsInline: true,
7499
+ className: "w-full max-h-[60vh] object-contain",
7500
+ "data-testid": "photo-capture-preview"
7501
+ }
7502
+ ) }),
7503
+ /* @__PURE__ */ jsx(
7504
+ Button,
7505
+ {
7506
+ type: "button",
7507
+ size: "lg",
7508
+ className: "h-16 w-16 rounded-full p-0",
7509
+ onClick: handleShutter,
7510
+ disabled: !camera.stream,
7511
+ "data-testid": "photo-capture-shutter-button",
7512
+ children: /* @__PURE__ */ jsx(Camera, { className: "h-6 w-6" })
7513
+ }
7514
+ ),
7515
+ /* @__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" }),
7516
+ captureError && /* @__PURE__ */ jsx("p", { className: "text-sm text-red-text", children: captureError })
7517
+ ] }),
7518
+ capturedBlob && /* @__PURE__ */ jsxs(Fragment, { children: [
7519
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx(ImageViewer, { blob: capturedBlob, alt: "Captured photo" }) }),
7520
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7521
+ /* @__PURE__ */ jsxs(
7522
+ Button,
7523
+ {
7524
+ type: "button",
7525
+ variant: "outline",
7526
+ onClick: onDiscard,
7527
+ disabled: isSaving,
7528
+ "data-testid": "photo-capture-discard-button",
7529
+ children: [
7530
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-4 w-4" }),
7531
+ "Discard"
7532
+ ]
7533
+ }
7534
+ ),
7535
+ /* @__PURE__ */ jsxs(
7536
+ Button,
7537
+ {
7538
+ type: "button",
7539
+ variant: "outline",
7540
+ onClick: handleRetake,
7541
+ disabled: isSaving,
7542
+ "data-testid": "photo-capture-retake-button",
7543
+ children: [
7544
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-1.5 h-4 w-4" }),
7545
+ "Retake"
7546
+ ]
7547
+ }
7548
+ ),
7549
+ /* @__PURE__ */ jsxs(
7550
+ Button,
7551
+ {
7552
+ type: "button",
7553
+ onClick: handleSave,
7554
+ disabled: isSaving,
7555
+ "data-testid": "photo-capture-save-button",
7556
+ children: [
7557
+ 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" }),
7558
+ isSaving ? "Saving\u2026" : "Save"
7559
+ ]
7560
+ }
7561
+ )
7562
+ ] })
7563
+ ] })
7564
+ ] });
7565
+ }
7566
+ function VideoCapture({ onSave, onDiscard, onError, isSaving = false }) {
7567
+ const camera = useCameraStream({ video: true, audio: true });
7568
+ const recorder = useVideoRecorder(camera.stream);
7569
+ const videoRef = useRef(null);
7570
+ useEffect(() => {
7571
+ void camera.start();
7572
+ }, []);
7573
+ useEffect(() => {
7574
+ if (camera.error) onError?.(camera.error);
7575
+ }, [camera.error]);
7576
+ useEffect(() => {
7577
+ const video = videoRef.current;
7578
+ if (!video || recorder.state === "stopped") return;
7579
+ video.srcObject = camera.stream;
7580
+ if (camera.stream) void video.play().catch(() => {
7581
+ });
7582
+ }, [camera.stream, recorder.state]);
7583
+ const handleRetake = () => {
7584
+ recorder.reset();
7585
+ };
7586
+ const handleSave = () => {
7587
+ if (!recorder.blob) return;
7588
+ void onSave(recorder.blob, recorder.mimeType);
7589
+ };
7590
+ return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-6 p-8", children: [
7591
+ recorder.state !== "stopped" && /* @__PURE__ */ jsxs(Fragment, { children: [
7592
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md overflow-hidden rounded-lg bg-muted/30", children: /* @__PURE__ */ jsx(
7593
+ "video",
7594
+ {
7595
+ ref: videoRef,
7596
+ autoPlay: true,
7597
+ muted: true,
7598
+ playsInline: true,
7599
+ className: "w-full max-h-[60vh] object-contain",
7600
+ "data-testid": "video-capture-preview"
7601
+ }
7602
+ ) }),
7603
+ recorder.state === "recording" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", "data-testid": "video-capture-rec-indicator", children: [
7604
+ /* @__PURE__ */ jsxs("span", { className: "relative flex h-2 w-2", children: [
7605
+ /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-red-500 opacity-75" }),
7606
+ /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-red-500" })
7607
+ ] }),
7608
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-red-500", children: "Rec" }),
7609
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs tabular-nums text-muted-foreground", children: formatElapsed(recorder.elapsedMs) })
7610
+ ] }),
7611
+ recorder.state === "recording" ? /* @__PURE__ */ jsx(
7612
+ Button,
7613
+ {
7614
+ type: "button",
7615
+ size: "lg",
7616
+ className: "h-16 w-16 rounded-full p-0",
7617
+ onClick: recorder.stop,
7618
+ "data-testid": "video-capture-stop-button",
7619
+ children: /* @__PURE__ */ jsx(Square, { className: "h-5 w-5 fill-current" })
7620
+ }
7621
+ ) : /* @__PURE__ */ jsx(
7622
+ Button,
7623
+ {
7624
+ type: "button",
7625
+ size: "lg",
7626
+ className: "h-16 w-16 rounded-full p-0",
7627
+ onClick: recorder.start,
7628
+ disabled: !camera.stream,
7629
+ "data-testid": "video-capture-record-button",
7630
+ children: /* @__PURE__ */ jsx(Circle, { className: "h-6 w-6 fill-current" })
7631
+ }
7632
+ ),
7633
+ /* @__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" })
7634
+ ] }),
7635
+ recorder.state === "stopped" && recorder.blob && /* @__PURE__ */ jsxs(Fragment, { children: [
7636
+ /* @__PURE__ */ jsx("div", { className: "w-full max-w-md", children: /* @__PURE__ */ jsx(VideoViewer, { blob: recorder.blob, title: "Captured video" }) }),
7637
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
7638
+ /* @__PURE__ */ jsxs(
7639
+ Button,
7640
+ {
7641
+ type: "button",
7642
+ variant: "outline",
7643
+ onClick: onDiscard,
7644
+ disabled: isSaving,
7645
+ "data-testid": "video-capture-discard-button",
7646
+ children: [
7647
+ /* @__PURE__ */ jsx(Trash2, { className: "mr-1.5 h-4 w-4" }),
7648
+ "Discard"
7649
+ ]
7650
+ }
7651
+ ),
7652
+ /* @__PURE__ */ jsxs(
7653
+ Button,
7654
+ {
7655
+ type: "button",
7656
+ variant: "outline",
7657
+ onClick: handleRetake,
7658
+ disabled: isSaving,
7659
+ "data-testid": "video-capture-retake-button",
7660
+ children: [
7661
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-1.5 h-4 w-4" }),
7662
+ "Record again"
7663
+ ]
7664
+ }
7665
+ ),
7666
+ /* @__PURE__ */ jsxs(
7667
+ Button,
7668
+ {
7669
+ type: "button",
7670
+ onClick: handleSave,
7671
+ disabled: isSaving,
7672
+ "data-testid": "video-capture-save-button",
7673
+ children: [
7674
+ 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" }),
7675
+ isSaving ? "Saving\u2026" : "Save"
7676
+ ]
7677
+ }
7678
+ )
7679
+ ] })
7680
+ ] })
7681
+ ] });
7682
+ }
7352
7683
 
7353
7684
  // src/documents/has-video-track.ts
7354
7685
  function hasVideoTrack(blob) {
@@ -7374,6 +7705,6 @@ function hasVideoTrack(blob) {
7374
7705
  });
7375
7706
  }
7376
7707
 
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 };
7708
+ 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
7709
  //# sourceMappingURL=index.js.map
7379
7710
  //# sourceMappingURL=index.js.map