/**
 * External dependencies
 */
import Moveable from 'react-moveable';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { useRef, useEffect } from '@wordpress/element';

/**
 * Internal dependencies
 */
import { useStory } from '../../app';

const CORNER_HANDLES = [ 'nw', 'ne', 'sw', 'se' ];
const ALL_HANDLES = [ 'n', 's', 'e', 'w', 'nw', 'ne', 'sw', 'se' ];

function Movable( {
	rotationAngle,
	x,
	y,
	type,
	targetEl,
	pushEvent,
	setPushEvent,
} ) {
	const moveable = useRef();

	const {
		actions: { setPropertiesOnSelectedElements },
	} = useStory();

	useEffect( () => {
		if ( moveable.current ) {
			// If we have persistent event then let's use that.
			if ( pushEvent ) {
				moveable.current.moveable.dragStart( pushEvent );
				// Remove the event right after using, not to influence other elements.
				setPushEvent( null );
			}
			moveable.current.updateRect();
		}
		// Disable reason: we should not run this when pushEvent changes!
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [ targetEl, moveable ] );

	const frame = {
		translate: [ 0, 0 ],
		rotate: rotationAngle,
	};

	const setStyle = ( target ) => {
		target.style.transform = `translate(${ frame.translate[ 0 ] }px, ${ frame.translate[ 1 ] }px) rotate(${ frame.rotate }deg)`;
	};

	/**
	 * Resets Movable once the action is done, sets the initial values.
	 *
	 * @param {Object} target Target element.
	 */
	const resetMoveable = ( target ) => {
		frame.translate = [ 0, 0 ];
		setStyle( target );
		if ( moveable.current ) {
			moveable.current.updateRect();
		}
	};

	return (
		<Moveable
			ref={ moveable }
			target={ targetEl }
			draggable={ true }
			resizable={ true }
			rotatable={ true }
			onDrag={ ( { target, beforeTranslate } ) => {
				frame.translate = beforeTranslate;
				setStyle( target );
			} }
			throttleDrag={ 0 }
			onDragStart={ ( { set } ) => {
				set( frame.translate );
			} }
			onDragEnd={ ( { target } ) => {
				// When dragging finishes, set the new properties based on the original + what moved meanwhile.
				const newProps = { x: x + frame.translate[ 0 ], y: y + frame.translate[ 1 ] };
				setPropertiesOnSelectedElements( newProps );
				resetMoveable( target );
			} }
			onResizeStart={ ( { setOrigin, dragStart } ) => {
				setOrigin( [ '%', '%' ] );
				if ( dragStart ) {
					dragStart.set( frame.translate );
				}
			} }
			onResize={ ( { target, width, height, drag } ) => {
				target.style.width = `${ width }px`;
				target.style.height = `${ height }px`;
				frame.translate = drag.beforeTranslate;
				setStyle( target );
			} }
			onResizeEnd={ ( { target } ) => {
				setPropertiesOnSelectedElements( {
					width: parseInt( target.style.width ),
					height: parseInt( target.style.height ),
					x: x + frame.translate[ 0 ],
					y: y + frame.translate[ 1 ],
				} );
				resetMoveable( target );
			} }
			onRotateStart={ ( { set } ) => {
				set( frame.rotate );
			} }
			onRotate={ ( { target, beforeRotate } ) => {
				frame.rotate = beforeRotate;
				setStyle( target );
			} }
			onRotateEnd={ () => {
				setPropertiesOnSelectedElements( { rotationAngle: frame.rotate } );
			} }
			origin={ false }
			pinchable={ true }
			keepRatio={ 'image' === type }
			renderDirections={ 'image' === type ? CORNER_HANDLES : ALL_HANDLES }
		/>
	);
}

Movable.propTypes = {
	rotationAngle: PropTypes.number.isRequired,
	targetEl: PropTypes.object.isRequired,
	pushEvent: PropTypes.object,
	setPushEvent: PropTypes.func,
	type: PropTypes.string.isRequired,
	x: PropTypes.number.isRequired,
	y: PropTypes.number.isRequired,
};

export default Movable;

@@ -463,23 +463,8 @@
 nt,%0A
-%09setPushEvent,%0A
 %7D ) 
@@ -674,184 +674,143 @@
 that
-.%0A%09%09%09if ( pushEvent ) %7B%0A%09%09%09%09moveable.current.moveable.dragStart( pushEvent );%0A%09%09%09%09// Remove the event right after using, not to influence other elements.%0A%09%09%09%09setPushEvent( null
+, ensuring the targets match.%0A%09%09%09if ( pushEvent && pushEvent.target === targetEl ) %7B%0A%09%09%09%09moveable.current.moveable.dragStart( pushEvent
  );%0A
@@ -922,9 +922,9 @@
 nges
-!
+.
 %0A%09%09/
@@ -3188,16 +3188,99 @@
 = type %7D
+ // @%E2%80%A0odo Even image doesn't always keep ratio, consider moving to element's model.
 %0A%09%09%09rend
@@ -3497,39 +3497,8 @@
 ct,%0A
-%09setPushEvent: PropTypes.func,%0A
 %09typ

Add todo notes.