UNPKG

wix-style-react

Version:
218 lines (179 loc) 7.13 kB
import React, { useCallback, useMemo, useRef, useImperativeHandle, } from 'react'; import PropTypes from 'prop-types'; import AddressInput from '../AddressInput'; import { addressInputItemBuilder } from '../AddressInputItem'; import usePlacesAutocomplete from '../providers/usePlacesAutocomplete'; import useAtlasClient from '../providers/useAtlasClient'; import { dataHooks } from './constants'; const AtlasAddressInput = React.forwardRef( ( { baseUrl, token, debounceMs, debounceFn, onChange, onClear, onSelect, onError, selectOnSubmit, optionLayout, optionPrefix, optionSuffix, status: statusProp, ...props }, ref, ) => { const client = useAtlasClient({ baseUrl, token }); const { predictions, updatePredictions, clearPredictions, loading } = usePlacesAutocomplete({ client, debounceMs, debounceFn, onError }); // If not loading, show the status passed from props const status = loading ? 'loading' : statusProp; const options = useMemo( () => predictions.map(prediction => addressInputItemBuilder({ id: prediction.searchId, mainLabel: prediction.textStructure.mainText, secondaryLabel: prediction.textStructure.secondaryText, displayLabel: prediction.description, optionLayout, prefix: optionPrefix, suffix: optionSuffix, dataHook: dataHooks.item, }), ), [predictions, optionLayout, optionPrefix, optionSuffix], ); const innerRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => innerRef?.current?.focus(), })); const _onChange = useCallback( event => { updatePredictions(event.target.value); onChange && onChange(event); }, [updatePredictions, onChange], ); const _onClear = useCallback(() => { clearPredictions(); onClear && onClear(); }, [clearPredictions, onClear]); const _onSelect = useCallback( option => { const getAddress = () => client.getAddress(option.id); onSelect && onSelect(option, getAddress); }, [client, onSelect], ); // A callback which is called when the user performs a Submit-Action const _onManualSubmit = useCallback( inputValue => { if (selectOnSubmit && onSelect && inputValue) { const option = addressInputItemBuilder({ id: inputValue, mainLabel: inputValue, displayLabel: inputValue, }); const getAddress = async () => { // search for address matching input value const addresses = await client.searchAddresses(inputValue); // Return first address result return addresses[0]; }; onSelect(option, getAddress); } }, [selectOnSubmit, onSelect, client], ); return ( <AddressInput {...props} options={options} onChange={_onChange} onClear={_onClear} onSelect={_onSelect} onManuallyInput={_onManualSubmit} status={status} ref={innerRef} /> ); }, ); AtlasAddressInput.displayName = 'AtlasAddressInput'; AtlasAddressInput.propTypes = { /** Accept a custom domain for WixAtlasServiceWeb to retrieve predictions from */ baseUrl: PropTypes.string, /** Sets an authorization token to pass to the Atlas Service */ token: PropTypes.string, /** Fetch predictions debounce in milliseconds (default: 200) */ debounceMs: PropTypes.number, /** Allows passing a custom debounce function (default: lodash debounce). * Usage: * (callback: Function, debounceMs: number) => Function */ debounceFn: PropTypes.func, /** Applies a data-hook HTML attribute that can be used in the tests */ dataHook: PropTypes.string, /** Specifies a CSS class name to be appended to the component’s root element */ className: PropTypes.string, /** Displays clear button (X) on a non-empty input */ clearButton: PropTypes.bool, /** Sets the initial input value */ initialValue: PropTypes.string, /** Sets a value to display (controlled mode) */ value: PropTypes.string, /** Specifies whether input is disabled */ disabled: PropTypes.bool, /** Defines a callback function which is called whenever a user selects a different option in the list. * @param {DropdownLayoutOption} option selected option * @param {() => Promise<Address>} getAddress function for retrieving additional place details */ onSelect: PropTypes.func, /** Defines a callback function which is called every time input value is changed */ onChange: PropTypes.func, /** Defines a handler for getting notified upon a clear event. When passed, it displays a clear button in the input. */ onClear: PropTypes.func, /** Defines a standard input onBlur callback */ onBlur: PropTypes.func, /** Specifies whether to trigger `onSelect` handler when performing a Submit-Action (Enter or Tab key down). * If set to true, `onSelect` will be called with the following params: * * `option`: an option with a label set to the input value. * * `getAddress`: function for retrieving additional place details * uses Atlas's search function to return the closest result to the input value * * This is useful when looking for locations for which Atlas does not give suggestions - for example: Apartment/Apt. */ selectOnSubmit: PropTypes.bool, /** Defines a handler for prediction fetching errors. Returns an error object. * you can read these [guidelines](https://bo.wix.com/wix-docs/rnd/platformization-guidelines/errors#platformization-guidelines_errors_errors) * to learn about the meaning of each error status. */ onError: PropTypes.func, /** Specify the status of a field. Mostly used for a “loading” indication upon async request calls. */ status: PropTypes.oneOf(['loading', 'error', 'warning']), /** Defines the message to display on status icon hover. If not given or empty there will be no tooltip */ statusMessage: PropTypes.node, /** Control the border style of an input */ border: PropTypes.oneOf(['standard', 'round', 'bottomLine']), /** Controls the size of the input */ size: PropTypes.oneOf(['small', 'medium', 'large']), /** Sets a placeholder message to display */ placeholder: PropTypes.string, /** Sets the message to show in a dropdown when no results are found */ noResultsText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), /** Sets the layout of `mainLabel` and `secondaryLabel`. The possible options can be either side by side or vertically stacked. */ optionLayout: PropTypes.oneOf(['single-line', 'double-line']), /** Pass any component to show as the prefix of the option, e.g., text, icon. */ optionPrefix: PropTypes.node, /** Pass any component to show as the suffix of the option, e.g., text, icon, button. */ optionSuffix: PropTypes.node, }; export default AtlasAddressInput;