@@ -59,6 +59,21 @@ export class Annotatable extends Component {
5959 if ( ! isEqual ( this . props . annotations , prevProps . annotations ) )
6060 this . setState ( { renderedAnnotations : this . props . annotations } ) ;
6161
62+ // if the user just removed a highlight, restore focus to the previous selection
63+ const lastAnnotation = this . state . renderedAnnotations [
64+ this . state . renderedAnnotations . length - 1
65+ ] ;
66+ const wasRemoved = lastAnnotation ?. attributes . removed ;
67+ const prevLastAnnotation =
68+ prevState . renderedAnnotations [ this . state . renderedAnnotations . length - 1 ] ;
69+ const prevWasRemoved = prevLastAnnotation ?. attributes . removed ;
70+ if ( wasRemoved !== prevWasRemoved ) {
71+ this . restoreFocusAndSelection ( {
72+ restoreFocusTo : "selection" ,
73+ restoreSelectionTo : "selection"
74+ } ) ;
75+ }
76+
6277 const { selection } = this . state . selectionState ?? { } ;
6378 const { range, ...selectionData } = selection ?? { } ;
6479 const { selection : prevSelection } = prevState . selectionState ?? { } ;
@@ -265,6 +280,15 @@ export class Annotatable extends Component {
265280 return res . promise ;
266281 } ;
267282
283+ /* Currently, this callback is used only for removing highlights.
284+ Annotations are deleted using a call in the global component that
285+ does not attempt to restore focus. In order to restore focus after
286+ delete, we create a *fake* here on success and reset selection and
287+ annotation state. We can't call this.resetState here because we
288+ don't want to overwrite this.state.renderedAnnotations once we push
289+ the fake. Then we call focus on the new node in componentDidUpdate
290+ to ensure that it happens after state updates there.
291+ */
268292 destroyAnnotation = annotation => {
269293 if ( ! annotation ) return ;
270294 const call = annotationsAPI . destroy ( annotation . id ) ;
@@ -273,14 +297,31 @@ export class Annotatable extends Component {
273297 request ( call , requests . rAnnotationDestroy , options )
274298 ) ;
275299 res . promise . then ( ( ) => {
276- // recreate destroyed node and move selection to it after state is reset
300+ // recreate destroyed node and append to renderedAnnotations
277301 const selectionAnnotation = this . createAnnotationFromSelection (
278- this . state . selectionState . selectionAnnotation
302+ this . state . selectionState . selectionAnnotation ,
303+ "previous" ,
304+ true
279305 ) ;
280- this . appendLastSelectionAnnotation ( selectionAnnotation ) ;
281- this . resetState ( {
282- restoreFocusTo : this . pendingAnnotationNode ,
283- restoreSelectionTo : this . pendingAnnotationNode
306+ // this state update gets overwritten by the one in componentDidUpdate
307+ // if not pushed to the bottom of the stack with setTimeout
308+ setTimeout ( ( ) => {
309+ this . setState ( {
310+ selectionState : {
311+ selection : null ,
312+ selectionComplete : false ,
313+ selectionAnnotation : null ,
314+ popupTriggerX : null ,
315+ popupTriggerY : null
316+ } ,
317+ activeEvent : null ,
318+ annotation : null ,
319+ annotationState : null ,
320+ renderedAnnotations : [
321+ ...this . state . renderedAnnotations ,
322+ selectionAnnotation
323+ ]
324+ } ) ;
284325 } ) ;
285326 } ) ;
286327 return res . promise ;
@@ -336,13 +377,14 @@ export class Annotatable extends Component {
336377 } ) ;
337378 } ;
338379
339- createAnnotationFromSelection = selection => {
380+ createAnnotationFromSelection = ( selection , style , removed ) => {
340381 return {
341382 id : "selection" ,
342383 attributes : {
343384 userIsCreator : true ,
344385 annotationStyle : "pending" ,
345- format : "highlight" ,
386+ format : style ?? "highlight" ,
387+ removed,
346388 ...selection
347389 }
348390 } ;
0 commit comments