@soomo/react-text-annotator 3.0.0-staging.4 → 3.0.0-staging.41
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/dist/TextAnnotator.d.ts +3 -3
- package/dist/TextAnnotator.d.ts.map +1 -1
- package/dist/TextAnnotatorPlugin.d.ts +1 -2
- package/dist/TextAnnotatorPlugin.d.ts.map +1 -1
- package/dist/TextAnnotatorPopup/TextAnnotatorPopup.d.ts +16 -0
- package/dist/TextAnnotatorPopup/TextAnnotatorPopup.d.ts.map +1 -0
- package/dist/TextAnnotatorPopup/index.d.ts +2 -0
- package/dist/TextAnnotatorPopup/index.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useAnnouncePopupNavigation.d.ts +10 -0
- package/dist/hooks/useAnnouncePopupNavigation.d.ts.map +1 -0
- package/dist/hooks/useRestoreSelectionCaret.d.ts +13 -0
- package/dist/hooks/useRestoreSelectionCaret.d.ts.map +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/react-text-annotator.css +31 -1
- package/dist/react-text-annotator.es.js +14 -4
- package/dist/react-text-annotator.es.js.map +1 -1
- package/dist/react-text-annotator.es11.js +1389 -827
- package/dist/react-text-annotator.es11.js.map +1 -1
- package/dist/react-text-annotator.es13.js +241 -2
- package/dist/react-text-annotator.es13.js.map +1 -1
- package/dist/react-text-annotator.es14.js +560 -105
- package/dist/react-text-annotator.es14.js.map +1 -1
- package/dist/react-text-annotator.es15.js +438 -260
- package/dist/react-text-annotator.es15.js.map +1 -1
- package/dist/react-text-annotator.es16.js +57 -51
- package/dist/react-text-annotator.es16.js.map +1 -1
- package/dist/react-text-annotator.es17.js +41 -16
- package/dist/react-text-annotator.es17.js.map +1 -1
- package/dist/react-text-annotator.es18.js +5 -0
- package/dist/react-text-annotator.es18.js.map +1 -0
- package/dist/{react-text-annotator.es10.js → react-text-annotator.es19.js} +7 -11
- package/dist/{react-text-annotator.es10.js.map → react-text-annotator.es19.js.map} +1 -1
- package/dist/react-text-annotator.es2.js +2 -2
- package/dist/react-text-annotator.es20.js +901 -0
- package/dist/react-text-annotator.es20.js.map +1 -0
- package/dist/react-text-annotator.es21.js +130 -0
- package/dist/react-text-annotator.es21.js.map +1 -0
- package/dist/react-text-annotator.es22.js +155 -0
- package/dist/react-text-annotator.es22.js.map +1 -0
- package/dist/react-text-annotator.es23.js +314 -0
- package/dist/react-text-annotator.es23.js.map +1 -0
- package/dist/react-text-annotator.es24.js +117 -0
- package/dist/react-text-annotator.es24.js.map +1 -0
- package/dist/react-text-annotator.es25.js +312 -0
- package/dist/react-text-annotator.es25.js.map +1 -0
- package/dist/react-text-annotator.es26.js +61 -0
- package/dist/react-text-annotator.es26.js.map +1 -0
- package/dist/react-text-annotator.es27.js +23 -0
- package/dist/react-text-annotator.es27.js.map +1 -0
- package/dist/{react-text-annotator.es12.js → react-text-annotator.es28.js} +1 -1
- package/dist/react-text-annotator.es28.js.map +1 -0
- package/dist/react-text-annotator.es29.js +5 -0
- package/dist/react-text-annotator.es29.js.map +1 -0
- package/dist/react-text-annotator.es3.js +2 -2
- package/dist/react-text-annotator.es30.js +152 -0
- package/dist/react-text-annotator.es30.js.map +1 -0
- package/dist/react-text-annotator.es31.js +563 -0
- package/dist/react-text-annotator.es31.js.map +1 -0
- package/dist/react-text-annotator.es4.js +29 -27
- package/dist/react-text-annotator.es4.js.map +1 -1
- package/dist/react-text-annotator.es5.js +38 -48
- package/dist/react-text-annotator.es5.js.map +1 -1
- package/dist/react-text-annotator.es6.js +25 -10
- package/dist/react-text-annotator.es6.js.map +1 -1
- package/dist/react-text-annotator.es7.js +134 -1
- package/dist/react-text-annotator.es7.js.map +1 -1
- package/dist/react-text-annotator.es8.js +177 -486
- package/dist/react-text-annotator.es8.js.map +1 -1
- package/dist/react-text-annotator.es9.js +10 -2
- package/dist/react-text-annotator.es9.js.map +1 -1
- package/dist/tei/TEIAnnotator.d.ts +2 -2
- package/package.json +23 -15
- package/dist/TextAnnotatorPopup.d.ts +0 -14
- package/dist/TextAnnotatorPopup.d.ts.map +0 -1
- package/dist/react-text-annotator.es12.js.map +0 -1
|
@@ -1,33 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const { anno, setAnno } = useContext(AnnotoriousContext);
|
|
1
|
+
import { useRef, useEffect } from "react";
|
|
2
|
+
import { useSelection } from "@annotorious/react";
|
|
3
|
+
const useRestoreSelectionCaret = (args) => {
|
|
4
|
+
var _a;
|
|
5
|
+
const { floatingOpen } = args;
|
|
6
|
+
const { selected } = useSelection();
|
|
7
|
+
const annotation = (_a = selected[0]) == null ? void 0 : _a.annotation;
|
|
8
|
+
const selectionRangeRef = useRef(null);
|
|
10
9
|
useEffect(() => {
|
|
11
|
-
if (!
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}, [setAnno]);
|
|
10
|
+
if (!floatingOpen || !annotation) return;
|
|
11
|
+
const sel = document.getSelection();
|
|
12
|
+
if (sel) {
|
|
13
|
+
selectionRangeRef.current = sel.getRangeAt(0).cloneRange();
|
|
14
|
+
}
|
|
15
|
+
}, [floatingOpen, annotation]);
|
|
18
16
|
useEffect(() => {
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
if (floatingOpen) return;
|
|
18
|
+
const { current: selectionRange } = selectionRangeRef;
|
|
19
|
+
if (!selectionRange) return;
|
|
20
|
+
const { startContainer, startOffset } = selectionRange;
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
const sel = document.getSelection();
|
|
23
|
+
if (sel && sel.isCollapsed && sel.anchorNode === document.body) {
|
|
24
|
+
sel.removeAllRanges();
|
|
25
|
+
sel.setPosition(startContainer, startOffset);
|
|
26
|
+
const startContainerElement = startContainer instanceof HTMLElement ? startContainer : startContainer.parentElement;
|
|
27
|
+
startContainerElement.focus({ preventScroll: true });
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}, [floatingOpen]);
|
|
29
31
|
};
|
|
30
32
|
export {
|
|
31
|
-
|
|
33
|
+
useRestoreSelectionCaret
|
|
32
34
|
};
|
|
33
35
|
//# sourceMappingURL=react-text-annotator.es4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-text-annotator.es4.js","sources":["../src/
|
|
1
|
+
{"version":3,"file":"react-text-annotator.es4.js","sources":["../src/hooks/useRestoreSelectionCaret.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\n\nimport { useSelection } from '@annotorious/react';\nimport type { TextAnnotation } from '@recogito/text-annotator';\n\n/**\n * Restores the caret position after the floating element gets closed\n * and the selection is lost and moved to the `body`.\n * The caret is placed at the start of the previous selection range.\n *\n * However, when the floating element is dismissed with intentional\n * caret repositioning via the mouse click or arrow key navigation ->\n * we shouldn't restore its position to the previous selection.\n */\nexport const useRestoreSelectionCaret = (args: { floatingOpen: boolean }) => {\n const { floatingOpen } = args;\n\n const { selected } = useSelection<TextAnnotation>();\n const annotation = selected[0]?.annotation;\n\n const selectionRangeRef = useRef<Range | null>(null);\n\n useEffect(() => {\n if (!floatingOpen || !annotation) return;\n\n const sel = document.getSelection();\n if (sel) {\n selectionRangeRef.current = sel.getRangeAt(0).cloneRange();\n }\n }, [floatingOpen, annotation]);\n\n useEffect(() => {\n if (floatingOpen) return;\n\n const { current: selectionRange } = selectionRangeRef;\n if (!selectionRange) return;\n\n const { startContainer, startOffset } = selectionRange;\n\n setTimeout(() => {\n const sel = document.getSelection();\n if (sel && sel.isCollapsed && sel.anchorNode === document.body) {\n sel.removeAllRanges();\n sel.setPosition(startContainer, startOffset);\n\n const startContainerElement = startContainer instanceof HTMLElement\n ? startContainer\n : startContainer.parentElement;\n startContainerElement.focus({ preventScroll: true });\n }\n });\n }, [floatingOpen]);\n};\n"],"names":[],"mappings":";;AAca,MAAA,2BAA2B,CAAC,SAAoC;;AACrE,QAAA,EAAE,aAAiB,IAAA;AAEnB,QAAA,EAAE,aAAa;AACf,QAAA,cAAa,cAAS,CAAC,MAAV,mBAAa;AAE1B,QAAA,oBAAoB,OAAqB,IAAI;AAEnD,YAAU,MAAM;AACV,QAAA,CAAC,gBAAgB,CAAC,WAAY;AAE5B,UAAA,MAAM,SAAS;AACrB,QAAI,KAAK;AACP,wBAAkB,UAAU,IAAI,WAAW,CAAC,EAAE;IAChD;AAAA,EAAA,GACC,CAAC,cAAc,UAAU,CAAC;AAE7B,YAAU,MAAM;AACd,QAAI,aAAc;AAEZ,UAAA,EAAE,SAAS,eAAmB,IAAA;AACpC,QAAI,CAAC,eAAgB;AAEf,UAAA,EAAE,gBAAgB,YAAgB,IAAA;AAExC,eAAW,MAAM;AACT,YAAA,MAAM,SAAS;AACrB,UAAI,OAAO,IAAI,eAAe,IAAI,eAAe,SAAS,MAAM;AAC9D,YAAI,gBAAgB;AAChB,YAAA,YAAY,gBAAgB,WAAW;AAE3C,cAAM,wBAAwB,0BAA0B,cACpD,iBACA,eAAe;AACnB,8BAAsB,MAAM,EAAE,eAAe,KAAM,CAAA;AAAA,MACrD;AAAA,IAAA,CACD;AAAA,EAAA,GACA,CAAC,YAAY,CAAC;AACnB;"}
|
|
@@ -1,53 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useEffect } from "react";
|
|
2
|
+
import { useAnnotationStore, useSelection, Origin } from "@annotorious/react";
|
|
3
|
+
import { announce as $319e236875307eab$export$a9b970dcc4ae71a9, destroyAnnouncer as $319e236875307eab$export$d8686216b8b81b2f } from "./react-text-annotator.es16.js";
|
|
4
|
+
import { exhaustiveUniqueRandom } from "./react-text-annotator.es17.js";
|
|
5
|
+
const useAnnouncePopupNavigation = (args) => {
|
|
6
|
+
const {
|
|
7
|
+
message = "Press Tab to move to Notes Dialog",
|
|
8
|
+
idle = 700,
|
|
9
|
+
floatingOpen,
|
|
10
|
+
disabled = false
|
|
11
|
+
} = args;
|
|
12
|
+
const store = useAnnotationStore();
|
|
13
|
+
const { event } = useSelection();
|
|
14
|
+
const uniqueRandom = useCallback(exhaustiveUniqueRandom(1, 1e4), []);
|
|
15
|
+
useLayoutEffect(() => {
|
|
16
|
+
if (disabled || !message) return;
|
|
17
|
+
$319e236875307eab$export$a9b970dcc4ae71a9("", "polite");
|
|
18
|
+
return () => $319e236875307eab$export$d8686216b8b81b2f();
|
|
19
|
+
}, [disabled, message]);
|
|
20
|
+
const announcementSeed = useMemo(() => floatingOpen ? uniqueRandom() : 0, [floatingOpen]);
|
|
21
|
+
const announcePopupNavigation = useCallback(() => {
|
|
22
|
+
const uniqueSpaces = Array.from({ length: announcementSeed }).map(() => " ").join("");
|
|
23
|
+
$319e236875307eab$export$a9b970dcc4ae71a9(`${message} ${uniqueSpaces}`, "polite");
|
|
24
|
+
}, [message, announcementSeed]);
|
|
25
|
+
const idleTimeoutRef = useRef(null);
|
|
10
26
|
useEffect(() => {
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let x = pointerEvent.clientX - left;
|
|
24
|
-
let y = pointerEvent.clientY - top;
|
|
25
|
-
const { id } = selected[0].annotation;
|
|
26
|
-
const { offsetX, offsetY } = pointerEvent;
|
|
27
|
-
const bounds = r.state.store.getAnnotationBounds(id, offsetX, offsetY);
|
|
28
|
-
if (bounds) {
|
|
29
|
-
x = Math.max(x, bounds.x - left);
|
|
30
|
-
x = Math.min(x, bounds.right - left);
|
|
31
|
-
}
|
|
32
|
-
el.current.style.left = `${x}px`;
|
|
33
|
-
el.current.style.top = `${y}px`;
|
|
34
|
-
}, [open, pointerEvent, r == null ? void 0 : r.element]);
|
|
35
|
-
const onPointerUp = (evt) => evt.stopPropagation();
|
|
36
|
-
return open && selected.length > 0 ? createPortal(
|
|
37
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
38
|
-
"div",
|
|
39
|
-
{
|
|
40
|
-
ref: el,
|
|
41
|
-
className: "a9s-popup r6o-popup not-annotatable",
|
|
42
|
-
style: { position: "absolute" },
|
|
43
|
-
onPointerUp,
|
|
44
|
-
children: props.popup({ selected })
|
|
45
|
-
}
|
|
46
|
-
),
|
|
47
|
-
r.element
|
|
48
|
-
) : null;
|
|
27
|
+
if (disabled || !floatingOpen || !message) return;
|
|
28
|
+
const scheduleIdleAnnouncement = () => {
|
|
29
|
+
clearTimeout(idleTimeoutRef.current);
|
|
30
|
+
idleTimeoutRef.current = setTimeout(announcePopupNavigation, idle);
|
|
31
|
+
};
|
|
32
|
+
scheduleIdleAnnouncement();
|
|
33
|
+
store.observe(scheduleIdleAnnouncement, { origin: Origin.LOCAL });
|
|
34
|
+
return () => {
|
|
35
|
+
clearTimeout(idleTimeoutRef.current);
|
|
36
|
+
store.unobserve(scheduleIdleAnnouncement);
|
|
37
|
+
};
|
|
38
|
+
}, [disabled, floatingOpen, event == null ? void 0 : event.type, message, announcePopupNavigation, store]);
|
|
49
39
|
};
|
|
50
40
|
export {
|
|
51
|
-
|
|
41
|
+
useAnnouncePopupNavigation
|
|
52
42
|
};
|
|
53
43
|
//# sourceMappingURL=react-text-annotator.es5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-text-annotator.es5.js","sources":["../src/
|
|
1
|
+
{"version":3,"file":"react-text-annotator.es5.js","sources":["../src/hooks/useAnnouncePopupNavigation.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';\n\nimport { Origin, useAnnotationStore, useSelection } from '@annotorious/react';\nimport type { TextAnnotation } from '@recogito/text-annotator';\nimport { announce, destroyAnnouncer } from '@react-aria/live-announcer';\nimport { exhaustiveUniqueRandom } from 'unique-random';\n\ninterface AnnouncePopupOpeningArgs {\n message?: string;\n idle?: number;\n floatingOpen: boolean;\n floatingFocused?: boolean;\n disabled?: boolean;\n}\n\nexport const useAnnouncePopupNavigation = (args: AnnouncePopupOpeningArgs) => {\n const {\n message = 'Press Tab to move to Notes Dialog',\n idle = 700,\n floatingOpen,\n disabled = false\n } = args;\n\n const store = useAnnotationStore();\n const { event } = useSelection<TextAnnotation>();\n\n // Generate random numbers that do not repeat until the entire 1-10000 range has appeared\n const uniqueRandom = useCallback(exhaustiveUniqueRandom(1, 10000), []);\n\n /**\n * Initialize the `LiveAnnouncer` class and\n * its `polite` announcements live area\n */\n useLayoutEffect(() => {\n if (disabled || !message) return;\n\n announce('', 'polite');\n return () => destroyAnnouncer();\n }, [disabled, message]);\n\n /**\n * Screen reader requires messages to always be unique!\n * Otherwise, the hint will be announced once per page.\n */\n const announcementSeed = useMemo(() => floatingOpen ? uniqueRandom() : 0, [floatingOpen]);\n\n const announcePopupNavigation = useCallback(() => {\n /**\n * To imitate the uniqueness of the announced message\n * w/o mutating it - we can append spaces at the end.\n */\n const uniqueSpaces = Array.from({ length: announcementSeed }).map(() => ' ').join('');\n announce(`${message} ${uniqueSpaces}`, 'polite');\n }, [message, announcementSeed]);\n\n const idleTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (disabled || !floatingOpen || !message) return;\n\n const scheduleIdleAnnouncement = () => {\n clearTimeout(idleTimeoutRef.current);\n idleTimeoutRef.current = setTimeout(announcePopupNavigation, idle);\n };\n\n scheduleIdleAnnouncement();\n store.observe(scheduleIdleAnnouncement, { origin: Origin.LOCAL });\n\n return () => {\n clearTimeout(idleTimeoutRef.current);\n store.unobserve(scheduleIdleAnnouncement);\n };\n }, [disabled, floatingOpen, event?.type, message, announcePopupNavigation, store]);\n\n};\n"],"names":["announce","destroyAnnouncer"],"mappings":";;;;AAea,MAAA,6BAA6B,CAAC,SAAmC;AACtE,QAAA;AAAA,IACJ,UAAU;AAAA,IACV,OAAO;AAAA,IACP;AAAA,IACA,WAAW;AAAA,EACT,IAAA;AAEJ,QAAM,QAAQ;AACR,QAAA,EAAE,UAAU;AAGlB,QAAM,eAAe,YAAY,uBAAuB,GAAG,GAAK,GAAG,CAAA,CAAE;AAMrE,kBAAgB,MAAM;AAChB,QAAA,YAAY,CAAC,QAAS;AAE1BA,8CAAS,IAAI,QAAQ;AACrB,WAAO,MAAMC,0CAAiB;AAAA,EAAA,GAC7B,CAAC,UAAU,OAAO,CAAC;AAMhB,QAAA,mBAAmB,QAAQ,MAAM,eAAe,iBAAiB,GAAG,CAAC,YAAY,CAAC;AAElF,QAAA,0BAA0B,YAAY,MAAM;AAKhD,UAAM,eAAe,MAAM,KAAK,EAAE,QAAQ,iBAAA,CAAkB,EAAE,IAAI,MAAM,GAAG,EAAE,KAAK,EAAE;AACpFD,8CAAS,GAAG,OAAO,IAAI,YAAY,IAAI,QAAQ;AAAA,EAAA,GAC9C,CAAC,SAAS,gBAAgB,CAAC;AAExB,QAAA,iBAAiB,OAA6C,IAAI;AAExE,YAAU,MAAM;AACd,QAAI,YAAY,CAAC,gBAAgB,CAAC,QAAS;AAE3C,UAAM,2BAA2B,MAAM;AACrC,mBAAa,eAAe,OAAO;AACpB,qBAAA,UAAU,WAAW,yBAAyB,IAAI;AAAA,IAAA;AAG1C;AACzB,UAAM,QAAQ,0BAA0B,EAAE,QAAQ,OAAO,OAAO;AAEhE,WAAO,MAAM;AACX,mBAAa,eAAe,OAAO;AACnC,YAAM,UAAU,wBAAwB;AAAA,IAAA;AAAA,EAC1C,GACC,CAAC,UAAU,cAAc,+BAAO,MAAM,SAAS,yBAAyB,KAAK,CAAC;AAEnF;"}
|
|
@@ -1,13 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
1
|
+
import { j as jsxRuntimeExports } from "./react-text-annotator.es9.js";
|
|
2
|
+
import { useRef, useContext, useEffect } from "react";
|
|
3
|
+
import { AnnotoriousContext } from "@annotorious/react";
|
|
4
|
+
import { createTextAnnotator } from "@soomo/text-annotator";
|
|
5
|
+
/* empty css */
|
|
6
|
+
const TextAnnotator = (props) => {
|
|
7
|
+
const el = useRef(null);
|
|
8
|
+
const { className, children, ...opts } = props;
|
|
9
|
+
const { annotatingEnabled, style, filter, userSelectAction, user } = opts;
|
|
10
|
+
const { anno, setAnno } = useContext(AnnotoriousContext);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!setAnno) return;
|
|
13
|
+
const adapter = typeof opts.adapter === "function" ? opts.adapter(el.current) : opts.adapter;
|
|
14
|
+
const anno2 = createTextAnnotator(el.current, { ...opts, adapter });
|
|
15
|
+
setAnno(anno2);
|
|
16
|
+
return () => anno2.destroy();
|
|
17
|
+
}, [setAnno]);
|
|
18
|
+
useEffect(() => anno == null ? void 0 : anno.setStyle(style), [anno, style]);
|
|
19
|
+
useEffect(() => anno == null ? void 0 : anno.setFilter(filter), [anno, filter]);
|
|
20
|
+
useEffect(() => anno == null ? void 0 : anno.setUserSelectAction(userSelectAction), [anno, userSelectAction]);
|
|
21
|
+
useEffect(() => anno == null ? void 0 : anno.setUser(user), [anno, user]);
|
|
22
|
+
useEffect(() => anno == null ? void 0 : anno.setAnnotatingEnabled(annotatingEnabled), [anno, annotatingEnabled]);
|
|
23
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: el, className, children });
|
|
24
|
+
};
|
|
10
25
|
export {
|
|
11
|
-
|
|
26
|
+
TextAnnotator
|
|
12
27
|
};
|
|
13
28
|
//# sourceMappingURL=react-text-annotator.es6.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-text-annotator.es6.js","sources":["
|
|
1
|
+
{"version":3,"file":"react-text-annotator.es6.js","sources":["../src/TextAnnotator.tsx"],"sourcesContent":["import { ReactNode, useContext, useEffect, useRef } from 'react';\nimport { AnnotoriousContext, Filter } from '@annotorious/react';\nimport type { FormatAdapter } from '@annotorious/core';\nimport type { HighlightStyleExpression, TextAnnotation, TextAnnotatorOptions } from '@soomo/text-annotator';\nimport { createTextAnnotator } from '@soomo/text-annotator';\n\nimport '@soomo/text-annotator/dist/text-annotator.css';\n\n\nexport interface TextAnnotatorProps<E extends unknown> extends Omit<TextAnnotatorOptions<E>, 'adapter'> {\n\n children?: ReactNode | JSX.Element;\n\n adapter?: FormatAdapter<TextAnnotation, E> | ((container: HTMLElement) => FormatAdapter<TextAnnotation, E>) | null;\n\n filter?: Filter;\n\n style?: HighlightStyleExpression;\n\n className?: string;\n\n}\n\nexport const TextAnnotator = <E extends unknown>(props: TextAnnotatorProps<E>) => {\n\n const el = useRef<HTMLDivElement>(null);\n\n const { className, children, ...opts } = props;\n const { annotatingEnabled, style, filter, userSelectAction, user } = opts;\n\n const { anno, setAnno } = useContext(AnnotoriousContext);\n\n useEffect(() => {\n if (!setAnno) return;\n\n const adapter = typeof opts.adapter === 'function' ? opts.adapter(el.current) : opts.adapter;\n\n const anno = createTextAnnotator(el.current, { ...opts, adapter });\n setAnno(anno);\n\n return () => anno.destroy();\n }, [setAnno]);\n\n useEffect(() => anno?.setStyle(style), [anno, style]);\n\n useEffect(() => anno?.setFilter(filter), [anno, filter]);\n\n useEffect(() => anno?.setUserSelectAction(userSelectAction), [anno, userSelectAction]);\n\n useEffect(() => anno?.setUser(user), [anno, user]);\n\n useEffect(() => anno?.setAnnotatingEnabled(annotatingEnabled), [anno, annotatingEnabled]);\n\n return (\n <div ref={el} className={className}>\n {children}\n </div>\n );\n\n};\n"],"names":["anno","jsx"],"mappings":";;;;;AAuBa,MAAA,gBAAgB,CAAoB,UAAiC;AAE1E,QAAA,KAAK,OAAuB,IAAI;AAEtC,QAAM,EAAE,WAAW,UAAU,GAAG,SAAS;AACzC,QAAM,EAAE,mBAAmB,OAAO,QAAQ,kBAAkB,KAAS,IAAA;AAErE,QAAM,EAAE,MAAM,QAAQ,IAAI,WAAW,kBAAkB;AAEvD,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAER,UAAA,UAAU,OAAO,KAAK,YAAY,aAAa,KAAK,QAAQ,GAAG,OAAO,IAAI,KAAK;AAE/EA,UAAAA,QAAO,oBAAoB,GAAG,SAAS,EAAE,GAAG,MAAM,SAAS;AACjE,YAAQA,KAAI;AAEL,WAAA,MAAMA,MAAK;EAAQ,GACzB,CAAC,OAAO,CAAC;AAEF,YAAA,MAAM,6BAAM,SAAS,QAAQ,CAAC,MAAM,KAAK,CAAC;AAE1C,YAAA,MAAM,6BAAM,UAAU,SAAS,CAAC,MAAM,MAAM,CAAC;AAE7C,YAAA,MAAM,6BAAM,oBAAoB,mBAAmB,CAAC,MAAM,gBAAgB,CAAC;AAE3E,YAAA,MAAM,6BAAM,QAAQ,OAAO,CAAC,MAAM,IAAI,CAAC;AAEvC,YAAA,MAAM,6BAAM,qBAAqB,oBAAoB,CAAC,MAAM,iBAAiB,CAAC;AAExF,SACGC,kCAAAA,IAAA,OAAA,EAAI,KAAK,IAAI,WACX,SACH,CAAA;AAGJ;"}
|
|
@@ -1,2 +1,135 @@
|
|
|
1
|
-
|
|
1
|
+
import { j as jsxRuntimeExports } from "./react-text-annotator.es9.js";
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
|
+
import { useFloating, useDismiss, useRole, useInteractions, FloatingPortal, FloatingFocusManager } from "./react-text-annotator.es11.js";
|
|
4
|
+
import { useAnnotator, useSelection } from "@annotorious/react";
|
|
5
|
+
import { denormalizeRectWithOffset, toDomRectList } from "@soomo/text-annotator";
|
|
6
|
+
import { useRestoreSelectionCaret } from "./react-text-annotator.es4.js";
|
|
7
|
+
import { useAnnouncePopupNavigation } from "./react-text-annotator.es5.js";
|
|
8
|
+
/* empty css */
|
|
9
|
+
import { offset, inline, flip, shift } from "./react-text-annotator.es13.js";
|
|
10
|
+
import { autoUpdate } from "./react-text-annotator.es14.js";
|
|
11
|
+
const TextAnnotatorPopup = (props) => {
|
|
12
|
+
var _a;
|
|
13
|
+
const { popup, popupNavigationMessage } = props;
|
|
14
|
+
const r = useAnnotator();
|
|
15
|
+
const { selected, event } = useSelection();
|
|
16
|
+
const annotation = (_a = selected[0]) == null ? void 0 : _a.annotation;
|
|
17
|
+
const [isOpen, setOpen] = useState((selected == null ? void 0 : selected.length) > 0);
|
|
18
|
+
const handleClose = () => r == null ? void 0 : r.cancelSelected();
|
|
19
|
+
const [isFloatingFocused, setFloatingFocused] = useState(false);
|
|
20
|
+
const handleFloatingFocus = () => setFloatingFocused(true);
|
|
21
|
+
const handleFloatingBlur = () => setFloatingFocused(false);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!isOpen) handleFloatingBlur();
|
|
24
|
+
}, [isOpen, handleFloatingBlur]);
|
|
25
|
+
const { refs, floatingStyles, update, context } = useFloating({
|
|
26
|
+
placement: "top",
|
|
27
|
+
open: isOpen,
|
|
28
|
+
onOpenChange: (open, event2, reason) => {
|
|
29
|
+
setOpen(open);
|
|
30
|
+
if (!open) {
|
|
31
|
+
if (reason === "escape-key" || /**
|
|
32
|
+
* When the focus leaves the floating - cancel the selection.
|
|
33
|
+
* However, it doesn't have a distinct reason yet, will be resolved in the discussion:
|
|
34
|
+
* @see https://github.com/floating-ui/floating-ui/discussions/3012#discussioncomment-10405906
|
|
35
|
+
*/
|
|
36
|
+
event2 instanceof FocusEvent) {
|
|
37
|
+
handleClose();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
middleware: [
|
|
42
|
+
offset(10),
|
|
43
|
+
inline(),
|
|
44
|
+
flip(),
|
|
45
|
+
shift({ mainAxis: false, crossAxis: true, padding: 10 })
|
|
46
|
+
],
|
|
47
|
+
whileElementsMounted: autoUpdate
|
|
48
|
+
});
|
|
49
|
+
const dismiss = useDismiss(context);
|
|
50
|
+
const role = useRole(context, { role: "dialog" });
|
|
51
|
+
const { getFloatingProps } = useInteractions([dismiss, role]);
|
|
52
|
+
const selectedKey = selected.map((a) => a.annotation.id).join("-");
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (selected.length > 0 && event) {
|
|
55
|
+
setOpen(event.type === "pointerup" || event.type === "keydown");
|
|
56
|
+
}
|
|
57
|
+
}, [selectedKey, event]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (selected.length === 0 && isOpen) {
|
|
60
|
+
setOpen(false);
|
|
61
|
+
}
|
|
62
|
+
}, [isOpen, selectedKey]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!isOpen || !(annotation == null ? void 0 : annotation.id) || !r) return;
|
|
65
|
+
refs.setPositionReference({
|
|
66
|
+
getBoundingClientRect: () => denormalizeRectWithOffset(
|
|
67
|
+
r.state.store.getAnnotationBounds(annotation.id),
|
|
68
|
+
r.element.getBoundingClientRect()
|
|
69
|
+
),
|
|
70
|
+
getClientRects: () => {
|
|
71
|
+
const rects = r.state.store.getAnnotationRects(annotation.id);
|
|
72
|
+
const denormalizedRects = rects.map(
|
|
73
|
+
(rect) => denormalizeRectWithOffset(rect, r.element.getBoundingClientRect())
|
|
74
|
+
);
|
|
75
|
+
return toDomRectList(denormalizedRects);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}, [isOpen, annotation == null ? void 0 : annotation.id, r]);
|
|
79
|
+
const getStopEventsPropagationProps = useCallback(
|
|
80
|
+
() => ({ onPointerUp: (event2) => event2.stopPropagation() }),
|
|
81
|
+
[]
|
|
82
|
+
);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const config = { attributes: true, childList: true, subtree: true };
|
|
85
|
+
const mutationObserver = new MutationObserver(() => update());
|
|
86
|
+
mutationObserver.observe(document.body, config);
|
|
87
|
+
window.document.addEventListener("scroll", update, true);
|
|
88
|
+
return () => {
|
|
89
|
+
mutationObserver.disconnect();
|
|
90
|
+
window.document.removeEventListener("scroll", update, true);
|
|
91
|
+
};
|
|
92
|
+
}, [update]);
|
|
93
|
+
useRestoreSelectionCaret({ floatingOpen: isOpen });
|
|
94
|
+
useAnnouncePopupNavigation({
|
|
95
|
+
disabled: isFloatingFocused,
|
|
96
|
+
floatingOpen: isOpen,
|
|
97
|
+
message: popupNavigationMessage
|
|
98
|
+
});
|
|
99
|
+
return isOpen && selected.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx(FloatingPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
100
|
+
FloatingFocusManager,
|
|
101
|
+
{
|
|
102
|
+
context,
|
|
103
|
+
modal: false,
|
|
104
|
+
closeOnFocusOut: true,
|
|
105
|
+
initialFocus: (
|
|
106
|
+
/**
|
|
107
|
+
* Don't shift focus to the floating element
|
|
108
|
+
* when the selection performed with the keyboard
|
|
109
|
+
*/
|
|
110
|
+
(event == null ? void 0 : event.type) === "keydown" ? -1 : 0
|
|
111
|
+
),
|
|
112
|
+
returnFocus: false,
|
|
113
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
114
|
+
"div",
|
|
115
|
+
{
|
|
116
|
+
className: "annotation-popup text-annotation-popup not-annotatable",
|
|
117
|
+
ref: refs.setFloating,
|
|
118
|
+
style: floatingStyles,
|
|
119
|
+
onFocus: handleFloatingFocus,
|
|
120
|
+
onBlur: handleFloatingBlur,
|
|
121
|
+
...getFloatingProps(),
|
|
122
|
+
...getStopEventsPropagationProps(),
|
|
123
|
+
children: [
|
|
124
|
+
popup({ selected }),
|
|
125
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "popup-close-message", onClick: handleClose, children: "This dialog closes when you leave it." })
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
) }) : null;
|
|
131
|
+
};
|
|
132
|
+
export {
|
|
133
|
+
TextAnnotatorPopup
|
|
134
|
+
};
|
|
2
135
|
//# sourceMappingURL=react-text-annotator.es7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-text-annotator.es7.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"react-text-annotator.es7.js","sources":["../src/TextAnnotatorPopup/TextAnnotatorPopup.tsx"],"sourcesContent":["import React, { FC, PointerEvent, ReactNode, useCallback, useEffect, useState } from 'react';\nimport {\n autoUpdate,\n flip,\n FloatingFocusManager,\n FloatingPortal,\n inline,\n offset,\n shift,\n useDismiss,\n useFloating,\n useInteractions,\n useRole\n} from '@floating-ui/react';\n\nimport { useAnnotator, useSelection } from '@annotorious/react';\nimport {\n denormalizeRectWithOffset,\n toDomRectList,\n type TextAnnotation,\n type TextAnnotator,\n} from '@soomo/text-annotator';\n\nimport { useAnnouncePopupNavigation, useRestoreSelectionCaret } from '../hooks';\nimport './TextAnnotatorPopup.css';\n\ninterface TextAnnotationPopupProps {\n\n popupNavigationMessage?: string;\n\n popup(props: TextAnnotatorPopupProps): ReactNode;\n\n}\n\nexport interface TextAnnotatorPopupProps {\n\n selected: { annotation: TextAnnotation, editable?: boolean }[];\n\n}\n\nexport const TextAnnotatorPopup: FC<TextAnnotationPopupProps> = (props) => {\n\n const { popup, popupNavigationMessage } = props;\n\n const r = useAnnotator<TextAnnotator>();\n\n const { selected, event } = useSelection<TextAnnotation>();\n const annotation = selected[0]?.annotation;\n\n const [isOpen, setOpen] = useState(selected?.length > 0);\n const handleClose = () => r?.cancelSelected();\n\n const [isFloatingFocused, setFloatingFocused] = useState(false);\n const handleFloatingFocus = () => setFloatingFocused(true);\n const handleFloatingBlur = () => setFloatingFocused(false);\n useEffect(() => {\n if (!isOpen) handleFloatingBlur();\n }, [isOpen, handleFloatingBlur]);\n\n const { refs, floatingStyles, update, context } = useFloating({\n placement: 'top',\n open: isOpen,\n onOpenChange: (open, event, reason) => {\n setOpen(open);\n\n if (!open) {\n if (\n reason === 'escape-key' ||\n /**\n * When the focus leaves the floating - cancel the selection.\n * However, it doesn't have a distinct reason yet, will be resolved in the discussion:\n * @see https://github.com/floating-ui/floating-ui/discussions/3012#discussioncomment-10405906\n */\n event instanceof FocusEvent\n ) {\n handleClose();\n }\n }\n },\n middleware: [\n offset(10),\n inline(),\n flip(),\n shift({ mainAxis: false, crossAxis: true, padding: 10 })\n ],\n whileElementsMounted: autoUpdate\n });\n\n const dismiss = useDismiss(context);\n const role = useRole(context, { role: 'dialog' });\n const { getFloatingProps } = useInteractions([dismiss, role]);\n\n const selectedKey = selected.map(a => a.annotation.id).join('-');\n useEffect(() => {\n // Ignore all selection changes except those accompanied by a user event.\n if (selected.length > 0 && event) {\n setOpen(event.type === 'pointerup' || event.type === 'keydown');\n }\n }, [selectedKey, event]);\n\n useEffect(() => {\n // Close the popup if the selection is cleared\n if (selected.length === 0 && isOpen) {\n setOpen(false);\n }\n }, [isOpen, selectedKey]);\n\n useEffect(() => {\n if (!isOpen || !annotation?.id || !r) return;\n\n refs.setPositionReference({\n getBoundingClientRect: () => denormalizeRectWithOffset(\n r.state.store.getAnnotationBounds(annotation.id),\n r.element.getBoundingClientRect()\n ),\n getClientRects: () => {\n const rects = r.state.store.getAnnotationRects(annotation.id);\n const denormalizedRects = rects.map(\n rect => denormalizeRectWithOffset(rect, r.element.getBoundingClientRect())\n );\n return toDomRectList(denormalizedRects);\n }\n });\n }, [isOpen, annotation?.id, r]);\n\n // Prevent text-annotator from handling the irrelevant events triggered from the popup\n const getStopEventsPropagationProps = useCallback(\n () => ({ onPointerUp: (event: PointerEvent<HTMLDivElement>) => event.stopPropagation() }),\n []\n );\n\n useEffect(() => {\n const config: MutationObserverInit = { attributes: true, childList: true, subtree: true };\n\n const mutationObserver = new MutationObserver(() => update());\n mutationObserver.observe(document.body, config);\n\n window.document.addEventListener('scroll', update, true);\n\n return () => {\n mutationObserver.disconnect();\n window.document.removeEventListener('scroll', update, true);\n }\n }, [update]);\n\n useRestoreSelectionCaret({ floatingOpen: isOpen });\n\n /**\n * Announce the navigation hint only on the keyboard selection,\n * because the focus isn't shifted to the popup automatically then\n */\n useAnnouncePopupNavigation({\n disabled: isFloatingFocused,\n floatingOpen: isOpen,\n message: popupNavigationMessage,\n });\n\n return isOpen && selected.length > 0 ? (\n <FloatingPortal>\n <FloatingFocusManager\n context={context}\n modal={false}\n closeOnFocusOut={true}\n initialFocus={\n /**\n * Don't shift focus to the floating element\n * when the selection performed with the keyboard\n */\n event?.type === 'keydown' ? -1 : 0\n }\n returnFocus={false}\n >\n <div\n className=\"annotation-popup text-annotation-popup not-annotatable\"\n ref={refs.setFloating}\n style={floatingStyles}\n onFocus={handleFloatingFocus}\n onBlur={handleFloatingBlur}\n {...getFloatingProps()}\n {...getStopEventsPropagationProps()}>\n {popup({ selected })}\n\n {/* It lets keyboard/sr users to know that the dialog closes when they focus out of it */}\n <button className=\"popup-close-message\" onClick={handleClose}>\n This dialog closes when you leave it.\n </button>\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n ) : null;\n\n}\n"],"names":["event","jsx","jsxs"],"mappings":"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"}
|