declare namespace Cropper {
  export type Action = 'crop' | 'move' | 'zoom' | 'e' | 's' | 'w' | 'n' | 'ne' | 'nw' | 'se' | 'sw' | 'all';
  export type DragMode = 'crop' | 'move' | 'none';
  export type ImageSmoothingQuality = 'low' | 'medium' | 'high';
  export type ViewMode = 0 | 1 | 2 | 3;

  export interface Data {
    x: number;
    y: number;
    width: number;
    height: number;
    rotate: number;
    scaleX: number;
    scaleY: number;
  }

  export interface ContainerData {
    width: number;
    height: number;
  }

  export interface ImageData {
    left: number;
    top: number;
    width: number;
    height: number;
    rotate: number;
    scaleX: number;
    scaleY: number;
    naturalWidth: number;
    naturalHeight: number;
    aspectRatio: number;
  }

  export interface CanvasData {
    left: number;
    top: number;
    width: number;
    height: number;
    naturalWidth: number;
    naturalHeight: number;
  }

  export interface CropBoxData {
    left: number;
    top: number;
    width: number;
    height: number;
  }

  export interface GetCroppedCanvasOptions {
    width?: number;
    height?: number;
    minWidth?: number;
    minHeight?: number;
    maxWidth?: number;
    maxHeight?: number;
    rounded?: boolean;
    fillColor?: string;
    imageSmoothingEnabled?: boolean;
    imageSmoothingQuality?: ImageSmoothingQuality;
  }

  export interface SetDataOptions {
    x?: number;
    y?: number;
    width?: number;
    height?: number;
    rotate?: number;
    scaleX?: number;
    scaleY?: number;
  }

  export interface SetCanvasDataOptions {
    left?: number;
    top?: number;
    width?: number;
    height?: number;
  }

  export interface SetCropBoxDataOptions {
    left?: number;
    top?: number;
    width?: number;
    height?: number;
  }

  interface CropperEvent<T extends EventTarget = EventTarget> extends CustomEvent {
    currentTarget: T & { cropper: Cropper };
  }

  export type ReadyEvent<T extends EventTarget> = CropperEvent<T>

  export interface CropEvent<T extends EventTarget = EventTarget> extends CropperEvent<T> {
    detail: Data;
  }

  export interface CropEventData {
    originalEvent: PointerEvent | TouchEvent | MouseEvent;
    action: Action;
  }

  export interface CropStartEvent<T extends EventTarget = EventTarget> extends CropperEvent<T> {
    detail: CropEventData;
  }

  export interface CropMoveEvent<T extends EventTarget = EventTarget> extends CropperEvent<T> {
    detail: CropEventData;
  }

  export interface CropEndEvent<T extends EventTarget = EventTarget> extends CropperEvent<T> {
    detail: CropEventData;
  }

  export interface ZoomEventData {
    originalEvent: WheelEvent | PointerEvent | TouchEvent | MouseEvent;
    oldRatio: number;
    ratio: number;
  }

  export interface ZoomEvent<T extends EventTarget = EventTarget> extends CropperEvent<T> {
    detail: ZoomEventData;
  }

  export interface Options<T extends EventTarget = EventTarget> {
    aspectRatio?: number;
    autoCrop?: boolean;
    autoCropArea?: number;
    background?: boolean;
    center?: boolean;
    checkCrossOrigin?: boolean;
    checkOrientation?: boolean;
    cropBoxMovable?: boolean;
    cropBoxResizable?: boolean;
    data?: SetDataOptions;
    dragMode?: DragMode;
    guides?: boolean;
    highlight?: boolean;
    initialAspectRatio?: number;
    minCanvasHeight?: number;
    minCanvasWidth?: number;
    minContainerHeight?: number;
    minContainerWidth?: number;
    minCropBoxHeight?: number;
    minCropBoxWidth?: number;
    modal?: boolean;
    movable?: boolean;
    preview?: HTMLElement | HTMLElement[] | NodeListOf<HTMLElement> | string;
    responsive?: boolean;
    restore?: boolean;
    rotatable?: boolean;
    scalable?: boolean;
    toggleDragModeOnDblclick?: boolean;
    viewMode?: ViewMode;
    wheelZoomRatio?: number;
    zoomOnTouch?: boolean;
    zoomOnWheel?: boolean;
    zoomable?: boolean;
    ready?(event: ReadyEvent<T>): void;
    crop?(event: CropEvent<T>): void;
    cropend?(event: CropEndEvent<T>): void;
    cropmove?(event: CropMoveEvent<T>): void;
    cropstart?(event: CropStartEvent<T>): void;
    zoom?(event: ZoomEvent<T>): void;
  }
}

declare class Cropper {
  constructor(element: HTMLImageElement, options?: Cropper.Options<HTMLImageElement>);
  constructor(element: HTMLCanvasElement, options?: Cropper.Options<HTMLCanvasElement>);
  clear(): Cropper;
  crop(): Cropper;
  destroy(): Cropper;
  disable(): Cropper;
  enable(): Cropper;
  getCanvasData(): Cropper.CanvasData;
  getContainerData(): Cropper.ContainerData;
  getCropBoxData(): Cropper.CropBoxData;
  getCroppedCanvas(options?: Cropper.GetCroppedCanvasOptions): HTMLCanvasElement;
  getData(rounded?: boolean): Cropper.Data;
  getImageData(): Cropper.ImageData;
  move(offsetX: number, offsetY?: number): Cropper;
  moveTo(x: number, y?: number): Cropper;
  replace(url: string, onlyColorChanged?: boolean): Cropper;
  reset(): Cropper;
  rotate(degree: number): Cropper;
  rotateTo(degree: number): Cropper;
  scale(scaleX: number, scaleY?: number): Cropper;
  scaleX(scaleX: number): Cropper;
  scaleY(scaleY: number): Cropper;
  setAspectRatio(aspectRatio: number): Cropper;
  setCanvasData(data: Cropper.SetCanvasDataOptions): Cropper;
  setCropBoxData(data: Cropper.SetCropBoxDataOptions): Cropper;
  setData(data: Cropper.SetDataOptions): Cropper;
  setDragMode(dragMode: Cropper.DragMode): Cropper;
  zoom(ratio: number): Cropper;
  zoomTo(ratio: number, pivot?: { x: number; y: number }): Cropper;
  static noConflict(): Cropper;
  static setDefaults(options: Cropper.Options<EventTarget>): void;
}

declare module 'cropperjs' {
  export default Cropper;
}
