@@ -6,6 +6,7 @@ import cloneElement from './cloneElement';
66import type { Element as ReactElement , Node as ReactNode } from 'react' ;
77
88type Axis = 'both' | 'x' | 'y' | 'none' ;
9+ type ResizeHandle = 's' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne' ;
910type State = {
1011 resizing : boolean ,
1112 width : number , height : number ,
@@ -19,14 +20,15 @@ type DragCallbackData = {
1920} ;
2021export type ResizeCallbackData = {
2122 node : HTMLElement ,
22- size : { width : number , height : number }
23+ size : { width : number , height : number } ,
24+ handle : ResizeHandle
2325} ;
2426export type Props = {
2527 children : ReactElement < any > ,
2628 className ?: ?string ,
2729 width : number ,
2830 height : number ,
29- handle : ReactElement < any > ,
31+ handle : ReactElement < any > | ( resizeHandle : ResizeHandle ) => ReactElement < any > ,
3032 handleSize : [ number , number ] ,
3133 lockAspectRatio : boolean ,
3234 axis : Axis ,
@@ -35,7 +37,8 @@ export type Props = {
3537 onResizeStop ?: ?( e : SyntheticEvent < > , data : ResizeCallbackData ) => any ,
3638 onResizeStart ?: ?( e : SyntheticEvent < > , data : ResizeCallbackData ) => any ,
3739 onResize ?: ?( e : SyntheticEvent < > , data : ResizeCallbackData ) => any ,
38- draggableOpts ?: ?Object
40+ draggableOpts ?: ?Object ,
41+ resizeHandles ?: ?ResizeHandle [ ]
3942} ;
4043
4144export default class Resizable extends React . Component < Props , State > {
@@ -61,6 +64,18 @@ export default class Resizable extends React.Component<Props, State> {
6164 // If you change this, be sure to update your css
6265 handleSize : PropTypes . array ,
6366
67+ // Defines which resize handles should be rendered (default: 'se')
68+ // Allows for any combination of:
69+ // 's' - South handle (bottom-center)
70+ // 'w' - West handle (left-center)
71+ // 'e' - East handle (right-center)
72+ // 'n' - North handle (top-center)
73+ // 'sw' - Southwest handle (bottom-left)
74+ // 'nw' - Northwest handle (top-left)
75+ // 'se' - Southeast handle (bottom-right)
76+ // 'ne' - Northeast handle (top-center)
77+ resizeHandles : PropTypes . arrayOf ( PropTypes . oneOf ( [ 's' , 'w' , 'e' , 'n' , 'sw' , 'nw' , 'se' , 'ne' ] ) ) ,
78+
6479 // If true, will only allow width/height to move in lockstep
6580 lockAspectRatio : PropTypes . bool ,
6681
@@ -89,7 +104,8 @@ export default class Resizable extends React.Component<Props, State> {
89104 lockAspectRatio : false ,
90105 axis : 'both' ,
91106 minConstraints : [ 20 , 20 ] ,
92- maxConstraints : [ Infinity , Infinity ]
107+ maxConstraints : [ Infinity , Infinity ] ,
108+ resizeHandles : [ 'se' ]
93109 } ;
94110
95111 state : State = {
@@ -161,12 +177,20 @@ export default class Resizable extends React.Component<Props, State> {
161177 * @param {String } handlerName Handler name to wrap.
162178 * @return {Function } Handler function.
163179 */
164- resizeHandler ( handlerName : string ) : Function {
180+ resizeHandler ( handlerName : string , axis : ResizeHandle ) : Function {
165181 return ( e : SyntheticEvent < > | MouseEvent , { node , deltaX , deltaY } : DragCallbackData ) => {
166182
167183 // Axis restrictions
168- const canDragX = this . props . axis === 'both' || this . props . axis === 'x' ;
169- const canDragY = this . props . axis === 'both' || this . props . axis === 'y' ;
184+ const canDragX = ( this . props . axis === 'both' || this . props . axis === 'x' ) && [ 'n' , 's' ] . indexOf ( axis ) === - 1 ;
185+ const canDragY = ( this . props . axis === 'both' || this . props . axis === 'y' ) && [ 'e' , 'w' ] . indexOf ( axis ) === - 1 ;
186+
187+ // reverse delta if using top or left drag handles
188+ if ( canDragX && axis [ axis . length - 1 ] === 'w' ) {
189+ deltaX = - deltaX ;
190+ }
191+ if ( canDragY && axis [ 0 ] === 'n' ) {
192+ deltaY = - deltaY ;
193+ }
170194
171195 // Update w/h
172196 let width = this . state . width + ( canDragX ? deltaX : 0 ) ;
@@ -195,18 +219,29 @@ export default class Resizable extends React.Component<Props, State> {
195219 const hasCb = typeof this . props [ handlerName ] === 'function' ;
196220 if ( hasCb ) {
197221 if ( typeof e . persist === 'function' ) e . persist ( ) ;
198- this . setState ( newState , ( ) => this . props [ handlerName ] ( e , { node, size : { width, height} } ) ) ;
222+ this . setState ( newState , ( ) => this . props [ handlerName ] ( e , { node, size : { width, height} , handle : axis } ) ) ;
199223 } else {
200224 this . setState ( newState ) ;
201225 }
202226 } ;
203227 }
204228
229+ renderResizeHandle ( resizeHandle : ResizeHandle ) : ReactNode {
230+ const { handle} = this . props ;
231+ if ( handle ) {
232+ if ( typeof handle === 'function' ) {
233+ return handle ( resizeHandle ) ;
234+ }
235+ return handle ;
236+ }
237+ return < span className = { `react-resizable-handle react-resizable-handle-${ resizeHandle } ` } /> ;
238+ }
239+
205240 render ( ) : ReactNode {
206241 // eslint-disable-next-line no-unused-vars
207- const { children, draggableOpts, width, height, handle , handleSize,
242+ const { children, draggableOpts, width, height, handleSize,
208243 lockAspectRatio, axis, minConstraints, maxConstraints, onResize,
209- onResizeStop, onResizeStart, ...p } = this . props ;
244+ onResizeStop, onResizeStart, resizeHandles , ...p } = this . props ;
210245
211246 const className = p . className ?
212247 `${ p . className } react-resizable` :
@@ -215,21 +250,23 @@ export default class Resizable extends React.Component<Props, State> {
215250 // What we're doing here is getting the child of this element, and cloning it with this element's props.
216251 // We are then defining its children as:
217252 // Its original children (resizable's child's children), and
218- // A draggable handle .
253+ // One or more draggable handles .
219254 return cloneElement ( children , {
220255 ...p ,
221256 className,
222257 children : [
223258 children . props . children ,
224- < DraggableCore
225- { ...draggableOpts }
226- key = "resizableHandle"
227- onStop = { this . resizeHandler ( 'onResizeStop' ) }
228- onStart = { this . resizeHandler ( 'onResizeStart' ) }
229- onDrag = { this . resizeHandler ( 'onResize' ) }
230- >
231- { handle || < span className = "react-resizable-handle" /> }
232- </ DraggableCore >
259+ resizeHandles . map ( h => (
260+ < DraggableCore
261+ { ...draggableOpts }
262+ key = { `resizableHandle-${ h } ` }
263+ onStop = { this . resizeHandler ( 'onResizeStop' , h ) }
264+ onStart = { this . resizeHandler ( 'onResizeStart' , h ) }
265+ onDrag = { this . resizeHandler ( 'onResize' , h ) }
266+ >
267+ { this . renderResizeHandle ( h ) }
268+ </ DraggableCore >
269+ ) )
233270 ]
234271 } ) ;
235272 }
0 commit comments