Skip to content

Instantly share code, notes, and snippets.

@zeckdude
Last active July 5, 2022 23:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeckdude/9f3cc8f73e4d661f4fa2b94c347a47a1 to your computer and use it in GitHub Desktop.
Save zeckdude/9f3cc8f73e4d661f4fa2b94c347a47a1 to your computer and use it in GitHub Desktop.
ResponsiveElements component to generate div to show/hide children content with varying prop values at varying breakpoints
import { FC, cloneElement, ReactElement } from 'react';
import { css } from '@emotion/react';
import { useTheme, Breakpoint, Box } from '@mui/material';
const getNextBreakpointSize = ({
currentBreakpoint,
supportedBreakpoints,
responsivePropsBreakpoints,
}: {
currentBreakpoint: Breakpoint;
supportedBreakpoints: Breakpoint[];
responsivePropsBreakpoints: string[];
}) => {
const currentBreakpointIndex = supportedBreakpoints.indexOf(currentBreakpoint);
for (let i = currentBreakpointIndex; i < supportedBreakpoints.length; i++) {
const nextSupportedBreakpoint = supportedBreakpoints[i + 1];
if (responsivePropsBreakpoints.includes(nextSupportedBreakpoint)) {
return nextSupportedBreakpoint;
}
}
return null;
};
interface ResponsiveProps {
[key: string]: any;
}
interface ResponsiveElementsProps {
responsiveProps: ResponsiveProps;
children: ReactElement;
}
/**
* Component to generate div to show/hide children content with varying prop values at varying breakpoints so that the content changes and still renders correctly when using SSR
*
* @param {ReactElement} children
* @param {object} responsiveProps - An object of breakpoints where a prop value changes
* @return {ReactElement} A div with css media queries to hide/show content that has varying props applied to each one
*
* @example
*
* <ResponsiveElements
* responsiveProps={{
* xs: {
* variant: 'md',
* },
* md: {
* variant: 'lg',
* },
* }}
* >
* <Typography>Yo I'm some text</Typography>
* </ResponsiveElements>
*/
export const ResponsiveElements: FC<ResponsiveElementsProps> = ({ children, responsiveProps }) => {
const theme = useTheme();
const responsiveElementsWithMediaQueries = theme.breakpoints.keys.map((breakpoint) => {
const isBreakpointInResponsiveProps = !!responsiveProps[breakpoint];
if (!isBreakpointInResponsiveProps) {
return null;
}
const nextBreakpointSize = getNextBreakpointSize({
currentBreakpoint: breakpoint,
supportedBreakpoints: theme.breakpoints.keys,
responsivePropsBreakpoints: Object.keys(responsiveProps),
});
return (
<Box
css={css`
display: none;
${theme.breakpoints.up(breakpoint)} {
display: block;
}
${nextBreakpointSize &&
`
${theme.breakpoints.up(nextBreakpointSize)} {
display: none;
}
`}
`}
>
{cloneElement(children, { ...responsiveProps[breakpoint] })}
</Box>
);
});
return <>{responsiveElementsWithMediaQueries}</>;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment