@arbidocs/react 0.3.185 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YJAYST7S.js → chunk-3CLGHHME.js} +880 -240
- package/dist/chunk-3CLGHHME.js.map +1 -0
- package/dist/chunk-6ALMBER7.js +176 -0
- package/dist/chunk-6ALMBER7.js.map +1 -0
- package/dist/chunk-BXP6S34V.cjs +284 -0
- package/dist/chunk-BXP6S34V.cjs.map +1 -0
- package/dist/chunk-EJ2BMHYK.js +272 -0
- package/dist/chunk-EJ2BMHYK.js.map +1 -0
- package/dist/{chunk-IZPXHVPJ.cjs → chunk-OU2QLIKS.cjs} +969 -344
- package/dist/chunk-OU2QLIKS.cjs.map +1 -0
- package/dist/chunk-RZQACYNQ.cjs +218 -0
- package/dist/chunk-RZQACYNQ.cjs.map +1 -0
- package/dist/{index-4WwLZsQO.d.cts → index-CcbVSNSP.d.cts} +40 -2
- package/dist/{index-4WwLZsQO.d.ts → index-CcbVSNSP.d.ts} +40 -2
- package/dist/index.cjs +589 -1070
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -155
- package/dist/index.d.ts +11 -155
- package/dist/index.js +223 -725
- package/dist/index.js.map +1 -1
- package/dist/shell/index.cjs +13 -4
- package/dist/shell/index.d.cts +1 -1
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/index.js +2 -1
- package/dist/ui/index.cjs +211 -190
- package/dist/ui/index.d.cts +204 -3
- package/dist/ui/index.d.ts +204 -3
- package/dist/ui/index.js +2 -1
- package/dist/viewers/index.cjs +327 -76
- package/dist/viewers/index.cjs.map +1 -1
- package/dist/viewers/index.d.cts +90 -4
- package/dist/viewers/index.d.ts +90 -4
- package/dist/viewers/index.js +316 -78
- package/dist/viewers/index.js.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-3MLQUKT4.cjs +0 -97
- package/dist/chunk-3MLQUKT4.cjs.map +0 -1
- package/dist/chunk-IZPXHVPJ.cjs.map +0 -1
- package/dist/chunk-J3XEKOV5.js +0 -87
- package/dist/chunk-J3XEKOV5.js.map +0 -1
- package/dist/chunk-YJAYST7S.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/viewers/usePageIntersectionObserver.ts","../../src/viewers/pdf-viewer-constants.ts","../../src/viewers/PdfViewer.tsx","../../src/viewers/DocxViewer.tsx","../../src/viewers/XlsxViewer.tsx","../../src/viewers/DocumentViewer.tsx"],"names":["useEffect","useRef","useState","jsxs","jsx","useMemo","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["import { useEffect, RefObject } from 'react'\n\n// Page synchronization constants\nconst PAGE_UPDATE_DEBOUNCE_MS = 10 // Delay before updating page number after scroll (10ms)\nconst MIN_VISIBILITY_THRESHOLD = 0.15 // Minimum visibility (15%) to consider page \"visible\"\nconst INTERSECTION_THRESHOLDS = [0, 0.25, 0.5, 0.75, 1.0] // IntersectionObserver thresholds\n\ninterface UsePageIntersectionObserverOptions {\n /** Container element that scrolls */\n containerRef: RefObject<HTMLElement | null>\n /** Ref tracking whether initial scroll has completed */\n scrollCompleteRef: RefObject<boolean>\n /** Whether the observer should be active */\n isEnabled: boolean\n /** Function to get page elements to observe */\n getPageElements: () => Element[]\n /** Function to extract page number from element */\n getPageNumber: (element: Element) => number\n /** Callback when page number changes */\n onPageChange: (pageNumber: number) => void\n /** Optional callback with visibility data for custom logic (e.g., lazy loading) */\n onVisibilityUpdate?: (visibilityMap: Map<number, number>) => void\n}\n\n/**\n * Custom hook to track visible pages using IntersectionObserver.\n * Used for bidirectional page synchronization in document viewers.\n */\nexport function usePageIntersectionObserver({\n containerRef,\n scrollCompleteRef,\n isEnabled,\n getPageElements,\n getPageNumber,\n onPageChange,\n onVisibilityUpdate,\n}: UsePageIntersectionObserverOptions) {\n useEffect(() => {\n if (!isEnabled || !containerRef.current) return\n\n const container = containerRef.current\n const visibilityMap = new Map<number, number>()\n let lastReportedPage: number | null = null\n let updateTimeout: ReturnType<typeof setTimeout> | null = null\n\n const updatePageNumber = () => {\n // Find page with highest visibility\n let mostVisiblePage = 1\n let maxVisibility = 0\n visibilityMap.forEach((ratio, pageNum) => {\n if (ratio > maxVisibility) {\n maxVisibility = ratio\n mostVisiblePage = pageNum\n }\n })\n\n // Only update page number if scroll is complete and page changed\n if (\n scrollCompleteRef.current &&\n mostVisiblePage !== lastReportedPage &&\n maxVisibility > MIN_VISIBILITY_THRESHOLD\n ) {\n lastReportedPage = mostVisiblePage\n onPageChange(mostVisiblePage)\n }\n\n // Call optional visibility update callback (e.g., for lazy loading)\n if (onVisibilityUpdate) {\n onVisibilityUpdate(new Map(visibilityMap))\n }\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n // Update visibility map\n entries.forEach((entry) => {\n const pageNum = getPageNumber(entry.target)\n if (pageNum > 0) {\n visibilityMap.set(pageNum, entry.intersectionRatio)\n }\n })\n\n // Debounce updates\n if (updateTimeout) {\n clearTimeout(updateTimeout)\n }\n updateTimeout = setTimeout(updatePageNumber, PAGE_UPDATE_DEBOUNCE_MS)\n },\n {\n root: container,\n threshold: INTERSECTION_THRESHOLDS,\n }\n )\n\n // Observe all page elements\n const elements = getPageElements()\n elements.forEach((element) => observer.observe(element))\n\n return () => {\n observer.disconnect()\n if (updateTimeout) {\n clearTimeout(updateTimeout)\n }\n }\n }, [\n containerRef,\n scrollCompleteRef,\n isEnabled,\n getPageElements,\n getPageNumber,\n onPageChange,\n onVisibilityUpdate,\n ])\n}\n","/** Pages to render before the visible area (canvas pre-load buffer) */\nexport const LAZY_LOAD_BUFFER_BEFORE = 2\n\n/** Pages to render after the visible area (canvas pre-load buffer) */\nexport const LAZY_LOAD_BUFFER_AFTER = 5\n\n/**\n * Smaller render window used on the very first paint so time-to-first-visible-page is\n * fast. Expanded to LAZY_LOAD_BUFFER_BEFORE / LAZY_LOAD_BUFFER_AFTER once the browser\n * is idle (via requestIdleCallback / setTimeout fallback).\n */\nexport const INITIAL_LAZY_LOAD_BUFFER = { before: 0, after: 1 }\n","/**\n * PdfViewer — 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 — 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 } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\nimport 'react-pdf/dist/Page/AnnotationLayer.css'\nimport 'react-pdf/dist/Page/TextLayer.css'\nimport { usePageIntersectionObserver } from './usePageIntersectionObserver'\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/** Configure the pdf.js worker before any Document mounts; re-set only if it changed. */\nfunction ensurePdfWorker(workerSrc: string) {\n if (pdfjs.GlobalWorkerOptions.workerSrc !== workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerSrc\n }\n}\n\n// Page rendering constants\nconst CONTAINER_PADDING_PX = 32 // Total horizontal padding (p-4 = 16px on each side)\nconst PAGE_ASPECT_RATIO = 1.414 // Standard A4 page aspect ratio (√2)\n\n// Text layer is enabled for pages within 1 page of the visible set — enough for smooth\n// scrolling while keeping DOM node count low on large documents.\nconst TEXT_LAYER_BUFFER = 1\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 /**\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\nexport function PdfViewer({\n file,\n currentPage,\n onLoadSuccess,\n scrollTrigger,\n onPageChange,\n disableFontFace = false,\n assets,\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 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 — 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 // 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 ({ numPages: n }: { numPages: number }) => {\n setNumPages(n)\n setLoadError(null) // Clear any previous errors\n\n // Expand lazy-load buffer once the main thread is idle after first paint.\n // Falls back to setTimeout(500ms) in environments where requestIdleCallback\n // is not available (e.g. Safari < 16).\n const expand = () => {\n setRenderedPages((prev) => {\n if (prev.size === 0) return prev\n const newSet = new Set(prev)\n // Always include at least the pages around page 1 at full buffer size\n const anchor = currentPage || 1\n for (\n let i = Math.max(1, anchor - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(n, anchor + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n }\n\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(expand, { timeout: 500 })\n } else {\n setTimeout(expand, 500)\n }\n\n try {\n onLoadSuccess?.(n)\n } catch (error) {\n console.error('Error in onLoadSuccess callback:', error)\n }\n },\n [onLoadSuccess, currentPage]\n )\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 — 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 → 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 // Measure container width for responsive sizing using ResizeObserver\n useEffect(() => {\n if (!containerRef.current) return\n\n const updateWidth = () => {\n if (containerRef.current) {\n setContainerWidth(containerRef.current.offsetWidth - CONTAINER_PADDING_PX)\n }\n }\n\n updateWidth()\n\n // Use ResizeObserver to detect container size changes (e.g., panel divider resize)\n const resizeObserver = new ResizeObserver(updateWidth)\n resizeObserver.observe(containerRef.current)\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 // Scroll to page when scrollTrigger changes (user entered a page number)\n useEffect(() => {\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, currentPage, 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)\n const pagesToRender = new Set<number>()\n for (\n let i = Math.max(1, minVisible - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(numPages, maxVisible + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n pagesToRender.add(i)\n }\n setRenderedPages(pagesToRender)\n\n // Update text-layer set (narrow window — 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(nearViewport)\n }\n },\n [numPages]\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 })\n\n return (\n <div\n ref={containerRef}\n className=\"w-full h-full overflow-y-auto overflow-x-hidden bg-muted flex flex-col items-center p-4\"\n role=\"region\"\n aria-label=\"PDF document viewer\"\n data-testid=\"pdf-viewer\"\n >\n <Document\n key={documentKey}\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 pageHeight = containerWidth * PAGE_ASPECT_RATIO\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 — 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 className=\"mb-6 shadow-xl bg-white border border-border\"\n style={!shouldRender ? { minHeight: pageHeight } : undefined}\n role=\"article\"\n aria-label={`Page ${pageNumber} of ${numPages}`}\n >\n {shouldRender ? (\n <Page\n pageNumber={pageNumber}\n width={containerWidth}\n renderTextLayer={shouldRenderTextLayer}\n renderAnnotationLayer={false}\n // Cap DPR at 2× — retina/hi-DPR displays otherwise render at 3× or\n // higher, multiplying raster work by up to 9× vs 1×. At 2× the\n // quality difference is imperceptible at normal zoom levels.\n devicePixelRatio={Math.min(window.devicePixelRatio || 1, 2)}\n loading={\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: containerWidth, height: pageHeight }}\n >\n <div className=\"text-sm text-muted-foreground\">\n Loading page {pageNumber}...\n </div>\n </div>\n }\n />\n ) : (\n <div\n className=\"flex items-center justify-center bg-muted\"\n style={{ width: containerWidth, height: pageHeight }}\n >\n <div className=\"text-sm text-muted-foreground\">Page {pageNumber}</div>\n </div>\n )}\n </div>\n )\n })}\n </Document>\n </div>\n )\n}\n","/**\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 * DocumentViewer — render an ARBI document as it actually looks.\n *\n * The individual viewers in this module each take a `Blob`. Getting from a\n * document to the right viewer means: work out the file type, download the\n * original, pick a renderer, and handle loading, failure and \"there is no\n * native view for this type\". Every consumer would otherwise write that same\n * dispatch, so it lives here.\n *\n * Pairs with `DocumentReview` from the root entry, which renders the extracted\n * text with AI citation highlighting. A review UI wants both: the native page is\n * what a person must see before making a call on a document; the text view is\n * where citations and search hits live.\n */\n\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport type { components } from '@arbidocs/client'\n\nimport { useArbi } from '../useArbi'\nimport { PdfViewer, type PdfViewerAssets } from './PdfViewer'\nimport { DocxViewer } from './DocxViewer'\nimport { XlsxViewer } from './XlsxViewer'\nimport { ImageViewer } from './ImageViewer'\nimport { AudioViewer } from './AudioViewer'\nimport { VideoViewer } from './VideoViewer'\n\ntype DocResponse = components['schemas']['DocResponse']\n\n/** Which native renderer a file needs; `none` when there is no native view. */\nexport type NativeViewerKind = 'pdf' | 'docx' | 'xlsx' | 'image' | 'audio' | 'video' | 'none'\n\nconst BY_EXTENSION: Record<string, NativeViewerKind> = {\n pdf: 'pdf',\n doc: 'docx',\n docx: 'docx',\n xls: 'xlsx',\n xlsx: 'xlsx',\n csv: 'xlsx',\n png: 'image',\n jpg: 'image',\n jpeg: 'image',\n gif: 'image',\n webp: 'image',\n bmp: 'image',\n tif: 'image',\n tiff: 'image',\n mp3: 'audio',\n wav: 'audio',\n m4a: 'audio',\n ogg: 'audio',\n mp4: 'video',\n mov: 'video',\n webm: 'video',\n avi: 'video',\n}\n\n/**\n * Which viewer a document needs. Extension first (it is what the user sees and\n * what ARBI preserves), falling back to the sniffed `file_type` — ARBI\n * identifies by digital signature, so a mislabelled file still renders.\n */\nexport function nativeViewerKind(doc: Pick<DocResponse, 'file_name' | 'file_type'> | undefined) {\n const name = (doc?.file_name ?? '').toLowerCase()\n const ext = name.includes('.') ? name.slice(name.lastIndexOf('.') + 1) : ''\n if (BY_EXTENSION[ext]) return BY_EXTENSION[ext]\n\n const type = (doc?.file_type ?? '').toLowerCase()\n if (!type) return 'none'\n if (type.includes('pdf')) return 'pdf'\n if (type.includes('word') || type.includes('officedocument.wordprocessing')) return 'docx'\n if (type.includes('sheet') || type.includes('excel') || type.includes('csv')) return 'xlsx'\n if (type.startsWith('image/')) return 'image'\n if (type.startsWith('audio/')) return 'audio'\n if (type.startsWith('video/')) return 'video'\n return 'none'\n}\n\nexport interface DocumentViewerProps {\n /** The document to render. */\n doc: Pick<DocResponse, 'external_id' | 'file_name' | 'file_type'> | undefined\n /** Where the app serves the pdf.js worker, cmaps and standard fonts from. */\n pdfAssets?: PdfViewerAssets\n /** Reported as the user scrolls a paged document. */\n onPageChange?: (page: number) => void\n /**\n * Page to show. Paired with `scrollTrigger` this drives a page-number control:\n * a viewer without one is an endless scroll with no way to say \"go to 14\".\n */\n currentPage?: number\n /** Increment to scroll to `currentPage` — lets the same value be re-applied. */\n scrollTrigger?: number\n /** Page count, once the document has loaded. Needed to render \"of N\". */\n onLoadSuccess?: (numPages: number) => void\n /** Rendered when the file type has no native viewer. */\n fallback?: ReactNode\n /** Rendered while the original is downloading. */\n loading?: ReactNode\n /** Rendered when the download or decode fails. Receives the message. */\n errorRender?: (message: string) => ReactNode\n className?: string\n}\n\nexport function DocumentViewer({\n doc,\n pdfAssets,\n onPageChange,\n currentPage,\n scrollTrigger,\n onLoadSuccess,\n fallback,\n loading,\n errorRender,\n className,\n}: DocumentViewerProps) {\n const arbi = useArbi()\n const [blob, setBlob] = useState<Blob | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n const kind = useMemo(() => nativeViewerKind(doc), [doc])\n const docId = doc?.external_id\n\n useEffect(() => {\n if (!docId || kind === 'none') {\n setBlob(null)\n return\n }\n let cancelled = false\n setBlob(null)\n setError(null)\n\n arbi.documents\n .download(docId)\n .then((res: Response) => res.blob())\n .then((b) => {\n if (!cancelled) setBlob(b)\n })\n .catch((err: unknown) => {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Could not load the file')\n })\n\n return () => {\n cancelled = true\n }\n }, [arbi, docId, kind])\n\n if (!doc) return null\n\n if (kind === 'none') {\n return (\n <>\n {fallback ?? (\n <div className=\"grid h-full place-items-center p-6 text-center text-sm text-muted-foreground\">\n No native view for this file type. The original is preserved and can be downloaded.\n </div>\n )}\n </>\n )\n }\n\n if (error) {\n return (\n <>\n {errorRender?.(error) ?? (\n <div className=\"grid h-full place-items-center p-6 text-center\">\n <div>\n <p className=\"text-sm font-medium text-destructive\">Could not load the original</p>\n <p className=\"mt-1 text-sm text-muted-foreground\">{error}</p>\n </div>\n </div>\n )}\n </>\n )\n }\n\n if (!blob) {\n return (\n <>\n {loading ?? (\n <div className=\"grid h-full place-items-center text-sm text-muted-foreground\">\n Loading the original…\n </div>\n )}\n </>\n )\n }\n\n const title = doc.file_name ?? doc.external_id\n const body = (() => {\n switch (kind) {\n case 'pdf':\n return (\n <PdfViewer\n file={blob}\n assets={pdfAssets}\n onPageChange={onPageChange}\n currentPage={currentPage}\n scrollTrigger={scrollTrigger}\n onLoadSuccess={onLoadSuccess}\n />\n )\n case 'docx':\n return <DocxViewer blob={blob} />\n case 'xlsx':\n return <XlsxViewer blob={blob} />\n case 'image':\n return <ImageViewer blob={blob} alt={title} />\n case 'audio':\n return <AudioViewer blob={blob} title={title} />\n case 'video':\n return <VideoViewer blob={blob} title={title} />\n default:\n return null\n }\n })()\n\n return className ? (\n <div className={className} data-testid=\"document-viewer\">\n {body}\n </div>\n ) : (\n body\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/viewers/page-scroll.ts","../../src/viewers/usePageIntersectionObserver.ts","../../src/viewers/viewer-zoom.ts","../../src/viewers/pdf-viewer-constants.ts","../../src/viewers/PdfViewer.tsx","../../src/viewers/DocxViewer.tsx","../../src/viewers/XlsxViewer.tsx","../../src/viewers/DocumentViewer.tsx"],"names":["useEffect","distance","useRef","useCallback","currentPage","ratio","useState","useLayoutEffect","jsxs","jsx","useMemo","Fragment"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Scroll stability for page-stacked viewers (PDF + parsed/HTML).\n *\n * Pages are lazy: their height can change after the user is already looking at something further\n * down (a placeholder replaced by the real page, a late canvas). Browsers that implement scroll\n * anchoring (Chromium) hide that; Safari/WebKit does not, so the content visibly jumps under the\n * finger and momentum scrolling is cut short. The viewers therefore do their own anchoring, the\n * same way on every engine: native anchoring is switched off and a page that changes height\n * entirely ABOVE the viewport shifts `scrollTop` by exactly that change.\n */\n\nimport { useEffect } from 'react'\nimport type { RefObject } from 'react'\n\n/** One page of a stacked viewer (both viewers mark pages like this). */\nexport const PAGE_SELECTOR = '[role=\"article\"][data-page-number]'\n\n/**\n * How far to move `scrollTop` after a page changed height from `previousHeight` to `nextHeight`.\n * Only a page that lay completely above the visible top edge (`containerTop`) pushes the content\n * the user is reading; anything at or below it just grows or shrinks away from the viewport.\n *\n * @param pageTop viewport-relative top of the page (unchanged by its own resize)\n */\nexport function anchorDelta(\n previousHeight: number,\n nextHeight: number,\n pageTop: number,\n containerTop: number\n): number {\n const delta = nextHeight - previousHeight\n if (delta === 0) return 0\n return pageTop + previousHeight <= containerTop + 1 ? delta : 0\n}\n\nexport interface PageBox {\n n: number\n top: number\n bottom: number\n}\n\n/**\n * Which page is being read: the one showing the most pixels inside [viewTop, viewBottom] (the\n * first on a tie). `score` is those pixels relative to the smaller of the page and the viewport,\n * so a page much taller than the screen can still count as \"mostly visible\". `visibility` maps\n * every page that shows any pixel to its visible fraction (for lazy loading).\n */\nexport function measureVisiblePages(\n pages: readonly PageBox[],\n viewTop: number,\n viewBottom: number\n): { page: number | null; score: number; visibility: Map<number, number> } {\n const visibility = new Map<number, number>()\n let page: number | null = null\n let bestPx = 0\n let score = 0\n const viewHeight = viewBottom - viewTop\n for (const p of pages) {\n const height = p.bottom - p.top\n const px = Math.min(p.bottom, viewBottom) - Math.max(p.top, viewTop)\n if (px <= 0 || height <= 0) continue\n visibility.set(p.n, px / height)\n if (px > bestPx) {\n bestPx = px\n page = p.n\n score = px / Math.min(height, viewHeight)\n }\n }\n return { page, score, visibility }\n}\n\n/**\n * Keep the reading position when pages above it change height. `key` re-scans for pages when the\n * page set changes (page count, first layout).\n */\nexport function useScrollAnchor(containerRef: RefObject<HTMLElement | null>, key: unknown): void {\n useEffect(() => {\n const container = containerRef.current\n if (!container || typeof ResizeObserver === 'undefined') return\n container.style.overflowAnchor = 'none'\n\n const heights = new Map<Element, number>()\n const observer = new ResizeObserver((entries) => {\n let shift = 0\n const containerTop = container.getBoundingClientRect().top\n for (const entry of entries) {\n const el = entry.target\n const height = el.getBoundingClientRect().height\n const previous = heights.get(el)\n heights.set(el, height)\n if (previous === undefined) continue\n shift += anchorDelta(previous, height, el.getBoundingClientRect().top, containerTop)\n }\n // A zoom change re-anchors the scroll position itself (see usePinchZoom).\n if (shift !== 0 && !container.dataset.zooming) container.scrollTop += shift\n })\n container.querySelectorAll(PAGE_SELECTOR).forEach((el) => {\n heights.set(el, el.getBoundingClientRect().height)\n observer.observe(el)\n })\n return () => observer.disconnect()\n }, [containerRef, key])\n}\n","import { useEffect, useRef, RefObject } from 'react'\nimport { measureVisiblePages, type PageBox } from './page-scroll'\n\n// Page synchronization constants\nconst PAGE_UPDATE_DEBOUNCE_MS = 10 // Delay before updating page number after scroll (10ms)\nconst MIN_VISIBILITY_THRESHOLD = 0.15 // Minimum visibility (15%) to consider page \"visible\"\nconst INTERSECTION_THRESHOLDS = [0, 0.25, 0.5, 0.75, 1.0] // IntersectionObserver thresholds\n\ninterface UsePageIntersectionObserverOptions {\n /** Container element that scrolls */\n containerRef: RefObject<HTMLElement | null>\n /** Ref tracking whether initial scroll has completed */\n scrollCompleteRef: RefObject<boolean>\n /** Whether the observer should be active */\n isEnabled: boolean\n /** Function to get page elements to observe */\n getPageElements: () => Element[]\n /** Function to extract page number from element */\n getPageNumber: (element: Element) => number\n /** Callback when page number changes */\n onPageChange: (pageNumber: number) => void\n /** Optional callback with visibility data for custom logic (e.g., lazy loading) */\n onVisibilityUpdate?: (visibilityMap: Map<number, number>) => void\n /**\n * Re-subscribe when this changes (the set of page elements: page count, first layout). Callers\n * may pass fresh inline callbacks every render: they are read through refs and never cause a\n * re-subscribe (a re-subscribe re-delivers every page and, with a state-setting callback, loops).\n */\n observeKey?: unknown\n}\n\n/**\n * Custom hook to track the visible page of a page-stacked viewer.\n * Used for bidirectional page synchronization in document viewers.\n *\n * IntersectionObserver wakes it when pages enter or leave the viewport; a passive scroll listener\n * (at most one measurement per frame) keeps it current in between. The page itself is chosen from\n * live geometry (see `measureVisiblePages`).\n */\nexport function usePageIntersectionObserver({\n containerRef,\n scrollCompleteRef,\n isEnabled,\n getPageElements,\n getPageNumber,\n onPageChange,\n onVisibilityUpdate,\n observeKey,\n}: UsePageIntersectionObserverOptions) {\n const latest = useRef({ getPageElements, getPageNumber, onPageChange, onVisibilityUpdate })\n latest.current = { getPageElements, getPageNumber, onPageChange, onVisibilityUpdate }\n\n useEffect(() => {\n if (!isEnabled || !containerRef.current) return\n\n const container = containerRef.current\n let lastReportedPage: number | null = null\n let updateTimeout: ReturnType<typeof setTimeout> | null = null\n let frame = 0\n\n // Read the live geometry rather than IntersectionObserver ratios: a ratio is relative to the\n // page's own height, so a zoomed page much taller than the screen never reaches the threshold\n // (and ratios only update on a few crossings, which is too coarse for tall pages).\n const evaluate = () => {\n const root = container.getBoundingClientRect()\n const pages: PageBox[] = []\n for (const el of latest.current.getPageElements()) {\n const n = latest.current.getPageNumber(el)\n if (n <= 0) continue\n const r = el.getBoundingClientRect()\n pages.push({ n, top: r.top, bottom: r.bottom })\n }\n const { page, score, visibility } = measureVisiblePages(pages, root.top, root.bottom)\n\n // Only report when the scroll is complete and the page changed\n if (\n scrollCompleteRef.current &&\n page !== null &&\n page !== lastReportedPage &&\n score > MIN_VISIBILITY_THRESHOLD\n ) {\n lastReportedPage = page\n latest.current.onPageChange(page)\n }\n\n // Call optional visibility update callback (e.g., for lazy loading)\n latest.current.onVisibilityUpdate?.(visibility)\n }\n\n const observer = new IntersectionObserver(\n () => {\n // Debounce updates\n if (updateTimeout) clearTimeout(updateTimeout)\n updateTimeout = setTimeout(evaluate, PAGE_UPDATE_DEBOUNCE_MS)\n },\n { root: container, threshold: INTERSECTION_THRESHOLDS }\n )\n // At most one measurement per frame while scrolling; nothing is stored in React state here.\n const onScroll = () => {\n if (!frame) {\n frame = requestAnimationFrame(() => {\n frame = 0\n evaluate()\n })\n }\n }\n container.addEventListener('scroll', onScroll, { passive: true })\n\n // Observe all page elements\n latest.current.getPageElements().forEach((element) => observer.observe(element))\n\n return () => {\n observer.disconnect()\n container.removeEventListener('scroll', onScroll)\n if (updateTimeout) clearTimeout(updateTimeout)\n if (frame) cancelAnimationFrame(frame)\n }\n }, [containerRef, scrollCompleteRef, isEnabled, observeKey])\n}\n","/**\n * Zoom for page-stacked viewers (PDF + parsed/HTML).\n *\n * Browser pinch-zoom only magnifies the bitmap the page already painted: a PDF canvas rendered at\n * fit-width stays blurry however far you pinch. The viewers therefore own the zoom: `zoom` is a\n * multiplier of the fit-width size (1 = fit width, 2 = twice as wide). The PDF viewer re-renders\n * its canvases at the new scale; the parsed viewer reflows its text. This module holds the pure\n * math and the touch gesture hook (pinch, double-tap) both use.\n */\n\nimport { useCallback, useEffect, useLayoutEffect, useRef } from 'react'\nimport type { RefObject } from 'react'\n\nexport const MIN_ZOOM = 0.5\nexport const MAX_ZOOM = 4\nexport const ZOOM_STEP = 1.25\nexport const DOUBLE_TAP_ZOOM = 2\n/** Canvas pixel budget per page: iOS Safari fails above ~16.7M pixels in total, so stay well under. */\nexport const MAX_CANVAS_PIXELS = 8_000_000\n/** Device pixel ratio is capped: beyond 2x the extra sharpness is invisible and costs 2-3x memory. */\nexport const MAX_RENDER_DPR = 2\n\nexport function clampZoom(zoom: number): number {\n if (!Number.isFinite(zoom)) return 1\n return Math.round(Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom)) * 100) / 100\n}\n\n/** One zoom button step in (`1`) or out (`-1`). */\nexport function stepZoom(zoom: number, direction: 1 | -1): number {\n return clampZoom(direction === 1 ? zoom * ZOOM_STEP : zoom / ZOOM_STEP)\n}\n\n/** Double-tap toggles between fit width and a comfortable reading zoom. */\nexport function doubleTapZoom(zoom: number): number {\n return zoom > 1.05 ? 1 : DOUBLE_TAP_ZOOM\n}\n\nexport function zoomLabel(zoom: number): string {\n return `${Math.round(zoom * 100)}%`\n}\n\n/** The zoom a pinch has reached: the start zoom scaled by how far the fingers moved apart. */\nexport function pinchZoom(startZoom: number, startDistance: number, distance: number): number {\n if (startDistance <= 0) return startZoom\n return clampZoom((startZoom * distance) / startDistance)\n}\n\n/**\n * New scroll offset that keeps the content point under `focal` (a viewport coordinate) still while\n * the zoom changes from `oldZoom` to `newZoom`.\n */\nexport function anchoredScroll(\n scroll: number,\n focal: number,\n oldZoom: number,\n newZoom: number\n): number {\n if (oldZoom <= 0) return scroll\n return ((scroll + focal) * newZoom) / oldZoom - focal\n}\n\n/**\n * Device pixel ratio to rasterise a page of `cssWidth` x `cssHeight` at: the device's own, capped,\n * and lowered further when the page would otherwise exceed the canvas pixel budget.\n */\nexport function renderDpr(\n cssWidth: number,\n cssHeight: number,\n devicePixelRatio: number,\n maxPixels: number = MAX_CANVAS_PIXELS\n): number {\n const wanted = Math.min(Math.max(devicePixelRatio || 1, 1), MAX_RENDER_DPR)\n const area = cssWidth * cssHeight\n if (area <= 0) return wanted\n const fits = Math.sqrt(maxPixels / area)\n return Math.max(1, Math.min(wanted, fits))\n}\n\nconst distance = (a: Touch, b: Touch) => Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY)\nconst INTERACTIVE = 'button, a, input, textarea, select, [role=\"button\"]'\nconst DOUBLE_TAP_MS = 300\nconst DOUBLE_TAP_SLOP_PX = 30\n\ninterface PinchZoomOptions {\n containerRef: RefObject<HTMLElement | null>\n zoom: number\n onZoomChange?: (zoom: number) => void\n}\n\n/**\n * Pinch and double-tap zoom on a scroller, plus focal-point preservation for EVERY zoom change\n * (gesture, buttons, props): after the new zoom has laid out, the scroll offset is moved so the\n * content under the pinch centre (or the viewport centre) stays where it was.\n *\n * The scroller must carry `touch-action: pan-x pan-y` so the browser leaves two-finger gestures\n * to this hook instead of zooming the whole app.\n */\nexport function usePinchZoom({ containerRef, zoom, onZoomChange }: PinchZoomOptions): void {\n const zoomRef = useRef(zoom)\n const onChangeRef = useRef(onZoomChange)\n onChangeRef.current = onZoomChange\n const focalRef = useRef<{ x: number; y: number } | null>(null)\n const appliedZoomRef = useRef(zoom)\n\n const request = useCallback((next: number, focal: { x: number; y: number } | null) => {\n const clamped = clampZoom(next)\n if (clamped === zoomRef.current) return\n focalRef.current = focal\n zoomRef.current = clamped\n onChangeRef.current?.(clamped)\n }, [])\n\n // Zoom changed (from here or from outside): keep the focal point still once it has laid out.\n useLayoutEffect(() => {\n zoomRef.current = zoom\n const container = containerRef.current\n const previous = appliedZoomRef.current\n appliedZoomRef.current = zoom\n if (!container || previous === zoom) return\n const rect = container.getBoundingClientRect()\n const focal = focalRef.current ?? { x: rect.width / 2, y: rect.height / 2 }\n focalRef.current = null\n // The page-anchoring observer must not also react to this resize.\n container.dataset.zooming = 'true'\n container.scrollLeft = anchoredScroll(container.scrollLeft, focal.x, previous, zoom)\n container.scrollTop = anchoredScroll(container.scrollTop, focal.y, previous, zoom)\n requestAnimationFrame(() =>\n requestAnimationFrame(() => {\n delete container.dataset.zooming\n })\n )\n }, [zoom, containerRef])\n\n useEffect(() => {\n const el = containerRef.current\n if (!el) return\n let pinch: { startDistance: number; startZoom: number } | null = null\n let lastTap: { time: number; x: number; y: number } | null = null\n let frame = 0\n let pending: { zoom: number; focal: { x: number; y: number } } | null = null\n\n const focalOf = (a: Touch, b: Touch) => {\n const rect = el.getBoundingClientRect()\n return {\n x: (a.clientX + b.clientX) / 2 - rect.left,\n y: (a.clientY + b.clientY) / 2 - rect.top,\n }\n }\n const flush = () => {\n frame = 0\n if (pending) request(pending.zoom, pending.focal)\n pending = null\n }\n\n const onStart = (e: TouchEvent) => {\n if (e.touches.length === 2) {\n pinch = { startDistance: distance(e.touches[0], e.touches[1]), startZoom: zoomRef.current }\n lastTap = null\n }\n }\n const onMove = (e: TouchEvent) => {\n if (!pinch || e.touches.length !== 2) return\n e.preventDefault()\n pending = {\n zoom: pinchZoom(pinch.startZoom, pinch.startDistance, distance(e.touches[0], e.touches[1])),\n focal: focalOf(e.touches[0], e.touches[1]),\n }\n if (!frame) frame = requestAnimationFrame(flush)\n }\n const onEnd = (e: TouchEvent) => {\n if (pinch && e.touches.length < 2) {\n pinch = null\n return\n }\n if (e.touches.length !== 0 || e.changedTouches.length !== 1) return\n const t = e.changedTouches[0]\n if ((e.target as Element | null)?.closest?.(INTERACTIVE)) return\n const now = e.timeStamp\n if (\n lastTap &&\n now - lastTap.time < DOUBLE_TAP_MS &&\n Math.hypot(t.clientX - lastTap.x, t.clientY - lastTap.y) < DOUBLE_TAP_SLOP_PX\n ) {\n e.preventDefault()\n const rect = el.getBoundingClientRect()\n request(doubleTapZoom(zoomRef.current), {\n x: t.clientX - rect.left,\n y: t.clientY - rect.top,\n })\n lastTap = null\n } else {\n lastTap = { time: now, x: t.clientX, y: t.clientY }\n }\n }\n\n el.addEventListener('touchstart', onStart, { passive: true })\n el.addEventListener('touchmove', onMove, { passive: false })\n el.addEventListener('touchend', onEnd, { passive: false })\n el.addEventListener('touchcancel', onEnd, { passive: false })\n return () => {\n el.removeEventListener('touchstart', onStart)\n el.removeEventListener('touchmove', onMove)\n el.removeEventListener('touchend', onEnd)\n el.removeEventListener('touchcancel', onEnd)\n if (frame) cancelAnimationFrame(frame)\n }\n }, [containerRef, request])\n}\n","/** Pages to render before the visible area (canvas pre-load buffer) */\nexport const LAZY_LOAD_BUFFER_BEFORE = 2\n\n/** Pages to render after the visible area (canvas pre-load buffer) */\nexport const LAZY_LOAD_BUFFER_AFTER = 5\n\n/**\n * Smaller render window used on the very first paint so time-to-first-visible-page is\n * fast. Expanded to LAZY_LOAD_BUFFER_BEFORE / LAZY_LOAD_BUFFER_AFTER once the browser\n * is idle (via requestIdleCallback / setTimeout fallback).\n */\nexport const INITIAL_LAZY_LOAD_BUFFER = { before: 0, after: 1 }\n","/**\n * PdfViewer — 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 — 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 } from 'react'\nimport { Document, Page, pdfjs } from 'react-pdf'\nimport 'react-pdf/dist/Page/AnnotationLayer.css'\nimport 'react-pdf/dist/Page/TextLayer.css'\nimport { usePageIntersectionObserver } from './usePageIntersectionObserver'\nimport { useScrollAnchor } from './page-scroll'\nimport { 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/** Configure the pdf.js worker before any Document mounts; re-set only if it changed. */\nfunction ensurePdfWorker(workerSrc: string) {\n if (pdfjs.GlobalWorkerOptions.workerSrc !== workerSrc) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerSrc\n }\n}\n\n// Page rendering constants\n// Horizontal space the page canvas does not get: p-4 on each side (32) + the page wrapper's 1px\n// borders (2). A fit-width page then fills the scroller exactly, with no sideways overflow.\nconst CONTAINER_PADDING_PX = 34\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 (√2)\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 — 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\nexport function PdfViewer({\n file,\n currentPage,\n onLoadSuccess,\n scrollTrigger,\n zoom = 1,\n onZoomChange,\n onPageChange,\n disableFontFace = false,\n assets,\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 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 — 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 // 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 const n = pdf.numPages\n void pdf\n .getPage?.(1)\n .then((page) => setDefaultRatio(ratioOf(page)))\n .catch(() => {})\n setNumPages(n)\n setLoadError(null) // Clear any previous errors\n\n // Expand lazy-load buffer once the main thread is idle after first paint.\n // Falls back to setTimeout(500ms) in environments where requestIdleCallback\n // is not available (e.g. Safari < 16).\n const expand = () => {\n setRenderedPages((prev) => {\n if (prev.size === 0) return prev\n const newSet = new Set(prev)\n // Always include at least the pages around page 1 at full buffer size\n const anchor = currentPage || 1\n for (\n let i = Math.max(1, anchor - LAZY_LOAD_BUFFER_BEFORE);\n i <= Math.min(n, anchor + LAZY_LOAD_BUFFER_AFTER);\n i++\n ) {\n newSet.add(i)\n }\n return newSet\n })\n }\n\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(expand, { timeout: 500 })\n } else {\n setTimeout(expand, 500)\n }\n\n try {\n onLoadSuccess?.(n)\n } catch (error) {\n console.error('Error in onLoadSuccess callback:', error)\n }\n },\n [onLoadSuccess, currentPage]\n )\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 — 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 → 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 // Measure container width for responsive sizing using ResizeObserver\n useEffect(() => {\n if (!containerRef.current) return\n\n const updateWidth = () => {\n if (containerRef.current) {\n setContainerWidth(containerRef.current.offsetWidth - CONTAINER_PADDING_PX)\n }\n }\n\n updateWidth()\n\n // Use ResizeObserver to detect container size changes (e.g., panel divider resize)\n const resizeObserver = new ResizeObserver(updateWidth)\n resizeObserver.observe(containerRef.current)\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 — 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 style={{ touchAction: 'pan-x pan-y' }}\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 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 — 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=\"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 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 </div>\n )\n })}\n </Document>\n </div>\n )\n}\n","/**\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 * DocumentViewer — render an ARBI document as it actually looks.\n *\n * The individual viewers in this module each take a `Blob`. Getting from a\n * document to the right viewer means: work out the file type, download the\n * original, pick a renderer, and handle loading, failure and \"there is no\n * native view for this type\". Every consumer would otherwise write that same\n * dispatch, so it lives here.\n *\n * Pairs with `DocumentReview` from the root entry, which renders the extracted\n * text with AI citation highlighting. A review UI wants both: the native page is\n * what a person must see before making a call on a document; the text view is\n * where citations and search hits live.\n */\n\nimport { useEffect, useMemo, useState, type ReactNode } from 'react'\nimport type { components } from '@arbidocs/client'\n\nimport { useArbi } from '../useArbi'\nimport { PdfViewer, type PdfViewerAssets } from './PdfViewer'\nimport { DocxViewer } from './DocxViewer'\nimport { XlsxViewer } from './XlsxViewer'\nimport { ImageViewer } from './ImageViewer'\nimport { AudioViewer } from './AudioViewer'\nimport { VideoViewer } from './VideoViewer'\n\ntype DocResponse = components['schemas']['DocResponse']\n\n/** Which native renderer a file needs; `none` when there is no native view. */\nexport type NativeViewerKind = 'pdf' | 'docx' | 'xlsx' | 'image' | 'audio' | 'video' | 'none'\n\nconst BY_EXTENSION: Record<string, NativeViewerKind> = {\n pdf: 'pdf',\n doc: 'docx',\n docx: 'docx',\n xls: 'xlsx',\n xlsx: 'xlsx',\n csv: 'xlsx',\n png: 'image',\n jpg: 'image',\n jpeg: 'image',\n gif: 'image',\n webp: 'image',\n bmp: 'image',\n tif: 'image',\n tiff: 'image',\n mp3: 'audio',\n wav: 'audio',\n m4a: 'audio',\n ogg: 'audio',\n mp4: 'video',\n mov: 'video',\n webm: 'video',\n avi: 'video',\n}\n\n/**\n * Which viewer a document needs. Extension first (it is what the user sees and\n * what ARBI preserves), falling back to the sniffed `file_type` — ARBI\n * identifies by digital signature, so a mislabelled file still renders.\n */\nexport function nativeViewerKind(doc: Pick<DocResponse, 'file_name' | 'file_type'> | undefined) {\n const name = (doc?.file_name ?? '').toLowerCase()\n const ext = name.includes('.') ? name.slice(name.lastIndexOf('.') + 1) : ''\n if (BY_EXTENSION[ext]) return BY_EXTENSION[ext]\n\n const type = (doc?.file_type ?? '').toLowerCase()\n if (!type) return 'none'\n if (type.includes('pdf')) return 'pdf'\n if (type.includes('word') || type.includes('officedocument.wordprocessing')) return 'docx'\n if (type.includes('sheet') || type.includes('excel') || type.includes('csv')) return 'xlsx'\n if (type.startsWith('image/')) return 'image'\n if (type.startsWith('audio/')) return 'audio'\n if (type.startsWith('video/')) return 'video'\n return 'none'\n}\n\nexport interface DocumentViewerProps {\n /** The document to render. */\n doc: Pick<DocResponse, 'external_id' | 'file_name' | 'file_type'> | undefined\n /** Where the app serves the pdf.js worker, cmaps and standard fonts from. */\n pdfAssets?: PdfViewerAssets\n /** Reported as the user scrolls a paged document. */\n onPageChange?: (page: number) => void\n /**\n * Page to show. Paired with `scrollTrigger` this drives a page-number control:\n * a viewer without one is an endless scroll with no way to say \"go to 14\".\n */\n currentPage?: number\n /** Increment to scroll to `currentPage` — lets the same value be re-applied. */\n scrollTrigger?: number\n /** Page count, once the document has loaded. Needed to render \"of N\". */\n onLoadSuccess?: (numPages: number) => void\n /** Rendered when the file type has no native viewer. */\n fallback?: ReactNode\n /** Rendered while the original is downloading. */\n loading?: ReactNode\n /** Rendered when the download or decode fails. Receives the message. */\n errorRender?: (message: string) => ReactNode\n className?: string\n}\n\nexport function DocumentViewer({\n doc,\n pdfAssets,\n onPageChange,\n currentPage,\n scrollTrigger,\n onLoadSuccess,\n fallback,\n loading,\n errorRender,\n className,\n}: DocumentViewerProps) {\n const arbi = useArbi()\n const [blob, setBlob] = useState<Blob | null>(null)\n const [error, setError] = useState<string | null>(null)\n\n const kind = useMemo(() => nativeViewerKind(doc), [doc])\n const docId = doc?.external_id\n\n useEffect(() => {\n if (!docId || kind === 'none') {\n setBlob(null)\n return\n }\n let cancelled = false\n setBlob(null)\n setError(null)\n\n arbi.documents\n .download(docId)\n .then((res: Response) => res.blob())\n .then((b) => {\n if (!cancelled) setBlob(b)\n })\n .catch((err: unknown) => {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Could not load the file')\n })\n\n return () => {\n cancelled = true\n }\n }, [arbi, docId, kind])\n\n if (!doc) return null\n\n if (kind === 'none') {\n return (\n <>\n {fallback ?? (\n <div className=\"grid h-full place-items-center p-6 text-center text-sm text-muted-foreground\">\n No native view for this file type. The original is preserved and can be downloaded.\n </div>\n )}\n </>\n )\n }\n\n if (error) {\n return (\n <>\n {errorRender?.(error) ?? (\n <div className=\"grid h-full place-items-center p-6 text-center\">\n <div>\n <p className=\"text-sm font-medium text-destructive\">Could not load the original</p>\n <p className=\"mt-1 text-sm text-muted-foreground\">{error}</p>\n </div>\n </div>\n )}\n </>\n )\n }\n\n if (!blob) {\n return (\n <>\n {loading ?? (\n <div className=\"grid h-full place-items-center text-sm text-muted-foreground\">\n Loading the original…\n </div>\n )}\n </>\n )\n }\n\n const title = doc.file_name ?? doc.external_id\n const body = (() => {\n switch (kind) {\n case 'pdf':\n return (\n <PdfViewer\n file={blob}\n assets={pdfAssets}\n onPageChange={onPageChange}\n currentPage={currentPage}\n scrollTrigger={scrollTrigger}\n onLoadSuccess={onLoadSuccess}\n />\n )\n case 'docx':\n return <DocxViewer blob={blob} />\n case 'xlsx':\n return <XlsxViewer blob={blob} />\n case 'image':\n return <ImageViewer blob={blob} alt={title} />\n case 'audio':\n return <AudioViewer blob={blob} title={title} />\n case 'video':\n return <VideoViewer blob={blob} title={title} />\n default:\n return null\n }\n })()\n\n return className ? (\n <div className={className} data-testid=\"document-viewer\">\n {body}\n </div>\n ) : (\n body\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arbidocs/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "React hooks and provider for the ARBI SDK",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
6
7
|
"main": "dist/index.cjs",
|
|
7
8
|
"module": "dist/index.js",
|
|
8
9
|
"types": "dist/index.d.ts",
|
|
@@ -52,8 +53,8 @@
|
|
|
52
53
|
"build-storybook": "storybook build"
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
|
-
"@arbidocs/sdk": "0.
|
|
56
|
-
"@arbidocs/client": "0.
|
|
56
|
+
"@arbidocs/sdk": "0.4.0",
|
|
57
|
+
"@arbidocs/client": "0.4.0",
|
|
57
58
|
"@radix-ui/react-avatar": "^1.2.0",
|
|
58
59
|
"@radix-ui/react-checkbox": "^1.3.5",
|
|
59
60
|
"@radix-ui/react-collapsible": "^1.1.14",
|
package/dist/chunk-3MLQUKT4.cjs
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var sonner = require('sonner');
|
|
4
|
-
var zustand = require('zustand');
|
|
5
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
-
|
|
7
|
-
// src/notifications/notify-store.ts
|
|
8
|
-
var seq = 0;
|
|
9
|
-
var uid = () => `n${Date.now().toString(36)}${(seq++).toString(36)}`;
|
|
10
|
-
var useNotify = zustand.create((set) => ({
|
|
11
|
-
notifications: [],
|
|
12
|
-
markRead: (id) => set((s) => ({
|
|
13
|
-
notifications: s.notifications.map((n) => n.id === id ? { ...n, read: true } : n)
|
|
14
|
-
})),
|
|
15
|
-
markAllRead: () => set((s) => ({ notifications: s.notifications.map((n) => ({ ...n, read: true })) })),
|
|
16
|
-
removeNotification: (id) => set((s) => ({ notifications: s.notifications.filter((n) => n.id !== id) })),
|
|
17
|
-
clearNotifications: () => set({ notifications: [] }),
|
|
18
|
-
seed: (items) => set({ notifications: items }),
|
|
19
|
-
record: (note) => set((s) => ({ notifications: [note, ...s.notifications].slice(0, 50) })),
|
|
20
|
-
syncSource: (source, items) => set((s) => ({
|
|
21
|
-
notifications: [
|
|
22
|
-
...items.map((n) => ({ ...n, source })),
|
|
23
|
-
...s.notifications.filter((n) => n.source !== source)
|
|
24
|
-
].sort((a, b) => b.ts - a.ts).slice(0, 100)
|
|
25
|
-
}))
|
|
26
|
-
}));
|
|
27
|
-
function make(variant) {
|
|
28
|
-
return (title, opts = {}) => {
|
|
29
|
-
sonner.toast[variant](title, {
|
|
30
|
-
description: opts.description,
|
|
31
|
-
duration: opts.duration,
|
|
32
|
-
action: opts.action,
|
|
33
|
-
icon: opts.icon
|
|
34
|
-
});
|
|
35
|
-
const id = uid();
|
|
36
|
-
if (opts.record !== false) {
|
|
37
|
-
useNotify.getState().record({
|
|
38
|
-
id,
|
|
39
|
-
title,
|
|
40
|
-
description: opts.description,
|
|
41
|
-
variant,
|
|
42
|
-
ts: Date.now(),
|
|
43
|
-
read: false,
|
|
44
|
-
href: opts.href,
|
|
45
|
-
ambient: opts.ambient
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
return id;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
var notify = {
|
|
52
|
-
success: make("success"),
|
|
53
|
-
error: make("error"),
|
|
54
|
-
info: make("info"),
|
|
55
|
-
warning: make("warning")
|
|
56
|
-
};
|
|
57
|
-
function seedNotifications(items) {
|
|
58
|
-
useNotify.getState().seed(items);
|
|
59
|
-
}
|
|
60
|
-
var selectUnread = (s) => s.notifications.filter((n) => !n.read && !n.ambient).length;
|
|
61
|
-
var DEFAULT_NOTIFY_TONE = {
|
|
62
|
-
success: "text-green-600",
|
|
63
|
-
error: "text-destructive",
|
|
64
|
-
warning: "text-amber-500",
|
|
65
|
-
info: "text-blue-500"
|
|
66
|
-
};
|
|
67
|
-
var DEFAULT_TOAST_OPTIONS = {
|
|
68
|
-
classNames: {
|
|
69
|
-
toast: "group toast group-[.toaster]:bg-card group-[.toaster]:text-foreground group-[.toaster]:border group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:rounded-lg",
|
|
70
|
-
description: "group-[.toast]:text-muted-foreground",
|
|
71
|
-
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
72
|
-
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
function Toaster({ toastOptions, ...props }) {
|
|
76
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
77
|
-
sonner.Toaster,
|
|
78
|
-
{
|
|
79
|
-
className: "toaster group",
|
|
80
|
-
toastOptions: toastOptions ?? DEFAULT_TOAST_OPTIONS,
|
|
81
|
-
...props
|
|
82
|
-
}
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
Object.defineProperty(exports, "toast", {
|
|
87
|
-
enumerable: true,
|
|
88
|
-
get: function () { return sonner.toast; }
|
|
89
|
-
});
|
|
90
|
-
exports.DEFAULT_NOTIFY_TONE = DEFAULT_NOTIFY_TONE;
|
|
91
|
-
exports.Toaster = Toaster;
|
|
92
|
-
exports.notify = notify;
|
|
93
|
-
exports.seedNotifications = seedNotifications;
|
|
94
|
-
exports.selectUnread = selectUnread;
|
|
95
|
-
exports.useNotify = useNotify;
|
|
96
|
-
//# sourceMappingURL=chunk-3MLQUKT4.cjs.map
|
|
97
|
-
//# sourceMappingURL=chunk-3MLQUKT4.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/notifications/notify-store.ts","../src/notifications/Toaster.tsx"],"names":["create","toast","jsx","Sonner"],"mappings":";;;;;;;AA+EA,IAAI,GAAA,GAAM,CAAA;AACV,IAAM,GAAA,GAAM,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,GAAA,EAAI,CAAE,QAAA,CAAS,EAAE,CAAC,CAAA,EAAA,CAAI,GAAA,EAAA,EAAO,QAAA,CAAS,EAAE,CAAC,CAAA,CAAA;AAE7D,IAAM,SAAA,GAAYA,cAAA,CAAoB,CAAC,GAAA,MAAS;AAAA,EACrD,eAAe,EAAC;AAAA,EAChB,QAAA,EAAU,CAAC,EAAA,KACT,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IACV,aAAA,EAAe,CAAA,CAAE,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,EAAA,KAAO,EAAA,GAAK,EAAE,GAAG,CAAA,EAAG,IAAA,EAAM,IAAA,KAAS,CAAE;AAAA,GACpF,CAAE,CAAA;AAAA,EACJ,aAAa,MACX,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,eAAe,CAAA,CAAE,aAAA,CAAc,IAAI,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,EAAG,MAAM,IAAA,EAAK,CAAE,GAAE,CAAE,CAAA;AAAA,EACpF,oBAAoB,CAAC,EAAA,KACnB,GAAA,CAAI,CAAC,OAAO,EAAE,aAAA,EAAe,CAAA,CAAE,aAAA,CAAc,OAAO,CAAC,CAAA,KAAM,EAAE,EAAA,KAAO,EAAE,GAAE,CAAE,CAAA;AAAA,EAC5E,oBAAoB,MAAM,GAAA,CAAI,EAAE,aAAA,EAAe,IAAI,CAAA;AAAA,EACnD,MAAM,CAAC,KAAA,KAAU,IAAI,EAAE,aAAA,EAAe,OAAO,CAAA;AAAA,EAC7C,QAAQ,CAAC,IAAA,KAAS,IAAI,CAAC,CAAA,MAAO,EAAE,aAAA,EAAe,CAAC,IAAA,EAAM,GAAG,EAAE,aAAa,CAAA,CAAE,MAAM,CAAA,EAAG,EAAE,GAAE,CAAE,CAAA;AAAA,EACzF,YAAY,CAAC,MAAA,EAAQ,KAAA,KACnB,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IACV,aAAA,EAAe;AAAA,MACb,GAAG,MAAM,GAAA,CAAI,CAAC,OAAO,EAAE,GAAG,CAAA,EAAG,MAAA,EAAO,CAAE,CAAA;AAAA,MACtC,GAAG,EAAE,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,MAAM;AAAA,KACtD,CACG,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,EAAA,GAAK,CAAA,CAAE,EAAE,CAAA,CAC1B,KAAA,CAAM,CAAA,EAAG,GAAG;AAAA,GACjB,CAAE;AACN,CAAA,CAAE;AAGF,SAAS,KAAK,OAAA,EAAwB;AACpC,EAAA,OAAO,CAAC,KAAA,EAAe,IAAA,GAAsB,EAAC,KAAc;AAC1D,IAAAC,YAAA,CAAM,OAAO,EAAE,KAAA,EAAO;AAAA,MACpB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,UAAU,IAAA,CAAK,QAAA;AAAA,MACf,QAAQ,IAAA,CAAK,MAAA;AAAA,MACb,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AACD,IAAA,MAAM,KAAK,GAAA,EAAI;AACf,IAAA,IAAI,IAAA,CAAK,WAAW,KAAA,EAAO;AACzB,MAAA,SAAA,CAAU,QAAA,GAAW,MAAA,CAAO;AAAA,QAC1B,EAAA;AAAA,QACA,KAAA;AAAA,QACA,aAAa,IAAA,CAAK,WAAA;AAAA,QAClB,OAAA;AAAA,QACA,EAAA,EAAI,KAAK,GAAA,EAAI;AAAA,QACb,IAAA,EAAM,KAAA;AAAA,QACN,MAAM,IAAA,CAAK,IAAA;AAAA,QACX,SAAS,IAAA,CAAK;AAAA,OACf,CAAA;AAAA,IACH;AACA,IAAA,OAAO,EAAA;AAAA,EACT,CAAA;AACF;AACO,IAAM,MAAA,GAAS;AAAA,EACpB,OAAA,EAAS,KAAK,SAAS,CAAA;AAAA,EACvB,KAAA,EAAO,KAAK,OAAO,CAAA;AAAA,EACnB,IAAA,EAAM,KAAK,MAAM,CAAA;AAAA,EACjB,OAAA,EAAS,KAAK,SAAS;AACzB;AAGO,SAAS,kBAAkB,KAAA,EAAgC;AAChE,EAAA,SAAA,CAAU,QAAA,EAAS,CAAE,IAAA,CAAK,KAAK,CAAA;AACjC;AAIO,IAAM,YAAA,GAAe,CAAC,CAAA,KAC3B,CAAA,CAAE,cAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,IAAQ,CAAC,CAAA,CAAE,OAAO,CAAA,CAAE;AAGhD,IAAM,mBAAA,GAAqD;AAAA,EAChE,OAAA,EAAS,gBAAA;AAAA,EACT,KAAA,EAAO,kBAAA;AAAA,EACP,OAAA,EAAS,gBAAA;AAAA,EACT,IAAA,EAAM;AACR;AC7IA,IAAM,qBAAA,GAAsD;AAAA,EAC1D,UAAA,EAAY;AAAA,IACV,KAAA,EACE,qLAAA;AAAA,IACF,WAAA,EAAa,sCAAA;AAAA,IACb,YAAA,EAAc,kEAAA;AAAA,IACd,YAAA,EAAc;AAAA;AAElB,CAAA;AAEO,SAAS,OAAA,CAAQ,EAAE,YAAA,EAAc,GAAG,OAAM,EAAiB;AAChE,EAAA,uBACEC,cAAA;AAAA,IAACC,cAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,eAAA;AAAA,MACV,cAAc,YAAA,IAAgB,qBAAA;AAAA,MAC7B,GAAG;AAAA;AAAA,GACN;AAEJ","file":"chunk-3MLQUKT4.cjs","sourcesContent":["/**\n * App notification store — the one shared toast + notification-centre. A single\n * `notify.*` call pops a transient toast (rendered by <Toaster/>, on sonner) and,\n * unless `{ record: false }`, records a persistent entry for the topbar bell.\n *\n * notify.success('Saved') // toast + centre entry\n * notify.error('Upload failed', { record: false }) // toast only\n *\n * sonner owns the transient toast lifecycle (stacking, timing, dismissal); this\n * store owns only the persistent centre history (what the <NotificationBell/>\n * shows). Brand-neutral: no seed data (inject via `seedNotifications`), no app\n * imports. For full sonner power (custom content, `toast.dismiss`, …) the raw\n * `toast` is re-exported.\n */\nimport { type ReactNode } from 'react'\n// This module IS the sanctioned toast engine home — the app-level rule that\n// steers callers to sendNotification()/notify() doesn't apply here.\n// eslint-disable-next-line no-restricted-imports\nimport { toast } from 'sonner'\nimport { create } from 'zustand'\n\nexport { toast }\n\nexport type NotifyVariant = 'success' | 'error' | 'info' | 'warning'\n\nexport interface AppNotification {\n id: string\n title: string\n description?: string\n variant: NotifyVariant\n /** Epoch ms the entry was recorded. */\n ts: number\n read: boolean\n /** Optional in-app link the entry deep-links to (passed to the bell's onNavigate). */\n href?: string\n /** Optional click action — wins over `href` when both are present. Session\n * history only; entries are never serialized, so a closure is safe here. */\n onSelect?: () => void\n /** Routine session activity (\"Opening workspace…\", \"Saved\") — kept for the\n * log but not something that demands attention: excluded from the unread\n * badge and from the bell's default list (shown under \"All activity\"). */\n ambient?: boolean\n /** Where the entry comes from. Session entries (`record`) have none; a\n * backend bridge stamps its own (e.g. 'server') so {@link syncSource} can\n * replace exactly its slice on every refetch without touching the rest. */\n source?: string\n}\n\nexport interface NotifyOptions {\n description?: string\n /** Also record a persistent notification-centre entry (default true). */\n record?: boolean\n href?: string\n duration?: number\n /** A toast action button (sonner). */\n action?: { label: ReactNode; onClick: () => void }\n /** Override the toast glyph (sonner). */\n icon?: ReactNode\n /** Record as routine session activity (see {@link AppNotification.ambient}). */\n ambient?: boolean\n}\n\ninterface NotifyState {\n notifications: AppNotification[]\n markRead: (id: string) => void\n markAllRead: () => void\n removeNotification: (id: string) => void\n clearNotifications: () => void\n /** Replace the centre's history (e.g. seed a demo/initial set). */\n seed: (items: AppNotification[]) => void\n /** Record a centre entry (used by `notify.*`; sonner renders the toast). */\n record: (note: AppNotification) => void\n /** Reconcile one source's slice with fresh truth (e.g. a backend list on\n * every refetch): entries stamped with `source` are replaced wholesale —\n * including their read state, which the source owns — while entries from\n * other sources (session activity) stay untouched. Newest first. */\n syncSource: (source: string, items: AppNotification[]) => void\n}\n\nlet seq = 0\nconst uid = () => `n${Date.now().toString(36)}${(seq++).toString(36)}`\n\nexport const useNotify = create<NotifyState>((set) => ({\n notifications: [],\n markRead: (id) =>\n set((s) => ({\n notifications: s.notifications.map((n) => (n.id === id ? { ...n, read: true } : n)),\n })),\n markAllRead: () =>\n set((s) => ({ notifications: s.notifications.map((n) => ({ ...n, read: true })) })),\n removeNotification: (id) =>\n set((s) => ({ notifications: s.notifications.filter((n) => n.id !== id) })),\n clearNotifications: () => set({ notifications: [] }),\n seed: (items) => set({ notifications: items }),\n record: (note) => set((s) => ({ notifications: [note, ...s.notifications].slice(0, 50) })),\n syncSource: (source, items) =>\n set((s) => ({\n notifications: [\n ...items.map((n) => ({ ...n, source })),\n ...s.notifications.filter((n) => n.source !== source),\n ]\n .sort((a, b) => b.ts - a.ts)\n .slice(0, 100),\n })),\n}))\n\n/** Ergonomic helper — `notify.success('Saved')` — toast (sonner) + optional centre entry. */\nfunction make(variant: NotifyVariant) {\n return (title: string, opts: NotifyOptions = {}): string => {\n toast[variant](title, {\n description: opts.description,\n duration: opts.duration,\n action: opts.action,\n icon: opts.icon,\n })\n const id = uid()\n if (opts.record !== false) {\n useNotify.getState().record({\n id,\n title,\n description: opts.description,\n variant,\n ts: Date.now(),\n read: false,\n href: opts.href,\n ambient: opts.ambient,\n })\n }\n return id\n }\n}\nexport const notify = {\n success: make('success'),\n error: make('error'),\n info: make('info'),\n warning: make('warning'),\n}\n\n/** Replace the notification centre's history — inject a seed/initial set. */\nexport function seedNotifications(items: AppNotification[]): void {\n useNotify.getState().seed(items)\n}\n\n/** Unread count selector for the topbar bell — ambient session activity never\n * demands attention, so it never counts. */\nexport const selectUnread = (s: NotifyState): number =>\n s.notifications.filter((n) => !n.read && !n.ambient).length\n\n/** Default glyph colour per variant (raw palette, override via `toneClassNames`). */\nexport const DEFAULT_NOTIFY_TONE: Record<NotifyVariant, string> = {\n success: 'text-green-600',\n error: 'text-destructive',\n warning: 'text-amber-500',\n info: 'text-blue-500',\n}\n","/**\n * Toaster — the one shared toast surface, built on sonner (the mature engine:\n * stacking, swipe-to-dismiss, a11y, timing). Mount once near the app root; any\n * code then calls `notify.*(...)` (or the re-exported `toast`) from anywhere.\n *\n * Firm-agnostic: every sonner `ToasterProps` passes through, so a consumer sets\n * its own `position` / `theme` / `toastOptions`. The defaults give a neutral\n * shadcn-token card that both apps can override.\n */\nimport { Toaster as Sonner, type ToasterProps } from 'sonner'\n\nexport type { ToasterProps }\n\nconst DEFAULT_TOAST_OPTIONS: ToasterProps['toastOptions'] = {\n classNames: {\n toast:\n 'group toast group-[.toaster]:bg-card group-[.toaster]:text-foreground group-[.toaster]:border group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:rounded-lg',\n description: 'group-[.toast]:text-muted-foreground',\n actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',\n cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',\n },\n}\n\nexport function Toaster({ toastOptions, ...props }: ToasterProps) {\n return (\n <Sonner\n className=\"toaster group\"\n toastOptions={toastOptions ?? DEFAULT_TOAST_OPTIONS}\n {...props}\n />\n )\n}\n"]}
|