Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential bug when cropping in chrome/safari #66

Open
garganmol111 opened this issue Apr 18, 2024 · 0 comments
Open

Potential bug when cropping in chrome/safari #66

garganmol111 opened this issue Apr 18, 2024 · 0 comments

Comments

@garganmol111
Copy link

I have created the following ImageCropper component for my project:

'use client';
import {
  Button,
  Modal,
  ModalContent,
  ModalHeader,
  ModalBody,
  ModalFooter,
  useDisclosure,
} from '@nextui-org/react';
import { useDropzone } from 'react-dropzone';
import React, { useEffect, useState } from 'react';
import { Cropper, ImageRestriction } from 'react-advanced-cropper';
import 'react-advanced-cropper/dist/style.css';
import { ImagePlus } from 'lucide-react';

const ImageCropper = ({
  croppedImage,
  setCroppedImage,
  label,
  className,
  imageType,
  aspect,
}) => {
  const [cropper, setCropper] = useState(null);
  const [isCropping, setIsCropping] = useState(false);
  const [image, setImage] = useState(null);
  const [croppedImageURL, setCroppedImageURL] = useState(null);

  const { isOpen, onOpen, onClose } = useDisclosure();

  const { getRootProps, getInputProps, open } = useDropzone({
    accept: {
      'image/png': ['.png'],
      'image/jpeg': ['.jpg', '.jpeg'],
    },
    noKeyboard: true,
    noClick: true,
    onDrop: acceptedFiles => {
      setIsCropping(true); // Set isCropping to true when a new image is dropped
      //   setCroppedImage(acceptedFiles[0]);
      onOpen();
    },
  });

  const onChange = cropper => {
    setCropper(cropper);
  };

  const handleDropzoneClick = e => {
    // If the modal is open, do nothing
    if (isOpen) {
      e.stopPropagation();
      // Prevent click from reaching dropzone
    } else {
      open();
    }
  };

  const handleFileChange = e => {
    const file = e.target.files[0];
    if (file) {
      setIsCropping(true); // Set isCropping to true when a new image is selected
      const reader = new FileReader();
      reader.onload = () => {
        setImage(reader.result);
        onOpen();
      };
      reader.readAsDataURL(file);
    }
  };

  const applyCrop = () => {
    if (cropper) {
      const canvas = cropper.getCanvas();
      if (canvas) {
        canvas.toBlob(blob => {
          setCroppedImage(blob);
        });

        setCropper(null);
        setIsCropping(false);
        onClose();
      }
    }
  };

  const cancelCrop = e => {
    setCroppedImage(null);
    setImage(null);
    setCropper(null);
    setIsCropping(false); // Reset isCropping when cropping is cancelled
    onClose();
  };

  useEffect(() => {
    if (croppedImage instanceof Blob) {
      setCroppedImageURL(URL.createObjectURL(croppedImage));
    } else if (croppedImage?.url) {
      setCroppedImageURL(croppedImage?.url);
    } else if (croppedImage === null) setCroppedImageURL(null);
  }, [croppedImage]);

  return (
    <div
      {...getRootProps({ className: 'dropzone' })}
      onClick={handleDropzoneClick}
      className={`${className}flex justify-center items-center flex-col text-center `}
    >
      <div>
        <input
          {...getInputProps()}
          id={imageType}
          onChange={handleFileChange}
        />
      </div>
      <div>
        <Modal
          isOpen={isOpen}
          onClose={cancelCrop}
          size="3xl"
          isDismissable={false}
        >
          <ModalContent>
            <ModalHeader className="flex flex-col gap-1">{label}</ModalHeader>
            <ModalBody>
              {image && isCropping && (
                <div>
                  <Cropper
                    src={image}
                    onChange={onChange}
                    className={'cropper'}
                    aspectRatio={aspect}
                    initialCrop={{ x: 0, y: 0, width: 100, height: 100 }}
                    stencilProps={{
                      handlers: true,
                      lines: true,
                      movable: true,
                      resizable: true,
                    }}
                    canvas={true}
                    stencilSize={{ width: 300, height: 300 }}
                    imageRestriction={ImageRestriction.fillArea}
                  />
                  <div className="flex gap-5 justify-center pt-4">
                    <Button color="primary" onClick={applyCrop}>
                      Apply Crop
                    </Button>
                    <Button color="danger" onClick={cancelCrop}>
                      Cancel Crop
                    </Button>
                  </div>
                </div>
              )}
            </ModalBody>
          </ModalContent>
        </Modal>
      </div>
      {croppedImageURL ? (
        <img
          src={croppedImageURL}
          alt="Cropped Image"
          className="
        object-cover"
        />
      ) : (
        <div>
          {label ? (
            <p className=" flex flex-col justify-center items-center w-full text-primary text-[8px]">
              <ImagePlus /> {label}
            </p>
          ) : (
            <ImagePlus className="text-primary" size={32} />
          )}
        </div>
      )}
    </div>
  );
};

export default ImageCropper;

In the above code, whenever ImageCropper is clicked on, the cropper opens in a nextui-org/react Modal. The above code works perfectly in Firefox, but doesn't seem to work in Chrome/Safari. In chrome/safari, the modal opens but the cropper is not shown. Plus there is no error/warning in the browser console when this happens as well.
Below are screen recording of how it looks on both browsers.

Firefox:

firefox.mp4

Chrome:

chrome.mp4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant