UNPKG

react-mapfilter

Version:

A React Component for viewing and filtering GeoJSON

225 lines (202 loc) 5.79 kB
import React, { Component } from 'react' import PropTypes from 'prop-types' import Autosuggest from 'react-autosuggest' import TextField from '@material-ui/core/TextField' import Paper from '@material-ui/core/Paper' import MenuItem from '@material-ui/core/MenuItem' import IsolatedScroll from 'react-isolated-scroll' import match from 'autosuggest-highlight/match' import parse from 'autosuggest-highlight/parse' import omit from 'lodash/omit' import isEqual from 'lodash/isEqual' import assign from 'object-assign' import { withStyles } from '@material-ui/core/styles' const ITEM_HEIGHT = 48 const styleSheet = theme => ({ container: { flexGrow: 1, position: 'relative', fontSize: 14 }, suggestionsContainerOpen: { position: 'absolute', marginTop: theme.spacing.unit, marginBottom: theme.spacing.unit * 3, left: 0, right: 0, zIndex: 99 }, suggestionsContainerInner: { maxHeight: ITEM_HEIGHT * 6.5, overflowY: 'auto' }, suggestion: { display: 'block', fontSize: 14 }, suggestionsList: { margin: 0, padding: 0, listStyleType: 'none' }, textField: { width: '100%' }, input: { fontSize: 'inherit' } }) function renderInput (props) { const {classes, home, value, inputRef, ref, style} = props const inputProps = assign({}, omit(props, ['classes', 'home', 'value', 'inputRef', 'ref', 'style']), {className: classes.input} ) function callRef (el) { inputRef(el) ref(el) } return ( <TextField style={style} autoFocus={home} className={classes.textField} value={value} inputRef={callRef} InputProps={inputProps} /> ) } function renderSuggestion (suggestion, { query, isHighlighted }) { const matches = match(suggestion, query) const parts = parse(suggestion, matches) return ( <MenuItem dense selected={isHighlighted} component='div' style={{fontSize: 14}}> <div> {parts.map((part, index) => { return part.highlight ? <span key={index} style={{ fontWeight: 500 }}> {part.text} </span> : <strong key={index} style={{ fontWeight: 300 }}> {part.text} </strong> })} </div> </MenuItem> ) } function getSuggestionValue (suggestion) { return suggestion } function shouldRenderSuggestions () { return true } function getSuggestions (value, suggestions) { const inputValue = value.trim().toLowerCase() const inputLength = inputValue.length let count = 0 return inputLength === 0 ? suggestions : suggestions.filter(suggestion => { const keep = count < 5 && suggestion.toLowerCase().slice(0, inputLength) === inputValue if (keep) { count += 1 } return keep }) } class Select extends Component { state = { suggestions: this.props.suggestions } componentWillReceiveProps (nextProps) { if (!isEqual(nextProps.suggestions, this.props.suggestions)) { this.setState({suggestions: nextProps.suggestions}) } } renderSuggestionsContainer = ({containerProps, children}) => { const callRef = isolatedScroll => { if (isolatedScroll !== null) { containerProps.ref(isolatedScroll.component) } } return ( <Paper {...containerProps}> <IsolatedScroll ref={callRef} className={this.props.classes.suggestionsContainerInner}> {children} </IsolatedScroll> </Paper> ) } getSuggestions = ({ value }) => { this.setState({ suggestions: this.justFocussed ? this.props.suggestions : getSuggestions(value, this.props.suggestions) }) } resetSuggestions = () => { this.setState({ suggestions: this.props.suggestions }) } selectInputText = (e) => { e.target.select() this.justFocussed = true // Naughty? But it works... *WARNING* relies on an internal method of react-autosuggest this.autosuggest && this.autosuggest.revealSuggestions() } handleChange = (e, d) => { this.justFocussed = false this.props.onChange(e, d) } render () { const { classes, className, value, onSuggestionSelected, onKeyDown, style } = this.props return ( <Autosuggest ref={(el) => (this.autosuggest = el)} theme={{ container: classes.container + ' ' + className, suggestionsContainerOpen: classes.suggestionsContainerOpen, suggestionsList: classes.suggestionsList, suggestion: classes.suggestion }} shouldRenderSuggestions={shouldRenderSuggestions} renderInputComponent={renderInput} suggestions={this.state.suggestions} onSuggestionsFetchRequested={this.getSuggestions} onSuggestionsClearRequested={this.resetSuggestions} onSuggestionSelected={onSuggestionSelected} renderSuggestionsContainer={this.renderSuggestionsContainer} getSuggestionValue={getSuggestionValue} renderSuggestion={renderSuggestion} inputProps={{ inputRef: (el) => (this.input = el), style, classes, value, onChange: this.handleChange, onFocus: this.selectInputText, onClick: this.selectInputText, onKeyDown: onKeyDown }} /> ) } } Select.propTypes = { classes: PropTypes.object.isRequired, suggestions: PropTypes.arrayOf(PropTypes.string), value: PropTypes.string, onChange: PropTypes.func.isRequired, onSuggestionSelected: PropTypes.func, onKeyDown: PropTypes.func, style: PropTypes.object } Select.defaultProps = { onSuggestionSelected: () => null, onKeyDown: () => null, value: '', classes: {} } export default withStyles(styleSheet)(Select)