@ionic/core 8.5.9-nightly.20250603 → 8.5.9
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 +101 -161
- package/css/core.css +1 -1
- package/css/core.css.map +1 -1
- package/css/ionic.bundle.css +1 -1
- package/css/ionic.bundle.css.map +1 -1
- package/dist/cjs/ion-modal.cjs.entry.js +101 -161
- package/dist/collection/components/modal/animations/ios.enter.js +1 -41
- package/dist/collection/components/modal/animations/ios.leave.js +2 -24
- package/dist/collection/components/modal/animations/md.enter.js +2 -42
- package/dist/collection/components/modal/animations/md.leave.js +2 -24
- package/dist/collection/components/modal/gestures/sheet.js +93 -29
- package/dist/collection/components/modal/modal.ios.css +0 -10
- package/dist/docs.json +1 -1
- package/dist/esm/ion-modal.entry.js +101 -161
- package/dist/esm-es5/ion-modal.entry.js +1 -1
- package/dist/ionic/ionic.esm.js +1 -1
- package/dist/ionic/p-4393fc08.entry.js +4 -0
- package/dist/ionic/p-44548aa3.system.entry.js +4 -0
- package/dist/ionic/p-f725bf9e.system.js +1 -1
- package/hydrate/index.js +101 -161
- package/hydrate/index.mjs +101 -161
- package/package.json +1 -1
- package/dist/ionic/p-12914457.entry.js +0 -4
- package/dist/ionic/p-cec902a0.system.entry.js +0 -4
|
@@ -35,6 +35,9 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
35
35
|
let offset = 0;
|
|
36
36
|
let canDismissBlocksGesture = false;
|
|
37
37
|
let cachedScrollEl = null;
|
|
38
|
+
let cachedFooterEl = null;
|
|
39
|
+
let cachedFooterYPosition = null;
|
|
40
|
+
let currentFooterState = null;
|
|
38
41
|
const canDismissMaxStep = 0.95;
|
|
39
42
|
const maxBreakpoint = breakpoints[breakpoints.length - 1];
|
|
40
43
|
const minBreakpoint = breakpoints[0];
|
|
@@ -64,29 +67,66 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
64
67
|
baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
|
|
65
68
|
};
|
|
66
69
|
/**
|
|
67
|
-
* Toggles the
|
|
68
|
-
*
|
|
70
|
+
* Toggles the footer to an absolute position while moving to prevent
|
|
71
|
+
* it from shaking while the sheet is being dragged.
|
|
72
|
+
* @param newPosition Whether the footer is in a moving or stationary position.
|
|
69
73
|
*/
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
const swapFooterPosition = (newPosition) => {
|
|
75
|
+
if (!cachedFooterEl) {
|
|
76
|
+
cachedFooterEl = baseEl.querySelector('ion-footer');
|
|
77
|
+
if (!cachedFooterEl) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
74
80
|
}
|
|
75
|
-
const clonedFooter = wrapperEl.nextElementSibling;
|
|
76
|
-
const footerToHide = footer === 'original' ? clonedFooter : originalFooter;
|
|
77
|
-
const footerToShow = footer === 'original' ? originalFooter : clonedFooter;
|
|
78
|
-
footerToShow.style.removeProperty('display');
|
|
79
|
-
footerToShow.removeAttribute('aria-hidden');
|
|
80
81
|
const page = baseEl.querySelector('.ion-page');
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
currentFooterState = newPosition;
|
|
83
|
+
if (newPosition === 'stationary') {
|
|
84
|
+
// Reset positioning styles to allow normal document flow
|
|
85
|
+
cachedFooterEl.classList.remove('modal-footer-moving');
|
|
86
|
+
cachedFooterEl.style.removeProperty('position');
|
|
87
|
+
cachedFooterEl.style.removeProperty('width');
|
|
88
|
+
cachedFooterEl.style.removeProperty('height');
|
|
89
|
+
cachedFooterEl.style.removeProperty('top');
|
|
90
|
+
cachedFooterEl.style.removeProperty('left');
|
|
91
|
+
page === null || page === void 0 ? void 0 : page.style.removeProperty('padding-bottom');
|
|
92
|
+
// Move to page
|
|
93
|
+
page === null || page === void 0 ? void 0 : page.appendChild(cachedFooterEl);
|
|
83
94
|
}
|
|
84
95
|
else {
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
// Get both the footer and document body positions
|
|
97
|
+
const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
|
|
98
|
+
const bodyRect = document.body.getBoundingClientRect();
|
|
99
|
+
// Add padding to the parent element to prevent content from being hidden
|
|
100
|
+
// when the footer is positioned absolutely. This has to be done before we
|
|
101
|
+
// make the footer absolutely positioned or we may accidentally cause the
|
|
102
|
+
// sheet to scroll.
|
|
103
|
+
const footerHeight = cachedFooterEl.clientHeight;
|
|
104
|
+
page === null || page === void 0 ? void 0 : page.style.setProperty('padding-bottom', `${footerHeight}px`);
|
|
105
|
+
// Apply positioning styles to keep footer at bottom
|
|
106
|
+
cachedFooterEl.classList.add('modal-footer-moving');
|
|
107
|
+
// Calculate absolute position relative to body
|
|
108
|
+
// We need to subtract the body's offsetTop to get true position within document.body
|
|
109
|
+
const absoluteTop = cachedFooterElRect.top - bodyRect.top;
|
|
110
|
+
const absoluteLeft = cachedFooterElRect.left - bodyRect.left;
|
|
111
|
+
// Capture the footer's current dimensions and hard code them during the drag
|
|
112
|
+
cachedFooterEl.style.setProperty('position', 'absolute');
|
|
113
|
+
cachedFooterEl.style.setProperty('width', `${cachedFooterEl.clientWidth}px`);
|
|
114
|
+
cachedFooterEl.style.setProperty('height', `${cachedFooterEl.clientHeight}px`);
|
|
115
|
+
cachedFooterEl.style.setProperty('top', `${absoluteTop}px`);
|
|
116
|
+
cachedFooterEl.style.setProperty('left', `${absoluteLeft}px`);
|
|
117
|
+
// Also cache the footer Y position, which we use to determine if the
|
|
118
|
+
// sheet has been moved below the footer. When that happens, we need to swap
|
|
119
|
+
// the position back so it will collapse correctly.
|
|
120
|
+
cachedFooterYPosition = absoluteTop;
|
|
121
|
+
// If there's a toolbar, we need to combine the toolbar height with the footer position
|
|
122
|
+
// because the toolbar moves with the drag handle, so when it starts overlapping the footer,
|
|
123
|
+
// we need to account for that.
|
|
124
|
+
const toolbar = baseEl.querySelector('ion-toolbar');
|
|
125
|
+
if (toolbar) {
|
|
126
|
+
cachedFooterYPosition -= toolbar.clientHeight;
|
|
127
|
+
}
|
|
128
|
+
document.body.appendChild(cachedFooterEl);
|
|
87
129
|
}
|
|
88
|
-
footerToHide.style.setProperty('display', 'none');
|
|
89
|
-
footerToHide.setAttribute('aria-hidden', 'true');
|
|
90
130
|
};
|
|
91
131
|
/**
|
|
92
132
|
* After the entering animation completes,
|
|
@@ -180,12 +220,11 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
180
220
|
}
|
|
181
221
|
/**
|
|
182
222
|
* If expandToScroll is disabled, we need to swap
|
|
183
|
-
* the footer
|
|
184
|
-
*
|
|
185
|
-
* and doesn't stay on the screen after the modal is gone.
|
|
223
|
+
* the footer position to moving so that it doesn't shake
|
|
224
|
+
* while the sheet is being dragged.
|
|
186
225
|
*/
|
|
187
226
|
if (!expandToScroll) {
|
|
188
|
-
|
|
227
|
+
swapFooterPosition('moving');
|
|
189
228
|
}
|
|
190
229
|
/**
|
|
191
230
|
* If we are pulling down, then it is possible we are pulling on the content.
|
|
@@ -204,6 +243,21 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
204
243
|
animation.progressStart(true, 1 - currentBreakpoint);
|
|
205
244
|
};
|
|
206
245
|
const onMove = (detail) => {
|
|
246
|
+
/**
|
|
247
|
+
* If `expandToScroll` is disabled, we need to see if we're currently below
|
|
248
|
+
* the footer element and the footer is in a stationary position. If so,
|
|
249
|
+
* we need to make the stationary the original position so that the footer
|
|
250
|
+
* collapses with the sheet.
|
|
251
|
+
*/
|
|
252
|
+
if (!expandToScroll && cachedFooterYPosition !== null && currentFooterState !== null) {
|
|
253
|
+
// Check if we need to swap the footer position
|
|
254
|
+
if (detail.currentY >= cachedFooterYPosition && currentFooterState === 'moving') {
|
|
255
|
+
swapFooterPosition('stationary');
|
|
256
|
+
}
|
|
257
|
+
else if (detail.currentY < cachedFooterYPosition && currentFooterState === 'stationary') {
|
|
258
|
+
swapFooterPosition('moving');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
207
261
|
/**
|
|
208
262
|
* If `expandToScroll` is disabled, and an upwards swipe gesture is done within
|
|
209
263
|
* the scrollable content, we should not allow the swipe gesture to continue.
|
|
@@ -337,14 +391,6 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
337
391
|
* snapping animation completes.
|
|
338
392
|
*/
|
|
339
393
|
gesture.enable(false);
|
|
340
|
-
/**
|
|
341
|
-
* If expandToScroll is disabled, we need to swap
|
|
342
|
-
* the footer visibility to the cloned one so the footer
|
|
343
|
-
* doesn't flicker when the sheet's height is animated.
|
|
344
|
-
*/
|
|
345
|
-
if (!expandToScroll && shouldRemainOpen) {
|
|
346
|
-
swapFooterVisibility('cloned');
|
|
347
|
-
}
|
|
348
394
|
if (shouldPreventDismiss) {
|
|
349
395
|
handleCanDismiss(baseEl, animation);
|
|
350
396
|
}
|
|
@@ -361,10 +407,28 @@ export const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpo
|
|
|
361
407
|
if (contentEl && (snapToBreakpoint === breakpoints[breakpoints.length - 1] || !expandToScroll)) {
|
|
362
408
|
contentEl.scrollY = true;
|
|
363
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* If expandToScroll is disabled and we're animating
|
|
412
|
+
* to close the sheet, we need to swap
|
|
413
|
+
* the footer position to stationary so that it
|
|
414
|
+
* will collapse correctly. We cannot just always swap
|
|
415
|
+
* here or it'll be jittery while animating movement.
|
|
416
|
+
*/
|
|
417
|
+
if (!expandToScroll && snapToBreakpoint === 0) {
|
|
418
|
+
swapFooterPosition('stationary');
|
|
419
|
+
}
|
|
364
420
|
return new Promise((resolve) => {
|
|
365
421
|
animation
|
|
366
422
|
.onFinish(() => {
|
|
367
423
|
if (shouldRemainOpen) {
|
|
424
|
+
/**
|
|
425
|
+
* If expandToScroll is disabled, we need to swap
|
|
426
|
+
* the footer position to stationary so that it
|
|
427
|
+
* will act as it would by default.
|
|
428
|
+
*/
|
|
429
|
+
if (!expandToScroll) {
|
|
430
|
+
swapFooterPosition('stationary');
|
|
431
|
+
}
|
|
368
432
|
/**
|
|
369
433
|
* Once the snapping animation completes,
|
|
370
434
|
* we need to reset the animation to go
|
|
@@ -331,14 +331,4 @@ ion-backdrop {
|
|
|
331
331
|
border-start-end-radius: var(--border-radius);
|
|
332
332
|
border-end-end-radius: 0;
|
|
333
333
|
border-end-start-radius: 0;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Sheet modals require an additional padding as mentioned in the
|
|
338
|
-
* `core.scss` file. However, there's a workaround that requires
|
|
339
|
-
* a cloned footer to be added to the modal. This is only necessary
|
|
340
|
-
* because the core styles are not being applied to the cloned footer.
|
|
341
|
-
*/
|
|
342
|
-
:host(.modal-sheet.modal-no-expand-scroll) ion-footer ion-toolbar:first-of-type {
|
|
343
|
-
padding-top: 6px;
|
|
344
334
|
}
|
package/dist/docs.json
CHANGED
|
@@ -584,47 +584,7 @@ const iosEnterAnimation = (baseEl, opts) => {
|
|
|
584
584
|
.addElement(baseEl)
|
|
585
585
|
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
586
586
|
.duration(500)
|
|
587
|
-
.addAnimation([wrapperAnimation])
|
|
588
|
-
.beforeAddWrite(() => {
|
|
589
|
-
if (expandToScroll) {
|
|
590
|
-
// Scroll can only be done when the modal is fully expanded.
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* There are some browsers that causes flickering when
|
|
595
|
-
* dragging the content when scroll is enabled at every
|
|
596
|
-
* breakpoint. This is due to the wrapper element being
|
|
597
|
-
* transformed off the screen and having a snap animation.
|
|
598
|
-
*
|
|
599
|
-
* A workaround is to clone the footer element and append
|
|
600
|
-
* it outside of the wrapper element. This way, the footer
|
|
601
|
-
* is still visible and the drag can be done without
|
|
602
|
-
* flickering. The original footer is hidden until the modal
|
|
603
|
-
* is dismissed. This maintains the animation of the footer
|
|
604
|
-
* when the modal is dismissed.
|
|
605
|
-
*
|
|
606
|
-
* The workaround needs to be done before the animation starts
|
|
607
|
-
* so there are no flickering issues.
|
|
608
|
-
*/
|
|
609
|
-
const ionFooter = baseEl.querySelector('ion-footer');
|
|
610
|
-
/**
|
|
611
|
-
* This check is needed to prevent more than one footer
|
|
612
|
-
* from being appended to the shadow root.
|
|
613
|
-
* Otherwise, iOS and MD enter animations would append
|
|
614
|
-
* the footer twice.
|
|
615
|
-
*/
|
|
616
|
-
const ionFooterAlreadyAppended = baseEl.shadowRoot.querySelector('ion-footer');
|
|
617
|
-
if (ionFooter && !ionFooterAlreadyAppended) {
|
|
618
|
-
const footerHeight = ionFooter.clientHeight;
|
|
619
|
-
const clonedFooter = ionFooter.cloneNode(true);
|
|
620
|
-
baseEl.shadowRoot.appendChild(clonedFooter);
|
|
621
|
-
ionFooter.style.setProperty('display', 'none');
|
|
622
|
-
ionFooter.setAttribute('aria-hidden', 'true');
|
|
623
|
-
// Padding is added to prevent some content from being hidden.
|
|
624
|
-
const page = baseEl.querySelector('.ion-page');
|
|
625
|
-
page.style.setProperty('padding-bottom', `${footerHeight}px`);
|
|
626
|
-
}
|
|
627
|
-
});
|
|
587
|
+
.addAnimation([wrapperAnimation]);
|
|
628
588
|
if (contentAnimation) {
|
|
629
589
|
baseAnimation.addAnimation(contentAnimation);
|
|
630
590
|
}
|
|
@@ -705,7 +665,7 @@ const createLeaveAnimation$1 = () => {
|
|
|
705
665
|
* iOS Modal Leave Animation
|
|
706
666
|
*/
|
|
707
667
|
const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
708
|
-
const { presentingEl, currentBreakpoint
|
|
668
|
+
const { presentingEl, currentBreakpoint } = opts;
|
|
709
669
|
const root = getElementRoot(baseEl);
|
|
710
670
|
const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation$1();
|
|
711
671
|
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
|
|
@@ -714,29 +674,7 @@ const iosLeaveAnimation = (baseEl, opts, duration = 500) => {
|
|
|
714
674
|
.addElement(baseEl)
|
|
715
675
|
.easing('cubic-bezier(0.32,0.72,0,1)')
|
|
716
676
|
.duration(duration)
|
|
717
|
-
.addAnimation(wrapperAnimation)
|
|
718
|
-
.beforeAddWrite(() => {
|
|
719
|
-
if (expandToScroll) {
|
|
720
|
-
// Scroll can only be done when the modal is fully expanded.
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* If expandToScroll is disabled, we need to swap
|
|
725
|
-
* the visibility to the original, so the footer
|
|
726
|
-
* dismisses with the modal and doesn't stay
|
|
727
|
-
* until the modal is removed from the DOM.
|
|
728
|
-
*/
|
|
729
|
-
const ionFooter = baseEl.querySelector('ion-footer');
|
|
730
|
-
if (ionFooter) {
|
|
731
|
-
const clonedFooter = baseEl.shadowRoot.querySelector('ion-footer');
|
|
732
|
-
ionFooter.style.removeProperty('display');
|
|
733
|
-
ionFooter.removeAttribute('aria-hidden');
|
|
734
|
-
clonedFooter.style.setProperty('display', 'none');
|
|
735
|
-
clonedFooter.setAttribute('aria-hidden', 'true');
|
|
736
|
-
const page = baseEl.querySelector('.ion-page');
|
|
737
|
-
page.style.removeProperty('padding-bottom');
|
|
738
|
-
}
|
|
739
|
-
});
|
|
677
|
+
.addAnimation(wrapperAnimation);
|
|
740
678
|
if (presentingEl) {
|
|
741
679
|
const isMobile = window.innerWidth < 768;
|
|
742
680
|
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
|
|
@@ -827,52 +765,12 @@ const mdEnterAnimation = (baseEl, opts) => {
|
|
|
827
765
|
wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
|
|
828
766
|
// The content animation is only added if scrolling is enabled for
|
|
829
767
|
// all the breakpoints.
|
|
830
|
-
expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
|
|
768
|
+
!expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
|
|
831
769
|
const baseAnimation = createAnimation()
|
|
832
770
|
.addElement(baseEl)
|
|
833
771
|
.easing('cubic-bezier(0.36,0.66,0.04,1)')
|
|
834
772
|
.duration(280)
|
|
835
|
-
.addAnimation([backdropAnimation, wrapperAnimation])
|
|
836
|
-
.beforeAddWrite(() => {
|
|
837
|
-
if (expandToScroll) {
|
|
838
|
-
// Scroll can only be done when the modal is fully expanded.
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* There are some browsers that causes flickering when
|
|
843
|
-
* dragging the content when scroll is enabled at every
|
|
844
|
-
* breakpoint. This is due to the wrapper element being
|
|
845
|
-
* transformed off the screen and having a snap animation.
|
|
846
|
-
*
|
|
847
|
-
* A workaround is to clone the footer element and append
|
|
848
|
-
* it outside of the wrapper element. This way, the footer
|
|
849
|
-
* is still visible and the drag can be done without
|
|
850
|
-
* flickering. The original footer is hidden until the modal
|
|
851
|
-
* is dismissed. This maintains the animation of the footer
|
|
852
|
-
* when the modal is dismissed.
|
|
853
|
-
*
|
|
854
|
-
* The workaround needs to be done before the animation starts
|
|
855
|
-
* so there are no flickering issues.
|
|
856
|
-
*/
|
|
857
|
-
const ionFooter = baseEl.querySelector('ion-footer');
|
|
858
|
-
/**
|
|
859
|
-
* This check is needed to prevent more than one footer
|
|
860
|
-
* from being appended to the shadow root.
|
|
861
|
-
* Otherwise, iOS and MD enter animations would append
|
|
862
|
-
* the footer twice.
|
|
863
|
-
*/
|
|
864
|
-
const ionFooterAlreadyAppended = baseEl.shadowRoot.querySelector('ion-footer');
|
|
865
|
-
if (ionFooter && !ionFooterAlreadyAppended) {
|
|
866
|
-
const footerHeight = ionFooter.clientHeight;
|
|
867
|
-
const clonedFooter = ionFooter.cloneNode(true);
|
|
868
|
-
baseEl.shadowRoot.appendChild(clonedFooter);
|
|
869
|
-
ionFooter.style.setProperty('display', 'none');
|
|
870
|
-
ionFooter.setAttribute('aria-hidden', 'true');
|
|
871
|
-
// Padding is added to prevent some content from being hidden.
|
|
872
|
-
const page = baseEl.querySelector('.ion-page');
|
|
873
|
-
page.style.setProperty('padding-bottom', `${footerHeight}px`);
|
|
874
|
-
}
|
|
875
|
-
});
|
|
773
|
+
.addAnimation([backdropAnimation, wrapperAnimation]);
|
|
876
774
|
if (contentAnimation) {
|
|
877
775
|
baseAnimation.addAnimation(contentAnimation);
|
|
878
776
|
}
|
|
@@ -891,7 +789,7 @@ const createLeaveAnimation = () => {
|
|
|
891
789
|
* Md Modal Leave Animation
|
|
892
790
|
*/
|
|
893
791
|
const mdLeaveAnimation = (baseEl, opts) => {
|
|
894
|
-
const { currentBreakpoint
|
|
792
|
+
const { currentBreakpoint } = opts;
|
|
895
793
|
const root = getElementRoot(baseEl);
|
|
896
794
|
const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation();
|
|
897
795
|
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
|
|
@@ -899,29 +797,7 @@ const mdLeaveAnimation = (baseEl, opts) => {
|
|
|
899
797
|
const baseAnimation = createAnimation()
|
|
900
798
|
.easing('cubic-bezier(0.47,0,0.745,0.715)')
|
|
901
799
|
.duration(200)
|
|
902
|
-
.addAnimation([backdropAnimation, wrapperAnimation])
|
|
903
|
-
.beforeAddWrite(() => {
|
|
904
|
-
if (expandToScroll) {
|
|
905
|
-
// Scroll can only be done when the modal is fully expanded.
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
/**
|
|
909
|
-
* If expandToScroll is disabled, we need to swap
|
|
910
|
-
* the visibility to the original, so the footer
|
|
911
|
-
* dismisses with the modal and doesn't stay
|
|
912
|
-
* until the modal is removed from the DOM.
|
|
913
|
-
*/
|
|
914
|
-
const ionFooter = baseEl.querySelector('ion-footer');
|
|
915
|
-
if (ionFooter) {
|
|
916
|
-
const clonedFooter = baseEl.shadowRoot.querySelector('ion-footer');
|
|
917
|
-
ionFooter.style.removeProperty('display');
|
|
918
|
-
ionFooter.removeAttribute('aria-hidden');
|
|
919
|
-
clonedFooter.style.setProperty('display', 'none');
|
|
920
|
-
clonedFooter.setAttribute('aria-hidden', 'true');
|
|
921
|
-
const page = baseEl.querySelector('.ion-page');
|
|
922
|
-
page.style.removeProperty('padding-bottom');
|
|
923
|
-
}
|
|
924
|
-
});
|
|
800
|
+
.addAnimation([backdropAnimation, wrapperAnimation]);
|
|
925
801
|
return baseAnimation;
|
|
926
802
|
};
|
|
927
803
|
|
|
@@ -953,6 +829,9 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
953
829
|
let offset = 0;
|
|
954
830
|
let canDismissBlocksGesture = false;
|
|
955
831
|
let cachedScrollEl = null;
|
|
832
|
+
let cachedFooterEl = null;
|
|
833
|
+
let cachedFooterYPosition = null;
|
|
834
|
+
let currentFooterState = null;
|
|
956
835
|
const canDismissMaxStep = 0.95;
|
|
957
836
|
const maxBreakpoint = breakpoints[breakpoints.length - 1];
|
|
958
837
|
const minBreakpoint = breakpoints[0];
|
|
@@ -982,29 +861,66 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
982
861
|
baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
|
|
983
862
|
};
|
|
984
863
|
/**
|
|
985
|
-
* Toggles the
|
|
986
|
-
*
|
|
864
|
+
* Toggles the footer to an absolute position while moving to prevent
|
|
865
|
+
* it from shaking while the sheet is being dragged.
|
|
866
|
+
* @param newPosition Whether the footer is in a moving or stationary position.
|
|
987
867
|
*/
|
|
988
|
-
const
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
868
|
+
const swapFooterPosition = (newPosition) => {
|
|
869
|
+
if (!cachedFooterEl) {
|
|
870
|
+
cachedFooterEl = baseEl.querySelector('ion-footer');
|
|
871
|
+
if (!cachedFooterEl) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
992
874
|
}
|
|
993
|
-
const clonedFooter = wrapperEl.nextElementSibling;
|
|
994
|
-
const footerToHide = footer === 'original' ? clonedFooter : originalFooter;
|
|
995
|
-
const footerToShow = footer === 'original' ? originalFooter : clonedFooter;
|
|
996
|
-
footerToShow.style.removeProperty('display');
|
|
997
|
-
footerToShow.removeAttribute('aria-hidden');
|
|
998
875
|
const page = baseEl.querySelector('.ion-page');
|
|
999
|
-
|
|
1000
|
-
|
|
876
|
+
currentFooterState = newPosition;
|
|
877
|
+
if (newPosition === 'stationary') {
|
|
878
|
+
// Reset positioning styles to allow normal document flow
|
|
879
|
+
cachedFooterEl.classList.remove('modal-footer-moving');
|
|
880
|
+
cachedFooterEl.style.removeProperty('position');
|
|
881
|
+
cachedFooterEl.style.removeProperty('width');
|
|
882
|
+
cachedFooterEl.style.removeProperty('height');
|
|
883
|
+
cachedFooterEl.style.removeProperty('top');
|
|
884
|
+
cachedFooterEl.style.removeProperty('left');
|
|
885
|
+
page === null || page === void 0 ? void 0 : page.style.removeProperty('padding-bottom');
|
|
886
|
+
// Move to page
|
|
887
|
+
page === null || page === void 0 ? void 0 : page.appendChild(cachedFooterEl);
|
|
1001
888
|
}
|
|
1002
889
|
else {
|
|
1003
|
-
|
|
1004
|
-
|
|
890
|
+
// Get both the footer and document body positions
|
|
891
|
+
const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
|
|
892
|
+
const bodyRect = document.body.getBoundingClientRect();
|
|
893
|
+
// Add padding to the parent element to prevent content from being hidden
|
|
894
|
+
// when the footer is positioned absolutely. This has to be done before we
|
|
895
|
+
// make the footer absolutely positioned or we may accidentally cause the
|
|
896
|
+
// sheet to scroll.
|
|
897
|
+
const footerHeight = cachedFooterEl.clientHeight;
|
|
898
|
+
page === null || page === void 0 ? void 0 : page.style.setProperty('padding-bottom', `${footerHeight}px`);
|
|
899
|
+
// Apply positioning styles to keep footer at bottom
|
|
900
|
+
cachedFooterEl.classList.add('modal-footer-moving');
|
|
901
|
+
// Calculate absolute position relative to body
|
|
902
|
+
// We need to subtract the body's offsetTop to get true position within document.body
|
|
903
|
+
const absoluteTop = cachedFooterElRect.top - bodyRect.top;
|
|
904
|
+
const absoluteLeft = cachedFooterElRect.left - bodyRect.left;
|
|
905
|
+
// Capture the footer's current dimensions and hard code them during the drag
|
|
906
|
+
cachedFooterEl.style.setProperty('position', 'absolute');
|
|
907
|
+
cachedFooterEl.style.setProperty('width', `${cachedFooterEl.clientWidth}px`);
|
|
908
|
+
cachedFooterEl.style.setProperty('height', `${cachedFooterEl.clientHeight}px`);
|
|
909
|
+
cachedFooterEl.style.setProperty('top', `${absoluteTop}px`);
|
|
910
|
+
cachedFooterEl.style.setProperty('left', `${absoluteLeft}px`);
|
|
911
|
+
// Also cache the footer Y position, which we use to determine if the
|
|
912
|
+
// sheet has been moved below the footer. When that happens, we need to swap
|
|
913
|
+
// the position back so it will collapse correctly.
|
|
914
|
+
cachedFooterYPosition = absoluteTop;
|
|
915
|
+
// If there's a toolbar, we need to combine the toolbar height with the footer position
|
|
916
|
+
// because the toolbar moves with the drag handle, so when it starts overlapping the footer,
|
|
917
|
+
// we need to account for that.
|
|
918
|
+
const toolbar = baseEl.querySelector('ion-toolbar');
|
|
919
|
+
if (toolbar) {
|
|
920
|
+
cachedFooterYPosition -= toolbar.clientHeight;
|
|
921
|
+
}
|
|
922
|
+
document.body.appendChild(cachedFooterEl);
|
|
1005
923
|
}
|
|
1006
|
-
footerToHide.style.setProperty('display', 'none');
|
|
1007
|
-
footerToHide.setAttribute('aria-hidden', 'true');
|
|
1008
924
|
};
|
|
1009
925
|
/**
|
|
1010
926
|
* After the entering animation completes,
|
|
@@ -1098,12 +1014,11 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1098
1014
|
}
|
|
1099
1015
|
/**
|
|
1100
1016
|
* If expandToScroll is disabled, we need to swap
|
|
1101
|
-
* the footer
|
|
1102
|
-
*
|
|
1103
|
-
* and doesn't stay on the screen after the modal is gone.
|
|
1017
|
+
* the footer position to moving so that it doesn't shake
|
|
1018
|
+
* while the sheet is being dragged.
|
|
1104
1019
|
*/
|
|
1105
1020
|
if (!expandToScroll) {
|
|
1106
|
-
|
|
1021
|
+
swapFooterPosition('moving');
|
|
1107
1022
|
}
|
|
1108
1023
|
/**
|
|
1109
1024
|
* If we are pulling down, then it is possible we are pulling on the content.
|
|
@@ -1122,6 +1037,21 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1122
1037
|
animation.progressStart(true, 1 - currentBreakpoint);
|
|
1123
1038
|
};
|
|
1124
1039
|
const onMove = (detail) => {
|
|
1040
|
+
/**
|
|
1041
|
+
* If `expandToScroll` is disabled, we need to see if we're currently below
|
|
1042
|
+
* the footer element and the footer is in a stationary position. If so,
|
|
1043
|
+
* we need to make the stationary the original position so that the footer
|
|
1044
|
+
* collapses with the sheet.
|
|
1045
|
+
*/
|
|
1046
|
+
if (!expandToScroll && cachedFooterYPosition !== null && currentFooterState !== null) {
|
|
1047
|
+
// Check if we need to swap the footer position
|
|
1048
|
+
if (detail.currentY >= cachedFooterYPosition && currentFooterState === 'moving') {
|
|
1049
|
+
swapFooterPosition('stationary');
|
|
1050
|
+
}
|
|
1051
|
+
else if (detail.currentY < cachedFooterYPosition && currentFooterState === 'stationary') {
|
|
1052
|
+
swapFooterPosition('moving');
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1125
1055
|
/**
|
|
1126
1056
|
* If `expandToScroll` is disabled, and an upwards swipe gesture is done within
|
|
1127
1057
|
* the scrollable content, we should not allow the swipe gesture to continue.
|
|
@@ -1255,14 +1185,6 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1255
1185
|
* snapping animation completes.
|
|
1256
1186
|
*/
|
|
1257
1187
|
gesture.enable(false);
|
|
1258
|
-
/**
|
|
1259
|
-
* If expandToScroll is disabled, we need to swap
|
|
1260
|
-
* the footer visibility to the cloned one so the footer
|
|
1261
|
-
* doesn't flicker when the sheet's height is animated.
|
|
1262
|
-
*/
|
|
1263
|
-
if (!expandToScroll && shouldRemainOpen) {
|
|
1264
|
-
swapFooterVisibility('cloned');
|
|
1265
|
-
}
|
|
1266
1188
|
if (shouldPreventDismiss) {
|
|
1267
1189
|
handleCanDismiss(baseEl, animation);
|
|
1268
1190
|
}
|
|
@@ -1279,10 +1201,28 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1279
1201
|
if (contentEl && (snapToBreakpoint === breakpoints[breakpoints.length - 1] || !expandToScroll)) {
|
|
1280
1202
|
contentEl.scrollY = true;
|
|
1281
1203
|
}
|
|
1204
|
+
/**
|
|
1205
|
+
* If expandToScroll is disabled and we're animating
|
|
1206
|
+
* to close the sheet, we need to swap
|
|
1207
|
+
* the footer position to stationary so that it
|
|
1208
|
+
* will collapse correctly. We cannot just always swap
|
|
1209
|
+
* here or it'll be jittery while animating movement.
|
|
1210
|
+
*/
|
|
1211
|
+
if (!expandToScroll && snapToBreakpoint === 0) {
|
|
1212
|
+
swapFooterPosition('stationary');
|
|
1213
|
+
}
|
|
1282
1214
|
return new Promise((resolve) => {
|
|
1283
1215
|
animation
|
|
1284
1216
|
.onFinish(() => {
|
|
1285
1217
|
if (shouldRemainOpen) {
|
|
1218
|
+
/**
|
|
1219
|
+
* If expandToScroll is disabled, we need to swap
|
|
1220
|
+
* the footer position to stationary so that it
|
|
1221
|
+
* will act as it would by default.
|
|
1222
|
+
*/
|
|
1223
|
+
if (!expandToScroll) {
|
|
1224
|
+
swapFooterPosition('stationary');
|
|
1225
|
+
}
|
|
1286
1226
|
/**
|
|
1287
1227
|
* Once the snapping animation completes,
|
|
1288
1228
|
* we need to reset the animation to go
|
|
@@ -1347,7 +1287,7 @@ const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, ba
|
|
|
1347
1287
|
};
|
|
1348
1288
|
};
|
|
1349
1289
|
|
|
1350
|
-
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;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@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}
|
|
1290
|
+
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;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@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}";
|
|
1351
1291
|
const IonModalIosStyle0 = modalIosCss;
|
|
1352
1292
|
|
|
1353
1293
|
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;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@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}";
|