Skip to content

Commit

Permalink
Merge pull request #178 from recogito/selection-mode
Browse files Browse the repository at this point in the history
New `selectionMode` init prop
  • Loading branch information
rsimon authored Nov 11, 2024
2 parents 22b45f0 + ee757d1 commit a8e7adb
Show file tree
Hide file tree
Showing 16 changed files with 229 additions and 205 deletions.
349 changes: 170 additions & 179 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 @@ -28,11 +28,11 @@
"devDependencies": {
"CETEIcean": "^1.9.3",
"typescript": "5.6.3",
"vite": "^5.4.10",
"vite": "^5.4.11",
"vite-plugin-dts": "^4.3.0"
},
"peerDependencies": {
"@annotorious/core": "^3.0.11",
"@annotorious/core": "^3.0.12",
"@recogito/text-annotator": "3.0.0-rc.51"
}
}
8 changes: 4 additions & 4 deletions packages/text-annotator-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"typescript": "5.6.3",
"vite": "^5.4.10",
"vite": "^5.4.11",
"vite-plugin-dts": "^4.3.0",
"vite-tsconfig-paths": "^5.1.0"
"vite-tsconfig-paths": "^5.1.2"
},
"peerDependencies": {
"openseadragon": "^3.0.0 || ^4.0.0 || ^5.0.0",
Expand All @@ -44,8 +44,8 @@
}
},
"dependencies": {
"@annotorious/core": "^3.0.11",
"@annotorious/react": "^3.0.11",
"@annotorious/core": "^3.0.12",
"@annotorious/react": "^3.0.12",
"@floating-ui/react": "^0.26.27",
"@recogito/text-annotator": "3.0.0-rc.51",
"@recogito/text-annotator-tei": "3.0.0-rc.51",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
useRole
} from '@floating-ui/react';

import './TextAnnotatorPopup.css';
import './TextAnnotationPopup.css';

interface TextAnnotationPopupProps {

Expand All @@ -39,11 +39,11 @@ export interface TextAnnotationPopupContentProps {

editable?: boolean;

event?: PointerEvent;
event?: PointerEvent | KeyboardEvent;

}

export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
export const TextAnnotationPopup = (props: TextAnnotationPopupProps) => {

const r = useAnnotator<TextAnnotator>();

Expand Down Expand Up @@ -177,3 +177,14 @@ const getStopEventsPropagationProps = <T extends HTMLElement = HTMLElement>() =>
onMouseDown: (event: React.MouseEvent<T>) => event.stopPropagation(),
onMouseUp: (event: React.MouseEvent<T>) => event.stopPropagation()
});

/** For backwards compatibility **/
/** @deprecated Use TextAnnotationPopup instead */
export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {

useEffect(() => {
console.warn('TextAnnotatorPopup is deprecated and will be removed in a future version. Please use TextAnnotationPopup instead.');
}, []);

return <TextAnnotationPopup {...props} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './TextAnnotationPopup';

This file was deleted.

6 changes: 3 additions & 3 deletions packages/text-annotator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@
"@types/rbush": "^4.0.0",
"jsdom": "^25.0.1",
"typescript": "5.6.3",
"vite": "^5.4.10",
"vite": "^5.4.11",
"vite-plugin-dts": "^4.3.0",
"vitest": "^2.1.4"
},
"dependencies": {
"@annotorious/core": "^3.0.11",
"@annotorious/core": "^3.0.12",
"colord": "^2.9.3",
"dequal": "^2.0.3",
"hotkeys-js": "^3.13.7",
"rbush": "^4.0.1",
"uuid": "^11.0.2"
"uuid": "^11.0.3"
}
}
20 changes: 14 additions & 6 deletions packages/text-annotator/src/SelectionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
trimRangeToContainer,
isNotAnnotatable
} from './utils';
import type { TextAnnotatorOptions } from './TextAnnotatorOptions';

const CLICK_TIMEOUT = 300;

Expand All @@ -30,12 +31,13 @@ const SELECTION_KEYS = [
export const SelectionHandler = (
container: HTMLElement,
state: TextAnnotatorState<TextAnnotation, unknown>,
annotatingEnabled: boolean,
offsetReferenceSelector?: string
options: TextAnnotatorOptions<TextAnnotation, unknown>
) => {

let currentUser: User | undefined;

const { annotatingEnabled, offsetReferenceSelector, selectionMode } = options;

const setUser = (user?: User) => currentUser = user;

let currentFilter: Filter | undefined;
Expand Down Expand Up @@ -179,14 +181,20 @@ export const SelectionHandler = (
const hovered =
evt.target instanceof Node &&
container.contains(evt.target) &&
store.getAt(evt.clientX - x, evt.clientY - y, currentFilter);
store.getAt(evt.clientX - x, evt.clientY - y, selectionMode === 'all', currentFilter);

if (hovered) {
const { selected } = selection;

if (selected.length !== 1 || selected[0].id !== hovered.id) {
selection.userSelect(hovered.id, evt);
}
const currentIds = new Set(selected.map(s => s.id));
const nextIds = Array.isArray(hovered) ? hovered.map(a => a.id) : [hovered.id];

const hasChanged =
currentIds.size !== nextIds.length ||
!nextIds.every(id => currentIds.has(id));

if (hasChanged)
selection.userSelect(nextIds, evt);
} else {
selection.clear();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/text-annotator/src/TextAnnotator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const createTextAnnotator = <E extends unknown = TextAnnotation>(
if (opts.style)
highlightRenderer.setStyle(opts.style);

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

/*************************/
Expand Down
2 changes: 2 additions & 0 deletions packages/text-annotator/src/TextAnnotatorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export interface TextAnnotatorOptions<I extends TextAnnotation = TextAnnotation,

presence?: PresencePainterOptions;

selectionMode?: 'shortest' | 'all';

style?: HighlightStyleExpression;

user?: User;
Expand Down
2 changes: 1 addition & 1 deletion packages/text-annotator/src/highlight/baseRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const createBaseRenderer = <T extends TextAnnotatorState = TextAnnotatorS
const onPointerMove = (event: PointerEvent) => {
const {x, y} = container.getBoundingClientRect();

const hit = store.getAt(event.clientX - x, event.clientY - y, currentFilter);
const hit = store.getAt(event.clientX - x, event.clientY - y, false, currentFilter);
if (hit) {
if (hover.current !== hit.id) {
container.classList.add('hovered');
Expand Down
4 changes: 3 additions & 1 deletion packages/text-annotator/src/state/TextAnnotationStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export interface TextAnnotationStore<T extends TextAnnotation = TextAnnotation>

getAnnotationRects(id: string): DOMRect[];

getAt(x: number, y: number, filter?: Filter): T | undefined;
getAt(x: number, y: number, all: true, filter?: Filter): T[] | undefined;
getAt(x: number, y: number, all: false, filter?: Filter): T | undefined;
getAt(x: number, y: number, all?: boolean, filter?: Filter): T | T[] | undefined;

getIntersecting(minX: number, minY: number, maxX: number, maxY: number): AnnotationRects<T>[];

Expand Down
17 changes: 13 additions & 4 deletions packages/text-annotator/src/state/TextAnnotatorState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Filter, Store, ViewportState, UserSelectActionExpression, Annotation } from '@annotorious/core';
import type { Filter, Store, ViewportState, UserSelectActionExpression } from '@annotorious/core';
import {
createHoverState,
createSelectionState,
Expand Down Expand Up @@ -99,10 +99,19 @@ export const createTextAnnotatorState = <I extends TextAnnotation = TextAnnotati
store.bulkUpdateTargets(revived, origin);
}

const getAt = (x: number, y: number, filter?: Filter): I | undefined => {
const annotations = tree.getAt(x, y, Boolean(filter)).map(id => store.getAnnotation(id));
function getAt(x: number, y: number, all: true, filter?: Filter): I[] | undefined;
function getAt(x: number, y: number, all: false, filter?: Filter): I | undefined;
function getAt(x: number, y: number, all?: boolean, filter?: Filter): I | I[] | undefined {
const getAll = all || Boolean(filter);

const annotations = tree.getAt(x, y, getAll).map(id => store.getAnnotation(id));

const filtered = filter ? annotations.filter(filter) : annotations;
return filtered.length > 0 ? filtered[0] : undefined;

if (filtered.length === 0)
return undefined;

return all ? filtered : filtered[0];
}

const getAnnotationBounds = (id: string, x?: number, y?: number, buffer = 5): DOMRect => {
Expand Down
1 change: 1 addition & 0 deletions packages/text-annotator/test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ <h3>Not annotatable block!</h3>
adapter: W3CTextFormat('https://www.gutenberg.org', contentContainer),
renderer: 'SPANS',
// annotatingEnabled: false,
// selectionMode: 'all',
style
});

Expand Down

0 comments on commit a8e7adb

Please sign in to comment.