From 11b2debedc1c4c9f14c3af4d237ae44a740e0311 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 1 Oct 2026 15:36:57 +0900 Subject: [PATCH] feat: accept an explicit vertical popover offset --- src/popover/animations/ios.enter.ts | 3 +++ src/popover/utils.spec.ts | 21 +++++++++++++++++++++ src/popover/utils.ts | 3 ++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/popover/animations/ios.enter.ts b/src/popover/animations/ios.enter.ts index 8d68957..e0e9c2e 100644 --- a/src/popover/animations/ios.enter.ts +++ b/src/popover/animations/ios.enter.ts @@ -8,6 +8,8 @@ const POPOVER_IOS_BODY_PADDING = 5; /** * iOS Popover Enter Animation + * `opts.verticalOffset` overrides the non-replacing surface offset in CSS pixels. + * Omit it to use the theme's default body margin. */ // TODO(FW-2832): types export const iosEnterAnimation = (baseEl: HTMLElement, opts: any = {}): Animation => { @@ -102,6 +104,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts: any = {}): Animatio results.referenceCoordinates, referenceSizeEl?.getBoundingClientRect(), isReplace, + opts.verticalOffset, ); // A replacing surface grows inward from the button's edge, not its center. const preferredLeft = diff --git a/src/popover/utils.spec.ts b/src/popover/utils.spec.ts index cd7a117..03f4999 100644 --- a/src/popover/utils.spec.ts +++ b/src/popover/utils.spec.ts @@ -3,6 +3,27 @@ import { describe, expect, it } from 'vitest'; import { calculateWindowAdjustment, getIndexOfItem, getNextItem, getPopoverPosition, getPrevItem } from './utils.js'; describe('popover utilities', () => { + it.each([undefined, 0, 3, -2])('uses verticalOffset=%s without fixing the caller to the default margin', (offset) => { + const position = calculateWindowAdjustment( + 'right', + 120, + 100, + 5, + 440, + 636, + 200, + 52, + 8, + 'right', + 'center', + undefined, + undefined, + false, + offset, + ); + expect(position.top).toBe(120 + (offset ?? 8)); + }); + it('navigates only relative to ion-item elements', () => { const items = [document.createElement('ion-item'), document.createElement('ion-item')] as HTMLIonItemElement[]; diff --git a/src/popover/utils.ts b/src/popover/utils.ts index ed30ce9..c4dcd43 100644 --- a/src/popover/utils.ts +++ b/src/popover/utils.ts @@ -612,11 +612,12 @@ export const calculateWindowAdjustment = ( triggerCoordinates?: ReferenceCoordinates, eventElementRect?: DOMRect, isReplace: boolean = false, + verticalOffset: number = POPOVER_IOS_BODY_MARGIN, ): PopoverStyles => { const triggerTop = triggerCoordinates ? triggerCoordinates.top + triggerCoordinates.height : bodyHeight / 2 - contentHeight / 2; const triggerHeight = triggerCoordinates ? triggerCoordinates.height : 0; let left = coordLeft; - let top = !isReplace ? coordTop + POPOVER_IOS_BODY_MARGIN : coordTop - triggerHeight; + let top = !isReplace ? coordTop + verticalOffset : coordTop - triggerHeight; let bottom; let originX = contentOriginX; let originY = contentOriginY;