wix-style-react
Version:
415 lines (359 loc) • 15.1 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
import _inherits from "@babel/runtime/helpers/inherits";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
/* eslint-disable no-console */
import React from 'react';
import PropTypes from 'prop-types';
import castArray from 'lodash/castArray';
import Search from 'wix-ui-icons-common/Search';
import Input from '../Input';
import InputWithOptions from '../InputWithOptions';
import { google2address, includes, trySetStreetNumberIfNotReceived } from './google2address';
import { classes } from './GoogleAddressInput.st.css';
export var GoogleAddressInputHandler = {
geocode: 'geocode',
places: 'places'
};
/**
* Address input box (using Google Maps)
*/
var GoogleAddressInput = /*#__PURE__*/function (_React$Component) {
_inherits(GoogleAddressInput, _React$Component);
var _super = _createSuper(GoogleAddressInput);
function GoogleAddressInput(props) {
var _this;
_classCallCheck(this, GoogleAddressInput);
_this = _super.call(this, props);
_this.state = {
suggestions: [],
value: props.value || ''
};
_this.autoCompleteRequestId = 0;
_this.geocodeRequestId = 0;
_this.client = new props.Client();
_this.onChange = _this.onChange.bind(_assertThisInitialized(_this));
_this.onBlur = _this.onBlur.bind(_assertThisInitialized(_this));
_this.onFocus = _this.onFocus.bind(_assertThisInitialized(_this));
_this.onSet = _this.onSet.bind(_assertThisInitialized(_this));
_this.onManuallyInput = _this.onManuallyInput.bind(_assertThisInitialized(_this));
return _this;
}
_createClass(GoogleAddressInput, [{
key: "UNSAFE_componentWillReceiveProps",
value: function UNSAFE_componentWillReceiveProps(nextProps) {
var _this2 = this;
if (nextProps.value !== this.props.value) {
this._getSuggestions(nextProps.value).then(function (suggestions) {
_this2.setState({
suggestions: suggestions
});
})["catch"](function () {
// Nothing really to do...
_this2.setState({
suggestions: []
});
});
}
}
}, {
key: "render",
value: function render() {
var _this3 = this;
var _this$state = this.state,
suggestions = _this$state.suggestions,
value = _this$state.value;
var magnifyingGlass = this.props.magnifyingGlass;
var options = [].concat(_toConsumableArray(suggestions.map(function (suggestion, index) {
var place_id = suggestion.place_id,
description = suggestion.description;
return {
id: place_id || index,
value: description
};
})), _toConsumableArray(this.props.footer ? [_objectSpread({
id: suggestions.length,
value: this.props.footer
}, this.props.footerOptions)] : []));
var suffix = magnifyingGlass ? /*#__PURE__*/React.createElement(Input.IconAffix, null, /*#__PURE__*/React.createElement(Search, {
"data-hook": "search-icon"
})) : undefined;
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(InputWithOptions, _extends({
ref: function ref(autocomplete) {
return _this3.autocomplete = autocomplete;
}
}, this.props, {
onInput: this.onChange,
onBlur: this.onBlur,
onFocus: this.onFocus,
onSelect: function onSelect(option) {
return _this3.onSet(option.value);
},
onManuallyInput: this.onManuallyInput,
value: value,
options: options,
fixedFooter: suggestions.length && this.props.poweredByGoogle ? GoogleAddressInput.getGoogleFooter() : null,
suffix: suffix,
selectedHighlight: false,
menuArrow: false
})));
}
}, {
key: "focus",
value: function focus() {
this.autocomplete.focus();
}
}, {
key: "select",
value: function select() {
this.autocomplete.select();
}
}, {
key: "onChange",
value: function onChange(e) {
var _this4 = this;
var value = e.target.value;
this.props.onChange && this.props.onChange(e);
this.props.onSet && this.props.onSet(null);
if (typeof this.props.value !== 'undefined') {
// Controlled mode
return;
}
this._getSuggestions(value).then(function (suggestions) {
_this4.setState({
suggestions: suggestions
});
})["catch"](function () {
// Nothing really to do...
_this4.setState({
suggestions: []
});
});
}
}, {
key: "onBlur",
value: function onBlur() {
var _this5 = this;
this.props.onBlur && this.props.onBlur();
if (this.props.clearSuggestionsOnBlur) {
this.timer = setTimeout(function () {
_this5.setState({
suggestions: []
});
}, 250);
}
}
}, {
key: "onFocus",
value: function onFocus() {
this.props.onFocus && this.props.onFocus();
}
}, {
key: "onSet",
value: function onSet(value) {
var _this6 = this;
var _this$props = this.props,
countryCode = _this$props.countryCode,
handler = _this$props.handler;
var suggestion = this.state.suggestions.find(function (s) {
return s.description === value;
});
this.setState({
suggestions: [],
value: this.props.value || value
});
var requestId = ++this.geocodeRequestId;
var handlerCall;
if (handler === GoogleAddressInputHandler.places && suggestion && suggestion.place_id) {
var request = {
request: {
placeId: suggestion.place_id
}
};
if (this.props.placeDetailsFields) {
request.request.fields = this.props.placeDetailsFields;
}
handlerCall = this.client.placeDetails(request);
} else {
handlerCall = this.client.geocode({
request: _defineProperty({
region: countryCode
}, suggestion ? 'placeId' : 'address', suggestion ? suggestion.place_id : value)
});
}
handlerCall.then(function (results) {
results = castArray(results).filter(Boolean);
if (requestId !== _this6.geocodeRequestId) {
return;
}
if (results.length === 0) {
console.error("[GoogleAddressInput] handler (".concat(handler, ") returned no results on"), value);
_this6.props.onSet && _this6.props.onSet(null); // This shouldn't happen since we're running geocode on exactly the same
// value returned by suggestions list
return;
}
var firstResult = trySetStreetNumberIfNotReceived(results[0], _this6.state.value);
var result = {
originValue: value,
googleResult: firstResult,
address: google2address(firstResult)
};
_this6.props.onSet && _this6.props.onSet(result);
})["catch"](function (e) {
console.error("[GoogleAddressInput] handler (".concat(handler, ") failed on"), value, e.message);
_this6.props.onSet && _this6.props.onSet(null);
});
}
}, {
key: "onManuallyInput",
value: function onManuallyInput(inputValue) {
var _this7 = this;
var _this$props2 = this.props,
value = _this$props2.value,
fallbackToManual = _this$props2.fallbackToManual,
onSet = _this$props2.onSet;
if (fallbackToManual) {
this._getSuggestions(inputValue, typeof value !== 'undefined').then(function (suggestions) {
if (suggestions.length === 0) {
// No suggestion to the text entered
if (inputValue) {
_this7.onSet(inputValue);
} else {
onSet && onSet(null);
}
}
});
}
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
if (this.timer) {
clearTimeout(this.timer);
}
}
}, {
key: "_getSuggestions",
value: function _getSuggestions(value, skipSetState) {
var _this8 = this;
var _this$props3 = this.props,
_this$props3$valuePre = _this$props3.valuePrefix,
valuePrefix = _this$props3$valuePre === void 0 ? '' : _this$props3$valuePre,
countryCode = _this$props3.countryCode,
types = _this$props3.types,
filterTypes = _this$props3.filterTypes;
var requestId = ++this.autoCompleteRequestId;
return new Promise(function (resolve) {
if (skipSetState) {
// Controlled mode
resolve();
return;
}
_this8.setState({
value: value
}, function () {
return resolve();
});
}).then(function () {
if (value === '') {
return Promise.resolve([]);
}
var request = {
types: types,
componentRestrictions: {
country: countryCode
},
input: valuePrefix + value
};
return _this8.client.autocomplete({
request: request
});
}).then(function (results) {
if (results.length === 0) {
return Promise.resolve([]);
}
if (requestId !== _this8.autoCompleteRequestId) {
return Promise.resolve([]);
}
if (filterTypes) {
results = results.filter(function (result) {
return includes(result.types, filterTypes);
});
}
return Promise.resolve(results);
});
}
}]);
return GoogleAddressInput;
}(React.Component);
_defineProperty(GoogleAddressInput, "getGoogleFooter", function () {
return /*#__PURE__*/React.createElement("div", {
className: classes.googleFooter,
"data-hook": "google-footer"
});
});
GoogleAddressInput.displayName = 'GoogleAddressInput';
GoogleAddressInput.defaultProps = {
magnifyingGlass: true,
autoSelect: true,
footerOptions: {},
clearSuggestionsOnBlur: true,
fallbackToManual: false,
poweredByGoogle: false,
handler: GoogleAddressInputHandler.geocode
};
GoogleAddressInput.propTypes = {
/** Placeholder for the input box */
placeholder: PropTypes.string,
/** Value to place before every search term (normally should not be used) */
valuePrefix: PropTypes.string,
/** Country code used to help with suggestions and geocoding */
countryCode: PropTypes.string,
/** Controlled mode - value to display */
value: PropTypes.string,
/** Limit the autocomplete to specific types (see [here](https://developers.google.com/places/supported_types#table3) for list) */
types: PropTypes.array,
/** Lower level filtering of autocomplete result types (see [here](https://developers.google.com/places/supported_types) for list) */
filterTypes: PropTypes.array,
/** Fields indicating which types of Places data to return (see [here](https://developers.google.com/maps/documentation/javascript/places#place_details)**/
placeDetailsFields: PropTypes.array,
/** Sets UI to indicate a status */
status: PropTypes.oneOf(['error', 'warning', 'loading']),
/** The status message to display when hovering the status icon, if not given or empty there will be no tooltip */
statusMessage: PropTypes.node,
onChange: PropTypes.func,
onBlur: PropTypes.func,
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
/** Callback for results. Will return an object containing: originValue (value in the search), googleResult (google geocode result for the search), address (which will include: formatted (google formatted address), country, countryCode, street, number, postalCode, latLng (lat, lng)) */
onSet: PropTypes.func,
/** Google map client implementation (should implement autocomplete and geocode functions). Normally you would use wix-style-react/clients/GoogleMapsClient */
Client: PropTypes.func.isRequired,
/** Show or hide magnifying glass icon */
magnifyingGlass: PropTypes.bool,
/** Sets the input to readOnly */
readOnly: PropTypes.bool,
autoSelect: PropTypes.bool,
/** Display a footer as the last suggestion in the list */
footer: PropTypes.any,
/** Set the footer's options (e.g. disabled, overrideStyles, etc. ) */
footerOptions: PropTypes.object,
/** Clear the suggestions list upon input blur */
clearSuggestionsOnBlur: PropTypes.bool,
/** If set to `true`, we will attempt to get a Google location from the input's text if there are no suggestions. This is useful when looking for locations for which google does not give suggestions - for example: Apartment/Apt */
fallbackToManual: PropTypes.bool,
/** Shows the Powered By Google credit in a fixed footer */
poweredByGoogle: PropTypes.bool,
/** Sets how to get more details for a place (e.g. geocode, places, etc) */
handler: PropTypes.oneOf([GoogleAddressInputHandler.geocode, GoogleAddressInputHandler.places])
};
export default GoogleAddressInput;