Skip to content

Commit

Permalink
[TextField] Migrate InputAdornment to emotion (#25279)
Browse files Browse the repository at this point in the history
  • Loading branch information
kayuapi committed Mar 14, 2021
1 parent 89f610f commit 5be4cd9
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 63 deletions.
3 changes: 2 additions & 1 deletion docs/pages/api-docs/input-adornment.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"disablePointerEvents": { "type": { "name": "bool" } },
"disableTypography": { "type": { "name": "bool" } },
"position": { "type": { "name": "enum", "description": "'end'<br>&#124;&nbsp;'start'" } },
"sx": { "type": { "name": "object" } },
"variant": {
"type": {
"name": "enum",
Expand All @@ -32,6 +33,6 @@
"filename": "/packages/material-ui/src/InputAdornment/InputAdornment.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/text-fields/\">Text Fields</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"disablePointerEvents": "Disable pointer events on the root. This allows for the content of the adornment to focus the <code>input</code> on click.",
"disableTypography": "If children is a string then disable wrapping in a Typography component.",
"position": "The position this adornment should appear relative to the <code>Input</code>.",
"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. Note: If you are using the <code>TextField</code> component or the <code>FormControl</code> component you do not have to set this manually."
},
"classDescriptions": {
Expand Down
6 changes: 3 additions & 3 deletions packages/material-ui/src/ButtonGroup/ButtonGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {
children,
className,
color = 'primary',
component: Component = 'div',
component = 'div',
disabled = false,
disableElevation = false,
disableFocusRipple = false,
Expand All @@ -206,7 +206,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {
const styleProps = {
...props,
color,
component: Component,
component,
disabled,
disableElevation,
disableFocusRipple,
Expand All @@ -221,7 +221,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) {

return (
<ButtonGroupRoot
as={Component}
as={component}
role="group"
className={clsx(classes.root, className)}
ref={ref}
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/InputAdornment/InputAdornment.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 '..';

export interface InputAdornmentTypeMap<P = {}, D extends React.ElementType = 'div'> {
props: P & {
Expand Down Expand Up @@ -41,6 +43,10 @@ export interface InputAdornmentTypeMap<P = {}, D extends React.ElementType = 'di
* The position this adornment should appear relative to the `Input`.
*/
position?: 'start' | 'end';
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* The variant to use.
* Note: If you are using the `TextField` component or the `FormControl` component
Expand Down
132 changes: 86 additions & 46 deletions packages/material-ui/src/InputAdornment/InputAdornment.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,99 @@
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 capitalize from '../utils/capitalize';
import Typography from '../Typography';
import withStyles from '../styles/withStyles';
import FormControlContext, { useFormControl } from '../FormControl/FormControlContext';
import experimentalStyled from '../styles/experimentalStyled';
import inputAdornmentClasses, { getInputAdornmentUtilityClass } from './inputAdornmentClasses';
import useThemeProps from '../styles/useThemeProps';

export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
display: 'flex',
height: '0.01em', // Fix IE11 flexbox alignment. To remove at some point.
maxHeight: '2em',
alignItems: 'center',
whiteSpace: 'nowrap',
color: theme.palette.action.active,
const overridesResolver = (props, styles) => {
const { styleProps } = props;

return deepmerge(
{
...styles[`position${capitalize(styleProps.position)}`],
...(styleProps.disablePointerEvents === true && styles.disablePointerEvents),
...(styleProps.variant === 'filled' && styles.filled),
},
styles.root || {},
);
};

const useUtilityClasses = (styleProps) => {
const { classes, disablePointerEvents, position, variant } = styleProps;
const slots = {
root: [
'root',
disablePointerEvents && 'disablePointerEvents',
position && `position${capitalize(position)}`,
variant,
'hiddenLabel',
'sizeSmall',
],
};

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

const InputAdornmentRoot = experimentalStyled(
'div',
{},
{
name: 'MuiInputAdornment',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the root element if `variant="filled"`. */
filled: {
'&$positionStart:not($hiddenLabel)': {
)(({ theme, styleProps }) => ({
display: 'flex',
height: '0.01em', // Fix IE11 flexbox alignment. To remove at some point.
maxHeight: '2em',
alignItems: 'center',
whiteSpace: 'nowrap',
color: theme.palette.action.active,
...(styleProps.variant === 'filled' && {
// Styles applied to the root element if `variant="filled"`.
[`&.${inputAdornmentClasses.positionStart}&:not(.Mui-hiddenLabel)`]: {
marginTop: 16,
},
},
/* Styles applied to the root element if `position="start"`. */
positionStart: {
}),
...(styleProps.position === 'start' && {
// Styles applied to the root element if `position="start"`.
marginRight: 8,
},
/* Styles applied to the root element if `position="end"`. */
positionEnd: {
}),
...(styleProps.position === 'end' && {
// Styles applied to the root element if `position="end"`.
marginLeft: 8,
},
/* Styles applied to the root element if `disablePointerEvents={true}`. */
disablePointerEvents: {
}),
...(styleProps.disablePointerEvents === true && {
// Styles applied to the root element if `disablePointerEvents={true}`.
pointerEvents: 'none',
},
/* Styles applied if the adornment is used inside <FormControl hiddenLabel />. */
hiddenLabel: {},
/* Styles applied if the adornment is used inside <FormControl size="small" />. */
sizeSmall: {},
});
}),
}));

const InputAdornment = React.forwardRef(function InputAdornment(props, ref) {
const InputAdornment = React.forwardRef(function InputAdornment(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiInputAdornment' });
const {
children,
classes,
className,
component: Component = 'div',
component = 'div',
disablePointerEvents = false,
disableTypography = false,
position,
variant: variantProp,
...other
} = props;

const styleProps = {
...props,
disablePointerEvents,
position,
variant: variantProp,
};

const muiFormControl = useFormControl() || {};

let variant = variantProp;
Expand All @@ -68,23 +111,16 @@ const InputAdornment = React.forwardRef(function InputAdornment(props, ref) {

if (muiFormControl && !variant) {
variant = muiFormControl.variant;
styleProps.variant = variant;
}
const classes = useUtilityClasses(styleProps);

return (
<FormControlContext.Provider value={null}>
<Component
className={clsx(
classes.root,
{
[classes.filled]: variant === 'filled',
[classes.positionStart]: position === 'start',
[classes.positionEnd]: position === 'end',
[classes.disablePointerEvents]: disablePointerEvents,
[classes.sizeSmall]: muiFormControl.size === 'small',
[classes.hiddenLabel]: muiFormControl.hiddenLabel,
},
className,
)}
<InputAdornmentRoot
as={component}
styleProps={styleProps}
className={clsx(classes.root, className)}
ref={ref}
{...other}
>
Expand All @@ -101,7 +137,7 @@ const InputAdornment = React.forwardRef(function InputAdornment(props, ref) {
{children}
</React.Fragment>
)}
</Component>
</InputAdornmentRoot>
</FormControlContext.Provider>
);
});
Expand Down Expand Up @@ -143,6 +179,10 @@ InputAdornment.propTypes /* remove-proptypes */ = {
* The position this adornment should appear relative to the `Input`.
*/
position: PropTypes.oneOf(['end', 'start']),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The variant to use.
* Note: If you are using the `TextField` component or the `FormControl` component
Expand All @@ -151,4 +191,4 @@ InputAdornment.propTypes /* remove-proptypes */ = {
variant: PropTypes.oneOf(['filled', 'outlined', 'standard']),
};

export default withStyles(styles, { name: 'MuiInputAdornment' })(InputAdornment);
export default InputAdornment;
23 changes: 11 additions & 12 deletions packages/material-ui/src/InputAdornment/InputAdornment.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 { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
import { typographyClasses } from '../Typography';
import InputAdornment from './InputAdornment';
import TextField from '../TextField';
import FormControl from '../FormControl';
import Input from '../Input';
import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import { typographyClasses } from '@material-ui/core/Typography';
import InputAdornment, { inputAdornmentClasses as classes } from '@material-ui/core/InputAdornment';
import TextField from '@material-ui/core/TextField';
import FormControl from '@material-ui/core/FormControl';
import Input from '@material-ui/core/Input';

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

before(() => {
classes = getClasses(<InputAdornment position="start">foo</InputAdornment>);
});

describeConformance(<InputAdornment position="start">foo</InputAdornment>, () => ({
describeConformanceV5(<InputAdornment position="start">foo</InputAdornment>, () => ({
classes,
inheritComponent: 'div',
mount,
render,
muiName: 'MuiInputAdornment',
testVariantProps: { color: 'primary' },
refInstanceof: window.HTMLDivElement,
skip: ['componentsProp'],
testComponentPropWith: 'span',
}));

Expand Down
5 changes: 4 additions & 1 deletion packages/material-ui/src/InputAdornment/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export { default } from './InputAdornment';
export * from './InputAdornment';
export { default } from './InputAdornment';

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

export { default as inputAdornmentClasses } from './inputAdornmentClasses';
export * from './inputAdornmentClasses';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { InputAdornmentClassKey } from './InputAdornment';

export type InputAdornmentClasses = Record<InputAdornmentClassKey, string>;

declare const inputAdornmentClasses: InputAdornmentClasses;

export function getInputAdornmentUtilityClass(slot: string): string;

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

export function getInputAdornmentUtilityClass(slot) {
return generateUtilityClass('MuiInputAdornment', slot);
}

const inputAdornmentClasses = generateUtilityClasses('MuiInputAdornment', [
'root',
'filled',
'positionStart',
'positionEnd',
'disablePointerEvents',
'hiddenLabel',
'sizeSmall',
]);

export default inputAdornmentClasses;

0 comments on commit 5be4cd9

Please sign in to comment.