All files react-cropper.tsx

75.86% Statements 22/29
73.08% Branches 19/26
83.33% Functions 5/6
75.86% Lines 22/29

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                               3x 3x 3x 3x   3x 2x 1x                     1x 1x           2x 1x                 3x 2x           3x                
import React, {useState, useEffect} from 'react';
import Cropper from 'cropperjs';
 
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.FC<ReactCropperProps> = (props) => {
    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 imageRef = React.createRef<HTMLImageElement>();
    const defaultOptions: ReactCropperDefaultOptions = {scaleY, scaleX, enable, zoomTo, rotateTo};
 
    useEffect(() => {
        if (imageRef.current !== null && imageRef.current.src) {
            const cropper = new Cropper(imageRef.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 () => {
            Iif (imageRef.current !== null) {
                cropper?.destroy();
            }
        };
    }, [imageRef.current]);
 
    /**
     * re-render when src changes
     */
    useEffect(() => {
        Iif (typeof cropper !== 'undefined' && typeof src !== 'undefined') {
            cropper.reset().clear().replace(src);
            __applyDefaultOptions(cropper, defaultOptions);
        }
    }, [src]);
 
    return (
        <div style={style} className={className}>
            <img crossOrigin={crossOrigin} src={src} alt={alt} style={{opacity: 0, maxWidth: '100%'}} ref={imageRef} />
        </div>
    );
};
 
export {ReactCropper, ReactCropperProps, __applyDefaultOptions};