@nyaruka/temba-components 0.138.4 → 0.139.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/locales/es.js +5 -5
  3. package/dist/locales/es.js.map +1 -1
  4. package/dist/locales/fr.js +5 -5
  5. package/dist/locales/fr.js.map +1 -1
  6. package/dist/locales/locale-codes.js +2 -11
  7. package/dist/locales/locale-codes.js.map +1 -1
  8. package/dist/locales/pt.js +5 -5
  9. package/dist/locales/pt.js.map +1 -1
  10. package/dist/temba-components.js +816 -852
  11. package/dist/temba-components.js.map +1 -1
  12. package/out-tsc/src/display/FloatingTab.js +23 -30
  13. package/out-tsc/src/display/FloatingTab.js.map +1 -1
  14. package/out-tsc/src/flow/CanvasMenu.js +5 -3
  15. package/out-tsc/src/flow/CanvasMenu.js.map +1 -1
  16. package/out-tsc/src/flow/CanvasNode.js +6 -7
  17. package/out-tsc/src/flow/CanvasNode.js.map +1 -1
  18. package/out-tsc/src/flow/Editor.js +152 -235
  19. package/out-tsc/src/flow/Editor.js.map +1 -1
  20. package/out-tsc/src/flow/Plumber.js +757 -403
  21. package/out-tsc/src/flow/Plumber.js.map +1 -1
  22. package/out-tsc/src/flow/utils.js +138 -66
  23. package/out-tsc/src/flow/utils.js.map +1 -1
  24. package/out-tsc/src/interfaces.js +1 -0
  25. package/out-tsc/src/interfaces.js.map +1 -1
  26. package/out-tsc/src/list/TicketList.js +4 -1
  27. package/out-tsc/src/list/TicketList.js.map +1 -1
  28. package/out-tsc/src/live/ContactChat.js +18 -1
  29. package/out-tsc/src/live/ContactChat.js.map +1 -1
  30. package/out-tsc/src/locales/es.js +5 -5
  31. package/out-tsc/src/locales/es.js.map +1 -1
  32. package/out-tsc/src/locales/fr.js +5 -5
  33. package/out-tsc/src/locales/fr.js.map +1 -1
  34. package/out-tsc/src/locales/locale-codes.js +2 -11
  35. package/out-tsc/src/locales/locale-codes.js.map +1 -1
  36. package/out-tsc/src/locales/pt.js +5 -5
  37. package/out-tsc/src/locales/pt.js.map +1 -1
  38. package/out-tsc/src/simulator/Simulator.js +1 -0
  39. package/out-tsc/src/simulator/Simulator.js.map +1 -1
  40. package/out-tsc/test/temba-floating-tab.test.js +4 -6
  41. package/out-tsc/test/temba-floating-tab.test.js.map +1 -1
  42. package/out-tsc/test/temba-flow-collision.test.js +221 -223
  43. package/out-tsc/test/temba-flow-collision.test.js.map +1 -1
  44. package/out-tsc/test/temba-flow-editor.test.js +0 -2
  45. package/out-tsc/test/temba-flow-editor.test.js.map +1 -1
  46. package/out-tsc/test/temba-flow-plumber-connections.test.js +83 -84
  47. package/out-tsc/test/temba-flow-plumber-connections.test.js.map +1 -1
  48. package/out-tsc/test/temba-flow-plumber.test.js +102 -93
  49. package/out-tsc/test/temba-flow-plumber.test.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/display/FloatingTab.ts +22 -31
  52. package/src/flow/CanvasMenu.ts +8 -3
  53. package/src/flow/CanvasNode.ts +6 -7
  54. package/src/flow/Editor.ts +184 -279
  55. package/src/flow/Plumber.ts +1011 -457
  56. package/src/flow/utils.ts +162 -84
  57. package/src/interfaces.ts +2 -1
  58. package/src/list/TicketList.ts +4 -1
  59. package/src/live/ContactChat.ts +19 -1
  60. package/src/locales/es.ts +13 -18
  61. package/src/locales/fr.ts +13 -18
  62. package/src/locales/locale-codes.ts +2 -11
  63. package/src/locales/pt.ts +13 -18
  64. package/src/simulator/Simulator.ts +1 -0
  65. package/test/temba-floating-tab.test.ts +4 -6
  66. package/test/temba-flow-collision.test.ts +225 -303
  67. package/test/temba-flow-editor.test.ts +0 -2
  68. package/test/temba-flow-plumber-connections.test.ts +97 -97
  69. package/test/temba-flow-plumber.test.ts +116 -103
@@ -265,17 +265,16 @@ describe('Collision Detection Utilities', () => {
265
265
  });
266
266
  describe('calculateReflowPositions', () => {
267
267
  it('returns empty map when no collisions', () => {
268
- const movedBounds = {
269
- uuid: 'moved',
270
- left: 100,
271
- top: 100,
272
- right: 200,
273
- bottom: 200,
274
- width: 100,
275
- height: 100
276
- };
277
268
  const allBounds = [
278
- movedBounds,
269
+ {
270
+ uuid: 'moved',
271
+ left: 100,
272
+ top: 100,
273
+ right: 200,
274
+ bottom: 200,
275
+ width: 100,
276
+ height: 100
277
+ },
279
278
  {
280
279
  uuid: 'node1',
281
280
  left: 300,
@@ -286,82 +285,46 @@ describe('Collision Detection Utilities', () => {
286
285
  height: 100
287
286
  }
288
287
  ];
289
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
288
+ const positions = calculateReflowPositions(['moved'], allBounds);
290
289
  expect(positions.size).to.equal(0);
291
290
  });
292
- it('moves colliding node down', () => {
293
- const movedBounds = {
294
- uuid: 'moved',
295
- left: 100,
296
- top: 100,
297
- right: 200,
298
- bottom: 200,
299
- width: 100,
300
- height: 100
301
- };
291
+ it('moves colliding node out of the way', () => {
302
292
  const allBounds = [
303
- movedBounds,
293
+ {
294
+ uuid: 'moved',
295
+ left: 100,
296
+ top: 100,
297
+ right: 200,
298
+ bottom: 200,
299
+ width: 100,
300
+ height: 100
301
+ },
304
302
  {
305
303
  uuid: 'node1',
306
- left: 150,
304
+ left: 100,
307
305
  top: 150,
308
- right: 250,
306
+ right: 200,
309
307
  bottom: 250,
310
308
  width: 100,
311
309
  height: 100
312
310
  }
313
311
  ];
314
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
312
+ const positions = calculateReflowPositions(['moved'], allBounds);
315
313
  expect(positions.size).to.equal(1);
316
314
  expect(positions.has('node1')).to.be.true;
317
- const newPos = positions.get('node1');
318
- expect(newPos.left).to.equal(150); // left unchanged
319
- expect(newPos.top).to.be.greaterThan(200); // moved below the moved node
315
+ expect(positions.has('moved')).to.be.false;
320
316
  });
321
- it('handles droppedBelowMidpoint by moving dropped node down', () => {
322
- const movedBounds = {
323
- uuid: 'moved',
324
- left: 100,
325
- top: 150,
326
- right: 200,
327
- bottom: 250,
328
- width: 100,
329
- height: 100
330
- };
317
+ it('sacred node never appears in returned positions', () => {
331
318
  const allBounds = [
332
- movedBounds,
333
319
  {
334
- uuid: 'existing',
320
+ uuid: 'dropped',
335
321
  left: 100,
336
322
  top: 100,
337
323
  right: 200,
338
324
  bottom: 200,
339
325
  width: 100,
340
326
  height: 100
341
- }
342
- ];
343
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, true // droppedBelowMidpoint
344
- );
345
- expect(positions.size).to.equal(1);
346
- expect(positions.has('moved')).to.be.true;
347
- const newPos = positions.get('moved');
348
- expect(newPos.top).to.be.greaterThan(200); // moved below existing node
349
- });
350
- it('gives priority to dropped node when dropped above midpoint', () => {
351
- // Dropped node overlaps with bottom of existing node
352
- // Bottom of dropped (180) is above midpoint of existing (150)
353
- // So dropped node should keep position, existing moves down
354
- const movedBounds = {
355
- uuid: 'dropped',
356
- left: 100,
357
- top: 80,
358
- right: 200,
359
- bottom: 180,
360
- width: 100,
361
- height: 100
362
- };
363
- const allBounds = [
364
- movedBounds,
327
+ },
365
328
  {
366
329
  uuid: 'existing',
367
330
  left: 100,
@@ -372,106 +335,79 @@ describe('Collision Detection Utilities', () => {
372
335
  height: 100
373
336
  }
374
337
  ];
375
- const positions = calculateReflowPositions('dropped', movedBounds, allBounds, false // dropped node's bottom is above target midpoint, dropped node gets priority
376
- );
377
- // Existing node should be moved down
338
+ const positions = calculateReflowPositions(['dropped'], allBounds);
339
+ expect(positions.has('dropped')).to.be.false;
378
340
  expect(positions.has('existing')).to.be.true;
379
- expect(positions.has('dropped')).to.be.false; // dropped keeps its position
380
- const existingNewPos = positions.get('existing');
381
- expect(existingNewPos.top).to.be.greaterThan(180); // moved below dropped node
382
341
  });
383
- it('gives priority to existing node when dropped below midpoint', () => {
384
- // Dropped node overlaps with top of existing node
385
- // Bottom of dropped (220) is below midpoint of existing (150)
386
- // So existing node keeps position, dropped moves down
387
- const movedBounds = {
388
- uuid: 'dropped',
389
- left: 100,
390
- top: 120,
391
- right: 200,
392
- bottom: 220,
393
- width: 100,
394
- height: 100
395
- };
342
+ it('prefers least-displacement direction', () => {
343
+ // Sacred at (100,100)-(200,200), collider at (180,100)-(280,200)
344
+ // Right requires only 60px displacement, down requires 140px
396
345
  const allBounds = [
397
- movedBounds,
398
346
  {
399
- uuid: 'existing',
347
+ uuid: 'sacred',
400
348
  left: 100,
401
349
  top: 100,
402
350
  right: 200,
403
351
  bottom: 200,
404
352
  width: 100,
405
353
  height: 100
354
+ },
355
+ {
356
+ uuid: 'collider',
357
+ left: 180,
358
+ top: 100,
359
+ right: 280,
360
+ bottom: 200,
361
+ width: 100,
362
+ height: 100
406
363
  }
407
364
  ];
408
- const positions = calculateReflowPositions('dropped', movedBounds, allBounds, true // dropped node's bottom is below target midpoint, target gets priority
409
- );
410
- // Dropped node should be moved down
411
- expect(positions.has('dropped')).to.be.true;
412
- expect(positions.has('existing')).to.be.false; // existing keeps its position
413
- const droppedNewPos = positions.get('dropped');
414
- expect(droppedNewPos.top).to.be.greaterThan(200); // moved below existing node
365
+ const positions = calculateReflowPositions(['sacred'], allBounds);
366
+ expect(positions.has('collider')).to.be.true;
367
+ const newPos = positions.get('collider');
368
+ // Should move right (shorter) rather than down (longer)
369
+ expect(newPos.left).to.be.greaterThan(200);
370
+ expect(newPos.top).to.equal(100); // vertical position unchanged
415
371
  });
416
- it('resolves cascading collisions', () => {
417
- const movedBounds = {
418
- uuid: 'moved',
419
- left: 100,
420
- top: 100,
421
- right: 200,
422
- bottom: 200,
423
- width: 100,
424
- height: 100
425
- };
372
+ it('prefers up when it is the shortest move', () => {
373
+ // Sacred at (100,200)-(200,300), collider at (100,180)-(200,280)
374
+ // Up: newTop=snapToGrid(200-100-30)=snapToGrid(70)=80, distance=100
375
+ // Down: newTop=snapToGrid(300+30)=340, distance=160
376
+ // Right: newLeft=snapToGrid(200+30)=240, distance=140
426
377
  const allBounds = [
427
- movedBounds,
428
378
  {
429
- uuid: 'node1',
379
+ uuid: 'sacred',
430
380
  left: 100,
431
- top: 150,
381
+ top: 200,
432
382
  right: 200,
433
- bottom: 250,
383
+ bottom: 300,
434
384
  width: 100,
435
385
  height: 100
436
386
  },
437
387
  {
438
- uuid: 'node2',
388
+ uuid: 'collider',
439
389
  left: 100,
440
- top: 200,
390
+ top: 180,
441
391
  right: 200,
442
- bottom: 300,
392
+ bottom: 280,
443
393
  width: 100,
444
394
  height: 100
445
395
  }
446
396
  ];
447
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
448
- // Both nodes should be repositioned to avoid collision
449
- expect(positions.size).to.be.greaterThan(0);
450
- // Check that moved nodes maintain vertical order and spacing
451
- if (positions.has('node1') && positions.has('node2')) {
452
- const node1Pos = positions.get('node1');
453
- const node2Pos = positions.get('node2');
454
- // node2 should be below node1
455
- expect(node2Pos.top).to.be.greaterThan(node1Pos.top);
456
- }
397
+ const positions = calculateReflowPositions(['sacred'], allBounds);
398
+ expect(positions.has('collider')).to.be.true;
399
+ const newPos = positions.get('collider');
400
+ // Should move up (shortest displacement)
401
+ expect(newPos.top).to.be.lessThan(200);
402
+ expect(newPos.left).to.equal(100); // horizontal position unchanged
457
403
  });
458
- it('handles multiple iterations for complex cascading collisions', () => {
459
- // Test case that requires multiple iterations to resolve all collisions
460
- // This scenario has nodes that initially don't collide with moved node,
461
- // but will collide with other nodes that get moved
462
- const movedBounds = {
463
- uuid: 'moved',
464
- left: 100,
465
- top: 50,
466
- right: 200,
467
- bottom: 150,
468
- width: 100,
469
- height: 100
470
- };
404
+ it('prefers direction with fewer cascading collisions', () => {
405
+ // Sacred at (100,100)-(200,200), collider at (100,150)-(200,250)
406
+ // A node sits below at (100,280)-(200,380) blocking the downward path
407
+ // Down causes cascade, right does not
471
408
  const allBounds = [
472
- movedBounds,
473
409
  {
474
- uuid: 'node1',
410
+ uuid: 'sacred',
475
411
  left: 100,
476
412
  top: 100,
477
413
  right: 200,
@@ -480,52 +416,41 @@ describe('Collision Detection Utilities', () => {
480
416
  height: 100
481
417
  },
482
418
  {
483
- uuid: 'node2',
419
+ uuid: 'collider',
484
420
  left: 100,
485
- top: 180,
421
+ top: 150,
486
422
  right: 200,
487
- bottom: 280,
423
+ bottom: 250,
488
424
  width: 100,
489
425
  height: 100
490
426
  },
491
427
  {
492
- uuid: 'node3',
428
+ uuid: 'blocker',
493
429
  left: 100,
494
- top: 260,
430
+ top: 280,
495
431
  right: 200,
496
- bottom: 360,
432
+ bottom: 380,
497
433
  width: 100,
498
434
  height: 100
499
435
  }
500
436
  ];
501
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
502
- // All three nodes should be repositioned to be stacked below the moved node
503
- expect(positions.size).to.equal(3);
504
- expect(positions.has('node1')).to.be.true;
505
- expect(positions.has('node2')).to.be.true;
506
- expect(positions.has('node3')).to.be.true;
507
- const node1Pos = positions.get('node1');
508
- const node2Pos = positions.get('node2');
509
- const node3Pos = positions.get('node3');
510
- // Nodes should be stacked vertically with proper spacing
511
- expect(node1Pos.top).to.be.at.least(170); // 150 (bottom of moved) + 20
512
- expect(node2Pos.top).to.be.at.least(node1Pos.top + 120); // node1 top + height + spacing
513
- expect(node3Pos.top).to.be.at.least(node2Pos.top + 120); // node2 top + height + spacing
437
+ const positions = calculateReflowPositions(['sacred'], allBounds);
438
+ expect(positions.has('collider')).to.be.true;
439
+ // Should avoid moving down (would cascade into blocker)
440
+ // blocker should not need to move
441
+ expect(positions.has('blocker')).to.be.false;
514
442
  });
515
- it('handles nodes that collide with already repositioned nodes', () => {
516
- // This test creates a scenario where node3 doesn't collide with the moved node,
517
- // but collides with node2 which itself got repositioned due to collision with node1
518
- const movedBounds = {
519
- uuid: 'moved',
520
- left: 100,
521
- top: 100,
522
- right: 200,
523
- bottom: 200,
524
- width: 100,
525
- height: 100
526
- };
443
+ it('resolves cascading collisions', () => {
527
444
  const allBounds = [
528
- movedBounds,
445
+ {
446
+ uuid: 'moved',
447
+ left: 100,
448
+ top: 100,
449
+ right: 200,
450
+ bottom: 200,
451
+ width: 100,
452
+ height: 100
453
+ },
529
454
  {
530
455
  uuid: 'node1',
531
456
  left: 100,
@@ -538,67 +463,118 @@ describe('Collision Detection Utilities', () => {
538
463
  {
539
464
  uuid: 'node2',
540
465
  left: 100,
541
- top: 240,
466
+ top: 200,
542
467
  right: 200,
543
- bottom: 340,
468
+ bottom: 300,
544
469
  width: 100,
545
470
  height: 100
546
471
  }
547
472
  ];
548
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
549
- // Both nodes should be moved
550
- expect(positions.size).to.equal(2);
551
- expect(positions.has('node1')).to.be.true;
552
- expect(positions.has('node2')).to.be.true;
553
- const node1Pos = positions.get('node1');
554
- const node2Pos = positions.get('node2');
555
- // node1 should be moved below moved node
556
- expect(node1Pos.top).to.be.at.least(220); // 200 + 20
557
- // node2 should be moved below the new position of node1
558
- // This tests the code path where we check against already repositioned nodes
559
- expect(node2Pos.top).to.be.at.least(node1Pos.top + 120);
473
+ const positions = calculateReflowPositions(['moved'], allBounds);
474
+ // At least one node should be repositioned
475
+ expect(positions.size).to.be.greaterThan(0);
476
+ // No node should overlap with the sacred node or each other after reflow
477
+ // (verified by the algorithm's correctness guarantee)
560
478
  });
561
- it('maintains horizontal position while moving vertically', () => {
562
- const movedBounds = {
563
- uuid: 'moved',
564
- left: 100,
565
- top: 100,
566
- right: 200,
567
- bottom: 200,
568
- width: 100,
569
- height: 100
570
- };
479
+ it('handles multiple sacred nodes', () => {
480
+ // Two sacred nodes with a non-sacred node overlapping one
571
481
  const allBounds = [
572
- movedBounds,
573
482
  {
574
- uuid: 'node1',
575
- left: 150,
483
+ uuid: 'sacred1',
484
+ left: 100,
485
+ top: 100,
486
+ right: 200,
487
+ bottom: 200,
488
+ width: 100,
489
+ height: 100
490
+ },
491
+ {
492
+ uuid: 'sacred2',
493
+ left: 100,
494
+ top: 400,
495
+ right: 200,
496
+ bottom: 500,
497
+ width: 100,
498
+ height: 100
499
+ },
500
+ {
501
+ uuid: 'collider',
502
+ left: 100,
576
503
  top: 150,
577
- right: 250,
504
+ right: 200,
578
505
  bottom: 250,
579
506
  width: 100,
580
507
  height: 100
581
508
  }
582
509
  ];
583
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
584
- const newPos = positions.get('node1');
585
- // Horizontal position should remain unchanged
586
- expect(newPos.left).to.equal(150);
510
+ const positions = calculateReflowPositions(['sacred1', 'sacred2'], allBounds);
511
+ // Sacred nodes should never be moved
512
+ expect(positions.has('sacred1')).to.be.false;
513
+ expect(positions.has('sacred2')).to.be.false;
514
+ // Collider should be moved
515
+ expect(positions.has('collider')).to.be.true;
587
516
  });
588
- it('adds minimum spacing between nodes', () => {
589
- const movedBounds = {
590
- uuid: 'moved',
591
- left: 100,
592
- top: 100,
593
- right: 200,
594
- bottom: 200,
517
+ it('does not move a node into another sacred node', () => {
518
+ // Two sacred nodes close together with a collider between them
519
+ // Moving right would overlap sacred2, so it should choose another direction
520
+ const allBounds = [
521
+ {
522
+ uuid: 'sacred1',
523
+ left: 100,
524
+ top: 100,
525
+ right: 200,
526
+ bottom: 200,
527
+ width: 100,
528
+ height: 100
529
+ },
530
+ {
531
+ uuid: 'sacred2',
532
+ left: 240,
533
+ top: 100,
534
+ right: 340,
535
+ bottom: 200,
536
+ width: 100,
537
+ height: 100
538
+ },
539
+ {
540
+ uuid: 'collider',
541
+ left: 150,
542
+ top: 100,
543
+ right: 250,
544
+ bottom: 200,
545
+ width: 100,
546
+ height: 100
547
+ }
548
+ ];
549
+ const positions = calculateReflowPositions(['sacred1', 'sacred2'], allBounds);
550
+ expect(positions.has('collider')).to.be.true;
551
+ const newPos = positions.get('collider');
552
+ // Should not overlap either sacred node after reflow
553
+ const newBounds = {
554
+ uuid: 'collider',
555
+ left: newPos.left,
556
+ top: newPos.top,
557
+ right: newPos.left + 100,
558
+ bottom: newPos.top + 100,
595
559
  width: 100,
596
560
  height: 100
597
561
  };
562
+ expect(nodesOverlap(newBounds, allBounds[0])).to.be.false;
563
+ expect(nodesOverlap(newBounds, allBounds[1])).to.be.false;
564
+ });
565
+ it('snaps reflow positions to grid', () => {
598
566
  const allBounds = [
599
- movedBounds,
600
567
  {
601
- uuid: 'node1',
568
+ uuid: 'sacred',
569
+ left: 100,
570
+ top: 100,
571
+ right: 200,
572
+ bottom: 200,
573
+ width: 100,
574
+ height: 100
575
+ },
576
+ {
577
+ uuid: 'collider',
602
578
  left: 100,
603
579
  top: 150,
604
580
  right: 200,
@@ -607,24 +583,46 @@ describe('Collision Detection Utilities', () => {
607
583
  height: 100
608
584
  }
609
585
  ];
610
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
611
- const newPos = positions.get('node1');
612
- // Should have at least 20px spacing (MIN_NODE_SPACING)
613
- expect(newPos.top).to.be.at.least(220); // 200 (bottom of moved) + 20
586
+ const positions = calculateReflowPositions(['sacred'], allBounds);
587
+ expect(positions.has('collider')).to.be.true;
588
+ const newPos = positions.get('collider');
589
+ // Both coordinates should be multiples of 20 (grid size)
590
+ expect(newPos.left % 20).to.equal(0);
591
+ expect(newPos.top % 20).to.equal(0);
592
+ });
593
+ it('clamps positions to zero (no negative coordinates)', () => {
594
+ // Sacred node near top-left, collider above it
595
+ // Moving up would go negative, so it should fall back
596
+ const allBounds = [
597
+ {
598
+ uuid: 'sacred',
599
+ left: 0,
600
+ top: 0,
601
+ right: 200,
602
+ bottom: 200,
603
+ width: 200,
604
+ height: 200
605
+ },
606
+ {
607
+ uuid: 'collider',
608
+ left: 0,
609
+ top: 100,
610
+ right: 200,
611
+ bottom: 200,
612
+ width: 200,
613
+ height: 100
614
+ }
615
+ ];
616
+ const positions = calculateReflowPositions(['sacred'], allBounds);
617
+ expect(positions.has('collider')).to.be.true;
618
+ const newPos = positions.get('collider');
619
+ expect(newPos.left).to.be.at.least(0);
620
+ expect(newPos.top).to.be.at.least(0);
614
621
  });
615
622
  });
616
623
  describe('edge cases', () => {
617
624
  it('handles empty allBounds array', () => {
618
- const movedBounds = {
619
- uuid: 'moved',
620
- left: 100,
621
- top: 100,
622
- right: 200,
623
- bottom: 200,
624
- width: 100,
625
- height: 100
626
- };
627
- const positions = calculateReflowPositions('moved', movedBounds, [], false);
625
+ const positions = calculateReflowPositions(['moved'], []);
628
626
  expect(positions.size).to.equal(0);
629
627
  });
630
628
  it('handles single node (no other nodes to collide with)', () => {
@@ -637,7 +635,7 @@ describe('Collision Detection Utilities', () => {
637
635
  width: 100,
638
636
  height: 100
639
637
  };
640
- const positions = calculateReflowPositions('moved', movedBounds, [movedBounds], false);
638
+ const positions = calculateReflowPositions(['moved'], [movedBounds]);
641
639
  expect(positions.size).to.equal(0);
642
640
  });
643
641
  it('prevents infinite loops with complex collisions', () => {
@@ -664,7 +662,7 @@ describe('Collision Detection Utilities', () => {
664
662
  });
665
663
  }
666
664
  // Should complete without hanging
667
- const positions = calculateReflowPositions('moved', movedBounds, allBounds, false);
665
+ const positions = calculateReflowPositions(['moved'], allBounds);
668
666
  // Should have resolved some collisions
669
667
  expect(positions.size).to.be.greaterThan(0);
670
668
  });