diff --git a/Examples/SampleApp/index.ios.js b/Examples/SampleApp/index.ios.js index 97ff012e7..c6139d947 100644 --- a/Examples/SampleApp/index.ios.js +++ b/Examples/SampleApp/index.ios.js @@ -20,8 +20,11 @@ var SampleApp = React.createClass({ Welcome to React Native! - To get started, edit index.ios.js{'\n'} - Press Cmd+R to reload + To get started, edit index.ios.js + + + Press Cmd+R to reload,{'\n'} + Cmd+Shift+Z for dev menu ); @@ -43,6 +46,7 @@ var styles = StyleSheet.create({ instructions: { textAlign: 'center', color: '#333333', + marginBottom: 5, }, }); diff --git a/Examples/UIExplorer/UIExplorerPage.js b/Examples/UIExplorer/UIExplorerPage.js index 6890349ea..ea1761a28 100644 --- a/Examples/UIExplorer/UIExplorerPage.js +++ b/Examples/UIExplorer/UIExplorerPage.js @@ -40,7 +40,7 @@ var UIExplorerPage = React.createClass({ ContentWrapper = View; } else { ContentWrapper = ScrollView; - wrapperProps.keyboardShouldPeristTaps = true; + wrapperProps.keyboardShouldPersistTaps = true; wrapperProps.keyboardDismissMode = 'interactive'; } var title = this.props.title ? diff --git a/Libraries/Components/MapView/MapView.js b/Libraries/Components/MapView/MapView.js index b778fc695..388e22ddc 100644 --- a/Libraries/Components/MapView/MapView.js +++ b/Libraries/Components/MapView/MapView.js @@ -147,6 +147,9 @@ var MapView = React.createClass({ legalLabelInsets={this.props.legalLabelInsets} onChange={this._onChange} onTouchStart={this.props.onTouchStart} + onTouchMove={this.props.onTouchMove} + onTouchEnd={this.props.onTouchEnd} + onTouchCancel={this.props.onTouchCancel} /> ); }, diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index ba6a2c8b1..fc7fc7223 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -59,13 +59,20 @@ var ScrollView = React.createClass({ contentOffset: PointPropType, // zeros onScroll: PropTypes.func, onScrollAnimationEnd: PropTypes.func, - scrollEnabled: PropTypes.bool, // tre + scrollEnabled: PropTypes.bool, // true scrollIndicatorInsets: EdgeInsetsPropType, // zeros showsHorizontalScrollIndicator: PropTypes.bool, showsVerticalScrollIndicator: PropTypes.bool, style: StyleSheetPropType(ViewStylePropTypes), scrollEventThrottle: PropTypes.number, // null + /** + * When true, the scroll view bounces when it reaches the end of the + * content if the content is larger then the scroll view along the axis of + * the scroll direction. When false, it disables all bouncing even if + * the `alwaysBounce*` props are true. The default value is true. + */ + bounces: PropTypes.bool, /** * When true, the scroll view bounces horizontally when it reaches the end * even if the content is smaller than the scroll view itself. The default @@ -195,6 +202,14 @@ var ScrollView = React.createClass({ ); }, + scrollWithoutAnimationTo: function(destY?: number, destX?: number) { + RCTUIManager.scrollWithoutAnimationTo( + this.getNodeHandle(), + destX || 0, + destY || 0 + ); + }, + render: function() { var contentContainerStyle = [ this.props.horizontal && styles.contentContainerHorizontal, @@ -308,6 +323,7 @@ var validAttributes = { alwaysBounceHorizontal: true, alwaysBounceVertical: true, automaticallyAdjustContentInsets: true, + bounces: true, centerContent: true, contentInset: {diff: insetsDiffer}, contentOffset: {diff: pointsDiffer}, diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js index 867143b8c..f05e2f61b 100644 --- a/Libraries/Components/WebView/WebView.ios.js +++ b/Libraries/Components/WebView/WebView.ios.js @@ -60,7 +60,8 @@ var WebView = React.createClass({ propTypes: { renderError: PropTypes.func.isRequired, // view to show if there's an error renderLoading: PropTypes.func.isRequired, // loading indicator to show - url: PropTypes.string.isRequired, + url: PropTypes.string, + html: PropTypes.string, automaticallyAdjustContentInsets: PropTypes.bool, shouldInjectAJAXHandler: PropTypes.bool, contentInset: EdgeInsetsPropType, @@ -115,6 +116,7 @@ var WebView = React.createClass({ key="webViewKey" style={webViewStyles} url={this.props.url} + html={this.props.html} shouldInjectAJAXHandler={this.props.shouldInjectAJAXHandler} contentInset={this.props.contentInset} automaticallyAdjustContentInsets={this.props.automaticallyAdjustContentInsets} @@ -182,6 +184,7 @@ var WebView = React.createClass({ var RCTWebView = createReactIOSNativeComponentClass({ validAttributes: merge(ReactIOSViewAttributes.UIView, { url: true, + html: true, contentInset: {diff: insetsDiffer}, automaticallyAdjustContentInsets: true, shouldInjectAJAXHandler: true diff --git a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js index a9e06a6cf..51f6809cc 100644 --- a/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js +++ b/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js @@ -60,6 +60,10 @@ function setupDocumentShim() { if (GLOBAL.document) { GLOBAL.document.createElement = null; } + + // There is no DOM so MutationObserver doesn't make sense. It is used + // as feature detection in Bluebird Promise implementation + GLOBAL.MutationObserver = undefined; } function handleErrorWithRedBox(e) { diff --git a/Libraries/ReactIOS/ReactIOS.js b/Libraries/ReactIOS/ReactIOS.js index 028577429..56faaa30b 100644 --- a/Libraries/ReactIOS/ReactIOS.js +++ b/Libraries/ReactIOS/ReactIOS.js @@ -67,8 +67,12 @@ var augmentElement = function(element: ReactElement) { return element; }; -var render = function(component: ReactComponent, mountInto: number) { - ReactIOSMount.renderComponent(component, mountInto); +var render = function( + element: ReactElement, + mountInto: number, + callback?: ?(() => void) +): ?ReactComponent { + return ReactIOSMount.renderComponent(element, mountInto, callback); }; var ReactIOS = { diff --git a/Libraries/ReactIOS/ReactIOSDefaultInjection.js b/Libraries/ReactIOS/ReactIOSDefaultInjection.js index d6b81da2c..a64236973 100644 --- a/Libraries/ReactIOS/ReactIOSDefaultInjection.js +++ b/Libraries/ReactIOS/ReactIOSDefaultInjection.js @@ -24,6 +24,7 @@ var NodeHandle = require('NodeHandle'); var ReactClass = require('ReactClass'); var ReactComponentEnvironment = require('ReactComponentEnvironment'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); +var ReactEmptyComponent = require('ReactEmptyComponent'); var ReactInstanceHandles = require('ReactInstanceHandles'); var ReactIOSComponentEnvironment = require('ReactIOSComponentEnvironment'); var ReactIOSComponentMixin = require('ReactIOSComponentMixin'); @@ -36,6 +37,8 @@ var ReactUpdates = require('ReactUpdates'); var ResponderEventPlugin = require('ResponderEventPlugin'); var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle'); +var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass'); + // Just to ensure this gets packaged, since its only caller is from Native. require('RCTEventEmitter'); require('RCTLog'); @@ -77,6 +80,13 @@ function inject() { ReactIOSComponentEnvironment ); + // Can't import View here because it depends on React to make its composite + var RCTView = createReactIOSNativeComponentClass({ + validAttributes: {}, + uiViewClassName: 'RCTView', + }); + ReactEmptyComponent.injection.injectEmptyComponent(RCTView); + EventPluginUtils.injection.injectMount(ReactIOSMount); ReactClass.injection.injectMixin(ReactIOSComponentMixin); diff --git a/Libraries/ReactIOS/ReactIOSMount.js b/Libraries/ReactIOS/ReactIOSMount.js index 7e4094408..730031672 100644 --- a/Libraries/ReactIOS/ReactIOSMount.js +++ b/Libraries/ReactIOS/ReactIOSMount.js @@ -16,13 +16,13 @@ var RCTUIManager = require('NativeModules').UIManager; var ReactIOSTagHandles = require('ReactIOSTagHandles'); var ReactPerf = require('ReactPerf'); var ReactReconciler = require('ReactReconciler'); +var ReactUpdateQueue = require('ReactUpdateQueue'); var ReactUpdates = require('ReactUpdates'); var emptyObject = require('emptyObject'); var instantiateReactComponent = require('instantiateReactComponent'); var invariant = require('invariant'); - -var TOP_ROOT_NODE_IDS = {}; +var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); function instanceNumberToChildRootID(rootNodeID, instanceNumber) { return rootNodeID + '[' + instanceNumber + ']'; @@ -85,10 +85,26 @@ var ReactIOSMount = { * @param {containerTag} containerView Handle to native view tag */ renderComponent: function( - descriptor: ReactComponent, - containerTag: number - ) { - var instance = instantiateReactComponent(descriptor); + nextElement: ReactElement, + containerTag: number, + callback?: ?(() => void) + ): ?ReactComponent { + var topRootNodeID = ReactIOSTagHandles.tagToRootNodeID[containerTag]; + if (topRootNodeID) { + var prevComponent = ReactIOSMount._instancesByContainerID[topRootNodeID]; + if (prevComponent) { + var prevElement = prevComponent._currentElement; + if (shouldUpdateReactComponent(prevElement, nextElement)) { + ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement); + if (callback) { + ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback); + } + return prevComponent; + } else { + ReactIOSMount.unmountComponentAtNode(containerTag); + } + } + } if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) { console.error('You cannot render into anything but a top root'); @@ -100,13 +116,14 @@ var ReactIOSMount = { topRootNodeID, containerTag ); - TOP_ROOT_NODE_IDS[topRootNodeID] = true; + + var instance = instantiateReactComponent(nextElement); + ReactIOSMount._instancesByContainerID[topRootNodeID] = instance; var childRootNodeID = instanceNumberToChildRootID( topRootNodeID, ReactIOSMount.instanceCount++ ); - ReactIOSMount._instancesByContainerID[topRootNodeID] = instance; // The initial render is synchronous but any updates that happen during // rendering, in componentWillMount or componentDidMount, will be batched @@ -118,6 +135,11 @@ var ReactIOSMount = { childRootNodeID, topRootNodeID ); + var component = instance.getPublicInstance(); + if (callback) { + callback.call(component); + } + return component; }, /** @@ -170,20 +192,18 @@ var ReactIOSMount = { * component at this time. */ unmountComponentAtNode: function(containerTag: number): bool { - var containerID = ReactIOSTagHandles.tagToRootNodeID[containerTag]; + if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) { + console.error('You cannot render into anything but a top root'); + return; + } - invariant( - TOP_ROOT_NODE_IDS[containerID], - 'We only currently support removing components from the root node' - ); + var containerID = ReactIOSTagHandles.tagToRootNodeID[containerTag]; var instance = ReactIOSMount._instancesByContainerID[containerID]; if (!instance) { - console.error('Tried to unmount a component that does not exist'); return false; } ReactIOSMount.unmountComponentFromNode(instance, containerID); delete ReactIOSMount._instancesByContainerID[containerID]; - delete TOP_ROOT_NODE_IDS[containerID]; return true; }, @@ -200,10 +220,8 @@ var ReactIOSMount = { instance: ReactComponent, containerID: string ) { - // call back into native to remove all of the subviews from this container - // TODO: ReactComponent.prototype.unmountComponent is missing from Flow's - // react lib. - (instance: any).unmountComponent(); + // Call back into native to remove all of the subviews from this container + ReactReconciler.unmountComponent(instance); var containerTag = ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID); RCTUIManager.removeSubviewsFromContainerWithID(containerTag); diff --git a/React.podspec b/React.podspec index 4ad740e4a..8abc2a5ba 100644 --- a/React.podspec +++ b/React.podspec @@ -1,78 +1,94 @@ Pod::Spec.new do |s| - s.name = "React" - s.version = "0.1.0" - s.summary = "Build high quality mobile apps using React." - s.description= <<-DESC - React Native apps are built using the React JS framework, - and render directly to native UIKit elements using a fully - asynchronous architecture. There is no browser and no HTML. - We have picked what we think is the best set of features from - these and other technologies to build what we hope to become - the best product development framework available, with an - emphasis on iteration speed, developer delight, continuity - of technology, and absolutely beautiful and fast products - with no compromises in quality or capability. - DESC - s.homepage = "http://facebook.github.io/react-native/" - s.license = "BSD" - s.author = "Facebook" - s.platform = :ios, "7.0" - s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "v#{s.version}" } - s.source_files = "React/**/*.{c,h,m}" - s.resources = "Resources/*.png" - s.preserve_paths = "cli.js", "Libraries/**/*.js", "lint", "linter.js", "node_modules", "package.json", "packager", "PATENTS", "react-native-cli" - s.exclude_files = "**/__tests__/*", "IntegrationTests/*" - s.frameworks = "JavaScriptCore" - s.requires_arc = true - s.prepare_command = 'npm install' - s.libraries = 'icucore' + s.name = "React" + s.version = "0.3.1" + s.summary = "Build high quality mobile apps using React." + s.description = <<-DESC + React Native apps are built using the React JS + framework, and render directly to native UIKit + elements using a fully asynchronous architecture. + There is no browser and no HTML. We have picked what + we think is the best set of features from these and + other technologies to build what we hope to become + the best product development framework available, + with an emphasis on iteration speed, developer + delight, continuity of technology, and absolutely + beautiful and fast products with no compromises in + quality or capability. + DESC + s.homepage = "http://facebook.github.io/react-native/" + s.license = "BSD" + s.author = "Facebook" + s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "v#{s.version}" } + s.default_subspec = 'Core' + s.requires_arc = true + s.platform = :ios, "7.0" + s.prepare_command = 'npm install' + s.preserve_paths = "cli.js", "Libraries/**/*.js", "lint", "linter.js", "node_modules", "package.json", "packager", "PATENTS", "react-native-cli" + s.header_mappings_dir = "." + + s.subspec 'Core' do |ss| + ss.source_files = "React/**/*.{c,h,m}" + ss.exclude_files = "**/__tests__/*", "IntegrationTests/*" + ss.frameworks = "JavaScriptCore" + end s.subspec 'RCTActionSheet' do |ss| - ss.source_files = "Libraries/ActionSheetIOS/*.{h,m}" - ss.preserve_paths = "Libraries/ActionSheetIOS/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/ActionSheetIOS/*.{h,m}" + ss.preserve_paths = "Libraries/ActionSheetIOS/*.js" end s.subspec 'RCTAdSupport' do |ss| - ss.source_files = "Libraries/RCTAdSupport/*.{h,m}" - ss.preserve_paths = "Libraries/RCTAdSupport/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/AdSupport/*.{h,m}" + ss.preserve_paths = "Libraries/AdSupport/*.js" end s.subspec 'RCTAnimation' do |ss| - ss.source_files = "Libraries/Animation/*.{h,m}" - ss.preserve_paths = "Libraries/Animation/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Animation/*.{h,m}" + ss.preserve_paths = "Libraries/Animation/*.js" end s.subspec 'RCTGeolocation' do |ss| - ss.source_files = "Libraries/Geolocation/*.{h,m}" - ss.preserve_paths = "Libraries/Geolocation/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Geolocation/*.{h,m}" + ss.preserve_paths = "Libraries/Geolocation/*.js" end s.subspec 'RCTImage' do |ss| - ss.source_files = "Libraries/Image/*.{h,m}" - ss.preserve_paths = "Libraries/Image/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Image/*.{h,m}" + ss.preserve_paths = "Libraries/Image/*.js" end s.subspec 'RCTNetwork' do |ss| - ss.source_files = "Libraries/Network/*.{h,m}" - ss.preserve_paths = "Libraries/Network/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Network/*.{h,m}" + ss.preserve_paths = "Libraries/Network/*.js" end s.subspec 'RCTPushNotification' do |ss| - ss.source_files = "Libraries/PushNotificationIOS/*.{h,m}" - ss.preserve_paths = "Libraries/PushNotificationIOS/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/PushNotificationIOS/*.{h,m}" + ss.preserve_paths = "Libraries/PushNotificationIOS/*.js" end s.subspec 'RCTWebSocketDebugger' do |ss| - ss.source_files = "Libraries/RCTWebSocketDebugger/*.{h,m}" + ss.dependency 'React/Core' + ss.libraries = 'icucore' + ss.source_files = "Libraries/RCTWebSocketDebugger/*.{h,m}" end s.subspec 'RCTText' do |ss| - ss.source_files = "Libraries/Text/*.{h,m}" - ss.preserve_paths = "Libraries/Text/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Text/*.{h,m}" + ss.preserve_paths = "Libraries/Text/*.js" end s.subspec 'RCTVibration' do |ss| - ss.source_files = "Libraries/Vibration/*.{h,m}" - ss.preserve_paths = "Libraries/Vibration/*.js" + ss.dependency 'React/Core' + ss.source_files = "Libraries/Vibration/*.{h,m}" + ss.preserve_paths = "Libraries/Vibration/*.js" end end diff --git a/React/Modules/RCTAsyncLocalStorage.m b/React/Modules/RCTAsyncLocalStorage.m index e1daeb2fb..95fb383e4 100644 --- a/React/Modules/RCTAsyncLocalStorage.m +++ b/React/Modules/RCTAsyncLocalStorage.m @@ -157,7 +157,7 @@ static dispatch_queue_t RCTFileQueue(void) return RCTMakeAndLogError(@"Entries must be arrays of the form [key: string, value: string], got: ", entry, nil); } if (![entry[1] isKindOfClass:[NSString class]]) { - return RCTMakeAndLogError(@"Values must be strings, got: ", entry[1], entry[0]); + return RCTMakeAndLogError(@"Values must be strings, got: ", entry[1], @{@"key": entry[0]}); } NSString *key = entry[0]; id errorOut = RCTErrorForKey(key); diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index d460ea68d..82324f281 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -507,7 +507,7 @@ static NSString *RCTViewNameForModuleName(NSString *moduleName) { RCT_EXPORT(); - id container = _viewRegistry[containerID]; + id container = _shadowViewRegistry[containerID]; RCTAssert(container != nil, @"container view (for ID %@) not found", containerID); NSUInteger subviewsCount = [[container reactSubviews] count]; @@ -1051,13 +1051,27 @@ static void RCTMeasureLayout(RCTShadowView *view, [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ UIView *view = viewRegistry[reactTag]; if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) { - [(id)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue])]; + [(id)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:YES]; } else { RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag %@", view, reactTag); } }]; } +- (void)scrollWithoutAnimationToOffsetWithView:(NSNumber *)reactTag scrollToOffsetX:(NSNumber *)offsetX offsetY:(NSNumber *)offsetY +{ + RCT_EXPORT(scrollWithoutAnimationTo); + + [self addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry){ + UIView *view = viewRegistry[reactTag]; + if ([view conformsToProtocol:@protocol(RCTScrollableProtocol)]) { + [(id)view scrollToOffset:CGPointMake([offsetX floatValue], [offsetY floatValue]) animated:NO]; + } else { + RCTLogError(@"tried to scrollToOffset: on non-RCTScrollableProtocol view %@ with tag %@", view, reactTag); + } + }]; +} + - (void)zoomToRectWithView:(NSNumber *)reactTag rect:(NSDictionary *)rectDict { RCT_EXPORT(zoomToRect); diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index fa9975ac8..50d55a8a7 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -79,7 +79,7 @@ RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString) RCT_REMAP_VIEW_PROPERTY(opacity, alpha, CGFloat) RCT_REMAP_VIEW_PROPERTY(shadowColor, layer.shadowColor, CGColor); RCT_REMAP_VIEW_PROPERTY(shadowOffset, layer.shadowOffset, CGSize); -RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, CGFloat) +RCT_REMAP_VIEW_PROPERTY(shadowOpacity, layer.shadowOpacity, float) RCT_REMAP_VIEW_PROPERTY(shadowRadius, layer.shadowRadius, CGFloat) RCT_REMAP_VIEW_PROPERTY(transformMatrix, layer.transform, CATransform3D) RCT_CUSTOM_VIEW_PROPERTY(overflow, css_overflow, RCTView) diff --git a/React/Views/RCTWebView.m b/React/Views/RCTWebView.m index 86dae0172..bb9bb2acf 100644 --- a/React/Views/RCTWebView.m +++ b/React/Views/RCTWebView.m @@ -73,6 +73,11 @@ [_webView loadRequest:[NSURLRequest requestWithURL:URL]]; } +- (void)setHTML:(NSString *)HTML +{ + [_webView loadHTMLString:HTML baseURL:nil]; +} + - (void)layoutSubviews { [super layoutSubviews]; diff --git a/React/Views/RCTWebViewManager.m b/React/Views/RCTWebViewManager.m index 4b02f6c0a..7525ee236 100644 --- a/React/Views/RCTWebViewManager.m +++ b/React/Views/RCTWebViewManager.m @@ -22,8 +22,9 @@ } RCT_REMAP_VIEW_PROPERTY(url, URL, NSURL); +RCT_REMAP_VIEW_PROPERTY(html, HTML, NSString); RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets); -RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, UIEdgeInsets); +RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL); RCT_EXPORT_VIEW_PROPERTY(shouldInjectAJAXHandler, BOOL); - (NSDictionary *)constantsToExport diff --git a/package.json b/package.json index 1db1dc05f..ca60030f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native", - "version": "0.3.0", + "version": "0.3.1", "description": "A framework for building native apps using React", "repository": { "type": "git", diff --git a/packager/debugger.html b/packager/debugger.html index 38e9e6cdd..d0d4aba54 100644 --- a/packager/debugger.html +++ b/packager/debugger.html @@ -66,7 +66,7 @@ ws.onopen = function() { setStatus('Debugger session #' + sessionID + ' active'); ws.send(JSON.stringify({replyID: parseInt(sessionID, 10)})); } else { - setStatus('Waiting for simulator'); + setStatus('Waiting, press ⌘R in simulator to reload and connect'); } } diff --git a/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/__tests__/DependencyGraph-test.js b/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/__tests__/DependencyGraph-test.js index 69ed11e65..3202274c4 100644 --- a/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/__tests__/DependencyGraph-test.js +++ b/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/__tests__/DependencyGraph-test.js @@ -14,6 +14,7 @@ jest .dontMock('path') .dontMock('absolute-path') .dontMock('../docblock') + .dontMock('../../requirePattern') .setMock('../../../ModuleDescriptor', function(data) {return data;}); describe('DependencyGraph', function() { diff --git a/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/index.js b/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/index.js index 00c4a5c5c..a23f6d500 100644 --- a/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/index.js +++ b/packager/react-packager/src/DependencyResolver/haste/DependencyGraph/index.js @@ -12,6 +12,7 @@ var ModuleDescriptor = require('../../ModuleDescriptor'); var q = require('q'); var fs = require('fs'); var docblock = require('./docblock'); +var requirePattern = require('../requirePattern'); var path = require('path'); var isAbsolutePath = require('absolute-path'); var debug = require('debug')('DependecyGraph'); @@ -600,7 +601,6 @@ DependecyGraph.prototype._processAssetChange = function(eventType, file) { /** * Extract all required modules from a `code` string. */ -var requireRe = /\brequire\s*\(\s*[\'"]([^"\']+)["\']\s*\)/g; var blockCommentRe = /\/\*(.|\n)*?\*\//g; var lineCommentRe = /\/\/.+(\n|$)/g; function extractRequires(code) { @@ -609,7 +609,7 @@ function extractRequires(code) { code .replace(blockCommentRe, '') .replace(lineCommentRe, '') - .replace(requireRe, function(match, dep) { + .replace(requirePattern, function(match, _, dep) { deps.push(dep); }); diff --git a/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js b/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js index 69354590d..c81944d8e 100644 --- a/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js +++ b/packager/react-packager/src/DependencyResolver/haste/__tests__/HasteDependencyResolver-test.js @@ -10,6 +10,7 @@ jest.dontMock('../') .dontMock('q') + .dontMock('../requirePattern') .setMock('../../ModuleDescriptor', function(data) {return data;}); var q = require('q'); @@ -226,11 +227,13 @@ describe('HasteDependencyResolver', function() { }); var depGraph = depResolver._depGraph; - var dependencies = ['x', 'y', 'z']; + var dependencies = ['x', 'y', 'z', 'a', 'b']; var code = [ 'require("x")', 'require("y")', - 'require("z")', + 'require( "z" )', + 'require( "a")', + 'require("b" )', ].join('\n'); depGraph.resolveDependency.mockImpl(function(fromModule, toModuleName) { @@ -255,7 +258,9 @@ describe('HasteDependencyResolver', function() { ' require, requireDynamic, requireLazy, module, exports) {' + ' require(\'changed\')', 'require(\'y\')', - 'require("z")});', + 'require("z")', + 'require("a")', + 'require("b")});', ].join('\n')); }); }); diff --git a/packager/react-packager/src/DependencyResolver/haste/index.js b/packager/react-packager/src/DependencyResolver/haste/index.js index 0e46d5e8a..941a687ec 100644 --- a/packager/react-packager/src/DependencyResolver/haste/index.js +++ b/packager/react-packager/src/DependencyResolver/haste/index.js @@ -9,8 +9,8 @@ 'use strict'; var path = require('path'); -var FileWatcher = require('../../FileWatcher'); var DependencyGraph = require('./DependencyGraph'); +var requirePattern = require('./requirePattern'); var ModuleDescriptor = require('../ModuleDescriptor'); var declareOpts = require('../../lib/declareOpts'); @@ -25,7 +25,6 @@ var DEFINE_MODULE_CODE = [ ].join(''); var DEFINE_MODULE_REPLACE_RE = /_moduleName_|_code_|_deps_/g; -var REL_REQUIRE_STMT = /require\(['"]([\.\/0-9A-Z_$\-]*)['"]\)/gi; var validateOpts = declareOpts({ projectRoots: { @@ -146,12 +145,12 @@ HasteDependencyResolver.prototype.wrapModule = function(module, code) { } var relativizedCode = - code.replace(REL_REQUIRE_STMT, function(codeMatch, depName) { + code.replace(requirePattern, function(codeMatch, _, depName) { var depId = resolvedDeps[depName]; if (depId != null) { return 'require(\'' + depId + '\')'; } else { - return codeMatch; + return codeMatch.replace(/\s+/g, ''); } }); diff --git a/packager/react-packager/src/DependencyResolver/haste/requirePattern.js b/packager/react-packager/src/DependencyResolver/haste/requirePattern.js new file mode 100644 index 000000000..26d807ffd --- /dev/null +++ b/packager/react-packager/src/DependencyResolver/haste/requirePattern.js @@ -0,0 +1,14 @@ +/** + * 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. + */ + +'use strict'; + +var REQUIRE_RE = /\brequire\s*?\(\s*?([\'"])([^"\']+)\1\s*?\)/g; + +module.exports = REQUIRE_RE;