All files react-cropper.tsx

85.71% Statements 24/28
82.14% Branches 23/28
83.33% Functions 5/6
85.71% Lines 24/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96                                            1x 2x 2x 2x 2x 2x 2x     1x                               6x 6x 6x 6x 6x 3x 2x                     2x 2x           3x 2x 2x               6x 4x 1x       6x                
import React, {useState, useEffect} from 'react';
import Cropper from 'cropperjs';
 
type ReactCropperRef = React.MutableRefObject<HTMLImageElement | null> | null;
 
interface ReactCropperDefaultOptions {
    scaleX?: number;
    scaleY?: number;
    enable?: boolean;
    zoomTo?: number;
    rotateTo?: number;
}
 
interface ReactCropperProps
    extends ReactCropperDefaultOptions,
        Cropper.Options,
        Omit<React.HTMLProps<HTMLImageElement>, 'data' | 'ref' | 'crossOrigin'> {
    crossOrigin?: '' | 'anonymous' | 'use-credentials' | undefined;
    on?: (eventName: string, callback: () => void | Promise<void>) => void | Promise<void>;
    onInitialized?: (instance: Cropper) => void | Promise<void>;
}
 
const applyDefaultOptions = (cropper: Cropper, options: ReactCropperDefaultOptions = {}): void => {
    const {enable = true, scaleX = 1, scaleY = 1, zoomTo = 1, rotateTo = 0} = options;
    enable ? cropper.enable() : cropper.disable();
    cropper.scaleX(scaleX);
    cropper.scaleY(scaleY);
    cropper.rotateTo(rotateTo);
    cropper.zoomTo(zoomTo);
};
 
const ReactCropper = React.forwardRef<HTMLImageElement, ReactCropperProps>(({...props}, ref) => {
    const {
        dragMode = 'crop',
        src,
        style,
        className,
        crossOrigin,
        scaleX,
        scaleY,
        enable,
        zoomTo,
        rotateTo,
        alt = 'picture',
        ready,
        onInitialized,
        ...rest
    } = props;
    const [cropper, setCropper] = useState<Cropper | undefined>(undefined);
    const defaultOptions: ReactCropperDefaultOptions = {scaleY, scaleX, enable, zoomTo, rotateTo};
    const cropperRef = ref as ReactCropperRef;
    useEffect(() => {
        if (cropperRef !== null && cropperRef.current !== null && typeof cropperRef !== 'undefined' && cropperRef) {
            const cropper = new Cropper(cropperRef.current, {
                dragMode,
                ...rest,
                ready: (e) => {
                    if (e.target !== null) {
                        const target = e.target as any;
                        applyDefaultOptions(target.cropper, defaultOptions);
                    }
                    ready && ready(e);
                },
            });
            onInitialized && onInitialized(cropper);
            setCropper(cropper);
        }
 
        /**
         * destroy cropper on un-mount
         */
        return () => {
            Eif (cropperRef !== null) {
                cropper?.destroy();
            }
        };
    }, [cropperRef]);
 
    /**
     * re-render when src changes
     */
    useEffect(() => {
        if (typeof cropper !== 'undefined' && typeof src !== 'undefined') {
            cropper.reset().clear().replace(src);
        }
    }, [src]);
 
    return (
        <div style={style} className={className}>
            <img crossOrigin={crossOrigin} src={src} alt={alt} style={{opacity: 0, maxWidth: '100%'}} ref={ref} />
        </div>
    );
});
 
export {ReactCropper, ReactCropperProps, applyDefaultOptions};