diff --git a/native/tooltip/nux-tips-overlay.react.js b/native/tooltip/nux-tips-overlay.react.js --- a/native/tooltip/nux-tips-overlay.react.js +++ b/native/tooltip/nux-tips-overlay.react.js @@ -23,6 +23,7 @@ } from '../types/layout-types.js'; import type { LayoutEvent } from '../types/react-native.js'; import { AnimatedView } from '../types/styles.js'; +import type { WritableAnimatedStyleObj } from '../types/styles.js'; const { Value } = Animated; @@ -63,6 +64,20 @@ height: 10, width: 10, }, + triangleDown: { + borderBottomColor: 'transparent', + borderBottomWidth: 0, + borderLeftColor: 'transparent', + borderLeftWidth: 10, + borderRightColor: 'transparent', + borderRightWidth: 10, + borderStyle: 'solid', + borderTopColor: 'tooltipBackground', + borderTopWidth: 10, + height: 10, + top: Platform.OS === 'android' ? -1 : 0, + width: 10, + }, tipText: { color: 'panelForegroundLabel', fontSize: 20, @@ -73,6 +88,7 @@ export type NUXTipsOverlayParams = { +initialCoordinates: LayoutCoordinates, +verticalBounds: VerticalBounds, + +tooltipLocation: 'above' | 'below', }; export type NUXTipsOverlayProps = { @@ -81,7 +97,6 @@ }; const margin: number = 20; -const tipContainerTranslateY = -80; function opacityEnteringAnimation() { 'worklet'; @@ -159,34 +174,41 @@ [dimensions.width, initialCoordinates, tipHorizontalOffset], ); + const { tooltipLocation } = route.params; + const baseTipContainerStyle = React.useMemo(() => { const { y, x, height, width } = initialCoordinates; - const top = - Math.min(y + height, verticalBounds.y + verticalBounds.height) + margin; + const style: WritableAnimatedStyleObj = { + position: 'absolute', + alignItems: 'center', + }; + + if (tooltipLocation === 'below') { + style.top = + Math.min(y + height, verticalBounds.y + verticalBounds.height) + + margin; + } else { + style.bottom = + dimensions.height - Math.max(y, verticalBounds.y) + margin; + } const extraLeftSpace = x; const extraRightSpace = dimensions.width - width - x; if (extraLeftSpace < extraRightSpace) { - return { - top, - position: 'absolute', - alignItems: 'center', - left: 0, - minWidth: width + 2 * extraLeftSpace, - }; + style.left = 0; + style.minWidth = width + 2 * extraLeftSpace; } else { - return { - top, - position: 'absolute', - alignItems: 'center', - right: 0, - minWidth: width + 2 * extraRightSpace, - }; + style.right = 0; + style.minWidth = width + 2 * extraRightSpace; } + + return style; }, [ + dimensions.height, dimensions.width, initialCoordinates, + tooltipLocation, verticalBounds.height, verticalBounds.y, ]); @@ -232,7 +254,10 @@ initialCoordinates.width + initialCoordinates.x) / 2; - const initialY = tipContainerTranslateY; + const initialY = + tooltipLocation === 'below' + ? -values.targetHeight / 2 + : values.targetHeight / 2; return { animations: { @@ -253,7 +278,7 @@ }, }; }, - [initialCoordinates.width, initialCoordinates.x], + [initialCoordinates.width, initialCoordinates.x, tooltipLocation], ); // prettier-ignore @@ -266,7 +291,10 @@ initialCoordinates.width + initialCoordinates.x) / 2; - const toValueY = tipContainerTranslateY; + const toValueY = + tooltipLocation === 'below' + ? -values.currentHeight / 2 + : values.currentHeight / 2;; return { animations: { @@ -291,9 +319,17 @@ }, }; }, - [initialCoordinates.width, initialCoordinates.x], + [initialCoordinates.width, initialCoordinates.x, tooltipLocation], ); + let triangleDown = null; + let triangleUp = null; + if (tooltipLocation === 'above') { + triangleDown = ; + } else if (tooltipLocation === 'below') { + triangleUp = ; + } + return ( @@ -317,10 +353,11 @@ entering={tipContainerEnteringAnimation} exiting={tipContainerExitingAnimation} > - + {triangleUp} {tipText} + {triangleDown}