@nguyentc21/react-native-tooltip
Version:
Simple tooltip for React native app
238 lines • 8.86 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import React, { useState, useEffect, useRef, useCallback, useReducer, useMemo } from 'react';
import { View, Pressable, Keyboard, StyleSheet, useWindowDimensions } from 'react-native';
import { NestedModal } from '@nguyentc21/react-native-modal-view';
import Caret from './Caret';
import { useCaretPosition, useTooltipPosition } from '../hooks/usePosition';
import useFinalPlacement from '../hooks/useFinalPlacement';
import useContainerStyles from '../hooks/useContainerStyles';
import useContentContainerStyles from '../hooks/useContentContainerStyles';
import useOffsetViewStyles from '../hooks/useOffsetViewStyles';
import { DEFAULT_BORDER_RADIUS, DEFAULT_CARET_SIZE, DEFAULT_ON_PRESS_ACTION_TYPE, DEFAULT_PLACEMENT, DEFAULT_TOOLTIP_OFFSET, DEFAULT_SCREEN_PADDING, DEFAULT_TOOLTIP_BACKGROUND, DEFAULT_BACKDROP_COLOR } from '../constants';
import useStableCallback from '../utils/useStableCallback';
function Tooltip(props) {
const {
visible,
content,
backgroundColor = DEFAULT_TOOLTIP_BACKGROUND,
backdropColor = DEFAULT_BACKDROP_COLOR,
borderRadius = DEFAULT_BORDER_RADIUS,
placement = DEFAULT_PLACEMENT,
forcePlacement,
caretSize = DEFAULT_CARET_SIZE,
hideCaret,
offset = DEFAULT_TOOLTIP_OFFSET,
screenPadding = DEFAULT_SCREEN_PADDING,
actionType = DEFAULT_ON_PRESS_ACTION_TYPE,
expose,
extraData,
modalContainerStyle,
containerStyle,
contentContainerStyle,
onClose,
onOpen,
onDidOpen,
...pressableProps
} = props;
const _caretSize = !hideCaret ? caretSize : 0;
const {
onPress,
onLongPress
} = pressableProps;
const [tooltipContentLayoutState, setTooltipContentLayoutState] = useState();
const [tooltipContainerLayoutState, setTooltipContainerLayoutState] = useState();
const [targetContentLayoutState, setTargetContentLayoutState] = useState();
const [visibleState, setVisibleState] = useState(false);
const [safeAreaInsetsState, setSafeAreaInsetsState] = useState({
top: screenPadding,
bottom: screenPadding,
left: screenPadding,
right: screenPadding
});
const [tick, bumpTick] = useReducer(x => x + 1, 0);
const _visible = visible ?? visibleState;
const contentRef = useRef(null);
const windowDimensions = useWindowDimensions();
const tooltipContentLayout = useMemo(() => {
if (!tooltipContainerLayoutState || !tooltipContentLayoutState) return undefined;
return {
...tooltipContentLayoutState,
x: tooltipContainerLayoutState.x + tooltipContentLayoutState.x,
y: tooltipContainerLayoutState.y + tooltipContentLayoutState.y
};
}, [tooltipContentLayoutState, tooltipContainerLayoutState]);
const finalPlacement = useFinalPlacement({
safeAreaInsets: safeAreaInsetsState,
dimension: windowDimensions,
placement,
forcePlacement,
targetContentLayout: targetContentLayoutState,
tooltipContentLayout,
borderRadius
});
const tooltipPosition = useTooltipPosition({
safeAreaInsets: safeAreaInsetsState,
dimension: windowDimensions,
placement: finalPlacement,
targetContentLayout: targetContentLayoutState,
tooltipContentLayout
});
const caretPosition = useCaretPosition({
placement: finalPlacement,
targetContentLayout: targetContentLayoutState,
tooltipContentLayout,
caretSize: _caretSize
});
const {
containerStyles,
wrapContainerStyles
} = useContainerStyles({
tooltipPosition,
placement: finalPlacement
});
const contentContainerStyles = useContentContainerStyles({
caretSize: _caretSize,
borderRadius
});
const offsetViewStyles = useOffsetViewStyles({
caretSize: _caretSize,
placement: finalPlacement,
offset
});
const _onOpen = useStableCallback(() => {
var _contentRef$current, _contentRef$current$m;
onOpen === null || onOpen === void 0 || onOpen();
Keyboard.dismiss();
(_contentRef$current = contentRef.current) === null || _contentRef$current === void 0 || (_contentRef$current$m = _contentRef$current.measure) === null || _contentRef$current$m === void 0 || _contentRef$current$m.call(_contentRef$current, (x, y, width, height, pageX, pageY) => {
setTargetContentLayoutState({
x,
y,
width,
height,
pageX,
pageY
});
});
});
const _onTooltipLayout = useCallback(e => {
setTooltipContainerLayoutState(e.nativeEvent.layout);
}, []);
const _onTooltipContentLayout = useCallback(e => {
setTooltipContentLayoutState(e.nativeEvent.layout);
}, []);
const _show = useCallback(() => {
setVisibleState(true);
}, []);
const _hide = useCallback(() => {
setVisibleState(false);
}, []);
const _onPress = useStableCallback(e => {
_show();
onPress === null || onPress === void 0 || onPress(e);
});
const _onLongPress = useStableCallback(e => {
_show();
onLongPress === null || onLongPress === void 0 || onLongPress(e);
});
const _getModalLayoutData = useCallback(data => {
const {
safeAreaInsets
} = data;
setSafeAreaInsetsState({
top: screenPadding + (safeAreaInsets.top || 0),
bottom: screenPadding + (safeAreaInsets.bottom || 0),
left: screenPadding + (safeAreaInsets.left || 0),
right: screenPadding + (safeAreaInsets.right || 0)
});
}, [screenPadding]);
useEffect(() => {
if (!expose) return;
const handler = {
show: _show,
hide: _hide
};
expose(handler);
return () => {
expose(undefined);
};
}, [expose, _show, _hide]);
useEffect(() => {
bumpTick();
}, [extraData, tooltipPosition === null || tooltipPosition === void 0 ? void 0 : tooltipPosition.top, tooltipPosition === null || tooltipPosition === void 0 ? void 0 : tooltipPosition.bottom, tooltipPosition === null || tooltipPosition === void 0 ? void 0 : tooltipPosition.left, tooltipPosition === null || tooltipPosition === void 0 ? void 0 : tooltipPosition.right, caretPosition === null || caretPosition === void 0 ? void 0 : caretPosition.top, caretPosition === null || caretPosition === void 0 ? void 0 : caretPosition.bottom, caretPosition === null || caretPosition === void 0 ? void 0 : caretPosition.left, caretPosition === null || caretPosition === void 0 ? void 0 : caretPosition.right]);
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Pressable, _extends({
ref: contentRef
}, pressableProps, {
onPress: actionType === 'onPress' ? _onPress : undefined,
onLongPress: actionType === 'onLongPress' ? _onLongPress : undefined
})), /*#__PURE__*/React.createElement(NestedModal, {
autoPadding: false,
bottomOffset: safeAreaInsetsState.bottom || 0,
dimension: windowDimensions,
visible: _visible,
close: _hide,
onOpen: _onOpen,
onDidOpen: onDidOpen,
onClose: onClose,
getLayoutData: _getModalLayoutData,
containerStyle: [lStyles.tooltipContainerStyle, wrapContainerStyles, modalContainerStyle],
contentContainerStyle: [lStyles.shadow10, lStyles.wrapContentContainerStyle, containerStyle],
backdropStyle: {
backgroundColor: backdropColor
},
onContainerLayout: _onTooltipLayout,
onMainContentLayout: _onTooltipContentLayout,
extraData: tick
}, /*#__PURE__*/React.createElement(View, {
style: [containerStyles]
}, /*#__PURE__*/React.createElement(View, {
style: lStyles.tooltipContent
}, /*#__PURE__*/React.createElement(View, {
style: [contentContainerStyles, contentContainerStyle, {
backgroundColor
}]
}, content)), /*#__PURE__*/React.createElement(View, {
style: [offsetViewStyles],
pointerEvents: 'box-none'
}, !!caretPosition && !!_caretSize && /*#__PURE__*/React.createElement(Caret, {
backgroundColor: backgroundColor,
size: _caretSize,
style: [lStyles.positionCaret, lStyles.caret, caretPosition]
})))));
}
const lStyles = StyleSheet.create({
shadow10: {
shadowColor: '#000000',
shadowOffset: {
width: 0,
height: 5
},
shadowOpacity: 0.34,
shadowRadius: 6.27,
elevation: 10
},
wrapContentContainerStyle: {
borderRadius: 0,
backgroundColor: 'transparent',
overflow: 'visible'
},
tooltipContainerStyle: {
maxHeight: '100%',
height: -1,
width: -1,
overflow: 'visible',
alignSelf: 'auto',
position: 'absolute'
},
positionCaret: {
position: 'absolute'
},
tooltipContent: {
zIndex: 2,
overflow: 'hidden'
},
caret: {
zIndex: 1
}
});
export default Tooltip;
//# sourceMappingURL=Tooltip.js.map