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 FormControl to emotion #24659

Merged
merged 7 commits into from
Jan 28, 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/form-control.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"type": { "name": "enum", "description": "'medium'<br>&#124;&nbsp;'small'" },
"default": "'medium'"
},
"sx": { "type": { "name": "object" } },
"variant": {
"type": {
"name": "enum",
Expand All @@ -43,6 +44,6 @@
"filename": "/packages/material-ui/src/FormControl/FormControl.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>\n<li><a href=\"/components/text-fields/\">Text Fields</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
1 change: 1 addition & 0 deletions docs/translations/api-docs/form-control/form-control.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"margin": "If <code>dense</code> or <code>normal</code>, will adjust vertical spacing of this and contained components.",
"required": "If <code>true</code>, the label will indicate that the <code>input</code> is required.",
"size": "The size of the component.",
"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.",
"variant": "The variant to use."
},
"classDescriptions": {
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/FormControl/FormControl.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as React from 'react';
import { SxProps } from '@material-ui/system';
import { OverridableComponent, OverrideProps } from '../OverridableComponent';
import { Theme } from '../styles';

export interface FormControlTypeMap<P = {}, D extends React.ElementType = 'div'> {
props: P & {
Expand Down Expand Up @@ -66,6 +68,10 @@ export interface FormControlTypeMap<P = {}, D extends React.ElementType = 'div'>
* @default 'medium'
*/
size?: 'small' | 'medium';
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* The variant to use.
* @default 'standard'
Expand Down
109 changes: 73 additions & 36 deletions packages/material-ui/src/FormControl/FormControl.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,62 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { deepmerge } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import useThemeProps from '../styles/useThemeProps';
import experimentalStyled from '../styles/experimentalStyled';
import { isFilled, isAdornedStart } from '../InputBase/utils';
import withStyles from '../styles/withStyles';
import capitalize from '../utils/capitalize';
import isMuiElement from '../utils/isMuiElement';
import FormControlContext from './FormControlContext';
import { getFormControlUtilityClasses } from './formControlClasses';

export const styles = {
/* Styles applied to the root element. */
root: {
display: 'inline-flex',
flexDirection: 'column',
position: 'relative',
// Reset fieldset default style.
minWidth: 0,
padding: 0,
margin: 0,
border: 0,
verticalAlign: 'top', // Fix alignment issue on Safari.
const overridesResolver = ({ styleProps }, styles) => {
return deepmerge(styles.root || {}, {
...styles[`margin${capitalize(styleProps.margin)}`],
...(styleProps.fullWidth && styles.fullWidth),
});
};

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

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

const FormControlRoot = experimentalStyled(
'div',
{},
{
name: 'MuiFormControl',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the root element if `margin="normal"`. */
marginNormal: {
)(({ styleProps }) => ({
display: 'inline-flex',
flexDirection: 'column',
position: 'relative',
// Reset fieldset default style.
minWidth: 0,
padding: 0,
margin: 0,
border: 0,
verticalAlign: 'top', // Fix alignment issue on Safari.
...(styleProps.margin === 'normal' && {
marginTop: 16,
marginBottom: 8,
},
/* Styles applied to the root element if `margin="dense"`. */
marginDense: {
}),
...(styleProps.margin === 'dense' && {
marginTop: 8,
marginBottom: 4,
},
/* Styles applied to the root element if `fullWidth={true}`. */
fullWidth: {
}),
...(styleProps.fullWidth && {
width: '100%',
},
};
}),
}));

/**
* Provides context such as filled/focused/error/required for form inputs.
Expand All @@ -60,10 +82,10 @@ export const styles = {
* ⚠️ Only one `InputBase` can be used within a FormControl because it create visual inconsistencies.
* For instance, only one input can be focused at the same time, the state shouldn't be shared.
*/
const FormControl = React.forwardRef(function FormControl(props, ref) {
const FormControl = React.forwardRef(function FormControl(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiFormControl' });
const {
children,
classes,
className,
color = 'primary',
component: Component = 'div',
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -79,6 +101,22 @@ const FormControl = React.forwardRef(function FormControl(props, ref) {
...other
} = props;

const styleProps = {
...props,
color,
component,
disabled,
error,
fullWidth,
hiddenLabel,
margin,
required,
size,
variant,
};

const classes = useUtilityClasses(styleProps);

const [adornedStart, setAdornedStart] = React.useState(() => {
// We need to iterate through the children and find the Input in order
// to fully support server-side rendering.
Expand Down Expand Up @@ -182,20 +220,15 @@ const FormControl = React.forwardRef(function FormControl(props, ref) {

return (
<FormControlContext.Provider value={childContext}>
<Component
className={clsx(
classes.root,
{
[classes[`margin${capitalize(margin)}`]]: margin !== 'none',
[classes.fullWidth]: fullWidth,
},
className,
)}
<FormControlRoot
as={Component}
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
styleProps={styleProps}
className={clsx(classes.root, className)}
ref={ref}
{...other}
>
{children}
</Component>
</FormControlRoot>
</FormControlContext.Provider>
);
});
Expand Down Expand Up @@ -268,11 +301,15 @@ FormControl.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 variant to use.
* @default 'standard'
*/
variant: PropTypes.oneOf(['filled', 'outlined', 'standard']),
};

export default withStyles(styles, { name: 'MuiFormControl' })(FormControl);
export default FormControl;
13 changes: 6 additions & 7 deletions packages/material-ui/src/FormControl/FormControl.test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
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 Input from '../Input';
import Select from '../Select';
import FormControl from './FormControl';
import useFormControl from './useFormControl';
import classes from './formControlClasses';

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

function TestComponent(props) {
const context = useFormControl();
Expand All @@ -20,16 +20,15 @@ describe('<FormControl />', () => {
return null;
}

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

describeConformance(<FormControl />, () => ({
describeConformanceV5(<FormControl />, () => ({
classes,
inheritComponent: 'div',
mount,
refInstanceof: window.HTMLDivElement,
testComponentPropWith: 'fieldset',
muiName: 'MuiFormControl',
testVariantProps: { margin: 'dense' },
skip: ['componentsProp'],
}));

describe('initial state', () => {
Expand Down
13 changes: 13 additions & 0 deletions packages/material-ui/src/FormControl/formControlClasses.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export interface FormControlClasses {
root: string;
marginNone: string;
marginNormal: string;
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
marginDense: string;
fullWidth: string;
}

declare const formControlClasses: FormControlClasses;

export function getFormControlUtilityClasses(slot: string): string;

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

export function getFormControlUtilityClasses(slot) {
return generateUtilityClass('MuiFormControl', slot);
}

const formControlClasses = generateUtilityClasses('MuiFormControl', [
'root',
'marginNone',
'marginNormal',
mnajdova marked this conversation as resolved.
Show resolved Hide resolved
'marginDense',
'fullWidth',
]);

export default formControlClasses;