@arbidocs/react 0.5.119 → 0.5.121
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/PdfViewerImpl-ZVJZ4KNW.cjs +22 -0
- package/dist/PdfViewerImpl-ZVJZ4KNW.cjs.map +1 -0
- package/dist/{PdfViewerImpl.d-B28hLEuj.d.ts → PdfViewerImpl.d-CqnEzQO7.d.ts} +9 -1
- package/dist/annotations/freeze/index.d.ts +1 -1
- package/dist/artifacts/artifact-kind.js +1 -0
- package/dist/artifacts/artifact-kind.js.map +2 -2
- package/dist/artifacts/index.cjs +3 -2
- package/dist/artifacts/index.cjs.map +1 -1
- package/dist/artifacts/index.d.ts +3 -2
- package/dist/calls/livekit/index.cjs +41 -41
- package/dist/chat/turn-flush.js +16 -0
- package/dist/chat/turn-flush.js.map +7 -0
- package/dist/chat/useConversationActions.js +3 -0
- package/dist/chat/useConversationActions.js.map +2 -2
- package/dist/{chunk-QP3WQSAA.cjs → chunk-4B2GW3AY.cjs} +3 -3
- package/dist/{chunk-QP3WQSAA.cjs.map → chunk-4B2GW3AY.cjs.map} +1 -1
- package/dist/{chunk-YMB6XUR2.cjs → chunk-7L7QRIQ2.cjs} +11 -7
- package/dist/chunk-7L7QRIQ2.cjs.map +1 -0
- package/dist/{chunk-LBAG7KL7.cjs → chunk-DLEHM4IA.cjs} +328 -180
- package/dist/chunk-DLEHM4IA.cjs.map +1 -0
- package/dist/{PdfViewerImpl-QUSDLNNM.cjs → chunk-ICBT2XGF.cjs} +5 -2
- package/dist/chunk-ICBT2XGF.cjs.map +1 -0
- package/dist/chunk-MAOGK7IC.cjs +61 -0
- package/dist/chunk-MAOGK7IC.cjs.map +1 -0
- package/dist/{chunk-5TRUFWKT.cjs → chunk-X5OZRLFZ.cjs} +5 -5
- package/dist/{chunk-5TRUFWKT.cjs.map → chunk-X5OZRLFZ.cjs.map} +1 -1
- package/dist/datasets/sources/documents.js +1 -1
- package/dist/datasets/sources/documents.js.map +2 -2
- package/dist/document-tools/images-to-pdf.js +43 -0
- package/dist/document-tools/images-to-pdf.js.map +7 -0
- package/dist/document-tools/index.cjs +104 -0
- package/dist/document-tools/index.cjs.map +1 -1
- package/dist/document-tools/index.d.ts +41 -1
- package/dist/document-tools/index.js +6 -1
- package/dist/document-tools/index.js.map +2 -2
- package/dist/document-tools/pdf-attachments.js +63 -0
- package/dist/document-tools/pdf-attachments.js.map +7 -0
- package/dist/entities/DocumentEntity.js +7 -2
- package/dist/entities/DocumentEntity.js.map +2 -2
- package/dist/entities/SharingEntity.js +85 -0
- package/dist/entities/SharingEntity.js.map +7 -0
- package/dist/entities/file-type.js +14 -2
- package/dist/entities/file-type.js.map +2 -2
- package/dist/entities/index.js +17 -1
- package/dist/entities/index.js.map +2 -2
- package/dist/icons/PresIcon.js +53 -0
- package/dist/icons/PresIcon.js.map +7 -0
- package/dist/icons/colors.js +2 -0
- package/dist/icons/colors.js.map +2 -2
- package/dist/icons/file-type.js +3 -0
- package/dist/icons/file-type.js.map +2 -2
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +2 -2
- package/dist/index.cjs +834 -789
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-CYXcTKYt.d.ts → index.d-D2puqWeN.d.ts} +47 -3
- package/dist/index.d.ts +50 -8
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/pdf-region-impl-ZG5G2OX2.cjs +98 -0
- package/dist/pdf-region-impl-ZG5G2OX2.cjs.map +1 -0
- package/dist/session/documents.js +9 -5
- package/dist/session/documents.js.map +2 -2
- package/dist/ui/index.cjs +182 -158
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/slider.js +7 -1
- package/dist/ui/slider.js.map +2 -2
- package/dist/viewers/PdfViewer.cjs +3 -3
- package/dist/viewers/PdfViewer.d.ts +2 -2
- package/dist/viewers/PdfViewerImpl.js +4 -1
- package/dist/viewers/PdfViewerImpl.js.map +2 -2
- package/dist/viewers/index.cjs +30 -4
- package/dist/viewers/index.cjs.map +1 -1
- package/dist/viewers/index.d.ts +72 -2
- package/dist/viewers/index.js +14 -0
- package/dist/viewers/index.js.map +2 -2
- package/dist/viewers/pdf-region-impl.js +96 -0
- package/dist/viewers/pdf-region-impl.js.map +7 -0
- package/dist/viewers/pdf-region.js +57 -0
- package/dist/viewers/pdf-region.js.map +7 -0
- package/dist/viewers/useProcessedChunks.js +2 -1
- package/dist/viewers/useProcessedChunks.js.map +2 -2
- package/package.json +3 -3
- package/dist/PdfViewerImpl-QUSDLNNM.cjs.map +0 -1
- package/dist/chunk-LBAG7KL7.cjs.map +0 -1
- package/dist/chunk-YMB6XUR2.cjs.map +0 -1
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ARBI_MARK_SRC, a as AgentBadge, b as AiMarkdown, c as ArbiIcon, d as Avatar, e as AvatarFallback, f as AvatarImage, B as BASE_COLORS, g as Badge, h as BadgeProps, i as Button, j as ButtonProps, C as COLUMN_LABEL_FALLBACKS, k as Card, l as CardContent, m as CardDescription, n as CardFooter, o as CardHeader, p as CardProps, q as CardTitle, r as Checkbox, s as Collapsible, t as CollapsibleContent, u as CollapsibleTrigger, v as Command, w as CommandDialog, x as CommandEmpty, y as CommandGroup, z as CommandInput, D as CommandItem, E as CommandList, F as CommandSeparator, G as CommandShortcut, H as DEFAULT_METADATA_TAGS, I as DebouncedInput, J as DebouncedInputProps, K as Dialog, L as DialogClose, M as DialogContent, N as DialogDescription, O as DialogFooter, P as DialogHeader, Q as DialogOverlay, R as DialogPortal, S as DialogPresentation, T as DialogTitle, U as DialogTrigger, V as DictateContextValue, W as DocumentEntity, X as DocumentEntityProps, Y as DocumentLike, Z as DropdownMenu, _ as DropdownMenuCheckboxItem, $ as DropdownMenuContent, a0 as DropdownMenuGroup, a1 as DropdownMenuItem, a2 as DropdownMenuLabel, a3 as DropdownMenuPortal, a4 as DropdownMenuRadioGroup, a5 as DropdownMenuRadioItem, a6 as DropdownMenuSeparator, a7 as DropdownMenuShortcut, a8 as DropdownMenuSub, a9 as DropdownMenuSubContent, aa as DropdownMenuSubTrigger, ab as DropdownMenuTrigger, ac as ENTITY_MAPPINGS, ad as EntityIcon, ae as EntityIconComponent, af as EntityLabelForm, ag as EntityNoun, ah as EntityPill, ai as EntityRegistryOverride, aj as EntitySize, ak as EntityType, al as EntityVocabulary, am as FileTypeIcon, an as FolderTreeNode, ao as FormatRelativeTimeOptions, ap as HoverCard, aq as HoverCardContent, ar as HoverCardTrigger, as as IconToggle, at as IconToggleProps, au as IdentityBusy, av as IdentityProblem, aw as IdentityPurchase, ax as IdentityState, ay as IdentityStatus, az as IdentityStep, aA as IdentityVerificationFlow, aB as Input, aC as InputProps, aD as Label, aE as MarkMenu, aF as MarkMenuItem, aG as MarkMenuProps, aH as MarkdownCode, aI as MarkdownLink, aJ as MarkdownRenderer, aK as MarkdownRendererProps, aL as MarkdownStreamingContext, aM as NEUTRAL_GRAY, aN as PLACEHOLDER_COLOR, aO as
|
|
1
|
+
export { A as ARBI_MARK_SRC, a as AgentBadge, b as AiMarkdown, c as ArbiIcon, d as Avatar, e as AvatarFallback, f as AvatarImage, B as BASE_COLORS, g as Badge, h as BadgeProps, i as Button, j as ButtonProps, C as COLUMN_LABEL_FALLBACKS, k as Card, l as CardContent, m as CardDescription, n as CardFooter, o as CardHeader, p as CardProps, q as CardTitle, r as Checkbox, s as Collapsible, t as CollapsibleContent, u as CollapsibleTrigger, v as Command, w as CommandDialog, x as CommandEmpty, y as CommandGroup, z as CommandInput, D as CommandItem, E as CommandList, F as CommandSeparator, G as CommandShortcut, H as DEFAULT_METADATA_TAGS, I as DebouncedInput, J as DebouncedInputProps, K as Dialog, L as DialogClose, M as DialogContent, N as DialogDescription, O as DialogFooter, P as DialogHeader, Q as DialogOverlay, R as DialogPortal, S as DialogPresentation, T as DialogTitle, U as DialogTrigger, V as DictateContextValue, W as DocumentEntity, X as DocumentEntityProps, Y as DocumentLike, Z as DropdownMenu, _ as DropdownMenuCheckboxItem, $ as DropdownMenuContent, a0 as DropdownMenuGroup, a1 as DropdownMenuItem, a2 as DropdownMenuLabel, a3 as DropdownMenuPortal, a4 as DropdownMenuRadioGroup, a5 as DropdownMenuRadioItem, a6 as DropdownMenuSeparator, a7 as DropdownMenuShortcut, a8 as DropdownMenuSub, a9 as DropdownMenuSubContent, aa as DropdownMenuSubTrigger, ab as DropdownMenuTrigger, ac as ENTITY_MAPPINGS, ad as EntityIcon, ae as EntityIconComponent, af as EntityLabelForm, ag as EntityNoun, ah as EntityPill, ai as EntityRegistryOverride, aj as EntitySize, ak as EntityType, al as EntityVocabulary, am as FileTypeIcon, an as FolderTreeNode, ao as FormatRelativeTimeOptions, ap as HoverCard, aq as HoverCardContent, ar as HoverCardTrigger, as as IconToggle, at as IconToggleProps, au as IdentityBusy, av as IdentityProblem, aw as IdentityPurchase, ax as IdentityState, ay as IdentityStatus, az as IdentityStep, aA as IdentityVerificationFlow, aB as Input, aC as InputProps, aD as Label, aE as MarkMenu, aF as MarkMenuItem, aG as MarkMenuProps, aH as MarkdownCode, aI as MarkdownLink, aJ as MarkdownRenderer, aK as MarkdownRendererProps, aL as MarkdownStreamingContext, aM as NEUTRAL_GRAY, aN as PLACEHOLDER_COLOR, aO as PRESENTATIONS_FOLDER, aP as PRESENTATION_TEMPLATES_FOLDER, aQ as PassageCard, aR as PassageCardProps, aS as Popover, aT as PopoverAnchor, aU as PopoverClose, aV as PopoverContent, aW as PopoverTrigger, aX as PortalContainerProvider, aY as PresenceDisplayStatus, aZ as PresenceLabel, a_ as Progress, a$ as ProjectEntity, b0 as ProjectEntityProps, b1 as ProjectRelation, b2 as ProviderIcon, b3 as RadioGroup, b4 as RadioGroupItem, b5 as Rag, b6 as SHARING_LABELS, b7 as ScrollArea, b8 as ScrollBar, b9 as Select, ba as SelectContent, bb as SelectGroup, bc as SelectItem, bd as SelectLabel, be as SelectScrollDownButton, bf as SelectScrollUpButton, bg as SelectSeparator, bh as SelectTrigger, bi as SelectValue, bj as Separator, bk as SharingEntity, bl as SharingEntityProps, bm as ShieldIcon, bn as ShieldIconProps, bo as Slider, bp as StatusBadgeComponent, bq as StatusBadgeProps, br as StatusPill, bs as StatusPillProps, bt as StatusVariant, bu as Switch, bv as TAG_TYPE_ICONS, bw as TAG_TYPE_LABELS, bx as Table, by as TableBody, bz as TableCaption, bA as TableCell, bB as TableFooter, bC as TableHead, bD as TableHeader, bE as TableRow, bF as Tabs, bG as TabsContent, bH as TabsList, bI as TabsTrigger, bJ as TagEntity, bK as TagEntityProps, bL as TagLike, bM as Textarea, bN as TextareaProps, bO as ThreadVisibilityIcon, bP as Toggle, bQ as ToggleGroup, bR as ToggleGroupItem, bS as Tooltip, bT as TooltipContent, bU as TooltipProvider, bV as TooltipTrigger, bW as UserEntity, bX as UserEntityProps, bY as UserMenu, bZ as UserMenuItem, b_ as UserMenuProps, b$ as UserMenuStatus, c0 as VISIBILITY_ICONS, c1 as VerifiedBadge, c2 as VerifiedBadgeProps, c3 as VerifiedToggle, c4 as VisibilityIcon, c5 as VisibilityToggle, c6 as VisibilityToggleProps, c7 as agentAvatarColors, c8 as badgeVariants, c9 as buildFolderTree, ca as buttonVariants, cb as canonicalFolderPath, cc as cardVariants, cd as closeOpenEmphasis, ce as cn, cf as configureEntityRegistry, cg as configureEntityVocabulary, ch as configureRagLabels, ci as configureSharingMembers, cj as configureStatusRegistry, ck as createUserAvatarIcon, cl as entityNoun, cm as extensionFromMime, cn as formatCompactLastSeen, co as formatDocDate, cp as formatFolderLabel, cq as formatFriendlyDate, cr as formatRelativeTime, cs as friendlyFileType, ct as getDocIcon, cu as getDocumentAuthor, cv as getDocumentDate, cw as getDocumentNature, cx as getDocumentSubject, cy as getDocumentTitle, cz as getEntityColor, cA as getEntityColorStyles, cB as getEntityIcon, cC as getEntityLabel, cD as getFileExtension, cE as getFileTypeIcon, cF as getStatusVariant, cG as getTagTypeIcon, cH as getTagTypeLabel, cI as getUserAvatarColor, cJ as getUserDisplayName, cK as getUserInitials, cL as getWorkspaceColor, cM as isAgent, cN as isAudioFile, cO as isDocumentAddableToConversation, cP as isDownloadOnlyFile, cQ as isImageDocument, cR as isImageFile, cS as isMediaFile, cT as isPresentationFileName, cU as isVideoFile, cV as markdownBaseComponents, cW as markdownSanitizeSchema, cX as markdownToPlainText, cY as markdownToPlainTextBlocks, c_ as splitMarkdownBlocks, c$ as tagKindNouns, d0 as tagKindTitle, d1 as toggleVariants, d2 as trimOpenCitation, d3 as useDictateContext, d4 as usePortalContainer, d5 as usesOriginalBytesForViewer } from '../index.d-D2puqWeN.js';
|
|
2
2
|
export { L as LazyChunk, l as lazyChunk, a as lazyComponent, p as preloadChunks } from '../lazy-chunk.d-B6YDLMKI.js';
|
|
3
3
|
import 'clsx';
|
|
4
4
|
import 'react';
|
package/dist/ui/slider.js
CHANGED
|
@@ -11,7 +11,13 @@ const Slider = React.forwardRef(
|
|
|
11
11
|
...props,
|
|
12
12
|
children: [
|
|
13
13
|
/* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: cn("absolute h-full bg-primary", rangeClassName) }) }),
|
|
14
|
-
/* @__PURE__ */ jsx(
|
|
14
|
+
/* @__PURE__ */ jsx(
|
|
15
|
+
SliderPrimitive.Thumb,
|
|
16
|
+
{
|
|
17
|
+
"aria-label": props["aria-label"],
|
|
18
|
+
className: "block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50"
|
|
19
|
+
}
|
|
20
|
+
)
|
|
15
21
|
]
|
|
16
22
|
}
|
|
17
23
|
)
|
package/dist/ui/slider.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/ui/slider.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport * as SliderPrimitive from '@radix-ui/react-slider'\n\nimport { cn } from '../lib/utils'\n\ninterface SliderProps extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n rangeClassName?: string\n}\n\nconst Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, SliderProps>(\n ({ className, rangeClassName, ...props }, ref) => (\n <SliderPrimitive.Root\n ref={ref}\n className={cn('relative flex w-full touch-none select-none items-center', className)}\n {...props}\n >\n <SliderPrimitive.Track className=\"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20\">\n <SliderPrimitive.Range className={cn('absolute h-full bg-primary', rangeClassName)} />\n </SliderPrimitive.Track>\n <SliderPrimitive.Thumb
|
|
5
|
-
"mappings": "AAWI,SAMI,KANJ;AAXJ,YAAY,WAAW;AACvB,YAAY,qBAAqB;AAEjC,SAAS,UAAU;AAMnB,MAAM,SAAS,MAAM;AAAA,EACnB,CAAC,EAAE,WAAW,gBAAgB,GAAG,MAAM,GAAG,QACxC;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW,GAAG,4DAA4D,SAAS;AAAA,MAClF,GAAG;AAAA,MAEJ;AAAA,4BAAC,gBAAgB,OAAhB,EAAsB,WAAU,yEAC/B,8BAAC,gBAAgB,OAAhB,EAAsB,WAAW,GAAG,8BAA8B,cAAc,GAAG,GACtF;AAAA,
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport * as SliderPrimitive from '@radix-ui/react-slider'\n\nimport { cn } from '../lib/utils'\n\ninterface SliderProps extends React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> {\n rangeClassName?: string\n}\n\nconst Slider = React.forwardRef<React.ElementRef<typeof SliderPrimitive.Root>, SliderProps>(\n ({ className, rangeClassName, ...props }, ref) => (\n <SliderPrimitive.Root\n ref={ref}\n className={cn('relative flex w-full touch-none select-none items-center', className)}\n {...props}\n >\n <SliderPrimitive.Track className=\"relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20\">\n <SliderPrimitive.Range className={cn('absolute h-full bg-primary', rangeClassName)} />\n </SliderPrimitive.Track>\n {/* The thumb is the `role=\"slider\"` element, so it carries the slider's name too. */}\n <SliderPrimitive.Thumb\n aria-label={props['aria-label']}\n className=\"block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\"\n />\n </SliderPrimitive.Root>\n )\n)\nSlider.displayName = SliderPrimitive.Root.displayName\n\nexport { Slider }\n"],
|
|
5
|
+
"mappings": "AAWI,SAMI,KANJ;AAXJ,YAAY,WAAW;AACvB,YAAY,qBAAqB;AAEjC,SAAS,UAAU;AAMnB,MAAM,SAAS,MAAM;AAAA,EACnB,CAAC,EAAE,WAAW,gBAAgB,GAAG,MAAM,GAAG,QACxC;AAAA,IAAC,gBAAgB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW,GAAG,4DAA4D,SAAS;AAAA,MAClF,GAAG;AAAA,MAEJ;AAAA,4BAAC,gBAAgB,OAAhB,EAAsB,WAAU,yEAC/B,8BAAC,gBAAgB,OAAhB,EAAsB,WAAW,GAAG,8BAA8B,cAAc,GAAG,GACtF;AAAA,QAEA;AAAA,UAAC,gBAAgB;AAAA,UAAhB;AAAA,YACC,cAAY,MAAM,YAAY;AAAA,YAC9B,WAAU;AAAA;AAAA,QACZ;AAAA;AAAA;AAAA,EACF;AAEJ;AACA,OAAO,cAAc,gBAAgB,KAAK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk4B2GW3AY_cjs = require('../chunk-4B2GW3AY.cjs');
|
|
4
4
|
require('../chunk-T5FZICXN.cjs');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Object.defineProperty(exports, "PdfViewer", {
|
|
9
9
|
enumerable: true,
|
|
10
|
-
get: function () { return
|
|
10
|
+
get: function () { return chunk4B2GW3AY_cjs.PdfViewer; }
|
|
11
11
|
});
|
|
12
12
|
Object.defineProperty(exports, "pdfViewerChunk", {
|
|
13
13
|
enumerable: true,
|
|
14
|
-
get: function () { return
|
|
14
|
+
get: function () { return chunk4B2GW3AY_cjs.pdfViewerChunk; }
|
|
15
15
|
});
|
|
16
16
|
//# sourceMappingURL=PdfViewer.cjs.map
|
|
17
17
|
//# sourceMappingURL=PdfViewer.cjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ComponentType } from 'react';
|
|
2
2
|
import { L as LazyChunk } from '../lazy-chunk.d-B6YDLMKI.js';
|
|
3
|
-
import { a as PdfViewerProps, _ as __PdfViewerImpl } from '../PdfViewerImpl.d-
|
|
4
|
-
export { P as PdfViewerAssets } from '../PdfViewerImpl.d-
|
|
3
|
+
import { a as PdfViewerProps, _ as __PdfViewerImpl } from '../PdfViewerImpl.d-CqnEzQO7.js';
|
|
4
|
+
export { P as PdfViewerAssets } from '../PdfViewerImpl.d-CqnEzQO7.js';
|
|
5
5
|
|
|
6
6
|
declare const pdfViewerChunk: LazyChunk<typeof __PdfViewerImpl>;
|
|
7
7
|
declare const PdfViewer: ComponentType<PdfViewerProps>;
|
|
@@ -270,6 +270,7 @@ function PdfViewer({
|
|
|
270
270
|
style: { touchAction: "pan-x pan-y", scrollbarGutter: "stable" },
|
|
271
271
|
role: "region",
|
|
272
272
|
"aria-label": "PDF document viewer",
|
|
273
|
+
"data-slot": "pdf-scroller",
|
|
273
274
|
"data-testid": "pdf-viewer",
|
|
274
275
|
children: /* @__PURE__ */ jsx(
|
|
275
276
|
Document,
|
|
@@ -379,6 +380,8 @@ function PdfViewer({
|
|
|
379
380
|
);
|
|
380
381
|
}
|
|
381
382
|
export {
|
|
382
|
-
|
|
383
|
+
DEFAULT_ASSETS,
|
|
384
|
+
PdfViewer,
|
|
385
|
+
ensurePdfWorker
|
|
383
386
|
};
|
|
384
387
|
//# sourceMappingURL=PdfViewerImpl.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/viewers/PdfViewerImpl.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * PdfViewer \u2014 paged PDF rendering with bidirectional page synchronisation.\n *\n * Uses IntersectionObserver to track the visible page and to drive two separate\n * lazy-load windows: a wide canvas buffer (so a page image is ready before the\n * user scrolls to it) and a narrow text-layer window (text spans are expensive\n * DOM, so they only exist for the active reading area).\n *\n * DECOUPLED FOR REUSE: page changes are reported through `onPageChange` rather\n * than written to an app store, and the pdf.js asset URLs are props rather than\n * hardcoded paths, because a consuming app decides where it serves the worker,\n * cmaps and standard fonts from.\n *\n * `react-pdf` and `pdfjs-dist` are OPTIONAL peer dependencies \u2014 install them\n * only if you render PDFs. The consuming app must also serve the pdf.js worker\n * (see `assets.workerSrc`).\n */\n\nimport { useState, useEffect, useRef, useCallback, useMemo, type ReactNode } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\nimport 'react-pdf/dist/Page/AnnotationLayer.css'\nimport 'react-pdf/dist/Page/TextLayer.css'\nimport { installPdfjsPolyfills } from './pdfjs-polyfills'\nimport { usePageIntersectionObserver } from './usePageIntersectionObserver'\nimport { useScrollAnchor } from './page-scroll'\nimport { contentBoxWidth, fitPageWidth, renderDpr, usePinchZoom } from './viewer-zoom'\nimport {\n LAZY_LOAD_BUFFER_BEFORE,\n LAZY_LOAD_BUFFER_AFTER,\n INITIAL_LAZY_LOAD_BUFFER,\n} from './pdf-viewer-constants'\n\n/** Where the app serves the pdf.js runtime assets from. */\nexport interface PdfViewerAssets {\n /** pdf.js worker bundle. Default `/pdf.worker.min.mjs`. */\n workerSrc?: string\n /** Directory of pdf.js character maps. Default `/cmaps/`. */\n cMapUrl?: string\n /** Directory of pdf.js standard font data. Default `/standard_fonts/`. */\n standardFontDataUrl?: string\n /**\n * Directory of the pdf.js wasm decoders (openjpeg for JPEG 2000, jbig2,\n * qcms). Scanned PDFs routinely embed JPX/JBIG2-compressed page images;\n * without these modules pdf.js fails image decoding with only a console\n * warning and renders blank white pages. Default `/wasm/`.\n */\n wasmUrl?: string\n}\n\nconst DEFAULT_ASSETS: Required<PdfViewerAssets> = {\n workerSrc: '/pdf.worker.min.mjs',\n cMapUrl: '/cmaps/',\n standardFontDataUrl: '/standard_fonts/',\n wasmUrl: '/wasm/',\n}\n\n/**\n * Ready pdf.js before any Document mounts: the built-ins it needs on this thread (older browsers\n * lack them and every page render would throw), and the worker, re-set only if it changed.\n */\nfunction ensurePdfWorker(workerSrc: string) {\n installPdfjsPolyfills()\n if (pdfjs.GlobalWorkerOptions.workerSrc !== workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerSrc\n }\n}\n\n// Page rendering constants\n// Height / width used for a page until its real size is known (the first page is read as soon as\n// the document opens, every other page as it renders). A placeholder that differs from the real\n// page shifts everything below it when the page renders.\nconst DEFAULT_PAGE_ASPECT_RATIO = 1.414 // A4 (\u221A2)\n/** The page wrapper's own border (border, top + bottom), included in its fixed height. */\nconst PAGE_BORDER_PX = 2\n/** Wait for the zoom to settle before re-rasterising every visible page. */\nconst RERENDER_DEBOUNCE_MS = 250\n/** Above this zoom a page canvas is large enough that the render window shrinks. */\nconst ZOOMED_BUFFER_THRESHOLD = 1.5\n\n/** Same set contents: lets a state setter bail out instead of re-rendering on every scroll tick. */\nfunction sameSet(a: ReadonlySet<number>, b: ReadonlySet<number>): boolean {\n if (a.size !== b.size) return false\n for (const v of a) if (!b.has(v)) return false\n return true\n}\n\n// Text layer is enabled for pages within 1 page of the visible set \u2014 enough for smooth\n// scrolling while keeping DOM node count low on large documents.\nconst TEXT_LAYER_BUFFER = 1\n\ninterface PdfPageSize {\n getViewport: (options: { scale: number }) => { width: number; height: number }\n}\nconst ratioOf = (page: PdfPageSize): number => {\n const { width, height } = page.getViewport({ scale: 1 })\n return width > 0 && height > 0 ? height / width : DEFAULT_PAGE_ASPECT_RATIO\n}\n\nexport interface PdfViewerProps {\n file: string | Blob\n currentPage?: number\n onLoadSuccess?: (numPages: number) => void\n /** Incremented to trigger scroll to currentPage */\n scrollTrigger?: number\n /** Zoom as a multiplier of the fit-width size (1 = fit width). Default 1. */\n zoom?: number\n /** Called by pinch and double-tap; the host owns the value (its buttons change it too). */\n onZoomChange?: (zoom: number) => void\n /**\n * Called as the user scrolls, with the page occupying most of the viewport.\n * This is the reusable form of the monolith's `setViewingDocumentPage`.\n */\n onPageChange?: (pageNumber: number) => void\n /**\n * Force pdf.js to rasterise fonts onto the canvas instead of using @font-face.\n * Required when rendering into a different document (e.g. a popped-out window),\n * where @font-face rules from the opener do not apply.\n */\n disableFontFace?: boolean\n /** Where the app serves the pdf.js worker, cmaps and standard fonts from. */\n assets?: PdfViewerAssets\n /**\n * Content drawn over every page, inside its border box (e.g. the annotation layer). It fills the\n * page area and moves and scales with it. `pageWidthPt` is the page's width in PDF points once\n * known, so overlays can size strokes and text to match what a later export draws.\n */\n renderPageOverlay?: (page: { pageNumber: number; pageWidthPt: number | undefined }) => ReactNode\n}\n\nexport function PdfViewer({\n file,\n currentPage,\n onLoadSuccess,\n scrollTrigger,\n zoom = 1,\n onZoomChange,\n onPageChange,\n disableFontFace = false,\n assets,\n renderPageOverlay,\n}: PdfViewerProps) {\n const workerSrc = assets?.workerSrc ?? DEFAULT_ASSETS.workerSrc\n const cMapUrl = assets?.cMapUrl ?? DEFAULT_ASSETS.cMapUrl\n const standardFontDataUrl = assets?.standardFontDataUrl ?? DEFAULT_ASSETS.standardFontDataUrl\n const wasmUrl = assets?.wasmUrl ?? DEFAULT_ASSETS.wasmUrl\n\n // Ensure the pdf.js worker is configured before any Document mounts\n ensurePdfWorker(workerSrc)\n\n const [numPages, setNumPages] = useState<number>(0)\n const [containerWidth, setContainerWidth] = useState<number>(0)\n // Real height/width of the document's pages: the first page's, then each page as it loads.\n const [defaultRatio, setDefaultRatio] = useState<number>(DEFAULT_PAGE_ASPECT_RATIO)\n const [pageRatios, setPageRatios] = useState<ReadonlyMap<number, number>>(new Map())\n // Each page's width in PDF points, for overlays that must size strokes and text like an export.\n const [pageWidthsPt, setPageWidthsPt] = useState<ReadonlyMap<number, number>>(new Map())\n const [loadError, setLoadError] = useState<Error | null>(null)\n const [documentKey, setDocumentKey] = useState<string>(() => `pdf-${Date.now()}`)\n\n // Initialize with pages around the current page (or first 3 pages if no current page).\n // Start with a small initial buffer so the first paint is cheap; expand to the full\n // buffer lazily via requestIdleCallback after the first render settles.\n const initialPage = currentPage || 1\n const [renderedPages, setRenderedPages] = useState<Set<number>>(\n new Set([\n Math.max(1, initialPage - INITIAL_LAZY_LOAD_BUFFER.before),\n initialPage,\n initialPage + INITIAL_LAZY_LOAD_BUFFER.after,\n ])\n )\n\n // Pages currently in/near the viewport \u2014 used to gate the text layer.\n // Keeping this separate from renderedPages lets the canvas still render on buffer pages\n // while text DOM nodes are only created for the user's active reading area.\n const [visiblePages, setVisiblePages] = useState<Set<number>>(new Set([initialPage]))\n\n // A late PDF.js completion belongs only to the file that started it.\n const loadLifetime = useMemo(() => ({ file, active: true }), [file])\n useEffect(() => {\n loadLifetime.active = true\n return () => {\n loadLifetime.active = false\n }\n }, [loadLifetime])\n\n // Reset document key when file changes to force remount\n useEffect(() => {\n setDocumentKey(`pdf-${Date.now()}`)\n setNumPages(0)\n setLoadError(null)\n }, [file])\n\n const containerRef = useRef<HTMLDivElement>(null)\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map())\n\n // Handle document load success\n const onDocumentLoadSuccess = useCallback(\n (pdf: { numPages: number; getPage?: (n: number) => Promise<PdfPageSize> }) => {\n if (!loadLifetime.active) return\n const n = pdf.numPages\n void pdf\n .getPage?.(1)\n .then((page) => {\n if (loadLifetime.active) setDefaultRatio(ratioOf(page))\n })\n .catch(() => {})\n setNumPages(n)\n setLoadError(null) // Clear any previous errors\n\n try {\n onLoadSuccess?.(n)\n } catch (error) {\n console.error('Error in onLoadSuccess callback:', error)\n }\n },\n [onLoadSuccess, loadLifetime]\n )\n\n // Expand only while this file is mounted. Cancellation also guards callbacks\n // that were already queued when the idle/timer handle was cancelled.\n useEffect(() => {\n if (numPages === 0) return\n let cancelled = false\n const expand = () => {\n if (cancelled || !loadLifetime.active) return\n setRenderedPages((prev) => {\n if (prev.size === 0) return prev\n const newSet = new Set(prev)\n const anchor = currentPage || 1\n for (\n let i = Math.max(1, anchor - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, anchor + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n }\n if (typeof requestIdleCallback !== 'undefined') {\n const handle = requestIdleCallback(expand, { timeout: 500 })\n return () => {\n cancelled = true\n if (typeof cancelIdleCallback !== 'undefined') cancelIdleCallback(handle)\n }\n }\n const handle = setTimeout(expand, 500)\n return () => {\n cancelled = true\n clearTimeout(handle)\n }\n }, [numPages, currentPage, loadLifetime])\n\n // Handle document load error\n const onDocumentLoadError = useCallback((error: Error) => {\n console.error('PDF loading error:', error)\n setLoadError(error)\n setNumPages(0)\n }, [])\n\n // react-pdf calls this when the PDF is encrypted (reason === 1) or the\n // supplied password was wrong (reason === 2). Default behaviour is a\n // window.prompt() that, when cancelled, never resolves the password\n // callback \u2014 pdf.js then leaves the document load Promise pending forever\n // and the viewer is stuck on \"Loading PDF...\".\n //\n // Always call updatePassword exactly once. On cancel we surface a\n // synthetic load error so onLoadError \u2192 setLoadError fires the standard\n // error UI instead of the indefinite spinner.\n const onPassword = useCallback((updatePassword: (password: string) => void, reason: number) => {\n const message =\n reason === 2\n ? 'Incorrect password. Enter the password to unlock this PDF:'\n : 'This PDF is password-protected. Enter the password to view it:'\n const password = window.prompt(message)\n if (password === null) {\n // Cancelled. Synthesise a load error so the error UI takes over.\n setLoadError(new Error('Password required to open this PDF'))\n setNumPages(0)\n return\n }\n updatePassword(password)\n }, [])\n\n // Fit width: the scroller's content box (inside its padding AND its vertical scrollbar) less the\n // page's own border. `offsetWidth` would count the scrollbar and overflow sideways by its width.\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n const setFromContentWidth = (contentWidth: number) =>\n setContainerWidth(fitPageWidth(contentWidth, PAGE_BORDER_PX))\n\n setFromContentWidth(contentBoxWidth(container))\n\n // Re-measure on any change of the content box: a panel resize, or the vertical scrollbar\n // appearing once the pages are taller than the scroller.\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[entries.length - 1]\n const box = entry?.contentBoxSize?.[0]\n setFromContentWidth(box ? box.inlineSize : (entry?.contentRect.width ?? 0))\n })\n resizeObserver.observe(container)\n\n return () => {\n resizeObserver.disconnect()\n }\n }, [])\n\n // Track whether initial scroll has completed to prevent feedback loop\n const scrollCompleteRef = useRef(false)\n\n // Scroll to page ONLY when PDF loads - not when page number updates from scrolling\n useEffect(() => {\n if (numPages === 0) return\n\n // If we already scrolled, don't scroll again\n if (scrollCompleteRef.current) return\n\n // Ensure the target page and surrounding pages are rendered\n if (currentPage) {\n setRenderedPages((prev) => {\n const newSet = new Set(prev)\n for (\n let i = Math.max(1, currentPage - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, currentPage + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n\n // Wait for DOM update, then scroll\n requestAnimationFrame(() => {\n const pageElement = pageRefs.current.get(currentPage)\n if (pageElement) {\n pageElement.scrollIntoView({ behavior: 'auto', block: 'start' })\n }\n // Wait for scroll to complete before allowing page number updates\n setTimeout(() => {\n scrollCompleteRef.current = true\n }, 100)\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [numPages]) // Note: currentPage is intentionally NOT a dependency to prevent feedback loop\n\n // The page the last explicit request (overlay arrows, typed number) asked for. Read when the\n // trigger fires; scrolling itself changes `currentPage` and must NOT re-run the scroll below,\n // or every page the user scrolls past would pull the view back to that page's top.\n const currentPageRef = useRef(currentPage)\n currentPageRef.current = currentPage\n\n // Scroll to page when scrollTrigger changes (user entered a page number)\n useEffect(() => {\n const currentPage = currentPageRef.current\n if (!scrollTrigger || numPages === 0 || !currentPage) return\n\n // Temporarily disable observer updates during manual scroll\n scrollCompleteRef.current = false\n\n // Ensure the target page and surrounding pages are rendered\n setRenderedPages((prev) => {\n const newSet = new Set(prev)\n for (\n let i = Math.max(1, currentPage - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, currentPage + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n\n // Double-rAF: first frame lets React commit the setRenderedPages update so\n // pages before the target are in the DOM at their correct heights; second\n // frame scrolls after layout has settled. Instant scroll avoids a race\n // where smooth-scroll animation is still running when the observer\n // re-enables and reports the wrong page.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n const pageElement = pageRefs.current.get(currentPage)\n if (pageElement) {\n pageElement.scrollIntoView({ behavior: 'instant', block: 'start' })\n }\n scrollCompleteRef.current = true\n })\n })\n }, [scrollTrigger, numPages])\n\n // Handle lazy loading based on visible pages\n const handleVisibilityUpdate = useCallback(\n (visibilityMap: Map<number, number>) => {\n const visiblePageNums = Array.from(visibilityMap.entries())\n .filter(([, ratio]) => ratio > 0)\n .map(([pageNum]) => pageNum)\n\n if (visiblePageNums.length > 0) {\n const minVisible = Math.min(...visiblePageNums)\n const maxVisible = Math.max(...visiblePageNums)\n\n // Update canvas render buffer (wider window for smooth pre-loading). Zoomed pages are\n // big canvases: keep fewer of them alive so far pages release their memory.\n const zoomed = zoom > ZOOMED_BUFFER_THRESHOLD\n const before = zoomed ? 1 : LAZY_LOAD_BUFFER_BEFORE\n const after = zoomed ? 2 : LAZY_LOAD_BUFFER_AFTER\n const pagesToRender = new Set<number>()\n for (\n let i = Math.max(1, minVisible - before);\n i <= Math.min(numPages, maxVisible + after);\n i++\n ) {\n pagesToRender.add(i)\n }\n setRenderedPages((prev) => (sameSet(prev, pagesToRender) ? prev : pagesToRender))\n\n // Update text-layer set (narrow window \u2014 text layer is expensive DOM)\n const nearViewport = new Set<number>()\n for (\n let i = Math.max(1, minVisible - TEXT_LAYER_BUFFER);\n i <= Math.min(numPages, maxVisible + TEXT_LAYER_BUFFER);\n i++\n ) {\n nearViewport.add(i)\n }\n setVisiblePages((prev) => (sameSet(prev, nearViewport) ? prev : nearViewport))\n }\n },\n [numPages, zoom]\n )\n\n // Memoize options to prevent unnecessary Document reloads.\n // When the options object changes reference, react-pdf reloads the document,\n // which fails if the source Blob's ArrayBuffer was already transferred to the worker.\n const documentOptions = useMemo(\n () => ({\n standardFontDataUrl,\n cMapUrl,\n cMapPacked: true,\n wasmUrl,\n ...(disableFontFace && { disableFontFace: true }),\n }),\n [standardFontDataUrl, cMapUrl, wasmUrl, disableFontFace]\n )\n\n // Observer callback is optional for consumers that don't track the page.\n const handlePageChange = useCallback(\n (pageNumber: number) => onPageChange?.(pageNumber),\n [onPageChange]\n )\n\n // Use IntersectionObserver to track visible pages and update page number\n usePageIntersectionObserver({\n containerRef,\n scrollCompleteRef,\n isEnabled: numPages > 0,\n getPageElements: () => Array.from(pageRefs.current.values()),\n getPageNumber: (element) => parseInt(element.getAttribute('data-page-number') ?? '0'),\n onPageChange: handlePageChange,\n onVisibilityUpdate: handleVisibilityUpdate,\n observeKey: `${numPages}:${containerWidth > 0}`,\n })\n\n // Pages above the reading position change height as they load their real size.\n useScrollAnchor(containerRef, `${numPages}:${containerWidth > 0}`)\n\n // Pinch / double-tap, and the focal point kept still for every zoom change.\n usePinchZoom({ containerRef, zoom, onZoomChange })\n\n // Layout follows `zoom` at once (a CSS scale of the already rendered canvas, so the gesture is\n // smooth); the canvases are re-rendered at the new resolution once the zoom has settled. Without\n // this the bitmap is only magnified and stays blurry.\n const [renderZoom, setRenderZoom] = useState(zoom)\n useEffect(() => {\n if (zoom === renderZoom) return\n const timer = setTimeout(() => setRenderZoom(zoom), RERENDER_DEBOUNCE_MS)\n return () => clearTimeout(timer)\n }, [zoom, renderZoom])\n\n return (\n <div\n ref={containerRef}\n className=\"w-full h-full overflow-auto bg-muted flex flex-col items-start p-4 pb-20\"\n // Two-finger gestures belong to the viewer (real zoom), not to the browser (bitmap zoom).\n // The scrollbar's gutter is always reserved, so the fit width does not change (and every page\n // re-rasterise) when the scrollbar appears, and cannot flip back and forth at the threshold.\n style={{ touchAction: 'pan-x pan-y', scrollbarGutter: 'stable' }}\n role=\"region\"\n aria-label=\"PDF document viewer\"\n data-testid=\"pdf-viewer\"\n >\n <Document\n // Wider than the scroller when zoomed in: the scroller pans horizontally over it.\n className=\"flex w-max min-w-full flex-col\"\n key={documentKey}\n // react-pdf 11 suspends while loading and sends failures to an error boundary. This viewer\n // owns its loading and error UI (and the password flow), so keep the callback behaviour.\n suspense={false}\n file={file}\n onLoadSuccess={onDocumentLoadSuccess}\n onLoadError={onDocumentLoadError}\n onPassword={onPassword}\n options={documentOptions}\n loading={\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading PDF...</div>\n </div>\n }\n error={\n <div className=\"flex flex-col items-center justify-center h-full gap-4 p-8\">\n <div className=\"text-destructive text-center\">\n {loadError?.message ===\n \"Cannot read properties of null (reading 'sendWithPromise')\" ? (\n <>\n <p className=\"font-semibold mb-2\">PDF viewer initialization failed</p>\n <p className=\"text-sm text-muted-foreground\">Please refresh the page to retry</p>\n </>\n ) : (\n <>\n <p className=\"font-semibold mb-2\">Failed to load PDF</p>\n {loadError && (\n <p className=\"text-sm text-muted-foreground\">{loadError.message}</p>\n )}\n </>\n )}\n </div>\n </div>\n }\n >\n {containerWidth > 0 &&\n Array.from(new Array(numPages), (_, index) => {\n const pageNumber = index + 1\n const shouldRender = renderedPages.has(pageNumber)\n const ratio = pageRatios.get(pageNumber) ?? defaultRatio\n const pageWidth = containerWidth * zoom\n const pageHeight = pageWidth * ratio\n // Resolution the canvas is (re-)rendered at, and how far it is CSS-scaled meanwhile.\n const renderWidth = containerWidth * renderZoom\n const scale = zoom / renderZoom\n // Only enable the text layer for pages in/near the viewport.\n // Pages in the wider render buffer get a canvas (so the image is ready when\n // the user scrolls to them) but no text spans until they're nearby \u2014 this\n // avoids committing thousands of DOM nodes synchronously on large documents.\n const shouldRenderTextLayer = visiblePages.has(pageNumber)\n\n return (\n <div\n key={`page_${pageNumber}`}\n ref={(el) => {\n if (el) {\n pageRefs.current.set(pageNumber, el)\n } else {\n pageRefs.current.delete(pageNumber)\n }\n }}\n data-page-number={pageNumber}\n // Fixed height in every state: a flex item would otherwise shrink (it is a\n // scroller itself via blocks.css) and a placeholder/real mismatch would shift the\n // pages below.\n className=\"relative mx-auto mb-6 shrink-0 shadow-xl bg-white border border-border\"\n style={{ width: pageWidth + PAGE_BORDER_PX, height: pageHeight + PAGE_BORDER_PX }}\n role=\"article\"\n aria-label={`Page ${pageNumber} of ${numPages}`}\n >\n {shouldRender ? (\n <div\n data-testid={`pdf-page-scaler-${pageNumber}`}\n style={\n scale === 1\n ? undefined\n : { transform: `scale(${scale})`, transformOrigin: '0 0' }\n }\n >\n <Page\n pageNumber={pageNumber}\n width={renderWidth}\n renderTextLayer={shouldRenderTextLayer}\n renderAnnotationLayer={false}\n onLoadSuccess={(page: { originalWidth: number; originalHeight: number }) => {\n setPageWidthsPt((prev) =>\n prev.get(pageNumber) === page.originalWidth\n ? prev\n : new Map(prev).set(pageNumber, page.originalWidth)\n )\n const ratio = page.originalHeight / page.originalWidth\n setPageRatios((prev) =>\n Math.abs((prev.get(pageNumber) ?? defaultRatio) - ratio) < 0.001\n ? prev\n : new Map(prev).set(pageNumber, ratio)\n )\n }}\n // DPR capped at 2x and lowered further when the page would exceed the canvas\n // pixel budget (zoomed pages are big; iOS Safari fails above ~16.7M pixels).\n devicePixelRatio={renderDpr(\n renderWidth,\n renderWidth * ratio,\n window.devicePixelRatio || 1\n )}\n loading={\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: renderWidth, height: renderWidth * ratio }}\n >\n <div className=\"text-sm text-muted-foreground\">\n Loading page {pageNumber}...\n </div>\n </div>\n }\n />\n </div>\n ) : (\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: pageWidth, height: pageHeight }}\n >\n <div className=\"text-sm text-muted-foreground\">Page {pageNumber}</div>\n </div>\n )}\n {renderPageOverlay?.({ pageNumber, pageWidthPt: pageWidthsPt.get(pageNumber) })}\n </div>\n )\n })}\n </Document>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * PdfViewer \u2014 paged PDF rendering with bidirectional page synchronisation.\n *\n * Uses IntersectionObserver to track the visible page and to drive two separate\n * lazy-load windows: a wide canvas buffer (so a page image is ready before the\n * user scrolls to it) and a narrow text-layer window (text spans are expensive\n * DOM, so they only exist for the active reading area).\n *\n * DECOUPLED FOR REUSE: page changes are reported through `onPageChange` rather\n * than written to an app store, and the pdf.js asset URLs are props rather than\n * hardcoded paths, because a consuming app decides where it serves the worker,\n * cmaps and standard fonts from.\n *\n * `react-pdf` and `pdfjs-dist` are OPTIONAL peer dependencies \u2014 install them\n * only if you render PDFs. The consuming app must also serve the pdf.js worker\n * (see `assets.workerSrc`).\n */\n\nimport { useState, useEffect, useRef, useCallback, useMemo, type ReactNode } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\nimport 'react-pdf/dist/Page/AnnotationLayer.css'\nimport 'react-pdf/dist/Page/TextLayer.css'\nimport { installPdfjsPolyfills } from './pdfjs-polyfills'\nimport { usePageIntersectionObserver } from './usePageIntersectionObserver'\nimport { useScrollAnchor } from './page-scroll'\nimport { contentBoxWidth, fitPageWidth, renderDpr, usePinchZoom } from './viewer-zoom'\nimport {\n LAZY_LOAD_BUFFER_BEFORE,\n LAZY_LOAD_BUFFER_AFTER,\n INITIAL_LAZY_LOAD_BUFFER,\n} from './pdf-viewer-constants'\n\n/** Where the app serves the pdf.js runtime assets from. */\nexport interface PdfViewerAssets {\n /** pdf.js worker bundle. Default `/pdf.worker.min.mjs`. */\n workerSrc?: string\n /** Directory of pdf.js character maps. Default `/cmaps/`. */\n cMapUrl?: string\n /** Directory of pdf.js standard font data. Default `/standard_fonts/`. */\n standardFontDataUrl?: string\n /**\n * Directory of the pdf.js wasm decoders (openjpeg for JPEG 2000, jbig2,\n * qcms). Scanned PDFs routinely embed JPX/JBIG2-compressed page images;\n * without these modules pdf.js fails image decoding with only a console\n * warning and renders blank white pages. Default `/wasm/`.\n */\n wasmUrl?: string\n}\n\nexport const DEFAULT_ASSETS: Required<PdfViewerAssets> = {\n workerSrc: '/pdf.worker.min.mjs',\n cMapUrl: '/cmaps/',\n standardFontDataUrl: '/standard_fonts/',\n wasmUrl: '/wasm/',\n}\n\n/**\n * Ready pdf.js before any Document mounts: the built-ins it needs on this thread (older browsers\n * lack them and every page render would throw), and the worker, re-set only if it changed.\n */\nexport function ensurePdfWorker(workerSrc: string) {\n installPdfjsPolyfills()\n if (pdfjs.GlobalWorkerOptions.workerSrc !== workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerSrc\n }\n}\n\n// Page rendering constants\n// Height / width used for a page until its real size is known (the first page is read as soon as\n// the document opens, every other page as it renders). A placeholder that differs from the real\n// page shifts everything below it when the page renders.\nconst DEFAULT_PAGE_ASPECT_RATIO = 1.414 // A4 (\u221A2)\n/** The page wrapper's own border (border, top + bottom), included in its fixed height. */\nconst PAGE_BORDER_PX = 2\n/** Wait for the zoom to settle before re-rasterising every visible page. */\nconst RERENDER_DEBOUNCE_MS = 250\n/** Above this zoom a page canvas is large enough that the render window shrinks. */\nconst ZOOMED_BUFFER_THRESHOLD = 1.5\n\n/** Same set contents: lets a state setter bail out instead of re-rendering on every scroll tick. */\nfunction sameSet(a: ReadonlySet<number>, b: ReadonlySet<number>): boolean {\n if (a.size !== b.size) return false\n for (const v of a) if (!b.has(v)) return false\n return true\n}\n\n// Text layer is enabled for pages within 1 page of the visible set \u2014 enough for smooth\n// scrolling while keeping DOM node count low on large documents.\nconst TEXT_LAYER_BUFFER = 1\n\ninterface PdfPageSize {\n getViewport: (options: { scale: number }) => { width: number; height: number }\n}\nconst ratioOf = (page: PdfPageSize): number => {\n const { width, height } = page.getViewport({ scale: 1 })\n return width > 0 && height > 0 ? height / width : DEFAULT_PAGE_ASPECT_RATIO\n}\n\nexport interface PdfViewerProps {\n file: string | Blob\n currentPage?: number\n onLoadSuccess?: (numPages: number) => void\n /** Incremented to trigger scroll to currentPage */\n scrollTrigger?: number\n /** Zoom as a multiplier of the fit-width size (1 = fit width). Default 1. */\n zoom?: number\n /** Called by pinch and double-tap; the host owns the value (its buttons change it too). */\n onZoomChange?: (zoom: number) => void\n /**\n * Called as the user scrolls, with the page occupying most of the viewport.\n * This is the reusable form of the monolith's `setViewingDocumentPage`.\n */\n onPageChange?: (pageNumber: number) => void\n /**\n * Force pdf.js to rasterise fonts onto the canvas instead of using @font-face.\n * Required when rendering into a different document (e.g. a popped-out window),\n * where @font-face rules from the opener do not apply.\n */\n disableFontFace?: boolean\n /** Where the app serves the pdf.js worker, cmaps and standard fonts from. */\n assets?: PdfViewerAssets\n /**\n * Content drawn over every page, inside its border box (e.g. the annotation layer). It fills the\n * page area and moves and scales with it. `pageWidthPt` is the page's width in PDF points once\n * known, so overlays can size strokes and text to match what a later export draws.\n */\n renderPageOverlay?: (page: { pageNumber: number; pageWidthPt: number | undefined }) => ReactNode\n}\n\nexport function PdfViewer({\n file,\n currentPage,\n onLoadSuccess,\n scrollTrigger,\n zoom = 1,\n onZoomChange,\n onPageChange,\n disableFontFace = false,\n assets,\n renderPageOverlay,\n}: PdfViewerProps) {\n const workerSrc = assets?.workerSrc ?? DEFAULT_ASSETS.workerSrc\n const cMapUrl = assets?.cMapUrl ?? DEFAULT_ASSETS.cMapUrl\n const standardFontDataUrl = assets?.standardFontDataUrl ?? DEFAULT_ASSETS.standardFontDataUrl\n const wasmUrl = assets?.wasmUrl ?? DEFAULT_ASSETS.wasmUrl\n\n // Ensure the pdf.js worker is configured before any Document mounts\n ensurePdfWorker(workerSrc)\n\n const [numPages, setNumPages] = useState<number>(0)\n const [containerWidth, setContainerWidth] = useState<number>(0)\n // Real height/width of the document's pages: the first page's, then each page as it loads.\n const [defaultRatio, setDefaultRatio] = useState<number>(DEFAULT_PAGE_ASPECT_RATIO)\n const [pageRatios, setPageRatios] = useState<ReadonlyMap<number, number>>(new Map())\n // Each page's width in PDF points, for overlays that must size strokes and text like an export.\n const [pageWidthsPt, setPageWidthsPt] = useState<ReadonlyMap<number, number>>(new Map())\n const [loadError, setLoadError] = useState<Error | null>(null)\n const [documentKey, setDocumentKey] = useState<string>(() => `pdf-${Date.now()}`)\n\n // Initialize with pages around the current page (or first 3 pages if no current page).\n // Start with a small initial buffer so the first paint is cheap; expand to the full\n // buffer lazily via requestIdleCallback after the first render settles.\n const initialPage = currentPage || 1\n const [renderedPages, setRenderedPages] = useState<Set<number>>(\n new Set([\n Math.max(1, initialPage - INITIAL_LAZY_LOAD_BUFFER.before),\n initialPage,\n initialPage + INITIAL_LAZY_LOAD_BUFFER.after,\n ])\n )\n\n // Pages currently in/near the viewport \u2014 used to gate the text layer.\n // Keeping this separate from renderedPages lets the canvas still render on buffer pages\n // while text DOM nodes are only created for the user's active reading area.\n const [visiblePages, setVisiblePages] = useState<Set<number>>(new Set([initialPage]))\n\n // A late PDF.js completion belongs only to the file that started it.\n const loadLifetime = useMemo(() => ({ file, active: true }), [file])\n useEffect(() => {\n loadLifetime.active = true\n return () => {\n loadLifetime.active = false\n }\n }, [loadLifetime])\n\n // Reset document key when file changes to force remount\n useEffect(() => {\n setDocumentKey(`pdf-${Date.now()}`)\n setNumPages(0)\n setLoadError(null)\n }, [file])\n\n const containerRef = useRef<HTMLDivElement>(null)\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map())\n\n // Handle document load success\n const onDocumentLoadSuccess = useCallback(\n (pdf: { numPages: number; getPage?: (n: number) => Promise<PdfPageSize> }) => {\n if (!loadLifetime.active) return\n const n = pdf.numPages\n void pdf\n .getPage?.(1)\n .then((page) => {\n if (loadLifetime.active) setDefaultRatio(ratioOf(page))\n })\n .catch(() => {})\n setNumPages(n)\n setLoadError(null) // Clear any previous errors\n\n try {\n onLoadSuccess?.(n)\n } catch (error) {\n console.error('Error in onLoadSuccess callback:', error)\n }\n },\n [onLoadSuccess, loadLifetime]\n )\n\n // Expand only while this file is mounted. Cancellation also guards callbacks\n // that were already queued when the idle/timer handle was cancelled.\n useEffect(() => {\n if (numPages === 0) return\n let cancelled = false\n const expand = () => {\n if (cancelled || !loadLifetime.active) return\n setRenderedPages((prev) => {\n if (prev.size === 0) return prev\n const newSet = new Set(prev)\n const anchor = currentPage || 1\n for (\n let i = Math.max(1, anchor - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, anchor + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n }\n if (typeof requestIdleCallback !== 'undefined') {\n const handle = requestIdleCallback(expand, { timeout: 500 })\n return () => {\n cancelled = true\n if (typeof cancelIdleCallback !== 'undefined') cancelIdleCallback(handle)\n }\n }\n const handle = setTimeout(expand, 500)\n return () => {\n cancelled = true\n clearTimeout(handle)\n }\n }, [numPages, currentPage, loadLifetime])\n\n // Handle document load error\n const onDocumentLoadError = useCallback((error: Error) => {\n console.error('PDF loading error:', error)\n setLoadError(error)\n setNumPages(0)\n }, [])\n\n // react-pdf calls this when the PDF is encrypted (reason === 1) or the\n // supplied password was wrong (reason === 2). Default behaviour is a\n // window.prompt() that, when cancelled, never resolves the password\n // callback \u2014 pdf.js then leaves the document load Promise pending forever\n // and the viewer is stuck on \"Loading PDF...\".\n //\n // Always call updatePassword exactly once. On cancel we surface a\n // synthetic load error so onLoadError \u2192 setLoadError fires the standard\n // error UI instead of the indefinite spinner.\n const onPassword = useCallback((updatePassword: (password: string) => void, reason: number) => {\n const message =\n reason === 2\n ? 'Incorrect password. Enter the password to unlock this PDF:'\n : 'This PDF is password-protected. Enter the password to view it:'\n const password = window.prompt(message)\n if (password === null) {\n // Cancelled. Synthesise a load error so the error UI takes over.\n setLoadError(new Error('Password required to open this PDF'))\n setNumPages(0)\n return\n }\n updatePassword(password)\n }, [])\n\n // Fit width: the scroller's content box (inside its padding AND its vertical scrollbar) less the\n // page's own border. `offsetWidth` would count the scrollbar and overflow sideways by its width.\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n const setFromContentWidth = (contentWidth: number) =>\n setContainerWidth(fitPageWidth(contentWidth, PAGE_BORDER_PX))\n\n setFromContentWidth(contentBoxWidth(container))\n\n // Re-measure on any change of the content box: a panel resize, or the vertical scrollbar\n // appearing once the pages are taller than the scroller.\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[entries.length - 1]\n const box = entry?.contentBoxSize?.[0]\n setFromContentWidth(box ? box.inlineSize : (entry?.contentRect.width ?? 0))\n })\n resizeObserver.observe(container)\n\n return () => {\n resizeObserver.disconnect()\n }\n }, [])\n\n // Track whether initial scroll has completed to prevent feedback loop\n const scrollCompleteRef = useRef(false)\n\n // Scroll to page ONLY when PDF loads - not when page number updates from scrolling\n useEffect(() => {\n if (numPages === 0) return\n\n // If we already scrolled, don't scroll again\n if (scrollCompleteRef.current) return\n\n // Ensure the target page and surrounding pages are rendered\n if (currentPage) {\n setRenderedPages((prev) => {\n const newSet = new Set(prev)\n for (\n let i = Math.max(1, currentPage - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, currentPage + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n\n // Wait for DOM update, then scroll\n requestAnimationFrame(() => {\n const pageElement = pageRefs.current.get(currentPage)\n if (pageElement) {\n pageElement.scrollIntoView({ behavior: 'auto', block: 'start' })\n }\n // Wait for scroll to complete before allowing page number updates\n setTimeout(() => {\n scrollCompleteRef.current = true\n }, 100)\n })\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [numPages]) // Note: currentPage is intentionally NOT a dependency to prevent feedback loop\n\n // The page the last explicit request (overlay arrows, typed number) asked for. Read when the\n // trigger fires; scrolling itself changes `currentPage` and must NOT re-run the scroll below,\n // or every page the user scrolls past would pull the view back to that page's top.\n const currentPageRef = useRef(currentPage)\n currentPageRef.current = currentPage\n\n // Scroll to page when scrollTrigger changes (user entered a page number)\n useEffect(() => {\n const currentPage = currentPageRef.current\n if (!scrollTrigger || numPages === 0 || !currentPage) return\n\n // Temporarily disable observer updates during manual scroll\n scrollCompleteRef.current = false\n\n // Ensure the target page and surrounding pages are rendered\n setRenderedPages((prev) => {\n const newSet = new Set(prev)\n for (\n let i = Math.max(1, currentPage - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, currentPage + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n\n // Double-rAF: first frame lets React commit the setRenderedPages update so\n // pages before the target are in the DOM at their correct heights; second\n // frame scrolls after layout has settled. Instant scroll avoids a race\n // where smooth-scroll animation is still running when the observer\n // re-enables and reports the wrong page.\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n const pageElement = pageRefs.current.get(currentPage)\n if (pageElement) {\n pageElement.scrollIntoView({ behavior: 'instant', block: 'start' })\n }\n scrollCompleteRef.current = true\n })\n })\n }, [scrollTrigger, numPages])\n\n // Handle lazy loading based on visible pages\n const handleVisibilityUpdate = useCallback(\n (visibilityMap: Map<number, number>) => {\n const visiblePageNums = Array.from(visibilityMap.entries())\n .filter(([, ratio]) => ratio > 0)\n .map(([pageNum]) => pageNum)\n\n if (visiblePageNums.length > 0) {\n const minVisible = Math.min(...visiblePageNums)\n const maxVisible = Math.max(...visiblePageNums)\n\n // Update canvas render buffer (wider window for smooth pre-loading). Zoomed pages are\n // big canvases: keep fewer of them alive so far pages release their memory.\n const zoomed = zoom > ZOOMED_BUFFER_THRESHOLD\n const before = zoomed ? 1 : LAZY_LOAD_BUFFER_BEFORE\n const after = zoomed ? 2 : LAZY_LOAD_BUFFER_AFTER\n const pagesToRender = new Set<number>()\n for (\n let i = Math.max(1, minVisible - before);\n i <= Math.min(numPages, maxVisible + after);\n i++\n ) {\n pagesToRender.add(i)\n }\n setRenderedPages((prev) => (sameSet(prev, pagesToRender) ? prev : pagesToRender))\n\n // Update text-layer set (narrow window \u2014 text layer is expensive DOM)\n const nearViewport = new Set<number>()\n for (\n let i = Math.max(1, minVisible - TEXT_LAYER_BUFFER);\n i <= Math.min(numPages, maxVisible + TEXT_LAYER_BUFFER);\n i++\n ) {\n nearViewport.add(i)\n }\n setVisiblePages((prev) => (sameSet(prev, nearViewport) ? prev : nearViewport))\n }\n },\n [numPages, zoom]\n )\n\n // Memoize options to prevent unnecessary Document reloads.\n // When the options object changes reference, react-pdf reloads the document,\n // which fails if the source Blob's ArrayBuffer was already transferred to the worker.\n const documentOptions = useMemo(\n () => ({\n standardFontDataUrl,\n cMapUrl,\n cMapPacked: true,\n wasmUrl,\n ...(disableFontFace && { disableFontFace: true }),\n }),\n [standardFontDataUrl, cMapUrl, wasmUrl, disableFontFace]\n )\n\n // Observer callback is optional for consumers that don't track the page.\n const handlePageChange = useCallback(\n (pageNumber: number) => onPageChange?.(pageNumber),\n [onPageChange]\n )\n\n // Use IntersectionObserver to track visible pages and update page number\n usePageIntersectionObserver({\n containerRef,\n scrollCompleteRef,\n isEnabled: numPages > 0,\n getPageElements: () => Array.from(pageRefs.current.values()),\n getPageNumber: (element) => parseInt(element.getAttribute('data-page-number') ?? '0'),\n onPageChange: handlePageChange,\n onVisibilityUpdate: handleVisibilityUpdate,\n observeKey: `${numPages}:${containerWidth > 0}`,\n })\n\n // Pages above the reading position change height as they load their real size.\n useScrollAnchor(containerRef, `${numPages}:${containerWidth > 0}`)\n\n // Pinch / double-tap, and the focal point kept still for every zoom change.\n usePinchZoom({ containerRef, zoom, onZoomChange })\n\n // Layout follows `zoom` at once (a CSS scale of the already rendered canvas, so the gesture is\n // smooth); the canvases are re-rendered at the new resolution once the zoom has settled. Without\n // this the bitmap is only magnified and stays blurry.\n const [renderZoom, setRenderZoom] = useState(zoom)\n useEffect(() => {\n if (zoom === renderZoom) return\n const timer = setTimeout(() => setRenderZoom(zoom), RERENDER_DEBOUNCE_MS)\n return () => clearTimeout(timer)\n }, [zoom, renderZoom])\n\n return (\n <div\n ref={containerRef}\n className=\"w-full h-full overflow-auto bg-muted flex flex-col items-start p-4 pb-20\"\n // Two-finger gestures belong to the viewer (real zoom), not to the browser (bitmap zoom).\n // The scrollbar's gutter is always reserved, so the fit width does not change (and every page\n // re-rasterise) when the scrollbar appears, and cannot flip back and forth at the threshold.\n style={{ touchAction: 'pan-x pan-y', scrollbarGutter: 'stable' }}\n role=\"region\"\n aria-label=\"PDF document viewer\"\n data-slot=\"pdf-scroller\"\n data-testid=\"pdf-viewer\"\n >\n <Document\n // Wider than the scroller when zoomed in: the scroller pans horizontally over it.\n className=\"flex w-max min-w-full flex-col\"\n key={documentKey}\n // react-pdf 11 suspends while loading and sends failures to an error boundary. This viewer\n // owns its loading and error UI (and the password flow), so keep the callback behaviour.\n suspense={false}\n file={file}\n onLoadSuccess={onDocumentLoadSuccess}\n onLoadError={onDocumentLoadError}\n onPassword={onPassword}\n options={documentOptions}\n loading={\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading PDF...</div>\n </div>\n }\n error={\n <div className=\"flex flex-col items-center justify-center h-full gap-4 p-8\">\n <div className=\"text-destructive text-center\">\n {loadError?.message ===\n \"Cannot read properties of null (reading 'sendWithPromise')\" ? (\n <>\n <p className=\"font-semibold mb-2\">PDF viewer initialization failed</p>\n <p className=\"text-sm text-muted-foreground\">Please refresh the page to retry</p>\n </>\n ) : (\n <>\n <p className=\"font-semibold mb-2\">Failed to load PDF</p>\n {loadError && (\n <p className=\"text-sm text-muted-foreground\">{loadError.message}</p>\n )}\n </>\n )}\n </div>\n </div>\n }\n >\n {containerWidth > 0 &&\n Array.from(new Array(numPages), (_, index) => {\n const pageNumber = index + 1\n const shouldRender = renderedPages.has(pageNumber)\n const ratio = pageRatios.get(pageNumber) ?? defaultRatio\n const pageWidth = containerWidth * zoom\n const pageHeight = pageWidth * ratio\n // Resolution the canvas is (re-)rendered at, and how far it is CSS-scaled meanwhile.\n const renderWidth = containerWidth * renderZoom\n const scale = zoom / renderZoom\n // Only enable the text layer for pages in/near the viewport.\n // Pages in the wider render buffer get a canvas (so the image is ready when\n // the user scrolls to them) but no text spans until they're nearby \u2014 this\n // avoids committing thousands of DOM nodes synchronously on large documents.\n const shouldRenderTextLayer = visiblePages.has(pageNumber)\n\n return (\n <div\n key={`page_${pageNumber}`}\n ref={(el) => {\n if (el) {\n pageRefs.current.set(pageNumber, el)\n } else {\n pageRefs.current.delete(pageNumber)\n }\n }}\n data-page-number={pageNumber}\n // Fixed height in every state: a flex item would otherwise shrink (it is a\n // scroller itself via blocks.css) and a placeholder/real mismatch would shift the\n // pages below.\n className=\"relative mx-auto mb-6 shrink-0 shadow-xl bg-white border border-border\"\n style={{ width: pageWidth + PAGE_BORDER_PX, height: pageHeight + PAGE_BORDER_PX }}\n role=\"article\"\n aria-label={`Page ${pageNumber} of ${numPages}`}\n >\n {shouldRender ? (\n <div\n data-testid={`pdf-page-scaler-${pageNumber}`}\n style={\n scale === 1\n ? undefined\n : { transform: `scale(${scale})`, transformOrigin: '0 0' }\n }\n >\n <Page\n pageNumber={pageNumber}\n width={renderWidth}\n renderTextLayer={shouldRenderTextLayer}\n renderAnnotationLayer={false}\n onLoadSuccess={(page: { originalWidth: number; originalHeight: number }) => {\n setPageWidthsPt((prev) =>\n prev.get(pageNumber) === page.originalWidth\n ? prev\n : new Map(prev).set(pageNumber, page.originalWidth)\n )\n const ratio = page.originalHeight / page.originalWidth\n setPageRatios((prev) =>\n Math.abs((prev.get(pageNumber) ?? defaultRatio) - ratio) < 0.001\n ? prev\n : new Map(prev).set(pageNumber, ratio)\n )\n }}\n // DPR capped at 2x and lowered further when the page would exceed the canvas\n // pixel budget (zoomed pages are big; iOS Safari fails above ~16.7M pixels).\n devicePixelRatio={renderDpr(\n renderWidth,\n renderWidth * ratio,\n window.devicePixelRatio || 1\n )}\n loading={\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: renderWidth, height: renderWidth * ratio }}\n >\n <div className=\"text-sm text-muted-foreground\">\n Loading page {pageNumber}...\n </div>\n </div>\n }\n />\n </div>\n ) : (\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: pageWidth, height: pageHeight }}\n >\n <div className=\"text-sm text-muted-foreground\">Page {pageNumber}</div>\n </div>\n )}\n {renderPageOverlay?.({ pageNumber, pageWidthPt: pageWidthsPt.get(pageNumber) })}\n </div>\n )\n })}\n </Document>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["handle", "currentPage", "ratio"]
|
|
7
7
|
}
|
package/dist/viewers/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk4B2GW3AY_cjs = require('../chunk-4B2GW3AY.cjs');
|
|
4
|
+
var chunkMAOGK7IC_cjs = require('../chunk-MAOGK7IC.cjs');
|
|
4
5
|
var chunkPWGSIM3F_cjs = require('../chunk-PWGSIM3F.cjs');
|
|
5
6
|
var chunkIU2CJNTB_cjs = require('../chunk-IU2CJNTB.cjs');
|
|
6
7
|
var chunkTMPDW7J5_cjs = require('../chunk-TMPDW7J5.cjs');
|
|
@@ -220,7 +221,8 @@ function useProcessedChunks(chunks, footnotes) {
|
|
|
220
221
|
content: hasFootnotes ? inlineFootnotes(chunk.content, footnotes) : chunk.content,
|
|
221
222
|
chunkIndex: chunk.metadata?.chunk_doc_idx,
|
|
222
223
|
chunkExtId: chunk.metadata?.chunk_ext_id,
|
|
223
|
-
docTitle: chunk.metadata?.doc_title ?? void 0
|
|
224
|
+
docTitle: chunk.metadata?.doc_title ?? void 0,
|
|
225
|
+
pageBbox: chunk.metadata?.page_bbox ?? void 0
|
|
224
226
|
});
|
|
225
227
|
});
|
|
226
228
|
if (currentPageChunks.length > 0) {
|
|
@@ -271,11 +273,35 @@ function computeSelectionRuns(pages, selectedChunks) {
|
|
|
271
273
|
|
|
272
274
|
Object.defineProperty(exports, "PdfViewer", {
|
|
273
275
|
enumerable: true,
|
|
274
|
-
get: function () { return
|
|
276
|
+
get: function () { return chunk4B2GW3AY_cjs.PdfViewer; }
|
|
275
277
|
});
|
|
276
278
|
Object.defineProperty(exports, "pdfViewerChunk", {
|
|
277
279
|
enumerable: true,
|
|
278
|
-
get: function () { return
|
|
280
|
+
get: function () { return chunk4B2GW3AY_cjs.pdfViewerChunk; }
|
|
281
|
+
});
|
|
282
|
+
Object.defineProperty(exports, "PDF_REGION_MAX_PIXELS", {
|
|
283
|
+
enumerable: true,
|
|
284
|
+
get: function () { return chunkMAOGK7IC_cjs.PDF_REGION_MAX_PIXELS; }
|
|
285
|
+
});
|
|
286
|
+
Object.defineProperty(exports, "closePdfRegionImage", {
|
|
287
|
+
enumerable: true,
|
|
288
|
+
get: function () { return chunkMAOGK7IC_cjs.closePdfRegionImage; }
|
|
289
|
+
});
|
|
290
|
+
Object.defineProperty(exports, "regionGeometry", {
|
|
291
|
+
enumerable: true,
|
|
292
|
+
get: function () { return chunkMAOGK7IC_cjs.regionGeometry; }
|
|
293
|
+
});
|
|
294
|
+
Object.defineProperty(exports, "regionMasks", {
|
|
295
|
+
enumerable: true,
|
|
296
|
+
get: function () { return chunkMAOGK7IC_cjs.regionMasks; }
|
|
297
|
+
});
|
|
298
|
+
Object.defineProperty(exports, "releasePdfRegionSource", {
|
|
299
|
+
enumerable: true,
|
|
300
|
+
get: function () { return chunkMAOGK7IC_cjs.releasePdfRegionSource; }
|
|
301
|
+
});
|
|
302
|
+
Object.defineProperty(exports, "renderPdfRegion", {
|
|
303
|
+
enumerable: true,
|
|
304
|
+
get: function () { return chunkMAOGK7IC_cjs.renderPdfRegion; }
|
|
279
305
|
});
|
|
280
306
|
Object.defineProperty(exports, "INITIAL_LAZY_LOAD_BUFFER", {
|
|
281
307
|
enumerable: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/viewers/DocxViewer.tsx","../../src/viewers/XlsxViewer.tsx","../../src/viewers/useProcessedChunks.ts","../../src/viewers/selection-runs.ts"],"names":["useRef","useState","useEffect","useLayoutEffect","jsx","jsxs","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * DocxViewer\n *\n * Renders DOCX files natively using docx-preview, preserving track changes\n * (shown as strikethrough deletions + inserted text) and inline comments.\n *\n * Pages render at their natural width and are scaled down to fit the\n * container, so the document resizes with the panel instead of clipping.\n *\n * `docx-preview` is an OPTIONAL peer dependency, imported dynamically — a\n * consumer that never renders a .docx does not need it installed. If it is\n * missing the viewer shows a load error rather than crashing the app.\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\n\nexport interface DocxViewerProps {\n blob: Blob\n}\n\n/** Natural width of the rendered document: widest page plus wrapper padding. */\nfunction measureContentWidth(container: HTMLElement): number {\n let pageWidth = 0\n container.querySelectorAll<HTMLElement>('section.docx').forEach((section) => {\n pageWidth = Math.max(pageWidth, section.offsetWidth)\n })\n if (pageWidth === 0) return 0\n\n const wrapper = container.querySelector<HTMLElement>('.docx-wrapper')\n if (wrapper) {\n const style = window.getComputedStyle(wrapper)\n pageWidth += (parseFloat(style.paddingLeft) || 0) + (parseFloat(style.paddingRight) || 0)\n }\n return pageWidth\n}\n\nexport function DocxViewer({ blob }: DocxViewerProps) {\n const outerRef = useRef<HTMLDivElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [containerWidth, setContainerWidth] = useState(0)\n const [contentWidth, setContentWidth] = useState(0)\n\n // Track container width so the document rescales when the panel is resized\n useEffect(() => {\n const outer = outerRef.current\n if (!outer) return\n\n const updateWidth = () => setContainerWidth(outer.clientWidth)\n updateWidth()\n\n const resizeObserver = new ResizeObserver(updateWidth)\n resizeObserver.observe(outer)\n return () => resizeObserver.disconnect()\n }, [])\n\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n let cancelled = false\n\n setIsLoading(true)\n setError(null)\n setContentWidth(0)\n container.innerHTML = ''\n\n import('docx-preview')\n .then(({ renderAsync }) => {\n if (cancelled) return\n return renderAsync(blob, container, undefined, {\n ignoreLastRenderedPageBreak: false,\n })\n })\n .then(() => {\n if (!cancelled) setIsLoading(false)\n })\n .catch((err) => {\n if (!cancelled) {\n console.error('DocxViewer render error:', err)\n setError('Failed to render document')\n setIsLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [blob])\n\n // Measure after the body is unhidden — offsetWidth is 0 while `hidden` (display: none)\n useLayoutEffect(() => {\n const container = containerRef.current\n if (isLoading || error || !container) return\n setContentWidth(measureContentWidth(container))\n }, [isLoading, error])\n\n const scale =\n containerWidth > 0 && contentWidth > 0 ? Math.min(1, containerWidth / contentWidth) : 1\n\n return (\n <div ref={outerRef} className=\"w-full h-full overflow-auto bg-muted\" data-testid=\"docx-viewer\">\n {isLoading && (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading document...</div>\n </div>\n )}\n {error && (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-destructive\">{error}</div>\n </div>\n )}\n <div\n ref={containerRef}\n data-testid=\"docx-viewer-body\"\n className={`docx-viewer-body${isLoading || error ? ' hidden' : ''}`}\n style={{ zoom: scale }}\n />\n </div>\n )\n}\n","/**\n * XlsxViewer\n *\n * Renders spreadsheets natively using SheetJS, showing every sheet with a tab\n * bar. Preserves cell data and multiple sheets.\n *\n * `xlsx` is an OPTIONAL peer dependency, imported dynamically — a consumer that\n * never renders a spreadsheet does not need it installed. If it is missing the\n * viewer shows a load error rather than crashing the app.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { WorkSheet } from 'xlsx'\n\nexport interface XlsxViewerProps {\n blob: Blob\n}\n\ntype WorkbookRef = {\n SheetNames: string[]\n Sheets: Record<string, WorkSheet>\n}\n\nexport function XlsxViewer({ blob }: XlsxViewerProps) {\n const [sheets, setSheets] = useState<string[]>([])\n const [activeSheet, setActiveSheet] = useState<string>('')\n const [rows, setRows] = useState<unknown[][]>([])\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const workbookRef = useRef<WorkbookRef | null>(null)\n\n const renderSheet = async (sheetName: string, wb: WorkbookRef) => {\n const XLSX = await import('xlsx')\n const sheet = wb.Sheets[sheetName]\n const data = XLSX.utils.sheet_to_json<unknown[]>(sheet, { header: 1, defval: '' })\n setRows(data)\n setActiveSheet(sheetName)\n }\n\n useEffect(() => {\n let cancelled = false\n\n blob\n .arrayBuffer()\n .then(async (buffer) => {\n if (cancelled) return\n const XLSX = await import('xlsx')\n const wb = XLSX.read(buffer, { type: 'array' }) as WorkbookRef\n workbookRef.current = wb\n const sheetNames = wb.SheetNames\n setSheets(sheetNames)\n const data = XLSX.utils.sheet_to_json<unknown[]>(wb.Sheets[sheetNames[0]], {\n header: 1,\n defval: '',\n })\n if (!cancelled) {\n setRows(data)\n setActiveSheet(sheetNames[0])\n setIsLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n console.error('XlsxViewer error:', err)\n setError('Failed to render spreadsheet')\n setIsLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [blob])\n\n const handleSheetChange = (sheetName: string) => {\n if (workbookRef.current) {\n renderSheet(sheetName, workbookRef.current)\n }\n }\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading spreadsheet...</div>\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-destructive\">{error}</div>\n </div>\n )\n }\n\n // Find max columns across all rows for consistent table width\n const colCount = rows.reduce((max, row) => Math.max(max, (row as unknown[]).length), 0)\n\n return (\n <div\n className=\"w-full h-full flex flex-col overflow-hidden bg-background\"\n data-testid=\"xlsx-viewer\"\n >\n {/* Sheet tabs */}\n {sheets.length > 0 && (\n <div className=\"flex-shrink-0 flex items-center gap-0.5 px-2 pt-1 border-b bg-muted overflow-x-auto\">\n {sheets.map((sheet) => (\n <button\n key={sheet}\n onClick={() => handleSheetChange(sheet)}\n className={`px-3 py-1 text-sm font-medium whitespace-nowrap rounded-t transition-colors border-x border-t ${\n sheet === activeSheet\n ? 'bg-background text-primary border-border'\n : 'bg-muted text-muted-foreground border-transparent hover:bg-muted hover:text-foreground'\n }`}\n >\n {sheet}\n </button>\n ))}\n </div>\n )}\n\n {/* Spreadsheet table */}\n <div className=\"flex-1 overflow-auto\">\n <table className=\"text-sm border-collapse min-w-full\">\n <tbody>\n {rows.map((row, rowIdx) => (\n <tr\n key={rowIdx}\n className={rowIdx === 0 ? 'bg-muted font-semibold sticky top-0' : 'hover:bg-accent'}\n >\n {/* Row number gutter */}\n <td className=\"border border-border px-1 text-center text-muted-foreground bg-muted select-none w-8 min-w-[2rem]\">\n {rowIdx + 1}\n </td>\n {Array.from({ length: colCount }).map((_, colIdx) => (\n <td\n key={colIdx}\n className=\"border border-border px-2 py-0.5 whitespace-nowrap max-w-[200px] overflow-hidden text-ellipsis\"\n title={String((row as unknown[])[colIdx] ?? '')}\n >\n {String((row as unknown[])[colIdx] ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {rows.length === 0 && (\n <div className=\"flex items-center justify-center p-8 text-sm text-muted-foreground\">\n Empty sheet\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * Processed Chunks Hook\n *\n * Processes raw document chunks into page-grouped structure.\n * Pre-computes footnote inlining so it runs once during processing, not on every render.\n */\n\nimport { useMemo } from 'react'\n\nexport interface RawChunk {\n content: string\n metadata?: {\n page_number?: number\n chunk_doc_idx?: number\n chunk_ext_id?: string\n doc_title?: string | null\n }\n}\n\nexport interface ProcessedChunk {\n content: string\n chunkIndex: number | undefined\n chunkExtId: string | undefined\n docTitle: string | undefined\n}\n\nexport interface ProcessedPage {\n pageNumber: number | null\n chunks: ProcessedChunk[]\n}\n\nexport interface UseProcessedChunksResult {\n processedChunks: ProcessedPage[]\n maxPageNumber: number\n}\n\n/**\n * Replace GFM footnote references [^key] with inline footnote content\n * and strip footnote definition blocks from the chunk text.\n * Uses the pre-parsed footnotes map from the backend.\n */\nfunction inlineFootnotes(content: string, footnotes: Record<string, string>): string {\n if (!footnotes || Object.keys(footnotes).length === 0) return content\n\n let result = content\n\n // Strip GFM footnote definition blocks: [^key]: content (and continuation lines)\n result = result.replace(/^\\[\\^[^\\]]+\\]:[ \\t]+.*(?:\\n(?:[ \\t]+.+)?)*/gm, '')\n\n // Replace footnote references [^key] with superscript + inline content\n result = result.replace(/\\[\\^([^\\]]+)\\]/g, (_match, key) => {\n const fnContent = footnotes[key]\n if (!fnContent) return `<sup class=\"fn-ref\">${key}</sup>`\n const escaped = fnContent\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n return `<sup class=\"fn-ref\">${key}</sup><span class=\"fn-inline\" title=\"${escaped}\">[${escaped}]</span>`\n })\n\n return result.trim()\n}\n\nexport function useProcessedChunks(\n chunks: RawChunk[] | undefined,\n footnotes?: Record<string, string>\n): UseProcessedChunksResult {\n return useMemo(() => {\n if (!chunks || chunks.length === 0) {\n return { processedChunks: [], maxPageNumber: 0 }\n }\n\n const hasFootnotes = footnotes && Object.keys(footnotes).length > 0\n const chunksByPage: ProcessedPage[] = []\n let currentPageNumber = -1\n let currentPageChunks: ProcessedChunk[] = []\n let maxPageNumber = 0\n\n chunks.forEach((chunk) => {\n const pageNum = chunk.metadata?.page_number\n\n // Track max page number\n if (pageNum && pageNum > maxPageNumber) {\n maxPageNumber = pageNum\n }\n\n // If page changed, save previous page and start new one\n if (pageNum !== currentPageNumber) {\n if (currentPageChunks.length > 0) {\n chunksByPage.push({\n pageNumber: currentPageNumber > 0 ? currentPageNumber : null,\n chunks: currentPageChunks,\n })\n }\n currentPageNumber = pageNum ?? -1\n currentPageChunks = []\n }\n\n currentPageChunks.push({\n content: hasFootnotes ? inlineFootnotes(chunk.content, footnotes) : chunk.content,\n chunkIndex: chunk.metadata?.chunk_doc_idx,\n chunkExtId: chunk.metadata?.chunk_ext_id,\n docTitle: chunk.metadata?.doc_title ?? undefined,\n })\n })\n\n // Add the last page\n if (currentPageChunks.length > 0) {\n chunksByPage.push({\n pageNumber: currentPageNumber > 0 ? currentPageNumber : null,\n chunks: currentPageChunks,\n })\n }\n\n return { processedChunks: chunksByPage, maxPageNumber }\n }, [chunks, footnotes])\n}\n","/**\n * Contiguous-run grouping for selected passages.\n *\n * Selecting passages 4–9 is one citation, not six. This collapses a flat set of\n * selected chunk ids into the contiguous runs they form in document order, so\n * the viewer can draw each run as a single block with a single \"p.3(4–9)\" label\n * instead of stacking six identical pills.\n *\n * Purely positional: the pages arrive in document order (which is\n * `chunk_doc_idx` order), so adjacency is just \"next in the list\".\n */\n\nexport interface RunChunk {\n chunkExtId: string | undefined\n /** 0-based index within the document; displayed 1-based */\n chunkIndex: number | undefined\n}\n\nexport interface RunPage {\n pageNumber: number | null\n chunks: RunChunk[]\n}\n\n/** Where a selected chunk sits inside its contiguous run of selected chunks. */\nexport interface ChunkRunInfo {\n isStart: boolean\n isEnd: boolean\n /** Set only on the run's first member — the bounds its single label shows. */\n endIndex: number | undefined\n endPage: number | null | undefined\n}\n\nexport function computeSelectionRuns(\n pages: RunPage[],\n selectedChunks: Set<string>\n): Map<string, ChunkRunInfo> {\n const runs = new Map<string, ChunkRunInfo>()\n if (selectedChunks.size === 0) return runs\n\n const flat = pages.flatMap((page) =>\n page.chunks.map((c) => ({ ...c, pageNumber: page.pageNumber }))\n )\n\n let i = 0\n while (i < flat.length) {\n const chunk = flat[i]\n if (!chunk.chunkExtId || !selectedChunks.has(chunk.chunkExtId)) {\n i += 1\n continue\n }\n\n // Walk forward while the neighbours are also selected.\n let end = i\n while (\n end + 1 < flat.length &&\n flat[end + 1].chunkExtId &&\n selectedChunks.has(flat[end + 1].chunkExtId!)\n ) {\n end += 1\n }\n\n const last = flat[end]\n const endIndex = last.chunkIndex !== undefined ? last.chunkIndex + 1 : undefined\n for (let k = i; k <= end; k += 1) {\n const id = flat[k].chunkExtId\n if (!id) continue\n runs.set(id, {\n isStart: k === i,\n isEnd: k === end,\n // Only the run's first member carries the label bounds.\n endIndex: k === i ? endIndex : undefined,\n endPage: k === i ? last.pageNumber : undefined,\n })\n }\n i = end + 1\n }\n\n return runs\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/viewers/DocxViewer.tsx","../../src/viewers/XlsxViewer.tsx","../../src/viewers/useProcessedChunks.ts","../../src/viewers/selection-runs.ts"],"names":["useRef","useState","useEffect","useLayoutEffect","jsx","jsxs","useMemo"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * DocxViewer\n *\n * Renders DOCX files natively using docx-preview, preserving track changes\n * (shown as strikethrough deletions + inserted text) and inline comments.\n *\n * Pages render at their natural width and are scaled down to fit the\n * container, so the document resizes with the panel instead of clipping.\n *\n * `docx-preview` is an OPTIONAL peer dependency, imported dynamically — a\n * consumer that never renders a .docx does not need it installed. If it is\n * missing the viewer shows a load error rather than crashing the app.\n */\n\nimport { useEffect, useLayoutEffect, useRef, useState } from 'react'\n\nexport interface DocxViewerProps {\n blob: Blob\n}\n\n/** Natural width of the rendered document: widest page plus wrapper padding. */\nfunction measureContentWidth(container: HTMLElement): number {\n let pageWidth = 0\n container.querySelectorAll<HTMLElement>('section.docx').forEach((section) => {\n pageWidth = Math.max(pageWidth, section.offsetWidth)\n })\n if (pageWidth === 0) return 0\n\n const wrapper = container.querySelector<HTMLElement>('.docx-wrapper')\n if (wrapper) {\n const style = window.getComputedStyle(wrapper)\n pageWidth += (parseFloat(style.paddingLeft) || 0) + (parseFloat(style.paddingRight) || 0)\n }\n return pageWidth\n}\n\nexport function DocxViewer({ blob }: DocxViewerProps) {\n const outerRef = useRef<HTMLDivElement>(null)\n const containerRef = useRef<HTMLDivElement>(null)\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const [containerWidth, setContainerWidth] = useState(0)\n const [contentWidth, setContentWidth] = useState(0)\n\n // Track container width so the document rescales when the panel is resized\n useEffect(() => {\n const outer = outerRef.current\n if (!outer) return\n\n const updateWidth = () => setContainerWidth(outer.clientWidth)\n updateWidth()\n\n const resizeObserver = new ResizeObserver(updateWidth)\n resizeObserver.observe(outer)\n return () => resizeObserver.disconnect()\n }, [])\n\n useEffect(() => {\n const container = containerRef.current\n if (!container) return\n\n let cancelled = false\n\n setIsLoading(true)\n setError(null)\n setContentWidth(0)\n container.innerHTML = ''\n\n import('docx-preview')\n .then(({ renderAsync }) => {\n if (cancelled) return\n return renderAsync(blob, container, undefined, {\n ignoreLastRenderedPageBreak: false,\n })\n })\n .then(() => {\n if (!cancelled) setIsLoading(false)\n })\n .catch((err) => {\n if (!cancelled) {\n console.error('DocxViewer render error:', err)\n setError('Failed to render document')\n setIsLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [blob])\n\n // Measure after the body is unhidden — offsetWidth is 0 while `hidden` (display: none)\n useLayoutEffect(() => {\n const container = containerRef.current\n if (isLoading || error || !container) return\n setContentWidth(measureContentWidth(container))\n }, [isLoading, error])\n\n const scale =\n containerWidth > 0 && contentWidth > 0 ? Math.min(1, containerWidth / contentWidth) : 1\n\n return (\n <div ref={outerRef} className=\"w-full h-full overflow-auto bg-muted\" data-testid=\"docx-viewer\">\n {isLoading && (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading document...</div>\n </div>\n )}\n {error && (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-destructive\">{error}</div>\n </div>\n )}\n <div\n ref={containerRef}\n data-testid=\"docx-viewer-body\"\n className={`docx-viewer-body${isLoading || error ? ' hidden' : ''}`}\n style={{ zoom: scale }}\n />\n </div>\n )\n}\n","/**\n * XlsxViewer\n *\n * Renders spreadsheets natively using SheetJS, showing every sheet with a tab\n * bar. Preserves cell data and multiple sheets.\n *\n * `xlsx` is an OPTIONAL peer dependency, imported dynamically — a consumer that\n * never renders a spreadsheet does not need it installed. If it is missing the\n * viewer shows a load error rather than crashing the app.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { WorkSheet } from 'xlsx'\n\nexport interface XlsxViewerProps {\n blob: Blob\n}\n\ntype WorkbookRef = {\n SheetNames: string[]\n Sheets: Record<string, WorkSheet>\n}\n\nexport function XlsxViewer({ blob }: XlsxViewerProps) {\n const [sheets, setSheets] = useState<string[]>([])\n const [activeSheet, setActiveSheet] = useState<string>('')\n const [rows, setRows] = useState<unknown[][]>([])\n const [error, setError] = useState<string | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n const workbookRef = useRef<WorkbookRef | null>(null)\n\n const renderSheet = async (sheetName: string, wb: WorkbookRef) => {\n const XLSX = await import('xlsx')\n const sheet = wb.Sheets[sheetName]\n const data = XLSX.utils.sheet_to_json<unknown[]>(sheet, { header: 1, defval: '' })\n setRows(data)\n setActiveSheet(sheetName)\n }\n\n useEffect(() => {\n let cancelled = false\n\n blob\n .arrayBuffer()\n .then(async (buffer) => {\n if (cancelled) return\n const XLSX = await import('xlsx')\n const wb = XLSX.read(buffer, { type: 'array' }) as WorkbookRef\n workbookRef.current = wb\n const sheetNames = wb.SheetNames\n setSheets(sheetNames)\n const data = XLSX.utils.sheet_to_json<unknown[]>(wb.Sheets[sheetNames[0]], {\n header: 1,\n defval: '',\n })\n if (!cancelled) {\n setRows(data)\n setActiveSheet(sheetNames[0])\n setIsLoading(false)\n }\n })\n .catch((err) => {\n if (!cancelled) {\n console.error('XlsxViewer error:', err)\n setError('Failed to render spreadsheet')\n setIsLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [blob])\n\n const handleSheetChange = (sheetName: string) => {\n if (workbookRef.current) {\n renderSheet(sheetName, workbookRef.current)\n }\n }\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-sm text-muted-foreground\">Loading spreadsheet...</div>\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <div className=\"text-destructive\">{error}</div>\n </div>\n )\n }\n\n // Find max columns across all rows for consistent table width\n const colCount = rows.reduce((max, row) => Math.max(max, (row as unknown[]).length), 0)\n\n return (\n <div\n className=\"w-full h-full flex flex-col overflow-hidden bg-background\"\n data-testid=\"xlsx-viewer\"\n >\n {/* Sheet tabs */}\n {sheets.length > 0 && (\n <div className=\"flex-shrink-0 flex items-center gap-0.5 px-2 pt-1 border-b bg-muted overflow-x-auto\">\n {sheets.map((sheet) => (\n <button\n key={sheet}\n onClick={() => handleSheetChange(sheet)}\n className={`px-3 py-1 text-sm font-medium whitespace-nowrap rounded-t transition-colors border-x border-t ${\n sheet === activeSheet\n ? 'bg-background text-primary border-border'\n : 'bg-muted text-muted-foreground border-transparent hover:bg-muted hover:text-foreground'\n }`}\n >\n {sheet}\n </button>\n ))}\n </div>\n )}\n\n {/* Spreadsheet table */}\n <div className=\"flex-1 overflow-auto\">\n <table className=\"text-sm border-collapse min-w-full\">\n <tbody>\n {rows.map((row, rowIdx) => (\n <tr\n key={rowIdx}\n className={rowIdx === 0 ? 'bg-muted font-semibold sticky top-0' : 'hover:bg-accent'}\n >\n {/* Row number gutter */}\n <td className=\"border border-border px-1 text-center text-muted-foreground bg-muted select-none w-8 min-w-[2rem]\">\n {rowIdx + 1}\n </td>\n {Array.from({ length: colCount }).map((_, colIdx) => (\n <td\n key={colIdx}\n className=\"border border-border px-2 py-0.5 whitespace-nowrap max-w-[200px] overflow-hidden text-ellipsis\"\n title={String((row as unknown[])[colIdx] ?? '')}\n >\n {String((row as unknown[])[colIdx] ?? '')}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n {rows.length === 0 && (\n <div className=\"flex items-center justify-center p-8 text-sm text-muted-foreground\">\n Empty sheet\n </div>\n )}\n </div>\n </div>\n )\n}\n","/**\n * Processed Chunks Hook\n *\n * Processes raw document chunks into page-grouped structure.\n * Pre-computes footnote inlining so it runs once during processing, not on every render.\n */\n\nimport { useMemo } from 'react'\n\nexport interface RawChunk {\n content: string\n metadata?: {\n page_number?: number\n chunk_doc_idx?: number\n chunk_ext_id?: string\n doc_title?: string | null\n /** Where the chunk sits on its page: [x0, y0, x1, y1] as fractions of the page, top-left origin. */\n page_bbox?: number[] | null\n }\n}\n\nexport interface ProcessedChunk {\n content: string\n chunkIndex: number | undefined\n chunkExtId: string | undefined\n docTitle: string | undefined\n /** Where the chunk sits on its page, as fractions of the page; absent for older parses. */\n pageBbox?: number[]\n}\n\nexport interface ProcessedPage {\n pageNumber: number | null\n chunks: ProcessedChunk[]\n}\n\nexport interface UseProcessedChunksResult {\n processedChunks: ProcessedPage[]\n maxPageNumber: number\n}\n\n/**\n * Replace GFM footnote references [^key] with inline footnote content\n * and strip footnote definition blocks from the chunk text.\n * Uses the pre-parsed footnotes map from the backend.\n */\nfunction inlineFootnotes(content: string, footnotes: Record<string, string>): string {\n if (!footnotes || Object.keys(footnotes).length === 0) return content\n\n let result = content\n\n // Strip GFM footnote definition blocks: [^key]: content (and continuation lines)\n result = result.replace(/^\\[\\^[^\\]]+\\]:[ \\t]+.*(?:\\n(?:[ \\t]+.+)?)*/gm, '')\n\n // Replace footnote references [^key] with superscript + inline content\n result = result.replace(/\\[\\^([^\\]]+)\\]/g, (_match, key) => {\n const fnContent = footnotes[key]\n if (!fnContent) return `<sup class=\"fn-ref\">${key}</sup>`\n const escaped = fnContent\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n return `<sup class=\"fn-ref\">${key}</sup><span class=\"fn-inline\" title=\"${escaped}\">[${escaped}]</span>`\n })\n\n return result.trim()\n}\n\nexport function useProcessedChunks(\n chunks: RawChunk[] | undefined,\n footnotes?: Record<string, string>\n): UseProcessedChunksResult {\n return useMemo(() => {\n if (!chunks || chunks.length === 0) {\n return { processedChunks: [], maxPageNumber: 0 }\n }\n\n const hasFootnotes = footnotes && Object.keys(footnotes).length > 0\n const chunksByPage: ProcessedPage[] = []\n let currentPageNumber = -1\n let currentPageChunks: ProcessedChunk[] = []\n let maxPageNumber = 0\n\n chunks.forEach((chunk) => {\n const pageNum = chunk.metadata?.page_number\n\n // Track max page number\n if (pageNum && pageNum > maxPageNumber) {\n maxPageNumber = pageNum\n }\n\n // If page changed, save previous page and start new one\n if (pageNum !== currentPageNumber) {\n if (currentPageChunks.length > 0) {\n chunksByPage.push({\n pageNumber: currentPageNumber > 0 ? currentPageNumber : null,\n chunks: currentPageChunks,\n })\n }\n currentPageNumber = pageNum ?? -1\n currentPageChunks = []\n }\n\n currentPageChunks.push({\n content: hasFootnotes ? inlineFootnotes(chunk.content, footnotes) : chunk.content,\n chunkIndex: chunk.metadata?.chunk_doc_idx,\n chunkExtId: chunk.metadata?.chunk_ext_id,\n docTitle: chunk.metadata?.doc_title ?? undefined,\n pageBbox: chunk.metadata?.page_bbox ?? undefined,\n })\n })\n\n // Add the last page\n if (currentPageChunks.length > 0) {\n chunksByPage.push({\n pageNumber: currentPageNumber > 0 ? currentPageNumber : null,\n chunks: currentPageChunks,\n })\n }\n\n return { processedChunks: chunksByPage, maxPageNumber }\n }, [chunks, footnotes])\n}\n","/**\n * Contiguous-run grouping for selected passages.\n *\n * Selecting passages 4–9 is one citation, not six. This collapses a flat set of\n * selected chunk ids into the contiguous runs they form in document order, so\n * the viewer can draw each run as a single block with a single \"p.3(4–9)\" label\n * instead of stacking six identical pills.\n *\n * Purely positional: the pages arrive in document order (which is\n * `chunk_doc_idx` order), so adjacency is just \"next in the list\".\n */\n\nexport interface RunChunk {\n chunkExtId: string | undefined\n /** 0-based index within the document; displayed 1-based */\n chunkIndex: number | undefined\n}\n\nexport interface RunPage {\n pageNumber: number | null\n chunks: RunChunk[]\n}\n\n/** Where a selected chunk sits inside its contiguous run of selected chunks. */\nexport interface ChunkRunInfo {\n isStart: boolean\n isEnd: boolean\n /** Set only on the run's first member — the bounds its single label shows. */\n endIndex: number | undefined\n endPage: number | null | undefined\n}\n\nexport function computeSelectionRuns(\n pages: RunPage[],\n selectedChunks: Set<string>\n): Map<string, ChunkRunInfo> {\n const runs = new Map<string, ChunkRunInfo>()\n if (selectedChunks.size === 0) return runs\n\n const flat = pages.flatMap((page) =>\n page.chunks.map((c) => ({ ...c, pageNumber: page.pageNumber }))\n )\n\n let i = 0\n while (i < flat.length) {\n const chunk = flat[i]\n if (!chunk.chunkExtId || !selectedChunks.has(chunk.chunkExtId)) {\n i += 1\n continue\n }\n\n // Walk forward while the neighbours are also selected.\n let end = i\n while (\n end + 1 < flat.length &&\n flat[end + 1].chunkExtId &&\n selectedChunks.has(flat[end + 1].chunkExtId!)\n ) {\n end += 1\n }\n\n const last = flat[end]\n const endIndex = last.chunkIndex !== undefined ? last.chunkIndex + 1 : undefined\n for (let k = i; k <= end; k += 1) {\n const id = flat[k].chunkExtId\n if (!id) continue\n runs.set(id, {\n isStart: k === i,\n isEnd: k === end,\n // Only the run's first member carries the label bounds.\n endIndex: k === i ? endIndex : undefined,\n endPage: k === i ? last.pageNumber : undefined,\n })\n }\n i = end + 1\n }\n\n return runs\n}\n"]}
|
package/dist/viewers/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { PdfViewer, pdfViewerChunk } from './PdfViewer.js';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { RefObject } from 'react';
|
|
4
|
-
|
|
4
|
+
import { P as PdfViewerAssets } from '../PdfViewerImpl.d-CqnEzQO7.js';
|
|
5
|
+
export { a as PdfViewerProps } from '../PdfViewerImpl.d-CqnEzQO7.js';
|
|
5
6
|
import '../lazy-chunk.d-B6YDLMKI.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -211,6 +212,8 @@ interface RawChunk {
|
|
|
211
212
|
chunk_doc_idx?: number;
|
|
212
213
|
chunk_ext_id?: string;
|
|
213
214
|
doc_title?: string | null;
|
|
215
|
+
/** Where the chunk sits on its page: [x0, y0, x1, y1] as fractions of the page, top-left origin. */
|
|
216
|
+
page_bbox?: number[] | null;
|
|
214
217
|
};
|
|
215
218
|
}
|
|
216
219
|
interface ProcessedChunk {
|
|
@@ -218,6 +221,8 @@ interface ProcessedChunk {
|
|
|
218
221
|
chunkIndex: number | undefined;
|
|
219
222
|
chunkExtId: string | undefined;
|
|
220
223
|
docTitle: string | undefined;
|
|
224
|
+
/** Where the chunk sits on its page, as fractions of the page; absent for older parses. */
|
|
225
|
+
pageBbox?: number[];
|
|
221
226
|
}
|
|
222
227
|
interface ProcessedPage {
|
|
223
228
|
pageNumber: number | null;
|
|
@@ -259,4 +264,69 @@ interface ChunkRunInfo {
|
|
|
259
264
|
}
|
|
260
265
|
declare function computeSelectionRuns(pages: RunPage[], selectedChunks: Set<string>): Map<string, ChunkRunInfo>;
|
|
261
266
|
|
|
262
|
-
|
|
267
|
+
/**
|
|
268
|
+
* One rectangle of a PDF page drawn at a chosen pixel width: a presentation clip. It is rendered
|
|
269
|
+
* again from the PDF (vector text, embedded images at their own resolution) for the size it is
|
|
270
|
+
* shown at, never scaled up from a screenshot, so it stays sharp on a large screen.
|
|
271
|
+
*
|
|
272
|
+
* The geometry is here (pure, tested); the pdf.js work (a few at a time, cancellable) is in
|
|
273
|
+
* `pdf-region-impl`, in the PDF engine's chunk, loaded the first time a region renders.
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/** Fractions of the displayed (rotated) page, origin top-left. */
|
|
277
|
+
interface PdfRegionRect {
|
|
278
|
+
x: number;
|
|
279
|
+
y: number;
|
|
280
|
+
w: number;
|
|
281
|
+
h: number;
|
|
282
|
+
}
|
|
283
|
+
interface PdfRegionRequest {
|
|
284
|
+
file: Blob;
|
|
285
|
+
/** 1-based page number. */
|
|
286
|
+
page: number;
|
|
287
|
+
rect: PdfRegionRect;
|
|
288
|
+
/** Width of the output in device pixels. */
|
|
289
|
+
width: number;
|
|
290
|
+
/** Rectangles of the page (same fractions) painted solid black over the output: redactions. */
|
|
291
|
+
masks?: readonly PdfRegionRect[];
|
|
292
|
+
assets?: PdfViewerAssets;
|
|
293
|
+
/** Cap on output pixels (canvas limits, memory). Default 16 megapixels. */
|
|
294
|
+
maxPixels?: number;
|
|
295
|
+
/** Aborting drops the render (before it starts) or cancels it (while it runs). */
|
|
296
|
+
signal?: AbortSignal;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* A rendered region: a bitmap (or, without `createImageBitmap`, a canvas), ready to draw into a
|
|
300
|
+
* canvas in any window. Its `width` × `height` are the output pixels. A bitmap holds memory until
|
|
301
|
+
* closed: `closePdfRegionImage` when it is replaced.
|
|
302
|
+
*/
|
|
303
|
+
type PdfRegionImage = ImageBitmap | HTMLCanvasElement;
|
|
304
|
+
declare function closePdfRegionImage(image: PdfRegionImage | null | undefined): void;
|
|
305
|
+
declare const PDF_REGION_MAX_PIXELS = 16000000;
|
|
306
|
+
/** The scale and output size for a region of a `pageWidth × pageHeight` (points) page. */
|
|
307
|
+
declare function regionGeometry(page: {
|
|
308
|
+
width: number;
|
|
309
|
+
height: number;
|
|
310
|
+
}, rect: PdfRegionRect, width: number, maxPixels?: number): {
|
|
311
|
+
scale: number;
|
|
312
|
+
width: number;
|
|
313
|
+
height: number;
|
|
314
|
+
offsetX: number;
|
|
315
|
+
offsetY: number;
|
|
316
|
+
};
|
|
317
|
+
/** The masks that fall in the region, in output pixels. */
|
|
318
|
+
declare function regionMasks(rect: PdfRegionRect, masks: readonly PdfRegionRect[], out: {
|
|
319
|
+
width: number;
|
|
320
|
+
height: number;
|
|
321
|
+
}): {
|
|
322
|
+
x: number;
|
|
323
|
+
y: number;
|
|
324
|
+
width: number;
|
|
325
|
+
height: number;
|
|
326
|
+
}[];
|
|
327
|
+
/** The region, drawn. */
|
|
328
|
+
declare function renderPdfRegion(request: PdfRegionRequest): Promise<PdfRegionImage>;
|
|
329
|
+
/** Free the PDF engine's copy of a file no clip shows any more. */
|
|
330
|
+
declare function releasePdfRegionSource(file: Blob): void;
|
|
331
|
+
|
|
332
|
+
export { AudioViewer, type AudioViewerProps, type ChunkRunInfo, DocxViewer, type DocxViewerProps, INITIAL_LAZY_LOAD_BUFFER, ImageViewer, type ImageViewerProps, LAZY_LOAD_BUFFER_AFTER, LAZY_LOAD_BUFFER_BEFORE, MAX_ZOOM, MIN_ZOOM, PAGE_SELECTOR, PDF_REGION_MAX_PIXELS, type PdfRegionImage, type PdfRegionRect, type PdfRegionRequest, PdfViewerAssets, type ProcessedChunk, type ProcessedPage, type RawChunk, type RunChunk, type RunPage, type UseProcessedChunksResult, VideoViewer, type VideoViewerProps, XlsxViewer, type XlsxViewerProps, anchorDelta, anchoredScroll, clampZoom, closePdfRegionImage, computeSelectionRuns, cycleZoom, doubleTapZoom, installPdfjsPolyfills, pinchZoom, regionGeometry, regionMasks, releasePdfRegionSource, renderDpr, renderPdfRegion, usePageIntersectionObserver, usePinchZoom, useProcessedChunks, useScrollAnchor, zoomLabel };
|