mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Improve types
This commit is contained in:
Vendored
+5
@@ -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"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user