Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

use-media

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

use-media - npm Package Compare versions

Comparing version 1.3.1 to 1.4.0

lib/types.d.ts

7

CHANGELOG.md

@@ -0,1 +1,8 @@

# [1.4.0](https://github.com/streamich/use-media/compare/v1.3.1...v1.4.0) (2019-07-27)
### Features
* refactor /src folder ([8f72ba2](https://github.com/streamich/use-media/commit/8f72ba2))
## [1.3.1](https://github.com/streamich/use-media/compare/v1.3.0...v1.3.1) (2019-07-27)

@@ -2,0 +9,0 @@

7

lib/index.d.ts

@@ -1,6 +0,1 @@

declare type MediaQueryObject = {
[key: string]: string | number | boolean;
};
export declare const useMedia: (rawQuery: string | MediaQueryObject, defaultState?: boolean) => boolean;
export declare const useMediaLayout: (rawQuery: string | MediaQueryObject, defaultState?: boolean) => boolean;
export default useMedia;
export { default, useMedia, useMediaLayout } from './useMedia';
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var useState = React.useState, useEffect = React.useEffect, useLayoutEffect = React.useLayoutEffect;
var camelToHyphen = function (str) {
return str.replace(/[A-Z]/g, function (m) { return "-" + m.toLowerCase(); }).toLowerCase();
};
var noWindowMatches = {
media: '',
addListener: noop,
removeListener: noop,
matches: false,
onchange: noop,
addEventListener: noop,
removeEventListener: noop,
dispatchEvent: function (_) { return true; }
};
var objectToString = function (query) {
if (typeof query === 'string')
return query;
return Object.entries(query)
.map(function (_a) {
var feature = _a[0], value = _a[1];
feature = camelToHyphen(feature);
if (typeof value === 'boolean') {
return value ? feature : "not " + feature;
}
if (typeof value === 'number' && /[height|width]$/.test(feature)) {
value = value + "px";
}
return "(" + feature + ": " + value + ")";
})
.join(' and ');
};
var createUseMedia = function (effect) { return function (rawQuery, defaultState) {
if (defaultState === void 0) { defaultState = false; }
var _a = useState(defaultState), state = _a[0], setState = _a[1];
var query = objectToString(rawQuery);
effect(function () {
var mounted = true;
var mql = typeof window === 'undefined'
? noWindowMatches
: window.matchMedia(query);
var onChange = function () {
if (!mounted)
return;
setState(!!mql.matches);
};
mql.addListener(onChange);
setState(mql.matches);
return function () {
mounted = false;
mql.removeListener(onChange);
};
}, [query]);
return state;
}; };
function noop() { }
exports.useMedia = createUseMedia(useEffect);
exports.useMediaLayout = createUseMedia(useLayoutEffect);
exports.default = exports.useMedia;
var useMedia_1 = require("./useMedia");
exports.default = useMedia_1.default;
exports.useMedia = useMedia_1.useMedia;
exports.useMediaLayout = useMedia_1.useMediaLayout;
{
"name": "use-media",
"version": "1.3.1",
"version": "1.4.0",
"description": "useMedia React hook",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -5,3 +5,2 @@ # use-media

## Usage

@@ -12,7 +11,9 @@

```jsx
import {useMedia} from 'use-media';
import useMedia from 'use-media';
// Alternatively, you can import as:
// import {useMedia} from 'use-media';
const Demo = () => {
// Accepts an object of features to test
const isWide = useMedia({ minWidth: 1000 });
const isWide = useMedia({minWidth: 1000});
// Or a regular media query string

@@ -36,3 +37,3 @@ const reduceMotion = useMedia('(prefers-reduced-motion: reduce)');

// Accepts an object of features to test
const isWide = useMediaLayout({ minWidth: 1000 });
const isWide = useMediaLayout({minWidth: 1000});
// Or a regular media query string

@@ -48,1 +49,144 @@ const reduceMotion = useMediaLayout('(prefers-reduced-motion: reduce)');

```
## Testing
Depending on your testing setup, you may need to mock `window.matchMedia` on components that utilize the `useMedia` hook. Below is an example of doing this in `jest`:
**`/test-utilities/index.ts`**
```jsx
import {mockMediaQueryList} from 'use-media/lib/useMedia';
// Types are also exported for convienence:
// import {Effect, MediaQueryObject} from 'use-media/lib/types';
export interface MockMatchMedia {
media: string;
matches?: boolean;
}
function getMockImplementation({media, matches = false}: MockMatchMedia) {
const mql: MediaQueryList = {
...mockMediaQueryList,
media,
matches,
};
return () => mql;
}
export function jestMockMatchMedia({media, matches = false}: MockMatchMedia) {
const mockedImplementation = getMockImplementation({media, matches});
window.matchMedia = jest.fn().mockImplementation(mockedImplementation);
}
```
**`/components/MyComponent/MyComponent.test.tsx`**
```jsx
const mediaQueries = {
mobile: '(max-width: 767px)',
prefersReducedMotion: '(prefers-reduced-motion: reduce)',
};
describe('<MyComponent />', () => {
const defaultProps: Props = {
duration: 100,
};
afterEach(() => {
jestMockMatchMedia({
media: mediaQueries.prefersReducedMotion,
matches: false,
});
});
it('sets `duration` to `0` when user-agent `prefers-reduced-motion`', () => {
jestMockMatchMedia({
media: mediaQueries.prefersReducedMotion,
matches: true,
});
const wrapper = mount(<MyComponent {...defaultProps} />);
const child = wrapper.find(TransitionComponent);
expect(child.prop('duration')).toBe(0);
});
});
```
## Storing in Context
Depending on your app, you may be using the `useMedia` hook to register many `matchMedia` listeners across multiple components. It may help to elevate these listeners to `Context`.
**`/components/MediaQueryProvider/MediaQueryProvider.tsx`**
```jsx
import React, {createContext, useContext, useMemo} from 'react';
import useMedia from 'use-media';
interface Props {
children: React.ReactNode;
}
export const MediaQueryContext = createContext(null);
const mediaQueries = {
mobile: '(max-width: 767px)',
prefersReducedMotion: '(prefers-reduced-motion: reduce)',
};
export default function MediaQueryProvider({children}: Props) {
const mobileView = useMedia(mediaQueries.mobile);
const prefersReducedMotion = useMedia(mediaQueries.prefersReducedMotion);
const value = useMemo(() => ({mobileView, prefersReducedMotion}), [
mobileView,
prefersReducedMotion,
]);
return (
<MediaQueryContext.Provider value={value}>
{children}
</MediaQueryContext.Provider>
);
}
export function useMediaQueryContext() {
return useContext(MediaQueryContext);
}
```
**`/components/App/App.tsx`**
```jsx
import React from 'react';
import MediaQueryProvider from '../MediaQueryProvider';
import MyComponent from '../MyComponent';
export default function App() {
return (
<MediaQueryProvider>
<div id="MyApp">
<MyComponent />
</div>
</MediaQueryProvider>
);
}
```
**`/components/MyComponent/MyComponent.tsx`**
```jsx
import React from 'react';
import {useMediaQueryContext} from '../MediaQueryProvider';
export default function MyComponent() {
const {mobileView, prefersReducedMotion} = useMediaQueryContext();
return (
<div>
<p>mobileView: {Boolean(mobileView).toString()}</p>
<p>prefersReducedMotion: {Boolean(prefersReducedMotion).toString()}</p>
</div>
);
}
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc