react-grid-layout 0.17.1 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc.js +10 -14
- package/.flowconfig +13 -1
- package/.travis.yml +3 -1
- package/CHANGELOG.md +66 -0
- package/README.md +47 -7
- package/__mocks__/react-grid-layout.js +2 -0
- package/build/GridItem.js +125 -211
- package/build/ReactGridLayout.js +142 -220
- package/build/ReactGridLayoutPropTypes.js +129 -0
- package/build/ResponsiveReactGridLayout.js +52 -44
- package/build/calculateUtils.js +177 -0
- package/build/components/WidthProvider.js +21 -11
- package/build/fastRGLPropsEqual.js +5 -0
- package/build/responsiveUtils.js +5 -5
- package/build/utils.js +77 -10
- package/css/styles.css +4 -0
- package/flow-typed/npm/classnames_v2.x.x.js +23 -0
- package/flow-typed/npm/enzyme_v3.x.x.js +143 -0
- package/flow-typed/npm/jest_v24.x.x.js +1182 -0
- package/lib/GridItem.jsx +125 -148
- package/lib/ReactGridLayout.jsx +83 -200
- package/lib/ReactGridLayoutPropTypes.js +179 -0
- package/lib/ResponsiveReactGridLayout.jsx +36 -28
- package/lib/calculateUtils.js +142 -0
- package/lib/components/WidthProvider.jsx +35 -16
- package/lib/fastRGLPropsEqual.js +46 -0
- package/lib/responsiveUtils.js +13 -20
- package/lib/utils.js +62 -10
- package/package.json +44 -29
package/lib/GridItem.jsx
CHANGED
|
@@ -4,7 +4,8 @@ import ReactDOM from "react-dom";
|
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
import { DraggableCore } from "react-draggable";
|
|
6
6
|
import { Resizable } from "react-resizable";
|
|
7
|
-
import { perc, setTopLeft, setTransform } from "./utils";
|
|
7
|
+
import { fastPositionEqual, perc, setTopLeft, setTransform } from "./utils";
|
|
8
|
+
import { calcGridItemPosition, calcXY, calcWH } from "./calculateUtils";
|
|
8
9
|
import classNames from "classnames";
|
|
9
10
|
import type { Element as ReactElement, Node as ReactNode } from "react";
|
|
10
11
|
|
|
@@ -16,6 +17,8 @@ import type {
|
|
|
16
17
|
Position
|
|
17
18
|
} from "./utils";
|
|
18
19
|
|
|
20
|
+
import type { PositionParams } from "./calculateUtils";
|
|
21
|
+
|
|
19
22
|
type PartialPosition = { top: number, left: number };
|
|
20
23
|
type GridItemCallback<Data: GridDragEvent | GridResizeEvent> = (
|
|
21
24
|
i: string,
|
|
@@ -151,8 +154,8 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
151
154
|
// Current position of a dropping element
|
|
152
155
|
droppingPosition: PropTypes.shape({
|
|
153
156
|
e: PropTypes.object.isRequired,
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
left: PropTypes.number.isRequired,
|
|
158
|
+
top: PropTypes.number.isRequired
|
|
156
159
|
})
|
|
157
160
|
};
|
|
158
161
|
|
|
@@ -175,19 +178,53 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
175
178
|
|
|
176
179
|
currentNode: HTMLElement;
|
|
177
180
|
|
|
181
|
+
shouldComponentUpdate(nextProps: Props, nextState: State) {
|
|
182
|
+
// We can't deeply compare children. If the developer memoizes them, we can
|
|
183
|
+
// use this optimization.
|
|
184
|
+
if (this.props.children !== nextProps.children) return true;
|
|
185
|
+
if (this.props.droppingPosition !== nextProps.droppingPosition) return true;
|
|
186
|
+
// TODO memoize these calculations so they don't take so long?
|
|
187
|
+
const oldPosition = calcGridItemPosition(
|
|
188
|
+
this.getPositionParams(this.props),
|
|
189
|
+
this.props.x,
|
|
190
|
+
this.props.y,
|
|
191
|
+
this.props.w,
|
|
192
|
+
this.props.h,
|
|
193
|
+
this.state
|
|
194
|
+
);
|
|
195
|
+
const newPosition = calcGridItemPosition(
|
|
196
|
+
this.getPositionParams(nextProps),
|
|
197
|
+
nextProps.x,
|
|
198
|
+
nextProps.y,
|
|
199
|
+
nextProps.w,
|
|
200
|
+
nextProps.h,
|
|
201
|
+
nextState
|
|
202
|
+
);
|
|
203
|
+
return (
|
|
204
|
+
!fastPositionEqual(oldPosition, newPosition) ||
|
|
205
|
+
this.props.useCSSTransforms !== nextProps.useCSSTransforms
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
componentDidMount() {
|
|
210
|
+
this.moveDroppingItem({});
|
|
211
|
+
}
|
|
212
|
+
|
|
178
213
|
componentDidUpdate(prevProps: Props) {
|
|
179
|
-
|
|
180
|
-
this.moveDroppingItem(prevProps);
|
|
181
|
-
}
|
|
214
|
+
this.moveDroppingItem(prevProps);
|
|
182
215
|
}
|
|
183
216
|
|
|
217
|
+
// When a droppingPosition is present, this means we should fire a move event, as if we had moved
|
|
218
|
+
// this element by `x, y` pixels.
|
|
184
219
|
moveDroppingItem(prevProps: Props) {
|
|
185
220
|
const { droppingPosition } = this.props;
|
|
186
|
-
|
|
221
|
+
if (!droppingPosition) return;
|
|
187
222
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
223
|
+
const prevDroppingPosition = prevProps.droppingPosition || {
|
|
224
|
+
left: 0,
|
|
225
|
+
top: 0
|
|
226
|
+
};
|
|
227
|
+
const { dragging } = this.state;
|
|
191
228
|
|
|
192
229
|
if (!this.currentNode) {
|
|
193
230
|
// eslint-disable-next-line react/no-find-dom-node
|
|
@@ -195,18 +232,18 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
195
232
|
}
|
|
196
233
|
|
|
197
234
|
const shouldDrag =
|
|
198
|
-
(dragging && droppingPosition.
|
|
199
|
-
droppingPosition.
|
|
235
|
+
(dragging && droppingPosition.left !== prevDroppingPosition.left) ||
|
|
236
|
+
droppingPosition.top !== prevDroppingPosition.top;
|
|
200
237
|
|
|
201
238
|
if (!dragging) {
|
|
202
239
|
this.onDragStart(droppingPosition.e, {
|
|
203
240
|
node: this.currentNode,
|
|
204
|
-
deltaX: droppingPosition.
|
|
205
|
-
deltaY: droppingPosition.
|
|
241
|
+
deltaX: droppingPosition.left,
|
|
242
|
+
deltaY: droppingPosition.top
|
|
206
243
|
});
|
|
207
244
|
} else if (shouldDrag) {
|
|
208
|
-
const deltaX = droppingPosition.
|
|
209
|
-
const deltaY = droppingPosition.
|
|
245
|
+
const deltaX = droppingPosition.left - dragging.left;
|
|
246
|
+
const deltaY = droppingPosition.top - dragging.top;
|
|
210
247
|
|
|
211
248
|
this.onDrag(droppingPosition.e, {
|
|
212
249
|
node: this.currentNode,
|
|
@@ -216,121 +253,15 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
216
253
|
}
|
|
217
254
|
}
|
|
218
255
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
* Return position on the page given an x, y, w, h.
|
|
229
|
-
* left, top, width, height are all in pixels.
|
|
230
|
-
* @param {Number} x X coordinate in grid units.
|
|
231
|
-
* @param {Number} y Y coordinate in grid units.
|
|
232
|
-
* @param {Number} w W coordinate in grid units.
|
|
233
|
-
* @param {Number} h H coordinate in grid units.
|
|
234
|
-
* @return {Object} Object containing coords.
|
|
235
|
-
*/
|
|
236
|
-
calcPosition(
|
|
237
|
-
x: number,
|
|
238
|
-
y: number,
|
|
239
|
-
w: number,
|
|
240
|
-
h: number,
|
|
241
|
-
state: ?Object
|
|
242
|
-
): Position {
|
|
243
|
-
const { margin, containerPadding, rowHeight } = this.props;
|
|
244
|
-
const colWidth = this.calcColWidth();
|
|
245
|
-
const out = {};
|
|
246
|
-
|
|
247
|
-
// If resizing, use the exact width and height as returned from resizing callbacks.
|
|
248
|
-
if (state && state.resizing) {
|
|
249
|
-
out.width = Math.round(state.resizing.width);
|
|
250
|
-
out.height = Math.round(state.resizing.height);
|
|
251
|
-
}
|
|
252
|
-
// Otherwise, calculate from grid units.
|
|
253
|
-
else {
|
|
254
|
-
// 0 * Infinity === NaN, which causes problems with resize constraints;
|
|
255
|
-
// Fix this if it occurs.
|
|
256
|
-
// Note we do it here rather than later because Math.round(Infinity) causes deopt
|
|
257
|
-
out.width =
|
|
258
|
-
w === Infinity
|
|
259
|
-
? w
|
|
260
|
-
: Math.round(colWidth * w + Math.max(0, w - 1) * margin[0]);
|
|
261
|
-
out.height =
|
|
262
|
-
h === Infinity
|
|
263
|
-
? h
|
|
264
|
-
: Math.round(rowHeight * h + Math.max(0, h - 1) * margin[1]);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// If dragging, use the exact width and height as returned from dragging callbacks.
|
|
268
|
-
if (state && state.dragging) {
|
|
269
|
-
out.top = Math.round(state.dragging.top);
|
|
270
|
-
out.left = Math.round(state.dragging.left);
|
|
271
|
-
}
|
|
272
|
-
// Otherwise, calculate from grid units.
|
|
273
|
-
else {
|
|
274
|
-
out.top = Math.round((rowHeight + margin[1]) * y + containerPadding[1]);
|
|
275
|
-
out.left = Math.round((colWidth + margin[0]) * x + containerPadding[0]);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return out;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Translate x and y coordinates from pixels to grid units.
|
|
283
|
-
* @param {Number} top Top position (relative to parent) in pixels.
|
|
284
|
-
* @param {Number} left Left position (relative to parent) in pixels.
|
|
285
|
-
* @return {Object} x and y in grid units.
|
|
286
|
-
*/
|
|
287
|
-
calcXY(top: number, left: number): { x: number, y: number } {
|
|
288
|
-
const { margin, cols, rowHeight, w, h, maxRows } = this.props;
|
|
289
|
-
const colWidth = this.calcColWidth();
|
|
290
|
-
|
|
291
|
-
// left = colWidth * x + margin * (x + 1)
|
|
292
|
-
// l = cx + m(x+1)
|
|
293
|
-
// l = cx + mx + m
|
|
294
|
-
// l - m = cx + mx
|
|
295
|
-
// l - m = x(c + m)
|
|
296
|
-
// (l - m) / (c + m) = x
|
|
297
|
-
// x = (left - margin) / (coldWidth + margin)
|
|
298
|
-
let x = Math.round((left - margin[0]) / (colWidth + margin[0]));
|
|
299
|
-
let y = Math.round((top - margin[1]) / (rowHeight + margin[1]));
|
|
300
|
-
|
|
301
|
-
// Capping
|
|
302
|
-
x = Math.max(Math.min(x, cols - w), 0);
|
|
303
|
-
y = Math.max(Math.min(y, maxRows - h), 0);
|
|
304
|
-
|
|
305
|
-
return { x, y };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Given a height and width in pixel values, calculate grid units.
|
|
310
|
-
* @param {Number} height Height in pixels.
|
|
311
|
-
* @param {Number} width Width in pixels.
|
|
312
|
-
* @return {Object} w, h as grid units.
|
|
313
|
-
*/
|
|
314
|
-
calcWH({
|
|
315
|
-
height,
|
|
316
|
-
width
|
|
317
|
-
}: {
|
|
318
|
-
height: number,
|
|
319
|
-
width: number
|
|
320
|
-
}): { w: number, h: number } {
|
|
321
|
-
const { margin, maxRows, cols, rowHeight, x, y } = this.props;
|
|
322
|
-
const colWidth = this.calcColWidth();
|
|
323
|
-
|
|
324
|
-
// width = colWidth * w - (margin * (w - 1))
|
|
325
|
-
// ...
|
|
326
|
-
// w = (width + margin) / (colWidth + margin)
|
|
327
|
-
let w = Math.round((width + margin[0]) / (colWidth + margin[0]));
|
|
328
|
-
let h = Math.round((height + margin[1]) / (rowHeight + margin[1]));
|
|
329
|
-
|
|
330
|
-
// Capping
|
|
331
|
-
w = Math.max(Math.min(w, cols - x), 0);
|
|
332
|
-
h = Math.max(Math.min(h, maxRows - y), 0);
|
|
333
|
-
return { w, h };
|
|
256
|
+
getPositionParams(props: Props = this.props): PositionParams {
|
|
257
|
+
return {
|
|
258
|
+
cols: props.cols,
|
|
259
|
+
containerPadding: props.containerPadding,
|
|
260
|
+
containerWidth: props.containerWidth,
|
|
261
|
+
margin: props.margin,
|
|
262
|
+
maxRows: props.maxRows,
|
|
263
|
+
rowHeight: props.rowHeight
|
|
264
|
+
};
|
|
334
265
|
}
|
|
335
266
|
|
|
336
267
|
/**
|
|
@@ -369,9 +300,13 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
369
300
|
* @param {Element} child Child element.
|
|
370
301
|
* @return {Element} Child wrapped in Draggable.
|
|
371
302
|
*/
|
|
372
|
-
mixinDraggable(
|
|
303
|
+
mixinDraggable(
|
|
304
|
+
child: ReactElement<any>,
|
|
305
|
+
isDraggable: boolean
|
|
306
|
+
): ReactElement<any> {
|
|
373
307
|
return (
|
|
374
308
|
<DraggableCore
|
|
309
|
+
disabled={!isDraggable}
|
|
375
310
|
onStart={this.onDragStart}
|
|
376
311
|
onDrag={this.onDrag}
|
|
377
312
|
onStop={this.onDragStop}
|
|
@@ -395,16 +330,19 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
395
330
|
*/
|
|
396
331
|
mixinResizable(
|
|
397
332
|
child: ReactElement<any>,
|
|
398
|
-
position: Position
|
|
333
|
+
position: Position,
|
|
334
|
+
isResizable: boolean
|
|
399
335
|
): ReactElement<any> {
|
|
400
|
-
const { cols, x, minW, minH, maxW, maxH } = this.props;
|
|
336
|
+
const { cols, x, minW, minH, maxW, maxH, transformScale } = this.props;
|
|
337
|
+
const positionParams = this.getPositionParams();
|
|
401
338
|
|
|
402
339
|
// This is the max possible width - doesn't go to infinity because of the width of the window
|
|
403
|
-
const maxWidth =
|
|
340
|
+
const maxWidth = calcGridItemPosition(positionParams, 0, 0, cols - x, 0)
|
|
341
|
+
.width;
|
|
404
342
|
|
|
405
343
|
// Calculate min/max constraints using our min & maxes
|
|
406
|
-
const mins =
|
|
407
|
-
const maxes =
|
|
344
|
+
const mins = calcGridItemPosition(positionParams, 0, 0, minW, minH);
|
|
345
|
+
const maxes = calcGridItemPosition(positionParams, 0, 0, maxW, maxH);
|
|
408
346
|
const minConstraints = [mins.width, mins.height];
|
|
409
347
|
const maxConstraints = [
|
|
410
348
|
Math.min(maxes.width, maxWidth),
|
|
@@ -412,6 +350,10 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
412
350
|
];
|
|
413
351
|
return (
|
|
414
352
|
<Resizable
|
|
353
|
+
draggableOpts={{
|
|
354
|
+
disabled: !isResizable
|
|
355
|
+
}}
|
|
356
|
+
className={isResizable ? undefined : "react-resizable-hide"}
|
|
415
357
|
width={position.width}
|
|
416
358
|
height={position.height}
|
|
417
359
|
minConstraints={minConstraints}
|
|
@@ -419,6 +361,7 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
419
361
|
onResizeStop={this.onResizeStop}
|
|
420
362
|
onResizeStart={this.onResizeStart}
|
|
421
363
|
onResize={this.onResize}
|
|
364
|
+
transformScale={transformScale}
|
|
422
365
|
>
|
|
423
366
|
{child}
|
|
424
367
|
</Resizable>
|
|
@@ -448,7 +391,13 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
448
391
|
newPosition.top = cTop - pTop + offsetParent.scrollTop;
|
|
449
392
|
this.setState({ dragging: newPosition });
|
|
450
393
|
|
|
451
|
-
const { x, y } =
|
|
394
|
+
const { x, y } = calcXY(
|
|
395
|
+
this.getPositionParams(),
|
|
396
|
+
newPosition.top,
|
|
397
|
+
newPosition.left,
|
|
398
|
+
this.props.w,
|
|
399
|
+
this.props.h
|
|
400
|
+
);
|
|
452
401
|
|
|
453
402
|
return (
|
|
454
403
|
this.props.onDragStart &&
|
|
@@ -466,7 +415,10 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
466
415
|
* @param {Object} callbackData an object with node, delta and position information
|
|
467
416
|
*/
|
|
468
417
|
onDrag = (e: Event, { node, deltaX, deltaY }: ReactDraggableCallbackData) => {
|
|
469
|
-
|
|
418
|
+
const { onDrag, transformScale } = this.props;
|
|
419
|
+
if (!onDrag) return;
|
|
420
|
+
deltaX /= transformScale;
|
|
421
|
+
deltaY /= transformScale;
|
|
470
422
|
|
|
471
423
|
const newPosition: PartialPosition = { top: 0, left: 0 };
|
|
472
424
|
|
|
@@ -476,11 +428,17 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
476
428
|
newPosition.top = this.state.dragging.top + deltaY;
|
|
477
429
|
this.setState({ dragging: newPosition });
|
|
478
430
|
|
|
479
|
-
const { x, y } =
|
|
431
|
+
const { x, y } = calcXY(
|
|
432
|
+
this.getPositionParams(),
|
|
433
|
+
newPosition.top,
|
|
434
|
+
newPosition.left,
|
|
435
|
+
this.props.w,
|
|
436
|
+
this.props.h
|
|
437
|
+
);
|
|
480
438
|
|
|
481
439
|
return (
|
|
482
|
-
|
|
483
|
-
|
|
440
|
+
onDrag &&
|
|
441
|
+
onDrag.call(this, this.props.i, x, y, {
|
|
484
442
|
e,
|
|
485
443
|
node,
|
|
486
444
|
newPosition
|
|
@@ -504,7 +462,13 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
504
462
|
newPosition.top = this.state.dragging.top;
|
|
505
463
|
this.setState({ dragging: null });
|
|
506
464
|
|
|
507
|
-
const { x, y } =
|
|
465
|
+
const { x, y } = calcXY(
|
|
466
|
+
this.getPositionParams(),
|
|
467
|
+
newPosition.top,
|
|
468
|
+
newPosition.left,
|
|
469
|
+
this.props.w,
|
|
470
|
+
this.props.h
|
|
471
|
+
);
|
|
508
472
|
|
|
509
473
|
return (
|
|
510
474
|
this.props.onDragStop &&
|
|
@@ -567,10 +531,16 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
567
531
|
) {
|
|
568
532
|
const handler = this.props[handlerName];
|
|
569
533
|
if (!handler) return;
|
|
570
|
-
const { cols, x, i, maxW, minW, maxH, minH } = this.props;
|
|
534
|
+
const { cols, x, y, i, maxW, minW, maxH, minH } = this.props;
|
|
571
535
|
|
|
572
536
|
// Get new XY
|
|
573
|
-
let { w, h } =
|
|
537
|
+
let { w, h } = calcWH(
|
|
538
|
+
this.getPositionParams(),
|
|
539
|
+
size.width,
|
|
540
|
+
size.height,
|
|
541
|
+
x,
|
|
542
|
+
y
|
|
543
|
+
);
|
|
574
544
|
|
|
575
545
|
// Cap w at numCols
|
|
576
546
|
w = Math.min(w, cols - x);
|
|
@@ -598,7 +568,14 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
598
568
|
useCSSTransforms
|
|
599
569
|
} = this.props;
|
|
600
570
|
|
|
601
|
-
const pos =
|
|
571
|
+
const pos = calcGridItemPosition(
|
|
572
|
+
this.getPositionParams(),
|
|
573
|
+
x,
|
|
574
|
+
y,
|
|
575
|
+
w,
|
|
576
|
+
h,
|
|
577
|
+
this.state
|
|
578
|
+
);
|
|
602
579
|
const child = React.Children.only(this.props.children);
|
|
603
580
|
|
|
604
581
|
// Create the child element. We clone the existing element but modify its className and style.
|
|
@@ -625,10 +602,10 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
625
602
|
});
|
|
626
603
|
|
|
627
604
|
// Resizable support. This is usually on but the user can toggle it off.
|
|
628
|
-
|
|
605
|
+
newChild = this.mixinResizable(newChild, pos, isResizable);
|
|
629
606
|
|
|
630
607
|
// Draggable support. This is always on, except for with placeholders.
|
|
631
|
-
|
|
608
|
+
newChild = this.mixinDraggable(newChild, isDraggable);
|
|
632
609
|
|
|
633
610
|
return newChild;
|
|
634
611
|
}
|