Improve types

This commit is contained in:
2025-09-05 18:18:40 +03:00
Unverified
parent cd0898057d
commit e50e94327d
2 changed files with 61 additions and 32 deletions
+5
View File
@@ -32,6 +32,11 @@ export interface Size2D {
y: number; y: number;
} }
export interface Rect extends Size2D {
width: number;
height: number;
}
// App types // App types
/** /**
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import type { Size2D, Rect } from "../../../core/types";
interface ImageCropperProps { interface ImageCropperProps {
onCrop: (croppedImageData: string) => void; onCrop: (croppedImageData: string) => void;
@@ -9,23 +10,21 @@ interface ImageCropperProps {
export function ImageCropper({ onCrop, onCancel, imageFile }: ImageCropperProps) { export function ImageCropper({ onCrop, onCancel, imageFile }: ImageCropperProps) {
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
const imageRef = useRef<HTMLImageElement>(null); const imageRef = useRef<HTMLImageElement>(null);
const [src, setSrc] = useState<string | undefined>(undefined);
const [isLoaded, setIsLoaded] = useState(false); const [isLoaded, setIsLoaded] = useState(false);
const [cropArea, setCropArea] = useState({ x: 0, y: 0, width: 200, height: 200 }); const [cropArea, setCropArea] = useState<Rect>({ x: 0, y: 0, width: 200, height: 200 });
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); const [dragStart, setDragStart] = useState<Size2D>({ x: 0, y: 0 });
useEffect(() => { useEffect(() => {
if (!imageFile) return; if (imageFile) {
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e) => {
if (imageRef.current) { function handleImageLoad() {
imageRef.current.src = e.target?.result as string;
imageRef.current.onload = () => {
setIsLoaded(true); setIsLoaded(true);
// Initialize crop area to center of image // Initialize crop area to center of image
if (imageRef.current) {
const img = imageRef.current; const img = imageRef.current;
if (img) {
const size = Math.min(img.naturalWidth, img.naturalHeight) * 0.8; const size = Math.min(img.naturalWidth, img.naturalHeight) * 0.8;
setCropArea({ setCropArea({
x: (img.naturalWidth - size) / 2, x: (img.naturalWidth - size) / 2,
@@ -34,10 +33,24 @@ export function ImageCropper({ onCrop, onCancel, imageFile }: ImageCropperProps)
height: size height: size
}); });
} }
};
} }
};
function handleReaderLoad() {
if (imageRef.current) {
setSrc(reader.result as string);
imageRef.current.addEventListener("load", handleImageLoad);
}
}
reader.addEventListener("load", handleReaderLoad);
reader.readAsDataURL(imageFile); reader.readAsDataURL(imageFile);
return () => {
reader.abort();
reader.removeEventListener("load", handleReaderLoad);
imageRef.current?.removeEventListener("load", handleImageLoad);
}
}
}, [imageFile]); }, [imageFile]);
function handleMouseDown(e: React.MouseEvent) { function handleMouseDown(e: React.MouseEvent) {
@@ -58,18 +71,28 @@ export function ImageCropper({ onCrop, onCancel, imageFile }: ImageCropperProps)
}; };
function handleMouseMove(e: React.MouseEvent) { function handleMouseMove(e: React.MouseEvent) {
if (!isDragging || !isLoaded) return;
const rect = canvasRef.current?.getBoundingClientRect(); const rect = canvasRef.current?.getBoundingClientRect();
if (!rect || !imageRef.current) return; if (isDragging && isLoaded && rect && imageRef.current) {
const x = e.clientX - rect.left; const x = e.clientX - rect.left;
const y = e.clientY - rect.top; const y = e.clientY - rect.top;
const newX = Math.max(0, Math.min(x - dragStart.x, imageRef.current.naturalWidth - cropArea.width)); const newX = Math.max(
const newY = Math.max(0, Math.min(y - dragStart.y, imageRef.current.naturalHeight - cropArea.height)); 0,
Math.min(
x - dragStart.x,
imageRef.current.naturalWidth - cropArea.width
)
);
const newY = Math.max(
0,
Math.min(
y - dragStart.y,
imageRef.current.naturalHeight - cropArea.height
)
);
setCropArea(prev => ({ ...prev, x: newX, y: newY })); setCropArea(prev => ({ ...prev, x: newX, y: newY }));
}
}; };
function handleMouseUp() { function handleMouseUp() {
@@ -152,6 +175,7 @@ export function ImageCropper({ onCrop, onCancel, imageFile }: ImageCropperProps)
/> />
<img <img
ref={imageRef} ref={imageRef}
src={src}
style={{ display: 'none' }} style={{ display: 'none' }}
alt="Crop source" alt="Crop source"
/> />