@@ -6,20 +6,12 @@ import {
66 View ,
77} from 'react-native' ;
88
9+ import { POSITION , Position } from '../../constants' ;
910import { Theme , withTheme } from '../../theme' ;
1011import { PopoverStyles } from '../../theme/style-getters/getPopoverStyles' ;
1112import Modal from '../Dialog/Modal' ;
1213import { LayoutMeasure , LayoutMeasurements } from '../Helpers' ;
13-
14- export type Position =
15- | 'top-left'
16- | 'top'
17- | 'top-right'
18- | 'left'
19- | 'right'
20- | 'bottom-right'
21- | 'bottom'
22- | 'bottom-left' ;
14+ import { getPopoverArrow } from './getPopoverArrow' ;
2315
2416export interface PopoverProps {
2517 theme : Theme ;
@@ -55,26 +47,38 @@ const resolveCorrectPosition = (position: Position) => ({
5547} ) => {
5648 let newPosition = position ;
5749
58- if ( position . includes ( 'bottom' ) && shouldFlipBottomToTop ) {
59- newPosition = newPosition . replace ( 'bottom' , 'top' ) as 'top' ;
50+ if ( position . includes ( POSITION . BOTTOM ) && shouldFlipBottomToTop ) {
51+ newPosition = newPosition . replace (
52+ POSITION . BOTTOM ,
53+ POSITION . TOP ,
54+ ) as Position ;
6055 }
6156
62- if ( position . includes ( 'top' ) && shouldFlipTopToBottom ) {
63- newPosition = newPosition . replace ( 'top' , 'bottom' ) as 'bottom' ;
57+ if ( position . includes ( POSITION . TOP ) && shouldFlipTopToBottom ) {
58+ newPosition = newPosition . replace (
59+ POSITION . TOP ,
60+ POSITION . BOTTOM ,
61+ ) as Position ;
6462 }
6563
66- if ( position . includes ( 'left' ) && shouldFlipLeftToRight ) {
67- newPosition = newPosition . replace ( 'left' , 'right' ) as 'right' ;
64+ if ( position . includes ( POSITION . LEFT ) && shouldFlipLeftToRight ) {
65+ newPosition = newPosition . replace (
66+ POSITION . LEFT ,
67+ POSITION . RIGHT ,
68+ ) as Position ;
6869 }
6970
70- if ( position . includes ( 'right' ) && shouldFlipRightToLeft ) {
71- newPosition = newPosition . replace ( 'right' , 'left' ) as 'left' ;
71+ if ( position . includes ( POSITION . RIGHT ) && shouldFlipRightToLeft ) {
72+ newPosition = newPosition . replace (
73+ POSITION . RIGHT ,
74+ POSITION . LEFT ,
75+ ) as Position ;
7276 }
7377
7478 return newPosition ;
7579} ;
7680
77- const getPositionCoordinates = ( position : Position ) => (
81+ const getPopoverPosition = ( position : Position ) => (
7882 screenLayout : ScaledSize ,
7983) => ( targetMeasurements : LayoutMeasurements ) => (
8084 popoverMeasurements : LayoutMeasurements ,
@@ -87,12 +91,12 @@ const getPositionCoordinates = (position: Position) => (
8791 targetMeasurements . height -
8892 offset ,
8993 shouldFlipLeftToRight :
90- position === 'left'
94+ position === POSITION . LEFT
9195 ? popoverMeasurements . width + offset > targetMeasurements . pageX - offset
9296 : popoverMeasurements . width + offset >
9397 screenLayout . width - targetMeasurements . pageX ,
9498 shouldFlipRightToLeft :
95- position === 'right'
99+ position === POSITION . RIGHT
96100 ? targetMeasurements . pageX +
97101 targetMeasurements . width +
98102 popoverMeasurements . width +
@@ -105,13 +109,17 @@ const getPositionCoordinates = (position: Position) => (
105109 } ) ;
106110
107111 switch ( newPosition ) {
108- case 'top-left' :
112+ case POSITION . TOP_LEFT :
109113 return {
114+ position : POSITION . TOP_LEFT ,
115+
110116 left : targetMeasurements . pageX ,
111117 top : targetMeasurements . pageY - popoverMeasurements . height - offset ,
112118 } ;
113- case 'top' :
119+ case POSITION . TOP :
114120 return {
121+ position : POSITION . TOP ,
122+
115123 left : targetMeasurements . pageX ,
116124 top : targetMeasurements . pageY - popoverMeasurements . height - offset ,
117125 transform : [
@@ -121,16 +129,20 @@ const getPositionCoordinates = (position: Position) => (
121129 } ,
122130 ] ,
123131 } ;
124- case 'top-right' :
132+ case POSITION . TOP_RIGHT :
125133 return {
134+ position : POSITION . TOP_RIGHT ,
135+
126136 left :
127137 targetMeasurements . pageX -
128138 popoverMeasurements . width +
129139 targetMeasurements . width ,
130140 top : targetMeasurements . pageY - popoverMeasurements . height - offset ,
131141 } ;
132- case 'left' :
142+ case POSITION . LEFT :
133143 return {
144+ position : POSITION . LEFT ,
145+
134146 left : targetMeasurements . pageX - popoverMeasurements . width - offset ,
135147 top : targetMeasurements . pageY ,
136148 transform : [
@@ -140,8 +152,10 @@ const getPositionCoordinates = (position: Position) => (
140152 } ,
141153 ] ,
142154 } ;
143- case 'right' :
155+ case POSITION . RIGHT :
144156 return {
157+ position : POSITION . RIGHT ,
158+
145159 left : targetMeasurements . pageX + targetMeasurements . width + offset ,
146160 top : targetMeasurements . pageY ,
147161 transform : [
@@ -151,16 +165,20 @@ const getPositionCoordinates = (position: Position) => (
151165 } ,
152166 ] ,
153167 } ;
154- case 'bottom-right' :
168+ case POSITION . BOTTOM_RIGHT :
155169 return {
170+ position : POSITION . BOTTOM_RIGHT ,
171+
156172 left :
157173 targetMeasurements . pageX -
158174 popoverMeasurements . width +
159175 targetMeasurements . width ,
160176 top : targetMeasurements . pageY + targetMeasurements . height + offset ,
161177 } ;
162- case 'bottom' :
178+ case POSITION . BOTTOM :
163179 return {
180+ position : POSITION . BOTTOM ,
181+
164182 left : targetMeasurements . pageX ,
165183 top : targetMeasurements . pageY + targetMeasurements . height + offset ,
166184 transform : [
@@ -170,13 +188,17 @@ const getPositionCoordinates = (position: Position) => (
170188 } ,
171189 ] ,
172190 } ;
173- case 'bottom-left' :
191+ case POSITION . BOTTOM_LEFT :
174192 return {
193+ position : POSITION . BOTTOM_LEFT ,
194+
175195 left : targetMeasurements . pageX ,
176196 top : targetMeasurements . pageY + targetMeasurements . height + offset ,
177197 } ;
178198 default :
179- return { } ;
199+ return {
200+ position : POSITION . BOTTOM_RIGHT ,
201+ } ;
180202 }
181203} ;
182204
@@ -217,31 +239,32 @@ class PopoverBase extends React.Component<PopoverProps, PopoverState> {
217239 parentHeight,
218240 isVisible,
219241 onClose,
220- position = 'bottom' ,
242+ position = POSITION . BOTTOM ,
221243 offset = 14 ,
222244 } = this . props ;
223245 const { popoverMeasurements, targetMeasurements } = this . state ;
224246 const {
225- containerStyle,
226247 popoverStyle,
227248 modalContainerStyle,
228249 overlayStyle,
229250 } = theme . getPopoverStyles ( ) ;
230251
231252 const windowDimensions = Dimensions . get ( 'window' ) ;
232- const positionCoordinates = getPositionCoordinates ( position ) ( {
253+ const {
254+ position : correctedPosition ,
255+ ...popoverPositionStyle
256+ } = getPopoverPosition ( position ) ( {
233257 ...windowDimensions ,
234258 height : parentHeight || windowDimensions . height ,
235259 } ) ( targetMeasurements ) ( popoverMeasurements ) ( offset ) ;
236260
261+ const renderArrow = getPopoverArrow ( correctedPosition ) ( targetMeasurements ) (
262+ theme ,
263+ ) ;
264+
237265 return (
238266 < >
239267 < LayoutMeasure
240- style = { {
241- ...containerStyle ,
242- ...( dangerouslySetInlineStyle &&
243- dangerouslySetInlineStyle . containerStyle ) ,
244- } }
245268 onMeasure = { measurements =>
246269 this . setState ( { targetMeasurements : measurements } )
247270 }
@@ -266,7 +289,7 @@ class PopoverBase extends React.Component<PopoverProps, PopoverState> {
266289 ...popoverStyle ,
267290 ...( dangerouslySetInlineStyle &&
268291 dangerouslySetInlineStyle . popoverStyle ) ,
269- ...positionCoordinates ,
292+ ...popoverPositionStyle ,
270293 // Hide flash mis-positioned content
271294 opacity :
272295 popoverMeasurements . width === 0 ||
@@ -279,6 +302,7 @@ class PopoverBase extends React.Component<PopoverProps, PopoverState> {
279302 }
280303 >
281304 { content }
305+ { renderArrow }
282306 </ LayoutMeasure >
283307 < TouchableWithoutFeedback
284308 onPress = { ( ) => {
0 commit comments