UNPKG

@navinc/base-react-components

Version:
119 lines 7.25 kB
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, jsxs as _jsxs } from "react/jsx-runtime"; /// <reference types="@types/google.maps" /> import { noop } from '@navinc/utils'; import { useEffect, useRef } from 'react'; import { styled } from 'styled-components'; import { Copy } from '../copy.js'; import { Err, Errors, Field, FieldWrapper, Input, Label } from './shared.js'; import { redactProps } from '../redact/redact.js'; import { loadPlacesAutocomplete } from '../load-places-autocomplete.js'; const handlePreventSubmitOnEnter = (keyDownEvent) => { if (keyDownEvent.keyCode === 13) keyDownEvent.preventDefault(); }; const UnstyledAddressInput = (_a) => { var { className, label, hasSpaceForErrors, isInvalid, value, required, type, errors = [], lede = '', onAddressSelected = noop, touched, placeholder = 'Enter a location', isPrivate = true, autocompleteDropdownClassName } = _a, props = __rest(_a, ["className", "label", "hasSpaceForErrors", "isInvalid", "value", "required", "type", "errors", "lede", "onAddressSelected", "touched", "placeholder", "isPrivate", "autocompleteDropdownClassName"]); const inputRef = useRef(null); useEffect(() => { // Add className to autocomplete dropdown once it's added to the DOM // https://developers.google.com/maps/documentation/javascript/place-autocomplete#style-autocomplete let autocompleteElement = null; const autocompleteDropdownObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1 && node instanceof HTMLElement && node.classList.contains('pac-container')) { if (autocompleteDropdownClassName) { node.classList.add(...autocompleteDropdownClassName.split(' ').map((className) => className.trim())); } autocompleteElement = node; autocompleteDropdownObserver.disconnect(); } }); }); }); autocompleteDropdownObserver.observe(document.body, { childList: true }); loadPlacesAutocomplete() .then((Autocomplete) => { const autocomplete = new Autocomplete(inputRef.current, { 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, }))); onAddressSelected({ city: city || subcity, state, street1, zip, country: country === 'United States' ? 'United States of America' : country, }); }); }) .catch((err) => console.error(err)); return () => { // Clean up Autocomplete dropdown autocompleteElement === null || autocompleteElement === void 0 ? void 0 : autocompleteElement.remove(); autocompleteDropdownObserver.disconnect(); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (_jsxs(FieldWrapper, { className: className, children: [lede && _jsx(Copy, { children: lede }), _jsxs(Field, Object.assign({}, (isPrivate && redactProps), { isVisited: touched || !!value || !!placeholder, onKeyDown: handlePreventSubmitOnEnter, children: [_jsx(Input, Object.assign({ ref: inputRef, type: type, required: required, value: value, isInvalid: isInvalid, placeholder: placeholder, "data-testid": `input:${props.name}` }, props)), _jsx(Label, { required: required, children: label })] })), _jsx(Errors, { hasSpaceForErrors: hasSpaceForErrors, children: !!errors.length && errors.map((err, i) => _jsx(Err, { children: err }, `err-${i}`)) })] })); }; /** Use the `<AddressInput />` component when full address information is needed. The AddressInput component is a fully uncontrolled component. Nav uses Google Maps Autocomplete api to autocomplete and validate addresses. It accepts an `onAddressSelected` function as a prop which is called once a complete addressed is selected from the Google Maps dropdown list. The `onAddressSelected` function is passed a structured address with the following fields: `street1`, `city`, `state`, `zip`. * * @example * ```tsx * <AddressInput * onAddressSelected={({ street1, city, state, zip }) => console.log({ street1, city, state, zip })} * label='Address' * /> * ``` * * #### Props * * AddressInput 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. * * ##### onAddressSelected * * 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 AddressInput component calls `onAddressSelected` passing it an object of address parts: * * ``` * { * street1: String, * city: String, * state: String, * zip: String * } * ``` * * @deprecated This component is deprecated and will be removed in a future release. Avoid using it in new code. */ export const AddressInput = styled(UnstyledAddressInput).withConfig({ displayName: "brc-sc-AddressInput", componentId: "brc-sc-8kwpqc" }) ``; //# sourceMappingURL=address-input.js.map