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

[TextField] Migrate FormControlLabel to emotion #25007

Merged
merged 18 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from all 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/form-control-label.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"default": "'end'"
},
"onChange": { "type": { "name": "func" } },
"sx": { "type": { "name": "object" } },
"value": { "type": { "name": "any" } }
},
"name": "FormControlLabel",
Expand All @@ -34,6 +35,6 @@
"filename": "/packages/material-ui/src/FormControlLabel/FormControlLabel.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/checkboxes/\">Checkboxes</a></li>\n<li><a href=\"/components/radio-buttons/\">Radio Buttons</a></li>\n<li><a href=\"/components/switches/\">Switches</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"label": "The text to be used in an enclosing label element.",
"labelPlacement": "The position of the label.",
"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).",
"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."
},
"classDescriptions": {
Expand Down
3 changes: 1 addition & 2 deletions packages/material-ui/src/FormControl/FormControl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { createMount, describeConformanceV5, act, createClientRender } from 'test/utils';
import FormControl, { formControlClasses as classes } from '@material-ui/core/FormControl';
import Input from '../Input';
import Select from '../Select';
import FormControl from './FormControl';
import useFormControl from './useFormControl';
import classes from './formControlClasses';

describe('<FormControl />', () => {
const mount = createMount();
Expand Down
4 changes: 4 additions & 0 deletions packages/material-ui/src/FormControl/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export { default } from './FormControl';
export * from './FormControl';

export { default as useFormControl, FormControlState } from './useFormControl';

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

export { default as formControlClasses } from './formControlClasses';
export * from './formControlClasses';
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { InternalStandardProps as StandardProps } from '..';
import { SxProps } from '@material-ui/system';
import { Theme, InternalStandardProps as StandardProps } from '..';

export interface FormControlLabelProps
extends StandardProps<React.LabelHTMLAttributes<HTMLLabelElement>, 'children' | 'onChange'> {
Expand Down Expand Up @@ -53,6 +54,10 @@ export interface FormControlLabelProps
* You can pull out the new checked state by accessing `event.target.checked` (boolean).
*/
onChange?: (event: React.SyntheticEvent, checked: boolean) => void;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* The value of the component.
*/
Expand Down
120 changes: 72 additions & 48 deletions packages/material-ui/src/FormControlLabel/FormControlLabel.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,80 @@
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 { useFormControl } from '../FormControl';
import withStyles from '../styles/withStyles';
import Typography from '../Typography';
import capitalize from '../utils/capitalize';
import experimentalStyled from '../styles/experimentalStyled';
import useThemeProps from '../styles/useThemeProps';
import formControlLabelClasses, {
getFormControlLabelUtilityClasses,
} from './formControlLabelClasses';

export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
display: 'inline-flex',
alignItems: 'center',
cursor: 'pointer',
// For correct alignment with the text.
verticalAlign: 'middle',
WebkitTapHighlightColor: 'transparent',
marginLeft: -11,
marginRight: 16, // used for row presentation of radio/checkbox
'&$disabled': {
cursor: 'default',
},
const overridesResolver = (props, styles) => {
const { styleProps } = props;

return deepmerge(styles.root || {}, {
...styles[`labelPlacement${capitalize(styleProps.labelPlacement)}`],
[`& .${formControlLabelClasses.label}`]: styles.label,
});
};

const useUtilityClasses = (styleProps) => {
const { classes, disabled, labelPlacement } = styleProps;
const slots = {
root: ['root', disabled && 'disabled', `labelPlacement${capitalize(labelPlacement)}`],
label: ['label', disabled && 'disabled'],
};

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

export const FormControlLabelRoot = experimentalStyled(
'label',
{},
{ name: 'MuiFormControlLabel', slot: 'Root', overridesResolver },
)(({ theme, styleProps }) => ({
display: 'inline-flex',
alignItems: 'center',
cursor: 'pointer',
// For correct alignment with the text.
verticalAlign: 'middle',
WebkitTapHighlightColor: 'transparent',
marginLeft: -11,
marginRight: 16, // used for row presentation of radio/checkbox
'&.Mui-disabled': {
cursor: 'default',
},
/* Styles applied to the root element if `labelPlacement="start"`. */
labelPlacementStart: {
...(styleProps.labelPlacement === 'start' && {
flexDirection: 'row-reverse',
marginLeft: 16, // used for row presentation of radio/checkbox
marginRight: -11,
},
/* Styles applied to the root element if `labelPlacement="top"`. */
labelPlacementTop: {
}),
...(styleProps.labelPlacement === 'top' && {
flexDirection: 'column-reverse',
marginLeft: 16,
},
/* Styles applied to the root element if `labelPlacement="bottom"`. */
labelPlacementBottom: {
}),
...(styleProps.labelPlacement === 'bottom' && {
flexDirection: 'column',
marginLeft: 16,
},
/* Pseudo-class applied to the root element if `disabled={true}`. */
disabled: {},
/* Styles applied to the label's Typography component. */
label: {
'&$disabled': {
}),
[`& .${formControlLabelClasses.label}`]: {
'&.Mui-disabled': {
color: theme.palette.text.disabled,
},
},
});
}));

/**
* Drop-in replacement of the `Radio`, `Switch` and `Checkbox` component.
* Use this component if you want to display an extra label.
*/
const FormControlLabel = React.forwardRef(function FormControlLabel(props, ref) {
const FormControlLabel = React.forwardRef(function FormControlLabel(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiFormControlLabel' });
const {
checked,
classes,
className,
control,
disabled: disabledProp,
Expand All @@ -67,6 +86,7 @@ const FormControlLabel = React.forwardRef(function FormControlLabel(props, ref)
value,
...other
} = props;

const muiFormControl = useFormControl();

let disabled = disabledProp;
Expand All @@ -87,27 +107,27 @@ const FormControlLabel = React.forwardRef(function FormControlLabel(props, ref)
}
});

const styleProps = {
...props,
disabled,
label,
labelPlacement,
};

const classes = useUtilityClasses(styleProps);

return (
<label
className={clsx(
classes.root,
{
[classes[`labelPlacement${capitalize(labelPlacement)}`]]: labelPlacement !== 'end',
[classes.disabled]: disabled,
},
className,
)}
<FormControlLabelRoot
className={clsx(classes.root, className)}
styleProps={styleProps}
ref={ref}
{...other}
>
{React.cloneElement(control, controlProps)}
<Typography
component="span"
className={clsx(classes.label, { [classes.disabled]: disabled })}
>
<Typography component="span" className={classes.label}>
{label}
</Typography>
</label>
</FormControlLabelRoot>
);
});

Expand Down Expand Up @@ -160,10 +180,14 @@ FormControlLabel.propTypes = {
* You can pull out the new checked state by accessing `event.target.checked` (boolean).
*/
onChange: PropTypes.func,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The value of the component.
*/
value: PropTypes.any,
};

export default withStyles(styles, { name: 'MuiFormControlLabel' })(FormControlLabel);
export default FormControlLabel;
24 changes: 12 additions & 12 deletions packages/material-ui/src/FormControlLabel/FormControlLabel.test.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import * as React from 'react';
import { expect } from 'chai';
import { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
import Checkbox from '../Checkbox';
import FormControlLabel from './FormControlLabel';
import FormControl from '../FormControl';
import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import FormControlLabel, {
formControlLabelClasses as classes,
} from '@material-ui/core/FormControlLabel';
import Checkbox from '@material-ui/core/Checkbox';
import FormControl from '@material-ui/core/FormControl';

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

before(() => {
classes = getClasses(<FormControlLabel label="Pizza" control={<div />} />);
});
const mount = createMount();

describeConformance(<FormControlLabel label="Pizza" control={<Checkbox />} />, () => ({
describeConformanceV5(<FormControlLabel label="Pizza" control={<Checkbox />} />, () => ({
classes,
inheritComponent: 'label',
render,
mount,
muiName: 'MuiFormControlLabel',
testVariantProps: { disabled: true },
refInstanceof: window.HTMLLabelElement,
skip: ['componentProp'],
skip: ['componentProp', 'componentsProp'],
}));

it('should render the label text inside an additional element', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { FormControlLabelClassKey } from './FormControlLabel';

export type FormControlLabelClasses = Record<FormControlLabelClassKey, string>;

declare const formControlLabelClasses: FormControlLabelClasses;

export function getFormControlLabelUtilityClasses(slot: string): string;

export default formControlLabelClasses;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { generateUtilityClasses, generateUtilityClass } from '@material-ui/unstyled';

export function getFormControlLabelUtilityClasses(slot) {
return generateUtilityClass('MuiFormControlLabel', slot);
}

const formControlLabelClasses = generateUtilityClasses('MuiFormControlLabel', [
'root',
'labelPlacementStart',
'labelPlacementTop',
'labelPlacementBottom',
'disabled',
'label',
]);

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

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

export { default as formControlLabelClasses } from './formControlLabelClasses';
export * from './formControlLabelClasses';
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import * as React from 'react';
import { expect } from 'chai';
import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import FormHelperText from './FormHelperText';
import FormHelperText, { formHelperTextClasses as classes } from '@material-ui/core/FormHelperText';
import FormControl from '../FormControl';
import classes from './formHelperTextClasses';

describe('<FormHelperText />', () => {
const mount = createMount();
Expand Down