Skip to content

Commit

Permalink
Creates a OutlinedInput component.
Browse files Browse the repository at this point in the history
  • Loading branch information
loriensleafs committed Mar 25, 2019
1 parent 4199a09 commit d3d20f4
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 137 deletions.
102 changes: 72 additions & 30 deletions src/OutlinedInput/NotchedOutline.js
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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',
Expand All @@ -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 (
<fieldset
Expand All @@ -58,24 +106,17 @@ function NotchedOutline(props) {
...style,
}}
className={classes.root}
ref={ref}
{...passThru}
>
<legend
className={classes.legend}
style={{
// IE 11: fieldset with legend does not render
// a border radius. This maintains consistency
// by always having a legend rendered
width: notched ? labelWidth : 0.01,
}}
>
<legend className={classes.legend} style={labelStyle}>
{/* Use the nominal use case of the legend, avoid rendering artefacts. */}
{/* eslint-disable-next-line react/no-danger */}
<span dangerouslySetInnerHTML={{ __html: '&#8203;' }} />
</legend>
</fieldset>
);
}
});

NotchedOutline.displayName = 'NotchedOutline';

Expand All @@ -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,
};

Expand Down
154 changes: 47 additions & 107 deletions src/OutlinedInput/OutlinedInput.js
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -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) => (
<InputBase
renderPrefix={state => (
ref={ref}
renderPrefix={({
filled,
focused,
startAdornment,
...passThru
}) => (
<NotchedOutline
focused={focused}
labelWidth={labelWidth}
notched={
typeof notched !== 'undefined'
? notched
: Boolean(
state.startAdornment ||
state.filled ||
state.focused,
)
: Boolean(startAdornment || filled || focused)
}
{...passThru}
{...notchedOutlineProps}
/>
)}
styles={styles}
{...passThru}
styles={getStyles}
{...props}
/>
);
}
),
);

OutlinedInput.displayName = 'OutlinedInput';

Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -261,8 +201,8 @@ OutlinedInput.propTypes = {

OutlinedInput.defaultProps = {
fullWidth: false,
multiline: false,
inputComponent: 'input',
multiline: false,
type: 'text',
};

Expand Down

0 comments on commit d3d20f4

Please sign in to comment.