@@ -37,6 +37,13 @@ export interface PopoverStyles {
3737 arrowTop : number ;
3838 arrowLeft : number ;
3939 addPopoverBottomClass : boolean ;
40+ /**
41+ * When true, the popover content was too tall to fit above or below
42+ * the trigger, so it was constrained to the full viewport height.
43+ * In this case, the arrow should be hidden as it cannot accurately
44+ * point to the trigger.
45+ */
46+ isFullyConstrained : boolean ;
4047}
4148
4249/**
@@ -835,6 +842,7 @@ export const calculateWindowAdjustment = (
835842 let checkSafeAreaBottom = false ;
836843 let checkSafeAreaLeft = false ;
837844 let checkSafeAreaRight = false ;
845+ let isFullyConstrained = false ;
838846 const triggerTop = triggerCoordinates
839847 ? triggerCoordinates . top + triggerCoordinates . height
840848 : bodyHeight / 2 - contentHeight / 2 ;
@@ -845,20 +853,29 @@ export const calculateWindowAdjustment = (
845853 * Adjust popover so it does not
846854 * go off the left of the screen.
847855 */
848- if ( left < bodyPadding + safeAreaMargin ) {
856+ if ( left < bodyPadding ) {
849857 left = bodyPadding ;
850- checkSafeAreaLeft = true ;
851858 originX = 'left' ;
852859 /**
853860 * Adjust popover so it does not
854861 * go off the right of the screen.
855862 */
856- } else if ( contentWidth + bodyPadding + left + safeAreaMargin > bodyWidth ) {
857- checkSafeAreaRight = true ;
863+ } else if ( contentWidth + bodyPadding + left > bodyWidth ) {
858864 left = bodyWidth - contentWidth - bodyPadding ;
859865 originX = 'right' ;
860866 }
861867
868+ /**
869+ * After position adjustment, check if popover is near edges
870+ * and needs safe-area CSS variable adjustments.
871+ */
872+ if ( left <= safeAreaMargin ) {
873+ checkSafeAreaLeft = true ;
874+ }
875+ if ( left + contentWidth >= bodyWidth - safeAreaMargin ) {
876+ checkSafeAreaRight = true ;
877+ }
878+
862879 /**
863880 * Adjust popover so it does not
864881 * go off the top of the screen.
@@ -894,16 +911,16 @@ export const calculateWindowAdjustment = (
894911
895912 /**
896913 * If not enough room for popover to appear
897- * above trigger, then cut it off.
914+ * above trigger, constrain to full viewport.
915+ * Pin both top and bottom to maximize visible area
916+ * and let the content scroll within those bounds.
898917 */
899918 } else {
919+ top = bodyPadding ;
900920 bottom = bodyPadding ;
901- /**
902- * When the popover is pinned to the bottom, account for safe area.
903- * This ensures the popover doesn't overlap with home indicators
904- * or navigation bars (e.g., Android API 36+ edge-to-edge).
905- */
921+ checkSafeAreaTop = true ;
906922 checkSafeAreaBottom = true ;
923+ isFullyConstrained = true ;
907924 }
908925 }
909926
@@ -934,6 +951,7 @@ export const calculateWindowAdjustment = (
934951 arrowTop,
935952 arrowLeft,
936953 addPopoverBottomClass,
954+ isFullyConstrained,
937955 } ;
938956} ;
939957
0 commit comments