hazo_pdf 1.7.0 → 2.0.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.
Files changed (36) hide show
  1. package/SETUP_CHECKLIST.md +693 -0
  2. package/config/hazo_pdf_config.ini.sample +42 -0
  3. package/db_setup_postgres.sql +17 -0
  4. package/db_setup_sqlite.sql +13 -0
  5. package/dist/{chunk-NQ6KUJWG.js → chunk-7M53O3HF.js} +14 -4
  6. package/dist/chunk-7M53O3HF.js.map +1 -0
  7. package/dist/{chunk-4JJOUQ62.js → chunk-KDOQ3FIO.js} +176 -87
  8. package/dist/chunk-KDOQ3FIO.js.map +1 -0
  9. package/dist/{chunk-KHB3VZJQ.js → chunk-LFFCPDWC.js} +14 -3
  10. package/dist/chunk-LFFCPDWC.js.map +1 -0
  11. package/dist/{chunk-264BTVJT.js → chunk-TZJ5S57X.js} +18 -31
  12. package/dist/chunk-TZJ5S57X.js.map +1 -0
  13. package/dist/index.d.ts +9 -5
  14. package/dist/index.js +35 -16
  15. package/dist/index.js.map +1 -1
  16. package/dist/{pdf_saver-7FA4DAXI.js → pdf_saver-T6SEDYEE.js} +3 -3
  17. package/dist/{pdf_viewer-B6S5PJJB.js → pdf_viewer-TFCSUGWU.js} +3 -3
  18. package/dist/server/index.d.ts +5 -1
  19. package/dist/server/index.js +219 -81
  20. package/dist/server/index.js.map +1 -1
  21. package/dist/server/{text_search-2OZOVUIP.js → text_search-PVDG5Y6I.js} +14 -3
  22. package/dist/server/text_search-PVDG5Y6I.js.map +1 -0
  23. package/dist/styles/full.css +5821 -7156
  24. package/dist/styles/full.css.map +1 -1
  25. package/dist/styles/index.css +4844 -3929
  26. package/dist/styles/index.css.map +1 -1
  27. package/dist/{text_search-I2KZ7DTW.js → text_search-SO4ZOMIZ.js} +2 -2
  28. package/package.json +51 -36
  29. package/dist/chunk-264BTVJT.js.map +0 -1
  30. package/dist/chunk-4JJOUQ62.js.map +0 -1
  31. package/dist/chunk-KHB3VZJQ.js.map +0 -1
  32. package/dist/chunk-NQ6KUJWG.js.map +0 -1
  33. package/dist/server/text_search-2OZOVUIP.js.map +0 -1
  34. /package/dist/{pdf_saver-7FA4DAXI.js.map → pdf_saver-T6SEDYEE.js.map} +0 -0
  35. /package/dist/{pdf_viewer-B6S5PJJB.js.map → pdf_viewer-TFCSUGWU.js.map} +0 -0
  36. /package/dist/{text_search-I2KZ7DTW.js.map → text_search-SO4ZOMIZ.js.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/pdf_viewer/pdf_viewer_dialog.tsx","../src/utils/xfdf_generator.ts","../src/components/split_viewer/pdf_split_viewer.tsx","../src/components/split_viewer/split_viewer_toolbar.tsx","../src/components/split_viewer/split_panel.tsx","../src/components/split_viewer/split_colors.ts","../src/components/split_viewer/split_panel_card.tsx","../src/components/split_viewer/split_viewer_layout.tsx","../src/components/split_viewer/split_page_renderer.tsx"],"sourcesContent":["/**\n * PdfViewerDialog component\n * Renders PdfViewer in a modal/dialog overlay\n */\n\n\"use client\";\n\nimport React, { Suspense, useCallback, useEffect, useRef, lazy } from \"react\";\nimport type { PdfViewerProps } from \"../../types\";\n\n// Lazy load PdfViewer to avoid SSR issues with pdfjs-dist\nconst PdfViewer = lazy(() =>\n import(\"./pdf_viewer\").then((mod) => ({ default: mod.PdfViewer }))\n);\n\n/**\n * Props for PdfViewerDialog component\n * Extends PdfViewerProps with dialog-specific props\n */\nexport interface PdfViewerDialogProps extends Omit<PdfViewerProps, \"on_close\"> {\n /** Whether the dialog is open */\n open: boolean;\n\n /** Callback when open state should change (close requested) */\n on_open_change: (open: boolean) => void;\n\n /** Dialog width (default: \"90vw\") */\n dialog_width?: string;\n\n /** Dialog height (default: \"90vh\") */\n dialog_height?: string;\n\n /** Whether clicking the backdrop closes the dialog (default: true) */\n close_on_backdrop_click?: boolean;\n\n /** Whether pressing Escape closes the dialog (default: true) */\n close_on_escape?: boolean;\n\n /** Loading fallback content (default: \"Loading PDF viewer...\") */\n loading_fallback?: React.ReactNode;\n\n /** Additional class names for the dialog container */\n dialog_class_name?: string;\n\n /** Additional class names for the backdrop overlay */\n backdrop_class_name?: string;\n}\n\n/**\n * PdfViewerDialog component\n * Renders PdfViewer in a centered modal with backdrop overlay\n *\n * @example\n * ```tsx\n * import { PdfViewerDialog } from \"hazo_pdf\";\n * import \"hazo_pdf/styles.css\";\n *\n * function App() {\n * const [isOpen, setIsOpen] = useState(false);\n *\n * return (\n * <>\n * <button onClick={() => setIsOpen(true)}>Open PDF</button>\n * <PdfViewerDialog\n * open={isOpen}\n * on_open_change={setIsOpen}\n * url=\"/document.pdf\"\n * />\n * </>\n * );\n * }\n * ```\n */\nexport function PdfViewerDialog({\n open,\n on_open_change,\n dialog_width = \"90vw\",\n dialog_height = \"90vh\",\n close_on_backdrop_click = true,\n close_on_escape = true,\n loading_fallback,\n dialog_class_name,\n backdrop_class_name,\n className,\n ...pdf_viewer_props\n}: PdfViewerDialogProps) {\n const dialog_ref = useRef<HTMLDivElement>(null);\n\n // Handle close\n const handle_close = useCallback(() => {\n on_open_change(false);\n }, [on_open_change]);\n\n // Handle backdrop click\n const handle_backdrop_click = useCallback(\n (e: React.MouseEvent) => {\n if (close_on_backdrop_click && e.target === e.currentTarget) {\n handle_close();\n }\n },\n [close_on_backdrop_click, handle_close]\n );\n\n // Handle escape key\n useEffect(() => {\n if (!open || !close_on_escape) return;\n\n const handle_keydown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n handle_close();\n }\n };\n\n document.addEventListener(\"keydown\", handle_keydown);\n return () => document.removeEventListener(\"keydown\", handle_keydown);\n }, [open, close_on_escape, handle_close]);\n\n // Prevent body scroll when dialog is open\n useEffect(() => {\n if (!open) return;\n\n const original_overflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original_overflow;\n };\n }, [open]);\n\n // Focus trap - focus dialog when opened\n useEffect(() => {\n if (open && dialog_ref.current) {\n dialog_ref.current.focus();\n }\n }, [open]);\n\n // Don't render if not open\n if (!open) {\n return null;\n }\n\n const default_fallback = (\n <div className=\"flex items-center justify-center h-full w-full p-8 text-center text-gray-500\">\n Loading PDF viewer...\n </div>\n );\n\n return (\n <div\n className={`cls_pdf_viewer_dialog_backdrop fixed inset-0 bg-black/50 flex items-center justify-center z-50 ${backdrop_class_name || \"\"}`}\n onClick={handle_backdrop_click}\n role=\"dialog\"\n aria-modal=\"true\"\n >\n <div\n ref={dialog_ref}\n className={`cls_pdf_viewer_dialog bg-white rounded-lg overflow-hidden shadow-xl ${dialog_class_name || \"\"}`}\n style={{ width: dialog_width, height: dialog_height }}\n tabIndex={-1}\n >\n <Suspense fallback={loading_fallback || default_fallback}>\n <PdfViewer\n {...pdf_viewer_props}\n className={`h-full w-full ${className || \"\"}`}\n on_close={handle_close}\n />\n </Suspense>\n </div>\n </div>\n );\n}\n\nexport default PdfViewerDialog;\n","/**\n * XFDF Generator Utility\n * Converts annotation and bookmark data to XFDF (XML Forms Data Format)\n * XFDF is the standard format for PDF annotations\n */\n\nimport type { PdfAnnotation, PdfBookmark } from '../types';\nimport { get_logger } from './logger';\n\n/**\n * Format date to PDF date format: D:YYYYMMDDhhmmss[Z+-hh'mm']\n * @param date - Date object or ISO string\n * @returns Formatted date string\n */\nfunction format_pdf_date(date: Date | string): string {\n const logger = get_logger();\n let date_obj: Date;\n\n if (typeof date === 'string') {\n // Try to parse the date string\n date_obj = new Date(date);\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n logger.warn(`Invalid date string: ${date}. Using current date.`);\n date_obj = new Date();\n }\n } else {\n date_obj = date;\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n logger.warn(`Invalid date object. Using current date.`);\n date_obj = new Date();\n }\n }\n \n const year = date_obj.getFullYear();\n const month = String(date_obj.getMonth() + 1).padStart(2, '0');\n const day = String(date_obj.getDate()).padStart(2, '0');\n const hours = String(date_obj.getHours()).padStart(2, '0');\n const minutes = String(date_obj.getMinutes()).padStart(2, '0');\n const seconds = String(date_obj.getSeconds()).padStart(2, '0');\n \n // Get timezone offset\n const offset_minutes = date_obj.getTimezoneOffset();\n const offset_hours = Math.abs(Math.floor(offset_minutes / 60));\n const offset_mins = Math.abs(offset_minutes % 60);\n const offset_sign = offset_minutes <= 0 ? '+' : '-';\n \n return `D:${year}${month}${day}${hours}${minutes}${seconds}${offset_sign}${String(offset_hours).padStart(2, '0')}'${String(offset_mins).padStart(2, '0')}'`;\n}\n\n/**\n * Escape XML special characters\n * @param text - Text to escape\n * @returns Escaped text\n */\nfunction escape_xml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Convert annotation type to XFDF tag name\n * @param type - Annotation type\n * @returns XFDF tag name (lowercase)\n */\nfunction annotation_type_to_tag(type: PdfAnnotation['type']): string {\n return type.toLowerCase();\n}\n\n/**\n * Generate XFDF XML from annotations and bookmarks\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @returns XFDF XML string\n */\nexport function generate_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf'\n): string {\n // Start XML boilerplate\n let xfdf = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\n xfdf += `<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\\n`;\n xfdf += ` <f href=\"${escape_xml(pdf_file_name)}\"/>\\n`;\n\n // Add annotations\n if (annotations.length > 0) {\n xfdf += ` <annots>\\n`;\n\n annotations.forEach((ann) => {\n // Format rectangle coordinates\n const rect_string = ann.rect.map((c) => c.toFixed(2)).join(', ');\n\n // Format date - ensure it's valid\n let date_string: string;\n try {\n date_string = format_pdf_date(ann.date);\n } catch (error) {\n const logger = get_logger();\n logger.warn(`Error formatting date for annotation ${ann.id}`, { data: error });\n // Fallback to current date\n date_string = format_pdf_date(new Date());\n }\n\n // Get tag name\n const tag_name = annotation_type_to_tag(ann.type);\n\n // Build annotation attributes\n const attributes: string[] = [];\n attributes.push(`subject=\"${escape_xml(ann.subject || ann.type)}\"`);\n attributes.push(`page=\"${ann.page_index}\"`);\n attributes.push(`rect=\"${rect_string}\"`);\n attributes.push(`flags=\"print\"`);\n attributes.push(`name=\"${escape_xml(ann.id)}\"`);\n attributes.push(`title=\"${escape_xml(ann.author)}\"`);\n attributes.push(`date=\"${date_string}\"`);\n\n if (ann.color) {\n attributes.push(`color=\"${escape_xml(ann.color)}\"`);\n }\n\n // Build annotation element\n xfdf += ` <${tag_name} ${attributes.join(' ')}>\\n`;\n\n // Add contents if present\n if (ann.contents) {\n xfdf += ` <contents><![CDATA[${ann.contents}]]></contents>\\n`;\n }\n\n // Close annotation tag\n xfdf += ` </${tag_name}>\\n`;\n });\n\n xfdf += ` </annots>\\n`;\n }\n\n // Add bookmarks\n if (bookmarks.length > 0) {\n xfdf += ` <bookmarks>\\n`;\n\n bookmarks.forEach((bookmark) => {\n const attributes: string[] = [];\n attributes.push(`title=\"${escape_xml(bookmark.title)}\"`);\n attributes.push(`action=\"${bookmark.action || 'GoTo'}\"`);\n attributes.push(`page=\"${bookmark.page_index}\"`);\n\n if (bookmark.y !== undefined) {\n attributes.push(`y=\"${bookmark.y}\"`);\n }\n\n xfdf += ` <bookmark ${attributes.join(' ')} />\\n`;\n });\n\n xfdf += ` </bookmarks>\\n`;\n }\n\n // Close XFDF\n xfdf += `</xfdf>`;\n\n return xfdf;\n}\n\n/**\n * Download XFDF file\n * @param xfdf_content - XFDF XML content\n * @param file_name - Name for the downloaded file\n */\nexport function download_xfdf(xfdf_content: string, file_name: string = 'annotations.xfdf'): void {\n const blob = new Blob([xfdf_content], { type: 'application/vnd.adobe.xfdf' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = file_name;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Generate and download XFDF file\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @param file_name - Name for the downloaded file\n */\nexport function export_annotations_to_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf',\n file_name: string = 'annotations.xfdf'\n): void {\n const xfdf_content = generate_xfdf(annotations, bookmarks, pdf_file_name);\n download_xfdf(xfdf_content, file_name);\n}\n","/**\n * PdfSplitViewer — Main orchestrator component\n *\n * Loads a PDF document, manages split state, and wires together:\n * - SplitViewerToolbar (top bar: zoom + split actions)\n * - SplitPanel (left sidebar: split list)\n * - SplitViewerLayout (right area: page preview)\n */\n\n'use client';\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\n\nimport { load_pdf_document } from '../pdf_viewer/pdf_worker_setup';\nimport { set_logger, get_logger } from '../../utils/logger';\nimport { cn } from '../../utils/cn';\n\nimport { SplitViewerToolbar } from './split_viewer_toolbar';\nimport { SplitPanel } from './split_panel';\nimport { SplitViewerLayout } from './split_viewer_layout';\n\nimport type {\n PdfSplit,\n PdfSplitViewerProps,\n PdfSplitRequest,\n PdfSplitResult,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generate_split_id(): string {\n return `split_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Deep-clone splits so mutations don't affect the original array.\n */\nfunction clone_splits(splits: PdfSplit[]): PdfSplit[] {\n return splits.map((s) => ({ ...s, pages: [...s.pages] }));\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport const PdfSplitViewer: React.FC<PdfSplitViewerProps> = ({\n url,\n file_manager,\n file_id,\n file_name: _file_name,\n splits: initial_splits,\n on_splits_changed,\n on_splits_confirmed,\n split_api_endpoint,\n output_folder,\n read_only = false,\n className,\n initial_scale = 1.0,\n fit_to_width = false,\n config_file: _config_file,\n logger,\n}) => {\n // ------ Logger setup ------\n useEffect(() => {\n if (logger) {\n set_logger(logger);\n }\n }, [logger]);\n\n // ------ PDF document ------\n const [pdf_document, set_pdf_document] = useState<PDFDocumentProxy | null>(null);\n const [pdf_loading, set_pdf_loading] = useState(true);\n const [pdf_error, set_pdf_error] = useState<string | null>(null);\n\n // ------ Split state ------\n const [splits, set_splits] = useState<PdfSplit[]>(() => clone_splits(initial_splits));\n const [original_splits] = useState<PdfSplit[]>(() => clone_splits(initial_splits));\n const [selected_split_id, set_selected_split_id] = useState<string | null>(\n initial_splits.length > 0 ? initial_splits[0].split_id : null\n );\n\n // ------ UI state ------\n const [scale, set_scale] = useState(initial_scale);\n const [is_adding_split, set_is_adding_split] = useState(false);\n const [is_confirming, set_is_confirming] = useState(false);\n const [panel_width, set_panel_width] = useState(300);\n\n // Ref to the right-side layout container for fit-to-width calculations\n const layout_container_ref = useRef<HTMLDivElement>(null);\n\n // ------ Load PDF ------\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const log = get_logger();\n set_pdf_loading(true);\n set_pdf_error(null);\n\n const load = async () => {\n try {\n let source: string | ArrayBuffer | Uint8Array;\n\n if (url) {\n // Prefer direct URL when provided\n source = url;\n } else if (file_manager && file_id) {\n // Load via file_manager (hazo_files FileAccessProvider)\n log.info('PdfSplitViewer: loading file via file_manager', { data: { file_id } });\n const result = await file_manager.downloadFile(file_id);\n if (!result.success || !result.data) {\n throw new Error(result.error ?? 'Failed to download file');\n }\n source = result.data instanceof Uint8Array\n ? result.data\n : new Uint8Array(result.data as ArrayBuffer);\n } else {\n throw new Error('PdfSplitViewer: either url or file_manager + file_id must be provided');\n }\n\n const doc = await load_pdf_document(source);\n set_pdf_document(doc);\n log.info('PdfSplitViewer: PDF loaded', { data: { pages: doc.numPages } });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('PdfSplitViewer: error loading PDF', { data: { error: message } });\n set_pdf_error(message);\n } finally {\n set_pdf_loading(false);\n }\n };\n\n load();\n }, [url, file_id]); // file_manager is stable; url/file_id drive reloads\n\n // ------ Escape key cancels add-split mode ------\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && is_adding_split) {\n set_is_adding_split(false);\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [is_adding_split]);\n\n // ------ Derived values ------\n const selected_split_index = splits.findIndex((s) => s.split_id === selected_split_id);\n const selected_split = selected_split_index >= 0 ? splits[selected_split_index] : null;\n\n const can_merge = selected_split !== null && splits.length > 1;\n\n // ------ Mutation helper ------\n const apply_splits = useCallback((next: PdfSplit[]) => {\n set_splits(next);\n on_splits_changed?.(next);\n }, [on_splits_changed]);\n\n // ------ Split operations ------\n\n const handle_move_first_to_prev = useCallback((split_id: string) => {\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === split_id);\n if (idx <= 0) return; // no previous split\n const current = next[idx];\n const prev = next[idx - 1];\n if (current.pages.length <= 1) return; // can't remove last page\n\n // Move the first page of current to the end of prev\n const [first_page, ...remaining] = current.pages;\n prev.pages = [...prev.pages, first_page];\n current.pages = remaining;\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_move_last_to_next = useCallback((split_id: string) => {\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === split_id);\n if (idx < 0 || idx >= next.length - 1) return; // no next split\n const current = next[idx];\n const nxt = next[idx + 1];\n if (current.pages.length <= 1) return; // can't remove last page\n\n // Move the last page of current to the start of next\n const last_page = current.pages[current.pages.length - 1];\n current.pages = current.pages.slice(0, -1);\n nxt.pages = [last_page, ...nxt.pages];\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_insert_split_after_page = useCallback((page_number: number) => {\n // Find which split contains this page\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.pages.includes(page_number));\n if (idx < 0) return;\n\n const target = next[idx];\n const split_point = target.pages.indexOf(page_number);\n\n if (split_point < 0 || split_point >= target.pages.length - 1) {\n // page is the last page in its split — nothing to split after\n return;\n }\n\n // Pages before and including the split point stay in original split\n const pages_before = target.pages.slice(0, split_point + 1);\n // Pages after form the new split\n const pages_after = target.pages.slice(split_point + 1);\n\n target.pages = pages_before;\n\n const new_split: PdfSplit = {\n split_id: generate_split_id(),\n label: 'Untitled Split',\n pages: pages_after,\n };\n\n // Insert new split after the target\n next.splice(idx + 1, 0, new_split);\n\n // Exit add-split mode and select the new split\n set_is_adding_split(false);\n set_selected_split_id(new_split.split_id);\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_merge = useCallback(() => {\n if (!selected_split) return;\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === selected_split.split_id);\n if (idx < 0 || next.length <= 1) return;\n\n if (idx < next.length - 1) {\n // Merge with next: keep label of selected, absorb next's pages\n const merged_pages = [...next[idx].pages, ...next[idx + 1].pages];\n next[idx] = { ...next[idx], pages: merged_pages };\n next.splice(idx + 1, 1);\n } else {\n // Last split: merge with previous, keep previous label\n const merged_pages = [...next[idx - 1].pages, ...next[idx].pages];\n next[idx - 1] = { ...next[idx - 1], pages: merged_pages };\n next.splice(idx, 1);\n set_selected_split_id(next[idx - 1].split_id);\n }\n\n apply_splits(next);\n }, [splits, selected_split, apply_splits]);\n\n const handle_rename = useCallback(() => {\n if (!selected_split) return;\n const new_label = window.prompt('Rename split:', selected_split.label);\n if (new_label === null) return; // cancelled\n const trimmed = new_label.trim();\n if (!trimmed || trimmed === selected_split.label) return;\n\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === selected_split.split_id);\n if (idx >= 0) {\n next[idx] = { ...next[idx], label: trimmed };\n apply_splits(next);\n }\n }, [splits, selected_split, apply_splits]);\n\n const handle_reset = useCallback(() => {\n const restored = clone_splits(original_splits);\n set_selected_split_id(restored.length > 0 ? restored[0].split_id : null);\n apply_splits(restored);\n }, [original_splits, apply_splits]);\n\n const handle_confirm = useCallback(async () => {\n if (is_confirming) return;\n set_is_confirming(true);\n const log = get_logger();\n\n try {\n if (split_api_endpoint) {\n // POST to the provided API endpoint\n const body: PdfSplitRequest = {\n source_file_id: file_id,\n splits: splits.map((s) => ({\n split_id: s.split_id,\n label: s.label,\n pages: s.pages,\n classification: s.classification,\n })),\n output_folder,\n };\n\n log.info('PdfSplitViewer: posting split request', { data: { endpoint: split_api_endpoint } });\n\n const response = await fetch(split_api_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => response.statusText);\n throw new Error(`Split API error ${response.status}: ${text}`);\n }\n\n const result: PdfSplitResult = await response.json();\n log.info('PdfSplitViewer: split confirmed via API', { data: { splits: result.splits.length } });\n on_splits_confirmed?.(result);\n } else {\n // No API endpoint — return splits as a result with empty file info\n const result: PdfSplitResult = {\n source_file_id: file_id,\n splits: splits.map((s) => ({\n split_id: s.split_id,\n label: s.label,\n pages: s.pages,\n file_id: '',\n file_name: '',\n file_path: '',\n page_count: s.pages.length,\n byte_size: 0,\n })),\n };\n log.info('PdfSplitViewer: split confirmed (no API)', { data: { splits: result.splits.length } });\n on_splits_confirmed?.(result);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('PdfSplitViewer: confirm failed', { data: { error: message } });\n // Surface the error visually via alert so the user knows what went wrong\n if (typeof window !== 'undefined') {\n window.alert(`Confirm failed: ${message}`);\n }\n } finally {\n set_is_confirming(false);\n }\n }, [splits, file_id, split_api_endpoint, output_folder, is_confirming, on_splits_confirmed]);\n\n // ------ Zoom handlers ------\n\n const handle_zoom_in = useCallback(() => {\n set_scale((s) => Math.min(s + 0.25, 4.0));\n }, []);\n\n const handle_zoom_out = useCallback(() => {\n set_scale((s) => Math.max(s - 0.25, 0.25));\n }, []);\n\n const handle_fit_to_width = useCallback(() => {\n if (!layout_container_ref.current || !pdf_document) return;\n\n // Approximate the container width minus some padding\n const container_width = layout_container_ref.current.clientWidth - 48; // 24px padding each side\n if (container_width <= 0) return;\n\n // Use the first page of the selected split (or page 1) to get the natural width\n const page_num = selected_split?.pages?.[0] ?? 1;\n\n pdf_document.getPage(page_num).then((page) => {\n const viewport = page.getViewport({ scale: 1 });\n const new_scale = container_width / viewport.width;\n set_scale(Math.max(0.25, Math.min(4.0, Math.round(new_scale * 100) / 100)));\n }).catch(() => {\n // ignore — page may not be available yet\n });\n }, [pdf_document, selected_split]);\n\n // Apply fit_to_width once on load\n useEffect(() => {\n if (fit_to_width && pdf_document) {\n handle_fit_to_width();\n }\n }, [fit_to_width, pdf_document]); // intentionally omit handle_fit_to_width to run once\n\n // ------ Add-split toggle ------\n const handle_add_split_toggle = useCallback(() => {\n set_is_adding_split((prev) => !prev);\n }, []);\n\n // ------ Render ------\n\n const root_class = cn('hazo-pdf-root cls_split_viewer', className);\n\n // Loading state\n if (pdf_loading) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#94a3b8',\n fontSize: 14,\n }}\n >\n Loading PDF…\n </div>\n );\n }\n\n // Error state\n if (pdf_error) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#f87171',\n fontSize: 14,\n padding: 24,\n textAlign: 'center',\n }}\n >\n Failed to load PDF: {pdf_error}\n </div>\n );\n }\n\n // Empty document state (document loaded but no pages — unlikely, but safe)\n if (!pdf_document) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#94a3b8',\n fontSize: 14,\n }}\n >\n No PDF document\n </div>\n );\n }\n\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n overflow: 'hidden',\n backgroundColor: '#0f172a',\n }}\n >\n {/* ── Top toolbar ── */}\n <SplitViewerToolbar\n scale={scale}\n on_zoom_in={handle_zoom_in}\n on_zoom_out={handle_zoom_out}\n on_fit_to_width={handle_fit_to_width}\n on_add_split={handle_add_split_toggle}\n on_merge={handle_merge}\n on_rename={handle_rename}\n on_reset={handle_reset}\n on_confirm={handle_confirm}\n read_only={read_only}\n is_adding_split={is_adding_split}\n is_confirming={is_confirming}\n can_merge={can_merge}\n has_selected_split={selected_split !== null}\n />\n\n {/* ── Main content row ── */}\n <div\n style={{\n display: 'flex',\n flex: 1,\n overflow: 'hidden',\n }}\n >\n {/* Left: Split panel */}\n <SplitPanel\n splits={splits}\n selected_split_id={selected_split_id}\n width={panel_width}\n on_width_change={set_panel_width}\n on_select_split={set_selected_split_id}\n on_move_first_to_prev={handle_move_first_to_prev}\n on_move_last_to_next={handle_move_last_to_next}\n read_only={read_only}\n is_adding_split={is_adding_split}\n on_insert_split_after_page={handle_insert_split_after_page}\n />\n\n {/* Right: Page preview */}\n <div\n ref={layout_container_ref}\n style={{ flex: 1, overflow: 'hidden', height: '100%' }}\n >\n <SplitViewerLayout\n pdf_document={pdf_document}\n selected_split={selected_split}\n selected_split_index={selected_split_index >= 0 ? selected_split_index : 0}\n scale={scale}\n />\n </div>\n </div>\n </div>\n );\n};\n\nexport default PdfSplitViewer;\n","/**\n * Split Viewer Toolbar Component\n * Top toolbar for PdfSplitViewer: zoom controls, split actions, confirm button.\n */\n\nimport React from 'react';\nimport {\n ZoomIn,\n ZoomOut,\n Maximize2,\n Scissors,\n Merge,\n Pencil,\n RotateCcw,\n Check,\n Loader2,\n X,\n} from 'lucide-react';\nimport { cn } from '../../utils/cn';\n\nexport interface SplitViewerToolbarProps {\n scale: number;\n on_zoom_in: () => void;\n on_zoom_out: () => void;\n on_fit_to_width: () => void;\n on_add_split: () => void;\n on_merge: () => void;\n on_rename: () => void;\n on_reset: () => void;\n on_confirm: () => void;\n read_only: boolean;\n is_adding_split: boolean;\n is_confirming: boolean;\n can_merge: boolean;\n has_selected_split: boolean;\n}\n\n/** Small toolbar icon button with optional disabled/active styling */\ninterface ToolbarButtonProps {\n onClick: () => void;\n disabled?: boolean;\n title: string;\n children: React.ReactNode;\n active?: boolean;\n active_bg?: string;\n className?: string;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n onClick,\n disabled = false,\n title,\n children,\n active = false,\n active_bg,\n className,\n}) => (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={cn('cls_split_toolbar_btn', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 5,\n padding: '5px 10px',\n borderRadius: 5,\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n backgroundColor: active && active_bg\n ? active_bg\n : active\n ? '#475569'\n : '#334155',\n color: disabled ? '#475569' : '#e2e8f0',\n fontSize: 12,\n fontWeight: 500,\n opacity: disabled ? 0.5 : 1,\n transition: 'background-color 0.15s, opacity 0.15s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n if (!disabled) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n active && active_bg ? active_bg : '#475569';\n }\n }}\n onMouseLeave={(e) => {\n if (!disabled) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n active && active_bg\n ? active_bg\n : active\n ? '#475569'\n : '#334155';\n }\n }}\n >\n {children}\n </button>\n);\n\n/** Thin vertical separator between toolbar groups */\nconst Separator: React.FC = () => (\n <div\n style={{\n width: 1,\n height: 22,\n backgroundColor: '#334155',\n flexShrink: 0,\n margin: '0 4px',\n }}\n />\n);\n\nexport const SplitViewerToolbar: React.FC<SplitViewerToolbarProps> = ({\n scale,\n on_zoom_in,\n on_zoom_out,\n on_fit_to_width,\n on_add_split,\n on_merge,\n on_rename,\n on_reset,\n on_confirm,\n read_only,\n is_adding_split,\n is_confirming,\n can_merge,\n has_selected_split,\n}) => {\n const zoom_pct = `${Math.round(scale * 100)}%`;\n\n return (\n <div\n className=\"cls_split_viewer_toolbar\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n backgroundColor: '#1e293b',\n borderBottom: '1px solid #334155',\n flexShrink: 0,\n flexWrap: 'wrap',\n }}\n >\n {/* ── Zoom group ── */}\n <ToolbarButton onClick={on_zoom_out} title=\"Zoom out\">\n <ZoomOut size={15} />\n </ToolbarButton>\n\n {/* Zoom percentage display */}\n <div\n style={{\n minWidth: 44,\n textAlign: 'center',\n fontSize: 12,\n color: '#94a3b8',\n fontVariantNumeric: 'tabular-nums',\n userSelect: 'none',\n }}\n >\n {zoom_pct}\n </div>\n\n <ToolbarButton onClick={on_zoom_in} title=\"Zoom in\">\n <ZoomIn size={15} />\n </ToolbarButton>\n\n <ToolbarButton onClick={on_fit_to_width} title=\"Fit to width\">\n <Maximize2 size={15} />\n </ToolbarButton>\n\n <Separator />\n\n {/* ── Split actions (hidden when read_only) ── */}\n {!read_only && (\n <>\n {/* Add Split / Cancel toggle */}\n <ToolbarButton\n onClick={on_add_split}\n title={is_adding_split ? 'Cancel adding split' : 'Add split'}\n active={is_adding_split}\n active_bg=\"#b45309\"\n >\n {is_adding_split ? (\n <>\n <X size={14} />\n Cancel\n </>\n ) : (\n <>\n <Scissors size={14} />\n Add Split\n </>\n )}\n </ToolbarButton>\n\n <ToolbarButton\n onClick={on_merge}\n disabled={!can_merge}\n title=\"Merge selected split with adjacent\"\n >\n <Merge size={14} />\n Merge\n </ToolbarButton>\n\n <ToolbarButton\n onClick={on_rename}\n disabled={!has_selected_split}\n title=\"Rename selected split\"\n >\n <Pencil size={14} />\n Rename\n </ToolbarButton>\n\n <Separator />\n </>\n )}\n\n {/* Reset button (hidden in read-only) */}\n {!read_only && (\n <ToolbarButton onClick={on_reset} title=\"Reset splits to original\">\n <RotateCcw size={14} />\n Reset\n </ToolbarButton>\n )}\n\n {/* Spacer */}\n <div style={{ flex: 1 }} />\n\n {/* ── Confirm button (right-aligned, green, hidden in read-only) ── */}\n {!read_only && <button\n type=\"button\"\n onClick={on_confirm}\n disabled={is_confirming}\n title={is_confirming ? 'Splitting in progress…' : 'Confirm splits'}\n className=\"cls_split_toolbar_confirm_btn\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '5px 14px',\n borderRadius: 5,\n border: 'none',\n cursor: is_confirming ? 'not-allowed' : 'pointer',\n backgroundColor: is_confirming ? '#14532d' : '#16a34a',\n color: '#fff',\n fontSize: 12,\n fontWeight: 600,\n opacity: is_confirming ? 0.8 : 1,\n transition: 'background-color 0.15s, opacity 0.15s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n if (!is_confirming) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#15803d';\n }\n }}\n onMouseLeave={(e) => {\n if (!is_confirming) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#16a34a';\n }\n }}\n >\n {is_confirming ? (\n <>\n <Loader2 size={14} className=\"cls_split_confirm_spinner\" style={{ animation: 'spin 1s linear infinite' }} />\n Splitting…\n </>\n ) : (\n <>\n <Check size={14} />\n Confirm Splits\n </>\n )}\n </button>}\n </div>\n );\n};\n\nexport default SplitViewerToolbar;\n","/**\n * Split Panel Component\n * Resizable left sidebar listing all split segments.\n * Follows the resize-handle pattern from file_info_sidepanel.tsx.\n */\n\nimport React, { useRef, useEffect } from 'react';\nimport type { PdfSplit } from './types';\nimport { get_split_color } from './split_colors';\nimport { SplitPanelCard } from './split_panel_card';\n\nexport interface SplitPanelProps {\n splits: PdfSplit[];\n selected_split_id: string | null;\n width: number;\n on_width_change: (width: number) => void;\n on_select_split: (split_id: string) => void;\n on_move_first_to_prev: (split_id: string) => void;\n on_move_last_to_next: (split_id: string) => void;\n read_only: boolean;\n is_adding_split: boolean;\n on_insert_split_after_page: (page_number: number) => void;\n}\n\nconst MIN_WIDTH = 200;\nconst MAX_WIDTH = 600;\n\n/**\n * Compute total page count across all splits.\n */\nfunction total_pages(splits: PdfSplit[]): number {\n const page_set = new Set<number>();\n for (const s of splits) {\n for (const p of s.pages) {\n page_set.add(p);\n }\n }\n return page_set.size;\n}\n\nexport const SplitPanel: React.FC<SplitPanelProps> = ({\n splits,\n selected_split_id,\n width,\n on_width_change,\n on_select_split,\n on_move_first_to_prev,\n on_move_last_to_next,\n read_only,\n is_adding_split,\n on_insert_split_after_page,\n}) => {\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Handle resize start (right edge drag)\n const handle_resize_start = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n is_resizing_ref.current = true;\n start_width_ref.current = width;\n start_x_ref.current = e.clientX;\n\n document.addEventListener('mousemove', handle_resize_move);\n document.addEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = 'ew-resize';\n document.body.style.userSelect = 'none';\n };\n\n // Dragging RIGHT increases width (left panel delta is positive when moving right)\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n const delta = e.clientX - start_x_ref.current;\n const new_width = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, start_width_ref.current + delta));\n on_width_change(new_width);\n };\n\n const handle_resize_end = () => {\n is_resizing_ref.current = false;\n document.removeEventListener('mousemove', handle_resize_move);\n document.removeEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n };\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n document.removeEventListener('mousemove', handle_resize_move);\n document.removeEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n };\n }, []);\n\n const page_count = total_pages(splits);\n\n return (\n <div\n className=\"cls_split_panel\"\n style={{\n position: 'relative',\n width,\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: '#111827',\n borderRight: '1px solid #334155',\n overflow: 'hidden',\n }}\n >\n {/* Header */}\n <div\n className=\"cls_split_panel_header\"\n style={{\n padding: '12px 14px 8px',\n borderBottom: '1px solid #1e293b',\n flexShrink: 0,\n }}\n >\n <div\n style={{\n fontSize: 13,\n fontWeight: 700,\n color: '#e2e8f0',\n marginBottom: 2,\n }}\n >\n Splits\n </div>\n <div style={{ fontSize: 11, color: '#64748b' }}>\n {splits.length} {splits.length === 1 ? 'document' : 'documents'} · {page_count} {page_count === 1 ? 'page' : 'pages'}\n </div>\n </div>\n\n {/* Scrollable list */}\n <div\n className=\"cls_split_panel_list\"\n style={{\n flex: 1,\n overflowY: 'auto',\n padding: '10px 10px 10px 10px',\n }}\n >\n {splits.map((split, index) => {\n const prev_color = index > 0 ? get_split_color(index - 1) : null;\n const next_color = index < splits.length - 1 ? get_split_color(index + 1) : null;\n\n return (\n <SplitPanelCard\n key={split.split_id}\n split={split}\n index={index}\n is_selected={selected_split_id === split.split_id}\n read_only={read_only}\n is_adding_split={is_adding_split}\n total_splits={splits.length}\n prev_split_color={prev_color}\n next_split_color={next_color}\n on_select={on_select_split}\n on_move_first_to_prev={on_move_first_to_prev}\n on_move_last_to_next={on_move_last_to_next}\n on_insert_split_after_page={on_insert_split_after_page}\n />\n );\n })}\n\n {splits.length === 0 && (\n <div\n style={{\n fontSize: 12,\n color: '#475569',\n textAlign: 'center',\n marginTop: 24,\n }}\n >\n No splits defined\n </div>\n )}\n </div>\n\n {/* Resize handle — right edge, 4px wide */}\n <div\n className=\"cls_split_panel_resize_handle\"\n onMouseDown={handle_resize_start}\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n width: 4,\n height: '100%',\n cursor: 'ew-resize',\n zIndex: 10,\n backgroundColor: 'transparent',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLDivElement).style.backgroundColor = '#334155';\n }}\n onMouseLeave={(e) => {\n if (!is_resizing_ref.current) {\n (e.currentTarget as HTMLDivElement).style.backgroundColor = 'transparent';\n }\n }}\n />\n </div>\n );\n};\n\nexport default SplitPanel;\n","/**\n * Fixed color palette for split viewer segments\n */\n\nexport const SPLIT_COLORS = [\n '#4a9eff', '#ff6b6b', '#4ecdc4', '#fbbf24',\n '#a78bfa', '#f472b6', '#34d399', '#fb923c',\n] as const;\n\nexport function get_split_color(index: number): string {\n return SPLIT_COLORS[index % SPLIT_COLORS.length];\n}\n","/**\n * Split Panel Card Component\n * Displays a single split segment in the left panel.\n * Shows label, page range, confidence, thumbnails, and reassignment controls.\n */\n\nimport React, { useState } from 'react';\nimport { ChevronRight, ChevronDown } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type { PdfSplit } from './types';\nimport { get_split_color } from './split_colors';\n\nexport interface SplitPanelCardProps {\n split: PdfSplit;\n index: number;\n is_selected: boolean;\n read_only: boolean;\n is_adding_split: boolean;\n total_splits: number;\n prev_split_color: string | null;\n next_split_color: string | null;\n on_select: (split_id: string) => void;\n on_move_first_to_prev: (split_id: string) => void;\n on_move_last_to_next: (split_id: string) => void;\n on_insert_split_after_page: (page_number: number) => void;\n}\n\n/**\n * Small colored page number thumbnail box.\n * When in \"add split\" mode, renders an insertion indicator bar\n * between this thumbnail and the next.\n */\ninterface PageThumbProps {\n page_num: number;\n color: string;\n show_insert_after: boolean;\n on_insert_after: (page_num: number) => void;\n}\n\nconst PageThumb: React.FC<PageThumbProps> = ({\n page_num,\n color,\n show_insert_after,\n on_insert_after,\n}) => (\n <div className=\"cls_split_thumb_wrapper\" style={{ display: 'flex', alignItems: 'center', gap: 0 }}>\n {/* Thumbnail box */}\n <div\n className=\"cls_split_page_thumb\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 28,\n height: 32,\n borderRadius: 4,\n border: `2px solid ${color}`,\n backgroundColor: `${color}22`,\n fontSize: 10,\n fontWeight: 600,\n color: color,\n flexShrink: 0,\n }}\n >\n {page_num}\n </div>\n\n {/* Insertion indicator bar (after this thumb) */}\n {show_insert_after && (\n <button\n type=\"button\"\n title={`Insert split after page ${page_num}`}\n onClick={(e) => {\n e.stopPropagation();\n on_insert_after(page_num);\n }}\n className=\"cls_split_insert_bar\"\n style={{\n width: 6,\n height: 32,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: '#4a9eff55',\n flexShrink: 0,\n transition: 'background-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#4a9eff';\n (e.currentTarget as HTMLButtonElement).style.boxShadow = '0 0 6px #4a9effaa';\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#4a9eff55';\n (e.currentTarget as HTMLButtonElement).style.boxShadow = '';\n }}\n />\n )}\n </div>\n);\n\n/**\n * Split Panel Card\n */\nexport const SplitPanelCard: React.FC<SplitPanelCardProps> = ({\n split,\n index,\n is_selected,\n read_only,\n is_adding_split,\n total_splits,\n prev_split_color,\n next_split_color,\n on_select,\n on_move_first_to_prev,\n on_move_last_to_next,\n on_insert_split_after_page,\n}) => {\n const [manually_expanded, set_manually_expanded] = useState(false);\n\n // Auto-expand when selected or in add-split mode (spec requirement)\n const is_expanded = manually_expanded || is_selected || is_adding_split;\n\n const { pages, label, classification } = split;\n const first_page = pages[0];\n const last_page = pages[pages.length - 1];\n const page_count = pages.length;\n\n const confidence_pct = classification?.confidence != null\n ? `${Math.round(classification.confidence * 100)}%`\n : null;\n\n const page_range =\n page_count === 1\n ? `p.${first_page}`\n : `p.${first_page}–${last_page}`;\n\n const card_color = get_split_color(index);\n\n // Show arrows when selected, not read-only, and more than 1 page\n const show_arrows = is_selected && !read_only && page_count > 1;\n const show_prev_arrow = show_arrows && prev_split_color !== null;\n const show_next_arrow = show_arrows && next_split_color !== null;\n\n // Thumbnail rendering\n const MAX_COLLAPSED_THUMBS = 3;\n const visible_pages = is_expanded ? pages : pages.slice(0, MAX_COLLAPSED_THUMBS);\n const overflow_count = !is_expanded && pages.length > MAX_COLLAPSED_THUMBS\n ? pages.length - MAX_COLLAPSED_THUMBS\n : 0;\n\n const handle_header_click = () => {\n on_select(split.split_id);\n if (is_selected) {\n set_manually_expanded((prev) => !prev);\n } else {\n set_manually_expanded(true);\n }\n };\n\n return (\n <div\n className={cn('cls_split_panel_card', is_selected && 'cls_split_panel_card_selected')}\n style={{\n borderRadius: 6,\n marginBottom: 8,\n border: `1px solid ${is_selected ? card_color : '#334155'}`,\n backgroundColor: is_selected ? '#1e293b' : '#0f172a',\n overflow: 'hidden',\n transition: 'border-color 0.15s',\n }}\n >\n {/* Card header — click to select/toggle */}\n <button\n type=\"button\"\n className=\"cls_split_panel_card_header\"\n onClick={handle_header_click}\n aria-label={`Split ${index + 1} of ${total_splits}: ${label}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n padding: '8px 10px',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n gap: 8,\n textAlign: 'left',\n }}\n >\n {/* Color accent stripe */}\n <div\n style={{\n width: 3,\n height: 32,\n borderRadius: 2,\n backgroundColor: card_color,\n flexShrink: 0,\n }}\n />\n\n {/* Label + meta */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n style={{\n fontSize: 12,\n fontWeight: 600,\n color: '#e2e8f0',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {label}\n </div>\n <div style={{ fontSize: 10, color: '#94a3b8', marginTop: 1, display: 'flex', gap: 6 }}>\n <span>{page_range}</span>\n {page_count !== 1 && (\n <span>({page_count} pages)</span>\n )}\n {confidence_pct && (\n <span style={{ color: card_color }}>{confidence_pct}</span>\n )}\n </div>\n </div>\n\n {/* Expand/collapse icon */}\n {is_selected ? (\n <ChevronDown size={14} color=\"#94a3b8\" />\n ) : (\n <ChevronRight size={14} color=\"#94a3b8\" />\n )}\n </button>\n\n {/* Thumbnail strip */}\n <div\n className=\"cls_split_panel_card_thumbs\"\n style={{\n padding: '0 10px 10px 22px',\n display: 'flex',\n flexWrap: is_expanded ? 'wrap' : 'nowrap',\n gap: 4,\n maxHeight: is_expanded ? 150 : undefined,\n overflowY: is_expanded ? 'auto' : undefined,\n alignItems: 'center',\n }}\n >\n {visible_pages.map((page_num, thumb_idx) => {\n const is_first = page_num === first_page;\n const is_last = page_num === last_page;\n\n // Show insertion bar between thumbnails (not after the last one) in add-split mode\n const show_insert_after =\n is_adding_split && thumb_idx < visible_pages.length - 1;\n\n return (\n <div\n key={page_num}\n style={{ display: 'flex', alignItems: 'center', gap: 4 }}\n >\n {/* ◀ Arrow: move first page to previous split */}\n {show_prev_arrow && is_first && (\n <button\n type=\"button\"\n title=\"Move page to previous split\"\n onClick={(e) => {\n e.stopPropagation();\n on_move_first_to_prev(split.split_id);\n }}\n style={{\n width: 18,\n height: 18,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: prev_split_color ?? card_color,\n color: '#fff',\n fontSize: 10,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n opacity: 0.9,\n }}\n >\n ◀\n </button>\n )}\n\n <PageThumb\n page_num={page_num}\n color={card_color}\n show_insert_after={show_insert_after}\n on_insert_after={on_insert_split_after_page}\n />\n\n {/* ▶ Arrow: move last page to next split */}\n {show_next_arrow && is_last && (\n <button\n type=\"button\"\n title=\"Move page to next split\"\n onClick={(e) => {\n e.stopPropagation();\n on_move_last_to_next(split.split_id);\n }}\n style={{\n width: 18,\n height: 18,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: next_split_color ?? card_color,\n color: '#fff',\n fontSize: 10,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n opacity: 0.9,\n }}\n >\n ▶\n </button>\n )}\n </div>\n );\n })}\n\n {/* Overflow count badge */}\n {overflow_count > 0 && (\n <div\n style={{\n fontSize: 10,\n color: '#94a3b8',\n backgroundColor: '#1e293b',\n border: '1px solid #334155',\n borderRadius: 4,\n padding: '2px 5px',\n flexShrink: 0,\n }}\n >\n +{overflow_count}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default SplitPanelCard;\n","/**\n * Split Viewer Layout Component\n * Right-side continuous-scroll area for the split viewer.\n * Loads and renders pages belonging to the selected split.\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react';\nimport type { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist';\nimport type { PdfSplit } from './types';\nimport { SplitPageRenderer } from './split_page_renderer';\nimport { get_split_color } from './split_colors';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\nexport interface SplitViewerLayoutProps {\n /** Loaded PDF document to render pages from */\n pdf_document: PDFDocumentProxy;\n\n /** Currently selected split (null = nothing to show) */\n selected_split: PdfSplit | null;\n\n /** 0-based index of the selected split in the parent splits array (drives color) */\n selected_split_index: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Optional class name */\n className?: string;\n}\n\nexport const SplitViewerLayout: React.FC<SplitViewerLayoutProps> = ({\n pdf_document,\n selected_split,\n selected_split_index,\n scale,\n className = '',\n}) => {\n const [pages, setPages] = useState<PDFPageProxy[]>([]);\n const [loading, setLoading] = useState(false);\n const [visible_page_index, setVisiblePageIndex] = useState(0);\n\n const container_ref = useRef<HTMLDivElement>(null);\n const page_refs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // Load pages for the current split whenever it changes\n useEffect(() => {\n if (!selected_split || selected_split.pages.length === 0) {\n setPages([]);\n return;\n }\n\n setLoading(true);\n setVisiblePageIndex(0);\n\n const page_promises = selected_split.pages.map((page_num) =>\n pdf_document.getPage(page_num)\n );\n\n Promise.all(page_promises)\n .then((loaded_pages) => {\n setPages(loaded_pages);\n setLoading(false);\n })\n .catch((error) => {\n const logger = get_logger();\n logger.error('SplitViewerLayout: Error loading pages', { data: error });\n setLoading(false);\n });\n }, [pdf_document, selected_split]);\n\n // Scroll to top when split selection changes\n useEffect(() => {\n if (container_ref.current) {\n container_ref.current.scrollTop = 0;\n }\n }, [selected_split?.split_id]);\n\n // Track the most visible page using IntersectionObserver\n useEffect(() => {\n if (!container_ref.current || pages.length === 0) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n let max_ratio = 0;\n let most_visible = 0;\n\n entries.forEach((entry) => {\n const idx = parseInt(entry.target.getAttribute('data-split-page-index') || '0', 10);\n if (entry.intersectionRatio > max_ratio) {\n max_ratio = entry.intersectionRatio;\n most_visible = idx;\n }\n });\n\n if (max_ratio > 0) {\n setVisiblePageIndex(most_visible);\n }\n },\n {\n root: container_ref.current,\n threshold: [0, 0.25, 0.5, 0.75, 1.0],\n }\n );\n\n page_refs.current.forEach((el) => observer.observe(el));\n\n return () => {\n observer.disconnect();\n };\n }, [pages.length]);\n\n // Stable ref callback for page wrappers\n const set_page_ref = useCallback((index: number, el: HTMLDivElement | null) => {\n if (el) {\n page_refs.current.set(index, el);\n } else {\n page_refs.current.delete(index);\n }\n }, []);\n\n // Derived display values\n const accent_color = get_split_color(selected_split_index);\n const total_pages = selected_split?.pages.length ?? 0;\n const current_display_page = visible_page_index + 1;\n\n // Format page range label (e.g. \"pp. 3–7\" or \"p. 5\")\n const page_range_label = (() => {\n if (!selected_split || selected_split.pages.length === 0) return '';\n const sorted = [...selected_split.pages].sort((a, b) => a - b);\n if (sorted.length === 1) return `p. ${sorted[0]}`;\n return `pp. ${sorted[0]}–${sorted[sorted.length - 1]}`;\n })();\n\n // --- Empty state ---\n if (!selected_split) {\n return (\n <div\n className={cn('cls_split_viewer_layout cls_split_viewer_empty', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#2d2d2d',\n color: '#888',\n fontSize: '14px',\n height: '100%',\n }}\n >\n Select a split to preview its pages\n </div>\n );\n }\n\n // --- Loading state ---\n if (loading) {\n return (\n <div\n className={cn('cls_split_viewer_layout cls_split_viewer_loading', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#2d2d2d',\n color: '#aaa',\n fontSize: '14px',\n height: '100%',\n }}\n >\n Loading pages…\n </div>\n );\n }\n\n return (\n <div\n className={cn('cls_split_viewer_layout', className)}\n style={{\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n backgroundColor: '#2d2d2d',\n overflow: 'hidden',\n }}\n >\n {/* Sticky label bar */}\n <div\n className=\"cls_split_viewer_label_bar\"\n style={{\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: '#1e1e1e',\n borderBottom: `2px solid ${accent_color}`,\n }}\n >\n {/* Color swatch */}\n <span\n className=\"cls_split_label_swatch\"\n style={{\n display: 'inline-block',\n width: '10px',\n height: '10px',\n borderRadius: '50%',\n backgroundColor: accent_color,\n flexShrink: 0,\n }}\n />\n\n {/* Split name */}\n <span\n className=\"cls_split_label_name\"\n style={{\n color: '#f0f0f0',\n fontWeight: 600,\n fontSize: '13px',\n flexShrink: 0,\n }}\n >\n {selected_split.label}\n </span>\n\n {/* Page range */}\n <span\n className=\"cls_split_label_range\"\n style={{\n color: '#aaa',\n fontSize: '12px',\n flexShrink: 0,\n }}\n >\n {page_range_label} · {total_pages} page{total_pages !== 1 ? 's' : ''}\n </span>\n\n {/* Confidence badge */}\n {selected_split.classification && (\n <span\n className=\"cls_split_label_confidence\"\n style={{\n marginLeft: 'auto',\n color: '#aaa',\n fontSize: '11px',\n whiteSpace: 'nowrap',\n }}\n >\n {selected_split.classification.document_type}\n {' '}\n <span style={{ color: accent_color, fontWeight: 600 }}>\n {Math.round(selected_split.classification.confidence * 100)}%\n </span>\n </span>\n )}\n </div>\n\n {/* Scrollable pages area */}\n <div\n ref={container_ref}\n className=\"cls_split_viewer_scroll\"\n style={{\n flex: 1,\n overflowY: 'auto',\n overflowX: 'auto',\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n alignItems: 'center',\n }}\n >\n {pages.map((page, index) => {\n const original_page_num = selected_split.pages[index];\n\n return (\n <div\n key={`${selected_split.split_id}-page-${index}`}\n ref={(el) => set_page_ref(index, el)}\n data-split-page-index={index}\n className=\"cls_split_page_wrapper\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: '6px',\n flexShrink: 0,\n }}\n >\n <SplitPageRenderer\n page={page}\n page_number={original_page_num}\n scale={scale}\n />\n\n {/* Page number badge below each page */}\n <span\n className=\"cls_split_page_badge\"\n style={{\n fontSize: '11px',\n color: '#888',\n userSelect: 'none',\n }}\n >\n Page {original_page_num}\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Floating page indicator */}\n {total_pages > 0 && (\n <div\n className=\"cls_split_viewer_page_indicator\"\n style={{\n position: 'absolute',\n bottom: '12px',\n right: '12px',\n backgroundColor: 'rgba(0,0,0,0.65)',\n color: '#ddd',\n fontSize: '12px',\n padding: '4px 10px',\n borderRadius: '12px',\n pointerEvents: 'none',\n userSelect: 'none',\n }}\n >\n Page {current_display_page} of {total_pages}\n </div>\n )}\n </div>\n );\n};\n\nexport default SplitViewerLayout;\n","/**\n * Split Page Renderer Component\n * Renders a single PDF page to canvas for the split viewer.\n * Simplified version of PdfPageRenderer — no annotation overlay or coordinate mapping.\n */\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\nexport interface SplitPageRendererProps {\n /** PDF page proxy object */\n page: PDFPageProxy;\n\n /** 1-indexed page number (for display / aria labels) */\n page_number: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Optional class name */\n className?: string;\n}\n\nexport const SplitPageRenderer: React.FC<SplitPageRendererProps> = ({\n page,\n page_number,\n scale,\n className = '',\n}) => {\n const canvas_ref = useRef<HTMLCanvasElement>(null);\n const render_task_ref = useRef<any>(null);\n\n // Calculate display dimensions from the viewport\n const viewport_dimensions = useMemo(() => {\n if (!page) return { width: 0, height: 0 };\n const viewport = page.getViewport({ scale });\n return { width: viewport.width, height: viewport.height };\n }, [page, scale]);\n\n // Render the page onto the canvas\n useEffect(() => {\n if (typeof window === 'undefined') return;\n if (!page) return;\n if (!canvas_ref.current) return;\n\n let cancelled = false;\n\n const cancel_previous = async () => {\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n await render_task_ref.current.promise.catch(() => {\n // Ignore cancellation errors\n });\n } catch (_error) {\n // Ignore errors from cancellation\n }\n render_task_ref.current = null;\n }\n };\n\n cancel_previous().then(() => {\n // Bail out if the effect was cleaned up during the async cancel\n if (cancelled || !canvas_ref.current) return;\n\n const viewport = page.getViewport({ scale });\n const canvas = canvas_ref.current;\n const context = canvas.getContext('2d', { alpha: false });\n\n if (!context) {\n const logger = get_logger();\n logger.error(`SplitPageRenderer page ${page_number}: Cannot get 2D context`);\n return;\n }\n\n // High DPI support\n const output_scale = window.devicePixelRatio || 1;\n\n // Setting width/height clears the canvas and invalidates any prior render task\n canvas.width = viewport.width * output_scale;\n canvas.height = viewport.height * output_scale;\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n // Scale context to match device pixel ratio\n context.scale(output_scale, output_scale);\n\n // Ensure transparent PDF areas appear white\n context.fillStyle = '#ffffff';\n context.fillRect(0, 0, viewport.width, viewport.height);\n\n const render_context = {\n canvasContext: context,\n viewport,\n annotationMode: 0, // Do not render PDF annotations on canvas\n background: 'white',\n };\n\n const render_task = page.render(render_context);\n render_task_ref.current = render_task;\n\n render_task.promise\n .then(() => {\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n })\n .catch((error) => {\n if (error.name !== 'RenderingCancelledException') {\n const logger = get_logger();\n logger.error(`SplitPageRenderer page ${page_number}: Error rendering`, { data: error });\n }\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n });\n });\n\n // Cleanup: cancel in-progress render on unmount or dep change\n return () => {\n cancelled = true;\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n } catch (_error) {\n // Ignore\n }\n render_task_ref.current = null;\n }\n };\n }, [page, scale, page_number]);\n\n if (!page) {\n return (\n <div className={cn('cls_split_page_loading', className)}>\n <div className=\"cls_split_page_spinner\">Loading page...</div>\n </div>\n );\n }\n\n return (\n <div\n className={cn('cls_split_page_container', className)}\n style={{\n position: 'relative',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n backgroundColor: '#ffffff',\n boxShadow: '0 2px 8px rgba(0,0,0,0.4)',\n }}\n >\n <canvas\n ref={canvas_ref}\n className=\"cls_split_page_canvas\"\n style={{\n display: 'block',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n pointerEvents: 'none',\n }}\n aria-label={`PDF page ${page_number}`}\n />\n </div>\n );\n};\n\nexport default SplitPageRenderer;\n"],"mappings":"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","names":["PdfViewer","useState","useEffect","useCallback","useRef","jsx","useRef","useEffect","jsx","jsxs","jsx","jsxs","useRef","useEffect","useState","useRef","useEffect","useCallback","useRef","useEffect","jsx","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","useCallback","total_pages","jsx","jsxs","useEffect","useState","useRef","useCallback"]}
1
+ {"version":3,"sources":["../src/components/pdf_viewer/pdf_viewer_dialog.tsx","../src/utils/xfdf_generator.ts","../src/components/split_viewer/pdf_split_viewer.tsx","../src/components/split_viewer/split_viewer_toolbar.tsx","../src/components/split_viewer/split_panel.tsx","../src/components/split_viewer/split_colors.ts","../src/components/split_viewer/split_panel_card.tsx","../src/components/split_viewer/split_viewer_layout.tsx","../src/components/split_viewer/split_page_renderer.tsx"],"sourcesContent":["/**\n * PdfViewerDialog component\n * Renders PdfViewer in a modal/dialog overlay\n */\n\n\"use client\";\n\nimport React, { Suspense, useCallback, useEffect, useRef, lazy } from \"react\";\nimport type { PdfViewerProps } from \"../../types\";\n\n// Lazy load PdfViewer to avoid SSR issues with pdfjs-dist\nconst PdfViewer = lazy(() =>\n import(\"./pdf_viewer\").then((mod) => ({ default: mod.PdfViewer }))\n);\n\n/**\n * Props for PdfViewerDialog component\n * Extends PdfViewerProps with dialog-specific props\n */\nexport interface PdfViewerDialogProps extends Omit<PdfViewerProps, \"on_close\"> {\n /** Whether the dialog is open */\n open: boolean;\n\n /** Callback when open state should change (close requested) */\n on_open_change: (open: boolean) => void;\n\n /** Dialog width (default: \"90vw\") */\n dialog_width?: string;\n\n /** Dialog height (default: \"90vh\") */\n dialog_height?: string;\n\n /** Whether clicking the backdrop closes the dialog (default: true) */\n close_on_backdrop_click?: boolean;\n\n /** Whether pressing Escape closes the dialog (default: true) */\n close_on_escape?: boolean;\n\n /** Loading fallback content (default: \"Loading PDF viewer...\") */\n loading_fallback?: React.ReactNode;\n\n /** Additional class names for the dialog container */\n dialog_class_name?: string;\n\n /** Additional class names for the backdrop overlay */\n backdrop_class_name?: string;\n}\n\n/**\n * PdfViewerDialog component\n * Renders PdfViewer in a centered modal with backdrop overlay\n *\n * @example\n * ```tsx\n * import { PdfViewerDialog } from \"hazo_pdf\";\n * import \"hazo_pdf/styles.css\";\n *\n * function App() {\n * const [isOpen, setIsOpen] = useState(false);\n *\n * return (\n * <>\n * <button onClick={() => setIsOpen(true)}>Open PDF</button>\n * <PdfViewerDialog\n * open={isOpen}\n * on_open_change={setIsOpen}\n * url=\"/document.pdf\"\n * />\n * </>\n * );\n * }\n * ```\n */\nexport function PdfViewerDialog({\n open,\n on_open_change,\n dialog_width = \"90vw\",\n dialog_height = \"90vh\",\n close_on_backdrop_click = true,\n close_on_escape = true,\n loading_fallback,\n dialog_class_name,\n backdrop_class_name,\n className,\n ...pdf_viewer_props\n}: PdfViewerDialogProps) {\n const dialog_ref = useRef<HTMLDivElement>(null);\n\n // Handle close\n const handle_close = useCallback(() => {\n on_open_change(false);\n }, [on_open_change]);\n\n // Handle backdrop click\n const handle_backdrop_click = useCallback(\n (e: React.MouseEvent) => {\n if (close_on_backdrop_click && e.target === e.currentTarget) {\n handle_close();\n }\n },\n [close_on_backdrop_click, handle_close]\n );\n\n // Handle escape key\n useEffect(() => {\n if (!open || !close_on_escape) return;\n\n const handle_keydown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n handle_close();\n }\n };\n\n document.addEventListener(\"keydown\", handle_keydown);\n return () => document.removeEventListener(\"keydown\", handle_keydown);\n }, [open, close_on_escape, handle_close]);\n\n // Prevent body scroll when dialog is open\n useEffect(() => {\n if (!open) return;\n\n const original_overflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = original_overflow;\n };\n }, [open]);\n\n // Focus trap - focus dialog when opened\n useEffect(() => {\n if (open && dialog_ref.current) {\n dialog_ref.current.focus();\n }\n }, [open]);\n\n // Don't render if not open\n if (!open) {\n return null;\n }\n\n const default_fallback = (\n <div className=\"flex items-center justify-center h-full w-full p-8 text-center text-gray-500\">\n Loading PDF viewer...\n </div>\n );\n\n return (\n <div\n className={`cls_pdf_viewer_dialog_backdrop fixed inset-0 bg-black/50 flex items-center justify-center z-50 ${backdrop_class_name || \"\"}`}\n onClick={handle_backdrop_click}\n role=\"dialog\"\n aria-modal=\"true\"\n >\n <div\n ref={dialog_ref}\n className={`cls_pdf_viewer_dialog bg-white rounded-lg overflow-hidden shadow-xl ${dialog_class_name || \"\"}`}\n style={{ width: dialog_width, height: dialog_height }}\n tabIndex={-1}\n >\n <Suspense fallback={loading_fallback || default_fallback}>\n <PdfViewer\n {...pdf_viewer_props}\n className={`h-full w-full ${className || \"\"}`}\n on_close={handle_close}\n />\n </Suspense>\n </div>\n </div>\n );\n}\n\nexport default PdfViewerDialog;\n","/**\n * XFDF Generator Utility\n * Converts annotation and bookmark data to XFDF (XML Forms Data Format)\n * XFDF is the standard format for PDF annotations\n */\n\nimport type { PdfAnnotation, PdfBookmark } from '../types';\nimport { get_logger } from './logger';\n\n/**\n * Format date to PDF date format: D:YYYYMMDDhhmmss[Z+-hh'mm']\n * @param date - Date object or ISO string\n * @returns Formatted date string\n */\nfunction format_pdf_date(date: Date | string): string {\n const logger = get_logger();\n let date_obj: Date;\n\n if (typeof date === 'string') {\n // Try to parse the date string\n date_obj = new Date(date);\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n logger.warn(`Invalid date string: ${date}. Using current date.`);\n date_obj = new Date();\n }\n } else {\n date_obj = date;\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n logger.warn(`Invalid date object. Using current date.`);\n date_obj = new Date();\n }\n }\n \n const year = date_obj.getFullYear();\n const month = String(date_obj.getMonth() + 1).padStart(2, '0');\n const day = String(date_obj.getDate()).padStart(2, '0');\n const hours = String(date_obj.getHours()).padStart(2, '0');\n const minutes = String(date_obj.getMinutes()).padStart(2, '0');\n const seconds = String(date_obj.getSeconds()).padStart(2, '0');\n \n // Get timezone offset\n const offset_minutes = date_obj.getTimezoneOffset();\n const offset_hours = Math.abs(Math.floor(offset_minutes / 60));\n const offset_mins = Math.abs(offset_minutes % 60);\n const offset_sign = offset_minutes <= 0 ? '+' : '-';\n \n return `D:${year}${month}${day}${hours}${minutes}${seconds}${offset_sign}${String(offset_hours).padStart(2, '0')}'${String(offset_mins).padStart(2, '0')}'`;\n}\n\n/**\n * Escape XML special characters\n * @param text - Text to escape\n * @returns Escaped text\n */\nfunction escape_xml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n\n/**\n * Convert annotation type to XFDF tag name\n * @param type - Annotation type\n * @returns XFDF tag name (lowercase)\n */\nfunction annotation_type_to_tag(type: PdfAnnotation['type']): string {\n return type.toLowerCase();\n}\n\n/**\n * Generate XFDF XML from annotations and bookmarks\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @returns XFDF XML string\n */\nexport function generate_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf'\n): string {\n // Start XML boilerplate\n let xfdf = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\n xfdf += `<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\\n`;\n xfdf += ` <f href=\"${escape_xml(pdf_file_name)}\"/>\\n`;\n\n // Add annotations\n if (annotations.length > 0) {\n xfdf += ` <annots>\\n`;\n\n annotations.forEach((ann) => {\n // Format rectangle coordinates\n const rect_string = ann.rect.map((c) => c.toFixed(2)).join(', ');\n\n // Format date - ensure it's valid\n let date_string: string;\n try {\n date_string = format_pdf_date(ann.date);\n } catch (error) {\n const logger = get_logger();\n logger.warn(`Error formatting date for annotation ${ann.id}`, { data: error });\n // Fallback to current date\n date_string = format_pdf_date(new Date());\n }\n\n // Get tag name\n const tag_name = annotation_type_to_tag(ann.type);\n\n // Build annotation attributes\n const attributes: string[] = [];\n attributes.push(`subject=\"${escape_xml(ann.subject || ann.type)}\"`);\n attributes.push(`page=\"${ann.page_index}\"`);\n attributes.push(`rect=\"${rect_string}\"`);\n attributes.push(`flags=\"print\"`);\n attributes.push(`name=\"${escape_xml(ann.id)}\"`);\n attributes.push(`title=\"${escape_xml(ann.author)}\"`);\n attributes.push(`date=\"${date_string}\"`);\n\n if (ann.color) {\n attributes.push(`color=\"${escape_xml(ann.color)}\"`);\n }\n\n // Build annotation element\n xfdf += ` <${tag_name} ${attributes.join(' ')}>\\n`;\n\n // Add contents if present\n if (ann.contents) {\n xfdf += ` <contents><![CDATA[${ann.contents}]]></contents>\\n`;\n }\n\n // Close annotation tag\n xfdf += ` </${tag_name}>\\n`;\n });\n\n xfdf += ` </annots>\\n`;\n }\n\n // Add bookmarks\n if (bookmarks.length > 0) {\n xfdf += ` <bookmarks>\\n`;\n\n bookmarks.forEach((bookmark) => {\n const attributes: string[] = [];\n attributes.push(`title=\"${escape_xml(bookmark.title)}\"`);\n attributes.push(`action=\"${bookmark.action || 'GoTo'}\"`);\n attributes.push(`page=\"${bookmark.page_index}\"`);\n\n if (bookmark.y !== undefined) {\n attributes.push(`y=\"${bookmark.y}\"`);\n }\n\n xfdf += ` <bookmark ${attributes.join(' ')} />\\n`;\n });\n\n xfdf += ` </bookmarks>\\n`;\n }\n\n // Close XFDF\n xfdf += `</xfdf>`;\n\n return xfdf;\n}\n\n/**\n * Download XFDF file\n * @param xfdf_content - XFDF XML content\n * @param file_name - Name for the downloaded file\n */\nexport function download_xfdf(xfdf_content: string, file_name: string = 'annotations.xfdf'): void {\n const blob = new Blob([xfdf_content], { type: 'application/vnd.adobe.xfdf' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = file_name;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Generate and download XFDF file\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @param file_name - Name for the downloaded file\n */\nexport function export_annotations_to_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf',\n file_name: string = 'annotations.xfdf'\n): void {\n const xfdf_content = generate_xfdf(annotations, bookmarks, pdf_file_name);\n download_xfdf(xfdf_content, file_name);\n}\n","/**\n * PdfSplitViewer — Main orchestrator component\n *\n * Loads a PDF document, manages split state, and wires together:\n * - SplitViewerToolbar (top bar: zoom + split actions)\n * - SplitPanel (left sidebar: split list)\n * - SplitViewerLayout (right area: page preview)\n */\n\n'use client';\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\n\nimport { load_pdf_document } from '../pdf_viewer/pdf_worker_setup';\nimport { set_logger, get_logger } from '../../utils/logger';\nimport { cn } from 'hazo_ui';\nimport { HazoExternalError, HazoValidationError } from 'hazo_core/errors';\n\nimport { SplitViewerToolbar } from './split_viewer_toolbar';\nimport { SplitPanel } from './split_panel';\nimport { SplitViewerLayout } from './split_viewer_layout';\n\nimport type {\n PdfSplit,\n PdfSplitViewerProps,\n PdfSplitRequest,\n PdfSplitResult,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generate_split_id(): string {\n return `split_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\n/**\n * Deep-clone splits so mutations don't affect the original array.\n */\nfunction clone_splits(splits: PdfSplit[]): PdfSplit[] {\n return splits.map((s) => ({ ...s, pages: [...s.pages] }));\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport const PdfSplitViewer: React.FC<PdfSplitViewerProps> = ({\n url,\n file_manager,\n file_id,\n file_name: _file_name,\n splits: initial_splits,\n on_splits_changed,\n on_splits_confirmed,\n split_api_endpoint,\n output_folder,\n read_only = false,\n className,\n initial_scale = 1.0,\n fit_to_width = false,\n config_file: _config_file,\n logger,\n}) => {\n // ------ Logger setup ------\n useEffect(() => {\n if (logger) {\n set_logger(logger);\n }\n }, [logger]);\n\n // ------ PDF document ------\n const [pdf_document, set_pdf_document] = useState<PDFDocumentProxy | null>(null);\n const [pdf_loading, set_pdf_loading] = useState(true);\n const [pdf_error, set_pdf_error] = useState<string | null>(null);\n\n // ------ Split state ------\n const [splits, set_splits] = useState<PdfSplit[]>(() => clone_splits(initial_splits));\n const [original_splits] = useState<PdfSplit[]>(() => clone_splits(initial_splits));\n const [selected_split_id, set_selected_split_id] = useState<string | null>(\n initial_splits.length > 0 ? initial_splits[0].split_id : null\n );\n\n // ------ UI state ------\n const [scale, set_scale] = useState(initial_scale);\n const [is_adding_split, set_is_adding_split] = useState(false);\n const [is_confirming, set_is_confirming] = useState(false);\n const [panel_width, set_panel_width] = useState(300);\n\n // Ref to the right-side layout container for fit-to-width calculations\n const layout_container_ref = useRef<HTMLDivElement>(null);\n\n // ------ Load PDF ------\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const log = get_logger();\n set_pdf_loading(true);\n set_pdf_error(null);\n\n const load = async () => {\n try {\n let source: string | ArrayBuffer | Uint8Array;\n\n if (url) {\n // Prefer direct URL when provided\n source = url;\n } else if (file_manager && file_id) {\n // Load via file_manager (hazo_files FileAccessProvider)\n log.info('PdfSplitViewer: loading file via file_manager', { data: { file_id } });\n const result = await file_manager.downloadFile(file_id);\n if (!result.success || !result.data) {\n throw new HazoExternalError({\n code: 'HAZO_PDF_EXTERNAL_DOWNLOAD_FAILED',\n pkg: 'hazo_pdf',\n message: result.error ?? 'Failed to download file',\n httpStatus: 502,\n });\n }\n source = result.data instanceof Uint8Array\n ? result.data\n : new Uint8Array(result.data as ArrayBuffer);\n } else {\n throw new HazoValidationError({\n code: 'HAZO_PDF_VALIDATION_ERROR',\n pkg: 'hazo_pdf',\n message: 'PdfSplitViewer: either url or file_manager + file_id must be provided',\n });\n }\n\n const doc = await load_pdf_document(source);\n set_pdf_document(doc);\n log.info('PdfSplitViewer: PDF loaded', { data: { pages: doc.numPages } });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('PdfSplitViewer: error loading PDF', { data: { error: message } });\n set_pdf_error(message);\n } finally {\n set_pdf_loading(false);\n }\n };\n\n load();\n }, [url, file_id]); // file_manager is stable; url/file_id drive reloads\n\n // ------ Escape key cancels add-split mode ------\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && is_adding_split) {\n set_is_adding_split(false);\n }\n };\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [is_adding_split]);\n\n // ------ Derived values ------\n const selected_split_index = splits.findIndex((s) => s.split_id === selected_split_id);\n const selected_split = selected_split_index >= 0 ? splits[selected_split_index] : null;\n\n const can_merge = selected_split !== null && splits.length > 1;\n\n // ------ Mutation helper ------\n const apply_splits = useCallback((next: PdfSplit[]) => {\n set_splits(next);\n on_splits_changed?.(next);\n }, [on_splits_changed]);\n\n // ------ Split operations ------\n\n const handle_move_first_to_prev = useCallback((split_id: string) => {\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === split_id);\n if (idx <= 0) return; // no previous split\n const current = next[idx];\n const prev = next[idx - 1];\n if (current.pages.length <= 1) return; // can't remove last page\n\n // Move the first page of current to the end of prev\n const [first_page, ...remaining] = current.pages;\n prev.pages = [...prev.pages, first_page];\n current.pages = remaining;\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_move_last_to_next = useCallback((split_id: string) => {\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === split_id);\n if (idx < 0 || idx >= next.length - 1) return; // no next split\n const current = next[idx];\n const nxt = next[idx + 1];\n if (current.pages.length <= 1) return; // can't remove last page\n\n // Move the last page of current to the start of next\n const last_page = current.pages[current.pages.length - 1];\n current.pages = current.pages.slice(0, -1);\n nxt.pages = [last_page, ...nxt.pages];\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_insert_split_after_page = useCallback((page_number: number) => {\n // Find which split contains this page\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.pages.includes(page_number));\n if (idx < 0) return;\n\n const target = next[idx];\n const split_point = target.pages.indexOf(page_number);\n\n if (split_point < 0 || split_point >= target.pages.length - 1) {\n // page is the last page in its split — nothing to split after\n return;\n }\n\n // Pages before and including the split point stay in original split\n const pages_before = target.pages.slice(0, split_point + 1);\n // Pages after form the new split\n const pages_after = target.pages.slice(split_point + 1);\n\n target.pages = pages_before;\n\n const new_split: PdfSplit = {\n split_id: generate_split_id(),\n label: 'Untitled Split',\n pages: pages_after,\n };\n\n // Insert new split after the target\n next.splice(idx + 1, 0, new_split);\n\n // Exit add-split mode and select the new split\n set_is_adding_split(false);\n set_selected_split_id(new_split.split_id);\n apply_splits(next);\n }, [splits, apply_splits]);\n\n const handle_merge = useCallback(() => {\n if (!selected_split) return;\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === selected_split.split_id);\n if (idx < 0 || next.length <= 1) return;\n\n if (idx < next.length - 1) {\n // Merge with next: keep label of selected, absorb next's pages\n const merged_pages = [...next[idx].pages, ...next[idx + 1].pages];\n next[idx] = { ...next[idx], pages: merged_pages };\n next.splice(idx + 1, 1);\n } else {\n // Last split: merge with previous, keep previous label\n const merged_pages = [...next[idx - 1].pages, ...next[idx].pages];\n next[idx - 1] = { ...next[idx - 1], pages: merged_pages };\n next.splice(idx, 1);\n set_selected_split_id(next[idx - 1].split_id);\n }\n\n apply_splits(next);\n }, [splits, selected_split, apply_splits]);\n\n const handle_rename = useCallback(() => {\n if (!selected_split) return;\n const new_label = window.prompt('Rename split:', selected_split.label);\n if (new_label === null) return; // cancelled\n const trimmed = new_label.trim();\n if (!trimmed || trimmed === selected_split.label) return;\n\n const next = clone_splits(splits);\n const idx = next.findIndex((s) => s.split_id === selected_split.split_id);\n if (idx >= 0) {\n next[idx] = { ...next[idx], label: trimmed };\n apply_splits(next);\n }\n }, [splits, selected_split, apply_splits]);\n\n const handle_reset = useCallback(() => {\n const restored = clone_splits(original_splits);\n set_selected_split_id(restored.length > 0 ? restored[0].split_id : null);\n apply_splits(restored);\n }, [original_splits, apply_splits]);\n\n const handle_confirm = useCallback(async () => {\n if (is_confirming) return;\n set_is_confirming(true);\n const log = get_logger();\n\n try {\n if (split_api_endpoint) {\n // POST to the provided API endpoint\n const body: PdfSplitRequest = {\n source_file_id: file_id,\n splits: splits.map((s) => ({\n split_id: s.split_id,\n label: s.label,\n pages: s.pages,\n classification: s.classification,\n })),\n output_folder,\n };\n\n log.info('PdfSplitViewer: posting split request', { data: { endpoint: split_api_endpoint } });\n\n const response = await fetch(split_api_endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => response.statusText);\n throw new HazoExternalError({\n code: 'HAZO_PDF_EXTERNAL_API_FAILED',\n pkg: 'hazo_pdf',\n message: `Split API error ${response.status}: ${text}`,\n httpStatus: 502,\n });\n }\n\n const result: PdfSplitResult = await response.json();\n log.info('PdfSplitViewer: split confirmed via API', { data: { splits: result.splits.length } });\n on_splits_confirmed?.(result);\n } else {\n // No API endpoint — return splits as a result with empty file info\n const result: PdfSplitResult = {\n source_file_id: file_id,\n splits: splits.map((s) => ({\n split_id: s.split_id,\n label: s.label,\n pages: s.pages,\n file_id: '',\n file_name: '',\n file_path: '',\n page_count: s.pages.length,\n byte_size: 0,\n })),\n };\n log.info('PdfSplitViewer: split confirmed (no API)', { data: { splits: result.splits.length } });\n on_splits_confirmed?.(result);\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('PdfSplitViewer: confirm failed', { data: { error: message } });\n // Surface the error visually via alert so the user knows what went wrong\n if (typeof window !== 'undefined') {\n window.alert(`Confirm failed: ${message}`);\n }\n } finally {\n set_is_confirming(false);\n }\n }, [splits, file_id, split_api_endpoint, output_folder, is_confirming, on_splits_confirmed]);\n\n // ------ Zoom handlers ------\n\n const handle_zoom_in = useCallback(() => {\n set_scale((s) => Math.min(s + 0.25, 4.0));\n }, []);\n\n const handle_zoom_out = useCallback(() => {\n set_scale((s) => Math.max(s - 0.25, 0.25));\n }, []);\n\n const handle_fit_to_width = useCallback(() => {\n if (!layout_container_ref.current || !pdf_document) return;\n\n // Approximate the container width minus some padding\n const container_width = layout_container_ref.current.clientWidth - 48; // 24px padding each side\n if (container_width <= 0) return;\n\n // Use the first page of the selected split (or page 1) to get the natural width\n const page_num = selected_split?.pages?.[0] ?? 1;\n\n pdf_document.getPage(page_num).then((page) => {\n const viewport = page.getViewport({ scale: 1 });\n const new_scale = container_width / viewport.width;\n set_scale(Math.max(0.25, Math.min(4.0, Math.round(new_scale * 100) / 100)));\n }).catch(() => {\n // ignore — page may not be available yet\n });\n }, [pdf_document, selected_split]);\n\n // Apply fit_to_width once on load\n useEffect(() => {\n if (fit_to_width && pdf_document) {\n handle_fit_to_width();\n }\n }, [fit_to_width, pdf_document]); // intentionally omit handle_fit_to_width to run once\n\n // ------ Add-split toggle ------\n const handle_add_split_toggle = useCallback(() => {\n set_is_adding_split((prev) => !prev);\n }, []);\n\n // ------ Render ------\n\n const root_class = cn('hazo-pdf-root cls_split_viewer', className);\n\n // Loading state\n if (pdf_loading) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#94a3b8',\n fontSize: 14,\n }}\n >\n Loading PDF…\n </div>\n );\n }\n\n // Error state\n if (pdf_error) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#f87171',\n fontSize: 14,\n padding: 24,\n textAlign: 'center',\n }}\n >\n Failed to load PDF: {pdf_error}\n </div>\n );\n }\n\n // Empty document state (document loaded but no pages — unlikely, but safe)\n if (!pdf_document) {\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n height: '100%',\n backgroundColor: '#1a1a2e',\n color: '#94a3b8',\n fontSize: 14,\n }}\n >\n No PDF document\n </div>\n );\n }\n\n return (\n <div\n className={root_class}\n style={{\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n overflow: 'hidden',\n backgroundColor: '#0f172a',\n }}\n >\n {/* ── Top toolbar ── */}\n <SplitViewerToolbar\n scale={scale}\n on_zoom_in={handle_zoom_in}\n on_zoom_out={handle_zoom_out}\n on_fit_to_width={handle_fit_to_width}\n on_add_split={handle_add_split_toggle}\n on_merge={handle_merge}\n on_rename={handle_rename}\n on_reset={handle_reset}\n on_confirm={handle_confirm}\n read_only={read_only}\n is_adding_split={is_adding_split}\n is_confirming={is_confirming}\n can_merge={can_merge}\n has_selected_split={selected_split !== null}\n />\n\n {/* ── Main content row ── */}\n <div\n style={{\n display: 'flex',\n flex: 1,\n overflow: 'hidden',\n }}\n >\n {/* Left: Split panel */}\n <SplitPanel\n splits={splits}\n selected_split_id={selected_split_id}\n width={panel_width}\n on_width_change={set_panel_width}\n on_select_split={set_selected_split_id}\n on_move_first_to_prev={handle_move_first_to_prev}\n on_move_last_to_next={handle_move_last_to_next}\n read_only={read_only}\n is_adding_split={is_adding_split}\n on_insert_split_after_page={handle_insert_split_after_page}\n />\n\n {/* Right: Page preview */}\n <div\n ref={layout_container_ref}\n style={{ flex: 1, overflow: 'hidden', height: '100%' }}\n >\n <SplitViewerLayout\n pdf_document={pdf_document}\n selected_split={selected_split}\n selected_split_index={selected_split_index >= 0 ? selected_split_index : 0}\n scale={scale}\n />\n </div>\n </div>\n </div>\n );\n};\n\nexport default PdfSplitViewer;\n","/**\n * Split Viewer Toolbar Component\n * Top toolbar for PdfSplitViewer: zoom controls, split actions, confirm button.\n */\n\nimport React from 'react';\nimport {\n ZoomIn,\n ZoomOut,\n Maximize2,\n Scissors,\n Merge,\n Pencil,\n RotateCcw,\n Check,\n Loader2,\n X,\n} from 'lucide-react';\nimport { cn } from 'hazo_ui';\n\nexport interface SplitViewerToolbarProps {\n scale: number;\n on_zoom_in: () => void;\n on_zoom_out: () => void;\n on_fit_to_width: () => void;\n on_add_split: () => void;\n on_merge: () => void;\n on_rename: () => void;\n on_reset: () => void;\n on_confirm: () => void;\n read_only: boolean;\n is_adding_split: boolean;\n is_confirming: boolean;\n can_merge: boolean;\n has_selected_split: boolean;\n}\n\n/** Small toolbar icon button with optional disabled/active styling */\ninterface ToolbarButtonProps {\n onClick: () => void;\n disabled?: boolean;\n title: string;\n children: React.ReactNode;\n active?: boolean;\n active_bg?: string;\n className?: string;\n}\n\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n onClick,\n disabled = false,\n title,\n children,\n active = false,\n active_bg,\n className,\n}) => (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n title={title}\n className={cn('cls_split_toolbar_btn', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 5,\n padding: '5px 10px',\n borderRadius: 5,\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n backgroundColor: active && active_bg\n ? active_bg\n : active\n ? '#475569'\n : '#334155',\n color: disabled ? '#475569' : '#e2e8f0',\n fontSize: 12,\n fontWeight: 500,\n opacity: disabled ? 0.5 : 1,\n transition: 'background-color 0.15s, opacity 0.15s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n if (!disabled) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n active && active_bg ? active_bg : '#475569';\n }\n }}\n onMouseLeave={(e) => {\n if (!disabled) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor =\n active && active_bg\n ? active_bg\n : active\n ? '#475569'\n : '#334155';\n }\n }}\n >\n {children}\n </button>\n);\n\n/** Thin vertical separator between toolbar groups */\nconst Separator: React.FC = () => (\n <div\n style={{\n width: 1,\n height: 22,\n backgroundColor: '#334155',\n flexShrink: 0,\n margin: '0 4px',\n }}\n />\n);\n\nexport const SplitViewerToolbar: React.FC<SplitViewerToolbarProps> = ({\n scale,\n on_zoom_in,\n on_zoom_out,\n on_fit_to_width,\n on_add_split,\n on_merge,\n on_rename,\n on_reset,\n on_confirm,\n read_only,\n is_adding_split,\n is_confirming,\n can_merge,\n has_selected_split,\n}) => {\n const zoom_pct = `${Math.round(scale * 100)}%`;\n\n return (\n <div\n className=\"cls_split_viewer_toolbar\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: '6px 12px',\n backgroundColor: '#1e293b',\n borderBottom: '1px solid #334155',\n flexShrink: 0,\n flexWrap: 'wrap',\n }}\n >\n {/* ── Zoom group ── */}\n <ToolbarButton onClick={on_zoom_out} title=\"Zoom out\">\n <ZoomOut size={15} />\n </ToolbarButton>\n\n {/* Zoom percentage display */}\n <div\n style={{\n minWidth: 44,\n textAlign: 'center',\n fontSize: 12,\n color: '#94a3b8',\n fontVariantNumeric: 'tabular-nums',\n userSelect: 'none',\n }}\n >\n {zoom_pct}\n </div>\n\n <ToolbarButton onClick={on_zoom_in} title=\"Zoom in\">\n <ZoomIn size={15} />\n </ToolbarButton>\n\n <ToolbarButton onClick={on_fit_to_width} title=\"Fit to width\">\n <Maximize2 size={15} />\n </ToolbarButton>\n\n <Separator />\n\n {/* ── Split actions (hidden when read_only) ── */}\n {!read_only && (\n <>\n {/* Add Split / Cancel toggle */}\n <ToolbarButton\n onClick={on_add_split}\n title={is_adding_split ? 'Cancel adding split' : 'Add split'}\n active={is_adding_split}\n active_bg=\"#b45309\"\n >\n {is_adding_split ? (\n <>\n <X size={14} />\n Cancel\n </>\n ) : (\n <>\n <Scissors size={14} />\n Add Split\n </>\n )}\n </ToolbarButton>\n\n <ToolbarButton\n onClick={on_merge}\n disabled={!can_merge}\n title=\"Merge selected split with adjacent\"\n >\n <Merge size={14} />\n Merge\n </ToolbarButton>\n\n <ToolbarButton\n onClick={on_rename}\n disabled={!has_selected_split}\n title=\"Rename selected split\"\n >\n <Pencil size={14} />\n Rename\n </ToolbarButton>\n\n <Separator />\n </>\n )}\n\n {/* Reset button (hidden in read-only) */}\n {!read_only && (\n <ToolbarButton onClick={on_reset} title=\"Reset splits to original\">\n <RotateCcw size={14} />\n Reset\n </ToolbarButton>\n )}\n\n {/* Spacer */}\n <div style={{ flex: 1 }} />\n\n {/* ── Confirm button (right-aligned, green, hidden in read-only) ── */}\n {!read_only && <button\n type=\"button\"\n onClick={on_confirm}\n disabled={is_confirming}\n title={is_confirming ? 'Splitting in progress…' : 'Confirm splits'}\n className=\"cls_split_toolbar_confirm_btn\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '5px 14px',\n borderRadius: 5,\n border: 'none',\n cursor: is_confirming ? 'not-allowed' : 'pointer',\n backgroundColor: is_confirming ? '#14532d' : '#16a34a',\n color: '#fff',\n fontSize: 12,\n fontWeight: 600,\n opacity: is_confirming ? 0.8 : 1,\n transition: 'background-color 0.15s, opacity 0.15s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n if (!is_confirming) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#15803d';\n }\n }}\n onMouseLeave={(e) => {\n if (!is_confirming) {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#16a34a';\n }\n }}\n >\n {is_confirming ? (\n <>\n <Loader2 size={14} className=\"cls_split_confirm_spinner\" style={{ animation: 'spin 1s linear infinite' }} />\n Splitting…\n </>\n ) : (\n <>\n <Check size={14} />\n Confirm Splits\n </>\n )}\n </button>}\n </div>\n );\n};\n\nexport default SplitViewerToolbar;\n","/**\n * Split Panel Component\n * Resizable left sidebar listing all split segments.\n * Follows the resize-handle pattern from file_info_sidepanel.tsx.\n */\n\nimport React, { useRef, useEffect } from 'react';\nimport type { PdfSplit } from './types';\nimport { get_split_color } from './split_colors';\nimport { SplitPanelCard } from './split_panel_card';\n\nexport interface SplitPanelProps {\n splits: PdfSplit[];\n selected_split_id: string | null;\n width: number;\n on_width_change: (width: number) => void;\n on_select_split: (split_id: string) => void;\n on_move_first_to_prev: (split_id: string) => void;\n on_move_last_to_next: (split_id: string) => void;\n read_only: boolean;\n is_adding_split: boolean;\n on_insert_split_after_page: (page_number: number) => void;\n}\n\nconst MIN_WIDTH = 200;\nconst MAX_WIDTH = 600;\n\n/**\n * Compute total page count across all splits.\n */\nfunction total_pages(splits: PdfSplit[]): number {\n const page_set = new Set<number>();\n for (const s of splits) {\n for (const p of s.pages) {\n page_set.add(p);\n }\n }\n return page_set.size;\n}\n\nexport const SplitPanel: React.FC<SplitPanelProps> = ({\n splits,\n selected_split_id,\n width,\n on_width_change,\n on_select_split,\n on_move_first_to_prev,\n on_move_last_to_next,\n read_only,\n is_adding_split,\n on_insert_split_after_page,\n}) => {\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Handle resize start (right edge drag)\n const handle_resize_start = (e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n is_resizing_ref.current = true;\n start_width_ref.current = width;\n start_x_ref.current = e.clientX;\n\n document.addEventListener('mousemove', handle_resize_move);\n document.addEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = 'ew-resize';\n document.body.style.userSelect = 'none';\n };\n\n // Dragging RIGHT increases width (left panel delta is positive when moving right)\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n const delta = e.clientX - start_x_ref.current;\n const new_width = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, start_width_ref.current + delta));\n on_width_change(new_width);\n };\n\n const handle_resize_end = () => {\n is_resizing_ref.current = false;\n document.removeEventListener('mousemove', handle_resize_move);\n document.removeEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n };\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n document.removeEventListener('mousemove', handle_resize_move);\n document.removeEventListener('mouseup', handle_resize_end);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n };\n }, []);\n\n const page_count = total_pages(splits);\n\n return (\n <div\n className=\"cls_split_panel\"\n style={{\n position: 'relative',\n width,\n flexShrink: 0,\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: '#111827',\n borderRight: '1px solid #334155',\n overflow: 'hidden',\n }}\n >\n {/* Header */}\n <div\n className=\"cls_split_panel_header\"\n style={{\n padding: '12px 14px 8px',\n borderBottom: '1px solid #1e293b',\n flexShrink: 0,\n }}\n >\n <div\n style={{\n fontSize: 13,\n fontWeight: 700,\n color: '#e2e8f0',\n marginBottom: 2,\n }}\n >\n Splits\n </div>\n <div style={{ fontSize: 11, color: '#64748b' }}>\n {splits.length} {splits.length === 1 ? 'document' : 'documents'} · {page_count} {page_count === 1 ? 'page' : 'pages'}\n </div>\n </div>\n\n {/* Scrollable list */}\n <div\n className=\"cls_split_panel_list\"\n style={{\n flex: 1,\n overflowY: 'auto',\n padding: '10px 10px 10px 10px',\n }}\n >\n {splits.map((split, index) => {\n const prev_color = index > 0 ? get_split_color(index - 1) : null;\n const next_color = index < splits.length - 1 ? get_split_color(index + 1) : null;\n\n return (\n <SplitPanelCard\n key={split.split_id}\n split={split}\n index={index}\n is_selected={selected_split_id === split.split_id}\n read_only={read_only}\n is_adding_split={is_adding_split}\n total_splits={splits.length}\n prev_split_color={prev_color}\n next_split_color={next_color}\n on_select={on_select_split}\n on_move_first_to_prev={on_move_first_to_prev}\n on_move_last_to_next={on_move_last_to_next}\n on_insert_split_after_page={on_insert_split_after_page}\n />\n );\n })}\n\n {splits.length === 0 && (\n <div\n style={{\n fontSize: 12,\n color: '#475569',\n textAlign: 'center',\n marginTop: 24,\n }}\n >\n No splits defined\n </div>\n )}\n </div>\n\n {/* Resize handle — right edge, 4px wide */}\n <div\n className=\"cls_split_panel_resize_handle\"\n onMouseDown={handle_resize_start}\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n width: 4,\n height: '100%',\n cursor: 'ew-resize',\n zIndex: 10,\n backgroundColor: 'transparent',\n transition: 'background-color 0.15s',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLDivElement).style.backgroundColor = '#334155';\n }}\n onMouseLeave={(e) => {\n if (!is_resizing_ref.current) {\n (e.currentTarget as HTMLDivElement).style.backgroundColor = 'transparent';\n }\n }}\n />\n </div>\n );\n};\n\nexport default SplitPanel;\n","/**\n * Fixed color palette for split viewer segments\n */\n\nexport const SPLIT_COLORS = [\n '#4a9eff', '#ff6b6b', '#4ecdc4', '#fbbf24',\n '#a78bfa', '#f472b6', '#34d399', '#fb923c',\n] as const;\n\nexport function get_split_color(index: number): string {\n return SPLIT_COLORS[index % SPLIT_COLORS.length];\n}\n","/**\n * Split Panel Card Component\n * Displays a single split segment in the left panel.\n * Shows label, page range, confidence, thumbnails, and reassignment controls.\n */\n\nimport React, { useState } from 'react';\nimport { ChevronRight, ChevronDown } from 'lucide-react';\nimport { cn } from 'hazo_ui';\nimport type { PdfSplit } from './types';\nimport { get_split_color } from './split_colors';\n\nexport interface SplitPanelCardProps {\n split: PdfSplit;\n index: number;\n is_selected: boolean;\n read_only: boolean;\n is_adding_split: boolean;\n total_splits: number;\n prev_split_color: string | null;\n next_split_color: string | null;\n on_select: (split_id: string) => void;\n on_move_first_to_prev: (split_id: string) => void;\n on_move_last_to_next: (split_id: string) => void;\n on_insert_split_after_page: (page_number: number) => void;\n}\n\n/**\n * Small colored page number thumbnail box.\n * When in \"add split\" mode, renders an insertion indicator bar\n * between this thumbnail and the next.\n */\ninterface PageThumbProps {\n page_num: number;\n color: string;\n show_insert_after: boolean;\n on_insert_after: (page_num: number) => void;\n}\n\nconst PageThumb: React.FC<PageThumbProps> = ({\n page_num,\n color,\n show_insert_after,\n on_insert_after,\n}) => (\n <div className=\"cls_split_thumb_wrapper\" style={{ display: 'flex', alignItems: 'center', gap: 0 }}>\n {/* Thumbnail box */}\n <div\n className=\"cls_split_page_thumb\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 28,\n height: 32,\n borderRadius: 4,\n border: `2px solid ${color}`,\n backgroundColor: `${color}22`,\n fontSize: 10,\n fontWeight: 600,\n color: color,\n flexShrink: 0,\n }}\n >\n {page_num}\n </div>\n\n {/* Insertion indicator bar (after this thumb) */}\n {show_insert_after && (\n <button\n type=\"button\"\n title={`Insert split after page ${page_num}`}\n onClick={(e) => {\n e.stopPropagation();\n on_insert_after(page_num);\n }}\n className=\"cls_split_insert_bar\"\n style={{\n width: 6,\n height: 32,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: '#4a9eff55',\n flexShrink: 0,\n transition: 'background-color 0.15s, box-shadow 0.15s',\n outline: 'none',\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#4a9eff';\n (e.currentTarget as HTMLButtonElement).style.boxShadow = '0 0 6px #4a9effaa';\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLButtonElement).style.backgroundColor = '#4a9eff55';\n (e.currentTarget as HTMLButtonElement).style.boxShadow = '';\n }}\n />\n )}\n </div>\n);\n\n/**\n * Split Panel Card\n */\nexport const SplitPanelCard: React.FC<SplitPanelCardProps> = ({\n split,\n index,\n is_selected,\n read_only,\n is_adding_split,\n total_splits,\n prev_split_color,\n next_split_color,\n on_select,\n on_move_first_to_prev,\n on_move_last_to_next,\n on_insert_split_after_page,\n}) => {\n const [manually_expanded, set_manually_expanded] = useState(false);\n\n // Auto-expand when selected or in add-split mode (spec requirement)\n const is_expanded = manually_expanded || is_selected || is_adding_split;\n\n const { pages, label, classification } = split;\n const first_page = pages[0];\n const last_page = pages[pages.length - 1];\n const page_count = pages.length;\n\n const confidence_pct = classification?.confidence != null\n ? `${Math.round(classification.confidence * 100)}%`\n : null;\n\n const page_range =\n page_count === 1\n ? `p.${first_page}`\n : `p.${first_page}–${last_page}`;\n\n const card_color = get_split_color(index);\n\n // Show arrows when selected, not read-only, and more than 1 page\n const show_arrows = is_selected && !read_only && page_count > 1;\n const show_prev_arrow = show_arrows && prev_split_color !== null;\n const show_next_arrow = show_arrows && next_split_color !== null;\n\n // Thumbnail rendering\n const MAX_COLLAPSED_THUMBS = 3;\n const visible_pages = is_expanded ? pages : pages.slice(0, MAX_COLLAPSED_THUMBS);\n const overflow_count = !is_expanded && pages.length > MAX_COLLAPSED_THUMBS\n ? pages.length - MAX_COLLAPSED_THUMBS\n : 0;\n\n const handle_header_click = () => {\n on_select(split.split_id);\n if (is_selected) {\n set_manually_expanded((prev) => !prev);\n } else {\n set_manually_expanded(true);\n }\n };\n\n return (\n <div\n className={cn('cls_split_panel_card', is_selected && 'cls_split_panel_card_selected')}\n style={{\n borderRadius: 6,\n marginBottom: 8,\n border: `1px solid ${is_selected ? card_color : '#334155'}`,\n backgroundColor: is_selected ? '#1e293b' : '#0f172a',\n overflow: 'hidden',\n transition: 'border-color 0.15s',\n }}\n >\n {/* Card header — click to select/toggle */}\n <button\n type=\"button\"\n className=\"cls_split_panel_card_header\"\n onClick={handle_header_click}\n aria-label={`Split ${index + 1} of ${total_splits}: ${label}`}\n style={{\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n padding: '8px 10px',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n gap: 8,\n textAlign: 'left',\n }}\n >\n {/* Color accent stripe */}\n <div\n style={{\n width: 3,\n height: 32,\n borderRadius: 2,\n backgroundColor: card_color,\n flexShrink: 0,\n }}\n />\n\n {/* Label + meta */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <div\n style={{\n fontSize: 12,\n fontWeight: 600,\n color: '#e2e8f0',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {label}\n </div>\n <div style={{ fontSize: 10, color: '#94a3b8', marginTop: 1, display: 'flex', gap: 6 }}>\n <span>{page_range}</span>\n {page_count !== 1 && (\n <span>({page_count} pages)</span>\n )}\n {confidence_pct && (\n <span style={{ color: card_color }}>{confidence_pct}</span>\n )}\n </div>\n </div>\n\n {/* Expand/collapse icon */}\n {is_selected ? (\n <ChevronDown size={14} color=\"#94a3b8\" />\n ) : (\n <ChevronRight size={14} color=\"#94a3b8\" />\n )}\n </button>\n\n {/* Thumbnail strip */}\n <div\n className=\"cls_split_panel_card_thumbs\"\n style={{\n padding: '0 10px 10px 22px',\n display: 'flex',\n flexWrap: is_expanded ? 'wrap' : 'nowrap',\n gap: 4,\n maxHeight: is_expanded ? 150 : undefined,\n overflowY: is_expanded ? 'auto' : undefined,\n alignItems: 'center',\n }}\n >\n {visible_pages.map((page_num, thumb_idx) => {\n const is_first = page_num === first_page;\n const is_last = page_num === last_page;\n\n // Show insertion bar between thumbnails (not after the last one) in add-split mode\n const show_insert_after =\n is_adding_split && thumb_idx < visible_pages.length - 1;\n\n return (\n <div\n key={page_num}\n style={{ display: 'flex', alignItems: 'center', gap: 4 }}\n >\n {/* ◀ Arrow: move first page to previous split */}\n {show_prev_arrow && is_first && (\n <button\n type=\"button\"\n title=\"Move page to previous split\"\n onClick={(e) => {\n e.stopPropagation();\n on_move_first_to_prev(split.split_id);\n }}\n style={{\n width: 18,\n height: 18,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: prev_split_color ?? card_color,\n color: '#fff',\n fontSize: 10,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n opacity: 0.9,\n }}\n >\n ◀\n </button>\n )}\n\n <PageThumb\n page_num={page_num}\n color={card_color}\n show_insert_after={show_insert_after}\n on_insert_after={on_insert_split_after_page}\n />\n\n {/* ▶ Arrow: move last page to next split */}\n {show_next_arrow && is_last && (\n <button\n type=\"button\"\n title=\"Move page to next split\"\n onClick={(e) => {\n e.stopPropagation();\n on_move_last_to_next(split.split_id);\n }}\n style={{\n width: 18,\n height: 18,\n borderRadius: 3,\n border: 'none',\n cursor: 'pointer',\n backgroundColor: next_split_color ?? card_color,\n color: '#fff',\n fontSize: 10,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n opacity: 0.9,\n }}\n >\n ▶\n </button>\n )}\n </div>\n );\n })}\n\n {/* Overflow count badge */}\n {overflow_count > 0 && (\n <div\n style={{\n fontSize: 10,\n color: '#94a3b8',\n backgroundColor: '#1e293b',\n border: '1px solid #334155',\n borderRadius: 4,\n padding: '2px 5px',\n flexShrink: 0,\n }}\n >\n +{overflow_count}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default SplitPanelCard;\n","/**\n * Split Viewer Layout Component\n * Right-side continuous-scroll area for the split viewer.\n * Loads and renders pages belonging to the selected split.\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react';\nimport type { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist';\nimport type { PdfSplit } from './types';\nimport { SplitPageRenderer } from './split_page_renderer';\nimport { get_split_color } from './split_colors';\nimport { cn } from 'hazo_ui';\nimport { get_logger } from '../../utils/logger';\n\nexport interface SplitViewerLayoutProps {\n /** Loaded PDF document to render pages from */\n pdf_document: PDFDocumentProxy;\n\n /** Currently selected split (null = nothing to show) */\n selected_split: PdfSplit | null;\n\n /** 0-based index of the selected split in the parent splits array (drives color) */\n selected_split_index: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Optional class name */\n className?: string;\n}\n\nexport const SplitViewerLayout: React.FC<SplitViewerLayoutProps> = ({\n pdf_document,\n selected_split,\n selected_split_index,\n scale,\n className = '',\n}) => {\n const [pages, setPages] = useState<PDFPageProxy[]>([]);\n const [loading, setLoading] = useState(false);\n const [visible_page_index, setVisiblePageIndex] = useState(0);\n\n const container_ref = useRef<HTMLDivElement>(null);\n const page_refs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // Load pages for the current split whenever it changes\n useEffect(() => {\n if (!selected_split || selected_split.pages.length === 0) {\n setPages([]);\n return;\n }\n\n setLoading(true);\n setVisiblePageIndex(0);\n\n const page_promises = selected_split.pages.map((page_num) =>\n pdf_document.getPage(page_num)\n );\n\n Promise.all(page_promises)\n .then((loaded_pages) => {\n setPages(loaded_pages);\n setLoading(false);\n })\n .catch((error) => {\n const logger = get_logger();\n logger.error('SplitViewerLayout: Error loading pages', { data: error });\n setLoading(false);\n });\n }, [pdf_document, selected_split]);\n\n // Scroll to top when split selection changes\n useEffect(() => {\n if (container_ref.current) {\n container_ref.current.scrollTop = 0;\n }\n }, [selected_split?.split_id]);\n\n // Track the most visible page using IntersectionObserver\n useEffect(() => {\n if (!container_ref.current || pages.length === 0) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n let max_ratio = 0;\n let most_visible = 0;\n\n entries.forEach((entry) => {\n const idx = parseInt(entry.target.getAttribute('data-split-page-index') || '0', 10);\n if (entry.intersectionRatio > max_ratio) {\n max_ratio = entry.intersectionRatio;\n most_visible = idx;\n }\n });\n\n if (max_ratio > 0) {\n setVisiblePageIndex(most_visible);\n }\n },\n {\n root: container_ref.current,\n threshold: [0, 0.25, 0.5, 0.75, 1.0],\n }\n );\n\n page_refs.current.forEach((el) => observer.observe(el));\n\n return () => {\n observer.disconnect();\n };\n }, [pages.length]);\n\n // Stable ref callback for page wrappers\n const set_page_ref = useCallback((index: number, el: HTMLDivElement | null) => {\n if (el) {\n page_refs.current.set(index, el);\n } else {\n page_refs.current.delete(index);\n }\n }, []);\n\n // Derived display values\n const accent_color = get_split_color(selected_split_index);\n const total_pages = selected_split?.pages.length ?? 0;\n const current_display_page = visible_page_index + 1;\n\n // Format page range label (e.g. \"pp. 3–7\" or \"p. 5\")\n const page_range_label = (() => {\n if (!selected_split || selected_split.pages.length === 0) return '';\n const sorted = [...selected_split.pages].sort((a, b) => a - b);\n if (sorted.length === 1) return `p. ${sorted[0]}`;\n return `pp. ${sorted[0]}–${sorted[sorted.length - 1]}`;\n })();\n\n // --- Empty state ---\n if (!selected_split) {\n return (\n <div\n className={cn('cls_split_viewer_layout cls_split_viewer_empty', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#2d2d2d',\n color: '#888',\n fontSize: '14px',\n height: '100%',\n }}\n >\n Select a split to preview its pages\n </div>\n );\n }\n\n // --- Loading state ---\n if (loading) {\n return (\n <div\n className={cn('cls_split_viewer_layout cls_split_viewer_loading', className)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: '#2d2d2d',\n color: '#aaa',\n fontSize: '14px',\n height: '100%',\n }}\n >\n Loading pages…\n </div>\n );\n }\n\n return (\n <div\n className={cn('cls_split_viewer_layout', className)}\n style={{\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n backgroundColor: '#2d2d2d',\n overflow: 'hidden',\n }}\n >\n {/* Sticky label bar */}\n <div\n className=\"cls_split_viewer_label_bar\"\n style={{\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '8px 12px',\n backgroundColor: '#1e1e1e',\n borderBottom: `2px solid ${accent_color}`,\n }}\n >\n {/* Color swatch */}\n <span\n className=\"cls_split_label_swatch\"\n style={{\n display: 'inline-block',\n width: '10px',\n height: '10px',\n borderRadius: '50%',\n backgroundColor: accent_color,\n flexShrink: 0,\n }}\n />\n\n {/* Split name */}\n <span\n className=\"cls_split_label_name\"\n style={{\n color: '#f0f0f0',\n fontWeight: 600,\n fontSize: '13px',\n flexShrink: 0,\n }}\n >\n {selected_split.label}\n </span>\n\n {/* Page range */}\n <span\n className=\"cls_split_label_range\"\n style={{\n color: '#aaa',\n fontSize: '12px',\n flexShrink: 0,\n }}\n >\n {page_range_label} · {total_pages} page{total_pages !== 1 ? 's' : ''}\n </span>\n\n {/* Confidence badge */}\n {selected_split.classification && (\n <span\n className=\"cls_split_label_confidence\"\n style={{\n marginLeft: 'auto',\n color: '#aaa',\n fontSize: '11px',\n whiteSpace: 'nowrap',\n }}\n >\n {selected_split.classification.document_type}\n {' '}\n <span style={{ color: accent_color, fontWeight: 600 }}>\n {Math.round(selected_split.classification.confidence * 100)}%\n </span>\n </span>\n )}\n </div>\n\n {/* Scrollable pages area */}\n <div\n ref={container_ref}\n className=\"cls_split_viewer_scroll\"\n style={{\n flex: 1,\n overflowY: 'auto',\n overflowX: 'auto',\n padding: '16px',\n display: 'flex',\n flexDirection: 'column',\n gap: '16px',\n alignItems: 'center',\n }}\n >\n {pages.map((page, index) => {\n const original_page_num = selected_split.pages[index];\n\n return (\n <div\n key={`${selected_split.split_id}-page-${index}`}\n ref={(el) => set_page_ref(index, el)}\n data-split-page-index={index}\n className=\"cls_split_page_wrapper\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: '6px',\n flexShrink: 0,\n }}\n >\n <SplitPageRenderer\n page={page}\n page_number={original_page_num}\n scale={scale}\n />\n\n {/* Page number badge below each page */}\n <span\n className=\"cls_split_page_badge\"\n style={{\n fontSize: '11px',\n color: '#888',\n userSelect: 'none',\n }}\n >\n Page {original_page_num}\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Floating page indicator */}\n {total_pages > 0 && (\n <div\n className=\"cls_split_viewer_page_indicator\"\n style={{\n position: 'absolute',\n bottom: '12px',\n right: '12px',\n backgroundColor: 'rgba(0,0,0,0.65)',\n color: '#ddd',\n fontSize: '12px',\n padding: '4px 10px',\n borderRadius: '12px',\n pointerEvents: 'none',\n userSelect: 'none',\n }}\n >\n Page {current_display_page} of {total_pages}\n </div>\n )}\n </div>\n );\n};\n\nexport default SplitViewerLayout;\n","/**\n * Split Page Renderer Component\n * Renders a single PDF page to canvas for the split viewer.\n * Simplified version of PdfPageRenderer — no annotation overlay or coordinate mapping.\n */\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport { cn } from 'hazo_ui';\nimport { get_logger } from '../../utils/logger';\n\nexport interface SplitPageRendererProps {\n /** PDF page proxy object */\n page: PDFPageProxy;\n\n /** 1-indexed page number (for display / aria labels) */\n page_number: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Optional class name */\n className?: string;\n}\n\nexport const SplitPageRenderer: React.FC<SplitPageRendererProps> = ({\n page,\n page_number,\n scale,\n className = '',\n}) => {\n const canvas_ref = useRef<HTMLCanvasElement>(null);\n const render_task_ref = useRef<any>(null);\n\n // Calculate display dimensions from the viewport\n const viewport_dimensions = useMemo(() => {\n if (!page) return { width: 0, height: 0 };\n const viewport = page.getViewport({ scale });\n return { width: viewport.width, height: viewport.height };\n }, [page, scale]);\n\n // Render the page onto the canvas\n useEffect(() => {\n if (typeof window === 'undefined') return;\n if (!page) return;\n if (!canvas_ref.current) return;\n\n let cancelled = false;\n\n const cancel_previous = async () => {\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n await render_task_ref.current.promise.catch(() => {\n // Ignore cancellation errors\n });\n } catch (_error) {\n // Ignore errors from cancellation\n }\n render_task_ref.current = null;\n }\n };\n\n cancel_previous().then(() => {\n // Bail out if the effect was cleaned up during the async cancel\n if (cancelled || !canvas_ref.current) return;\n\n const viewport = page.getViewport({ scale });\n const canvas = canvas_ref.current;\n const context = canvas.getContext('2d', { alpha: false });\n\n if (!context) {\n const logger = get_logger();\n logger.error(`SplitPageRenderer page ${page_number}: Cannot get 2D context`);\n return;\n }\n\n // High DPI support\n const output_scale = window.devicePixelRatio || 1;\n\n // Setting width/height clears the canvas and invalidates any prior render task\n canvas.width = viewport.width * output_scale;\n canvas.height = viewport.height * output_scale;\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n // Scale context to match device pixel ratio\n context.scale(output_scale, output_scale);\n\n // Ensure transparent PDF areas appear white\n context.fillStyle = '#ffffff';\n context.fillRect(0, 0, viewport.width, viewport.height);\n\n const render_context = {\n canvasContext: context,\n viewport,\n annotationMode: 0, // Do not render PDF annotations on canvas\n background: 'white',\n };\n\n const render_task = page.render(render_context);\n render_task_ref.current = render_task;\n\n render_task.promise\n .then(() => {\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n })\n .catch((error) => {\n if (error.name !== 'RenderingCancelledException') {\n const logger = get_logger();\n logger.error(`SplitPageRenderer page ${page_number}: Error rendering`, { data: error });\n }\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n });\n });\n\n // Cleanup: cancel in-progress render on unmount or dep change\n return () => {\n cancelled = true;\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n } catch (_error) {\n // Ignore\n }\n render_task_ref.current = null;\n }\n };\n }, [page, scale, page_number]);\n\n if (!page) {\n return (\n <div className={cn('cls_split_page_loading', className)}>\n <div className=\"cls_split_page_spinner\">Loading page...</div>\n </div>\n );\n }\n\n return (\n <div\n className={cn('cls_split_page_container', className)}\n style={{\n position: 'relative',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n backgroundColor: '#ffffff',\n boxShadow: '0 2px 8px rgba(0,0,0,0.4)',\n }}\n >\n <canvas\n ref={canvas_ref}\n className=\"cls_split_page_canvas\"\n style={{\n display: 'block',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n pointerEvents: 'none',\n }}\n aria-label={`PDF page ${page_number}`}\n />\n </div>\n );\n};\n\nexport default SplitPageRenderer;\n"],"mappings":"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","names":["PdfViewer","useState","useEffect","useCallback","useRef","cn","jsx","useRef","useEffect","cn","jsx","jsxs","cn","jsx","jsxs","useRef","useEffect","useState","useRef","useEffect","useCallback","useRef","useEffect","cn","jsx","useRef","useEffect","cn","cn","jsx","jsxs","useState","useRef","useEffect","useCallback","total_pages","cn","jsx","jsxs","useEffect","useState","useRef","useCallback","cn"]}
@@ -3,12 +3,12 @@ import {
3
3
  download_pdf,
4
4
  save_and_download_pdf,
5
5
  save_annotations_to_pdf
6
- } from "./chunk-NQ6KUJWG.js";
7
- import "./chunk-264BTVJT.js";
6
+ } from "./chunk-7M53O3HF.js";
7
+ import "./chunk-TZJ5S57X.js";
8
8
  import "./chunk-AOSHQP7D.js";
9
9
  export {
10
10
  download_pdf,
11
11
  save_and_download_pdf,
12
12
  save_annotations_to_pdf
13
13
  };
14
- //# sourceMappingURL=pdf_saver-7FA4DAXI.js.map
14
+ //# sourceMappingURL=pdf_saver-T6SEDYEE.js.map
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  PdfViewer,
4
4
  pdf_viewer_default
5
- } from "./chunk-4JJOUQ62.js";
6
- import "./chunk-264BTVJT.js";
5
+ } from "./chunk-KDOQ3FIO.js";
6
+ import "./chunk-TZJ5S57X.js";
7
7
  import "./chunk-AOSHQP7D.js";
8
8
  export {
9
9
  PdfViewer,
10
10
  pdf_viewer_default as default
11
11
  };
12
- //# sourceMappingURL=pdf_viewer-B6S5PJJB.js.map
12
+ //# sourceMappingURL=pdf_viewer-TFCSUGWU.js.map
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * Logger Utility for hazo_pdf
3
- * Provides a unified logging interface that can use hazo_logs or fallback to console
3
+ *
4
+ * Default behavior: delegates to hazo_core's createLogger('hazo_pdf'), which
5
+ * auto-injects correlationId, env, and writes structured JSON via hazo_logs.
6
+ * Consumers can still override with set_logger() — useful for browser-only
7
+ * loggers or app-specific instrumentation.
4
8
  */
5
9
  /**
6
10
  * Logger interface matching hazo_logs Logger type