diff --git a/src/FilledInput/FilledInput.js b/src/FilledInput/FilledInput.js index 5fb308d..f35a0ed 100644 --- a/src/FilledInput/FilledInput.js +++ b/src/FilledInput/FilledInput.js @@ -1,21 +1,41 @@ -import React from 'react'; import PropTypes from 'prop-types'; +import React, { forwardRef } from 'react'; import InputBase from '../InputBase'; +import { getSpacing } from '../system'; import combine from '../utils/combine'; -import { getSpacing, useStyles } from '../system'; -import { componentPropType, stylesPropType } from '../utils/propTypes'; +import { stylesPropType } from '../utils/propTypes'; -const getStartAdornmentStyles = ({ startAdornment }) => - startAdornment && { - root: getSpacing({ pr: 14 }), - input: getSpacing({ pr: 0 }), - }; - -const getEndAdornmentStyles = ({ endAdornment }) => - endAdornment && { - root: getSpacing({ pl: 14 }), - input: getSpacing({ pl: 0 }), - }; +const getBaseStyles = ({ theme: { getTransition, palette, shape } }) => ({ + root: { + position: 'relative', + backgroundColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.09)' + : 'rgba(255, 255, 255, 0.09)', + borderTopLeftRadius: shape.borderRadius.round, + borderTopRightRadius: shape.borderRadius.round, + transition: getTransition('background-color', { + duration: 'shorter', + easing: 'out', + }), + ':hover': { + backgroundColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.13)' + : 'rgba(255, 255, 255, 0.13)', + // Reset on touch devices so as not to add specificity. + '@media (hover: none)': { + backgroundColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.09)' + : 'rgba(255, 255, 255, 0.09)', + }, + }, + }, + input: { + padding: '27px 12px 10px', + }, +}); const getDisabledStyles = ({ disabled, theme: { palette } }) => disabled && { @@ -24,10 +44,23 @@ const getDisabledStyles = ({ disabled, theme: { palette } }) => palette.type === 'light' ? 'rgba(0, 0, 0, 0.12)' : 'rgba(255, 255, 255, 0.09)', + ':before': { + borderBottomStyle: 'dotted', + }, + ':hover:before': { + borderBottom: `1px dotted ${palette.text.disabled}`, + }, }, }; -const getErrorStyles = ({ error, theme: { palette } }) => +const getEndAdornmentStyles = ({ endAdornment }) => + endAdornment && { + root: getSpacing({ pl: 14 }), + input: getSpacing({ pl: 0 }), + }; + +const getErrorStyles = ({ disabled, error, theme: { palette } }) => + !disabled && error && { root: { ':after': { @@ -37,6 +70,34 @@ const getErrorStyles = ({ error, theme: { palette } }) => }, }; +const getFocusedStyles = ({ disabled, focused, theme: { palette } }) => + !disabled && + focused && { + root: { + backgroundColor: + palette.type === 'light' + ? 'rgba(0, 0, 0, 0.09)' + : 'rgba(255, 255, 255, 0.09)', + ':before': { + borderBottom: `1px solid ${ + palette.type === 'light' + ? 'rgba(0,0,0,0.42)' + : 'rgba(255,255,255, 0.7)' + }`, + }, + ':after': { + transform: 'scaleX(1)', + }, + ':hover:before': { + borderBottom: `1px solid ${ + palette.type === 'light' + ? 'rgba(0,0,0,0.42)' + : 'rgba(255,255,255, 0.7)' + }`, + }, + }, + }; + const getMarginStyles = ({ margin }) => margin === 'dense' && { input: getSpacing({ pt: 3.5, pb: 1.5 }), @@ -54,112 +115,68 @@ const getMultilineStyles = ({ multilined }) => }, }; -const getUnderlinedStyles = ({ - disabled, +const getUnderlineStyles = ({ disableUnderline, - error, - focused, theme: { getTransition, palette }, -}) => { - const isLight = palette.type === 'light'; - const bottomLineColor = isLight - ? 'rgba(0,0,0,0.42)' - : 'rgba(255,255,255, 0.7)'; - let next = {}; - - if (!disableUnderline) { - next = { - root: { - ':before': { - content: '"\\00a0"', - position: 'absolute', - right: '0px', - bottom: '0px', - left: '0px', - borderBottom: `1px solid ${bottomLineColor}`, - transition: getTransition('border-bottom-color', { - duration: 'shorter', - }), - pointerEvents: 'none', - }, - ':after': { - content: '""', - position: 'absolute', - right: '0px', - bottom: '0px', - left: '0px', - borderBottom: `2px solid ${palette.primary[palette.type]}`, - transform: 'scaleX(0)', - transition: getTransition('transform', { - duration: 'shorter', - easing: 'out', - }), - pointerEvents: 'none', - }, - ':disabled:before': { - borderBottom: `1px dotted ${bottomLineColor}`, - }, +}) => + !disableUnderline && { + root: { + ':before': { + content: '"\\00a0"', + position: 'absolute', + right: '0px', + bottom: '0px', + left: '0px', + borderBottom: `1px solid ${ + palette.type === 'light' + ? 'rgba(0,0,0,0.42)' + : 'rgba(255,255,255, 0.7)' + }`, + transition: getTransition('border-bottom-color', { + duration: 'shorter', + easing: 'out', + }), + pointerEvents: 'none', }, - }; - - if (!error && !disabled && !focused) { - next.root[':hover'] = { + ':after': { + content: '""', + position: 'absolute', + right: '0px', + left: '0px', + bottom: '0px', + borderBottom: `2px solid ${palette.primary[palette.type]}`, + transform: 'scaleX(0)', + transition: getTransition('transform', { + duration: 'shorter', + easing: 'out', + }), + pointerEvents: 'none', + }, + ':hover:before': { borderBottom: `1px solid ${palette.text.primary}`, - }; - } - } - - return next; -}; - -const getBaseStyles = ({ theme: { getTransition, palette, shape } }) => ({ - root: { - position: 'relative', - backgroundColor: - palette.type === 'light' - ? 'rgba(0, 0, 0, 0.09)' - : 'rgba(255, 255, 255, 0.09)', - borderTopLeftRadius: shape.borderRadius.round, - borderTopRightRadius: shape.borderRadius.round, - transition: getTransition('background-color', { - duration: 'shorter', - easing: 'out', - }), - ':hover': { - backgroundColor: - palette.type === 'light' - ? 'rgba(0, 0, 0, 0.13)' - : 'rgba(255, 255, 255, 0.13)', - // Reset on touch devices so as not to add specificity. - '@media (hover: none)': { - backgroundColor: - palette.type === 'light' - ? 'rgba(0, 0, 0, 0.09)' - : 'rgba(255, 255, 255, 0.09)', }, }, - ':focused': { - backgroundColor: - palette.type === 'light' - ? 'rgba(0, 0, 0, 0.09)' - : 'rgba(255, 255, 255, 0.12)', - }, - }, - input: { - padding: '27px 12px 10px', - }, -}); + }; -const getStyles = combine( +const getStartAdornmentStyles = ({ startAdornment }) => + startAdornment && { + root: getSpacing({ pr: 14 }), + input: getSpacing({ pr: 0 }), + }; + +const getFilledInputStyles = combine( getBaseStyles, + getEndAdornmentStyles, getMarginStyles, getMultilineStyles, getStartAdornmentStyles, - getEndAdornmentStyles, - getErrorStyles, + getUnderlineStyles, getDisabledStyles, - getUnderlinedStyles, + getErrorStyles, + getFocusedStyles, ); + +const getStyles = props => getFilledInputStyles(props); getStyles.propTypes = { // If `true`, the input will not have an underline. disableUnderline: PropTypes.bool, @@ -177,20 +194,9 @@ getStyles.propTypes = { startAdornment: PropTypes.node, }; -function FilledInput(props) { - const [{ styles }, passThru] = useStyles(props, getStyles, { - whitelist: [ - 'endAdornment', - 'error', - 'disabled', - 'margin', - 'multiline', - 'startAdornment', - ], - }); - - return ; -} +const FilledInput = forwardRef((props, ref) => ( + +)); FilledInput.displayName = 'FilledInput'; @@ -275,12 +281,11 @@ FilledInput.propTypes = { ), ]), ...getStyles.propTypes, - ...componentPropType, ...stylesPropType, }; InputBase.defaultProps = { - as: 'input', + inputComponent: 'input', fullWidth: false, multiline: false, type: 'text',