Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Checkbox] Migrate to emotion #24702

Merged
merged 10 commits into from
Feb 9, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/pages/api-docs/checkbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"type": { "name": "enum", "description": "'medium'<br>&#124;&nbsp;'small'" },
"default": "'medium'"
},
"sx": { "type": { "name": "object" } },
"value": { "type": { "name": "any" } }
},
"name": "Checkbox",
Expand All @@ -38,6 +39,6 @@
"filename": "/packages/material-ui/src/Checkbox/Checkbox.js",
"inheritance": { "component": "IconButton", "pathname": "/api/icon-button/" },
"demos": "<ul><li><a href=\"/components/checkboxes/\">Checkboxes</a></li>\n<li><a href=\"/components/transfer-list/\">Transfer List</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
1 change: 1 addition & 0 deletions docs/translations/api-docs/checkbox/checkbox.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"onChange": "Callback fired when the state is changed.<br><br><strong>Signature:</strong><br><code>function(event: object) =&gt; void</code><br><em>event:</em> The event source of the callback. You can pull out the new checked state by accessing <code>event.target.checked</code> (boolean).",
"required": "If <code>true</code>, the <code>input</code> element is required.",
"size": "The size of the component. <code>small</code> is equivalent to the dense checkbox styling.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/basics/#the-sx-prop\">`sx` page</a> for more details.",
"value": "The value of the component. The DOM API casts this to a string. The browser uses &quot;on&quot; as the default value."
},
"classDescriptions": {
Expand Down
1 change: 1 addition & 0 deletions framer/scripts/framerConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export const componentSettings = {
'indeterminateIcon',
'onChange',
'required',
'sx',
'type',
'value',
],
Expand Down
7 changes: 6 additions & 1 deletion packages/material-ui/src/Checkbox/Checkbox.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SxProps } from '@material-ui/system';
import * as React from 'react';
import { InternalStandardProps as StandardProps } from '..';
import { InternalStandardProps as StandardProps, Theme } from '..';
import { SwitchBaseProps } from '../internal/SwitchBase';

export interface CheckboxProps
Expand Down Expand Up @@ -90,6 +91,10 @@ export interface CheckboxProps
* @default 'medium'
*/
size?: 'small' | 'medium';
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* The value of the component. The DOM API casts this to a string.
* The browser uses "on" as the default value.
Expand Down
119 changes: 71 additions & 48 deletions packages/material-ui/src/Checkbox/Checkbox.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,83 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { refType } from '@material-ui/utils';
import { refType, deepmerge } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import SwitchBase from '../internal/SwitchBase';
import CheckBoxOutlineBlankIcon from '../internal/svg-icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '../internal/svg-icons/CheckBox';
import { alpha } from '../styles/colorManipulator';
import IndeterminateCheckBoxIcon from '../internal/svg-icons/IndeterminateCheckBox';
import capitalize from '../utils/capitalize';
import withStyles from '../styles/withStyles';

export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
color: theme.palette.text.secondary,
},
/* Pseudo-class applied to the root element if `checked={true}`. */
checked: {},
/* Pseudo-class applied to the root element if `disabled={true}`. */
disabled: {},
/* Pseudo-class applied to the root element if `indeterminate={true}`. */
indeterminate: {},
/* Styles applied to the root element if `color="primary"`. */
colorPrimary: {
'&$checked, &$indeterminate': {
color: theme.palette.primary.main,
'&:hover': {
backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.hoverOpacity),
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
'&$disabled': {
color: theme.palette.action.disabled,
},
import useThemeProps from '../styles/useThemeProps';
import experimentalStyled from '../styles/experimentalStyled';
import checkboxClasses, { getCheckboxUtilityClass } from './checkboxClasses';

const overridesResolver = (props, styles) => {
const { styleProps } = props;

return deepmerge(styles.root || {}, {
...(styleProps.indeterminate && styles.indeterminate),
...(styleProps.color !== 'default' && styles[`color${capitalize(styleProps.color)}`]),
});
};

const useUtilityClasses = (styleProps) => {
const { classes, disabled, checked, indeterminate, color } = styleProps;

const slots = {
root: [
'root',
checked && 'checked',
disabled && 'disabled',
indeterminate && 'indeterminate',
`color${capitalize(color)}`,
],
};

return composeClasses(slots, getCheckboxUtilityClass, classes);
};

const CheckboxRoot = experimentalStyled(
SwitchBase,
{},
{
name: 'MuiCheckbox',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the root element if `color="secondary"`. */
colorSecondary: {
'&$checked, &$indeterminate': {
color: theme.palette.secondary.main,
)(({ theme, styleProps }) => ({
/* Styles applied to the root element. */
color: theme.palette.text.secondary,
/* Styles applied to the root element unless `color="default"`. */
...(styleProps.color !== 'default' && {
[`&.Mui-checked, &.${checkboxClasses.indeterminate}`]: {
color: theme.palette[styleProps.color].main,
'&:hover': {
backgroundColor: alpha(theme.palette.secondary.main, theme.palette.action.hoverOpacity),
backgroundColor: alpha(
theme.palette[styleProps.color].main,
theme.palette.action.hoverOpacity,
),
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
'&$disabled': {
'&.Mui-disabled': {
color: theme.palette.action.disabled,
},
},
});
}),
}));

const defaultCheckedIcon = <CheckBoxIcon />;
const defaultIcon = <CheckBoxOutlineBlankIcon />;
const defaultIndeterminateIcon = <IndeterminateCheckBoxIcon />;

const Checkbox = React.forwardRef(function Checkbox(props, ref) {
const Checkbox = React.forwardRef(function Checkbox(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiCheckbox' });
const {
checkedIcon = defaultCheckedIcon,
classes,
color = 'secondary',
icon: iconProp = defaultIcon,
indeterminate = false,
Expand All @@ -75,16 +90,19 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
const icon = indeterminate ? indeterminateIconProp : iconProp;
const indeterminateIcon = indeterminate ? indeterminateIconProp : checkedIcon;

const styleProps = {
...props,
color,
indeterminate,
size,
};

const classes = useUtilityClasses(styleProps);

return (
<SwitchBase
<CheckboxRoot
type="checkbox"
classes={{
root: clsx(classes.root, classes[`color${capitalize(color)}`], {
[classes.indeterminate]: indeterminate,
}),
checked: classes.checked,
disabled: classes.disabled,
}}
className={classes.root}
color={color}
inputProps={{
'data-indeterminate': indeterminate,
Expand All @@ -100,6 +118,7 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
? size
: indeterminateIcon.props.fontSize,
})}
styleProps={styleProps}
ref={ref}
{...other}
/>
Expand Down Expand Up @@ -188,11 +207,15 @@ Checkbox.propTypes = {
* @default 'medium'
*/
size: PropTypes.oneOf(['medium', 'small']),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The value of the component. The DOM API casts this to a string.
* The browser uses "on" as the default value.
*/
value: PropTypes.any,
};

export default withStyles(styles, { name: 'MuiCheckbox' })(Checkbox);
export default Checkbox;
15 changes: 7 additions & 8 deletions packages/material-ui/src/Checkbox/Checkbox.test.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { getClasses, createMount, describeConformance, act, createClientRender } from 'test/utils';
import { createMount, describeConformanceV5, act, createClientRender } from 'test/utils';
import Checkbox from './Checkbox';
import FormControl from '../FormControl';
import IconButton from '../IconButton';
import classes from './checkboxClasses';

describe('<Checkbox />', () => {
const render = createClientRender();
let classes;
const mount = createMount();

before(() => {
classes = getClasses(<Checkbox />);
});

describeConformance(<Checkbox checked />, () => ({
describeConformanceV5(<Checkbox checked />, () => ({
classes,
inheritComponent: IconButton,
mount,
muiName: 'MuiCheckbox',
testVariantProps: { variant: 'foo' },
testStateOverrides: { prop: 'color', value: 'secondary', styleKey: classes.colorSecondary },
refInstanceof: window.HTMLSpanElement,
skip: ['componentProp'],
skip: ['componentProp', 'componentsProp', 'rootClass'],
}));

it('should have the classes required for Checkbox', () => {
Expand Down
7 changes: 7 additions & 0 deletions packages/material-ui/src/Checkbox/checkboxClasses.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { CheckboxClassKey } from './Checkbox';

declare const checkboxClasses: Record<CheckboxClassKey, string>;

export function getCheckboxUtilityClass(slot: string): string;

export default checkboxClasses;
16 changes: 16 additions & 0 deletions packages/material-ui/src/Checkbox/checkboxClasses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';

export function getCheckboxUtilityClass(slot) {
return generateUtilityClass('MuiCheckbox', slot);
}

const checkboxClasses = generateUtilityClasses('MuiCheckbox', [
'root',
'checked',
'disabled',
'indeterminate',
'colorPrimary',
'colorSecondary',
]);

export default checkboxClasses;
3 changes: 3 additions & 0 deletions packages/material-ui/src/Checkbox/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export { default } from './Checkbox';
export * from './Checkbox';

export { default as checkboxClasses } from './checkboxClasses';
export * from './checkboxClasses';
3 changes: 3 additions & 0 deletions packages/material-ui/src/Checkbox/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { default } from './Checkbox';

export { default as checkboxClasses } from './checkboxClasses';
export * from './checkboxClasses';