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

[SelectField,TextField] Refactoring/Popover/Keyboard #3628

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import SelectField from 'material-ui/lib/select-field';
import MenuItem from 'material-ui/lib/menus/menu-item';

export default class SelectFieldExampleSimple extends React.Component {

constructor(props) {
super(props);
this.state = {
open: true,
value: 2,
};
}

handleChange = (event, index, value) => this.setState({value});

render() {
const {open} = this.state;
return (
<div>
<SelectField
open={open}
onRequestClose={() => this.setState({open: false})}
value={this.state.value}
onChange={this.handleChange}
>
<MenuItem value={1} primaryText="Never" />
<MenuItem value={2} primaryText="Every Night" />
<MenuItem value={3} primaryText="Weeknights" />
<MenuItem value={4} primaryText="Weekends" />
<MenuItem value={5} primaryText="Weekly" />
</SelectField>
<br />
<SelectField value={1} disabled={true}>
<MenuItem value={1} primaryText="Never" />
<MenuItem value={2} primaryText="Every Night" />
</SelectField>
</div>
);
}
}
10 changes: 10 additions & 0 deletions docs/src/app/components/pages/components/SelectField/Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import SelectFieldExampleCustomLabel from './ExampleCustomLabel';
import selectFieldExampleCustomLabelCode from '!raw!./ExampleCustomLabel';
import SelectFieldExampleFloatingLabel from './ExampleFloatingLabel';
import selectFieldExampleFloatingLabelCode from '!raw!./ExampleFloatingLabel';
import SelectFieldExampleOpenOnMount from './ExampleOpenOnMount';
import selectFieldExampleOpenOnMountCode from '!raw!./ExampleOpenOnMount';
import SelectFieldExampleError from './ExampleError';
import selectFieldExampleErrorCode from '!raw!./ExampleError';
import selectFieldCode from '!raw!material-ui/lib/SelectField/SelectField';
Expand Down Expand Up @@ -70,6 +72,14 @@ const SelectFieldPage = () => (
>
<SelectFieldExampleError />
</CodeExample>

<CodeExample
title="Open on mount"
description={descriptions.errorText}
code={selectFieldExampleOpenOnMountCode}
>
<SelectFieldExampleOpenOnMount />
</CodeExample>
<PropTypeDescription code={selectFieldCode} />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"homepage": "http://material-ui.com/",
"dependencies": {
"inline-style-prefixer": "^1.0.1",
"keycode": "^2.1.0",
"keycode": "^2.1.1",
"lodash.flowright": "^3.2.1",
"lodash.merge": "^4.1.0",
"lodash.throttle": "^4.0.0",
Expand Down
215 changes: 161 additions & 54 deletions src/SelectField/SelectField.jsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
import React from 'react';
import TextField from '../text-field';
import DropDownMenu from '../DropDownMenu';
import ReactDom from 'react-dom';
import TextFieldDecorator from '../TextField/TextFieldDecorator';
import SelectFieldMenu from './SelectFieldMenu';
import SelectFieldLabel from './SelectFieldLabel';
import getMuiTheme from '../styles/getMuiTheme';

function getStyles(props) {
return {
label: {
paddingLeft: 0,
top: props.floatingLabelText ? 6 : -4,
},
icon: {
right: 0,
top: props.floatingLabelText ? 22 : 14,
},
hideDropDownUnderline: {
borderTop: 'none',
},
};
}
import keycode from 'keycode';

const SelectField = React.createClass({

Expand Down Expand Up @@ -82,6 +69,11 @@ const SelectField = React.createClass({
*/
iconStyle: React.PropTypes.object,

/**
* The id prop for the text field.
*/
id: React.PropTypes.string,

/**
* Overrides the styles of label when the `SelectField` is inactive.
*/
Expand All @@ -102,6 +94,15 @@ const SelectField = React.createClass({
*/
onFocus: React.PropTypes.func,

/**
* Callback function that is fired when the `SelectField` is closed.
*/
onRequestClose: React.PropTypes.func,

/**
* Property controlling whether the `SelectField` is open. Use to open `DropDown` on mount.
*/
open: React.PropTypes.bool,
/**
* The style object to use to override the `DropDownMenu`.
*/
Expand All @@ -112,6 +113,8 @@ const SelectField = React.createClass({
*/
style: React.PropTypes.object,

tabIndex: React.PropTypes.number,

/**
* Override the inline-styles of the underline element when disabled.
*/
Expand Down Expand Up @@ -146,12 +149,16 @@ const SelectField = React.createClass({
autoWidth: false,
disabled: false,
fullWidth: false,
id: 'select',
open: false,
tabIndex: 0,
};
},

getInitialState() {
return {
muiTheme: this.context.muiTheme || getMuiTheme(),
open: false,
};
},

Expand All @@ -161,70 +168,170 @@ const SelectField = React.createClass({
};
},

componentWillMount() {
if (this.props.open) {
/* eslint react/no-did-mount-set-state: 0 */
/* because we're using ref for popover anchorEl */
this.setState({open: true});
}
},

componentWillReceiveProps(nextProps, nextContext) {
this.setState({
muiTheme: nextContext.muiTheme || this.state.muiTheme,
open: nextProps.open,
});
},

componentWillUnmount() {
this.label = null;
},

handleMenuRequestClose() {
this.setState({
open: false,
isFocused: true,
}, () => this.label.focus());
const {onRequestClose} = this.props;
return onRequestClose ? onRequestClose() : null;
},

handleTouchTap() {
if (this.props.disabled)
return;

this.setState({
open: true,
isFocused: false,
});
},

onFocus() {
if (this.props.disabled)
return;
this.setState({isFocused: true});
const {onFocus} = this.props;
return onFocus ? onFocus() : null;
},

onBlur() {
const {onBlur} = this.props;
this.setState({isFocused: false});
return onBlur ? onBlur() : null;
},

handleKeyDown(event) {
switch (keycode(event)) {
case 'enter':
case 'space':
case 'down':
event.preventDefault();
if (!this.props.disabled) {
this.setState({
open: !this.state.open,
anchorEl: this.refs.root,
});
}
}
},

render() {
const {
autoWidth,
children,
style,
labelStyle,
iconStyle,
underlineDisabledStyle,
underlineFocusStyle,
underlineStyle,
errorStyle,
selectFieldRoot,
disabled,
floatingLabelText,
errorStyle,
errorText,
floatingLabelStyle,
floatingLabelText,
fullWidth,
hintStyle,
hintText,
fullWidth,
errorText,
onFocus,
iconStyle,
id,
labelStyle,
onBlur,
onChange,
selectFieldRoot,
style,
tabIndex,
underlineDisabledStyle,
underlineFocusStyle,
underlineStyle,
value,
...other,
} = this.props;

const styles = getStyles(this.props, this.state);
const {
isFocused,
} = this.state;

const {open, muiTheme} = this.state;
const errorStylePrepared = Object.assign({}, errorStyle, {position: 'absolute', bottom: -10});
const floatingLabelStylePrepared = Object.assign({}, floatingLabelStyle, {cursor: 'pointer'});
// ^^^^^^^^^^^^^^^^^
// current implementation
// doesn't do this, but should
let displayValue = '';
React.Children.forEach(children, (child) => {
if (value === child.props.value) {
// This will need to be improved (in case primaryText is a node)
displayValue = child.props.label || child.props.primaryText;
}
});
const selecter = (
<SelectFieldLabel
disabled={disabled}
muiTheme={muiTheme}
onBlur={this.onBlur}
onFocus={this.onFocus}
onKeyDown={this.handleKeyDown}
onTouchTap={this.handleTouchTap}
ref={(c) => this.label = ReactDom.findDOMNode(c)}
style={labelStyle}
value={displayValue}
/>
);

const menu = (
<SelectFieldMenu
{...other}
anchorEl={this.label}
autoWidth={autoWidth}
floatingLabelText={floatingLabelText}
onChange={onChange}
onRequestClose={this.handleMenuRequestClose}
open={open}
value={value}
>
{children}
</SelectFieldMenu>
);

return (
<TextField
style={style}
<TextFieldDecorator
disabled={disabled}
errorStyle={errorStylePrepared}
errorText={errorText}
floatingLabelStyle={floatingLabelStylePrepared}
floatingLabelText={floatingLabelText}
floatingLabelStyle={floatingLabelStyle}
fullWidth={fullWidth}
hasValue={true}
height={24}
hintStyle={hintStyle}
hintText={(!hintText && !floatingLabelText) ? ' ' : hintText}
fullWidth={fullWidth}
errorText={errorText}
underlineStyle={underlineStyle}
errorStyle={errorStyle}
onFocus={onFocus}
onBlur={onBlur}
id={id}
isFocused={isFocused}
muiTheme={muiTheme}
style={style}
tabIndex={tabIndex}
underlineDisabledStyle={underlineDisabledStyle}
underlineFocusStyle={underlineFocusStyle}
underlineStyle={underlineStyle}
>
<DropDownMenu
disabled={disabled}
style={selectFieldRoot}
labelStyle={Object.assign(styles.label, labelStyle)}
iconStyle={Object.assign(styles.icon, iconStyle)}
underlineStyle={styles.hideDropDownUnderline}
autoWidth={autoWidth}
value={value}
onChange={onChange}
{...other}
>
{children}
</DropDownMenu>
</TextField>
{selecter}
{menu}
</TextFieldDecorator>
);
},
});
Expand Down