11// @flow
22import { default as React , PropTypes } from 'react' ;
3- import Draggable from 'react-draggable' ;
3+ import { DraggableCore } from 'react-draggable' ;
44import cloneElement from './cloneElement' ;
55
6- type Bounds = {
7- top : number ,
8- right : number ,
9- bottom : number ,
10- left : number
11- } ;
126type Position = {
137 deltaX : number ,
148 deltaY : number
159} ;
1610type State = {
1711 resizing : boolean ,
1812 width : number , height : number ,
19- initialWidth : number , initialHeight : number
13+ slackW : number , slackH : number
2014} ;
2115type DragCallbackData = {
2216 node : HTMLElement ,
23- deltaX : number ,
24- deltaY : number ,
25- position : { left : number , top : number }
17+ position : Position
2618} ;
2719
2820export default class Resizable extends React . Component {
@@ -71,10 +63,8 @@ export default class Resizable extends React.Component {
7163
7264 state : State = {
7365 resizing : false ,
74- initialHeight : this . props . height ,
75- initialWidth : this . props . width ,
76- height : this . props . height ,
77- width : this . props . width ,
66+ width : this . props . width , height : this . props . height ,
67+ slackW : 0 , slackH : 0
7868 } ;
7969
8070 componentWillReceiveProps ( nextProps : Object ) {
@@ -83,50 +73,75 @@ export default class Resizable extends React.Component {
8373 ( nextProps . width !== this . props . width || nextProps . height !== this . props . height ) ) {
8474 this . setState ( {
8575 width : nextProps . width ,
86- height : nextProps . height ,
87- initialWidth : nextProps . width ,
88- initialHeight : nextProps . height
76+ height : nextProps . height
8977 } ) ;
9078 }
9179 }
9280
93- /**
94- * Convert our constraints into bounds for the <Draggable>.
95- * We have to use initialHeight/Width here because that's where the <Draggable>'s `0` is.
96- */
97- constraintsToBounds ( ) : Bounds {
98- const { minConstraints, maxConstraints} = this . props ;
99- const { initialHeight, initialWidth} = this . state ;
100- return {
101- left : minConstraints [ 0 ] - initialWidth ,
102- top : minConstraints [ 1 ] - initialHeight ,
103- right : maxConstraints [ 0 ] - initialWidth ,
104- bottom : maxConstraints [ 1 ] - initialHeight
105- } ;
106- }
107-
10881 lockAspectRatio ( width : number , height : number , aspectRatio : number ) : [ number , number ] {
10982 height = width / aspectRatio ;
11083 width = height * aspectRatio ;
11184 return [ width , height ] ;
11285 }
11386
87+ // If you do this, be careful of constraints
88+ runConstraints ( width : number , height : number ) : [ number , number ] {
89+ let [ min , max ] = [ this . props . minConstraints , this . props . maxConstraints ] ;
90+
91+ if ( this . props . lockAspectRatio ) {
92+ const ratio = this . state . width / this . state . height ;
93+ height = width / ratio ;
94+ width = height * ratio ;
95+ }
96+
97+ if ( ! min && ! max ) return [ width , height ] ;
98+
99+ let [ oldW , oldH ] = [ width , height ] ;
100+
101+ // Add slack to the values used to calculate bound position. This will ensure that if
102+ // we start removing slack, the element won't react to it right away until it's been
103+ // completely removed.
104+ let { slackW, slackH} = this . state ;
105+ width += slackW ;
106+ height += slackH ;
107+
108+ if ( min ) {
109+ width = Math . max ( min [ 0 ] , width ) ;
110+ height = Math . max ( min [ 1 ] , height ) ;
111+ }
112+ if ( max ) {
113+ width = Math . min ( max [ 0 ] , width ) ;
114+ height = Math . min ( max [ 1 ] , height ) ;
115+ }
116+
117+ // If the numbers changed, we must have introduced some slack. Record it for the next iteration.
118+ slackW += ( oldW - width ) ;
119+ slackH += ( oldH - height ) ;
120+ if ( slackW !== this . state . slackW || slackH !== this . state . slackH ) {
121+ this . setState ( { slackW, slackH} ) ;
122+ }
123+
124+ return [ width , height ] ;
125+ }
126+
114127 /**
115128 * Wrapper around drag events to provide more useful data.
116129 *
117130 * @param {String } handlerName Handler name to wrap.
118131 * @return {Function } Handler function.
119132 */
120133 resizeHandler ( handlerName : string ) : Function {
121- return ( e , { node, deltaX, deltaY} : DragCallbackData ) => {
134+ return ( e , { node, position} : DragCallbackData ) => {
135+ const { deltaX, deltaY} = position ;
122136 let width = this . state . width + deltaX , height = this . state . height + deltaY ;
123137
138+ // Early return if no change
124139 let widthChanged = width !== this . state . width , heightChanged = height !== this . state . height ;
125140 if ( handlerName === 'onResize' && ! widthChanged && ! heightChanged ) return ;
126141
127- if ( this . props . lockAspectRatio ) {
128- [ width , height ] = this . lockAspectRatio ( width , height , this . state . width / this . state . height ) ;
129- }
142+ console . log ( { width , height , slackW : this . state . slackW , slackH : this . state . slackH } ) ;
143+ [ width , height ] = this . runConstraints ( width , height ) ;
144+ console . log ( { width , height , slackW : this . state . slackW , slackH : this . state . slackH } ) ;
130145
131146 // Set the appropriate state for this handler.
132147 let newState = { } ;
@@ -135,6 +150,8 @@ export default class Resizable extends React.Component {
135150 } else if ( handlerName === 'onResizeStop' ) {
136151 newState . resizing = false ;
137152 } else {
153+ // Early return if no change after constraints
154+ if ( width === this . state . width && height === this . state . height ) return ;
138155 newState . width = width ;
139156 newState . height = height ;
140157 }
@@ -161,17 +178,15 @@ export default class Resizable extends React.Component {
161178 className,
162179 children : [
163180 p . children . props . children ,
164- < Draggable
181+ < DraggableCore
165182 { ...p . draggableOpts }
166183 ref = "draggable"
167- axis = "none"
168184 onStop = { this . resizeHandler ( 'onResizeStop' ) }
169185 onStart = { this . resizeHandler ( 'onResizeStart' ) }
170186 onDrag = { this . resizeHandler ( 'onResize' ) }
171- bounds = { this . constraintsToBounds ( ) }
172187 >
173188 < span className = "react-resizable-handle" />
174- </ Draggable >
189+ </ DraggableCore >
175190 ]
176191 } ) ;
177192 }
0 commit comments