hazo_pdf 1.6.2 → 1.6.4

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
@@ -879,6 +879,7 @@ You can override any or all of these on a per-highlight basis.
879
879
  |------|------|---------|-------------|
880
880
  | `className` | `string` | `""` | Additional CSS classes to apply to the viewer container. |
881
881
  | `scale` | `number` | `1.0` | Initial zoom level. Values > 1.0 zoom in, < 1.0 zoom out. |
882
+ | `fit_to_width` | `boolean` | `false` | If `true`, automatically scales the PDF to fit the container width. Manual zoom buttons override auto-scaling. Container must have explicit dimensions. |
882
883
  | `background_color` | `string` | `"#2d2d2d"` | Background color for areas outside PDF pages (hex format: `#RRGGBB`). Overrides config file value. |
883
884
  | `config_file` | `string` | `undefined` | Path to configuration INI file (e.g., `"config/hazo_pdf_config.ini"`). If not provided, uses default configuration. |
884
885
  | `logger` | `Logger` | `undefined` | Logger instance from hazo_logs or custom logger matching the Logger interface. If not provided, falls back to console-based logging. Useful for debugging and monitoring PDF operations. |
@@ -1319,6 +1320,28 @@ The PDF viewer includes a toolbar at the top with the following controls:
1319
1320
  - Click "Reset" to return to default zoom
1320
1321
  - Zoom affects the PDF page size but maintains aspect ratio
1321
1322
 
1323
+ ### Fit-to-Width Mode
1324
+
1325
+ Enable automatic width-based scaling with the `fit_to_width` prop:
1326
+
1327
+ ```tsx
1328
+ <PdfViewer
1329
+ url="/document.pdf"
1330
+ fit_to_width={true}
1331
+ />
1332
+ ```
1333
+
1334
+ **Behavior:**
1335
+ - When enabled, the PDF automatically scales to fit the container width on initial load and after window resize
1336
+ - User can manually zoom in/out with zoom buttons, which disables auto-scaling for that session
1337
+ - Changing the `fit_to_width` prop value re-enables auto-scaling behavior
1338
+ - Use case: Viewing documents where full-width display is preferred (e.g., forms, contracts)
1339
+
1340
+ **Technical Notes:**
1341
+ - Does not conflict with the `scale` prop (scale is the initial value, fit_to_width can override it after render)
1342
+ - Manual zoom buttons override fit-to-width mode, allowing users to adjust as needed
1343
+ - Container must have explicit width and height (see [Container Requirements](#container-requirements))
1344
+
1322
1345
  ### Annotation Tools
1323
1346
 
1324
1347
  - **Square button**: Activates square/rectangle annotation tool
@@ -657,7 +657,7 @@ var AnnotationOverlay = ({
657
657
  e.stopPropagation();
658
658
  e.nativeEvent.stopImmediatePropagation();
659
659
  log_annotation_click(annotation, "svg_hit_test", point);
660
- on_annotation_click(annotation, point.x, point.y);
660
+ on_annotation_click(annotation, point.x, point.y, e.clientX, e.clientY);
661
661
  return;
662
662
  }
663
663
  }
@@ -673,7 +673,7 @@ var AnnotationOverlay = ({
673
673
  e.preventDefault();
674
674
  e.stopPropagation();
675
675
  if (on_freetext_click) {
676
- on_freetext_click(point.x, point.y);
676
+ on_freetext_click(point.x, point.y, e.clientX, e.clientY);
677
677
  }
678
678
  return;
679
679
  }
@@ -906,7 +906,7 @@ var AnnotationOverlay = ({
906
906
  const click_x = e.clientX - rect.left;
907
907
  const click_y = e.clientY - rect.top;
908
908
  log_annotation_click(annotation, "freetext_rect", { x: click_x, y: click_y });
909
- on_annotation_click(annotation, click_x, click_y);
909
+ on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);
910
910
  }
911
911
  },
912
912
  onClick: (e) => {
@@ -1020,7 +1020,7 @@ var AnnotationOverlay = ({
1020
1020
  const click_x = e.clientX - rect.left;
1021
1021
  const click_y = e.clientY - rect.top;
1022
1022
  log_annotation_click(annotation, "rect_overlay", { x: click_x, y: click_y });
1023
- on_annotation_click(annotation, click_x, click_y);
1023
+ on_annotation_click(annotation, click_x, click_y, e.clientX, e.clientY);
1024
1024
  }
1025
1025
  },
1026
1026
  onClick: (e) => {
@@ -1349,14 +1349,14 @@ var PdfViewerLayout = ({
1349
1349
  on_context_menu(e, index, screen_x, screen_y, mapper_data.mapper);
1350
1350
  }
1351
1351
  },
1352
- on_annotation_click: (annotation, screen_x, screen_y) => {
1352
+ on_annotation_click: (annotation, screen_x, screen_y, viewport_x, viewport_y) => {
1353
1353
  if (on_annotation_click && mapper_data.mapper) {
1354
- on_annotation_click(annotation, screen_x, screen_y, mapper_data.mapper);
1354
+ on_annotation_click(annotation, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);
1355
1355
  }
1356
1356
  },
1357
- on_freetext_click: (screen_x, screen_y) => {
1357
+ on_freetext_click: (screen_x, screen_y, viewport_x, viewport_y) => {
1358
1358
  if (on_freetext_click && mapper_data.mapper) {
1359
- on_freetext_click(index, screen_x, screen_y, mapper_data.mapper);
1359
+ on_freetext_click(index, screen_x, screen_y, mapper_data.mapper, viewport_x, viewport_y);
1360
1360
  }
1361
1361
  }
1362
1362
  }
@@ -4611,6 +4611,7 @@ var PdfViewer = forwardRef(({
4611
4611
  }, []);
4612
4612
  const content_container_ref = useRef11(null);
4613
4613
  const [first_page_width, setFirstPageWidth] = useState13(null);
4614
+ const [fit_to_width_active, setFitToWidthActive] = useState13(fit_to_width);
4614
4615
  useEffect10(() => {
4615
4616
  if (files && files.length > 0) {
4616
4617
  if (!current_file || !files.find((f) => f.id === current_file.id)) {
@@ -4994,7 +4995,10 @@ ${suffix_line}`;
4994
4995
  });
4995
4996
  }, [pdf_document]);
4996
4997
  useEffect10(() => {
4997
- if (!fit_to_width || !first_page_width || !content_container_ref.current) {
4998
+ setFitToWidthActive(fit_to_width);
4999
+ }, [fit_to_width]);
5000
+ useEffect10(() => {
5001
+ if (!fit_to_width_active || !first_page_width || !content_container_ref.current) {
4998
5002
  return;
4999
5003
  }
5000
5004
  const calculate_fit_scale = () => {
@@ -5003,9 +5007,7 @@ ${suffix_line}`;
5003
5007
  const padding = 40;
5004
5008
  const available_width = container_width - padding;
5005
5009
  const new_scale = Math.max(0.1, Math.min(3, available_width / first_page_width));
5006
- if (Math.abs(new_scale - scale) > 0.01) {
5007
- setScale(new_scale);
5008
- }
5010
+ setScale(new_scale);
5009
5011
  };
5010
5012
  calculate_fit_scale();
5011
5013
  const resize_observer = new ResizeObserver(() => {
@@ -5015,7 +5017,7 @@ ${suffix_line}`;
5015
5017
  return () => {
5016
5018
  resize_observer.disconnect();
5017
5019
  };
5018
- }, [fit_to_width, first_page_width, scale]);
5020
+ }, [fit_to_width_active, first_page_width]);
5019
5021
  const save_to_history = (new_annotations) => {
5020
5022
  if (history_ref.current.saving) {
5021
5023
  return;
@@ -5161,13 +5163,19 @@ ${suffix_line}`;
5161
5163
  };
5162
5164
  }, [handle_undo, handle_redo]);
5163
5165
  const handle_zoom_in = () => {
5166
+ setFitToWidthActive(false);
5164
5167
  setScale((prev) => Math.min(prev + 0.25, 3));
5165
5168
  };
5166
5169
  const handle_zoom_out = () => {
5170
+ setFitToWidthActive(false);
5167
5171
  setScale((prev) => Math.max(prev - 0.25, 0.5));
5168
5172
  };
5169
5173
  const handle_zoom_reset = () => {
5170
- setScale(1);
5174
+ if (fit_to_width) {
5175
+ setFitToWidthActive(true);
5176
+ } else {
5177
+ setScale(1);
5178
+ }
5171
5179
  };
5172
5180
  const normalize_rotation = (rotation) => {
5173
5181
  let normalized = rotation % 360;
@@ -6015,18 +6023,17 @@ ${suffix_line}`;
6015
6023
  page_rotations,
6016
6024
  on_visible_page_change: handle_visible_page_change,
6017
6025
  on_annotation_create: handle_annotation_create,
6018
- on_annotation_click: (annotation, screen_x, screen_y, mapper) => {
6026
+ on_annotation_click: (annotation, screen_x, screen_y, mapper, viewport_x, viewport_y) => {
6019
6027
  console.log(
6020
6028
  `\u{1F7E0} [AnnotationClick] opening editor id=${annotation.id}, page=${annotation.page_index}, screen=(${screen_x.toFixed(
6021
6029
  1
6022
6030
  )}, ${screen_y.toFixed(1)})`
6023
6031
  );
6024
- const dialog_x = window.innerWidth / 2;
6025
- const dialog_y = Math.max(50, screen_y);
6032
+ const dialog_y = Math.max(50, viewport_y);
6026
6033
  setTextDialog({
6027
6034
  open: true,
6028
6035
  page_index: annotation.page_index,
6029
- x: dialog_x,
6036
+ x: viewport_x,
6030
6037
  y: dialog_y,
6031
6038
  screen_x,
6032
6039
  screen_y,
@@ -6047,12 +6054,12 @@ ${suffix_line}`;
6047
6054
  mapper
6048
6055
  });
6049
6056
  },
6050
- on_freetext_click: (page_index, screen_x, screen_y, mapper) => {
6057
+ on_freetext_click: (page_index, screen_x, screen_y, mapper, viewport_x, viewport_y) => {
6051
6058
  setTextDialog({
6052
6059
  open: true,
6053
6060
  page_index,
6054
- x: screen_x,
6055
- y: screen_y,
6061
+ x: viewport_x,
6062
+ y: viewport_y,
6056
6063
  screen_x,
6057
6064
  screen_y,
6058
6065
  mapper
@@ -6308,4 +6315,4 @@ export {
6308
6315
  PdfViewer,
6309
6316
  pdf_viewer_default
6310
6317
  };
6311
- //# sourceMappingURL=chunk-ETZ57VO7.js.map
6318
+ //# sourceMappingURL=chunk-EPV2C5AQ.js.map