Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TextField] Extract floating label #2701

Merged
merged 1 commit into from
Dec 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 8 additions & 15 deletions src/TextField/TextField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import DefaultRawTheme from '../styles/raw-themes/light-raw-theme';
import ThemeManager from '../styles/theme-manager';
import ContextPure from '../mixins/context-pure';
import TextFieldHint from './TextFieldHint';
import TextFieldLabel from './TextFieldLabel';
import TextFieldUnderline from './TextFieldUnderline';
import warning from 'warning';

Expand Down Expand Up @@ -118,6 +119,7 @@ const TextField = React.createClass({
let props = (this.props.children) ? this.props.children.props : this.props;

return {
isFocused: false,
errorText: this.props.errorText,
hasValue: isValid(props.value) || isValid(props.defaultValue) ||
(props.valueLink && isValid(props.valueLink.value)),
Expand Down Expand Up @@ -188,16 +190,7 @@ const TextField = React.createClass({
transition: Transitions.easeOut(),
},
floatingLabel: {
position: 'absolute',
lineHeight: '22px',
top: 38,
opacity: 1,
color: hintColor,
transition: Transitions.easeOut(),
zIndex: 1, // Needed to display label above Chrome's autocomplete field background
cursor: 'text',
transform: 'scale(1) translate3d(0, 0, 0)',
transformOrigin: 'left top',
},
input: {
tapHighlightColor: 'rgba(0,0,0,0)',
Expand All @@ -222,15 +215,12 @@ const TextField = React.createClass({
font: 'inherit',
});


if (this.state.isFocused) {
styles.floatingLabel.color = focusColor;
styles.floatingLabel.transform = 'perspective(1px) scale(0.75) translate3d(2px, -28px, 0)';
}

if (this.state.hasValue) {
styles.floatingLabel.color = ColorManipulator.fade(props.disabled ? disabledTextColor : floatingLabelColor, 0.5);
styles.floatingLabel.transform = 'perspective(1px) scale(0.75) translate3d(2px, -28px, 0)';
}

if (props.floatingLabelText) {
Expand Down Expand Up @@ -289,12 +279,15 @@ const TextField = React.createClass({
) : null;

let floatingLabelTextElement = floatingLabelText ? (
<label
style={this.prepareStyles(styles.floatingLabel, this.props.floatingLabelStyle)}
<TextFieldLabel
muiTheme={this.state.muiTheme}
style={this.mergeStyles(styles.floatingLabel, this.props.floatingLabelStyle)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider extracting the rest of the styles from styles.floatingLabel and putting it in the TextFieldLabel component? That way the only thing TextField has to pass is the floatingLabelStyle prop?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose that means we would have to pass a focused or isFocused prop down to the TextFieldLabel so that it knows how to change styles properly. I think I'm doing something similar for the TextFieldUnderline component.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thoughts, but it's not that simple. Doing this will couple the components a LOT. In order to calculate the color, hasError, hasValue and errorColor must too be passed down only to calculate a simple color so I left that calculation to the TextField.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm, okay, I see.

htmlFor={inputId}
shrink={this.state.hasValue || this.state.isFocused}
disabled={disabled}
onTouchTap={this.focus}>
{floatingLabelText}
</label>
</TextFieldLabel>
) : null;

let inputProps;
Expand Down
97 changes: 97 additions & 0 deletions src/TextField/TextFieldLabel.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import Transitions from '../styles/transitions';
import styleUtils from '../utils/styles';

const propTypes = {
/**
* The material-ui theme applied to this component.
*/
muiTheme: React.PropTypes.object.isRequired,

/**
* The css class name of the root element.
*/
className: React.PropTypes.string,

/**
* The label contents.
*/
children: React.PropTypes.node,

/**
* Disables the label if set to true.
*/
disabled: React.PropTypes.bool,

/**
* True if the floating label should shrink.
*/
shrink: React.PropTypes.bool,

/**
* The id of the target element that this label should refer to.
*/
htmlFor: React.PropTypes.string,

/**
* Callback function for when the label is selected via a touch tap.
*/
onTouchTap: React.PropTypes.func,

/**
* Override the inline-styles of the floating label.
*/
style: React.PropTypes.object,
};

const defaultProps = {
disabled: false,
shrink: false,
};

const TextFieldLabel = (props) => {

const {
muiTheme,
className,
children,
disabled,
shrink,
htmlFor,
style,
onTouchTap,
} = props;

const styles = {
root: {
position: 'absolute',
lineHeight: '22px',
top: 38,
transition: Transitions.easeOut(),
zIndex: 1, // Needed to display label above Chrome's autocomplete field background
cursor: disabled ? 'default' : 'text',
transform: shrink
? 'perspective(1px) scale(0.75) translate3d(2px, -28px, 0)'
: 'scale(1) translate3d(0, 0, 0)',
transformOrigin: 'left top',
pointerEvents: shrink ? 'none' : 'auto',
userSelect: 'none',
},
};

return (
<label
className={className}
style={styleUtils.prepareStyles(muiTheme, styles.root, style)}
htmlFor={htmlFor}
onTouchTap={onTouchTap}
>
{children}
</label>
);
};

TextFieldLabel.propTypes = propTypes;
TextFieldLabel.defaultProps = defaultProps;

export default TextFieldLabel;