Skip to content

Commit

Permalink
Merge branch 'recogito#172-fix-popup-flickering-selection' into stagi…
Browse files Browse the repository at this point in the history
…ng-testing

# Conflicts:
#	packages/text-annotator-react/src/TextAnnotatorPopup/TextAnnotatorPopup.tsx
#	packages/text-annotator-react/src/hooks/index.ts
#	packages/text-annotator/src/SelectionHandler.ts
  • Loading branch information
oleksandr-danylchenko committed Nov 6, 2024
2 parents 6c09045 + 718ebfb commit 71196b1
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { FC, PointerEvent, MouseEvent, ReactNode, useCallback, useEffect, useMemo, useState } from 'react';

import { useAnnotator, useSelection } from '@annotorious/react';
import {
isRevived,
denormalizeRectWithOffset,
toDomRectList,
NOT_ANNOTATABLE_CLASS,
type TextAnnotation,
type TextAnnotator
} from '@soomo/text-annotator';
Expand All @@ -24,7 +24,7 @@ import {
} from '@floating-ui/react';

import { isMobile } from './isMobile';
import { useAnnouncePopupNavigation } from '../hooks';
import { useAnnouncePopupNavigation, useAnnotationTargetIdling } from '../hooks';

import './TextAnnotatorPopup.css';

Expand Down Expand Up @@ -55,9 +55,10 @@ export const TextAnnotatorPopup: FC<TextAnnotationPopupProps> = (props) => {
const r = useAnnotator<TextAnnotator>();

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

const annotation = selected[0]?.annotation;

const isAnnotationIdling = useAnnotationTargetIdling(annotation?.id);

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

Expand Down Expand Up @@ -94,8 +95,8 @@ export const TextAnnotatorPopup: FC<TextAnnotationPopupProps> = (props) => {

useEffect(() => {
const annotationSelector = annotation?.target.selector;
setOpen(annotationSelector?.length > 0 ? isRevived(annotationSelector) : false);
}, [annotation]);
setOpen(isAnnotationIdling && annotationSelector?.length > 0 ? isRevived(annotationSelector) : false);
}, [annotation?.target?.selector, isAnnotationIdling]);

useEffect(() => {
if (!r) return;
Expand Down Expand Up @@ -159,7 +160,7 @@ export const TextAnnotatorPopup: FC<TextAnnotationPopupProps> = (props) => {
returnFocus={false}
initialFocus={initialFocus}>
<div
className="a9s-popup r6o-popup annotation-popup r6o-text-popup not-annotatable"
className={`a9s-popup r6o-popup annotation-popup r6o-text-popup ${NOT_ANNOTATABLE_CLASS}`}
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps({
Expand All @@ -180,7 +181,7 @@ export const TextAnnotatorPopup: FC<TextAnnotationPopupProps> = (props) => {
</FloatingPortal>
) : null;

}
};

/**
* Prevent text-annotator from handling the irrelevant events
Expand Down
3 changes: 2 additions & 1 deletion packages/text-annotator-react/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './useAnnouncePopupNavigation';
export { useAnnouncePopupNavigation } from './useAnnouncePopupNavigation';
export { useAnnotationTargetIdling } from './useAnnotationTargetIdling';
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Origin, useAnnotationStore } from '@annotorious/react';
import { useEffect, useState } from 'react';
import { Ignore } from '@annotorious/core';

export const useAnnotationTargetIdling = (
annotationId: string | undefined,
options: { timeout: number } = { timeout: 500 }
) => {
const store = useAnnotationStore();

const [isIdling, setIdling] = useState(true);

useEffect(() => {
if (!annotationId) return;

let idlingTimeout: ReturnType<typeof setTimeout>;

const scheduleSetIdling = () => {
setIdling(false);

clearTimeout(idlingTimeout);
idlingTimeout = setTimeout(() => setIdling(true), options.timeout);
};

store.observe(
scheduleSetIdling,
{
annotations: annotationId,
ignore: Ignore.BODY_ONLY,
origin: Origin.LOCAL
}
);
return () => {
clearTimeout(idlingTimeout);
store.unobserve(scheduleSetIdling);
};
}, [annotationId]);

return isIdling;
};
9 changes: 3 additions & 6 deletions packages/text-annotator-react/test/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,10 @@ export const App: FC = () => {
to pity him except Neptune, who still persecuted him without ceasing
and would not let him get home.
</p>
</TextAnnotator>

<TextAnnotatorPopup
popup={
props => (<TestPopup {...props} />)
}
/>
<TextAnnotatorPopup popup={props => (<TestPopup {...props} />)} />

</TextAnnotator>

<MockStorage />
</Annotorious>
Expand Down
6 changes: 4 additions & 2 deletions packages/text-annotator/src/SelectionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,10 @@ export const createSelectionHandler = (

if (sel?.isCollapsed) return;

// When selecting the initial word, Chrome Android fires `contextmenu`
// before selectionChanged.
/**
* When selecting the initial word, Chrome Android
* fires the`contextmenu`before the `selectionchange`
*/
if (!currentTarget || currentTarget.selector.length === 0) {
onSelectionChange(evt);
}
Expand Down

0 comments on commit 71196b1

Please sign in to comment.