mirror of
https://github.com/danog/react-datalist-input.git
synced 2024-12-11 17:09:39 +01:00
went linting
This commit is contained in:
parent
7ef3ff88e5
commit
c7a31b06e4
@ -1,18 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import './DataListInput.css';
|
import './input.scss';
|
||||||
|
|
||||||
class DataListInput extends React.Component {
|
class DataListInput extends React.Component {
|
||||||
|
constructor( props ) {
|
||||||
constructor(props) {
|
super( props );
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
/* last valid item that was selected from the drop down menu */
|
/* last valid item that was selected from the drop down menu */
|
||||||
lastValidItem: undefined,
|
lastValidItem: undefined,
|
||||||
/* current input text */
|
/* current input text */
|
||||||
currentInput: "",
|
currentInput: '',
|
||||||
/* current set of matching items */
|
/* current set of matching items */
|
||||||
matchingItems: [],
|
matchingItems: [],
|
||||||
/* visibility property of the drop down menu */
|
/* visibility property of the drop down menu */
|
||||||
@ -24,32 +23,32 @@ class DataListInput extends React.Component {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* gets called when someone starts to write in the input field
|
* gets called when someone starts to write in the input field
|
||||||
* @param event
|
* @param value
|
||||||
*/
|
*/
|
||||||
onHandleInput = (event) => {
|
onHandleInput = ( event ) => {
|
||||||
const currentInput = event.target.value;
|
const currentInput = event.target.value;
|
||||||
const matchingItems = this.props.items.filter((item) => {
|
const { items, match } = this.props;
|
||||||
if (typeof(this.props.match) === typeof(Function))
|
const matchingItems = items.filter( ( item ) => {
|
||||||
return this.props.match(currentInput, item);
|
if ( typeof ( match ) === typeof ( Function ) ) { return match( currentInput, item ); }
|
||||||
return this.match(currentInput, item);
|
return this.match( currentInput, item );
|
||||||
});
|
} );
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: currentInput,
|
currentInput,
|
||||||
matchingItems: matchingItems,
|
matchingItems,
|
||||||
focusIndex: 0,
|
focusIndex: 0,
|
||||||
visible: true,
|
visible: true,
|
||||||
});
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* default function for matching the current input value (needle) and the values of the items array
|
* default function for matching the current input value (needle)
|
||||||
|
* and the values of the items array
|
||||||
* @param currentInput
|
* @param currentInput
|
||||||
* @param item
|
* @param item
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
match = (currentInput, item) => {
|
match = ( currentInput, item ) => item
|
||||||
return item.label.substr(0, currentInput.length).toUpperCase() === currentInput.toUpperCase();
|
.label.substr( 0, currentInput.length ).toUpperCase() === currentInput.toUpperCase();
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* function for getting the index of the currentValue inside a value of the values array
|
* function for getting the index of the currentValue inside a value of the values array
|
||||||
@ -57,40 +56,40 @@ class DataListInput extends React.Component {
|
|||||||
* @param item
|
* @param item
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
indexOfMatch = (currentInput, item) => {
|
indexOfMatch = ( currentInput, item ) => item
|
||||||
return item.label.toUpperCase().indexOf(currentInput.toUpperCase());
|
.label.toUpperCase().indexOf( currentInput.toUpperCase() );
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle key events
|
* handle key events
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onHandleKeydown = (event) => {
|
onHandleKeydown = ( event ) => {
|
||||||
|
const { visible, focusIndex, matchingItems } = this.state;
|
||||||
// only do something if drop-down div is visible
|
// only do something if drop-down div is visible
|
||||||
if (!this.state.visible) return;
|
if ( !visible ) return;
|
||||||
let currentFocusIndex = this.state.focusIndex;
|
let currentFocusIndex = focusIndex;
|
||||||
if (event.keyCode === 40 || event.keyCode === 9) {
|
if ( event.keyCode === 40 || event.keyCode === 9 ) {
|
||||||
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
|
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
|
||||||
currentFocusIndex += 1;
|
currentFocusIndex += 1;
|
||||||
if (currentFocusIndex >= this.state.matchingItems.length) currentFocusIndex = 0;
|
if ( currentFocusIndex >= matchingItems.length ) currentFocusIndex = 0;
|
||||||
this.setState({
|
this.setState( {
|
||||||
focusIndex: currentFocusIndex,
|
focusIndex: currentFocusIndex,
|
||||||
});
|
} );
|
||||||
// prevent tab to jump to the next input field if drop down is still open
|
// prevent tab to jump to the next input field if drop down is still open
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (event.keyCode === 38) {
|
} else if ( event.keyCode === 38 ) {
|
||||||
// If the arrow UP key is pressed, decrease the currentFocus variable:
|
// If the arrow UP key is pressed, decrease the currentFocus variable:
|
||||||
currentFocusIndex -= 1;
|
currentFocusIndex -= 1;
|
||||||
if (currentFocusIndex <= -1) currentFocusIndex = this.state.matchingItems.length - 1;
|
if ( currentFocusIndex <= -1 ) currentFocusIndex = matchingItems.length - 1;
|
||||||
this.setState({
|
this.setState( {
|
||||||
focusIndex: currentFocusIndex,
|
focusIndex: currentFocusIndex,
|
||||||
});
|
} );
|
||||||
} else if (event.keyCode === 13) {
|
} else if ( event.keyCode === 13 ) {
|
||||||
// Enter pressed, similar to onClickItem
|
// Enter pressed, similar to onClickItem
|
||||||
if (this.state.focusIndex > -1) {
|
if ( focusIndex > -1 ) {
|
||||||
// Simulate a click on the "active" item:
|
// Simulate a click on the "active" item:
|
||||||
const selectedItem = this.state.matchingItems[currentFocusIndex];
|
const selectedItem = matchingItems[ currentFocusIndex ];
|
||||||
this.onSelect(selectedItem);
|
this.onSelect( selectedItem );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -99,11 +98,19 @@ class DataListInput extends React.Component {
|
|||||||
* onClickItem gets called when onClick happens on one of the list elements
|
* onClickItem gets called when onClick happens on one of the list elements
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onClickItem = (event) => {
|
onClickItem = ( event ) => {
|
||||||
|
const { matchingItems } = this.state;
|
||||||
// update the input value and close the dropdown again
|
// update the input value and close the dropdown again
|
||||||
const selectedKey = event.currentTarget.children[1].value;
|
const elements = event.currentTarget.children;
|
||||||
const selectedItem = this.state.matchingItems.find(item => item.key === selectedKey);
|
let selectedKey;
|
||||||
this.onSelect(selectedItem);
|
for ( let i = 0; i < elements.length; i += 1 ) {
|
||||||
|
if ( elements[ i ].tagName === 'INPUT' ) {
|
||||||
|
selectedKey = Number( elements[ i ].value );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const selectedItem = matchingItems.find( item => item.key === selectedKey );
|
||||||
|
this.onSelect( selectedItem );
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,63 +118,89 @@ class DataListInput extends React.Component {
|
|||||||
* does nothing if the key has not changed since the last onSelect event
|
* does nothing if the key has not changed since the last onSelect event
|
||||||
* @param selectedItem
|
* @param selectedItem
|
||||||
*/
|
*/
|
||||||
onSelect = (selectedItem) => {
|
onSelect = ( selectedItem ) => {
|
||||||
if (this.state.lastValidItem !== undefined && selectedItem.key === this.state.lastValidItem.key){
|
console.log( selectedItem );
|
||||||
|
const { lastValidItem } = this.state;
|
||||||
|
if ( lastValidItem && selectedItem.key === lastValidItem.key ) {
|
||||||
// do not trigger the callback function
|
// do not trigger the callback function
|
||||||
// but still change state to fit new selection
|
// but still change state to fit new selection
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: selectedItem.label,
|
currentInput: selectedItem.label,
|
||||||
visible: false,
|
visible: false,
|
||||||
focusIndex: -1,
|
focusIndex: -1,
|
||||||
});
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// change state to fit new selection
|
// change state to fit new selection
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: selectedItem.label,
|
currentInput: selectedItem.label,
|
||||||
lastValidItem: selectedItem,
|
lastValidItem: selectedItem,
|
||||||
visible: false,
|
visible: false,
|
||||||
focusIndex: -1,
|
focusIndex: -1,
|
||||||
});
|
} );
|
||||||
// callback function onSelect
|
// callback function onSelect
|
||||||
this.props.onSelect(selectedItem);
|
const { onSelect } = this.props;
|
||||||
|
onSelect( selectedItem );
|
||||||
};
|
};
|
||||||
|
|
||||||
renderItems = ( items, focusIndex, activeItemClassName, itemClassName) => (
|
renderItemLabel = ( currentInput, item ) => (
|
||||||
|
<React.Fragment>
|
||||||
|
{item.label.substr( 0, this.indexOfMatch( currentInput, item ) )}
|
||||||
|
<strong>
|
||||||
|
{item.label.substr( this.indexOfMatch( currentInput, item ), currentInput.length )}
|
||||||
|
</strong>
|
||||||
|
{item.label.substr( this.indexOfMatch( currentInput, item ) + currentInput.length )}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
|
||||||
|
renderItems = ( currentInput, items, focusIndex, activeItemClassName, itemClassName ) => (
|
||||||
<div className="datalist-items">
|
<div className="datalist-items">
|
||||||
{items.map((item, i) => {
|
{items.map( ( item, i ) => {
|
||||||
const isActive = focusIndex === i;
|
const isActive = focusIndex === i;
|
||||||
const itemActiveClasses = isActive ? `datalist-active-item ${activeItemClassName}` : ''
|
const itemActiveClasses = isActive ? `datalist-active-item ${ activeItemClassName }` : '';
|
||||||
const itemClasses = `${itemClassName} ${itemActiveClasses};`
|
const itemClasses = `${ itemClassName } ${ itemActiveClasses };`;
|
||||||
return (
|
return (
|
||||||
<div onClick={this.onClickItem}
|
<div
|
||||||
className={itemClasses}
|
onClick={this.onClickItem}
|
||||||
key={item.key}>
|
className={itemClasses}
|
||||||
{item.label.substr(0, this.indexOfMatch(currentInput, item))}
|
key={item.key}
|
||||||
<strong>{item.label.substr(this.indexOfMatch(currentInput, item), currentInput.length)}</strong>
|
tabIndex={0}
|
||||||
{item.label.substr(this.indexOfMatch(currentInput, item) + currentInput.length)}
|
role="button"
|
||||||
<input type='hidden' value={item.key}/>
|
onKeyUp={event => event.preventDefault()}
|
||||||
|
>
|
||||||
|
{ this.renderItemLabel( currentInput, item )}
|
||||||
|
<input type="hidden" value={item.key} />
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
})}
|
} )}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
renderInputField = ( placeholder, currentInput, inputClassName ) => (
|
renderInputField = ( placeholder, currentInput, inputClassName ) => (
|
||||||
<input onKeyDown={this.onHandleKeydown} onInput={this.onHandleInput} type="text"
|
<input
|
||||||
className={ `autocomplete-input ${inputClassName}` }
|
onChange={this.onHandleInput}
|
||||||
placeholder={placeholder} value={currentInput}/>
|
onKeyDown={this.onHandleKeydown}
|
||||||
|
type="text"
|
||||||
|
className={`autocomplete-input ${ inputClassName }`}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={currentInput}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { currentInput, matchingItems, focusIndex, visible } = this.state;
|
const {
|
||||||
const { placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength } = this.props;
|
currentInput, matchingItems, focusIndex, visible,
|
||||||
|
} = this.state;
|
||||||
|
const {
|
||||||
|
placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength,
|
||||||
|
} = this.props;
|
||||||
const reachedRequiredLength = currentInput.length >= requiredInputLength;
|
const reachedRequiredLength = currentInput.length >= requiredInputLength;
|
||||||
return (
|
return (
|
||||||
<div className="datalist-input">
|
<div className="datalist-input">
|
||||||
{ this.renderInputField( placeholder, currentInput, inputClassName ) }
|
{ this.renderInputField( placeholder, currentInput, inputClassName ) }
|
||||||
{ reachedRequiredLength && visible &&
|
{ reachedRequiredLength && visible
|
||||||
this.renderItems( matchingItems, focusIndex, activeItemClassName, itemClassName )
|
&& this.renderItems( currentInput, matchingItems, focusIndex,
|
||||||
|
activeItemClassName, itemClassName )
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -175,7 +208,12 @@ class DataListInput extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataListInput.propTypes = {
|
DataListInput.propTypes = {
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape( {
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
key: PropTypes.number.isRequired,
|
||||||
|
} ),
|
||||||
|
).isRequired,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
match: PropTypes.func,
|
match: PropTypes.func,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-datalist-input",
|
"name": "react-datalist-input",
|
||||||
"version": "1.0.8",
|
"version": "1.0.11",
|
||||||
"description": "This package provides a react component as follows: an input field with a drop down menu to pick a possible option based on the current input.",
|
"description": "This package provides a react component as follows: an input field with a drop down menu to pick a possible option based on the current input.",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
180
src/index.js
180
src/index.js
@ -29,35 +29,37 @@ class DataListInput extends React.Component {
|
|||||||
this.onSelect = this.onSelect.bind(this);
|
this.onSelect = this.onSelect.bind(this);
|
||||||
this.renderItems = this.renderItems.bind(this);
|
this.renderItems = this.renderItems.bind(this);
|
||||||
this.renderInputField = this.renderInputField.bind(this);
|
this.renderInputField = this.renderInputField.bind(this);
|
||||||
|
this.renderItemLabel = this.renderItemLabel.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gets called when someone starts to write in the input field
|
* gets called when someone starts to write in the input field
|
||||||
* @param event
|
* @param value
|
||||||
*/
|
*/
|
||||||
onHandleInput(event) {
|
onHandleInput( event ){
|
||||||
const currentInput = event.target.value;
|
const currentInput = event.target.value;
|
||||||
const matchingItems = this.props.items.filter((item) => {
|
const { items, match } = this.props;
|
||||||
if (typeof(this.props.match) === typeof(Function))
|
const matchingItems = items.filter( ( item ) => {
|
||||||
return this.props.match(currentInput, item);
|
if ( typeof ( match ) === typeof ( Function ) ) { return match( currentInput, item ); }
|
||||||
return this.match(currentInput, item);
|
return this.match( currentInput, item );
|
||||||
});
|
} );
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: currentInput,
|
currentInput,
|
||||||
matchingItems: matchingItems,
|
matchingItems,
|
||||||
focusIndex: 0,
|
focusIndex: 0,
|
||||||
visible: true,
|
visible: true,
|
||||||
});
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* default function for matching the current input value (needle) and the values of the items array
|
* default function for matching the current input value (needle)
|
||||||
|
* and the values of the items array
|
||||||
* @param currentInput
|
* @param currentInput
|
||||||
* @param item
|
* @param item
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
match(currentInput, item) {
|
match( currentInput, item ) {
|
||||||
return item.label.substr(0, currentInput.length).toUpperCase() === currentInput.toUpperCase();
|
return item.label.substr( 0, currentInput.length ).toUpperCase() === currentInput.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,40 +68,41 @@ class DataListInput extends React.Component {
|
|||||||
* @param item
|
* @param item
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
indexOfMatch(currentInput, item) {
|
indexOfMatch( currentInput, item ) {
|
||||||
return item.label.toUpperCase().indexOf(currentInput.toUpperCase());
|
return item.label.toUpperCase().indexOf( currentInput.toUpperCase() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle key events
|
* handle key events
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onHandleKeydown(event) {
|
onHandleKeydown( event ) {
|
||||||
|
const { visible, focusIndex, matchingItems } = this.state;
|
||||||
// only do something if drop-down div is visible
|
// only do something if drop-down div is visible
|
||||||
if (!this.state.visible) return;
|
if ( !visible ) return;
|
||||||
let currentFocusIndex = this.state.focusIndex;
|
let currentFocusIndex = focusIndex;
|
||||||
if (event.keyCode === 40 || event.keyCode === 9) {
|
if ( event.keyCode === 40 || event.keyCode === 9 ) {
|
||||||
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
|
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
|
||||||
currentFocusIndex += 1;
|
currentFocusIndex += 1;
|
||||||
if (currentFocusIndex >= this.state.matchingItems.length) currentFocusIndex = 0;
|
if ( currentFocusIndex >= matchingItems.length ) currentFocusIndex = 0;
|
||||||
this.setState({
|
this.setState( {
|
||||||
focusIndex: currentFocusIndex,
|
focusIndex: currentFocusIndex,
|
||||||
});
|
} );
|
||||||
// prevent tab to jump to the next input field if drop down is still open
|
// prevent tab to jump to the next input field if drop down is still open
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (event.keyCode === 38) {
|
} else if ( event.keyCode === 38 ) {
|
||||||
// If the arrow UP key is pressed, decrease the currentFocus variable:
|
// If the arrow UP key is pressed, decrease the currentFocus variable:
|
||||||
currentFocusIndex -= 1;
|
currentFocusIndex -= 1;
|
||||||
if (currentFocusIndex <= -1) currentFocusIndex = this.state.matchingItems.length - 1;
|
if ( currentFocusIndex <= -1 ) currentFocusIndex = matchingItems.length - 1;
|
||||||
this.setState({
|
this.setState( {
|
||||||
focusIndex: currentFocusIndex,
|
focusIndex: currentFocusIndex,
|
||||||
});
|
} );
|
||||||
} else if (event.keyCode === 13) {
|
} else if ( event.keyCode === 13 ) {
|
||||||
// Enter pressed, similar to onClickItem
|
// Enter pressed, similar to onClickItem
|
||||||
if (this.state.focusIndex > -1) {
|
if ( focusIndex > -1 ) {
|
||||||
// Simulate a click on the "active" item:
|
// Simulate a click on the "active" item:
|
||||||
const selectedItem = this.state.matchingItems[currentFocusIndex];
|
const selectedItem = matchingItems[ currentFocusIndex ];
|
||||||
this.onSelect(selectedItem);
|
this.onSelect( selectedItem );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,11 +111,19 @@ class DataListInput extends React.Component {
|
|||||||
* onClickItem gets called when onClick happens on one of the list elements
|
* onClickItem gets called when onClick happens on one of the list elements
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
onClickItem(event) {
|
onClickItem( event ) {
|
||||||
|
const { matchingItems } = this.state;
|
||||||
// update the input value and close the dropdown again
|
// update the input value and close the dropdown again
|
||||||
const selectedKey = event.currentTarget.children[1].value;
|
const elements = event.currentTarget.children;
|
||||||
const selectedItem = this.state.matchingItems.find(item => item.key === selectedKey);
|
let selectedKey;
|
||||||
this.onSelect(selectedItem);
|
for ( let i = 0; i < elements.length; i += 1 ) {
|
||||||
|
if ( elements[ i ].tagName === 'INPUT' ) {
|
||||||
|
selectedKey = Number( elements[ i ].value );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const selectedItem = matchingItems.find( item => item.key === selectedKey );
|
||||||
|
this.onSelect( selectedItem );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,65 +131,93 @@ class DataListInput extends React.Component {
|
|||||||
* does nothing if the key has not changed since the last onSelect event
|
* does nothing if the key has not changed since the last onSelect event
|
||||||
* @param selectedItem
|
* @param selectedItem
|
||||||
*/
|
*/
|
||||||
onSelect(selectedItem) {
|
onSelect( selectedItem ) {
|
||||||
if (this.state.lastValidItem !== undefined && selectedItem.key === this.state.lastValidItem.key){
|
const { lastValidItem } = this.state;
|
||||||
|
if ( lastValidItem && selectedItem.key === lastValidItem.key ) {
|
||||||
// do not trigger the callback function
|
// do not trigger the callback function
|
||||||
// but still change state to fit new selection
|
// but still change state to fit new selection
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: selectedItem.label,
|
currentInput: selectedItem.label,
|
||||||
visible: false,
|
visible: false,
|
||||||
focusIndex: -1,
|
focusIndex: -1,
|
||||||
});
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// change state to fit new selection
|
// change state to fit new selection
|
||||||
this.setState({
|
this.setState( {
|
||||||
currentInput: selectedItem.label,
|
currentInput: selectedItem.label,
|
||||||
lastValidItem: selectedItem,
|
lastValidItem: selectedItem,
|
||||||
visible: false,
|
visible: false,
|
||||||
focusIndex: -1,
|
focusIndex: -1,
|
||||||
});
|
} );
|
||||||
// callback function onSelect
|
// callback function onSelect
|
||||||
this.props.onSelect(selectedItem);
|
const { onSelect } = this.props;
|
||||||
|
onSelect( selectedItem );
|
||||||
}
|
}
|
||||||
|
|
||||||
renderItems( items, focusIndex, activeItemClassName, itemClassName) {
|
renderItemLabel( currentInput, item ) {
|
||||||
return (
|
return (
|
||||||
<div className="datalist-items">
|
<React.Fragment>
|
||||||
{items.map((item, i) => {
|
{item.label.substr( 0, this.indexOfMatch( currentInput, item ) )}
|
||||||
const isActive = focusIndex === i;
|
<strong>
|
||||||
const itemActiveClasses = isActive ? `datalist-active-item ${activeItemClassName}` : ''
|
{item.label.substr( this.indexOfMatch( currentInput, item ), currentInput.length )}
|
||||||
const itemClasses = `${itemClassName} ${itemActiveClasses};`
|
</strong>
|
||||||
return (
|
{item.label.substr( this.indexOfMatch( currentInput, item ) + currentInput.length )}
|
||||||
<div onClick={this.onClickItem}
|
</React.Fragment>
|
||||||
className={itemClasses}
|
);
|
||||||
key={item.key}>
|
}
|
||||||
{item.label.substr(0, this.indexOfMatch(currentInput, item))}
|
|
||||||
<strong>{item.label.substr(this.indexOfMatch(currentInput, item), currentInput.length)}</strong>
|
renderItems( currentInput, items, focusIndex, activeItemClassName, itemClassName ) {
|
||||||
{item.label.substr(this.indexOfMatch(currentInput, item) + currentInput.length)}
|
return (
|
||||||
<input type='hidden' value={item.key}/>
|
<div className="datalist-items">
|
||||||
</div>
|
{items.map( ( item, i ) => {
|
||||||
)
|
const isActive = focusIndex === i;
|
||||||
})}
|
const itemActiveClasses = isActive ? `datalist-active-item ${ activeItemClassName }` : '';
|
||||||
</div> );
|
const itemClasses = `${ itemClassName } ${ itemActiveClasses };`;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={this.onClickItem}
|
||||||
|
className={itemClasses}
|
||||||
|
key={item.key}
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
onKeyUp={event => event.preventDefault()}
|
||||||
|
>
|
||||||
|
{ this.renderItemLabel( currentInput, item )}
|
||||||
|
<input type="hidden" value={item.key} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} )}
|
||||||
|
</div> );
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInputField( placeholder, currentInput, inputClassName ) {
|
renderInputField( placeholder, currentInput, inputClassName ) {
|
||||||
return (
|
return (
|
||||||
<input onKeyDown={this.onHandleKeydown} onInput={this.onHandleInput} type="text"
|
<input
|
||||||
className={ `autocomplete-input ${inputClassName}` }
|
onChange={this.onHandleInput}
|
||||||
placeholder={placeholder} value={currentInput} /> );
|
onKeyDown={this.onHandleKeydown}
|
||||||
|
type="text"
|
||||||
|
className={`autocomplete-input ${ inputClassName }`}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={currentInput}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { currentInput, matchingItems, focusIndex, visible } = this.state;
|
const {
|
||||||
const { placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength } = this.props;
|
currentInput, matchingItems, focusIndex, visible,
|
||||||
|
} = this.state;
|
||||||
|
const {
|
||||||
|
placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength,
|
||||||
|
} = this.props;
|
||||||
const reachedRequiredLength = currentInput.length >= requiredInputLength;
|
const reachedRequiredLength = currentInput.length >= requiredInputLength;
|
||||||
return (
|
return (
|
||||||
<div className="datalist-input">
|
<div className="datalist-input">
|
||||||
{ this.renderInputField( placeholder, currentInput, inputClassName ) }
|
{ this.renderInputField( placeholder, currentInput, inputClassName ) }
|
||||||
{ reachedRequiredLength && visible &&
|
{ reachedRequiredLength && visible
|
||||||
this.renderItems( matchingItems, focusIndex, activeItemClassName, itemClassName )
|
&& this.renderItems( currentInput, matchingItems, focusIndex,
|
||||||
|
activeItemClassName, itemClassName )
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -186,7 +225,12 @@ class DataListInput extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DataListInput.propTypes = {
|
DataListInput.propTypes = {
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape( {
|
||||||
|
label: PropTypes.string.isRequired,
|
||||||
|
key: PropTypes.number.isRequired,
|
||||||
|
} ),
|
||||||
|
).isRequired,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
onSelect: PropTypes.func.isRequired,
|
onSelect: PropTypes.func.isRequired,
|
||||||
match: PropTypes.func,
|
match: PropTypes.func,
|
||||||
|
Loading…
Reference in New Issue
Block a user