From 7f966d096f142ad1775042695bc2ff86aec1207f Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 10 Apr 2017 16:10:54 +0300 Subject: [PATCH 01/36] Adjusted styles accordingto specs, fixed #6425 --- .../text-fields/ComposedTextField.js | 3 ++- src/Form/FormControl.js | 19 +++++++++++++++---- src/Input/Input.js | 6 ++++-- src/Input/InputLabel.js | 4 ++-- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/src/pages/component-demos/text-fields/ComposedTextField.js b/docs/src/pages/component-demos/text-fields/ComposedTextField.js index d1c683576ecb7b..f555eba4e233c5 100644 --- a/docs/src/pages/component-demos/text-fields/ComposedTextField.js +++ b/docs/src/pages/component-demos/text-fields/ComposedTextField.js @@ -13,7 +13,8 @@ const styleSheet = createStyleSheet('ComposedTextField', () => ({ flexWrap: 'wrap', }, input: { - margin: 10, + marginLeft: 10, + marginRight: 10, }, })); diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index 75f5317c14dcc0..1c73aed8f97dbf 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -11,6 +11,8 @@ export const styleSheet = createStyleSheet('MuiFormControl', () => { root: { display: 'flex', flexDirection: 'column', + marginBottom: 8, + marginTop: 16, position: 'relative', }, row: { @@ -55,10 +57,19 @@ export default class FormControl extends Component { muiFormControl: PropTypes.object.isRequired, }; - state = { - dirty: false, - focused: false, - }; + constructor(props, context) { + super(props, context); + + const dirty = props.children.some((child) => { + return child.type && child.type.name === 'Input' && + child.props.value && child.props.value.length > 0; + }); + + this.state = { + dirty, + focused: false, + }; + } getChildContext() { const { error, required } = this.props; diff --git a/src/Input/Input.js b/src/Input/Input.js index 2b69bdeb57528b..4dbf5bc792d379 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -16,11 +16,13 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { wrapper: { // Mimics the default input display property used by browsers for an input. display: 'inline-block', + marginBottom: 8, + marginTop: 8, position: 'relative', }, formControl: { - marginTop: 10, - marginBottom: 10, + marginBottom: 0, + marginTop: 16, }, inkbar: { '&:after': { diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 1bbb3362bafcde..b45119e409e860 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -17,10 +17,10 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { position: 'absolute', left: 0, top: 0, - transform: 'translate(0, 18px) scale(1)', + transform: 'translate(0, 24px) scale(1)', }, shrink: { - transform: 'translate(0, 0px) scale(0.75)', + transform: 'translate(0, 0) scale(0.75)', transformOrigin: 'top left', }, animated: { From 6e8ad06b9929ac0d266880fdea9ed17a2d1d4e98 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 02:24:32 +0300 Subject: [PATCH 02/36] Fixes, simplified styles --- src/Form/FormControl.js | 14 +++++++------- src/Input/Input.js | 5 ++--- src/Input/InputLabel.js | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index 1c73aed8f97dbf..f0bdabc8a8bab8 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -1,18 +1,17 @@ // @flow weak -import React, { Component } from 'react'; +import React, { Children, Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { createStyleSheet } from 'jss-theme-reactor'; import customPropTypes from '../utils/customPropTypes'; +import { isDirty } from '../Input/Input' export const styleSheet = createStyleSheet('MuiFormControl', () => { return { root: { display: 'flex', flexDirection: 'column', - marginBottom: 8, - marginTop: 16, position: 'relative', }, row: { @@ -60,10 +59,11 @@ export default class FormControl extends Component { constructor(props, context) { super(props, context); - const dirty = props.children.some((child) => { - return child.type && child.type.name === 'Input' && - child.props.value && child.props.value.length > 0; - }); + const dirty = Children.map(props.children, (child) => { + if(child.type && child.type.name === 'Input' && isDirty(child.props)) { + return child; + } + }).length; this.state = { dirty, diff --git a/src/Input/Input.js b/src/Input/Input.js index 4dbf5bc792d379..bc50f496b6cfff 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -6,7 +6,7 @@ import classNames from 'classnames'; import { createStyleSheet } from 'jss-theme-reactor'; import customPropTypes from '../utils/customPropTypes'; -function isDirty(obj) { +export function isDirty(obj) { return obj && obj.value && obj.value.length > 0; } @@ -21,8 +21,7 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { position: 'relative', }, formControl: { - marginBottom: 0, - marginTop: 16, + marginTop: 32, }, inkbar: { '&:after': { diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index b45119e409e860..dac321823778e6 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -17,10 +17,10 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { position: 'absolute', left: 0, top: 0, - transform: 'translate(0, 24px) scale(1)', + transform: 'translate(0, 40px) scale(1)', }, shrink: { - transform: 'translate(0, 0) scale(0.75)', + transform: 'translate(0, 16px) scale(0.75)', transformOrigin: 'top left', }, animated: { From b5fb82aaf845cd6eb7162dcfff640c50d1148ff5 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 02:52:17 +0300 Subject: [PATCH 03/36] Removed dead `TextFieldLabel` component as for #6580 --- .../component-api/TextField/TextFieldLabel.md | 19 ---- .../text-fields/text-fields.md | 2 +- src/TextField/TextFieldLabel.js | 94 ------------------- src/TextField/TextFieldLabel.spec.js | 42 --------- src/TextField/index.js | 1 - src/index.js | 1 - src/styles/MuiThemeProvider.js | 2 - 7 files changed, 1 insertion(+), 160 deletions(-) delete mode 100644 docs/src/pages/component-api/TextField/TextFieldLabel.md delete mode 100644 src/TextField/TextFieldLabel.js delete mode 100644 src/TextField/TextFieldLabel.spec.js diff --git a/docs/src/pages/component-api/TextField/TextFieldLabel.md b/docs/src/pages/component-api/TextField/TextFieldLabel.md deleted file mode 100644 index a5c7e620196a46..00000000000000 --- a/docs/src/pages/component-api/TextField/TextFieldLabel.md +++ /dev/null @@ -1,19 +0,0 @@ -TextFieldLabel -============== - - - -Props ------ - -| Name | Type | Default | Description | -|:-----|:-----|:--------|:------------| -| children | node | | The content of the component. | -| className | string | | The CSS class name of the root element. | -| disableAnimation | bool | false | If `true`, the transition animation is disabled. | -| error | bool | | If `true`, the label is displayed in an error state. | -| focused | bool | | If `true`, the input of this label is focused. | -| required | bool | | If `true`, the label will indicate that the input is required. | -| shrink | bool | false | If `true`, the label is shrunk. | - -Any other properties supplied will be spread to the root element. diff --git a/docs/src/pages/component-demos/text-fields/text-fields.md b/docs/src/pages/component-demos/text-fields/text-fields.md index 5100e997e25678..cd2c523d4c7de3 100644 --- a/docs/src/pages/component-demos/text-fields/text-fields.md +++ b/docs/src/pages/component-demos/text-fields/text-fields.md @@ -1,5 +1,5 @@ --- -components: Input, TextField, TextFieldLabel +components: Input, TextField --- # Text Fields diff --git a/src/TextField/TextFieldLabel.js b/src/TextField/TextFieldLabel.js deleted file mode 100644 index 3029ff6b92b6be..00000000000000 --- a/src/TextField/TextFieldLabel.js +++ /dev/null @@ -1,94 +0,0 @@ -// @flow weak - -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { createStyleSheet } from 'jss-theme-reactor'; -import customPropTypes from '../utils/customPropTypes'; -import { FormLabel } from '../Form'; - -export const styleSheet = createStyleSheet('MuiTextFieldLabel', (theme) => { - const { transitions } = theme; - return { - root: { - position: 'absolute', - left: 0, - top: 0, - transform: 'translate(0, 18px) scale(1)', - transformOrigin: 'top left', - }, - shrink: { - transform: 'translate(0, 0px) scale(0.75)', - }, - animated: { - transition: transitions.create('transform', { - duration: transitions.duration.shorter, - easing: transitions.easing.easeOut, - }), - }, - }; -}); - -export default function TextFieldLabel(props, context) { - const { - disableAnimation, - children, - className: classNameProp, - shrink, - ...other - } = props; - const classes = context.styleManager.render(styleSheet); - - const className = classNames(classes.root, { - [classes.animated]: !disableAnimation, - [classes.shrink]: shrink, - }, classNameProp); - - return ( - - {children} - - ); -} - -TextFieldLabel.propTypes = { - /** - * The content of the component. - */ - children: PropTypes.node, - /** - * The CSS class name of the root element. - */ - className: PropTypes.string, - /** - * If `true`, the transition animation is disabled. - */ - disableAnimation: PropTypes.bool, - /** - * If `true`, the label is displayed in an error state. - */ - error: PropTypes.bool, - /** - * If `true`, the input of this label is focused. - */ - focused: PropTypes.bool, - /** - * If `true`, the label will indicate that the input is required. - */ - required: PropTypes.bool, - /** - * If `true`, the label is shrunk. - */ - shrink: PropTypes.bool, -}; - -TextFieldLabel.defaultProps = { - disableAnimation: false, - shrink: false, -}; - -TextFieldLabel.contextTypes = { - styleManager: customPropTypes.muiRequired, -}; - -TextFieldLabel.muiName = 'TextFieldLabel'; diff --git a/src/TextField/TextFieldLabel.spec.js b/src/TextField/TextFieldLabel.spec.js deleted file mode 100644 index 51086be929e0f5..00000000000000 --- a/src/TextField/TextFieldLabel.spec.js +++ /dev/null @@ -1,42 +0,0 @@ -// @flow weak - -import React from 'react'; -import { assert } from 'chai'; -import { createShallow } from 'src/test-utils'; -import TextFieldLabel, { styleSheet } from './TextFieldLabel'; - -describe('', () => { - let shallow; - let classes; - - before(() => { - shallow = createShallow(); - classes = shallow.context.styleManager.render(styleSheet); - }); - - it('should render a FormLabel', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.is('FormLabel'), true, 'should be a FormLabel'); - }); - - it('should animate by default', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.animated), true, 'should have the animated class'); - }); - - it('should not animate', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.animated), false, - 'should not have the animated class'); - }); - - it('should not shrink by default', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.shrink), false, 'should not have the shrink class'); - }); - - it('should shrink', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.shrink), true, 'should have the shrink class'); - }); -}); diff --git a/src/TextField/index.js b/src/TextField/index.js index 253a5fe2464823..cbf0bc4f02a0dd 100644 --- a/src/TextField/index.js +++ b/src/TextField/index.js @@ -2,4 +2,3 @@ export default from './TextField'; export TextField from './TextField'; -export TextFieldLabel from './TextFieldLabel'; diff --git a/src/index.js b/src/index.js index 16e74b4c77a1b7..bbce937d36bfeb 100644 --- a/src/index.js +++ b/src/index.js @@ -143,7 +143,6 @@ export { export { TextField, - TextFieldLabel, } from './TextField'; export { diff --git a/src/styles/MuiThemeProvider.js b/src/styles/MuiThemeProvider.js index 73dd413bb576ff..890e41c4a6644e 100644 --- a/src/styles/MuiThemeProvider.js +++ b/src/styles/MuiThemeProvider.js @@ -80,8 +80,6 @@ export const MUI_SHEET_ORDER = [ 'MuiCardHeader', 'MuiCard', - 'MuiTextFieldLabel', - 'MuiTextFieldInput', 'MuiTextField', 'MuiTable', From 6cece8589c37d5cb7a05c1fb22165c71521081d2 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 05:20:43 +0300 Subject: [PATCH 04/36] Added colors according to specs, `InputLabel` disabled prop --- .../component-demos/text-fields/TextFields.js | 8 ++++++++ src/Form/FormLabel.js | 4 ++-- src/Input/Input.js | 16 ++++++++++++---- src/Input/InputLabel.js | 12 +++++++++++- src/TextField/TextField.js | 2 +- src/styles/palette.js | 17 +++++++++++++++++ 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/docs/src/pages/component-demos/text-fields/TextFields.js b/docs/src/pages/component-demos/text-fields/TextFields.js index e11a1e2218d466..7e22bdaac7a634 100644 --- a/docs/src/pages/component-demos/text-fields/TextFields.js +++ b/docs/src/pages/component-demos/text-fields/TextFields.js @@ -56,6 +56,14 @@ export default class TextFields extends Component { defaultValue="Hello World" className={classes.input} /> + this.setState({ name: event.target.value })} + disabled + /> ); } diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index 265ba05ac6a329..d8439aee86a431 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -8,10 +8,10 @@ import { createStyleSheet } from 'jss-theme-reactor'; import customPropTypes from '../utils/customPropTypes'; export const styleSheet = createStyleSheet('MuiFormLabel', (theme) => { - const focusColor = theme.palette.primary.A200; + const focusColor = theme.palette.type === 'light' ? theme.palette.primary.A700 : theme.palette.primary.A200; return { root: { - color: theme.palette.text.secondary, + color: theme.palette.input.labelText, lineHeight: 1, }, focused: { diff --git a/src/Input/Input.js b/src/Input/Input.js index bc50f496b6cfff..c25bbd8624dc31 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -25,7 +25,7 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { }, inkbar: { '&:after': { - backgroundColor: palette.primary.A200, + backgroundColor: palette.type === 'light' ? palette.primary.A700 : palette.primary.A200, left: 0, bottom: -1, // Doing the other way around crash on IE11 "''" https://github.com/cssinjs/jss/issues/242 @@ -60,7 +60,7 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { background: 'none', lineHeight: 1, appearance: 'textfield', // Improve type search style. - color: theme.palette.text.primary, + color: theme.palette.input.inputText, width: '100%', '&:focus': { outline: 0, @@ -70,11 +70,19 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { }, }, disabled: { - color: theme.palette.text.disabled, + color: theme.palette.input.disabled, cursor: 'not-allowed', }, underline: { - borderBottom: `1px solid ${theme.palette.text.divider}`, + borderBottom: `1px solid ${theme.palette.input.bottomLine}`, + '&:hover:not($disabled)': { + borderBottom: `2px solid ${theme.palette.text.primary}`, + marginBottom: -1, + transition: transitions.create('border-color', { + duration: transitions.duration.shorter, + easing: transitions.easing.ease, + }), + }, '&$disabled': { borderBottomStyle: 'dotted', }, diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index dac321823778e6..19cbb7e1ef0632 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -20,7 +20,7 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { transform: 'translate(0, 40px) scale(1)', }, shrink: { - transform: 'translate(0, 16px) scale(0.75)', + transform: 'translate(0, 18px) scale(0.75)', transformOrigin: 'top left', }, animated: { @@ -29,11 +29,15 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { easing: transitions.easing.easeOut, }), }, + disabled: { + color: theme.palette.input.disabled, + }, }; }); export default function InputLabel(props, context) { const { + disabled, disableAnimation, children, className: classNameProp, @@ -54,6 +58,7 @@ export default function InputLabel(props, context) { [classes.formControl]: muiFormControl, [classes.animated]: !disableAnimation, [classes.shrink]: shrink, + [classes.disabled]: disabled, }, classNameProp); return ( @@ -72,6 +77,10 @@ InputLabel.propTypes = { * The CSS class name of the root element. */ className: PropTypes.string, + /** + * If `true`, apply disabled class. + */ + disabled: PropTypes.bool, /** * If `true`, the transition animation is disabled. */ @@ -95,6 +104,7 @@ InputLabel.propTypes = { }; InputLabel.defaultProps = { + disabled: false, disableAnimation: false, }; diff --git a/src/TextField/TextField.js b/src/TextField/TextField.js index 0cb3e37553ac49..fae533aecf9b23 100644 --- a/src/TextField/TextField.js +++ b/src/TextField/TextField.js @@ -103,7 +103,7 @@ export default class TextField extends Component { {...other} > {label && ( - + {label} )} diff --git a/src/styles/palette.js b/src/styles/palette.js index e450c420063d2f..5b026cc95bac66 100644 --- a/src/styles/palette.js +++ b/src/styles/palette.js @@ -13,6 +13,14 @@ export const light = { divider: 'rgba(0, 0, 0, 0.12)', lightDivider: 'rgba(0, 0, 0, 0.075)', }, + input: { + bottomLine: 'rgba(0, 0, 0, 0.42)', + helperText: 'rgba(0, 0, 0, 0.54)', + labelText: 'rgba(0, 0, 0, 0.54)', + inputText: 'rgba(0, 0, 0, 0.87)', + placeholderRext: 'rgba(0, 0, 0, 0.42)', + disabled: 'rgba(0, 0, 0, 0.42)', + }, action: { active: 'rgba(0, 0, 0, 0.54)', disabled: 'rgba(0, 0, 0, 0.26)', @@ -36,6 +44,14 @@ export const dark = { divider: 'rgba(255, 255, 255, 0.12)', lightDivider: 'rgba(255, 255, 255, 0.075)', }, + input: { + bottomLine: 'rgba(255, 255, 255, 0.7)', + helperText: 'rgba(255, 255, 255, 0.7)', + labelText: 'rgba(255, 255, 255, 0.7)', + inputText: 'rgba(255, 255, 255, 1)', + placeholderRext: 'rgba(255, 255, 255, 0.5)', + disabled: 'rgba(0, 0, 0, 0.5)', + }, action: { active: 'rgba(255, 255, 255, 1)', disabled: 'rgba(255, 255, 255, 0.3)', @@ -67,6 +83,7 @@ export default function createPalette({ return { type, text: shades[type].text, + input: shades[type].input, action: shades[type].action, background: shades[type].background, shades, From 7b7fa13ea6b65a9137925c9acbfc4464f9fed499 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 05:47:15 +0300 Subject: [PATCH 05/36] Avoiding label flicker and blurry text in webkit browsers --- src/Input/InputLabel.js | 8 ++++---- src/styles/palette.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 19cbb7e1ef0632..7aba3c522d491e 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -16,15 +16,15 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { formControl: { position: 'absolute', left: 0, - top: 0, - transform: 'translate(0, 40px) scale(1)', + top: 40, }, shrink: { - transform: 'translate(0, 18px) scale(0.75)', + fontSize: 12, + top: 18, transformOrigin: 'top left', }, animated: { - transition: transitions.create('transform', { + transition: transitions.create(['top', 'font-size'], { duration: transitions.duration.shorter, easing: transitions.easing.easeOut, }), diff --git a/src/styles/palette.js b/src/styles/palette.js index 5b026cc95bac66..e8a796343af50b 100644 --- a/src/styles/palette.js +++ b/src/styles/palette.js @@ -50,7 +50,7 @@ export const dark = { labelText: 'rgba(255, 255, 255, 0.7)', inputText: 'rgba(255, 255, 255, 1)', placeholderRext: 'rgba(255, 255, 255, 0.5)', - disabled: 'rgba(0, 0, 0, 0.5)', + disabled: 'rgba(255, 255, 255, 0.5)', }, action: { active: 'rgba(255, 255, 255, 1)', From 4716659ef226ab8fcbdfebe0f1c09ec4f5fdee3e Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 06:13:23 +0300 Subject: [PATCH 06/36] More smooth label animation. --- src/Input/InputLabel.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 7aba3c522d491e..d14d857695f85a 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -16,15 +16,16 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { formControl: { position: 'absolute', left: 0, - top: 40, + top: 0, + transform: 'translate(0, 40px)', }, shrink: { fontSize: 12, - top: 18, + transform: 'translate(0, 18px)', transformOrigin: 'top left', }, animated: { - transition: transitions.create(['top', 'font-size'], { + transition: transitions.create(['transform', 'font-size'], { duration: transitions.duration.shorter, easing: transitions.easing.easeOut, }), From 6f83e5b16e803bebc41502610ecb2afec43b6be8 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 07:03:23 +0300 Subject: [PATCH 07/36] More smooth font-size animation --- src/Input/InputLabel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index d14d857695f85a..47bdbb7261161b 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -12,6 +12,7 @@ export const styleSheet = createStyleSheet('MuiInputLabel', (theme) => { return { root: { transformOrigin: 'top left', + fontSmoothing: 'antialiased', }, formControl: { position: 'absolute', From 186a251f52e2f9116bdcd05313469a3943a36223 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 07:34:25 +0300 Subject: [PATCH 08/36] Proper error color, added `FormHelperText` component --- .../text-fields/ComposedTextField.js | 21 ++++++ .../component-demos/text-fields/TextFields.js | 7 ++ src/Form/FormHelperText.js | 70 +++++++++++++++++++ src/Form/FormLabel.js | 2 +- src/Form/index.js | 1 + src/Input/Input.js | 2 +- src/TextField/TextField.js | 14 ++++ 7 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 src/Form/FormHelperText.js diff --git a/docs/src/pages/component-demos/text-fields/ComposedTextField.js b/docs/src/pages/component-demos/text-fields/ComposedTextField.js index f555eba4e233c5..267d6fc4520f3b 100644 --- a/docs/src/pages/component-demos/text-fields/ComposedTextField.js +++ b/docs/src/pages/component-demos/text-fields/ComposedTextField.js @@ -6,6 +6,7 @@ import customPropTypes from 'material-ui/utils/customPropTypes'; import Input from 'material-ui/Input'; import InputLabel from 'material-ui/Input/InputLabel'; import FormControl from 'material-ui/Form/FormControl'; +import FormHelperText from 'material-ui/Form/FormHelperText'; const styleSheet = createStyleSheet('ComposedTextField', () => ({ container: { @@ -42,6 +43,26 @@ export default class ComposedTextField extends Component { onChange={(event) => this.setState({ name: event.target.value })} /> + + + Name + + + Some important helper text + + + + Name + + + Some important helper text + ); } diff --git a/docs/src/pages/component-demos/text-fields/TextFields.js b/docs/src/pages/component-demos/text-fields/TextFields.js index 7e22bdaac7a634..472202f118cf11 100644 --- a/docs/src/pages/component-demos/text-fields/TextFields.js +++ b/docs/src/pages/component-demos/text-fields/TextFields.js @@ -64,6 +64,13 @@ export default class TextFields extends Component { onChange={(event) => this.setState({ name: event.target.value })} disabled /> + ); } diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js new file mode 100644 index 00000000000000..b90802da00d049 --- /dev/null +++ b/src/Form/FormHelperText.js @@ -0,0 +1,70 @@ +// @flow weak +/* eslint-disable jsx-a11y/label-has-for */ + +import React from 'react'; +import PropTypes from 'prop-types'; +import classNames from 'classnames'; +import { createStyleSheet } from 'jss-theme-reactor'; +import customPropTypes from '../utils/customPropTypes'; + +export const styleSheet = createStyleSheet('MuiFormHelperText', (theme) => { + return { + root: { + color: theme.palette.input.helperText, + fontSize: 12, + lineHeight: 1.33333333, + margin: 0, + }, + error: { + color: theme.palette.error.A400, + }, + }; +}); + +export default function FormHelperText(props, context) { + const { + children, + className: classNameProp, + error: errorProp, + ...other + } = props; + + const { muiFormControl, styleManager } = context; + const classes = styleManager.render(styleSheet); + + let error = errorProp; + + if (muiFormControl && typeof error === 'undefined') { + error = muiFormControl.error; + } + + const className = classNames(classes.root, { + [classes.error]: error, + }, classNameProp); + + return ( +

+ {children} +

+ ); +} + +FormHelperText.propTypes = { + /** + * The content of the component. + */ + children: PropTypes.node, + /** + * The CSS class name of the root element. + */ + className: PropTypes.string, + /** + * Whether the helper text should be displayed in an error state. + */ + error: PropTypes.bool, +}; + +FormHelperText.contextTypes = { + muiFormControl: PropTypes.object, + styleManager: customPropTypes.muiRequired, +}; diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index d8439aee86a431..1e86674f217043 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -18,7 +18,7 @@ export const styleSheet = createStyleSheet('MuiFormLabel', (theme) => { color: focusColor, }, error: { - color: theme.palette.error[500], + color: theme.palette.error.A400, }, }; }); diff --git a/src/Form/index.js b/src/Form/index.js index bf0431fb0bb361..cf590965e0a9fb 100644 --- a/src/Form/index.js +++ b/src/Form/index.js @@ -3,3 +3,4 @@ export FormGroup from './FormGroup'; export FormLabel from './FormLabel'; export FormControl from './FormControl'; +export FormHelperText from './FormHelperText'; diff --git a/src/Input/Input.js b/src/Input/Input.js index c25bbd8624dc31..81dbf33e576c97 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -46,7 +46,7 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { focused: {}, error: { '&:after': { - backgroundColor: palette.error[500], + backgroundColor: palette.error.A400, transform: 'scaleX(1)', // error is always underlined in red }, }, diff --git a/src/TextField/TextField.js b/src/TextField/TextField.js index fae533aecf9b23..a1841e90e4c41a 100644 --- a/src/TextField/TextField.js +++ b/src/TextField/TextField.js @@ -6,6 +6,7 @@ import shallowEqual from 'recompose/shallowEqual'; import { Input, InputLabel } from '../Input'; import customPropTypes from '../utils/customPropTypes'; import FormControl from '../Form/FormControl'; +import FormHelperText from '../Form/FormHelperText'; /** * ``` @@ -46,6 +47,14 @@ export default class TextField extends Component { * The CSS class name of the label element. */ labelClassName: PropTypes.string, + /** + * The helper text content. + */ + helperText: PropTypes.node, + /** + * The CSS class name of the helper text element. + */ + helperTextClassName: PropTypes.string, /** * Name attribute of the `Input` element. */ @@ -88,6 +97,8 @@ export default class TextField extends Component { inputProps, label, labelClassName, + helperText, + helperTextClassName, name, required, type, @@ -115,6 +126,9 @@ export default class TextField extends Component { disabled={disabled} {...inputProps} /> + + {helperText} + ); } From 7abcec9ac40570496b9b10fbe540d94ba4802585 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 07:57:13 +0300 Subject: [PATCH 09/36] FormHelperText docs --- .../pages/component-api/Form/FormHelperText.md | 15 +++++++++++++++ .../component-demos/text-fields/text-fields.md | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 docs/src/pages/component-api/Form/FormHelperText.md diff --git a/docs/src/pages/component-api/Form/FormHelperText.md b/docs/src/pages/component-api/Form/FormHelperText.md new file mode 100644 index 00000000000000..6be33354a7016e --- /dev/null +++ b/docs/src/pages/component-api/Form/FormHelperText.md @@ -0,0 +1,15 @@ +FormHelperText +========= + + + +Props +----- + +| Name | Type | Default | Description | +|:-----|:-----|:--------|:------------| +| children | node | | The content of the component. | +| className | string | | The CSS class name of the root element. | +| error | bool | | Whether the helper text should be displayed in an error state. | + +Any other properties supplied will be spread to the root element. diff --git a/docs/src/pages/component-demos/text-fields/text-fields.md b/docs/src/pages/component-demos/text-fields/text-fields.md index cd2c523d4c7de3..c0754cd959cfa1 100644 --- a/docs/src/pages/component-demos/text-fields/text-fields.md +++ b/docs/src/pages/component-demos/text-fields/text-fields.md @@ -1,5 +1,5 @@ --- -components: Input, TextField +components: Input, TextField, FormHelperText --- # Text Fields From d02154ca882bea79fd8bbc0ed2b8b03a142f687a Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Wed, 12 Apr 2017 18:38:27 +0300 Subject: [PATCH 10/36] Fixed lint errors --- src/Form/FormControl.js | 32 +++++++++++++++++--------------- src/Form/FormLabel.js | 7 ++++--- src/Input/InputLabel.js | 8 ++++---- src/TextField/TextField.js | 24 +++++++++++++----------- 4 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index f0bdabc8a8bab8..873377b51d71ea 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import { createStyleSheet } from 'jss-theme-reactor'; import customPropTypes from '../utils/customPropTypes'; -import { isDirty } from '../Input/Input' +import { isDirty } from '../Input/Input'; export const styleSheet = createStyleSheet('MuiFormControl', () => { return { @@ -56,20 +56,10 @@ export default class FormControl extends Component { muiFormControl: PropTypes.object.isRequired, }; - constructor(props, context) { - super(props, context); - - const dirty = Children.map(props.children, (child) => { - if(child.type && child.type.name === 'Input' && isDirty(child.props)) { - return child; - } - }).length; - - this.state = { - dirty, - focused: false, - }; - } + state = { + dirty: false, + focused: false, + }; getChildContext() { const { error, required } = this.props; @@ -89,6 +79,18 @@ export default class FormControl extends Component { }; } + componentWillMount() { + let dirty = false; + Children.map(this.props.children, (child) => { + if (child && child.type && child.type.name === 'Input' && isDirty(child.props)) { + dirty = true; + } + return child; + }); + + this.setState({ dirty }); + } + handleFocus = () => { if (!this.state.focused) { this.setState({ focused: true }); diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index 1e86674f217043..ff6e12e55ad32a 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -8,17 +8,18 @@ import { createStyleSheet } from 'jss-theme-reactor'; import customPropTypes from '../utils/customPropTypes'; export const styleSheet = createStyleSheet('MuiFormLabel', (theme) => { - const focusColor = theme.palette.type === 'light' ? theme.palette.primary.A700 : theme.palette.primary.A200; + const { palette } = theme; + const focusColor = palette.type === 'light' ? palette.primary.A700 : palette.primary.A200; return { root: { - color: theme.palette.input.labelText, + color: palette.input.labelText, lineHeight: 1, }, focused: { color: focusColor, }, error: { - color: theme.palette.error.A400, + color: palette.error.A400, }, }; }); diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 47bdbb7261161b..124741f0e77679 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -79,14 +79,14 @@ InputLabel.propTypes = { * The CSS class name of the root element. */ className: PropTypes.string, - /** - * If `true`, apply disabled class. - */ - disabled: PropTypes.bool, /** * If `true`, the transition animation is disabled. */ disableAnimation: PropTypes.bool, + /** + * If `true`, apply disabled class. + */ + disabled: PropTypes.bool, /** * If `true`, the label will be displayed in an error state. */ diff --git a/src/TextField/TextField.js b/src/TextField/TextField.js index a1841e90e4c41a..7040d8af7fe615 100644 --- a/src/TextField/TextField.js +++ b/src/TextField/TextField.js @@ -27,6 +27,14 @@ export default class TextField extends Component { * If `true`, the label will be displayed in an error state. */ error: PropTypes.bool, + /** + * The helper text content. + */ + helperText: PropTypes.node, + /** + * The CSS class name of the helper text element. + */ + helperTextClassName: PropTypes.string, /* * @ignore */ @@ -47,14 +55,6 @@ export default class TextField extends Component { * The CSS class name of the label element. */ labelClassName: PropTypes.string, - /** - * The helper text content. - */ - helperText: PropTypes.node, - /** - * The CSS class name of the helper text element. - */ - helperTextClassName: PropTypes.string, /** * Name attribute of the `Input` element. */ @@ -126,9 +126,11 @@ export default class TextField extends Component { disabled={disabled} {...inputProps} /> - - {helperText} - + {helperText && ( + + {helperText} + + )} ); } From dffc9765d26cd4f0879518a6ab6cce3534088531 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 15 Apr 2017 06:14:15 +0300 Subject: [PATCH 11/36] Added new component to styles order, fixes --- src/Form/FormControl.js | 3 +-- src/Form/FormHelperText.js | 2 +- src/styles/MuiThemeProvider.js | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index 873377b51d71ea..ff865a912197ae 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -81,11 +81,10 @@ export default class FormControl extends Component { componentWillMount() { let dirty = false; - Children.map(this.props.children, (child) => { + Children.forEach(this.props.children, (child) => { if (child && child.type && child.type.name === 'Input' && isDirty(child.props)) { dirty = true; } - return child; }); this.setState({ dirty }); diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index b90802da00d049..27808b39d0c7b4 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -12,7 +12,7 @@ export const styleSheet = createStyleSheet('MuiFormHelperText', (theme) => { root: { color: theme.palette.input.helperText, fontSize: 12, - lineHeight: 1.33333333, + lineHeight: 1.4, margin: 0, }, error: { diff --git a/src/styles/MuiThemeProvider.js b/src/styles/MuiThemeProvider.js index 890e41c4a6644e..9b5605da706a3f 100644 --- a/src/styles/MuiThemeProvider.js +++ b/src/styles/MuiThemeProvider.js @@ -22,6 +22,7 @@ export const MUI_SHEET_ORDER = [ 'MuiFormLabel', 'MuiFormGroup', + 'MuiFormHelperText', 'MuiText', 'MuiPaper', From 0b1523018dade0009115a79d73a182e884cd55bf Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 15 Apr 2017 19:55:09 +0300 Subject: [PATCH 12/36] Fixed disabled border style --- src/Input/Input.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Input/Input.js b/src/Input/Input.js index 81dbf33e576c97..219b445da10783 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -85,6 +85,7 @@ export const styleSheet = createStyleSheet('MuiInput', (theme) => { }, '&$disabled': { borderBottomStyle: 'dotted', + borderImage: `linear-gradient(to right, ${theme.palette.input.bottomLine} 33%, transparent 0%) 100 0 / 0 0 1px / 0 0 0 3px repeat`, }, }, }; From b11a2e86152adeabe4a36eb6d2366ef122f2c80c Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 02:13:11 +0300 Subject: [PATCH 13/36] FormHelperText exports --- src/Form/index.js | 1 + src/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Form/index.js b/src/Form/index.js index 437dd6a4c13c0d..67b4ee3d076e84 100644 --- a/src/Form/index.js +++ b/src/Form/index.js @@ -3,3 +3,4 @@ export { default as FormGroup } from './FormGroup'; export { default as FormLabel } from './FormLabel'; export { default as FormControl } from './FormControl'; +export { default as FormHelperText } from './FormHelperText'; diff --git a/src/index.js b/src/index.js index 599d5d1465d0b1..b3943016d3474d 100644 --- a/src/index.js +++ b/src/index.js @@ -24,7 +24,7 @@ export { export { default as Divider } from './Divider'; export { default as Drawer } from './Drawer'; -export { FormControl, FormGroup, FormLabel } from './Form'; +export { FormControl, FormGroup, FormLabel, FormHelperText } from './Form'; export { default as Hidden } from './Hidden'; export { default as Icon } from './Icon'; From 710e605ccfbbc3fc4c275b47e05a64776afd449f Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 02:21:44 +0300 Subject: [PATCH 14/36] Remove unused TextFieldLabel --- src/TextField/TextFieldLabel.js | 90 ---------------------------- src/TextField/TextFieldLabel.spec.js | 45 -------------- src/TextField/index.js | 1 - src/index.js | 2 +- 4 files changed, 1 insertion(+), 137 deletions(-) delete mode 100644 src/TextField/TextFieldLabel.js delete mode 100644 src/TextField/TextFieldLabel.spec.js diff --git a/src/TextField/TextFieldLabel.js b/src/TextField/TextFieldLabel.js deleted file mode 100644 index 304fcace1992a6..00000000000000 --- a/src/TextField/TextFieldLabel.js +++ /dev/null @@ -1,90 +0,0 @@ -// @flow weak - -import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import { createStyleSheet } from 'jss-theme-reactor'; -import withStyles from '../styles/withStyles'; -import { FormLabel } from '../Form'; - -export const styleSheet = createStyleSheet('MuiTextFieldLabel', theme => ({ - root: { - position: 'absolute', - left: 0, - top: 0, - transform: 'translate(0, 18px) scale(1)', - transformOrigin: 'top left', - }, - shrink: { - transform: 'translate(0, 0px) scale(0.75)', - }, - animated: { - transition: theme.transitions.create('transform', { - duration: theme.transitions.duration.shorter, - easing: theme.transitions.easing.easeOut, - }), - }, -})); - -function TextFieldLabel(props) { - const { disableAnimation, children, classes, className: classNameProp, shrink, ...other } = props; - - const className = classNames( - classes.root, - { - [classes.animated]: !disableAnimation, - [classes.shrink]: shrink, - }, - classNameProp, - ); - - return ( - - {children} - - ); -} - -TextFieldLabel.propTypes = { - /** - * The content of the component. - */ - children: PropTypes.node, - /** - * Useful to extend the style applied to components. - */ - classes: PropTypes.object.isRequired, - /** - * @ignore - */ - className: PropTypes.string, - /** - * If `true`, the transition animation is disabled. - */ - disableAnimation: PropTypes.bool, - /** - * If `true`, the label is displayed in an error state. - */ - error: PropTypes.bool, - /** - * If `true`, the input of this label is focused. - */ - focused: PropTypes.bool, - /** - * If `true`, the label will indicate that the input is required. - */ - required: PropTypes.bool, - /** - * If `true`, the label is shrunk. - */ - shrink: PropTypes.bool, -}; - -TextFieldLabel.defaultProps = { - disableAnimation: false, - shrink: false, -}; - -TextFieldLabel.muiName = 'TextFieldLabel'; - -export default withStyles(styleSheet)(TextFieldLabel); diff --git a/src/TextField/TextFieldLabel.spec.js b/src/TextField/TextFieldLabel.spec.js deleted file mode 100644 index c6b25f4e7aa29a..00000000000000 --- a/src/TextField/TextFieldLabel.spec.js +++ /dev/null @@ -1,45 +0,0 @@ -// @flow - -import React from 'react'; -import { assert } from 'chai'; -import { createShallow } from '../test-utils'; -import TextFieldLabel, { styleSheet } from './TextFieldLabel'; - -describe('', () => { - let shallow; - let classes; - - before(() => { - shallow = createShallow({ dive: true }); - classes = shallow.context.styleManager.render(styleSheet); - }); - - it('should render a FormLabel', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.name(), 'withStyles(FormLabel)'); - }); - - it('should animate by default', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.animated), true, 'should have the animated class'); - }); - - it('should not animate', () => { - const wrapper = shallow(); - assert.strictEqual( - wrapper.hasClass(classes.animated), - false, - 'should not have the animated class', - ); - }); - - it('should not shrink by default', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.shrink), false, 'should not have the shrink class'); - }); - - it('should shrink', () => { - const wrapper = shallow(); - assert.strictEqual(wrapper.hasClass(classes.shrink), true, 'should have the shrink class'); - }); -}); diff --git a/src/TextField/index.js b/src/TextField/index.js index 47034307915d5e..5b60303a7f1d62 100644 --- a/src/TextField/index.js +++ b/src/TextField/index.js @@ -1,4 +1,3 @@ // @flow export { default } from './TextField'; -export { default as TextFieldLabel } from './TextFieldLabel'; diff --git a/src/index.js b/src/index.js index b3943016d3474d..4b607256d36e5e 100644 --- a/src/index.js +++ b/src/index.js @@ -71,6 +71,6 @@ export { default as Tabs, Tab } from './Tabs'; export { default as Typography } from './Typography'; -export { default as TextField, TextFieldLabel } from './TextField'; +export { default as TextField } from './TextField'; export { default as Toolbar } from './Toolbar'; From 0061db18bf55eb7abf40f9e340c270b95dfefc0b Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 19:40:09 +0300 Subject: [PATCH 15/36] Form helper fixes, test, docs --- .../component-api/Form/FormHelperText.md | 17 ++++- src/Form/FormControl.js | 6 +- src/Form/FormHelperText.js | 57 +++++++++-------- src/Form/FormHelperText.spec.js | 63 +++++++++++++++++++ src/TextField/TextField.js | 5 +- 5 files changed, 110 insertions(+), 38 deletions(-) create mode 100644 src/Form/FormHelperText.spec.js diff --git a/docs/src/pages/component-api/Form/FormHelperText.md b/docs/src/pages/component-api/Form/FormHelperText.md index 6be33354a7016e..c9e8c45310b2ff 100644 --- a/docs/src/pages/component-api/Form/FormHelperText.md +++ b/docs/src/pages/component-api/Form/FormHelperText.md @@ -3,9 +3,7 @@ FormHelperText -Props ------ - +## Props | Name | Type | Default | Description | |:-----|:-----|:--------|:------------| | children | node | | The content of the component. | @@ -13,3 +11,16 @@ Props | error | bool | | Whether the helper text should be displayed in an error state. | Any other properties supplied will be spread to the root element. +## Classes + +You can overrides all the class names injected by Material-UI thanks to the `classes` property. +This property accepts the following keys: +- `root` +- `error` + +Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) +section for more detail. + +If using the `overrides` key of the theme as documented +[here](/customization/themes#customizing-all-instances-of-a-component-type), +you need to use the following style sheet name: `MuiFormHelperText`. diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index a6dcba2116c75d..50b00c07ba3e37 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -53,9 +53,9 @@ class FormControl extends Component { componentWillMount() { Children.forEach(this.props.children, child => { if ( - child && child.type && - (child.type.name === 'Input' || - (child.type.Naked && child.type.Naked.name === 'Input')) && + child && + child.type && + (child.type.name === 'Input' || (child.type.Naked && child.type.Naked.name === 'Input')) && isDirty(child.props) ) { this.setState({ dirty: true }); diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 27808b39d0c7b4..8e5c929e65bd7b 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -1,36 +1,26 @@ // @flow weak -/* eslint-disable jsx-a11y/label-has-for */ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { createStyleSheet } from 'jss-theme-reactor'; -import customPropTypes from '../utils/customPropTypes'; +import withStyles from '../styles/withStyles'; -export const styleSheet = createStyleSheet('MuiFormHelperText', (theme) => { - return { - root: { - color: theme.palette.input.helperText, - fontSize: 12, - lineHeight: 1.4, - margin: 0, - }, - error: { - color: theme.palette.error.A400, - }, - }; -}); +export const styleSheet = createStyleSheet('MuiFormHelperText', theme => ({ + root: { + color: theme.palette.input.helperText, + fontSize: 12, + lineHeight: 1.4, + margin: 0, + }, + error: { + color: theme.palette.error.A400, + }, +})); -export default function FormHelperText(props, context) { - const { - children, - className: classNameProp, - error: errorProp, - ...other - } = props; - - const { muiFormControl, styleManager } = context; - const classes = styleManager.render(styleSheet); +function FormHelperText(props, context) { + const { children, classes, className: classNameProp, error: errorProp, ...other } = props; + const { muiFormControl } = context; let error = errorProp; @@ -38,9 +28,13 @@ export default function FormHelperText(props, context) { error = muiFormControl.error; } - const className = classNames(classes.root, { - [classes.error]: error, - }, classNameProp); + const className = classNames( + classes.root, + { + [classes.error]: error, + }, + classNameProp, + ); return (

@@ -54,6 +48,10 @@ FormHelperText.propTypes = { * The content of the component. */ children: PropTypes.node, + /** + * Useful to extend the style applied to components. + */ + classes: PropTypes.object.isRequired, /** * The CSS class name of the root element. */ @@ -66,5 +64,6 @@ FormHelperText.propTypes = { FormHelperText.contextTypes = { muiFormControl: PropTypes.object, - styleManager: customPropTypes.muiRequired, }; + +export default withStyles(styleSheet)(FormHelperText); diff --git a/src/Form/FormHelperText.spec.js b/src/Form/FormHelperText.spec.js new file mode 100644 index 00000000000000..64e6e578377ebb --- /dev/null +++ b/src/Form/FormHelperText.spec.js @@ -0,0 +1,63 @@ +// @flow + +import React from 'react'; +import { assert } from 'chai'; +import { createShallow } from '../test-utils'; +import FormHelperText, { styleSheet } from './FormHelperText'; + +describe('', () => { + let shallow; + let classes; + + before(() => { + shallow = createShallow({ dive: true }); + classes = shallow.context.styleManager.render(styleSheet); + }); + + it('should render a

', () => { + const wrapper = shallow(); + assert.strictEqual(wrapper.name(), 'p'); + assert.strictEqual(wrapper.hasClass(classes.root), true, 'should have the root class'); + assert.strictEqual(wrapper.hasClass('woof'), true, 'should have the user class'); + }); + + describe('prop: error', () => { + it('should show an error class', () => { + const wrapper = shallow(); + assert.strictEqual(wrapper.hasClass(classes.error), true); + }); + }); + + describe('with muiFormControl context', () => { + let wrapper; + let muiFormControl; + + function setFormControlContext(muiFormControlContext) { + muiFormControl = muiFormControlContext; + wrapper.setContext({ ...wrapper.context(), muiFormControl }); + } + + beforeEach(() => { + wrapper = shallow(Foo); + }); + ['error'].forEach(visualState => { + describe(visualState, () => { + beforeEach(() => { + setFormControlContext({ [visualState]: true }); + }); + + it(`should have the ${visualState} class`, () => { + assert.strictEqual(wrapper.hasClass(classes[visualState]), true); + }); + + it('should be overridden by props', () => { + assert.strictEqual(wrapper.hasClass(classes[visualState]), true); + wrapper.setProps({ [visualState]: false }); + assert.strictEqual(wrapper.hasClass(classes[visualState]), false); + wrapper.setProps({ [visualState]: true }); + assert.strictEqual(wrapper.hasClass(classes[visualState]), true); + }); + }); + }); + }); +}); diff --git a/src/TextField/TextField.js b/src/TextField/TextField.js index b15b92d1017c18..08b35a6cef8972 100644 --- a/src/TextField/TextField.js +++ b/src/TextField/TextField.js @@ -62,11 +62,10 @@ function TextField(props) { inputRef={inputRef} {...InputProps} /> - {helperText && ( + {helperText && {helperText} - - )} + } ); } From 0565e9452485caccfb9abd16615dd5d25340b832 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 21:01:10 +0300 Subject: [PATCH 16/36] TextField tests for FormHelperText --- src/TextField/TextField.spec.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/TextField/TextField.spec.js b/src/TextField/TextField.spec.js index 22f2c21c0080b8..c67e13550ca677 100644 --- a/src/TextField/TextField.spec.js +++ b/src/TextField/TextField.spec.js @@ -4,6 +4,7 @@ import React from 'react'; import { assert } from 'chai'; import { createShallow, createMount } from '../test-utils'; import Input, { InputLabel } from '../Input'; +import FormHelperText from '../Form/FormHelperText'; import TextField from './TextField'; describe('', () => { @@ -80,6 +81,29 @@ describe('', () => { }); }); + describe('with a helper text', () => { + beforeEach(() => { + wrapper.setProps({ helperText: 'Foo bar' }); + }); + + it('should have 2 children', () => { + assert.strictEqual(wrapper.children().length, 2); + }); + + it('should have an FormHelperText as the second child', () => { + assert.strictEqual(wrapper.childAt(1).is(FormHelperText), true); + }); + + it('should pass helperTextClassName to the FormHelperText as className', () => { + wrapper.setProps({ helperTextClassName: 'foo' }); + assert.strictEqual(wrapper.find(FormHelperText).hasClass('foo'), true); + }); + + it('should have an Input as the first child', () => { + assert.strictEqual(wrapper.childAt(0).is(Input), true); + }); + }); + describe('prop: InputProps', () => { it('should apply additional properties to the Input component', () => { wrapper.setProps({ From c3bde34f084e7ad8ccbd36c2bea893e3e9ceaae5 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 21:20:44 +0300 Subject: [PATCH 17/36] Get rid of TextFieldLabel.md, added tests for InputLabel --- .../component-api/TextField/TextFieldLabel.md | 30 ------------------- src/Input/InputLabel.spec.js | 5 ++++ 2 files changed, 5 insertions(+), 30 deletions(-) delete mode 100644 docs/src/pages/component-api/TextField/TextFieldLabel.md diff --git a/docs/src/pages/component-api/TextField/TextFieldLabel.md b/docs/src/pages/component-api/TextField/TextFieldLabel.md deleted file mode 100644 index 7ef68b98e4a9ea..00000000000000 --- a/docs/src/pages/component-api/TextField/TextFieldLabel.md +++ /dev/null @@ -1,30 +0,0 @@ -# TextFieldLabel - - - -## Props -| Name | Type | Default | Description | -|:-----|:-----|:--------|:------------| -| children | node | | The content of the component. | -| classes | object | | Useful to extend the style applied to components. | -| disableAnimation | bool | false | If `true`, the transition animation is disabled. | -| error | bool | | If `true`, the label is displayed in an error state. | -| focused | bool | | If `true`, the input of this label is focused. | -| required | bool | | If `true`, the label will indicate that the input is required. | -| shrink | bool | false | If `true`, the label is shrunk. | - -Any other properties supplied will be spread to the root element. -## Classes - -You can overrides all the class names injected by Material-UI thanks to the `classes` property. -This property accepts the following keys: -- `root` -- `shrink` -- `animated` - -Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) -section for more detail. - -If using the `overrides` key of the theme as documented -[here](/customization/themes#customizing-all-instances-of-a-component-type), -you need to use the following style sheet name: `MuiTextFieldLabel`. diff --git a/src/Input/InputLabel.spec.js b/src/Input/InputLabel.spec.js index 288ae002e50baf..caf8002f05cba4 100644 --- a/src/Input/InputLabel.spec.js +++ b/src/Input/InputLabel.spec.js @@ -31,6 +31,11 @@ describe('', () => { assert.strictEqual(wrapper.hasClass(classes.animated), false); }); + it('should have the disabled class when disabled', () => { + const wrapper = shallow(Foo); + assert.strictEqual(wrapper.hasClass(classes.disabled), true); + }); + describe('with muiFormControl context', () => { let wrapper; let muiFormControl; From c740da254cadda7de0d660f2d36af6cc5043b224 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Sat, 27 May 2017 21:42:52 +0300 Subject: [PATCH 18/36] Added tests for FormControl --- src/Form/FormControl.spec.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Form/FormControl.spec.js b/src/Form/FormControl.spec.js index 29aece5a0ddf0e..56f006d16e7d9f 100644 --- a/src/Form/FormControl.spec.js +++ b/src/Form/FormControl.spec.js @@ -4,6 +4,7 @@ import React from 'react'; import { spy } from 'sinon'; import { assert } from 'chai'; import { createShallow } from '../test-utils'; +import Input from '../Input'; import FormControl, { styleSheet } from './FormControl'; describe('', () => { @@ -47,6 +48,18 @@ describe('', () => { }); }); + describe('should be dirty if has input with value set', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallow(); + }); + + it('should be dirty initially', () => { + assert.strictEqual(wrapper.state().dirty, true); + }); + }); + describe('muiFormControl child context', () => { let wrapper; let muiFormControlContext; From 4e16f7c860d20e5f993606e9a60d72f07497d4f5 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 14:49:44 +0300 Subject: [PATCH 19/36] Make dirty if `defaultValue` is set --- src/Input/Input.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Input/Input.js b/src/Input/Input.js index a273a2e63a06c9..4d40a1e6bdea19 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -8,7 +8,9 @@ import withStyles from '../styles/withStyles'; import Textarea from './Textarea'; export function isDirty(obj) { - return obj && obj.value && obj.value.length > 0; + return ( + obj && ((obj.value && obj.value.length) || (obj.defaultValue && obj.defaultValue.length)) > 0 + ); } export const styleSheet = createStyleSheet('MuiInput', theme => ({ From e7e7f478dfc0618ed342dc106f8bca1da80ad6b3 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 14:49:56 +0300 Subject: [PATCH 20/36] Fix helper text font --- src/Form/FormHelperText.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 8e5c929e65bd7b..7a598af87afb73 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -9,6 +9,7 @@ import withStyles from '../styles/withStyles'; export const styleSheet = createStyleSheet('MuiFormHelperText', theme => ({ root: { color: theme.palette.input.helperText, + fontFamily: theme.typography.fontFamily, fontSize: 12, lineHeight: 1.4, margin: 0, From 38d404326dfb391e16275c81ce699126b43db26d Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 14:51:04 +0300 Subject: [PATCH 21/36] Fix label "flicker" in webkit browsers. --- src/Input/InputLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 12f5a602abe280..f71027fc1f8ff5 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -18,7 +18,7 @@ export const styleSheet = createStyleSheet('MuiInputLabel', theme => ({ transform: 'translate(0, 40px) scale(1)', }, shrink: { - transform: 'translate(0, 18px) scale(0.75)', + transform: 'translate(0, 18.5px) scale(0.75)', transformOrigin: 'top left', }, animated: { From 2f70c6cdc00fa9831d889d69a0312eebb32c4bad Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:21:05 +0300 Subject: [PATCH 22/36] Use `theme.spacing.unit` instead of number values --- src/Input/Input.js | 16 +++++++++------- src/Input/InputLabel.js | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Input/Input.js b/src/Input/Input.js index 4d40a1e6bdea19..d2a1df2a271bc4 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -21,10 +21,10 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ fontFamily: theme.typography.fontFamily, }, formControl: { - marginTop: 8, - marginBottom: 8, + marginTop: theme.spacing.unit, + marginBottom: theme.spacing.unit, 'label + &': { - marginTop: 32, + marginTop: theme.spacing.unit * 4, }, }, inkbar: { @@ -56,7 +56,7 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ }, input: { font: 'inherit', - padding: '8px 0', + padding: `${theme.spacing.unit}px 0`, border: 0, display: 'block', boxSizing: 'content-box', @@ -83,7 +83,7 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ padding: 0, }, multilineWrapper: { - padding: '6px 0', + padding: `${theme.spacing.unit}px 0`, }, disabled: { color: theme.palette.text.disabled, @@ -92,7 +92,7 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ borderBottom: `1px solid ${theme.palette.input.bottomLine}`, '&:hover:not($disabled)': { borderBottom: `2px solid ${theme.palette.text.primary}`, - marginBottom: 7, + marginBottom: theme.spacing.unit - 1, transition: theme.transitions.create('border-color', { duration: theme.transitions.duration.shorter, easing: theme.transitions.easing.ease, @@ -101,7 +101,7 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ '&$disabled': { borderBottomStyle: 'dotted', borderImage: `linear-gradient(to right, ${theme.palette.input.bottomLine} 33%, transparent 0%) - 100 0 / 0 0 1px / 0 0 0 3px repeat`, + 100 0 / 0 0 1px / 0 0 0 0 repeat`, }, }, })); @@ -426,4 +426,6 @@ Input.contextTypes = { muiFormControl: PropTypes.object, }; +Input.muiName = 'Input'; + export default withStyles(styleSheet)(Input); diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index f71027fc1f8ff5..1a8aae156fd742 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -15,10 +15,10 @@ export const styleSheet = createStyleSheet('MuiInputLabel', theme => ({ position: 'absolute', left: 0, top: 0, - transform: 'translate(0, 40px) scale(1)', + transform: `translate(0, ${theme.spacing.unit * 5}px) scale(1)`, }, shrink: { - transform: 'translate(0, 18.5px) scale(0.75)', + transform: `translate(0, ${theme.spacing.unit * 2 + 2.5}px) scale(0.75)`, transformOrigin: 'top left', }, animated: { From 1457b964adc116c3fcd97957feb455ff35a6a7d4 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:21:33 +0300 Subject: [PATCH 23/36] Disabled composed text field demo --- .../pages/component-demos/text-fields/ComposedTextField.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/src/pages/component-demos/text-fields/ComposedTextField.js b/docs/src/pages/component-demos/text-fields/ComposedTextField.js index 2e6d3368a7aa71..25cf3f36a2198c 100644 --- a/docs/src/pages/component-demos/text-fields/ComposedTextField.js +++ b/docs/src/pages/component-demos/text-fields/ComposedTextField.js @@ -45,6 +45,13 @@ class ComposedTextField extends Component { Some important helper text + + + Name + + + Some important helper text + Name From 5fe667a1ab3c30c843d6e1d512fbac6bae0eba82 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:21:56 +0300 Subject: [PATCH 24/36] Fixed type check --- src/Form/FormControl.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index 50b00c07ba3e37..cbd6ba71a6a562 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -53,9 +53,7 @@ class FormControl extends Component { componentWillMount() { Children.forEach(this.props.children, child => { if ( - child && - child.type && - (child.type.name === 'Input' || (child.type.Naked && child.type.Naked.name === 'Input')) && + child.type && child.type.muiName === 'Input' && isDirty(child.props) ) { this.setState({ dirty: true }); From 5d6970da50591fce1fe9356687ee60d4940e3277 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:24:44 +0300 Subject: [PATCH 25/36] Fixed type check error --- src/Form/FormControl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index cbd6ba71a6a562..8146b10dde2ad6 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -53,7 +53,7 @@ class FormControl extends Component { componentWillMount() { Children.forEach(this.props.children, child => { if ( - child.type && child.type.muiName === 'Input' && + child && child.type && child.type.muiName === 'Input' && isDirty(child.props) ) { this.setState({ dirty: true }); From 612b02ca96e60b1a0318c8a6df9a64f3e537e885 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:54:13 +0300 Subject: [PATCH 26/36] Make `ComposedTextFiled` accept disabled prop --- .../text-fields/ComposedTextField.js | 4 ++-- src/Form/FormControl.js | 14 +++++++++----- src/Form/FormHelperText.js | 15 ++++++++++++++- src/Form/FormLabel.js | 9 +++++++++ src/Input/Input.js | 8 ++++++-- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/docs/src/pages/component-demos/text-fields/ComposedTextField.js b/docs/src/pages/component-demos/text-fields/ComposedTextField.js index 25cf3f36a2198c..e8513201949c58 100644 --- a/docs/src/pages/component-demos/text-fields/ComposedTextField.js +++ b/docs/src/pages/component-demos/text-fields/ComposedTextField.js @@ -45,11 +45,11 @@ class ComposedTextField extends Component { Some important helper text - + Name - + Some important helper text diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index 8146b10dde2ad6..da54e1e98e1914 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -23,6 +23,7 @@ export const styleSheet = createStyleSheet('MuiFormControl', { */ class FormControl extends Component { static defaultProps = { + disabled: false, error: false, required: false, }; @@ -33,12 +34,13 @@ class FormControl extends Component { }; getChildContext() { - const { error, required } = this.props; + const { disabled, error, required } = this.props; const { dirty, focused } = this.state; return { muiFormControl: { dirty, + disabled, error, focused, required, @@ -52,10 +54,7 @@ class FormControl extends Component { componentWillMount() { Children.forEach(this.props.children, child => { - if ( - child && child.type && child.type.muiName === 'Input' && - isDirty(child.props) - ) { + if (child && child.type && child.type.muiName === 'Input' && isDirty(child.props)) { this.setState({ dirty: true }); } }); @@ -96,6 +95,7 @@ class FormControl extends Component { children, classes, className, + disabled, // eslint-disable-line no-unused-vars error, // eslint-disable-line no-unused-vars ...other } = this.props; @@ -126,6 +126,10 @@ FormControl.propTypes = { * @ignore */ className: PropTypes.string, + /** + * If `true`, the label should be displayed in an disabled state. + */ + disabled: PropTypes.bool, /** * If `true`, the label should be displayed in an error state. */ diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 7a598af87afb73..57caf1caf8bf82 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -17,14 +17,22 @@ export const styleSheet = createStyleSheet('MuiFormHelperText', theme => ({ error: { color: theme.palette.error.A400, }, + disabled: { + color: theme.palette.input.disabled, + }, })); function FormHelperText(props, context) { - const { children, classes, className: classNameProp, error: errorProp, ...other } = props; + const { children, classes, className: classNameProp, disabled: disabledProp, error: errorProp, ...other } = props; const { muiFormControl } = context; + let disabled = disabledProp; let error = errorProp; + if (muiFormControl && typeof disabled === 'undefined') { + disabled = muiFormControl.disabled; + } + if (muiFormControl && typeof error === 'undefined') { error = muiFormControl.error; } @@ -32,6 +40,7 @@ function FormHelperText(props, context) { const className = classNames( classes.root, { + [classes.disabled]: disabled, [classes.error]: error, }, classNameProp, @@ -57,6 +66,10 @@ FormHelperText.propTypes = { * The CSS class name of the root element. */ className: PropTypes.string, + /** + * Whether the helper text should be displayed in an disabled state. + */ + disabled: PropTypes.bool, /** * Whether the helper text should be displayed in an error state. */ diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index a822f7715e8cc6..632e822a782ade 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -21,6 +21,9 @@ export const styleSheet = createStyleSheet('MuiFormLabel', theme => { error: { color: theme.palette.error.A400, }, + disabled: { + color: theme.palette.input.disabled, + }, }; }); @@ -29,6 +32,7 @@ function FormLabel(props, context) { children, classes, className: classNameProp, + disabled: disabledProp, error: errorProp, focused: focusedProp, required: requiredProp, @@ -39,6 +43,7 @@ function FormLabel(props, context) { let required = requiredProp; let focused = focusedProp; + let disabled = disabledProp; let error = errorProp; if (muiFormControl) { @@ -48,6 +53,9 @@ function FormLabel(props, context) { if (typeof focused === 'undefined') { focused = muiFormControl.focused; } + if (typeof disabled === 'undefined') { + disabled = muiFormControl.disabled; + } if (typeof error === 'undefined') { error = muiFormControl.error; } @@ -57,6 +65,7 @@ function FormLabel(props, context) { classes.root, { [classes.focused]: focused, + [classes.disabled]: disabled, [classes.error]: error, }, classNameProp, diff --git a/src/Input/Input.js b/src/Input/Input.js index d2a1df2a271bc4..7bfe5549da0493 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -108,7 +108,6 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ class Input extends Component { static defaultProps = { - disabled: false, type: 'text', disableUnderline: false, multiline: false, @@ -207,7 +206,7 @@ class Input extends Component { className: classNameProp, component, defaultValue, - disabled, + disabled: disabledProp, disableUnderline, error: errorProp, id, @@ -231,8 +230,13 @@ class Input extends Component { const { muiFormControl } = this.context; + let disabled = disabledProp; let error = errorProp; + if (muiFormControl && typeof disabled === 'undefined') { + disabled = muiFormControl.disabled; + } + if (typeof error === 'undefined' && muiFormControl) { error = muiFormControl.error; } From ae3d010150875a40172dce61f61d857b9ab055e4 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 15:56:23 +0300 Subject: [PATCH 27/36] Fixed lint --- src/Form/FormHelperText.js | 9 ++++++++- src/Form/FormLabel.js | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 57caf1caf8bf82..54501bc954d7ad 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -23,7 +23,14 @@ export const styleSheet = createStyleSheet('MuiFormHelperText', theme => ({ })); function FormHelperText(props, context) { - const { children, classes, className: classNameProp, disabled: disabledProp, error: errorProp, ...other } = props; + const { + children, + classes, + className: classNameProp, + disabled: disabledProp, + error: errorProp, + ...other + } = props; const { muiFormControl } = context; let disabled = disabledProp; diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index 632e822a782ade..78a887fbee6f1d 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -99,6 +99,10 @@ FormLabel.propTypes = { * @ignore */ className: PropTypes.string, + /** + * Whether the label should be displayed in an disabled state. + */ + disabled: PropTypes.bool, /** * Whether the label should be displayed in an error state. */ From 3cd4b999818dc115ab5d8f1f16819f158c619e56 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 16:00:31 +0300 Subject: [PATCH 28/36] Fixed docs and input --- docs/src/pages/component-api/Form/FormHelperText.md | 5 +++-- src/Input/Input.js | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/pages/component-api/Form/FormHelperText.md b/docs/src/pages/component-api/Form/FormHelperText.md index c9e8c45310b2ff..acf3f4bb128dc1 100644 --- a/docs/src/pages/component-api/Form/FormHelperText.md +++ b/docs/src/pages/component-api/Form/FormHelperText.md @@ -1,5 +1,4 @@ -FormHelperText -========= +# FormHelperText @@ -8,6 +7,7 @@ FormHelperText |:-----|:-----|:--------|:------------| | children | node | | The content of the component. | | className | string | | The CSS class name of the root element. | +| disabled | bool | | Whether the helper text should be displayed in an disabled state. | | error | bool | | Whether the helper text should be displayed in an error state. | Any other properties supplied will be spread to the root element. @@ -16,6 +16,7 @@ Any other properties supplied will be spread to the root element. You can overrides all the class names injected by Material-UI thanks to the `classes` property. This property accepts the following keys: - `root` +- `disabled` - `error` Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) diff --git a/src/Input/Input.js b/src/Input/Input.js index 7bfe5549da0493..f25a7dfcf6e919 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -107,6 +107,7 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ })); class Input extends Component { + static muiName = 'Input'; static defaultProps = { type: 'text', disableUnderline: false, @@ -430,6 +431,4 @@ Input.contextTypes = { muiFormControl: PropTypes.object, }; -Input.muiName = 'Input'; - export default withStyles(styleSheet)(Input); From 9b40eee0f60fac394992ba28c6ed6a384e9c1802 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 16:44:34 +0300 Subject: [PATCH 29/36] Exposed FormHelperTextProps and InputLabelProps --- src/TextField/TextField.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/TextField/TextField.js b/src/TextField/TextField.js index 08b35a6cef8972..1fbb1525482d72 100644 --- a/src/TextField/TextField.js +++ b/src/TextField/TextField.js @@ -20,8 +20,10 @@ function TextField(props) { inputRef, label, labelClassName, + InputLabelProps, helperText, helperTextClassName, + FormHelperTextProps, name, required, type, @@ -44,7 +46,7 @@ function TextField(props) { return ( {label && - + {label} } {helperText && - + {helperText} } @@ -87,6 +89,10 @@ TextField.propTypes = { * If `true`, the label will be displayed in an error state. */ error: PropTypes.bool, + /** + * Properties applied to the `FormHelperText` element. + */ + FormHelperTextProps: PropTypes.object, /** * The helper text content. */ @@ -107,6 +113,10 @@ TextField.propTypes = { * The CSS class name of the `Input` element. */ InputClassName: PropTypes.string, + /** + * Properties applied to the `InputLabel` element. + */ + InputLabelProps: PropTypes.object, /** * Properties applied to the `input` element. */ From 428d8709cdad191b2f96bd75a8d2d6f0e1418e62 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 16:44:45 +0300 Subject: [PATCH 30/36] Fixed docs --- docs/src/pages/component-api/Form/FormControl.md | 1 + docs/src/pages/component-api/Form/FormHelperText.md | 3 ++- docs/src/pages/component-api/Form/FormLabel.md | 2 ++ docs/src/pages/component-api/Input/Input.md | 2 +- docs/src/pages/component-api/Input/InputLabel.md | 2 ++ docs/src/pages/component-api/Progress/CircularProgress.md | 6 +++--- docs/src/pages/component-api/TextField/TextField.md | 4 ++++ 7 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/src/pages/component-api/Form/FormControl.md b/docs/src/pages/component-api/Form/FormControl.md index c40ec342ab6bdd..bbd896f73836a3 100644 --- a/docs/src/pages/component-api/Form/FormControl.md +++ b/docs/src/pages/component-api/Form/FormControl.md @@ -7,6 +7,7 @@ Provides context such as dirty/focused/error/required for form inputs. |:-----|:-----|:--------|:------------| | children | node | | The contents of the form control. | | classes | object | | Useful to extend the style applied to components. | +| disabled | bool | false | If `true`, the label should be displayed in an disabled state. | | error | bool | false | If `true`, the label should be displayed in an error state. | | required | bool | false | If `true`, the label will indicate that the input is required. | diff --git a/docs/src/pages/component-api/Form/FormHelperText.md b/docs/src/pages/component-api/Form/FormHelperText.md index acf3f4bb128dc1..c56a0792c47aa1 100644 --- a/docs/src/pages/component-api/Form/FormHelperText.md +++ b/docs/src/pages/component-api/Form/FormHelperText.md @@ -6,6 +6,7 @@ | Name | Type | Default | Description | |:-----|:-----|:--------|:------------| | children | node | | The content of the component. | +| classes | object | | Useful to extend the style applied to components. | | className | string | | The CSS class name of the root element. | | disabled | bool | | Whether the helper text should be displayed in an disabled state. | | error | bool | | Whether the helper text should be displayed in an error state. | @@ -16,8 +17,8 @@ Any other properties supplied will be spread to the root element. You can overrides all the class names injected by Material-UI thanks to the `classes` property. This property accepts the following keys: - `root` -- `disabled` - `error` +- `disabled` Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) section for more detail. diff --git a/docs/src/pages/component-api/Form/FormLabel.md b/docs/src/pages/component-api/Form/FormLabel.md index ab2968881414df..b035501c7496b5 100644 --- a/docs/src/pages/component-api/Form/FormLabel.md +++ b/docs/src/pages/component-api/Form/FormLabel.md @@ -7,6 +7,7 @@ |:-----|:-----|:--------|:------------| | children | node | | The content of the component. | | classes | object | | Useful to extend the style applied to components. | +| disabled | bool | | Whether the label should be displayed in an disabled state. | | error | bool | | Whether the label should be displayed in an error state. | | focused | bool | | If `true`, the input of this label is focused (used by `FormGroup` components). | | required | bool | | If `true`, the label will indicate that the input is required. | @@ -19,6 +20,7 @@ This property accepts the following keys: - `root` - `focused` - `error` +- `disabled` Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) section for more detail. diff --git a/docs/src/pages/component-api/Input/Input.md b/docs/src/pages/component-api/Input/Input.md index 279cd15065eda7..7b2e1a034b11ed 100644 --- a/docs/src/pages/component-api/Input/Input.md +++ b/docs/src/pages/component-api/Input/Input.md @@ -9,7 +9,7 @@ | className | string | | The CSS class name of the wrapper element. | | component | union: string
 func
| | The component used for the root node. Either a string to use a DOM element or a component. It's an `input` by default. | | defaultValue | string | | The default value of the `Input` element. | -| disabled | bool | false | If `true`, the input will be disabled. | +| disabled | bool | | If `true`, the input will be disabled. | | disableUnderline | bool | false | If `true`, the input will not have an underline. | | error | bool | | If `true`, the input will indicate an error. | | id | string | | | diff --git a/docs/src/pages/component-api/Input/InputLabel.md b/docs/src/pages/component-api/Input/InputLabel.md index 41dca00c328f10..683e854f59d728 100644 --- a/docs/src/pages/component-api/Input/InputLabel.md +++ b/docs/src/pages/component-api/Input/InputLabel.md @@ -8,6 +8,7 @@ | children | node | | The contents of the `InputLabel`. | | classes | object | | Useful to extend the style applied to components. | | disableAnimation | bool | false | If `true`, the transition animation is disabled. | +| disabled | bool | false | If `true`, apply disabled class. | | error | bool | | If `true`, the label will be displayed in an error state. | | focused | bool | | If `true`, the input of this label is focused. | | required | bool | | if `true`, the label will indicate that the input is required. | @@ -22,6 +23,7 @@ This property accepts the following keys: - `formControl` - `shrink` - `animated` +- `disabled` Have a look at [overriding with class names](/customization/overrides#overriding-with-class-names) section for more detail. diff --git a/docs/src/pages/component-api/Progress/CircularProgress.md b/docs/src/pages/component-api/Progress/CircularProgress.md index 693c5fb64c2fd3..82edaa15adffb9 100644 --- a/docs/src/pages/component-api/Progress/CircularProgress.md +++ b/docs/src/pages/component-api/Progress/CircularProgress.md @@ -6,10 +6,10 @@ | Name | Type | Default | Description | |:-----|:-----|:--------|:------------| | classes | object | | Useful to extend the style applied to components. | -| size | number | 40 | The size of the circle. | -| mode | enum:
 'determinate'
 'indeterminate' | 'indeterminate' | The mode of show your progress. Indeterminate for when there is no value for progress. Determinate for controlled progress value. | | max | number | 100 | The max value of progress in determinate mode. | -| min | number | 0 | TThe min value of progress in determinate mode. | +| min | number | 0 | The min value of progress in determinate mode. | +| mode | enum: 'determinate'
 'indeterminate'
| 'indeterminate' | The mode of show your progress. Indeterminate for when there is no value for progress. Determinate for controlled progress value. | +| size | number | 40 | The size of the circle. | | value | number | 0 | The value of progress in determinate mode. | Any other properties supplied will be spread to the root element. diff --git a/docs/src/pages/component-api/TextField/TextField.md b/docs/src/pages/component-api/TextField/TextField.md index 6a48c2a229b3d9..2d5e03b55b6430 100644 --- a/docs/src/pages/component-api/TextField/TextField.md +++ b/docs/src/pages/component-api/TextField/TextField.md @@ -8,9 +8,13 @@ | defaultValue | string | | The default value of the `Input` element. | | disabled | bool | | If `true`, the input will be disabled. | | error | bool | | If `true`, the label will be displayed in an error state. | +| helperText | node | | The helper text content. | +| helperTextClassName | string | | The CSS class name of the helper text element. | +| FormHelperTextProps | object | | Properties applied to the `FormHelperText` element. | | id | string | | | | inputClassName | string | | The CSS class name of the `input` element. | | InputClassName | string | | The CSS class name of the `Input` element. | +| InputLabelProps | object | | Properties applied to the `InputLabel` element. | | inputProps | object | | Properties applied to the `input` element. | | InputProps | object | | Properties applied to the `Input` element. | | inputRef | function | | Use that property to pass a ref callback to the native input component. | From a8a9a6c43f503545f4831973967936528c194d40 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 20:51:55 +0300 Subject: [PATCH 31/36] Fixed multiline styles --- src/Input/Input.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Input/Input.js b/src/Input/Input.js index f25a7dfcf6e919..c2b9098e61e051 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -83,20 +83,20 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ padding: 0, }, multilineWrapper: { - padding: `${theme.spacing.unit}px 0`, + padding: `${theme.spacing.unit - 2}px 0`, }, disabled: { color: theme.palette.text.disabled, }, underline: { borderBottom: `1px solid ${theme.palette.input.bottomLine}`, + transition: theme.transitions.create('border-color', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.ease, + }), '&:hover:not($disabled)': { borderBottom: `2px solid ${theme.palette.text.primary}`, marginBottom: theme.spacing.unit - 1, - transition: theme.transitions.create('border-color', { - duration: theme.transitions.duration.shorter, - easing: theme.transitions.easing.ease, - }), }, '&$disabled': { borderBottomStyle: 'dotted', From 3043877701e53af9961c173999b1d41d2fce022f Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 21:13:15 +0300 Subject: [PATCH 32/36] Placeholder + Label behaviour --- .../pages/component-demos/text-fields/TextFields.js | 8 ++++++++ src/Input/Input.js | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/docs/src/pages/component-demos/text-fields/TextFields.js b/docs/src/pages/component-demos/text-fields/TextFields.js index 335237e999cdfe..f12ddae3d374fd 100644 --- a/docs/src/pages/component-demos/text-fields/TextFields.js +++ b/docs/src/pages/component-demos/text-fields/TextFields.js @@ -85,6 +85,14 @@ class TextFields extends Component { className={classes.input} helperText="Some important text" /> + ); } diff --git a/src/Input/Input.js b/src/Input/Input.js index c2b9098e61e051..94a8b311a18553 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -73,6 +73,18 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ // Remove the padding when type=search. appearance: 'none', }, + 'label + $formControl > &': { + '&::-webkit-input-placeholder': { + opacity: 0, + transition: theme.transitions.create('opacity', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.ease, + }), + }, + '&:focus::-webkit-input-placeholder': { + opacity: 1, + }, + }, }, singleline: { height: '1em', From f30dbea50ccbe8980cfa94f32a669d0bdc764c4f Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 23:35:04 +0300 Subject: [PATCH 33/36] Fixes Placeholder styles look ugly. laceholder prefixing is to be impplemented in next JSS versions. --- .../component-demos/text-fields/TextFields.js | 6 ++-- src/Form/FormHelperText.js | 2 +- src/Input/Input.js | 32 ++++++++++++++++++- src/Input/InputLabel.js | 4 ++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/docs/src/pages/component-demos/text-fields/TextFields.js b/docs/src/pages/component-demos/text-fields/TextFields.js index f12ddae3d374fd..af800fa4e53863 100644 --- a/docs/src/pages/component-demos/text-fields/TextFields.js +++ b/docs/src/pages/component-demos/text-fields/TextFields.js @@ -86,11 +86,11 @@ class TextFields extends Component { helperText="Some important text" /> diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 54501bc954d7ad..08c758a8bad9fb 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -70,7 +70,7 @@ FormHelperText.propTypes = { */ classes: PropTypes.object.isRequired, /** - * The CSS class name of the root element. + * @ignore */ className: PropTypes.string, /** diff --git a/src/Input/Input.js b/src/Input/Input.js index 94a8b311a18553..0c0a166598b3a2 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -81,8 +81,38 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ easing: theme.transitions.easing.ease, }), }, + '&::-moz-placeholder': { + opacity: 0, + transition: theme.transitions.create('opacity', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.ease, + }), + }, + '&:-ms-input-placeholder': { + opacity: 0, + transition: theme.transitions.create('opacity', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.ease, + }), + }, + '&:-moz-placeholder': { + opacity: 0, + transition: theme.transitions.create('opacity', { + duration: theme.transitions.duration.shorter, + easing: theme.transitions.easing.ease, + }), + }, '&:focus::-webkit-input-placeholder': { - opacity: 1, + opacity: theme.palette.type === 'light' ? .42 : .5, + }, + '&:focus::-moz-placeholder': { + opacity: theme.palette.type === 'light' ? .42 : .5, + }, + '&:focus:-ms-input-placeholder': { + opacity: theme.palette.type === 'light' ? .42 : .5, + }, + '&:focus:-moz-placeholder': { + opacity: theme.palette.type === 'light' ? .42 : .5, }, }, }, diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 1a8aae156fd742..48e2d913bf7398 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -10,6 +10,8 @@ import { FormLabel } from '../Form'; export const styleSheet = createStyleSheet('MuiInputLabel', theme => ({ root: { transformOrigin: 'top left', + // '-webkit-backface-visibility': 'hidden', + transform: 'translateZ(0)', }, formControl: { position: 'absolute', @@ -18,7 +20,7 @@ export const styleSheet = createStyleSheet('MuiInputLabel', theme => ({ transform: `translate(0, ${theme.spacing.unit * 5}px) scale(1)`, }, shrink: { - transform: `translate(0, ${theme.spacing.unit * 2 + 2.5}px) scale(0.75)`, + transform: `translate(0, ${theme.spacing.unit * 2 + 2}px) scale(0.75)`, transformOrigin: 'top left', }, animated: { From 04199223be295879a62ba46ed48b336ff1bf7de0 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Mon, 29 May 2017 23:37:38 +0300 Subject: [PATCH 34/36] Fixed lint errors --- src/Input/Input.js | 8 ++++---- src/Input/InputLabel.js | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Input/Input.js b/src/Input/Input.js index 0c0a166598b3a2..495920e58e7893 100644 --- a/src/Input/Input.js +++ b/src/Input/Input.js @@ -103,16 +103,16 @@ export const styleSheet = createStyleSheet('MuiInput', theme => ({ }), }, '&:focus::-webkit-input-placeholder': { - opacity: theme.palette.type === 'light' ? .42 : .5, + opacity: theme.palette.type === 'light' ? 0.42 : 0.5, }, '&:focus::-moz-placeholder': { - opacity: theme.palette.type === 'light' ? .42 : .5, + opacity: theme.palette.type === 'light' ? 0.42 : 0.5, }, '&:focus:-ms-input-placeholder': { - opacity: theme.palette.type === 'light' ? .42 : .5, + opacity: theme.palette.type === 'light' ? 0.42 : 0.5, }, '&:focus:-moz-placeholder': { - opacity: theme.palette.type === 'light' ? .42 : .5, + opacity: theme.palette.type === 'light' ? 0.42 : 0.5, }, }, }, diff --git a/src/Input/InputLabel.js b/src/Input/InputLabel.js index 48e2d913bf7398..68a0d26414cd35 100644 --- a/src/Input/InputLabel.js +++ b/src/Input/InputLabel.js @@ -10,8 +10,6 @@ import { FormLabel } from '../Form'; export const styleSheet = createStyleSheet('MuiInputLabel', theme => ({ root: { transformOrigin: 'top left', - // '-webkit-backface-visibility': 'hidden', - transform: 'translateZ(0)', }, formControl: { position: 'absolute', From 30be343729ee64b5ca15cf112ee686b9c130b1cb Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Tue, 30 May 2017 17:21:35 +0300 Subject: [PATCH 35/36] Typo fixes --- src/Form/FormControl.js | 2 +- src/Form/FormHelperText.js | 2 +- src/Form/FormHelperText.spec.js | 2 +- src/Form/FormLabel.js | 2 +- src/Form/FormLabel.spec.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Form/FormControl.js b/src/Form/FormControl.js index da54e1e98e1914..80dae39e1f5430 100644 --- a/src/Form/FormControl.js +++ b/src/Form/FormControl.js @@ -127,7 +127,7 @@ FormControl.propTypes = { */ className: PropTypes.string, /** - * If `true`, the label should be displayed in an disabled state. + * If `true`, the label, input and helper text should be displayed in a disabled state. */ disabled: PropTypes.bool, /** diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index 08c758a8bad9fb..e040b34e52dcb7 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -74,7 +74,7 @@ FormHelperText.propTypes = { */ className: PropTypes.string, /** - * Whether the helper text should be displayed in an disabled state. + * If `true`, the helper text should be displayed in a disabled state. */ disabled: PropTypes.bool, /** diff --git a/src/Form/FormHelperText.spec.js b/src/Form/FormHelperText.spec.js index 64e6e578377ebb..3382c0f50e5c16 100644 --- a/src/Form/FormHelperText.spec.js +++ b/src/Form/FormHelperText.spec.js @@ -22,7 +22,7 @@ describe('', () => { }); describe('prop: error', () => { - it('should show an error class', () => { + it('should have an error class', () => { const wrapper = shallow(); assert.strictEqual(wrapper.hasClass(classes.error), true); }); diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index 78a887fbee6f1d..93776d30349d4c 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -100,7 +100,7 @@ FormLabel.propTypes = { */ className: PropTypes.string, /** - * Whether the label should be displayed in an disabled state. + * If `true`, the label should be displayed in a disabled state. */ disabled: PropTypes.bool, /** diff --git a/src/Form/FormLabel.spec.js b/src/Form/FormLabel.spec.js index c016b3dee0587a..a037d9365ca601 100644 --- a/src/Form/FormLabel.spec.js +++ b/src/Form/FormLabel.spec.js @@ -37,7 +37,7 @@ describe('', () => { }); describe('prop: error', () => { - it('should show an error class', () => { + it('should have an error class', () => { const wrapper = shallow(); const asteriskWrapper = wrapper.find('[data-mui-test="FormLabelAsterisk"]'); assert.strictEqual(asteriskWrapper.length, 1); From 60ae4d7410397b3c661fa7b996d61123206e1563 Mon Sep 17 00:00:00 2001 From: Ruslan Kyba Date: Tue, 30 May 2017 17:22:52 +0300 Subject: [PATCH 36/36] Typo fixes 2 --- src/Form/FormHelperText.js | 2 +- src/Form/FormLabel.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Form/FormHelperText.js b/src/Form/FormHelperText.js index e040b34e52dcb7..ee690cc022c0e7 100644 --- a/src/Form/FormHelperText.js +++ b/src/Form/FormHelperText.js @@ -78,7 +78,7 @@ FormHelperText.propTypes = { */ disabled: PropTypes.bool, /** - * Whether the helper text should be displayed in an error state. + * If `true`, helper text should be displayed in an error state. */ error: PropTypes.bool, }; diff --git a/src/Form/FormLabel.js b/src/Form/FormLabel.js index 93776d30349d4c..599a96b279ec6b 100644 --- a/src/Form/FormLabel.js +++ b/src/Form/FormLabel.js @@ -104,7 +104,7 @@ FormLabel.propTypes = { */ disabled: PropTypes.bool, /** - * Whether the label should be displayed in an error state. + * If `true`, the label should be displayed in an error state. */ error: PropTypes.bool, /**