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

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 (60) hide show
  1. package/README.md +1 -1
  2. package/build/@types/index.d.ts +2194 -94
  3. package/build/BMCollectionView/BMCollectionView.js +977 -196
  4. package/build/BMCollectionView/BMCollectionViewFlowLayout.js +11 -4
  5. package/build/BMCoreUI.css +133 -2
  6. package/build/BMView/BMDragSession.js +1150 -0
  7. package/build/BMView/BMDragSessionActions.js +121 -0
  8. package/build/BMView/BMDragSessionPreview.js +1631 -0
  9. package/build/BMView/BMLayoutConstraint_v2.5.js +14 -59
  10. package/build/BMView/BMView_v2.5.js +34 -3
  11. package/build/BMWindow/BMPopover/BMPopover.js +35 -20
  12. package/build/BMWindow/BMToolWindow.js +29 -1
  13. package/build/BMWindow/BMWindow.js +128 -65
  14. package/build/images/AlignBottom.png +0 -0
  15. package/build/images/AlignCenterX.png +0 -0
  16. package/build/images/AlignCenterY.png +0 -0
  17. package/build/images/AlignLeading.png +0 -0
  18. package/build/images/AlignTop.png +0 -0
  19. package/build/images/AlignTrailing.png +0 -0
  20. package/build/images/AllConstraints.png +0 -0
  21. package/build/images/BottomConstraint.png +0 -0
  22. package/build/images/CenterXConstraint.png +0 -0
  23. package/build/images/CenterYConstraint.png +0 -0
  24. package/build/images/CoreUI2.png +0 -0
  25. package/build/images/CoreUI2@2x.png +0 -0
  26. package/build/images/Desktop.png +0 -0
  27. package/build/images/DesktopMini.png +0 -0
  28. package/build/images/EqualHeight.png +0 -0
  29. package/build/images/EqualHorizontalSpacing.png +0 -0
  30. package/build/images/EqualHorizontalSpacingInSuperview.png +0 -0
  31. package/build/images/EqualVerticalSpacing.png +0 -0
  32. package/build/images/EqualVerticalSpacingInSuperview.png +0 -0
  33. package/build/images/EqualWidth.png +0 -0
  34. package/build/images/HeightConstraint.png +0 -0
  35. package/build/images/InactiveConstraints.png +0 -0
  36. package/build/images/Layout.png +0 -0
  37. package/build/images/LayoutVariables.png +0 -0
  38. package/build/images/LeftConstraint.png +0 -0
  39. package/build/images/OwnConstraints.png +0 -0
  40. package/build/images/Phone.png +0 -0
  41. package/build/images/PhoneLandscape.png +0 -0
  42. package/build/images/PhoneLandscapeMini.png +0 -0
  43. package/build/images/PhoneMini.png +0 -0
  44. package/build/images/PhonePortrait.png +0 -0
  45. package/build/images/PhonePortraitMini.png +0 -0
  46. package/build/images/Properties.png +0 -0
  47. package/build/images/RightConstraint.png +0 -0
  48. package/build/images/SubviewConstraints.png +0 -0
  49. package/build/images/Tablet.png +0 -0
  50. package/build/images/TabletLandscape.png +0 -0
  51. package/build/images/TabletLandscapeMini.png +0 -0
  52. package/build/images/TabletMini.png +0 -0
  53. package/build/images/TabletPortrait.png +0 -0
  54. package/build/images/TabletPortraitMini.png +0 -0
  55. package/build/images/TopConstraint.png +0 -0
  56. package/build/images/WidthConstraint.png +0 -0
  57. package/build/index.js +4 -0
  58. package/lib/@types/BMCoreUI.min.d.ts +2194 -94
  59. package/lib/BMCoreUI.min.js +1 -1
  60. package/package.json +2 -2
@@ -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
 
@@ -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
 
@@ -3,7 +3,7 @@
3
3
  import {YES, NO, BMExtend, BMCopyProperties} from '../Core/BMCoreUI'
4
4
  import {BMPointMake} from '../Core/BMPoint'
5
5
  import {BMRectMake, BMRectMakeWithNodeFrame, BMRectMakeWithOrigin} from '../Core/BMRect'
6
- import {BMAnimateWithBlock, BMAnimationContextGetCurrent, BMAnimationContextEnableWebAnimations, __BMVelocityAnimate, BMHook} from '../Core/BMAnimationContext'
6
+ import {BMAnimateWithBlock, BMAnimationContextGetCurrent, BMAnimationContextEnableWebAnimations, __BMVelocityAnimate, BMHook, BMAnimationContextBeginStatic, BMAnimationApply, BMAnimationBeginWithDuration, BMAnimationContextAddCompletionHandler} from '../Core/BMAnimationContext'
7
7
  import {BMView, BMViewColorScheme} from '../BMView/BMView_v2.5'
8
8
  import {BMLayoutOrientation} from '../BMView/BMLayoutSizeClass'
9
9
  import { BMSizeMake } from '../Core/BMSize'
@@ -746,16 +746,30 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
746
746
  set frame(frame) {
747
747
  if (this._fullScreen) return;
748
748
 
749
+ const currentFrame = this._frame ?? frame;
750
+
749
751
  frame = frame.integralRect;
750
752
 
751
753
  this._frame = frame.copy();
752
754
 
753
- BMCopyProperties(this._window.style, {
754
- left: frame.origin.x + 'px',
755
- top: frame.origin.y + 'px',
756
- width: frame.size.width + 'px',
757
- height: frame.size.height + 'px'
758
- });
755
+ let context = BMAnimationContextGetCurrent();
756
+ if (context) {
757
+ const controller = context.controllerForObject(this, {node: this._window});
758
+ controller.registerBuiltInPropertiesWithDictionary({
759
+ left: [frame.origin.x + 'px', currentFrame.origin.x + 'px'],
760
+ top: [frame.origin.y + 'px', currentFrame.origin.y + 'px'],
761
+ width: [frame.size.width + 'px', currentFrame.size.width + 'px'],
762
+ height: [frame.size.height + 'px', currentFrame.size.height + 'px']
763
+ });
764
+ }
765
+ else {
766
+ BMCopyProperties(this._window.style, {
767
+ left: frame.origin.x + 'px',
768
+ top: frame.origin.y + 'px',
769
+ width: frame.size.width + 'px',
770
+ height: frame.size.height + 'px'
771
+ });
772
+ }
759
773
 
760
774
  switch (this.frameHorizontalPositionLayoutAttribute) {
761
775
  case BMLayoutAttribute.Left:
@@ -849,6 +863,26 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
849
863
  return this._toolbar;
850
864
  },
851
865
 
866
+ /**
867
+ * Defined for non-modal windows. The drag handle used to resize the window.
868
+ */
869
+ _dragHandle: undefined, // <DOMNode>
870
+
871
+ /**
872
+ * Controls whether the window resize handle appears.
873
+ */
874
+ _resizable: YES, // <Boolean>
875
+
876
+ get resizable() {
877
+ return this._resizable;
878
+ },
879
+ set resizable(resizable) {
880
+ if (this._dragHandle) {
881
+ this._dragHandle.style.display = resizable ? 'block' : 'none';
882
+ }
883
+ this._resizable = resizable;
884
+ },
885
+
852
886
  /**
853
887
  * The window overlay.
854
888
  */
@@ -1069,7 +1103,7 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1069
1103
  this.widthConstraint.isActive = YES;
1070
1104
  this.heightConstraint.isActive = YES;
1071
1105
 
1072
- if (!modal && withToolbar) {
1106
+ if (!modal) {
1073
1107
  // In non-modal mode, allow the toolbar to move the window
1074
1108
  this.maxLeftConstraint = this.left.greaterThanOrEqualTo(0);
1075
1109
  this.maxTopConstraint = this.top.greaterThanOrEqualTo(0);
@@ -1086,7 +1120,7 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1086
1120
  window.addEventListener('resize', this._boundViewportDidResize = this._viewportDidResize.bind(this));
1087
1121
 
1088
1122
  // Initialize dragging touch events for the toolbar
1089
- this._toolbar.addEventListener('mousedown', event => {
1123
+ this._toolbar?.addEventListener('mousedown', event => {
1090
1124
  // Don't process events originating from children of the toolbar
1091
1125
  if (event.target != this._toolbar) return;
1092
1126
 
@@ -1130,7 +1164,7 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1130
1164
 
1131
1165
  let touchDragPoint;
1132
1166
 
1133
- this._toolbar.addEventListener('touchstart', /** @type {TouchEvent} */ event => {
1167
+ this._toolbar?.addEventListener('touchstart', /** @type {TouchEvent} */ event => {
1134
1168
  // If there is already a drag in progress, don't process this new event
1135
1169
  if (typeof touchDragPoint !== 'undefined') {
1136
1170
  return;
@@ -1194,11 +1228,11 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1194
1228
  event.preventDefault();
1195
1229
  });
1196
1230
 
1197
- this._toolbar.addEventListener('dbclick', event => {
1231
+ this._toolbar?.addEventListener('dbclick', event => {
1198
1232
  this.minimizeAnimated(YES);
1199
1233
  });
1200
1234
 
1201
- this._toolbar.addEventListener('wheel', /** @param {WheelEvent} event */ event => {
1235
+ this._toolbar?.addEventListener('wheel', /** @param {WheelEvent} event */ event => {
1202
1236
  // Scrolling on the toolbar should enter showcase
1203
1237
  if (event.deltaY > 0) {
1204
1238
  // Allow the delegate to suppress this behaviour
@@ -1918,9 +1952,6 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1918
1952
 
1919
1953
  animated = (animated === undefined ? YES : animated);
1920
1954
 
1921
- //__BMVelocityAnimate(this._blocker, 'stop');
1922
- //__BMVelocityAnimate(this._window, 'stop');
1923
-
1924
1955
  var self = this;
1925
1956
 
1926
1957
  this._blocker.style.pointerEvents = 'none';
@@ -1931,8 +1962,11 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1931
1962
  }
1932
1963
  this._visible = NO;
1933
1964
 
1965
+ // Dismiss all associated tool windows if they are visible
1934
1966
  for (let window of this._toolWindows) {
1935
- window.dismissAnimated(animated);
1967
+ if (window._visible) {
1968
+ window.dismissAnimated(animated);
1969
+ }
1936
1970
  }
1937
1971
 
1938
1972
  if (animated) {
@@ -1941,10 +1975,6 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1941
1975
  duration: _BMWindowAnimationDurationDefault,
1942
1976
  easing: _BMWindowAnimationEasingDefault,
1943
1977
  display: 'none',
1944
- /*progress: function (elements, complete) {
1945
- self._blocker.style.webkitBackdropFilter = 'blur(' + ((1 - complete) * 15).toFixed(2) + 'px)';
1946
- self._blocker.style.backdropFilter = 'blur(' + ((1 - complete) * 15).toFixed(2) + 'px)';
1947
- },*/
1948
1978
  complete: function () {
1949
1979
  self.windowDidClose();
1950
1980
  if (self.delegate && self.delegate.windowDidClose) {
@@ -2195,7 +2225,15 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
2195
2225
  duration: _BMWindowAnimationDurationDefault,
2196
2226
  easing: _BMWindowAnimationEasingDefault,
2197
2227
  display: 'block'
2198
- }, YES);
2228
+ }, YES)?.then(() => {
2229
+ BMHook(this._window, {
2230
+ opacity: 1,
2231
+ translateX: '0px',
2232
+ translateY: '0px',
2233
+ scaleX: 1,
2234
+ scaleY: 1
2235
+ });
2236
+ });
2199
2237
 
2200
2238
  const title = animationNode.querySelector('span');
2201
2239
  __BMVelocityAnimate(title, {translateX: ['30px', '0px']}, {duration: _BMWindowAnimationDurationDefault, easing: _BMWindowAnimationEasingDefault}, YES);
@@ -2242,30 +2280,48 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
2242
2280
 
2243
2281
  var self = this;
2244
2282
 
2283
+ BMAnimationContextBeginStatic();
2284
+
2245
2285
  this.widthConstraint.constant = window.innerWidth;
2246
2286
  this.heightConstraint.constant = window.innerHeight;
2247
2287
  this.leftConstraint.constant = 0;
2248
2288
  this.topConstraint.constant = 0;
2289
+
2290
+ BMAnimationApply();
2249
2291
 
2250
2292
  if (animated) {
2251
- BMAnimateWithBlock(() => {
2252
- let controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
2253
- controller.registerBuiltInPropertiesWithDictionary({left: '0px', top: '0px', width: window.innerWidth + 'px', height: window.innerHeight + 'px'});
2293
+ const completionHandler = function () {
2294
+ if (self.delegate && self.delegate.windowDidEnterFullScreen) self.delegate.windowDidEnterFullScreen(self);
2295
+ if (args && args.completionHandler) args.completionHandler();
2296
+
2297
+ self._window.classList.add('BMFullScreenWindow');
2298
+ };
2299
+
2300
+ // If an animation context is already started, reuse it
2301
+ let contextStarted = NO;
2302
+ if (!BMAnimationContextGetCurrent()) {
2303
+ contextStarted = YES;
2304
+ BMAnimationBeginWithDuration(300, {duration: 300, easing: 'easeInOutQuart',
2305
+ complete: completionHandler
2306
+ });
2307
+ }
2308
+ else {
2309
+ BMAnimationContextAddCompletionHandler(completionHandler);
2310
+ }
2254
2311
 
2255
- const frame = this.frame.copy();
2256
- this.layout();
2312
+ let controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
2257
2313
 
2258
- // When the window contains elements whose intrinsic size must be measured, upon finishing the layout, the window will continue to keep its
2259
- // temporary frame used for measuring, so it has to be reset prior to the animation starting
2260
- BMCopyProperties(this.node.style, {left: frame.origin.x + 'px', top: frame.origin.y + 'px', width: frame.size.width + 'px', height: frame.size.height + 'px'})
2261
- }, {duration: 300, easing: 'easeInOutQuart',
2262
- complete: function () {
2263
- if (self.delegate && self.delegate.windowDidEnterFullScreen) self.delegate.windowDidEnterFullScreen(self);
2264
- if (args && args.completionHandler) args.completionHandler();
2265
-
2266
- self._window.classList.add('BMFullScreenWindow');
2267
- }
2268
- });
2314
+ const frame = this.frame.copy();
2315
+ this.layout();
2316
+ controller.registerBuiltInPropertiesWithDictionary({left: '0px', top: '0px', width: window.innerWidth + 'px', height: window.innerHeight + 'px'});
2317
+
2318
+ // When the window contains elements whose intrinsic size must be measured, upon finishing the layout, the window will continue to keep its
2319
+ // temporary frame used for measuring, so it has to be reset prior to the animation starting
2320
+ BMCopyProperties(this.node.style, {left: frame.origin.x + 'px', top: frame.origin.y + 'px', width: frame.size.width + 'px', height: frame.size.height + 'px'})
2321
+
2322
+ if (contextStarted) {
2323
+ BMAnimationApply();
2324
+ }
2269
2325
  }
2270
2326
  else {
2271
2327
  self._window.classList.add('BMFullScreenWindow');
@@ -2300,44 +2356,51 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
2300
2356
 
2301
2357
  var self = this;
2302
2358
 
2359
+ BMAnimationContextBeginStatic();
2360
+
2303
2361
  this.widthConstraint.constant = this.frame.width;
2304
2362
  this.heightConstraint.constant = this.frame.height;
2305
2363
  this.leftConstraint.constant = this.frame.left;
2306
2364
  this.topConstraint.constant = this.frame.top;
2365
+
2366
+ BMAnimationApply();
2307
2367
 
2308
2368
  if (animated) {
2309
2369
  self._window.classList.remove('BMFullScreenWindow');
2310
2370
  var frame = self.frame;
2311
2371
  BMCopyProperties(self._window.style, {left: '0px', top: '0px', width: window.innerWidth + 'px', height: window.innerHeight + 'px'});
2312
- /*__BMVelocityAnimate(this._window, {left: frame.origin.x + 'px', top: frame.origin.y + 'px', width: frame.size.width + 'px', height: frame.size.height + 'px'}, {
2313
- duration: 300,
2314
- easing: 'easeInOutQuart',
2315
- complete: function () {
2316
- if (self.delegate && self.delegate.windowDidExitFullScreen) self.delegate.windowDidExitFullScreen(self);
2317
- if (args && args.completionHandler) args.completionHandler();
2318
-
2319
- self.frame = self.frame;
2320
- }
2321
- });*/
2322
2372
 
2323
- BMAnimateWithBlock(() => {
2324
- let controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
2325
- controller.registerBuiltInProperty('left', {withValue: frame.origin.x + 'px'});
2326
- controller.registerBuiltInProperty('top', {withValue: frame.origin.y + 'px'});
2327
- controller.registerBuiltInProperty('width', {withValue: frame.size.width + 'px'});
2328
- controller.registerBuiltInProperty('height', {withValue: frame.size.height + 'px'});
2329
- this._fullScreen = NO;
2330
- this.layout();
2331
- BMCopyProperties(self._window.style, {left: '0px', top: '0px', width: window.innerWidth + 'px', height: window.innerHeight + 'px'});
2332
- }, {
2333
- duration: 300, easing: 'easeInOutQuart',
2334
- complete: function () {
2335
- if (self.delegate && self.delegate.windowDidExitFullScreen) self.delegate.windowDidExitFullScreen(self);
2336
- if (args && args.completionHandler) args.completionHandler();
2337
-
2338
- self.frame = self.frame;
2339
- }
2340
- });
2373
+ const completionHandler = function () {
2374
+ if (self.delegate && self.delegate.windowDidExitFullScreen) self.delegate.windowDidExitFullScreen(self);
2375
+ if (args && args.completionHandler) args.completionHandler();
2376
+
2377
+ self.frame = self.frame;
2378
+ };
2379
+
2380
+ // If an animation context is already started, reuse it
2381
+ let contextStarted = NO;
2382
+ if (!BMAnimationContextGetCurrent()) {
2383
+ contextStarted = YES;
2384
+ BMAnimationBeginWithDuration(300, {duration: 300, easing: 'easeInOutQuart',
2385
+ complete: completionHandler
2386
+ });
2387
+ }
2388
+ else {
2389
+ BMAnimationContextAddCompletionHandler(completionHandler);
2390
+ }
2391
+
2392
+ this._fullScreen = NO;
2393
+ this.layout();
2394
+ let controller = BMAnimationContextGetCurrent().controllerForObject(this, {node: this.node});
2395
+ controller.registerBuiltInProperty('left', {withValue: frame.origin.x + 'px'});
2396
+ controller.registerBuiltInProperty('top', {withValue: frame.origin.y + 'px'});
2397
+ controller.registerBuiltInProperty('width', {withValue: frame.size.width + 'px'});
2398
+ controller.registerBuiltInProperty('height', {withValue: frame.size.height + 'px'});
2399
+ BMCopyProperties(self._window.style, {left: '0px', top: '0px', width: window.innerWidth + 'px', height: window.innerHeight + 'px'});
2400
+
2401
+ if (contextStarted) {
2402
+ BMAnimationApply();
2403
+ }
2341
2404
  }
2342
2405
  else {
2343
2406
  self._window.classList.remove('BMFullScreenWindow');
Binary file