From d2283518f2773dc5f75833480ee8b778a96f70a2 Mon Sep 17 00:00:00 2001
From: duganbrett <44508924+duganbrett@users.noreply.github.com>
Date: Thu, 28 Jan 2021 00:34:29 -0700
Subject: [PATCH] [TextField] Migrate FormControl to emotion (#24659)
---
docs/pages/api-docs/form-control.json | 3 +-
.../api-docs/form-control/form-control.json | 1 +
.../src/FormControl/FormControl.d.ts | 6 +
.../src/FormControl/FormControl.js | 111 ++++++++++++------
.../src/FormControl/FormControl.test.js | 13 +-
.../src/FormControl/formControlClasses.d.ts | 13 ++
.../src/FormControl/formControlClasses.js | 15 +++
7 files changed, 117 insertions(+), 45 deletions(-)
create mode 100644 packages/material-ui/src/FormControl/formControlClasses.d.ts
create mode 100644 packages/material-ui/src/FormControl/formControlClasses.js
diff --git a/docs/pages/api-docs/form-control.json b/docs/pages/api-docs/form-control.json
index 7b1ab4edb661be..4c59fe8ea36f4b 100644
--- a/docs/pages/api-docs/form-control.json
+++ b/docs/pages/api-docs/form-control.json
@@ -24,6 +24,7 @@
"type": { "name": "enum", "description": "'medium'
| 'small'" },
"default": "'medium'"
},
+ "sx": { "type": { "name": "object" } },
"variant": {
"type": {
"name": "enum",
@@ -43,6 +44,6 @@
"filename": "/packages/material-ui/src/FormControl/FormControl.js",
"inheritance": null,
"demos": "
",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/translations/api-docs/form-control/form-control.json b/docs/translations/api-docs/form-control/form-control.json
index 02575bd9d30a5e..885343fdeabe7b 100644
--- a/docs/translations/api-docs/form-control/form-control.json
+++ b/docs/translations/api-docs/form-control/form-control.json
@@ -13,6 +13,7 @@
"margin": "If dense
or normal
, will adjust vertical spacing of this and contained components.",
"required": "If true
, the label will indicate that the input
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 `sx` page for more details.",
"variant": "The variant to use."
},
"classDescriptions": {
diff --git a/packages/material-ui/src/FormControl/FormControl.d.ts b/packages/material-ui/src/FormControl/FormControl.d.ts
index 7956c4371a44ca..b51b2ceb62282d 100644
--- a/packages/material-ui/src/FormControl/FormControl.d.ts
+++ b/packages/material-ui/src/FormControl/FormControl.d.ts
@@ -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 {
props: P & {
@@ -66,6 +68,10 @@ export interface FormControlTypeMap
* @default 'medium'
*/
size?: 'small' | 'medium';
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx?: SxProps;
/**
* The variant to use.
* @default 'standard'
diff --git a/packages/material-ui/src/FormControl/FormControl.js b/packages/material-ui/src/FormControl/FormControl.js
index 5a7c8d60f25c7a..e0da18ccfcd497 100644
--- a/packages/material-ui/src/FormControl/FormControl.js
+++ b/packages/material-ui/src/FormControl/FormControl.js
@@ -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.
@@ -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,
@@ -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.
@@ -182,20 +220,15 @@ const FormControl = React.forwardRef(function FormControl(props, ref) {
return (
-
{children}
-
+
);
});
@@ -268,6 +301,10 @@ 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'
@@ -275,4 +312,4 @@ FormControl.propTypes = {
variant: PropTypes.oneOf(['filled', 'outlined', 'standard']),
};
-export default withStyles(styles, { name: 'MuiFormControl' })(FormControl);
+export default FormControl;
diff --git a/packages/material-ui/src/FormControl/FormControl.test.js b/packages/material-ui/src/FormControl/FormControl.test.js
index 952186260e5bd3..04f7eec0fafdd0 100644
--- a/packages/material-ui/src/FormControl/FormControl.test.js
+++ b/packages/material-ui/src/FormControl/FormControl.test.js
@@ -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('', () => {
const mount = createMount();
const render = createClientRender();
- let classes;
function TestComponent(props) {
const context = useFormControl();
@@ -20,16 +20,15 @@ describe('', () => {
return null;
}
- before(() => {
- classes = getClasses();
- });
-
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: 'div',
mount,
refInstanceof: window.HTMLDivElement,
testComponentPropWith: 'fieldset',
+ muiName: 'MuiFormControl',
+ testVariantProps: { margin: 'dense' },
+ skip: ['componentsProp'],
}));
describe('initial state', () => {
diff --git a/packages/material-ui/src/FormControl/formControlClasses.d.ts b/packages/material-ui/src/FormControl/formControlClasses.d.ts
new file mode 100644
index 00000000000000..b081c8840a02df
--- /dev/null
+++ b/packages/material-ui/src/FormControl/formControlClasses.d.ts
@@ -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;
diff --git a/packages/material-ui/src/FormControl/formControlClasses.js b/packages/material-ui/src/FormControl/formControlClasses.js
new file mode 100644
index 00000000000000..afd2e623acd5ba
--- /dev/null
+++ b/packages/material-ui/src/FormControl/formControlClasses.js
@@ -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;