react-grid-layout 1.3.4 → 1.4.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.
package/build/utils.js CHANGED
@@ -31,106 +31,136 @@ exports.sortLayoutItemsByRowCol = sortLayoutItemsByRowCol;
31
31
  exports.synchronizeLayoutWithChildren = synchronizeLayoutWithChildren;
32
32
  exports.validateLayout = validateLayout;
33
33
  exports.withLayoutItem = withLayoutItem;
34
-
35
- var _lodash = _interopRequireDefault(require("lodash.isequal"));
36
-
34
+ var _fastEquals = require("fast-equals");
37
35
  var _react = _interopRequireDefault(require("react"));
38
-
39
36
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
+ /*:: import type {
38
+ ChildrenArray as ReactChildrenArray,
39
+ Element as ReactElement
40
+ } from "react";*/
41
+ /*:: export type LayoutItem = {
42
+ w: number,
43
+ h: number,
44
+ x: number,
45
+ y: number,
46
+ i: string,
47
+ minW?: number,
48
+ minH?: number,
49
+ maxW?: number,
50
+ maxH?: number,
51
+ moved?: boolean,
52
+ static?: boolean,
53
+ isDraggable?: ?boolean,
54
+ isResizable?: ?boolean,
55
+ resizeHandles?: Array<"s" | "w" | "e" | "n" | "sw" | "nw" | "se" | "ne">,
56
+ isBounded?: ?boolean
57
+ };*/
58
+ /*:: export type Layout = $ReadOnlyArray<LayoutItem>;*/
59
+ /*:: export type Position = {
60
+ left: number,
61
+ top: number,
62
+ width: number,
63
+ height: number
64
+ };*/
65
+ /*:: export type ReactDraggableCallbackData = {
66
+ node: HTMLElement,
67
+ x?: number,
68
+ y?: number,
69
+ deltaX: number,
70
+ deltaY: number,
71
+ lastX?: number,
72
+ lastY?: number
73
+ };*/
74
+ /*:: export type PartialPosition = { left: number, top: number };*/
75
+ /*:: export type DroppingPosition = { left: number, top: number, e: Event };*/
76
+ /*:: export type Size = { width: number, height: number };*/
77
+ /*:: export type GridDragEvent = {
78
+ e: Event,
79
+ node: HTMLElement,
80
+ newPosition: PartialPosition
81
+ };*/
82
+ /*:: export type GridResizeEvent = {
83
+ e: Event,
84
+ node: HTMLElement,
85
+ size: Size,
86
+ handle: string
87
+ };*/
88
+ /*:: export type DragOverEvent = MouseEvent & {
89
+ nativeEvent: {
90
+ layerX: number,
91
+ layerY: number,
92
+ ...Event
93
+ }
94
+ };*/
95
+ /*:: export type Pick<FromType, Properties: { [string]: 0 }> = $Exact<
96
+ $ObjMapi<Properties, <K, V>(k: K, v: V) => $ElementType<FromType, K>>
97
+ >;*/
98
+ // Helpful port from TS
99
+ /*:: type REl = ReactElement<any>;*/
100
+ /*:: export type ReactChildren = ReactChildrenArray<REl>;*/
101
+ /*:: export type EventCallback = (
102
+ Layout,
103
+ oldItem: ?LayoutItem,
104
+ newItem: ?LayoutItem,
105
+ placeholder: ?LayoutItem,
106
+ Event,
107
+ ?HTMLElement
108
+ ) => void;*/
109
+ // All callbacks are of the signature (layout, oldItem, newItem, placeholder, e).
110
+ /*:: export type CompactType = ?("horizontal" | "vertical");*/
111
+ const isProduction = process.env.NODE_ENV === "production";
112
+ const DEBUG = false;
40
113
 
41
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
42
-
43
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
44
-
45
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
46
-
47
- var isProduction = process.env.NODE_ENV === "production";
48
- var DEBUG = false;
49
114
  /**
50
115
  * Return the bottom coordinate of the layout.
51
116
  *
52
117
  * @param {Array} layout Layout array.
53
118
  * @return {Number} Bottom coordinate.
54
119
  */
55
-
56
- function bottom(layout
57
- /*: Layout*/
58
- )
59
- /*: number*/
60
- {
61
- var max = 0,
62
- bottomY;
63
-
64
- for (var i = 0, len = layout.length; i < len; i++) {
120
+ function bottom(layout /*: Layout*/) /*: number*/{
121
+ let max = 0,
122
+ bottomY;
123
+ for (let i = 0, len = layout.length; i < len; i++) {
65
124
  bottomY = layout[i].y + layout[i].h;
66
125
  if (bottomY > max) max = bottomY;
67
126
  }
68
-
69
127
  return max;
70
128
  }
71
-
72
- function cloneLayout(layout
73
- /*: Layout*/
74
- )
75
- /*: Layout*/
76
- {
77
- var newLayout = Array(layout.length);
78
-
79
- for (var i = 0, len = layout.length; i < len; i++) {
129
+ function cloneLayout(layout /*: Layout*/) /*: Layout*/{
130
+ const newLayout = Array(layout.length);
131
+ for (let i = 0, len = layout.length; i < len; i++) {
80
132
  newLayout[i] = cloneLayoutItem(layout[i]);
81
133
  }
82
-
83
134
  return newLayout;
84
- } // Modify a layoutItem inside a layout. Returns a new Layout,
85
- // does not mutate. Carries over all other LayoutItems unmodified.
86
-
87
-
88
- function modifyLayout(layout
89
- /*: Layout*/
90
- , layoutItem
91
- /*: LayoutItem*/
92
- )
93
- /*: Layout*/
94
- {
95
- var newLayout = Array(layout.length);
135
+ }
96
136
 
97
- for (var i = 0, len = layout.length; i < len; i++) {
137
+ // Modify a layoutItem inside a layout. Returns a new Layout,
138
+ // does not mutate. Carries over all other LayoutItems unmodified.
139
+ function modifyLayout(layout /*: Layout*/, layoutItem /*: LayoutItem*/) /*: Layout*/{
140
+ const newLayout = Array(layout.length);
141
+ for (let i = 0, len = layout.length; i < len; i++) {
98
142
  if (layoutItem.i === layout[i].i) {
99
143
  newLayout[i] = layoutItem;
100
144
  } else {
101
145
  newLayout[i] = layout[i];
102
146
  }
103
147
  }
104
-
105
148
  return newLayout;
106
- } // Function to be called to modify a layout item.
107
- // Does defensive clones to ensure the layout is not modified.
108
-
149
+ }
109
150
 
110
- function withLayoutItem(layout
111
- /*: Layout*/
112
- , itemKey
113
- /*: string*/
114
- , cb
115
- /*: LayoutItem => LayoutItem*/
116
- )
117
- /*: [Layout, ?LayoutItem]*/
118
- {
119
- var item = getLayoutItem(layout, itemKey);
151
+ // Function to be called to modify a layout item.
152
+ // Does defensive clones to ensure the layout is not modified.
153
+ function withLayoutItem(layout /*: Layout*/, itemKey /*: string*/, cb /*: LayoutItem => LayoutItem*/) /*: [Layout, ?LayoutItem]*/{
154
+ let item = getLayoutItem(layout, itemKey);
120
155
  if (!item) return [layout, null];
121
156
  item = cb(cloneLayoutItem(item)); // defensive clone then modify
122
157
  // FIXME could do this faster if we already knew the index
123
-
124
158
  layout = modifyLayout(layout, item);
125
159
  return [layout, item];
126
- } // Fast path to cloning, since this is monomorphic
127
-
160
+ }
128
161
 
129
- function cloneLayoutItem(layoutItem
130
- /*: LayoutItem*/
131
- )
132
- /*: LayoutItem*/
133
- {
162
+ // Fast path to cloning, since this is monomorphic
163
+ function cloneLayoutItem(layoutItem /*: LayoutItem*/) /*: LayoutItem*/{
134
164
  return {
135
165
  w: layoutItem.w,
136
166
  h: layoutItem.h,
@@ -150,25 +180,15 @@ function cloneLayoutItem(layoutItem
150
180
  isBounded: layoutItem.isBounded
151
181
  };
152
182
  }
183
+
153
184
  /**
154
185
  * Comparing React `children` is a bit difficult. This is a good way to compare them.
155
186
  * This will catch differences in keys, order, and length.
156
187
  */
157
-
158
-
159
- function childrenEqual(a
160
- /*: ReactChildren*/
161
- , b
162
- /*: ReactChildren*/
163
- )
164
- /*: boolean*/
165
- {
166
- return (0, _lodash.default)(_react.default.Children.map(a, function (c) {
167
- return c === null || c === void 0 ? void 0 : c.key;
168
- }), _react.default.Children.map(b, function (c) {
169
- return c === null || c === void 0 ? void 0 : c.key;
170
- }));
188
+ function childrenEqual(a /*: ReactChildren*/, b /*: ReactChildren*/) /*: boolean*/{
189
+ return (0, _fastEquals.deepEqual)(_react.default.Children.map(a, c => c === null || c === void 0 ? void 0 : c.key), _react.default.Children.map(b, c => c === null || c === void 0 ? void 0 : c.key)) && (0, _fastEquals.deepEqual)(_react.default.Children.map(a, c => c === null || c === void 0 ? void 0 : c.props["data-grid"]), _react.default.Children.map(b, c => c === null || c === void 0 ? void 0 : c.props["data-grid"]));
171
190
  }
191
+
172
192
  /**
173
193
  * See `fastRGLPropsEqual.js`.
174
194
  * We want this to run as fast as possible - it is called often - and to be
@@ -177,50 +197,27 @@ function childrenEqual(a
177
197
  * function in conjunction with preval to generate the fastest possible comparison
178
198
  * function, tuned for exactly our props.
179
199
  */
180
-
181
200
  /*:: type FastRGLPropsEqual = (Object, Object, Function) => boolean;*/
201
+ const fastRGLPropsEqual /*: FastRGLPropsEqual*/ = require("./fastRGLPropsEqual");
182
202
 
183
-
184
- var fastRGLPropsEqual
185
- /*: FastRGLPropsEqual*/
186
- = require("./fastRGLPropsEqual"); // Like the above, but a lot simpler.
187
-
188
-
203
+ // Like the above, but a lot simpler.
189
204
  exports.fastRGLPropsEqual = fastRGLPropsEqual;
190
-
191
- function fastPositionEqual(a
192
- /*: Position*/
193
- , b
194
- /*: Position*/
195
- )
196
- /*: boolean*/
197
- {
205
+ function fastPositionEqual(a /*: Position*/, b /*: Position*/) /*: boolean*/{
198
206
  return a.left === b.left && a.top === b.top && a.width === b.width && a.height === b.height;
199
207
  }
208
+
200
209
  /**
201
210
  * Given two layoutitems, check if they collide.
202
211
  */
203
-
204
-
205
- function collides(l1
206
- /*: LayoutItem*/
207
- , l2
208
- /*: LayoutItem*/
209
- )
210
- /*: boolean*/
211
- {
212
+ function collides(l1 /*: LayoutItem*/, l2 /*: LayoutItem*/) /*: boolean*/{
212
213
  if (l1.i === l2.i) return false; // same element
213
-
214
214
  if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2
215
-
216
215
  if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2
217
-
218
216
  if (l1.y + l1.h <= l2.y) return false; // l1 is above l2
219
-
220
217
  if (l1.y >= l2.y + l2.h) return false; // l1 is below l2
221
-
222
218
  return true; // boxes overlap
223
219
  }
220
+
224
221
  /**
225
222
  * Given a layout, compact it. This involves going down each y coordinate and removing gaps
226
223
  * between items.
@@ -230,113 +227,81 @@ function collides(l1
230
227
  * @param {Array} layout Layout.
231
228
  * @param {Boolean} verticalCompact Whether or not to compact the layout
232
229
  * vertically.
230
+ * @param {Boolean} allowOverlap When `true`, allows overlapping grid items.
233
231
  * @return {Array} Compacted Layout.
234
232
  */
235
-
236
-
237
- function compact(layout
238
- /*: Layout*/
239
- , compactType
240
- /*: CompactType*/
241
- , cols
242
- /*: number*/
243
- )
244
- /*: Layout*/
245
- {
233
+ function compact(layout /*: Layout*/, compactType /*: CompactType*/, cols /*: number*/, allowOverlap /*: ?boolean*/) /*: Layout*/{
246
234
  // Statics go in the compareWith array right away so items flow around them.
247
- var compareWith = getStatics(layout); // We go through the items by row and column.
248
-
249
- var sorted = sortLayoutItems(layout, compactType); // Holding for new items.
250
-
251
- var out = Array(layout.length);
252
-
253
- for (var i = 0, len = sorted.length; i < len; i++) {
254
- var l = cloneLayoutItem(sorted[i]); // Don't move static elements
255
-
235
+ const compareWith = getStatics(layout);
236
+ // We go through the items by row and column.
237
+ const sorted = sortLayoutItems(layout, compactType);
238
+ // Holding for new items.
239
+ const out = Array(layout.length);
240
+ for (let i = 0, len = sorted.length; i < len; i++) {
241
+ let l = cloneLayoutItem(sorted[i]);
242
+
243
+ // Don't move static elements
256
244
  if (!l.static) {
257
- l = compactItem(compareWith, l, compactType, cols, sorted); // Add to comparison array. We only collide with items before this one.
258
- // Statics are already in this array.
245
+ l = compactItem(compareWith, l, compactType, cols, sorted, allowOverlap);
259
246
 
247
+ // Add to comparison array. We only collide with items before this one.
248
+ // Statics are already in this array.
260
249
  compareWith.push(l);
261
- } // Add to output array to make sure they still come out in the right order.
262
-
250
+ }
263
251
 
264
- out[layout.indexOf(sorted[i])] = l; // Clear moved flag, if it exists.
252
+ // Add to output array to make sure they still come out in the right order.
253
+ out[layout.indexOf(sorted[i])] = l;
265
254
 
255
+ // Clear moved flag, if it exists.
266
256
  l.moved = false;
267
257
  }
268
-
269
258
  return out;
270
259
  }
271
-
272
- var heightWidth = {
260
+ const heightWidth = {
273
261
  x: "w",
274
262
  y: "h"
275
263
  };
276
264
  /**
277
265
  * Before moving item down, it will check if the movement will cause collisions and move those items down before.
278
266
  */
279
-
280
- function resolveCompactionCollision(layout
281
- /*: Layout*/
282
- , item
283
- /*: LayoutItem*/
284
- , moveToCoord
285
- /*: number*/
286
- , axis
287
- /*: "x" | "y"*/
288
- ) {
289
- var sizeProp = heightWidth[axis];
267
+ function resolveCompactionCollision(layout /*: Layout*/, item /*: LayoutItem*/, moveToCoord /*: number*/, axis /*: "x" | "y"*/) {
268
+ const sizeProp = heightWidth[axis];
290
269
  item[axis] += 1;
291
- var itemIndex = layout.map(function (layoutItem) {
270
+ const itemIndex = layout.map(layoutItem => {
292
271
  return layoutItem.i;
293
- }).indexOf(item.i); // Go through each item we collide with.
272
+ }).indexOf(item.i);
294
273
 
295
- for (var i = itemIndex + 1; i < layout.length; i++) {
296
- var otherItem = layout[i]; // Ignore static items
274
+ // Go through each item we collide with.
275
+ for (let i = itemIndex + 1; i < layout.length; i++) {
276
+ const otherItem = layout[i];
277
+ // Ignore static items
278
+ if (otherItem.static) continue;
297
279
 
298
- if (otherItem.static) continue; // Optimization: we can break early if we know we're past this el
280
+ // Optimization: we can break early if we know we're past this el
299
281
  // We can do this b/c it's a sorted layout
300
-
301
282
  if (otherItem.y > item.y + item.h) break;
302
-
303
283
  if (collides(item, otherItem)) {
304
284
  resolveCompactionCollision(layout, otherItem, moveToCoord + item[sizeProp], axis);
305
285
  }
306
286
  }
307
-
308
287
  item[axis] = moveToCoord;
309
288
  }
289
+
310
290
  /**
311
291
  * Compact an item in the layout.
312
292
  *
313
293
  * Modifies item.
314
294
  *
315
295
  */
316
-
317
-
318
- function compactItem(compareWith
319
- /*: Layout*/
320
- , l
321
- /*: LayoutItem*/
322
- , compactType
323
- /*: CompactType*/
324
- , cols
325
- /*: number*/
326
- , fullLayout
327
- /*: Layout*/
328
- )
329
- /*: LayoutItem*/
330
- {
331
- var compactV = compactType === "vertical";
332
- var compactH = compactType === "horizontal";
333
-
296
+ function compactItem(compareWith /*: Layout*/, l /*: LayoutItem*/, compactType /*: CompactType*/, cols /*: number*/, fullLayout /*: Layout*/, allowOverlap /*: ?boolean*/) /*: LayoutItem*/{
297
+ const compactV = compactType === "vertical";
298
+ const compactH = compactType === "horizontal";
334
299
  if (compactV) {
335
300
  // Bottom 'y' possible is the bottom of the layout.
336
301
  // This allows you to do nice stuff like specify {y: Infinity}
337
302
  // This is here because the layout must be sorted in order to get the correct bottom `y`.
338
- l.y = Math.min(bottom(compareWith), l.y); // Move the element up as far as it can go without colliding.
339
-
303
+ l.y = Math.min(bottom(compareWith), l.y);
304
+ // Move the element up as far as it can go without colliding.
340
305
  while (l.y > 0 && !getFirstCollision(compareWith, l)) {
341
306
  l.y--;
342
307
  }
@@ -345,30 +310,34 @@ function compactItem(compareWith
345
310
  while (l.x > 0 && !getFirstCollision(compareWith, l)) {
346
311
  l.x--;
347
312
  }
348
- } // Move it down, and keep moving it down if it's colliding.
349
-
350
-
351
- var collides;
313
+ }
352
314
 
353
- while (collides = getFirstCollision(compareWith, l)) {
315
+ // Move it down, and keep moving it down if it's colliding.
316
+ let collides;
317
+ // Checking the compactType null value to avoid breaking the layout when overlapping is allowed.
318
+ while ((collides = getFirstCollision(compareWith, l)) && !(compactType === null && allowOverlap)) {
354
319
  if (compactH) {
355
320
  resolveCompactionCollision(fullLayout, l, collides.x + collides.w, "x");
356
321
  } else {
357
322
  resolveCompactionCollision(fullLayout, l, collides.y + collides.h, "y");
358
- } // Since we can't grow without bounds horizontally, if we've overflown, let's move it down and try again.
359
-
360
-
323
+ }
324
+ // Since we can't grow without bounds horizontally, if we've overflown, let's move it down and try again.
361
325
  if (compactH && l.x + l.w > cols) {
362
326
  l.x = cols - l.w;
363
327
  l.y++;
328
+ // ALso move element as left as we can
329
+ while (l.x > 0 && !getFirstCollision(compareWith, l)) {
330
+ l.x--;
331
+ }
364
332
  }
365
- } // Ensure that there are no negative positions
366
-
333
+ }
367
334
 
335
+ // Ensure that there are no negative positions
368
336
  l.y = Math.max(l.y, 0);
369
337
  l.x = Math.max(l.x, 0);
370
338
  return l;
371
339
  }
340
+
372
341
  /**
373
342
  * Given a layout, make sure all elements fit within its bounds.
374
343
  *
@@ -377,27 +346,17 @@ function compactItem(compareWith
377
346
  * @param {Array} layout Layout array.
378
347
  * @param {Number} bounds Number of columns.
379
348
  */
380
-
381
-
382
- function correctBounds(layout
383
- /*: Layout*/
384
- , bounds
385
- /*: { cols: number }*/
386
- )
387
- /*: Layout*/
388
- {
389
- var collidesWith = getStatics(layout);
390
-
391
- for (var i = 0, len = layout.length; i < len; i++) {
392
- var l = layout[i]; // Overflows right
393
-
394
- if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w; // Overflows left
395
-
349
+ function correctBounds(layout /*: Layout*/, bounds /*: { cols: number }*/) /*: Layout*/{
350
+ const collidesWith = getStatics(layout);
351
+ for (let i = 0, len = layout.length; i < len; i++) {
352
+ const l = layout[i];
353
+ // Overflows right
354
+ if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w;
355
+ // Overflows left
396
356
  if (l.x < 0) {
397
357
  l.x = 0;
398
358
  l.w = bounds.cols;
399
359
  }
400
-
401
360
  if (!l.static) collidesWith.push(l);else {
402
361
  // If this is static and collides with other statics, we must move it down.
403
362
  // We have to do something nicer than just letting them overlap.
@@ -406,9 +365,9 @@ function correctBounds(layout
406
365
  }
407
366
  }
408
367
  }
409
-
410
368
  return layout;
411
369
  }
370
+
412
371
  /**
413
372
  * Get a layout item by ID. Used so we can override later on if necessary.
414
373
  *
@@ -416,19 +375,12 @@ function correctBounds(layout
416
375
  * @param {String} id ID
417
376
  * @return {LayoutItem} Item at ID.
418
377
  */
419
-
420
-
421
- function getLayoutItem(layout
422
- /*: Layout*/
423
- , id
424
- /*: string*/
425
- )
426
- /*: ?LayoutItem*/
427
- {
428
- for (var i = 0, len = layout.length; i < len; i++) {
378
+ function getLayoutItem(layout /*: Layout*/, id /*: string*/) /*: ?LayoutItem*/{
379
+ for (let i = 0, len = layout.length; i < len; i++) {
429
380
  if (layout[i].i === id) return layout[i];
430
381
  }
431
382
  }
383
+
432
384
  /**
433
385
  * Returns the first item this layout collides with.
434
386
  * It doesn't appear to matter which order we approach this from, although
@@ -437,47 +389,24 @@ function getLayoutItem(layout
437
389
  * @param {Object} layoutItem Layout item.
438
390
  * @return {Object|undefined} A colliding layout item, or undefined.
439
391
  */
440
-
441
-
442
- function getFirstCollision(layout
443
- /*: Layout*/
444
- , layoutItem
445
- /*: LayoutItem*/
446
- )
447
- /*: ?LayoutItem*/
448
- {
449
- for (var i = 0, len = layout.length; i < len; i++) {
392
+ function getFirstCollision(layout /*: Layout*/, layoutItem /*: LayoutItem*/) /*: ?LayoutItem*/{
393
+ for (let i = 0, len = layout.length; i < len; i++) {
450
394
  if (collides(layout[i], layoutItem)) return layout[i];
451
395
  }
452
396
  }
453
-
454
- function getAllCollisions(layout
455
- /*: Layout*/
456
- , layoutItem
457
- /*: LayoutItem*/
458
- )
459
- /*: Array<LayoutItem>*/
460
- {
461
- return layout.filter(function (l) {
462
- return collides(l, layoutItem);
463
- });
397
+ function getAllCollisions(layout /*: Layout*/, layoutItem /*: LayoutItem*/) /*: Array<LayoutItem>*/{
398
+ return layout.filter(l => collides(l, layoutItem));
464
399
  }
400
+
465
401
  /**
466
402
  * Get all static elements.
467
403
  * @param {Array} layout Array of layout objects.
468
404
  * @return {Array} Array of static layout items..
469
405
  */
470
-
471
-
472
- function getStatics(layout
473
- /*: Layout*/
474
- )
475
- /*: Array<LayoutItem>*/
476
- {
477
- return layout.filter(function (l) {
478
- return l.static;
479
- });
406
+ function getStatics(layout /*: Layout*/) /*: Array<LayoutItem>*/{
407
+ return layout.filter(l => l.static);
480
408
  }
409
+
481
410
  /**
482
411
  * Move an element. Responsible for doing cascading movements of other elements.
483
412
  *
@@ -488,53 +417,35 @@ function getStatics(layout
488
417
  * @param {Number} [x] X position in grid units.
489
418
  * @param {Number} [y] Y position in grid units.
490
419
  */
491
-
492
-
493
- function moveElement(layout
494
- /*: Layout*/
495
- , l
496
- /*: LayoutItem*/
497
- , x
498
- /*: ?number*/
499
- , y
500
- /*: ?number*/
501
- , isUserAction
502
- /*: ?boolean*/
503
- , preventCollision
504
- /*: ?boolean*/
505
- , compactType
506
- /*: CompactType*/
507
- , cols
508
- /*: number*/
509
- , allowOverlap
510
- /*: ?boolean*/
511
- )
512
- /*: Layout*/
513
- {
420
+ function moveElement(layout /*: Layout*/, l /*: LayoutItem*/, x /*: ?number*/, y /*: ?number*/, isUserAction /*: ?boolean*/, preventCollision /*: ?boolean*/, compactType /*: CompactType*/, cols /*: number*/, allowOverlap /*: ?boolean*/) /*: Layout*/{
514
421
  // If this is static and not explicitly enabled as draggable,
515
422
  // no move is possible, so we can short-circuit this immediately.
516
- if (l.static && l.isDraggable !== true) return layout; // Short-circuit if nothing to do.
423
+ if (l.static && l.isDraggable !== true) return layout;
517
424
 
425
+ // Short-circuit if nothing to do.
518
426
  if (l.y === y && l.x === x) return layout;
519
427
  log("Moving element ".concat(l.i, " to [").concat(String(x), ",").concat(String(y), "] from [").concat(l.x, ",").concat(l.y, "]"));
520
- var oldX = l.x;
521
- var oldY = l.y; // This is quite a bit faster than extending the object
428
+ const oldX = l.x;
429
+ const oldY = l.y;
522
430
 
431
+ // This is quite a bit faster than extending the object
523
432
  if (typeof x === "number") l.x = x;
524
433
  if (typeof y === "number") l.y = y;
525
- l.moved = true; // If this collides with anything, move it.
434
+ l.moved = true;
435
+
436
+ // If this collides with anything, move it.
526
437
  // When doing this comparison, we have to sort the items we compare with
527
438
  // to ensure, in the case of multiple collisions, that we're getting the
528
439
  // nearest collision.
529
-
530
- var sorted = sortLayoutItems(layout, compactType);
531
- var movingUp = compactType === "vertical" && typeof y === "number" ? oldY >= y : compactType === "horizontal" && typeof x === "number" ? oldX >= x : false; // $FlowIgnore acceptable modification of read-only array as it was recently cloned
532
-
440
+ let sorted = sortLayoutItems(layout, compactType);
441
+ const movingUp = compactType === "vertical" && typeof y === "number" ? oldY >= y : compactType === "horizontal" && typeof x === "number" ? oldX >= x : false;
442
+ // $FlowIgnore acceptable modification of read-only array as it was recently cloned
533
443
  if (movingUp) sorted = sorted.reverse();
534
- var collisions = getAllCollisions(sorted, l);
535
- var hasCollisions = collisions.length > 0; // We may have collisions. We can short-circuit if we've turned off collisions or
536
- // allowed overlap.
444
+ const collisions = getAllCollisions(sorted, l);
445
+ const hasCollisions = collisions.length > 0;
537
446
 
447
+ // We may have collisions. We can short-circuit if we've turned off collisions or
448
+ // allowed overlap.
538
449
  if (hasCollisions && allowOverlap) {
539
450
  // Easy, we don't need to resolve collisions. But we *did* change the layout,
540
451
  // so clone it on the way out.
@@ -548,24 +459,26 @@ function moveElement(layout
548
459
  l.y = oldY;
549
460
  l.moved = false;
550
461
  return layout; // did not change so don't clone
551
- } // Move each item that collides away from this element.
552
-
462
+ }
553
463
 
554
- for (var i = 0, len = collisions.length; i < len; i++) {
555
- var collision = collisions[i];
556
- log("Resolving collision between ".concat(l.i, " at [").concat(l.x, ",").concat(l.y, "] and ").concat(collision.i, " at [").concat(collision.x, ",").concat(collision.y, "]")); // Short circuit so we can't infinite loop
464
+ // Move each item that collides away from this element.
465
+ for (let i = 0, len = collisions.length; i < len; i++) {
466
+ const collision = collisions[i];
467
+ log("Resolving collision between ".concat(l.i, " at [").concat(l.x, ",").concat(l.y, "] and ").concat(collision.i, " at [").concat(collision.x, ",").concat(collision.y, "]"));
557
468
 
558
- if (collision.moved) continue; // Don't move static items - we have to move *this* element away
469
+ // Short circuit so we can't infinite loop
470
+ if (collision.moved) continue;
559
471
 
472
+ // Don't move static items - we have to move *this* element away
560
473
  if (collision.static) {
561
474
  layout = moveElementAwayFromCollision(layout, collision, l, isUserAction, compactType, cols);
562
475
  } else {
563
476
  layout = moveElementAwayFromCollision(layout, l, collision, isUserAction, compactType, cols);
564
477
  }
565
478
  }
566
-
567
479
  return layout;
568
480
  }
481
+
569
482
  /**
570
483
  * This is where the magic needs to happen - given a collision, move an element away from the collision.
571
484
  * We attempt to move it up if there's room, otherwise it goes below.
@@ -574,78 +487,71 @@ function moveElement(layout
574
487
  * @param {LayoutItem} collidesWith Layout item we're colliding with.
575
488
  * @param {LayoutItem} itemToMove Layout item we're moving.
576
489
  */
490
+ function moveElementAwayFromCollision(layout /*: Layout*/, collidesWith /*: LayoutItem*/, itemToMove /*: LayoutItem*/, isUserAction /*: ?boolean*/, compactType /*: CompactType*/, cols /*: number*/) /*: Layout*/{
491
+ const compactH = compactType === "horizontal";
492
+ // Compact vertically if not set to horizontal
493
+ const compactV = compactType === "vertical";
494
+ const preventCollision = collidesWith.static; // we're already colliding (not for static items)
577
495
 
578
-
579
- function moveElementAwayFromCollision(layout
580
- /*: Layout*/
581
- , collidesWith
582
- /*: LayoutItem*/
583
- , itemToMove
584
- /*: LayoutItem*/
585
- , isUserAction
586
- /*: ?boolean*/
587
- , compactType
588
- /*: CompactType*/
589
- , cols
590
- /*: number*/
591
- )
592
- /*: Layout*/
593
- {
594
- var compactH = compactType === "horizontal"; // Compact vertically if not set to horizontal
595
-
596
- var compactV = compactType !== "horizontal";
597
- var preventCollision = collidesWith.static; // we're already colliding (not for static items)
598
496
  // If there is enough space above the collision to put this element, move it there.
599
497
  // We only do this on the main collision as this can get funky in cascades and cause
600
498
  // unwanted swapping behavior.
601
-
602
499
  if (isUserAction) {
603
500
  // Reset isUserAction flag because we're not in the main collision anymore.
604
- isUserAction = false; // Make a mock item so we don't modify the item here, only modify in moveElement.
501
+ isUserAction = false;
605
502
 
606
- var fakeItem
607
- /*: LayoutItem*/
608
- = {
503
+ // Make a mock item so we don't modify the item here, only modify in moveElement.
504
+ const fakeItem /*: LayoutItem*/ = {
609
505
  x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
610
506
  y: compactV ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
611
507
  w: itemToMove.w,
612
508
  h: itemToMove.h,
613
509
  i: "-1"
614
- }; // No collision? If so, we can go up there; otherwise, we'll end up moving down as normal
510
+ };
511
+ const firstCollision = getFirstCollision(layout, fakeItem);
512
+ const collisionNorth = firstCollision && firstCollision.y + firstCollision.h > collidesWith.y;
513
+ const collisionWest = firstCollision && collidesWith.x + collidesWith.w > firstCollision.x;
615
514
 
616
- if (!getFirstCollision(layout, fakeItem)) {
515
+ // No collision? If so, we can go up there; otherwise, we'll end up moving down as normal
516
+ if (!firstCollision) {
617
517
  log("Doing reverse collision on ".concat(itemToMove.i, " up to [").concat(fakeItem.x, ",").concat(fakeItem.y, "]."));
618
518
  return moveElement(layout, itemToMove, compactH ? fakeItem.x : undefined, compactV ? fakeItem.y : undefined, isUserAction, preventCollision, compactType, cols);
519
+ } else if (collisionNorth && compactV) {
520
+ return moveElement(layout, itemToMove, undefined, collidesWith.y + 1, isUserAction, preventCollision, compactType, cols);
521
+ } else if (collisionNorth && compactType == null) {
522
+ collidesWith.y = itemToMove.y;
523
+ itemToMove.y = itemToMove.y + itemToMove.h;
524
+ return layout;
525
+ } else if (collisionWest && compactH) {
526
+ return moveElement(layout, collidesWith, itemToMove.x, undefined, isUserAction, preventCollision, compactType, cols);
619
527
  }
620
528
  }
621
-
529
+ const newX = compactH ? itemToMove.x + 1 : undefined;
530
+ const newY = compactV ? itemToMove.y + 1 : undefined;
531
+ if (newX == null && newY == null) {
532
+ return layout;
533
+ }
622
534
  return moveElement(layout, itemToMove, compactH ? itemToMove.x + 1 : undefined, compactV ? itemToMove.y + 1 : undefined, isUserAction, preventCollision, compactType, cols);
623
535
  }
536
+
624
537
  /**
625
538
  * Helper to convert a number to a percentage string.
626
539
  *
627
540
  * @param {Number} num Any number
628
541
  * @return {String} That number as a percentage.
629
542
  */
630
-
631
-
632
- function perc(num
633
- /*: number*/
634
- )
635
- /*: string*/
636
- {
543
+ function perc(num /*: number*/) /*: string*/{
637
544
  return num * 100 + "%";
638
545
  }
639
-
640
- function setTransform(_ref)
641
- /*: Object*/
642
- {
643
- var top = _ref.top,
644
- left = _ref.left,
645
- width = _ref.width,
646
- height = _ref.height;
546
+ function setTransform(_ref /*:: */) /*: Object*/{
547
+ let {
548
+ top,
549
+ left,
550
+ width,
551
+ height
552
+ } /*: Position*/ = _ref /*: Position*/;
647
553
  // Replace unitless items with px
648
- var translate = "translate(".concat(left, "px,").concat(top, "px)");
554
+ const translate = "translate(".concat(left, "px,").concat(top, "px)");
649
555
  return {
650
556
  transform: translate,
651
557
  WebkitTransform: translate,
@@ -657,14 +563,13 @@ function setTransform(_ref)
657
563
  position: "absolute"
658
564
  };
659
565
  }
660
-
661
- function setTopLeft(_ref2)
662
- /*: Object*/
663
- {
664
- var top = _ref2.top,
665
- left = _ref2.left,
666
- width = _ref2.width,
667
- height = _ref2.height;
566
+ function setTopLeft(_ref2 /*:: */) /*: Object*/{
567
+ let {
568
+ top,
569
+ left,
570
+ width,
571
+ height
572
+ } /*: Position*/ = _ref2 /*: Position*/;
668
573
  return {
669
574
  top: "".concat(top, "px"),
670
575
  left: "".concat(left, "px"),
@@ -673,36 +578,24 @@ function setTopLeft(_ref2)
673
578
  position: "absolute"
674
579
  };
675
580
  }
581
+
676
582
  /**
677
583
  * Get layout items sorted from top left to right and down.
678
584
  *
679
585
  * @return {Array} Array of layout objects.
680
586
  * @return {Array} Layout, sorted static items first.
681
587
  */
682
-
683
-
684
- function sortLayoutItems(layout
685
- /*: Layout*/
686
- , compactType
687
- /*: CompactType*/
688
- )
689
- /*: Layout*/
690
- {
588
+ function sortLayoutItems(layout /*: Layout*/, compactType /*: CompactType*/) /*: Layout*/{
691
589
  if (compactType === "horizontal") return sortLayoutItemsByColRow(layout);
692
590
  if (compactType === "vertical") return sortLayoutItemsByRowCol(layout);else return layout;
693
591
  }
592
+
694
593
  /**
695
594
  * Sort layout items by row ascending and column ascending.
696
595
  *
697
596
  * Does not modify Layout.
698
597
  */
699
-
700
-
701
- function sortLayoutItemsByRowCol(layout
702
- /*: Layout*/
703
- )
704
- /*: Layout*/
705
- {
598
+ function sortLayoutItemsByRowCol(layout /*: Layout*/) /*: Layout*/{
706
599
  // Slice to clone array as sort modifies
707
600
  return layout.slice(0).sort(function (a, b) {
708
601
  if (a.y > b.y || a.y === b.y && a.x > b.x) {
@@ -711,30 +604,24 @@ function sortLayoutItemsByRowCol(layout
711
604
  // Without this, we can get different sort results in IE vs. Chrome/FF
712
605
  return 0;
713
606
  }
714
-
715
607
  return -1;
716
608
  });
717
609
  }
610
+
718
611
  /**
719
612
  * Sort layout items by column ascending then row ascending.
720
613
  *
721
614
  * Does not modify Layout.
722
615
  */
723
-
724
-
725
- function sortLayoutItemsByColRow(layout
726
- /*: Layout*/
727
- )
728
- /*: Layout*/
729
- {
616
+ function sortLayoutItemsByColRow(layout /*: Layout*/) /*: Layout*/{
730
617
  return layout.slice(0).sort(function (a, b) {
731
618
  if (a.x > b.x || a.x === b.x && a.y > b.y) {
732
619
  return 1;
733
620
  }
734
-
735
621
  return -1;
736
622
  });
737
623
  }
624
+
738
625
  /**
739
626
  * Generate a layout using the initialLayout and children as a template.
740
627
  * Missing entries will be added, extraneous ones will be truncated.
@@ -746,53 +633,31 @@ function sortLayoutItemsByColRow(layout
746
633
  * @param {?String} compact Compaction option.
747
634
  * @return {Array} Working layout.
748
635
  */
636
+ function synchronizeLayoutWithChildren(initialLayout /*: Layout*/, children /*: ReactChildren*/, cols /*: number*/, compactType /*: CompactType*/, allowOverlap /*: ?boolean*/) /*: Layout*/{
637
+ initialLayout = initialLayout || [];
749
638
 
750
-
751
- function synchronizeLayoutWithChildren(initialLayout
752
- /*: Layout*/
753
- , children
754
- /*: ReactChildren*/
755
- , cols
756
- /*: number*/
757
- , compactType
758
- /*: CompactType*/
759
- , allowOverlap
760
- /*: ?boolean*/
761
- )
762
- /*: Layout*/
763
- {
764
- initialLayout = initialLayout || []; // Generate one layout item per child.
765
-
766
- var layout
767
- /*: LayoutItem[]*/
768
- = [];
769
-
770
- _react.default.Children.forEach(children, function (child
771
- /*: ReactElement<any>*/
772
- ) {
639
+ // Generate one layout item per child.
640
+ const layout /*: LayoutItem[]*/ = [];
641
+ _react.default.Children.forEach(children, (child /*: ReactElement<any>*/) => {
773
642
  // Child may not exist
774
- if ((child === null || child === void 0 ? void 0 : child.key) == null) return; // Don't overwrite if it already exists.
775
-
776
- var exists = getLayoutItem(initialLayout, String(child.key));
777
-
778
- if (exists) {
643
+ if ((child === null || child === void 0 ? void 0 : child.key) == null) return;
644
+ const exists = getLayoutItem(initialLayout, String(child.key));
645
+ const g = child.props["data-grid"];
646
+ // Don't overwrite the layout item if it's already in the initial layout.
647
+ // If it has a `data-grid` property, prefer that over what's in the layout.
648
+ if (exists && g == null) {
779
649
  layout.push(cloneLayoutItem(exists));
780
650
  } else {
781
- if (!isProduction && child.props._grid) {
782
- console.warn("`_grid` properties on children have been deprecated as of React 15.2. " + "Please use `data-grid` or add your properties directly to the `layout`.");
783
- }
784
-
785
- var g = child.props["data-grid"] || child.props._grid; // Hey, this item has a data-grid property, use it.
786
-
651
+ // Hey, this item has a data-grid property, use it.
787
652
  if (g) {
788
653
  if (!isProduction) {
789
654
  validateLayout([g], "ReactGridLayout.children");
790
- } // FIXME clone not really necessary here
791
-
792
-
793
- layout.push(cloneLayoutItem(_objectSpread(_objectSpread({}, g), {}, {
655
+ }
656
+ // FIXME clone not really necessary here
657
+ layout.push(cloneLayoutItem({
658
+ ...g,
794
659
  i: child.key
795
- })));
660
+ }));
796
661
  } else {
797
662
  // Nothing provided: ensure this is added to the bottom
798
663
  // FIXME clone not really necessary here
@@ -805,14 +670,15 @@ function synchronizeLayoutWithChildren(initialLayout
805
670
  }));
806
671
  }
807
672
  }
808
- }); // Correct the layout.
809
-
673
+ });
810
674
 
811
- var correctedLayout = correctBounds(layout, {
675
+ // Correct the layout.
676
+ const correctedLayout = correctBounds(layout, {
812
677
  cols: cols
813
678
  });
814
679
  return allowOverlap ? correctedLayout : compact(correctedLayout, compactType, cols);
815
680
  }
681
+
816
682
  /**
817
683
  * Validate a layout. Throws errors.
818
684
  *
@@ -820,51 +686,32 @@ function synchronizeLayoutWithChildren(initialLayout
820
686
  * @param {String} [contextName] Context name for errors.
821
687
  * @throw {Error} Validation error.
822
688
  */
823
-
824
-
825
- function validateLayout(layout
826
- /*: Layout*/
827
- )
828
- /*: void*/
829
- {
830
- var contextName
831
- /*: string*/
832
- = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "Layout";
833
- var subProps = ["x", "y", "w", "h"];
689
+ function validateLayout(layout /*: Layout*/) /*: void*/{
690
+ let contextName /*: string*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "Layout";
691
+ const subProps = ["x", "y", "w", "h"];
834
692
  if (!Array.isArray(layout)) throw new Error(contextName + " must be an array!");
835
-
836
- for (var i = 0, len = layout.length; i < len; i++) {
837
- var item = layout[i];
838
-
839
- for (var j = 0; j < subProps.length; j++) {
693
+ for (let i = 0, len = layout.length; i < len; i++) {
694
+ const item = layout[i];
695
+ for (let j = 0; j < subProps.length; j++) {
840
696
  if (typeof item[subProps[j]] !== "number") {
841
697
  throw new Error("ReactGridLayout: " + contextName + "[" + i + "]." + subProps[j] + " must be a number!");
842
698
  }
843
699
  }
844
700
  }
845
- } // Legacy support for verticalCompact: false
846
-
847
-
848
- function compactType(props
849
- /*: ?{ verticalCompact: boolean, compactType: CompactType }*/
850
- )
851
- /*: CompactType*/
852
- {
853
- var _ref3 = props || {},
854
- verticalCompact = _ref3.verticalCompact,
855
- compactType = _ref3.compactType;
701
+ }
856
702
 
703
+ // Legacy support for verticalCompact: false
704
+ function compactType(props /*: ?{ verticalCompact: boolean, compactType: CompactType }*/) /*: CompactType*/{
705
+ const {
706
+ verticalCompact,
707
+ compactType
708
+ } = props || {};
857
709
  return verticalCompact === false ? null : compactType;
858
710
  }
859
-
860
711
  function log() {
861
- var _console;
862
-
863
- if (!DEBUG) return; // eslint-disable-next-line no-console
864
-
865
- (_console = console).log.apply(_console, arguments);
712
+ if (!DEBUG) return;
713
+ // eslint-disable-next-line no-console
714
+ console.log(...arguments);
866
715
  }
867
-
868
- var noop = function noop() {};
869
-
716
+ const noop = () => {};
870
717
  exports.noop = noop;