@atlaskit/primitives
Version:
Primitives are token-backed low-level building blocks.
72 lines (69 loc) • 6.17 kB
JavaScript
var _window, _window$matchMedia, _window2, _window2$matchMedia, _window3, _window3$matchMedia, _window4, _window4$matchMedia, _window5, _window5$matchMedia, _window6, _window6$matchMedia, _window7, _window7$matchMedia, _window8, _window8$matchMedia, _window9, _window9$matchMedia, _window10, _window10$matchMedia, _window11, _window11$matchMedia;
import { useEffect, useRef } from 'react';
import { bind } from 'bind-event-listener';
import { useLayoutEffect } from '@atlaskit/ds-lib/use-layout-effect';
import { UNSAFE_media } from './media-helper';
const queries = {
'above.xxs': typeof window === 'undefined' ? undefined : (_window = window) === null || _window === void 0 ? void 0 : (_window$matchMedia = _window.matchMedia) === null || _window$matchMedia === void 0 ? void 0 : _window$matchMedia.call(_window, UNSAFE_media.above.xxs.replace('@media ', '').trim()),
'above.xs': typeof window === 'undefined' ? undefined : (_window2 = window) === null || _window2 === void 0 ? void 0 : (_window2$matchMedia = _window2.matchMedia) === null || _window2$matchMedia === void 0 ? void 0 : _window2$matchMedia.call(_window2, UNSAFE_media.above.xs.replace('@media ', '').trim()),
'above.sm': typeof window === 'undefined' ? undefined : (_window3 = window) === null || _window3 === void 0 ? void 0 : (_window3$matchMedia = _window3.matchMedia) === null || _window3$matchMedia === void 0 ? void 0 : _window3$matchMedia.call(_window3, UNSAFE_media.above.sm.replace('@media ', '').trim()),
'above.md': typeof window === 'undefined' ? undefined : (_window4 = window) === null || _window4 === void 0 ? void 0 : (_window4$matchMedia = _window4.matchMedia) === null || _window4$matchMedia === void 0 ? void 0 : _window4$matchMedia.call(_window4, UNSAFE_media.above.md.replace('@media ', '').trim()),
'above.lg': typeof window === 'undefined' ? undefined : (_window5 = window) === null || _window5 === void 0 ? void 0 : (_window5$matchMedia = _window5.matchMedia) === null || _window5$matchMedia === void 0 ? void 0 : _window5$matchMedia.call(_window5, UNSAFE_media.above.lg.replace('@media ', '').trim()),
'above.xl': typeof window === 'undefined' ? undefined : (_window6 = window) === null || _window6 === void 0 ? void 0 : (_window6$matchMedia = _window6.matchMedia) === null || _window6$matchMedia === void 0 ? void 0 : _window6$matchMedia.call(_window6, UNSAFE_media.above.xl.replace('@media ', '').trim()),
'below.xs': typeof window === 'undefined' ? undefined : (_window7 = window) === null || _window7 === void 0 ? void 0 : (_window7$matchMedia = _window7.matchMedia) === null || _window7$matchMedia === void 0 ? void 0 : _window7$matchMedia.call(_window7, UNSAFE_media.below.xs.replace('@media ', '').trim()),
'below.sm': typeof window === 'undefined' ? undefined : (_window8 = window) === null || _window8 === void 0 ? void 0 : (_window8$matchMedia = _window8.matchMedia) === null || _window8$matchMedia === void 0 ? void 0 : _window8$matchMedia.call(_window8, UNSAFE_media.below.sm.replace('@media ', '').trim()),
'below.md': typeof window === 'undefined' ? undefined : (_window9 = window) === null || _window9 === void 0 ? void 0 : (_window9$matchMedia = _window9.matchMedia) === null || _window9$matchMedia === void 0 ? void 0 : _window9$matchMedia.call(_window9, UNSAFE_media.below.md.replace('@media ', '').trim()),
'below.lg': typeof window === 'undefined' ? undefined : (_window10 = window) === null || _window10 === void 0 ? void 0 : (_window10$matchMedia = _window10.matchMedia) === null || _window10$matchMedia === void 0 ? void 0 : _window10$matchMedia.call(_window10, UNSAFE_media.below.lg.replace('@media ', '').trim()),
'below.xl': typeof window === 'undefined' ? undefined : (_window11 = window) === null || _window11 === void 0 ? void 0 : (_window11$matchMedia = _window11.matchMedia) === null || _window11$matchMedia === void 0 ? void 0 : _window11$matchMedia.call(_window11, UNSAFE_media.below.xl.replace('@media ', '').trim())
};
/**
* A hook which returnes a `window.matchMedia` result to help you build responsively around breakpoints in JavaScript.
*
* The returning value **WILL NOT** update or react to change. You can use `mq.matches` to get the latest version and you can use the optional listener argument to react to changes as desired.
*
* @important
* - This will always be `null` in SSR and the event listener should not fire on SSR => clientside hydration.
* - `above.xxs` will always be truthy, your listener should never fire.
*
* @experimental This hook only works on the client-side and is not safe in an SSR environment as `window` is unavailable (and the user's viewport would be unknown)
*
* @example
* const mq = useMediaQuery('below.md', useCallback((event) => console.log('changed', event.matches)), []))
* const isMobile = mq?.matches;
*
* @returns
* - `MediaQueryList`, primarily used to get if that media query is currently
* - `null` when `matchMedia` is unavailable, eg. in SSR.
*/
export const UNSAFE_useMediaQuery = (queryString, listener) => {
const listenerRef = useRef(listener);
useEffect(() => {
// Bind the listener if changed so it's called on the next change event; no guarantee on timing.
listenerRef.current = listener;
}, [listener]);
/**
* We explicitly only react to boolean changes for binding our listener
* Changes to the functional reference are ignored.
*/
const hasListener = !!listener;
/**
* The `matchMedia(…)` return value for our breakpoint query.
*/
const mq = queries[queryString];
useLayoutEffect(() => {
listenerRef.current = listener; // Bind the listener now in case the `useEffect` hasn't fired above yet
if (!mq || !hasListener || !listenerRef.current) {
return;
}
return bind(mq, {
type: 'change',
listener: event => {
// We explicitly call the current version of the function
return listenerRef.current(event);
}
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps -- explicitly do not trigger the effect on `listener` reference change, only on a boolean representation of it.
[mq, hasListener]);
return mq || null;
};