@huridocs/react-text-selection-handler 0.3.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"HandleTextSelection.d.ts","sourceRoot":"","sources":["../src/HandleTextSelection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAU,MAAM,OAAO,CAAC;AAGzD,OAAO,EAA+B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE7E,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,GAAG,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAcD,QAAA,MAAM,mBAAmB,EAAE,iBAAiB,CAAC,qBAAqB,CAwDjE,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"HandleTextSelection.d.ts","sourceRoot":"","sources":["../src/HandleTextSelection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,iBAAiB,EAAqB,MAAM,OAAO,CAAC;AAGpE,OAAO,EAA+B,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG7E,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,GAAG,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAcD,QAAA,MAAM,mBAAmB,EAAE,iBAAiB,CAAC,qBAAqB,CAgFjE,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -1,7 +1,8 @@
1
- import React, { useRef } from 'react';
1
+ import React, { useRef, useEffect } from 'react';
2
2
  import { elementContainsDomRect } from './elementContainsDomRect';
3
3
  import { rangeToTextRects } from './rangeToTextRects';
4
4
  import { domRectToSelectionRectangle } from './TextSelection';
5
+ import { getSelectedText } from './getSelectedText';
5
6
  const notNull = (value) => value !== null;
6
7
  const normalizedFirefoxRange = (selection) => {
7
8
  const finalRange = selection.getRangeAt(selection.rangeCount - 1);
@@ -33,8 +34,29 @@ const HandleTextSelection = ({ onSelect, onDeselect = () => { }, children, }) =>
33
34
  return domRectToSelectionRectangle(rectangle, region);
34
35
  })
35
36
  .filter(notNull);
36
- onSelect({ text: selection.toString(), selectionRectangles });
37
+ const text = getSelectedText();
38
+ onSelect({ text, selectionRectangles });
37
39
  };
40
+ useEffect(() => {
41
+ const refElement = ref.current;
42
+ if (!refElement) {
43
+ return () => { };
44
+ }
45
+ const handleKeyDown = (event) => {
46
+ if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
47
+ event.preventDefault();
48
+ const selection = window.getSelection();
49
+ if (selection && selection.toString().trim()) {
50
+ const text = getSelectedText();
51
+ navigator.clipboard.writeText(text);
52
+ }
53
+ }
54
+ };
55
+ refElement.addEventListener('keydown', handleKeyDown);
56
+ return () => {
57
+ refElement.removeEventListener('keydown', handleKeyDown);
58
+ };
59
+ }, [ref]);
38
60
  return (React.createElement("div", { role: "none", ref: ref, onMouseDown: e => {
39
61
  var _a;
40
62
  if (e.button !== 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"HandleTextSelection.js","sourceRoot":"","sources":["../src/HandleTextSelection.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HandleTextSelection.js","sourceRoot":"","sources":["../src/HandleTextSelection.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const normalizeSpaces: (text: string) => string;
2
+ export declare const getRangeSelectedText: (range: Range, containerElement: HTMLElement) => string;
3
+ //# sourceMappingURL=getRangeSelectedText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRangeSelectedText.d.ts","sourceRoot":"","sources":["../src/getRangeSelectedText.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,eAAe,SAAU,MAAM,WAyB3C,CAAC;AAEF,eAAO,MAAM,oBAAoB,UAAW,KAAK,oBAAoB,WAAW,KAAG,MAmBlF,CAAC"}
@@ -0,0 +1,52 @@
1
+ const getLeafNodes = (node) => {
2
+ if (node.nodeType === Node.TEXT_NODE) {
3
+ return [node];
4
+ }
5
+ if (node.nodeType === Node.ELEMENT_NODE) {
6
+ const element = node;
7
+ if (element.tagName === 'BR') {
8
+ return [node];
9
+ }
10
+ }
11
+ return Array.from(node.childNodes).reduce((acc, child) => acc.concat(getLeafNodes(child)), []);
12
+ };
13
+ const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
14
+ export const normalizeSpaces = (text) => {
15
+ const pairedCharacters = {
16
+ '(': ')',
17
+ '[': ']',
18
+ '{': '}',
19
+ '"': '"',
20
+ "'": "'",
21
+ };
22
+ let result = text;
23
+ Object.entries(pairedCharacters).forEach(([openChar, closeChar]) => {
24
+ const escapedOpen = escapeRegExp(openChar);
25
+ const escapedClose = escapeRegExp(closeChar);
26
+ const pattern = new RegExp(`${escapedOpen}\\s*(.*?)\\s*${escapedClose}`, 'g');
27
+ result = result.replace(pattern, `${openChar}$1${closeChar}`);
28
+ });
29
+ const spaceAfterChars = escapeRegExp('$£€@#');
30
+ const spaceBeforeChars = escapeRegExp(',.!?:;');
31
+ result = result.replace(new RegExp(`([${spaceAfterChars}])\\s+`, 'g'), '$1');
32
+ result = result.replace(new RegExp(`\\s+([${spaceBeforeChars}])`, 'g'), '$1');
33
+ return result;
34
+ };
35
+ export const getRangeSelectedText = (range, containerElement) => {
36
+ const rangeContent = range.cloneContents();
37
+ const elements = getLeafNodes(rangeContent)
38
+ .filter(node => containerElement.contains(range.commonAncestorContainer.contains(node) ? node : range.commonAncestorContainer))
39
+ .map((node) => {
40
+ var _a, _b;
41
+ if (node.nodeType === Node.ELEMENT_NODE) {
42
+ const element = node;
43
+ if (element.tagName === 'BR')
44
+ return '\n';
45
+ return ((_a = element.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
46
+ }
47
+ return ((_b = node.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || '';
48
+ })
49
+ .filter(Boolean);
50
+ return normalizeSpaces(elements.join(' '));
51
+ };
52
+ //# sourceMappingURL=getRangeSelectedText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getRangeSelectedText.js","sourceRoot":"","sources":["../src/getRangeSelectedText.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const getSelectedText: () => string;
2
+ //# sourceMappingURL=getSelectedText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getSelectedText.d.ts","sourceRoot":"","sources":["../src/getSelectedText.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,eAAe,QAAO,MAiBlC,CAAC"}
@@ -0,0 +1,46 @@
1
+ const isElementOnNextLine = (firstElement, secondElement) => {
2
+ var _a, _b;
3
+ if (!firstElement || !secondElement)
4
+ return false;
5
+ const left1 = (_a = firstElement === null || firstElement === void 0 ? void 0 : firstElement.style) === null || _a === void 0 ? void 0 : _a.left;
6
+ const left2 = (_b = secondElement === null || secondElement === void 0 ? void 0 : secondElement.style) === null || _b === void 0 ? void 0 : _b.left;
7
+ return parseFloat(left1) > parseFloat(left2);
8
+ };
9
+ const prepareSelectedElements = () => {
10
+ const selection = window.getSelection();
11
+ if (!selection || !selection.rangeCount)
12
+ return [];
13
+ const range = selection.getRangeAt(0);
14
+ const selectedContent = range.cloneContents();
15
+ const selectedElements = Array.from(selectedContent.querySelectorAll('*')).filter(element => !element.children.length);
16
+ const elements = [];
17
+ selectedElements.forEach((element, idx) => {
18
+ const previousElement = selectedElements[idx - 1];
19
+ if (previousElement) {
20
+ if (isElementOnNextLine(previousElement, element)) {
21
+ const spacer = document.createElement('span');
22
+ spacer.innerText = ' ';
23
+ elements.push(spacer);
24
+ }
25
+ }
26
+ elements.push(element);
27
+ });
28
+ return elements;
29
+ };
30
+ export const getSelectedText = () => {
31
+ const elementsSelected = prepareSelectedElements();
32
+ if (elementsSelected.length <= 1) {
33
+ const selection = window.getSelection();
34
+ return (selection && selection.toString()) || '';
35
+ }
36
+ const selectedText = elementsSelected.reduce((acc, el) => {
37
+ let newText = acc;
38
+ newText += el.innerText;
39
+ if (el.tagName === 'BR') {
40
+ newText += '\n';
41
+ }
42
+ return newText;
43
+ }, '');
44
+ return selectedText;
45
+ };
46
+ //# sourceMappingURL=getSelectedText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getSelectedText.js","sourceRoot":"","sources":["../src/getSelectedText.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG,CAAC,YAAyB,EAAE,aAA0B,EAAE,EAAE;;IACpF,IAAI,CAAC,YAAY,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,KAAK,GAAG,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,KAAK,0CAAE,IAAI,CAAC;IACxC,MAAM,KAAK,GAAG,MAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,KAAK,0CAAE,IAAI,CAAC;IACzC,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,GAAkB,EAAE;IAClD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACxC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAEnD,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,eAAe,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;IAC9C,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAC/E,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CACd,CAAC;IACxB,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,gBAAgB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;QACxC,MAAM,eAAe,GAAG,gBAAgB,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,mBAAmB,CAAC,eAAe,EAAE,OAAO,CAAC,EAAE,CAAC;gBAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;gBAC9C,MAAM,CAAC,SAAS,GAAG,GAAG,CAAC;gBACvB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAW,EAAE;IAC1C,MAAM,gBAAgB,GAAG,uBAAuB,EAAE,CAAC;IACnD,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;QACxC,OAAO,CAAC,SAAS,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE;QACvD,IAAI,OAAO,GAAG,GAAG,CAAC;QAClB,OAAO,IAAI,EAAE,CAAC,SAAS,CAAC;QACxB,IAAI,EAAE,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YACxB,OAAO,IAAI,IAAI,CAAC;QAClB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huridocs/react-text-selection-handler",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "main": "./dist/index.js",
5
5
  "description": "React pdf handler allows to render a PDF and handle text selection and highlights.",
6
6
  "author": "HURIDOCS",
@@ -1,7 +1,8 @@
1
- import React, { FunctionComponent, useRef } from 'react';
1
+ import React, { FunctionComponent, useRef, useEffect } from 'react';
2
2
  import { elementContainsDomRect } from './elementContainsDomRect';
3
3
  import { rangeToTextRects } from './rangeToTextRects';
4
4
  import { domRectToSelectionRectangle, TextSelection } from './TextSelection';
5
+ import { getSelectedText } from './getSelectedText';
5
6
 
6
7
  interface SelectionHandlerProps {
7
8
  onSelect: (textSelection: TextSelection) => any;
@@ -51,10 +52,34 @@ const HandleTextSelection: FunctionComponent<SelectionHandlerProps> = ({
51
52
  return domRectToSelectionRectangle(rectangle, region);
52
53
  })
53
54
  .filter(notNull);
54
-
55
- onSelect({ text: selection.toString(), selectionRectangles });
55
+ const text = getSelectedText();
56
+ onSelect({ text, selectionRectangles });
56
57
  };
57
58
 
59
+ useEffect(() => {
60
+ const refElement = ref.current;
61
+
62
+ if (!refElement) {
63
+ return () => {};
64
+ }
65
+
66
+ const handleKeyDown = (event: KeyboardEvent) => {
67
+ if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
68
+ event.preventDefault();
69
+ const selection = window.getSelection();
70
+ if (selection && selection.toString().trim()) {
71
+ const text = getSelectedText();
72
+ navigator.clipboard.writeText(text);
73
+ }
74
+ }
75
+ };
76
+
77
+ refElement.addEventListener('keydown', handleKeyDown);
78
+ return () => {
79
+ refElement.removeEventListener('keydown', handleKeyDown);
80
+ };
81
+ }, [ref]);
82
+
58
83
  return (
59
84
  <div
60
85
  role="none"
@@ -0,0 +1,51 @@
1
+ const isElementOnNextLine = (firstElement: HTMLElement, secondElement: HTMLElement) => {
2
+ if (!firstElement || !secondElement) return false;
3
+ const left1 = firstElement?.style?.left;
4
+ const left2 = secondElement?.style?.left;
5
+ return parseFloat(left1) > parseFloat(left2);
6
+ };
7
+
8
+ const prepareSelectedElements = (): HTMLElement[] => {
9
+ const selection = window.getSelection();
10
+ if (!selection || !selection.rangeCount) return [];
11
+
12
+ const range = selection.getRangeAt(0);
13
+ const selectedContent = range.cloneContents();
14
+ const selectedElements = Array.from(selectedContent.querySelectorAll('*')).filter(
15
+ element => !element.children.length
16
+ ) as Array<HTMLElement>;
17
+ const elements: HTMLElement[] = [];
18
+
19
+ selectedElements.forEach((element, idx) => {
20
+ const previousElement = selectedElements[idx - 1];
21
+ if (previousElement) {
22
+ if (isElementOnNextLine(previousElement, element)) {
23
+ const spacer = document.createElement('span');
24
+ spacer.innerText = ' ';
25
+ elements.push(spacer);
26
+ }
27
+ }
28
+ elements.push(element);
29
+ });
30
+
31
+ return elements;
32
+ };
33
+
34
+ export const getSelectedText = (): string => {
35
+ const elementsSelected = prepareSelectedElements();
36
+ if (elementsSelected.length <= 1) {
37
+ const selection = window.getSelection();
38
+ return (selection && selection.toString()) || '';
39
+ }
40
+
41
+ const selectedText = elementsSelected.reduce((acc, el) => {
42
+ let newText = acc;
43
+ newText += el.innerText;
44
+ if (el.tagName === 'BR') {
45
+ newText += '\n';
46
+ }
47
+ return newText;
48
+ }, '');
49
+
50
+ return selectedText;
51
+ };