bm-core-ui 2.11.9-beta.2 → 2.12.0-beta.12

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 (62) hide show
  1. package/README.md +1 -1
  2. package/build/@types/index.d.ts +2268 -71
  3. package/build/BMCollectionView/BMCollectionView.js +1070 -235
  4. package/build/BMCollectionView/BMCollectionViewFlowLayout.js +11 -4
  5. package/build/BMCollectionView/BMCollectionViewLayout.js +19 -0
  6. package/build/BMCoreUI.css +213 -44
  7. package/build/BMView/BMDragSession.js +1243 -0
  8. package/build/BMView/BMDragSessionActions.js +121 -0
  9. package/build/BMView/BMDragSessionPreview.js +1650 -0
  10. package/build/BMView/BMLayoutConstraint_v2.5.js +14 -59
  11. package/build/BMView/BMMenu.js +50 -20
  12. package/build/BMView/BMView_v2.5.js +34 -3
  13. package/build/BMWindow/BMPopover/BMPopover.js +35 -20
  14. package/build/BMWindow/BMToolWindow.js +29 -1
  15. package/build/BMWindow/BMWindow.js +128 -65
  16. package/build/images/AlignBottom.png +0 -0
  17. package/build/images/AlignCenterX.png +0 -0
  18. package/build/images/AlignCenterY.png +0 -0
  19. package/build/images/AlignLeading.png +0 -0
  20. package/build/images/AlignTop.png +0 -0
  21. package/build/images/AlignTrailing.png +0 -0
  22. package/build/images/AllConstraints.png +0 -0
  23. package/build/images/BottomConstraint.png +0 -0
  24. package/build/images/CenterXConstraint.png +0 -0
  25. package/build/images/CenterYConstraint.png +0 -0
  26. package/build/images/CoreUI2.png +0 -0
  27. package/build/images/CoreUI2@2x.png +0 -0
  28. package/build/images/Desktop.png +0 -0
  29. package/build/images/DesktopMini.png +0 -0
  30. package/build/images/EqualHeight.png +0 -0
  31. package/build/images/EqualHorizontalSpacing.png +0 -0
  32. package/build/images/EqualHorizontalSpacingInSuperview.png +0 -0
  33. package/build/images/EqualVerticalSpacing.png +0 -0
  34. package/build/images/EqualVerticalSpacingInSuperview.png +0 -0
  35. package/build/images/EqualWidth.png +0 -0
  36. package/build/images/HeightConstraint.png +0 -0
  37. package/build/images/InactiveConstraints.png +0 -0
  38. package/build/images/Layout.png +0 -0
  39. package/build/images/LayoutVariables.png +0 -0
  40. package/build/images/LeftConstraint.png +0 -0
  41. package/build/images/OwnConstraints.png +0 -0
  42. package/build/images/Phone.png +0 -0
  43. package/build/images/PhoneLandscape.png +0 -0
  44. package/build/images/PhoneLandscapeMini.png +0 -0
  45. package/build/images/PhoneMini.png +0 -0
  46. package/build/images/PhonePortrait.png +0 -0
  47. package/build/images/PhonePortraitMini.png +0 -0
  48. package/build/images/Properties.png +0 -0
  49. package/build/images/RightConstraint.png +0 -0
  50. package/build/images/SubviewConstraints.png +0 -0
  51. package/build/images/Tablet.png +0 -0
  52. package/build/images/TabletLandscape.png +0 -0
  53. package/build/images/TabletLandscapeMini.png +0 -0
  54. package/build/images/TabletMini.png +0 -0
  55. package/build/images/TabletPortrait.png +0 -0
  56. package/build/images/TabletPortraitMini.png +0 -0
  57. package/build/images/TopConstraint.png +0 -0
  58. package/build/images/WidthConstraint.png +0 -0
  59. package/build/index.js +4 -0
  60. package/lib/@types/BMCoreUI.min.d.ts +2268 -71
  61. package/lib/BMCoreUI.min.js +1 -1
  62. package/package.json +3 -3
@@ -541,10 +541,12 @@ BMLayoutConstraint.prototype = {
541
541
  if (this._solver) {
542
542
  if (this._constraint) {
543
543
  try {
544
- if (this._solver.hasConstraint(this._constraint)) this._solver.removeConstraint(this._constraint);
544
+ if (this._solver.hasConstraint(this._constraint)) {
545
+ this._solver.removeConstraint(this._constraint);
546
+ }
545
547
  }
546
548
  catch (layoutError) {
547
- this._cassowaryConstraint = undefined;
549
+ this._constraint = undefined;
548
550
  this._sourceView.rootView._invalidatedConstraints = YES;
549
551
  this._sourceView.needsLayout = YES;
550
552
  }
@@ -556,7 +558,7 @@ BMLayoutConstraint.prototype = {
556
558
  this._solver.addConstraint(this._cassowaryConstraint);
557
559
  }
558
560
  catch (layoutError) {
559
- this._cassowaryConstraint = undefined;
561
+ this._constraint = undefined;
560
562
  this._sourceView.rootView._invalidatedConstraints = YES;
561
563
  this._sourceView.needsLayout = YES;
562
564
  }
@@ -605,22 +607,12 @@ BMLayoutConstraint.prototype = {
605
607
  return this._constant;
606
608
  },
607
609
  set constant(constant) {
608
- if (constant == this._constant) return;
609
- this._constant = constant;
610
- return this._updateConfiguration();
611
-
612
- // When changing the constant, update the attached solver, if there is one
613
- if (this._solver) {
614
- if (this._constraint) {
615
- this._solver.removeConstraint(this._constraint);
616
- this._constraint = undefined;
617
- }
618
- this._solver.addConstraint(this._cassowaryConstraint);
610
+ if (constant == this._constant) {
611
+ return;
619
612
  }
620
613
 
621
- if (this.isActive) {
622
- this._sourceView.needsLayout = YES;
623
- }
614
+ this._constant = constant;
615
+ this._updateConfiguration();
624
616
  },
625
617
 
626
618
  /**
@@ -694,15 +686,7 @@ BMLayoutConstraint.prototype = {
694
686
  * Returns this constraint's constant for the currently active size class.
695
687
  */
696
688
  get activeConstant() { // <Number or String>
697
- // TODO:
698
689
  return this._configuration.constant;
699
- let sizeClassHash = this._sourceView.sizeClass._hashString;
700
-
701
- if ('constant' in this._variations[sizeClassHash]) {
702
- return this._variations[sizeClassHash].constant;
703
- }
704
-
705
- return this._constant;
706
690
  },
707
691
 
708
692
  /**
@@ -716,12 +700,7 @@ BMLayoutConstraint.prototype = {
716
700
  set priority(priority) {
717
701
  if (this._priority != priority) {
718
702
  this._priority = priority;
719
- return this._updateConfiguration();
720
-
721
- this._sourceView.needsLayout = YES;
722
-
723
- if (this._targetView) this._targetView.needsLayout = YES;
724
- this._sourceView.rootView._invalidatedConstraints = YES;
703
+ this._updateConfiguration();
725
704
  }
726
705
  },
727
706
 
@@ -798,13 +777,6 @@ BMLayoutConstraint.prototype = {
798
777
  get activePriority() { // <Number>
799
778
  // TODO:
800
779
  return this._configuration.priority;
801
- let sizeClassHash = this._sourceView.sizeClass._hashString;
802
-
803
- if ('priority' in this._variations[sizeClassHash]) {
804
- return this._variations[sizeClassHash].priority;
805
- }
806
-
807
- return this._priority;
808
780
  },
809
781
 
810
782
  /**
@@ -855,19 +827,7 @@ BMLayoutConstraint.prototype = {
855
827
  set isActive(active) {
856
828
  if (active != this._isActive) {
857
829
  this._isActive = active;
858
- return this._updateConfiguration();
859
- this._sourceView._checkConstraints();
860
- this._sourceView.needsLayout = YES;
861
- this._sourceView.rootView._invalidatedConstraints = YES;
862
-
863
- if (this._targetView) {
864
- if (this._targetView.rootView != this._sourceView.rootView) {
865
- throw new Error('[BMCoreUI] Incorrectly attempting to activate a layout constraint that affects two views that do not share a common ancestor.');
866
- }
867
-
868
- this._targetView._checkConstraints();
869
- this._targetView.needsLayout = YES;
870
- }
830
+ this._updateConfiguration();
871
831
  }
872
832
  },
873
833
 
@@ -942,13 +902,6 @@ BMLayoutConstraint.prototype = {
942
902
  */
943
903
  get affectsLayout() { // <Boolean>
944
904
  return this._configuration.isActive;
945
- let sizeClassHash = this._sourceView.sizeClass._hashString;
946
-
947
- if ('isActive' in this._variations[sizeClassHash]) {
948
- return this._variations[sizeClassHash].isActive;
949
- }
950
-
951
- return this._isActive;
952
905
  },
953
906
 
954
907
  /**
@@ -1048,7 +1001,9 @@ BMLayoutConstraint.prototype = {
1048
1001
  * generated by this layout constraint.
1049
1002
  */
1050
1003
  get _cassowaryConstraint() {
1051
- if (this._constraint) return this._constraint;
1004
+ if (this._constraint) {
1005
+ return this._constraint;
1006
+ }
1052
1007
 
1053
1008
  var expression = this._cassowaryExpression;
1054
1009
 
@@ -460,6 +460,12 @@ BMMenu.prototype = {
460
460
  this.__delaysClosing = delays;
461
461
  },
462
462
 
463
+ /**
464
+ * When set to `YES`, the menu item actions and item selection delegate callbacks will be invoked
465
+ * with a slight delay to allow time for the menu closing animation to play.
466
+ */
467
+ delaysActions: NO, // <Boolean>
468
+
463
469
  /**
464
470
  * Initializes this menu with the specified items.
465
471
  * The menu will be hidden by default; the method showAtPoint(_) should be used to make the menu visible.
@@ -701,20 +707,13 @@ BMMenu.prototype = {
701
707
  // animation to play out
702
708
  this._delaysClosing = YES;
703
709
 
704
- if (item.action) {
705
- // Invoke the menu's action if configured
706
- item.action(item);
707
- }
710
+ this._selectedMenuItem = item;
708
711
 
709
712
  itemNode.classList.add('BMMenuItemActive');
710
-
711
- if (this.delegate && this.delegate.menuDidSelectItem) {
712
- this.delegate.menuDidSelectItem(this, item);
713
- }
714
713
  });
715
714
 
716
715
  // When moving the mouse over an item, set the highlight index to it,
717
- // allowing further keyboard navigation to continute from this item
716
+ // allowing further keyboard navigation to continue from this item
718
717
  itemNode.addEventListener('mouseover', event => {
719
718
  // Disabled items can't be highlighted and can't open submenus
720
719
  if (!item._enabled) {
@@ -747,6 +746,21 @@ BMMenu.prototype = {
747
746
  });
748
747
  },
749
748
 
749
+ /**
750
+ * Temporarily set to the menu item that was selected until its action is performed.
751
+ */
752
+ _selectedMenuItem: undefined, // <BMMenuItem, nullable>
753
+
754
+ /**
755
+ * Performs the action for the specified menu item and invokes the delegate selection callback for it.
756
+ * @param item <BMMenuItem> The menu item whose action should be performed.
757
+ */
758
+ _performActionForMenuItem(item) {
759
+ item.action?.(item);
760
+
761
+ this.delegate?.menuDidSelectItem?.(this, item);
762
+ },
763
+
750
764
  /**
751
765
  * The kind of menu currently displayed.
752
766
  */
@@ -899,8 +913,8 @@ BMMenu.prototype = {
899
913
  });
900
914
 
901
915
  if (!this._supermenu) {
902
- // Make the container visible
903
- __BMVelocityAnimate(menuContainer, {opacity: 1}, {duration, easing}, BMMENU_USE_WEB_ANIMATIONS);
916
+ // Make the container visible, using a different easing for the opacity so that it doesn't overshoot the 1 limit
917
+ __BMVelocityAnimate(menuContainer, {opacity: 1}, {duration: duration / 2, easing: 'easeOutQuad'}, BMMENU_USE_WEB_ANIMATIONS);
904
918
  }
905
919
  else {
906
920
  this._supermenu._node.classList.add('BMMenuInactive');
@@ -911,8 +925,9 @@ BMMenu.prototype = {
911
925
  itemsContainerNode.style.overflow = 'hidden';
912
926
 
913
927
  __BMVelocityAnimate(menuNode, {opacity: 1}, {
914
- duration,
915
- easing
928
+ duration: duration / 2,
929
+ // Use a different easing for the opacity so that it doesn't overshoot the 1 limit
930
+ easing: 'easeOutQuad',
916
931
  }, BMMENU_USE_WEB_ANIMATIONS);
917
932
 
918
933
  __BMVelocityAnimate(menuNode, {scaleX: 1, scaleY: 1, translateZ: 0, translateY: 0, translateX: 0}, {
@@ -921,7 +936,7 @@ BMMenu.prototype = {
921
936
  complete: _ => {
922
937
  menuNode.style.pointerEvents = 'all';
923
938
  menuContainer.style.pointerEvents = 'all';
924
- }
939
+ },
925
940
  }, BMMENU_USE_WEB_ANIMATIONS);
926
941
 
927
942
  // Animate each child node in
@@ -1267,7 +1282,9 @@ BMMenu.prototype = {
1267
1282
  // If the mouse pointer enters the submenu's frame, cause it to acquire focus
1268
1283
  // and resume events
1269
1284
  if (submenuFrame.intersectsPoint(currentPosition)) {
1270
- submenu._node.focus();
1285
+ if (submenu._node) {
1286
+ submenu._node.focus();
1287
+ }
1271
1288
  resumeEvents();
1272
1289
  return;
1273
1290
  }
@@ -1380,11 +1397,27 @@ BMMenu.prototype = {
1380
1397
  let delay = Math.min(this._itemsContainerNode.childNodes.length * 16, 150);
1381
1398
  delay = (delay < 0 ? 0 : delay);
1382
1399
 
1400
+ let selectedItemCallbackDelay = 0;
1401
+
1383
1402
  // If an item was clicked, further delay closing to allow the selection animation to play
1384
1403
  const delaysClosing = this._delaysClosing;
1385
1404
  this._delaysClosing = NO;
1386
1405
  if (delaysClosing && !this._sourceNodeShadow) {
1387
1406
  delay += 200;
1407
+
1408
+ selectedItemCallbackDelay = 200;
1409
+ }
1410
+
1411
+ const selectedMenuItem = this._selectedMenuItem;
1412
+ this._selectedMenuItem = undefined;
1413
+
1414
+ if (selectedMenuItem) {
1415
+ if (this.delaysActions && selectedItemCallbackDelay) {
1416
+ setTimeout(() => this._performActionForMenuItem(selectedMenuItem), selectedItemCallbackDelay);
1417
+ }
1418
+ else {
1419
+ this._performActionForMenuItem(selectedMenuItem);
1420
+ }
1388
1421
  }
1389
1422
 
1390
1423
  const sourceNodeShadow = this._sourceNodeShadow;
@@ -1547,6 +1580,7 @@ BMMenu.prototype = {
1547
1580
  },
1548
1581
 
1549
1582
  /**
1583
+ * @protected
1550
1584
  * Invoked when the key sequence for a menu item is pressed.
1551
1585
  * @param event <KeyboardEvent> The event that triggered this action.
1552
1586
  * {
@@ -1598,11 +1632,7 @@ BMMenu.prototype = {
1598
1632
  // animation to play out
1599
1633
  this._delaysClosing = YES;
1600
1634
 
1601
- if (item.action) item.action(item);
1602
-
1603
- if (this.delegate && this.delegate.menuDidSelectItem) {
1604
- this.delegate.menuDidSelectItem(this, item);
1605
- }
1635
+ this._selectedMenuItem = item;
1606
1636
 
1607
1637
  const highlightedNode = item._node;
1608
1638
  if (highlightedNode) {
@@ -11,6 +11,7 @@ import {BMViewport} from './BMViewport'
11
11
  import {BMLayoutAttribute, BMLayoutConstraintRelation, BMLayoutConstraint, BMLayoutConstraintPriorityRequired, BMLayoutConstraintKind} from './BMLayoutConstraint_v2.5'
12
12
  import * as kiwi from 'kiwi.js'
13
13
  import { BMKeyboardShortcutModifier } from '../BMWindow/BMKeyboardShortcut'
14
+ import { BMDragSession } from './BMDragSession'
14
15
 
15
16
 
16
17
  // When set to YES, this will cause view to use transforms instead of left/right for positioning
@@ -2276,7 +2277,9 @@ BMView.prototype = BMExtend(BMView.prototype, {
2276
2277
  * @param shortcut <BMKeyboardShortcut> The keyboard shortcut to register.
2277
2278
  */
2278
2279
  registerKeyboardShortcut(shortcut) {
2279
- if (!Object.keys(this._keyboardShortcuts).length) this._enableKeyboardShortcuts();
2280
+ if (!Object.keys(this._keyboardShortcuts).length) {
2281
+ this._enableKeyboardShortcuts();
2282
+ }
2280
2283
 
2281
2284
  if (!this._keyboardShortcuts[shortcut.keyCode]) {
2282
2285
  this._keyboardShortcuts[shortcut.keyCode] = [];
@@ -2306,7 +2309,9 @@ BMView.prototype = BMExtend(BMView.prototype, {
2306
2309
  }
2307
2310
  }
2308
2311
 
2309
- if (!Object.keys(this._keyboardShortcuts).length) this._disableKeyboardShortcuts();
2312
+ if (!Object.keys(this._keyboardShortcuts).length) {
2313
+ this._disableKeyboardShortcuts();
2314
+ }
2310
2315
  },
2311
2316
 
2312
2317
  /**
@@ -2314,9 +2319,12 @@ BMView.prototype = BMExtend(BMView.prototype, {
2314
2319
  * and handle key presses. Subclasses that override this method should invoke the base implementation to allow
2315
2320
  * keyboard shortcuts to be handled correctly.
2316
2321
  * @param event <KeyboardEvent> The event that triggered this action.
2322
+ * @return <Boolean, nullable> `YES` if a keyboard shortcut was handled, `NO` or `undefined` otherwise.
2317
2323
  */
2318
2324
  keyPressedWithEvent(event) {
2319
- if (!this._keyboardShortcuts[event.code]) return;
2325
+ if (!this._keyboardShortcuts[event.code]) return NO;
2326
+
2327
+ let shortcutHandled = NO;
2320
2328
 
2321
2329
  // Check if a shortcut key has been pressed.
2322
2330
  for (const shortcut of this._keyboardShortcuts[event.code]) {
@@ -2331,8 +2339,11 @@ BMView.prototype = BMExtend(BMView.prototype, {
2331
2339
  if (bitmap == shortcut._modifierBitmap) {
2332
2340
  if (shortcut.preventsDefault) event.preventDefault();
2333
2341
  shortcut.target[shortcut.action](event, {forKeyboardShortcut: shortcut});
2342
+ shortcutHandled = YES;
2334
2343
  }
2335
2344
  }
2345
+
2346
+ return shortcutHandled;
2336
2347
  },
2337
2348
 
2338
2349
  /**
@@ -2370,6 +2381,26 @@ BMView.prototype = BMExtend(BMView.prototype, {
2370
2381
 
2371
2382
  // #endregion
2372
2383
 
2384
+ // #region Gestures
2385
+
2386
+ /**
2387
+ * Initiates a drag session with the specified drag delegate from a touch or mouse event.
2388
+ * @param event <MouseEvent or TouchEvent> The event that triggered the drag gesture.
2389
+ * {
2390
+ * @param delegate <BMDragDelegate> The drag session delegate supplying items and
2391
+ * handling events for the session.
2392
+ * @param touchIdentifier <Number, nullable> If the event is a touch event and this is specified,
2393
+ * it represents the identifier of the touch point that
2394
+ * will be tracked throughout the drag session. If not
2395
+ * specified, the first changed touch will be used.
2396
+ * }
2397
+ */
2398
+ performDragWithEvent(event, {delegate, touchIdentifier}) {
2399
+ BMDragSession._beginDragWithEvent(event, {dragDelegate: delegate, view: this, touchIdentifier});
2400
+ },
2401
+
2402
+ // #endregion
2403
+
2373
2404
  // #region Constraints and Cassowary Variables
2374
2405
 
2375
2406
 
@@ -1127,12 +1127,16 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
1127
1127
  }
1128
1128
 
1129
1129
  if (!this._isDetached) {
1130
+ const popoverLayers = [this.contentNode, this._background, this._dropShadowContainer];
1131
+
1130
1132
  // If not detached, apply a displacement to this popover that is half of the regular
1131
1133
  // drag distance, until this popover is fully detached
1132
- BMHook(this.node, {
1133
- translateX: `${(toPosition.x - this._initialDragPosition.x) / 3 | 0}px`,
1134
- translateY: `${(toPosition.y - this._initialDragPosition.y) / 3 | 0}px`,
1135
- });
1134
+ for (const node of popoverLayers) {
1135
+ BMHook(node, {
1136
+ translateX: `${(toPosition.x - this._initialDragPosition.x) / 3 | 0}px`,
1137
+ translateY: `${(toPosition.y - this._initialDragPosition.y) / 3 | 0}px`,
1138
+ });
1139
+ }
1136
1140
 
1137
1141
  const distance = toPosition.distanceToPoint(this._initialDragPosition);
1138
1142
  if (distance > BMPopoverDragThreshold) {
@@ -1158,11 +1162,15 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
1158
1162
  // If the drag operation didn't cause this popover to detach, animate it back to its
1159
1163
  // regular position
1160
1164
  BMAnimateWithBlock(() => {
1161
- const controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
1162
- controller.registerBuiltInPropertiesWithDictionary({
1163
- translateX: '0px',
1164
- translateY: '0px',
1165
- });
1165
+ const popoverLayers = [this.contentNode, this._background, this._dropShadowContainer];
1166
+
1167
+ for (const node of popoverLayers) {
1168
+ const controller = BMAnimationContextGetCurrent().controllerForObject(node, {node});
1169
+ controller.registerBuiltInPropertiesWithDictionary({
1170
+ translateX: '0px',
1171
+ translateY: '0px',
1172
+ });
1173
+ }
1166
1174
  }, {duration: 500, easing: 'easeInOutQuart'});
1167
1175
  }
1168
1176
 
@@ -1194,19 +1202,24 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
1194
1202
 
1195
1203
  let promise;
1196
1204
 
1205
+ const popoverLayers = [this.contentNode, this._background, this._dropShadowContainer];
1206
+
1197
1207
  // If a temporary transform was applied to this node, clear it
1198
- if (BMAnimationContextGetCurrent()) {
1199
- const controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
1200
- controller.registerBuiltInPropertiesWithDictionary({
1201
- translateX: '0px',
1202
- translateY: '0px',
1203
- });
1208
+ for (const node of popoverLayers) {
1209
+ if (BMAnimationContextGetCurrent()) {
1210
+ const controller = BMAnimationContextGetCurrent().controllerForObject(node, {node});
1211
+ controller.registerBuiltInPropertiesWithDictionary({
1212
+ translateX: '0px',
1213
+ translateY: '0px',
1214
+ });
1204
1215
 
1205
- promise = new Promise(r => BMAnimationContextAddCompletionHandler(r));
1206
- }
1207
- else {
1208
- BMHook(this.node, {translateX: '0px', translateY: '0px'});
1216
+ promise = new Promise(r => BMAnimationContextAddCompletionHandler(r));
1217
+ }
1218
+ else {
1219
+ BMHook(node, {translateX: '0px', translateY: '0px'});
1220
+ }
1209
1221
  }
1222
+
1210
1223
 
1211
1224
  if (animationContextStarted) {
1212
1225
  BMAnimationApplyBlocking(YES);
@@ -1229,7 +1242,9 @@ BMPopover.prototype = BMExtend(Object.create(BMWindow.prototype), {
1229
1242
  for (const layer of popoverLayers) {
1230
1243
  BMHook(layer, {scaleX: .75, scaleY: .75, opacity: 0});
1231
1244
 
1232
- __BMVelocityAnimate(layer, {scaleX: 1, scaleY: 1, opacity: 1}, {duration: 300, easing: [0,1.59,.49,1], complete: first ? completionHandler : undefined}, YES);
1245
+ __BMVelocityAnimate(layer, {scaleX: 1, scaleY: 1, opacity: 1}, {duration: 300, easing: [0,1.59,.49,1], complete: first ? completionHandler : undefined}, YES)?.then(() => {
1246
+ BMHook(layer, {scaleX: 1, scaleY: 1, opacity: 1});
1247
+ });
1233
1248
  first = NO;
1234
1249
  }
1235
1250
  },
@@ -1,5 +1,6 @@
1
1
  // @ts-check
2
2
 
3
+ import { BMView } from '../BMView/BMView_v2.5';
3
4
  import {YES, NO, BMExtend} from '../Core/BMCoreUI'
4
5
  import {BMWindow} from './BMWindow'
5
6
 
@@ -25,6 +26,11 @@ BMToolWindow.prototype = BMExtend(Object.create(BMWindow.prototype), {
25
26
  */
26
27
  opensAutomatically: YES, // <Boolean>
27
28
 
29
+ /**
30
+ * The window to which this tool window is associated.
31
+ */
32
+ _parentWindow: undefined, // <BMWindow>
33
+
28
34
  /**
29
35
  * Initializes this tool window with the given frame and associates it with the given window.
30
36
  * @param frame <BMRect> The window's frame.
@@ -41,8 +47,14 @@ BMToolWindow.prototype = BMExtend(Object.create(BMWindow.prototype), {
41
47
  this.node.classList.add('BMToolWindow');
42
48
  window._toolWindows.push(this);
43
49
 
50
+ this._parentWindow = window;
51
+
44
52
  // If the window is the key window, make this tool window visible
45
- if (BMWindow._keyWindow == window) this.bringToFrontAnimated(YES);
53
+ if (BMWindow._keyWindow == window) {
54
+ this.bringToFrontAnimated(YES);
55
+ }
56
+
57
+ this._enableKeyboardShortcuts();
46
58
 
47
59
  return this;
48
60
  },
@@ -53,6 +65,22 @@ BMToolWindow.prototype = BMExtend(Object.create(BMWindow.prototype), {
53
65
 
54
66
  resignKeyWindow() {
55
67
  // This operation is a no-op for tool windows
68
+ },
69
+
70
+ keyPressedWithEvent(event, args) {
71
+ const handled = BMView.prototype.keyPressedWithEvent.apply(this, [event, args]);
72
+
73
+ if (!handled) {
74
+ this._parentWindow?.keyPressedWithEvent(event, args);
75
+ }
76
+ },
77
+
78
+ release() {
79
+ const index = this._parentWindow._toolWindows.indexOf(this);
80
+ if (index != -1) {
81
+ this._parentWindow._toolWindows.splice(index, -1);
82
+ }
83
+ BMWindow.prototype.release.call(this);
56
84
  }
57
85
  });
58
86