1- import { PointerEvent , ReactNode , useCallback , useEffect , useState } from 'react' ;
1+ import { ReactNode , useCallback , useEffect , useState , PointerEvent } from 'react' ;
22import { useAnnotator , useSelection } from '@annotorious/react' ;
3- import type { TextAnnotation , TextAnnotator } from '@recogito/text-annotator' ;
3+ import { type TextAnnotation , type TextAnnotator } from '@recogito/text-annotator' ;
44import {
55 autoUpdate ,
6- flip ,
7- FloatingFocusManager ,
8- FloatingPortal ,
96 inline ,
107 offset ,
8+ flip ,
119 shift ,
1210 useDismiss ,
1311 useFloating ,
1412 useInteractions ,
1513 useRole
1614} from '@floating-ui/react' ;
1715
18- import './TextAnnotatorPopup.css' ;
19-
2016interface TextAnnotationPopupProps {
2117
2218 popup ( props : TextAnnotationPopupContentProps ) : ReactNode ;
2319
2420}
2521
26- export interface TextAnnotationPopupContentProps {
22+ interface TextAnnotationPopupContentProps {
2723
2824 annotation : TextAnnotation ;
29-
25+
3026 editable ?: boolean ;
3127
3228 event ?: PointerEvent ;
@@ -37,27 +33,21 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
3733
3834 const r = useAnnotator < TextAnnotator > ( ) ;
3935
40- const { selected, event } = useSelection < TextAnnotation > ( ) ;
36+ const { selected } = useSelection < TextAnnotation > ( ) ;
37+
4138 const annotation = selected [ 0 ] ?. annotation ;
4239
4340 const [ isOpen , setOpen ] = useState ( selected ?. length > 0 ) ;
4441
45- const handleClose = ( ) => {
46- r ?. cancelSelected ( ) ;
47- } ;
48-
4942 const { refs, floatingStyles, update, context } = useFloating ( {
5043 placement : 'top' ,
5144 open : isOpen ,
52- onOpenChange : ( open , _event , reason ) => {
45+ /* onOpenChange: (open, _event, reason) => {
5346 setOpen(open);
54-
55- if ( ! open ) {
56- if ( reason === 'escape-key' || reason === 'focus-out' ) {
57- r ?. cancelSelected ( ) ;
58- }
47+ if (!open && reason === 'escape-key') {
48+ r?.cancelSelected();
5949 }
60- } ,
50+ }, */
6151 middleware : [
6252 offset ( 10 ) ,
6353 inline ( ) ,
@@ -68,41 +58,33 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
6858 } ) ;
6959
7060 const dismiss = useDismiss ( context ) ;
71- const role = useRole ( context , { role : 'dialog' } ) ;
61+
62+ const role = useRole ( context , { role : 'tooltip' } ) ;
63+
7264 const { getFloatingProps } = useInteractions ( [ dismiss , role ] ) ;
7365
7466 const selectedKey = selected . map ( a => a . annotation . id ) . join ( '-' ) ;
7567
7668 useEffect ( ( ) => {
77- // Ignore all selection changes except those accompanied by a user event.
78- if ( selected . length > 0 ) { // && event) {
79- setOpen ( true ) ; // event.type === 'pointerup' || event.type === 'keydown');
80- }
81- } , [ selectedKey /*, event */ ] ) ;
69+ // Ignore all selection changes except those accompanied by a pointer event.
70+ setOpen ( selected . length > 0 ) ;
71+ } , [ selectedKey ] ) ;
8272
8373 useEffect ( ( ) => {
84- // Close the popup if the selection is cleared
85- if ( selected . length === 0 && isOpen ) {
86- setOpen ( false ) ;
87- }
88- } , [ isOpen , selectedKey ] ) ;
74+ if ( ! isOpen || ! annotation ) return ;
8975
90- useEffect ( ( ) => {
91- if ( isOpen && annotation ) {
92- const {
93- target : {
94- selector : [ { range } ]
95- }
96- } = annotation ;
97-
98- refs . setPositionReference ( {
99- getBoundingClientRect : range . getBoundingClientRect . bind ( range ) ,
100- getClientRects : range . getClientRects . bind ( range )
101- } ) ;
102- } else {
103- // Don't leave the reference depending on the previously selected annotation
104- refs . setPositionReference ( null ) ;
105- }
76+ if ( ! annotation . target . selector || annotation . target . selector . length === 0 ) return ;
77+
78+ const {
79+ target : {
80+ selector : [ { range } ]
81+ }
82+ } = annotation ;
83+
84+ refs . setPositionReference ( {
85+ getBoundingClientRect : ( ) => range . getBoundingClientRect ( ) ,
86+ getClientRects :( ) => range . getClientRects ( )
87+ } ) ;
10688 } , [ isOpen , annotation , refs ] ) ;
10789
10890 // Prevent text-annotator from handling the irrelevant events triggered from the popup
@@ -122,43 +104,21 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
122104 return ( ) => {
123105 mutationObserver . disconnect ( ) ;
124106 window . document . removeEventListener ( 'scroll' , update , true ) ;
125- } ;
107+ }
126108 } , [ update ] ) ;
127109
128110 return isOpen && selected . length > 0 ? (
129- < FloatingPortal >
130- < FloatingFocusManager
131- context = { context }
132- modal = { false }
133- closeOnFocusOut = { true }
134- initialFocus = {
135- /**
136- * Don't shift focus to the floating element
137- * when the selection performed with the keyboard
138- */
139- event ?. type === 'keydown' ? - 1 : 0
140- }
141- returnFocus = { false }
142- >
143- < div
144- className = "annotation-popup text-annotation-popup not-annotatable"
145- ref = { refs . setFloating }
146- style = { floatingStyles }
147- { ...getFloatingProps ( ) }
148- { ...getStopEventsPropagationProps ( ) } >
149- { props . popup ( {
150- annotation : selected [ 0 ] . annotation ,
151- editable : selected [ 0 ] . editable ,
152- event
153- } ) }
154-
155- { /* It lets keyboard/sr users to know that the dialog closes when they focus out of it */ }
156- < button className = "popup-close-message" onClick = { handleClose } >
157- This dialog closes when you leave it.
158- </ button >
159- </ div >
160- </ FloatingFocusManager >
161- </ FloatingPortal >
111+ < div
112+ className = "annotation-popup text-annotation-popup not-annotatable"
113+ ref = { refs . setFloating }
114+ style = { floatingStyles }
115+ { ...getFloatingProps ( ) }
116+ { ...getStopEventsPropagationProps ( ) } >
117+ { props . popup ( {
118+ annotation : selected [ 0 ] . annotation ,
119+ editable : selected [ 0 ] . editable
120+ } ) }
121+ </ div >
162122 ) : null ;
163123
164- }
124+ }
0 commit comments