@ionic/core 8.7.17-dev.11767895575.16ea7cef → 8.7.17-dev.11767897190.1ef0f479
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.
- package/components/content.js +96 -8
- package/components/ion-tab-bar.js +3 -23
- package/components/modal.js +213 -12
- package/components/popover.js +83 -11
- package/dist/cjs/ion-app_8.cjs.entry.js +107 -20
- package/dist/cjs/ion-modal.cjs.entry.js +213 -12
- package/dist/cjs/ion-popover.cjs.entry.js +83 -11
- package/dist/cjs/ion-tab-bar_2.cjs.entry.js +3 -23
- package/dist/collection/components/content/content.css +10 -0
- package/dist/collection/components/content/content.js +94 -6
- package/dist/collection/components/modal/gestures/sheet.js +3 -1
- package/dist/collection/components/modal/gestures/swipe-to-close.js +3 -1
- package/dist/collection/components/modal/modal.ios.css +0 -4
- package/dist/collection/components/modal/modal.js +205 -7
- package/dist/collection/components/modal/modal.md.css +0 -4
- package/dist/collection/components/popover/animations/ios.enter.js +21 -5
- package/dist/collection/components/popover/animations/md.enter.js +30 -5
- package/dist/collection/components/popover/utils.js +32 -1
- package/dist/collection/components/tab-bar/tab-bar.js +3 -23
- package/dist/docs.json +1 -1
- package/dist/esm/ion-app_8.entry.js +96 -9
- package/dist/esm/ion-modal.entry.js +213 -12
- package/dist/esm/ion-popover.entry.js +83 -11
- package/dist/esm/ion-tab-bar_2.entry.js +3 -23
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-7268efa5.entry.js +4 -0
- package/dist/ionic/p-968a55d1.entry.js +4 -0
- package/dist/ionic/p-d9fd799f.entry.js +4 -0
- package/dist/ionic/p-ec9ca3fe.entry.js +4 -0
- package/dist/types/components/content/content.d.ts +24 -0
- package/dist/types/components/modal/gestures/sheet.d.ts +1 -1
- package/dist/types/components/modal/gestures/swipe-to-close.d.ts +1 -1
- package/dist/types/components/modal/modal.d.ts +45 -0
- package/dist/types/components/popover/utils.d.ts +2 -0
- package/dist/types/components/tab-bar/tab-bar.d.ts +0 -1
- package/hydrate/index.js +385 -52
- package/hydrate/index.mjs +385 -52
- package/package.json +1 -1
- package/dist/ionic/p-172a579f.entry.js +0 -4
- package/dist/ionic/p-732b2fd6.entry.js +0 -4
- package/dist/ionic/p-91840a80.entry.js +0 -4
- package/dist/ionic/p-f9061316.entry.js +0 -4
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* (C) Ionic http://ionicframework.com - MIT License
|
|
3
3
|
*/
|
|
4
4
|
import { r as registerInstance, c as createEvent, f as printIonWarning, w as writeTask, e as config, h, d as Host, g as getElement } from './index-C8IsBmNU.js';
|
|
5
|
+
import { w as win } from './index-ZjP4CjeZ.js';
|
|
5
6
|
import { f as findClosestIonContent, i as isIonContent, d as disableContentScrollY, r as resetContentScrollY, a as findIonContent, p as printIonContentErrorMsg } from './index-Bs3kT4bc.js';
|
|
6
7
|
import { C as CoreDelegate, a as attachComponent, d as detachComponent } from './framework-delegate-BYawdMXj.js';
|
|
7
8
|
import { e as clamp, g as getElementRoot, r as raf, b as inheritAttributes, h as hasLazyBuild } from './helpers-DEn3pfjm.js';
|
|
@@ -15,7 +16,6 @@ import { KEYBOARD_DID_OPEN } from './keyboard-ywgs5efA.js';
|
|
|
15
16
|
import { c as createAnimation } from './animation-Dt8bGnA-.js';
|
|
16
17
|
import { g as getTimeGivenProgression } from './cubic-bezier-hHmYLOfE.js';
|
|
17
18
|
import { createGesture } from './index-CfgBF1SE.js';
|
|
18
|
-
import { w as win } from './index-ZjP4CjeZ.js';
|
|
19
19
|
import './hardware-back-button-CPLxO-Ev.js';
|
|
20
20
|
import './gesture-controller-BTEOs1at.js';
|
|
21
21
|
import './keyboard-CUw4ekVy.js';
|
|
@@ -247,7 +247,7 @@ const calculateSpringStep = (t) => {
|
|
|
247
247
|
const SwipeToCloseDefaults = {
|
|
248
248
|
MIN_PRESENTING_SCALE: 0.915,
|
|
249
249
|
};
|
|
250
|
-
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
250
|
+
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onGestureMove) => {
|
|
251
251
|
/**
|
|
252
252
|
* The step value at which a card modal
|
|
253
253
|
* is eligible for dismissing via gesture.
|
|
@@ -404,6 +404,8 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) =>
|
|
|
404
404
|
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
|
|
405
405
|
const clampedStep = clamp(0.0001, processedStep, maxStep);
|
|
406
406
|
animation.progressStep(clampedStep);
|
|
407
|
+
// Notify modal of position change for safe-area updates
|
|
408
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
407
409
|
/**
|
|
408
410
|
* When swiping down half way, the status bar style
|
|
409
411
|
* should be reset to its default value.
|
|
@@ -947,7 +949,7 @@ const mdLeaveAnimation = (baseEl, opts) => {
|
|
|
947
949
|
return baseAnimation;
|
|
948
950
|
};
|
|
949
951
|
|
|
950
|
-
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
|
|
952
|
+
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onGestureMove) => {
|
|
951
953
|
// Defaults for the sheet swipe animation
|
|
952
954
|
const defaultBackdrop = [
|
|
953
955
|
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
|
|
@@ -1278,6 +1280,8 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1278
1280
|
: step;
|
|
1279
1281
|
offset = clamp(0.0001, processedStep, maxStep);
|
|
1280
1282
|
animation.progressStep(offset);
|
|
1283
|
+
// Notify modal of position change for safe-area updates
|
|
1284
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
1281
1285
|
};
|
|
1282
1286
|
const onEnd = (detail) => {
|
|
1283
1287
|
/**
|
|
@@ -1472,9 +1476,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1472
1476
|
};
|
|
1473
1477
|
};
|
|
1474
1478
|
|
|
1475
|
-
const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px
|
|
1479
|
+
const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}";
|
|
1476
1480
|
|
|
1477
|
-
const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px
|
|
1481
|
+
const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}";
|
|
1478
1482
|
|
|
1479
1483
|
const Modal = class {
|
|
1480
1484
|
constructor(hostRef) {
|
|
@@ -1497,6 +1501,10 @@ const Modal = class {
|
|
|
1497
1501
|
this.inline = false;
|
|
1498
1502
|
// Whether or not modal is being dismissed via gesture
|
|
1499
1503
|
this.gestureAnimationDismissing = false;
|
|
1504
|
+
// Whether to skip coordinate-based safe-area detection (for fullscreen phone modals)
|
|
1505
|
+
this.skipSafeAreaCoordinateDetection = false;
|
|
1506
|
+
// Track previous safe-area state to avoid redundant DOM writes
|
|
1507
|
+
this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
|
|
1500
1508
|
this.presented = false;
|
|
1501
1509
|
/** @internal */
|
|
1502
1510
|
this.hasController = false;
|
|
@@ -1687,7 +1695,10 @@ const Modal = class {
|
|
|
1687
1695
|
}
|
|
1688
1696
|
}
|
|
1689
1697
|
onWindowResize() {
|
|
1690
|
-
//
|
|
1698
|
+
// Invalidate safe-area cache on resize (device rotation may change values)
|
|
1699
|
+
this.cachedSafeAreas = undefined;
|
|
1700
|
+
this.updateSafeAreaOverrides();
|
|
1701
|
+
// Only handle view transition for iOS card modals when no custom animations are provided
|
|
1691
1702
|
if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
1692
1703
|
return;
|
|
1693
1704
|
}
|
|
@@ -1710,6 +1721,8 @@ const Modal = class {
|
|
|
1710
1721
|
this.triggerController.removeClickListener();
|
|
1711
1722
|
this.cleanupViewTransitionListener();
|
|
1712
1723
|
this.cleanupParentRemovalObserver();
|
|
1724
|
+
// Reset safe-area state to handle removal without dismiss (e.g., framework unmount)
|
|
1725
|
+
this.resetSafeAreaState();
|
|
1713
1726
|
}
|
|
1714
1727
|
componentWillLoad() {
|
|
1715
1728
|
var _a;
|
|
@@ -1869,6 +1882,8 @@ const Modal = class {
|
|
|
1869
1882
|
else if (!this.keepContentsMounted) {
|
|
1870
1883
|
await waitForMount();
|
|
1871
1884
|
}
|
|
1885
|
+
// Predict safe-area needs based on modal configuration to avoid visual snap
|
|
1886
|
+
this.setInitialSafeAreaOverrides(presentingElement);
|
|
1872
1887
|
writeTask(() => this.el.classList.add('show-modal'));
|
|
1873
1888
|
const hasCardModal = presentingElement !== undefined;
|
|
1874
1889
|
/**
|
|
@@ -1930,6 +1945,8 @@ const Modal = class {
|
|
|
1930
1945
|
else if (hasCardModal) {
|
|
1931
1946
|
this.initSwipeToClose();
|
|
1932
1947
|
}
|
|
1948
|
+
// Now that animation is complete, update safe-area based on actual position
|
|
1949
|
+
this.updateSafeAreaOverrides();
|
|
1933
1950
|
// Initialize view transition listener for iOS card modals
|
|
1934
1951
|
this.initViewTransitionListener();
|
|
1935
1952
|
// Initialize parent removal observer
|
|
@@ -1981,7 +1998,7 @@ const Modal = class {
|
|
|
1981
1998
|
await this.dismiss(undefined, GESTURE);
|
|
1982
1999
|
this.gestureAnimationDismissing = false;
|
|
1983
2000
|
});
|
|
1984
|
-
});
|
|
2001
|
+
}, () => this.updateSafeAreaOverrides());
|
|
1985
2002
|
this.gesture.enable(true);
|
|
1986
2003
|
}
|
|
1987
2004
|
initSheetGesture() {
|
|
@@ -2002,7 +2019,8 @@ const Modal = class {
|
|
|
2002
2019
|
this.currentBreakpoint = breakpoint;
|
|
2003
2020
|
this.ionBreakpointDidChange.emit({ breakpoint });
|
|
2004
2021
|
}
|
|
2005
|
-
|
|
2022
|
+
this.updateSafeAreaOverrides();
|
|
2023
|
+
}, () => this.updateSafeAreaOverrides());
|
|
2006
2024
|
this.gesture = gesture;
|
|
2007
2025
|
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
|
|
2008
2026
|
this.gesture.enable(true);
|
|
@@ -2080,6 +2098,187 @@ const Modal = class {
|
|
|
2080
2098
|
// Clear the cached reference
|
|
2081
2099
|
this.cachedPageParent = undefined;
|
|
2082
2100
|
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Sets initial safe-area overrides based on modal configuration before
|
|
2103
|
+
* the modal becomes visible. This predicts whether the modal will touch
|
|
2104
|
+
* screen edges to avoid a visual snap after animation completes.
|
|
2105
|
+
*/
|
|
2106
|
+
setInitialSafeAreaOverrides(presentingElement) {
|
|
2107
|
+
const style = this.el.style;
|
|
2108
|
+
const mode = getIonMode(this);
|
|
2109
|
+
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2110
|
+
// Card modals only exist in iOS mode - in MD mode, presentingElement is ignored
|
|
2111
|
+
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2112
|
+
const isTablet = window.innerWidth >= 768;
|
|
2113
|
+
// Sheet modals always touch bottom edge, never top/left/right
|
|
2114
|
+
if (isSheetModal) {
|
|
2115
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2116
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2117
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2118
|
+
return;
|
|
2119
|
+
}
|
|
2120
|
+
// Card modals have rounded top corners
|
|
2121
|
+
if (isCardModal) {
|
|
2122
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2123
|
+
if (isTablet) {
|
|
2124
|
+
// On tablets, card modals are inset from all edges
|
|
2125
|
+
this.zeroAllSafeAreas();
|
|
2126
|
+
}
|
|
2127
|
+
else {
|
|
2128
|
+
// On phones, card modals still extend to the bottom edge
|
|
2129
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2130
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2131
|
+
this.applyFullscreenSafeArea();
|
|
2132
|
+
}
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
// Phone-sized fullscreen modals inherit safe areas and use wrapper padding
|
|
2136
|
+
if (!isTablet) {
|
|
2137
|
+
this.applyFullscreenSafeArea();
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
// Check if tablet modal is fullscreen via CSS custom properties
|
|
2141
|
+
const computedStyle = getComputedStyle(this.el);
|
|
2142
|
+
const width = computedStyle.getPropertyValue('--width').trim();
|
|
2143
|
+
const height = computedStyle.getPropertyValue('--height').trim();
|
|
2144
|
+
const isFullscreen = width === '100%' && height === '100%';
|
|
2145
|
+
if (isFullscreen) {
|
|
2146
|
+
this.applyFullscreenSafeArea();
|
|
2147
|
+
}
|
|
2148
|
+
else {
|
|
2149
|
+
// Centered dialog doesn't touch edges
|
|
2150
|
+
this.zeroAllSafeAreas();
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
/**
|
|
2154
|
+
* Applies safe-area handling for fullscreen modals.
|
|
2155
|
+
* Adds wrapper padding when no footer is present to prevent
|
|
2156
|
+
* content from overlapping system navigation areas.
|
|
2157
|
+
*/
|
|
2158
|
+
applyFullscreenSafeArea() {
|
|
2159
|
+
this.skipSafeAreaCoordinateDetection = true;
|
|
2160
|
+
this.updateFooterPadding();
|
|
2161
|
+
// Watch for dynamic footer additions/removals (e.g., async data loading)
|
|
2162
|
+
// Use subtree:true to support wrapped footers in framework components
|
|
2163
|
+
// (e.g., <my-footer><ion-footer>...</ion-footer></my-footer>)
|
|
2164
|
+
if (!this.footerObserver && win !== undefined && 'MutationObserver' in win) {
|
|
2165
|
+
this.footerObserver = new MutationObserver(() => this.updateFooterPadding());
|
|
2166
|
+
this.footerObserver.observe(this.el, { childList: true, subtree: true });
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
/**
|
|
2170
|
+
* Updates wrapper padding based on footer presence.
|
|
2171
|
+
* Called initially and when footer is dynamically added/removed.
|
|
2172
|
+
*/
|
|
2173
|
+
updateFooterPadding() {
|
|
2174
|
+
if (!this.wrapperEl)
|
|
2175
|
+
return;
|
|
2176
|
+
const hasFooter = this.el.querySelector('ion-footer') !== null;
|
|
2177
|
+
if (hasFooter) {
|
|
2178
|
+
this.wrapperEl.style.removeProperty('padding-bottom');
|
|
2179
|
+
this.wrapperEl.style.removeProperty('box-sizing');
|
|
2180
|
+
}
|
|
2181
|
+
else {
|
|
2182
|
+
this.wrapperEl.style.setProperty('padding-bottom', 'var(--ion-safe-area-bottom, 0px)');
|
|
2183
|
+
this.wrapperEl.style.setProperty('box-sizing', 'border-box');
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Sets all safe-area CSS variables to 0px for modals that
|
|
2188
|
+
* don't touch screen edges.
|
|
2189
|
+
*/
|
|
2190
|
+
zeroAllSafeAreas() {
|
|
2191
|
+
const style = this.el.style;
|
|
2192
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2193
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2194
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2195
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2196
|
+
}
|
|
2197
|
+
/**
|
|
2198
|
+
* Resets all safe-area related state and styles.
|
|
2199
|
+
* Called during dismiss and disconnectedCallback to ensure clean state
|
|
2200
|
+
* for re-presentation of inline modals.
|
|
2201
|
+
*/
|
|
2202
|
+
resetSafeAreaState() {
|
|
2203
|
+
var _a;
|
|
2204
|
+
this.skipSafeAreaCoordinateDetection = false;
|
|
2205
|
+
this.cachedSafeAreas = undefined;
|
|
2206
|
+
this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
|
|
2207
|
+
(_a = this.footerObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
2208
|
+
this.footerObserver = undefined;
|
|
2209
|
+
// Clear wrapper styles that may have been set for safe-area handling
|
|
2210
|
+
if (this.wrapperEl) {
|
|
2211
|
+
this.wrapperEl.style.removeProperty('padding-bottom');
|
|
2212
|
+
this.wrapperEl.style.removeProperty('box-sizing');
|
|
2213
|
+
}
|
|
2214
|
+
// Clear safe-area CSS variable overrides
|
|
2215
|
+
const style = this.el.style;
|
|
2216
|
+
style.removeProperty('--ion-safe-area-top');
|
|
2217
|
+
style.removeProperty('--ion-safe-area-bottom');
|
|
2218
|
+
style.removeProperty('--ion-safe-area-left');
|
|
2219
|
+
style.removeProperty('--ion-safe-area-right');
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Gets the root safe-area values from the document element.
|
|
2223
|
+
* Uses cached values during gestures to avoid getComputedStyle calls.
|
|
2224
|
+
*/
|
|
2225
|
+
getSafeAreaValues() {
|
|
2226
|
+
if (!this.cachedSafeAreas) {
|
|
2227
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
2228
|
+
this.cachedSafeAreas = {
|
|
2229
|
+
top: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-top')) || 0,
|
|
2230
|
+
bottom: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-bottom')) || 0,
|
|
2231
|
+
left: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-left')) || 0,
|
|
2232
|
+
right: parseFloat(rootStyle.getPropertyValue('--ion-safe-area-right')) || 0,
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
return this.cachedSafeAreas;
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2239
|
+
* extends into each safe-area region. Called after animation
|
|
2240
|
+
* and during gestures to handle dynamic position changes.
|
|
2241
|
+
*
|
|
2242
|
+
* Optimized to avoid redundant DOM writes by tracking previous state.
|
|
2243
|
+
*/
|
|
2244
|
+
updateSafeAreaOverrides() {
|
|
2245
|
+
if (this.skipSafeAreaCoordinateDetection) {
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
const wrapper = this.wrapperEl;
|
|
2249
|
+
if (!wrapper) {
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
const rect = wrapper.getBoundingClientRect();
|
|
2253
|
+
const safeAreas = this.getSafeAreaValues();
|
|
2254
|
+
const extendsIntoTop = rect.top < safeAreas.top;
|
|
2255
|
+
const extendsIntoBottom = rect.bottom > window.innerHeight - safeAreas.bottom;
|
|
2256
|
+
const extendsIntoLeft = rect.left < safeAreas.left;
|
|
2257
|
+
const extendsIntoRight = rect.right > window.innerWidth - safeAreas.right;
|
|
2258
|
+
// Only update DOM when state actually changes
|
|
2259
|
+
const prev = this.prevSafeAreaState;
|
|
2260
|
+
const style = this.el.style;
|
|
2261
|
+
if (extendsIntoTop !== prev.top) {
|
|
2262
|
+
extendsIntoTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2263
|
+
prev.top = extendsIntoTop;
|
|
2264
|
+
}
|
|
2265
|
+
if (extendsIntoBottom !== prev.bottom) {
|
|
2266
|
+
extendsIntoBottom
|
|
2267
|
+
? style.removeProperty('--ion-safe-area-bottom')
|
|
2268
|
+
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2269
|
+
prev.bottom = extendsIntoBottom;
|
|
2270
|
+
}
|
|
2271
|
+
if (extendsIntoLeft !== prev.left) {
|
|
2272
|
+
extendsIntoLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2273
|
+
prev.left = extendsIntoLeft;
|
|
2274
|
+
}
|
|
2275
|
+
if (extendsIntoRight !== prev.right) {
|
|
2276
|
+
extendsIntoRight
|
|
2277
|
+
? style.removeProperty('--ion-safe-area-right')
|
|
2278
|
+
: style.setProperty('--ion-safe-area-right', '0px');
|
|
2279
|
+
prev.right = extendsIntoRight;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2083
2282
|
sheetOnDismiss() {
|
|
2084
2283
|
/**
|
|
2085
2284
|
* While the gesture animation is finishing
|
|
@@ -2172,6 +2371,8 @@ const Modal = class {
|
|
|
2172
2371
|
}
|
|
2173
2372
|
this.currentBreakpoint = undefined;
|
|
2174
2373
|
this.animation = undefined;
|
|
2374
|
+
// Reset safe-area state for potential re-presentation
|
|
2375
|
+
this.resetSafeAreaState();
|
|
2175
2376
|
unlock();
|
|
2176
2377
|
return dismissed;
|
|
2177
2378
|
}
|
|
@@ -2421,20 +2622,20 @@ const Modal = class {
|
|
|
2421
2622
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2422
2623
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2423
2624
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2424
|
-
return (h(Host, Object.assign({ key: '
|
|
2625
|
+
return (h(Host, Object.assign({ key: '44022099fcaf047b97d1c2cb45b9b51c930e707c', "no-router": true,
|
|
2425
2626
|
// Allow the modal to be navigable when the handle is focusable
|
|
2426
2627
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2427
2628
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2428
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '
|
|
2629
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: 'ddd7e4f6eef51ac1f62ac70e0af10fb01e707f07', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '58620980e3e4ec273c6787bde026e1c010b904b7', class: "modal-shadow" }), h("div", Object.assign({ key: '3fb7f6218644ba898fc504467775593eb89426a0',
|
|
2429
2630
|
/*
|
|
2430
2631
|
role and aria-modal must be used on the
|
|
2431
2632
|
same element. They must also be set inside the
|
|
2432
2633
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2433
2634
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2434
2635
|
*/
|
|
2435
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
2636
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '9745cd590fdaa9d023a14b487ec2c87ddbafd7f7', class: "modal-handle",
|
|
2436
2637
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2437
|
-
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '
|
|
2638
|
+
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'b9a8b5d2d3d3c9b06f99179f496c9f08907d0bad', onSlotchange: this.onSlotChange }))));
|
|
2438
2639
|
}
|
|
2439
2640
|
get el() { return getElement(this); }
|
|
2440
2641
|
static get watchers() { return {
|
|
@@ -658,6 +658,8 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
658
658
|
let bottom;
|
|
659
659
|
let originX = contentOriginX;
|
|
660
660
|
let originY = contentOriginY;
|
|
661
|
+
let checkSafeAreaTop = false;
|
|
662
|
+
let checkSafeAreaBottom = false;
|
|
661
663
|
let checkSafeAreaLeft = false;
|
|
662
664
|
let checkSafeAreaRight = false;
|
|
663
665
|
const triggerTop = triggerCoordinates
|
|
@@ -702,10 +704,18 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
702
704
|
* We chose 12 here so that the popover position looks a bit nicer as
|
|
703
705
|
* it is not right up against the edge of the screen.
|
|
704
706
|
*/
|
|
705
|
-
top = Math.max(
|
|
707
|
+
top = Math.max(bodyPadding, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
|
|
706
708
|
arrowTop = top + contentHeight;
|
|
707
709
|
originY = 'bottom';
|
|
708
710
|
addPopoverBottomClass = true;
|
|
711
|
+
/**
|
|
712
|
+
* If the popover is positioned near the top edge, account for safe area.
|
|
713
|
+
* This ensures the popover doesn't overlap with status bars or notches.
|
|
714
|
+
*/
|
|
715
|
+
if (top <= bodyPadding + safeAreaMargin) {
|
|
716
|
+
checkSafeAreaTop = true;
|
|
717
|
+
top = bodyPadding;
|
|
718
|
+
}
|
|
709
719
|
/**
|
|
710
720
|
* If not enough room for popover to appear
|
|
711
721
|
* above trigger, then cut it off.
|
|
@@ -713,14 +723,35 @@ const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyW
|
|
|
713
723
|
}
|
|
714
724
|
else {
|
|
715
725
|
bottom = bodyPadding;
|
|
726
|
+
/**
|
|
727
|
+
* When the popover is pinned to the bottom, account for safe area.
|
|
728
|
+
* This ensures the popover doesn't overlap with home indicators
|
|
729
|
+
* or navigation bars (e.g., Android API 36+ edge-to-edge).
|
|
730
|
+
*/
|
|
731
|
+
checkSafeAreaBottom = true;
|
|
716
732
|
}
|
|
717
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* Final check: If the popover extends into any safe-area region,
|
|
736
|
+
* ensure the corresponding flag is set regardless of side.
|
|
737
|
+
* This handles cases where a side-positioned popover (left/right)
|
|
738
|
+
* still needs bottom safe-area padding because it extends into that region.
|
|
739
|
+
*/
|
|
740
|
+
const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
|
|
741
|
+
if (popoverBottom + safeAreaMargin > bodyHeight) {
|
|
742
|
+
checkSafeAreaBottom = true;
|
|
743
|
+
}
|
|
744
|
+
if (top < safeAreaMargin) {
|
|
745
|
+
checkSafeAreaTop = true;
|
|
746
|
+
}
|
|
718
747
|
return {
|
|
719
748
|
top,
|
|
720
749
|
left,
|
|
721
750
|
bottom,
|
|
722
751
|
originX,
|
|
723
752
|
originY,
|
|
753
|
+
checkSafeAreaTop,
|
|
754
|
+
checkSafeAreaBottom,
|
|
724
755
|
checkSafeAreaLeft,
|
|
725
756
|
checkSafeAreaRight,
|
|
726
757
|
arrowTop,
|
|
@@ -781,7 +812,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
781
812
|
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, arrowWidth, arrowHeight, reference, side, align, defaultPosition, trigger, ev);
|
|
782
813
|
const padding = size === 'cover' ? 0 : POPOVER_IOS_BODY_PADDING;
|
|
783
814
|
const margin = size === 'cover' ? 0 : 25;
|
|
784
|
-
const { originX, originY, top, left, bottom, checkSafeAreaLeft, checkSafeAreaRight, arrowTop, arrowLeft, addPopoverBottomClass, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, margin, results.originX, results.originY, results.referenceCoordinates, results.arrowTop, results.arrowLeft, arrowHeight);
|
|
815
|
+
const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, arrowTop, arrowLeft, addPopoverBottomClass, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, margin, results.originX, results.originY, results.referenceCoordinates, results.arrowTop, results.arrowLeft, arrowHeight);
|
|
785
816
|
const baseAnimation = createAnimation();
|
|
786
817
|
const backdropAnimation = createAnimation();
|
|
787
818
|
const contentAnimation = createAnimation();
|
|
@@ -811,19 +842,35 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
811
842
|
if (addPopoverBottomClass) {
|
|
812
843
|
baseEl.classList.add('popover-bottom');
|
|
813
844
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
845
|
+
/**
|
|
846
|
+
* Safe area CSS variable adjustments.
|
|
847
|
+
* When the popover is positioned near an edge, we add the corresponding
|
|
848
|
+
* safe-area inset to ensure the popover doesn't overlap with system UI
|
|
849
|
+
* (status bars, home indicators, navigation bars on Android API 36+, etc.)
|
|
850
|
+
*/
|
|
851
|
+
const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
|
|
852
|
+
const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
|
|
817
853
|
const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
|
|
818
854
|
const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
|
|
855
|
+
let topValue = `${top}px`;
|
|
856
|
+
let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
|
|
819
857
|
let leftValue = `${left}px`;
|
|
858
|
+
if (checkSafeAreaTop) {
|
|
859
|
+
topValue = `${top}px${safeAreaTop}`;
|
|
860
|
+
}
|
|
861
|
+
if (checkSafeAreaBottom && bottomValue !== undefined) {
|
|
862
|
+
bottomValue = `${bottom}px${safeAreaBottom}`;
|
|
863
|
+
}
|
|
820
864
|
if (checkSafeAreaLeft) {
|
|
821
865
|
leftValue = `${left}px${safeAreaLeft}`;
|
|
822
866
|
}
|
|
823
867
|
if (checkSafeAreaRight) {
|
|
824
868
|
leftValue = `${left}px${safeAreaRight}`;
|
|
825
869
|
}
|
|
826
|
-
|
|
870
|
+
if (bottomValue !== undefined) {
|
|
871
|
+
contentEl.style.setProperty('bottom', `calc(${bottomValue})`);
|
|
872
|
+
}
|
|
873
|
+
contentEl.style.setProperty('top', `calc(${topValue} + var(--offset-y, 0))`);
|
|
827
874
|
contentEl.style.setProperty('left', `calc(${leftValue} + var(--offset-x, 0))`);
|
|
828
875
|
contentEl.style.setProperty('transform-origin', `${originY} ${originX}`);
|
|
829
876
|
if (arrowEl !== null) {
|
|
@@ -899,7 +946,32 @@ const mdEnterAnimation = (baseEl, opts) => {
|
|
|
899
946
|
};
|
|
900
947
|
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, 0, 0, reference, side, align, defaultPosition, trigger, ev);
|
|
901
948
|
const padding = size === 'cover' ? 0 : POPOVER_MD_BODY_PADDING;
|
|
902
|
-
const { originX, originY, top, left, bottom } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
|
|
949
|
+
const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
|
|
950
|
+
/**
|
|
951
|
+
* Safe area CSS variable adjustments.
|
|
952
|
+
* When the popover is positioned near an edge, we add the corresponding
|
|
953
|
+
* safe-area inset to ensure the popover doesn't overlap with system UI
|
|
954
|
+
* (status bars, home indicators, navigation bars on Android API 36+, etc.)
|
|
955
|
+
*/
|
|
956
|
+
const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
|
|
957
|
+
const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
|
|
958
|
+
const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
|
|
959
|
+
const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
|
|
960
|
+
let topValue = `${top}px`;
|
|
961
|
+
let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
|
|
962
|
+
let leftValue = `${left}px`;
|
|
963
|
+
if (checkSafeAreaTop) {
|
|
964
|
+
topValue = `${top}px${safeAreaTop}`;
|
|
965
|
+
}
|
|
966
|
+
if (checkSafeAreaBottom && bottomValue !== undefined) {
|
|
967
|
+
bottomValue = `${bottom}px${safeAreaBottom}`;
|
|
968
|
+
}
|
|
969
|
+
if (checkSafeAreaLeft) {
|
|
970
|
+
leftValue = `${left}px${safeAreaLeft}`;
|
|
971
|
+
}
|
|
972
|
+
if (checkSafeAreaRight) {
|
|
973
|
+
leftValue = `${left}px${safeAreaRight}`;
|
|
974
|
+
}
|
|
903
975
|
const baseAnimation = createAnimation();
|
|
904
976
|
const backdropAnimation = createAnimation();
|
|
905
977
|
const wrapperAnimation = createAnimation();
|
|
@@ -916,13 +988,13 @@ const mdEnterAnimation = (baseEl, opts) => {
|
|
|
916
988
|
contentAnimation
|
|
917
989
|
.addElement(contentEl)
|
|
918
990
|
.beforeStyles({
|
|
919
|
-
top: `calc(${
|
|
920
|
-
left: `calc(${
|
|
991
|
+
top: `calc(${topValue} + var(--offset-y, 0px))`,
|
|
992
|
+
left: `calc(${leftValue} + var(--offset-x, 0px))`,
|
|
921
993
|
'transform-origin': `${originY} ${originX}`,
|
|
922
994
|
})
|
|
923
995
|
.beforeAddWrite(() => {
|
|
924
|
-
if (
|
|
925
|
-
contentEl.style.setProperty('bottom',
|
|
996
|
+
if (bottomValue !== undefined) {
|
|
997
|
+
contentEl.style.setProperty('bottom', `calc(${bottomValue})`);
|
|
926
998
|
}
|
|
927
999
|
})
|
|
928
1000
|
.fromTo('transform', 'scale(0.8)', 'scale(1)');
|
|
@@ -20,7 +20,6 @@ const TabBar = class {
|
|
|
20
20
|
this.ionTabBarChanged = createEvent(this, "ionTabBarChanged", 7);
|
|
21
21
|
this.ionTabBarLoaded = createEvent(this, "ionTabBarLoaded", 7);
|
|
22
22
|
this.keyboardCtrl = null;
|
|
23
|
-
this.keyboardCtrlPromise = null;
|
|
24
23
|
this.didLoad = false;
|
|
25
24
|
this.keyboardVisible = false;
|
|
26
25
|
/**
|
|
@@ -56,7 +55,7 @@ const TabBar = class {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
async connectedCallback() {
|
|
59
|
-
|
|
58
|
+
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
|
|
60
59
|
/**
|
|
61
60
|
* If the keyboard is hiding, then we need to wait
|
|
62
61
|
* for the webview to resize. Otherwise, the tab bar
|
|
@@ -67,40 +66,21 @@ const TabBar = class {
|
|
|
67
66
|
}
|
|
68
67
|
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
|
|
69
68
|
});
|
|
70
|
-
this.keyboardCtrlPromise = promise;
|
|
71
|
-
const keyboardCtrl = await promise;
|
|
72
|
-
/**
|
|
73
|
-
* Only assign if this is still the current promise.
|
|
74
|
-
* Otherwise, a new connectedCallback has started or
|
|
75
|
-
* disconnectedCallback was called, so destroy this instance.
|
|
76
|
-
*/
|
|
77
|
-
if (this.keyboardCtrlPromise === promise) {
|
|
78
|
-
this.keyboardCtrl = keyboardCtrl;
|
|
79
|
-
this.keyboardCtrlPromise = null;
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
keyboardCtrl.destroy();
|
|
83
|
-
}
|
|
84
69
|
}
|
|
85
70
|
disconnectedCallback() {
|
|
86
|
-
if (this.keyboardCtrlPromise) {
|
|
87
|
-
this.keyboardCtrlPromise.then((ctrl) => ctrl.destroy());
|
|
88
|
-
this.keyboardCtrlPromise = null;
|
|
89
|
-
}
|
|
90
71
|
if (this.keyboardCtrl) {
|
|
91
72
|
this.keyboardCtrl.destroy();
|
|
92
|
-
this.keyboardCtrl = null;
|
|
93
73
|
}
|
|
94
74
|
}
|
|
95
75
|
render() {
|
|
96
76
|
const { color, translucent, keyboardVisible } = this;
|
|
97
77
|
const mode = getIonMode(this);
|
|
98
78
|
const shouldHide = keyboardVisible && this.el.getAttribute('slot') !== 'top';
|
|
99
|
-
return (h(Host, { key: '
|
|
79
|
+
return (h(Host, { key: '388ec37ce308035bab78d6c9a016bb616e9517a9', role: "tablist", "aria-hidden": shouldHide ? 'true' : null, class: createColorClasses(color, {
|
|
100
80
|
[mode]: true,
|
|
101
81
|
'tab-bar-translucent': translucent,
|
|
102
82
|
'tab-bar-hidden': shouldHide,
|
|
103
|
-
}) }, h("slot", { key: '
|
|
83
|
+
}) }, h("slot", { key: 'ce10ade2b86725e24f3254516483eeedd8ecb16a' })));
|
|
104
84
|
}
|
|
105
85
|
get el() { return getElement(this); }
|
|
106
86
|
static get watchers() { return {
|