Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-datalist-input

Package Overview
Dependencies
Maintainers
1
Versions
100
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-datalist-input - npm Package Compare versions

Comparing version 1.0.10 to 1.0.11

173

lib/DataListInput.js
import React from 'react';
import PropTypes from 'prop-types';
import './DataListInput.css';
import './input.scss';
class DataListInput extends React.Component {
constructor( props ) {
super( props );
constructor(props) {
super(props);
this.state = {

@@ -15,3 +14,3 @@ /* last valid item that was selected from the drop down menu */

/* current input text */
currentInput: "",
currentInput: '',
/* current set of matching items */

@@ -30,9 +29,10 @@ matchingItems: [],

*/
onHandleInput = (currentInput) => {
const matchingItems = this.props.items.filter((item) => {
if (typeof(this.props.match) === typeof(Function))
return this.props.match(currentInput, item);
return this.match(currentInput, item);
});
this.setState({
onHandleInput = ( event ) => {
const currentInput = event.target.value;
const { items, match } = this.props;
const matchingItems = items.filter( ( item ) => {
if ( typeof ( match ) === typeof ( Function ) ) { return match( currentInput, item ); }
return this.match( currentInput, item );
} );
this.setState( {
currentInput,

@@ -42,7 +42,8 @@ matchingItems,

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

@@ -52,5 +53,4 @@ * @param item

*/
match = (currentInput, item) => {
return item.label.substr(0, currentInput.length).toUpperCase() === currentInput.toUpperCase();
};
match = ( currentInput, item ) => item
.label.substr( 0, currentInput.length ).toUpperCase() === currentInput.toUpperCase();

@@ -63,5 +63,4 @@ /**

*/
indexOfMatch = (currentInput, item) => {
return item.label.toUpperCase().indexOf(currentInput.toUpperCase());
};
indexOfMatch = ( currentInput, item ) => item
.label.toUpperCase().indexOf( currentInput.toUpperCase() );

@@ -72,28 +71,29 @@ /**

*/
onHandleKeydown = (event) => {
onHandleKeydown = ( event ) => {
const { visible, focusIndex, matchingItems } = this.state;
// only do something if drop-down div is visible
if (!this.state.visible) return;
let currentFocusIndex = this.state.focusIndex;
if (event.keyCode === 40 || event.keyCode === 9) {
if ( !visible ) return;
let currentFocusIndex = focusIndex;
if ( event.keyCode === 40 || event.keyCode === 9 ) {
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
currentFocusIndex += 1;
if (currentFocusIndex >= this.state.matchingItems.length) currentFocusIndex = 0;
this.setState({
if ( currentFocusIndex >= matchingItems.length ) currentFocusIndex = 0;
this.setState( {
focusIndex: currentFocusIndex,
});
} );
// prevent tab to jump to the next input field if drop down is still open
event.preventDefault();
} else if (event.keyCode === 38) {
} else if ( event.keyCode === 38 ) {
// If the arrow UP key is pressed, decrease the currentFocus variable:
currentFocusIndex -= 1;
if (currentFocusIndex <= -1) currentFocusIndex = this.state.matchingItems.length - 1;
this.setState({
if ( currentFocusIndex <= -1 ) currentFocusIndex = matchingItems.length - 1;
this.setState( {
focusIndex: currentFocusIndex,
});
} else if (event.keyCode === 13) {
} );
} else if ( event.keyCode === 13 ) {
// Enter pressed, similar to onClickItem
if (this.state.focusIndex > -1) {
if ( focusIndex > -1 ) {
// Simulate a click on the "active" item:
const selectedItem = this.state.matchingItems[currentFocusIndex];
this.onSelect(selectedItem);
const selectedItem = matchingItems[ currentFocusIndex ];
this.onSelect( selectedItem );
}

@@ -107,7 +107,15 @@ }

*/
onClickItem = (event) => {
onClickItem = ( event ) => {
const { matchingItems } = this.state;
// update the input value and close the dropdown again
const selectedKey = event.currentTarget.children[1].value;
const selectedItem = this.state.matchingItems.find(item => item.key === selectedKey);
this.onSelect(selectedItem);
const elements = event.currentTarget.children;
let selectedKey;
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,15 +128,17 @@

*/
onSelect = (selectedItem) => {
if (this.state.lastValidItem !== undefined && selectedItem.key === this.state.lastValidItem.key){
onSelect = ( selectedItem ) => {
console.log( selectedItem );
const { lastValidItem } = this.state;
if ( lastValidItem && selectedItem.key === lastValidItem.key ) {
// do not trigger the callback function
// but still change state to fit new selection
this.setState({
this.setState( {
currentInput: selectedItem.label,
visible: false,
focusIndex: -1,
});
} );
return;
}
// change state to fit new selection
this.setState({
this.setState( {
currentInput: selectedItem.label,

@@ -138,24 +148,38 @@ lastValidItem: selectedItem,

focusIndex: -1,
});
} );
// 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">
{items.map((item, i) => {
{items.map( ( item, i ) => {
const isActive = focusIndex === i;
const itemActiveClasses = isActive ? `datalist-active-item ${activeItemClassName}` : ''
const itemClasses = `${itemClassName} ${itemActiveClasses};`
const itemActiveClasses = isActive ? `datalist-active-item ${ activeItemClassName }` : '';
const itemClasses = `${ itemClassName } ${ itemActiveClasses };`;
return (
<div onClick={this.onClickItem}
className={itemClasses}
key={item.key}>
{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)}
<input type='hidden' value={item.key}/>
<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>

@@ -165,10 +189,19 @@ );

renderInputField = ( placeholder, currentInput, inputClassName ) => (
<input onKeyDown={this.onHandleKeydown} onChange={this.onHandleInput} type="text"
className={ `autocomplete-input ${inputClassName}` }
placeholder={placeholder} value={currentInput}/>
<input
onChange={this.onHandleInput}
onKeyDown={this.onHandleKeydown}
type="text"
className={`autocomplete-input ${ inputClassName }`}
placeholder={placeholder}
value={currentInput}
/>
)
render() {
const { currentInput, matchingItems, focusIndex, visible } = this.state;
const { placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength } = this.props;
const {
currentInput, matchingItems, focusIndex, visible,
} = this.state;
const {
placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength,
} = this.props;
const reachedRequiredLength = currentInput.length >= requiredInputLength;

@@ -178,4 +211,5 @@ return (

{ this.renderInputField( placeholder, currentInput, inputClassName ) }
{ reachedRequiredLength && visible &&
this.renderItems( matchingItems, focusIndex, activeItemClassName, itemClassName )
{ reachedRequiredLength && visible
&& this.renderItems( currentInput, matchingItems, focusIndex,
activeItemClassName, itemClassName )
}

@@ -188,3 +222,8 @@ </div>

DataListInput.propTypes = {
items: PropTypes.array.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape( {
label: PropTypes.string.isRequired,
key: PropTypes.number.isRequired,
} ),
).isRequired,
placeholder: PropTypes.string,

@@ -191,0 +230,0 @@ onSelect: PropTypes.func.isRequired,

{
"name": "react-datalist-input",
"version": "1.0.10",
"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.",

@@ -5,0 +5,0 @@ "main": "build/index.js",

@@ -32,2 +32,3 @@ import React from 'react';

this.renderInputField = this.renderInputField.bind(this);
this.renderItemLabel = this.renderItemLabel.bind(this);
}

@@ -37,11 +38,12 @@

* gets called when someone starts to write in the input field
* @param event
* @param value
*/
onHandleInput(currentInput) {
const matchingItems = this.props.items.filter((item) => {
if (typeof(this.props.match) === typeof(Function))
return this.props.match(currentInput, item);
return this.match(currentInput, item);
});
this.setState({
onHandleInput( event ){
const currentInput = event.target.value;
const { items, match } = this.props;
const matchingItems = items.filter( ( item ) => {
if ( typeof ( match ) === typeof ( Function ) ) { return match( currentInput, item ); }
return this.match( currentInput, item );
} );
this.setState( {
currentInput,

@@ -51,7 +53,8 @@ matchingItems,

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

@@ -61,4 +64,4 @@ * @param item

*/
match(currentInput, item) {
return item.label.substr(0, currentInput.length).toUpperCase() === currentInput.toUpperCase();
match( currentInput, item ) {
return item.label.substr( 0, currentInput.length ).toUpperCase() === currentInput.toUpperCase();
}

@@ -72,4 +75,4 @@

*/
indexOfMatch(currentInput, item) {
return item.label.toUpperCase().indexOf(currentInput.toUpperCase());
indexOfMatch( currentInput, item ) {
return item.label.toUpperCase().indexOf( currentInput.toUpperCase() );
}

@@ -81,28 +84,29 @@

*/
onHandleKeydown(event) {
onHandleKeydown( event ) {
const { visible, focusIndex, matchingItems } = this.state;
// only do something if drop-down div is visible
if (!this.state.visible) return;
let currentFocusIndex = this.state.focusIndex;
if (event.keyCode === 40 || event.keyCode === 9) {
if ( !visible ) return;
let currentFocusIndex = focusIndex;
if ( event.keyCode === 40 || event.keyCode === 9 ) {
// If the arrow DOWN key or tab is pressed increase the currentFocus variable:
currentFocusIndex += 1;
if (currentFocusIndex >= this.state.matchingItems.length) currentFocusIndex = 0;
this.setState({
if ( currentFocusIndex >= matchingItems.length ) currentFocusIndex = 0;
this.setState( {
focusIndex: currentFocusIndex,
});
} );
// prevent tab to jump to the next input field if drop down is still open
event.preventDefault();
} else if (event.keyCode === 38) {
} else if ( event.keyCode === 38 ) {
// If the arrow UP key is pressed, decrease the currentFocus variable:
currentFocusIndex -= 1;
if (currentFocusIndex <= -1) currentFocusIndex = this.state.matchingItems.length - 1;
this.setState({
if ( currentFocusIndex <= -1 ) currentFocusIndex = matchingItems.length - 1;
this.setState( {
focusIndex: currentFocusIndex,
});
} else if (event.keyCode === 13) {
} );
} else if ( event.keyCode === 13 ) {
// Enter pressed, similar to onClickItem
if (this.state.focusIndex > -1) {
if ( focusIndex > -1 ) {
// Simulate a click on the "active" item:
const selectedItem = this.state.matchingItems[currentFocusIndex];
this.onSelect(selectedItem);
const selectedItem = matchingItems[ currentFocusIndex ];
this.onSelect( selectedItem );
}

@@ -116,7 +120,15 @@ }

*/
onClickItem(event) {
onClickItem( event ) {
const { matchingItems } = this.state;
// update the input value and close the dropdown again
const selectedKey = event.currentTarget.children[1].value;
const selectedItem = this.state.matchingItems.find(item => item.key === selectedKey);
this.onSelect(selectedItem);
const elements = event.currentTarget.children;
let selectedKey;
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 );
}

@@ -129,15 +141,16 @@

*/
onSelect(selectedItem) {
if (this.state.lastValidItem !== undefined && selectedItem.key === this.state.lastValidItem.key){
onSelect( selectedItem ) {
const { lastValidItem } = this.state;
if ( lastValidItem && selectedItem.key === lastValidItem.key ) {
// do not trigger the callback function
// but still change state to fit new selection
this.setState({
this.setState( {
currentInput: selectedItem.label,
visible: false,
focusIndex: -1,
});
} );
return;
}
// change state to fit new selection
this.setState({
this.setState( {
currentInput: selectedItem.label,

@@ -147,38 +160,64 @@ lastValidItem: selectedItem,

focusIndex: -1,
});
} );
// callback function onSelect
this.props.onSelect(selectedItem);
const { onSelect } = this.props;
onSelect( selectedItem );
}
renderItems( items, focusIndex, activeItemClassName, itemClassName) {
renderItemLabel( currentInput, item ) {
return (
<div className="datalist-items">
{items.map((item, i) => {
const isActive = focusIndex === i;
const itemActiveClasses = isActive ? `datalist-active-item ${activeItemClassName}` : ''
const itemClasses = `${itemClassName} ${itemActiveClasses};`
return (
<div onClick={this.onClickItem}
className={itemClasses}
key={item.key}>
{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)}
<input type='hidden' value={item.key}/>
</div>
)
})}
</div> );
<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 ) {
return (
<div className="datalist-items">
{items.map( ( item, i ) => {
const isActive = focusIndex === i;
const itemActiveClasses = isActive ? `datalist-active-item ${ activeItemClassName }` : '';
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 ) {
return (
<input onKeyDown={this.onHandleKeydown} onChange={this.onHandleInput} type="text"
className={ `autocomplete-input ${inputClassName}` }
placeholder={placeholder} value={currentInput} /> );
<input
onChange={this.onHandleInput}
onKeyDown={this.onHandleKeydown}
type="text"
className={`autocomplete-input ${ inputClassName }`}
placeholder={placeholder}
value={currentInput}
/>
);
}
render() {
const { currentInput, matchingItems, focusIndex, visible } = this.state;
const { placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength } = this.props;
const {
currentInput, matchingItems, focusIndex, visible,
} = this.state;
const {
placeholder, inputClassName, activeItemClassName, itemClassName, requiredInputLength,
} = this.props;
const reachedRequiredLength = currentInput.length >= requiredInputLength;

@@ -188,4 +227,5 @@ return (

{ this.renderInputField( placeholder, currentInput, inputClassName ) }
{ reachedRequiredLength && visible &&
this.renderItems( matchingItems, focusIndex, activeItemClassName, itemClassName )
{ reachedRequiredLength && visible
&& this.renderItems( currentInput, matchingItems, focusIndex,
activeItemClassName, itemClassName )
}

@@ -198,3 +238,8 @@ </div>

DataListInput.propTypes = {
items: PropTypes.array.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape( {
label: PropTypes.string.isRequired,
key: PropTypes.number.isRequired,
} ),
).isRequired,
placeholder: PropTypes.string,

@@ -218,2 +263,2 @@ onSelect: PropTypes.func.isRequired,

export default DataListInput;
export default DataListInput;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc