2016-12-30 20:38:50 +01:00
|
|
|
import React from 'react'
|
2017-11-06 16:32:04 +01:00
|
|
|
import PropTypes from 'prop-types'
|
2017-01-11 14:03:48 +01:00
|
|
|
import classnames from 'classnames'
|
2016-12-30 20:38:50 +01:00
|
|
|
import Autocomplete from 'react-autocomplete'
|
2017-01-11 14:03:48 +01:00
|
|
|
|
2016-12-30 20:38:50 +01:00
|
|
|
|
2017-11-29 11:29:11 +01:00
|
|
|
const MAX_HEIGHT = 140;
|
|
|
|
|
2017-11-08 16:44:43 +01:00
|
|
|
class AutocompleteMenu extends React.Component {
|
|
|
|
static propTypes = {
|
|
|
|
keepMenuWithinWindowBounds: PropTypes.bool,
|
|
|
|
style: PropTypes.object,
|
2017-11-29 11:19:22 +01:00
|
|
|
children: PropTypes.node
|
2017-11-08 16:44:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
calcMaxHeight() {
|
|
|
|
if(this.props.keepMenuWithinWindowBounds) {
|
|
|
|
const maxHeight = window.innerHeight - this.autocompleteMenuEl.getBoundingClientRect().top;
|
2017-11-29 11:29:11 +01:00
|
|
|
const limitedMaxHeight = Math.min(maxHeight, MAX_HEIGHT);
|
|
|
|
|
|
|
|
if(limitedMaxHeight != this.state.maxHeight) {
|
2017-11-08 16:44:43 +01:00
|
|
|
this.setState({
|
2017-11-29 11:29:11 +01:00
|
|
|
maxHeight: limitedMaxHeight
|
2017-11-08 16:44:43 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
componentDidMount() {
|
|
|
|
this.calcMaxHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
this.calcMaxHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
2017-11-29 11:29:11 +01:00
|
|
|
maxHeight: MAX_HEIGHT
|
2017-11-08 16:44:43 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static defaultProps = {
|
|
|
|
style: {}
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const maxHeight = this.state.maxHeight - this.props.style.marginBottom || 0;
|
|
|
|
const style = {
|
|
|
|
maxHeight: maxHeight+"px"
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
ref={(el) => {
|
|
|
|
this.autocompleteMenuEl = el;
|
|
|
|
}}
|
|
|
|
className={"maputnik-autocomplete-menu"}
|
|
|
|
style={style}
|
|
|
|
>
|
|
|
|
{this.props.children}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-30 20:38:50 +01:00
|
|
|
class AutocompleteInput extends React.Component {
|
|
|
|
static propTypes = {
|
2017-11-06 16:32:04 +01:00
|
|
|
value: PropTypes.string,
|
|
|
|
options: PropTypes.array,
|
|
|
|
onChange: PropTypes.func,
|
2017-11-08 16:44:43 +01:00
|
|
|
keepMenuWithinWindowBounds: PropTypes.bool
|
2016-12-31 10:39:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static defaultProps = {
|
|
|
|
onChange: () => {},
|
|
|
|
options: [],
|
2016-12-30 20:38:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2016-12-30 20:46:27 +01:00
|
|
|
return <Autocomplete
|
2017-01-11 13:34:38 +01:00
|
|
|
wrapperProps={{
|
|
|
|
className: "maputnik-autocomplete",
|
|
|
|
style: null
|
|
|
|
}}
|
2017-11-08 16:44:43 +01:00
|
|
|
renderMenu={(items) => {
|
|
|
|
return <AutocompleteMenu keepMenuWithinWindowBounds={this.props.keepMenuWithinWindowBounds} style={{marginBottom: 4}}>
|
|
|
|
{items}
|
|
|
|
</AutocompleteMenu>
|
|
|
|
}}
|
2016-12-30 20:46:27 +01:00
|
|
|
inputProps={{
|
2017-01-11 13:34:38 +01:00
|
|
|
className: "maputnik-string"
|
2016-12-30 20:46:27 +01:00
|
|
|
}}
|
2016-12-30 20:38:50 +01:00
|
|
|
value={this.props.value}
|
2016-12-30 20:46:27 +01:00
|
|
|
items={this.props.options}
|
|
|
|
getItemValue={(item) => item[0]}
|
|
|
|
onSelect={v => this.props.onChange(v)}
|
2016-12-30 20:38:50 +01:00
|
|
|
onChange={(e, v) => this.props.onChange(v)}
|
2016-12-30 20:46:27 +01:00
|
|
|
renderItem={(item, isHighlighted) => (
|
|
|
|
<div
|
|
|
|
key={item[0]}
|
2017-01-11 14:03:48 +01:00
|
|
|
className={classnames({
|
|
|
|
"maputnik-autocomplete-menu-item": true,
|
|
|
|
"maputnik-autocomplete-menu-item-selected": isHighlighted,
|
|
|
|
})}
|
2016-12-30 20:46:27 +01:00
|
|
|
>
|
|
|
|
{item[1]}
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
/>
|
2016-12-30 20:38:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default AutocompleteInput
|