bm-core-ui 2.12.0-beta.14 → 2.12.0-beta.16

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.
@@ -9992,7 +9992,7 @@ export class BMMenu {
9992
9992
  * The menu items displayed by this menu.
9993
9993
  *
9994
9994
  */
9995
- readonly items: BMMenuItem[];
9995
+ items: BMMenuItem[];
9996
9996
 
9997
9997
  /**
9998
9998
  * An optional delegate object that will receive callbacks events from this menu.
@@ -10076,7 +10076,7 @@ export class BMMenu {
10076
10076
  * The menu that opened this menu, if any.
10077
10077
  *
10078
10078
  */
10079
- private _supermenu?: BMMenu | null | undefined;
10079
+ readonly supermenu?: BMMenu | null | undefined;
10080
10080
 
10081
10081
  /**
10082
10082
  * The menu's frame, relative to the viewport, available while this menu is visible.
@@ -6059,14 +6059,18 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
6059
6059
 
6060
6060
  // If this update occurs because of a drag & drop operation, try to obtain the associated index paths from the data set
6061
6061
  let dropPreviewMap;
6062
+ /** @type {Map} */
6063
+ let dropPreviewReverseMap;
6062
6064
  if (this._dropPreviews && this.dataSet.indexPathForDragItem) {
6063
6065
  dropPreviewMap = new Map();
6066
+ dropPreviewReverseMap = new Map();
6064
6067
 
6065
6068
  for (const preview of this._dropPreviews) {
6066
6069
  const indexPath = this.dataSet.indexPathForDragItem(preview.item);
6067
6070
 
6068
6071
  if (indexPath) {
6069
6072
  dropPreviewMap.set(indexPath, preview);
6073
+ dropPreviewReverseMap.set(preview, indexPath);
6070
6074
  }
6071
6075
  }
6072
6076
  }
@@ -6464,6 +6468,18 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
6464
6468
  for (const cell of insertedCells) {
6465
6469
  cell._dropPreview.performDropToNode(cell.node);
6466
6470
 
6471
+ // Handle the cases where multiple drop previews target this cell
6472
+ for (const [preview, indexPath] of dropPreviewReverseMap.entries()) {
6473
+ if (indexPath.isLooselyEqualToIndexPath(cell.indexPath, {usingComparator: self.identityComparator}) && preview != cell._dropPreview) {
6474
+ preview.performDropToNode(cell.node);
6475
+ const index = self._dropPreviews.indexOf(cell._dropPreview);
6476
+
6477
+ if (index != -1) {
6478
+ self._dropPreviews.splice(index, 1);
6479
+ }
6480
+ }
6481
+ }
6482
+
6467
6483
  const index = self._dropPreviews.indexOf(cell._dropPreview);
6468
6484
 
6469
6485
  if (index != -1) {
@@ -6486,6 +6502,19 @@ BMCollectionView.prototype = BMExtend(BM_COLLECTION_VIEW_USE_BMVIEW_SUBCLASS ? O
6486
6502
  // Play all drop animations
6487
6503
  for (const cell of dropMovingCells) {
6488
6504
  cell._dropPreview.performDropToNode(cell.node);
6505
+
6506
+ // Handle the cases where multiple drop previews target this cell
6507
+ for (const [preview, indexPath] of dropPreviewReverseMap.entries()) {
6508
+ if (indexPath.isLooselyEqualToIndexPath(cell.indexPath, {usingComparator: self.identityComparator}) && preview != cell._dropPreview) {
6509
+ preview.performDropToNode(cell.node);
6510
+ const index = self._dropPreviews.indexOf(cell._dropPreview);
6511
+
6512
+ if (index != -1) {
6513
+ self._dropPreviews.splice(index, 1);
6514
+ }
6515
+ }
6516
+ }
6517
+
6489
6518
  const index = self._dropPreviews.indexOf(cell._dropPreview);
6490
6519
 
6491
6520
  if (index != -1) {
@@ -7368,4 +7397,4 @@ class BMCollectionViewDataSetAdapter {
7368
7397
  }
7369
7398
  }
7370
7399
 
7371
- // #endregion
7400
+ // #endregion
@@ -1346,6 +1346,19 @@ input:not(:checked) + .BMWindowSwitchGutter > .BMWindowSwitchKnob, .BMWindowSwit
1346
1346
  z-index: 9999999;
1347
1347
  }
1348
1348
 
1349
+ /* A class that is temporarily added to the menu container to allow the user
1350
+ to move over menu items without triggering them while moving torwards the submenu;
1351
+ additionally, this causes the `mouseenter` event to trigger when this class is removed */
1352
+ .BMMenuContainer.BMMenuContainerSubmenuActive > * {
1353
+ pointer-events: none !important;
1354
+ }
1355
+
1356
+ /* This allows clicking on an item with a submenu during the event delaying period
1357
+ after a submenu has just been opened */
1358
+ .BMMenuContainer.BMMenuContainerSubmenuActive .BMMenuItemHighlighted {
1359
+ pointer-events: all !important;
1360
+ }
1361
+
1349
1362
  .BMMenuContainerFullScreen {
1350
1363
  background-color: rgba(0, 0, 0, .33);
1351
1364
  }
@@ -406,6 +406,42 @@ BMMenu.prototype = {
406
406
  get items() {
407
407
  return this._items.slice();
408
408
  },
409
+ set items(items) {
410
+ this._items = items.slice();
411
+
412
+ // If this menu was already open when items are updated, destroy
413
+ // and re-render it
414
+ if (this._node) {
415
+ if (this._supermenu) {
416
+ this._node.remove();
417
+ }
418
+ else {
419
+ this._containerNode.remove();
420
+ }
421
+
422
+ this._renderMenu();
423
+
424
+ if (!this._supermenu) {
425
+ document.body.appendChild(this._containerNode);
426
+ }
427
+
428
+ this._setAnchorRect(this._rect);
429
+
430
+ // Restore the highlighted menu item
431
+ if (this._highlightedIndex != -1) {
432
+ const item = this._items[this._highlightedIndex];
433
+ if (item && !item._isSeparator && item._enabled) {
434
+ const index = this._highlightedIndex;
435
+ this._highlightedIndex = -1;
436
+ this.highlightedIndex = index;
437
+ }
438
+ }
439
+
440
+ for (const node of this._itemsContainerNode.children) {
441
+ BMHook(node, {opacity: 1, translateY: '0px'});
442
+ }
443
+ }
444
+ },
409
445
 
410
446
  /**
411
447
  * An optional delegate object that will receive callbacks events from this menu.
@@ -519,6 +555,9 @@ BMMenu.prototype = {
519
555
  * The menu that opened this menu, if any.
520
556
  */
521
557
  _supermenu: undefined, // <BMMenu, nullable>
558
+ get supermenu() {
559
+ return this._supermenu;
560
+ },
522
561
 
523
562
  /**
524
563
  * The menu's frame, relative to the viewport, available while this menu is visible.
@@ -1458,9 +1497,6 @@ BMMenu.prototype = {
1458
1497
  let topPoint;
1459
1498
  let bottomPoint;
1460
1499
 
1461
- // Determines whether the slope needs to be between the min and max slopes or outside their range
1462
- let flipSlopes = false;
1463
-
1464
1500
  const eventTarget = this._containerNode;
1465
1501
  // Immediately block interactions with menu elements
1466
1502
  this._delaysEvents = YES;
@@ -1478,7 +1514,7 @@ BMMenu.prototype = {
1478
1514
  this._delaysEvents = NO;
1479
1515
 
1480
1516
  // Remove the mousemove event handler
1481
- eventTarget.removeEventListener(mouseMoveEvent, handler, {capture: YES});
1517
+ window.removeEventListener(mouseMoveEvent, handler, {capture: YES});
1482
1518
 
1483
1519
  // Allow pointer interaction with the menu nodes
1484
1520
  eventTarget.classList.remove('BMMenuContainerSubmenuActive');
@@ -1511,14 +1547,6 @@ BMMenu.prototype = {
1511
1547
  BMPointMake(submenuFrame.origin.x, submenuFrame.bottom) :
1512
1548
  BMPointMake(submenuFrame.right, submenuFrame.bottom);
1513
1549
 
1514
- if (submenuFrame.origin.x < lastPosition.x) {
1515
- // When the menu appears to the left, the min and max slopes need to be
1516
- // flipped, because the "interior" of the slopes is counted clockwise
1517
- // from the bottom slope to the top one, but on the left side
1518
- // the interior needs to be counted counter-clockwise
1519
- flipSlopes = true;
1520
- }
1521
-
1522
1550
  return;
1523
1551
  }
1524
1552
 
@@ -1563,20 +1591,39 @@ BMMenu.prototype = {
1563
1591
  const topSlope = currentPosition.slopeAngleToPoint(topPoint);
1564
1592
  const bottomSlope = currentPosition.slopeAngleToPoint(bottomPoint);
1565
1593
 
1594
+ // Normalizes the specified angle so that it's within the [0, 2Pi] range
1595
+ function normalizeAngle(angle) {
1596
+ // Coerce angle into [-2Pi, 2Pi]
1597
+ angle %= 2 * Math.PI;
1598
+
1599
+ // Coerce the result into a positive angle
1600
+ return angle < 0 ? angle + 2 * Math.PI : angle;
1601
+ }
1602
+
1566
1603
  // Get the slope angle for the current movement, which indicates the direction
1567
1604
  // in which the pointer moves
1568
- const currentSlope = lastPosition.slopeAngleToPoint(currentPosition);
1605
+ const currentSlope = normalizeAngle(lastPosition.slopeAngleToPoint(currentPosition));
1569
1606
 
1570
- const minSlope = Math.min(topSlope, bottomSlope);
1571
- const maxSlope = Math.max(topSlope, bottomSlope);
1607
+ const minSlope = normalizeAngle(bottomSlope - topSlope);
1608
+ const maxSlope = normalizeAngle(topSlope - bottomSlope);
1572
1609
 
1610
+ // Determine which is the starting and ending slopes and normalize them
1611
+ let startSlope, endSlope;
1612
+ if (minSlope <= maxSlope) {
1613
+ startSlope = normalizeAngle(topSlope);
1614
+ endSlope = normalizeAngle(bottomSlope);
1615
+ }
1616
+ else {
1617
+ startSlope = normalizeAngle(bottomSlope);
1618
+ endSlope = normalizeAngle(topSlope);
1619
+ }
1620
+
1573
1621
  // If the mouse moves away from the submenu, resume events
1574
1622
  // The pointer is considered to be moving towards the menu if the slope angle
1575
1623
  // of the line formed between the current and previous mouse positions
1576
1624
  // is between these two slope angles
1577
- let isOutsideSlopeRange = flipSlopes ?
1578
- currentSlope > minSlope && currentSlope < maxSlope :
1579
- currentSlope < minSlope || currentSlope > maxSlope;
1625
+ // This is done by rotating the end and current slope by the start slope and checking which is larger
1626
+ const isOutsideSlopeRange = normalizeAngle(currentSlope - startSlope) >= normalizeAngle(endSlope - startSlope);
1580
1627
 
1581
1628
  if (isOutsideSlopeRange) {
1582
1629
  resumeEvents();
@@ -1587,7 +1634,7 @@ BMMenu.prototype = {
1587
1634
  lastPosition = currentPosition;
1588
1635
  };
1589
1636
 
1590
- eventTarget.addEventListener(mouseMoveEvent, handler, {capture: YES});
1637
+ window.addEventListener(mouseMoveEvent, handler, {capture: YES});
1591
1638
  },
1592
1639
 
1593
1640
  /**
@@ -1603,6 +1650,14 @@ BMMenu.prototype = {
1603
1650
  closeAnimated(animated = YES, {withSupermenu = NO} = {}) {
1604
1651
  // If the menu isn't visible this action has no effect.
1605
1652
  if (!this._node) return;
1653
+
1654
+ const sourceNodeShadow = this._sourceNodeShadow;
1655
+ const containerNode = this._containerNode;
1656
+ const node = this._node;
1657
+ const itemsContainerNode = this._itemsContainerNode;
1658
+ const sourceNode = this._sourceNode;
1659
+
1660
+ this._node = undefined;
1606
1661
 
1607
1662
  this._containerNode.removeEventListener('keydown', this, {passive: true});
1608
1663
  this._containerNode.removeEventListener('keyup', this, {passive: true});
@@ -1647,8 +1702,8 @@ BMMenu.prototype = {
1647
1702
  }
1648
1703
 
1649
1704
  // Prevent interaction with the menu while its close animation is running
1650
- this._node.style.pointerEvents = 'none';
1651
- // this._node.inert = true;
1705
+ node.style.pointerEvents = 'none';
1706
+ // node.inert = true;
1652
1707
 
1653
1708
  if (!supermenu) {
1654
1709
  this._containerNode.style.pointerEvents = 'none';
@@ -1685,12 +1740,6 @@ BMMenu.prototype = {
1685
1740
  }
1686
1741
  }
1687
1742
 
1688
- const sourceNodeShadow = this._sourceNodeShadow;
1689
- const containerNode = this._containerNode;
1690
- const node = this._node;
1691
- const itemsContainerNode = this._itemsContainerNode;
1692
- const sourceNode = this._sourceNode;
1693
-
1694
1743
  this._sourceNode = undefined;
1695
1744
  this._sourceNodeShadow = undefined;
1696
1745
 
@@ -1721,7 +1770,7 @@ BMMenu.prototype = {
1721
1770
 
1722
1771
  itemsContainerNode.style.overflow = 'hidden';
1723
1772
 
1724
- __BMVelocityAnimate(this._node, {
1773
+ __BMVelocityAnimate(node, {
1725
1774
  scaleX: this._kind == BMMenuKind.PullDownMenu ? 1 : scale,
1726
1775
  scaleY: scale,
1727
1776
  opacity: (sourceNodeShadow && !supermenu) ? 1 : 0,
@@ -9992,7 +9992,7 @@ declare class BMMenu {
9992
9992
  * The menu items displayed by this menu.
9993
9993
  *
9994
9994
  */
9995
- readonly items: BMMenuItem[];
9995
+ items: BMMenuItem[];
9996
9996
 
9997
9997
  /**
9998
9998
  * An optional delegate object that will receive callbacks events from this menu.
@@ -10076,7 +10076,7 @@ declare class BMMenu {
10076
10076
  * The menu that opened this menu, if any.
10077
10077
  *
10078
10078
  */
10079
- private _supermenu?: BMMenu | null | undefined;
10079
+ readonly supermenu?: BMMenu | null | undefined;
10080
10080
 
10081
10081
  /**
10082
10082
  * The menu's frame, relative to the viewport, available while this menu is visible.