UNPKG

react-moveable

Version:

A React Component that create Moveable, Draggable, Resizable, Scalable, Rotatable, Warpable, Pinchable, Groupable.

857 lines (796 loc) 23.5 kB
import { IObject } from "@daybrush/utils"; import Dragger, * as DraggerTypes from "@daybrush/drag"; import CustomDragger from "./CustomDragger"; import { Position } from "@daybrush/drag"; export interface MoveableClientRect { left: number; top: number; right: number; bottom: number; width: number; height: number; } export type MoveableManagerProps<T = {}> = { target?: SVGElement | HTMLElement | null; container?: SVGElement | HTMLElement | null; dragArea?: boolean; parentMoveable?: any; parentPosition?: { left: number, top: number } | null; origin?: boolean; transformOrigin?: Array<string | number> | ""; edge?: boolean; keepRatio?: boolean; pinchThreshold?: number; ables?: Array<Able<T>>; className?: string; } & T; export type MoveableManagerState<T = {}> = { container: SVGElement | HTMLElement | null | undefined; target: SVGElement | HTMLElement | null | undefined; left: number; top: number; right: number; bottom: number; width: number; height: number; beforeMatrix: number[]; matrix: number[]; targetTransform: string; targetMatrix: number[]; offsetMatrix: number[]; is3d: boolean; transformOrigin: number[]; beforeOrigin: number[]; origin: number[]; beforeDirection: 1 | -1; direction: 1 | -1; pos1: number[]; pos2: number[]; pos3: number[]; pos4: number[]; dragger: Dragger | CustomDragger | null; clientRect: MoveableClientRect; containerRect: MoveableClientRect; } & T; export interface Renderer { createElement(type: any, props?: any, ...children: any[]): any; } export interface Guideline { type: "horizontal" | "vertical"; element?: Element | null; center?: boolean; pos: number[]; size: number; } export interface BoundInfo { isBound: boolean; offset: number; pos: number; } export interface SnapInfo { isSnap: boolean; dist: number; offset: number; guidelines: Guideline[]; snapPoses: number[]; } export interface MoveableProps extends MoveableManagerProps<any>, DraggableProps, RotatableProps, ResizableProps, ScalableProps, WarpableProps, PinchableProps, GroupableProps, SnappableProps, ScrollableProps, RenderProps { target?: SVGElement | HTMLElement | Array<SVGElement | HTMLElement> | null; container?: SVGElement | HTMLElement | null; origin?: boolean; keepRatio?: boolean; edge?: boolean; pinchThreshold?: number; ables?: Able[]; } export type MoveableState = MoveableManagerState; export interface Able<T = any> { name: string & keyof MoveableManagerProps<T>; ableGroup?: string; updateRect?: boolean; canPinch?: boolean; unset?: (moveable: MoveableManagerProps<any>) => any; render?: (moveable: MoveableManagerProps<any>, renderer: Renderer) => any; dragStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragStart) => any; drag?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDrag) => any; dragEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragEnd) => any; pinchStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinchStart) => any; pinch?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinch) => any; pinchEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinchEnd) => any; dragControlCondition?: (target: SVGElement | HTMLElement) => boolean; dragControlStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragStart) => any; dragControl?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDrag) => any; dragControlEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragEnd) => any; dragGroupCondition?: (target: SVGElement | HTMLElement) => boolean; dragGroupStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragStart) => any; dragGroup?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDrag) => any; dragGroupEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragEnd) => any; pinchGroupStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinchStart) => any; pinchGroup?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinch) => any; pinchGroupEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnPinchEnd) => any; dragGroupControlCondition?: (target: SVGElement | HTMLElement) => boolean; dragGroupControlStart?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragStart) => any; dragGroupControl?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragStart) => any; dragGroupControlEnd?: (moveable: MoveableManagerProps<any>, e: DraggerTypes.OnDragEnd) => any; } /** * @typedef * @memberof Moveable * @property - The Moveable instance * @property - The Moveable target * @property - The horizontal coordinate within the application's client area at which the event occurred. * @property - The vertical coordinate within the application's client area at which the event occurred. * @property - Objects that can send information to the following events. * @property - The mouse or touch input event that is invoking the moveable event */ export interface OnEvent { currentTarget: MoveableInterface; target: HTMLElement | SVGElement; clientX: number; clientY: number; datas: IObject<any>; inputEvent: any; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent */ export interface OnPinchStart extends OnEvent { } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent */ export interface OnPinch extends OnEvent { } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent */ export interface OnPinchEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - You can set the start translate value. */ export interface OnDragStart extends OnEvent { set: (translate: number[]) => void; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @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 right * @property - Whether or not it is being pinched. */ export interface OnDrag extends OnEvent { beforeDelta: number[]; beforeDist: number[]; beforeTranslate: number[]; delta: number[]; dist: number[]; translate: number[]; transform: string; left: number; top: number; bottom: number; right: number; isPinch: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Whether drag called */ export interface OnDragEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The direction of scale. * @property - scale causes a `dragStart` event. * @property - You can set the start scale value. */ export interface OnScaleStart extends OnEvent { direction: number[]; dragStart: OnDragStart | false; set: (scale: number[]) => void; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The direction of scale. * @property - a target's scale * @property - The distance of scale * @property - The delta of scale * @property - a target's transform * @property - scale causes a `drag` event. */ export interface OnScale extends OnEvent { direction: number[]; scale: number[]; dist: number[]; delta: number[]; transform: string; isPinch: boolean; drag: OnDrag; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Whether scale called */ export interface OnScaleEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The direction of resize. * @property - resize causes a `dragStart` event. * @property - You can set the css width, height value. */ export interface OnResizeStart extends OnEvent { direction: number[]; dragStart: OnDragStart | false; set: (sizes: number[]) => any; setOrigin: (origin: Array<string | number>) => any; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The direction of resize. * @property - a target's cssWidth * @property - a target's cssHeight * @property - a target's offsetWidth * @property - a target's offsetHeight * @property - The distance of [width, height] * @property - The delta of [width, height] * @property - resize causes a `drag` event. */ export interface OnResize extends OnEvent { direction: number[]; width: number; height: number; offsetWidth: number; offsetHeight: number; dist: number[]; delta: number[]; isPinch: boolean; drag: OnDrag; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Whether resize called */ export interface OnResizeEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - You can set the start rotate value. */ export interface OnRotateStart extends OnEvent { set: (rotate: number) => void; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The distance of rotation rad before transform is applied * @property - The delta of rotation rad before transform is applied * @property - The now rotation rad before transform is applied * @property - The distance of rotation rad * @property - The delta of rotation rad * @property - The now rotation rad * @property - a target's transform */ export interface OnRotate extends OnEvent { beforeDist: number; beforeDelta: number; beforeRotate: number; dist: number; delta: number; rotate: number; transform: string; isPinch: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Whether rotate called */ export interface OnRotateEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - You can set the start matrix value. */ export interface OnWarpStart extends OnEvent { set: (matrix: number[]) => any; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - a target's transform * @property - The delta of warp matrix * @property - The dist of warp matrix * @property - The caculated warp matrix * @property - Multiply function that can multiply previous matrix by warp matrix */ export interface OnWarp extends OnEvent { transform: string; delta: number[]; dist: number[]; matrix: number[]; multiply: (matrix1: number[], matrix2: number[], n?: number) => number[]; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Whether rotate called */ export interface OnWarpEnd extends OnEvent { isDrag: boolean; } /** * @typedef * @memberof Moveable * @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 * @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 * @extends Moveable.OnDragEnd * @property - The drag finished targets * @property - Whether `dragGroup` called */ export interface OnDragGroupEnd extends OnDragEnd { targets: Array<HTMLElement | SVGElement>; isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnRotateStart * @property - targets to rotate * @property - Each `rotateStart` & `dragStart` event on the targets */ export interface OnRotateGroupStart extends OnRotateStart { targets: Array<HTMLElement | SVGElement>; events: Array<OnRotateStart & { dragStart: OnDragStart | false }>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnRotate * @property - The rotating targets * @property - Each `rotate` & `drag` event on the targets */ export interface OnRotateGroup extends OnRotate { targets: Array<HTMLElement | SVGElement>; events: Array<OnRotate & { drag: OnDrag }>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnRotateEnd * @property - The rotate finished targets * @property - Whether `rotateGroup` called */ export interface OnRotateGroupEnd extends OnRotateEnd { targets: Array<HTMLElement | SVGElement>; isDrag: boolean; } /** * @typedef * @memberof Moveable * @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 * @extends Moveable.OnResize * @property - The resizing targets * @property - Each `resize` & `drag `event on the targets */ export interface OnResizeGroup extends OnResize { targets: Array<HTMLElement | SVGElement>; events: Array<OnResize & { drag: OnDrag }>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnResizeEnd * @property - The resize finished targets * @property - Whether `resizeGroup` called */ export interface OnResizeGroupEnd extends OnResizeEnd { targets: Array<HTMLElement | SVGElement>; isDrag: boolean; } /** * @typedef * @memberof Moveable * @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 * @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: Array<OnScale & { drag: OnDrag }>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnScaleEnd * @property - The scale finished targets * @property - Whether `scaleGroup` called */ export interface OnScaleGroupEnd extends OnScaleEnd { targets: Array<HTMLElement | SVGElement>; isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnPinchStart * @property - targets to pinch */ export interface OnPinchGroupStart extends OnPinchStart { targets: Array<HTMLElement | SVGElement>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnPinch * @property - targets to pinch */ export interface OnPinchGroup extends OnPinch { targets: Array<HTMLElement | SVGElement>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnPinchEnd * @property - The pinch finished targets */ export interface OnPinchGroupEnd extends OnPinchEnd { targets: Array<HTMLElement | SVGElement>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - Clicked target. * @property - Whether the clicked target is moveable target. * @property - Whether the clicked target is a child of moveable target. */ export interface OnClick extends OnEvent { inputTarget: HTMLElement | SVGElement; isTarget: boolean; containsTarget: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - targets set to group. * @property - Clicked target. * @property - Whether the clicked target is on the targets set in the group. * @property - Whether the clicked target is a child of the targets set in the group. * @property - The corresponding index among the targets set as a group. */ export interface OnClickGroup extends OnEvent { targets: Array<HTMLElement | SVGElement>; inputTarget: HTMLElement | SVGElement; isTarget: boolean; containsTarget: boolean; targetIndex: number; } // `renderStart` event occurs at the first start of all events. /** * @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 * @property - Whether or not it is being pinched. */ export interface OnRender extends OnEvent { isPinch: boolean; } // `renderEnd` event occurs at 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 OnRenderEnd extends OnEvent { isPinch: boolean; isDrag: boolean; } /** * @typedef * @memberof Moveable * @extends Moveable.OnEvent * @property - The container corresponding to scrolling area * @property - The direction of scrolling [left, top] */ export interface OnScroll extends OnEvent { scrollContainer: HTMLElement; direction: number[]; } /** * @typedef * @memberof Moveable * @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. */ export interface OnRenderGroup extends OnRender { targets: Array<HTMLElement | SVGElement>; } /** * @typedef * @memberof Moveable * @extends Moveable.OnRenderEnd * @property - targets set to group. */ export interface OnRenderGroupEnd extends OnRenderEnd { targets: Array<HTMLElement | SVGElement>; } export interface OriginProps { origin: boolean; } export interface DraggableProps { draggable?: boolean; throttleDrag?: number; onDragStart?: (e: OnDragStart) => any; onDrag?: (e: OnDrag) => any; onDragEnd?: (e: OnDragEnd) => any; onDragGroupStart?: (e: OnDragGroupStart) => any; onDragGroup?: (e: OnDragGroup) => any; onDragGroupEnd?: (e: OnDragGroupEnd) => any; } export interface ResizableProps { resizable?: boolean; throttleResize?: number; renderDirections?: string[]; onResizeStart?: (e: OnResizeStart) => any; onResize?: (e: OnResize) => any; onResizeEnd?: (e: OnResizeEnd) => any; onResizeGroupStart?: (e: OnResizeGroupStart) => any; onResizeGroup?: (e: OnResizeGroup) => any; onResizeGroupEnd?: (e: OnResizeGroupEnd) => any; } export interface ScalableProps { scalable?: boolean; throttleScale?: number; renderDirections?: string[]; onScaleStart?: (e: OnScaleStart) => any; onScale?: (e: OnScale) => any; onScaleEnd?: (e: OnScaleEnd) => any; onScaleGroupStart?: (e: OnScaleGroupStart) => any; onScaleGroup?: (e: OnScaleGroup) => any; onScaleGroupEnd?: (e: OnScaleGroupEnd) => any; } export interface RotatableProps { rotatable?: boolean; rotationPosition?: "top" | "bottom" | "left" | "right"; throttleRotate?: number; onRotateStart?: (e: OnRotateStart) => any; onRotate?: (e: OnRotate) => any; onRotateEnd?: (e: OnRotateEnd) => any; onRotateGroupStart?: (e: OnRotateGroupStart) => any; onRotateGroup?: (e: OnRotateGroup) => any; onRotateGroupEnd?: (e: OnRotateGroupEnd) => any; } export interface WarpableProps { warpable?: boolean; renderDirections?: string[]; onWarpStart?: (e: OnWarpStart) => any; onWarp?: (e: OnWarp) => any; onWarpEnd?: (e: OnWarpEnd) => any; } export interface PinchableProps extends ResizableProps, ScalableProps, RotatableProps { pinchable?: boolean | Array<"rotatable" | "resizable" | "scalable">; onPinchStart?: (e: OnPinchStart) => any; onPinch?: (e: OnPinch) => any; onPinchEnd?: (e: OnPinchEnd) => any; onPinchGroupStart?: (e: OnPinchGroupStart) => any; onPinchGroup?: (e: OnPinchGroup) => any; onPinchGroupEnd?: (e: OnPinchGroupEnd) => any; } export interface GroupableProps extends PinchableProps, DraggableProps, RotatableProps, ResizableProps, ScalableProps, SnappableProps, RenderProps, DragAreaProps, ScrollableProps { groupable?: boolean; targets?: Array<HTMLElement | SVGElement>; updateGroup?: boolean; } export interface SnappableProps { snappable?: boolean | string[]; snapCenter?: boolean; snapThreshold?: number; horizontalGuidelines?: number[]; verticalGuidelines?: number[]; elementGuidelines?: Element[]; bounds?: { left?: number, top?: number, right?: number, bottom?: number }; } export interface SnappableState { guidelines: any[]; snapDirection: number[] | true | null; enableSnap: boolean; } export interface ScrollableProps { scrollable?: boolean; scrollContainer?: HTMLElement; scrollThreshold?: number; getScrollPosition?: (e: { scrollContainer: HTMLElement, direction: number[] }) => number[]; onScroll?: (e: OnScroll) => any; onScrollGroup?: (e: OnScrollGroup) => any; } export interface DragAreaProps { dragArea?: boolean; onClick?: (e: OnClick) => any; onClickGroup?: (e: OnClickGroup) => any; } export interface RenderProps { onRenderStart?: (e: OnRenderStart) => any; onRender?: (e: OnRender) => any; onRenderEnd?: (e: OnRenderEnd) => any; onRenderGroupStart?: (e: OnRenderGroupStart) => any; onRenderGroup?: (e: OnRenderGroup) => any; onRenderGroupEnd?: (e: OnRenderGroupEnd) => any; } export interface OnCustomDrag extends Position { inputEvent: any; isDrag: boolean; datas: IObject<any>; parentEvent: boolean; parentDragger: CustomDragger; } /** * @typedef * @memberof Moveable * @property - The coordinates of the vertex 1 * @property - The coordinates of the vertex 1 * @property - The coordinates of the vertex 1 * @property - The coordinates of the vertex 1 * @property - left position of the target relative to the container * @property - top position of the target relative to the container * @property - the offset width of the target * @property - the offset height of the target */ export interface RectInfo { pos1: number[]; pos2: number[]; pos3: number[]; pos4: number[]; left: number; top: number; width: number; height: number; } export interface MoveableInterface { getRect(): RectInfo; isMoveableElement(target: HTMLElement | SVGElement): boolean; updateRect(isNotSetState?: boolean): void; updateTarget(): void; destroy(): void; dragStart(e: MouseEvent | TouchEvent): void; isInside(clientX: number, clientY: number): boolean; setState(state: any, callback?: () => any): any; }