react-resizable-box
Version:
<p align="center"><img src ="https://github.com/bokuweb/react-resizable-box/blob/master/logo.png?raw=true" /></p>
418 lines (374 loc) • 15.6 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _resizer = require('./resizer');
var _resizer2 = _interopRequireDefault(_resizer);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable react/no-unused-prop-types */
/* eslint-disable react/require-default-props */
/* eslint-disable react/jsx-filename-extension */
/* eslint-disable react/sort-comp */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable max-len */
/* eslint-disable no-bitwise */
/* eslint-disable react/no-did-mount-set-state */
var userSelectNone = {
userSelect: 'none',
MozUserSelect: 'none',
WebkitUserSelect: 'none',
MsUserSelect: 'none'
};
var userSelectAuto = {
userSelect: 'auto',
MozUserSelect: 'auto',
WebkitUserSelect: 'auto',
MsUserSelect: 'auto'
};
var clamp = function clamp(n, min, max) {
return Math.max(Math.min(n, max), min);
};
var snap = function snap(n, size) {
return Math.round(n / size) * size;
};
var Resizable = function (_Component) {
_inherits(Resizable, _Component);
function Resizable(props) {
_classCallCheck(this, Resizable);
var _this = _possibleConstructorReturn(this, (Resizable.__proto__ || Object.getPrototypeOf(Resizable)).call(this, props));
var width = props.width,
height = props.height;
_this.state = {
isResizing: false,
width: typeof width === 'undefined' ? 'auto' : width,
height: typeof height === 'undefined' ? 'auto' : height,
direction: 'right',
original: {
x: 0,
y: 0,
width: 0,
height: 0
}
};
_this.onResizeStart = _this.onResizeStart.bind(_this);
_this.onMouseMove = _this.onMouseMove.bind(_this);
_this.onMouseUp = _this.onMouseUp.bind(_this);
if (typeof window !== 'undefined') {
window.addEventListener('mouseup', _this.onMouseUp);
window.addEventListener('mousemove', _this.onMouseMove);
window.addEventListener('touchmove', _this.onMouseMove);
window.addEventListener('touchend', _this.onMouseUp);
}
return _this;
}
_createClass(Resizable, [{
key: 'componentDidMount',
value: function componentDidMount() {
var size = this.size;
// If props.width or height is not defined, set default size when mounted.
this.setState({
width: this.state.width || size.width,
height: this.state.height || size.height
});
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(_ref) {
var width = _ref.width,
height = _ref.height;
if (width !== this.props.width) {
this.setState({ width: width });
}
if (height !== this.props.height) {
this.setState({ height: height });
}
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (typeof window !== 'undefined') {
window.removeEventListener('mouseup', this.onMouseUp);
window.removeEventListener('mousemove', this.onMouseMove);
window.removeEventListener('touchmove', this.onMouseMove);
window.removeEventListener('touchend', this.onMouseUp);
}
}
}, {
key: 'onResizeStart',
value: function onResizeStart(event, direction) {
var clientX = 0;
var clientY = 0;
if (event.nativeEvent instanceof MouseEvent) {
clientX = event.nativeEvent.clientX;
clientY = event.nativeEvent.clientY;
} else if (event.nativeEvent instanceof TouchEvent) {
clientX = event.nativeEvent.touches[0].clientX;
clientY = event.nativeEvent.touches[0].clientY;
}
if (this.props.onResizeStart) {
this.props.onResizeStart(event, direction, this.resizable);
}
var size = this.size;
this.setState({
original: {
x: clientX,
y: clientY,
width: size.width,
height: size.height
},
isResizing: true,
direction: direction
});
}
}, {
key: 'onMouseMove',
value: function onMouseMove(event) {
if (!this.state.isResizing) return;
var clientX = event instanceof MouseEvent ? event.clientX : event.touches[0].clientX;
var clientY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
var _state = this.state,
direction = _state.direction,
original = _state.original,
width = _state.width,
height = _state.height;
var _props = this.props,
lockAspectRatio = _props.lockAspectRatio,
minWidth = _props.minWidth,
minHeight = _props.minHeight;
var _props2 = this.props,
maxWidth = _props2.maxWidth,
maxHeight = _props2.maxHeight;
var ratio = original.height / original.width;
var newWidth = original.width;
var newHeight = original.height;
if (/right/i.test(direction)) {
newWidth = original.width + (clientX - original.x);
if (lockAspectRatio) newHeight = newWidth * ratio;
}
if (/left/i.test(direction)) {
newWidth = original.width - (clientX - original.x);
if (lockAspectRatio) newHeight = newWidth * ratio;
}
if (/bottom/i.test(direction)) {
newHeight = original.height + (clientY - original.y);
if (lockAspectRatio) newWidth = newHeight / ratio;
}
if (/top/i.test(direction)) {
newHeight = original.height - (clientY - original.y);
if (lockAspectRatio) newWidth = newHeight / ratio;
}
if (this.props.bounds === 'parent') {
var parent = this.resizable.parentNode;
if (parent instanceof HTMLElement) {
var parentRect = parent.getBoundingClientRect();
var parentLeft = parentRect.left;
var parentTop = parentRect.top;
var _resizable$getBoundin = this.resizable.getBoundingClientRect(),
_left = _resizable$getBoundin.left,
_top = _resizable$getBoundin.top;
var boundWidth = parent.offsetWidth + (parentLeft - _left);
var boundHeight = parent.offsetHeight + (parentTop - _top);
maxWidth = maxWidth && maxWidth < boundWidth ? maxWidth : boundWidth;
maxHeight = maxHeight && maxHeight < boundHeight ? maxHeight : boundHeight;
}
} else if (this.props.bounds === 'window') {
if (typeof window !== 'undefined') {
var _resizable$getBoundin2 = this.resizable.getBoundingClientRect(),
_left2 = _resizable$getBoundin2.left,
_top2 = _resizable$getBoundin2.top;
var _boundWidth = window.innerWidth - _left2;
var _boundHeight = window.innerHeight - _top2;
maxWidth = maxWidth && maxWidth < _boundWidth ? maxWidth : _boundWidth;
maxHeight = maxHeight && maxHeight < _boundHeight ? maxHeight : _boundHeight;
}
} else if (this.props.bounds instanceof HTMLElement) {
var targetRect = this.props.bounds.getBoundingClientRect();
var targetLeft = targetRect.left;
var targetTop = targetRect.top;
var _resizable$getBoundin3 = this.resizable.getBoundingClientRect(),
_left3 = _resizable$getBoundin3.left,
_top3 = _resizable$getBoundin3.top;
if (!(this.props.bounds instanceof HTMLElement)) return;
var _boundWidth2 = this.props.bounds.offsetWidth + (targetLeft - _left3);
var _boundHeight2 = this.props.bounds.offsetHeight + (targetTop - _top3);
maxWidth = maxWidth && maxWidth < _boundWidth2 ? maxWidth : _boundWidth2;
maxHeight = maxHeight && maxHeight < _boundHeight2 ? maxHeight : _boundHeight2;
}
var computedMinWidth = typeof minWidth === 'undefined' || minWidth < 0 ? 0 : minWidth;
var computedMaxWidth = typeof maxWidth === 'undefined' || maxWidth < 0 ? newWidth : maxWidth;
var computedMinHeight = typeof minHeight === 'undefined' || minHeight < 0 ? 0 : minHeight;
var computedMaxHeight = typeof maxHeight === 'undefined' || maxHeight < 0 ? newHeight : maxHeight;
if (lockAspectRatio) {
var lockedMinWidth = computedMinWidth > computedMinHeight / ratio ? computedMinWidth : computedMinHeight / ratio;
var lockedMaxWidth = computedMaxWidth < computedMaxHeight / ratio ? computedMaxWidth : computedMaxHeight / ratio;
var lockedMinHeight = computedMinHeight > computedMinWidth * ratio ? computedMinHeight : computedMinWidth * ratio;
var lockedMaxHeight = computedMaxHeight < computedMaxWidth * ratio ? computedMaxHeight : computedMaxWidth * ratio;
newWidth = clamp(newWidth, lockedMinWidth, lockedMaxWidth);
newHeight = clamp(newHeight, lockedMinHeight, lockedMaxHeight);
} else {
newWidth = clamp(newWidth, computedMinWidth, computedMaxWidth);
newHeight = clamp(newHeight, computedMinHeight, computedMaxHeight);
}
if (this.props.grid) {
newWidth = snap(newWidth, this.props.grid[0]);
}
if (this.props.grid) {
newHeight = snap(newHeight, this.props.grid[1]);
}
this.setState({
width: width !== 'auto' ? newWidth : 'auto',
height: height !== 'auto' ? newHeight : 'auto'
});
var delta = {
width: newWidth - original.width,
height: newHeight - original.height
};
if (this.props.onResize) {
this.props.onResize(event, direction, this.resizable, delta);
}
}
}, {
key: 'onMouseUp',
value: function onMouseUp(event) {
var _state2 = this.state,
isResizing = _state2.isResizing,
direction = _state2.direction,
original = _state2.original;
if (!isResizing) return;
var delta = {
width: this.size.width - original.width,
height: this.size.height - original.height
};
if (this.props.onResizeStop) {
this.props.onResizeStop(event, direction, this.resizable, delta);
}
this.setState({ isResizing: false });
}
}, {
key: 'setSize',
value: function setSize(size) {
this.setState({
width: this.state.width || size.width,
height: this.state.height || size.height
});
}
}, {
key: 'updateSize',
value: function updateSize(size) {
this.setState({ width: size.width, height: size.height });
}
}, {
key: 'renderResizer',
value: function renderResizer() {
var _this2 = this;
var _props3 = this.props,
enable = _props3.enable,
handlerStyles = _props3.handlerStyles,
handlerClasses = _props3.handlerClasses;
if (!enable) return null;
var content = Object.keys(enable).map(function (dir) {
if (enable[dir] !== false) {
return _react2.default.createElement(_resizer2.default, {
key: dir,
direction: dir,
onResizeStart: _this2.onResizeStart,
replaceStyles: handlerStyles && handlerStyles[dir],
className: handlerClasses && handlerClasses[dir]
});
}
return null;
});
var wrapperClass = handlerClasses && handlerClasses['wrapper'];
var wrapperStyle = handlerStyles && handlerStyles['wrapper'];
// #93 Wrap the resize box in span (will not break 100% width/height)
if (wrapperClass || wrapperStyle) {
return _react2.default.createElement(
'span',
{
className: wrapperClass,
style: wrapperStyle },
content
);
}
return content;
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
var userSelect = this.state.isResizing ? userSelectNone : userSelectAuto;
var _props4 = this.props,
style = _props4.style,
className = _props4.className;
return _react2.default.createElement(
'div',
_extends({
ref: function ref(c) {
_this3.resizable = c;
},
style: _extends({
position: 'relative'
}, userSelect, style, this.style, {
boxSizing: 'border-box'
}),
className: className
}, this.props.extendsProps),
this.props.children,
this.renderResizer()
);
}
}, {
key: 'size',
get: function get() {
var width = 0;
var height = 0;
if (typeof window !== 'undefined') {
var _style = window.getComputedStyle(this.resizable, null);
width = ~~_style.getPropertyValue('width').replace('px', '');
height = ~~_style.getPropertyValue('height').replace('px', '');
}
return { width: width, height: height };
}
}, {
key: 'style',
get: function get() {
var _this4 = this;
var size = function size(key) {
if (typeof _this4.state[key] === 'undefined' || _this4.state[key] === 'auto') return 'auto';else if (/px$/.test(_this4.state[key].toString())) return _this4.state[key].toString();else if (/%$/.test(_this4.state[key].toString())) return _this4.state[key].toString();
return _this4.state[key] + 'px';
};
return {
width: size('width'),
height: size('height')
};
}
}]);
return Resizable;
}(_react.Component);
Resizable.defaultProps = {
onResizeStart: function onResizeStart() {},
onResize: function onResize() {},
onResizeStop: function onResizeStop() {},
enable: {
top: true,
right: true,
bottom: true,
left: true,
topRight: true,
bottomRight: true,
bottomLeft: true,
topLeft: true
},
style: {},
grid: [1, 1],
lockAspectRatio: false
};
exports.default = Resizable;