From d3d20f4e7b2c68e586167d5c622a63c41ead5f41 Mon Sep 17 00:00:00 2001 From: loriensleafs Date: Sun, 24 Mar 2019 20:21:17 -0400 Subject: [PATCH] Creates a OutlinedInput component. --- src/OutlinedInput/NotchedOutline.js | 102 ++++++++++++------ src/OutlinedInput/OutlinedInput.js | 154 +++++++++------------------- 2 files changed, 119 insertions(+), 137 deletions(-) diff --git a/src/OutlinedInput/NotchedOutline.js b/src/OutlinedInput/NotchedOutline.js index 7e758fb..7a45cec 100644 --- a/src/OutlinedInput/NotchedOutline.js +++ b/src/OutlinedInput/NotchedOutline.js @@ -1,18 +1,23 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React, { forwardRef } from 'react'; import useStyles from '../system/useStyles'; +import combine from '../utils/combine'; import { stylesPropType } from '../utils/propTypes'; -const getStyles = ({ theme: { getTransition, shape } }) => ({ +const getBaseStyles = ({ theme: { getTransition, palette, shape } }) => ({ root: { position: 'absolute', - bottom: 0, - right: 0, - top: -5, - left: 0, - margin: 0, - padding: 0, + bottom: '0px', + right: '0px', + top: '-5px', + left: '0px', + margin: '0px', + padding: '0px', pointerEvents: 'none', + borderColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.23)' + : 'rgba(255, 255, 255, 0.23)', borderRadius: shape.borderRadius.round, borderStyle: 'solid', borderWidth: '1px', @@ -23,6 +28,15 @@ const getStyles = ({ theme: { getTransition, shape } }) => ({ easing: 'out', }, ), + ':hover': { + borderColor: palette.text.primary, + '@media (hover: none)': { + borderColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.23)' + : 'rgba(255, 255, 255, 0.23)', + }, + }, }, legend: { padding: '0px', @@ -35,20 +49,54 @@ const getStyles = ({ theme: { getTransition, shape } }) => ({ }, }); -function NotchedOutline(props) { - const [ - { classes }, - { - children, - className, - labelWidth: labelWidthProp, - notched, - style, - ...passThru +const getDisabledStyles = ({ disabled, theme: { palette } }) => + disabled && { + root: { + borderColor: palette.action.disabled, + }, + }; + +const getErrorStyles = ({ disabled, error, theme: { palette } }) => + !disabled && + error && { + root: { + borderColor: palette.error.main, }, - ] = useStyles(props, getStyles); + }; - const labelWidth = labelWidthProp > 0 ? labelWidthProp * 0.75 + 8 : 0; +const getFocusedStyles = ({ disabled, focused, theme: { palette } }) => + !disabled && + focused && { + root: { + borderColor: palette.primary.main, + borderWidth: '2px', + }, + }; + +const getStyles = combine( + getBaseStyles, + getDisabledStyles, + getFocusedStyles, + getErrorStyles, +); +getStyles.propTypes = { + disabled: PropTypes.bool, + error: PropTypes.bool, + focused: PropTypes.bool, +}; + +const NotchedOutline = forwardRef((props, ref) => { + const { + classes, + props: { children, labelWidth, notched, style, ...passThru }, + } = useStyles(props, getStyles, { nested: true }); + const labelStyle = { + /** + * IE 11: fieldset with legend does not render a border radius. This + * maintains consistency by always having a legend rendered. + */ + width: notched ? (labelWidth > 0 ? labelWidth * 0.75 + 8 : 0) : 0.01, + }; return (
- + {/* Use the nominal use case of the legend, avoid rendering artefacts. */} {/* eslint-disable-next-line react/no-danger */}
); -} +}); NotchedOutline.displayName = 'NotchedOutline'; @@ -93,6 +134,7 @@ NotchedOutline.propTypes = { // If `true`, the outline is notched to accommodate the label. notched: PropTypes.bool.isRequired, style: PropTypes.object, + ...getStyles.propTypes, ...stylesPropType, }; diff --git a/src/OutlinedInput/OutlinedInput.js b/src/OutlinedInput/OutlinedInput.js index 8382fc5..7dfa87b 100644 --- a/src/OutlinedInput/OutlinedInput.js +++ b/src/OutlinedInput/OutlinedInput.js @@ -1,75 +1,26 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React, { forwardRef } from 'react'; import InputBase from '../InputBase'; -import NotchedOutline from './NotchedOutline'; +import { getSpacing } from '../system'; import combine from '../utils/combine'; -import { getSpacing, useStyles } from '../system'; -import { stylesPropType } from '../utils/propTypes'; +import { componentPropType, stylesPropType } from '../utils/propTypes'; +import NotchedOutline from './NotchedOutline'; + +const getBaseStyles = () => ({ + root: { + position: 'relative', + }, + input: { + padding: '18.5px 14px', + }, +}); -const getAdornmentStyles = ({ endAdornment, startAdornment }) => - (endAdornment && { +const getEndAdornmentStyles = ({ endAdornment }) => + endAdornment && { root: getSpacing({ pl: 14 }), input: getSpacing({ pl: 0 }), - }) || - (startAdornment && { - root: getSpacing({ pr: 14 }), - input: getSpacing({ pr: 0 }), - }); - -const getNotchedOutlineStyles = ({ - hasError, - disabled, - focused, - notched, - theme: { palette }, -}) => { - if (!notched) { - return null; - } - - const isLight = palette.type === 'light'; - let next = { - root: { - borderColor: isLight - ? 'rgba(0, 0, 0, 0.23)' - : 'rgba(255, 255, 255, 0.23)', - ':focused': { - borderColor: palette.primary.main, - borderWidth: '2px', - }, - ':disabled': { - borderColor: palette.action.disabled, - }, - }, }; - if (hasError) { - next = { - ...next, - borderColor: palette.error.main, - }; - } - - if (!hasError && !disabled && !focused) { - next = { - ...next, - root: { - ':hover': { - borderColor: palette.text.primary, - // Reset on touch devices so as not to add specificity. - '@media (hover:none)': { - borderColor: isLight - ? 'rgba(0, 0, 0, 0.23)' - : 'rgba(255, 255, 255, 0.23)', - }, - }, - }, - }; - } - - return next; -}; - const getMarginStyles = ({ margin }) => margin === 'dense' && { input: { @@ -90,61 +41,50 @@ const getMultilineStyles = ({ multilined }) => }, }; -const baseStyles = { - root: { - position: 'relative', - }, - input: { - padding: '18.5px 14px', - }, -}; +const getStartAdornmentStyles = ({ startAdornment }) => + startAdornment && { + root: getSpacing({ pr: 14 }), + input: getSpacing({ pr: 0 }), + }; -const getStyles = combine( - getMultilineStyles, +const getOutlinedInputStyles = combine( + getBaseStyles, getMarginStyles, - getNotchedOutlineStyles, - getAdornmentStyles, + getMultilineStyles, + getEndAdornmentStyles, + getStartAdornmentStyles, ); -getStyles.propTypes = {}; -function OutlinedInput(props) { - const [{ styles }, { labelWidth, notched, ...passThru }] = useStyles( - props, - getStyles, - { - baseStyles, - whitelist: [ - 'endAdornment', - 'error', - 'multilined', - 'notched', - 'margin', - 'startAdornment', - ], - }, - ); +const getStyles = props => getOutlinedInputStyles(props); +getStyles.propTypes = {}; - return ( +const OutlinedInput = forwardRef( + ({ labelWidth, notched, notchedOutlineProps, ...props }, ref) => ( ( + ref={ref} + renderPrefix={({ + filled, + focused, + startAdornment, + ...passThru + }) => ( )} - styles={styles} - {...passThru} + styles={getStyles} + {...props} /> - ); -} + ), +); OutlinedInput.displayName = 'OutlinedInput'; @@ -162,7 +102,7 @@ OutlinedInput.propTypes = { * Override or extend the styles applied to the component. * See [CSS API](#css-api) below for more details. */ - classes: PropTypes.object.isRequired, + classes: PropTypes.object, // The CSS class name of the wrapper element. className: PropTypes.string, // The default input value, useful when not controlling the component. @@ -196,7 +136,7 @@ OutlinedInput.propTypes = { * The component used for the native input. * Either a string to use a DOM element or a component. */ - inputComponent: componentPropType, + inputComponent: PropTypes.any, // Attributes applied to the `input` element. inputProps: PropTypes.object, // Use that property to pass a ref callback to the native input component. @@ -261,8 +201,8 @@ OutlinedInput.propTypes = { OutlinedInput.defaultProps = { fullWidth: false, - multiline: false, inputComponent: 'input', + multiline: false, type: 'text', };