diff --git a/core/src/components/modal/gestures/sheet.ts b/core/src/components/modal/gestures/sheet.ts index afac8f3d3ed..a9f7855e4d4 100644 --- a/core/src/components/modal/gestures/sheet.ts +++ b/core/src/components/modal/gestures/sheet.ts @@ -52,7 +52,8 @@ export const createSheetGesture = ( expandToScroll: boolean, getCurrentBreakpoint: () => number, onDismiss: () => void, - onBreakpointChange: (breakpoint: number) => void + onBreakpointChange: (breakpoint: number) => void, + onGestureMove?: () => void ) => { // Defaults for the sheet swipe animation const defaultBackdrop = [ @@ -423,6 +424,9 @@ export const createSheetGesture = ( offset = clamp(0.0001, processedStep, maxStep); animation.progressStep(offset); + + // Notify modal of position change for safe-area updates + onGestureMove?.(); }; const onEnd = (detail: GestureDetail) => { diff --git a/core/src/components/modal/gestures/swipe-to-close.ts b/core/src/components/modal/gestures/swipe-to-close.ts index 17ec454ff15..c81a6a6ba21 100644 --- a/core/src/components/modal/gestures/swipe-to-close.ts +++ b/core/src/components/modal/gestures/swipe-to-close.ts @@ -20,7 +20,8 @@ export const createSwipeToCloseGesture = ( el: HTMLIonModalElement, animation: Animation, statusBarStyle: StatusBarStyle, - onDismiss: () => void + onDismiss: () => void, + onGestureMove?: () => void ) => { /** * The step value at which a card modal @@ -199,6 +200,9 @@ export const createSwipeToCloseGesture = ( animation.progressStep(clampedStep); + // Notify modal of position change for safe-area updates + onGestureMove?.(); + /** * When swiping down half way, the status bar style * should be reset to its default value. diff --git a/core/src/components/modal/modal.scss b/core/src/components/modal/modal.scss index 7c5ec7916fe..ac4cb533b48 100644 --- a/core/src/components/modal/modal.scss +++ b/core/src/components/modal/modal.scss @@ -94,10 +94,6 @@ ion-backdrop { :host { --width: #{$modal-inset-width}; --height: #{$modal-inset-height-small}; - --ion-safe-area-top: 0px; - --ion-safe-area-bottom: 0px; - --ion-safe-area-right: 0px; - --ion-safe-area-left: 0px; } } diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index 174ac2f9d8a..73639da0588 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -276,7 +276,10 @@ export class Modal implements ComponentInterface, OverlayInterface { @Listen('resize', { target: 'window' }) onWindowResize() { - // Only handle resize for iOS card modals when no custom animations are provided + // Update safe-area overrides for all modal types on resize + this.updateSafeAreaOverrides(); + + // Only handle view transition for iOS card modals when no custom animations are provided if (getIonMode(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) { return; } @@ -592,6 +595,9 @@ export class Modal implements ComponentInterface, OverlayInterface { await waitForMount(); } + // Predict safe-area needs based on modal configuration to avoid visual snap + this.setInitialSafeAreaOverrides(presentingElement); + writeTask(() => this.el.classList.add('show-modal')); const hasCardModal = presentingElement !== undefined; @@ -659,6 +665,9 @@ export class Modal implements ComponentInterface, OverlayInterface { this.initSwipeToClose(); } + // Now that animation is complete, update safe-area based on actual position + this.updateSafeAreaOverrides(); + // Initialize view transition listener for iOS card modals this.initViewTransitionListener(); @@ -692,33 +701,39 @@ export class Modal implements ComponentInterface, OverlayInterface { const statusBarStyle = this.statusBarStyle ?? StatusBarStyle.Default; - this.gesture = createSwipeToCloseGesture(el, ani, statusBarStyle, () => { - /** - * While the gesture animation is finishing - * it is possible for a user to tap the backdrop. - * This would result in the dismiss animation - * being played again. Typically this is avoided - * by setting `presented = false` on the overlay - * component; however, we cannot do that here as - * that would prevent the element from being - * removed from the DOM. - */ - this.gestureAnimationDismissing = true; - - /** - * Reset the status bar style as the dismiss animation - * starts otherwise the status bar will be the wrong - * color for the duration of the dismiss animation. - * The dismiss method does this as well, but - * in this case it's only called once the animation - * has finished. - */ - setCardStatusBarDefault(this.statusBarStyle); - this.animation!.onFinish(async () => { - await this.dismiss(undefined, GESTURE); - this.gestureAnimationDismissing = false; - }); - }); + this.gesture = createSwipeToCloseGesture( + el, + ani, + statusBarStyle, + () => { + /** + * While the gesture animation is finishing + * it is possible for a user to tap the backdrop. + * This would result in the dismiss animation + * being played again. Typically this is avoided + * by setting `presented = false` on the overlay + * component; however, we cannot do that here as + * that would prevent the element from being + * removed from the DOM. + */ + this.gestureAnimationDismissing = true; + + /** + * Reset the status bar style as the dismiss animation + * starts otherwise the status bar will be the wrong + * color for the duration of the dismiss animation. + * The dismiss method does this as well, but + * in this case it's only called once the animation + * has finished. + */ + setCardStatusBarDefault(this.statusBarStyle); + this.animation!.onFinish(async () => { + await this.dismiss(undefined, GESTURE); + this.gestureAnimationDismissing = false; + }); + }, + () => this.updateSafeAreaOverrides() + ); this.gesture.enable(true); } @@ -755,7 +770,9 @@ export class Modal implements ComponentInterface, OverlayInterface { this.currentBreakpoint = breakpoint; this.ionBreakpointDidChange.emit({ breakpoint }); } - } + this.updateSafeAreaOverrides(); + }, + () => this.updateSafeAreaOverrides() ); this.gesture = gesture; @@ -849,6 +866,86 @@ export class Modal implements ComponentInterface, OverlayInterface { this.cachedPageParent = undefined; } + /** + * Sets initial safe-area overrides based on modal configuration before + * the modal becomes visible. This predicts whether the modal will touch + * screen edges to avoid a visual snap after animation completes. + */ + private setInitialSafeAreaOverrides(presentingElement: HTMLElement | undefined) { + const style = this.el.style; + const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined; + const isCardModal = presentingElement !== undefined; + const isTablet = window.innerWidth >= 768; + + // Sheet modals: always touch bottom, top depends on breakpoint + if (isSheetModal) { + style.setProperty('--ion-safe-area-top', '0px'); + // Don't override bottom - sheet always touches bottom + style.setProperty('--ion-safe-area-left', '0px'); + style.setProperty('--ion-safe-area-right', '0px'); + return; + } + + // Card modals are inset from edges (rounded corners), no safe areas needed + if (isCardModal) { + style.setProperty('--ion-safe-area-top', '0px'); + style.setProperty('--ion-safe-area-bottom', '0px'); + style.setProperty('--ion-safe-area-left', '0px'); + style.setProperty('--ion-safe-area-right', '0px'); + return; + } + + // Phone modals are fullscreen, need all safe areas + if (!isTablet) { + // Don't set any overrides - inherit from :root + return; + } + + // Default tablet modal: centered dialog, no safe areas needed + // Check for fullscreen override via CSS custom properties + const computedStyle = getComputedStyle(this.el); + const width = computedStyle.getPropertyValue('--width').trim(); + const height = computedStyle.getPropertyValue('--height').trim(); + + if (width === '100%' && height === '100%') { + // Fullscreen modal - need safe areas, don't override + return; + } + + // Centered dialog - zero out all safe areas + style.setProperty('--ion-safe-area-top', '0px'); + style.setProperty('--ion-safe-area-bottom', '0px'); + style.setProperty('--ion-safe-area-left', '0px'); + style.setProperty('--ion-safe-area-right', '0px'); + } + + /** + * Updates safe-area CSS variable overrides based on whether the modal + * is touching each edge of the viewport. This is called after animation + * and during gestures to handle dynamic position changes. + */ + private updateSafeAreaOverrides() { + const wrapper = this.wrapperEl; + if (!wrapper) return; + + const rect = wrapper.getBoundingClientRect(); + const threshold = 2; // Account for subpixel rendering + + const touchingTop = rect.top <= threshold; + const touchingBottom = rect.bottom >= window.innerHeight - threshold; + const touchingLeft = rect.left <= threshold; + const touchingRight = rect.right >= window.innerWidth - threshold; + + // Remove override when touching edge (allow inheritance), set to 0 when not touching + const style = this.el.style; + touchingTop ? style.removeProperty('--ion-safe-area-top') : style.setProperty('--ion-safe-area-top', '0px'); + touchingBottom + ? style.removeProperty('--ion-safe-area-bottom') + : style.setProperty('--ion-safe-area-bottom', '0px'); + touchingLeft ? style.removeProperty('--ion-safe-area-left') : style.setProperty('--ion-safe-area-left', '0px'); + touchingRight ? style.removeProperty('--ion-safe-area-right') : style.setProperty('--ion-safe-area-right', '0px'); + } + private sheetOnDismiss() { /** * While the gesture animation is finishing diff --git a/core/src/components/modal/test/safe-area/index.html b/core/src/components/modal/test/safe-area/index.html new file mode 100644 index 00000000000..a1e2490dee4 --- /dev/null +++ b/core/src/components/modal/test/safe-area/index.html @@ -0,0 +1,175 @@ + + + + + Modal - Safe Area + + + + + + + + + + + +
+ + + Modal - Safe Area + + + + +

Test safe-area handling in modals on tablet-sized screens.

+ + + + +

Default Modal

+

Centered dialog on tablet - should NOT have safe-area padding

+
+ Present +
+ + + +

Fullscreen Modal

+

Full screen on tablet - should have safe-area padding

+
+ Present +
+ + + +

Sheet Modal (Partial)

+

At 0.5 breakpoint - should have bottom safe-area only

+
+ Present +
+ + + +

Sheet Modal (Full)

+

At 1.0 breakpoint - should have bottom safe-area (handle creates top gap)

+
+ Present +
+ + + +

Card Modal (iOS)

+

Card presentation - inset from edges, no safe-area padding

+
+ Present +
+
+
+
+
+ + + + diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts b/core/src/components/modal/test/safe-area/modal.e2e.ts new file mode 100644 index 00000000000..54308da3679 --- /dev/null +++ b/core/src/components/modal/test/safe-area/modal.e2e.ts @@ -0,0 +1,106 @@ +import { expect } from '@playwright/test'; +import { configs, test, Viewports } from '@utils/test/playwright'; + +/** + * Safe-area tests verify that modals correctly handle safe-area insets + * based on whether they're touching the screen edges. + */ + +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('modal: safe-area - tablet'), () => { + test.beforeEach(async ({ page }) => { + await page.setViewportSize(Viewports.tablet.portrait); + await page.goto('/src/components/modal/test/safe-area', config); + }); + + test('default modal should not have safe-area padding on tablet', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#default-modal'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-default-tablet`)); + }); + + test('fullscreen modal should have safe-area padding on tablet', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#fullscreen-modal'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-fullscreen-tablet`)); + }); + + test('sheet modal at partial breakpoint should have bottom safe-area only', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#sheet-modal-partial'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-sheet-partial-tablet`)); + }); + + test('sheet modal at full breakpoint should have bottom safe-area', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#sheet-modal-full'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-sheet-full-tablet`)); + }); + }); +}); + +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('modal: safe-area - card modal'), () => { + test.beforeEach(async ({ page }) => { + await page.setViewportSize(Viewports.tablet.portrait); + await page.goto('/src/components/modal/test/safe-area', config); + }); + + test('card modal should not have safe-area padding', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#card-modal'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-card-tablet`)); + }); + }); +}); + +configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('modal: safe-area - tablet (MD mode)'), () => { + test.beforeEach(async ({ page }) => { + await page.setViewportSize(Viewports.tablet.portrait); + await page.goto('/src/components/modal/test/safe-area', config); + }); + + test('default modal should not have safe-area padding on tablet', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#default-modal'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-default-tablet`)); + }); + + test('fullscreen modal should have safe-area padding on tablet', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#fullscreen-modal'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-fullscreen-tablet`)); + }); + + test('sheet modal at full breakpoint should have bottom safe-area', async ({ page }) => { + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + + await page.click('#sheet-modal-full'); + await ionModalDidPresent.next(); + + await expect(page).toHaveScreenshot(screenshot(`modal-safe-area-sheet-full-tablet`)); + }); + }); +}); diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..3b3d61f0cc0 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..d4382fd040d Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..baa00f0341b Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-card-tablet-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..b2fecbb0fdc Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..db891951d8b Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..49f5b0864b3 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..ea089882f87 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..0df0d931480 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..9e9a3c19098 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-default-tablet-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..74ec7dc3a38 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..65ab9784735 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..d464ee43d2d Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..a7ce9d2acc1 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..cc8506bce00 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..75671eee08f Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-fullscreen-tablet-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..413829550ad Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..56e510de598 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..c02d6c45629 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..61bc3e8821b Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..257d82b40ec Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..252eb46d25a Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-full-tablet-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..413829550ad Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..56e510de598 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Safari-linux.png b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 00000000000..c02d6c45629 Binary files /dev/null and b/core/src/components/modal/test/safe-area/modal.e2e.ts-snapshots/modal-safe-area-sheet-partial-tablet-ios-ltr-Mobile-Safari-linux.png differ