diff --git a/core/src/components/popover/test/adjustment/index.html b/core/src/components/popover/test/adjustment/index.html new file mode 100644 index 00000000000..78d8dc105a6 --- /dev/null +++ b/core/src/components/popover/test/adjustment/index.html @@ -0,0 +1,59 @@ + + + + + Popover - Adjustment + + + + + + + + + + + +

Click everywhere to open the popover.

+
+
+ + + + diff --git a/core/src/components/popover/test/adjustment/popover.e2e.ts b/core/src/components/popover/test/adjustment/popover.e2e.ts new file mode 100644 index 00000000000..77a0386cb32 --- /dev/null +++ b/core/src/components/popover/test/adjustment/popover.e2e.ts @@ -0,0 +1,32 @@ +import { expect } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('popover: adjustment', async () => { + test('should not render the popover offscreen', async ({ page }) => { + await page.goto('/src/components/popover/test/adjustment'); + + /** + * We need to click in an area where + * there is not enough room to show the popover + * below the click coordinates but not enough + * room above the click coordinates that we + * can just move the popover to without it going + * offscreen. + */ + await page.setViewportSize({ + width: 500, + height: 400, + }); + + const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent'); + + await page.mouse.click(300, 300); + + await ionPopoverDidPresent.next(); + + const popoverContent = page.locator('ion-popover .popover-content'); + const box = (await popoverContent.boundingBox())!; + + expect(box.y > 0).toBe(true); + }); +}); diff --git a/core/src/components/popover/utils.ts b/core/src/components/popover/utils.ts index 3457379591c..363db25c520 100644 --- a/core/src/components/popover/utils.ts +++ b/core/src/components/popover/utils.ts @@ -863,7 +863,17 @@ export const calculateWindowAdjustment = ( */ if (triggerTop + triggerHeight + contentHeight > bodyHeight && (side === 'top' || side === 'bottom')) { if (triggerTop - contentHeight > 0) { - top = triggerTop - contentHeight - triggerHeight - (arrowHeight - 1); + /** + * While we strive to align the popover with the trigger + * on smaller screens this is not always possible. As a result, + * we adjust the popover up so that it does not hang + * off the bottom of the screen. However, we do not want to move + * the popover up so much that it goes off the top of the screen. + * + * We chose 12 here so that the popover position looks a bit nicer as + * it is not right up against the edge of the screen. + */ + top = Math.max(12, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1)); arrowTop = top + contentHeight; originY = 'bottom'; addPopoverBottomClass = true;