@navinc/base-react-components
Version:
Nav's Pattern Library
119 lines • 7.25 kB
JavaScript
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