packages/react-moveable/src/types.ts

import { IObject } from "@daybrush/utils";
import Gesto, * as GestoTypes from "gesto";
import CustomGesto from "./gesto/CustomGesto";
import { MoveableTargetInfo } from "./utils/getMoveableTargetInfo";
import { DragScrollOptions } from "@scena/dragscroll";
import { MOVEABLE_PROPS, MOVEABLE_EVENTS } from "./ables/consts";

export interface MoveableClientRect {
    left: number;
    top: number;
    right: number;
    bottom: number;
    width: number;
    height: number;
    clientLeft?: number;
    clientTop?: number;
    clientWidth?: number;
    clientHeight?: number;
    scrollWidth?: number;
    scrollHeight?: number;
    overflow?: boolean;
}
export type MoveableManagerProps<T = {}> = {
    cssStyled: any;
    customStyledMap: Record<string, any>;
    wrapperMoveable?: MoveableManagerInterface | null;
    isWrapperMounted?: boolean;
    parentMoveable?: MoveableManagerInterface | null;
    parentPosition?: number[] | null;
    groupable?: boolean;
} & MoveableDefaultOptions & (unknown extends T ? IObject<any> : T);

export type AnyObject<T> = (unknown extends T ? IObject<any> : T);

/**
 * @typedef
 * @memberof Moveable
 */
export interface MoveablePosition {
    left: number;
    top: number;
    right: number;
    bottom: number;
    origin: number[];
    pos1: number[];
    pos2: number[];
    pos3: number[];
    pos4: number[];
    direction: 1 | -1;
}

/**
 * @typedef
 * @memberof Moveable
 * @options
 */
export interface DefaultOptions {
    /**
     * The target(s) to indicate Moveable Control Box.
     * @default null
     */
    target?: SVGElement | HTMLElement | null;
    /**
     * The external target(s) to drag Moveable target(s)
     * @default target
     */
    dragTarget?: MoveableRefType | null;
    /**
     * If dragTarget is set directly, taget itself cannot be dragged.
     * Whether to drag the target as well.
     * @default false
     */
    dragTargetSelf?: boolean;
    /**
     * Container area where drag works
     * @default window
     */
    dragContainer?: null | Window | MoveableRefType<HTMLElement>;
    /**
     * A container into which Moveables are inserted.
     * Set it only when used within the slot of Web Components or when the container is different.
     * @default parentElement
     */
    container?: SVGElement | HTMLElement | null;
    /**
     * Whether to warp itself to the container itself. Don't set it.
     * @private
     * @default false
     */
    warpSelf?: boolean;
    /**
     * Moveable Root Container (No Transformed Container)
     * @default parentElement
     * @story options--options-root-container
     */
    rootContainer?: MoveableRefType<HTMLElement>;
    /**
     * If you want to set the dragging information to the viewer, refer to the following.
     * @default null
     * @story options--options-view-container
     */
    viewContainer?: MoveableRefType<HTMLElement>;
    /**
     * Whether the target size is detected and updated whenever it changes.
     * It is more effective when used together with `useMutationObserver`.
     * @default false
     * @story options--options-resize-observer
     */
    useResizeObserver?: boolean;
    /**
     * Whether the target size, pos in inline style is detected and updated whenever it changes.
     * It is more effective when used together with `useResizeObserver`.
     * @default false
     * @story options--options-mutation-observer
     */
    useMutationObserver?: boolean;
    /**
     * Zooms in the elements of a moveable.
     * @default 1
     */
    zoom?: number;
    /**
     * The default transformOrigin of the target can be set in advance.
     * @default ""
     */
    transformOrigin?: Array<string | number> | string | "";
    /**
     * You can add your custom able.
     * @default []
     */
    ables?: Able[];
    /**
     * You can specify the className of the moveable controlbox.
     * @default ""
     */
    className?: string;
    /**
     * Minimum distance to pinch.
     * @default 20
     */
    pinchThreshold?: number;
    /**
     * Whether the container containing the target becomes a pinch.
     * @default true
     */
    pinchOutside?: boolean;
    /**
     * Lets generate events of ables at the same time. (like Resizable, Scalable)
     * @default false
     */
    triggerAblesSimultaneously?: boolean;
    /**
     * Checks whether this is an element to input text or contentEditable, and prevents dragging.
     * @default false
     */
    checkInput?: boolean;
    /**
     * add nonce property to style for CSP.
     * @deprecated
     * @default ""
     */
    cspNonce?: string;
    /**
     * You can set the translateZ value of moveable.
     * @default 50
     */
    translateZ?: number | string;
    /**
     * Whether to hide the line corresponding to the rect of the target.
     * @default false
     */
    hideDefaultLines?: boolean;
    /**
     * Whether to prevent bubbling of events like mousedown, touchstart, etc.
     * @default false
     */
    stopPropagation?: boolean;
    /**
     * Whether to call preventDefault on touchstart or mousedown
     * @since 0.44.0
     * @default true
     */
    preventDefault?: boolean;
    /**
     * Whether to prevent dragging using the right mouse button
     * @default true
     */
    preventRightClick?: boolean;
    /**
     * Whether to prevent dragging using the wheel (middle) mouse button
     * @default true
     */
    preventWheelClick?: boolean;
    /**
     * Prevent click event on drag. (mousemove, touchmove)
     * @default true
     */
    preventClickEventOnDrag?: boolean;
    /**
     * Whether to drag the focused input
     * If `checkInput` is true, this option is not applied.
     * @since 0.47.0
     * @story options--options-drag-focused-input
     * @default false
     */
    dragFocusedInput?: boolean;
    /**
     * Prevent click event on dragStart. (mousedown, touchstart)
     * @default false
     */
    preventClickDefault?: boolean;
    /**
     * You can use props in object format or custom props.
     * @default empty object
     */
    props?: Record<string, any>;
    /**
     * Data for first render
     * @default null
     */
    persistData?: PersistRectData | null;
    /**
     * Whether to accurately show the position of a movable control box
     * Because getBoundingClientRect is used, css zoom, transform: rotate between container and rootContainer cannot be used.
     * group is not supported.
     * @default false
     */
    useAccuratePosition?: boolean;
    /**
     * By adding padding to the line, you can increase the area of the line that can be clicked and dragged.
     * @since 0.43.0
     * @story options--options-line-padding
     * @default 0
     */
    linePadding?: number;
    /**
     * By adding padding to the control, you can increase the area of the control that can be clicked and dragged.
     * Either `rotateAroundControls` or `displayAroundControls` can be used.
     * @since 0.44.0
     * @story options--options-control-padding
     * @default 0
     */
    controlPadding?: number;
    /**
     * @private
     * single => group로 변환과정에 도형 유지를 위한 첫 렌더링 state
     */
    firstRenderState?: MoveableManagerState | null;
    /**
     * @private
     */
    requestStyles?: string[];
    /**
     * If you are using React 18's concurrent mode, use `flushSync` for UI sync.
     * @default empty function
     * @example
     * ```jsx
     * import { flushSync } from "react-dom";
     *
     * <Moveable flushSync={flushSync} />
     * ```
     */
    flushSync?: (callback: () => void) => void;
}
/**
 * @typedef
 * @extends Moveable.DefaultOptions
 * @extends Moveable.DragAreaOptions
 * @extends Moveable.OriginOptions
 * @extends Moveable.PaddingOptions
 */
export interface MoveableDefaultOptions
    extends DefaultOptions, DragAreaOptions, OriginOptions, PaddingOptions {
}
export interface MatrixInfo {
    type: "offset" | "target" | "zoom";
    target: SVGElement | HTMLElement;
    matrix?: number[];
    origin?: number[];
    zoom?: number;
}
export type MoveableManagerState<T = {}> = {
    container: SVGElement | HTMLElement | null | undefined;
    disableNativeEvent: boolean;
    gestos: Record<string, Gesto | CustomGesto | null>;
    renderLines: number[][][];
    renderPoses: number[][];
    posDelta: number[];
    style: Partial<Writable<CSSStyleDeclaration>>;
    isPersisted?: boolean;
} & MoveableTargetInfo & T;

/**
 * @typedef
 * @memberof Moveable
 */
export interface ElementSizes {
    svg: boolean;
    offsetWidth: number;
    offsetHeight: number;
    clientWidth: number;
    clientHeight: number;
    inlineCSSWidth: number;
    inlineCSSHeight: number;
    cssWidth: number;
    cssHeight: number;
    contentWidth: number;
    contentHeight: number;
    minWidth: number;
    minHeight: number;
    maxWidth: number;
    maxHeight: number;
    minOffsetWidth: number;
    minOffsetHeight: number;
    maxOffsetWidth: number;
    maxOffsetHeight: number;
}

/**
 * @typedef
 * @memberof Moveable
 */
export type LineDirection = "n" | "e" | "s" | "w" | "nw" | "ne" | "sw" | "se";

/**
 * @typedef
 * @memberof Moveable
 * @property - left padding
 * @property - top padding
 * @property - right padding
 * @property - bottom padding
 */
export interface PaddingBox {
    left?: number;
    top?: number;
    right?: number;
    bottom?: number;
}

export interface Renderer {
    createElement(type: any, props?: any, ...children: any[]): any;
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface SnapGuideline {
    type: "horizontal" | "vertical";
    direction: string;
    hide?: boolean;
    element?: Element | null;

    isStart?: boolean;
    isEnd?: boolean;
    isCenter?: boolean;
    isInner?: boolean;
    grid?: boolean;

    pos: number[];
    size: number;
    className?: string;
    sizes?: number[];

    gap?: number;
    elementDirection?: string;
    elementRect?: SnapElementRect;
    gapRects?: SnapElementRect[];
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface SnapElementGuideline extends SnapGuideline {

}

export interface SnapBoundInfo {
    isBound: boolean;
    isSnap: boolean;
    offset: number;
    dist: number;
    snapIndex?: number;
    bounds?: BoundInfo[];
    snap?: SnapInfo;
}
export interface BoundInfo {
    direction?: "start" | "end";
    isBound: boolean;
    offset: number;
    pos: number;
}
export interface SnapOffsetInfo {
    isSnap: boolean;
    offset: number;
    pos: number;
}
export interface SnapDirectionInfo extends SnapInfo {
    direction: string;
}
export interface SnapInfo {
    isSnap: boolean;
    index: number;
    direction: string;
    posInfos: SnapPosInfo[];
}
export interface SnapPosInfo {
    pos: number;
    index: number;
    direction: string;
    guidelineInfos: SnapGuidelineInfo[];
}
export interface SnapGuidelineInfo {
    dist: number;
    offset: number;
    direction: string;
    guideline: SnapGuideline;
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface RenderGuidelineInfo {
    key?: string;
    direction: string;
    classNames: string[];
    size: string;
    pos: string[];
    sizeValue: number;
    posValue: number[];
    zoom: number;
}
export interface RenderGuidelineInnerInfo {
    key?: string;
    direction: string;
    classNames: Array<string | undefined>;
    size?: string;
    pos?: string[];
    sizeValue: number;
    posValue: number[];
    zoom: number;
}
export type ExcludeKeys<T extends IObject<any>, U> = Pick<T, Exclude<keyof T, U>>;

export interface MoveableProps extends
    MoveableDefaultProps,
    DraggableProps,
    DragAreaProps,
    OriginDraggableProps,
    RotatableProps,
    ResizableProps,
    ScalableProps,
    WarpableProps,
    PinchableProps,
    ExcludeKeys<GroupableProps, "targets" | "updateGroup">,
    IndividualGroupableProps,
    SnappableProps,
    ScrollableProps,
    ClippableProps,
    RoundableProps,
    BeforeRenderableProps,
    ClickableProps,
    RenderableProps {
}
/**
 * @memberof Moveable
 * @typedef
 */
export interface MoveableDefaultEvents {
    onChangeTargets?: (e: OnChangeTargets) => void;
}

export interface MoveableInitalOptions extends ExcludeKeys<MoveableDefaultOptions, "target"> {
    target?: MoveableRefTargetType;
}

/**
 * @memberof Moveable
 * @typedef
 * @extends Moveable.MoveableDefaultOptions
 * @extends Moveable.MoveableDefaultEvents
 */
export interface MoveableDefaultProps extends MoveableInitalOptions, MoveableDefaultEvents {

}
/**
 * @memberof Moveable
 * @typedef
 */
export type MoveableRefTargetType = MoveableRefType | ArrayFormat<MoveableRefTargetType>;

export type MoveableRefTargetsResultType
    = Array<HTMLElement | SVGElement | string | null | MoveableRefTargetsResultType>;

/**
 * @memberof Moveable
 * @typedef
 */
export type MoveableRefType<T extends Element = HTMLElement | SVGElement>
    = string | (() => T) | MoveableRefObject<T> | T | null | undefined;
/**
 * @memberof Moveable
 * @typedef
 */
export interface MoveableRefObject<T extends Element = HTMLElement | SVGElement> {
    current: T | undefined | null;
}
/**
 * @memberof Moveable
 * @typedef
 * @extends Moveable.MoveableDefaultProps
 * @extends Moveable.Draggable.DraggableOptions
 * @extends Moveable.Resizable.ResizableOptions
 * @extends Moveable.Scalable.ScalableOptions
 * @extends Moveable.Rotatable.RotatableOptions
 * @extends Moveable.Warpable.WarpableOptions
 * @extends Moveable.Pinchable.PinchableOptions
 * @extends Moveable.Group.GroupableOptions
 * @extends Moveable.OriginDraggable.OriginDraggableOptions
 * @extends Moveable.Scrollable.ScrollableOptions
 * @extends Moveable.Clippable.ClippableOptions
 * @extends Moveable.Roundable.RoundableOptions
 * @extends Moveable.Clickable.ClickableOptions
 */
export interface MoveableOptions extends
    MoveableInitalOptions,
    DraggableOptions,
    DragAreaOptions,
    OriginDraggableOptions,
    RotatableOptions,
    ResizableOptions,
    ScalableOptions,
    WarpableOptions,
    PinchableOptions,
    GroupableOptions,
    IndividualGroupableOptions,
    SnappableOptions,
    ScrollableOptions,
    ClippableOptions,
    RoundableOptions,
    ClickableOptions {
}

export type MoveableState = MoveableManagerState;

/**
 * You can make Able that can work in Moveable.
 * @typedef
 * In Able, you can manage drag events, props, state, fire event props, and render elements.
 * @memberof Moveable
 */
export interface Able<
    Props extends IObject<any> = IObject<any>,
    Events extends IObject<any> = IObject<any>
> {
    name: string;
    props?: readonly (keyof Props)[];
    events?: readonly (keyof Events)[];
    // Whether to always include in able. It is recommended to use always in frameworks other than react
    always?: boolean;
    ableGroup?: string;
    updateRect?: boolean;
    canPinch?: boolean;
    css?: string[];
    /**
     * You can request style. Specify the name of the style in camel case.
     * You can check it with `moveable.state.style`
     * @exmaple
     * ["borderRadius", "top", "left"]
     */
    requestStyle?(): string[];
    /**
     * If you use group, you can request child style. Specify the name of the style in camel case.
     * You can check it with `moveable.state.style`
     * @exmaple
     * ["borderRadius", "top", "left"]
     */
    requestChildStyle?(): string[];
    /**
     * You can specify the class name to be added to the Moveable control box.
     */
    className?(moveable: any): string;
    /**
     * You can specify the class name to be added to the Moveable View Container
     */
    viewClassName?(moveable: any): string;
    /**
     * Check how related to drag
     */
    dragRelation?: "strong" | "weak" | undefined | null | false,
    /**
     * Fired when the event is cleared
     */
    unset?(moveable: any): any;
    /**
     * Renders the React DOM structure for the able.
     */
    render?(moveable: any, renderer: Renderer): any;

    // Operates when a drag event occurs for the single target.
    dragStart?(moveable: any, e: any): any;
    drag?(moveable: any, e: any): any;
    dragEnd?(moveable: any, e: any): any;
    dragAfter?(moveable: any, e: any): any;

    // Operates when a pinch event occurs for the single target.
    pinchStart?(moveable: any, e: GestoTypes.OnPinchStart): any;
    pinch?(moveable: any, e: GestoTypes.OnPinch): any;
    pinchEnd?(moveable: any, e: GestoTypes.OnPinchEnd): any;

    // Condition that occurs dragControl
    dragControlCondition?(moveable: any, e: any): boolean;
    // Operates when a drag event occurs for the moveable control and single target.
    dragControlStart?(moveable: any, e: any): any;
    dragControl?(moveable: any, e: any): any;
    dragControlEnd?(moveable: any, e: any): any;
    dragControlAfter?(moveable: any, e: any): any;

    // Condition that occurs dragGroup
    dragGroupCondition?(moveable: any, e: any): boolean;
    // Operates when a drag event occurs for the multi target.
    dragGroupStart?(moveable: any, e: any): any;
    dragGroup?(moveable: any, e: any): any;
    dragGroupEnd?(moveable: any, e: any): any;

    // Operates when a pinch event occurs for the multi target.
    pinchGroupStart?(moveable: any, e: GestoTypes.OnPinchStart): any;
    pinchGroup?(moveable: any, e: GestoTypes.OnPinch): any;
    pinchGroupEnd?(moveable: any, e: GestoTypes.OnPinchEnd): any;

    // Condition that occurs dragGroupControl
    dragGroupControlCondition?(moveable: any, e: any): boolean;

    // Operates when a drag event occurs for the moveable control and multi target.
    dragGroupControlStart?(moveable: any, e: any): any;
    dragGroupControl?(moveable: any, e: any): any;
    dragGroupControlEnd?(moveable: any, e: any): any;

    // mouse enter event
    mouseEnter?(moveable: any, e: any): any;
    // mouse leave event
    mouseLeave?(moveable: any, e: any): any;

    // mouse enter event for group
    mouseGroupEnter?(moveable: any, e: any): any;
    // mouse leave event for group
    mouseGroupLeave?(moveable: any, e: any): any;


    // Execute the operation of able for external request
    request?(moveable: any): AbleRequester;
}

/**
 * @typedef
 * @memberof Moveable
 */
export interface OnEvent {
    /**
     * The Moveable instance
     */
    currentTarget: MoveableManagerInterface<Record<string, any>, Record<string, any>>;
    /**
     * The Moveable instance
     */
    moveable: MoveableManagerInterface<Record<string, any>, Record<string, any>>;
    /**
     * The Moveable's target
     */
    target: HTMLElement | SVGElement;
    /**
     * The horizontal coordinate within the application's client area at which the event occurred.
     */
    clientX: number;
    /**
     * The vertical coordinate within the application's client area at which the event occurred.
     */
    clientY: number;
    /**
     * Whether this is the first drag in the drag event
     */
    isFirstDrag: number;
    /**
     * Objects that can send information to the following events.
     */
    datas: IObject<any>;
    /**
     * The mouse or touch input event that is invoking the moveable event
     */
    inputEvent: any;
    /**
     * Stop the currently working able.
     */
    stopAble(): void;
    /**
     * Calling `stopDrag` in a drag-related event ends the drag.
     */
    stopDrag(): void;
    /**
     * Whether the event did not occur externally
     */
    isTrusted: boolean;

}
/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @property - This is the last dragged event. No, if you haven't dragged.
 * @property - Whether this moved
 * @property - Whether it is double-click
 */
export interface OnEndEvent extends OnEvent {
    lastEvent: any | undefined;
    isDrag: boolean;
    isDouble: boolean;
}
/**
 * @typedef
 * @memberof Moveable
 */
export interface OnTransformStartEvent {
    /**
     * Set your original transform.
     * `transformIndex` is the sequence of functions used in the event.
     * If you use `setTransform`, you don't need to use `set` function.
     * @default transform of target's inline style
     */
    setTransform(transform: string | string[], transformIndex?: number): void;
    /**
     * `transformIndex` is the sequence of functions used in the event.
     * @default index with that property in transform or last
     */
    setTransformIndex(transformIndex: number): void;
}
/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.CSSObject
 */
export interface TransformObject extends CSSObject {
    /**
     * a target's next transform string value.
     */
    transform: string;
    /**
     * A transform obtained by the simultaneous occurrence of other events in the current event
     */
    afterTransform: string;
}
/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.TransformObject
 */
export interface OnTransformEvent extends TransformObject {
    /**
     * transform events causes a `drag` event. In some events, there may be no value.
     */
    drag: OnDrag;
}
/**
 * @typedef
 * @memberof Moveable
 */
export interface AbleRequestParam {
    /**
     * Run the request instantly. (requestStart, request, requestEnd happen at the same time)
     */
    isInstant?: boolean;
    [key: string]: any;
}
/**
 * @typedef
 * @memberof Moveable
 * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.html#request|Request Method}
 * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Draggable.html#request|Draggable Requester}
 * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Resizable.html#request|Resizable Requester}
 * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Scalable.html#request|Scalable Requester}
 * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Rotatable.html#request|Rotatable Requester}
 * @property - Continue executing the request.
 * @property - End the request.
 */
export interface Requester<RequestParam extends {} = AbleRequestParam> {
    request(param: RequestParam): this;
    requestEnd(): this;
}

export interface AbleRequester {
    isControl: boolean;
    requestStart(param: IObject<any>): IObject<any>;
    request(param: IObject<any>): IObject<any>;
    requestEnd(): IObject<any>;
}


/**
 * @typedef
 * @memberof Moveable
 */
export interface OnChangeTargets {
    /**
     * The Moveable instance
     */
    moveable: MoveableManagerInterface<any, any>;
    /**
     * The Moveable's targets
     */
    targets: Array<HTMLElement | SVGElement>;
}



/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnEvent
 */
export interface OnPinchStart extends OnEvent {
}
/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnEvent
 */
export interface OnPinch extends OnEvent {
}
/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnEndEvent
 */
export interface OnPinchEnd extends OnEndEvent { }
/**
 * When the drag starts, the dragStart event is called.
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformStartEvent
 */
export interface OnDragStart extends OnEvent, OnTransformStartEvent {
    /**
     * You can set the start translate value.
     */
    set: (translate: number[]) => void;
}
/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 * @property - The delta of [left, top]
 * @property - The distance of [left, top]
 * @property - The position of [left, top]
 * @property - The delta of [translateX, translateY]
 * @property - The distance of [translateX, translateY]
 * @property - The position of [translateX, translateY]
 * @property - a target's transform
 * @property - a target's left
 * @property - a target's top
 * @property - a target's bottom
 * @property - a target's offset width
 * @property - a target's offset height
 * @property - a target's right
 * @property - Whether or not it is being pinched.
 */
export interface OnDrag extends OnEvent, CSSObject {
    beforeDelta: number[];
    beforeDist: number[];
    beforeTranslate: number[];
    delta: number[];
    dist: number[];
    translate: number[];
    transform: string;
    left: number;
    top: number;
    bottom: number;
    width: number;
    height: number;
    right: number;
    isPinch: boolean;
}
/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnEndEvent
 */
export interface OnDragEnd extends OnEndEvent {
}

/**
 * @typedef
 * @memberof Moveable.OriginDraggable
 * @extends Moveable.OnEvent
 * @property - dragOrigin causes a `dragStart` event.
 */
export interface OnDragOriginStart extends OnEvent {
    dragStart: OnDragStart | false;
}

/**
 * @typedef
 * @memberof Moveable.OriginDraggable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 */
export interface OnDragOrigin extends OnEvent, CSSObject {
    /**
     * Offset width of target
     */
    width: number;
    /**
     * Offset height of target
     */
    height: number;
    /**
     * The delta of [x, y]
     */
    delta: number[];
    /**
     * The distance of [x, y]
     */
    dist: number[];
    /**
     * The target's moved transform-origin poses
     */
    origin: number[];
    /**
     * The target's moved transform-origin css
     */
    transformOrigin: string;
    /**
     * A transform obtained by the simultaneous occurrence of other events in the current event
     */
    afterTransform: string;
    /**
     * `dragOrigin` causes a `drag` event.
     */
    drag: OnDrag;

}
/**
 * @typedef
 * @memberof Moveable.OriginDraggable
 * @extends Moveable.OnEndEvent
 */
export interface OnDragOriginEnd extends OnEndEvent {
}

/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnEvent
 */
export interface OnRoundStart extends OnEvent { }

/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 * @property - Offset width of target
 * @property - Offset height of target
 * @property - The delta of [x, y]
 * @property - The distance of [x, y]
 * @property - The target's moved border-radius's horizontal poses
 * @property - The target's moved border-radius's vertical poses
 * @property - The target's moved border-radius
 */
export interface OnRound extends OnEvent, CSSObject {
    width: number;
    height: number;
    delta: number[];
    dist: number[];
    horizontals: number[];
    verticals: number[];
    borderRadius: string;

}

/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnEndEvent
 */
export interface OnRoundEnd extends OnEndEvent {
}


/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnRoundStart
 */
export interface OnRoundGroupStart extends OnRoundStart {
    /**
     * moveable's targets
     */
    targets: Array<HTMLElement | SVGElement>;
    /**
     * moveable's child events
     */
    events: OnRoundStart[];
}

/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnRound
 */
export interface OnRoundGroup extends OnRound {
    /**
     * moveable's targets
     */
    targets: Array<HTMLElement | SVGElement>;
    /**
     * moveable's child events
     */
    events: OnRound[];
}

/**
 * @typedef
 * @memberof Moveable.Roundable
 * @extends Moveable.OnRoundEnd
 */
export interface OnRoundGroupEnd extends OnRoundEnd {
    /**
     * moveable's targets
     */
    targets: Array<HTMLElement | SVGElement>;
    /**
     * moveable's child events
     */
    events: OnRoundEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformStartEvent
 */
export interface OnScaleStart extends OnEvent, OnTransformStartEvent {
    /**
     * The direction of scale.
     */
    direction: number[];
    /**
     * scale causes a `dragStart` event.
     */
    dragStart: OnDragStart | false;
    /**
     * You can set the start scale value.
     */
    set: (scale: number[]) => void;
    /**
     * Set a fixed direction to scale.
     * @default Opposite direction
     */
    setFixedDirection: (startDirecition: number[]) => void;
    /**
     * Set the ratio of width and height.
     * @default offsetWidth / offsetHeight
     */
    setRatio: (ratio: number) => void;
    /**
     * You can set the min scale width, height value.
     * scale size = scale value * offset size
     * @default [-Infinity, -Infinity]
     */
    setMinScaleSize: (min: number[]) => void;
    /**
     * You can set the max scale width, height value.
     * scale size = scale value * offset size
     * @default [Infinity, Infinity]
     */
    setMaxScaleSize: (max: number[]) => void;
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnEvent
 */
export interface OnBeforeScale extends OnEvent {
    /**
     * Set a fixed direction to scale.
     * If fixedDirection is set, the scale values can be changed and can be reconfirmed as a return value.
     */
    setFixedDirection: (startDirecition: number[]) => number[];
    /**
     * fixedDirection set by rotateStart.
     */
    startFixedDirection: number[];
    /**
     * Set target's scale to scaling.
     */
    setScale: (scale: number[]) => void;
    /**
     * a target's scale before snap and throttle and format
     */
    scale: number[];
}


/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformEvent
 * @property - The direction of scale.
 * @property - a target's offsetWidth
 * @property - a target's offsetHeight
 * @property - a target's scale
 * @property - The distance of scale
 * @property - The delta of scale
 * @property - Whether or not it is being pinched.
 */
export interface OnScale extends OnEvent, OnTransformEvent {
    direction: number[];
    offsetWidth: number;
    offsetHeight: number;

    scale: number[];
    dist: number[];
    delta: number[];

    isPinch: boolean;
}
/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnEndEvent
 */
export interface OnScaleEnd extends OnEndEvent {
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnEvent
 * @property - The direction of resize.
 * @property - resize causes a `dragStart` event.
 * @property - You can set the css width, height value.
 * @property - You can set the css min width, min height value. (default: min-width)
 * @property - You can set the css max width, max height value. (default: max-width)
 * @property - You can set the css origin (default: % %)
 * @property - Set a fixed direction to resize. (default: Opposite direction)
 * @property - Set the ratio of width and height. (default: offsetWidth / offsetHeight)
 */
export interface OnResizeStart extends OnEvent {
    /**
     * The direction of resize.
     */
    direction: number[];
    /**
     * First set (boundingWidth / boundingHeight) value
     */
    startRatio: number;
    /**
     * resize causes a `dragStart` event.
     */
    dragStart: OnDragStart | false;
    /**
     * You can set the css width, height value.
     */
    set: (size: number[]) => any;
    /**
     * You can set the css min offset width, min offset height value.
     * @default [minOffsetWidth, minOffsetHeight])
     */
    setMin: (minSize: Array<string | number>) => any;
    /**
     * You can set the css max offset width, max offset height value.
     * @default [maxOffsetWidth, maxOffsetHeight])
     */
    setMax: (maxSize: Array<string | number>) => any;
    /**
     * You can set the css origin
     * @default transformOrigin
     */
    setOrigin: (origin: Array<string | number>) => any;
    /**
     * Set a fixed direction to resize.
     * @default Opposite direction
     */
    setFixedDirection: (startDirecition: number[]) => any;
    /**
     * Set a fixed direction to resize.
     * @default Opposite position
     * @private
     */
    setFixedPosition: (startPosition: number[]) => any;
    /**
     * Set the ratio of width and height.
     * @default offsetWidth / offsetHeight
     */
    setRatio: (ratio: number) => any;
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnEvent
 */
export interface OnBeforeResize extends OnEvent {
    /**
     * Set a fixed direction to resize.
     * If fixedDirection is set, the boundingWidth and boundingHeight values can be changed and can be reconfirmed as a return value.
     */
    setFixedDirection: (startDirecition: number[]) => number[];
    /**
     * Set a fixed position to resize.
     * If fixedPosition is set, the boundingWidth and boundingHeight values can be changed and can be reconfirmed as a return value.
     * @private
     */
    setFixedPosition: (startPosition: number[]) => number[];
    /**
     * fixedDirection set by resizeStart.
     */
    startFixedDirection: number[];
    /**
     * fixedPosition set by resizeStart.
     * @private
     */
    startFixedPosition: number[];
    /**
     * Set the bounding size to resizing.
     */
    setSize: (size: number[]) => void;
    /**
     * a target's bounding width before snap and throttle and format
     */
    boundingWidth: number;
    /**
     * a target's bounding height before snap and throttle and format
     */
    boundingHeight: number;
}
/**
 * @typedef
 * @memberof Moveable
 */
export interface CSSObject {
    /**
     * You can get the style you can get from the event.
     */
    style: Record<string, string>;
    /**
     * You can get it as a cssText that you can get from that event.
     */
    cssText: string;
}
/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformEvent
 */
export interface OnResize extends OnEvent, OnTransformEvent {
    /**
     * The direction of resize.
     */
    direction: number[];
    /**
     * a target's cssWidth
     */
    width: number;
    /**
     * a target's cssHeight
     */
    height: number;
    /**
     * a target's offset width as an integer with bounding width
     */
    offsetWidth: number;
    /**
     * a target's offset height as an integer with bounding height
     */
    offsetHeight: number;
    /**
     * a target's bounding width
     */
    boundingWidth: number;
    /**
     * a target's bounding height
     */
    boundingHeight: number;
    /**
     * The distance of [boundingWidth, boundingHeight]
     */
    dist: number[];
    /**
     * The delta of [boundingWidth, boundingHeight]
     */
    delta: number[];
    /**
     * First set (boundingWidth / boundingHeight) value
     */
    startRatio: number;
    /**
     * Whether or not it is being pinched.
     */
    isPinch: boolean;
}
/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnEndEvent
 */
export interface OnResizeEnd extends OnEndEvent {
}
/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformStartEvent
 */
export interface OnRotateStart extends OnEvent, OnTransformStartEvent {
    /**
     * You can set the start rotate value.
     */
    set: (rotate: number) => void;
    /**
     * Set a fixed direction to rotate.
     * @default target's transformOrigin
     */
    setFixedDirection: (fixedDirection: number[]) => void;
    /**
     * Set a fixed position to rotate.
     * @default target's transformOrigin
     */
    setFixedPosition: (fixedPosition: number[]) => void;
    /**
     * rotate causes a `dragStart` event.
     */
    dragStart: OnDragStart | false;
    /**
     * rotate causes a `resizeStart` event.
     */
    resizeStart: OnResizeStart | false;
}
/**
 * @typedef
 * @description Parameters for the `beforeRotate` event
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnEvent
 */
export interface OnBeforeRotate extends OnEvent {
    /**
     * The rotation degree before transform is applied before snap and throttle and format
     */
    beforeRotation: number;
    /**
     * The rotation degree before snap and throttle and format
     */
    rotation: number;
    /**
     * The client rotation degree before snap and throttle and format
     */
    absoluteRotation: number;
    /**
     * You can set the value of `rotation`.
     */
    setRotation(nextRotation: number): void;
}


/**
 * @typedef
 * @description Parameters for the `rotate` event
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformEvent
 */
export interface OnRotate extends OnEvent, OnTransformEvent {
    /**
     * The distance of rotation degree before transform is applied
     */
    beforeDist: number;
    /**
     * The delta of rotation degree before transform is applied
     */
    beforeDelta: number;
    /**
     * The now rotation degree before transform is applied
     * @deprecated
     */
    beforeRotate: number;
    /**
     * The now rotation degree before transform is applied
     */
    beforeRotation: number;
    /**
     * The distance of rotation degree
     */
    dist: number;
    /**
     * The delta of rotation degree
     */
    delta: number;
    /**
     * The now rotation degree
     * @deprecated
     */
    rotate: number;
    /**
     * The now rotation degree
     */
    rotation: number;
    /**
     * The distance of client rotation degree
     */
    absoluteDist: number;
    /**
     * The delta of client rotation degree
     */
    absoluteDelta: number;
    /**
     * The now client rotation degree
     * @deprecated
     */
    absoluteRotate: number;
    /**
     * The now client rotation degree
     */
    absoluteRotation: number;
    /**
     * Whether or not it is being pinched.
     */
    isPinch: boolean;
    /**
     * rotate causes a `resize` event.
     */
    resize?: OnResize;
}
/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnEndEvent
 */
export interface OnRotateEnd extends OnEndEvent { }

/**
 * @typedef
 * @memberof Moveable.Warpable
 * @extends Moveable.OnEvent
 * @extends Moveable.OnTransformStartEvent
 * @property - You can set the start matrix value.
 */
export interface OnWarpStart extends OnEvent, OnTransformStartEvent {
    set: (matrix: number[]) => any;
}
/**
 * @typedef
 * @memberof Moveable.Warpable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 */
export interface OnWarp extends OnEvent, CSSObject {
    /**
     * The delta of warp matrix
     */
    delta: number[];
    /**
     * The dist of warp matrix
     */
    dist: number[];
    /**
     * The calculated warp matrix
     */
    matrix: number[];
    /**
     * a target's transform
     */
    transform: string;
    /**
     * Multiply function that can multiply previous matrix by warp matrix
     */
    multiply: (matrix1: number[], matrix2: number[], n?: number) => number[];
}
/**
 * @typedef
 * @memberof Moveable.Warpable
 * @extends Moveable.OnEndEvent
 */
export interface OnWarpEnd extends OnEndEvent { }

/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnDragStart
 * @property - targets to drag
 * @property - Each `dragStart` event on the targets
 */
export interface OnDragGroupStart extends OnDragStart {
    targets: Array<HTMLElement | SVGElement>;
    events: OnDragStart[];
}

/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnDrag
 * @property - The dragging targets
 * @property - Each `drag` event on the targets
 */
export interface OnDragGroup extends OnDrag {
    targets: Array<HTMLElement | SVGElement>;
    events: OnDrag[];
}
/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.OnDragEnd
 * @property - The drag finished targets
 * @property - Each `dragEnd` event on the targets
 */
export interface OnDragGroupEnd extends OnDragEnd {
    targets: Array<HTMLElement | SVGElement>;
    events: OnDragEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnRotateStart
 * @property - targets to rotate
 * @property - Each `rotateStart` event on the targets
 */
export interface OnRotateGroupStart extends OnRotateStart {
    targets: Array<HTMLElement | SVGElement>;
    events: OnRotateStart[];
}

/**
 * @typedef
 * @description Parameters for the `beforeRotateGroup` event
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnBeforeRotate
 */
export interface OnBeforeRotateGroup extends OnBeforeRotate {
    /**
     * The rotating targets
     */
    targets: Array<HTMLElement | SVGElement>;
}
/**
 * @typedef
 * @description Parameters for the `rotateGroup` event
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnRotate
 */
export interface OnRotateGroup extends OnRotate {
    /**
     * The rotating targets
     */
    targets: Array<HTMLElement | SVGElement>;
    /**
     * Each `rotate` event on the targets
     */
    events: OnRotate[];
    /**
     * You can set the group's rotation.
     * @deprecated
     */
    set: (rotation: number) => any;
    /**
     * You can set the group's rotation.
     */
    setGroupRotation: (rotation: number) => any;
}

/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.OnRotateEnd
 * @property - The rotate finished targets
 * @property - Each `rotateEnd` event on the targets
 */
export interface OnRotateGroupEnd extends OnRotateEnd {
    targets: Array<HTMLElement | SVGElement>;
    events: OnRotateEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnResizeStart
 * @property - targets to resize
 * @property - Each `resizeStart` event on the targets
 */
export interface OnResizeGroupStart extends OnResizeStart {
    targets: Array<HTMLElement | SVGElement>;
    events: OnResizeStart[];
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnBeforeResize
 */
export interface OnBeforeResizeGroup extends OnBeforeResize {
    /**
     * The resizing targets
     */
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnResize
 * @property - The resizing targets
 * @property - Each `resize`event on the targets
 */
export interface OnResizeGroup extends OnResize {
    targets: Array<HTMLElement | SVGElement>;
    events: OnResize[];
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.OnResizeEnd
 * @property - The resize finished targets
 * @property - Each `resizeEnd` event on the targets
 */
export interface OnResizeGroupEnd extends OnResizeEnd {
    targets: Array<HTMLElement | SVGElement>;
    events: OnResizeEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnScaleStart
 * @property - targets to scale
 * @property - Each `scaleStart` & `dragStart` event on the targets
 */
export interface OnScaleGroupStart extends OnScaleStart {
    targets: Array<HTMLElement | SVGElement>;
    events: OnScaleStart[];
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnBeforeScale
 * @property - The scaling targets
 */
export interface OnBeforeScaleGroup extends OnBeforeScale {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnScale
 * @property - The scaling targets
 * @property - Each `scale` & `drag` event on the targets
 */
export interface OnScaleGroup extends OnScale {
    targets: Array<HTMLElement | SVGElement>;
    events: OnScale[];
}

/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.OnScaleEnd
 * @property - The scale finished targets
 * @property - Each `scaleEnd` event on the targets
 */
export interface OnScaleGroupEnd extends OnScaleEnd {
    targets: Array<HTMLElement | SVGElement>;
    events: OnScaleEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnPinchStart
 * @property - targets to pinch
 */
export interface OnPinchGroupStart extends OnPinchStart {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnPinch
 * @property - targets to pinch
 */
export interface OnPinchGroup extends OnPinch {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable.Pinchable
 * @extends Moveable.OnPinchEnd
 * @property - The pinch finished targets
 */
export interface OnPinchGroupEnd extends OnPinchEnd {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 */
export interface OnClick extends OnEvent {
    /**
     * Clicked element.
     */
    inputTarget: Element;
    /**
     * clicked moveable target
     */
    moveableTarget: HTMLElement | SVGElement | null;
    /**
     * Whether the clicked target is moveable target.
     */
    isTarget: boolean;
    /**
     * Whether the clicked target is a child of moveable target.
     */
    containsTarget: boolean;
    /**
     * Whether it is double-click
     */
    isDouble: boolean;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnClick
 */
export interface OnClickGroup extends OnClick {
    /**
     * targets set to group.
     */
    targets: Element[];
    /**
     * The corresponding index among the targets set as a group.
     */
    targetIndex: number;
}

/**
 * `beforeRenderStart` event occurs before the first start of all events.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @property - Whether or not it is being pinched.
 * @property - Set your original transform.
 */
export interface OnBeforeRenderStart extends OnEvent {
    isPinch: boolean;
    setTransform(transform: string | string[]): any;
}

/**
 * `beforeRender` event occurs before the dragging of all events.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @property - Whether or not it is being pinched.
 */
export interface OnBeforeRender extends OnEvent {
    isPinch: boolean;
}

/**
 * `beforeRenderEnd` event occurs before the end of all events.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @property - Whether or not it is being dragged.
 * @property - Whether or not it is being pinched.
 */
export interface OnBeforeRenderEnd extends OnEvent {
    isPinch: boolean;
    isDrag: boolean;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnBeforeRenderStart
 * @property - targets set to group.
 * @property - children's `beforeRenderStart` events
 */
export interface OnBeforeRenderGroupStart extends OnBeforeRenderStart {
    targets: Array<HTMLElement | SVGElement>;
    events: OnBeforeRenderStart[];
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnBeforeRender
 * @property - targets set to group.
 * @property - children's `beforeRender` events
 */
export interface OnBeforeRenderGroup extends OnBeforeRender {
    targets: Array<HTMLElement | SVGElement>;
    events: OnBeforeRender[];
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnBeforeRenderEnd
 * @property - targets set to group.
 */
export interface OnBeforeRenderGroupEnd extends OnBeforeRenderEnd {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * `renderStart` event occurs at the first start of all events.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @property - Whether or not it is being pinched.
 */
export interface OnRenderStart extends OnEvent {
    isPinch: boolean;
}

/**
 * `render` event occurs before the target is drawn on the screen.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 */
export interface OnRender extends OnEvent, CSSObject {
    /**
     * a target's next transform string value.
     */
    transform: string;
    /**
     * Whether or not it is being pinched.
     */
    isPinch: boolean;
    /**
     * Return transform as a transform object.
     * `rotate` is a number and everything else is an array of numbers.
     */
    transformObject: Record<string, any>;
}

/**
 * `renderEnd` event occurs at the end of all events.
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 */
export interface OnRenderEnd extends OnEvent, CSSObject {
    /**
     * a target's next transform string value.
     */
    transform: string;
    /**
     * Whether or not it is being dragged.
     */
    isPinch: boolean;
    /**
     * Whether or not it is being pinched.
     */
    isDrag: boolean;
    /**
     * Return transform as a transform object.
     * `rotate` is a number and everything else is an array of numbers.
     */
    transformObject: Record<string, any>;
}

export type EventInterface<T extends IObject<any> = {}> = {
    [key in keyof T]?: (e: T[key]) => any;
};

/**
 * @typedef
 * @memberof Moveable.Scrollable
 * @extends Moveable.OnEvent
 * @property - The container corresponding to scrolling area (scrollContainer >= rootContainer >= container)
 * @property - The direction of scrolling [left, top]
 */
export interface OnScroll extends OnEvent {
    scrollContainer: HTMLElement;
    direction: number[];
}

/**
 * @typedef
 * @memberof Moveable.Scrollable
 * @extends Moveable.OnScroll
 * @property - targets set to group.
 */
export interface OnScrollGroup extends OnScroll {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnRenderStart
 * @property - targets set to group.
 */
export interface OnRenderGroupStart extends OnRenderStart {
    targets: Array<HTMLElement | SVGElement>;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnRender
 * @property - targets set to group.
 * @property - Each `render` event on the targets
 */
export interface OnRenderGroup extends OnRender {
    targets: Array<HTMLElement | SVGElement>;
    events: OnRender[];
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.OnRenderEnd
 * @property - targets set to group.
 * @property - Each `renderEnd` event on the targets
 */
export interface OnRenderGroupEnd extends OnRenderEnd {
    targets: Array<HTMLElement | SVGElement>;
    events: OnRenderEnd[];
}

/**
 * @typedef
 * @memberof Moveable.Draggable
 */
export interface DraggableOptions {
    /**
     * Whether or not target can be dragged.
     * @default false
     */
    draggable?: boolean;
    /**
     * throttle of x, y when drag.
     * @default 0
     */
    throttleDrag?: number;
    /**
     * throttle of angle(degree) of x,y when drag.
     * @default 0
     */
    throttleDragRotate?: number;
    /**
     * Hides the guidelines that appear when using the `throttleDragRotate` prop.
     * @default false
     */
    hideThrottleDragRotateLine?: boolean;
    /**
     * start angle(degree) of x,y for throttleDragRotate when drag.
     * @default 0
     */
    startDragRotate?: number;
    /**
     * Whether to move by dragging the edge line
     * @default false
     */
    edgeDraggable?: boolean | Array<LineDirection>;
}
export interface DraggableEvents {
    onDragStart: OnDragStart;
    onDrag: OnDrag;
    onDragEnd: OnDragEnd;

    onDragGroupStart: OnDragGroupStart;
    onDragGroup: OnDragGroup;
    onDragGroupEnd: OnDragGroupEnd;
}

export interface DraggableProps extends DraggableOptions, EventInterface<DraggableEvents> {
}

export interface DraggableState {
    dragInfo: {
        startRect: RectInfo;
        dist: number[];
    } | null;
}

/**
 * @typedef
 * @memberof Moveable
 */
export interface PaddingOptions {
    /**
     * Add padding around the target to increase the drag area.
     * @default null
     */
    padding?: PaddingBox | number;
}
/**
 * @typedef
 * @memberof Moveable
 */
export interface OriginOptions {
    /**
     * Whether or not the origin control box will be visible or not.
     * @default true
     */
    origin?: boolean;
    /**
     * Sets the transform origin based on the svg target. If not set, it is set as the transform origin based on the owner of svg.
     * @since 0.47.0
     * @default ""
     */
    svgOrigin?: string;
}
/**
 * @typedef
 * @memberof Moveable.OriginDraggable
 */
export interface OriginDraggableOptions {
    /**
     * Whether to drag origin.
     * @default false
     */
    originDraggable?: boolean;
    /**
     * % Can be used instead of the absolute px.
     * @default true
     */
    originRelative?: boolean;
}
export interface OriginDraggableEvents {
    onDragOriginStart: OnDragOriginStart;
    onDragOrigin: OnDragOrigin;
    onDragOriginEnd: OnDragOriginEnd;
}
export interface OriginDraggableProps extends OriginDraggableOptions, EventInterface<OriginDraggableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Roundable
 */
export interface RoundableOptions {
    /**
     * Whether to show and drag border-radius.
     * @default false
     */
    roundable?: boolean;
    /**
     * % Can be used instead of the absolute px
     * @default false
     */
    roundRelative?: boolean;
    /**
     * Minimum number of round controls. It moves in proportion by control. [horizontal, vertical]
     * @default [0, 0]
     */
    minRoundControls?: number[];
    /**
     * Maximum number of round controls. It moves in proportion by control. [horizontal, vertical]
     * @default [4, 4]
     */
    maxRoundControls?: number[];
    /**
     * Whether you can add/delete round controls by double-clicking a line or control.
     * @default true
     */
    roundClickable?: boolean | "line" | "control";
    /**
     * Whether to show a round control that does not actually exist as a shadow
     * @default false
     */
    isDisplayShadowRoundControls?: boolean | "horizontal";
    /**
     * The padding value of the position of the round control
     * @default 0
     */
    roundPadding?: number;
}

export interface RoundableEvents {
    onRoundStart: OnRoundStart;
    onRound: OnRound;
    onRoundEnd: OnRoundEnd;
    onRoundGroupStart: OnRoundGroupStart;
    onRoundGroup: OnRoundGroup;
    onRoundGroupEnd: OnRoundGroupEnd;
}
export interface RoundableProps extends RoundableOptions, EventInterface<RoundableEvents> {
}

export interface RoundableState {
    borderRadiusState?: string;
}
/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.RenderDirections
 */
export interface ResizableOptions extends RenderDirections {
    /**
     * Whether or not target can be resized.
     * @default false
     */
    resizable?: boolean | ResizableOptions;
    /**
     * throttle of width, height when resize.
     * @default 1
     */
    throttleResize?: number;
    /**
     * When resize or scale, keeps a ratio of the width, height.
     * @default false
     */
    keepRatio?: boolean;
    /**
     * The size can be changed by format and throttle, but the ratio is maintained at the end. Forced true when using groups.
     * @default false
     */
    keepRatioFinally?: boolean;
    /**
     * Function to convert size for resize.
     * @default oneself
     */
    resizeFormat?: (size: number[]) => number[];
    /**
     * Whether to scale and resize through edge lines.
     * You can use "n", "w", "s", "e" in LineDirection array.
     * @default false
     */
    edge?: boolean | Array<LineDirection>;
    /**
     * Whether to recalculate when the size to be calculated is different from the actual size
     * @default true
     */
    checkResizableError?: boolean;
}
/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.AbleRequestParam
 * @description the Resizable's request parameter
 */
export interface AbleRequesters {
    draggable: DraggableRequestParam;
    resizable: ResizableRequestParam;
    scalable: ScalableRequestParam;
    rotatable: RotatableRequestParam;
    [key: string]: AbleRequestParam;
}

/**
 * @typedef
 * @memberof Moveable.Draggable
 * @extends Moveable.AbleRequestParam
 * @description the Draggable's request parameter
 */
export interface DraggableRequestParam extends AbleRequestParam {
    /**
     * x position
     */
    x?: number;
    /**
     * y position
     */
    y?: number;
    /**
     * X number to move
     */
    deltaX?: number;
    /**
     * Y number to move
     */
    deltaY?: number;
    /**
     * whether to use with `snappable`
     */
    useSnap?: boolean;
}

/**
 * @typedef
 * @memberof Moveable.Resizable
 * @extends Moveable.AbleRequestParam
 * @description the Resizable's request parameter
 */
export interface ResizableRequestParam extends AbleRequestParam {
    /**
     * Direction to resize
     * @default [1, 1]
     */
    direction?: number[];
    /**
     * Whether to force keepRatio to resize
     */
    keepRatio?: boolean;
    /**
     * delta number of width
     */
    deltaWidth?: number;
    /**
     * delta number of height
     */
    deltaHeight?: number;
    /**
     * offset number of width
     */
    offsetWidth?: number;
    /**
     * offset number of height
     */
    offsetHeight?: number;
    /**
     *
     */
    horizontal?: boolean;
    /**
     * whether to use with `snappable`
     */
    useSnap?: boolean;
}

export interface ResizableEvents {
    onResizeStart: OnResizeStart;
    onBeforeResize: OnBeforeResize;
    onResize: OnResize;
    onResizeEnd: OnResizeEnd;

    onResizeGroupStart: OnResizeGroupStart;
    onBeforeResizeGroup: OnBeforeResizeGroup;
    onResizeGroup: OnResizeGroup;
    onResizeGroupEnd: OnResizeGroupEnd;
}

export interface ResizableProps extends ResizableOptions, EventInterface<ResizableEvents> {
}


/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.RenderDirections
 */
export interface ScalableOptions extends RenderDirections {
    /**
     * Whether or not target can be scaled.
     * @default false
     */
    scalable?: boolean | ScalableOptions;
    /**
     * throttle of scaleX, scaleY when scale.
     * @default 0
     */
    throttleScale?: number;
    /**
     * When resize or scale, keeps a ratio of the width, height.
     * @default false
     */
    keepRatio?: boolean;
    /**
     * Whether to scale and resize through edge lines.
     * You can use "n", "w", "s", "e" in LineDirection array.
     * @default false
     */
    edge?: boolean | Array<LineDirection>;
}


/**
 * @typedef
 * @memberof Moveable.Scalable
 * @extends Moveable.AbleRequestParam
 * @description the Scalable's request parameter
 */
export interface ScalableRequestParam extends AbleRequestParam {
    /**
     * Direction to scale
     * @default [1, 1]
     */
    direction?: number[];
    /**
     * Whether to force keepRatio to resize
     */
    keepRatio?: boolean;
    /**
     * delta number of width
     */
    deltaWidth?: number;
    /**
     * delta number of height
     */
    deltaHeight?: number;
    /**
     * whether to use with `snappable`
     */
    useSnap?: boolean;
}




/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.AbleRequestParam
 * @description the Rotatable's request parameter
 */
export interface RotatableRequestParam extends AbleRequestParam {
    /**
     * delta number of rotation
     */
    deltaRotate?: number;
    /**
     * absolute number of moveable's rotation
     */
    rotate?: number;
}


export interface ScalableEvents {
    onScaleStart: OnScaleStart;
    onBeforeScale: OnBeforeScale;
    onScale: OnScale;
    onScaleEnd: OnScaleEnd;

    onScaleGroupStart: OnScaleGroupStart;
    onBeforeScaleGroup: OnBeforeScaleGroup;
    onScaleGroup: OnScaleGroup;
    onScaleGroupEnd: OnScaleGroupEnd;
}
export interface ScalableProps extends ScalableOptions, EventInterface<ScalableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface GapGuideline extends SnapGuideline {
    renderPos: number[];
    inner?: boolean;
}
/**
 * @typedef
 * @memberof Moveable
 */
export interface RenderDirections {
    /**
     * Set directions to show the control box.
     * @default false if rotatable, ["n", "nw", "ne", "s", "se", "sw", "e", "w"] otherwise
     */
    renderDirections?: boolean | string[];
    /**
     * Whether to scale and resize through edge lines.
     * You can use "n", "w", "s", "e" in LineDirection array.
     * @default false
     */
    edge?: boolean | Array<LineDirection>;
    /**
     * You can expand the area around the control.
     * Either `rotateAroundControls` or `displayAroundControls` can be used.
     * You can set the area through the `controlPadding` value.
     * @since 0.44.0
     * @story options--options-control-padding
     * @default false
     */
    displayAroundControls?: boolean;
}

export type RotationPosition
    = "top" | "bottom"
    | "left" | "right"
    | "top-right" | "top-left"
    | "bottom-right" | "bottom-left"
    | "left-top" | "left-bottom"
    | "right-top" | "right-bottom"
    | "none";

/**
 * @typedef
 * @memberof Moveable.Rotatable
 * @extends Moveable.RenderDirections
 */
export interface RotatableOptions extends RenderDirections {
    /**
     * Whether or not target can be rotated.
     * @default false
     */
    rotatable?: boolean | RotatableOptions;
    /**
     * You can specify the position of the rotation.
     * @default "top"
     */
    rotationPosition?: RotationPosition | RotationPosition[];
    /**
     * You can rotate around direction controls.
     * Either `rotateAroundControls` or `displayAroundControls` can be used.
     * @default 0
     */
    rotateAroundControls?: boolean;
    /**
     * Sets the control that will cause resize along with rotate. (Only Single Target, Only resizable, Beta)
     * @default null
     */
    resolveAblesWithRotatable?: Record<string, LineDirection[]> | null | undefined;
    /**
     * throttle of angle(degree) when rotate.
     * @default 0
     */
    throttleRotate?: number;

    /**
     * Set additional rotationTargets.
     * @default null
     */
    rotationTarget?: MoveableRefType | ArrayFormat<MoveableRefType> | false;
}
export interface RotatableEvents {
    onRotateStart: OnRotateStart;
    onBeforeRotate: OnBeforeRotate;
    onRotate: OnRotate;
    onRotateEnd: OnRotateEnd;

    onRotateGroupStart: OnRotateGroupStart;
    onBeforeRotateGroup: OnBeforeRotateGroup;
    onRotateGroup: OnRotateGroup;
    onRotateGroupEnd: OnRotateGroupEnd;
}
export interface RotatableProps extends RotatableOptions, EventInterface<RotatableEvents> {
}
/**
 * @typedef
 * @memberof Moveable.Warpable
 * @extends Moveable.RenderDirections
 */
export interface WarpableOptions extends RenderDirections {
    /**
     * Whether or not target can be warped.
     * @default false
     */
    warpable?: boolean;
}

export interface WarpableEvents {
    onWarpStart: OnWarpStart;
    onWarp: OnWarp;
    onWarpEnd: OnWarpEnd;
}
export interface WarpableProps extends WarpableOptions, EventInterface<WarpableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Pinchable
 */
export interface PinchableOptions {
    /**
     * Whether or not target can be pinched with draggable, resizable, scalable, rotatable.
     * @default false
     */
    pinchable?: boolean | Array<"rotatable" | "resizable" | "scalable">;
}
export interface PinchableEvents {
    onPinchStart: OnPinchStart;
    onPinch: OnPinch;
    onPinchEnd: OnPinchEnd;

    onPinchGroupStart: OnPinchGroupStart;
    onPinchGroup: OnPinchGroup;
    onPinchGroupEnd: OnPinchGroupEnd;
}
export interface PinchableProps
    extends PinchableOptions, ResizableProps, ScalableProps,
    RotatableProps, EventInterface<PinchableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Group
 */
export interface GroupableOptions {
    /**
     * Sets the initial rotation of the group.
     * @default 0
     */
    defaultGroupRotate?: number;
    /**
     * Use the defaultGroupRotate even if the children's rotations match.
     * @default false
     */
    useDefaultGroupRotate?: boolean;
    /**
     * Sets the initial transform origin of the group.
     * @default  "50% 50%"
     */
    defaultGroupOrigin?: string;
    /**
     * @default
     */
    targetGroups?: MoveableTargetGroupsType;
    /**
     * @private
     */
    groupable?: boolean;
    /**
     * Whether to hide the line in child moveable for group corresponding to the rect of the target.
     * @default false
     */
    hideChildMoveableDefaultLines?: boolean;
    /**
     * Props that work when group
     * @example
     * ```js
     * {
     *     roundable: true,
     *     groupableProps: {
     *         roundable: false,
     *     },
     * }
     * ```
     */
    groupableProps?: Record<string, any>;
}

/**
 * @typedef
 * @memberof Moveable
 */
export type MoveableTargetGroupsType = Array<HTMLElement | SVGElement | MoveableTargetGroupsType>;


/**
 * @typedef
 * @memberof Moveable.IndividualGroup
 */
export interface IndividualGroupableOptions {
    /**
     * Create targets individually, not as a group.
     * @story individual-group--individual-group-draggable-scalable-rotatable
     */
    individualGroupable?: boolean;
    /**
     * When using individualGroupable you can pass props to child moveable.
     * @story individual-group--individual-group-groupable-props
     * @since 0.44.0
     */
    individualGroupableProps?: (
        element: HTMLElement | SVGElement | null | undefined,
        index: number,
    ) => Record<string, any> | undefined | null | void;
}

export interface IndividualGroupableProps extends IndividualGroupableOptions {
}

export interface GroupableProps extends GroupableOptions {
    targets?: Array<HTMLElement | SVGElement>;
    updateGroup?: boolean;
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface SnappableOptions {
    /**
     * Whether or not target can be snapped to the guideline.
     * @default false
     */
    snappable?: boolean | string[];
    /**
     * A snap container that is the basis for snap, bounds, and innerBounds.
     * @default null
     */
    snapContainer?: MoveableRefType<HTMLElement | SVGElement>;
    /**
     * You can specify the directions to snap to the target.
     * @default true (true is all directions)
     */
    snapDirections?: boolean | SnapDirections;
    /**
     * You can specify the snap directions of elements.
     * @default true (true is all directions)
     */
    elementSnapDirections?: boolean | SnapDirections;
    /**
     * When you drag, make the gap snap in the element guidelines.
     * @default true
     */
    snapGap?: boolean;
    /**
    /**
     * Distance value that can snap to guidelines.
     * Use `snapHorizontalThreshold` and `snapVerticalThreshold`
     * @default 0
     * @depreacted
     */
    snapThreshold?: number;
    /**
     * Distance horizontal between horizontal value that can snap to guidelines.
     * @default 5
     */
    snapHorizontalThreshold?: number;
    /**
     * Distance Horizontal value that can snap to guidelines.
     * @default 5
     */
    snapVerticalThreshold?: number;
    /**
     * Distance value that render snapped guidelines.
     * @default 1
     */
    snapRenderThreshold?: number;
    /**
     * snap distance digits.
     * @default 0
     */
    snapDigit?: number;
    /**
     * Whether to show guideline of snap by grid
     * @default false
     */
    isDisplayGridGuidelines?: boolean;
    /**
     * Snap works if `abs(current rotation - snapRotationDegrees) < snapRotationThreshold`.
     * @default 5
     */
    snapRotationThreshold?: number;
    /**
     * degree angles to snap to rotation
     * @default []
     */
    snapRotationDegrees?: number[];
    /**
     * If width size is greater than 0, you can vertical snap to the grid.
     * @default 0 (0 is not used)
     */
    snapGridWidth?: number;
    /**
     * If height size is greater than 0, you can horizontal snap to the grid.
     * @default 0 (0 is not used)
     */
    snapGridHeight?: number;
    /**
     * In the case of a group, if `snapGridWidth` and `snapGridHeight` are used, all children can be snapped.
     * Custom fixed directions are not yet allowed. Also, it cannot be applied if rotated.
     * @default false
     */
    snapGridAll?: boolean;
    /**
     * Whether to show snap distance.
     * @default true
     */
    isDisplaySnapDigit?: boolean;
    /**
     * Whether to show element inner snap distance
     * @default false
     */
    isDisplayInnerSnapDigit?: boolean;
    /**
     * Add guidelines in the horizontal direction.
     * @default []
     */
    horizontalGuidelines?: Array<PosGuideline | number | string>;
    /**
     * Add guidelines in the vertical direction.
     * @default []
     */
    verticalGuidelines?: Array<PosGuideline | number | string>;
    /**
     * Add guidelines for the element.
     * @default []
     */
    elementGuidelines?: Array<ElementGuidelineValueOption | MoveableRefType<Element>>;
    /**
     * Maximum distance to which element guidelines can be snapped.
     * @default Infinity
     */
    maxSnapElementGuidelineDistance?: number;
    /**
     * Maximum distance to which element gap guidelines can be snapped.
     * @default Infinity
     */
    maxSnapElementGapDistance?: number;
    /**
     * You can set up boundaries.
     * @default null
     */
    bounds?: BoundType | null;
    /**
     * You can set up inner boundaries.
     * @default null
     */
    innerBounds?: InnerBoundType | null;
    /**
     * You can set the text format of the distance shown in the guidelines.
     * @default oneself
     */
    snapDistFormat?: (distance: number, type: "vertical" | "horizontal") => number | string;
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface SnapDirections {
    /**
     * Whether to snap the top of the element
     * @default true
     */
    left?: boolean;
    /**
     * Whether to snap the left of the element
     * @default true
     */
    top?: boolean;
    /**
     * Whether to snap the right of the element
     * @default true
     */
    right?: boolean;
    /**
     * Whether to snap the bottom of the element
     * @default true
     */
    bottom?: boolean;
    /**
     * Whether to snap the center((left + right) / 2) of the element
     * @default false
     */
    center?: boolean;
    /**
     * Whether to snap the middle((top + bottom) / 2) of the element
     * @default false
     */
    middle?: boolean;
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 * @extends Moveable.Snappable.SnapDirections
 */
export interface ElementGuidelineValue extends SnapDirections {
    /**
     * guideline element
     */
    element: Element;
    /**
     * class names to add to guideline
     * @default ""
     * @example
     *
     * ```css
     * .moveable-gap.red {
     *   background: red!important;
     * }
     * ```
     * ```css
     * .moveable-bold.red {
     *   background: red!important;
     * }
     * ```
     * ```css
     * .moveable-dashed.red {
     *   border-top-color: red!important;
     * }
     * ```
     */
    className?: string;
    /**
     * Whether to update the element size at every render
     * @default false
     */
    refresh?: boolean;
}



/**
 * @typedef
 * @memberof Moveable.Snappable
 * @extends Moveable.Snappable.SnapDirections
 */
export interface ElementGuidelineValueOption extends SnapDirections {
    /**
     * guideline element
     */
    element: MoveableRefType<Element>;
    /**
     * class names to add to guideline
     * @default ""
     */
    className?: string;
    /**
     * Whether to update the element size at every render
     * @default false
     */
    refresh?: boolean;
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface PosGuideline {
    /**
     * guideline pos
     */
    pos: number | string;
    /**
     * class names to add to guideline
     * @default ""
     */
    className?: string;
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface NumericPosGuideline extends PosGuideline {
    pos: number;
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 * @extends Moveable.Snappable.SnapDirections
 */
export interface ElementGuidelineValue extends SnapDirections {
    /**
     * guideline element
     */
    element: Element;
    /**
     * class names to add to guideline
     * @default ""
     */
    className?: string;
    /**
     * Whether to update the element size at every render
     * @default false
     */
    refresh?: boolean;
}
export interface SnappableEvents {
    onSnap: OnSnap;
    onBound: OnBound;
}
export interface SnappableProps extends SnappableOptions, EventInterface<SnappableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface OnSnap {
    /**
     * snapped verticalGuidelines, horizontalGuidelines,
     */
    guidelines: SnapGuideline[];
    /**
     * snapped elements (group by element)
     */
    elements: SnapGuideline[];
    /**
     * gaps is snapped guidelines that became gap snap between elements.
     */
    gaps: SnapGuideline[];
}

/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface OnBound {
    bounds: {
        left: boolean;
        top: boolean;
        right: boolean;
        bottom: boolean;
    };
    innerBounds: {
        left: boolean;
        top: boolean;
        right: boolean;
        bottom: boolean;
    };
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface InnerBoundType {
    left: number;
    top: number;
    width: number;
    height: number;
}
/**
 * @typedef
 * @memberof Moveable.Snappable
 */
export interface BoundType {
    /**
     * If position is css, right and bottom are calculated as css right and css bottom of container.
     * @default "client"
     */
    position?: "client" | "css";
    left?: number;
    top?: number;
    right?: number;
    bottom?: number;
}

export interface SnapDirectionPoses {
    left?: number;
    top?: number;
    right?: number;
    bottom?: number;
    center?: number;
    middle?: number;
}

export interface SnapElementRect extends ElementGuidelineValue {
    rect: SnapDirectionPoses;
}
export interface SnappableState {
    staticGuidelines: SnapGuideline[];
    elementRects: SnapElementRect[];
    guidelines: SnapGuideline[];
    snapContainer: MoveableRefType<HTMLElement | SVGElement>;
    snapOffset: { left: number, top: number, bottom: number, right: number }
    snapRenderInfo?: SnapRenderInfo | null;
    snapThresholdInfo?: { multiples: number[]; offset: number[]; } | null;
    enableSnap: boolean;
}
export interface SnapRenderInfo {
    render?: boolean;
    direction?: number[];
    snap?: boolean;
    center?: boolean;
    request?: boolean;
    externalPoses?: number[][];
    externalBounds?: BoundType | false | null;
}

/**
 * @typedef
 * @options
 * @memberof Moveable.Scrollable
 */
export interface ScrollableOptions {
    /**
     * Whether or not target can be scrolled to the scroll container
     * @default false
     */
    scrollable?: boolean;
    /**
     * The container to which scroll is applied
     * @deprecated
     * @default container
     */
    scrollContainer?: MoveableRefType<HTMLElement>;
    /**
     * Expand the range of the scroll check area.
     * @deprecated
     * @default 0
     */
    scrollThreshold?: number;
    /**
     * Time interval that occurs when scrolling occurs when dragging is maintained
     * If set to 0, it does not occur.
     * @deprecated
     * @default 0
     */
    scrollThrottleTime?: number;
    /**
     * Sets a function to get the scroll position.
     * @deprecated
     * @default scrollContainer's scrollTop, scrollLeft
     */
    getScrollPosition?: (e: { scrollContainer: HTMLElement, direction: number[] }) => number[];
    /**
     * Option to scroll with dragging
     * @since 0.43.0
     * @story support-scroll--scrolling-scrollable
     * @example
     * const scrollOptions = {
     *     container: () => viewer.getContainer(),
     *     threshold: 20,
     *     getScrollPosition: () => {
     *         return [
     *             viewer.getScrollLeft({ absolute: true }),
     *             viewer.getScrollTop({ absolute: true }),
     *         ];
     *     },
     * };
     */
    scrollOptions?: Partial<DragScrollOptions> | null;
}
export interface ScrollableEvents {
    onScroll: OnScroll;
    onScrollGroup: OnScrollGroup;
}
export interface ScrollableProps extends ScrollableOptions, EventInterface<ScrollableEvents> {
}

/**
 * @typedef
 * @memberof Moveable
 */
export interface DragAreaOptions {
    /**
     * Instead of firing an event on the target, we add it to the moveable control element. You can use click and clickGroup events.
     * @default if group, true, else fals
     */
    dragArea?: boolean;
    /**
     * Set `pointerEvents: none;` css to pass events in dragArea.
     * @default false
     */
    passDragArea?: boolean;
}
export interface DragAreaProps extends DragAreaOptions {
}
/**
 * @typedef
 * @memberof Moveable.Clickable
 */
export interface ClickableEvents {
    onClick: OnClick;
    onClickGroup: OnClickGroup;
}

export interface ArrayFormat<T = any> {
    length: number;
    [key: number]: T;
}
/**
 * @typedef
 * @memberof Moveable.Clickable
 */
export interface ClickableOptions {
    /**
     * Whether to trigger the moveable's click event.
     * @default true
     */
    clickable?: boolean;
}
/**
 * @memberof Moveable.Clickable
 * @extends Moveable.Clickable.ClickableEvents
 * @extends Moveable.Clickable.ClickableOptions
 * @typedef
 */
export interface ClickableProps extends EventInterface<ClickableEvents>, ClickableOptions {
}
export interface BeforeRenderableEvents {
    onBeforeRenderStart: OnBeforeRenderStart;
    onBeforeRender: OnBeforeRender;
    onBeforeRenderEnd: OnBeforeRenderEnd;
    onBeforeRenderGroupStart: OnBeforeRenderGroupStart;
    onBeforeRenderGroup: OnBeforeRenderGroup;
    onBeforeRenderGroupEnd: OnBeforeRenderGroupEnd;
}
export interface BeforeRenderableProps extends EventInterface<BeforeRenderableEvents> {
}
export interface RenderableEvents {
    onRenderStart: OnRenderStart;
    onRender: OnRender;
    onRenderEnd: OnRenderEnd;
    onRenderGroupStart: OnRenderGroupStart;
    onRenderGroup: OnRenderGroup;
    onRenderGroupEnd: OnRenderGroupEnd;
}
export interface RenderableProps extends EventInterface<RenderableEvents> {
}

/**
 * @typedef
 * @memberof Moveable.Clippable
 */
export interface ClippableOptions {
    /**
     * Whether to clip the target.
     * @default false
     */
    clippable?: boolean | ClippableOptions;
    /**
     * Whether to keep the ratio of size if your clipPath is 'inset', 'rect', 'ellipse' type
     * @default false
     */
    keepRatio?: boolean;
    /**
     * You can force the custom clipPath. (defaultClipPath < style < customClipPath < dragging clipPath)
     */
    customClipPath?: string;
    /**
     * If clippath is not set, the default value can be set. (defaultClipPath < style < customClipPath < dragging clipPath)
     */
    defaultClipPath?: string;
    /**
     * % Can be used instead of the absolute px (`rect` not possible)
     * @default false
     */
    clipRelative?: boolean;
    /**
     * When dragging the target, the clip also moves.
     * @default true
     */
    dragWithClip?: boolean;
    /**
     * You can drag the clip by setting clipArea.
     * @default false
     */
    clipArea?: boolean;
    /**
     * Whether the clip is bound to the target.
     * @default false
     */
    clipTargetBounds?: boolean;
    /**
     * Add clip guidelines in the vertical direction.
     * @default []
     */
    clipVerticalGuidelines?: Array<string | number>;
    /**
     * Add clip guidelines in the horizontal direction.
     * @default []
     */
    clipHorizontalGuidelines?: Array<string | number>;
    /**
     * Distance value that can snap to clip guidelines.
     * @default 5
     */
    clipSnapThreshold?: number;
}
export interface ClippableEvents {
    onClipStart: OnClipStart;
    onClip: OnClip;
    onClipEnd: OnClipEnd;
}
export interface ClippableProps extends ClippableOptions, EventInterface<ClippableEvents> {
}
export interface ClippableState {
    clipPathState?: string;
    snapBoundInfos?: { vertical: Required<SnapBoundInfo>, horizontal: Required<SnapBoundInfo> } | null;
}

/**
 * @typedef
 * @memberof Moveable.Clippable
 * @extends Moveable.OnEvent
 * @property - The clip type.
 * @property - The control positions
 * @property - CSS style of changed clip
 */
export interface OnClipStart extends OnEvent {
    clipType: "polygon" | "circle" | "ellipse" | "inset" | "rect";
    poses: number[][];
    clipStyle: string;
}
/**
 * @typedef
 * @memberof Moveable.Clippable
 * @extends Moveable.OnEvent
 * @extends Moveable.CSSObject
 */
export interface OnClip extends OnEvent, CSSObject {
    /**
     * The clip type.
     */
    clipType: "polygon" | "circle" | "ellipse" | "inset" | "rect";
    /**
     * The clip event type.
     */
    clipEventType: "added" | "changed" | "removed";
    /**
     * The control positions
     */
    poses: number[][];
    /**
     * x position of the distance the control has moved
     */
    distX: number;
    /**
     * y position of the distance the control has moved
     */
    distY: number;
    /**
     * CSS style of changed clip
     */
    clipStyle: string;
    /**
     * Splited CSS styles of changed clip
     */
    clipStyles: string[];

}
/**
 * @typedef
 * @memberof Moveable.Clippable
 * @extends Moveable.OnEndEvent
 */
export interface OnClipEnd extends OnEndEvent { }

export interface OnCustomDrag extends GestoTypes.Position {
    type: string;
    inputEvent: any;
    isDrag: boolean;
    isFirstDrag: boolean;
    datas: IObject<any>;
    originalDatas: IObject<any>;
    parentEvent: boolean;
    parentGesto: CustomGesto;
}

/**
 * @typedef
 * @memberof Moveable
 */
export type PersistRectData = Omit<Partial<RectInfo>, "children"> & {
    children?: Array<Partial<RectInfo>>;
};


/**
 * @typedef
 * @memberof Moveable
 */
export interface RectInfo {
    /**
     * The coordinates of the vertex 1
     */
    pos1: number[];
    /**
     * The coordinates of the vertex 2
     */
    pos2: number[];
    /**
     * The coordinates of the vertex 3
     */
    pos3: number[];
    /**
     * The coordinates of the vertex 4
     */
    pos4: number[];
    /**
     * left position of the target relative to the container
     */
    left: number;
    /**
     * top position of the target relative to the container
     */
    top: number;
    /**
     * The width of moveable element
     */
    width: number;
    /**
     * The height of moveable element
     */
    height: number;
    /**
     * The offset width of the target
     */
    offsetWidth: number;
    /**
     * The offset height of the target
     */
    offsetHeight: number;
    /**
     * The absolute transform origin
     */
    origin: number[];
    /**
     * The absolute transform origin before transformation
     */
    beforeOrigin: number[];
    /**
     * The target transform origin
     */
    transformOrigin: number[];
    /**
     * you can get the absolute rotation value
     */
    rotation: number;
    /**
     * If you use a group, you can get child moveables' rect info
     */
    children?: RectInfo[];
}

/**
 * @typedef
 * @memberof Moveable
 */
export interface GroupRect {
    pos1: number[];
    pos2: number[];
    pos3: number[];
    pos4: number[];
    minX: number;
    minY: number;
    maxX: number;
    maxY: number;
    width: number;
    height: number;
    rotation: number;
}

/**
 * @typedef
 * @memberof Moveable
 * @property - top position
 * @property - left position
 * @property - target's width
 * @property - target's height
 */
export interface HitRect {
    top: number;
    left: number;
    width?: number;
    height?: number;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.MoveableInterface
 */
export interface MoveableManagerInterface<T = {}, U = {}> extends MoveableInterface {
    moveables?: MoveableManagerInterface[];
    props: MoveableManagerProps<T>;
    state: MoveableManagerState<U>;
    renderState: Record<string, any>;
    rotation: number;
    scale: number[];
    controlGesto: Gesto;
    targetGesto: Gesto;
    enabledAbles: Able[];
    controlAbles: Able[];
    targetAbles: Able[];
    areaElement: HTMLElement;
    controlBox: HTMLElement,
    isUnmounted: boolean;
    useCSS(tag: string, css: string): any;
    getContainer(): HTMLElement | SVGElement;
    getRotation(): number;
    getState(): MoveableManagerState<U>;
    triggerEvent(name: string, params: IObject<any>, isManager?: boolean): any;
}

/**
 * @typedef
 * @memberof Moveable
 * @extends Moveable.MoveableManagerInterface
 */
export interface MoveableGroupInterface<T = {}, U = {}> extends MoveableManagerInterface<T, U> {
    props: MoveableManagerProps<T> & { targets: Array<HTMLElement | SVGElement> };
    moveables: MoveableManagerInterface[];
    transformOrigin: string;
    renderGroupRects: GroupRect[];
    getRequestChildStyles(): string[];
}

/**
 * @typedef
 * @memberof Moveable
 */
export interface MoveableInterface {
    getManager(): MoveableManagerInterface<any, any>;
    getRect(): RectInfo;
    getAble<T extends Able>(ableName: string): T | undefined;
    isMoveableElement(target: Element): boolean;
    /**
     * If the location or size of the target is changed, call the `.updateRect()` method.
     * Use the `useResizeObserver` and `useMutationObserver` props to update automatically.
     */
    updateRect(type?: "Start" | "" | "End", isTarget?: boolean, isSetState?: boolean): void;
    /**
     * @deprecated
     * Use `.updateRect()` method
     */
    updateTarget(): void;
    /**
     * Request able through a method rather than an event.
     * At the moment of execution, requestStart is executed,
     * and then request and requestEnd can be executed through Requester.
     * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Draggable.html#request Draggable Requester}
     * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Resizable.html#request Resizable Requester}
     * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Scalable.html#request Scalable Requester}
     * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.Rotatable.html#request Rotatable Requester}
     * @see {@link https://daybrush.com/moveable/release/latest/doc/Moveable.OriginDraggable.html#request OriginDraggable Requester}
     * @param - ableName
     * @param - request to be able params.
     * @param - If isInstant is true, request and requestEnd are executed immediately.
     * @return - Able Requester. If there is no request in able, nothing will work.
     * @example
     * import Moveable from "moveable";
     *
     * const moveable = new Moveable(document.body);
     *
     * // Instantly Request (requestStart - request - requestEnd)
     * moveable.request("draggable", { deltaX: 10, deltaY: 10 }, true);
     *
     * // Start move
     * const requester = moveable.request("draggable");
     * requester.request({ deltaX: 10, deltaY: 10 });
     * requester.request({ deltaX: 10, deltaY: 10 });
     * requester.request({ deltaX: 10, deltaY: 10 });
     * requester.requestEnd();
     */
    request<
        RequestParam extends AbleRequesters[Name],
        Name extends string = string,
    >(ableName: Name, params?: RequestParam, isInstant?: boolean): Requester<RequestParam>;
    /**
     * moveable is the top level that manages targets
     * `Single`: MoveableManager instance
     * `Group`: MoveableGroup instance
     * `IndividualGroup`: MoveableIndividaulGroup instance
     * Returns leaf target MoveableManagers.
     */
    getMoveables(): MoveableManagerInterface[];
    /**
     * Returns the element of the control box.
     */
    getControlBoxElement(): HTMLElement;
    /**
     * Target element to be dragged in moveable
     */
    getDragElement(): HTMLElement | SVGElement | null | undefined;
    destroy(): void;
    dragStart(e: MouseEvent | TouchEvent, target?: EventTarget | null): void;
    isInside(clientX: number, clientY: number): boolean;
    isDragging(ableName?: string): boolean;
    hitTest(el: Element | HitRect): number;
    setState(state: any, callback?: () => any): any;
    waitToChangeTarget(): Promise<void>;
    forceUpdate(callback?: () => any): any;
    updateSelectors(): void;
    getTargets(): Array<HTMLElement | SVGElement>;
    stopDrag(type?: "target" | "control"): void;
}

export interface ControlPose {
    virtual?: boolean;
    vertical: number;
    horizontal: number;
    pos: number[];
    sub?: boolean;
    raw?: number;
    direction?: "n" | "e" | "s" | "w" | "nw" | "ne" | "sw" | "se" | "nesw";
}


export type AnyProps<T extends IObject<any>> = Required<{ [key in keyof T]: any }>;
export type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

// export type MoveableEventsProps = Parameters<Required<MoveableProps>[keyof typeof MOVEABLE_EVENTS_PROPS_MAP]>[0];
export type MoveableEvents = {
    [key in typeof MOVEABLE_EVENTS[number]]
    : Parameters<Required<MoveableProps>[`on${Capitalize<key>}`]>[0];
};

export type Writable<T> = {
    -readonly [key in keyof T]: T[key];
};

export type MoveableProperties = {
    -readonly [key in typeof MOVEABLE_PROPS[number]]?: MoveableProps[key];
};

export interface SnappableRenderType {
    type: "snap" | "bounds";
    pos: number;
}

export type ExcludeParams<T extends IObject<any>>
    = ExcludeKeys<T, keyof OnEvent>;
export type ExcludeEndParams<T extends IObject<any>>
    = ExcludeKeys<ExcludeParams<T>, "lastEvent" | "isDrag" | "isDouble">;
export type DefaultProps<Name extends string, AbleObject extends Partial<Able<any, any>>>
    = AbleObject extends { props: {} } ? AbleObject["props"] : { readonly [key in Name]: BooleanConstructor; };