import React from 'react'; import PropTypes from 'prop-types'; import { injectGlobal, css } from 'react-emotion'; import Autosuggest from 'react-autosuggest'; import uuid from 'uuid/v4'; import { List, Map } from 'immutable'; import { debounce } from 'lodash'; import { Loader, components } from 'netlify-cms-ui-default'; injectGlobal` .react-autosuggest__container { position: relative; } .react-autosuggest__suggestions-container { display: none; } .react-autosuggest__container--open .react-autosuggest__suggestions-container { ${components.dropdownList} position: absolute; display: block; top: 51px; width: 100%; z-index: 2; } .react-autosuggest__suggestion { ${components.dropdownItem} } .react-autosuggest__suggestions-list { margin: 0; padding: 0; list-style-type: none; } .react-autosuggest__suggestion { cursor: pointer; padding: 10px 20px; } .react-autosuggest__suggestion--focused { background-color: #ddd; } ` function escapeRegexCharacters(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } export default class RelationControl extends React.Component { static propTypes = { onChange: PropTypes.func.isRequired, forID: PropTypes.string.isRequired, value: PropTypes.node, field: PropTypes.node, isFetching: PropTypes.node, query: PropTypes.func.isRequired, clearSearch: PropTypes.func.isRequired, queryHits: PropTypes.oneOfType([ PropTypes.array, PropTypes.object, ]), classNameWrapper: PropTypes.string.isRequired, setActiveStyle: PropTypes.func.isRequired, setInactiveStyle: PropTypes.func.isRequired, }; static defaultProps = { value: '', }; constructor(props, ctx) { super(props, ctx); this.controlID = uuid(); this.didInitialSearch = false; } componentDidMount() { const { value, field } = this.props; if (value) { const collection = field.get('collection'); const searchFields = field.get('searchFields').toJS(); this.props.query(this.controlID, collection, searchFields, value); } } componentWillReceiveProps(nextProps) { if (this.didInitialSearch) return; if (nextProps.queryHits !== this.props.queryHits && nextProps.queryHits.get && nextProps.queryHits.get(this.controlID)) { this.didInitialSearch = true; const suggestion = nextProps.queryHits.get(this.controlID); if (suggestion && suggestion.length === 1) { const val = this.getSuggestionValue(suggestion[0]); this.props.onChange(val, { [nextProps.field.get('collection')]: { [val]: suggestion[0].data } }); } } } onChange = (event, { newValue }) => { this.props.onChange(newValue); }; onSuggestionSelected = (event, { suggestion }) => { const value = this.getSuggestionValue(suggestion); this.props.onChange(value, { [this.props.field.get('collection')]: { [value]: suggestion.data } }); }; onSuggestionsFetchRequested = debounce(({ value }) => { if (value.length < 2) return; const { field } = this.props; const collection = field.get('collection'); const searchFields = field.get('searchFields').toJS(); this.props.query(this.controlID, collection, searchFields, value); }, 500); onSuggestionsClearRequested = () => { this.props.clearSearch(); }; getSuggestionValue = (suggestion) => { const { field } = this.props; const valueField = field.get('valueField'); return suggestion.data[valueField]; }; renderSuggestion = (suggestion) => { const { field } = this.props; const valueField = field.get('displayFields') || field.get('valueField'); if (List.isList(valueField)) { return ( {valueField.toJS().map(key => {new String(suggestion.data[key])}{' '})} ); } return {new String(suggestion.data[valueField])}; }; render() { const { value, isFetching, forID, queryHits, classNameWrapper, setActiveStyle, setInactiveStyle } = this.props; const inputProps = { placeholder: '', value: value || '', onChange: this.onChange, id: forID, className: classNameWrapper, onFocus: setActiveStyle, onBlur: setInactiveStyle, }; const suggestions = (queryHits.get) ? queryHits.get(this.controlID, []) : []; return (
); } };