react-grid-layout 0.16.4 → 0.17.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.
@@ -28,7 +28,9 @@ import type {
28
28
  CompactType,
29
29
  GridResizeEvent,
30
30
  GridDragEvent,
31
+ DragOverEvent,
31
32
  Layout,
33
+ DroppingPosition,
32
34
  LayoutItem
33
35
  } from "./utils";
34
36
 
@@ -38,7 +40,13 @@ type State = {
38
40
  mounted: boolean,
39
41
  oldDragItem: ?LayoutItem,
40
42
  oldLayout: ?Layout,
41
- oldResizeItem: ?LayoutItem
43
+ oldResizeItem: ?LayoutItem,
44
+ droppingDOMNode: ?ReactElement<any>,
45
+ droppingPosition?: DroppingPosition,
46
+ // Mirrored props
47
+ children: ReactChildrenArray<ReactElement<any>>,
48
+ compactType?: CompactType,
49
+ propsLayout?: Layout
42
50
  };
43
51
 
44
52
  export type Props = {
@@ -50,7 +58,7 @@ export type Props = {
50
58
  draggableCancel: string,
51
59
  draggableHandle: string,
52
60
  verticalCompact: boolean,
53
- compactType: ?("horizontal" | "vertical"),
61
+ compactType: CompactType,
54
62
  layout: Layout,
55
63
  margin: [number, number],
56
64
  containerPadding: [number, number] | null,
@@ -58,8 +66,11 @@ export type Props = {
58
66
  maxRows: number,
59
67
  isDraggable: boolean,
60
68
  isResizable: boolean,
69
+ isDroppable: boolean,
61
70
  preventCollision: boolean,
62
71
  useCSSTransforms: boolean,
72
+ transformScale: number,
73
+ droppingItem: $Shape<LayoutItem>,
63
74
 
64
75
  // Callbacks
65
76
  onLayoutChange: Layout => void,
@@ -69,10 +80,31 @@ export type Props = {
69
80
  onResize: EventCallback,
70
81
  onResizeStart: EventCallback,
71
82
  onResizeStop: EventCallback,
83
+ onDrop: (itemPosition: {
84
+ x: number,
85
+ y: number,
86
+ w: number,
87
+ h: number
88
+ }) => void,
72
89
  children: ReactChildrenArray<ReactElement<any>>
73
90
  };
74
91
  // End Types
75
92
 
93
+ const compactType = (props: Props): CompactType => {
94
+ const { verticalCompact, compactType } = props || {};
95
+
96
+ return verticalCompact === false ? null : compactType;
97
+ };
98
+
99
+ const layoutClassName = "react-grid-layout";
100
+ let isFirefox = false;
101
+ // Try...catch will protect from navigator not existing (e.g. node) or a bad implementation of navigator
102
+ try {
103
+ isFirefox = navigator.userAgent.toLowerCase().includes("firefox");
104
+ } catch (e) {
105
+ /* Ignore */
106
+ }
107
+
76
108
  /**
77
109
  * A reactive, fluid grid layout with draggable, resizable components.
78
110
  */
@@ -154,6 +186,10 @@ export default class ReactGridLayout extends React.Component<Props, State> {
154
186
  preventCollision: PropTypes.bool,
155
187
  // Use CSS transforms instead of top/left
156
188
  useCSSTransforms: PropTypes.bool,
189
+ // parent layout transform scale
190
+ transformScale: PropTypes.number,
191
+ // If true, an external element can trigger onDrop callback with a specific grid position as a parameter
192
+ isDroppable: PropTypes.bool,
157
193
 
158
194
  //
159
195
  // Callbacks
@@ -175,11 +211,19 @@ export default class ReactGridLayout extends React.Component<Props, State> {
175
211
  onResize: PropTypes.func,
176
212
  // Calls when resize is complete.
177
213
  onResizeStop: PropTypes.func,
214
+ // Calls when some element is dropped.
215
+ onDrop: PropTypes.func,
178
216
 
179
217
  //
180
218
  // Other validations
181
219
  //
182
220
 
221
+ droppingItem: PropTypes.shape({
222
+ i: PropTypes.string.isRequired,
223
+ w: PropTypes.number.isRequired,
224
+ h: PropTypes.number.isRequired
225
+ }),
226
+
183
227
  // Children must not have duplicate keys.
184
228
  children: function(props: Props, propName: string) {
185
229
  var children = props[propName];
@@ -213,17 +257,25 @@ export default class ReactGridLayout extends React.Component<Props, State> {
213
257
  margin: [10, 10],
214
258
  isDraggable: true,
215
259
  isResizable: true,
260
+ isDroppable: false,
216
261
  useCSSTransforms: true,
262
+ transformScale: 1,
217
263
  verticalCompact: true,
218
264
  compactType: "vertical",
219
265
  preventCollision: false,
266
+ droppingItem: {
267
+ i: "__dropping-elem__",
268
+ h: 1,
269
+ w: 1
270
+ },
220
271
  onLayoutChange: noop,
221
272
  onDragStart: noop,
222
273
  onDrag: noop,
223
274
  onDragStop: noop,
224
275
  onResizeStart: noop,
225
276
  onResize: noop,
226
- onResizeStop: noop
277
+ onResizeStop: noop,
278
+ onDrop: noop
227
279
  };
228
280
 
229
281
  state: State = {
@@ -233,14 +285,18 @@ export default class ReactGridLayout extends React.Component<Props, State> {
233
285
  this.props.children,
234
286
  this.props.cols,
235
287
  // Legacy support for verticalCompact: false
236
- this.compactType()
288
+ compactType(this.props)
237
289
  ),
238
290
  mounted: false,
239
291
  oldDragItem: null,
240
292
  oldLayout: null,
241
- oldResizeItem: null
293
+ oldResizeItem: null,
294
+ droppingDOMNode: null,
295
+ children: []
242
296
  };
243
297
 
298
+ dragEnterCounter = 0;
299
+
244
300
  constructor(props: Props, context: any): void {
245
301
  super(props, context);
246
302
  autoBindHandlers(this, [
@@ -260,20 +316,25 @@ export default class ReactGridLayout extends React.Component<Props, State> {
260
316
  this.onLayoutMaybeChanged(this.state.layout, this.props.layout);
261
317
  }
262
318
 
263
- componentWillReceiveProps(nextProps: Props) {
319
+ static getDerivedStateFromProps(nextProps: Props, prevState: State) {
264
320
  let newLayoutBase;
321
+
322
+ if (prevState.activeDrag) {
323
+ return null;
324
+ }
325
+
265
326
  // Legacy support for compactType
266
327
  // Allow parent to set layout directly.
267
328
  if (
268
- !isEqual(nextProps.layout, this.props.layout) ||
269
- nextProps.compactType !== this.props.compactType
329
+ !isEqual(nextProps.layout, prevState.propsLayout) ||
330
+ nextProps.compactType !== prevState.compactType
270
331
  ) {
271
332
  newLayoutBase = nextProps.layout;
272
- } else if (!childrenEqual(this.props.children, nextProps.children)) {
333
+ } else if (!childrenEqual(nextProps.children, prevState.children)) {
273
334
  // If children change, also regenerate the layout. Use our state
274
335
  // as the base in case because it may be more up to date than
275
336
  // what is in props.
276
- newLayoutBase = this.state.layout;
337
+ newLayoutBase = prevState.layout;
277
338
  }
278
339
 
279
340
  // We need to regenerate the layout.
@@ -282,10 +343,27 @@ export default class ReactGridLayout extends React.Component<Props, State> {
282
343
  newLayoutBase,
283
344
  nextProps.children,
284
345
  nextProps.cols,
285
- this.compactType(nextProps)
346
+ compactType(nextProps)
286
347
  );
287
- const oldLayout = this.state.layout;
288
- this.setState({ layout: newLayout });
348
+
349
+ return {
350
+ layout: newLayout,
351
+ // We need to save these props to state for using
352
+ // getDerivedStateFromProps instead of componentDidMount (in which we would get extra rerender)
353
+ compactType: nextProps.compactType,
354
+ children: nextProps.children,
355
+ propsLayout: nextProps.layout
356
+ };
357
+ }
358
+
359
+ return null;
360
+ }
361
+
362
+ componentDidUpdate(prevProps: Props, prevState: State) {
363
+ if (!this.state.activeDrag) {
364
+ const newLayout = this.state.layout;
365
+ const oldLayout = prevState.layout;
366
+
289
367
  this.onLayoutMaybeChanged(newLayout, oldLayout);
290
368
  }
291
369
  }
@@ -308,11 +386,6 @@ export default class ReactGridLayout extends React.Component<Props, State> {
308
386
  );
309
387
  }
310
388
 
311
- compactType(props: ?Object): CompactType {
312
- if (!props) props = this.props;
313
- return props.verticalCompact === false ? null : props.compactType;
314
- }
315
-
316
389
  /**
317
390
  * When dragging starts
318
391
  * @param {String} i Id of the child
@@ -368,14 +441,14 @@ export default class ReactGridLayout extends React.Component<Props, State> {
368
441
  y,
369
442
  isUserAction,
370
443
  this.props.preventCollision,
371
- this.compactType(),
444
+ compactType(this.props),
372
445
  cols
373
446
  );
374
447
 
375
448
  this.props.onDrag(layout, oldDragItem, l, placeholder, e, node);
376
449
 
377
450
  this.setState({
378
- layout: compact(layout, this.compactType(), cols),
451
+ layout: compact(layout, compactType(this.props), cols),
379
452
  activeDrag: placeholder
380
453
  });
381
454
  }
@@ -404,14 +477,15 @@ export default class ReactGridLayout extends React.Component<Props, State> {
404
477
  y,
405
478
  isUserAction,
406
479
  preventCollision,
407
- this.compactType(),
480
+ compactType(this.props),
408
481
  cols
409
482
  );
410
-
411
- this.props.onDragStop(layout, oldDragItem, l, null, e, node);
483
+ if (this.state.activeDrag) {
484
+ this.props.onDragStop(layout, oldDragItem, l, null, e, node);
485
+ }
412
486
 
413
487
  // Set state
414
- const newLayout = compact(layout, this.compactType(), cols);
488
+ const newLayout = compact(layout, compactType(this.props), cols);
415
489
  const { oldLayout } = this.state;
416
490
  this.setState({
417
491
  activeDrag: null,
@@ -425,6 +499,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
425
499
 
426
500
  onLayoutMaybeChanged(newLayout: Layout, oldLayout: ?Layout) {
427
501
  if (!oldLayout) oldLayout = this.state.layout;
502
+
428
503
  if (!isEqual(oldLayout, newLayout)) {
429
504
  this.props.onLayoutChange(newLayout);
430
505
  }
@@ -453,14 +528,17 @@ export default class ReactGridLayout extends React.Component<Props, State> {
453
528
  // to find collisions faster
454
529
  let hasCollisions;
455
530
  if (preventCollision) {
456
- const collisions = getAllCollisions(layout, { ...l, w, h }).filter((layoutItem) => layoutItem.i !== l.i);
531
+ const collisions = getAllCollisions(layout, { ...l, w, h }).filter(
532
+ layoutItem => layoutItem.i !== l.i
533
+ );
457
534
  hasCollisions = collisions.length > 0;
458
535
 
459
536
  // If we're colliding, we need adjust the placeholder.
460
537
  if (hasCollisions) {
461
538
  // adjust w && h to maximum allowed space
462
- let leastX = Infinity, leastY = Infinity;
463
- collisions.forEach((layoutItem) => {
539
+ let leastX = Infinity,
540
+ leastY = Infinity;
541
+ collisions.forEach(layoutItem => {
464
542
  if (layoutItem.x > l.x) leastX = Math.min(leastX, layoutItem.x);
465
543
  if (layoutItem.y > l.y) leastY = Math.min(leastY, layoutItem.y);
466
544
  });
@@ -490,7 +568,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
490
568
 
491
569
  // Re-compact the layout and set the drag placeholder.
492
570
  this.setState({
493
- layout: compact(layout, this.compactType(), cols),
571
+ layout: compact(layout, compactType(this.props), cols),
494
572
  activeDrag: placeholder
495
573
  });
496
574
  }
@@ -503,7 +581,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
503
581
  this.props.onResizeStop(layout, oldResizeItem, l, null, e, node);
504
582
 
505
583
  // Set state
506
- const newLayout = compact(layout, this.compactType(), cols);
584
+ const newLayout = compact(layout, compactType(this.props), cols);
507
585
  const { oldLayout } = this.state;
508
586
  this.setState({
509
587
  activeDrag: null,
@@ -529,7 +607,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
529
607
  containerPadding,
530
608
  rowHeight,
531
609
  maxRows,
532
- useCSSTransforms
610
+ useCSSTransforms,
611
+ transformScale
533
612
  } = this.props;
534
613
 
535
614
  // {...this.state.activeDrag} is pretty slow, actually
@@ -550,6 +629,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
550
629
  isDraggable={false}
551
630
  isResizable={false}
552
631
  useCSSTransforms={useCSSTransforms}
632
+ transformScale={transformScale}
553
633
  >
554
634
  <div />
555
635
  </GridItem>
@@ -561,7 +641,10 @@ export default class ReactGridLayout extends React.Component<Props, State> {
561
641
  * @param {Element} child React element.
562
642
  * @return {Element} Element wrapped in draggable and properly placed.
563
643
  */
564
- processGridItem(child: ReactElement<any>): ?ReactElement<any> {
644
+ processGridItem(
645
+ child: ReactElement<any>,
646
+ isDroppingItem?: boolean
647
+ ): ?ReactElement<any> {
565
648
  if (!child || !child.key) return;
566
649
  const l = getLayoutItem(this.state.layout, String(child.key));
567
650
  if (!l) return null;
@@ -575,10 +658,11 @@ export default class ReactGridLayout extends React.Component<Props, State> {
575
658
  isDraggable,
576
659
  isResizable,
577
660
  useCSSTransforms,
661
+ transformScale,
578
662
  draggableCancel,
579
663
  draggableHandle
580
664
  } = this.props;
581
- const { mounted } = this.state;
665
+ const { mounted, droppingPosition } = this.state;
582
666
 
583
667
  // Parse 'static'. Any properties defined directly on the grid item will take precedence.
584
668
  const draggable = Boolean(
@@ -608,6 +692,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
608
692
  isResizable={resizable}
609
693
  useCSSTransforms={useCSSTransforms && mounted}
610
694
  usePercentages={!mounted}
695
+ transformScale={transformScale}
611
696
  w={l.w}
612
697
  h={l.h}
613
698
  x={l.x}
@@ -618,26 +703,126 @@ export default class ReactGridLayout extends React.Component<Props, State> {
618
703
  maxH={l.maxH}
619
704
  maxW={l.maxW}
620
705
  static={l.static}
706
+ droppingPosition={isDroppingItem ? droppingPosition : undefined}
621
707
  >
622
708
  {child}
623
709
  </GridItem>
624
710
  );
625
711
  }
626
712
 
713
+ onDragOver = (e: DragOverEvent) => {
714
+ // we should ignore events from layout's children in Firefox
715
+ // to avoid unpredictable jumping of a dropping placeholder
716
+ if (
717
+ isFirefox &&
718
+ !e.nativeEvent.target.className.includes(layoutClassName)
719
+ ) {
720
+ return false;
721
+ }
722
+
723
+ const { droppingItem } = this.props;
724
+ const { layout } = this.state;
725
+ const { layerX, layerY } = e.nativeEvent;
726
+ const droppingPosition = { x: layerX, y: layerY, e };
727
+
728
+ if (!this.state.droppingDOMNode) {
729
+ this.setState({
730
+ droppingDOMNode: <div key={droppingItem.i} />,
731
+ droppingPosition,
732
+ layout: [
733
+ ...layout,
734
+ {
735
+ ...droppingItem,
736
+ x: 0,
737
+ y: 0,
738
+ static: false,
739
+ isDraggable: true
740
+ }
741
+ ]
742
+ });
743
+ } else if (this.state.droppingPosition) {
744
+ const shouldUpdatePosition =
745
+ this.state.droppingPosition.x != layerX ||
746
+ this.state.droppingPosition.y != layerY;
747
+ shouldUpdatePosition && this.setState({ droppingPosition });
748
+ }
749
+
750
+ e.stopPropagation();
751
+ e.preventDefault();
752
+ };
753
+
754
+ removeDroppingPlaceholder = () => {
755
+ const { droppingItem, cols } = this.props;
756
+ const { layout } = this.state;
757
+
758
+ const newLayout = compact(
759
+ layout.filter(l => l.i !== droppingItem.i),
760
+ compactType(this.props),
761
+ cols
762
+ );
763
+
764
+ this.setState({
765
+ layout: newLayout,
766
+ droppingDOMNode: null,
767
+ activeDrag: null,
768
+ droppingPosition: undefined
769
+ });
770
+ };
771
+
772
+ onDragLeave = () => {
773
+ this.dragEnterCounter--;
774
+
775
+ // onDragLeave can be triggered on each layout's child.
776
+ // But we know that count of dragEnter and dragLeave events
777
+ // will be balanced after leaving the layout's container
778
+ // so we can increase and decrease count of dragEnter and
779
+ // when it'll be equal to 0 we'll remove the placeholder
780
+ if (this.dragEnterCounter === 0) {
781
+ this.removeDroppingPlaceholder();
782
+ }
783
+ };
784
+
785
+ onDragEnter = () => {
786
+ this.dragEnterCounter++;
787
+ };
788
+
789
+ onDrop = () => {
790
+ const { droppingItem } = this.props;
791
+ const { layout } = this.state;
792
+ const { x, y, w, h } = layout.find(l => l.i === droppingItem.i) || {};
793
+
794
+ // reset gragEnter counter on drop
795
+ this.dragEnterCounter = 0;
796
+
797
+ this.removeDroppingPlaceholder();
798
+
799
+ this.props.onDrop({ x, y, w, h });
800
+ };
801
+
627
802
  render() {
628
- const { className, style } = this.props;
803
+ const { className, style, isDroppable } = this.props;
629
804
 
630
- const mergedClassName = classNames("react-grid-layout", className);
805
+ const mergedClassName = classNames(layoutClassName, className);
631
806
  const mergedStyle = {
632
807
  height: this.containerHeight(),
633
808
  ...style
634
809
  };
635
810
 
636
811
  return (
637
- <div className={mergedClassName} style={mergedStyle}>
812
+ <div
813
+ className={mergedClassName}
814
+ style={mergedStyle}
815
+ onDrop={isDroppable ? this.onDrop : noop}
816
+ onDragLeave={isDroppable ? this.onDragLeave : noop}
817
+ onDragEnter={isDroppable ? this.onDragEnter : noop}
818
+ onDragOver={isDroppable ? this.onDragOver : noop}
819
+ >
638
820
  {React.Children.map(this.props.children, child =>
639
821
  this.processGridItem(child)
640
822
  )}
823
+ {isDroppable &&
824
+ this.state.droppingDOMNode &&
825
+ this.processGridItem(this.state.droppingDOMNode, true)}
641
826
  {this.placeholder()}
642
827
  </div>
643
828
  );
@@ -20,10 +20,26 @@ import type { Layout } from "./utils";
20
20
 
21
21
  const type = obj => Object.prototype.toString.call(obj);
22
22
 
23
+ /**
24
+ * Get a value of margin or containerPadding.
25
+ *
26
+ * @param {Array | Object} param Margin | containerPadding, e.g. [10, 10] | {lg: [10, 10], ...}.
27
+ * @param {String} breakpoint Breakpoint: lg, md, sm, xs and etc.
28
+ * @return {Array}
29
+ */
30
+
31
+ function getIndentationValue(
32
+ param: { [key: string]: [number, number] } | [number, number],
33
+ breakpoint: string
34
+ ) {
35
+ return Array.isArray(param) ? param : param[breakpoint];
36
+ }
37
+
23
38
  type State = {
24
39
  layout: Layout,
25
40
  breakpoint: string,
26
- cols: number
41
+ cols: number,
42
+ layouts?: { [key: string]: Layout }
27
43
  };
28
44
 
29
45
  type Props<Breakpoint: string = string> = {
@@ -35,6 +51,8 @@ type Props<Breakpoint: string = string> = {
35
51
  cols: { [key: Breakpoint]: number },
36
52
  layouts: { [key: Breakpoint]: Layout },
37
53
  width: number,
54
+ margin: { [key: Breakpoint]: [number, number] } | [number, number],
55
+ containerPadding: { [key: Breakpoint]: [number, number] } | [number, number],
38
56
 
39
57
  // Callbacks
40
58
  onBreakpointChange: (Breakpoint, cols: number) => void,
@@ -68,6 +86,18 @@ export default class ResponsiveReactGridLayout extends React.Component<
68
86
  // # of cols. This is a breakpoint -> cols map
69
87
  cols: PropTypes.object,
70
88
 
89
+ // # of margin. This is a breakpoint -> margin map
90
+ // e.g. { lg: [5, 5], md: [10, 10], sm: [15, 15] }
91
+ // Margin between items [x, y] in px
92
+ // e.g. [10, 10]
93
+ margin: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
94
+
95
+ // # of containerPadding. This is a breakpoint -> containerPadding map
96
+ // e.g. { lg: [5, 5], md: [10, 10], sm: [15, 15] }
97
+ // Padding inside the container [x, y] in px
98
+ // e.g. [10, 10]
99
+ containerPadding: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
100
+
71
101
  // layouts is an object mapping breakpoints to layouts.
72
102
  // e.g. {lg: Layout, md: Layout, ...}
73
103
  layouts(props: Props<>, propName: string) {
@@ -110,6 +140,8 @@ export default class ResponsiveReactGridLayout extends React.Component<
110
140
  breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
111
141
  cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
112
142
  layouts: {},
143
+ margin: [10, 10],
144
+ containerPadding: { lg: null, md: null, sm: null, xs: null, xxs: null },
113
145
  onBreakpointChange: noop,
114
146
  onLayoutChange: noop,
115
147
  onWidthChange: noop
@@ -142,18 +174,10 @@ export default class ResponsiveReactGridLayout extends React.Component<
142
174
  };
143
175
  }
144
176
 
145
- componentWillReceiveProps(nextProps: Props<*>) {
146
- // Allow parent to set width or breakpoint directly.
147
- if (
148
- nextProps.width != this.props.width ||
149
- nextProps.breakpoint !== this.props.breakpoint ||
150
- !isEqual(nextProps.breakpoints, this.props.breakpoints) ||
151
- !isEqual(nextProps.cols, this.props.cols)
152
- ) {
153
- this.onWidthChange(nextProps);
154
- } else if (!isEqual(nextProps.layouts, this.props.layouts)) {
177
+ static getDerivedStateFromProps(nextProps: Props<*>, prevState: State) {
178
+ if (!isEqual(nextProps.layouts, prevState.layouts)) {
155
179
  // Allow parent to set layouts directly.
156
- const { breakpoint, cols } = this.state;
180
+ const { breakpoint, cols } = prevState;
157
181
 
158
182
  // Since we're setting an entirely new layout object, we must generate a new responsive layout
159
183
  // if one does not exist.
@@ -165,7 +189,21 @@ export default class ResponsiveReactGridLayout extends React.Component<
165
189
  cols,
166
190
  nextProps.compactType
167
191
  );
168
- this.setState({ layout: newLayout });
192
+ return { layout: newLayout, layouts: nextProps.layouts };
193
+ }
194
+
195
+ return null;
196
+ }
197
+
198
+ componentDidUpdate(prevProps: Props<*>) {
199
+ // Allow parent to set width or breakpoint directly.
200
+ if (
201
+ this.props.width != prevProps.width ||
202
+ this.props.breakpoint !== prevProps.breakpoint ||
203
+ !isEqual(this.props.breakpoints, prevProps.breakpoints) ||
204
+ !isEqual(this.props.cols, prevProps.cols)
205
+ ) {
206
+ this.onWidthChange(this.props);
169
207
  }
170
208
  }
171
209
 
@@ -188,6 +226,7 @@ export default class ResponsiveReactGridLayout extends React.Component<
188
226
  getBreakpointFromWidth(nextProps.breakpoints, nextProps.width);
189
227
 
190
228
  const lastBreakpoint = this.state.breakpoint;
229
+ const newCols: number = getColsFromBreakpoint(newBreakpoint, cols);
191
230
 
192
231
  // Breakpoint change
193
232
  if (
@@ -200,7 +239,6 @@ export default class ResponsiveReactGridLayout extends React.Component<
200
239
  layouts[lastBreakpoint] = cloneLayout(this.state.layout);
201
240
 
202
241
  // Find or generate a new layout.
203
- const newCols: number = getColsFromBreakpoint(newBreakpoint, cols);
204
242
  let layout = findOrGenerateResponsiveLayout(
205
243
  layouts,
206
244
  breakpoints,
@@ -224,12 +262,6 @@ export default class ResponsiveReactGridLayout extends React.Component<
224
262
  // callbacks
225
263
  this.props.onLayoutChange(layout, layouts);
226
264
  this.props.onBreakpointChange(newBreakpoint, newCols);
227
- this.props.onWidthChange(
228
- nextProps.width,
229
- nextProps.margin,
230
- newCols,
231
- nextProps.containerPadding
232
- );
233
265
 
234
266
  this.setState({
235
267
  breakpoint: newBreakpoint,
@@ -237,6 +269,20 @@ export default class ResponsiveReactGridLayout extends React.Component<
237
269
  cols: newCols
238
270
  });
239
271
  }
272
+
273
+ const margin = getIndentationValue(nextProps.margin, newBreakpoint);
274
+ const containerPadding = getIndentationValue(
275
+ nextProps.containerPadding,
276
+ newBreakpoint
277
+ );
278
+
279
+ //call onWidthChange on every change of width, not only on breakpoint changes
280
+ this.props.onWidthChange(
281
+ nextProps.width,
282
+ margin,
283
+ newCols,
284
+ containerPadding
285
+ );
240
286
  }
241
287
 
242
288
  render() {
@@ -246,6 +292,8 @@ export default class ResponsiveReactGridLayout extends React.Component<
246
292
  breakpoints,
247
293
  cols,
248
294
  layouts,
295
+ margin,
296
+ containerPadding,
249
297
  onBreakpointChange,
250
298
  onLayoutChange,
251
299
  onWidthChange,
@@ -256,6 +304,11 @@ export default class ResponsiveReactGridLayout extends React.Component<
256
304
  return (
257
305
  <ReactGridLayout
258
306
  {...other}
307
+ margin={getIndentationValue(margin, this.state.breakpoint)}
308
+ containerPadding={getIndentationValue(
309
+ containerPadding,
310
+ this.state.breakpoint
311
+ )}
259
312
  onLayoutChange={this.onLayoutChange}
260
313
  layout={this.state.layout}
261
314
  cols={this.state.cols}
@@ -57,7 +57,7 @@ export default function WidthProvider<
57
57
 
58
58
  onWindowResize = () => {
59
59
  if (!this.mounted) return;
60
- // eslint-disable-next-line
60
+ // eslint-disable-next-line react/no-find-dom-node
61
61
  const node = ReactDOM.findDOMNode(this); // Flow casts this to Text | Element
62
62
  if (node instanceof HTMLElement)
63
63
  this.setState({ width: node.offsetWidth });