diff --git a/package.json b/package.json
index 0ed56a6..fb113ba 100644
--- a/package.json
+++ b/package.json
@@ -45,10 +45,12 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/react-hooks": "^5.1.1",
+ "@types/css-mediaquery": "^0.1.1",
"@types/jest": "^26.0.22",
"@types/react": "^17.0.3",
"@typescript-eslint/eslint-plugin": "^4.21.0",
"@typescript-eslint/parser": "^4.21.0",
+ "css-mediaquery": "^0.1.2",
"eslint": "^7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
diff --git a/readme.md b/readme.md
index a65f43e..b5efe7c 100644
--- a/readme.md
+++ b/readme.md
@@ -12,6 +12,7 @@ This package includes different tools that support you with common tasks.
- [useInterval](#useinterval)
- [Async Data](#async-data)
- [LocationProvider](#locationprovider)
+ - [useMatchMediaQuery](#usematchmediaquery)
- [Build & Publish](#build--publish)
- [Information](#information)
@@ -149,6 +150,20 @@ const MyComponent = () => {
}
```
+### useMatchMediaQuery
+
+This hook is based on the `window.matchQuery` API and can be used to find out if a certain media query matches the current window.
+
+```tsx
+import { useMatchMediaQuery } from '@aboutbits/react-toolbox'
+
+const TestComponent = () => {
+ const matches = useMatchMediaQuery('(min-width : 500px)')
+ if (matches) return
visible
+ return null
+}
+```
+
## Build & Publish
To publish the package commit all changes and push them to main. Then run one of the following commands locally:
diff --git a/src/index.ts b/src/index.ts
index cfec293..dd89387 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,6 +6,7 @@ import {
LocationContext,
LocationContextValue,
} from './location-provider/LocationProvider'
+import { useMatchMediaQuery } from './useMatchMediaQuery/useMatchMediaQuery'
export {
useInterval,
@@ -15,4 +16,5 @@ export {
LocationProvider,
LocationContext,
LocationContextValue,
+ useMatchMediaQuery,
}
diff --git a/src/useMatchMediaQuery/__test__/useMatchMediaQuery.test.tsx b/src/useMatchMediaQuery/__test__/useMatchMediaQuery.test.tsx
new file mode 100644
index 0000000..d377555
--- /dev/null
+++ b/src/useMatchMediaQuery/__test__/useMatchMediaQuery.test.tsx
@@ -0,0 +1,46 @@
+import React from 'react'
+import isMatching from 'css-mediaquery'
+import { render, RenderResult } from '@testing-library/react'
+import { useMatchMediaQuery } from '../useMatchMediaQuery'
+
+beforeEach(() => {
+ // mock window.matchMedia (use 'css-mediaquery')
+ window.matchMedia = jest.fn().mockImplementation((query) => {
+ return {
+ addListener: jest.fn(),
+ media: query,
+ matches: isMatching.match(query, {
+ width: 500,
+ }),
+ }
+ })
+})
+
+const TestComponent = ({ query }: { query: string }) => {
+ const isMatched = useMatchMediaQuery(query)
+ if (isMatched) return visible
+ return hidden
+}
+
+function renderTestComponent(query: string): RenderResult {
+ return render()
+}
+
+describe('useReactSimpleMatchMedia', () => {
+ it('should be visible when min width matches', () => {
+ const { getByText } = renderTestComponent('(min-width : 500px)')
+ expect(getByText(/visible/i)).toBeInTheDocument()
+ })
+
+ it('should not be visible min does not match', () => {
+ const { getByText } = renderTestComponent('(min-width : 600px)')
+ expect(getByText(/hidden/i)).toBeInTheDocument()
+ })
+
+ it('should be visible if between matches', () => {
+ const { getByText } = renderTestComponent(
+ '(min-width : 500px) and (max-width: 600px)'
+ )
+ expect(getByText(/visible/i)).toBeInTheDocument()
+ })
+})
diff --git a/src/useMatchMediaQuery/useMatchMediaQuery.ts b/src/useMatchMediaQuery/useMatchMediaQuery.ts
new file mode 100644
index 0000000..eb2c205
--- /dev/null
+++ b/src/useMatchMediaQuery/useMatchMediaQuery.ts
@@ -0,0 +1,26 @@
+import { useState, useEffect } from 'react'
+
+function useMatchMediaQuery(query: string): boolean | undefined {
+ if (typeof window !== 'object' || !window.matchMedia) return
+
+ const [matches, setMatches] = useState(window.matchMedia(query).matches)
+
+ useEffect(() => {
+ const media = window.matchMedia(query)
+
+ if (media.matches !== matches) setMatches(media.matches)
+
+ const listener = () => setMatches(media.matches)
+
+ if (media.addEventListener) {
+ media.addEventListener('change', listener)
+ }
+
+ return () =>
+ media.removeEventListener && media.removeEventListener('change', listener)
+ }, [matches, query])
+
+ return matches
+}
+
+export { useMatchMediaQuery }