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,35 +10,47 @@ 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(); function handleImageLoad() {
reader.onload = (e) => { setIsLoaded(true);
if (imageRef.current) { // Initialize crop area to center of image
imageRef.current.src = e.target?.result as string; const img = imageRef.current;
imageRef.current.onload = () => { if (img) {
setIsLoaded(true); const size = Math.min(img.naturalWidth, img.naturalHeight) * 0.8;
// Initialize crop area to center of image setCropArea({
if (imageRef.current) { x: (img.naturalWidth - size) / 2,
const img = imageRef.current; y: (img.naturalHeight - size) / 2,
const size = Math.min(img.naturalWidth, img.naturalHeight) * 0.8; width: size,
setCropArea({ height: size
x: (img.naturalWidth - size) / 2, });
y: (img.naturalHeight - size) / 2, }
width: size,
height: size
});
}
};
} }
};
reader.readAsDataURL(imageFile); function handleReaderLoad() {
if (imageRef.current) {
setSrc(reader.result as string);
imageRef.current.addEventListener("load", handleImageLoad);
}
}
reader.addEventListener("load", handleReaderLoad);
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 y = e.clientY - rect.top;
const x = e.clientX - rect.left; const newX = Math.max(
const y = e.clientY - rect.top; 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
)
);
const newX = Math.max(0, Math.min(x - dragStart.x, imageRef.current.naturalWidth - cropArea.width)); setCropArea(prev => ({ ...prev, x: newX, y: newY }));
const newY = Math.max(0, Math.min(y - dragStart.y, imageRef.current.naturalHeight - cropArea.height)); }
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"
/> />