Skip to content

Commit

Permalink
Change input types to be hidden via CSS so autoComplete can be used
Browse files Browse the repository at this point in the history
  • Loading branch information
mmintel committed Nov 29, 2017
1 parent 6cc59dd commit 56f4cac
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 6 deletions.
2 changes: 2 additions & 0 deletions examples/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import NumericSelect from './components/NumericSelect';
import BooleanSelect from './components/BooleanSelect';
import Virtualized from './components/Virtualized';
import States from './components/States';
import AutoComplete from './components/AutoComplete';

ReactDOM.render(
<div>
<States label="States" searchable />
<AutoComplete label="AutoComplete (testing only example)" autoComplete="country" />
<Multiselect label="Multiselect" />
<Virtualized label="Virtualized" />
<Contributors label="Contributors (Async)" />
Expand Down
78 changes: 78 additions & 0 deletions examples/src/components/AutoComplete.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';
import createClass from 'create-react-class';
import PropTypes from 'prop-types';
import Select from 'react-select';

const STATES = require('../data/states');

var AutoCompleteField = createClass({
displayName: 'AutoCompleteField',
propTypes: {
label: PropTypes.string,
searchable: PropTypes.bool,
},
componentDidMount() {
// reveal hidden input for testing
document.querySelector('[autocomplete="country"]').classList.remove('Select-hidden');
},
getDefaultProps () {
return {
label: 'States:',
searchable: true,
};
},
getInitialState () {
return {
selectValue: '',
clearable: true,
rtl: false,
};
},
switchCountry (e) {
var newCountry = e.target.value;
this.setState({
country: newCountry,
selectValue: null,
});
},
updateValue (newValue) {
this.setState({
selectValue: newValue,
});
},
toggleCheckbox (e) {
let newState = {};
newState[e.target.name] = e.target.checked;
this.setState(newState);
},
render () {
var options = [
{ value: 'EN', label: 'England' },
{ value: 'DE', label: 'Germany' },
];
return (
<div className="section">
<h3 className="section-heading">{this.props.label} <a href="https://github.com/JedWatson/react-select/tree/master/examples/src/components/AutoComplete.js">(Source)</a></h3>
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<input placeholder="email" type="email" autoComplete="email" />
</div>
<Select
id="country"
ref="autoCompleteSelect"
autoFocus
autosize={false}
options={options}
simpleValue
joinValues
name="country"
value={this.state.selectValue}
onChange={this.updateValue}
autoComplete={this.props.autoComplete}
/>
</div>
);
}
});


module.exports = AutoCompleteField;
13 changes: 13 additions & 0 deletions less/control.less
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,19 @@
float: left;
}

// visually hidden fields

.Select-hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}

// Animation
// ------------------------------

Expand Down
12 changes: 11 additions & 1 deletion scss/control.scss
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,18 @@
position: relative;
}

// visually hidden fields


.Select-hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}

// Animation
// ------------------------------
Expand Down
41 changes: 36 additions & 5 deletions src/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Select extends React.Component {
'handleMouseDownOnArrow',
'handleMouseDownOnMenu',
'handleRequired',
'handleSelect',
'handleTouchOutside',
'handleTouchMove',
'handleTouchStart',
Expand All @@ -59,10 +60,12 @@ class Select extends React.Component {
'onOptionRef',
'removeValue',
'selectValue',
'handleHiddenInputChange',
].forEach((fn) => this[fn] = this[fn].bind(this));

this.state = {
inputValue: '',
isAutoFilled: false,
isFocused: false,
isOpen: false,
isPseudoFocused: false,
Expand Down Expand Up @@ -345,7 +348,6 @@ class Select extends React.Component {
if (this.state.inputValue !== event.target.value) {
newInputValue = this.handleInputValueChange(newInputValue);
}

this.setState({
isOpen: true,
isPseudoFocused: false,
Expand All @@ -364,9 +366,24 @@ class Select extends React.Component {
return newValue;
}

handleHiddenInputChange (e) {
this.selectValue({ value: e.target.value });
// basically a change event on the hidden field means the autoComplete function of the browser was used
this.setState({
isAutoFilled: true,
});
}


handleKeyDown (event) {
if (this.props.disabled) return;

if (event.key !== 'Unidentified') {
this.setState({
isAutoFilled: false,
});
}

if (typeof this.props.onInputKeyDown === 'function') {
this.props.onInputKeyDown(event);
if (event.defaultPrevented) {
Expand Down Expand Up @@ -587,6 +604,13 @@ class Select extends React.Component {
this.focus();
}

handleSelect (value) {
this.setState({
isAutoFilled: false,
});
this.selectValue(value);
}

clearValue (event) {
// if the event was triggered by a mousedown and not the primary
// button, ignore it.
Expand All @@ -598,6 +622,7 @@ class Select extends React.Component {
this.setValue(this.getResetValue());
this.setState({
isOpen: false,
isAutoFilled: false,
inputValue: this.handleInputValueChange(''),
}, this.focus);
}
Expand Down Expand Up @@ -817,7 +842,7 @@ class Select extends React.Component {
onFocus={this.handleInputFocus}
ref={ref => this.input = ref}
aria-disabled={'' + !!this.props.disabled}
style={{ border: 0, width: 1, display:'inline-block' }}/>
style={{ border: 0 }}/>
);
}

Expand Down Expand Up @@ -919,7 +944,7 @@ class Select extends React.Component {
instancePrefix: this._instancePrefix,
labelKey: this.props.labelKey,
onFocus: this.focusOption,
onSelect: this.selectValue,
onSelect: this.handleSelect,
optionClassName: this.props.optionClassName,
optionComponent: this.props.optionComponent,
optionRenderer: this.props.optionRenderer || this.getOptionLabel,
Expand Down Expand Up @@ -947,17 +972,21 @@ class Select extends React.Component {
let value = valueArray.map(i => stringifyValue(i[this.props.valueKey])).join(this.props.delimiter);
return (
<input
type="hidden"
className="Select-hidden"
onChange={this.handleHiddenInputChange}
ref={ref => this.value = ref}
autoComplete={this.props.autoComplete}
name={this.props.name}
value={value}
disabled={this.props.disabled} />
);
}
return valueArray.map((item, index) => (
<input key={'hidden.' + index}
type="hidden"
className="Select-hidden"
onChange={this.handleHiddenInputChange}
ref={'value' + index}
autoComplete={this.props.autoComplete}
name={this.props.name}
value={stringifyValue(item[this.props.valueKey])}
disabled={this.props.disabled} />
Expand Down Expand Up @@ -1024,6 +1053,7 @@ class Select extends React.Component {
let className = classNames('Select', this.props.className, {
'Select--multi': this.props.multi,
'Select--single': !this.props.multi,
'is-autofilled': this.state.isAutoFilled,
'is-clearable': this.props.clearable,
'is-disabled': this.props.disabled,
'is-focused': this.state.isFocused,
Expand Down Expand Up @@ -1084,6 +1114,7 @@ Select.propTypes = {
'aria-labelledby': PropTypes.string, // HTML ID of an element that should be used as the label (for assistive tech)
arrowRenderer: PropTypes.func, // Create drop-down caret element
autoBlur: PropTypes.bool, // automatically blur the component when an option is selected
autoComplete: PropTypes.string, // support for form auto completion
autoFocus: PropTypes.bool, // autofocus the component on mount
autofocus: PropTypes.bool, // deprecated; use autoFocus instead
autosize: PropTypes.bool, // whether to enable autosizing or not
Expand Down

0 comments on commit 56f4cac

Please sign in to comment.