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/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 { calcGridItemPosition, calcXY, calcWH } from "./calculateUtils";
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
- const prevDroppingPosition = prevProps.droppingPosition;
217
- const { dragging } = this.state;
232
+ if (!droppingPosition) return;
218
233
 
219
- if (!droppingPosition || !prevDroppingPosition) {
220
- return;
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 { cols, x, minW, minH, maxW, maxH, transformScale } = this.props;
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
- if (!this.props.onDragStart) return;
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
- this.props.onDragStart &&
398
- this.props.onDragStart.call(this, this.props.i, x, y, {
399
- e,
400
- node,
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
- const newPosition: PartialPosition = { top: 0, left: 0 };
418
-
419
- if (!this.state.dragging)
443
+ if (!this.state.dragging) {
420
444
  throw new Error("onDrag called before onDragStart.");
421
- newPosition.left = this.state.dragging.left + deltaX;
422
- newPosition.top = this.state.dragging.top + deltaY;
423
- this.setState({ dragging: newPosition });
445
+ }
446
+ let top = this.state.dragging.top + deltaY;
447
+ let left = this.state.dragging.left + deltaX;
424
448
 
425
- const { x, y } = calcXY(
426
- this.getPositionParams(),
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
- return (
434
- onDrag &&
435
- onDrag.call(this, this.props.i, x, y, {
436
- e,
437
- node,
438
- newPosition
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
- if (!this.props.onDragStop) return;
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
- newPosition.left = this.state.dragging.left;
456
- newPosition.top = this.state.dragging.top;
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
- this.props.onDragStop &&
469
- this.props.onDragStop.call(this, this.props.i, x, y, {
470
- e,
471
- node,
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, maxW, minW, maxH, minH } = this.props;
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
- // Cap w at numCols
540
- w = Math.min(w, cols - x);
541
- // Ensure w is at least 1
542
- w = Math.max(w, 1);
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 = Math.max(Math.min(w, maxW), minW);
546
- h = Math.max(Math.min(h, maxH), minH);
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
 
@@ -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
- !isEqual(this.state.activeDrag, nextState.activeDrag)
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 { x, y, w, h } = layout.find(l => l.i === droppingItem.i) || {};
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({ x, y, w, h, e });
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] | null,
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: (itemPosition: {
42
- x: number,
43
- y: number,
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]: [number, number] } | [number, number],
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: { [key: Breakpoint]: number },
53
+ breakpoints: Breakpoints<Breakpoint>,
50
54
  cols: { [key: Breakpoint]: number },
51
- layouts: { [key: Breakpoint]: Layout },
55
+ layouts: ResponsiveLayout<Breakpoint>,
52
56
  width: number,
53
57
  margin: { [key: Breakpoint]: [number, number] } | [number, number],
54
- containerPadding: { [key: Breakpoint]: [number, number] } | [number, number],
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] | null
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
@@ -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
- // 0 * Infinity === NaN, which causes problems with resize constraints;
51
- // Fix this if it occurs.
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 = Math.max(Math.min(x, cols - w), 0);
108
- y = Math.max(Math.min(y, maxRows - h), 0);
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 = Math.max(Math.min(w, cols - x), 0);
140
- h = Math.max(Math.min(h, maxRows - y), 0);
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
+ }