@ionic/core 8.6.3-dev.11750971489.140836b0 → 8.6.3-dev.11751315648.1da06a67
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/modal.js +208 -8
- package/dist/cjs/ion-modal.cjs.entry.js +208 -8
- package/dist/collection/components/modal/animations/ios.enter.js +2 -2
- package/dist/collection/components/modal/animations/ios.leave.js +2 -2
- package/dist/collection/components/modal/animations/ios.transition.js +140 -0
- package/dist/collection/components/modal/modal.js +78 -4
- package/dist/docs.json +1 -1
- package/dist/esm/ion-modal.entry.js +208 -8
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-262429fb.entry.js +4 -0
- package/dist/types/components/modal/animations/ios.transition.d.ts +14 -0
- package/dist/types/components/modal/modal.d.ts +6 -0
- package/hydrate/index.js +208 -8
- package/hydrate/index.mjs +208 -8
- package/package.json +3 -3
- package/dist/ionic/p-9e32212d.entry.js +0 -4
package/components/modal.js
CHANGED
|
@@ -587,7 +587,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
587
587
|
baseAnimation.addAnimation(contentAnimation);
|
|
588
588
|
}
|
|
589
589
|
if (presentingEl) {
|
|
590
|
-
const
|
|
590
|
+
const isPortrait = window.innerWidth < 768;
|
|
591
591
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
592
592
|
const presentingElRoot = getElementRoot(presentingEl);
|
|
593
593
|
const presentingAnimation = createAnimation().beforeStyles({
|
|
@@ -596,7 +596,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
596
596
|
overflow: 'hidden',
|
|
597
597
|
});
|
|
598
598
|
const bodyEl = document.body;
|
|
599
|
-
if (
|
|
599
|
+
if (isPortrait) {
|
|
600
600
|
/**
|
|
601
601
|
* Fallback for browsers that does not support `max()` (ex: Firefox)
|
|
602
602
|
* No need to worry about statusbar padding since engines like Gecko
|
|
@@ -674,7 +674,7 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
674
674
|
.duration(duration)
|
|
675
675
|
.addAnimation(wrapperAnimation);
|
|
676
676
|
if (presentingEl) {
|
|
677
|
-
const
|
|
677
|
+
const isPortrait = window.innerWidth < 768;
|
|
678
678
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
679
679
|
const presentingElRoot = getElementRoot(presentingEl);
|
|
680
680
|
const presentingAnimation = createAnimation()
|
|
@@ -692,7 +692,7 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
692
692
|
}
|
|
693
693
|
});
|
|
694
694
|
const bodyEl = document.body;
|
|
695
|
-
if (
|
|
695
|
+
if (isPortrait) {
|
|
696
696
|
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
697
697
|
const modalTransform = hasCardModal ? '-10px' : transformOffset;
|
|
698
698
|
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
@@ -739,6 +739,141 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
739
739
|
return baseAnimation;
|
|
740
740
|
};
|
|
741
741
|
|
|
742
|
+
/**
|
|
743
|
+
* Transition animation from portrait view to landscape view
|
|
744
|
+
* This handles the case where a card modal is open in portrait view
|
|
745
|
+
* and the user switches to landscape view
|
|
746
|
+
*/
|
|
747
|
+
const portraitToLandscapeTransition = (baseEl, opts, duration = 300) => {
|
|
748
|
+
const { presentingEl } = opts;
|
|
749
|
+
if (!presentingEl) {
|
|
750
|
+
// No transition needed for non-card modals
|
|
751
|
+
return createAnimation('portrait-to-landscape-transition');
|
|
752
|
+
}
|
|
753
|
+
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
754
|
+
const presentingElRoot = getElementRoot(presentingEl);
|
|
755
|
+
const bodyEl = document.body;
|
|
756
|
+
const baseAnimation = createAnimation('portrait-to-landscape-transition')
|
|
757
|
+
.addElement(baseEl)
|
|
758
|
+
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
759
|
+
.duration(duration);
|
|
760
|
+
const presentingAnimation = createAnimation().beforeStyles({
|
|
761
|
+
transform: 'translateY(0)',
|
|
762
|
+
'transform-origin': 'top center',
|
|
763
|
+
overflow: 'hidden',
|
|
764
|
+
});
|
|
765
|
+
if (!hasCardModal) {
|
|
766
|
+
// Non-card modal: transition from portrait state to landscape state
|
|
767
|
+
// Portrait: presentingEl has transform and body has black background
|
|
768
|
+
// Landscape: no transform, no body background, modal wrapper opacity changes
|
|
769
|
+
const root = getElementRoot(baseEl);
|
|
770
|
+
const wrapperAnimation = createAnimation()
|
|
771
|
+
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
|
|
772
|
+
.fromTo('opacity', '1', '1'); // Keep wrapper visible in landscape
|
|
773
|
+
const backdropAnimation = createAnimation()
|
|
774
|
+
.addElement(root.querySelector('ion-backdrop'))
|
|
775
|
+
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
|
776
|
+
// Animate presentingEl from portrait state back to normal
|
|
777
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
778
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
779
|
+
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
780
|
+
presentingAnimation
|
|
781
|
+
.addElement(presentingEl)
|
|
782
|
+
.afterStyles({
|
|
783
|
+
transform: 'translateY(0px) scale(1)',
|
|
784
|
+
'border-radius': '0px',
|
|
785
|
+
})
|
|
786
|
+
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', ''))
|
|
787
|
+
.fromTo('transform', fromTransform, 'translateY(0px) scale(1)')
|
|
788
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(1)')
|
|
789
|
+
.fromTo('border-radius', '10px 10px 0 0', '0px');
|
|
790
|
+
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
// Card modal: transition from portrait card state to landscape card state
|
|
794
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
795
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
796
|
+
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
797
|
+
const toTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
|
798
|
+
presentingAnimation
|
|
799
|
+
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
|
|
800
|
+
.fromTo('transform', fromTransform, toTransform)
|
|
801
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
|
802
|
+
const shadowAnimation = createAnimation()
|
|
803
|
+
.addElement(presentingElRoot.querySelector('.modal-shadow'))
|
|
804
|
+
.fromTo('opacity', '0', '0') // Shadow stays hidden in landscape for card modals
|
|
805
|
+
.fromTo('transform', fromTransform, toTransform);
|
|
806
|
+
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
|
807
|
+
}
|
|
808
|
+
return baseAnimation;
|
|
809
|
+
};
|
|
810
|
+
/**
|
|
811
|
+
* Transition animation from landscape view to portrait view
|
|
812
|
+
* This handles the case where a card modal is open in landscape view
|
|
813
|
+
* and the user switches to portrait view
|
|
814
|
+
*/
|
|
815
|
+
const landscapeToPortraitTransition = (baseEl, opts, duration = 300) => {
|
|
816
|
+
const { presentingEl } = opts;
|
|
817
|
+
if (!presentingEl) {
|
|
818
|
+
// No transition needed for non-card modals
|
|
819
|
+
return createAnimation('landscape-to-portrait-transition');
|
|
820
|
+
}
|
|
821
|
+
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
822
|
+
const presentingElRoot = getElementRoot(presentingEl);
|
|
823
|
+
const bodyEl = document.body;
|
|
824
|
+
const baseAnimation = createAnimation('landscape-to-portrait-transition')
|
|
825
|
+
.addElement(baseEl)
|
|
826
|
+
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
827
|
+
.duration(duration);
|
|
828
|
+
const presentingAnimation = createAnimation().beforeStyles({
|
|
829
|
+
transform: 'translateY(0)',
|
|
830
|
+
'transform-origin': 'top center',
|
|
831
|
+
overflow: 'hidden',
|
|
832
|
+
});
|
|
833
|
+
if (!hasCardModal) {
|
|
834
|
+
// Non-card modal: transition from landscape state to portrait state
|
|
835
|
+
const root = getElementRoot(baseEl);
|
|
836
|
+
const wrapperAnimation = createAnimation()
|
|
837
|
+
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
|
|
838
|
+
.fromTo('opacity', '1', '1'); // Keep wrapper visible
|
|
839
|
+
const backdropAnimation = createAnimation()
|
|
840
|
+
.addElement(root.querySelector('ion-backdrop'))
|
|
841
|
+
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
|
842
|
+
// Animate presentingEl from normal state to portrait state
|
|
843
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
844
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
845
|
+
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
846
|
+
presentingAnimation
|
|
847
|
+
.addElement(presentingEl)
|
|
848
|
+
.afterStyles({
|
|
849
|
+
transform: toTransform,
|
|
850
|
+
'border-radius': '10px 10px 0 0',
|
|
851
|
+
})
|
|
852
|
+
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
|
|
853
|
+
.fromTo('transform', 'translateY(0px) scale(1)', toTransform)
|
|
854
|
+
.fromTo('filter', 'contrast(1)', 'contrast(0.85)')
|
|
855
|
+
.fromTo('border-radius', '0px', '10px 10px 0 0');
|
|
856
|
+
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
// Card modal: transition from landscape card state to portrait card state
|
|
860
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
861
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
862
|
+
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
|
863
|
+
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
864
|
+
presentingAnimation
|
|
865
|
+
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
|
|
866
|
+
.fromTo('transform', fromTransform, toTransform)
|
|
867
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
|
868
|
+
const shadowAnimation = createAnimation()
|
|
869
|
+
.addElement(presentingElRoot.querySelector('.modal-shadow'))
|
|
870
|
+
.fromTo('opacity', '0', '0') // Shadow stays hidden
|
|
871
|
+
.fromTo('transform', fromTransform, toTransform);
|
|
872
|
+
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
|
873
|
+
}
|
|
874
|
+
return baseAnimation;
|
|
875
|
+
};
|
|
876
|
+
|
|
742
877
|
const createEnterAnimation = () => {
|
|
743
878
|
const backdropAnimation = createAnimation()
|
|
744
879
|
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
|
|
@@ -1522,6 +1657,7 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1522
1657
|
}
|
|
1523
1658
|
disconnectedCallback() {
|
|
1524
1659
|
this.triggerController.removeClickListener();
|
|
1660
|
+
this.cleanupViewTransitionListener();
|
|
1525
1661
|
}
|
|
1526
1662
|
componentWillLoad() {
|
|
1527
1663
|
var _a;
|
|
@@ -1732,6 +1868,8 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1732
1868
|
else if (hasCardModal) {
|
|
1733
1869
|
this.initSwipeToClose();
|
|
1734
1870
|
}
|
|
1871
|
+
// Initialize view transition listener for iOS card modals
|
|
1872
|
+
this.initViewTransitionListener();
|
|
1735
1873
|
unlock();
|
|
1736
1874
|
}
|
|
1737
1875
|
initSwipeToClose() {
|
|
@@ -1885,6 +2023,7 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1885
2023
|
if (this.gesture) {
|
|
1886
2024
|
this.gesture.destroy();
|
|
1887
2025
|
}
|
|
2026
|
+
this.cleanupViewTransitionListener();
|
|
1888
2027
|
}
|
|
1889
2028
|
this.currentBreakpoint = undefined;
|
|
1890
2029
|
this.animation = undefined;
|
|
@@ -1960,6 +2099,67 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1960
2099
|
await this.setCurrentBreakpoint(nextBreakpoint);
|
|
1961
2100
|
return true;
|
|
1962
2101
|
}
|
|
2102
|
+
initViewTransitionListener() {
|
|
2103
|
+
// Only enable for iOS card modals when no custom animations are provided
|
|
2104
|
+
if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
// Set initial view state
|
|
2108
|
+
this.currentViewIsPortrait = window.innerWidth < 768;
|
|
2109
|
+
// Create debounced resize handler
|
|
2110
|
+
let resizeTimeout;
|
|
2111
|
+
this.resizeListener = () => {
|
|
2112
|
+
clearTimeout(resizeTimeout);
|
|
2113
|
+
resizeTimeout = setTimeout(() => {
|
|
2114
|
+
this.handleViewTransition();
|
|
2115
|
+
}, 100); // Debounce for 100ms to avoid excessive calls
|
|
2116
|
+
};
|
|
2117
|
+
window.addEventListener('resize', this.resizeListener);
|
|
2118
|
+
}
|
|
2119
|
+
handleViewTransition() {
|
|
2120
|
+
const isPortrait = window.innerWidth < 768;
|
|
2121
|
+
// Only transition if view state actually changed
|
|
2122
|
+
if (this.currentViewIsPortrait === isPortrait) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
// Cancel any ongoing transition animation
|
|
2126
|
+
if (this.viewTransitionAnimation) {
|
|
2127
|
+
this.viewTransitionAnimation.destroy();
|
|
2128
|
+
this.viewTransitionAnimation = undefined;
|
|
2129
|
+
}
|
|
2130
|
+
const { presentingElement } = this;
|
|
2131
|
+
if (!presentingElement) {
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
// Create transition animation
|
|
2135
|
+
let transitionAnimation;
|
|
2136
|
+
if (this.currentViewIsPortrait && !isPortrait) {
|
|
2137
|
+
// Portrait to landscape transition
|
|
2138
|
+
transitionAnimation = portraitToLandscapeTransition(this.el, {
|
|
2139
|
+
presentingEl: presentingElement});
|
|
2140
|
+
}
|
|
2141
|
+
else {
|
|
2142
|
+
// Landscape to portrait transition
|
|
2143
|
+
transitionAnimation = landscapeToPortraitTransition(this.el, {
|
|
2144
|
+
presentingEl: presentingElement});
|
|
2145
|
+
}
|
|
2146
|
+
// Update state and play animation
|
|
2147
|
+
this.currentViewIsPortrait = isPortrait;
|
|
2148
|
+
this.viewTransitionAnimation = transitionAnimation;
|
|
2149
|
+
transitionAnimation.play().then(() => {
|
|
2150
|
+
this.viewTransitionAnimation = undefined;
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
cleanupViewTransitionListener() {
|
|
2154
|
+
if (this.resizeListener) {
|
|
2155
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
2156
|
+
this.resizeListener = undefined;
|
|
2157
|
+
}
|
|
2158
|
+
if (this.viewTransitionAnimation) {
|
|
2159
|
+
this.viewTransitionAnimation.destroy();
|
|
2160
|
+
this.viewTransitionAnimation = undefined;
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
1963
2163
|
render() {
|
|
1964
2164
|
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
|
|
1965
2165
|
const showHandle = handle !== false && isSheetModal;
|
|
@@ -1967,20 +2167,20 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
|
|
|
1967
2167
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
1968
2168
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
1969
2169
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
1970
|
-
return (h(Host, Object.assign({ key: '
|
|
2170
|
+
return (h(Host, Object.assign({ key: 'd5bcaa588471573e1bcbd99997b306c8ecdd124f', "no-router": true,
|
|
1971
2171
|
// Allow the modal to be navigable when the handle is focusable
|
|
1972
2172
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
1973
2173
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
1974
|
-
}, 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: '
|
|
2174
|
+
}, 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: '78b954a1c50a0325eb51db04314e86701c66d840', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '21887227c272f5eba1b3d164be3572bd710d415c', class: "modal-shadow" }), h("div", Object.assign({ key: 'a40472a9065c04ad12fb7b2b2a05e5021f077ad5',
|
|
1975
2175
|
/*
|
|
1976
2176
|
role and aria-modal must be used on the
|
|
1977
2177
|
same element. They must also be set inside the
|
|
1978
2178
|
shadow DOM otherwise ion-button will not be highlighted
|
|
1979
2179
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
1980
2180
|
*/
|
|
1981
|
-
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '
|
|
2181
|
+
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: 'a4973f66587546031d1cc0197e1ba7c2521a3fbc', class: "modal-handle",
|
|
1982
2182
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
1983
|
-
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: '
|
|
2183
|
+
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: 'ee5e007e3a4e592d98f1b5a5d31ad55e6faa3bdb' }))));
|
|
1984
2184
|
}
|
|
1985
2185
|
get el() { return this; }
|
|
1986
2186
|
static get watchers() { return {
|
|
@@ -589,7 +589,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
589
589
|
baseAnimation.addAnimation(contentAnimation);
|
|
590
590
|
}
|
|
591
591
|
if (presentingEl) {
|
|
592
|
-
const
|
|
592
|
+
const isPortrait = window.innerWidth < 768;
|
|
593
593
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
594
594
|
const presentingElRoot = helpers.getElementRoot(presentingEl);
|
|
595
595
|
const presentingAnimation = animation.createAnimation().beforeStyles({
|
|
@@ -598,7 +598,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
598
598
|
overflow: 'hidden',
|
|
599
599
|
});
|
|
600
600
|
const bodyEl = document.body;
|
|
601
|
-
if (
|
|
601
|
+
if (isPortrait) {
|
|
602
602
|
/**
|
|
603
603
|
* Fallback for browsers that does not support `max()` (ex: Firefox)
|
|
604
604
|
* No need to worry about statusbar padding since engines like Gecko
|
|
@@ -676,7 +676,7 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
676
676
|
.duration(duration)
|
|
677
677
|
.addAnimation(wrapperAnimation);
|
|
678
678
|
if (presentingEl) {
|
|
679
|
-
const
|
|
679
|
+
const isPortrait = window.innerWidth < 768;
|
|
680
680
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
681
681
|
const presentingElRoot = helpers.getElementRoot(presentingEl);
|
|
682
682
|
const presentingAnimation = animation.createAnimation()
|
|
@@ -694,7 +694,7 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
694
694
|
}
|
|
695
695
|
});
|
|
696
696
|
const bodyEl = document.body;
|
|
697
|
-
if (
|
|
697
|
+
if (isPortrait) {
|
|
698
698
|
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
699
699
|
const modalTransform = hasCardModal ? '-10px' : transformOffset;
|
|
700
700
|
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
@@ -741,6 +741,141 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
741
741
|
return baseAnimation;
|
|
742
742
|
};
|
|
743
743
|
|
|
744
|
+
/**
|
|
745
|
+
* Transition animation from portrait view to landscape view
|
|
746
|
+
* This handles the case where a card modal is open in portrait view
|
|
747
|
+
* and the user switches to landscape view
|
|
748
|
+
*/
|
|
749
|
+
const portraitToLandscapeTransition = (baseEl, opts, duration = 300) => {
|
|
750
|
+
const { presentingEl } = opts;
|
|
751
|
+
if (!presentingEl) {
|
|
752
|
+
// No transition needed for non-card modals
|
|
753
|
+
return animation.createAnimation('portrait-to-landscape-transition');
|
|
754
|
+
}
|
|
755
|
+
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
756
|
+
const presentingElRoot = helpers.getElementRoot(presentingEl);
|
|
757
|
+
const bodyEl = document.body;
|
|
758
|
+
const baseAnimation = animation.createAnimation('portrait-to-landscape-transition')
|
|
759
|
+
.addElement(baseEl)
|
|
760
|
+
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
761
|
+
.duration(duration);
|
|
762
|
+
const presentingAnimation = animation.createAnimation().beforeStyles({
|
|
763
|
+
transform: 'translateY(0)',
|
|
764
|
+
'transform-origin': 'top center',
|
|
765
|
+
overflow: 'hidden',
|
|
766
|
+
});
|
|
767
|
+
if (!hasCardModal) {
|
|
768
|
+
// Non-card modal: transition from portrait state to landscape state
|
|
769
|
+
// Portrait: presentingEl has transform and body has black background
|
|
770
|
+
// Landscape: no transform, no body background, modal wrapper opacity changes
|
|
771
|
+
const root = helpers.getElementRoot(baseEl);
|
|
772
|
+
const wrapperAnimation = animation.createAnimation()
|
|
773
|
+
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
|
|
774
|
+
.fromTo('opacity', '1', '1'); // Keep wrapper visible in landscape
|
|
775
|
+
const backdropAnimation = animation.createAnimation()
|
|
776
|
+
.addElement(root.querySelector('ion-backdrop'))
|
|
777
|
+
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
|
778
|
+
// Animate presentingEl from portrait state back to normal
|
|
779
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
780
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
781
|
+
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
782
|
+
presentingAnimation
|
|
783
|
+
.addElement(presentingEl)
|
|
784
|
+
.afterStyles({
|
|
785
|
+
transform: 'translateY(0px) scale(1)',
|
|
786
|
+
'border-radius': '0px',
|
|
787
|
+
})
|
|
788
|
+
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', ''))
|
|
789
|
+
.fromTo('transform', fromTransform, 'translateY(0px) scale(1)')
|
|
790
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(1)')
|
|
791
|
+
.fromTo('border-radius', '10px 10px 0 0', '0px');
|
|
792
|
+
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
// Card modal: transition from portrait card state to landscape card state
|
|
796
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
797
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
798
|
+
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
799
|
+
const toTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
|
800
|
+
presentingAnimation
|
|
801
|
+
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
|
|
802
|
+
.fromTo('transform', fromTransform, toTransform)
|
|
803
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
|
804
|
+
const shadowAnimation = animation.createAnimation()
|
|
805
|
+
.addElement(presentingElRoot.querySelector('.modal-shadow'))
|
|
806
|
+
.fromTo('opacity', '0', '0') // Shadow stays hidden in landscape for card modals
|
|
807
|
+
.fromTo('transform', fromTransform, toTransform);
|
|
808
|
+
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
|
809
|
+
}
|
|
810
|
+
return baseAnimation;
|
|
811
|
+
};
|
|
812
|
+
/**
|
|
813
|
+
* Transition animation from landscape view to portrait view
|
|
814
|
+
* This handles the case where a card modal is open in landscape view
|
|
815
|
+
* and the user switches to portrait view
|
|
816
|
+
*/
|
|
817
|
+
const landscapeToPortraitTransition = (baseEl, opts, duration = 300) => {
|
|
818
|
+
const { presentingEl } = opts;
|
|
819
|
+
if (!presentingEl) {
|
|
820
|
+
// No transition needed for non-card modals
|
|
821
|
+
return animation.createAnimation('landscape-to-portrait-transition');
|
|
822
|
+
}
|
|
823
|
+
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
824
|
+
const presentingElRoot = helpers.getElementRoot(presentingEl);
|
|
825
|
+
const bodyEl = document.body;
|
|
826
|
+
const baseAnimation = animation.createAnimation('landscape-to-portrait-transition')
|
|
827
|
+
.addElement(baseEl)
|
|
828
|
+
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
829
|
+
.duration(duration);
|
|
830
|
+
const presentingAnimation = animation.createAnimation().beforeStyles({
|
|
831
|
+
transform: 'translateY(0)',
|
|
832
|
+
'transform-origin': 'top center',
|
|
833
|
+
overflow: 'hidden',
|
|
834
|
+
});
|
|
835
|
+
if (!hasCardModal) {
|
|
836
|
+
// Non-card modal: transition from landscape state to portrait state
|
|
837
|
+
const root = helpers.getElementRoot(baseEl);
|
|
838
|
+
const wrapperAnimation = animation.createAnimation()
|
|
839
|
+
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
|
|
840
|
+
.fromTo('opacity', '1', '1'); // Keep wrapper visible
|
|
841
|
+
const backdropAnimation = animation.createAnimation()
|
|
842
|
+
.addElement(root.querySelector('ion-backdrop'))
|
|
843
|
+
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
|
|
844
|
+
// Animate presentingEl from normal state to portrait state
|
|
845
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
846
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
847
|
+
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
848
|
+
presentingAnimation
|
|
849
|
+
.addElement(presentingEl)
|
|
850
|
+
.afterStyles({
|
|
851
|
+
transform: toTransform,
|
|
852
|
+
'border-radius': '10px 10px 0 0',
|
|
853
|
+
})
|
|
854
|
+
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
|
|
855
|
+
.fromTo('transform', 'translateY(0px) scale(1)', toTransform)
|
|
856
|
+
.fromTo('filter', 'contrast(1)', 'contrast(0.85)')
|
|
857
|
+
.fromTo('border-radius', '0px', '10px 10px 0 0');
|
|
858
|
+
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
// Card modal: transition from landscape card state to portrait card state
|
|
862
|
+
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|
|
863
|
+
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
864
|
+
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
|
|
865
|
+
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
|
|
866
|
+
presentingAnimation
|
|
867
|
+
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
|
|
868
|
+
.fromTo('transform', fromTransform, toTransform)
|
|
869
|
+
.fromTo('filter', 'contrast(0.85)', 'contrast(0.85)'); // Keep same contrast for card
|
|
870
|
+
const shadowAnimation = animation.createAnimation()
|
|
871
|
+
.addElement(presentingElRoot.querySelector('.modal-shadow'))
|
|
872
|
+
.fromTo('opacity', '0', '0') // Shadow stays hidden
|
|
873
|
+
.fromTo('transform', fromTransform, toTransform);
|
|
874
|
+
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
|
|
875
|
+
}
|
|
876
|
+
return baseAnimation;
|
|
877
|
+
};
|
|
878
|
+
|
|
744
879
|
const createEnterAnimation = () => {
|
|
745
880
|
const backdropAnimation = animation.createAnimation()
|
|
746
881
|
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
|
|
@@ -1522,6 +1657,7 @@ const Modal = class {
|
|
|
1522
1657
|
}
|
|
1523
1658
|
disconnectedCallback() {
|
|
1524
1659
|
this.triggerController.removeClickListener();
|
|
1660
|
+
this.cleanupViewTransitionListener();
|
|
1525
1661
|
}
|
|
1526
1662
|
componentWillLoad() {
|
|
1527
1663
|
var _a;
|
|
@@ -1732,6 +1868,8 @@ const Modal = class {
|
|
|
1732
1868
|
else if (hasCardModal) {
|
|
1733
1869
|
this.initSwipeToClose();
|
|
1734
1870
|
}
|
|
1871
|
+
// Initialize view transition listener for iOS card modals
|
|
1872
|
+
this.initViewTransitionListener();
|
|
1735
1873
|
unlock();
|
|
1736
1874
|
}
|
|
1737
1875
|
initSwipeToClose() {
|
|
@@ -1885,6 +2023,7 @@ const Modal = class {
|
|
|
1885
2023
|
if (this.gesture) {
|
|
1886
2024
|
this.gesture.destroy();
|
|
1887
2025
|
}
|
|
2026
|
+
this.cleanupViewTransitionListener();
|
|
1888
2027
|
}
|
|
1889
2028
|
this.currentBreakpoint = undefined;
|
|
1890
2029
|
this.animation = undefined;
|
|
@@ -1960,6 +2099,67 @@ const Modal = class {
|
|
|
1960
2099
|
await this.setCurrentBreakpoint(nextBreakpoint);
|
|
1961
2100
|
return true;
|
|
1962
2101
|
}
|
|
2102
|
+
initViewTransitionListener() {
|
|
2103
|
+
// Only enable for iOS card modals when no custom animations are provided
|
|
2104
|
+
if (index$3.getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
// Set initial view state
|
|
2108
|
+
this.currentViewIsPortrait = window.innerWidth < 768;
|
|
2109
|
+
// Create debounced resize handler
|
|
2110
|
+
let resizeTimeout;
|
|
2111
|
+
this.resizeListener = () => {
|
|
2112
|
+
clearTimeout(resizeTimeout);
|
|
2113
|
+
resizeTimeout = setTimeout(() => {
|
|
2114
|
+
this.handleViewTransition();
|
|
2115
|
+
}, 100); // Debounce for 100ms to avoid excessive calls
|
|
2116
|
+
};
|
|
2117
|
+
window.addEventListener('resize', this.resizeListener);
|
|
2118
|
+
}
|
|
2119
|
+
handleViewTransition() {
|
|
2120
|
+
const isPortrait = window.innerWidth < 768;
|
|
2121
|
+
// Only transition if view state actually changed
|
|
2122
|
+
if (this.currentViewIsPortrait === isPortrait) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2125
|
+
// Cancel any ongoing transition animation
|
|
2126
|
+
if (this.viewTransitionAnimation) {
|
|
2127
|
+
this.viewTransitionAnimation.destroy();
|
|
2128
|
+
this.viewTransitionAnimation = undefined;
|
|
2129
|
+
}
|
|
2130
|
+
const { presentingElement } = this;
|
|
2131
|
+
if (!presentingElement) {
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
// Create transition animation
|
|
2135
|
+
let transitionAnimation;
|
|
2136
|
+
if (this.currentViewIsPortrait && !isPortrait) {
|
|
2137
|
+
// Portrait to landscape transition
|
|
2138
|
+
transitionAnimation = portraitToLandscapeTransition(this.el, {
|
|
2139
|
+
presentingEl: presentingElement});
|
|
2140
|
+
}
|
|
2141
|
+
else {
|
|
2142
|
+
// Landscape to portrait transition
|
|
2143
|
+
transitionAnimation = landscapeToPortraitTransition(this.el, {
|
|
2144
|
+
presentingEl: presentingElement});
|
|
2145
|
+
}
|
|
2146
|
+
// Update state and play animation
|
|
2147
|
+
this.currentViewIsPortrait = isPortrait;
|
|
2148
|
+
this.viewTransitionAnimation = transitionAnimation;
|
|
2149
|
+
transitionAnimation.play().then(() => {
|
|
2150
|
+
this.viewTransitionAnimation = undefined;
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
cleanupViewTransitionListener() {
|
|
2154
|
+
if (this.resizeListener) {
|
|
2155
|
+
window.removeEventListener('resize', this.resizeListener);
|
|
2156
|
+
this.resizeListener = undefined;
|
|
2157
|
+
}
|
|
2158
|
+
if (this.viewTransitionAnimation) {
|
|
2159
|
+
this.viewTransitionAnimation.destroy();
|
|
2160
|
+
this.viewTransitionAnimation = undefined;
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
1963
2163
|
render() {
|
|
1964
2164
|
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
|
|
1965
2165
|
const showHandle = handle !== false && isSheetModal;
|
|
@@ -1967,20 +2167,20 @@ const Modal = class {
|
|
|
1967
2167
|
const isCardModal = presentingElement !== undefined && mode === 'ios';
|
|
1968
2168
|
const isHandleCycle = handleBehavior === 'cycle';
|
|
1969
2169
|
const isSheetModalWithHandle = isSheetModal && showHandle;
|
|
1970
|
-
return (index$3.h(index$3.Host, Object.assign({ key: '
|
|
2170
|
+
return (index$3.h(index$3.Host, Object.assign({ key: 'd5bcaa588471573e1bcbd99997b306c8ecdd124f', "no-router": true,
|
|
1971
2171
|
// Allow the modal to be navigable when the handle is focusable
|
|
1972
2172
|
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
|
|
1973
2173
|
zIndex: `${20000 + this.overlayIndex}`,
|
|
1974
|
-
}, 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: '
|
|
2174
|
+
}, 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: '78b954a1c50a0325eb51db04314e86701c66d840', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && index$3.h("div", { key: '21887227c272f5eba1b3d164be3572bd710d415c', class: "modal-shadow" }), index$3.h("div", Object.assign({ key: 'a40472a9065c04ad12fb7b2b2a05e5021f077ad5',
|
|
1975
2175
|
/*
|
|
1976
2176
|
role and aria-modal must be used on the
|
|
1977
2177
|
same element. They must also be set inside the
|
|
1978
2178
|
shadow DOM otherwise ion-button will not be highlighted
|
|
1979
2179
|
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
|
|
1980
2180
|
*/
|
|
1981
|
-
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: '
|
|
2181
|
+
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: 'a4973f66587546031d1cc0197e1ba7c2521a3fbc', class: "modal-handle",
|
|
1982
2182
|
// Prevents the handle from receiving keyboard focus when it does not cycle
|
|
1983
|
-
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: '
|
|
2183
|
+
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: 'ee5e007e3a4e592d98f1b5a5d31ad55e6faa3bdb' }))));
|
|
1984
2184
|
}
|
|
1985
2185
|
get el() { return index$3.getElement(this); }
|
|
1986
2186
|
static get watchers() { return {
|
|
@@ -36,7 +36,7 @@ export const iosEnterAnimation = (baseEl, opts) => {
|
|
|
36
36
|
baseAnimation.addAnimation(contentAnimation);
|
|
37
37
|
}
|
|
38
38
|
if (presentingEl) {
|
|
39
|
-
const
|
|
39
|
+
const isPortrait = window.innerWidth < 768;
|
|
40
40
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
41
41
|
const presentingElRoot = getElementRoot(presentingEl);
|
|
42
42
|
const presentingAnimation = createAnimation().beforeStyles({
|
|
@@ -45,7 +45,7 @@ export const iosEnterAnimation = (baseEl, opts) => {
|
|
|
45
45
|
overflow: 'hidden',
|
|
46
46
|
});
|
|
47
47
|
const bodyEl = document.body;
|
|
48
|
-
if (
|
|
48
|
+
if (isPortrait) {
|
|
49
49
|
/**
|
|
50
50
|
* Fallback for browsers that does not support `max()` (ex: Firefox)
|
|
51
51
|
* No need to worry about statusbar padding since engines like Gecko
|
|
@@ -25,7 +25,7 @@ export const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
25
25
|
.duration(duration)
|
|
26
26
|
.addAnimation(wrapperAnimation);
|
|
27
27
|
if (presentingEl) {
|
|
28
|
-
const
|
|
28
|
+
const isPortrait = window.innerWidth < 768;
|
|
29
29
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
30
30
|
const presentingElRoot = getElementRoot(presentingEl);
|
|
31
31
|
const presentingAnimation = createAnimation()
|
|
@@ -43,7 +43,7 @@ export const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
const bodyEl = document.body;
|
|
46
|
-
if (
|
|
46
|
+
if (isPortrait) {
|
|
47
47
|
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
|
|
48
48
|
const modalTransform = hasCardModal ? '-10px' : transformOffset;
|
|
49
49
|
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
|