commit 23d9e912c8bcc6f024f7ae9c4da1f84669ab90d2 Author: chirag04 Date: Mon May 18 23:07:42 2015 -0400 inital commit diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..3cf7ab7 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,32 @@ +[ignore] + +# We fork some components by platform. +.*/*.web.js +.*/*.android.js + +# Some modules have their own node_modules with overlap +.*/node_modules/node-haste/.* + +# Ignore react-tools where there are overlaps, but don't ignore anything that +# react-native relies on +.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js +.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js +.*/node_modules/react-tools/src/browser/ui/React.js +.*/node_modules/react-tools/src/core/ReactInstanceHandles.js +.*/node_modules/react-tools/src/event/EventPropagators.js +.*/node_modules/flux/lib/invariant.js + +# Ignore jest +.*/node_modules/jest-cli/.* + +# Ignore examples +.*/Examples/.* + +[include] + +[libs] +node_modules/react-native/Libraries/react-native/react-native-interface.js +interfaces.js + +[options] +module.system=haste diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b927355 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# node.js +# +node_modules/ +npm-debug.log diff --git a/README.md b/README.md new file mode 100644 index 0000000..7850508 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# react-native-tooltip + +A react-native component from displaying tooltip. Uses UIMenuController. + +### Add it to your project + +1. Run `npm install react-native-tooltip --save` +2. Open your project in XCode, right click on `Libraries` and click `Add + Files to "Your Project Name"` [(Screenshot)](http://url.brentvatne.ca/jQp8) then [(Screenshot)](http://url.brentvatne.ca/1gqUD). +3. Add `libRNToolTip.a` to `Build Phases -> Link Binary With Libraries` + [(Screenshot)](http://url.brentvatne.ca/17Xfe). +4. Whenever you want to use it within React code now you can: `var ToolTipText = require('react-native-tooltip');` + + +## Example +```javascript +var React = require('react-native'); +var { + AppRegistry, + StyleSheet, + Text, + TouchableHighlight, + PixelRatio, + View, +} = React; + +var ToolTipMenu = require('NativeModules').ToolTipMenu; +var ToolTipText = require('react-native-tooltip'); + +var tooltip = React.createClass({ + getInitialState: function() { + return { + input: 'chirag', + } + }, + handleChange: function(event) { + this.setState({input: event.nativeEvent.text}); + }, + handleFocus: function(change) { + ToolTipMenu.show(this.refs.input.getNodeHandle(), ['x', 'z']); + }, + render: function() { + return ( + + + {this.state.input} + + + ); + } +}); + +var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + textinputContainer: { + marginTop: 20, + justifyContent: 'center', + alignItems: 'center', + }, + textinput: { + width: 60, + marginVertical: 2, + marginHorizontal: 2, + borderWidth: 1 / PixelRatio.get(), + borderRadius: 5, + borderColor: '#c7c7cc', + padding: 2, + fontSize: 14, + backgroundColor: 'white', + }, +}); + +AppRegistry.registerComponent('tooltip', () => tooltip); +``` + +## Here is how it looks: +![Demo gif](https://github.com/chirag04/react-native-tooltip/blob/master/screenshot.png) diff --git a/ToolTipMenu.xcodeproj/project.pbxproj b/ToolTipMenu.xcodeproj/project.pbxproj new file mode 100644 index 0000000..77f1d24 --- /dev/null +++ b/ToolTipMenu.xcodeproj/project.pbxproj @@ -0,0 +1,403 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 4681C0251B05271A004D67D4 /* ToolTipMenu.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4681C0241B05271A004D67D4 /* ToolTipMenu.h */; }; + 4681C0271B05271A004D67D4 /* ToolTipMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 4681C0261B05271A004D67D4 /* ToolTipMenu.m */; }; + 4681C02D1B05271A004D67D4 /* libToolTipMenu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4681C0211B05271A004D67D4 /* libToolTipMenu.a */; }; + 469F58B71B069FF300C571E8 /* RCTToolTipText.m in Sources */ = {isa = PBXBuildFile; fileRef = 469F58B61B069FF300C571E8 /* RCTToolTipText.m */; }; + 469F58B91B06A00C00C571E8 /* RCTToolTipTextManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 469F58B81B06A00C00C571E8 /* RCTToolTipTextManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 4681C02E1B05271A004D67D4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4681C0191B05271A004D67D4 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4681C0201B05271A004D67D4; + remoteInfo = ToolTipMenu; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 4681C01F1B05271A004D67D4 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + 4681C0251B05271A004D67D4 /* ToolTipMenu.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4681C0211B05271A004D67D4 /* libToolTipMenu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libToolTipMenu.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 4681C0241B05271A004D67D4 /* ToolTipMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ToolTipMenu.h; sourceTree = ""; }; + 4681C0261B05271A004D67D4 /* ToolTipMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ToolTipMenu.m; sourceTree = ""; }; + 4681C02C1B05271A004D67D4 /* ToolTipMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ToolTipMenuTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4681C0321B05271A004D67D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 469F58B31B069F9800C571E8 /* RCTToolTipText.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTToolTipText.h; sourceTree = ""; }; + 469F58B61B069FF300C571E8 /* RCTToolTipText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTToolTipText.m; sourceTree = ""; }; + 469F58B81B06A00C00C571E8 /* RCTToolTipTextManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTToolTipTextManager.m; sourceTree = ""; }; + 469F58BA1B06A01D00C571E8 /* RCTToolTipTextManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTToolTipTextManager.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4681C01E1B05271A004D67D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4681C0291B05271A004D67D4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4681C02D1B05271A004D67D4 /* libToolTipMenu.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4681C0181B05271A004D67D4 = { + isa = PBXGroup; + children = ( + 4681C0231B05271A004D67D4 /* ToolTipMenu */, + 4681C0301B05271A004D67D4 /* ToolTipMenuTests */, + 4681C0221B05271A004D67D4 /* Products */, + ); + sourceTree = ""; + }; + 4681C0221B05271A004D67D4 /* Products */ = { + isa = PBXGroup; + children = ( + 4681C0211B05271A004D67D4 /* libToolTipMenu.a */, + 4681C02C1B05271A004D67D4 /* ToolTipMenuTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 4681C0231B05271A004D67D4 /* ToolTipMenu */ = { + isa = PBXGroup; + children = ( + 4681C0241B05271A004D67D4 /* ToolTipMenu.h */, + 4681C0261B05271A004D67D4 /* ToolTipMenu.m */, + 469F58B31B069F9800C571E8 /* RCTToolTipText.h */, + 469F58B61B069FF300C571E8 /* RCTToolTipText.m */, + 469F58BA1B06A01D00C571E8 /* RCTToolTipTextManager.h */, + 469F58B81B06A00C00C571E8 /* RCTToolTipTextManager.m */, + ); + path = ToolTipMenu; + sourceTree = ""; + }; + 4681C0301B05271A004D67D4 /* ToolTipMenuTests */ = { + isa = PBXGroup; + children = ( + 4681C0311B05271A004D67D4 /* Supporting Files */, + ); + path = ToolTipMenuTests; + sourceTree = ""; + }; + 4681C0311B05271A004D67D4 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 4681C0321B05271A004D67D4 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4681C0201B05271A004D67D4 /* ToolTipMenu */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4681C0351B05271A004D67D4 /* Build configuration list for PBXNativeTarget "ToolTipMenu" */; + buildPhases = ( + 4681C01D1B05271A004D67D4 /* Sources */, + 4681C01E1B05271A004D67D4 /* Frameworks */, + 4681C01F1B05271A004D67D4 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ToolTipMenu; + productName = ToolTipMenu; + productReference = 4681C0211B05271A004D67D4 /* libToolTipMenu.a */; + productType = "com.apple.product-type.library.static"; + }; + 4681C02B1B05271A004D67D4 /* ToolTipMenuTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4681C0381B05271A004D67D4 /* Build configuration list for PBXNativeTarget "ToolTipMenuTests" */; + buildPhases = ( + 4681C0281B05271A004D67D4 /* Sources */, + 4681C0291B05271A004D67D4 /* Frameworks */, + 4681C02A1B05271A004D67D4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4681C02F1B05271A004D67D4 /* PBXTargetDependency */, + ); + name = ToolTipMenuTests; + productName = ToolTipMenuTests; + productReference = 4681C02C1B05271A004D67D4 /* ToolTipMenuTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4681C0191B05271A004D67D4 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = "Chirag Jain"; + TargetAttributes = { + 4681C0201B05271A004D67D4 = { + CreatedOnToolsVersion = 6.3.1; + }; + 4681C02B1B05271A004D67D4 = { + CreatedOnToolsVersion = 6.3.1; + }; + }; + }; + buildConfigurationList = 4681C01C1B05271A004D67D4 /* Build configuration list for PBXProject "ToolTipMenu" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 4681C0181B05271A004D67D4; + productRefGroup = 4681C0221B05271A004D67D4 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4681C0201B05271A004D67D4 /* ToolTipMenu */, + 4681C02B1B05271A004D67D4 /* ToolTipMenuTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4681C02A1B05271A004D67D4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4681C01D1B05271A004D67D4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4681C0271B05271A004D67D4 /* ToolTipMenu.m in Sources */, + 469F58B91B06A00C00C571E8 /* RCTToolTipTextManager.m in Sources */, + 469F58B71B069FF300C571E8 /* RCTToolTipText.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4681C0281B05271A004D67D4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 4681C02F1B05271A004D67D4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4681C0201B05271A004D67D4 /* ToolTipMenu */; + targetProxy = 4681C02E1B05271A004D67D4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 4681C0331B05271A004D67D4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 4681C0341B05271A004D67D4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 4681C0361B05271A004D67D4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4681C0371B05271A004D67D4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../node_modules/react-native/React/**", + "$(SRCROOT)/../node_modules/react-native/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 4681C0391B05271A004D67D4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = ToolTipMenuTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 4681C03A1B05271A004D67D4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = ToolTipMenuTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4681C01C1B05271A004D67D4 /* Build configuration list for PBXProject "ToolTipMenu" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4681C0331B05271A004D67D4 /* Debug */, + 4681C0341B05271A004D67D4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4681C0351B05271A004D67D4 /* Build configuration list for PBXNativeTarget "ToolTipMenu" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4681C0361B05271A004D67D4 /* Debug */, + 4681C0371B05271A004D67D4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4681C0381B05271A004D67D4 /* Build configuration list for PBXNativeTarget "ToolTipMenuTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4681C0391B05271A004D67D4 /* Debug */, + 4681C03A1B05271A004D67D4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4681C0191B05271A004D67D4 /* Project object */; +} diff --git a/ToolTipMenu/RCTToolTipText.h b/ToolTipMenu/RCTToolTipText.h new file mode 100644 index 0000000..e6d8d4c --- /dev/null +++ b/ToolTipMenu/RCTToolTipText.h @@ -0,0 +1,14 @@ +#import +#import "RCTText.h" + +@class RCTEventDispatcher; + +@interface RCTToolTipText : RCTText + +@property(nonatomic, strong) RCTEventDispatcher *_eventDispatcher; + +- (void)tappedMenuItem:(NSString *)text; + +- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; + +@end diff --git a/ToolTipMenu/RCTToolTipText.m b/ToolTipMenu/RCTToolTipText.m new file mode 100644 index 0000000..f9796f4 --- /dev/null +++ b/ToolTipMenu/RCTToolTipText.m @@ -0,0 +1,54 @@ +#import "RCTToolTipText.h" +#import "RCTEventDispatcher.h" +#import "UIView+React.h" + +@implementation RCTToolTipText + +- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher +{ + if ((self = [super initWithFrame:CGRectZero])) { + self._eventDispatcher = eventDispatcher; + } + + return self; +} + +- (BOOL) canBecomeFirstResponder +{ + return YES; +} + +- (void)tappedMenuItem:(NSString *)text { + [self._eventDispatcher sendTextEventWithType:RCTTextEventTypeChange + reactTag:self.reactTag + text:text]; +} + +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { + NSString *sel = NSStringFromSelector(action); + NSRange match = [sel rangeOfString:@"magic_"]; + if (match.location == 0) { + return YES; + } + return NO; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + if ([super methodSignatureForSelector:sel]) { + return [super methodSignatureForSelector:sel]; + } + return [super methodSignatureForSelector:@selector(tappedMenuItem:)]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + NSString *sel = NSStringFromSelector([invocation selector]); + NSRange match = [sel rangeOfString:@"magic_"]; + if (match.location == 0) { + [self tappedMenuItem:[sel substringFromIndex:6]]; + } else { + [super forwardInvocation:invocation]; + } +} + + +@end diff --git a/ToolTipMenu/RCTToolTipTextManager.h b/ToolTipMenu/RCTToolTipTextManager.h new file mode 100644 index 0000000..904fd92 --- /dev/null +++ b/ToolTipMenu/RCTToolTipTextManager.h @@ -0,0 +1,5 @@ +#import "RCTTextManager.h" + +@interface RCTToolTipTextManager : RCTTextManager + +@end diff --git a/ToolTipMenu/RCTToolTipTextManager.m b/ToolTipMenu/RCTToolTipTextManager.m new file mode 100644 index 0000000..eb7326d --- /dev/null +++ b/ToolTipMenu/RCTToolTipTextManager.m @@ -0,0 +1,14 @@ +#import "RCTToolTipTextManager.h" +#import "RCTToolTipText.h" +#import "RCTBridge.h" + +@implementation RCTToolTipTextManager + +RCT_EXPORT_MODULE() + +- (UIView *)view +{ + return [[RCTToolTipText alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; +} + +@end diff --git a/ToolTipMenu/ToolTipMenu.h b/ToolTipMenu/ToolTipMenu.h new file mode 100644 index 0000000..6985356 --- /dev/null +++ b/ToolTipMenu/ToolTipMenu.h @@ -0,0 +1,6 @@ +#import +#import "RCTBridgeModule.h" + +@interface ToolTipMenu : NSObject + +@end \ No newline at end of file diff --git a/ToolTipMenu/ToolTipMenu.m b/ToolTipMenu/ToolTipMenu.m new file mode 100644 index 0000000..abb7ea1 --- /dev/null +++ b/ToolTipMenu/ToolTipMenu.m @@ -0,0 +1,41 @@ +#import "ToolTipMenu.h" + +#import "RCTToolTipText.h" +#import "RCTSparseArray.h" +#import "RCTUIManager.h" + +@implementation ToolTipMenu + +@synthesize bridge = _bridge; + +RCT_EXPORT_MODULE() + +RCT_EXPORT_METHOD(show:(NSNumber *)reactTag + items: (NSArray *)items) +{ + [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { + + RCTToolTipText *view = viewRegistry[reactTag]; + if (!view) { + RCTLogError(@"Cannot find view with tag #%@", reactTag); + return; + } + + NSArray *buttons = items; + NSMutableArray *menuItems = [NSMutableArray array]; + for (NSString *buttonText in buttons) { + NSString *sel = [NSString stringWithFormat:@"magic_%@", buttonText]; + [menuItems addObject:[[UIMenuItem alloc] + initWithTitle:buttonText + action:NSSelectorFromString(sel)]]; + } + [view becomeFirstResponder]; + UIMenuController *menuCont = [UIMenuController sharedMenuController]; + [menuCont setTargetRect:view.frame inView:view.superview]; + menuCont.arrowDirection = UIMenuControllerArrowDown; + menuCont.menuItems = menuItems; + [menuCont setMenuVisible:YES animated:YES]; + }]; +} + +@end diff --git a/ToolTipMenuTests/Info.plist b/ToolTipMenuTests/Info.plist new file mode 100644 index 0000000..19d31a6 --- /dev/null +++ b/ToolTipMenuTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + cj.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/ToolTipText.js b/ToolTipText.js new file mode 100644 index 0000000..0fa616f --- /dev/null +++ b/ToolTipText.js @@ -0,0 +1,220 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ToolTipText + * @flow + */ +'use strict'; + +var NativeMethodsMixin = require('NativeMethodsMixin'); +var React = require('React'); +var ReactNativeViewAttributes = require('ReactNativeViewAttributes'); +var StyleSheetPropType = require('StyleSheetPropType'); +var TextStylePropTypes = require('TextStylePropTypes'); +var Touchable = require('Touchable'); + +var createReactNativeComponentClass = + require('createReactNativeComponentClass'); +var merge = require('merge'); + +var stylePropType = StyleSheetPropType(TextStylePropTypes); + +var viewConfig = { + validAttributes: merge(ReactNativeViewAttributes.UIView, { + isHighlighted: true, + numberOfLines: true, + }), + uiViewClassName: 'RCTToolTipText', +}; + +/** + * A React component for displaying text which supports nesting, + * styling, and touch handling. In the following example, the nested title and + * body text will inherit the `fontFamily` from `styles.baseText`, but the title + * provides its own additional styles. The title and body will stack on top of + * each other on account of the literal newlines: + * + * ``` + * renderText: function() { + * return ( + * + * + * {this.state.titleText + '\n\n'} + * + * + * {this.state.bodyText} + * + * + * ); + * }, + * ... + * var styles = StyleSheet.create({ + * baseText: { + * fontFamily: 'Cochin', + * }, + * titleText: { + * fontSize: 20, + * fontWeight: 'bold', + * }, + * }; + * ``` + */ + +var Text = React.createClass({ + + mixins: [Touchable.Mixin, NativeMethodsMixin], + + propTypes: { + /** + * Used to truncate the text with an elipsis after computing the text + * layout, including line wrapping, such that the total number of lines does + * not exceed this number. + */ + numberOfLines: React.PropTypes.number, + /** + * This function is called on press. Text intrinsically supports press + * handling with a default highlight state (which can be disabled with + * `suppressHighlighting`). + */ + onPress: React.PropTypes.func, + /** + * Callback that is called when the text input's text changes. + */ + onChange: React.PropTypes.func, + /** + * When true, no visual change is made when text is pressed down. By + * default, a gray oval highlights the text on press down. + */ + suppressHighlighting: React.PropTypes.bool, + style: stylePropType, + /** + * Used to locate this view in end-to-end tests. + */ + testID: React.PropTypes.string, + /** + * Invoked on mount and layout changes with + * + * {nativeEvent: { layout: {x, y, width, height}}}. + */ + onLayout: React.PropTypes.func, + }, + + viewConfig: viewConfig, + + getInitialState: function() { + return merge(this.touchableGetInitialState(), { + isHighlighted: false, + }); + }, + + onStartShouldSetResponder: function(): bool { + var shouldSetFromProps = this.props.onStartShouldSetResponder && + this.props.onStartShouldSetResponder(); + return shouldSetFromProps || !!this.props.onPress; + }, + + /* + * Returns true to allow responder termination + */ + handleResponderTerminationRequest: function(): bool { + // Allow touchable or props.onResponderTerminationRequest to deny + // the request + var allowTermination = this.touchableHandleResponderTerminationRequest(); + if (allowTermination && this.props.onResponderTerminationRequest) { + allowTermination = this.props.onResponderTerminationRequest(); + } + return allowTermination; + }, + + handleResponderGrant: function(e: SyntheticEvent, dispatchID: string) { + this.touchableHandleResponderGrant(e, dispatchID); + this.props.onResponderGrant && + this.props.onResponderGrant.apply(this, arguments); + }, + + handleResponderMove: function(e: SyntheticEvent) { + this.touchableHandleResponderMove(e); + this.props.onResponderMove && + this.props.onResponderMove.apply(this, arguments); + }, + + handleResponderRelease: function(e: SyntheticEvent) { + this.touchableHandleResponderRelease(e); + this.props.onResponderRelease && + this.props.onResponderRelease.apply(this, arguments); + }, + + handleResponderTerminate: function(e: SyntheticEvent) { + this.touchableHandleResponderTerminate(e); + this.props.onResponderTerminate && + this.props.onResponderTerminate.apply(this, arguments); + }, + + touchableHandleActivePressIn: function() { + if (this.props.suppressHighlighting || !this.props.onPress) { + return; + } + this.setState({ + isHighlighted: true, + }); + }, + + touchableHandleActivePressOut: function() { + if (this.props.suppressHighlighting || !this.props.onPress) { + return; + } + this.setState({ + isHighlighted: false, + }); + }, + + touchableHandlePress: function() { + this.props.onPress && this.props.onPress(); + }, + + touchableGetPressRectOffset: function(): RectOffset { + return PRESS_RECT_OFFSET; + }, + + _onChange: function(event: Event) { + this.props.onChange && this.props.onChange(event); + }, + + render: function() { + var props = {}; + for (var key in this.props) { + props[key] = this.props[key]; + } + // Text is accessible by default + if (props.accessible !== false) { + props.accessible = true; + } + props.isHighlighted = this.state.isHighlighted; + props.onStartShouldSetResponder = this.onStartShouldSetResponder; + props.onResponderTerminationRequest = + this.handleResponderTerminationRequest; + props.onResponderGrant = this.handleResponderGrant; + props.onResponderMove = this.handleResponderMove; + props.onResponderRelease = this.handleResponderRelease; + props.onResponderTerminate = this.handleResponderTerminate; + return ; + }, +}); + +type RectOffset = { + top: number; + left: number; + right: number; + bottom: number; +} + +var PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; + +var RCTText = createReactNativeComponentClass(viewConfig); + +module.exports = Text; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..6e71f26 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "react-native-tooltip", + "version": "0.1.0", + "description": "A react-native wrapper for showing tooltips", + "main": "ToolTipText.ios.js", + "author": { + "name": "Chirag Jain", + "email": "jain_chirag04@yahoo.com", + "url": "http://chiragjain.tumblr.com" + }, + "repository": { + "type": "git", + "url": "git@github.com:chirag04/react-native-tooltip.git" + }, + "keywords": [ + "react", + "react-native", + "react-component", + "ios", + "tooltip", + ], + "dependencies": { + "react-native": "^0.4.4" + } +} diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..9a9f6a7 Binary files /dev/null and b/screenshot.png differ