hazo_pdf 1.6.7 → 1.7.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/pdf_viewer/pdf_viewer.tsx","../src/components/pdf_viewer/toolbar_dropdown_button.tsx","../src/utils/cn.ts","../src/components/pdf_viewer/pdf_worker_setup.ts","../src/components/pdf_viewer/pdf_viewer_layout.tsx","../src/components/pdf_viewer/pdf_page_renderer.tsx","../src/utils/coordinate_mapper.ts","../src/components/pdf_viewer/annotation_overlay.tsx","../src/utils/annotation_utils.ts","../src/components/pdf_viewer/context_menu.tsx","../src/components/pdf_viewer/text_annotation_dialog.tsx","../src/components/pdf_viewer/metadata_sidepanel.tsx","../src/components/pdf_viewer/file_info_sidepanel.tsx","../src/utils/config_loader.ts","../src/components/file_manager/index.tsx","../src/components/file_manager/file_list.tsx","../src/components/file_manager/file_list_item.tsx","../src/components/file_manager/upload_dropzone.tsx","../src/components/file_manager/upload_progress.tsx","../src/components/file_manager/file_manager_button.tsx","../src/utils/pdf_converter.ts","../src/utils/file_access_middleware.ts"],"sourcesContent":["/**\n * PDF Viewer Component\n * Main component for displaying and interacting with PDF documents\n * Integrates PDF rendering, annotation overlay, and layout management\n */\n\nimport { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { Save, Download, Undo2, Redo2, PanelRight, PanelRightOpen, ZoomIn, ZoomOut, RotateCcw, RotateCw, RefreshCw, Square, Type, ExternalLink, Info, Sparkles, X } from 'lucide-react';\nimport { ToolbarDropdownButton } from './toolbar_dropdown_button';\nimport { load_pdf_document } from './pdf_worker_setup';\nimport { PdfViewerLayout } from './pdf_viewer_layout';\nimport { ContextMenu } from './context_menu';\nimport { TextAnnotationDialog } from './text_annotation_dialog';\nimport { MetadataSidepanel } from './metadata_sidepanel';\nimport { FileInfoSidepanel } from './file_info_sidepanel';\nimport type { PdfViewerProps, PdfAnnotation, CoordinateMapper, PdfViewerConfig, CustomStamp, MetadataInput, MetadataDataItem, PdfViewerRef, HighlightOptions } from '../../types';\nimport { load_pdf_config, load_pdf_config_async } from '../../utils/config_loader';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { set_logger, get_logger } from '../../utils/logger';\nimport { FileManager } from '../file_manager';\nimport type { FileItem, PopoutContext } from '../file_manager/types';\nimport { load_pdf_data, save_pdf_data } from '../../utils/file_access_middleware';\n\n// Storage key for popout context\nconst POPOUT_STORAGE_KEY = 'hazo_pdf_popout';\n\n/**\n * PDF Viewer Component\n * Main entry point for PDF viewing and annotation\n */\nexport const PdfViewer = forwardRef<PdfViewerRef, PdfViewerProps>(({\n url,\n className = '',\n scale: initial_scale = 1.0,\n fit_to_width = false,\n on_load,\n on_error,\n annotations: initial_annotations = [],\n on_annotation_create,\n on_annotation_update,\n on_annotation_delete,\n on_save,\n background_color,\n config_file,\n append_timestamp_to_text_edits,\n annotation_text_suffix_fixed_text,\n right_click_custom_stamps,\n sidepanel_metadata_enabled = false,\n metadata_input,\n on_metadata_change,\n file_metadata,\n // Toolbar visibility props (override config file values)\n toolbar_enabled,\n show_zoom_controls,\n show_square_button,\n show_undo_button,\n show_redo_button,\n show_save_button,\n show_download_button,\n show_metadata_button,\n show_annotate_button,\n show_file_info_button,\n // Data extraction props\n show_extract_button,\n extract_prompt_area,\n extract_prompt_key,\n extract_api_endpoint,\n extract_storage_type = 'local',\n on_extract_complete,\n on_extract_error,\n on_close,\n // Multi-file support props\n files,\n on_file_select,\n on_file_delete,\n on_upload,\n on_files_change,\n // file_manager_display_mode is reserved for future use (dialog/standalone modes)\n download_filename,\n display_filename,\n on_download,\n enable_popout = false,\n popout_route = '/pdf-viewer',\n on_popout,\n viewer_title,\n logger,\n // hazo_files integration props\n file_manager,\n save_path,\n // Upload behavior\n direct_upload,\n // File info sidepanel data props\n doc_data,\n highlight_fields_info,\n extractions,\n // Auto-highlight props\n auto_highlight_enabled,\n auto_highlight_options,\n auto_highlight_search_options,\n}, ref) => {\n const pdf_logger = get_logger();\n const [pdf_document, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n // Cached PDF data for use when saving (when loaded via file_manager)\n const [cached_pdf_data, setCachedPdfData] = useState<ArrayBuffer | null>(null);\n const [scale, setScale] = useState(initial_scale);\n const [annotations, setAnnotations] = useState<PdfAnnotation[]>(initial_annotations);\n // Default tool is Pan (null) for scrolling the document\n const [current_tool, setCurrentTool] = useState<'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null>(null);\n const [saving, setSaving] = useState(false);\n const [downloading, setDownloading] = useState(false);\n // Data extraction state\n const [extracting, setExtracting] = useState(false);\n const [extract_error, setExtractError] = useState<string | null>(null);\n // Sidepanel state (existing metadata sidepanel)\n const [sidepanel_open, setSidepanelOpen] = useState(false);\n const [sidepanel_width, setSidepanelWidth] = useState(300);\n\n // File info sidepanel state (combined extraction data + file system info)\n const [file_info_sidepanel_open, setFileInfoSidepanelOpen] = useState(false);\n const [file_info_sidepanel_width, setFileInfoSidepanelWidth] = useState(300);\n const [hazo_files_available, setHazoFilesAvailable] = useState<boolean | null>(null);\n\n // Auto-highlight state (track IDs of auto-created highlights)\n const [auto_highlight_ids, setAutoHighlightIds] = useState<Set<string>>(new Set());\n\n // Page rotation state\n const [page_rotations, setPageRotations] = useState<Map<number, number>>(new Map());\n const [current_visible_page, setCurrentVisiblePage] = useState(0);\n // Config loaded trigger (forces re-render after async config load)\n const [, setConfigVersion] = useState(0);\n\n // Multi-file state\n const [current_file, setCurrentFile] = useState<FileItem | null>(\n files && files.length > 0 ? files[0] : null\n );\n // Multi-file mode is enabled when files prop is provided (even if empty array)\n // This allows showing the file manager for uploads when no files exist yet\n const is_multi_file_mode = files !== undefined;\n\n // Get the effective URL for loading (single file mode or from current file in multi-file mode)\n const effective_url = is_multi_file_mode ? current_file?.url : url;\n\n // Set logger instance when provided\n useEffect(() => {\n set_logger(logger);\n if (logger) {\n logger.debug('Logger initialized for PdfViewer');\n }\n }, [logger]);\n\n // Check if hazo_files package is available (for file info sidepanel)\n useEffect(() => {\n const check_hazo_files = async () => {\n try {\n const module = await import('hazo_files/ui');\n // Check if FileInfoPanel exists as a property in the module\n if ('FileInfoPanel' in module && typeof module.FileInfoPanel === 'function') {\n setHazoFilesAvailable(true);\n } else {\n setHazoFilesAvailable(false);\n }\n } catch {\n setHazoFilesAvailable(false);\n }\n };\n check_hazo_files();\n }, []);\n\n // Content container ref for fit-to-width calculations\n const content_container_ref = useRef<HTMLDivElement>(null);\n\n // First page dimensions for fit-to-width calculation (at scale=1)\n const [first_page_width, setFirstPageWidth] = useState<number | null>(null);\n\n // When true, fit-to-width auto-scaling is active. Disabled on manual zoom.\n // State drives useEffect cleanup/setup (disconnects/reconnects the ResizeObserver).\n // Ref provides a synchronous guard inside the ResizeObserver callback, preventing\n // stale callbacks from overriding manual zoom between DOM commit and effect cleanup.\n const [fit_to_width_active, setFitToWidthActive] = useState(fit_to_width);\n const fit_to_width_active_ref = useRef(fit_to_width);\n\n // Sync current_file when files prop changes\n useEffect(() => {\n if (files && files.length > 0) {\n // If current file is not in the new files array, select the first file\n if (!current_file || !files.find(f => f.id === current_file.id)) {\n setCurrentFile(files[0]);\n }\n } else {\n setCurrentFile(null);\n }\n }, [files]);\n\n // Handle file selection in multi-file mode\n const handle_file_select = useCallback((file: FileItem) => {\n setCurrentFile(file);\n on_file_select?.(file);\n }, [on_file_select]);\n\n // Load configuration from file\n // Initialize with defaults so config is available on first render\n const config_ref = useRef<PdfViewerConfig | null>(load_pdf_config());\n\n // Load config from file on mount (overrides defaults)\n // Uses hazo_config in Node.js (preferred), fetch + compatible parsing in browser\n useEffect(() => {\n if (!config_file) {\n // No config file specified, use defaults\n config_ref.current = load_pdf_config();\n return;\n }\n \n // Detect environment\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser: use async loader (fetch + compatible parsing)\n // Note: hazo_config requires Node.js fs, so we use compatible parsing instead\n load_pdf_config_async(config_file)\n .then(config => {\n config_ref.current = config;\n setConfigVersion(v => v + 1);\n pdf_logger.debug('Config loaded', {\n append_timestamp_to_text_edits: config.viewer.append_timestamp_to_text_edits,\n config_object: config,\n });\n })\n .catch(error => {\n pdf_logger.warn(`Could not load config file \"${config_file}\", using defaults`, { error });\n config_ref.current = load_pdf_config(); // Use defaults\n setConfigVersion(v => v + 1);\n });\n } else {\n // Node.js: use hazo_config (preferred method)\n config_ref.current = load_pdf_config(config_file);\n pdf_logger.debug('Config loaded (Node.js)', {\n append_timestamp_to_text_edits: config_ref.current?.viewer.append_timestamp_to_text_edits,\n });\n }\n }, [config_file]);\n\n // Override direct_upload from prop at render time (not in useEffect)\n // so FileManager sees the correct value on first render\n if (direct_upload !== undefined && config_ref.current) {\n config_ref.current = {\n ...config_ref.current,\n file_upload: {\n ...config_ref.current.file_upload,\n direct_upload,\n },\n };\n }\n\n // Get effective background color: prop > config > default\n const effective_background_color = background_color || \n config_ref.current?.viewer.viewer_background_color || \n '#2d2d2d';\n \n /**\n * Format timestamp for annotation text edits\n * Returns timestamp in format YYYY-MM-DD h:mmam/pm (without brackets)\n * Brackets are added by add_suffix_text based on configuration\n * Example: 2025-11-17 2:24pm\n */\n const format_annotation_timestamp = (): string => {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n \n let hours = now.getHours();\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const am_pm = hours >= 12 ? 'pm' : 'am';\n hours = hours % 12;\n if (hours === 0) hours = 12; // Convert 0 to 12 for 12-hour format\n \n return `${year}-${month}-${day} ${hours}:${minutes}${am_pm}`;\n };\n \n /**\n * Parse custom stamps from JSON string (prop or config)\n * @param stamps_json - JSON string array of custom stamps\n * @returns Array of CustomStamp objects, or empty array if invalid\n */\n const parse_custom_stamps = (stamps_json: string | undefined): CustomStamp[] => {\n if (!stamps_json || stamps_json.trim() === '') {\n return [];\n }\n \n try {\n const parsed = JSON.parse(stamps_json);\n if (!Array.isArray(parsed)) {\n pdf_logger.warn('Custom stamps must be a JSON array');\n return [];\n }\n \n // Validate and normalize stamp objects\n return parsed\n .filter((stamp: any) => stamp && typeof stamp === 'object')\n .map((stamp: any) => ({\n name: String(stamp.name || ''),\n text: String(stamp.text || ''),\n order: typeof stamp.order === 'number' ? stamp.order : 999,\n time_stamp_suffix_enabled: Boolean(stamp.time_stamp_suffix_enabled),\n fixed_text_suffix_enabled: Boolean(stamp.fixed_text_suffix_enabled),\n // Optional styling fields\n background_color: stamp.background_color !== undefined ? String(stamp.background_color) : undefined,\n border_size: stamp.border_size !== undefined ? (typeof stamp.border_size === 'number' ? stamp.border_size : undefined) : undefined,\n font_color: stamp.font_color !== undefined ? String(stamp.font_color) : undefined,\n font_weight: stamp.font_weight !== undefined ? String(stamp.font_weight) : undefined,\n font_style: stamp.font_style !== undefined ? String(stamp.font_style) : undefined,\n font_size: stamp.font_size !== undefined ? (typeof stamp.font_size === 'number' ? stamp.font_size : undefined) : undefined,\n font_name: stamp.font_name !== undefined ? String(stamp.font_name) : undefined,\n }))\n .filter((stamp) => stamp.name && stamp.text); // Only include stamps with name and text\n } catch (error) {\n pdf_logger.warn('Failed to parse custom stamps JSON', { error });\n return [];\n }\n };\n \n /**\n * Consolidated helper to append suffix text (fixed text, timestamp) with configurable formatting\n * @param text - Base text to append suffixes to\n * @param fixed_text_suffix_enabled - Whether fixed text suffix should be appended\n * @param time_stamp_suffix_enabled - Whether timestamp suffix should be appended\n * @param fixed_text - Optional fixed text to append\n * @param add_enclosing_brackets_override - Optional override for bracket usage\n * @returns Text with suffixes applied based on configuration\n */\n const add_suffix_text = (\n text: string,\n fixed_text_suffix_enabled: boolean,\n time_stamp_suffix_enabled: boolean,\n fixed_text?: string,\n add_enclosing_brackets_override?: boolean\n ): string => {\n const viewer_config = config_ref.current?.viewer;\n const add_enclosing_brackets =\n add_enclosing_brackets_override ??\n viewer_config?.add_enclosing_brackets_to_suffixes ??\n true;\n \n const suffix_enclosing_brackets = viewer_config?.suffix_enclosing_brackets || '[]';\n const suffix_text_position =\n viewer_config?.suffix_text_position || 'below_multi_line';\n \n const opening_bracket = suffix_enclosing_brackets[0] || '[';\n const closing_bracket = suffix_enclosing_brackets[1] || ']';\n \n const suffix_parts: string[] = [];\n \n if (fixed_text_suffix_enabled) {\n const trimmed_fixed_text = fixed_text?.trim();\n if (trimmed_fixed_text && trimmed_fixed_text.length > 0) {\n suffix_parts.push(\n add_enclosing_brackets\n ? `${opening_bracket}${trimmed_fixed_text}${closing_bracket}`\n : trimmed_fixed_text\n );\n }\n }\n \n if (time_stamp_suffix_enabled) {\n const timestamp = format_annotation_timestamp();\n suffix_parts.push(\n add_enclosing_brackets\n ? `${opening_bracket}${timestamp}${closing_bracket}`\n : timestamp\n );\n }\n \n if (suffix_parts.length === 0) {\n return text;\n }\n \n switch (suffix_text_position) {\n case 'adjacent': {\n if (!text) {\n return suffix_parts.join(' ');\n }\n const separator = text.endsWith(' ') ? '' : ' ';\n return `${text}${separator}${suffix_parts.join(' ')}`;\n }\n case 'below_single_line':\n return text\n ? `${text}\\n${suffix_parts.join(' ')}`\n : suffix_parts.join(' ');\n case 'below_multi_line':\n default:\n return text\n ? `${text}\\n${suffix_parts.join('\\n')}`\n : suffix_parts.join('\\n');\n }\n };\n\n /**\n * Format stamp text with optional timestamp and fixed text suffixes\n * Uses add_suffix_text helper for consistent formatting\n * @param stamp - Custom stamp configuration\n * @param base_text - Base text from stamp\n * @returns Formatted text with suffixes if enabled\n */\n const format_stamp_text = (stamp: CustomStamp, base_text: string): string => {\n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = config_ref.current?.viewer.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined ? fixed_text_prop : fixed_text_config;\n return add_suffix_text(\n base_text,\n stamp.fixed_text_suffix_enabled ?? false,\n stamp.time_stamp_suffix_enabled ?? false,\n fixed_text\n );\n };\n \n /**\n * Strip auto-inserted suffix from annotation text\n * Handles configurable bracket styles and suffix positioning\n * @param text - Annotation text that may contain auto-inserted suffix\n * @returns Text with suffix removed\n */\n const strip_auto_inserted_suffix = (text: string): string => {\n const viewer_config = config_ref.current?.viewer;\n const bracket_pair = viewer_config?.suffix_enclosing_brackets || '[]';\n const add_enclosing_brackets =\n viewer_config?.add_enclosing_brackets_to_suffixes ?? true;\n const suffix_text_position =\n viewer_config?.suffix_text_position || 'below_multi_line';\n \n const opening_bracket = bracket_pair[0] || '[';\n const closing_bracket = bracket_pair[1] || ']';\n \n const escape_regexp = (value: string) =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n \n const timestamp_core_pattern =\n '\\\\d{4}-\\\\d{2}-\\\\d{2} \\\\d{1,2}:\\\\d{2}(?:am|pm)';\n const timestamp_pattern = add_enclosing_brackets\n ? `${escape_regexp(opening_bracket)}${timestamp_core_pattern}${escape_regexp(\n closing_bracket\n )}`\n : timestamp_core_pattern;\n \n const timestamp_line_regex = new RegExp(`^${timestamp_pattern}$`);\n const timestamp_trailing_regex = new RegExp(\n `(?:[ \\\\t]+)?${timestamp_pattern}$`\n );\n \n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = viewer_config?.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined ? fixed_text_prop : fixed_text_config;\n const trimmed_fixed_text = fixed_text?.trim() || '';\n const fixed_segment = trimmed_fixed_text\n ? add_enclosing_brackets\n ? `${opening_bracket}${trimmed_fixed_text}${closing_bracket}`\n : trimmed_fixed_text\n : null;\n \n const fixed_line_regex = fixed_segment\n ? new RegExp(`^${escape_regexp(fixed_segment)}$`)\n : null;\n const fixed_trailing_regex = fixed_segment\n ? new RegExp(`(?:[ \\\\t]+)?${escape_regexp(fixed_segment)}$`)\n : null;\n \n const remove_trailing_pattern = (\n value: string,\n pattern: RegExp | null\n ): { updated: string; removed: boolean } => {\n if (!pattern) {\n return { updated: value, removed: false };\n }\n const new_value = value.replace(pattern, '');\n return { updated: new_value, removed: new_value !== value };\n };\n \n const strip_adjacent_suffix = (value: string): string => {\n let updated = value;\n let removed_any = false;\n \n const timestamp_removal = remove_trailing_pattern(\n updated,\n timestamp_trailing_regex\n );\n updated = timestamp_removal.updated;\n removed_any ||= timestamp_removal.removed;\n \n const fixed_removal = remove_trailing_pattern(\n updated,\n fixed_trailing_regex\n );\n updated = fixed_removal.updated;\n removed_any ||= fixed_removal.removed;\n \n return removed_any ? updated.replace(/[ \\\\t]+$/, '') : value;\n };\n \n const strip_below_single_line_suffix = (value: string): string => {\n const last_newline_index = value.lastIndexOf('\\n');\n if (last_newline_index === -1) {\n // Fallback to adjacent stripping if newline is missing\n return strip_adjacent_suffix(value);\n }\n \n const prefix = value.slice(0, last_newline_index);\n let suffix_line = value.slice(last_newline_index + 1);\n let suffix_changed = false;\n \n const timestamp_removal = remove_trailing_pattern(\n suffix_line,\n timestamp_trailing_regex\n );\n suffix_line = timestamp_removal.updated;\n suffix_changed ||= timestamp_removal.removed;\n \n const fixed_removal = remove_trailing_pattern(\n suffix_line,\n fixed_trailing_regex\n );\n suffix_line = fixed_removal.updated;\n suffix_changed ||= fixed_removal.removed;\n \n if (!suffix_changed) {\n return value;\n }\n \n if (suffix_line.trim().length === 0) {\n return prefix;\n }\n \n return `${prefix}\\n${suffix_line}`;\n };\n \n const strip_below_multi_line_suffix = (value: string): string => {\n const lines = value.split('\\n');\n if (lines.length === 0) {\n return value;\n }\n \n let changed = false;\n const remove_last_line_if_matches = (pattern: RegExp | null) => {\n if (!pattern || lines.length === 0) {\n return;\n }\n const last_line = lines[lines.length - 1].trim();\n if (pattern.test(last_line)) {\n lines.pop();\n changed = true;\n }\n };\n \n remove_last_line_if_matches(timestamp_line_regex);\n remove_last_line_if_matches(fixed_line_regex);\n \n return changed ? lines.join('\\n') : value;\n };\n \n switch (suffix_text_position) {\n case 'adjacent':\n return strip_adjacent_suffix(text);\n case 'below_single_line':\n return strip_below_single_line_suffix(text);\n case 'below_multi_line':\n default:\n return strip_below_multi_line_suffix(text);\n }\n };\n \n /**\n * Append timestamp to annotation text if enabled\n * @param text - Original annotation text\n * @returns Text with timestamp appended (if enabled) or original text\n * Note: Checks config dynamically to handle async config loading in browser\n * If fixed text is provided, format will be: text\\n[fixed_text] [timestamp]\n */\n const append_timestamp_if_enabled = (text: string): string => {\n // Check config dynamically since it loads asynchronously in browser\n // Priority: prop > config > default (false)\n const prop_value = append_timestamp_to_text_edits;\n const config_value = config_ref.current?.viewer.append_timestamp_to_text_edits;\n const should_append = prop_value !== undefined\n ? prop_value\n : (config_value ?? false);\n \n // Get fixed text: prop > config > default (empty string)\n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = config_ref.current?.viewer.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined\n ? fixed_text_prop\n : fixed_text_config;\n \n pdf_logger.debug('append_timestamp_if_enabled', {\n prop_value,\n config_value,\n should_append,\n fixed_text_prop,\n fixed_text_config,\n fixed_text,\n config_loaded: !!config_ref.current,\n original_text: text,\n });\n \n if (!should_append) {\n pdf_logger.debug('Timestamp NOT appended (disabled)');\n return text;\n }\n \n const include_fixed_text_suffix = Boolean(fixed_text && fixed_text.trim().length > 0);\n const result = add_suffix_text(\n text,\n include_fixed_text_suffix,\n true,\n fixed_text\n );\n pdf_logger.debug('Timestamp appended via add_suffix_text', {\n original: text,\n fixed_text,\n include_fixed_text_suffix,\n result,\n });\n return result;\n };\n \n // Undo/Redo history\n const [history, setHistory] = useState<PdfAnnotation[][]>([initial_annotations]);\n const [history_index, setHistoryIndex] = useState(0);\n const history_ref = useRef({ saving: false }); // Track if we're applying history to prevent loops\n \n // Context menu state\n const [context_menu, setContextMenu] = useState<{\n visible: boolean;\n x: number;\n y: number;\n page_index: number;\n screen_x: number;\n screen_y: number;\n mapper?: CoordinateMapper;\n } | null>(null);\n \n // Text annotation dialog state\n const [text_dialog, setTextDialog] = useState<{\n open: boolean;\n page_index: number;\n x: number; // Viewport X coordinate\n y: number; // Viewport Y coordinate\n screen_x: number;\n screen_y: number;\n mapper?: CoordinateMapper;\n editing_annotation?: PdfAnnotation; // Annotation being edited (if any)\n } | null>(null);\n\n // Initialize history when initial annotations change\n useEffect(() => {\n if (history.length === 1 && history[0].length === 0 && initial_annotations.length === 0) {\n // Only reset if history is empty and initial is also empty\n return;\n }\n setHistory([initial_annotations]);\n setHistoryIndex(0);\n history_ref.current.saving = false;\n }, [effective_url]); // Reset history when PDF URL changes\n\n // Load PDF document\n useEffect(() => {\n // Ensure we're in browser environment before loading PDF\n if (typeof window === 'undefined') {\n return;\n }\n\n if (!effective_url) {\n // In multi-file mode with no files, this is expected - not loading, just empty\n if (is_multi_file_mode) {\n setLoading(false);\n setPdfDocument(null);\n setCachedPdfData(null);\n } else {\n pdf_logger.warn('No URL provided');\n }\n return;\n }\n\n setLoading(true);\n setError(null);\n setCachedPdfData(null);\n\n // Use a timeout to ensure we're fully in browser context\n // This helps with React Strict Mode and SSR hydration issues\n const load_timeout = setTimeout(async () => {\n try {\n let pdf_data: ArrayBuffer | string = effective_url;\n const logger = get_logger();\n\n // If file_manager is provided and initialized, use it to load the PDF\n if (file_manager && file_manager.isInitialized()) {\n logger.debug('[PdfViewer] Loading PDF via hazo_files file_manager');\n const loaded_data = await load_pdf_data(effective_url, file_manager);\n // Make a copy for caching (pdfjs may detach the original buffer)\n const cached_copy = loaded_data.slice(0);\n setCachedPdfData(cached_copy);\n pdf_data = loaded_data;\n } else {\n // Fetch the PDF ourselves and cache the ArrayBuffer\n // This ensures extraction uses the same data as the displayed document\n logger.debug('[PdfViewer] Loading PDF via fetch, caching for extraction', { url: effective_url });\n const response = await fetch(effective_url);\n\n // Check for HTTP errors before parsing response\n if (!response.ok) {\n const error_text = await response.text().catch(() => '');\n const truncated = error_text.length > 200 ? error_text.slice(0, 200) + '...' : error_text;\n throw new Error(\n `Failed to fetch PDF (${response.status} ${response.statusText}): ${truncated || 'No response body'}`\n );\n }\n\n // Verify content type is PDF (some servers return HTML for errors with 200 status)\n const content_type = response.headers.get('content-type') || '';\n if (!content_type.includes('application/pdf') && !content_type.includes('application/octet-stream')) {\n logger.warn('[PdfViewer] Unexpected content type for PDF', {\n url: effective_url,\n content_type,\n note: 'Expected application/pdf or application/octet-stream'\n });\n }\n\n const array_buffer = await response.arrayBuffer();\n // Make a copy for caching (pdfjs may detach the original buffer)\n const cached_copy = array_buffer.slice(0);\n setCachedPdfData(cached_copy);\n pdf_data = array_buffer;\n }\n\n const document = await load_pdf_document(pdf_data);\n setPdfDocument(document);\n setLoading(false);\n if (on_load) {\n on_load(document);\n }\n } catch (err) {\n pdf_logger.error('Error loading PDF', { error: err });\n const error_obj = err instanceof Error ? err : new Error(String(err));\n setError(error_obj);\n setLoading(false);\n if (on_error) {\n on_error(error_obj);\n }\n }\n }, 0);\n\n // Cleanup: cancel loading if component unmounts\n return () => {\n clearTimeout(load_timeout);\n };\n }, [effective_url, on_load, on_error, is_multi_file_mode, file_manager]);\n\n // Get first page dimensions when PDF document loads (for fit-to-width calculation)\n useEffect(() => {\n if (!pdf_document) {\n setFirstPageWidth(null);\n return;\n }\n\n // Get first page to determine intrinsic width at scale=1\n pdf_document.getPage(1).then((page) => {\n const viewport = page.getViewport({ scale: 1 });\n setFirstPageWidth(viewport.width);\n }).catch((err) => {\n pdf_logger.error('Error getting first page dimensions', { error: err });\n });\n }, [pdf_document]);\n\n // Re-enable fit-to-width when the prop changes\n useEffect(() => {\n fit_to_width_active_ref.current = fit_to_width;\n setFitToWidthActive(fit_to_width);\n }, [fit_to_width]);\n\n // Fit-to-width: Calculate scale based on container width and PDF page width.\n // When fit_to_width_active is false (e.g. after manual zoom), this effect\n // cleans up the ResizeObserver so it won't override the user's zoom level.\n useEffect(() => {\n if (!fit_to_width_active || !first_page_width || !content_container_ref.current) {\n return;\n }\n\n const calculate_fit_scale = () => {\n // Guard: check ref synchronously to prevent stale ResizeObserver callbacks\n // from overriding manual zoom (ref is set immediately by zoom handlers,\n // before the async useEffect cleanup can disconnect the observer)\n if (!fit_to_width_active_ref.current) return;\n if (!content_container_ref.current || !first_page_width) return;\n\n // Get container width (subtract some padding for page margins)\n const container_width = content_container_ref.current.clientWidth;\n const padding = 40; // Account for margins/padding around the page\n const available_width = container_width - padding;\n\n // Calculate scale to fit PDF width to available width\n const new_scale = Math.max(0.1, Math.min(3.0, available_width / first_page_width));\n\n setScale(new_scale);\n };\n\n // Calculate initial scale\n calculate_fit_scale();\n\n // Set up ResizeObserver to recalculate on container resize\n const resize_observer = new ResizeObserver(() => {\n calculate_fit_scale();\n });\n\n resize_observer.observe(content_container_ref.current);\n\n return () => {\n resize_observer.disconnect();\n };\n }, [fit_to_width_active, first_page_width]);\n\n // Previously logged global mouse clicks for debugging; removed for cleaner console.\n\n // Save to history when annotations change (but not when applying undo/redo)\n const save_to_history = (new_annotations: PdfAnnotation[]) => {\n if (history_ref.current.saving) {\n return; // Don't save to history when applying undo/redo\n }\n \n // Create new history array up to current index, then add new state\n const new_history = history.slice(0, history_index + 1);\n new_history.push(new_annotations);\n \n // Limit history to 50 states to prevent memory issues\n if (new_history.length > 50) {\n new_history.shift();\n setHistory(new_history);\n setHistoryIndex(new_history.length - 1);\n } else {\n setHistory(new_history);\n setHistoryIndex(new_history.length - 1);\n }\n };\n\n // Handle annotation creation\n const handle_annotation_create = (annotation: PdfAnnotation) => {\n // Use functional update to avoid stale closure when adding multiple annotations quickly\n setAnnotations(prev => {\n const new_annotations = [...prev, annotation];\n save_to_history(new_annotations);\n if (on_annotation_create) {\n on_annotation_create(annotation);\n }\n return new_annotations;\n });\n };\n\n // Handle annotation update\n const handle_annotation_update = (annotation: PdfAnnotation) => {\n const updated_annotations = annotations.map((ann) =>\n ann.id === annotation.id ? annotation : ann\n );\n setAnnotations(updated_annotations);\n save_to_history(updated_annotations);\n if (on_annotation_update) {\n on_annotation_update(annotation);\n }\n };\n\n // Handle annotation delete\n const handle_annotation_delete = (annotation_id: string) => {\n const filtered_annotations = annotations.filter(\n (ann) => ann.id !== annotation_id\n );\n setAnnotations(filtered_annotations);\n save_to_history(filtered_annotations);\n if (on_annotation_delete) {\n on_annotation_delete(annotation_id);\n }\n };\n\n // Expose imperative methods via ref for programmatic control\n useImperativeHandle(ref, () => ({\n /**\n * Create a highlight on a specific page region\n * @param page_index - Zero-based page index\n * @param rect - Rectangle coordinates in PDF space [x1, y1, x2, y2]\n * @param options - Optional styling overrides\n * @returns The highlight annotation ID\n */\n highlight_region: (\n page_index: number,\n rect: [number, number, number, number],\n options?: HighlightOptions\n ): string => {\n const highlight_config = config_ref.current?.highlight_annotation || default_config.highlight_annotation;\n\n const annotation: PdfAnnotation = {\n id: `highlight_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n type: 'Highlight',\n page_index,\n rect,\n author: 'API',\n date: new Date().toISOString(),\n contents: '',\n color: options?.background_color || highlight_config.highlight_fill_color,\n flags: 'api_highlight', // Marker to identify API-created highlights\n };\n\n // Store custom options in subject field as JSON (for rendering)\n if (options) {\n annotation.subject = JSON.stringify({\n border_color: options.border_color,\n background_color: options.background_color,\n background_opacity: options.background_opacity,\n border_width: options.border_width,\n });\n }\n\n handle_annotation_create(annotation);\n return annotation.id;\n },\n\n /**\n * Remove a specific highlight by ID\n * @param id - The highlight annotation ID\n * @returns true if highlight was found and removed\n */\n remove_highlight: (id: string): boolean => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n return true;\n }\n return false;\n },\n\n /**\n * Remove all highlights created via the highlight_region API\n */\n clear_all_highlights: (): void => {\n const api_highlights = annotations.filter(a => a.flags === 'api_highlight');\n api_highlights.forEach(a => handle_annotation_delete(a.id));\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [annotations, handle_annotation_create, handle_annotation_delete]);\n\n // Handle undo\n const handle_undo = useCallback(() => {\n if (history_index > 0) {\n history_ref.current.saving = true;\n const previous_index = history_index - 1;\n const previous_annotations = history[previous_index];\n setAnnotations([...previous_annotations]); // Create new array to trigger re-render\n setHistoryIndex(previous_index);\n setTimeout(() => {\n history_ref.current.saving = false;\n }, 0);\n }\n }, [history_index, history]);\n\n // Handle redo\n const handle_redo = useCallback(() => {\n if (history_index < history.length - 1) {\n history_ref.current.saving = true;\n const next_index = history_index + 1;\n const next_annotations = history[next_index];\n setAnnotations([...next_annotations]); // Create new array to trigger re-render\n setHistoryIndex(next_index);\n setTimeout(() => {\n history_ref.current.saving = false;\n }, 0);\n }\n }, [history_index, history]);\n\n // Keyboard shortcuts for undo/redo\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n // Only handle if not typing in an input field\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n // Check for Ctrl+Z (undo) or Cmd+Z on Mac\n if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n handle_undo();\n }\n // Check for Ctrl+Y or Ctrl+Shift+Z (redo)\n if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.key === 'z' && e.shiftKey))) {\n e.preventDefault();\n handle_redo();\n }\n };\n\n window.addEventListener('keydown', handle_keydown);\n return () => {\n window.removeEventListener('keydown', handle_keydown);\n };\n }, [handle_undo, handle_redo]);\n\n // Handle zoom controls — manual zoom disables fit-to-width auto-scaling\n const handle_zoom_in = () => {\n fit_to_width_active_ref.current = false;\n setFitToWidthActive(false);\n setScale((prev) => Math.min(prev + 0.25, 3.0));\n };\n\n const handle_zoom_out = () => {\n fit_to_width_active_ref.current = false;\n setFitToWidthActive(false);\n setScale((prev) => Math.max(prev - 0.25, 0.5));\n };\n\n const handle_zoom_reset = () => {\n // If fit_to_width prop is enabled, reset re-enables fit-to-width mode\n // instead of going to 100%. This lets the user return to fitted view.\n if (fit_to_width) {\n fit_to_width_active_ref.current = true;\n setFitToWidthActive(true);\n } else {\n setScale(1.0);\n }\n };\n\n // Handle rotation controls\n const normalize_rotation = (rotation: number): number => {\n // Normalize rotation to 0, 90, 180, 270\n let normalized = rotation % 360;\n if (normalized < 0) normalized += 360;\n return normalized;\n };\n\n const handle_rotate_left = useCallback(() => {\n // Rotate current visible page left (counterclockwise 90°)\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n const current_rotation = new_map.get(current_visible_page) || 0;\n new_map.set(current_visible_page, normalize_rotation(current_rotation - 90));\n return new_map;\n });\n }, [current_visible_page]);\n\n const handle_rotate_right = useCallback(() => {\n // Rotate current visible page right (clockwise 90°)\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n const current_rotation = new_map.get(current_visible_page) || 0;\n new_map.set(current_visible_page, normalize_rotation(current_rotation + 90));\n return new_map;\n });\n }, [current_visible_page]);\n\n const handle_rotate_all_left = useCallback(() => {\n // Rotate all pages left (counterclockwise 90°)\n if (!pdf_document) return;\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n for (let i = 0; i < pdf_document.numPages; i++) {\n const current_rotation = new_map.get(i) || 0;\n new_map.set(i, normalize_rotation(current_rotation - 90));\n }\n return new_map;\n });\n }, [pdf_document]);\n\n const handle_rotate_all_right = useCallback(() => {\n // Rotate all pages right (clockwise 90°)\n if (!pdf_document) return;\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n for (let i = 0; i < pdf_document.numPages; i++) {\n const current_rotation = new_map.get(i) || 0;\n new_map.set(i, normalize_rotation(current_rotation + 90));\n }\n return new_map;\n });\n }, [pdf_document]);\n\n const handle_visible_page_change = useCallback((page_index: number) => {\n setCurrentVisiblePage(page_index);\n }, []);\n\n // Handle sidepanel toggle\n const handle_sidepanel_toggle = () => {\n setSidepanelOpen((prev) => !prev);\n };\n\n // Handle sidepanel width change\n const handle_sidepanel_width_change = (width: number) => {\n setSidepanelWidth(width);\n };\n\n // Handle file info sidepanel toggle\n const handle_file_info_sidepanel_toggle = () => {\n setFileInfoSidepanelOpen((prev) => !prev);\n };\n\n // Handle file info sidepanel width change\n const handle_file_info_sidepanel_width_change = (width: number) => {\n setFileInfoSidepanelWidth(width);\n };\n\n // Handle metadata change\n const handle_metadata_change = (updatedRow: MetadataDataItem, allData: MetadataInput) => {\n if (on_metadata_change) {\n return on_metadata_change(updatedRow, allData);\n }\n return { updatedRow, allData };\n };\n\n // Handle popout to new tab\n const handle_popout = useCallback(() => {\n // Single-file mode: simply open the URL in a new tab\n if (!is_multi_file_mode) {\n if (effective_url) {\n window.open(effective_url, '_blank');\n }\n return;\n }\n\n // Multi-file mode: use sessionStorage-based popout\n if (!files || files.length === 0) {\n pdf_logger.warn('No files to popout');\n return;\n }\n\n // Create popout context\n const context: PopoutContext = {\n files: files,\n selected_file_id: current_file?.id || files[0].id,\n annotations_map: {},\n viewer_title: viewer_title,\n };\n\n // If custom handler is provided, use it\n if (on_popout) {\n on_popout(context);\n return;\n }\n\n // Default behavior: save to sessionStorage and open new tab\n try {\n sessionStorage.setItem(POPOUT_STORAGE_KEY, JSON.stringify(context));\n window.open(popout_route, '_blank');\n } catch (err) {\n pdf_logger.error('Failed to popout', { error: err });\n }\n }, [is_multi_file_mode, effective_url, files, current_file, viewer_title, on_popout, popout_route]);\n\n // Auto-highlight effect - runs when PDF loads and highlight_fields_info changes\n useEffect(() => {\n const should_auto_highlight =\n auto_highlight_enabled !== false && // Default true\n highlight_fields_info &&\n highlight_fields_info.length > 0 &&\n pdf_document;\n\n if (!should_auto_highlight) {\n return;\n }\n\n const logger = get_logger();\n\n // Clear previous auto-highlights\n auto_highlight_ids.forEach(id => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n }\n });\n setAutoHighlightIds(new Set());\n\n // Async highlighting (non-blocking)\n const perform_auto_highlights = async () => {\n const { find_text_in_pdf } = await import('../../utils/text_search');\n const new_ids = new Set<string>();\n\n // Get config values\n const auto_config = config_ref.current?.auto_highlight || default_config.auto_highlight;\n\n // Merge search options: props > config > defaults\n const search_opts = {\n normalize: auto_config.auto_highlight_normalize_text,\n padding_x: auto_config.auto_highlight_padding_x,\n padding_y: auto_config.auto_highlight_padding_y,\n y_offset: auto_config.auto_highlight_y_offset,\n ...auto_highlight_search_options,\n };\n\n // Merge highlight style: props > config > defaults\n const highlight_opts = auto_highlight_options || {\n border_color: auto_config.auto_highlight_border_color,\n background_color: auto_config.auto_highlight_background_color,\n background_opacity: auto_config.auto_highlight_background_opacity,\n border_width: auto_config.auto_highlight_border_width,\n };\n\n for (const field of highlight_fields_info!) {\n try {\n const page_idx = field.page_index ?? 0;\n const result = await find_text_in_pdf(pdf_document!, field.value, {\n page_index: page_idx,\n ...search_opts,\n });\n\n if (result) {\n logger.debug('[AutoHighlight] Found text', {\n field: field.field_name,\n value: field.value,\n match_type: result.match_type,\n position: { x: result.x, y: result.y },\n });\n\n const rect: [number, number, number, number] = [\n result.x,\n result.y,\n result.x + result.width,\n result.y + result.height,\n ];\n\n // Create highlight annotation directly\n const highlight_config = config_ref.current?.highlight_annotation || default_config.highlight_annotation;\n\n const annotation: PdfAnnotation = {\n id: `auto_highlight_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n type: 'Highlight',\n page_index: page_idx,\n rect,\n author: 'AutoHighlight',\n date: new Date().toISOString(),\n contents: field.field_name, // Store field name in contents\n color: highlight_opts.background_color || highlight_config.highlight_fill_color,\n flags: 'api_highlight', // Marker to identify API-created highlights\n };\n\n // Store custom options in subject field as JSON (for rendering)\n annotation.subject = JSON.stringify({\n border_color: highlight_opts.border_color,\n background_color: highlight_opts.background_color,\n background_opacity: highlight_opts.background_opacity,\n border_width: highlight_opts.border_width,\n });\n\n handle_annotation_create(annotation);\n new_ids.add(annotation.id);\n } else {\n logger.warn('[AutoHighlight] Text not found in PDF', {\n field: field.field_name,\n value: field.value,\n page: page_idx,\n });\n }\n } catch (err) {\n logger.error('[AutoHighlight] Search failed', {\n field: field.field_name,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n setAutoHighlightIds(new_ids);\n };\n\n perform_auto_highlights();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdf_document, highlight_fields_info, auto_highlight_enabled]);\n\n // Cleanup auto-highlights on unmount\n useEffect(() => {\n return () => {\n auto_highlight_ids.forEach(id => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Check if there are changes to save (annotations or rotations)\n const has_changes_to_save = annotations.length > 0 || page_rotations.size > 0;\n\n // Handle save annotations to PDF\n const handle_save = async () => {\n if (!has_changes_to_save) {\n pdf_logger.warn('No changes to save');\n return;\n }\n\n if (!effective_url) {\n pdf_logger.error('No PDF URL available for saving');\n return;\n }\n\n setSaving(true);\n try {\n const logger = get_logger();\n\n // Generate output filename (use current_file.name in multi-file mode)\n const original_filename = is_multi_file_mode && current_file\n ? current_file.name\n : (effective_url.split('/').pop() || 'document.pdf');\n const filename_without_ext = original_filename.replace(/\\.pdf$/i, '');\n const output_filename = `${filename_without_ext}_annotated.pdf`;\n\n // Import save function to get PDF bytes\n const { save_annotations_to_pdf, download_pdf } = await import('../../utils/pdf_saver');\n\n // Use cached PDF data if available (loaded via file_manager), otherwise use URL\n const pdf_source: string | ArrayBuffer = cached_pdf_data || effective_url;\n logger.debug('[PdfViewer] Saving PDF', { source_type: cached_pdf_data ? 'cached ArrayBuffer' : 'URL' });\n\n // Save annotations to PDF and get the modified bytes\n const pdf_bytes = await save_annotations_to_pdf(pdf_source, annotations, output_filename, config_ref.current, page_rotations);\n\n // If file_manager and save_path are provided, save to remote storage\n if (file_manager && save_path && file_manager.isInitialized()) {\n logger.info('[PdfViewer] Saving PDF to remote storage via hazo_files', { path: save_path });\n const save_result = await save_pdf_data(pdf_bytes, save_path, file_manager);\n if (!save_result.success) {\n throw new Error(`Failed to save to remote storage: ${save_result.error}`);\n }\n logger.info('[PdfViewer] PDF saved to remote storage successfully');\n }\n\n // Call on_save callback if provided (caller may want to handle the bytes)\n // This still fires even after hazo_files save, for caller notification\n if (on_save) {\n on_save(pdf_bytes, output_filename);\n } else if (!file_manager || !save_path) {\n // Only download locally if not saving to remote storage\n download_pdf(pdf_bytes, output_filename);\n }\n } catch (error) {\n pdf_logger.error('Error saving PDF', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n // Notify parent via error callback\n if (on_error) {\n on_error(error_obj);\n }\n } finally {\n setSaving(false);\n }\n };\n\n // Handle download PDF (with annotations baked in)\n const handle_download = async () => {\n if (!effective_url && !cached_pdf_data) {\n pdf_logger.error('No PDF available for download');\n return;\n }\n\n setDownloading(true);\n try {\n const logger = get_logger();\n const { save_annotations_to_pdf, download_pdf } = await import('../../utils/pdf_saver');\n\n // Resolve filename\n const original_filename = is_multi_file_mode && current_file\n ? current_file.name\n : (effective_url?.split('/').pop() || 'document.pdf');\n const output_filename = download_filename || original_filename;\n\n // Use cached PDF data if available, otherwise use URL\n const pdf_source: string | ArrayBuffer = cached_pdf_data || effective_url as string;\n logger.debug('[PdfViewer] Downloading PDF', { filename: output_filename });\n\n // Bake annotations and rotations into the PDF\n const pdf_bytes = await save_annotations_to_pdf(pdf_source, annotations, output_filename, config_ref.current, page_rotations);\n\n // Trigger browser download\n download_pdf(pdf_bytes, output_filename);\n\n // Notify caller\n on_download?.(output_filename);\n } catch (error) {\n pdf_logger.error('Error downloading PDF', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n if (on_error) {\n on_error(error_obj);\n }\n } finally {\n setDownloading(false);\n }\n };\n\n // Handle data extraction via LLM\n const handle_extract = async () => {\n if (!extract_api_endpoint) {\n pdf_logger.warn('No extract_api_endpoint configured');\n const error = new Error('No extract_api_endpoint configured');\n on_extract_error?.(error);\n return;\n }\n\n if (!pdf_document) {\n pdf_logger.warn('No PDF document loaded for extraction');\n const error = new Error('No PDF document loaded');\n on_extract_error?.(error);\n return;\n }\n\n if (!cached_pdf_data) {\n pdf_logger.warn('No cached PDF data available for extraction');\n const error = new Error('No cached PDF data available - please reload the document');\n on_extract_error?.(error);\n return;\n }\n\n setExtracting(true);\n setExtractError(null);\n try {\n const logger = get_logger();\n\n // Get current filename for logging and database matching\n const current_filename = is_multi_file_mode\n ? current_file?.name\n : (display_filename || (url ? url.split('/').pop() || 'unknown' : 'unknown'));\n\n logger.info('[PdfViewer] Starting data extraction', { filename: current_filename });\n\n // Use cached PDF data (always available since we cache during loading)\n // This ensures we extract from the exact same document that's displayed\n const bytes = new Uint8Array(cached_pdf_data);\n // Convert to base64 in chunks to avoid stack overflow\n let binary = '';\n const chunk_size = 8192;\n for (let i = 0; i < bytes.length; i += chunk_size) {\n const chunk = bytes.subarray(i, i + chunk_size);\n binary += String.fromCharCode.apply(null, chunk as unknown as number[]);\n }\n const pdf_base64 = btoa(binary);\n\n logger.debug('[PdfViewer] PDF converted to base64', { size_bytes: bytes.length });\n\n // Determine file path for hazo_files storage\n // In multi-file mode, prefer file_path (actual filesystem path), fall back to url\n // For single-file mode, use the url prop\n const file_path = is_multi_file_mode\n ? (current_file?.file_path || current_file?.url)\n : url;\n\n logger.info('[PdfViewer] Calling extract API', { file_path });\n\n // Call the extract API endpoint\n const api_response = await fetch(extract_api_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n document_b64: pdf_base64,\n document_mime_type: 'application/pdf',\n prompt_area: extract_prompt_area,\n prompt_key: extract_prompt_key,\n // Include file_path, filename, and storage_type for hazo_files integration\n file_path: file_path,\n filename: current_filename,\n storage_type: extract_storage_type,\n }),\n });\n\n if (!api_response.ok) {\n const error_text = await api_response.text();\n throw new Error(`Extract API error: ${api_response.status} - ${error_text}`);\n }\n\n const result = await api_response.json();\n\n if (!result.success) {\n throw new Error(result.error || 'Unknown extraction error');\n }\n\n logger.info('[PdfViewer] Extraction completed successfully');\n\n // Call the success callback with extracted data\n on_extract_complete?.(result.data);\n\n } catch (error) {\n pdf_logger.error('Error extracting data', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n setExtractError(error_obj.message);\n on_extract_error?.(error_obj);\n } finally {\n setExtracting(false);\n }\n };\n\n // Loading state\n if (loading) {\n return (\n <div className={cn('cls_pdf_viewer', 'cls_pdf_viewer_loading', className)}>\n <div className=\"cls_pdf_viewer_spinner\">Loading PDF document...</div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className={cn('cls_pdf_viewer', 'cls_pdf_viewer_error', className)}>\n <div className=\"cls_pdf_viewer_error_message\">\n Error loading PDF: {error.message}\n </div>\n </div>\n );\n }\n\n // No document - in multi-file mode, show file manager for uploads\n if (!pdf_document) {\n if (is_multi_file_mode) {\n // Show file manager with empty state for upload\n return (\n <div className={cn('hazo-pdf-root cls_pdf_viewer', className)}>\n <FileManager\n files={files || []}\n selected_file_id={null}\n config={config_ref.current}\n on_file_select={handle_file_select}\n on_file_delete={on_file_delete}\n on_upload={on_upload}\n on_files_change={on_files_change}\n />\n <div className=\"cls_pdf_viewer_empty_state\">\n <div className=\"cls_pdf_viewer_empty_message\">\n Click the + button above to upload a file\n </div>\n </div>\n </div>\n );\n }\n return (\n <div className={cn('cls_pdf_viewer', className)}>\n <div className=\"cls_pdf_viewer_no_document\">No PDF document loaded</div>\n </div>\n );\n }\n\n // Get toolbar config: props override config file values\n const base_toolbar_config = config_ref.current?.toolbar || default_config.toolbar;\n const toolbar_config = {\n ...base_toolbar_config,\n // Props override config file values (undefined means use config value)\n toolbar_show_zoom_controls: show_zoom_controls ?? base_toolbar_config.toolbar_show_zoom_controls,\n toolbar_show_square_button: show_square_button ?? base_toolbar_config.toolbar_show_square_button,\n toolbar_show_undo_button: show_undo_button ?? base_toolbar_config.toolbar_show_undo_button,\n toolbar_show_redo_button: show_redo_button ?? base_toolbar_config.toolbar_show_redo_button,\n toolbar_show_save_button: show_save_button ?? base_toolbar_config.toolbar_show_save_button,\n toolbar_show_metadata_button: show_metadata_button ?? base_toolbar_config.toolbar_show_metadata_button,\n toolbar_show_annotate_button: show_annotate_button ?? base_toolbar_config.toolbar_show_annotate_button,\n toolbar_show_file_info_button: show_file_info_button ?? base_toolbar_config.toolbar_show_file_info_button,\n toolbar_show_extract_button: show_extract_button ?? base_toolbar_config.toolbar_show_extract_button,\n toolbar_show_download_button: show_download_button ?? base_toolbar_config.toolbar_show_download_button,\n toolbar_show_rotation_controls: base_toolbar_config.toolbar_show_rotation_controls ?? true,\n };\n\n // Master toolbar toggle (defaults to true)\n const is_toolbar_enabled = toolbar_enabled ?? true;\n\n return (\n <div className={cn('hazo-pdf-root cls_pdf_viewer', className)}>\n {/* File Manager for multi-file mode */}\n {is_multi_file_mode && (\n <FileManager\n files={files}\n selected_file_id={current_file?.id || null}\n config={config_ref.current}\n on_file_select={handle_file_select}\n on_file_delete={on_file_delete}\n on_upload={on_upload}\n on_files_change={on_files_change}\n />\n )}\n\n {/* Toolbar */}\n {is_toolbar_enabled && (\n <div\n className=\"cls_pdf_viewer_toolbar\"\n style={{\n backgroundColor: toolbar_config.toolbar_background_color,\n borderColor: toolbar_config.toolbar_border_color,\n fontFamily: toolbar_config.toolbar_font_family,\n fontSize: `${toolbar_config.toolbar_font_size}px`,\n color: toolbar_config.toolbar_font_color,\n }}\n >\n {/* Zoom Controls */}\n {toolbar_config.toolbar_show_zoom_controls && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_zoom_out}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ZoomOut className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <span className=\"cls_pdf_viewer_zoom_level\">\n {Math.round(scale * 100)}%\n </span>\n <button\n type=\"button\"\n onClick={handle_zoom_in}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ZoomIn className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <button\n type=\"button\"\n onClick={handle_zoom_reset}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Reset zoom\"\n title=\"Reset zoom\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <RefreshCw className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Rotation Controls */}\n {toolbar_config.toolbar_show_rotation_controls && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <ToolbarDropdownButton\n icon={<RotateCcw size={16} />}\n aria_label=\"Rotate page left\"\n title=\"Rotate page left (click for current page)\"\n on_main_click={handle_rotate_left}\n background_color={toolbar_config.toolbar_button_background_color}\n background_color_hover={toolbar_config.toolbar_button_background_color_hover}\n text_color={toolbar_config.toolbar_button_text_color}\n options={[\n {\n id: 'rotate_left_current',\n label: 'Rotate left (current page)',\n icon: <RotateCcw size={14} />,\n on_click: handle_rotate_left,\n },\n {\n id: 'rotate_right_current',\n label: 'Rotate right (current page)',\n icon: <RotateCw size={14} />,\n on_click: handle_rotate_right,\n },\n {\n id: 'rotate_left_all',\n label: 'Rotate left (all pages)',\n icon: <RotateCcw size={14} />,\n on_click: handle_rotate_all_left,\n },\n {\n id: 'rotate_right_all',\n label: 'Rotate right (all pages)',\n icon: <RotateCw size={14} />,\n on_click: handle_rotate_all_right,\n },\n ]}\n />\n </div>\n )}\n\n {/* Square Annotation Button */}\n {toolbar_config.toolbar_show_square_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={() => setCurrentTool(current_tool === 'Square' ? null : 'Square')}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n current_tool === 'Square' && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Square annotation tool\"\n title=\"Square annotation\"\n style={{\n backgroundColor: current_tool === 'Square'\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: current_tool === 'Square'\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (current_tool !== 'Square') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (current_tool !== 'Square') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }\n }}\n >\n <Square className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Annotate (FreeText) Button */}\n {toolbar_config.toolbar_show_annotate_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={() => setCurrentTool(current_tool === 'FreeText' ? null : 'FreeText')}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n current_tool === 'FreeText' && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Text annotation tool\"\n title=\"Text annotation\"\n style={{\n backgroundColor: current_tool === 'FreeText'\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: current_tool === 'FreeText'\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (current_tool !== 'FreeText') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (current_tool !== 'FreeText') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }\n }}\n >\n <Type className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Undo/Redo Controls */}\n {(toolbar_config.toolbar_show_undo_button || toolbar_config.toolbar_show_redo_button) && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n {toolbar_config.toolbar_show_undo_button && (\n <button\n type=\"button\"\n onClick={handle_undo}\n disabled={history_index === 0}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n history_index === 0 && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Undo last annotation\"\n title=\"Undo (Ctrl+Z)\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: history_index === 0 ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (history_index > 0) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Undo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n )}\n {toolbar_config.toolbar_show_redo_button && (\n <button\n type=\"button\"\n onClick={handle_redo}\n disabled={history_index >= history.length - 1}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n history_index >= history.length - 1 && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Redo last undone annotation\"\n title=\"Redo (Ctrl+Y)\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: history_index >= history.length - 1 ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (history_index < history.length - 1) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Redo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n )}\n </div>\n )}\n\n {/* Save Button */}\n {toolbar_config.toolbar_show_save_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_save}\n disabled={saving || !has_changes_to_save}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n 'cls_pdf_viewer_toolbar_button_save',\n (saving || !has_changes_to_save) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Save PDF\"\n title={saving ? 'Saving...' : (!has_changes_to_save ? 'No changes to save' : 'Save PDF')}\n style={{\n backgroundColor: toolbar_config.toolbar_button_save_background_color,\n color: toolbar_config.toolbar_button_save_text_color,\n opacity: (saving || !has_changes_to_save) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(saving || !has_changes_to_save)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_save_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_save_background_color;\n }}\n >\n <Save className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Download Button */}\n {toolbar_config.toolbar_show_download_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_download}\n disabled={downloading || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n 'cls_pdf_viewer_toolbar_button_download',\n (downloading || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Download PDF\"\n title={downloading ? 'Downloading...' : 'Download PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (downloading || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(downloading || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Download className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Extract Data Button */}\n {toolbar_config.toolbar_show_extract_button && extract_api_endpoint && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_extract}\n disabled={extracting || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n (extracting || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Extract data\"\n title={extracting ? 'Extracting...' : 'Extract data from PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (extracting || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(extracting || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Sparkles className={cn('cls_pdf_viewer_toolbar_icon', extracting && 'animate-spin')} size={16} />\n </button>\n </div>\n )}\n\n {/* Sidepanel toggle button (original metadata) */}\n {sidepanel_metadata_enabled && metadata_input && toolbar_config.toolbar_show_metadata_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_sidepanel_toggle}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n sidepanel_open && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Toggle metadata panel\"\n title=\"Toggle metadata panel\"\n style={{\n backgroundColor: sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: sidepanel_open\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (!sidepanel_open) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color;\n }}\n >\n <PanelRight className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* File Info sidepanel toggle button (shown when file_metadata, hazo_files, doc_data, or highlight_fields_info is available) */}\n {((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && toolbar_config.toolbar_show_file_info_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_file_info_sidepanel_toggle}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n file_info_sidepanel_open && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Toggle file info panel\"\n title=\"Toggle file info panel\"\n style={{\n backgroundColor: file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (!file_info_sidepanel_open) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color;\n }}\n >\n <Info className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Popout & Download Buttons (shown when enable_popout is true) */}\n {enable_popout && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_popout}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ExternalLink className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <button\n type=\"button\"\n onClick={handle_download}\n disabled={downloading || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n (downloading || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Download PDF\"\n title={downloading ? 'Downloading...' : 'Download PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (downloading || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(downloading || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Download className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Close Button (shown when on_close callback is provided) */}\n {on_close && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={on_close}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Close viewer\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n ✕\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* PDF Viewer Layout with Sidepanel */}\n {(() => {\n const any_sidepanel_open = sidepanel_open || file_info_sidepanel_open;\n const total_sidepanel_width = (sidepanel_open ? sidepanel_width : 0) + (file_info_sidepanel_open ? file_info_sidepanel_width : 0);\n // Check if any sidepanel is available (has content)\n const has_metadata_sidepanel = sidepanel_metadata_enabled && metadata_input;\n const has_file_info_sidepanel = ((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && toolbar_config.toolbar_show_file_info_button;\n const any_sidepanel_available = has_metadata_sidepanel || has_file_info_sidepanel;\n return (\n <div className={cn('cls_pdf_viewer_content_wrapper', any_sidepanel_open && 'cls_pdf_viewer_content_wrapper_with_sidepanel')}>\n {/* Floating metadata expand button at top-right of PDF content */}\n {any_sidepanel_available && !any_sidepanel_open && (\n <button\n type=\"button\"\n onClick={() => {\n // Open the first available sidepanel\n if (has_file_info_sidepanel) {\n handle_file_info_sidepanel_toggle();\n } else if (has_metadata_sidepanel) {\n handle_sidepanel_toggle();\n }\n }}\n className=\"cls_pdf_viewer_metadata_expand_btn\"\n aria-label=\"Open metadata panel\"\n title=\"Open metadata panel\"\n >\n <PanelRightOpen size={18} />\n <span className=\"cls_pdf_viewer_metadata_expand_text\">Metadata</span>\n </button>\n )}\n <div\n ref={content_container_ref}\n className={cn('cls_pdf_viewer_content', any_sidepanel_open && 'cls_pdf_viewer_content_with_sidepanel')}\n style={any_sidepanel_open ? { width: `calc(100% - ${total_sidepanel_width}px)` } : undefined}\n >\n <PdfViewerLayout\n pdf_document={pdf_document}\n scale={scale}\n annotations={annotations}\n current_tool={current_tool}\n background_color={effective_background_color}\n config={config_ref.current}\n page_rotations={page_rotations}\n on_visible_page_change={handle_visible_page_change}\n on_annotation_create={handle_annotation_create}\n on_annotation_click={(annotation, screen_x, screen_y, mapper, viewport_x, viewport_y) => {\n pdf_logger.debug(\n `AnnotationClick: opening editor id=${annotation.id}, page=${annotation.page_index}, screen=(${screen_x.toFixed(\n 1\n )}, ${screen_y.toFixed(1)})`\n );\n // Use viewport coordinates for dialog positioning (position: fixed)\n const dialog_y = Math.max(50, viewport_y);\n\n // Open text dialog for editing\n // For FreeText annotations, show existing text\n // For other annotations, show empty dialog (they don't have text)\n setTextDialog({\n open: true,\n page_index: annotation.page_index,\n x: viewport_x,\n y: dialog_y,\n screen_x,\n screen_y,\n mapper,\n editing_annotation: annotation,\n });\n }}\n on_context_menu={(e, page_index, screen_x, screen_y, mapper) => {\n const menu_x = e.clientX;\n const menu_y = e.clientY;\n\n setContextMenu({\n visible: true,\n x: menu_x,\n y: menu_y,\n page_index,\n screen_x,\n screen_y,\n mapper,\n });\n }}\n on_freetext_click={(page_index, screen_x, screen_y, mapper, viewport_x, viewport_y) => {\n // Open text dialog at click position using viewport coordinates (for position: fixed)\n setTextDialog({\n open: true,\n page_index,\n x: viewport_x,\n y: viewport_y,\n screen_x,\n screen_y,\n mapper,\n });\n // Deselect the FreeText tool after creating annotation\n setCurrentTool(null);\n }}\n />\n </div>\n\n {/* Metadata Sidepanel */}\n {sidepanel_metadata_enabled && metadata_input && (\n <MetadataSidepanel\n is_open={sidepanel_open}\n on_toggle={handle_sidepanel_toggle}\n metadata={metadata_input}\n on_change={handle_metadata_change}\n width={sidepanel_width}\n on_width_change={handle_sidepanel_width_change}\n />\n )}\n\n {/* File Info Sidepanel (combined extraction data + file system info) */}\n {((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && (\n <FileInfoSidepanel\n is_open={file_info_sidepanel_open}\n on_toggle={handle_file_info_sidepanel_toggle}\n item={(() => {\n // Create FileSystemItem from current PDF\n const filename = current_file?.name || display_filename || (url ? url.split('/').pop() || '' : '');\n const filepath = effective_url || '';\n if (!filename) return null;\n return {\n name: filename,\n path: filepath,\n is_directory: false,\n extension: filename.includes('.') ? filename.split('.').pop() : undefined,\n mime_type: 'application/pdf',\n };\n })()}\n width={file_info_sidepanel_width}\n on_width_change={handle_file_info_sidepanel_width_change}\n file_metadata={file_metadata}\n current_filename={current_file?.name || display_filename || (url ? url.split('/').pop() || '' : '')}\n doc_data={doc_data}\n highlight_fields_info={highlight_fields_info}\n extractions={extractions}\n />\n )}\n </div>\n );\n })()}\n\n {/* Context Menu */}\n {context_menu?.visible && (\n <>\n {/* Backdrop to close menu */}\n <div\n className=\"cls_pdf_viewer_context_menu_backdrop\"\n onClick={() => setContextMenu(null)}\n onContextMenu={(e) => {\n e.preventDefault();\n setContextMenu(null);\n }}\n />\n <ContextMenu\n x={context_menu.x}\n y={context_menu.y}\n can_undo={history_index > 0}\n config={config_ref.current}\n custom_stamps={(() => {\n // Get stamps from prop or config (prop takes priority)\n const stamps_json = right_click_custom_stamps || config_ref.current?.context_menu.right_click_custom_stamps || '';\n return parse_custom_stamps(stamps_json);\n })()}\n on_undo={() => {\n handle_undo();\n setContextMenu(null);\n }}\n on_annotate={() => {\n setTextDialog({\n open: true,\n page_index: context_menu.page_index,\n x: context_menu.x, // Use same viewport coordinates as context menu\n y: context_menu.y,\n screen_x: context_menu.screen_x,\n screen_y: context_menu.screen_y,\n mapper: context_menu.mapper,\n });\n setContextMenu(null);\n }}\n on_stamp_click={(stamp) => {\n if (!context_menu || !context_menu.mapper) return;\n \n // Format stamp text with optional suffixes\n const formatted_text = format_stamp_text(stamp, stamp.text);\n \n // Convert screen coordinates to PDF coordinates\n const [pdf_x, pdf_y] = context_menu.mapper.to_pdf(context_menu.screen_x, context_menu.screen_y);\n \n // Get text color - use stamp font_color if provided, otherwise use config\n const fonts_config = config_ref.current?.fonts || default_config.fonts;\n const freetext_config = config_ref.current?.freetext_annotation || default_config.freetext_annotation;\n const text_color = stamp.font_color || \n (freetext_config.freetext_text_color && freetext_config.freetext_text_color !== '#000000'\n ? freetext_config.freetext_text_color\n : fonts_config.font_foreground_color);\n \n // Store stamp styling in subject field as JSON for rendering\n // This allows annotation_overlay to apply stamp-specific styling\n const stamp_styling = {\n stamp_name: stamp.name,\n background_color: stamp.background_color,\n border_size: stamp.border_size,\n font_color: stamp.font_color,\n font_weight: stamp.font_weight,\n font_style: stamp.font_style,\n font_size: stamp.font_size,\n font_name: stamp.font_name,\n };\n \n // Create annotation with stamp styling stored in subject\n const annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: 'FreeText',\n page_index: context_menu.page_index,\n rect: [pdf_x, pdf_y, pdf_x + 10, pdf_y + 10], // Placeholder rect\n author: 'User',\n date: new Date().toISOString(),\n contents: formatted_text,\n color: text_color,\n subject: JSON.stringify(stamp_styling), // Store stamp styling metadata\n };\n \n handle_annotation_create(annotation);\n setContextMenu(null);\n }}\n on_close={() => setContextMenu(null)}\n />\n </>\n )}\n\n {/* Text Annotation Dialog */}\n {text_dialog && (\n <TextAnnotationDialog\n open={text_dialog.open}\n x={text_dialog.x}\n y={text_dialog.y}\n config={config_ref.current}\n initial_text={text_dialog.editing_annotation \n ? strip_auto_inserted_suffix(text_dialog.editing_annotation.contents) \n : ''}\n is_editing={!!text_dialog.editing_annotation}\n on_close={() => setTextDialog(null)}\n on_delete={() => {\n if (text_dialog.editing_annotation) {\n handle_annotation_delete(text_dialog.editing_annotation.id);\n }\n setTextDialog(null);\n }}\n on_submit={(text) => {\n if (!text_dialog || !text_dialog.mapper) return;\n \n // Check if we're editing an existing annotation\n if (text_dialog.editing_annotation) {\n // For editing: strip any existing suffix first, then append new suffix\n // This ensures old suffix is removed and new one is added\n const stripped_text = strip_auto_inserted_suffix(text);\n const final_text = append_timestamp_if_enabled(stripped_text);\n \n // Update existing annotation\n const updated_annotation: PdfAnnotation = {\n ...text_dialog.editing_annotation,\n contents: final_text,\n date: new Date().toISOString(), // Update modification date\n };\n \n handle_annotation_update(updated_annotation);\n setTextDialog(null);\n return;\n }\n \n // For new annotation: append timestamp if enabled\n const final_text = append_timestamp_if_enabled(text);\n \n // Create new annotation (existing code)\n // Convert screen coordinates to PDF coordinates\n // This gives us the exact click position in PDF space\n const [pdf_x, pdf_y] = text_dialog.mapper.to_pdf(text_dialog.screen_x, text_dialog.screen_y);\n \n // Create a text annotation at the clicked position\n //\n // IMPORTANT: For FreeText annotations, the annotation rect serves as a POSITION MARKER only.\n // The actual rendered box dimensions are calculated dynamically during rendering based on:\n // - Text content length\n // - Font size from config\n // - Padding values from config\n //\n // WHY PLACEHOLDER DIMENSIONS:\n // We store minimal placeholder dimensions because:\n // 1. The annotation rect format requires [x1, y1, x2, y2] coordinates\n // 2. We can't know the final text dimensions until we have the text content\n // 3. The rendering logic calculates the actual box size from text + padding\n // 4. Only rect[0] and rect[1] (top-left) matter - they mark the click position\n //\n // ⚠️ DO NOT change placeholder dimensions without updating rendering logic!\n // The rendering code in annotation_overlay.tsx uses screen_x1/y1 directly (not Math.min)\n // to avoid coordinate conversion issues. If placeholder dimensions change significantly,\n // ensure the rendering logic still correctly uses the top-left corner.\n const placeholder_width = 100; // Minimal placeholder width (not used for rendering)\n const placeholder_height = 30; // Minimal placeholder height (not used for rendering)\n \n // Get text color from config with fallback hierarchy:\n // freetext_text_color (if explicitly set) > font_foreground_color > default black\n // Only use freetext_text_color if it's not the default black value\n const freetext_text_color = config_ref.current?.freetext_annotation.freetext_text_color;\n const font_foreground_color = config_ref.current?.fonts.font_foreground_color;\n \n // Use freetext_text_color only if it's explicitly set and not the default black\n // Otherwise, fall back to font_foreground_color\n const text_color = (freetext_text_color && freetext_text_color !== '#000000') \n ? freetext_text_color\n : (font_foreground_color || '#000000');\n \n // Create FreeText annotation\n // rect[0] and rect[1] = pdf_x, pdf_y: These are CRITICAL - they mark where the user clicked\n // rect[2] and rect[3] = placeholder bottom-right: These are NOT used for positioning\n // The rendering code MUST use rect[0]/rect[1] directly after conversion (see annotation_overlay.tsx)\n const annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: 'FreeText',\n page_index: text_dialog.page_index,\n rect: [\n pdf_x, // Top-left X (click position)\n pdf_y, // Top-left Y (click position)\n pdf_x + placeholder_width, // Bottom-right X (placeholder)\n pdf_y + placeholder_height, // Bottom-right Y (placeholder)\n ],\n author: 'User',\n date: new Date().toISOString(),\n contents: final_text,\n color: text_color,\n };\n \n handle_annotation_create(annotation);\n setTextDialog(null);\n }}\n />\n )}\n\n {/* Extract Error Dialog */}\n {extract_error && (\n <div className=\"cls_pdf_viewer_error_dialog_overlay\">\n <div className=\"cls_pdf_viewer_error_dialog\">\n <div className=\"cls_pdf_viewer_error_dialog_header\">\n <span className=\"cls_pdf_viewer_error_dialog_title\">Extraction Error</span>\n <button\n type=\"button\"\n onClick={() => setExtractError(null)}\n className=\"cls_pdf_viewer_error_dialog_close\"\n aria-label=\"Close\"\n >\n <X size={16} />\n </button>\n </div>\n <div className=\"cls_pdf_viewer_error_dialog_content\">\n {extract_error}\n </div>\n <div className=\"cls_pdf_viewer_error_dialog_footer\">\n <button\n type=\"button\"\n onClick={() => setExtractError(null)}\n className=\"cls_pdf_viewer_error_dialog_button\"\n >\n OK\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n});\n\n// Set display name for debugging\nPdfViewer.displayName = 'PdfViewer';\n\nexport default PdfViewer;\n\n","/**\n * Toolbar Dropdown Button Component\n * Split button with main action and dropdown menu for additional options\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronDown } from 'lucide-react';\nimport { cn } from '../../utils/cn';\n\nexport interface DropdownOption {\n /** Unique identifier for the option */\n id: string;\n /** Display label */\n label: string;\n /** Icon to display (optional) */\n icon?: React.ReactNode;\n /** Click handler */\n on_click: () => void;\n /** Whether the option is disabled */\n disabled?: boolean;\n}\n\nexport interface ToolbarDropdownButtonProps {\n /** Icon for the main button */\n icon: React.ReactNode;\n /** Aria label for accessibility */\n aria_label: string;\n /** Tooltip text */\n title: string;\n /** Handler for main button click */\n on_main_click: () => void;\n /** Dropdown options */\n options: DropdownOption[];\n /** Button background color */\n background_color?: string;\n /** Button hover background color */\n background_color_hover?: string;\n /** Button text/icon color */\n text_color?: string;\n /** Whether the button is disabled */\n disabled?: boolean;\n}\n\n/**\n * Toolbar Dropdown Button\n * Split button design with main action and dropdown chevron\n */\nexport const ToolbarDropdownButton: React.FC<ToolbarDropdownButtonProps> = ({\n icon,\n aria_label,\n title,\n on_main_click,\n options,\n background_color = '#ffffff',\n background_color_hover = '#f3f4f6',\n text_color = '#374151',\n disabled = false,\n}) => {\n const [dropdown_open, setDropdownOpen] = useState(false);\n const [is_main_hovered, setIsMainHovered] = useState(false);\n const [is_chevron_hovered, setIsChevronHovered] = useState(false);\n const container_ref = useRef<HTMLDivElement>(null);\n const dropdown_ref = useRef<HTMLDivElement>(null);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handle_click_outside = (e: MouseEvent) => {\n if (container_ref.current && !container_ref.current.contains(e.target as Node)) {\n setDropdownOpen(false);\n }\n };\n\n if (dropdown_open) {\n document.addEventListener('mousedown', handle_click_outside);\n return () => {\n document.removeEventListener('mousedown', handle_click_outside);\n };\n }\n return undefined;\n }, [dropdown_open]);\n\n // Close dropdown on escape key\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && dropdown_open) {\n setDropdownOpen(false);\n }\n };\n\n if (dropdown_open) {\n document.addEventListener('keydown', handle_keydown);\n return () => {\n document.removeEventListener('keydown', handle_keydown);\n };\n }\n return undefined;\n }, [dropdown_open]);\n\n const handle_main_click = () => {\n if (!disabled) {\n on_main_click();\n }\n };\n\n const handle_chevron_click = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!disabled) {\n setDropdownOpen(!dropdown_open);\n }\n };\n\n const handle_option_click = (option: DropdownOption) => {\n if (!option.disabled) {\n option.on_click();\n setDropdownOpen(false);\n }\n };\n\n return (\n <div ref={container_ref} className=\"cls_toolbar_dropdown_container\" style={{ position: 'relative' }}>\n <div\n className={cn(\n 'cls_toolbar_dropdown_button',\n disabled && 'cls_toolbar_dropdown_button_disabled'\n )}\n style={{\n display: 'flex',\n alignItems: 'stretch',\n borderRadius: '0.25rem',\n overflow: 'hidden',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n {/* Main button area */}\n <button\n type=\"button\"\n onClick={handle_main_click}\n className=\"cls_toolbar_dropdown_main\"\n aria-label={aria_label}\n title={title}\n disabled={disabled}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '0.25rem 0.5rem',\n backgroundColor: is_main_hovered ? background_color_hover : background_color,\n color: text_color,\n border: '1px solid #d1d5db',\n borderRight: 'none',\n borderTopLeftRadius: '0.25rem',\n borderBottomLeftRadius: '0.25rem',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={() => setIsMainHovered(true)}\n onMouseLeave={() => setIsMainHovered(false)}\n >\n {icon}\n </button>\n\n {/* Chevron dropdown trigger */}\n <button\n type=\"button\"\n onClick={handle_chevron_click}\n className=\"cls_toolbar_dropdown_chevron\"\n aria-label=\"Show more options\"\n aria-expanded={dropdown_open}\n aria-haspopup=\"menu\"\n disabled={disabled}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '0.25rem 0.25rem',\n backgroundColor: is_chevron_hovered ? background_color_hover : background_color,\n color: text_color,\n border: '1px solid #d1d5db',\n borderTopRightRadius: '0.25rem',\n borderBottomRightRadius: '0.25rem',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={() => setIsChevronHovered(true)}\n onMouseLeave={() => setIsChevronHovered(false)}\n >\n <ChevronDown\n size={12}\n style={{\n transform: dropdown_open ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 0.15s ease',\n }}\n />\n </button>\n </div>\n\n {/* Dropdown menu */}\n {dropdown_open && (\n <div\n ref={dropdown_ref}\n className=\"cls_toolbar_dropdown_menu\"\n role=\"menu\"\n style={{\n position: 'absolute',\n top: '100%',\n left: '0',\n marginTop: '4px',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\n zIndex: 1000,\n minWidth: '160px',\n overflow: 'hidden',\n }}\n >\n {options.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n role=\"menuitem\"\n onClick={() => handle_option_click(option)}\n disabled={option.disabled}\n className={cn(\n 'cls_toolbar_dropdown_item',\n option.disabled && 'cls_toolbar_dropdown_item_disabled'\n )}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n width: '100%',\n padding: '8px 12px',\n textAlign: 'left',\n fontSize: '13px',\n color: option.disabled ? '#9ca3af' : '#374151',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: option.disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={(e) => {\n if (!option.disabled) {\n e.currentTarget.style.backgroundColor = '#f3f4f6';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n {option.icon && <span style={{ flexShrink: 0 }}>{option.icon}</span>}\n <span>{option.label}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default ToolbarDropdownButton;\n","/**\n * Class name utility function\n * Combines clsx and tailwind-merge for better class merging\n */\n\nimport { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n","/**\n * PDF Worker Setup\n * Configures pdfjs-dist to use Web Workers for PDF processing\n * This ensures PDF parsing and rendering happens off the main thread\n * \n * IMPORTANT: This module uses dynamic imports to prevent SSR evaluation\n * PDF.js can only run in the browser, so we must avoid importing it during SSR\n */\n\n// Type imports are safe - they don't execute code\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { get_logger } from '../../utils/logger';\n\n// Track if worker has been configured to avoid multiple configurations\nlet worker_configured = false;\n\n/**\n * Configure the PDF.js worker dynamically (only in browser)\n * This function must be called before loading any PDF documents\n * @returns Promise that resolves when worker is configured\n */\nasync function configure_worker(): Promise<void> {\n const logger = get_logger();\n // Only configure in browser environment - double check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Skip if already configured\n if (worker_configured) {\n return;\n }\n\n try {\n // Use a dynamic import that only executes in browser\n // Wrap in a function that checks browser environment again\n const pdfjs_module = await (async () => {\n if (typeof window === 'undefined') {\n throw new Error('Cannot configure PDF.js worker in non-browser environment');\n }\n // Dynamic import - only loads in browser\n return await import('pdfjs-dist');\n })();\n \n const { GlobalWorkerOptions, version } = pdfjs_module;\n const pdfjsVersion = version;\n \n // jsdelivr CDN - supports all npm package versions\n GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`;\n \n logger.info(`Worker configured: ${GlobalWorkerOptions.workerSrc}`);\n worker_configured = true;\n \n // Alternative CDN options (uncomment to use):\n // - cdnjs (may not have all versions): `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsVersion}/pdf.worker.min.mjs`\n // - unpkg: `https://unpkg.com/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`\n \n // For offline/local development, you can:\n // 1. Copy pdfjs-dist/build/pdf.worker.min.mjs to your public folder\n // 2. Set: GlobalWorkerOptions.workerSrc = '/pdf.worker.min.mjs';\n } catch (error) {\n // Only log error if in browser - don't throw during SSR\n if (typeof window !== 'undefined') {\n logger.error('Error configuring worker', { data: error });\n throw error;\n }\n }\n}\n\n/**\n * Load a PDF document from a URL or ArrayBuffer\n * For local files (like in Storybook), fetch as ArrayBuffer for better compatibility\n * @param source - URL string, ArrayBuffer, or Uint8Array\n * @returns Promise resolving to PDFDocumentProxy\n */\nexport async function load_pdf_document(\n source: string | ArrayBuffer | Uint8Array\n): Promise<PDFDocumentProxy> {\n // Ensure we're in browser environment - multiple checks\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('load_pdf_document can only be called in the browser');\n }\n \n // Additional check: ensure we're not in Node.js environment\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n throw new Error('load_pdf_document cannot be called in Node.js environment');\n }\n \n // Configure worker first (idempotent - won't reconfigure if already done)\n await configure_worker();\n \n const logger = get_logger();\n // Dynamic import of getDocument - direct import() for bundler compatibility\n const pdfjs_module = await import('pdfjs-dist');\n const { getDocument } = pdfjs_module;\n\n logger.info('Loading PDF', { data: { source: typeof source === 'string' ? source : 'ArrayBuffer/Uint8Array' } });\n \n try {\n // If source is a URL string, try to fetch it as ArrayBuffer for better compatibility\n let pdfData: ArrayBuffer | Uint8Array | string = source;\n \n if (typeof source === 'string') {\n // Check if it's a relative URL (likely a local file)\n if (source.startsWith('/') || source.startsWith('./') || !source.includes('://')) {\n logger.info('Fetching local PDF file as ArrayBuffer', { data: { source } });\n try {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\n }\n pdfData = await response.arrayBuffer();\n logger.info('PDF fetched successfully', { data: { size: pdfData.byteLength } });\n } catch (fetchError) {\n logger.error('Error fetching PDF as ArrayBuffer, trying URL directly', { data: fetchError });\n // Fall back to URL if fetch fails\n pdfData = source;\n }\n }\n }\n \n const loading_task = getDocument({\n url: typeof pdfData === 'string' ? pdfData : undefined,\n data: typeof pdfData !== 'string' ? pdfData : undefined,\n verbosity: 0, // Suppress console warnings\n // Add CORS support\n httpHeaders: {},\n withCredentials: false,\n // Enable range requests for better performance\n rangeChunkSize: 65536,\n });\n \n const document = await loading_task.promise;\n logger.info('PDF loaded successfully', { data: { pages: document.numPages } });\n return document;\n } catch (error) {\n logger.error('Error loading PDF', { data: error });\n throw error;\n }\n}\n\n/**\n * Export types for use in components\n * Note: getDocument and GlobalWorkerOptions are not exported directly\n * to prevent SSR evaluation - use load_pdf_document instead\n */\nexport type { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\n/**\n * Export configure_worker for components that need to ensure worker is configured\n * This is called automatically by load_pdf_document, so you typically don't need this\n */\nexport { configure_worker };\n","/**\n * PDF Viewer Layout Component\n * Main layout container with scrollable viewport\n * Manages page rendering and annotation overlay\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react';\nimport type { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist';\nimport type { PdfAnnotation, CoordinateMapper, PageDimensions, PdfViewerConfig } from '../../types';\nimport { PdfPageRenderer } from './pdf_page_renderer';\nimport { AnnotationOverlay } from './annotation_overlay';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for PdfViewerLayout component\n */\nexport interface PdfViewerLayoutProps {\n pdf_document: PDFDocumentProxy;\n scale: number;\n annotations: PdfAnnotation[];\n current_tool: 'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null;\n on_annotation_create: (annotation: PdfAnnotation) => void;\n on_context_menu: (e: React.MouseEvent, page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper) => void;\n on_annotation_click: (annotation: PdfAnnotation, screen_x: number, screen_y: number, mapper: CoordinateMapper, viewport_x: number, viewport_y: number) => void;\n on_freetext_click?: (page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper, viewport_x: number, viewport_y: number) => void;\n background_color?: string;\n config: PdfViewerConfig | null;\n className?: string;\n /** Page rotation state - Map of page_index to rotation degrees (0, 90, 180, 270) */\n page_rotations?: Map<number, number>;\n /** Callback when current visible page changes */\n on_visible_page_change?: (page_index: number) => void;\n}\n\n/**\n * PDF Viewer Layout Component\n * Manages page rendering and annotation overlay coordination\n */\nexport const PdfViewerLayout: React.FC<PdfViewerLayoutProps> = ({\n pdf_document,\n scale,\n annotations = [],\n current_tool = 'Square',\n on_annotation_create,\n on_context_menu,\n on_annotation_click,\n on_freetext_click,\n background_color = '#2d2d2d',\n config = null,\n className = '',\n page_rotations = new Map(),\n on_visible_page_change,\n}) => {\n const [pages, setPages] = useState<PDFPageProxy[]>([]);\n const [loading, setLoading] = useState(true);\n const [coordinate_mappers, setCoordinateMappers] = useState<\n Map<number, { mapper: CoordinateMapper; dimensions: PageDimensions }>\n >(new Map());\n const container_ref = useRef<HTMLDivElement>(null);\n const has_centered_ref = useRef(false);\n const page_refs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // Pan/scroll state\n const [is_panning, setIsPanning] = useState(false);\n const pan_start_ref = useRef<{ x: number; y: number; scrollLeft: number; scrollTop: number } | null>(null);\n\n // Track visible page using IntersectionObserver\n useEffect(() => {\n if (!container_ref.current || pages.length === 0 || !on_visible_page_change) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n // Find the most visible page (highest intersection ratio)\n let max_ratio = 0;\n let most_visible_page = 0;\n\n entries.forEach((entry) => {\n const page_index = parseInt(entry.target.getAttribute('data-page-index') || '0', 10);\n if (entry.intersectionRatio > max_ratio) {\n max_ratio = entry.intersectionRatio;\n most_visible_page = page_index;\n }\n });\n\n if (max_ratio > 0) {\n on_visible_page_change(most_visible_page);\n }\n },\n {\n root: container_ref.current,\n threshold: [0, 0.25, 0.5, 0.75, 1.0],\n }\n );\n\n // Observe all page wrappers\n page_refs.current.forEach((element) => {\n observer.observe(element);\n });\n\n return () => {\n observer.disconnect();\n };\n }, [pages.length, on_visible_page_change]);\n\n // Load all pages from the PDF document\n useEffect(() => {\n if (!pdf_document) {\n return;\n }\n setLoading(true);\n const num_pages = pdf_document.numPages;\n const page_promises: Promise<PDFPageProxy>[] = [];\n\n for (let i = 1; i <= num_pages; i++) {\n page_promises.push(pdf_document.getPage(i));\n }\n\n Promise.all(page_promises)\n .then((loaded_pages) => {\n setPages(loaded_pages);\n setLoading(false);\n // Reset centered flag when PDF document changes\n has_centered_ref.current = false;\n })\n .catch((error) => {\n const logger = get_logger();\n logger.error('Error loading PDF pages', { data: error });\n setLoading(false);\n });\n }, [pdf_document]);\n\n // Handle coordinate mapper ready callback - memoized to prevent re-renders\n const handle_coordinate_mapper_ready = useCallback((\n page_index: number,\n mapper: CoordinateMapper,\n dimensions: PageDimensions\n ) => {\n setCoordinateMappers((prev) => {\n // Check if the mapper data has actually changed to avoid unnecessary updates\n const existing = prev.get(page_index);\n if (existing && \n existing.dimensions.width === dimensions.width && \n existing.dimensions.height === dimensions.height) {\n // Dimensions haven't changed, don't update\n return prev;\n }\n const new_map = new Map(prev);\n new_map.set(page_index, { mapper, dimensions });\n return new_map;\n });\n }, []);\n\n // Center horizontal scroll when PDF first loads\n useEffect(() => {\n // Only center once when pages are loaded and we have at least one mapper\n if (loading || pages.length === 0 || coordinate_mappers.size === 0 || has_centered_ref.current) {\n return;\n }\n\n // Wait for next frame to ensure layout is calculated\n const timeout_id = setTimeout(() => {\n if (container_ref.current) {\n const container = container_ref.current;\n const scroll_width = container.scrollWidth;\n const client_width = container.clientWidth;\n \n // Only center if content is wider than container\n if (scroll_width > client_width) {\n const center_scroll = (scroll_width - client_width) / 2;\n container.scrollLeft = center_scroll;\n has_centered_ref.current = true;\n } else {\n // Content fits, mark as centered anyway\n has_centered_ref.current = true;\n }\n }\n }, 100); // Small delay to ensure layout is complete\n\n return () => {\n clearTimeout(timeout_id);\n };\n }, [loading, pages.length, coordinate_mappers.size]);\n\n // Pan/scroll handlers (only active when current_tool is null/pan mode)\n const handle_mouse_down = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n // Only handle left mouse button\n if (e.button !== 0) return;\n \n const native_event = e.nativeEvent as unknown as { __annotation_clicked?: string; __annotation_click_source?: string };\n if (native_event?.__annotation_clicked) {\n const logger = get_logger();\n logger.debug(\n `Layout received annotation click marker id=${native_event.__annotation_clicked}, source=${native_event.__annotation_click_source || 'unknown'}`\n );\n return;\n }\n \n // Only pan when no tool is selected (pan mode)\n if (current_tool !== null) return;\n \n if (container_ref.current) {\n setIsPanning(true);\n pan_start_ref.current = {\n x: e.clientX,\n y: e.clientY,\n scrollLeft: container_ref.current.scrollLeft,\n scrollTop: container_ref.current.scrollTop,\n };\n e.preventDefault(); // Prevent text selection while panning\n e.stopPropagation(); // Prevent event bubbling\n container_ref.current.style.cursor = 'grabbing';\n \n }\n }, [current_tool]);\n\n const handle_mouse_move = useCallback((e: React.MouseEvent<HTMLDivElement> | MouseEvent) => {\n if (!is_panning || !pan_start_ref.current || !container_ref.current) return;\n \n // Prevent default to avoid text selection and other default behaviors\n e.preventDefault();\n \n const delta_x = pan_start_ref.current.x - e.clientX;\n const delta_y = pan_start_ref.current.y - e.clientY;\n \n // Calculate new scroll positions\n const max_scroll_left = Math.max(0, container_ref.current.scrollWidth - container_ref.current.clientWidth);\n const max_scroll_top = Math.max(0, container_ref.current.scrollHeight - container_ref.current.clientHeight);\n \n const new_scroll_left = Math.max(0, Math.min(max_scroll_left, pan_start_ref.current.scrollLeft + delta_x));\n const new_scroll_top = Math.max(0, Math.min(max_scroll_top, pan_start_ref.current.scrollTop + delta_y));\n \n // Update both horizontal and vertical scroll positions (browser will clamp these anyway)\n container_ref.current.scrollLeft = new_scroll_left;\n container_ref.current.scrollTop = new_scroll_top;\n \n }, [is_panning]);\n\n const handle_mouse_up = useCallback(() => {\n if (container_ref.current) {\n container_ref.current.style.cursor = current_tool === null ? 'grab' : 'default';\n }\n setIsPanning(false);\n pan_start_ref.current = null;\n }, [current_tool]);\n\n // Update cursor style based on current tool\n useEffect(() => {\n if (container_ref.current) {\n if (current_tool === null) {\n container_ref.current.style.cursor = is_panning ? 'grabbing' : 'grab';\n } else {\n container_ref.current.style.cursor = 'default';\n }\n }\n }, [current_tool, is_panning]);\n\n // Add global mouse move and up listeners for panning\n useEffect(() => {\n if (is_panning) {\n window.addEventListener('mousemove', handle_mouse_move);\n window.addEventListener('mouseup', handle_mouse_up);\n \n return () => {\n window.removeEventListener('mousemove', handle_mouse_move);\n window.removeEventListener('mouseup', handle_mouse_up);\n };\n }\n return undefined;\n }, [is_panning, handle_mouse_move, handle_mouse_up]);\n\n // AnnotationOverlay now handles annotation clicks directly and stamps native events.\n // The container only pans when those markers are absent, preventing accidental grab mode.\n\n if (loading) {\n return (\n <div className={cn('cls_pdf_viewer_loading', className)}>\n <div className=\"cls_pdf_viewer_spinner\">Loading PDF...</div>\n </div>\n );\n }\n\n return (\n <div\n ref={container_ref}\n className={cn('cls_pdf_viewer_layout', className)}\n style={{\n // Don't constrain width/height - let content determine size\n // This allows container to expand beyond viewport when zoomed\n position: 'relative',\n backgroundColor: background_color,\n // Cursor is managed dynamically - default to grab in pan mode, but annotations will override\n cursor: current_tool === null ? (is_panning ? 'grabbing' : 'grab') : 'default',\n userSelect: is_panning ? 'none' : 'auto',\n // Allow both horizontal and vertical scrolling\n overflow: 'auto',\n overflowX: 'auto',\n overflowY: 'auto',\n // Container must be viewport size (100%) to create scrollable area\n // Content inside (pages_container) expands beyond this to enable scrolling\n width: '100%',\n height: '100%',\n // Don't constrain content expansion\n minWidth: 0,\n minHeight: 0,\n }}\n onMouseDown={handle_mouse_down}\n onMouseMove={(e) => {\n // Check if mouse is over an annotation overlay\n // If so, don't override cursor - let the annotation overlay manage it\n const target = e.target as HTMLElement;\n if (target.closest('svg.cls_annotation_overlay') || target.closest('rect[style*=\"cursor: pointer\"]')) {\n // Don't override cursor - annotation overlay will handle it\n return;\n }\n \n // Update cursor for pan mode if not over annotation\n if (container_ref.current && current_tool === null && !is_panning) {\n container_ref.current.style.cursor = 'grab';\n }\n }}\n >\n <div className=\"cls_pdf_viewer_pages_container\">\n {pages.map((page, index) => {\n const mapper_data = coordinate_mappers.get(index);\n const page_annotations = annotations?.filter(\n (ann) => ann.page_index === index\n ) || [];\n const page_rotation = page_rotations.get(index) || 0;\n\n return (\n <div\n key={index}\n ref={(el) => {\n if (el) {\n page_refs.current.set(index, el);\n } else {\n page_refs.current.delete(index);\n }\n }}\n data-page-index={index}\n className=\"cls_pdf_viewer_page_wrapper\"\n style={{\n position: 'relative',\n marginBottom: '20px',\n // Inherit cursor from parent (grab/grabbing in pan mode)\n cursor: 'inherit',\n }}\n >\n {/* PDF Page Renderer */}\n <PdfPageRenderer\n page={page}\n page_index={index}\n scale={scale}\n rotation={page_rotation}\n config={config}\n on_coordinate_mapper_ready={(mapper, dimensions) =>\n handle_coordinate_mapper_ready(index, mapper, dimensions)\n }\n />\n\n {/* Annotation Overlay - Must be positioned absolutely to overlay the canvas */}\n {mapper_data && (\n <AnnotationOverlay\n width={mapper_data.dimensions.width}\n height={mapper_data.dimensions.height}\n page_index={index}\n map_coords={mapper_data.mapper}\n annotations={page_annotations}\n current_tool={current_tool}\n config={config}\n on_annotation_create={on_annotation_create}\n on_context_menu={(e, screen_x, screen_y) => {\n if (on_context_menu && mapper_data.mapper) {\n on_context_menu(e, index, screen_x, screen_y, mapper_data.mapper);\n }\n }}\n on_annotation_click={(annotation, screen_x, screen_y, viewport_x, viewport_y) => {\n if (on_annotation_click && mapper_data.mapper) {\n on_annotation_click(annotation, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);\n }\n }}\n on_freetext_click={(screen_x, screen_y, viewport_x, viewport_y) => {\n if (on_freetext_click && mapper_data.mapper) {\n on_freetext_click(index, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);\n }\n }}\n />\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default PdfViewerLayout;\n\n","/**\n * PDF Page Renderer Component\n * Renders a single PDF page to a canvas element\n * Provides coordinate mapping utilities for annotations\n */\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport { create_coordinate_mapper } from '../../utils/coordinate_mapper';\nimport type { CoordinateMapper, PageDimensions, PdfViewerConfig } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for PDFPageRenderer component\n */\nexport interface PdfPageRendererProps {\n /** PDF page proxy object */\n page: PDFPageProxy;\n\n /** Zero-based page index */\n page_index: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Rotation in degrees (0, 90, 180, 270) */\n rotation?: number;\n\n /** Optional class name */\n className?: string;\n\n /** Callback to provide coordinate mapper to parent */\n on_coordinate_mapper_ready?: (mapper: CoordinateMapper, dimensions: PageDimensions) => void;\n\n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n}\n\n/**\n * PDF Page Renderer Component\n * Handles rendering of a single PDF page to canvas\n */\nexport const PdfPageRenderer: React.FC<PdfPageRendererProps> = ({\n page,\n page_index,\n scale,\n rotation = 0,\n className = '',\n on_coordinate_mapper_ready,\n config = null,\n}) => {\n const canvas_ref = useRef<HTMLCanvasElement>(null);\n const render_task_ref = useRef<any>(null);\n const notified_dimensions_ref = useRef<{ width: number; height: number; scale: number } | null>(null);\n const callback_ref = useRef(on_coordinate_mapper_ready);\n \n // Update callback ref when it changes (but don't trigger re-render)\n useEffect(() => {\n callback_ref.current = on_coordinate_mapper_ready;\n }, [on_coordinate_mapper_ready]);\n \n // Calculate dimensions from viewport (doesn't change unless page, scale, or rotation changes)\n const viewport_dimensions = useMemo(() => {\n if (!page) return { width: 0, height: 0 };\n const viewport = page.getViewport({ scale, rotation });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n }, [page, scale, rotation]);\n\n // Create coordinate mapper - memoized to prevent recreation\n const coordinate_mapper = useMemo(() => {\n if (!page) return null;\n return create_coordinate_mapper(page, scale, rotation);\n }, [page, scale, rotation]);\n\n // Notify parent of coordinate mapper - only when dimensions actually change\n useEffect(() => {\n if (!page || !coordinate_mapper) return;\n \n const current_dimensions = viewport_dimensions;\n const last_notified = notified_dimensions_ref.current;\n \n // Only notify if dimensions or scale have actually changed\n if (!last_notified || \n last_notified.width !== current_dimensions.width || \n last_notified.height !== current_dimensions.height ||\n last_notified.scale !== scale) {\n if (callback_ref.current) {\n callback_ref.current(coordinate_mapper, current_dimensions);\n notified_dimensions_ref.current = { ...current_dimensions, scale };\n }\n }\n }, [page, coordinate_mapper, viewport_dimensions.width, viewport_dimensions.height, scale]);\n\n // Render the page onto the canvas\n useEffect(() => {\n // Ensure we're in browser environment\n if (typeof window === 'undefined') {\n return;\n }\n\n if (!page) {\n return;\n }\n\n if (!canvas_ref.current) {\n return;\n }\n\n // Cancel any previous render task and wait for it to complete\n // This prevents multiple renders on the same canvas (React Strict Mode issue)\n let cancelled = false;\n const cancel_previous = async () => {\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n // Wait for cancellation to complete\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 render and then start new one\n cancel_previous().then(() => {\n // Check if effect was cancelled during async operation\n if (cancelled || !canvas_ref.current) {\n return;\n }\n\n // Get the viewport with the current scale and rotation\n const viewport = page.getViewport({ scale, rotation });\n\n // Set up canvas\n const canvas = canvas_ref.current;\n const context = canvas.getContext('2d', { alpha: false }); // Disable alpha for better performance\n if (!context) {\n const logger = get_logger();\n logger.error(`Page ${page_index}: Cannot get 2D context`);\n return;\n }\n\n // Handle high DPI displays\n const output_scale = window.devicePixelRatio || 1;\n\n // Set native canvas size for sharp rendering\n // Note: Setting canvas.width/height automatically clears the canvas\n // This also invalidates any previous render tasks\n canvas.width = viewport.width * output_scale;\n canvas.height = viewport.height * output_scale;\n\n // Set CSS size (what the browser displays)\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n // Scale the context to match device pixel ratio\n context.scale(output_scale, output_scale);\n\n // Fill canvas with white background before rendering\n // This ensures any transparent areas in the PDF appear white\n context.fillStyle = '#ffffff';\n context.fillRect(0, 0, viewport.width, viewport.height);\n\n // Render the page\n // Note: annotationMode: 0 disables annotation rendering on the canvas\n // This prevents form fields and other annotations from being drawn with incorrect fills\n // Our custom annotation overlay handles annotation display separately\n const render_context = {\n canvasContext: context,\n viewport: viewport,\n annotationMode: 0, // DISABLE - don't render annotations on canvas\n background: 'white', // Explicitly set white background for pdfjs rendering\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 // Only clear ref if this is still the current render task\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n })\n .catch((error) => {\n // Ignore cancellation errors (expected during cleanup)\n if (error.name !== 'RenderingCancelledException') {\n const logger = get_logger();\n logger.error(`Page ${page_index}: Error rendering`, { data: error });\n }\n // Only clear ref if this is still the current render task\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n });\n });\n\n // Cleanup: cancel rendering if component unmounts or dependencies 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 cancellation errors\n }\n render_task_ref.current = null;\n }\n };\n }, [page, scale, rotation, page_index]);\n\n // Show loading only if we don't have a page yet\n if (!page) {\n return (\n <div className={cn('cls_pdf_page_loading', className)}>\n <div className=\"cls_pdf_page_spinner\">Loading page...</div>\n </div>\n );\n }\n\n // Get styling values from config or use defaults\n const page_config = config?.page_styling || default_config.page_styling;\n \n return (\n <div\n className={cn('cls_pdf_page_container', className)}\n style={{\n position: 'relative',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n border: `1px solid ${page_config.page_border_color}`,\n boxShadow: page_config.page_box_shadow,\n backgroundColor: page_config.page_background_color,\n // Inherit cursor from parent (grab/grabbing in pan mode)\n cursor: 'inherit',\n }}\n >\n {/* Canvas: The PDF rendering base layer */}\n <canvas\n ref={canvas_ref}\n className=\"cls_pdf_page_canvas\"\n style={{\n display: 'block',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n pointerEvents: 'none', // Allow events to pass through to SVG overlay\n }}\n aria-label={`PDF page ${page_index + 1}`}\n />\n </div>\n );\n};\n\nexport default PdfPageRenderer;\n\n","/**\n * Coordinate Mapper Utilities\n * Handles conversion between PDF coordinate space and Screen coordinate space\n * PDF coordinates use bottom-left origin, Screen coordinates use top-left origin\n */\n\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport type { CoordinateMapper } from '../types';\n\n/**\n * Create a coordinate mapper for a specific page, scale, and rotation\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @param rotation - Rotation in degrees (0, 90, 180, 270)\n * @returns CoordinateMapper with to_pdf and to_screen methods\n */\nexport function create_coordinate_mapper(\n page: PDFPageProxy,\n scale: number,\n rotation: number = 0\n): CoordinateMapper {\n const viewport = page.getViewport({ scale, rotation });\n\n return {\n /**\n * Convert screen (CSS pixel) coordinates to PDF (abstract) coordinates\n * @param x_screen - X coordinate in screen space\n * @param y_screen - Y coordinate in screen space\n * @returns [x_pdf, y_pdf] coordinates in PDF space\n */\n to_pdf: (x_screen: number, y_screen: number): [number, number] => {\n // PDF.js viewport handles the coordinate transformation\n // including the origin conversion (top-left vs bottom-left)\n const result = viewport.convertToPdfPoint(x_screen, y_screen);\n return [result[0], result[1]];\n },\n\n /**\n * Convert PDF (abstract) coordinates to Screen (CSS pixel) coordinates\n * @param x_pdf - X coordinate in PDF space\n * @param y_pdf - Y coordinate in PDF space\n * @returns [x_screen, y_screen] coordinates in screen space\n */\n to_screen: (x_pdf: number, y_pdf: number): [number, number] => {\n const result = viewport.convertToViewportPoint(x_pdf, y_pdf);\n return [result[0], result[1]];\n },\n };\n}\n\n/**\n * Get viewport dimensions for a page at a specific scale and rotation\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @param rotation - Rotation in degrees (0, 90, 180, 270)\n * @returns Object with width and height in screen pixels\n */\nexport function get_viewport_dimensions(\n page: PDFPageProxy,\n scale: number,\n rotation: number = 0\n): { width: number; height: number } {\n const viewport = page.getViewport({ scale, rotation });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n}\n\n","/**\n * Annotation Overlay Component\n * DOM/SVG layer for handling annotation interactions\n * Positioned above the canvas layer\n */\n\nimport React, { useState, useRef } from 'react';\nimport type { PdfAnnotation, CoordinateMapper, PdfViewerConfig } from '../../types';\nimport {\n calculate_rectangle_coords,\n is_rectangle_too_small,\n} from '../../utils/annotation_utils';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for AnnotationOverlay component\n */\nexport interface AnnotationOverlayProps {\n /** Page dimensions in screen space */\n width: number;\n height: number;\n \n /** Zero-based page index */\n page_index: number;\n \n /** Coordinate mapper for PDF ↔ Screen conversion */\n map_coords: CoordinateMapper;\n \n /** Existing annotations for this page */\n annotations?: PdfAnnotation[];\n \n /** Current annotation tool type */\n current_tool?: 'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null;\n \n /** Callback when annotation is created */\n on_annotation_create?: (annotation: PdfAnnotation) => void;\n \n /** Callback when right-click occurs */\n on_context_menu?: (event: React.MouseEvent, screen_x: number, screen_y: number) => void;\n \n /** Callback when annotation is clicked. screen_x/y are SVG-relative, viewport_x/y are viewport-relative (for positioning fixed dialogs). */\n on_annotation_click?: (annotation: PdfAnnotation, screen_x: number, screen_y: number, viewport_x: number, viewport_y: number) => void;\n\n /** Callback when FreeText tool is active and user clicks on empty area. screen_x/y are SVG-relative, viewport_x/y are viewport-relative. */\n on_freetext_click?: (screen_x: number, screen_y: number, viewport_x: number, viewport_y: number) => void;\n\n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n \n /** Optional class name */\n className?: string;\n}\n\n/**\n * Temporary drawing box component\n * Shows visual feedback while drawing\n */\nconst TempDrawBox: React.FC<{\n start: { x: number; y: number } | null;\n current: { x: number; y: number } | null;\n tool_type?: string;\n config?: PdfViewerConfig | null;\n}> = ({ start, current, tool_type = 'Square', config = null }) => {\n if (!start || !current) return null;\n\n const { x, y, width, height } = calculate_rectangle_coords(start, current);\n\n // Get config values or use defaults\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n\n // Helper to convert hex color to rgba\n const hex_to_rgba = (hex: string, opacity: number): string => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n };\n\n // Determine fill color and opacity based on tool type\n const get_fill_props = () => {\n switch (tool_type) {\n case 'Highlight':\n return {\n fill: hex_to_rgba(highlight_config.highlight_fill_color, highlight_config.highlight_fill_opacity),\n stroke: highlight_config.highlight_border_color,\n };\n case 'Square':\n return {\n fill: hex_to_rgba(square_config.square_fill_color, square_config.square_fill_opacity),\n stroke: square_config.square_border_color,\n };\n default:\n return {\n fill: 'rgba(0, 0, 255, 0.2)',\n stroke: '#0000FF',\n };\n }\n };\n\n const { fill, stroke } = get_fill_props();\n\n return (\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n stroke={stroke}\n strokeWidth=\"2\"\n fill={fill}\n pointerEvents=\"none\"\n />\n );\n};\n\n/**\n * Annotation Overlay Component\n * Handles mouse interactions for creating annotations\n */\nexport const AnnotationOverlay: React.FC<AnnotationOverlayProps> = ({\n width,\n height,\n page_index,\n map_coords,\n annotations = [],\n current_tool = 'Square',\n on_annotation_create,\n on_context_menu,\n on_annotation_click,\n on_freetext_click,\n config = null,\n className = '',\n}) => {\n const logger = get_logger();\n const [is_drawing, setIsDrawing] = useState(false);\n const [start_point, setStartPoint] = useState<{ x: number; y: number } | null>(null);\n const [current_point, setCurrentPoint] = useState<{ x: number; y: number } | null>(null);\n const [hovered_annotation_id, setHoveredAnnotationId] = useState<string | null>(null);\n const svg_ref = useRef<SVGSVGElement>(null);\n\n /**\n * Emit a concise debug log whenever we dispatch an annotation click.\n * This helps confirm left-click routing without flooding the console.\n */\n const log_annotation_click = (\n annotation: PdfAnnotation,\n origin: string,\n point: { x: number; y: number }\n ) => {\n logger.debug('Annotation click dispatched', {\n data: {\n origin,\n id: annotation.id,\n page: annotation.page_index,\n screen_x: point.x.toFixed(1),\n screen_y: point.y.toFixed(1),\n },\n });\n };\n\n // Filter annotations for this page\n const page_annotations = annotations.filter(\n (ann) => ann.page_index === page_index\n );\n\n // Check if a point is inside an annotation\n const is_point_in_annotation = (\n point: { x: number; y: number },\n annotation: PdfAnnotation\n ): boolean => {\n // Convert PDF coordinates to screen coordinates\n const [screen_x1, screen_y1] = map_coords.to_screen(\n annotation.rect[0],\n annotation.rect[1]\n );\n const [screen_x2, screen_y2] = map_coords.to_screen(\n annotation.rect[2],\n annotation.rect[3]\n );\n\n // For FreeText annotations, calculate box dimensions\n if (annotation.type === 'FreeText') {\n const fonts_config = config?.fonts || default_config.fonts;\n const freetext_config = config?.freetext_annotation || default_config.freetext_annotation;\n \n const text = annotation.contents || '';\n if (!text) return false;\n \n const font_size = fonts_config.freetext_font_size_default;\n const padding_h = freetext_config.freetext_padding_horizontal;\n const padding_v = freetext_config.freetext_padding_vertical;\n const text_width_estimate = font_size * 0.6 * text.length;\n const box_width = text_width_estimate + (padding_h * 2);\n const box_height = font_size + (padding_v * 2);\n \n const box_x = screen_x1;\n const box_y = screen_y1;\n \n // Check if point is inside the box\n return (\n point.x >= box_x &&\n point.x <= box_x + box_width &&\n point.y >= box_y &&\n point.y <= box_y + box_height\n );\n }\n \n // For rectangle annotations (Square, Highlight)\n const screen_x = Math.min(screen_x1, screen_x2);\n const screen_y = Math.min(screen_y1, screen_y2);\n const screen_width = Math.abs(screen_x2 - screen_x1);\n const screen_height = Math.abs(screen_y2 - screen_y1);\n \n // Check if point is inside the rectangle\n return (\n point.x >= screen_x &&\n point.x <= screen_x + screen_width &&\n point.y >= screen_y &&\n point.y <= screen_y + screen_height\n );\n };\n\n // Mouse event handlers\n const handle_mouse_down = (e: React.MouseEvent<SVGSVGElement>) => {\n // Only handle left mouse button\n if (e.button !== 0) return;\n\n // Get mouse position relative to SVG\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n\n const point = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n\n // CRITICAL: Check if clicking on an existing annotation FIRST\n // This must happen before any other mode checking (pan/drawing)\n // Annotations should be clickable in ALL modes (pan, Square, Highlight, etc.)\n // Only handle left mouse button - right-click is handled by context menu\n if (e.button === 0 && on_annotation_click) {\n for (const annotation of page_annotations) {\n if (is_point_in_annotation(point, annotation)) {\n \n // Mark event so pan handler knows an annotation was clicked\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'svg_hit_test';\n \n // Stop all event propagation - prevent pan mode and drawing from starting\n e.preventDefault();\n e.stopPropagation();\n e.nativeEvent.stopImmediatePropagation(); // Also stop immediate propagation\n // Call click handler with annotation, screen coordinates, and viewport coordinates\n log_annotation_click(annotation, 'svg_hit_test', point);\n on_annotation_click(annotation, point.x, point.y, e.clientX, e.clientY);\n return;\n }\n }\n } else if (e.button !== 0) {\n // Right-click or other buttons - let context menu handler process it\n return;\n } else if (!on_annotation_click) {\n logger.warn('on_annotation_click not provided');\n }\n\n // In pan mode (current_tool === null), allow panning by not capturing events\n if (!current_tool) {\n // Do not stop propagation; allow parent to handle pan\n return;\n }\n\n // For FreeText tool, open dialog immediately on click (no drag needed)\n if (current_tool === 'FreeText') {\n e.preventDefault();\n e.stopPropagation();\n if (on_freetext_click) {\n on_freetext_click(point.x, point.y, e.clientX, e.clientY);\n }\n return;\n }\n\n setIsDrawing(true);\n setStartPoint(point);\n setCurrentPoint(point);\n };\n\n const handle_mouse_move = (e: React.MouseEvent<SVGSVGElement>) => {\n if (!is_drawing || !start_point) return;\n\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n\n const point = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n\n setCurrentPoint(point);\n };\n\n const handle_mouse_up = (_e: React.MouseEvent<SVGSVGElement>) => {\n if (!is_drawing || !start_point || !current_point) return;\n\n setIsDrawing(false);\n\n // Calculate final rectangle\n const screen_rect = calculate_rectangle_coords(start_point, current_point);\n\n // Ignore tiny clicks/drags\n if (is_rectangle_too_small(screen_rect, 5)) {\n setStartPoint(null);\n setCurrentPoint(null);\n return;\n }\n\n // Convert screen coordinates to PDF coordinates\n const [pdf_x1, pdf_y1] = map_coords.to_pdf(screen_rect.x, screen_rect.y);\n const [pdf_x2, pdf_y2] = map_coords.to_pdf(\n screen_rect.x + screen_rect.width,\n screen_rect.y + screen_rect.height\n );\n\n // Create PDF rect (ensure proper ordering)\n const pdf_rect: [number, number, number, number] = [\n Math.min(pdf_x1, pdf_x2),\n Math.min(pdf_y1, pdf_y2),\n Math.max(pdf_x1, pdf_x2),\n Math.max(pdf_y1, pdf_y2),\n ];\n\n // Get config values for default colors\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n \n // Create new annotation object\n const new_annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: current_tool || 'Square',\n page_index: page_index,\n rect: pdf_rect,\n author: 'User',\n date: new Date().toISOString(),\n contents: '',\n color: current_tool === 'Highlight' ? highlight_config.highlight_fill_color : square_config.square_fill_color,\n };\n\n // Notify parent component\n if (on_annotation_create) {\n on_annotation_create(new_annotation);\n }\n\n // Reset drawing state\n setStartPoint(null);\n setCurrentPoint(null);\n };\n\n const handle_mouse_leave = () => {\n // Stop drawing if mouse leaves the overlay\n if (is_drawing) {\n setIsDrawing(false);\n setStartPoint(null);\n setCurrentPoint(null);\n }\n };\n\n // Handle context menu (right-click)\n const handle_context_menu = (e: React.MouseEvent<SVGSVGElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Get mouse position relative to SVG\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) {\n logger.warn('Could not get SVG bounding rect');\n return;\n }\n \n if (!on_context_menu) {\n logger.warn('on_context_menu callback not provided');\n return;\n }\n\n const screen_x = e.clientX - rect.left;\n const screen_y = e.clientY - rect.top;\n\n // Call parent handler with event and screen coordinates\n on_context_menu(e, screen_x, screen_y);\n };\n\n // Render existing annotations\n const render_annotation = (annotation: PdfAnnotation) => {\n // Convert PDF coordinates to screen coordinates\n // annotation.rect format: [x1, y1, x2, y2] where (x1, y1) is top-left, (x2, y2) is bottom-right\n // In PDF coordinates: origin (0,0) is at bottom-left, Y increases upward\n // In screen coordinates: origin (0,0) is at top-left, Y increases downward\n const [screen_x1, screen_y1] = map_coords.to_screen(\n annotation.rect[0], // Top-left X in PDF space\n annotation.rect[1] // Top-left Y in PDF space\n );\n const [screen_x2, screen_y2] = map_coords.to_screen(\n annotation.rect[2], // Bottom-right X in PDF space\n annotation.rect[3] // Bottom-right Y in PDF space\n );\n\n // For rectangle annotations (Square, Highlight), calculate normalized screen coordinates\n // Math.min ensures we always get the top-left corner, regardless of how rect was stored\n const screen_x = Math.min(screen_x1, screen_x2);\n const screen_y = Math.min(screen_y1, screen_y2);\n const screen_width = Math.abs(screen_x2 - screen_x1);\n const screen_height = Math.abs(screen_y2 - screen_y1);\n \n // Get config values or use defaults\n const fonts_config = config?.fonts || default_config.fonts;\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n const freetext_config = config?.freetext_annotation || default_config.freetext_annotation;\n \n // Helper to convert hex color to rgba\n const hex_to_rgba = (hex: string, opacity: number): string => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n };\n\n // ============================================================================\n // FreeText Annotation Rendering\n // ============================================================================\n // \n // FreeText annotations differ from rectangle annotations (Square, Highlight) because:\n // 1. The annotation rect serves as a POSITION MARKER only (rect[0], rect[1] = click position)\n // 2. Box dimensions are calculated dynamically from text content + padding\n // 3. Positioning MUST use screen_x1/y1 directly, NOT Math.min()\n //\n // See detailed comments below for why Math.min() breaks positioning.\n //\n if (annotation.type === 'FreeText') {\n const text = annotation.contents || '';\n if (!text) return null; // Don't render if no text\n\n // Parse stamp styling from subject field if present\n let stamp_styling: any = null;\n if (annotation.subject) {\n try {\n const parsed = JSON.parse(annotation.subject);\n if (parsed && parsed.stamp_name) {\n stamp_styling = parsed;\n }\n } catch (e) {\n // Not JSON, ignore\n }\n }\n \n // Calculate font size - use stamp font_size if provided, otherwise config default\n const font_size = stamp_styling?.font_size !== undefined \n ? stamp_styling.font_size \n : fonts_config.freetext_font_size_default;\n \n // Text color priority: stamp font_color > annotation.color > freetext_text_color (if not default) > font_foreground_color > default black\n const text_color = stamp_styling?.font_color ||\n annotation.color || \n (freetext_config.freetext_text_color && freetext_config.freetext_text_color !== '#000000'\n ? freetext_config.freetext_text_color\n : fonts_config.font_foreground_color) ||\n '#000000';\n \n // Get font family - use stamp font_name if provided, otherwise config\n const font_family = stamp_styling?.font_name || fonts_config.freetext_font_family;\n \n // Get font weight - use stamp font_weight if provided, otherwise config\n const font_weight = stamp_styling?.font_weight !== undefined\n ? stamp_styling.font_weight\n : freetext_config.freetext_font_weight;\n \n // Get font style - use stamp font_style if provided, otherwise config\n const font_style = stamp_styling?.font_style !== undefined\n ? stamp_styling.font_style\n : freetext_config.freetext_font_style;\n \n // Get padding values\n const padding_h = freetext_config.freetext_padding_horizontal;\n const padding_v = freetext_config.freetext_padding_vertical;\n \n // Split text by newlines to calculate dimensions for multi-line text\n const text_lines = text.split('\\n');\n const max_line_length = Math.max(...text_lines.map(line => line.length), 1);\n \n // Measure text width - estimate based on font size and longest line length\n // Average character is about 0.6 * font_size wide for most fonts\n const text_width_estimate = font_size * 0.6 * max_line_length;\n \n // Calculate box dimensions based on text width + padding\n // Height needs to account for multiple lines (line height = font_size)\n const box_width = text_width_estimate + (padding_h * 2);\n const box_height = (font_size * text_lines.length) + (padding_v * 2);\n \n // ⚠️ CRITICAL FIX: Position must use screen_x1/screen_y1 DIRECTLY, not Math.min!\n //\n // WHY THIS MATTERS:\n // For FreeText annotations, annotation.rect[0] and annotation.rect[1] represent the EXACT\n // click position in PDF space (where the user right-clicked). When we convert these to\n // screen coordinates, we get screen_x1 and screen_y1, which is the exact click position.\n //\n // The annotation rect also has placeholder dimensions (rect[2], rect[3]) representing a\n // minimal placeholder box. When converted to screen coordinates, these become screen_x2/y2.\n //\n // COORDINATE SYSTEM DIFFERENCE:\n // - PDF coordinates: Y=0 at bottom, Y increases upward\n // - Screen coordinates: Y=0 at top, Y increases downward\n // Because of this difference, when converting the placeholder bottom-right:\n // - screen_y2 will be SMALLER than screen_y1 (higher on screen = lower Y value)\n // - Using Math.min(screen_y1, screen_y2) would incorrectly select screen_y2\n // - This creates an offset equal to the placeholder height, misaligning the border\n //\n // SOLUTION:\n // Always use screen_x1 and screen_y1 directly for FreeText annotations. These represent\n // the converted coordinates of annotation.rect[0]/rect[1], which is the exact click position.\n // Do NOT use Math.min() here - it will break positioning due to coordinate system differences.\n //\n // NOTE: For rectangle annotations (Square, Highlight), we DO use Math.min because those\n // annotations have actual meaningful dimensions, not placeholders.\n const box_x = screen_x1;\n const box_y = screen_y1;\n \n // Text position: add padding offset from box top-left\n const text_x = box_x + padding_h;\n const text_y = box_y + padding_v + font_size; // Y is baseline, so add padding_v + font_size\n \n // Determine if we need a background or border\n // Use stamp styling if provided, otherwise use config\n const border_size = stamp_styling?.border_size !== undefined\n ? stamp_styling.border_size\n : freetext_config.freetext_border_width;\n \n // Border color: use config border color (stamp doesn't define border color, only size)\n const border_color_trimmed = freetext_config.freetext_border_color?.trim() || '';\n const has_border = border_size > 0 && border_color_trimmed !== '';\n \n // Background color: use stamp background_color if provided, otherwise config\n const background_color_trimmed = (stamp_styling?.background_color !== undefined\n ? String(stamp_styling.background_color)\n : freetext_config.freetext_background_color)?.trim() || '';\n const has_background = background_color_trimmed !== '';\n \n // Helper to convert hex/rgb to rgba for background\n // Supports both hex (#RRGGBB) and rgb(r, g, b) formats\n const hex_to_rgba_bg = (color_str: string, opacity: number): string => {\n if (!color_str || color_str === '') return 'transparent';\n \n // Trim whitespace from color string\n const trimmed = color_str.trim();\n \n // Handle rgb(r, g, b) format - case insensitive and flexible spacing\n // Matches: rgb(0, 54, 105), rgb(0,54,105), RGB(0, 54, 105), etc.\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = trimmed.match(rgb_pattern);\n if (rgb_match) {\n const r = parseInt(rgb_match[1], 10);\n const g = parseInt(rgb_match[2], 10);\n const b = parseInt(rgb_match[3], 10);\n // Validate RGB values (0-255)\n if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n }\n logger.warn('Invalid RGB values (must be 0-255)', { data: { r, g, b } });\n return 'transparent';\n }\n \n // Handle hex format (#RRGGBB)\n if (trimmed.startsWith('#')) {\n const hex = trimmed.slice(1).trim(); // Remove # and trim\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n }\n logger.warn('Invalid hex color format', { data: { color: trimmed } });\n return 'transparent';\n }\n \n logger.warn('Unrecognized color format', { data: { color: trimmed } });\n return 'transparent';\n };\n\n return (\n <g key={annotation.id}>\n {/* Background rectangle (if configured) */}\n {has_background && (\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill={hex_to_rgba_bg(background_color_trimmed, freetext_config.freetext_background_opacity)}\n pointerEvents=\"none\"\n />\n )}\n \n {/* Border rectangle (if configured) */}\n {has_border && (\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill=\"none\"\n stroke={border_color_trimmed}\n strokeWidth={border_size}\n pointerEvents=\"none\"\n />\n )}\n \n {/* Clickable overlay for FreeText annotations */}\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill=\"transparent\"\n stroke=\"none\"\n pointerEvents=\"auto\"\n style={{ cursor: 'pointer' }}\n onMouseEnter={() => {\n setHoveredAnnotationId(annotation.id);\n // Change SVG cursor when hovering over annotation\n if (svg_ref.current) {\n svg_ref.current.style.cursor = 'pointer';\n }\n }}\n onMouseLeave={() => {\n setHoveredAnnotationId(null);\n // Restore SVG cursor when leaving annotation\n if (svg_ref.current) {\n if (current_tool === null) {\n svg_ref.current.style.cursor = 'inherit';\n } else {\n svg_ref.current.style.cursor = current_tool ? 'crosshair' : 'default';\n }\n }\n }}\n onMouseDown={(e) => {\n // This handler is now the primary click detector for annotations\n if (e.button !== 0) return; // Only handle left-click\n // Mark native event for upstream listeners\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'freetext_rect';\n e.stopPropagation(); // Stop event from bubbling to the SVG's onMouseDown\n e.nativeEvent.stopImmediatePropagation();\n\n if (on_annotation_click) {\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n const click_x = e.clientX - rect.left;\n const click_y = e.clientY - rect.top;\n log_annotation_click(annotation, 'freetext_rect', { x: click_x, y: click_y });\n on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);\n }\n }}\n onClick={(e) => {\n // Also handle onClick as backup\n e.preventDefault();\n e.stopPropagation();\n }}\n />\n \n {/* Text content - positioned with padding (always rendered, even if no border/background) */}\n {/* Split text by newlines and render each line separately to support multi-line text (e.g., timestamp) */}\n <text\n x={text_x}\n y={text_y} // Y coordinate is baseline for text in SVG\n fontSize={font_size}\n fill={text_color}\n pointerEvents=\"none\"\n style={{\n fontFamily: font_family,\n fontWeight: font_weight,\n fontStyle: font_style,\n textDecoration: freetext_config.freetext_text_decoration,\n userSelect: 'none',\n }}\n >\n {text.split('\\n').map((line, line_index) => (\n <tspan\n key={line_index}\n x={text_x}\n dy={line_index === 0 ? 0 : font_size} // First line at y position, subsequent lines below\n >\n {line}\n </tspan>\n ))}\n </text>\n </g>\n );\n }\n\n // Get fill properties based on annotation type for rectangle annotations\n const get_annotation_props = () => {\n switch (annotation.type) {\n case 'Highlight': {\n // Check for custom options in subject field (from API highlight_region)\n let custom_highlight_options: {\n border_color?: string;\n background_color?: string;\n background_opacity?: number;\n border_width?: number;\n } | null = null;\n\n if (annotation.subject) {\n try {\n custom_highlight_options = JSON.parse(annotation.subject);\n } catch {\n // Not JSON, ignore\n }\n }\n\n // Use custom colors if provided, then annotation color, then config defaults\n const highlight_fill_color = custom_highlight_options?.background_color ||\n annotation.color ||\n highlight_config.highlight_fill_color;\n const highlight_fill_opacity = custom_highlight_options?.background_opacity ??\n highlight_config.highlight_fill_opacity;\n const highlight_border_color = custom_highlight_options?.border_color ||\n highlight_config.highlight_border_color;\n const highlight_border_width = custom_highlight_options?.border_width ?? 2;\n\n return {\n fill: hex_to_rgba(highlight_fill_color, highlight_fill_opacity),\n stroke: highlight_border_color,\n strokeWidth: highlight_border_width,\n };\n }\n case 'Square': {\n // Use annotation color if provided, otherwise use config\n const square_color = annotation.color || square_config.square_fill_color;\n return {\n fill: hex_to_rgba(square_color, square_config.square_fill_opacity),\n stroke: square_config.square_border_color,\n strokeWidth: 2,\n };\n }\n default:\n return {\n fill: 'rgba(0, 0, 255, 0.2)',\n stroke: '#0000FF',\n strokeWidth: 2,\n };\n }\n };\n\n const { fill, stroke, strokeWidth } = get_annotation_props();\n\n return (\n <g key={annotation.id}>\n {/* Clickable overlay for rectangle annotations */}\n <rect\n x={screen_x}\n y={screen_y}\n width={screen_width}\n height={screen_height}\n fill=\"transparent\"\n stroke=\"none\"\n pointerEvents=\"auto\"\n style={{ cursor: 'pointer' }}\n onMouseEnter={() => {\n setHoveredAnnotationId(annotation.id);\n // Change SVG cursor when hovering over annotation\n if (svg_ref.current) {\n svg_ref.current.style.cursor = 'pointer';\n }\n }}\n onMouseLeave={() => {\n setHoveredAnnotationId(null);\n // Restore SVG cursor when leaving annotation\n if (svg_ref.current) {\n if (current_tool === null) {\n svg_ref.current.style.cursor = 'inherit';\n } else {\n svg_ref.current.style.cursor = current_tool ? 'crosshair' : 'default';\n }\n }\n }}\n onMouseDown={(e) => {\n // This handler is now the primary click detector for annotations\n if (e.button !== 0) return; // Only handle left-click\n // Mark native event for upstream listeners\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'rect_overlay';\n e.stopPropagation(); // Stop event from bubbling to the SVG's onMouseDown\n e.nativeEvent.stopImmediatePropagation();\n\n if (on_annotation_click) {\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n const click_x = e.clientX - rect.left;\n const click_y = e.clientY - rect.top;\n log_annotation_click(annotation, 'rect_overlay', { x: click_x, y: click_y });\n on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);\n }\n }}\n onClick={(e) => {\n // Also handle onClick as backup\n e.preventDefault();\n e.stopPropagation();\n }}\n />\n {/* Visual annotation rectangle */}\n <rect\n x={screen_x}\n y={screen_y}\n width={screen_width}\n height={screen_height}\n stroke={stroke}\n strokeWidth={strokeWidth}\n fill={fill}\n pointerEvents=\"none\"\n />\n </g>\n );\n };\n\n return (\n <svg\n ref={svg_ref}\n className={cn('cls_annotation_overlay', className)}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: width,\n height: height,\n // Cursor will be dynamically updated by onMouseEnter/Leave on annotations\n // Default: In pan mode, inherit cursor from parent (grab/grabbing)\n // In annotation mode, show crosshair\n cursor: hovered_annotation_id \n ? 'pointer' \n : (current_tool === null ? 'inherit' : (current_tool ? 'crosshair' : 'default')),\n // Always allow pointer events so context menu (right-click) and annotation clicks work\n // Left-click panning is handled by returning early in handle_mouse_down\n pointerEvents: 'auto',\n zIndex: 10, // Ensure annotations are above the canvas but below dialogs\n }}\n width={width}\n height={height}\n onMouseDown={handle_mouse_down}\n onMouseMove={handle_mouse_move}\n onMouseUp={handle_mouse_up}\n onMouseLeave={() => {\n // Reset hover state when mouse leaves SVG entirely\n setHoveredAnnotationId(null);\n handle_mouse_leave();\n }}\n onContextMenu={handle_context_menu}\n >\n {/* Render existing annotations */}\n {page_annotations.map(render_annotation)}\n\n {/* Render temporary drawing box */}\n {is_drawing && (\n <TempDrawBox\n start={start_point}\n current={current_point}\n tool_type={current_tool || 'Square'}\n config={config}\n />\n )}\n </svg>\n );\n};\n\nexport default AnnotationOverlay;\n\n","/**\n * Annotation Utility Functions\n * Helper functions for annotation calculations and transformations\n */\n\n/**\n * Point coordinates\n */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/**\n * Rectangle coordinates (normalized)\n */\nexport interface Rectangle {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Calculates a normalized rectangle bounding box (x, y, width, height)\n * given any two diagonal points\n * @param p1 - First point\n * @param p2 - Second point\n * @returns Normalized rectangle with top-left origin\n */\nexport function calculate_rectangle_coords(\n p1: Point,\n p2: Point\n): Rectangle {\n const x = Math.min(p1.x, p2.x);\n const y = Math.min(p1.y, p2.y);\n const width = Math.abs(p1.x - p2.x);\n const height = Math.abs(p1.y - p2.y);\n \n return { x, y, width, height };\n}\n\n/**\n * Convert rectangle to PDF rect format [x1, y1, x2, y2]\n * @param rect - Rectangle with x, y, width, height\n * @returns PDF rect array [x1, y1, x2, y2]\n */\nexport function rectangle_to_pdf_rect(rect: Rectangle): [number, number, number, number] {\n return [\n rect.x,\n rect.y,\n rect.x + rect.width,\n rect.y + rect.height,\n ];\n}\n\n/**\n * Convert PDF rect format [x1, y1, x2, y2] to rectangle\n * @param pdf_rect - PDF rect array [x1, y1, x2, y2]\n * @returns Rectangle with x, y, width, height\n */\nexport function pdf_rect_to_rectangle(\n pdf_rect: [number, number, number, number]\n): Rectangle {\n const [x1, y1, x2, y2] = pdf_rect;\n return {\n x: Math.min(x1, x2),\n y: Math.min(y1, y2),\n width: Math.abs(x2 - x1),\n height: Math.abs(y2 - y1),\n };\n}\n\n/**\n * Check if a rectangle is too small (likely a click, not a drag)\n * @param rect - Rectangle to check\n * @param min_size - Minimum size in pixels (default: 5)\n * @returns True if rectangle is too small\n */\nexport function is_rectangle_too_small(\n rect: Rectangle,\n min_size: number = 5\n): boolean {\n return rect.width < min_size || rect.height < min_size;\n}\n\n","/**\n * Context Menu Component\n * Displays a context menu on right-click\n */\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Undo2, FileText } from 'lucide-react';\nimport type { PdfViewerConfig, CustomStamp } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for ContextMenu component\n */\nexport interface ContextMenuProps {\n /** X position of the menu */\n x: number;\n \n /** Y position of the menu */\n y: number;\n \n /** Whether undo is available */\n can_undo?: boolean;\n \n /** Callback when undo is clicked */\n on_undo?: () => void;\n \n /** Callback when annotate is clicked */\n on_annotate?: () => void;\n \n /** Callback to close the menu */\n on_close?: () => void;\n \n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n \n /** Custom stamps for right-click menu */\n custom_stamps?: CustomStamp[];\n \n /** Callback when a custom stamp is clicked */\n on_stamp_click?: (stamp: CustomStamp) => void;\n}\n\n/**\n * Context Menu Component\n * Displays a menu with undo and annotate options\n */\nexport const ContextMenu: React.FC<ContextMenuProps> = ({\n x,\n y,\n can_undo = false,\n on_undo,\n on_annotate,\n on_close,\n config = null,\n custom_stamps = [],\n on_stamp_click,\n}) => {\n const logger = get_logger();\n const menu_ref = useRef<HTMLDivElement>(null);\n const render_count_ref = useRef(0);\n const [adjusted_position, setAdjustedPosition] = useState({ x, y });\n const props_received_time_ref = useRef(performance.now());\n const [mounted, setMounted] = useState(false);\n\n // Ensure we're mounted (client-side only) before creating portal\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n // Track when props change\n useEffect(() => {\n props_received_time_ref.current = performance.now();\n }, [x, y]);\n\n // Adjust position once we know the menu's dimensions\n useEffect(() => {\n render_count_ref.current += 1;\n \n if (menu_ref.current && mounted) {\n const rect = menu_ref.current.getBoundingClientRect();\n \n // Calculate the actual position (accounting for any transforms or offsets)\n const actual_x = x;\n const actual_y = y;\n \n // Get parent elements for hierarchy debugging\n const menu_element = menu_ref.current;\n \n // Walk up the DOM to find all positioned ancestors\n const positioned_ancestors: Array<{ element: Element; boundingRect: DOMRect; computedStyle: CSSStyleDeclaration }> = [];\n let current: Element | null = menu_element.parentElement;\n while (current && current !== document.body && current !== document.documentElement) {\n const style = window.getComputedStyle(current);\n const position = style.position;\n if (position === 'fixed' || position === 'absolute' || position === 'relative' || position === 'sticky') {\n positioned_ancestors.push({\n element: current,\n boundingRect: current.getBoundingClientRect(),\n computedStyle: style,\n });\n }\n current = current.parentElement;\n }\n\n // Check for transforms in ancestors\n const parent_transforms: Array<{ element: Element; transform: string }> = [];\n let check: Element | null = menu_element.parentElement;\n while (check && check !== document.body) {\n const style = window.getComputedStyle(check);\n const transform = style.transform;\n if (transform && transform !== 'none') {\n parent_transforms.push({\n element: check,\n transform: transform,\n });\n }\n check = check.parentElement;\n }\n \n const x_offset = rect.left - x;\n const y_offset = rect.top - y;\n const position_correct = Math.abs(x_offset) < 1 && Math.abs(y_offset) < 1;\n const parent_transform_count = parent_transforms.length;\n const positioned_ancestor_count = positioned_ancestors.length;\n \n logger.debug('ContextMenu position debug', { data: { render: render_count_ref.current, expected_x: x, expected_y: y, actual_x: Number(rect.left.toFixed(1)), actual_y: Number(rect.top.toFixed(1)), x_offset: Number(x_offset.toFixed(1)), y_offset: Number(y_offset.toFixed(1)), correct: position_correct, ancestors: positioned_ancestor_count, transforms: parent_transform_count } });\n\n // Offset adjustment - currently disabled (set to zero)\n // If bottom-left is at mouse, adjust so top-left is at mouse\n // Check if bottom-left is close to mouse position (within 5px tolerance)\n const bottom_left_x = rect.left;\n const bottom_left_y = rect.bottom;\n const tolerance = 5;\n const offset_x = 0; // Offset disabled for now\n const offset_y = 0; // Offset disabled for now\n \n if (Math.abs(bottom_left_x - x) < tolerance && Math.abs(bottom_left_y - y) < tolerance) {\n logger.debug('ContextMenu detected bottom-left positioning, adjusting to top-left');\n // Menu height is already known, adjust Y upward\n setAdjustedPosition({\n x: actual_x + offset_x,\n y: actual_y + offset_y - rect.height,\n });\n } else {\n // Use original position with offset (currently zero)\n setAdjustedPosition({ \n x: actual_x + offset_x, \n y: actual_y + offset_y \n });\n }\n }\n }, [x, y, mounted]);\n\n const handle_item_click = (callback?: () => void) => {\n if (callback) {\n callback();\n }\n if (on_close) {\n on_close();\n }\n };\n\n logger.debug('ContextMenu render call', { data: { render: render_count_ref.current, props_x: x, props_y: y, adjusted_x: adjusted_position.x, adjusted_y: adjusted_position.y, mounted } });\n\n // Don't render until mounted (to avoid SSR issues)\n if (!mounted) {\n return null;\n }\n\n // Handle mouse leave - close menu when mouse moves away\n const handle_mouse_leave = () => {\n if (on_close) {\n on_close();\n }\n };\n\n // Get config values or use defaults\n const menu_config = config?.context_menu || default_config.context_menu;\n \n // Render menu content\n const menu_content = (\n <div\n ref={menu_ref}\n className=\"cls_pdf_viewer_context_menu\"\n style={{\n position: 'fixed',\n left: `${adjusted_position.x}px`,\n top: `${adjusted_position.y}px`,\n zIndex: 10000,\n backgroundColor: menu_config.context_menu_background_color,\n borderColor: menu_config.context_menu_border_color,\n }}\n onClick={(e) => e.stopPropagation()}\n onContextMenu={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n onMouseLeave={handle_mouse_leave}\n >\n <div className=\"cls_pdf_viewer_context_menu_items\">\n {/* Undo option */}\n <button\n type=\"button\"\n onClick={() => handle_item_click(on_undo)}\n disabled={!can_undo}\n className={cn(\n 'cls_pdf_viewer_context_menu_item',\n !can_undo && 'cls_pdf_viewer_context_menu_item_disabled'\n )}\n style={{\n opacity: !can_undo ? menu_config.context_menu_item_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (can_undo) {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label=\"Undo\"\n >\n <Undo2 className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">Undo</span>\n </button>\n\n {/* Annotate option */}\n <button\n type=\"button\"\n onClick={() => handle_item_click(on_annotate)}\n className=\"cls_pdf_viewer_context_menu_item\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label=\"Annotate\"\n >\n <FileText className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">Annotate</span>\n </button>\n\n {/* Custom stamps - sorted by order, displayed at bottom */}\n {custom_stamps.length > 0 && (\n <>\n {/* Separator line before custom stamps */}\n <div\n style={{\n height: '1px',\n backgroundColor: menu_config.context_menu_border_color,\n margin: '4px 0',\n }}\n />\n {/* Custom stamp items - sorted by order */}\n {[...custom_stamps]\n .sort((a, b) => a.order - b.order)\n .map((stamp, index) => (\n <button\n key={`${stamp.name}-${index}`}\n type=\"button\"\n onClick={() => {\n if (on_stamp_click) {\n on_stamp_click(stamp);\n }\n if (on_close) {\n on_close();\n }\n }}\n className=\"cls_pdf_viewer_context_menu_item\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label={stamp.name}\n >\n <FileText className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">{stamp.name}</span>\n </button>\n ))}\n </>\n )}\n </div>\n </div>\n );\n\n // CRITICAL: Use portal to render at document.body level to escape any containing blocks\n // This ensures position: fixed works relative to viewport, not Storybook containers\n return createPortal(menu_content, document.body);\n};\n\nexport default ContextMenu;\n\n","/**\n * Text Annotation Dialog Component\n * Dialog for entering text annotation\n */\n\nimport React, { useState, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Check, X, Trash2 } from 'lucide-react';\nimport type { PdfViewerConfig } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for TextAnnotationDialog component\n */\nexport interface TextAnnotationDialogProps {\n /** Whether the dialog is open */\n open: boolean;\n \n /** X position of the dialog (viewport coordinates) */\n x: number;\n \n /** Y position of the dialog (viewport coordinates) */\n y: number;\n \n /** Callback when dialog is closed */\n on_close: () => void;\n \n /** Callback when text is submitted */\n on_submit: (text: string) => void;\n \n /** Callback when annotation is deleted (only used in edit mode) */\n on_delete?: () => void;\n \n /** Initial text value */\n initial_text?: string;\n \n /** Whether this is editing an existing annotation (shows delete button) */\n is_editing?: boolean;\n \n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n}\n\n/**\n * Text Annotation Dialog Component\n * Slim inline dialog for entering text annotation\n */\nexport const TextAnnotationDialog: React.FC<TextAnnotationDialogProps> = ({\n open,\n x,\n y,\n on_close,\n on_submit,\n on_delete,\n initial_text = '',\n is_editing = false,\n config = null,\n}) => {\n const [text, setText] = useState(initial_text);\n const input_ref = useRef<HTMLInputElement>(null);\n const [mounted, setMounted] = useState(false);\n\n // Ensure we're mounted (client-side only) before creating portal\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n // Reset text when dialog opens/closes\n useEffect(() => {\n if (open) {\n setText(initial_text);\n // Focus input when dialog opens\n setTimeout(() => {\n input_ref.current?.focus();\n input_ref.current?.select();\n }, 0);\n }\n }, [open, initial_text]);\n\n // Handle submit\n const handle_submit = (e?: React.FormEvent) => {\n if (e) {\n e.preventDefault();\n }\n if (text.trim()) {\n on_submit(text.trim());\n setText('');\n on_close();\n }\n };\n\n // Handle cancel\n const handle_cancel = () => {\n setText('');\n on_close();\n };\n\n // Handle delete\n const handle_delete = () => {\n if (on_delete) {\n on_delete();\n setText('');\n on_close();\n }\n };\n\n // Handle keyboard events\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n if (!open) return;\n \n if (e.key === 'Escape') {\n e.preventDefault();\n handle_cancel();\n } else if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handle_submit();\n }\n };\n\n if (open) {\n window.addEventListener('keydown', handle_keydown);\n return () => {\n window.removeEventListener('keydown', handle_keydown);\n };\n }\n return undefined;\n }, [open, text]);\n\n if (!open || !mounted) {\n return null;\n }\n\n // Get config values or use defaults\n const dialog_config = config?.dialog || default_config.dialog;\n\n // Render dialog content\n const dialog_content = (\n <>\n {/* Backdrop */}\n <div\n className=\"cls_pdf_viewer_dialog_backdrop\"\n onClick={handle_cancel}\n aria-hidden=\"true\"\n style={{\n backgroundColor: `rgba(0, 0, 0, ${dialog_config.dialog_backdrop_opacity})`,\n }}\n />\n\n {/* Slim Dialog - positioned at x, y coordinates */}\n <div\n className=\"cls_pdf_viewer_text_dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n style={{\n position: 'fixed',\n left: `${x}px`,\n top: `${y}px`,\n zIndex: 10001, // Higher than context menu\n backgroundColor: dialog_config.dialog_background_color,\n borderColor: dialog_config.dialog_border_color,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <form onSubmit={handle_submit} className=\"cls_pdf_viewer_dialog_form\">\n <input\n ref={input_ref}\n type=\"text\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n className=\"cls_pdf_viewer_dialog_input\"\n placeholder=\"Enter annotation text...\"\n autoFocus\n />\n <div className=\"cls_pdf_viewer_dialog_buttons\">\n {/* Delete button - only shown when editing */}\n {is_editing && on_delete && (\n <button\n type=\"button\"\n onClick={handle_delete}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_delete'\n )}\n style={{\n color: dialog_config.dialog_button_cancel_color,\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color_hover;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color;\n }}\n aria-label=\"Delete annotation\"\n title=\"Delete annotation\"\n >\n <Trash2 size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={handle_cancel}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_cancel'\n )}\n style={{\n color: dialog_config.dialog_button_cancel_color,\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color_hover;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color;\n }}\n aria-label=\"Cancel\"\n title=\"Cancel (Esc)\"\n >\n <X size={14} />\n </button>\n <button\n type=\"submit\"\n disabled={!text.trim()}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_submit',\n !text.trim() && 'cls_pdf_viewer_dialog_button_disabled'\n )}\n style={{\n color: !text.trim() ? undefined : dialog_config.dialog_button_submit_color,\n opacity: !text.trim() ? dialog_config.dialog_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (text.trim()) {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_submit_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (text.trim()) {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_submit_color;\n }\n }}\n aria-label=\"Submit\"\n title=\"Submit (Enter)\"\n >\n <Check size={14} />\n </button>\n </div>\n </form>\n </div>\n </>\n );\n\n // Use portal to render at document.body level to escape any containing blocks\n return createPortal(dialog_content, document.body);\n};\n\nexport default TextAnnotationDialog;\n\n","/**\n * Metadata Sidepanel Component\n * Displays JSON metadata with header, data (accordions), and footer sections\n * Supports editable fields with inline editing\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Pencil, CheckCircle2, X } from 'lucide-react';\nimport type { MetadataInput, MetadataDataItem } from '../../types';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for MetadataSidepanel component\n */\nexport interface MetadataSidepanelProps {\n /** Whether the panel is open */\n is_open: boolean;\n /** Callback to toggle panel open/closed */\n on_toggle: () => void;\n /** Metadata input structure */\n metadata: MetadataInput;\n /** Callback when metadata is changed via editing */\n on_change: (updatedRow: MetadataDataItem, allData: MetadataInput) => { updatedRow: MetadataDataItem; allData: MetadataInput };\n /** Current width of the panel */\n width: number;\n /** Callback when panel width changes */\n on_width_change: (width: number) => void;\n}\n\n/**\n * Format text component based on style type\n */\nconst FormatText: React.FC<{ style: string; children: React.ReactNode; className?: string }> = ({ style, children, className }) => {\n const baseClassName = cn('cls_metadata_text', className);\n \n switch (style) {\n case 'h1':\n return <h1 className={cn(baseClassName, 'cls_metadata_h1')}>{children}</h1>;\n case 'h2':\n return <h2 className={cn(baseClassName, 'cls_metadata_h2')}>{children}</h2>;\n case 'h3':\n return <h3 className={cn(baseClassName, 'cls_metadata_h3')}>{children}</h3>;\n case 'h4':\n return <h4 className={cn(baseClassName, 'cls_metadata_h4')}>{children}</h4>;\n case 'h5':\n return <h5 className={cn(baseClassName, 'cls_metadata_h5')}>{children}</h5>;\n case 'body':\n default:\n return <p className={cn(baseClassName, 'cls_metadata_body')}>{children}</p>;\n }\n};\n\n/**\n * Metadata Sidepanel Component\n */\nexport const MetadataSidepanel: React.FC<MetadataSidepanelProps> = ({\n is_open,\n on_toggle,\n metadata,\n on_change,\n width,\n on_width_change,\n}) => {\n const [expanded_items, setExpandedItems] = useState<Set<number>>(new Set());\n const [editing_index, setEditingIndex] = useState<number | null>(null);\n const [edit_value, setEditValue] = useState<string>('');\n const resize_ref = useRef<HTMLDivElement>(null);\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Toggle accordion item expanded/collapsed\n const toggle_item = (index: number) => {\n setExpandedItems(prev => {\n const next = new Set(prev);\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n return next;\n });\n };\n\n // Start editing a field\n const start_edit = (index: number, current_value: string) => {\n setEditingIndex(index);\n setEditValue(current_value);\n };\n\n // Cancel editing\n const cancel_edit = () => {\n setEditingIndex(null);\n setEditValue('');\n };\n\n // Save edited value\n const save_edit = () => {\n if (editing_index === null) return;\n\n const updated_data = [...metadata.data];\n const updated_row = { ...updated_data[editing_index], value: edit_value };\n updated_data[editing_index] = updated_row;\n\n const updated_metadata: MetadataInput = {\n header: metadata.header,\n data: updated_data,\n footer: metadata.footer,\n };\n\n const result = on_change(updated_row, updated_metadata);\n setEditingIndex(null);\n setEditValue('');\n };\n\n // Handle resize start\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 // Handle resize move\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n \n const delta_x = start_x_ref.current - e.clientX; // Reverse because we're resizing from left\n const new_width = Math.max(200, Math.min(800, start_width_ref.current + delta_x));\n on_width_change(new_width);\n };\n\n // Handle resize end\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 resize listeners 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 return (\n <>\n {/* Toggle button on right edge when closed */}\n {!is_open && (\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_metadata_sidepanel_toggle_edge\"\n aria-label=\"Open metadata panel\"\n title=\"Open metadata panel\"\n >\n <ChevronLeft size={20} />\n </button>\n )}\n\n {/* Sidepanel */}\n <div\n className={cn('cls_metadata_sidepanel', is_open && 'cls_metadata_sidepanel_open')}\n style={{ width: is_open ? `${width}px` : '0', display: is_open ? 'flex' : 'none' }}\n >\n {/* Resize handle */}\n {is_open && (\n <div\n ref={resize_ref}\n className=\"cls_metadata_sidepanel_resize_handle\"\n onMouseDown={handle_resize_start}\n aria-label=\"Resize panel\"\n />\n )}\n\n {/* Panel content */}\n <div className=\"cls_metadata_sidepanel_content\">\n {/* Header with close button */}\n <div className=\"cls_metadata_sidepanel_header\">\n <span className=\"cls_metadata_sidepanel_title\">Metadata</span>\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_metadata_sidepanel_close\"\n aria-label=\"Close metadata panel\"\n >\n <ChevronRight size={20} />\n </button>\n </div>\n\n {/* Scrollable content area */}\n <div className=\"cls_metadata_sidepanel_body\">\n {/* Header section */}\n {metadata.header && metadata.header.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_header_section\">\n {metadata.header.map((item, index) => (\n <FormatText key={`header-${index}`} style={item.style}>\n {item.label}\n </FormatText>\n ))}\n </div>\n )}\n\n {/* Data section (accordions) */}\n {metadata.data && metadata.data.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_data_section\">\n {metadata.data.map((item, index) => {\n const is_expanded = expanded_items.has(index);\n const is_editing = editing_index === index;\n\n return (\n <div key={`data-${index}`} className=\"cls_metadata_accordion\">\n {/* Accordion header */}\n <button\n type=\"button\"\n onClick={() => toggle_item(index)}\n className=\"cls_metadata_accordion_header\"\n aria-expanded={is_expanded}\n >\n <FormatText style={item.style} className=\"cls_metadata_accordion_label\">\n {item.label}\n </FormatText>\n {is_expanded ? (\n <ChevronUp className=\"cls_metadata_accordion_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_metadata_accordion_icon\" size={16} />\n )}\n </button>\n\n {/* Accordion content */}\n {is_expanded && (\n <div className=\"cls_metadata_accordion_content\">\n {is_editing ? (\n <div className=\"cls_metadata_edit_mode\">\n <input\n type=\"text\"\n value={edit_value}\n onChange={(e) => setEditValue(e.target.value)}\n className=\"cls_metadata_edit_input\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n save_edit();\n } else if (e.key === 'Escape') {\n cancel_edit();\n }\n }}\n />\n <div className=\"cls_metadata_edit_buttons\">\n <button\n type=\"button\"\n onClick={save_edit}\n className=\"cls_metadata_edit_save\"\n aria-label=\"Save\"\n >\n <CheckCircle2 size={18} className=\"text-green-600\" />\n </button>\n <button\n type=\"button\"\n onClick={cancel_edit}\n className=\"cls_metadata_edit_cancel\"\n aria-label=\"Cancel\"\n >\n <X size={18} className=\"text-red-600\" />\n </button>\n </div>\n </div>\n ) : (\n <div className=\"cls_metadata_value_container\">\n <span className=\"cls_metadata_value\">{item.value}</span>\n {item.editable && (\n <button\n type=\"button\"\n onClick={() => start_edit(index, item.value)}\n className=\"cls_metadata_edit_button\"\n aria-label=\"Edit\"\n >\n <Pencil size={16} />\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Footer section */}\n {metadata.footer && metadata.footer.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_footer_section\">\n {metadata.footer.map((item, index) => (\n <FormatText key={`footer-${index}`} style={item.style}>\n {item.label}\n </FormatText>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n};\n\n","/**\n * File Info Sidepanel Component\n * Displays combined file information:\n * - Extracted metadata (from LLM extraction)\n * - File system info (from hazo_files package)\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronDown, ChevronUp } from 'lucide-react';\nimport type { FileMetadataInput, ExtractionEntry } from '../../types';\nimport { cn } from '../../utils/cn';\n\n/**\n * FileSystemItem interface matching hazo_files\n */\ninterface FileSystemItem {\n name: string;\n path: string;\n is_directory: boolean;\n size?: number;\n modified?: Date;\n created?: Date;\n extension?: string;\n mime_type?: string;\n}\n\n/**\n * Highlight field info for display in sidepanel\n */\nexport interface HighlightFieldInfo {\n field_name: string;\n value: string;\n}\n\n/**\n * Props for FileInfoSidepanel component\n */\nexport interface FileInfoSidepanelProps {\n /** Whether the panel is open */\n is_open: boolean;\n /** Callback to toggle panel open/closed */\n on_toggle: () => void;\n /** File item to display info for */\n item: FileSystemItem | null;\n /** Current width of the panel */\n width: number;\n /** Callback when panel width changes */\n on_width_change: (width: number) => void;\n /** Optional file metadata (extraction data) */\n file_metadata?: FileMetadataInput;\n /** Current filename to match against metadata */\n current_filename?: string;\n /** Document data to display (e.g., doc_data from extraction) */\n doc_data?: Record<string, unknown>;\n /** Highlight fields info to display */\n highlight_fields_info?: HighlightFieldInfo[];\n /** Extraction entries from hazo_files file_data */\n extractions?: ExtractionEntry[];\n}\n\n/**\n * Format field name for display (converts snake_case to Title Case)\n */\nconst format_field_name = (name: string): string => {\n return name\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n};\n\n/**\n * Check if a value is a table (array of objects)\n */\nconst is_table = (value: unknown): value is Array<Record<string, string>> => {\n return Array.isArray(value) && value.length > 0 && typeof value[0] === 'object';\n};\n\n/**\n * File Info Sidepanel Component\n * Combines extracted metadata with file system info\n */\nexport const FileInfoSidepanel: React.FC<FileInfoSidepanelProps> = ({\n is_open,\n on_toggle,\n item,\n width,\n on_width_change,\n file_metadata,\n current_filename,\n doc_data,\n highlight_fields_info,\n extractions,\n}) => {\n const [expanded_tables, setExpandedTables] = useState<Set<string>>(new Set());\n const resize_ref = useRef<HTMLDivElement>(null);\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Find metadata matching current filename\n const filename = current_filename || item?.name || '';\n const current_metadata = file_metadata?.find(\n (meta) => meta.filename === filename\n );\n\n // Toggle table expanded/collapsed\n const toggle_table = (table_name: string) => {\n setExpandedTables((prev) => {\n const next = new Set(prev);\n if (next.has(table_name)) {\n next.delete(table_name);\n } else {\n next.add(table_name);\n }\n return next;\n });\n };\n\n // Handle resize start\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 // Handle resize move\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n\n const delta_x = start_x_ref.current - e.clientX;\n const new_width = Math.max(200, Math.min(800, start_width_ref.current + delta_x));\n on_width_change(new_width);\n };\n\n // Handle resize end\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 resize listeners 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 // Separate extracted fields into simple values and tables\n const simple_fields: Array<[string, string]> = [];\n const table_fields: Array<[string, Array<Record<string, string>>]> = [];\n\n if (current_metadata?.file_data) {\n for (const [key, value] of Object.entries(current_metadata.file_data)) {\n if (is_table(value)) {\n table_fields.push([key, value]);\n } else if (typeof value === 'string') {\n simple_fields.push([key, value]);\n }\n }\n }\n\n const has_extracted_data = simple_fields.length > 0 || table_fields.length > 0;\n const has_file_info = item !== null;\n const has_doc_data = doc_data && Object.keys(doc_data).length > 0;\n const has_highlight_info = highlight_fields_info && highlight_fields_info.length > 0;\n const has_extractions = extractions && extractions.length > 0;\n\n return (\n <>\n {/* Toggle button on right edge when closed */}\n {!is_open && (\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_file_info_sidepanel_toggle_edge\"\n aria-label=\"Open file info panel\"\n title=\"Open file info panel\"\n >\n <ChevronLeft size={20} />\n </button>\n )}\n\n {/* Sidepanel */}\n <div\n className={cn('cls_file_info_sidepanel', is_open && 'cls_file_info_sidepanel_open')}\n style={{ width: is_open ? `${width}px` : '0', display: is_open ? 'flex' : 'none' }}\n >\n {/* Resize handle */}\n {is_open && (\n <div\n ref={resize_ref}\n className=\"cls_file_info_sidepanel_resize_handle\"\n onMouseDown={handle_resize_start}\n aria-label=\"Resize panel\"\n />\n )}\n\n {/* Panel content */}\n <div className=\"cls_file_info_sidepanel_content\">\n {/* Header with close button */}\n <div className=\"cls_file_info_sidepanel_header\">\n <span className=\"cls_file_info_sidepanel_title\">File Info</span>\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_file_info_sidepanel_close\"\n aria-label=\"Close file info panel\"\n >\n <ChevronRight size={20} />\n </button>\n </div>\n\n {/* Scrollable content area */}\n <div className=\"cls_file_info_sidepanel_body\">\n {/* Extracted Metadata Section */}\n {has_extracted_data && (\n <div className=\"cls_file_info_extracted_section\">\n <div className=\"cls_file_info_section_header\">Extracted Data</div>\n\n {/* Simple field values */}\n {simple_fields.length > 0 && (\n <div className=\"cls_file_metadata_fields\">\n {simple_fields.map(([key, value]) => (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">{value}</span>\n </div>\n ))}\n </div>\n )}\n\n {/* Table sections */}\n {table_fields.map(([table_name, rows]) => {\n const is_expanded = expanded_tables.has(table_name);\n\n return (\n <div key={table_name} className=\"cls_file_metadata_table_section\">\n {/* Table header (accordion toggle) */}\n <button\n type=\"button\"\n onClick={() => toggle_table(table_name)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={is_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {format_field_name(table_name)}\n </span>\n <span className=\"cls_file_metadata_table_count\">\n ({rows.length} {rows.length === 1 ? 'item' : 'items'})\n </span>\n {is_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n\n {/* Table content - two column layout per row */}\n {is_expanded && (\n <div className=\"cls_file_metadata_table_content\">\n {rows.map((row, row_index) => (\n <div key={row_index} className=\"cls_file_metadata_table_row\">\n <table className=\"cls_file_metadata_row_table\">\n <tbody>\n {Object.entries(row).map(([field_name, field_value]) => (\n <tr key={field_name} className=\"cls_file_metadata_row_tr\">\n <td className=\"cls_file_metadata_row_label\">\n {format_field_name(field_name)}\n </td>\n <td className=\"cls_file_metadata_row_value\">\n {field_value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Doc Data Section */}\n {has_doc_data && (\n <div className=\"cls_file_info_doc_data_section\">\n <div className=\"cls_file_info_section_header\">Document Data</div>\n <div className=\"cls_file_metadata_fields\">\n {Object.entries(doc_data).map(([key, value]) => (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">\n {typeof value === 'object' ? JSON.stringify(value) : String(value)}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Divider between doc_data and highlight info */}\n {has_doc_data && has_highlight_info && (\n <div className=\"cls_file_info_divider\" />\n )}\n\n {/* Highlight Fields Section */}\n {has_highlight_info && (\n <div className=\"cls_file_info_highlight_section\">\n <div className=\"cls_file_info_section_header\">\n Highlighted Fields ({highlight_fields_info.length})\n </div>\n <div className=\"cls_file_metadata_fields\">\n {highlight_fields_info.map((field, idx) => (\n <div key={idx} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(field.field_name)}\n </span>\n <span className=\"cls_file_metadata_field_value cls_highlight_value\">\n {field.value}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Extractions Section */}\n {has_extractions && (\n <div className=\"cls_file_info_extractions_section\">\n {(has_extracted_data || has_doc_data || has_highlight_info) && (\n <div className=\"cls_file_info_divider\" />\n )}\n <div className=\"cls_file_info_section_header\">\n Extractions ({extractions.length})\n </div>\n {extractions.map((entry, idx) => {\n const entry_key = entry.id || `extraction_${idx}`;\n const is_expanded = expanded_tables.has(entry_key);\n const timestamp = entry.extracted_at\n ? new Date(entry.extracted_at).toLocaleString()\n : undefined;\n const data_entries = Object.entries(entry.data);\n\n return (\n <div key={entry_key} className=\"cls_file_metadata_table_section\">\n <button\n type=\"button\"\n onClick={() => toggle_table(entry_key)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={is_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {entry.source || `Extraction ${idx + 1}`}\n </span>\n {timestamp && (\n <span className=\"cls_file_metadata_table_count\">\n {timestamp}\n </span>\n )}\n {is_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n\n {is_expanded && (\n <div className=\"cls_file_metadata_fields\">\n {data_entries.map(([key, value]) => {\n if (is_table(value)) {\n const table_key = `${entry_key}_${key}`;\n const table_expanded = expanded_tables.has(table_key);\n return (\n <div key={key} className=\"cls_file_metadata_table_section\">\n <button\n type=\"button\"\n onClick={() => toggle_table(table_key)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={table_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_table_count\">\n ({value.length} {value.length === 1 ? 'item' : 'items'})\n </span>\n {table_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n {table_expanded && (\n <div className=\"cls_file_metadata_table_content\">\n {value.map((row, row_index) => (\n <div key={row_index} className=\"cls_file_metadata_table_row\">\n <table className=\"cls_file_metadata_row_table\">\n <tbody>\n {Object.entries(row).map(([field_name, field_value]) => (\n <tr key={field_name} className=\"cls_file_metadata_row_tr\">\n <td className=\"cls_file_metadata_row_label\">\n {format_field_name(field_name)}\n </td>\n <td className=\"cls_file_metadata_row_value\">\n {field_value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n const display_value = typeof value === 'object' && value !== null\n ? JSON.stringify(value, null, 2)\n : String(value ?? '');\n\n return (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">\n {display_value}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Divider between sections */}\n {(has_extracted_data || has_doc_data || has_highlight_info || has_extractions) && has_file_info && (\n <div className=\"cls_file_info_divider\" />\n )}\n\n {/* File System Info Section */}\n {has_file_info && item && (\n <div className=\"cls_file_info_system_section\">\n <div className=\"cls_file_info_section_header\">File</div>\n <div className=\"cls_file_info_properties\">\n <div className=\"cls_file_info_property\">\n <span className=\"cls_file_info_property_label\">Name</span>\n <span className=\"cls_file_info_property_value\">{item.name}</span>\n </div>\n <div className=\"cls_file_info_property\">\n <span className=\"cls_file_info_property_label\">Path</span>\n <span className=\"cls_file_info_property_value cls_file_info_path\">{item.path}</span>\n </div>\n </div>\n </div>\n )}\n\n {/* No data message */}\n {!has_extracted_data && !has_doc_data && !has_highlight_info && !has_extractions && !has_file_info && (\n <div className=\"cls_file_info_no_data\">\n No file information available\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n};\n","/**\n * Configuration loader for hazo_pdf\n * Loads configuration from INI file using hazo_config package (Node.js) or fetch (browser)\n * Falls back to defaults if config file is missing or invalid\n */\n\nimport { default_config } from '../config/default_config';\nimport type { PdfViewerConfig } from '../types/config';\nimport { get_logger } from './logger';\n\n/**\n * Simple INI parser for browser environments\n * Parses INI format: [section] followed by key=value pairs\n */\nfunction parse_ini_browser(ini_text: string): Record<string, Record<string, string>> {\n const result: Record<string, Record<string, string>> = {};\n let current_section = '';\n \n const lines = ini_text.split('\\n');\n \n for (const line of lines) {\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n \n // Check for section header [section_name]\n const section_match = trimmed.match(/^\\[([^\\]]+)\\]$/);\n if (section_match) {\n current_section = section_match[1].trim();\n if (!result[current_section]) {\n result[current_section] = {};\n }\n continue;\n }\n \n // Parse key=value pairs\n const key_value_match = trimmed.match(/^([^=]+)=(.*)$/);\n if (key_value_match && current_section) {\n const key = key_value_match[1].trim();\n const value = key_value_match[2].trim();\n result[current_section][key] = value;\n }\n }\n \n return result;\n}\n\n/**\n * Load config in browser environment by fetching the INI file\n * Note: In browser, we parse INI manually since hazo_config requires Node.js fs module\n * The parsing logic matches hazo_config's parsing behavior\n * For Next.js apps, the config is served via /api/config which uses hazo_config on the server\n */\nasync function load_config_browser(config_file: string): Promise<PdfViewerConfig> {\n const logger = get_logger();\n try {\n // In Next.js, serve config via API route that uses hazo_config\n // This ensures the config file stays in root and hazo_config is used server-side\n // If config_file is a relative path (config/hazo_pdf_config.ini), use /api/config\n // If it's already a full URL or API path, use it directly\n const config_url = (config_file === 'config/hazo_pdf_config.ini' || config_file.includes('config/hazo_pdf_config.ini'))\n ? '/api/config'\n : config_file;\n \n const response = await fetch(config_url);\n if (!response.ok) {\n throw new Error(`Failed to fetch config file: ${response.status} ${response.statusText}`);\n }\n const ini_text = await response.text();\n \n // Parse INI manually (matching hazo_config's parsing behavior)\n // hazo_config requires Node.js fs, so we implement compatible parsing here\n const parsed = parse_ini_browser(ini_text);\n \n // Debug: Log parsed values for troubleshooting\n logger.debug('Parsed config sections', { data: Object.keys(parsed) });\n if (parsed['fonts']) {\n logger.debug('fonts section', { data: parsed['fonts'] });\n }\n if (parsed['freetext_annotation']) {\n logger.debug('freetext_annotation section', { data: parsed['freetext_annotation'] });\n }\n if (parsed['viewer']) {\n logger.debug('viewer section', { data: parsed['viewer'] });\n } else {\n logger.warn('viewer section NOT found in parsed config!');\n }\n \n // Extract values from parsed INI\n const get_value = (section: string, key: string): string | undefined => {\n return parsed[section]?.[key];\n };\n \n // Build config object using same function as hazo_config version\n const config = build_config_from_ini(get_value);\n \n // Debug: Log final config values\n logger.debug('Final config values', {\n font_foreground_color: config.fonts.font_foreground_color,\n freetext_text_color: config.freetext_annotation.freetext_text_color,\n freetext_background_color: config.freetext_annotation.freetext_background_color,\n freetext_background_opacity: config.freetext_annotation.freetext_background_opacity,\n append_timestamp_to_text_edits: config.viewer.append_timestamp_to_text_edits,\n annotation_text_suffix_fixed_text: config.viewer.annotation_text_suffix_fixed_text,\n });\n \n // Debug: Log viewer section parsing\n const raw_value = get_value('viewer', 'append_timestamp_to_text_edits');\n logger.debug('append_timestamp_to_text_edits', {\n raw_value: raw_value,\n raw_type: typeof raw_value,\n parsed_boolean: config.viewer.append_timestamp_to_text_edits,\n parse_boolean_test: parse_boolean(raw_value, false),\n });\n\n // Also log all viewer keys for debugging\n if (parsed['viewer']) {\n logger.debug('All viewer section keys', { data: Object.keys(parsed['viewer']) });\n logger.debug('All viewer section values', { data: parsed['viewer'] });\n }\n \n return config;\n } catch (error) {\n logger.warn(`Could not load config file \"${config_file}\" in browser, using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n\n/**\n * Load config asynchronously (works in both browser and Node.js)\n * Uses hazo_config in Node.js, fetch + manual parsing in browser\n * @param config_file - Path to config file\n * @returns Promise resolving to PdfViewerConfig\n */\nexport async function load_pdf_config_async(config_file: string): Promise<PdfViewerConfig> {\n const logger = get_logger();\n // Detect environment\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser: use fetch + manual parsing (hazo_config requires Node.js)\n return load_config_browser(config_file);\n }\n \n // Node.js: use hazo_config (preferred method)\n try {\n // Dynamically import hazo_config only in Node.js\n const { HazoConfig } = require('hazo_config');\n const hazo_config = new HazoConfig({ filePath: config_file });\n \n logger.debug(`Using hazo_config to load: ${config_file}`);\n \n // Use hazo_config's get method\n const get_value = (section: string, key: string): string | undefined => {\n return hazo_config.get(section, key);\n };\n \n const config = build_config_from_ini(get_value);\n logger.info(`Successfully loaded config using hazo_config from: ${config_file}`);\n return config;\n } catch (error) {\n logger.warn(`Could not load config file \"${config_file}\" using hazo_config, using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n\n/**\n * Build config object from INI values (shared between browser and Node.js)\n * @param get_value - Function to get a value from INI (section, key) -> value\n * @returns Complete PdfViewerConfig object\n */\nexport function build_config_from_ini(get_value: (section: string, key: string) => string | undefined): PdfViewerConfig {\n const logger = get_logger();\n return {\n fonts: {\n freetext_font_family: parse_string(\n get_value('fonts', 'freetext_font_family'),\n default_config.fonts.freetext_font_family\n ),\n freetext_font_size_min: parse_number(\n get_value('fonts', 'freetext_font_size_min'),\n default_config.fonts.freetext_font_size_min\n ),\n freetext_font_size_max: parse_number(\n get_value('fonts', 'freetext_font_size_max'),\n default_config.fonts.freetext_font_size_max\n ),\n freetext_font_size_default: parse_number(\n get_value('fonts', 'freetext_font_size_default'),\n default_config.fonts.freetext_font_size_default\n ),\n font_foreground_color: parse_color(\n get_value('fonts', 'font_foreground_color'),\n default_config.fonts.font_foreground_color\n ),\n },\n\n highlight_annotation: {\n highlight_fill_color: parse_color(\n get_value('highlight_annotation', 'highlight_fill_color'),\n default_config.highlight_annotation.highlight_fill_color\n ),\n highlight_fill_opacity: parse_opacity(\n get_value('highlight_annotation', 'highlight_fill_opacity'),\n default_config.highlight_annotation.highlight_fill_opacity\n ),\n highlight_border_color: parse_color(\n get_value('highlight_annotation', 'highlight_border_color'),\n default_config.highlight_annotation.highlight_border_color\n ),\n highlight_border_color_hover: parse_color(\n get_value('highlight_annotation', 'highlight_border_color_hover'),\n default_config.highlight_annotation.highlight_border_color_hover\n ),\n highlight_fill_opacity_hover: parse_opacity(\n get_value('highlight_annotation', 'highlight_fill_opacity_hover'),\n default_config.highlight_annotation.highlight_fill_opacity_hover\n ),\n },\n\n square_annotation: {\n square_fill_color: parse_color(\n get_value('square_annotation', 'square_fill_color'),\n default_config.square_annotation.square_fill_color\n ),\n square_fill_opacity: parse_opacity(\n get_value('square_annotation', 'square_fill_opacity'),\n default_config.square_annotation.square_fill_opacity\n ),\n square_border_color: parse_color(\n get_value('square_annotation', 'square_border_color'),\n default_config.square_annotation.square_border_color\n ),\n square_border_color_hover: parse_color(\n get_value('square_annotation', 'square_border_color_hover'),\n default_config.square_annotation.square_border_color_hover\n ),\n square_fill_opacity_hover: parse_opacity(\n get_value('square_annotation', 'square_fill_opacity_hover'),\n default_config.square_annotation.square_fill_opacity_hover\n ),\n },\n\n freetext_annotation: {\n freetext_text_color: parse_color(\n get_value('freetext_annotation', 'freetext_text_color'),\n default_config.freetext_annotation.freetext_text_color\n ),\n freetext_text_color_hover: parse_color(\n get_value('freetext_annotation', 'freetext_text_color_hover'),\n default_config.freetext_annotation.freetext_text_color_hover\n ),\n freetext_border_color: parse_string(\n get_value('freetext_annotation', 'freetext_border_color'),\n default_config.freetext_annotation.freetext_border_color\n ),\n freetext_border_width: parse_number(\n get_value('freetext_annotation', 'freetext_border_width'),\n default_config.freetext_annotation.freetext_border_width\n ),\n freetext_background_color: (() => {\n const raw_value = get_value('freetext_annotation', 'freetext_background_color');\n const parsed = parse_string(raw_value, default_config.freetext_annotation.freetext_background_color);\n logger.debug(`freetext_background_color: raw=\"${raw_value}\", parsed=\"${parsed}\"`);\n return parsed;\n })(),\n freetext_background_opacity: parse_opacity(\n get_value('freetext_annotation', 'freetext_background_opacity'),\n default_config.freetext_annotation.freetext_background_opacity\n ),\n freetext_font_weight: parse_string(\n get_value('freetext_annotation', 'freetext_font_weight'),\n default_config.freetext_annotation.freetext_font_weight\n ),\n freetext_font_style: parse_string(\n get_value('freetext_annotation', 'freetext_font_style'),\n default_config.freetext_annotation.freetext_font_style\n ),\n freetext_text_decoration: parse_string(\n get_value('freetext_annotation', 'freetext_text_decoration'),\n default_config.freetext_annotation.freetext_text_decoration\n ),\n freetext_padding_horizontal: parse_number(\n get_value('freetext_annotation', 'freetext_padding_horizontal'),\n default_config.freetext_annotation.freetext_padding_horizontal\n ),\n freetext_padding_vertical: parse_number(\n get_value('freetext_annotation', 'freetext_padding_vertical'),\n default_config.freetext_annotation.freetext_padding_vertical\n ),\n },\n\n page_styling: {\n page_border_color: parse_color(\n get_value('page_styling', 'page_border_color'),\n default_config.page_styling.page_border_color\n ),\n page_box_shadow: parse_string(\n get_value('page_styling', 'page_box_shadow'),\n default_config.page_styling.page_box_shadow\n ),\n page_background_color: parse_color(\n get_value('page_styling', 'page_background_color'),\n default_config.page_styling.page_background_color\n ),\n },\n\n viewer: {\n viewer_background_color: parse_color(\n get_value('viewer', 'viewer_background_color'),\n default_config.viewer.viewer_background_color\n ),\n append_timestamp_to_text_edits: parse_boolean(\n get_value('viewer', 'append_timestamp_to_text_edits'),\n default_config.viewer.append_timestamp_to_text_edits\n ),\n annotation_text_suffix_fixed_text: parse_string(\n get_value('viewer', 'annotation_text_suffix_fixed_text'),\n default_config.viewer.annotation_text_suffix_fixed_text\n ),\n add_enclosing_brackets_to_suffixes: parse_boolean(\n get_value('viewer', 'add_enclosing_brackets_to_suffixes'),\n default_config.viewer.add_enclosing_brackets_to_suffixes\n ),\n suffix_enclosing_brackets: (() => {\n const raw_value = parse_string(\n get_value('viewer', 'suffix_enclosing_brackets'),\n default_config.viewer.suffix_enclosing_brackets\n );\n if (raw_value.length === 2) {\n return raw_value;\n }\n logger.warn(`suffix_enclosing_brackets must be 2 characters, received \"${raw_value}\". Using default.`);\n return default_config.viewer.suffix_enclosing_brackets;\n })(),\n suffix_text_position: (() => {\n const raw_value = parse_string(\n get_value('viewer', 'suffix_text_position'),\n default_config.viewer.suffix_text_position\n ) as 'adjacent' | 'below_single_line' | 'below_multi_line';\n const valid_values: Array<'adjacent' | 'below_single_line' | 'below_multi_line'> = [\n 'adjacent',\n 'below_single_line',\n 'below_multi_line',\n ];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n logger.warn(`Invalid suffix_text_position \"${raw_value}\". Using default \"${default_config.viewer.suffix_text_position}\".`);\n return default_config.viewer.suffix_text_position;\n })(),\n },\n\n context_menu: {\n context_menu_background_color: parse_color(\n get_value('context_menu', 'context_menu_background_color'),\n default_config.context_menu.context_menu_background_color\n ),\n context_menu_border_color: parse_color(\n get_value('context_menu', 'context_menu_border_color'),\n default_config.context_menu.context_menu_border_color\n ),\n context_menu_item_hover_background: parse_color(\n get_value('context_menu', 'context_menu_item_hover_background'),\n default_config.context_menu.context_menu_item_hover_background\n ),\n context_menu_item_disabled_opacity: parse_opacity(\n get_value('context_menu', 'context_menu_item_disabled_opacity'),\n default_config.context_menu.context_menu_item_disabled_opacity\n ),\n right_click_custom_stamps: parse_string(\n get_value('context_menu', 'right_click_custom_stamps'),\n default_config.context_menu.right_click_custom_stamps\n ),\n },\n\n dialog: {\n dialog_backdrop_opacity: parse_opacity(\n get_value('dialog', 'dialog_backdrop_opacity'),\n default_config.dialog.dialog_backdrop_opacity\n ),\n dialog_background_color: parse_color(\n get_value('dialog', 'dialog_background_color'),\n default_config.dialog.dialog_background_color\n ),\n dialog_border_color: parse_color(\n get_value('dialog', 'dialog_border_color'),\n default_config.dialog.dialog_border_color\n ),\n dialog_button_submit_color: parse_color(\n get_value('dialog', 'dialog_button_submit_color'),\n default_config.dialog.dialog_button_submit_color\n ),\n dialog_button_submit_color_hover: parse_color(\n get_value('dialog', 'dialog_button_submit_color_hover'),\n default_config.dialog.dialog_button_submit_color_hover\n ),\n dialog_button_cancel_color: parse_color(\n get_value('dialog', 'dialog_button_cancel_color'),\n default_config.dialog.dialog_button_cancel_color\n ),\n dialog_button_cancel_color_hover: parse_color(\n get_value('dialog', 'dialog_button_cancel_color_hover'),\n default_config.dialog.dialog_button_cancel_color_hover\n ),\n dialog_button_disabled_opacity: parse_opacity(\n get_value('dialog', 'dialog_button_disabled_opacity'),\n default_config.dialog.dialog_button_disabled_opacity\n ),\n },\n\n toolbar: {\n toolbar_background_color: parse_color(\n get_value('toolbar', 'toolbar_background_color'),\n default_config.toolbar.toolbar_background_color\n ),\n toolbar_border_color: parse_color(\n get_value('toolbar', 'toolbar_border_color'),\n default_config.toolbar.toolbar_border_color\n ),\n toolbar_font_family: parse_string(\n get_value('toolbar', 'toolbar_font_family'),\n default_config.toolbar.toolbar_font_family\n ),\n toolbar_font_size: parse_number(\n get_value('toolbar', 'toolbar_font_size'),\n default_config.toolbar.toolbar_font_size\n ),\n toolbar_font_color: parse_color(\n get_value('toolbar', 'toolbar_font_color'),\n default_config.toolbar.toolbar_font_color\n ),\n toolbar_button_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_background_color'),\n default_config.toolbar.toolbar_button_background_color\n ),\n toolbar_button_background_color_hover: parse_color(\n get_value('toolbar', 'toolbar_button_background_color_hover'),\n default_config.toolbar.toolbar_button_background_color_hover\n ),\n toolbar_button_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_text_color'),\n default_config.toolbar.toolbar_button_text_color\n ),\n toolbar_button_active_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_active_background_color'),\n default_config.toolbar.toolbar_button_active_background_color\n ),\n toolbar_button_active_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_active_text_color'),\n default_config.toolbar.toolbar_button_active_text_color\n ),\n toolbar_button_save_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_save_background_color'),\n default_config.toolbar.toolbar_button_save_background_color\n ),\n toolbar_button_save_background_color_hover: parse_color(\n get_value('toolbar', 'toolbar_button_save_background_color_hover'),\n default_config.toolbar.toolbar_button_save_background_color_hover\n ),\n toolbar_button_save_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_save_text_color'),\n default_config.toolbar.toolbar_button_save_text_color\n ),\n toolbar_button_disabled_opacity: parse_opacity(\n get_value('toolbar', 'toolbar_button_disabled_opacity'),\n default_config.toolbar.toolbar_button_disabled_opacity\n ),\n toolbar_show_zoom_controls: parse_boolean(\n get_value('toolbar', 'toolbar_show_zoom_controls'),\n default_config.toolbar.toolbar_show_zoom_controls\n ),\n toolbar_show_rotation_controls: parse_boolean(\n get_value('toolbar', 'toolbar_show_rotation_controls'),\n default_config.toolbar.toolbar_show_rotation_controls\n ),\n toolbar_show_square_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_square_button'),\n default_config.toolbar.toolbar_show_square_button\n ),\n toolbar_show_undo_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_undo_button'),\n default_config.toolbar.toolbar_show_undo_button\n ),\n toolbar_show_redo_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_redo_button'),\n default_config.toolbar.toolbar_show_redo_button\n ),\n toolbar_show_save_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_save_button'),\n default_config.toolbar.toolbar_show_save_button\n ),\n toolbar_show_metadata_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_metadata_button'),\n default_config.toolbar.toolbar_show_metadata_button\n ),\n toolbar_show_annotate_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_annotate_button'),\n default_config.toolbar.toolbar_show_annotate_button\n ),\n toolbar_show_file_info_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_file_info_button'),\n default_config.toolbar.toolbar_show_file_info_button\n ),\n toolbar_show_extract_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_extract_button'),\n default_config.toolbar.toolbar_show_extract_button\n ),\n toolbar_show_download_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_download_button'),\n default_config.toolbar.toolbar_show_download_button\n ),\n toolbar_zoom_out_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_out_label'),\n default_config.toolbar.toolbar_zoom_out_label\n ),\n toolbar_zoom_in_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_in_label'),\n default_config.toolbar.toolbar_zoom_in_label\n ),\n toolbar_zoom_reset_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_reset_label'),\n default_config.toolbar.toolbar_zoom_reset_label\n ),\n toolbar_square_label: parse_string(\n get_value('toolbar', 'toolbar_square_label'),\n default_config.toolbar.toolbar_square_label\n ),\n toolbar_undo_label: parse_string(\n get_value('toolbar', 'toolbar_undo_label'),\n default_config.toolbar.toolbar_undo_label\n ),\n toolbar_redo_label: parse_string(\n get_value('toolbar', 'toolbar_redo_label'),\n default_config.toolbar.toolbar_redo_label\n ),\n toolbar_save_label: parse_string(\n get_value('toolbar', 'toolbar_save_label'),\n default_config.toolbar.toolbar_save_label\n ),\n toolbar_saving_label: parse_string(\n get_value('toolbar', 'toolbar_saving_label'),\n default_config.toolbar.toolbar_saving_label\n ),\n toolbar_metadata_label: parse_string(\n get_value('toolbar', 'toolbar_metadata_label'),\n default_config.toolbar.toolbar_metadata_label\n ),\n },\n\n file_manager: {\n file_manager_enabled: parse_boolean(\n get_value('file_manager', 'file_manager_enabled'),\n default_config.file_manager.file_manager_enabled\n ),\n show_file_list: parse_boolean(\n get_value('file_manager', 'show_file_list'),\n default_config.file_manager.show_file_list\n ),\n allow_delete: parse_boolean(\n get_value('file_manager', 'allow_delete'),\n default_config.file_manager.allow_delete\n ),\n show_popout_button: parse_boolean(\n get_value('file_manager', 'show_popout_button'),\n default_config.file_manager.show_popout_button\n ),\n file_list_height: parse_number(\n get_value('file_manager', 'file_list_height'),\n default_config.file_manager.file_list_height\n ),\n selected_color: parse_color(\n get_value('file_manager', 'selected_color'),\n default_config.file_manager.selected_color\n ),\n file_list_background_color: parse_color(\n get_value('file_manager', 'file_list_background_color'),\n default_config.file_manager.file_list_background_color\n ),\n file_list_border_color: parse_color(\n get_value('file_manager', 'file_list_border_color'),\n default_config.file_manager.file_list_border_color\n ),\n },\n\n file_upload: {\n upload_enabled: parse_boolean(\n get_value('file_upload', 'upload_enabled'),\n default_config.file_upload.upload_enabled\n ),\n allowed_types: parse_string(\n get_value('file_upload', 'allowed_types'),\n default_config.file_upload.allowed_types\n ),\n max_file_size: parse_number(\n get_value('file_upload', 'max_file_size'),\n default_config.file_upload.max_file_size\n ),\n max_files: parse_number(\n get_value('file_upload', 'max_files'),\n default_config.file_upload.max_files\n ),\n show_add_button: parse_boolean(\n get_value('file_upload', 'show_add_button'),\n default_config.file_upload.show_add_button\n ),\n dropzone_border_color: parse_color(\n get_value('file_upload', 'dropzone_border_color'),\n default_config.file_upload.dropzone_border_color\n ),\n dropzone_border_color_active: parse_color(\n get_value('file_upload', 'dropzone_border_color_active'),\n default_config.file_upload.dropzone_border_color_active\n ),\n dropzone_background_color: parse_color(\n get_value('file_upload', 'dropzone_background_color'),\n default_config.file_upload.dropzone_background_color\n ),\n direct_upload: parse_boolean(\n get_value('file_upload', 'direct_upload'),\n default_config.file_upload.direct_upload\n ),\n },\n\n pdf_conversion: {\n conversion_enabled: parse_boolean(\n get_value('pdf_conversion', 'conversion_enabled'),\n default_config.pdf_conversion.conversion_enabled\n ),\n page_size: (() => {\n const raw_value = parse_string(\n get_value('pdf_conversion', 'page_size'),\n default_config.pdf_conversion.page_size\n ) as 'letter' | 'a4' | 'legal';\n const valid_values: Array<'letter' | 'a4' | 'legal'> = ['letter', 'a4', 'legal'];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n return default_config.pdf_conversion.page_size;\n })(),\n image_quality: parse_opacity(\n get_value('pdf_conversion', 'image_quality'),\n default_config.pdf_conversion.image_quality\n ),\n image_fit: (() => {\n const raw_value = parse_string(\n get_value('pdf_conversion', 'image_fit'),\n default_config.pdf_conversion.image_fit\n ) as 'fit' | 'fill' | 'stretch';\n const valid_values: Array<'fit' | 'fill' | 'stretch'> = ['fit', 'fill', 'stretch'];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n return default_config.pdf_conversion.image_fit;\n })(),\n margin: parse_number(\n get_value('pdf_conversion', 'margin'),\n default_config.pdf_conversion.margin\n ),\n },\n\n auto_highlight: {\n auto_highlight_border_color: parse_color(\n get_value('auto_highlight', 'auto_highlight_border_color'),\n default_config.auto_highlight.auto_highlight_border_color\n ),\n auto_highlight_background_color: parse_color(\n get_value('auto_highlight', 'auto_highlight_background_color'),\n default_config.auto_highlight.auto_highlight_background_color\n ),\n auto_highlight_background_opacity: parse_opacity(\n get_value('auto_highlight', 'auto_highlight_background_opacity'),\n default_config.auto_highlight.auto_highlight_background_opacity\n ),\n auto_highlight_border_width: parse_number(\n get_value('auto_highlight', 'auto_highlight_border_width'),\n default_config.auto_highlight.auto_highlight_border_width\n ),\n auto_highlight_normalize_text: parse_boolean(\n get_value('auto_highlight', 'auto_highlight_normalize_text'),\n default_config.auto_highlight.auto_highlight_normalize_text\n ),\n auto_highlight_padding_x: parse_number(\n get_value('auto_highlight', 'auto_highlight_padding_x'),\n default_config.auto_highlight.auto_highlight_padding_x\n ),\n auto_highlight_padding_y: parse_number(\n get_value('auto_highlight', 'auto_highlight_padding_y'),\n default_config.auto_highlight.auto_highlight_padding_y\n ),\n auto_highlight_y_offset: parse_number(\n get_value('auto_highlight', 'auto_highlight_y_offset'),\n default_config.auto_highlight.auto_highlight_y_offset\n ),\n },\n\n file_button: {\n icon_size: parse_number(\n get_value('file_button', 'icon_size'),\n default_config.file_button.icon_size\n ),\n icon_color: parse_color(\n get_value('file_button', 'icon_color'),\n default_config.file_button.icon_color\n ),\n icon_color_hover: parse_color(\n get_value('file_button', 'icon_color_hover'),\n default_config.file_button.icon_color_hover\n ),\n icon_color_with_files: parse_color(\n get_value('file_button', 'icon_color_with_files'),\n default_config.file_button.icon_color_with_files\n ),\n badge_background: parse_color(\n get_value('file_button', 'badge_background'),\n default_config.file_button.badge_background\n ),\n badge_text_color: parse_color(\n get_value('file_button', 'badge_text_color'),\n default_config.file_button.badge_text_color\n ),\n },\n };\n}\n\n/**\n * Parse a color value from config (hex format)\n * @param value - Color value from config\n * @param default_value - Default color if parsing fails\n * @returns Parsed color value\n */\nexport function parse_color(value: string | undefined, default_value: string): string {\n if (!value) return default_value;\n // Validate hex color format\n if (/^#[0-9A-Fa-f]{6}$/.test(value)) {\n return value;\n }\n // Try to parse rgba format\n if (value.startsWith('rgba') || value.startsWith('rgb')) {\n return value;\n }\n get_logger().warn(`Invalid color format: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse an opacity value from config (0.0 to 1.0)\n * @param value - Opacity value from config\n * @param default_value - Default opacity if parsing fails\n * @returns Parsed opacity value\n */\nexport function parse_opacity(value: string | undefined, default_value: number): number {\n if (!value) return default_value;\n const parsed = parseFloat(value);\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n return parsed;\n }\n get_logger().warn(`Invalid opacity value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse a number value from config\n * @param value - Number value from config\n * @param default_value - Default number if parsing fails\n * @returns Parsed number value\n */\nexport function parse_number(value: string | undefined, default_value: number): number {\n if (!value) return default_value;\n const parsed = parseFloat(value);\n if (!isNaN(parsed)) {\n return parsed;\n }\n get_logger().warn(`Invalid number value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse a string value from config\n * @param value - String value from config\n * @param default_value - Default string if value is missing\n * @returns Parsed string value\n */\nexport function parse_string(value: string | undefined, default_value: string): string {\n return value || default_value;\n}\n\n/**\n * Parse a boolean value from config\n * @param value - Boolean value from config (true/false, yes/no, 1/0)\n * @param default_value - Default boolean if parsing fails\n * @returns Parsed boolean value\n */\nexport function parse_boolean(value: string | undefined, default_value: boolean): boolean {\n if (!value) return default_value;\n const lower = value.toLowerCase().trim();\n if (lower === 'true' || lower === 'yes' || lower === '1') {\n return true;\n }\n if (lower === 'false' || lower === 'no' || lower === '0') {\n return false;\n }\n get_logger().warn(`Invalid boolean value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Load PDF viewer configuration from INI file\n * Supports both Node.js (using hazo_config) and browser (using fetch) environments\n * @param config_file - Optional path to config file. If not provided, returns defaults\n * @returns Configuration object with loaded values merged with defaults\n */\nexport function load_pdf_config(config_file?: string): PdfViewerConfig {\n const logger = get_logger();\n // If no config file specified, return defaults\n if (!config_file) {\n logger.debug('No config file specified, using defaults');\n return default_config;\n }\n\n // Detect environment: browser vs Node.js\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser environment: use fetch to load INI file\n // Note: This is async, but we need sync behavior for React component initialization\n // We'll load it synchronously by throwing an error if fetch fails, and the component\n // will need to handle async loading or we use a different approach\n logger.warn('Browser environment detected. Config loading should be async, but load_pdf_config is sync. Using defaults. Consider making this async or using a different approach.');\n return default_config;\n }\n\n // Node.js environment: use hazo_config\n try {\n // Dynamically import hazo_config only in Node.js\n const { HazoConfig } = require('hazo_config');\n const hazo_config = new HazoConfig({ filePath: config_file });\n\n // Use the shared build function\n const get_value = (section: string, key: string): string | undefined => {\n return hazo_config.get(section, key);\n };\n \n const config = build_config_from_ini(get_value);\n logger.info(`Successfully loaded config from: ${config_file}`);\n return config;\n } catch (error) {\n // If config file doesn't exist or has errors, use defaults\n logger.warn(`Could not load config file \"${config_file}\", using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n","/**\n * File Manager Component\n * Main orchestrator for multi-file management in hazo_pdf\n */\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport type { FileItem, UploadProgress, UploadResult } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { FileList } from './file_list';\nimport { UploadDropzone } from './upload_dropzone';\nimport { FileManagerButton } from './file_manager_button';\nimport { convert_to_pdf, can_convert_to_pdf } from '../../utils/pdf_converter';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\nexport interface FileManagerProps {\n /** Initial files to display */\n files?: FileItem[];\n /** Currently selected file ID */\n selected_file_id?: string | null;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when a file is selected */\n on_file_select?: (file: FileItem) => void;\n /** Callback when a file is deleted */\n on_file_delete?: (file_id: string) => void;\n /** Callback for file upload (caller handles actual storage) */\n on_upload?: (file: File, converted_pdf?: Uint8Array) => Promise<UploadResult>;\n /** Callback when files array changes */\n on_files_change?: (files: FileItem[]) => void;\n /** Whether to show only the compact button trigger */\n show_button_only?: boolean;\n /** Callback to open file manager dialog (for button mode) */\n on_open_dialog?: () => void;\n /** Additional CSS class name */\n className?: string;\n}\n\n/**\n * Generate a unique ID for a file\n */\nfunction generate_file_id(): string {\n return `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Determine file type from MIME type\n */\nfunction get_file_type(mime_type: string): FileItem['type'] {\n if (mime_type === 'application/pdf') return 'pdf';\n if (mime_type.startsWith('image/')) return 'image';\n if (mime_type.startsWith('text/')) return 'text';\n return 'other';\n}\n\nexport const FileManager: React.FC<FileManagerProps> = ({\n files: external_files,\n selected_file_id: external_selected_id,\n config,\n on_file_select,\n on_file_delete,\n on_upload,\n on_files_change,\n show_button_only = false,\n on_open_dialog,\n className,\n}) => {\n // Internal state for files if not controlled externally\n const [internal_files, setInternalFiles] = useState<FileItem[]>(external_files || []);\n const [internal_selected_id, setInternalSelectedId] = useState<string | null>(\n external_selected_id || external_files?.[0]?.id || null\n );\n const [uploads, setUploads] = useState<UploadProgress[]>([]);\n const [show_dropzone, setShowDropzone] = useState(false);\n\n // Use external files if provided, otherwise use internal\n const files = external_files ?? internal_files;\n const selected_file_id = external_selected_id ?? internal_selected_id;\n\n // Sync internal state with external files when they change\n useEffect(() => {\n if (external_files !== undefined) {\n setInternalFiles(external_files);\n }\n }, [external_files]);\n\n useEffect(() => {\n if (external_selected_id !== undefined) {\n setInternalSelectedId(external_selected_id);\n }\n }, [external_selected_id]);\n\n /**\n * Handle file selection\n */\n const handle_file_select = useCallback((file: FileItem) => {\n setInternalSelectedId(file.id);\n on_file_select?.(file);\n }, [on_file_select]);\n\n /**\n * Handle file deletion\n */\n const handle_file_delete = useCallback((file_id: string) => {\n const new_files = files.filter(f => f.id !== file_id);\n setInternalFiles(new_files);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(new_files), 0);\n on_file_delete?.(file_id);\n\n // Select next file if deleted file was selected\n if (selected_file_id === file_id && new_files.length > 0) {\n handle_file_select(new_files[0]);\n } else if (new_files.length === 0) {\n setInternalSelectedId(null);\n }\n }, [files, selected_file_id, on_files_change, on_file_delete, handle_file_select]);\n\n /**\n * Handle files selected for upload\n */\n const handle_files_selected = useCallback(async (selected_files: File[]) => {\n const conversion_config = config?.pdf_conversion;\n\n for (const file of selected_files) {\n const file_id = generate_file_id();\n const needs_conversion = file.type !== 'application/pdf' &&\n conversion_config?.conversion_enabled !== false &&\n can_convert_to_pdf(file.type);\n\n // Add placeholder file immediately to show in the list\n const placeholder_file: FileItem = {\n id: file_id,\n name: needs_conversion ? file.name.replace(/\\.[^.]+$/, '.pdf') : file.name,\n url: '', // Empty URL until ready\n type: 'pdf',\n mime_type: 'application/pdf',\n status: needs_conversion ? 'converting' : 'uploading',\n original_file: file,\n };\n\n // Add placeholder to file list immediately\n setInternalFiles(prev => {\n const updated = [...prev, placeholder_file];\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n // Add to upload progress\n setUploads(prev => [...prev, {\n file_id,\n filename: file.name,\n progress: 0,\n status: needs_conversion ? 'converting' : 'uploading',\n }]);\n\n try {\n let converted_pdf: Uint8Array | undefined;\n let final_mime_type = file.type;\n let final_name = file.name;\n let is_converted = false;\n\n // Check if conversion is needed\n if (needs_conversion) {\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'converting', progress: 30 } : u\n ));\n\n const result = await convert_to_pdf(file, file.name, {\n page_size: conversion_config?.page_size || 'letter',\n image_quality: conversion_config?.image_quality || 0.85,\n image_fit: conversion_config?.image_fit || 'fit',\n margin: conversion_config?.margin || 36,\n });\n\n if (result.success && result.pdf_bytes) {\n converted_pdf = result.pdf_bytes;\n final_mime_type = 'application/pdf';\n final_name = result.pdf_filename || file.name.replace(/\\.[^.]+$/, '.pdf');\n is_converted = true;\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, progress: 60 } : u\n ));\n } else {\n throw new Error(result.error || 'Conversion failed');\n }\n }\n\n // If caller provides on_upload, use it\n if (on_upload) {\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'uploading', progress: 80 } : u\n ));\n\n // Update placeholder to uploading status\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? { ...f, status: 'uploading' as const } : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n const upload_result = await on_upload(file, converted_pdf);\n\n if (upload_result.success && upload_result.file) {\n const new_file: FileItem = {\n ...upload_result.file,\n id: file_id, // Keep original ID\n is_converted,\n original_file: is_converted ? file : undefined,\n status: 'ready',\n };\n\n // Update placeholder with real file data\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? new_file : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'complete', progress: 100 } : u\n ));\n\n // Auto-select the newly uploaded file\n handle_file_select(new_file);\n } else {\n throw new Error(upload_result.error || 'Upload failed');\n }\n } else {\n // Create data URL for local display\n // Create new Uint8Array to ensure proper ArrayBuffer type for Blob constructor\n const blob = converted_pdf\n ? new Blob([new Uint8Array(converted_pdf)], { type: 'application/pdf' })\n : file;\n const url = URL.createObjectURL(blob);\n\n const new_file: FileItem = {\n id: file_id,\n name: final_name,\n url: url,\n type: get_file_type(final_mime_type),\n mime_type: final_mime_type,\n size: blob.size,\n is_converted,\n original_file: is_converted ? file : undefined,\n status: 'ready',\n };\n\n // Update placeholder with real file data\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? new_file : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'complete', progress: 100 } : u\n ));\n\n // Auto-select the newly uploaded file\n handle_file_select(new_file);\n }\n } catch (error) {\n const logger = get_logger();\n logger.error('Upload/conversion error', { data: error });\n\n // Update placeholder to error status\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? { ...f, status: 'error' as const } : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? {\n ...u,\n status: 'error',\n progress: 0,\n error_message: error instanceof Error ? error.message : 'Upload failed',\n } : u\n ));\n }\n }\n\n // Clear completed uploads after delay\n setTimeout(() => {\n setUploads(prev => prev.filter(u => u.status !== 'complete'));\n }, 3000);\n\n // Close dropzone after files are selected\n setShowDropzone(false);\n }, [config, on_upload, on_files_change, handle_file_select]);\n\n const file_manager_config = config?.file_manager;\n const upload_config = config?.file_upload;\n const is_direct_upload = upload_config?.direct_upload ?? false;\n\n // If button-only mode, render just the button\n if (show_button_only) {\n return (\n <FileManagerButton\n file_count={files.length}\n config={config}\n on_click={() => on_open_dialog?.()}\n className={className}\n />\n );\n }\n\n return (\n <div className={cn('cls_file_manager', className)}>\n {/* File list */}\n {file_manager_config?.show_file_list !== false && (\n <FileList\n files={files}\n selected_file_id={selected_file_id}\n config={config}\n on_select={handle_file_select}\n on_delete={file_manager_config?.allow_delete !== false ? handle_file_delete : undefined}\n on_add_click={upload_config?.upload_enabled !== false && !is_direct_upload ? () => setShowDropzone(true) : undefined}\n on_files_selected={upload_config?.upload_enabled !== false && is_direct_upload ? handle_files_selected : undefined}\n />\n )}\n\n {/* Dropzone overlay (only for non-direct mode) */}\n {show_dropzone && !is_direct_upload && (\n <div className=\"cls_file_manager_dropzone_overlay\">\n <div className=\"cls_file_manager_dropzone_dialog\">\n <UploadDropzone\n config={config}\n uploads={uploads}\n on_files_selected={handle_files_selected}\n on_close={() => setShowDropzone(false)}\n />\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// Re-export sub-components\nexport { FileList } from './file_list';\nexport { FileListItem } from './file_list_item';\nexport { FileManagerButton } from './file_manager_button';\nexport { UploadDropzone } from './upload_dropzone';\nexport { UploadProgressDisplay } from './upload_progress';\nexport type { FileItem, UploadProgress, UploadResult, FileManagerDisplayMode, PopoutContext } from './types';\n\nexport default FileManager;\n","/**\n * File List Component\n * Horizontal scrollable list of file items with navigation and add button\n */\n\nimport React, { useRef, useState, useEffect, useCallback } from 'react';\nimport { ChevronLeft, ChevronRight, Plus } from 'lucide-react';\nimport type { FileItem } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { FileListItem } from './file_list_item';\nimport { cn } from '../../utils/cn';\n\nexport interface FileListProps {\n /** Array of files to display */\n files: FileItem[];\n /** ID of the currently selected file */\n selected_file_id: string | null;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when a file is selected */\n on_select: (file: FileItem) => void;\n /** Callback when a file is deleted */\n on_delete?: (file_id: string) => void;\n /** Callback when add button is clicked (opens dropzone overlay) */\n on_add_click?: () => void;\n /** Callback when files are selected directly (for direct_upload mode) */\n on_files_selected?: (files: File[]) => void;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const FileList: React.FC<FileListProps> = ({\n files,\n selected_file_id,\n config,\n on_select,\n on_delete,\n on_add_click,\n on_files_selected,\n className,\n}) => {\n const scroll_ref = useRef<HTMLDivElement>(null);\n const file_input_ref = useRef<HTMLInputElement>(null);\n const drag_counter = useRef(0);\n const [can_scroll_left, setCanScrollLeft] = useState(false);\n const [can_scroll_right, setCanScrollRight] = useState(false);\n const [is_dragging, setIsDragging] = useState(false);\n\n const file_manager_config = config?.file_manager;\n const upload_config = config?.file_upload;\n const is_direct_upload = !!on_files_selected;\n\n // Parse allowed types for file input accept attribute\n const accept_string = upload_config?.allowed_types || 'application/pdf';\n\n // Check scroll state\n const update_scroll_state = () => {\n if (!scroll_ref.current) return;\n\n const { scrollLeft, scrollWidth, clientWidth } = scroll_ref.current;\n setCanScrollLeft(scrollLeft > 0);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n };\n\n // Update scroll state on mount and when files change\n useEffect(() => {\n update_scroll_state();\n window.addEventListener('resize', update_scroll_state);\n return () => window.removeEventListener('resize', update_scroll_state);\n }, [files]);\n\n // Scroll handlers\n const scroll_left = () => {\n if (scroll_ref.current) {\n scroll_ref.current.scrollBy({ left: -200, behavior: 'smooth' });\n }\n };\n\n const scroll_right = () => {\n if (scroll_ref.current) {\n scroll_ref.current.scrollBy({ left: 200, behavior: 'smooth' });\n }\n };\n\n // Scroll selected file into view\n useEffect(() => {\n if (!scroll_ref.current || !selected_file_id) return;\n\n const selected_element = scroll_ref.current.querySelector(\n `[data-file-id=\"${selected_file_id}\"]`\n );\n if (selected_element) {\n selected_element.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }\n }, [selected_file_id]);\n\n // Direct upload: click opens file picker\n const handle_add_click = useCallback(() => {\n if (is_direct_upload) {\n file_input_ref.current?.click();\n } else {\n on_add_click?.();\n }\n }, [is_direct_upload, on_add_click]);\n\n // Direct upload: file input change\n const handle_input_change = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n on_files_selected?.(Array.from(e.target.files));\n e.target.value = '';\n }\n }, [on_files_selected]);\n\n // Direct upload: drag handlers for add button\n const handle_drag_enter = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current++;\n if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {\n setIsDragging(true);\n }\n }, []);\n\n const handle_drag_leave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current--;\n if (drag_counter.current === 0) {\n setIsDragging(false);\n }\n }, []);\n\n const handle_drag_over = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handle_drop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n drag_counter.current = 0;\n if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n on_files_selected?.(Array.from(e.dataTransfer.files));\n }\n }, [on_files_selected]);\n\n const height = file_manager_config?.file_list_height || 60;\n const background_color = file_manager_config?.file_list_background_color || '#f3f4f6';\n const border_color = file_manager_config?.file_list_border_color || '#e5e7eb';\n const allow_delete = file_manager_config?.allow_delete ?? true;\n const show_add_button = upload_config?.show_add_button ?? true;\n const has_add_handler = is_direct_upload || !!on_add_click;\n\n return (\n <div\n className={cn('cls_file_list_container', className)}\n style={{\n minHeight: `${height}px`,\n backgroundColor: background_color,\n borderBottomColor: border_color,\n }}\n >\n {/* Scroll left button */}\n <button\n className={cn(\n 'cls_file_list_scroll_btn cls_file_list_scroll_btn_left',\n !can_scroll_left && 'cls_file_list_scroll_btn_disabled'\n )}\n onClick={scroll_left}\n disabled={!can_scroll_left}\n aria-label=\"Scroll left\"\n title=\"Scroll left\"\n >\n <ChevronLeft size={16} />\n </button>\n\n {/* Scrollable file list */}\n <div\n ref={scroll_ref}\n className=\"cls_file_list_scroll\"\n onScroll={update_scroll_state}\n >\n {files.map((file) => (\n <FileListItem\n key={file.id}\n file={file}\n is_selected={file.id === selected_file_id}\n show_delete={allow_delete}\n config={config}\n on_select={on_select}\n on_delete={on_delete}\n />\n ))}\n\n {/* Add button - in direct_upload mode, also acts as dropzone */}\n {show_add_button && has_add_handler && (\n <>\n <button\n className={cn(\n 'cls_file_list_add_btn',\n is_dragging && 'cls_file_list_add_btn_dragging'\n )}\n onClick={handle_add_click}\n onDragEnter={is_direct_upload ? handle_drag_enter : undefined}\n onDragLeave={is_direct_upload ? handle_drag_leave : undefined}\n onDragOver={is_direct_upload ? handle_drag_over : undefined}\n onDrop={is_direct_upload ? handle_drop : undefined}\n aria-label=\"Add file\"\n title={is_direct_upload ? 'Click to browse or drag files here' : 'Add file'}\n >\n <Plus size={16} />\n <span className=\"cls_file_list_add_btn_text\">\n {is_dragging ? 'Drop here' : 'Add file'}\n </span>\n </button>\n {/* Hidden file input for direct upload mode */}\n {is_direct_upload && (\n <input\n ref={file_input_ref}\n type=\"file\"\n accept={accept_string}\n multiple\n onChange={handle_input_change}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n )}\n </>\n )}\n </div>\n\n {/* Scroll right button */}\n <button\n className={cn(\n 'cls_file_list_scroll_btn cls_file_list_scroll_btn_right',\n !can_scroll_right && 'cls_file_list_scroll_btn_disabled'\n )}\n onClick={scroll_right}\n disabled={!can_scroll_right}\n aria-label=\"Scroll right\"\n title=\"Scroll right\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n );\n};\n\nexport default FileList;\n","/**\n * File List Item Component\n * Simple horizontal tab-style file item\n */\n\nimport React, { useState } from 'react';\nimport { X, FileText, Loader2 } from 'lucide-react';\nimport type { FileItem } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { cn } from '../../utils/cn';\n\nexport interface FileListItemProps {\n /** File to display */\n file: FileItem;\n /** Whether this file is currently selected */\n is_selected: boolean;\n /** Whether to show delete button */\n show_delete: boolean;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when file is selected */\n on_select: (file: FileItem) => void;\n /** Callback when delete is clicked */\n on_delete?: (file_id: string) => void;\n}\n\n/**\n * Get display name - truncate if needed\n */\nfunction get_display_name(filename: string, max_length: number = 24): string {\n if (filename.length <= max_length) {\n return filename;\n }\n\n const ext_index = filename.lastIndexOf('.');\n if (ext_index === -1 || ext_index === 0) {\n return filename.substring(0, max_length - 3) + '...';\n }\n\n const ext = filename.substring(ext_index);\n const name = filename.substring(0, ext_index);\n const available = max_length - ext.length - 3;\n\n if (available <= 0) {\n return filename.substring(0, max_length - 3) + '...';\n }\n\n return name.substring(0, available) + '...' + ext;\n}\n\nexport const FileListItem: React.FC<FileListItemProps> = ({\n file,\n is_selected,\n show_delete,\n config,\n on_select,\n on_delete,\n}) => {\n const [is_hovered, setIsHovered] = useState(false);\n\n const file_manager_config = config?.file_manager;\n const selected_color = file_manager_config?.selected_color || '#3b82f6';\n\n const handle_click = () => {\n on_select(file);\n };\n\n const handle_delete_click = (e: React.MouseEvent) => {\n e.stopPropagation();\n on_delete?.(file.id);\n };\n\n const display_name = get_display_name(file.name);\n const show_close = show_delete && on_delete && (is_hovered || is_selected);\n\n return (\n <div\n className={cn(\n 'cls_file_tab',\n is_selected && 'cls_file_tab_selected'\n )}\n data-file-id={file.id}\n style={is_selected ? {\n borderColor: selected_color,\n } : undefined}\n onClick={handle_click}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n title={file.name}\n role=\"tab\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handle_click();\n }\n }}\n aria-selected={is_selected}\n aria-label={file.name}\n >\n {file.status === 'converting' || file.status === 'uploading' ? (\n <Loader2 size={16} className=\"cls_file_tab_icon cls_file_tab_spinner\" />\n ) : file.type === 'pdf' ? (\n <FileText size={16} className=\"cls_file_tab_icon\" />\n ) : null}\n <span className=\"cls_file_tab_name\">\n {display_name}\n </span>\n\n {show_close && (\n <button\n className=\"cls_file_tab_close\"\n onClick={handle_delete_click}\n aria-label={`Close ${file.name}`}\n title={`Close ${file.name}`}\n >\n <X size={14} />\n </button>\n )}\n </div>\n );\n};\n\nexport default FileListItem;\n","/**\n * Upload Dropzone Component\n * Drag-and-drop file upload zone with click-to-upload support\n */\n\nimport React, { useState, useRef, useCallback } from 'react';\nimport { Upload, X } from 'lucide-react';\nimport type { PdfViewerConfig } from '../../types/config';\nimport type { UploadProgress } from './types';\nimport { UploadProgressDisplay } from './upload_progress';\nimport { cn } from '../../utils/cn';\n\nexport interface UploadDropzoneProps {\n /** Configuration for styling and upload settings */\n config: PdfViewerConfig | null;\n /** Current upload progress items */\n uploads: UploadProgress[];\n /** Callback when files are selected for upload */\n on_files_selected: (files: File[]) => void;\n /** Whether the dropzone is disabled */\n disabled?: boolean;\n /** Callback to close the dropzone (for modal mode) */\n on_close?: () => void;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const UploadDropzone: React.FC<UploadDropzoneProps> = ({\n config,\n uploads,\n on_files_selected,\n disabled = false,\n on_close,\n className,\n}) => {\n const [is_dragging, setIsDragging] = useState(false);\n const [validation_error, setValidationError] = useState<string | null>(null);\n const input_ref = useRef<HTMLInputElement>(null);\n const drag_counter = useRef(0);\n\n const upload_config = config?.file_upload;\n\n // Parse allowed types from config\n const allowed_types = (upload_config?.allowed_types || 'application/pdf').split(',').map(t => t.trim());\n const max_file_size = upload_config?.max_file_size || 10485760; // 10MB\n const max_files = upload_config?.max_files || 10;\n\n /**\n * Validate a single file\n */\n const validate_file = useCallback((file: File): string | null => {\n // Check file type\n const is_type_allowed = allowed_types.some(type => {\n const trimmed = type.trim().toLowerCase();\n const file_type = file.type.toLowerCase();\n\n // Handle wildcard patterns like image/*\n if (trimmed.endsWith('/*')) {\n const prefix = trimmed.slice(0, -2);\n return file_type.startsWith(prefix);\n }\n\n return file_type === trimmed;\n });\n\n if (!is_type_allowed) {\n return `File type \"${file.type || 'unknown'}\" is not allowed`;\n }\n\n // Check file size\n if (file.size > max_file_size) {\n const max_mb = Math.round(max_file_size / 1024 / 1024);\n const file_mb = (file.size / 1024 / 1024).toFixed(1);\n return `File is too large (${file_mb}MB). Maximum size is ${max_mb}MB`;\n }\n\n return null;\n }, [allowed_types, max_file_size]);\n\n /**\n * Handle selected files (from drag or click)\n */\n const handle_files = useCallback((file_list: FileList | File[]) => {\n const files = Array.from(file_list);\n setValidationError(null);\n\n if (files.length === 0) {\n return;\n }\n\n // Check max files limit\n if (files.length > max_files) {\n setValidationError(`Too many files. Maximum is ${max_files} files.`);\n return;\n }\n\n // Validate each file\n const valid_files: File[] = [];\n const errors: string[] = [];\n\n for (const file of files) {\n const error = validate_file(file);\n if (error) {\n errors.push(`${file.name}: ${error}`);\n } else {\n valid_files.push(file);\n }\n }\n\n // Show first error if any\n if (errors.length > 0) {\n setValidationError(errors[0]);\n }\n\n // Process valid files\n if (valid_files.length > 0) {\n on_files_selected(valid_files);\n }\n }, [max_files, validate_file, on_files_selected]);\n\n // Drag handlers\n const handle_drag_enter = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current++;\n if (!disabled && e.dataTransfer.items && e.dataTransfer.items.length > 0) {\n setIsDragging(true);\n }\n };\n\n const handle_drag_leave = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current--;\n if (drag_counter.current === 0) {\n setIsDragging(false);\n }\n };\n\n const handle_drag_over = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n const handle_drop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n drag_counter.current = 0;\n\n if (!disabled && e.dataTransfer.files) {\n handle_files(e.dataTransfer.files);\n }\n };\n\n // Click handler\n const handle_click = () => {\n if (!disabled) {\n input_ref.current?.click();\n }\n };\n\n // File input change handler\n const handle_input_change = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files) {\n handle_files(e.target.files);\n // Reset input value so same file can be selected again\n e.target.value = '';\n }\n };\n\n // Get accept string for file input\n const accept_string = allowed_types.join(',');\n\n // Styling from config\n const border_color = is_dragging\n ? (upload_config?.dropzone_border_color_active || '#3b82f6')\n : (upload_config?.dropzone_border_color || '#d1d5db');\n const background_color = upload_config?.dropzone_background_color || '#f9fafb';\n\n return (\n <div className={cn('cls_upload_dropzone_wrapper', className)}>\n {/* Close button for modal mode */}\n {on_close && (\n <button\n className=\"cls_upload_dropzone_close_btn\"\n onClick={on_close}\n aria-label=\"Close\"\n >\n <X size={20} />\n </button>\n )}\n\n {/* Dropzone area */}\n <div\n className={cn(\n 'cls_upload_dropzone',\n is_dragging && 'cls_upload_dropzone_active',\n disabled && 'cls_upload_dropzone_disabled'\n )}\n style={{\n borderColor: border_color,\n backgroundColor: is_dragging ? `${border_color}10` : background_color,\n }}\n onDragEnter={handle_drag_enter}\n onDragLeave={handle_drag_leave}\n onDragOver={handle_drag_over}\n onDrop={handle_drop}\n onClick={handle_click}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onKeyDown={(e) => {\n if ((e.key === 'Enter' || e.key === ' ') && !disabled) {\n e.preventDefault();\n handle_click();\n }\n }}\n aria-label=\"Drop files here or click to upload\"\n aria-disabled={disabled}\n >\n <input\n ref={input_ref}\n type=\"file\"\n accept={accept_string}\n multiple\n onChange={handle_input_change}\n className=\"cls_upload_dropzone_input\"\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n\n <Upload\n size={40}\n className={cn(\n 'cls_upload_dropzone_icon',\n is_dragging && 'cls_upload_dropzone_icon_active'\n )}\n style={{ color: is_dragging ? border_color : '#9ca3af' }}\n />\n\n <p className=\"cls_upload_dropzone_text\">\n {is_dragging ? 'Drop files here' : 'Drop files here or click to upload'}\n </p>\n\n <p className=\"cls_upload_dropzone_hint\">\n PDF, images, text files, or Excel spreadsheets\n </p>\n\n {/* Validation error */}\n {validation_error && (\n <p className=\"cls_upload_dropzone_error\">\n {validation_error}\n </p>\n )}\n </div>\n\n {/* Upload progress */}\n <UploadProgressDisplay uploads={uploads} />\n </div>\n );\n};\n\nexport default UploadDropzone;\n","/**\n * Upload Progress Component\n * Shows upload progress for files being uploaded/converted\n */\n\nimport React from 'react';\nimport { Loader2, CheckCircle, XCircle } from 'lucide-react';\nimport type { UploadProgress } from './types';\nimport { cn } from '../../utils/cn';\n\nexport interface UploadProgressProps {\n /** Array of upload progress items */\n uploads: UploadProgress[];\n /** Additional CSS class name */\n className?: string;\n}\n\n/**\n * Get status icon based on upload status\n */\nfunction get_status_icon(status: UploadProgress['status']) {\n switch (status) {\n case 'complete':\n return <CheckCircle size={16} className=\"cls_upload_progress_icon_success\" />;\n case 'error':\n return <XCircle size={16} className=\"cls_upload_progress_icon_error\" />;\n case 'converting':\n case 'uploading':\n case 'pending':\n return <Loader2 size={16} className=\"cls_upload_progress_icon_loading\" />;\n default:\n return null;\n }\n}\n\n/**\n * Get status text for display\n */\nfunction get_status_text(upload: UploadProgress): string {\n switch (upload.status) {\n case 'pending':\n return 'Waiting...';\n case 'uploading':\n return `${upload.progress}%`;\n case 'converting':\n return 'Converting...';\n case 'complete':\n return 'Done';\n case 'error':\n return upload.error_message || 'Failed';\n default:\n return '';\n }\n}\n\nexport const UploadProgressDisplay: React.FC<UploadProgressProps> = ({\n uploads,\n className,\n}) => {\n if (uploads.length === 0) {\n return null;\n }\n\n return (\n <div className={cn('cls_upload_progress_container', className)}>\n {uploads.map((upload) => (\n <div\n key={upload.file_id}\n className={cn(\n 'cls_upload_progress_item',\n upload.status === 'error' && 'cls_upload_progress_item_error',\n upload.status === 'complete' && 'cls_upload_progress_item_complete'\n )}\n >\n <div className=\"cls_upload_progress_icon\">\n {get_status_icon(upload.status)}\n </div>\n\n <span className=\"cls_upload_progress_filename\" title={upload.filename}>\n {upload.filename}\n </span>\n\n <div className=\"cls_upload_progress_bar_container\">\n <div\n className={cn(\n 'cls_upload_progress_bar',\n upload.status === 'error' && 'cls_upload_progress_bar_error',\n upload.status === 'complete' && 'cls_upload_progress_bar_complete'\n )}\n style={{ width: `${upload.progress}%` }}\n />\n </div>\n\n <span className=\"cls_upload_progress_status\">\n {get_status_text(upload)}\n </span>\n </div>\n ))}\n </div>\n );\n};\n\nexport default UploadProgressDisplay;\n","/**\n * File Manager Button Component\n * Compact trigger button with badge showing file count\n */\n\nimport React, { useState } from 'react';\nimport { FaFileAlt, FaFolderOpen } from 'react-icons/fa';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { cn } from '../../utils/cn';\n\nexport interface FileManagerButtonProps {\n /** Number of files in the file manager */\n file_count: number;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when button is clicked */\n on_click: () => void;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** Custom tooltip text */\n tooltip?: string;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const FileManagerButton: React.FC<FileManagerButtonProps> = ({\n file_count,\n config,\n on_click,\n disabled = false,\n tooltip,\n className,\n}) => {\n const [is_hovered, setIsHovered] = useState(false);\n\n const button_config = config?.file_button;\n\n const icon_size = button_config?.icon_size || 24;\n\n // Determine icon color based on state\n let icon_color = button_config?.icon_color || '#6b7280';\n if (file_count > 0) {\n icon_color = button_config?.icon_color_with_files || '#3b82f6';\n }\n if (is_hovered && !disabled) {\n icon_color = button_config?.icon_color_hover || '#374151';\n if (file_count > 0) {\n icon_color = button_config?.icon_color_with_files || '#3b82f6';\n }\n }\n\n const badge_background = button_config?.badge_background || '#3b82f6';\n const badge_text_color = button_config?.badge_text_color || '#ffffff';\n\n // Format badge count\n const badge_text = file_count > 99 ? '99+' : file_count.toString();\n\n // Generate tooltip text\n const tooltip_text = tooltip || (\n file_count === 0\n ? 'No files'\n : file_count === 1\n ? '1 file'\n : `${file_count} files`\n );\n\n return (\n <button\n className={cn(\n 'cls_file_manager_button',\n disabled && 'cls_file_manager_button_disabled',\n className\n )}\n onClick={on_click}\n disabled={disabled}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n aria-label={tooltip_text}\n title={tooltip_text}\n >\n {file_count > 0 ? (\n <FaFolderOpen size={icon_size} style={{ color: icon_color }} />\n ) : (\n <FaFileAlt size={icon_size} style={{ color: icon_color }} />\n )}\n\n {file_count > 0 && (\n <span\n className=\"cls_file_manager_button_badge\"\n style={{\n backgroundColor: badge_background,\n color: badge_text_color,\n }}\n >\n {badge_text}\n </span>\n )}\n </button>\n );\n};\n\nexport default FileManagerButton;\n","/**\n * PDF Converter Utility\n * Converts images and text files to PDF using pdf-lib\n * This module is standalone and can be tested independently\n */\n\nimport { get_logger } from './logger';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SupportedImageType =\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp';\n\nexport type SupportedTextType =\n | 'text/plain'\n | 'text/markdown'\n | 'text/csv';\n\nexport type SupportedExcelType =\n | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' // .xlsx\n | 'application/vnd.ms-excel' // .xls\n | 'application/vnd.google-apps.spreadsheet'; // Google Sheets (when exported)\n\nexport type SupportedConversionType = SupportedImageType | SupportedTextType | SupportedExcelType;\n\nexport interface PdfConversionOptions {\n /** Page size: 'letter' (612x792), 'a4' (595x842), 'legal' (612x1008) */\n page_size?: 'letter' | 'a4' | 'legal';\n /** Image quality 0.0-1.0 for lossy compression (default: 0.85) */\n image_quality?: number;\n /** How image fits on page: 'fit' (preserve aspect), 'fill' (crop), 'stretch' */\n image_fit?: 'fit' | 'fill' | 'stretch';\n /** Margin in points (72 points = 1 inch, default: 36) */\n margin?: number;\n /** Font size for text files in points (default: 12) */\n font_size?: number;\n /** Line height multiplier for text files (default: 1.4) */\n line_height?: number;\n}\n\nexport interface ConversionResult {\n /** Whether conversion succeeded */\n success: boolean;\n /** Converted PDF as Uint8Array (if success) */\n pdf_bytes?: Uint8Array;\n /** Original filename without extension */\n original_name?: string;\n /** Generated PDF filename */\n pdf_filename?: string;\n /** Original file type that was converted */\n source_type?: 'image' | 'text' | 'excel';\n /** Number of pages in the resulting PDF */\n page_count?: number;\n /** Error message (if !success) */\n error?: string;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst PAGE_SIZES = {\n letter: { width: 612, height: 792 },\n a4: { width: 595, height: 842 },\n legal: { width: 612, height: 1008 },\n} as const;\n\nconst SUPPORTED_IMAGE_TYPES: SupportedImageType[] = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n];\n\nconst SUPPORTED_TEXT_TYPES: SupportedTextType[] = [\n 'text/plain',\n 'text/markdown',\n 'text/csv',\n];\n\nconst SUPPORTED_EXCEL_TYPES: SupportedExcelType[] = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel',\n 'application/vnd.google-apps.spreadsheet',\n];\n\nconst DEFAULT_OPTIONS: Required<PdfConversionOptions> = {\n page_size: 'letter',\n image_quality: 0.85,\n image_fit: 'fit',\n margin: 36,\n font_size: 12,\n line_height: 1.4,\n};\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Check if a MIME type can be converted to PDF\n * @param mime_type - MIME type to check\n * @returns true if the type is supported for conversion\n */\nexport function can_convert_to_pdf(mime_type: string): boolean {\n const normalized = mime_type.toLowerCase().trim();\n return (\n SUPPORTED_IMAGE_TYPES.includes(normalized as SupportedImageType) ||\n SUPPORTED_TEXT_TYPES.includes(normalized as SupportedTextType) ||\n SUPPORTED_EXCEL_TYPES.includes(normalized as SupportedExcelType)\n );\n}\n\n/**\n * Get list of supported MIME types for conversion\n * @returns Array of supported MIME types\n */\nexport function get_supported_types(): string[] {\n return [...SUPPORTED_IMAGE_TYPES, ...SUPPORTED_TEXT_TYPES, ...SUPPORTED_EXCEL_TYPES];\n}\n\n/**\n * Check if a MIME type is an image type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported image type\n */\nexport function is_image_type(mime_type: string): boolean {\n return SUPPORTED_IMAGE_TYPES.includes(mime_type.toLowerCase().trim() as SupportedImageType);\n}\n\n/**\n * Check if a MIME type is a text type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported text type\n */\nexport function is_text_type(mime_type: string): boolean {\n return SUPPORTED_TEXT_TYPES.includes(mime_type.toLowerCase().trim() as SupportedTextType);\n}\n\n/**\n * Check if a MIME type is an Excel/spreadsheet type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported Excel type\n */\nexport function is_excel_type(mime_type: string): boolean {\n return SUPPORTED_EXCEL_TYPES.includes(mime_type.toLowerCase().trim() as SupportedExcelType);\n}\n\n/**\n * Convert a file to PDF\n * @param file - File or Blob to convert\n * @param filename - Original filename (used for output naming)\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_to_pdf(\n file: File | Blob,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const mime_type = file.type.toLowerCase().trim();\n\n if (!can_convert_to_pdf(mime_type)) {\n return {\n success: false,\n error: `Unsupported file type: ${mime_type}. Supported types: ${get_supported_types().join(', ')}`,\n };\n }\n\n try {\n if (is_image_type(mime_type)) {\n const image_bytes = new Uint8Array(await file.arrayBuffer());\n return await convert_image_to_pdf(\n image_bytes,\n mime_type as SupportedImageType,\n filename,\n options\n );\n }\n\n if (is_text_type(mime_type)) {\n const text_content = await file.text();\n return await convert_text_to_pdf(text_content, filename, options);\n }\n\n if (is_excel_type(mime_type)) {\n const excel_bytes = new Uint8Array(await file.arrayBuffer());\n return await convert_excel_to_pdf(excel_bytes, filename, options);\n }\n\n return {\n success: false,\n error: `Conversion not implemented for type: ${mime_type}`,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting file', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during conversion',\n };\n }\n}\n\n/**\n * Convert image bytes to PDF\n * @param image_bytes - Raw image data as Uint8Array\n * @param mime_type - Image MIME type\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_image_to_pdf(\n image_bytes: Uint8Array,\n mime_type: SupportedImageType,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const page_size = PAGE_SIZES[opts.page_size];\n\n try {\n // Dynamically import pdf-lib\n const { PDFDocument } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting image to PDF', { filename, mime_type });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed the image based on type\n let embedded_image;\n\n if (mime_type === 'image/jpeg') {\n logger.debug('Embedding JPEG image directly', { bytes: image_bytes.length });\n embedded_image = await pdf_doc.embedJpg(image_bytes);\n } else if (mime_type === 'image/png') {\n logger.debug('Embedding PNG image directly', { bytes: image_bytes.length });\n embedded_image = await pdf_doc.embedPng(image_bytes);\n } else if (mime_type === 'image/gif' || mime_type === 'image/webp') {\n // GIF and WebP need to be converted to PNG first via canvas\n logger.debug('Converting image via canvas', { mime_type, bytes: image_bytes.length });\n const png_bytes = await convert_image_via_canvas(image_bytes, mime_type);\n logger.debug('Image converted to PNG', { original_bytes: image_bytes.length, png_bytes: png_bytes.length });\n embedded_image = await pdf_doc.embedPng(png_bytes);\n } else {\n return {\n success: false,\n error: `Unsupported image type: ${mime_type}`,\n };\n }\n\n // Calculate image dimensions to fit on page\n const { width: img_width, height: img_height } = embedded_image;\n const available_width = page_size.width - (opts.margin * 2);\n const available_height = page_size.height - (opts.margin * 2);\n\n let draw_width: number;\n let draw_height: number;\n\n if (opts.image_fit === 'stretch') {\n // Stretch to fill available area\n draw_width = available_width;\n draw_height = available_height;\n } else if (opts.image_fit === 'fill') {\n // Fill available area (may crop)\n const scale = Math.max(\n available_width / img_width,\n available_height / img_height\n );\n draw_width = img_width * scale;\n draw_height = img_height * scale;\n } else {\n // 'fit' - preserve aspect ratio, fit within available area\n const scale = Math.min(\n available_width / img_width,\n available_height / img_height\n );\n draw_width = img_width * scale;\n draw_height = img_height * scale;\n }\n\n // Center the image on the page\n const draw_x = opts.margin + (available_width - draw_width) / 2;\n const draw_y = opts.margin + (available_height - draw_height) / 2;\n\n // Add a page and draw the image\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n page.drawImage(embedded_image, {\n x: draw_x,\n y: draw_y,\n width: draw_width,\n height: draw_height,\n });\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Image converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'image',\n page_count: 1,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting image', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting image',\n };\n }\n}\n\n/**\n * Convert text content to PDF\n * @param text_content - Text string to convert\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_text_to_pdf(\n text_content: string,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const page_size = PAGE_SIZES[opts.page_size];\n\n try {\n // Dynamically import pdf-lib\n const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting text to PDF', { filename, content_length: text_content.length });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed a standard font\n const font = await pdf_doc.embedFont(StandardFonts.Helvetica);\n\n // Calculate text area dimensions\n const margin = opts.margin;\n const font_size = opts.font_size;\n const line_height = font_size * opts.line_height;\n const available_width = page_size.width - (margin * 2);\n const available_height = page_size.height - (margin * 2);\n const lines_per_page = Math.floor(available_height / line_height);\n\n // Split text into lines that fit within the page width\n const lines = wrap_text(text_content, font, font_size, available_width);\n\n // Create pages and draw text\n let current_line = 0;\n let page_count = 0;\n\n while (current_line < lines.length) {\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n page_count++;\n\n let y = page_size.height - margin - font_size;\n\n for (let i = 0; i < lines_per_page && current_line < lines.length; i++) {\n page.drawText(lines[current_line], {\n x: margin,\n y: y,\n size: font_size,\n font: font,\n color: rgb(0, 0, 0),\n });\n\n y -= line_height;\n current_line++;\n }\n }\n\n // Ensure at least one page exists\n if (page_count === 0) {\n pdf_doc.addPage([page_size.width, page_size.height]);\n page_count = 1;\n }\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Text converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length, pages: page_count });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'text',\n page_count,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting text', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting text',\n };\n }\n}\n\n/**\n * Convert Excel spreadsheet to PDF\n * Fits all columns on one page by scaling down (zooming out) if needed\n * Includes row numbers and column letters like Excel\n * @param excel_bytes - Raw Excel data as Uint8Array\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_excel_to_pdf(\n excel_bytes: Uint8Array,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const base_page_size = PAGE_SIZES[opts.page_size];\n // Use landscape orientation for Excel (swap width and height)\n const page_size = { width: base_page_size.height, height: base_page_size.width };\n\n try {\n // Dynamically import xlsx and pdf-lib\n const XLSX = await import('xlsx');\n const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting Excel to PDF', { filename, orientation: 'landscape' });\n\n // Parse the Excel workbook\n const workbook = XLSX.read(excel_bytes, { type: 'array' });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed fonts\n const font = await pdf_doc.embedFont(StandardFonts.Helvetica);\n const bold_font = await pdf_doc.embedFont(StandardFonts.HelveticaBold);\n\n // Layout constants (base values - will be scaled per page)\n const margin = opts.margin;\n const font_size = opts.font_size;\n const small_font_size = font_size - 2;\n const title_font_size = font_size + 2;\n const line_height = font_size * opts.line_height;\n const cell_padding = 5;\n const row_num_width = 35; // Width for row number column\n const available_width = page_size.width - (margin * 2) - row_num_width;\n const available_height = page_size.height - (margin * 2);\n\n // Collect all pages info first, then render with correct page numbers\n interface PageInfo {\n sheet_name: string;\n sheet_idx: number;\n start_row: number;\n end_row: number;\n col_widths: number[]; // Scaled column widths\n scale: number; // Scale factor applied to fit columns on page\n }\n const all_pages: PageInfo[] = [];\n\n // Process each sheet to collect page info\n for (let sheet_idx = 0; sheet_idx < workbook.SheetNames.length; sheet_idx++) {\n const sheet_name = workbook.SheetNames[sheet_idx];\n const sheet = workbook.Sheets[sheet_name];\n\n // Get the range of data in the sheet\n const range = XLSX.utils.decode_range(sheet['!ref'] || 'A1');\n const num_cols = range.e.c - range.s.c + 1;\n\n if (num_cols === 0) continue;\n\n // Convert sheet to 2D array\n const data: string[][] = XLSX.utils.sheet_to_json(sheet, {\n header: 1,\n defval: ''\n }) as string[][];\n\n if (data.length === 0) continue;\n\n // Calculate optimal column widths\n const col_widths = calculate_optimal_column_widths(data, font, font_size, num_cols);\n\n // Calculate scale factor to fit all columns on one page\n const total_width = col_widths.reduce((sum, w) => sum + w, 0);\n const scale = total_width > available_width ? available_width / total_width : 1;\n const scaled_col_widths = col_widths.map(w => w * scale);\n\n logger.debug('Excel sheet scale calculation', {\n sheet_name,\n num_cols,\n total_width,\n available_width,\n scale: Math.round(scale * 100) / 100,\n rows: data.length,\n });\n\n // Calculate rows per page using scaled dimensions\n const scaled_line_height = line_height * scale;\n const scaled_cell_padding = cell_padding * scale;\n const scaled_title_height = title_font_size * scale * 2;\n const scaled_col_label_height = (small_font_size * scale) + 4;\n const row_height = scaled_line_height + scaled_cell_padding * 2;\n const content_height = available_height - scaled_title_height - scaled_col_label_height - row_height;\n const rows_per_page = Math.floor(content_height / row_height);\n\n // Generate pages: one page per vertical section (all columns fit on each page)\n let current_row = 1; // Start after header\n while (current_row < data.length) {\n const end_row = Math.min(current_row + rows_per_page, data.length);\n\n all_pages.push({\n sheet_name,\n sheet_idx,\n start_row: current_row,\n end_row,\n col_widths: scaled_col_widths,\n scale,\n });\n\n current_row = end_row;\n }\n }\n\n // Now render all pages\n for (let page_num = 0; page_num < all_pages.length; page_num++) {\n const page_info = all_pages[page_num];\n const sheet = workbook.Sheets[page_info.sheet_name];\n const data: string[][] = XLSX.utils.sheet_to_json(sheet, {\n header: 1,\n defval: ''\n }) as string[][];\n\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n\n // Use scaled dimensions\n const scale = page_info.scale;\n const scaled_font_size = font_size * scale;\n const scaled_small_font_size = small_font_size * scale;\n const scaled_title_font_size = title_font_size * scale;\n const scaled_line_height = line_height * scale;\n const scaled_cell_padding = cell_padding * scale;\n const scaled_row_num_width = row_num_width * scale;\n const scaled_title_height = scaled_title_font_size * 2;\n const scaled_col_label_height = scaled_small_font_size + 4;\n const row_height = scaled_line_height + scaled_cell_padding * 2;\n\n let y = page_size.height - margin;\n\n // Draw title with sheet name (only if multiple sheets)\n const show_sheet_name = workbook.SheetNames.length > 1;\n if (show_sheet_name) {\n page.drawText(`Sheet: ${page_info.sheet_name}`, {\n x: margin,\n y: y - scaled_title_font_size,\n size: scaled_title_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n y -= scaled_title_height;\n }\n\n // Calculate table width for this page\n const table_width = page_info.col_widths.reduce((sum, w) => sum + w, 0);\n const num_cols = page_info.col_widths.length;\n\n // Draw column letter row (A, B, C...)\n let x = margin + scaled_row_num_width;\n page.drawRectangle({\n x: margin,\n y: y - scaled_col_label_height,\n width: scaled_row_num_width + table_width,\n height: scaled_col_label_height,\n color: rgb(0.85, 0.85, 0.85),\n });\n\n // Empty cell for row number column header\n page.drawRectangle({\n x: margin,\n y: y - scaled_col_label_height,\n width: scaled_row_num_width,\n height: scaled_col_label_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const col_letter = column_index_to_letter(col_idx);\n\n // Center the column letter\n const letter_width = font.widthOfTextAtSize(col_letter, scaled_small_font_size);\n page.drawText(col_letter, {\n x: x + (col_width - letter_width) / 2,\n y: y - scaled_col_label_height + 3,\n size: scaled_small_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n\n page.drawRectangle({\n x: x,\n y: y - scaled_col_label_height,\n width: col_width,\n height: scaled_col_label_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n y -= scaled_col_label_height;\n\n // Draw header row (row 1 from data)\n const header_row = data[0] || [];\n x = margin;\n\n // Row number for header (1)\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n color: rgb(0.85, 0.85, 0.85),\n });\n const row_1_text = '1';\n const row_1_width = font.widthOfTextAtSize(row_1_text, scaled_small_font_size);\n page.drawText(row_1_text, {\n x: margin + (scaled_row_num_width - row_1_width) / 2,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_small_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x = margin + scaled_row_num_width;\n\n // Draw header background\n page.drawRectangle({\n x: margin + scaled_row_num_width,\n y: y - row_height,\n width: table_width,\n height: row_height,\n color: rgb(0.9, 0.9, 0.9),\n });\n\n // Draw header cells\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const cell_value = String(header_row[col_idx] || '');\n const truncated = truncate_text(cell_value, font, scaled_font_size, col_width - scaled_cell_padding * 2);\n\n page.drawText(truncated, {\n x: x + scaled_cell_padding,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_font_size,\n font: bold_font,\n color: rgb(0, 0, 0),\n });\n\n page.drawRectangle({\n x: x,\n y: y - row_height,\n width: col_width,\n height: row_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n\n y -= row_height;\n\n // Draw data rows\n for (let row_idx = page_info.start_row; row_idx < page_info.end_row; row_idx++) {\n const row = data[row_idx] || [];\n x = margin;\n\n // Row number cell\n const row_num = row_idx + 1; // Excel rows are 1-indexed\n const row_num_text = String(row_num);\n const row_num_text_width = font.widthOfTextAtSize(row_num_text, scaled_small_font_size);\n\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n color: rgb(0.92, 0.92, 0.92),\n });\n page.drawText(row_num_text, {\n x: margin + (scaled_row_num_width - row_num_text_width) / 2,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_small_font_size,\n font: font,\n color: rgb(0.4, 0.4, 0.4),\n });\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n borderColor: rgb(0.7, 0.7, 0.7),\n borderWidth: 0.5,\n });\n\n x = margin + scaled_row_num_width;\n\n // Alternate row background\n if ((row_idx - page_info.start_row) % 2 === 1) {\n page.drawRectangle({\n x: margin + scaled_row_num_width,\n y: y - row_height,\n width: table_width,\n height: row_height,\n color: rgb(0.97, 0.97, 0.97),\n });\n }\n\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const cell_value = String(row[col_idx] || '');\n const truncated = truncate_text(cell_value, font, scaled_font_size, col_width - scaled_cell_padding * 2);\n\n page.drawText(truncated, {\n x: x + scaled_cell_padding,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_font_size,\n font: font,\n color: rgb(0, 0, 0),\n });\n\n page.drawRectangle({\n x: x,\n y: y - row_height,\n width: col_width,\n height: row_height,\n borderColor: rgb(0.7, 0.7, 0.7),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n\n y -= row_height;\n }\n }\n\n const total_page_count = pdf_doc.getPageCount();\n\n // Ensure at least one page exists\n if (total_page_count === 0) {\n pdf_doc.addPage([page_size.width, page_size.height]);\n }\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Excel converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length, pages: pdf_doc.getPageCount() });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'excel',\n page_count: pdf_doc.getPageCount(),\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting Excel', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting Excel',\n };\n }\n}\n\n// =============================================================================\n// Internal Helpers\n// =============================================================================\n\n/**\n * Convert column index to Excel-style letter (0 -> A, 1 -> B, 25 -> Z, 26 -> AA, etc.)\n * @param index - Zero-based column index\n * @returns Column letter(s)\n */\nfunction column_index_to_letter(index: number): string {\n let result = '';\n let num = index;\n\n while (num >= 0) {\n result = String.fromCharCode((num % 26) + 65) + result;\n num = Math.floor(num / 26) - 1;\n }\n\n return result;\n}\n\n/**\n * Calculate optimal column widths without constraining to page width\n * Each column gets the width it needs to display content properly\n * @param data - 2D array of cell data\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param num_cols - Number of columns\n * @returns Array of optimal column widths\n */\nfunction calculate_optimal_column_widths(\n data: string[][],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n num_cols: number\n): number[] {\n const min_col_width = 50;\n const max_col_width = 250; // Cap individual column width\n const padding = 14;\n\n const col_widths: number[] = new Array(num_cols).fill(min_col_width);\n\n // Sample all rows (or first 100 for performance)\n const sample_rows = data.slice(0, 100);\n\n for (const row of sample_rows) {\n for (let col = 0; col < num_cols; col++) {\n const cell_value = String(row[col] || '');\n const text_width = font.widthOfTextAtSize(cell_value, font_size) + padding;\n col_widths[col] = Math.max(col_widths[col], Math.min(text_width, max_col_width));\n }\n }\n\n return col_widths;\n}\n\n/**\n * Truncate text to fit within a given width\n * @param text - Text to truncate\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param max_width - Maximum width in points\n * @returns Truncated text with ellipsis if needed\n */\nfunction truncate_text(\n text: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n max_width: number\n): string {\n if (font.widthOfTextAtSize(text, font_size) <= max_width) {\n return text;\n }\n\n const ellipsis = '...';\n let truncated = text;\n\n while (truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n if (font.widthOfTextAtSize(truncated + ellipsis, font_size) <= max_width) {\n return truncated + ellipsis;\n }\n }\n\n return ellipsis;\n}\n\n/**\n * Convert GIF or WebP images to PNG using canvas\n * This is needed because pdf-lib only natively supports JPEG and PNG\n * @param image_bytes - Raw image data\n * @param mime_type - Original MIME type\n * @returns PNG bytes as Uint8Array\n */\nasync function convert_image_via_canvas(\n image_bytes: Uint8Array,\n mime_type: string\n): Promise<Uint8Array> {\n // This function requires browser environment\n if (typeof document === 'undefined' || typeof Image === 'undefined') {\n throw new Error('Image conversion requires browser environment (canvas support)');\n }\n\n return new Promise((resolve, reject) => {\n // Create blob URL from image bytes\n // Create new Uint8Array to ensure proper ArrayBuffer type for Blob constructor\n const blob = new Blob([new Uint8Array(image_bytes)], { type: mime_type });\n const url = URL.createObjectURL(blob);\n\n // Load image\n const img = new Image();\n img.onload = () => {\n try {\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = img.width;\n canvas.height = img.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas 2D context');\n }\n\n ctx.drawImage(img, 0, 0);\n\n // Export as PNG\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image to PNG'));\n return;\n }\n\n blob.arrayBuffer().then((buffer) => {\n resolve(new Uint8Array(buffer));\n }).catch(reject);\n }, 'image/png');\n\n // Clean up\n URL.revokeObjectURL(url);\n } catch (error) {\n URL.revokeObjectURL(url);\n reject(error);\n }\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image for conversion'));\n };\n\n img.src = url;\n });\n}\n\n/**\n * Wrap text to fit within a given width\n * @param text - Text to wrap\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param max_width - Maximum line width in points\n * @returns Array of lines\n */\nfunction wrap_text(\n text: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n max_width: number\n): string[] {\n const lines: string[] = [];\n\n // Split by explicit line breaks first\n const paragraphs = text.split(/\\r?\\n/);\n\n for (const paragraph of paragraphs) {\n if (paragraph.trim() === '') {\n // Preserve empty lines\n lines.push('');\n continue;\n }\n\n const words = paragraph.split(/\\s+/);\n let current_line = '';\n\n for (const word of words) {\n const test_line = current_line ? `${current_line} ${word}` : word;\n const width = font.widthOfTextAtSize(test_line, font_size);\n\n if (width <= max_width) {\n current_line = test_line;\n } else {\n if (current_line) {\n lines.push(current_line);\n }\n\n // Check if the word itself is too long and needs to be broken\n if (font.widthOfTextAtSize(word, font_size) > max_width) {\n // Break the word character by character\n let char_line = '';\n for (const char of word) {\n const test_char_line = char_line + char;\n if (font.widthOfTextAtSize(test_char_line, font_size) <= max_width) {\n char_line = test_char_line;\n } else {\n if (char_line) {\n lines.push(char_line);\n }\n char_line = char;\n }\n }\n current_line = char_line;\n } else {\n current_line = word;\n }\n }\n }\n\n if (current_line) {\n lines.push(current_line);\n }\n }\n\n return lines;\n}\n","/**\n * File Access Middleware\n * Provides abstraction for loading and saving PDF files\n * Supports both direct fetch (default) and hazo_files integration\n */\n\nimport type { FileAccessProvider } from '../types/file_access';\nimport { get_logger } from './logger';\n\n/**\n * Load PDF data from a source (URL or hazo_files path)\n * @param source - URL or path to the PDF file\n * @param file_manager - Optional hazo_files FileAccessProvider for remote storage\n * @returns Promise with ArrayBuffer containing PDF data\n */\nexport async function load_pdf_data(\n source: string,\n file_manager?: FileAccessProvider\n): Promise<ArrayBuffer> {\n const logger = get_logger();\n\n // If file_manager is provided and initialized, use it\n if (file_manager && file_manager.isInitialized()) {\n logger.debug(`[file_access_middleware] Loading PDF via hazo_files: ${source}`);\n\n const result = await file_manager.downloadFile(source);\n\n if (!result.success || !result.data) {\n const error_msg = result.error || 'Unknown error loading file';\n logger.error(`[file_access_middleware] Failed to load PDF via hazo_files: ${error_msg}`);\n throw new Error(`Failed to load PDF from storage: ${error_msg}`);\n }\n\n // Convert data to ArrayBuffer\n // Handle Buffer (Node.js), ArrayBuffer, or Uint8Array\n const data = result.data;\n if (data instanceof ArrayBuffer) {\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files, size: ${data.byteLength} bytes`);\n return data;\n } else if (data instanceof Uint8Array) {\n // Uint8Array - get the underlying ArrayBuffer\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files (Uint8Array), size: ${data.byteLength} bytes`);\n return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);\n } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(data)) {\n // Node.js Buffer - convert to ArrayBuffer\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files (Buffer), size: ${data.length} bytes`);\n return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);\n }\n\n throw new Error('Unexpected data type from file manager');\n }\n\n // Default: use fetch\n logger.debug(`[file_access_middleware] Loading PDF via fetch: ${source}`);\n\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\n }\n\n const array_buffer = await response.arrayBuffer();\n logger.debug(`[file_access_middleware] PDF loaded via fetch, size: ${array_buffer.byteLength} bytes`);\n\n return array_buffer;\n}\n\n/**\n * Save PDF data to remote storage via hazo_files\n * @param pdf_bytes - PDF data as Uint8Array\n * @param remote_path - Destination path in remote storage\n * @param file_manager - hazo_files FileAccessProvider\n * @param overwrite - Whether to overwrite existing file (default: true)\n * @returns Promise with save result\n */\nexport async function save_pdf_data(\n pdf_bytes: Uint8Array,\n remote_path: string,\n file_manager: FileAccessProvider,\n overwrite: boolean = true\n): Promise<{ success: boolean; error?: string }> {\n const logger = get_logger();\n\n if (!file_manager.isInitialized()) {\n logger.error('[file_access_middleware] File manager not initialized');\n return { success: false, error: 'File manager not initialized' };\n }\n\n logger.debug(`[file_access_middleware] Saving PDF via hazo_files: ${remote_path} (${pdf_bytes.byteLength} bytes)`);\n\n try {\n // Convert Uint8Array to Buffer if in Node.js environment\n // or pass as-is if Buffer is not available (browser)\n let source: Buffer | Uint8Array = pdf_bytes;\n if (typeof Buffer !== 'undefined') {\n source = Buffer.from(pdf_bytes);\n }\n\n const result = await file_manager.uploadFile(source, remote_path, { overwrite });\n\n if (!result.success) {\n logger.error(`[file_access_middleware] Failed to save PDF: ${result.error}`);\n return { success: false, error: result.error };\n }\n\n logger.info(`[file_access_middleware] PDF saved successfully: ${remote_path}`);\n return { success: true };\n } catch (error) {\n const error_msg = error instanceof Error ? error.message : String(error);\n logger.error(`[file_access_middleware] Error saving PDF: ${error_msg}`);\n return { success: false, error: error_msg };\n }\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useCallback","Undo2","X","document","useState","useRef","useEffect","useRef","useEffect","jsx","useRef","useEffect","useState","useRef","jsx","jsxs","useState","useRef","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useState","useEffect","useRef","createPortal","Fragment","jsx","jsxs","useState","useRef","useEffect","createPortal","useState","useRef","useEffect","ChevronDown","X","Fragment","jsx","jsxs","useState","useRef","useEffect","ChevronDown","X","useState","useRef","useEffect","ChevronLeft","ChevronRight","ChevronDown","ChevronUp","Fragment","jsx","jsxs","useState","useRef","useEffect","ChevronLeft","ChevronRight","ChevronUp","ChevronDown","useState","useCallback","useEffect","useRef","useState","useEffect","useCallback","ChevronLeft","ChevronRight","useState","X","FileText","jsx","jsxs","useState","FileText","X","Fragment","jsx","jsxs","useRef","useState","useEffect","useCallback","ChevronLeft","ChevronRight","useState","useRef","useCallback","X","Loader2","jsx","jsxs","Loader2","jsx","jsxs","useState","useRef","useCallback","X","useState","jsx","jsxs","useState","blob","jsx","jsxs","useState","useEffect","useCallback","Fragment","jsx","jsxs","useState","useEffect","useRef","useCallback","error","logger","document","Undo2","final_text","X"]}
1
+ {"version":3,"sources":["../src/components/pdf_viewer/pdf_viewer.tsx","../src/components/pdf_viewer/toolbar_dropdown_button.tsx","../src/utils/cn.ts","../src/components/pdf_viewer/pdf_worker_setup.ts","../src/components/pdf_viewer/pdf_viewer_layout.tsx","../src/components/pdf_viewer/pdf_page_renderer.tsx","../src/utils/coordinate_mapper.ts","../src/components/pdf_viewer/annotation_overlay.tsx","../src/utils/annotation_utils.ts","../src/components/pdf_viewer/context_menu.tsx","../src/components/pdf_viewer/text_annotation_dialog.tsx","../src/components/pdf_viewer/metadata_sidepanel.tsx","../src/components/pdf_viewer/file_info_sidepanel.tsx","../src/utils/config_loader.ts","../src/components/file_manager/index.tsx","../src/components/file_manager/file_list.tsx","../src/components/file_manager/file_list_item.tsx","../src/components/file_manager/upload_dropzone.tsx","../src/components/file_manager/upload_progress.tsx","../src/components/file_manager/file_manager_button.tsx","../src/utils/pdf_converter.ts","../src/utils/file_access_middleware.ts"],"sourcesContent":["/**\n * PDF Viewer Component\n * Main component for displaying and interacting with PDF documents\n * Integrates PDF rendering, annotation overlay, and layout management\n */\n\nimport { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { Save, Download, Undo2, Redo2, PanelRight, PanelRightOpen, ZoomIn, ZoomOut, RotateCcw, RotateCw, RefreshCw, Square, Type, ExternalLink, Info, Sparkles, X } from 'lucide-react';\nimport { ToolbarDropdownButton } from './toolbar_dropdown_button';\nimport { load_pdf_document } from './pdf_worker_setup';\nimport { PdfViewerLayout } from './pdf_viewer_layout';\nimport { ContextMenu } from './context_menu';\nimport { TextAnnotationDialog } from './text_annotation_dialog';\nimport { MetadataSidepanel } from './metadata_sidepanel';\nimport { FileInfoSidepanel } from './file_info_sidepanel';\nimport type { PdfViewerProps, PdfAnnotation, CoordinateMapper, PdfViewerConfig, CustomStamp, MetadataInput, MetadataDataItem, PdfViewerRef, HighlightOptions } from '../../types';\nimport { load_pdf_config, load_pdf_config_async } from '../../utils/config_loader';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { set_logger, get_logger } from '../../utils/logger';\nimport { FileManager } from '../file_manager';\nimport type { FileItem, PopoutContext } from '../file_manager/types';\nimport { load_pdf_data, save_pdf_data } from '../../utils/file_access_middleware';\n\n// Storage key for popout context\nconst POPOUT_STORAGE_KEY = 'hazo_pdf_popout';\n\n/**\n * PDF Viewer Component\n * Main entry point for PDF viewing and annotation\n */\nexport const PdfViewer = forwardRef<PdfViewerRef, PdfViewerProps>(({\n url,\n className = '',\n scale: initial_scale = 1.0,\n fit_to_width = false,\n on_load,\n on_error,\n annotations: initial_annotations = [],\n on_annotation_create,\n on_annotation_update,\n on_annotation_delete,\n on_save,\n background_color,\n config_file,\n append_timestamp_to_text_edits,\n annotation_text_suffix_fixed_text,\n right_click_custom_stamps,\n sidepanel_metadata_enabled = false,\n metadata_input,\n on_metadata_change,\n file_metadata,\n // Toolbar visibility props (override config file values)\n toolbar_enabled,\n show_zoom_controls,\n show_square_button,\n show_undo_button,\n show_redo_button,\n show_save_button,\n show_download_button,\n show_metadata_button,\n show_annotate_button,\n show_file_info_button,\n // Data extraction props\n show_extract_button,\n extract_prompt_area,\n extract_prompt_key,\n extract_api_endpoint,\n extract_storage_type = 'local',\n on_extract_complete,\n on_extract_error,\n on_close,\n // Multi-file support props\n files,\n on_file_select,\n on_file_delete,\n on_upload,\n on_files_change,\n // file_manager_display_mode is reserved for future use (dialog/standalone modes)\n download_filename,\n display_filename,\n on_download,\n enable_popout = false,\n popout_route = '/pdf-viewer',\n on_popout,\n viewer_title,\n logger,\n // hazo_files integration props\n file_manager,\n save_path,\n // Upload behavior\n direct_upload,\n // File info sidepanel data props\n doc_data,\n highlight_fields_info,\n extractions,\n // Auto-highlight props\n auto_highlight_enabled,\n auto_highlight_options,\n auto_highlight_search_options,\n}, ref) => {\n const pdf_logger = get_logger();\n const [pdf_document, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n // Cached PDF data for use when saving (when loaded via file_manager)\n const [cached_pdf_data, setCachedPdfData] = useState<ArrayBuffer | null>(null);\n const [scale, setScale] = useState(initial_scale);\n const [annotations, setAnnotations] = useState<PdfAnnotation[]>(initial_annotations);\n // Default tool is Pan (null) for scrolling the document\n const [current_tool, setCurrentTool] = useState<'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null>(null);\n const [saving, setSaving] = useState(false);\n const [downloading, setDownloading] = useState(false);\n // Data extraction state\n const [extracting, setExtracting] = useState(false);\n const [extract_error, setExtractError] = useState<string | null>(null);\n // Sidepanel state (existing metadata sidepanel)\n const [sidepanel_open, setSidepanelOpen] = useState(false);\n const [sidepanel_width, setSidepanelWidth] = useState(300);\n\n // File info sidepanel state (combined extraction data + file system info)\n const [file_info_sidepanel_open, setFileInfoSidepanelOpen] = useState(false);\n const [file_info_sidepanel_width, setFileInfoSidepanelWidth] = useState(300);\n const [hazo_files_available, setHazoFilesAvailable] = useState<boolean | null>(null);\n\n // Auto-highlight state (track IDs of auto-created highlights)\n const [auto_highlight_ids, setAutoHighlightIds] = useState<Set<string>>(new Set());\n\n // Page rotation state\n const [page_rotations, setPageRotations] = useState<Map<number, number>>(new Map());\n const [current_visible_page, setCurrentVisiblePage] = useState(0);\n // Config loaded trigger (forces re-render after async config load)\n const [, setConfigVersion] = useState(0);\n\n // Multi-file state\n const [current_file, setCurrentFile] = useState<FileItem | null>(\n files && files.length > 0 ? files[0] : null\n );\n // Multi-file mode is enabled when files prop is provided (even if empty array)\n // This allows showing the file manager for uploads when no files exist yet\n const is_multi_file_mode = files !== undefined;\n\n // Get the effective URL for loading (single file mode or from current file in multi-file mode)\n const effective_url = is_multi_file_mode ? current_file?.url : url;\n\n // Set logger instance when provided\n useEffect(() => {\n set_logger(logger);\n if (logger) {\n logger.debug('Logger initialized for PdfViewer');\n }\n }, [logger]);\n\n // Check if hazo_files package is available (for file info sidepanel)\n useEffect(() => {\n const check_hazo_files = async () => {\n try {\n const module = await import('hazo_files/ui');\n // Check if FileInfoPanel exists as a property in the module\n if ('FileInfoPanel' in module && typeof module.FileInfoPanel === 'function') {\n setHazoFilesAvailable(true);\n } else {\n setHazoFilesAvailable(false);\n }\n } catch {\n setHazoFilesAvailable(false);\n }\n };\n check_hazo_files();\n }, []);\n\n // Content container ref for fit-to-width calculations\n const content_container_ref = useRef<HTMLDivElement>(null);\n\n // First page dimensions for fit-to-width calculation (at scale=1)\n const [first_page_width, setFirstPageWidth] = useState<number | null>(null);\n\n // When true, fit-to-width auto-scaling is active. Disabled on manual zoom.\n // State drives useEffect cleanup/setup (disconnects/reconnects the ResizeObserver).\n // Ref provides a synchronous guard inside the ResizeObserver callback, preventing\n // stale callbacks from overriding manual zoom between DOM commit and effect cleanup.\n const [fit_to_width_active, setFitToWidthActive] = useState(fit_to_width);\n const fit_to_width_active_ref = useRef(fit_to_width);\n\n // Sync current_file when files prop changes\n useEffect(() => {\n if (files && files.length > 0) {\n // If current file is not in the new files array, select the first file\n if (!current_file || !files.find(f => f.id === current_file.id)) {\n setCurrentFile(files[0]);\n }\n } else {\n setCurrentFile(null);\n }\n }, [files]);\n\n // Handle file selection in multi-file mode\n const handle_file_select = useCallback((file: FileItem) => {\n setCurrentFile(file);\n on_file_select?.(file);\n }, [on_file_select]);\n\n // Load configuration from file\n // Initialize with defaults so config is available on first render\n const config_ref = useRef<PdfViewerConfig | null>(load_pdf_config());\n\n // Load config from file on mount (overrides defaults)\n // Uses hazo_config in Node.js (preferred), fetch + compatible parsing in browser\n useEffect(() => {\n if (!config_file) {\n // No config file specified, use defaults\n config_ref.current = load_pdf_config();\n return;\n }\n \n // Detect environment\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser: use async loader (fetch + compatible parsing)\n // Note: hazo_config requires Node.js fs, so we use compatible parsing instead\n load_pdf_config_async(config_file)\n .then(config => {\n config_ref.current = config;\n setConfigVersion(v => v + 1);\n pdf_logger.debug('Config loaded', {\n append_timestamp_to_text_edits: config.viewer.append_timestamp_to_text_edits,\n config_object: config,\n });\n })\n .catch(error => {\n pdf_logger.warn(`Could not load config file \"${config_file}\", using defaults`, { error });\n config_ref.current = load_pdf_config(); // Use defaults\n setConfigVersion(v => v + 1);\n });\n } else {\n // Node.js: use hazo_config (preferred method)\n config_ref.current = load_pdf_config(config_file);\n pdf_logger.debug('Config loaded (Node.js)', {\n append_timestamp_to_text_edits: config_ref.current?.viewer.append_timestamp_to_text_edits,\n });\n }\n }, [config_file]);\n\n // Override direct_upload from prop at render time (not in useEffect)\n // so FileManager sees the correct value on first render\n if (direct_upload !== undefined && config_ref.current) {\n config_ref.current = {\n ...config_ref.current,\n file_upload: {\n ...config_ref.current.file_upload,\n direct_upload,\n },\n };\n }\n\n // Get effective background color: prop > config > default\n const effective_background_color = background_color || \n config_ref.current?.viewer.viewer_background_color || \n '#2d2d2d';\n \n /**\n * Format timestamp for annotation text edits\n * Returns timestamp in format YYYY-MM-DD h:mmam/pm (without brackets)\n * Brackets are added by add_suffix_text based on configuration\n * Example: 2025-11-17 2:24pm\n */\n const format_annotation_timestamp = (): string => {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const day = String(now.getDate()).padStart(2, '0');\n \n let hours = now.getHours();\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const am_pm = hours >= 12 ? 'pm' : 'am';\n hours = hours % 12;\n if (hours === 0) hours = 12; // Convert 0 to 12 for 12-hour format\n \n return `${year}-${month}-${day} ${hours}:${minutes}${am_pm}`;\n };\n \n /**\n * Parse custom stamps from JSON string (prop or config)\n * @param stamps_json - JSON string array of custom stamps\n * @returns Array of CustomStamp objects, or empty array if invalid\n */\n const parse_custom_stamps = (stamps_json: string | undefined): CustomStamp[] => {\n if (!stamps_json || stamps_json.trim() === '') {\n return [];\n }\n \n try {\n const parsed = JSON.parse(stamps_json);\n if (!Array.isArray(parsed)) {\n pdf_logger.warn('Custom stamps must be a JSON array');\n return [];\n }\n \n // Validate and normalize stamp objects\n return parsed\n .filter((stamp: any) => stamp && typeof stamp === 'object')\n .map((stamp: any) => ({\n name: String(stamp.name || ''),\n text: String(stamp.text || ''),\n order: typeof stamp.order === 'number' ? stamp.order : 999,\n time_stamp_suffix_enabled: Boolean(stamp.time_stamp_suffix_enabled),\n fixed_text_suffix_enabled: Boolean(stamp.fixed_text_suffix_enabled),\n // Optional styling fields\n background_color: stamp.background_color !== undefined ? String(stamp.background_color) : undefined,\n border_size: stamp.border_size !== undefined ? (typeof stamp.border_size === 'number' ? stamp.border_size : undefined) : undefined,\n font_color: stamp.font_color !== undefined ? String(stamp.font_color) : undefined,\n font_weight: stamp.font_weight !== undefined ? String(stamp.font_weight) : undefined,\n font_style: stamp.font_style !== undefined ? String(stamp.font_style) : undefined,\n font_size: stamp.font_size !== undefined ? (typeof stamp.font_size === 'number' ? stamp.font_size : undefined) : undefined,\n font_name: stamp.font_name !== undefined ? String(stamp.font_name) : undefined,\n }))\n .filter((stamp) => stamp.name && stamp.text); // Only include stamps with name and text\n } catch (error) {\n pdf_logger.warn('Failed to parse custom stamps JSON', { error });\n return [];\n }\n };\n \n /**\n * Consolidated helper to append suffix text (fixed text, timestamp) with configurable formatting\n * @param text - Base text to append suffixes to\n * @param fixed_text_suffix_enabled - Whether fixed text suffix should be appended\n * @param time_stamp_suffix_enabled - Whether timestamp suffix should be appended\n * @param fixed_text - Optional fixed text to append\n * @param add_enclosing_brackets_override - Optional override for bracket usage\n * @returns Text with suffixes applied based on configuration\n */\n const add_suffix_text = (\n text: string,\n fixed_text_suffix_enabled: boolean,\n time_stamp_suffix_enabled: boolean,\n fixed_text?: string,\n add_enclosing_brackets_override?: boolean\n ): string => {\n const viewer_config = config_ref.current?.viewer;\n const add_enclosing_brackets =\n add_enclosing_brackets_override ??\n viewer_config?.add_enclosing_brackets_to_suffixes ??\n true;\n \n const suffix_enclosing_brackets = viewer_config?.suffix_enclosing_brackets || '[]';\n const suffix_text_position =\n viewer_config?.suffix_text_position || 'below_multi_line';\n \n const opening_bracket = suffix_enclosing_brackets[0] || '[';\n const closing_bracket = suffix_enclosing_brackets[1] || ']';\n \n const suffix_parts: string[] = [];\n \n if (fixed_text_suffix_enabled) {\n const trimmed_fixed_text = fixed_text?.trim();\n if (trimmed_fixed_text && trimmed_fixed_text.length > 0) {\n suffix_parts.push(\n add_enclosing_brackets\n ? `${opening_bracket}${trimmed_fixed_text}${closing_bracket}`\n : trimmed_fixed_text\n );\n }\n }\n \n if (time_stamp_suffix_enabled) {\n const timestamp = format_annotation_timestamp();\n suffix_parts.push(\n add_enclosing_brackets\n ? `${opening_bracket}${timestamp}${closing_bracket}`\n : timestamp\n );\n }\n \n if (suffix_parts.length === 0) {\n return text;\n }\n \n switch (suffix_text_position) {\n case 'adjacent': {\n if (!text) {\n return suffix_parts.join(' ');\n }\n const separator = text.endsWith(' ') ? '' : ' ';\n return `${text}${separator}${suffix_parts.join(' ')}`;\n }\n case 'below_single_line':\n return text\n ? `${text}\\n${suffix_parts.join(' ')}`\n : suffix_parts.join(' ');\n case 'below_multi_line':\n default:\n return text\n ? `${text}\\n${suffix_parts.join('\\n')}`\n : suffix_parts.join('\\n');\n }\n };\n\n /**\n * Format stamp text with optional timestamp and fixed text suffixes\n * Uses add_suffix_text helper for consistent formatting\n * @param stamp - Custom stamp configuration\n * @param base_text - Base text from stamp\n * @returns Formatted text with suffixes if enabled\n */\n const format_stamp_text = (stamp: CustomStamp, base_text: string): string => {\n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = config_ref.current?.viewer.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined ? fixed_text_prop : fixed_text_config;\n return add_suffix_text(\n base_text,\n stamp.fixed_text_suffix_enabled ?? false,\n stamp.time_stamp_suffix_enabled ?? false,\n fixed_text\n );\n };\n \n /**\n * Strip auto-inserted suffix from annotation text\n * Handles configurable bracket styles and suffix positioning\n * @param text - Annotation text that may contain auto-inserted suffix\n * @returns Text with suffix removed\n */\n const strip_auto_inserted_suffix = (text: string): string => {\n const viewer_config = config_ref.current?.viewer;\n const bracket_pair = viewer_config?.suffix_enclosing_brackets || '[]';\n const add_enclosing_brackets =\n viewer_config?.add_enclosing_brackets_to_suffixes ?? true;\n const suffix_text_position =\n viewer_config?.suffix_text_position || 'below_multi_line';\n \n const opening_bracket = bracket_pair[0] || '[';\n const closing_bracket = bracket_pair[1] || ']';\n \n const escape_regexp = (value: string) =>\n value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n \n const timestamp_core_pattern =\n '\\\\d{4}-\\\\d{2}-\\\\d{2} \\\\d{1,2}:\\\\d{2}(?:am|pm)';\n const timestamp_pattern = add_enclosing_brackets\n ? `${escape_regexp(opening_bracket)}${timestamp_core_pattern}${escape_regexp(\n closing_bracket\n )}`\n : timestamp_core_pattern;\n \n const timestamp_line_regex = new RegExp(`^${timestamp_pattern}$`);\n const timestamp_trailing_regex = new RegExp(\n `(?:[ \\\\t]+)?${timestamp_pattern}$`\n );\n \n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = viewer_config?.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined ? fixed_text_prop : fixed_text_config;\n const trimmed_fixed_text = fixed_text?.trim() || '';\n const fixed_segment = trimmed_fixed_text\n ? add_enclosing_brackets\n ? `${opening_bracket}${trimmed_fixed_text}${closing_bracket}`\n : trimmed_fixed_text\n : null;\n \n const fixed_line_regex = fixed_segment\n ? new RegExp(`^${escape_regexp(fixed_segment)}$`)\n : null;\n const fixed_trailing_regex = fixed_segment\n ? new RegExp(`(?:[ \\\\t]+)?${escape_regexp(fixed_segment)}$`)\n : null;\n \n const remove_trailing_pattern = (\n value: string,\n pattern: RegExp | null\n ): { updated: string; removed: boolean } => {\n if (!pattern) {\n return { updated: value, removed: false };\n }\n const new_value = value.replace(pattern, '');\n return { updated: new_value, removed: new_value !== value };\n };\n \n const strip_adjacent_suffix = (value: string): string => {\n let updated = value;\n let removed_any = false;\n \n const timestamp_removal = remove_trailing_pattern(\n updated,\n timestamp_trailing_regex\n );\n updated = timestamp_removal.updated;\n removed_any ||= timestamp_removal.removed;\n \n const fixed_removal = remove_trailing_pattern(\n updated,\n fixed_trailing_regex\n );\n updated = fixed_removal.updated;\n removed_any ||= fixed_removal.removed;\n \n return removed_any ? updated.replace(/[ \\\\t]+$/, '') : value;\n };\n \n const strip_below_single_line_suffix = (value: string): string => {\n const last_newline_index = value.lastIndexOf('\\n');\n if (last_newline_index === -1) {\n // Fallback to adjacent stripping if newline is missing\n return strip_adjacent_suffix(value);\n }\n \n const prefix = value.slice(0, last_newline_index);\n let suffix_line = value.slice(last_newline_index + 1);\n let suffix_changed = false;\n \n const timestamp_removal = remove_trailing_pattern(\n suffix_line,\n timestamp_trailing_regex\n );\n suffix_line = timestamp_removal.updated;\n suffix_changed ||= timestamp_removal.removed;\n \n const fixed_removal = remove_trailing_pattern(\n suffix_line,\n fixed_trailing_regex\n );\n suffix_line = fixed_removal.updated;\n suffix_changed ||= fixed_removal.removed;\n \n if (!suffix_changed) {\n return value;\n }\n \n if (suffix_line.trim().length === 0) {\n return prefix;\n }\n \n return `${prefix}\\n${suffix_line}`;\n };\n \n const strip_below_multi_line_suffix = (value: string): string => {\n const lines = value.split('\\n');\n if (lines.length === 0) {\n return value;\n }\n \n let changed = false;\n const remove_last_line_if_matches = (pattern: RegExp | null) => {\n if (!pattern || lines.length === 0) {\n return;\n }\n const last_line = lines[lines.length - 1].trim();\n if (pattern.test(last_line)) {\n lines.pop();\n changed = true;\n }\n };\n \n remove_last_line_if_matches(timestamp_line_regex);\n remove_last_line_if_matches(fixed_line_regex);\n \n return changed ? lines.join('\\n') : value;\n };\n \n switch (suffix_text_position) {\n case 'adjacent':\n return strip_adjacent_suffix(text);\n case 'below_single_line':\n return strip_below_single_line_suffix(text);\n case 'below_multi_line':\n default:\n return strip_below_multi_line_suffix(text);\n }\n };\n \n /**\n * Append timestamp to annotation text if enabled\n * @param text - Original annotation text\n * @returns Text with timestamp appended (if enabled) or original text\n * Note: Checks config dynamically to handle async config loading in browser\n * If fixed text is provided, format will be: text\\n[fixed_text] [timestamp]\n */\n const append_timestamp_if_enabled = (text: string): string => {\n // Check config dynamically since it loads asynchronously in browser\n // Priority: prop > config > default (false)\n const prop_value = append_timestamp_to_text_edits;\n const config_value = config_ref.current?.viewer.append_timestamp_to_text_edits;\n const should_append = prop_value !== undefined\n ? prop_value\n : (config_value ?? false);\n \n // Get fixed text: prop > config > default (empty string)\n const fixed_text_prop = annotation_text_suffix_fixed_text;\n const fixed_text_config = config_ref.current?.viewer.annotation_text_suffix_fixed_text || '';\n const fixed_text = fixed_text_prop !== undefined\n ? fixed_text_prop\n : fixed_text_config;\n \n pdf_logger.debug('append_timestamp_if_enabled', {\n prop_value,\n config_value,\n should_append,\n fixed_text_prop,\n fixed_text_config,\n fixed_text,\n config_loaded: !!config_ref.current,\n original_text: text,\n });\n \n if (!should_append) {\n pdf_logger.debug('Timestamp NOT appended (disabled)');\n return text;\n }\n \n const include_fixed_text_suffix = Boolean(fixed_text && fixed_text.trim().length > 0);\n const result = add_suffix_text(\n text,\n include_fixed_text_suffix,\n true,\n fixed_text\n );\n pdf_logger.debug('Timestamp appended via add_suffix_text', {\n original: text,\n fixed_text,\n include_fixed_text_suffix,\n result,\n });\n return result;\n };\n \n // Undo/Redo history\n const [history, setHistory] = useState<PdfAnnotation[][]>([initial_annotations]);\n const [history_index, setHistoryIndex] = useState(0);\n const history_ref = useRef({ saving: false }); // Track if we're applying history to prevent loops\n \n // Context menu state\n const [context_menu, setContextMenu] = useState<{\n visible: boolean;\n x: number;\n y: number;\n page_index: number;\n screen_x: number;\n screen_y: number;\n mapper?: CoordinateMapper;\n } | null>(null);\n \n // Text annotation dialog state\n const [text_dialog, setTextDialog] = useState<{\n open: boolean;\n page_index: number;\n x: number; // Viewport X coordinate\n y: number; // Viewport Y coordinate\n screen_x: number;\n screen_y: number;\n mapper?: CoordinateMapper;\n editing_annotation?: PdfAnnotation; // Annotation being edited (if any)\n } | null>(null);\n\n // Initialize history when initial annotations change\n useEffect(() => {\n if (history.length === 1 && history[0].length === 0 && initial_annotations.length === 0) {\n // Only reset if history is empty and initial is also empty\n return;\n }\n setHistory([initial_annotations]);\n setHistoryIndex(0);\n history_ref.current.saving = false;\n }, [effective_url]); // Reset history when PDF URL changes\n\n // Load PDF document\n useEffect(() => {\n // Ensure we're in browser environment before loading PDF\n if (typeof window === 'undefined') {\n return;\n }\n\n if (!effective_url) {\n // In multi-file mode with no files, this is expected - not loading, just empty\n if (is_multi_file_mode) {\n setLoading(false);\n setPdfDocument(null);\n setCachedPdfData(null);\n } else {\n pdf_logger.warn('No URL provided');\n }\n return;\n }\n\n setLoading(true);\n setError(null);\n setCachedPdfData(null);\n\n // Use a timeout to ensure we're fully in browser context\n // This helps with React Strict Mode and SSR hydration issues\n const load_timeout = setTimeout(async () => {\n try {\n let pdf_data: ArrayBuffer | string = effective_url;\n const logger = get_logger();\n\n // If file_manager is provided and initialized, use it to load the PDF\n if (file_manager && file_manager.isInitialized()) {\n logger.debug('[PdfViewer] Loading PDF via hazo_files file_manager');\n const loaded_data = await load_pdf_data(effective_url, file_manager);\n // Make a copy for caching (pdfjs may detach the original buffer)\n const cached_copy = loaded_data.slice(0);\n setCachedPdfData(cached_copy);\n pdf_data = loaded_data;\n } else {\n // Fetch the PDF ourselves and cache the ArrayBuffer\n // This ensures extraction uses the same data as the displayed document\n logger.debug('[PdfViewer] Loading PDF via fetch, caching for extraction', { url: effective_url });\n const response = await fetch(effective_url);\n\n // Check for HTTP errors before parsing response\n if (!response.ok) {\n const error_text = await response.text().catch(() => '');\n const truncated = error_text.length > 200 ? error_text.slice(0, 200) + '...' : error_text;\n throw new Error(\n `Failed to fetch PDF (${response.status} ${response.statusText}): ${truncated || 'No response body'}`\n );\n }\n\n // Verify content type is PDF (some servers return HTML for errors with 200 status)\n const content_type = response.headers.get('content-type') || '';\n if (!content_type.includes('application/pdf') && !content_type.includes('application/octet-stream')) {\n logger.warn('[PdfViewer] Unexpected content type for PDF', {\n url: effective_url,\n content_type,\n note: 'Expected application/pdf or application/octet-stream'\n });\n }\n\n const array_buffer = await response.arrayBuffer();\n // Make a copy for caching (pdfjs may detach the original buffer)\n const cached_copy = array_buffer.slice(0);\n setCachedPdfData(cached_copy);\n pdf_data = array_buffer;\n }\n\n const document = await load_pdf_document(pdf_data);\n setPdfDocument(document);\n setLoading(false);\n if (on_load) {\n on_load(document);\n }\n } catch (err) {\n pdf_logger.error('Error loading PDF', { error: err });\n const error_obj = err instanceof Error ? err : new Error(String(err));\n setError(error_obj);\n setLoading(false);\n if (on_error) {\n on_error(error_obj);\n }\n }\n }, 0);\n\n // Cleanup: cancel loading if component unmounts\n return () => {\n clearTimeout(load_timeout);\n };\n }, [effective_url, on_load, on_error, is_multi_file_mode, file_manager]);\n\n // Get first page dimensions when PDF document loads (for fit-to-width calculation)\n useEffect(() => {\n if (!pdf_document) {\n setFirstPageWidth(null);\n return;\n }\n\n // Get first page to determine intrinsic width at scale=1\n pdf_document.getPage(1).then((page) => {\n const viewport = page.getViewport({ scale: 1 });\n setFirstPageWidth(viewport.width);\n }).catch((err) => {\n pdf_logger.error('Error getting first page dimensions', { error: err });\n });\n }, [pdf_document]);\n\n // Re-enable fit-to-width when the prop changes\n useEffect(() => {\n fit_to_width_active_ref.current = fit_to_width;\n setFitToWidthActive(fit_to_width);\n }, [fit_to_width]);\n\n // Fit-to-width: Calculate scale based on container width and PDF page width.\n // When fit_to_width_active is false (e.g. after manual zoom), this effect\n // cleans up the ResizeObserver so it won't override the user's zoom level.\n useEffect(() => {\n if (!fit_to_width_active || !first_page_width || !content_container_ref.current) {\n return;\n }\n\n const calculate_fit_scale = () => {\n // Guard: check ref synchronously to prevent stale ResizeObserver callbacks\n // from overriding manual zoom (ref is set immediately by zoom handlers,\n // before the async useEffect cleanup can disconnect the observer)\n if (!fit_to_width_active_ref.current) return;\n if (!content_container_ref.current || !first_page_width) return;\n\n // Get container width (subtract some padding for page margins)\n const container_width = content_container_ref.current.clientWidth;\n const padding = 40; // Account for margins/padding around the page\n const available_width = container_width - padding;\n\n // Calculate scale to fit PDF width to available width\n const new_scale = Math.max(0.1, Math.min(3.0, available_width / first_page_width));\n\n setScale(new_scale);\n };\n\n // Calculate initial scale\n calculate_fit_scale();\n\n // Set up ResizeObserver to recalculate on container resize\n const resize_observer = new ResizeObserver(() => {\n calculate_fit_scale();\n });\n\n resize_observer.observe(content_container_ref.current);\n\n return () => {\n resize_observer.disconnect();\n };\n }, [fit_to_width_active, first_page_width]);\n\n // Previously logged global mouse clicks for debugging; removed for cleaner console.\n\n // Save to history when annotations change (but not when applying undo/redo)\n const save_to_history = (new_annotations: PdfAnnotation[]) => {\n if (history_ref.current.saving) {\n return; // Don't save to history when applying undo/redo\n }\n \n // Create new history array up to current index, then add new state\n const new_history = history.slice(0, history_index + 1);\n new_history.push(new_annotations);\n \n // Limit history to 50 states to prevent memory issues\n if (new_history.length > 50) {\n new_history.shift();\n setHistory(new_history);\n setHistoryIndex(new_history.length - 1);\n } else {\n setHistory(new_history);\n setHistoryIndex(new_history.length - 1);\n }\n };\n\n // Handle annotation creation\n const handle_annotation_create = (annotation: PdfAnnotation) => {\n // Use functional update to avoid stale closure when adding multiple annotations quickly\n setAnnotations(prev => {\n const new_annotations = [...prev, annotation];\n save_to_history(new_annotations);\n if (on_annotation_create) {\n on_annotation_create(annotation);\n }\n return new_annotations;\n });\n };\n\n // Handle annotation update\n const handle_annotation_update = (annotation: PdfAnnotation) => {\n const updated_annotations = annotations.map((ann) =>\n ann.id === annotation.id ? annotation : ann\n );\n setAnnotations(updated_annotations);\n save_to_history(updated_annotations);\n if (on_annotation_update) {\n on_annotation_update(annotation);\n }\n };\n\n // Handle annotation delete\n const handle_annotation_delete = (annotation_id: string) => {\n const filtered_annotations = annotations.filter(\n (ann) => ann.id !== annotation_id\n );\n setAnnotations(filtered_annotations);\n save_to_history(filtered_annotations);\n if (on_annotation_delete) {\n on_annotation_delete(annotation_id);\n }\n };\n\n // Expose imperative methods via ref for programmatic control\n useImperativeHandle(ref, () => ({\n /**\n * Create a highlight on a specific page region\n * @param page_index - Zero-based page index\n * @param rect - Rectangle coordinates in PDF space [x1, y1, x2, y2]\n * @param options - Optional styling overrides\n * @returns The highlight annotation ID\n */\n highlight_region: (\n page_index: number,\n rect: [number, number, number, number],\n options?: HighlightOptions\n ): string => {\n const highlight_config = config_ref.current?.highlight_annotation || default_config.highlight_annotation;\n\n const annotation: PdfAnnotation = {\n id: `highlight_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n type: 'Highlight',\n page_index,\n rect,\n author: 'API',\n date: new Date().toISOString(),\n contents: '',\n color: options?.background_color || highlight_config.highlight_fill_color,\n flags: 'api_highlight', // Marker to identify API-created highlights\n };\n\n // Store custom options in subject field as JSON (for rendering)\n if (options) {\n annotation.subject = JSON.stringify({\n border_color: options.border_color,\n background_color: options.background_color,\n background_opacity: options.background_opacity,\n border_width: options.border_width,\n });\n }\n\n handle_annotation_create(annotation);\n return annotation.id;\n },\n\n /**\n * Remove a specific highlight by ID\n * @param id - The highlight annotation ID\n * @returns true if highlight was found and removed\n */\n remove_highlight: (id: string): boolean => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n return true;\n }\n return false;\n },\n\n /**\n * Remove all highlights created via the highlight_region API\n */\n clear_all_highlights: (): void => {\n const api_highlights = annotations.filter(a => a.flags === 'api_highlight');\n api_highlights.forEach(a => handle_annotation_delete(a.id));\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }), [annotations, handle_annotation_create, handle_annotation_delete]);\n\n // Handle undo\n const handle_undo = useCallback(() => {\n if (history_index > 0) {\n history_ref.current.saving = true;\n const previous_index = history_index - 1;\n const previous_annotations = history[previous_index];\n setAnnotations([...previous_annotations]); // Create new array to trigger re-render\n setHistoryIndex(previous_index);\n setTimeout(() => {\n history_ref.current.saving = false;\n }, 0);\n }\n }, [history_index, history]);\n\n // Handle redo\n const handle_redo = useCallback(() => {\n if (history_index < history.length - 1) {\n history_ref.current.saving = true;\n const next_index = history_index + 1;\n const next_annotations = history[next_index];\n setAnnotations([...next_annotations]); // Create new array to trigger re-render\n setHistoryIndex(next_index);\n setTimeout(() => {\n history_ref.current.saving = false;\n }, 0);\n }\n }, [history_index, history]);\n\n // Keyboard shortcuts for undo/redo\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n // Only handle if not typing in an input field\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n // Check for Ctrl+Z (undo) or Cmd+Z on Mac\n if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {\n e.preventDefault();\n handle_undo();\n }\n // Check for Ctrl+Y or Ctrl+Shift+Z (redo)\n if ((e.ctrlKey || e.metaKey) && (e.key === 'y' || (e.key === 'z' && e.shiftKey))) {\n e.preventDefault();\n handle_redo();\n }\n };\n\n window.addEventListener('keydown', handle_keydown);\n return () => {\n window.removeEventListener('keydown', handle_keydown);\n };\n }, [handle_undo, handle_redo]);\n\n // Handle zoom controls — manual zoom disables fit-to-width auto-scaling\n const handle_zoom_in = () => {\n fit_to_width_active_ref.current = false;\n setFitToWidthActive(false);\n setScale((prev) => Math.min(prev + 0.25, 3.0));\n };\n\n const handle_zoom_out = () => {\n fit_to_width_active_ref.current = false;\n setFitToWidthActive(false);\n setScale((prev) => Math.max(prev - 0.25, 0.5));\n };\n\n const handle_zoom_reset = () => {\n // If fit_to_width prop is enabled, reset re-enables fit-to-width mode\n // instead of going to 100%. This lets the user return to fitted view.\n if (fit_to_width) {\n fit_to_width_active_ref.current = true;\n setFitToWidthActive(true);\n } else {\n setScale(1.0);\n }\n };\n\n // Handle rotation controls\n const normalize_rotation = (rotation: number): number => {\n // Normalize rotation to 0, 90, 180, 270\n let normalized = rotation % 360;\n if (normalized < 0) normalized += 360;\n return normalized;\n };\n\n const handle_rotate_left = useCallback(() => {\n // Rotate current visible page left (counterclockwise 90°)\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n const current_rotation = new_map.get(current_visible_page) || 0;\n new_map.set(current_visible_page, normalize_rotation(current_rotation - 90));\n return new_map;\n });\n }, [current_visible_page]);\n\n const handle_rotate_right = useCallback(() => {\n // Rotate current visible page right (clockwise 90°)\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n const current_rotation = new_map.get(current_visible_page) || 0;\n new_map.set(current_visible_page, normalize_rotation(current_rotation + 90));\n return new_map;\n });\n }, [current_visible_page]);\n\n const handle_rotate_all_left = useCallback(() => {\n // Rotate all pages left (counterclockwise 90°)\n if (!pdf_document) return;\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n for (let i = 0; i < pdf_document.numPages; i++) {\n const current_rotation = new_map.get(i) || 0;\n new_map.set(i, normalize_rotation(current_rotation - 90));\n }\n return new_map;\n });\n }, [pdf_document]);\n\n const handle_rotate_all_right = useCallback(() => {\n // Rotate all pages right (clockwise 90°)\n if (!pdf_document) return;\n setPageRotations((prev) => {\n const new_map = new Map(prev);\n for (let i = 0; i < pdf_document.numPages; i++) {\n const current_rotation = new_map.get(i) || 0;\n new_map.set(i, normalize_rotation(current_rotation + 90));\n }\n return new_map;\n });\n }, [pdf_document]);\n\n const handle_visible_page_change = useCallback((page_index: number) => {\n setCurrentVisiblePage(page_index);\n }, []);\n\n // Handle sidepanel toggle\n const handle_sidepanel_toggle = () => {\n setSidepanelOpen((prev) => !prev);\n };\n\n // Handle sidepanel width change\n const handle_sidepanel_width_change = (width: number) => {\n setSidepanelWidth(width);\n };\n\n // Handle file info sidepanel toggle\n const handle_file_info_sidepanel_toggle = () => {\n setFileInfoSidepanelOpen((prev) => !prev);\n };\n\n // Handle file info sidepanel width change\n const handle_file_info_sidepanel_width_change = (width: number) => {\n setFileInfoSidepanelWidth(width);\n };\n\n // Handle metadata change\n const handle_metadata_change = (updatedRow: MetadataDataItem, allData: MetadataInput) => {\n if (on_metadata_change) {\n return on_metadata_change(updatedRow, allData);\n }\n return { updatedRow, allData };\n };\n\n // Handle popout to new tab\n const handle_popout = useCallback(() => {\n // Single-file mode: simply open the URL in a new tab\n if (!is_multi_file_mode) {\n if (effective_url) {\n window.open(effective_url, '_blank');\n }\n return;\n }\n\n // Multi-file mode: use sessionStorage-based popout\n if (!files || files.length === 0) {\n pdf_logger.warn('No files to popout');\n return;\n }\n\n // Create popout context\n const context: PopoutContext = {\n files: files,\n selected_file_id: current_file?.id || files[0].id,\n annotations_map: {},\n viewer_title: viewer_title,\n };\n\n // If custom handler is provided, use it\n if (on_popout) {\n on_popout(context);\n return;\n }\n\n // Default behavior: save to sessionStorage and open new tab\n try {\n sessionStorage.setItem(POPOUT_STORAGE_KEY, JSON.stringify(context));\n window.open(popout_route, '_blank');\n } catch (err) {\n pdf_logger.error('Failed to popout', { error: err });\n }\n }, [is_multi_file_mode, effective_url, files, current_file, viewer_title, on_popout, popout_route]);\n\n // Auto-highlight effect - runs when PDF loads and highlight_fields_info changes\n useEffect(() => {\n const should_auto_highlight =\n auto_highlight_enabled !== false && // Default true\n highlight_fields_info &&\n highlight_fields_info.length > 0 &&\n pdf_document;\n\n if (!should_auto_highlight) {\n return;\n }\n\n const logger = get_logger();\n\n // Clear previous auto-highlights\n auto_highlight_ids.forEach(id => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n }\n });\n setAutoHighlightIds(new Set());\n\n // Async highlighting (non-blocking)\n const perform_auto_highlights = async () => {\n const { find_text_in_pdf } = await import('../../utils/text_search');\n const new_ids = new Set<string>();\n\n // Get config values\n const auto_config = config_ref.current?.auto_highlight || default_config.auto_highlight;\n\n // Merge search options: props > config > defaults\n const search_opts = {\n normalize: auto_config.auto_highlight_normalize_text,\n padding_x: auto_config.auto_highlight_padding_x,\n padding_y: auto_config.auto_highlight_padding_y,\n y_offset: auto_config.auto_highlight_y_offset,\n ...auto_highlight_search_options,\n };\n\n // Merge highlight style: props > config > defaults\n const highlight_opts = auto_highlight_options || {\n border_color: auto_config.auto_highlight_border_color,\n background_color: auto_config.auto_highlight_background_color,\n background_opacity: auto_config.auto_highlight_background_opacity,\n border_width: auto_config.auto_highlight_border_width,\n };\n\n for (const field of highlight_fields_info!) {\n try {\n const page_idx = field.page_index ?? 0;\n const result = await find_text_in_pdf(pdf_document!, field.value, {\n page_index: page_idx,\n ...search_opts,\n });\n\n if (result) {\n logger.debug('[AutoHighlight] Found text', {\n field: field.field_name,\n value: field.value,\n match_type: result.match_type,\n position: { x: result.x, y: result.y },\n });\n\n const rect: [number, number, number, number] = [\n result.x,\n result.y,\n result.x + result.width,\n result.y + result.height,\n ];\n\n // Create highlight annotation directly\n const highlight_config = config_ref.current?.highlight_annotation || default_config.highlight_annotation;\n\n const annotation: PdfAnnotation = {\n id: `auto_highlight_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n type: 'Highlight',\n page_index: page_idx,\n rect,\n author: 'AutoHighlight',\n date: new Date().toISOString(),\n contents: field.field_name, // Store field name in contents\n color: highlight_opts.background_color || highlight_config.highlight_fill_color,\n flags: 'api_highlight', // Marker to identify API-created highlights\n };\n\n // Store custom options in subject field as JSON (for rendering)\n annotation.subject = JSON.stringify({\n border_color: highlight_opts.border_color,\n background_color: highlight_opts.background_color,\n background_opacity: highlight_opts.background_opacity,\n border_width: highlight_opts.border_width,\n });\n\n handle_annotation_create(annotation);\n new_ids.add(annotation.id);\n } else {\n logger.warn('[AutoHighlight] Text not found in PDF', {\n field: field.field_name,\n value: field.value,\n page: page_idx,\n });\n }\n } catch (err) {\n logger.error('[AutoHighlight] Search failed', {\n field: field.field_name,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n setAutoHighlightIds(new_ids);\n };\n\n perform_auto_highlights();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pdf_document, highlight_fields_info, auto_highlight_enabled]);\n\n // Cleanup auto-highlights on unmount\n useEffect(() => {\n return () => {\n auto_highlight_ids.forEach(id => {\n const annotation = annotations.find(a => a.id === id);\n if (annotation) {\n handle_annotation_delete(id);\n }\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Check if there are changes to save (annotations or rotations)\n const has_changes_to_save = annotations.length > 0 || page_rotations.size > 0;\n\n // Handle save annotations to PDF\n const handle_save = async () => {\n if (!has_changes_to_save) {\n pdf_logger.warn('No changes to save');\n return;\n }\n\n if (!effective_url) {\n pdf_logger.error('No PDF URL available for saving');\n return;\n }\n\n setSaving(true);\n try {\n const logger = get_logger();\n\n // Generate output filename (use current_file.name in multi-file mode)\n const original_filename = is_multi_file_mode && current_file\n ? current_file.name\n : (effective_url.split('/').pop() || 'document.pdf');\n const filename_without_ext = original_filename.replace(/\\.pdf$/i, '');\n const output_filename = `${filename_without_ext}_annotated.pdf`;\n\n // Import save function to get PDF bytes\n const { save_annotations_to_pdf, download_pdf } = await import('../../utils/pdf_saver');\n\n // Use cached PDF data if available (loaded via file_manager), otherwise use URL\n const pdf_source: string | ArrayBuffer = cached_pdf_data || effective_url;\n logger.debug('[PdfViewer] Saving PDF', { source_type: cached_pdf_data ? 'cached ArrayBuffer' : 'URL' });\n\n // Save annotations to PDF and get the modified bytes\n const pdf_bytes = await save_annotations_to_pdf(pdf_source, annotations, output_filename, config_ref.current, page_rotations);\n\n // If file_manager and save_path are provided, save to remote storage\n if (file_manager && save_path && file_manager.isInitialized()) {\n logger.info('[PdfViewer] Saving PDF to remote storage via hazo_files', { path: save_path });\n const save_result = await save_pdf_data(pdf_bytes, save_path, file_manager);\n if (!save_result.success) {\n throw new Error(`Failed to save to remote storage: ${save_result.error}`);\n }\n logger.info('[PdfViewer] PDF saved to remote storage successfully');\n }\n\n // Call on_save callback if provided (caller may want to handle the bytes)\n // This still fires even after hazo_files save, for caller notification\n if (on_save) {\n on_save(pdf_bytes, output_filename);\n } else if (!file_manager || !save_path) {\n // Only download locally if not saving to remote storage\n download_pdf(pdf_bytes, output_filename);\n }\n } catch (error) {\n pdf_logger.error('Error saving PDF', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n // Notify parent via error callback\n if (on_error) {\n on_error(error_obj);\n }\n } finally {\n setSaving(false);\n }\n };\n\n // Handle download PDF (with annotations baked in)\n const handle_download = async () => {\n if (!effective_url && !cached_pdf_data) {\n pdf_logger.error('No PDF available for download');\n return;\n }\n\n setDownloading(true);\n try {\n const logger = get_logger();\n const { save_annotations_to_pdf, download_pdf } = await import('../../utils/pdf_saver');\n\n // Resolve filename\n const original_filename = is_multi_file_mode && current_file\n ? current_file.name\n : (effective_url?.split('/').pop() || 'document.pdf');\n const output_filename = download_filename || original_filename;\n\n // Use cached PDF data if available, otherwise use URL\n const pdf_source: string | ArrayBuffer = cached_pdf_data || effective_url as string;\n logger.debug('[PdfViewer] Downloading PDF', { filename: output_filename });\n\n // Bake annotations and rotations into the PDF\n const pdf_bytes = await save_annotations_to_pdf(pdf_source, annotations, output_filename, config_ref.current, page_rotations);\n\n // Trigger browser download\n download_pdf(pdf_bytes, output_filename);\n\n // Notify caller\n on_download?.(output_filename);\n } catch (error) {\n pdf_logger.error('Error downloading PDF', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n if (on_error) {\n on_error(error_obj);\n }\n } finally {\n setDownloading(false);\n }\n };\n\n // Handle data extraction via LLM\n const handle_extract = async () => {\n if (!extract_api_endpoint) {\n pdf_logger.warn('No extract_api_endpoint configured');\n const error = new Error('No extract_api_endpoint configured');\n on_extract_error?.(error);\n return;\n }\n\n if (!pdf_document) {\n pdf_logger.warn('No PDF document loaded for extraction');\n const error = new Error('No PDF document loaded');\n on_extract_error?.(error);\n return;\n }\n\n if (!cached_pdf_data) {\n pdf_logger.warn('No cached PDF data available for extraction');\n const error = new Error('No cached PDF data available - please reload the document');\n on_extract_error?.(error);\n return;\n }\n\n setExtracting(true);\n setExtractError(null);\n try {\n const logger = get_logger();\n\n // Get current filename for logging and database matching\n const current_filename = is_multi_file_mode\n ? current_file?.name\n : (display_filename || (url ? url.split('/').pop() || 'unknown' : 'unknown'));\n\n logger.info('[PdfViewer] Starting data extraction', { filename: current_filename });\n\n // Use cached PDF data (always available since we cache during loading)\n // This ensures we extract from the exact same document that's displayed\n const bytes = new Uint8Array(cached_pdf_data);\n // Convert to base64 in chunks to avoid stack overflow\n let binary = '';\n const chunk_size = 8192;\n for (let i = 0; i < bytes.length; i += chunk_size) {\n const chunk = bytes.subarray(i, i + chunk_size);\n binary += String.fromCharCode.apply(null, chunk as unknown as number[]);\n }\n const pdf_base64 = btoa(binary);\n\n logger.debug('[PdfViewer] PDF converted to base64', { size_bytes: bytes.length });\n\n // Determine file path for hazo_files storage\n // In multi-file mode, prefer file_path (actual filesystem path), fall back to url\n // For single-file mode, use the url prop\n const file_path = is_multi_file_mode\n ? (current_file?.file_path || current_file?.url)\n : url;\n\n logger.info('[PdfViewer] Calling extract API', { file_path });\n\n // Call the extract API endpoint\n const api_response = await fetch(extract_api_endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n document_b64: pdf_base64,\n document_mime_type: 'application/pdf',\n prompt_area: extract_prompt_area,\n prompt_key: extract_prompt_key,\n // Include file_path, filename, and storage_type for hazo_files integration\n file_path: file_path,\n filename: current_filename,\n storage_type: extract_storage_type,\n }),\n });\n\n if (!api_response.ok) {\n const error_text = await api_response.text();\n throw new Error(`Extract API error: ${api_response.status} - ${error_text}`);\n }\n\n const result = await api_response.json();\n\n if (!result.success) {\n throw new Error(result.error || 'Unknown extraction error');\n }\n\n logger.info('[PdfViewer] Extraction completed successfully');\n\n // Call the success callback with extracted data\n on_extract_complete?.(result.data);\n\n } catch (error) {\n pdf_logger.error('Error extracting data', { error });\n const error_obj = error instanceof Error ? error : new Error(String(error));\n setExtractError(error_obj.message);\n on_extract_error?.(error_obj);\n } finally {\n setExtracting(false);\n }\n };\n\n // Loading state\n if (loading) {\n return (\n <div className={cn('cls_pdf_viewer', 'cls_pdf_viewer_loading', className)}>\n <div className=\"cls_pdf_viewer_spinner\">Loading PDF document...</div>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className={cn('cls_pdf_viewer', 'cls_pdf_viewer_error', className)}>\n <div className=\"cls_pdf_viewer_error_message\">\n Error loading PDF: {error.message}\n </div>\n </div>\n );\n }\n\n // No document - in multi-file mode, show file manager for uploads\n if (!pdf_document) {\n if (is_multi_file_mode) {\n // Show file manager with empty state for upload\n return (\n <div className={cn('hazo-pdf-root cls_pdf_viewer', className)}>\n <FileManager\n files={files || []}\n selected_file_id={null}\n config={config_ref.current}\n on_file_select={handle_file_select}\n on_file_delete={on_file_delete}\n on_upload={on_upload}\n on_files_change={on_files_change}\n />\n <div className=\"cls_pdf_viewer_empty_state\">\n <div className=\"cls_pdf_viewer_empty_message\">\n Click the + button above to upload a file\n </div>\n </div>\n </div>\n );\n }\n return (\n <div className={cn('cls_pdf_viewer', className)}>\n <div className=\"cls_pdf_viewer_no_document\">No PDF document loaded</div>\n </div>\n );\n }\n\n // Get toolbar config: props override config file values\n const base_toolbar_config = config_ref.current?.toolbar || default_config.toolbar;\n const toolbar_config = {\n ...base_toolbar_config,\n // Props override config file values (undefined means use config value)\n toolbar_show_zoom_controls: show_zoom_controls ?? base_toolbar_config.toolbar_show_zoom_controls,\n toolbar_show_square_button: show_square_button ?? base_toolbar_config.toolbar_show_square_button,\n toolbar_show_undo_button: show_undo_button ?? base_toolbar_config.toolbar_show_undo_button,\n toolbar_show_redo_button: show_redo_button ?? base_toolbar_config.toolbar_show_redo_button,\n toolbar_show_save_button: show_save_button ?? base_toolbar_config.toolbar_show_save_button,\n toolbar_show_metadata_button: show_metadata_button ?? base_toolbar_config.toolbar_show_metadata_button,\n toolbar_show_annotate_button: show_annotate_button ?? base_toolbar_config.toolbar_show_annotate_button,\n toolbar_show_file_info_button: show_file_info_button ?? base_toolbar_config.toolbar_show_file_info_button,\n toolbar_show_extract_button: show_extract_button ?? base_toolbar_config.toolbar_show_extract_button,\n toolbar_show_download_button: show_download_button ?? base_toolbar_config.toolbar_show_download_button,\n toolbar_show_rotation_controls: base_toolbar_config.toolbar_show_rotation_controls ?? true,\n };\n\n // Master toolbar toggle (defaults to true)\n const is_toolbar_enabled = toolbar_enabled ?? true;\n\n return (\n <div className={cn('hazo-pdf-root cls_pdf_viewer', className)}>\n {/* File Manager for multi-file mode */}\n {is_multi_file_mode && (\n <FileManager\n files={files}\n selected_file_id={current_file?.id || null}\n config={config_ref.current}\n on_file_select={handle_file_select}\n on_file_delete={on_file_delete}\n on_upload={on_upload}\n on_files_change={on_files_change}\n />\n )}\n\n {/* Toolbar */}\n {is_toolbar_enabled && (\n <div\n className=\"cls_pdf_viewer_toolbar\"\n style={{\n backgroundColor: toolbar_config.toolbar_background_color,\n borderColor: toolbar_config.toolbar_border_color,\n fontFamily: toolbar_config.toolbar_font_family,\n fontSize: `${toolbar_config.toolbar_font_size}px`,\n color: toolbar_config.toolbar_font_color,\n }}\n >\n {/* Zoom Controls */}\n {toolbar_config.toolbar_show_zoom_controls && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_zoom_out}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ZoomOut className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <span className=\"cls_pdf_viewer_zoom_level\">\n {Math.round(scale * 100)}%\n </span>\n <button\n type=\"button\"\n onClick={handle_zoom_in}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Zoom in\"\n title=\"Zoom in\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ZoomIn className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <button\n type=\"button\"\n onClick={handle_zoom_reset}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Reset zoom\"\n title=\"Reset zoom\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <RefreshCw className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Rotation Controls */}\n {toolbar_config.toolbar_show_rotation_controls && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <ToolbarDropdownButton\n icon={<RotateCcw size={16} />}\n aria_label=\"Rotate page left\"\n title=\"Rotate page left (click for current page)\"\n on_main_click={handle_rotate_left}\n background_color={toolbar_config.toolbar_button_background_color}\n background_color_hover={toolbar_config.toolbar_button_background_color_hover}\n text_color={toolbar_config.toolbar_button_text_color}\n options={[\n {\n id: 'rotate_left_current',\n label: 'Rotate left (current page)',\n icon: <RotateCcw size={14} />,\n on_click: handle_rotate_left,\n },\n {\n id: 'rotate_right_current',\n label: 'Rotate right (current page)',\n icon: <RotateCw size={14} />,\n on_click: handle_rotate_right,\n },\n {\n id: 'rotate_left_all',\n label: 'Rotate left (all pages)',\n icon: <RotateCcw size={14} />,\n on_click: handle_rotate_all_left,\n },\n {\n id: 'rotate_right_all',\n label: 'Rotate right (all pages)',\n icon: <RotateCw size={14} />,\n on_click: handle_rotate_all_right,\n },\n ]}\n />\n </div>\n )}\n\n {/* Square Annotation Button */}\n {toolbar_config.toolbar_show_square_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={() => setCurrentTool(current_tool === 'Square' ? null : 'Square')}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n current_tool === 'Square' && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Square annotation tool\"\n title=\"Square annotation\"\n style={{\n backgroundColor: current_tool === 'Square'\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: current_tool === 'Square'\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (current_tool !== 'Square') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (current_tool !== 'Square') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }\n }}\n >\n <Square className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Annotate (FreeText) Button */}\n {toolbar_config.toolbar_show_annotate_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={() => setCurrentTool(current_tool === 'FreeText' ? null : 'FreeText')}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n current_tool === 'FreeText' && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Text annotation tool\"\n title=\"Text annotation\"\n style={{\n backgroundColor: current_tool === 'FreeText'\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: current_tool === 'FreeText'\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (current_tool !== 'FreeText') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (current_tool !== 'FreeText') {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }\n }}\n >\n <Type className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Undo/Redo Controls */}\n {(toolbar_config.toolbar_show_undo_button || toolbar_config.toolbar_show_redo_button) && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n {toolbar_config.toolbar_show_undo_button && (\n <button\n type=\"button\"\n onClick={handle_undo}\n disabled={history_index === 0}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n history_index === 0 && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Undo last annotation\"\n title=\"Undo (Ctrl+Z)\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: history_index === 0 ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (history_index > 0) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Undo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n )}\n {toolbar_config.toolbar_show_redo_button && (\n <button\n type=\"button\"\n onClick={handle_redo}\n disabled={history_index >= history.length - 1}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n history_index >= history.length - 1 && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Redo last undone annotation\"\n title=\"Redo (Ctrl+Y)\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: history_index >= history.length - 1 ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (history_index < history.length - 1) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Redo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n )}\n </div>\n )}\n\n {/* Save Button */}\n {toolbar_config.toolbar_show_save_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_save}\n disabled={saving || !has_changes_to_save}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n 'cls_pdf_viewer_toolbar_button_save',\n (saving || !has_changes_to_save) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Save PDF\"\n title={saving ? 'Saving...' : (!has_changes_to_save ? 'No changes to save' : 'Save PDF')}\n style={{\n backgroundColor: toolbar_config.toolbar_button_save_background_color,\n color: toolbar_config.toolbar_button_save_text_color,\n opacity: (saving || !has_changes_to_save) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(saving || !has_changes_to_save)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_save_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_save_background_color;\n }}\n >\n <Save className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Download Button */}\n {toolbar_config.toolbar_show_download_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_download}\n disabled={downloading || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n 'cls_pdf_viewer_toolbar_button_download',\n (downloading || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Download PDF\"\n title={downloading ? 'Downloading...' : 'Download PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (downloading || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(downloading || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Download className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Extract Data Button */}\n {toolbar_config.toolbar_show_extract_button && extract_api_endpoint && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_extract}\n disabled={extracting || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n (extracting || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Extract data\"\n title={extracting ? 'Extracting...' : 'Extract data from PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (extracting || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(extracting || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Sparkles className={cn('cls_pdf_viewer_toolbar_icon', extracting && 'animate-spin')} size={16} />\n </button>\n </div>\n )}\n\n {/* Sidepanel toggle button (original metadata) */}\n {sidepanel_metadata_enabled && metadata_input && toolbar_config.toolbar_show_metadata_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_sidepanel_toggle}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n sidepanel_open && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Toggle metadata panel\"\n title=\"Toggle metadata panel\"\n style={{\n backgroundColor: sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: sidepanel_open\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (!sidepanel_open) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color;\n }}\n >\n <PanelRight className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* File Info sidepanel toggle button (shown when file_metadata, hazo_files, doc_data, or highlight_fields_info is available) */}\n {((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && toolbar_config.toolbar_show_file_info_button && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_file_info_sidepanel_toggle}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n file_info_sidepanel_open && 'cls_pdf_viewer_toolbar_button_active'\n )}\n aria-label=\"Toggle file info panel\"\n title=\"Toggle file info panel\"\n style={{\n backgroundColor: file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color,\n color: file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_text_color\n : toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n if (!file_info_sidepanel_open) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = file_info_sidepanel_open\n ? toolbar_config.toolbar_button_active_background_color\n : toolbar_config.toolbar_button_background_color;\n }}\n >\n <Info className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Popout & Download Buttons (shown when enable_popout is true) */}\n {enable_popout && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_popout}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <ExternalLink className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n <button\n type=\"button\"\n onClick={handle_download}\n disabled={downloading || !pdf_document}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n (downloading || !pdf_document) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Download PDF\"\n title={downloading ? 'Downloading...' : 'Download PDF'}\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n opacity: (downloading || !pdf_document) ? toolbar_config.toolbar_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (!(downloading || !pdf_document)) {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n <Download className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n </button>\n </div>\n )}\n\n {/* Close Button (shown when on_close callback is provided) */}\n {on_close && (\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={on_close}\n className=\"cls_pdf_viewer_toolbar_button\"\n aria-label=\"Close viewer\"\n style={{\n backgroundColor: toolbar_config.toolbar_button_background_color,\n color: toolbar_config.toolbar_button_text_color,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color_hover;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = toolbar_config.toolbar_button_background_color;\n }}\n >\n ✕\n </button>\n </div>\n )}\n </div>\n )}\n\n {/* PDF Viewer Layout with Sidepanel */}\n {(() => {\n const any_sidepanel_open = sidepanel_open || file_info_sidepanel_open;\n const total_sidepanel_width = (sidepanel_open ? sidepanel_width : 0) + (file_info_sidepanel_open ? file_info_sidepanel_width : 0);\n // Check if any sidepanel is available (has content)\n const has_metadata_sidepanel = sidepanel_metadata_enabled && metadata_input;\n const has_file_info_sidepanel = ((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && toolbar_config.toolbar_show_file_info_button;\n const any_sidepanel_available = has_metadata_sidepanel || has_file_info_sidepanel;\n return (\n <div className={cn('cls_pdf_viewer_content_wrapper', any_sidepanel_open && 'cls_pdf_viewer_content_wrapper_with_sidepanel')}>\n {/* Floating metadata expand button at top-right of PDF content */}\n {any_sidepanel_available && !any_sidepanel_open && (\n <button\n type=\"button\"\n onClick={() => {\n // Open the first available sidepanel\n if (has_file_info_sidepanel) {\n handle_file_info_sidepanel_toggle();\n } else if (has_metadata_sidepanel) {\n handle_sidepanel_toggle();\n }\n }}\n className=\"cls_pdf_viewer_metadata_expand_btn\"\n aria-label=\"Open metadata panel\"\n title=\"Open metadata panel\"\n >\n <PanelRightOpen size={18} />\n <span className=\"cls_pdf_viewer_metadata_expand_text\">Metadata</span>\n </button>\n )}\n <div\n ref={content_container_ref}\n className={cn('cls_pdf_viewer_content', any_sidepanel_open && 'cls_pdf_viewer_content_with_sidepanel')}\n style={any_sidepanel_open ? { width: `calc(100% - ${total_sidepanel_width}px)` } : undefined}\n >\n <PdfViewerLayout\n pdf_document={pdf_document}\n scale={scale}\n annotations={annotations}\n current_tool={current_tool}\n background_color={effective_background_color}\n config={config_ref.current}\n page_rotations={page_rotations}\n on_visible_page_change={handle_visible_page_change}\n on_annotation_create={handle_annotation_create}\n on_annotation_click={(annotation, screen_x, screen_y, mapper, viewport_x, viewport_y) => {\n pdf_logger.debug(\n `AnnotationClick: opening editor id=${annotation.id}, page=${annotation.page_index}, screen=(${screen_x.toFixed(\n 1\n )}, ${screen_y.toFixed(1)})`\n );\n // Use viewport coordinates for dialog positioning (position: fixed)\n const dialog_y = Math.max(50, viewport_y);\n\n // Open text dialog for editing\n // For FreeText annotations, show existing text\n // For other annotations, show empty dialog (they don't have text)\n setTextDialog({\n open: true,\n page_index: annotation.page_index,\n x: viewport_x,\n y: dialog_y,\n screen_x,\n screen_y,\n mapper,\n editing_annotation: annotation,\n });\n }}\n on_context_menu={(e, page_index, screen_x, screen_y, mapper) => {\n const menu_x = e.clientX;\n const menu_y = e.clientY;\n\n setContextMenu({\n visible: true,\n x: menu_x,\n y: menu_y,\n page_index,\n screen_x,\n screen_y,\n mapper,\n });\n }}\n on_freetext_click={(page_index, screen_x, screen_y, mapper, viewport_x, viewport_y) => {\n // Open text dialog at click position using viewport coordinates (for position: fixed)\n setTextDialog({\n open: true,\n page_index,\n x: viewport_x,\n y: viewport_y,\n screen_x,\n screen_y,\n mapper,\n });\n // Deselect the FreeText tool after creating annotation\n setCurrentTool(null);\n }}\n />\n </div>\n\n {/* Metadata Sidepanel */}\n {sidepanel_metadata_enabled && metadata_input && (\n <MetadataSidepanel\n is_open={sidepanel_open}\n on_toggle={handle_sidepanel_toggle}\n metadata={metadata_input}\n on_change={handle_metadata_change}\n width={sidepanel_width}\n on_width_change={handle_sidepanel_width_change}\n />\n )}\n\n {/* File Info Sidepanel (combined extraction data + file system info) */}\n {((file_metadata && file_metadata.length > 0) || hazo_files_available || doc_data || highlight_fields_info || (extractions && extractions.length > 0)) && (\n <FileInfoSidepanel\n is_open={file_info_sidepanel_open}\n on_toggle={handle_file_info_sidepanel_toggle}\n item={(() => {\n // Create FileSystemItem from current PDF\n const filename = current_file?.name || display_filename || (url ? url.split('/').pop() || '' : '');\n const filepath = effective_url || '';\n if (!filename) return null;\n return {\n name: filename,\n path: filepath,\n is_directory: false,\n extension: filename.includes('.') ? filename.split('.').pop() : undefined,\n mime_type: 'application/pdf',\n };\n })()}\n width={file_info_sidepanel_width}\n on_width_change={handle_file_info_sidepanel_width_change}\n file_metadata={file_metadata}\n current_filename={current_file?.name || display_filename || (url ? url.split('/').pop() || '' : '')}\n doc_data={doc_data}\n highlight_fields_info={highlight_fields_info}\n extractions={extractions}\n />\n )}\n </div>\n );\n })()}\n\n {/* Context Menu */}\n {context_menu?.visible && (\n <>\n {/* Backdrop to close menu */}\n <div\n className=\"cls_pdf_viewer_context_menu_backdrop\"\n onClick={() => setContextMenu(null)}\n onContextMenu={(e) => {\n e.preventDefault();\n setContextMenu(null);\n }}\n />\n <ContextMenu\n x={context_menu.x}\n y={context_menu.y}\n can_undo={history_index > 0}\n config={config_ref.current}\n custom_stamps={(() => {\n // Get stamps from prop or config (prop takes priority)\n const stamps_json = right_click_custom_stamps || config_ref.current?.context_menu.right_click_custom_stamps || '';\n return parse_custom_stamps(stamps_json);\n })()}\n on_undo={() => {\n handle_undo();\n setContextMenu(null);\n }}\n on_annotate={() => {\n setTextDialog({\n open: true,\n page_index: context_menu.page_index,\n x: context_menu.x, // Use same viewport coordinates as context menu\n y: context_menu.y,\n screen_x: context_menu.screen_x,\n screen_y: context_menu.screen_y,\n mapper: context_menu.mapper,\n });\n setContextMenu(null);\n }}\n on_stamp_click={(stamp) => {\n if (!context_menu || !context_menu.mapper) return;\n \n // Format stamp text with optional suffixes\n const formatted_text = format_stamp_text(stamp, stamp.text);\n \n // Convert screen coordinates to PDF coordinates\n const [pdf_x, pdf_y] = context_menu.mapper.to_pdf(context_menu.screen_x, context_menu.screen_y);\n \n // Get text color - use stamp font_color if provided, otherwise use config\n const fonts_config = config_ref.current?.fonts || default_config.fonts;\n const freetext_config = config_ref.current?.freetext_annotation || default_config.freetext_annotation;\n const text_color = stamp.font_color || \n (freetext_config.freetext_text_color && freetext_config.freetext_text_color !== '#000000'\n ? freetext_config.freetext_text_color\n : fonts_config.font_foreground_color);\n \n // Store stamp styling in subject field as JSON for rendering\n // This allows annotation_overlay to apply stamp-specific styling\n const stamp_styling = {\n stamp_name: stamp.name,\n background_color: stamp.background_color,\n border_size: stamp.border_size,\n font_color: stamp.font_color,\n font_weight: stamp.font_weight,\n font_style: stamp.font_style,\n font_size: stamp.font_size,\n font_name: stamp.font_name,\n };\n \n // Create annotation with stamp styling stored in subject\n const annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: 'FreeText',\n page_index: context_menu.page_index,\n rect: [pdf_x, pdf_y, pdf_x + 10, pdf_y + 10], // Placeholder rect\n author: 'User',\n date: new Date().toISOString(),\n contents: formatted_text,\n color: text_color,\n subject: JSON.stringify(stamp_styling), // Store stamp styling metadata\n };\n \n handle_annotation_create(annotation);\n setContextMenu(null);\n }}\n on_close={() => setContextMenu(null)}\n />\n </>\n )}\n\n {/* Text Annotation Dialog */}\n {text_dialog && (\n <TextAnnotationDialog\n open={text_dialog.open}\n x={text_dialog.x}\n y={text_dialog.y}\n config={config_ref.current}\n initial_text={text_dialog.editing_annotation \n ? strip_auto_inserted_suffix(text_dialog.editing_annotation.contents) \n : ''}\n is_editing={!!text_dialog.editing_annotation}\n on_close={() => setTextDialog(null)}\n on_delete={() => {\n if (text_dialog.editing_annotation) {\n handle_annotation_delete(text_dialog.editing_annotation.id);\n }\n setTextDialog(null);\n }}\n on_submit={(text) => {\n if (!text_dialog || !text_dialog.mapper) return;\n \n // Check if we're editing an existing annotation\n if (text_dialog.editing_annotation) {\n // For editing: strip any existing suffix first, then append new suffix\n // This ensures old suffix is removed and new one is added\n const stripped_text = strip_auto_inserted_suffix(text);\n const final_text = append_timestamp_if_enabled(stripped_text);\n \n // Update existing annotation\n const updated_annotation: PdfAnnotation = {\n ...text_dialog.editing_annotation,\n contents: final_text,\n date: new Date().toISOString(), // Update modification date\n };\n \n handle_annotation_update(updated_annotation);\n setTextDialog(null);\n return;\n }\n \n // For new annotation: append timestamp if enabled\n const final_text = append_timestamp_if_enabled(text);\n \n // Create new annotation (existing code)\n // Convert screen coordinates to PDF coordinates\n // This gives us the exact click position in PDF space\n const [pdf_x, pdf_y] = text_dialog.mapper.to_pdf(text_dialog.screen_x, text_dialog.screen_y);\n \n // Create a text annotation at the clicked position\n //\n // IMPORTANT: For FreeText annotations, the annotation rect serves as a POSITION MARKER only.\n // The actual rendered box dimensions are calculated dynamically during rendering based on:\n // - Text content length\n // - Font size from config\n // - Padding values from config\n //\n // WHY PLACEHOLDER DIMENSIONS:\n // We store minimal placeholder dimensions because:\n // 1. The annotation rect format requires [x1, y1, x2, y2] coordinates\n // 2. We can't know the final text dimensions until we have the text content\n // 3. The rendering logic calculates the actual box size from text + padding\n // 4. Only rect[0] and rect[1] (top-left) matter - they mark the click position\n //\n // ⚠️ DO NOT change placeholder dimensions without updating rendering logic!\n // The rendering code in annotation_overlay.tsx uses screen_x1/y1 directly (not Math.min)\n // to avoid coordinate conversion issues. If placeholder dimensions change significantly,\n // ensure the rendering logic still correctly uses the top-left corner.\n const placeholder_width = 100; // Minimal placeholder width (not used for rendering)\n const placeholder_height = 30; // Minimal placeholder height (not used for rendering)\n \n // Get text color from config with fallback hierarchy:\n // freetext_text_color (if explicitly set) > font_foreground_color > default black\n // Only use freetext_text_color if it's not the default black value\n const freetext_text_color = config_ref.current?.freetext_annotation.freetext_text_color;\n const font_foreground_color = config_ref.current?.fonts.font_foreground_color;\n \n // Use freetext_text_color only if it's explicitly set and not the default black\n // Otherwise, fall back to font_foreground_color\n const text_color = (freetext_text_color && freetext_text_color !== '#000000') \n ? freetext_text_color\n : (font_foreground_color || '#000000');\n \n // Create FreeText annotation\n // rect[0] and rect[1] = pdf_x, pdf_y: These are CRITICAL - they mark where the user clicked\n // rect[2] and rect[3] = placeholder bottom-right: These are NOT used for positioning\n // The rendering code MUST use rect[0]/rect[1] directly after conversion (see annotation_overlay.tsx)\n const annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: 'FreeText',\n page_index: text_dialog.page_index,\n rect: [\n pdf_x, // Top-left X (click position)\n pdf_y, // Top-left Y (click position)\n pdf_x + placeholder_width, // Bottom-right X (placeholder)\n pdf_y + placeholder_height, // Bottom-right Y (placeholder)\n ],\n author: 'User',\n date: new Date().toISOString(),\n contents: final_text,\n color: text_color,\n };\n \n handle_annotation_create(annotation);\n setTextDialog(null);\n }}\n />\n )}\n\n {/* Extract Error Dialog */}\n {extract_error && (\n <div className=\"cls_pdf_viewer_error_dialog_overlay\">\n <div className=\"cls_pdf_viewer_error_dialog\">\n <div className=\"cls_pdf_viewer_error_dialog_header\">\n <span className=\"cls_pdf_viewer_error_dialog_title\">Extraction Error</span>\n <button\n type=\"button\"\n onClick={() => setExtractError(null)}\n className=\"cls_pdf_viewer_error_dialog_close\"\n aria-label=\"Close\"\n >\n <X size={16} />\n </button>\n </div>\n <div className=\"cls_pdf_viewer_error_dialog_content\">\n {extract_error}\n </div>\n <div className=\"cls_pdf_viewer_error_dialog_footer\">\n <button\n type=\"button\"\n onClick={() => setExtractError(null)}\n className=\"cls_pdf_viewer_error_dialog_button\"\n >\n OK\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n});\n\n// Set display name for debugging\nPdfViewer.displayName = 'PdfViewer';\n\nexport default PdfViewer;\n\n","/**\n * Toolbar Dropdown Button Component\n * Split button with main action and dropdown menu for additional options\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronDown } from 'lucide-react';\nimport { cn } from '../../utils/cn';\n\nexport interface DropdownOption {\n /** Unique identifier for the option */\n id: string;\n /** Display label */\n label: string;\n /** Icon to display (optional) */\n icon?: React.ReactNode;\n /** Click handler */\n on_click: () => void;\n /** Whether the option is disabled */\n disabled?: boolean;\n}\n\nexport interface ToolbarDropdownButtonProps {\n /** Icon for the main button */\n icon: React.ReactNode;\n /** Aria label for accessibility */\n aria_label: string;\n /** Tooltip text */\n title: string;\n /** Handler for main button click */\n on_main_click: () => void;\n /** Dropdown options */\n options: DropdownOption[];\n /** Button background color */\n background_color?: string;\n /** Button hover background color */\n background_color_hover?: string;\n /** Button text/icon color */\n text_color?: string;\n /** Whether the button is disabled */\n disabled?: boolean;\n}\n\n/**\n * Toolbar Dropdown Button\n * Split button design with main action and dropdown chevron\n */\nexport const ToolbarDropdownButton: React.FC<ToolbarDropdownButtonProps> = ({\n icon,\n aria_label,\n title,\n on_main_click,\n options,\n background_color = '#ffffff',\n background_color_hover = '#f3f4f6',\n text_color = '#374151',\n disabled = false,\n}) => {\n const [dropdown_open, setDropdownOpen] = useState(false);\n const [is_main_hovered, setIsMainHovered] = useState(false);\n const [is_chevron_hovered, setIsChevronHovered] = useState(false);\n const container_ref = useRef<HTMLDivElement>(null);\n const dropdown_ref = useRef<HTMLDivElement>(null);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handle_click_outside = (e: MouseEvent) => {\n if (container_ref.current && !container_ref.current.contains(e.target as Node)) {\n setDropdownOpen(false);\n }\n };\n\n if (dropdown_open) {\n document.addEventListener('mousedown', handle_click_outside);\n return () => {\n document.removeEventListener('mousedown', handle_click_outside);\n };\n }\n return undefined;\n }, [dropdown_open]);\n\n // Close dropdown on escape key\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && dropdown_open) {\n setDropdownOpen(false);\n }\n };\n\n if (dropdown_open) {\n document.addEventListener('keydown', handle_keydown);\n return () => {\n document.removeEventListener('keydown', handle_keydown);\n };\n }\n return undefined;\n }, [dropdown_open]);\n\n const handle_main_click = () => {\n if (!disabled) {\n on_main_click();\n }\n };\n\n const handle_chevron_click = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!disabled) {\n setDropdownOpen(!dropdown_open);\n }\n };\n\n const handle_option_click = (option: DropdownOption) => {\n if (!option.disabled) {\n option.on_click();\n setDropdownOpen(false);\n }\n };\n\n return (\n <div ref={container_ref} className=\"cls_toolbar_dropdown_container\" style={{ position: 'relative' }}>\n <div\n className={cn(\n 'cls_toolbar_dropdown_button',\n disabled && 'cls_toolbar_dropdown_button_disabled'\n )}\n style={{\n display: 'flex',\n alignItems: 'stretch',\n borderRadius: '0.25rem',\n overflow: 'hidden',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n {/* Main button area */}\n <button\n type=\"button\"\n onClick={handle_main_click}\n className=\"cls_toolbar_dropdown_main\"\n aria-label={aria_label}\n title={title}\n disabled={disabled}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '0.25rem 0.5rem',\n backgroundColor: is_main_hovered ? background_color_hover : background_color,\n color: text_color,\n border: '1px solid #d1d5db',\n borderRight: 'none',\n borderTopLeftRadius: '0.25rem',\n borderBottomLeftRadius: '0.25rem',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={() => setIsMainHovered(true)}\n onMouseLeave={() => setIsMainHovered(false)}\n >\n {icon}\n </button>\n\n {/* Chevron dropdown trigger */}\n <button\n type=\"button\"\n onClick={handle_chevron_click}\n className=\"cls_toolbar_dropdown_chevron\"\n aria-label=\"Show more options\"\n aria-expanded={dropdown_open}\n aria-haspopup=\"menu\"\n disabled={disabled}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '0.25rem 0.25rem',\n backgroundColor: is_chevron_hovered ? background_color_hover : background_color,\n color: text_color,\n border: '1px solid #d1d5db',\n borderTopRightRadius: '0.25rem',\n borderBottomRightRadius: '0.25rem',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={() => setIsChevronHovered(true)}\n onMouseLeave={() => setIsChevronHovered(false)}\n >\n <ChevronDown\n size={12}\n style={{\n transform: dropdown_open ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 0.15s ease',\n }}\n />\n </button>\n </div>\n\n {/* Dropdown menu */}\n {dropdown_open && (\n <div\n ref={dropdown_ref}\n className=\"cls_toolbar_dropdown_menu\"\n role=\"menu\"\n style={{\n position: 'absolute',\n top: '100%',\n left: '0',\n marginTop: '4px',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d5db',\n borderRadius: '0.375rem',\n boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',\n zIndex: 1000,\n minWidth: '160px',\n overflow: 'hidden',\n }}\n >\n {options.map((option) => (\n <button\n key={option.id}\n type=\"button\"\n role=\"menuitem\"\n onClick={() => handle_option_click(option)}\n disabled={option.disabled}\n className={cn(\n 'cls_toolbar_dropdown_item',\n option.disabled && 'cls_toolbar_dropdown_item_disabled'\n )}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n width: '100%',\n padding: '8px 12px',\n textAlign: 'left',\n fontSize: '13px',\n color: option.disabled ? '#9ca3af' : '#374151',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: option.disabled ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.15s ease',\n }}\n onMouseEnter={(e) => {\n if (!option.disabled) {\n e.currentTarget.style.backgroundColor = '#f3f4f6';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n }}\n >\n {option.icon && <span style={{ flexShrink: 0 }}>{option.icon}</span>}\n <span>{option.label}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n};\n\nexport default ToolbarDropdownButton;\n","/**\n * Class name utility function\n * Combines clsx and tailwind-merge for better class merging\n */\n\nimport { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n\n","/**\n * PDF Worker Setup\n * Configures pdfjs-dist to use Web Workers for PDF processing\n * This ensures PDF parsing and rendering happens off the main thread\n * \n * IMPORTANT: This module uses dynamic imports to prevent SSR evaluation\n * PDF.js can only run in the browser, so we must avoid importing it during SSR\n */\n\n// Type imports are safe - they don't execute code\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { get_logger } from '../../utils/logger';\n\n// Track if worker has been configured to avoid multiple configurations\nlet worker_configured = false;\n\n/**\n * Configure the PDF.js worker dynamically (only in browser)\n * This function must be called before loading any PDF documents\n * @returns Promise that resolves when worker is configured\n */\nasync function configure_worker(): Promise<void> {\n const logger = get_logger();\n // Only configure in browser environment - double check\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return;\n }\n\n // Skip if already configured\n if (worker_configured) {\n return;\n }\n\n try {\n // Use a dynamic import that only executes in browser\n // Wrap in a function that checks browser environment again\n const pdfjs_module = await (async () => {\n if (typeof window === 'undefined') {\n throw new Error('Cannot configure PDF.js worker in non-browser environment');\n }\n // Dynamic import - only loads in browser\n return await import('pdfjs-dist');\n })();\n \n const { GlobalWorkerOptions, version } = pdfjs_module;\n const pdfjsVersion = version;\n \n // jsdelivr CDN - supports all npm package versions\n GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`;\n \n logger.info(`Worker configured: ${GlobalWorkerOptions.workerSrc}`);\n worker_configured = true;\n \n // Alternative CDN options (uncomment to use):\n // - cdnjs (may not have all versions): `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsVersion}/pdf.worker.min.mjs`\n // - unpkg: `https://unpkg.com/pdfjs-dist@${pdfjsVersion}/build/pdf.worker.min.mjs`\n \n // For offline/local development, you can:\n // 1. Copy pdfjs-dist/build/pdf.worker.min.mjs to your public folder\n // 2. Set: GlobalWorkerOptions.workerSrc = '/pdf.worker.min.mjs';\n } catch (error) {\n // Only log error if in browser - don't throw during SSR\n if (typeof window !== 'undefined') {\n logger.error('Error configuring worker', { data: error });\n throw error;\n }\n }\n}\n\n/**\n * Load a PDF document from a URL or ArrayBuffer\n * For local files (like in Storybook), fetch as ArrayBuffer for better compatibility\n * @param source - URL string, ArrayBuffer, or Uint8Array\n * @returns Promise resolving to PDFDocumentProxy\n */\nexport async function load_pdf_document(\n source: string | ArrayBuffer | Uint8Array\n): Promise<PDFDocumentProxy> {\n // Ensure we're in browser environment - multiple checks\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n throw new Error('load_pdf_document can only be called in the browser');\n }\n \n // Additional check: ensure we're not in Node.js environment\n if (typeof process !== 'undefined' && process.versions && process.versions.node) {\n throw new Error('load_pdf_document cannot be called in Node.js environment');\n }\n \n // Configure worker first (idempotent - won't reconfigure if already done)\n await configure_worker();\n \n const logger = get_logger();\n // Dynamic import of getDocument - direct import() for bundler compatibility\n const pdfjs_module = await import('pdfjs-dist');\n const { getDocument } = pdfjs_module;\n\n logger.info('Loading PDF', { data: { source: typeof source === 'string' ? source : 'ArrayBuffer/Uint8Array' } });\n \n try {\n // If source is a URL string, try to fetch it as ArrayBuffer for better compatibility\n let pdfData: ArrayBuffer | Uint8Array | string = source;\n \n if (typeof source === 'string') {\n // Check if it's a relative URL (likely a local file)\n if (source.startsWith('/') || source.startsWith('./') || !source.includes('://')) {\n logger.info('Fetching local PDF file as ArrayBuffer', { data: { source } });\n try {\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\n }\n pdfData = await response.arrayBuffer();\n logger.info('PDF fetched successfully', { data: { size: pdfData.byteLength } });\n } catch (fetchError) {\n logger.error('Error fetching PDF as ArrayBuffer, trying URL directly', { data: fetchError });\n // Fall back to URL if fetch fails\n pdfData = source;\n }\n }\n }\n \n const loading_task = getDocument({\n url: typeof pdfData === 'string' ? pdfData : undefined,\n data: typeof pdfData !== 'string' ? pdfData : undefined,\n verbosity: 0, // Suppress console warnings\n // Add CORS support\n httpHeaders: {},\n withCredentials: false,\n // Enable range requests for better performance\n rangeChunkSize: 65536,\n });\n \n const document = await loading_task.promise;\n logger.info('PDF loaded successfully', { data: { pages: document.numPages } });\n return document;\n } catch (error) {\n logger.error('Error loading PDF', { data: error });\n throw error;\n }\n}\n\n/**\n * Export types for use in components\n * Note: getDocument and GlobalWorkerOptions are not exported directly\n * to prevent SSR evaluation - use load_pdf_document instead\n */\nexport type { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';\n\n/**\n * Export configure_worker for components that need to ensure worker is configured\n * This is called automatically by load_pdf_document, so you typically don't need this\n */\nexport { configure_worker };\n","/**\n * PDF Viewer Layout Component\n * Main layout container with scrollable viewport\n * Manages page rendering and annotation overlay\n */\n\nimport React, { useState, useRef, useEffect, useCallback } from 'react';\nimport type { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist';\nimport type { PdfAnnotation, CoordinateMapper, PageDimensions, PdfViewerConfig } from '../../types';\nimport { PdfPageRenderer } from './pdf_page_renderer';\nimport { AnnotationOverlay } from './annotation_overlay';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for PdfViewerLayout component\n */\nexport interface PdfViewerLayoutProps {\n pdf_document: PDFDocumentProxy;\n scale: number;\n annotations: PdfAnnotation[];\n current_tool: 'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null;\n on_annotation_create: (annotation: PdfAnnotation) => void;\n on_context_menu: (e: React.MouseEvent, page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper) => void;\n on_annotation_click: (annotation: PdfAnnotation, screen_x: number, screen_y: number, mapper: CoordinateMapper, viewport_x: number, viewport_y: number) => void;\n on_freetext_click?: (page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper, viewport_x: number, viewport_y: number) => void;\n background_color?: string;\n config: PdfViewerConfig | null;\n className?: string;\n /** Page rotation state - Map of page_index to rotation degrees (0, 90, 180, 270) */\n page_rotations?: Map<number, number>;\n /** Callback when current visible page changes */\n on_visible_page_change?: (page_index: number) => void;\n}\n\n/**\n * PDF Viewer Layout Component\n * Manages page rendering and annotation overlay coordination\n */\nexport const PdfViewerLayout: React.FC<PdfViewerLayoutProps> = ({\n pdf_document,\n scale,\n annotations = [],\n current_tool = 'Square',\n on_annotation_create,\n on_context_menu,\n on_annotation_click,\n on_freetext_click,\n background_color = '#2d2d2d',\n config = null,\n className = '',\n page_rotations = new Map(),\n on_visible_page_change,\n}) => {\n const [pages, setPages] = useState<PDFPageProxy[]>([]);\n const [loading, setLoading] = useState(true);\n const [coordinate_mappers, setCoordinateMappers] = useState<\n Map<number, { mapper: CoordinateMapper; dimensions: PageDimensions }>\n >(new Map());\n const container_ref = useRef<HTMLDivElement>(null);\n const has_centered_ref = useRef(false);\n const page_refs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // Pan/scroll state\n const [is_panning, setIsPanning] = useState(false);\n const pan_start_ref = useRef<{ x: number; y: number; scrollLeft: number; scrollTop: number } | null>(null);\n\n // Track visible page using IntersectionObserver\n useEffect(() => {\n if (!container_ref.current || pages.length === 0 || !on_visible_page_change) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n // Find the most visible page (highest intersection ratio)\n let max_ratio = 0;\n let most_visible_page = 0;\n\n entries.forEach((entry) => {\n const page_index = parseInt(entry.target.getAttribute('data-page-index') || '0', 10);\n if (entry.intersectionRatio > max_ratio) {\n max_ratio = entry.intersectionRatio;\n most_visible_page = page_index;\n }\n });\n\n if (max_ratio > 0) {\n on_visible_page_change(most_visible_page);\n }\n },\n {\n root: container_ref.current,\n threshold: [0, 0.25, 0.5, 0.75, 1.0],\n }\n );\n\n // Observe all page wrappers\n page_refs.current.forEach((element) => {\n observer.observe(element);\n });\n\n return () => {\n observer.disconnect();\n };\n }, [pages.length, on_visible_page_change]);\n\n // Load all pages from the PDF document\n useEffect(() => {\n if (!pdf_document) {\n return;\n }\n setLoading(true);\n const num_pages = pdf_document.numPages;\n const page_promises: Promise<PDFPageProxy>[] = [];\n\n for (let i = 1; i <= num_pages; i++) {\n page_promises.push(pdf_document.getPage(i));\n }\n\n Promise.all(page_promises)\n .then((loaded_pages) => {\n setPages(loaded_pages);\n setLoading(false);\n // Reset centered flag when PDF document changes\n has_centered_ref.current = false;\n })\n .catch((error) => {\n const logger = get_logger();\n logger.error('Error loading PDF pages', { data: error });\n setLoading(false);\n });\n }, [pdf_document]);\n\n // Handle coordinate mapper ready callback - memoized to prevent re-renders\n const handle_coordinate_mapper_ready = useCallback((\n page_index: number,\n mapper: CoordinateMapper,\n dimensions: PageDimensions\n ) => {\n setCoordinateMappers((prev) => {\n // Check if the mapper data has actually changed to avoid unnecessary updates\n const existing = prev.get(page_index);\n if (existing && \n existing.dimensions.width === dimensions.width && \n existing.dimensions.height === dimensions.height) {\n // Dimensions haven't changed, don't update\n return prev;\n }\n const new_map = new Map(prev);\n new_map.set(page_index, { mapper, dimensions });\n return new_map;\n });\n }, []);\n\n // Center horizontal scroll when PDF first loads\n useEffect(() => {\n // Only center once when pages are loaded and we have at least one mapper\n if (loading || pages.length === 0 || coordinate_mappers.size === 0 || has_centered_ref.current) {\n return;\n }\n\n // Wait for next frame to ensure layout is calculated\n const timeout_id = setTimeout(() => {\n if (container_ref.current) {\n const container = container_ref.current;\n const scroll_width = container.scrollWidth;\n const client_width = container.clientWidth;\n \n // Only center if content is wider than container\n if (scroll_width > client_width) {\n const center_scroll = (scroll_width - client_width) / 2;\n container.scrollLeft = center_scroll;\n has_centered_ref.current = true;\n } else {\n // Content fits, mark as centered anyway\n has_centered_ref.current = true;\n }\n }\n }, 100); // Small delay to ensure layout is complete\n\n return () => {\n clearTimeout(timeout_id);\n };\n }, [loading, pages.length, coordinate_mappers.size]);\n\n // Pan/scroll handlers (only active when current_tool is null/pan mode)\n const handle_mouse_down = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n // Only handle left mouse button\n if (e.button !== 0) return;\n \n const native_event = e.nativeEvent as unknown as { __annotation_clicked?: string; __annotation_click_source?: string };\n if (native_event?.__annotation_clicked) {\n const logger = get_logger();\n logger.debug(\n `Layout received annotation click marker id=${native_event.__annotation_clicked}, source=${native_event.__annotation_click_source || 'unknown'}`\n );\n return;\n }\n \n // Only pan when no tool is selected (pan mode)\n if (current_tool !== null) return;\n \n if (container_ref.current) {\n setIsPanning(true);\n pan_start_ref.current = {\n x: e.clientX,\n y: e.clientY,\n scrollLeft: container_ref.current.scrollLeft,\n scrollTop: container_ref.current.scrollTop,\n };\n e.preventDefault(); // Prevent text selection while panning\n e.stopPropagation(); // Prevent event bubbling\n container_ref.current.style.cursor = 'grabbing';\n \n }\n }, [current_tool]);\n\n const handle_mouse_move = useCallback((e: React.MouseEvent<HTMLDivElement> | MouseEvent) => {\n if (!is_panning || !pan_start_ref.current || !container_ref.current) return;\n \n // Prevent default to avoid text selection and other default behaviors\n e.preventDefault();\n \n const delta_x = pan_start_ref.current.x - e.clientX;\n const delta_y = pan_start_ref.current.y - e.clientY;\n \n // Calculate new scroll positions\n const max_scroll_left = Math.max(0, container_ref.current.scrollWidth - container_ref.current.clientWidth);\n const max_scroll_top = Math.max(0, container_ref.current.scrollHeight - container_ref.current.clientHeight);\n \n const new_scroll_left = Math.max(0, Math.min(max_scroll_left, pan_start_ref.current.scrollLeft + delta_x));\n const new_scroll_top = Math.max(0, Math.min(max_scroll_top, pan_start_ref.current.scrollTop + delta_y));\n \n // Update both horizontal and vertical scroll positions (browser will clamp these anyway)\n container_ref.current.scrollLeft = new_scroll_left;\n container_ref.current.scrollTop = new_scroll_top;\n \n }, [is_panning]);\n\n const handle_mouse_up = useCallback(() => {\n if (container_ref.current) {\n container_ref.current.style.cursor = current_tool === null ? 'grab' : 'default';\n }\n setIsPanning(false);\n pan_start_ref.current = null;\n }, [current_tool]);\n\n // Update cursor style based on current tool\n useEffect(() => {\n if (container_ref.current) {\n if (current_tool === null) {\n container_ref.current.style.cursor = is_panning ? 'grabbing' : 'grab';\n } else {\n container_ref.current.style.cursor = 'default';\n }\n }\n }, [current_tool, is_panning]);\n\n // Add global mouse move and up listeners for panning\n useEffect(() => {\n if (is_panning) {\n window.addEventListener('mousemove', handle_mouse_move);\n window.addEventListener('mouseup', handle_mouse_up);\n \n return () => {\n window.removeEventListener('mousemove', handle_mouse_move);\n window.removeEventListener('mouseup', handle_mouse_up);\n };\n }\n return undefined;\n }, [is_panning, handle_mouse_move, handle_mouse_up]);\n\n // AnnotationOverlay now handles annotation clicks directly and stamps native events.\n // The container only pans when those markers are absent, preventing accidental grab mode.\n\n if (loading) {\n return (\n <div className={cn('cls_pdf_viewer_loading', className)}>\n <div className=\"cls_pdf_viewer_spinner\">Loading PDF...</div>\n </div>\n );\n }\n\n return (\n <div\n ref={container_ref}\n className={cn('cls_pdf_viewer_layout', className)}\n style={{\n // Don't constrain width/height - let content determine size\n // This allows container to expand beyond viewport when zoomed\n position: 'relative',\n backgroundColor: background_color,\n // Cursor is managed dynamically - default to grab in pan mode, but annotations will override\n cursor: current_tool === null ? (is_panning ? 'grabbing' : 'grab') : 'default',\n userSelect: is_panning ? 'none' : 'auto',\n // Allow both horizontal and vertical scrolling\n overflow: 'auto',\n overflowX: 'auto',\n overflowY: 'auto',\n // Container must be viewport size (100%) to create scrollable area\n // Content inside (pages_container) expands beyond this to enable scrolling\n width: '100%',\n height: '100%',\n // Don't constrain content expansion\n minWidth: 0,\n minHeight: 0,\n }}\n onMouseDown={handle_mouse_down}\n onMouseMove={(e) => {\n // Check if mouse is over an annotation overlay\n // If so, don't override cursor - let the annotation overlay manage it\n const target = e.target as HTMLElement;\n if (target.closest('svg.cls_annotation_overlay') || target.closest('rect[style*=\"cursor: pointer\"]')) {\n // Don't override cursor - annotation overlay will handle it\n return;\n }\n \n // Update cursor for pan mode if not over annotation\n if (container_ref.current && current_tool === null && !is_panning) {\n container_ref.current.style.cursor = 'grab';\n }\n }}\n >\n <div className=\"cls_pdf_viewer_pages_container\">\n {pages.map((page, index) => {\n const mapper_data = coordinate_mappers.get(index);\n const page_annotations = annotations?.filter(\n (ann) => ann.page_index === index\n ) || [];\n const page_rotation = page_rotations.get(index) || 0;\n\n return (\n <div\n key={index}\n ref={(el) => {\n if (el) {\n page_refs.current.set(index, el);\n } else {\n page_refs.current.delete(index);\n }\n }}\n data-page-index={index}\n className=\"cls_pdf_viewer_page_wrapper\"\n style={{\n position: 'relative',\n marginBottom: '20px',\n // Inherit cursor from parent (grab/grabbing in pan mode)\n cursor: 'inherit',\n }}\n >\n {/* PDF Page Renderer */}\n <PdfPageRenderer\n page={page}\n page_index={index}\n scale={scale}\n rotation={page_rotation}\n config={config}\n on_coordinate_mapper_ready={(mapper, dimensions) =>\n handle_coordinate_mapper_ready(index, mapper, dimensions)\n }\n />\n\n {/* Annotation Overlay - Must be positioned absolutely to overlay the canvas */}\n {mapper_data && (\n <AnnotationOverlay\n width={mapper_data.dimensions.width}\n height={mapper_data.dimensions.height}\n page_index={index}\n map_coords={mapper_data.mapper}\n annotations={page_annotations}\n current_tool={current_tool}\n config={config}\n on_annotation_create={on_annotation_create}\n on_context_menu={(e, screen_x, screen_y) => {\n if (on_context_menu && mapper_data.mapper) {\n on_context_menu(e, index, screen_x, screen_y, mapper_data.mapper);\n }\n }}\n on_annotation_click={(annotation, screen_x, screen_y, viewport_x, viewport_y) => {\n if (on_annotation_click && mapper_data.mapper) {\n on_annotation_click(annotation, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);\n }\n }}\n on_freetext_click={(screen_x, screen_y, viewport_x, viewport_y) => {\n if (on_freetext_click && mapper_data.mapper) {\n on_freetext_click(index, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);\n }\n }}\n />\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default PdfViewerLayout;\n\n","/**\n * PDF Page Renderer Component\n * Renders a single PDF page to a canvas element\n * Provides coordinate mapping utilities for annotations\n */\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport { create_coordinate_mapper } from '../../utils/coordinate_mapper';\nimport type { CoordinateMapper, PageDimensions, PdfViewerConfig } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for PDFPageRenderer component\n */\nexport interface PdfPageRendererProps {\n /** PDF page proxy object */\n page: PDFPageProxy;\n\n /** Zero-based page index */\n page_index: number;\n\n /** Zoom/scale factor */\n scale: number;\n\n /** Rotation in degrees (0, 90, 180, 270) */\n rotation?: number;\n\n /** Optional class name */\n className?: string;\n\n /** Callback to provide coordinate mapper to parent */\n on_coordinate_mapper_ready?: (mapper: CoordinateMapper, dimensions: PageDimensions) => void;\n\n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n}\n\n/**\n * PDF Page Renderer Component\n * Handles rendering of a single PDF page to canvas\n */\nexport const PdfPageRenderer: React.FC<PdfPageRendererProps> = ({\n page,\n page_index,\n scale,\n rotation = 0,\n className = '',\n on_coordinate_mapper_ready,\n config = null,\n}) => {\n const canvas_ref = useRef<HTMLCanvasElement>(null);\n const render_task_ref = useRef<any>(null);\n const notified_dimensions_ref = useRef<{ width: number; height: number; scale: number } | null>(null);\n const callback_ref = useRef(on_coordinate_mapper_ready);\n \n // Update callback ref when it changes (but don't trigger re-render)\n useEffect(() => {\n callback_ref.current = on_coordinate_mapper_ready;\n }, [on_coordinate_mapper_ready]);\n \n // Calculate dimensions from viewport (doesn't change unless page, scale, or rotation changes)\n const viewport_dimensions = useMemo(() => {\n if (!page) return { width: 0, height: 0 };\n const viewport = page.getViewport({ scale, rotation });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n }, [page, scale, rotation]);\n\n // Create coordinate mapper - memoized to prevent recreation\n const coordinate_mapper = useMemo(() => {\n if (!page) return null;\n return create_coordinate_mapper(page, scale, rotation);\n }, [page, scale, rotation]);\n\n // Notify parent of coordinate mapper - only when dimensions actually change\n useEffect(() => {\n if (!page || !coordinate_mapper) return;\n \n const current_dimensions = viewport_dimensions;\n const last_notified = notified_dimensions_ref.current;\n \n // Only notify if dimensions or scale have actually changed\n if (!last_notified || \n last_notified.width !== current_dimensions.width || \n last_notified.height !== current_dimensions.height ||\n last_notified.scale !== scale) {\n if (callback_ref.current) {\n callback_ref.current(coordinate_mapper, current_dimensions);\n notified_dimensions_ref.current = { ...current_dimensions, scale };\n }\n }\n }, [page, coordinate_mapper, viewport_dimensions.width, viewport_dimensions.height, scale]);\n\n // Render the page onto the canvas\n useEffect(() => {\n // Ensure we're in browser environment\n if (typeof window === 'undefined') {\n return;\n }\n\n if (!page) {\n return;\n }\n\n if (!canvas_ref.current) {\n return;\n }\n\n // Cancel any previous render task and wait for it to complete\n // This prevents multiple renders on the same canvas (React Strict Mode issue)\n let cancelled = false;\n const cancel_previous = async () => {\n if (render_task_ref.current) {\n try {\n render_task_ref.current.cancel();\n // Wait for cancellation to complete\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 render and then start new one\n cancel_previous().then(() => {\n // Check if effect was cancelled during async operation\n if (cancelled || !canvas_ref.current) {\n return;\n }\n\n // Get the viewport with the current scale and rotation\n const viewport = page.getViewport({ scale, rotation });\n\n // Set up canvas\n const canvas = canvas_ref.current;\n const context = canvas.getContext('2d', { alpha: false }); // Disable alpha for better performance\n if (!context) {\n const logger = get_logger();\n logger.error(`Page ${page_index}: Cannot get 2D context`);\n return;\n }\n\n // Handle high DPI displays\n const output_scale = window.devicePixelRatio || 1;\n\n // Set native canvas size for sharp rendering\n // Note: Setting canvas.width/height automatically clears the canvas\n // This also invalidates any previous render tasks\n canvas.width = viewport.width * output_scale;\n canvas.height = viewport.height * output_scale;\n\n // Set CSS size (what the browser displays)\n canvas.style.width = `${viewport.width}px`;\n canvas.style.height = `${viewport.height}px`;\n\n // Scale the context to match device pixel ratio\n context.scale(output_scale, output_scale);\n\n // Fill canvas with white background before rendering\n // This ensures any transparent areas in the PDF appear white\n context.fillStyle = '#ffffff';\n context.fillRect(0, 0, viewport.width, viewport.height);\n\n // Render the page\n // Note: annotationMode: 0 disables annotation rendering on the canvas\n // This prevents form fields and other annotations from being drawn with incorrect fills\n // Our custom annotation overlay handles annotation display separately\n const render_context = {\n canvasContext: context,\n viewport: viewport,\n annotationMode: 0, // DISABLE - don't render annotations on canvas\n background: 'white', // Explicitly set white background for pdfjs rendering\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 // Only clear ref if this is still the current render task\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n })\n .catch((error) => {\n // Ignore cancellation errors (expected during cleanup)\n if (error.name !== 'RenderingCancelledException') {\n const logger = get_logger();\n logger.error(`Page ${page_index}: Error rendering`, { data: error });\n }\n // Only clear ref if this is still the current render task\n if (render_task_ref.current === render_task) {\n render_task_ref.current = null;\n }\n });\n });\n\n // Cleanup: cancel rendering if component unmounts or dependencies 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 cancellation errors\n }\n render_task_ref.current = null;\n }\n };\n }, [page, scale, rotation, page_index]);\n\n // Show loading only if we don't have a page yet\n if (!page) {\n return (\n <div className={cn('cls_pdf_page_loading', className)}>\n <div className=\"cls_pdf_page_spinner\">Loading page...</div>\n </div>\n );\n }\n\n // Get styling values from config or use defaults\n const page_config = config?.page_styling || default_config.page_styling;\n \n return (\n <div\n className={cn('cls_pdf_page_container', className)}\n style={{\n position: 'relative',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n border: `1px solid ${page_config.page_border_color}`,\n boxShadow: page_config.page_box_shadow,\n backgroundColor: page_config.page_background_color,\n // Inherit cursor from parent (grab/grabbing in pan mode)\n cursor: 'inherit',\n }}\n >\n {/* Canvas: The PDF rendering base layer */}\n <canvas\n ref={canvas_ref}\n className=\"cls_pdf_page_canvas\"\n style={{\n display: 'block',\n width: viewport_dimensions.width,\n height: viewport_dimensions.height,\n pointerEvents: 'none', // Allow events to pass through to SVG overlay\n }}\n aria-label={`PDF page ${page_index + 1}`}\n />\n </div>\n );\n};\n\nexport default PdfPageRenderer;\n\n","/**\n * Coordinate Mapper Utilities\n * Handles conversion between PDF coordinate space and Screen coordinate space\n * PDF coordinates use bottom-left origin, Screen coordinates use top-left origin\n */\n\nimport type { PDFPageProxy } from 'pdfjs-dist';\nimport type { CoordinateMapper } from '../types';\n\n/**\n * Create a coordinate mapper for a specific page, scale, and rotation\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @param rotation - Rotation in degrees (0, 90, 180, 270)\n * @returns CoordinateMapper with to_pdf and to_screen methods\n */\nexport function create_coordinate_mapper(\n page: PDFPageProxy,\n scale: number,\n rotation: number = 0\n): CoordinateMapper {\n const viewport = page.getViewport({ scale, rotation });\n\n return {\n /**\n * Convert screen (CSS pixel) coordinates to PDF (abstract) coordinates\n * @param x_screen - X coordinate in screen space\n * @param y_screen - Y coordinate in screen space\n * @returns [x_pdf, y_pdf] coordinates in PDF space\n */\n to_pdf: (x_screen: number, y_screen: number): [number, number] => {\n // PDF.js viewport handles the coordinate transformation\n // including the origin conversion (top-left vs bottom-left)\n const result = viewport.convertToPdfPoint(x_screen, y_screen);\n return [result[0], result[1]];\n },\n\n /**\n * Convert PDF (abstract) coordinates to Screen (CSS pixel) coordinates\n * @param x_pdf - X coordinate in PDF space\n * @param y_pdf - Y coordinate in PDF space\n * @returns [x_screen, y_screen] coordinates in screen space\n */\n to_screen: (x_pdf: number, y_pdf: number): [number, number] => {\n const result = viewport.convertToViewportPoint(x_pdf, y_pdf);\n return [result[0], result[1]];\n },\n };\n}\n\n/**\n * Get viewport dimensions for a page at a specific scale and rotation\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @param rotation - Rotation in degrees (0, 90, 180, 270)\n * @returns Object with width and height in screen pixels\n */\nexport function get_viewport_dimensions(\n page: PDFPageProxy,\n scale: number,\n rotation: number = 0\n): { width: number; height: number } {\n const viewport = page.getViewport({ scale, rotation });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n}\n\n","/**\n * Annotation Overlay Component\n * DOM/SVG layer for handling annotation interactions\n * Positioned above the canvas layer\n */\n\nimport React, { useState, useRef } from 'react';\nimport type { PdfAnnotation, CoordinateMapper, PdfViewerConfig } from '../../types';\nimport {\n calculate_rectangle_coords,\n is_rectangle_too_small,\n} from '../../utils/annotation_utils';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for AnnotationOverlay component\n */\nexport interface AnnotationOverlayProps {\n /** Page dimensions in screen space */\n width: number;\n height: number;\n \n /** Zero-based page index */\n page_index: number;\n \n /** Coordinate mapper for PDF ↔ Screen conversion */\n map_coords: CoordinateMapper;\n \n /** Existing annotations for this page */\n annotations?: PdfAnnotation[];\n \n /** Current annotation tool type */\n current_tool?: 'Square' | 'Highlight' | 'FreeText' | 'CustomBookmark' | null;\n \n /** Callback when annotation is created */\n on_annotation_create?: (annotation: PdfAnnotation) => void;\n \n /** Callback when right-click occurs */\n on_context_menu?: (event: React.MouseEvent, screen_x: number, screen_y: number) => void;\n \n /** Callback when annotation is clicked. screen_x/y are SVG-relative, viewport_x/y are viewport-relative (for positioning fixed dialogs). */\n on_annotation_click?: (annotation: PdfAnnotation, screen_x: number, screen_y: number, viewport_x: number, viewport_y: number) => void;\n\n /** Callback when FreeText tool is active and user clicks on empty area. screen_x/y are SVG-relative, viewport_x/y are viewport-relative. */\n on_freetext_click?: (screen_x: number, screen_y: number, viewport_x: number, viewport_y: number) => void;\n\n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n \n /** Optional class name */\n className?: string;\n}\n\n/**\n * Temporary drawing box component\n * Shows visual feedback while drawing\n */\nconst TempDrawBox: React.FC<{\n start: { x: number; y: number } | null;\n current: { x: number; y: number } | null;\n tool_type?: string;\n config?: PdfViewerConfig | null;\n}> = ({ start, current, tool_type = 'Square', config = null }) => {\n if (!start || !current) return null;\n\n const { x, y, width, height } = calculate_rectangle_coords(start, current);\n\n // Get config values or use defaults\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n\n // Helper to convert hex color to rgba\n const hex_to_rgba = (hex: string, opacity: number): string => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n };\n\n // Determine fill color and opacity based on tool type\n const get_fill_props = () => {\n switch (tool_type) {\n case 'Highlight':\n return {\n fill: hex_to_rgba(highlight_config.highlight_fill_color, highlight_config.highlight_fill_opacity),\n stroke: highlight_config.highlight_border_color,\n };\n case 'Square':\n return {\n fill: hex_to_rgba(square_config.square_fill_color, square_config.square_fill_opacity),\n stroke: square_config.square_border_color,\n };\n default:\n return {\n fill: 'rgba(0, 0, 255, 0.2)',\n stroke: '#0000FF',\n };\n }\n };\n\n const { fill, stroke } = get_fill_props();\n\n return (\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n stroke={stroke}\n strokeWidth=\"2\"\n fill={fill}\n pointerEvents=\"none\"\n />\n );\n};\n\n/**\n * Annotation Overlay Component\n * Handles mouse interactions for creating annotations\n */\nexport const AnnotationOverlay: React.FC<AnnotationOverlayProps> = ({\n width,\n height,\n page_index,\n map_coords,\n annotations = [],\n current_tool = 'Square',\n on_annotation_create,\n on_context_menu,\n on_annotation_click,\n on_freetext_click,\n config = null,\n className = '',\n}) => {\n const logger = get_logger();\n const [is_drawing, setIsDrawing] = useState(false);\n const [start_point, setStartPoint] = useState<{ x: number; y: number } | null>(null);\n const [current_point, setCurrentPoint] = useState<{ x: number; y: number } | null>(null);\n const [hovered_annotation_id, setHoveredAnnotationId] = useState<string | null>(null);\n const svg_ref = useRef<SVGSVGElement>(null);\n\n /**\n * Emit a concise debug log whenever we dispatch an annotation click.\n * This helps confirm left-click routing without flooding the console.\n */\n const log_annotation_click = (\n annotation: PdfAnnotation,\n origin: string,\n point: { x: number; y: number }\n ) => {\n logger.debug('Annotation click dispatched', {\n data: {\n origin,\n id: annotation.id,\n page: annotation.page_index,\n screen_x: point.x.toFixed(1),\n screen_y: point.y.toFixed(1),\n },\n });\n };\n\n // Filter annotations for this page\n const page_annotations = annotations.filter(\n (ann) => ann.page_index === page_index\n );\n\n // Check if a point is inside an annotation\n const is_point_in_annotation = (\n point: { x: number; y: number },\n annotation: PdfAnnotation\n ): boolean => {\n // Convert PDF coordinates to screen coordinates\n const [screen_x1, screen_y1] = map_coords.to_screen(\n annotation.rect[0],\n annotation.rect[1]\n );\n const [screen_x2, screen_y2] = map_coords.to_screen(\n annotation.rect[2],\n annotation.rect[3]\n );\n\n // For FreeText annotations, calculate box dimensions\n if (annotation.type === 'FreeText') {\n const fonts_config = config?.fonts || default_config.fonts;\n const freetext_config = config?.freetext_annotation || default_config.freetext_annotation;\n \n const text = annotation.contents || '';\n if (!text) return false;\n \n const font_size = fonts_config.freetext_font_size_default;\n const padding_h = freetext_config.freetext_padding_horizontal;\n const padding_v = freetext_config.freetext_padding_vertical;\n const text_width_estimate = font_size * 0.6 * text.length;\n const box_width = text_width_estimate + (padding_h * 2);\n const box_height = font_size + (padding_v * 2);\n \n const box_x = screen_x1;\n const box_y = screen_y1;\n \n // Check if point is inside the box\n return (\n point.x >= box_x &&\n point.x <= box_x + box_width &&\n point.y >= box_y &&\n point.y <= box_y + box_height\n );\n }\n \n // For rectangle annotations (Square, Highlight)\n const screen_x = Math.min(screen_x1, screen_x2);\n const screen_y = Math.min(screen_y1, screen_y2);\n const screen_width = Math.abs(screen_x2 - screen_x1);\n const screen_height = Math.abs(screen_y2 - screen_y1);\n \n // Check if point is inside the rectangle\n return (\n point.x >= screen_x &&\n point.x <= screen_x + screen_width &&\n point.y >= screen_y &&\n point.y <= screen_y + screen_height\n );\n };\n\n // Mouse event handlers\n const handle_mouse_down = (e: React.MouseEvent<SVGSVGElement>) => {\n // Only handle left mouse button\n if (e.button !== 0) return;\n\n // Get mouse position relative to SVG\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n\n const point = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n\n // CRITICAL: Check if clicking on an existing annotation FIRST\n // This must happen before any other mode checking (pan/drawing)\n // Annotations should be clickable in ALL modes (pan, Square, Highlight, etc.)\n // Only handle left mouse button - right-click is handled by context menu\n if (e.button === 0 && on_annotation_click) {\n for (const annotation of page_annotations) {\n if (is_point_in_annotation(point, annotation)) {\n \n // Mark event so pan handler knows an annotation was clicked\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'svg_hit_test';\n \n // Stop all event propagation - prevent pan mode and drawing from starting\n e.preventDefault();\n e.stopPropagation();\n e.nativeEvent.stopImmediatePropagation(); // Also stop immediate propagation\n // Call click handler with annotation, screen coordinates, and viewport coordinates\n log_annotation_click(annotation, 'svg_hit_test', point);\n on_annotation_click(annotation, point.x, point.y, e.clientX, e.clientY);\n return;\n }\n }\n } else if (e.button !== 0) {\n // Right-click or other buttons - let context menu handler process it\n return;\n } else if (!on_annotation_click) {\n logger.warn('on_annotation_click not provided');\n }\n\n // In pan mode (current_tool === null), allow panning by not capturing events\n if (!current_tool) {\n // Do not stop propagation; allow parent to handle pan\n return;\n }\n\n // For FreeText tool, open dialog immediately on click (no drag needed)\n if (current_tool === 'FreeText') {\n e.preventDefault();\n e.stopPropagation();\n if (on_freetext_click) {\n on_freetext_click(point.x, point.y, e.clientX, e.clientY);\n }\n return;\n }\n\n setIsDrawing(true);\n setStartPoint(point);\n setCurrentPoint(point);\n };\n\n const handle_mouse_move = (e: React.MouseEvent<SVGSVGElement>) => {\n if (!is_drawing || !start_point) return;\n\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n\n const point = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n };\n\n setCurrentPoint(point);\n };\n\n const handle_mouse_up = (_e: React.MouseEvent<SVGSVGElement>) => {\n if (!is_drawing || !start_point || !current_point) return;\n\n setIsDrawing(false);\n\n // Calculate final rectangle\n const screen_rect = calculate_rectangle_coords(start_point, current_point);\n\n // Ignore tiny clicks/drags\n if (is_rectangle_too_small(screen_rect, 5)) {\n setStartPoint(null);\n setCurrentPoint(null);\n return;\n }\n\n // Convert screen coordinates to PDF coordinates\n const [pdf_x1, pdf_y1] = map_coords.to_pdf(screen_rect.x, screen_rect.y);\n const [pdf_x2, pdf_y2] = map_coords.to_pdf(\n screen_rect.x + screen_rect.width,\n screen_rect.y + screen_rect.height\n );\n\n // Create PDF rect (ensure proper ordering)\n const pdf_rect: [number, number, number, number] = [\n Math.min(pdf_x1, pdf_x2),\n Math.min(pdf_y1, pdf_y2),\n Math.max(pdf_x1, pdf_x2),\n Math.max(pdf_y1, pdf_y2),\n ];\n\n // Get config values for default colors\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n \n // Create new annotation object\n const new_annotation: PdfAnnotation = {\n id: crypto.randomUUID(),\n type: current_tool || 'Square',\n page_index: page_index,\n rect: pdf_rect,\n author: 'User',\n date: new Date().toISOString(),\n contents: '',\n color: current_tool === 'Highlight' ? highlight_config.highlight_fill_color : square_config.square_fill_color,\n };\n\n // Notify parent component\n if (on_annotation_create) {\n on_annotation_create(new_annotation);\n }\n\n // Reset drawing state\n setStartPoint(null);\n setCurrentPoint(null);\n };\n\n const handle_mouse_leave = () => {\n // Stop drawing if mouse leaves the overlay\n if (is_drawing) {\n setIsDrawing(false);\n setStartPoint(null);\n setCurrentPoint(null);\n }\n };\n\n // Handle context menu (right-click)\n const handle_context_menu = (e: React.MouseEvent<SVGSVGElement>) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Get mouse position relative to SVG\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) {\n logger.warn('Could not get SVG bounding rect');\n return;\n }\n \n if (!on_context_menu) {\n logger.warn('on_context_menu callback not provided');\n return;\n }\n\n const screen_x = e.clientX - rect.left;\n const screen_y = e.clientY - rect.top;\n\n // Call parent handler with event and screen coordinates\n on_context_menu(e, screen_x, screen_y);\n };\n\n // Render existing annotations\n const render_annotation = (annotation: PdfAnnotation) => {\n // Convert PDF coordinates to screen coordinates\n // annotation.rect format: [x1, y1, x2, y2] where (x1, y1) is top-left, (x2, y2) is bottom-right\n // In PDF coordinates: origin (0,0) is at bottom-left, Y increases upward\n // In screen coordinates: origin (0,0) is at top-left, Y increases downward\n const [screen_x1, screen_y1] = map_coords.to_screen(\n annotation.rect[0], // Top-left X in PDF space\n annotation.rect[1] // Top-left Y in PDF space\n );\n const [screen_x2, screen_y2] = map_coords.to_screen(\n annotation.rect[2], // Bottom-right X in PDF space\n annotation.rect[3] // Bottom-right Y in PDF space\n );\n\n // For rectangle annotations (Square, Highlight), calculate normalized screen coordinates\n // Math.min ensures we always get the top-left corner, regardless of how rect was stored\n const screen_x = Math.min(screen_x1, screen_x2);\n const screen_y = Math.min(screen_y1, screen_y2);\n const screen_width = Math.abs(screen_x2 - screen_x1);\n const screen_height = Math.abs(screen_y2 - screen_y1);\n \n // Get config values or use defaults\n const fonts_config = config?.fonts || default_config.fonts;\n const highlight_config = config?.highlight_annotation || default_config.highlight_annotation;\n const square_config = config?.square_annotation || default_config.square_annotation;\n const freetext_config = config?.freetext_annotation || default_config.freetext_annotation;\n \n // Helper to convert hex color to rgba\n const hex_to_rgba = (hex: string, opacity: number): string => {\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n };\n\n // ============================================================================\n // FreeText Annotation Rendering\n // ============================================================================\n // \n // FreeText annotations differ from rectangle annotations (Square, Highlight) because:\n // 1. The annotation rect serves as a POSITION MARKER only (rect[0], rect[1] = click position)\n // 2. Box dimensions are calculated dynamically from text content + padding\n // 3. Positioning MUST use screen_x1/y1 directly, NOT Math.min()\n //\n // See detailed comments below for why Math.min() breaks positioning.\n //\n if (annotation.type === 'FreeText') {\n const text = annotation.contents || '';\n if (!text) return null; // Don't render if no text\n\n // Parse stamp styling from subject field if present\n let stamp_styling: any = null;\n if (annotation.subject) {\n try {\n const parsed = JSON.parse(annotation.subject);\n if (parsed && parsed.stamp_name) {\n stamp_styling = parsed;\n }\n } catch (e) {\n // Not JSON, ignore\n }\n }\n \n // Calculate font size - use stamp font_size if provided, otherwise config default\n const font_size = stamp_styling?.font_size !== undefined \n ? stamp_styling.font_size \n : fonts_config.freetext_font_size_default;\n \n // Text color priority: stamp font_color > annotation.color > freetext_text_color (if not default) > font_foreground_color > default black\n const text_color = stamp_styling?.font_color ||\n annotation.color || \n (freetext_config.freetext_text_color && freetext_config.freetext_text_color !== '#000000'\n ? freetext_config.freetext_text_color\n : fonts_config.font_foreground_color) ||\n '#000000';\n \n // Get font family - use stamp font_name if provided, otherwise config\n const font_family = stamp_styling?.font_name || fonts_config.freetext_font_family;\n \n // Get font weight - use stamp font_weight if provided, otherwise config\n const font_weight = stamp_styling?.font_weight !== undefined\n ? stamp_styling.font_weight\n : freetext_config.freetext_font_weight;\n \n // Get font style - use stamp font_style if provided, otherwise config\n const font_style = stamp_styling?.font_style !== undefined\n ? stamp_styling.font_style\n : freetext_config.freetext_font_style;\n \n // Get padding values\n const padding_h = freetext_config.freetext_padding_horizontal;\n const padding_v = freetext_config.freetext_padding_vertical;\n \n // Split text by newlines to calculate dimensions for multi-line text\n const text_lines = text.split('\\n');\n const max_line_length = Math.max(...text_lines.map(line => line.length), 1);\n \n // Measure text width - estimate based on font size and longest line length\n // Average character is about 0.6 * font_size wide for most fonts\n const text_width_estimate = font_size * 0.6 * max_line_length;\n \n // Calculate box dimensions based on text width + padding\n // Height needs to account for multiple lines (line height = font_size)\n const box_width = text_width_estimate + (padding_h * 2);\n const box_height = (font_size * text_lines.length) + (padding_v * 2);\n \n // ⚠️ CRITICAL FIX: Position must use screen_x1/screen_y1 DIRECTLY, not Math.min!\n //\n // WHY THIS MATTERS:\n // For FreeText annotations, annotation.rect[0] and annotation.rect[1] represent the EXACT\n // click position in PDF space (where the user right-clicked). When we convert these to\n // screen coordinates, we get screen_x1 and screen_y1, which is the exact click position.\n //\n // The annotation rect also has placeholder dimensions (rect[2], rect[3]) representing a\n // minimal placeholder box. When converted to screen coordinates, these become screen_x2/y2.\n //\n // COORDINATE SYSTEM DIFFERENCE:\n // - PDF coordinates: Y=0 at bottom, Y increases upward\n // - Screen coordinates: Y=0 at top, Y increases downward\n // Because of this difference, when converting the placeholder bottom-right:\n // - screen_y2 will be SMALLER than screen_y1 (higher on screen = lower Y value)\n // - Using Math.min(screen_y1, screen_y2) would incorrectly select screen_y2\n // - This creates an offset equal to the placeholder height, misaligning the border\n //\n // SOLUTION:\n // Always use screen_x1 and screen_y1 directly for FreeText annotations. These represent\n // the converted coordinates of annotation.rect[0]/rect[1], which is the exact click position.\n // Do NOT use Math.min() here - it will break positioning due to coordinate system differences.\n //\n // NOTE: For rectangle annotations (Square, Highlight), we DO use Math.min because those\n // annotations have actual meaningful dimensions, not placeholders.\n const box_x = screen_x1;\n const box_y = screen_y1;\n \n // Text position: add padding offset from box top-left\n const text_x = box_x + padding_h;\n const text_y = box_y + padding_v + font_size; // Y is baseline, so add padding_v + font_size\n \n // Determine if we need a background or border\n // Use stamp styling if provided, otherwise use config\n const border_size = stamp_styling?.border_size !== undefined\n ? stamp_styling.border_size\n : freetext_config.freetext_border_width;\n \n // Border color: use config border color (stamp doesn't define border color, only size)\n const border_color_trimmed = freetext_config.freetext_border_color?.trim() || '';\n const has_border = border_size > 0 && border_color_trimmed !== '';\n \n // Background color: use stamp background_color if provided, otherwise config\n const background_color_trimmed = (stamp_styling?.background_color !== undefined\n ? String(stamp_styling.background_color)\n : freetext_config.freetext_background_color)?.trim() || '';\n const has_background = background_color_trimmed !== '';\n \n // Helper to convert hex/rgb to rgba for background\n // Supports both hex (#RRGGBB) and rgb(r, g, b) formats\n const hex_to_rgba_bg = (color_str: string, opacity: number): string => {\n if (!color_str || color_str === '') return 'transparent';\n \n // Trim whitespace from color string\n const trimmed = color_str.trim();\n \n // Handle rgb(r, g, b) format - case insensitive and flexible spacing\n // Matches: rgb(0, 54, 105), rgb(0,54,105), RGB(0, 54, 105), etc.\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = trimmed.match(rgb_pattern);\n if (rgb_match) {\n const r = parseInt(rgb_match[1], 10);\n const g = parseInt(rgb_match[2], 10);\n const b = parseInt(rgb_match[3], 10);\n // Validate RGB values (0-255)\n if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n }\n logger.warn('Invalid RGB values (must be 0-255)', { data: { r, g, b } });\n return 'transparent';\n }\n \n // Handle hex format (#RRGGBB)\n if (trimmed.startsWith('#')) {\n const hex = trimmed.slice(1).trim(); // Remove # and trim\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n }\n logger.warn('Invalid hex color format', { data: { color: trimmed } });\n return 'transparent';\n }\n \n logger.warn('Unrecognized color format', { data: { color: trimmed } });\n return 'transparent';\n };\n\n return (\n <g key={annotation.id}>\n {/* Background rectangle (if configured) */}\n {has_background && (\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill={hex_to_rgba_bg(background_color_trimmed, freetext_config.freetext_background_opacity)}\n pointerEvents=\"none\"\n />\n )}\n \n {/* Border rectangle (if configured) */}\n {has_border && (\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill=\"none\"\n stroke={border_color_trimmed}\n strokeWidth={border_size}\n pointerEvents=\"none\"\n />\n )}\n \n {/* Clickable overlay for FreeText annotations */}\n <rect\n x={box_x}\n y={box_y}\n width={box_width}\n height={box_height}\n fill=\"transparent\"\n stroke=\"none\"\n pointerEvents=\"auto\"\n style={{ cursor: 'pointer' }}\n onMouseEnter={() => {\n setHoveredAnnotationId(annotation.id);\n // Change SVG cursor when hovering over annotation\n if (svg_ref.current) {\n svg_ref.current.style.cursor = 'pointer';\n }\n }}\n onMouseLeave={() => {\n setHoveredAnnotationId(null);\n // Restore SVG cursor when leaving annotation\n if (svg_ref.current) {\n if (current_tool === null) {\n svg_ref.current.style.cursor = 'inherit';\n } else {\n svg_ref.current.style.cursor = current_tool ? 'crosshair' : 'default';\n }\n }\n }}\n onMouseDown={(e) => {\n // This handler is now the primary click detector for annotations\n if (e.button !== 0) return; // Only handle left-click\n // Mark native event for upstream listeners\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'freetext_rect';\n e.stopPropagation(); // Stop event from bubbling to the SVG's onMouseDown\n e.nativeEvent.stopImmediatePropagation();\n\n if (on_annotation_click) {\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n const click_x = e.clientX - rect.left;\n const click_y = e.clientY - rect.top;\n log_annotation_click(annotation, 'freetext_rect', { x: click_x, y: click_y });\n on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);\n }\n }}\n onClick={(e) => {\n // Also handle onClick as backup\n e.preventDefault();\n e.stopPropagation();\n }}\n />\n \n {/* Text content - positioned with padding (always rendered, even if no border/background) */}\n {/* Split text by newlines and render each line separately to support multi-line text (e.g., timestamp) */}\n <text\n x={text_x}\n y={text_y} // Y coordinate is baseline for text in SVG\n fontSize={font_size}\n fill={text_color}\n pointerEvents=\"none\"\n style={{\n fontFamily: font_family,\n fontWeight: font_weight,\n fontStyle: font_style,\n textDecoration: freetext_config.freetext_text_decoration,\n userSelect: 'none',\n }}\n >\n {text.split('\\n').map((line, line_index) => (\n <tspan\n key={line_index}\n x={text_x}\n dy={line_index === 0 ? 0 : font_size} // First line at y position, subsequent lines below\n >\n {line}\n </tspan>\n ))}\n </text>\n </g>\n );\n }\n\n // Get fill properties based on annotation type for rectangle annotations\n const get_annotation_props = () => {\n switch (annotation.type) {\n case 'Highlight': {\n // Check for custom options in subject field (from API highlight_region)\n let custom_highlight_options: {\n border_color?: string;\n background_color?: string;\n background_opacity?: number;\n border_width?: number;\n } | null = null;\n\n if (annotation.subject) {\n try {\n custom_highlight_options = JSON.parse(annotation.subject);\n } catch {\n // Not JSON, ignore\n }\n }\n\n // Use custom colors if provided, then annotation color, then config defaults\n const highlight_fill_color = custom_highlight_options?.background_color ||\n annotation.color ||\n highlight_config.highlight_fill_color;\n const highlight_fill_opacity = custom_highlight_options?.background_opacity ??\n highlight_config.highlight_fill_opacity;\n const highlight_border_color = custom_highlight_options?.border_color ||\n highlight_config.highlight_border_color;\n const highlight_border_width = custom_highlight_options?.border_width ?? 2;\n\n return {\n fill: hex_to_rgba(highlight_fill_color, highlight_fill_opacity),\n stroke: highlight_border_color,\n strokeWidth: highlight_border_width,\n };\n }\n case 'Square': {\n // Use annotation color if provided, otherwise use config\n const square_color = annotation.color || square_config.square_fill_color;\n return {\n fill: hex_to_rgba(square_color, square_config.square_fill_opacity),\n stroke: square_config.square_border_color,\n strokeWidth: 2,\n };\n }\n default:\n return {\n fill: 'rgba(0, 0, 255, 0.2)',\n stroke: '#0000FF',\n strokeWidth: 2,\n };\n }\n };\n\n const { fill, stroke, strokeWidth } = get_annotation_props();\n\n return (\n <g key={annotation.id}>\n {/* Clickable overlay for rectangle annotations */}\n <rect\n x={screen_x}\n y={screen_y}\n width={screen_width}\n height={screen_height}\n fill=\"transparent\"\n stroke=\"none\"\n pointerEvents=\"auto\"\n style={{ cursor: 'pointer' }}\n onMouseEnter={() => {\n setHoveredAnnotationId(annotation.id);\n // Change SVG cursor when hovering over annotation\n if (svg_ref.current) {\n svg_ref.current.style.cursor = 'pointer';\n }\n }}\n onMouseLeave={() => {\n setHoveredAnnotationId(null);\n // Restore SVG cursor when leaving annotation\n if (svg_ref.current) {\n if (current_tool === null) {\n svg_ref.current.style.cursor = 'inherit';\n } else {\n svg_ref.current.style.cursor = current_tool ? 'crosshair' : 'default';\n }\n }\n }}\n onMouseDown={(e) => {\n // This handler is now the primary click detector for annotations\n if (e.button !== 0) return; // Only handle left-click\n // Mark native event for upstream listeners\n (e.nativeEvent as any).__annotation_clicked = annotation.id;\n (e.nativeEvent as any).__annotation_click_source = 'rect_overlay';\n e.stopPropagation(); // Stop event from bubbling to the SVG's onMouseDown\n e.nativeEvent.stopImmediatePropagation();\n\n if (on_annotation_click) {\n const rect = svg_ref.current?.getBoundingClientRect();\n if (!rect) return;\n const click_x = e.clientX - rect.left;\n const click_y = e.clientY - rect.top;\n log_annotation_click(annotation, 'rect_overlay', { x: click_x, y: click_y });\n on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);\n }\n }}\n onClick={(e) => {\n // Also handle onClick as backup\n e.preventDefault();\n e.stopPropagation();\n }}\n />\n {/* Visual annotation rectangle */}\n <rect\n x={screen_x}\n y={screen_y}\n width={screen_width}\n height={screen_height}\n stroke={stroke}\n strokeWidth={strokeWidth}\n fill={fill}\n pointerEvents=\"none\"\n />\n </g>\n );\n };\n\n return (\n <svg\n ref={svg_ref}\n className={cn('cls_annotation_overlay', className)}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: width,\n height: height,\n // Cursor will be dynamically updated by onMouseEnter/Leave on annotations\n // Default: In pan mode, inherit cursor from parent (grab/grabbing)\n // In annotation mode, show crosshair\n cursor: hovered_annotation_id \n ? 'pointer' \n : (current_tool === null ? 'inherit' : (current_tool ? 'crosshair' : 'default')),\n // Always allow pointer events so context menu (right-click) and annotation clicks work\n // Left-click panning is handled by returning early in handle_mouse_down\n pointerEvents: 'auto',\n zIndex: 10, // Ensure annotations are above the canvas but below dialogs\n }}\n width={width}\n height={height}\n onMouseDown={handle_mouse_down}\n onMouseMove={handle_mouse_move}\n onMouseUp={handle_mouse_up}\n onMouseLeave={() => {\n // Reset hover state when mouse leaves SVG entirely\n setHoveredAnnotationId(null);\n handle_mouse_leave();\n }}\n onContextMenu={handle_context_menu}\n >\n {/* Render existing annotations */}\n {page_annotations.map(render_annotation)}\n\n {/* Render temporary drawing box */}\n {is_drawing && (\n <TempDrawBox\n start={start_point}\n current={current_point}\n tool_type={current_tool || 'Square'}\n config={config}\n />\n )}\n </svg>\n );\n};\n\nexport default AnnotationOverlay;\n\n","/**\n * Annotation Utility Functions\n * Helper functions for annotation calculations and transformations\n */\n\n/**\n * Point coordinates\n */\nexport interface Point {\n x: number;\n y: number;\n}\n\n/**\n * Rectangle coordinates (normalized)\n */\nexport interface Rectangle {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Calculates a normalized rectangle bounding box (x, y, width, height)\n * given any two diagonal points\n * @param p1 - First point\n * @param p2 - Second point\n * @returns Normalized rectangle with top-left origin\n */\nexport function calculate_rectangle_coords(\n p1: Point,\n p2: Point\n): Rectangle {\n const x = Math.min(p1.x, p2.x);\n const y = Math.min(p1.y, p2.y);\n const width = Math.abs(p1.x - p2.x);\n const height = Math.abs(p1.y - p2.y);\n \n return { x, y, width, height };\n}\n\n/**\n * Convert rectangle to PDF rect format [x1, y1, x2, y2]\n * @param rect - Rectangle with x, y, width, height\n * @returns PDF rect array [x1, y1, x2, y2]\n */\nexport function rectangle_to_pdf_rect(rect: Rectangle): [number, number, number, number] {\n return [\n rect.x,\n rect.y,\n rect.x + rect.width,\n rect.y + rect.height,\n ];\n}\n\n/**\n * Convert PDF rect format [x1, y1, x2, y2] to rectangle\n * @param pdf_rect - PDF rect array [x1, y1, x2, y2]\n * @returns Rectangle with x, y, width, height\n */\nexport function pdf_rect_to_rectangle(\n pdf_rect: [number, number, number, number]\n): Rectangle {\n const [x1, y1, x2, y2] = pdf_rect;\n return {\n x: Math.min(x1, x2),\n y: Math.min(y1, y2),\n width: Math.abs(x2 - x1),\n height: Math.abs(y2 - y1),\n };\n}\n\n/**\n * Check if a rectangle is too small (likely a click, not a drag)\n * @param rect - Rectangle to check\n * @param min_size - Minimum size in pixels (default: 5)\n * @returns True if rectangle is too small\n */\nexport function is_rectangle_too_small(\n rect: Rectangle,\n min_size: number = 5\n): boolean {\n return rect.width < min_size || rect.height < min_size;\n}\n\n","/**\n * Context Menu Component\n * Displays a context menu on right-click\n */\n\nimport React, { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Undo2, FileText } from 'lucide-react';\nimport type { PdfViewerConfig, CustomStamp } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\n/**\n * Props for ContextMenu component\n */\nexport interface ContextMenuProps {\n /** X position of the menu */\n x: number;\n \n /** Y position of the menu */\n y: number;\n \n /** Whether undo is available */\n can_undo?: boolean;\n \n /** Callback when undo is clicked */\n on_undo?: () => void;\n \n /** Callback when annotate is clicked */\n on_annotate?: () => void;\n \n /** Callback to close the menu */\n on_close?: () => void;\n \n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n \n /** Custom stamps for right-click menu */\n custom_stamps?: CustomStamp[];\n \n /** Callback when a custom stamp is clicked */\n on_stamp_click?: (stamp: CustomStamp) => void;\n}\n\n/**\n * Context Menu Component\n * Displays a menu with undo and annotate options\n */\nexport const ContextMenu: React.FC<ContextMenuProps> = ({\n x,\n y,\n can_undo = false,\n on_undo,\n on_annotate,\n on_close,\n config = null,\n custom_stamps = [],\n on_stamp_click,\n}) => {\n const logger = get_logger();\n const menu_ref = useRef<HTMLDivElement>(null);\n const render_count_ref = useRef(0);\n const [adjusted_position, setAdjustedPosition] = useState({ x, y });\n const props_received_time_ref = useRef(performance.now());\n const [mounted, setMounted] = useState(false);\n\n // Ensure we're mounted (client-side only) before creating portal\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n // Track when props change\n useEffect(() => {\n props_received_time_ref.current = performance.now();\n }, [x, y]);\n\n // Adjust position once we know the menu's dimensions\n useEffect(() => {\n render_count_ref.current += 1;\n \n if (menu_ref.current && mounted) {\n const rect = menu_ref.current.getBoundingClientRect();\n \n // Calculate the actual position (accounting for any transforms or offsets)\n const actual_x = x;\n const actual_y = y;\n \n // Get parent elements for hierarchy debugging\n const menu_element = menu_ref.current;\n \n // Walk up the DOM to find all positioned ancestors\n const positioned_ancestors: Array<{ element: Element; boundingRect: DOMRect; computedStyle: CSSStyleDeclaration }> = [];\n let current: Element | null = menu_element.parentElement;\n while (current && current !== document.body && current !== document.documentElement) {\n const style = window.getComputedStyle(current);\n const position = style.position;\n if (position === 'fixed' || position === 'absolute' || position === 'relative' || position === 'sticky') {\n positioned_ancestors.push({\n element: current,\n boundingRect: current.getBoundingClientRect(),\n computedStyle: style,\n });\n }\n current = current.parentElement;\n }\n\n // Check for transforms in ancestors\n const parent_transforms: Array<{ element: Element; transform: string }> = [];\n let check: Element | null = menu_element.parentElement;\n while (check && check !== document.body) {\n const style = window.getComputedStyle(check);\n const transform = style.transform;\n if (transform && transform !== 'none') {\n parent_transforms.push({\n element: check,\n transform: transform,\n });\n }\n check = check.parentElement;\n }\n \n const x_offset = rect.left - x;\n const y_offset = rect.top - y;\n const position_correct = Math.abs(x_offset) < 1 && Math.abs(y_offset) < 1;\n const parent_transform_count = parent_transforms.length;\n const positioned_ancestor_count = positioned_ancestors.length;\n \n logger.debug('ContextMenu position debug', { data: { render: render_count_ref.current, expected_x: x, expected_y: y, actual_x: Number(rect.left.toFixed(1)), actual_y: Number(rect.top.toFixed(1)), x_offset: Number(x_offset.toFixed(1)), y_offset: Number(y_offset.toFixed(1)), correct: position_correct, ancestors: positioned_ancestor_count, transforms: parent_transform_count } });\n\n // Offset adjustment - currently disabled (set to zero)\n // If bottom-left is at mouse, adjust so top-left is at mouse\n // Check if bottom-left is close to mouse position (within 5px tolerance)\n const bottom_left_x = rect.left;\n const bottom_left_y = rect.bottom;\n const tolerance = 5;\n const offset_x = 0; // Offset disabled for now\n const offset_y = 0; // Offset disabled for now\n \n if (Math.abs(bottom_left_x - x) < tolerance && Math.abs(bottom_left_y - y) < tolerance) {\n logger.debug('ContextMenu detected bottom-left positioning, adjusting to top-left');\n // Menu height is already known, adjust Y upward\n setAdjustedPosition({\n x: actual_x + offset_x,\n y: actual_y + offset_y - rect.height,\n });\n } else {\n // Use original position with offset (currently zero)\n setAdjustedPosition({ \n x: actual_x + offset_x, \n y: actual_y + offset_y \n });\n }\n }\n }, [x, y, mounted]);\n\n const handle_item_click = (callback?: () => void) => {\n if (callback) {\n callback();\n }\n if (on_close) {\n on_close();\n }\n };\n\n logger.debug('ContextMenu render call', { data: { render: render_count_ref.current, props_x: x, props_y: y, adjusted_x: adjusted_position.x, adjusted_y: adjusted_position.y, mounted } });\n\n // Don't render until mounted (to avoid SSR issues)\n if (!mounted) {\n return null;\n }\n\n // Handle mouse leave - close menu when mouse moves away\n const handle_mouse_leave = () => {\n if (on_close) {\n on_close();\n }\n };\n\n // Get config values or use defaults\n const menu_config = config?.context_menu || default_config.context_menu;\n \n // Render menu content\n const menu_content = (\n <div\n ref={menu_ref}\n className=\"cls_pdf_viewer_context_menu\"\n style={{\n position: 'fixed',\n left: `${adjusted_position.x}px`,\n top: `${adjusted_position.y}px`,\n zIndex: 10000,\n backgroundColor: menu_config.context_menu_background_color,\n borderColor: menu_config.context_menu_border_color,\n }}\n onClick={(e) => e.stopPropagation()}\n onContextMenu={(e) => {\n e.preventDefault();\n e.stopPropagation();\n }}\n onMouseLeave={handle_mouse_leave}\n >\n <div className=\"cls_pdf_viewer_context_menu_items\">\n {/* Undo option */}\n <button\n type=\"button\"\n onClick={() => handle_item_click(on_undo)}\n disabled={!can_undo}\n className={cn(\n 'cls_pdf_viewer_context_menu_item',\n !can_undo && 'cls_pdf_viewer_context_menu_item_disabled'\n )}\n style={{\n opacity: !can_undo ? menu_config.context_menu_item_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (can_undo) {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label=\"Undo\"\n >\n <Undo2 className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">Undo</span>\n </button>\n\n {/* Annotate option */}\n <button\n type=\"button\"\n onClick={() => handle_item_click(on_annotate)}\n className=\"cls_pdf_viewer_context_menu_item\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label=\"Annotate\"\n >\n <FileText className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">Annotate</span>\n </button>\n\n {/* Custom stamps - sorted by order, displayed at bottom */}\n {custom_stamps.length > 0 && (\n <>\n {/* Separator line before custom stamps */}\n <div\n style={{\n height: '1px',\n backgroundColor: menu_config.context_menu_border_color,\n margin: '4px 0',\n }}\n />\n {/* Custom stamp items - sorted by order */}\n {[...custom_stamps]\n .sort((a, b) => a.order - b.order)\n .map((stamp, index) => (\n <button\n key={`${stamp.name}-${index}`}\n type=\"button\"\n onClick={() => {\n if (on_stamp_click) {\n on_stamp_click(stamp);\n }\n if (on_close) {\n on_close();\n }\n }}\n className=\"cls_pdf_viewer_context_menu_item\"\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = menu_config.context_menu_item_hover_background;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.backgroundColor = 'transparent';\n }}\n aria-label={stamp.name}\n >\n <FileText className=\"cls_pdf_viewer_context_menu_icon\" size={16} />\n <span className=\"cls_pdf_viewer_context_menu_text\">{stamp.name}</span>\n </button>\n ))}\n </>\n )}\n </div>\n </div>\n );\n\n // CRITICAL: Use portal to render at document.body level to escape any containing blocks\n // This ensures position: fixed works relative to viewport, not Storybook containers\n return createPortal(menu_content, document.body);\n};\n\nexport default ContextMenu;\n\n","/**\n * Text Annotation Dialog Component\n * Dialog for entering text annotation\n */\n\nimport React, { useState, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Check, X, Trash2 } from 'lucide-react';\nimport type { PdfViewerConfig } from '../../types';\nimport { default_config } from '../../config/default_config';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for TextAnnotationDialog component\n */\nexport interface TextAnnotationDialogProps {\n /** Whether the dialog is open */\n open: boolean;\n \n /** X position of the dialog (viewport coordinates) */\n x: number;\n \n /** Y position of the dialog (viewport coordinates) */\n y: number;\n \n /** Callback when dialog is closed */\n on_close: () => void;\n \n /** Callback when text is submitted */\n on_submit: (text: string) => void;\n \n /** Callback when annotation is deleted (only used in edit mode) */\n on_delete?: () => void;\n \n /** Initial text value */\n initial_text?: string;\n \n /** Whether this is editing an existing annotation (shows delete button) */\n is_editing?: boolean;\n \n /** Configuration object for styling */\n config?: PdfViewerConfig | null;\n}\n\n/**\n * Text Annotation Dialog Component\n * Slim inline dialog for entering text annotation\n */\nexport const TextAnnotationDialog: React.FC<TextAnnotationDialogProps> = ({\n open,\n x,\n y,\n on_close,\n on_submit,\n on_delete,\n initial_text = '',\n is_editing = false,\n config = null,\n}) => {\n const [text, setText] = useState(initial_text);\n const input_ref = useRef<HTMLInputElement>(null);\n const [mounted, setMounted] = useState(false);\n\n // Ensure we're mounted (client-side only) before creating portal\n useEffect(() => {\n setMounted(true);\n return () => setMounted(false);\n }, []);\n\n // Reset text when dialog opens/closes\n useEffect(() => {\n if (open) {\n setText(initial_text);\n // Focus input when dialog opens\n setTimeout(() => {\n input_ref.current?.focus();\n input_ref.current?.select();\n }, 0);\n }\n }, [open, initial_text]);\n\n // Handle submit\n const handle_submit = (e?: React.FormEvent) => {\n if (e) {\n e.preventDefault();\n }\n if (text.trim()) {\n on_submit(text.trim());\n setText('');\n on_close();\n }\n };\n\n // Handle cancel\n const handle_cancel = () => {\n setText('');\n on_close();\n };\n\n // Handle delete\n const handle_delete = () => {\n if (on_delete) {\n on_delete();\n setText('');\n on_close();\n }\n };\n\n // Handle keyboard events\n useEffect(() => {\n const handle_keydown = (e: KeyboardEvent) => {\n if (!open) return;\n \n if (e.key === 'Escape') {\n e.preventDefault();\n handle_cancel();\n } else if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handle_submit();\n }\n };\n\n if (open) {\n window.addEventListener('keydown', handle_keydown);\n return () => {\n window.removeEventListener('keydown', handle_keydown);\n };\n }\n return undefined;\n }, [open, text]);\n\n if (!open || !mounted) {\n return null;\n }\n\n // Get config values or use defaults\n const dialog_config = config?.dialog || default_config.dialog;\n\n // Render dialog content\n const dialog_content = (\n <>\n {/* Backdrop */}\n <div\n className=\"cls_pdf_viewer_dialog_backdrop\"\n onClick={handle_cancel}\n aria-hidden=\"true\"\n style={{\n backgroundColor: `rgba(0, 0, 0, ${dialog_config.dialog_backdrop_opacity})`,\n }}\n />\n\n {/* Slim Dialog - positioned at x, y coordinates */}\n <div\n className=\"cls_pdf_viewer_text_dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n style={{\n position: 'fixed',\n left: `${x}px`,\n top: `${y}px`,\n zIndex: 10001, // Higher than context menu\n backgroundColor: dialog_config.dialog_background_color,\n borderColor: dialog_config.dialog_border_color,\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <form onSubmit={handle_submit} className=\"cls_pdf_viewer_dialog_form\">\n <input\n ref={input_ref}\n type=\"text\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n className=\"cls_pdf_viewer_dialog_input\"\n placeholder=\"Enter annotation text...\"\n autoFocus\n />\n <div className=\"cls_pdf_viewer_dialog_buttons\">\n {/* Delete button - only shown when editing */}\n {is_editing && on_delete && (\n <button\n type=\"button\"\n onClick={handle_delete}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_delete'\n )}\n style={{\n color: dialog_config.dialog_button_cancel_color,\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color_hover;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color;\n }}\n aria-label=\"Delete annotation\"\n title=\"Delete annotation\"\n >\n <Trash2 size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={handle_cancel}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_cancel'\n )}\n style={{\n color: dialog_config.dialog_button_cancel_color,\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color_hover;\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_cancel_color;\n }}\n aria-label=\"Cancel\"\n title=\"Cancel (Esc)\"\n >\n <X size={14} />\n </button>\n <button\n type=\"submit\"\n disabled={!text.trim()}\n className={cn(\n 'cls_pdf_viewer_dialog_button',\n 'cls_pdf_viewer_dialog_button_submit',\n !text.trim() && 'cls_pdf_viewer_dialog_button_disabled'\n )}\n style={{\n color: !text.trim() ? undefined : dialog_config.dialog_button_submit_color,\n opacity: !text.trim() ? dialog_config.dialog_button_disabled_opacity : 1,\n }}\n onMouseEnter={(e) => {\n if (text.trim()) {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_submit_color_hover;\n }\n }}\n onMouseLeave={(e) => {\n if (text.trim()) {\n (e.currentTarget as HTMLElement).style.color = dialog_config.dialog_button_submit_color;\n }\n }}\n aria-label=\"Submit\"\n title=\"Submit (Enter)\"\n >\n <Check size={14} />\n </button>\n </div>\n </form>\n </div>\n </>\n );\n\n // Use portal to render at document.body level to escape any containing blocks\n return createPortal(dialog_content, document.body);\n};\n\nexport default TextAnnotationDialog;\n\n","/**\n * Metadata Sidepanel Component\n * Displays JSON metadata with header, data (accordions), and footer sections\n * Supports editable fields with inline editing\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronDown, ChevronUp, Pencil, CheckCircle2, X } from 'lucide-react';\nimport type { MetadataInput, MetadataDataItem } from '../../types';\nimport { cn } from '../../utils/cn';\n\n/**\n * Props for MetadataSidepanel component\n */\nexport interface MetadataSidepanelProps {\n /** Whether the panel is open */\n is_open: boolean;\n /** Callback to toggle panel open/closed */\n on_toggle: () => void;\n /** Metadata input structure */\n metadata: MetadataInput;\n /** Callback when metadata is changed via editing */\n on_change: (updatedRow: MetadataDataItem, allData: MetadataInput) => { updatedRow: MetadataDataItem; allData: MetadataInput };\n /** Current width of the panel */\n width: number;\n /** Callback when panel width changes */\n on_width_change: (width: number) => void;\n}\n\n/**\n * Format text component based on style type\n */\nconst FormatText: React.FC<{ style: string; children: React.ReactNode; className?: string }> = ({ style, children, className }) => {\n const baseClassName = cn('cls_metadata_text', className);\n \n switch (style) {\n case 'h1':\n return <h1 className={cn(baseClassName, 'cls_metadata_h1')}>{children}</h1>;\n case 'h2':\n return <h2 className={cn(baseClassName, 'cls_metadata_h2')}>{children}</h2>;\n case 'h3':\n return <h3 className={cn(baseClassName, 'cls_metadata_h3')}>{children}</h3>;\n case 'h4':\n return <h4 className={cn(baseClassName, 'cls_metadata_h4')}>{children}</h4>;\n case 'h5':\n return <h5 className={cn(baseClassName, 'cls_metadata_h5')}>{children}</h5>;\n case 'body':\n default:\n return <p className={cn(baseClassName, 'cls_metadata_body')}>{children}</p>;\n }\n};\n\n/**\n * Metadata Sidepanel Component\n */\nexport const MetadataSidepanel: React.FC<MetadataSidepanelProps> = ({\n is_open,\n on_toggle,\n metadata,\n on_change,\n width,\n on_width_change,\n}) => {\n const [expanded_items, setExpandedItems] = useState<Set<number>>(new Set());\n const [editing_index, setEditingIndex] = useState<number | null>(null);\n const [edit_value, setEditValue] = useState<string>('');\n const resize_ref = useRef<HTMLDivElement>(null);\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Toggle accordion item expanded/collapsed\n const toggle_item = (index: number) => {\n setExpandedItems(prev => {\n const next = new Set(prev);\n if (next.has(index)) {\n next.delete(index);\n } else {\n next.add(index);\n }\n return next;\n });\n };\n\n // Start editing a field\n const start_edit = (index: number, current_value: string) => {\n setEditingIndex(index);\n setEditValue(current_value);\n };\n\n // Cancel editing\n const cancel_edit = () => {\n setEditingIndex(null);\n setEditValue('');\n };\n\n // Save edited value\n const save_edit = () => {\n if (editing_index === null) return;\n\n const updated_data = [...metadata.data];\n const updated_row = { ...updated_data[editing_index], value: edit_value };\n updated_data[editing_index] = updated_row;\n\n const updated_metadata: MetadataInput = {\n header: metadata.header,\n data: updated_data,\n footer: metadata.footer,\n };\n\n const result = on_change(updated_row, updated_metadata);\n setEditingIndex(null);\n setEditValue('');\n };\n\n // Handle resize start\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 // Handle resize move\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n \n const delta_x = start_x_ref.current - e.clientX; // Reverse because we're resizing from left\n const new_width = Math.max(200, Math.min(800, start_width_ref.current + delta_x));\n on_width_change(new_width);\n };\n\n // Handle resize end\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 resize listeners 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 return (\n <>\n {/* Toggle button on right edge when closed */}\n {!is_open && (\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_metadata_sidepanel_toggle_edge\"\n aria-label=\"Open metadata panel\"\n title=\"Open metadata panel\"\n >\n <ChevronLeft size={20} />\n </button>\n )}\n\n {/* Sidepanel */}\n <div\n className={cn('cls_metadata_sidepanel', is_open && 'cls_metadata_sidepanel_open')}\n style={{ width: is_open ? `${width}px` : '0', display: is_open ? 'flex' : 'none' }}\n >\n {/* Resize handle */}\n {is_open && (\n <div\n ref={resize_ref}\n className=\"cls_metadata_sidepanel_resize_handle\"\n onMouseDown={handle_resize_start}\n aria-label=\"Resize panel\"\n />\n )}\n\n {/* Panel content */}\n <div className=\"cls_metadata_sidepanel_content\">\n {/* Header with close button */}\n <div className=\"cls_metadata_sidepanel_header\">\n <span className=\"cls_metadata_sidepanel_title\">Metadata</span>\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_metadata_sidepanel_close\"\n aria-label=\"Close metadata panel\"\n >\n <ChevronRight size={20} />\n </button>\n </div>\n\n {/* Scrollable content area */}\n <div className=\"cls_metadata_sidepanel_body\">\n {/* Header section */}\n {metadata.header && metadata.header.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_header_section\">\n {metadata.header.map((item, index) => (\n <FormatText key={`header-${index}`} style={item.style}>\n {item.label}\n </FormatText>\n ))}\n </div>\n )}\n\n {/* Data section (accordions) */}\n {metadata.data && metadata.data.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_data_section\">\n {metadata.data.map((item, index) => {\n const is_expanded = expanded_items.has(index);\n const is_editing = editing_index === index;\n\n return (\n <div key={`data-${index}`} className=\"cls_metadata_accordion\">\n {/* Accordion header */}\n <button\n type=\"button\"\n onClick={() => toggle_item(index)}\n className=\"cls_metadata_accordion_header\"\n aria-expanded={is_expanded}\n >\n <FormatText style={item.style} className=\"cls_metadata_accordion_label\">\n {item.label}\n </FormatText>\n {is_expanded ? (\n <ChevronUp className=\"cls_metadata_accordion_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_metadata_accordion_icon\" size={16} />\n )}\n </button>\n\n {/* Accordion content */}\n {is_expanded && (\n <div className=\"cls_metadata_accordion_content\">\n {is_editing ? (\n <div className=\"cls_metadata_edit_mode\">\n <input\n type=\"text\"\n value={edit_value}\n onChange={(e) => setEditValue(e.target.value)}\n className=\"cls_metadata_edit_input\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n save_edit();\n } else if (e.key === 'Escape') {\n cancel_edit();\n }\n }}\n />\n <div className=\"cls_metadata_edit_buttons\">\n <button\n type=\"button\"\n onClick={save_edit}\n className=\"cls_metadata_edit_save\"\n aria-label=\"Save\"\n >\n <CheckCircle2 size={18} className=\"text-green-600\" />\n </button>\n <button\n type=\"button\"\n onClick={cancel_edit}\n className=\"cls_metadata_edit_cancel\"\n aria-label=\"Cancel\"\n >\n <X size={18} className=\"text-red-600\" />\n </button>\n </div>\n </div>\n ) : (\n <div className=\"cls_metadata_value_container\">\n <span className=\"cls_metadata_value\">{item.value}</span>\n {item.editable && (\n <button\n type=\"button\"\n onClick={() => start_edit(index, item.value)}\n className=\"cls_metadata_edit_button\"\n aria-label=\"Edit\"\n >\n <Pencil size={16} />\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Footer section */}\n {metadata.footer && metadata.footer.length > 0 && (\n <div className=\"cls_metadata_section cls_metadata_footer_section\">\n {metadata.footer.map((item, index) => (\n <FormatText key={`footer-${index}`} style={item.style}>\n {item.label}\n </FormatText>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n};\n\n","/**\n * File Info Sidepanel Component\n * Displays combined file information:\n * - Extracted metadata (from LLM extraction)\n * - File system info (from hazo_files package)\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { ChevronLeft, ChevronRight, ChevronDown, ChevronUp } from 'lucide-react';\nimport type { FileMetadataInput, ExtractionEntry } from '../../types';\nimport { cn } from '../../utils/cn';\n\n/**\n * FileSystemItem interface matching hazo_files\n */\ninterface FileSystemItem {\n name: string;\n path: string;\n is_directory: boolean;\n size?: number;\n modified?: Date;\n created?: Date;\n extension?: string;\n mime_type?: string;\n}\n\n/**\n * Highlight field info for display in sidepanel\n */\nexport interface HighlightFieldInfo {\n field_name: string;\n value: string;\n}\n\n/**\n * Props for FileInfoSidepanel component\n */\nexport interface FileInfoSidepanelProps {\n /** Whether the panel is open */\n is_open: boolean;\n /** Callback to toggle panel open/closed */\n on_toggle: () => void;\n /** File item to display info for */\n item: FileSystemItem | null;\n /** Current width of the panel */\n width: number;\n /** Callback when panel width changes */\n on_width_change: (width: number) => void;\n /** Optional file metadata (extraction data) */\n file_metadata?: FileMetadataInput;\n /** Current filename to match against metadata */\n current_filename?: string;\n /** Document data to display (e.g., doc_data from extraction) */\n doc_data?: Record<string, unknown>;\n /** Highlight fields info to display */\n highlight_fields_info?: HighlightFieldInfo[];\n /** Extraction entries from hazo_files file_data */\n extractions?: ExtractionEntry[];\n}\n\n/**\n * Format field name for display (converts snake_case to Title Case)\n */\nconst format_field_name = (name: string): string => {\n return name\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n};\n\n/**\n * Check if a value is a table (array of objects)\n */\nconst is_table = (value: unknown): value is Array<Record<string, string>> => {\n return Array.isArray(value) && value.length > 0 && typeof value[0] === 'object';\n};\n\n/**\n * File Info Sidepanel Component\n * Combines extracted metadata with file system info\n */\nexport const FileInfoSidepanel: React.FC<FileInfoSidepanelProps> = ({\n is_open,\n on_toggle,\n item,\n width,\n on_width_change,\n file_metadata,\n current_filename,\n doc_data,\n highlight_fields_info,\n extractions,\n}) => {\n const [expanded_tables, setExpandedTables] = useState<Set<string>>(new Set());\n const resize_ref = useRef<HTMLDivElement>(null);\n const is_resizing_ref = useRef(false);\n const start_width_ref = useRef(0);\n const start_x_ref = useRef(0);\n\n // Find metadata matching current filename\n const filename = current_filename || item?.name || '';\n const current_metadata = file_metadata?.find(\n (meta) => meta.filename === filename\n );\n\n // Toggle table expanded/collapsed\n const toggle_table = (table_name: string) => {\n setExpandedTables((prev) => {\n const next = new Set(prev);\n if (next.has(table_name)) {\n next.delete(table_name);\n } else {\n next.add(table_name);\n }\n return next;\n });\n };\n\n // Handle resize start\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 // Handle resize move\n const handle_resize_move = (e: MouseEvent) => {\n if (!is_resizing_ref.current) return;\n\n const delta_x = start_x_ref.current - e.clientX;\n const new_width = Math.max(200, Math.min(800, start_width_ref.current + delta_x));\n on_width_change(new_width);\n };\n\n // Handle resize end\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 resize listeners 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 // Separate extracted fields into simple values and tables\n const simple_fields: Array<[string, string]> = [];\n const table_fields: Array<[string, Array<Record<string, string>>]> = [];\n\n if (current_metadata?.file_data) {\n for (const [key, value] of Object.entries(current_metadata.file_data)) {\n if (is_table(value)) {\n table_fields.push([key, value]);\n } else if (typeof value === 'string') {\n simple_fields.push([key, value]);\n }\n }\n }\n\n const has_extracted_data = simple_fields.length > 0 || table_fields.length > 0;\n const has_file_info = item !== null;\n const has_doc_data = doc_data && Object.keys(doc_data).length > 0;\n const has_highlight_info = highlight_fields_info && highlight_fields_info.length > 0;\n const has_extractions = extractions && extractions.length > 0;\n\n return (\n <>\n {/* Toggle button on right edge when closed */}\n {!is_open && (\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_file_info_sidepanel_toggle_edge\"\n aria-label=\"Open file info panel\"\n title=\"Open file info panel\"\n >\n <ChevronLeft size={20} />\n </button>\n )}\n\n {/* Sidepanel */}\n <div\n className={cn('cls_file_info_sidepanel', is_open && 'cls_file_info_sidepanel_open')}\n style={{ width: is_open ? `${width}px` : '0', display: is_open ? 'flex' : 'none' }}\n >\n {/* Resize handle */}\n {is_open && (\n <div\n ref={resize_ref}\n className=\"cls_file_info_sidepanel_resize_handle\"\n onMouseDown={handle_resize_start}\n aria-label=\"Resize panel\"\n />\n )}\n\n {/* Panel content */}\n <div className=\"cls_file_info_sidepanel_content\">\n {/* Header with close button */}\n <div className=\"cls_file_info_sidepanel_header\">\n <span className=\"cls_file_info_sidepanel_title\">File Info</span>\n <button\n type=\"button\"\n onClick={on_toggle}\n className=\"cls_file_info_sidepanel_close\"\n aria-label=\"Close file info panel\"\n >\n <ChevronRight size={20} />\n </button>\n </div>\n\n {/* Scrollable content area */}\n <div className=\"cls_file_info_sidepanel_body\">\n {/* Extracted Metadata Section */}\n {has_extracted_data && (\n <div className=\"cls_file_info_extracted_section\">\n <div className=\"cls_file_info_section_header\">Extracted Data</div>\n\n {/* Simple field values */}\n {simple_fields.length > 0 && (\n <div className=\"cls_file_metadata_fields\">\n {simple_fields.map(([key, value]) => (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">{value}</span>\n </div>\n ))}\n </div>\n )}\n\n {/* Table sections */}\n {table_fields.map(([table_name, rows]) => {\n const is_expanded = expanded_tables.has(table_name);\n\n return (\n <div key={table_name} className=\"cls_file_metadata_table_section\">\n {/* Table header (accordion toggle) */}\n <button\n type=\"button\"\n onClick={() => toggle_table(table_name)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={is_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {format_field_name(table_name)}\n </span>\n <span className=\"cls_file_metadata_table_count\">\n ({rows.length} {rows.length === 1 ? 'item' : 'items'})\n </span>\n {is_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n\n {/* Table content - two column layout per row */}\n {is_expanded && (\n <div className=\"cls_file_metadata_table_content\">\n {rows.map((row, row_index) => (\n <div key={row_index} className=\"cls_file_metadata_table_row\">\n <table className=\"cls_file_metadata_row_table\">\n <tbody>\n {Object.entries(row).map(([field_name, field_value]) => (\n <tr key={field_name} className=\"cls_file_metadata_row_tr\">\n <td className=\"cls_file_metadata_row_label\">\n {format_field_name(field_name)}\n </td>\n <td className=\"cls_file_metadata_row_value\">\n {field_value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Doc Data Section */}\n {has_doc_data && (\n <div className=\"cls_file_info_doc_data_section\">\n <div className=\"cls_file_info_section_header\">Document Data</div>\n <div className=\"cls_file_metadata_fields\">\n {Object.entries(doc_data).map(([key, value]) => (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">\n {typeof value === 'object' ? JSON.stringify(value) : String(value)}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Divider between doc_data and highlight info */}\n {has_doc_data && has_highlight_info && (\n <div className=\"cls_file_info_divider\" />\n )}\n\n {/* Highlight Fields Section */}\n {has_highlight_info && (\n <div className=\"cls_file_info_highlight_section\">\n <div className=\"cls_file_info_section_header\">\n Highlighted Fields ({highlight_fields_info.length})\n </div>\n <div className=\"cls_file_metadata_fields\">\n {highlight_fields_info.map((field, idx) => (\n <div key={idx} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(field.field_name)}\n </span>\n <span className=\"cls_file_metadata_field_value cls_highlight_value\">\n {field.value}\n </span>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Extractions Section */}\n {has_extractions && (\n <div className=\"cls_file_info_extractions_section\">\n {(has_extracted_data || has_doc_data || has_highlight_info) && (\n <div className=\"cls_file_info_divider\" />\n )}\n <div className=\"cls_file_info_section_header\">\n Extractions ({extractions.length})\n </div>\n {extractions.map((entry, idx) => {\n const entry_key = entry.id || `extraction_${idx}`;\n const is_expanded = expanded_tables.has(entry_key);\n const timestamp = entry.extracted_at\n ? new Date(entry.extracted_at).toLocaleString()\n : undefined;\n const data_entries = Object.entries(entry.data);\n\n return (\n <div key={entry_key} className=\"cls_file_metadata_table_section\">\n <button\n type=\"button\"\n onClick={() => toggle_table(entry_key)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={is_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {entry.source || `Extraction ${idx + 1}`}\n </span>\n {timestamp && (\n <span className=\"cls_file_metadata_table_count\">\n {timestamp}\n </span>\n )}\n {is_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n\n {is_expanded && (\n <div className=\"cls_file_metadata_fields\">\n {data_entries.map(([key, value]) => {\n if (is_table(value)) {\n const table_key = `${entry_key}_${key}`;\n const table_expanded = expanded_tables.has(table_key);\n return (\n <div key={key} className=\"cls_file_metadata_table_section\">\n <button\n type=\"button\"\n onClick={() => toggle_table(table_key)}\n className=\"cls_file_metadata_table_header\"\n aria-expanded={table_expanded}\n >\n <span className=\"cls_file_metadata_table_name\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_table_count\">\n ({value.length} {value.length === 1 ? 'item' : 'items'})\n </span>\n {table_expanded ? (\n <ChevronUp className=\"cls_file_metadata_table_icon\" size={16} />\n ) : (\n <ChevronDown className=\"cls_file_metadata_table_icon\" size={16} />\n )}\n </button>\n {table_expanded && (\n <div className=\"cls_file_metadata_table_content\">\n {value.map((row, row_index) => (\n <div key={row_index} className=\"cls_file_metadata_table_row\">\n <table className=\"cls_file_metadata_row_table\">\n <tbody>\n {Object.entries(row).map(([field_name, field_value]) => (\n <tr key={field_name} className=\"cls_file_metadata_row_tr\">\n <td className=\"cls_file_metadata_row_label\">\n {format_field_name(field_name)}\n </td>\n <td className=\"cls_file_metadata_row_value\">\n {field_value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n }\n\n const display_value = typeof value === 'object' && value !== null\n ? JSON.stringify(value, null, 2)\n : String(value ?? '');\n\n return (\n <div key={key} className=\"cls_file_metadata_field\">\n <span className=\"cls_file_metadata_field_label\">\n {format_field_name(key)}\n </span>\n <span className=\"cls_file_metadata_field_value\">\n {display_value}\n </span>\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Divider between sections */}\n {(has_extracted_data || has_doc_data || has_highlight_info || has_extractions) && has_file_info && (\n <div className=\"cls_file_info_divider\" />\n )}\n\n {/* File System Info Section */}\n {has_file_info && item && (\n <div className=\"cls_file_info_system_section\">\n <div className=\"cls_file_info_section_header\">File</div>\n <div className=\"cls_file_info_properties\">\n <div className=\"cls_file_info_property\">\n <span className=\"cls_file_info_property_label\">Name</span>\n <span className=\"cls_file_info_property_value\">{item.name}</span>\n </div>\n <div className=\"cls_file_info_property\">\n <span className=\"cls_file_info_property_label\">Path</span>\n <span className=\"cls_file_info_property_value cls_file_info_path\">{item.path}</span>\n </div>\n </div>\n </div>\n )}\n\n {/* No data message */}\n {!has_extracted_data && !has_doc_data && !has_highlight_info && !has_extractions && !has_file_info && (\n <div className=\"cls_file_info_no_data\">\n No file information available\n </div>\n )}\n </div>\n </div>\n </div>\n </>\n );\n};\n","/**\n * Configuration loader for hazo_pdf\n * Loads configuration from INI file using hazo_config package (Node.js) or fetch (browser)\n * Falls back to defaults if config file is missing or invalid\n */\n\nimport { default_config } from '../config/default_config';\nimport type { PdfViewerConfig } from '../types/config';\nimport { get_logger } from './logger';\n\n/**\n * Simple INI parser for browser environments\n * Parses INI format: [section] followed by key=value pairs\n */\nfunction parse_ini_browser(ini_text: string): Record<string, Record<string, string>> {\n const result: Record<string, Record<string, string>> = {};\n let current_section = '';\n \n const lines = ini_text.split('\\n');\n \n for (const line of lines) {\n const trimmed = line.trim();\n \n // Skip empty lines and comments\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n \n // Check for section header [section_name]\n const section_match = trimmed.match(/^\\[([^\\]]+)\\]$/);\n if (section_match) {\n current_section = section_match[1].trim();\n if (!result[current_section]) {\n result[current_section] = {};\n }\n continue;\n }\n \n // Parse key=value pairs\n const key_value_match = trimmed.match(/^([^=]+)=(.*)$/);\n if (key_value_match && current_section) {\n const key = key_value_match[1].trim();\n const value = key_value_match[2].trim();\n result[current_section][key] = value;\n }\n }\n \n return result;\n}\n\n/**\n * Load config in browser environment by fetching the INI file\n * Note: In browser, we parse INI manually since hazo_config requires Node.js fs module\n * The parsing logic matches hazo_config's parsing behavior\n * For Next.js apps, the config is served via /api/config which uses hazo_config on the server\n */\nasync function load_config_browser(config_file: string): Promise<PdfViewerConfig> {\n const logger = get_logger();\n try {\n // In Next.js, serve config via API route that uses hazo_config\n // This ensures the config file stays in root and hazo_config is used server-side\n // If config_file is a relative path (config/hazo_pdf_config.ini), use /api/config\n // If it's already a full URL or API path, use it directly\n const config_url = (config_file === 'config/hazo_pdf_config.ini' || config_file.includes('config/hazo_pdf_config.ini'))\n ? '/api/config'\n : config_file;\n \n const response = await fetch(config_url);\n if (!response.ok) {\n throw new Error(`Failed to fetch config file: ${response.status} ${response.statusText}`);\n }\n const ini_text = await response.text();\n \n // Parse INI manually (matching hazo_config's parsing behavior)\n // hazo_config requires Node.js fs, so we implement compatible parsing here\n const parsed = parse_ini_browser(ini_text);\n \n // Debug: Log parsed values for troubleshooting\n logger.debug('Parsed config sections', { data: Object.keys(parsed) });\n if (parsed['fonts']) {\n logger.debug('fonts section', { data: parsed['fonts'] });\n }\n if (parsed['freetext_annotation']) {\n logger.debug('freetext_annotation section', { data: parsed['freetext_annotation'] });\n }\n if (parsed['viewer']) {\n logger.debug('viewer section', { data: parsed['viewer'] });\n } else {\n logger.warn('viewer section NOT found in parsed config!');\n }\n \n // Extract values from parsed INI\n const get_value = (section: string, key: string): string | undefined => {\n return parsed[section]?.[key];\n };\n \n // Build config object using same function as hazo_config version\n const config = build_config_from_ini(get_value);\n \n // Debug: Log final config values\n logger.debug('Final config values', {\n font_foreground_color: config.fonts.font_foreground_color,\n freetext_text_color: config.freetext_annotation.freetext_text_color,\n freetext_background_color: config.freetext_annotation.freetext_background_color,\n freetext_background_opacity: config.freetext_annotation.freetext_background_opacity,\n append_timestamp_to_text_edits: config.viewer.append_timestamp_to_text_edits,\n annotation_text_suffix_fixed_text: config.viewer.annotation_text_suffix_fixed_text,\n });\n \n // Debug: Log viewer section parsing\n const raw_value = get_value('viewer', 'append_timestamp_to_text_edits');\n logger.debug('append_timestamp_to_text_edits', {\n raw_value: raw_value,\n raw_type: typeof raw_value,\n parsed_boolean: config.viewer.append_timestamp_to_text_edits,\n parse_boolean_test: parse_boolean(raw_value, false),\n });\n\n // Also log all viewer keys for debugging\n if (parsed['viewer']) {\n logger.debug('All viewer section keys', { data: Object.keys(parsed['viewer']) });\n logger.debug('All viewer section values', { data: parsed['viewer'] });\n }\n \n return config;\n } catch (error) {\n logger.warn(`Could not load config file \"${config_file}\" in browser, using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n\n/**\n * Load config asynchronously (works in both browser and Node.js)\n * Uses hazo_config in Node.js, fetch + manual parsing in browser\n * @param config_file - Path to config file\n * @returns Promise resolving to PdfViewerConfig\n */\nexport async function load_pdf_config_async(config_file: string): Promise<PdfViewerConfig> {\n const logger = get_logger();\n // Detect environment\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser: use fetch + manual parsing (hazo_config requires Node.js)\n return load_config_browser(config_file);\n }\n \n // Node.js: use hazo_config (preferred method)\n try {\n // Dynamically import hazo_config only in Node.js\n const { AppConfig } = require('hazo_config');\n const hazo_config = new AppConfig({ filePath: config_file });\n \n logger.debug(`Using hazo_config to load: ${config_file}`);\n \n // Use hazo_config's get method\n const get_value = (section: string, key: string): string | undefined => {\n return hazo_config.get(section, key);\n };\n \n const config = build_config_from_ini(get_value);\n logger.info(`Successfully loaded config using hazo_config from: ${config_file}`);\n return config;\n } catch (error) {\n logger.warn(`Could not load config file \"${config_file}\" using hazo_config, using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n\n/**\n * Build config object from INI values (shared between browser and Node.js)\n * @param get_value - Function to get a value from INI (section, key) -> value\n * @returns Complete PdfViewerConfig object\n */\nexport function build_config_from_ini(get_value: (section: string, key: string) => string | undefined): PdfViewerConfig {\n const logger = get_logger();\n return {\n fonts: {\n freetext_font_family: parse_string(\n get_value('fonts', 'freetext_font_family'),\n default_config.fonts.freetext_font_family\n ),\n freetext_font_size_min: parse_number(\n get_value('fonts', 'freetext_font_size_min'),\n default_config.fonts.freetext_font_size_min\n ),\n freetext_font_size_max: parse_number(\n get_value('fonts', 'freetext_font_size_max'),\n default_config.fonts.freetext_font_size_max\n ),\n freetext_font_size_default: parse_number(\n get_value('fonts', 'freetext_font_size_default'),\n default_config.fonts.freetext_font_size_default\n ),\n font_foreground_color: parse_color(\n get_value('fonts', 'font_foreground_color'),\n default_config.fonts.font_foreground_color\n ),\n },\n\n highlight_annotation: {\n highlight_fill_color: parse_color(\n get_value('highlight_annotation', 'highlight_fill_color'),\n default_config.highlight_annotation.highlight_fill_color\n ),\n highlight_fill_opacity: parse_opacity(\n get_value('highlight_annotation', 'highlight_fill_opacity'),\n default_config.highlight_annotation.highlight_fill_opacity\n ),\n highlight_border_color: parse_color(\n get_value('highlight_annotation', 'highlight_border_color'),\n default_config.highlight_annotation.highlight_border_color\n ),\n highlight_border_color_hover: parse_color(\n get_value('highlight_annotation', 'highlight_border_color_hover'),\n default_config.highlight_annotation.highlight_border_color_hover\n ),\n highlight_fill_opacity_hover: parse_opacity(\n get_value('highlight_annotation', 'highlight_fill_opacity_hover'),\n default_config.highlight_annotation.highlight_fill_opacity_hover\n ),\n },\n\n square_annotation: {\n square_fill_color: parse_color(\n get_value('square_annotation', 'square_fill_color'),\n default_config.square_annotation.square_fill_color\n ),\n square_fill_opacity: parse_opacity(\n get_value('square_annotation', 'square_fill_opacity'),\n default_config.square_annotation.square_fill_opacity\n ),\n square_border_color: parse_color(\n get_value('square_annotation', 'square_border_color'),\n default_config.square_annotation.square_border_color\n ),\n square_border_color_hover: parse_color(\n get_value('square_annotation', 'square_border_color_hover'),\n default_config.square_annotation.square_border_color_hover\n ),\n square_fill_opacity_hover: parse_opacity(\n get_value('square_annotation', 'square_fill_opacity_hover'),\n default_config.square_annotation.square_fill_opacity_hover\n ),\n },\n\n freetext_annotation: {\n freetext_text_color: parse_color(\n get_value('freetext_annotation', 'freetext_text_color'),\n default_config.freetext_annotation.freetext_text_color\n ),\n freetext_text_color_hover: parse_color(\n get_value('freetext_annotation', 'freetext_text_color_hover'),\n default_config.freetext_annotation.freetext_text_color_hover\n ),\n freetext_border_color: parse_string(\n get_value('freetext_annotation', 'freetext_border_color'),\n default_config.freetext_annotation.freetext_border_color\n ),\n freetext_border_width: parse_number(\n get_value('freetext_annotation', 'freetext_border_width'),\n default_config.freetext_annotation.freetext_border_width\n ),\n freetext_background_color: (() => {\n const raw_value = get_value('freetext_annotation', 'freetext_background_color');\n const parsed = parse_string(raw_value, default_config.freetext_annotation.freetext_background_color);\n logger.debug(`freetext_background_color: raw=\"${raw_value}\", parsed=\"${parsed}\"`);\n return parsed;\n })(),\n freetext_background_opacity: parse_opacity(\n get_value('freetext_annotation', 'freetext_background_opacity'),\n default_config.freetext_annotation.freetext_background_opacity\n ),\n freetext_font_weight: parse_string(\n get_value('freetext_annotation', 'freetext_font_weight'),\n default_config.freetext_annotation.freetext_font_weight\n ),\n freetext_font_style: parse_string(\n get_value('freetext_annotation', 'freetext_font_style'),\n default_config.freetext_annotation.freetext_font_style\n ),\n freetext_text_decoration: parse_string(\n get_value('freetext_annotation', 'freetext_text_decoration'),\n default_config.freetext_annotation.freetext_text_decoration\n ),\n freetext_padding_horizontal: parse_number(\n get_value('freetext_annotation', 'freetext_padding_horizontal'),\n default_config.freetext_annotation.freetext_padding_horizontal\n ),\n freetext_padding_vertical: parse_number(\n get_value('freetext_annotation', 'freetext_padding_vertical'),\n default_config.freetext_annotation.freetext_padding_vertical\n ),\n },\n\n page_styling: {\n page_border_color: parse_color(\n get_value('page_styling', 'page_border_color'),\n default_config.page_styling.page_border_color\n ),\n page_box_shadow: parse_string(\n get_value('page_styling', 'page_box_shadow'),\n default_config.page_styling.page_box_shadow\n ),\n page_background_color: parse_color(\n get_value('page_styling', 'page_background_color'),\n default_config.page_styling.page_background_color\n ),\n },\n\n viewer: {\n viewer_background_color: parse_color(\n get_value('viewer', 'viewer_background_color'),\n default_config.viewer.viewer_background_color\n ),\n append_timestamp_to_text_edits: parse_boolean(\n get_value('viewer', 'append_timestamp_to_text_edits'),\n default_config.viewer.append_timestamp_to_text_edits\n ),\n annotation_text_suffix_fixed_text: parse_string(\n get_value('viewer', 'annotation_text_suffix_fixed_text'),\n default_config.viewer.annotation_text_suffix_fixed_text\n ),\n add_enclosing_brackets_to_suffixes: parse_boolean(\n get_value('viewer', 'add_enclosing_brackets_to_suffixes'),\n default_config.viewer.add_enclosing_brackets_to_suffixes\n ),\n suffix_enclosing_brackets: (() => {\n const raw_value = parse_string(\n get_value('viewer', 'suffix_enclosing_brackets'),\n default_config.viewer.suffix_enclosing_brackets\n );\n if (raw_value.length === 2) {\n return raw_value;\n }\n logger.warn(`suffix_enclosing_brackets must be 2 characters, received \"${raw_value}\". Using default.`);\n return default_config.viewer.suffix_enclosing_brackets;\n })(),\n suffix_text_position: (() => {\n const raw_value = parse_string(\n get_value('viewer', 'suffix_text_position'),\n default_config.viewer.suffix_text_position\n ) as 'adjacent' | 'below_single_line' | 'below_multi_line';\n const valid_values: Array<'adjacent' | 'below_single_line' | 'below_multi_line'> = [\n 'adjacent',\n 'below_single_line',\n 'below_multi_line',\n ];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n logger.warn(`Invalid suffix_text_position \"${raw_value}\". Using default \"${default_config.viewer.suffix_text_position}\".`);\n return default_config.viewer.suffix_text_position;\n })(),\n },\n\n context_menu: {\n context_menu_background_color: parse_color(\n get_value('context_menu', 'context_menu_background_color'),\n default_config.context_menu.context_menu_background_color\n ),\n context_menu_border_color: parse_color(\n get_value('context_menu', 'context_menu_border_color'),\n default_config.context_menu.context_menu_border_color\n ),\n context_menu_item_hover_background: parse_color(\n get_value('context_menu', 'context_menu_item_hover_background'),\n default_config.context_menu.context_menu_item_hover_background\n ),\n context_menu_item_disabled_opacity: parse_opacity(\n get_value('context_menu', 'context_menu_item_disabled_opacity'),\n default_config.context_menu.context_menu_item_disabled_opacity\n ),\n right_click_custom_stamps: parse_string(\n get_value('context_menu', 'right_click_custom_stamps'),\n default_config.context_menu.right_click_custom_stamps\n ),\n },\n\n dialog: {\n dialog_backdrop_opacity: parse_opacity(\n get_value('dialog', 'dialog_backdrop_opacity'),\n default_config.dialog.dialog_backdrop_opacity\n ),\n dialog_background_color: parse_color(\n get_value('dialog', 'dialog_background_color'),\n default_config.dialog.dialog_background_color\n ),\n dialog_border_color: parse_color(\n get_value('dialog', 'dialog_border_color'),\n default_config.dialog.dialog_border_color\n ),\n dialog_button_submit_color: parse_color(\n get_value('dialog', 'dialog_button_submit_color'),\n default_config.dialog.dialog_button_submit_color\n ),\n dialog_button_submit_color_hover: parse_color(\n get_value('dialog', 'dialog_button_submit_color_hover'),\n default_config.dialog.dialog_button_submit_color_hover\n ),\n dialog_button_cancel_color: parse_color(\n get_value('dialog', 'dialog_button_cancel_color'),\n default_config.dialog.dialog_button_cancel_color\n ),\n dialog_button_cancel_color_hover: parse_color(\n get_value('dialog', 'dialog_button_cancel_color_hover'),\n default_config.dialog.dialog_button_cancel_color_hover\n ),\n dialog_button_disabled_opacity: parse_opacity(\n get_value('dialog', 'dialog_button_disabled_opacity'),\n default_config.dialog.dialog_button_disabled_opacity\n ),\n },\n\n toolbar: {\n toolbar_background_color: parse_color(\n get_value('toolbar', 'toolbar_background_color'),\n default_config.toolbar.toolbar_background_color\n ),\n toolbar_border_color: parse_color(\n get_value('toolbar', 'toolbar_border_color'),\n default_config.toolbar.toolbar_border_color\n ),\n toolbar_font_family: parse_string(\n get_value('toolbar', 'toolbar_font_family'),\n default_config.toolbar.toolbar_font_family\n ),\n toolbar_font_size: parse_number(\n get_value('toolbar', 'toolbar_font_size'),\n default_config.toolbar.toolbar_font_size\n ),\n toolbar_font_color: parse_color(\n get_value('toolbar', 'toolbar_font_color'),\n default_config.toolbar.toolbar_font_color\n ),\n toolbar_button_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_background_color'),\n default_config.toolbar.toolbar_button_background_color\n ),\n toolbar_button_background_color_hover: parse_color(\n get_value('toolbar', 'toolbar_button_background_color_hover'),\n default_config.toolbar.toolbar_button_background_color_hover\n ),\n toolbar_button_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_text_color'),\n default_config.toolbar.toolbar_button_text_color\n ),\n toolbar_button_active_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_active_background_color'),\n default_config.toolbar.toolbar_button_active_background_color\n ),\n toolbar_button_active_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_active_text_color'),\n default_config.toolbar.toolbar_button_active_text_color\n ),\n toolbar_button_save_background_color: parse_color(\n get_value('toolbar', 'toolbar_button_save_background_color'),\n default_config.toolbar.toolbar_button_save_background_color\n ),\n toolbar_button_save_background_color_hover: parse_color(\n get_value('toolbar', 'toolbar_button_save_background_color_hover'),\n default_config.toolbar.toolbar_button_save_background_color_hover\n ),\n toolbar_button_save_text_color: parse_color(\n get_value('toolbar', 'toolbar_button_save_text_color'),\n default_config.toolbar.toolbar_button_save_text_color\n ),\n toolbar_button_disabled_opacity: parse_opacity(\n get_value('toolbar', 'toolbar_button_disabled_opacity'),\n default_config.toolbar.toolbar_button_disabled_opacity\n ),\n toolbar_show_zoom_controls: parse_boolean(\n get_value('toolbar', 'toolbar_show_zoom_controls'),\n default_config.toolbar.toolbar_show_zoom_controls\n ),\n toolbar_show_rotation_controls: parse_boolean(\n get_value('toolbar', 'toolbar_show_rotation_controls'),\n default_config.toolbar.toolbar_show_rotation_controls\n ),\n toolbar_show_square_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_square_button'),\n default_config.toolbar.toolbar_show_square_button\n ),\n toolbar_show_undo_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_undo_button'),\n default_config.toolbar.toolbar_show_undo_button\n ),\n toolbar_show_redo_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_redo_button'),\n default_config.toolbar.toolbar_show_redo_button\n ),\n toolbar_show_save_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_save_button'),\n default_config.toolbar.toolbar_show_save_button\n ),\n toolbar_show_metadata_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_metadata_button'),\n default_config.toolbar.toolbar_show_metadata_button\n ),\n toolbar_show_annotate_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_annotate_button'),\n default_config.toolbar.toolbar_show_annotate_button\n ),\n toolbar_show_file_info_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_file_info_button'),\n default_config.toolbar.toolbar_show_file_info_button\n ),\n toolbar_show_extract_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_extract_button'),\n default_config.toolbar.toolbar_show_extract_button\n ),\n toolbar_show_download_button: parse_boolean(\n get_value('toolbar', 'toolbar_show_download_button'),\n default_config.toolbar.toolbar_show_download_button\n ),\n toolbar_zoom_out_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_out_label'),\n default_config.toolbar.toolbar_zoom_out_label\n ),\n toolbar_zoom_in_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_in_label'),\n default_config.toolbar.toolbar_zoom_in_label\n ),\n toolbar_zoom_reset_label: parse_string(\n get_value('toolbar', 'toolbar_zoom_reset_label'),\n default_config.toolbar.toolbar_zoom_reset_label\n ),\n toolbar_square_label: parse_string(\n get_value('toolbar', 'toolbar_square_label'),\n default_config.toolbar.toolbar_square_label\n ),\n toolbar_undo_label: parse_string(\n get_value('toolbar', 'toolbar_undo_label'),\n default_config.toolbar.toolbar_undo_label\n ),\n toolbar_redo_label: parse_string(\n get_value('toolbar', 'toolbar_redo_label'),\n default_config.toolbar.toolbar_redo_label\n ),\n toolbar_save_label: parse_string(\n get_value('toolbar', 'toolbar_save_label'),\n default_config.toolbar.toolbar_save_label\n ),\n toolbar_saving_label: parse_string(\n get_value('toolbar', 'toolbar_saving_label'),\n default_config.toolbar.toolbar_saving_label\n ),\n toolbar_metadata_label: parse_string(\n get_value('toolbar', 'toolbar_metadata_label'),\n default_config.toolbar.toolbar_metadata_label\n ),\n },\n\n file_manager: {\n file_manager_enabled: parse_boolean(\n get_value('file_manager', 'file_manager_enabled'),\n default_config.file_manager.file_manager_enabled\n ),\n show_file_list: parse_boolean(\n get_value('file_manager', 'show_file_list'),\n default_config.file_manager.show_file_list\n ),\n allow_delete: parse_boolean(\n get_value('file_manager', 'allow_delete'),\n default_config.file_manager.allow_delete\n ),\n show_popout_button: parse_boolean(\n get_value('file_manager', 'show_popout_button'),\n default_config.file_manager.show_popout_button\n ),\n file_list_height: parse_number(\n get_value('file_manager', 'file_list_height'),\n default_config.file_manager.file_list_height\n ),\n selected_color: parse_color(\n get_value('file_manager', 'selected_color'),\n default_config.file_manager.selected_color\n ),\n file_list_background_color: parse_color(\n get_value('file_manager', 'file_list_background_color'),\n default_config.file_manager.file_list_background_color\n ),\n file_list_border_color: parse_color(\n get_value('file_manager', 'file_list_border_color'),\n default_config.file_manager.file_list_border_color\n ),\n },\n\n file_upload: {\n upload_enabled: parse_boolean(\n get_value('file_upload', 'upload_enabled'),\n default_config.file_upload.upload_enabled\n ),\n allowed_types: parse_string(\n get_value('file_upload', 'allowed_types'),\n default_config.file_upload.allowed_types\n ),\n max_file_size: parse_number(\n get_value('file_upload', 'max_file_size'),\n default_config.file_upload.max_file_size\n ),\n max_files: parse_number(\n get_value('file_upload', 'max_files'),\n default_config.file_upload.max_files\n ),\n show_add_button: parse_boolean(\n get_value('file_upload', 'show_add_button'),\n default_config.file_upload.show_add_button\n ),\n dropzone_border_color: parse_color(\n get_value('file_upload', 'dropzone_border_color'),\n default_config.file_upload.dropzone_border_color\n ),\n dropzone_border_color_active: parse_color(\n get_value('file_upload', 'dropzone_border_color_active'),\n default_config.file_upload.dropzone_border_color_active\n ),\n dropzone_background_color: parse_color(\n get_value('file_upload', 'dropzone_background_color'),\n default_config.file_upload.dropzone_background_color\n ),\n direct_upload: parse_boolean(\n get_value('file_upload', 'direct_upload'),\n default_config.file_upload.direct_upload\n ),\n },\n\n pdf_conversion: {\n conversion_enabled: parse_boolean(\n get_value('pdf_conversion', 'conversion_enabled'),\n default_config.pdf_conversion.conversion_enabled\n ),\n page_size: (() => {\n const raw_value = parse_string(\n get_value('pdf_conversion', 'page_size'),\n default_config.pdf_conversion.page_size\n ) as 'letter' | 'a4' | 'legal';\n const valid_values: Array<'letter' | 'a4' | 'legal'> = ['letter', 'a4', 'legal'];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n return default_config.pdf_conversion.page_size;\n })(),\n image_quality: parse_opacity(\n get_value('pdf_conversion', 'image_quality'),\n default_config.pdf_conversion.image_quality\n ),\n image_fit: (() => {\n const raw_value = parse_string(\n get_value('pdf_conversion', 'image_fit'),\n default_config.pdf_conversion.image_fit\n ) as 'fit' | 'fill' | 'stretch';\n const valid_values: Array<'fit' | 'fill' | 'stretch'> = ['fit', 'fill', 'stretch'];\n if (valid_values.includes(raw_value)) {\n return raw_value;\n }\n return default_config.pdf_conversion.image_fit;\n })(),\n margin: parse_number(\n get_value('pdf_conversion', 'margin'),\n default_config.pdf_conversion.margin\n ),\n },\n\n auto_highlight: {\n auto_highlight_border_color: parse_color(\n get_value('auto_highlight', 'auto_highlight_border_color'),\n default_config.auto_highlight.auto_highlight_border_color\n ),\n auto_highlight_background_color: parse_color(\n get_value('auto_highlight', 'auto_highlight_background_color'),\n default_config.auto_highlight.auto_highlight_background_color\n ),\n auto_highlight_background_opacity: parse_opacity(\n get_value('auto_highlight', 'auto_highlight_background_opacity'),\n default_config.auto_highlight.auto_highlight_background_opacity\n ),\n auto_highlight_border_width: parse_number(\n get_value('auto_highlight', 'auto_highlight_border_width'),\n default_config.auto_highlight.auto_highlight_border_width\n ),\n auto_highlight_normalize_text: parse_boolean(\n get_value('auto_highlight', 'auto_highlight_normalize_text'),\n default_config.auto_highlight.auto_highlight_normalize_text\n ),\n auto_highlight_padding_x: parse_number(\n get_value('auto_highlight', 'auto_highlight_padding_x'),\n default_config.auto_highlight.auto_highlight_padding_x\n ),\n auto_highlight_padding_y: parse_number(\n get_value('auto_highlight', 'auto_highlight_padding_y'),\n default_config.auto_highlight.auto_highlight_padding_y\n ),\n auto_highlight_y_offset: parse_number(\n get_value('auto_highlight', 'auto_highlight_y_offset'),\n default_config.auto_highlight.auto_highlight_y_offset\n ),\n },\n\n file_button: {\n icon_size: parse_number(\n get_value('file_button', 'icon_size'),\n default_config.file_button.icon_size\n ),\n icon_color: parse_color(\n get_value('file_button', 'icon_color'),\n default_config.file_button.icon_color\n ),\n icon_color_hover: parse_color(\n get_value('file_button', 'icon_color_hover'),\n default_config.file_button.icon_color_hover\n ),\n icon_color_with_files: parse_color(\n get_value('file_button', 'icon_color_with_files'),\n default_config.file_button.icon_color_with_files\n ),\n badge_background: parse_color(\n get_value('file_button', 'badge_background'),\n default_config.file_button.badge_background\n ),\n badge_text_color: parse_color(\n get_value('file_button', 'badge_text_color'),\n default_config.file_button.badge_text_color\n ),\n },\n };\n}\n\n/**\n * Parse a color value from config (hex format)\n * @param value - Color value from config\n * @param default_value - Default color if parsing fails\n * @returns Parsed color value\n */\nexport function parse_color(value: string | undefined, default_value: string): string {\n if (!value) return default_value;\n // Validate hex color format\n if (/^#[0-9A-Fa-f]{6}$/.test(value)) {\n return value;\n }\n // Try to parse rgba format\n if (value.startsWith('rgba') || value.startsWith('rgb')) {\n return value;\n }\n get_logger().warn(`Invalid color format: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse an opacity value from config (0.0 to 1.0)\n * @param value - Opacity value from config\n * @param default_value - Default opacity if parsing fails\n * @returns Parsed opacity value\n */\nexport function parse_opacity(value: string | undefined, default_value: number): number {\n if (!value) return default_value;\n const parsed = parseFloat(value);\n if (!isNaN(parsed) && parsed >= 0 && parsed <= 1) {\n return parsed;\n }\n get_logger().warn(`Invalid opacity value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse a number value from config\n * @param value - Number value from config\n * @param default_value - Default number if parsing fails\n * @returns Parsed number value\n */\nexport function parse_number(value: string | undefined, default_value: number): number {\n if (!value) return default_value;\n const parsed = parseFloat(value);\n if (!isNaN(parsed)) {\n return parsed;\n }\n get_logger().warn(`Invalid number value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Parse a string value from config\n * @param value - String value from config\n * @param default_value - Default string if value is missing\n * @returns Parsed string value\n */\nexport function parse_string(value: string | undefined, default_value: string): string {\n return value || default_value;\n}\n\n/**\n * Parse a boolean value from config\n * @param value - Boolean value from config (true/false, yes/no, 1/0)\n * @param default_value - Default boolean if parsing fails\n * @returns Parsed boolean value\n */\nexport function parse_boolean(value: string | undefined, default_value: boolean): boolean {\n if (!value) return default_value;\n const lower = value.toLowerCase().trim();\n if (lower === 'true' || lower === 'yes' || lower === '1') {\n return true;\n }\n if (lower === 'false' || lower === 'no' || lower === '0') {\n return false;\n }\n get_logger().warn(`Invalid boolean value: ${value}, using default: ${default_value}`);\n return default_value;\n}\n\n/**\n * Load PDF viewer configuration from INI file\n * Supports both Node.js (using hazo_config) and browser (using fetch) environments\n * @param config_file - Optional path to config file. If not provided, returns defaults\n * @returns Configuration object with loaded values merged with defaults\n */\nexport function load_pdf_config(config_file?: string): PdfViewerConfig {\n const logger = get_logger();\n // If no config file specified, return defaults\n if (!config_file) {\n logger.debug('No config file specified, using defaults');\n return default_config;\n }\n\n // Detect environment: browser vs Node.js\n const is_browser = typeof window !== 'undefined' && typeof fetch !== 'undefined';\n \n if (is_browser) {\n // Browser environment: use fetch to load INI file\n // Note: This is async, but we need sync behavior for React component initialization\n // We'll load it synchronously by throwing an error if fetch fails, and the component\n // will need to handle async loading or we use a different approach\n logger.warn('Browser environment detected. Config loading should be async, but load_pdf_config is sync. Using defaults. Consider making this async or using a different approach.');\n return default_config;\n }\n\n // Node.js environment: use hazo_config\n try {\n // Dynamically import hazo_config only in Node.js\n const { AppConfig } = require('hazo_config');\n const hazo_config = new AppConfig({ filePath: config_file });\n\n // Use the shared build function\n const get_value = (section: string, key: string): string | undefined => {\n return hazo_config.get(section, key);\n };\n \n const config = build_config_from_ini(get_value);\n logger.info(`Successfully loaded config from: ${config_file}`);\n return config;\n } catch (error) {\n // If config file doesn't exist or has errors, use defaults\n logger.warn(`Could not load config file \"${config_file}\", using defaults`, { error: error instanceof Error ? error.message : String(error) });\n return default_config;\n }\n}\n","/**\n * File Manager Component\n * Main orchestrator for multi-file management in hazo_pdf\n */\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport type { FileItem, UploadProgress, UploadResult } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { FileList } from './file_list';\nimport { UploadDropzone } from './upload_dropzone';\nimport { FileManagerButton } from './file_manager_button';\nimport { convert_to_pdf, can_convert_to_pdf } from '../../utils/pdf_converter';\nimport { cn } from '../../utils/cn';\nimport { get_logger } from '../../utils/logger';\n\nexport interface FileManagerProps {\n /** Initial files to display */\n files?: FileItem[];\n /** Currently selected file ID */\n selected_file_id?: string | null;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when a file is selected */\n on_file_select?: (file: FileItem) => void;\n /** Callback when a file is deleted */\n on_file_delete?: (file_id: string) => void;\n /** Callback for file upload (caller handles actual storage) */\n on_upload?: (file: File, converted_pdf?: Uint8Array) => Promise<UploadResult>;\n /** Callback when files array changes */\n on_files_change?: (files: FileItem[]) => void;\n /** Whether to show only the compact button trigger */\n show_button_only?: boolean;\n /** Callback to open file manager dialog (for button mode) */\n on_open_dialog?: () => void;\n /** Additional CSS class name */\n className?: string;\n}\n\n/**\n * Generate a unique ID for a file\n */\nfunction generate_file_id(): string {\n return `file_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * Determine file type from MIME type\n */\nfunction get_file_type(mime_type: string): FileItem['type'] {\n if (mime_type === 'application/pdf') return 'pdf';\n if (mime_type.startsWith('image/')) return 'image';\n if (mime_type.startsWith('text/')) return 'text';\n return 'other';\n}\n\nexport const FileManager: React.FC<FileManagerProps> = ({\n files: external_files,\n selected_file_id: external_selected_id,\n config,\n on_file_select,\n on_file_delete,\n on_upload,\n on_files_change,\n show_button_only = false,\n on_open_dialog,\n className,\n}) => {\n // Internal state for files if not controlled externally\n const [internal_files, setInternalFiles] = useState<FileItem[]>(external_files || []);\n const [internal_selected_id, setInternalSelectedId] = useState<string | null>(\n external_selected_id || external_files?.[0]?.id || null\n );\n const [uploads, setUploads] = useState<UploadProgress[]>([]);\n const [show_dropzone, setShowDropzone] = useState(false);\n\n // Use external files if provided, otherwise use internal\n const files = external_files ?? internal_files;\n const selected_file_id = external_selected_id ?? internal_selected_id;\n\n // Sync internal state with external files when they change\n useEffect(() => {\n if (external_files !== undefined) {\n setInternalFiles(external_files);\n }\n }, [external_files]);\n\n useEffect(() => {\n if (external_selected_id !== undefined) {\n setInternalSelectedId(external_selected_id);\n }\n }, [external_selected_id]);\n\n /**\n * Handle file selection\n */\n const handle_file_select = useCallback((file: FileItem) => {\n setInternalSelectedId(file.id);\n on_file_select?.(file);\n }, [on_file_select]);\n\n /**\n * Handle file deletion\n */\n const handle_file_delete = useCallback((file_id: string) => {\n const new_files = files.filter(f => f.id !== file_id);\n setInternalFiles(new_files);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(new_files), 0);\n on_file_delete?.(file_id);\n\n // Select next file if deleted file was selected\n if (selected_file_id === file_id && new_files.length > 0) {\n handle_file_select(new_files[0]);\n } else if (new_files.length === 0) {\n setInternalSelectedId(null);\n }\n }, [files, selected_file_id, on_files_change, on_file_delete, handle_file_select]);\n\n /**\n * Handle files selected for upload\n */\n const handle_files_selected = useCallback(async (selected_files: File[]) => {\n const conversion_config = config?.pdf_conversion;\n\n for (const file of selected_files) {\n const file_id = generate_file_id();\n const needs_conversion = file.type !== 'application/pdf' &&\n conversion_config?.conversion_enabled !== false &&\n can_convert_to_pdf(file.type);\n\n // Add placeholder file immediately to show in the list\n const placeholder_file: FileItem = {\n id: file_id,\n name: needs_conversion ? file.name.replace(/\\.[^.]+$/, '.pdf') : file.name,\n url: '', // Empty URL until ready\n type: 'pdf',\n mime_type: 'application/pdf',\n status: needs_conversion ? 'converting' : 'uploading',\n original_file: file,\n };\n\n // Add placeholder to file list immediately\n setInternalFiles(prev => {\n const updated = [...prev, placeholder_file];\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n // Add to upload progress\n setUploads(prev => [...prev, {\n file_id,\n filename: file.name,\n progress: 0,\n status: needs_conversion ? 'converting' : 'uploading',\n }]);\n\n try {\n let converted_pdf: Uint8Array | undefined;\n let final_mime_type = file.type;\n let final_name = file.name;\n let is_converted = false;\n\n // Check if conversion is needed\n if (needs_conversion) {\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'converting', progress: 30 } : u\n ));\n\n const result = await convert_to_pdf(file, file.name, {\n page_size: conversion_config?.page_size || 'letter',\n image_quality: conversion_config?.image_quality || 0.85,\n image_fit: conversion_config?.image_fit || 'fit',\n margin: conversion_config?.margin || 36,\n });\n\n if (result.success && result.pdf_bytes) {\n converted_pdf = result.pdf_bytes;\n final_mime_type = 'application/pdf';\n final_name = result.pdf_filename || file.name.replace(/\\.[^.]+$/, '.pdf');\n is_converted = true;\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, progress: 60 } : u\n ));\n } else {\n throw new Error(result.error || 'Conversion failed');\n }\n }\n\n // If caller provides on_upload, use it\n if (on_upload) {\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'uploading', progress: 80 } : u\n ));\n\n // Update placeholder to uploading status\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? { ...f, status: 'uploading' as const } : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n const upload_result = await on_upload(file, converted_pdf);\n\n if (upload_result.success && upload_result.file) {\n const new_file: FileItem = {\n ...upload_result.file,\n id: file_id, // Keep original ID\n is_converted,\n original_file: is_converted ? file : undefined,\n status: 'ready',\n };\n\n // Update placeholder with real file data\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? new_file : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'complete', progress: 100 } : u\n ));\n\n // Auto-select the newly uploaded file\n handle_file_select(new_file);\n } else {\n throw new Error(upload_result.error || 'Upload failed');\n }\n } else {\n // Create data URL for local display\n // Create new Uint8Array to ensure proper ArrayBuffer type for Blob constructor\n const blob = converted_pdf\n ? new Blob([new Uint8Array(converted_pdf)], { type: 'application/pdf' })\n : file;\n const url = URL.createObjectURL(blob);\n\n const new_file: FileItem = {\n id: file_id,\n name: final_name,\n url: url,\n type: get_file_type(final_mime_type),\n mime_type: final_mime_type,\n size: blob.size,\n is_converted,\n original_file: is_converted ? file : undefined,\n status: 'ready',\n };\n\n // Update placeholder with real file data\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? new_file : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? { ...u, status: 'complete', progress: 100 } : u\n ));\n\n // Auto-select the newly uploaded file\n handle_file_select(new_file);\n }\n } catch (error) {\n const logger = get_logger();\n logger.error('Upload/conversion error', { data: error });\n\n // Update placeholder to error status\n setInternalFiles(prev => {\n const updated = prev.map(f => f.id === file_id ? { ...f, status: 'error' as const } : f);\n // Defer callback to avoid setState during render\n setTimeout(() => on_files_change?.(updated), 0);\n return updated;\n });\n\n setUploads(prev => prev.map(u =>\n u.file_id === file_id ? {\n ...u,\n status: 'error',\n progress: 0,\n error_message: error instanceof Error ? error.message : 'Upload failed',\n } : u\n ));\n }\n }\n\n // Clear completed uploads after delay\n setTimeout(() => {\n setUploads(prev => prev.filter(u => u.status !== 'complete'));\n }, 3000);\n\n // Close dropzone after files are selected\n setShowDropzone(false);\n }, [config, on_upload, on_files_change, handle_file_select]);\n\n const file_manager_config = config?.file_manager;\n const upload_config = config?.file_upload;\n const is_direct_upload = upload_config?.direct_upload ?? false;\n\n // If button-only mode, render just the button\n if (show_button_only) {\n return (\n <FileManagerButton\n file_count={files.length}\n config={config}\n on_click={() => on_open_dialog?.()}\n className={className}\n />\n );\n }\n\n return (\n <div className={cn('cls_file_manager', className)}>\n {/* File list */}\n {file_manager_config?.show_file_list !== false && (\n <FileList\n files={files}\n selected_file_id={selected_file_id}\n config={config}\n on_select={handle_file_select}\n on_delete={file_manager_config?.allow_delete !== false ? handle_file_delete : undefined}\n on_add_click={upload_config?.upload_enabled !== false && !is_direct_upload ? () => setShowDropzone(true) : undefined}\n on_files_selected={upload_config?.upload_enabled !== false && is_direct_upload ? handle_files_selected : undefined}\n />\n )}\n\n {/* Dropzone overlay (only for non-direct mode) */}\n {show_dropzone && !is_direct_upload && (\n <div className=\"cls_file_manager_dropzone_overlay\">\n <div className=\"cls_file_manager_dropzone_dialog\">\n <UploadDropzone\n config={config}\n uploads={uploads}\n on_files_selected={handle_files_selected}\n on_close={() => setShowDropzone(false)}\n />\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// Re-export sub-components\nexport { FileList } from './file_list';\nexport { FileListItem } from './file_list_item';\nexport { FileManagerButton } from './file_manager_button';\nexport { UploadDropzone } from './upload_dropzone';\nexport { UploadProgressDisplay } from './upload_progress';\nexport type { FileItem, UploadProgress, UploadResult, FileManagerDisplayMode, PopoutContext } from './types';\n\nexport default FileManager;\n","/**\n * File List Component\n * Horizontal scrollable list of file items with navigation and add button\n */\n\nimport React, { useRef, useState, useEffect, useCallback } from 'react';\nimport { ChevronLeft, ChevronRight, Plus } from 'lucide-react';\nimport type { FileItem } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { FileListItem } from './file_list_item';\nimport { cn } from '../../utils/cn';\n\nexport interface FileListProps {\n /** Array of files to display */\n files: FileItem[];\n /** ID of the currently selected file */\n selected_file_id: string | null;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when a file is selected */\n on_select: (file: FileItem) => void;\n /** Callback when a file is deleted */\n on_delete?: (file_id: string) => void;\n /** Callback when add button is clicked (opens dropzone overlay) */\n on_add_click?: () => void;\n /** Callback when files are selected directly (for direct_upload mode) */\n on_files_selected?: (files: File[]) => void;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const FileList: React.FC<FileListProps> = ({\n files,\n selected_file_id,\n config,\n on_select,\n on_delete,\n on_add_click,\n on_files_selected,\n className,\n}) => {\n const scroll_ref = useRef<HTMLDivElement>(null);\n const file_input_ref = useRef<HTMLInputElement>(null);\n const drag_counter = useRef(0);\n const [can_scroll_left, setCanScrollLeft] = useState(false);\n const [can_scroll_right, setCanScrollRight] = useState(false);\n const [is_dragging, setIsDragging] = useState(false);\n\n const file_manager_config = config?.file_manager;\n const upload_config = config?.file_upload;\n const is_direct_upload = !!on_files_selected;\n\n // Parse allowed types for file input accept attribute\n const accept_string = upload_config?.allowed_types || 'application/pdf';\n\n // Check scroll state\n const update_scroll_state = () => {\n if (!scroll_ref.current) return;\n\n const { scrollLeft, scrollWidth, clientWidth } = scroll_ref.current;\n setCanScrollLeft(scrollLeft > 0);\n setCanScrollRight(scrollLeft + clientWidth < scrollWidth - 1);\n };\n\n // Update scroll state on mount and when files change\n useEffect(() => {\n update_scroll_state();\n window.addEventListener('resize', update_scroll_state);\n return () => window.removeEventListener('resize', update_scroll_state);\n }, [files]);\n\n // Scroll handlers\n const scroll_left = () => {\n if (scroll_ref.current) {\n scroll_ref.current.scrollBy({ left: -200, behavior: 'smooth' });\n }\n };\n\n const scroll_right = () => {\n if (scroll_ref.current) {\n scroll_ref.current.scrollBy({ left: 200, behavior: 'smooth' });\n }\n };\n\n // Scroll selected file into view\n useEffect(() => {\n if (!scroll_ref.current || !selected_file_id) return;\n\n const selected_element = scroll_ref.current.querySelector(\n `[data-file-id=\"${selected_file_id}\"]`\n );\n if (selected_element) {\n selected_element.scrollIntoView({\n behavior: 'smooth',\n block: 'nearest',\n inline: 'nearest',\n });\n }\n }, [selected_file_id]);\n\n // Direct upload: click opens file picker\n const handle_add_click = useCallback(() => {\n if (is_direct_upload) {\n file_input_ref.current?.click();\n } else {\n on_add_click?.();\n }\n }, [is_direct_upload, on_add_click]);\n\n // Direct upload: file input change\n const handle_input_change = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n on_files_selected?.(Array.from(e.target.files));\n e.target.value = '';\n }\n }, [on_files_selected]);\n\n // Direct upload: drag handlers for add button\n const handle_drag_enter = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current++;\n if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {\n setIsDragging(true);\n }\n }, []);\n\n const handle_drag_leave = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current--;\n if (drag_counter.current === 0) {\n setIsDragging(false);\n }\n }, []);\n\n const handle_drag_over = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n }, []);\n\n const handle_drop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n drag_counter.current = 0;\n if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n on_files_selected?.(Array.from(e.dataTransfer.files));\n }\n }, [on_files_selected]);\n\n const height = file_manager_config?.file_list_height || 60;\n const background_color = file_manager_config?.file_list_background_color || '#f3f4f6';\n const border_color = file_manager_config?.file_list_border_color || '#e5e7eb';\n const allow_delete = file_manager_config?.allow_delete ?? true;\n const show_add_button = upload_config?.show_add_button ?? true;\n const has_add_handler = is_direct_upload || !!on_add_click;\n\n return (\n <div\n className={cn('cls_file_list_container', className)}\n style={{\n minHeight: `${height}px`,\n backgroundColor: background_color,\n borderBottomColor: border_color,\n }}\n >\n {/* Scroll left button */}\n <button\n className={cn(\n 'cls_file_list_scroll_btn cls_file_list_scroll_btn_left',\n !can_scroll_left && 'cls_file_list_scroll_btn_disabled'\n )}\n onClick={scroll_left}\n disabled={!can_scroll_left}\n aria-label=\"Scroll left\"\n title=\"Scroll left\"\n >\n <ChevronLeft size={16} />\n </button>\n\n {/* Scrollable file list */}\n <div\n ref={scroll_ref}\n className=\"cls_file_list_scroll\"\n onScroll={update_scroll_state}\n >\n {files.map((file) => (\n <FileListItem\n key={file.id}\n file={file}\n is_selected={file.id === selected_file_id}\n show_delete={allow_delete}\n config={config}\n on_select={on_select}\n on_delete={on_delete}\n />\n ))}\n\n {/* Add button - in direct_upload mode, also acts as dropzone */}\n {show_add_button && has_add_handler && (\n <>\n <button\n className={cn(\n 'cls_file_list_add_btn',\n is_dragging && 'cls_file_list_add_btn_dragging'\n )}\n onClick={handle_add_click}\n onDragEnter={is_direct_upload ? handle_drag_enter : undefined}\n onDragLeave={is_direct_upload ? handle_drag_leave : undefined}\n onDragOver={is_direct_upload ? handle_drag_over : undefined}\n onDrop={is_direct_upload ? handle_drop : undefined}\n aria-label=\"Add file\"\n title={is_direct_upload ? 'Click to browse or drag files here' : 'Add file'}\n >\n <Plus size={16} />\n <span className=\"cls_file_list_add_btn_text\">\n {is_dragging ? 'Drop here' : 'Add file'}\n </span>\n </button>\n {/* Hidden file input for direct upload mode */}\n {is_direct_upload && (\n <input\n ref={file_input_ref}\n type=\"file\"\n accept={accept_string}\n multiple\n onChange={handle_input_change}\n style={{ display: 'none' }}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n )}\n </>\n )}\n </div>\n\n {/* Scroll right button */}\n <button\n className={cn(\n 'cls_file_list_scroll_btn cls_file_list_scroll_btn_right',\n !can_scroll_right && 'cls_file_list_scroll_btn_disabled'\n )}\n onClick={scroll_right}\n disabled={!can_scroll_right}\n aria-label=\"Scroll right\"\n title=\"Scroll right\"\n >\n <ChevronRight size={16} />\n </button>\n </div>\n );\n};\n\nexport default FileList;\n","/**\n * File List Item Component\n * Simple horizontal tab-style file item\n */\n\nimport React, { useState } from 'react';\nimport { X, FileText, Loader2 } from 'lucide-react';\nimport type { FileItem } from './types';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { cn } from '../../utils/cn';\n\nexport interface FileListItemProps {\n /** File to display */\n file: FileItem;\n /** Whether this file is currently selected */\n is_selected: boolean;\n /** Whether to show delete button */\n show_delete: boolean;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when file is selected */\n on_select: (file: FileItem) => void;\n /** Callback when delete is clicked */\n on_delete?: (file_id: string) => void;\n}\n\n/**\n * Get display name - truncate if needed\n */\nfunction get_display_name(filename: string, max_length: number = 24): string {\n if (filename.length <= max_length) {\n return filename;\n }\n\n const ext_index = filename.lastIndexOf('.');\n if (ext_index === -1 || ext_index === 0) {\n return filename.substring(0, max_length - 3) + '...';\n }\n\n const ext = filename.substring(ext_index);\n const name = filename.substring(0, ext_index);\n const available = max_length - ext.length - 3;\n\n if (available <= 0) {\n return filename.substring(0, max_length - 3) + '...';\n }\n\n return name.substring(0, available) + '...' + ext;\n}\n\nexport const FileListItem: React.FC<FileListItemProps> = ({\n file,\n is_selected,\n show_delete,\n config,\n on_select,\n on_delete,\n}) => {\n const [is_hovered, setIsHovered] = useState(false);\n\n const file_manager_config = config?.file_manager;\n const selected_color = file_manager_config?.selected_color || '#3b82f6';\n\n const handle_click = () => {\n on_select(file);\n };\n\n const handle_delete_click = (e: React.MouseEvent) => {\n e.stopPropagation();\n on_delete?.(file.id);\n };\n\n const display_name = get_display_name(file.name);\n const show_close = show_delete && on_delete && (is_hovered || is_selected);\n\n return (\n <div\n className={cn(\n 'cls_file_tab',\n is_selected && 'cls_file_tab_selected'\n )}\n data-file-id={file.id}\n style={is_selected ? {\n borderColor: selected_color,\n } : undefined}\n onClick={handle_click}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n title={file.name}\n role=\"tab\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handle_click();\n }\n }}\n aria-selected={is_selected}\n aria-label={file.name}\n >\n {file.status === 'converting' || file.status === 'uploading' ? (\n <Loader2 size={16} className=\"cls_file_tab_icon cls_file_tab_spinner\" />\n ) : file.type === 'pdf' ? (\n <FileText size={16} className=\"cls_file_tab_icon\" />\n ) : null}\n <span className=\"cls_file_tab_name\">\n {display_name}\n </span>\n\n {show_close && (\n <button\n className=\"cls_file_tab_close\"\n onClick={handle_delete_click}\n aria-label={`Close ${file.name}`}\n title={`Close ${file.name}`}\n >\n <X size={14} />\n </button>\n )}\n </div>\n );\n};\n\nexport default FileListItem;\n","/**\n * Upload Dropzone Component\n * Drag-and-drop file upload zone with click-to-upload support\n */\n\nimport React, { useState, useRef, useCallback } from 'react';\nimport { Upload, X } from 'lucide-react';\nimport type { PdfViewerConfig } from '../../types/config';\nimport type { UploadProgress } from './types';\nimport { UploadProgressDisplay } from './upload_progress';\nimport { cn } from '../../utils/cn';\n\nexport interface UploadDropzoneProps {\n /** Configuration for styling and upload settings */\n config: PdfViewerConfig | null;\n /** Current upload progress items */\n uploads: UploadProgress[];\n /** Callback when files are selected for upload */\n on_files_selected: (files: File[]) => void;\n /** Whether the dropzone is disabled */\n disabled?: boolean;\n /** Callback to close the dropzone (for modal mode) */\n on_close?: () => void;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const UploadDropzone: React.FC<UploadDropzoneProps> = ({\n config,\n uploads,\n on_files_selected,\n disabled = false,\n on_close,\n className,\n}) => {\n const [is_dragging, setIsDragging] = useState(false);\n const [validation_error, setValidationError] = useState<string | null>(null);\n const input_ref = useRef<HTMLInputElement>(null);\n const drag_counter = useRef(0);\n\n const upload_config = config?.file_upload;\n\n // Parse allowed types from config\n const allowed_types = (upload_config?.allowed_types || 'application/pdf').split(',').map(t => t.trim());\n const max_file_size = upload_config?.max_file_size || 10485760; // 10MB\n const max_files = upload_config?.max_files || 10;\n\n /**\n * Validate a single file\n */\n const validate_file = useCallback((file: File): string | null => {\n // Check file type\n const is_type_allowed = allowed_types.some(type => {\n const trimmed = type.trim().toLowerCase();\n const file_type = file.type.toLowerCase();\n\n // Handle wildcard patterns like image/*\n if (trimmed.endsWith('/*')) {\n const prefix = trimmed.slice(0, -2);\n return file_type.startsWith(prefix);\n }\n\n return file_type === trimmed;\n });\n\n if (!is_type_allowed) {\n return `File type \"${file.type || 'unknown'}\" is not allowed`;\n }\n\n // Check file size\n if (file.size > max_file_size) {\n const max_mb = Math.round(max_file_size / 1024 / 1024);\n const file_mb = (file.size / 1024 / 1024).toFixed(1);\n return `File is too large (${file_mb}MB). Maximum size is ${max_mb}MB`;\n }\n\n return null;\n }, [allowed_types, max_file_size]);\n\n /**\n * Handle selected files (from drag or click)\n */\n const handle_files = useCallback((file_list: FileList | File[]) => {\n const files = Array.from(file_list);\n setValidationError(null);\n\n if (files.length === 0) {\n return;\n }\n\n // Check max files limit\n if (files.length > max_files) {\n setValidationError(`Too many files. Maximum is ${max_files} files.`);\n return;\n }\n\n // Validate each file\n const valid_files: File[] = [];\n const errors: string[] = [];\n\n for (const file of files) {\n const error = validate_file(file);\n if (error) {\n errors.push(`${file.name}: ${error}`);\n } else {\n valid_files.push(file);\n }\n }\n\n // Show first error if any\n if (errors.length > 0) {\n setValidationError(errors[0]);\n }\n\n // Process valid files\n if (valid_files.length > 0) {\n on_files_selected(valid_files);\n }\n }, [max_files, validate_file, on_files_selected]);\n\n // Drag handlers\n const handle_drag_enter = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current++;\n if (!disabled && e.dataTransfer.items && e.dataTransfer.items.length > 0) {\n setIsDragging(true);\n }\n };\n\n const handle_drag_leave = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n drag_counter.current--;\n if (drag_counter.current === 0) {\n setIsDragging(false);\n }\n };\n\n const handle_drag_over = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n };\n\n const handle_drop = (e: React.DragEvent) => {\n e.preventDefault();\n e.stopPropagation();\n setIsDragging(false);\n drag_counter.current = 0;\n\n if (!disabled && e.dataTransfer.files) {\n handle_files(e.dataTransfer.files);\n }\n };\n\n // Click handler\n const handle_click = () => {\n if (!disabled) {\n input_ref.current?.click();\n }\n };\n\n // File input change handler\n const handle_input_change = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (e.target.files) {\n handle_files(e.target.files);\n // Reset input value so same file can be selected again\n e.target.value = '';\n }\n };\n\n // Get accept string for file input\n const accept_string = allowed_types.join(',');\n\n // Styling from config\n const border_color = is_dragging\n ? (upload_config?.dropzone_border_color_active || '#3b82f6')\n : (upload_config?.dropzone_border_color || '#d1d5db');\n const background_color = upload_config?.dropzone_background_color || '#f9fafb';\n\n return (\n <div className={cn('cls_upload_dropzone_wrapper', className)}>\n {/* Close button for modal mode */}\n {on_close && (\n <button\n className=\"cls_upload_dropzone_close_btn\"\n onClick={on_close}\n aria-label=\"Close\"\n >\n <X size={20} />\n </button>\n )}\n\n {/* Dropzone area */}\n <div\n className={cn(\n 'cls_upload_dropzone',\n is_dragging && 'cls_upload_dropzone_active',\n disabled && 'cls_upload_dropzone_disabled'\n )}\n style={{\n borderColor: border_color,\n backgroundColor: is_dragging ? `${border_color}10` : background_color,\n }}\n onDragEnter={handle_drag_enter}\n onDragLeave={handle_drag_leave}\n onDragOver={handle_drag_over}\n onDrop={handle_drop}\n onClick={handle_click}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n onKeyDown={(e) => {\n if ((e.key === 'Enter' || e.key === ' ') && !disabled) {\n e.preventDefault();\n handle_click();\n }\n }}\n aria-label=\"Drop files here or click to upload\"\n aria-disabled={disabled}\n >\n <input\n ref={input_ref}\n type=\"file\"\n accept={accept_string}\n multiple\n onChange={handle_input_change}\n className=\"cls_upload_dropzone_input\"\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n\n <Upload\n size={40}\n className={cn(\n 'cls_upload_dropzone_icon',\n is_dragging && 'cls_upload_dropzone_icon_active'\n )}\n style={{ color: is_dragging ? border_color : '#9ca3af' }}\n />\n\n <p className=\"cls_upload_dropzone_text\">\n {is_dragging ? 'Drop files here' : 'Drop files here or click to upload'}\n </p>\n\n <p className=\"cls_upload_dropzone_hint\">\n PDF, images, text files, or Excel spreadsheets\n </p>\n\n {/* Validation error */}\n {validation_error && (\n <p className=\"cls_upload_dropzone_error\">\n {validation_error}\n </p>\n )}\n </div>\n\n {/* Upload progress */}\n <UploadProgressDisplay uploads={uploads} />\n </div>\n );\n};\n\nexport default UploadDropzone;\n","/**\n * Upload Progress Component\n * Shows upload progress for files being uploaded/converted\n */\n\nimport React from 'react';\nimport { Loader2, CheckCircle, XCircle } from 'lucide-react';\nimport type { UploadProgress } from './types';\nimport { cn } from '../../utils/cn';\n\nexport interface UploadProgressProps {\n /** Array of upload progress items */\n uploads: UploadProgress[];\n /** Additional CSS class name */\n className?: string;\n}\n\n/**\n * Get status icon based on upload status\n */\nfunction get_status_icon(status: UploadProgress['status']) {\n switch (status) {\n case 'complete':\n return <CheckCircle size={16} className=\"cls_upload_progress_icon_success\" />;\n case 'error':\n return <XCircle size={16} className=\"cls_upload_progress_icon_error\" />;\n case 'converting':\n case 'uploading':\n case 'pending':\n return <Loader2 size={16} className=\"cls_upload_progress_icon_loading\" />;\n default:\n return null;\n }\n}\n\n/**\n * Get status text for display\n */\nfunction get_status_text(upload: UploadProgress): string {\n switch (upload.status) {\n case 'pending':\n return 'Waiting...';\n case 'uploading':\n return `${upload.progress}%`;\n case 'converting':\n return 'Converting...';\n case 'complete':\n return 'Done';\n case 'error':\n return upload.error_message || 'Failed';\n default:\n return '';\n }\n}\n\nexport const UploadProgressDisplay: React.FC<UploadProgressProps> = ({\n uploads,\n className,\n}) => {\n if (uploads.length === 0) {\n return null;\n }\n\n return (\n <div className={cn('cls_upload_progress_container', className)}>\n {uploads.map((upload) => (\n <div\n key={upload.file_id}\n className={cn(\n 'cls_upload_progress_item',\n upload.status === 'error' && 'cls_upload_progress_item_error',\n upload.status === 'complete' && 'cls_upload_progress_item_complete'\n )}\n >\n <div className=\"cls_upload_progress_icon\">\n {get_status_icon(upload.status)}\n </div>\n\n <span className=\"cls_upload_progress_filename\" title={upload.filename}>\n {upload.filename}\n </span>\n\n <div className=\"cls_upload_progress_bar_container\">\n <div\n className={cn(\n 'cls_upload_progress_bar',\n upload.status === 'error' && 'cls_upload_progress_bar_error',\n upload.status === 'complete' && 'cls_upload_progress_bar_complete'\n )}\n style={{ width: `${upload.progress}%` }}\n />\n </div>\n\n <span className=\"cls_upload_progress_status\">\n {get_status_text(upload)}\n </span>\n </div>\n ))}\n </div>\n );\n};\n\nexport default UploadProgressDisplay;\n","/**\n * File Manager Button Component\n * Compact trigger button with badge showing file count\n */\n\nimport React, { useState } from 'react';\nimport { FaFileAlt, FaFolderOpen } from 'react-icons/fa';\nimport type { PdfViewerConfig } from '../../types/config';\nimport { cn } from '../../utils/cn';\n\nexport interface FileManagerButtonProps {\n /** Number of files in the file manager */\n file_count: number;\n /** Configuration for styling */\n config: PdfViewerConfig | null;\n /** Callback when button is clicked */\n on_click: () => void;\n /** Whether the button is disabled */\n disabled?: boolean;\n /** Custom tooltip text */\n tooltip?: string;\n /** Additional CSS class name */\n className?: string;\n}\n\nexport const FileManagerButton: React.FC<FileManagerButtonProps> = ({\n file_count,\n config,\n on_click,\n disabled = false,\n tooltip,\n className,\n}) => {\n const [is_hovered, setIsHovered] = useState(false);\n\n const button_config = config?.file_button;\n\n const icon_size = button_config?.icon_size || 24;\n\n // Determine icon color based on state\n let icon_color = button_config?.icon_color || '#6b7280';\n if (file_count > 0) {\n icon_color = button_config?.icon_color_with_files || '#3b82f6';\n }\n if (is_hovered && !disabled) {\n icon_color = button_config?.icon_color_hover || '#374151';\n if (file_count > 0) {\n icon_color = button_config?.icon_color_with_files || '#3b82f6';\n }\n }\n\n const badge_background = button_config?.badge_background || '#3b82f6';\n const badge_text_color = button_config?.badge_text_color || '#ffffff';\n\n // Format badge count\n const badge_text = file_count > 99 ? '99+' : file_count.toString();\n\n // Generate tooltip text\n const tooltip_text = tooltip || (\n file_count === 0\n ? 'No files'\n : file_count === 1\n ? '1 file'\n : `${file_count} files`\n );\n\n return (\n <button\n className={cn(\n 'cls_file_manager_button',\n disabled && 'cls_file_manager_button_disabled',\n className\n )}\n onClick={on_click}\n disabled={disabled}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n aria-label={tooltip_text}\n title={tooltip_text}\n >\n {file_count > 0 ? (\n <FaFolderOpen size={icon_size} style={{ color: icon_color }} />\n ) : (\n <FaFileAlt size={icon_size} style={{ color: icon_color }} />\n )}\n\n {file_count > 0 && (\n <span\n className=\"cls_file_manager_button_badge\"\n style={{\n backgroundColor: badge_background,\n color: badge_text_color,\n }}\n >\n {badge_text}\n </span>\n )}\n </button>\n );\n};\n\nexport default FileManagerButton;\n","/**\n * PDF Converter Utility\n * Converts images and text files to PDF using pdf-lib\n * This module is standalone and can be tested independently\n */\n\nimport { get_logger } from './logger';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SupportedImageType =\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp';\n\nexport type SupportedTextType =\n | 'text/plain'\n | 'text/markdown'\n | 'text/csv';\n\nexport type SupportedExcelType =\n | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' // .xlsx\n | 'application/vnd.ms-excel' // .xls\n | 'application/vnd.google-apps.spreadsheet'; // Google Sheets (when exported)\n\nexport type SupportedConversionType = SupportedImageType | SupportedTextType | SupportedExcelType;\n\nexport interface PdfConversionOptions {\n /** Page size: 'letter' (612x792), 'a4' (595x842), 'legal' (612x1008) */\n page_size?: 'letter' | 'a4' | 'legal';\n /** Image quality 0.0-1.0 for lossy compression (default: 0.85) */\n image_quality?: number;\n /** How image fits on page: 'fit' (preserve aspect), 'fill' (crop), 'stretch' */\n image_fit?: 'fit' | 'fill' | 'stretch';\n /** Margin in points (72 points = 1 inch, default: 36) */\n margin?: number;\n /** Font size for text files in points (default: 12) */\n font_size?: number;\n /** Line height multiplier for text files (default: 1.4) */\n line_height?: number;\n}\n\nexport interface ConversionResult {\n /** Whether conversion succeeded */\n success: boolean;\n /** Converted PDF as Uint8Array (if success) */\n pdf_bytes?: Uint8Array;\n /** Original filename without extension */\n original_name?: string;\n /** Generated PDF filename */\n pdf_filename?: string;\n /** Original file type that was converted */\n source_type?: 'image' | 'text' | 'excel';\n /** Number of pages in the resulting PDF */\n page_count?: number;\n /** Error message (if !success) */\n error?: string;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst PAGE_SIZES = {\n letter: { width: 612, height: 792 },\n a4: { width: 595, height: 842 },\n legal: { width: 612, height: 1008 },\n} as const;\n\nconst SUPPORTED_IMAGE_TYPES: SupportedImageType[] = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n];\n\nconst SUPPORTED_TEXT_TYPES: SupportedTextType[] = [\n 'text/plain',\n 'text/markdown',\n 'text/csv',\n];\n\nconst SUPPORTED_EXCEL_TYPES: SupportedExcelType[] = [\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-excel',\n 'application/vnd.google-apps.spreadsheet',\n];\n\nconst DEFAULT_OPTIONS: Required<PdfConversionOptions> = {\n page_size: 'letter',\n image_quality: 0.85,\n image_fit: 'fit',\n margin: 36,\n font_size: 12,\n line_height: 1.4,\n};\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Check if a MIME type can be converted to PDF\n * @param mime_type - MIME type to check\n * @returns true if the type is supported for conversion\n */\nexport function can_convert_to_pdf(mime_type: string): boolean {\n const normalized = mime_type.toLowerCase().trim();\n return (\n SUPPORTED_IMAGE_TYPES.includes(normalized as SupportedImageType) ||\n SUPPORTED_TEXT_TYPES.includes(normalized as SupportedTextType) ||\n SUPPORTED_EXCEL_TYPES.includes(normalized as SupportedExcelType)\n );\n}\n\n/**\n * Get list of supported MIME types for conversion\n * @returns Array of supported MIME types\n */\nexport function get_supported_types(): string[] {\n return [...SUPPORTED_IMAGE_TYPES, ...SUPPORTED_TEXT_TYPES, ...SUPPORTED_EXCEL_TYPES];\n}\n\n/**\n * Check if a MIME type is an image type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported image type\n */\nexport function is_image_type(mime_type: string): boolean {\n return SUPPORTED_IMAGE_TYPES.includes(mime_type.toLowerCase().trim() as SupportedImageType);\n}\n\n/**\n * Check if a MIME type is a text type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported text type\n */\nexport function is_text_type(mime_type: string): boolean {\n return SUPPORTED_TEXT_TYPES.includes(mime_type.toLowerCase().trim() as SupportedTextType);\n}\n\n/**\n * Check if a MIME type is an Excel/spreadsheet type\n * @param mime_type - MIME type to check\n * @returns true if the type is a supported Excel type\n */\nexport function is_excel_type(mime_type: string): boolean {\n return SUPPORTED_EXCEL_TYPES.includes(mime_type.toLowerCase().trim() as SupportedExcelType);\n}\n\n/**\n * Convert a file to PDF\n * @param file - File or Blob to convert\n * @param filename - Original filename (used for output naming)\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_to_pdf(\n file: File | Blob,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const mime_type = file.type.toLowerCase().trim();\n\n if (!can_convert_to_pdf(mime_type)) {\n return {\n success: false,\n error: `Unsupported file type: ${mime_type}. Supported types: ${get_supported_types().join(', ')}`,\n };\n }\n\n try {\n if (is_image_type(mime_type)) {\n const image_bytes = new Uint8Array(await file.arrayBuffer());\n return await convert_image_to_pdf(\n image_bytes,\n mime_type as SupportedImageType,\n filename,\n options\n );\n }\n\n if (is_text_type(mime_type)) {\n const text_content = await file.text();\n return await convert_text_to_pdf(text_content, filename, options);\n }\n\n if (is_excel_type(mime_type)) {\n const excel_bytes = new Uint8Array(await file.arrayBuffer());\n return await convert_excel_to_pdf(excel_bytes, filename, options);\n }\n\n return {\n success: false,\n error: `Conversion not implemented for type: ${mime_type}`,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting file', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error during conversion',\n };\n }\n}\n\n/**\n * Convert image bytes to PDF\n * @param image_bytes - Raw image data as Uint8Array\n * @param mime_type - Image MIME type\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_image_to_pdf(\n image_bytes: Uint8Array,\n mime_type: SupportedImageType,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const page_size = PAGE_SIZES[opts.page_size];\n\n try {\n // Dynamically import pdf-lib\n const { PDFDocument } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting image to PDF', { filename, mime_type });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed the image based on type\n let embedded_image;\n\n if (mime_type === 'image/jpeg') {\n logger.debug('Embedding JPEG image directly', { bytes: image_bytes.length });\n embedded_image = await pdf_doc.embedJpg(image_bytes);\n } else if (mime_type === 'image/png') {\n logger.debug('Embedding PNG image directly', { bytes: image_bytes.length });\n embedded_image = await pdf_doc.embedPng(image_bytes);\n } else if (mime_type === 'image/gif' || mime_type === 'image/webp') {\n // GIF and WebP need to be converted to PNG first via canvas\n logger.debug('Converting image via canvas', { mime_type, bytes: image_bytes.length });\n const png_bytes = await convert_image_via_canvas(image_bytes, mime_type);\n logger.debug('Image converted to PNG', { original_bytes: image_bytes.length, png_bytes: png_bytes.length });\n embedded_image = await pdf_doc.embedPng(png_bytes);\n } else {\n return {\n success: false,\n error: `Unsupported image type: ${mime_type}`,\n };\n }\n\n // Calculate image dimensions to fit on page\n const { width: img_width, height: img_height } = embedded_image;\n const available_width = page_size.width - (opts.margin * 2);\n const available_height = page_size.height - (opts.margin * 2);\n\n let draw_width: number;\n let draw_height: number;\n\n if (opts.image_fit === 'stretch') {\n // Stretch to fill available area\n draw_width = available_width;\n draw_height = available_height;\n } else if (opts.image_fit === 'fill') {\n // Fill available area (may crop)\n const scale = Math.max(\n available_width / img_width,\n available_height / img_height\n );\n draw_width = img_width * scale;\n draw_height = img_height * scale;\n } else {\n // 'fit' - preserve aspect ratio, fit within available area\n const scale = Math.min(\n available_width / img_width,\n available_height / img_height\n );\n draw_width = img_width * scale;\n draw_height = img_height * scale;\n }\n\n // Center the image on the page\n const draw_x = opts.margin + (available_width - draw_width) / 2;\n const draw_y = opts.margin + (available_height - draw_height) / 2;\n\n // Add a page and draw the image\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n page.drawImage(embedded_image, {\n x: draw_x,\n y: draw_y,\n width: draw_width,\n height: draw_height,\n });\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Image converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'image',\n page_count: 1,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting image', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting image',\n };\n }\n}\n\n/**\n * Convert text content to PDF\n * @param text_content - Text string to convert\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_text_to_pdf(\n text_content: string,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const page_size = PAGE_SIZES[opts.page_size];\n\n try {\n // Dynamically import pdf-lib\n const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting text to PDF', { filename, content_length: text_content.length });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed a standard font\n const font = await pdf_doc.embedFont(StandardFonts.Helvetica);\n\n // Calculate text area dimensions\n const margin = opts.margin;\n const font_size = opts.font_size;\n const line_height = font_size * opts.line_height;\n const available_width = page_size.width - (margin * 2);\n const available_height = page_size.height - (margin * 2);\n const lines_per_page = Math.floor(available_height / line_height);\n\n // Split text into lines that fit within the page width\n const lines = wrap_text(text_content, font, font_size, available_width);\n\n // Create pages and draw text\n let current_line = 0;\n let page_count = 0;\n\n while (current_line < lines.length) {\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n page_count++;\n\n let y = page_size.height - margin - font_size;\n\n for (let i = 0; i < lines_per_page && current_line < lines.length; i++) {\n page.drawText(lines[current_line], {\n x: margin,\n y: y,\n size: font_size,\n font: font,\n color: rgb(0, 0, 0),\n });\n\n y -= line_height;\n current_line++;\n }\n }\n\n // Ensure at least one page exists\n if (page_count === 0) {\n pdf_doc.addPage([page_size.width, page_size.height]);\n page_count = 1;\n }\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Text converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length, pages: page_count });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'text',\n page_count,\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting text', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting text',\n };\n }\n}\n\n/**\n * Convert Excel spreadsheet to PDF\n * Fits all columns on one page by scaling down (zooming out) if needed\n * Includes row numbers and column letters like Excel\n * @param excel_bytes - Raw Excel data as Uint8Array\n * @param filename - Original filename\n * @param options - Conversion options\n * @returns Promise resolving to ConversionResult\n */\nexport async function convert_excel_to_pdf(\n excel_bytes: Uint8Array,\n filename: string,\n options?: PdfConversionOptions\n): Promise<ConversionResult> {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n const base_page_size = PAGE_SIZES[opts.page_size];\n // Use landscape orientation for Excel (swap width and height)\n const page_size = { width: base_page_size.height, height: base_page_size.width };\n\n try {\n // Dynamically import xlsx and pdf-lib\n const XLSX = await import('xlsx');\n const { PDFDocument, StandardFonts, rgb } = await import('pdf-lib');\n\n const logger = get_logger();\n logger.info('Converting Excel to PDF', { filename, orientation: 'landscape' });\n\n // Parse the Excel workbook\n const workbook = XLSX.read(excel_bytes, { type: 'array' });\n\n // Create a new PDF document\n const pdf_doc = await PDFDocument.create();\n\n // Embed fonts\n const font = await pdf_doc.embedFont(StandardFonts.Helvetica);\n const bold_font = await pdf_doc.embedFont(StandardFonts.HelveticaBold);\n\n // Layout constants (base values - will be scaled per page)\n const margin = opts.margin;\n const font_size = opts.font_size;\n const small_font_size = font_size - 2;\n const title_font_size = font_size + 2;\n const line_height = font_size * opts.line_height;\n const cell_padding = 5;\n const row_num_width = 35; // Width for row number column\n const available_width = page_size.width - (margin * 2) - row_num_width;\n const available_height = page_size.height - (margin * 2);\n\n // Collect all pages info first, then render with correct page numbers\n interface PageInfo {\n sheet_name: string;\n sheet_idx: number;\n start_row: number;\n end_row: number;\n col_widths: number[]; // Scaled column widths\n scale: number; // Scale factor applied to fit columns on page\n }\n const all_pages: PageInfo[] = [];\n\n // Process each sheet to collect page info\n for (let sheet_idx = 0; sheet_idx < workbook.SheetNames.length; sheet_idx++) {\n const sheet_name = workbook.SheetNames[sheet_idx];\n const sheet = workbook.Sheets[sheet_name];\n\n // Get the range of data in the sheet\n const range = XLSX.utils.decode_range(sheet['!ref'] || 'A1');\n const num_cols = range.e.c - range.s.c + 1;\n\n if (num_cols === 0) continue;\n\n // Convert sheet to 2D array\n const data: string[][] = XLSX.utils.sheet_to_json(sheet, {\n header: 1,\n defval: ''\n }) as string[][];\n\n if (data.length === 0) continue;\n\n // Calculate optimal column widths\n const col_widths = calculate_optimal_column_widths(data, font, font_size, num_cols);\n\n // Calculate scale factor to fit all columns on one page\n const total_width = col_widths.reduce((sum, w) => sum + w, 0);\n const scale = total_width > available_width ? available_width / total_width : 1;\n const scaled_col_widths = col_widths.map(w => w * scale);\n\n logger.debug('Excel sheet scale calculation', {\n sheet_name,\n num_cols,\n total_width,\n available_width,\n scale: Math.round(scale * 100) / 100,\n rows: data.length,\n });\n\n // Calculate rows per page using scaled dimensions\n const scaled_line_height = line_height * scale;\n const scaled_cell_padding = cell_padding * scale;\n const scaled_title_height = title_font_size * scale * 2;\n const scaled_col_label_height = (small_font_size * scale) + 4;\n const row_height = scaled_line_height + scaled_cell_padding * 2;\n const content_height = available_height - scaled_title_height - scaled_col_label_height - row_height;\n const rows_per_page = Math.floor(content_height / row_height);\n\n // Generate pages: one page per vertical section (all columns fit on each page)\n let current_row = 1; // Start after header\n while (current_row < data.length) {\n const end_row = Math.min(current_row + rows_per_page, data.length);\n\n all_pages.push({\n sheet_name,\n sheet_idx,\n start_row: current_row,\n end_row,\n col_widths: scaled_col_widths,\n scale,\n });\n\n current_row = end_row;\n }\n }\n\n // Now render all pages\n for (let page_num = 0; page_num < all_pages.length; page_num++) {\n const page_info = all_pages[page_num];\n const sheet = workbook.Sheets[page_info.sheet_name];\n const data: string[][] = XLSX.utils.sheet_to_json(sheet, {\n header: 1,\n defval: ''\n }) as string[][];\n\n const page = pdf_doc.addPage([page_size.width, page_size.height]);\n\n // Use scaled dimensions\n const scale = page_info.scale;\n const scaled_font_size = font_size * scale;\n const scaled_small_font_size = small_font_size * scale;\n const scaled_title_font_size = title_font_size * scale;\n const scaled_line_height = line_height * scale;\n const scaled_cell_padding = cell_padding * scale;\n const scaled_row_num_width = row_num_width * scale;\n const scaled_title_height = scaled_title_font_size * 2;\n const scaled_col_label_height = scaled_small_font_size + 4;\n const row_height = scaled_line_height + scaled_cell_padding * 2;\n\n let y = page_size.height - margin;\n\n // Draw title with sheet name (only if multiple sheets)\n const show_sheet_name = workbook.SheetNames.length > 1;\n if (show_sheet_name) {\n page.drawText(`Sheet: ${page_info.sheet_name}`, {\n x: margin,\n y: y - scaled_title_font_size,\n size: scaled_title_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n y -= scaled_title_height;\n }\n\n // Calculate table width for this page\n const table_width = page_info.col_widths.reduce((sum, w) => sum + w, 0);\n const num_cols = page_info.col_widths.length;\n\n // Draw column letter row (A, B, C...)\n let x = margin + scaled_row_num_width;\n page.drawRectangle({\n x: margin,\n y: y - scaled_col_label_height,\n width: scaled_row_num_width + table_width,\n height: scaled_col_label_height,\n color: rgb(0.85, 0.85, 0.85),\n });\n\n // Empty cell for row number column header\n page.drawRectangle({\n x: margin,\n y: y - scaled_col_label_height,\n width: scaled_row_num_width,\n height: scaled_col_label_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const col_letter = column_index_to_letter(col_idx);\n\n // Center the column letter\n const letter_width = font.widthOfTextAtSize(col_letter, scaled_small_font_size);\n page.drawText(col_letter, {\n x: x + (col_width - letter_width) / 2,\n y: y - scaled_col_label_height + 3,\n size: scaled_small_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n\n page.drawRectangle({\n x: x,\n y: y - scaled_col_label_height,\n width: col_width,\n height: scaled_col_label_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n y -= scaled_col_label_height;\n\n // Draw header row (row 1 from data)\n const header_row = data[0] || [];\n x = margin;\n\n // Row number for header (1)\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n color: rgb(0.85, 0.85, 0.85),\n });\n const row_1_text = '1';\n const row_1_width = font.widthOfTextAtSize(row_1_text, scaled_small_font_size);\n page.drawText(row_1_text, {\n x: margin + (scaled_row_num_width - row_1_width) / 2,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_small_font_size,\n font: bold_font,\n color: rgb(0.3, 0.3, 0.3),\n });\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x = margin + scaled_row_num_width;\n\n // Draw header background\n page.drawRectangle({\n x: margin + scaled_row_num_width,\n y: y - row_height,\n width: table_width,\n height: row_height,\n color: rgb(0.9, 0.9, 0.9),\n });\n\n // Draw header cells\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const cell_value = String(header_row[col_idx] || '');\n const truncated = truncate_text(cell_value, font, scaled_font_size, col_width - scaled_cell_padding * 2);\n\n page.drawText(truncated, {\n x: x + scaled_cell_padding,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_font_size,\n font: bold_font,\n color: rgb(0, 0, 0),\n });\n\n page.drawRectangle({\n x: x,\n y: y - row_height,\n width: col_width,\n height: row_height,\n borderColor: rgb(0.6, 0.6, 0.6),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n\n y -= row_height;\n\n // Draw data rows\n for (let row_idx = page_info.start_row; row_idx < page_info.end_row; row_idx++) {\n const row = data[row_idx] || [];\n x = margin;\n\n // Row number cell\n const row_num = row_idx + 1; // Excel rows are 1-indexed\n const row_num_text = String(row_num);\n const row_num_text_width = font.widthOfTextAtSize(row_num_text, scaled_small_font_size);\n\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n color: rgb(0.92, 0.92, 0.92),\n });\n page.drawText(row_num_text, {\n x: margin + (scaled_row_num_width - row_num_text_width) / 2,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_small_font_size,\n font: font,\n color: rgb(0.4, 0.4, 0.4),\n });\n page.drawRectangle({\n x: margin,\n y: y - row_height,\n width: scaled_row_num_width,\n height: row_height,\n borderColor: rgb(0.7, 0.7, 0.7),\n borderWidth: 0.5,\n });\n\n x = margin + scaled_row_num_width;\n\n // Alternate row background\n if ((row_idx - page_info.start_row) % 2 === 1) {\n page.drawRectangle({\n x: margin + scaled_row_num_width,\n y: y - row_height,\n width: table_width,\n height: row_height,\n color: rgb(0.97, 0.97, 0.97),\n });\n }\n\n for (let col_idx = 0; col_idx < num_cols; col_idx++) {\n const col_width = page_info.col_widths[col_idx];\n const cell_value = String(row[col_idx] || '');\n const truncated = truncate_text(cell_value, font, scaled_font_size, col_width - scaled_cell_padding * 2);\n\n page.drawText(truncated, {\n x: x + scaled_cell_padding,\n y: y - row_height + scaled_cell_padding + 2,\n size: scaled_font_size,\n font: font,\n color: rgb(0, 0, 0),\n });\n\n page.drawRectangle({\n x: x,\n y: y - row_height,\n width: col_width,\n height: row_height,\n borderColor: rgb(0.7, 0.7, 0.7),\n borderWidth: 0.5,\n });\n\n x += col_width;\n }\n\n y -= row_height;\n }\n }\n\n const total_page_count = pdf_doc.getPageCount();\n\n // Ensure at least one page exists\n if (total_page_count === 0) {\n pdf_doc.addPage([page_size.width, page_size.height]);\n }\n\n // Save the PDF\n const pdf_bytes = await pdf_doc.save();\n\n // Generate output filename\n const name_without_ext = filename.replace(/\\.[^.]+$/, '');\n const pdf_filename = `${name_without_ext}.pdf`;\n\n logger.info('Excel converted to PDF', { filename: pdf_filename, bytes: pdf_bytes.length, pages: pdf_doc.getPageCount() });\n\n return {\n success: true,\n pdf_bytes,\n original_name: name_without_ext,\n pdf_filename,\n source_type: 'excel',\n page_count: pdf_doc.getPageCount(),\n };\n } catch (error) {\n const logger = get_logger();\n logger.error('Error converting Excel', { error: error instanceof Error ? error.message : String(error) });\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error converting Excel',\n };\n }\n}\n\n// =============================================================================\n// Internal Helpers\n// =============================================================================\n\n/**\n * Convert column index to Excel-style letter (0 -> A, 1 -> B, 25 -> Z, 26 -> AA, etc.)\n * @param index - Zero-based column index\n * @returns Column letter(s)\n */\nfunction column_index_to_letter(index: number): string {\n let result = '';\n let num = index;\n\n while (num >= 0) {\n result = String.fromCharCode((num % 26) + 65) + result;\n num = Math.floor(num / 26) - 1;\n }\n\n return result;\n}\n\n/**\n * Calculate optimal column widths without constraining to page width\n * Each column gets the width it needs to display content properly\n * @param data - 2D array of cell data\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param num_cols - Number of columns\n * @returns Array of optimal column widths\n */\nfunction calculate_optimal_column_widths(\n data: string[][],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n num_cols: number\n): number[] {\n const min_col_width = 50;\n const max_col_width = 250; // Cap individual column width\n const padding = 14;\n\n const col_widths: number[] = new Array(num_cols).fill(min_col_width);\n\n // Sample all rows (or first 100 for performance)\n const sample_rows = data.slice(0, 100);\n\n for (const row of sample_rows) {\n for (let col = 0; col < num_cols; col++) {\n const cell_value = String(row[col] || '');\n const text_width = font.widthOfTextAtSize(cell_value, font_size) + padding;\n col_widths[col] = Math.max(col_widths[col], Math.min(text_width, max_col_width));\n }\n }\n\n return col_widths;\n}\n\n/**\n * Truncate text to fit within a given width\n * @param text - Text to truncate\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param max_width - Maximum width in points\n * @returns Truncated text with ellipsis if needed\n */\nfunction truncate_text(\n text: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n max_width: number\n): string {\n if (font.widthOfTextAtSize(text, font_size) <= max_width) {\n return text;\n }\n\n const ellipsis = '...';\n let truncated = text;\n\n while (truncated.length > 0) {\n truncated = truncated.slice(0, -1);\n if (font.widthOfTextAtSize(truncated + ellipsis, font_size) <= max_width) {\n return truncated + ellipsis;\n }\n }\n\n return ellipsis;\n}\n\n/**\n * Convert GIF or WebP images to PNG using canvas\n * This is needed because pdf-lib only natively supports JPEG and PNG\n * @param image_bytes - Raw image data\n * @param mime_type - Original MIME type\n * @returns PNG bytes as Uint8Array\n */\nasync function convert_image_via_canvas(\n image_bytes: Uint8Array,\n mime_type: string\n): Promise<Uint8Array> {\n // This function requires browser environment\n if (typeof document === 'undefined' || typeof Image === 'undefined') {\n throw new Error('Image conversion requires browser environment (canvas support)');\n }\n\n return new Promise((resolve, reject) => {\n // Create blob URL from image bytes\n // Create new Uint8Array to ensure proper ArrayBuffer type for Blob constructor\n const blob = new Blob([new Uint8Array(image_bytes)], { type: mime_type });\n const url = URL.createObjectURL(blob);\n\n // Load image\n const img = new Image();\n img.onload = () => {\n try {\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = img.width;\n canvas.height = img.height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get canvas 2D context');\n }\n\n ctx.drawImage(img, 0, 0);\n\n // Export as PNG\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to convert image to PNG'));\n return;\n }\n\n blob.arrayBuffer().then((buffer) => {\n resolve(new Uint8Array(buffer));\n }).catch(reject);\n }, 'image/png');\n\n // Clean up\n URL.revokeObjectURL(url);\n } catch (error) {\n URL.revokeObjectURL(url);\n reject(error);\n }\n };\n\n img.onerror = () => {\n URL.revokeObjectURL(url);\n reject(new Error('Failed to load image for conversion'));\n };\n\n img.src = url;\n });\n}\n\n/**\n * Wrap text to fit within a given width\n * @param text - Text to wrap\n * @param font - pdf-lib font object\n * @param font_size - Font size in points\n * @param max_width - Maximum line width in points\n * @returns Array of lines\n */\nfunction wrap_text(\n text: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n font: any,\n font_size: number,\n max_width: number\n): string[] {\n const lines: string[] = [];\n\n // Split by explicit line breaks first\n const paragraphs = text.split(/\\r?\\n/);\n\n for (const paragraph of paragraphs) {\n if (paragraph.trim() === '') {\n // Preserve empty lines\n lines.push('');\n continue;\n }\n\n const words = paragraph.split(/\\s+/);\n let current_line = '';\n\n for (const word of words) {\n const test_line = current_line ? `${current_line} ${word}` : word;\n const width = font.widthOfTextAtSize(test_line, font_size);\n\n if (width <= max_width) {\n current_line = test_line;\n } else {\n if (current_line) {\n lines.push(current_line);\n }\n\n // Check if the word itself is too long and needs to be broken\n if (font.widthOfTextAtSize(word, font_size) > max_width) {\n // Break the word character by character\n let char_line = '';\n for (const char of word) {\n const test_char_line = char_line + char;\n if (font.widthOfTextAtSize(test_char_line, font_size) <= max_width) {\n char_line = test_char_line;\n } else {\n if (char_line) {\n lines.push(char_line);\n }\n char_line = char;\n }\n }\n current_line = char_line;\n } else {\n current_line = word;\n }\n }\n }\n\n if (current_line) {\n lines.push(current_line);\n }\n }\n\n return lines;\n}\n","/**\n * File Access Middleware\n * Provides abstraction for loading and saving PDF files\n * Supports both direct fetch (default) and hazo_files integration\n */\n\nimport type { FileAccessProvider } from '../types/file_access';\nimport { get_logger } from './logger';\n\n/**\n * Load PDF data from a source (URL or hazo_files path)\n * @param source - URL or path to the PDF file\n * @param file_manager - Optional hazo_files FileAccessProvider for remote storage\n * @returns Promise with ArrayBuffer containing PDF data\n */\nexport async function load_pdf_data(\n source: string,\n file_manager?: FileAccessProvider\n): Promise<ArrayBuffer> {\n const logger = get_logger();\n\n // If file_manager is provided and initialized, use it\n if (file_manager && file_manager.isInitialized()) {\n logger.debug(`[file_access_middleware] Loading PDF via hazo_files: ${source}`);\n\n const result = await file_manager.downloadFile(source);\n\n if (!result.success || !result.data) {\n const error_msg = result.error || 'Unknown error loading file';\n logger.error(`[file_access_middleware] Failed to load PDF via hazo_files: ${error_msg}`);\n throw new Error(`Failed to load PDF from storage: ${error_msg}`);\n }\n\n // Convert data to ArrayBuffer\n // Handle Buffer (Node.js), ArrayBuffer, or Uint8Array\n const data = result.data;\n if (data instanceof ArrayBuffer) {\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files, size: ${data.byteLength} bytes`);\n return data;\n } else if (data instanceof Uint8Array) {\n // Uint8Array - get the underlying ArrayBuffer\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files (Uint8Array), size: ${data.byteLength} bytes`);\n return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);\n } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(data)) {\n // Node.js Buffer - convert to ArrayBuffer\n logger.debug(`[file_access_middleware] PDF loaded via hazo_files (Buffer), size: ${data.length} bytes`);\n return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);\n }\n\n throw new Error('Unexpected data type from file manager');\n }\n\n // Default: use fetch\n logger.debug(`[file_access_middleware] Loading PDF via fetch: ${source}`);\n\n const response = await fetch(source);\n if (!response.ok) {\n throw new Error(`Failed to fetch PDF: ${response.status} ${response.statusText}`);\n }\n\n const array_buffer = await response.arrayBuffer();\n logger.debug(`[file_access_middleware] PDF loaded via fetch, size: ${array_buffer.byteLength} bytes`);\n\n return array_buffer;\n}\n\n/**\n * Save PDF data to remote storage via hazo_files\n * @param pdf_bytes - PDF data as Uint8Array\n * @param remote_path - Destination path in remote storage\n * @param file_manager - hazo_files FileAccessProvider\n * @param overwrite - Whether to overwrite existing file (default: true)\n * @returns Promise with save result\n */\nexport async function save_pdf_data(\n pdf_bytes: Uint8Array,\n remote_path: string,\n file_manager: FileAccessProvider,\n overwrite: boolean = true\n): Promise<{ success: boolean; error?: string }> {\n const logger = get_logger();\n\n if (!file_manager.isInitialized()) {\n logger.error('[file_access_middleware] File manager not initialized');\n return { success: false, error: 'File manager not initialized' };\n }\n\n logger.debug(`[file_access_middleware] Saving PDF via hazo_files: ${remote_path} (${pdf_bytes.byteLength} bytes)`);\n\n try {\n // Convert Uint8Array to Buffer if in Node.js environment\n // or pass as-is if Buffer is not available (browser)\n let source: Buffer | Uint8Array = pdf_bytes;\n if (typeof Buffer !== 'undefined') {\n source = Buffer.from(pdf_bytes);\n }\n\n const result = await file_manager.uploadFile(source, remote_path, { overwrite });\n\n if (!result.success) {\n logger.error(`[file_access_middleware] Failed to save PDF: ${result.error}`);\n return { success: false, error: result.error };\n }\n\n logger.info(`[file_access_middleware] PDF saved successfully: ${remote_path}`);\n return { success: true };\n } catch (error) {\n const error_msg = error instanceof Error ? error.message : String(error);\n logger.error(`[file_access_middleware] Error saving PDF: ${error_msg}`);\n return { success: false, error: error_msg };\n }\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useCallback","Undo2","X","document","useState","useRef","useEffect","useRef","useEffect","jsx","useRef","useEffect","useState","useRef","jsx","jsxs","useState","useRef","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useEffect","useState","useEffect","useRef","createPortal","Fragment","jsx","jsxs","useState","useRef","useEffect","createPortal","useState","useRef","useEffect","ChevronDown","X","Fragment","jsx","jsxs","useState","useRef","useEffect","ChevronDown","X","useState","useRef","useEffect","ChevronLeft","ChevronRight","ChevronDown","ChevronUp","Fragment","jsx","jsxs","useState","useRef","useEffect","ChevronLeft","ChevronRight","ChevronUp","ChevronDown","useState","useCallback","useEffect","useRef","useState","useEffect","useCallback","ChevronLeft","ChevronRight","useState","X","FileText","jsx","jsxs","useState","FileText","X","Fragment","jsx","jsxs","useRef","useState","useEffect","useCallback","ChevronLeft","ChevronRight","useState","useRef","useCallback","X","Loader2","jsx","jsxs","Loader2","jsx","jsxs","useState","useRef","useCallback","X","useState","jsx","jsxs","useState","blob","jsx","jsxs","useState","useEffect","useCallback","Fragment","jsx","jsxs","useState","useEffect","useRef","useCallback","error","logger","document","Undo2","final_text","X"]}