Skip to content

Commit

Permalink
Merge branch 'main' into recogito#127-annotating-enabled-reactive
Browse files Browse the repository at this point in the history
# Conflicts:
#	packages/text-annotator/src/SelectionHandler.ts
  • Loading branch information
oleksandr-danylchenko committed Oct 7, 2024
2 parents ac26a81 + 9ce6e88 commit befcf51
Show file tree
Hide file tree
Showing 17 changed files with 792 additions and 676 deletions.
500 changes: 250 additions & 250 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator-monorepo",
"version": "3.0.0-rc.46",
"version": "3.0.0-rc.49",
"description": "Recogito Text Annotator monorepo",
"author": "Rainer Simon",
"repository": {
Expand Down
4 changes: 2 additions & 2 deletions packages/extension-tei/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator-tei",
"version": "3.0.0-rc.46",
"version": "3.0.0-rc.49",
"description": "Recogito Text Annotator TEI extension",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -33,6 +33,6 @@
},
"peerDependencies": {
"@annotorious/core": "^3.0.9",
"@recogito/text-annotator": "3.0.0-rc.46"
"@recogito/text-annotator": "3.0.0-rc.49"
}
}
17 changes: 12 additions & 5 deletions packages/extension-tei/test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
<link rel="stylesheet" href="CETEIcean.css">
<script type="module" src="../src/index.ts"></script>
<style>
html, body {
*,
*:before,
*:after {
box-sizing: border-box;
}

html,
body {
background: #e2e2e2;
padding: 0;
margin: 0;
Expand All @@ -33,7 +40,7 @@
margin: 0;
padding: 0 0 20px 0;
}

p {
font-size: 17px;
line-height: 160%;
Expand All @@ -52,12 +59,12 @@

import '@recogito/text-annotator/dist/text-annotator.css';

window.onload = async function() {
window.onload = async function () {
var CETEIcean = new CETEI();

CETEIcean.getHTML5('macbeth.xml', data => {
document.getElementById('content').appendChild(data);

var anno = TEIPlugin(createTextAnnotator(document.getElementById('content')));

anno.loadAnnotations('annotations.json');
Expand All @@ -82,7 +89,7 @@
console.log('viewport', annotations);
});
});
}
};
</script>
</body>
</html>
8 changes: 4 additions & 4 deletions packages/text-annotator-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/react-text-annotator",
"version": "3.0.0-rc.46",
"version": "3.0.0-rc.49",
"description": "Recogito Text Annotator React bindings",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -47,8 +47,8 @@
"@annotorious/core": "^3.0.9",
"@annotorious/react": "^3.0.9",
"@floating-ui/react": "^0.26.24",
"@recogito/text-annotator": "3.0.0-rc.46",
"@recogito/text-annotator-tei": "3.0.0-rc.46",
"@recogito/text-annotator": "3.0.0-rc.49",
"@recogito/text-annotator-tei": "3.0.0-rc.49",
"CETEIcean": "^1.9.3"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or the screen reader users as the popup behavior hint
* Inspired by https://gist.github.com/ffoodd/000b59f431e3e64e4ce1a24d5bb36034
*/
.popup-close-message {
.r6o-popup-sr-only {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
Expand All @@ -17,8 +17,8 @@
white-space: nowrap;
}

.popup-close-message:focus,
.popup-close-message:active {
.r6o-popup-sr-only:focus,
.r6o-popup-sr-only:active {
clip: auto;
-webkit-clip-path: none;
clip-path: none;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import React, { PointerEvent, ReactNode, useCallback, useEffect, useState } from 'react';
import { PointerEvent, ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
import { useAnnotator, useSelection } from '@annotorious/react';
import type { TextAnnotation, TextAnnotator } from '@recogito/text-annotator';
import { isMobile } from './isMobile';
import {
autoUpdate,
flip,
Expand All @@ -13,13 +16,12 @@ import {
useRole
} from '@floating-ui/react';

import { useAnnotator, useSelection } from '@annotorious/react';
import type { TextAnnotation, TextAnnotator } from '@recogito/text-annotator';

import './TextAnnotatorPopup.css';

interface TextAnnotationPopupProps {

ariaCloseWarning?: string;

popup(props: TextAnnotationPopupContentProps): ReactNode;

}
Expand All @@ -39,24 +41,18 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
const r = useAnnotator<TextAnnotator>();

const { selected, event } = useSelection<TextAnnotation>();

const annotation = selected[0]?.annotation;

const [isOpen, setOpen] = useState(selected?.length > 0);

const handleClose = () => {
r?.cancelSelected();
};

const { refs, floatingStyles, update, context } = useFloating({
placement: 'top',
placement: isMobile() ? 'bottom' : 'top',
open: isOpen,
onOpenChange: (open, _event, reason) => {
setOpen(open);

if (!open) {
if (reason === 'escape-key' || reason === 'focus-out') {
r?.cancelSelected();
}
if (!open && (reason === 'escape-key' || reason === 'focus-out')) {
setOpen(open);
r?.cancelSelected();
}
},
middleware: [
Expand All @@ -69,23 +65,22 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
});

const dismiss = useDismiss(context);

const role = useRole(context, { role: 'dialog' });
const { getFloatingProps } = useInteractions([dismiss, role]);

const selectedKey = selected.map(a => a.annotation.id).join('-');
useEffect(() => {
// Ignore all selection changes except those accompanied by a user event.
if (selected.length > 0 && event) {
setOpen(event.type === 'pointerup' || event.type === 'keydown');
}
}, [selectedKey, event]);
const { getFloatingProps } = useInteractions([dismiss, role]);

useEffect(() => {
// Close the popup if the selection is cleared
if (selected.length === 0 && isOpen) {
setOpen(false);
}
}, [isOpen, selectedKey]);
setOpen(
// Selected annotation exists and has a selector?
annotation?.target.selector &&
// Selector not empty? (Annotations from plugins, general defensive programming)
annotation.target.selector.length > 0 &&
// Range not collapsed? (E.g. lazy loading PDFs. Note that this will have to
// change if we switch from ranges to pre-computed bounds!)
!annotation.target.selector[0].range.collapsed
);
}, [annotation]);

useEffect(() => {
if (isOpen && annotation) {
Expand All @@ -96,21 +91,14 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
} = annotation;

refs.setPositionReference({
getBoundingClientRect: range.getBoundingClientRect.bind(range),
getClientRects: range.getClientRects.bind(range)
getBoundingClientRect: () => range.getBoundingClientRect(),
getClientRects: () => range.getClientRects()
});
} else {
// Don't leave the reference depending on the previously selected annotation
refs.setPositionReference(null);
}
}, [isOpen, annotation, refs]);

// Prevent text-annotator from handling the irrelevant events triggered from the popup
const getStopEventsPropagationProps = useCallback(
() => ({ onPointerUp: (event: PointerEvent<HTMLDivElement>) => event.stopPropagation() }),
[]
);

useEffect(() => {
const config: MutationObserverInit = { attributes: true, childList: true, subtree: true };

Expand All @@ -125,23 +113,29 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
};
}, [update]);

return isOpen && selected.length > 0 ? (
// Prevent text-annotator from handling the irrelevant events triggered from the popup
const getStopEventsPropagationProps = useCallback(
() => ({ onPointerUp: (event: PointerEvent<HTMLDivElement>) => event.stopPropagation() }),
[]
);

// Don't shift focus to the floating element if selected via keyboard or on mobile.
const initialFocus = useMemo(() => {
return (event?.type === 'keyup' || event?.type === 'contextmenu' || isMobile()) ? -1 : 0;
}, [event]);

const onClose = () => r?.cancelSelected();

return isOpen && annotation ? (
<FloatingPortal>
<FloatingFocusManager
context={context}
modal={false}
closeOnFocusOut={true}
initialFocus={
/**
* Don't shift focus to the floating element
* when the selection performed with the keyboard
*/
event?.type === 'keydown' ? -1 : 0
}
returnFocus={false}
>
initialFocus={initialFocus}>
<div
className="annotation-popup text-annotation-popup not-annotatable"
className="a9s-popup r6o-popup annotation-popup r6o-text-popup not-annotatable"
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
Expand All @@ -152,13 +146,12 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
event
})}

{/* It lets keyboard/sr users to know that the dialog closes when they focus out of it */}
<button className="popup-close-message" onClick={handleClose}>
This dialog closes when you leave it.
<button className="r6o-popup-sr-only" aria-live="assertive" onClick={onClose}>
{props.ariaCloseWarning || 'Click or leave this dialog to close it.'}
</button>
</div>
</FloatingFocusManager>
</FloatingPortal>
) : null;

};
}
17 changes: 17 additions & 0 deletions packages/text-annotator-react/src/TextAnnotatorPopup/isMobile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// https://stackoverflow.com/questions/21741841/detecting-ios-android-operating-system
export const isMobile = () => {
// @ts-ignore
var userAgent: string = navigator.userAgent || navigator.vendor || window.opera;

if (/android/i.test(userAgent))
return true;

// @ts-ignore
// Note: as of recently, this NO LONGER DETECTS FIREFOX ON iOS!
// This means FF/iOS will behave like on the desktop, and loose
// selection handlebars after the popup opens.
if (/iPad|iPhone/.test(userAgent) && !window.MSStream)
return true;

return false;
}
4 changes: 2 additions & 2 deletions packages/text-annotator-react/test/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FC, useCallback, useEffect } from 'react';
import { AnnotationBody, Annotorious, useAnnotationStore, useAnnotator, useSelection } from '@annotorious/react';
import { TextAnnotator, TextAnnotatorPopup, type TextAnnotationPopupContentProps } from '../src';
import { AnnotationBody, Annotorious, useAnnotationStore, useAnnotator } from '@annotorious/react';
import { TextAnnotationPopupContentProps, TextAnnotator, TextAnnotatorPopup } from '../src';
import { W3CTextFormat, type TextAnnotation, type TextAnnotator as RecogitoTextAnnotator } from '@recogito/text-annotator';

const TestPopup: FC<TextAnnotationPopupContentProps> = (props) => {
Expand Down
8 changes: 6 additions & 2 deletions packages/text-annotator-react/test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RecogitoJS React</title>
<style>
*, *:before, *:after {
box-sizing: border-box;
}

html, body {
background: #fff;
padding: 40px;
Expand All @@ -18,13 +22,13 @@
margin: 0;
padding: 0 0 20px 0;
}

p {
font-size: 17px;
line-height: 160%;
}

.annotation-popup {
.r6o-popup {
background-color: #fff;
border: 1px solid gray;
padding: 20px;
Expand Down
6 changes: 3 additions & 3 deletions packages/text-annotator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator",
"version": "3.0.0-rc.46",
"version": "3.0.0-rc.49",
"description": "A JavaScript text annotation library",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -34,7 +34,7 @@
"typescript": "5.6.2",
"vite": "^5.4.8",
"vite-plugin-dts": "^4.2.3",
"vitest": "^2.1.1"
"vitest": "^2.1.2"
},
"dependencies": {
"@annotorious/core": "^3.0.9",
Expand All @@ -45,4 +45,4 @@
"rbush": "^4.0.1",
"uuid": "^10.0.0"
}
}
}
Loading

0 comments on commit befcf51

Please sign in to comment.