Skip to content

Commit

Permalink
Merge branch 'main' into recogito#136-fix-not-dismisssed-annotation-o…
Browse files Browse the repository at this point in the history
…n-native-range-click

# Conflicts:
#	packages/text-annotator/src/SelectionHandler.ts
  • Loading branch information
oleksandr-danylchenko committed Sep 2, 2024
2 parents cecc655 + c6d2c9b commit 3444946
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 168 deletions.
244 changes: 119 additions & 125 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator-monorepo",
"version": "3.0.0-rc.41",
"version": "3.0.0-rc.44",
"description": "Recogito Text Annotator monorepo",
"author": "Rainer Simon",
"repository": {
Expand Down
8 changes: 4 additions & 4 deletions packages/extension-tei/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator-tei",
"version": "3.0.0-rc.41",
"version": "3.0.0-rc.44",
"description": "Recogito Text Annotator TEI extension",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -29,10 +29,10 @@
"CETEIcean": "^1.9.3",
"typescript": "5.5.4",
"vite": "^5.4.2",
"vite-plugin-dts": "^4.0.3"
"vite-plugin-dts": "^4.1.0"
},
"peerDependencies": {
"@annotorious/core": "^3.0.0",
"@recogito/text-annotator": "3.0.0-rc.41"
"@annotorious/core": "^3.0.2",
"@recogito/text-annotator": "3.0.0-rc.44"
}
}
12 changes: 6 additions & 6 deletions packages/text-annotator-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/react-text-annotator",
"version": "3.0.0-rc.41",
"version": "3.0.0-rc.44",
"description": "Recogito Text Annotator React bindings",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -30,7 +30,7 @@
"react-dom": "^18.3.1",
"typescript": "5.5.4",
"vite": "^5.4.2",
"vite-plugin-dts": "^4.0.3",
"vite-plugin-dts": "^4.1.0",
"vite-tsconfig-paths": "^5.0.1"
},
"peerDependencies": {
Expand All @@ -44,11 +44,11 @@
}
},
"dependencies": {
"@annotorious/core": "^3.0.0",
"@annotorious/react": "^3.0.0",
"@annotorious/core": "^3.0.2",
"@annotorious/react": "^3.0.2",
"@floating-ui/react": "^0.26.23",
"@recogito/text-annotator": "3.0.0-rc.41",
"@recogito/text-annotator-tei": "3.0.0-rc.41",
"@recogito/text-annotator": "3.0.0-rc.44",
"@recogito/text-annotator-tei": "3.0.0-rc.44",
"CETEIcean": "^1.9.3"
}
}
16 changes: 12 additions & 4 deletions packages/text-annotator-react/src/TextAnnotatorPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ import {

interface TextAnnotationPopupProps {

popup(props: TextAnnotatorPopupProps): ReactNode;
popup(props: TextAnnotationPopupContentProps): ReactNode;

}

export interface TextAnnotatorPopupProps {
interface TextAnnotationPopupContentProps {

selected: { annotation: TextAnnotation, editable?: boolean }[];
annotation: TextAnnotation;

editable?: boolean;

event?: PointerEvent;

}

Expand Down Expand Up @@ -110,7 +114,11 @@ export const TextAnnotatorPopup = (props: TextAnnotationPopupProps) => {
style={floatingStyles}
{...getFloatingProps()}
{...getStopEventsPropagationProps()}>
{props.popup({ selected })}
{props.popup({
annotation: selected[0].annotation,
editable: selected[0].editable,
event
})}
</div>
) : null;

Expand Down
6 changes: 3 additions & 3 deletions packages/text-annotator/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@recogito/text-annotator",
"version": "3.0.0-rc.41",
"version": "3.0.0-rc.44",
"description": "A JavaScript text annotation library",
"author": "Rainer Simon",
"license": "BSD-3-Clause",
Expand Down Expand Up @@ -33,11 +33,11 @@
"svelte": "^4.2.19",
"typescript": "5.5.4",
"vite": "^5.4.2",
"vite-plugin-dts": "^4.0.3",
"vite-plugin-dts": "^4.1.0",
"vitest": "^2.0.5"
},
"dependencies": {
"@annotorious/core": "^3.0.0",
"@annotorious/core": "^3.0.2",
"colord": "^2.9.3",
"dequal": "^2.0.3",
"rbush": "^4.0.1",
Expand Down
21 changes: 10 additions & 11 deletions packages/text-annotator/src/SelectionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ export const SelectionHandler = (
}
}

if (annotatingEnabled)
container.addEventListener('selectstart', onSelectStart);

const onSelectionChange = debounce((evt: PointerEvent) => {
const sel = document.getSelection();

Expand Down Expand Up @@ -113,10 +110,7 @@ export const SelectionHandler = (
// select events don't have offsetX/offsetY - reuse last up/down)
selection.userSelect(currentTarget.annotation, lastPointerDown);
}
})

if (annotatingEnabled)
document.addEventListener('selectionchange', onSelectionChange);
});

// Select events don't carry information about the mouse button
// Therefore, to prevent right-click selection, we need to listen
Expand All @@ -129,8 +123,6 @@ export const SelectionHandler = (
isLeftClick = evt.button === 0;
}

document.addEventListener('pointerdown', onPointerDown);

const onPointerUp = (evt: PointerEvent) => {
const annotatable = !(evt.target as Node).parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
if (!annotatable || !isLeftClick)
Expand Down Expand Up @@ -179,14 +171,21 @@ export const SelectionHandler = (
});
}

container.addEventListener('pointerdown', onPointerDown);
document.addEventListener('pointerup', onPointerUp);

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

const destroy = () => {
container.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('pointerup', onPointerUp);

container.removeEventListener('selectstart', onSelectStart);
document.removeEventListener('selectionchange', onSelectionChange);

document.removeEventListener('pointerdown', onPointerDown);
document.removeEventListener('pointerup', onPointerUp);
}

return {
Expand Down
4 changes: 2 additions & 2 deletions packages/text-annotator/src/highlight/baseRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ export interface Renderer {

}

export const createBaseRenderer = (
export const createBaseRenderer = <T extends TextAnnotatorState = TextAnnotatorState> (
container: HTMLElement,
state: TextAnnotatorState,
state: T,
viewport: ViewportState,
renderer: RendererImplementation
): Renderer => {
Expand Down
4 changes: 2 additions & 2 deletions packages/text-annotator/src/highlight/span/spansRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ const createRenderer = (container: HTMLElement): RendererImplementation => {

}

export const createSpansRenderer = (
export const createSpansRenderer = <T extends TextAnnotatorState = TextAnnotatorState> (
container: HTMLElement,
state: TextAnnotatorState,
state: T,
viewport: ViewportState
) => createBaseRenderer(container, state, viewport, createRenderer(container));
2 changes: 2 additions & 0 deletions packages/text-annotator/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './model';
export * from './state';
export * from './utils';
export * from './presence/PresencePainterOptions';
export * from './SelectionHandler';
export * from './TextAnnotator';
export * from './TextAnnotatorOptions';

Expand All @@ -25,6 +26,7 @@ export type {
ParseResult,
User,
UserSelectActionExpression,
ViewportState,
W3CAnnotation,
W3CAnnotationBody,
W3CAnnotationTarget
Expand Down
16 changes: 9 additions & 7 deletions packages/text-annotator/src/state/TextAnnotationStore.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
import type { Filter, Origin, Store } from '@annotorious/core';
import type { TextAnnotation } from '../model';

export interface TextAnnotationStore extends Omit<Store<TextAnnotation>, 'addAnnotation' | 'bulkAddAnnotation'> {
export interface TextAnnotationStore<T extends TextAnnotation = TextAnnotation> extends Omit<Store<T>, 'addAnnotation' | 'bulkAddAnnotation'> {

// Minor changes to default Annotorious store - text store returns feedback
// on annotations that failed to render, to support lazy document loading scenarios
addAnnotation(annotation: TextAnnotation, origin?: Origin): boolean;
addAnnotation(annotation: T, origin?: Origin): boolean;

bulkAddAnnotation(annotations: TextAnnotation[], replace: boolean, origin?: Origin): TextAnnotation[];
bulkAddAnnotation(annotations: T[], replace: boolean, origin?: Origin): T[];

bulkUpsertAnnotations(annotations: TextAnnotation[], origin?: Origin): TextAnnotation[];
bulkUpsertAnnotations(annotations: T[], origin?: Origin): T[];

getAnnotationBounds(id: string, hintX?: number, hintY?: number, buffer?: number): DOMRect;

getAnnotationRects(id: string): DOMRect[];

getAt(x: number, y: number, filter?: Filter): TextAnnotation | undefined;

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

recalculatePositions(): void;

}

export interface AnnotationRects {
export interface AnnotationRects <T extends TextAnnotation = TextAnnotation>{

annotation: TextAnnotation;
annotation: T;

rects: Rect[];

Expand Down
7 changes: 5 additions & 2 deletions packages/text-annotator/src/state/TextAnnotatorState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import type { TextAnnotation, TextAnnotationTarget } from '../model';
import type { TextAnnotationStore } from './TextAnnotationStore';
import { isRevived, reviveAnnotation, reviveTarget } from '../utils';

export interface TextAnnotatorState extends AnnotatorState<TextAnnotation> {
export interface TextAnnotatorState<T extends TextAnnotation = TextAnnotation> extends AnnotatorState<T> {

store: TextAnnotationStore;
store: TextAnnotationStore<T>;

selection: SelectionState<TextAnnotation>;

Expand Down Expand Up @@ -130,6 +130,8 @@ export const createTextAnnotatorState = (
return tree.getAnnotationBounds(id);
}

const getAnnotationRects = (id: string): DOMRect[] => tree.getAnnotationRects(id);

const recalculatePositions = () => tree.recalculate();

store.observe(({ changes }) => {
Expand All @@ -155,6 +157,7 @@ export const createTextAnnotatorState = (
bulkUpdateTargets,
bulkUpsertAnnotations,
getAnnotationBounds,
getAnnotationRects,
getAt,
getIntersecting: tree.getIntersecting,
recalculatePositions,
Expand Down
1 change: 0 additions & 1 deletion packages/text-annotator/src/state/spatialTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ export const createSpatialTree = (store: Store<TextAnnotation>, container: HTMLE

const insert = (target: TextAnnotationTarget) => {
const rects = toItems(target, container.getBoundingClientRect());

rects.forEach(rect => tree.insert(rect));
index.set(target.annotation, rects);
}
Expand Down
51 changes: 51 additions & 0 deletions packages/text-annotator/src/utils/mergeClientRects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,54 @@ export const mergeClientRects = (rects: DOMRect[]) => rects.reduce((merged, rect

return wasMerged ? next : [ ...next, rectA ];
}, [] as DOMRect[]);

/* Pixels that rects can be apart vertically while still
// being considered to be on the same line.
const TOLERANCE = 3;
export const mergeClientRects = (rects: DOMRect[]) => {
const lines: DOMRect[][] = [];
// Sort rects from the top, to make grouping simpler
rects.sort((a, b) => a.top - b.top);
// Group rects into lines
for (const rect of rects) {
if (lines.length === 0 || Math.abs(rect.top - lines[lines.length - 1][0].top) > TOLERANCE) {
// Start a new line
lines.push([rect]);
} else {
lines[lines.length - 1].push(rect);
}
}
// Merge lines
const mergedRects = lines.map(line => {
const top = Math.min(...line.map(r => r.top));
const bottom = Math.max(...line.map(r => r.bottom));
const left = Math.min(...line.map(r => r.left));
const right = Math.max(...line.map(r => r.right));
return {
top: top,
bottom: bottom,
left: left,
right: right,
height: bottom - top,
width: right - left
} as DOMRect;
}).filter(r => r.height > 0 && r.width > 0);
// Checks if the given rect contains any other rects
const containsOthers = (rect: DOMRect) => mergedRects.some(other =>
other !== rect &&
other.left >= rect.left &&
other.right <= rect.right &&
other.top >= rect.top &&
other.bottom <= rect.bottom
);
// Remove all rects that contain other rects (block-level elements!)
return mergedRects.filter(rect => !containsOthers(rect));
}
*/

0 comments on commit 3444946

Please sign in to comment.