forked from akai/readest
This commit is contained in:
@@ -3,23 +3,28 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { BookNote, HighlightColor } from '@/types/book';
|
||||
import { Point, TextSelection } from '@/utils/sel';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { useAnnotationEditor } from '../../hooks/useAnnotationEditor';
|
||||
import { getHighlightColorHex } from '../../utils/annotatorUtil';
|
||||
import MagnifierLoupe from './MagnifierLoupe';
|
||||
|
||||
interface HandleProps {
|
||||
hidden?: boolean;
|
||||
position: Point;
|
||||
isVertical: boolean;
|
||||
type: 'start' | 'end';
|
||||
color: string;
|
||||
onDragStart: () => void;
|
||||
onDragStart: (pointerType: string) => void;
|
||||
onDrag: (point: Point) => void;
|
||||
onDragEnd: () => void;
|
||||
}
|
||||
|
||||
const Handle: React.FC<HandleProps> = ({
|
||||
hidden,
|
||||
position,
|
||||
isVertical,
|
||||
type,
|
||||
@@ -38,7 +43,7 @@ const Handle: React.FC<HandleProps> = ({
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
isDragging.current = true;
|
||||
onDragStart();
|
||||
onDragStart(e.pointerType);
|
||||
(e.target as HTMLElement).setPointerCapture(e.pointerId);
|
||||
},
|
||||
[onDragStart],
|
||||
@@ -68,7 +73,10 @@ const Handle: React.FC<HandleProps> = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className='pointer-events-auto absolute z-50 cursor-grab touch-none active:cursor-grabbing'
|
||||
className={clsx(
|
||||
'pointer-events-auto absolute z-50 cursor-grab touch-none active:cursor-grabbing',
|
||||
hidden && 'hidden',
|
||||
)}
|
||||
style={{
|
||||
left: isVertical
|
||||
? type === 'start'
|
||||
@@ -143,8 +151,11 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
setSelection,
|
||||
onStartEdit,
|
||||
}) => {
|
||||
const { appService } = useEnv();
|
||||
const { settings } = useSettingsStore();
|
||||
const { isDarkMode } = useThemeStore();
|
||||
const { getViewSettings } = useReaderStore();
|
||||
const viewSettings = getViewSettings(bookKey);
|
||||
const isEink = settings.globalViewSettings.isEink;
|
||||
const einkFgColor = isDarkMode ? '#ffffff' : '#000000';
|
||||
const { handlePositions, getHandlePositionsFromRange, handleAnnotationRangeChange } =
|
||||
@@ -153,10 +164,13 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
const initializedRef = useRef(false);
|
||||
const handleColorHex = getHighlightColorHex(settings, handleColor) ?? '#FFFF00';
|
||||
const draggingRef = useRef<'start' | 'end' | null>(null);
|
||||
const dragPointerTypeRef = useRef<string>('');
|
||||
const startRef = useRef<Point>({ x: 0, y: 0 });
|
||||
const endRef = useRef<Point>({ x: 0, y: 0 });
|
||||
const [draggingHandle, setDraggingHandle] = useState<'start' | 'end' | null>(null);
|
||||
const [currentStart, setCurrentStart] = useState<Point>({ x: 0, y: 0 });
|
||||
const [currentEnd, setCurrentEnd] = useState<Point>({ x: 0, y: 0 });
|
||||
const [loupePoint, setLoupePoint] = useState<Point | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (initializedRef.current) return;
|
||||
@@ -184,19 +198,32 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
endRef.current = handlePositions.end;
|
||||
}, [handlePositions]);
|
||||
|
||||
const handleStartDragStart = useCallback(() => {
|
||||
draggingRef.current = 'start';
|
||||
onStartEdit();
|
||||
}, [onStartEdit]);
|
||||
const handleStartDragStart = useCallback(
|
||||
(pointerType: string) => {
|
||||
draggingRef.current = 'start';
|
||||
dragPointerTypeRef.current = pointerType;
|
||||
setDraggingHandle('start');
|
||||
setLoupePoint({ ...startRef.current });
|
||||
onStartEdit();
|
||||
},
|
||||
[onStartEdit],
|
||||
);
|
||||
|
||||
const handleEndDragStart = useCallback(() => {
|
||||
draggingRef.current = 'end';
|
||||
onStartEdit();
|
||||
}, [onStartEdit]);
|
||||
const handleEndDragStart = useCallback(
|
||||
(pointerType: string) => {
|
||||
draggingRef.current = 'end';
|
||||
dragPointerTypeRef.current = pointerType;
|
||||
setDraggingHandle('end');
|
||||
setLoupePoint({ ...endRef.current });
|
||||
onStartEdit();
|
||||
},
|
||||
[onStartEdit],
|
||||
);
|
||||
|
||||
const handleStartDrag = useCallback(
|
||||
(point: Point) => {
|
||||
setCurrentStart(point);
|
||||
setLoupePoint(point);
|
||||
startRef.current = point;
|
||||
handleAnnotationRangeChange(point, endRef.current, isVertical, true);
|
||||
},
|
||||
@@ -206,6 +233,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
const handleEndDrag = useCallback(
|
||||
(point: Point) => {
|
||||
setCurrentEnd(point);
|
||||
setLoupePoint(point);
|
||||
endRef.current = point;
|
||||
handleAnnotationRangeChange(startRef.current, point, isVertical, true);
|
||||
},
|
||||
@@ -214,6 +242,8 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
|
||||
const handleDragEnd = useCallback(() => {
|
||||
draggingRef.current = null;
|
||||
setDraggingHandle(null);
|
||||
setLoupePoint(null);
|
||||
handleAnnotationRangeChange(startRef.current, endRef.current, isVertical, false);
|
||||
}, [isVertical, handleAnnotationRangeChange]);
|
||||
|
||||
@@ -221,9 +251,12 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
return null;
|
||||
}
|
||||
|
||||
const showLoupe = loupePoint !== null && appService?.isMobile && !viewSettings?.vertical;
|
||||
|
||||
return (
|
||||
<div className='pointer-events-none fixed inset-0 z-50'>
|
||||
<Handle
|
||||
hidden={draggingHandle === 'end'}
|
||||
position={currentStart}
|
||||
isVertical={isVertical}
|
||||
type='start'
|
||||
@@ -233,6 +266,7 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
onDragEnd={handleDragEnd}
|
||||
/>
|
||||
<Handle
|
||||
hidden={draggingHandle === 'start'}
|
||||
position={currentEnd}
|
||||
isVertical={isVertical}
|
||||
type='end'
|
||||
@@ -241,6 +275,14 @@ const AnnotationRangeEditor: React.FC<AnnotationRangeEditorProps> = ({
|
||||
onDrag={handleEndDrag}
|
||||
onDragEnd={handleDragEnd}
|
||||
/>
|
||||
{showLoupe && (
|
||||
<MagnifierLoupe
|
||||
bookKey={bookKey}
|
||||
dragPoint={loupePoint}
|
||||
isVertical={isVertical}
|
||||
color={handleColorHex}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Point } from '@/utils/sel';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
|
||||
interface MagnifierLoupeProps {
|
||||
bookKey: string;
|
||||
dragPoint: Point;
|
||||
isVertical: boolean;
|
||||
color: string;
|
||||
}
|
||||
|
||||
const MagnifierLoupe: React.FC<MagnifierLoupeProps> = ({
|
||||
bookKey,
|
||||
dragPoint,
|
||||
isVertical,
|
||||
color,
|
||||
}) => {
|
||||
const { getView } = useReaderStore();
|
||||
const radius = useResponsiveSize(52);
|
||||
|
||||
useEffect(() => {
|
||||
const view = getView(bookKey);
|
||||
if (!view) return;
|
||||
view.renderer.showLoupe?.(dragPoint.x, dragPoint.y, { isVertical, color, radius });
|
||||
return () => view.renderer.hideLoupe?.();
|
||||
}, [bookKey, dragPoint, getView, isVertical, color, radius]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default MagnifierLoupe;
|
||||
@@ -79,6 +79,12 @@ export interface FoliateView extends HTMLElement {
|
||||
option?: AddEventListenerOptions,
|
||||
) => void;
|
||||
removeEventListener: (type: string, listener: EventListener) => void;
|
||||
showLoupe?: (
|
||||
x: number,
|
||||
y: number,
|
||||
options: { isVertical: boolean; color: string; radius: number },
|
||||
) => void;
|
||||
hideLoupe?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: 4fbd77f4a3...8880dd2bb2
Reference in New Issue
Block a user