feat(annotator): instant highlighting with mouse, touch or pen (#2881)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { BookNote } from '@/types/book';
|
||||
import { BookNote, HighlightColor } from '@/types/book';
|
||||
import { Point, TextSelection } from '@/utils/sel';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useAnnotationEditor } from '../../hooks/useAnnotationEditor';
|
||||
@@ -105,6 +105,7 @@ interface AnnotationRangeEditorProps {
|
||||
bookKey: string;
|
||||
annotation: BookNote;
|
||||
selection: TextSelection;
|
||||
handleColor: HighlightColor;
|
||||
getAnnotationText: (range: Range) => Promise<string>;
|
||||
setSelection: React.Dispatch<React.SetStateAction<TextSelection | null>>;
|
||||
onStartEdit: () => void;
|
||||
@@ -114,6 +115,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
bookKey,
|
||||
annotation,
|
||||
selection,
|
||||
handleColor,
|
||||
getAnnotationText,
|
||||
setSelection,
|
||||
onStartEdit,
|
||||
@@ -123,7 +125,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
useAnnotationEditor({ bookKey, annotation, getAnnotationText, setSelection });
|
||||
|
||||
const initializedRef = useRef(false);
|
||||
const handleColor = getHighlightColorHex(settings, annotation.color) ?? '#FFFF00';
|
||||
const handleColorHex = getHighlightColorHex(settings, handleColor) ?? '#FFFF00';
|
||||
const draggingRef = useRef<'start' | 'end' | null>(null);
|
||||
const startRef = useRef<Point>({ x: 0, y: 0 });
|
||||
const endRef = useRef<Point>({ x: 0, y: 0 });
|
||||
@@ -198,7 +200,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
<Handle
|
||||
position={currentStart}
|
||||
type='start'
|
||||
color={handleColor}
|
||||
color={handleColorHex}
|
||||
onDragStart={handleStartDragStart}
|
||||
onDrag={handleStartDrag}
|
||||
onDragEnd={handleDragEnd}
|
||||
@@ -206,7 +208,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
<Handle
|
||||
position={currentEnd}
|
||||
type='end'
|
||||
color={handleColor}
|
||||
color={handleColorHex}
|
||||
onDragStart={handleEndDragStart}
|
||||
onDrag={handleEndDrag}
|
||||
onDragEnd={handleDragEnd}
|
||||
|
||||
@@ -198,9 +198,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
isTextSelected,
|
||||
handleScroll,
|
||||
handleTouchStart,
|
||||
handleTouchMove,
|
||||
handleTouchEnd,
|
||||
handlePointerdown,
|
||||
handlePointerup,
|
||||
handlePointerDown,
|
||||
handlePointerMove,
|
||||
handlePointerCancel,
|
||||
handlePointerUp,
|
||||
handleSelectionchange,
|
||||
handleShowPopup,
|
||||
handleUpToPopup,
|
||||
@@ -217,10 +220,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
const { doc, index } = detail;
|
||||
|
||||
const handleTouchmove = () => {
|
||||
const handleTouchmove = (ev: TouchEvent) => {
|
||||
// Available on iOS, on Android not fired
|
||||
// To make the popup not follow the selection while dragging
|
||||
setShowAnnotPopup(false);
|
||||
setEditingAnnotation(null);
|
||||
handleTouchMove(ev);
|
||||
};
|
||||
|
||||
const handleNativeTouch = (event: CustomEvent) => {
|
||||
@@ -229,7 +234,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
handleTouchStart();
|
||||
} else if (ev.type === 'touchend') {
|
||||
handleTouchEnd();
|
||||
handlePointerup(doc, index);
|
||||
handlePointerUp(doc, index);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -245,13 +250,14 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
view?.renderer?.addEventListener('scroll', () => {
|
||||
repositionPopups();
|
||||
});
|
||||
detail.doc?.addEventListener('touchstart', handleTouchStart);
|
||||
detail.doc?.addEventListener('touchmove', handleTouchmove);
|
||||
const opts = { passive: false };
|
||||
detail.doc?.addEventListener('touchstart', handleTouchStart, opts);
|
||||
detail.doc?.addEventListener('touchmove', handleTouchmove, opts);
|
||||
detail.doc?.addEventListener('touchend', handleTouchEnd);
|
||||
detail.doc?.addEventListener('pointerdown', handlePointerdown);
|
||||
detail.doc?.addEventListener('pointerup', (ev: PointerEvent) =>
|
||||
handlePointerup(doc, index, ev),
|
||||
);
|
||||
detail.doc?.addEventListener('pointerdown', handlePointerDown.bind(null, doc, index), opts);
|
||||
detail.doc?.addEventListener('pointermove', handlePointerMove.bind(null, doc, index), opts);
|
||||
detail.doc?.addEventListener('pointercancel', handlePointerCancel.bind(null, doc, index));
|
||||
detail.doc?.addEventListener('pointerup', handlePointerUp.bind(null, doc, index));
|
||||
detail.doc?.addEventListener('selectionchange', () => handleSelectionchange(doc));
|
||||
|
||||
// For PDF selections, enable right-click context menu to directly open translator popup.
|
||||
@@ -935,6 +941,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
bookKey={bookKey}
|
||||
annotation={editingAnnotation}
|
||||
selection={selection}
|
||||
handleColor={selectedColor}
|
||||
getAnnotationText={getAnnotationText}
|
||||
setSelection={setSelection}
|
||||
onStartEdit={handleStartEditAnnotation}
|
||||
|
||||
Reference in New Issue
Block a user