Skip to content

Instantly share code, notes, and snippets.

@lokeb
Last active September 7, 2018 23:22
Show Gist options
  • Save lokeb/ae072c99d06cb9cf885c8fb4e6bfc0cf to your computer and use it in GitHub Desktop.
Save lokeb/ae072c99d06cb9cf885c8fb4e6bfc0cf to your computer and use it in GitHub Desktop.
Ready to use React Material-UI component to render autocomplete input field. Accepts standard input properties
import React from 'react';
import deburr from 'lodash/deburr'
import Autosuggest from 'react-autosuggest';
import match from 'autosuggest-highlight/match'
import parse from 'autosuggest-highlight/parse'
import TextField from '@material-ui/core/TextField'
import Paper from '@material-ui/core/Paper'
import MenuItem from '@material-ui/core/MenuItem'
import { withStyles } from '@material-ui/core/styles'
function renderInputComponent(inputProps) {
const { classes, inputRef = () => {}, ref, ...other } = inputProps;
return (
<TextField
fullWidth
InputProps={{
inputRef: node => {
ref(node);
inputRef(node);
},
classes: {
input: classes.input,
},
}}
{...other}
/>
)
}
function renderSuggestion(suggestion, { query, isHighlighted }) {
const matches = match(suggestion, query)
const parts = parse(suggestion, matches)
return (
<MenuItem selected={isHighlighted} component="div">
<div>
{parts.map((part, index) => {
return part.highlight ? (
<span key={String(index)} style={{ fontWeight: 500 }}>
{part.text}
</span>
) : (
<strong key={String(index)} style={{ fontWeight: 300 }}>
{part.text}
</strong>
)
})}
</div>
</MenuItem>
)
}
function getSuggestionValue(suggestion) {
return suggestion
}
const styles = theme => ({
root: {
height: 'auto',
flexGrow: 1,
},
container: {
position: 'relative',
},
suggestionsContainerOpen: {
position: 'absolute',
zIndex: 1,
marginTop: theme.spacing.unit,
left: 0,
right: 0,
},
suggestion: {
display: 'block',
},
suggestionsList: {
margin: 0,
padding: 0,
listStyleType: 'none',
},
divider: {
height: theme.spacing.unit * 2,
},
});
class IntegrationAutosuggest extends React.Component {
popperNode = null;
state = {
suggestions: [],
}
getSuggestions = value => {
const inputValue = deburr(value.trim()).toLowerCase()
const inputLength = inputValue.length
let count = 0
return inputLength !== 0 && this.props.options ? this.props.options.filter(suggestion => {
const keep = count < 5 && suggestion.slice(0, inputLength).toLowerCase() === inputValue
if (keep) count += 1
return keep
}) : []
}
handleSuggestionsFetchRequested = ({ value }) => {
this.setState({
suggestions: this.getSuggestions(value),
});
};
handleSuggestionsClearRequested = () => {
this.setState({
suggestions: [],
})
}
handleChange = (event, { newValue }) => {
event.target.value = newValue
if(this.props.hasOwnProperty('onChange')) this.props.onChange(event)
}
render() {
const { classes } = this.props;
const autosuggestProps = {
renderInputComponent,
suggestions: this.state.suggestions,
onSuggestionsFetchRequested: this.handleSuggestionsFetchRequested,
onSuggestionsClearRequested: this.handleSuggestionsClearRequested,
getSuggestionValue,
renderSuggestion,
}
return (
<div className={classes.root}>
<Autosuggest
{...autosuggestProps}
inputProps={{
classes,
autoComplete: this.props.autoComplete,
label: this.props.label,
value: this.props.value,
onChange: this.handleChange,
required: this.props.required,
id: this.props.id,
name: this.props.name
}}
theme={{
container: classes.container,
suggestionsContainerOpen: classes.suggestionsContainerOpen,
suggestionsList: classes.suggestionsList,
suggestion: classes.suggestion,
}}
renderSuggestionsContainer={options => (
<Paper {...options.containerProps} square>
{options.children}
</Paper>
)}
/>
</div>
)
}
}
export default withStyles(styles)(IntegrationAutosuggest)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment