@@ -19,54 +19,78 @@ const createEnterAnimation = () => {
1919 { offset : 1 , opacity : 1 , transform : `translateY(0px)` } ,
2020 ] ) ;
2121
22- return { backdropAnimation, wrapperAnimation, contentAnimation : undefined , footerAnimation : undefined } ;
22+ return { backdropAnimation, wrapperAnimation, contentAnimation : undefined } ;
2323} ;
2424
2525/**
2626 * Md Modal Enter Animation
2727 */
2828export const mdEnterAnimation = ( baseEl : HTMLElement , opts : ModalAnimationOptions ) : Animation => {
29- const { currentBreakpoint, animateContentHeight } = opts ;
29+ const { currentBreakpoint, scrollAtEdge } = opts ;
3030 const root = getElementRoot ( baseEl ) ;
31- const { wrapperAnimation, backdropAnimation, contentAnimation, footerAnimation } =
32- currentBreakpoint !== undefined ? createSheetEnterAnimation ( baseEl , opts ) : createEnterAnimation ( ) ;
31+ const { wrapperAnimation, backdropAnimation, contentAnimation } =
32+ currentBreakpoint !== undefined ? createSheetEnterAnimation ( opts ) : createEnterAnimation ( ) ;
3333
3434 backdropAnimation . addElement ( root . querySelector ( 'ion-backdrop' ) ! ) ;
3535
3636 wrapperAnimation . addElement ( root . querySelector ( '.modal-wrapper' ) ! ) ;
3737
38- contentAnimation ?. addElement ( baseEl . querySelector ( '.ion-page' ) ! ) ;
38+ // The content animation is only added if scrolling is enabled for
39+ // all the breakpoints.
40+ scrollAtEdge && contentAnimation ?. addElement ( baseEl . querySelector ( '.ion-page' ) ! ) ;
3941
4042 const baseAnimation = createAnimation ( )
41- . addElement ( baseEl )
42- . easing ( 'cubic-bezier(0.36,0.66,0.04,1)' )
43- . duration ( 280 )
44- . addAnimation ( [ backdropAnimation , wrapperAnimation ] )
45- . beforeAddWrite ( ( ) => {
46- if ( ! animateContentHeight ) return ;
43+ . addElement ( baseEl )
44+ . easing ( 'cubic-bezier(0.36,0.66,0.04,1)' )
45+ . duration ( 280 )
46+ . addAnimation ( [ backdropAnimation , wrapperAnimation ] )
47+ . beforeAddWrite ( ( ) => {
48+ if ( scrollAtEdge ) {
49+ // Scroll can only be done when the modal is fully expanded.
50+ return ;
51+ }
52+
53+ /**
54+ * There are some browsers that causes flickering when
55+ * dragging the content when scroll is enabled at every
56+ * breakpoint. This is due to the wrapper element being
57+ * transformed off the screen and having a snap animation.
58+ *
59+ * A workaround is to clone the footer element and append
60+ * it outside of the wrapper element. This way, the footer
61+ * is still visible and the drag can be done without
62+ * flickering. The original footer is hidden until the modal
63+ * is dismissed. This maintains the animation of the footer
64+ * when the modal is dismissed.
65+ *
66+ * The workaround needs to be done before the animation starts
67+ * so there are no flickering issues.
68+ */
69+ const ionFooter = baseEl . querySelector ( 'ion-footer' ) ;
70+ /**
71+ * This check is needed to prevent more than one footer
72+ * from being appended to the shadow root.
73+ * Otherwise, iOS and MD enter animations would append
74+ * the footer twice.
75+ */
76+ const ionFooterAlreadyAppended = baseEl . shadowRoot ! . querySelector ( 'ion-footer' ) ;
77+ if ( ionFooter && ! ionFooterAlreadyAppended ) {
78+ const footerHeight = ionFooter . clientHeight ;
79+ const clonedFooter = ionFooter . cloneNode ( true ) as HTMLIonFooterElement ;
4780
48- const ionFooter = baseEl . querySelector ( 'ion-footer' ) ;
49- if ( ionFooter && footerAnimation ) {
50- const footerHeight = ionFooter . clientHeight ;
51- const clonedFooter = ionFooter . cloneNode ( true ) as HTMLElement ;
52- baseEl . shadowRoot ! . appendChild ( clonedFooter ) ;
53- ionFooter . remove ( ) ;
81+ baseEl . shadowRoot ! . appendChild ( clonedFooter ) ;
82+ ionFooter . style . setProperty ( 'display' , 'none' ) ;
83+ ionFooter . setAttribute ( 'aria-hidden' , 'true' ) ;
5484
55- // add padding bottom to the .ion-page element to be
56- // the same as the cloned footer height
57- const page = baseEl . querySelector ( '.ion-page' ) as HTMLElement ;
58- page . style . setProperty ( 'padding-bottom' , `${ footerHeight } px` ) ;
59- footerAnimation . addElement ( root . querySelector ( 'ion-footer' ) ! ) ;
85+ // Padding is added to prevent some content from being hidden.
86+ const page = baseEl . querySelector ( '.ion-page' ) as HTMLElement ;
87+ page . style . setProperty ( 'padding-bottom' , `${ footerHeight } px` ) ;
6088 }
61- } ) ;
89+ } ) ;
6290
63- if ( animateContentHeight && contentAnimation ) {
91+ if ( contentAnimation ) {
6492 baseAnimation . addAnimation ( contentAnimation ) ;
6593 }
6694
67- if ( animateContentHeight && footerAnimation ) {
68- baseAnimation . addAnimation ( footerAnimation ) ;
69- }
70-
7195 return baseAnimation ;
7296} ;
0 commit comments