Last active
March 7, 2024 14:31
-
-
Save PinkiNice/596ac733614bbd90eecb0593dccdee08 to your computer and use it in GitHub Desktop.
Media Queries for CSS-in-JS + Rect
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CSSPropertiesWithMultiValues } from '@emotion/serialize'; | |
import React, { PropsWithChildren, useEffect, useState } from 'react'; | |
type ScreenSize = 'xs' | 'sm' | 'md' | 'lg'; | |
const screenSize = { | |
xs: 0, | |
sm: 576, | |
md: 768, | |
lg: 992, | |
}; | |
type MediaQueryTarget = { min?: ScreenSize; max?: ScreenSize } | ScreenSize; | |
function buildMediaQueryString(size: MediaQueryTarget) { | |
const min = typeof size === 'string' ? size : size.min; | |
const max = typeof size === 'string' ? null : size.max; | |
const maxStatement = max ? `(max-width: ${screenSize[max]}px)` : ''; | |
const minStatement = min ? `(min-width: ${screenSize[min]}px)` : ''; | |
const combined = [minStatement, maxStatement].filter(Boolean).join(' and '); | |
return combined; | |
} | |
/** | |
* | |
* @param size mobile-first size or object with min and max sizes | |
* @param css styles to be applied when condition is met | |
* @returns | |
*/ | |
export function media( | |
size: MediaQueryTarget, | |
css: CSSPropertiesWithMultiValues | { [key: string]: any } | |
) { | |
const mediaQueryExpression = buildMediaQueryString(size); | |
return { | |
[`@media ${mediaQueryExpression}`]: { | |
...css, | |
}, | |
}; | |
} | |
export function useMediaQuery(size: MediaQueryTarget) { | |
const [matches, setMatches] = useState(false); | |
useEffect(() => { | |
const mediaQuery = window.matchMedia(buildMediaQueryString(size)); | |
setMatches(mediaQuery.matches); | |
const listener = () => { | |
setMatches(mediaQuery.matches); | |
}; | |
mediaQuery.addEventListener('change', listener); | |
return () => { | |
mediaQuery.removeEventListener('change', listener); | |
}; | |
}, [size]); | |
return matches; | |
} | |
export const MediaQuery = ({ | |
min, | |
children, | |
}: PropsWithChildren<{ min: ScreenSize }>) => { | |
const matches = useMediaQuery(min); | |
if (matches) { | |
return <React.Fragment>{children}</React.Fragment>; | |
} | |
return null; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment