Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make compatible with RN 49+, refactored and added onHide and onShow props #36

Merged
merged 4 commits into from
Feb 8, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 53 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,66 @@ You can see the list on the react native [website](https://facebook.github.io/re
### Example

```javascript
var React = require('react-native');
var {
import React from 'react';
import {
AppRegistry,
StyleSheet,
PixelRatio,
View,
Text,
} = React;

var ToolTip = require('react-native-tooltip');

var tooltip = React.createClass({
getInitialState: function() {
return {
input: 'chirag',
} from 'react-native';

import ToolTip from 'react-native-tooltip';

export default class MyToolTip extends React.Component {
state = {
input: 'chirag'
};

handleCopyPress = () => {
AlertIOS.alert(`Copy has been pressed!`);
};

handleOtherPress = () => {
AlertIOS.alert(`Other has been pressed!`);
};

handleHide = () => {
console.log('Tooltip did hide');
};

handleShow = () => {
console.log('tooltip did show');
};

isTooltipVisible = () => {
console.log('tooltip visible', this.refs.tooltip.isToolTipVisible);
};

render() {
return (
<View style={{flex: 1, justifyContent: 'center'}}>
<ToolTip
ref='tooltip'
actions={[
{text: 'Copy', onPress: this.handleCopyPress },
{text: 'Other', onPress: this.handleOtherPress }
]}
onHide={this.handleHide}
onShow={this.handleShow}
underlayColor={'blue'}
style={styles.selectedName}
>
<Text style={styles.welcome}>
Press Here.
</Text>
</ToolTip>
</View>
);
}
},
render: function() {
return (
<View style={styles.container}>
<View style={styles.textinputContainer}>
<ToolTip
ref='theToolTip'
actions={[
{text: 'x', onPress: () => { this.setState({input: 'x pressed'}) }},
{text: 'y', onPress: () => { this.setState({input: 'y pressed'}) }}
]}
underlayColor='transparent'
longPress={true}
arrowDirection='down'
style={styles.textinput}
>
<Text>
{this.state.input}
</Text>
</ToolTip>
</View>
</View>
);
}
});
}

var styles = StyleSheet.create({
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
Expand Down
162 changes: 86 additions & 76 deletions ToolTip.ios.js
Original file line number Diff line number Diff line change
@@ -1,92 +1,102 @@
'use strict';

var {
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {
requireNativeComponent,
TouchableHighlight,
View,
NativeModules,
findNodeHandle,
} = require('react-native');
var React = require('react');
var ToolTipMenu = NativeModules.ToolTipMenu;
var RCTToolTipText = requireNativeComponent('RCTToolTipText', null);

var propTypes = {
actions: React.PropTypes.arrayOf(React.PropTypes.shape({
text: React.PropTypes.string.isRequired,
onPress: React.PropTypes.func,
})),
arrowDirection: React.PropTypes.oneOf(['up', 'down', 'left', 'right']),
longPress: React.PropTypes.bool,
...TouchableHighlight.propTypes,
};

var ViewClass = React.createClass({
getDefaultProps: function() {
return {
arrowDirection: 'down'
} from 'react-native';

const ToolTipMenu = NativeModules.ToolTipMenu;
const RCTToolTipText = requireNativeComponent('RCTToolTipText', null);

export let isToolTipVisible = false;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would put this in the component and expose via ref. this.refs.tooltip.isToolTipVisible.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the idea is to use it as an import.

if you have multiple tooltip components and you want to know if there is at least one of those components showing the tooltip without looping though all of them.

does it make sense?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you have multiple tooltip components and you want to know if there is at least one of those components showing the tooltip without looping though all of them.

That sounds like a state that should live in your application then. It's little weird to keep this global export in a library.idk


export default class ToolTip extends PureComponent {
static propTypes = {
actions: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.string.isRequired,
onPress: PropTypes.func
})),
arrowDirection: PropTypes.oneOf(['up', 'down', 'left', 'right']),
longPress: PropTypes.bool,
onHide: PropTypes.func,
onShow: PropTypes.func,
...TouchableHighlight.propTypes
};
},

showMenu: function() {
ToolTipMenu.show(findNodeHandle(this.refs.toolTipText), this.getOptionTexts(), this.props.arrowDirection);
},
hideMenu: function() {
ToolTipMenu.hide();
},

getOptionTexts: function() {
return this.props.actions.map((option) => option.text);
},

// Assuming there is no actions with the same text
getCallback: function(optionText) {
var selectedOption = this.props.actions.find((option) => option.text === optionText);

if (selectedOption) {
return selectedOption.onPress;
}

return null;
},
static defaultProps = {
arrowDirection: 'down',
onHide: () => true,
onShow: () => true
};

getTouchableHighlightProps: function() {
var props = {};
showMenu = () => {
ToolTipMenu.show(findNodeHandle(this.refs.toolTipText), this.getOptionTexts(), this.props.arrowDirection);
isToolTipVisible = true;
this.props.onShow();
};

Object.keys(TouchableHighlight.propTypes).forEach((key) => props[key] = this.props[key]);
hideMenu = () => {
ToolTipMenu.hide();
isToolTipVisible = false;
this.props.onHide();
};

if (this.props.longPress) {
props.onLongPress = this.showMenu;
} else {
props.onPress = this.showMenu;
}
getOptionTexts = () => {
return this.props.actions.map((option) => option.text);
};

// Assuming there is no actions with the same text
getCallback = (optionText) => {
const selectedOption = this.props.actions.find((option) => option.text === optionText);

return props;
},
if (selectedOption) {
return selectedOption.onPress;
}

return null;
};

handleToolTipTextChange: function(event) {
var callback = this.getCallback(event.nativeEvent.text);
getTouchableHighlightProps = () => {
const props = {};

Object.keys(TouchableHighlight.propTypes).forEach((key) => props[key] = this.props[key]);

if (this.props.longPress) {
props.onLongPress = this.showMenu;
} else {
props.onPress = this.showMenu;
}

return props;
};

handleToolTipTextChange = (event) => {
const callback = this.getCallback(event.nativeEvent.text);
if (callback) {
callback(event);
}
};

handleBlurToolTip = () => {
this.hideMenu();
};

if (callback) {
callback(event);
render() {
return (
<RCTToolTipText ref='toolTipText' onChange={this.handleToolTipTextChange} onBlur={this.handleBlurToolTip}>
<TouchableHighlight
{...this.getTouchableHighlightProps()}
>
<View>
{this.props.children}
</View>
</TouchableHighlight>
</RCTToolTipText>
);
}
},

render: function() {
return (
<RCTToolTipText ref='toolTipText' onChange={this.handleToolTipTextChange}>
<TouchableHighlight
{...this.getTouchableHighlightProps()}
>
<View>
{this.props.children}
</View>
</TouchableHighlight>
</RCTToolTipText>
);
}
});

ViewClass.propTypes = propTypes;

module.exports = ViewClass;
}
2 changes: 2 additions & 0 deletions ToolTipMenu/RCTToolTipText.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

- (void)tappedMenuItem:(NSString *)text;

- (void)didHideMenu:(NSNotification *)notification;

- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;

@end
10 changes: 10 additions & 0 deletions ToolTipMenu/RCTToolTipText.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ - (void)tappedMenuItem:(NSString *)text {
eventCount:_nativeEventCount];
}

- (void)didHideMenu:(NSNotification *)notification {
_nativeEventCount++;
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeBlur
reactTag:self.reactTag
text:nil
key:nil
eventCount:_nativeEventCount];

}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
NSString *sel = NSStringFromSelector(action);
NSRange match = [sel rangeOfString:@"magic_"];
Expand Down
5 changes: 5 additions & 0 deletions ToolTipMenu/RCTToolTipTextManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ @implementation RCTToolTipTextManager

RCT_EXPORT_MODULE()

+ (BOOL)requiresMainQueueSetup
{
return YES;
}

- (UIView *)view
{
return [[RCTToolTipText alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
Expand Down
3 changes: 3 additions & 0 deletions ToolTipMenu/ToolTipMenu.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ - (dispatch_queue_t)methodQueue
UIMenuController *menuCont = [UIMenuController sharedMenuController];
[menuCont setTargetRect:view.frame inView:view.superview];

[[NSNotificationCenter defaultCenter] addObserver:view selector:@selector(didHideMenu:) name:UIMenuControllerDidHideMenuNotification object:nil];


if([arrowDirection isEqualToString: @"up"]){
menuCont.arrowDirection = UIMenuControllerArrowUp;
}else if ([arrowDirection isEqualToString: @"right"]){
Expand Down