react-resizable-box
Version:
<p align="center"><img src ="https://github.com/bokuweb/react-resizable-box/blob/master/logo.png?raw=true" /></p>
775 lines (655 loc) • 22.6 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
typeof define === 'function' && define.amd ? define(['react'], factory) :
(global['re-resizable'] = factory(global.React));
}(this, (function (React) { 'use strict';
var React__default = React['default'];
var babelHelpers = {};
var asyncGenerator = function () {
function AwaitValue(value) {
this.value = value;
}
function AsyncGenerator(gen) {
var front, back;
function send(key, arg) {
return new Promise(function (resolve, reject) {
var request = {
key: key,
arg: arg,
resolve: resolve,
reject: reject,
next: null
};
if (back) {
back = back.next = request;
} else {
front = back = request;
resume(key, arg);
}
});
}
function resume(key, arg) {
try {
var result = gen[key](arg);
var value = result.value;
if (value instanceof AwaitValue) {
Promise.resolve(value.value).then(function (arg) {
resume("next", arg);
}, function (arg) {
resume("throw", arg);
});
} else {
settle(result.done ? "return" : "normal", result.value);
}
} catch (err) {
settle("throw", err);
}
}
function settle(type, value) {
switch (type) {
case "return":
front.resolve({
value: value,
done: true
});
break;
case "throw":
front.reject(value);
break;
default:
front.resolve({
value: value,
done: false
});
break;
}
front = front.next;
if (front) {
resume(front.key, front.arg);
} else {
back = null;
}
}
this._invoke = send;
if (typeof gen.return !== "function") {
this.return = undefined;
}
}
if (typeof Symbol === "function" && Symbol.asyncIterator) {
AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
return this;
};
}
AsyncGenerator.prototype.next = function (arg) {
return this._invoke("next", arg);
};
AsyncGenerator.prototype.throw = function (arg) {
return this._invoke("throw", arg);
};
AsyncGenerator.prototype.return = function (arg) {
return this._invoke("return", arg);
};
return {
wrap: function (fn) {
return function () {
return new AsyncGenerator(fn.apply(this, arguments));
};
},
await: function (value) {
return new AwaitValue(value);
}
};
}();
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
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 _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 inherits = function (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;
};
var possibleConstructorReturn = function (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;
};
babelHelpers;
var styles = {
base: {
position: 'absolute'
},
top: {
width: '100%',
height: '10px',
top: '-5px',
left: '0px',
cursor: 'row-resize'
},
right: {
width: '10px',
height: '100%',
top: '0px',
right: '-5px',
cursor: 'col-resize'
},
bottom: {
width: '100%',
height: '10px',
bottom: '-5px',
left: '0px',
cursor: 'row-resize'
},
left: {
width: '10px',
height: '100%',
top: '0px',
left: '-5px',
cursor: 'col-resize'
},
topRight: {
width: '20px',
height: '20px',
position: 'absolute',
right: '-10px',
top: '-10px',
cursor: 'ne-resize'
},
bottomRight: {
width: '20px',
height: '20px',
position: 'absolute',
right: '-10px',
bottom: '-10px',
cursor: 'se-resize'
},
bottomLeft: {
width: '20px',
height: '20px',
position: 'absolute',
left: '-10px',
bottom: '-10px',
cursor: 'sw-resize'
},
topLeft: {
width: '20px',
height: '20px',
position: 'absolute',
left: '-10px',
top: '-10px',
cursor: 'nw-resize'
}
};
var Resizer = (function (props) {
return React.createElement('div', {
className: props.className,
style: _extends({}, styles.base, styles[props.direction], props.replaceStyles || {}),
onMouseDown: function onMouseDown(e) {
props.onResizeStart(e, props.direction);
},
onTouchStart: function onTouchStart(e) {
props.onResizeStart(e, props.direction);
}
});
});
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 baseSizeId = 0;
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);
_this.baseSizeId = '__resizable' + baseSizeId;
baseSizeId += 1;
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: 'getParentSize',
value: function getParentSize() {
var base = document.getElementById(this.baseSizeId);
if (!base) return { width: window.innerWidth, height: window.innerHeight };
return {
width: base.offsetWidth,
height: base.offsetHeight
};
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
var size = this.size;
// const debounced = debounce(() => {
// this.setState(this.style);
// }, 0);
// const ro = new ResizeObserver(debounced);
// ro.observe(this.parentNode);
// 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
});
var element = document.createElement('div');
element.id = this.baseSizeId;
element.style.width = '100%';
element.style.height = '100%';
element.style.position = 'relative';
element.style.left = '-99999px';
var parent = this.parentNode;
if (!(parent instanceof HTMLElement)) return;
parent.appendChild(element);
}
}, {
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);
var parent = this.parentNode;
var base = document.getElementById(this.baseSizeId);
if (!base) return;
if (!(parent instanceof HTMLElement)) return;
parent.removeChild(base);
}
}
}, {
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 lockAspectRatio = this.props.lockAspectRatio;
var _props = this.props,
maxWidth = _props.maxWidth,
maxHeight = _props.maxHeight,
minWidth = _props.minWidth,
minHeight = _props.minHeight;
// TODO: refactor
var parentSize = this.getParentSize();
if (maxWidth && typeof maxWidth === 'string' && maxWidth.endsWith('%')) {
var _ratio = Number(maxWidth.replace('%', '')) / 100;
maxWidth = parentSize.width * _ratio;
}
if (maxHeight && typeof maxHeight === 'string' && maxHeight.endsWith('%')) {
var _ratio2 = Number(maxHeight.replace('%', '')) / 100;
maxHeight = parentSize.height * _ratio2;
}
if (minWidth && typeof minWidth === 'string' && minWidth.endsWith('%')) {
var _ratio3 = Number(minWidth.replace('%', '')) / 100;
minWidth = parentSize.width * _ratio3;
}
if (minHeight && typeof minHeight === 'string' && minHeight.endsWith('%')) {
var _ratio4 = Number(minHeight.replace('%', '')) / 100;
minHeight = parentSize.height * _ratio4;
}
maxWidth = typeof maxWidth === 'undefined' ? undefined : Number(maxWidth);
maxHeight = typeof maxHeight === 'undefined' ? undefined : Number(maxHeight);
minWidth = typeof minWidth === 'undefined' ? undefined : Number(minWidth);
minHeight = typeof minHeight === 'undefined' ? undefined : Number(minHeight);
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.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]);
}
var delta = {
width: newWidth - original.width,
height: newHeight - original.height
};
if (width && typeof width === 'string' && width.endsWith('%')) {
var percent = newWidth / parentSize.width * 100;
newWidth = percent + '%';
}
if (height && typeof height === 'string' && height.endsWith('%')) {
var _percent = newHeight / parentSize.height * 100;
newHeight = _percent + '%';
}
this.setState({
width: width !== 'auto' || typeof this.props.width === 'undefined' ? newWidth : 'auto',
height: height !== 'auto' || typeof this.props.height === 'undefined' ? newHeight : 'auto'
});
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: 'updateSize',
value: function updateSize(size) {
this.setState({ width: size.width, height: size.height });
}
}, {
key: 'renderResizer',
value: function renderResizer() {
var _this2 = this;
var _props2 = this.props,
enable = _props2.enable,
handleStyles = _props2.handleStyles,
handleClasses = _props2.handleClasses,
handleWrapperStyle = _props2.handleWrapperStyle,
handleWrapperClass = _props2.handleWrapperClass;
if (!enable) return null;
var resizers = Object.keys(enable).map(function (dir) {
if (enable[dir] !== false) {
return React__default.createElement(Resizer, {
key: dir,
direction: dir,
onResizeStart: _this2.onResizeStart,
replaceStyles: handleStyles && handleStyles[dir],
className: handleClasses && handleClasses[dir]
});
}
return null;
});
// #93 Wrap the resize box in span (will not break 100% width/height)
return React__default.createElement(
'span',
{
className: handleWrapperClass,
style: handleWrapperStyle
},
resizers
);
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
var userSelect = this.state.isResizing ? userSelectNone : userSelectAuto;
var _props3 = this.props,
style = _props3.style,
className = _props3.className;
return React__default.createElement(
'div',
_extends({
ref: function ref(c) {
_this3.resizable = c;
},
style: _extends({
position: 'relative'
}, userSelect, style, this.style, {
maxWidth: this.props.maxWidth,
maxHeight: this.props.maxHeight,
minWidth: this.props.minWidth,
minHeight: this.props.minHeight,
boxSizing: 'border-box'
}),
className: className
}, this.props.extendsProps),
this.props.children,
this.renderResizer()
);
}
}, {
key: 'parentNode',
get: function get$$1() {
return this.props.parentNode || this.resizable.parentNode;
}
}, {
key: 'size',
get: function get$$1() {
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 };
}
// TODO: rename
}, {
key: 'style',
get: function get$$1() {
var _this4 = this;
var size = function size(key) {
if (typeof _this4.state[key] === 'undefined' || _this4.state[key] === 'auto') return 'auto';
if (_this4.props[key] && _this4.props[key].toString().endsWith('%')) {
if (_this4.state[key].toString().endsWith('%')) return _this4.state[key].toString();
var parentSize = _this4.getParentSize();
var value = Number(_this4.state[key].toString().replace('px', ''));
var percent = value / parentSize[key] * 100;
return percent + '%';
}
if (_this4.state[key].toString().endsWith('px')) return _this4.state[key].toString();
if (_this4.state[key].toString().endsWith('%')) 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
};
return Resizable;
})));
//# sourceMappingURL=re-resizable.umd.js.map