├── .gitignore ├── .prettierrc ├── README.md ├── package.json ├── src └── index.tsx ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "semi": true, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "bracketSpacing": true, 7 | "jsxBracketSameLine": false, 8 | "arrowParens": "always" 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-dev-menu-on-touch 2 | 3 | 4 | [![npm](https://img.shields.io/npm/v/react-native-dev-menu-on-touch.svg)](https://npmjs.com/package/react-native-dev-menu-on-touch) 5 | 6 | Open dev menu with 3 fingers touch instead of shake. 7 | 8 | ![shake](https://media0.giphy.com/media/l41Ywr1TS6nV7GsIE/giphy.gif?cid=3640f6095c46cf8b544775586795984a) 9 | 10 | > *when you want to reload the app* 11 | 12 | ## Why? 13 | 14 | It's annoying to shake real device every time you need dev menu. Also - it looks quite awkward if you have co-workers sitting next to you and you shake your phone every 2 minutes. 15 | 16 | ## How to use 17 | 18 | Wrap entire app inside this component 19 | 20 | ```jsx 21 | import DevMenuOnTouch from 'react-native-dev-menu-on-touch'; 22 | // or: import { DevMenuOnTouch } from 'react-native-dev-menu-on-touch' 23 | 24 | class YourRootApp extends Component { 25 | render() { 26 | return ( 27 | 28 | 29 | 30 | ); 31 | } 32 | } 33 | ``` 34 | 35 | or use with higher order component 36 | 37 | ```jsx 38 | import { withDevMenuOnTouch } from 'react-native-dev-menu-on-touch'; 39 | const YourAppRoot = withDevMenuOnTouch(YourApp); 40 | ``` 41 | 42 | ## Notes 43 | 44 | - It's enabled only in dev mode - in production it'll return normal view without changing anything (so it's safe to use in production) 45 | - It's inspider by comment of @slicejunk https://github.com/facebook/react-native/issues/10191#issuecomment-277208461 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-dev-menu-on-touch", 3 | "version": "1.0.3", 4 | "main": "dist/index.js", 5 | "types": "dist/index.d.ts", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "tsc" 9 | }, 10 | "peerDependencies": { 11 | "react": "^16.0.0", 12 | "react-native": "^0.57.5" 13 | }, 14 | "devDependencies": { 15 | "@types/react": "^16.7.20", 16 | "@types/react-native": "^0.57.12", 17 | "typescript": "^3.1.6" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component, ComponentType } from 'react'; 2 | import { NativeModules, PanResponder, View } from 'react-native'; 3 | 4 | export class DevMenuOnTouch extends Component { 5 | private panResponder = PanResponder.create({ 6 | onStartShouldSetPanResponder: (evt, gestureState) => { 7 | if (gestureState.numberActiveTouches === 3) { 8 | NativeModules.DevMenu.show(); 9 | } 10 | return false; 11 | }, 12 | }); 13 | 14 | public render() { 15 | const { children } = this.props; 16 | 17 | // return children; 18 | const panHandlers = __DEV__ ? this.panResponder.panHandlers : {}; 19 | return ( 20 | 21 | {children} 22 | 23 | ); 24 | } 25 | } 26 | 27 | export function withDevMenuOnTouch

(TargetComponent: ComponentType

) { 28 | return class WithDevMenuOnTouch extends Component

{ 29 | public render() { 30 | return ( 31 | 32 | 33 | 34 | ); 35 | } 36 | }; 37 | } 38 | 39 | export default DevMenuOnTouch; 40 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "allowSyntheticDefaultImports": true, 6 | "jsx": "react-native", 7 | "declaration": true, 8 | "outDir": "./dist", 9 | "strict": true, 10 | "lib": ["es2015"], 11 | "skipLibCheck": true 12 | }, 13 | "exclude": ["./node_modules/*", "./dist"] 14 | } 15 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/prop-types@*": 6 | version "15.5.6" 7 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.6.tgz#9c03d3fed70a8d517c191b7734da2879b50ca26c" 8 | 9 | "@types/react-native@^0.57.12": 10 | version "0.57.12" 11 | resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.12.tgz#cd012ea3f4f30e70af580a14f5805d85827f92e6" 12 | dependencies: 13 | "@types/prop-types" "*" 14 | "@types/react" "*" 15 | 16 | "@types/react@*": 17 | version "16.7.6" 18 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040" 19 | dependencies: 20 | "@types/prop-types" "*" 21 | csstype "^2.2.0" 22 | 23 | "@types/react@^16.7.20": 24 | version "16.7.20" 25 | resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.20.tgz#13ae752c012710d0fa800985ca809814b51d3b58" 26 | dependencies: 27 | "@types/prop-types" "*" 28 | csstype "^2.2.0" 29 | 30 | csstype@^2.2.0: 31 | version "2.5.7" 32 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.7.tgz#bf9235d5872141eccfb2d16d82993c6b149179ff" 33 | 34 | "js-tokens@^3.0.0 || ^4.0.0": 35 | version "4.0.0" 36 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 37 | 38 | loose-envify@^1.1.0, loose-envify@^1.3.1: 39 | version "1.4.0" 40 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 41 | dependencies: 42 | js-tokens "^3.0.0 || ^4.0.0" 43 | 44 | object-assign@^4.1.1: 45 | version "4.1.1" 46 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 47 | 48 | prop-types@^15.6.2: 49 | version "15.6.2" 50 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" 51 | dependencies: 52 | loose-envify "^1.3.1" 53 | object-assign "^4.1.1" 54 | 55 | react@^16.7.0: 56 | version "16.7.0" 57 | resolved "https://registry.yarnpkg.com/react/-/react-16.7.0.tgz#b674ec396b0a5715873b350446f7ea0802ab6381" 58 | dependencies: 59 | loose-envify "^1.1.0" 60 | object-assign "^4.1.1" 61 | prop-types "^15.6.2" 62 | scheduler "^0.12.0" 63 | 64 | scheduler@^0.12.0: 65 | version "0.12.0" 66 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b" 67 | dependencies: 68 | loose-envify "^1.1.0" 69 | object-assign "^4.1.1" 70 | 71 | typescript@^3.1.6: 72 | version "3.1.6" 73 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.6.tgz#b6543a83cfc8c2befb3f4c8fba6896f5b0c9be68" 74 | --------------------------------------------------------------------------------