import * as React from 'react' ; import type { ViewProps } from 'react-native' ; import Animated , { useAnimatedStyle , useSharedValue , } from 'react-native-reanimated' ; import { LineChartDimensionsContext } from './Chart' ; import { CursorContext } from './Cursor' ; import { LineChartPriceText , LineChartPriceTextProps } from './PriceText' ; import { useLineChart } from './useLineChart' ; type LineChartTooltipProps = Animated . AnimateProps < ViewProps > & { children ? : React . ReactNode ; xGutter ? : number ; yGutter ? : number ; cursorGutter ? : number ; position ? : 'top' | 'bottom' ; textProps ? : LineChartPriceTextProps ; textStyle ? : LineChartPriceTextProps [ 'style' ] ; } ; LineChartTooltip . displayName = 'LineChartTooltip' ; export function LineChartTooltip ( { children , xGutter = 8 , yGutter = 8 , cursorGutter = 48 , position = 'top' , textProps , textStyle , ... props } ) { const { width , height } = React . useContext ( LineChartDimensionsContext ) ; const { type } = React . useContext ( CursorContext ) ; const { currentX , currentY , isActive } = useLineChart ( ) ; const x = useSharedValue ( 0 ) ; const elementWidth = useSharedValue ( 0 ) ; const elementHeight = useSharedValue ( 0 ) ; const handleLayout = React . useCallback ( ( event ) => { x . value = event . nativeEvent . layout . x ; elementWidth . value = event . nativeEvent . layout . width ; elementHeight . value = event . nativeEvent . layout . height ; } , [ elementHeight , elementWidth , x ] ) ; const animatedCursorStyle = useAnimatedStyle ( ( ) => { let translateXOffset = elementWidth . value / 2 ; if ( currentX . value < elementWidth . value / 2 + xGutter ) { const xOffset = elementWidth . value / 2 + xGutter - currentX . value ; translateXOffset = translateXOffset - xOffset ; } if ( currentX . value > width - elementWidth . value / 2 - xGutter ) { const xOffset = currentX . value - ( width - elementWidth . value / 2 - xGutter ) ; translateXOffset = translateXOffset + xOffset ; } let translateYOffset = 0 ; if ( position === 'top' ) { translateYOffset = elementHeight . value / 2 + cursorGutter ; if ( currentY . value - translateYOffset < yGutter ) { translateYOffset = currentY . value - yGutter ; } } else if ( position === 'bottom' ) { translateYOffset = - ( elementHeight . value / 2 ) - cursorGutter / 2 ; if ( currentY . value - translateYOffset + elementHeight . value > height - yGutter ) { translateYOffset = currentY . value - ( height - yGutter ) + elementHeight . value ; } } return { transform : [ { translateX : currentX . value - translateXOffset } , { translateY : type === 'crosshair' ? currentY . value - translateYOffset : position === 'top' ? yGutter : height - elementHeight . value - yGutter , } , ] , opacity : isActive . value ? 1 : 0 , } ; } ) ; return ( < Animated . View onLayout = { handleLayout } { ... props } style = { [ { position : 'absolute' , padding : 4 , alignSelf : 'flex-start' , } , animatedCursorStyle , props . style , ] } > { children || < LineChartPriceText style = { [ textStyle ] } { ... textProps } />} < /Animated.View>); }