Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#127 Made annotatingEnabled property reactive #128

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
edd2e4a
Added `annotatingEnabled` flag updating support
oleksandr-danylchenko Aug 1, 2024
2c5b4da
Added `annotatingEnabled` update from the react wrapper
oleksandr-danylchenko Aug 1, 2024
2c9fb93
Added undefined `annotatingEnabled` prop handling
oleksandr-danylchenko Aug 28, 2024
e6ef046
Added cleanable `debounce` function
oleksandr-danylchenko Aug 28, 2024
da40d2c
Added selection state cleanup on annotating disabling
oleksandr-danylchenko Aug 28, 2024
5baebe7
Decreased debounce timeout to 10ms
oleksandr-danylchenko Aug 28, 2024
6b19a83
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Aug 30, 2024
3d7e09c
Added strict context binding to the debounced function
oleksandr-danylchenko Aug 30, 2024
c0dc156
Added context-unaware `debounce` wrapper
oleksandr-danylchenko Aug 30, 2024
822ee71
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Sep 2, 2024
0b4ebc9
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Sep 3, 2024
21249d7
Replaced custom `debounce` method with the library one
oleksandr-danylchenko Sep 10, 2024
ffd4564
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Sep 10, 2024
a4079b0
Decreased debounce timeout to 10ms
oleksandr-danylchenko Sep 10, 2024
06adc93
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Sep 26, 2024
eb65af5
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Sep 30, 2024
ac26a81
Merged `main` into `#127-annotating-enabled-reactive`
oleksandr-danylchenko Sep 30, 2024
befcf51
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Oct 7, 2024
8084534
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Oct 29, 2024
b3e9a54
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Nov 4, 2024
2ee7384
Removed `isContextMenuOpen` usage
oleksandr-danylchenko Nov 4, 2024
7a44635
Added `isLeftClick` reset on annotating disabling
oleksandr-danylchenko Nov 4, 2024
843c284
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Nov 11, 2024
4249cc1
Added `annotatingEnabled` in opts handling
oleksandr-danylchenko Nov 11, 2024
3ca9ab6
Merge branch 'main' into #127-annotating-enabled-reactive
oleksandr-danylchenko Dec 16, 2024
b2bbebc
Comment formatting
oleksandr-danylchenko Dec 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions packages/text-annotator-react/src/TextAnnotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export const TextAnnotator = <I extends TextAnnotation = TextAnnotation, E exten
const el = useRef<HTMLDivElement>(null);

const { className, children, ...opts } = props;
const { style, filter, user } = opts;

const { style, filter, user, annotatingEnabled } = opts;

const { anno, setAnno } = useContext(AnnotoriousContext);

Expand All @@ -49,10 +49,12 @@ export const TextAnnotator = <I extends TextAnnotation = TextAnnotation, E exten

useEffect(() => anno?.setUser(user), [anno, user]);

useEffect(() => anno?.setAnnotatingEnabled(annotatingEnabled), [anno, annotatingEnabled]);

return (
<div ref={el} className={className}>
{children}
</div>
)
);

}
1 change: 1 addition & 0 deletions packages/text-annotator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"dependencies": {
"@annotorious/core": "^3.0.14",
"colord": "^2.9.3",
"debounce": "^2.1.1",
"dequal": "^2.0.3",
"hotkeys-js": "^3.13.9",
"rbush": "^4.0.1",
Expand Down
58 changes: 41 additions & 17 deletions packages/text-annotator/src/SelectionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Origin } from '@annotorious/core';
import type { Filter, Selection, User } from '@annotorious/core';
import debounce from 'debounce';
import { v4 as uuidv4 } from 'uuid';
import hotkeys from 'hotkeys-js';

import { Origin, type Filter, type Selection, type User } from '@annotorious/core';

import type { TextAnnotatorState } from './state';
import type { TextAnnotation, TextAnnotationTarget } from './model';
import type { TextAnnotatorOptions } from './TextAnnotatorOptions';
import {
clonePointerEvent,
cloneKeyboardEvent,
debounce,
splitAnnotatableRanges,
rangeToSelector,
isMac,
Expand All @@ -28,12 +29,14 @@ const SELECTION_KEYS = [
SELECT_ALL
];

export const SelectionHandler = (
export const createSelectionHandler = (
container: HTMLElement,
state: TextAnnotatorState<TextAnnotation, unknown>,
options: TextAnnotatorOptions<TextAnnotation, unknown>
) => {

const { store, selection } = state;

let currentUser: User | undefined;

const { annotatingEnabled, offsetReferenceSelector, selectionMode } = options;
Expand All @@ -44,17 +47,29 @@ export const SelectionHandler = (

const setFilter = (filter?: Filter) => currentFilter = filter;

const { store, selection } = state;

let currentTarget: TextAnnotationTarget | undefined;

let isLeftClick: boolean | undefined;

let lastDownEvent: Selection['event'] | undefined;

let currentAnnotatingEnabled = annotatingEnabled;

const setAnnotatingEnabled = (enabled: boolean) => {
currentAnnotatingEnabled = enabled;
onSelectionChange.clear();

if (!enabled) {
currentTarget = undefined;
isLeftClick = undefined;
lastDownEvent = undefined;
}
};

const onSelectStart = (evt: Event) => {
if (isLeftClick === false)
return;
if (!currentAnnotatingEnabled) return;

if (isLeftClick === false) return;

/**
* Make sure we don't listen to selection changes that were
Expand All @@ -73,6 +88,8 @@ export const SelectionHandler = (
};

const onSelectionChange = debounce((evt: Event) => {
if (!currentAnnotatingEnabled) return;

const sel = document.getSelection();

/**
Expand Down Expand Up @@ -166,7 +183,7 @@ export const SelectionHandler = (
// Proper lifecycle management: clear the previous selection first...
selection.clear();
}
});
}, 10);

/**
* Select events don't carry information about the mouse button.
Expand Down Expand Up @@ -243,18 +260,20 @@ export const SelectionHandler = (

if (sel?.isCollapsed) return;

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

upsertCurrentTarget();

selection.userSelect(currentTarget.annotation, clonePointerEvent(evt));
}

const onKeyup = (evt: KeyboardEvent) => {
if (!currentAnnotatingEnabled) return;

if (evt.key === 'Shift' && currentTarget) {
const sel = document.getSelection();

Expand Down Expand Up @@ -351,13 +370,17 @@ export const SelectionHandler = (
document.addEventListener('pointerup', onPointerUp);
document.addEventListener('contextmenu', onContextMenu);

if (annotatingEnabled) {
container.addEventListener('keyup', onKeyup);
container.addEventListener('selectstart', onSelectStart);
document.addEventListener('selectionchange', onSelectionChange);
}
container.addEventListener('keyup', onKeyup);
container.addEventListener('selectstart', onSelectStart);
document.addEventListener('selectionchange', onSelectionChange);

const destroy = () => {
currentTarget = undefined;
isLeftClick = undefined;
lastDownEvent = undefined;

onSelectionChange.clear();

container.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('pointerup', onPointerUp);
document.removeEventListener('contextmenu', onContextMenu);
Expand All @@ -372,7 +395,8 @@ export const SelectionHandler = (
return {
destroy,
setFilter,
setUser
setUser,
setAnnotatingEnabled
}

}
Expand Down
35 changes: 28 additions & 7 deletions packages/text-annotator/src/TextAnnotator.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { createAnonymousGuest, createLifecycleObserver, createBaseAnnotator, createUndoStack } from '@annotorious/core';
import type { Filter } from '@annotorious/core';
import {
createAnonymousGuest,
createLifecycleObserver,
createBaseAnnotator,
createUndoStack,
type Filter,
} from '@annotorious/core';
import type { Annotator, User, PresenceProvider } from '@annotorious/core';
import { createCanvasRenderer, createHighlightsRenderer, createSpansRenderer, type HighlightStyleExpression } from './highlight';

import {
createCanvasRenderer,
createHighlightsRenderer,
createSpansRenderer,
type HighlightStyleExpression
} from './highlight';
import { createPresencePainter } from './presence';
import { scrollIntoView } from './api';
import { type TextAnnotationStore, type TextAnnotatorState, createTextAnnotatorState } from './state';
import type { TextAnnotation } from './model';
import { cancelSingleClickEvents, programmaticallyFocusable } from './utils';
import { fillDefaults, type RendererType, type TextAnnotatorOptions } from './TextAnnotatorOptions';
import { SelectionHandler } from './SelectionHandler';
import { createSelectionHandler } from './SelectionHandler';

import './TextAnnotator.css';

Expand All @@ -23,6 +34,8 @@ export interface TextAnnotator<I extends TextAnnotation = TextAnnotation, E exte
// Returns true if successful (or false if the annotation is not currently rendered)
scrollIntoView(annotationOrId: I | string): boolean;

setAnnotatingEnabled: (enabled: boolean) => void;

state: TextAnnotatorState<I, E>;

}
Expand Down Expand Up @@ -65,8 +78,8 @@ export const createTextAnnotator = <I extends TextAnnotation = TextAnnotation, E

const highlightRenderer =
useRenderer === 'SPANS' ? createSpansRenderer(container, state, viewport) :
useRenderer === 'CSS_HIGHLIGHTS' ? createHighlightsRenderer(container, state, viewport) :
useRenderer === 'CANVAS' ? createCanvasRenderer(container, state, viewport) : undefined;
useRenderer === 'CSS_HIGHLIGHTS' ? createHighlightsRenderer(container, state, viewport) :
useRenderer === 'CANVAS' ? createCanvasRenderer(container, state, viewport) : undefined;

if (!highlightRenderer)
throw `Unknown renderer implementation: ${useRenderer}`;
Expand All @@ -76,8 +89,9 @@ export const createTextAnnotator = <I extends TextAnnotation = TextAnnotation, E
if (opts.style)
highlightRenderer.setStyle(opts.style);

const selectionHandler = SelectionHandler(container, state, opts);
const selectionHandler = createSelectionHandler(container, state, opts);
selectionHandler.setUser(currentUser);
selectionHandler.setAnnotatingEnabled(opts.annotatingEnabled);

/*************************/
/* External API */
Expand All @@ -88,6 +102,12 @@ export const createTextAnnotator = <I extends TextAnnotation = TextAnnotation, E

const getUser = () => currentUser;

const setAnnotatingEnabled = (enabled?: boolean) => {
selectionHandler.setAnnotatingEnabled(
enabled === undefined ? true : enabled
);
};

const setFilter = (filter?: Filter<I>) => {
highlightRenderer.setFilter(filter);
selectionHandler.setFilter(filter);
Expand Down Expand Up @@ -132,6 +152,7 @@ export const createTextAnnotator = <I extends TextAnnotation = TextAnnotation, E
destroy,
element: container,
getUser,
setAnnotatingEnabled,
setFilter,
setStyle,
setUser,
Expand Down
14 changes: 5 additions & 9 deletions packages/text-annotator/src/TextAnnotatorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@ export type RendererType = 'SPANS' | 'CANVAS' | 'CSS_HIGHLIGHTS';
export const fillDefaults = <I extends TextAnnotation = TextAnnotation, E extends unknown = TextAnnotation>(
opts: TextAnnotatorOptions<I, E>,
defaults: TextAnnotatorOptions<I, E>
): TextAnnotatorOptions<I, E> => {

return {
...opts,
annotatingEnabled: opts.annotatingEnabled ?? defaults.annotatingEnabled,
user: opts.user || defaults.user
};

};
): TextAnnotatorOptions<I, E> => ({
...opts,
annotatingEnabled: opts.annotatingEnabled ?? defaults.annotatingEnabled,
user: opts.user || defaults.user
});
10 changes: 6 additions & 4 deletions packages/text-annotator/src/highlight/baseRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import debounce from 'debounce';

import type { Filter, ViewportState } from '@annotorious/core';

import type { TextAnnotatorState } from '../state';
import { debounce } from '../utils';
import { type ViewportBounds, getViewportBounds, trackViewport } from './viewport';
import type { HighlightPainter } from './HighlightPainter';
import type { Highlight } from './Highlight';
Expand Down Expand Up @@ -135,11 +137,10 @@ export const createBaseRenderer = <T extends TextAnnotatorState = TextAnnotatorS
const onResize = debounce(() => {
store.recalculatePositions();

if (currentPainter)
currentPainter.reset();
currentPainter?.reset();

redraw();
});
}, 10);

window.addEventListener('resize', onResize);

Expand Down Expand Up @@ -169,6 +170,7 @@ export const createBaseRenderer = <T extends TextAnnotatorState = TextAnnotatorS

document.removeEventListener('scroll', onScroll);

onResize.clear();
window.removeEventListener('resize', onResize);
resizeObserver.disconnect();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import debounce from 'debounce';

import type { ViewportState } from '@annotorious/core';

import type { TextAnnotatorState } from '../../state';
import { debounce } from '../../utils';
import type { ViewportBounds } from '../viewport';
import type { HighlightStyle } from '../HighlightStyle';
import { DEFAULT_SELECTED_STYLE, DEFAULT_STYLE, type HighlightStyleExpression } from '../HighlightStyle';
Expand Down Expand Up @@ -117,9 +119,7 @@ const createRenderer = (container: HTMLElement): RendererImplementation => {
});
});

const onResize = debounce(() => {
resetCanvas(canvas);
});
const onResize = debounce(() => resetCanvas(canvas), 10);

window.addEventListener('resize', onResize);

Expand All @@ -130,6 +130,7 @@ const createRenderer = (container: HTMLElement): RendererImplementation => {
const destroy = () => {
canvas.remove();

onResize.clear();
window.removeEventListener('resize', onResize);
}

Expand Down
8 changes: 0 additions & 8 deletions packages/text-annotator/src/utils/debounce.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/text-annotator/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ export * from './cancelSingleClickEvents';
export * from './cloneEvents';
export * from './device';
export * from './programmaticallyFocusable';
export * from './debounce';
export * from './getQuoteContext';
export * from './isNotAnnotatable';
export * from './isRevived';
Expand Down