@navinc/base-react-components
Version:
Nav's Pattern Library
109 lines • 5.9 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx } from "react/jsx-runtime";
import { forwardRef, useEffect, useRef } from 'react';
import { BaseStringInput } from '../base-string-input/base-string-input.js';
import { combineRefs } from '../../combine-refs.js';
import { triggerChangeEvent } from '../../trigger-change.js';
import { loadPlacesAutocomplete } from '../../load-places-autocomplete.js';
const setupAutocomplete = (input, onAddressSelect) => __awaiter(void 0, void 0, void 0, function* () {
const Autocomplete = yield loadPlacesAutocomplete();
const autocomplete = new Autocomplete(input, {
types: ['address'],
componentRestrictions: { country: 'us' },
});
autocomplete.addListener('place_changed', () => {
const place = autocomplete.getPlace();
// bail if there is a problem getting data from the api
if (!place || !Array.isArray(place.address_components))
return;
const { locality: city = '', sublocality_level_1: subcity = '', administrative_area_level_1: state = '', postal_code: zip = '', street_number: streetNumber = '', route: street = '', street1 = `${streetNumber} ${street}`.trim(), country = '', } = Object.assign({}, ...place.address_components
.filter(({ types: [type] }) => [
'street_number',
'route',
'locality',
'sublocality_level_1',
'administrative_area_level_1',
'postal_code',
'country',
].includes(type))
.map(({ types: [type], long_name: longName, short_name: shortName }) => ({
[type]: ['route', 'locality', 'sublocality_level_1', 'country'].includes(type) ? longName : shortName,
})));
// trigger change event to keep the updated input value in sync with state
triggerChangeEvent(input);
onAddressSelect({
city: city || subcity,
state,
street1,
zip,
country: country === 'United States' ? 'United States of America' : country,
});
});
});
/** Use the `<BaseAddressTypeahead />` component when full address information is needed. The BaseAddressTypeahead component is a fully uncontrolled component. Nav uses Google Maps Autocomplete api to autocomplete and validate addresses. It accepts an `onAddressSelect` function as a prop which is called once a complete addressed is selected from the Google Maps dropdown list. The `onAddressSelect` function is passed a structured address with the following fields: `street1`, `city`, `state`, `zip`.
*
* @example
* ```tsx
* <BaseAddressTypeahead
* onAddressSelect={({ street1, city, state, zip }) => console.log({ street1, city, state, zip })}
* />
* ```
*
* #### Props
*
* BaseAddressTypeahead accepts all the props the Input component accepts -- including `onChange` -- with the exception of `value` -- use `defaultValue` to populate with an existing value at mount time -- and `type` -- the type is internally assigned the value of `text` to not interfere with the Autocomplete functionality -- and with the following additions.
*
* ##### onAddressSelect
*
* The GoogleMaps Autocomplete API binds to an input element and provides a dropdown of autocompleted addresses to choose from. When the user clicks on one of these, the input's value is updated to reflect the address string and the BaseAddressTypeahead component calls `onAddressSelect` passing it an object of address parts:
*
* ```
* {
* street1: String,
* city: String,
* state: String,
* zip: String
* }
* ```
*/
export const BaseAddressTypeahead = forwardRef((_a, ref) => {
var { onKeyDown, onAddressSelect } = _a, props = __rest(_a, ["onKeyDown", "onAddressSelect"]);
const inputRef = useRef(null);
const onAddressSelectRef = useRef(onAddressSelect);
const combinedInputRef = combineRefs(inputRef, ref);
onAddressSelectRef.current = onAddressSelect;
useEffect(() => {
if (inputRef.current) {
setupAutocomplete(inputRef.current, (addr) => { var _a; return (_a = onAddressSelectRef.current) === null || _a === void 0 ? void 0 : _a.call(onAddressSelectRef, addr); }).catch((err) =>
// eslint-disable-next-line no-console -- not sure what to do here, this is what we've done in the old AddressInput
console.error(err));
}
}, []);
return (_jsx(BaseStringInput, Object.assign({ ref: combinedInputRef, onKeyDown: (e) => {
if (e.keyCode === 13) {
e.preventDefault();
return;
}
onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(e);
} }, props)));
});
//# sourceMappingURL=base-address-typeahead.js.map