hazo_pdf 1.1.0 → 1.2.1

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/README.md CHANGED
@@ -19,6 +19,47 @@ A React component library for viewing and annotating PDF documents with support
19
19
  npm install hazo_pdf
20
20
  ```
21
21
 
22
+ ## CSS Import Options
23
+
24
+ The library provides two CSS files to choose from:
25
+
26
+ ### For apps with existing styles (Recommended)
27
+
28
+ Use `styles.css` - this does NOT include Tailwind preflight/base resets, so it won't interfere with your existing styles:
29
+
30
+ ```tsx
31
+ import 'hazo_pdf/styles.css';
32
+ ```
33
+
34
+ ### For standalone apps
35
+
36
+ Use `styles-full.css` - includes Tailwind preflight/base styles for apps without existing CSS resets:
37
+
38
+ ```tsx
39
+ import 'hazo_pdf/styles-full.css';
40
+ ```
41
+
42
+ ## Container Requirements
43
+
44
+ The PDF viewer requires its parent container to have explicit dimensions:
45
+
46
+ ```tsx
47
+ // Good - explicit dimensions
48
+ <div style={{ width: '100%', height: '600px' }}>
49
+ <PdfViewer url="/document.pdf" />
50
+ </div>
51
+
52
+ // Bad - no explicit height
53
+ <div>
54
+ <PdfViewer url="/document.pdf" />
55
+ </div>
56
+ ```
57
+
58
+ **Requirements:**
59
+ - Parent must have explicit `width` and `height` (CSS or inline style)
60
+ - Recommended minimum size: 400x400px
61
+ - Parent should NOT have `overflow: hidden` (the viewer handles its own scrolling)
62
+
22
63
  ## Quick Start
23
64
 
24
65
  ```tsx
@@ -307,7 +348,7 @@ function ProductionViewer() {
307
348
  <div style={{ flex: 1, overflow: 'hidden' }}>
308
349
  <PdfViewer
309
350
  url="/api/documents/contract.pdf"
310
- config_file="hazo_pdf_config.ini"
351
+ config_file="config/hazo_pdf_config.ini"
311
352
  className="h-full w-full"
312
353
  scale={initialScale}
313
354
  annotations={annotations}
@@ -327,7 +368,7 @@ function ProductionViewer() {
327
368
  ```
328
369
 
329
370
  **Features demonstrated:**
330
- - Configuration file integration (`hazo_pdf_config.ini`)
371
+ - Configuration file integration (`config/hazo_pdf_config.ini`)
331
372
  - Custom stamps with styling
332
373
  - Timestamp and fixed text suffixes
333
374
  - Responsive scaling based on screen size
@@ -340,7 +381,7 @@ function ProductionViewer() {
340
381
 
341
382
  ## Configuration File
342
383
 
343
- The PDF viewer can be configured via an INI file (default: `hazo_pdf_config.ini`). This allows you to customize styling, colors, fonts, and behavior without modifying code.
384
+ The PDF viewer can be configured via an INI file (default: `config/hazo_pdf_config.ini`). This allows you to customize styling, colors, fonts, and behavior without modifying code.
344
385
 
345
386
  **Basic setup:**
346
387
 
@@ -357,11 +398,18 @@ freetext_background_opacity = 0.1
357
398
  freetext_border_color = #003366
358
399
  freetext_border_width = 1
359
400
 
401
+ [toolbar]
402
+ toolbar_background_color = rgb(240, 248, 255)
403
+ toolbar_font_color = rgb(30, 58, 138)
404
+ toolbar_button_background_color = rgb(219, 234, 254)
405
+ toolbar_button_text_color = rgb(30, 64, 175)
406
+ toolbar_button_save_background_color = rgb(34, 197, 94)
407
+
360
408
  [context_menu]
361
409
  right_click_custom_stamps = [{"name":"Verified","text":"✅","order":1,"time_stamp_suffix_enabled":true,"fixed_text_suffix_enabled":true}]
362
410
  ```
363
411
 
364
- See `hazo_pdf_config.ini` in the project root for all available configuration options.
412
+ See `config/hazo_pdf_config.ini` in the project root for all available configuration options.
365
413
 
366
414
  ---
367
415
 
@@ -384,7 +432,7 @@ See `hazo_pdf_config.ini` in the project root for all available configuration op
384
432
  | `className` | `string` | `""` | Additional CSS classes to apply to the viewer container. |
385
433
  | `scale` | `number` | `1.0` | Initial zoom level. Values > 1.0 zoom in, < 1.0 zoom out. |
386
434
  | `background_color` | `string` | `"#2d2d2d"` | Background color for areas outside PDF pages (hex format: `#RRGGBB`). Overrides config file value. |
387
- | `config_file` | `string` | `undefined` | Path to configuration INI file (e.g., `"hazo_pdf_config.ini"`). If not provided, uses default configuration. |
435
+ | `config_file` | `string` | `undefined` | Path to configuration INI file (e.g., `"config/hazo_pdf_config.ini"`). If not provided, uses default configuration. |
388
436
 
389
437
  ##### Event Callbacks
390
438
 
@@ -462,12 +510,50 @@ const stamps = JSON.stringify([
462
510
  }
463
511
  ]);
464
512
 
465
- <PdfViewer
513
+ <PdfViewer
466
514
  url="/document.pdf"
467
515
  right_click_custom_stamps={stamps}
468
516
  />
469
517
  ```
470
518
 
519
+ ##### Toolbar Visibility
520
+
521
+ Props to control toolbar button visibility. These override config file values.
522
+
523
+ | Prop | Type | Default | Description |
524
+ |------|------|---------|-------------|
525
+ | `toolbar_enabled` | `boolean` | `true` | Master toggle to show/hide the entire toolbar. |
526
+ | `show_zoom_controls` | `boolean` | `true` | Show zoom in/out/reset buttons. |
527
+ | `show_square_button` | `boolean` | `true` | Show square annotation button. |
528
+ | `show_undo_button` | `boolean` | `true` | Show undo button. |
529
+ | `show_redo_button` | `boolean` | `true` | Show redo button. |
530
+ | `show_save_button` | `boolean` | `true` | Show save button. |
531
+ | `show_metadata_button` | `boolean` | `true` | Show metadata panel button (only visible when `sidepanel_metadata_enabled` is true). |
532
+ | `on_close` | `() => void` | `undefined` | Callback when close button is clicked. When provided, shows a close button (X) in the toolbar. Useful for modal/dialog usage. |
533
+
534
+ **Example - Minimal toolbar:**
535
+
536
+ ```tsx
537
+ <PdfViewer
538
+ url="/document.pdf"
539
+ toolbar_enabled={true}
540
+ show_zoom_controls={true}
541
+ show_square_button={false}
542
+ show_undo_button={false}
543
+ show_redo_button={false}
544
+ show_save_button={false}
545
+ />
546
+ ```
547
+
548
+ **Example - Dialog with close button:**
549
+
550
+ ```tsx
551
+ <PdfViewer
552
+ url="/document.pdf"
553
+ on_close={() => setDialogOpen(false)}
554
+ />
555
+ ```
556
+
471
557
  ### PdfAnnotation Interface
472
558
 
473
559
  Represents a PDF annotation in the standard PDF coordinate space.
@@ -497,6 +583,72 @@ Type from `pdfjs-dist`. Contains PDF metadata and page proxies.
497
583
 
498
584
  ---
499
585
 
586
+ ## Toolbar Configuration
587
+
588
+ The toolbar can be fully customized via the `[toolbar]` section in the configuration file. You can configure:
589
+
590
+ - **Colors**: Background, border, font, and button colors (background, hover, active, save)
591
+ - **Fonts**: Font family and size for toolbar text
592
+ - **Visibility**: Show/hide individual button groups (zoom, square, undo, redo, save)
593
+ - **Labels**: Customize all button labels and text
594
+
595
+ **All toolbar settings with defaults:**
596
+
597
+ | Setting | Type | Default | Description |
598
+ |---------|------|---------|-------------|
599
+ | `toolbar_background_color` | Color | `#f9fafb` | Toolbar background color |
600
+ | `toolbar_border_color` | Color | `#e5e7eb` | Toolbar border color |
601
+ | `toolbar_font_family` | String | `system-ui, -apple-system, sans-serif` | Font family for toolbar |
602
+ | `toolbar_font_size` | Number | `14` | Font size in pixels |
603
+ | `toolbar_font_color` | Color | `#111827` | Text color for toolbar |
604
+ | `toolbar_button_background_color` | Color | `#ffffff` | Regular button background |
605
+ | `toolbar_button_background_color_hover` | Color | `#f3f4f6` | Button hover background |
606
+ | `toolbar_button_text_color` | Color | `#374151` | Button text color |
607
+ | `toolbar_button_active_background_color` | Color | `#3b82f6` | Active button background |
608
+ | `toolbar_button_active_text_color` | Color | `#ffffff` | Active button text color |
609
+ | `toolbar_button_save_background_color` | Color | `#10b981` | Save button background |
610
+ | `toolbar_button_save_background_color_hover` | Color | `#059669` | Save button hover background |
611
+ | `toolbar_button_save_text_color` | Color | `#ffffff` | Save button text color |
612
+ | `toolbar_button_disabled_opacity` | Number | `0.5` | Opacity for disabled buttons (0.0-1.0) |
613
+ | `toolbar_show_zoom_controls` | Boolean | `true` | Show zoom controls |
614
+ | `toolbar_show_square_button` | Boolean | `true` | Show square annotation button |
615
+ | `toolbar_show_undo_button` | Boolean | `true` | Show undo button |
616
+ | `toolbar_show_redo_button` | Boolean | `true` | Show redo button |
617
+ | `toolbar_show_save_button` | Boolean | `true` | Show save button |
618
+ | `toolbar_show_metadata_button` | Boolean | `true` | Show metadata panel button (only shown when sidepanel is enabled) |
619
+ | `toolbar_zoom_out_label` | String | `"−"` | Zoom out button label |
620
+ | `toolbar_zoom_in_label` | String | `"+"` | Zoom in button label |
621
+ | `toolbar_zoom_reset_label` | String | `"Reset"` | Reset zoom button label |
622
+ | `toolbar_square_label` | String | `"Square"` | Square button label |
623
+ | `toolbar_undo_label` | String | `"Undo"` | Undo button label |
624
+ | `toolbar_redo_label` | String | `"Redo"` | Redo button label |
625
+ | `toolbar_save_label` | String | `"Save"` | Save button label |
626
+ | `toolbar_saving_label` | String | `"Saving..."` | Saving button label |
627
+ | `toolbar_metadata_label` | String | `"Metadata"` | Metadata panel button label |
628
+
629
+ **Example configuration:**
630
+
631
+ ```ini
632
+ [toolbar]
633
+ # Customize colors
634
+ toolbar_background_color = rgb(240, 248, 255)
635
+ toolbar_border_color = rgb(59, 130, 246)
636
+ toolbar_font_color = rgb(30, 58, 138)
637
+ toolbar_button_background_color = rgb(219, 234, 254)
638
+ toolbar_button_text_color = rgb(30, 64, 175)
639
+ toolbar_button_active_background_color = rgb(37, 99, 235)
640
+ toolbar_button_save_background_color = rgb(34, 197, 94)
641
+
642
+ # Hide some controls
643
+ toolbar_show_redo_button = false
644
+ toolbar_show_square_button = false
645
+ toolbar_show_metadata_button = false
646
+
647
+ # Customize labels
648
+ toolbar_save_label = Save PDF
649
+ toolbar_undo_label = ← Undo
650
+ ```
651
+
500
652
  ## Toolbar Controls
501
653
 
502
654
  The PDF viewer includes a toolbar at the top with the following controls:
@@ -73,6 +73,38 @@ var default_config = {
73
73
  dialog_button_cancel_color: "#6b7280",
74
74
  dialog_button_cancel_color_hover: "#4b5563",
75
75
  dialog_button_disabled_opacity: 0.4
76
+ },
77
+ toolbar: {
78
+ toolbar_background_color: "#f9fafb",
79
+ toolbar_border_color: "#e5e7eb",
80
+ toolbar_font_family: "system-ui, -apple-system, sans-serif",
81
+ toolbar_font_size: 14,
82
+ toolbar_font_color: "#111827",
83
+ toolbar_button_background_color: "#ffffff",
84
+ toolbar_button_background_color_hover: "#f3f4f6",
85
+ toolbar_button_text_color: "#374151",
86
+ toolbar_button_active_background_color: "#3b82f6",
87
+ toolbar_button_active_text_color: "#ffffff",
88
+ toolbar_button_save_background_color: "#10b981",
89
+ toolbar_button_save_background_color_hover: "#059669",
90
+ toolbar_button_save_text_color: "#ffffff",
91
+ toolbar_button_disabled_opacity: 0.5,
92
+ toolbar_show_zoom_controls: true,
93
+ toolbar_show_square_button: true,
94
+ toolbar_show_undo_button: true,
95
+ toolbar_show_redo_button: true,
96
+ toolbar_show_save_button: true,
97
+ toolbar_show_metadata_button: true,
98
+ toolbar_show_annotate_button: true,
99
+ toolbar_zoom_out_label: "\u2212",
100
+ toolbar_zoom_in_label: "+",
101
+ toolbar_zoom_reset_label: "Reset",
102
+ toolbar_square_label: "Square",
103
+ toolbar_undo_label: "Undo",
104
+ toolbar_redo_label: "Redo",
105
+ toolbar_save_label: "Save",
106
+ toolbar_saving_label: "Saving...",
107
+ toolbar_metadata_label: "Metadata"
76
108
  }
77
109
  };
78
110
 
@@ -280,4 +312,4 @@ export {
280
312
  download_pdf,
281
313
  save_and_download_pdf
282
314
  };
283
- //# sourceMappingURL=chunk-2POHPGR3.js.map
315
+ //# sourceMappingURL=chunk-S3AJUZ7D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/default_config.ts","../src/utils/pdf_saver.ts"],"sourcesContent":["/**\n * Default configuration values for hazo_pdf\n * All styling defaults organized by category\n */\n\nimport type { PdfViewerConfig } from '../types/config';\n\n/**\n * Default PDF Viewer Configuration\n * These values are used when no config file is provided or when values are missing\n */\nexport const default_config: PdfViewerConfig = {\n fonts: {\n freetext_font_family: 'Arial, sans-serif',\n freetext_font_size_min: 12,\n freetext_font_size_max: 24,\n freetext_font_size_default: 14,\n font_foreground_color: '#000000', // Black by default\n },\n\n highlight_annotation: {\n highlight_fill_color: '#FFFF00',\n highlight_fill_opacity: 0.3,\n highlight_border_color: '#FFD700',\n highlight_border_color_hover: '#FFD700',\n highlight_fill_opacity_hover: 0.4,\n },\n\n square_annotation: {\n square_fill_color: '#FF0000',\n square_fill_opacity: 0.2,\n square_border_color: '#FF0000',\n square_border_color_hover: '#CC0000',\n square_fill_opacity_hover: 0.3,\n },\n\n freetext_annotation: {\n freetext_text_color: '#000000',\n freetext_text_color_hover: '#000000',\n freetext_border_color: '#003366',\n freetext_border_width: 1,\n freetext_background_color: '#E6F3FF',\n freetext_background_opacity: 0.1,\n freetext_font_weight: 'normal',\n freetext_font_style: 'normal',\n freetext_text_decoration: 'none',\n freetext_padding_horizontal: 4,\n freetext_padding_vertical: 2,\n },\n\n page_styling: {\n page_border_color: '#999999',\n page_box_shadow: '0 2px 8px rgba(0, 0, 0, 0.3)',\n page_background_color: '#ffffff',\n },\n\n viewer: {\n viewer_background_color: '#2d2d2d',\n append_timestamp_to_text_edits: false,\n annotation_text_suffix_fixed_text: '',\n add_enclosing_brackets_to_suffixes: true,\n suffix_enclosing_brackets: '[]',\n suffix_text_position: 'below_multi_line',\n },\n\n context_menu: {\n context_menu_background_color: '#ffffff',\n context_menu_border_color: '#d1d5db',\n context_menu_item_hover_background: '#f3f4f6',\n context_menu_item_disabled_opacity: 0.5,\n right_click_custom_stamps: '', // Empty string means no custom stamps\n },\n\n dialog: {\n dialog_backdrop_opacity: 0.2,\n dialog_background_color: '#ffffff',\n dialog_border_color: '#d1d5db',\n dialog_button_submit_color: '#16a34a',\n dialog_button_submit_color_hover: '#15803d',\n dialog_button_cancel_color: '#6b7280',\n dialog_button_cancel_color_hover: '#4b5563',\n dialog_button_disabled_opacity: 0.4,\n },\n\n toolbar: {\n toolbar_background_color: '#f9fafb',\n toolbar_border_color: '#e5e7eb',\n toolbar_font_family: 'system-ui, -apple-system, sans-serif',\n toolbar_font_size: 14,\n toolbar_font_color: '#111827',\n toolbar_button_background_color: '#ffffff',\n toolbar_button_background_color_hover: '#f3f4f6',\n toolbar_button_text_color: '#374151',\n toolbar_button_active_background_color: '#3b82f6',\n toolbar_button_active_text_color: '#ffffff',\n toolbar_button_save_background_color: '#10b981',\n toolbar_button_save_background_color_hover: '#059669',\n toolbar_button_save_text_color: '#ffffff',\n toolbar_button_disabled_opacity: 0.5,\n toolbar_show_zoom_controls: true,\n toolbar_show_square_button: true,\n toolbar_show_undo_button: true,\n toolbar_show_redo_button: true,\n toolbar_show_save_button: true,\n toolbar_show_metadata_button: true,\n toolbar_show_annotate_button: true,\n toolbar_zoom_out_label: '−',\n toolbar_zoom_in_label: '+',\n toolbar_zoom_reset_label: 'Reset',\n toolbar_square_label: 'Square',\n toolbar_undo_label: 'Undo',\n toolbar_redo_label: 'Redo',\n toolbar_save_label: 'Save',\n toolbar_saving_label: 'Saving...',\n toolbar_metadata_label: 'Metadata',\n },\n};\n","/**\n * PDF Saver Utility\n * Saves annotations directly into PDF documents using pdf-lib\n * This allows annotations to be embedded in the PDF file itself\n */\n\nimport type { PdfAnnotation, PdfViewerConfig } from '../types';\nimport { default_config } from '../config/default_config';\n\n/**\n * Save annotations into a PDF document\n * This function fetches the PDF, adds annotations, and downloads the modified PDF\n * @param pdf_url - URL of the PDF file\n * @param annotations - Array of annotations to save\n * @param output_filename - Name for the saved PDF file (default: original filename with '_annotated' suffix)\n * @param config - Optional configuration for styling values\n * @returns Promise that resolves when the PDF is saved\n */\nexport async function save_annotations_to_pdf(\n pdf_url: string,\n annotations: PdfAnnotation[],\n _output_filename?: string, // Currently unused, kept for API compatibility\n config?: PdfViewerConfig | null\n): Promise<Uint8Array> {\n try {\n // Dynamically import pdf-lib\n const { PDFDocument, rgb } = await import('pdf-lib');\n \n // Fetch the original PDF\n console.log('[PDF Saver] Fetching PDF from:', pdf_url);\n const pdf_response = await fetch(pdf_url);\n if (!pdf_response.ok) {\n throw new Error(`Failed to fetch PDF: ${pdf_response.status} ${pdf_response.statusText}`);\n }\n \n const pdf_bytes = await pdf_response.arrayBuffer();\n console.log('[PDF Saver] PDF fetched, size:', pdf_bytes.byteLength, 'bytes');\n \n // Load the PDF document\n const pdf_doc = await PDFDocument.load(pdf_bytes);\n console.log('[PDF Saver] PDF loaded, pages:', pdf_doc.getPageCount());\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 // Add annotations to each page\n for (const annotation of annotations) {\n if (annotation.page_index >= pdf_doc.getPageCount()) {\n console.warn(`[PDF Saver] Annotation ${annotation.id} references page ${annotation.page_index}, but PDF only has ${pdf_doc.getPageCount()} pages. Skipping.`);\n continue;\n }\n \n const page = pdf_doc.getPage(annotation.page_index);\n const [x1, y1, x2, y2] = annotation.rect;\n \n // PDF coordinate system: bottom-left is origin (pdfjs-dist)\n // pdf-lib uses bottom-left as origin too, so coordinates should be fine\n // But we need to ensure rect is normalized\n const rect_x = Math.min(x1, x2);\n const rect_y = Math.min(y1, y2);\n const rect_width = Math.abs(x2 - x1);\n const rect_height = Math.abs(y2 - y1);\n \n // Parse color (hex or rgb to RGB for pdf-lib)\n // Supports both hex (#RRGGBB) and rgb(r, g, b) formats\n let color = rgb(0, 0, 0); // Default black\n if (annotation.color) {\n const color_str = annotation.color.trim();\n \n // Handle rgb(r, g, b) format\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = color_str.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) and convert to 0-1 range for pdf-lib\n if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {\n color = rgb(r / 255, g / 255, b / 255);\n } else {\n console.warn(`[PDF Saver] Invalid RGB values for annotation ${annotation.id}: r=${r}, g=${g}, b=${b}`);\n }\n } else if (color_str.startsWith('#')) {\n // Handle hex format (#RRGGBB)\n const hex = color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n const r = parseInt(hex.substring(0, 2), 16) / 255;\n const g = parseInt(hex.substring(2, 4), 16) / 255;\n const b = parseInt(hex.substring(4, 6), 16) / 255;\n color = rgb(r, g, b);\n } else {\n console.warn(`[PDF Saver] Invalid hex color format for annotation ${annotation.id}: ${color_str}`);\n }\n } else {\n console.warn(`[PDF Saver] Unrecognized color format for annotation ${annotation.id}: ${color_str}`);\n }\n }\n \n // Create annotation based on type using pdf-lib's annotation methods\n try {\n switch (annotation.type) {\n case 'Square': {\n // Create a rectangle/square annotation\n page.drawRectangle({\n x: rect_x,\n y: rect_y,\n width: rect_width,\n height: rect_height,\n borderColor: color,\n borderWidth: 2,\n borderOpacity: 0.8,\n });\n \n // Add text comment if present\n if (annotation.contents) {\n const comment_color_str = (annotation.color || square_config.square_border_color).trim();\n let comment_r = 0, comment_g = 0, comment_b = 0;\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = comment_color_str.match(rgb_pattern);\n if (rgb_match) {\n comment_r = parseInt(rgb_match[1], 10) / 255;\n comment_g = parseInt(rgb_match[2], 10) / 255;\n comment_b = parseInt(rgb_match[3], 10) / 255;\n } else if (comment_color_str.startsWith('#')) {\n const hex = comment_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n comment_r = parseInt(hex.substring(0, 2), 16) / 255;\n comment_g = parseInt(hex.substring(2, 4), 16) / 255;\n comment_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n \n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y + rect_height + 5,\n size: fonts_config.freetext_font_size_default,\n color: rgb(comment_r, comment_g, comment_b),\n });\n }\n break;\n }\n \n case 'Highlight': {\n // Create a highlight annotation (semi-transparent rectangle)\n const highlight_color_str = (annotation.color || highlight_config.highlight_fill_color).trim();\n let highlight_r = 255 / 255, highlight_g = 255 / 255, highlight_b = 0 / 255; // Default yellow\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = highlight_color_str.match(rgb_pattern);\n if (rgb_match) {\n highlight_r = parseInt(rgb_match[1], 10) / 255;\n highlight_g = parseInt(rgb_match[2], 10) / 255;\n highlight_b = parseInt(rgb_match[3], 10) / 255;\n } else if (highlight_color_str.startsWith('#')) {\n const hex = highlight_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n highlight_r = parseInt(hex.substring(0, 2), 16) / 255;\n highlight_g = parseInt(hex.substring(2, 4), 16) / 255;\n highlight_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n const highlight_color = rgb(highlight_r, highlight_g, highlight_b);\n \n page.drawRectangle({\n x: rect_x,\n y: rect_y,\n width: rect_width,\n height: rect_height,\n color: highlight_color,\n opacity: highlight_config.highlight_fill_opacity,\n });\n \n // Add text comment if present\n if (annotation.contents) {\n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y + rect_height + 5,\n size: fonts_config.freetext_font_size_default,\n color: rgb(0, 0, 0),\n });\n }\n break;\n }\n \n case 'FreeText': {\n // Create a free text annotation\n if (annotation.contents) {\n // Text color priority: annotation.color > freetext_text_color > font_foreground_color > default black\n const text_color_str = (annotation.color || \n freetext_config.freetext_text_color || \n fonts_config.font_foreground_color || \n '#000000').trim();\n let text_r = 0, text_g = 0, text_b = 0;\n \n // Parse color (hex or rgb format)\n const rgb_pattern = /^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i;\n const rgb_match = text_color_str.match(rgb_pattern);\n if (rgb_match) {\n text_r = parseInt(rgb_match[1], 10) / 255;\n text_g = parseInt(rgb_match[2], 10) / 255;\n text_b = parseInt(rgb_match[3], 10) / 255;\n } else if (text_color_str.startsWith('#')) {\n const hex = text_color_str.slice(1).trim();\n if (hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex)) {\n text_r = parseInt(hex.substring(0, 2), 16) / 255;\n text_g = parseInt(hex.substring(2, 4), 16) / 255;\n text_b = parseInt(hex.substring(4, 6), 16) / 255;\n }\n }\n \n page.drawText(annotation.contents, {\n x: rect_x,\n y: rect_y,\n size: fonts_config.freetext_font_size_default,\n color: rgb(text_r, text_g, text_b),\n maxWidth: rect_width,\n });\n }\n break;\n }\n \n default:\n console.warn(`[PDF Saver] Unsupported annotation type: ${annotation.type}`);\n }\n } catch (annotation_error) {\n console.error(`[PDF Saver] Error adding annotation ${annotation.id}:`, annotation_error);\n // Continue with other annotations\n }\n }\n \n // Save the PDF\n const modified_pdf_bytes = await pdf_doc.save();\n console.log('[PDF Saver] PDF modified, size:', modified_pdf_bytes.length, 'bytes');\n \n return modified_pdf_bytes;\n } catch (error) {\n if (error && typeof error === 'object' && 'message' in error && \n typeof error.message === 'string' && error.message.includes('pdf-lib')) {\n throw new Error('pdf-lib is required to save annotations to PDF. Please install it: npm install pdf-lib');\n }\n console.error('[PDF Saver] Error saving PDF:', error);\n throw error;\n }\n}\n\n/**\n * Download PDF bytes as a file\n * @param pdf_bytes - PDF file bytes\n * @param filename - Name for the downloaded file\n */\nexport function download_pdf(pdf_bytes: Uint8Array, filename: string): void {\n // Create a new ArrayBuffer view to ensure compatibility with Blob constructor\n // Uint8Array.buffer can be SharedArrayBuffer, which Blob doesn't accept directly\n const buffer = new Uint8Array(pdf_bytes).buffer;\n const blob = new Blob([buffer], { type: 'application/pdf' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\n/**\n * Save annotations to PDF and download\n * @param pdf_url - URL of the PDF file\n * @param annotations - Array of annotations to save\n * @param output_filename - Name for the saved PDF file (default: original filename with '_annotated' suffix)\n * @param config - Optional configuration for styling values\n */\nexport async function save_and_download_pdf(\n pdf_url: string,\n annotations: PdfAnnotation[],\n output_filename?: string,\n config?: PdfViewerConfig | null\n): Promise<void> {\n const pdf_bytes = await save_annotations_to_pdf(pdf_url, annotations, output_filename, config);\n \n // Generate output filename\n const original_filename = pdf_url.split('/').pop() || 'document.pdf';\n const filename_without_ext = original_filename.replace(/\\.pdf$/i, '');\n const final_filename = output_filename || `${filename_without_ext}_annotated.pdf`;\n \n // Download the modified PDF\n download_pdf(pdf_bytes, final_filename);\n console.log('[PDF Saver] PDF saved as:', final_filename);\n}\n\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -127,6 +127,68 @@ interface PdfViewerConfig {
127
127
  /** Opacity for disabled dialog buttons (0.0 to 1.0) */
128
128
  dialog_button_disabled_opacity: number;
129
129
  };
130
+ toolbar: {
131
+ /** Background color for toolbar (hex format: #RRGGBB or rgb(r, g, b)) */
132
+ toolbar_background_color: string;
133
+ /** Border color for toolbar (hex format: #RRGGBB or rgb(r, g, b)) */
134
+ toolbar_border_color: string;
135
+ /** Font family for toolbar text */
136
+ toolbar_font_family: string;
137
+ /** Font size for toolbar text (pixels) */
138
+ toolbar_font_size: number;
139
+ /** Font color for toolbar text (hex format: #RRGGBB or rgb(r, g, b)) */
140
+ toolbar_font_color: string;
141
+ /** Button background color (hex format: #RRGGBB or rgb(r, g, b)) */
142
+ toolbar_button_background_color: string;
143
+ /** Button background color on hover (hex format: #RRGGBB or rgb(r, g, b)) */
144
+ toolbar_button_background_color_hover: string;
145
+ /** Button text color (hex format: #RRGGBB or rgb(r, g, b)) */
146
+ toolbar_button_text_color: string;
147
+ /** Active button background color (hex format: #RRGGBB or rgb(r, g, b)) */
148
+ toolbar_button_active_background_color: string;
149
+ /** Active button text color (hex format: #RRGGBB or rgb(r, g, b)) */
150
+ toolbar_button_active_text_color: string;
151
+ /** Save button background color (hex format: #RRGGBB or rgb(r, g, b)) */
152
+ toolbar_button_save_background_color: string;
153
+ /** Save button background color on hover (hex format: #RRGGBB or rgb(r, g, b)) */
154
+ toolbar_button_save_background_color_hover: string;
155
+ /** Save button text color (hex format: #RRGGBB or rgb(r, g, b)) */
156
+ toolbar_button_save_text_color: string;
157
+ /** Disabled button opacity (0.0 to 1.0) */
158
+ toolbar_button_disabled_opacity: number;
159
+ /** Whether to show zoom controls (true/false) */
160
+ toolbar_show_zoom_controls: boolean;
161
+ /** Whether to show square annotation button (true/false) */
162
+ toolbar_show_square_button: boolean;
163
+ /** Whether to show undo button (true/false) */
164
+ toolbar_show_undo_button: boolean;
165
+ /** Whether to show redo button (true/false) */
166
+ toolbar_show_redo_button: boolean;
167
+ /** Whether to show save button (true/false) */
168
+ toolbar_show_save_button: boolean;
169
+ /** Whether to show metadata panel button (true/false) */
170
+ toolbar_show_metadata_button: boolean;
171
+ /** Whether to show annotate (FreeText) button (true/false) */
172
+ toolbar_show_annotate_button: boolean;
173
+ /** Label for zoom out button (default: "−") */
174
+ toolbar_zoom_out_label: string;
175
+ /** Label for zoom in button (default: "+") */
176
+ toolbar_zoom_in_label: string;
177
+ /** Label for reset zoom button (default: "Reset") */
178
+ toolbar_zoom_reset_label: string;
179
+ /** Label for square annotation button (default: "Square") */
180
+ toolbar_square_label: string;
181
+ /** Label for undo button (default: "Undo") */
182
+ toolbar_undo_label: string;
183
+ /** Label for redo button (default: "Redo") */
184
+ toolbar_redo_label: string;
185
+ /** Label for save button (default: "Save") */
186
+ toolbar_save_label: string;
187
+ /** Label for saving button (default: "Saving...") */
188
+ toolbar_saving_label: string;
189
+ /** Label for metadata panel button (default: "Metadata") */
190
+ toolbar_metadata_label: string;
191
+ };
130
192
  }
131
193
 
132
194
  /**
@@ -160,7 +222,7 @@ interface PdfViewerProps {
160
222
  on_save?: (pdf_bytes: Uint8Array, filename: string) => void;
161
223
  /** Background color for areas outside PDF pages (default: dark grey) */
162
224
  background_color?: string;
163
- /** Optional path to configuration INI file (e.g., "hazo_pdf_config.ini") */
225
+ /** Optional path to configuration INI file (e.g., "config/hazo_pdf_config.ini") */
164
226
  config_file?: string;
165
227
  /** Whether to append timestamp to annotated text edits (default: false) */
166
228
  append_timestamp_to_text_edits?: boolean;
@@ -181,6 +243,24 @@ interface PdfViewerProps {
181
243
  updatedRow: MetadataDataItem;
182
244
  allData: MetadataInput;
183
245
  };
246
+ /** Whether to show the toolbar at all (default: true) */
247
+ toolbar_enabled?: boolean;
248
+ /** Whether to show zoom controls (default: true) */
249
+ show_zoom_controls?: boolean;
250
+ /** Whether to show square annotation button (default: true) */
251
+ show_square_button?: boolean;
252
+ /** Whether to show undo button (default: true) */
253
+ show_undo_button?: boolean;
254
+ /** Whether to show redo button (default: true) */
255
+ show_redo_button?: boolean;
256
+ /** Whether to show save button (default: true) */
257
+ show_save_button?: boolean;
258
+ /** Whether to show metadata panel button (default: true, only visible when sidepanel_metadata_enabled) */
259
+ show_metadata_button?: boolean;
260
+ /** Whether to show annotate (FreeText) button (default: true) */
261
+ show_annotate_button?: boolean;
262
+ /** Callback when close button is clicked (shows close button in toolbar when provided) */
263
+ on_close?: () => void;
184
264
  }
185
265
  /**
186
266
  * PDF Annotation interface matching PDF standard
@@ -353,6 +433,7 @@ interface PdfViewerLayoutProps {
353
433
  on_annotation_create: (annotation: PdfAnnotation) => void;
354
434
  on_context_menu: (e: React.MouseEvent, page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper) => void;
355
435
  on_annotation_click: (annotation: PdfAnnotation, screen_x: number, screen_y: number, mapper: CoordinateMapper) => void;
436
+ on_freetext_click?: (page_index: number, screen_x: number, screen_y: number, mapper: CoordinateMapper) => void;
356
437
  background_color?: string;
357
438
  config: PdfViewerConfig | null;
358
439
  className?: string;
@@ -419,6 +500,8 @@ interface AnnotationOverlayProps {
419
500
  on_context_menu?: (event: React.MouseEvent, screen_x: number, screen_y: number) => void;
420
501
  /** Callback when annotation is clicked */
421
502
  on_annotation_click?: (annotation: PdfAnnotation, screen_x: number, screen_y: number) => void;
503
+ /** Callback when FreeText tool is active and user clicks on empty area */
504
+ on_freetext_click?: (screen_x: number, screen_y: number) => void;
422
505
  /** Configuration object for styling */
423
506
  config?: PdfViewerConfig | null;
424
507
  /** Optional class name */