88 type LayoutRectangle ,
99 Dimensions ,
1010 Platform ,
11- type LayoutChangeEvent ,
1211 InteractionManager ,
1312} from 'react-native' ;
1413
@@ -45,52 +44,55 @@ export const HighlightToolTip: React.FC<HighlightOverlayProps> = ({
4544 androidOffsetY = 0 ,
4645} ) => {
4746 const [ hole , setHole ] = useState < LayoutRectangle | null > ( null ) ;
48- const [ tooltipLayout , setTooltipLayout ] = useState < {
49- width : number ;
50- height : number ;
51- } | null > ( null ) ;
5247 const { width : screenWidth , height : screenHeight } = Dimensions . get ( 'window' ) ;
5348
5449 useEffect ( ( ) => {
5550 const task = InteractionManager . runAfterInteractions ( ( ) => {
56- if ( targetRef . current ) {
57- const handle = findNodeHandle ( targetRef . current ) ;
58- if ( handle ) {
59- UIManager . measureInWindow (
60- handle ,
61- ( x : number , y : number , width : number , height : number ) => {
62- const isAndroid = Platform . OS === 'android' ;
63- setHole ( {
64- x ,
65- y : isAndroid ? y + androidOffsetY : y ,
66- width ,
67- height ,
68- } ) ;
51+ if ( ! targetRef . current ) {
52+ return ;
53+ }
54+ const handle = findNodeHandle ( targetRef . current ) ;
55+ if ( handle ) {
56+ UIManager . measureInWindow (
57+ handle ,
58+ ( x : number , y : number , width : number , height : number ) => {
59+ if ( [ x , y , width , height ] . some ( ( val ) => isNaN ( val ) ) ) {
60+ console . warn (
61+ 'HighlightToolTip: Failed to measure target component.'
62+ ) ;
63+ return ;
6964 }
70- ) ;
71- }
65+
66+ const isAndroid = Platform . OS === 'android' ;
67+ setHole ( {
68+ x,
69+ y : isAndroid ? y + androidOffsetY : y ,
70+ width,
71+ height,
72+ } ) ;
73+ }
74+ ) ;
7275 }
7376 } ) ;
7477
75- return ( ) => task . cancel ( ) ;
78+ return ( ) => {
79+ task . cancel ( ) ;
80+ } ;
7681 } , [ targetRef , androidOffsetY ] ) ;
7782
78- const onTooltipLayout = ( event : LayoutChangeEvent ) => {
79- const { width, height } = event . nativeEvent . layout ;
80- if ( tooltipLayout ?. width !== width || tooltipLayout ?. height !== height ) {
81- setTooltipLayout ( { width, height } ) ;
82- }
83- } ;
84-
8583 const getTooltipPosition = ( ) => {
86- if ( ! hole || ! tooltipLayout ) {
87- return { top : 0 , left : 0 , opacity : 0 } ;
88- }
84+ if ( ! hole ) return { top : 0 , left : 0 } ;
8985
9086 const { x : offsetX = 0 , y : offsetY = 0 } = offset ;
91- const margin = allowOverlap ? - 4 : 24 ;
92- const { width : tooltipWidth , height : tooltipHeight } = tooltipLayout ;
87+ // Adjust margin based on allowOverlap - use larger margin to prevent overlap
88+ const margin = allowOverlap ? - 4 : 24 ; // Negative margin when overlap is allowed, otherwise larger margin
89+
90+ // Calculate tooltip size dynamically based on screen size
91+ const maxTooltipWidth = Math . min ( screenWidth * 0.8 , 320 ) ; // Max 80% of screen width or 320px
92+ const tooltipWidth = maxTooltipWidth ;
93+ const tooltipHeight = 120 ; // Adjust to actual height + extra space
9394
95+ // Calculate initial position
9496 let calculatedPosition = { top : 0 , left : 0 } ;
9597
9698 switch ( tooltipPosition ) {
@@ -167,26 +169,39 @@ export const HighlightToolTip: React.FC<HighlightOverlayProps> = ({
167169 } ;
168170 }
169171
172+ // Check screen boundaries and auto-adjust
170173 let { top, left } = calculatedPosition ;
174+
175+ // Fixed margin for screen boundary adjustment (always positive)
171176 const boundaryMargin = 16 ;
172177
178+ // Left boundary check
173179 if ( left < boundaryMargin ) {
174180 left = boundaryMargin ;
175181 }
176182
183+ // Right boundary check - ensure tooltip doesn't extend beyond screen
177184 if ( left + tooltipWidth > screenWidth - boundaryMargin ) {
178185 left = screenWidth - tooltipWidth - boundaryMargin ;
186+ // If still not enough space, adjust tooltip width
187+ if ( left < boundaryMargin ) {
188+ left = boundaryMargin ;
189+ }
179190 }
180191
192+ // Top boundary check
181193 if ( top < boundaryMargin ) {
194+ // If it goes above, move to bottom - maintain allowOverlap setting
182195 if ( tooltipPosition . includes ( 'top' ) ) {
183196 top = hole . y + hole . height + ( allowOverlap ? - 4 : 24 ) ;
184197 } else {
185198 top = boundaryMargin ;
186199 }
187200 }
188201
202+ // Bottom boundary check
189203 if ( top + tooltipHeight > screenHeight - boundaryMargin ) {
204+ // If it goes below, move to top - maintain allowOverlap setting
190205 if ( tooltipPosition . includes ( 'bottom' ) ) {
191206 top = hole . y - tooltipHeight - ( allowOverlap ? - 4 : 24 ) ;
192207 } else {
@@ -197,17 +212,11 @@ export const HighlightToolTip: React.FC<HighlightOverlayProps> = ({
197212 return {
198213 top : top + offsetY ,
199214 left : left + offsetX ,
200- opacity : 1 ,
201- maxWidth : screenWidth * 0.9 ,
215+ maxWidth : tooltipWidth ,
202216 } ;
203217 } ;
204218
205- const isHoleLayoutInvalid =
206- ! hole || [ hole . x , hole . y , hole . width , hole . height ] . some ( isNaN ) ;
207-
208- if ( isHoleLayoutInvalid ) {
209- return null ;
210- }
219+ if ( ! hole ) return null ;
211220
212221 const tooltipStyle = getTooltipPosition ( ) ;
213222
@@ -265,12 +274,10 @@ export const HighlightToolTip: React.FC<HighlightOverlayProps> = ({
265274
266275 { /* Tooltip */ }
267276 < View
268- onLayout = { onTooltipLayout }
269277 style = { {
270278 position : 'absolute' ,
271279 top : tooltipStyle . top ,
272280 left : tooltipStyle . left ,
273- opacity : tooltipStyle . opacity ,
274281 maxWidth : tooltipStyle . maxWidth ,
275282 } }
276283 >
0 commit comments