react-cm-ui
Version:
React UI for Healthy Church
402 lines (374 loc) • 12.5 kB
JSX
import {
reduce,
} from 'lodash';
import ClassNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import {
BEM_GRID,
BEM_GRID_COLUMN,
UI_CLASS_NAME,
} from '../../global/constants';
import {
GRID_SIZES,
} from './gridConstants';
import makeStyles from '../../styles/makeStyles';
const propTypes = {
/**
* The content of the GridColumn
*/
children: PropTypes.node,
/**
* Override or extend the styles applied to the component.
*/
classes: PropTypes.shape({
root: PropTypes.string,
}),
/**
* Assign additional class names to GridColumn.
*/
className: PropTypes.string,
/**
* Used for DOM testing. https://testing-library.com/docs/queries/bytestid/
*/
dataTestId: PropTypes.string,
/**
* The `id` of the GridColumn.
*/
id: PropTypes.string,
/**
* Defines the number of columns the component is going to use.
* It's applied for the `lg` breakpoint and wider screens if not overridden.
*/
lg: PropTypes.oneOfType([
PropTypes.oneOf(['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
PropTypes.bool,
]),
/**
* Defines the number of columns the component is going to use.
* It's applied for the `md` breakpoint and wider screens if not overridden.
*/
md: PropTypes.oneOfType([
PropTypes.oneOf(['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
PropTypes.bool,
]),
/**
* Defines the number of columns the component is going to use.
* It's applied for the `sm` breakpoint and wider screens if not overridden.
*/
sm: PropTypes.oneOfType([
PropTypes.oneOf(['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
PropTypes.bool,
]),
/**
* Defines the number of columns the component is going to use.
* It's applied for the `xl` breakpoint and wider screens if not overridden.
*/
xl: PropTypes.oneOfType([
PropTypes.oneOf(['auto', true, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
PropTypes.bool,
]),
// ****
// NOTE: All props below are deprecated and should not be used.
// ****
/**
* Deprecated prop. Please use `classes` to override styles.
*/
align: PropTypes.oneOf(['stretch']),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
desktop: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
desktopLarge: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
fieldType: PropTypes.oneOf(['checkbox', 'legend', 'radio']),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
floated: PropTypes.oneOf(['left', 'right']),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
laptop: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
mobile: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
mobileLarge: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
mobileMedium: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
style: PropTypes.shape({}),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
tablet: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
textAlign: PropTypes.oneOf(['center', 'left', 'right']),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
verticalAlign: PropTypes.oneOf(['bottom', 'middle', 'top']),
/**
* Deprecated prop. Please use `classes` to override styles.
*/
width: PropTypes.oneOf(['auto', true, false, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
};
const defaultProps = {
classes: null,
children: null,
className: null,
dataTestId: `${UI_CLASS_NAME}-${BEM_GRID}_column`,
id: null,
lg: false,
md: false,
sm: false,
xl: false,
// ****
// NOTE: All props below are deprecated and should not be used.
// ****
align: undefined,
desktop: false,
desktopLarge: false,
fieldType: undefined,
floated: undefined,
laptop: false,
mobile: false,
mobileLarge: false,
mobileMedium: false,
style: null,
tablet: false,
textAlign: undefined,
verticalAlign: undefined,
width: false,
};
const generateGrid = (globalStyles, theme, breakpoint) => {
const styles = {};
GRID_SIZES.forEach((size) => {
const key = `${BEM_GRID_COLUMN}-${breakpoint}-${size}`;
const width = `${Math.round((size / 12) * 10e7) / 10e5}%`;
if (
breakpoint === 'mobile' ||
breakpoint === 'mobile-medium' ||
breakpoint === 'mobile-large' ||
breakpoint === 'tablet' ||
breakpoint === 'laptop' ||
breakpoint === 'desktop' ||
breakpoint === 'desktop-large'
) {
styles[key] = {
flexBasis: width,
maxWidth: width,
width,
};
return;
}
if (size === true) {
// For the auto layouting
styles[key] = {
flexBasis: 0,
flexGrow: 1,
maxWidth: '100%',
};
return;
}
if (size === 'auto') {
styles[key] = {
flexBasis: 'auto',
flexGrow: 0,
maxWidth: 'none',
};
return;
}
styles[key] = {
flexBasis: width,
flexGrow: 0,
maxWidth: width,
};
});
switch (breakpoint) {
/* eslint-disable no-param-reassign */
case 'mobile':
globalStyles[theme.breakpoints.down(374)] = styles;
break;
case 'mobile-medium':
globalStyles[theme.breakpoints.up(375)] = styles;
break;
case 'mobile-large':
globalStyles[theme.breakpoints.up(425)] = styles;
break;
case 'laptop':
globalStyles[theme.breakpoints.up(1024)] = styles;
break;
case 'desktop':
globalStyles[theme.breakpoints.up(1440)] = styles;
break;
case 'desktop-large':
globalStyles[theme.breakpoints.up(1720)] = styles;
break;
case 'sm':
Object.assign(globalStyles, styles);
break;
default:
globalStyles[theme.breakpoints.up(breakpoint)] = styles;
/* eslint-enable no-param-reassign */
}
};
const useStyles = makeStyles((theme) => ({
root: {
margin: 0,
/**
* Deprecated classses
*/
'&$deprecatedAlignStretch': {
alignSelf: 'stretch',
},
'&deprecatedFloatedLeft': {
marginRight: 'auto',
},
'&$deprecatedFloatedRight': {
marginLeft: 'auto',
},
'&$deprecatedTextAlignCenter': {
textAlign: 'center',
},
'&$deprecatedTextAlignLeft': {
textAlign: 'left',
},
'&$deprecatedTextAlignRight': {
textAlign: 'right',
},
'&$deprecatedVerticalAlignBottom': {
alignItems: 'bottom',
display: 'flex',
},
'&$deprecatedVerticalAlignCenter': {
alignItems: 'center',
display: 'flex',
},
'&$deprecatedVerticalAlignTop': {
alignItems: 'top',
display: 'flex',
},
/**
* End of deprecated classes
*/
},
/**
* Deprecated classses
*/
deprecatedAlignStretch: {},
deprecatedFloatedLeft: {},
deprecatedFloatedRight: {},
deprecatedTextAlignCenter: {},
deprecatedTextAlignLeft: {},
deprecatedTextAlignRight: {},
deprecatedVerticalAlignBottom: {},
deprecatedVerticalAlignCenter: {},
deprecatedVerticalAlignTop: {},
/**
* End of deprecated classes
*/
...reduce([
...theme.breakpoints.keys,
'mobile',
'mobile-medium',
'mobile-large',
'laptop',
'desktop',
'desktop-large',
], (accumulator, key) => {
generateGrid(accumulator, theme, key);
return accumulator;
}, {}),
}));
const GridColumn = React.forwardRef(
/* eslint-disable react-hooks/rules-of-hooks */
// eslint-disable-next-line prefer-arrow-callback
function GridColumn(props, ref) {
const {
children,
className,
dataTestId,
id,
lg,
md,
sm,
style,
xl,
...otherProps
} = props;
const classes = useStyles(props);
const rootClasses = ClassNames(
UI_CLASS_NAME,
BEM_GRID_COLUMN,
classes.root,
className,
{
[classes[`${BEM_GRID_COLUMN}-sm-${String(sm || otherProps.width)}`]]:
sm !== false || otherProps.width !== false,
/**
* `otherProps.tablet` is a deprecated prop. It is using the same breakpoint (768)
* as `md`, so we're combining in order to have less JSS.
*/
[classes[`${BEM_GRID_COLUMN}-md-${String(md || otherProps.tablet)}`]]:
md !== false || otherProps.tablet !== false,
[classes[`${BEM_GRID_COLUMN}-lg-${String(lg)}`]]: lg !== false,
[classes[`${BEM_GRID_COLUMN}-xl-${String(xl)}`]]: xl !== false,
/**
* Deprecated classes below
*/
[classes[`${BEM_GRID_COLUMN}-mobile-${String(otherProps.mobile)}`]]:
otherProps.mobile !== false,
[classes[`${BEM_GRID_COLUMN}-mobile-medium-${String(otherProps.mobileMedium)}`]]:
otherProps.mobileMedium !== false,
[classes[`${BEM_GRID_COLUMN}-mobile-large-${String(otherProps.mobileLarge)}`]]:
otherProps.mobileLarge !== false,
[classes[`${BEM_GRID_COLUMN}-laptop-${String(otherProps.laptop)}`]]:
otherProps.laptop !== false,
[classes[`${BEM_GRID_COLUMN}-desktop-${String(otherProps.desktop)}`]]:
otherProps.desktop !== false,
[classes[`${BEM_GRID_COLUMN}-desktop-large-${String(otherProps.desktopLarge)}`]]:
otherProps.desktopLarge !== false,
[classes.deprecatedAlignStretch]: otherProps.align === 'stretch',
[classes.deprecatedFloatedLeft]: otherProps.floated === 'left',
[classes.deprecatedFloatedRight]: otherProps.floated === 'right',
[classes.deprecatedTextAlignCenter]: otherProps.textAlign === 'center',
[classes.deprecatedTextAlignLeft]: otherProps.textAlign === 'left',
[classes.deprecatedTextAlignRight]: otherProps.textAlign === 'right',
[classes.deprecatedVerticalAlignBottom]: otherProps.verticalAlign === 'bottom',
[classes.deprecatedVerticalAlignCenter]: otherProps.verticalAlign === 'center',
[classes.deprecatedVerticalAlignTop]: otherProps.verticalAlign === 'top',
},
);
return (
<div
className={rootClasses}
data-testid={dataTestId}
id={id}
ref={ref}
style={style}
>
{children}
</div>
);
},
/* eslint-enable react-hooks/rules-of-hooks */
);
GridColumn.propTypes = propTypes;
GridColumn.defaultProps = defaultProps;
export default GridColumn;