├── .babelrc
├── .bookignore
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── .watchmanconfig
├── CHANGELOG.md
├── CONTRIBUTING.md
├── GLOSSARY.md
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── SUMMARY.md
├── assets
├── install_remove_libs_1.png
├── install_remove_libs_2.png
└── install_swift_syntax.png
├── book.json
├── build.gradle
├── docs
├── FAQ.md
├── GLOSSARY.md
├── README.md
├── api
│ ├── README.md
│ ├── navigator-config.md
│ ├── navigator-shared-element-group.md
│ ├── navigator-shared-element.md
│ ├── navigator-spacer.md
│ ├── navigator-tab-bar.md
│ ├── navigator-tab.md
│ └── navigator
│ │ ├── README.md
│ │ ├── dismiss.md
│ │ ├── pop.md
│ │ ├── present.md
│ │ ├── push.md
│ │ └── registerScreen.md
├── guides
│ ├── README.md
│ ├── basic-usage.md
│ ├── custom-navigation-implementations.md
│ ├── deep-linking.md
│ ├── integrating-with-existing-apps.md
│ ├── platform-differences.md
│ ├── project-structure.md
│ ├── shared-element-transitions.md
│ └── tabs.md
├── implementations
│ ├── DefaultImplementation.md
│ └── README.md
├── installation.md
├── roadmap.md
└── types
│ └── NavigationResult.md
├── example
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── android
│ ├── .idea
│ │ └── codeStyleSettings.xml
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── gen
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ ├── BuildConfig.java
│ │ │ │ ├── Manifest.java
│ │ │ │ └── R.java
│ │ │ ├── ic_launcher-web.png
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── airbnb
│ │ │ │ └── android
│ │ │ │ └── react
│ │ │ │ └── navigation
│ │ │ │ └── example
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainApplication.java
│ │ │ │ ├── MainFragment.java
│ │ │ │ └── NativeFragment.java
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ ├── ic_create_black_48dp.png
│ │ │ ├── ic_menu_black_24dp.png
│ │ │ ├── ic_settings_black_48dp.png
│ │ │ ├── launcher_icon.png
│ │ │ ├── legacy_image.png
│ │ │ ├── n2_ic_am_tv.xml
│ │ │ ├── n2_ic_am_twentyfourhourcheckin.xml
│ │ │ ├── n2_ic_am_washer.xml
│ │ │ ├── n2_ic_am_wifi.xml
│ │ │ ├── n2_ic_arrow_back_black.xml
│ │ │ └── n2_ic_arrow_back_white.xml
│ │ │ ├── layout
│ │ │ ├── activity_example.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── fragment_main.xml
│ │ │ └── fragment_native.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ └── gradlew.bat
├── components
│ ├── BaseRow.js
│ ├── ImageRow.js
│ ├── LoremHeader.js
│ ├── LoremImage.js
│ ├── LoremParagraph.js
│ ├── PlatformTouchableHighlight.js
│ ├── Row.js
│ └── Screen.js
├── icons
│ ├── alarm.png
│ ├── alarm@2x.png
│ ├── alarm@3x.png
│ ├── backup.png
│ ├── backup@2x.png
│ ├── backup@3x.png
│ ├── chat.png
│ ├── chat@2x.png
│ ├── chat@3x.png
│ ├── chevron_right.png
│ ├── chevron_right@2x.png
│ ├── chevron_right@3x.png
│ ├── close.png
│ ├── close@2x.png
│ ├── close@3x.png
│ ├── faces.png
│ ├── faces@2x.png
│ ├── faces@3x.png
│ ├── filter.png
│ ├── filter@2x.png
│ ├── filter@3x.png
│ ├── home.png
│ ├── home@2x.png
│ ├── home@3x.png
│ ├── settings.png
│ ├── settings@2x.png
│ └── settings@3x.png
├── index.js
├── ios
│ ├── Podfile
│ ├── Podfile.lock
│ ├── bundler
│ ├── fuzzy_match
│ ├── native-navigation.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── native-navigation.xcscheme
│ ├── native-navigation.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── native-navigation
│ │ ├── AppDelegate.swift
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ └── NavBarButtonPlus.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── NavBarButtonPlus@3x.png
│ │ ├── Info.plist
│ │ └── ViewController.swift
│ ├── pod
│ ├── sandbox-pod
│ └── xcodeproj
├── screens
│ ├── NavigationBar.js
│ ├── NavigationExampleScreen.js
│ ├── SharedElementFromScreen.js
│ ├── SharedElementToScreen.js
│ └── TabScreen.js
└── util
│ ├── platformTouchable.js
│ ├── theme.js
│ └── titleForId.js
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── index.js
├── lib
├── android
│ ├── .idea
│ │ └── codeStyleSettings.xml
│ ├── build.gradle
│ ├── gradle-maven-push.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── gen
│ │ └── com
│ │ │ └── airbnb
│ │ │ └── android
│ │ │ ├── BuildConfig.java
│ │ │ ├── Manifest.java
│ │ │ └── R.java
│ │ ├── java
│ │ └── com
│ │ │ └── airbnb
│ │ │ └── android
│ │ │ └── react
│ │ │ └── navigation
│ │ │ ├── ActivityUtils.java
│ │ │ ├── AndroidVersion.java
│ │ │ ├── AutoSharedElementCallback.java
│ │ │ ├── BackStack.java
│ │ │ ├── BundleBuilder.java
│ │ │ ├── ConversionUtil.java
│ │ │ ├── DefaultNavigationImplementation.java
│ │ │ ├── ExtendableBundleBuilder.java
│ │ │ ├── FragmentSharedElementTransition.java
│ │ │ ├── JacksonUtils.java
│ │ │ ├── NativeNavigationPackage.java
│ │ │ ├── NavigationImplementation.java
│ │ │ ├── NavigatorModule.java
│ │ │ ├── ReactActivity.java
│ │ │ ├── ReactAwareActivity.java
│ │ │ ├── ReactAwareActivityFacade.java
│ │ │ ├── ReactBottomNavigation.java
│ │ │ ├── ReactExposedActivityParams.java
│ │ │ ├── ReactExposedActivityParamsConstants.java
│ │ │ ├── ReactInterface.java
│ │ │ ├── ReactInterfaceManager.java
│ │ │ ├── ReactNativeActivity.java
│ │ │ ├── ReactNativeFragment.java
│ │ │ ├── ReactNativeFragmentViewGroup.java
│ │ │ ├── ReactNativeIntents.java
│ │ │ ├── ReactNativeTabActivity.java
│ │ │ ├── ReactNativeUtils.java
│ │ │ ├── ReactNavigationCoordinator.java
│ │ │ ├── ReactScreenMode.java
│ │ │ ├── ReactToolbar.java
│ │ │ ├── ScreenCoordinator.java
│ │ │ ├── ScreenCoordinatorComponent.java
│ │ │ ├── ScreenCoordinatorLayout.java
│ │ │ ├── SharedElementGroupManager.java
│ │ │ ├── SharedElementViewManager.java
│ │ │ ├── SimpleTransitionListener.java
│ │ │ ├── TabBarView.java
│ │ │ ├── TabBarViewManager.java
│ │ │ ├── TabCoordinator.java
│ │ │ ├── TabView.java
│ │ │ ├── TabViewManager.java
│ │ │ ├── TransitionName.java
│ │ │ └── ViewUtils.java
│ │ └── res
│ │ ├── anim
│ │ ├── delay.xml
│ │ ├── fade_in.xml
│ │ ├── fade_out.xml
│ │ ├── slide_down.xml
│ │ ├── slide_in_left.xml
│ │ ├── slide_in_right.xml
│ │ ├── slide_out_left.xml
│ │ ├── slide_out_right.xml
│ │ └── slide_up.xml
│ │ ├── layout
│ │ ├── activity_react_native.xml
│ │ ├── activity_tab_2.xml
│ │ ├── fragment_react_native.xml
│ │ ├── menu_item_view.xml
│ │ ├── react_root_view.xml
│ │ └── tab_react_native.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── ids.xml
│ │ └── styles.xml
├── ios
│ └── native-navigation
│ │ ├── Dictionary+FunctionalExtensions.swift
│ │ ├── NativeNavigationBridge.m
│ │ ├── ReactNavigation.swift
│ │ ├── ReactNavigationCoordinator.swift
│ │ ├── ReactNavigationImplementation.swift
│ │ ├── ReactSharedElementAnimation.swift
│ │ ├── ReactSharedElementTransition.swift
│ │ ├── ReactTabBarController.swift
│ │ ├── ReactViewController.swift
│ │ ├── ReactViewControllerProtocol.swift
│ │ ├── SharedElementGroupManager.swift
│ │ ├── SharedElementGroupManagerBridge.m
│ │ ├── SharedElementManager.swift
│ │ ├── SharedElementManagerBridge.m
│ │ ├── SharedElementTransitionController.swift
│ │ ├── TabBarViewManager.swift
│ │ ├── TabBarViewManagerBridge.m
│ │ ├── TabViewManager.swift
│ │ ├── TabViewMangerBridge.m
│ │ ├── TransitionAnimation.swift
│ │ ├── UIBarButtonItem+addAction.swift
│ │ ├── UIView+Snapshot.swift
│ │ └── UIViewController+TopMostViewController.swift
└── js
│ ├── Config.js
│ ├── EventEmitter.js
│ ├── Navigator.js
│ ├── NavigatorModule.js
│ ├── SharedElement.js
│ ├── SharedElementGroup.js
│ ├── Spacer.js
│ ├── Tab.js
│ ├── TabBar.js
│ ├── index.js
│ ├── navBar.js
│ ├── navigatorEmitter.js
│ ├── shallowEquals.js
│ └── utils.js
├── native-navigation.podspec
├── package.json
├── postinstall.sh
├── rn-cli.config.js
└── settings.gradle
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"],
3 | "plugins": [
4 | [
5 | "module-resolver",
6 | {
7 | "alias": {
8 | "native-navigation": "./"
9 | },
10 | "cwd": "babelrc"
11 | }
12 | ]
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.bookignore:
--------------------------------------------------------------------------------
1 | lib/
2 | gradle/
3 | gen/
4 | example/
5 | build/
6 | .gradle/
7 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | _book
4 | gradle
5 | lib/android
6 | lib/ios
7 | example/android
8 | example/ios
9 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "airbnb",
4 | "globals": {
5 | "__DEV__": true
6 | },
7 | "plugins": [
8 | "prefer-object-spread"
9 | ],
10 | "rules": {
11 | "no-console": 0,
12 | "prefer-template": 0,
13 | "global-require": 0,
14 | "no-use-before-define": 0,
15 | "prefer-object-spread/prefer-object-spread": 2,
16 | "react/prefer-stateless-function": 0,
17 | "react/jsx-filename-extension": 0,
18 | "react/sort-comp": 0,
19 | "import/no-extraneous-dependencies": 0,
20 | "import/no-unresolved": [2, { "ignore": ["^native-navigation$"] }]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | # We fork some components by platform.
4 | .*/*.web.js
5 | .*/*.android.js
6 |
7 | # Some modules have their own node_modules with overlap
8 | .*/node_modules/node-haste/.*
9 |
10 | # Ugh
11 | .*/node_modules/babel.*
12 | .*/node_modules/babylon.*
13 | .*/node_modules/invariant.*
14 |
15 | # Ignore react and fbjs where there are overlaps, but don't ignore
16 | # anything that react-native relies on
17 | .*/node_modules/fbjs-haste/.*/__tests__/.*
18 | .*/node_modules/fbjs-haste/__forks__/Map.js
19 | .*/node_modules/fbjs-haste/__forks__/Promise.js
20 | .*/node_modules/fbjs-haste/__forks__/fetch.js
21 | .*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
22 | .*/node_modules/fbjs-haste/core/isEmpty.js
23 | .*/node_modules/fbjs-haste/crypto/crc32.js
24 | .*/node_modules/fbjs-haste/stubs/ErrorUtils.js
25 | .*/node_modules/react-haste/React.js
26 | .*/node_modules/react-haste/renderers/dom/ReactDOM.js
27 | .*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
28 |
29 | # Ignore commoner tests
30 | .*/node_modules/commoner/test/.*
31 |
32 | # See https://github.com/facebook/flow/issues/442
33 | .*/react-tools/node_modules/commoner/lib/reader.js
34 |
35 | # Ignore jest
36 | .*/node_modules/jest-cli/.*
37 |
38 | # Ignore Website
39 | .*/website/.*
40 |
41 | [include]
42 |
43 | [libs]
44 | node_modules/react-native/Libraries/react-native/react-native-interface.js
45 |
46 | [options]
47 | module.system=haste
48 |
49 | munge_underscores=true
50 |
51 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
52 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
53 |
54 | suppress_type=$FlowIssue
55 | suppress_type=$FlowFixMe
56 | suppress_type=$FixMe
57 |
58 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
59 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
60 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
61 |
62 | [version]
63 | 0.18.1
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IJ
26 | #
27 | .idea
28 | *.iml
29 | .gradle
30 | local.properties
31 |
32 | # node.js
33 | #
34 | node_modules/*
35 | npm-debug.log
36 |
37 | # BUCK
38 | buck-out/
39 | \.buckd/
40 | android/app/libs
41 | *.keystore
42 |
43 | # Gitbook generated files
44 | _book
45 |
46 | Pods/
47 |
48 | .vscode
49 | .bundle/
50 |
51 | # Only apps should have lockfiles
52 | yarn.lock
53 | npm-shrinkwrap.json
54 | package-lock.json
55 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # babel configuration
20 | .babelrc
21 |
22 | # node-waf configuration
23 | .lock-wscript
24 |
25 | # Compiled binary addons (http://nodejs.org/api/addons.html)
26 | build/Release
27 |
28 | # Dependency directory
29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
30 | node_modules
31 |
32 | # Jetbrains IDEs
33 | .idea
34 |
35 | #/build # commented out intentionally, since this is the meat of the package.
36 | _book
37 |
38 | # Example Project
39 |
40 | example
41 | rn-cli.config.js
42 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "6"
5 |
6 | script: npm run ci
7 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## 0.2.1 (Apr 17, 2017)
4 |
5 | ## Patches
6 |
7 | - Set an id to container view in ReactActivity [(#93)](https://github.com/airbnb/native-navigation/pull/93)
8 |
9 | ## 0.2.0 (Apr 17, 2017)
10 |
11 | ## New Features
12 |
13 | - Cleanup warnings, implement some tab/tabbar props [(#74)](https://github.com/airbnb/native-navigation/pull/74)
14 |
15 | - Translucent fragments [(#69)](https://github.com/airbnb/native-navigation/pull/69)
16 |
17 | - Use the same container for all Fragments [(#50)](https://github.com/airbnb/native-navigation/pull/50)
18 |
19 | - Encapsulate a back stack in a data class [(#47)](https://github.com/airbnb/native-navigation/pull/47)
20 |
21 |
22 | ## Patches
23 |
24 | - Make android button ordering consistent with iOS [(#91)](https://github.com/airbnb/native-navigation/pull/91)
25 |
26 | - Use correct event prefix on android [(#89)](https://github.com/airbnb/native-navigation/pull/89)
27 |
28 | - Use gradle provided RN instead of specific version [(#88)](https://github.com/airbnb/native-navigation/pull/88)
29 |
30 | - Updated the ColorStateList for Tab Bars containing less then 4 tabs [(#71)](https://github.com/airbnb/native-navigation/pull/71)
31 |
32 | - De-register onReactContextInitialized listener after first run [(#58)](https://github.com/airbnb/native-navigation/pull/58)
33 |
34 | - Remove clown town dispatch asyncs [(#39)](https://github.com/airbnb/native-navigation/pull/39)
35 |
36 |
37 | ## 0.1.0 (Mar 13, 2017)
38 |
39 | - Official Release!
40 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guide
2 |
3 | Contributions are welcome and are greatly appreciated! Every little bit helps, and credit will
4 | always be given.
5 |
6 |
7 | ## Setting up your environment
8 |
9 | After forking to your own github org, do the following steps to get started:
10 |
11 | ```bash
12 | # clone your fork to your local machine
13 | git clone https://github.com/airbnb/native-navigation.git
14 |
15 | # step into local repo
16 | cd native-navigation
17 |
18 | # install dependencies
19 | npm install
20 | ```
21 |
22 | ### Developing on Android
23 |
24 | ```bash
25 | # run packager for development
26 | npm start
27 |
28 | # in a separate window, you can run the example app with:
29 | npm run run:android
30 | ```
31 |
32 | ### Developing on iOS
33 |
34 | ```bash
35 | # run packager for development
36 | npm start
37 |
38 | # in a separate window, you can run the example app with:
39 | npm run run:ios
40 | ```
41 |
42 | ### Style & Linting
43 |
44 | This codebase adheres to the [Airbnb Styleguide](https://github.com/airbnb/javascript) and is
45 | enforced using [ESLint](http://eslint.org/).
46 |
47 | It is recommended that you install an eslint plugin for your editor of choice when working on this
48 | codebase, however you can always check to see if the source code is compliant by running:
49 |
50 | ```bash
51 | npm run lint
52 | ```
53 |
54 |
55 | ### Building Docs
56 |
57 | Building the docs locally is extremely simple. First execute the following command:
58 |
59 | ```bash
60 | npm run docs:watch
61 | ```
62 |
63 | After this, you can open up your browser to the specified port (usually http://localhost:4000 )
64 |
65 | The browser will automatically refresh when there are changes to any of the source files.
66 |
67 |
68 | ## Pull Request Guidelines
69 |
70 | Before you submit a pull request from your forked repo, check that it meets these guidelines:
71 |
72 | 1. If the pull request adds functionality, the docs should be updated as part of the same PR.
73 | 1. If the pull request adds functionality, code in the example app that demonstrates the new functionality should be updated as part of the same PR.
74 | 1. If the pull request adds functionality, the PR description should include motivation and use cases for the feature.
75 | 1. If the pull request fixes a bug, an explanation including what the bug was, and how to reproduce it should be included in the PR description.
76 | 1. Please rebase and resolve all conflicts before submitting.
77 |
--------------------------------------------------------------------------------
/GLOSSARY.md:
--------------------------------------------------------------------------------
1 | ./docs/GLOSSARY.md
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | ruby '2.4.0'
3 | gem 'cocoapods', '1.2.0'
4 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (2.3.5)
5 | activesupport (4.2.8)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | claide (1.0.1)
11 | cocoapods (1.2.0)
12 | activesupport (>= 4.0.2, < 5)
13 | claide (>= 1.0.1, < 2.0)
14 | cocoapods-core (= 1.2.0)
15 | cocoapods-deintegrate (>= 1.0.1, < 2.0)
16 | cocoapods-downloader (>= 1.1.3, < 2.0)
17 | cocoapods-plugins (>= 1.0.0, < 2.0)
18 | cocoapods-search (>= 1.0.0, < 2.0)
19 | cocoapods-stats (>= 1.0.0, < 2.0)
20 | cocoapods-trunk (>= 1.1.2, < 2.0)
21 | cocoapods-try (>= 1.1.0, < 2.0)
22 | colored (~> 1.2)
23 | escape (~> 0.0.4)
24 | fourflusher (~> 2.0.1)
25 | gh_inspector (~> 1.0)
26 | molinillo (~> 0.5.5)
27 | nap (~> 1.0)
28 | ruby-macho (~> 0.2.5)
29 | xcodeproj (>= 1.4.1, < 2.0)
30 | cocoapods-core (1.2.0)
31 | activesupport (>= 4.0.2, < 5)
32 | fuzzy_match (~> 2.0.4)
33 | nap (~> 1.0)
34 | cocoapods-deintegrate (1.0.1)
35 | cocoapods-downloader (1.1.3)
36 | cocoapods-plugins (1.0.0)
37 | nap
38 | cocoapods-search (1.0.0)
39 | cocoapods-stats (1.0.0)
40 | cocoapods-trunk (1.1.2)
41 | nap (>= 0.8, < 2.0)
42 | netrc (= 0.7.8)
43 | cocoapods-try (1.1.0)
44 | colored (1.2)
45 | escape (0.0.4)
46 | fourflusher (2.0.1)
47 | fuzzy_match (2.0.4)
48 | gh_inspector (1.0.3)
49 | i18n (0.8.1)
50 | minitest (5.10.1)
51 | molinillo (0.5.7)
52 | nanaimo (0.2.3)
53 | nap (1.1.0)
54 | netrc (0.7.8)
55 | ruby-macho (0.2.6)
56 | thread_safe (0.3.6)
57 | tzinfo (1.2.2)
58 | thread_safe (~> 0.1)
59 | xcodeproj (1.4.2)
60 | CFPropertyList (~> 2.3.3)
61 | activesupport (>= 3)
62 | claide (>= 1.0.1, < 2.0)
63 | colored (~> 1.2)
64 | nanaimo (~> 0.2.3)
65 |
66 | PLATFORMS
67 | ruby
68 |
69 | DEPENDENCIES
70 | cocoapods (= 1.2.0)
71 |
72 | RUBY VERSION
73 | ruby 2.2.4p230
74 |
75 | BUNDLED WITH
76 | 1.14.6
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Airbnb
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | ./docs/README.md
--------------------------------------------------------------------------------
/assets/install_remove_libs_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/assets/install_remove_libs_1.png
--------------------------------------------------------------------------------
/assets/install_remove_libs_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/assets/install_remove_libs_2.png
--------------------------------------------------------------------------------
/assets/install_swift_syntax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/assets/install_swift_syntax.png
--------------------------------------------------------------------------------
/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "gitbook": "3.2.2",
3 | "title": "Native Navigation",
4 | "description": "Native Navigation for React Native",
5 | "structure": {
6 | "glossary": "GLOSSARY.md"
7 | },
8 | "plugins": [
9 | "edit-link",
10 | "prism",
11 | "-highlight",
12 | "github",
13 | "anchorjs",
14 | "-search"
15 | ],
16 | "pluginsConfig": {
17 | "edit-link": {
18 | "base": "https://github.com/airbnb/native-navigation/tree/master",
19 | "label": "Edit This Page"
20 | },
21 | "github": {
22 | "url": "https://github.com/airbnb/native-navigation/"
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.0'
9 | }
10 | }
11 |
12 | allprojects {
13 | repositories {
14 | mavenLocal()
15 | jcenter()
16 | maven {
17 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
18 | url "$rootDir/node_modules/react-native/android"
19 | }
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/docs/FAQ.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions
2 |
3 | ## Is Native Navigation used in the public Airbnb app?
4 |
5 | Not yet. This repository started out as a direct rewrite of the Navigation infrastructure we
6 | currently use in our public app. It started out very coupled to our own Navigation components, and
7 | we are currently attempting to replace our current navigation infrastructure with this library
8 | using a [custom implementation](/docs/guides/custom-navigation-implementations.md). We consider
9 | this one of our criteria in our [Roadmap to 1.0](/docs/roadmap.md), and will not consider the
10 | library to be "production ready" until we ourselves are using it in production.
11 |
12 |
13 | ## I want to use React Native in my app, but we have custom Navigation. Can this library work for me?
14 |
15 | Maybe. We have explicitly designed this library to be extensible so that apps with existing infrastructure
16 | that's *not* in React Native can integrate with our library and have their React Native screens and
17 | "Native" screens use the same navigation components. This is precisely why we built the library for
18 | Airbnb in the first place. With that said, we can't guarantee that this library will integrate
19 | seamlessly with yours. If you are having any trouble with this, please file an issue. We are still
20 | learning what points of extensibility are needed. See our
21 | [custom implementation guide](/docs/guides/custom-navigation-implementations.md) for more info.
22 |
23 |
24 | ## Why is Native Navigation written in Swift?
25 |
26 | Native Navigation is written using Swift because Airbnb is written with Swift, and we are likely
27 | not going to change that any time soon. This makes integrating with React Native slightly more
28 | difficult, but we are hoping that this will get better over time.
29 |
30 |
--------------------------------------------------------------------------------
/docs/GLOSSARY.md:
--------------------------------------------------------------------------------
1 | # Thunk
2 |
3 | Description about term
4 |
5 |
6 | # Screen
7 |
8 | what is a screen
9 |
10 |
11 | # Screen Identifier
12 |
13 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ## Table of Contents
2 |
3 | * [Introduction](/README.md)
4 | * [Installation](/docs/installation.md)
5 | * [Roadmap to 1.0](/docs/roadmap.md)
6 | * [Guides](/docs/guides/README.md)
7 | * [Integrating with existing apps](/docs/guides/integrating-with-existing-apps.md)
8 | * [Custom Navigation Implementations](/docs/guides/custom-navigation-implementations.md)
9 | * [Tabs](/docs/guides/tabs.md)
10 | * [Deep Linking](/docs/guides/deep-linking.md)
11 | * [Project Structure](/docs/guides/project-structure.md)
12 | * [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
13 | * [API Documentation](/docs/api/README.md)
14 | * [Navigator](/docs/api/navigator/README.md)
15 | * [Navigator.registerScreen](/docs/api/navigator/registerScreen.md)
16 | * [Navigator.push](/docs/api/navigator/push.md)
17 | * [Navigator.present](/docs/api/navigator/present.md)
18 | * [Navigator.pop](/docs/api/navigator/pop.md)
19 | * [Navigator.dismiss](/docs/api/navigator/dismiss.md)
20 | * [Config](/docs/api/navigator-config.md)
21 | * [Spacer](/docs/api/navigator-spacer.md)
22 | * [Tab](/docs/api/navigator-tab.md)
23 | * [TabBar](/docs/api/navigator-tab-bar.md)
24 | * [SharedElement](/docs/api/navigator-shared-element.md)
25 | * [SharedElementGroup](/docs/api/navigator-shared-element-group.md)
26 | * [Implementations](/docs/implementations/README.md)
27 | * [DefaultImplementations](/docs/implementations/DefaultImplementation.md)
28 | * [Change Log](/CHANGELOG.md)
29 | * [FAQ](/docs/FAQ.md)
30 | * [Contributing Guide](/CONTRIBUTING.md)
31 |
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | # API Reference
2 |
3 |
4 | ```js
5 | import Navigator from 'native-navigation';
6 | ```
7 |
8 |
9 | ### `Navigator`
10 |
11 | [View Documentation](/docs/api/navigator.md)
12 |
13 | ### ``
14 |
15 | [View Documentation](/docs/api/navigator-config.md)
16 |
17 | ### ``
18 |
19 | [View Documentation](/docs/api/navigator-spacer.md)
20 |
21 | ### ``
22 |
23 | [View Documentation](/docs/api/navigator-tab-bat.md)
24 |
25 | ### ``
26 |
27 | [View Documentation](/docs/api/navigator-tab.md)
28 |
29 | ### ``
30 |
31 | [View Documentation](/docs/api/navigator-shared-element.md)
32 |
33 | ### ``
34 |
35 | [View Documentation](/docs/api/navigator-shared-element-group.md)
36 |
--------------------------------------------------------------------------------
/docs/api/navigator-shared-element-group.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 |
4 | ## Props
5 |
6 | #### `id: number | string`
7 |
8 |
9 | ## Example Usage
10 |
11 | ```jsx
12 | import React from 'react';
13 | import { Image } from 'react-native';
14 | import { SharedElement } from 'native-navigation';
15 |
16 | export default class UserImage extends React.Component {
17 | render() {
18 | const { user } = this.props;
19 | return (
20 |
25 |
29 |
30 | );
31 | }
32 | }
33 | ```
34 |
35 |
36 | ## Related Guides
37 |
38 | - [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
39 |
40 |
41 | ## Related pages
42 |
43 | - [`SharedElement` API Reference](/docs/api/navigator-shared-element.md)
44 |
--------------------------------------------------------------------------------
/docs/api/navigator-shared-element.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 |
4 | ## Props
5 |
6 | #### `type: string`
7 |
8 | #### `typeId: number | string`
9 |
10 | #### `subType: string`
11 |
12 | #### `subTypeId: number | string`
13 |
14 |
15 | ## Example Usage
16 |
17 | ```jsx
18 | import React from 'react';
19 | import { Image } from 'react-native';
20 | import { SharedElement } from 'native-navigation';
21 |
22 | export default class UserImage extends React.Component {
23 | render() {
24 | const { user } = this.props;
25 | return (
26 |
31 |
35 |
36 | );
37 | }
38 | }
39 | ```
40 |
41 |
42 | ## Related Guides
43 |
44 | - [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
45 |
46 |
47 | ## Related pages
48 |
49 | - [`SharedElementGroup` API Reference](/docs/api/navigator-shared-element-group.md)
50 |
--------------------------------------------------------------------------------
/docs/api/navigator-spacer.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 | The `Spacer` component is intended to be used in order to properly pad content to never be rendered
4 | under the navigation bar.
5 |
6 | This component automatically sizes itself and changes height when the navigation bar changes height.
7 |
8 |
9 | ## Props
10 |
11 | #### `animated: boolean`
12 |
13 | Whether or not you want this view's height to animate when the size of the navigation bar changes.
14 |
15 | Default is `false`.
16 |
17 |
18 | ## Example Usage
19 |
20 | ```jsx
21 | import React from 'react';
22 | import { ScrollView, View, Text } from 'react-native';
23 | import { Spacer } from 'native-navigation';
24 |
25 | export default class Screen extends React.Component {
26 | render() {
27 | return (
28 |
29 |
30 | {/* This view will be the exact height of the Navigation Bar */}
31 |
32 |
33 | {/* This content will be rendered below the navigation bar */}
34 |
35 | Hello World
36 |
37 |
38 | )
39 | }
40 | }
41 | ```
42 |
--------------------------------------------------------------------------------
/docs/api/navigator-tab-bar.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 |
4 | ## Props
5 |
6 | _The `TabBar` component does not have any non-implementation props_
7 |
8 |
9 | ## Implementation Props
10 |
11 | The following props are defined on the tab bar as a part of the [DefaultImplementation](/docs/implementations/DefaultImplementation.md):
12 |
13 | #### `enabled: boolean`
14 |
15 | #### `backgroundColor: Color`
16 |
17 | #### `backgroundImage: Image`
18 |
19 | #### `shadowImage: Image`
20 |
21 | #### `selectionIndicatorImage: Image`
22 |
23 | #### `elevation: number`
24 |
25 | #### `translucent: boolean`
26 |
27 | #### `tintColor: Color`
28 |
29 | #### `barTintColor: Color`
30 |
31 | #### `itemIconColor: Color`
32 |
33 | #### `itemIconActiveColor: Color`
34 |
35 | #### `itemIconSelectedColor: Color`
36 |
37 | #### `itemIconDisabledColor: Color`
38 |
39 | #### `itemTextColor: Color`
40 |
41 | #### `itemTextActiveColor: Color`
42 |
43 | #### `itemTextSelectedColor: Color`
44 |
45 | #### `itemTextDisabledColor: Color`
46 |
47 |
48 | ## Example Usage
49 |
50 | ```jsx
51 |
52 | ```
53 |
54 | ## Related Pages
55 |
56 | - [`Tab` API Reference](/docs/api/navigator-tab.md)
57 |
58 |
59 | ## Related Guides
60 |
61 | - [Tabs](/docs/guides/tabs.md)
62 |
--------------------------------------------------------------------------------
/docs/api/navigator-tab.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 | The `Spacer` component is intended to be used in order to properly pad content to never be rendered
4 | under the navigation bar.
5 |
6 | This component automatically sizes itself and changes height when the navigation bar changes height.
7 |
8 |
9 | ## Props
10 |
11 | #### `route: string` (required)
12 |
13 | #### `props: Object`
14 |
15 |
16 | ## Implementation Props
17 |
18 | The following props are defined on tab as a part of the [DefaultImplementation](/docs/implementations/DefaultImplementation.md):
19 |
20 | #### `enabled: boolean`
21 |
22 | #### `image: Image`
23 |
24 | #### `selectedImage: Image`
25 |
26 | #### `title: string`
27 |
28 | #### `titleFontSize: number`
29 |
30 | #### `titleFontColor: Color`
31 |
32 | #### `titleFontName: string`
33 |
34 | #### `badgeValue: number`
35 |
36 | #### `badgeColor: Color`
37 |
38 | #### `badgeFontSize: number`
39 |
40 | #### `badgeFontColor: Color`
41 |
42 | #### `badgeFontName: string`
43 |
44 |
45 | ## Example Usage
46 |
47 | ```jsx
48 |
49 | ```
50 |
51 | ## Related Pages
52 |
53 | - [`TabBar` API Reference](/docs/api/navigator-tab-bar.md)
54 |
55 | ## Related Guides
56 |
57 | - [Tabs](/docs/guides/tabs.md)
58 |
--------------------------------------------------------------------------------
/docs/api/navigator/README.md:
--------------------------------------------------------------------------------
1 | # Navigator: API Reference
2 |
3 |
4 | ## Methods
5 |
6 | ### `registerScreen(screenName, getScreen[, options])`
7 |
8 | [View Documentation](/docs/api/navigator/registerScreen.md)
9 |
10 |
11 | ### `push(screenName[, props, options]): Promise`
12 |
13 | [View Documentation](/docs/api/navigator/push.md)
14 |
15 |
16 | ### `present(screenName[, props, options]): Promise`
17 |
18 | [View Documentation](/docs/api/navigator/present.md)
19 |
20 |
21 | ### `pop([payload])`
22 |
23 | [View Documentation](/docs/api/navigator/pop.md)
24 |
25 |
26 | ### `dismiss([payload])`
27 |
28 | [View Documentation](/docs/api/navigator/dismiss.md)
29 |
30 |
31 | ## Components
32 |
33 | ### `Config`
34 |
35 | [View Documentation](/docs/api/navigator-config.md)
36 |
37 | ### `Spacer`
38 |
39 | [View Documentation](/docs/api/navigator-spacer.md)
40 |
41 | ### `TabBar`
42 |
43 | [View Documentation](/docs/api/navigator-tab-bat.md)
44 |
45 | ### `Tab`
46 |
47 | [View Documentation](/docs/api/navigator-tab.md)
48 |
49 | ### `SharedElement`
50 |
51 | [View Documentation](/docs/api/navigator-shared-element.md)
52 |
53 | ### `SharedElementGroup`
54 |
55 | [View Documentation](/docs/api/navigator-shared-element-group.md)
56 |
--------------------------------------------------------------------------------
/docs/api/navigator/dismiss.md:
--------------------------------------------------------------------------------
1 | # `dismiss([payload])`
2 |
3 | ## Arguments
4 |
5 | 1. `payload` (`Object`): An optional payload to pass back to the presenting screen. This is what
6 | the promise returned from `present(...)` will resolve with.
7 |
8 | ## Example Usage
9 |
10 | ```js
11 | import Navigator from 'native-navigation';
12 |
13 | Navigator.dismiss();
14 | ```
15 |
16 |
17 | ## Related Guides
18 |
19 | - [Basic Usage](/docs/guides/basic-usage.md)
20 |
--------------------------------------------------------------------------------
/docs/api/navigator/pop.md:
--------------------------------------------------------------------------------
1 | # `pop()`
2 |
3 |
4 |
5 | ## Example Usage
6 |
7 | ```js
8 | import Navigator from 'native-navigation';
9 |
10 | Navigator.pop();
11 | ```
12 |
13 |
14 | ## Related Guides
15 |
16 | - [Basic Usage](/docs/guides/basic-usage.md)
17 |
--------------------------------------------------------------------------------
/docs/api/navigator/present.md:
--------------------------------------------------------------------------------
1 | # `present(screenName[, props, options])`
2 |
3 | ## Arguments
4 |
5 | 1. `screenName` (`string`): The screen identifier of the screen to be pushed.
6 | 2. `props` (`Object`): Props to be passed into the presented screen.
7 | 3. `options` (`Object`): Options for the navigation transition:
8 | - `options.transitionGroup` (`string`): The shared element group ID to use for the shared element
9 | transition
10 | - `options.modalPresentationStyle` (`string`, iOS only): The presentation style to use when presenting
11 | the view modally. Either `fullScreen` (default), `pageSheet`, `formSheet`, `currentContext`, `custom`,
12 | `overFullScreen`, `overCurrentContext`, `popover` or `none`.
13 |
14 | ## Returns
15 |
16 | (`Promise`): A promise that resolves when the presented screen gets dismissed.
17 |
18 | ## Example Usage
19 |
20 |
21 | ```js
22 | import React from 'react';
23 |
24 | import Navigator from 'native-navigation';
25 |
26 | class Foo extends React.Component {
27 | constructor(props) {
28 | super(props);
29 | this.state = {
30 | registered: false,
31 | };
32 | this.onPress = this.onPress.bind(this);
33 | }
34 | onPress() {
35 | return Navigator
36 | .present('Register', { source: 'Foo' })
37 | .then(({ code }) => this.setState({ registered: code === Navigator.RESULT_OK }));
38 | }
39 | render() {
40 | return (
41 |
42 | {!registered && (
43 |
47 | )}
48 | {!!registered && (
49 |
53 | )}
54 |
55 | );
56 | }
57 | }
58 |
59 |
60 | ```
61 |
62 |
63 | ## Related Guides
64 |
65 | - [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
66 |
67 |
68 | ## Types
69 |
70 | - [`NavigationResult`](/docs/types/NavigationResult.md)
71 |
--------------------------------------------------------------------------------
/docs/api/navigator/push.md:
--------------------------------------------------------------------------------
1 | # `push(screenName[, props, options])`
2 |
3 | ## Arguments
4 |
5 | 1. `screenName` (`string`): The screen identifier of the screen to be pushed.
6 | 2. `props` (`Object`): Props to be passed into the pushed screen.
7 | 3. `options` (`Object`): Options for the navigation transition:
8 | - `options.transitionGroup` (`string`): The shared element group ID to use for the shared element
9 | transition
10 |
11 | ## Returns
12 |
13 | (`Promise`): A
14 |
15 | ## Example Usage
16 |
17 | ```js
18 | import Navigator from 'native-navigation';
19 |
20 | Navigator.push('ScreenOne', { foo: 'bar' });
21 | ```
22 |
23 |
24 | ## Related Guides
25 |
26 | - [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
27 |
28 |
29 | ## Types
30 |
31 | - [`NavigationResult`](/docs/types/NavigationResult.md)
32 |
--------------------------------------------------------------------------------
/docs/api/navigator/registerScreen.md:
--------------------------------------------------------------------------------
1 | # `registerScreen(screenName, getScreen[, options])`
2 |
3 |
4 |
5 | ## Arguments
6 |
7 | 1. `screenName` (`string`): The screen identifier to be registered with this screen.
8 |
9 | 2. `getScreen` (`Thunk`): A function returning the component to use for the screen.
10 |
11 | 3. `options` (`ScreenOptions` _optional_):
12 |
13 | - `options.waitForRender` (`boolean` _optional_): If `true`, the screen will not get pushed or
14 | presented until it renders once, allowing for react-rendered views to render and navigation configuration
15 | to happen if it needs to. Defaults to `true`.
16 | - `options.initialConfig` (`ScreenConfig` _optional_): Any `ScreenConfig` props to apply initially to the
17 | screen. Values passed here will get merged with values passed into any `Navigator.Config` in the actual
18 | rendered screen, with the rendered config values taking precedence. Defaults to `{}`.
19 | - `options.mode` (`'screen' | 'tabs'`): Defaults to `'screen'`.
20 |
21 |
22 | ## Example Usage
23 |
24 | This function is used to expose React components to the native context. Under the hood, it utilizes
25 | [`Application.registerComponent`](http://facebook.github.io/react-native/docs/appregistry.html#registercomponent).
26 |
27 | We recommend that you separate screen _registration_ from screen _definition_. As your app grows in
28 | number of screens, it is advantageous to import as few files as possible at app startup time, and
29 | lazily import some files using `require` as they are needed.
30 |
31 | For example, here we have our screen component defined and exported in one file:
32 |
33 | ```js
34 | // ScreenOne.js
35 | import React from 'react';
36 |
37 | export default class ScreenOne extends React.Component {
38 | render() {
39 | // ...
40 | }
41 | }
42 | ```
43 |
44 | And then we have a separate `register.js` file where we register the screen, with the `getScreen`
45 | parameter being an anonymous function returning the result of `require('./ScreenOne')`, which
46 | is referred to a "Thunk", or a "lazy value".
47 |
48 | ```js
49 | // register.js
50 | import Navigator from 'native-navigation';
51 |
52 | Navigator.registerScreen('ScreenOne', () => require('./ScreenOne'));
53 | ```
54 |
55 | You can also pass some static configuration to the screen, if it is convenient:
56 |
57 | ```js
58 | // register.js
59 | import Navigator from 'native-navigation';
60 |
61 | Navigator.registerScreen('ScreenOne', () => require('./ScreenOne'), {
62 | waitForRender: false,
63 | initialConfig: {
64 | title: 'ScreenOne',
65 | },
66 | });
67 | ```
68 |
69 |
70 | ## Related Guides
71 |
72 | - [Project Structure](/docs/guides/project-structure.md)
73 |
--------------------------------------------------------------------------------
/docs/guides/README.md:
--------------------------------------------------------------------------------
1 | # Guides
2 |
3 | * [Basic Usage](/docs/guides/basic-usage.md)
4 | * [Integrating with existing apps](/docs/guides/integrating-with-existing-apps.md)
5 | * [Custom Navigation Implementations](/docs/guides/custom-navigation-implementations.md)
6 | * [Deep Linking](/docs/guides/deep-linking.md)
7 | * [Platform Differences](/docs/guides/platform-differences.md)
8 | * [Project Structure](/docs/guides/project-structure.md)
9 | * [Shared Element Transitions](/docs/guides/shared-element-transitions.md)
10 |
--------------------------------------------------------------------------------
/docs/guides/basic-usage.md:
--------------------------------------------------------------------------------
1 | # Basic Usage
2 |
3 | _This documentation has not been created yet. Sorry about that! Hang tight!_
4 |
--------------------------------------------------------------------------------
/docs/guides/deep-linking.md:
--------------------------------------------------------------------------------
1 | # Deep Linking
2 |
3 | _This documentation has not been created yet. Sorry about that! Hang tight!_
4 |
--------------------------------------------------------------------------------
/docs/guides/integrating-with-existing-apps.md:
--------------------------------------------------------------------------------
1 | # Integrating with existing apps
2 |
3 | _This documentation has not been created yet. Sorry about that! Hang tight!_
4 |
--------------------------------------------------------------------------------
/docs/guides/platform-differences.md:
--------------------------------------------------------------------------------
1 | # Platform Differences
2 |
3 | _This documentation has not been created yet. Sorry about that! Hang tight!_
4 |
--------------------------------------------------------------------------------
/docs/guides/tabs.md:
--------------------------------------------------------------------------------
1 | # Tabs Guide
2 |
3 | _This documentation has not been created yet. Sorry about that! Hang tight!_
4 |
--------------------------------------------------------------------------------
/docs/implementations/DefaultImplementation.md:
--------------------------------------------------------------------------------
1 | # `DefaultImplementation`
2 |
3 | _This page is not filled out yet_
4 |
5 |
--------------------------------------------------------------------------------
/docs/implementations/README.md:
--------------------------------------------------------------------------------
1 | # Implementations
2 |
3 | See the [Custom Navigation Implementations Guide](/docs/guides/custom-navigation-implementations.md)
4 | for more information on implementing a custom implementation.
5 |
6 | Native Navigation ships with the [DefaultImplementation](/docs/implementations/DefaultImplementation.md)
7 | by default.
8 |
--------------------------------------------------------------------------------
/docs/roadmap.md:
--------------------------------------------------------------------------------
1 | # Road map to 1.0
2 |
3 | As indicated in the README of this project, **Native Navigation is currently in "beta"**, and not
4 | recommended for production use in its current state.
5 |
6 | We wanted to make Native Navigation public so that we could collaborate in the open and make sure
7 | that we are making API decisions that can be useful for more people.
8 |
9 | In the process of decoupling this library from Airbnb's internal navigation infrastructure, we have
10 | had to make a lot of changes to the code in order to make it extensible to work both for Airbnb and
11 | for others. In order to accomplish the level of extensibility we wanted, we had to refactor a lot
12 | of the code base, and so the library now has a lot of code that has not yet been tested in a
13 | production environment.
14 |
15 | There are several things that we would like to do before we can recommend it for use in production
16 | apps. Right now, those things are primarily the following:
17 |
18 |
19 | ### Ship it in Airbnb's App
20 |
21 | The most important test that we can have is the test of us actually using this library in the main
22 | Airbnb app for every React Native flow we have in production, completely moving over our current
23 | navigation solution to this library.
24 |
25 |
26 | ### Proper Extension Points
27 |
28 | One of the primary goals of Native Navigation is to allow for
29 | [custom navigation implementations](/docs/guides/custom-navigation-implementations.md) to be
30 | injected into the library and allow for really custom branded navigation implementations to easily
31 | integrate with React Native through Native Navigation, while successfully abstracting away a lot of
32 | the non-trivial parts of navigation.
33 |
34 | Note: This is where YOU can help! If you are wanting to use Native Navigation for exactly this
35 | purpose but have some non-trivial requirements, please file an issue so we can talk about it!
36 |
37 |
38 | ### Deep Linking
39 |
40 | We need to figure out the right way to expose deep linking with this library in a way that doesn't
41 | lock people in to any one deep linking library.
42 |
43 |
44 | ## 1.0 and Beyond
45 |
46 | Beyond a 1.0 release, there are a lot of ideas we have for this library that we are excited to work
47 | on! While these are not necessary for a 1.0 release, we hope to work on them in parallel, or have
48 | interested community members help out!
49 |
50 | These features include (but are certainly not limited to!):
51 |
52 |
53 | ### Lottie Transitions
54 |
55 | On iOS, ViewController transitions can be animated using [Lottie](https://github.com/airbnb/lottie-ios).
56 | It's possible we could add support for such a feature into Native Navigation.
57 |
58 |
59 | ### React-rendered NavigationBar and TabBar
60 |
61 | A second navigation implementation could be shipped with this library that allows for navigation
62 | components such as the navigation bar and tab bars be rendered using React Native just like the
63 | rest of your React Native app.
64 |
65 |
66 | ### Web version
67 |
68 | OK, We realize it's a little wonky for a "Native Navigation" library to have a web version... but
69 | why not?!
70 |
71 | Just like the iOS and Android implementations of Native Navigation hide behind a common JS
72 | interface, a JS-based web navigator could also implement the same interface, helping pave a path
73 | towards cross-platform development!
74 |
--------------------------------------------------------------------------------
/docs/types/NavigationResult.md:
--------------------------------------------------------------------------------
1 |
2 | # `NavigationResult` Type Definition
3 |
4 | ```js
5 | type RESULT_OK = 1;
6 | type RESULT_CANCELLED = 0;
7 |
8 | type NavigationResult = {
9 | code: RESULT_OK | RESULT_CANCELLED;
10 | payload: Object;
11 | }
12 | ```
13 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 | .*/Libraries/react-native/ReactNative.js
16 |
17 | [include]
18 |
19 | [libs]
20 | node_modules/react-native/Libraries/react-native/react-native-interface.js
21 | node_modules/react-native/flow
22 | flow/
23 |
24 | [options]
25 | module.system=haste
26 |
27 | experimental.strict_type_args=true
28 |
29 | munge_underscores=true
30 |
31 | module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
32 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
33 |
34 | suppress_type=$FlowIssue
35 | suppress_type=$FlowFixMe
36 | suppress_type=$FixMe
37 |
38 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-5]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
39 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-5]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
40 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
41 |
42 | unsafe.enable_getters_and_setters=true
43 |
44 | [version]
45 | ^0.35.0
46 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | # To learn about Buck see [Docs](https://buckbuild.com/).
4 | # To run your application with Buck:
5 | # - install Buck
6 | # - `npm start` - to start the packager
7 | # - `cd android`
8 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
9 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
10 | # - `buck install -r android/app` - compile, install and run application
11 | #
12 |
13 | lib_deps = []
14 | for jarfile in glob(['libs/*.jar']):
15 | name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
16 | lib_deps.append(':' + name)
17 | prebuilt_jar(
18 | name = name,
19 | binary_jar = jarfile,
20 | )
21 |
22 | for aarfile in glob(['libs/*.aar']):
23 | name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
24 | lib_deps.append(':' + name)
25 | android_prebuilt_aar(
26 | name = name,
27 | aar = aarfile,
28 | )
29 |
30 | android_library(
31 | name = 'all-libs',
32 | exported_deps = lib_deps
33 | )
34 |
35 | android_library(
36 | name = 'app-code',
37 | srcs = glob([
38 | 'src/main/java/**/*.java',
39 | ]),
40 | deps = [
41 | ':all-libs',
42 | ':build_config',
43 | ':res',
44 | ],
45 | )
46 |
47 | android_build_config(
48 | name = 'build_config',
49 | package = 'com.example',
50 | )
51 |
52 | android_resource(
53 | name = 'res',
54 | res = 'src/main/res',
55 | package = 'com.example',
56 | )
57 |
58 | android_binary(
59 | name = 'app',
60 | package_type = 'debug',
61 | manifest = 'src/main/AndroidManifest.xml',
62 | keystore = '//android/keystores:debug',
63 | deps = [
64 | ':app-code',
65 | ],
66 | )
67 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # okhttp
54 |
55 | -keepattributes Signature
56 | -keepattributes *Annotation*
57 | -keep class okhttp3.** { *; }
58 | -keep interface okhttp3.** { *; }
59 | -dontwarn okhttp3.**
60 |
61 | # okio
62 |
63 | -keep class sun.misc.Unsafe { *; }
64 | -dontwarn java.nio.file.*
65 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
66 | -dontwarn okio.**
67 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
9 |
10 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/android/app/src/main/gen/com/example/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.example;
4 |
5 | /* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
6 | public final class BuildConfig {
7 | public final static boolean DEBUG = Boolean.parseBoolean(null);
8 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/gen/com/example/Manifest.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.example;
4 |
5 | /* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
6 | public final class Manifest {
7 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/gen/com/example/R.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.example;
4 |
5 | /* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
6 | public final class R {
7 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/airbnb/android/react/navigation/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation.example;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 |
6 | import com.airbnb.android.react.navigation.ScreenCoordinatorLayout;
7 | import com.airbnb.android.react.navigation.ReactAwareActivity;
8 | import com.airbnb.android.react.navigation.ScreenCoordinator;
9 | import com.airbnb.android.react.navigation.ScreenCoordinatorComponent;
10 |
11 | public class MainActivity extends ReactAwareActivity implements ScreenCoordinatorComponent {
12 | private static final String TAG = MainActivity.class.getSimpleName();
13 |
14 | private ScreenCoordinator screenCoordinator;
15 |
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.activity_main);
20 | ScreenCoordinatorLayout container = (ScreenCoordinatorLayout) findViewById(R.id.content);
21 | screenCoordinator = new ScreenCoordinator(this, container, savedInstanceState);
22 |
23 | if (savedInstanceState == null) {
24 | screenCoordinator.presentScreen(MainFragment.newInstance());
25 | }
26 | }
27 |
28 | @Override
29 | public ScreenCoordinator getScreenCoordinator() {
30 | return screenCoordinator;
31 | }
32 |
33 | @Override
34 | public void onBackPressed() {
35 | screenCoordinator.onBackPressed();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/airbnb/android/react/navigation/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation.example;
2 |
3 | import android.app.Application;
4 | import com.airbnb.android.react.navigation.NativeNavigationPackage;
5 | import com.airbnb.android.react.navigation.ReactNavigationCoordinator;
6 | import com.facebook.react.ReactApplication;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.shell.MainReactPackage;
10 | import com.facebook.soloader.SoLoader;
11 |
12 | import java.util.Arrays;
13 | import java.util.List;
14 |
15 | public class MainApplication extends Application implements ReactApplication {
16 |
17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
18 | @Override
19 | public boolean getUseDeveloperSupport() {
20 | return BuildConfig.DEBUG;
21 | }
22 |
23 | @Override
24 | protected List getPackages() {
25 | return Arrays.asList(
26 | new MainReactPackage(),
27 | new NativeNavigationPackage()
28 | );
29 | }
30 |
31 | @Override
32 | protected String getJSMainModuleName() {
33 | return "example/index";
34 | }
35 | };
36 |
37 | @Override
38 | public ReactNativeHost getReactNativeHost() {
39 | return mReactNativeHost;
40 | }
41 |
42 | @Override
43 | public void onCreate() {
44 | super.onCreate();
45 | SoLoader.init(this, /* native exopackage */ false);
46 |
47 | ReactNavigationCoordinator coordinator = ReactNavigationCoordinator.sharedInstance;
48 | coordinator.injectReactInstanceManager(mReactNativeHost.getReactInstanceManager());
49 | coordinator.start(this);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/airbnb/android/react/navigation/example/MainFragment.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation.example;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.Toolbar;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.Button;
13 | import android.widget.Toast;
14 |
15 | import com.airbnb.android.react.navigation.ReactNativeTabActivity;
16 | import com.airbnb.android.react.navigation.ScreenCoordinator;
17 | import com.airbnb.android.react.navigation.ScreenCoordinatorComponent;
18 |
19 | public class MainFragment extends Fragment {
20 |
21 | static MainFragment newInstance() {
22 | return new MainFragment();
23 | }
24 |
25 | Toolbar toolbar;
26 |
27 | @Nullable
28 | @Override
29 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
30 | View view = inflater.inflate(R.layout.fragment_main, container, false);
31 | toolbar = (Toolbar) view.findViewById(R.id.toolbar);
32 | initToolBar();
33 |
34 | Button btnScreen = (Button) view.findViewById(R.id.button_screen);
35 |
36 | btnScreen.setText("Screen One");
37 |
38 | btnScreen.setOnClickListener(new View.OnClickListener() {
39 | @Override
40 | public void onClick(View v) {
41 | getScreenCoordinator().presentScreen(NativeFragment.newInstance(1));
42 | }
43 | });
44 |
45 | Button btnTabs = (Button) view.findViewById(R.id.button_tab);
46 |
47 | btnTabs.setText("Tabs");
48 |
49 | btnTabs.setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | startActivity(new Intent(getContext(), ReactNativeTabActivity.class));
53 | }
54 | });
55 |
56 | return view;
57 | }
58 |
59 | private void initToolBar() {
60 | toolbar.setTitle(R.string.native_navigation);
61 | ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
62 | toolbar.setNavigationOnClickListener(
63 | new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | Toast.makeText(getContext(), "clicking the toolbar!", Toast.LENGTH_SHORT).show();
67 | }
68 | }
69 | );
70 | }
71 |
72 | private ScreenCoordinator getScreenCoordinator() {
73 | return ((ScreenCoordinatorComponent) getActivity()).getScreenCoordinator();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/ic_create_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/drawable/ic_create_black_48dp.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/ic_menu_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/drawable/ic_menu_black_24dp.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/ic_settings_black_48dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/drawable/ic_settings_black_48dp.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/drawable/launcher_icon.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/legacy_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/drawable/legacy_image.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_am_tv.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
28 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_am_twentyfourhourcheckin.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_am_washer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
32 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_am_wifi.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
30 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_arrow_back_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/n2_ic_arrow_back_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/layout/activity_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
28 |
29 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/layout/fragment_native.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
24 |
25 |
32 |
33 |
40 |
41 |
48 |
49 |
56 |
57 |
64 |
65 |
69 |
74 |
80 |
81 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Navigation
3 | Native Navigation
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Feb 21 23:07:53 PST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/components/BaseRow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | View,
5 | StyleSheet,
6 | } from 'react-native';
7 |
8 | import PlatformTouchableHighlight from './PlatformTouchableHighlight';
9 | import theme from '../util/theme';
10 |
11 | const propTypes = {
12 | children: PropTypes.node,
13 | onPress: PropTypes.func,
14 | };
15 |
16 | const defaultProps = {
17 | };
18 |
19 | export default class BaseRow extends React.Component {
20 | render() {
21 | const {
22 | children,
23 | onPress,
24 | } = this.props;
25 |
26 | const content = (
27 |
28 |
29 | {children}
30 |
31 |
32 | );
33 |
34 | if (onPress) {
35 | return (
36 |
40 | {content}
41 |
42 | );
43 | }
44 | return content;
45 | }
46 | }
47 |
48 | BaseRow.defaultProps = defaultProps;
49 | BaseRow.propTypes = propTypes;
50 |
51 | const styles = StyleSheet.create({
52 | container: {
53 | overflow: 'hidden',
54 | paddingHorizontal: theme.size.horizontalPadding,
55 | },
56 | row: {
57 | paddingVertical: theme.size.verticalPadding,
58 | borderBottomColor: '#dedede',
59 | borderBottomWidth: 1,
60 | },
61 | });
62 |
--------------------------------------------------------------------------------
/example/components/ImageRow.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | View,
5 | Text,
6 | StyleSheet,
7 | Dimensions,
8 | } from 'react-native';
9 |
10 | import BaseRow from './BaseRow';
11 | import LoremImage from './LoremImage';
12 | import theme from '../util/theme';
13 | import titleForId from '../util/titleForId';
14 |
15 | const { width } = Dimensions.get('window');
16 |
17 | const propTypes = {
18 | id: PropTypes.number.isRequired,
19 | onPress: PropTypes.func,
20 | };
21 |
22 | const defaultProps = {
23 | };
24 |
25 | export default class ImageRow extends React.Component {
26 | render() {
27 | const {
28 | id,
29 | onPress,
30 | } = this.props;
31 |
32 | const w = width - (2 * theme.size.horizontalPadding);
33 |
34 | return (
35 |
36 |
43 |
44 | {titleForId(id)}
45 |
46 |
47 | );
48 | }
49 | }
50 |
51 | ImageRow.defaultProps = defaultProps;
52 | ImageRow.propTypes = propTypes;
53 |
54 | const styles = StyleSheet.create({
55 | titleContainer: {
56 | marginTop: theme.size.verticalPadding,
57 | },
58 | title: theme.font.large,
59 | });
60 |
--------------------------------------------------------------------------------
/example/components/LoremHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | Text,
5 | StyleSheet,
6 | } from 'react-native';
7 | import murmurHash from 'murmur2js';
8 |
9 | import theme from '../util/theme';
10 | import titleForId from '../util/titleForId';
11 |
12 | const propTypes = {
13 | id: PropTypes.number,
14 | ...Text.propTypes,
15 | };
16 |
17 | const contextTypes = {
18 | nativeNavigationInstanceId: PropTypes.string,
19 | };
20 |
21 | export default class LoremHeader extends React.Component {
22 | render() {
23 | const { id, style } = this.props;
24 | const { nativeNavigationInstanceId } = this.context;
25 | return (
26 |
27 | {titleForId(id || murmurHash(nativeNavigationInstanceId))}
28 |
29 | );
30 | }
31 | }
32 |
33 | LoremHeader.propTypes = propTypes;
34 | LoremHeader.contextTypes = contextTypes;
35 |
36 | const styles = StyleSheet.create({
37 | header: theme.font.title,
38 | });
39 |
--------------------------------------------------------------------------------
/example/components/LoremImage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | Image,
5 | StyleSheet,
6 | } from 'react-native';
7 | import murmurHash from 'murmur2js';
8 | import { SharedElement } from 'native-navigation';
9 |
10 | import theme from '../util/theme';
11 |
12 | const propTypes = {
13 | width: PropTypes.number.isRequired,
14 | height: PropTypes.number.isRequired,
15 | urlWidth: PropTypes.number,
16 | urlHeight: PropTypes.number,
17 | id: PropTypes.number,
18 | };
19 |
20 | const defaultProps = {
21 | urlWidth: 0,
22 | urlheight: 0,
23 | id: null,
24 | };
25 |
26 | const contextTypes = {
27 | nativeNavigationInstanceId: PropTypes.string,
28 | };
29 |
30 | const CARDINALITY = 30;
31 |
32 | // const getImage = (w, h, id) => `https://unsplash.it/${w}/${h}?image=${id}`;
33 | // const getImage = (w, h, id) => `http://lorempixel.com/${w}/${h}/abstract/${id}/`;
34 | const getImage = (w, h, id) => `https://placem.at/places?w=${w}&h=${h}&random=${id}&txt=0`;
35 |
36 | export default class LoremImage extends React.PureComponent {
37 | render() {
38 | const { id, width, height, urlWidth, urlHeight } = this.props;
39 | const w = Math.round(urlWidth || width);
40 | const h = Math.round(urlHeight || height);
41 | const { nativeNavigationInstanceId } = this.context;
42 | const image = id == null ? murmurHash(nativeNavigationInstanceId) % CARDINALITY : id;
43 | const uri = getImage(w, h, image);
44 | const sizeStyle = { width: Math.round(width), height: Math.round(height) };
45 | return (
46 |
51 |
57 |
58 | );
59 | }
60 | }
61 |
62 | LoremImage.defaultProps = defaultProps;
63 | LoremImage.propTypes = propTypes;
64 | LoremImage.contextTypes = contextTypes;
65 |
66 | const styles = StyleSheet.create({
67 | image: {
68 | backgroundColor: theme.color.image,
69 | },
70 | });
71 |
--------------------------------------------------------------------------------
/example/components/PlatformTouchableHighlight.js:
--------------------------------------------------------------------------------
1 | /* eslint react/prop-types: 0 */
2 | import React from 'react';
3 | import {
4 | ColorPropType,
5 | TouchableHighlight,
6 | } from 'react-native';
7 | import {
8 | createPlatformTouchableComponent,
9 | touchablePropTypes,
10 | } from '../util/platformTouchable';
11 |
12 | const propTypes = {
13 | ...touchablePropTypes,
14 | color: ColorPropType,
15 | };
16 |
17 | export default createPlatformTouchableComponent({
18 | displayName: 'PlatformTouchableHighlight',
19 | renderDefaultTouchable(props, color) {
20 | return (
21 |
27 | {props.children}
28 |
29 | );
30 | },
31 | propTypes,
32 | });
33 |
--------------------------------------------------------------------------------
/example/components/Row.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | View,
5 | Text,
6 | Image,
7 | StyleSheet,
8 | } from 'react-native';
9 |
10 | import BaseRow from './BaseRow';
11 | import theme from '../util/theme';
12 |
13 | const propTypes = {
14 | title: PropTypes.string.isRequired,
15 | subtitle: PropTypes.string,
16 | onPress: PropTypes.func,
17 | };
18 |
19 | const defaultProps = {
20 | };
21 |
22 | export default class Row extends React.Component {
23 | render() {
24 | const {
25 | title,
26 | subtitle,
27 | onPress,
28 | } = this.props;
29 |
30 | return (
31 |
32 |
33 |
34 |
35 | {title}
36 |
37 | {!!subtitle && (
38 |
39 | {subtitle}
40 |
41 | )}
42 |
43 | {onPress && (
44 |
52 | )}
53 |
54 |
55 | );
56 | }
57 | }
58 |
59 | Row.defaultProps = defaultProps;
60 | Row.propTypes = propTypes;
61 |
62 | const styles = StyleSheet.create({
63 | content: {
64 | flexDirection: 'row',
65 | justifyContent: 'space-between',
66 | alignItems: 'flex-start',
67 | marginVertical: 8,
68 | },
69 | contentTween: {
70 | marginVertical: 24,
71 | },
72 | loadingContainer: {
73 | flex: 0,
74 | },
75 | titleContainer: {
76 | flex: 1,
77 | },
78 | title: theme.font.large,
79 | subtitle: {
80 | ...theme.font.small,
81 | marginTop: 4,
82 | },
83 | icon: {
84 | marginTop: 0.4 * 8,
85 | },
86 | });
87 |
--------------------------------------------------------------------------------
/example/components/Screen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | ScrollView,
5 | } from 'react-native';
6 |
7 | import Navigator from 'native-navigation';
8 | import theme from '../util/theme';
9 |
10 | const propTypes = {
11 | title: PropTypes.string,
12 | children: PropTypes.node,
13 | onPress: PropTypes.func,
14 | };
15 |
16 | const defaultProps = {
17 | };
18 |
19 | const contextTypes = {
20 | nativeNavigationInstanceId: PropTypes.string,
21 | };
22 |
23 | export default class Screen extends React.Component {
24 | render() {
25 | const {
26 | children,
27 | title,
28 | } = this.props;
29 |
30 | return (
31 | console.log('onBackPress')}
36 | onLeftPress={() => console.log('onLeftPress')}
37 | onRightPress={(x) => console.log('onRightPress', x)}
38 | onAppear={() => console.log('onAppear', this.context.nativeNavigationInstanceId)}
39 | onDisappear={() => console.log('onDisappear', this.context.nativeNavigationInstanceId)}
40 | >
41 |
42 |
43 | {children}
44 |
45 |
46 | );
47 | }
48 | }
49 |
50 | Screen.defaultProps = defaultProps;
51 | Screen.propTypes = propTypes;
52 | Screen.contextTypes = contextTypes;
53 |
--------------------------------------------------------------------------------
/example/icons/alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/alarm.png
--------------------------------------------------------------------------------
/example/icons/alarm@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/alarm@2x.png
--------------------------------------------------------------------------------
/example/icons/alarm@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/alarm@3x.png
--------------------------------------------------------------------------------
/example/icons/backup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/backup.png
--------------------------------------------------------------------------------
/example/icons/backup@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/backup@2x.png
--------------------------------------------------------------------------------
/example/icons/backup@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/backup@3x.png
--------------------------------------------------------------------------------
/example/icons/chat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chat.png
--------------------------------------------------------------------------------
/example/icons/chat@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chat@2x.png
--------------------------------------------------------------------------------
/example/icons/chat@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chat@3x.png
--------------------------------------------------------------------------------
/example/icons/chevron_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chevron_right.png
--------------------------------------------------------------------------------
/example/icons/chevron_right@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chevron_right@2x.png
--------------------------------------------------------------------------------
/example/icons/chevron_right@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/chevron_right@3x.png
--------------------------------------------------------------------------------
/example/icons/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/close.png
--------------------------------------------------------------------------------
/example/icons/close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/close@2x.png
--------------------------------------------------------------------------------
/example/icons/close@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/close@3x.png
--------------------------------------------------------------------------------
/example/icons/faces.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/faces.png
--------------------------------------------------------------------------------
/example/icons/faces@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/faces@2x.png
--------------------------------------------------------------------------------
/example/icons/faces@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/faces@3x.png
--------------------------------------------------------------------------------
/example/icons/filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/filter.png
--------------------------------------------------------------------------------
/example/icons/filter@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/filter@2x.png
--------------------------------------------------------------------------------
/example/icons/filter@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/filter@3x.png
--------------------------------------------------------------------------------
/example/icons/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/home.png
--------------------------------------------------------------------------------
/example/icons/home@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/home@2x.png
--------------------------------------------------------------------------------
/example/icons/home@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/home@3x.png
--------------------------------------------------------------------------------
/example/icons/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/settings.png
--------------------------------------------------------------------------------
/example/icons/settings@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/settings@2x.png
--------------------------------------------------------------------------------
/example/icons/settings@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/icons/settings@3x.png
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | import Navigator from 'native-navigation';
2 |
3 | Navigator.registerScreen(
4 | 'SharedElementToScreen',
5 | () => require('./screens/SharedElementToScreen')
6 | );
7 | Navigator.registerScreen(
8 | 'SharedElementFromScreen',
9 | () => require('./screens/SharedElementFromScreen')
10 | );
11 | Navigator.registerScreen('NavigationBar', () =>
12 | require('./screens/NavigationBar')
13 | );
14 | Navigator.registerScreen(
15 | 'ScreenOne',
16 | () => require('./screens/NavigationExampleScreen'),
17 | {
18 | initialConfig: {
19 | // title: 'FooBar',
20 | },
21 | }
22 | );
23 | Navigator.registerScreen(
24 | 'TabScreen',
25 | () => require('./screens/TabScreen'),
26 | {
27 | mode: 'tabs',
28 | }
29 | );
30 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | react_native_path = '../../node_modules/react-native'
2 |
3 | use_frameworks!
4 |
5 | project 'native-navigation.xcodeproj'
6 |
7 | target 'native-navigation' do
8 | pod 'native-navigation', :path => '../../'
9 |
10 | # To use CocoaPods with React Native, you need to add this specific Yoga spec as well
11 | pod 'yoga', :path => react_native_path + '/ReactCommon/yoga/yoga.podspec'
12 |
13 | # Third party deps used for CxxBridge
14 | pod 'DoubleConversion', :podspec => react_native_path + '/third-party-podspecs/DoubleConversion.podspec'
15 | pod 'GLog', :podspec => react_native_path + '/third-party-podspecs/GLog.podspec'
16 | pod 'Folly', :podspec => react_native_path + '/third-party-podspecs/Folly.podspec'
17 |
18 | pod 'React', :path => react_native_path, :subspecs => [
19 | 'Core',
20 | 'DevSupport',
21 | 'CxxBridge',
22 | 'RCTText',
23 | 'RCTNetwork',
24 | 'RCTWebSocket', # needed for debugging
25 | 'RCTAnimation',
26 | 'RCTImage',
27 | 'RCTNetwork'
28 | # Add any other subspecs you want to use in your project
29 | ]
30 | end
31 |
--------------------------------------------------------------------------------
/example/ios/bundler:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'bundler' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("bundler", "bundler")
18 |
--------------------------------------------------------------------------------
/example/ios/fuzzy_match:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'fuzzy_match' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("fuzzy_match", "fuzzy_match")
18 |
--------------------------------------------------------------------------------
/example/ios/native-navigation.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/native-navigation/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // native-navigation
4 | //
5 | // Created by bachand on 02/11/2017.
6 | // Copyright (c) 2017 bachand. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import NativeNavigation
11 | import React
12 |
13 | @UIApplicationMain
14 | class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate, ReactNavigationCoordinatorDelegate {
15 |
16 | var window: UIWindow?
17 | var bridge: RCTBridge?
18 | var reactViewController: ReactViewController?
19 |
20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
21 |
22 | bridge = RCTBridge(delegate: self, launchOptions: nil)
23 | ReactNavigationCoordinator.sharedInstance.bridge = bridge
24 | ReactNavigationCoordinator.sharedInstance.delegate = self
25 |
26 | let rootViewController = ViewController()
27 | let navigationController = UINavigationController(rootViewController: rootViewController)
28 |
29 | window = UIWindow(frame: UIScreen.main.bounds)
30 | window?.rootViewController = navigationController
31 | window?.makeKeyAndVisible()
32 |
33 | return true
34 | }
35 |
36 | func applicationWillResignActive(_ application: UIApplication) {
37 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
38 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
39 | }
40 |
41 | func applicationDidEnterBackground(_ application: UIApplication) {
42 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
43 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
44 | }
45 |
46 | func applicationWillEnterForeground(_ application: UIApplication) {
47 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
48 | }
49 |
50 | func applicationDidBecomeActive(_ application: UIApplication) {
51 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
52 | }
53 |
54 | func applicationWillTerminate(_ application: UIApplication) {
55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
56 | }
57 |
58 | func sourceURL(for bridge: RCTBridge!) -> URL! {
59 | return URL(string: "http://localhost:8081/example/index.bundle?platform=ios&dev=true")
60 | }
61 |
62 | func rootViewController(forCoordinator coordinator: ReactNavigationCoordinator) -> UIViewController? {
63 | return window?.rootViewController
64 | }
65 |
66 | func flowCoordinatorForId(_ name: String) -> ReactFlowCoordinator? {
67 | return nil
68 | }
69 |
70 | func registerReactDeepLinkUrl(_ deepLinkUrl: String) {
71 |
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/example/ios/native-navigation/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ios-marketing",
45 | "size" : "1024x1024",
46 | "scale" : "1x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/example/ios/native-navigation/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/example/ios/native-navigation/Images.xcassets/NavBarButtonPlus.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "universal",
13 | "filename" : "NavBarButtonPlus@3x.png",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/example/ios/native-navigation/Images.xcassets/NavBarButtonPlus.imageset/NavBarButtonPlus@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/example/ios/native-navigation/Images.xcassets/NavBarButtonPlus.imageset/NavBarButtonPlus@3x.png
--------------------------------------------------------------------------------
/example/ios/native-navigation/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIViewControllerBasedStatusBarAppearance
6 |
7 | NSAppTransportSecurity
8 |
9 | NSExceptionDomains
10 |
11 | localhost
12 |
13 | NSTemporaryExceptionAllowsInsecureHTTPLoads
14 |
15 |
16 |
17 |
18 | CFBundleDevelopmentRegion
19 | en
20 | CFBundleExecutable
21 | $(EXECUTABLE_NAME)
22 | CFBundleIdentifier
23 | $(PRODUCT_BUNDLE_IDENTIFIER)
24 | CFBundleInfoDictionaryVersion
25 | 6.0
26 | CFBundleName
27 | $(PRODUCT_NAME)
28 | CFBundlePackageType
29 | APPL
30 | CFBundleShortVersionString
31 | 1.0
32 | CFBundleSignature
33 | ????
34 | CFBundleVersion
35 | 1
36 | LSRequiresIPhoneOS
37 |
38 | UILaunchStoryboardName
39 | LaunchScreen
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/example/ios/native-navigation/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // native-navigation
4 | //
5 | // Created by bachand on 02/11/2017.
6 | // Copyright (c) 2017 bachand. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import NativeNavigation
11 |
12 | final class ViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | title = "Root"
17 |
18 | let pushButton1 = UIButton(type: .roundedRect)
19 | pushButton1.setTitle("Push ScreenOne", for: .normal)
20 | pushButton1.addTarget(self, action: #selector(pushScreenOne(sender:)), for: .touchUpInside)
21 | pushButton1.frame = CGRect(x: 0, y: 100, width: 320, height: 60)
22 | view.addSubview(pushButton1)
23 |
24 | let pushButton2 = UIButton(type: .roundedRect)
25 | pushButton2.setTitle("Push TabScreen", for: .normal)
26 | pushButton2.addTarget(self, action: #selector(pushTabScreen(sender:)), for: .touchUpInside)
27 | pushButton2.frame = CGRect(x: 0, y: 160, width: 320, height: 60)
28 | view.addSubview(pushButton2)
29 |
30 | // let button = UIButton(type: .roundedRect)
31 | // button.setTitle("Push ScreenOne", for: .normal)
32 | // button.addTarget(self, action: "pushScreenOne", for: .touchUpInside)
33 | // view.addSubview(button)
34 |
35 | // UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
36 | // [button setTitle:@"Push ScreenOne" forState:UIControlStateNormal];
37 | // button.frame = CGRectMake(0, 100, 320, 140);
38 | // [button addTarget:self action:@selector(pushScreenOne) forControlEvents:UIControlEventTouchUpInside];
39 | // [self.view addSubview:button];
40 | //
41 | // UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
42 | // [button2 setTitle:@"Push TabBar" forState:UIControlStateNormal];
43 | // button2.frame = CGRectMake(0, 300, 320, 140);
44 | // [button2 addTarget:self action:@selector(pushTabBar) forControlEvents:UIControlEventTouchUpInside];
45 | // [self.view addSubview:button2];
46 |
47 |
48 | view.backgroundColor = .white
49 | }
50 |
51 | func pushScreenOne(sender: UIButton) {
52 | let screenOne = ReactViewController(moduleName: "ScreenOne")
53 | navigationController?.pushReactViewController(screenOne, animated: true)
54 | }
55 |
56 | func pushTabScreen(sender: UIButton) {
57 | let tabScreen = ReactTabBarController(moduleName: "TabScreen")
58 | self.presentReactViewController(tabScreen, animated: true, completion: nil)
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/example/ios/pod:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'pod' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("cocoapods", "pod")
18 |
--------------------------------------------------------------------------------
/example/ios/sandbox-pod:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'sandbox-pod' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("cocoapods", "sandbox-pod")
18 |
--------------------------------------------------------------------------------
/example/ios/xcodeproj:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # frozen_string_literal: true
3 | #
4 | # This file was generated by Bundler.
5 | #
6 | # The application 'xcodeproj' is installed as part of a gem, and
7 | # this file is here to facilitate running it.
8 | #
9 |
10 | require "pathname"
11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
12 | Pathname.new(__FILE__).realpath)
13 |
14 | require "rubygems"
15 | require "bundler/setup"
16 |
17 | load Gem.bin_path("xcodeproj", "xcodeproj")
18 |
--------------------------------------------------------------------------------
/example/screens/NavigationBar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Dimensions } from 'react-native';
4 |
5 | import Navigator from 'native-navigation';
6 |
7 | import LoremImage from '../components/LoremImage';
8 | import Screen from '../components/Screen';
9 | import Row from '../components/Row';
10 |
11 | const propTypes = {};
12 | const defaultProps = {};
13 | const contextTypes = {
14 | nativeNavigationInstanceId: PropTypes.string,
15 | };
16 |
17 | const { width } = Dimensions.get('window');
18 |
19 | export default class NavigationExampleScreen extends Component {
20 | state = {};
21 |
22 | render() {
23 | return (
24 |
25 |
26 |
27 | this.setState({
30 | title: 'A title',
31 | subtitle: undefined,
32 | rightButtons: undefined,
33 | })}
34 | />
35 | this.setState({
38 | title: 'A title',
39 | subtitle: 'A subtitle',
40 | rightButtons: undefined,
41 | })}
42 | />
43 | this.setState({
46 | title: 'A title',
47 | subtitle: undefined,
48 | rightButtons: [{ title: 'Hello' }],
49 | })}
50 | />
51 | this.setState({
54 | title: 'A title',
55 | subtitle: undefined,
56 | rightButtons: [{ systemItem: 'add' }],
57 | })}
58 | />
59 | this.setState({
62 | title: 'A title',
63 | subtitle: undefined,
64 | rightButtons: [{ systemItem: 'add' }, { systemItem: 'edit' }],
65 | })}
66 | />
67 |
68 | );
69 | }
70 | }
71 |
72 | NavigationExampleScreen.defaultProps = defaultProps;
73 | NavigationExampleScreen.propTypes = propTypes;
74 | NavigationExampleScreen.contextTypes = contextTypes;
75 |
--------------------------------------------------------------------------------
/example/screens/NavigationExampleScreen.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | Component,
3 | } from 'react';
4 | import PropTypes from 'prop-types';
5 | import {
6 | Dimensions,
7 | } from 'react-native';
8 |
9 | import Navigator from 'native-navigation';
10 |
11 | import LoremImage from '../components/LoremImage';
12 | import Screen from '../components/Screen';
13 | import Row from '../components/Row';
14 |
15 | const propTypes = {};
16 | const defaultProps = {};
17 | const contextTypes = {
18 | nativeNavigationInstanceId: PropTypes.string,
19 | };
20 |
21 | const { width } = Dimensions.get('window');
22 |
23 | export default class NavigationExampleScreen extends Component {
24 | render() {
25 | return (
26 |
27 |
31 |
35 | Navigator.present('ScreenOne')}
38 | />
39 | Navigator.push('ScreenOne')}
42 | />
43 | Navigator.pop()}
46 | />
47 | Navigator.dismiss()}
50 | />
51 | Navigator.push('SharedElementFromScreen')}
54 | />
55 | Navigator.push('NavigationBar')}
58 | />
59 |
60 | );
61 | }
62 | }
63 |
64 | NavigationExampleScreen.defaultProps = defaultProps;
65 | NavigationExampleScreen.propTypes = propTypes;
66 | NavigationExampleScreen.contextTypes = contextTypes;
67 |
--------------------------------------------------------------------------------
/example/screens/SharedElementFromScreen.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | Component,
3 | } from 'react';
4 | import Navigator from 'native-navigation';
5 |
6 | import ImageRow from '../components/ImageRow';
7 | import Screen from '../components/Screen';
8 |
9 | export default class SharedElementFromScreen extends Component {
10 | render() {
11 | return (
12 |
13 | {Array.from({ length: 8 }).map((_, id) => (
14 |
19 | Navigator.push('SharedElementToScreen', { id }, {
22 | transitionGroup: `${id}`,
23 | })}
24 | />
25 |
26 | ))}
27 |
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/example/screens/SharedElementToScreen.js:
--------------------------------------------------------------------------------
1 | import React, {
2 | Component,
3 | } from 'react';
4 | import PropTypes from 'prop-types';
5 | import {
6 | View,
7 | Dimensions,
8 | } from 'react-native';
9 |
10 | import LoremImage from '../components/LoremImage';
11 | import LoremHeader from '../components/LoremHeader';
12 | import LoremParagraph from '../components/LoremParagraph';
13 | import Screen from '../components/Screen';
14 | import theme from '../util/theme';
15 |
16 | const propTypes = {
17 | id: PropTypes.number.isRequired,
18 | };
19 | const defaultProps = {};
20 |
21 | const { width } = Dimensions.get('window');
22 |
23 | export default class SharedElementToScreen extends Component {
24 | render() {
25 | const { id } = this.props;
26 | return (
27 |
28 |
33 |
41 |
42 |
43 | {Array.from({ length: 8 }).map((_, i) => (
44 |
52 |
55 |
56 | ))}
57 |
58 | );
59 | }
60 | }
61 |
62 | SharedElementToScreen.defaultProps = defaultProps;
63 | SharedElementToScreen.propTypes = propTypes;
64 |
--------------------------------------------------------------------------------
/example/screens/TabScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { TabBar, Tab } from 'native-navigation';
3 |
4 | const propTypes = {};
5 | const defaultProps = {};
6 |
7 | export default class TabScreen extends React.Component {
8 | render() {
9 | return (
10 |
13 |
18 |
23 |
28 |
33 |
34 | );
35 | }
36 | }
37 |
38 | TabScreen.defaultProps = defaultProps;
39 | TabScreen.propTypes = propTypes;
40 |
--------------------------------------------------------------------------------
/example/util/platformTouchable.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | TouchableNativeFeedback,
5 | View,
6 | Platform,
7 | } from 'react-native';
8 |
9 | export const touchablePropTypes = {
10 | children: PropTypes.element.isRequired,
11 | disabled: PropTypes.bool,
12 | onPress: PropTypes.func,
13 | };
14 |
15 | export const touchableDefaultProps = {
16 | disabled: false,
17 | };
18 |
19 | const supportsRipple = Platform.select({
20 | android: () => Platform.Version >= 21,
21 | ios: () => false,
22 | });
23 |
24 | export function createPlatformTouchableComponent(options) {
25 | class PlatformTouchable extends React.Component {
26 | renderNativeFeedback(color) {
27 | let content = this.props.children;
28 | if (this.props.children.type !== View) {
29 | content = {this.props.children};
30 | }
31 | return (
32 |
38 | {content}
39 |
40 | );
41 | }
42 |
43 | render() {
44 | const { color } = this.props;
45 | if (supportsRipple()) {
46 | return this.renderNativeFeedback(color);
47 | }
48 | return options.renderDefaultTouchable(this.props, color);
49 | }
50 | }
51 |
52 | PlatformTouchable.displayName = options.displayName;
53 | PlatformTouchable.propTypes = options.propTypes;
54 | PlatformTouchable.defaultProps = options.defaultProps || touchableDefaultProps;
55 |
56 | return PlatformTouchable;
57 | }
58 |
--------------------------------------------------------------------------------
/example/util/theme.js:
--------------------------------------------------------------------------------
1 |
2 | const size = {
3 | horizontalPadding: 24,
4 | verticalPadding: 16,
5 | };
6 |
7 | const color = {
8 | darkText: '#484848',
9 | image: '#484848',
10 | lightGray: '#f7f7f7',
11 | };
12 |
13 | const font = {
14 | title: {
15 | color: color.darkText,
16 | fontSize: 32,
17 | lineHeight: 36,
18 | fontWeight: 'bold',
19 | },
20 | large: {
21 | color: color.darkText,
22 | fontSize: 19,
23 | lineHeight: 24,
24 | },
25 | small: {
26 | color: color.darkText,
27 | fontSize: 15,
28 | lineHeight: 18,
29 | },
30 | };
31 |
32 | module.exports = {
33 | size,
34 | font,
35 | color,
36 | aspectRatio: 1 / 1.6,
37 | };
38 |
--------------------------------------------------------------------------------
/example/util/titleForId.js:
--------------------------------------------------------------------------------
1 | const HEADERS = [
2 | 'Lorem ipsum dolor sit amet, magna ante nec.',
3 | 'Risus nibh.',
4 | 'Ultricies non, amet penatibus fermentum.',
5 | 'Nunc wisi donec.',
6 | 'Molestiae integer.',
7 | 'Tincidunt aliquet justo.',
8 | 'Pellentesque ullamcorper.',
9 | 'Mattis sit, posuere ut quam.',
10 | 'Sodales a erat, felis a.',
11 | 'Ac interdum, suspendisse lacus dignissim.',
12 | 'Urna augue et, magna ipsum dictum.',
13 | 'Varius vestibulum vulputate.',
14 | 'Ut eros, in praesent nunc, dolor torquent.',
15 | 'Et in, nisl a, eleifend risus nulla.',
16 | 'Urna sit lacus, faucibus tortor arcu.',
17 | 'Vehicula porta et, varius duis turpis.',
18 | 'Justo in, duis massa.',
19 | 'Sagittis ac.',
20 | 'Tempus velit donec.',
21 | 'Aptent auctor, mauris suspendisse eu.',
22 | ];
23 |
24 | module.exports = function titleForId(id) {
25 | return HEADERS[id % HEADERS.length];
26 | };
27 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Apr 17 12:11:17 PDT 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/js');
2 |
--------------------------------------------------------------------------------
/lib/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply from: 'gradle-maven-push.gradle'
3 |
4 | android {
5 | compileSdkVersion 25
6 | buildToolsVersion "25.0.2"
7 |
8 | defaultConfig {
9 | minSdkVersion 16
10 | targetSdkVersion 25
11 | }
12 |
13 | packagingOptions {
14 | exclude 'META-INF/LICENSE'
15 | exclude 'META-INF/DEPENDENCIES.txt'
16 | exclude 'META-INF/LICENSE.txt'
17 | exclude 'META-INF/NOTICE.txt'
18 | exclude 'META-INF/NOTICE'
19 | exclude 'META-INF/DEPENDENCIES'
20 | exclude 'META-INF/notice.txt'
21 | exclude 'META-INF/license.txt'
22 | exclude 'META-INF/dependencies.txt'
23 | exclude 'META-INF/LGPL2.1'
24 | }
25 |
26 | lintOptions {
27 | disable 'InvalidPackage'
28 | }
29 |
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_7
32 | targetCompatibility JavaVersion.VERSION_1_7
33 | }
34 | }
35 |
36 | dependencies {
37 | compile 'com.android.support:appcompat-v7:25.2.0'
38 | compile 'com.android.support:support-annotations:25.2.0'
39 | compile 'com.android.support:design:25.2.0'
40 | compile 'com.fasterxml.jackson.core:jackson-databind:2.8.3'
41 | compile 'com.facebook.fresco:fresco:1.0.1'
42 | compile 'com.facebook.fresco:imagepipeline-okhttp3:1.0.1'
43 | provided 'com.facebook.react:react-native:+'
44 | }
45 |
--------------------------------------------------------------------------------
/lib/android/gradle.properties:
--------------------------------------------------------------------------------
1 | VERSION_CODE=2
2 | VERSION_NAME=0.1.0
3 | GROUP=com.airbnb.android
4 |
5 | POM_DESCRIPTION=Native Navigation for React Native
6 | POM_URL=https://github.com/airbnb/native-navigation/tree/new-scv
7 | POM_SCM_URL=https://github.com/airbnb/native-navigation/tree/new-scv
8 | POM_SCM_CONNECTION=scm:git@github.com:airbnb/native-navigation.git
9 | POM_SCM_DEV_CONNECTION=scm:git@github.com:airbnb/native-navigation.git
10 | POM_LICENSE_NAME=MIT
11 | POM_LICENSE_URL=https://github.com/airbnb/native-navigation/blob/master/LICENSE
12 | POM_LICENSE_DIST=repo
13 | POM_DEVELOPER_ID=airbnb
14 | POM_DEVELOPER_NAME=Leland Richardson
15 |
16 | POM_NAME=Native Navigation
17 | POM_ARTIFACT_ID=native-navigation
18 | POM_PACKAGING=aar
19 |
--------------------------------------------------------------------------------
/lib/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/airbnb/native-navigation/9cf50bf9b751b40778f473f3b19fcfe2c4d40599/lib/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/lib/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Feb 21 23:07:53 PST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/lib/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lib/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/lib/android/src/main/gen/com/airbnb/android/BuildConfig.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.airbnb.android;
4 |
5 | /* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
6 | public final class BuildConfig {
7 | public final static boolean DEBUG = Boolean.parseBoolean(null);
8 | }
--------------------------------------------------------------------------------
/lib/android/src/main/gen/com/airbnb/android/Manifest.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.airbnb.android;
4 |
5 | /* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
6 | public final class Manifest {
7 | }
--------------------------------------------------------------------------------
/lib/android/src/main/gen/com/airbnb/android/R.java:
--------------------------------------------------------------------------------
1 | /*___Generated_by_IDEA___*/
2 |
3 | package com.airbnb.android;
4 |
5 | /* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
6 | public final class R {
7 | }
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ActivityUtils.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.graphics.Point;
7 | import android.graphics.Rect;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.view.Window;
10 | import android.view.WindowManager;
11 |
12 | final class ActivityUtils {
13 | private ActivityUtils() {
14 | }
15 |
16 | static boolean hasActivityStopped(Activity activity) {
17 | return activity.getWindow() == null || activity.isFinishing();
18 | }
19 |
20 | private static int getAndroidDimension(Context context, String resourceIdName) {
21 | Resources resources = context.getResources();
22 | try {
23 | int id = resources.getIdentifier(resourceIdName, "dimen", "android");
24 | return id > 0 ? resources.getDimensionPixelSize(id) : 0;
25 | } catch (Resources.NotFoundException exception) {
26 | return 0;
27 | }
28 | }
29 |
30 | private static int getStatusBarHeight(Activity activity) {
31 | Rect rectangle = new Rect();
32 | Window window = activity.getWindow();
33 | window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
34 | if (rectangle.top > 0) {
35 | return rectangle.top;
36 | }
37 | return getAndroidDimension(activity, "status_bar_height");
38 | }
39 |
40 | /**
41 | * Returns the height of the standard status bar and action bar height. Should be called AFTER the
42 | * initial view layout pass (e.g. wrapped in a post() call).
43 | */
44 | static int getStatusBarActionBarHeight(AppCompatActivity activity) {
45 | return getStatusBarHeight(activity) + activity.getSupportActionBar().getHeight();
46 | }
47 |
48 | static boolean hasTranslucentStatusBar(Window window) {
49 | if (AndroidVersion.isAtLeastKitKat()) {
50 | int flags = window.getAttributes().flags;
51 | return (flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) ==
52 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
53 | }
54 | return false;
55 | }
56 |
57 | static int getNavBarHeight(Context context) {
58 | if (ActivityUtils.isPortraitMode(context)) {
59 | return getAndroidDimension(context, "navigation_bar_height");
60 | }
61 | return getAndroidDimension(context, "navigation_bar_height_landscape");
62 | }
63 |
64 | private static boolean isPortraitMode(Context context) {
65 | Point point = ViewUtils.getScreenSize(context);
66 | return point.x < point.y;
67 | }
68 |
69 | static boolean isLandscapeMode(Context context) {
70 | return !isPortraitMode(context);
71 | }
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/AndroidVersion.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.os.Build.VERSION;
4 | import android.os.Build.VERSION_CODES;
5 |
6 | final class AndroidVersion {
7 | static boolean isAtLeastJellyBeanMR1() {
8 | return VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1;
9 | }
10 |
11 | static boolean isAtLeastJellyBeanMR2() {
12 | return VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR2;
13 | }
14 |
15 | static boolean isAtLeastKitKat() {
16 | return VERSION.SDK_INT >= VERSION_CODES.KITKAT;
17 | }
18 |
19 | static boolean isAtLeastLollipop() {
20 | return VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP;
21 | }
22 |
23 | static boolean isAtLeastMarshmallow() {
24 | return VERSION.SDK_INT >= VERSION_CODES.M;
25 | }
26 |
27 | static boolean isAtLeastLollipopMR1() {
28 | return VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP_MR1;
29 | }
30 |
31 | static boolean isJellyBean() {
32 | return VERSION.SDK_INT == VERSION_CODES.JELLY_BEAN;
33 | }
34 |
35 | static boolean isAtLeastNougat() {
36 | return VERSION.SDK_INT >= VERSION_CODES.N;
37 | }
38 |
39 | private AndroidVersion() {
40 | // Prevent users from instantiating this class.
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/BackStack.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.support.annotation.Nullable;
4 | import android.support.v4.app.Fragment;
5 |
6 | import com.facebook.react.bridge.Promise;
7 |
8 | import java.util.Stack;
9 |
10 | class BackStack {
11 |
12 | private final Stack fragments = new Stack<>();
13 | private final String tag;
14 | private final ScreenCoordinator.PresentAnimation animation;
15 | private final Promise promise;
16 |
17 | BackStack(String tag, ScreenCoordinator.PresentAnimation animation, Promise promise) {
18 | this.tag = tag;
19 | this.animation = animation;
20 | this.promise = promise;
21 | }
22 |
23 | String getTag() {
24 | return tag;
25 | }
26 |
27 | ScreenCoordinator.PresentAnimation getAnimation() {
28 | return animation;
29 | }
30 |
31 | Promise getPromise() {
32 | return promise;
33 | }
34 |
35 | @Nullable
36 | Fragment peekFragment() {
37 | if (fragments.isEmpty()) {
38 | return null;
39 | }
40 | return fragments.peek();
41 | }
42 |
43 | void pushFragment(Fragment fragment) {
44 | fragments.push(fragment);
45 | }
46 |
47 | Fragment popFragment() {
48 | if (fragments.isEmpty()) {
49 | throw new IllegalStateException("Cannot pop empty stack.");
50 | }
51 | return fragments.remove(fragments.size() - 1);
52 | }
53 |
54 | int getSize() {
55 | return fragments.size();
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | return "BackStack{" + ", tag='" + tag +
61 | ", size=" + fragments.size() +
62 | ", animation=" + animation +
63 | ", promise?=" + (promise != null) +
64 | '}';
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/BundleBuilder.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.os.Bundle;
4 |
5 | /** A Bundle that doesn't suck. Allows you to chain method calls as you'd expect. */
6 | public class BundleBuilder extends ExtendableBundleBuilder {
7 | public BundleBuilder() {
8 | }
9 |
10 | public BundleBuilder(Bundle bundle) {
11 | putAll(bundle);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/FragmentSharedElementTransition.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build;
5 | import android.support.v4.view.animation.FastOutSlowInInterpolator;
6 | import android.transition.ChangeBounds;
7 | import android.transition.ChangeImageTransform;
8 | import android.transition.ChangeTransform;
9 | import android.transition.Fade;
10 | import android.transition.TransitionSet;
11 |
12 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
13 | class FragmentSharedElementTransition extends TransitionSet {
14 |
15 | public FragmentSharedElementTransition() {
16 | addTransition(new ChangeBounds());
17 | addTransition(new Fade());
18 | addTransition(new ChangeImageTransform());
19 | addTransition(new ChangeTransform());
20 | setInterpolator(new FastOutSlowInInterpolator());
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/JacksonUtils.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.fasterxml.jackson.databind.JavaType;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.fasterxml.jackson.databind.ObjectReader;
7 | import com.fasterxml.jackson.databind.ObjectWriter;
8 |
9 | import java.io.IOException;
10 | import java.lang.reflect.Type;
11 | import java.util.List;
12 |
13 | public final class JacksonUtils {
14 | private JacksonUtils() {
15 | }
16 |
17 | public static ObjectWriter writerForType(ObjectMapper mapper, Type type) {
18 | JavaType javaType = mapper.getTypeFactory().constructType(type);
19 | return mapper.writerFor(javaType);
20 | }
21 |
22 | public static ObjectReader readerForType(ObjectMapper mapper, Type type) {
23 | JavaType javaType = mapper.getTypeFactory().constructType(type);
24 | return mapper.readerFor(javaType);
25 | }
26 |
27 | /** Convenient way to read a JSON Array String into a List */
28 | public static List readJsonArray(ObjectMapper objectMapper, String value) {
29 | ObjectReader reader = JacksonUtils.readerForType(objectMapper, List.class);
30 | //noinspection OverlyBroadCatchBlock
31 | try {
32 | return reader.readValue(value);
33 | } catch (IOException e) {
34 | throw new RuntimeException(e);
35 | }
36 | }
37 |
38 | /** Convenient way to write a List into a JSON Array string */
39 | public static String writeJsonArray(ObjectMapper objectMapper, List value) {
40 | ObjectWriter writer = JacksonUtils.writerForType(objectMapper, List.class);
41 | try {
42 | return writer.writeValueAsString(value);
43 | } catch (JsonProcessingException e) {
44 | throw new RuntimeException(e);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/NativeNavigationPackage.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.Arrays;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | @SuppressWarnings("unused")
14 | public class NativeNavigationPackage implements ReactPackage {
15 | @Override public List createNativeModules(ReactApplicationContext reactContext) {
16 | return Collections.singletonList(
17 | new NavigatorModule(reactContext, ReactNavigationCoordinator.sharedInstance));
18 | }
19 |
20 | @Override public List> createJSModules() {
21 | return Collections.emptyList();
22 | }
23 |
24 | @SuppressWarnings("rawtypes") @Override
25 | public List createViewManagers(ReactApplicationContext reactContext) {
26 | return Arrays.asList(
27 | new SharedElementGroupManager(),
28 | new SharedElementViewManager(ReactNavigationCoordinator.sharedInstance),
29 | new TabBarViewManager(),
30 | new TabViewManager()
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/NavigationImplementation.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.support.v7.app.ActionBar;
4 | import android.view.Menu;
5 | import android.view.MenuItem;
6 | import com.facebook.react.bridge.ReadableMap;
7 |
8 | interface NavigationImplementation {
9 | void reconcileNavigationProperties(
10 | ReactInterface component,
11 | ReactToolbar toolbar,
12 | ActionBar bar,
13 | ReadableMap previous,
14 | ReadableMap next,
15 | boolean firstCall
16 | );
17 |
18 | void prepareOptionsMenu(
19 | ReactInterface component,
20 | ReactToolbar toolbar,
21 | ActionBar bar,
22 | Menu menu,
23 | ReadableMap previous,
24 | ReadableMap next
25 | );
26 |
27 | boolean onOptionsItemSelected(
28 | ReactInterface component,
29 | ReactToolbar toolbar,
30 | ActionBar bar,
31 | MenuItem item,
32 | ReadableMap config
33 | );
34 |
35 | float getBarHeight(
36 | ReactInterface component,
37 | ReactToolbar toolbar,
38 | ActionBar actionBar,
39 | ReadableMap config,
40 | boolean firstCall
41 | );
42 |
43 | void makeTabItem(
44 | ReactBottomNavigation bottomNavigation,
45 | Menu menu,
46 | int index,
47 | Integer itemId,
48 | ReadableMap config
49 | );
50 |
51 | void reconcileTabBarProperties(
52 | ReactBottomNavigation bottomNavigation,
53 | Menu menu,
54 | ReadableMap prev,
55 | ReadableMap next
56 | );
57 | }
58 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactActivity.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.view.Gravity;
6 | import android.view.ViewGroup;
7 | import com.airbnb.android.R;
8 |
9 | public abstract class ReactActivity extends ReactAwareActivity implements ScreenCoordinatorComponent {
10 | private static final String TAG = ReactActivity.class.getSimpleName();
11 |
12 | private ScreenCoordinator screenCoordinator;
13 |
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | ScreenCoordinatorLayout container = new ScreenCoordinatorLayout(this);
18 | container.setLayoutParams(
19 | new ViewGroup.LayoutParams(
20 | ViewGroup.LayoutParams.MATCH_PARENT,
21 | ViewGroup.LayoutParams.MATCH_PARENT
22 | )
23 | );
24 | container.setForegroundGravity(Gravity.CENTER);
25 | container.setId(R.id.react_activity_container_id);
26 | setContentView(container);
27 |
28 | screenCoordinator = new ScreenCoordinator(this, container, savedInstanceState);
29 |
30 | if (savedInstanceState == null) {
31 | screenCoordinator.presentScreen(
32 | getInitialScreenName(),
33 | getInitialScreenProps(),
34 | getInitialScreenOptions(),
35 | null
36 | );
37 | }
38 | }
39 |
40 | protected @Nullable String getInitialScreenName() {
41 | return null;
42 | }
43 |
44 | protected @Nullable Bundle getInitialScreenProps() {
45 | return null;
46 | }
47 |
48 | protected @Nullable Bundle getInitialScreenOptions() {
49 | return null;
50 | }
51 |
52 | @Override
53 | public ScreenCoordinator getScreenCoordinator() {
54 | return screenCoordinator;
55 | }
56 |
57 | @Override
58 | public void onBackPressed() {
59 | screenCoordinator.onBackPressed();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactAwareActivityFacade.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | interface ReactAwareActivityFacade {
8 | // @formatter:off
9 | void runOnUiThread(Runnable action);
10 | Context getBaseContext();
11 | void startActivityForResult(Intent intent, int requestCode, Bundle bundle);
12 | void startActivityForResult(Intent intent, int requestCode);
13 | void setResult(int resultCode, Intent resultIntent);
14 | void finish();
15 | // @formatter:on
16 | }
17 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactExposedActivityParams.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Parcelable;
8 |
9 | import com.facebook.react.bridge.ReadableMap;
10 | import com.fasterxml.jackson.databind.ObjectMapper;
11 |
12 | import static com.airbnb.android.react.navigation.ReactExposedActivityParamsConstants.KEY_ARGUMENT;
13 |
14 | public class ReactExposedActivityParams {
15 | private final ObjectMapper objectMapper;
16 | private final String key;
17 | private final Class extends Activity> klass;
18 | private final Class extends Parcelable> argumentType;
19 | private static final Class DEFAULT_CLASS = Bundle.class;
20 |
21 | public ReactExposedActivityParams(ObjectMapper objectMapper, String key,
22 | Class extends Activity> klass) {
23 | this(objectMapper, key, klass, DEFAULT_CLASS);
24 | }
25 |
26 | public ReactExposedActivityParams(ObjectMapper objectMapper, String key,
27 | Class extends Activity> klass,
28 | Class extends Parcelable> argumentType) {
29 | this.objectMapper = objectMapper;
30 | this.key = key;
31 | this.klass = klass;
32 | this.argumentType = argumentType;
33 | }
34 |
35 | /**
36 | * Converts the provided {@link ReadableMap} arguments into an {@link Intent} used for launching
37 | * the {@link Activity} associated with this object. The {@code arguments} will be used as {@link
38 | * Intent} {@code extras} and converted according to the {@code argumentType} field. By default,
39 | * all activities will take a {@link Bundle} extra, however, if a custom {@code argumentType}
40 | * class is provided, the {@code arguments} will be automatically converted into an object of the
41 | * type {@code argumentType} instead, by using Jackson to deserialize the contents of {@code
42 | * arguments}.
43 | */
44 | Intent toIntent(Context context, ReadableMap arguments) {
45 | Intent intent = new Intent(context, klass);
46 | if (argumentType.equals(DEFAULT_CLASS)) {
47 | intent.putExtras(ConversionUtil.toBundle(arguments));
48 | } else {
49 | intent.putExtra(KEY_ARGUMENT, ConversionUtil.toType(objectMapper, arguments, argumentType));
50 | }
51 | return intent;
52 | }
53 |
54 | String key() {
55 | return key;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactExposedActivityParamsConstants.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | public final class ReactExposedActivityParamsConstants {
4 | public static final String KEY_ARGUMENT = "KEY_RN_ACTIVITY_ARGUMENT";
5 | }
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactInterface.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.support.v4.app.FragmentActivity;
4 |
5 | import com.facebook.react.ReactRootView;
6 | import com.facebook.react.bridge.ReadableMap;
7 |
8 | import java.util.Map;
9 |
10 | public interface ReactInterface {
11 | // @formatter:off
12 | String getInstanceId();
13 | ReactRootView getReactRootView();
14 | ReactToolbar getToolbar();
15 | boolean isDismissible();
16 | void signalFirstRenderComplete();
17 | void notifySharedElementAddition();
18 | FragmentActivity getActivity();
19 | void emitEvent(String eventName, Object object);
20 | void receiveNavigationProperties(ReadableMap properties);
21 | void dismiss();
22 | // @formatter:on
23 | }
24 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeActivity.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.os.Bundle;
4 | import android.os.Handler;
5 | import android.util.Log;
6 |
7 | import com.airbnb.android.R;
8 | import com.facebook.react.bridge.ReadableMap;
9 |
10 | public class ReactNativeActivity extends ReactAwareActivity {
11 | private static final String TAG = ReactNativeActivity.class.getSimpleName();
12 |
13 | private final Handler handler = new Handler();
14 | private ReactNavigationCoordinator reactNavigationCoordinator = ReactNavigationCoordinator.sharedInstance;
15 | private ReadableMap initialConfig = ConversionUtil.EMPTY_MAP;
16 | private ReactNativeFragment fragment;
17 |
18 | @Override
19 | protected void onCreate(Bundle savedInstanceState) {
20 | super.onCreate(savedInstanceState);
21 | Log.d(TAG, "onCreate");
22 |
23 | String moduleName = getIntent().getStringExtra(ReactNativeIntents.EXTRA_MODULE_NAME);
24 | initialConfig = reactNavigationCoordinator.getInitialConfigForModuleName(moduleName);
25 |
26 | setContentView(R.layout.activity_react_native);
27 | fragment = ReactNativeFragment.newInstance(getIntent().getExtras());
28 | getSupportFragmentManager().beginTransaction()
29 | .setAllowOptimization(true)
30 | .add(R.id.content, fragment)
31 | .commitNow();
32 | getSupportFragmentManager().executePendingTransactions();
33 | supportPostponeEnterTransition();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactNativeFragmentViewGroup.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.Nullable;
5 | import android.util.AttributeSet;
6 | import android.view.KeyEvent;
7 | import android.widget.FrameLayout;
8 |
9 | import com.facebook.react.ReactRootView;
10 |
11 | /**
12 | * Root ViewGroup for {@link ReactNativeFragment} that allows it to get KeyEvents.
13 | */
14 | public class ReactNativeFragmentViewGroup extends FrameLayout {
15 | public interface KeyListener {
16 | boolean onKeyDown(int keyCode, KeyEvent event);
17 | boolean onKeyUp(int keyCode, KeyEvent event);
18 | }
19 |
20 | @Nullable private ReactRootView reactRootView;
21 | @Nullable private KeyListener keyListener;
22 |
23 | public ReactNativeFragmentViewGroup(Context context) {
24 | super(context);
25 | }
26 |
27 | public ReactNativeFragmentViewGroup(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | }
30 |
31 | public ReactNativeFragmentViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
32 | super(context, attrs, defStyleAttr);
33 | }
34 |
35 | void setKeyListener(@Nullable KeyListener keyListener) {
36 | this.keyListener = keyListener;
37 | }
38 |
39 | @Override
40 | public boolean onKeyDown(int keyCode, KeyEvent event) {
41 | boolean handled = super.onKeyDown(keyCode, event);
42 | if (!handled && keyListener != null) {
43 | handled = keyListener.onKeyDown(keyCode, event);
44 | }
45 | return handled;
46 | }
47 |
48 | void unmountReactApplicationAfterAnimation(ReactRootView reactRootView) {
49 | this.reactRootView = reactRootView;
50 | }
51 |
52 | @Override
53 | protected void onAnimationEnd() {
54 | super.onAnimationEnd();
55 | if (reactRootView != null) {
56 | reactRootView.unmountReactApplication();
57 | reactRootView = null;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ReactScreenMode.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | public enum ReactScreenMode {
4 | SCREEN(ReactNativeActivity.class, ReactNativeActivity.class),
5 | TABS(ReactNativeTabActivity.class),
6 | UNKNOWN(ReactNativeActivity.class, ReactNativeActivity.class);
7 |
8 | public static ReactScreenMode fromString(String s) {
9 | try {
10 | return ReactScreenMode.valueOf(s.toUpperCase());
11 | } catch (Exception e) {
12 | return ReactScreenMode.UNKNOWN;
13 | }
14 | }
15 |
16 | // TODO: merge these fields. They should be the same.
17 | private Class pushActivityClass;
18 | private Class presentActivityClass;
19 |
20 | ReactScreenMode(
21 | Class pushActivityClass
22 | ) {
23 | this(pushActivityClass, pushActivityClass);
24 | }
25 |
26 | ReactScreenMode(
27 | Class pushActivityClass,
28 | Class presentActivityClass
29 | ) {
30 | this.pushActivityClass = pushActivityClass;
31 | this.presentActivityClass = presentActivityClass;
32 | }
33 |
34 | public Class getPushActivityClass() {
35 | return this.pushActivityClass;
36 | }
37 | public Class getPresentActivityClass() {
38 | return this.presentActivityClass;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/ScreenCoordinatorComponent.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | public interface ScreenCoordinatorComponent {
4 | ScreenCoordinator getScreenCoordinator();
5 | }
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/SharedElementGroupManager.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import com.airbnb.android.R;
4 | import com.facebook.react.common.MapBuilder;
5 | import com.facebook.react.uimanager.ThemedReactContext;
6 | import com.facebook.react.uimanager.ViewGroupManager;
7 | import com.facebook.react.uimanager.annotations.ReactProp;
8 | import com.facebook.react.views.view.ReactViewGroup;
9 |
10 | import java.util.Map;
11 |
12 | import static com.airbnb.android.react.navigation.ReactNativeUtils.VERSION_CONSTANT_KEY;
13 |
14 | public class SharedElementGroupManager extends ViewGroupManager {
15 | private static final String REACT_CLASS = "NativeNavigationSharedElementGroup";
16 | private static final int VERSION = 1;
17 |
18 | @Override
19 | public Map getExportedViewConstants() {
20 | return MapBuilder.builder()
21 | .put(VERSION_CONSTANT_KEY, VERSION)
22 | .build();
23 | }
24 |
25 | @Override
26 | public String getName() {
27 | return REACT_CLASS;
28 | }
29 |
30 | @Override
31 | public ReactViewGroup createViewInstance(ThemedReactContext context) {
32 | return new ReactViewGroup(context);
33 | }
34 |
35 | @ReactProp(name = "id")
36 | public void setIdentifier(ReactViewGroup view, String id) {
37 | view.setTag(R.id.react_shared_element_group_id, id);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/SharedElementViewManager.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.support.v4.view.ViewCompat;
4 | import android.view.View;
5 |
6 | import com.airbnb.android.R;
7 | import com.facebook.react.common.MapBuilder;
8 | import com.facebook.react.uimanager.ThemedReactContext;
9 | import com.facebook.react.uimanager.ViewGroupManager;
10 | import com.facebook.react.uimanager.annotations.ReactProp;
11 | import com.facebook.react.views.image.ReactImageView;
12 | import com.facebook.react.views.view.ReactViewGroup;
13 |
14 | import java.util.Map;
15 |
16 | import static com.airbnb.android.react.navigation.ReactNativeUtils.VERSION_CONSTANT_KEY;
17 |
18 | public class SharedElementViewManager extends ViewGroupManager {
19 | private static final String REACT_CLASS = "NativeNavigationSharedElement";
20 | private static final int VERSION = 1;
21 |
22 | private final ReactNavigationCoordinator coordinator;
23 |
24 | SharedElementViewManager(ReactNavigationCoordinator coordinator) {
25 | this.coordinator = coordinator;
26 | }
27 |
28 | @Override
29 | public Map getExportedViewConstants() {
30 | return MapBuilder.builder()
31 | .put(VERSION_CONSTANT_KEY, VERSION)
32 | .build();
33 | }
34 |
35 | @Override
36 | public String getName() {
37 | return REACT_CLASS;
38 | }
39 |
40 | @Override
41 | public ReactViewGroup createViewInstance(ThemedReactContext context) {
42 | return new ReactViewGroup(context);
43 | }
44 |
45 | @ReactProp(name = "id")
46 | public void setIdentifier(ReactViewGroup view, String id) {
47 | view.setTag(R.id.react_shared_element_transition_name, id);
48 | }
49 |
50 | @ReactProp(name = "nativeNavigationInstanceId")
51 | public void setInstanceId(ReactViewGroup view, String instanceId) {
52 | view.setTag(R.id.react_shared_element_screen_instance_id, instanceId);
53 | }
54 |
55 | @Override
56 | public void addView(ReactViewGroup parent, View child, int index) {
57 | String transitionName = (String) parent.getTag(R.id.react_shared_element_transition_name);
58 | String instanceId = (String) parent.getTag(R.id.react_shared_element_screen_instance_id);
59 | ReactInterface component = coordinator.componentFromId(instanceId);
60 |
61 | if (child instanceof ReactImageView) {
62 | ReactImageView iv = (ReactImageView) child;
63 | // TODO(lmr): do something to wait for image to load
64 | }
65 |
66 | ViewCompat.setTransitionName(child, transitionName);
67 | parent.addView(child, index);
68 |
69 | if (component != null) {
70 | component.notifySharedElementAddition();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/SimpleTransitionListener.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.annotation.TargetApi;
4 | import android.os.Build.VERSION_CODES;
5 | import android.transition.Transition;
6 | import android.transition.Transition.TransitionListener;
7 |
8 | @TargetApi(VERSION_CODES.KITKAT)
9 | public class SimpleTransitionListener implements TransitionListener {
10 | @Override public void onTransitionStart(Transition transition) {
11 | }
12 |
13 | @Override public void onTransitionEnd(Transition transition) {
14 | }
15 |
16 | @Override public void onTransitionCancel(Transition transition) {
17 | }
18 |
19 | @Override public void onTransitionPause(Transition transition) {
20 | }
21 |
22 | @Override public void onTransitionResume(Transition transition) {
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/TabBarView.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import com.facebook.react.bridge.ReadableMap;
8 |
9 | /**
10 | * This view is used as a data structure to hold configuration for a TabBar in a
11 | * ReactNativeTabActivity, and doesn't actually render anything that will be visible
12 | * to the user.
13 | */
14 | public class TabBarView extends ViewGroup {
15 |
16 | private ReadableMap prevConfig = ConversionUtil.EMPTY_MAP;
17 | private ReadableMap renderedConfig = ConversionUtil.EMPTY_MAP;
18 |
19 | public TabBarView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | setVisibility(View.GONE);
22 | }
23 |
24 | @Override
25 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
26 |
27 | }
28 |
29 | public void setConfig(ReadableMap config) {
30 | this.prevConfig = this.renderedConfig;
31 | this.renderedConfig = config;
32 | }
33 |
34 | public ReadableMap getConfig() {
35 | return renderedConfig;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/TabBarViewManager.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.util.Log;
4 | import com.facebook.react.bridge.ReadableMap;
5 | import com.facebook.react.uimanager.ThemedReactContext;
6 | import com.facebook.react.uimanager.ViewGroupManager;
7 | import com.facebook.react.uimanager.annotations.ReactProp;
8 |
9 | public class TabBarViewManager extends ViewGroupManager {
10 | private static final String TAG = "TabBarViewManager";
11 |
12 | @Override
13 | public String getName() {
14 | return "NativeNavigationTabBarView";
15 | }
16 |
17 | @Override
18 | protected TabBarView createViewInstance(ThemedReactContext reactContext) {
19 | return new TabBarView(reactContext, null);
20 | }
21 |
22 | @ReactProp(name="config")
23 | public void setConfig(TabBarView view, ReadableMap config) {
24 | Log.d(TAG, "setConfig");
25 | view.setConfig(config);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/TabCoordinator.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.support.v4.util.LongSparseArray;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.util.Log;
9 |
10 | public class TabCoordinator {
11 | private static final String TAG = TabCoordinator.class.getSimpleName();
12 |
13 | private final LongSparseArray screenCoordinators = new LongSparseArray<>();
14 | private final AppCompatActivity activity;
15 | private final ScreenCoordinatorLayout container;
16 |
17 | private Integer currentTabId = null;
18 |
19 | public TabCoordinator(AppCompatActivity activity, ScreenCoordinatorLayout container,
20 | @Nullable Bundle savedInstanceState) {
21 | this.activity = activity;
22 | this.container = container;
23 | }
24 |
25 | public void showTab(Fragment startingFragment, int id) {
26 | if (currentTabId != null) {
27 | if (id == currentTabId) {
28 | // TODO: add support for other behavior here such as reset the tab stack.
29 | return;
30 | }
31 | ScreenCoordinator coordinator = screenCoordinators.get(currentTabId);
32 | coordinator.dismissAll();
33 | }
34 | currentTabId = id;
35 | ScreenCoordinator coordinator = screenCoordinators.get(id);
36 | if (coordinator == null) {
37 | coordinator = new ScreenCoordinator(activity, container, null);
38 | screenCoordinators.put(id, coordinator);
39 | }
40 | coordinator.presentScreen(startingFragment, ScreenCoordinator.PresentAnimation.Fade, null);
41 | Log.d(TAG, toString());
42 | }
43 |
44 | @Nullable
45 | public ScreenCoordinator getCurrentScreenCoordinator() {
46 | if (currentTabId == null)
47 | return null;
48 | return screenCoordinators.get(currentTabId);
49 | }
50 |
51 | public boolean onBackPressed() {
52 | if (currentTabId == null) {
53 | return false;
54 | }
55 | screenCoordinators.get(currentTabId).pop();
56 | return true;
57 | }
58 |
59 | @Override
60 | public String toString() {
61 | StringBuilder sb = new StringBuilder();
62 | sb.append("TabCoordinator={");
63 | int size = screenCoordinators.size();
64 | for (int i = 0; i < size; i++) {
65 | long id = screenCoordinators.keyAt(i);
66 | ScreenCoordinator coordinator = screenCoordinators.valueAt(i);
67 | sb.append('\n').append(id).append(": ").append(coordinator);
68 | }
69 | sb.append("\n}");
70 | return sb.toString();
71 | }
72 | }
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/TabView.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import com.facebook.react.bridge.ReadableMap;
9 |
10 | /**
11 | * This view is used as a data structure to hold configuration for a Tab in a
12 | * ReactNativeTabActivity, and doesn't actually render anything that will be visible
13 | * to the user.
14 | */
15 | public class TabView extends View {
16 |
17 | private String route;
18 | private String title;
19 | private ReadableMap prevConfig;
20 | private ReadableMap renderedConfig;
21 | private Bundle props;
22 | private Fragment fragment;
23 |
24 | public TabView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 | setVisibility(View.GONE);
27 | }
28 |
29 | public void setRoute(String route) {
30 | this.route = route;
31 | }
32 |
33 | public void setProps(ReadableMap props) {
34 | this.props = ConversionUtil.toBundle(props);
35 | }
36 |
37 | public void setConfig(ReadableMap config) {
38 | this.prevConfig = this.renderedConfig;
39 | this.renderedConfig = config;
40 | }
41 |
42 | public ReadableMap getPrevConfig() {
43 | return prevConfig;
44 | }
45 |
46 | public ReadableMap getRenderedConfig() {
47 | return renderedConfig;
48 | }
49 |
50 | public Fragment getFragment() {
51 | if (fragment == null) {
52 | fragment = instantiateFragment();
53 | }
54 | return fragment;
55 | }
56 | public String getRoute() {
57 | return route;
58 | }
59 |
60 | private ReactNativeFragment instantiateFragment() {
61 | return ReactNativeFragment.newInstance(route, props);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/android/src/main/java/com/airbnb/android/react/navigation/TabViewManager.java:
--------------------------------------------------------------------------------
1 | package com.airbnb.android.react.navigation;
2 |
3 | import android.util.Log;
4 | import com.facebook.react.bridge.ReadableMap;
5 | import com.facebook.react.uimanager.SimpleViewManager;
6 | import com.facebook.react.uimanager.ThemedReactContext;
7 | import com.facebook.react.uimanager.annotations.ReactProp;
8 |
9 | public class TabViewManager extends SimpleViewManager {
10 | private static final String TAG = "TabViewManager";
11 |
12 | @Override
13 | public String getName() {
14 | return "NativeNavigationTabView";
15 | }
16 |
17 | @Override
18 | protected TabView createViewInstance(ThemedReactContext reactContext) {
19 | Log.d(TAG, "createViewInstance");
20 | return new TabView(reactContext, null);
21 | }
22 |
23 | @ReactProp(name="route")
24 | public void setRoute(TabView view, String route) {
25 | Log.d(TAG, "setRoute");
26 | view.setRoute(route);
27 | }
28 |
29 | @ReactProp(name="props")
30 | public void setProps(TabView view, ReadableMap props) {
31 | Log.d(TAG, "setProps");
32 | view.setProps(props);
33 | }
34 |
35 | @ReactProp(name="config")
36 | public void setConfig(TabView view, ReadableMap config) {
37 | Log.d(TAG, "setConfig");
38 | view.setConfig(config);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/delay.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_down.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_in_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_in_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_out_left.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_out_right.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/anim/slide_up.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/activity_react_native.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/activity_tab_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
24 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/fragment_react_native.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
21 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/menu_item_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/react_root_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/layout/tab_react_native.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
24 |
25 |
30 |
31 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #7d7f80
3 | #98999a
4 | #a4a3a2
5 |
6 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/lib/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/Dictionary+FunctionalExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+FunctionalExtensions.swift
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/15/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | extension Dictionary {
12 | init(_ pairs: [Element]) {
13 | self.init()
14 | for (k, v) in pairs {
15 | self[k] = v
16 | }
17 | }
18 |
19 | public mutating func merge(values: [Key: Value]) -> [Key: Value] {
20 | for (key, value) in values {
21 | self[key] = value
22 | }
23 | return self
24 | }
25 |
26 | public func combineWith(values: [Key: Value]) -> [Key: Value] {
27 | var out = [Key: Value]()
28 | let _ = out.merge(values: self);
29 | let _ = out.merge(values: values);
30 | return out;
31 | }
32 |
33 | public func filterValues(predicate: (Value) throws -> Bool) rethrows -> [Key: Value] {
34 | var dict = [Key: Value]()
35 | for (key, value) in self {
36 | if try predicate(value) {
37 | dict[key] = value
38 | }
39 | }
40 | return dict
41 | }
42 |
43 | #if swift(>=3.2)
44 | #else
45 | public func mapValues(transform: (Value) throws -> OutValue) rethrows -> [Key: OutValue] {
46 | var dict = [Key: OutValue]()
47 | for (key, value) in self {
48 | dict[key] = try transform(value)
49 | }
50 | return dict
51 | }
52 | #endif
53 | }
54 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/NativeNavigationBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // ReactNavigationBridge.m
3 | // NativeNavigation
4 | //
5 | // Created by Spike Brehm on 5/5/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface RCT_EXTERN_REMAP_MODULE(NativeNavigationModule, ReactNavigation, NSObject)
12 |
13 | RCT_EXTERN_METHOD(registerScreen:(NSString *)sceneName
14 | properties:(NSDictionary *)properties
15 | waitForRender:(BOOL)waitForRender
16 | mode:(NSString *)mode)
17 | RCT_EXTERN_METHOD(signalFirstRenderComplete:(NSString *)instanceId)
18 | RCT_EXTERN_METHOD(setScreenProperties:(NSDictionary *)props withInstanceId:(NSString *)instanceId)
19 | RCT_EXTERN_METHOD(push:(NSString *)screenName
20 | withProps:(NSDictionary *)props
21 | options:(NSDictionary *)options
22 | resolve:(RCTPromiseResolveBlock)resolve
23 | reject:(RCTPromiseRejectBlock)reject)
24 | RCT_EXTERN_METHOD(pushNative:(NSString *)name
25 | withProps:(NSDictionary *)props
26 | options:(NSDictionary *)options
27 | resolve:(RCTPromiseResolveBlock)resolve
28 | reject:(RCTPromiseRejectBlock)reject)
29 | RCT_EXTERN_METHOD(present:(NSString *)screenName
30 | withProps:(NSDictionary *)props
31 | options:(NSDictionary *)options
32 | resolve:(RCTPromiseResolveBlock)resolve
33 | reject:(RCTPromiseRejectBlock)reject)
34 | RCT_EXTERN_METHOD(presentNative:(NSString *)name
35 | withProps:(NSDictionary *)props
36 | options:(NSDictionary *)options
37 | resolve:(RCTPromiseResolveBlock)resolve
38 | reject:(RCTPromiseRejectBlock)reject)
39 | RCT_EXTERN_METHOD(dismiss:(NSDictionary *)payload animated:(BOOL)animated)
40 | RCT_EXTERN_METHOD(pop:(NSDictionary *)payload animated:(BOOL)animated)
41 | RCT_EXTERN_METHOD(replace:(NSString *)screenName withProps:(NSDictionary *)props animated:(BOOL)animated)
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/SharedElementGroupManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementGroupManager.swift
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import React
10 |
11 | // MARK: - SharedElementGroup
12 |
13 | final class SharedElementGroup: RCTView {
14 |
15 | // MARK: Internal
16 |
17 | func setIdentifier(_ identifier: String!) {
18 | self.identifier = identifier
19 | addToViewControllerIfPossible()
20 | }
21 |
22 | func setNativeNavigationInstanceId(_ nativeNavigationInstanceId: String!) {
23 | self.nativeNavigationInstanceId = nativeNavigationInstanceId
24 | addToViewControllerIfPossible()
25 | }
26 |
27 | func addToViewControllerIfPossible() {
28 | guard let seid = identifier, let id = nativeNavigationInstanceId else { return }
29 | let vc = ReactNavigationCoordinator.sharedInstance.viewControllerForId(id)
30 | vc?.sharedElementGroupsById[seid] = WeakViewHolder(view: self)
31 | }
32 |
33 | // MARK: Private
34 |
35 | fileprivate var identifier: String?
36 | fileprivate var nativeNavigationInstanceId: String?
37 | }
38 |
39 | // MARK: - SharedElementGroupManager
40 |
41 | private let VERSION: Int = 1
42 |
43 | @objc(SharedElementGroupManager)
44 | final class SharedElementGroupManager: RCTViewManager {
45 | override func view() -> UIView! {
46 | return SharedElementGroup()
47 | }
48 |
49 | override func constantsToExport() -> [AnyHashable: Any] {
50 | return [
51 | "VERSION": VERSION
52 | ]
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/SharedElementGroupManagerBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementGroupManagerBridge.m
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface RCT_EXTERN_REMAP_MODULE(NativeNavigationSharedElementGroup, SharedElementGroupManager, RCTViewManager)
13 |
14 | RCT_EXPORT_VIEW_PROPERTY(nativeNavigationInstanceId, NSString);
15 | RCT_REMAP_VIEW_PROPERTY(id, identifier, NSString);
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/SharedElementManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementManager.swift
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import React
10 | import UIKit
11 |
12 | // MARK: - SharedElement
13 |
14 | final class SharedElement: RCTView {
15 |
16 | // MARK: Internal
17 |
18 | func setIdentifier(_ identifier: String!) {
19 | self.identifier = identifier
20 | }
21 |
22 | func setNativeNavigationInstanceId(_ nativeNavigationInstanceId: String!) {
23 | self.nativeNavigationInstanceId = nativeNavigationInstanceId
24 | }
25 |
26 | override func insertReactSubview(_ subview: UIView, at index: Int) {
27 | super.insertReactSubview(subview, at: index)
28 | guard let seid = identifier, let id = nativeNavigationInstanceId else { return }
29 | let vc = ReactNavigationCoordinator.sharedInstance.viewControllerForId(id)
30 | vc?.sharedElementsById[seid] = WeakViewHolder(view: subview)
31 | }
32 |
33 | override func removeReactSubview(_ subview: UIView) {
34 | super.removeReactSubview(subview)
35 | guard let seid = identifier, let id = nativeNavigationInstanceId else { return }
36 | let vc = ReactNavigationCoordinator.sharedInstance.viewControllerForId(id)
37 | vc?.sharedElementsById[seid] = nil
38 | }
39 |
40 | // MARK: Private
41 |
42 | fileprivate var identifier: String?
43 | fileprivate var nativeNavigationInstanceId: String?
44 | }
45 |
46 | // MARK: - SharedElementManager
47 |
48 | private let VERSION: Int = 1
49 |
50 | @objc(SharedElementManager)
51 | final class SharedElementManager: RCTViewManager {
52 | override func view() -> UIView! {
53 | return SharedElement()
54 | }
55 |
56 | override func constantsToExport() -> [AnyHashable: Any] {
57 | return [
58 | "VERSION": VERSION
59 | ]
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/SharedElementManagerBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementManagerBridge.m
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface RCT_EXTERN_REMAP_MODULE(NativeNavigationSharedElement, SharedElementManager, RCTViewManager)
13 |
14 | RCT_EXPORT_VIEW_PROPERTY(nativeNavigationInstanceId, NSString);
15 | RCT_REMAP_VIEW_PROPERTY(id, identifier, NSString);
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/TabBarViewManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabBarViewManager.swift
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import React
10 |
11 | final class TabBar: RCTView {
12 |
13 | // MARK: Internal
14 |
15 | func setConfig(_ config: [String: AnyObject]) {
16 | self.prevConfig = self.renderedConfig
17 | self.renderedConfig = config
18 | refresh()
19 | }
20 |
21 | func refresh() {
22 | if let tabBar = tabBar {
23 | implementation.reconcileTabBarConfig(
24 | tabBar: tabBar,
25 | prev: prevConfig,
26 | next: renderedConfig
27 | );
28 | }
29 | }
30 |
31 | // MARK: Private
32 |
33 | private var implementation: ReactNavigationImplementation = ReactNavigationCoordinator.sharedInstance.navigation
34 | var tabBar: UITabBar?
35 | private var prevConfig: [String: AnyObject] = [:]
36 | private var renderedConfig: [String: AnyObject] = [:]
37 |
38 | }
39 |
40 | private let VERSION: Int = 1
41 |
42 | @objc(TabBarViewManager)
43 | final class TabBarViewManager: RCTViewManager {
44 | override func view() -> UIView! {
45 | return TabBar()
46 | }
47 |
48 | override func constantsToExport() -> [AnyHashable: Any] {
49 | return [
50 | "VERSION": VERSION
51 | ]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/TabBarViewManagerBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementManagerBridge.m
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface RCT_EXTERN_REMAP_MODULE(NativeNavigationTabBarViewManager, TabBarViewManager, RCTViewManager)
13 |
14 | RCT_EXPORT_VIEW_PROPERTY(config, NSDictionary);
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/TabViewManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TabViewManager.swift
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import React
10 |
11 | // MARK: - TabView
12 |
13 | final class TabView: UIView {
14 |
15 | // init(implementation: ReactNavigationImplementation) {
16 | // super.init()
17 | // self.implementation = implementation
18 | // }
19 |
20 | // required init?(coder aDecoder: NSCoder) {
21 | // fatalError("init(coder:) has not been implemented")
22 | // }
23 |
24 | // MARK: Internal
25 |
26 | func setRoute(_ route: String!) {
27 | self.route = route
28 | }
29 |
30 | func setConfig(_ config: [String: AnyObject]) {
31 | self.prevConfig = self.renderedConfig
32 | self.renderedConfig = config
33 | implementation.reconcileTabConfig(
34 | tabBarItem: tabBarItem,
35 | prev: prevConfig,
36 | next: renderedConfig
37 | );
38 | }
39 |
40 | func setProps(_ props: [String: AnyObject]) {
41 | self.props = props
42 | }
43 |
44 | func getViewController() -> UIViewController? {
45 |
46 | if let viewController = viewController {
47 | return viewController
48 | }
49 |
50 | // TODO(lmr): handle non-RN tabs
51 | if let route = route {
52 | let vc = ReactViewController(moduleName: route, props: props).prepareViewControllerForPresenting()
53 | vc.tabBarItem = tabBarItem
54 | viewController = vc
55 | }
56 |
57 | return viewController
58 |
59 | }
60 |
61 | // MARK: Private
62 |
63 | private var implementation: ReactNavigationImplementation = ReactNavigationCoordinator.sharedInstance.navigation
64 | private var viewController: UIViewController?
65 | private var tabBarItem: UITabBarItem = UITabBarItem()
66 | private var route: String?
67 | private var props: [String: AnyObject] = [:]
68 | private var prevConfig: [String: AnyObject] = [:]
69 | private var renderedConfig: [String: AnyObject] = [:]
70 |
71 | }
72 |
73 | // MARK: - TabViewManager
74 |
75 | private let VERSION: Int = 1
76 |
77 | @objc(TabViewManager)
78 | final class TabViewManager: RCTViewManager {
79 | override func view() -> UIView! {
80 | return TabView()
81 | // return TabView(implementation: ReactNavigationCoordinator.sharedInstance.navigation)
82 | }
83 |
84 | override func constantsToExport() -> [AnyHashable: Any] {
85 | return [
86 | "VERSION": VERSION
87 | ]
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/TabViewMangerBridge.m:
--------------------------------------------------------------------------------
1 | //
2 | // SharedElementManagerBridge.m
3 | // NativeNavigation
4 | //
5 | // Created by Leland Richardson on 8/10/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface RCT_EXTERN_REMAP_MODULE(NativeNavigationTabViewManager, TabViewManager, RCTViewManager)
13 |
14 | RCT_EXPORT_VIEW_PROPERTY(route, NSString);
15 | RCT_EXPORT_VIEW_PROPERTY(props, NSDictionary);
16 | RCT_EXPORT_VIEW_PROPERTY(config, NSDictionary);
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/TransitionAnimation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TransitionAnimation.swift
3 | // NativeNavigation
4 | //
5 | // Created by Laura Skelton on 2/17/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | public protocol TransitionAnimation {
10 |
11 | associatedtype Style
12 | associatedtype FromContent
13 | associatedtype ToContent
14 |
15 | init(style: Style)
16 |
17 | var duration: TimeInterval { get }
18 |
19 | func animateWithContainer(
20 | _ container: UIView,
21 | isPresenting: Bool,
22 | fromContent: FromContent,
23 | toContent: ToContent,
24 | completion: @escaping ()->())
25 | }
26 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/UIBarButtonItem+addAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarButtonItem+addAction.swift
3 | // Pods
4 | //
5 | // Created by Leland Richardson on 2/14/17.
6 | //
7 | //
8 |
9 | import Foundation
10 |
11 |
12 | public class ClosureWrapper : NSObject {
13 | let _callback : (Void) -> Void
14 | init(callback : @escaping (Void) -> Void) {
15 | _callback = callback
16 | }
17 |
18 | public func invoke() {
19 | _callback()
20 | }
21 | }
22 |
23 | var AssociatedClosure: UInt8 = 0
24 |
25 | extension UIControl {
26 | func nn_addAction(forControlEvents events: UIControlEvents, withCallback callback: @escaping (Void) -> Void) {
27 | let wrapper = ClosureWrapper(callback: callback)
28 | addTarget(wrapper, action: #selector(ClosureWrapper.invoke), for: events)
29 | objc_setAssociatedObject(self, &AssociatedClosure, wrapper, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
30 | }
31 | }
32 |
33 | extension UIBarButtonItem {
34 | func nn_addAction() {
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/ios/native-navigation/UIViewController+TopMostViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+TopMostViewController.swift
3 | // NativeNavigation
4 | //
5 | // Created by ortal_yahdav on 7/25/16.
6 | // Copyright © 2016 Airbnb. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | public protocol CustomTopMostViewController {
12 | func customTopMostViewController() -> UIViewController?
13 | }
14 |
15 | public extension UIViewController {
16 | func topMostViewController() -> UIViewController? {
17 | if let custom = (self as? CustomTopMostViewController)?.customTopMostViewController() {
18 | return custom.topMostViewController()
19 | } else if let presented = self.presentedViewController {
20 | return presented.topMostViewController()
21 | } else if let tabBarSelected = (self as? UITabBarController)?.selectedViewController {
22 | return tabBarSelected.topMostViewController()
23 | } else if let navVisible = (self as? UINavigationController)?.visibleViewController {
24 | return navVisible.topMostViewController()
25 | } else if let lastChild = self.childViewControllers.last {
26 | return lastChild.topMostViewController()
27 | } else {
28 | return self
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/js/EventEmitter.js:
--------------------------------------------------------------------------------
1 | // A basic, minimalist EventEmitter
2 | export default class EventEmitter {
3 | constructor() {
4 | this.registry = {};
5 | }
6 |
7 | on(event, handler) {
8 | if (!this.registry[event]) {
9 | this.registry[event] = [];
10 | }
11 | this.registry[event].push(handler);
12 | return { event, handler };
13 | }
14 |
15 | unsubscribe({ event, handler }) {
16 | this.off(event, handler);
17 | }
18 |
19 | off(event, handler) {
20 | const events = this.registry[event];
21 | if (!events) return;
22 | const index = events.indexOf(handler);
23 | if (index === -1) return;
24 | events.splice(index, 1);
25 | if (events.length === 0) {
26 | delete this.registry[event];
27 | }
28 | }
29 |
30 | emit(event, ...args) {
31 | const events = this.registry[event];
32 | if (!events) return;
33 | events.forEach(handler => handler(...args));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/js/NavigatorModule.js:
--------------------------------------------------------------------------------
1 | import SafeModule from 'react-native-safe-module';
2 |
3 | const noop = () => {};
4 | const unresolvedPromise = () => new Promise(() => {});
5 |
6 | const NavigatorModule = SafeModule.module({
7 | moduleName: 'NativeNavigationModule',
8 | mock: {
9 | push: unresolvedPromise,
10 | pushNative: unresolvedPromise,
11 | present: unresolvedPromise,
12 | presentNative: unresolvedPromise,
13 | replace: unresolvedPromise,
14 | pop: noop,
15 | dismiss: noop,
16 | signalFirstRenderComplete: noop,
17 | setScreenProperties: noop,
18 | registerScreen: noop,
19 | },
20 | });
21 |
22 | export default NavigatorModule;
23 |
--------------------------------------------------------------------------------
/lib/js/SharedElement.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import SafeModule from 'react-native-safe-module';
4 |
5 | const NativeSharedElement = SafeModule.component({
6 | viewName: 'NativeNavigationSharedElement',
7 | mockComponent: ({ children }) => children,
8 | propTypes: {
9 | id: PropTypes.string,
10 | nativeNavigationInstanceId: PropTypes.string,
11 | },
12 | });
13 |
14 | const numberOrString = PropTypes.oneOfType([
15 | PropTypes.number,
16 | PropTypes.string,
17 | ]);
18 |
19 | const IdPropTypes = {
20 | type: PropTypes.string.isRequired,
21 | typeId: numberOrString,
22 | subType: PropTypes.string,
23 | subTypeId: numberOrString,
24 | };
25 |
26 | const propTypes = {
27 | ...IdPropTypes,
28 | children: PropTypes.node.isRequired,
29 | };
30 |
31 | const defaultProps = {
32 | typeId: '',
33 | subType: '',
34 | subTypeId: '',
35 | };
36 |
37 | const contextTypes = {
38 | nativeNavigationInstanceId: PropTypes.string,
39 | };
40 |
41 | class SharedElement extends React.Component {
42 | getId() {
43 | const { type, typeId, subType, subTypeId } = this.props;
44 | return `${type}|${typeId}|${subType}|${subTypeId}`;
45 | }
46 | render() {
47 | return (
48 |
52 | {React.Children.only(this.props.children)}
53 |
54 | );
55 | }
56 | }
57 |
58 | SharedElement.propTypes = propTypes;
59 | SharedElement.defaultProps = defaultProps;
60 | SharedElement.contextTypes = contextTypes;
61 | SharedElement.IdPropTypes = IdPropTypes;
62 |
63 | module.exports = SharedElement;
64 |
--------------------------------------------------------------------------------
/lib/js/SharedElementGroup.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import SafeModule from 'react-native-safe-module';
4 |
5 | const NativeSharedElement = SafeModule.component({
6 | viewName: 'NativeNavigationSharedElementGroup',
7 | mockComponent: ({ children }) => children,
8 | propTypes: {
9 | id: PropTypes.string,
10 | nativeNavigationInstanceId: PropTypes.string,
11 | },
12 | });
13 |
14 | const propTypes = {
15 | id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
16 | children: PropTypes.node.isRequired,
17 | };
18 |
19 | const contextTypes = {
20 | nativeNavigationInstanceId: PropTypes.string,
21 | };
22 |
23 | class SharedElement extends React.Component {
24 | render() {
25 | return (
26 |
30 | {this.props.children}
31 |
32 | );
33 | }
34 | }
35 |
36 | SharedElement.propTypes = propTypes;
37 | SharedElement.contextTypes = contextTypes;
38 |
39 | module.exports = SharedElement;
40 |
--------------------------------------------------------------------------------
/lib/js/Spacer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | DeviceEventEmitter,
5 | View,
6 | LayoutAnimation,
7 | } from 'react-native';
8 |
9 | class Spacer extends React.Component {
10 | constructor(props, context) {
11 | super(props, context);
12 | this.state = {
13 | height: context.nativeNavigationInitialBarHeight || 0,
14 | };
15 |
16 | this.subscription = null;
17 | this.onHeightChanged = this.onHeightChanged.bind(this);
18 | }
19 |
20 | componentDidMount() {
21 | const id = this.context.nativeNavigationInstanceId;
22 | const key = `NativeNavigationScreen.onBarHeightChanged.${id}`;
23 | this.subscription = DeviceEventEmitter.addListener(key, this.onHeightChanged);
24 | }
25 |
26 | componentWillUnmount() {
27 | DeviceEventEmitter.removeSubscription(this.subscription);
28 | }
29 |
30 | onHeightChanged(height) {
31 | if (this.props.animated) {
32 | LayoutAnimation.easeInEaseOut();
33 | }
34 | this.setState({ height });
35 | }
36 |
37 | render() {
38 | return ;
39 | }
40 | }
41 |
42 | Spacer.propTypes = {
43 | animated: PropTypes.bool,
44 | };
45 |
46 | Spacer.defaultProps = {
47 | animated: false,
48 | };
49 |
50 | Spacer.contextTypes = {
51 | nativeNavigationInstanceId: PropTypes.string,
52 | nativeNavigationInitialBarHeight: PropTypes.number,
53 | };
54 |
55 | module.exports = Spacer;
56 |
--------------------------------------------------------------------------------
/lib/js/Tab.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | View,
5 | } from 'react-native';
6 | import SafeModule from 'react-native-safe-module';
7 | import { processConfig } from './utils';
8 |
9 | const NativeTab = SafeModule.component({
10 | viewName: 'NativeNavigationTabView',
11 | mockComponent: () => ,
12 | });
13 |
14 | class Tab extends React.Component {
15 | render() {
16 | const { route, props, ...config } = this.props;
17 | return (
18 |
23 | );
24 | }
25 | }
26 |
27 | Tab.propTypes = {
28 | route: PropTypes.string.isRequired,
29 | props: PropTypes.any,
30 | };
31 |
32 | module.exports = Tab;
33 |
--------------------------------------------------------------------------------
/lib/js/TabBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import {
4 | View,
5 | } from 'react-native';
6 | import SafeModule from 'react-native-safe-module';
7 | import { processConfig } from './utils';
8 |
9 | const NativeTabBar = SafeModule.component({
10 | viewName: 'NativeNavigationTabBarView',
11 | mockComponent: () => ,
12 | });
13 |
14 | class TabBar extends React.Component {
15 | render() {
16 | const { children, ...config } = this.props;
17 | // TODO(lmr): handle event registration with config as well...
18 | return (
19 |
22 | {children}
23 |
24 | );
25 | }
26 | }
27 |
28 | TabBar.propTypes = {
29 | children: PropTypes.node,
30 | };
31 |
32 | module.exports = TabBar;
33 |
--------------------------------------------------------------------------------
/lib/js/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./Navigator');
2 | module.exports.Config = require('./Config');
3 | module.exports.Spacer = require('./Spacer');
4 | module.exports.TabBar = require('./TabBar');
5 | module.exports.Tab = require('./Tab');
6 | module.exports.SharedElement = require('./SharedElement');
7 | module.exports.SharedElementGroup = require('./SharedElementGroup');
8 |
--------------------------------------------------------------------------------
/lib/js/navBar.js:
--------------------------------------------------------------------------------
1 | const BAR_TYPE = {
2 | SPECIALTY: 'specialty',
3 | INVERSE_SPECIALTY: 'inverse-specialty',
4 | SHEET: 'sheet',
5 | STATIC: 'static',
6 | OVERLAY: 'overlay',
7 | BASIC: 'basic',
8 | };
9 |
10 | const COLOR = {
11 | CELEBRATORY: 'celebratory',
12 | VALID: 'valid',
13 | INVALID: 'invalid',
14 | UNVALIDATED: 'unvalidated',
15 | };
16 |
17 | const CLOSE_BEHAVIOR = {
18 | POP: 'pop',
19 | DISMISS: 'dismiss',
20 | };
21 |
22 | // Android-only.
23 | const LEFT_ICON = {
24 | CLOSE: 'close',
25 | MENU: 'menu',
26 | NONE: 'none',
27 | NAV_LEFT: 'nav-left',
28 | };
29 |
30 | function themeFromBarStyle({ barType }) {
31 | // NOTE(lmr):
32 | // This function could be replaced with a simple map, but I believe that we
33 | // may actually need a more nuanced method that looks at other properties, so'
34 | // I am proactively making it a function + switch statement.
35 | switch (barType) {
36 | case BAR_TYPE.SPECIALTY: return 'transparent-light';
37 | case BAR_TYPE.INVERSE_SPECIALTY: return 'transparent-light';
38 | case BAR_TYPE.SHEET: return 'transparent-light';
39 | case BAR_TYPE.STATIC: return 'opaque';
40 | case BAR_TYPE.OVERLAY: return 'transparent-light';
41 | case BAR_TYPE.BASIC: return 'transparent-dark';
42 | default: return 'transparent-light';
43 | }
44 | }
45 |
46 | module.exports = {
47 | BAR_TYPE,
48 | COLOR,
49 | CLOSE_BEHAVIOR,
50 | LEFT_ICON,
51 | themeFromBarStyle,
52 | };
53 |
--------------------------------------------------------------------------------
/lib/js/navigatorEmitter.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from './EventEmitter';
2 |
3 | export default new EventEmitter();
4 |
--------------------------------------------------------------------------------
/lib/js/shallowEquals.js:
--------------------------------------------------------------------------------
1 | /* eslint no-restricted-syntax:0 */
2 | const hasOwnProperty = Object.prototype.hasOwnProperty;
3 |
4 | function shallowArray(a, b, compare) {
5 | const l = a.length;
6 | if (l !== b.length) return false;
7 |
8 | if (compare) {
9 | for (let i = 0; i < l; i += 1) {
10 | if (!compare(a[i], b[i])) return false;
11 | }
12 | } else {
13 | for (let i = 0; i < l; i += 1) {
14 | if (a[i] !== b[i]) return false;
15 | }
16 | }
17 |
18 | return true;
19 | }
20 |
21 | function shallowObject(a, b, compare) {
22 | let ka = 0;
23 | let kb = 0;
24 |
25 | if (compare) {
26 | for (const key in a) {
27 | if (
28 | hasOwnProperty.call(a, key) &&
29 | !compare(a[key], b[key])
30 | ) return false;
31 |
32 | ka += 1;
33 | }
34 | } else {
35 | for (const key in a) {
36 | if (
37 | hasOwnProperty.call(a, key) &&
38 | a[key] !== b[key]
39 | ) return false;
40 |
41 | ka += 1;
42 | }
43 | }
44 |
45 | for (const key in b) {
46 | if (hasOwnProperty.call(b, key)) kb += 1;
47 | }
48 |
49 | return ka === kb;
50 | }
51 |
52 | function flat(type) {
53 | return (
54 | type !== 'function' &&
55 | type !== 'object'
56 | );
57 | }
58 |
59 | function shallow(a, b, compare) {
60 | const aIsArray = Array.isArray(a);
61 | const bIsArray = Array.isArray(b);
62 |
63 | if (aIsArray !== bIsArray) return false;
64 |
65 | const aTypeof = typeof a;
66 | const bTypeof = typeof b;
67 |
68 | if (aTypeof !== bTypeof) return false;
69 | if (flat(aTypeof)) {
70 | return compare
71 | ? compare(a, b)
72 | : a === b;
73 | }
74 |
75 | return aIsArray
76 | ? shallowArray(a, b, compare)
77 | : shallowObject(a, b, compare);
78 | }
79 |
80 | module.exports = shallow;
81 |
--------------------------------------------------------------------------------
/lib/js/utils.js:
--------------------------------------------------------------------------------
1 | import {
2 | processColor,
3 | Image,
4 | } from 'react-native';
5 | import shallowEquals from './shallowEquals';
6 |
7 | function isEventKey(key) {
8 | if (key.substr(0, 2) !== 'on') return false; // doesn't start with 'on';
9 | const c = key[2];
10 | if (c === undefined || !isNaN(c * 1)) return false; // 3rd char is numeric
11 | return c === c.toUpperCase(); // only event if 3rd char is uppercase letter
12 | }
13 | const IS_IMAGE_REGEX = /image/i;
14 |
15 | function isImageKey(key) {
16 | return IS_IMAGE_REGEX.test(key);
17 | }
18 |
19 | const IS_COLOR_REGEX = /color$/i;
20 |
21 |
22 | function isColorKey(key) {
23 | return IS_COLOR_REGEX.test(key);
24 | }
25 |
26 | function processConfig(config) {
27 | if (typeof config !== 'object') {
28 | return config;
29 | }
30 | const obj = {};
31 | Object.keys(config).forEach(key => {
32 | if (isColorKey(key)) {
33 | obj[key] = processColor(config[key]);
34 | } else if (isImageKey(key)) {
35 | obj[key] = Image.resolveAssetSource(config[key]);
36 | } else if (isEventKey(key)) {
37 | // do nothing
38 | } else if (Array.isArray(config[key])) {
39 | obj[key] = config[key].map(processConfig);
40 | } else {
41 | obj[key] = config[key];
42 | }
43 | });
44 | return obj;
45 | }
46 |
47 | function processConfigWatchingForMutations(target, prev, next, mutationFlag, onEvent) {
48 | /* eslint no-param-reassign: 0, no-unused-expressions: 0 */
49 | if (typeof next !== 'object') {
50 | return;
51 | }
52 | Object.keys(next).forEach(key => {
53 | if (key === 'children') return;
54 | if (isEventKey(key)) {
55 | onEvent && onEvent(key);
56 | } else if (prev[key] !== next[key]) {
57 | if (isColorKey(key)) {
58 | target[key] = processColor(next[key]);
59 | mutationFlag.hasMutated = true;
60 | } else if (isImageKey(key)) {
61 | target[key] = Image.resolveAssetSource(next[key]);
62 | mutationFlag.hasMutated = true;
63 | } else if (Array.isArray(next[key])) {
64 | // TODO: shallow
65 | if (!shallowEquals(next[key], prev[key], shallowEquals)) {
66 | processConfigWatchingForMutations(target[key]);
67 | target[key] = next[key].map(el => {
68 | const result = {};
69 | processConfigWatchingForMutations(result, {}, el, mutationFlag, null);
70 | return result;
71 | });
72 | mutationFlag.hasMutated = true;
73 | }
74 | } else {
75 | target[key] = next[key];
76 | mutationFlag.hasMutated = true;
77 | }
78 | }
79 | });
80 |
81 | // we need to also cycle through keys that were there previously but might not be
82 | // anymore and treat that as a removal
83 | Object.keys(prev).forEach(key => {
84 | if (key in prev && !(key in next)) {
85 | if (isEventKey(key)) {
86 | onEvent && onEvent(key);
87 | } else if (key === 'children') {
88 | // do nothing
89 | } else {
90 | // remove from barProps
91 | target[key] = undefined;
92 | mutationFlag.hasMutated = true;
93 | }
94 | }
95 | });
96 | }
97 |
98 | module.exports = {
99 | isEventKey,
100 | isColorKey,
101 | processConfig,
102 | processConfigWatchingForMutations,
103 | };
104 |
--------------------------------------------------------------------------------
/native-navigation.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "native-navigation"
7 | s.version = package['version']
8 | s.summary = "Native navigation library for React Native applications"
9 |
10 | s.authors = { "intelligibabble" => "leland.m.richardson@gmail.com" }
11 | s.homepage = "https://github.com/airbnb/native-navigation#readme"
12 | s.license = package['license']
13 | s.platform = :ios, "8.0"
14 |
15 | s.module_name = 'NativeNavigation'
16 |
17 | s.source = { :git => "https://github.com/airbnb/native-navigation.git", :tag => "v#{s.version}" }
18 | s.source_files = "lib/ios/native-navigation/*.{h,m,swift}"
19 |
20 | s.dependency 'React'
21 | s.frameworks = 'UIKit'
22 | end
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "native-navigation",
3 | "version": "0.2.2",
4 | "description": "Native Navigation for React Native",
5 | "main": "index.js",
6 | "scripts": {
7 | "postinstall":"sh postinstall.sh",
8 | "start": "node node_modules/react-native/local-cli/cli.js start",
9 | "run:packager": "./node_modules/react-native/packager/packager.sh",
10 | "run:ios": "react-native run-ios --project-path ./example/ios",
11 | "start:android": "adb shell am start -n com.airbnb.android.react.navigation.example/.MainActivity",
12 | "run:android": "./gradlew installDebug && npm run start:android",
13 | "lint": "eslint ./",
14 | "build": "npm run build:js && npm run build:android && npm run build:ios",
15 | "build:js": "exit 0",
16 | "build:ios": "bundle install --binstubs ./examples/ios && bundle exec pod install --project-directory=./example/ios/",
17 | "build:android": "./gradlew :native-navigation:assembleDebug",
18 | "ci": "npm run lint",
19 | "publish:pod": "exit 0",
20 | "publish:maven": "exit 0",
21 | "publish:mavenold": "cd lib/android/ && ./gradlew clean check uploadArchives && cd -",
22 | "docs:clean": "rimraf _book",
23 | "docs:prepare": "gitbook install",
24 | "docs:build": "npm run docs:prepare && gitbook build",
25 | "docs:watch": "npm run docs:prepare && gitbook serve",
26 | "docs:publish": "npm run docs:clean && npm run docs:build && cd _book && git init && git commit --allow-empty -m 'update book' && git fetch https://github.com/airbnb/native-navigation.git gh-pages && git checkout -b gh-pages && git add . && git commit -am 'update book' && git push https://github.com/airbnb/native-navigation.git gh-pages --force",
27 | "test": "echo \"Error: no test specified\" && exit 1"
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/airbnb/native-navigation.git"
32 | },
33 | "keywords": [],
34 | "author": "Leland Richardson ",
35 | "license": "MIT",
36 | "bugs": {
37 | "url": "https://github.com/airbnb/native-navigation/issues"
38 | },
39 | "homepage": "https://github.com/airbnb/native-navigation#readme",
40 | "peerDependencies": {
41 | "react": ">=16.0.0",
42 | "react-native": ">=0.50"
43 | },
44 | "dependencies": {
45 | "prop-types": "^15.5.10",
46 | "react-native-safe-module": "^1.1.0"
47 | },
48 | "devDependencies": {
49 | "babel-eslint": "^6.1.2",
50 | "babel-plugin-module-resolver": "^2.3.0",
51 | "babel-preset-airbnb": "^1.1.1",
52 | "babel-preset-react-native": "1.9.0",
53 | "eslint": "^3.3.1",
54 | "eslint-config-airbnb": "^10.0.1",
55 | "eslint-import-resolver-babel-module": "^2.2.1",
56 | "eslint-plugin-import": "^1.14.0",
57 | "eslint-plugin-jsx-a11y": "^2.1.0",
58 | "eslint-plugin-prefer-object-spread": "^1.1.0",
59 | "eslint-plugin-react": "^6.1.2",
60 | "gitbook-cli": "^2.3.0",
61 | "murmur2js": "^1.0.0",
62 | "react": "^16.1.1",
63 | "react-native": "^0.50.4"
64 | },
65 | "rnpm": {
66 | "android": {
67 | "sourceDir": "./lib/android"
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/postinstall.sh:
--------------------------------------------------------------------------------
1 | echo 'hacking...'
2 | sed -i '' 's/\#import /\#import \"RCTValueAnimatedNode.h\"/' ./node_modules/react-native/Libraries/NativeAnimation/RCTNativeAnimatedNodesManager.h
3 | sed -i '' 's/\#import /\#import /' ./node_modules/react-native/Libraries/WebSocket/RCTReconnectingWebSocket.m
4 | echo 'hacked'
5 |
--------------------------------------------------------------------------------
/rn-cli.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | /**
3 | * Returns a regular expression for modules that should be ignored by the
4 | * packager on a given platform.
5 | */
6 | getBlacklistRE() {
7 | return /_book\//;
8 | },
9 | };
10 |
11 | module.exports = config;
12 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'native-navigation'
2 |
3 | include ":example-android"
4 | project(":example-android").projectDir = file("./example/android/app")
5 |
6 | include ":native-navigation-lib"
7 | project(":native-navigation-lib").projectDir = file("./lib/android")
8 |
--------------------------------------------------------------------------------