Skip to content

Instantly share code, notes, and snippets.

@jepser
Last active May 18, 2019 16:11
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 jepser/e3c5954cd0885aae02adb403d661c1cf to your computer and use it in GitHub Desktop.
Save jepser/e3c5954cd0885aae02adb403d661c1cf to your computer and use it in GitHub Desktop.
Implementation of responsive styled components
// helpers.js
/**
* Generate a valid structure for responsive configuration for a component
* @param {object} props props received from the component
* @param {array} baseProps list of props to be validated
*
* @returns a structured object with the props for each media query
*/
export const generateResponsiveProps = (props, baseProps) => {
// from the breakpoints registered check which props exists
const shapedPropsWithMq = Object.keys(BREAKPOINTS).reduce(
(responsiveProps, mqName) => {
const propsForMq = props[mqName];
if (!propsForMq && typeof propsForMq !== 'object') return responsiveProps;
// for the props that exists, prepare them with the correct shape
const shapedProps = baseProps.reduce(
(propList, prop) => ({
...propList,
[prop]: propsForMq[prop],
}),
{}
);
return {
...responsiveProps,
[mqName]: shapedProps,
};
},
{}
);
return shapedPropsWithMq;
};
/**
* Call the styles factory for with the correct props for each media query
* @param {function} stylesGenerator function that generates the styles
*
* @returns {array} array of styles to be applied for the registered media queries
*/
export const generateResponsiveStyles = stylesGenerator => props =>
Object.keys(mediaqueries).reduce((rules, mq) => {
if (!props[mq]) return rules;
const styles = mediaqueries[mq]`
${stylesGenerator(props[mq])}
`;
return [...rules, styles];
}, []);
// styled components
const baseStyles = ({ top, left, right, bottom }) => css`
margin-top: ${top ? unitizedPx(top) : null};
margin-right: ${right ? unitizedPx(right) : null};
margin-bottom: ${bottom ? unitizedPx(bottom) : null};
margin-left: ${left ? unitizedPx(left) : null};
`;
const responsiveStyles = generateResponsiveStyles(baseStyles);
export const Root = styled.div`
display: ${props => (props.inline ? 'inline-block' : 'block')};
${baseStyles}
${responsiveStyles}
}
`;
// component
const BASE_PROPS = ['top', 'left', 'right', 'bottom'];
const Spacer = ({ top, left, bottom, right, children, inline, ...rest }) => {
const responsiveProps = generateResponsiveProps(rest, BASE_PROPS);
return (
<Root
bottom={bottom}
inline={inline}
left={left}
right={right}
top={top}
{...responsiveProps}
>
{children}
</Root>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment