Skip to content

Commit

Permalink
[TextField] Migrate FormControl to emotion (mui#24659)
Browse files Browse the repository at this point in the history
  • Loading branch information
duganbrett authored and natac13 committed Jan 30, 2021
1 parent 5078260 commit f7a9bc6
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 45 deletions.
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
111 changes: 74 additions & 37 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,13 +82,13 @@ 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',
component = 'div',
disabled = false,
error = false,
focused: visuallyFocused,
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}
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;
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',
'marginDense',
'fullWidth',
]);

export default formControlClasses;

0 comments on commit f7a9bc6

Please sign in to comment.