From a648676d6d3bdf1224555a0e11a9c00f6cb3336c Mon Sep 17 00:00:00 2001 From: Alexandr Date: Wed, 14 Jun 2017 21:17:48 +0300 Subject: [PATCH 1/3] Updated react to latest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated react, react-dom & added new deps — prop-types. --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 900b4f1..daa5ddb 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,9 @@ "prepublish": "npm run build" }, "dependencies": { - "react": "^15.3.2", - "react-dom": "^15.3.2" + "react": "^15.6.0", + "react-dom": "^15.6.0", + "prop-types": "^15.5.10", }, "keywords": [ "react", From 248d2a8daeb5e896fac9029d6c83a4957aa764ce Mon Sep 17 00:00:00 2001 From: Alexandr Date: Wed, 14 Jun 2017 21:20:50 +0300 Subject: [PATCH 2/3] Moved propTypes to external deps --- src/ResizableComponent.jsx | 621 +++++++++++++++++++------------------ 1 file changed, 311 insertions(+), 310 deletions(-) diff --git a/src/ResizableComponent.jsx b/src/ResizableComponent.jsx index 58718db..152e255 100644 --- a/src/ResizableComponent.jsx +++ b/src/ResizableComponent.jsx @@ -1,316 +1,317 @@ var React = require('react'); var ReactDOM = require('react-dom'); +var PropTypes = require('prop-types'); var ResizableComponent = React.createClass({ - getInitialState: function() { - return { - // Mouse events - mouseHeldDown: false, - originalY: 0, - originalX: 0, - - // Dimensions of box - direction: this.props.direction, - initialBoxHeight: this.props.height, - initialBoxWidth: this.props.width, - boxHeight: this.props.height, - boxWidth: this.props.width, - minHeight: this.props.options.minHeight || this.props.height, - minWidth: this.props.options.minWidth || this.props.width, - maxHeight: this.props.options.maxHeight || Infinity, - maxWidth: this.props.options.maxWidth || Infinity, - lockAspectRatio: this.props.options.lockAspectRatio || false, - fullWidth: this.props.options.fullWidth || false, - - // Stepping of resizing - step: this.props.options.step || 1, - currStepY: 0, - currStepX: 0, - steppingMargin: this.props.steppingMargin, - originalBoxWidth: this.props.width, - originalBoxHeight: this.props.height, - - // Width of resizable handle - cursorMargin: this.props.options.cursorMargin || this.props.cursorMargin, - - // Ghost Resizing - allowGhostResize: this.props.options.allowGhostResize || false - }; - }, - - propTypes: { - children: React.PropTypes.element.isRequired, - direction: React.PropTypes.oneOf(['s', 'e', 'se']), - - // Dimensions - width: React.PropTypes.number, - height: React.PropTypes.number, - - // Styling - className: React.PropTypes.string, - style: React.PropTypes.object, - ghostCssStyles: React.PropTypes.object, - - // Callbacks - onStartResize: React.PropTypes.func, - onStopResize: React.PropTypes.func, - onEachStep: React.PropTypes.func, - onDuringResize: React.PropTypes.func, - - // Other options - options: React.PropTypes.object - }, - - getDefaultProps: function() { - return { - options: {}, - direction: 's', - - height: 50, - width: 250, - - steppingMargin: 20, - cursorMargin: 10 - }; - }, - - componentDidMount: function() { - var _this = this; - var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; - var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; - - if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { - parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; - parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; - } - - // Attaches event listeners to parent div - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mousemove', (e) => { - _this._resizeDiv(e); - }); - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseup', (e) => { - _this._stopDrag(e); - }); - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseleave', (e) => { - _this._stopDrag(e); - }); - }, - - _startDrag: function(e) { - this.makeParentHighlightable(false); - this.setState({ - mouseHeldDown: true, - originalY: e.clientY, - originalX: e.clientX - }, function() { - if (this.props.onStartResize) this.props.onStartResize( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - }); - }, - - _stopDrag: function(e) { - this.makeParentHighlightable(true); - // Only invoke onStopResize if this component has started resizing - if (this.state.mouseHeldDown && this.props.onStopResize) { - this.props.onStopResize( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - } - if (!this.state.allowGhostResize) { - this.setState({ - mouseHeldDown: false, - initialBoxHeight: this.state.boxHeight, - initialBoxWidth: this.state.boxWidth - }); - } else { - // Ghost resizing - // Change the dimensions back to the original - this.setState({ - mouseHeldDown: false, - boxHeight: this.state.originalBoxHeight, - boxWidth: this.state.originalBoxWidth - }); - } - - }, - - _resizeDiv: function(e) { - if (this.state.mouseHeldDown) { - var distanceY = e.clientY - this.state.originalY; - var distanceX = e.clientX - this.state.originalX; - - var newHeight = this.state.initialBoxHeight + distanceY; - var newWidth = this.state.initialBoxWidth + distanceX; - - var steppingRemainderY = distanceY % this.state.step; - var steppingRemainderX = distanceX % this.state.step; - - // NOTE: For checking whether the new dimensions violates the minimum constraints, - // The steeping margin is given as allowance so that the box can be re-sized to the smallest - // dimension smoothly. - var heightCanChange = newHeight >= (this.state.minHeight - this.state.steppingMargin) - && newHeight <= (this.state.maxHeight + this.state.steppingMargin) // newHeight is below maxHeight - && steppingRemainderY <= this.state.steppingMargin // A little allowance is given for stepping - && this.state.direction.indexOf('s') > -1; - - var widthCanChange = newWidth >= (this.state.minWidth - this.state.steppingMargin) - && newWidth <= (this.state.maxWidth + this.state.steppingMargin) - && steppingRemainderX <= this.state.steppingMargin - && this.state.direction.indexOf('e') > -1; - - // If new dimensions are indeed lesser than the minimum constraint or greater than the maximum constraint, - // set the dimension to the minimum/maximum respectively - newHeight = newHeight - steppingRemainderY; - newWidth = newWidth - steppingRemainderX; - if (newHeight < this.state.minHeight) newHeight = this.state.minHeight; - if (newWidth < this.state.minWidth) newWidth = this.state.minWidth; - if (newHeight > this.state.maxHeight) newHeight = this.state.maxHeight; - if (newWidth > this.state.maxWidth) newWidth = this.state.maxWidth; - - // If lockAspectRatio is true, we programatically calculate the width - if (this.state.direction === 'se' && this.state.lockAspectRatio) { - var aspectRatio = this.state.originalBoxHeight / this.state.originalBoxWidth; - newWidth = newHeight / aspectRatio; - } - - this.setState({ - boxHeight: heightCanChange ? newHeight : this.state.boxHeight, - boxWidth: widthCanChange ? newWidth : this.state.boxWidth - }, function() { - - // Callback for onDuringResize - // Not called when step is active - if (this.props.onDuringResize && this.state.step === 1) { - this.props.onDuringResize(this.state.boxWidth, - this.state.boxHeight); - } - - // Callback for onEachStep - // Only when step size has changed, then we invoke to callback - if ((this.state.boxHeight !== this.state.currStepY || this.state.boxWidth !== this.state.currStepX) - && this.props.onEachStep && this.state.step > 1) { - this.props.onEachStep( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - this.setState({ - currStepY: this.state.boxHeight, - currStepX: this.state.boxWidth - }); - } - - }); - - } - }, - - // Styles the resize handler according to the direction given - getResizeHandlerStyle: function() { - var resizeHandlerStyle = {}; - - if (this.state.direction === 's') { - resizeHandlerStyle = { - width: this.state.boxWidth + 'px', - height: this.state.cursorMargin + 'px', - cursor: 's-resize', - position: 'absolute', - bottom: '0px', - left: '0px' - }; - } - - if (this.state.direction === 'e') { - resizeHandlerStyle = { - width: this.state.cursorMargin + 'px', - height: this.state.boxHeight + 'px', - cursor: 'e-resize', - position: 'absolute', - bottom: '0px', - right: '0px' - }; - } - - if (this.state.direction === 'se') { - resizeHandlerStyle = { - width: this.state.cursorMargin + 'px', - height: this.state.cursorMargin + 'px', - cursor: 'se-resize', - position: 'absolute', - bottom: '0px', - right: '0px' - }; - } - - resizeHandlerStyle['zIndex'] = 1; - return resizeHandlerStyle; - }, - - // Helper function to make the all components in parent non-highlight-able - makeParentHighlightable: function(highlight) { - var _this = this; - var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; - var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; - - if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { - parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; - parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; - } - - // Attaches event listeners to parent div - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.userSelect = highlight ? 'all' : 'none'; - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.mozUserSelect = highlight ? 'all' : 'none'; - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.webkitUserSelect = highlight ? 'all' : 'none'; - }, - - render: function() { - var outerDivStyle = { - backgroundColor: 'transparent', - width: (!this.state.allowGhostResize) ? this.state.boxWidth + 'px' : - (this.state.fullWidth ? '100%' : this.state.originalBoxWidth), - height: (!this.state.allowGhostResize) ? this.state.boxHeight + 'px' : this.state.originalBoxHeight, - cursor: 'default', - position: 'relative' - }; - - // Merge in any custom styles and overwrite existing styles (if any) - if (this.props.style) { - var customStyles = this.props.style; - for (var prop in customStyles) outerDivStyle[prop] = customStyles[prop]; - } - - var resizeHandlerStyle = this.getResizeHandlerStyle(); - - // For ghostResizing - var highlightDiv; - if (this.state.allowGhostResize) { - var ghostDivStyles = { - zIndex: '1', - display: this.state.mouseHeldDown ? 'block' : 'none', - backgroundColor: '#000000', - opacity: '0.3', - width: (this.state.fullWidth) ? '100%' :this.state.boxWidth + 'px', - height: this.state.boxHeight + 'px', - cursor: 'default', - position: 'absolute', - top: '0px', - left: '0px' - }; - if (this.props.ghostCssStyles) { - var css = this.props.ghostCssStyles - for (var prop in css) ghostDivStyles[prop] = css[prop]; - } - highlightDiv =
; - } - - return
- {highlightDiv} -
- {this.props.children} -
; - } + getInitialState: function() { + return { + // Mouse events + mouseHeldDown: false, + originalY: 0, + originalX: 0, + + // Dimensions of box + direction: this.props.direction, + initialBoxHeight: this.props.height, + initialBoxWidth: this.props.width, + boxHeight: this.props.height, + boxWidth: this.props.width, + minHeight: this.props.options.minHeight || this.props.height, + minWidth: this.props.options.minWidth || this.props.width, + maxHeight: this.props.options.maxHeight || Infinity, + maxWidth: this.props.options.maxWidth || Infinity, + lockAspectRatio: this.props.options.lockAspectRatio || false, + fullWidth: this.props.options.fullWidth || false, + + // Stepping of resizing + step: this.props.options.step || 1, + currStepY: 0, + currStepX: 0, + steppingMargin: this.props.steppingMargin, + originalBoxWidth: this.props.width, + originalBoxHeight: this.props.height, + + // Width of resizable handle + cursorMargin: this.props.options.cursorMargin || this.props.cursorMargin, + + // Ghost Resizing + allowGhostResize: this.props.options.allowGhostResize || false + }; + }, + + propTypes: { + children: PropTypes.element.isRequired, + direction: PropTypes.oneOf(['s', 'e', 'se']), + + // Dimensions + width: PropTypes.number, + height: PropTypes.number, + + // Styling + className: PropTypes.string, + style: PropTypes.object, + ghostCssStyles: PropTypes.object, + + // Callbacks + onStartResize: PropTypes.func, + onStopResize: PropTypes.func, + onEachStep: PropTypes.func, + onDuringResize: PropTypes.func, + + // Other options + options: PropTypes.object + }, + + getDefaultProps: function() { + return { + options: {}, + direction: 's', + + height: 50, + width: 250, + + steppingMargin: 20, + cursorMargin: 10 + }; + }, + + componentDidMount: function() { + var _this = this; + var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; + var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; + + if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { + parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; + parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; + } + + // Attaches event listeners to parent div + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mousemove', (e) => { + _this._resizeDiv(e); + }); + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseup', (e) => { + _this._stopDrag(e); + }); + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseleave', (e) => { + _this._stopDrag(e); + }); + }, + + _startDrag: function(e) { + this.makeParentHighlightable(false); + this.setState({ + mouseHeldDown: true, + originalY: e.clientY, + originalX: e.clientX + }, function() { + if (this.props.onStartResize) this.props.onStartResize( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + }); + }, + + _stopDrag: function(e) { + this.makeParentHighlightable(true); + // Only invoke onStopResize if this component has started resizing + if (this.state.mouseHeldDown && this.props.onStopResize) { + this.props.onStopResize( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + } + if (!this.state.allowGhostResize) { + this.setState({ + mouseHeldDown: false, + initialBoxHeight: this.state.boxHeight, + initialBoxWidth: this.state.boxWidth + }); + } else { + // Ghost resizing + // Change the dimensions back to the original + this.setState({ + mouseHeldDown: false, + boxHeight: this.state.originalBoxHeight, + boxWidth: this.state.originalBoxWidth + }); + } + + }, + + _resizeDiv: function(e) { + if (this.state.mouseHeldDown) { + var distanceY = e.clientY - this.state.originalY; + var distanceX = e.clientX - this.state.originalX; + + var newHeight = this.state.initialBoxHeight + distanceY; + var newWidth = this.state.initialBoxWidth + distanceX; + + var steppingRemainderY = distanceY % this.state.step; + var steppingRemainderX = distanceX % this.state.step; + + // NOTE: For checking whether the new dimensions violates the minimum constraints, + // The steeping margin is given as allowance so that the box can be re-sized to the smallest + // dimension smoothly. + var heightCanChange = newHeight >= (this.state.minHeight - this.state.steppingMargin) + && newHeight <= (this.state.maxHeight + this.state.steppingMargin) // newHeight is below maxHeight + && steppingRemainderY <= this.state.steppingMargin // A little allowance is given for stepping + && this.state.direction.indexOf('s') > -1; + + var widthCanChange = newWidth >= (this.state.minWidth - this.state.steppingMargin) + && newWidth <= (this.state.maxWidth + this.state.steppingMargin) + && steppingRemainderX <= this.state.steppingMargin + && this.state.direction.indexOf('e') > -1; + + // If new dimensions are indeed lesser than the minimum constraint or greater than the maximum constraint, + // set the dimension to the minimum/maximum respectively + newHeight = newHeight - steppingRemainderY; + newWidth = newWidth - steppingRemainderX; + if (newHeight < this.state.minHeight) newHeight = this.state.minHeight; + if (newWidth < this.state.minWidth) newWidth = this.state.minWidth; + if (newHeight > this.state.maxHeight) newHeight = this.state.maxHeight; + if (newWidth > this.state.maxWidth) newWidth = this.state.maxWidth; + + // If lockAspectRatio is true, we programatically calculate the width + if (this.state.direction === 'se' && this.state.lockAspectRatio) { + var aspectRatio = this.state.originalBoxHeight / this.state.originalBoxWidth; + newWidth = newHeight / aspectRatio; + } + + this.setState({ + boxHeight: heightCanChange ? newHeight : this.state.boxHeight, + boxWidth: widthCanChange ? newWidth : this.state.boxWidth + }, function() { + + // Callback for onDuringResize + // Not called when step is active + if (this.props.onDuringResize && this.state.step === 1) { + this.props.onDuringResize(this.state.boxWidth, + this.state.boxHeight); + } + + // Callback for onEachStep + // Only when step size has changed, then we invoke to callback + if ((this.state.boxHeight !== this.state.currStepY || this.state.boxWidth !== this.state.currStepX) + && this.props.onEachStep && this.state.step > 1) { + this.props.onEachStep( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + this.setState({ + currStepY: this.state.boxHeight, + currStepX: this.state.boxWidth + }); + } + + }); + + } + }, + + // Styles the resize handler according to the direction given + getResizeHandlerStyle: function() { + var resizeHandlerStyle = {}; + + if (this.state.direction === 's') { + resizeHandlerStyle = { + width: this.state.boxWidth + 'px', + height: this.state.cursorMargin + 'px', + cursor: 's-resize', + position: 'absolute', + bottom: '0px', + left: '0px' + }; + } + + if (this.state.direction === 'e') { + resizeHandlerStyle = { + width: this.state.cursorMargin + 'px', + height: this.state.boxHeight + 'px', + cursor: 'e-resize', + position: 'absolute', + bottom: '0px', + right: '0px' + }; + } + + if (this.state.direction === 'se') { + resizeHandlerStyle = { + width: this.state.cursorMargin + 'px', + height: this.state.cursorMargin + 'px', + cursor: 'se-resize', + position: 'absolute', + bottom: '0px', + right: '0px' + }; + } + + resizeHandlerStyle['zIndex'] = 1; + return resizeHandlerStyle; + }, + + // Helper function to make the all components in parent non-highlight-able + makeParentHighlightable: function(highlight) { + var _this = this; + var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; + var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; + + if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { + parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; + parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; + } + + // Attaches event listeners to parent div + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.userSelect = highlight ? 'all' : 'none'; + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.mozUserSelect = highlight ? 'all' : 'none'; + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.webkitUserSelect = highlight ? 'all' : 'none'; + }, + + render: function() { + var outerDivStyle = { + backgroundColor: 'transparent', + width: (!this.state.allowGhostResize) ? this.state.boxWidth + 'px' : + (this.state.fullWidth ? '100%' : this.state.originalBoxWidth), + height: (!this.state.allowGhostResize) ? this.state.boxHeight + 'px' : this.state.originalBoxHeight, + cursor: 'default', + position: 'relative' + }; + + // Merge in any custom styles and overwrite existing styles (if any) + if (this.props.style) { + var customStyles = this.props.style; + for (var prop in customStyles) outerDivStyle[prop] = customStyles[prop]; + } + + var resizeHandlerStyle = this.getResizeHandlerStyle(); + + // For ghostResizing + var highlightDiv; + if (this.state.allowGhostResize) { + var ghostDivStyles = { + zIndex: '1', + display: this.state.mouseHeldDown ? 'block' : 'none', + backgroundColor: '#000000', + opacity: '0.3', + width: (this.state.fullWidth) ? '100%' :this.state.boxWidth + 'px', + height: this.state.boxHeight + 'px', + cursor: 'default', + position: 'absolute', + top: '0px', + left: '0px' + }; + if (this.props.ghostCssStyles) { + var css = this.props.ghostCssStyles + for (var prop in css) ghostDivStyles[prop] = css[prop]; + } + highlightDiv =
; + } + + return
+ {highlightDiv} +
+ {this.props.children} +
; + } }); -module.exports = ResizableComponent; \ No newline at end of file +module.exports = ResizableComponent; From ef6da68b8f0cdd5d6e022222aadfcc0882602c2b Mon Sep 17 00:00:00 2001 From: Alexandr Date: Wed, 14 Jun 2017 21:26:01 +0300 Subject: [PATCH 3/3] Fixed indentation --- src/ResizableComponent.jsx | 618 ++++++++++++++++++------------------- 1 file changed, 309 insertions(+), 309 deletions(-) diff --git a/src/ResizableComponent.jsx b/src/ResizableComponent.jsx index 152e255..e66c967 100644 --- a/src/ResizableComponent.jsx +++ b/src/ResizableComponent.jsx @@ -3,315 +3,315 @@ var ReactDOM = require('react-dom'); var PropTypes = require('prop-types'); var ResizableComponent = React.createClass({ - getInitialState: function() { - return { - // Mouse events - mouseHeldDown: false, - originalY: 0, - originalX: 0, - - // Dimensions of box - direction: this.props.direction, - initialBoxHeight: this.props.height, - initialBoxWidth: this.props.width, - boxHeight: this.props.height, - boxWidth: this.props.width, - minHeight: this.props.options.minHeight || this.props.height, - minWidth: this.props.options.minWidth || this.props.width, - maxHeight: this.props.options.maxHeight || Infinity, - maxWidth: this.props.options.maxWidth || Infinity, - lockAspectRatio: this.props.options.lockAspectRatio || false, - fullWidth: this.props.options.fullWidth || false, - - // Stepping of resizing - step: this.props.options.step || 1, - currStepY: 0, - currStepX: 0, - steppingMargin: this.props.steppingMargin, - originalBoxWidth: this.props.width, - originalBoxHeight: this.props.height, - - // Width of resizable handle - cursorMargin: this.props.options.cursorMargin || this.props.cursorMargin, - - // Ghost Resizing - allowGhostResize: this.props.options.allowGhostResize || false - }; - }, - - propTypes: { - children: PropTypes.element.isRequired, - direction: PropTypes.oneOf(['s', 'e', 'se']), - - // Dimensions - width: PropTypes.number, - height: PropTypes.number, - - // Styling - className: PropTypes.string, - style: PropTypes.object, - ghostCssStyles: PropTypes.object, - - // Callbacks - onStartResize: PropTypes.func, - onStopResize: PropTypes.func, - onEachStep: PropTypes.func, - onDuringResize: PropTypes.func, - - // Other options - options: PropTypes.object - }, - - getDefaultProps: function() { - return { - options: {}, - direction: 's', - - height: 50, - width: 250, - - steppingMargin: 20, - cursorMargin: 10 - }; - }, - - componentDidMount: function() { - var _this = this; - var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; - var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; - - if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { - parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; - parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; - } - - // Attaches event listeners to parent div - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mousemove', (e) => { - _this._resizeDiv(e); - }); - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseup', (e) => { - _this._stopDrag(e); - }); - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseleave', (e) => { - _this._stopDrag(e); - }); - }, - - _startDrag: function(e) { - this.makeParentHighlightable(false); - this.setState({ - mouseHeldDown: true, - originalY: e.clientY, - originalX: e.clientX - }, function() { - if (this.props.onStartResize) this.props.onStartResize( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - }); - }, - - _stopDrag: function(e) { - this.makeParentHighlightable(true); - // Only invoke onStopResize if this component has started resizing - if (this.state.mouseHeldDown && this.props.onStopResize) { - this.props.onStopResize( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - } - if (!this.state.allowGhostResize) { - this.setState({ - mouseHeldDown: false, - initialBoxHeight: this.state.boxHeight, - initialBoxWidth: this.state.boxWidth - }); - } else { - // Ghost resizing - // Change the dimensions back to the original - this.setState({ - mouseHeldDown: false, - boxHeight: this.state.originalBoxHeight, - boxWidth: this.state.originalBoxWidth - }); - } - - }, - - _resizeDiv: function(e) { - if (this.state.mouseHeldDown) { - var distanceY = e.clientY - this.state.originalY; - var distanceX = e.clientX - this.state.originalX; - - var newHeight = this.state.initialBoxHeight + distanceY; - var newWidth = this.state.initialBoxWidth + distanceX; - - var steppingRemainderY = distanceY % this.state.step; - var steppingRemainderX = distanceX % this.state.step; - - // NOTE: For checking whether the new dimensions violates the minimum constraints, - // The steeping margin is given as allowance so that the box can be re-sized to the smallest - // dimension smoothly. - var heightCanChange = newHeight >= (this.state.minHeight - this.state.steppingMargin) - && newHeight <= (this.state.maxHeight + this.state.steppingMargin) // newHeight is below maxHeight - && steppingRemainderY <= this.state.steppingMargin // A little allowance is given for stepping - && this.state.direction.indexOf('s') > -1; - - var widthCanChange = newWidth >= (this.state.minWidth - this.state.steppingMargin) - && newWidth <= (this.state.maxWidth + this.state.steppingMargin) - && steppingRemainderX <= this.state.steppingMargin - && this.state.direction.indexOf('e') > -1; - - // If new dimensions are indeed lesser than the minimum constraint or greater than the maximum constraint, - // set the dimension to the minimum/maximum respectively - newHeight = newHeight - steppingRemainderY; - newWidth = newWidth - steppingRemainderX; - if (newHeight < this.state.minHeight) newHeight = this.state.minHeight; - if (newWidth < this.state.minWidth) newWidth = this.state.minWidth; - if (newHeight > this.state.maxHeight) newHeight = this.state.maxHeight; - if (newWidth > this.state.maxWidth) newWidth = this.state.maxWidth; - - // If lockAspectRatio is true, we programatically calculate the width - if (this.state.direction === 'se' && this.state.lockAspectRatio) { - var aspectRatio = this.state.originalBoxHeight / this.state.originalBoxWidth; - newWidth = newHeight / aspectRatio; - } - - this.setState({ - boxHeight: heightCanChange ? newHeight : this.state.boxHeight, - boxWidth: widthCanChange ? newWidth : this.state.boxWidth - }, function() { - - // Callback for onDuringResize - // Not called when step is active - if (this.props.onDuringResize && this.state.step === 1) { - this.props.onDuringResize(this.state.boxWidth, - this.state.boxHeight); - } - - // Callback for onEachStep - // Only when step size has changed, then we invoke to callback - if ((this.state.boxHeight !== this.state.currStepY || this.state.boxWidth !== this.state.currStepX) - && this.props.onEachStep && this.state.step > 1) { - this.props.onEachStep( - (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, - (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step - ); - this.setState({ - currStepY: this.state.boxHeight, - currStepX: this.state.boxWidth - }); - } - - }); - - } - }, - - // Styles the resize handler according to the direction given - getResizeHandlerStyle: function() { - var resizeHandlerStyle = {}; - - if (this.state.direction === 's') { - resizeHandlerStyle = { - width: this.state.boxWidth + 'px', - height: this.state.cursorMargin + 'px', - cursor: 's-resize', - position: 'absolute', - bottom: '0px', - left: '0px' - }; - } - - if (this.state.direction === 'e') { - resizeHandlerStyle = { - width: this.state.cursorMargin + 'px', - height: this.state.boxHeight + 'px', - cursor: 'e-resize', - position: 'absolute', - bottom: '0px', - right: '0px' - }; - } - - if (this.state.direction === 'se') { - resizeHandlerStyle = { - width: this.state.cursorMargin + 'px', - height: this.state.cursorMargin + 'px', - cursor: 'se-resize', - position: 'absolute', - bottom: '0px', - right: '0px' - }; - } - - resizeHandlerStyle['zIndex'] = 1; - return resizeHandlerStyle; - }, - - // Helper function to make the all components in parent non-highlight-able - makeParentHighlightable: function(highlight) { - var _this = this; - var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; - var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; - - if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { - parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; - parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; - } - - // Attaches event listeners to parent div - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.userSelect = highlight ? 'all' : 'none'; - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.mozUserSelect = highlight ? 'all' : 'none'; - document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.webkitUserSelect = highlight ? 'all' : 'none'; - }, - - render: function() { - var outerDivStyle = { - backgroundColor: 'transparent', - width: (!this.state.allowGhostResize) ? this.state.boxWidth + 'px' : - (this.state.fullWidth ? '100%' : this.state.originalBoxWidth), - height: (!this.state.allowGhostResize) ? this.state.boxHeight + 'px' : this.state.originalBoxHeight, - cursor: 'default', - position: 'relative' - }; - - // Merge in any custom styles and overwrite existing styles (if any) - if (this.props.style) { - var customStyles = this.props.style; - for (var prop in customStyles) outerDivStyle[prop] = customStyles[prop]; - } - - var resizeHandlerStyle = this.getResizeHandlerStyle(); - - // For ghostResizing - var highlightDiv; - if (this.state.allowGhostResize) { - var ghostDivStyles = { - zIndex: '1', - display: this.state.mouseHeldDown ? 'block' : 'none', - backgroundColor: '#000000', - opacity: '0.3', - width: (this.state.fullWidth) ? '100%' :this.state.boxWidth + 'px', - height: this.state.boxHeight + 'px', - cursor: 'default', - position: 'absolute', - top: '0px', - left: '0px' - }; - if (this.props.ghostCssStyles) { - var css = this.props.ghostCssStyles - for (var prop in css) ghostDivStyles[prop] = css[prop]; - } - highlightDiv =
; - } - - return
- {highlightDiv} -
- {this.props.children} -
; - } + getInitialState: function() { + return { + // Mouse events + mouseHeldDown: false, + originalY: 0, + originalX: 0, + + // Dimensions of box + direction: this.props.direction, + initialBoxHeight: this.props.height, + initialBoxWidth: this.props.width, + boxHeight: this.props.height, + boxWidth: this.props.width, + minHeight: this.props.options.minHeight || this.props.height, + minWidth: this.props.options.minWidth || this.props.width, + maxHeight: this.props.options.maxHeight || Infinity, + maxWidth: this.props.options.maxWidth || Infinity, + lockAspectRatio: this.props.options.lockAspectRatio || false, + fullWidth: this.props.options.fullWidth || false, + + // Stepping of resizing + step: this.props.options.step || 1, + currStepY: 0, + currStepX: 0, + steppingMargin: this.props.steppingMargin, + originalBoxWidth: this.props.width, + originalBoxHeight: this.props.height, + + // Width of resizable handle + cursorMargin: this.props.options.cursorMargin || this.props.cursorMargin, + + // Ghost Resizing + allowGhostResize: this.props.options.allowGhostResize || false + }; + }, + + propTypes: { + children: PropTypes.element.isRequired, + direction: PropTypes.oneOf(['s', 'e', 'se']), + + // Dimensions + width: PropTypes.number, + height: PropTypes.number, + + // Styling + className: PropTypes.string, + style: PropTypes.object, + ghostCssStyles: PropTypes.object, + + // Callbacks + onStartResize: PropTypes.func, + onStopResize: PropTypes.func, + onEachStep: PropTypes.func, + onDuringResize: PropTypes.func, + + // Other options + options: PropTypes.object + }, + + getDefaultProps: function() { + return { + options: {}, + direction: 's', + + height: 50, + width: 250, + + steppingMargin: 20, + cursorMargin: 10 + }; + }, + + componentDidMount: function() { + var _this = this; + var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; + var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; + + if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { + parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; + parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; + } + + // Attaches event listeners to parent div + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mousemove', (e) => { + _this._resizeDiv(e); + }); + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseup', (e) => { + _this._stopDrag(e); + }); + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').addEventListener('mouseleave', (e) => { + _this._stopDrag(e); + }); + }, + + _startDrag: function(e) { + this.makeParentHighlightable(false); + this.setState({ + mouseHeldDown: true, + originalY: e.clientY, + originalX: e.clientX + }, function() { + if (this.props.onStartResize) this.props.onStartResize( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + }); + }, + + _stopDrag: function(e) { + this.makeParentHighlightable(true); + // Only invoke onStopResize if this component has started resizing + if (this.state.mouseHeldDown && this.props.onStopResize) { + this.props.onStopResize( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + } + if (!this.state.allowGhostResize) { + this.setState({ + mouseHeldDown: false, + initialBoxHeight: this.state.boxHeight, + initialBoxWidth: this.state.boxWidth + }); + } else { + // Ghost resizing + // Change the dimensions back to the original + this.setState({ + mouseHeldDown: false, + boxHeight: this.state.originalBoxHeight, + boxWidth: this.state.originalBoxWidth + }); + } + + }, + + _resizeDiv: function(e) { + if (this.state.mouseHeldDown) { + var distanceY = e.clientY - this.state.originalY; + var distanceX = e.clientX - this.state.originalX; + + var newHeight = this.state.initialBoxHeight + distanceY; + var newWidth = this.state.initialBoxWidth + distanceX; + + var steppingRemainderY = distanceY % this.state.step; + var steppingRemainderX = distanceX % this.state.step; + + // NOTE: For checking whether the new dimensions violates the minimum constraints, + // The steeping margin is given as allowance so that the box can be re-sized to the smallest + // dimension smoothly. + var heightCanChange = newHeight >= (this.state.minHeight - this.state.steppingMargin) + && newHeight <= (this.state.maxHeight + this.state.steppingMargin) // newHeight is below maxHeight + && steppingRemainderY <= this.state.steppingMargin // A little allowance is given for stepping + && this.state.direction.indexOf('s') > -1; + + var widthCanChange = newWidth >= (this.state.minWidth - this.state.steppingMargin) + && newWidth <= (this.state.maxWidth + this.state.steppingMargin) + && steppingRemainderX <= this.state.steppingMargin + && this.state.direction.indexOf('e') > -1; + + // If new dimensions are indeed lesser than the minimum constraint or greater than the maximum constraint, + // set the dimension to the minimum/maximum respectively + newHeight = newHeight - steppingRemainderY; + newWidth = newWidth - steppingRemainderX; + if (newHeight < this.state.minHeight) newHeight = this.state.minHeight; + if (newWidth < this.state.minWidth) newWidth = this.state.minWidth; + if (newHeight > this.state.maxHeight) newHeight = this.state.maxHeight; + if (newWidth > this.state.maxWidth) newWidth = this.state.maxWidth; + + // If lockAspectRatio is true, we programatically calculate the width + if (this.state.direction === 'se' && this.state.lockAspectRatio) { + var aspectRatio = this.state.originalBoxHeight / this.state.originalBoxWidth; + newWidth = newHeight / aspectRatio; + } + + this.setState({ + boxHeight: heightCanChange ? newHeight : this.state.boxHeight, + boxWidth: widthCanChange ? newWidth : this.state.boxWidth + }, function() { + + // Callback for onDuringResize + // Not called when step is active + if (this.props.onDuringResize && this.state.step === 1) { + this.props.onDuringResize(this.state.boxWidth, + this.state.boxHeight); + } + + // Callback for onEachStep + // Only when step size has changed, then we invoke to callback + if ((this.state.boxHeight !== this.state.currStepY || this.state.boxWidth !== this.state.currStepX) + && this.props.onEachStep && this.state.step > 1) { + this.props.onEachStep( + (this.state.boxWidth - this.state.originalBoxWidth) / this.state.step, + (this.state.boxHeight - this.state.originalBoxHeight) / this.state.step + ); + this.setState({ + currStepY: this.state.boxHeight, + currStepX: this.state.boxWidth + }); + } + + }); + + } + }, + + // Styles the resize handler according to the direction given + getResizeHandlerStyle: function() { + var resizeHandlerStyle = {}; + + if (this.state.direction === 's') { + resizeHandlerStyle = { + width: this.state.boxWidth + 'px', + height: this.state.cursorMargin + 'px', + cursor: 's-resize', + position: 'absolute', + bottom: '0px', + left: '0px' + }; + } + + if (this.state.direction === 'e') { + resizeHandlerStyle = { + width: this.state.cursorMargin + 'px', + height: this.state.boxHeight + 'px', + cursor: 'e-resize', + position: 'absolute', + bottom: '0px', + right: '0px' + }; + } + + if (this.state.direction === 'se') { + resizeHandlerStyle = { + width: this.state.cursorMargin + 'px', + height: this.state.cursorMargin + 'px', + cursor: 'se-resize', + position: 'absolute', + bottom: '0px', + right: '0px' + }; + } + + resizeHandlerStyle['zIndex'] = 1; + return resizeHandlerStyle; + }, + + // Helper function to make the all components in parent non-highlight-able + makeParentHighlightable: function(highlight) { + var _this = this; + var parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[0].name; + var parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[0].value; + + if (ReactDOM.findDOMNode(this).parentNode.attributes.length > 1) { + parentAttrName = ReactDOM.findDOMNode(this).parentNode.attributes[1].name; + parentAttrValue = ReactDOM.findDOMNode(this).parentNode.attributes[1].value; + } + + // Attaches event listeners to parent div + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.userSelect = highlight ? 'all' : 'none'; + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.mozUserSelect = highlight ? 'all' : 'none'; + document.querySelector('[' + parentAttrName + '="' + parentAttrValue + '"]').style.webkitUserSelect = highlight ? 'all' : 'none'; + }, + + render: function() { + var outerDivStyle = { + backgroundColor: 'transparent', + width: (!this.state.allowGhostResize) ? this.state.boxWidth + 'px' : + (this.state.fullWidth ? '100%' : this.state.originalBoxWidth), + height: (!this.state.allowGhostResize) ? this.state.boxHeight + 'px' : this.state.originalBoxHeight, + cursor: 'default', + position: 'relative' + }; + + // Merge in any custom styles and overwrite existing styles (if any) + if (this.props.style) { + var customStyles = this.props.style; + for (var prop in customStyles) outerDivStyle[prop] = customStyles[prop]; + } + + var resizeHandlerStyle = this.getResizeHandlerStyle(); + + // For ghostResizing + var highlightDiv; + if (this.state.allowGhostResize) { + var ghostDivStyles = { + zIndex: '1', + display: this.state.mouseHeldDown ? 'block' : 'none', + backgroundColor: '#000000', + opacity: '0.3', + width: (this.state.fullWidth) ? '100%' :this.state.boxWidth + 'px', + height: this.state.boxHeight + 'px', + cursor: 'default', + position: 'absolute', + top: '0px', + left: '0px' + }; + if (this.props.ghostCssStyles) { + var css = this.props.ghostCssStyles + for (var prop in css) ghostDivStyles[prop] = css[prop]; + } + highlightDiv =
; + } + + return
+ {highlightDiv} +
+ {this.props.children} +
; + } }); module.exports = ResizableComponent;