react-grid-layout 0.16.5 → 0.16.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ 0.16.6 (Mar 8, 2018)
4
+ ----
5
+
6
+ - Fixed collision issue where items below could rearrange on a move.
7
+ - The root cause was "teleportation", or practically the same bug that leads to Pac-Man going through
8
+ ghosts now and then. If a large element moves up by a few grid units, the space it vacates can suddenly
9
+ become occupiable by an element below it. Rather than the collision happening properly, they exchange spaces
10
+ atomically. The fix is to move items down one grid unit at a time to ensure
11
+ this rearrangement does not happen.
12
+ - Thanks @torkelo for your hard work on this for Grafana 5, which I very unfortunately managed to break
13
+ when refactoring for 0.16.1.
14
+ - Ref: #650, #739
15
+ - Added a "Toolbox" demo (thanks @jhob)
16
+
3
17
  0.16.5 (Feb 26, 2018)
4
18
  ----
5
19
 
@@ -453,14 +453,17 @@ export default class ReactGridLayout extends React.Component<Props, State> {
453
453
  // to find collisions faster
454
454
  let hasCollisions;
455
455
  if (preventCollision) {
456
- const collisions = getAllCollisions(layout, { ...l, w, h }).filter((layoutItem) => layoutItem.i !== l.i);
456
+ const collisions = getAllCollisions(layout, { ...l, w, h }).filter(
457
+ layoutItem => layoutItem.i !== l.i
458
+ );
457
459
  hasCollisions = collisions.length > 0;
458
460
 
459
461
  // If we're colliding, we need adjust the placeholder.
460
462
  if (hasCollisions) {
461
463
  // adjust w && h to maximum allowed space
462
- let leastX = Infinity, leastY = Infinity;
463
- collisions.forEach((layoutItem) => {
464
+ let leastX = Infinity,
465
+ leastY = Infinity;
466
+ collisions.forEach(layoutItem => {
464
467
  if (layoutItem.x > l.x) leastX = Math.min(leastX, layoutItem.x);
465
468
  if (layoutItem.y > l.y) leastY = Math.min(leastY, layoutItem.y);
466
469
  });
package/build/utils.js CHANGED
@@ -162,10 +162,13 @@ function resolveCompactionCollision(layout, item, moveToCoord, axis) {
162
162
  // Go through each item we collide with.
163
163
  for (var _i4 = itemIndex + 1; _i4 < layout.length; _i4++) {
164
164
  var otherItem = layout[_i4];
165
-
166
165
  // Ignore static items
167
166
  if (otherItem.static) continue;
168
167
 
168
+ // Optimization: we can break early if we know we're past this el
169
+ // We can do this b/c it's a sorted layout
170
+ if (otherItem.y > item.y + item.h) break;
171
+
169
172
  if (collides(item, otherItem)) {
170
173
  resolveCompactionCollision(layout, otherItem, moveToCoord + item[sizeProp], axis);
171
174
  }
@@ -296,17 +299,17 @@ function getStatics(layout) {
296
299
  */
297
300
  function moveElement(layout, l, x, y, isUserAction, preventCollision, compactType, cols) {
298
301
  if (l.static) return layout;
299
- log("Moving element " + l.i + " to [" + x + "," + y + "] from [" + l.x + "," + l.y + "]");
300
302
 
301
303
  // Short-circuit if nothing to do.
302
304
  if (l.y === y && l.x === x) return layout;
303
305
 
306
+ log("Moving element " + l.i + " to [" + String(x) + "," + String(y) + "] from [" + l.x + "," + l.y + "]");
304
307
  var oldX = l.x;
305
308
  var oldY = l.y;
306
309
 
307
310
  // This is quite a bit faster than extending the object
308
- l.x = x;
309
- l.y = y;
311
+ if (typeof x === 'number') l.x = x;
312
+ if (typeof y === 'number') l.y = y;
310
313
  l.moved = true;
311
314
 
312
315
  // If this collides with anything, move it.
@@ -314,7 +317,7 @@ function moveElement(layout, l, x, y, isUserAction, preventCollision, compactTyp
314
317
  // to ensure, in the case of multiple collisions, that we're getting the
315
318
  // nearest collision.
316
319
  var sorted = sortLayoutItems(layout, compactType);
317
- var movingUp = compactType === "vertical" ? oldY >= y : compactType === "horizontal" ? oldX >= x : false;
320
+ var movingUp = compactType === "vertical" && typeof y === 'number' ? oldY >= y : compactType === "horizontal" && typeof x === 'number' ? oldX >= x : false;
318
321
  if (movingUp) sorted = sorted.reverse();
319
322
  var collisions = getAllCollisions(sorted, l);
320
323
 
@@ -369,7 +372,7 @@ function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAc
369
372
  // Make a mock item so we don't modify the item here, only modify in moveElement.
370
373
  var fakeItem = {
371
374
  x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
372
- y: !compactH ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
375
+ y: compactV ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
373
376
  w: itemToMove.w,
374
377
  h: itemToMove.h,
375
378
  i: "-1"
@@ -378,11 +381,11 @@ function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAc
378
381
  // No collision? If so, we can go up there; otherwise, we'll end up moving down as normal
379
382
  if (!getFirstCollision(layout, fakeItem)) {
380
383
  log("Doing reverse collision on " + itemToMove.i + " up to [" + fakeItem.x + "," + fakeItem.y + "].");
381
- return moveElement(layout, itemToMove, fakeItem.x, fakeItem.y, isUserAction, preventCollision, compactType, cols);
384
+ return moveElement(layout, itemToMove, compactH ? fakeItem.x : undefined, compactV ? fakeItem.y : undefined, isUserAction, preventCollision, compactType, cols);
382
385
  }
383
386
  }
384
387
 
385
- return moveElement(layout, itemToMove, compactH ? collidesWith.x + collidesWith.w : itemToMove.x, compactV ? collidesWith.y + collidesWith.h : itemToMove.y, isUserAction, preventCollision, compactType, cols);
388
+ return moveElement(layout, itemToMove, compactH ? itemToMove.x + 1 : undefined, compactV ? itemToMove.y + 1 : undefined, isUserAction, preventCollision, compactType, cols);
386
389
  }
387
390
 
388
391
  /**
@@ -190,10 +190,13 @@ function resolveCompactionCollision(
190
190
  // Go through each item we collide with.
191
191
  for (let i = itemIndex + 1; i < layout.length; i++) {
192
192
  const otherItem = layout[i];
193
-
194
193
  // Ignore static items
195
194
  if (otherItem.static) continue;
196
195
 
196
+ // Optimization: we can break early if we know we're past this el
197
+ // We can do this b/c it's a sorted layout
198
+ if (otherItem.y > (item.y + item.h)) break;
199
+
197
200
  if (collides(item, otherItem)) {
198
201
  resolveCompactionCollision(
199
202
  layout,
@@ -342,25 +345,25 @@ export function getStatics(layout: Layout): Array<LayoutItem> {
342
345
  export function moveElement(
343
346
  layout: Layout,
344
347
  l: LayoutItem,
345
- x: number,
346
- y: number,
348
+ x: ?number,
349
+ y: ?number,
347
350
  isUserAction: ?boolean,
348
351
  preventCollision: ?boolean,
349
352
  compactType: CompactType,
350
- cols: number
353
+ cols: number,
351
354
  ): Layout {
352
355
  if (l.static) return layout;
353
- log(`Moving element ${l.i} to [${x},${y}] from [${l.x},${l.y}]`);
354
356
 
355
357
  // Short-circuit if nothing to do.
356
358
  if (l.y === y && l.x === x) return layout;
357
359
 
360
+ log(`Moving element ${l.i} to [${String(x)},${String(y)}] from [${l.x},${l.y}]`);
358
361
  const oldX = l.x;
359
362
  const oldY = l.y;
360
363
 
361
364
  // This is quite a bit faster than extending the object
362
- l.x = x;
363
- l.y = y;
365
+ if (typeof x === 'number') l.x = x;
366
+ if (typeof y === 'number') l.y = y;
364
367
  l.moved = true;
365
368
 
366
369
  // If this collides with anything, move it.
@@ -369,9 +372,9 @@ export function moveElement(
369
372
  // nearest collision.
370
373
  let sorted = sortLayoutItems(layout, compactType);
371
374
  const movingUp =
372
- compactType === "vertical"
373
- ? oldY >= y
374
- : compactType === "horizontal" ? oldX >= x : false;
375
+ compactType === "vertical" && typeof y === 'number' ? oldY >= y
376
+ : compactType === "horizontal" && typeof x === 'number' ? oldX >= x
377
+ : false;
375
378
  if (movingUp) sorted = sorted.reverse();
376
379
  const collisions = getAllCollisions(sorted, l);
377
380
 
@@ -451,7 +454,7 @@ export function moveElementAwayFromCollision(
451
454
  // Make a mock item so we don't modify the item here, only modify in moveElement.
452
455
  const fakeItem: LayoutItem = {
453
456
  x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x,
454
- y: !compactH ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
457
+ y: compactV ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y,
455
458
  w: itemToMove.w,
456
459
  h: itemToMove.h,
457
460
  i: "-1"
@@ -467,8 +470,8 @@ export function moveElementAwayFromCollision(
467
470
  return moveElement(
468
471
  layout,
469
472
  itemToMove,
470
- fakeItem.x,
471
- fakeItem.y,
473
+ compactH ? fakeItem.x : undefined,
474
+ compactV ? fakeItem.y : undefined,
472
475
  isUserAction,
473
476
  preventCollision,
474
477
  compactType,
@@ -480,8 +483,8 @@ export function moveElementAwayFromCollision(
480
483
  return moveElement(
481
484
  layout,
482
485
  itemToMove,
483
- compactH ? collidesWith.x + collidesWith.w : itemToMove.x,
484
- compactV ? collidesWith.y + collidesWith.h : itemToMove.y,
486
+ compactH ? itemToMove.x + 1 : undefined,
487
+ compactV ? itemToMove.y + 1 : undefined,
485
488
  isUserAction,
486
489
  preventCollision,
487
490
  compactType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-grid-layout",
3
- "version": "0.16.5",
3
+ "version": "0.16.6",
4
4
  "description": "A draggable and resizable grid layout with responsive breakpoints, for React.",
5
5
  "main": "index.js",
6
6
  "scripts": {