├── .travis.yml
├── .prettierrc
├── tsconfig.json
├── .eslintrc.json
├── src
├── index.ts
└── __test__
│ └── index.test.js
├── LICENSE
├── README.md
├── .gitignore
└── package.json
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 | script: npm run test
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "singleQuote": true,
4 | "useTabs": false,
5 | "tabWidth": 2,
6 | "semi": true,
7 | "bracketSpacing": true,
8 | "brace_style": "collapse,preserve-inline"
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es6",
5 | "module": "commonjs",
6 | "esModuleInterop": true,
7 | "strict": true,
8 | "removeComments": false,
9 | "declaration": true,
10 | "outDir": "build"
11 | },
12 | "include": ["src", "src/index.ts"],
13 | "exclude": ["node_modules", "**/__tests__/*"]
14 | }
15 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "parserOptions": {
4 | "sourceType": "module",
5 | "parser": "babel-eslint"
6 | },
7 | "rules": {
8 | "arrow-parens": ["off"],
9 | "compat/compat": 2,
10 | "consistent-return": "off",
11 | "comma-dangle": "off",
12 | "generator-star-spacing": "off",
13 | "import/no-unresolved": "off",
14 | "import/no-extraneous-dependencies": "off",
15 | "no-use-before-define": "off",
16 | "promise/param-names": 2,
17 | "promise/always-return": 2,
18 | "promise/catch-or-return": 2,
19 | "promise/no-native": 0,
20 | "react/jsx-no-bind": "off",
21 | "react/jsx-filename-extension": ["error", { "extensions": [".js", ".jsx"] }],
22 | "react/prefer-stateless-function": "off"
23 | },
24 | "plugins": ["promise", "compat", "react"],
25 | "env": {
26 | "jest": true,
27 | "browser": true
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | const { useEffect } = require('react');
2 |
3 | const getMobileDetect = (userAgent: string) => {
4 | const isAndroid = (): boolean => Boolean(userAgent.match(/Android/i));
5 | const isIos = (): boolean => Boolean(userAgent.match(/iPhone|iPad|iPod/i));
6 | const isOpera = (): boolean => Boolean(userAgent.match(/Opera Mini/i));
7 | const isWindows = (): boolean => Boolean(userAgent.match(/IEMobile/i));
8 | const isSSR = (): boolean => Boolean(userAgent.match(/SSR/i));
9 |
10 | const isMobile = (): boolean => Boolean(isAndroid() || isIos() || isOpera() || isWindows());
11 | const isDesktop = (): boolean => Boolean(!isMobile() && !isSSR());
12 | return {
13 | isMobile,
14 | isDesktop,
15 | isAndroid,
16 | isIos,
17 | isSSR
18 | };
19 | };
20 | const useMobileDetect = () => {
21 | const userAgent = typeof navigator === 'undefined' ? 'SSR' : navigator.userAgent;
22 | return getMobileDetect(userAgent);
23 | };
24 |
25 | module.exports = useMobileDetect;
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Mahesh Haldar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://badge.fury.io/js/use-mobile-detect-hook)
2 |
3 | # use-mobile-detect-hook
4 |
5 | React hook to detect the device type. This hook is able to detect mobile, desktop, android or iOS device.
6 |
7 | # Installing
8 |
9 | ```bash
10 | npm install use-mobile-detect-hook
11 | ```
12 |
13 | ```bash
14 | yarn add use-mobile-detect-hook
15 | ```
16 |
17 | # Demo
18 |
19 | Follow [this link](http://www.maheshhaldar.com/demo-use-mobile-detect-hook/) to check the demo.
20 |
21 | # Usage
22 |
23 | ```javascript
24 | import useMobileDetect from 'use-mobile-detect-hook';
25 |
26 | function MyComponent = (props) => {
27 | const detectMobile = useMobileDetect();
28 |
29 | return (
30 |
31 | is Mobile: { detectMobile.isMobile() }
32 | is Desktop: { detectMobile.isDesktop() }
33 | is Android: { detectMobile.isAndroid() }
34 | is iOS: { detectMobile.isIos() }
35 |
36 | );
37 | };
38 | ```
39 |
40 | # Contributing
41 |
42 | If you have any new suggestions, new features, bug fixes, etc. please contribute by raising pull request on the [repository](https://github.com/haldarmahesh/use-mobile-detect-hook).
43 |
44 | If you have any issue with the `use-mobile-detect-hook`, open an issue on [Github](https://github.com/haldarmahesh/use-mobile-detect-hook).
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/node
2 | # Edit at https://www.gitignore.io/?templates=node
3 |
4 | ### Node ###
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 |
24 | # nyc test coverage
25 | .nyc_output
26 |
27 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
28 | .grunt
29 |
30 | # Bower dependency directory (https://bower.io/)
31 | bower_components
32 |
33 | # node-waf configuration
34 | .lock-wscript
35 |
36 | # Compiled binary addons (https://nodejs.org/api/addons.html)
37 | build/Release
38 | build
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # Optional npm cache directory
48 | .npm
49 |
50 | # Optional eslint cache
51 | .eslintcache
52 |
53 | # Optional REPL history
54 | .node_repl_history
55 |
56 | # Output of 'npm pack'
57 | *.tgz
58 |
59 | # Yarn Integrity file
60 | .yarn-integrity
61 |
62 | # dotenv environment variables file
63 | .env
64 |
65 | # parcel-bundler cache (https://parceljs.org/)
66 | .cache
67 |
68 | # next.js build output
69 | .next
70 |
71 | # nuxt.js build output
72 | .nuxt
73 |
74 | # vuepress build output
75 | .vuepress/dist
76 |
77 | # Serverless directories
78 | .serverless
79 |
80 | # FuseBox cache
81 | .fusebox/
82 |
83 | # End of https://www.gitignore.io/api/node
84 | # auto generated yarn.lock file removed.
85 | yarn.lock%
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "use-mobile-detect-hook",
3 | "version": "1.0.5",
4 | "description": "The React hook to detect if the device is mobile or desktop.",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/haldarmahesh/use-mobile-detect-hook.git"
8 | },
9 | "main": "build/index.js",
10 | "types": "build/index.d.ts",
11 | "scripts": {
12 | "test": "npm run build && jest --coverage",
13 | "test-watch": "npm run build && jest --watchAll --coverage",
14 | "lint": "./node_modules/eslint/bin/eslint.js --ext js,jsx src",
15 | "lint-fix": "./node_modules/eslint/bin/eslint.js --ext js,jsx src --fix",
16 | "format:check": "prettier --config ./.prettierrc --list-different \"src/**/*{.ts,.js,.json,.css,.scss}\"",
17 | "format:fix": "pretty-quick --staged",
18 | "build": "tsc"
19 | },
20 | "peerDependencies": {
21 | "react": "^16.7.0-alpha.0"
22 | },
23 | "files": [
24 | "build/index.js",
25 | "build/index.d.ts"
26 | ],
27 | "husky": {
28 | "hooks": {
29 | "pre-commit": "npm run test && npm run format:fix && npm run lint"
30 | }
31 | },
32 | "devDependencies": {
33 | "eslint": "^7.17.0",
34 | "eslint-config-airbnb": "^17.1.0",
35 | "eslint-plugin-compat": "^3.9.0",
36 | "eslint-plugin-import": "^2.14.0",
37 | "eslint-plugin-jsx-a11y": "^6.1.2",
38 | "eslint-plugin-promise": "^4.0.1",
39 | "eslint-plugin-react": "^7.11.1",
40 | "husky": "1.1.2",
41 | "jest": "^26.6.3",
42 | "prettier": "1.14.3",
43 | "pretty-quick": "^1.8.0",
44 | "react": "^16.7.0-alpha.0",
45 | "ts-jest": "^26.4.4",
46 | "ts-node": "^9.1.1",
47 | "typescript": "^4.1.3",
48 | "@types/jest": "^26.0.19"
49 | },
50 | "engines": {
51 | "node": ">=8",
52 | "npm": ">=5"
53 | },
54 | "keywords": [
55 | "React",
56 | "hook",
57 | "javascript",
58 | "mobile",
59 | "detect",
60 | "device",
61 | "type"
62 | ],
63 | "author": "haldarmahesh",
64 | "license": "MIT",
65 | "dependencies": {}
66 | }
67 |
--------------------------------------------------------------------------------
/src/__test__/index.test.js:
--------------------------------------------------------------------------------
1 | jest.mock('react', () => ({
2 | useEffect: jest.fn(cb => cb())
3 | }));
4 |
5 | const { useEffect } = require('react');
6 | const useMobileDetect = require('../../build/index');
7 |
8 | const setUserAgent = userAgent => {
9 | Object.defineProperty(navigator, 'userAgent', {
10 | value: userAgent,
11 | writable: true
12 | });
13 | };
14 | describe('useMobileDetect', () => {
15 | test('should call useEffect and callback', () => {
16 | useMobileDetect();
17 | expect(useEffect).not.toHaveBeenCalled();
18 | });
19 | test('should return an object of functions and vals', () => {
20 | const detect = useMobileDetect();
21 | expect(typeof detect.isMobile).toEqual('function');
22 | expect(typeof detect.isMobile()).toEqual('boolean');
23 | expect(typeof detect.isDesktop()).toEqual('boolean');
24 | expect(typeof detect.isAndroid).toEqual('function');
25 | expect(typeof detect.isAndroid()).toEqual('boolean');
26 | expect(typeof detect.isIos).toEqual('function');
27 | expect(typeof detect.isIos()).toEqual('boolean');
28 | expect(typeof detect.isSSR).toEqual('function');
29 | expect(typeof detect.isSSR()).toEqual('boolean');
30 | });
31 | });
32 |
33 | describe('getMobileDetect', () => {
34 | test('should return isMobile true when valid user agent is mobile', () => {
35 | const samsungGalaxyUa = `Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv)
36 | AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Mobile Safari/537.36`;
37 | setUserAgent(samsungGalaxyUa);
38 | expect(useMobileDetect().isMobile()).toEqual(true);
39 |
40 | const samsungGalaxys6Ua = `Mozilla/5.0 (Linux; Android 5.1.1; SM-G928X Build/LMY47X)
41 | AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.83 Mobile Safari/537.36`;
42 | setUserAgent(samsungGalaxys6Ua);
43 | expect(useMobileDetect().isMobile()).toEqual(true);
44 | expect(useMobileDetect().isAndroid()).toEqual(true);
45 | expect(useMobileDetect().isIos()).toEqual(false);
46 |
47 | const windows10 = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
48 | (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246`;
49 | setUserAgent(windows10);
50 | expect(useMobileDetect().isMobile()).toEqual(false);
51 | expect(useMobileDetect().isDesktop()).toEqual(true);
52 |
53 | const htcOneM9 = `Mozilla/5.0 (Linux; Android 6.0; HTC One M9 Build/MRA58K)
54 | AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.3`;
55 | setUserAgent(htcOneM9);
56 | expect(useMobileDetect().isMobile()).toEqual(true);
57 |
58 | const iPhone8 = `Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X)
59 | AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1`;
60 | setUserAgent(iPhone8);
61 | expect(useMobileDetect().isMobile()).toEqual(true);
62 | expect(useMobileDetect().isIos()).toEqual(true);
63 | expect(useMobileDetect().isAndroid()).toEqual(false);
64 |
65 | const microsoftLumia950 = `Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950)
66 | AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.1058`;
67 | setUserAgent(microsoftLumia950);
68 | expect(useMobileDetect().isMobile()).toEqual(true);
69 |
70 | const windows7Chrome = `Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
71 | (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36`;
72 | setUserAgent(windows7Chrome);
73 | expect(useMobileDetect().isMobile()).toEqual(false);
74 | expect(useMobileDetect().isAndroid()).toEqual(false);
75 | expect(useMobileDetect().isIos()).toEqual(false);
76 | expect(useMobileDetect().isDesktop()).toEqual(true);
77 | });
78 |
79 | test('should return isSSR true when valid user agent is SSR', () => {
80 | setUserAgent('SSR');
81 | expect(useMobileDetect().isSSR()).toEqual(true);
82 | });
83 | });
84 |
--------------------------------------------------------------------------------