├── .all-contributorsrc ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── .lintstagedrc.json ├── .npmignore ├── .releaserc.json ├── CHANGELOG.md ├── README.md ├── commitlint.config.js ├── example ├── .gitignore ├── README.md ├── __tests__ │ └── App-test.js ├── android │ ├── app │ │ ├── _BUCK │ │ ├── build.gradle │ │ ├── build_defs.bzl │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── awesomeproject │ │ │ │ └── ReactNativeFlipper.java │ │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── awesomeproject │ │ │ │ ├── MainActivity.java │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── strings.xml │ │ │ └── styles.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── AwesomeProject-tvOS │ │ └── Info.plist │ ├── AwesomeProject-tvOSTests │ │ └── Info.plist │ ├── AwesomeProject.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── AwesomeProject-tvOS.xcscheme │ │ │ └── AwesomeProject.xcscheme │ ├── AwesomeProject.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── AwesomeProject │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ ├── AwesomeProjectTests │ │ ├── AwesomeProjectTests.m │ │ └── Info.plist │ ├── Podfile │ └── Podfile.lock ├── metro.config.js ├── package-lock.json ├── package.json ├── src │ ├── components │ │ ├── CustomDrawer.js │ │ └── DrawerButton.js │ └── pages │ │ ├── AnotherPage.js │ │ ├── HomePage.js │ │ ├── Page1.js │ │ └── Page2.js └── yarn.lock ├── lib ├── RNNDrawer.d.ts ├── RNNDrawer.js ├── SideMenuView.d.ts ├── SideMenuView.js ├── events.d.ts ├── events.js ├── index.d.ts └── index.js ├── package-lock.json ├── package.json ├── prettier.config.js ├── src ├── RNNDrawer.tsx ├── SideMenuView.tsx ├── events.ts └── index.ts └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "rodriigovieira", 10 | "name": "Rodrigo Vieira", 11 | "avatar_url": "https://avatars.githubusercontent.com/u/7014073?v=4", 12 | "profile": "https://github.com/rodriigovieira", 13 | "contributions": [ 14 | "code", 15 | "bug", 16 | "doc", 17 | "maintenance" 18 | ] 19 | }, 20 | { 21 | "login": "lukebrandonfarrell", 22 | "name": "Luke Brandon Farrell", 23 | "avatar_url": "https://avatars.githubusercontent.com/u/18139277?v=4", 24 | "profile": "https://discord.gg/QqTN6HqNTG", 25 | "contributions": [ 26 | "code", 27 | "bug", 28 | "doc" 29 | ] 30 | }, 31 | { 32 | "login": "Danite", 33 | "name": "Daniil Merkulov", 34 | "avatar_url": "https://avatars.githubusercontent.com/u/9094825?v=4", 35 | "profile": "https://github.com/Danite", 36 | "contributions": [ 37 | "code", 38 | ] 39 | }, 40 | { 41 | "login": "CursedWizard", 42 | "name": "CyberFuntik", 43 | "avatar_url": "https://avatars.githubusercontent.com/u/67508707?v=4", 44 | "profile": "https://github.com/CursedWizard", 45 | "contributions": [ 46 | "code", 47 | "doc" 48 | ] 49 | } 50 | ], 51 | "contributorsPerLine": 7, 52 | "projectName": "react-native-navigation-drawer-extension", 53 | "projectOwner": "aspect-apps", 54 | "repoType": "github", 55 | "repoHost": "https://github.com", 56 | "skipCi": true 57 | } 58 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Release 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-18.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v1 15 | - name: Setup Node.js 16 | uses: actions/setup-node@v1 17 | with: 18 | node-version: 12 19 | - name: Install dependencies 20 | run: npm ci 21 | - name: Release 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | run: npx semantic-release 26 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | .DS_Store -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | 5 | npm run pre-commit 6 | npx tsc 7 | git add . 8 | 9 | -------------------------------------------------------------------------------- /.lintstagedrc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [ 4 | "prettier --write", 5 | "git add ." 6 | ] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | example/ 2 | .idea 3 | node_modules/ 4 | .DS_Store -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "branches": ["master", "main", "next"] 4 | } 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.2.0 (November 2020) 2 | - Added orientation support 3 | - Drawer can now be closed by swipping it 4 | - Added example project 5 | 6 | ## 2.0.2 (October 2019) 7 | - Fixed possuble undefined value when swipping. 8 | 9 | ## 2.0.1 (August 2019) 10 | - Added types declaration to NPM package.json 11 | 12 | ## 2.0.0 (August 2019) 13 | 14 | - Package has been re-written using TypeScript! 15 | - The 'jetemit' dependancy has been removed in favour of a in-built event system (zero dependancies 🚀). 16 | - Height / Width of drawer can now be provided as a percentage or absolute value (e.g. `"80%"` | `425`) 17 | - The library no longer monkey patches the RNN Navigation method. Instead the drawer can be toggled using `RNNDrawer.showDrawer(options: Layout)` or `RNNDrawer.dismissDrawer(options: Layout)`. 18 | - Fixed [#8](https://github.com/lukebrandonfarrell/react-native-navigation-drawer-extension/issues/8) with undefined listenr. 19 | - Drawers are now created using a `create` method on `RNNDrawer` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 | React Native Navigation Drawer Extension 5 |

6 | 7 |

8 | 9 | version 10 | 11 | 12 | license 13 | 14 | 15 | downloads 16 | 17 | 18 | 19 | contributors 20 | 21 | 22 |

23 | 24 | [React Native Navigation by Wix](https://wix.github.io/react-native-navigation/#/) does not offer an in-built solution for displaying a drawer on iOS. Their current side-menu has limited functionality on both iOS and Android. This is a drawer solution using showOverlay under the hood to display a drawer on iOS and Android. 25 | 26 | If you are using React Native Navigation >= 3.0.0 then use version 3.x.x + of this library. 27 | 28 | 29 | 30 | 31 | ## Install 32 | 33 | ```sh 34 | npm install react-native-navigation-drawer-extension --save 35 | ``` 36 | 37 | or 38 | 39 | ```sh 40 | yarn add react-native-navigation-drawer-extension 41 | ``` 42 | 43 | ## Usage 44 | 45 | You need to register your drawer component with RNN. To do this use the register method and wrap your component in the RNNDrawer HOC. 46 | 47 | ```js 48 | import { Navigation } from "react-native-navigation"; 49 | import { RNNDrawer } from "react-native-navigation-drawer-extension"; 50 | 51 | // register our drawer component with RNN 52 | Navigation.registerComponent("CustomDrawer", () => RNNDrawer.create(CustomDrawer)); 53 | ``` 54 | 55 | You can then use the drawer by calling a custom method. The `showDrawer` method 56 | will take a single parameter `options` identical to `showOverlay`. 57 | 58 | ````js 59 | import { RNNDrawer } from "react-native-navigation-drawer-extension"; 60 | 61 | RNNDrawer.showDrawer({ 62 | component: { 63 | name: "CustomDrawer", 64 | passProps: { 65 | animationOpenTime: 300, 66 | animationCloseTime: 300, 67 | direction: "left", 68 | dismissWhenTouchOutside: true, 69 | fadeOpacity: 0.6, 70 | drawerScreenWidth: "75%" || 445, // Use relative to screen '%' or absolute 71 | drawerScreenHeight: "100%" || 700, 72 | style: { // Styles the drawer container, supports any react-native style 73 | backgroundColor: "red", 74 | }, 75 | parentComponentId: props.componentId, // Custom prop, will be available in your custom drawer component props 76 | }, 77 | } 78 | }); 79 | 80 | RNNDrawer.dismissDrawer(); 81 | ```` 82 | 83 | To navigate from the drawer you must pass the parent `componentId` and use that to navigate. e.g: 84 | 85 | ```js 86 | // From drawer component 87 | Navigation.push(parentComponentId, { 88 | component: { 89 | name: "CustomScreenFromDrawer", 90 | }, 91 | }); 92 | ``` 93 | 94 | There's a complete and functional example at the `example` folder, with more thorough explanation on each method. 95 | 96 | #### Props 97 | 98 | The props below are used to configure the drawer and are to be used in RNN `passProps:`. Any aditional 99 | props will be passed to your custom drawer component. 100 | 101 | | Prop | Type | Optional | Default | Description | 102 | | ---------------------------- | ------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ | 103 | | animationOpenTime | float | Yes | 300 | Time in milliseconds to execute the drawer opening animation. | 104 | | animationCloseTime | float | Yes | 300 | Time in milliseconds to execute the drawer closing animation. | 105 | | direction | string | Yes | left | Direction to open the collage, one of: ["left", "right", "top", "bottom"]. | 106 | | dismissWhenTouchOutside | bool | Yes | true | Should the drawer be dismissed when a click is registered outside? | 107 | | fadeOpacity | number | Yes | 0.6 | Opacity of the screen outside the drawer. | 108 | | drawerScreenWidth | number/string | Yes | 80% | Width of drawer on portrait orientation. Pass a string containing '%' (e.g. "80%") for setting the width in relation to the screen or a number for absolute width (e.g. 300) | 109 | | drawerScreenWidthOnLandscape | number/string | Yes | 30% | Width of drawer on landscape orientation. Pass a string containing '%' (e.g. "80%") for setting the width in relation to the screen or a number for absolute width (e.g. 300) | 110 | | drawerScreenHeight | number/string | Yes | 100% | Height of drawer. Pass a string containing '%' (e.g. "30%") for setting the height in relation to the screen or a number for absolute height (e.g. 300) 111 | | disableDragging | boolean | Yes | false | Whether you want to disable dragging of the drawer. Useful if you have ScrollView inside the drawer (addresses #62).| 112 | | disableSwiping | boolean | Yes | false | Whether you want to disable swiping gesture. Use it only in pair with disableDragging. | 113 | 114 | ## SideMenuView 115 | 116 | 117 | 118 | The library also exposes a component which will allow you to open the drawer by either swiping the left or right gutter of the phone. This is achieved by using event listeners 119 | to communicate with the RNNDrawer HOC component. To enable this feature wrap your screen with the `SideMenuView` component. `` is just an enhanced `` all props are passed down to ``. 120 | 121 | ```js 122 | import { SideMenuView } from "react-native-navigation-drawer-extension"; 123 | 124 | 145 | {...} 146 | 147 | 148 | ``` 149 | 150 | #### Props 151 | 152 | | Prop | Type | Optional | Default | Description | 153 | | ------------------- | ------------- | --------- | ------- | --------------------------------------------------------------------------------------- | 154 | | style | StyleProp | Yes | | The style of the drawer container. | 155 | | drawerName | string | No | | The name of the drawer component. 156 | | direction | string | Yes | left | The direction to open the drawer, one of: ["left", "right"]. 157 | | passProps | object | Yes | | The values passed to the drawer. See props in RNNDrawer above. 158 | | options | Options | Yes | | The options to configure properties of the React Native Navigation native screen. Refer to React Native Navigation's options object. 159 | | swipeSensitivity | number | Yes | 0.2 | The sensitivity of the swipe to invoke each function. | 160 | | sideMargin | number | Yes | 15 | The size of the gutter for both sides. | 161 | | sideMarginLeft | number | Yes | | The size of the gutter for the left side. | 162 | | sideMarginRight | number | Yes | | The size of the gutter for the right side. | 163 | 164 | ## Contributors ✨ 165 | 166 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 |

Daniil Merkulov

💻 📖

Rodrigo Vieira

💻 🐛 📖 🚧

Luke Brandon Farrell

💻 🐛 📖

CyberFuntik

💻 📖
179 | 180 | 181 | 182 | 183 | 184 | 185 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 186 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /example/.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/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | ios/Pods -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example Project 2 | 3 | ![Gravação de Tela 2020-11-04 às 03 46 15](https://user-images.githubusercontent.com/7014073/98164480-200b4e80-1ec3-11eb-9c4d-45a3dd4b3683.gif) 4 | 5 | This project contains a complete example of the `react-native-navigation-drawer-extension` package. 6 | 7 | The entry point is at `index.js`, replacing the default RN content with the listener from `react-native-navigation` to start the app. 8 | 9 | The pages and components are in the `src` folder. 10 | 11 | -------------------------------------------------------------------------------- /example/__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /example/android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.awesomeproject", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.awesomeproject", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation. If none specified and 19 | * // "index.android.js" exists, it will be used. Otherwise "index.js" is 20 | * // default. Can be overridden with ENTRY_FILE environment variable. 21 | * entryFile: "index.android.js", 22 | * 23 | * // https://reactnative.dev/docs/performance#enable-the-ram-format 24 | * bundleCommand: "ram-bundle", 25 | * 26 | * // whether to bundle JS and assets in debug mode 27 | * bundleInDebug: false, 28 | * 29 | * // whether to bundle JS and assets in release mode 30 | * bundleInRelease: true, 31 | * 32 | * // whether to bundle JS and assets in another build variant (if configured). 33 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 34 | * // The configuration property can be in the following formats 35 | * // 'bundleIn${productFlavor}${buildType}' 36 | * // 'bundleIn${buildType}' 37 | * // bundleInFreeDebug: true, 38 | * // bundleInPaidRelease: true, 39 | * // bundleInBeta: true, 40 | * 41 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 42 | * // for example: to disable dev mode in the staging build type (if configured) 43 | * devDisabledInStaging: true, 44 | * // The configuration property can be in the following formats 45 | * // 'devDisabledIn${productFlavor}${buildType}' 46 | * // 'devDisabledIn${buildType}' 47 | * 48 | * // the root of your project, i.e. where "package.json" lives 49 | * root: "../../", 50 | * 51 | * // where to put the JS bundle asset in debug mode 52 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 53 | * 54 | * // where to put the JS bundle asset in release mode 55 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 56 | * 57 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 58 | * // require('./image.png')), in debug mode 59 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 60 | * 61 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 62 | * // require('./image.png')), in release mode 63 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 64 | * 65 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 66 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 67 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 68 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 69 | * // for example, you might want to remove it from here. 70 | * inputExcludes: ["android/**", "ios/**"], 71 | * 72 | * // override which node gets called and with what additional arguments 73 | * nodeExecutableAndArgs: ["node"], 74 | * 75 | * // supply additional arguments to the packager 76 | * extraPackagerArgs: [] 77 | * ] 78 | */ 79 | 80 | project.ext.react = [ 81 | enableHermes: false, // clean and rebuild if changing 82 | ] 83 | 84 | apply from: "../../node_modules/react-native/react.gradle" 85 | 86 | /** 87 | * Set this to true to create two separate APKs instead of one: 88 | * - An APK that only works on ARM devices 89 | * - An APK that only works on x86 devices 90 | * The advantage is the size of the APK is reduced by about 4MB. 91 | * Upload all the APKs to the Play Store and people will download 92 | * the correct one based on the CPU architecture of their device. 93 | */ 94 | def enableSeparateBuildPerCPUArchitecture = false 95 | 96 | /** 97 | * Run Proguard to shrink the Java bytecode in release builds. 98 | */ 99 | def enableProguardInReleaseBuilds = false 100 | 101 | /** 102 | * The preferred build flavor of JavaScriptCore. 103 | * 104 | * For example, to use the international variant, you can use: 105 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 106 | * 107 | * The international variant includes ICU i18n library and necessary data 108 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 109 | * give correct results when using with locales other than en-US. Note that 110 | * this variant is about 6MiB larger per architecture than default. 111 | */ 112 | def jscFlavor = 'org.webkit:android-jsc:+' 113 | 114 | /** 115 | * Whether to enable the Hermes VM. 116 | * 117 | * This should be set on project.ext.react and mirrored here. If it is not set 118 | * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode 119 | * and the benefits of using Hermes will therefore be sharply reduced. 120 | */ 121 | def enableHermes = project.ext.react.get("enableHermes", false); 122 | 123 | android { 124 | compileSdkVersion rootProject.ext.compileSdkVersion 125 | 126 | compileOptions { 127 | sourceCompatibility JavaVersion.VERSION_1_8 128 | targetCompatibility JavaVersion.VERSION_1_8 129 | } 130 | 131 | defaultConfig { 132 | applicationId "com.awesomeproject" 133 | minSdkVersion rootProject.ext.minSdkVersion 134 | targetSdkVersion rootProject.ext.targetSdkVersion 135 | versionCode 1 136 | versionName "1.0" 137 | multiDexEnabled true 138 | } 139 | splits { 140 | abi { 141 | reset() 142 | enable enableSeparateBuildPerCPUArchitecture 143 | universalApk false // If true, also generate a universal APK 144 | include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" 145 | } 146 | } 147 | signingConfigs { 148 | debug { 149 | storeFile file('debug.keystore') 150 | storePassword 'android' 151 | keyAlias 'androiddebugkey' 152 | keyPassword 'android' 153 | } 154 | } 155 | buildTypes { 156 | debug { 157 | signingConfig signingConfigs.debug 158 | } 159 | release { 160 | // Caution! In production, you need to generate your own keystore file. 161 | // see https://reactnative.dev/docs/signed-apk-android. 162 | signingConfig signingConfigs.debug 163 | minifyEnabled enableProguardInReleaseBuilds 164 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 165 | } 166 | } 167 | 168 | // applicationVariants are e.g. debug, release 169 | applicationVariants.all { variant -> 170 | variant.outputs.each { output -> 171 | // For each separate APK per architecture, set a unique version code as described here: 172 | // https://developer.android.com/studio/build/configure-apk-splits.html 173 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 174 | def abi = output.getFilter(OutputFile.ABI) 175 | if (abi != null) { // null for the universal-debug, universal-release variants 176 | output.versionCodeOverride = 177 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 178 | } 179 | 180 | } 181 | } 182 | } 183 | 184 | dependencies { 185 | implementation fileTree(dir: "libs", include: ["*.jar"]) 186 | //noinspection GradleDynamicVersion 187 | implementation "com.facebook.react:react-native:+" // From node_modules 188 | 189 | implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" 190 | 191 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { 192 | exclude group:'com.facebook.fbjni' 193 | } 194 | 195 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { 196 | exclude group:'com.facebook.flipper' 197 | exclude group:'com.squareup.okhttp3', module:'okhttp' 198 | } 199 | 200 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { 201 | exclude group:'com.facebook.flipper' 202 | } 203 | 204 | if (enableHermes) { 205 | def hermesPath = "../../node_modules/hermes-engine/android/"; 206 | debugImplementation files(hermesPath + "hermes-debug.aar") 207 | releaseImplementation files(hermesPath + "hermes-release.aar") 208 | } else { 209 | implementation jscFlavor 210 | } 211 | } 212 | 213 | // Run this once to be able to run the application with BUCK 214 | // puts all compile dependencies into folder libs for BUCK to use 215 | task copyDownloadableDepsToLibs(type: Copy) { 216 | from configurations.compile 217 | into 'libs' 218 | } 219 | 220 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 221 | -------------------------------------------------------------------------------- /example/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/debug/java/com/awesomeproject/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.awesomeproject; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin; 21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | public class ReactNativeFlipper { 28 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 29 | if (FlipperUtils.shouldEnableFlipper(context)) { 30 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 31 | 32 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 33 | client.addPlugin(new ReactFlipperPlugin()); 34 | client.addPlugin(new DatabasesFlipperPlugin(context)); 35 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 36 | client.addPlugin(CrashReporterPlugin.getInstance()); 37 | 38 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 39 | NetworkingModule.setCustomClientBuilder( 40 | new NetworkingModule.CustomClientBuilder() { 41 | @Override 42 | public void apply(OkHttpClient.Builder builder) { 43 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 44 | } 45 | }); 46 | client.addPlugin(networkFlipperPlugin); 47 | client.start(); 48 | 49 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 50 | // Hence we run if after all native modules have been initialized 51 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 52 | if (reactContext == null) { 53 | reactInstanceManager.addReactInstanceEventListener( 54 | new ReactInstanceManager.ReactInstanceEventListener() { 55 | @Override 56 | public void onReactContextInitialized(ReactContext reactContext) { 57 | reactInstanceManager.removeReactInstanceEventListener(this); 58 | reactContext.runOnNativeModulesQueueThread( 59 | new Runnable() { 60 | @Override 61 | public void run() { 62 | client.addPlugin(new FrescoFlipperPlugin()); 63 | } 64 | }); 65 | } 66 | }); 67 | } else { 68 | client.addPlugin(new FrescoFlipperPlugin()); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/awesomeproject/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.awesomeproject; 2 | 3 | import com.reactnativenavigation.NavigationActivity; 4 | 5 | public class MainActivity extends NavigationActivity { 6 | 7 | 8 | } 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/awesomeproject/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.awesomeproject; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.reactnativenavigation.NavigationApplication; 7 | import com.facebook.react.ReactInstanceManager; 8 | import com.facebook.react.ReactNativeHost; 9 | import com.reactnativenavigation.react.NavigationReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.soloader.SoLoader; 12 | import java.lang.reflect.InvocationTargetException; 13 | import java.util.List; 14 | 15 | public class MainApplication extends NavigationApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = 18 | new NavigationReactNativeHost(this) { 19 | @Override 20 | public boolean getUseDeveloperSupport() { 21 | return BuildConfig.DEBUG; 22 | } 23 | 24 | @Override 25 | protected List getPackages() { 26 | @SuppressWarnings("UnnecessaryLocalVariable") 27 | List packages = new PackageList(this).getPackages(); 28 | // Packages that cannot be autolinked yet can be added manually here, for example: 29 | // packages.add(new MyReactNativePackage()); 30 | return packages; 31 | } 32 | 33 | @Override 34 | protected String getJSMainModuleName() { 35 | return "index"; 36 | } 37 | }; 38 | 39 | @Override 40 | public ReactNativeHost getReactNativeHost() { 41 | return mReactNativeHost; 42 | } 43 | 44 | @Override 45 | public void onCreate() { 46 | super.onCreate(); 47 | 48 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 49 | } 50 | 51 | /** 52 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like 53 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 54 | * 55 | * @param context 56 | * @param reactInstanceManager 57 | */ 58 | private static void initializeFlipper( 59 | Context context, ReactInstanceManager reactInstanceManager) { 60 | if (BuildConfig.DEBUG) { 61 | try { 62 | /* 63 | We use reflection here to pick up the class that initializes Flipper, 64 | since Flipper library is not available in release mode 65 | */ 66 | Class aClass = Class.forName("com.awesomeproject.ReactNativeFlipper"); 67 | aClass 68 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) 69 | .invoke(null, context, reactInstanceManager); 70 | } catch (ClassNotFoundException e) { 71 | e.printStackTrace(); 72 | } catch (NoSuchMethodException e) { 73 | e.printStackTrace(); 74 | } catch (IllegalAccessException e) { 75 | e.printStackTrace(); 76 | } catch (InvocationTargetException e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AwesomeProject 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | RNNKotlinVersion = "1.3.61" 6 | buildToolsVersion = "29.0.2" 7 | minSdkVersion = 19 8 | compileSdkVersion = 29 9 | targetSdkVersion = 29 10 | } 11 | repositories { 12 | google() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61" 17 | classpath("com.android.tools.build:gradle:3.5.3") 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | allprojects { 24 | repositories { 25 | mavenLocal() 26 | maven { 27 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 28 | url("$rootDir/../node_modules/react-native/android") 29 | } 30 | maven { 31 | // Android JSC is installed from npm 32 | url("$rootDir/../node_modules/jsc-android/dist") 33 | } 34 | 35 | google() 36 | jcenter() 37 | maven { url 'https://www.jitpack.io' } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /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 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | 27 | # Version of flipper SDK to use with React Native 28 | FLIPPER_VERSION=0.54.0 29 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lukebrandonfarrell/react-native-navigation-drawer-extension/f705aca041a652aa45daf08c631bc197e11f0f41/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | @rem Execute Gradle 88 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 89 | 90 | :end 91 | @rem End local scope for the variables with windows NT shell 92 | if "%ERRORLEVEL%"=="0" goto mainEnd 93 | 94 | :fail 95 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 96 | rem the _cmd.exe /c_ return code! 97 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 98 | exit /b 1 99 | 100 | :mainEnd 101 | if "%OS%"=="Windows_NT" endlocal 102 | 103 | :omega 104 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'AwesomeProject' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AwesomeProject", 3 | "displayName": "AwesomeProject" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import {Navigation} from 'react-native-navigation'; 2 | import {RNNDrawer} from 'react-native-navigation-drawer-extension'; 3 | 4 | import CustomDrawer from './src/components/CustomDrawer'; 5 | import AnotherPage from './src/pages/AnotherPage'; 6 | import HomePage from './src/pages/HomePage'; 7 | import Page1 from './src/pages/Page1'; 8 | import Page2 from './src/pages/Page2'; 9 | 10 | Navigation.registerComponent('HomePage', () => HomePage); 11 | Navigation.registerComponent('CustomDrawer', () => 12 | RNNDrawer.create(CustomDrawer), 13 | ); 14 | Navigation.registerComponent('AnotherPage', () => AnotherPage); 15 | Navigation.registerComponent('Page1', () => Page1); 16 | Navigation.registerComponent('Page2', () => Page2); 17 | 18 | Navigation.events().registerAppLaunchedListener(() => { 19 | Navigation.setRoot({ 20 | root: { 21 | stack: { 22 | children: [ 23 | { 24 | component: { 25 | name: 'HomePage', 26 | }, 27 | }, 28 | ], 29 | }, 30 | }, 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject.xcodeproj/xcshareddata/xcschemes/AwesomeProject-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject.xcodeproj/xcshareddata/xcschemes/AwesomeProject.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (nonatomic, strong) UIWindow *window; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #ifdef FB_SONARKIT_ENABLED 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | static void InitializeFlipper(UIApplication *application) { 16 | FlipperClient *client = [FlipperClient sharedClient]; 17 | SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; 18 | [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; 19 | [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; 20 | [client addPlugin:[FlipperKitReactPlugin new]]; 21 | [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; 22 | [client start]; 23 | } 24 | #endif 25 | 26 | @implementation AppDelegate 27 | 28 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 29 | { 30 | #ifdef FB_SONARKIT_ENABLED 31 | InitializeFlipper(application); 32 | #endif 33 | 34 | [ReactNativeNavigation bootstrapWithDelegate:self launchOptions:launchOptions]; 35 | return YES; 36 | } 37 | 38 | - (NSArray> *)extraModulesForBridge:(RCTBridge *)bridge { 39 | return [ReactNativeNavigation extraModulesForBridge:bridge]; 40 | } 41 | 42 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 43 | { 44 | #if DEBUG 45 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 46 | #else 47 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 48 | #endif 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /example/ios/AwesomeProject/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AwesomeProject 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | NSExceptionDomains 32 | 33 | localhost 34 | 35 | NSExceptionAllowsInsecureHTTPLoads 36 | 37 | 38 | 39 | 40 | NSLocationWhenInUseUsageDescription 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /example/ios/AwesomeProject/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/ios/AwesomeProjectTests/AwesomeProjectTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface AwesomeProjectTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation AwesomeProjectTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 38 | if (level >= RCTLogLevelError) { 39 | redboxError = message; 40 | } 41 | }); 42 | #endif 43 | 44 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 45 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 46 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | 48 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 49 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 50 | return YES; 51 | } 52 | return NO; 53 | }]; 54 | } 55 | 56 | #ifdef DEBUG 57 | RCTSetLogFunction(RCTDefaultLogFunction); 58 | #endif 59 | 60 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 61 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 62 | } 63 | 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /example/ios/AwesomeProjectTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, '11.0' 5 | 6 | target 'AwesomeProject' do 7 | config = use_native_modules! 8 | 9 | use_react_native!(:path => config["reactNativePath"]) 10 | 11 | target 'AwesomeProjectTests' do 12 | inherit! :complete 13 | # Pods for testing 14 | end 15 | 16 | # Enables Flipper. 17 | # 18 | # Note that if you have use_frameworks! enabled, Flipper will not work and 19 | # you should disable these next few lines. 20 | use_flipper! 21 | post_install do |installer| 22 | flipper_post_install(installer) 23 | end 24 | end 25 | 26 | target 'AwesomeProject-tvOS' do 27 | # Pods for AwesomeProject-tvOS 28 | 29 | target 'AwesomeProject-tvOSTests' do 30 | inherit! :search_paths 31 | # Pods for testing 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - boost-for-react-native (1.63.0) 3 | - CocoaAsyncSocket (7.6.4) 4 | - CocoaLibEvent (1.0.0) 5 | - DoubleConversion (1.1.6) 6 | - FBLazyVector (0.63.3) 7 | - FBReactNativeSpec (0.63.3): 8 | - Folly (= 2020.01.13.00) 9 | - RCTRequired (= 0.63.3) 10 | - RCTTypeSafety (= 0.63.3) 11 | - React-Core (= 0.63.3) 12 | - React-jsi (= 0.63.3) 13 | - ReactCommon/turbomodule/core (= 0.63.3) 14 | - Flipper (0.54.0): 15 | - Flipper-Folly (~> 2.2) 16 | - Flipper-RSocket (~> 1.1) 17 | - Flipper-DoubleConversion (1.1.7) 18 | - Flipper-Folly (2.3.0): 19 | - boost-for-react-native 20 | - CocoaLibEvent (~> 1.0) 21 | - Flipper-DoubleConversion 22 | - Flipper-Glog 23 | - OpenSSL-Universal (= 1.0.2.20) 24 | - Flipper-Glog (0.3.6) 25 | - Flipper-PeerTalk (0.0.4) 26 | - Flipper-RSocket (1.1.0): 27 | - Flipper-Folly (~> 2.2) 28 | - FlipperKit (0.54.0): 29 | - FlipperKit/Core (= 0.54.0) 30 | - FlipperKit/Core (0.54.0): 31 | - Flipper (~> 0.54.0) 32 | - FlipperKit/CppBridge 33 | - FlipperKit/FBCxxFollyDynamicConvert 34 | - FlipperKit/FBDefines 35 | - FlipperKit/FKPortForwarding 36 | - FlipperKit/CppBridge (0.54.0): 37 | - Flipper (~> 0.54.0) 38 | - FlipperKit/FBCxxFollyDynamicConvert (0.54.0): 39 | - Flipper-Folly (~> 2.2) 40 | - FlipperKit/FBDefines (0.54.0) 41 | - FlipperKit/FKPortForwarding (0.54.0): 42 | - CocoaAsyncSocket (~> 7.6) 43 | - Flipper-PeerTalk (~> 0.0.4) 44 | - FlipperKit/FlipperKitHighlightOverlay (0.54.0) 45 | - FlipperKit/FlipperKitLayoutPlugin (0.54.0): 46 | - FlipperKit/Core 47 | - FlipperKit/FlipperKitHighlightOverlay 48 | - FlipperKit/FlipperKitLayoutTextSearchable 49 | - YogaKit (~> 1.18) 50 | - FlipperKit/FlipperKitLayoutTextSearchable (0.54.0) 51 | - FlipperKit/FlipperKitNetworkPlugin (0.54.0): 52 | - FlipperKit/Core 53 | - FlipperKit/FlipperKitReactPlugin (0.54.0): 54 | - FlipperKit/Core 55 | - FlipperKit/FlipperKitUserDefaultsPlugin (0.54.0): 56 | - FlipperKit/Core 57 | - FlipperKit/SKIOSNetworkPlugin (0.54.0): 58 | - FlipperKit/Core 59 | - FlipperKit/FlipperKitNetworkPlugin 60 | - Folly (2020.01.13.00): 61 | - boost-for-react-native 62 | - DoubleConversion 63 | - Folly/Default (= 2020.01.13.00) 64 | - glog 65 | - Folly/Default (2020.01.13.00): 66 | - boost-for-react-native 67 | - DoubleConversion 68 | - glog 69 | - glog (0.3.5) 70 | - OpenSSL-Universal (1.0.2.20): 71 | - OpenSSL-Universal/Static (= 1.0.2.20) 72 | - OpenSSL-Universal/Static (1.0.2.20) 73 | - RCTRequired (0.63.3) 74 | - RCTTypeSafety (0.63.3): 75 | - FBLazyVector (= 0.63.3) 76 | - Folly (= 2020.01.13.00) 77 | - RCTRequired (= 0.63.3) 78 | - React-Core (= 0.63.3) 79 | - React (0.63.3): 80 | - React-Core (= 0.63.3) 81 | - React-Core/DevSupport (= 0.63.3) 82 | - React-Core/RCTWebSocket (= 0.63.3) 83 | - React-RCTActionSheet (= 0.63.3) 84 | - React-RCTAnimation (= 0.63.3) 85 | - React-RCTBlob (= 0.63.3) 86 | - React-RCTImage (= 0.63.3) 87 | - React-RCTLinking (= 0.63.3) 88 | - React-RCTNetwork (= 0.63.3) 89 | - React-RCTSettings (= 0.63.3) 90 | - React-RCTText (= 0.63.3) 91 | - React-RCTVibration (= 0.63.3) 92 | - React-callinvoker (0.63.3) 93 | - React-Core (0.63.3): 94 | - Folly (= 2020.01.13.00) 95 | - glog 96 | - React-Core/Default (= 0.63.3) 97 | - React-cxxreact (= 0.63.3) 98 | - React-jsi (= 0.63.3) 99 | - React-jsiexecutor (= 0.63.3) 100 | - Yoga 101 | - React-Core/CoreModulesHeaders (0.63.3): 102 | - Folly (= 2020.01.13.00) 103 | - glog 104 | - React-Core/Default 105 | - React-cxxreact (= 0.63.3) 106 | - React-jsi (= 0.63.3) 107 | - React-jsiexecutor (= 0.63.3) 108 | - Yoga 109 | - React-Core/Default (0.63.3): 110 | - Folly (= 2020.01.13.00) 111 | - glog 112 | - React-cxxreact (= 0.63.3) 113 | - React-jsi (= 0.63.3) 114 | - React-jsiexecutor (= 0.63.3) 115 | - Yoga 116 | - React-Core/DevSupport (0.63.3): 117 | - Folly (= 2020.01.13.00) 118 | - glog 119 | - React-Core/Default (= 0.63.3) 120 | - React-Core/RCTWebSocket (= 0.63.3) 121 | - React-cxxreact (= 0.63.3) 122 | - React-jsi (= 0.63.3) 123 | - React-jsiexecutor (= 0.63.3) 124 | - React-jsinspector (= 0.63.3) 125 | - Yoga 126 | - React-Core/RCTActionSheetHeaders (0.63.3): 127 | - Folly (= 2020.01.13.00) 128 | - glog 129 | - React-Core/Default 130 | - React-cxxreact (= 0.63.3) 131 | - React-jsi (= 0.63.3) 132 | - React-jsiexecutor (= 0.63.3) 133 | - Yoga 134 | - React-Core/RCTAnimationHeaders (0.63.3): 135 | - Folly (= 2020.01.13.00) 136 | - glog 137 | - React-Core/Default 138 | - React-cxxreact (= 0.63.3) 139 | - React-jsi (= 0.63.3) 140 | - React-jsiexecutor (= 0.63.3) 141 | - Yoga 142 | - React-Core/RCTBlobHeaders (0.63.3): 143 | - Folly (= 2020.01.13.00) 144 | - glog 145 | - React-Core/Default 146 | - React-cxxreact (= 0.63.3) 147 | - React-jsi (= 0.63.3) 148 | - React-jsiexecutor (= 0.63.3) 149 | - Yoga 150 | - React-Core/RCTImageHeaders (0.63.3): 151 | - Folly (= 2020.01.13.00) 152 | - glog 153 | - React-Core/Default 154 | - React-cxxreact (= 0.63.3) 155 | - React-jsi (= 0.63.3) 156 | - React-jsiexecutor (= 0.63.3) 157 | - Yoga 158 | - React-Core/RCTLinkingHeaders (0.63.3): 159 | - Folly (= 2020.01.13.00) 160 | - glog 161 | - React-Core/Default 162 | - React-cxxreact (= 0.63.3) 163 | - React-jsi (= 0.63.3) 164 | - React-jsiexecutor (= 0.63.3) 165 | - Yoga 166 | - React-Core/RCTNetworkHeaders (0.63.3): 167 | - Folly (= 2020.01.13.00) 168 | - glog 169 | - React-Core/Default 170 | - React-cxxreact (= 0.63.3) 171 | - React-jsi (= 0.63.3) 172 | - React-jsiexecutor (= 0.63.3) 173 | - Yoga 174 | - React-Core/RCTSettingsHeaders (0.63.3): 175 | - Folly (= 2020.01.13.00) 176 | - glog 177 | - React-Core/Default 178 | - React-cxxreact (= 0.63.3) 179 | - React-jsi (= 0.63.3) 180 | - React-jsiexecutor (= 0.63.3) 181 | - Yoga 182 | - React-Core/RCTTextHeaders (0.63.3): 183 | - Folly (= 2020.01.13.00) 184 | - glog 185 | - React-Core/Default 186 | - React-cxxreact (= 0.63.3) 187 | - React-jsi (= 0.63.3) 188 | - React-jsiexecutor (= 0.63.3) 189 | - Yoga 190 | - React-Core/RCTVibrationHeaders (0.63.3): 191 | - Folly (= 2020.01.13.00) 192 | - glog 193 | - React-Core/Default 194 | - React-cxxreact (= 0.63.3) 195 | - React-jsi (= 0.63.3) 196 | - React-jsiexecutor (= 0.63.3) 197 | - Yoga 198 | - React-Core/RCTWebSocket (0.63.3): 199 | - Folly (= 2020.01.13.00) 200 | - glog 201 | - React-Core/Default (= 0.63.3) 202 | - React-cxxreact (= 0.63.3) 203 | - React-jsi (= 0.63.3) 204 | - React-jsiexecutor (= 0.63.3) 205 | - Yoga 206 | - React-CoreModules (0.63.3): 207 | - FBReactNativeSpec (= 0.63.3) 208 | - Folly (= 2020.01.13.00) 209 | - RCTTypeSafety (= 0.63.3) 210 | - React-Core/CoreModulesHeaders (= 0.63.3) 211 | - React-jsi (= 0.63.3) 212 | - React-RCTImage (= 0.63.3) 213 | - ReactCommon/turbomodule/core (= 0.63.3) 214 | - React-cxxreact (0.63.3): 215 | - boost-for-react-native (= 1.63.0) 216 | - DoubleConversion 217 | - Folly (= 2020.01.13.00) 218 | - glog 219 | - React-callinvoker (= 0.63.3) 220 | - React-jsinspector (= 0.63.3) 221 | - React-jsi (0.63.3): 222 | - boost-for-react-native (= 1.63.0) 223 | - DoubleConversion 224 | - Folly (= 2020.01.13.00) 225 | - glog 226 | - React-jsi/Default (= 0.63.3) 227 | - React-jsi/Default (0.63.3): 228 | - boost-for-react-native (= 1.63.0) 229 | - DoubleConversion 230 | - Folly (= 2020.01.13.00) 231 | - glog 232 | - React-jsiexecutor (0.63.3): 233 | - DoubleConversion 234 | - Folly (= 2020.01.13.00) 235 | - glog 236 | - React-cxxreact (= 0.63.3) 237 | - React-jsi (= 0.63.3) 238 | - React-jsinspector (0.63.3) 239 | - React-RCTActionSheet (0.63.3): 240 | - React-Core/RCTActionSheetHeaders (= 0.63.3) 241 | - React-RCTAnimation (0.63.3): 242 | - FBReactNativeSpec (= 0.63.3) 243 | - Folly (= 2020.01.13.00) 244 | - RCTTypeSafety (= 0.63.3) 245 | - React-Core/RCTAnimationHeaders (= 0.63.3) 246 | - React-jsi (= 0.63.3) 247 | - ReactCommon/turbomodule/core (= 0.63.3) 248 | - React-RCTBlob (0.63.3): 249 | - FBReactNativeSpec (= 0.63.3) 250 | - Folly (= 2020.01.13.00) 251 | - React-Core/RCTBlobHeaders (= 0.63.3) 252 | - React-Core/RCTWebSocket (= 0.63.3) 253 | - React-jsi (= 0.63.3) 254 | - React-RCTNetwork (= 0.63.3) 255 | - ReactCommon/turbomodule/core (= 0.63.3) 256 | - React-RCTImage (0.63.3): 257 | - FBReactNativeSpec (= 0.63.3) 258 | - Folly (= 2020.01.13.00) 259 | - RCTTypeSafety (= 0.63.3) 260 | - React-Core/RCTImageHeaders (= 0.63.3) 261 | - React-jsi (= 0.63.3) 262 | - React-RCTNetwork (= 0.63.3) 263 | - ReactCommon/turbomodule/core (= 0.63.3) 264 | - React-RCTLinking (0.63.3): 265 | - FBReactNativeSpec (= 0.63.3) 266 | - React-Core/RCTLinkingHeaders (= 0.63.3) 267 | - React-jsi (= 0.63.3) 268 | - ReactCommon/turbomodule/core (= 0.63.3) 269 | - React-RCTNetwork (0.63.3): 270 | - FBReactNativeSpec (= 0.63.3) 271 | - Folly (= 2020.01.13.00) 272 | - RCTTypeSafety (= 0.63.3) 273 | - React-Core/RCTNetworkHeaders (= 0.63.3) 274 | - React-jsi (= 0.63.3) 275 | - ReactCommon/turbomodule/core (= 0.63.3) 276 | - React-RCTSettings (0.63.3): 277 | - FBReactNativeSpec (= 0.63.3) 278 | - Folly (= 2020.01.13.00) 279 | - RCTTypeSafety (= 0.63.3) 280 | - React-Core/RCTSettingsHeaders (= 0.63.3) 281 | - React-jsi (= 0.63.3) 282 | - ReactCommon/turbomodule/core (= 0.63.3) 283 | - React-RCTText (0.63.3): 284 | - React-Core/RCTTextHeaders (= 0.63.3) 285 | - React-RCTVibration (0.63.3): 286 | - FBReactNativeSpec (= 0.63.3) 287 | - Folly (= 2020.01.13.00) 288 | - React-Core/RCTVibrationHeaders (= 0.63.3) 289 | - React-jsi (= 0.63.3) 290 | - ReactCommon/turbomodule/core (= 0.63.3) 291 | - ReactCommon/turbomodule/core (0.63.3): 292 | - DoubleConversion 293 | - Folly (= 2020.01.13.00) 294 | - glog 295 | - React-callinvoker (= 0.63.3) 296 | - React-Core (= 0.63.3) 297 | - React-cxxreact (= 0.63.3) 298 | - React-jsi (= 0.63.3) 299 | - ReactNativeNavigation (7.3.0): 300 | - React-Core 301 | - React-RCTImage 302 | - React-RCTText 303 | - ReactNativeNavigation/Core (= 7.3.0) 304 | - ReactNativeNavigation/Core (7.3.0): 305 | - React-Core 306 | - React-RCTImage 307 | - React-RCTText 308 | - Yoga (1.14.0) 309 | - YogaKit (1.18.1): 310 | - Yoga (~> 1.14) 311 | 312 | DEPENDENCIES: 313 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) 314 | - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) 315 | - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) 316 | - Flipper (~> 0.54.0) 317 | - Flipper-DoubleConversion (= 1.1.7) 318 | - Flipper-Folly (~> 2.2) 319 | - Flipper-Glog (= 0.3.6) 320 | - Flipper-PeerTalk (~> 0.0.4) 321 | - Flipper-RSocket (~> 1.1) 322 | - FlipperKit (~> 0.54.0) 323 | - FlipperKit/Core (~> 0.54.0) 324 | - FlipperKit/CppBridge (~> 0.54.0) 325 | - FlipperKit/FBCxxFollyDynamicConvert (~> 0.54.0) 326 | - FlipperKit/FBDefines (~> 0.54.0) 327 | - FlipperKit/FKPortForwarding (~> 0.54.0) 328 | - FlipperKit/FlipperKitHighlightOverlay (~> 0.54.0) 329 | - FlipperKit/FlipperKitLayoutPlugin (~> 0.54.0) 330 | - FlipperKit/FlipperKitLayoutTextSearchable (~> 0.54.0) 331 | - FlipperKit/FlipperKitNetworkPlugin (~> 0.54.0) 332 | - FlipperKit/FlipperKitReactPlugin (~> 0.54.0) 333 | - FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.54.0) 334 | - FlipperKit/SKIOSNetworkPlugin (~> 0.54.0) 335 | - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) 336 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) 337 | - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) 338 | - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) 339 | - React (from `../node_modules/react-native/`) 340 | - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) 341 | - React-Core (from `../node_modules/react-native/`) 342 | - React-Core/DevSupport (from `../node_modules/react-native/`) 343 | - React-Core/RCTWebSocket (from `../node_modules/react-native/`) 344 | - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) 345 | - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) 346 | - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) 347 | - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) 348 | - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) 349 | - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) 350 | - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) 351 | - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) 352 | - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) 353 | - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) 354 | - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) 355 | - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) 356 | - React-RCTText (from `../node_modules/react-native/Libraries/Text`) 357 | - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) 358 | - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) 359 | - ReactNativeNavigation (from `../node_modules/react-native-navigation`) 360 | - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) 361 | 362 | SPEC REPOS: 363 | trunk: 364 | - boost-for-react-native 365 | - CocoaAsyncSocket 366 | - CocoaLibEvent 367 | - Flipper 368 | - Flipper-DoubleConversion 369 | - Flipper-Folly 370 | - Flipper-Glog 371 | - Flipper-PeerTalk 372 | - Flipper-RSocket 373 | - FlipperKit 374 | - OpenSSL-Universal 375 | - YogaKit 376 | 377 | EXTERNAL SOURCES: 378 | DoubleConversion: 379 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" 380 | FBLazyVector: 381 | :path: "../node_modules/react-native/Libraries/FBLazyVector" 382 | FBReactNativeSpec: 383 | :path: "../node_modules/react-native/Libraries/FBReactNativeSpec" 384 | Folly: 385 | :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" 386 | glog: 387 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" 388 | RCTRequired: 389 | :path: "../node_modules/react-native/Libraries/RCTRequired" 390 | RCTTypeSafety: 391 | :path: "../node_modules/react-native/Libraries/TypeSafety" 392 | React: 393 | :path: "../node_modules/react-native/" 394 | React-callinvoker: 395 | :path: "../node_modules/react-native/ReactCommon/callinvoker" 396 | React-Core: 397 | :path: "../node_modules/react-native/" 398 | React-CoreModules: 399 | :path: "../node_modules/react-native/React/CoreModules" 400 | React-cxxreact: 401 | :path: "../node_modules/react-native/ReactCommon/cxxreact" 402 | React-jsi: 403 | :path: "../node_modules/react-native/ReactCommon/jsi" 404 | React-jsiexecutor: 405 | :path: "../node_modules/react-native/ReactCommon/jsiexecutor" 406 | React-jsinspector: 407 | :path: "../node_modules/react-native/ReactCommon/jsinspector" 408 | React-RCTActionSheet: 409 | :path: "../node_modules/react-native/Libraries/ActionSheetIOS" 410 | React-RCTAnimation: 411 | :path: "../node_modules/react-native/Libraries/NativeAnimation" 412 | React-RCTBlob: 413 | :path: "../node_modules/react-native/Libraries/Blob" 414 | React-RCTImage: 415 | :path: "../node_modules/react-native/Libraries/Image" 416 | React-RCTLinking: 417 | :path: "../node_modules/react-native/Libraries/LinkingIOS" 418 | React-RCTNetwork: 419 | :path: "../node_modules/react-native/Libraries/Network" 420 | React-RCTSettings: 421 | :path: "../node_modules/react-native/Libraries/Settings" 422 | React-RCTText: 423 | :path: "../node_modules/react-native/Libraries/Text" 424 | React-RCTVibration: 425 | :path: "../node_modules/react-native/Libraries/Vibration" 426 | ReactCommon: 427 | :path: "../node_modules/react-native/ReactCommon" 428 | ReactNativeNavigation: 429 | :path: "../node_modules/react-native-navigation" 430 | Yoga: 431 | :path: "../node_modules/react-native/ReactCommon/yoga" 432 | 433 | SPEC CHECKSUMS: 434 | boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c 435 | CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 436 | CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f 437 | DoubleConversion: cde416483dac037923206447da6e1454df403714 438 | FBLazyVector: 878b59e31113e289e275165efbe4b54fa614d43d 439 | FBReactNativeSpec: 7da9338acfb98d4ef9e5536805a0704572d33c2f 440 | Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 441 | Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 442 | Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a 443 | Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 444 | Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 445 | Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 446 | FlipperKit: ab353d41aea8aae2ea6daaf813e67496642f3d7d 447 | Folly: b73c3869541e86821df3c387eb0af5f65addfab4 448 | glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3 449 | OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd 450 | RCTRequired: 48884c74035a0b5b76dbb7a998bd93bcfc5f2047 451 | RCTTypeSafety: edf4b618033c2f1c5b7bc3d90d8e085ed95ba2ab 452 | React: f36e90f3ceb976546e97df3403e37d226f79d0e3 453 | React-callinvoker: 18874f621eb96625df7a24a7dc8d6e07391affcd 454 | React-Core: ac3d816b8e3493970153f4aaf0cff18af0bb95e6 455 | React-CoreModules: 4016d3a4e518bcfc4f5a51252b5a05692ca6f0e1 456 | React-cxxreact: ffc9129013b87cb36cf3f30a86695a3c397b0f99 457 | React-jsi: df07aa95b39c5be3e41199921509bfa929ed2b9d 458 | React-jsiexecutor: b56c03e61c0dd5f5801255f2160a815f4a53d451 459 | React-jsinspector: 8e68ffbfe23880d3ee9bafa8be2777f60b25cbe2 460 | React-RCTActionSheet: 53ea72699698b0b47a6421cb1c8b4ab215a774aa 461 | React-RCTAnimation: 1befece0b5183c22ae01b966f5583f42e69a83c2 462 | React-RCTBlob: 0b284339cbe4b15705a05e2313a51c6d8b51fa40 463 | React-RCTImage: d1756599ebd4dc2cb19d1682fe67c6b976658387 464 | React-RCTLinking: 9af0a51c6d6a4dd1674daadafffc6d03033a6d18 465 | React-RCTNetwork: 332c83929cc5eae0b3bbca4add1d668e1fc18bda 466 | React-RCTSettings: d6953772cfd55f2c68ad72b7ef29efc7ec49f773 467 | React-RCTText: 65a6de06a7389098ce24340d1d3556015c38f746 468 | React-RCTVibration: 8e9fb25724a0805107fc1acc9075e26f814df454 469 | ReactCommon: 4167844018c9ed375cc01a843e9ee564399e53c3 470 | ReactNativeNavigation: c2dcda2b86e32090c443182206c915107d03106f 471 | Yoga: 7d13633d129fd179e01b8953d38d47be90db185a 472 | YogaKit: f782866e155069a2cca2517aafea43200b01fd5a 473 | 474 | PODFILE CHECKSUM: 25cec2777a38e06f777b15a78e1658c4214b6b68 475 | 476 | COCOAPODS: 1.10.0 477 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rnn-drawer-example", 3 | "version": "0.0.1", 4 | "description": "This is an example project for the react-native-navigation-drawer-extension package", 5 | "private": true, 6 | "scripts": { 7 | "android": "react-native run-android", 8 | "ios": "react-native run-ios", 9 | "start": "react-native start", 10 | "test": "jest", 11 | "lint": "eslint ." 12 | }, 13 | "dependencies": { 14 | "react": "16.13.1", 15 | "react-native": "0.63.3", 16 | "react-native-navigation": "^7.2.0", 17 | "react-native-navigation-drawer-extension": "^3.2.0" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.8.4", 21 | "@babel/runtime": "^7.8.4", 22 | "@react-native-community/eslint-config": "^1.1.0", 23 | "babel-jest": "^25.1.0", 24 | "eslint": "^6.5.1", 25 | "jest": "^25.1.0", 26 | "metro-react-native-babel-preset": "^0.59.0", 27 | "react-test-renderer": "16.13.1" 28 | }, 29 | "jest": { 30 | "preset": "react-native" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example/src/components/CustomDrawer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {SafeAreaView, StyleSheet, Text, View} from 'react-native'; 3 | import DrawerButton from './DrawerButton'; 4 | 5 | const Buttons = [ 6 | { 7 | id: 1, 8 | name: 'Home Page', 9 | component: 'HomePage', 10 | }, 11 | { 12 | id: 2, 13 | name: 'Page 1', 14 | component: 'Page1', 15 | }, 16 | { 17 | id: 3, 18 | name: 'Page 2', 19 | component: 'Page2', 20 | }, 21 | { 22 | id: 4, 23 | name: 'Another Page', 24 | component: 'AnotherPage', 25 | }, 26 | ]; 27 | 28 | const CustomDrawer = ({parentComponentId}) => { 29 | return ( 30 | 31 | 32 | Custom Drawer 33 | 34 | {Buttons.map((button) => { 35 | return ( 36 | 42 | ); 43 | })} 44 | 45 | 46 | ); 47 | }; 48 | 49 | const styles = StyleSheet.create({ 50 | mainContainer: { 51 | padding: 20, 52 | }, 53 | 54 | bodyText: { 55 | fontSize: 20, 56 | margin: 20, 57 | textAlign: 'center', 58 | }, 59 | }); 60 | 61 | export default CustomDrawer; 62 | -------------------------------------------------------------------------------- /example/src/components/DrawerButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {StyleSheet, Text, TouchableOpacity} from 'react-native'; 3 | import {Navigation} from 'react-native-navigation'; 4 | import {RNNDrawer} from 'react-native-navigation-drawer-extension'; 5 | 6 | /** 7 | * A workaround to avoid pushing 8 | * the same screen multiple times. 9 | * 10 | * For details, check: 11 | * https://github.com/aspect-apps/react-native-navigation-drawer-extension/issues/31 12 | */ 13 | 14 | /** 15 | * We set this to HomePage because, 16 | * in this project, HomePage 17 | * is the initial component. 18 | */ 19 | let lastPageName = 'HomePage'; 20 | const CurrentComponentName = 'CustomDrawer'; 21 | 22 | Navigation.events().registerComponentDidAppearListener((event) => { 23 | if (event.componentName !== CurrentComponentName) { 24 | lastPageName = event.componentName; 25 | } 26 | }); 27 | 28 | const DrawerButton = ({name, component, parentComponentId}) => { 29 | const handleOpenPage = () => { 30 | RNNDrawer.dismissDrawer(); 31 | 32 | if (lastPageName === component) { 33 | return; 34 | } 35 | 36 | Navigation.push(parentComponentId, { 37 | component: { 38 | name: component, 39 | }, 40 | }); 41 | }; 42 | 43 | return ( 44 | 45 | {name} 46 | 47 | ); 48 | }; 49 | 50 | const styles = StyleSheet.create({ 51 | buttonContainer: { 52 | margin: 5, 53 | padding: 10, 54 | borderRadius: 8, 55 | backgroundColor: '#44475a', 56 | }, 57 | 58 | buttonText: { 59 | color: 'white', 60 | textAlign: 'center', 61 | fontSize: 18, 62 | }, 63 | }); 64 | 65 | export default DrawerButton; 66 | -------------------------------------------------------------------------------- /example/src/pages/AnotherPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleSheet, Text } from 'react-native'; 3 | import { SideMenuView } from 'react-native-navigation-drawer-extension'; 4 | 5 | const AnotherPage = (props) => { 6 | console.log(props); 7 | return ( 8 | 16 | 17 | In this page, you can try the SideMenuView component, by simply swiping 18 | from the right to the left. 19 | 20 | 21 | ); 22 | }; 23 | 24 | const styles = StyleSheet.create({ 25 | mainContainer: { 26 | padding: 20, 27 | backgroundColor: 'white', 28 | flex: 1, 29 | }, 30 | 31 | bodyText: { 32 | fontSize: 20, 33 | }, 34 | }); 35 | 36 | export default AnotherPage; 37 | -------------------------------------------------------------------------------- /example/src/pages/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | SafeAreaView, 4 | StyleSheet, 5 | Text, 6 | TouchableOpacity, 7 | View, 8 | } from 'react-native'; 9 | import { 10 | RNNDrawer, 11 | SideMenuView, 12 | } from 'react-native-navigation-drawer-extension'; 13 | 14 | const HomePage = (props) => { 15 | const onPress = () => { 16 | RNNDrawer.showDrawer({ 17 | component: { 18 | name: 'CustomDrawer', 19 | passProps: { 20 | animationOpenTime: 300, 21 | animationCloseTime: 300, 22 | direction: 'left', 23 | dismissWhenTouchOutside: true, 24 | fadeOpacity: 0.6, 25 | drawerScreenWidth: '75%' || 445, 26 | drawerScreenHeight: '100%' || 700, 27 | parentComponentId: props.componentId, 28 | style: { 29 | backgroundColor: 'white', 30 | }, 31 | }, 32 | options: { 33 | layout: { 34 | componentBackgroundColor: 'black', 35 | }, 36 | }, 37 | }, 38 | }); 39 | }; 40 | 41 | return ( 42 | 64 | 65 | 66 | HomePage View 67 | 68 | 69 | Open Drawer 70 | 71 | 72 | 73 | 74 | ); 75 | }; 76 | 77 | const styles = StyleSheet.create({ 78 | mainContainer: { 79 | padding: 20, 80 | backgroundColor: 'white', 81 | alignItems: 'center', 82 | }, 83 | 84 | headlineText: { 85 | textAlign: 'center', 86 | fontSize: 24, 87 | fontWeight: '700', 88 | }, 89 | 90 | buttonContainer: { 91 | width: '90%', 92 | backgroundColor: '#44475a', 93 | borderRadius: 10, 94 | padding: 10, 95 | marginTop: 20, 96 | }, 97 | 98 | buttonText: { 99 | fontSize: 20, 100 | color: 'white', 101 | textAlign: 'center', 102 | fontWeight: '600', 103 | textTransform: 'uppercase', 104 | letterSpacing: 1.1, 105 | }, 106 | }); 107 | 108 | export default HomePage; 109 | -------------------------------------------------------------------------------- /example/src/pages/Page1.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | SafeAreaView, 4 | StyleSheet, 5 | Text, 6 | TouchableOpacity, 7 | View, 8 | } from 'react-native'; 9 | import {RNNDrawer} from 'react-native-navigation-drawer-extension'; 10 | 11 | const Page1 = (props) => { 12 | const onPress = () => { 13 | RNNDrawer.showDrawer({ 14 | component: { 15 | name: 'CustomDrawer', 16 | passProps: { 17 | direction: 'left', 18 | dismissWhenTouchOutside: true, 19 | fadeOpacity: 0.6, 20 | drawerScreenWidth: '75%' || 445, 21 | drawerScreenHeight: '100%' || 700, 22 | parentComponentId: props.componentId, 23 | }, 24 | }, 25 | }); 26 | }; 27 | 28 | return ( 29 | 30 | 31 | Page1 View 32 | 33 | 34 | Open Drawer 35 | 36 | 37 | 38 | ); 39 | }; 40 | 41 | const styles = StyleSheet.create({ 42 | mainContainer: { 43 | padding: 20, 44 | backgroundColor: 'white', 45 | alignItems: 'center', 46 | }, 47 | 48 | headlineText: { 49 | textAlign: 'center', 50 | fontSize: 24, 51 | fontWeight: '700', 52 | }, 53 | 54 | buttonContainer: { 55 | width: '90%', 56 | backgroundColor: '#44475a', 57 | borderRadius: 10, 58 | padding: 10, 59 | marginTop: 20, 60 | }, 61 | 62 | buttonText: { 63 | fontSize: 20, 64 | color: 'white', 65 | textAlign: 'center', 66 | fontWeight: '600', 67 | textTransform: 'uppercase', 68 | letterSpacing: 1.1, 69 | }, 70 | }); 71 | 72 | export default Page1; 73 | -------------------------------------------------------------------------------- /example/src/pages/Page2.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | SafeAreaView, 4 | StyleSheet, 5 | Text, 6 | TouchableOpacity, 7 | View, 8 | } from 'react-native'; 9 | import {RNNDrawer} from 'react-native-navigation-drawer-extension'; 10 | 11 | const Page2 = (props) => { 12 | const onPress = () => { 13 | RNNDrawer.showDrawer({ 14 | component: { 15 | name: 'CustomDrawer', 16 | passProps: { 17 | direction: 'left', 18 | dismissWhenTouchOutside: true, 19 | fadeOpacity: 0.6, 20 | drawerScreenWidth: '75%' || 445, 21 | drawerScreenHeight: '100%' || 700, 22 | parentComponentId: props.componentId, 23 | }, 24 | }, 25 | }); 26 | }; 27 | 28 | return ( 29 | 30 | 31 | Page2 View 32 | 33 | 34 | Open Drawer 35 | 36 | 37 | 38 | ); 39 | }; 40 | 41 | const styles = StyleSheet.create({ 42 | mainContainer: { 43 | padding: 20, 44 | backgroundColor: 'white', 45 | alignItems: 'center', 46 | }, 47 | 48 | headlineText: { 49 | textAlign: 'center', 50 | fontSize: 24, 51 | fontWeight: '700', 52 | }, 53 | 54 | buttonContainer: { 55 | width: '90%', 56 | backgroundColor: '#44475a', 57 | borderRadius: 10, 58 | padding: 10, 59 | marginTop: 20, 60 | }, 61 | 62 | buttonText: { 63 | fontSize: 20, 64 | color: 'white', 65 | textAlign: 'center', 66 | fontWeight: '600', 67 | textTransform: 'uppercase', 68 | letterSpacing: 1.1, 69 | }, 70 | }); 71 | 72 | export default Page2; 73 | -------------------------------------------------------------------------------- /lib/RNNDrawer.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @description An animated drawer component for react-native-navigation. 4 | */ 5 | import * as React from 'react'; 6 | import { Layout } from 'react-native-navigation'; 7 | declare interface RNNDrawerOptions { 8 | /** 9 | * Id of parent component of the drawer. 10 | * This field is necessary in order to be able 11 | * to push screens inside the drawer 12 | */ 13 | parentComponentId: string; 14 | /** 15 | * Direction to open the collage, 16 | * one of: ["left", "right", "top", "bottom"] 17 | * If not provided, drawer might have 18 | * a weird effect when closing 19 | */ 20 | direction?: DirectionType; 21 | /** 22 | * Time in milliseconds to execute the drawer opening animation 23 | */ 24 | animationOpenTime?: number; 25 | /** 26 | * Time in milliseconds to execute the drawer closing animation 27 | */ 28 | animationCloseTime?: number; 29 | /** 30 | * Whether the drawer be dismissed when a click is registered outside 31 | */ 32 | dismissWhenTouchOutside?: boolean; 33 | /** 34 | * Opacity of the screen outside the drawer 35 | */ 36 | fadeOpacity?: number; 37 | /** 38 | * Width of drawer on portrait orientation. Pass a string containing '%' (e.g. "80%") 39 | * for setting the width in relation to the screen or a number for absolute width (e.g. 300) 40 | */ 41 | drawerScreenWidth?: number | string; 42 | /** 43 | * Width of drawer on landscape orientation. Pass a string containing '%' (e.g. "80%") 44 | * for setting the width in relation to the screen or a number for absolute width (e.g. 300) 45 | */ 46 | drawerScreenWidthOnLandscape?: number | string; 47 | /** 48 | * Height of drawer. Pass a string containing '%' (e.g. "30%") 49 | * for setting the height in relation to the screen or a number for absolute height (e.g. 300) 50 | */ 51 | drawerScreenHeight?: number | string; 52 | disableDragging?: boolean; 53 | disableSwiping?: boolean; 54 | } 55 | export declare enum DirectionType { 56 | left = "left", 57 | right = "right", 58 | bottom = "bottom", 59 | top = "top" 60 | } 61 | declare class RNNDrawer { 62 | /** 63 | * Generates the drawer component to 64 | * be used with react-native-navigation 65 | * 66 | * @param component 67 | */ 68 | static create(Component: React.ComponentType): any; 69 | /** 70 | * Shows a drawer component 71 | * 72 | * @param layout 73 | */ 74 | static showDrawer(layout: Layout): void; 75 | /** 76 | * Dismiss the drawer component 77 | */ 78 | static dismissDrawer(): void; 79 | } 80 | export default RNNDrawer; 81 | -------------------------------------------------------------------------------- /lib/RNNDrawer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @author Luke Brandon Farrell 4 | * @description An animated drawer component for react-native-navigation. 5 | */ 6 | var __extends = (this && this.__extends) || (function () { 7 | var extendStatics = function (d, b) { 8 | extendStatics = Object.setPrototypeOf || 9 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 10 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 11 | return extendStatics(d, b); 12 | }; 13 | return function (d, b) { 14 | extendStatics(d, b); 15 | function __() { this.constructor = d; } 16 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 17 | }; 18 | })(); 19 | var __assign = (this && this.__assign) || function () { 20 | __assign = Object.assign || function(t) { 21 | for (var s, i = 1, n = arguments.length; i < n; i++) { 22 | s = arguments[i]; 23 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 24 | t[p] = s[p]; 25 | } 26 | return t; 27 | }; 28 | return __assign.apply(this, arguments); 29 | }; 30 | Object.defineProperty(exports, "__esModule", { value: true }); 31 | exports.DirectionType = void 0; 32 | /* NPM - Node Package Manage */ 33 | var React = require("react"); 34 | var react_native_1 = require("react-native"); 35 | var react_native_navigation_1 = require("react-native-navigation"); 36 | /* Utils - Project Utilities */ 37 | var events_1 = require("./events"); 38 | var DirectionType; 39 | (function (DirectionType) { 40 | DirectionType["left"] = "left"; 41 | DirectionType["right"] = "right"; 42 | DirectionType["bottom"] = "bottom"; 43 | DirectionType["top"] = "top"; 44 | })(DirectionType = exports.DirectionType || (exports.DirectionType = {})); 45 | var RNNDrawer = /** @class */ (function () { 46 | function RNNDrawer() { 47 | } 48 | /** 49 | * Generates the drawer component to 50 | * be used with react-native-navigation 51 | * 52 | * @param component 53 | */ 54 | RNNDrawer.create = function (Component) { 55 | var WrappedDrawer = /** @class */ (function (_super) { 56 | __extends(WrappedDrawer, _super); 57 | /** 58 | * [ Built-in React method. ] 59 | * 60 | * Setup the component. Executes when the component is created 61 | * 62 | * @param {object} props 63 | */ 64 | function WrappedDrawer(props) { 65 | var _this = _super.call(this, props) || this; 66 | _this.panningStartedPoint = { moveX: 0, moveY: 0 }; 67 | _this.startedFromSideMenu = false; 68 | _this.onOrientationChange = function (_a) { 69 | var window = _a.window; 70 | var screenHeight = window.height; 71 | _this.setState({ screenHeight: screenHeight }); 72 | // Apply correct position if opened from right 73 | if (_this.props.direction === 'right') { 74 | // Calculates the position of the drawer from the left side of the screen 75 | var alignedMovementValue = window.width - _this.drawerWidth; 76 | _this.state.sideMenuOpenValue.setValue(alignedMovementValue); 77 | } 78 | }; 79 | _this.screenWidth = react_native_1.Dimensions.get('window').width; 80 | _this.screenHeight = react_native_1.Dimensions.get('window').height; 81 | _this.panResponder = react_native_1.PanResponder.create({ 82 | onStartShouldSetPanResponder: function (_evt, _gestureState) { return false; }, 83 | onStartShouldSetPanResponderCapture: function (_evt, _gestureState) { return false; }, 84 | onMoveShouldSetPanResponder: function (_evt, _gestureState) { 85 | var dx = _gestureState.dx, dy = _gestureState.dy; 86 | if (_this.props.direction === DirectionType.left || 87 | _this.props.direction === DirectionType.right) 88 | return Math.abs(dx) > 5; 89 | else 90 | return Math.abs(dy) > 5; 91 | }, 92 | onMoveShouldSetPanResponderCapture: function (_evt, _gestureState) { return false; }, 93 | onPanResponderGrant: function (_evt, _gestureState) { 94 | var moveX = _gestureState.moveX, moveY = _gestureState.moveY; 95 | events_1.dispatch('SWIPE_START', { moveX: moveX, moveY: moveY }); 96 | }, 97 | onPanResponderRelease: function (_evt, gestureState) { 98 | var vx = gestureState.vx; 99 | // Emit this event when the gesture ends 100 | events_1.dispatch('SWIPE_END', vx > 0 ? 'right' : 'left'); 101 | }, 102 | onPanResponderTerminationRequest: function (_evt, _gestureState) { return false; }, 103 | onShouldBlockNativeResponder: function (_evt, _gestureState) { return false; }, 104 | onPanResponderMove: function (_evt, _gestureState) { 105 | var moveX = _gestureState.moveX, moveY = _gestureState.moveY; 106 | var direction = _this.props.direction || 'left'; 107 | events_1.dispatch('SWIPE_MOVE', { value: { moveX: moveX, moveY: moveY }, direction: direction }); 108 | }, 109 | }); 110 | /* 111 | * We need to convert the pushed drawer width 112 | * to a number as it can either be a string ('20%') 113 | * or number (400). 114 | */ 115 | var _resolveDrawerSize = function (value, max) { 116 | /* 117 | * If the type is a string '%' then it should be a percentage relative 118 | * to our max size. 119 | */ 120 | if (typeof value === 'string') { 121 | var valueAsNumber = parseFloat(value) || 100; 122 | var size = max * (valueAsNumber / 100); 123 | return size; 124 | } 125 | return value; 126 | }; 127 | /** Component Variables */ 128 | _this.drawerWidth = _resolveDrawerSize(_this.isLandscape() 129 | ? props.drawerScreenWidthOnLandscape 130 | : props.drawerScreenWidth, _this.screenWidth); 131 | _this.drawerHeight = _resolveDrawerSize(props.drawerScreenHeight, _this.screenHeight); 132 | _this.drawerOpenedValues = { 133 | left: 0, 134 | right: _this.screenWidth - _this.drawerWidth, 135 | top: _this.drawerHeight - _this.screenHeight, 136 | bottom: _this.screenHeight - _this.drawerHeight, 137 | }; 138 | _this.initialValues = { 139 | left: -_this.drawerWidth, 140 | right: _this.screenWidth, 141 | top: -_this.screenHeight, 142 | bottom: _this.screenHeight, 143 | }; 144 | /** Component State */ 145 | _this.state = { 146 | sideMenuOpenValue: new react_native_1.Animated.Value(_this.initialValues[props.direction]), 147 | sideMenuOverlayOpacity: new react_native_1.Animated.Value(0), 148 | sideMenuSwipingStarted: false, 149 | sideMenuIsDismissing: false, 150 | screenHeight: _this.screenHeight, 151 | }; 152 | /** Component Bindings */ 153 | _this.touchedOutside = _this.touchedOutside.bind(_this); 154 | _this.dismissDrawerWithAnimation = _this.dismissDrawerWithAnimation.bind(_this); 155 | _this.registerListeners = _this.registerListeners.bind(_this); 156 | _this.removeListeners = _this.removeListeners.bind(_this); 157 | _this.isLandscape = _this.isLandscape.bind(_this); 158 | react_native_navigation_1.Navigation.events().bindComponent(_this); 159 | return _this; 160 | } 161 | /** 162 | * Check if device is in landscape mode 163 | */ 164 | WrappedDrawer.prototype.isLandscape = function () { 165 | var dim = react_native_1.Dimensions.get('window'); 166 | return dim.height <= dim.width; 167 | }; 168 | /** 169 | * [ Built-in React method. ] 170 | * 171 | * Executed when the component is mounted to the screen 172 | */ 173 | WrappedDrawer.prototype.componentDidMount = function () { 174 | /** Props */ 175 | var _a = this.props, direction = _a.direction, fadeOpacity = _a.fadeOpacity, animateDrawerExpanding = _a.animateDrawerExpanding; 176 | if (typeof animateDrawerExpanding !== 'undefined' && 177 | !animateDrawerExpanding) 178 | this.startedFromSideMenu = true; 179 | // Animate side menu open 180 | this.animatedDrawer = react_native_1.Animated.timing(this.state.sideMenuOpenValue, { 181 | toValue: this.drawerOpenedValues[direction], 182 | duration: this.props.animationOpenTime, 183 | useNativeDriver: true, 184 | }); 185 | // Animate outside side menu opacity 186 | this.animatedOpacity = react_native_1.Animated.timing(this.state.sideMenuOverlayOpacity, { 187 | toValue: fadeOpacity, 188 | duration: this.props.animationOpenTime, 189 | useNativeDriver: true, 190 | }); 191 | }; 192 | /** 193 | * [ react-native-navigation method. ] 194 | * 195 | * Executed when the component is navigated to view. 196 | */ 197 | WrappedDrawer.prototype.componentDidAppear = function () { 198 | this.registerListeners(); 199 | // If there has been no Swiping, and this component appears, then just start the open animations 200 | if (!this.state.sideMenuSwipingStarted && 201 | this.props.animateDrawerExpanding) { 202 | this.animatedDrawer.start(); 203 | this.animatedOpacity.start(); 204 | } 205 | }; 206 | /** 207 | * [ react-native-navigation method. ] 208 | * 209 | * Executed when the component is navigated away from view. 210 | */ 211 | WrappedDrawer.prototype.componentDidDisappear = function () { 212 | this.removeListeners(); 213 | events_1.dispatch('DRAWER_CLOSED'); 214 | }; 215 | /** 216 | * Registers all the listenrs for this component 217 | */ 218 | WrappedDrawer.prototype.registerListeners = function () { 219 | var _this = this; 220 | /** Props */ 221 | var _a = this.props, direction = _a.direction, fadeOpacity = _a.fadeOpacity; 222 | // Adapt the drawer's size on orientation change 223 | this.orientationChangeListener = react_native_1.Dimensions.addEventListener('change', this.onOrientationChange); 224 | // Executes when the side of the screen interaction starts 225 | this.unsubscribeSwipeStart = events_1.listen('SWIPE_START', function (value) { 226 | _this.panningStartedPoint.moveX = value.moveX; 227 | _this.panningStartedPoint.moveY = value.moveY; 228 | _this.setState({ 229 | sideMenuSwipingStarted: true, 230 | }); 231 | }); 232 | // Executes when the side of the screen is interacted with 233 | this.unsubscribeSwipeMove = events_1.listen('SWIPE_MOVE', function (_a) { 234 | var value = _a.value, swipeDirection = _a.direction; 235 | // Cover special case when we are swiping from the edge of the screen 236 | if (_this.startedFromSideMenu) { 237 | if (direction === 'left' && value.moveX < _this.drawerWidth) { 238 | _this.state.sideMenuOpenValue.setValue(value.moveX - _this.drawerWidth); 239 | var normalizedOpacity_1 = Math.min((value.moveX / _this.drawerWidth) * fadeOpacity, fadeOpacity); 240 | _this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity_1); 241 | } 242 | if (direction === 'right' && 243 | _this.screenWidth - value.moveX < _this.drawerWidth) { 244 | _this.state.sideMenuOpenValue.setValue(value.moveX); 245 | var normalizedOpacity_2 = Math.min(((_this.screenWidth - value.moveX) / _this.drawerWidth) * 246 | fadeOpacity, fadeOpacity); 247 | _this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity_2); 248 | } 249 | return; 250 | } 251 | if (_this.props.disableDragging) 252 | return; 253 | // Calculates the translateX / translateY value 254 | var alignedMovementValue = 0; 255 | // To swap the direction if needed 256 | var directionModifier = 1; 257 | // Whether we use the height of the drawer or the width 258 | var drawerDimension = _this.drawerWidth; 259 | if (swipeDirection === 'left') { 260 | alignedMovementValue = 261 | value.moveX - _this.panningStartedPoint.moveX; 262 | } 263 | else if (swipeDirection === 'right') { 264 | alignedMovementValue = 265 | _this.panningStartedPoint.moveX - value.moveX; 266 | directionModifier = -1; 267 | } 268 | else if (swipeDirection === 'bottom') { 269 | alignedMovementValue = 270 | _this.panningStartedPoint.moveY - value.moveY; 271 | directionModifier = -1; 272 | drawerDimension = _this.drawerHeight; 273 | } 274 | else if (swipeDirection === 'top') { 275 | alignedMovementValue = 276 | value.moveY - _this.panningStartedPoint.moveY; 277 | drawerDimension = _this.drawerHeight; 278 | } 279 | // Calculates the percentage 0 - 1 of which the drawer is open 280 | var openedPercentage = Math.abs(drawerDimension + alignedMovementValue) / 281 | drawerDimension; 282 | // Calculates the opacity to set of the screen based on the percentage the drawer is open 283 | var normalizedOpacity = Math.min(openedPercentage * fadeOpacity, fadeOpacity); 284 | // Does not allow the drawer to go further than the maximum width / height 285 | if (0 > alignedMovementValue) { 286 | // Sets the animation values, we use this so we can resume animation from any point 287 | _this.state.sideMenuOpenValue.setValue(_this.drawerOpenedValues[direction] + 288 | alignedMovementValue * directionModifier); 289 | _this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity); 290 | } 291 | }); 292 | // Executes when the side of the screen interaction ends 293 | this.unsubscribeSwipeEnd = events_1.listen('SWIPE_END', function (swipeDirection) { 294 | if (_this.props.disableSwiping && !_this.startedFromSideMenu) 295 | return; 296 | var reverseDirection = { 297 | right: 'left', 298 | left: 'right', 299 | top: 'bottom', 300 | bottom: 'top', 301 | }; 302 | // In case the drawer started by dragging the edge of the screen reset the flag 303 | _this.startedFromSideMenu = false; 304 | if (swipeDirection === reverseDirection[direction]) { 305 | _this.animatedDrawer.start(); 306 | _this.animatedOpacity.start(); 307 | } 308 | else { 309 | if (!_this.state.sideMenuIsDismissing) { 310 | _this.setState({ 311 | sideMenuIsDismissing: true, 312 | }, function () { 313 | _this.dismissDrawerWithAnimation(); 314 | }); 315 | } 316 | } 317 | }); 318 | // Executes when the drawer needs to be dismissed 319 | this.unsubscribeDismissDrawer = events_1.listen('DISMISS_DRAWER', function () { 320 | if (!_this.state.sideMenuIsDismissing) { 321 | _this.dismissDrawerWithAnimation(); 322 | } 323 | }); 324 | }; 325 | /** 326 | * Removes all the listenrs from this component 327 | */ 328 | WrappedDrawer.prototype.removeListeners = function () { 329 | if (this.orientationChangeListener) 330 | this.orientationChangeListener.remove(); 331 | if (this.unsubscribeSwipeStart) 332 | this.unsubscribeSwipeStart(); 333 | if (this.unsubscribeSwipeMove) 334 | this.unsubscribeSwipeMove(); 335 | if (this.unsubscribeSwipeEnd) 336 | this.unsubscribeSwipeEnd(); 337 | if (this.unsubscribeDismissDrawer) 338 | this.unsubscribeDismissDrawer(); 339 | }; 340 | /** 341 | * [ Built-in React method. ] 342 | * 343 | * Allows us to render JSX to the screen 344 | */ 345 | WrappedDrawer.prototype.render = function () { 346 | /** Styles */ 347 | var sideMenuOverlayStyle = styles.sideMenuOverlayStyle, sideMenuContainerStyle = styles.sideMenuContainerStyle; 348 | /** Props */ 349 | var _a = this.props, direction = _a.direction, style = _a.style; 350 | /** State */ 351 | var _b = this.state, sideMenuOpenValue = _b.sideMenuOpenValue, sideMenuOverlayOpacity = _b.sideMenuOverlayOpacity; 352 | /** Variables */ 353 | var animatedValue = direction === DirectionType.left || direction === DirectionType.right 354 | ? { translateX: sideMenuOpenValue } 355 | : { translateY: sideMenuOpenValue }; 356 | return (React.createElement(react_native_1.View, __assign({ style: sideMenuContainerStyle }, this.panResponder.panHandlers), 357 | React.createElement(react_native_1.TouchableWithoutFeedback, { onPress: this.touchedOutside }, 358 | React.createElement(react_native_1.Animated.View, { style: [ 359 | sideMenuOverlayStyle, 360 | { opacity: sideMenuOverlayOpacity }, 361 | ] })), 362 | React.createElement(react_native_1.Animated.View, { style: [ 363 | { backgroundColor: '#FFF' }, 364 | style, 365 | { 366 | height: this.state.screenHeight, 367 | width: this.drawerWidth, 368 | transform: [animatedValue], 369 | }, 370 | ] }, 371 | React.createElement(Component, __assign({}, this.props))))); 372 | }; 373 | /** 374 | * Touched outside drawer 375 | */ 376 | WrappedDrawer.prototype.touchedOutside = function () { 377 | var dismissWhenTouchOutside = this.props.dismissWhenTouchOutside; 378 | if (dismissWhenTouchOutside) { 379 | this.dismissDrawerWithAnimation(); 380 | } 381 | }; 382 | /** 383 | * Dismisses drawer with animation 384 | */ 385 | WrappedDrawer.prototype.dismissDrawerWithAnimation = function () { 386 | var _this = this; 387 | var direction = this.props.direction; 388 | var sideMenuIsDismissing = this.state.sideMenuIsDismissing; 389 | var closeValues = { 390 | left: -this.drawerWidth, 391 | right: this.screenWidth, 392 | top: -this.screenHeight, 393 | bottom: this.screenHeight, 394 | }; 395 | // Animate side menu close 396 | react_native_1.Animated.timing(this.state.sideMenuOpenValue, { 397 | toValue: closeValues[direction], 398 | duration: this.props.animationCloseTime, 399 | useNativeDriver: true, 400 | }).start(function () { 401 | react_native_navigation_1.Navigation.dismissOverlay(_this.props.componentId); 402 | _this.setState({ sideMenuIsDismissing: false }); 403 | }); 404 | // Animate outside side menu opacity 405 | react_native_1.Animated.timing(this.state.sideMenuOverlayOpacity, { 406 | toValue: 0, 407 | duration: this.props.animationCloseTime, 408 | useNativeDriver: true, 409 | }).start(); 410 | }; 411 | WrappedDrawer.defaultProps = { 412 | animationOpenTime: 300, 413 | animationCloseTime: 300, 414 | direction: 'left', 415 | dismissWhenTouchOutside: true, 416 | fadeOpacity: 0.6, 417 | drawerScreenWidth: '80%', 418 | drawerScreenWidthOnLandscape: '30%', 419 | drawerScreenHeight: '100%', 420 | animateDrawerExpanding: true, 421 | disableDragging: false, 422 | disableSwiping: false, 423 | }; 424 | return WrappedDrawer; 425 | }(React.Component)); 426 | return WrappedDrawer; 427 | }; 428 | /** 429 | * Shows a drawer component 430 | * 431 | * @param layout 432 | */ 433 | RNNDrawer.showDrawer = function (layout) { 434 | var _a, _b, _c, _d, _e; 435 | // By default for this library, we make the 'componentBackgroundColor' transparent 436 | var componentBackgroundColor = (_d = (_c = (_b = (_a = layout === null || layout === void 0 ? void 0 : layout.component) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.layout) === null || _c === void 0 ? void 0 : _c.componentBackgroundColor) !== null && _d !== void 0 ? _d : 'transparent'; 437 | var options = __assign(__assign({}, (_e = layout === null || layout === void 0 ? void 0 : layout.component) === null || _e === void 0 ? void 0 : _e.options), { layout: { 438 | componentBackgroundColor: componentBackgroundColor, 439 | } }); 440 | // Mutate options to add 'transparent' by default 441 | // @ts-ignore 442 | layout.component.options = __assign({}, options); 443 | react_native_navigation_1.Navigation.showOverlay(layout); 444 | }; 445 | /** 446 | * Dismiss the drawer component 447 | */ 448 | RNNDrawer.dismissDrawer = function () { 449 | events_1.dispatch('DISMISS_DRAWER', true); 450 | }; 451 | return RNNDrawer; 452 | }()); 453 | exports.default = RNNDrawer; 454 | /** -------------------------------------------- */ 455 | /** Component Styling */ 456 | /** -------------------------------------------- */ 457 | var styles = react_native_1.StyleSheet.create({ 458 | sideMenuContainerStyle: { 459 | flex: 1, 460 | flexDirection: 'row', 461 | }, 462 | sideMenuOverlayStyle: { 463 | position: 'absolute', 464 | width: '100%', 465 | height: '100%', 466 | backgroundColor: '#000', 467 | }, 468 | }); 469 | -------------------------------------------------------------------------------- /lib/SideMenuView.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @title SideMenuView.js 4 | * @description A swipeable view to open a drawer. 5 | */ 6 | import * as React from 'react'; 7 | import { StyleProp, ViewStyle } from 'react-native'; 8 | import { Options } from 'react-native-navigation'; 9 | interface IProps { 10 | swipeSensitivity?: number; 11 | sideMargin?: number; 12 | sideMarginLeft?: number; 13 | sideMarginRight?: number; 14 | style?: StyleProp; 15 | drawerName: string; 16 | direction: 'left' | 'right'; 17 | passProps?: any; 18 | options?: Options; 19 | } 20 | declare class SideMenuView extends React.Component { 21 | private isOpened; 22 | private _panResponderMethods; 23 | private _leftPanResponder; 24 | private _rightPanResponder; 25 | private unsubscribeDrawerClosed; 26 | static defaultProps: { 27 | sideMargin: number; 28 | swipeSensitivity: number; 29 | direction: string; 30 | }; 31 | /** 32 | * [ Built-in React method. ] 33 | * 34 | * Setup the component. Executes when the component is created 35 | * 36 | * @param {object} props 37 | */ 38 | constructor(props: IProps); 39 | /** 40 | * [ Built-in React method. ] 41 | * 42 | * Executed when the component is mounted to the screen 43 | */ 44 | componentDidMount(): void; 45 | /** 46 | * Registers all the listenrs for this component 47 | */ 48 | registerListeners(): void; 49 | /** 50 | * Removes all the listenrs from this component 51 | */ 52 | removeListeners(): void; 53 | /** 54 | * [ Built-in React method. ] 55 | * 56 | * Allows us to render JSX to the screen 57 | */ 58 | render(): JSX.Element; 59 | } 60 | export default SideMenuView; 61 | -------------------------------------------------------------------------------- /lib/SideMenuView.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @author Luke Brandon Farrell 4 | * @title SideMenuView.js 5 | * @description A swipeable view to open a drawer. 6 | */ 7 | var __extends = (this && this.__extends) || (function () { 8 | var extendStatics = function (d, b) { 9 | extendStatics = Object.setPrototypeOf || 10 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 11 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 12 | return extendStatics(d, b); 13 | }; 14 | return function (d, b) { 15 | extendStatics(d, b); 16 | function __() { this.constructor = d; } 17 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 18 | }; 19 | })(); 20 | var __assign = (this && this.__assign) || function () { 21 | __assign = Object.assign || function(t) { 22 | for (var s, i = 1, n = arguments.length; i < n; i++) { 23 | s = arguments[i]; 24 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 25 | t[p] = s[p]; 26 | } 27 | return t; 28 | }; 29 | return __assign.apply(this, arguments); 30 | }; 31 | var __rest = (this && this.__rest) || function (s, e) { 32 | var t = {}; 33 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) 34 | t[p] = s[p]; 35 | if (s != null && typeof Object.getOwnPropertySymbols === "function") 36 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { 37 | if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) 38 | t[p[i]] = s[p[i]]; 39 | } 40 | return t; 41 | }; 42 | Object.defineProperty(exports, "__esModule", { value: true }); 43 | /* NPM - Node Package Manage */ 44 | var React = require("react"); 45 | var react_native_1 = require("react-native"); 46 | /* Utils - Project Utilities */ 47 | var RNNDrawer_1 = require("./RNNDrawer"); 48 | var events_1 = require("./events"); 49 | var RNNDrawer_2 = require("./RNNDrawer"); 50 | var screenHeight = react_native_1.Dimensions.get('screen').height; 51 | var SideMenuView = /** @class */ (function (_super) { 52 | __extends(SideMenuView, _super); 53 | /** 54 | * [ Built-in React method. ] 55 | * 56 | * Setup the component. Executes when the component is created 57 | * 58 | * @param {object} props 59 | */ 60 | function SideMenuView(props) { 61 | var _this = _super.call(this, props) || this; 62 | _this.isOpened = false; 63 | var swipeSensitivity = props.swipeSensitivity, drawerName = props.drawerName, direction = props.direction, passProps = props.passProps, options = props.options; 64 | var directionIsLeft = direction ? direction == 'left' : true; 65 | _this._panResponderMethods = { 66 | // Ask to be the responder: 67 | onStartShouldSetPanResponder: function (_evt, _gestureState) { return true; }, 68 | onStartShouldSetPanResponderCapture: function (_evt, _gestureState) { return true; }, 69 | onMoveShouldSetPanResponder: function (_evt, _gestureState) { return true; }, 70 | onMoveShouldSetPanResponderCapture: function (_evt, _gestureState) { return true; }, 71 | onPanResponderGrant: function (_evt, _gestureState) { 72 | events_1.dispatch('SWIPE_START'); 73 | }, 74 | onPanResponderRelease: function (_evt, gestureState) { 75 | var vx = gestureState.vx; 76 | // Emit this event when the gesture ends 77 | events_1.dispatch('SWIPE_END', vx > 0 ? 'right' : 'left'); 78 | }, 79 | onPanResponderTerminationRequest: function (_evt, _gestureState) { return false; }, 80 | onShouldBlockNativeResponder: function (_evt, _gestureState) { return false; }, 81 | }; 82 | // LEFT PAN RESPONDER 83 | _this._leftPanResponder = react_native_1.PanResponder.create(__assign(__assign({}, _this._panResponderMethods), { onPanResponderMove: function (_evt, gestureState) { 84 | var moveX = gestureState.moveX, vx = gestureState.vx; 85 | // Emit this event on movement 86 | events_1.dispatch('SWIPE_MOVE', { value: { moveX: moveX }, direction: 'left' }); 87 | // Left Swipe 88 | if (typeof swipeSensitivity !== 'undefined') { 89 | if (vx > swipeSensitivity && !_this.isOpened && directionIsLeft) { 90 | _this.isOpened = true; 91 | RNNDrawer_1.default.showDrawer({ 92 | component: { 93 | name: drawerName, 94 | passProps: __assign({ direction: RNNDrawer_2.DirectionType.left, parentComponentId: passProps === null || passProps === void 0 ? void 0 : passProps.parentComponentId, animateDrawerExpanding: false }, passProps), 95 | options: __assign({}, options), 96 | }, 97 | }); 98 | } 99 | } 100 | } })); 101 | // RIGHT PAN RESPONDER 102 | _this._rightPanResponder = react_native_1.PanResponder.create(__assign(__assign({}, _this._panResponderMethods), { onPanResponderMove: function (_evt, gestureState) { 103 | var moveX = gestureState.moveX, vx = gestureState.vx; 104 | // Emit this event on movement 105 | events_1.dispatch('SWIPE_MOVE', { value: { moveX: moveX }, direction: 'right' }); 106 | // Right Swipe 107 | if (typeof swipeSensitivity !== 'undefined') { 108 | if (vx > -swipeSensitivity && !_this.isOpened && !directionIsLeft) { 109 | _this.isOpened = true; 110 | RNNDrawer_1.default.showDrawer({ 111 | component: { 112 | name: drawerName, 113 | passProps: __assign({ direction: RNNDrawer_2.DirectionType.right, parentComponentId: passProps === null || passProps === void 0 ? void 0 : passProps.parentComponentId, animateDrawerExpanding: false }, passProps), 114 | options: __assign({}, options), 115 | }, 116 | }); 117 | } 118 | } 119 | } })); 120 | _this.registerListeners = _this.registerListeners.bind(_this); 121 | _this.removeListeners = _this.removeListeners.bind(_this); 122 | return _this; 123 | } 124 | /** 125 | * [ Built-in React method. ] 126 | * 127 | * Executed when the component is mounted to the screen 128 | */ 129 | SideMenuView.prototype.componentDidMount = function () { 130 | this.registerListeners(); 131 | }; 132 | /** 133 | * Registers all the listenrs for this component 134 | */ 135 | SideMenuView.prototype.registerListeners = function () { 136 | var _this = this; 137 | // Event fires when drawer is closed 138 | this.unsubscribeDrawerClosed = events_1.listen('DRAWER_CLOSED', function () { 139 | _this.isOpened = false; 140 | }); 141 | }; 142 | /** 143 | * Removes all the listenrs from this component 144 | */ 145 | SideMenuView.prototype.removeListeners = function () { 146 | this.unsubscribeDrawerClosed(); 147 | }; 148 | /** 149 | * [ Built-in React method. ] 150 | * 151 | * Allows us to render JSX to the screen 152 | */ 153 | SideMenuView.prototype.render = function () { 154 | /** Props */ 155 | var _a = this.props, children = _a.children, direction = _a.direction, sideMargin = _a.sideMargin, sideMarginLeft = _a.sideMarginLeft, sideMarginRight = _a.sideMarginRight, props = __rest(_a, ["children", "direction", "sideMargin", "sideMarginLeft", "sideMarginRight"]); 156 | var directionIsLeft = direction ? direction == 'left' : true; 157 | return (React.createElement(react_native_1.View, __assign({}, props), 158 | children, 159 | directionIsLeft ? (React.createElement(react_native_1.View, __assign({ style: { 160 | left: 0, 161 | position: 'absolute', 162 | width: sideMargin || sideMarginLeft, 163 | height: screenHeight, 164 | zIndex: 9999, 165 | } }, this._leftPanResponder.panHandlers))) : (React.createElement(react_native_1.View, __assign({ style: { 166 | position: 'absolute', 167 | right: 0, 168 | width: sideMargin || sideMarginRight, 169 | height: screenHeight, 170 | zIndex: 9999, 171 | } }, this._rightPanResponder.panHandlers))))); 172 | }; 173 | SideMenuView.defaultProps = { 174 | sideMargin: 15, 175 | swipeSensitivity: 0.2, 176 | direction: 'left', 177 | }; 178 | return SideMenuView; 179 | }(React.Component)); 180 | exports.default = SideMenuView; 181 | -------------------------------------------------------------------------------- /lib/events.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @description Event dispatcher for comunication between components. 4 | */ 5 | /** 6 | * @description add listener 7 | * @public 8 | * @param {string} name name listener 9 | * @param {function} func function for call 10 | * @returns {function} unsubscribe function 11 | */ 12 | export declare function listen(name: string, func: any): () => void; 13 | /** 14 | * @description dispatch to listener 15 | * @public 16 | * @param {string} name name listener 17 | * @param {any} arg argument for send to listen(...) 18 | * @returns {void} 19 | */ 20 | export declare function dispatch(name: string, arg?: any): void; 21 | -------------------------------------------------------------------------------- /lib/events.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @author Luke Brandon Farrell 4 | * @description Event dispatcher for comunication between components. 5 | */ 6 | Object.defineProperty(exports, "__esModule", { value: true }); 7 | exports.dispatch = exports.listen = void 0; 8 | /** 9 | * @description events 10 | * @private 11 | */ 12 | var _events = {}; 13 | /** 14 | * @description add listener 15 | * @public 16 | * @param {string} name name listener 17 | * @param {function} func function for call 18 | * @returns {function} unsubscribe function 19 | */ 20 | function listen(name, func) { 21 | if (!_events[name]) 22 | _events[name] = { count: 0, funcs: {} }; 23 | var key = _events[name].count++; 24 | _events[name].funcs[key] = func; 25 | return function () { 26 | delete _events[name].funcs[key]; 27 | }; 28 | } 29 | exports.listen = listen; 30 | /** 31 | * @description dispatch to listener 32 | * @public 33 | * @param {string} name name listener 34 | * @param {any} arg argument for send to listen(...) 35 | * @returns {void} 36 | */ 37 | function dispatch(name, arg) { 38 | if (_events[name]) 39 | for (var func in _events[name].funcs) 40 | _events[name].funcs[func] && _events[name].funcs[func](arg); 41 | } 42 | exports.dispatch = dispatch; 43 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | export { default as RNNDrawer } from './RNNDrawer'; 2 | export { default as SideMenuView } from './SideMenuView'; 3 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var RNNDrawer_1 = require("./RNNDrawer"); 4 | Object.defineProperty(exports, "RNNDrawer", { enumerable: true, get: function () { return RNNDrawer_1.default; } }); 5 | var SideMenuView_1 = require("./SideMenuView"); 6 | Object.defineProperty(exports, "SideMenuView", { enumerable: true, get: function () { return SideMenuView_1.default; } }); 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-navigation-drawer-extension", 3 | "version": "4.0.1", 4 | "description": "Drawer API built on top of wix react-native-navigation for iOS and Android.", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "files": [ 8 | "lib/**/*" 9 | ], 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\"", 12 | "prepublishOnly": "pinst --disable", 13 | "postpublish": "pinst --enable", 14 | "pre-commit": "lint-staged", 15 | "postinstall": "husky install" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/lukebrandonfarrell/wix-react-native-navigation-drawer.git" 20 | }, 21 | "keywords": [ 22 | "wix", 23 | "react-native-navigation", 24 | "navigation", 25 | "react-native", 26 | "drawer", 27 | "side-menu", 28 | "ios", 29 | "android", 30 | "native", 31 | "typescript" 32 | ], 33 | "peerDependencies": { 34 | "react-native-navigation": ">= 3.x" 35 | }, 36 | "author": "Luke Brandon Farrell", 37 | "license": "MIT", 38 | "bugs": { 39 | "url": "https://github.com/lukebrandonfarrell/wix-react-native-navigation-drawer/issues" 40 | }, 41 | "homepage": "https://github.com/lukebrandonfarrell/wix-react-native-navigation-drawer#readme", 42 | "dependencies": {}, 43 | "devDependencies": { 44 | "@commitlint/cli": "^12.1.4", 45 | "@commitlint/config-conventional": "^12.1.4", 46 | "@types/react": "^16.9.1", 47 | "@types/react-native": "^0.70", 48 | "husky": "^6.0.0", 49 | "lint-staged": "^11.0.0", 50 | "pinst": "^2.1.6", 51 | "prettier": "^2.0.4", 52 | "react": "^16.9.0", 53 | "react-native": "^0.62.3", 54 | "react-native-navigation": "^6.4.0", 55 | "semantic-release": "^17.4.3", 56 | "typescript": "^3.9.9" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "printWidth": 80, 3 | "trailingComma": "all", 4 | "singleQuote": true 5 | } -------------------------------------------------------------------------------- /src/RNNDrawer.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @description An animated drawer component for react-native-navigation. 4 | */ 5 | 6 | /* NPM - Node Package Manage */ 7 | import * as React from 'react'; 8 | import { 9 | View, 10 | Animated, 11 | Dimensions, 12 | TouchableWithoutFeedback, 13 | StyleSheet, 14 | ViewStyle, 15 | ImageStyle, 16 | PanResponderInstance, 17 | PanResponder, 18 | PanResponderGestureState, 19 | GestureResponderEvent, 20 | EmitterSubscription, 21 | } from 'react-native'; 22 | import { Navigation, Layout } from 'react-native-navigation'; 23 | /* Utils - Project Utilities */ 24 | import { listen, dispatch } from './events'; 25 | 26 | declare interface RNNDrawerOptions { 27 | /** 28 | * Id of parent component of the drawer. 29 | * This field is necessary in order to be able 30 | * to push screens inside the drawer 31 | */ 32 | parentComponentId: string; 33 | 34 | /** 35 | * Direction to open the collage, 36 | * one of: ["left", "right", "top", "bottom"] 37 | * If not provided, drawer might have 38 | * a weird effect when closing 39 | */ 40 | direction?: DirectionType; 41 | 42 | /** 43 | * Time in milliseconds to execute the drawer opening animation 44 | */ 45 | animationOpenTime?: number; 46 | 47 | /** 48 | * Time in milliseconds to execute the drawer closing animation 49 | */ 50 | animationCloseTime?: number; 51 | 52 | /** 53 | * Whether the drawer be dismissed when a click is registered outside 54 | */ 55 | dismissWhenTouchOutside?: boolean; 56 | 57 | /** 58 | * Opacity of the screen outside the drawer 59 | */ 60 | fadeOpacity?: number; 61 | 62 | /** 63 | * Width of drawer on portrait orientation. Pass a string containing '%' (e.g. "80%") 64 | * for setting the width in relation to the screen or a number for absolute width (e.g. 300) 65 | */ 66 | drawerScreenWidth?: number | string; 67 | 68 | /** 69 | * Width of drawer on landscape orientation. Pass a string containing '%' (e.g. "80%") 70 | * for setting the width in relation to the screen or a number for absolute width (e.g. 300) 71 | */ 72 | drawerScreenWidthOnLandscape?: number | string; 73 | 74 | /** 75 | * Height of drawer. Pass a string containing '%' (e.g. "30%") 76 | * for setting the height in relation to the screen or a number for absolute height (e.g. 300) 77 | */ 78 | drawerScreenHeight?: number | string; 79 | 80 | disableDragging?: boolean; 81 | 82 | disableSwiping?: boolean; 83 | } 84 | 85 | export enum DirectionType { 86 | left = 'left', 87 | right = 'right', 88 | bottom = 'bottom', 89 | top = 'top', 90 | } 91 | 92 | interface Point { 93 | moveX: number; 94 | moveY: number; 95 | } 96 | 97 | interface IState { 98 | sideMenuOpenValue: Animated.Value; 99 | sideMenuOverlayOpacity: Animated.Value; 100 | sideMenuSwipingStarted: boolean; 101 | sideMenuIsDismissing: boolean; 102 | screenHeight: number; 103 | } 104 | 105 | interface IProps { 106 | /** react-native-navigation */ 107 | componentId: string; 108 | /** Props */ 109 | animationOpenTime: number; 110 | animationCloseTime: number; 111 | direction: DirectionType; 112 | dismissWhenTouchOutside: boolean; 113 | fadeOpacity: number; 114 | drawerScreenWidth: number | string; 115 | drawerScreenWidthOnLandscape: number | string; 116 | drawerScreenHeight: number | string; 117 | animateDrawerExpanding?: boolean; 118 | disableDragging?: boolean; 119 | disableSwiping?: boolean; 120 | style: any; 121 | } 122 | 123 | interface HOCProps { 124 | Component: React.ComponentType; 125 | } 126 | 127 | interface StylesInterface { 128 | sideMenuContainerStyle: ViewStyle; 129 | sideMenuOverlayStyle: ImageStyle; 130 | } 131 | 132 | interface DrawerDirectionValuesInterface { 133 | [key: string]: number; 134 | left: number; 135 | right: number; 136 | top: number; 137 | bottom: number; 138 | } 139 | 140 | interface DrawerReverseDirectionInterface { 141 | [key: string]: string; 142 | left: string; 143 | right: string; 144 | } 145 | 146 | interface SwipeMoveInterface { 147 | value: Point; 148 | direction: string; 149 | } 150 | 151 | class RNNDrawer { 152 | /** 153 | * Generates the drawer component to 154 | * be used with react-native-navigation 155 | * 156 | * @param component 157 | */ 158 | static create(Component: React.ComponentType): any { 159 | class WrappedDrawer extends React.Component { 160 | private readonly screenWidth: number; 161 | private readonly screenHeight: number; 162 | private readonly drawerWidth: number; 163 | private readonly drawerHeight: number; 164 | private readonly drawerOpenedValues: DrawerDirectionValuesInterface; 165 | private readonly initialValues: DrawerDirectionValuesInterface; 166 | private panResponder: PanResponderInstance; 167 | private animatedDrawer!: Animated.CompositeAnimation; 168 | private animatedOpacity!: Animated.CompositeAnimation; 169 | private unsubscribeSwipeStart!: () => void; 170 | private unsubscribeSwipeMove!: () => void; 171 | private unsubscribeSwipeEnd!: () => void; 172 | private unsubscribeDismissDrawer!: () => void; 173 | private panningStartedPoint: Point = { moveX: 0, moveY: 0 }; 174 | private startedFromSideMenu: boolean = false; 175 | private orientationChangeListener?: EmitterSubscription; 176 | 177 | static defaultProps = { 178 | animationOpenTime: 300, 179 | animationCloseTime: 300, 180 | direction: 'left', 181 | dismissWhenTouchOutside: true, 182 | fadeOpacity: 0.6, 183 | drawerScreenWidth: '80%', 184 | drawerScreenWidthOnLandscape: '30%', 185 | drawerScreenHeight: '100%', 186 | animateDrawerExpanding: true, 187 | disableDragging: false, 188 | disableSwiping: false, 189 | }; 190 | 191 | /** 192 | * [ Built-in React method. ] 193 | * 194 | * Setup the component. Executes when the component is created 195 | * 196 | * @param {object} props 197 | */ 198 | constructor(props: IProps) { 199 | super(props); 200 | 201 | this.screenWidth = Dimensions.get('window').width; 202 | this.screenHeight = Dimensions.get('window').height; 203 | 204 | this.panResponder = PanResponder.create({ 205 | onStartShouldSetPanResponder: ( 206 | _evt: GestureResponderEvent, 207 | _gestureState: PanResponderGestureState, 208 | ) => false, 209 | onStartShouldSetPanResponderCapture: ( 210 | _evt: GestureResponderEvent, 211 | _gestureState: PanResponderGestureState, 212 | ) => false, 213 | onMoveShouldSetPanResponder: ( 214 | _evt: GestureResponderEvent, 215 | _gestureState: PanResponderGestureState, 216 | ) => { 217 | const { dx, dy } = _gestureState; 218 | 219 | if ( 220 | this.props.direction === DirectionType.left || 221 | this.props.direction === DirectionType.right 222 | ) 223 | return Math.abs(dx) > 5; 224 | else return Math.abs(dy) > 5; 225 | }, 226 | onMoveShouldSetPanResponderCapture: ( 227 | _evt: GestureResponderEvent, 228 | _gestureState: PanResponderGestureState, 229 | ) => false, 230 | onPanResponderGrant: ( 231 | _evt: GestureResponderEvent, 232 | _gestureState: PanResponderGestureState, 233 | ) => { 234 | const { moveX, moveY } = _gestureState; 235 | 236 | dispatch('SWIPE_START', { moveX, moveY }); 237 | }, 238 | onPanResponderRelease: ( 239 | _evt: GestureResponderEvent, 240 | gestureState: PanResponderGestureState, 241 | ) => { 242 | const { vx } = gestureState; 243 | 244 | // Emit this event when the gesture ends 245 | dispatch('SWIPE_END', vx > 0 ? 'right' : 'left'); 246 | }, 247 | onPanResponderTerminationRequest: ( 248 | _evt: GestureResponderEvent, 249 | _gestureState: PanResponderGestureState, 250 | ) => false, 251 | onShouldBlockNativeResponder: ( 252 | _evt: GestureResponderEvent, 253 | _gestureState: PanResponderGestureState, 254 | ) => false, 255 | onPanResponderMove: ( 256 | _evt: GestureResponderEvent, 257 | _gestureState: PanResponderGestureState, 258 | ) => { 259 | const { moveX, moveY } = _gestureState; 260 | const direction = this.props.direction || 'left'; 261 | 262 | dispatch('SWIPE_MOVE', { value: { moveX, moveY }, direction }); 263 | }, 264 | }); 265 | 266 | /* 267 | * We need to convert the pushed drawer width 268 | * to a number as it can either be a string ('20%') 269 | * or number (400). 270 | */ 271 | const _resolveDrawerSize = ( 272 | value: number | string, 273 | max: number, 274 | ): number => { 275 | /* 276 | * If the type is a string '%' then it should be a percentage relative 277 | * to our max size. 278 | */ 279 | if (typeof value === 'string') { 280 | const valueAsNumber = parseFloat(value as string) || 100; 281 | const size = max * (valueAsNumber / 100); 282 | 283 | return size; 284 | } 285 | 286 | return value; 287 | }; 288 | 289 | /** Component Variables */ 290 | this.drawerWidth = _resolveDrawerSize( 291 | this.isLandscape() 292 | ? props.drawerScreenWidthOnLandscape 293 | : props.drawerScreenWidth, 294 | this.screenWidth, 295 | ); 296 | this.drawerHeight = _resolveDrawerSize( 297 | props.drawerScreenHeight, 298 | this.screenHeight, 299 | ); 300 | 301 | this.drawerOpenedValues = { 302 | left: 0, 303 | right: this.screenWidth - this.drawerWidth, 304 | top: this.drawerHeight - this.screenHeight, 305 | bottom: this.screenHeight - this.drawerHeight, 306 | }; 307 | 308 | this.initialValues = { 309 | left: -this.drawerWidth, 310 | right: this.screenWidth, 311 | top: -this.screenHeight, 312 | bottom: this.screenHeight, 313 | }; 314 | 315 | /** Component State */ 316 | this.state = { 317 | sideMenuOpenValue: new Animated.Value( 318 | this.initialValues[props.direction], 319 | ), 320 | sideMenuOverlayOpacity: new Animated.Value(0), 321 | sideMenuSwipingStarted: false, 322 | sideMenuIsDismissing: false, 323 | screenHeight: this.screenHeight, 324 | }; 325 | 326 | /** Component Bindings */ 327 | this.touchedOutside = this.touchedOutside.bind(this); 328 | this.dismissDrawerWithAnimation = this.dismissDrawerWithAnimation.bind( 329 | this, 330 | ); 331 | this.registerListeners = this.registerListeners.bind(this); 332 | this.removeListeners = this.removeListeners.bind(this); 333 | this.isLandscape = this.isLandscape.bind(this); 334 | Navigation.events().bindComponent(this); 335 | } 336 | 337 | /** 338 | * Check if device is in landscape mode 339 | */ 340 | isLandscape() { 341 | const dim = Dimensions.get('window'); 342 | 343 | return dim.height <= dim.width; 344 | } 345 | 346 | /** 347 | * [ Built-in React method. ] 348 | * 349 | * Executed when the component is mounted to the screen 350 | */ 351 | componentDidMount() { 352 | /** Props */ 353 | const { direction, fadeOpacity, animateDrawerExpanding } = this.props; 354 | 355 | if ( 356 | typeof animateDrawerExpanding !== 'undefined' && 357 | !animateDrawerExpanding 358 | ) 359 | this.startedFromSideMenu = true; 360 | 361 | // Animate side menu open 362 | this.animatedDrawer = Animated.timing(this.state.sideMenuOpenValue, { 363 | toValue: this.drawerOpenedValues[direction], 364 | duration: this.props.animationOpenTime, 365 | useNativeDriver: true, 366 | }); 367 | 368 | // Animate outside side menu opacity 369 | this.animatedOpacity = Animated.timing( 370 | this.state.sideMenuOverlayOpacity, 371 | { 372 | toValue: fadeOpacity, 373 | duration: this.props.animationOpenTime, 374 | useNativeDriver: true, 375 | }, 376 | ); 377 | } 378 | 379 | /** 380 | * [ react-native-navigation method. ] 381 | * 382 | * Executed when the component is navigated to view. 383 | */ 384 | componentDidAppear() { 385 | this.registerListeners(); 386 | 387 | // If there has been no Swiping, and this component appears, then just start the open animations 388 | if ( 389 | !this.state.sideMenuSwipingStarted && 390 | this.props.animateDrawerExpanding 391 | ) { 392 | this.animatedDrawer.start(); 393 | this.animatedOpacity.start(); 394 | } 395 | } 396 | 397 | /** 398 | * [ react-native-navigation method. ] 399 | * 400 | * Executed when the component is navigated away from view. 401 | */ 402 | componentDidDisappear() { 403 | this.removeListeners(); 404 | 405 | dispatch('DRAWER_CLOSED'); 406 | } 407 | 408 | onOrientationChange = ({ window }: any) => { 409 | const screenHeight = window.height; 410 | 411 | this.setState({ screenHeight }); 412 | 413 | // Apply correct position if opened from right 414 | if (this.props.direction === 'right') { 415 | // Calculates the position of the drawer from the left side of the screen 416 | const alignedMovementValue = window.width - this.drawerWidth; 417 | 418 | this.state.sideMenuOpenValue.setValue(alignedMovementValue); 419 | } 420 | }; 421 | 422 | /** 423 | * Registers all the listenrs for this component 424 | */ 425 | registerListeners() { 426 | /** Props */ 427 | const { direction, fadeOpacity } = this.props; 428 | 429 | // Adapt the drawer's size on orientation change 430 | this.orientationChangeListener = Dimensions.addEventListener( 431 | 'change', 432 | this.onOrientationChange, 433 | ); 434 | 435 | // Executes when the side of the screen interaction starts 436 | this.unsubscribeSwipeStart = listen('SWIPE_START', (value: Point) => { 437 | this.panningStartedPoint.moveX = value.moveX; 438 | this.panningStartedPoint.moveY = value.moveY; 439 | 440 | this.setState({ 441 | sideMenuSwipingStarted: true, 442 | }); 443 | }); 444 | 445 | // Executes when the side of the screen is interacted with 446 | this.unsubscribeSwipeMove = listen( 447 | 'SWIPE_MOVE', 448 | ({ value, direction: swipeDirection }: SwipeMoveInterface) => { 449 | // Cover special case when we are swiping from the edge of the screen 450 | if (this.startedFromSideMenu) { 451 | if (direction === 'left' && value.moveX < this.drawerWidth) { 452 | this.state.sideMenuOpenValue.setValue( 453 | value.moveX - this.drawerWidth, 454 | ); 455 | const normalizedOpacity = Math.min( 456 | (value.moveX / this.drawerWidth) * fadeOpacity, 457 | fadeOpacity, 458 | ); 459 | this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity); 460 | } 461 | if ( 462 | direction === 'right' && 463 | this.screenWidth - value.moveX < this.drawerWidth 464 | ) { 465 | this.state.sideMenuOpenValue.setValue(value.moveX); 466 | const normalizedOpacity = Math.min( 467 | ((this.screenWidth - value.moveX) / this.drawerWidth) * 468 | fadeOpacity, 469 | fadeOpacity, 470 | ); 471 | this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity); 472 | } 473 | 474 | return; 475 | } 476 | 477 | if (this.props.disableDragging) return; 478 | // Calculates the translateX / translateY value 479 | let alignedMovementValue = 0; 480 | // To swap the direction if needed 481 | let directionModifier = 1; 482 | // Whether we use the height of the drawer or the width 483 | let drawerDimension = this.drawerWidth; 484 | 485 | if (swipeDirection === 'left') { 486 | alignedMovementValue = 487 | value.moveX - this.panningStartedPoint.moveX; 488 | } else if (swipeDirection === 'right') { 489 | alignedMovementValue = 490 | this.panningStartedPoint.moveX - value.moveX; 491 | directionModifier = -1; 492 | } else if (swipeDirection === 'bottom') { 493 | alignedMovementValue = 494 | this.panningStartedPoint.moveY - value.moveY; 495 | directionModifier = -1; 496 | drawerDimension = this.drawerHeight; 497 | } else if (swipeDirection === 'top') { 498 | alignedMovementValue = 499 | value.moveY - this.panningStartedPoint.moveY; 500 | drawerDimension = this.drawerHeight; 501 | } 502 | 503 | // Calculates the percentage 0 - 1 of which the drawer is open 504 | const openedPercentage = 505 | Math.abs(drawerDimension + alignedMovementValue) / 506 | drawerDimension; 507 | // Calculates the opacity to set of the screen based on the percentage the drawer is open 508 | const normalizedOpacity = Math.min( 509 | openedPercentage * fadeOpacity, 510 | fadeOpacity, 511 | ); 512 | 513 | // Does not allow the drawer to go further than the maximum width / height 514 | if (0 > alignedMovementValue) { 515 | // Sets the animation values, we use this so we can resume animation from any point 516 | this.state.sideMenuOpenValue.setValue( 517 | this.drawerOpenedValues[direction] + 518 | alignedMovementValue * directionModifier, 519 | ); 520 | this.state.sideMenuOverlayOpacity.setValue(normalizedOpacity); 521 | } 522 | }, 523 | ); 524 | 525 | // Executes when the side of the screen interaction ends 526 | this.unsubscribeSwipeEnd = listen( 527 | 'SWIPE_END', 528 | (swipeDirection: string) => { 529 | if (this.props.disableSwiping && !this.startedFromSideMenu) return; 530 | 531 | const reverseDirection: DrawerReverseDirectionInterface = { 532 | right: 'left', 533 | left: 'right', 534 | top: 'bottom', 535 | bottom: 'top', 536 | }; 537 | // In case the drawer started by dragging the edge of the screen reset the flag 538 | this.startedFromSideMenu = false; 539 | 540 | if (swipeDirection === reverseDirection[direction]) { 541 | this.animatedDrawer.start(); 542 | this.animatedOpacity.start(); 543 | } else { 544 | if (!this.state.sideMenuIsDismissing) { 545 | this.setState( 546 | { 547 | sideMenuIsDismissing: true, 548 | }, 549 | () => { 550 | this.dismissDrawerWithAnimation(); 551 | }, 552 | ); 553 | } 554 | } 555 | }, 556 | ); 557 | 558 | // Executes when the drawer needs to be dismissed 559 | this.unsubscribeDismissDrawer = listen('DISMISS_DRAWER', () => { 560 | if (!this.state.sideMenuIsDismissing) { 561 | this.dismissDrawerWithAnimation(); 562 | } 563 | }); 564 | } 565 | 566 | /** 567 | * Removes all the listenrs from this component 568 | */ 569 | removeListeners() { 570 | if (this.orientationChangeListener) 571 | this.orientationChangeListener.remove(); 572 | if (this.unsubscribeSwipeStart) this.unsubscribeSwipeStart(); 573 | if (this.unsubscribeSwipeMove) this.unsubscribeSwipeMove(); 574 | if (this.unsubscribeSwipeEnd) this.unsubscribeSwipeEnd(); 575 | if (this.unsubscribeDismissDrawer) this.unsubscribeDismissDrawer(); 576 | } 577 | 578 | /** 579 | * [ Built-in React method. ] 580 | * 581 | * Allows us to render JSX to the screen 582 | */ 583 | render() { 584 | /** Styles */ 585 | const { sideMenuOverlayStyle, sideMenuContainerStyle } = styles; 586 | /** Props */ 587 | const { direction, style } = this.props; 588 | /** State */ 589 | const { sideMenuOpenValue, sideMenuOverlayOpacity } = this.state; 590 | /** Variables */ 591 | const animatedValue = 592 | direction === DirectionType.left || direction === DirectionType.right 593 | ? { translateX: sideMenuOpenValue } 594 | : { translateY: sideMenuOpenValue }; 595 | 596 | return ( 597 | 601 | 602 | 608 | 609 | 620 | 621 | 622 | 623 | ); 624 | } 625 | 626 | /** 627 | * Touched outside drawer 628 | */ 629 | touchedOutside() { 630 | const { dismissWhenTouchOutside } = this.props; 631 | 632 | if (dismissWhenTouchOutside) { 633 | this.dismissDrawerWithAnimation(); 634 | } 635 | } 636 | 637 | /** 638 | * Dismisses drawer with animation 639 | */ 640 | dismissDrawerWithAnimation() { 641 | const { direction } = this.props; 642 | const { sideMenuIsDismissing } = this.state; 643 | const closeValues: DrawerDirectionValuesInterface = { 644 | left: -this.drawerWidth, 645 | right: this.screenWidth, 646 | top: -this.screenHeight, 647 | bottom: this.screenHeight, 648 | }; 649 | 650 | // Animate side menu close 651 | Animated.timing(this.state.sideMenuOpenValue, { 652 | toValue: closeValues[direction], 653 | duration: this.props.animationCloseTime, 654 | useNativeDriver: true, 655 | }).start(() => { 656 | Navigation.dismissOverlay(this.props.componentId); 657 | this.setState({ sideMenuIsDismissing: false }); 658 | }); 659 | 660 | // Animate outside side menu opacity 661 | Animated.timing(this.state.sideMenuOverlayOpacity, { 662 | toValue: 0, 663 | duration: this.props.animationCloseTime, 664 | useNativeDriver: true, 665 | }).start(); 666 | } 667 | } 668 | 669 | return WrappedDrawer; 670 | } 671 | 672 | /** 673 | * Shows a drawer component 674 | * 675 | * @param layout 676 | */ 677 | static showDrawer(layout: Layout) { 678 | // By default for this library, we make the 'componentBackgroundColor' transparent 679 | const componentBackgroundColor = 680 | layout?.component?.options?.layout?.componentBackgroundColor ?? 681 | 'transparent'; 682 | const options = { 683 | ...layout?.component?.options, 684 | layout: { 685 | componentBackgroundColor: componentBackgroundColor, 686 | }, 687 | }; 688 | 689 | // Mutate options to add 'transparent' by default 690 | // @ts-ignore 691 | layout.component.options = { ...options }; 692 | 693 | Navigation.showOverlay(layout); 694 | } 695 | 696 | /** 697 | * Dismiss the drawer component 698 | */ 699 | static dismissDrawer() { 700 | dispatch('DISMISS_DRAWER', true); 701 | } 702 | } 703 | 704 | export default RNNDrawer; 705 | 706 | /** -------------------------------------------- */ 707 | /** Component Styling */ 708 | /** -------------------------------------------- */ 709 | const styles = StyleSheet.create({ 710 | sideMenuContainerStyle: { 711 | flex: 1, 712 | flexDirection: 'row', 713 | }, 714 | sideMenuOverlayStyle: { 715 | position: 'absolute', 716 | width: '100%', 717 | height: '100%', 718 | backgroundColor: '#000', 719 | }, 720 | }); 721 | -------------------------------------------------------------------------------- /src/SideMenuView.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @title SideMenuView.js 4 | * @description A swipeable view to open a drawer. 5 | */ 6 | 7 | /* NPM - Node Package Manage */ 8 | import * as React from 'react'; 9 | import { 10 | View, 11 | PanResponder, 12 | Dimensions, 13 | PanResponderCallbacks, 14 | PanResponderInstance, 15 | GestureResponderEvent, 16 | PanResponderGestureState, 17 | StyleProp, 18 | ViewStyle, 19 | } from 'react-native'; 20 | import { Options } from 'react-native-navigation'; 21 | /* Utils - Project Utilities */ 22 | import RNNDrawer from './RNNDrawer'; 23 | import { listen, dispatch } from './events'; 24 | import { DirectionType } from './RNNDrawer'; 25 | 26 | const screenHeight: number = Dimensions.get('screen').height; 27 | 28 | interface IProps { 29 | swipeSensitivity?: number; 30 | sideMargin?: number; 31 | sideMarginLeft?: number; 32 | sideMarginRight?: number; 33 | style?: StyleProp; 34 | drawerName: string; 35 | direction: 'left' | 'right'; 36 | passProps?: any; 37 | options?: Options; 38 | } 39 | 40 | class SideMenuView extends React.Component { 41 | private isOpened: boolean; 42 | private _panResponderMethods: PanResponderCallbacks; 43 | private _leftPanResponder: PanResponderInstance; 44 | private _rightPanResponder: PanResponderInstance; 45 | private unsubscribeDrawerClosed: any; 46 | 47 | static defaultProps = { 48 | sideMargin: 15, 49 | swipeSensitivity: 0.2, 50 | direction: 'left', 51 | }; 52 | 53 | /** 54 | * [ Built-in React method. ] 55 | * 56 | * Setup the component. Executes when the component is created 57 | * 58 | * @param {object} props 59 | */ 60 | constructor(props: IProps) { 61 | super(props); 62 | 63 | this.isOpened = false; 64 | 65 | const { 66 | swipeSensitivity, 67 | drawerName, 68 | direction, 69 | passProps, 70 | options, 71 | } = props; 72 | const directionIsLeft = direction ? direction == 'left' : true; 73 | this._panResponderMethods = { 74 | // Ask to be the responder: 75 | onStartShouldSetPanResponder: ( 76 | _evt: GestureResponderEvent, 77 | _gestureState: PanResponderGestureState, 78 | ) => true, 79 | onStartShouldSetPanResponderCapture: ( 80 | _evt: GestureResponderEvent, 81 | _gestureState: PanResponderGestureState, 82 | ) => true, 83 | onMoveShouldSetPanResponder: ( 84 | _evt: GestureResponderEvent, 85 | _gestureState: PanResponderGestureState, 86 | ) => true, 87 | onMoveShouldSetPanResponderCapture: ( 88 | _evt: GestureResponderEvent, 89 | _gestureState: PanResponderGestureState, 90 | ) => true, 91 | onPanResponderGrant: ( 92 | _evt: GestureResponderEvent, 93 | _gestureState: PanResponderGestureState, 94 | ) => { 95 | dispatch('SWIPE_START'); 96 | }, 97 | onPanResponderRelease: ( 98 | _evt: GestureResponderEvent, 99 | gestureState: PanResponderGestureState, 100 | ) => { 101 | const { vx } = gestureState; 102 | 103 | // Emit this event when the gesture ends 104 | dispatch('SWIPE_END', vx > 0 ? 'right' : 'left'); 105 | }, 106 | onPanResponderTerminationRequest: ( 107 | _evt: GestureResponderEvent, 108 | _gestureState: PanResponderGestureState, 109 | ) => false, 110 | onShouldBlockNativeResponder: ( 111 | _evt: GestureResponderEvent, 112 | _gestureState: PanResponderGestureState, 113 | ) => false, 114 | }; 115 | 116 | // LEFT PAN RESPONDER 117 | this._leftPanResponder = PanResponder.create({ 118 | ...this._panResponderMethods, 119 | onPanResponderMove: ( 120 | _evt: GestureResponderEvent, 121 | gestureState: PanResponderGestureState, 122 | ) => { 123 | const { moveX, vx } = gestureState; 124 | 125 | // Emit this event on movement 126 | dispatch('SWIPE_MOVE', { value: { moveX }, direction: 'left' }); 127 | 128 | // Left Swipe 129 | if (typeof swipeSensitivity !== 'undefined') { 130 | if (vx > swipeSensitivity && !this.isOpened && directionIsLeft) { 131 | this.isOpened = true; 132 | RNNDrawer.showDrawer({ 133 | component: { 134 | name: drawerName, 135 | passProps: { 136 | direction: DirectionType.left, 137 | parentComponentId: passProps?.parentComponentId, 138 | animateDrawerExpanding: false, 139 | ...passProps, 140 | }, 141 | options: { ...options }, 142 | }, 143 | }); 144 | } 145 | } 146 | }, 147 | }); 148 | 149 | // RIGHT PAN RESPONDER 150 | this._rightPanResponder = PanResponder.create({ 151 | ...this._panResponderMethods, 152 | onPanResponderMove: ( 153 | _evt: GestureResponderEvent, 154 | gestureState: PanResponderGestureState, 155 | ) => { 156 | const { moveX, vx } = gestureState; 157 | 158 | // Emit this event on movement 159 | dispatch('SWIPE_MOVE', { value: { moveX }, direction: 'right' }); 160 | 161 | // Right Swipe 162 | if (typeof swipeSensitivity !== 'undefined') { 163 | if (vx > -swipeSensitivity && !this.isOpened && !directionIsLeft) { 164 | this.isOpened = true; 165 | RNNDrawer.showDrawer({ 166 | component: { 167 | name: drawerName, 168 | passProps: { 169 | direction: DirectionType.right, 170 | parentComponentId: passProps?.parentComponentId, 171 | animateDrawerExpanding: false, 172 | ...passProps, 173 | }, 174 | options: { ...options }, 175 | }, 176 | }); 177 | } 178 | } 179 | }, 180 | }); 181 | 182 | this.registerListeners = this.registerListeners.bind(this); 183 | this.removeListeners = this.removeListeners.bind(this); 184 | } 185 | 186 | /** 187 | * [ Built-in React method. ] 188 | * 189 | * Executed when the component is mounted to the screen 190 | */ 191 | componentDidMount() { 192 | this.registerListeners(); 193 | } 194 | 195 | /** 196 | * Registers all the listenrs for this component 197 | */ 198 | registerListeners() { 199 | // Event fires when drawer is closed 200 | this.unsubscribeDrawerClosed = listen('DRAWER_CLOSED', () => { 201 | this.isOpened = false; 202 | }); 203 | } 204 | 205 | /** 206 | * Removes all the listenrs from this component 207 | */ 208 | removeListeners() { 209 | this.unsubscribeDrawerClosed(); 210 | } 211 | 212 | /** 213 | * [ Built-in React method. ] 214 | * 215 | * Allows us to render JSX to the screen 216 | */ 217 | render() { 218 | /** Props */ 219 | const { 220 | children, 221 | direction, 222 | sideMargin, 223 | sideMarginLeft, 224 | sideMarginRight, 225 | ...props 226 | } = this.props; 227 | 228 | const directionIsLeft = direction ? direction == 'left' : true; 229 | return ( 230 | 231 | {children} 232 | 233 | {directionIsLeft ? ( 234 | 244 | ) : ( 245 | 255 | )} 256 | 257 | ); 258 | } 259 | } 260 | 261 | export default SideMenuView; 262 | -------------------------------------------------------------------------------- /src/events.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Luke Brandon Farrell 3 | * @description Event dispatcher for comunication between components. 4 | */ 5 | 6 | interface EvnetsInterface { 7 | [key: string]: any; 8 | } 9 | 10 | /** 11 | * @description events 12 | * @private 13 | */ 14 | var _events: EvnetsInterface = {}; 15 | 16 | /** 17 | * @description add listener 18 | * @public 19 | * @param {string} name name listener 20 | * @param {function} func function for call 21 | * @returns {function} unsubscribe function 22 | */ 23 | export function listen(name: string, func: any): () => void { 24 | if (!_events[name]) _events[name] = { count: 0, funcs: {} }; 25 | 26 | const key = _events[name].count++; 27 | _events[name].funcs[key] = func; 28 | 29 | return function () { 30 | delete _events[name].funcs[key]; 31 | }; 32 | } 33 | 34 | /** 35 | * @description dispatch to listener 36 | * @public 37 | * @param {string} name name listener 38 | * @param {any} arg argument for send to listen(...) 39 | * @returns {void} 40 | */ 41 | export function dispatch(name: string, arg?: any): void { 42 | if (_events[name]) 43 | for (var func in _events[name].funcs) 44 | _events[name].funcs[func] && _events[name].funcs[func](arg); 45 | } 46 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as RNNDrawer } from './RNNDrawer'; 2 | export { default as SideMenuView } from './SideMenuView'; 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "declaration": true, 6 | "outDir": "./lib", 7 | "strict": true, 8 | "jsx": "react", 9 | "skipLibCheck": true, 10 | }, 11 | "include": ["src"], 12 | "exclude": ["node_modules", "**/__tests__/*"] 13 | } --------------------------------------------------------------------------------