Skip to content

Instantly share code, notes, and snippets.

@oxyii
Last active March 4, 2021 23:00
Show Gist options
  • Save oxyii/b28c003d87c619674def0878473338a0 to your computer and use it in GitHub Desktop.
Save oxyii/b28c003d87c619674def0878473338a0 to your computer and use it in GitHub Desktop.
[RNE] Temporary fix to Tooltip inside Modal on Android
{
"name": "rne-modal-tooltip",
"version": "1.1.0",
"main": "./RNEModalTooltip.js",
"dependencies": {
"react-native-elements": "1.1.0"
}
}
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, Modal, View } from 'react-native';
import { ViewPropTypes, withTheme } from 'react-native-elements/src/config';
import { ScreenWidth, ScreenHeight, isIOS } from 'react-native-elements/src/helpers';
import Triangle from 'react-native-elements/src/tooltip/Triangle';
import getTooltipCoordinate, {
getElementVisibleWidth,
} from 'react-native-elements/src/tooltip/getTooltipCoordinate';
class RNEModalTooltip extends React.PureComponent {
state = {
isVisible: false,
yOffset: 0,
xOffset: 0,
elementWidth: 0,
elementHeight: 0,
};
renderedElement;
toggleTooltip = () => {
const { onClose } = this.props;
this.getElementPosition();
this.setState(prevState => {
if (prevState.isVisible && !isIOS) {
onClose && onClose();
}
return { isVisible: !prevState.isVisible };
});
};
wrapWithPress = (toggleOnPress, children) => {
if (toggleOnPress) {
return (
<TouchableOpacity onPress={this.toggleTooltip} activeOpacity={1}>
{children}
</TouchableOpacity>
);
}
return children;
};
getTooltipStyle = () => {
const { yOffset, xOffset, elementHeight, elementWidth } = this.state;
const {
height,
backgroundColor,
width,
withPointer,
containerStyle,
} = this.props;
const { x, y } = getTooltipCoordinate(
xOffset,
yOffset,
elementWidth,
elementHeight,
ScreenWidth,
ScreenHeight,
width,
height,
withPointer
);
return {
position: 'absolute',
left: x,
top: y,
width,
height,
backgroundColor,
// default styles
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flex: 1,
borderRadius: 10,
padding: 10,
...containerStyle,
};
};
renderPointer = tooltipY => {
const { yOffset, xOffset, elementHeight, elementWidth } = this.state;
const { backgroundColor, pointerColor } = this.props;
const pastMiddleLine = yOffset > tooltipY;
return (
<View
style={{
position: 'absolute',
top: pastMiddleLine ? yOffset - 13 : yOffset + elementHeight - 2,
left:
xOffset +
getElementVisibleWidth(elementWidth, xOffset, ScreenWidth) / 2 -
7.5,
}}
>
<Triangle
style={{ borderBottomColor: pointerColor || backgroundColor }}
isDown={pastMiddleLine}
/>
</View>
);
};
renderContent = withTooltip => {
const { popover, withPointer, toggleOnPress, highlightColor } = this.props;
if (!withTooltip)
return this.wrapWithPress(toggleOnPress, this.props.children);
const { yOffset, xOffset, elementWidth, elementHeight } = this.state;
const tooltipStyle = this.getTooltipStyle();
return (
<View>
<View
style={{
position: 'absolute',
top: yOffset,
left: xOffset,
backgroundColor: highlightColor,
overflow: 'visible',
width: elementWidth,
height: elementHeight,
}}
>
{this.props.children}
</View>
{withPointer && this.renderPointer(tooltipStyle.top)}
<View style={tooltipStyle} testID="tooltipPopoverContainer">
{popover}
</View>
</View>
);
};
componentDidMount() {
// wait to compute onLayout values.
setTimeout(this.getElementPosition, 500);
}
getElementPosition = () => {
this.renderedElement &&
this.renderedElement.measure(
(
frameOffsetX,
frameOffsetY,
width,
height,
pageOffsetX,
pageOffsetY
) => {
this.setState({
xOffset: pageOffsetX,
yOffset: pageOffsetY,
elementWidth: width,
elementHeight: height,
});
}
);
};
render() {
const { isVisible } = this.state;
const { onClose, withOverlay, onOpen } = this.props;
return (
<View
collapsable={false}
ref={e => {
this.renderedElement = e;
}}
>
{this.renderContent(false)}
<Modal
animationType="fade"
visible={isVisible}
transparent
onDismiss={onClose}
onShow={onOpen}
onRequestClose={onClose}
>
<TouchableOpacity
style={styles.container(withOverlay)}
onPress={this.toggleTooltip}
activeOpacity={1}
>
{this.renderContent(true)}
</TouchableOpacity>
</Modal>
</View>
);
}
}
RNEModalTooltip.propTypes = {
children: PropTypes.element,
withPointer: PropTypes.bool,
popover: PropTypes.element,
toggleOnPress: PropTypes.bool,
height: PropTypes.number,
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
containerStyle: ViewPropTypes.style,
pointerColor: PropTypes.string,
onClose: PropTypes.func,
onOpen: PropTypes.func,
withOverlay: PropTypes.bool,
backgroundColor: PropTypes.string,
highlightColor: PropTypes.string,
};
RNEModalTooltip.defaultProps = {
withOverlay: true,
highlightColor: 'transparent',
withPointer: true,
toggleOnPress: true,
height: 40,
width: 150,
containerStyle: {},
backgroundColor: '#617080',
onClose: () => {},
onOpen: () => {},
};
const styles = {
container: withOverlay => ({
backgroundColor: withOverlay ? 'rgba(250, 250, 250, 0.70)' : 'transparent',
flex: 1,
}),
};
export { RNEModalTooltip };
export default withTheme(RNEModalTooltip, 'RNEModalTooltip');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment