Skip to content

Instantly share code, notes, and snippets.

@andrecastelo
Last active August 1, 2024 06:35
Show Gist options
  • Save andrecastelo/d6ed8c341e4e8130060033cdef75262f to your computer and use it in GitHub Desktop.
Save andrecastelo/d6ed8c341e4e8130060033cdef75262f to your computer and use it in GitHub Desktop.
Prop Forwarding with Emotion, Material-UI and Material-UI-System
import styled from '@emotion/styled';
import {
Typography as MaterialTypography,
TypographyProps as MaterialTypographyProps,
} from '@material-ui/core';
import {
spacing,
SpacingProps,
sizing,
SizingProps,
typography,
TypographyProps as MaterialSystemTypographyProps,
} from '@material-ui/system';
import shouldForwardProp from './shouldForwardProp';
type TypographyProps = MaterialTypographyProps &
SpacingProps &
SizingProps &
MaterialSystemTypographyProps;
export const Typography = styled(MaterialTypography, {
shouldForwardProp,
})<TypographyProps>`
${sizing}
${spacing}
${typography}
`;
import memoize from '@emotion/memoize';
import isPropValid from '@emotion/is-prop-valid';
/**
* These props will not be forwarded to the wrapped element by @emotion/styled.
*/
// prettier-ignore
const props: string[] = [
// @material-ui/system/borders
'border', 'borderBottom', 'borderColor', 'borderLeft', 'borderRadius',
'borderRight', 'borderTop',
// @material-ui/system/shadows
'boxShadow',
// @material-ui/system/spacing
'm', 'mx', 'my', 'margin',
'mb', 'marginBottom',
'ml', 'marginLeft',
'mr', 'marginRight',
'mt', 'marginTop',
'p', 'px', 'py', 'padding',
'pb', 'paddingBottom',
'pl', 'paddingLeft',
'pr', 'paddingRight',
'pt', 'paddingTop',
// @material-ui/system/display
'displayPrint', 'display',
// @material-ui/system/flexbox
'alignContent', 'alignItems', 'alignSelf', 'flex', 'flexDirection',
'flexGrow', 'flexShrink', 'flexWrap', 'justifyContent', 'order',
// @material-ui/system/palette
'bgColor', 'color',
// @material-ui/system/positions
'bottom', 'left', 'position', 'right', 'top', 'zIndex',
// @material-ui/system/sizing
'height', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'width', 'boxSizing',
// @material-ui/system/typography
'fontFamily', 'fontSize', 'fontWeight', 'textAlign',
];
const regex = new RegExp(`^(${props.join('|')})$`);
type Fn<T> = (key: string) => T;
/**
* The return function will only filter out the props listed above. This is the
* one we want to use if we are wrapping a Material-UI component.
*/
export const createShouldForwardProp = (): Fn<boolean> =>
memoize((prop) => !regex.test(prop));
export default createShouldForwardProp();
/**
* The created function will filter out the props listed above and any prop
* that is not a valid DOM prop. So this is the function we want to use if
* we are wrapping existing DOM components.
*/
const createShouldForwardDomProp = (): Fn<boolean> =>
memoize((prop) => isPropValid(prop) && !regex.test(prop));
export const shouldForwardDomProp: Fn<boolean> = createShouldForwardDomProp();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment