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
#	packages/text-annotator/src/utils/index.ts
  • Loading branch information
oleksandr-danylchenko committed Sep 30, 2024
2 parents 06adc93 + 1b9fbb5 commit eb65af5
Show file tree
Hide file tree
Showing 20 changed files with 616 additions and 405 deletions.
311 changes: 157 additions & 154 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions packages/extension-tei/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
"CETEIcean": "^1.9.3",
"typescript": "5.6.2",
"vite": "^5.4.8",
"vite-plugin-dts": "^4.2.2"
"vite-plugin-dts": "^4.2.3"
},
"peerDependencies": {
"@annotorious/core": "^3.0.8",
"@annotorious/core": "^3.0.9",
"@recogito/text-annotator": "3.0.0-rc.46"
}
}
12 changes: 6 additions & 6 deletions packages/text-annotator-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
"types": "./dist/index.d.ts",
"devDependencies": {
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"@vitejs/plugin-react": "^4.3.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"typescript": "5.6.2",
"vite": "^5.4.6",
"vite-plugin-dts": "^4.2.1",
"vite": "^5.4.8",
"vite-plugin-dts": "^4.2.3",
"vite-tsconfig-paths": "^5.0.1"
},
"peerDependencies": {
Expand All @@ -44,11 +44,11 @@
}
},
"dependencies": {
"@annotorious/core": "^3.0.8",
"@annotorious/react": "^3.0.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",
"CETEIcean": "^1.9.3"
}
}
}
124 changes: 0 additions & 124 deletions packages/text-annotator-react/src/TextAnnotatorPopup.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Close message should be visible only to the keyboard
* or the screen reader users as the popup behavior hint
* Inspired by https://gist.github.com/ffoodd/000b59f431e3e64e4ce1a24d5bb36034
*/
.popup-close-message {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;
}

.popup-close-message:focus,
.popup-close-message:active {
clip: auto;
-webkit-clip-path: none;
clip-path: none;
height: auto;
margin: auto;
overflow: visible;
width: auto;
white-space: normal;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import React, { PointerEvent, ReactNode, useCallback, useEffect, useState } from 'react';
import {
autoUpdate,
flip,
FloatingFocusManager,
FloatingPortal,
inline,
offset,
shift,
useDismiss,
useFloating,
useInteractions,
useRole
} from '@floating-ui/react';

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

import './TextAnnotatorPopup.css';

interface TextAnnotationPopupProps {

popup(props: TextAnnotationPopupContentProps): ReactNode;

}

export interface TextAnnotationPopupContentProps {

annotation: TextAnnotation;

editable?: boolean;

event?: PointerEvent;

}

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',
open: isOpen,
onOpenChange: (open, _event, reason) => {
setOpen(open);

if (!open) {
if (reason === 'escape-key' || reason === 'focus-out') {
r?.cancelSelected();
}
}
},
middleware: [
offset(10),
inline(),
flip(),
shift({ mainAxis: false, crossAxis: true, padding: 10 })
],
whileElementsMounted: autoUpdate
});

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]);

useEffect(() => {
// Close the popup if the selection is cleared
if (selected.length === 0 && isOpen) {
setOpen(false);
}
}, [isOpen, selectedKey]);

useEffect(() => {
if (isOpen && annotation) {
const {
target: {
selector: [{ range }]
}
} = annotation;

refs.setPositionReference({
getBoundingClientRect: range.getBoundingClientRect.bind(range),
getClientRects: range.getClientRects.bind(range)
});
} 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 };

const mutationObserver = new MutationObserver(() => update());
mutationObserver.observe(document.body, config);

window.document.addEventListener('scroll', update, true);

return () => {
mutationObserver.disconnect();
window.document.removeEventListener('scroll', update, true);
};
}, [update]);

return isOpen && selected.length > 0 ? (
<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}
>
<div
className="annotation-popup text-annotation-popup not-annotatable"
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
{...getStopEventsPropagationProps()}>
{props.popup({
annotation: selected[0].annotation,
editable: selected[0].editable,
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>
</div>
</FloatingFocusManager>
</FloatingPortal>
) : null;

};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './TextAnnotatorPopup';
2 changes: 1 addition & 1 deletion packages/text-annotator-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type {
export {
createBody,
Origin,
UserSelectAction,
UserSelectAction
} from '@annotorious/core';

// Essential re-exports from @annotorious/react
Expand Down
Loading

0 comments on commit eb65af5

Please sign in to comment.