UNPKG

wix-style-react

Version:
415 lines (359 loc) • 15.1 kB
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;