@rzymek/react-pdf-highlighter 8.0.1-rc.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +43 -0
  3. package/dist/components/AreaHighlight.d.ts +8 -0
  4. package/dist/components/Highlight.d.ts +17 -0
  5. package/dist/components/HighlightLayer.d.ts +26 -0
  6. package/dist/components/MouseMonitor.d.ts +15 -0
  7. package/dist/components/MouseSelection.d.ts +10 -0
  8. package/dist/components/PdfHighlighter.d.ts +92 -0
  9. package/dist/components/PdfLoader.d.ts +32 -0
  10. package/dist/components/Popup.d.ts +8 -0
  11. package/dist/components/Tip.d.ts +20 -0
  12. package/dist/components/TipContainer.d.ts +13 -0
  13. package/dist/index.d.ts +7 -0
  14. package/dist/lib/coordinates.d.ts +8 -0
  15. package/dist/lib/get-area-as-png.d.ts +2 -0
  16. package/dist/lib/get-bounding-rect.d.ts +2 -0
  17. package/dist/lib/get-client-rects.d.ts +2 -0
  18. package/dist/lib/optimize-client-rects.d.ts +2 -0
  19. package/dist/lib/pdfjs-dom.d.ts +8 -0
  20. package/dist/node_modules/.pnpm/pdfjs-dist@4.4.168/node_modules/pdfjs-dist/web/pdf_viewer.js +8022 -0
  21. package/dist/node_modules/.pnpm/ts-debounce@4.0.0/node_modules/ts-debounce/dist/src/index.esm.js +38 -0
  22. package/dist/src/components/AreaHighlight.js +58 -0
  23. package/dist/src/components/Highlight.js +45 -0
  24. package/dist/src/components/HighlightLayer.js +47 -0
  25. package/dist/src/components/MouseMonitor.js +45 -0
  26. package/dist/src/components/MouseSelection.js +119 -0
  27. package/dist/src/components/PdfHighlighter.js +543 -0
  28. package/dist/src/components/PdfLoader.js +81 -0
  29. package/dist/src/components/Popup.js +42 -0
  30. package/dist/src/components/Tip.js +82 -0
  31. package/dist/src/components/TipContainer.js +62 -0
  32. package/dist/src/index.js +15 -0
  33. package/dist/src/lib/coordinates.js +50 -0
  34. package/dist/src/lib/get-area-as-png.js +31 -0
  35. package/dist/src/lib/get-bounding-rect.js +40 -0
  36. package/dist/src/lib/get-client-rects.js +39 -0
  37. package/dist/src/lib/optimize-client-rects.js +54 -0
  38. package/dist/src/lib/pdfjs-dom.js +64 -0
  39. package/dist/src/style/AreaHighlight.module.css.js +14 -0
  40. package/dist/src/style/Highlight.module.css.js +20 -0
  41. package/dist/src/style/MouseSelection.module.css.js +8 -0
  42. package/dist/src/style/PdfHighlighter.module.css.js +14 -0
  43. package/dist/src/style/Tip.module.css.js +11 -0
  44. package/dist/src/style/TipContainer.module.css.js +8 -0
  45. package/dist/style.css +2903 -0
  46. package/dist/types.d.ts +62 -0
  47. package/package.json +69 -0
@@ -0,0 +1,82 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Component } from "react";
6
+ import styles from "../style/Tip.module.css.js";
7
+ class Tip extends Component {
8
+ constructor() {
9
+ super(...arguments);
10
+ __publicField(this, "state", {
11
+ compact: true,
12
+ text: "",
13
+ emoji: ""
14
+ });
15
+ }
16
+ // for TipContainer
17
+ componentDidUpdate(_, nextState) {
18
+ const { onUpdate } = this.props;
19
+ if (onUpdate && this.state.compact !== nextState.compact) {
20
+ onUpdate();
21
+ }
22
+ }
23
+ render() {
24
+ const { onConfirm, onOpen } = this.props;
25
+ const { compact, text, emoji } = this.state;
26
+ return /* @__PURE__ */ jsx("div", { children: compact ? /* @__PURE__ */ jsx(
27
+ "div",
28
+ {
29
+ className: styles.compact,
30
+ onClick: () => {
31
+ onOpen();
32
+ this.setState({ compact: false });
33
+ },
34
+ children: "Add highlight"
35
+ }
36
+ ) : /* @__PURE__ */ jsxs(
37
+ "form",
38
+ {
39
+ className: styles.card,
40
+ onSubmit: (event) => {
41
+ event.preventDefault();
42
+ onConfirm({ text, emoji });
43
+ },
44
+ children: [
45
+ /* @__PURE__ */ jsxs("div", { children: [
46
+ /* @__PURE__ */ jsx(
47
+ "textarea",
48
+ {
49
+ placeholder: "Your comment",
50
+ autoFocus: true,
51
+ value: text,
52
+ onChange: (event) => this.setState({ text: event.target.value }),
53
+ ref: (node) => {
54
+ if (node) {
55
+ node.focus();
56
+ }
57
+ }
58
+ }
59
+ ),
60
+ /* @__PURE__ */ jsx("div", { children: ["💩", "😱", "😍", "🔥", "😳", "⚠️"].map((_emoji) => /* @__PURE__ */ jsxs("label", { children: [
61
+ /* @__PURE__ */ jsx(
62
+ "input",
63
+ {
64
+ checked: emoji === _emoji,
65
+ type: "radio",
66
+ name: "emoji",
67
+ value: _emoji,
68
+ onChange: (event) => this.setState({ emoji: event.target.value })
69
+ }
70
+ ),
71
+ _emoji
72
+ ] }, _emoji)) })
73
+ ] }),
74
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("input", { type: "submit", value: "Save" }) })
75
+ ]
76
+ }
77
+ ) });
78
+ }
79
+ }
80
+ export {
81
+ Tip
82
+ };
@@ -0,0 +1,62 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import React, { useState, useRef, useCallback, useEffect } from "react";
3
+ import styles from "../style/TipContainer.module.css.js";
4
+ function clamp(value, left, right) {
5
+ return Math.min(Math.max(value, left), right);
6
+ }
7
+ function TipContainer({
8
+ children,
9
+ style,
10
+ scrollTop,
11
+ pageBoundingRect
12
+ }) {
13
+ const [height, setHeight] = useState(0);
14
+ const [width, setWidth] = useState(0);
15
+ const nodeRef = useRef(null);
16
+ const updatePosition = useCallback(() => {
17
+ if (!nodeRef.current) {
18
+ return;
19
+ }
20
+ const { offsetHeight, offsetWidth } = nodeRef.current;
21
+ setHeight(offsetHeight);
22
+ setWidth(offsetWidth);
23
+ }, []);
24
+ useEffect(() => {
25
+ setTimeout(updatePosition, 0);
26
+ }, [updatePosition]);
27
+ const isStyleCalculationInProgress = width === 0 && height === 0;
28
+ const shouldMove = style.top - height - 5 < scrollTop;
29
+ const top = shouldMove ? style.bottom + 5 : style.top - height - 5;
30
+ const left = clamp(style.left - width / 2, 0, pageBoundingRect.width - width);
31
+ const handleUpdate = useCallback(() => {
32
+ setWidth(0);
33
+ setHeight(0);
34
+ setTimeout(updatePosition, 0);
35
+ }, [updatePosition]);
36
+ const childrenWithProps = React.Children.map(
37
+ children,
38
+ (child) => child != null ? React.cloneElement(child, {
39
+ onUpdate: handleUpdate,
40
+ popup: {
41
+ position: shouldMove ? "below" : "above"
42
+ }
43
+ }) : null
44
+ );
45
+ return /* @__PURE__ */ jsx(
46
+ "div",
47
+ {
48
+ id: "PdfHighlighter__tip-container",
49
+ className: styles.tipContainer,
50
+ style: {
51
+ visibility: isStyleCalculationInProgress ? "hidden" : "visible",
52
+ top,
53
+ left
54
+ },
55
+ ref: nodeRef,
56
+ children: childrenWithProps
57
+ }
58
+ );
59
+ }
60
+ export {
61
+ TipContainer
62
+ };
@@ -0,0 +1,15 @@
1
+ import { PdfHighlighter } from "./components/PdfHighlighter.js";
2
+ import { Tip } from "./components/Tip.js";
3
+ import { Highlight } from "./components/Highlight.js";
4
+ import { Popup } from "./components/Popup.js";
5
+ import { AreaHighlight } from "./components/AreaHighlight.js";
6
+ import { PdfLoader } from "./components/PdfLoader.js";
7
+ /* empty css */
8
+ export {
9
+ AreaHighlight,
10
+ Highlight,
11
+ PdfHighlighter,
12
+ PdfLoader,
13
+ Popup,
14
+ Tip
15
+ };
@@ -0,0 +1,50 @@
1
+ const viewportToScaled = (rect, { width, height }) => {
2
+ return {
3
+ x1: rect.left,
4
+ y1: rect.top,
5
+ x2: rect.left + rect.width,
6
+ y2: rect.top + rect.height,
7
+ width,
8
+ height,
9
+ pageNumber: rect.pageNumber
10
+ };
11
+ };
12
+ const pdfToViewport = (pdf, viewport) => {
13
+ const [x1, y1, x2, y2] = viewport.convertToViewportRectangle([
14
+ pdf.x1,
15
+ pdf.y1,
16
+ pdf.x2,
17
+ pdf.y2
18
+ ]);
19
+ return {
20
+ left: Math.min(x1, x2),
21
+ top: Math.min(y1, y2),
22
+ width: Math.abs(x2 - x1),
23
+ height: Math.abs(y1 - y2),
24
+ pageNumber: pdf.pageNumber
25
+ };
26
+ };
27
+ const scaledToViewport = (scaled, viewport, usePdfCoordinates = false) => {
28
+ const { width, height } = viewport;
29
+ if (usePdfCoordinates) {
30
+ return pdfToViewport(scaled, viewport);
31
+ }
32
+ if (scaled.x1 === void 0) {
33
+ throw new Error("You are using old position format, please update");
34
+ }
35
+ const x1 = width * scaled.x1 / scaled.width;
36
+ const y1 = height * scaled.y1 / scaled.height;
37
+ const x2 = width * scaled.x2 / scaled.width;
38
+ const y2 = height * scaled.y2 / scaled.height;
39
+ return {
40
+ left: x1,
41
+ top: y1,
42
+ width: x2 - x1,
43
+ height: y2 - y1,
44
+ pageNumber: scaled.pageNumber
45
+ };
46
+ };
47
+ export {
48
+ scaledToViewport,
49
+ viewportToScaled
50
+ };
@@ -0,0 +1,31 @@
1
+ import { isHTMLCanvasElement } from "./pdfjs-dom.js";
2
+ const getAreaAsPNG = (canvas, position) => {
3
+ const { left, top, width, height } = position;
4
+ const doc = canvas ? canvas.ownerDocument : null;
5
+ const newCanvas = doc == null ? void 0 : doc.createElement("canvas");
6
+ if (!newCanvas || !isHTMLCanvasElement(newCanvas)) {
7
+ return "";
8
+ }
9
+ newCanvas.width = width;
10
+ newCanvas.height = height;
11
+ const newCanvasContext = newCanvas.getContext("2d");
12
+ if (!newCanvasContext || !canvas) {
13
+ return "";
14
+ }
15
+ const dpr = window.devicePixelRatio;
16
+ newCanvasContext.drawImage(
17
+ canvas,
18
+ left * dpr,
19
+ top * dpr,
20
+ width * dpr,
21
+ height * dpr,
22
+ 0,
23
+ 0,
24
+ width,
25
+ height
26
+ );
27
+ return newCanvas.toDataURL("image/png");
28
+ };
29
+ export {
30
+ getAreaAsPNG
31
+ };
@@ -0,0 +1,40 @@
1
+ const getBoundingRect = (clientRects) => {
2
+ const rects = Array.from(clientRects).map((rect) => {
3
+ const { left, top, width, height, pageNumber: pageNumber2 } = rect;
4
+ const X02 = left;
5
+ const X12 = left + width;
6
+ const Y02 = top;
7
+ const Y12 = top + height;
8
+ return { X0: X02, X1: X12, Y0: Y02, Y1: Y12, pageNumber: pageNumber2 };
9
+ });
10
+ let firstPageNumber = Number.MAX_SAFE_INTEGER;
11
+ for (const rect of rects) {
12
+ firstPageNumber = Math.min(
13
+ firstPageNumber,
14
+ rect.pageNumber ?? firstPageNumber
15
+ );
16
+ }
17
+ const rectsWithSizeOnFirstPage = rects.filter(
18
+ (rect) => (rect.X0 > 0 || rect.X1 > 0 || rect.Y0 > 0 || rect.Y1 > 0) && rect.pageNumber === firstPageNumber
19
+ );
20
+ const optimal = rectsWithSizeOnFirstPage.reduce((res, rect) => {
21
+ return {
22
+ X0: Math.min(res.X0, rect.X0),
23
+ X1: Math.max(res.X1, rect.X1),
24
+ Y0: Math.min(res.Y0, rect.Y0),
25
+ Y1: Math.max(res.Y1, rect.Y1),
26
+ pageNumber: firstPageNumber
27
+ };
28
+ }, rectsWithSizeOnFirstPage[0]);
29
+ const { X0, X1, Y0, Y1, pageNumber } = optimal;
30
+ return {
31
+ left: X0,
32
+ top: Y0,
33
+ width: X1 - X0,
34
+ height: Y1 - Y0,
35
+ pageNumber
36
+ };
37
+ };
38
+ export {
39
+ getBoundingRect
40
+ };
@@ -0,0 +1,39 @@
1
+ import { optimizeClientRects } from "./optimize-client-rects.js";
2
+ const isClientRectInsidePageRect = (clientRect, pageRect) => {
3
+ if (clientRect.top < pageRect.top) {
4
+ return false;
5
+ }
6
+ if (clientRect.bottom > pageRect.bottom) {
7
+ return false;
8
+ }
9
+ if (clientRect.right > pageRect.right) {
10
+ return false;
11
+ }
12
+ if (clientRect.left < pageRect.left) {
13
+ return false;
14
+ }
15
+ return true;
16
+ };
17
+ const getClientRects = (range, pages, shouldOptimize = true) => {
18
+ const clientRects = Array.from(range.getClientRects());
19
+ const rects = [];
20
+ for (const clientRect of clientRects) {
21
+ for (const page of pages) {
22
+ const pageRect = page.node.getBoundingClientRect();
23
+ if (isClientRectInsidePageRect(clientRect, pageRect) && clientRect.width > 0 && clientRect.height > 0 && clientRect.width < pageRect.width && clientRect.height < pageRect.height) {
24
+ const highlightedRect = {
25
+ top: clientRect.top + page.node.scrollTop - pageRect.top,
26
+ left: clientRect.left + page.node.scrollLeft - pageRect.left,
27
+ width: clientRect.width,
28
+ height: clientRect.height,
29
+ pageNumber: page.number
30
+ };
31
+ rects.push(highlightedRect);
32
+ }
33
+ }
34
+ }
35
+ return shouldOptimize ? optimizeClientRects(rects) : rects;
36
+ };
37
+ export {
38
+ getClientRects
39
+ };
@@ -0,0 +1,54 @@
1
+ const sort = (rects) => rects.sort((A, B) => {
2
+ const top = (A.pageNumber || 0) * A.top - (B.pageNumber || 0) * B.top;
3
+ if (top === 0) {
4
+ return A.left - B.left;
5
+ }
6
+ return top;
7
+ });
8
+ const overlaps = (A, B) => A.pageNumber === B.pageNumber && A.left <= B.left && B.left <= A.left + A.width;
9
+ const sameLine = (A, B, yMargin = 5) => A.pageNumber === B.pageNumber && Math.abs(A.top - B.top) < yMargin && Math.abs(A.height - B.height) < yMargin;
10
+ const inside = (A, B) => A.pageNumber === B.pageNumber && A.top > B.top && A.left > B.left && A.top + A.height < B.top + B.height && A.left + A.width < B.left + B.width;
11
+ const nextTo = (A, B, xMargin = 10) => {
12
+ const Aright = A.left + A.width;
13
+ const Bright = B.left + B.width;
14
+ return A.pageNumber === B.pageNumber && A.left <= B.left && Aright <= Bright && B.left - Aright <= xMargin;
15
+ };
16
+ const extendWidth = (A, B) => {
17
+ A.width = Math.max(B.width - A.left + B.left, A.width);
18
+ };
19
+ const optimizeClientRects = (clientRects) => {
20
+ const rects = sort(clientRects);
21
+ const toRemove = /* @__PURE__ */ new Set();
22
+ const firstPass = rects.filter((rect) => {
23
+ return rects.every((otherRect) => {
24
+ return !inside(rect, otherRect);
25
+ });
26
+ });
27
+ let passCount = 0;
28
+ while (passCount <= 2) {
29
+ for (const A of firstPass) {
30
+ for (const B of firstPass) {
31
+ if (A === B || toRemove.has(A) || toRemove.has(B)) {
32
+ continue;
33
+ }
34
+ if (!sameLine(A, B)) {
35
+ continue;
36
+ }
37
+ if (overlaps(A, B)) {
38
+ extendWidth(A, B);
39
+ A.height = Math.max(A.height, B.height);
40
+ toRemove.add(B);
41
+ }
42
+ if (nextTo(A, B)) {
43
+ extendWidth(A, B);
44
+ toRemove.add(B);
45
+ }
46
+ }
47
+ }
48
+ passCount += 1;
49
+ }
50
+ return firstPass.filter((rect) => !toRemove.has(rect));
51
+ };
52
+ export {
53
+ optimizeClientRects
54
+ };
@@ -0,0 +1,64 @@
1
+ const getDocument = (element) => element.ownerDocument || document;
2
+ const getWindow = (element) => getDocument(element).defaultView || window;
3
+ const isHTMLElement = (element) => element != null && (element instanceof HTMLElement || element instanceof getWindow(element).HTMLElement);
4
+ const isHTMLCanvasElement = (element) => element instanceof HTMLCanvasElement || element instanceof getWindow(element).HTMLCanvasElement;
5
+ const getPageFromElement = (target) => {
6
+ const node = target.closest(".page");
7
+ if (!isHTMLElement(node)) {
8
+ return null;
9
+ }
10
+ const number = Number(node.dataset.pageNumber);
11
+ return { node, number };
12
+ };
13
+ const getPagesFromRange = (range) => {
14
+ const startParentElement = range.startContainer.parentElement;
15
+ const endParentElement = range.endContainer.parentElement;
16
+ if (!isHTMLElement(startParentElement) || !isHTMLElement(endParentElement)) {
17
+ return [];
18
+ }
19
+ const startPage = getPageFromElement(startParentElement);
20
+ const endPage = getPageFromElement(endParentElement);
21
+ if (!(startPage == null ? void 0 : startPage.number) || !(endPage == null ? void 0 : endPage.number)) {
22
+ return [];
23
+ }
24
+ if (startPage.number === endPage.number) {
25
+ return [startPage];
26
+ }
27
+ if (startPage.number === endPage.number - 1) {
28
+ return [startPage, endPage];
29
+ }
30
+ const pages = [];
31
+ let currentPageNumber = startPage.number;
32
+ const document2 = startPage.node.ownerDocument;
33
+ while (currentPageNumber <= endPage.number) {
34
+ const currentPage = getPageFromElement(
35
+ document2.querySelector(
36
+ `[data-page-number='${currentPageNumber}'`
37
+ )
38
+ );
39
+ if (currentPage) {
40
+ pages.push(currentPage);
41
+ }
42
+ currentPageNumber++;
43
+ }
44
+ return pages;
45
+ };
46
+ const findOrCreateContainerLayer = (container, className, selector) => {
47
+ const doc = getDocument(container);
48
+ let layer = container.querySelector(selector);
49
+ if (!layer) {
50
+ layer = doc.createElement("div");
51
+ layer.className = className;
52
+ container.appendChild(layer);
53
+ }
54
+ return layer;
55
+ };
56
+ export {
57
+ findOrCreateContainerLayer,
58
+ getDocument,
59
+ getPageFromElement,
60
+ getPagesFromRange,
61
+ getWindow,
62
+ isHTMLCanvasElement,
63
+ isHTMLElement
64
+ };
@@ -0,0 +1,14 @@
1
+ const areaHighlight = "_areaHighlight_1ppoh_1";
2
+ const part = "_part_1ppoh_8";
3
+ const scrolledTo = "_scrolledTo_1ppoh_15";
4
+ const styles = {
5
+ areaHighlight,
6
+ part,
7
+ scrolledTo
8
+ };
9
+ export {
10
+ areaHighlight,
11
+ styles as default,
12
+ part,
13
+ scrolledTo
14
+ };
@@ -0,0 +1,20 @@
1
+ const highlight = "_highlight_3l4zw_1";
2
+ const emoji = "_emoji_3l4zw_5";
3
+ const parts = "_parts_3l4zw_12";
4
+ const part = "_part_3l4zw_12";
5
+ const scrolledTo = "_scrolledTo_3l4zw_23";
6
+ const styles = {
7
+ highlight,
8
+ emoji,
9
+ parts,
10
+ part,
11
+ scrolledTo
12
+ };
13
+ export {
14
+ styles as default,
15
+ emoji,
16
+ highlight,
17
+ part,
18
+ parts,
19
+ scrolledTo
20
+ };
@@ -0,0 +1,8 @@
1
+ const mouseSelection = "_mouseSelection_1p43j_1";
2
+ const styles = {
3
+ mouseSelection
4
+ };
5
+ export {
6
+ styles as default,
7
+ mouseSelection
8
+ };
@@ -0,0 +1,14 @@
1
+ const container = "_container_12oj9_1";
2
+ const highlightLayer = "_highlightLayer_12oj9_8";
3
+ const disableSelection = "_disableSelection_12oj9_19";
4
+ const styles = {
5
+ container,
6
+ highlightLayer,
7
+ disableSelection
8
+ };
9
+ export {
10
+ container,
11
+ styles as default,
12
+ disableSelection,
13
+ highlightLayer
14
+ };
@@ -0,0 +1,11 @@
1
+ const compact = "_compact_1um8o_1";
2
+ const card = "_card_1um8o_10";
3
+ const styles = {
4
+ compact,
5
+ card
6
+ };
7
+ export {
8
+ card,
9
+ compact,
10
+ styles as default
11
+ };
@@ -0,0 +1,8 @@
1
+ const tipContainer = "_tipContainer_f56kr_1";
2
+ const styles = {
3
+ tipContainer
4
+ };
5
+ export {
6
+ styles as default,
7
+ tipContainer
8
+ };