Changeset View
Changeset View
Standalone View
Standalone View
native/tooltip/tooltip.react.js
// @flow | // @flow | ||||
import type { RouteProp } from '@react-navigation/native'; | import type { RouteProp } from '@react-navigation/native'; | ||||
import * as Haptics from 'expo-haptics'; | import * as Haptics from 'expo-haptics'; | ||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { | import { | ||||
View, | View, | ||||
TouchableWithoutFeedback, | TouchableWithoutFeedback, | ||||
Platform, | Platform, | ||||
Keyboard, | Keyboard, | ||||
} from 'react-native'; | } from 'react-native'; | ||||
import Animated, { SlideInDown, SlideOutDown } from 'react-native-reanimated'; | import Animated from 'react-native-reanimated'; | ||||
import { | import { | ||||
TooltipContextProvider, | TooltipContextProvider, | ||||
TooltipContext, | TooltipContext, | ||||
type TooltipContextType, | type TooltipContextType, | ||||
} from './tooltip-context.react.js'; | } from './tooltip-context.react.js'; | ||||
import BaseTooltipItem, { | import BaseTooltipItem, { | ||||
type TooltipItemBaseProps, | type TooltipItemBaseProps, | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | ): React.ComponentType<BaseTooltipPropsType> { | ||||
> { | > { | ||||
backdropOpacity: Node; | backdropOpacity: Node; | ||||
tooltipContainerOpacity: Node; | tooltipContainerOpacity: Node; | ||||
tooltipVerticalAbove: Node; | tooltipVerticalAbove: Node; | ||||
tooltipVerticalBelow: Node; | tooltipVerticalBelow: Node; | ||||
tooltipHorizontalOffset: Value = new Value(0); | tooltipHorizontalOffset: Value = new Value(0); | ||||
tooltipHorizontal: Node; | tooltipHorizontal: Node; | ||||
tooltipScale: Node; | tooltipScale: Node; | ||||
fixedTooltipVertical: Node; | |||||
constructor(props: TooltipProps<BaseTooltipPropsType>) { | constructor(props: TooltipProps<BaseTooltipPropsType>) { | ||||
super(props); | super(props); | ||||
const { overlayContext } = props; | const { overlayContext } = props; | ||||
invariant(overlayContext, 'Tooltip should have OverlayContext'); | invariant(overlayContext, 'Tooltip should have OverlayContext'); | ||||
const { position } = overlayContext; | const { position } = overlayContext; | ||||
Show All 15 Lines | constructor(props: TooltipProps<BaseTooltipPropsType>) { | ||||
extrapolate: Extrapolate.CLAMP, | extrapolate: Extrapolate.CLAMP, | ||||
}); | }); | ||||
this.tooltipVerticalBelow = interpolateNode(position, { | this.tooltipVerticalBelow = interpolateNode(position, { | ||||
inputRange: [0, 1], | inputRange: [0, 1], | ||||
outputRange: [-margin - this.tooltipHeight / 2, 0], | outputRange: [-margin - this.tooltipHeight / 2, 0], | ||||
extrapolate: Extrapolate.CLAMP, | extrapolate: Extrapolate.CLAMP, | ||||
}); | }); | ||||
const invertedPosition = add(1, multiply(-1, position)); | |||||
this.tooltipHorizontal = multiply( | this.tooltipHorizontal = multiply( | ||||
add(1, multiply(-1, position)), | invertedPosition, | ||||
this.tooltipHorizontalOffset, | this.tooltipHorizontalOffset, | ||||
); | ); | ||||
this.tooltipScale = interpolateNode(position, { | this.tooltipScale = interpolateNode(position, { | ||||
inputRange: [0, 0.2, 0.8, 1], | inputRange: [0, 0.2, 0.8, 1], | ||||
outputRange: [0, 0, 1, 1], | outputRange: [0, 0, 1, 1], | ||||
extrapolate: Extrapolate.CLAMP, | extrapolate: Extrapolate.CLAMP, | ||||
}); | }); | ||||
this.fixedTooltipVertical = multiply( | |||||
invertedPosition, | |||||
props.dimensions.height, | |||||
); | |||||
} | } | ||||
componentDidMount() { | componentDidMount() { | ||||
Haptics.impactAsync(); | Haptics.impactAsync(); | ||||
} | } | ||||
get tooltipHeight(): number { | get tooltipHeight(): number { | ||||
if (this.props.route.params.tooltipLocation === 'fixed') { | if (this.props.route.params.tooltipLocation === 'fixed') { | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | get tooltipContainerStyle() { | ||||
style.left = 8; | style.left = 8; | ||||
style.right = 8; | style.right = 8; | ||||
style.bottom = | style.bottom = | ||||
dimensions.height - | dimensions.height - | ||||
verticalBounds.height - | verticalBounds.height - | ||||
verticalBounds.y - | verticalBounds.y - | ||||
inputBarHeight + | inputBarHeight + | ||||
padding; | padding; | ||||
style.transform = [{ translateY: this.fixedTooltipVertical }]; | |||||
} else if (tooltipLocation === 'above') { | } else if (tooltipLocation === 'above') { | ||||
style.bottom = | style.bottom = | ||||
dimensions.height - Math.max(y, verticalBounds.y) + margin; | dimensions.height - Math.max(y, verticalBounds.y) + margin; | ||||
style.transform.push({ translateY: this.tooltipVerticalAbove }); | style.transform.push({ translateY: this.tooltipVerticalAbove }); | ||||
} else { | } else { | ||||
style.top = | style.top = | ||||
Math.min(y + height, verticalBounds.y + verticalBounds.height) + | Math.min(y + height, verticalBounds.y + verticalBounds.height) + | ||||
margin; | margin; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | render() { | ||||
const buttonProps: ButtonProps<BaseTooltipPropsType> = { | const buttonProps: ButtonProps<BaseTooltipPropsType> = { | ||||
...navAndRouteForFlow, | ...navAndRouteForFlow, | ||||
progress: position, | progress: position, | ||||
isOpeningSidebar, | isOpeningSidebar, | ||||
}; | }; | ||||
const itemsStyles = [styles.items, styles.itemsFixed]; | const itemsStyles = [styles.items, styles.itemsFixed]; | ||||
const animationDelay = Platform.OS === 'ios' ? 200 : 500; | |||||
const enterAnimation = SlideInDown.delay(animationDelay); | |||||
const exitAnimation = SlideOutDown; | |||||
let tooltip = null; | let tooltip = null; | ||||
if (this.tooltipLocation !== 'fixed') { | if (this.tooltipLocation !== 'fixed') { | ||||
tooltip = ( | tooltip = ( | ||||
<AnimatedView | <AnimatedView | ||||
style={this.tooltipContainerStyle} | style={this.tooltipContainerStyle} | ||||
onLayout={this.onTooltipContainerLayout} | onLayout={this.onTooltipContainerLayout} | ||||
> | > | ||||
{triangleUp} | {triangleUp} | ||||
<View style={styles.items}>{items}</View> | <View style={styles.items}>{items}</View> | ||||
{triangleDown} | {triangleDown} | ||||
</AnimatedView> | </AnimatedView> | ||||
); | ); | ||||
} else if ( | } else if ( | ||||
this.tooltipLocation === 'fixed' && | this.tooltipLocation === 'fixed' && | ||||
!this.props.route.params.hideTooltip | !this.props.route.params.hideTooltip | ||||
) { | ) { | ||||
tooltip = ( | tooltip = ( | ||||
<AnimatedView | <AnimatedView style={this.tooltipContainerStyle}> | ||||
style={this.tooltipContainerStyle} | |||||
entering={enterAnimation} | |||||
exiting={exitAnimation} | |||||
> | |||||
<View style={itemsStyles}>{items}</View> | <View style={itemsStyles}>{items}</View> | ||||
</AnimatedView> | </AnimatedView> | ||||
); | ); | ||||
} | } | ||||
return ( | return ( | ||||
<TouchableWithoutFeedback onPress={this.props.closeTooltip}> | <TouchableWithoutFeedback onPress={this.props.closeTooltip}> | ||||
<View style={styles.container}> | <View style={styles.container}> | ||||
▲ Show 20 Lines • Show All 197 Lines • Show Last 20 Lines |