16 | };
17 |
18 |
19 | if (root) {
20 | ReactDOM.render(
21 | ,
22 | document.getElementById("root")
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "jsx": "react",
5 | "lib": [
6 | "dom",
7 | "es2018"
8 | ],
9 | "module": "esnext",
10 | "moduleResolution": "node",
11 | "noImplicitAny": false,
12 | "noImplicitReturns": true,
13 | "noUnusedLocals": true,
14 | "noUnusedParameters": true,
15 | "strict": true,
16 | "strictFunctionTypes": false,
17 | "stripInternal": true
18 | },
19 | "include": [
20 | "**/*.d.ts"
21 | ],
22 | "exclude": [
23 | "node_modules"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 BRAINHUB GROUP LLC
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 | # react-media-hook
2 |
3 | [](https://circleci.com/gh/brainhubinc/react-media-hook)
4 | [](https://www.npmjs.com/package/react-media-hook)
5 | [](https://www.npmjs.com/package/react-media-hook)
6 |
7 | React Hook for Media Queries.
8 | Uses [matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) API.
9 |
10 | ## Installation
11 |
12 | Install it with yarn:
13 |
14 | ```
15 | yarn add react-media-hook
16 | ```
17 |
18 | Or with npm:
19 |
20 | ```
21 | npm i react-media-hook --save
22 | ```
23 |
24 | ## Usage
25 |
26 | Pass query to *useMediaPredicate*:
27 |
28 | ```javascript
29 | import React from "react";
30 | import { useMediaPredicate } from "react-media-hook";
31 |
32 | const Component = () => {
33 | const biggerThan400 = useMediaPredicate("(min-width: 400px)");
34 |
35 | return
36 | {biggerThan400 && }
37 |
38 | };
39 |
40 | ```
41 |
42 | ## API
43 |
44 | #### `useMedia(query: string)`
45 | Returns *undefined* (for example, in Node.js environment
46 | where *mathMedia* is not defined), or object, simular to *mathMedia(...)* result:
47 | ```javascript
48 | {
49 | matches: boolean,
50 | media: string
51 | }
52 | ```
53 |
54 | #### `useMediaPredicate(query: string)`
55 | Returns just *true* or *false*.
56 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var React = require('react')
2 |
3 | function fallbackMatchMedia (query) {
4 | if (typeof matchMedia !== 'function') {
5 | return null
6 | }
7 | return matchMedia(query)
8 | }
9 |
10 | function omitMatchMediaResult (matchMediaResult) {
11 | if (!matchMediaResult) {
12 | return null
13 | }
14 | return { media: matchMediaResult.media, matches: matchMediaResult.matches }
15 | }
16 |
17 | function useMedia (query) {
18 | var mounted = React.useState(false)
19 | var setMounted = mounted[1]
20 |
21 | React.useEffect(function () {
22 | setMounted(true)
23 | }, [setMounted])
24 |
25 | var result = React.useState(function () {
26 | return omitMatchMediaResult(fallbackMatchMedia(query))
27 | })
28 | var setResult = result[1]
29 |
30 | var callback = React.useCallback(function (matchMediaResult) {
31 | return setResult(omitMatchMediaResult(matchMediaResult))
32 | }, [setResult])
33 |
34 | React.useEffect(
35 | function () {
36 | var matchMediaResult = fallbackMatchMedia(query)
37 | callback(matchMediaResult)
38 | if (matchMediaResult) {
39 | matchMediaResult.addEventListener('change', callback)
40 | }
41 | return function () {
42 | if (matchMediaResult) {
43 | matchMediaResult.removeEventListener('change', callback)
44 | }
45 | }
46 | },
47 | [callback, query]
48 | )
49 |
50 | if (!mounted[0]) {
51 | return null
52 | }
53 |
54 | return result[0]
55 | }
56 |
57 | function useMediaPredicate (query) {
58 | var result = useMedia(query)
59 | return (result && result.matches) || false
60 | }
61 |
62 | module.exports = {
63 | useMedia: useMedia,
64 | useMediaPredicate: useMediaPredicate
65 | }
66 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-media-hook",
3 | "version": "0.5.1",
4 | "main": "index.js",
5 | "types": "index.d.ts",
6 | "description": "React Hook for media query",
7 | "scripts": {
8 | "flow": "flow",
9 | "typescript": "tsc -p tsconfig.json --noEmit",
10 | "size": "size-limit",
11 | "lint": "eslint '**/*.{js,jsx}' --quiet",
12 | "run:example": "parcel ./example/index.html",
13 | "prepublish": "npm run flow && npm run lint && npm run size"
14 | },
15 | "size-limit": [
16 | {
17 | "ignore": [
18 | "react"
19 | ],
20 | "limit": "442 B",
21 | "name": "useMedia",
22 | "import": {
23 | "./index.js": "{ useMedia }"
24 | }
25 | },
26 | {
27 | "ignore": [
28 | "react"
29 | ],
30 | "limit": "442 B",
31 | "name": "useMediaPredicate",
32 | "import": {
33 | "./index.js": "{ useMediaPredicate }"
34 | }
35 | }
36 | ],
37 | "eslintConfig": {
38 | "extends": [
39 | "@brainhubinc/eslint-config/lib",
40 | "@brainhubinc/eslint-config/react-hooks"
41 | ]
42 | },
43 | "files": [
44 | "index.js",
45 | "index.js.flow",
46 | "index.d.ts"
47 | ],
48 | "repository": {
49 | "type": "git",
50 | "url": "git+ssh://git@github.com/brainhubinc/react-media-hook.git"
51 | },
52 | "keywords": [
53 | "react",
54 | "hook",
55 | "media"
56 | ],
57 | "author": "Ilya Lesik",
58 | "license": "MIT",
59 | "bugs": {
60 | "url": "https://github.com/brainhubinc/react-media-hook/issues"
61 | },
62 | "homepage": "https://github.com/brainhubinc/react-media-hook#readme",
63 | "peerDependencies": {
64 | "react": ">=16.8.0"
65 | },
66 | "devDependencies": {
67 | "@babel/core": "^7.2.2",
68 | "@babel/preset-env": "^7.2.0",
69 | "@babel/preset-react": "^7.0.0",
70 | "@brainhubinc/eslint-config": "^0.0.1",
71 | "@size-limit/file": "^11.2.0",
72 | "@size-limit/webpack": "^11.2.0",
73 | "eslint": "^5.16.0",
74 | "eslint-config-standard": "^12.0.0",
75 | "eslint-plugin-es5": "^1.4.1",
76 | "eslint-plugin-import": "^2.17.3",
77 | "eslint-plugin-import-helpers": "^0.1.4",
78 | "eslint-plugin-node": "^9.1.0",
79 | "eslint-plugin-promise": "^4.1.1",
80 | "eslint-plugin-react-hooks": "^1.6.0",
81 | "eslint-plugin-security": "^1.4.0",
82 | "eslint-plugin-standard": "^4.0.0",
83 | "flow-bin": "^0.89.0",
84 | "parcel-bundler": "^1.12.3",
85 | "react": "^16.8.6",
86 | "react-dom": "^16.8.6",
87 | "size-limit": "^11.2.0",
88 | "typescript": "^5.8.3"
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 |
7 | defaults: &defaults
8 | working_directory: ~/repo
9 | docker:
10 | - image: cimg/node:21.6
11 |
12 | jobs:
13 | install:
14 | <<: *defaults
15 |
16 | steps:
17 | - checkout
18 |
19 | # Download and cache dependencies
20 | - restore_cache:
21 | keys:
22 | - v1-dependencies-{{ checksum "package.json" }}
23 | # fallback to using the latest cache if no exact match is found
24 | - v1-dependencies-
25 |
26 | - run: yarn --frozen-lockfile
27 |
28 | - save_cache:
29 | paths:
30 | - node_modules
31 | key: v1-dependencies-{{ checksum "package.json" }}
32 |
33 | - persist_to_workspace:
34 | root: ~/repo
35 | paths: .
36 |
37 | flow:
38 | <<: *defaults
39 |
40 | steps:
41 | - attach_workspace:
42 | at: ~/repo
43 | - run:
44 | name: Run Flow
45 | command: npm run flow
46 |
47 | typescript:
48 | <<: *defaults
49 |
50 | steps:
51 | - attach_workspace:
52 | at: ~/repo
53 | - run:
54 | name: Run TypeScript
55 | command: npm run typescript
56 |
57 | lint:
58 | <<: *defaults
59 |
60 | steps:
61 | - attach_workspace:
62 | at: ~/repo
63 | - run:
64 | name: Run linting check
65 | command: npm run lint
66 |
67 | size:
68 | <<: *defaults
69 |
70 | steps:
71 | - attach_workspace:
72 | at: ~/repo
73 | - run:
74 | name: Run package size check
75 | command: npm run size
76 |
77 | deploy:
78 | <<: *defaults
79 | steps:
80 | - attach_workspace:
81 | at: ~/repo
82 | - run:
83 | name: Authenticate with registry
84 | command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/repo/.npmrc
85 | - run:
86 | name: Publish package
87 | command: npm publish
88 |
89 | workflows:
90 | version: 2
91 | test-deploy:
92 | jobs:
93 | - install:
94 | filters:
95 | tags:
96 | only: /^v.*/
97 | - flow:
98 | requires:
99 | - install
100 | filters:
101 | tags:
102 | only: /^v.*/
103 | - typescript:
104 | requires:
105 | - install
106 | filters:
107 | tags:
108 | only: /^v.*/
109 | - lint:
110 | requires:
111 | - install
112 | filters:
113 | tags:
114 | only: /^v.*/
115 | - size:
116 | requires:
117 | - install
118 | filters:
119 | tags:
120 | only: /^v.*/
121 | - deploy:
122 | requires:
123 | - flow
124 | - typescript
125 | - lint
126 | - size
127 | filters:
128 | tags:
129 | only: /^v.*/
130 | branches:
131 | ignore: /.*/
132 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at info@brainhub.team. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------