From 6b738d1b2eb42e2fba6bd7c6cd246ff1d885a27a Mon Sep 17 00:00:00 2001 From: Aaron Chiu Date: Tue, 28 Feb 2017 20:03:14 -0800 Subject: [PATCH 001/168] remove getAllPerformanceCounters() function Reviewed By: fkgozali Differential Revision: D4626085 fbshipit-source-id: f07f5a72791176f075d3ce450af4c7ae4cd6fa5c --- .../facebook/react/bridge/ReactContext.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java index f83c2ba56b9070..cf5f9e77fa206f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContext.java @@ -12,8 +12,6 @@ import javax.annotation.Nullable; import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; import android.app.Activity; @@ -28,10 +26,6 @@ import com.facebook.react.bridge.queue.ReactQueueConfiguration; import com.facebook.react.common.LifecycleState; -import static com.facebook.react.common.LifecycleState.BEFORE_CREATE; -import static com.facebook.react.common.LifecycleState.BEFORE_RESUME; -import static com.facebook.react.common.LifecycleState.RESUMED; - /** * Abstract ContextWrapper for Android application or activity {@link Context} and * {@link CatalystInstance} @@ -180,20 +174,6 @@ public void removeLifecycleEventListener(LifecycleEventListener listener) { mLifecycleEventListeners.remove(listener); } - public Map> getAllPerformanceCounters() { - Map> totalPerfMap = - new HashMap<>(); - if (mCatalystInstance != null) { - for (NativeModule nativeModule : mCatalystInstance.getNativeModules()) { - if (nativeModule instanceof PerformanceCounter) { - PerformanceCounter perfCounterModule = (PerformanceCounter) nativeModule; - totalPerfMap.put(nativeModule.getName(), perfCounterModule.getPerformanceCounters()); - } - } - } - return totalPerfMap; - } - public void addActivityEventListener(ActivityEventListener listener) { mActivityEventListeners.add(listener); } From 23f2f5f239a79c4bac74d79d11865519de5d4227 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 07:10:00 -0800 Subject: [PATCH 002/168] default root node to size of parent contraints Reviewed By: dshahidehpour Differential Revision: D4634616 fbshipit-source-id: 089eb4313c5bb810a6ff56f158cd19cec71808ec --- React/Views/RCTRootShadowView.m | 10 ---------- ReactCommon/yoga/yoga/Yoga.c | 12 +++++++++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/React/Views/RCTRootShadowView.m b/React/Views/RCTRootShadowView.m index 1d925a4fc9085a..2a134a7fe4fc2d 100644 --- a/React/Views/RCTRootShadowView.m +++ b/React/Views/RCTRootShadowView.m @@ -33,16 +33,6 @@ - (instancetype)init float availableWidth = _availableSize.width == INFINITY ? YGUndefined : _availableSize.width; float availableHeight = _availableSize.height == INFINITY ? YGUndefined : _availableSize.height; - YGUnit widthUnit = YGNodeStyleGetWidth(self.yogaNode).unit; - if (widthUnit == YGUnitUndefined || widthUnit == YGUnitAuto) { - YGNodeStyleSetWidthPercent(self.yogaNode, 100); - } - - YGUnit heightUnit = YGNodeStyleGetHeight(self.yogaNode).unit; - if (heightUnit == YGUnitUndefined || heightUnit == YGUnitAuto) { - YGNodeStyleSetHeightPercent(self.yogaNode, 100); - } - YGNodeCalculateLayout(self.yogaNode, availableWidth, availableHeight, _baseDirection); NSMutableSet *viewsWithNewFrame = [NSMutableSet set]; diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index f4de9b95c94e32..4bd7bc2831a3ce 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -3251,7 +3251,7 @@ static void YGRoundToPixelGrid(const YGNodeRef node) { float fractialTop = fmodf(nodeTop, gPointScaleFactor); float roundedLeft = nodeLeft - fractialLeft; float roundedTop = nodeTop - fractialTop; - + // To do the actual rounding we check if leftover fraction is bigger or equal than half of the grid step if (fractialLeft >= gPointScaleFactor / 2.0) { roundedLeft += gPointScaleFactor; @@ -3263,13 +3263,13 @@ static void YGRoundToPixelGrid(const YGNodeRef node) { } node->layout.position[YGEdgeLeft] = roundedLeft; node->layout.position[YGEdgeTop] = roundedTop; - + // Now we round width and height in the same way accounting for fractial leftovers from rounding position const float adjustedWidth = fractialLeft + node->layout.dimensions[YGDimensionWidth]; const float adjustedHeight = fractialTop + node->layout.dimensions[YGDimensionHeight]; float roundedWidth = adjustedWidth - fmodf(adjustedWidth, gPointScaleFactor); float roundedHeight = adjustedHeight - fmodf(adjustedHeight, gPointScaleFactor); - + if (adjustedWidth - roundedWidth >= gPointScaleFactor / 2.0) { roundedWidth += gPointScaleFactor; } @@ -3307,6 +3307,9 @@ void YGNodeCalculateLayout(const YGNodeRef node, } else if (YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], parentWidth) >= 0.0f) { width = YGValueResolve(&node->style.maxDimensions[YGDimensionWidth], parentWidth); widthMeasureMode = YGMeasureModeAtMost; + } else { + width = parentWidth; + widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined : YGMeasureModeExactly; } float height = YGUndefined; @@ -3319,6 +3322,9 @@ void YGNodeCalculateLayout(const YGNodeRef node, 0.0f) { height = YGValueResolve(&node->style.maxDimensions[YGDimensionHeight], parentHeight); heightMeasureMode = YGMeasureModeAtMost; + } else { + height = parentHeight; + heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined : YGMeasureModeExactly; } if (YGLayoutNodeInternal(node, From e44730cb633aa6e9667426b13f00947d2c99dd7f Mon Sep 17 00:00:00 2001 From: Martin Konicek Date: Wed, 1 Mar 2017 07:46:22 -0800 Subject: [PATCH 003/168] Fast finish Travis builds, disable tvOS and JS tests Reviewed By: mkonicek Differential Revision: D4635182 Ninja: Manual import https://github.com/facebook/react-native/pull/12603 fbshipit-source-id: f512bf3ce7840b3fbc229e9225e06e3112d849d3 --- .travis.yml | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 40f52ea8c85334..1729ddb1090e7a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,21 +18,18 @@ install: script: - if [[ "$TEST_TYPE" = objc-ios ]]; then travis_retry travis_wait ./scripts/objc-test-ios.sh; fi - - if [[ "$TEST_TYPE" = objc-tvos ]]; then travis_retry travis_wait ./scripts/objc-test-tvos.sh; fi - if [[ "$TEST_TYPE" = e2e-objc ]]; then node ./scripts/run-ci-e2e-tests.js --ios --js --retries 3; fi - - if [[ "$TEST_TYPE" = e2e-objc-tvos ]]; then node ./scripts/run-ci-e2e-tests.js --tvos --retries 3; fi - - if [[ "$TEST_TYPE" = js ]]; then npm run flow check; fi - - if [[ "$TEST_TYPE" = js ]]; then npm test -- --maxWorkers=1; fi - if [[ ( "$TEST_TYPE" = podspecs ) && ( "$TRAVIS_PULL_REQUEST" = "false" ) ]]; then gem install cocoapods && ./scripts/process-podspecs.sh; fi + +matrix: + - fast_finish: true # Fail the whole build as soon as one test type fails. Should help with Travis capacity issues (very long queues). + +# The order of these tests says which are more likely to run first and fail the whole build fast. env: - matrix: - - TEST_TYPE=e2e-objc-tvos - - TEST_TYPE=e2e-objc - - TEST_TYPE=objc-ios - - TEST_TYPE=objc-tvos - - TEST_TYPE=js - - TEST_TYPE=podspecs + - TEST_TYPE=objc-ios + - TEST_TYPE=podspecs + - TEST_TYPE=e2e-objc branches: only: @@ -43,7 +40,7 @@ notifications: email: recipients: - mkonicek@fb.com - - eloy@artsy.net + - eloy@artsy.net # Eloy Durán maintains the podspecs test and wants to be notified about failures. on_failure: change on_success: change slack: From 04f42ab0757f1d9866e48715537b029ecca3c17f Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Wed, 1 Mar 2017 07:50:39 -0800 Subject: [PATCH 004/168] packager: DependencyGraph-test: go through fs.watch mock rather than manual API Reviewed By: davidaurelio Differential Revision: D4628593 fbshipit-source-id: 43ccdb038bd387e87096f2a7020c98d915fa5bba --- .../src/node-haste/__mocks__/graceful-fs.js | 34 +++++ .../__tests__/DependencyGraph-test.js | 138 +++++++++--------- packager/src/node-haste/index.js | 5 +- 3 files changed, 111 insertions(+), 66 deletions(-) diff --git a/packager/src/node-haste/__mocks__/graceful-fs.js b/packager/src/node-haste/__mocks__/graceful-fs.js index 8a885f8b814996..bd429181fdbbb1 100644 --- a/packager/src/node-haste/__mocks__/graceful-fs.js +++ b/packager/src/node-haste/__mocks__/graceful-fs.js @@ -8,6 +8,7 @@ */ 'use strict'; +const {EventEmitter} = require('events'); const {dirname} = require.requireActual('path'); const fs = jest.genMockFromModule('fs'); const path = require('path'); @@ -96,7 +97,12 @@ fs.readFileSync.mockImplementation(function(filepath, encoding) { function makeStatResult(node) { const isSymlink = node != null && node.SYMLINK != null; return { + isBlockDevice: () => false, + isCharacterDevice: () => false, isDirectory: () => node != null && typeof node === 'object' && !isSymlink, + isFIFO: () => false, + isFile: () => node != null && typeof node === 'string', + isSocket: () => false, isSymbolicLink: () => isSymlink, mtime, }; @@ -242,6 +248,34 @@ fs.createWriteStream.mock.returned = []; fs.__setMockFilesystem = object => (filesystem = object); +const watcherListByPath = new Map(); + +fs.watch.mockImplementation((filename, options, listener) => { + if (options.recursive) { + throw new Error('recursive watch not implemented'); + } + let watcherList = watcherListByPath.get(filename); + if (watcherList == null) { + watcherList = []; + watcherListByPath.set(filename, watcherList); + } + const fsWatcher = new EventEmitter(); + fsWatcher.on('change', listener); + fsWatcher.close = () => { + watcherList.splice(watcherList.indexOf(fsWatcher), 1); + fsWatcher.close = () => { throw new Error('FSWatcher is already closed'); }; + }; + watcherList.push(fsWatcher); +}); + +fs.__triggerWatchEvent = (eventType, filename) => { + const directWatchers = watcherListByPath.get(filename) || []; + directWatchers.forEach(wtc => wtc.emit('change', eventType)); + const dirPath = path.dirname(filename); + const dirWatchers = watcherListByPath.get(dirPath) || []; + dirWatchers.forEach(wtc => wtc.emit('change', eventType, path.relative(dirPath, filename))); +}; + function getToNode(filepath) { // Ignore the drive for Windows paths. if (filepath.match(/^[a-zA-Z]:\\/)) { diff --git a/packager/src/node-haste/__tests__/DependencyGraph-test.js b/packager/src/node-haste/__tests__/DependencyGraph-test.js index e6e00a01eee826..e3449e624e48f8 100644 --- a/packager/src/node-haste/__tests__/DependencyGraph-test.js +++ b/packager/src/node-haste/__tests__/DependencyGraph-test.js @@ -130,7 +130,7 @@ describe('DependencyGraph', function() { }, getTransformCacheKey: () => 'abcdef', reporter: require('../../lib/reporting').nullReporter, - watch: false, + watch: true, }; }); @@ -3111,70 +3111,74 @@ describe('DependencyGraph', function() { filesystem.root['index.js'] = filesystem.root['index.js'] .replace('require("dontWork")', '') .replace('require("wontWork")', ''); - dgraph.processFileChange('change', root + '/index.js', mockStat); - return getOrderedDependenciesAsJSON(dgraph, '/root/index.js') - .then(deps => { - expect(deps).toEqual([ - { - id: 'index', - path: '/root/index.js', - dependencies: [ - 'shouldWork', - 'ember', - 'internalVendoredPackage', - 'anotherIndex', - ], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'shouldWork', - path: '/root/node_modules/react-haste/main.js', - dependencies: ['submodule'], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'submodule/main.js', - path: '/root/node_modules/react-haste/node_modules/submodule/main.js', - dependencies: [], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'ember/main.js', - path: '/root/node_modules/ember/main.js', - dependencies: [], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'internalVendoredPackage', - path: '/root/vendored_modules/a-vendored-package/main.js', - dependencies: [], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - { - id: 'anotherIndex', - path: '/anotherRoot/index.js', - dependencies: [], - isAsset: false, - isJSON: false, - isPolyfill: false, - resolution: undefined, - }, - ]); + triggerWatchEvent('change', root + '/index.js'); + return new Promise(resolve => { + dgraph.once('change', () => { + return resolve(getOrderedDependenciesAsJSON(dgraph, '/root/index.js') + .then(deps => { + expect(deps).toEqual([ + { + id: 'index', + path: '/root/index.js', + dependencies: [ + 'shouldWork', + 'ember', + 'internalVendoredPackage', + 'anotherIndex', + ], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'shouldWork', + path: '/root/node_modules/react-haste/main.js', + dependencies: ['submodule'], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'submodule/main.js', + path: '/root/node_modules/react-haste/node_modules/submodule/main.js', + dependencies: [], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'ember/main.js', + path: '/root/node_modules/ember/main.js', + dependencies: [], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'internalVendoredPackage', + path: '/root/vendored_modules/a-vendored-package/main.js', + dependencies: [], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + { + id: 'anotherIndex', + path: '/anotherRoot/index.js', + dependencies: [], + isAsset: false, + isJSON: false, + isPolyfill: false, + resolution: undefined, + }, + ]); + })); + }); }); }); }); @@ -5455,4 +5459,8 @@ describe('DependencyGraph', function() { function setMockFileSystem(object) { return require('graceful-fs').__setMockFilesystem(object); } + + function triggerWatchEvent(eventType, filename) { + return require('graceful-fs').__triggerWatchEvent(eventType, filename); + } }); diff --git a/packager/src/node-haste/index.js b/packager/src/node-haste/index.js index 7aeaadd17a2a08..5600b0904ebbef 100644 --- a/packager/src/node-haste/index.js +++ b/packager/src/node-haste/index.js @@ -36,6 +36,7 @@ const { createActionStartEntry, log, } = require('../Logger'); +const {EventEmitter} = require('events'); import type {Options as TransformOptions} from '../JSTransformer/worker/worker'; import type GlobalTransformCache from '../lib/GlobalTransformCache'; @@ -72,7 +73,7 @@ type Options = { watch: boolean, }; -class DependencyGraph { +class DependencyGraph extends EventEmitter { _opts: Options; _haste: JestHasteMap; _hasteFS: HasteFS; @@ -84,6 +85,7 @@ class DependencyGraph { _loading: Promise; constructor(opts: Options) { + super(); this._opts = {...opts}; this._helpers = new DependencyGraphHelpers(this._opts); this.load(); @@ -154,6 +156,7 @@ class DependencyGraph { eventsQueue.forEach(({type, filePath, stat}) => this.processFileChange(type, filePath, stat) ); + this.emit('change'); }); const buildingHasteMapLogEntry = From 4d00df41b451e5223ac75e6914454b7e44105aa4 Mon Sep 17 00:00:00 2001 From: Christoph Pojer Date: Wed, 1 Mar 2017 08:05:59 -0800 Subject: [PATCH 005/168] Fix lint errors 2/2 Reviewed By: jeanlauliac Differential Revision: D4628330 fbshipit-source-id: 94fad1294e22fa0073e15843f94241ae778112a0 --- packager/blacklist.js | 2 +- packager/src/Bundler/__tests__/Bundle-test.js | 56 +++++------ packager/src/Bundler/index.js | 5 +- packager/src/Bundler/source-map/encode.js | 6 +- .../worker/__tests__/inline-test.js | 22 ++--- .../worker/extract-dependencies.js | 7 +- .../src/ModuleGraph/__tests__/Graph-test.js | 92 ++++++++++--------- .../src/ModuleGraph/node-haste/HasteFS.js | 8 +- .../__tests__/collect-dependencies-test.js | 44 ++++----- .../worker/__tests__/optimize-module-test.js | 1 + .../worker/__tests__/transform-module-test.js | 44 ++++----- .../ModuleGraph/worker/transform-module.js | 4 +- .../src/Resolver/__tests__/Resolver-test.js | 41 +-------- packager/src/Resolver/index.js | 5 +- packager/src/Resolver/polyfills/Number.es6.js | 1 + .../src/Resolver/polyfills/error-guard.js | 2 + packager/src/Server/index.js | 6 +- packager/src/lib/relativizeSourceMap.js | 4 +- .../node-haste/DependencyGraph/HasteMap.js | 1 + .../src/node-haste/__mocks__/graceful-fs.js | 8 +- .../__tests__/DependencyGraph-test.js | 2 +- packager/src/node-haste/index.js | 4 +- packager/transformer.js | 4 +- 23 files changed, 183 insertions(+), 186 deletions(-) diff --git a/packager/blacklist.js b/packager/blacklist.js index 9a6b08c8133839..3ae74047c60a7e 100644 --- a/packager/blacklist.js +++ b/packager/blacklist.js @@ -29,7 +29,7 @@ function escapeRegExp(pattern) { } else if (typeof pattern === 'string') { var escaped = pattern.replace(/[\-\[\]\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); // convert the '/' into an escaped local file separator - return escaped.replace(/\//g,'\\' + path.sep); + return escaped.replace(/\//g, '\\' + path.sep); } else { throw new Error('Unexpected packager blacklist pattern: ' + pattern); } diff --git a/packager/src/Bundler/__tests__/Bundle-test.js b/packager/src/Bundler/__tests__/Bundle-test.js index 0cafff1a62c206..a35770cd8786b4 100644 --- a/packager/src/Bundler/__tests__/Bundle-test.js +++ b/packager/src/Bundler/__tests__/Bundle-test.js @@ -12,7 +12,6 @@ jest.disableAutomock(); const Bundle = require('../Bundle'); const ModuleTransport = require('../../lib/ModuleTransport'); -const SourceMapGenerator = require('source-map').SourceMapGenerator; const crypto = require('crypto'); describe('Bundle', () => { @@ -107,33 +106,37 @@ describe('Bundle', () => { }); }); - it('should insert modules in a deterministic order, independent from timing of the wrapping process', () => { - const moduleTransports = [ - createModuleTransport({name: 'module1'}), - createModuleTransport({name: 'module2'}), - createModuleTransport({name: 'module3'}), - ]; - - const resolves = {}; - const resolver = { - wrapModule({name}) { - return new Promise(resolve => resolves[name] = resolve); - }, - }; - - const promise = Promise.all( - moduleTransports.map(m => bundle.addModule(resolver, null, {isPolyfill: () => false}, m))) - .then(() => { - expect(bundle.getModules()) - .toEqual(moduleTransports); - }); + it('inserts modules in a deterministic order, independent of timing of the wrapper process', + () => { + const moduleTransports = [ + createModuleTransport({name: 'module1'}), + createModuleTransport({name: 'module2'}), + createModuleTransport({name: 'module3'}), + ]; + + const resolves = {}; + const resolver = { + wrapModule({name}) { + return new Promise(resolve => { + resolves[name] = resolve; + }); + }, + }; + + const promise = Promise.all(moduleTransports.map( + m => bundle.addModule(resolver, null, {isPolyfill: () => false}, m) + )).then(() => { + expect(bundle.getModules()) + .toEqual(moduleTransports); + }); - resolves.module2({code: ''}); - resolves.module3({code: ''}); - resolves.module1({code: ''}); + resolves.module2({code: ''}); + resolves.module3({code: ''}); + resolves.module1({code: ''}); - return promise; - }); + return promise; + }, + ); }); describe('sourcemap bundle', () => { @@ -268,7 +271,6 @@ describe('Bundle', () => { describe('getEtag()', function() { it('should return an etag', function() { - var bundle = new Bundle({sourceMapUrl: 'test_url'}); bundle.finalize({}); var eTag = crypto.createHash('md5').update(bundle.getSource()).digest('hex'); expect(bundle.getEtag()).toEqual(eTag); diff --git a/packager/src/Bundler/index.js b/packager/src/Bundler/index.js index 7ad32fbd7f9c59..15b06b0cc4591c 100644 --- a/packager/src/Bundler/index.js +++ b/packager/src/Bundler/index.js @@ -38,7 +38,10 @@ const VERSION = require('../../package.json').version; import type AssetServer from '../AssetServer'; import type Module, {HasteImpl} from '../node-haste/Module'; import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse'; -import type {Options as JSTransformerOptions, TransformOptions} from '../JSTransformer/worker/worker'; +import type { + Options as JSTransformerOptions, + TransformOptions, +} from '../JSTransformer/worker/worker'; import type {Reporter} from '../lib/reporting'; import type GlobalTransformCache from '../lib/GlobalTransformCache'; diff --git a/packager/src/Bundler/source-map/encode.js b/packager/src/Bundler/source-map/encode.js index 04bf463aac1f47..cc05fa10308cd6 100644 --- a/packager/src/Bundler/source-map/encode.js +++ b/packager/src/Bundler/source-map/encode.js @@ -8,13 +8,14 @@ * * @flow */ + /** * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause * * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * https://git.io/vymuA * * Copyright 2011 The Closure Compiler Authors. All rights reserved. * Redistribution and use in source and binary forms, with or without @@ -107,7 +108,8 @@ function toVLQSigned(value) { * V8 OPTIMIZATION! */ function encode(value: number, buffer: Buffer, position: number): number { - let digit, vlq = toVLQSigned(value); + let vlq = toVLQSigned(value); + let digit; do { digit = vlq & VLQ_BASE_MASK; vlq >>>= VLQ_BASE_SHIFT; diff --git a/packager/src/JSTransformer/worker/__tests__/inline-test.js b/packager/src/JSTransformer/worker/__tests__/inline-test.js index 821aaf4cf0a702..d2a10f556452f1 100644 --- a/packager/src/JSTransformer/worker/__tests__/inline-test.js +++ b/packager/src/JSTransformer/worker/__tests__/inline-test.js @@ -8,6 +8,8 @@ */ 'use strict'; +/* eslint-disable max-len */ + jest.disableAutomock(); const inline = require('../inline'); const {transform, transformFromAst} = require('babel-core'); @@ -205,7 +207,9 @@ describe('inline constants', () => { var b = a.ReactNative.Platform.select({}); }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'ios'}); - expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative\.Platform\.select[^;]+/, '1'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/ReactNative\.Platform\.select[^;]+/, '1')), + ); }); it('replaces React.Platform.select in the code if React is a top level import', () => { @@ -237,7 +241,9 @@ describe('inline constants', () => { var b = a.ReactNative.Platform.select; }`; const {ast} = inline('arbitrary.js', {code}, {platform: 'android'}); - expect(toString(ast)).toEqual(normalize(code.replace(/ReactNative.Platform\.select[^;]+/, '2'))); + expect(toString(ast)).toEqual( + normalize(code.replace(/ReactNative.Platform\.select[^;]+/, '2')), + ); }); it('replaces require("react-native").Platform.select in the code', () => { @@ -269,18 +275,6 @@ describe('inline constants', () => { normalize(code.replace(/process\.env\.NODE_ENV/, '"production"'))); }); - it('replaces process.env.NODE_ENV in the code', () => { - const code = `function a() { - if (process.env.NODE_ENV === 'production') { - return require('Prod'); - } - return require('Dev'); - }`; - const {ast} = inline('arbitrary.js', {code}, {dev: true}); - expect(toString(ast)).toEqual( - normalize(code.replace(/process\.env\.NODE_ENV/, '"development"'))); - }); - it('accepts an AST as input', function() { const code = 'function ifDev(a,b){return __DEV__?a:b;}'; const {ast} = inline('arbitrary.hs', {ast: toAst(code)}, {dev: false}); diff --git a/packager/src/JSTransformer/worker/extract-dependencies.js b/packager/src/JSTransformer/worker/extract-dependencies.js index d88407f11650e4..1ce908b98e5356 100644 --- a/packager/src/JSTransformer/worker/extract-dependencies.js +++ b/packager/src/JSTransformer/worker/extract-dependencies.js @@ -33,7 +33,12 @@ function extractDependencies(code: string) { const node = path.node; const callee = node.callee; const arg = node.arguments[0]; - if (callee.type !== 'Identifier' || callee.name !== 'require' || !arg || arg.type !== 'StringLiteral') { + if ( + callee.type !== 'Identifier' || + callee.name !== 'require' || + !arg || + arg.type !== 'StringLiteral' + ) { return; } dependencyOffsets.push(arg.start); diff --git a/packager/src/ModuleGraph/__tests__/Graph-test.js b/packager/src/ModuleGraph/__tests__/Graph-test.js index 7183c7b075d0d8..621f489d77cb70 100644 --- a/packager/src/ModuleGraph/__tests__/Graph-test.js +++ b/packager/src/ModuleGraph/__tests__/Graph-test.js @@ -208,50 +208,52 @@ describe('Graph:', () => { }); }); - it('calls back with an array of modules in depth-first traversal order, regardless of the order of resolution', done => { - load.stub.reset(); - resolve.stub.reset(); - - const ids = [ - 'a', - 'b', - 'c', 'd', - 'e', - 'f', 'g', - 'h', - ]; - ids.forEach(id => { - const path = idToPath(id); - resolve.stub.withArgs(id).yields(null, path); - load.stub.withArgs(path).yields(null, createFile(id), []); - }); - load.stub.withArgs(idToPath('a')).yields(null, createFile('a'), ['b', 'e', 'h']); - load.stub.withArgs(idToPath('b')).yields(null, createFile('b'), ['c', 'd']); - load.stub.withArgs(idToPath('e')).yields(null, createFile('e'), ['f', 'g']); - - // load certain ids later - ['b', 'e', 'h'].forEach(id => resolve.stub.withArgs(id).resetBehavior()); - resolve.stub.withArgs('h').func = (a, b, c, d, callback) => { - callback(null, idToPath('h')); - ['e', 'b'].forEach( - id => resolve.stub.withArgs(id).yield(null, idToPath(id))); - }; - - graph(['a'], anyPlatform, noOpts, (error, result) => { - expect(error).toEqual(null); - expect(result.modules).toEqual([ - createModule('a', ['b', 'e', 'h']), - createModule('b', ['c', 'd']), - createModule('c'), - createModule('d'), - createModule('e', ['f', 'g']), - createModule('f'), - createModule('g'), - createModule('h'), - ]); - done(); - }); - }); + it('resolves modules in depth-first traversal order, regardless of the order of resolution', + done => { + load.stub.reset(); + resolve.stub.reset(); + + const ids = [ + 'a', + 'b', + 'c', 'd', + 'e', + 'f', 'g', + 'h', + ]; + ids.forEach(id => { + const path = idToPath(id); + resolve.stub.withArgs(id).yields(null, path); + load.stub.withArgs(path).yields(null, createFile(id), []); + }); + load.stub.withArgs(idToPath('a')).yields(null, createFile('a'), ['b', 'e', 'h']); + load.stub.withArgs(idToPath('b')).yields(null, createFile('b'), ['c', 'd']); + load.stub.withArgs(idToPath('e')).yields(null, createFile('e'), ['f', 'g']); + + // load certain ids later + ['b', 'e', 'h'].forEach(id => resolve.stub.withArgs(id).resetBehavior()); + resolve.stub.withArgs('h').func = (a, b, c, d, callback) => { + callback(null, idToPath('h')); + ['e', 'b'].forEach( + id => resolve.stub.withArgs(id).yield(null, idToPath(id))); + }; + + graph(['a'], anyPlatform, noOpts, (error, result) => { + expect(error).toEqual(null); + expect(result.modules).toEqual([ + createModule('a', ['b', 'e', 'h']), + createModule('b', ['c', 'd']), + createModule('c'), + createModule('d'), + createModule('e', ['f', 'g']), + createModule('f'), + createModule('g'), + createModule('h'), + ]); + done(); + }); + }, + ); it('calls back with the resolved modules of the entry points', done => { load.stub.reset(); @@ -274,7 +276,7 @@ describe('Graph:', () => { }); }); - it('calls back with the resolved modules of the entry points if one entry point is a dependency of another', done => { + it('resolves modules for all entry points correctly if one is a dependency of another', done => { load.stub.reset(); resolve.stub.reset(); diff --git a/packager/src/ModuleGraph/node-haste/HasteFS.js b/packager/src/ModuleGraph/node-haste/HasteFS.js index 11717926815de0..c48f7c25ff6f35 100644 --- a/packager/src/ModuleGraph/node-haste/HasteFS.js +++ b/packager/src/ModuleGraph/node-haste/HasteFS.js @@ -25,7 +25,9 @@ module.exports = class HasteFS { } closest(path: string, fileName: string): ?string { - let {dir, root} = parse(path); + const parsedPath = parse(path); + const root = parsedPath.root; + let dir = parsedPath.dir; do { const candidate = join(dir, fileName); if (this.files.has(candidate)) { @@ -63,7 +65,9 @@ module.exports = class HasteFS { function buildDirectorySet(files) { const directories = new Set(); files.forEach(path => { - let {dir, root} = parse(path); + const parsedPath = parse(path); + const root = parsedPath.root; + let dir = parsedPath.dir; while (dir !== '.' && dir !== root && !directories.has(dir)) { directories.add(dir); dir = dirname(dir); diff --git a/packager/src/ModuleGraph/worker/__tests__/collect-dependencies-test.js b/packager/src/ModuleGraph/worker/__tests__/collect-dependencies-test.js index 72d9a6f3b1dadd..5ce6310ac3515d 100644 --- a/packager/src/ModuleGraph/worker/__tests__/collect-dependencies-test.js +++ b/packager/src/ModuleGraph/worker/__tests__/collect-dependencies-test.js @@ -63,27 +63,29 @@ describe('dependency collection from ASTs:', () => { .toEqual(any(String)); }); - it('replaces all required module ID strings with array lookups and keeps the ID as second argument', () => { - const ast = astFromCode(` - const a = require('b/lib/a'); - const b = require(123); - exports.do = () => require("do"); - if (!something) { - require("setup/something"); - } - `); - - const {dependencyMapName} = collectDependencies(ast); - - expect(codeFromAst(ast)).toEqual(comparableCode(` - const a = require(${dependencyMapName}[0], 'b/lib/a'); - const b = require(123); - exports.do = () => require(${dependencyMapName}[1], "do"); - if (!something) { - require(${dependencyMapName}[2], "setup/something"); - } - `)); - }); + it('replaces all required module ID strings with array lookups, keeps the ID as second argument', + () => { + const ast = astFromCode(` + const a = require('b/lib/a'); + const b = require(123); + exports.do = () => require("do"); + if (!something) { + require("setup/something"); + } + `); + + const {dependencyMapName} = collectDependencies(ast); + + expect(codeFromAst(ast)).toEqual(comparableCode(` + const a = require(${dependencyMapName}[0], 'b/lib/a'); + const b = require(123); + exports.do = () => require(${dependencyMapName}[1], "do"); + if (!something) { + require(${dependencyMapName}[2], "setup/something"); + } + `)); + }, + ); }); describe('Dependency collection from optimized ASTs:', () => { diff --git a/packager/src/ModuleGraph/worker/__tests__/optimize-module-test.js b/packager/src/ModuleGraph/worker/__tests__/optimize-module-test.js index e94f8a07f48248..efec7f3a319316 100644 --- a/packager/src/ModuleGraph/worker/__tests__/optimize-module-test.js +++ b/packager/src/ModuleGraph/worker/__tests__/optimize-module-test.js @@ -94,4 +94,5 @@ function findLast(code, needle) { return {line: line + 1, column}; } } + return null; } diff --git a/packager/src/ModuleGraph/worker/__tests__/transform-module-test.js b/packager/src/ModuleGraph/worker/__tests__/transform-module-test.js index ceda733caaf523..105e84b4d04f36 100644 --- a/packager/src/ModuleGraph/worker/__tests__/transform-module-test.js +++ b/packager/src/ModuleGraph/worker/__tests__/transform-module-test.js @@ -19,8 +19,6 @@ const {parse} = require('babylon'); const generate = require('babel-generator').default; const {traverse} = require('babel-core'); -const {any, objectContaining} = jasmine; - describe('transforming JS modules:', () => { const filename = 'arbitrary'; @@ -47,7 +45,7 @@ describe('transforming JS modules:', () => { it('passes through file name and code', done => { transformModule(sourceCode, options(), (error, result) => { - expect(result).toEqual(objectContaining({ + expect(result).toEqual(expect.objectContaining({ code: sourceCode, file: filename, })); @@ -59,36 +57,39 @@ describe('transforming JS modules:', () => { const hasteID = 'TheModule'; const codeWithHasteID = `/** @providesModule ${hasteID} */`; transformModule(codeWithHasteID, options(), (error, result) => { - expect(result).toEqual(objectContaining({hasteID})); + expect(result).toEqual(expect.objectContaining({hasteID})); done(); }); }); it('sets `type` to `"module"` by default', done => { transformModule(sourceCode, options(), (error, result) => { - expect(result).toEqual(objectContaining({type: 'module'})); + expect(result).toEqual(expect.objectContaining({type: 'module'})); done(); }); }); it('sets `type` to `"script"` if the input is a polyfill', done => { transformModule(sourceCode, {...options(), polyfill: true}, (error, result) => { - expect(result).toEqual(objectContaining({type: 'script'})); + expect(result).toEqual(expect.objectContaining({type: 'script'})); done(); }); }); - it('calls the passed-in transform function with code, file name, and options for all passed in variants', done => { - const variants = {dev: {dev: true}, prod: {dev: false}}; + it('calls the passed-in transform function with code, file name, and options ' + + 'for all passed in variants', + done => { + const variants = {dev: {dev: true}, prod: {dev: false}}; - transformModule(sourceCode, options(variants), () => { - expect(transformer.transform) - .toBeCalledWith(sourceCode, filename, variants.dev); - expect(transformer.transform) - .toBeCalledWith(sourceCode, filename, variants.prod); - done(); - }); - }); + transformModule(sourceCode, options(variants), () => { + expect(transformer.transform) + .toBeCalledWith(sourceCode, filename, variants.dev); + expect(transformer.transform) + .toBeCalledWith(sourceCode, filename, variants.prod); + done(); + }); + }, + ); it('calls back with any error yielded by the transform function', done => { const error = new Error(); @@ -114,7 +115,7 @@ describe('transforming JS modules:', () => { }); }); - it('wraps the code produced by the transform function into an immediately invoked function expression for polyfills', done => { + it('wraps the code produced by the transform function into an IIFE for polyfills', done => { transformModule(sourceCode, {...options(), polyfill: true}, (error, result) => { expect(error).toEqual(null); @@ -131,20 +132,21 @@ describe('transforming JS modules:', () => { const column = code.indexOf('code'); const consumer = new SourceMapConsumer(map); expect(consumer.originalPositionFor({line: 1, column})) - .toEqual(objectContaining({line: 1, column: sourceCode.indexOf('code')})); + .toEqual(expect.objectContaining({line: 1, column: sourceCode.indexOf('code')})); done(); }); }); it('extracts dependencies (require calls)', done => { - const dep1 = 'foo', dep2 = 'bar'; + const dep1 = 'foo'; + const dep2 = 'bar'; const code = `require('${dep1}'),require('${dep2}')`; const {body} = parse(code).program; transformer.transform.stub.returns(transformResult(body)); transformModule(code, options(), (error, result) => { expect(result.transformed.default) - .toEqual(objectContaining({dependencies: [dep1, dep2]})); + .toEqual(expect.objectContaining({dependencies: [dep1, dep2]})); done(); }); }); @@ -190,7 +192,7 @@ describe('transforming JS modules:', () => { it('does not create source maps for JSON files', done => { transformModule('{}', {...options(), filename: 'some.json'}, (error, result) => { expect(result.transformed.default) - .toEqual(objectContaining({map: null})); + .toEqual(expect.objectContaining({map: null})); done(); }); }); diff --git a/packager/src/ModuleGraph/worker/transform-module.js b/packager/src/ModuleGraph/worker/transform-module.js index 9f670e4cbe78d3..c451e03ffa1d10 100644 --- a/packager/src/ModuleGraph/worker/transform-module.js +++ b/packager/src/ModuleGraph/worker/transform-module.js @@ -44,7 +44,8 @@ function transformModule( callback: Callback, ): void { if (options.filename.endsWith('.json')) { - return transformJSON(code, options, callback); + transformJSON(code, options, callback); + return; } const {filename, transformer, variants = defaultVariants} = options; @@ -86,6 +87,7 @@ function transformModule( type: options.polyfill ? 'script' : 'module', }); }); + return; } function transformJSON(json, options, callback) { diff --git a/packager/src/Resolver/__tests__/Resolver-test.js b/packager/src/Resolver/__tests__/Resolver-test.js index cff9d5dc978e29..821282d4ca9990 100644 --- a/packager/src/Resolver/__tests__/Resolver-test.js +++ b/packager/src/Resolver/__tests__/Resolver-test.js @@ -237,40 +237,6 @@ describe('Resolver', function() { }); }); - it('should get dependencies with polyfills', function() { - var module = createModule('index'); - var deps = [module]; - - var depResolver = new Resolver({ - projectRoot: '/root', - }); - - DependencyGraph.prototype.getDependencies.mockImplementation(function() { - return Promise.resolve(new ResolutionResponseMock({ - dependencies: deps, - mainModuleId: 'index', - })); - }); - - const polyfill = {}; - DependencyGraph.prototype.createPolyfill.mockReturnValueOnce(polyfill); - return depResolver - .getDependencies( - '/root/index.js', - {dev: true}, - undefined, - undefined, - createGetModuleId() - ).then(function(result) { - expect(result.mainModuleId).toEqual('index'); - expect(DependencyGraph.mock.instances[0].getDependencies) - .toBeCalledWith({entryPath: '/root/index.js', recursive: true}); - expect(result.dependencies[0]).toBe(polyfill); - expect(result.dependencies[result.dependencies.length - 1]) - .toBe(module); - }); - }); - it('should pass in more polyfills', function() { var module = createModule('index'); var deps = [module]; @@ -296,7 +262,9 @@ describe('Resolver', function() { createGetModuleId() ).then(result => { expect(result.mainModuleId).toEqual('index'); - expect(DependencyGraph.prototype.createPolyfill.mock.calls[result.dependencies.length - 2]).toEqual([ + const calls = + DependencyGraph.prototype.createPolyfill.mock.calls[result.dependencies.length - 2]; + expect(calls).toEqual([ {file: 'some module', id: 'some module', dependencies: [ @@ -444,7 +412,8 @@ describe('Resolver', function() { expect(processedCode).toEqual([ '(function(global) {', 'global.fetch = () => 1;', - "\n})(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);", + '\n})' + + "(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);", ].join('')); }); }); diff --git a/packager/src/Resolver/index.js b/packager/src/Resolver/index.js index 4e92c0ef8a8201..63245edd17628f 100644 --- a/packager/src/Resolver/index.js +++ b/packager/src/Resolver/index.js @@ -76,7 +76,8 @@ class Resolver { }, platforms: new Set(opts.platforms), preferNativePlatform: true, - providesModuleNodeModules: opts.providesModuleNodeModules || defaults.providesModuleNodeModules, + providesModuleNodeModules: + opts.providesModuleNodeModules || defaults.providesModuleNodeModules, reporter: opts.reporter, resetCache: opts.resetCache, roots: opts.projectRoots, @@ -261,7 +262,7 @@ function defineModuleCode(moduleName, code, verboseName = '', dev = true) { ].join(''); } -function definePolyfillCode(code,) { +function definePolyfillCode(code) { return [ '(function(global) {', code, diff --git a/packager/src/Resolver/polyfills/Number.es6.js b/packager/src/Resolver/polyfills/Number.es6.js index 4b0964e218ceb5..bd669c3c4b8644 100644 --- a/packager/src/Resolver/polyfills/Number.es6.js +++ b/packager/src/Resolver/polyfills/Number.es6.js @@ -27,6 +27,7 @@ if (Number.MIN_SAFE_INTEGER === undefined) { }); } if (!Number.isNaN) { + // eslint-disable-next-line max-len // https://github.com/dherman/tc39-codex-wiki/blob/master/data/es6/number/index.md#polyfill-for-numberisnan const globalIsNaN = global.isNaN; Object.defineProperty(Number, 'isNaN', { diff --git a/packager/src/Resolver/polyfills/error-guard.js b/packager/src/Resolver/polyfills/error-guard.js index 080602953ffba7..b9330506982929 100644 --- a/packager/src/Resolver/polyfills/error-guard.js +++ b/packager/src/Resolver/polyfills/error-guard.js @@ -52,6 +52,7 @@ const ErrorUtils = { } finally { _inGuard--; } + return null; }, applyWithGuardIfNeeded(fun, context, args) { if (ErrorUtils.inGuard()) { @@ -59,6 +60,7 @@ const ErrorUtils = { } else { ErrorUtils.applyWithGuard(fun, context, args); } + return null; }, inGuard() { return _inGuard; diff --git a/packager/src/Server/index.js b/packager/src/Server/index.js index 32ddfc73d21b4c..c77bea8db7d75b 100644 --- a/packager/src/Server/index.js +++ b/packager/src/Server/index.js @@ -43,7 +43,8 @@ const { } = require('../Logger'); function debounceAndBatch(fn, delay) { - let timeout, args = []; + let args = []; + let timeout; return value => { args.push(value); clearTimeout(timeout); @@ -957,7 +958,8 @@ class Server { 'entryModuleOnly', false, ), - generateSourceMaps: minify || !dev || this._getBoolOptionFromQuery(urlObj.query, 'babelSourcemap', false), + generateSourceMaps: + minify || !dev || this._getBoolOptionFromQuery(urlObj.query, 'babelSourcemap', false), assetPlugins, }; } diff --git a/packager/src/lib/relativizeSourceMap.js b/packager/src/lib/relativizeSourceMap.js index c09cc3d4beb43b..4b9050d83d6cbd 100644 --- a/packager/src/lib/relativizeSourceMap.js +++ b/packager/src/lib/relativizeSourceMap.js @@ -17,11 +17,11 @@ import type {MixedSourceMap} from './SourceMap'; function relativizeSourceMapInternal(sourceMap: any, sourcesRoot: string) { if (sourceMap.sections) { - for (var i = 0; i < sourceMap.sections.length; i++) { + for (let i = 0; i < sourceMap.sections.length; i++) { relativizeSourceMapInternal(sourceMap.sections[i].map, sourcesRoot); } } else { - for (var i = 0; i < sourceMap.sources.length; i++) { + for (let i = 0; i < sourceMap.sources.length; i++) { sourceMap.sources[i] = path.relative(sourcesRoot, sourceMap.sources[i]); } } diff --git a/packager/src/node-haste/DependencyGraph/HasteMap.js b/packager/src/node-haste/DependencyGraph/HasteMap.js index 975cd305a5754e..d869f17cc125ec 100644 --- a/packager/src/node-haste/DependencyGraph/HasteMap.js +++ b/packager/src/node-haste/DependencyGraph/HasteMap.js @@ -87,6 +87,7 @@ class HasteMap extends EventEmitter { return this._processHasteModule(absPath, invalidated); } } + return null; }); } diff --git a/packager/src/node-haste/__mocks__/graceful-fs.js b/packager/src/node-haste/__mocks__/graceful-fs.js index bd429181fdbbb1..638b6c8f312661 100644 --- a/packager/src/node-haste/__mocks__/graceful-fs.js +++ b/packager/src/node-haste/__mocks__/graceful-fs.js @@ -37,7 +37,7 @@ fs.realpath.mockImplementation((filepath, callback) => { if (node && typeof node === 'object' && node.SYMLINK != null) { return callback(null, node.SYMLINK); } - callback(null, filepath); + return callback(null, filepath); }); fs.readdirSync.mockImplementation(filepath => Object.keys(getToNode(filepath))); @@ -58,7 +58,7 @@ fs.readdir.mockImplementation((filepath, callback) => { return callback(new Error(filepath + ' is not a directory.')); } - callback(null, Object.keys(node)); + return callback(null, Object.keys(node)); }); fs.readFile.mockImplementation(function(filepath, encoding, callback) { @@ -76,9 +76,9 @@ fs.readFile.mockImplementation(function(filepath, encoding, callback) { callback(new Error('Error readFile a dir: ' + filepath)); } if (node == null) { - callback(Error('No such file: ' + filepath)); + return callback(Error('No such file: ' + filepath)); } else { - callback(null, node); + return callback(null, node); } } catch (e) { return callback(e); diff --git a/packager/src/node-haste/__tests__/DependencyGraph-test.js b/packager/src/node-haste/__tests__/DependencyGraph-test.js index e3449e624e48f8..86149ac9787a89 100644 --- a/packager/src/node-haste/__tests__/DependencyGraph-test.js +++ b/packager/src/node-haste/__tests__/DependencyGraph-test.js @@ -748,7 +748,7 @@ describe('DependencyGraph', function() { }); }); - it('should work with packages', function() { + it('should work with packages with a trailing slash', function() { var root = '/root'; setMockFileSystem({ 'root': { diff --git a/packager/src/node-haste/index.js b/packager/src/node-haste/index.js index 5600b0904ebbef..a60c7daa41dbd2 100644 --- a/packager/src/node-haste/index.js +++ b/packager/src/node-haste/index.js @@ -130,7 +130,9 @@ class DependencyGraph extends EventEmitter { moduleOptions: this._opts.moduleOptions, reporter: this._opts.reporter, getClosestPackage: filePath => { - let {dir, root} = path.parse(filePath); + const parsedPath = path.parse(filePath); + const root = parsedPath.root; + let dir = parsedPath.dir; do { const candidate = path.join(dir, 'package.json'); if (this._hasteFS.exists(candidate)) { diff --git a/packager/transformer.js b/packager/transformer.js index f60b6e5aa61ee2..88e22d52d967d6 100644 --- a/packager/transformer.js +++ b/packager/transformer.js @@ -35,7 +35,7 @@ const getBabelRC = (function() { return babelRC; } - babelRC = { plugins: [] }; // empty babelrc + babelRC = {plugins: []}; // empty babelrc // Let's look for the .babelrc in the first project root. // In the future let's look into adding a command line option to specify @@ -54,7 +54,7 @@ const getBabelRC = (function() { ); // Require the babel-preset's listed in the default babel config - babelRC.presets = babelRC.presets.map((preset) => require('babel-preset-' + preset)); + babelRC.presets = babelRC.presets.map(preset => require('babel-preset-' + preset)); babelRC.plugins = resolvePlugins(babelRC.plugins); } else { // if we find a .babelrc file we tell babel to use it From 5facc237994012b525248a4209841ffebf04a837 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 1 Mar 2017 08:10:44 -0800 Subject: [PATCH 006/168] Packager - Fix absolute imports on Windows Summary: Absolute imports on Windows were broken, I'm not 100% sure when this happens but when I tested Exponent on Windows which uses `rn-cli.config.js` with ```js getTransformOptions() { return { reactNativePath: path.resolve('./node_modules/react-native'), reactPath: path.resolve('./node_modules/react'), }; } ``` it seemed to use absolute paths for these modules. I also tested absolute paths in node repl and it does work for absolute paths of different formats. `C:/root/test.js`, `/root/test.js`, `C:\root\test.js` all do resolve properly to the same module. To fix this I resolve the absolute path using `path.resolve` on Windows. Noop on other platforms to avoid the overhead since it's not necessary. **Test plan** - Tested that it fixed the bug I had when running Exponent on Windows. - Updated the absolute path test to use forward slashes since this is what happens in practice when using `getTransformOptions`. We can't test all cases on linux since adding the drive letter au Closes https://github.com/facebook/react-native/pull/12530 Differential Revision: D4634699 Pulled By: jeanlauliac fbshipit-source-id: 0cf6528069b79cba2e0f79f48f5a524d59b7091e --- .../node-haste/DependencyGraph/ResolutionRequest.js | 12 +++++++++++- .../src/node-haste/__tests__/DependencyGraph-test.js | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js index 8afb850c3f22ed..b59798e61b39ac 100644 --- a/packager/src/node-haste/DependencyGraph/ResolutionRequest.js +++ b/packager/src/node-haste/DependencyGraph/ResolutionRequest.js @@ -278,7 +278,7 @@ class ResolutionRequest { _resolveFileOrDir(fromModule: Module, toModuleName: string) { const potentialModulePath = isAbsolutePath(toModuleName) ? - toModuleName : + resolveWindowsPath(toModuleName) : path.join(path.dirname(fromModule.path), toModuleName); return this._redirectRequire(fromModule, potentialModulePath).then( @@ -509,6 +509,16 @@ function normalizePath(modulePath) { return modulePath.replace(/\/$/, ''); } +// HasteFS stores paths with backslashes on Windows, this ensures the path is +// in the proper format. Will also add drive letter if not present so `/root` will +// resolve to `C:\root`. Noop on other platforms. +function resolveWindowsPath(modulePath) { + if (path.sep !== '\\') { + return modulePath; + } + return path.resolve(modulePath); +} + function resolveKeyWithPromise([key, promise]) { return promise.then(value => [key, value]); } diff --git a/packager/src/node-haste/__tests__/DependencyGraph-test.js b/packager/src/node-haste/__tests__/DependencyGraph-test.js index 86149ac9787a89..a37186250be12f 100644 --- a/packager/src/node-haste/__tests__/DependencyGraph-test.js +++ b/packager/src/node-haste/__tests__/DependencyGraph-test.js @@ -2478,7 +2478,7 @@ describe('DependencyGraph', function() { const root = 'C:\\root'; setMockFileSystem({ 'root': { - 'index.js': 'require("C:\\\\root\\\\apple.js");', + 'index.js': 'require("C:/root/apple.js");', 'apple.js': '', }, }); @@ -2493,7 +2493,7 @@ describe('DependencyGraph', function() { { id: 'C:\\root\\index.js', path: 'C:\\root\\index.js', - dependencies: ['C:\\root\\apple.js'], + dependencies: ['C:/root/apple.js'], isAsset: false, isJSON: false, isPolyfill: false, From 7b35eb3fdb803ddb00a82d0cda7904771f15e438 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Wed, 1 Mar 2017 09:11:59 -0800 Subject: [PATCH 007/168] Move new components out of `Experimental` directory Summary: I think these are sufficiently baked. Also beef up comments. Reviewed By: yungsters Differential Revision: D4632604 fbshipit-source-id: 64ae6b240a05d62e418099f7403e1781f9b4717c --- .../Lists}/FlatList.js | 18 ++++++++++++++---- .../Lists}/MetroListView.js | 0 .../Lists}/SectionList.js | 0 .../Lists}/ViewabilityHelper.js | 16 ++++++++++++++++ .../Lists}/VirtualizeUtils.js | 0 .../Lists}/VirtualizedList.js | 0 .../Lists}/VirtualizedSectionList.js | 0 .../Lists}/__flowtests__/FlatList-flowtest.js | 0 .../__flowtests__/SectionList-flowtest.js | 0 .../Lists}/__tests__/ViewabilityHelper-test.js | 0 .../Lists}/__tests__/VirtualizeUtils-test.js | 0 11 files changed, 30 insertions(+), 4 deletions(-) rename Libraries/{Experimental => CustomComponents/Lists}/FlatList.js (92%) rename Libraries/{Experimental => CustomComponents/Lists}/MetroListView.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/SectionList.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/ViewabilityHelper.js (94%) rename Libraries/{Experimental => CustomComponents/Lists}/VirtualizeUtils.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/VirtualizedList.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/VirtualizedSectionList.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/__flowtests__/FlatList-flowtest.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/__flowtests__/SectionList-flowtest.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/__tests__/ViewabilityHelper-test.js (100%) rename Libraries/{Experimental => CustomComponents/Lists}/__tests__/VirtualizeUtils-test.js (100%) diff --git a/Libraries/Experimental/FlatList.js b/Libraries/CustomComponents/Lists/FlatList.js similarity index 92% rename from Libraries/Experimental/FlatList.js rename to Libraries/CustomComponents/Lists/FlatList.js index 240f0c73b47e60..aac931077a9081 100644 --- a/Libraries/Experimental/FlatList.js +++ b/Libraries/CustomComponents/Lists/FlatList.js @@ -53,7 +53,7 @@ type RequiredProps = { * * ); * ... - * + * * * Provides additional metadata like `index` if you need it. */ @@ -136,7 +136,7 @@ type OptionalProps = { nextInfo: {item: ItemT, index: number} ) => boolean, /** - * See ViewabilityHelper for flow type and comments. + * See ViewabilityHelper for flow type and further documentation. */ viewabilityConfig?: ViewabilityConfig, }; @@ -160,14 +160,24 @@ type DefaultProps = typeof defaultProps; * - Separator support. * - Pull to Refresh * - * If you need sticky section header support, use ListView. + * If you need sticky section header support, use ListView for now. * * Minimal Example: * * {item.key}} * /> + * + * Some notes for all of the `VirtualizedList` based components: + * - Internal state is not preserved when content scrolls out of the render window. Make sure all + * your data is captured in the item data or external stores like Flux, Redux, or Relay. + * - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously + * offscreen. This means it's possible to scroll faster than the fill rate ands momentarily see + * blank content. This is a tradeoff that can be adjusted to suit the needs of each application, + * and we are working on improving it behind the scenes. + * - By default, the list looks for a `key` prop on each item and uses that for the React key. + * Alternatively, you can provide a custom keyExtractor prop. */ class FlatList extends React.PureComponent, void> { static defaultProps: DefaultProps = defaultProps; diff --git a/Libraries/Experimental/MetroListView.js b/Libraries/CustomComponents/Lists/MetroListView.js similarity index 100% rename from Libraries/Experimental/MetroListView.js rename to Libraries/CustomComponents/Lists/MetroListView.js diff --git a/Libraries/Experimental/SectionList.js b/Libraries/CustomComponents/Lists/SectionList.js similarity index 100% rename from Libraries/Experimental/SectionList.js rename to Libraries/CustomComponents/Lists/SectionList.js diff --git a/Libraries/Experimental/ViewabilityHelper.js b/Libraries/CustomComponents/Lists/ViewabilityHelper.js similarity index 94% rename from Libraries/Experimental/ViewabilityHelper.js rename to Libraries/CustomComponents/Lists/ViewabilityHelper.js index a8a185165c1697..ef2b73a9e9c09c 100644 --- a/Libraries/Experimental/ViewabilityHelper.js +++ b/Libraries/CustomComponents/Lists/ViewabilityHelper.js @@ -54,6 +54,9 @@ export type ViewabilityConfig = {| |}; /** +* A Utility class for calculating viewable items based on current metrics like scroll position and +* layout. +* * An item is said to be in a "viewable" state when any of the following * is true for longer than `minViewTime` milliseconds (after an interaction if `waitForInteraction` * is true): @@ -78,10 +81,16 @@ class ViewabilityHelper { this._config = config; } + /** + * Cleanup, e.g. on unmount. Clears any pending timers. + */ dispose() { this._timers.forEach(clearTimeout); } + /** + * Determines which items are viewable based on the current metrics and config. + */ computeViewableItems( itemCount: number, scrollOffset: number, @@ -135,6 +144,10 @@ class ViewabilityHelper { return viewableIndices; } + /** + * Figures out which items are viewable and how that has changed from before and calls + * `onViewableItemsChanged` as appropriate. + */ onUpdate( itemCount: number, scrollOffset: number, @@ -196,6 +209,9 @@ class ViewabilityHelper { } } + /** + * Records that an interaction has happened even if there has been no scroll. + */ recordInteraction() { this._hasInteracted = true; } diff --git a/Libraries/Experimental/VirtualizeUtils.js b/Libraries/CustomComponents/Lists/VirtualizeUtils.js similarity index 100% rename from Libraries/Experimental/VirtualizeUtils.js rename to Libraries/CustomComponents/Lists/VirtualizeUtils.js diff --git a/Libraries/Experimental/VirtualizedList.js b/Libraries/CustomComponents/Lists/VirtualizedList.js similarity index 100% rename from Libraries/Experimental/VirtualizedList.js rename to Libraries/CustomComponents/Lists/VirtualizedList.js diff --git a/Libraries/Experimental/VirtualizedSectionList.js b/Libraries/CustomComponents/Lists/VirtualizedSectionList.js similarity index 100% rename from Libraries/Experimental/VirtualizedSectionList.js rename to Libraries/CustomComponents/Lists/VirtualizedSectionList.js diff --git a/Libraries/Experimental/__flowtests__/FlatList-flowtest.js b/Libraries/CustomComponents/Lists/__flowtests__/FlatList-flowtest.js similarity index 100% rename from Libraries/Experimental/__flowtests__/FlatList-flowtest.js rename to Libraries/CustomComponents/Lists/__flowtests__/FlatList-flowtest.js diff --git a/Libraries/Experimental/__flowtests__/SectionList-flowtest.js b/Libraries/CustomComponents/Lists/__flowtests__/SectionList-flowtest.js similarity index 100% rename from Libraries/Experimental/__flowtests__/SectionList-flowtest.js rename to Libraries/CustomComponents/Lists/__flowtests__/SectionList-flowtest.js diff --git a/Libraries/Experimental/__tests__/ViewabilityHelper-test.js b/Libraries/CustomComponents/Lists/__tests__/ViewabilityHelper-test.js similarity index 100% rename from Libraries/Experimental/__tests__/ViewabilityHelper-test.js rename to Libraries/CustomComponents/Lists/__tests__/ViewabilityHelper-test.js diff --git a/Libraries/Experimental/__tests__/VirtualizeUtils-test.js b/Libraries/CustomComponents/Lists/__tests__/VirtualizeUtils-test.js similarity index 100% rename from Libraries/Experimental/__tests__/VirtualizeUtils-test.js rename to Libraries/CustomComponents/Lists/__tests__/VirtualizeUtils-test.js From d5a381f4933e90b3c1bdf0f97faf9eb4c3d61b93 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 09:12:40 -0800 Subject: [PATCH 008/168] Fix margin auto for start and end values Reviewed By: astreet Differential Revision: D4627339 fbshipit-source-id: eebf64e79a34331e79cffcfa3662d4938fbd6c13 --- ReactCommon/yoga/yoga/Yoga.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index 4bd7bc2831a3ce..9407835a4c7805 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -1247,6 +1247,22 @@ static float YGNodeBoundAxisWithinMinAndMax(const YGNodeRef node, return boundValue; } +static inline YGValue *YGMarginLeadingValue(const YGNodeRef node, const YGFlexDirection axis) { + if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeStart].unit != YGUnitUndefined) { + return &node->style.margin[YGEdgeStart]; + } else { + return &node->style.margin[leading[axis]]; + } +} + +static inline YGValue *YGMarginTrailingValue(const YGNodeRef node, const YGFlexDirection axis) { + if (YGFlexDirectionIsRow(axis) && node->style.margin[YGEdgeEnd].unit != YGUnitUndefined) { + return &node->style.margin[YGEdgeEnd]; + } else { + return &node->style.margin[trailing[axis]]; + } +} + // Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't go // below the // padding and border amount. @@ -2442,10 +2458,10 @@ static void YGNodelayoutImpl(const YGNodeRef node, for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) { const YGNodeRef child = YGNodeListGet(node->children, i); if (child->style.positionType == YGPositionTypeRelative) { - if (child->style.margin[leading[mainAxis]].unit == YGUnitAuto) { + if (YGMarginLeadingValue(child, mainAxis)->unit == YGUnitAuto) { numberOfAutoMarginsOnCurrentLine++; } - if (child->style.margin[trailing[mainAxis]].unit == YGUnitAuto) { + if (YGMarginTrailingValue(child, mainAxis)->unit == YGUnitAuto) { numberOfAutoMarginsOnCurrentLine++; } } @@ -2500,7 +2516,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, // We need to do that only for relative elements. Absolute elements // do not take part in that phase. if (child->style.positionType == YGPositionTypeRelative) { - if (child->style.margin[leading[mainAxis]].unit == YGUnitAuto) { + if (YGMarginLeadingValue(child, mainAxis)->unit == YGUnitAuto) { mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine; } @@ -2508,7 +2524,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, child->layout.position[pos[mainAxis]] += mainDim; } - if (child->style.margin[trailing[mainAxis]].unit == YGUnitAuto) { + if (YGMarginTrailingValue(child, mainAxis)->unit == YGUnitAuto) { mainDim += remainingFreeSpace / numberOfAutoMarginsOnCurrentLine; } @@ -2601,8 +2617,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, // forcing the cross-axis size to be the computed cross size for the // current line. if (alignItem == YGAlignStretch && - child->style.margin[leading[crossAxis]].unit != YGUnitAuto && - child->style.margin[trailing[crossAxis]].unit != YGUnitAuto) { + YGMarginLeadingValue(child, crossAxis)->unit != YGUnitAuto && + YGMarginTrailingValue(child, crossAxis)->unit != YGUnitAuto) { // If the child defines a definite size for its cross axis, there's // no need to stretch. if (!YGNodeIsStyleDimDefined(child, crossAxis, availableInnerCrossDim)) { @@ -2650,12 +2666,12 @@ static void YGNodelayoutImpl(const YGNodeRef node, const float remainingCrossDim = containerCrossAxis - YGNodeDimWithMargin(child, crossAxis, availableInnerWidth); - if (child->style.margin[leading[crossAxis]].unit == YGUnitAuto && - child->style.margin[trailing[crossAxis]].unit == YGUnitAuto) { + if (YGMarginLeadingValue(child, crossAxis)->unit == YGUnitAuto && + YGMarginTrailingValue(child, crossAxis)->unit == YGUnitAuto) { leadingCrossDim += remainingCrossDim / 2; - } else if (child->style.margin[trailing[crossAxis]].unit == YGUnitAuto) { + } else if (YGMarginTrailingValue(child, crossAxis)->unit == YGUnitAuto) { // No-Op - } else if (child->style.margin[leading[crossAxis]].unit == YGUnitAuto) { + } else if (YGMarginLeadingValue(child, crossAxis)->unit == YGUnitAuto) { leadingCrossDim += remainingCrossDim; } else if (alignItem == YGAlignFlexStart) { // No-Op From fb266fcaad44777afae97cad5d0cc9e00bd96d44 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 09:12:43 -0800 Subject: [PATCH 009/168] More efficient decoding of Dynamic value in LayoutShadowNode Reviewed By: astreet Differential Revision: D4627219 fbshipit-source-id: 1495d58b08af3c619a8dc0d2df655e0c42aa813e --- .../react/uimanager/LayoutShadowNode.java | 180 ++++++++++++------ 1 file changed, 118 insertions(+), 62 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index 586b24e0caaa2a..f80f85d44a90d1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -15,7 +15,6 @@ import com.facebook.yoga.YogaJustify; import com.facebook.yoga.YogaOverflow; import com.facebook.yoga.YogaPositionType; -import com.facebook.yoga.YogaValue; import com.facebook.yoga.YogaUnit; import com.facebook.yoga.YogaWrap; import com.facebook.react.uimanager.annotations.ReactProp; @@ -32,22 +31,36 @@ */ public class LayoutShadowNode extends ReactShadowNode { - private static boolean dynamicIsPercent(Dynamic dynamic) { - return dynamic.getType() == ReadableType.String && dynamic.asString().endsWith("%"); - } - - private static float getDynamicAsPercent(Dynamic dynamic) { - final String value = dynamic.asString(); - return Float.parseFloat(value.substring(0, value.length() - 1)); - } - - private static float getDynamicAsFloat(Dynamic dynamic) { - return (float) PixelUtil.toPixelFromDIP(dynamic.asDouble()); + /** + * A Mutable version of com.facebook.yoga.YogaValue + */ + private static class MutableYogaValue { + float value; + YogaUnit unit; + + void setFromDynamic(Dynamic dynamic) { + if (dynamic.isNull()) { + unit = YogaUnit.UNDEFINED; + value = YogaConstants.UNDEFINED; + } else if (dynamic.getType() == ReadableType.String) { + final String s = dynamic.asString(); + if (s.equals("auto")) { + unit = YogaUnit.AUTO; + value = YogaConstants.UNDEFINED; + } else if (s.endsWith("%")) { + unit = YogaUnit.PERCENT; + value = Float.parseFloat(s.substring(0, s.length() - 1)); + } else { + throw new IllegalArgumentException("Unknown value: " + s); + } + } else { + unit = YogaUnit.POINT; + value = PixelUtil.toPixelFromDIP(dynamic.asDouble()); + } + } } - private static boolean isNull(Dynamic d) { - return d == null || d.isNull(); - } + private final MutableYogaValue mTempYogaValue = new MutableYogaValue(); @ReactProp(name = ViewProps.WIDTH) public void setWidth(Dynamic width) { @@ -55,10 +68,15 @@ public void setWidth(Dynamic width) { return; } - if (!isNull(width) && dynamicIsPercent(width)) { - setStyleWidthPercent(getDynamicAsPercent(width)); - } else { - setStyleWidth(isNull(width) ? YogaConstants.UNDEFINED : getDynamicAsFloat(width)); + mTempYogaValue.setFromDynamic(width); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleWidth(mTempYogaValue.value); + break; + case PERCENT: + setStyleWidthPercent(mTempYogaValue.value); + break; } width.recycle(); @@ -70,10 +88,15 @@ public void setMinWidth(Dynamic minWidth) { return; } - if (!isNull(minWidth) && dynamicIsPercent(minWidth)) { - setStyleMinWidthPercent(getDynamicAsPercent(minWidth)); - } else { - setStyleMinWidth(isNull(minWidth) ? YogaConstants.UNDEFINED : getDynamicAsFloat(minWidth)); + mTempYogaValue.setFromDynamic(minWidth); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleMinWidth(mTempYogaValue.value); + break; + case PERCENT: + setStyleMinWidthPercent(mTempYogaValue.value); + break; } minWidth.recycle(); @@ -85,10 +108,15 @@ public void setMaxWidth(Dynamic maxWidth) { return; } - if (!isNull(maxWidth) && dynamicIsPercent(maxWidth)) { - setStyleMaxWidthPercent(getDynamicAsPercent(maxWidth)); - } else { - setStyleMaxWidth(isNull(maxWidth) ? YogaConstants.UNDEFINED : getDynamicAsFloat(maxWidth)); + mTempYogaValue.setFromDynamic(maxWidth); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleMaxWidth(mTempYogaValue.value); + break; + case PERCENT: + setStyleMaxWidthPercent(mTempYogaValue.value); + break; } maxWidth.recycle(); @@ -100,10 +128,15 @@ public void setHeight(Dynamic height) { return; } - if (!isNull(height) && dynamicIsPercent(height)) { - setStyleHeightPercent(getDynamicAsPercent(height)); - } else { - setStyleHeight(isNull(height) ? YogaConstants.UNDEFINED : getDynamicAsFloat(height)); + mTempYogaValue.setFromDynamic(height); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleHeight(mTempYogaValue.value); + break; + case PERCENT: + setStyleHeightPercent(mTempYogaValue.value); + break; } height.recycle(); @@ -115,10 +148,15 @@ public void setMinHeight(Dynamic minHeight) { return; } - if (!isNull(minHeight) && dynamicIsPercent(minHeight)) { - setStyleMinHeightPercent(getDynamicAsPercent(minHeight)); - } else { - setStyleMinHeight(isNull(minHeight) ? YogaConstants.UNDEFINED : getDynamicAsFloat(minHeight)); + mTempYogaValue.setFromDynamic(minHeight); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleMinHeight(mTempYogaValue.value); + break; + case PERCENT: + setStyleMinHeightPercent(mTempYogaValue.value); + break; } minHeight.recycle(); @@ -130,10 +168,15 @@ public void setMaxHeight(Dynamic maxHeight) { return; } - if (!isNull(maxHeight) && dynamicIsPercent(maxHeight)) { - setStyleMaxHeightPercent(getDynamicAsPercent(maxHeight)); - } else { - setStyleMaxHeight(isNull(maxHeight) ? YogaConstants.UNDEFINED : getDynamicAsFloat(maxHeight)); + mTempYogaValue.setFromDynamic(maxHeight); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setStyleMaxHeight(mTempYogaValue.value); + break; + case PERCENT: + setStyleMaxHeightPercent(mTempYogaValue.value); + break; } maxHeight.recycle(); @@ -169,10 +212,15 @@ public void setFlexBasis(Dynamic flexBasis) { return; } - if (!isNull(flexBasis) && dynamicIsPercent(flexBasis)) { - setFlexBasisPercent(getDynamicAsPercent(flexBasis)); - } else { - setFlexBasis(isNull(flexBasis) ? 0 : getDynamicAsFloat(flexBasis)); + mTempYogaValue.setFromDynamic(flexBasis); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setFlexBasis(mTempYogaValue.value); + break; + case PERCENT: + setFlexBasisPercent(mTempYogaValue.value); + break; } flexBasis.recycle(); @@ -258,12 +306,15 @@ public void setMargins(int index, Dynamic margin) { return; } - if (!isNull(margin) && dynamicIsPercent(margin)) { - setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], getDynamicAsPercent(margin)); - } else { - setMargin( - ViewProps.PADDING_MARGIN_SPACING_TYPES[index], - isNull(margin) ? YogaConstants.UNDEFINED : getDynamicAsFloat(margin)); + mTempYogaValue.setFromDynamic(margin); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setMargin(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); + break; + case PERCENT: + setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); + break; } margin.recycle(); @@ -283,13 +334,15 @@ public void setPaddings(int index, Dynamic padding) { return; } - if (!isNull(padding) && dynamicIsPercent(padding)) { - setPaddingPercent( - ViewProps.PADDING_MARGIN_SPACING_TYPES[index], getDynamicAsPercent(padding)); - } else { - setPadding( - ViewProps.PADDING_MARGIN_SPACING_TYPES[index], - isNull(padding) ? YogaConstants.UNDEFINED : getDynamicAsFloat(padding)); + mTempYogaValue.setFromDynamic(padding); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setPadding(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); + break; + case PERCENT: + setPaddingPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); + break; } padding.recycle(); @@ -320,12 +373,15 @@ public void setPositionValues(int index, Dynamic position) { return; } - if (!isNull(position) && dynamicIsPercent(position)) { - setPositionPercent(ViewProps.POSITION_SPACING_TYPES[index], getDynamicAsPercent(position)); - } else { - setPosition( - ViewProps.POSITION_SPACING_TYPES[index], - isNull(position) ? YogaConstants.UNDEFINED : getDynamicAsFloat(position)); + mTempYogaValue.setFromDynamic(position); + switch (mTempYogaValue.unit) { + case POINT: + case UNDEFINED: + setPosition(ViewProps.POSITION_SPACING_TYPES[index], mTempYogaValue.value); + break; + case PERCENT: + setPositionPercent(ViewProps.POSITION_SPACING_TYPES[index], mTempYogaValue.value); + break; } position.recycle(); From cc275557be3cb8ecb1d535b4e136fd75cd3e9227 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 09:12:45 -0800 Subject: [PATCH 010/168] Add margin auto support to react native Summary: This diff adds margin:auto (https://drafts.csswg.org/css-flexbox-1/#auto-margins) support to React Native. This enables layout not previously supported without inserting empty 'spacer' views. See below Playground for usage. ``` class Playground extends React.Component { render() { return ( ); } } ``` Reviewed By: astreet Differential Revision: D4611753 fbshipit-source-id: e78335565c193f7fb263129a638b444715ba5ab0 --- React/Base/RCTConvert.m | 4 +- React/Views/RCTShadowView.m | 68 ++++++++++++++----- .../react/uimanager/LayoutShadowNode.java | 12 ++++ .../react/uimanager/ReactShadowNode.java | 16 +++++ 4 files changed, 81 insertions(+), 19 deletions(-) diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index d8a0e9df2ce370..709b1278b60b5f 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -507,7 +507,9 @@ + (YGValue)YGValue:(id)json return (YGValue) { [json floatValue], YGUnitPoint }; } else if ([json isKindOfClass:[NSString class]]) { NSString *s = (NSString *) json; - if ([s hasSuffix:@"%"]) { + if ([s isEqualToString:@"auto"]) { + return (YGValue) { YGUndefined, YGUnitAuto }; + } else if ([s hasSuffix:@"%"]) { return (YGValue) { [[s substringToIndex:s.length] floatValue], YGUnitPercent }; } else { RCTLogConvertError(json, @"a YGValue. Did you forget the % or pt suffix?"); diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index 8a82794edeb7fb..e6ca99b8b6c847 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -70,20 +70,42 @@ static void RCTPrint(YGNodeRef node) break; \ } -#define DEFINE_PROCESS_META_PROPS(type) \ -static void RCTProcessMetaProps##type(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { \ - RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSet##type, node, YGEdgeStart); \ - RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSet##type, node, YGEdgeEnd); \ - RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSet##type, node, YGEdgeTop); \ - RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSet##type, node, YGEdgeBottom); \ - RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSet##type, node, YGEdgeHorizontal); \ - RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSet##type, node, YGEdgeVertical); \ - RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSet##type, node, YGEdgeAll); \ +#define RCT_SET_YGVALUE_AUTO(ygvalue, setter, ...) \ +switch (ygvalue.unit) { \ + case YGUnitAuto: \ + setter##Auto(__VA_ARGS__); \ + break; \ + case YGUnitUndefined: \ + setter(__VA_ARGS__, YGUndefined); \ + break; \ + case YGUnitPoint: \ + setter(__VA_ARGS__, ygvalue.value); \ + break; \ + case YGUnitPercent: \ + setter##Percent(__VA_ARGS__, ygvalue.value); \ + break; \ +} + +static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { + RCT_SET_YGVALUE(metaProps[META_PROP_LEFT], YGNodeStyleSetPadding, node, YGEdgeStart); + RCT_SET_YGVALUE(metaProps[META_PROP_RIGHT], YGNodeStyleSetPadding, node, YGEdgeEnd); + RCT_SET_YGVALUE(metaProps[META_PROP_TOP], YGNodeStyleSetPadding, node, YGEdgeTop); + RCT_SET_YGVALUE(metaProps[META_PROP_BOTTOM], YGNodeStyleSetPadding, node, YGEdgeBottom); + RCT_SET_YGVALUE(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetPadding, node, YGEdgeHorizontal); + RCT_SET_YGVALUE(metaProps[META_PROP_VERTICAL], YGNodeStyleSetPadding, node, YGEdgeVertical); + RCT_SET_YGVALUE(metaProps[META_PROP_ALL], YGNodeStyleSetPadding, node, YGEdgeAll); +} + +static void RCTProcessMetaPropsMargin(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_LEFT], YGNodeStyleSetMargin, node, YGEdgeStart); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_RIGHT], YGNodeStyleSetMargin, node, YGEdgeEnd); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_TOP], YGNodeStyleSetMargin, node, YGEdgeTop); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_BOTTOM], YGNodeStyleSetMargin, node, YGEdgeBottom); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_HORIZONTAL], YGNodeStyleSetMargin, node, YGEdgeHorizontal); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_VERTICAL], YGNodeStyleSetMargin, node, YGEdgeVertical); + RCT_SET_YGVALUE_AUTO(metaProps[META_PROP_ALL], YGNodeStyleSetMargin, node, YGEdgeAll); } -DEFINE_PROCESS_META_PROPS(Padding); -DEFINE_PROCESS_META_PROPS(Margin); - static void RCTProcessMetaPropsBorder(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node) { YGNodeStyleSetBorder(node, YGEdgeStart, metaProps[META_PROP_LEFT].value); YGNodeStyleSetBorder(node, YGEdgeEnd, metaProps[META_PROP_RIGHT].value); @@ -522,9 +544,19 @@ - (float)border##prop##Width \ RCT_BORDER_PROPERTY(Right, RIGHT) // Dimensions - #define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \ - (void)set##setProp:(YGValue)value \ +{ \ + RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \ + [self dirtyText]; \ +} \ +- (YGValue)getProp \ +{ \ + return YGNodeStyleGet##cssProp(_yogaNode); \ +} + +#define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \ +- (void)set##setProp:(YGValue)value \ { \ RCT_SET_YGVALUE(value, YGNodeStyleSet##cssProp, _yogaNode); \ [self dirtyText]; \ @@ -536,10 +568,10 @@ - (YGValue)getProp \ RCT_DIMENSION_PROPERTY(Width, width, Width) RCT_DIMENSION_PROPERTY(Height, height, Height) -RCT_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth) -RCT_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight) -RCT_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth) -RCT_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight) +RCT_MIN_MAX_DIMENSION_PROPERTY(MinWidth, minWidth, MinWidth) +RCT_MIN_MAX_DIMENSION_PROPERTY(MinHeight, minHeight, MinHeight) +RCT_MIN_MAX_DIMENSION_PROPERTY(MaxWidth, maxWidth, MaxWidth) +RCT_MIN_MAX_DIMENSION_PROPERTY(MaxHeight, maxHeight, MaxHeight) // Position @@ -644,7 +676,7 @@ - (void)setFlex:(float)value - (void)setFlexBasis:(YGValue)value { - RCT_SET_YGVALUE(value, YGNodeStyleSetFlexBasis, _yogaNode); + RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode); } - (YGValue)flexBasis diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index f80f85d44a90d1..17b6217e84a6bd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -74,6 +74,9 @@ public void setWidth(Dynamic width) { case UNDEFINED: setStyleWidth(mTempYogaValue.value); break; + case AUTO: + setStyleWidthAuto(); + break; case PERCENT: setStyleWidthPercent(mTempYogaValue.value); break; @@ -134,6 +137,9 @@ public void setHeight(Dynamic height) { case UNDEFINED: setStyleHeight(mTempYogaValue.value); break; + case AUTO: + setStyleHeightAuto(); + break; case PERCENT: setStyleHeightPercent(mTempYogaValue.value); break; @@ -218,6 +224,9 @@ public void setFlexBasis(Dynamic flexBasis) { case UNDEFINED: setFlexBasis(mTempYogaValue.value); break; + case AUTO: + setFlexBasisAuto(); + break; case PERCENT: setFlexBasisPercent(mTempYogaValue.value); break; @@ -312,6 +321,9 @@ public void setMargins(int index, Dynamic margin) { case UNDEFINED: setMargin(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); break; + case AUTO: + setMarginAuto(ViewProps.PADDING_MARGIN_SPACING_TYPES[index]); + break; case PERCENT: setMarginPercent(ViewProps.PADDING_MARGIN_SPACING_TYPES[index], mTempYogaValue.value); break; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index 6bcfa50a16f9e2..8fda24b9e30aa9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -554,6 +554,10 @@ public void setStyleWidthPercent(float percent) { mYogaNode.setWidthPercent(percent); } + public void setStyleWidthAuto() { + mYogaNode.setWidthAuto(); + } + public void setStyleMinWidth(float widthPx) { mYogaNode.setMinWidth(widthPx); } @@ -582,6 +586,10 @@ public void setStyleHeightPercent(float percent) { mYogaNode.setHeightPercent(percent); } + public void setStyleHeightAuto() { + mYogaNode.setHeightAuto(); + } + public void setStyleMinHeight(float widthPx) { mYogaNode.setMinHeight(widthPx); } @@ -614,6 +622,10 @@ public void setFlexBasis(float flexBasis) { mYogaNode.setFlexBasis(flexBasis); } + public void setFlexBasisAuto() { + mYogaNode.setFlexBasisAuto(); + } + public void setFlexBasisPercent(float percent) { mYogaNode.setFlexBasisPercent(percent); } @@ -654,6 +666,10 @@ public void setMarginPercent(int spacingType, float percent) { mYogaNode.setMarginPercent(YogaEdge.fromInt(spacingType), percent); } + public void setMarginAuto(int spacingType) { + mYogaNode.setMarginAuto(YogaEdge.fromInt(spacingType)); + } + public final float getPadding(int spacingType) { return mYogaNode.getLayoutPadding(YogaEdge.fromInt(spacingType)); } From 31f848a5fa56e17fbc6dbbba7d319a3b30083ac8 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 09:12:48 -0800 Subject: [PATCH 011/168] Expose alignContent to react native Summary: This diff adds alignContent (https://developer.mozilla.org/en-US/docs/Web/CSS/align-content) support to React Native. This enables aligning the lines of multi-line content. See below playground for example usage. ``` class Playground extends React.Component { render() { return ( ); } } ``` Reviewed By: astreet Differential Revision: D4611803 fbshipit-source-id: ae7f6b4b7e9f4bc78d2502da948214294aad4dd2 --- Libraries/StyleSheet/LayoutPropTypes.js | 14 ++++++++++++++ React/Base/RCTConvert.m | 4 +++- React/Views/RCTShadowView.h | 1 + React/Views/RCTShadowView.m | 1 + React/Views/RCTViewManager.m | 1 + .../facebook/react/uimanager/LayoutShadowNode.java | 10 ++++++++++ .../facebook/react/uimanager/ReactShadowNode.java | 4 ++++ .../com/facebook/react/uimanager/ViewProps.java | 2 ++ 8 files changed, 36 insertions(+), 1 deletion(-) diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index d8790f2af8f900..df0fb87efa4b75 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -402,6 +402,20 @@ var LayoutPropTypes = { 'baseline' ]), + /** `alignContent` controls how a rows align in the cross direction, + * overriding the `alignContent` of the parent. + * See https://developer.mozilla.org/en-US/docs/Web/CSS/align-content + * for more details. + */ + alignContent: ReactPropTypes.oneOf([ + 'flex-start', + 'flex-end', + 'center', + 'stretch', + 'space-between', + 'space-around' + ]), + /** `overflow` controls how a children are measured and displayed. * `overflow: hidden` causes views to be clipped while `overflow: scroll` * causes views to be measured independently of their parents main axis.` diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 709b1278b60b5f..89409e9324101d 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -666,7 +666,9 @@ + (NSPropertyList)NSPropertyList:(id)json @"center": @(YGAlignCenter), @"auto": @(YGAlignAuto), @"stretch": @(YGAlignStretch), - @"baseline": @(YGAlignBaseline) + @"baseline": @(YGAlignBaseline), + @"space-between": @(YGAlignSpaceBetween), + @"space-around": @(YGAlignSpaceAround) }), YGAlignFlexStart, intValue) RCT_ENUM_CONVERTER(YGDirection, (@{ diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h index 6bc9966384dcc5..3895985bb64480 100644 --- a/React/Views/RCTShadowView.h +++ b/React/Views/RCTShadowView.h @@ -130,6 +130,7 @@ typedef void (^RCTApplierBlock)(NSDictionary *viewRegistry @property (nonatomic, assign) YGJustify justifyContent; @property (nonatomic, assign) YGAlign alignSelf; @property (nonatomic, assign) YGAlign alignItems; +@property (nonatomic, assign) YGAlign alignContent; @property (nonatomic, assign) YGPositionType position; @property (nonatomic, assign) YGWrap flexWrap; diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index e6ca99b8b6c847..a45c47a1b1b44a 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -700,6 +700,7 @@ - (type)getProp \ RCT_STYLE_PROPERTY(JustifyContent, justifyContent, JustifyContent, YGJustify) RCT_STYLE_PROPERTY(AlignSelf, alignSelf, AlignSelf, YGAlign) RCT_STYLE_PROPERTY(AlignItems, alignItems, AlignItems, YGAlign) +RCT_STYLE_PROPERTY(AlignContent, alignContent, AlignContent, YGAlign) RCT_STYLE_PROPERTY(Position, position, PositionType, YGPositionType) RCT_STYLE_PROPERTY(FlexWrap, flexWrap, FlexWrap, YGWrap) RCT_STYLE_PROPERTY(Overflow, overflow, Overflow, YGOverflow) diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index d551781d2471af..792f6cc87e737d 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -305,6 +305,7 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_EXPORT_SHADOW_PROPERTY(justifyContent, YGJustify) RCT_EXPORT_SHADOW_PROPERTY(alignItems, YGAlign) RCT_EXPORT_SHADOW_PROPERTY(alignSelf, YGAlign) +RCT_EXPORT_SHADOW_PROPERTY(alignContent, YGAlign) RCT_EXPORT_SHADOW_PROPERTY(position, YGPositionType) RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index 17b6217e84a6bd..d526b7d397dace 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -283,6 +283,16 @@ public void setAlignItems(@Nullable String alignItems) { alignItems.toUpperCase(Locale.US).replace("-", "_"))); } + @ReactProp(name = ViewProps.ALIGN_CONTENT) + public void setAlignContent(@Nullable String alignContent) { + if (isVirtual()) { + return; + } + setAlignContent( + alignContent == null ? YogaAlign.FLEX_START : YogaAlign.valueOf( + alignContent.toUpperCase(Locale.US).replace("-", "_"))); + } + @ReactProp(name = ViewProps.JUSTIFY_CONTENT) public void setJustifyContent(@Nullable String justifyContent) { if (isVirtual()) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index 8fda24b9e30aa9..e1278b14c4660b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -650,6 +650,10 @@ public void setAlignItems(YogaAlign alignItems) { mYogaNode.setAlignItems(alignItems); } + public void setAlignContent(YogaAlign alignContent) { + mYogaNode.setAlignContent(alignContent); + } + public void setJustifyContent(YogaJustify justifyContent) { mYogaNode.setJustifyContent(justifyContent); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 1384379406333e..4d60d3add8b4da 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -25,6 +25,7 @@ public class ViewProps { // !!! Keep in sync with LAYOUT_ONLY_PROPS below public static final String ALIGN_ITEMS = "alignItems"; public static final String ALIGN_SELF = "alignSelf"; + public static final String ALIGN_CONTENT = "alignContent"; public static final String OVERFLOW = "overflow"; public static final String BOTTOM = "bottom"; public static final String COLLAPSABLE = "collapsable"; @@ -122,6 +123,7 @@ public class ViewProps { FLEX_WRAP, JUSTIFY_CONTENT, OVERFLOW, + ALIGN_CONTENT, /* position */ POSITION, From 4d69f4b2d1cf4f2e8265fe5758f28086f1b67500 Mon Sep 17 00:00:00 2001 From: Emil Sjolander Date: Wed, 1 Mar 2017 09:12:50 -0800 Subject: [PATCH 012/168] Add display:none support to react native Summary: This diff adds display:none support to React Native. This enables hiding components which still calling their render method and keeping them within the state of your application. This enables preserving state in a component even though the component is not visible. Previously this was often implemented by rendering a component off screen as a work around. See below playground for usage. ``` class Playground extends React.Component { render() { return ( ); } } ``` Reviewed By: astreet Differential Revision: D4611771 fbshipit-source-id: 0dbe0494d989df42994ab9ad5125d47f3233cc5a --- Libraries/StyleSheet/LayoutPropTypes.js | 7 +++++++ React/Base/RCTConvert.h | 1 + React/Base/RCTConvert.m | 5 +++++ React/Views/RCTShadowView.h | 1 + React/Views/RCTShadowView.m | 1 + React/Views/RCTViewManager.m | 1 + .../com/facebook/react/uimanager/LayoutShadowNode.java | 10 ++++++++++ .../com/facebook/react/uimanager/ReactShadowNode.java | 5 +++++ .../java/com/facebook/react/uimanager/ViewProps.java | 2 ++ 9 files changed, 33 insertions(+) diff --git a/Libraries/StyleSheet/LayoutPropTypes.js b/Libraries/StyleSheet/LayoutPropTypes.js index df0fb87efa4b75..a8ab32c0772d72 100644 --- a/Libraries/StyleSheet/LayoutPropTypes.js +++ b/Libraries/StyleSheet/LayoutPropTypes.js @@ -27,6 +27,13 @@ var ReactPropTypes = require('React').PropTypes; * algorithm and affect the positioning and sizing of views. */ var LayoutPropTypes = { + /** `display` sets the display type of this component. + * + * It works similarly to `display` in CSS, but only support 'flex' and 'none'. + * 'flex' is the default. + */ + display: ReactPropTypes.string, + /** `width` sets the width of this component. * * It works similarly to `width` in CSS, but in React Native you diff --git a/React/Base/RCTConvert.h b/React/Base/RCTConvert.h index 57e8333dfd27db..dbd4d1f7b8b5a0 100644 --- a/React/Base/RCTConvert.h +++ b/React/Base/RCTConvert.h @@ -112,6 +112,7 @@ typedef id NSPropertyList; typedef BOOL css_backface_visibility_t; + (YGOverflow)YGOverflow:(id)json; ++ (YGDisplay)YGDisplay:(id)json; + (css_backface_visibility_t)css_backface_visibility_t:(id)json; + (YGFlexDirection)YGFlexDirection:(id)json; + (YGJustify)YGJustify:(id)json; diff --git a/React/Base/RCTConvert.m b/React/Base/RCTConvert.m index 89409e9324101d..256fd854bc6e1f 100644 --- a/React/Base/RCTConvert.m +++ b/React/Base/RCTConvert.m @@ -645,6 +645,11 @@ + (NSPropertyList)NSPropertyList:(id)json @"scroll": @(YGOverflowScroll), }), YGOverflowVisible, intValue) +RCT_ENUM_CONVERTER(YGDisplay, (@{ + @"flex": @(YGDisplayFlex), + @"none": @(YGDisplayNone), +}), YGDisplayFlex, intValue) + RCT_ENUM_CONVERTER(YGFlexDirection, (@{ @"row": @(YGFlexDirectionRow), @"row-reverse": @(YGFlexDirectionRowReverse), diff --git a/React/Views/RCTShadowView.h b/React/Views/RCTShadowView.h index 3895985bb64480..bc15bfe595e0c6 100644 --- a/React/Views/RCTShadowView.h +++ b/React/Views/RCTShadowView.h @@ -133,6 +133,7 @@ typedef void (^RCTApplierBlock)(NSDictionary *viewRegistry @property (nonatomic, assign) YGAlign alignContent; @property (nonatomic, assign) YGPositionType position; @property (nonatomic, assign) YGWrap flexWrap; +@property (nonatomic, assign) YGDisplay display; @property (nonatomic, assign) float flexGrow; @property (nonatomic, assign) float flexShrink; diff --git a/React/Views/RCTShadowView.m b/React/Views/RCTShadowView.m index a45c47a1b1b44a..c50f38281bbd40 100644 --- a/React/Views/RCTShadowView.m +++ b/React/Views/RCTShadowView.m @@ -704,6 +704,7 @@ - (type)getProp \ RCT_STYLE_PROPERTY(Position, position, PositionType, YGPositionType) RCT_STYLE_PROPERTY(FlexWrap, flexWrap, FlexWrap, YGWrap) RCT_STYLE_PROPERTY(Overflow, overflow, Overflow, YGOverflow) +RCT_STYLE_PROPERTY(Display, display, Display, YGDisplay) RCT_STYLE_PROPERTY(Direction, direction, Direction, YGDirection) RCT_STYLE_PROPERTY(AspectRatio, aspectRatio, AspectRatio, float) diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 792f6cc87e737d..7bbc9741075acb 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -310,6 +310,7 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(__unused NSDictio RCT_EXPORT_SHADOW_PROPERTY(aspectRatio, float) RCT_EXPORT_SHADOW_PROPERTY(overflow, YGOverflow) +RCT_EXPORT_SHADOW_PROPERTY(display, YGDisplay) RCT_EXPORT_SHADOW_PROPERTY(onLayout, RCTDirectEventBlock) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java index d526b7d397dace..3f5020e3ad4157 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/LayoutShadowNode.java @@ -11,6 +11,7 @@ import com.facebook.yoga.YogaAlign; import com.facebook.yoga.YogaConstants; +import com.facebook.yoga.YogaDisplay; import com.facebook.yoga.YogaFlexDirection; import com.facebook.yoga.YogaJustify; import com.facebook.yoga.YogaOverflow; @@ -311,6 +312,15 @@ public void setOverflow(@Nullable String overflow) { overflow.toUpperCase(Locale.US).replace("-", "_"))); } + @ReactProp(name = ViewProps.DISPLAY) + public void setDisplay(@Nullable String display) { + if (isVirtual()) { + return; + } + setDisplay(display == null ? YogaDisplay.FLEX : YogaDisplay.valueOf( + display.toUpperCase(Locale.US).replace("-", "_"))); + } + @ReactPropGroup(names = { ViewProps.MARGIN, ViewProps.MARGIN_VERTICAL, diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java index e1278b14c4660b..2cad696e502860 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import com.facebook.yoga.YogaAlign; +import com.facebook.yoga.YogaDisplay; import com.facebook.yoga.YogaEdge; import com.facebook.yoga.YogaConstants; import com.facebook.yoga.YogaDirection; @@ -662,6 +663,10 @@ public void setOverflow(YogaOverflow overflow) { mYogaNode.setOverflow(overflow); } + public void setDisplay(YogaDisplay display) { + mYogaNode.setDisplay(display); + } + public void setMargin(int spacingType, float margin) { mYogaNode.setMargin(YogaEdge.fromInt(spacingType), margin); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java index 4d60d3add8b4da..67265436ae9eec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewProps.java @@ -27,6 +27,7 @@ public class ViewProps { public static final String ALIGN_SELF = "alignSelf"; public static final String ALIGN_CONTENT = "alignContent"; public static final String OVERFLOW = "overflow"; + public static final String DISPLAY = "display"; public static final String BOTTOM = "bottom"; public static final String COLLAPSABLE = "collapsable"; public static final String FLEX = "flex"; @@ -124,6 +125,7 @@ public class ViewProps { JUSTIFY_CONTENT, OVERFLOW, ALIGN_CONTENT, + DISPLAY, /* position */ POSITION, From bdd9aed909842af05ea4dde30488427c4c484ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6hrl?= Date: Wed, 1 Mar 2017 09:19:55 -0800 Subject: [PATCH 013/168] Move configuration to new YGConfig and pass them down to CalculateLayout Summary: Move configuration to new ```YGConfig``` and pass them down to CalculateLayout. See #418 . Adds ```YGConfigNew()``` + ```YGConfigFree```, and changed ```YGSetExperimentalFeatureEnabled``` to use the config. New function for calculation is ```YGNodeCalculateLayoutWithConfig```. Closes https://github.com/facebook/yoga/pull/432 Reviewed By: astreet Differential Revision: D4611359 Pulled By: emilsjolander fbshipit-source-id: a1332f0e1b21cec02129dd021ee57408449e10b0 --- .../java/com/facebook/yoga/YogaConfig.java | 49 +++++++++ .../main/java/com/facebook/yoga/YogaNode.java | 22 ++-- .../jni/first-party/yogajni/jni/YGJNI.cpp | 50 ++++++--- ReactCommon/yoga/yoga/Yoga.c | 100 +++++++++++++----- ReactCommon/yoga/yoga/Yoga.h | 13 ++- 5 files changed, 177 insertions(+), 57 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java new file mode 100644 index 00000000000000..716a212e76d515 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaConfig.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2014-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. + */ + +package com.facebook.yoga; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.soloader.SoLoader; + +@DoNotStrip +public class YogaConfig { + + static { + SoLoader.loadLibrary("yoga"); + } + + long mNativePointer; + + private native long jni_YGConfigNew(); + public YogaConfig() { + mNativePointer = jni_YGConfigNew(); + if (mNativePointer == 0) { + throw new IllegalStateException("Failed to allocate native memory"); + } + } + + private native void jni_YGConfigFree(long nativePointer); + @Override + protected void finalize() throws Throwable { + try { + jni_YGConfigFree(mNativePointer); + } finally { + super.finalize(); + } + } + + private native void jni_YGConfigSetExperimentalFeatureEnabled( + long nativePointer, + int feature, + boolean enabled); + public void setExperimentalFeatureEnabled(YogaExperimentalFeature feature, boolean enabled) { + jni_YGConfigSetExperimentalFeatureEnabled(mNativePointer, feature.intValue(), enabled); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java index 94f16a991bdc5f..3772c4f11d1084 100644 --- a/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java +++ b/ReactAndroid/src/main/java/com/facebook/yoga/YogaNode.java @@ -35,20 +35,6 @@ public static void setLogger(YogaLogger logger) { jni_YGSetLogger(logger); } - private static native void jni_YGSetExperimentalFeatureEnabled( - int feature, - boolean enabled); - public static void setExperimentalFeatureEnabled( - YogaExperimentalFeature feature, - boolean enabled) { - jni_YGSetExperimentalFeatureEnabled(feature.intValue(), enabled); - } - - private static native boolean jni_YGIsExperimentalFeatureEnabled(int feature); - public static boolean isExperimentalFeatureEnabled(YogaExperimentalFeature feature) { - return jni_YGIsExperimentalFeatureEnabled(feature.intValue()); - } - private YogaNode mParent; private List mChildren; private YogaMeasureFunction mMeasureFunction; @@ -104,6 +90,14 @@ public YogaNode() { } } + private native long jni_YGNodeNewWithConfig(long configPointer); + public YogaNode(YogaConfig config) { + mNativePointer = jni_YGNodeNewWithConfig(config.mNativePointer); + if (mNativePointer == 0) { + throw new IllegalStateException("Failed to allocate native memory"); + } + } + private native void jni_YGNodeFree(long nativePointer); @Override protected void finalize() throws Throwable { diff --git a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp index 15f6d46f53bd63..72e704c8c82e81 100644 --- a/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp +++ b/ReactAndroid/src/main/jni/first-party/yogajni/jni/YGJNI.cpp @@ -150,6 +150,10 @@ static inline YGNodeRef _jlong2YGNodeRef(jlong addr) { return reinterpret_cast(static_cast(addr)); } +static inline YGConfigRef _jlong2YGConfigRef(jlong addr) { + return reinterpret_cast(static_cast(addr)); +} + void jni_YGSetLogger(alias_ref clazz, alias_ref logger) { if (jLogger) { jLogger->releaseAlias(); @@ -171,18 +175,6 @@ void jni_YGLog(alias_ref clazz, jint level, jstring message) { Environment::current()->ReleaseStringUTFChars(message, nMessage); } -void jni_YGSetExperimentalFeatureEnabled(alias_ref clazz, jint feature, jboolean enabled) { - YGSetExperimentalFeatureEnabled(static_cast(feature), enabled); -} - -jboolean jni_YGIsExperimentalFeatureEnabled(alias_ref clazz, jint feature) { - return YGIsExperimentalFeatureEnabled(static_cast(feature)); -} - -jint jni_YGNodeGetInstanceCount(alias_ref clazz) { - return YGNodeGetInstanceCount(); -} - jlong jni_YGNodeNew(alias_ref thiz) { const YGNodeRef node = YGNodeNew(); YGNodeSetContext(node, new weak_ref(make_weak(thiz))); @@ -190,6 +182,13 @@ jlong jni_YGNodeNew(alias_ref thiz) { return reinterpret_cast(node); } +jlong jni_YGNodeNewWithConfig(alias_ref thiz, jlong configPointer) { + const YGNodeRef node = YGNodeNewWithConfig(_jlong2YGConfigRef(configPointer)); + YGNodeSetContext(node, new weak_ref(make_weak(thiz))); + YGNodeSetPrintFunc(node, YGPrint); + return reinterpret_cast(node); +} + void jni_YGNodeFree(alias_ref thiz, jlong nativePointer) { const YGNodeRef node = _jlong2YGNodeRef(nativePointer); delete YGNodeJobject(node); @@ -368,6 +367,24 @@ YG_NODE_JNI_STYLE_UNIT_PROP(MaxHeight); // Yoga specific properties, not compatible with flexbox specification YG_NODE_JNI_STYLE_PROP(jfloat, float, AspectRatio); +jlong jni_YGConfigNew(alias_ref) { + return reinterpret_cast(YGConfigNew()); +} + +void jni_YGConfigFree(alias_ref, jlong nativePointer) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + YGConfigFree(config); +} + +void jni_YGConfigSetExperimentalFeatureEnabled(alias_ref, jlong nativePointer, jint feature, jboolean enabled) { + const YGConfigRef config = _jlong2YGConfigRef(nativePointer); + YGConfigSetExperimentalFeatureEnabled(config, static_cast(feature), enabled); +} + +jint jni_YGNodeGetInstanceCount(alias_ref clazz) { + return YGNodeGetInstanceCount(); +} + #define YGMakeNativeMethod(name) makeNativeMethod(#name, name) jint JNI_OnLoad(JavaVM *vm, void *) { @@ -375,6 +392,7 @@ jint JNI_OnLoad(JavaVM *vm, void *) { registerNatives("com/facebook/yoga/YogaNode", { YGMakeNativeMethod(jni_YGNodeNew), + YGMakeNativeMethod(jni_YGNodeNewWithConfig), YGMakeNativeMethod(jni_YGNodeFree), YGMakeNativeMethod(jni_YGNodeReset), YGMakeNativeMethod(jni_YGNodeInsertChild), @@ -452,8 +470,12 @@ jint JNI_OnLoad(JavaVM *vm, void *) { YGMakeNativeMethod(jni_YGNodeGetInstanceCount), YGMakeNativeMethod(jni_YGSetLogger), YGMakeNativeMethod(jni_YGLog), - YGMakeNativeMethod(jni_YGSetExperimentalFeatureEnabled), - YGMakeNativeMethod(jni_YGIsExperimentalFeatureEnabled), + }); + registerNatives("com/facebook/yoga/YogaConfig", + { + YGMakeNativeMethod(jni_YGConfigNew), + YGMakeNativeMethod(jni_YGConfigFree), + YGMakeNativeMethod(jni_YGConfigSetExperimentalFeatureEnabled), }); }); } diff --git a/ReactCommon/yoga/yoga/Yoga.c b/ReactCommon/yoga/yoga/Yoga.c index 9407835a4c7805..3f85dfeb9fa5e7 100644 --- a/ReactCommon/yoga/yoga/Yoga.c +++ b/ReactCommon/yoga/yoga/Yoga.c @@ -94,6 +94,8 @@ typedef struct YGStyle { float aspectRatio; } YGStyle; +typedef struct YGConfig { bool experimentalFeatures[YGExperimentalFeatureCount + 1]; } YGConfig; + typedef struct YGNode { YGStyle style; YGLayout layout; @@ -107,6 +109,7 @@ typedef struct YGNode { YGMeasureFunc measure; YGBaselineFunc baseline; YGPrintFunc print; + YGConfigRef config; void *context; bool isDirty; @@ -191,6 +194,14 @@ static YGNode gYGNodeDefaults = { }, }; +static YGConfig gYGConfigDefaults = { + .experimentalFeatures = + { + [YGExperimentalFeatureRounding] = false, + [YGExperimentalFeatureWebFlexBasis] = false, + }, +}; + static void YGNodeMarkDirtyInternal(const YGNodeRef node); YGMalloc gYGMalloc = &malloc; @@ -290,15 +301,21 @@ static inline float YGValueResolveMargin(const YGValue *const value, const float int32_t gNodeInstanceCount = 0; -YGNodeRef YGNodeNew(void) { + +WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) { const YGNodeRef node = gYGMalloc(sizeof(YGNode)); YG_ASSERT(node, "Could not allocate memory for node"); gNodeInstanceCount++; memcpy(node, &gYGNodeDefaults, sizeof(YGNode)); + node->config = config; return node; } +YGNodeRef YGNodeNew(void) { + return YGNodeNewWithConfig(&gYGConfigDefaults); +} + void YGNodeFree(const YGNodeRef node) { if (node->parent) { YGNodeListDelete(node->parent->children, node); @@ -331,13 +348,27 @@ void YGNodeReset(const YGNodeRef node) { YG_ASSERT(node->parent == NULL, "Cannot reset a node still attached to a parent"); YGNodeListFree(node->children); + + const YGConfigRef config = node->config; memcpy(node, &gYGNodeDefaults, sizeof(YGNode)); + node->config = config; } int32_t YGNodeGetInstanceCount(void) { return gNodeInstanceCount; } +YGConfigRef YGConfigNew(void) { + const YGConfigRef config = gYGMalloc(sizeof(YGConfig)); + YG_ASSERT(config, "Could not allocate memory for config"); + memcpy(config, &gYGConfigDefaults, sizeof(YGConfig)); + return config; +} + +void YGConfigFree(const YGConfigRef config) { + gYGFree(config); +} + static void YGNodeMarkDirtyInternal(const YGNodeRef node) { if (!node->isDirty) { node->isDirty = true; @@ -678,7 +709,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const float parentWidth, const float parentHeight, const bool performLayout, - const char *reason); + const char *reason, + const YGConfigRef config); inline bool YGFloatIsUndefined(const float value) { return isnan(value); @@ -1335,7 +1367,8 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, const float parentWidth, const float parentHeight, const YGMeasureMode heightMode, - const YGDirection direction) { + const YGDirection direction, + const YGConfigRef config) { const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); const float mainAxisSize = isMainAxisRow ? width : height; @@ -1354,7 +1387,7 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, if (!YGFloatIsUndefined(resolvedFlexBasis) && !YGFloatIsUndefined(mainAxisSize)) { if (YGFloatIsUndefined(child->layout.computedFlexBasis) || - (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis) && + (YGConfigIsExperimentalFeatureEnabled(config, YGExperimentalFeatureWebFlexBasis) && child->layout.computedFlexBasisGeneration != gCurrentGenerationCount)) { child->layout.computedFlexBasis = fmaxf(resolvedFlexBasis, YGNodePaddingAndBorderForAxis(child, mainAxis, parentWidth)); @@ -1456,7 +1489,8 @@ static void YGNodeComputeFlexBasisForChild(const YGNodeRef node, parentWidth, parentHeight, false, - "measure"); + "measure", + config); child->layout.computedFlexBasis = fmaxf(child->layout.measuredDimensions[dim[mainAxis]], @@ -1471,7 +1505,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, const float width, const YGMeasureMode widthMode, const float height, - const YGDirection direction) { + const YGDirection direction, + const YGConfigRef config) { const YGFlexDirection mainAxis = YGFlexDirectionResolve(node->style.flexDirection, direction); const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction); const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis); @@ -1560,7 +1595,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childWidth, childHeight, false, - "abs-measure"); + "abs-measure", + config); childWidth = child->layout.measuredDimensions[YGDimensionWidth] + YGNodeMarginForAxis(child, YGFlexDirectionRow, width); childHeight = child->layout.measuredDimensions[YGDimensionHeight] + @@ -1576,7 +1612,8 @@ static void YGNodeAbsoluteLayoutChild(const YGNodeRef node, childWidth, childHeight, true, - "abs-layout"); + "abs-layout", + config); if (YGNodeIsTrailingPosDefined(child, mainAxis) && !YGNodeIsLeadingPosDefined(child, mainAxis)) { child->layout.position[leading[mainAxis]] = node->layout.measuredDimensions[dim[mainAxis]] - @@ -1854,7 +1891,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, const YGMeasureMode heightMeasureMode, const float parentWidth, const float parentHeight, - const bool performLayout) { + const bool performLayout, + const YGConfigRef config) { YG_ASSERT(YGFloatIsUndefined(availableWidth) ? widthMeasureMode == YGMeasureModeUndefined : true, "availableWidth is indefinite so widthMeasureMode must be " "YGMeasureModeUndefined"); @@ -2056,7 +2094,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, availableInnerHeight, heightMeasureMode, - direction); + direction, + config); } } @@ -2173,7 +2212,7 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerMainDim = minInnerMainDim; } else if (!YGFloatIsUndefined(maxInnerMainDim) && sizeConsumedOnCurrentLine > maxInnerMainDim) { availableInnerMainDim = maxInnerMainDim; - } else if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureMinFlexFix)) { + } else if (YGConfigIsExperimentalFeatureEnabled(config, YGExperimentalFeatureMinFlexFix)) { // TODO: this needs to be moved out of experimental feature, as this is legitimate fix // If the measurement isn't exact, we want to use as little space as possible availableInnerMainDim = sizeConsumedOnCurrentLine; @@ -2422,7 +2461,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, availableInnerHeight, performLayout && !requiresStretchLayout, - "flex"); + "flex", + config); currentRelativeChild = currentRelativeChild->nextChild; } @@ -2660,7 +2700,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, availableInnerHeight, true, - "stretch"); + "stretch", + config); } } else { const float remainingCrossDim = @@ -2827,7 +2868,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, availableInnerHeight, true, - "stretch"); + "stretch", + config); } } break; @@ -2915,7 +2957,8 @@ static void YGNodelayoutImpl(const YGNodeRef node, availableInnerWidth, isMainAxisRow ? measureModeMainDim : measureModeCrossDim, availableInnerHeight, - direction); + direction, + config); } // STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN @@ -3057,7 +3100,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, const float parentWidth, const float parentHeight, const bool performLayout, - const char *reason) { + const char *reason, + const YGConfigRef config) { YGLayout *layout = &node->layout; gDepth++; @@ -3186,7 +3230,8 @@ bool YGLayoutNodeInternal(const YGNodeRef node, heightMeasureMode, parentWidth, parentHeight, - performLayout); + performLayout, + config); if (gPrintChanges) { printf("%s%d.}%s", YGSpacer(gDepth), gDepth, needToVisitNode ? "*" : ""); @@ -3352,11 +3397,11 @@ void YGNodeCalculateLayout(const YGNodeRef node, parentWidth, parentHeight, true, - "initia" - "l")) { - YGNodeSetPosition(node, node->layout.direction, node->layout.dimensions[YGDimensionWidth], node->layout.dimensions[YGDimensionHeight], parentWidth); + "initial", + node->config)) { + YGNodeSetPosition(node, node->layout.direction, parentWidth, parentHeight, parentWidth); - if (YGIsExperimentalFeatureEnabled(YGExperimentalFeatureRounding)) { + if (YGConfigIsExperimentalFeatureEnabled(node->config, YGExperimentalFeatureRounding)) { YGRoundToPixelGrid(node); } @@ -3377,14 +3422,15 @@ void YGLog(YGLogLevel level, const char *format, ...) { va_end(args); } -static bool experimentalFeatures[YGExperimentalFeatureCount + 1]; - -void YGSetExperimentalFeatureEnabled(YGExperimentalFeature feature, bool enabled) { - experimentalFeatures[feature] = enabled; +void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature, + const bool enabled) { + config->experimentalFeatures[feature] = enabled; } -inline bool YGIsExperimentalFeatureEnabled(YGExperimentalFeature feature) { - return experimentalFeatures[feature]; +inline bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature) { + return config->experimentalFeatures[feature]; } void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree) { diff --git a/ReactCommon/yoga/yoga/Yoga.h b/ReactCommon/yoga/yoga/Yoga.h index 64b0cda07ec6f7..cbcf92eec583bc 100644 --- a/ReactCommon/yoga/yoga/Yoga.h +++ b/ReactCommon/yoga/yoga/Yoga.h @@ -46,6 +46,7 @@ typedef struct YGValue { static const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; static const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; +typedef struct YGConfig *YGConfigRef; typedef struct YGNode *YGNodeRef; typedef YGSize (*YGMeasureFunc)(YGNodeRef node, float width, @@ -63,6 +64,7 @@ typedef void (*YGFree)(void *ptr); // YGNode WIN_EXPORT YGNodeRef YGNodeNew(void); +WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config); WIN_EXPORT void YGNodeFree(const YGNodeRef node); WIN_EXPORT void YGNodeFreeRecursive(const YGNodeRef node); WIN_EXPORT void YGNodeReset(const YGNodeRef node); @@ -223,8 +225,15 @@ WIN_EXPORT void YGLog(YGLogLevel level, const char *message, ...); // If you want to avoid rounding - set PointScaleFactor to 0 WIN_EXPORT void YGSetPointScaleFactor(float pixelsInPoint); -WIN_EXPORT void YGSetExperimentalFeatureEnabled(YGExperimentalFeature feature, bool enabled); -WIN_EXPORT bool YGIsExperimentalFeatureEnabled(YGExperimentalFeature feature); +// YGConfig +WIN_EXPORT YGConfigRef YGConfigNew(void); +WIN_EXPORT void YGConfigFree(const YGConfigRef config); + +WIN_EXPORT void YGConfigSetExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature, + const bool enabled); +WIN_EXPORT bool YGConfigIsExperimentalFeatureEnabled(const YGConfigRef config, + const YGExperimentalFeature feature); WIN_EXPORT void YGSetMemoryFuncs(YGMalloc ygmalloc, YGCalloc yccalloc, YGRealloc ygrealloc, YGFree ygfree); From d54c7f82822f623a903858d8d686d7f14ec71aae Mon Sep 17 00:00:00 2001 From: Hector Ramos Date: Wed, 1 Mar 2017 10:58:27 -0800 Subject: [PATCH 014/168] Refresh website Reviewed By: mkonicek Differential Revision: D4634272 fbshipit-source-id: 97d22115ffa29456ce253ad8c97a720d0c4e4d53 --- website/core/DocsSidebar.js | 2 +- website/core/Hero.js | 2 +- website/package.json | 1 + website/server/extractDocs.js | 5 +- website/server/server.js | 43 +- website/src/react-native/css/react-native.css | 2239 +++++++++-------- website/src/react-native/index.js | 15 +- website/styles/_blog.scss | 186 ++ website/styles/_footer.scss | 109 + website/styles/_help.scss | 56 + website/styles/_hero.scss | 39 + website/styles/_showcase.scss | 82 + website/styles/_webplayer.scss | 13 + website/styles/lib/multisite/_mixins.scss | 7 + website/styles/lib/multisite/_variables.scss | 25 + website/styles/lib/vendor/_algolia.scss | 86 + website/styles/lib/vendor/_prism.scss | 30 + website/styles/lib/vendor/normalize.css | 461 ++++ website/styles/react-native.scss | 1423 +++++++++++ 19 files changed, 3696 insertions(+), 1128 deletions(-) create mode 100644 website/styles/_blog.scss create mode 100644 website/styles/_footer.scss create mode 100644 website/styles/_help.scss create mode 100644 website/styles/_hero.scss create mode 100644 website/styles/_showcase.scss create mode 100644 website/styles/_webplayer.scss create mode 100644 website/styles/lib/multisite/_mixins.scss create mode 100644 website/styles/lib/multisite/_variables.scss create mode 100644 website/styles/lib/vendor/_algolia.scss create mode 100644 website/styles/lib/vendor/_prism.scss create mode 100644 website/styles/lib/vendor/normalize.css create mode 100644 website/styles/react-native.scss diff --git a/website/core/DocsSidebar.js b/website/core/DocsSidebar.js index 1212af7abf5c6d..dd0d5f878cd782 100644 --- a/website/core/DocsSidebar.js +++ b/website/core/DocsSidebar.js @@ -83,8 +83,8 @@ var DocsSidebar = React.createClass({ {category.links.map((metadata) =>
  • {metadata.title} diff --git a/website/core/Hero.js b/website/core/Hero.js index ba2b1ba32c4070..79463ce46a9148 100644 --- a/website/core/Hero.js +++ b/website/core/Hero.js @@ -17,7 +17,7 @@ var Hero = React.createClass({ return (
    -
    {this.props.title}
    +
    {this.props.title}
    {this.props.subtitle}
    diff --git a/website/package.json b/website/package.json index b41d6e418a2657..9e15ca756fc492 100644 --- a/website/package.json +++ b/website/package.json @@ -22,6 +22,7 @@ "jstransform": "11.0.3", "memory-cache": "^0.1.6", "mkdirp": "^0.5.1", + "node-sass-middleware": "^0.11.0", "optimist": "0.6.0", "react": "~0.13.0", "react-docgen": "^2.9.0", diff --git a/website/server/extractDocs.js b/website/server/extractDocs.js index eb671b398d5e71..5a9df680f4c105 100644 --- a/website/server/extractDocs.js +++ b/website/server/extractDocs.js @@ -200,8 +200,11 @@ function componentsToMarkdown(type, json, filepath, idx, styles) { json.methods = json.methods.filter(filterMethods); } + if (type === 'api') { + type = 'API'; + } // Put styles (e.g. Flexbox) into the API category - const category = (type === 'style' ? 'apis' : type + 's'); + const category = (type === 'style' ? 'APIs' : type + 's'); const next = getNextComponent(idx); const previous = getPreviousComponent(idx); diff --git a/website/server/server.js b/website/server/server.js index 3ba76960c76142..f6511d4c7ab921 100644 --- a/website/server/server.js +++ b/website/server/server.js @@ -7,27 +7,28 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -"use strict"; -var connect = require('connect'); -var http = require('http'); -var optimist = require('optimist'); -var path = require('path'); -var reactMiddleware = require('react-page-middleware'); -var convert = require('./convert.js'); +'use strict'; +const connect = require('connect'); +const convert = require('./convert.js'); +const http = require('http'); +const optimist = require('optimist'); +const path = require('path'); +const reactMiddleware = require('react-page-middleware'); +const sassMiddleware = require('node-sass-middleware'); -var argv = optimist.argv; +const argv = optimist.argv; -var PROJECT_ROOT = path.resolve(__dirname, '..'); -var FILE_SERVE_ROOT = path.join(PROJECT_ROOT, 'src'); +const PROJECT_ROOT = path.resolve(__dirname, '..'); +const FILE_SERVE_ROOT = path.join(PROJECT_ROOT, 'src'); -var port = argv.port; -if (argv.$0 === 'node ./server/generate.js') { +let port = argv.port; +if (argv.$0.indexOf('node ./server/generate.js') !== -1) { // Using a different port so that you can publish the website // and keeping the server up at the same time. port = 8079; } -var buildOptions = { +const buildOptions = { projectRoot: PROJECT_ROOT, pageRouteRoot: FILE_SERVE_ROOT, useBrowserBuiltins: false, @@ -41,7 +42,15 @@ var buildOptions = { static: true }; -var app = connect() +const app = connect() + .use(sassMiddleware({ + /* Options */ + src: path.join(PROJECT_ROOT,'styles'), + dest: path.join(FILE_SERVE_ROOT,'react-native','css'), + response: false, + outputStyle: 'extended', + prefix: '/react-native/css', + })) .use(function(req, res, next) { // convert all the md files on every request. This is not optimal // but fast enough that we don't really need to care right now. @@ -52,14 +61,14 @@ var app = connect() next(); }) .use(reactMiddleware.provide(buildOptions)) - .use(connect['static'](FILE_SERVE_ROOT)) + .use(connect.static(FILE_SERVE_ROOT)) .use(connect.favicon(path.join(FILE_SERVE_ROOT, 'react-native', 'img', 'favicon.png'))) .use(connect.logger()) .use(connect.compress()) .use(connect.errorHandler()); -var portToUse = port || 8079; -var server = http.createServer(app); +const portToUse = port || 8079; +const server = http.createServer(app); server.listen(portToUse, function(){ console.log('Open http://localhost:' + portToUse + '/react-native/index.html'); }); diff --git a/website/src/react-native/css/react-native.css b/website/src/react-native/css/react-native.css index 3160da3e37aa78..6c20eedfb866d6 100644 --- a/website/src/react-native/css/react-native.css +++ b/website/src/react-native/css/react-native.css @@ -1,532 +1,779 @@ +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ +/* Document + ========================================================================== */ +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ +html { + font-family: sans-serif; + /* 1 */ + line-height: 1.15; + /* 2 */ + -ms-text-size-adjust: 100%; + /* 3 */ + -webkit-text-size-adjust: 100%; + /* 3 */ } + +/* Sections + ========================================================================== */ +/** + * Remove the margin in all browsers (opinionated). + */ +body { + margin: 0; } + +/** + * Add the correct display in IE 9-. + */ +article, +aside, +footer, +header, +nav, +section { + display: block; } + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/* Grouping content + ========================================================================== */ +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ +figcaption, +figure, +main { + /* 1 */ + display: block; } + +/** + * Add the correct margin in IE 8. + */ +figure { + margin: 1em 40px; } + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ +hr { + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +pre { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/* Text-level semantics + ========================================================================== */ +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ +a { + background-color: transparent; + /* 1 */ + -webkit-text-decoration-skip: objects; + /* 2 */ } + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ +a:active, +a:hover { + outline-width: 0; } + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ +abbr[title] { + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ } + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ +b, +strong { + font-weight: inherit; } + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ +b, +strong { + font-weight: bolder; } + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ +code, +kbd, +samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } + +/** + * Add the correct font style in Android 4.3-. + */ +dfn { + font-style: italic; } + +/** + * Add the correct background and color in IE 9-. + */ +mark { + background-color: #ff0; + color: #000; } + +/** + * Add the correct font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sub { + bottom: -0.25em; } + +sup { + top: -0.5em; } + +/* Embedded content + ========================================================================== */ +/** + * Add the correct display in IE 9-. + */ +audio, +video { + display: inline-block; } + +/** + * Add the correct display in iOS 4-7. + */ +audio:not([controls]) { + display: none; + height: 0; } + +/** + * Remove the border on images inside links in IE 10-. + */ +img { + border-style: none; } + +/** + * Hide the overflow in IE. + */ +svg:not(:root) { + overflow: hidden; } + +/* Forms + ========================================================================== */ +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ } + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ +button, +input { + /* 1 */ + overflow: visible; } + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ +button, +select { + /* 1 */ + text-transform: none; } + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ +button, +html [type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; + /* 2 */ } + +/** + * Remove the inner border and padding in Firefox. + */ +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; } + +/** + * Restore the focus styles unset by the previous rule. + */ +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; } + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; } + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ +legend { + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ } + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ +progress { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ } + +/** + * Remove the default vertical scrollbar in IE. + */ +textarea { + overflow: auto; } + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ +[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ } + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ } + +/* Interactive + ========================================================================== */ +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ +details, +menu { + display: block; } + +/* + * Add the correct display in all browsers. + */ +summary { + display: list-item; } + +/* Scripting + ========================================================================== */ +/** + * Add the correct display in IE 9-. + */ +canvas { + display: inline-block; } + +/** + * Add the correct display in IE. + */ +template { + display: none; } + +/* Hidden + ========================================================================== */ +/** + * Add the correct display in IE 10-. + */ +[hidden] { + display: none; } + html { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif; color: #484848; - line-height: 1.28; -} + line-height: 1.28; } body { - background-color: #F5FCFF; -} + background-color: #F5FCFF; } p { margin: 0 0 16px; line-height: 1.4; } -.subHeader { - font-size: 21px; - font-weight: 300; - line-height: 30px; - margin-bottom: 10px; -} +* { + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border: none; + margin: 0; + padding: 0; } em { - font-style: italic; -} + font-style: italic; } h1, h2, h3, h4, h5, h6 { margin: 10px 0; font-family: inherit; - font-weight: bold; + font-weight: 400; line-height: 20px; - color: inherit; - text-rendering: optimizelegibility; -} + color: #025268; + text-rendering: optimizelegibility; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-weight: normal; - color: #7b7b7b; -} + color: #7b7b7b; } h1, h2, h3, h4 { - line-height: 40px; -} + line-height: 40px; } h1 { - font-size: 39px; -} + font-size: 39px; } h2 { - font-size: 31px; -} + font-size: 31px; } h3 { - font-size: 23px; -} + font-size: 23px; } h4 { - font-size: 17px; -} + font-size: 17px; } h5 { - font-size: 14px; -} + font-size: 14px; } h6 { - font-size: 11px; -} + font-size: 11px; } h1 small { - font-size: 24px; -} + font-size: 24px; } h2 small { - font-size: 18px; -} + font-size: 18px; } h3 small { - font-size: 16px; -} + font-size: 16px; } h4 small { - font-size: 14px; -} + font-size: 14px; } img { max-width: 100%; - height: auto; -} + height: auto; } ul, ol { margin: 0 0 10px 25px; - padding: 0; -} + padding: 0; } ul ul, ul ol, ol ol, ol ul { - margin-bottom: 0; -} + margin-bottom: 0; } li { - line-height: 20px; -} + line-height: 20px; } a { color: #05A5D1; - text-decoration: none; -} + text-decoration: none; } a:hover, a:focus { - color: #0485A9; - text-decoration: underline; -} + color: #047e9f; + text-decoration: underline; } a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} + outline-offset: -2px; } .center { - text-align: center; -} + text-align: center; } html * { color-profile: sRGB; - rendering-intent: auto; -} + rendering-intent: auto; } + +.subHeader { + font-size: 21px; + font-weight: 300; + line-height: 30px; + margin-bottom: 10px; } .example-container { - position: relative; -} + position: relative; } .embedded-simulator, .embedded-simulator * { - box-sizing: border-box; -} + box-sizing: border-box; } .embedded-simulator p { text-align: center; - color: #999; -} + color: #999; } .embedded-simulator { width: 210px; position: absolute; right: -200px; - top: 0; -} + top: 0; } @media screen and (max-width: 680px) { .embedded-simulator { position: relative; - right: 0; - } -} - -.prism { - white-space: pre-wrap; - font-family: 'source-code-pro', Menlo, 'Courier New', Consolas, monospace; - font-size: 13px; - line-height: 20px; - border-left: 4px solid #05A5D1; - padding: 5px 10px; - background-color: rgba(5, 165, 209, 0.05); - overflow: auto; -} - -.prism + .prism { - margin-top: 10px; -} - -.token.keyword { - color: #1990B8; -} - -.token.string, .token.regex { - color: #2F9C0A; -} - -.token.boolean, .token.number { - color: #C92C2C; -} - -.token.comment { - color: #7D8B99; -} + right: 0; } } .side-by-side { - overflow: hidden; -} + overflow: hidden; } .side-by-side > div { width: 460; margin-left: 0; - float: left; -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - border: none; - margin: 0; - padding: 0; -} + float: left; } .left { - float: left; -} + float: left; } .right { - float: right; -} + float: right; } .container { padding-top: 50px; - min-width: 1160px; -} + min-width: 1160px; } .wrap { max-width: 1260px; margin: 0 auto; - padding: 0 20px; -} + padding: 0 20px; } .skinnyWrap { width: 690px; margin-left: auto; margin-right: auto; padding-left: 20px; - padding-right: 20px; -} + padding-right: 20px; } hr { height: 0; border-top: 1px solid #ccc; - border-bottom: 1px solid #eee; -} + border-bottom: 1px solid #eee; } ul, li { - margin-left: 20px; -} + margin-left: 20px; } h1 .anchor, h2 .anchor, h3 .anchor, h4 .anchor, h5 .anchor, h6 .anchor { margin-top: -50px; - position: absolute; -} + position: absolute; } h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-link, h5:hover .hash-link, h6:hover .hash-link { - visibility: visible; -} + visibility: visible; } .hash-link { color: #aaa; - visibility: hidden; -} + visibility: hidden; } .nav-main { *zoom: 1; - background: #3B3738; + background: #222; color: #fafafa; position: fixed; top: 0; min-height: 50px; - box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); width: 100%; z-index: 100; -} + box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); } .nav-main:before, .nav-main:after { content: " "; - display: table; -} + display: table; } .nav-main:after { - clear: both; -} + clear: both; } .nav-main a { color: #e9e9e9; - text-decoration: none; -} + text-decoration: none; } .nav-main .nav-site-wrapper { - display: inline; -} + display: inline; } .nav-main .nav-site-internal { - margin: 0 0 0 20px; -} + margin: 0 0 0 20px; } .nav-main .nav-site-external { float: right; - margin: 0 12px 0 0; -} + margin: 0 12px 0 0; } .nav-main .nav-site li { - margin: 0; -} + margin: 0; } .nav-main .nav-site a { box-sizing: content-box; padding: 0 10px; - line-height: 50px; - display: inline-block; - height: 50px; - color: #ddd; -} - -.nav-main .nav-site a:hover { - color: #fff; -} - -.nav-main .nav-site a.active { - color: #fff; - border-bottom: 3px solid #05A5D1; - background: #333; -} - -.nav-main .nav-home { - font-size: 24px; - line-height: 50px; -} - -.nav-home img { - vertical-align: -9px; - margin-right: 8px; - margin-left: 1px; - width: 34px; -} - -.nav-main a.nav-home { - color: white; -} - -.nav-main ul { - display: inline-block; - vertical-align: top; -} - -.nav-main li { - display: inline; -} - -.nav-main a.nav-version { - font-size: 16px; - font-weight: 800; - color: #05A5D1; - margin-left: 8px; - text-decoration: underline; -} - -@media screen and (max-width: 680px) { - .nav-main .nav-home { - font-size: 20px; - } - - .nav-main a.nav-version { - font-size: 14px; - } - - .nav-main .nav-site-wrapper { - display: block; - overflow: hidden; - } - - .nav-main ul { - display: -webkit-flex; - display: flex; - overflow: hidden; - } - - .nav-main li { - -webkit-flex: 1; - flex: 1; - } - - .nav-main .nav-site li a { - width: 100%; - padding: 0; - text-align: center; - font-size: 14px; - } - - .nav-main .nav-site a.active { - color: #05A5D1; - font-weight: bold; - background-color: transparent; - } - - .nav-main .nav-site-internal { - margin: 0; - width: 100%; - } - - .nav-main .nav-site-external { - position: absolute; - top: 0; - right: 0; - float: none; - } - - .nav-main .nav-site-external li a { - padding: 0 6px; - } -} - -.hero { - background: #2D2D2D; - padding: 50px 0; - color: #FDF3E7; - font-weight: 300; -} - -.hero .text { - font-size: 64px; - text-align: center; -} - -.hero .minitext { - font-size: 16px; - text-align: center; - text-transform: uppercase; -} - -.hero strong { - font-weight: 400; -} - -.buttons-unit { - margin-top: 40px; - text-align: center; -} - -.buttons-unit a { - color: #FA6900; -} - -.buttons-unit .button { - font-size: 24px; - background: #05A5D1; - color: #fafafa; -} - -.buttons-unit .button:active { - background: #0485A9; -} - -.buttons-unit.downloads { - margin: 30px 0; -} - -.nav-docs { - font-size: 14px; - float: left; - width: 210px; - margin: 5px 48px 0 0; -} + line-height: 50px; + display: inline-block; + height: 50px; } -.nav-docs ul { - list-style: none; - margin: 0; - margin-left: 1px; -} +.nav-site-wrapper a:hover { + color: #fff; } -.nav-docs ul ul { - margin-left: 20px; -} +.nav-site-wrapper a.active { + color: #fff; + border-bottom: 3px solid #05A5D1; + background-color: #2D2D2D; } -.nav-docs li { - margin: 0; -} +.nav-main .nav-home { + font-size: 24px; + font-weight: 300; + line-height: 50px; } -.nav-docs h3 { - text-transform: uppercase; - font-size: 14px; -} +.nav-home img { + vertical-align: -9px; + margin-right: 8px; + margin-left: 1px; + width: 34px; } -.nav-docs a { - color: #666; - display: block; -} +.nav-main a.nav-home { + color: white; } -.nav-docs a:hover { - text-decoration: none; - color: #0485A9; -} +.nav-main ul { + display: inline-block; + vertical-align: top; } -.nav-docs a.active { - color: #0485A9; -} +.nav-main li { + display: inline; } -.nav-docs h3 { - line-height: 25px; - margin-top: 12px; - margin-bottom: 5px; -} +.nav-main a.nav-version { + font-size: 16px; + font-weight: 300; + margin-left: 8px; + text-decoration: underline; } -.nav-docs .nav-docs-section:first-child h3 { - margin-top: 0; -} +@media screen and (max-width: 680px) { + .nav-main .nav-home { + font-size: 20px; } + .nav-main a.nav-version { + font-size: 14px; } + .nav-main .nav-site-wrapper { + display: block; + overflow: hidden; } + .nav-main ul { + display: -webkit-flex; + display: flex; + overflow: hidden; } + .nav-main li { + -webkit-flex: 1; + flex: 1; } + .nav-main .nav-site li a { + width: 100%; + padding: 0; + text-align: center; + font-size: 14px; } + .nav-main .nav-site a.active { + color: #05A5D1; + font-weight: 300; + background-color: transparent; } + .nav-main .nav-site-internal { + margin: 0; + width: 100%; } + .nav-main .nav-site-external { + position: absolute; + top: 0; + right: 0; + float: none; } + .nav-main .nav-site-external li a { + padding: 0 6px; } } -.nav-docs .nav-docs-section:first-child { - padding-top: 0; - border-top: 0; -} +.nav-docs { + font-size: 14px; + float: left; + width: 210px; + margin: 5px 48px 0 0; } + .nav-docs ul { + list-style: none; + margin: 0; + margin-left: 1px; } + .nav-docs ul ul { + margin-left: 20px; } + .nav-docs li { + margin: 0; } + .nav-docs a:hover { + text-decoration: none; + color: #025268; } + .nav-docs a.active { + color: #05A5D1; + font-weight: bold; } -.nav-docs .nav-docs-section:last-child { - padding-bottom: 0; - border-bottom: 0; -} +.nav-docs-section { + background-color: rgba(59, 55, 56, 0.05); + padding-bottom: 0; } + .nav-docs-section h3 { + color: white; + font-size: 16px; + font-weight: 400; + line-height: 20px; + margin-top: 12px; + margin-bottom: 5px; + padding: 10px; + background-color: #222; + text-transform: capitalize; } + .nav-docs-section ul { + display: block; + padding-bottom: 10px; + padding-top: 10px; } + .nav-docs-section a { + color: #025268; + display: block; + margin: 2px 10px 5px; } + .nav-docs-section .nav-docs-section:first-child h3 { + margin-top: 0; } + .nav-docs-section .nav-docs-section:first-child { + padding-top: 0; + border-top: 0; } + .nav-docs-section .nav-docs-section:last-child { + padding-bottom: 0; + border-bottom: 0; } @media only screen and (max-device-width: 1024px) { @-webkit-keyframes slide-in { - 0% { top: -30px; opacity: 0; } - 100% { top: 0; opacity: 1; } - } + 0% { + top: -30px; + opacity: 0; } + 100% { + top: 0; + opacity: 1; } } @-moz-keyframes slide-in { - 0% { top: -30px; opacity: 0; } - 100% { top: 0; opacity: 1; } - } + 0% { + top: -30px; + opacity: 0; } + 100% { + top: 0; + opacity: 1; } } @-o-keyframes slide-in { - 0% { top: -30px; opacity: 0; } - 100% { top: 0; opacity: 1; } - } + 0% { + top: -30px; + opacity: 0; } + 100% { + top: 0; + opacity: 1; } } @keyframes slide-in { - 0% { top: -30px; opacity: 0; } - 100% { top: 0; opacity: 1; } - } - + 0% { + top: -30px; + opacity: 0; } + 100% { + top: 0; + opacity: 1; } } .nav-docs { position: fixed; z-index: 90; @@ -536,405 +783,312 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li height: 100%; margin: 0; padding: 53px 0 0 0; - background: #3B3738; - } - + background: #3B3738; } .nav-docs-viewport { - border-top: 1px solid rgb(5, 165, 209); + border-top: 1px solid #05a5d1; padding: 25px; overflow: scroll; -webkit-overflow-scrolling: touch; position: relative; width: 100%; - height: 100%; - } - + height: 100%; } /* Active state */ .nav-docs.in { top: 0; - -webkit-animation: slide-in 0.3s forwards; -moz-animation: slide-in 0.3s forwards; + -ms-animation: slide-in 0.3s forwards; -o-animation: slide-in 0.3s forwards; - animation: slide-in 0.3s forwards; - } - + -webkit-animation: slide-in 0.3s forwards; + animation: slide-in 0.3s forwards; } .nav-docs * { - -webkit-font-smoothing: antialiased; - } - + -webkit-font-smoothing: antialiased; } .nav-docs-section + .nav-docs-section { - margin-top: 50px; - } - + margin-top: 50px; } .nav-docs-section li { - margin: 5px 0; - } - + margin: 5px 0; } .nav-docs-section h3, .nav-docs-section a { - color: white; - } - + color: white; } .nav-docs-section h3 { border-bottom: 1px solid white; margin-bottom: 10px; - opacity: 0.3; - } - + opacity: 0.3; } .nav-docs-section a { margin-right: 25px; font-size: 120%; - padding: 5px 0; - } - + padding: 5px 0; } .nav-docs-section a.active { border-bottom-style: solid; border-bottom-width: 1px; - color: rgb(5, 165, 209); - } -} + color: #05A5D1; } } /** * Multicolumn layout for phone (landscape only) & tablet (regardless its screen orientation)/ */ -@media only screen and (min-device-width : 375px) and (max-device-width : 1024px) { +@media only screen and (min-device-width: 375px) and (max-device-width: 1024px) { .nav-docs-section ul { display: flex; - flex-wrap: wrap; - } - + flex-wrap: wrap; } .nav-docs-section li { - width: 100%; - } -} + width: 100%; } } /* 2 columns layout */ -@media - /*Phone, landscape screen orientation*/ - only screen and (min-device-width : 375px) and (max-device-width : 1024px) and (orientation : landscape), - /*Tablet, portrait screen orientation*/ - only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) { +@media only screen and (min-device-width: 375px) and (max-device-width: 1024px) and (orientation: landscape), only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) { .nav-docs-section li { - width: 50%; - } -} + width: 50%; } } /* 3 columns layout on tablet (landscape screen orientation) */ -@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) { +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) { .nav-docs-section li { - width: 33%; - } -} + width: 33%; } } .home-section { - margin: 50px 0; -} + margin: 50px 0; } .home-section ol { - margin-left: 0; -} + margin-left: 0; } .home-divider { border-top-color: #bbb; margin: 0 auto; - width: 400px; -} + width: 400px; } .marketing-row { *zoom: 1; - margin: 50px 0; -} + margin: 50px 0; } .marketing-row:before, .marketing-row:after { content: " "; - display: table; -} + display: table; } .marketing-row:after { - clear: both; -} + clear: both; } .marketing-col { float: left; margin-left: 40px; - width: 280px; -} + width: 280px; } .marketing-col h3 { color: #2d2d2d; font-size: 24px; font-weight: normal; - text-transform: uppercase; -} + text-transform: uppercase; } .marketing-col p { - font-size: 16px; -} + font-size: 16px; } .marketing-col:first-child { - margin-left: 0; -} + margin-left: 0; } .tutorial-mock { - text-align: center; -} + text-align: center; } + .tutorial-mock img { border: 1px solid #ccc; - box-shadow: 5px 5px 5px #888888; -} + box-shadow: 5px 5px 5px #888888; } #examples h3, .home-presentation h3 { color: #2d2d2d; font-size: 24px; font-weight: normal; - margin-bottom: 5px; -} + margin-bottom: 5px; } #examples p { margin: 0 0 25px 0; - max-width: 600px; -} + max-width: 600px; } #examples .example { - margin-top: 60px; -} + margin-top: 60px; } #examples #todoExample { - font-size: 14px; -} + font-size: 14px; } #examples #todoExample ul { list-style-type: square; - margin: 0 0 10px 0; -} + margin: 0 0 10px 0; } #examples #todoExample input { border: 1px solid #ccc; - font: 14px proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; padding: 3px; - width: 150px; -} + width: 150px; } #examples #todoExample button { - font: 14px proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; margin-left: 5px; - padding: 4px 10px; -} + padding: 4px 10px; } #examples #markdownExample textarea { border: 1px solid #ccc; - font: 14px proxima-nova, "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; margin-bottom: 10px; - padding: 5px; -} + padding: 5px; } -.home-bottom-section { - margin-bottom: 100px; -} +.home-get-started-section { + margin-bottom: 60px; } .docs-nextprev { - *zoom: 1; -} + *zoom: 1; } .docs-nextprev:before, .docs-nextprev:after { content: " "; - display: table; -} + display: table; } .docs-nextprev:after { - clear: both; -} + clear: both; } .docs-prev { - float: left; -} + float: left; } .docs-next { - float: right; -} + float: right; } section.black content { - padding-bottom: 18px; -} + padding-bottom: 18px; } .blogContent { *zoom: 1; - padding-top: 20px; -} + padding-top: 20px; } .blogContent:before, .blogContent:after { content: " "; - display: table; -} + display: table; } .blogContent:after { - clear: both; -} + clear: both; } .blogContent blockquote { padding: 5px 15px; margin: 20px 0; background-color: #f8f5ec; - border-left: 5px solid #f7ebc6; -} + border-left: 5px solid #f7ebc6; } .documentationContent { *zoom: 1; padding-top: 20px; - padding-bottom: 80px; -} + padding-bottom: 80px; } .documentationContent:before, .documentationContent:after { content: " "; - display: table; -} + display: table; } .documentationContent:after { - clear: both; -} + clear: both; } .documentationContent .subHeader { - font-size: 24px; -} + font-size: 24px; } h2 { - margin-top: 30px; -} + margin-top: 30px; } .documentationContent blockquote { padding: 15px 30px 15px 15px; margin: 20px 0; background-color: rgba(248, 245, 236, 0.1); - border-left: 5px solid rgba(191, 87, 73, 0.2); -} + border-left: 5px solid rgba(191, 87, 73, 0.2); } .documentationContent blockquote h4 { - margin-top: 0; -} + margin-top: 0; } .documentationContent blockquote p { - margin-bottom: 0; -} + margin-bottom: 0; } .documentationContent blockquote p:first-child { font-size: 14px; line-height: 20px; margin-top: 0; - text-rendering: optimizelegibility; -} + text-rendering: optimizelegibility; } .docs-prevnext { min-width: 320px; max-width: 640px; margin: 0 auto 40px; - padding-bottom: 20px; -} + padding-bottom: 20px; } .button { - background: -webkit-linear-gradient( #9a9a9a, #646464); - background: linear-gradient( #9a9a9a, #646464); + background: -webkit-linear-gradient(#9a9a9a, #646464); + background: linear-gradient(#9a9a9a, #646464); border-radius: 4px; padding: 8px 16px; font-size: 18px; - font-weight: 400; + font-weight: 300; margin: 0 12px; display: inline-block; color: #fafafa; text-decoration: none; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); - box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); - text-decoration: none; -} + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } .button:hover { - text-decoration: none; -} + text-decoration: none; } .button:active { - box-shadow: none; -} + box-shadow: none; } .hero .button { - box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3); -} + box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3); } .button.blue { - background: -webkit-linear-gradient( #77a3d2, #4783c2); - background: linear-gradient( #77a3d2, #4783c2); -} + background: -webkit-linear-gradient(#77a3d2, #4783c2); + background: linear-gradient(#77a3d2, #4783c2); } .row { - padding-bottom: 4px; -} + padding-bottom: 4px; } .row .span4 { width: 33.33%; - display: table-cell; -} + display: table-cell; } .row .span8 { width: 66.66%; - display: table-cell; -} + display: table-cell; } .row .span6 { width: 50%; - display: table-cell; -} + display: table-cell; } p { - margin: 10px 0; -} + margin: 10px 0; } .highlight { padding: 10px; - margin-bottom: 20px; -} + margin-bottom: 20px; } figure { - text-align: center; -} + text-align: center; } .inner-content { float: left; - width: 650px; -} + width: 650px; } .showcaseSection .inner-content { - width: 800px; -} + width: 800px; } .helpSection .inner-content { - width: 800px; -} + width: 800px; } .nosidebar .inner-content { float: none; - margin: 0 auto; -} + margin: 0 auto; } -.post-list-item+.post-list-item { - margin-top: 60px; -} +.post-list-item + .post-list-item { + margin-top: 60px; } small code, li code, p code { color: #555; background-color: rgba(0, 0, 0, 0.04); - padding: 1px 3px; -} + padding: 1px 3px; } .playground { - *zoom: 1; -} + *zoom: 1; } .playground:before, .playground:after { content: " "; - display: table; -} + display: table; } .playground:after { - clear: both; -} + clear: both; } .playground-tab { border-bottom: none !important; @@ -945,41 +1099,34 @@ small code, li code, p code { color: #c2c0bc; background-color: #f1ede4; display: inline-block; - cursor: pointer; -} + cursor: pointer; } .playgroundCode, .playground-tab, .playgroundPreview { - border: 1px solid rgba(16, 16, 16, 0.1); -} + border: 1px solid rgba(16, 16, 16, 0.1); } .playground-tab-active { - color: #222; -} + color: #222; } .playgroundCode { border-radius: 0 3px 3px 3px; float: left; overflow: hidden; - width: 600px; -} + width: 600px; } .playgroundPreview { background-color: white; border-radius: 3px; float: right; padding: 15px 20px; - width: 280px; -} + width: 280px; } .playgroundError { color: #c5695c; - font-size: 15px; -} + font-size: 15px; } .MarkdownEditor textarea { width: 100%; - height: 100px; -} + height: 100px; } .hll { background-color: #f7ebc6; @@ -987,13 +1134,11 @@ small code, li code, p code { display: block; margin-left: -14px; margin-right: -14px; - padding-left: 9px; -} + padding-left: 9px; } .highlight .javascript .err { background-color: transparent; - color: inherit; -} + color: inherit; } .highlight { position: relative; @@ -1001,22 +1146,19 @@ small code, li code, p code { padding: 30px 14px 14px; border: none; border-radius: 0; - overflow: auto; -} + overflow: auto; } .highlight pre { padding: 0; margin-top: 0; margin-bottom: 0; background-color: transparent; - border: 0; -} + border: 0; } .highlight pre code { background: none; font-size: inherit; - padding: 0; -} + padding: 0; } .highlight pre .lineno { display: inline-block; @@ -1024,8 +1166,7 @@ small code, li code, p code { padding-right: 5px; margin-right: 10px; color: #bebec5; - text-align: right; -} + text-align: right; } .highlight:after { position: absolute; @@ -1037,22 +1178,19 @@ small code, li code, p code { font-weight: bold; color: #c2c0bc; background-color: #f1ede4; - content: "Code"; -} + content: "Code"; } .downloadCenter { text-align: center; margin-top: 20px; - margin-bottom: 25px; -} + margin-bottom: 25px; } .downloadSection:hover { - text-decoration: none !important; -} + text-decoration: none !important; } /* Modal */ .modal-backdrop { - background: rgba(0,0,0,.4); + background: rgba(0, 0, 0, 0.4); display: none; height: 100%; left: 0; @@ -1060,13 +1198,12 @@ small code, li code, p code { position: fixed; top: 0; width: 100%; - z-index: 9900; -} + z-index: 9900; } .modal { background: #F6F6F6; bottom: 0; - box-shadow: 2px 2px 4px 0 rgba(0,0,0,.11); + box-shadow: 2px 2px 4px 0 rgba(0, 0, 0, 0.11); display: none; border-radius: 10px; height: 95%; @@ -1079,28 +1216,27 @@ small code, li code, p code { right: 0; top: 0; width: 80%; - z-index: 9999; -} + z-index: 9999; } -.modal-open { display: block; } +.modal-open { + display: block; } .modal-content { padding: 40px 24px 8px 24px; - position: relative; -} + position: relative; } -.modal-content iframe { margin: 0 auto; } +.modal-content iframe { + margin: 0 auto; } .modal-button-open { cursor: pointer; - text-align: center; -} + text-align: center; } .modal-button-open-img { - height: 358px; -} + height: 358px; } -.modal-button-open-img:hover img { opacity: 0.9; } +.modal-button-open-img:hover img { + opacity: 0.9; } .modal-button-close { background: transparent; @@ -1114,182 +1250,146 @@ small code, li code, p code { padding: 0 12px; position: absolute; right: 0; - top: 0; -} + top: 0; } .modal-button-close:active, .modal-button-close:focus, .modal-button-close:hover { background: #EAF8FD; - outline: none; -} + outline: none; } @media screen and (max-width: 680px) { .container { - padding-top: 100px; - } - + padding-top: 100px; } .nav-docs { - padding-top: 103px; - } -} + padding-top: 103px; } } .post { - margin-bottom: 30px; -} + margin-bottom: 30px; } .pagination { margin-bottom: 30px; width: 100%; - overflow: hidden; -} + overflow: hidden; } .pagination .next { - float: right; -} + float: right; } div[data-twttr-id] iframe { - margin: 10px auto !important; -} + margin: 10px auto !important; } .three-column { - *zoom: 1; -} + *zoom: 1; } .three-column:before, .three-column:after { content: " "; - display: table; -} + display: table; } .three-column:after { - clear: both; -} + clear: both; } -.three-column>ul { +.three-column > ul { float: left; margin-left: 30px; - width: 190px; -} + width: 190px; } .three-column > ul:first-child { - margin-left: 20px; -} + margin-left: 20px; } .home-why { - margin-top: 25px; -} + margin-top: 25px; } .home-why h3 { - text-align: center; -} + text-align: center; } .home-why .blurb { margin-bottom: 20px; - text-align: center; -} + text-align: center; } .home-why .list { margin: 0 auto; - max-width: 460px; -} + max-width: 460px; } .home-getting-started { width: 500px; - margin: 20px auto 40px auto; -} + margin: 20px auto 40px auto; } .home-getting-started h3 { - text-align: center; -} - + text-align: center; } .props { - background-color: hsl(198, 100%, 96%); -} + background-color: #ebf9ff; } .compactProps { - border-left: 2px solid hsl(198, 100%, 94%); + border-left: 2px solid #e0f6ff; margin-left: 20px; - padding-left: 5px; -} + padding-left: 5px; } .props > .prop:nth-child(2n) { - background-color: hsl(198, 100%, 94%); -} + background-color: #e0f6ff; } .propTitle { font-weight: bold; - font-size: 16px; -} + font-size: 16px; } .compactProps .propTitle { font-size: 14px; margin-bottom: 0; - margin-top: 0; -} + margin-top: 0; } .compactProps .propTitle div { font-weight: normal; - margin-left: 20px; -} + margin-left: 20px; } .methodTitle { font-weight: bold; font-size: 24px; - color: #2F9C0A; -} + color: #025268; } .compactProps .methodTitle { font-size: 14px; margin-bottom: 0; - margin-top: 0; -} + margin-top: 0; } .compactProps .methodTitle div { font-weight: normal; - margin-left: 20px; -} + margin-left: 20px; } .prop { - padding: 5px 10px; -} + padding: 5px 10px; } .compactProps .prop { - padding: 3px 10px; -} + padding: 3px 10px; } .propType { font-weight: normal; font-size: 15px; - white-space: pre-wrap; -} + white-space: pre-wrap; } .compactProps .propType { font-weight: normal; - font-size: 13px; -} + font-size: 13px; } .methodType { font-weight: normal; - font-size: 24px; -} + font-size: 24px; } .compactProps .methodType { font-weight: normal; - font-size: 13px; -} + font-size: 13px; } .platform { - background-color: hsl(198, 100%, 87%); + background-color: #bdebff; border-radius: 5px; margin-right: 5px; padding: 0 5px; font-size: 13px; font-weight: normal; - -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -} + -o-user-select: none; + -webkit-user-select: none; + user-select: none; } .color { display: inline-block; @@ -1297,8 +1397,7 @@ div[data-twttr-id] iframe { height: 20px; margin-right: 5px; position: relative; - top: 5px; -} + top: 5px; } .color::before { content: ''; @@ -1308,356 +1407,386 @@ div[data-twttr-id] iframe { left: 0; right: 0; bottom: 0; - border: 1px solid rgba(0, 0, 0, 0.2); -} + border: 1px solid rgba(0, 0, 0, 0.2); } .deprecated { - margin-bottom: 24px; -} + margin-bottom: 24px; } .deprecatedTitle { margin-bottom: 6px; line-height: 18px; font-weight: bold; - color: #ffa500; -} + color: #ffa500; } .deprecatedIcon { width: 18px; height: 18px; margin-right: 8px; - vertical-align: top; -} + vertical-align: top; } .deprecatedMessage { - margin-left: 26px; -} + margin-left: 26px; } #content { - display: none; -} - - -/** Showcase **/ - -.home-showcase-section { - max-width: 800px; - margin: 20px auto 40px auto; - text-align: center; -} - -.home-showcase-section p { - max-width: 540px; - margin: 0 auto; -} - -.footnote { - font-size: 12px; - color: rgba(0, 0, 0, 0.4); -} - -.home-showcase-section .showcase img { - width: 110px; - border-radius: 20px; -} - -.showcaseHeader { - padding-bottom: 15px; - padding-top: 15px; - text-align: center; -} - -.showcase { - margin: 30px auto 30px auto; - width: 100%; - display: inline-block; - text-align: center; - vertical-align: top; -} - -@media only screen - and (min-device-width: 768px) - and (max-device-width: 1024px) { - .showcase { - width: 50%; - } -} - -@media only screen - and (min-device-width: 1024px) { - .showcase { - width: 25%; - } -} - -.showcase h3 { - margin-bottom: 0px; - line-height: 20px; - padding-left: 5px; - padding-right: 5px; - font-size: 16px; -} - -.showcase p { - margin-top: 5px; - font-weight: normal; -} - -.showcase a { - font-weight: bold; -} - -.showcase h3, .showcase p { - color: rgb(72, 72, 72); -} - -.showcase img { - width: 100px; - height: 100px; - border-radius: 20px; -} - -.pinned img { - width: 150px; - border-radius: 20px; -} + display: none; } -table.versions { - width: 60%; -} +table.versions { + width: 60%; } .versions th { - width: 20%; -} + width: 20%; } .versions td, .versions th { - padding: 2px 5px; -} + padding: 2px 5px; } .versions tr:nth-child(2n+1) { - background-color: hsl(198, 100%, 94%); -} + background-color: #e0f6ff; } -@media only screen - and (max-device-width: 1024px) { +@media only screen and (max-device-width: 1024px) { #content { - display: inline; - } - + display: inline; } .container { min-width: 0; - overflow: auto; - } + overflow: auto; } .wrap { - width: auto; - } + width: auto; } .home-getting-started { - width: auto; - } + width: auto; } .inner-content { width: auto; - float: none; - } + float: none; } .marketing-col { margin-left: 0; float: none; margin-bottom: 30px; - text-align: center; - } + text-align: center; } .home-section, .marketing-row { - margin: 0; - } + margin: 0; } .nav-main .nav-site a { - padding: 0 8px; - } + padding: 0 8px; } .nav-main .nav-home { - margin-left: 8px; - } + margin-left: 8px; } .nav-main .wrap { - padding: 0; - } + padding: 0; } .home-divider { - display: none; - } + display: none; } .hero { - padding: 10px 0 30px 0; - } + padding: 10px 0 30px 0; } .prism { padding: 4px 8px; margin-left: -12px; - font-size: 11px; - } + font-size: 11px; } .nav-docs .nav-docs-section { border: none; - padding: 0; - } + padding: 0; } h1 { font-size: 30px; - line-height: 30px; - } + line-height: 30px; } ol { - margin: 0; - } -} - + margin: 0; } } @media only screen and (max-device-width: 840px) { .showcaseSection .inner-content { - width: 100%; - } - + width: 100%; } .helpSection .inner-content { - width: 100%; - } -} + width: 100%; } } -/** Algolia Doc Search **/ +.params, .props { + border-spacing: 0; + border: 0; + border-collapse: collapse; } + +.params .name, .props .name, .name code { + color: #4D4E53; } + +.params td, .params th, .props td, .props th { + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; } + +.params thead tr, .props thead tr { + background-color: #c9eaf7; + font-weight: bold; } + +.params .params thead tr, .props .props thead tr { + background-color: #fff; + font-weight: bold; } + +.params th, .props th { + border-right: 1px solid #aaa; } + +.params thead .last, .props thead .last { + border-right: 1px solid #ddd; } + +.params td.description > div > p:first-child, +.props td.description > div > p:first-child { + margin-top: 0; + padding-top: 0; } + +.params td.description > p:last-child, +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; } + +.edit-page-block { + padding: 5px; + margin-bottom: 40px; + font-size: 12px; + color: #887766; + text-align: center; + background-color: rgba(5, 165, 209, 0.05); } + +.prism { + white-space: pre-wrap; + font-family: 'source-code-pro', Menlo, 'Courier New', Consolas, monospace; + font-size: 13px; + line-height: 20px; + border-left: 4px solid #05A5D1; + padding: 5px 10px; + background-color: rgba(5, 165, 209, 0.05); + overflow: auto; } + +.prism + .prism { + margin-top: 10px; } + +.token.keyword { + color: #1990B8; } + +.token.string, .token.regex { + color: #2F9C0A; } + +.token.boolean, .token.number { + color: #C92C2C; } +.token.comment { + color: #7D8B99; } +/** Algolia Doc Search **/ div.algolia-search-wrapper { display: inline-block; vertical-align: top; - margin-left: 15px; -} + margin-left: 15px; } -.algolia-autocomplete .aa-dropdown-menu { - margin-left: -210px; - margin-top: -4px; -} +@media screen and (max-width: 960px) { + div.algolia-search-wrapper { + display: none; } } + +input#algolia-doc-search { + background: transparent url("../img/search.png") no-repeat 10px center; + background-size: 16px 16px; + font-family: inherit; + padding: 0 10px; + padding-left: 35px; + margin-top: 10px; + height: 30px; + font-size: 16px; + line-height: 20px; + background-color: #2f2f2f; + border-radius: 4px; + color: inherit; + outline: none; + border: none; + width: 170px; + -moz-transition: 0.5s width ease; + -ms-transition: 0.5s width ease; + -o-transition: 0.5s width ease; + -webkit-transition: 0.5s width ease; + transition: 0.5s width ease; } + +input#algolia-doc-search::placeholder { + color: rgba(255, 255, 255, 0.8); } + +input#algolia-doc-search::-moz-placeholder { + color: rgba(255, 255, 255, 0.8); } + +input#algolia-doc-search:-ms-input-placeholder { + color: rgba(255, 255, 255, 0.8); } + +input#algolia-doc-search::-webkit-input-placeholder { + color: rgba(255, 255, 255, 0.8); } + +input#algolia-doc-search:focus { + width: 220px; } + +.algolia-autocomplete { + vertical-align: top; + height: 53px; } + .algolia-autocomplete .aa-dropdown-menu { + margin-left: -210px; + margin-top: -4px; } + +.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { + background-color: #05A5D1; } + +.aa-cursor .algolia-docsearch-suggestion--content { + color: #05A5D1; } + +.aa-cursor .algolia-docsearch-suggestion { + background: #ebf9ff; } + +.algolia-docsearch-suggestion { + border-bottom-color: #e0f6ff; } + .algolia-docsearch-suggestion--category-header { + background-color: #3B3738; } + .algolia-docsearch-suggestion--highlight { + color: #05A5D1; } + .algolia-docsearch-suggestion--subcategory-column { + border-right-color: #e0f6ff; + background-color: #ebf9ff; + color: #3B3738; } + +.hero { + background: #2D2D2D; + padding: 50px 0; + color: #FDF3E7; + font-weight: 300; } + +.hero .text { + font-size: 300%; + text-align: center; } + +.hero .minitext { + font-size: 24px; + text-align: center; } + +.buttons-unit { + margin-top: 40px; + text-align: center; } + +.buttons-unit a { + color: #FA6900; } + +.buttons-unit .button { + font-size: 24px; + background: #05A5D1; + color: #fafafa; } + +.buttons-unit .button:active { + background: #0485A9; } + +.buttons-unit.downloads { + margin: 30px 0; } + +/** Showcase **/ +.home-showcase-section { + max-width: 800px; + margin: 20px auto 100px auto; + text-align: center; } + +.home-showcase-section p { + max-width: 540px; + margin: 0 auto; } + +.footnote { + font-size: 12px; + color: rgba(0, 0, 0, 0.4); } + +.home-showcase-section .showcase img { + width: 110px; + border-radius: 20px; } + +.showcaseHeader { + padding-bottom: 15px; + padding-top: 15px; + text-align: center; } + +.showcase { + margin: 30px auto 30px auto; + width: 100%; + display: inline-block; + text-align: center; + vertical-align: top; } -@media screen and (max-width: 960px) { - div.algolia-search-wrapper { - display: none; - } -} +@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { + .showcase { + width: 50%; } } -input#algolia-doc-search { - background: transparent url('../img/search.png') no-repeat 10px center; - background-size: 16px 16px; +@media only screen and (min-device-width: 1024px) { + .showcase { + width: 25%; } } - padding: 0 10px; - padding-left: 35px; - margin-top: 10px; - height: 30px; - font-size: 16px; +.showcase h3 { + margin-bottom: 0px; line-height: 20px; - background-color: #555; - border-radius: 4px; - color: white; - outline: none; - border: none; - width: 170px; - transition: .5s width ease; - -webkit-transition: .5s width ease; - -moz-transition: .5s width ease; - -o-transition: .5s width ease; -} + padding-left: 5px; + padding-right: 5px; + font-size: 16px; } -input#algolia-doc-search:focus { - width: 220px; -} +.showcase p { + margin-top: 5px; } -.algolia-autocomplete { - vertical-align: top; - height: 53px; -} +.showcase h3, .showcase p { + color: #484848; } -.algolia-docsearch-suggestion--category-header { - background-color: #3B3738; -} -.algolia-docsearch-suggestion--highlight { - color: #05A5D1; -} -.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { - background-color: #05A5D1; -} -.aa-cursor .algolia-docsearch-suggestion--content { - color: #05A5D1; -} -.aa-cursor .algolia-docsearch-suggestion { - background: hsl(198, 100%, 96%); -} -.algolia-docsearch-suggestion { - border-bottom-color: hsl(198, 100%, 94%); -} -.algolia-docsearch-suggestion--subcategory-column { - border-right-color: hsl(198, 100%, 94%); - background-color: hsl(198, 100%, 96%); - color: #3B3738; -} +.showcase img { + width: 100px; + height: 100px; + border-radius: 20px; } -.params, .props { - border-spacing: 0; - border: 0; - border-collapse: collapse; -} +.pinned img { + width: 150px; + border-radius: 20px; } -.params .name, .props .name, .name code { - color: #4D4E53; -} +/** Web player **/ +.web-player > iframe, .web-player > .prism { + display: none; } -.params td, .params th, .props td, .props th { - border: 1px solid #ddd; - margin: 0px; - text-align: left; - vertical-align: top; - padding: 4px 6px; - display: table-cell; -} +.web-player.desktop > iframe { + display: block; } -.params thead tr, .props thead tr { - background-color: hsl(198, 75%, 88%); - font-weight: bold; -} +.web-player.mobile > .prism { + display: block; } -.params .params thead tr, .props .props thead tr { - background-color: #fff; - font-weight: bold; -} +/** Help **/ +.helpSection h2 { + font-size: 24px; } -.params th, .props th { border-right: 1px solid #aaa; } -.params thead .last, .props thead .last { border-right: 1px solid #ddd; } +.help-row { + margin: 50px 0; } -.params td.description > div > p:first-child, -.props td.description > div > p:first-child { - margin-top: 0; - padding-top: 0; -} +.help-row:after { + content: ""; + display: table; + clear: both; } -.params td.description > p:last-child, -.props td.description > p:last-child { - margin-bottom: 0; - padding-bottom: 0; -} +.help-col { + float: left; } -.edit-page-block { - padding: 5px; - margin-bottom: 40px; - font-size: 12px; - color: #887766; - text-align: center; - background-color: rgba(5, 165, 209, 0.05); -} +.help-col p { + font-size: 16px; } -/** Web player **/ +.help-col h3 { + color: #2d2d2d; + font-size: 18px; + line-height: 28px; + font-weight: normal; } -.web-player > iframe, .web-player > .prism { - display: none; -} +@media (min-width: 600px) { + .help-col { + float: left; + margin-left: 40px; + width: 240px; } + .help-col:first-child { + margin-left: 0; } } -.web-player.desktop > iframe { - display: block; -} +.help-list { + padding: 0; + list-style: none; + margin: 1.25em 0 1em 0; } -.web-player.mobile > .prism { - display: block; -} +.entry ul, li { + margin: 0; } -/** Blog **/ +.help-list .help-list-entry { + padding: 16px 0; + border-top: 1px solid #f1eff0; } +/** Blog **/ .entry-header { - margin: 0; -} + margin: 0; } .entry-header h1 { margin: 0; @@ -1669,40 +1798,34 @@ input#algolia-doc-search:focus { margin: 0 0 10px; line-height: 16px; font-size: 14px; -} + line-height: 1; } .entry-header .author { color: #5A6b77; - font-weight: 700; -} + font-weight: 700; } .entry-header .date { - color: rgba(102,99,122,.5); -} + color: rgba(102, 99, 122, 0.5); } .entry-readmore { - margin: 12px 0 0; -} + margin: 12px 0 0; } .entry-share { padding: 36px 0; display: block; - text-align: left; -} + text-align: left; } .entry-excerpt { min-width: 320px; max-width: 640px; margin: 0 auto 40px; padding-bottom: 40px; - border-bottom: 1px solid #EDEDED; -} + border-bottom: 1px solid #EDEDED; } .entry-body { min-width: 320px; max-width: 640px; - margin: 0 auto; -} + margin: 0 auto; } .small-title { font-size: 10px; @@ -1715,34 +1838,28 @@ input#algolia-doc-search:focus { .entry-share .small-title { float: left; - width: 50%; -} + width: 50%; } .social-buttons { padding-top: 7px; float: left; - width: 50%; -} + width: 50%; } article { - margin: 0 0 40px 0; -} + margin: 0 0 40px 0; } article h2 { font-size: 26px; - line-height: 1; -} + line-height: 1; } article li { - line-height: 28px; -} + line-height: 28px; } .author-info { margin-top: 26px; text-align: center; border-bottom: 1px solid #f1f1f1; - padding-bottom: 20px -} + padding-bottom: 20px; } .the-image { position: relative; @@ -1753,12 +1870,10 @@ article li { border-radius: 50%; background-position: center center; background-color: #fff; - background-size: cover; -} + background-size: cover; } .author-image { - position: relative; -} + position: relative; } .author-image:before { content: ""; @@ -1768,51 +1883,43 @@ article li { height: 1px; top: 50%; left: 0; - background-color: #F1F1F1; -} + background-color: #F1F1F1; } .posted-on { font-size: 12px; - color: rgba(102,99,122,.29); + color: rgba(102, 99, 122, 0.29); margin-bottom: 0; - margin-top: 15px; -} + margin-top: 15px; } .name-title { margin-top: 2px; font-size: 22px; font-weight: 400; margin: 3px 0 5px; - color: #5A6B77; -} + color: #5A6B77; } .name-title a { - color: #5A6B77; -} + color: #5A6B77; } .name-title .title { - color: rgba(102,99,122,.44); -} + color: rgba(102, 99, 122, 0.44); } .btn { - background: 0 0; - color: #05A5D1; - min-width: 0; - border: 1px solid #05A5D1; - display: inline-block; - padding: 9px 18px; - border-radius: 4px; - text-align: center; - font-size: 12px; -} + background: 0 0; + color: #05A5D1; + min-width: 0; + border: 1px solid #05A5D1; + display: inline-block; + padding: 9px 18px; + border-radius: 4px; + text-align: center; + font-size: 12px; } .btn a { - text-decoration: none !important; -} + text-decoration: none !important; } .btn:hover { - text-decoration: none !important; -} + text-decoration: none !important; } .video-container { border-radius: 4px; @@ -1824,79 +1931,17 @@ article li { background-position: center center; position: relative; height: 0; - overflow: hidden; -} + overflow: hidden; } @media (min-width: 760px) { .video-container { - height: 345px; - } -} + height: 345px; } } #mc_embed_signup { - clear:left; - width:100%; -} - -/** Help **/ -.helpSection h2 { - font-size: 24px; -} - -.help-row { - margin: 50px 0; -} - -.help-row:after { - content: ""; - display: table; - clear: both; -} - -.help-col { - float: left; -} - -.help-col p { - font-size: 16px; -} - -.help-col h3 { - color: #2d2d2d; - font-size: 18px; - line-height: 28px; - font-weight: normal; -} - -@media (min-width: 600px) { - .help-col { - float: left; - margin-left: 40px; - width: 240px; - } - - .help-col:first-child { - margin-left: 0; - } -} - -.help-list { - padding: 0; - list-style: none; - margin: 1.25em 0 1em 0; -} - -.entry ul, li { - margin: 0; -} - -.help-list .help-list-entry { - padding: 16px 0; - border-top: 1px solid #f1eff0; -} + clear: left; + width: 100%; } /** Footer **/ - footer.nav-footer { box-sizing: border-box; border: none; @@ -1904,22 +1949,22 @@ footer.nav-footer { color: #202020; font-size: 15px; line-height: 24px; - background: #2D2D2D; - box-shadow: inset 0 10px 10px -5px #0d1116; + background: #012129; + box-shadow: inset 0 10px 10px -5px rgba(0, 0, 0, 0.2); padding-top: 2em; padding-bottom: 2em; -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} + -moz-osx-font-smoothing: grayscale; } + footer .sitemap { display: flex; justify-content: space-between; max-width: 1080px; - margin: 0 auto 1em; -} + margin: 0 auto 1em; } + footer .sitemap div { - flex: 1; -} + flex: 1; } + footer .sitemap .nav-home { display: table; margin: -12px 20px 0 0; @@ -1927,79 +1972,71 @@ footer .sitemap .nav-home { width: 50px; height: 50px; opacity: 0.4; - transition: opacity 0.15s ease-in-out; -} + transition: opacity 0.15s ease-in-out; } + footer .sitemap .nav-home:hover, footer .sitemap .nav-home:focus { - opacity: 1.0; -} + opacity: 1.0; } + @media screen and (max-width: 768px) { footer .sitemap { - display: none; - } - + display: none; } footer .newsletter { - display: none; - } - + display: none; } #mc_embed_signup { - display: none; - } -} + display: none; } } footer .sitemap a { color: white; display: table; margin: 2px -10px; - padding: 3px 10px; -} + padding: 3px 10px; } + footer .sitemap a:hover, footer .sitemap a:focus { color: #05A5D1; - text-decoration: none; -} + text-decoration: none; } + footer .sitemap h5 > a:hover, footer .sitemap h5 > a:focus { color: white; - text-decoration: none; -} + text-decoration: none; } + footer .sitemap h5, footer .sitemap h6 { - margin: 0 0 10px; -} + margin: 0 0 10px; } + footer .sitemap h5, footer .sitemap h6, footer .sitemap h5 > a, footer .sitemap h6 > a { color: #05A5D1; -} + font-weight: 900; } + footer .sitemap h5 > a, footer .sitemap h6 > a { - margin: 0 -10px; -} + margin: 0 -10px; } + footer .fbOpenSource { display: block; margin: 1em auto; opacity: 0.4; transition: opacity 0.15s ease-in-out; - width: 170px; -} + width: 170px; } + footer .fbOpenSource:hover { - opacity: 1.0; -} + opacity: 1.0; } + footer .copyright { color: rgba(255, 255, 255, 0.4); - text-align: center; -} + text-align: center; } footer .newsletter { display: flex; justify-content: space-between; max-width: 640px; - margin: 0 auto 1em; -} + margin: 0 auto 1em; } footer .newsletter h5 { color: #05A5D1; - margin: 0 0 10px; -} + margin: 0 0 10px; } diff --git a/website/src/react-native/index.js b/website/src/react-native/index.js index d5d12ad8ad270a..d52b51f4447bab 100644 --- a/website/src/react-native/index.js +++ b/website/src/react-native/index.js @@ -121,7 +121,8 @@ var index = React.createClass({
    @@ -129,7 +130,7 @@ var index = React.createClass({
    -

    Build Native Mobile Apps using JavaScript and React

    +

    Build native mobile apps using JavaScript and React

    React Native lets you build mobile apps using only JavaScript. It uses the same design as React, letting you compose a rich mobile UI from declarative components.

    @@ -156,7 +157,7 @@ class WhyReactNativeIsSoGreat extends Component { }`} -

    A React Native App is a Real Mobile App

    +

    A React Native app is a real mobile app

    With React Native, you don't build a “mobile web app”, an “HTML5 app”, or a “hybrid app”. You build a real mobile app that's indistinguishable from an app built using Objective-C or Java. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React.

    @@ -186,14 +187,14 @@ class AwkwardScrollingImageWithText extends Component { }`} -

    Don't Waste Time Recompiling

    +

    Don't waste time recompiling

    React Native lets you build your app faster. Instead of recompiling, you can reload your app instantly. With hot reloading, you can even run new code while retaining your application state. Give it a try - it's a magical experience.


    -

    Use Native Code When You Need To

    +

    Use native code when you need to

    React Native combines smoothly with components written in Objective-C, Java, or Swift. It's simple to drop down to native code if you need to optimize a few aspects of your application. It's also easy to build part of your app in React Native, and part of your app using native code directly - that's how the Facebook app works.

    @@ -219,9 +220,9 @@ class SomethingFast extends Component {
    -
    +
    diff --git a/website/styles/_blog.scss b/website/styles/_blog.scss new file mode 100644 index 00000000000000..684bd1e4aa3c15 --- /dev/null +++ b/website/styles/_blog.scss @@ -0,0 +1,186 @@ +/** Blog **/ + +.entry-header { + margin: 0; +} + +.entry-header h1 { + margin: 0; + font-size: 33px; + line-height: 36px; + line-height: 1; +} + +.entry-header h4 { + margin: 0 0 10px; + line-height: 16px; + font-size: 14px; + line-height: 1; +} + +.entry-header .author { + color: #5A6b77; + font-weight: 700; +} + +.entry-header .date { + color: rgba(102,99,122,.5); +} + +.entry-readmore { + margin: 12px 0 0; +} + +.entry-share { + padding: 36px 0; + display: block; + text-align: left; +} + +.entry-excerpt { + min-width: 320px; + max-width: 640px; + margin: 0 auto 40px; + padding-bottom: 40px; + border-bottom: 1px solid #EDEDED; +} + +.entry-body { + min-width: 320px; + max-width: 640px; + margin: 0 auto; +} + +.small-title { + font-size: 10px; + color: #66637A; + letter-spacing: .4rem; + text-transform: uppercase; + font-weight: 400; + line-height: 12px; +} + +.entry-share .small-title { + float: left; + width: 50%; +} + +.social-buttons { + padding-top: 7px; + float: left; + width: 50%; +} + +article { + margin: 0 0 40px 0; +} + +article h2 { + font-size: 26px; + line-height: 1; +} + +article li { + line-height: 28px; +} + +.author-info { + margin-top: 26px; + text-align: center; + border-bottom: 1px solid #f1f1f1; + padding-bottom: 20px +} + +.the-image { + position: relative; + display: block; + width: 64px; + height: 64px; + margin: 0 auto; + border-radius: 50%; + background-position: center center; + background-color: #fff; + background-size: cover; +} + +.author-image { + position: relative; +} + +.author-image:before { + content: ""; + display: block; + position: absolute; + width: 100%; + height: 1px; + top: 50%; + left: 0; + background-color: #F1F1F1; +} + +.posted-on { + font-size: 12px; + color: rgba(102,99,122,.29); + margin-bottom: 0; + margin-top: 15px; +} + +.name-title { + margin-top: 2px; + font-size: 22px; + font-weight: 400; + margin: 3px 0 5px; + color: #5A6B77; +} + +.name-title a { + color: #5A6B77; +} + +.name-title .title { + color: rgba(102,99,122,.44); +} + +.btn { + background: 0 0; + color: $color-react-native-blue; + min-width: 0; + border: 1px solid $color-react-native-blue; + display: inline-block; + padding: 9px 18px; + border-radius: 4px; + text-align: center; + font-size: 12px; +} + +.btn a { + text-decoration: none !important; +} + +.btn:hover { + text-decoration: none !important; +} + +.video-container { + border-radius: 4px; + background-clip: padding-box; + margin: 0 0 18px; + height: 180px; + width: 100%; + background-size: cover; + background-position: center center; + position: relative; + height: 0; + overflow: hidden; +} + +@media (min-width: 760px) { + .video-container { + height: 345px; + } +} + +#mc_embed_signup { + clear:left; + width:100%; +} diff --git a/website/styles/_footer.scss b/website/styles/_footer.scss new file mode 100644 index 00000000000000..4d3bfe2bb9c325 --- /dev/null +++ b/website/styles/_footer.scss @@ -0,0 +1,109 @@ +/** Footer **/ + +footer.nav-footer { + box-sizing: border-box; + border: none; + font-weight: 300; + color: #202020; + font-size: 15px; + line-height: 24px; + background: #012129; + box-shadow: inset 0 10px 10px -5px rgba(0,0,0,0.2); + padding-top: 2em; + padding-bottom: 2em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +footer .sitemap { + display: flex; + justify-content: space-between; + max-width: 1080px; + margin: 0 auto 1em; +} +footer .sitemap div { + flex: 1; +} +footer .sitemap .nav-home { + display: table; + margin: -12px 20px 0 0; + padding: 10px; + width: 50px; + height: 50px; + opacity: 0.4; + transition: opacity 0.15s ease-in-out; +} +footer .sitemap .nav-home:hover, +footer .sitemap .nav-home:focus { + opacity: 1.0; +} +@media screen and (max-width: 768px) { + footer .sitemap { + display: none; + } + + footer .newsletter { + display: none; + } + + #mc_embed_signup { + display: none; + } +} + +footer .sitemap a { + color: white; + display: table; + margin: 2px -10px; + padding: 3px 10px; +} +footer .sitemap a:hover, +footer .sitemap a:focus { + color: $color-react-native-blue; + text-decoration: none; +} +footer .sitemap h5 > a:hover, +footer .sitemap h5 > a:focus { + color: white; + text-decoration: none; +} +footer .sitemap h5, +footer .sitemap h6 { + margin: 0 0 10px; +} +footer .sitemap h5, +footer .sitemap h6, +footer .sitemap h5 > a, +footer .sitemap h6 > a { + color: $color-react-native-blue; + font-weight: 900; +} +footer .sitemap h5 > a, +footer .sitemap h6 > a { + margin: 0 -10px; +} +footer .fbOpenSource { + display: block; + margin: 1em auto; + opacity: 0.4; + transition: opacity 0.15s ease-in-out; + width: 170px; +} +footer .fbOpenSource:hover { + opacity: 1.0; +} +footer .copyright { + color: rgba(255, 255, 255, 0.4); + text-align: center; +} + +footer .newsletter { + display: flex; + justify-content: space-between; + max-width: 640px; + margin: 0 auto 1em; +} + +footer .newsletter h5 { + color: $color-react-native-blue; + margin: 0 0 10px; +} diff --git a/website/styles/_help.scss b/website/styles/_help.scss new file mode 100644 index 00000000000000..21dd0c990aba13 --- /dev/null +++ b/website/styles/_help.scss @@ -0,0 +1,56 @@ +/** Help **/ +.helpSection h2 { + font-size: 24px; +} + +.help-row { + margin: 50px 0; +} + +.help-row:after { + content: ""; + display: table; + clear: both; +} + +.help-col { + float: left; +} + +.help-col p { + font-size: 16px; +} + +.help-col h3 { + color: #2d2d2d; + font-size: 18px; + line-height: 28px; + font-weight: normal; +} + +@media (min-width: 600px) { + .help-col { + float: left; + margin-left: 40px; + width: 240px; + } + + .help-col:first-child { + margin-left: 0; + } +} + +.help-list { + padding: 0; + list-style: none; + margin: 1.25em 0 1em 0; +} + +.entry ul, li { + margin: 0; +} + +.help-list .help-list-entry { + padding: 16px 0; + border-top: 1px solid #f1eff0; +} diff --git a/website/styles/_hero.scss b/website/styles/_hero.scss new file mode 100644 index 00000000000000..525564cbce020b --- /dev/null +++ b/website/styles/_hero.scss @@ -0,0 +1,39 @@ +.hero { + background: $color-hero-bg; + padding: 50px 0; + color: #FDF3E7; + font-weight: 300; +} + +.hero .text { + font-size: 300%; + text-align: center; +} + +.hero .minitext { + font-size: 24px; + text-align: center; +} + +.buttons-unit { + margin-top: 40px; + text-align: center; +} + +.buttons-unit a { + color: #FA6900; +} + +.buttons-unit .button { + font-size: 24px; + background: $color-react-native-blue; + color: #fafafa; +} + +.buttons-unit .button:active { + background: #0485A9; +} + +.buttons-unit.downloads { + margin: 30px 0; +} diff --git a/website/styles/_showcase.scss b/website/styles/_showcase.scss new file mode 100644 index 00000000000000..d97939d126c360 --- /dev/null +++ b/website/styles/_showcase.scss @@ -0,0 +1,82 @@ +/** Showcase **/ + +.home-showcase-section { + max-width: 800px; + margin: 20px auto 100px auto; + text-align: center; +} + + +.home-showcase-section p { + max-width: 540px; + margin: 0 auto; +} + +.footnote { + font-size: 12px; + color: rgba(0, 0, 0, 0.4); +} + +.home-showcase-section .showcase img { + width: 110px; + border-radius: 20px; +} + +.showcaseHeader { + padding-bottom: 15px; + padding-top: 15px; + text-align: center; +} + +.showcase { + margin: 30px auto 30px auto; + width: 100%; + display: inline-block; + text-align: center; + vertical-align: top; +} + +@media only screen + and (min-device-width: 768px) + and (max-device-width: 1024px) { + .showcase { + width: 50%; + } +} + +@media only screen + and (min-device-width: 1024px) { + .showcase { + width: 25%; + } +} + +.showcase h3 { + margin-bottom: 0px; + line-height: 20px; + padding-left: 5px; + padding-right: 5px; + font-size: 16px; +} + +.showcase p { + margin-top: 5px; +} + +.showcase a { +} + +.showcase h3, .showcase p { + color: rgb(72, 72, 72); +} + +.showcase img { + width: 100px; + height: 100px; + border-radius: 20px; +} + +.pinned img { + width: 150px; + border-radius: 20px; +} diff --git a/website/styles/_webplayer.scss b/website/styles/_webplayer.scss new file mode 100644 index 00000000000000..d7001e314b9a61 --- /dev/null +++ b/website/styles/_webplayer.scss @@ -0,0 +1,13 @@ +/** Web player **/ + +.web-player > iframe, .web-player > .prism { + display: none; +} + +.web-player.desktop > iframe { + display: block; +} + +.web-player.mobile > .prism { + display: block; +} diff --git a/website/styles/lib/multisite/_mixins.scss b/website/styles/lib/multisite/_mixins.scss new file mode 100644 index 00000000000000..89eaa5a09733e4 --- /dev/null +++ b/website/styles/lib/multisite/_mixins.scss @@ -0,0 +1,7 @@ +@mixin vendorize($property, $value) { + -moz-#{$property}: $value; + -ms-#{$property}: $value; + -o-#{$property}: $value; + -webkit-#{$property}: $value; + #{$property}: $value; +} diff --git a/website/styles/lib/multisite/_variables.scss b/website/styles/lib/multisite/_variables.scss new file mode 100644 index 00000000000000..ea58479750f3e5 --- /dev/null +++ b/website/styles/lib/multisite/_variables.scss @@ -0,0 +1,25 @@ +$color-react-native-blue: #05A5D1 !default; +$color-react-native-blue-dark: #0484A7 !default; +$color-react-native-blue-darker: #025268 !default; +$color-react-native-gray: #3B3738 !default; +$color-react-native-gray-dark: #2D2D2D !default; +$color-react-native-gray-darkest: #222 !default; +$color-react-native-blue-light: #F5FCFF !default; + +$color-nav-bg: $color-react-native-gray-darkest; +$color-hero-bg: $color-react-native-gray-dark; +$color-body-bg: $color-react-native-blue-light; +$color-sidenav-header-bg: $color-react-native-gray-darkest; +$color-sidenav-contents-bg: rgba($color-react-native-gray, 0.05); +$color-sidenav-title: $color-react-native-blue-darker; +$color-sidenav-title-active: $color-react-native-blue; +$color-h1: $color-react-native-blue-darker; + +$color-reference-title: $color-react-native-blue-darker; + +$color-algolia-search: lighten($color-nav-bg,5%); + +$font-proxima-nova: proxima-nova; +$font-helvetica-neue: "Helvetica Neue"; + +$font-default: $font-proxima-nova, $font-helvetica-neue, Helvetica, Arial, sans-serif; diff --git a/website/styles/lib/vendor/_algolia.scss b/website/styles/lib/vendor/_algolia.scss new file mode 100644 index 00000000000000..da68b0f13692c7 --- /dev/null +++ b/website/styles/lib/vendor/_algolia.scss @@ -0,0 +1,86 @@ +/** Algolia Doc Search **/ + +div.algolia-search-wrapper { + display: inline-block; + vertical-align: top; + margin-left: 15px; +} + +@media screen and (max-width: 960px) { + div.algolia-search-wrapper { + display: none; + } +} + +input#algolia-doc-search { + background: transparent url('../img/search.png') no-repeat 10px center; + background-size: 16px 16px; + font-family: inherit; + padding: 0 10px; + padding-left: 35px; + margin-top: 10px; + height: 30px; + font-size: 16px; + line-height: 20px; + background-color: $color-algolia-search; + border-radius: 4px; + color: inherit; + outline: none; + border: none; + width: 170px; + @include vendorize(transition, .5s width ease); +} + +input#algolia-doc-search::placeholder { + color: rgba(white, 0.8); +} +input#algolia-doc-search::-moz-placeholder { + color: rgba(white, 0.8); +} +input#algolia-doc-search:-ms-input-placeholder { + color: rgba(white, 0.8); +} +input#algolia-doc-search::-webkit-input-placeholder { + color: rgba(white, 0.8); +} + +input#algolia-doc-search:focus { + width: 220px; +} + +.algolia-autocomplete { + vertical-align: top; + height: 53px; + + .aa-dropdown-menu { + margin-left: -210px; + margin-top: -4px; + } +} +.algolia-docsearch-suggestion--category-header .algolia-docsearch-suggestion--highlight { + background-color: $color-react-native-blue; +} +.aa-cursor .algolia-docsearch-suggestion--content { + color: $color-react-native-blue; +} +.aa-cursor .algolia-docsearch-suggestion { + background: hsl(198, 100%, 96%); +} +.algolia-docsearch-suggestion { + border-bottom-color: hsl(198, 100%, 94%); + + &--category-header { + background-color: #3B3738; + } + + &--highlight { + color: $color-react-native-blue; + } + + &--subcategory-column { + + border-right-color: hsl(198, 100%, 94%); + background-color: hsl(198, 100%, 96%); + color: #3B3738; + } +} diff --git a/website/styles/lib/vendor/_prism.scss b/website/styles/lib/vendor/_prism.scss new file mode 100644 index 00000000000000..a70a15e94c6ab0 --- /dev/null +++ b/website/styles/lib/vendor/_prism.scss @@ -0,0 +1,30 @@ +.prism { + white-space: pre-wrap; + font-family: 'source-code-pro', Menlo, 'Courier New', Consolas, monospace; + font-size: 13px; + line-height: 20px; + border-left: 4px solid $color-react-native-blue; + padding: 5px 10px; + background-color: rgba(5, 165, 209, 0.05); + overflow: auto; +} + +.prism + .prism { + margin-top: 10px; +} + +.token.keyword { + color: #1990B8; +} + +.token.string, .token.regex { + color: #2F9C0A; +} + +.token.boolean, .token.number { + color: #C92C2C; +} + +.token.comment { + color: #7D8B99; +} diff --git a/website/styles/lib/vendor/normalize.css b/website/styles/lib/vendor/normalize.css new file mode 100644 index 00000000000000..f1644731cf10a1 --- /dev/null +++ b/website/styles/lib/vendor/normalize.css @@ -0,0 +1,461 @@ +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +html { + font-family: sans-serif; /* 1 */ + line-height: 1.15; /* 2 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/website/styles/react-native.scss b/website/styles/react-native.scss new file mode 100644 index 00000000000000..a8eb23fcf0b6a5 --- /dev/null +++ b/website/styles/react-native.scss @@ -0,0 +1,1423 @@ +@import "lib/vendor/normalize"; +@import "lib/multisite/variables"; +@import "lib/multisite/mixins"; + +html { + font-family: $font-default; + color: #484848; + line-height: 1.28; +} + +body { + background-color: $color-body-bg; +} + +* { + @include vendorize(box-sizing, border-box); + border: none; + margin: 0; + padding: 0; +} + +p { + margin: 0 0 16px; + line-height: 1.4; + } + +em { + font-style: italic; +} + +h1, h2, h3, h4, h5, h6 { + margin: 10px 0; + font-family: inherit; + font-weight: 400; + line-height: 20px; + color: $color-h1; + text-rendering: optimizelegibility; +} + +h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + font-weight: normal; + color: #7b7b7b; +} + +h1, h2, h3, h4 { + line-height: 40px; +} + +h1 { + font-size: 39px; +} + +h2 { + font-size: 31px; +} + +h3 { + font-size: 23px; +} + +h4 { + font-size: 17px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11px; +} + +h1 small { + font-size: 24px; +} + +h2 small { + font-size: 18px; +} + +h3 small { + font-size: 16px; +} + +h4 small { + font-size: 14px; +} + +img { + max-width: 100%; + height: auto; +} + +ul, ol { + margin: 0 0 10px 25px; + padding: 0; +} + +ul ul, ul ol, ol ol, ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +a { + color: $color-react-native-blue; + text-decoration: none; +} + +a:hover, a:focus { + color: darken($color-react-native-blue, 10%); + text-decoration: underline; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.center { + text-align: center; +} + +html * { + color-profile: sRGB; + rendering-intent: auto; +} + +.subHeader { + font-size: 21px; + font-weight: 300; + line-height: 30px; + margin-bottom: 10px; +} + +.example-container { + position: relative; +} + +.embedded-simulator, .embedded-simulator * { + box-sizing: border-box; +} + +.embedded-simulator p { + text-align: center; + color: #999; +} + +.embedded-simulator { + width: 210px; + position: absolute; + right: -200px; + top: 0; +} + +@media screen and (max-width: 680px) { + .embedded-simulator { + position: relative; + right: 0; + } +} + +.side-by-side { + overflow: hidden; +} + +.side-by-side > div { + width: 460; + margin-left: 0; + float: left; +} + +.left { + float: left; +} + +.right { + float: right; +} + +.container { + padding-top: 50px; + min-width: 1160px; +} + +.wrap { + max-width: 1260px; + margin: 0 auto; + padding: 0 20px; +} + +.skinnyWrap { + width: 690px; + margin-left: auto; + margin-right: auto; + padding-left: 20px; + padding-right: 20px; +} + +hr { + height: 0; + border-top: 1px solid #ccc; + border-bottom: 1px solid #eee; +} + +ul, li { + margin-left: 20px; +} + +h1 .anchor, h2 .anchor, h3 .anchor, h4 .anchor, h5 .anchor, h6 .anchor { + margin-top: -50px; + position: absolute; +} + +h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-link, h5:hover .hash-link, h6:hover .hash-link { + visibility: visible; +} + +.hash-link { + color: #aaa; + visibility: hidden; +} + +.nav-main { + *zoom: 1; + background: $color-nav-bg; + color: #fafafa; + position: fixed; + top: 0; + min-height: 50px; + width: 100%; + z-index: 100; + box-shadow: 0 0 5px rgba(black, 0.5); +} + +.nav-main:before, .nav-main:after { + content: " "; + display: table; +} + +.nav-main:after { + clear: both; +} + +.nav-main a { + color: #e9e9e9; + text-decoration: none; +} + +.nav-main .nav-site-wrapper { + display: inline; +} + +.nav-main .nav-site-internal { + margin: 0 0 0 20px; +} + +.nav-main .nav-site-external { + float: right; + margin: 0 12px 0 0; +} + +.nav-main .nav-site li { + margin: 0; +} + +.nav-main .nav-site a { + box-sizing: content-box; + padding: 0 10px; + line-height: 50px; + display: inline-block; + height: 50px; +} + +.nav-site-wrapper a:hover { + color: #fff; +} + +.nav-site-wrapper a.active { + color: #fff; + border-bottom: 3px solid $color-react-native-blue; + background-color: $color-react-native-gray-dark; +} + +.nav-main .nav-home { + font-size: 24px; + font-weight: 300; + line-height: 50px; +} + +.nav-home img { + vertical-align: -9px; + margin-right: 8px; + margin-left: 1px; + width: 34px; +} + +.nav-main a.nav-home { + color: white; +} + +.nav-main ul { + display: inline-block; + vertical-align: top; +} + +.nav-main li { + display: inline; +} + +.nav-main a.nav-version { + font-size: 16px; + font-weight: 300; + margin-left: 8px; + text-decoration: underline; +} + +@media screen and (max-width: 680px) { + .nav-main .nav-home { + font-size: 20px; + } + + .nav-main a.nav-version { + font-size: 14px; + } + + .nav-main .nav-site-wrapper { + display: block; + overflow: hidden; + } + + .nav-main ul { + display: -webkit-flex; + display: flex; + overflow: hidden; + } + + .nav-main li { + -webkit-flex: 1; + flex: 1; + } + + .nav-main .nav-site li a { + width: 100%; + padding: 0; + text-align: center; + font-size: 14px; + } + + .nav-main .nav-site a.active { + color: $color-sidenav-title-active; + font-weight: 300; + background-color: transparent; + } + + .nav-main .nav-site-internal { + margin: 0; + width: 100%; + } + + .nav-main .nav-site-external { + position: absolute; + top: 0; + right: 0; + float: none; + } + + .nav-main .nav-site-external li a { + padding: 0 6px; + } +} + +.nav-docs { + font-size: 14px; + float: left; + width: 210px; + margin: 5px 48px 0 0; + + ul { + list-style: none; + margin: 0; + margin-left: 1px; + + ul { + margin-left: 20px; + } + } + + li { + margin: 0; + } + + a:hover { + text-decoration: none; + color: $color-react-native-blue-darker; + } + + a.active { + color: $color-sidenav-title-active; + font-weight: bold; + } +} + +.nav-docs-section { + background-color: $color-sidenav-contents-bg; + padding-bottom: 0; + + h3 { + color: white; + font-size: 16px; + font-weight: 400; + line-height: 20px; + margin-top: 12px; + margin-bottom: 5px; + padding: 10px; + background-color: $color-sidenav-header-bg; + text-transform: capitalize; + } + + ul { + display: block; + padding-bottom: 10px; + padding-top: 10px; + } + + a { + color: $color-sidenav-title; + display: block; + margin: 2px 10px 5px; + } + + .nav-docs-section:first-child h3 { + margin-top: 0; + } + + .nav-docs-section:first-child { + padding-top: 0; + border-top: 0; + } + + .nav-docs-section:last-child { + padding-bottom: 0; + border-bottom: 0; + } +} + +@media only screen and (max-device-width: 1024px) { + @-webkit-keyframes slide-in { + 0% { top: -30px; opacity: 0; } + 100% { top: 0; opacity: 1; } + } + @-moz-keyframes slide-in { + 0% { top: -30px; opacity: 0; } + 100% { top: 0; opacity: 1; } + } + @-o-keyframes slide-in { + 0% { top: -30px; opacity: 0; } + 100% { top: 0; opacity: 1; } + } + @keyframes slide-in { + 0% { top: -30px; opacity: 0; } + 100% { top: 0; opacity: 1; } + } + + .nav-docs { + position: fixed; + z-index: 90; + top: -100%; + left: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 53px 0 0 0; + background: #3B3738; + } + + .nav-docs-viewport { + border-top: 1px solid rgb(5, 165, 209); + padding: 25px; + overflow: scroll; + -webkit-overflow-scrolling: touch; + position: relative; + width: 100%; + height: 100%; + } + + /* Active state */ + .nav-docs.in { + top: 0; + @include vendorize(animation, slide-in 0.3s forwards); + } + + .nav-docs * { + -webkit-font-smoothing: antialiased; + } + + .nav-docs-section + .nav-docs-section { + margin-top: 50px; + } + + .nav-docs-section li { + margin: 5px 0; + } + + .nav-docs-section h3, + .nav-docs-section a { + color: white; + } + + .nav-docs-section h3 { + border-bottom: 1px solid white; + margin-bottom: 10px; + opacity: 0.3; + } + + .nav-docs-section a { + margin-right: 25px; + font-size: 120%; + padding: 5px 0; + } + + .nav-docs-section a.active { + border-bottom-style: solid; + border-bottom-width: 1px; + color: $color-sidenav-title-active; + } +} + +/** + * Multicolumn layout for phone (landscape only) & tablet (regardless its screen orientation)/ + */ +@media only screen and (min-device-width : 375px) and (max-device-width : 1024px) { + .nav-docs-section ul { + display: flex; + flex-wrap: wrap; + } + + .nav-docs-section li { + width: 100%; + } +} + +/* 2 columns layout */ +@media + /*Phone, landscape screen orientation*/ + only screen and (min-device-width : 375px) and (max-device-width : 1024px) and (orientation : landscape), + /*Tablet, portrait screen orientation*/ + only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) { + .nav-docs-section li { + width: 50%; + } +} + +/* 3 columns layout on tablet (landscape screen orientation) */ +@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) { + .nav-docs-section li { + width: 33%; + } +} + +.home-section { + margin: 50px 0; +} + +.home-section ol { + margin-left: 0; +} + +.home-divider { + border-top-color: #bbb; + margin: 0 auto; + width: 400px; +} + +.marketing-row { + *zoom: 1; + margin: 50px 0; +} + +.marketing-row:before, .marketing-row:after { + content: " "; + display: table; +} + +.marketing-row:after { + clear: both; +} + +.marketing-col { + float: left; + margin-left: 40px; + width: 280px; +} + +.marketing-col h3 { + color: #2d2d2d; + font-size: 24px; + font-weight: normal; + text-transform: uppercase; +} + +.marketing-col p { + font-size: 16px; +} + +.marketing-col:first-child { + margin-left: 0; +} + +.tutorial-mock { + text-align: center; +} +.tutorial-mock img { + border: 1px solid #ccc; + box-shadow: 5px 5px 5px #888888; +} + +#examples h3, .home-presentation h3 { + color: #2d2d2d; + font-size: 24px; + font-weight: normal; + margin-bottom: 5px; +} + +#examples p { + margin: 0 0 25px 0; + max-width: 600px; +} + +#examples .example { + margin-top: 60px; +} + +#examples #todoExample { + font-size: 14px; +} + +#examples #todoExample ul { + list-style-type: square; + margin: 0 0 10px 0; +} + +#examples #todoExample input { + border: 1px solid #ccc; + font-size: 14px; + padding: 3px; + width: 150px; +} + +#examples #todoExample button { + font-size: 14px; + margin-left: 5px; + padding: 4px 10px; +} + +#examples #markdownExample textarea { + border: 1px solid #ccc; + font-size: 14px; + margin-bottom: 10px; + padding: 5px; +} + +.home-get-started-section { + margin-bottom: 60px; +} + +.docs-nextprev { + *zoom: 1; +} + +.docs-nextprev:before, .docs-nextprev:after { + content: " "; + display: table; +} + +.docs-nextprev:after { + clear: both; +} + +.docs-prev { + float: left; +} + +.docs-next { + float: right; +} + +section.black content { + padding-bottom: 18px; +} + +.blogContent { + *zoom: 1; + padding-top: 20px; +} + +.blogContent:before, .blogContent:after { + content: " "; + display: table; +} + +.blogContent:after { + clear: both; +} + +.blogContent blockquote { + padding: 5px 15px; + margin: 20px 0; + background-color: #f8f5ec; + border-left: 5px solid #f7ebc6; +} + +.documentationContent { + *zoom: 1; + padding-top: 20px; + padding-bottom: 80px; +} + +.documentationContent:before, .documentationContent:after { + content: " "; + display: table; +} + +.documentationContent:after { + clear: both; +} + +.documentationContent .subHeader { + font-size: 24px; +} + +h2 { + margin-top: 30px; +} + +.documentationContent blockquote { + padding: 15px 30px 15px 15px; + margin: 20px 0; + background-color: rgba(248, 245, 236, 0.1); + border-left: 5px solid rgba(191, 87, 73, 0.2); +} + +.documentationContent blockquote h4 { + margin-top: 0; +} + +.documentationContent blockquote p { + margin-bottom: 0; +} + +.documentationContent blockquote p:first-child { + font-size: 14px; + line-height: 20px; + margin-top: 0; + text-rendering: optimizelegibility; +} + +.docs-prevnext { + min-width: 320px; + max-width: 640px; + margin: 0 auto 40px; + padding-bottom: 20px; +} + +.button { + background: -webkit-linear-gradient( #9a9a9a, #646464); + background: linear-gradient( #9a9a9a, #646464); + border-radius: 4px; + padding: 8px 16px; + font-size: 18px; + font-weight: 300; + margin: 0 12px; + display: inline-block; + color: #fafafa; + text-decoration: none; + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); +} + +.button:hover { + text-decoration: none; +} + +.button:active { + box-shadow: none; +} + +.hero .button { + box-shadow: 1px 3px 3px rgba(0, 0, 0, 0.3); +} + +.button.blue { + background: -webkit-linear-gradient( #77a3d2, #4783c2); + background: linear-gradient( #77a3d2, #4783c2); +} + +.row { + padding-bottom: 4px; +} + +.row .span4 { + width: 33.33%; + display: table-cell; +} + +.row .span8 { + width: 66.66%; + display: table-cell; +} + +.row .span6 { + width: 50%; + display: table-cell; +} + +p { + margin: 10px 0; +} + +.highlight { + padding: 10px; + margin-bottom: 20px; +} + +figure { + text-align: center; +} + +.inner-content { + float: left; + width: 650px; +} + +.showcaseSection .inner-content { + width: 800px; +} + +.helpSection .inner-content { + width: 800px; +} + +.nosidebar .inner-content { + float: none; + margin: 0 auto; +} + +.post-list-item+.post-list-item { + margin-top: 60px; +} + +small code, li code, p code { + color: #555; + background-color: rgba(0, 0, 0, 0.04); + padding: 1px 3px; +} + +.playground { + *zoom: 1; +} + +.playground:before, .playground:after { + content: " "; + display: table; +} + +.playground:after { + clear: both; +} + +.playground-tab { + border-bottom: none !important; + border-radius: 3px 3px 0 0; + padding: 6px 8px; + font-size: 12px; + font-weight: bold; + color: #c2c0bc; + background-color: #f1ede4; + display: inline-block; + cursor: pointer; +} + +.playgroundCode, .playground-tab, .playgroundPreview { + border: 1px solid rgba(16, 16, 16, 0.1); +} + +.playground-tab-active { + color: #222; +} + +.playgroundCode { + border-radius: 0 3px 3px 3px; + float: left; + overflow: hidden; + width: 600px; +} + +.playgroundPreview { + background-color: white; + border-radius: 3px; + float: right; + padding: 15px 20px; + width: 280px; +} + +.playgroundError { + color: #c5695c; + font-size: 15px; +} + +.MarkdownEditor textarea { + width: 100%; + height: 100px; +} + +.hll { + background-color: #f7ebc6; + border-left: 5px solid #f7d87c; + display: block; + margin-left: -14px; + margin-right: -14px; + padding-left: 9px; +} + +.highlight .javascript .err { + background-color: transparent; + color: inherit; +} + +.highlight { + position: relative; + margin-bottom: 14px; + padding: 30px 14px 14px; + border: none; + border-radius: 0; + overflow: auto; +} + +.highlight pre { + padding: 0; + margin-top: 0; + margin-bottom: 0; + background-color: transparent; + border: 0; +} + +.highlight pre code { + background: none; + font-size: inherit; + padding: 0; +} + +.highlight pre .lineno { + display: inline-block; + width: 22px; + padding-right: 5px; + margin-right: 10px; + color: #bebec5; + text-align: right; +} + +.highlight:after { + position: absolute; + top: 0; + right: 0; + left: 0; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + color: #c2c0bc; + background-color: #f1ede4; + content: "Code"; +} + +.downloadCenter { + text-align: center; + margin-top: 20px; + margin-bottom: 25px; +} + +.downloadSection:hover { + text-decoration: none !important; +} + +/* Modal */ +.modal-backdrop { + background: rgba(0,0,0,.4); + display: none; + height: 100%; + left: 0; + overflow: auto; + position: fixed; + top: 0; + width: 100%; + z-index: 9900; +} + +.modal { + background: #F6F6F6; + bottom: 0; + box-shadow: 2px 2px 4px 0 rgba(0,0,0,.11); + display: none; + border-radius: 10px; + height: 95%; + left: 0; + margin: auto; + max-height: 648px; + max-width: 460px; + overflow: auto; + position: fixed; + right: 0; + top: 0; + width: 80%; + z-index: 9999; +} + +.modal-open { display: block; } + +.modal-content { + padding: 40px 24px 8px 24px; + position: relative; +} + +.modal-content iframe { margin: 0 auto; } + +.modal-button-open { + cursor: pointer; + text-align: center; +} + +.modal-button-open-img { + height: 358px; +} + +.modal-button-open-img:hover img { opacity: 0.9; } + +.modal-button-close { + background: transparent; + border-radius: 0 0 0 4px; + border: 0; + color: #555; + font-size: 1.2em; + font-weight: bolder; + line-height: 32px; + margin: 0; + padding: 0 12px; + position: absolute; + right: 0; + top: 0; +} + +.modal-button-close:active, +.modal-button-close:focus, +.modal-button-close:hover { + background: #EAF8FD; + outline: none; +} + +@media screen and (max-width: 680px) { + .container { + padding-top: 100px; + } + + .nav-docs { + padding-top: 103px; + } +} + +.post { + margin-bottom: 30px; +} + +.pagination { + margin-bottom: 30px; + width: 100%; + overflow: hidden; +} + +.pagination .next { + float: right; +} + +div[data-twttr-id] iframe { + margin: 10px auto !important; +} + +.three-column { + *zoom: 1; +} + +.three-column:before, .three-column:after { + content: " "; + display: table; +} + +.three-column:after { + clear: both; +} + +.three-column>ul { + float: left; + margin-left: 30px; + width: 190px; +} + +.three-column > ul:first-child { + margin-left: 20px; +} + +.home-why { + margin-top: 25px; +} + +.home-why h3 { + text-align: center; +} + +.home-why .blurb { + margin-bottom: 20px; + text-align: center; +} + +.home-why .list { + margin: 0 auto; + max-width: 460px; +} + +.home-getting-started { + width: 500px; + margin: 20px auto 40px auto; +} + +.home-getting-started h3 { + text-align: center; +} + + +.props { + background-color: hsl(198, 100%, 96%); +} + +.compactProps { + border-left: 2px solid hsl(198, 100%, 94%); + margin-left: 20px; + padding-left: 5px; +} + +.props > .prop:nth-child(2n) { + background-color: hsl(198, 100%, 94%); +} + +.propTitle { + font-weight: bold; + font-size: 16px; +} + +.compactProps .propTitle { + font-size: 14px; + margin-bottom: 0; + margin-top: 0; +} + +.compactProps .propTitle div { + font-weight: normal; + margin-left: 20px; +} + +.methodTitle { + font-weight: bold; + font-size: 24px; + color: $color-reference-title; +} + +.compactProps .methodTitle { + font-size: 14px; + margin-bottom: 0; + margin-top: 0; +} + +.compactProps .methodTitle div { + font-weight: normal; + margin-left: 20px; +} + +.prop { + padding: 5px 10px; +} + +.compactProps .prop { + padding: 3px 10px; +} + +.propType { + font-weight: normal; + font-size: 15px; + white-space: pre-wrap; +} + +.compactProps .propType { + font-weight: normal; + font-size: 13px; +} + +.methodType { + font-weight: normal; + font-size: 24px; +} + +.compactProps .methodType { + font-weight: normal; + font-size: 13px; +} + +.platform { + background-color: hsl(198, 100%, 87%); + border-radius: 5px; + margin-right: 5px; + padding: 0 5px; + font-size: 13px; + font-weight: normal; + @include vendorize(user-select, none); +} + +.color { + display: inline-block; + width: 20px; + height: 20px; + margin-right: 5px; + position: relative; + top: 5px; +} + +.color::before { + content: ''; + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border: 1px solid rgba(0, 0, 0, 0.2); +} + +.deprecated { + margin-bottom: 24px; +} + +.deprecatedTitle { + margin-bottom: 6px; + line-height: 18px; + font-weight: bold; + color: #ffa500; +} + +.deprecatedIcon { + width: 18px; + height: 18px; + margin-right: 8px; + vertical-align: top; +} + +.deprecatedMessage { + margin-left: 26px; +} + +#content { + display: none; +} + + + + +table.versions { + width: 60%; +} + +.versions th { + width: 20%; +} + +.versions td, .versions th { + padding: 2px 5px; +} + +.versions tr:nth-child(2n+1) { + background-color: hsl(198, 100%, 94%); +} + +@media only screen + and (max-device-width: 1024px) { + #content { + display: inline; + } + + .container { + min-width: 0; + overflow: auto; + } + .wrap { + width: auto; + } + .home-getting-started { + width: auto; + } + .inner-content { + width: auto; + float: none; + } + .marketing-col { + margin-left: 0; + float: none; + margin-bottom: 30px; + text-align: center; + } + .home-section, .marketing-row { + margin: 0; + } + .nav-main .nav-site a { + padding: 0 8px; + } + .nav-main .nav-home { + margin-left: 8px; + } + .nav-main .wrap { + padding: 0; + } + .home-divider { + display: none; + } + .hero { + padding: 10px 0 30px 0; + } + .prism { + padding: 4px 8px; + margin-left: -12px; + font-size: 11px; + } + .nav-docs .nav-docs-section { + border: none; + padding: 0; + } + h1 { + font-size: 30px; + line-height: 30px; + } + ol { + margin: 0; + } +} + +@media only screen and (max-device-width: 840px) { + .showcaseSection .inner-content { + width: 100%; + } + + .helpSection .inner-content { + width: 100%; + } +} + +.params, .props { + border-spacing: 0; + border: 0; + border-collapse: collapse; +} + +.params .name, .props .name, .name code { + color: #4D4E53; +} + +.params td, .params th, .props td, .props th { + border: 1px solid #ddd; + margin: 0px; + text-align: left; + vertical-align: top; + padding: 4px 6px; + display: table-cell; +} + +.params thead tr, .props thead tr { + background-color: hsl(198, 75%, 88%); + font-weight: bold; +} + +.params .params thead tr, .props .props thead tr { + background-color: #fff; + font-weight: bold; +} + +.params th, .props th { border-right: 1px solid #aaa; } +.params thead .last, .props thead .last { border-right: 1px solid #ddd; } + +.params td.description > div > p:first-child, +.props td.description > div > p:first-child { + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child { + margin-bottom: 0; + padding-bottom: 0; +} + +.edit-page-block { + padding: 5px; + margin-bottom: 40px; + font-size: 12px; + color: #887766; + text-align: center; + background-color: rgba(5, 165, 209, 0.05); +} + +@import "lib/vendor/prism"; +@import "lib/vendor/algolia"; +@import "hero"; +@import "showcase"; +@import "webplayer"; +@import "help"; +@import "blog"; +@import "footer"; From 08dbc43fa64ff1dfc0d364b6cef6262426f76b64 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Wed, 1 Mar 2017 11:34:27 -0800 Subject: [PATCH 015/168] Deprecate NavigationExperimental Summary: Docs change to encourage people to use React Navigation over other options. Explains a bit of history about Navigator and NavigationExperimental. Remove an intro guide that encourages use of Navigator. Hopefully the existing ReactNav guide fills this void. Navigator docs are less emphasized but still present. Reviewed By: mkonicek Differential Revision: D4634452 fbshipit-source-id: 26763c2f02530009b3dfd20b0590fadcb5ea35ee --- docs/MoreResources.md | 2 +- docs/Navigation.md | 310 ++++++++-------------------------------- docs/Networking.md | 2 +- docs/UsingNavigators.md | 182 ----------------------- 4 files changed, 62 insertions(+), 434 deletions(-) delete mode 100644 docs/UsingNavigators.md diff --git a/docs/MoreResources.md b/docs/MoreResources.md index 1b4286ed17a803..d37ff50783fad3 100644 --- a/docs/MoreResources.md +++ b/docs/MoreResources.md @@ -5,7 +5,7 @@ layout: docs category: The Basics permalink: docs/more-resources.html next: integration-with-existing-apps -previous: using-navigators +previous: networking --- If you just read through this website, you should be able to build a pretty cool React Native app. But React Native isn't just a product made by one company - it's a community of thousands of developers. So if you're interested in React Native, here's some related stuff you might want to check out. diff --git a/docs/Navigation.md b/docs/Navigation.md index 4f1326a4a96822..f93410be3775c6 100644 --- a/docs/Navigation.md +++ b/docs/Navigation.md @@ -8,15 +8,67 @@ next: performance previous: javascript-environment --- -This guide covers the various navigation components available in React Native. If you are just getting started with navigation, you will probably want to use `Navigator`. If you are only targeting iOS and would like to stick to the native look and feel, check out `NavigatorIOS`. If you are looking for greater control over your navigation stack, you can't go wrong with `NavigationExperimental`. +This guide covers the various navigation components available in React Native. If you are just getting started with navigation, you will probably want to use React Navigation. + +If you are only targeting iOS and would like to stick to the native look and feel, check out `NavigatorIOS`. The `Navigator` component is older but has been thoroughly tested in production. + +## React Navigation + +The community solution to navigation is a standalone library that allows developers to set up the screens of an app with just a few lines of code. + +The first step is to install in your app: + +``` +npm install --save react-navigation +``` + +Then you can quickly create an app with a home screen and a profile screen: + +``` +import { + StackNavigator, +} from 'react-navigation'; + +const App = StackNavigator({ + Main: {screen: MainScreen}, + Profile: {screen: ProfileScreen}, +}); +``` + +Each screen component can set navigation options such as the header title. It can use action creators on the `navigation` prop to link to other screens: + +``` +class MainScreen extends React.Component { + static navigationOptions = { + title: 'Welcome', + }; + render() { + const { navigate } = this.props.navigation; + return ( +
    - +