hazo_pdf 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/chunk-2POHPGR3.js +283 -0
- package/dist/chunk-2POHPGR3.js.map +1 -0
- package/dist/index.d.ts +593 -0
- package/dist/index.js +2815 -0
- package/dist/index.js.map +1 -0
- package/dist/pdf_saver-D2H5SLPN.js +12 -0
- package/dist/pdf_saver-D2H5SLPN.js.map +1 -0
- package/dist/styles/index.css +1789 -0
- package/dist/styles/index.css.map +1 -0
- package/package.json +94 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/pdf_viewer/pdf_viewer.tsx","../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/utils/cn.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/utils/config_loader.ts","../src/utils/xfdf_generator.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 React, { useState, useEffect, useRef, useCallback } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { Save, Undo2, Redo2 } from 'lucide-react';\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 type { PdfViewerProps, PdfAnnotation, CoordinateMapper, PdfViewerConfig, CustomStamp } 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';\n\n/**\n * PDF Viewer Component\n * Main entry point for PDF viewing and annotation\n */\nexport const PdfViewer: React.FC<PdfViewerProps> = ({\n url,\n className = '',\n scale: initial_scale = 1.0,\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}) => {\n const [pdf_document, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<Error | 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 \n // Load configuration from file\n const config_ref = useRef<PdfViewerConfig | null>(null);\n \n // Load config once on mount\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 console.log('[PdfViewer] 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 console.warn(`[PdfViewer] Could not load config file \"${config_file}\", using defaults:`, error);\n config_ref.current = load_pdf_config(); // Use defaults\n });\n } else {\n // Node.js: use hazo_config (preferred method)\n config_ref.current = load_pdf_config(config_file);\n console.log('[PdfViewer] 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 // 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 console.warn('[PdfViewer] 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 console.warn('[PdfViewer] 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 console.log('[PdfViewer] 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 console.log('[PdfViewer] 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 console.log('[PdfViewer] 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 }, [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 (!url) {\n console.warn('PdfViewer: No URL provided');\n return;\n }\n\n setLoading(true);\n setError(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(() => {\n load_pdf_document(url)\n .then((document) => {\n setPdfDocument(document);\n setLoading(false);\n if (on_load) {\n on_load(document);\n }\n })\n .catch((err) => {\n console.error('PdfViewer: Error loading PDF:', 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 }, [url, on_load, on_error]);\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 const new_annotations = [...annotations, annotation];\n setAnnotations(new_annotations);\n save_to_history(new_annotations);\n if (on_annotation_create) {\n on_annotation_create(annotation);\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 // 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\n const handle_zoom_in = () => {\n setScale((prev) => Math.min(prev + 0.25, 3.0));\n };\n\n const handle_zoom_out = () => {\n setScale((prev) => Math.max(prev - 0.25, 0.5));\n };\n\n const handle_zoom_reset = () => {\n setScale(1.0);\n };\n\n // Handle save annotations to PDF\n const handle_save = async () => {\n if (annotations.length === 0) {\n console.warn('PdfViewer: No annotations to save');\n return;\n }\n\n if (!url) {\n console.error('PdfViewer: No PDF URL available for saving');\n return;\n }\n\n setSaving(true);\n try {\n // Generate output filename\n const original_filename = 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 // Save annotations to PDF and get the modified bytes\n const pdf_bytes = await save_annotations_to_pdf(url, annotations, output_filename, config_ref.current);\n \n // Download the modified PDF\n download_pdf(pdf_bytes, output_filename);\n\n // If callback is provided, call it with the modified PDF bytes\n if (on_save) {\n on_save(pdf_bytes, output_filename);\n }\n } catch (error) {\n console.error('PdfViewer: 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 // 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\n if (!pdf_document) {\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 return (\n <div className={cn('cls_pdf_viewer', className)}>\n {/* Toolbar */}\n <div className=\"cls_pdf_viewer_toolbar\">\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 >\n −\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 >\n +\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 >\n Reset\n </button>\n </div>\n\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={() => setCurrentTool('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 >\n Square\n </button>\n </div>\n\n <div className=\"cls_pdf_viewer_toolbar_group\">\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 >\n <Undo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n <span className=\"cls_pdf_viewer_toolbar_button_text\">Undo</span>\n </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 >\n <Redo2 className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n <span className=\"cls_pdf_viewer_toolbar_button_text\">Redo</span>\n </button>\n </div>\n\n <div className=\"cls_pdf_viewer_toolbar_group\">\n <button\n type=\"button\"\n onClick={handle_save}\n disabled={saving || annotations.length === 0}\n className={cn(\n 'cls_pdf_viewer_toolbar_button',\n 'cls_pdf_viewer_toolbar_button_save',\n (saving || annotations.length === 0) && 'cls_pdf_viewer_toolbar_button_disabled'\n )}\n aria-label=\"Save annotations to PDF\"\n title={annotations.length === 0 ? 'No annotations to save' : 'Save annotations to PDF'}\n >\n <Save className=\"cls_pdf_viewer_toolbar_icon\" size={16} />\n <span className=\"cls_pdf_viewer_toolbar_button_text\">\n {saving ? 'Saving...' : 'Save'}\n </span>\n </button>\n </div>\n </div>\n\n {/* PDF Viewer Layout */}\n <div className=\"cls_pdf_viewer_content\">\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 on_annotation_create={handle_annotation_create}\n on_annotation_click={(annotation, screen_x, screen_y, mapper) => {\n console.log(\n `🟠 [AnnotationClick] opening editor id=${annotation.id}, page=${annotation.page_index}, screen=(${screen_x.toFixed(\n 1\n )}, ${screen_y.toFixed(1)})`\n );\n const dialog_x = window.innerWidth / 2; // Center horizontally\n const dialog_y = Math.max(50, screen_y); // Position near annotation, but at least 50px from top\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: dialog_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 />\n </div>\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 </div>\n );\n};\n\nexport default PdfViewer;\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';\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 // 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 console.log(`[PDF Worker] 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 console.error('[PDF Worker] Error configuring worker:', 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 // Dynamic import of getDocument - direct import() for bundler compatibility\n const pdfjs_module = await import('pdfjs-dist');\n const { getDocument } = pdfjs_module;\n \n console.log('[PDF Loader] Loading PDF from:', 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 console.log('[PDF Loader] Fetching local PDF file as ArrayBuffer:', 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 console.log('[PDF Loader] PDF fetched successfully, size:', pdfData.byteLength, 'bytes');\n } catch (fetchError) {\n console.error('[PDF Loader] Error fetching PDF as ArrayBuffer, trying URL directly:', 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 console.log('[PDF Loader] PDF loaded successfully:', document.numPages, 'pages');\n return document;\n } catch (error) {\n console.error('[PDF Loader] Error loading PDF:', 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';\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) => void;\n background_color?: string;\n config: PdfViewerConfig | null;\n className?: string;\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 background_color = '#2d2d2d',\n config = null,\n className = '',\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 \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 // 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 console.error('[PdfViewerLayout] Error loading PDF pages:', 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 console.log(\n `🟢 [AnnotationClick] layout received 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\n return (\n <div\n key={index}\n className=\"cls_pdf_viewer_page_wrapper\"\n style={{\n position: 'relative',\n marginBottom: '20px',\n display: 'flex',\n justifyContent: 'center',\n // Inherit cursor from parent (grab/grabbing in pan mode)\n cursor: 'inherit',\n // Ensure page wrapper doesn't constrain width\n width: 'auto',\n minWidth: 'fit-content',\n }}\n >\n {/* PDF Page Renderer */}\n <PdfPageRenderer\n page={page}\n page_index={index}\n scale={scale}\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) => {\n if (on_annotation_click && mapper_data.mapper) {\n on_annotation_click(annotation, screen_x, screen_y, mapper_data.mapper);\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';\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 /** 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 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 or scale changes)\n const viewport_dimensions = useMemo(() => {\n if (!page) return { width: 0, height: 0 };\n const viewport = page.getViewport({ scale });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n }, [page, scale]);\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);\n }, [page, scale]);\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\n const viewport = page.getViewport({ scale });\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 console.error(`[PdfPageRenderer] 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 // Render the page\n const render_context = {\n canvasContext: context,\n viewport: viewport,\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 console.error(`[PdfPageRenderer] Page ${page_index}: Error rendering:`, 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, 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 margin: '0 auto',\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: '100%',\n height: '100%',\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 and scale\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @returns CoordinateMapper with to_pdf and to_screen methods\n */\nexport function create_coordinate_mapper(\n page: PDFPageProxy,\n scale: number\n): CoordinateMapper {\n const viewport = page.getViewport({ scale });\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\n * @param page - PDF page proxy\n * @param scale - Zoom/scale factor\n * @returns Object with width and height in screen pixels\n */\nexport function get_viewport_dimensions(\n page: PDFPageProxy,\n scale: number\n): { width: number; height: number } {\n const viewport = page.getViewport({ scale });\n return {\n width: viewport.width,\n height: viewport.height,\n };\n}\n\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 * 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';\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 */\n on_annotation_click?: (annotation: PdfAnnotation, screen_x: number, screen_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 config = null,\n className = '',\n}) => {\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 console.log(\n `🟢 [AnnotationClick] origin=${origin}, id=${annotation.id}, page=${annotation.page_index}, screen=(${point.x.toFixed(\n 1\n )}, ${point.y.toFixed(1)})`\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 and screen coordinates\n log_annotation_click(annotation, 'svg_hit_test', point);\n on_annotation_click(annotation, point.x, point.y);\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 console.warn(`⚠️ [AnnotationOverlay] 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 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 console.warn('[AnnotationOverlay] Could not get SVG bounding rect');\n return;\n }\n \n if (!on_context_menu) {\n console.warn('[AnnotationOverlay] 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 console.warn(`[FreeText] Invalid RGB values: r=${r}, g=${g}, b=${b} (must be 0-255)`);\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 console.warn(`[FreeText] Invalid hex color format: ${trimmed}`);\n return 'transparent';\n }\n \n console.warn(`[FreeText] Unrecognized color format: ${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);\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 // Use annotation color if provided, otherwise use config\n const highlight_color = annotation.color || highlight_config.highlight_fill_color;\n return {\n fill: hex_to_rgba(highlight_color, highlight_config.highlight_fill_opacity),\n stroke: highlight_config.highlight_border_color,\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 };\n default:\n return {\n fill: 'rgba(0, 0, 255, 0.2)',\n stroke: '#0000FF',\n };\n }\n };\n\n const { fill, stroke } = 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);\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=\"2\"\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';\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 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 console.log(`🟡 [ContextMenu] Position debug: render=${render_count_ref.current}, expected=(${x}, ${y}), actual=(${rect.left.toFixed(1)}, ${rect.top.toFixed(1)}), offset=(${x_offset.toFixed(1)}, ${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 console.log('[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 console.log(`⚪ [ContextMenu] Render call: render=${render_count_ref.current}, props=(${x}, ${y}), adjusted=(${adjusted_position.x}, ${adjusted_position.y}), mounted=${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 * 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';\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 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 (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 === 'hazo_pdf_config.ini' || config_file.includes('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 console.log('[ConfigLoader] Parsed config sections:', Object.keys(parsed));\n if (parsed['fonts']) {\n console.log('[ConfigLoader] fonts section:', parsed['fonts']);\n }\n if (parsed['freetext_annotation']) {\n console.log('[ConfigLoader] freetext_annotation section:', parsed['freetext_annotation']);\n }\n if (parsed['viewer']) {\n console.log('[ConfigLoader] viewer section:', parsed['viewer']);\n } else {\n console.warn('[ConfigLoader] 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 console.log('[ConfigLoader] Final config values:');\n console.log(' font_foreground_color:', config.fonts.font_foreground_color);\n console.log(' freetext_text_color:', config.freetext_annotation.freetext_text_color);\n console.log(' freetext_background_color:', config.freetext_annotation.freetext_background_color);\n console.log(' freetext_background_opacity:', config.freetext_annotation.freetext_background_opacity);\n console.log(' append_timestamp_to_text_edits:', config.viewer.append_timestamp_to_text_edits);\n console.log(' annotation_text_suffix_fixed_text:', config.viewer.annotation_text_suffix_fixed_text);\n \n // Debug: Log viewer section parsing\n const raw_value = get_value('viewer', 'append_timestamp_to_text_edits');\n console.log('[ConfigLoader] append_timestamp_to_text_edits:');\n console.log(' raw_value from INI:', raw_value, '(type:', typeof raw_value, ')');\n console.log(' parsed boolean:', config.viewer.append_timestamp_to_text_edits);\n console.log(' parse_boolean test:', parse_boolean(raw_value, false));\n \n // Also log all viewer keys for debugging\n if (parsed['viewer']) {\n console.log('[ConfigLoader] All viewer section keys:', Object.keys(parsed['viewer']));\n console.log('[ConfigLoader] All viewer section values:', parsed['viewer']);\n }\n \n return config;\n } catch (error) {\n console.warn(`[ConfigLoader] Could not load config file \"${config_file}\" in browser, using defaults:`, 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 // 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 console.log(`[ConfigLoader] 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 console.log(`[ConfigLoader] Successfully loaded config using hazo_config from: ${config_file}`);\n return config;\n } catch (error) {\n console.warn(\n `[ConfigLoader] Could not load config file \"${config_file}\" using hazo_config, using defaults:`,\n error instanceof Error ? error.message : String(error)\n );\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 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 console.log(`[ConfigLoader] 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 console.warn(\n `[ConfigLoader] suffix_enclosing_brackets must be 2 characters, received \"${raw_value}\". Using default.`\n );\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 console.warn(\n `[ConfigLoader] Invalid suffix_text_position \"${raw_value}\". Using default \"${default_config.viewer.suffix_text_position}\".`\n );\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}\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 console.warn(`[ConfigLoader] 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 console.warn(`[ConfigLoader] 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 console.warn(`[ConfigLoader] 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 console.warn(`[ConfigLoader] 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 // If no config file specified, return defaults\n if (!config_file) {\n console.log('[ConfigLoader] 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 console.warn('[ConfigLoader] 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 console.log(`[ConfigLoader] 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 console.warn(\n `[ConfigLoader] Could not load config file \"${config_file}\", using defaults:`,\n error instanceof Error ? error.message : String(error)\n );\n return default_config;\n }\n}\n","/**\n * XFDF Generator Utility\n * Converts annotation and bookmark data to XFDF (XML Forms Data Format)\n * XFDF is the standard format for PDF annotations\n */\n\nimport type { PdfAnnotation, PdfBookmark } from '../types';\n\n/**\n * Format date to PDF date format: D:YYYYMMDDhhmmss[Z+-hh'mm']\n * @param date - Date object or ISO string\n * @returns Formatted date string\n */\nfunction format_pdf_date(date: Date | string): string {\n let date_obj: Date;\n \n if (typeof date === 'string') {\n // Try to parse the date string\n date_obj = new Date(date);\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n console.warn(`Invalid date string: ${date}. Using current date.`);\n date_obj = new Date();\n }\n } else {\n date_obj = date;\n // Validate the date - if invalid, use current date\n if (isNaN(date_obj.getTime())) {\n console.warn(`Invalid date object. Using current date.`);\n date_obj = new Date();\n }\n }\n \n const year = date_obj.getFullYear();\n const month = String(date_obj.getMonth() + 1).padStart(2, '0');\n const day = String(date_obj.getDate()).padStart(2, '0');\n const hours = String(date_obj.getHours()).padStart(2, '0');\n const minutes = String(date_obj.getMinutes()).padStart(2, '0');\n const seconds = String(date_obj.getSeconds()).padStart(2, '0');\n \n // Get timezone offset\n const offset_minutes = date_obj.getTimezoneOffset();\n const offset_hours = Math.abs(Math.floor(offset_minutes / 60));\n const offset_mins = Math.abs(offset_minutes % 60);\n const offset_sign = offset_minutes <= 0 ? '+' : '-';\n \n return `D:${year}${month}${day}${hours}${minutes}${seconds}${offset_sign}${String(offset_hours).padStart(2, '0')}'${String(offset_mins).padStart(2, '0')}'`;\n}\n\n/**\n * Escape XML special characters\n * @param text - Text to escape\n * @returns Escaped text\n */\nfunction escape_xml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Convert annotation type to XFDF tag name\n * @param type - Annotation type\n * @returns XFDF tag name (lowercase)\n */\nfunction annotation_type_to_tag(type: PdfAnnotation['type']): string {\n return type.toLowerCase();\n}\n\n/**\n * Generate XFDF XML from annotations and bookmarks\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @returns XFDF XML string\n */\nexport function generate_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf'\n): string {\n // Start XML boilerplate\n let xfdf = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n`;\n xfdf += `<xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\\n`;\n xfdf += ` <f href=\"${escape_xml(pdf_file_name)}\"/>\\n`;\n\n // Add annotations\n if (annotations.length > 0) {\n xfdf += ` <annots>\\n`;\n\n annotations.forEach((ann) => {\n // Format rectangle coordinates\n const rect_string = ann.rect.map((c) => c.toFixed(2)).join(', ');\n\n // Format date - ensure it's valid\n let date_string: string;\n try {\n date_string = format_pdf_date(ann.date);\n } catch (error) {\n console.warn(`Error formatting date for annotation ${ann.id}:`, error);\n // Fallback to current date\n date_string = format_pdf_date(new Date());\n }\n\n // Get tag name\n const tag_name = annotation_type_to_tag(ann.type);\n\n // Build annotation attributes\n const attributes: string[] = [];\n attributes.push(`subject=\"${escape_xml(ann.subject || ann.type)}\"`);\n attributes.push(`page=\"${ann.page_index}\"`);\n attributes.push(`rect=\"${rect_string}\"`);\n attributes.push(`flags=\"print\"`);\n attributes.push(`name=\"${escape_xml(ann.id)}\"`);\n attributes.push(`title=\"${escape_xml(ann.author)}\"`);\n attributes.push(`date=\"${date_string}\"`);\n\n if (ann.color) {\n attributes.push(`color=\"${escape_xml(ann.color)}\"`);\n }\n\n // Build annotation element\n xfdf += ` <${tag_name} ${attributes.join(' ')}>\\n`;\n\n // Add contents if present\n if (ann.contents) {\n xfdf += ` <contents><![CDATA[${ann.contents}]]></contents>\\n`;\n }\n\n // Close annotation tag\n xfdf += ` </${tag_name}>\\n`;\n });\n\n xfdf += ` </annots>\\n`;\n }\n\n // Add bookmarks\n if (bookmarks.length > 0) {\n xfdf += ` <bookmarks>\\n`;\n\n bookmarks.forEach((bookmark) => {\n const attributes: string[] = [];\n attributes.push(`title=\"${escape_xml(bookmark.title)}\"`);\n attributes.push(`action=\"${bookmark.action || 'GoTo'}\"`);\n attributes.push(`page=\"${bookmark.page_index}\"`);\n\n if (bookmark.y !== undefined) {\n attributes.push(`y=\"${bookmark.y}\"`);\n }\n\n xfdf += ` <bookmark ${attributes.join(' ')} />\\n`;\n });\n\n xfdf += ` </bookmarks>\\n`;\n }\n\n // Close XFDF\n xfdf += `</xfdf>`;\n\n return xfdf;\n}\n\n/**\n * Download XFDF file\n * @param xfdf_content - XFDF XML content\n * @param file_name - Name for the downloaded file\n */\nexport function download_xfdf(xfdf_content: string, file_name: string = 'annotations.xfdf'): void {\n const blob = new Blob([xfdf_content], { type: 'application/vnd.adobe.xfdf' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = file_name;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Generate and download XFDF file\n * @param annotations - Array of annotations\n * @param bookmarks - Array of bookmarks (optional)\n * @param pdf_file_name - Name of the PDF file\n * @param file_name - Name for the downloaded file\n */\nexport function export_annotations_to_xfdf(\n annotations: PdfAnnotation[],\n bookmarks: PdfBookmark[] = [],\n pdf_file_name: string = 'document.pdf',\n file_name: string = 'annotations.xfdf'\n): void {\n const xfdf_content = generate_xfdf(annotations, bookmarks, pdf_file_name);\n download_xfdf(xfdf_content, file_name);\n}\n"],"mappings":"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","names":["useState","useEffect","useRef","useCallback","Undo2","document","useState","useRef","useEffect","useRef","jsx","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","Fragment","jsx","jsxs","useState","useRef","useEffect","error","document","useCallback","save_annotations_to_pdf","download_pdf","Undo2","final_text"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
download_pdf,
|
|
4
|
+
save_and_download_pdf,
|
|
5
|
+
save_annotations_to_pdf
|
|
6
|
+
} from "./chunk-2POHPGR3.js";
|
|
7
|
+
export {
|
|
8
|
+
download_pdf,
|
|
9
|
+
save_and_download_pdf,
|
|
10
|
+
save_annotations_to_pdf
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=pdf_saver-D2H5SLPN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|