diff --git a/src/components/AddressSearch.js b/src/components/AddressSearch.js
index 2cb3df16232f..dac2f8cd7c8d 100644
--- a/src/components/AddressSearch.js
+++ b/src/components/AddressSearch.js
@@ -9,6 +9,7 @@ import styles from '../styles/styles';
import TextInput from './TextInput';
import Log from '../libs/Log';
import * as GooglePlacesUtils from '../libs/GooglePlacesUtils';
+import * as FormUtils from '../libs/FormUtils';
// The error that's being thrown below will be ignored until we fork the
// react-native-google-places-autocomplete repo and replace the
@@ -16,6 +17,26 @@ import * as GooglePlacesUtils from '../libs/GooglePlacesUtils';
LogBox.ignoreLogs(['VirtualizedLists should never be nested']);
const propTypes = {
+ /** Indicates that the input is being used with the Form component */
+ isFormInput: PropTypes.bool,
+
+ /**
+ * The ID used to uniquely identify the input
+ *
+ * @param {Object} props - props passed to the input
+ * @returns {Object} - returns an Error object if isFormInput is supplied but inputID is falsey or not a string
+ */
+ inputID: props => FormUtils.validateInputIDProps(props),
+
+ /** Saves a draft of the input value when used in a form */
+ shouldSaveDraft: PropTypes.bool,
+
+ /** Callback that is called when the text input is blurred */
+ onBlur: PropTypes.func,
+
+ /** Error text to display */
+ errorText: PropTypes.string,
+
/** The label to display for the field */
label: PropTypes.string.isRequired,
@@ -32,7 +53,12 @@ const propTypes = {
};
const defaultProps = {
- value: '',
+ isFormInput: false,
+ inputID: undefined,
+ shouldSaveDraft: false,
+ onBlur: () => {},
+ errorText: '',
+ value: undefined,
containerStyles: [],
};
@@ -66,7 +92,7 @@ const AddressSearch = (props) => {
const state = GooglePlacesUtils.getAddressComponent(addressComponents, 'administrative_area_level_1', 'short_name');
const values = {};
- if (street && street.length > props.value.trim().length) {
+ if (street && props.value && street.length > props.value.trim().length) {
// We are only passing the street number and name if the combined length is longer than the value
// that was initially passed to the autocomplete component. Google Places can truncate details
// like Apt # and this is the best way we have to tell that the new value it's giving us is less
@@ -111,10 +137,27 @@ const AddressSearch = (props) => {
}}
textInputProps={{
InputComp: TextInput,
+ ref: (node) => {
+ if (!props.innerRef) {
+ return;
+ }
+
+ if (_.isFunction(props.innerRef)) {
+ props.innerRef(node);
+ return;
+ }
+
+ // eslint-disable-next-line no-param-reassign
+ props.innerRef.current = node;
+ },
label: props.label,
containerStyles: props.containerStyles,
errorText: props.errorText,
value: props.value,
+ isFormInput: props.isFormInput,
+ inputID: props.inputID,
+ shouldSaveDraft: props.shouldSaveDraft,
+ onBlur: props.onBlur,
onChangeText: (text) => {
if (skippedFirstOnChangeTextRef.current) {
props.onChange({street: text});
@@ -160,4 +203,7 @@ const AddressSearch = (props) => {
AddressSearch.propTypes = propTypes;
AddressSearch.defaultProps = defaultProps;
-export default withLocalize(AddressSearch);
+export default withLocalize(React.forwardRef((props, ref) => (
+ // eslint-disable-next-line react/jsx-props-no-spreading
+
+)));
diff --git a/src/stories/AddressSearch.stories.js b/src/stories/AddressSearch.stories.js
new file mode 100644
index 000000000000..6f03680c47f7
--- /dev/null
+++ b/src/stories/AddressSearch.stories.js
@@ -0,0 +1,42 @@
+import React, {useState} from 'react';
+import AddressSearch from '../components/AddressSearch';
+
+/**
+ * We use the Component Story Format for writing stories. Follow the docs here:
+ *
+ * https://storybook.js.org/docs/react/writing-stories/introduction#component-story-format
+ */
+export default {
+ title: 'Components/AddressSearch',
+ component: AddressSearch,
+ args: {
+ label: 'Enter street',
+ errorText: '',
+ },
+};
+
+const Template = (args) => {
+ const [value, setValue] = useState('');
+ return (
+ setValue(street)}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...args}
+ />
+ );
+};
+
+// Arguments can be passed to the component by binding
+// See: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
+const Default = Template.bind({});
+
+const ErrorStory = Template.bind({});
+ErrorStory.args = {
+ errorText: 'The street you are looking for does not exist',
+};
+
+export {
+ Default,
+ ErrorStory,
+};
diff --git a/src/stories/Form.stories.js b/src/stories/Form.stories.js
index f8b0a9b8cbe3..a9f2ffbd5e56 100644
--- a/src/stories/Form.stories.js
+++ b/src/stories/Form.stories.js
@@ -1,6 +1,7 @@
import React from 'react';
import {View} from 'react-native';
import TextInput from '../components/TextInput';
+import AddressSearch from '../components/AddressSearch';
import Form from '../components/Form';
import * as FormActions from '../libs/actions/FormActions';
import styles from '../styles/styles';
@@ -13,7 +14,7 @@ import styles from '../styles/styles';
const story = {
title: 'Components/Form',
component: Form,
- subcomponents: {TextInput},
+ subcomponents: {TextInput, AddressSearch},
};
const Template = (args) => {
@@ -39,6 +40,12 @@ const Template = (args) => {
containerStyles={[styles.mt4]}
isFormInput
/>
+
);
};