react-grid-layout 1.2.2 → 1.3.0

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.
@@ -4,7 +4,6 @@ import * as React from "react";
4
4
  import isEqual from "lodash.isequal";
5
5
  import classNames from "classnames";
6
6
  import {
7
- autoBindHandlers,
8
7
  bottom,
9
8
  childrenEqual,
10
9
  cloneLayoutItem,
@@ -95,6 +94,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
95
94
  isBounded: false,
96
95
  isDraggable: true,
97
96
  isResizable: true,
97
+ allowOverlap: false,
98
98
  isDroppable: false,
99
99
  useCSSTransforms: true,
100
100
  transformScale: 1,
@@ -114,7 +114,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
114
114
  onResizeStart: noop,
115
115
  onResize: noop,
116
116
  onResizeStop: noop,
117
- onDrop: noop
117
+ onDrop: noop,
118
+ onDropDragOver: noop
118
119
  };
119
120
 
120
121
  state: State = {
@@ -124,7 +125,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
124
125
  this.props.children,
125
126
  this.props.cols,
126
127
  // Legacy support for verticalCompact: false
127
- compactType(this.props)
128
+ compactType(this.props),
129
+ this.props.allowOverlap
128
130
  ),
129
131
  mounted: false,
130
132
  oldDragItem: null,
@@ -136,18 +138,6 @@ export default class ReactGridLayout extends React.Component<Props, State> {
136
138
 
137
139
  dragEnterCounter: number = 0;
138
140
 
139
- constructor(props: Props, context: any): void {
140
- super(props, context);
141
- autoBindHandlers(this, [
142
- "onDragStart",
143
- "onDrag",
144
- "onDragStop",
145
- "onResizeStart",
146
- "onResize",
147
- "onResizeStop"
148
- ]);
149
- }
150
-
151
141
  componentDidMount() {
152
142
  this.setState({ mounted: true });
153
143
  // Possibly call back with layout on mount. This should be done after correcting the layout width
@@ -185,7 +175,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
185
175
  newLayoutBase,
186
176
  nextProps.children,
187
177
  nextProps.cols,
188
- compactType(nextProps)
178
+ compactType(nextProps),
179
+ nextProps.allowOverlap
189
180
  );
190
181
 
191
182
  return {
@@ -249,12 +240,12 @@ export default class ReactGridLayout extends React.Component<Props, State> {
249
240
  * @param {Event} e The mousedown event
250
241
  * @param {Element} node The current dragging DOM element
251
242
  */
252
- onDragStart(
243
+ onDragStart: (i: string, x: number, y: number, GridDragEvent) => void = (
253
244
  i: string,
254
245
  x: number,
255
246
  y: number,
256
247
  { e, node }: GridDragEvent
257
- ): void {
248
+ ) => {
258
249
  const { layout } = this.state;
259
250
  const l = getLayoutItem(layout, i);
260
251
  if (!l) return;
@@ -265,7 +256,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
265
256
  });
266
257
 
267
258
  return this.props.onDragStart(layout, l, l, null, e, node);
268
- }
259
+ };
269
260
 
270
261
  /**
271
262
  * Each drag movement create a new dragelement and move the element to the dragged location
@@ -275,10 +266,15 @@ export default class ReactGridLayout extends React.Component<Props, State> {
275
266
  * @param {Event} e The mousedown event
276
267
  * @param {Element} node The current dragging DOM element
277
268
  */
278
- onDrag(i: string, x: number, y: number, { e, node }: GridDragEvent): void {
269
+ onDrag: (i: string, x: number, y: number, GridDragEvent) => void = (
270
+ i,
271
+ x,
272
+ y,
273
+ { e, node }
274
+ ) => {
279
275
  const { oldDragItem } = this.state;
280
276
  let { layout } = this.state;
281
- const { cols } = this.props;
277
+ const { cols, allowOverlap } = this.props;
282
278
  const l = getLayoutItem(layout, i);
283
279
  if (!l) return;
284
280
 
@@ -302,16 +298,19 @@ export default class ReactGridLayout extends React.Component<Props, State> {
302
298
  isUserAction,
303
299
  this.props.preventCollision,
304
300
  compactType(this.props),
305
- cols
301
+ cols,
302
+ allowOverlap
306
303
  );
307
304
 
308
305
  this.props.onDrag(layout, oldDragItem, l, placeholder, e, node);
309
306
 
310
307
  this.setState({
311
- layout: compact(layout, compactType(this.props), cols),
308
+ layout: allowOverlap
309
+ ? layout
310
+ : compact(layout, compactType(this.props), cols),
312
311
  activeDrag: placeholder
313
312
  });
314
- }
313
+ };
315
314
 
316
315
  /**
317
316
  * When dragging stops, figure out which position the element is closest to and update its x and y.
@@ -321,17 +320,17 @@ export default class ReactGridLayout extends React.Component<Props, State> {
321
320
  * @param {Event} e The mousedown event
322
321
  * @param {Element} node The current dragging DOM element
323
322
  */
324
- onDragStop(
325
- i: string,
326
- x: number,
327
- y: number,
328
- { e, node }: GridDragEvent
329
- ): void {
323
+ onDragStop: (i: string, x: number, y: number, GridDragEvent) => void = (
324
+ i,
325
+ x,
326
+ y,
327
+ { e, node }
328
+ ) => {
330
329
  if (!this.state.activeDrag) return;
331
330
 
332
331
  const { oldDragItem } = this.state;
333
332
  let { layout } = this.state;
334
- const { cols, preventCollision } = this.props;
333
+ const { cols, preventCollision, allowOverlap } = this.props;
335
334
  const l = getLayoutItem(layout, i);
336
335
  if (!l) return;
337
336
 
@@ -345,13 +344,16 @@ export default class ReactGridLayout extends React.Component<Props, State> {
345
344
  isUserAction,
346
345
  preventCollision,
347
346
  compactType(this.props),
348
- cols
347
+ cols,
348
+ allowOverlap
349
349
  );
350
350
 
351
351
  this.props.onDragStop(layout, oldDragItem, l, null, e, node);
352
352
 
353
353
  // Set state
354
- const newLayout = compact(layout, compactType(this.props), cols);
354
+ const newLayout = allowOverlap
355
+ ? layout
356
+ : compact(layout, compactType(this.props), cols);
355
357
  const { oldLayout } = this.state;
356
358
  this.setState({
357
359
  activeDrag: null,
@@ -361,7 +363,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
361
363
  });
362
364
 
363
365
  this.onLayoutMaybeChanged(newLayout, oldLayout);
364
- }
366
+ };
365
367
 
366
368
  onLayoutMaybeChanged(newLayout: Layout, oldLayout: ?Layout) {
367
369
  if (!oldLayout) oldLayout = this.state.layout;
@@ -371,7 +373,12 @@ export default class ReactGridLayout extends React.Component<Props, State> {
371
373
  }
372
374
  }
373
375
 
374
- onResizeStart(i: string, w: number, h: number, { e, node }: GridResizeEvent) {
376
+ onResizeStart: (i: string, w: number, h: number, GridResizeEvent) => void = (
377
+ i,
378
+ w,
379
+ h,
380
+ { e, node }
381
+ ) => {
375
382
  const { layout } = this.state;
376
383
  const l = getLayoutItem(layout, i);
377
384
  if (!l) return;
@@ -382,17 +389,22 @@ export default class ReactGridLayout extends React.Component<Props, State> {
382
389
  });
383
390
 
384
391
  this.props.onResizeStart(layout, l, l, null, e, node);
385
- }
392
+ };
386
393
 
387
- onResize(i: string, w: number, h: number, { e, node }: GridResizeEvent) {
394
+ onResize: (i: string, w: number, h: number, GridResizeEvent) => void = (
395
+ i,
396
+ w,
397
+ h,
398
+ { e, node }
399
+ ) => {
388
400
  const { layout, oldResizeItem } = this.state;
389
- const { cols, preventCollision } = this.props;
401
+ const { cols, preventCollision, allowOverlap } = this.props;
390
402
 
391
403
  const [newLayout, l] = withLayoutItem(layout, i, l => {
392
404
  // Something like quad tree should be used
393
405
  // to find collisions faster
394
406
  let hasCollisions;
395
- if (preventCollision) {
407
+ if (preventCollision && !allowOverlap) {
396
408
  const collisions = getAllCollisions(layout, { ...l, w, h }).filter(
397
409
  layoutItem => layoutItem.i !== l.i
398
410
  );
@@ -439,20 +451,29 @@ export default class ReactGridLayout extends React.Component<Props, State> {
439
451
 
440
452
  // Re-compact the newLayout and set the drag placeholder.
441
453
  this.setState({
442
- layout: compact(newLayout, compactType(this.props), cols),
454
+ layout: allowOverlap
455
+ ? newLayout
456
+ : compact(newLayout, compactType(this.props), cols),
443
457
  activeDrag: placeholder
444
458
  });
445
- }
459
+ };
446
460
 
447
- onResizeStop(i: string, w: number, h: number, { e, node }: GridResizeEvent) {
461
+ onResizeStop: (i: string, w: number, h: number, GridResizeEvent) => void = (
462
+ i,
463
+ w,
464
+ h,
465
+ { e, node }
466
+ ) => {
448
467
  const { layout, oldResizeItem } = this.state;
449
- const { cols } = this.props;
468
+ const { cols, allowOverlap } = this.props;
450
469
  const l = getLayoutItem(layout, i);
451
470
 
452
471
  this.props.onResizeStop(layout, oldResizeItem, l, null, e, node);
453
472
 
454
473
  // Set state
455
- const newLayout = compact(layout, compactType(this.props), cols);
474
+ const newLayout = allowOverlap
475
+ ? layout
476
+ : compact(layout, compactType(this.props), cols);
456
477
  const { oldLayout } = this.state;
457
478
  this.setState({
458
479
  activeDrag: null,
@@ -462,7 +483,7 @@ export default class ReactGridLayout extends React.Component<Props, State> {
462
483
  });
463
484
 
464
485
  this.onLayoutMaybeChanged(newLayout, oldLayout);
465
- }
486
+ };
466
487
 
467
488
  /**
468
489
  * Create a placeholder object.
@@ -599,6 +620,9 @@ export default class ReactGridLayout extends React.Component<Props, State> {
599
620
  // Called while dragging an element. Part of browser native drag/drop API.
600
621
  // Native event target might be the layout itself, or an element within the layout.
601
622
  onDragOver: DragOverEvent => void | false = e => {
623
+ e.preventDefault(); // Prevent any browser native action
624
+ e.stopPropagation();
625
+
602
626
  // we should ignore events from layout's children in Firefox
603
627
  // to avoid unpredictable jumping of a dropping placeholder
604
628
  // FIXME remove this hack
@@ -607,24 +631,35 @@ export default class ReactGridLayout extends React.Component<Props, State> {
607
631
  // $FlowIgnore can't figure this out
608
632
  !e.nativeEvent.target?.classList.contains(layoutClassName)
609
633
  ) {
610
- // without this Firefox will not allow drop if currently over droppingItem
611
- e.preventDefault();
612
634
  return false;
613
635
  }
614
636
 
615
637
  const {
616
638
  droppingItem,
639
+ onDropDragOver,
617
640
  margin,
618
641
  cols,
619
642
  rowHeight,
620
643
  maxRows,
621
644
  width,
622
- containerPadding
645
+ containerPadding,
646
+ transformScale
623
647
  } = this.props;
648
+ // Allow user to customize the dropping item or short-circuit the drop based on the results
649
+ // of the `onDragOver(e: Event)` callback.
650
+ const onDragOverResult = onDropDragOver?.(e);
651
+ if (onDragOverResult === false) {
652
+ if (this.state.droppingDOMNode) {
653
+ this.removeDroppingPlaceholder();
654
+ }
655
+ return false;
656
+ }
657
+ const finalDroppingItem = { ...droppingItem, ...onDragOverResult };
658
+
624
659
  const { layout } = this.state;
625
660
  // This is relative to the DOM element that this event fired for.
626
661
  const { layerX, layerY } = e.nativeEvent;
627
- const droppingPosition = { left: layerX, top: layerY, e };
662
+ const droppingPosition = { left: layerX / transformScale, top: layerY / transformScale, e };
628
663
 
629
664
  if (!this.state.droppingDOMNode) {
630
665
  const positionParams: PositionParams = {
@@ -640,17 +675,17 @@ export default class ReactGridLayout extends React.Component<Props, State> {
640
675
  positionParams,
641
676
  layerY,
642
677
  layerX,
643
- droppingItem.w,
644
- droppingItem.h
678
+ finalDroppingItem.w,
679
+ finalDroppingItem.h
645
680
  );
646
681
 
647
682
  this.setState({
648
- droppingDOMNode: <div key={droppingItem.i} />,
683
+ droppingDOMNode: <div key={finalDroppingItem.i} />,
649
684
  droppingPosition,
650
685
  layout: [
651
686
  ...layout,
652
687
  {
653
- ...droppingItem,
688
+ ...finalDroppingItem,
654
689
  x: calculatedPosition.x,
655
690
  y: calculatedPosition.y,
656
691
  static: false,
@@ -665,9 +700,6 @@ export default class ReactGridLayout extends React.Component<Props, State> {
665
700
  this.setState({ droppingPosition });
666
701
  }
667
702
  }
668
-
669
- e.stopPropagation();
670
- e.preventDefault();
671
703
  };
672
704
 
673
705
  removeDroppingPlaceholder: () => void = () => {
@@ -688,7 +720,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
688
720
  });
689
721
  };
690
722
 
691
- onDragLeave: () => void = () => {
723
+ onDragLeave: EventHandler = e => {
724
+ e.preventDefault(); // Prevent any browser native action
692
725
  this.dragEnterCounter--;
693
726
 
694
727
  // onDragLeave can be triggered on each layout's child.
@@ -701,11 +734,13 @@ export default class ReactGridLayout extends React.Component<Props, State> {
701
734
  }
702
735
  };
703
736
 
704
- onDragEnter: () => void = () => {
737
+ onDragEnter: EventHandler = e => {
738
+ e.preventDefault(); // Prevent any browser native action
705
739
  this.dragEnterCounter++;
706
740
  };
707
741
 
708
742
  onDrop: EventHandler = (e: Event) => {
743
+ e.preventDefault(); // Prevent any browser native action
709
744
  const { droppingItem } = this.props;
710
745
  const { layout } = this.state;
711
746
  const item = layout.find(l => l.i === droppingItem.i);
@@ -6,13 +6,34 @@ import type {
6
6
  ChildrenArray as ReactChildrenArray,
7
7
  Element as ReactElement
8
8
  } from "react";
9
- import type { EventCallback, CompactType, Layout, LayoutItem } from "./utils";
9
+ import type {
10
+ DragOverEvent,
11
+ EventCallback,
12
+ CompactType,
13
+ Layout,
14
+ LayoutItem
15
+ } from "./utils";
16
+
17
+ // util
18
+ export type ReactRef<T: HTMLElement> = {|
19
+ +current: T | null
20
+ |};
10
21
 
11
- type ResizeHandleAxis = "s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne";
12
- export type ResizeHandles = Array<ResizeHandleAxis>;
22
+ export type ResizeHandleAxis =
23
+ | "s"
24
+ | "w"
25
+ | "e"
26
+ | "n"
27
+ | "sw"
28
+ | "nw"
29
+ | "se"
30
+ | "ne";
13
31
  export type ResizeHandle =
14
32
  | ReactElement<any>
15
- | ((resizeHandleAxis: ResizeHandleAxis) => ReactElement<any>);
33
+ | ((
34
+ resizeHandleAxis: ResizeHandleAxis,
35
+ ref: ReactRef<HTMLElement>
36
+ ) => ReactElement<any>);
16
37
 
17
38
  // Defines which resize handles should be rendered (default: 'se')
18
39
  // Allows for any combination of:
@@ -24,13 +45,13 @@ export type ResizeHandle =
24
45
  // 'nw' - Northwest handle (top-left)
25
46
  // 'se' - Southeast handle (bottom-right)
26
47
  // 'ne' - Northeast handle (top-right)
27
- export const resizeHandlesType: ReactPropsChainableTypeChecker = PropTypes.arrayOf(
28
- PropTypes.oneOf(["s", "w", "e", "n", "sw", "nw", "se", "ne"])
29
- );
48
+ export const resizeHandleAxesType: ReactPropsChainableTypeChecker =
49
+ PropTypes.arrayOf(
50
+ PropTypes.oneOf(["s", "w", "e", "n", "sw", "nw", "se", "ne"])
51
+ );
30
52
  // Custom component for resize handles
31
- export const resizeHandleType: ReactPropsChainableTypeChecker = PropTypes.oneOfType(
32
- [PropTypes.node, PropTypes.func]
33
- );
53
+ export const resizeHandleType: ReactPropsChainableTypeChecker =
54
+ PropTypes.oneOfType([PropTypes.node, PropTypes.func]);
34
55
 
35
56
  export type Props = {|
36
57
  className: string,
@@ -55,8 +76,9 @@ export type Props = {|
55
76
  useCSSTransforms: boolean,
56
77
  transformScale: number,
57
78
  droppingItem: $Shape<LayoutItem>,
58
- resizeHandles: ResizeHandles,
79
+ resizeHandles: ResizeHandleAxis[],
59
80
  resizeHandle?: ResizeHandle,
81
+ allowOverlap: boolean,
60
82
 
61
83
  // Callbacks
62
84
  onLayoutChange: Layout => void,
@@ -66,6 +88,7 @@ export type Props = {|
66
88
  onResize: EventCallback,
67
89
  onResizeStart: EventCallback,
68
90
  onResizeStop: EventCallback,
91
+ onDropDragOver: (e: DragOverEvent) => ?({| w?: number, h?: number |} | false),
69
92
  onDrop: (layout: Layout, item: ?LayoutItem, e: Event) => void,
70
93
  children: ReactChildrenArray<ReactElement<any>>,
71
94
  innerRef?: Ref<"div">
@@ -154,6 +177,8 @@ export default {
154
177
  isBounded: PropTypes.bool,
155
178
  isDraggable: PropTypes.bool,
156
179
  isResizable: PropTypes.bool,
180
+ // If true, grid can be placed one over the other.
181
+ allowOverlap: PropTypes.bool,
157
182
  // If true, grid items won't change position when being dragged over.
158
183
  preventCollision: PropTypes.bool,
159
184
  // Use CSS transforms instead of top/left
@@ -164,7 +189,7 @@ export default {
164
189
  isDroppable: PropTypes.bool,
165
190
 
166
191
  // Resize handle options
167
- resizeHandles: resizeHandlesType,
192
+ resizeHandles: resizeHandleAxesType,
168
193
  resizeHandle: resizeHandleType,
169
194
 
170
195
  //
@@ -202,11 +227,12 @@ export default {
202
227
 
203
228
  // Children must not have duplicate keys.
204
229
  children: function (props: Props, propName: string) {
205
- var children = props[propName];
230
+ const children = props[propName];
206
231
 
207
232
  // Check children keys for duplicates. Throw if found.
208
- var keys = {};
233
+ const keys = {};
209
234
  React.Children.forEach(children, function (child) {
235
+ if (child?.key == null) return;
210
236
  if (keys[child.key]) {
211
237
  throw new Error(
212
238
  'Duplicate child key "' +
@@ -21,6 +21,7 @@ import {
21
21
  } from "./responsiveUtils";
22
22
  import ReactGridLayout from "./ReactGridLayout";
23
23
 
24
+ // $FlowFixMe[method-unbinding]
24
25
  const type = obj => Object.prototype.toString.call(obj);
25
26
 
26
27
  /**
@@ -74,6 +75,7 @@ type Props<Breakpoint: string = string> = {|
74
75
  type DefaultProps = Pick<
75
76
  Props<>,
76
77
  {|
78
+ allowOverlap: 0,
77
79
  breakpoints: 0,
78
80
  cols: 0,
79
81
  containerPadding: 0,
@@ -103,6 +105,8 @@ export default class ResponsiveReactGridLayout extends React.Component<
103
105
  // {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
104
106
  breakpoints: PropTypes.object,
105
107
 
108
+ allowOverlap: PropTypes.bool,
109
+
106
110
  // # of cols. This is a breakpoint -> cols map
107
111
  cols: PropTypes.object,
108
112
 
@@ -162,6 +166,7 @@ export default class ResponsiveReactGridLayout extends React.Component<
162
166
  containerPadding: { lg: null, md: null, sm: null, xs: null, xxs: null },
163
167
  layouts: {},
164
168
  margin: [10, 10],
169
+ allowOverlap: false,
165
170
  onBreakpointChange: noop,
166
171
  onLayoutChange: noop,
167
172
  onWidthChange: noop
@@ -277,7 +282,8 @@ export default class ResponsiveReactGridLayout extends React.Component<
277
282
  layout,
278
283
  this.props.children,
279
284
  newCols,
280
- compactType
285
+ compactType,
286
+ this.props.allowOverlap
281
287
  );
282
288
 
283
289
  // Store the new layout.
@@ -1,7 +1,8 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
3
  import PropTypes from "prop-types";
4
- import ReactDOM from "react-dom";
4
+ import classNames from "classnames";
5
+ import type { ReactRef } from "../ReactGridLayoutPropTypes";
5
6
 
6
7
  type WPDefaultProps = {|
7
8
  measureBeforeMount: boolean
@@ -18,29 +19,27 @@ type WPState = {|
18
19
  width: number
19
20
  |};
20
21
 
22
+ type ComposedProps<Config> = {|
23
+ ...Config,
24
+ measureBeforeMount?: boolean,
25
+ className?: string,
26
+ style?: Object,
27
+ width?: number
28
+ |};
29
+
30
+ const layoutClassName = "react-grid-layout";
31
+
21
32
  /*
22
33
  * A simple HOC that provides facility for listening to container resizes.
23
34
  *
24
35
  * The Flow type is pretty janky here. I can't just spread `WPProps` into this returned object - I wish I could - but it triggers
25
36
  * a flow bug of some sort that causes it to stop typechecking.
26
37
  */
27
- export default function WidthProvider<Config>(
38
+ export default function WidthProvideRGL<Config>(
28
39
  ComposedComponent: React.AbstractComponent<Config>
29
- ): React.AbstractComponent<{|
30
- ...Config,
31
- measureBeforeMount?: boolean,
32
- className?: string,
33
- style?: Object,
34
- width?: number
35
- |}> {
40
+ ): React.AbstractComponent<ComposedProps<Config>> {
36
41
  return class WidthProvider extends React.Component<
37
- {|
38
- ...Config,
39
- measureBeforeMount?: boolean,
40
- className?: string,
41
- style?: Object,
42
- width?: number
43
- |},
42
+ ComposedProps<Config>,
44
43
  WPState
45
44
  > {
46
45
  static defaultProps: WPDefaultProps = {
@@ -53,15 +52,15 @@ export default function WidthProvider<Config>(
53
52
  measureBeforeMount: PropTypes.bool
54
53
  };
55
54
 
56
- state = {
55
+ state: WPState = {
57
56
  width: 1280
58
57
  };
59
58
 
59
+ elementRef: ReactRef<HTMLDivElement> = React.createRef();
60
60
  mounted: boolean = false;
61
61
 
62
62
  componentDidMount() {
63
63
  this.mounted = true;
64
-
65
64
  window.addEventListener("resize", this.onWindowResize);
66
65
  // Call to properly set the breakpoint and resize the elements.
67
66
  // Note that if you're doing a full-width element, this can get a little wonky if a scrollbar
@@ -76,21 +75,34 @@ export default function WidthProvider<Config>(
76
75
 
77
76
  onWindowResize = () => {
78
77
  if (!this.mounted) return;
79
- // eslint-disable-next-line react/no-find-dom-node
80
- const node = ReactDOM.findDOMNode(this); // Flow casts this to Text | Element
81
- if (node instanceof HTMLElement)
78
+ const node = this.elementRef.current; // Flow casts this to Text | Element
79
+ // fix: grid position error when node or parentNode display is none by window resize
80
+ // #924 #1084
81
+ if (node instanceof HTMLElement && node.offsetWidth) {
82
82
  this.setState({ width: node.offsetWidth });
83
+ }
83
84
  };
84
85
 
85
86
  render() {
86
87
  const { measureBeforeMount, ...rest } = this.props;
87
88
  if (measureBeforeMount && !this.mounted) {
88
89
  return (
89
- <div className={this.props.className} style={this.props.style} />
90
+ <div
91
+ className={classNames(this.props.className, layoutClassName)}
92
+ style={this.props.style}
93
+ // $FlowIgnore ref types
94
+ ref={this.elementRef}
95
+ />
90
96
  );
91
97
  }
92
98
 
93
- return <ComposedComponent {...rest} {...this.state} />;
99
+ return (
100
+ <ComposedComponent
101
+ innerRef={this.elementRef}
102
+ {...rest}
103
+ {...this.state}
104
+ />
105
+ );
94
106
  }
95
107
  };
96
108
  }