@ionic/core 8.7.15-dev.11766421552.180757ca → 8.7.15-dev.11766778555.1415245b
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/header.js +1 -1
- package/components/modal.js +92 -11
- package/dist/cjs/ion-app_8.cjs.entry.js +1 -1
- package/dist/cjs/ion-modal.cjs.entry.js +92 -11
- package/dist/collection/components/header/header.md.css +1 -1
- 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 +84 -7
- package/dist/collection/components/modal/modal.md.css +0 -4
- package/dist/docs.json +1 -1
- package/dist/esm/ion-app_8.entry.js +1 -1
- package/dist/esm/ion-modal.entry.js +92 -11
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/{p-ea509e3c.entry.js → p-732b2fd6.entry.js} +1 -1
- package/dist/ionic/p-88b087a9.entry.js +4 -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 +12 -0
- package/hydrate/index.js +93 -12
- package/hydrate/index.mjs +93 -12
- package/package.json +1 -1
- package/dist/ionic/p-b28af559.entry.js +0 -4
package/components/header.js
CHANGED
|
@@ -241,7 +241,7 @@ const getRoleType = (isInsideMenu, isCondensed, mode) => {
|
|
|
241
241
|
|
|
242
242
|
const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
|
|
243
243
|
|
|
244
|
-
const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
|
|
244
|
+
const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-md.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
|
|
245
245
|
|
|
246
246
|
const Header = /*@__PURE__*/ proxyCustomElement(class Header extends HTMLElement {
|
|
247
247
|
constructor(registerHost) {
|
package/components/modal.js
CHANGED
|
@@ -246,7 +246,7 @@ const calculateSpringStep = (t) => {
|
|
|
246
246
|
const SwipeToCloseDefaults = {
|
|
247
247
|
MIN_PRESENTING_SCALE: 0.915,
|
|
248
248
|
};
|
|
249
|
-
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
249
|
+
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onGestureMove) => {
|
|
250
250
|
/**
|
|
251
251
|
* The step value at which a card modal
|
|
252
252
|
* is eligible for dismissing via gesture.
|
|
@@ -403,6 +403,8 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) =>
|
|
|
403
403
|
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
|
|
404
404
|
const clampedStep = clamp(0.0001, processedStep, maxStep);
|
|
405
405
|
animation.progressStep(clampedStep);
|
|
406
|
+
// Notify modal of position change for safe-area updates
|
|
407
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
406
408
|
/**
|
|
407
409
|
* When swiping down half way, the status bar style
|
|
408
410
|
* should be reset to its default value.
|
|
@@ -946,7 +948,7 @@ const mdLeaveAnimation = (baseEl, opts) => {
|
|
|
946
948
|
return baseAnimation;
|
|
947
949
|
};
|
|
948
950
|
|
|
949
|
-
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
|
|
951
|
+
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onGestureMove) => {
|
|
950
952
|
// Defaults for the sheet swipe animation
|
|
951
953
|
const defaultBackdrop = [
|
|
952
954
|
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
|
|
@@ -1277,6 +1279,8 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1277
1279
|
: step;
|
|
1278
1280
|
offset = clamp(0.0001, processedStep, maxStep);
|
|
1279
1281
|
animation.progressStep(offset);
|
|
1282
|
+
// Notify modal of position change for safe-area updates
|
|
1283
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
1280
1284
|
};
|
|
1281
1285
|
const onEnd = (detail) => {
|
|
1282
1286
|
/**
|
|
@@ -1471,9 +1475,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1471
1475
|
};
|
|
1472
1476
|
};
|
|
1473
1477
|
|
|
1474
|
-
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
|
|
1478
|
+
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}";
|
|
1475
1479
|
|
|
1476
|
-
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
|
|
1480
|
+
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}";
|
|
1477
1481
|
|
|
1478
1482
|
const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
1479
1483
|
constructor(registerHost) {
|
|
@@ -1690,7 +1694,9 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1690
1694
|
}
|
|
1691
1695
|
}
|
|
1692
1696
|
onWindowResize() {
|
|
1693
|
-
//
|
|
1697
|
+
// Update safe-area overrides for all modal types on resize
|
|
1698
|
+
this.updateSafeAreaOverrides();
|
|
1699
|
+
// Only handle view transition for iOS card modals when no custom animations are provided
|
|
1694
1700
|
if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
1695
1701
|
return;
|
|
1696
1702
|
}
|
|
@@ -1872,6 +1878,8 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1872
1878
|
else if (!this.keepContentsMounted) {
|
|
1873
1879
|
await waitForMount();
|
|
1874
1880
|
}
|
|
1881
|
+
// Predict safe-area needs based on modal configuration to avoid visual snap
|
|
1882
|
+
this.setInitialSafeAreaOverrides(presentingElement);
|
|
1875
1883
|
writeTask(() => this.el.classList.add('show-modal'));
|
|
1876
1884
|
const hasCardModal = presentingElement !== undefined;
|
|
1877
1885
|
/**
|
|
@@ -1933,6 +1941,8 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1933
1941
|
else if (hasCardModal) {
|
|
1934
1942
|
this.initSwipeToClose();
|
|
1935
1943
|
}
|
|
1944
|
+
// Now that animation is complete, update safe-area based on actual position
|
|
1945
|
+
this.updateSafeAreaOverrides();
|
|
1936
1946
|
// Initialize view transition listener for iOS card modals
|
|
1937
1947
|
this.initViewTransitionListener();
|
|
1938
1948
|
// Initialize parent removal observer
|
|
@@ -1984,7 +1994,7 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1984
1994
|
await this.dismiss(undefined, GESTURE);
|
|
1985
1995
|
this.gestureAnimationDismissing = false;
|
|
1986
1996
|
});
|
|
1987
|
-
});
|
|
1997
|
+
}, () => this.updateSafeAreaOverrides());
|
|
1988
1998
|
this.gesture.enable(true);
|
|
1989
1999
|
}
|
|
1990
2000
|
initSheetGesture() {
|
|
@@ -2005,7 +2015,8 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2005
2015
|
this.currentBreakpoint = breakpoint;
|
|
2006
2016
|
this.ionBreakpointDidChange.emit({ breakpoint });
|
|
2007
2017
|
}
|
|
2008
|
-
|
|
2018
|
+
this.updateSafeAreaOverrides();
|
|
2019
|
+
}, () => this.updateSafeAreaOverrides());
|
|
2009
2020
|
this.gesture = gesture;
|
|
2010
2021
|
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
|
|
2011
2022
|
this.gesture.enable(true);
|
|
@@ -2083,6 +2094,76 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2083
2094
|
// Clear the cached reference
|
|
2084
2095
|
this.cachedPageParent = undefined;
|
|
2085
2096
|
}
|
|
2097
|
+
/**
|
|
2098
|
+
* Sets initial safe-area overrides based on modal configuration before
|
|
2099
|
+
* the modal becomes visible. This predicts whether the modal will touch
|
|
2100
|
+
* screen edges to avoid a visual snap after animation completes.
|
|
2101
|
+
*/
|
|
2102
|
+
setInitialSafeAreaOverrides(presentingElement) {
|
|
2103
|
+
const style = this.el.style;
|
|
2104
|
+
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2105
|
+
const isCardModal = presentingElement !== undefined;
|
|
2106
|
+
const isTablet = window.innerWidth >= 768;
|
|
2107
|
+
// Sheet modals: always touch bottom, top depends on breakpoint
|
|
2108
|
+
if (isSheetModal) {
|
|
2109
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2110
|
+
// Don't override bottom - sheet always touches bottom
|
|
2111
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2112
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
// Card modals are inset from edges (rounded corners), no safe areas needed
|
|
2116
|
+
if (isCardModal) {
|
|
2117
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2118
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2119
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2120
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
// Phone modals are fullscreen, need all safe areas
|
|
2124
|
+
if (!isTablet) {
|
|
2125
|
+
// Don't set any overrides - inherit from :root
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
// Default tablet modal: centered dialog, no safe areas needed
|
|
2129
|
+
// Check for fullscreen override via CSS custom properties
|
|
2130
|
+
const computedStyle = getComputedStyle(this.el);
|
|
2131
|
+
const width = computedStyle.getPropertyValue('--width').trim();
|
|
2132
|
+
const height = computedStyle.getPropertyValue('--height').trim();
|
|
2133
|
+
if (width === '100%' && height === '100%') {
|
|
2134
|
+
// Fullscreen modal - need safe areas, don't override
|
|
2135
|
+
return;
|
|
2136
|
+
}
|
|
2137
|
+
// Centered dialog - zero out all safe areas
|
|
2138
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2139
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2140
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2141
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2142
|
+
}
|
|
2143
|
+
/**
|
|
2144
|
+
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2145
|
+
* is touching each edge of the viewport. This is called after animation
|
|
2146
|
+
* and during gestures to handle dynamic position changes.
|
|
2147
|
+
*/
|
|
2148
|
+
updateSafeAreaOverrides() {
|
|
2149
|
+
const wrapper = this.wrapperEl;
|
|
2150
|
+
if (!wrapper)
|
|
2151
|
+
return;
|
|
2152
|
+
const rect = wrapper.getBoundingClientRect();
|
|
2153
|
+
const threshold = 2; // Account for subpixel rendering
|
|
2154
|
+
const touchingTop = rect.top <= threshold;
|
|
2155
|
+
const touchingBottom = rect.bottom >= window.innerHeight - threshold;
|
|
2156
|
+
const touchingLeft = rect.left <= threshold;
|
|
2157
|
+
const touchingRight = rect.right >= window.innerWidth - threshold;
|
|
2158
|
+
// Remove override when touching edge (allow inheritance), set to 0 when not touching
|
|
2159
|
+
const style = this.el.style;
|
|
2160
|
+
touchingTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2161
|
+
touchingBottom
|
|
2162
|
+
? style.removeProperty('--ion-safe-area-bottom')
|
|
2163
|
+
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2164
|
+
touchingLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2165
|
+
touchingRight ? style.removeProperty('--ion-safe-area-right') : style.setProperty('--ion-safe-area-right', '0px');
|
|
2166
|
+
}
|
|
2086
2167
|
sheetOnDismiss() {
|
|
2087
2168
|
/**
|
|
2088
2169
|
* While the gesture animation is finishing
|
|
@@ -2420,20 +2501,20 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
2420
2501
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2421
2502
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2422
2503
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2423
|
-
return (h(Host, Object.assign({ key: '
|
|
2504
|
+
return (h(Host, Object.assign({ key: 'e80cac8f52f1056eaf63112eafcfdcd029aa31e8', "no-router": true,
|
|
2424
2505
|
// Allow the modal to be navigable when the handle is focusable
|
|
2425
2506
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2426
2507
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2427
|
-
}, 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: '
|
|
2508
|
+
}, 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: 'dcc24085006dd1e41c47a55031d78bd55ddeb622', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '74c4ff6bdc87f8c29ee8ba0592c97db2c597d876', class: "modal-shadow" }), h("div", Object.assign({ key: '79f3b01bdadc0d830e5707026aa2055d62714274',
|
|
2428
2509
|
/*
|
|
2429
2510
|
role and aria-modal must be used on the
|
|
2430
2511
|
same element. They must also be set inside the
|
|
2431
2512
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2432
2513
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2433
2514
|
*/
|
|
2434
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
2515
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: 'b250920bad86e23269f900353d531975a95662af', class: "modal-handle",
|
|
2435
2516
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2436
|
-
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: '
|
|
2517
|
+
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: '2ba83c0f0a92784cac127c6581f12ea06b201b97', onSlotchange: this.onSlotChange }))));
|
|
2437
2518
|
}
|
|
2438
2519
|
get el() { return this; }
|
|
2439
2520
|
static get watchers() { return {
|
|
@@ -952,7 +952,7 @@ const getRoleType = (isInsideMenu, isCondensed, mode) => {
|
|
|
952
952
|
|
|
953
953
|
const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
|
|
954
954
|
|
|
955
|
-
const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
|
|
955
|
+
const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-md.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
|
|
956
956
|
|
|
957
957
|
const Header = class {
|
|
958
958
|
constructor(hostRef) {
|
|
@@ -249,7 +249,7 @@ const calculateSpringStep = (t) => {
|
|
|
249
249
|
const SwipeToCloseDefaults = {
|
|
250
250
|
MIN_PRESENTING_SCALE: 0.915,
|
|
251
251
|
};
|
|
252
|
-
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
252
|
+
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onGestureMove) => {
|
|
253
253
|
/**
|
|
254
254
|
* The step value at which a card modal
|
|
255
255
|
* is eligible for dismissing via gesture.
|
|
@@ -406,6 +406,8 @@ const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) =>
|
|
|
406
406
|
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
|
|
407
407
|
const clampedStep = helpers.clamp(0.0001, processedStep, maxStep);
|
|
408
408
|
animation.progressStep(clampedStep);
|
|
409
|
+
// Notify modal of position change for safe-area updates
|
|
410
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
409
411
|
/**
|
|
410
412
|
* When swiping down half way, the status bar style
|
|
411
413
|
* should be reset to its default value.
|
|
@@ -949,7 +951,7 @@ const mdLeaveAnimation = (baseEl, opts) => {
|
|
|
949
951
|
return baseAnimation;
|
|
950
952
|
};
|
|
951
953
|
|
|
952
|
-
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
|
|
954
|
+
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onGestureMove) => {
|
|
953
955
|
// Defaults for the sheet swipe animation
|
|
954
956
|
const defaultBackdrop = [
|
|
955
957
|
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
|
|
@@ -1280,6 +1282,8 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1280
1282
|
: step;
|
|
1281
1283
|
offset = helpers.clamp(0.0001, processedStep, maxStep);
|
|
1282
1284
|
animation.progressStep(offset);
|
|
1285
|
+
// Notify modal of position change for safe-area updates
|
|
1286
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
1283
1287
|
};
|
|
1284
1288
|
const onEnd = (detail) => {
|
|
1285
1289
|
/**
|
|
@@ -1474,9 +1478,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1474
1478
|
};
|
|
1475
1479
|
};
|
|
1476
1480
|
|
|
1477
|
-
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
|
|
1481
|
+
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}";
|
|
1478
1482
|
|
|
1479
|
-
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
|
|
1483
|
+
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}";
|
|
1480
1484
|
|
|
1481
1485
|
const Modal = class {
|
|
1482
1486
|
constructor(hostRef) {
|
|
@@ -1689,7 +1693,9 @@ const Modal = class {
|
|
|
1689
1693
|
}
|
|
1690
1694
|
}
|
|
1691
1695
|
onWindowResize() {
|
|
1692
|
-
//
|
|
1696
|
+
// Update safe-area overrides for all modal types on resize
|
|
1697
|
+
this.updateSafeAreaOverrides();
|
|
1698
|
+
// Only handle view transition for iOS card modals when no custom animations are provided
|
|
1693
1699
|
if (ionicGlobal.getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
1694
1700
|
return;
|
|
1695
1701
|
}
|
|
@@ -1871,6 +1877,8 @@ const Modal = class {
|
|
|
1871
1877
|
else if (!this.keepContentsMounted) {
|
|
1872
1878
|
await index$4.waitForMount();
|
|
1873
1879
|
}
|
|
1880
|
+
// Predict safe-area needs based on modal configuration to avoid visual snap
|
|
1881
|
+
this.setInitialSafeAreaOverrides(presentingElement);
|
|
1874
1882
|
index$3.writeTask(() => this.el.classList.add('show-modal'));
|
|
1875
1883
|
const hasCardModal = presentingElement !== undefined;
|
|
1876
1884
|
/**
|
|
@@ -1932,6 +1940,8 @@ const Modal = class {
|
|
|
1932
1940
|
else if (hasCardModal) {
|
|
1933
1941
|
this.initSwipeToClose();
|
|
1934
1942
|
}
|
|
1943
|
+
// Now that animation is complete, update safe-area based on actual position
|
|
1944
|
+
this.updateSafeAreaOverrides();
|
|
1935
1945
|
// Initialize view transition listener for iOS card modals
|
|
1936
1946
|
this.initViewTransitionListener();
|
|
1937
1947
|
// Initialize parent removal observer
|
|
@@ -1983,7 +1993,7 @@ const Modal = class {
|
|
|
1983
1993
|
await this.dismiss(undefined, overlays.GESTURE);
|
|
1984
1994
|
this.gestureAnimationDismissing = false;
|
|
1985
1995
|
});
|
|
1986
|
-
});
|
|
1996
|
+
}, () => this.updateSafeAreaOverrides());
|
|
1987
1997
|
this.gesture.enable(true);
|
|
1988
1998
|
}
|
|
1989
1999
|
initSheetGesture() {
|
|
@@ -2004,7 +2014,8 @@ const Modal = class {
|
|
|
2004
2014
|
this.currentBreakpoint = breakpoint;
|
|
2005
2015
|
this.ionBreakpointDidChange.emit({ breakpoint });
|
|
2006
2016
|
}
|
|
2007
|
-
|
|
2017
|
+
this.updateSafeAreaOverrides();
|
|
2018
|
+
}, () => this.updateSafeAreaOverrides());
|
|
2008
2019
|
this.gesture = gesture;
|
|
2009
2020
|
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
|
|
2010
2021
|
this.gesture.enable(true);
|
|
@@ -2082,6 +2093,76 @@ const Modal = class {
|
|
|
2082
2093
|
// Clear the cached reference
|
|
2083
2094
|
this.cachedPageParent = undefined;
|
|
2084
2095
|
}
|
|
2096
|
+
/**
|
|
2097
|
+
* Sets initial safe-area overrides based on modal configuration before
|
|
2098
|
+
* the modal becomes visible. This predicts whether the modal will touch
|
|
2099
|
+
* screen edges to avoid a visual snap after animation completes.
|
|
2100
|
+
*/
|
|
2101
|
+
setInitialSafeAreaOverrides(presentingElement) {
|
|
2102
|
+
const style = this.el.style;
|
|
2103
|
+
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
|
|
2104
|
+
const isCardModal = presentingElement !== undefined;
|
|
2105
|
+
const isTablet = window.innerWidth >= 768;
|
|
2106
|
+
// Sheet modals: always touch bottom, top depends on breakpoint
|
|
2107
|
+
if (isSheetModal) {
|
|
2108
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2109
|
+
// Don't override bottom - sheet always touches bottom
|
|
2110
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2111
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
// Card modals are inset from edges (rounded corners), no safe areas needed
|
|
2115
|
+
if (isCardModal) {
|
|
2116
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2117
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2118
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2119
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2122
|
+
// Phone modals are fullscreen, need all safe areas
|
|
2123
|
+
if (!isTablet) {
|
|
2124
|
+
// Don't set any overrides - inherit from :root
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
// Default tablet modal: centered dialog, no safe areas needed
|
|
2128
|
+
// Check for fullscreen override via CSS custom properties
|
|
2129
|
+
const computedStyle = getComputedStyle(this.el);
|
|
2130
|
+
const width = computedStyle.getPropertyValue('--width').trim();
|
|
2131
|
+
const height = computedStyle.getPropertyValue('--height').trim();
|
|
2132
|
+
if (width === '100%' && height === '100%') {
|
|
2133
|
+
// Fullscreen modal - need safe areas, don't override
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
// Centered dialog - zero out all safe areas
|
|
2137
|
+
style.setProperty('--ion-safe-area-top', '0px');
|
|
2138
|
+
style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2139
|
+
style.setProperty('--ion-safe-area-left', '0px');
|
|
2140
|
+
style.setProperty('--ion-safe-area-right', '0px');
|
|
2141
|
+
}
|
|
2142
|
+
/**
|
|
2143
|
+
* Updates safe-area CSS variable overrides based on whether the modal
|
|
2144
|
+
* is touching each edge of the viewport. This is called after animation
|
|
2145
|
+
* and during gestures to handle dynamic position changes.
|
|
2146
|
+
*/
|
|
2147
|
+
updateSafeAreaOverrides() {
|
|
2148
|
+
const wrapper = this.wrapperEl;
|
|
2149
|
+
if (!wrapper)
|
|
2150
|
+
return;
|
|
2151
|
+
const rect = wrapper.getBoundingClientRect();
|
|
2152
|
+
const threshold = 2; // Account for subpixel rendering
|
|
2153
|
+
const touchingTop = rect.top <= threshold;
|
|
2154
|
+
const touchingBottom = rect.bottom >= window.innerHeight - threshold;
|
|
2155
|
+
const touchingLeft = rect.left <= threshold;
|
|
2156
|
+
const touchingRight = rect.right >= window.innerWidth - threshold;
|
|
2157
|
+
// Remove override when touching edge (allow inheritance), set to 0 when not touching
|
|
2158
|
+
const style = this.el.style;
|
|
2159
|
+
touchingTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px');
|
|
2160
|
+
touchingBottom
|
|
2161
|
+
? style.removeProperty('--ion-safe-area-bottom')
|
|
2162
|
+
: style.setProperty('--ion-safe-area-bottom', '0px');
|
|
2163
|
+
touchingLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px');
|
|
2164
|
+
touchingRight ? style.removeProperty('--ion-safe-area-right') : style.setProperty('--ion-safe-area-right', '0px');
|
|
2165
|
+
}
|
|
2085
2166
|
sheetOnDismiss() {
|
|
2086
2167
|
/**
|
|
2087
2168
|
* While the gesture animation is finishing
|
|
@@ -2419,20 +2500,20 @@ const Modal = class {
|
|
|
2419
2500
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
2420
2501
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
2421
2502
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
2422
|
-
return (index$3.h(index$3.Host, Object.assign({ key: '
|
|
2503
|
+
return (index$3.h(index$3.Host, Object.assign({ key: 'e80cac8f52f1056eaf63112eafcfdcd029aa31e8', "no-router": true,
|
|
2423
2504
|
// Allow the modal to be navigable when the handle is focusable
|
|
2424
2505
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
2425
2506
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
2426
|
-
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: '
|
|
2507
|
+
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: 'dcc24085006dd1e41c47a55031d78bd55ddeb622', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && index$3.h("div", { key: '74c4ff6bdc87f8c29ee8ba0592c97db2c597d876', class: "modal-shadow" }), index$3.h("div", Object.assign({ key: '79f3b01bdadc0d830e5707026aa2055d62714274',
|
|
2427
2508
|
/*
|
|
2428
2509
|
role and aria-modal must be used on the
|
|
2429
2510
|
same element. They must also be set inside the
|
|
2430
2511
|
shadow DOM otherwise ion-button will not be highlighted
|
|
2431
2512
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
2432
2513
|
*/
|
|
2433
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: '
|
|
2514
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: 'b250920bad86e23269f900353d531975a95662af', class: "modal-handle",
|
|
2434
2515
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
2435
|
-
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) })), index$3.h("slot", { key: '
|
|
2516
|
+
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) })), index$3.h("slot", { key: '2ba83c0f0a92784cac127c6581f12ea06b201b97', onSlotchange: this.onSlotChange }))));
|
|
2436
2517
|
}
|
|
2437
2518
|
get el() { return index$3.getElement(this); }
|
|
2438
2519
|
static get watchers() { return {
|
|
@@ -124,7 +124,7 @@ ion-header ion-toolbar:first-of-type {
|
|
|
124
124
|
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
.header-collapse-condense {
|
|
127
|
+
.header-md.header-collapse-condense {
|
|
128
128
|
display: none;
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -7,7 +7,7 @@ import { clamp, getElementRoot, raf } from "../../../utils/helpers";
|
|
|
7
7
|
import { FOCUS_TRAP_DISABLE_CLASS } from "../../../utils/overlays";
|
|
8
8
|
import { getBackdropValueForSheet } from "../utils";
|
|
9
9
|
import { calculateSpringStep, handleCanDismiss } from "./utils";
|
|
10
|
-
export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
|
|
10
|
+
export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange, onGestureMove) => {
|
|
11
11
|
// Defaults for the sheet swipe animation
|
|
12
12
|
const defaultBackdrop = [
|
|
13
13
|
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
|
|
@@ -338,6 +338,8 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
338
338
|
: step;
|
|
339
339
|
offset = clamp(0.0001, processedStep, maxStep);
|
|
340
340
|
animation.progressStep(offset);
|
|
341
|
+
// Notify modal of position change for safe-area updates
|
|
342
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
341
343
|
};
|
|
342
344
|
const onEnd = (detail) => {
|
|
343
345
|
/**
|
|
@@ -12,7 +12,7 @@ import { calculateSpringStep, handleCanDismiss } from "./utils";
|
|
|
12
12
|
export const SwipeToCloseDefaults = {
|
|
13
13
|
MIN_PRESENTING_SCALE: 0.915,
|
|
14
14
|
};
|
|
15
|
-
export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
|
|
15
|
+
export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss, onGestureMove) => {
|
|
16
16
|
/**
|
|
17
17
|
* The step value at which a card modal
|
|
18
18
|
* is eligible for dismissing via gesture.
|
|
@@ -169,6 +169,8 @@ export const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismi
|
|
|
169
169
|
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
|
|
170
170
|
const clampedStep = clamp(0.0001, processedStep, maxStep);
|
|
171
171
|
animation.progressStep(clampedStep);
|
|
172
|
+
// Notify modal of position change for safe-area updates
|
|
173
|
+
onGestureMove === null || onGestureMove === void 0 ? void 0 : onGestureMove();
|
|
172
174
|
/**
|
|
173
175
|
* When swiping down half way, the status bar style
|
|
174
176
|
* should be reset to its default value.
|
|
@@ -135,10 +135,6 @@ ion-backdrop {
|
|
|
135
135
|
:host {
|
|
136
136
|
--width: 600px;
|
|
137
137
|
--height: 500px;
|
|
138
|
-
--ion-safe-area-top: 0px;
|
|
139
|
-
--ion-safe-area-bottom: 0px;
|
|
140
|
-
--ion-safe-area-right: 0px;
|
|
141
|
-
--ion-safe-area-left: 0px;
|
|
142
138
|
}
|
|
143
139
|
}
|
|
144
140
|
@media only screen and (min-width: 768px) and (min-height: 768px) {
|