react-grid-layout 0.18.2 → 1.1.1
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 +5 -3
- package/.flowconfig +2 -5
- package/.travis.yml +2 -1
- package/CHANGELOG.md +53 -0
- package/README.md +33 -9
- package/build/GridItem.js +129 -75
- package/build/ReactGridLayout.js +67 -59
- package/build/ReactGridLayoutPropTypes.js +15 -1
- package/build/ResponsiveReactGridLayout.js +33 -24
- package/build/calculateUtils.js +35 -9
- package/build/components/WidthProvider.js +14 -12
- package/build/fastRGLPropsEqual.js +1 -1
- package/build/responsiveUtils.js +5 -5
- package/build/utils.js +36 -10
- package/dist/react-grid-layout.min.js +7 -0
- package/dist/react-grid-layout.min.js.map +1 -0
- package/lib/GridItem.jsx +101 -69
- package/lib/ReactGridLayout.jsx +19 -5
- package/lib/ReactGridLayoutPropTypes.js +29 -14
- package/lib/ResponsiveReactGridLayout.jsx +16 -17
- package/lib/calculateUtils.js +27 -16
- package/lib/responsiveUtils.js +16 -21
- package/lib/utils.js +36 -11
- package/package.json +46 -36
- package/interfaces/classnames.js +0 -16
package/lib/GridItem.jsx
CHANGED
|
@@ -5,7 +5,14 @@ import PropTypes from "prop-types";
|
|
|
5
5
|
import { DraggableCore } from "react-draggable";
|
|
6
6
|
import { Resizable } from "react-resizable";
|
|
7
7
|
import { fastPositionEqual, perc, setTopLeft, setTransform } from "./utils";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
calcGridItemPosition,
|
|
10
|
+
calcGridItemWHPx,
|
|
11
|
+
calcGridColWidth,
|
|
12
|
+
calcXY,
|
|
13
|
+
calcWH,
|
|
14
|
+
clamp
|
|
15
|
+
} from "./calculateUtils";
|
|
9
16
|
import classNames from "classnames";
|
|
10
17
|
import type { Element as ReactElement, Node as ReactNode } from "react";
|
|
11
18
|
|
|
@@ -43,6 +50,7 @@ type Props = {
|
|
|
43
50
|
maxRows: number,
|
|
44
51
|
isDraggable: boolean,
|
|
45
52
|
isResizable: boolean,
|
|
53
|
+
isBounded: boolean,
|
|
46
54
|
static?: boolean,
|
|
47
55
|
useCSSTransforms?: boolean,
|
|
48
56
|
usePercentages?: boolean,
|
|
@@ -66,6 +74,8 @@ type Props = {
|
|
|
66
74
|
maxH: number,
|
|
67
75
|
i: string,
|
|
68
76
|
|
|
77
|
+
resizeHandles?: Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'>,
|
|
78
|
+
|
|
69
79
|
onDrag?: GridItemCallback<GridDragEvent>,
|
|
70
80
|
onDragStart?: GridItemCallback<GridDragEvent>,
|
|
71
81
|
onDragStop?: GridItemCallback<GridDragEvent>,
|
|
@@ -97,28 +107,28 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
97
107
|
h: PropTypes.number.isRequired,
|
|
98
108
|
|
|
99
109
|
// All optional
|
|
100
|
-
minW: function(props: Props, propName: string) {
|
|
110
|
+
minW: function (props: Props, propName: string) {
|
|
101
111
|
const value = props[propName];
|
|
102
112
|
if (typeof value !== "number") return new Error("minWidth not Number");
|
|
103
113
|
if (value > props.w || value > props.maxW)
|
|
104
114
|
return new Error("minWidth larger than item width/maxWidth");
|
|
105
115
|
},
|
|
106
116
|
|
|
107
|
-
maxW: function(props: Props, propName: string) {
|
|
117
|
+
maxW: function (props: Props, propName: string) {
|
|
108
118
|
const value = props[propName];
|
|
109
119
|
if (typeof value !== "number") return new Error("maxWidth not Number");
|
|
110
120
|
if (value < props.w || value < props.minW)
|
|
111
121
|
return new Error("maxWidth smaller than item width/minWidth");
|
|
112
122
|
},
|
|
113
123
|
|
|
114
|
-
minH: function(props: Props, propName: string) {
|
|
124
|
+
minH: function (props: Props, propName: string) {
|
|
115
125
|
const value = props[propName];
|
|
116
126
|
if (typeof value !== "number") return new Error("minHeight not Number");
|
|
117
127
|
if (value > props.h || value > props.maxH)
|
|
118
128
|
return new Error("minHeight larger than item height/maxHeight");
|
|
119
129
|
},
|
|
120
130
|
|
|
121
|
-
maxH: function(props: Props, propName: string) {
|
|
131
|
+
maxH: function (props: Props, propName: string) {
|
|
122
132
|
const value = props[propName];
|
|
123
133
|
if (typeof value !== "number") return new Error("maxHeight not Number");
|
|
124
134
|
if (value < props.h || value < props.minH)
|
|
@@ -139,6 +149,7 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
139
149
|
// Flags
|
|
140
150
|
isDraggable: PropTypes.bool.isRequired,
|
|
141
151
|
isResizable: PropTypes.bool.isRequired,
|
|
152
|
+
isBounded: PropTypes.bool.isRequired,
|
|
142
153
|
static: PropTypes.bool,
|
|
143
154
|
|
|
144
155
|
// Use CSS transforms instead of top/left
|
|
@@ -182,6 +193,7 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
182
193
|
// We can't deeply compare children. If the developer memoizes them, we can
|
|
183
194
|
// use this optimization.
|
|
184
195
|
if (this.props.children !== nextProps.children) return true;
|
|
196
|
+
if (this.props.droppingPosition !== nextProps.droppingPosition) return true;
|
|
185
197
|
// TODO memoize these calculations so they don't take so long?
|
|
186
198
|
const oldPosition = calcGridItemPosition(
|
|
187
199
|
this.getPositionParams(this.props),
|
|
@@ -205,6 +217,10 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
205
217
|
);
|
|
206
218
|
}
|
|
207
219
|
|
|
220
|
+
componentDidMount() {
|
|
221
|
+
this.moveDroppingItem({});
|
|
222
|
+
}
|
|
223
|
+
|
|
208
224
|
componentDidUpdate(prevProps: Props) {
|
|
209
225
|
this.moveDroppingItem(prevProps);
|
|
210
226
|
}
|
|
@@ -213,12 +229,13 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
213
229
|
// this element by `x, y` pixels.
|
|
214
230
|
moveDroppingItem(prevProps: Props) {
|
|
215
231
|
const { droppingPosition } = this.props;
|
|
216
|
-
|
|
217
|
-
const { dragging } = this.state;
|
|
232
|
+
if (!droppingPosition) return;
|
|
218
233
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
234
|
+
const prevDroppingPosition = prevProps.droppingPosition || {
|
|
235
|
+
left: 0,
|
|
236
|
+
top: 0
|
|
237
|
+
};
|
|
238
|
+
const { dragging } = this.state;
|
|
222
239
|
|
|
223
240
|
if (!this.currentNode) {
|
|
224
241
|
// eslint-disable-next-line react/no-find-dom-node
|
|
@@ -327,7 +344,16 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
327
344
|
position: Position,
|
|
328
345
|
isResizable: boolean
|
|
329
346
|
): ReactElement<any> {
|
|
330
|
-
const {
|
|
347
|
+
const {
|
|
348
|
+
cols,
|
|
349
|
+
x,
|
|
350
|
+
minW,
|
|
351
|
+
minH,
|
|
352
|
+
maxW,
|
|
353
|
+
maxH,
|
|
354
|
+
transformScale,
|
|
355
|
+
resizeHandles
|
|
356
|
+
} = this.props;
|
|
331
357
|
const positionParams = this.getPositionParams();
|
|
332
358
|
|
|
333
359
|
// This is the max possible width - doesn't go to infinity because of the width of the window
|
|
@@ -356,6 +382,7 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
356
382
|
onResizeStart={this.onResizeStart}
|
|
357
383
|
onResize={this.onResize}
|
|
358
384
|
transformScale={transformScale}
|
|
385
|
+
resizeHandles={resizeHandles}
|
|
359
386
|
>
|
|
360
387
|
{child}
|
|
361
388
|
</Resizable>
|
|
@@ -368,7 +395,8 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
368
395
|
* @param {Object} callbackData an object with node, delta and position information
|
|
369
396
|
*/
|
|
370
397
|
onDragStart = (e: Event, { node }: ReactDraggableCallbackData) => {
|
|
371
|
-
|
|
398
|
+
const { onDragStart } = this.props;
|
|
399
|
+
if (!onDragStart) return;
|
|
372
400
|
|
|
373
401
|
const newPosition: PartialPosition = { top: 0, left: 0 };
|
|
374
402
|
|
|
@@ -385,6 +413,7 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
385
413
|
newPosition.top = cTop - pTop + offsetParent.scrollTop;
|
|
386
414
|
this.setState({ dragging: newPosition });
|
|
387
415
|
|
|
416
|
+
// Call callback with this data
|
|
388
417
|
const { x, y } = calcXY(
|
|
389
418
|
this.getPositionParams(),
|
|
390
419
|
newPosition.top,
|
|
@@ -393,14 +422,11 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
393
422
|
this.props.h
|
|
394
423
|
);
|
|
395
424
|
|
|
396
|
-
return (
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
newPosition
|
|
402
|
-
})
|
|
403
|
-
);
|
|
425
|
+
return onDragStart.call(this, this.props.i, x, y, {
|
|
426
|
+
e,
|
|
427
|
+
node,
|
|
428
|
+
newPosition
|
|
429
|
+
});
|
|
404
430
|
};
|
|
405
431
|
|
|
406
432
|
/**
|
|
@@ -414,30 +440,42 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
414
440
|
deltaX /= transformScale;
|
|
415
441
|
deltaY /= transformScale;
|
|
416
442
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
if (!this.state.dragging)
|
|
443
|
+
if (!this.state.dragging) {
|
|
420
444
|
throw new Error("onDrag called before onDragStart.");
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
this.
|
|
445
|
+
}
|
|
446
|
+
let top = this.state.dragging.top + deltaY;
|
|
447
|
+
let left = this.state.dragging.left + deltaX;
|
|
424
448
|
|
|
425
|
-
const {
|
|
426
|
-
|
|
427
|
-
newPosition.top,
|
|
428
|
-
newPosition.left,
|
|
429
|
-
this.props.w,
|
|
430
|
-
this.props.h
|
|
431
|
-
);
|
|
449
|
+
const { isBounded, i, w, h, containerWidth } = this.props;
|
|
450
|
+
const positionParams = this.getPositionParams();
|
|
432
451
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
452
|
+
// Boundary calculations; keeps items within the grid
|
|
453
|
+
if (isBounded) {
|
|
454
|
+
const { offsetParent } = node;
|
|
455
|
+
|
|
456
|
+
if (offsetParent) {
|
|
457
|
+
const { margin, rowHeight } = this.props;
|
|
458
|
+
const bottomBoundary =
|
|
459
|
+
offsetParent.clientHeight - calcGridItemWHPx(h, rowHeight, margin[1]);
|
|
460
|
+
top = clamp(top, 0, bottomBoundary);
|
|
461
|
+
|
|
462
|
+
const colWidth = calcGridColWidth(positionParams);
|
|
463
|
+
const rightBoundary =
|
|
464
|
+
containerWidth - calcGridItemWHPx(w, colWidth, margin[0]);
|
|
465
|
+
left = clamp(left, 0, rightBoundary);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const newPosition: PartialPosition = { top, left };
|
|
470
|
+
this.setState({ dragging: newPosition });
|
|
471
|
+
|
|
472
|
+
// Call callback with this data
|
|
473
|
+
const { x, y } = calcXY(positionParams, top, left, w, h);
|
|
474
|
+
return onDrag.call(this, i, x, y, {
|
|
475
|
+
e,
|
|
476
|
+
node,
|
|
477
|
+
newPosition
|
|
478
|
+
});
|
|
441
479
|
};
|
|
442
480
|
|
|
443
481
|
/**
|
|
@@ -446,32 +484,24 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
446
484
|
* @param {Object} callbackData an object with node, delta and position information
|
|
447
485
|
*/
|
|
448
486
|
onDragStop = (e: Event, { node }: ReactDraggableCallbackData) => {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const newPosition: PartialPosition = { top: 0, left: 0 };
|
|
487
|
+
const { onDragStop } = this.props;
|
|
488
|
+
if (!onDragStop) return;
|
|
452
489
|
|
|
453
|
-
if (!this.state.dragging)
|
|
490
|
+
if (!this.state.dragging) {
|
|
454
491
|
throw new Error("onDragEnd called before onDragStart.");
|
|
455
|
-
|
|
456
|
-
|
|
492
|
+
}
|
|
493
|
+
const { w, h, i } = this.props;
|
|
494
|
+
const { left, top } = this.state.dragging;
|
|
495
|
+
const newPosition: PartialPosition = { top, left };
|
|
457
496
|
this.setState({ dragging: null });
|
|
458
497
|
|
|
459
|
-
const { x, y } = calcXY(
|
|
460
|
-
this.getPositionParams(),
|
|
461
|
-
newPosition.top,
|
|
462
|
-
newPosition.left,
|
|
463
|
-
this.props.w,
|
|
464
|
-
this.props.h
|
|
465
|
-
);
|
|
498
|
+
const { x, y } = calcXY(this.getPositionParams(), top, left, w, h);
|
|
466
499
|
|
|
467
|
-
return (
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
newPosition
|
|
473
|
-
})
|
|
474
|
-
);
|
|
500
|
+
return onDragStop.call(this, i, x, y, {
|
|
501
|
+
e,
|
|
502
|
+
node,
|
|
503
|
+
newPosition
|
|
504
|
+
});
|
|
475
505
|
};
|
|
476
506
|
|
|
477
507
|
/**
|
|
@@ -525,7 +555,8 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
525
555
|
) {
|
|
526
556
|
const handler = this.props[handlerName];
|
|
527
557
|
if (!handler) return;
|
|
528
|
-
const { cols, x, y, i,
|
|
558
|
+
const { cols, x, y, i, maxH, minH } = this.props;
|
|
559
|
+
let { minW, maxW } = this.props;
|
|
529
560
|
|
|
530
561
|
// Get new XY
|
|
531
562
|
let { w, h } = calcWH(
|
|
@@ -536,14 +567,15 @@ export default class GridItem extends React.Component<Props, State> {
|
|
|
536
567
|
y
|
|
537
568
|
);
|
|
538
569
|
|
|
539
|
-
//
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
570
|
+
// minW should be at least 1 (TODO propTypes validation?)
|
|
571
|
+
minW = Math.max(minW, 1);
|
|
572
|
+
|
|
573
|
+
// maxW should be at most (cols - x)
|
|
574
|
+
maxW = Math.min(maxW, cols - x);
|
|
543
575
|
|
|
544
576
|
// Min/max capping
|
|
545
|
-
w =
|
|
546
|
-
h =
|
|
577
|
+
w = clamp(w, minW, maxW);
|
|
578
|
+
h = clamp(h, minH, maxH);
|
|
547
579
|
|
|
548
580
|
this.setState({ resizing: handlerName === "onResizeStop" ? null : size });
|
|
549
581
|
|
package/lib/ReactGridLayout.jsx
CHANGED
|
@@ -91,6 +91,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
91
91
|
maxRows: Infinity, // infinite vertical growth
|
|
92
92
|
layout: [],
|
|
93
93
|
margin: [10, 10],
|
|
94
|
+
isBounded: false,
|
|
94
95
|
isDraggable: true,
|
|
95
96
|
isResizable: true,
|
|
96
97
|
isDroppable: false,
|
|
@@ -104,6 +105,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
104
105
|
h: 1,
|
|
105
106
|
w: 1
|
|
106
107
|
},
|
|
108
|
+
resizeHandles: ["se"],
|
|
107
109
|
onLayoutChange: noop,
|
|
108
110
|
onDragStart: noop,
|
|
109
111
|
onDrag: noop,
|
|
@@ -202,7 +204,9 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
202
204
|
// handle changes properly, performance will increase.
|
|
203
205
|
this.props.children !== nextProps.children ||
|
|
204
206
|
!fastRGLPropsEqual(this.props, nextProps, isEqual) ||
|
|
205
|
-
|
|
207
|
+
this.state.activeDrag !== nextState.activeDrag ||
|
|
208
|
+
this.state.mounted !== nextState.mounted ||
|
|
209
|
+
this.state.droppingPosition !== nextState.droppingPosition
|
|
206
210
|
);
|
|
207
211
|
}
|
|
208
212
|
|
|
@@ -476,6 +480,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
476
480
|
rowHeight={rowHeight}
|
|
477
481
|
isDraggable={false}
|
|
478
482
|
isResizable={false}
|
|
483
|
+
isBounded={false}
|
|
479
484
|
useCSSTransforms={useCSSTransforms}
|
|
480
485
|
transformScale={transformScale}
|
|
481
486
|
>
|
|
@@ -505,10 +510,12 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
505
510
|
maxRows,
|
|
506
511
|
isDraggable,
|
|
507
512
|
isResizable,
|
|
513
|
+
isBounded,
|
|
508
514
|
useCSSTransforms,
|
|
509
515
|
transformScale,
|
|
510
516
|
draggableCancel,
|
|
511
|
-
draggableHandle
|
|
517
|
+
draggableHandle,
|
|
518
|
+
resizeHandles
|
|
512
519
|
} = this.props;
|
|
513
520
|
const { mounted, droppingPosition } = this.state;
|
|
514
521
|
|
|
@@ -523,6 +530,10 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
523
530
|
typeof l.isResizable === "boolean"
|
|
524
531
|
? l.isResizable
|
|
525
532
|
: !l.static && isResizable;
|
|
533
|
+
const resizeHandlesOptions = l.resizeHandles || resizeHandles;
|
|
534
|
+
|
|
535
|
+
// isBounded set on child if set on parent, and child is not explicitly false
|
|
536
|
+
const bounded = draggable && isBounded && l.isBounded !== false;
|
|
526
537
|
|
|
527
538
|
return (
|
|
528
539
|
<GridItem
|
|
@@ -542,6 +553,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
542
553
|
onResizeStop={this.onResizeStop}
|
|
543
554
|
isDraggable={draggable}
|
|
544
555
|
isResizable={resizable}
|
|
556
|
+
isBounded={bounded}
|
|
545
557
|
useCSSTransforms={useCSSTransforms && mounted}
|
|
546
558
|
usePercentages={!mounted}
|
|
547
559
|
transformScale={transformScale}
|
|
@@ -556,6 +568,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
556
568
|
maxW={l.maxW}
|
|
557
569
|
static={l.static}
|
|
558
570
|
droppingPosition={isDroppingItem ? droppingPosition : undefined}
|
|
571
|
+
resizeHandles={resizeHandlesOptions}
|
|
559
572
|
>
|
|
560
573
|
{child}
|
|
561
574
|
</GridItem>
|
|
@@ -671,18 +684,18 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
671
684
|
onDrop = (e: Event) => {
|
|
672
685
|
const { droppingItem } = this.props;
|
|
673
686
|
const { layout } = this.state;
|
|
674
|
-
const
|
|
687
|
+
const item = layout.find(l => l.i === droppingItem.i);
|
|
675
688
|
|
|
676
689
|
// reset gragEnter counter on drop
|
|
677
690
|
this.dragEnterCounter = 0;
|
|
678
691
|
|
|
679
692
|
this.removeDroppingPlaceholder();
|
|
680
693
|
|
|
681
|
-
this.props.onDrop(
|
|
694
|
+
this.props.onDrop(layout, item, e);
|
|
682
695
|
};
|
|
683
696
|
|
|
684
697
|
render() {
|
|
685
|
-
const { className, style, isDroppable } = this.props;
|
|
698
|
+
const { className, style, isDroppable, innerRef } = this.props;
|
|
686
699
|
|
|
687
700
|
const mergedClassName = classNames(layoutClassName, className);
|
|
688
701
|
const mergedStyle = {
|
|
@@ -692,6 +705,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
|
|
|
692
705
|
|
|
693
706
|
return (
|
|
694
707
|
<div
|
|
708
|
+
ref={innerRef}
|
|
695
709
|
className={mergedClassName}
|
|
696
710
|
style={mergedStyle}
|
|
697
711
|
onDrop={isDroppable ? this.onDrop : noop}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import type {
|
|
5
|
+
Ref,
|
|
5
6
|
ChildrenArray as ReactChildrenArray,
|
|
6
7
|
Element as ReactElement
|
|
7
8
|
} from "react";
|
|
@@ -19,9 +20,10 @@ export type Props = {|
|
|
|
19
20
|
compactType: CompactType,
|
|
20
21
|
layout: Layout,
|
|
21
22
|
margin: [number, number],
|
|
22
|
-
containerPadding: [number, number]
|
|
23
|
+
containerPadding: ?[number, number],
|
|
23
24
|
rowHeight: number,
|
|
24
25
|
maxRows: number,
|
|
26
|
+
isBounded: boolean,
|
|
25
27
|
isDraggable: boolean,
|
|
26
28
|
isResizable: boolean,
|
|
27
29
|
isDroppable: boolean,
|
|
@@ -29,6 +31,7 @@ export type Props = {|
|
|
|
29
31
|
useCSSTransforms: boolean,
|
|
30
32
|
transformScale: number,
|
|
31
33
|
droppingItem: $Shape<LayoutItem>,
|
|
34
|
+
resizeHandles: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">,
|
|
32
35
|
|
|
33
36
|
// Callbacks
|
|
34
37
|
onLayoutChange: Layout => void,
|
|
@@ -38,14 +41,9 @@ export type Props = {|
|
|
|
38
41
|
onResize: EventCallback,
|
|
39
42
|
onResizeStart: EventCallback,
|
|
40
43
|
onResizeStop: EventCallback,
|
|
41
|
-
onDrop: (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
w: number,
|
|
45
|
-
h: number,
|
|
46
|
-
e: Event
|
|
47
|
-
}) => void,
|
|
48
|
-
children: ReactChildrenArray<ReactElement<any>>
|
|
44
|
+
onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void,
|
|
45
|
+
children: ReactChildrenArray<ReactElement<any>>,
|
|
46
|
+
innerRef?: Ref<"div">
|
|
49
47
|
|};
|
|
50
48
|
|
|
51
49
|
export default {
|
|
@@ -71,7 +69,7 @@ export default {
|
|
|
71
69
|
draggableHandle: PropTypes.string,
|
|
72
70
|
|
|
73
71
|
// Deprecated
|
|
74
|
-
verticalCompact: function(props: Props) {
|
|
72
|
+
verticalCompact: function (props: Props) {
|
|
75
73
|
if (
|
|
76
74
|
props.verticalCompact === false &&
|
|
77
75
|
process.env.NODE_ENV !== "production"
|
|
@@ -88,7 +86,7 @@ export default {
|
|
|
88
86
|
|
|
89
87
|
// layout is an array of object with the format:
|
|
90
88
|
// {x: Number, y: Number, w: Number, h: Number, i: String}
|
|
91
|
-
layout: function(props: Props) {
|
|
89
|
+
layout: function (props: Props) {
|
|
92
90
|
var layout = props.layout;
|
|
93
91
|
// I hope you're setting the data-grid property on the grid items
|
|
94
92
|
if (layout === undefined) return;
|
|
@@ -115,6 +113,7 @@ export default {
|
|
|
115
113
|
//
|
|
116
114
|
// Flags
|
|
117
115
|
//
|
|
116
|
+
isBounded: PropTypes.bool,
|
|
118
117
|
isDraggable: PropTypes.bool,
|
|
119
118
|
isResizable: PropTypes.bool,
|
|
120
119
|
// If true, grid items won't change position when being dragged over.
|
|
@@ -125,6 +124,19 @@ export default {
|
|
|
125
124
|
transformScale: PropTypes.number,
|
|
126
125
|
// If true, an external element can trigger onDrop callback with a specific grid position as a parameter
|
|
127
126
|
isDroppable: PropTypes.bool,
|
|
127
|
+
// Defines which resize handles should be rendered (default: 'se')
|
|
128
|
+
// Allows for any combination of:
|
|
129
|
+
// 's' - South handle (bottom-center)
|
|
130
|
+
// 'w' - West handle (left-center)
|
|
131
|
+
// 'e' - East handle (right-center)
|
|
132
|
+
// 'n' - North handle (top-center)
|
|
133
|
+
// 'sw' - Southwest handle (bottom-left)
|
|
134
|
+
// 'nw' - Northwest handle (top-left)
|
|
135
|
+
// 'se' - Southeast handle (bottom-right)
|
|
136
|
+
// 'ne' - Northeast handle (top-right)
|
|
137
|
+
resizeHandles: PropTypes.arrayOf(
|
|
138
|
+
PropTypes.oneOf(["s", "w", "e", "n", "sw", "nw", "se", "ne"])
|
|
139
|
+
),
|
|
128
140
|
|
|
129
141
|
//
|
|
130
142
|
// Callbacks
|
|
@@ -160,12 +172,12 @@ export default {
|
|
|
160
172
|
}),
|
|
161
173
|
|
|
162
174
|
// Children must not have duplicate keys.
|
|
163
|
-
children: function(props: Props, propName: string) {
|
|
175
|
+
children: function (props: Props, propName: string) {
|
|
164
176
|
var children = props[propName];
|
|
165
177
|
|
|
166
178
|
// Check children keys for duplicates. Throw if found.
|
|
167
179
|
var keys = {};
|
|
168
|
-
React.Children.forEach(children, function(child) {
|
|
180
|
+
React.Children.forEach(children, function (child) {
|
|
169
181
|
if (keys[child.key]) {
|
|
170
182
|
throw new Error(
|
|
171
183
|
'Duplicate child key "' +
|
|
@@ -175,5 +187,8 @@ export default {
|
|
|
175
187
|
}
|
|
176
188
|
keys[child.key] = true;
|
|
177
189
|
});
|
|
178
|
-
}
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
// Optional ref for getting a reference for the wrapping div.
|
|
193
|
+
innerRef: PropTypes.any
|
|
179
194
|
};
|
|
@@ -7,15 +7,17 @@ import {
|
|
|
7
7
|
cloneLayout,
|
|
8
8
|
synchronizeLayoutWithChildren,
|
|
9
9
|
validateLayout,
|
|
10
|
-
noop
|
|
10
|
+
noop,
|
|
11
|
+
type Layout
|
|
11
12
|
} from "./utils";
|
|
12
13
|
import {
|
|
13
14
|
getBreakpointFromWidth,
|
|
14
15
|
getColsFromBreakpoint,
|
|
15
|
-
findOrGenerateResponsiveLayout
|
|
16
|
+
findOrGenerateResponsiveLayout,
|
|
17
|
+
type ResponsiveLayout,
|
|
18
|
+
type Breakpoints
|
|
16
19
|
} from "./responsiveUtils";
|
|
17
20
|
import ReactGridLayout from "./ReactGridLayout";
|
|
18
|
-
import type { Layout } from "./utils";
|
|
19
21
|
|
|
20
22
|
const type = obj => Object.prototype.toString.call(obj);
|
|
21
23
|
|
|
@@ -27,10 +29,12 @@ const type = obj => Object.prototype.toString.call(obj);
|
|
|
27
29
|
* @return {Array}
|
|
28
30
|
*/
|
|
29
31
|
|
|
30
|
-
function getIndentationValue(
|
|
31
|
-
param: { [key: string]:
|
|
32
|
+
function getIndentationValue<T: ?[number, number]>(
|
|
33
|
+
param: { [key: string]: T } | T,
|
|
32
34
|
breakpoint: string
|
|
33
|
-
) {
|
|
35
|
+
): T {
|
|
36
|
+
// $FlowIssue doesn't seem to understand this
|
|
37
|
+
if (param == null) return null;
|
|
34
38
|
return Array.isArray(param) ? param : param[breakpoint];
|
|
35
39
|
}
|
|
36
40
|
|
|
@@ -46,12 +50,13 @@ type Props<Breakpoint: string = string> = {|
|
|
|
46
50
|
|
|
47
51
|
// Responsive config
|
|
48
52
|
breakpoint?: ?Breakpoint,
|
|
49
|
-
breakpoints:
|
|
53
|
+
breakpoints: Breakpoints<Breakpoint>,
|
|
50
54
|
cols: { [key: Breakpoint]: number },
|
|
51
|
-
layouts:
|
|
55
|
+
layouts: ResponsiveLayout<Breakpoint>,
|
|
52
56
|
width: number,
|
|
53
57
|
margin: { [key: Breakpoint]: [number, number] } | [number, number],
|
|
54
|
-
|
|
58
|
+
/* prettier-ignore */
|
|
59
|
+
containerPadding: { [key: Breakpoint]: ?[number, number] } | ?[number, number],
|
|
55
60
|
|
|
56
61
|
// Callbacks
|
|
57
62
|
onBreakpointChange: (Breakpoint, cols: number) => void,
|
|
@@ -60,7 +65,7 @@ type Props<Breakpoint: string = string> = {|
|
|
|
60
65
|
containerWidth: number,
|
|
61
66
|
margin: [number, number],
|
|
62
67
|
cols: number,
|
|
63
|
-
containerPadding: [number, number]
|
|
68
|
+
containerPadding: ?[number, number]
|
|
64
69
|
) => void
|
|
65
70
|
|};
|
|
66
71
|
|
|
@@ -140,13 +145,7 @@ export default class ResponsiveReactGridLayout extends React.Component<
|
|
|
140
145
|
cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
|
|
141
146
|
layouts: {},
|
|
142
147
|
margin: [10, 10],
|
|
143
|
-
containerPadding: {
|
|
144
|
-
lg: [0, 0],
|
|
145
|
-
md: [0, 0],
|
|
146
|
-
sm: [0, 0],
|
|
147
|
-
xs: [0, 0],
|
|
148
|
-
xxs: [0, 0]
|
|
149
|
-
},
|
|
148
|
+
containerPadding: { lg: null, md: null, sm: null, xs: null, xxs: null },
|
|
150
149
|
onBreakpointChange: noop,
|
|
151
150
|
onLayoutChange: noop,
|
|
152
151
|
onWidthChange: noop
|
package/lib/calculateUtils.js
CHANGED
|
@@ -18,6 +18,22 @@ export function calcGridColWidth(positionParams: PositionParams): number {
|
|
|
18
18
|
);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
// This can either be called:
|
|
22
|
+
// calcGridItemWHPx(w, colWidth, margin[0])
|
|
23
|
+
// or
|
|
24
|
+
// calcGridItemWHPx(h, rowHeight, margin[1])
|
|
25
|
+
export function calcGridItemWHPx(
|
|
26
|
+
gridUnits: number,
|
|
27
|
+
colOrRowSize: number,
|
|
28
|
+
marginPx: number
|
|
29
|
+
) {
|
|
30
|
+
// 0 * Infinity === NaN, which causes problems with resize contraints
|
|
31
|
+
if (!Number.isFinite(gridUnits)) return gridUnits;
|
|
32
|
+
return Math.round(
|
|
33
|
+
colOrRowSize * gridUnits + Math.max(0, gridUnits - 1) * marginPx
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* Return position on the page given an x, y, w, h.
|
|
23
39
|
* left, top, width, height are all in pixels.
|
|
@@ -47,17 +63,8 @@ export function calcGridItemPosition(
|
|
|
47
63
|
}
|
|
48
64
|
// Otherwise, calculate from grid units.
|
|
49
65
|
else {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
// Note we do it here rather than later because Math.round(Infinity) causes deopt
|
|
53
|
-
out.width =
|
|
54
|
-
w === Infinity
|
|
55
|
-
? w
|
|
56
|
-
: Math.round(colWidth * w + Math.max(0, w - 1) * margin[0]);
|
|
57
|
-
out.height =
|
|
58
|
-
h === Infinity
|
|
59
|
-
? h
|
|
60
|
-
: Math.round(rowHeight * h + Math.max(0, h - 1) * margin[1]);
|
|
66
|
+
out.width = calcGridItemWHPx(w, colWidth, margin[0]);
|
|
67
|
+
out.height = calcGridItemWHPx(h, rowHeight, margin[1]);
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
// If dragging, use the exact width and height as returned from dragging callbacks.
|
|
@@ -104,9 +111,8 @@ export function calcXY(
|
|
|
104
111
|
let y = Math.round((top - margin[1]) / (rowHeight + margin[1]));
|
|
105
112
|
|
|
106
113
|
// Capping
|
|
107
|
-
x =
|
|
108
|
-
y =
|
|
109
|
-
|
|
114
|
+
x = clamp(x, 0, cols - w);
|
|
115
|
+
y = clamp(y, 0, maxRows - h);
|
|
110
116
|
return { x, y };
|
|
111
117
|
}
|
|
112
118
|
|
|
@@ -136,7 +142,12 @@ export function calcWH(
|
|
|
136
142
|
let h = Math.round((height + margin[1]) / (rowHeight + margin[1]));
|
|
137
143
|
|
|
138
144
|
// Capping
|
|
139
|
-
w =
|
|
140
|
-
h =
|
|
145
|
+
w = clamp(w, 0, cols - x);
|
|
146
|
+
h = clamp(h, 0, maxRows - y);
|
|
141
147
|
return { w, h };
|
|
142
148
|
}
|
|
149
|
+
|
|
150
|
+
// Similar to _.clamp
|
|
151
|
+
export function clamp(num: number, lowerBound: number, upperBound: number) {
|
|
152
|
+
return Math.max(Math.min(num, upperBound), lowerBound);
|
|
153
|
+
}
|