@ionic/core 7.4.4-dev.11696860023.1b8ee3ef → 7.4.4-dev.11696895407.1bd7a380

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 (153) hide show
  1. package/components/animation.js +60 -1
  2. package/components/checkbox.js +3 -0
  3. package/components/ion-footer.js +11 -21
  4. package/components/ion-menu.js +51 -19
  5. package/components/ion-tab-bar.js +11 -21
  6. package/components/ion-toggle.js +3 -0
  7. package/components/radio-group.js +1 -1
  8. package/components/radio.js +4 -1
  9. package/components/swipe-back.js +5 -1
  10. package/dist/cjs/{animation-2bb33618.js → animation-c8bdd3c7.js} +60 -1
  11. package/dist/cjs/{index-97a3eade.js → index-1f1ea05f.js} +1 -1
  12. package/dist/cjs/{index-acf6bdf0.js → index-fa649bd8.js} +2 -2
  13. package/dist/cjs/index.cjs.js +5 -5
  14. package/dist/cjs/ion-action-sheet.cjs.entry.js +1 -1
  15. package/dist/cjs/ion-alert.cjs.entry.js +1 -1
  16. package/dist/cjs/ion-app_8.cjs.entry.js +14 -23
  17. package/dist/cjs/ion-checkbox.cjs.entry.js +3 -0
  18. package/dist/cjs/ion-datetime_3.cjs.entry.js +1 -1
  19. package/dist/cjs/ion-loading.cjs.entry.js +1 -1
  20. package/dist/cjs/ion-menu_3.cjs.entry.js +53 -21
  21. package/dist/cjs/ion-modal.cjs.entry.js +2 -2
  22. package/dist/cjs/ion-nav_2.cjs.entry.js +2 -2
  23. package/dist/cjs/ion-popover.cjs.entry.js +2 -2
  24. package/dist/cjs/ion-radio_2.cjs.entry.js +5 -2
  25. package/dist/cjs/ion-refresher_2.cjs.entry.js +1 -1
  26. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +12 -21
  27. package/dist/cjs/ion-toast.cjs.entry.js +1 -1
  28. package/dist/cjs/ion-toggle.cjs.entry.js +3 -0
  29. package/dist/cjs/{ios.transition-e31445c2.js → ios.transition-4195d10d.js} +2 -2
  30. package/dist/cjs/{md.transition-fb13ac79.js → md.transition-0713f667.js} +2 -2
  31. package/dist/cjs/{swipe-back-6c57d1df.js → swipe-back-d0412fb6.js} +5 -1
  32. package/dist/collection/components/checkbox/checkbox.js +3 -0
  33. package/dist/collection/components/footer/footer.js +11 -21
  34. package/dist/collection/components/menu/menu.js +51 -19
  35. package/dist/collection/components/menu/test/disable/menu.e2e.js +55 -0
  36. package/dist/collection/components/radio/radio.js +4 -1
  37. package/dist/collection/components/radio-group/radio-group.js +1 -1
  38. package/dist/collection/components/tab-bar/tab-bar.js +11 -21
  39. package/dist/collection/components/toggle/toggle.js +3 -0
  40. package/dist/collection/utils/animation/animation.js +60 -1
  41. package/dist/collection/utils/gesture/swipe-back.js +5 -1
  42. package/dist/collection/utils/keyboard/keyboard-controller.js +1 -1
  43. package/dist/docs.json +1 -1
  44. package/dist/esm/{animation-a1d9e088.js → animation-92066c62.js} +60 -1
  45. package/dist/esm/{index-32c6828b.js → index-0b0dd67c.js} +2 -2
  46. package/dist/esm/{index-3d6aefa2.js → index-97a2bb98.js} +1 -1
  47. package/dist/esm/index.js +5 -5
  48. package/dist/esm/ion-action-sheet.entry.js +1 -1
  49. package/dist/esm/ion-alert.entry.js +1 -1
  50. package/dist/esm/ion-app_8.entry.js +14 -23
  51. package/dist/esm/ion-checkbox.entry.js +3 -0
  52. package/dist/esm/ion-datetime_3.entry.js +1 -1
  53. package/dist/esm/ion-loading.entry.js +1 -1
  54. package/dist/esm/ion-menu_3.entry.js +53 -21
  55. package/dist/esm/ion-modal.entry.js +2 -2
  56. package/dist/esm/ion-nav_2.entry.js +2 -2
  57. package/dist/esm/ion-popover.entry.js +2 -2
  58. package/dist/esm/ion-radio_2.entry.js +5 -2
  59. package/dist/esm/ion-refresher_2.entry.js +1 -1
  60. package/dist/esm/ion-tab-bar_2.entry.js +12 -21
  61. package/dist/esm/ion-toast.entry.js +1 -1
  62. package/dist/esm/ion-toggle.entry.js +3 -0
  63. package/dist/esm/{ios.transition-d8223b18.js → ios.transition-875ba2ea.js} +2 -2
  64. package/dist/esm/{md.transition-caed184e.js → md.transition-54c79f72.js} +2 -2
  65. package/dist/esm/{swipe-back-6d4c0a4e.js → swipe-back-0f3bfc8e.js} +5 -1
  66. package/dist/esm-es5/animation-92066c62.js +4 -0
  67. package/dist/esm-es5/{index-32c6828b.js → index-0b0dd67c.js} +1 -1
  68. package/dist/esm-es5/{index-3d6aefa2.js → index-97a2bb98.js} +1 -1
  69. package/dist/esm-es5/index.js +1 -1
  70. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  71. package/dist/esm-es5/ion-alert.entry.js +1 -1
  72. package/dist/esm-es5/ion-app_8.entry.js +1 -1
  73. package/dist/esm-es5/ion-checkbox.entry.js +1 -1
  74. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  75. package/dist/esm-es5/ion-loading.entry.js +1 -1
  76. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  77. package/dist/esm-es5/ion-modal.entry.js +1 -1
  78. package/dist/esm-es5/ion-nav_2.entry.js +1 -1
  79. package/dist/esm-es5/ion-popover.entry.js +1 -1
  80. package/dist/esm-es5/ion-radio_2.entry.js +1 -1
  81. package/dist/esm-es5/ion-refresher_2.entry.js +1 -1
  82. package/dist/esm-es5/ion-tab-bar_2.entry.js +1 -1
  83. package/dist/esm-es5/ion-toast.entry.js +1 -1
  84. package/dist/esm-es5/ion-toggle.entry.js +1 -1
  85. package/dist/esm-es5/{ios.transition-d8223b18.js → ios.transition-875ba2ea.js} +1 -1
  86. package/dist/esm-es5/{md.transition-caed184e.js → md.transition-54c79f72.js} +1 -1
  87. package/dist/esm-es5/{swipe-back-6d4c0a4e.js → swipe-back-0f3bfc8e.js} +1 -1
  88. package/dist/ionic/index.esm.js +1 -1
  89. package/dist/ionic/ionic.esm.js +1 -1
  90. package/dist/ionic/p-00d3814a.system.entry.js +4 -0
  91. package/dist/ionic/p-015187e5.system.js +4 -0
  92. package/dist/ionic/{p-96ad49f1.entry.js → p-07c816fb.entry.js} +1 -1
  93. package/dist/ionic/{p-1d2d1ab5.system.entry.js → p-0c7d0167.system.entry.js} +1 -1
  94. package/dist/ionic/{p-95e44641.system.entry.js → p-0dcdf480.system.entry.js} +1 -1
  95. package/dist/ionic/{p-8957b1de.system.entry.js → p-0fc8a522.system.entry.js} +1 -1
  96. package/dist/ionic/{p-57c5eca2.system.js → p-15041a8c.system.js} +1 -1
  97. package/dist/ionic/{p-30b04d8d.js → p-2062958e.js} +1 -1
  98. package/dist/ionic/{p-4b23f472.entry.js → p-2134558d.entry.js} +1 -1
  99. package/dist/ionic/{p-037e2738.system.entry.js → p-2330af92.system.entry.js} +1 -1
  100. package/dist/ionic/{p-e88ed929.system.entry.js → p-24952f8a.system.entry.js} +1 -1
  101. package/dist/ionic/{p-1caf1ec6.entry.js → p-32eaa293.entry.js} +1 -1
  102. package/dist/ionic/{p-fb18f74b.system.entry.js → p-3d278648.system.entry.js} +1 -1
  103. package/dist/ionic/p-446230d7.js +4 -0
  104. package/dist/ionic/p-4c274938.entry.js +4 -0
  105. package/dist/ionic/{p-58565369.system.entry.js → p-52e5f8f0.system.entry.js} +1 -1
  106. package/dist/ionic/p-53d4606a.entry.js +4 -0
  107. package/dist/ionic/{p-d580cbb7.system.entry.js → p-63b4ef44.system.entry.js} +1 -1
  108. package/dist/ionic/{p-7cad90ed.entry.js → p-678f37d7.entry.js} +1 -1
  109. package/dist/ionic/{p-c381a9a9.system.entry.js → p-7061fa75.system.entry.js} +1 -1
  110. package/dist/ionic/p-73eba881.system.js +1 -1
  111. package/dist/ionic/p-775f3749.entry.js +4 -0
  112. package/dist/ionic/p-77872abc.entry.js +4 -0
  113. package/dist/ionic/p-77b9d68a.system.entry.js +4 -0
  114. package/dist/ionic/p-7b15d413.entry.js +4 -0
  115. package/dist/ionic/p-8b33cfef.entry.js +4 -0
  116. package/dist/ionic/{p-c57cde35.system.js → p-8dbdb163.system.js} +1 -1
  117. package/dist/ionic/p-8f36cde3.system.entry.js +4 -0
  118. package/dist/ionic/{p-9e727d1d.entry.js → p-979dc719.entry.js} +1 -1
  119. package/dist/ionic/{p-9d0916cb.system.js → p-9e6bf328.system.js} +1 -1
  120. package/dist/ionic/{p-e7d69cad.entry.js → p-a1528344.entry.js} +1 -1
  121. package/dist/ionic/p-a1e2f98c.js +4 -0
  122. package/dist/ionic/{p-c2d6b2fb.entry.js → p-ab37db48.entry.js} +1 -1
  123. package/dist/ionic/p-af39c1c5.js +4 -0
  124. package/dist/ionic/{p-a760fd9a.system.js → p-b7258ddb.system.js} +1 -1
  125. package/dist/ionic/p-c5395981.js +4 -0
  126. package/dist/ionic/{p-043e8328.system.js → p-c9524896.system.js} +1 -1
  127. package/dist/ionic/{p-6db9035a.system.entry.js → p-cd075e75.system.entry.js} +1 -1
  128. package/dist/ionic/{p-a0e2f6d8.entry.js → p-d055bba9.entry.js} +1 -1
  129. package/dist/ionic/p-d17638e9.system.js +4 -0
  130. package/dist/ionic/{p-6b3784a2.system.entry.js → p-df951755.system.entry.js} +1 -1
  131. package/dist/ionic/p-e627ed84.js +4 -0
  132. package/dist/ionic/{p-ab7edc16.system.entry.js → p-e92068d4.system.entry.js} +1 -1
  133. package/dist/ionic/{p-e3272ed8.entry.js → p-eaa58d23.entry.js} +1 -1
  134. package/dist/types/components/menu/menu.d.ts +8 -1
  135. package/hydrate/index.js +149 -63
  136. package/package.json +1 -1
  137. package/dist/esm-es5/animation-a1d9e088.js +0 -4
  138. package/dist/ionic/p-0cbec498.system.entry.js +0 -4
  139. package/dist/ionic/p-1c59608c.system.entry.js +0 -4
  140. package/dist/ionic/p-469d6a98.entry.js +0 -4
  141. package/dist/ionic/p-4af11953.entry.js +0 -4
  142. package/dist/ionic/p-606fddbe.system.entry.js +0 -4
  143. package/dist/ionic/p-6641d7fa.js +0 -4
  144. package/dist/ionic/p-686a9d53.entry.js +0 -4
  145. package/dist/ionic/p-68b405cc.entry.js +0 -4
  146. package/dist/ionic/p-6b2641f6.system.js +0 -4
  147. package/dist/ionic/p-90ebbca0.entry.js +0 -4
  148. package/dist/ionic/p-94a4ce40.js +0 -4
  149. package/dist/ionic/p-9649c54e.js +0 -4
  150. package/dist/ionic/p-a0b19468.entry.js +0 -4
  151. package/dist/ionic/p-a732cfec.system.js +0 -4
  152. package/dist/ionic/p-b370d1b4.js +0 -4
  153. package/dist/ionic/p-df7357c5.js +0 -4
@@ -10,13 +10,13 @@ const cubicBezier = require('./cubic-bezier-6b9222ad.js');
10
10
  const index$2 = require('./index-306a7476.js');
11
11
  const gestureController = require('./gesture-controller-b46721be.js');
12
12
  const helpers = require('./helpers-ea4ccbcb.js');
13
- const index$1 = require('./index-97a3eade.js');
13
+ const index$1 = require('./index-1f1ea05f.js');
14
14
  const overlays = require('./overlays-efc9d511.js');
15
15
  const ionicGlobal = require('./ionic-global-a71608df.js');
16
16
  const theme = require('./theme-fbc56b3b.js');
17
17
  const index$3 = require('./index-d8d1fc0b.js');
18
18
  require('./hardware-back-button-b67c8e75.js');
19
- require('./animation-2bb33618.js');
19
+ require('./animation-c8bdd3c7.js');
20
20
  require('./framework-delegate-c0873a6f.js');
21
21
  require('./index-cc7dfb7c.js');
22
22
 
@@ -40,6 +40,14 @@ const Menu = class {
40
40
  this.lastOnEnd = 0;
41
41
  this.blocker = gestureController.GESTURE_CONTROLLER.createBlocker({ disableScroll: true });
42
42
  this.didLoad = false;
43
+ /**
44
+ * Flag used to determine if an open/close
45
+ * operation was cancelled. For example, if
46
+ * an app calls "menu.open" then disables the menu
47
+ * part way through the animation, then this would
48
+ * be considered a cancelled operation.
49
+ */
50
+ this.operationCancelled = false;
43
51
  this.isAnimating = false;
44
52
  this._isOpen = false;
45
53
  this.inheritedAttributes = {};
@@ -305,6 +313,15 @@ const Menu = class {
305
313
  this.beforeAnimation(shouldOpen);
306
314
  await this.loadAnimation();
307
315
  await this.startAnimation(shouldOpen, animated);
316
+ /**
317
+ * If the animation was cancelled then
318
+ * return false because the operation
319
+ * did not succeed.
320
+ */
321
+ if (this.operationCancelled) {
322
+ this.operationCancelled = false;
323
+ return false;
324
+ }
308
325
  this.afterAnimation(shouldOpen);
309
326
  return true;
310
327
  }
@@ -341,18 +358,23 @@ const Menu = class {
341
358
  const easingReverse = mode === 'ios' ? iosEasingReverse : mdEasingReverse;
342
359
  const ani = this.animation
343
360
  .direction(isReversed ? 'reverse' : 'normal')
344
- .easing(isReversed ? easingReverse : easing)
345
- .onFinish(() => {
346
- if (ani.getDirection() === 'reverse') {
347
- ani.direction('normal');
348
- }
349
- });
361
+ .easing(isReversed ? easingReverse : easing);
350
362
  if (animated) {
351
363
  await ani.play();
352
364
  }
353
365
  else {
354
366
  ani.play({ sync: true });
355
367
  }
368
+ /**
369
+ * We run this after the play invocation
370
+ * instead of using ani.onFinish so that
371
+ * multiple onFinish callbacks do not get
372
+ * run if an animation is played, stopped,
373
+ * and then played again.
374
+ */
375
+ if (ani.getDirection() === 'reverse') {
376
+ ani.direction('normal');
377
+ }
356
378
  }
357
379
  _isActive() {
358
380
  return !this.disabled && !this.isPaneVisible;
@@ -489,7 +511,6 @@ const Menu = class {
489
511
  }
490
512
  afterAnimation(isOpen) {
491
513
  var _a;
492
- helpers.assert(this.isAnimating, '_before() should be called while animating');
493
514
  // keep opening/closing the menu disabled for a touch more yet
494
515
  // only add listeners/css if it's enabled and isOpen
495
516
  // and only remove listeners/css if it's not open
@@ -548,10 +569,29 @@ const Menu = class {
548
569
  if (this.gesture) {
549
570
  this.gesture.enable(isActive && this.swipeGesture);
550
571
  }
551
- // Close menu immediately
552
- if (!isActive && this._isOpen) {
553
- // close if this menu is open, and should not be enabled
554
- this.forceClosing();
572
+ /**
573
+ * If the menu is disabled but it is still open
574
+ * then we should close the menu immediately.
575
+ * Additionally, if the menu is in the process
576
+ * of animating {open, close} and the menu is disabled
577
+ * then it should still be closed immediately.
578
+ */
579
+ if (!isActive) {
580
+ /**
581
+ * It is possible to disable the menu while
582
+ * it is mid-animation. When this happens, we
583
+ * need to set the operationCancelled flag
584
+ * so that this._setOpen knows to return false
585
+ * and not run the "afterAnimation" callback.
586
+ */
587
+ if (this.isAnimating) {
588
+ this.operationCancelled = true;
589
+ }
590
+ /**
591
+ * If the menu is disabled then we should
592
+ * forcibly close the menu even if it is open.
593
+ */
594
+ this.afterAnimation(false);
555
595
  }
556
596
  if (index$2.doc === null || index$2.doc === void 0 ? void 0 : index$2.doc.contains(this.el)) {
557
597
  /**
@@ -564,14 +604,6 @@ const Menu = class {
564
604
  index$1.menuController._setActiveMenu(this);
565
605
  }
566
606
  }
567
- helpers.assert(!this.isAnimating, 'can not be animating');
568
- }
569
- forceClosing() {
570
- helpers.assert(this._isOpen, 'menu cannot be closed');
571
- this.isAnimating = true;
572
- const ani = this.animation.direction('reverse');
573
- ani.play({ sync: true });
574
- this.afterAnimation(false);
575
607
  }
576
608
  render() {
577
609
  const { type, disabled, isPaneVisible, inheritedAttributes, side } = this;
@@ -14,10 +14,10 @@ const index$4 = require('./index-cc7dfb7c.js');
14
14
  const capacitor = require('./capacitor-2ffba62a.js');
15
15
  const overlays = require('./overlays-efc9d511.js');
16
16
  const theme = require('./theme-fbc56b3b.js');
17
- const index$5 = require('./index-acf6bdf0.js');
17
+ const index$5 = require('./index-fa649bd8.js');
18
18
  const ionicGlobal = require('./ionic-global-a71608df.js');
19
19
  const keyboard = require('./keyboard-38f2bb7b.js');
20
- const animation = require('./animation-2bb33618.js');
20
+ const animation = require('./animation-c8bdd3c7.js');
21
21
  const cubicBezier = require('./cubic-bezier-6b9222ad.js');
22
22
  const index$1 = require('./index-0ee995e4.js');
23
23
  const index = require('./index-306a7476.js');
@@ -8,7 +8,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
8
8
  const index = require('./index-14a4821e.js');
9
9
  const cubicBezier = require('./cubic-bezier-6b9222ad.js');
10
10
  const helpers = require('./helpers-ea4ccbcb.js');
11
- const index$1 = require('./index-acf6bdf0.js');
11
+ const index$1 = require('./index-fa649bd8.js');
12
12
  const ionicGlobal = require('./ionic-global-a71608df.js');
13
13
  const frameworkDelegate = require('./framework-delegate-c0873a6f.js');
14
14
 
@@ -135,7 +135,7 @@ const Nav = class {
135
135
  // We want to set this flag before any watch callbacks are manually called
136
136
  this.didLoad = true;
137
137
  this.rootChanged();
138
- this.gesture = (await Promise.resolve().then(function () { return require('./swipe-back-6c57d1df.js'); })).createSwipeBackGesture(this.el, this.canStart.bind(this), this.onStart.bind(this), this.onMove.bind(this), this.onEnd.bind(this));
138
+ this.gesture = (await Promise.resolve().then(function () { return require('./swipe-back-d0412fb6.js'); })).createSwipeBackGesture(this.el, this.canStart.bind(this), this.onStart.bind(this), this.onMove.bind(this), this.onEnd.bind(this));
139
139
  this.swipeGestureChanged();
140
140
  }
141
141
  connectedCallback() {
@@ -13,8 +13,8 @@ const index$1 = require('./index-cc7dfb7c.js');
13
13
  const overlays = require('./overlays-efc9d511.js');
14
14
  const ionicGlobal = require('./ionic-global-a71608df.js');
15
15
  const theme = require('./theme-fbc56b3b.js');
16
- const index$2 = require('./index-acf6bdf0.js');
17
- const animation = require('./animation-2bb33618.js');
16
+ const index$2 = require('./index-fa649bd8.js');
17
+ const animation = require('./animation-c8bdd3c7.js');
18
18
  require('./index-306a7476.js');
19
19
  require('./hardware-back-button-b67c8e75.js');
20
20
 
@@ -32,7 +32,10 @@ const Radio = class {
32
32
  }
33
33
  };
34
34
  this.onClick = () => {
35
- const { radioGroup, checked } = this;
35
+ const { radioGroup, checked, disabled } = this;
36
+ if (disabled) {
37
+ return;
38
+ }
36
39
  /**
37
40
  * The legacy control uses a native input inside
38
41
  * of the radio host, so we can set this.checked
@@ -232,7 +235,7 @@ const RadioGroup = class {
232
235
  * using the `name` attribute.
233
236
  */
234
237
  const selectedRadio = ev.target && ev.target.closest('ion-radio');
235
- if (selectedRadio) {
238
+ if (selectedRadio && selectedRadio.disabled === false) {
236
239
  const currentValue = this.value;
237
240
  const newValue = selectedRadio.value;
238
241
  if (newValue !== currentValue) {
@@ -11,7 +11,7 @@ const index$1 = require('./index-10873539.js');
11
11
  const helpers = require('./helpers-ea4ccbcb.js');
12
12
  const haptic = require('./haptic-c5f6b4d5.js');
13
13
  const ionicGlobal = require('./ionic-global-a71608df.js');
14
- const animation = require('./animation-2bb33618.js');
14
+ const animation = require('./animation-c8bdd3c7.js');
15
15
  const config = require('./config-d5882735.js');
16
16
  const index$2 = require('./index-d8d1fc0b.js');
17
17
  const spinnerConfigs = require('./spinner-configs-f7b5105b.js');
@@ -7,11 +7,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
7
7
 
8
8
  const index = require('./index-14a4821e.js');
9
9
  const keyboardController = require('./keyboard-controller-50beb83a.js');
10
- const keyboard = require('./keyboard-fd7db491.js');
11
10
  const theme = require('./theme-fbc56b3b.js');
12
11
  const ionicGlobal = require('./ionic-global-a71608df.js');
13
12
  const helpers = require('./helpers-ea4ccbcb.js');
14
13
  require('./index-306a7476.js');
14
+ require('./keyboard-fd7db491.js');
15
15
  require('./capacitor-2ffba62a.js');
16
16
 
17
17
  const tabBarIosCss = ":host{-webkit-padding-start:var(--ion-safe-area-left);padding-inline-start:var(--ion-safe-area-left);-webkit-padding-end:var(--ion-safe-area-right);padding-inline-end:var(--ion-safe-area-right);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-bottom:var(--ion-safe-area-bottom, 0);border-top:var(--border);background:var(--background);color:var(--color);text-align:center;contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:10;-webkit-box-sizing:content-box !important;box-sizing:content-box !important}:host(.ion-color) ::slotted(ion-tab-button){--background-focused:var(--ion-color-shade);--color-selected:var(--ion-color-contrast)}:host(.ion-color) ::slotted(.tab-selected){color:var(--ion-color-contrast)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){color:rgba(var(--ion-color-contrast-rgb), 0.7)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){background:var(--ion-color-base)}:host(.ion-color) ::slotted(ion-tab-button.ion-focused),:host(.tab-bar-translucent) ::slotted(ion-tab-button.ion-focused){background:var(--background-focused)}:host(.tab-bar-translucent) ::slotted(ion-tab-button){background:transparent}:host([slot=top]){padding-top:var(--ion-safe-area-top, 0);padding-bottom:0;border-top:0;border-bottom:var(--border)}:host(.tab-bar-hidden){display:none !important}:host{--background:var(--ion-tab-bar-background, var(--ion-color-step-50, #f7f7f7));--background-focused:var(--ion-tab-bar-background-focused, #e0e0e0);--border:0.55px solid var(--ion-tab-bar-border-color, var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, 0.2))));--color:var(--ion-tab-bar-color, var(--ion-color-step-600, #666666));--color-selected:var(--ion-tab-bar-color-selected, var(--ion-color-primary, #3880ff));height:50px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.tab-bar-translucent){--background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(210%) blur(20px);backdrop-filter:saturate(210%) blur(20px)}:host(.ion-color.tab-bar-translucent){background:rgba(var(--ion-color-base-rgb), 0.8)}:host(.tab-bar-translucent) ::slotted(ion-tab-button.ion-focused){background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.6)}}";
@@ -40,26 +40,17 @@ const TabBar = class {
40
40
  this.selectedTabChanged();
41
41
  }
42
42
  async connectedCallback() {
43
- const resizeMode = await keyboard.Keyboard.getResizeMode();
44
- /**
45
- * If the resize mode is set to None then we don't want to
46
- * hide the tab bar here since it will never sit on top
47
- * of the keyboard. Hiding the tab bar will cause a layout shift
48
- * in apps that have resize set to None.
49
- */
50
- if (resizeMode === undefined || resizeMode.mode !== keyboard.KeyboardResize.None) {
51
- this.keyboardCtrl = await keyboardController.createKeyboardController(async (keyboardOpen, waitForResize) => {
52
- /**
53
- * If the keyboard is hiding, then we need to wait
54
- * for the webview to resize. Otherwise, the tab bar
55
- * will flicker before the webview resizes.
56
- */
57
- if (keyboardOpen === false && waitForResize !== undefined) {
58
- await waitForResize;
59
- }
60
- this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
61
- });
62
- }
43
+ this.keyboardCtrl = await keyboardController.createKeyboardController(async (keyboardOpen, waitForResize) => {
44
+ /**
45
+ * If the keyboard is hiding, then we need to wait
46
+ * for the webview to resize. Otherwise, the tab bar
47
+ * will flicker before the webview resizes.
48
+ */
49
+ if (keyboardOpen === false && waitForResize !== undefined) {
50
+ await waitForResize;
51
+ }
52
+ this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
53
+ });
63
54
  }
64
55
  disconnectedCallback() {
65
56
  if (this.keyboardCtrl) {
@@ -13,7 +13,7 @@ const index$1 = require('./index-cc7dfb7c.js');
13
13
  const overlays = require('./overlays-efc9d511.js');
14
14
  const theme = require('./theme-fbc56b3b.js');
15
15
  const ionicGlobal = require('./ionic-global-a71608df.js');
16
- const animation = require('./animation-2bb33618.js');
16
+ const animation = require('./animation-c8bdd3c7.js');
17
17
  require('./index-306a7476.js');
18
18
  require('./framework-delegate-c0873a6f.js');
19
19
  require('./hardware-back-button-b67c8e75.js');
@@ -51,6 +51,9 @@ const Toggle = class {
51
51
  }
52
52
  };
53
53
  this.onClick = (ev) => {
54
+ if (this.disabled) {
55
+ return;
56
+ }
54
57
  ev.preventDefault();
55
58
  if (this.lastDrag + 300 < Date.now()) {
56
59
  this.toggleChecked();
@@ -3,8 +3,8 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
- const animation = require('./animation-2bb33618.js');
7
- const index = require('./index-acf6bdf0.js');
6
+ const animation = require('./animation-c8bdd3c7.js');
7
+ const index = require('./index-fa649bd8.js');
8
8
  require('./index-306a7476.js');
9
9
  require('./helpers-ea4ccbcb.js');
10
10
  require('./index-14a4821e.js');
@@ -3,8 +3,8 @@
3
3
  */
4
4
  'use strict';
5
5
 
6
- const animation = require('./animation-2bb33618.js');
7
- const index = require('./index-acf6bdf0.js');
6
+ const animation = require('./animation-c8bdd3c7.js');
7
+ const index = require('./index-fa649bd8.js');
8
8
  require('./index-306a7476.js');
9
9
  require('./helpers-ea4ccbcb.js');
10
10
  require('./index-14a4821e.js');
@@ -65,7 +65,11 @@ const createSwipeBackGesture = (el, canStartHandler, onStartHandler, onMoveHandl
65
65
  return index.createGesture({
66
66
  el,
67
67
  gestureName: 'goback-swipe',
68
- gesturePriority: 40,
68
+ /**
69
+ * Swipe to go back should have priority over other horizontal swipe
70
+ * gestures. These gestures have a priority of 100 which is why 101 was chosen here.
71
+ */
72
+ gesturePriority: 101,
69
73
  threshold: 10,
70
74
  canStart,
71
75
  onStart: onStartHandler,
@@ -48,6 +48,9 @@ export class Checkbox {
48
48
  this.ionBlur.emit();
49
49
  };
50
50
  this.onClick = (ev) => {
51
+ if (this.disabled) {
52
+ return;
53
+ }
51
54
  this.toggleChecked(ev);
52
55
  };
53
56
  this.color = undefined;
@@ -4,7 +4,6 @@
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { findIonContent, getScrollElement, printIonContentErrorMsg } from "../../utils/content/index";
6
6
  import { createKeyboardController } from "../../utils/keyboard/keyboard-controller";
7
- import { Keyboard, KeyboardResize } from "../../utils/native/keyboa";
8
7
  import { getIonMode } from "../../global/ionic-global";
9
8
  import { handleFooterFade } from "./footer.utils";
10
9
  /**
@@ -53,26 +52,17 @@ export class Footer {
53
52
  this.checkCollapsibleFooter();
54
53
  }
55
54
  async connectedCallback() {
56
- const resizeMode = await Keyboard.getResizeMode();
57
- /**
58
- * If the resize mode is set to None then we don't want to
59
- * hide the tab bar here since it will never sit on top
60
- * of the keyboard. Hiding the tab bar will cause a layout shift
61
- * in apps that have resize set to None.
62
- */
63
- if (resizeMode === undefined || resizeMode.mode !== KeyboardResize.None) {
64
- this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
65
- /**
66
- * If the keyboard is hiding, then we need to wait
67
- * for the webview to resize. Otherwise, the footer
68
- * will flicker before the webview resizes.
69
- */
70
- if (keyboardOpen === false && waitForResize !== undefined) {
71
- await waitForResize;
72
- }
73
- this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
74
- });
75
- }
55
+ this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
56
+ /**
57
+ * If the keyboard is hiding, then we need to wait
58
+ * for the webview to resize. Otherwise, the footer
59
+ * will flicker before the webview resizes.
60
+ */
61
+ if (keyboardOpen === false && waitForResize !== undefined) {
62
+ await waitForResize;
63
+ }
64
+ this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
65
+ });
76
66
  }
77
67
  disconnectedCallback() {
78
68
  if (this.keyboardCtrl) {
@@ -24,6 +24,14 @@ export class Menu {
24
24
  this.lastOnEnd = 0;
25
25
  this.blocker = GESTURE_CONTROLLER.createBlocker({ disableScroll: true });
26
26
  this.didLoad = false;
27
+ /**
28
+ * Flag used to determine if an open/close
29
+ * operation was cancelled. For example, if
30
+ * an app calls "menu.open" then disables the menu
31
+ * part way through the animation, then this would
32
+ * be considered a cancelled operation.
33
+ */
34
+ this.operationCancelled = false;
27
35
  this.isAnimating = false;
28
36
  this._isOpen = false;
29
37
  this.inheritedAttributes = {};
@@ -292,6 +300,15 @@ export class Menu {
292
300
  this.beforeAnimation(shouldOpen);
293
301
  await this.loadAnimation();
294
302
  await this.startAnimation(shouldOpen, animated);
303
+ /**
304
+ * If the animation was cancelled then
305
+ * return false because the operation
306
+ * did not succeed.
307
+ */
308
+ if (this.operationCancelled) {
309
+ this.operationCancelled = false;
310
+ return false;
311
+ }
295
312
  this.afterAnimation(shouldOpen);
296
313
  return true;
297
314
  }
@@ -328,18 +345,23 @@ export class Menu {
328
345
  const easingReverse = mode === 'ios' ? iosEasingReverse : mdEasingReverse;
329
346
  const ani = this.animation
330
347
  .direction(isReversed ? 'reverse' : 'normal')
331
- .easing(isReversed ? easingReverse : easing)
332
- .onFinish(() => {
333
- if (ani.getDirection() === 'reverse') {
334
- ani.direction('normal');
335
- }
336
- });
348
+ .easing(isReversed ? easingReverse : easing);
337
349
  if (animated) {
338
350
  await ani.play();
339
351
  }
340
352
  else {
341
353
  ani.play({ sync: true });
342
354
  }
355
+ /**
356
+ * We run this after the play invocation
357
+ * instead of using ani.onFinish so that
358
+ * multiple onFinish callbacks do not get
359
+ * run if an animation is played, stopped,
360
+ * and then played again.
361
+ */
362
+ if (ani.getDirection() === 'reverse') {
363
+ ani.direction('normal');
364
+ }
343
365
  }
344
366
  _isActive() {
345
367
  return !this.disabled && !this.isPaneVisible;
@@ -476,7 +498,6 @@ export class Menu {
476
498
  }
477
499
  afterAnimation(isOpen) {
478
500
  var _a;
479
- assert(this.isAnimating, '_before() should be called while animating');
480
501
  // keep opening/closing the menu disabled for a touch more yet
481
502
  // only add listeners/css if it's enabled and isOpen
482
503
  // and only remove listeners/css if it's not open
@@ -535,10 +556,29 @@ export class Menu {
535
556
  if (this.gesture) {
536
557
  this.gesture.enable(isActive && this.swipeGesture);
537
558
  }
538
- // Close menu immediately
539
- if (!isActive && this._isOpen) {
540
- // close if this menu is open, and should not be enabled
541
- this.forceClosing();
559
+ /**
560
+ * If the menu is disabled but it is still open
561
+ * then we should close the menu immediately.
562
+ * Additionally, if the menu is in the process
563
+ * of animating {open, close} and the menu is disabled
564
+ * then it should still be closed immediately.
565
+ */
566
+ if (!isActive) {
567
+ /**
568
+ * It is possible to disable the menu while
569
+ * it is mid-animation. When this happens, we
570
+ * need to set the operationCancelled flag
571
+ * so that this._setOpen knows to return false
572
+ * and not run the "afterAnimation" callback.
573
+ */
574
+ if (this.isAnimating) {
575
+ this.operationCancelled = true;
576
+ }
577
+ /**
578
+ * If the menu is disabled then we should
579
+ * forcibly close the menu even if it is open.
580
+ */
581
+ this.afterAnimation(false);
542
582
  }
543
583
  if (doc === null || doc === void 0 ? void 0 : doc.contains(this.el)) {
544
584
  /**
@@ -551,14 +591,6 @@ export class Menu {
551
591
  menuController._setActiveMenu(this);
552
592
  }
553
593
  }
554
- assert(!this.isAnimating, 'can not be animating');
555
- }
556
- forceClosing() {
557
- assert(this._isOpen, 'menu cannot be closed');
558
- this.isAnimating = true;
559
- const ani = this.animation.direction('reverse');
560
- ani.play({ sync: true });
561
- this.afterAnimation(false);
562
594
  }
563
595
  render() {
564
596
  const { type, disabled, isPaneVisible, inheritedAttributes, side } = this;
@@ -0,0 +1,55 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { expect } from "@playwright/test";
5
+ import { configs, test } from "../../../../utils/test/playwright/index";
6
+ /**
7
+ * This behavior does not vary across modes/directions
8
+ */
9
+ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
10
+ test.describe(title('menu: disable'), () => {
11
+ test.beforeEach(async ({ page }) => {
12
+ await page.goto(`/src/components/menu/test/disable`, config);
13
+ });
14
+ test('should disable when menu is fully open', async ({ page }) => {
15
+ const logs = [];
16
+ page.on('console', (msg) => {
17
+ if (msg.type() === 'error') {
18
+ logs.push(msg.text());
19
+ }
20
+ });
21
+ const menu = page.locator('ion-menu');
22
+ // Should be visible on initial presentation
23
+ await menu.evaluate((el) => el.open());
24
+ await expect(menu).toBeVisible();
25
+ // Disabling menu should hide it
26
+ await menu.evaluate((el) => (el.disabled = true));
27
+ await expect(menu).toBeHidden();
28
+ // Re-enabling menu and opening it show make it visible
29
+ await menu.evaluate((el) => (el.disabled = false));
30
+ await menu.evaluate((el) => el.open());
31
+ await expect(menu).toBeVisible();
32
+ expect(logs.length).toBe(0);
33
+ });
34
+ test('should disable when menu is animating', async ({ page }) => {
35
+ const logs = [];
36
+ page.on('console', (msg) => {
37
+ if (msg.type() === 'error') {
38
+ logs.push(msg.text());
39
+ }
40
+ });
41
+ const menu = page.locator('ion-menu');
42
+ // Opening and quickly disabling menu should hide it
43
+ menu.evaluate((el) => {
44
+ el.open();
45
+ setTimeout(() => (el.disabled = true), 0);
46
+ });
47
+ await expect(menu).toBeHidden();
48
+ // Re-enabling menu and opening it show make it visible
49
+ await menu.evaluate((el) => (el.disabled = false));
50
+ await menu.evaluate((el) => el.open());
51
+ await expect(menu).toBeVisible();
52
+ expect(logs.length).toBe(0);
53
+ });
54
+ });
55
+ });
@@ -27,7 +27,10 @@ export class Radio {
27
27
  }
28
28
  };
29
29
  this.onClick = () => {
30
- const { radioGroup, checked } = this;
30
+ const { radioGroup, checked, disabled } = this;
31
+ if (disabled) {
32
+ return;
33
+ }
31
34
  /**
32
35
  * The legacy control uses a native input inside
33
36
  * of the radio host, so we can set this.checked
@@ -33,7 +33,7 @@ export class RadioGroup {
33
33
  * using the `name` attribute.
34
34
  */
35
35
  const selectedRadio = ev.target && ev.target.closest('ion-radio');
36
- if (selectedRadio) {
36
+ if (selectedRadio && selectedRadio.disabled === false) {
37
37
  const currentValue = this.value;
38
38
  const newValue = selectedRadio.value;
39
39
  if (newValue !== currentValue) {
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import { Host, h } from "@stencil/core";
5
5
  import { createKeyboardController } from "../../utils/keyboard/keyboard-controller";
6
- import { Keyboard, KeyboardResize } from "../../utils/native/keyboa";
7
6
  import { createColorClasses } from "../../utils/theme";
8
7
  import { getIonMode } from "../../global/ionic-global";
9
8
  /**
@@ -28,26 +27,17 @@ export class TabBar {
28
27
  this.selectedTabChanged();
29
28
  }
30
29
  async connectedCallback() {
31
- const resizeMode = await Keyboard.getResizeMode();
32
- /**
33
- * If the resize mode is set to None then we don't want to
34
- * hide the tab bar here since it will never sit on top
35
- * of the keyboard. Hiding the tab bar will cause a layout shift
36
- * in apps that have resize set to None.
37
- */
38
- if (resizeMode === undefined || resizeMode.mode !== KeyboardResize.None) {
39
- this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
40
- /**
41
- * If the keyboard is hiding, then we need to wait
42
- * for the webview to resize. Otherwise, the tab bar
43
- * will flicker before the webview resizes.
44
- */
45
- if (keyboardOpen === false && waitForResize !== undefined) {
46
- await waitForResize;
47
- }
48
- this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
49
- });
50
- }
30
+ this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
31
+ /**
32
+ * If the keyboard is hiding, then we need to wait
33
+ * for the webview to resize. Otherwise, the tab bar
34
+ * will flicker before the webview resizes.
35
+ */
36
+ if (keyboardOpen === false && waitForResize !== undefined) {
37
+ await waitForResize;
38
+ }
39
+ this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
40
+ });
51
41
  }
52
42
  disconnectedCallback() {
53
43
  if (this.keyboardCtrl) {
@@ -44,6 +44,9 @@ export class Toggle {
44
44
  }
45
45
  };
46
46
  this.onClick = (ev) => {
47
+ if (this.disabled) {
48
+ return;
49
+ }
47
50
  ev.preventDefault();
48
51
  if (this.lastDrag + 300 < Date.now()) {
49
52
  this.toggleChecked();