@soomo/react-text-annotator 3.3.0-staging.0 → 3.4.0-staging.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.
@@ -17,17 +17,6 @@ export interface TextAnnotationPopupContentProps<T extends TextAnnotation = Text
17
17
  event?: PointerEvent | KeyboardEvent;
18
18
  }
19
19
  export declare const TextAnnotationPopup: (props: TextAnnotationPopupProps) => import("react/jsx-runtime").JSX.Element;
20
- /**
21
- * Prevent text-annotator from handling the irrelevant events
22
- * triggered from the popup/toolbar/dialog
23
- *
24
- const getStopEventsPropagationProps = <T extends HTMLElement = HTMLElement>() => ({
25
- onPointerUp: (event: React.PointerEvent<T>) => event.stopPropagation(),
26
- onPointerDown: (event: React.PointerEvent<T>) => event.stopPropagation(),
27
- onMouseDown: (event: React.MouseEvent<T>) => event.stopPropagation(),
28
- onMouseUp: (event: React.MouseEvent<T>) => event.stopPropagation()
29
- });
30
- */
31
20
  /** For backwards compatibility **/
32
21
  /** @deprecated Use TextAnnotationPopup instead */
33
22
  export declare const TextAnnotatorPopup: (props: TextAnnotationPopupProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"TextAnnotationPopup.d.ts","sourceRoot":"","sources":["../../src/TextAnnotationPopup/TextAnnotationPopup.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAM,SAAS,EAAqD,MAAM,OAAO,CAAC;AAGhG,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAKL,kBAAkB,EAKlB,SAAS,EAMV,MAAM,oBAAoB,CAAC;AAI5B,OAAO,2BAA2B,CAAC;AAEnC,UAAU,wBAAwB;IAEhC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,KAAK,CAAC,CAAC;IAEzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,KAAK,CAAC,KAAK,EAAE,+BAA+B,GAAG,SAAS,CAAC;IAEzD,OAAO,CAAC,IAAI,IAAI,CAAC;CAElB;AAED,MAAM,WAAW,+BAA+B,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAExF,UAAU,EAAE,CAAC,CAAC;IAEd,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,KAAK,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;CAEtC;AAYD,eAAO,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CAmJlE,CAAC;AAEF;;;;;;;;;;EAUE;AAEF,mCAAmC;AACnC,kDAAkD;AAClD,eAAO,MAAM,kBAAkB,GAAI,OAAO,wBAAwB,4CAOjE,CAAC"}
1
+ {"version":3,"file":"TextAnnotationPopup.d.ts","sourceRoot":"","sources":["../../src/TextAnnotationPopup/TextAnnotationPopup.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAM,SAAS,EAAqD,MAAM,OAAO,CAAC;AAGhG,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAKL,kBAAkB,EAKlB,SAAS,EAMV,MAAM,oBAAoB,CAAC;AAI5B,OAAO,2BAA2B,CAAC;AAEnC,UAAU,wBAAwB;IAEhC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,UAAU,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,KAAK,CAAC,CAAC;IAEzD,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,KAAK,CAAC,KAAK,EAAE,+BAA+B,GAAG,SAAS,CAAC;IAEzD,OAAO,CAAC,IAAI,IAAI,CAAC;CAElB;AAED,MAAM,WAAW,+BAA+B,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc;IAExF,UAAU,EAAE,CAAC,CAAC;IAEd,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,KAAK,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC;CAEtC;AAYD,eAAO,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CA6JlE,CAAC;AAEF,mCAAmC;AACnC,kDAAkD;AAClD,eAAO,MAAM,kBAAkB,GAAI,OAAO,wBAAwB,4CAOjE,CAAC"}
@@ -1,18 +1,18 @@
1
- import { jsx as f, Fragment as k, jsxs as U } from "react/jsx-runtime";
2
- import { useRef as w, useEffect as a, useContext as O, useCallback as x, Children as W, cloneElement as _, useState as S, useMemo as j } from "react";
3
- import D from "CETEIcean";
4
- import { AnnotoriousContext as P, useAnnotationStore as H, Origin as Q, useAnnotator as z, useSelection as V } from "@annotorious/react";
5
- import { AnnotoriousPlugin as Be } from "@annotorious/react";
6
- import { TEIPlugin as Y } from "@recogito/text-annotator-tei";
7
- import { serializeW3CTEIAnnotation as Le } from "@recogito/text-annotator-tei";
8
- import { createTextAnnotator as R, toViewportBounds as B, toDomRectList as $, NOT_ANNOTATABLE_CLASS as q } from "@soomo/text-annotator";
9
- import { W3CTextFormat as Me, parseW3CTextAnnotation as ke, serializeW3CTextAnnotation as Ue } from "@soomo/text-annotator";
1
+ import { jsx as f, Fragment as M, jsxs as k } from "react/jsx-runtime";
2
+ import { useRef as w, useEffect as u, useContext as P, useCallback as v, Children as U, cloneElement as W, useState as x, useMemo as _ } from "react";
3
+ import j from "CETEIcean";
4
+ import { AnnotoriousContext as B, useAnnotationStore as H, Origin as Q, useAnnotator as z, useSelection as D } from "@annotorious/react";
5
+ import { AnnotoriousPlugin as ye } from "@annotorious/react";
6
+ import { TEIPlugin as V } from "@recogito/text-annotator-tei";
7
+ import { serializeW3CTEIAnnotation as Oe } from "@recogito/text-annotator-tei";
8
+ import { createTextAnnotator as L, toViewportBounds as R, toDomRectList as Y, NOT_ANNOTATABLE_CLASS as $ } from "@soomo/text-annotator";
9
+ import { W3CTextFormat as Pe, parseW3CTextAnnotation as Be, serializeW3CTextAnnotation as Le } from "@soomo/text-annotator";
10
10
  import "@soomo/text-annotator/dist/text-annotator.css";
11
- import { Ignore as J } from "@annotorious/core";
12
- import { Origin as _e, UserSelectAction as je, createBody as De } from "@annotorious/core";
13
- import G from "debounce";
14
- import { useFloating as K, autoUpdate as X, inline as Z, offset as ee, flip as te, shift as ne, arrow as oe, useDismiss as re, useRole as se, useInteractions as ie, FloatingPortal as le, FloatingFocusManager as ae, FloatingArrow as ce } from "@floating-ui/react";
15
- const v = {
11
+ import { Ignore as q } from "@annotorious/core";
12
+ import { Origin as Ie, UserSelectAction as Ne, createBody as Me } from "@annotorious/core";
13
+ import J from "debounce";
14
+ import { useFloating as G, autoUpdate as K, inline as X, offset as Z, flip as ee, shift as te, arrow as ne, FloatingPortal as re, FloatingFocusManager as oe, FloatingArrow as ie } from "@floating-ui/react";
15
+ const O = {
16
16
  tei: {
17
17
  ref: (e) => {
18
18
  const t = document.createElement("a");
@@ -22,9 +22,9 @@ const v = {
22
22
  },
23
23
  // Cf. https://github.com/TEIC/CETEIcean/issues/67
24
24
  graphic: (e) => {
25
- var r;
25
+ var o;
26
26
  const t = new Image();
27
- t.src = (r = e.getAttribute("url")) == null ? void 0 : r.trim(), e.hasAttribute("width") && t.setAttribute("width", e.getAttribute("width")), e.hasAttribute("height") && t.setAttribute("height", e.getAttribute("height")), e.appendChild(t);
27
+ t.src = (o = e.getAttribute("url")) == null ? void 0 : o.trim(), e.hasAttribute("width") && t.setAttribute("width", e.getAttribute("width")), e.hasAttribute("height") && t.setAttribute("height", e.getAttribute("height")), e.appendChild(t);
28
28
  },
29
29
  list: null,
30
30
  note: null,
@@ -33,20 +33,20 @@ const v = {
33
33
  e.hidden = !0;
34
34
  }
35
35
  }
36
- }, Fe = (e) => {
36
+ }, Ce = (e) => {
37
37
  const t = w(null);
38
- return a(() => {
39
- var r;
38
+ return u(() => {
39
+ var o;
40
40
  if (e.tei) {
41
- const s = new D(e.initArgs);
42
- s.addBehaviors({
43
- ...v,
41
+ const i = new j(e.initArgs);
42
+ i.addBehaviors({
43
+ ...O,
44
44
  ...e.behaviors || {},
45
45
  tei: {
46
- ...v.tei,
47
- ...((r = e.behaviors) == null ? void 0 : r.tei) || {}
46
+ ...O.tei,
47
+ ...((o = e.behaviors) == null ? void 0 : o.tei) || {}
48
48
  }
49
- }), s.makeHTML5(e.tei, (n) => {
49
+ }), i.makeHTML5(e.tei, (n) => {
50
50
  t.current.appendChild(n), e.onLoad(t.current);
51
51
  });
52
52
  }
@@ -60,141 +60,147 @@ const v = {
60
60
  className: "tei-container"
61
61
  }
62
62
  );
63
- }, ve = (e) => {
64
- const { children: t, ...r } = e, { anno: s, setAnno: n } = O(P), i = x((l) => {
65
- const u = Y(R(l, r));
66
- n(u);
63
+ }, we = (e) => {
64
+ const { children: t, ...o } = e, { anno: i, setAnno: n } = P(B), s = v((l) => {
65
+ const a = V(L(l, o));
66
+ n(a);
67
67
  }, []);
68
- return a(() => {
69
- s && s.setStyle(e.style);
70
- }, [e.style]), a(() => {
71
- s && s.setFilter(e.filter);
72
- }, [e.filter]), e.children ? /* @__PURE__ */ f(k, { children: W.toArray(e.children).map((l) => _(l, { onLoad: i })) }) : null;
68
+ return u(() => {
69
+ i && i.setStyle(e.style);
70
+ }, [e.style]), u(() => {
71
+ i && i.setFilter(e.filter);
72
+ }, [e.filter]), e.children ? /* @__PURE__ */ f(M, { children: U.toArray(e.children).map((l) => W(l, { onLoad: s })) }) : null;
73
73
  }, T = (e, t = { timeout: 250 }) => {
74
- const r = H(), [s, n] = S(!0);
75
- return a(() => {
76
- if (!r || !e) return;
77
- let i;
78
- const l = (u) => {
79
- const { changes: { updated: g } } = u;
80
- (g == null ? void 0 : g.some((o) => {
81
- const { targetUpdated: c } = o;
74
+ const o = H(), [i, n] = x(!0);
75
+ return u(() => {
76
+ if (!o || !e) return;
77
+ let s;
78
+ const l = (a) => {
79
+ const { changes: { updated: g } } = a;
80
+ (g == null ? void 0 : g.some((r) => {
81
+ const { targetUpdated: c } = r;
82
82
  if (c) {
83
- const { oldTarget: h, newTarget: d } = c;
84
- return ue(h, d);
83
+ const { oldTarget: p, newTarget: d } = c;
84
+ return se(p, d);
85
85
  }
86
- })) && (n(!1), clearTimeout(i), i = setTimeout(() => n(!0), t.timeout));
86
+ })) && (n(!1), clearTimeout(s), s = setTimeout(() => n(!0), t.timeout));
87
87
  };
88
- return r.observe(l, {
88
+ return o.observe(l, {
89
89
  annotations: e,
90
- ignore: J.BODY_ONLY,
90
+ ignore: q.BODY_ONLY,
91
91
  origin: Q.LOCAL
92
92
  }), () => {
93
- clearTimeout(i), r.unobserve(l);
93
+ clearTimeout(s), o.unobserve(l);
94
94
  };
95
- }, [r, e, t.timeout]), s;
96
- }, ue = (e, t) => {
97
- const { selector: r } = e, s = r.map(({ quote: l }) => l), { selector: n } = t, i = n.map(({ quote: l }) => l);
98
- return s.join() !== i.join();
99
- }, Ee = (e) => {
100
- const t = w(null), { className: r, children: s, ...n } = e, { style: i, filter: l, user: u, annotatingEnabled: g, userSelectAction: m } = n, { anno: o, setAnno: c } = O(P);
101
- return a(() => {
95
+ }, [o, e, t.timeout]), i;
96
+ }, se = (e, t) => {
97
+ const { selector: o } = e, i = o.map(({ quote: l }) => l), { selector: n } = t, s = n.map(({ quote: l }) => l);
98
+ return i.join() !== s.join();
99
+ }, Te = (e) => {
100
+ const t = w(null), { className: o, children: i, ...n } = e, { style: s, filter: l, user: a, annotatingEnabled: g, userSelectAction: A } = n, { anno: r, setAnno: c } = P(B);
101
+ return u(() => {
102
102
  if (!c) return;
103
- const h = typeof n.adapter == "function" ? n.adapter(t.current) : n.adapter, d = R(t.current, { ...n, adapter: h });
103
+ const p = typeof n.adapter == "function" ? n.adapter(t.current) : n.adapter, d = L(t.current, { ...n, adapter: p });
104
104
  return c(d), () => d.destroy();
105
- }, [c]), a(() => o == null ? void 0 : o.setStyle(i), [o, i]), a(() => o == null ? void 0 : o.setFilter(l), [o, l]), a(() => o == null ? void 0 : o.setFilter(l), [o, l]), a(() => o == null ? void 0 : o.setUserSelectAction(m), [o, m]), a(() => o == null ? void 0 : o.setUser(u), [o, u]), a(() => o == null ? void 0 : o.setAnnotatingEnabled(g), [o, g]), /* @__PURE__ */ f("div", { ref: t, className: `r6o-annotatable no-focus-outline ${r}`, children: s });
106
- }, E = () => {
105
+ }, [c]), u(() => r == null ? void 0 : r.setStyle(s), [r, s]), u(() => r == null ? void 0 : r.setFilter(l), [r, l]), u(() => r == null ? void 0 : r.setFilter(l), [r, l]), u(() => r == null ? void 0 : r.setUserSelectAction(A), [r, A]), u(() => r == null ? void 0 : r.setUser(a), [r, a]), u(() => r == null ? void 0 : r.setAnnotatingEnabled(g), [r, g]), /* @__PURE__ */ f("div", { ref: t, className: `r6o-annotatable no-focus-outline ${o}`, children: i });
106
+ }, F = () => {
107
107
  if (typeof navigator > "u") return !1;
108
108
  var e = navigator.userAgent || navigator.vendor || (window == null ? void 0 : window.opera);
109
109
  return !!(/android/i.test(e) || /iPad|iPhone/.test(e) && !window.MSStream);
110
110
  };
111
- let y = null;
112
- const de = G((e, t, r) => {
111
+ let S = null;
112
+ const le = J((e, t, o) => {
113
113
  requestAnimationFrame(() => {
114
- const s = t.getAnnotationBounds(e);
115
- s && (y = B(s, r.getBoundingClientRect()));
114
+ const i = t.getAnnotationBounds(e);
115
+ i && (S = R(i, o.getBoundingClientRect()));
116
116
  });
117
- }, 250), fe = (e) => {
118
- var F;
119
- const t = z(), { selected: r, event: s } = V(), n = (F = r[0]) == null ? void 0 : F.annotation;
117
+ }, 250), ue = (e) => {
118
+ var E;
119
+ const t = z(), { selected: o, event: i } = D(), n = (E = o[0]) == null ? void 0 : E.annotation;
120
120
  T(n == null ? void 0 : n.id);
121
- const [i, l] = S((r == null ? void 0 : r.length) > 0), u = () => t == null ? void 0 : t.cancelSelected(), [g, m] = S(!1);
122
- x(() => m(!0), []);
123
- const o = x(() => m(!1), []);
124
- a(() => {
125
- i || o();
126
- }, [i, o]);
127
- const c = w(!1), h = w(null), { refs: d, floatingStyles: I, update: ge, context: C } = K({
128
- placement: E() ? "bottom" : e.placement || "top",
121
+ const [s, l] = x((o == null ? void 0 : o.length) > 0), a = () => t == null ? void 0 : t.cancelSelected(), [g, A] = x(!1);
122
+ v(() => A(!0), []);
123
+ const r = v(() => A(!1), []);
124
+ u(() => {
125
+ s || r();
126
+ }, [s, r]);
127
+ const c = w(!1), p = w(null), { refs: d, floatingStyles: I, update: C, context: y } = G({
128
+ placement: F() ? "bottom" : e.placement || "top",
129
129
  strategy: "absolute",
130
- open: i,
131
- onOpenChange: (p, b, A) => {
132
- !p && (A === "escape-key" || A === "focus-out") && (l(p), u());
130
+ open: s,
131
+ onOpenChange: (m, h, b) => {
132
+ !m && (b === "escape-key" || b === "focus-out") && (l(m), a());
133
133
  },
134
134
  middleware: [
135
- Z(),
136
- ee(10),
137
- te({ crossAxis: !0 }),
138
- ne({ crossAxis: !0, padding: 10 }),
139
- oe({ element: h })
135
+ X(),
136
+ Z(10),
137
+ ee({ crossAxis: !0 }),
138
+ te({ crossAxis: !0, padding: 10 }),
139
+ ne({ element: p })
140
140
  ],
141
- whileElementsMounted: X
142
- }), L = re(C), N = se(C, { role: "dialog" }), { getFloatingProps: me } = ie([L, N]);
143
- a(() => {
141
+ whileElementsMounted: K
142
+ });
143
+ u(() => {
144
144
  if (!t) return;
145
- const p = n == null ? void 0 : n.id, b = n == null ? void 0 : n.target.selector.length;
146
- if (p && b > 0 && T) {
147
- const A = t == null ? void 0 : t.state.store.getAnnotationBounds(n.id);
148
- l(!!A);
145
+ const m = n == null ? void 0 : n.id, h = n == null ? void 0 : n.target.selector.length;
146
+ if (m && h > 0 && T) {
147
+ const b = t == null ? void 0 : t.state.store.getAnnotationBounds(n.id);
148
+ l(!!b);
149
149
  } else
150
150
  l(!1);
151
- }, [n == null ? void 0 : n.id, n == null ? void 0 : n.target.selector, T, t == null ? void 0 : t.state.store]), a(() => {
152
- e.onClose && (i ? c.current = !0 : c.current && (c.current = !1, e.onClose()));
153
- }, [e.onClose, i]), a(() => {
154
- t && (i && (n != null && n.id) ? d.setPositionReference({
155
- getBoundingClientRect: () => (de(n.id, t.state.store, t.element), y || new DOMRect()),
151
+ }, [n == null ? void 0 : n.id, n == null ? void 0 : n.target.selector, T, t == null ? void 0 : t.state.store]), u(() => {
152
+ e.onClose && (s ? c.current = !0 : c.current && (c.current = !1, e.onClose()));
153
+ }, [e.onClose, s]), u(() => {
154
+ t && (s && (n != null && n.id) ? d.setPositionReference({
155
+ getBoundingClientRect: () => (le(n.id, t.state.store, t.element), S || new DOMRect()),
156
156
  getClientRects: () => {
157
- const b = t.state.store.getAnnotationRects(n.id).map(
158
- (A) => B(A, t.element.getBoundingClientRect())
157
+ const h = t.state.store.getAnnotationRects(n.id).map(
158
+ (b) => R(b, t.element.getBoundingClientRect())
159
159
  );
160
- return $(b);
160
+ return Y(h);
161
161
  }
162
162
  }) : d.setPositionReference(null));
163
- }, [i, n == null ? void 0 : n.id, n == null ? void 0 : n.target, t]);
164
- const M = j(() => (s == null ? void 0 : s.type) === "keyup" || (s == null ? void 0 : s.type) === "contextmenu" || E() ? -1 : 0, [s]);
165
- return i && n ? /* @__PURE__ */ f(
166
- le,
163
+ }, [s, n == null ? void 0 : n.id, n == null ? void 0 : n.target, t]), u(() => {
164
+ if (!e.asPortal) return;
165
+ const m = { attributes: !0, childList: !0, subtree: !0 }, h = new MutationObserver(() => C());
166
+ return h.observe(document.body, m), window.document.addEventListener("scroll", C, !0), () => {
167
+ h.disconnect(), window.document.removeEventListener("scroll", C, !0);
168
+ };
169
+ }, [C, e.asPortal]);
170
+ const N = _(() => (i == null ? void 0 : i.type) === "keyup" || (i == null ? void 0 : i.type) === "contextmenu" || F() ? -1 : 0, [i]);
171
+ return s && n ? /* @__PURE__ */ f(
172
+ re,
167
173
  {
168
- root: e.asPortal ? null : t.element,
174
+ root: e.asPortal ? void 0 : t.element,
169
175
  children: /* @__PURE__ */ f(
170
- ae,
176
+ oe,
171
177
  {
172
- context: C,
178
+ context: y,
173
179
  modal: !1,
174
180
  closeOnFocusOut: !0,
175
181
  returnFocus: !1,
176
- initialFocus: M,
177
- children: /* @__PURE__ */ U(
182
+ initialFocus: N,
183
+ children: /* @__PURE__ */ k(
178
184
  "div",
179
185
  {
180
- className: `a9s-popup r6o-popup annotation-popup r6o-text-popup ${q}`,
186
+ className: `a9s-popup r6o-popup annotation-popup r6o-text-popup ${$}`,
181
187
  ref: d.setFloating,
182
188
  style: I,
183
189
  children: [
184
190
  e.popup({
185
- annotation: r[0].annotation,
186
- editable: r[0].editable,
187
- event: s
191
+ annotation: o[0].annotation,
192
+ editable: o[0].editable,
193
+ event: i
188
194
  }),
189
195
  e.arrow && /* @__PURE__ */ f(
190
- ce,
196
+ ie,
191
197
  {
192
- ref: h,
193
- context: C,
198
+ ref: p,
199
+ context: y,
194
200
  ...e.arrowProps || {}
195
201
  }
196
202
  ),
197
- /* @__PURE__ */ f("button", { className: "r6o-popup-sr-only", "aria-live": "assertive", onClick: u, children: e.ariaCloseWarning || "Click or leave this dialog to close it." })
203
+ /* @__PURE__ */ f("button", { className: "r6o-popup-sr-only", "aria-live": "assertive", onClick: a, children: e.ariaCloseWarning || "Click or leave this dialog to close it." })
198
204
  ]
199
205
  }
200
206
  )
@@ -202,23 +208,23 @@ const de = G((e, t, r) => {
202
208
  )
203
209
  }
204
210
  ) : null;
205
- }, Oe = (e) => (a(() => {
211
+ }, ve = (e) => (u(() => {
206
212
  console.warn("TextAnnotatorPopup is deprecated and will be removed in a future version. Please use TextAnnotationPopup instead.");
207
- }, []), /* @__PURE__ */ f(fe, { ...e }));
213
+ }, []), /* @__PURE__ */ f(ue, { ...e }));
208
214
  export {
209
- Be as AnnotoriousPlugin,
210
- Fe as CETEIcean,
211
- _e as Origin,
212
- ve as TEIAnnotator,
213
- fe as TextAnnotationPopup,
214
- Ee as TextAnnotator,
215
- Oe as TextAnnotatorPopup,
216
- je as UserSelectAction,
217
- Me as W3CTextFormat,
218
- De as createBody,
219
- ke as parseW3CTextAnnotation,
220
- Le as serializeW3CTEIAnnotation,
221
- Ue as serializeW3CTextAnnotation,
215
+ ye as AnnotoriousPlugin,
216
+ Ce as CETEIcean,
217
+ Ie as Origin,
218
+ we as TEIAnnotator,
219
+ ue as TextAnnotationPopup,
220
+ Te as TextAnnotator,
221
+ ve as TextAnnotatorPopup,
222
+ Ne as UserSelectAction,
223
+ Pe as W3CTextFormat,
224
+ Me as createBody,
225
+ Be as parseW3CTextAnnotation,
226
+ Oe as serializeW3CTEIAnnotation,
227
+ Le as serializeW3CTextAnnotation,
222
228
  T as useAnnotationQuoteIdle
223
229
  };
224
230
  //# sourceMappingURL=react-text-annotator.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"react-text-annotator.es.js","sources":["../src/tei/CETEIcean.tsx","../src/tei/TEIAnnotator.tsx","../src/hooks/useAnnotationQuoteIdle.ts","../src/TextAnnotator.tsx","../src/TextAnnotationPopup/isMobile.ts","../src/TextAnnotationPopup/TextAnnotationPopup.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport CETEI from 'CETEIcean';\n\ninterface CETEIceanProps {\n\n initArgs?: any;\n\n tei?: string;\n\n onLoad?(element: Element): void;\n\n behaviors?: any;\n\n}\n\n// Override default list, note, table, and ref behaviors \n// so they don't introduce text into the DOM that interferes\n// with annotation. Apply a patch to graphics for robustness.\nconst PRESET_BEHAVIORS = {\n tei: {\n ref: (elem: Element) => {\n const a = document.createElement('a');\n\n while(elem.firstChild) {\n a.appendChild(elem.removeChild(elem.firstChild));\n }\n\n a.setAttribute('href', elem.getAttribute('target'));\n\n elem.appendChild(a);\n },\n // Cf. https://github.com/TEIC/CETEIcean/issues/67\n graphic: (elem: Element) => {\n const content = new Image();\n content.src = elem.getAttribute('url')?.trim();\n\n if (elem.hasAttribute('width'))\n content.setAttribute('width', elem.getAttribute('width'));\n\n if (elem.hasAttribute('height'))\n content.setAttribute('height', elem.getAttribute('height'));\n\n elem.appendChild(content);\n },\n list: null,\n note: null,\n table: null,\n teiHeader: (elem: HTMLElement) => {\n elem.hidden = true;\n }\n }\n}\n\nexport const CETEIcean = (props: CETEIceanProps) => {\n\n const el = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (props.tei) {\n const ceteicean = new CETEI(props.initArgs);\n\n ceteicean.addBehaviors({\n ...PRESET_BEHAVIORS,\n ...(props.behaviors || {}),\n tei: {\n ...PRESET_BEHAVIORS.tei,\n ...(props.behaviors?.tei || {})\n }\n });\n\n ceteicean.makeHTML5(props.tei, (data: Element) => {\n el.current.appendChild(data);\n props.onLoad(el.current);\n });\n }\n\n return () => {\n if (el.current)\n el.current.innerHTML = '';\n }\n }, [props.tei, JSON.stringify(props.initArgs), props.onLoad]);\n\n return (\n <div \n ref={el}\n className=\"tei-container\" />\n )\n\n}","import { Children, JSX, ReactElement, ReactNode, cloneElement, useCallback, useContext, useEffect } from 'react';\nimport { AnnotoriousContext, Filter } from '@annotorious/react';\nimport { TEIPlugin } from '@recogito/text-annotator-tei';\nimport { createTextAnnotator, HighlightStyleExpression } from '@soomo/text-annotator';\nimport type { TextAnnotatorOptions } from '@soomo/text-annotator';\n\nimport '@soomo/text-annotator/dist/text-annotator.css';\n\nexport type TEIAnnotatorProps = TextAnnotatorOptions & {\n\n children?: ReactNode | JSX.Element;\n\n filter?: Filter;\n\n style?: HighlightStyleExpression\n\n}\n\nexport const TEIAnnotator = (props: TEIAnnotatorProps) => {\n\n const { children, ...opts } = props;\n\n const { anno, setAnno } = useContext(AnnotoriousContext);\n\n const onLoad = useCallback((element: HTMLElement) => {\n const anno = TEIPlugin(createTextAnnotator(element, opts));\n setAnno(anno);\n }, []);\n\n useEffect(() => {\n if (!anno)\n return;\n \n anno.setStyle(props.style);\n }, [props.style]);\n\n useEffect(() => {\n if (!anno)\n return;\n \n anno.setFilter(props.filter);\n }, [props.filter]);\n\n return props.children ? (\n <>\n {Children.toArray(props.children).map(child => \n cloneElement(child as ReactElement, { onLoad } as any))}\n </>\n ) : null;\n\n}\n","import { useEffect, useState } from 'react';\nimport { Origin, useAnnotationStore } from '@annotorious/react';\nimport { Ignore, type StoreChangeEvent } from '@annotorious/core';\nimport type { TextAnnotation, TextAnnotationStore, TextAnnotationTarget } from '@soomo/text-annotator';\n\nexport const useAnnotationQuoteIdle = (\n annotationId: string | undefined,\n options: { timeout: number } = { timeout: 250 }\n) => {\n const store = useAnnotationStore<TextAnnotationStore>();\n\n const [isIdle, setIsIdle] = useState(true);\n\n useEffect(() => {\n if (!store || !annotationId) return;\n\n let idleTimeout: ReturnType<typeof setTimeout>;\n\n const scheduleSetIsIdle = (event: StoreChangeEvent<TextAnnotation>) => {\n const { changes: { updated } } = event;\n\n const hasChanged = updated?.some(update => {\n const { targetUpdated } = update;\n if (targetUpdated) {\n const { oldTarget, newTarget } = targetUpdated;\n return hasQuoteChanged(oldTarget, newTarget);\n }\n });\n\n if (hasChanged) {\n setIsIdle(false);\n clearTimeout(idleTimeout);\n idleTimeout = setTimeout(() => setIsIdle(true), options.timeout);\n }\n };\n\n store.observe(scheduleSetIsIdle, {\n annotations: annotationId,\n ignore: Ignore.BODY_ONLY,\n origin: Origin.LOCAL\n });\n\n return () => {\n clearTimeout(idleTimeout);\n store.unobserve(scheduleSetIsIdle);\n };\n }, [store, annotationId, options.timeout]);\n\n return isIdle;\n};\n\nconst hasQuoteChanged = (oldValue: TextAnnotationTarget, newValue: TextAnnotationTarget) => {\n const { selector: oldSelector } = oldValue;\n const oldQuotes = oldSelector.map(({ quote }) => quote);\n\n const { selector: newSelector } = newValue;\n const newQuotes = newSelector.map(({ quote }) => quote);\n\n return oldQuotes.join() !== newQuotes.join();\n};\n","import { JSX, 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\nexport interface TextAnnotatorProps<I extends TextAnnotation = TextAnnotation, E extends unknown = TextAnnotation> extends Omit<TextAnnotatorOptions<I, E>, 'adapter'> {\n\n children?: ReactNode | JSX.Element;\n\n adapter?: FormatAdapter<I, E> | ((container: HTMLElement) => FormatAdapter<I, E>) | null;\n\n filter?: Filter<I>;\n\n style?: HighlightStyleExpression;\n\n className?: string;\n\n}\n\nexport const TextAnnotator = <I extends TextAnnotation = TextAnnotation, E extends unknown = TextAnnotation>(\n props: TextAnnotatorProps<I, E>\n) => {\n\n const el = useRef<HTMLDivElement>(null);\n\n const { className, children, ...opts } = props;\n const { style, filter, user, annotatingEnabled, userSelectAction } = 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?.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={`r6o-annotatable no-focus-outline ${className}`}>\n {children}\n </div>\n );\n\n};\n","// https://stackoverflow.com/questions/21741841/detecting-ios-android-operating-system\nexport const isMobile = () => {\n if (typeof navigator === 'undefined') return false;\n\n // @ts-ignore\n var userAgent: string = navigator.userAgent || navigator.vendor || window?.opera;\n\n if (/android/i.test(userAgent)) \n return true;\n\n // @ts-ignore\n // Note: as of recently, this NO LONGER DETECTS FIREFOX ON iOS!\n // This means FF/iOS will behave like on the desktop, and loose\n // selection handlebars after the popup opens.\n if (/iPad|iPhone/.test(userAgent) && !window.MSStream)\n return true;\n\n return false;\n}","import React, { FC, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport debounce from 'debounce';\nimport { useAnnotator, useSelection } from '@annotorious/react';\nimport {\n NOT_ANNOTATABLE_CLASS,\n TextAnnotationStore,\n toViewportBounds,\n toDomRectList,\n type TextAnnotation,\n type TextAnnotator,\n} from '@soomo/text-annotator';\nimport {\n arrow,\n autoUpdate,\n flip,\n FloatingArrow,\n FloatingArrowProps,\n FloatingFocusManager,\n FloatingPortal,\n inline,\n offset,\n Placement,\n shift,\n useDismiss,\n useFloating,\n useInteractions,\n useRole\n} from '@floating-ui/react';\nimport { isMobile } from './isMobile';\nimport { useAnnotationQuoteIdle } from '../hooks';\n\nimport './TextAnnotationPopup.css';\n\ninterface TextAnnotationPopupProps {\n\n ariaNavigationMessage?: string;\n\n ariaCloseWarning?: string;\n\n arrow?: boolean;\n\n arrowProps?: Omit<FloatingArrowProps, 'context' | 'ref'>;\n\n asPortal?: boolean;\n\n placement?: Placement;\n\n popup(props: TextAnnotationPopupContentProps): ReactNode;\n\n onClose?(): void;\n\n}\n\nexport interface TextAnnotationPopupContentProps<T extends TextAnnotation = TextAnnotation> {\n\n annotation: T;\n\n editable?: boolean;\n\n event?: PointerEvent | KeyboardEvent;\n\n}\n\nlet cachedBounds = null;\n\nconst updateViewportBounds = debounce((annotationId: string, store: TextAnnotationStore, container: HTMLElement) => {\n requestAnimationFrame(() => {\n const bounds = store.getAnnotationBounds(annotationId);\n if (!bounds) return;\n cachedBounds = toViewportBounds(bounds, container.getBoundingClientRect());\n });\n}, 250);\n\nexport const TextAnnotationPopup = (props: TextAnnotationPopupProps) => {\n\n const r = useAnnotator<TextAnnotator>();\n\n const { selected, event } = useSelection<TextAnnotation>();\n\n const annotation = selected[0]?.annotation;\n\n const isAnnotationQuoteIdle = useAnnotationQuoteIdle(annotation?.id);\n\n const [isOpen, setOpen] = useState(selected?.length > 0);\n const handleClose = () => r?.cancelSelected();\n\n const [isFocused, setFocused] = useState(false);\n const handleFocus = useCallback(() => setFocused(true), []);\n const handleBlur = useCallback(() => setFocused(false), []);\n useEffect(() => {\n if (!isOpen) handleBlur();\n }, [isOpen, handleBlur]);\n\n // So we can reliably trigger the onClose callback\n const wasOpenRef = useRef(false);\n\n const arrowRef = useRef(null);\n\n const { refs, floatingStyles, update, context } = useFloating({\n placement: isMobile() ? 'bottom' : props.placement || 'top',\n strategy: 'absolute',\n open: isOpen,\n onOpenChange: (open, _event, reason) => {\n if (!open && (reason === 'escape-key' || reason === 'focus-out')) {\n setOpen(open);\n handleClose();\n }\n },\n middleware: [\n inline(),\n offset(10),\n flip({ crossAxis: true }),\n shift({ crossAxis: true, padding: 10, }),\n arrow({ element: arrowRef })\n ],\n whileElementsMounted: autoUpdate\n });\n\n const dismiss = useDismiss(context);\n\n const role = useRole(context, { role: 'dialog' });\n\n const { getFloatingProps } = useInteractions([dismiss, role]);\n\n useEffect(() => {\n if (!r) return;\n\n const annotationId = annotation?.id;\n const annotationSelectorsLength = annotation?.target.selector.length;\n\n if (annotationId && annotationSelectorsLength > 0 && useAnnotationQuoteIdle) {\n const bounds = r?.state.store.getAnnotationBounds(annotation.id);\n setOpen(Boolean(bounds));\n } else {\n setOpen(false);\n }\n }, [annotation?.id, annotation?.target.selector, useAnnotationQuoteIdle, r?.state.store]);\n\n useEffect(() => {\n if (!props.onClose) return;\n\n if (isOpen) {\n wasOpenRef.current = true;\n } else if (wasOpenRef.current) {\n wasOpenRef.current = false;\n props.onClose();\n }\n }, [props.onClose, isOpen]);\n\n useEffect(() => {\n if (!r) return;\n\n if (isOpen && annotation?.id) {\n refs.setPositionReference({\n getBoundingClientRect: () => {\n // Debounced!\n updateViewportBounds(annotation.id, r.state.store, r.element);\n return cachedBounds ? cachedBounds : new DOMRect();\n },\n getClientRects: () => {\n const rects = r.state.store.getAnnotationRects(annotation.id);\n const denormalizedRects = rects.map((rect) =>\n toViewportBounds(rect, r.element.getBoundingClientRect())\n );\n return toDomRectList(denormalizedRects);\n }\n });\n } else {\n refs.setPositionReference(null);\n }\n }, [isOpen, annotation?.id, annotation?.target, r]);\n\n // Don't shift focus to the floating element if selected via keyboard or on mobile.\n const initialFocus = useMemo(() => {\n return (event?.type === 'keyup' || event?.type === 'contextmenu' || isMobile()) ? -1 : 0;\n }, [event]);\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: isFocused,\n // floatingOpen: isOpen,\n // message: ariaNavigationMessage,\n // });\n\n return isOpen && annotation ? (\n <FloatingPortal\n root={props.asPortal ? null : r.element}>\n <FloatingFocusManager\n context={context}\n modal={false}\n closeOnFocusOut={true}\n returnFocus={false}\n initialFocus={initialFocus}>\n <div\n className={`a9s-popup r6o-popup annotation-popup r6o-text-popup ${NOT_ANNOTATABLE_CLASS}`}\n ref={refs.setFloating}\n style={floatingStyles}>\n {props.popup({\n annotation: selected[0].annotation,\n editable: selected[0].editable,\n event\n })}\n{props.arrow && (\n <FloatingArrow\n ref={arrowRef}\n context={context}\n {...(props.arrowProps || {})} />\n )}\n\n <button className=\"r6o-popup-sr-only\" aria-live=\"assertive\" onClick={handleClose}>\n {props.ariaCloseWarning || 'Click or leave this dialog to close it.'}\n </button>\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n ) : null;\n\n};\n\n/**\n * Prevent text-annotator from handling the irrelevant events\n * triggered from the popup/toolbar/dialog\n *\nconst getStopEventsPropagationProps = <T extends HTMLElement = HTMLElement>() => ({\n onPointerUp: (event: React.PointerEvent<T>) => event.stopPropagation(),\n onPointerDown: (event: React.PointerEvent<T>) => event.stopPropagation(),\n onMouseDown: (event: React.MouseEvent<T>) => event.stopPropagation(),\n onMouseUp: (event: React.MouseEvent<T>) => event.stopPropagation()\n});\n*/\n\n/** For backwards compatibility **/\n/** @deprecated Use TextAnnotationPopup instead */\nexport const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {\n\n useEffect(() => {\n console.warn('TextAnnotatorPopup is deprecated and will be removed in a future version. Please use TextAnnotationPopup instead.');\n }, []);\n\n return <TextAnnotationPopup {...props} />;\n};\n"],"names":["PRESET_BEHAVIORS","elem","a","content","_a","CETEIcean","props","el","useRef","useEffect","ceteicean","CETEI","data","jsx","TEIAnnotator","children","opts","anno","setAnno","useContext","AnnotoriousContext","onLoad","useCallback","element","TEIPlugin","createTextAnnotator","Fragment","Children","child","cloneElement","useAnnotationQuoteIdle","annotationId","options","store","useAnnotationStore","isIdle","setIsIdle","useState","idleTimeout","scheduleSetIsIdle","event","updated","update","targetUpdated","oldTarget","newTarget","hasQuoteChanged","Ignore","Origin","oldValue","newValue","oldSelector","oldQuotes","quote","newSelector","newQuotes","TextAnnotator","className","style","filter","user","annotatingEnabled","userSelectAction","adapter","isMobile","userAgent","cachedBounds","updateViewportBounds","debounce","container","bounds","toViewportBounds","TextAnnotationPopup","r","useAnnotator","selected","useSelection","annotation","isOpen","setOpen","handleClose","isFocused","setFocused","handleBlur","wasOpenRef","arrowRef","refs","floatingStyles","context","useFloating","open","_event","reason","inline","offset","flip","shift","arrow","autoUpdate","dismiss","useDismiss","role","useRole","getFloatingProps","useInteractions","annotationSelectorsLength","denormalizedRects","rect","toDomRectList","initialFocus","useMemo","FloatingPortal","FloatingFocusManager","jsxs","NOT_ANNOTATABLE_CLASS","FloatingArrow","TextAnnotatorPopup"],"mappings":"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"}
1
+ {"version":3,"file":"react-text-annotator.es.js","sources":["../src/tei/CETEIcean.tsx","../src/tei/TEIAnnotator.tsx","../src/hooks/useAnnotationQuoteIdle.ts","../src/TextAnnotator.tsx","../src/TextAnnotationPopup/isMobile.ts","../src/TextAnnotationPopup/TextAnnotationPopup.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport CETEI from 'CETEIcean';\n\ninterface CETEIceanProps {\n\n initArgs?: any;\n\n tei?: string;\n\n onLoad?(element: Element): void;\n\n behaviors?: any;\n\n}\n\n// Override default list, note, table, and ref behaviors \n// so they don't introduce text into the DOM that interferes\n// with annotation. Apply a patch to graphics for robustness.\nconst PRESET_BEHAVIORS = {\n tei: {\n ref: (elem: Element) => {\n const a = document.createElement('a');\n\n while(elem.firstChild) {\n a.appendChild(elem.removeChild(elem.firstChild));\n }\n\n a.setAttribute('href', elem.getAttribute('target'));\n\n elem.appendChild(a);\n },\n // Cf. https://github.com/TEIC/CETEIcean/issues/67\n graphic: (elem: Element) => {\n const content = new Image();\n content.src = elem.getAttribute('url')?.trim();\n\n if (elem.hasAttribute('width'))\n content.setAttribute('width', elem.getAttribute('width'));\n\n if (elem.hasAttribute('height'))\n content.setAttribute('height', elem.getAttribute('height'));\n\n elem.appendChild(content);\n },\n list: null,\n note: null,\n table: null,\n teiHeader: (elem: HTMLElement) => {\n elem.hidden = true;\n }\n }\n}\n\nexport const CETEIcean = (props: CETEIceanProps) => {\n\n const el = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (props.tei) {\n const ceteicean = new CETEI(props.initArgs);\n\n ceteicean.addBehaviors({\n ...PRESET_BEHAVIORS,\n ...(props.behaviors || {}),\n tei: {\n ...PRESET_BEHAVIORS.tei,\n ...(props.behaviors?.tei || {})\n }\n });\n\n ceteicean.makeHTML5(props.tei, (data: Element) => {\n el.current.appendChild(data);\n props.onLoad(el.current);\n });\n }\n\n return () => {\n if (el.current)\n el.current.innerHTML = '';\n }\n }, [props.tei, JSON.stringify(props.initArgs), props.onLoad]);\n\n return (\n <div \n ref={el}\n className=\"tei-container\" />\n )\n\n}","import { Children, JSX, ReactElement, ReactNode, cloneElement, useCallback, useContext, useEffect } from 'react';\nimport { AnnotoriousContext, Filter } from '@annotorious/react';\nimport { TEIPlugin } from '@recogito/text-annotator-tei';\nimport { createTextAnnotator, HighlightStyleExpression } from '@soomo/text-annotator';\nimport type { TextAnnotatorOptions } from '@soomo/text-annotator';\n\nimport '@soomo/text-annotator/dist/text-annotator.css';\n\nexport type TEIAnnotatorProps = TextAnnotatorOptions & {\n\n children?: ReactNode | JSX.Element;\n\n filter?: Filter;\n\n style?: HighlightStyleExpression\n\n}\n\nexport const TEIAnnotator = (props: TEIAnnotatorProps) => {\n\n const { children, ...opts } = props;\n\n const { anno, setAnno } = useContext(AnnotoriousContext);\n\n const onLoad = useCallback((element: HTMLElement) => {\n const anno = TEIPlugin(createTextAnnotator(element, opts));\n setAnno(anno);\n }, []);\n\n useEffect(() => {\n if (!anno)\n return;\n \n anno.setStyle(props.style);\n }, [props.style]);\n\n useEffect(() => {\n if (!anno)\n return;\n \n anno.setFilter(props.filter);\n }, [props.filter]);\n\n return props.children ? (\n <>\n {Children.toArray(props.children).map(child => \n cloneElement(child as ReactElement, { onLoad } as any))}\n </>\n ) : null;\n\n}\n","import { useEffect, useState } from 'react';\nimport { Origin, useAnnotationStore } from '@annotorious/react';\nimport { Ignore, type StoreChangeEvent } from '@annotorious/core';\nimport type { TextAnnotation, TextAnnotationStore, TextAnnotationTarget } from '@soomo/text-annotator';\n\nexport const useAnnotationQuoteIdle = (\n annotationId: string | undefined,\n options: { timeout: number } = { timeout: 250 }\n) => {\n const store = useAnnotationStore<TextAnnotationStore>();\n\n const [isIdle, setIsIdle] = useState(true);\n\n useEffect(() => {\n if (!store || !annotationId) return;\n\n let idleTimeout: ReturnType<typeof setTimeout>;\n\n const scheduleSetIsIdle = (event: StoreChangeEvent<TextAnnotation>) => {\n const { changes: { updated } } = event;\n\n const hasChanged = updated?.some(update => {\n const { targetUpdated } = update;\n if (targetUpdated) {\n const { oldTarget, newTarget } = targetUpdated;\n return hasQuoteChanged(oldTarget, newTarget);\n }\n });\n\n if (hasChanged) {\n setIsIdle(false);\n clearTimeout(idleTimeout);\n idleTimeout = setTimeout(() => setIsIdle(true), options.timeout);\n }\n };\n\n store.observe(scheduleSetIsIdle, {\n annotations: annotationId,\n ignore: Ignore.BODY_ONLY,\n origin: Origin.LOCAL\n });\n\n return () => {\n clearTimeout(idleTimeout);\n store.unobserve(scheduleSetIsIdle);\n };\n }, [store, annotationId, options.timeout]);\n\n return isIdle;\n};\n\nconst hasQuoteChanged = (oldValue: TextAnnotationTarget, newValue: TextAnnotationTarget) => {\n const { selector: oldSelector } = oldValue;\n const oldQuotes = oldSelector.map(({ quote }) => quote);\n\n const { selector: newSelector } = newValue;\n const newQuotes = newSelector.map(({ quote }) => quote);\n\n return oldQuotes.join() !== newQuotes.join();\n};\n","import { JSX, 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\nexport interface TextAnnotatorProps<I extends TextAnnotation = TextAnnotation, E extends unknown = TextAnnotation> extends Omit<TextAnnotatorOptions<I, E>, 'adapter'> {\n\n children?: ReactNode | JSX.Element;\n\n adapter?: FormatAdapter<I, E> | ((container: HTMLElement) => FormatAdapter<I, E>) | null;\n\n filter?: Filter<I>;\n\n style?: HighlightStyleExpression;\n\n className?: string;\n\n}\n\nexport const TextAnnotator = <I extends TextAnnotation = TextAnnotation, E extends unknown = TextAnnotation>(\n props: TextAnnotatorProps<I, E>\n) => {\n\n const el = useRef<HTMLDivElement>(null);\n\n const { className, children, ...opts } = props;\n const { style, filter, user, annotatingEnabled, userSelectAction } = 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?.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={`r6o-annotatable no-focus-outline ${className}`}>\n {children}\n </div>\n );\n\n};\n","// https://stackoverflow.com/questions/21741841/detecting-ios-android-operating-system\nexport const isMobile = () => {\n if (typeof navigator === 'undefined') return false;\n\n // @ts-ignore\n var userAgent: string = navigator.userAgent || navigator.vendor || window?.opera;\n\n if (/android/i.test(userAgent)) \n return true;\n\n // @ts-ignore\n // Note: as of recently, this NO LONGER DETECTS FIREFOX ON iOS!\n // This means FF/iOS will behave like on the desktop, and loose\n // selection handlebars after the popup opens.\n if (/iPad|iPhone/.test(userAgent) && !window.MSStream)\n return true;\n\n return false;\n}","import React, { FC, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport debounce from 'debounce';\nimport { useAnnotator, useSelection } from '@annotorious/react';\nimport {\n NOT_ANNOTATABLE_CLASS,\n TextAnnotationStore,\n toViewportBounds,\n toDomRectList,\n type TextAnnotation,\n type TextAnnotator,\n} from '@soomo/text-annotator';\nimport {\n arrow,\n autoUpdate,\n flip,\n FloatingArrow,\n FloatingArrowProps,\n FloatingFocusManager,\n FloatingPortal,\n inline,\n offset,\n Placement,\n shift,\n useDismiss,\n useFloating,\n useInteractions,\n useRole\n} from '@floating-ui/react';\nimport { isMobile } from './isMobile';\nimport { useAnnotationQuoteIdle } from '../hooks';\n\nimport './TextAnnotationPopup.css';\n\ninterface TextAnnotationPopupProps {\n\n ariaNavigationMessage?: string;\n\n ariaCloseWarning?: string;\n\n arrow?: boolean;\n\n arrowProps?: Omit<FloatingArrowProps, 'context' | 'ref'>;\n\n asPortal?: boolean;\n\n placement?: Placement;\n\n popup(props: TextAnnotationPopupContentProps): ReactNode;\n\n onClose?(): void;\n\n}\n\nexport interface TextAnnotationPopupContentProps<T extends TextAnnotation = TextAnnotation> {\n\n annotation: T;\n\n editable?: boolean;\n\n event?: PointerEvent | KeyboardEvent;\n\n}\n\nlet cachedBounds = null;\n\nconst updateViewportBounds = debounce((annotationId: string, store: TextAnnotationStore, container: HTMLElement) => {\n requestAnimationFrame(() => {\n const bounds = store.getAnnotationBounds(annotationId);\n if (!bounds) return;\n cachedBounds = toViewportBounds(bounds, container.getBoundingClientRect());\n });\n}, 250);\n\nexport const TextAnnotationPopup = (props: TextAnnotationPopupProps) => {\n\n const r = useAnnotator<TextAnnotator>();\n\n const { selected, event } = useSelection<TextAnnotation>();\n\n const annotation = selected[0]?.annotation;\n\n const isAnnotationQuoteIdle = useAnnotationQuoteIdle(annotation?.id);\n\n const [isOpen, setOpen] = useState(selected?.length > 0);\n const handleClose = () => r?.cancelSelected();\n\n const [isFocused, setFocused] = useState(false);\n const handleFocus = useCallback(() => setFocused(true), []);\n const handleBlur = useCallback(() => setFocused(false), []);\n useEffect(() => {\n if (!isOpen) handleBlur();\n }, [isOpen, handleBlur]);\n\n // So we can reliably trigger the onClose callback\n const wasOpenRef = useRef(false);\n\n const arrowRef = useRef(null);\n\n const { refs, floatingStyles, update, context } = useFloating({\n placement: isMobile() ? 'bottom' : props.placement || 'top',\n strategy: 'absolute',\n open: isOpen,\n onOpenChange: (open, _event, reason) => {\n if (!open && (reason === 'escape-key' || reason === 'focus-out')) {\n setOpen(open);\n handleClose();\n }\n },\n middleware: [\n inline(),\n offset(10),\n flip({ crossAxis: true }),\n shift({ crossAxis: true, padding: 10, }),\n arrow({ element: arrowRef })\n ],\n whileElementsMounted: autoUpdate\n });\n\n useEffect(() => {\n if (!r) return;\n\n const annotationId = annotation?.id;\n const annotationSelectorsLength = annotation?.target.selector.length;\n\n if (annotationId && annotationSelectorsLength > 0 && useAnnotationQuoteIdle) {\n const bounds = r?.state.store.getAnnotationBounds(annotation.id);\n setOpen(Boolean(bounds));\n } else {\n setOpen(false);\n }\n }, [annotation?.id, annotation?.target.selector, useAnnotationQuoteIdle, r?.state.store]);\n\n useEffect(() => {\n if (!props.onClose) return;\n\n if (isOpen) {\n wasOpenRef.current = true;\n } else if (wasOpenRef.current) {\n wasOpenRef.current = false;\n props.onClose();\n }\n }, [props.onClose, isOpen]);\n\n useEffect(() => {\n if (!r) return;\n\n if (isOpen && annotation?.id) {\n refs.setPositionReference({\n getBoundingClientRect: () => {\n // Debounced!\n updateViewportBounds(annotation.id, r.state.store, r.element);\n return cachedBounds ? cachedBounds : new DOMRect();\n },\n getClientRects: () => {\n const rects = r.state.store.getAnnotationRects(annotation.id);\n const denormalizedRects = rects.map((rect) =>\n toViewportBounds(rect, r.element.getBoundingClientRect())\n );\n return toDomRectList(denormalizedRects);\n }\n });\n } else {\n refs.setPositionReference(null);\n }\n }, [isOpen, annotation?.id, annotation?.target, r]);\n\n useEffect(() => {\n if (!props.asPortal) return;\n\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, props.asPortal]);\n\n // Don't shift focus to the floating element if selected via keyboard or on mobile.\n const initialFocus = useMemo(() => {\n return (event?.type === 'keyup' || event?.type === 'contextmenu' || isMobile()) ? -1 : 0;\n }, [event]);\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: isFocused,\n // floatingOpen: isOpen,\n // message: ariaNavigationMessage,\n // });\n\n return isOpen && annotation ? (\n <FloatingPortal\n root={props.asPortal ? undefined : r.element}>\n <FloatingFocusManager\n context={context}\n modal={false}\n closeOnFocusOut={true}\n returnFocus={false}\n initialFocus={initialFocus}>\n <div\n className={`a9s-popup r6o-popup annotation-popup r6o-text-popup ${NOT_ANNOTATABLE_CLASS}`}\n ref={refs.setFloating}\n style={floatingStyles}>\n {props.popup({\n annotation: selected[0].annotation,\n editable: selected[0].editable,\n event\n })}\n{props.arrow && (\n <FloatingArrow\n ref={arrowRef}\n context={context}\n {...(props.arrowProps || {})} />\n )}\n\n <button className=\"r6o-popup-sr-only\" aria-live=\"assertive\" onClick={handleClose}>\n {props.ariaCloseWarning || 'Click or leave this dialog to close it.'}\n </button>\n </div>\n </FloatingFocusManager>\n </FloatingPortal>\n ) : null;\n\n};\n\n/** For backwards compatibility **/\n/** @deprecated Use TextAnnotationPopup instead */\nexport const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {\n\n useEffect(() => {\n console.warn('TextAnnotatorPopup is deprecated and will be removed in a future version. Please use TextAnnotationPopup instead.');\n }, []);\n\n return <TextAnnotationPopup {...props} />;\n};\n"],"names":["PRESET_BEHAVIORS","elem","a","content","_a","CETEIcean","props","el","useRef","useEffect","ceteicean","CETEI","data","jsx","TEIAnnotator","children","opts","anno","setAnno","useContext","AnnotoriousContext","onLoad","useCallback","element","TEIPlugin","createTextAnnotator","Fragment","Children","child","cloneElement","useAnnotationQuoteIdle","annotationId","options","store","useAnnotationStore","isIdle","setIsIdle","useState","idleTimeout","scheduleSetIsIdle","event","updated","update","targetUpdated","oldTarget","newTarget","hasQuoteChanged","Ignore","Origin","oldValue","newValue","oldSelector","oldQuotes","quote","newSelector","newQuotes","TextAnnotator","className","style","filter","user","annotatingEnabled","userSelectAction","adapter","isMobile","userAgent","cachedBounds","updateViewportBounds","debounce","container","bounds","toViewportBounds","TextAnnotationPopup","r","useAnnotator","selected","useSelection","annotation","isOpen","setOpen","handleClose","isFocused","setFocused","handleBlur","wasOpenRef","arrowRef","refs","floatingStyles","context","useFloating","open","_event","reason","inline","offset","flip","shift","arrow","autoUpdate","annotationSelectorsLength","denormalizedRects","rect","toDomRectList","config","mutationObserver","initialFocus","useMemo","FloatingPortal","FloatingFocusManager","jsxs","NOT_ANNOTATABLE_CLASS","FloatingArrow","TextAnnotatorPopup"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soomo/react-text-annotator",
3
- "version": "3.3.0-staging.0",
3
+ "version": "3.4.0-staging.1",
4
4
  "description": "Recogito Text Annotator React bindings",
5
5
  "author": "Rainer Simon",
6
6
  "license": "BSD-3-Clause",
@@ -50,7 +50,7 @@
50
50
  "@annotorious/react": "^3.7.7",
51
51
  "@floating-ui/react": "^0.27.16",
52
52
  "@react-aria/live-announcer": "^3.3.4",
53
- "@soomo/text-annotator": "3.3.0-staging.0",
53
+ "@soomo/text-annotator": "3.4.0-staging.1",
54
54
  "@recogito/text-annotator-tei": "3.1.6",
55
55
  "CETEIcean": "^1.9.5",
56
56
  "debounce": "^2.2.0",