react-grid-layout
Advanced tools
Comparing version
@@ -1,349 +0,401 @@ | ||
'use strict'; | ||
var React = require('react'); | ||
var cloneWithProps = require('react/lib/cloneWithProps'); | ||
var utils = require('./utils'); | ||
var Draggable = require('react-draggable'); | ||
var Resizable = require('react-resizable').Resizable; | ||
var PureDeepRenderMixin = require('./mixins/PureDeepRenderMixin'); | ||
/** | ||
* An individual item within a ReactGridLayout. | ||
*/ | ||
var GridItem = React.createClass({ | ||
displayName: 'GridItem', | ||
'use strict'; | ||
mixins: [PureDeepRenderMixin], | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
propTypes: { | ||
// Children must be only a single element | ||
children: React.PropTypes.element, | ||
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; }; })(); | ||
// General grid attributes | ||
cols: React.PropTypes.number.isRequired, | ||
containerWidth: React.PropTypes.number.isRequired, | ||
rowHeight: React.PropTypes.number.isRequired, | ||
margin: React.PropTypes.array.isRequired, | ||
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | ||
// These are all in grid units | ||
x: React.PropTypes.number.isRequired, | ||
y: React.PropTypes.number.isRequired, | ||
w: React.PropTypes.number.isRequired, | ||
h: React.PropTypes.number.isRequired, | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
// All optional | ||
minW: function minW(props, propName, componentName) { | ||
React.PropTypes.number.apply(this, arguments); | ||
if (props.minW > props.w || props.minW > props.maxW) constraintError('minW', props); | ||
}, | ||
maxW: function maxW(props, propName, componentName) { | ||
React.PropTypes.number.apply(this, arguments); | ||
if (props.maxW < props.w || props.maxW < props.minW) constraintError('maxW', props); | ||
}, | ||
minH: function minH(props, propName, componentName) { | ||
React.PropTypes.number.apply(this, arguments); | ||
if (props.minH > props.h || props.minH > props.maxH) constraintError('minH', props); | ||
}, | ||
maxH: function maxH(props, propName, componentName) { | ||
React.PropTypes.number.apply(this, arguments); | ||
if (props.maxH < props.h || props.maxH < props.minH) constraintError('maxH', props); | ||
}, | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
// ID is nice to have for callbacks | ||
i: React.PropTypes.string.isRequired, | ||
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; } | ||
// If true, item will be repositioned when x/y/w/h change | ||
moveOnStartChange: React.PropTypes.bool, | ||
var _react = require('react'); | ||
// Functions | ||
onDragStop: React.PropTypes.func, | ||
onDragStart: React.PropTypes.func, | ||
onDrag: React.PropTypes.func, | ||
onResizeStop: React.PropTypes.func, | ||
onResizeStart: React.PropTypes.func, | ||
onResize: React.PropTypes.func, | ||
var _react2 = _interopRequireDefault(_react); | ||
// Flags | ||
isDraggable: React.PropTypes.bool, | ||
isResizable: React.PropTypes.bool, | ||
// Use CSS transforms instead of top/left | ||
useCSSTransforms: React.PropTypes.bool, | ||
isPlaceholder: React.PropTypes.bool, | ||
var _utils = require('./utils'); | ||
// Others | ||
className: React.PropTypes.string, | ||
// Selector for draggable handle | ||
handle: React.PropTypes.string, | ||
// Selector for draggable cancel (see react-draggable) | ||
cancel: React.PropTypes.string | ||
}, | ||
var _reactDraggable = require('react-draggable'); | ||
getDefaultProps: function getDefaultProps() { | ||
return { | ||
isDraggable: true, | ||
isResizable: true, | ||
useCSSTransforms: true, | ||
className: '', | ||
cancel: '', | ||
minH: 1, | ||
minW: 1, | ||
maxH: Infinity, | ||
maxW: Infinity | ||
}; | ||
}, | ||
var _reactDraggable2 = _interopRequireDefault(_reactDraggable); | ||
getInitialState: function getInitialState() { | ||
return { | ||
resizing: false, | ||
var _reactResizable = require('react-resizable'); | ||
var _objectAssign = require('object-assign'); | ||
var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
var GridItem = (function (_Component) { | ||
_inherits(GridItem, _Component); | ||
function GridItem() { | ||
var _this = this, | ||
_arguments2 = arguments; | ||
_classCallCheck(this, GridItem); | ||
_get(Object.getPrototypeOf(GridItem.prototype), 'constructor', this).apply(this, arguments); | ||
this.state = { | ||
resizing: null, | ||
className: '' | ||
}; | ||
}, | ||
/** | ||
* Return position on the page given an x, y, w, h. | ||
* left, top, width, height are all in pixels. | ||
* @param {Number} x X coordinate in grid units. | ||
* @param {Number} y Y coordinate in grid units. | ||
* @param {Number} w W coordinate in grid units. | ||
* @param {Number} h H coordinate in grid units. | ||
* @return {Object} Object containing coords. | ||
*/ | ||
calcPosition: function calcPosition(x, y, w, h) { | ||
var p = this.props; | ||
var width = p.containerWidth - p.margin[0]; | ||
var out = { | ||
left: width * (x / p.cols) + p.margin[0], | ||
top: p.rowHeight * y + p.margin[1], | ||
width: width * (w / p.cols) - p.margin[0], | ||
height: h * p.rowHeight - p.margin[1] | ||
this.onDragHandler = function (handlerName) { | ||
return function (e, _ref) { | ||
var element = _ref.element; | ||
var position = _ref.position; | ||
return (function () { | ||
if (!this.props[handlerName]) return; | ||
// Get new XY | ||
var _calcXY = this.calcXY(position); | ||
var x = _calcXY.x; | ||
var y = _calcXY.y; | ||
// Cap x at numCols | ||
x = Math.min(x, this.props.cols - this.props.w); | ||
this.props[handlerName](this.props.i, x, y, { e: e, element: element, position: position }); | ||
}).apply(_this, _arguments2); | ||
}; | ||
}; | ||
return out; | ||
}, | ||
/** | ||
* Translate x and y coordinates from pixels to grid units. | ||
* @param {Number} options.left Left offset in pixels. | ||
* @param {Number} options.top Top offset in pixels. | ||
* @return {Object} x and y in grid units. | ||
*/ | ||
calcXY: function calcXY(_ref) { | ||
var left = _ref.left; | ||
var top = _ref.top; | ||
this.onResizeHandler = function (handlerName) { | ||
return function (e, _ref2) { | ||
var element = _ref2.element; | ||
var size = _ref2.size; | ||
return (function () { | ||
if (!this.props[handlerName]) return; | ||
left = left - this.props.margin[0]; | ||
top = top - this.props.margin[1]; | ||
// This is intentional; because so much of the logic on moving boxes up/down relies | ||
// on an exact y position, we only round the x, not the y. | ||
var x = Math.round(left / this.props.containerWidth * this.props.cols); | ||
var y = Math.floor(top / this.props.rowHeight); | ||
x = Math.max(Math.min(x, this.props.cols), 0); | ||
y = Math.max(y, 0); | ||
return { x: x, y: y }; | ||
}, | ||
// Get new XY | ||
/** | ||
* Given a height and width in pixel values, calculate grid units. | ||
* @param {Number} options.height Height in pixels. | ||
* @param {Number} options.width Width in pixels. | ||
* @return {Object} w, h as grid units. | ||
*/ | ||
calcWH: function calcWH(_ref2) { | ||
var height = _ref2.height; | ||
var width = _ref2.width; | ||
var _calcWH = this.calcWH(size); | ||
width = width + this.props.margin[0]; | ||
height = height + this.props.margin[1]; | ||
var w = Math.round(width / this.props.containerWidth * this.props.cols); | ||
var h = Math.round(height / this.props.rowHeight); | ||
w = Math.max(Math.min(w, this.props.cols - this.props.x), 0); | ||
h = Math.max(h, 0); | ||
return { w: w, h: h }; | ||
}, | ||
var w = _calcWH.w; | ||
var h = _calcWH.h; | ||
/** | ||
* This is where we set the grid item's absolute placement. It gets a little tricky because we want to do it | ||
* well when server rendering, and the only way to do that properly is to use percentage width/left because | ||
* we don't know exactly what the browser viewport is. | ||
* Unfortunately, CSS Transforms, which are great for performance, break in this instance because a percentage | ||
* left is relative to the item itself, not its container! So we cannot use them on the server rendering pass. | ||
* | ||
* @param {Object} pos Position object with width, height, left, top. | ||
* @return {Object} Style object. | ||
*/ | ||
createStyle: function createStyle(pos) { | ||
var style = { | ||
width: pos.width + 'px', | ||
height: pos.height + 'px', | ||
left: pos.left + 'px', | ||
top: pos.top + 'px', | ||
position: 'absolute' | ||
// Cap w at numCols | ||
w = Math.min(w, this.props.cols - this.props.x); | ||
// Ensure w is at least 1 | ||
w = Math.max(w, 1); | ||
// Min/max capping | ||
w = Math.max(Math.min(w, this.props.maxW), this.props.minW); | ||
h = Math.max(Math.min(h, this.props.maxH), this.props.minH); | ||
this.setState({ resizing: handlerName === 'onResizeStop' ? null : size }); | ||
this.props[handlerName](this.props.i, w, h, { e: e, element: element, size: size }); | ||
}).apply(_this, _arguments2); | ||
}; | ||
}; | ||
} | ||
// This is used for server rendering. | ||
if (this.props.usePercentages) { | ||
pos.left = utils.perc(pos.left / this.props.containerWidth); | ||
style.left = pos.left; | ||
style.width = utils.perc(pos.width / this.props.containerWidth); | ||
_createClass(GridItem, [{ | ||
key: 'calcPosition', | ||
/** | ||
* Return position on the page given an x, y, w, h. | ||
* left, top, width, height are all in pixels. | ||
* @param {Number} x X coordinate in grid units. | ||
* @param {Number} y Y coordinate in grid units. | ||
* @param {Number} w W coordinate in grid units. | ||
* @param {Number} h H coordinate in grid units. | ||
* @return {Object} Object containing coords. | ||
*/ | ||
value: function calcPosition(x, y, w, h) { | ||
var p = this.props; | ||
var width = p.containerWidth - p.margin[0]; | ||
var out = { | ||
left: width * (x / p.cols) + p.margin[0], | ||
top: p.rowHeight * y + p.margin[1], | ||
width: width * (w / p.cols) - p.margin[0], | ||
height: h * p.rowHeight - p.margin[1] | ||
}; | ||
return out; | ||
} | ||
// CSS Transforms support | ||
if (this.props.useCSSTransforms) { | ||
utils.setTransform(style, [pos.left, pos.top]); | ||
delete style.left; | ||
delete style.top; | ||
/** | ||
* Translate x and y coordinates from pixels to grid units. | ||
* @param {Number} options.left Left offset in pixels. | ||
* @param {Number} options.top Top offset in pixels. | ||
* @return {Object} x and y in grid units. | ||
*/ | ||
}, { | ||
key: 'calcXY', | ||
value: function calcXY(_ref3) { | ||
var left = _ref3.left; | ||
var top = _ref3.top; | ||
return (function () { | ||
left = left - this.props.margin[0]; | ||
top = top - this.props.margin[1]; | ||
// This is intentional; because so much of the logic on moving boxes up/down relies | ||
// on an exact y position, we only round the x, not the y. | ||
var x = Math.round(left / this.props.containerWidth * this.props.cols); | ||
var y = Math.floor(top / this.props.rowHeight); | ||
x = Math.max(Math.min(x, this.props.cols), 0); | ||
y = Math.max(y, 0); | ||
return { x: x, y: y }; | ||
}).apply(this, arguments); | ||
} | ||
return style; | ||
}, | ||
/** | ||
* Given a height and width in pixel values, calculate grid units. | ||
* @param {Number} options.height Height in pixels. | ||
* @param {Number} options.width Width in pixels. | ||
* @return {Object} w, h as grid units. | ||
*/ | ||
}, { | ||
key: 'calcWH', | ||
value: function calcWH(_ref4) { | ||
var height = _ref4.height; | ||
var width = _ref4.width; | ||
return (function () { | ||
width = width + this.props.margin[0]; | ||
height = height + this.props.margin[1]; | ||
var w = Math.round(width / this.props.containerWidth * this.props.cols); | ||
var h = Math.round(height / this.props.rowHeight); | ||
w = Math.max(Math.min(w, this.props.cols - this.props.x), 0); | ||
h = Math.max(h, 0); | ||
return { w: w, h: h }; | ||
}).apply(this, arguments); | ||
} | ||
/** | ||
* Mix a Draggable instance into a child. | ||
* @param {Element} child Child element. | ||
* @param {Object} position Position object (pixel values) | ||
* @return {Element} Child wrapped in Draggable. | ||
*/ | ||
mixinDraggable: function mixinDraggable(child, position) { | ||
return React.createElement( | ||
Draggable, | ||
{ | ||
start: { x: position.left, y: position.top }, | ||
moveOnStartChange: this.props.moveOnStartChange, | ||
onStop: this.onDragHandler('onDragStop'), | ||
onStart: this.onDragHandler('onDragStart'), | ||
onDrag: this.onDragHandler('onDrag'), | ||
handle: this.props.handle, | ||
cancel: ".react-resizable-handle " + this.props.cancel, | ||
useCSSTransforms: this.props.useCSSTransforms | ||
}, | ||
child | ||
); | ||
}, | ||
/** | ||
* This is where we set the grid item's absolute placement. It gets a little tricky because we want to do it | ||
* well when server rendering, and the only way to do that properly is to use percentage width/left because | ||
* we don't know exactly what the browser viewport is. | ||
* Unfortunately, CSS Transforms, which are great for performance, break in this instance because a percentage | ||
* left is relative to the item itself, not its container! So we cannot use them on the server rendering pass. | ||
* | ||
* @param {Object} pos Position object with width, height, left, top. | ||
* @return {Object} Style object. | ||
*/ | ||
}, { | ||
key: 'createStyle', | ||
value: function createStyle(pos) { | ||
var style = { | ||
width: pos.width + 'px', | ||
height: pos.height + 'px', | ||
left: pos.left + 'px', | ||
top: pos.top + 'px', | ||
position: 'absolute' | ||
}; | ||
/** | ||
* Mix a Resizable instance into a child. | ||
* @param {Element} child Child element. | ||
* @param {Object} position Position object (pixel values) | ||
* @return {Element} Child wrapped in Resizable. | ||
*/ | ||
mixinResizable: function mixinResizable(child, position) { | ||
var p = this.props; | ||
// This is the max possible width - doesn't go to infinity because of the width of the window | ||
var maxWidth = this.calcPosition(0, 0, p.cols - p.x, 0).width; | ||
// This is used for server rendering. | ||
if (this.props.usePercentages) { | ||
style.left = (0, _utils.perc)(pos.left / this.props.containerWidth); | ||
style.width = (0, _utils.perc)(pos.width / this.props.containerWidth); | ||
} | ||
// Calculate min/max constraints using our min & maxes | ||
var mins = this.calcPosition(0, 0, p.minW, p.minH); | ||
var maxes = this.calcPosition(0, 0, p.maxW, p.maxH); | ||
var minConstraints = [mins.width, mins.height]; | ||
var maxConstraints = [Math.min(maxes.width, maxWidth), Math.min(maxes.height, Infinity)]; | ||
return React.createElement( | ||
Resizable, | ||
{ | ||
width: position.width, | ||
height: position.height, | ||
minConstraints: minConstraints, | ||
maxConstraints: maxConstraints, | ||
onResizeStop: this.onResizeHandler('onResizeStop'), | ||
onResizeStart: this.onResizeHandler('onResizeStart'), | ||
onResize: this.onResizeHandler('onResize') | ||
}, | ||
child | ||
); | ||
}, | ||
// CSS Transforms support | ||
if (this.props.useCSSTransforms) { | ||
(0, _utils.setTransform)(style, [pos.left, pos.top]); | ||
style.left = null; | ||
style.top = null; | ||
} | ||
/** | ||
* Wrapper around drag events to provide more useful data. | ||
* All drag events call the function with the given handler name, | ||
* with the signature (index, x, y). | ||
* | ||
* @param {String} handlerName Handler name to wrap. | ||
* @return {Function} Handler function. | ||
*/ | ||
onDragHandler: function onDragHandler(handlerName) { | ||
var me = this; | ||
return function (e, _ref3) { | ||
var element = _ref3.element; | ||
var position = _ref3.position; | ||
return style; | ||
} | ||
if (!me.props[handlerName]) return; | ||
// Get new XY | ||
/** | ||
* Mix a Draggable instance into a child. | ||
* @param {Element} child Child element. | ||
* @param {Object} position Position object (pixel values) | ||
* @return {Element} Child wrapped in Draggable. | ||
*/ | ||
}, { | ||
key: 'mixinDraggable', | ||
value: function mixinDraggable(child, position) { | ||
var start = typeof position.left === "string" ? undefined : { x: position.left, y: position.top }; | ||
return _react2['default'].createElement( | ||
_reactDraggable2['default'], | ||
{ | ||
start: start, | ||
moveOnStartChange: this.props.moveOnStartChange, | ||
onStop: this.onDragHandler('onDragStop'), | ||
onStart: this.onDragHandler('onDragStart'), | ||
onDrag: this.onDragHandler('onDrag'), | ||
handle: this.props.handle, | ||
cancel: ".react-resizable-handle " + this.props.cancel, | ||
useCSSTransforms: this.props.useCSSTransforms | ||
}, | ||
_react2['default'].createElement( | ||
'span', | ||
null, | ||
child | ||
) | ||
); | ||
} | ||
var _me$calcXY = me.calcXY(position); | ||
/** | ||
* Mix a Resizable instance into a child. | ||
* @param {Element} child Child element. | ||
* @param {Object} position Position object (pixel values) | ||
* @return {Element} Child wrapped in Resizable. | ||
*/ | ||
}, { | ||
key: 'mixinResizable', | ||
value: function mixinResizable(child, position) { | ||
var p = this.props; | ||
// This is the max possible width - doesn't go to infinity because of the width of the window | ||
var maxWidth = this.calcPosition(0, 0, p.cols - p.x, 0).width; | ||
var x = _me$calcXY.x; | ||
var y = _me$calcXY.y; | ||
// Calculate min/max constraints using our min & maxes | ||
var mins = this.calcPosition(0, 0, p.minW, p.minH); | ||
var maxes = this.calcPosition(0, 0, p.maxW, p.maxH); | ||
var minConstraints = [mins.width, mins.height]; | ||
var maxConstraints = [Math.min(maxes.width, maxWidth), Math.min(maxes.height, Infinity)]; | ||
return _react2['default'].createElement( | ||
_reactResizable.Resizable, | ||
{ | ||
width: position.width, | ||
height: position.height, | ||
minConstraints: minConstraints, | ||
maxConstraints: maxConstraints, | ||
onResizeStop: this.onResizeHandler('onResizeStop'), | ||
onResizeStart: this.onResizeHandler('onResizeStart'), | ||
onResize: this.onResizeHandler('onResize') | ||
}, | ||
child | ||
); | ||
} | ||
// Cap x at numCols | ||
x = Math.min(x, me.props.cols - me.props.w); | ||
/** | ||
* Wrapper around drag events to provide more useful data. | ||
* All drag events call the function with the given handler name, | ||
* with the signature (index, x, y). | ||
* | ||
* @param {String} handlerName Handler name to wrap. | ||
* @return {Function} Handler function. | ||
*/ | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var p = this.props, | ||
pos = this.calcPosition(p.x, p.y, p.w, p.h); | ||
if (this.state.resizing) { | ||
pos.width = this.state.resizing.width; | ||
pos.height = this.state.resizing.height; | ||
} | ||
me.props[handlerName](me.props.i, x, y, { e: e, element: element, position: position }); | ||
}; | ||
}, | ||
// Create the child element. We clone the existing element but modify its className and style. | ||
var child = _react2['default'].cloneElement(this.props.children, { | ||
// Munge a classname. Use passed in classnames and resizing. | ||
// React with merge the classNames. | ||
className: ['react-grid-item', this.props.className, this.props.isDraggable ? '' : 'static', this.state.resizing ? 'resizing' : '', this.props.useCSSTransforms ? 'cssTransforms' : ''].join(' '), | ||
// We can set the width and height on the child, but unfortunately we can't set the position. | ||
style: (0, _objectAssign2['default'])({}, this.props.style, this.createStyle(pos)) | ||
}); | ||
/** | ||
* Wrapper around drag events to provide more useful data. | ||
* All drag events call the function with the given handler name, | ||
* with the signature (index, x, y). | ||
* | ||
* @param {String} handlerName Handler name to wrap. | ||
* @return {Function} Handler function. | ||
*/ | ||
onResizeHandler: function onResizeHandler(handlerName) { | ||
var me = this; | ||
return function (e, _ref4) { | ||
var element = _ref4.element; | ||
var size = _ref4.size; | ||
// Resizable support. This is usually on but the user can toggle it off. | ||
if (this.props.isResizable) { | ||
child = this.mixinResizable(child, pos); | ||
} | ||
if (!me.props[handlerName]) return; | ||
// Draggable support. This is always on, except for with placeholders. | ||
if (this.props.isDraggable) { | ||
child = this.mixinDraggable(child, pos); | ||
} | ||
// Get new XY | ||
return child; | ||
} | ||
}], [{ | ||
key: 'propTypes', | ||
value: { | ||
// Children must be only a single element | ||
children: _react2['default'].PropTypes.element, | ||
var _me$calcWH = me.calcWH(size); | ||
// General grid attributes | ||
cols: _react2['default'].PropTypes.number.isRequired, | ||
containerWidth: _react2['default'].PropTypes.number.isRequired, | ||
rowHeight: _react2['default'].PropTypes.number.isRequired, | ||
margin: _react2['default'].PropTypes.array.isRequired, | ||
var w = _me$calcWH.w; | ||
var h = _me$calcWH.h; | ||
// These are all in grid units | ||
x: _react2['default'].PropTypes.number.isRequired, | ||
y: _react2['default'].PropTypes.number.isRequired, | ||
w: _react2['default'].PropTypes.number.isRequired, | ||
h: _react2['default'].PropTypes.number.isRequired, | ||
// Cap w at numCols | ||
w = Math.min(w, me.props.cols - me.props.x); | ||
// Ensure w is at least 1 | ||
w = Math.max(w, 1); | ||
// All optional | ||
minW: function minW(props, propName, _componentName) { | ||
_react2['default'].PropTypes.number.apply(this, arguments); | ||
if (props.minW > props.w || props.minW > props.maxW) constraintError('minW', props); | ||
}, | ||
maxW: function maxW(props, propName, _componentName) { | ||
_react2['default'].PropTypes.number.apply(this, arguments); | ||
if (props.maxW < props.w || props.maxW < props.minW) constraintError('maxW', props); | ||
}, | ||
minH: function minH(props, propName, _componentName) { | ||
_react2['default'].PropTypes.number.apply(this, arguments); | ||
if (props.minH > props.h || props.minH > props.maxH) constraintError('minH', props); | ||
}, | ||
maxH: function maxH(props, propName, _componentName) { | ||
_react2['default'].PropTypes.number.apply(this, arguments); | ||
if (props.maxH < props.h || props.maxH < props.minH) constraintError('maxH', props); | ||
}, | ||
// Min/max capping | ||
w = Math.max(Math.min(w, me.props.maxW), me.props.minW); | ||
h = Math.max(Math.min(h, me.props.maxH), me.props.minH); | ||
// ID is nice to have for callbacks | ||
i: _react2['default'].PropTypes.number.isRequired, | ||
me.setState({ resizing: handlerName === 'onResizeStop' ? null : size }); | ||
// If true, item will be repositioned when x/y/w/h change | ||
moveOnStartChange: _react2['default'].PropTypes.bool, | ||
me.props[handlerName](me.props.i, w, h, { e: e, element: element, size: size }); | ||
}; | ||
}, | ||
// Functions | ||
onDragStop: _react2['default'].PropTypes.func, | ||
onDragStart: _react2['default'].PropTypes.func, | ||
onDrag: _react2['default'].PropTypes.func, | ||
onResizeStop: _react2['default'].PropTypes.func, | ||
onResizeStart: _react2['default'].PropTypes.func, | ||
onResize: _react2['default'].PropTypes.func, | ||
render: function render() { | ||
var p = this.props, | ||
pos = this.calcPosition(p.x, p.y, p.w, p.h); | ||
if (this.state.resizing) { | ||
pos.width = this.state.resizing.width; | ||
pos.height = this.state.resizing.height; | ||
} | ||
// Flags | ||
isDraggable: _react2['default'].PropTypes.bool, | ||
isResizable: _react2['default'].PropTypes.bool, | ||
// Create the child element. We clone the existing element but modify its className and style. | ||
var child = cloneWithProps(this.props.children, { | ||
// Munge a classname. Use passed in classnames and resizing. | ||
// React with merge the classNames. | ||
className: ['react-grid-item', this.props.className, this.state.resizing ? 'resizing' : '', this.props.useCSSTransforms ? 'cssTransforms' : ''].join(' '), | ||
// We can set the width and height on the child, but unfortunately we can't set the position. | ||
style: this.createStyle(pos) | ||
}); | ||
// Use CSS transforms instead of top/left | ||
useCSSTransforms: _react2['default'].PropTypes.bool, | ||
isPlaceholder: _react2['default'].PropTypes.bool, | ||
// Resizable support. This is usually on but the user can toggle it off. | ||
if (this.props.isResizable) { | ||
child = this.mixinResizable(child, pos); | ||
} | ||
// Others | ||
className: _react2['default'].PropTypes.string, | ||
// Selector for draggable handle | ||
handle: _react2['default'].PropTypes.string, | ||
// Selector for draggable cancel (see react-draggable) | ||
cancel: _react2['default'].PropTypes.string | ||
}, | ||
enumerable: true | ||
}, { | ||
key: 'defaultProps', | ||
value: { | ||
isDraggable: true, | ||
isResizable: true, | ||
useCSSTransforms: true, | ||
className: '', | ||
cancel: '', | ||
minH: 1, | ||
minW: 1, | ||
maxH: Infinity, | ||
maxW: Infinity | ||
}, | ||
enumerable: true | ||
}]); | ||
// Draggable support. This is always on, except for with placeholders. | ||
if (this.props.isDraggable) { | ||
child = this.mixinDraggable(child, pos); | ||
} | ||
return GridItem; | ||
})(_react.Component); | ||
return child; | ||
} | ||
}); | ||
exports['default'] = GridItem; | ||
@@ -354,3 +406,11 @@ function constraintError(name, props) { | ||
} | ||
module.exports = exports['default']; | ||
module.exports = GridItem; | ||
/** | ||
* Wrapper around drag events to provide more useful data. | ||
* All drag events call the function with the given handler name, | ||
* with the signature (index, x, y). | ||
* | ||
* @param {String} handlerName Handler name to wrap. | ||
* @return {Function} Handler function. | ||
*/ |
'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 _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
var React = require('react'); | ||
var GridItem = require('./GridItem'); | ||
var utils = require('./utils'); | ||
var PureDeepRenderMixin = require('./mixins/PureDeepRenderMixin'); | ||
var WidthListeningMixin = require('./mixins/WidthListeningMixin'); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
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; } | ||
var _react = require('react'); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _utils = require('./utils'); | ||
var _GridItem = require('./GridItem'); | ||
var _GridItem2 = _interopRequireDefault(_GridItem); | ||
var _componentsListensToWidth = require('./components/ListensToWidth'); | ||
var _componentsListensToWidth2 = _interopRequireDefault(_componentsListensToWidth); | ||
// Types | ||
// End Types | ||
/** | ||
* A reactive, fluid grid layout with draggable, resizable components. | ||
*/ | ||
var ReactGridLayout = React.createClass({ | ||
displayName: 'ReactGridLayout', | ||
mixins: [PureDeepRenderMixin, WidthListeningMixin], | ||
var ReactGridLayout = (function (_React$Component) { | ||
_inherits(ReactGridLayout, _React$Component); | ||
propTypes: { | ||
// | ||
// Basic props | ||
// | ||
function ReactGridLayout() { | ||
var _this = this; | ||
// If true, the container height swells and contracts to fit contents | ||
autoSize: React.PropTypes.bool, | ||
// # of cols. | ||
cols: React.PropTypes.number, | ||
_classCallCheck(this, ReactGridLayout); | ||
// A selector that will not be draggable. | ||
draggableCancel: React.PropTypes.string, | ||
// A selector for the draggable handler | ||
draggableHandle: React.PropTypes.string, | ||
_get(Object.getPrototypeOf(ReactGridLayout.prototype), 'constructor', this).apply(this, arguments); | ||
// If true, the layout will compact vertically | ||
verticalCompact: React.PropTypes.bool, | ||
this.state = { | ||
activeDrag: null, | ||
isMounted: false, | ||
layout: (0, _utils.synchronizeLayoutWithChildren)(this.props.layout, this.props.children, this.props.cols, this.props.verticalCompact), | ||
width: this.props.initialWidth, | ||
oldDragItem: null, | ||
oldResizeItem: null | ||
}; | ||
// layout is an array of object with the format: | ||
// {x: Number, y: Number, w: Number, h: Number} | ||
layout: function layout(props, propName, componentName) { | ||
var layout = props.layout; | ||
// I hope you're setting the _grid property on the grid items | ||
if (layout === undefined) return; | ||
utils.validateLayout(layout, 'layout'); | ||
}, | ||
this.onWidthChange = function (width) { | ||
_this.setState({ width: width }); | ||
}; | ||
layouts: function layouts(props, propName, componentName) { | ||
if (props.layouts) { | ||
throw new Error("ReactGridLayout does not use `layouts`: Use ReactGridLayout.Responsive."); | ||
} | ||
}, | ||
this.onDragStart = function (i, x, y, _ref) { | ||
var e = _ref.e; | ||
var element = _ref.element; | ||
// margin between items [x, y] in px | ||
margin: React.PropTypes.array, | ||
// Rows have a static height, but you can change this based on breakpoints if you like | ||
rowHeight: React.PropTypes.number, | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
if (!l) return; | ||
// | ||
// Flags | ||
// | ||
isDraggable: React.PropTypes.bool, | ||
isResizable: React.PropTypes.bool, | ||
// Use CSS transforms instead of top/left | ||
useCSSTransforms: React.PropTypes.bool, | ||
_this.setState({ oldDragItem: (0, _utils.clone)(l) }); | ||
// | ||
// Callbacks | ||
// | ||
_this.props.onDragStart(layout, l, l, null, e, element); | ||
}; | ||
// Callback so you can save the layout. | ||
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint. | ||
onLayoutChange: React.PropTypes.func, | ||
this.onDrag = function (i, x, y, _ref2) { | ||
var e = _ref2.e; | ||
var element = _ref2.element; | ||
// Calls when drag starts. Callback is of the signature (layout, oldItem, newItem, placeholder, e). | ||
// All callbacks below have the same signature. 'start' and 'stop' callbacks omit the 'placeholder'. | ||
onDragStart: React.PropTypes.func, | ||
// Calls on each drag movement. | ||
onDrag: React.PropTypes.func, | ||
// Calls when drag is complete. | ||
onDragStop: React.PropTypes.func, | ||
//Calls when resize starts. | ||
onResizeStart: React.PropTypes.func, | ||
// Calls when resize movement happens. | ||
onResize: React.PropTypes.func, | ||
// Calls when resize is complete. | ||
onResizeStop: React.PropTypes.func, | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
if (!l) return; | ||
var oldL = _this.state.oldDragItem; | ||
// | ||
// Other validations | ||
// | ||
// Create placeholder (display only) | ||
var placeholder = { | ||
w: l.w, h: l.h, x: l.x, y: l.y, placeholder: true, i: i | ||
}; | ||
// Children must not have duplicate keys. | ||
children: function children(props, propName, componentName) { | ||
React.PropTypes.node.apply(this, arguments); | ||
var children = props[propName]; | ||
// Move the element to the dragged location. | ||
layout = (0, _utils.moveElement)(layout, l, x, y, true /* isUserAction */); | ||
// Check children keys for duplicates. Throw if found. | ||
var keys = {}; | ||
React.Children.forEach(children, function (child, i, list) { | ||
if (keys[child.key]) { | ||
throw new Error("Duplicate child key found! This will cause problems in ReactGridLayout."); | ||
} | ||
keys[child.key] = true; | ||
_this.props.onDrag(layout, oldL, l, placeholder, e, element); | ||
_this.setState({ | ||
layout: (0, _utils.compact)(layout, _this.props.verticalCompact), | ||
activeDrag: placeholder | ||
}); | ||
} | ||
}, | ||
getDefaultProps: function getDefaultProps() { | ||
return { | ||
autoSize: true, | ||
cols: 12, | ||
rowHeight: 150, | ||
layout: [], | ||
margin: [10, 10], | ||
isDraggable: true, | ||
isResizable: true, | ||
useCSSTransforms: true, | ||
verticalCompact: true, | ||
onLayoutChange: function onLayoutChange() {}, | ||
onDragStart: function onDragStart() {}, | ||
onDrag: function onDrag() {}, | ||
onDragStop: function onDragStop() {}, | ||
onResizeStart: function onResizeStart() {}, | ||
onResize: function onResize() {}, | ||
onResizeStop: function onResizeStop() {} | ||
}; | ||
}, | ||
getInitialState: function getInitialState() { | ||
return { | ||
activeDrag: null, | ||
isMounted: false, | ||
layout: utils.synchronizeLayoutWithChildren(this.props.layout, this.props.children, this.props.cols, this.props.verticalCompact), | ||
width: this.props.initialWidth | ||
}; | ||
}, | ||
this.onDragStop = function (i, x, y, _ref3) { | ||
var e = _ref3.e; | ||
var element = _ref3.element; | ||
componentDidMount: function componentDidMount() { | ||
// Call back with layout on mount. This should be done after correcting the layout width | ||
// to ensure we don't rerender with the wrong width. | ||
this.props.onLayoutChange(this.state.layout); | ||
this.setState({ isMounted: true }); | ||
}, | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
if (!l) return; | ||
var oldL = _this.state.oldDragItem; | ||
componentWillReceiveProps: function componentWillReceiveProps(nextProps) { | ||
// This allows you to set the width manually if you like. | ||
// Use manual width changes in combination with `listenToWindowResize: false` | ||
if (nextProps.width !== this.props.width) this.onWidthChange(nextProps.width); | ||
// Move the element here | ||
layout = (0, _utils.moveElement)(layout, l, x, y, true /* isUserAction */); | ||
// If children change, regenerate the layout. | ||
if (nextProps.children.length !== this.props.children.length) { | ||
this.setState({ | ||
layout: utils.synchronizeLayoutWithChildren(this.state.layout, nextProps.children, nextProps.cols, this.props.verticalCompact) | ||
}); | ||
} | ||
_this.props.onDragStop(layout, oldL, l, null, e, element); | ||
// Allow parent to set layout directly. | ||
if (nextProps.layout && JSON.stringify(nextProps.layout) !== JSON.stringify(this.state.layout)) { | ||
this.setState({ | ||
layout: utils.synchronizeLayoutWithChildren(nextProps.layout, nextProps.children, nextProps.cols, this.props.verticalCompact) | ||
// Set state | ||
_this.setState({ | ||
layout: (0, _utils.compact)(layout, _this.props.verticalCompact), | ||
activeDrag: null, | ||
oldDragItem: null | ||
}); | ||
} | ||
}, | ||
}; | ||
componentDidUpdate: function componentDidUpdate(prevProps, prevState) { | ||
// Call back so we can store the layout | ||
// Do it only when a resize/drag is not active, otherwise there are way too many callbacks | ||
if (this.state.layout !== prevState.layout && !this.state.activeDrag) { | ||
this.props.onLayoutChange(this.state.layout, this.state.layouts); | ||
} | ||
}, | ||
this.onResizeStart = function (i, w, h, _ref4) { | ||
var e = _ref4.e; | ||
var element = _ref4.element; | ||
/** | ||
* Calculates a pixel value for the container. | ||
* @return {String} Container height in pixels. | ||
*/ | ||
containerHeight: function containerHeight() { | ||
if (!this.props.autoSize) return; | ||
return utils.bottom(this.state.layout) * this.props.rowHeight + this.props.margin[1] + 'px'; | ||
}, | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
if (!l) return; | ||
/** | ||
* When the width changes, save it to state. This helps with left/width calculations. | ||
*/ | ||
onWidthChange: function onWidthChange(width) { | ||
this.setState({ width: width }); | ||
}, | ||
_this.setState({ oldResizeItem: (0, _utils.clone)(l) }); | ||
/** | ||
* When dragging starts | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ | ||
onDragStart: function onDragStart(i, x, y, _ref) { | ||
var e = _ref.e; | ||
var element = _ref.element; | ||
var position = _ref.position; | ||
_this.props.onResizeStart(layout, l, l, null, e, element); | ||
}; | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
this.onResize = function (i, w, h, _ref5) { | ||
var e = _ref5.e; | ||
var element = _ref5.element; | ||
// No need to clone, `l` hasn't changed. | ||
this.props.onDragStart(layout, l, l, null, e); | ||
}, | ||
/** | ||
* Each drag movement create a new dragelement and move the element to the dragged location | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ | ||
onDrag: function onDrag(i, x, y, _ref2) { | ||
var e = _ref2.e; | ||
var element = _ref2.element; | ||
var position = _ref2.position; | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
if (!l) return; | ||
var oldL = _this.state.oldResizeItem; | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
// Clone layout item so we can pass it to the callback. | ||
var oldL = utils.clone(l); | ||
// Set new width and height. | ||
l.w = w; | ||
l.h = h; | ||
// Create placeholder (display only) | ||
var placeholder = { | ||
w: l.w, h: l.h, x: l.x, y: l.y, placeholder: true, i: i | ||
// Create placeholder element (display only) | ||
var placeholder = { | ||
w: w, h: h, x: l.x, y: l.y, placeholder: true, i: i | ||
}; | ||
_this.props.onResize(layout, oldL, l, placeholder, e, element); | ||
// Re-compact the layout and set the drag placeholder. | ||
_this.setState({ layout: (0, _utils.compact)(layout, _this.props.verticalCompact), activeDrag: placeholder }); | ||
}; | ||
// Move the element to the dragged location. | ||
layout = utils.moveElement(layout, l, x, y, true /* isUserAction */); | ||
this.onResizeStop = function (i, w, h, _ref6) { | ||
var e = _ref6.e; | ||
var element = _ref6.element; | ||
this.props.onDrag(layout, oldL, l, placeholder, e); | ||
var layout = _this.state.layout; | ||
var l = (0, _utils.getLayoutItem)(layout, i); | ||
var oldL = _this.state.oldResizeItem; | ||
this.setState({ | ||
layout: utils.compact(layout, this.props.verticalCompact), | ||
activeDrag: placeholder | ||
}); | ||
}, | ||
_this.props.onResizeStop(layout, oldL, l, null, e, element); | ||
/** | ||
* When dragging stops, figure out which position the element is closest to and update its x and y. | ||
* @param {Number} i Index of the child. | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ | ||
onDragStop: function onDragStop(i, x, y, _ref3) { | ||
var e = _ref3.e; | ||
var element = _ref3.element; | ||
var position = _ref3.position; | ||
_this.setState({ | ||
layout: (0, _utils.compact)(layout, _this.props.verticalCompact), | ||
activeDrag: null, | ||
oldResizeItem: null | ||
}); | ||
}; | ||
} | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
var oldL = utils.clone(l); | ||
_createClass(ReactGridLayout, [{ | ||
key: 'componentDidMount', | ||
value: function componentDidMount() { | ||
// Call back with layout on mount. This should be done after correcting the layout width | ||
// to ensure we don't rerender with the wrong width. | ||
this.props.onLayoutChange(this.state.layout); | ||
this.setState({ isMounted: true }); | ||
} | ||
// Move the element here | ||
layout = utils.moveElement(layout, l, x, y, true /* isUserAction */); | ||
// FIXME would like to reconcile propTypes & flow, but we want propTypes for consumers of this module | ||
// (they might not be using Flow), and I don't want to duplicate a typedef & propTypes | ||
}, { | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(nextProps) { | ||
// This allows you to set the width manually if you like. | ||
// Use manual width changes in combination with `listenToWindowResize: false` | ||
if (nextProps.width !== this.props.width) this.onWidthChange(nextProps.width); | ||
this.props.onDragStop(layout, oldL, l, null, e); | ||
// If children change, regenerate the layout. | ||
if (nextProps.children.length !== this.props.children.length) { | ||
this.setState({ | ||
layout: (0, _utils.synchronizeLayoutWithChildren)(this.state.layout, nextProps.children, nextProps.cols, this.props.verticalCompact) | ||
}); | ||
} | ||
// Set state | ||
this.setState({ layout: utils.compact(layout, this.props.verticalCompact), activeDrag: null }); | ||
}, | ||
// Allow parent to set layout directly. | ||
if (nextProps.layout && JSON.stringify(nextProps.layout) !== JSON.stringify(this.state.layout)) { | ||
this.setState({ | ||
layout: (0, _utils.synchronizeLayoutWithChildren)(nextProps.layout, nextProps.children, nextProps.cols, this.props.verticalCompact) | ||
}); | ||
} | ||
} | ||
}, { | ||
key: 'componentDidUpdate', | ||
value: function componentDidUpdate(prevProps, prevState) { | ||
// Call back so we can store the layout | ||
// Do it only when a resize/drag is not active, otherwise there are way too many callbacks | ||
if (this.state.layout !== prevState.layout && !this.state.activeDrag) { | ||
this.props.onLayoutChange(this.state.layout, this.state.layouts); | ||
} | ||
} | ||
onResizeStart: function onResizeStart(i, w, h, _ref4) { | ||
var e = _ref4.e; | ||
var element = _ref4.element; | ||
var size = _ref4.size; | ||
/** | ||
* Calculates a pixel value for the container. | ||
* @return {String} Container height in pixels. | ||
*/ | ||
}, { | ||
key: 'containerHeight', | ||
value: function containerHeight() { | ||
if (!this.props.autoSize) return; | ||
return (0, _utils.bottom)(this.state.layout) * this.props.rowHeight + this.props.margin[1] + 'px'; | ||
} | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
/** | ||
* When the width changes, save it to state. This helps with left/width calculations. | ||
*/ | ||
}, { | ||
key: 'placeholder', | ||
// No need to clone, item hasn't changed | ||
this.props.onResizeStart(layout, l, l, null, e); | ||
}, | ||
/** | ||
* Create a placeholder object. | ||
* @return {Element} Placeholder div. | ||
*/ | ||
value: function placeholder() { | ||
if (!this.state.activeDrag) return null; | ||
onResize: function onResize(i, w, h, _ref5) { | ||
var e = _ref5.e; | ||
var element = _ref5.element; | ||
var size = _ref5.size; | ||
// {...this.state.activeDrag} is pretty slow, actually | ||
return _react2['default'].createElement( | ||
_GridItem2['default'], | ||
{ | ||
w: this.state.activeDrag.w, | ||
h: this.state.activeDrag.h, | ||
x: this.state.activeDrag.x, | ||
y: this.state.activeDrag.y, | ||
i: this.state.activeDrag.i, | ||
isPlaceholder: true, | ||
className: 'react-grid-placeholder', | ||
containerWidth: this.state.width, | ||
cols: this.props.cols, | ||
margin: this.props.margin, | ||
rowHeight: this.props.rowHeight, | ||
isDraggable: false, | ||
isResizable: false, | ||
useCSSTransforms: this.props.useCSSTransforms | ||
}, | ||
_react2['default'].createElement('div', null) | ||
); | ||
} | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
var oldL = utils.clone(l); | ||
/** | ||
* Given a grid item, set its style attributes & surround in a <Draggable>. | ||
* @param {Element} child React element. | ||
* @param {Number} i Index of element. | ||
* @return {Element} Element wrapped in draggable and properly placed. | ||
*/ | ||
}, { | ||
key: 'processGridItem', | ||
value: function processGridItem(child) { | ||
if (!child.key) return; | ||
var i = parseInt(child.key, 10); | ||
var l = (0, _utils.getLayoutItem)(this.state.layout, i); | ||
if (!l) return; | ||
// Set new width and height. | ||
l.w = w; | ||
l.h = h; | ||
// watchStart property tells Draggable to react to changes in the start param | ||
// Must be turned off on the item we're dragging as the changes in `activeDrag` cause rerenders | ||
var moveOnStartChange = !(this.state.activeDrag && this.state.activeDrag.i === i); | ||
// Create placeholder element (display only) | ||
var placeholder = { | ||
w: w, h: h, x: l.x, y: l.y, placeholder: true, i: i | ||
}; | ||
// Parse 'static'. Any properties defined directly on the grid item will take precedence. | ||
var draggable, resizable; | ||
if (l['static'] || this.props.isDraggable === false) draggable = false; | ||
if (l['static'] || this.props.isResizable === false) resizable = false; | ||
this.props.onResize(layout, oldL, l, placeholder, e); | ||
return _react2['default'].createElement( | ||
_GridItem2['default'], | ||
_extends({ | ||
containerWidth: this.state.width, | ||
cols: this.props.cols, | ||
margin: this.props.margin, | ||
rowHeight: this.props.rowHeight, | ||
moveOnStartChange: moveOnStartChange, | ||
cancel: this.props.draggableCancel, | ||
handle: this.props.draggableHandle, | ||
onDragStop: this.onDragStop, | ||
onDragStart: this.onDragStart, | ||
onDrag: this.onDrag, | ||
onResizeStart: this.onResizeStart, | ||
onResize: this.onResize, | ||
onResizeStop: this.onResizeStop, | ||
isDraggable: draggable, | ||
isResizable: resizable, | ||
useCSSTransforms: this.props.useCSSTransforms && this.state.isMounted, | ||
usePercentages: !this.state.isMounted | ||
}, l), | ||
child | ||
); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
// Calculate classname | ||
/*eslint no-redeclare:0*/ // eslint bug? | ||
var _props = this.props; | ||
var className = _props.className; | ||
// Re-compact the layout and set the drag placeholder. | ||
this.setState({ layout: utils.compact(layout, this.props.verticalCompact), activeDrag: placeholder }); | ||
}, | ||
var props = _objectWithoutProperties(_props, ['className']); | ||
onResizeStop: function onResizeStop(i, x, y, _ref6) { | ||
var e = _ref6.e; | ||
var element = _ref6.element; | ||
var size = _ref6.size; | ||
className = 'react-grid-layout ' + (className || ''); | ||
var layout = this.state.layout; | ||
var l = utils.getLayoutItem(layout, i); | ||
var oldL = utils.clone(l); | ||
return _react2['default'].createElement( | ||
'div', | ||
_extends({}, props, { className: className, style: { height: this.containerHeight() } }), | ||
_react2['default'].Children.map(this.props.children, this.processGridItem.bind(this)), | ||
this.placeholder() | ||
); | ||
} | ||
}], [{ | ||
key: 'propTypes', | ||
this.props.onResizeStop(layout, oldL, l, null, e); | ||
// mixins: [PureDeepRenderMixin, WidthListeningMixin], // FIXME | ||
this.setState({ activeDrag: null, layout: utils.compact(layout, this.props.verticalCompact) }); | ||
}, | ||
value: { | ||
// | ||
// Basic props | ||
// | ||
/** | ||
* Create a placeholder object. | ||
* @return {Element} Placeholder div. | ||
*/ | ||
placeholder: function placeholder() { | ||
if (!this.state.activeDrag) return ''; | ||
// If true, the container height swells and contracts to fit contents | ||
autoSize: _react2['default'].PropTypes.bool, | ||
// # of cols. | ||
cols: _react2['default'].PropTypes.number, | ||
// {...this.state.activeDrag} is pretty slow, actually | ||
return React.createElement( | ||
GridItem, | ||
{ | ||
w: this.state.activeDrag.w, | ||
h: this.state.activeDrag.h, | ||
x: this.state.activeDrag.x, | ||
y: this.state.activeDrag.y, | ||
i: this.state.activeDrag.i, | ||
isPlaceholder: true, | ||
className: 'react-grid-placeholder', | ||
containerWidth: this.state.width, | ||
cols: this.props.cols, | ||
margin: this.props.margin, | ||
rowHeight: this.props.rowHeight, | ||
isDraggable: false, | ||
isResizable: false, | ||
useCSSTransforms: this.props.useCSSTransforms | ||
// A selector that will not be draggable. | ||
draggableCancel: _react2['default'].PropTypes.string, | ||
// A selector for the draggable handler | ||
draggableHandle: _react2['default'].PropTypes.string, | ||
// If true, the layout will compact vertically | ||
verticalCompact: _react2['default'].PropTypes.bool, | ||
// layout is an array of object with the format: | ||
// {x: Number, y: Number, w: Number, h: Number, i: Number} | ||
layout: function layout(props, propName, _componentName) { | ||
var layout = props.layout; | ||
// I hope you're setting the _grid property on the grid items | ||
if (layout === undefined) return; | ||
(0, _utils.validateLayout)(layout, 'layout'); | ||
}, | ||
React.createElement('div', null) | ||
); | ||
}, | ||
/** | ||
* Given a grid item, set its style attributes & surround in a <Draggable>. | ||
* @param {Element} child React element. | ||
* @param {Number} i Index of element. | ||
* @return {Element} Element wrapped in draggable and properly placed. | ||
*/ | ||
processGridItem: function processGridItem(child) { | ||
var i = child.key; | ||
var l = utils.getLayoutItem(this.state.layout, i); | ||
layouts: function layouts(props, propName, _componentName) { | ||
if (props.layouts) { | ||
throw new Error("ReactGridLayout does not use `layouts`: Use ReactGridLayout.Responsive."); | ||
} | ||
}, | ||
// watchStart property tells Draggable to react to changes in the start param | ||
// Must be turned off on the item we're dragging as the changes in `activeDrag` cause rerenders | ||
var drag = this.state.activeDrag; | ||
var moveOnStartChange = drag && drag.i === i ? false : true; | ||
// margin between items [x, y] in px | ||
margin: _react2['default'].PropTypes.array, | ||
// Rows have a static height, but you can change this based on breakpoints if you like | ||
rowHeight: _react2['default'].PropTypes.number, | ||
// Parse 'static'. Any properties defined directly on the grid item will take precedence. | ||
var draggable, resizable; | ||
if (l['static'] || this.props.isDraggable === false) draggable = false; | ||
if (l['static'] || this.props.isResizable === false) resizable = false; | ||
// | ||
// Flags | ||
// | ||
isDraggable: _react2['default'].PropTypes.bool, | ||
isResizable: _react2['default'].PropTypes.bool, | ||
// Use CSS transforms instead of top/left | ||
useCSSTransforms: _react2['default'].PropTypes.bool, | ||
return React.createElement( | ||
GridItem, | ||
_extends({ | ||
containerWidth: this.state.width, | ||
cols: this.props.cols, | ||
margin: this.props.margin, | ||
rowHeight: this.props.rowHeight, | ||
moveOnStartChange: moveOnStartChange, | ||
cancel: this.props.draggableCancel, | ||
handle: this.props.draggableHandle, | ||
onDragStop: this.onDragStop, | ||
onDragStart: this.onDragStart, | ||
onDrag: this.onDrag, | ||
onResizeStart: this.onResizeStart, | ||
onResize: this.onResize, | ||
onResizeStop: this.onResizeStop, | ||
isDraggable: draggable, | ||
isResizable: resizable, | ||
useCSSTransforms: this.props.useCSSTransforms && this.state.isMounted, | ||
usePercentages: !this.state.isMounted | ||
}, l), | ||
child | ||
); | ||
}, | ||
// | ||
// Callbacks | ||
// | ||
render: function render() { | ||
// Calculate classname | ||
var _props = this.props; | ||
var className = _props.className; | ||
// Callback so you can save the layout. | ||
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint. | ||
onLayoutChange: _react2['default'].PropTypes.func, | ||
var props = _objectWithoutProperties(_props, ['className']); | ||
// Calls when drag starts. Callback is of the signature (layout, oldItem, newItem, placeholder, e). | ||
// All callbacks below have the same signature. 'start' and 'stop' callbacks omit the 'placeholder'. | ||
onDragStart: _react2['default'].PropTypes.func, | ||
// Calls on each drag movement. | ||
onDrag: _react2['default'].PropTypes.func, | ||
// Calls when drag is complete. | ||
onDragStop: _react2['default'].PropTypes.func, | ||
//Calls when resize starts. | ||
onResizeStart: _react2['default'].PropTypes.func, | ||
// Calls when resize movement happens. | ||
onResize: _react2['default'].PropTypes.func, | ||
// Calls when resize is complete. | ||
onResizeStop: _react2['default'].PropTypes.func, | ||
className = 'react-grid-layout ' + (className || ''); | ||
// | ||
// Other validations | ||
// | ||
return React.createElement( | ||
'div', | ||
_extends({}, props, { className: className, style: { height: this.containerHeight() } }), | ||
React.Children.map(this.props.children, this.processGridItem), | ||
this.placeholder() | ||
); | ||
} | ||
}); | ||
// Children must not have duplicate keys. | ||
children: function children(props, propName, _componentName) { | ||
_react2['default'].PropTypes.node.apply(this, arguments); | ||
var children = props[propName]; | ||
module.exports = ReactGridLayout; | ||
// Check children keys for duplicates. Throw if found. | ||
var keys = {}; | ||
_react2['default'].Children.forEach(children, function (child) { | ||
if (keys[child.key]) { | ||
throw new Error("Duplicate child key found! This will cause problems in ReactGridLayout."); | ||
} | ||
keys[child.key] = true; | ||
}); | ||
} | ||
}, | ||
enumerable: true | ||
}, { | ||
key: 'defaultProps', | ||
value: { | ||
autoSize: true, | ||
cols: 12, | ||
rowHeight: 150, | ||
layout: [], | ||
margin: [10, 10], | ||
isDraggable: true, | ||
isResizable: true, | ||
useCSSTransforms: true, | ||
verticalCompact: true, | ||
onLayoutChange: function onLayoutChange() {}, | ||
onDragStart: function onDragStart() {}, | ||
onDrag: function onDrag() {}, | ||
onDragStop: function onDragStop() {}, | ||
onResizeStart: function onResizeStart() {}, | ||
onResize: function onResize() {}, | ||
onResizeStop: function onResizeStop() {} | ||
}, | ||
enumerable: true | ||
}]); | ||
return ReactGridLayout; | ||
})(_react2['default'].Component); | ||
ReactGridLayout.displayName = 'ReactGridLayout'; | ||
exports['default'] = (0, _componentsListensToWidth2['default'])(ReactGridLayout); | ||
module.exports = exports['default']; | ||
/** | ||
* When dragging starts | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ | ||
/** | ||
* Each drag movement create a new dragelement and move the element to the dragged location | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ | ||
/** | ||
* When dragging stops, figure out which position the element is closest to and update its x and y. | ||
* @param {Number} i Index of the child. | ||
* @param {Number} i Index of the child | ||
* @param {Number} x X position of the move | ||
* @param {Number} y Y position of the move | ||
* @param {Event} e The mousedown event | ||
* @param {Element} element The current dragging DOM element | ||
* @param {Object} position Drag information | ||
*/ |
'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 _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
var React = require('react'); | ||
var utils = require('./utils'); | ||
var responsiveUtils = require('./responsiveUtils'); | ||
var PureDeepRenderMixin = require('./mixins/PureDeepRenderMixin'); | ||
var WidthListeningMixin = require('./mixins/WidthListeningMixin'); | ||
var ReactGridLayout = require('./ReactGridLayout'); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } | ||
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; } | ||
var _react = require('react'); | ||
var _react2 = _interopRequireDefault(_react); | ||
var _utils = require('./utils'); | ||
var _responsiveUtils = require('./responsiveUtils'); | ||
var _ReactGridLayout = require('./ReactGridLayout'); | ||
var _ReactGridLayout2 = _interopRequireDefault(_ReactGridLayout); | ||
var _componentsListensToWidth = require('./components/ListensToWidth'); | ||
var _componentsListensToWidth2 = _interopRequireDefault(_componentsListensToWidth); | ||
// Types | ||
// End Types | ||
/** | ||
* A wrapper around ReactGridLayout to support responsive breakpoints. | ||
*/ | ||
var ResponsiveReactGridLayout = React.createClass({ | ||
displayName: 'ResponsiveReactGridLayout', | ||
mixins: [PureDeepRenderMixin, WidthListeningMixin], | ||
var ResponsiveReactGridLayout = (function (_React$Component) { | ||
_inherits(ResponsiveReactGridLayout, _React$Component); | ||
propTypes: { | ||
// | ||
// Basic props | ||
// | ||
_createClass(ResponsiveReactGridLayout, null, [{ | ||
key: 'propTypes', | ||
// Optional, but if you are managing width yourself you may want to set the breakpoint | ||
// yourself as well. | ||
breakpoint: React.PropTypes.string, | ||
// mixins: [PureDeepRenderMixin, WidthListeningMixin], // FIXME | ||
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480} | ||
breakpoints: React.PropTypes.object, | ||
value: { | ||
// | ||
// Basic props | ||
// | ||
// # of cols. This is a breakpoint -> cols map | ||
cols: React.PropTypes.object, | ||
// Optional, but if you are managing width yourself you may want to set the breakpoint | ||
// yourself as well. | ||
breakpoint: _react2['default'].PropTypes.string, | ||
// layouts is an object mapping breakpoints to layouts. | ||
// e.g. {lg: Layout, md: Layout, ...} | ||
layouts: function layouts(props, propName, componentName) { | ||
React.PropTypes.object.isRequired.apply(this, arguments); | ||
// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480} | ||
breakpoints: _react2['default'].PropTypes.object, | ||
var layouts = props.layouts; | ||
Object.keys(layouts).map(function (k) { | ||
utils.validateLayout(layouts[k], 'layouts.' + k); | ||
}); | ||
}, | ||
// # of cols. This is a breakpoint -> cols map | ||
cols: _react2['default'].PropTypes.object, | ||
// | ||
// Callbacks | ||
// | ||
// layouts is an object mapping breakpoints to layouts. | ||
// e.g. {lg: Layout, md: Layout, ...} | ||
layouts: function layouts(props, propName, _componentName) { | ||
_react2['default'].PropTypes.object.isRequired.apply(this, arguments); | ||
// Calls back with breakpoint and new # cols | ||
onBreakpointChange: React.PropTypes.func, | ||
var layouts = props.layouts; | ||
Object.keys(layouts).map(function (k) { | ||
(0, _utils.validateLayout)(layouts[k], 'layouts.' + k); | ||
}); | ||
}, | ||
// Callback so you can save the layout. | ||
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint. | ||
onLayoutChange: React.PropTypes.func | ||
}, | ||
// | ||
// Callbacks | ||
// | ||
getDefaultProps: function getDefaultProps() { | ||
return { | ||
// Calls back with breakpoint and new # cols | ||
onBreakpointChange: _react2['default'].PropTypes.func, | ||
// Callback so you can save the layout. | ||
// Calls back with (currentLayout, allLayouts). allLayouts are keyed by breakpoint. | ||
onLayoutChange: _react2['default'].PropTypes.func, | ||
// Calls back with (containerWidth, margin, cols) | ||
onWidthChange: _react2['default'].PropTypes.func | ||
}, | ||
enumerable: true | ||
}, { | ||
key: 'defaultProps', | ||
value: { | ||
breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }, | ||
@@ -66,15 +101,60 @@ cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }, | ||
onBreakpointChange: function onBreakpointChange() {}, | ||
onLayoutChange: function onLayoutChange() {} | ||
onLayoutChange: function onLayoutChange() {}, | ||
onWidthChange: function onWidthChange() {} | ||
}, | ||
enumerable: true | ||
}]); | ||
function ResponsiveReactGridLayout(props) { | ||
var _this = this; | ||
_classCallCheck(this, ResponsiveReactGridLayout); | ||
_get(Object.getPrototypeOf(ResponsiveReactGridLayout.prototype), 'constructor', this).call(this, props); | ||
this.onLayoutChange = function (layout) { | ||
_this.state.layouts[_this.state.breakpoint] = layout; | ||
_this.setState({ layout: layout, layouts: _this.state.layouts }); | ||
_this.props.onLayoutChange(layout, _this.state.layouts); | ||
}; | ||
}, | ||
getInitialState: function getInitialState() { | ||
var breakpoint = this.props.breakpoint || responsiveUtils.getBreakpointFromWidth(this.props.breakpoints, this.props.initialWidth); | ||
var cols = responsiveUtils.getColsFromBreakpoint(breakpoint, this.props.cols); | ||
this.onWidthChange = function (width) { | ||
// Set new breakpoint | ||
var newState = { | ||
width: width, | ||
breakpoint: _this.props.breakpoint || (0, _responsiveUtils.getBreakpointFromWidth)(_this.props.breakpoints, width) | ||
}; | ||
newState.cols = (0, _responsiveUtils.getColsFromBreakpoint)(newState.breakpoint, _this.props.cols); | ||
// Breakpoint change | ||
if (newState.cols !== _this.state.cols) { | ||
// Store the current layout | ||
newState.layouts = _this.state.layouts; | ||
newState.layouts[_this.state.breakpoint] = JSON.parse(JSON.stringify(_this.state.layout)); | ||
// Find or generate a new one. | ||
newState.layout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(newState.layouts, _this.props.breakpoints, newState.breakpoint, _this.state.breakpoint, newState.cols, _this.props.verticalLayout); | ||
// This adds missing items. | ||
newState.layout = (0, _utils.synchronizeLayoutWithChildren)(newState.layout, _this.props.children, newState.cols, _this.props.verticalCompact); | ||
// Store this new layout as well. | ||
newState.layouts[newState.breakpoint] = newState.layout; | ||
_this.props.onBreakpointChange(newState.breakpoint, newState.cols); | ||
} | ||
_this.props.onWidthChange(width, _this.props.margin, newState.cols); | ||
_this.setState(newState); | ||
}; | ||
var breakpoint = this.props.breakpoint || (0, _responsiveUtils.getBreakpointFromWidth)(this.props.breakpoints, this.props.initialWidth); | ||
var cols = (0, _responsiveUtils.getColsFromBreakpoint)(breakpoint, this.props.cols); | ||
// Get the initial layout. This can tricky; we try to generate one however possible if one doesn't exist | ||
// for this layout. | ||
var initialLayout = responsiveUtils.findOrGenerateResponsiveLayout(this.props.layouts, this.props.breakpoints, breakpoint, breakpoint, cols, this.props.verticalCompact); | ||
var initialLayout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(this.props.layouts, this.props.breakpoints, breakpoint, breakpoint, cols, this.props.verticalCompact); | ||
return { | ||
this.state = { | ||
layout: initialLayout, | ||
@@ -87,92 +167,70 @@ // storage for layouts obsoleted by breakpoints | ||
}; | ||
}, | ||
} | ||
componentWillReceiveProps: function componentWillReceiveProps(nextProps) { | ||
// This allows you to set the width manually if you like. | ||
// Use manual width changes in combination with `listenToWindowResize: false` | ||
if (nextProps.width) this.onWidthChange(nextProps.width); | ||
// FIXME reconcile Flow types & PropTypes | ||
// Allow parent to set breakpoint directly. | ||
if (nextProps.breakpoint !== this.props.breakpoint) { | ||
this.onWidthChange(this.state.width); | ||
} | ||
_createClass(ResponsiveReactGridLayout, [{ | ||
key: 'componentWillReceiveProps', | ||
value: function componentWillReceiveProps(nextProps) { | ||
// This allows you to set the width manually if you like. | ||
// Use manual width changes in combination with `listenToWindowResize: false` | ||
if (nextProps.width) this.onWidthChange(nextProps.width); | ||
// Allow parent to set layouts directly. | ||
if (nextProps.layouts && nextProps.layouts !== this.state.layouts) { | ||
// Since we're setting an entirely new layout object, we must generate a new responsive layout | ||
// if one does not exist. | ||
var newLayout = responsiveUtils.findOrGenerateResponsiveLayout(nextProps.layouts, nextProps.breakpoints, this.state.breakpoint, this.state.breakpoint, this.state.cols, this.props.verticalLayout); | ||
// Allow parent to set breakpoint directly. | ||
if (nextProps.breakpoint !== this.props.breakpoint) { | ||
this.onWidthChange(this.state.width); | ||
} | ||
this.setState({ | ||
layouts: nextProps.layouts, | ||
layout: newLayout | ||
}); | ||
// Allow parent to set layouts directly. | ||
if (nextProps.layouts && nextProps.layouts !== this.state.layouts) { | ||
// Since we're setting an entirely new layout object, we must generate a new responsive layout | ||
// if one does not exist. | ||
var newLayout = (0, _responsiveUtils.findOrGenerateResponsiveLayout)(nextProps.layouts, nextProps.breakpoints, this.state.breakpoint, this.state.breakpoint, this.state.cols, this.props.verticalLayout); | ||
this.setState({ | ||
layouts: nextProps.layouts, | ||
layout: newLayout | ||
}); | ||
} | ||
} | ||
}, | ||
/** | ||
* Bubble this up, add `layouts` object. | ||
* @param {Array} layout Layout from inner Grid. | ||
*/ | ||
onLayoutChange: function onLayoutChange(layout) { | ||
this.state.layouts[this.state.breakpoint] = layout; | ||
this.setState({ layout: layout, layouts: this.state.layouts }); | ||
this.props.onLayoutChange(layout, this.state.layouts); | ||
}, | ||
/** | ||
* Bubble this up, add `layouts` object. | ||
* @param {Array} layout Layout from inner Grid. | ||
*/ | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
// Don't pass responsive props to RGL. | ||
/*eslint no-redeclare: 0*/ // bug? | ||
var _props = this.props; | ||
var layouts = _props.layouts; | ||
var onBreakpointChange = _props.onBreakpointChange; | ||
var breakpoints = _props.breakpoints; | ||
/** | ||
* When the width changes work through breakpoints and reset state with the new width & breakpoint. | ||
* Width changes are necessary to figure out the widget widths. | ||
*/ | ||
onWidthChange: function onWidthChange(width) { | ||
// Set new breakpoint | ||
var newState = { width: width }; | ||
newState.breakpoint = this.props.breakpoint || responsiveUtils.getBreakpointFromWidth(this.props.breakpoints, newState.width); | ||
newState.cols = responsiveUtils.getColsFromBreakpoint(newState.breakpoint, this.props.cols); | ||
var props = _objectWithoutProperties(_props, ['layouts', 'onBreakpointChange', 'breakpoints']); | ||
// Breakpoint change | ||
if (newState.cols !== this.state.cols) { | ||
// Store the current layout | ||
newState.layouts = this.state.layouts; | ||
newState.layouts[this.state.breakpoint] = JSON.parse(JSON.stringify(this.state.layout)); | ||
// Find or generate a new one. | ||
newState.layout = responsiveUtils.findOrGenerateResponsiveLayout(newState.layouts, this.props.breakpoints, newState.breakpoint, this.state.breakpoint, newState.cols, this.props.verticalLayout); | ||
// This adds missing items. | ||
newState.layout = utils.synchronizeLayoutWithChildren(newState.layout, this.props.children, newState.cols, this.props.verticalCompact); | ||
// Store this new layout as well. | ||
newState.layouts[newState.breakpoint] = newState.layout; | ||
this.props.onBreakpointChange(newState.breakpoint, newState.cols); | ||
return _react2['default'].createElement( | ||
_ReactGridLayout2['default'], | ||
_extends({}, props, { | ||
layout: this.state.layout, | ||
cols: this.state.cols, | ||
listenToWindowResize: false, | ||
onLayoutChange: this.onLayoutChange, | ||
width: this.state.width }), | ||
this.props.children | ||
); | ||
} | ||
}]); | ||
this.setState(newState); | ||
}, | ||
return ResponsiveReactGridLayout; | ||
})(_react2['default'].Component); | ||
render: function render() { | ||
// Don't pass responsive props to RGL. | ||
/*jshint unused:false*/ | ||
var _props = this.props; | ||
var layouts = _props.layouts; | ||
var onBreakpointChange = _props.onBreakpointChange; | ||
var breakpoints = _props.breakpoints; | ||
ResponsiveReactGridLayout.displayName = 'ResponsiveReactGridLayout'; | ||
exports['default'] = (0, _componentsListensToWidth2['default'])(ResponsiveReactGridLayout); | ||
module.exports = exports['default']; | ||
var props = _objectWithoutProperties(_props, ['layouts', 'onBreakpointChange', 'breakpoints']); | ||
return React.createElement( | ||
ReactGridLayout, | ||
_extends({}, props, { | ||
layout: this.state.layout, | ||
cols: this.state.cols, | ||
listenToWindowResize: false, | ||
onLayoutChange: this.onLayoutChange, | ||
width: this.state.width }), | ||
this.props.children | ||
); | ||
} | ||
}); | ||
module.exports = ResponsiveReactGridLayout; | ||
/** | ||
* When the width changes work through breakpoints and reset state with the new width & breakpoint. | ||
* Width changes are necessary to figure out the widget widths. | ||
*/ |
'use strict'; | ||
var utils = require('./utils'); | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
exports.getBreakpointFromWidth = getBreakpointFromWidth; | ||
exports.getColsFromBreakpoint = getColsFromBreakpoint; | ||
exports.findOrGenerateResponsiveLayout = findOrGenerateResponsiveLayout; | ||
exports.sortBreakpoints = sortBreakpoints; | ||
var responsiveUtils = module.exports = { | ||
var _utils = require('./utils'); | ||
/** | ||
* Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint). | ||
* | ||
* @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...}) | ||
* @param {Number} width Screen width. | ||
* @return {String} Highest breakpoint that is less than width. | ||
*/ | ||
getBreakpointFromWidth: function getBreakpointFromWidth(breakpoints, width) { | ||
var sorted = responsiveUtils.sortBreakpoints(breakpoints); | ||
var matching = sorted[0]; | ||
for (var i = 1, len = sorted.length; i < len; i++) { | ||
var breakpointName = sorted[i]; | ||
if (width > breakpoints[breakpointName]) matching = breakpointName; | ||
} | ||
return matching; | ||
}, | ||
/** | ||
* Given a width, find the highest breakpoint that matches is valid for it (width > breakpoint). | ||
* | ||
* @param {Object} breakpoints Breakpoints object (e.g. {lg: 1200, md: 960, ...}) | ||
* @param {Number} width Screen width. | ||
* @return {String} Highest breakpoint that is less than width. | ||
*/ | ||
/** | ||
* Given a breakpoint, get the # of cols set for it. | ||
* @param {String} breakpoint Breakpoint name. | ||
* @param {Object} cols Map of breakpoints to cols. | ||
* @return {Number} Number of cols. | ||
*/ | ||
getColsFromBreakpoint: function getColsFromBreakpoint(breakpoint, cols) { | ||
if (!cols[breakpoint]) { | ||
throw new Error("ResponsiveReactGridLayout: `cols` entry for breakpoint " + breakpoint + " is missing!"); | ||
} | ||
return cols[breakpoint]; | ||
}, | ||
function getBreakpointFromWidth(breakpoints, width) { | ||
var sorted = sortBreakpoints(breakpoints); | ||
var matching = sorted[0]; | ||
for (var i = 1, len = sorted.length; i < len; i++) { | ||
var breakpointName = sorted[i]; | ||
if (width > breakpoints[breakpointName]) matching = breakpointName; | ||
} | ||
return matching; | ||
} | ||
/** | ||
* Given existing layouts and a new breakpoint, find or generate a new layout. | ||
* | ||
* This finds the layout above the new one and generates from it, if it exists. | ||
* | ||
* @param {Array} layouts Existing layouts. | ||
* @param {Array} breakpoints All breakpoints. | ||
* @param {String} breakpoint New breakpoint. | ||
* @param {String} breakpoint Last breakpoint (for fallback). | ||
* @param {Number} cols Column count at new breakpoint. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} New layout. | ||
*/ | ||
findOrGenerateResponsiveLayout: function findOrGenerateResponsiveLayout(layouts, breakpoints, breakpoint, lastBreakpoint, cols, verticalCompact) { | ||
// If it already exists, just return it. | ||
if (layouts[breakpoint]) return layouts[breakpoint]; | ||
// Find or generate the next layout | ||
var layout = layouts[lastBreakpoint]; | ||
var breakpointsSorted = responsiveUtils.sortBreakpoints(breakpoints); | ||
var breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint)); | ||
for (var i = 0, len = breakpointsAbove.length; i < len; i++) { | ||
var b = breakpointsAbove[i]; | ||
if (layouts[b]) { | ||
layout = layouts[b]; | ||
break; | ||
} | ||
/** | ||
* Given a breakpoint, get the # of cols set for it. | ||
* @param {String} breakpoint Breakpoint name. | ||
* @param {Object} cols Map of breakpoints to cols. | ||
* @return {Number} Number of cols. | ||
*/ | ||
function getColsFromBreakpoint(breakpoint, cols) { | ||
if (!cols[breakpoint]) { | ||
throw new Error("ResponsiveReactGridLayout: `cols` entry for breakpoint " + breakpoint + " is missing!"); | ||
} | ||
return cols[breakpoint]; | ||
} | ||
/** | ||
* Given existing layouts and a new breakpoint, find or generate a new layout. | ||
* | ||
* This finds the layout above the new one and generates from it, if it exists. | ||
* | ||
* @param {Object} layouts Existing layouts. | ||
* @param {Array} breakpoints All breakpoints. | ||
* @param {String} breakpoint New breakpoint. | ||
* @param {String} breakpoint Last breakpoint (for fallback). | ||
* @param {Number} cols Column count at new breakpoint. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} New layout. | ||
*/ | ||
function findOrGenerateResponsiveLayout(layouts, breakpoints, breakpoint, lastBreakpoint, cols, verticalCompact) { | ||
// If it already exists, just return it. | ||
if (layouts[breakpoint]) return layouts[breakpoint]; | ||
// Find or generate the next layout | ||
var layout = layouts[lastBreakpoint]; | ||
var breakpointsSorted = sortBreakpoints(breakpoints); | ||
var breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint)); | ||
for (var i = 0, len = breakpointsAbove.length; i < len; i++) { | ||
var b = breakpointsAbove[i]; | ||
if (layouts[b]) { | ||
layout = layouts[b]; | ||
break; | ||
} | ||
layout = JSON.parse(JSON.stringify(layout || [])); // clone layout so we don't modify existing items | ||
return utils.compact(utils.correctBounds(layout, { cols: cols }), verticalCompact); | ||
}, | ||
} | ||
layout = JSON.parse(JSON.stringify(layout || [])); // clone layout so we don't modify existing items | ||
return (0, _utils.compact)((0, _utils.correctBounds)(layout, { cols: cols }), verticalCompact); | ||
} | ||
/** | ||
* Given breakpoints, return an array of breakpoints sorted by width. This is usually | ||
* e.g. ['xxs', 'xs', 'sm', ...] | ||
* | ||
* @param {Object} breakpoints Key/value pair of breakpoint names to widths. | ||
* @return {Array} Sorted breakpoints. | ||
*/ | ||
sortBreakpoints: function sortBreakpoints(breakpoints) { | ||
var keys = Object.keys(breakpoints); | ||
return keys.sort(function (a, b) { | ||
return breakpoints[a] - breakpoints[b]; | ||
}); | ||
} | ||
}; | ||
/** | ||
* Given breakpoints, return an array of breakpoints sorted by width. This is usually | ||
* e.g. ['xxs', 'xs', 'sm', ...] | ||
* | ||
* @param {Object} breakpoints Key/value pair of breakpoint names to widths. | ||
* @return {Array} Sorted breakpoints. | ||
*/ | ||
function sortBreakpoints(breakpoints) { | ||
var keys = Object.keys(breakpoints); | ||
return keys.sort(function (a, b) { | ||
return breakpoints[a] - breakpoints[b]; | ||
}); | ||
} |
'use strict'; | ||
var assign = require('object-assign'); | ||
/*global ReactElement*/ | ||
Object.defineProperty(exports, '__esModule', { | ||
value: true | ||
}); | ||
exports.bottom = bottom; | ||
exports.clone = clone; | ||
exports.collides = collides; | ||
exports.compact = compact; | ||
exports.compactItem = compactItem; | ||
exports.correctBounds = correctBounds; | ||
exports.getLayoutItem = getLayoutItem; | ||
exports.getFirstCollision = getFirstCollision; | ||
exports.getAllCollisions = getAllCollisions; | ||
exports.getStatics = getStatics; | ||
exports.moveElement = moveElement; | ||
exports.moveElementAwayFromCollision = moveElementAwayFromCollision; | ||
exports.perc = perc; | ||
exports.setTransform = setTransform; | ||
exports.sortLayoutItemsByRowCol = sortLayoutItemsByRowCol; | ||
exports.synchronizeLayoutWithChildren = synchronizeLayoutWithChildren; | ||
exports.validateLayout = validateLayout; | ||
var utils = module.exports = { | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } | ||
/** | ||
* Return the bottom coordinate of the layout. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @return {Number} Bottom coordinate. | ||
*/ | ||
bottom: function bottom(layout) { | ||
var max = 0, | ||
bottomY; | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
bottomY = layout[i].y + layout[i].h; | ||
if (bottomY > max) max = bottomY; | ||
} | ||
return max; | ||
}, | ||
var _objectAssign = require('object-assign'); | ||
/** | ||
* Clones a shallow object. | ||
* @param {Object} obj Object to clone. | ||
* @return {Object} Cloned object. | ||
*/ | ||
clone: function clone(obj) { | ||
return assign({}, obj); | ||
}, | ||
var _objectAssign2 = _interopRequireDefault(_objectAssign); | ||
/** | ||
* Given two layouts, check if they collide. | ||
* | ||
* @param {Object} l1 Layout object. | ||
* @param {Object} l2 Layout object. | ||
* @return {Boolean} True if colliding. | ||
*/ | ||
collides: function collides(l1, l2) { | ||
if (l1 === l2) return false; // same element | ||
if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2 | ||
if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2 | ||
if (l1.y + l1.h <= l2.y) return false; // l1 is above l2 | ||
if (l1.y >= l2.y + l2.h) return false; // l1 is below l2 | ||
return true; // boxes overlap | ||
}, | ||
/** | ||
* Return the bottom coordinate of the layout. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @return {Number} Bottom coordinate. | ||
*/ | ||
/** | ||
* Given a layout, compact it. This involves going down each y coordinate and removing gaps | ||
* between items. | ||
* | ||
* @param {Array} layout Layout. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} Compacted Layout. | ||
*/ | ||
compact: function compact(layout, verticalCompact) { | ||
// Statics go in the compareWith array right away so items flow around them. | ||
var compareWith = utils.getStatics(layout), | ||
out = []; | ||
// We go through the items by row and column. | ||
var sorted = utils.sortLayoutItemsByRowCol(layout); | ||
function bottom(layout) { | ||
var max = 0, | ||
bottomY = undefined; | ||
for (var _i = 0, len = layout.length; _i < len; _i++) { | ||
bottomY = layout[_i].y + layout[_i].h; | ||
if (bottomY > max) max = bottomY; | ||
} | ||
return max; | ||
} | ||
for (var i = 0, len = sorted.length; i < len; i++) { | ||
var l = sorted[i]; | ||
/** | ||
* Clones a shallow object. | ||
* @param {Object} obj Object to clone. | ||
* @return {Object} Cloned object. | ||
*/ | ||
// Don't move static elements | ||
if (!l['static']) { | ||
l = utils.compactItem(compareWith, l, verticalCompact); | ||
function clone(obj) { | ||
return (0, _objectAssign2['default'])({}, obj); | ||
} | ||
// Add to comparison array. We only collide with items before this one. | ||
// Statics are already in this array. | ||
compareWith.push(l); | ||
} | ||
/** | ||
* Given two layoutitems, check if they collide. | ||
* | ||
* @return {Boolean} True if colliding. | ||
*/ | ||
// Add to output array to make sure they still come out in the right order. | ||
out[layout.indexOf(l)] = l; | ||
function collides(l1, l2) { | ||
if (l1 === l2) return false; // same element | ||
if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2 | ||
if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2 | ||
if (l1.y + l1.h <= l2.y) return false; // l1 is above l2 | ||
if (l1.y >= l2.y + l2.h) return false; // l1 is below l2 | ||
return true; // boxes overlap | ||
} | ||
// Clear moved flag, if it exists. | ||
delete l.moved; | ||
/** | ||
* Given a layout, compact it. This involves going down each y coordinate and removing gaps | ||
* between items. | ||
* | ||
* @param {Array} layout Layout. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} Compacted Layout. | ||
*/ | ||
function compact(layout, verticalCompact) { | ||
// Statics go in the compareWith array right away so items flow around them. | ||
var compareWith = getStatics(layout), | ||
out = []; | ||
// We go through the items by row and column. | ||
var sorted = sortLayoutItemsByRowCol(layout); | ||
for (var _i2 = 0, len = sorted.length; _i2 < len; _i2++) { | ||
var l = sorted[_i2]; | ||
// Don't move static elements | ||
if (!l['static']) { | ||
l = compactItem(compareWith, l, verticalCompact); | ||
// Add to comparison array. We only collide with items before this one. | ||
// Statics are already in this array. | ||
compareWith.push(l); | ||
} | ||
return out; | ||
}, | ||
// Add to output array to make sure they still come out in the right order. | ||
out[layout.indexOf(l)] = l; | ||
compactItem: function compactItem(compareWith, l, verticalCompact) { | ||
if (verticalCompact) { | ||
// Move the element up as far as it can go without colliding. | ||
while (l.y > 0 && !utils.getFirstCollision(compareWith, l)) { | ||
l.y--; | ||
} | ||
// Clear moved flag, if it exists. | ||
l.moved = false; | ||
} | ||
return out; | ||
} | ||
/** | ||
* Compact an item in the layout. | ||
*/ | ||
function compactItem(compareWith, l, verticalCompact) { | ||
if (verticalCompact) { | ||
// Move the element up as far as it can go without colliding. | ||
while (l.y > 0 && !getFirstCollision(compareWith, l)) { | ||
l.y--; | ||
} | ||
} | ||
// Move it down, and keep moving it down if it's colliding. | ||
var collides; | ||
while (collides = utils.getFirstCollision(compareWith, l)) { | ||
l.y = collides.y + collides.h; | ||
// Move it down, and keep moving it down if it's colliding. | ||
var collides = undefined; | ||
while (collides = getFirstCollision(compareWith, l)) { | ||
l.y = collides.y + collides.h; | ||
} | ||
return l; | ||
} | ||
/** | ||
* Given a layout, make sure all elements fit within its bounds. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @param {Number} bounds Number of columns. | ||
*/ | ||
function correctBounds(layout, bounds) { | ||
var collidesWith = getStatics(layout); | ||
for (var _i3 = 0, len = layout.length; _i3 < len; _i3++) { | ||
var l = layout[_i3]; | ||
// Overflows right | ||
if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w; | ||
// Overflows left | ||
if (l.x < 0) { | ||
l.x = 0; | ||
l.w = bounds.cols; | ||
} | ||
return l; | ||
}, | ||
/** | ||
* Given a layout, make sure all elements fit within its bounds. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @param {Number} bounds Number of columns. | ||
* @return {[type]} [description] | ||
*/ | ||
correctBounds: function correctBounds(layout, bounds) { | ||
var collidesWith = utils.getStatics(layout); | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
var l = layout[i]; | ||
// Overflows right | ||
if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w; | ||
// Overflows left | ||
if (l.x < 0) { | ||
l.x = 0; | ||
l.w = bounds.cols; | ||
if (!l['static']) collidesWith.push(l);else { | ||
// If this is static and collides with other statics, we must move it down. | ||
// We have to do something nicer than just letting them overlap. | ||
while (getFirstCollision(collidesWith, l)) { | ||
l.y++; | ||
} | ||
if (!l['static']) collidesWith.push(l);else { | ||
// If this is static and collides with other statics, we must move it down. | ||
// We have to do something nicer than just letting them overlap. | ||
while (utils.getFirstCollision(collidesWith, l)) { | ||
l.y++; | ||
} | ||
} | ||
} | ||
return layout; | ||
}, | ||
} | ||
return layout; | ||
} | ||
/** | ||
* Get a layout item by ID. Used so we can override later on if necessary. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @param {Number} id ID | ||
* @return {LayoutItem} Item at ID. | ||
*/ | ||
getLayoutItem: function getLayoutItem(layout, id) { | ||
id = "" + id; | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
if ("" + layout[i].i === id) return layout[i]; | ||
} | ||
}, | ||
/** | ||
* Get a layout item by ID. Used so we can override later on if necessary. | ||
* | ||
* @param {Array} layout Layout array. | ||
* @param {Number} id ID | ||
* @return {LayoutItem} Item at ID. | ||
*/ | ||
/** | ||
* Returns the first item this layout collides with. | ||
* It doesn't appear to matter which order we approach this from, although | ||
* perhaps that is the wrong thing to do. | ||
* | ||
* @param {Object} layoutItem Layout item. | ||
* @return {Object|undefined} A colliding layout item, or undefined. | ||
*/ | ||
getFirstCollision: function getFirstCollision(layout, layoutItem) { | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
if (utils.collides(layout[i], layoutItem)) return layout[i]; | ||
} | ||
}, | ||
function getLayoutItem(layout, id) { | ||
for (var _i4 = 0, len = layout.length; _i4 < len; _i4++) { | ||
if (layout[_i4].i === id) return layout[_i4]; | ||
} | ||
} | ||
getAllCollisions: function getAllCollisions(layout, layoutItem) { | ||
var out = []; | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
if (utils.collides(layout[i], layoutItem)) out.push(layout[i]); | ||
} | ||
return out; | ||
}, | ||
/** | ||
* Returns the first item this layout collides with. | ||
* It doesn't appear to matter which order we approach this from, although | ||
* perhaps that is the wrong thing to do. | ||
* | ||
* @param {Object} layoutItem Layout item. | ||
* @return {Object|undefined} A colliding layout item, or undefined. | ||
*/ | ||
/** | ||
* Get all static elements. | ||
* @param {Array} layout Array of layout objects. | ||
* @return {Array} Array of static layout items.. | ||
*/ | ||
getStatics: function getStatics(layout) { | ||
var out = []; | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
if (layout[i]['static']) out.push(layout[i]); | ||
} | ||
return out; | ||
}, | ||
function getFirstCollision(layout, layoutItem) { | ||
for (var _i5 = 0, len = layout.length; _i5 < len; _i5++) { | ||
if (collides(layout[_i5], layoutItem)) return layout[_i5]; | ||
} | ||
} | ||
/** | ||
* Move an element. Responsible for doing cascading movements of other elements. | ||
* | ||
* @param {Array} layout Full layout to modify. | ||
* @param {LayoutItem} l element to move. | ||
* @param {Number} [x] X position in grid units. | ||
* @param {Number} [y] Y position in grid units. | ||
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is | ||
* being dragged/resized by th euser. | ||
*/ | ||
moveElement: function moveElement(layout, l, x, y, isUserAction) { | ||
if (l['static']) return layout; | ||
function getAllCollisions(layout, layoutItem) { | ||
var out = []; | ||
for (var _i6 = 0, len = layout.length; _i6 < len; _i6++) { | ||
if (collides(layout[_i6], layoutItem)) out.push(layout[_i6]); | ||
} | ||
return out; | ||
} | ||
// Short-circuit if nothing to do. | ||
if (l.y === y && l.x === x) return layout; | ||
/** | ||
* Get all static elements. | ||
* @param {Array} layout Array of layout objects. | ||
* @return {Array} Array of static layout items.. | ||
*/ | ||
var movingUp = l.y > y; | ||
// This is quite a bit faster than extending the object | ||
if (x !== undefined) l.x = x; | ||
if (y !== undefined) l.y = y; | ||
l.moved = true; | ||
function getStatics(layout) { | ||
var out = []; | ||
for (var _i7 = 0, len = layout.length; _i7 < len; _i7++) { | ||
if (layout[_i7]['static']) out.push(layout[_i7]); | ||
} | ||
return out; | ||
} | ||
// If this collides with anything, move it. | ||
// When doing this comparison, we have to sort the items we compare with | ||
// to ensure, in the case of multiple collisions, that we're getting the | ||
// nearest collision. | ||
var sorted = utils.sortLayoutItemsByRowCol(layout); | ||
if (movingUp) sorted = sorted.reverse(); | ||
var collisions = utils.getAllCollisions(sorted, l); | ||
/** | ||
* Move an element. Responsible for doing cascading movements of other elements. | ||
* | ||
* @param {Array} layout Full layout to modify. | ||
* @param {LayoutItem} l element to move. | ||
* @param {Number} [x] X position in grid units. | ||
* @param {Number} [y] Y position in grid units. | ||
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is | ||
* being dragged/resized by th euser. | ||
*/ | ||
// Move each item that collides away from this element. | ||
for (var i = 0, len = collisions.length; i < len; i++) { | ||
var collision = collisions[i]; | ||
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y); | ||
function moveElement(layout, l, x, y, isUserAction) { | ||
if (l['static']) return layout; | ||
// Short circuit so we can't infinite loop | ||
if (collision.moved) continue; | ||
// Short-circuit if nothing to do. | ||
if (l.y === y && l.x === x) return layout; | ||
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up. | ||
if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue; | ||
var movingUp = y && l.y > y; | ||
// This is quite a bit faster than extending the object | ||
if (x != null) l.x = x; | ||
if (y != null) l.y = y; | ||
l.moved = true; | ||
// Don't move static items - we have to move *this* element away | ||
if (collision['static']) { | ||
layout = utils.moveElementAwayFromCollision(layout, collision, l, isUserAction); | ||
} else { | ||
layout = utils.moveElementAwayFromCollision(layout, l, collision, isUserAction); | ||
} | ||
// If this collides with anything, move it. | ||
// When doing this comparison, we have to sort the items we compare with | ||
// to ensure, in the case of multiple collisions, that we're getting the | ||
// nearest collision. | ||
var sorted = sortLayoutItemsByRowCol(layout); | ||
if (movingUp) sorted = sorted.reverse(); | ||
var collisions = getAllCollisions(sorted, l); | ||
// Move each item that collides away from this element. | ||
for (var _i8 = 0, len = collisions.length; _i8 < len; _i8++) { | ||
var collision = collisions[_i8]; | ||
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y); | ||
// Short circuit so we can't infinite loop | ||
if (collision.moved) continue; | ||
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up. | ||
if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue; | ||
// Don't move static items - we have to move *this* element away | ||
if (collision['static']) { | ||
layout = moveElementAwayFromCollision(layout, collision, l, isUserAction); | ||
} else { | ||
layout = moveElementAwayFromCollision(layout, l, collision, isUserAction); | ||
} | ||
} | ||
return layout; | ||
}, | ||
return layout; | ||
} | ||
/** | ||
* This is where the magic needs to happen - given a collision, move an element away from the collision. | ||
* We attempt to move it up if there's room, otherwise it goes below. | ||
* | ||
* @param {Array} layout Full layout to modify. | ||
* @param {LayoutItem} collidesWith Layout item we're colliding with. | ||
* @param {LayoutItem} itemToMove Layout item we're moving. | ||
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is being dragged/resized | ||
* by the user. | ||
*/ | ||
moveElementAwayFromCollision: function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAction) { | ||
/** | ||
* This is where the magic needs to happen - given a collision, move an element away from the collision. | ||
* We attempt to move it up if there's room, otherwise it goes below. | ||
* | ||
* @param {Array} layout Full layout to modify. | ||
* @param {LayoutItem} collidesWith Layout item we're colliding with. | ||
* @param {LayoutItem} itemToMove Layout item we're moving. | ||
* @param {Boolean} [isUserAction] If true, designates that the item we're moving is being dragged/resized | ||
* by the user. | ||
*/ | ||
// If there is enough space above the collision to put this element, move it there. | ||
// We only do this on the main collision as this can get funky in cascades and cause | ||
// unwanted swapping behavior. | ||
if (isUserAction) { | ||
// Make a mock item so we don't modify the item here, only modify in moveElement. | ||
var fakeItem = { | ||
x: itemToMove.x, | ||
y: itemToMove.y, | ||
w: itemToMove.w, | ||
h: itemToMove.h | ||
}; | ||
fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0); | ||
if (!utils.getFirstCollision(layout, fakeItem)) { | ||
return utils.moveElement(layout, itemToMove, undefined, fakeItem.y); | ||
} | ||
function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAction) { | ||
// If there is enough space above the collision to put this element, move it there. | ||
// We only do this on the main collision as this can get funky in cascades and cause | ||
// unwanted swapping behavior. | ||
if (isUserAction) { | ||
// Make a mock item so we don't modify the item here, only modify in moveElement. | ||
var fakeItem = { | ||
x: itemToMove.x, | ||
y: itemToMove.y, | ||
w: itemToMove.w, | ||
h: itemToMove.h, | ||
i: -1 | ||
}; | ||
fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0); | ||
if (!getFirstCollision(layout, fakeItem)) { | ||
return moveElement(layout, itemToMove, undefined, fakeItem.y); | ||
} | ||
} | ||
// Previously this was optimized to move below the collision directly, but this can cause problems | ||
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order. | ||
return utils.moveElement(layout, itemToMove, undefined, itemToMove.y + 1); | ||
}, | ||
// Previously this was optimized to move below the collision directly, but this can cause problems | ||
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order. | ||
return moveElement(layout, itemToMove, undefined, itemToMove.y + 1); | ||
} | ||
/** | ||
* Helper to convert a number to a percentage string. | ||
* | ||
* @param {Number} num Any number | ||
* @return {String} That number as a percentage. | ||
*/ | ||
perc: function perc(num) { | ||
return num * 100 + '%'; | ||
}, | ||
/** | ||
* Helper to convert a number to a percentage string. | ||
* | ||
* @param {Number} num Any number | ||
* @return {String} That number as a percentage. | ||
*/ | ||
setTransform: function setTransform(style, coords) { | ||
// Replace unitless items with px | ||
var x = ('' + coords[0]).replace(/(\d)$/, '$1px'); | ||
var y = ('' + coords[1]).replace(/(\d)$/, '$1px'); | ||
style.transform = "translate(" + x + "," + y + ")"; | ||
style.WebkitTransform = "translate(" + x + "," + y + ")"; | ||
style.MozTransform = "translate(" + x + "," + y + ")"; | ||
style.msTransform = "translate(" + x + "," + y + ")"; | ||
style.OTransform = "translate(" + x + "," + y + ")"; | ||
return style; | ||
}, | ||
function perc(num) { | ||
return num * 100 + '%'; | ||
} | ||
/** | ||
* Get layout items sorted from top left to right and down. | ||
* | ||
* @return {Array} Array of layout objects. | ||
* @return {Array} Layout, sorted static items first. | ||
*/ | ||
sortLayoutItemsByRowCol: function sortLayoutItemsByRowCol(layout) { | ||
return [].concat(layout).sort(function (a, b) { | ||
if (a.y > b.y || a.y === b.y && a.x > b.x) { | ||
return 1; | ||
} | ||
return -1; | ||
}); | ||
}, | ||
function setTransform(style, coords) { | ||
// Replace unitless items with px | ||
var x = ('' + coords[0]).replace(/(\d)$/, '$1px'); | ||
var y = ('' + coords[1]).replace(/(\d)$/, '$1px'); | ||
style.transform = "translate(" + x + "," + y + ")"; | ||
style.WebkitTransform = "translate(" + x + "," + y + ")"; | ||
style.MozTransform = "translate(" + x + "," + y + ")"; | ||
style.msTransform = "translate(" + x + "," + y + ")"; | ||
style.OTransform = "translate(" + x + "," + y + ")"; | ||
return style; | ||
} | ||
/** | ||
* Generate a layout using the initialLayout an children as a template. | ||
* Missing entries will be added, extraneous ones will be truncated. | ||
* | ||
* @param {Array} initialLayout Layout passed in through props. | ||
* @param {String} breakpoint Current responsive breakpoint. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} Working layout. | ||
*/ | ||
synchronizeLayoutWithChildren: function synchronizeLayoutWithChildren(initialLayout, children, cols, verticalCompact) { | ||
// ensure 'children' is always an array | ||
if (!Array.isArray(children)) { | ||
children = [children]; | ||
/** | ||
* Get layout items sorted from top left to right and down. | ||
* | ||
* @return {Array} Array of layout objects. | ||
* @return {Array} Layout, sorted static items first. | ||
*/ | ||
function sortLayoutItemsByRowCol(layout) { | ||
return [].concat(layout).sort(function (a, b) { | ||
if (a.y > b.y || a.y === b.y && a.x > b.x) { | ||
return 1; | ||
} | ||
initialLayout = initialLayout || []; | ||
return -1; | ||
}); | ||
} | ||
// Generate one layout item per child. | ||
var layout = []; | ||
for (var i = 0, len = children.length; i < len; i++) { | ||
var child = children[i]; | ||
// Don't overwrite if it already exists. | ||
var exists = utils.getLayoutItem(initialLayout, child.key); | ||
if (exists) { | ||
// Ensure 'i' is always a string | ||
exists.i = '' + exists.i; | ||
layout.push(exists); | ||
continue; | ||
} | ||
// New item: attempt to use a layout item from the child, if it exists. | ||
var g = child.props._grid; | ||
if (g) { | ||
utils.validateLayout([g], 'ReactGridLayout.child'); | ||
// Validated; add it to the layout. Bottom 'y' possible is the bottom of the layout. | ||
// This allows you to do nice stuff like specify {y: Infinity} | ||
if (verticalCompact) { | ||
layout.push(assign({}, g, { y: Math.min(utils.bottom(layout), g.y), i: child.key })); | ||
} else { | ||
layout.push(assign({}, g, { y: g.y, i: child.key })); | ||
} | ||
/** | ||
* Generate a layout using the initialLayout and children as a template. | ||
* Missing entries will be added, extraneous ones will be truncated. | ||
* | ||
* @param {Array} initialLayout Layout passed in through props. | ||
* @param {String} breakpoint Current responsive breakpoint. | ||
* @param {Boolean} verticalCompact Whether or not to compact the layout | ||
* vertically. | ||
* @return {Array} Working layout. | ||
*/ | ||
function synchronizeLayoutWithChildren(initialLayout, children, cols, verticalCompact) { | ||
// ensure 'children' is always an array | ||
if (!Array.isArray(children)) { | ||
children = [children]; | ||
} | ||
initialLayout = initialLayout || []; | ||
// Generate one layout item per child. | ||
var layout = []; | ||
for (var _i9 = 0, len = children.length; _i9 < len; _i9++) { | ||
var child = children[_i9]; | ||
// Don't overwrite if it already exists. | ||
var exists = getLayoutItem(initialLayout, parseInt(child.key || "1", /* FIXME satisfies Flow */10)); | ||
if (exists) { | ||
layout.push(exists); | ||
continue; | ||
} | ||
// New item: attempt to use a layout item from the child, if it exists. | ||
var g = child.props._grid; | ||
if (g) { | ||
validateLayout([g], 'ReactGridLayout.child'); | ||
// Validated; add it to the layout. Bottom 'y' possible is the bottom of the layout. | ||
// This allows you to do nice stuff like specify {y: Infinity} | ||
if (verticalCompact) { | ||
layout.push((0, _objectAssign2['default'])({}, g, { y: Math.min(bottom(layout), g.y), i: child.key })); | ||
} else { | ||
// Nothing provided: ensure this is added to the bottom | ||
layout.push({ w: 1, h: 1, x: 0, y: utils.bottom(layout), i: child.key }); | ||
layout.push((0, _objectAssign2['default'])({}, g, { y: g.y, i: child.key })); | ||
} | ||
} else { | ||
// Nothing provided: ensure this is added to the bottom | ||
layout.push({ w: 1, h: 1, x: 0, y: bottom(layout), i: parseInt(child.key || "1", 10) }); | ||
} | ||
} | ||
// Correct the layout. | ||
layout = utils.correctBounds(layout, { cols: cols }); | ||
layout = utils.compact(layout, verticalCompact); | ||
// Correct the layout. | ||
layout = correctBounds(layout, { cols: cols }); | ||
layout = compact(layout, verticalCompact); | ||
return layout; | ||
}, | ||
return layout; | ||
} | ||
/** | ||
* Validate a layout. Throws errors. | ||
* | ||
* @param {Array} layout Array of layout items. | ||
* @param {String} [contextName] Context name for errors. | ||
* @throw {Error} Validation error. | ||
*/ | ||
validateLayout: function validateLayout(layout, contextName) { | ||
contextName = contextName || "Layout"; | ||
var subProps = ['x', 'y', 'w', 'h']; | ||
if (!Array.isArray(layout)) throw new Error(contextName + " must be an array!"); | ||
for (var i = 0, len = layout.length; i < len; i++) { | ||
for (var j = 0; j < subProps.length; j++) { | ||
if (typeof layout[i][subProps[j]] !== 'number') { | ||
throw new Error('ReactGridLayout: ' + contextName + '[' + i + '].' + subProps[j] + ' must be a Number!'); | ||
} | ||
/** | ||
* Validate a layout. Throws errors. | ||
* | ||
* @param {Array} layout Array of layout items. | ||
* @param {String} [contextName] Context name for errors. | ||
* @throw {Error} Validation error. | ||
*/ | ||
function validateLayout(layout, contextName) { | ||
contextName = contextName || "Layout"; | ||
var subProps = ['x', 'y', 'w', 'h']; | ||
if (!Array.isArray(layout)) throw new Error(contextName + " must be an array!"); | ||
for (var _i10 = 0, len = layout.length; _i10 < len; _i10++) { | ||
for (var j = 0; j < subProps.length; j++) { | ||
if (typeof layout[_i10][subProps[j]] !== 'number') { | ||
throw new Error('ReactGridLayout: ' + contextName + '[' + _i10 + '].' + subProps[j] + ' must be a Number!'); | ||
} | ||
if (layout[i]['static'] !== undefined && typeof layout[i]['static'] !== 'boolean') { | ||
throw new Error('ReactGridLayout: ' + contextName + '[' + i + '].static must be a Boolean!'); | ||
} | ||
} | ||
if (layout[_i10]['static'] !== undefined && typeof layout[_i10]['static'] !== 'boolean') { | ||
throw new Error('ReactGridLayout: ' + contextName + '[' + _i10 + '].static must be a Boolean!'); | ||
} | ||
} | ||
}; | ||
} |
@@ -1,15 +0,35 @@ | ||
0.8.5 | ||
0.10.0-beta0 | ||
------------ | ||
*This release is unstable!* | ||
- React 0.14 compatibility. | ||
- This release includes a rewrite of much of the project in ES6/7 style with Flow typing. | ||
- This release brings us onto mainline (1.x) react-draggable and react-resizable, eliminating | ||
the previous github dependency. | ||
- 0.10.0 is not yet complete. Use this release at your own risk. | ||
Known bugs: | ||
- The placeholder box does not properly follow the mouse and stays pinned to the active drag. | ||
0.9.2 | ||
----- | ||
- Fixup for possible duplicated React external. | ||
- Update `react-draggable` to `v0.8.0` to fix IE11 issues (#29). | ||
0.8.4 | ||
0.9.1 | ||
----- | ||
- Update underlying react-draggable fork to remove emptyFunction import. | ||
- Update `react-draggable` to `v0.7.3` to fix a bounds bug (#56). | ||
0.9.0 | ||
----- | ||
- Move off `react-draggable` fork to mainline `v0.7.2`. Incremented minor (major in the case of | ||
npm's `^`, since we are pre-v1) version in case of unforeseen conflicts. | ||
0.8.3 | ||
----- | ||
- Add property to disable vertical compacting. | ||
- Add `verticalCompact` toggle. | ||
@@ -16,0 +36,0 @@ 0.8.2 |
{ | ||
"name": "react-grid-layout", | ||
"version": "0.8.5", | ||
"version": "0.10.0-beta0", | ||
"description": "A draggable and resizable grid layout with responsive breakpoints, for React.", | ||
"main": "index.js", | ||
"scripts": { | ||
"lint": "jsxhint lib/ test/", | ||
"lint": "eslint --ext .js,.jsx lib/ test/; flow", | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
@@ -12,3 +12,4 @@ "build": "bash build.sh", | ||
"dev": "echo 'Open http://localhost:4002'; webpack-dev-server --config webpack-dev-server.config.js --hot --progress --colors --port 4002 --content-base .", | ||
"prepublish": "npm run build" | ||
"prepublish": "npm run build", | ||
"validate": "valiquire ./lib" | ||
}, | ||
@@ -36,26 +37,34 @@ "repository": { | ||
"dependencies": { | ||
"deep-equal": "^1.0.0", | ||
"object-assign": "^2.0.0", | ||
"react-draggable": "strml/react-draggable#v0.3.3", | ||
"react-resizable": "^0.3.2" | ||
"deep-equal": "^1.0.1", | ||
"object-assign": "^4.0.1", | ||
"react-draggable": "^1.1.1", | ||
"react-resizable": "^1.0.1" | ||
}, | ||
"devDependencies": { | ||
"babel": "^5.0.1", | ||
"babel-core": "^5.0.1", | ||
"babel-loader": "^5.0.0", | ||
"babel-runtime": "^5.0.1", | ||
"css-loader": "^0.9.1", | ||
"ejs": "^2.3.1", | ||
"babel": "5.x", | ||
"babel-core": "^5.x", | ||
"babel-eslint": "^4.1.5", | ||
"babel-loader": "^5.x", | ||
"babel-plugin-react-class-display-name": "^0.1.0", | ||
"babel-plugin-react-transform": "^1.1.1", | ||
"babel-plugin-typecheck": "^2.0.0", | ||
"babel-runtime": "5.x", | ||
"css-loader": "^0.23.0", | ||
"ejs": "^2.3.4", | ||
"eslint": "^1.9.0", | ||
"eslint-plugin-react": "^3.9.0", | ||
"exports-loader": "^0.6.2", | ||
"imports-loader": "^0.6.3", | ||
"jsxhint": "^0.14.0", | ||
"lodash": "^3.6.0", | ||
"pre-commit": "^1.0.6", | ||
"precommit-hook": "^2.0.1", | ||
"react": "^0.13.1", | ||
"react-clonewithprops": "^1.0.1", | ||
"react-hot-loader": "^1.2.4", | ||
"style-loader": "^0.9.0", | ||
"webpack": "^1.7.3", | ||
"webpack-dev-server": "^1.8.0" | ||
"imports-loader": "^0.6.5", | ||
"jsxhint": "^0.15.1", | ||
"lodash": "^3.10.1", | ||
"pre-commit": "^1.1.2", | ||
"precommit-hook": "^3.0.0", | ||
"react": "^0.14.2", | ||
"react-dom": "^0.14.2", | ||
"react-hot-loader": "^1.3.0", | ||
"react-transform-hmr": "^1.0.1", | ||
"style-loader": "^0.13.0", | ||
"valiquire": "^0.3.0", | ||
"webpack": "^1.12.6", | ||
"webpack-dev-server": "^1.12.1" | ||
}, | ||
@@ -66,4 +75,5 @@ "publishConfig": { | ||
"pre-commit": [ | ||
"lint" | ||
"lint", | ||
"validate" | ||
] | ||
} |
@@ -200,3 +200,3 @@ # React-Grid-Layout | ||
// | ||
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e). | ||
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element). | ||
// 'start' and 'stop' callbacks pass `undefined` for 'placeholder'. | ||
@@ -246,2 +246,6 @@ // | ||
onLayoutChange: React.PropTypes.func | ||
// Callback when the width changes, so you can modify the layout as needed. | ||
// Calls back with (containerWidth, margin, cols) | ||
onWidthChange: React.Proptypes.func | ||
``` | ||
@@ -248,0 +252,0 @@ |
@@ -17,4 +17,19 @@ var webpack = require("webpack"); | ||
loaders: [ | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?stage=0'}, | ||
{test: /\.jsx$/, exclude: /node_modules/, loader: 'react-hot-loader'} | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', | ||
query: { | ||
cacheDirectory: true, | ||
plugins: ['react-transform'], | ||
extra: { | ||
'react-transform': { | ||
transforms: [ | ||
{ | ||
transform: 'react-transform-hmr', | ||
imports: ['react'], | ||
locals: ['module'] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
} | ||
] | ||
@@ -31,3 +46,3 @@ }, | ||
debug: true, | ||
devtool: 'eval', | ||
devtool: "#cheap-module-source-map", | ||
publicPath: '/examples/', | ||
@@ -34,0 +49,0 @@ resolve: { |
@@ -18,3 +18,3 @@ 'use strict'; | ||
loaders: [ | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?stage=0&optional=runtime'} | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime'} | ||
] | ||
@@ -21,0 +21,0 @@ }, |
@@ -1,47 +0,44 @@ | ||
'use strict'; | ||
var webpack = require('webpack'); | ||
var webpack = require("webpack"); | ||
// Builds bundle usable <script>. Includes RGL and all deps, excluding React. | ||
module.exports = { | ||
context: __dirname, | ||
entry: { | ||
'react-grid-layout': './index-dev.js' | ||
}, | ||
output: { | ||
path: __dirname + "/dist", | ||
filename: "[name].min.js", | ||
libraryTarget: "umd", | ||
library: "ReactGridLayout" | ||
}, | ||
devtool: 'source-map', | ||
externals: { | ||
'react': { | ||
'commonjs': 'react', | ||
'commonjs2': 'react', | ||
'amd': 'react', | ||
// React dep should be available as window.React, not window.react | ||
'root': 'React' | ||
context: __dirname, | ||
entry: { | ||
"react-grid-layout": "./index-dev.js" | ||
}, | ||
output: { | ||
path: __dirname + "/dist", | ||
filename: "[name].min.js", | ||
libraryTarget: "umd", | ||
library: "ReactGridLayout" | ||
}, | ||
devtool: "source-map", | ||
externals: { | ||
"react": { | ||
"commonjs": "react", | ||
"commonjs2": "react", | ||
"amd": "react", | ||
// React dep should be available as window.React, not window.react | ||
"root": "React" | ||
} | ||
}, | ||
module: { | ||
loaders: [ | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: "babel-loader"} | ||
] | ||
}, | ||
plugins: [ | ||
new webpack.DefinePlugin({ | ||
"process.env": { | ||
NODE_ENV: JSON.stringify("production") | ||
} | ||
}, | ||
module: { | ||
loaders: [ | ||
{test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?stage=0'} | ||
] | ||
}, | ||
plugins: [ | ||
new webpack.DefinePlugin({ | ||
"process.env": { | ||
NODE_ENV: JSON.stringify('production') | ||
} | ||
}), | ||
new webpack.optimize.OccurenceOrderPlugin(), | ||
new webpack.optimize.DedupePlugin(), | ||
// See #40 - duplicated React modules don't play nice | ||
new webpack.NormalModuleReplacementPlugin(/\/react\/lib\/cloneWithProps/, '../../react-clonewithprops/index.js'), | ||
// Compress, but don't print warnings to console | ||
new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) | ||
], | ||
resolve: { | ||
extensions: ["", ".webpack.js", ".web.js", ".js", ".jsx"] | ||
} | ||
}), | ||
new webpack.optimize.OccurenceOrderPlugin(), | ||
new webpack.optimize.DedupePlugin(), | ||
// Compress, but don't print warnings to console | ||
new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) | ||
], | ||
resolve: { | ||
extensions: ["", ".webpack.js", ".web.js", ".js", ".jsx"] | ||
} | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
91428
25.39%24
9.09%1656
14.6%334
1.21%0
-100%26
44.44%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
Updated
Updated
Updated
Updated