react-pdf-highlighter-plus 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.
Files changed (99) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +411 -0
  3. package/dist/esm/components/AreaHighlight.d.ts +82 -0
  4. package/dist/esm/components/AreaHighlight.js +109 -0
  5. package/dist/esm/components/AreaHighlight.js.map +1 -0
  6. package/dist/esm/components/DrawingCanvas.d.ts +48 -0
  7. package/dist/esm/components/DrawingCanvas.js +277 -0
  8. package/dist/esm/components/DrawingCanvas.js.map +1 -0
  9. package/dist/esm/components/DrawingHighlight.d.ts +70 -0
  10. package/dist/esm/components/DrawingHighlight.js +164 -0
  11. package/dist/esm/components/DrawingHighlight.js.map +1 -0
  12. package/dist/esm/components/FreetextHighlight.d.ts +112 -0
  13. package/dist/esm/components/FreetextHighlight.js +193 -0
  14. package/dist/esm/components/FreetextHighlight.js.map +1 -0
  15. package/dist/esm/components/HighlightLayer.d.ts +49 -0
  16. package/dist/esm/components/HighlightLayer.js +37 -0
  17. package/dist/esm/components/HighlightLayer.js.map +1 -0
  18. package/dist/esm/components/ImageHighlight.d.ts +63 -0
  19. package/dist/esm/components/ImageHighlight.js +65 -0
  20. package/dist/esm/components/ImageHighlight.js.map +1 -0
  21. package/dist/esm/components/MonitoredHighlightContainer.d.ts +37 -0
  22. package/dist/esm/components/MonitoredHighlightContainer.js +42 -0
  23. package/dist/esm/components/MonitoredHighlightContainer.js.map +1 -0
  24. package/dist/esm/components/MouseMonitor.d.ts +34 -0
  25. package/dist/esm/components/MouseMonitor.js +30 -0
  26. package/dist/esm/components/MouseMonitor.js.map +1 -0
  27. package/dist/esm/components/MouseSelection.d.ts +66 -0
  28. package/dist/esm/components/MouseSelection.js +122 -0
  29. package/dist/esm/components/MouseSelection.js.map +1 -0
  30. package/dist/esm/components/PdfHighlighter.d.ts +184 -0
  31. package/dist/esm/components/PdfHighlighter.js +410 -0
  32. package/dist/esm/components/PdfHighlighter.js.map +1 -0
  33. package/dist/esm/components/PdfLoader.d.ts +55 -0
  34. package/dist/esm/components/PdfLoader.js +57 -0
  35. package/dist/esm/components/PdfLoader.js.map +1 -0
  36. package/dist/esm/components/ShapeCanvas.d.ts +51 -0
  37. package/dist/esm/components/ShapeCanvas.js +205 -0
  38. package/dist/esm/components/ShapeCanvas.js.map +1 -0
  39. package/dist/esm/components/ShapeHighlight.d.ts +107 -0
  40. package/dist/esm/components/ShapeHighlight.js +140 -0
  41. package/dist/esm/components/ShapeHighlight.js.map +1 -0
  42. package/dist/esm/components/SignaturePad.d.ts +40 -0
  43. package/dist/esm/components/SignaturePad.js +138 -0
  44. package/dist/esm/components/SignaturePad.js.map +1 -0
  45. package/dist/esm/components/TextHighlight.d.ts +93 -0
  46. package/dist/esm/components/TextHighlight.js +115 -0
  47. package/dist/esm/components/TextHighlight.js.map +1 -0
  48. package/dist/esm/components/TipContainer.d.ts +27 -0
  49. package/dist/esm/components/TipContainer.js +58 -0
  50. package/dist/esm/components/TipContainer.js.map +1 -0
  51. package/dist/esm/contexts/HighlightContext.d.ts +44 -0
  52. package/dist/esm/contexts/HighlightContext.js +16 -0
  53. package/dist/esm/contexts/HighlightContext.js.map +1 -0
  54. package/dist/esm/contexts/PdfHighlighterContext.d.ts +89 -0
  55. package/dist/esm/contexts/PdfHighlighterContext.js +16 -0
  56. package/dist/esm/contexts/PdfHighlighterContext.js.map +1 -0
  57. package/dist/esm/index.d.ts +19 -0
  58. package/dist/esm/index.js +19 -0
  59. package/dist/esm/index.js.map +1 -0
  60. package/dist/esm/lib/coordinates.d.ts +16 -0
  61. package/dist/esm/lib/coordinates.js +69 -0
  62. package/dist/esm/lib/coordinates.js.map +1 -0
  63. package/dist/esm/lib/export-pdf.d.ts +81 -0
  64. package/dist/esm/lib/export-pdf.js +511 -0
  65. package/dist/esm/lib/export-pdf.js.map +1 -0
  66. package/dist/esm/lib/get-bounding-rect.d.ts +3 -0
  67. package/dist/esm/lib/get-bounding-rect.js +35 -0
  68. package/dist/esm/lib/get-bounding-rect.js.map +1 -0
  69. package/dist/esm/lib/get-client-rects.d.ts +3 -0
  70. package/dist/esm/lib/get-client-rects.js +43 -0
  71. package/dist/esm/lib/get-client-rects.js.map +1 -0
  72. package/dist/esm/lib/group-highlights-by-page.d.ts +6 -0
  73. package/dist/esm/lib/group-highlights-by-page.js +23 -0
  74. package/dist/esm/lib/group-highlights-by-page.js.map +1 -0
  75. package/dist/esm/lib/optimize-client-rects.d.ts +3 -0
  76. package/dist/esm/lib/optimize-client-rects.js +65 -0
  77. package/dist/esm/lib/optimize-client-rects.js.map +1 -0
  78. package/dist/esm/lib/pdfjs-dom.d.ts +9 -0
  79. package/dist/esm/lib/pdfjs-dom.js +55 -0
  80. package/dist/esm/lib/pdfjs-dom.js.map +1 -0
  81. package/dist/esm/lib/screenshot.d.ts +4 -0
  82. package/dist/esm/lib/screenshot.js +24 -0
  83. package/dist/esm/lib/screenshot.js.map +1 -0
  84. package/dist/esm/style/AreaHighlight.css +134 -0
  85. package/dist/esm/style/DrawingCanvas.css +62 -0
  86. package/dist/esm/style/DrawingHighlight.css +184 -0
  87. package/dist/esm/style/FreetextHighlight.css +249 -0
  88. package/dist/esm/style/ImageHighlight.css +97 -0
  89. package/dist/esm/style/MouseSelection.css +15 -0
  90. package/dist/esm/style/PdfHighlighter.css +77 -0
  91. package/dist/esm/style/ShapeCanvas.css +47 -0
  92. package/dist/esm/style/ShapeHighlight.css +182 -0
  93. package/dist/esm/style/SignaturePad.css +83 -0
  94. package/dist/esm/style/TextHighlight.css +199 -0
  95. package/dist/esm/style/pdf_viewer.css +41 -0
  96. package/dist/esm/types.d.ts +213 -0
  97. package/dist/esm/types.js +2 -0
  98. package/dist/esm/types.js.map +1 -0
  99. package/package.json +91 -0
@@ -0,0 +1,138 @@
1
+ import React, { useRef, useEffect, useCallback } from "react";
2
+ import "../style/SignaturePad.css";
3
+ /**
4
+ * A modal component with a canvas for drawing signatures.
5
+ * Supports both mouse and touch input.
6
+ *
7
+ * @category Component
8
+ */
9
+ export const SignaturePad = ({ isOpen, onComplete, onClose, width = 400, height = 200, }) => {
10
+ const canvasRef = useRef(null);
11
+ const isDrawingRef = useRef(false);
12
+ const lastPosRef = useRef({ x: 0, y: 0 });
13
+ // Initialize canvas context
14
+ useEffect(() => {
15
+ if (!isOpen || !canvasRef.current)
16
+ return;
17
+ const canvas = canvasRef.current;
18
+ const ctx = canvas.getContext("2d");
19
+ if (!ctx)
20
+ return;
21
+ // Set up drawing style
22
+ ctx.strokeStyle = "#000000";
23
+ ctx.lineWidth = 2;
24
+ ctx.lineCap = "round";
25
+ ctx.lineJoin = "round";
26
+ // Clear canvas
27
+ ctx.fillStyle = "white";
28
+ ctx.fillRect(0, 0, width, height);
29
+ }, [isOpen, width, height]);
30
+ const getPosition = useCallback((e) => {
31
+ const canvas = canvasRef.current;
32
+ if (!canvas)
33
+ return { x: 0, y: 0 };
34
+ const rect = canvas.getBoundingClientRect();
35
+ let clientX;
36
+ let clientY;
37
+ if ("touches" in e) {
38
+ clientX = e.touches[0].clientX;
39
+ clientY = e.touches[0].clientY;
40
+ }
41
+ else {
42
+ clientX = e.clientX;
43
+ clientY = e.clientY;
44
+ }
45
+ return {
46
+ x: clientX - rect.left,
47
+ y: clientY - rect.top,
48
+ };
49
+ }, []);
50
+ const startDrawing = useCallback((e) => {
51
+ e.preventDefault();
52
+ isDrawingRef.current = true;
53
+ lastPosRef.current = getPosition(e);
54
+ }, [getPosition]);
55
+ const draw = useCallback((e) => {
56
+ if (!isDrawingRef.current)
57
+ return;
58
+ e.preventDefault();
59
+ const canvas = canvasRef.current;
60
+ const ctx = canvas?.getContext("2d");
61
+ if (!ctx)
62
+ return;
63
+ const currentPos = getPosition(e);
64
+ ctx.beginPath();
65
+ ctx.moveTo(lastPosRef.current.x, lastPosRef.current.y);
66
+ ctx.lineTo(currentPos.x, currentPos.y);
67
+ ctx.stroke();
68
+ lastPosRef.current = currentPos;
69
+ }, [getPosition]);
70
+ const stopDrawing = useCallback(() => {
71
+ isDrawingRef.current = false;
72
+ }, []);
73
+ // Set up event listeners
74
+ useEffect(() => {
75
+ if (!isOpen)
76
+ return;
77
+ const canvas = canvasRef.current;
78
+ if (!canvas)
79
+ return;
80
+ // Mouse events
81
+ const handleMouseDown = (e) => startDrawing(e);
82
+ const handleMouseMove = (e) => draw(e);
83
+ const handleMouseUp = () => stopDrawing();
84
+ const handleMouseLeave = () => stopDrawing();
85
+ // Touch events
86
+ const handleTouchStart = (e) => startDrawing(e);
87
+ const handleTouchMove = (e) => draw(e);
88
+ const handleTouchEnd = () => stopDrawing();
89
+ canvas.addEventListener("mousedown", handleMouseDown);
90
+ canvas.addEventListener("mousemove", handleMouseMove);
91
+ canvas.addEventListener("mouseup", handleMouseUp);
92
+ canvas.addEventListener("mouseleave", handleMouseLeave);
93
+ canvas.addEventListener("touchstart", handleTouchStart, { passive: false });
94
+ canvas.addEventListener("touchmove", handleTouchMove, { passive: false });
95
+ canvas.addEventListener("touchend", handleTouchEnd);
96
+ return () => {
97
+ canvas.removeEventListener("mousedown", handleMouseDown);
98
+ canvas.removeEventListener("mousemove", handleMouseMove);
99
+ canvas.removeEventListener("mouseup", handleMouseUp);
100
+ canvas.removeEventListener("mouseleave", handleMouseLeave);
101
+ canvas.removeEventListener("touchstart", handleTouchStart);
102
+ canvas.removeEventListener("touchmove", handleTouchMove);
103
+ canvas.removeEventListener("touchend", handleTouchEnd);
104
+ };
105
+ }, [isOpen, startDrawing, draw, stopDrawing]);
106
+ const handleClear = () => {
107
+ const canvas = canvasRef.current;
108
+ const ctx = canvas?.getContext("2d");
109
+ if (!ctx || !canvas)
110
+ return;
111
+ ctx.fillStyle = "white";
112
+ ctx.fillRect(0, 0, width, height);
113
+ };
114
+ const handleDone = () => {
115
+ const canvas = canvasRef.current;
116
+ if (!canvas)
117
+ return;
118
+ const dataUrl = canvas.toDataURL("image/png");
119
+ onComplete(dataUrl);
120
+ };
121
+ const handleOverlayClick = (e) => {
122
+ // Close if clicking the overlay background
123
+ if (e.target === e.currentTarget) {
124
+ onClose();
125
+ }
126
+ };
127
+ if (!isOpen)
128
+ return null;
129
+ return (React.createElement("div", { className: "SignaturePad__overlay", onClick: handleOverlayClick },
130
+ React.createElement("div", { className: "SignaturePad__modal" },
131
+ React.createElement("h3", { className: "SignaturePad__title" }, "Draw your signature"),
132
+ React.createElement("canvas", { ref: canvasRef, className: "SignaturePad__canvas", width: width, height: height }),
133
+ React.createElement("div", { className: "SignaturePad__buttons" },
134
+ React.createElement("button", { type: "button", className: "SignaturePad__button SignaturePad__button--clear", onClick: handleClear }, "Clear"),
135
+ React.createElement("button", { type: "button", className: "SignaturePad__button SignaturePad__button--cancel", onClick: onClose }, "Cancel"),
136
+ React.createElement("button", { type: "button", className: "SignaturePad__button SignaturePad__button--done", onClick: handleDone }, "Done")))));
137
+ };
138
+ //# sourceMappingURL=SignaturePad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignaturePad.js","sourceRoot":"","sources":["../../../src/components/SignaturePad.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import React, { CSSProperties, MouseEvent, ReactNode } from "react";
2
+ import "../style/TextHighlight.css";
3
+ import type { ViewportHighlight } from "../types";
4
+ /**
5
+ * Style options for text highlight appearance.
6
+ */
7
+ export interface TextHighlightStyle {
8
+ highlightColor?: string;
9
+ highlightStyle?: "highlight" | "underline" | "strikethrough";
10
+ }
11
+ /**
12
+ * The props type for {@link TextHighlight}.
13
+ *
14
+ * @category Component Properties
15
+ */
16
+ export interface TextHighlightProps {
17
+ /**
18
+ * Highlight to render over text.
19
+ */
20
+ highlight: ViewportHighlight;
21
+ /**
22
+ * Callback triggered whenever the user clicks on the part of a highlight.
23
+ *
24
+ * @param event - Mouse event associated with click.
25
+ */
26
+ onClick?(event: MouseEvent<HTMLDivElement>): void;
27
+ /**
28
+ * Callback triggered whenever the user enters the area of a text highlight.
29
+ *
30
+ * @param event - Mouse event associated with movement.
31
+ */
32
+ onMouseOver?(event: MouseEvent<HTMLDivElement>): void;
33
+ /**
34
+ * Callback triggered whenever the user leaves the area of a text highlight.
35
+ *
36
+ * @param event - Mouse event associated with movement.
37
+ */
38
+ onMouseOut?(event: MouseEvent<HTMLDivElement>): void;
39
+ /**
40
+ * Indicates whether the component is autoscrolled into view, affecting
41
+ * default theming.
42
+ */
43
+ isScrolledTo: boolean;
44
+ /**
45
+ * Callback triggered whenever the user tries to open context menu on highlight.
46
+ *
47
+ * @param event - Mouse event associated with click.
48
+ */
49
+ onContextMenu?(event: MouseEvent<HTMLDivElement>): void;
50
+ /**
51
+ * Optional CSS styling applied to each TextHighlight part.
52
+ */
53
+ style?: CSSProperties;
54
+ /**
55
+ * Background/line color for the highlight.
56
+ * Default: "rgba(255, 226, 143, 1)" (yellow)
57
+ */
58
+ highlightColor?: string;
59
+ /**
60
+ * Style mode for the highlight.
61
+ * - "highlight": Solid background color (default)
62
+ * - "underline": Line under the text
63
+ * - "strikethrough": Line through the text
64
+ */
65
+ highlightStyle?: "highlight" | "underline" | "strikethrough";
66
+ /**
67
+ * Callback triggered when the style changes.
68
+ */
69
+ onStyleChange?(style: TextHighlightStyle): void;
70
+ /**
71
+ * Callback triggered when the delete button is clicked.
72
+ */
73
+ onDelete?(): void;
74
+ /**
75
+ * Custom style icon. Replaces the default palette icon.
76
+ */
77
+ styleIcon?: ReactNode;
78
+ /**
79
+ * Custom delete icon. Replaces the default trash icon.
80
+ */
81
+ deleteIcon?: ReactNode;
82
+ /**
83
+ * Custom color presets for the style panel.
84
+ * Default: ["rgba(255, 226, 143, 1)", "#ffcdd2", "#c8e6c9", "#bbdefb", "#e1bee7"]
85
+ */
86
+ colorPresets?: string[];
87
+ }
88
+ /**
89
+ * A component for displaying a highlighted text area.
90
+ *
91
+ * @category Component
92
+ */
93
+ export declare const TextHighlight: ({ highlight, onClick, onMouseOver, onMouseOut, isScrolledTo, onContextMenu, style, highlightColor, highlightStyle, onStyleChange, onDelete, styleIcon, deleteIcon, colorPresets, }: TextHighlightProps) => React.JSX.Element;
@@ -0,0 +1,115 @@
1
+ import React, { useState, useRef, useEffect, } from "react";
2
+ import "../style/TextHighlight.css";
3
+ // Default icons
4
+ const DefaultStyleIcon = () => (React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" },
5
+ React.createElement("path", { d: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" })));
6
+ const DefaultDeleteIcon = () => (React.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" },
7
+ React.createElement("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" })));
8
+ // Highlight style icons
9
+ const HighlightIcon = () => (React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" },
10
+ React.createElement("path", { d: "M6 14l3 3v5h6v-5l3-3V9H6v5zm5-12h2v3h-2V2zM3.5 5.875L4.914 4.46l2.12 2.122L5.622 8 3.5 5.875zm13.46.71l2.123-2.12 1.414 1.414L18.375 8l-1.414-1.414z" })));
11
+ const UnderlineIcon = () => (React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" },
12
+ React.createElement("path", { d: "M12 17c3.31 0 6-2.69 6-6V3h-2.5v8c0 1.93-1.57 3.5-3.5 3.5S8.5 12.93 8.5 11V3H6v8c0 3.31 2.69 6 6 6zm-7 2v2h14v-2H5z" })));
13
+ const StrikethroughIcon = () => (React.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" },
14
+ React.createElement("path", { d: "M10 19h4v-3h-4v3zM5 4v3h5v3h4V7h5V4H5zM3 14h18v-2H3v2z" })));
15
+ // Default color presets
16
+ const DEFAULT_COLOR_PRESETS = [
17
+ "rgba(255, 226, 143, 1)", // Yellow (default)
18
+ "#ffcdd2", // Light red
19
+ "#c8e6c9", // Light green
20
+ "#bbdefb", // Light blue
21
+ "#e1bee7", // Light purple
22
+ ];
23
+ /**
24
+ * A component for displaying a highlighted text area.
25
+ *
26
+ * @category Component
27
+ */
28
+ export const TextHighlight = ({ highlight, onClick, onMouseOver, onMouseOut, isScrolledTo, onContextMenu, style, highlightColor = "rgba(255, 226, 143, 1)", highlightStyle = "highlight", onStyleChange, onDelete, styleIcon, deleteIcon, colorPresets = DEFAULT_COLOR_PRESETS, }) => {
29
+ const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
30
+ const [isHovered, setIsHovered] = useState(false);
31
+ const stylePanelRef = useRef(null);
32
+ const containerRef = useRef(null);
33
+ // Close style panel when clicking outside
34
+ useEffect(() => {
35
+ if (!isStylePanelOpen)
36
+ return;
37
+ const handleClickOutside = (e) => {
38
+ if (stylePanelRef.current &&
39
+ !stylePanelRef.current.contains(e.target)) {
40
+ setIsStylePanelOpen(false);
41
+ }
42
+ };
43
+ // Delay adding listener to avoid immediate close
44
+ const timeoutId = setTimeout(() => {
45
+ document.addEventListener("mousedown", handleClickOutside);
46
+ }, 0);
47
+ return () => {
48
+ clearTimeout(timeoutId);
49
+ document.removeEventListener("mousedown", handleClickOutside);
50
+ };
51
+ }, [isStylePanelOpen]);
52
+ const highlightClass = isScrolledTo ? "TextHighlight--scrolledTo" : "";
53
+ const { rects } = highlight.position;
54
+ // Get the first rect to position the toolbar
55
+ const firstRect = rects[0];
56
+ // Build style class based on highlight style
57
+ const getPartStyleClass = () => {
58
+ switch (highlightStyle) {
59
+ case "underline":
60
+ return "TextHighlight__part--underline";
61
+ case "strikethrough":
62
+ return "TextHighlight__part--strikethrough";
63
+ default:
64
+ return "";
65
+ }
66
+ };
67
+ // Build inline style for each part
68
+ const getPartStyle = (rect) => {
69
+ const baseStyle = { ...rect, ...style };
70
+ if (highlightStyle === "highlight") {
71
+ baseStyle.backgroundColor = highlightColor;
72
+ }
73
+ else {
74
+ // For underline and strikethrough, use the color for the line
75
+ baseStyle.backgroundColor = "transparent";
76
+ baseStyle.color = highlightColor;
77
+ }
78
+ return baseStyle;
79
+ };
80
+ return (React.createElement("div", { className: `TextHighlight ${highlightClass}`, onContextMenu: onContextMenu, ref: containerRef },
81
+ (onStyleChange || onDelete) && firstRect && (React.createElement("div", { className: "TextHighlight__toolbar-wrapper", style: {
82
+ position: "absolute",
83
+ left: firstRect.left,
84
+ top: firstRect.top - 28,
85
+ paddingBottom: 12,
86
+ }, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) },
87
+ React.createElement("div", { className: `TextHighlight__toolbar ${isHovered || isStylePanelOpen ? "TextHighlight__toolbar--visible" : ""}` },
88
+ onStyleChange && (React.createElement("button", { className: "TextHighlight__style-button", onClick: (e) => {
89
+ e.stopPropagation();
90
+ setIsStylePanelOpen(!isStylePanelOpen);
91
+ }, title: "Change style", type: "button" }, styleIcon || React.createElement(DefaultStyleIcon, null))),
92
+ onDelete && (React.createElement("button", { className: "TextHighlight__delete-button", onClick: (e) => {
93
+ e.stopPropagation();
94
+ onDelete();
95
+ }, title: "Delete", type: "button" }, deleteIcon || React.createElement(DefaultDeleteIcon, null)))),
96
+ isStylePanelOpen && onStyleChange && (React.createElement("div", { className: "TextHighlight__style-panel", ref: stylePanelRef, onClick: (e) => e.stopPropagation() },
97
+ React.createElement("div", { className: "TextHighlight__style-row" },
98
+ React.createElement("label", null, "Style"),
99
+ React.createElement("div", { className: "TextHighlight__style-buttons" },
100
+ React.createElement("button", { type: "button", className: `TextHighlight__style-type-button ${highlightStyle === "highlight" ? "active" : ""}`, onClick: () => onStyleChange({ highlightStyle: "highlight" }), title: "Highlight" },
101
+ React.createElement(HighlightIcon, null)),
102
+ React.createElement("button", { type: "button", className: `TextHighlight__style-type-button ${highlightStyle === "underline" ? "active" : ""}`, onClick: () => onStyleChange({ highlightStyle: "underline" }), title: "Underline" },
103
+ React.createElement(UnderlineIcon, null)),
104
+ React.createElement("button", { type: "button", className: `TextHighlight__style-type-button ${highlightStyle === "strikethrough" ? "active" : ""}`, onClick: () => onStyleChange({ highlightStyle: "strikethrough" }), title: "Strikethrough" },
105
+ React.createElement(StrikethroughIcon, null)))),
106
+ React.createElement("div", { className: "TextHighlight__style-row" },
107
+ React.createElement("label", null, "Color"),
108
+ React.createElement("div", { className: "TextHighlight__color-options" },
109
+ React.createElement("div", { className: "TextHighlight__color-presets" }, colorPresets.map((c) => (React.createElement("button", { key: c, type: "button", className: `TextHighlight__color-preset ${highlightColor === c ? "active" : ""}`, style: { backgroundColor: c }, onClick: () => onStyleChange({ highlightColor: c }), title: c })))),
110
+ React.createElement("input", { type: "color", value: highlightColor, onChange: (e) => {
111
+ onStyleChange({ highlightColor: e.target.value });
112
+ } }))))))),
113
+ React.createElement("div", { className: "TextHighlight__parts", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false) }, rects.map((rect, index) => (React.createElement("div", { onMouseOver: onMouseOver, onMouseOut: onMouseOut, onClick: onClick, key: index, style: getPartStyle(rect), className: `TextHighlight__part ${getPartStyleClass()}` }))))));
114
+ };
115
+ //# sourceMappingURL=TextHighlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TextHighlight.js","sourceRoot":"","sources":["../../../src/components/TextHighlight.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { PDFViewer } from "pdfjs-dist/types/web/pdf_viewer";
2
+ import React, { MutableRefObject } from "react";
3
+ /**
4
+ * The props type for {@link TipContainer}.
5
+ *
6
+ * @category Component Properties
7
+ * @internal
8
+ */
9
+ export interface TipContainerProps {
10
+ /**
11
+ * The PDFViewer instance containing the HighlightLayer
12
+ */
13
+ viewer: PDFViewer;
14
+ /**
15
+ * Reference to the callback to update the tip's position.This should be
16
+ * managed by the PdfHighlighter.
17
+ */
18
+ updateTipPositionRef: MutableRefObject<() => void>;
19
+ }
20
+ /**
21
+ * A component that manages rendering and placement of a tip around a highlight.
22
+ * It does not automatically update the tip's position if it resizes.
23
+ *
24
+ * @category Component
25
+ * @internal
26
+ */
27
+ export declare const TipContainer: ({ viewer, updateTipPositionRef, }: TipContainerProps) => React.JSX.Element | null;
@@ -0,0 +1,58 @@
1
+ import React, { useLayoutEffect, useRef, useState, } from "react";
2
+ import { usePdfHighlighterContext } from "../contexts/PdfHighlighterContext";
3
+ const clamp = (value, left, right) => Math.min(Math.max(value, left), right);
4
+ const VERTICAL_PADDING = 5;
5
+ /**
6
+ * A component that manages rendering and placement of a tip around a highlight.
7
+ * It does not automatically update the tip's position if it resizes.
8
+ *
9
+ * @category Component
10
+ * @internal
11
+ */
12
+ export const TipContainer = ({ viewer, updateTipPositionRef, }) => {
13
+ const [height, setHeight] = useState(0);
14
+ const [width, setWidth] = useState(0);
15
+ const containerRef = useRef(null);
16
+ const updatePosition = () => {
17
+ if (!containerRef.current)
18
+ return;
19
+ const { offsetHeight, offsetWidth } = containerRef.current;
20
+ setHeight(offsetHeight);
21
+ setWidth(offsetWidth);
22
+ };
23
+ updateTipPositionRef.current = updatePosition;
24
+ // useLayoutEffect ensures state is updated before re-render, preventing flickering
25
+ useLayoutEffect(() => {
26
+ updatePosition();
27
+ }, [updatePosition]);
28
+ const { getTip } = usePdfHighlighterContext();
29
+ const currentTip = getTip();
30
+ if (!currentTip)
31
+ return null;
32
+ // Destructuring current tip's position and content
33
+ const { position, content } = currentTip;
34
+ const { boundingRect } = position;
35
+ const pageNumber = boundingRect.pageNumber;
36
+ const pageNode = viewer.getPageView(pageNumber - 1).div; // Account for 1 indexing of pdf documents
37
+ const pageBoundingClientRect = pageNode.getBoundingClientRect();
38
+ const { left: pageLeft, width: pageWidth } = pageBoundingClientRect;
39
+ // Calculate the position and dimensions of the tip container
40
+ const scrollTop = viewer.container.scrollTop; // How much the viewer has been scrolled vertically
41
+ const left = pageNode.offsetLeft + boundingRect.left + boundingRect.width / 2; // center tip over highlight
42
+ const highlightTop = boundingRect.top + pageNode.offsetTop;
43
+ const highlightBottom = highlightTop + boundingRect.height;
44
+ // Determine whether the tip should be moved below the highlight
45
+ const shouldMove = highlightTop - height - VERTICAL_PADDING < scrollTop; // Would the tip render beyond the top of the visible document?
46
+ const top = shouldMove
47
+ ? highlightBottom + VERTICAL_PADDING
48
+ : highlightTop - height - VERTICAL_PADDING;
49
+ // Ensure the tip stays within the left edge of the viewer and the right edge of the page
50
+ const clampedLeft = clamp(left - width / 2, 0, pageLeft + pageWidth - width);
51
+ return (React.createElement("div", { className: "PdfHighlighter__tip-container", style: {
52
+ top,
53
+ left: clampedLeft,
54
+ height: "max-content",
55
+ width: "max-content",
56
+ }, ref: containerRef }, content));
57
+ };
58
+ //# sourceMappingURL=TipContainer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TipContainer.js","sourceRoot":"","sources":["../../../src/components/TipContainer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /// <reference types="react" />
2
+ import { Highlight, HighlightBindings, LTWH, LTWHP, Scaled, ViewportHighlight } from "../types";
3
+ /**
4
+ * A set of utilities for rendering highlights. Designed to be used within a
5
+ * highlight container.
6
+ *
7
+ * @category Context
8
+ */
9
+ export type HighlightContainerUtils<T extends Highlight = Highlight> = {
10
+ /**
11
+ * The highlight being rendered at this component.
12
+ */
13
+ highlight: ViewportHighlight<T>;
14
+ /**
15
+ * Convert a Viewport rectangle to a scaled rectangle. Can be used
16
+ * for storing and updating area selection highlights, for example.
17
+ *
18
+ * @returns - Scaled/display agnostic rectangle.
19
+ */
20
+ viewportToScaled(rect: LTWHP): Scaled;
21
+ /**
22
+ * Capture a PNG data url of a viewport rectangle.
23
+ *
24
+ * @returns - PNG data url. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
25
+ */
26
+ screenshot(position: LTWH): string;
27
+ /**
28
+ * Whether the highlight has been autoscrolled to.
29
+ */
30
+ isScrolledTo: boolean;
31
+ /**
32
+ * All the DOM refs for the highlights shared on the same page
33
+ * as `highlight`
34
+ */
35
+ highlightBindings: HighlightBindings;
36
+ };
37
+ export declare const HighlightContext: import("react").Context<HighlightContainerUtils<Highlight> | undefined>;
38
+ /**
39
+ * Custom hook for providing {@link HighlightContainerUtils}. Must be used
40
+ * within a child of {@link PdfHighlighter}.
41
+ *
42
+ * @category Context
43
+ */
44
+ export declare const useHighlightContainerContext: <T extends Highlight = Highlight>() => HighlightContainerUtils<T>;
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from "react";
2
+ export const HighlightContext = createContext(undefined);
3
+ /**
4
+ * Custom hook for providing {@link HighlightContainerUtils}. Must be used
5
+ * within a child of {@link PdfHighlighter}.
6
+ *
7
+ * @category Context
8
+ */
9
+ export const useHighlightContainerContext = () => {
10
+ const highlightContainerUtils = useContext(HighlightContext);
11
+ if (highlightContainerUtils === undefined) {
12
+ throw new Error("useHighlightContainerContext must be used within a child of PdfHighlighter!");
13
+ }
14
+ return highlightContainerUtils;
15
+ };
16
+ //# sourceMappingURL=HighlightContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HighlightContext.js","sourceRoot":"","sources":["../../../src/contexts/HighlightContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAiDlD,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAE3C,SAAS,CAAC,CAAC;AAEb;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAExC,EAAE;IACJ,MAAM,uBAAuB,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAE7D,IAAI,uBAAuB,KAAK,SAAS,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IAED,OAAO,uBAAqD,CAAC;AAC/D,CAAC,CAAC"}
@@ -0,0 +1,89 @@
1
+ /// <reference types="react" />
2
+ import { GhostHighlight, Highlight, PdfSelection, Tip } from "../types";
3
+ import { PDFViewer } from "pdfjs-dist/types/web/pdf_viewer";
4
+ /**
5
+ * A set of utilities for to control the behaviour of {@link PdfHighlighter}.
6
+ *
7
+ * @category Context
8
+ */
9
+ export type PdfHighlighterUtils = {
10
+ /**
11
+ * Checks whether a selection is progress, a ghost highlight, or an edit.
12
+ *
13
+ * @returns - `true` if editing, ghost highlighting, or selecting.
14
+ */
15
+ isEditingOrHighlighting(): boolean;
16
+ /**
17
+ * Get currently selected area or text selection.
18
+ *
19
+ * @returns - current selection or `null` if no selection is being made.
20
+ */
21
+ getCurrentSelection(): PdfSelection | null;
22
+ /**
23
+ * Get the currently present ghost highlight.
24
+ *
25
+ * @return - currently present ghost highlight or `null` if non-existent.
26
+ */
27
+ getGhostHighlight(): GhostHighlight | null;
28
+ /**
29
+ * Cancel any ghost highlight.
30
+ * The selected area will stay selected until the user clicks away.
31
+ */
32
+ removeGhostHighlight(): void;
33
+ /**
34
+ * If enabled, automatic tips/popups inside of a PdfHighlighter will be disabled.
35
+ * Additional niceties will also be provided to prevent new highlights being made.
36
+ */
37
+ toggleEditInProgress(flag?: boolean): void;
38
+ /**
39
+ * Whether an AreaHighlight is being moved/resized, or a manual highlight edit has
40
+ * been toggled.
41
+ *
42
+ * @returns - `true` if AreaHighlight is being edited or edit mode was set.
43
+ */
44
+ isEditInProgress(): boolean;
45
+ /**
46
+ * Whether a mouse selection or text selection is currently being performed.
47
+ *
48
+ * @returns - `true` if mouse selection or text selection is being performed.
49
+ */
50
+ isSelectionInProgress(): boolean;
51
+ /**
52
+ * Scroll to a highlight in this viewer.
53
+ *
54
+ * @param highlight - A highlight provided to the {@link PdfHighlighter} to
55
+ * scroll to.
56
+ */
57
+ scrollToHighlight(highlight: Highlight): void;
58
+ /**
59
+ * Get a reference to the currently used instance of a PDF Viewer.
60
+ *
61
+ * @returns - The currently active PDF Viewer.
62
+ */
63
+ getViewer(): PDFViewer | null;
64
+ /**
65
+ * Get the currently active tip, if any.
66
+ *
67
+ * @returns - the currently active tip or `null` if inactive.
68
+ */
69
+ getTip(): Tip | null;
70
+ /**
71
+ * Set a tip to be displayed in the current PDF Viewer.
72
+ *
73
+ * @param tip - tip to be displayed, or `null` to hide any tip.
74
+ */
75
+ setTip(tip: Tip | null): void;
76
+ /**
77
+ * Callback to update any currently active tip's position. This will make sure
78
+ * the tip is visible above/below its highlight.
79
+ */
80
+ updateTipPosition(): void;
81
+ };
82
+ export declare const PdfHighlighterContext: import("react").Context<PdfHighlighterUtils | undefined>;
83
+ /**
84
+ * Custom hook for providing {@link PdfHighlighterUtils}. Must be used
85
+ * within a child of {@link PdfHighlighter}.
86
+ *
87
+ * @category Context
88
+ */
89
+ export declare const usePdfHighlighterContext: () => PdfHighlighterUtils;
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from "react";
2
+ export const PdfHighlighterContext = createContext(undefined);
3
+ /**
4
+ * Custom hook for providing {@link PdfHighlighterUtils}. Must be used
5
+ * within a child of {@link PdfHighlighter}.
6
+ *
7
+ * @category Context
8
+ */
9
+ export const usePdfHighlighterContext = () => {
10
+ const pdfHighlighterUtils = useContext(PdfHighlighterContext);
11
+ if (pdfHighlighterUtils === undefined) {
12
+ throw new Error("usePdfHighlighterContext must be used within PdfHighlighter!");
13
+ }
14
+ return pdfHighlighterUtils;
15
+ };
16
+ //# sourceMappingURL=PdfHighlighterContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PdfHighlighterContext.js","sourceRoot":"","sources":["../../../src/contexts/PdfHighlighterContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AA6FlD,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAEhD,SAAS,CAAC,CAAC;AAEb;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,EAAE;IAC3C,MAAM,mBAAmB,GAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAE9D,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CACb,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IAED,OAAO,mBAAmB,CAAC;AAC7B,CAAC,CAAC"}