I created a media query that looks like this:
media.ts
export const breakpoints = {
sm: 420,
md: 768,
lg: 992,
xlg: 1200,
};
export const media = Object.keys(breakpoints).reduce((acc, label) => {
acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) =>
css`
@media (min-width: ${breakpoints[label]}px) {
${css(literals, ...placeholders)};
}
`.join('');
return acc;
}, {} as Record<keyof typeof breakpoints, (l: TemplateStringsArray, ...p: any[]) => string>);
Which will work like this:
* @example
* const StyledComponent = styled.div`
* background-color: red;
*
* ${media.sm`
* background-color: blue
* `}
*
* ${media.md`
* background-color: green;
* `}
However, when I pass props into the media query, it seems to get ignored. Example here:
<GreetingContainer isTesting>
...
</GreetingContainer>
const GreetingContainer = styled.div`
display: flex;
background: green;
${media.md`
flex-direction: row;
`}
${media.lg`
background: ${(props: { isTesting: any }) => (props.isTesting ? 'blue' : 'red')};
`}
` as any;
It seems like in my media.lg
, the whole thing gets ignored completely. Does anyone know what's going on? Is there a workaround or a fix in the utility I've written?
I'm seeing my css looks like this:
which is very much not what I want. What seems to be the issue here?
The culprit is the ending .join('')
, which forces the output of css
template tag function to be converted as a string, hence the "inlining" of your function body in the CSS rule.
Just remove it to restore your expected behaviour:
export const media = Object.keys(breakpoints).reduce((acc, label) => {
acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) =>
css`
@media (min-width: ${breakpoints[label]}px) {
${css(literals, ...placeholders)};
}
`; //.join(""); // Let the output remain a function
return acc;
}, {} as Record<keyof typeof breakpoints, (l: TemplateStringsArray, ...p: any[]) => string>);
Demo: https://codesandbox.io/s/eager-benji-qepx9o?file=/src/App.tsx