Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
85 changes: 49 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,49 +32,62 @@ 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');
};

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
158 changes: 82 additions & 76 deletions ToolTip.ios.js
Original file line number Diff line number Diff line change
@@ -1,92 +1,98 @@
'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 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);
this.props.onShow();
};

Object.keys(TouchableHighlight.propTypes).forEach((key) => props[key] = this.props[key]);
hideMenu = () => {
ToolTipMenu.hide();
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