react-native-google-places-autocomplete 2.5.6 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GooglePlacesAutocomplete.d.ts +11 -0
- package/GooglePlacesAutocomplete.js +754 -553
- package/README.md +0 -18
- package/example/App.js +221 -0
- package/example/README.md +64 -0
- package/example/app.json +24 -0
- package/example/babel.config.js +6 -0
- package/example/package.json +23 -0
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable react-native/no-inline-styles */
|
|
2
2
|
import debounce from 'lodash.debounce';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
3
|
import Qs from 'qs';
|
|
4
|
+
import { randomUUID } from 'expo-crypto';
|
|
5
5
|
import React, {
|
|
6
6
|
forwardRef,
|
|
7
7
|
useMemo,
|
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
View,
|
|
26
26
|
} from 'react-native';
|
|
27
27
|
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// CONSTANTS
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
28
32
|
const defaultStyles = {
|
|
29
33
|
container: {
|
|
30
34
|
flex: 1,
|
|
@@ -42,7 +46,9 @@ const defaultStyles = {
|
|
|
42
46
|
flex: 1,
|
|
43
47
|
marginBottom: 5,
|
|
44
48
|
},
|
|
45
|
-
listView: {
|
|
49
|
+
listView: {
|
|
50
|
+
backgroundColor: '#FFFFFF',
|
|
51
|
+
},
|
|
46
52
|
row: {
|
|
47
53
|
backgroundColor: '#FFFFFF',
|
|
48
54
|
padding: 13,
|
|
@@ -70,40 +76,195 @@ const defaultStyles = {
|
|
|
70
76
|
powered: {},
|
|
71
77
|
};
|
|
72
78
|
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// COMPONENT
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
73
83
|
export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
// ==========================================================================
|
|
85
|
+
// PROPS DESTRUCTURING
|
|
86
|
+
// ==========================================================================
|
|
87
|
+
const {
|
|
88
|
+
autoFillOnNotFound = false,
|
|
89
|
+
currentLocation = false,
|
|
90
|
+
currentLocationLabel = 'Current location',
|
|
91
|
+
debounce: debounceMs = 0,
|
|
92
|
+
disableScroll = false,
|
|
93
|
+
enableHighAccuracyLocation = true,
|
|
94
|
+
enablePoweredByContainer = true,
|
|
95
|
+
fetchDetails = false,
|
|
96
|
+
filterReverseGeocodingByTypes = [],
|
|
97
|
+
GooglePlacesDetailsQuery = {},
|
|
98
|
+
GooglePlacesSearchQuery = {
|
|
99
|
+
rankby: 'distance',
|
|
100
|
+
type: 'restaurant',
|
|
101
|
+
},
|
|
102
|
+
GoogleReverseGeocodingQuery = {},
|
|
103
|
+
isRowScrollable = true,
|
|
104
|
+
keyboardShouldPersistTaps = 'always',
|
|
105
|
+
listHoverColor = '#ececec',
|
|
106
|
+
listUnderlayColor = '#c8c7cc',
|
|
107
|
+
listViewDisplayed: listViewDisplayedProp = 'auto',
|
|
108
|
+
keepResultsAfterBlur = false,
|
|
109
|
+
minLength = 0,
|
|
110
|
+
nearbyPlacesAPI = 'GooglePlacesSearch',
|
|
111
|
+
numberOfLines = 1,
|
|
112
|
+
onFail = () => {},
|
|
113
|
+
onNotFound = () => {},
|
|
114
|
+
onPress = () => {},
|
|
115
|
+
onTimeout = () =>
|
|
116
|
+
console.warn('google places autocomplete: request timeout'),
|
|
117
|
+
placeholder = '',
|
|
118
|
+
predefinedPlaces: predefinedPlacesProp = [],
|
|
119
|
+
predefinedPlacesAlwaysVisible = false,
|
|
120
|
+
query = {
|
|
121
|
+
key: 'missing api key',
|
|
122
|
+
language: 'en',
|
|
123
|
+
types: 'geocode',
|
|
124
|
+
},
|
|
125
|
+
styles = {},
|
|
126
|
+
suppressDefaultStyles = false,
|
|
127
|
+
textInputHide = false,
|
|
128
|
+
textInputProps = {},
|
|
129
|
+
timeout = 20000,
|
|
130
|
+
isNewPlacesAPI = false,
|
|
131
|
+
fields = '*',
|
|
132
|
+
...restProps
|
|
133
|
+
} = props;
|
|
134
|
+
|
|
135
|
+
// ==========================================================================
|
|
136
|
+
// STATE & REFS
|
|
137
|
+
// ==========================================================================
|
|
138
|
+
const predefinedPlaces = useMemo(() => predefinedPlacesProp || [], [
|
|
139
|
+
predefinedPlacesProp,
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
// Store results array - useRef prevents re-renders when updating results, allows access to latest results in callbacks
|
|
143
|
+
const resultsRef = useRef([]);
|
|
144
|
+
|
|
145
|
+
// Store active XMLHttpRequest objects - needed to abort requests when component unmounts or new search starts
|
|
146
|
+
const requestsRef = useRef([]);
|
|
147
|
+
|
|
148
|
+
// Track if navigator warning has been shown - prevents duplicate console warnings
|
|
149
|
+
const hasWarnedAboutNavigator = useRef(false);
|
|
150
|
+
|
|
151
|
+
// Reference to TextInput component - enables imperative methods (focus, blur, clear) via ref
|
|
152
|
+
const inputRef = useRef(null);
|
|
153
|
+
|
|
154
|
+
// Store current query object - allows access to latest query in callbacks without stale closures
|
|
155
|
+
const queryRef = useRef(query);
|
|
156
|
+
|
|
157
|
+
// Store previous query string - used to detect query changes without causing re-renders
|
|
158
|
+
const prevQueryStringRef = useRef(JSON.stringify(query));
|
|
159
|
+
|
|
160
|
+
// Store latest _request function - ensures debounced function always calls current version with latest closures
|
|
161
|
+
const requestRef = useRef(_request);
|
|
162
|
+
const queryString = useMemo(() => JSON.stringify(query), [query]);
|
|
163
|
+
|
|
164
|
+
const [stateText, setStateText] = useState('');
|
|
165
|
+
const [dataSource, setDataSource] = useState([]);
|
|
166
|
+
const [listViewDisplayed, setListViewDisplayed] = useState(
|
|
167
|
+
listViewDisplayedProp === 'auto' ? false : listViewDisplayedProp,
|
|
168
|
+
);
|
|
169
|
+
const [url, setUrl] = useState('');
|
|
170
|
+
const [listLoaderDisplayed, setListLoaderDisplayed] = useState(false);
|
|
171
|
+
const [sessionToken, setSessionToken] = useState(randomUUID());
|
|
172
|
+
|
|
173
|
+
// ==========================================================================
|
|
174
|
+
// UTILITY FUNCTIONS
|
|
175
|
+
// ==========================================================================
|
|
76
176
|
|
|
77
|
-
const hasNavigator = () => {
|
|
177
|
+
const hasNavigator = useCallback(() => {
|
|
78
178
|
if (navigator?.geolocation) {
|
|
79
179
|
return true;
|
|
80
|
-
}
|
|
180
|
+
}
|
|
181
|
+
if (!hasWarnedAboutNavigator.current) {
|
|
182
|
+
if (Platform.OS === 'web') {
|
|
183
|
+
console.warn(
|
|
184
|
+
'Geolocation is not available. For web, ensure your site is served over HTTPS or localhost to use geolocation features.',
|
|
185
|
+
);
|
|
186
|
+
} else {
|
|
187
|
+
console.warn(
|
|
188
|
+
'Geolocation is not available. For React Native, you may need to install and configure @react-native-community/geolocation or expo-location to enable currentLocation.',
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
hasWarnedAboutNavigator.current = true;
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}, []);
|
|
195
|
+
|
|
196
|
+
const supportedPlatform = () => {
|
|
197
|
+
if (Platform.OS === 'web' && !props.requestUrl) {
|
|
81
198
|
console.warn(
|
|
82
|
-
'
|
|
199
|
+
'This library cannot be used for the web unless you specify the requestUrl prop. See https://git.io/JflFv for more for details.',
|
|
83
200
|
);
|
|
84
201
|
return false;
|
|
85
202
|
}
|
|
203
|
+
return true;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const getRequestUrl = (requestUrl) => {
|
|
207
|
+
if (requestUrl) {
|
|
208
|
+
if (requestUrl.useOnPlatform === 'all') {
|
|
209
|
+
return requestUrl.url;
|
|
210
|
+
}
|
|
211
|
+
if (requestUrl.useOnPlatform === 'web') {
|
|
212
|
+
return Platform.select({
|
|
213
|
+
web: requestUrl.url,
|
|
214
|
+
default: 'https://maps.googleapis.com/maps/api',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return 'https://maps.googleapis.com/maps/api';
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const getRequestHeaders = (requestUrl) => {
|
|
222
|
+
return requestUrl?.headers || {};
|
|
86
223
|
};
|
|
87
224
|
|
|
225
|
+
const setRequestHeaders = (request, headers) => {
|
|
226
|
+
Object.keys(headers).forEach((headerKey) =>
|
|
227
|
+
request.setRequestHeader(headerKey, headers[headerKey]),
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const requestShouldUseWithCredentials = useCallback(() => {
|
|
232
|
+
return url === 'https://maps.googleapis.com/maps/api';
|
|
233
|
+
}, [url]);
|
|
234
|
+
|
|
235
|
+
const _abortRequests = useCallback(() => {
|
|
236
|
+
requestsRef.current.forEach((request) => {
|
|
237
|
+
request.onreadystatechange = null;
|
|
238
|
+
request.abort();
|
|
239
|
+
});
|
|
240
|
+
requestsRef.current = [];
|
|
241
|
+
}, []);
|
|
242
|
+
|
|
243
|
+
// ==========================================================================
|
|
244
|
+
// DATA PROCESSING FUNCTIONS
|
|
245
|
+
// ==========================================================================
|
|
246
|
+
|
|
88
247
|
const buildRowsFromResults = useCallback(
|
|
89
248
|
(results, text) => {
|
|
90
249
|
let res = [];
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
250
|
+
// Show predefined places if:
|
|
251
|
+
// 1. No text entered and no results, OR
|
|
252
|
+
// 2. predefinedPlacesAlwaysVisible is true
|
|
253
|
+
const shouldDisplayPredefinedPlaces =
|
|
254
|
+
(!text || text.length === 0) && results.length === 0;
|
|
94
255
|
if (
|
|
95
256
|
shouldDisplayPredefinedPlaces ||
|
|
96
|
-
|
|
257
|
+
predefinedPlacesAlwaysVisible === true
|
|
97
258
|
) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(place) => place?.description
|
|
101
|
-
|
|
102
|
-
|
|
259
|
+
if (predefinedPlaces.length > 0) {
|
|
260
|
+
res = [
|
|
261
|
+
...predefinedPlaces.filter((place) => place?.description?.length),
|
|
262
|
+
];
|
|
263
|
+
}
|
|
103
264
|
|
|
104
|
-
if (
|
|
265
|
+
if (currentLocation === true && hasNavigator()) {
|
|
105
266
|
res.unshift({
|
|
106
|
-
description:
|
|
267
|
+
description: currentLocationLabel,
|
|
107
268
|
isCurrentLocation: true,
|
|
108
269
|
});
|
|
109
270
|
}
|
|
@@ -117,109 +278,310 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
117
278
|
return [...res, ...results];
|
|
118
279
|
},
|
|
119
280
|
[
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
281
|
+
predefinedPlacesAlwaysVisible,
|
|
282
|
+
predefinedPlaces,
|
|
283
|
+
currentLocation,
|
|
284
|
+
currentLocationLabel,
|
|
285
|
+
hasNavigator,
|
|
124
286
|
],
|
|
125
287
|
);
|
|
126
288
|
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
289
|
+
const _filterResultsByTypes = useCallback((unfilteredResults, types) => {
|
|
290
|
+
if (!types || types.length === 0) return unfilteredResults;
|
|
291
|
+
|
|
292
|
+
const results = [];
|
|
293
|
+
for (let i = 0; i < unfilteredResults.length; i++) {
|
|
294
|
+
let found = false;
|
|
295
|
+
|
|
296
|
+
for (let j = 0; j < types.length; j++) {
|
|
297
|
+
if (unfilteredResults[i].types?.indexOf(types[j]) !== -1) {
|
|
298
|
+
found = true;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
131
301
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
default: 'https://maps.googleapis.com/maps/api',
|
|
136
|
-
});
|
|
302
|
+
|
|
303
|
+
if (found === true) {
|
|
304
|
+
results.push(unfilteredResults[i]);
|
|
137
305
|
}
|
|
138
|
-
} else {
|
|
139
|
-
return 'https://maps.googleapis.com/maps/api';
|
|
140
306
|
}
|
|
307
|
+
return results;
|
|
141
308
|
}, []);
|
|
142
309
|
|
|
143
|
-
const
|
|
144
|
-
|
|
310
|
+
const _filterResultsByPlacePredictions = (unfilteredResults) => {
|
|
311
|
+
const results = [];
|
|
312
|
+
for (let i = 0; i < unfilteredResults.length; i++) {
|
|
313
|
+
if (unfilteredResults[i].placePrediction) {
|
|
314
|
+
results.push({
|
|
315
|
+
description: unfilteredResults[i].placePrediction.text?.text,
|
|
316
|
+
place_id: unfilteredResults[i].placePrediction.placeId,
|
|
317
|
+
reference: unfilteredResults[i].placePrediction.placeId,
|
|
318
|
+
structured_formatting: {
|
|
319
|
+
main_text:
|
|
320
|
+
unfilteredResults[i].placePrediction.structuredFormat?.mainText
|
|
321
|
+
?.text,
|
|
322
|
+
secondary_text:
|
|
323
|
+
unfilteredResults[i].placePrediction.structuredFormat
|
|
324
|
+
?.secondaryText?.text,
|
|
325
|
+
},
|
|
326
|
+
types: unfilteredResults[i].placePrediction.types ?? [],
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return results;
|
|
145
331
|
};
|
|
146
332
|
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
};
|
|
333
|
+
const _getPredefinedPlace = (rowData) => {
|
|
334
|
+
if (rowData.isPredefinedPlace !== true) {
|
|
335
|
+
return rowData;
|
|
336
|
+
}
|
|
152
337
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
338
|
+
if (predefinedPlaces.length > 0) {
|
|
339
|
+
for (let i = 0; i < predefinedPlaces.length; i++) {
|
|
340
|
+
if (predefinedPlaces[i].description === rowData.description) {
|
|
341
|
+
return predefinedPlaces[i];
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
160
345
|
|
|
161
|
-
|
|
346
|
+
return rowData;
|
|
347
|
+
};
|
|
162
348
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
349
|
+
// ==========================================================================
|
|
350
|
+
// API REQUEST FUNCTIONS
|
|
351
|
+
// ==========================================================================
|
|
166
352
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
_handleChangeText(stateText);
|
|
170
|
-
return () => {
|
|
353
|
+
const _requestNearby = useCallback(
|
|
354
|
+
(latitude, longitude) => {
|
|
171
355
|
_abortRequests();
|
|
172
|
-
};
|
|
173
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
174
|
-
}, [props.query]);
|
|
175
356
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
357
|
+
if (
|
|
358
|
+
latitude !== undefined &&
|
|
359
|
+
longitude !== undefined &&
|
|
360
|
+
latitude !== null &&
|
|
361
|
+
longitude !== null
|
|
362
|
+
) {
|
|
363
|
+
const request = new XMLHttpRequest();
|
|
364
|
+
requestsRef.current.push(request);
|
|
365
|
+
request.timeout = timeout;
|
|
366
|
+
request.ontimeout = onTimeout;
|
|
367
|
+
request.onreadystatechange = () => {
|
|
368
|
+
if (request.readyState !== 4) {
|
|
369
|
+
setListLoaderDisplayed(true);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
setListLoaderDisplayed(false);
|
|
374
|
+
if (request.status === 200) {
|
|
375
|
+
const responseJSON = JSON.parse(request.responseText);
|
|
376
|
+
|
|
377
|
+
_disableRowLoaders();
|
|
378
|
+
|
|
379
|
+
if (typeof responseJSON.results !== 'undefined') {
|
|
380
|
+
let results = [];
|
|
381
|
+
if (nearbyPlacesAPI === 'GoogleReverseGeocoding') {
|
|
382
|
+
results = _filterResultsByTypes(
|
|
383
|
+
responseJSON.results,
|
|
384
|
+
filterReverseGeocodingByTypes,
|
|
385
|
+
);
|
|
386
|
+
} else {
|
|
387
|
+
results = responseJSON.results;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
resultsRef.current = results;
|
|
391
|
+
const newDataSource = buildRowsFromResults(results);
|
|
392
|
+
setDataSource(newDataSource);
|
|
393
|
+
// Auto-show list when results arrive if in 'auto' mode
|
|
394
|
+
if (
|
|
395
|
+
listViewDisplayedProp === 'auto' &&
|
|
396
|
+
newDataSource.length > 0
|
|
397
|
+
) {
|
|
398
|
+
setListViewDisplayed(true);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (typeof responseJSON.error_message !== 'undefined') {
|
|
402
|
+
if (!onFail) {
|
|
403
|
+
console.warn(
|
|
404
|
+
'google places autocomplete: ' + responseJSON.error_message,
|
|
405
|
+
);
|
|
406
|
+
} else {
|
|
407
|
+
onFail(responseJSON.error_message);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
let requestUrl = '';
|
|
414
|
+
if (nearbyPlacesAPI === 'GoogleReverseGeocoding') {
|
|
415
|
+
// your key must be allowed to use Google Maps Geocoding API
|
|
416
|
+
requestUrl =
|
|
417
|
+
`${url}/geocode/json?` +
|
|
418
|
+
Qs.stringify({
|
|
419
|
+
latlng: latitude + ',' + longitude,
|
|
420
|
+
key: query.key,
|
|
421
|
+
...GoogleReverseGeocodingQuery,
|
|
422
|
+
});
|
|
423
|
+
} else {
|
|
424
|
+
requestUrl =
|
|
425
|
+
`${url}/place/nearbysearch/json?` +
|
|
426
|
+
Qs.stringify({
|
|
427
|
+
location: latitude + ',' + longitude,
|
|
428
|
+
key: query.key,
|
|
429
|
+
...GooglePlacesSearchQuery,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
request.open('GET', requestUrl);
|
|
434
|
+
|
|
435
|
+
request.withCredentials = requestShouldUseWithCredentials();
|
|
436
|
+
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
180
437
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
438
|
+
request.send();
|
|
439
|
+
} else {
|
|
440
|
+
resultsRef.current = [];
|
|
441
|
+
setDataSource(buildRowsFromResults([]));
|
|
442
|
+
}
|
|
184
443
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
444
|
+
[
|
|
445
|
+
_abortRequests,
|
|
446
|
+
timeout,
|
|
447
|
+
onTimeout,
|
|
448
|
+
_disableRowLoaders,
|
|
449
|
+
nearbyPlacesAPI,
|
|
450
|
+
_filterResultsByTypes,
|
|
451
|
+
filterReverseGeocodingByTypes,
|
|
452
|
+
buildRowsFromResults,
|
|
453
|
+
listViewDisplayedProp,
|
|
454
|
+
onFail,
|
|
455
|
+
url,
|
|
456
|
+
query,
|
|
457
|
+
GoogleReverseGeocodingQuery,
|
|
458
|
+
GooglePlacesSearchQuery,
|
|
459
|
+
requestShouldUseWithCredentials,
|
|
460
|
+
props.requestUrl,
|
|
461
|
+
],
|
|
462
|
+
);
|
|
203
463
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
464
|
+
const _request = (text) => {
|
|
465
|
+
_abortRequests();
|
|
466
|
+
|
|
467
|
+
if (!url) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (supportedPlatform() && text && text.length >= minLength) {
|
|
472
|
+
const request = new XMLHttpRequest();
|
|
473
|
+
requestsRef.current.push(request);
|
|
474
|
+
|
|
475
|
+
request.timeout = timeout;
|
|
476
|
+
request.ontimeout = onTimeout;
|
|
477
|
+
request.onreadystatechange = () => {
|
|
478
|
+
if (request.readyState !== 4) {
|
|
479
|
+
setListLoaderDisplayed(true);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
setListLoaderDisplayed(false);
|
|
484
|
+
|
|
485
|
+
if (request.status === 200) {
|
|
486
|
+
const responseJSON = JSON.parse(request.responseText);
|
|
487
|
+
|
|
488
|
+
if (typeof responseJSON.predictions !== 'undefined') {
|
|
489
|
+
const results =
|
|
490
|
+
nearbyPlacesAPI === 'GoogleReverseGeocoding'
|
|
491
|
+
? _filterResultsByTypes(
|
|
492
|
+
responseJSON.predictions,
|
|
493
|
+
filterReverseGeocodingByTypes,
|
|
494
|
+
)
|
|
495
|
+
: responseJSON.predictions;
|
|
496
|
+
|
|
497
|
+
resultsRef.current = results;
|
|
498
|
+
const newDataSource = buildRowsFromResults(results, text);
|
|
499
|
+
setDataSource(newDataSource);
|
|
500
|
+
// Auto-show list when results arrive if in 'auto' mode
|
|
501
|
+
if (listViewDisplayedProp === 'auto' && newDataSource.length > 0) {
|
|
502
|
+
setListViewDisplayed(true);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (typeof responseJSON.suggestions !== 'undefined') {
|
|
506
|
+
const results = _filterResultsByPlacePredictions(
|
|
507
|
+
responseJSON.suggestions,
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
resultsRef.current = results;
|
|
511
|
+
const newDataSource = buildRowsFromResults(results, text);
|
|
512
|
+
setDataSource(newDataSource);
|
|
513
|
+
// Auto-show list when results arrive if in 'auto' mode
|
|
514
|
+
if (listViewDisplayedProp === 'auto' && newDataSource.length > 0) {
|
|
515
|
+
setListViewDisplayed(true);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
if (typeof responseJSON.error_message !== 'undefined') {
|
|
519
|
+
if (!onFail) {
|
|
520
|
+
console.warn(
|
|
521
|
+
'google places autocomplete: ' + responseJSON.error_message,
|
|
522
|
+
);
|
|
523
|
+
} else {
|
|
524
|
+
onFail(responseJSON.error_message);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
} else {
|
|
528
|
+
console.warn(
|
|
529
|
+
'google places autocomplete: request could not be completed or has been aborted',
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
if (props.preProcess) {
|
|
535
|
+
setStateText(props.preProcess(text));
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (isNewPlacesAPI) {
|
|
539
|
+
const keyQueryParam = query.key
|
|
540
|
+
? '?' +
|
|
541
|
+
Qs.stringify({
|
|
542
|
+
key: query.key,
|
|
543
|
+
})
|
|
544
|
+
: '';
|
|
545
|
+
request.open('POST', `${url}/v1/places:autocomplete${keyQueryParam}`);
|
|
546
|
+
} else {
|
|
547
|
+
request.open(
|
|
548
|
+
'GET',
|
|
549
|
+
`${url}/place/autocomplete/json?input=` +
|
|
550
|
+
encodeURIComponent(text) +
|
|
551
|
+
'&' +
|
|
552
|
+
Qs.stringify(query),
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
request.withCredentials = requestShouldUseWithCredentials();
|
|
557
|
+
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
558
|
+
|
|
559
|
+
if (isNewPlacesAPI) {
|
|
560
|
+
const { key, locationbias, types, ...rest } = query;
|
|
561
|
+
request.send(
|
|
562
|
+
JSON.stringify({
|
|
563
|
+
input: text,
|
|
564
|
+
sessionToken,
|
|
565
|
+
...rest,
|
|
566
|
+
}),
|
|
567
|
+
);
|
|
568
|
+
} else {
|
|
569
|
+
request.send();
|
|
570
|
+
}
|
|
210
571
|
} else {
|
|
211
|
-
|
|
572
|
+
resultsRef.current = [];
|
|
573
|
+
setDataSource(buildRowsFromResults([]));
|
|
212
574
|
}
|
|
213
575
|
};
|
|
214
576
|
|
|
215
|
-
const getCurrentLocation = () => {
|
|
577
|
+
const getCurrentLocation = useCallback(() => {
|
|
216
578
|
let options = {
|
|
217
579
|
enableHighAccuracy: false,
|
|
218
580
|
timeout: 20000,
|
|
219
581
|
maximumAge: 1000,
|
|
220
582
|
};
|
|
221
583
|
|
|
222
|
-
if (
|
|
584
|
+
if (enableHighAccuracyLocation && Platform.OS === 'android') {
|
|
223
585
|
options = {
|
|
224
586
|
enableHighAccuracy: true,
|
|
225
587
|
timeout: 20000,
|
|
@@ -227,14 +589,14 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
227
589
|
}
|
|
228
590
|
const getCurrentPosition =
|
|
229
591
|
navigator.geolocation.getCurrentPosition ||
|
|
230
|
-
navigator.geolocation.default
|
|
592
|
+
navigator.geolocation.default?.getCurrentPosition;
|
|
231
593
|
|
|
232
|
-
getCurrentPosition
|
|
594
|
+
if (getCurrentPosition) {
|
|
233
595
|
getCurrentPosition(
|
|
234
596
|
(position) => {
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
description:
|
|
597
|
+
if (nearbyPlacesAPI === 'None') {
|
|
598
|
+
const currentLocationData = {
|
|
599
|
+
description: currentLocationLabel,
|
|
238
600
|
geometry: {
|
|
239
601
|
location: {
|
|
240
602
|
lat: position.coords.latitude,
|
|
@@ -244,7 +606,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
244
606
|
};
|
|
245
607
|
|
|
246
608
|
_disableRowLoaders();
|
|
247
|
-
|
|
609
|
+
onPress(currentLocationData, currentLocationData);
|
|
248
610
|
} else {
|
|
249
611
|
_requestNearby(position.coords.latitude, position.coords.longitude);
|
|
250
612
|
}
|
|
@@ -255,10 +617,47 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
255
617
|
},
|
|
256
618
|
options,
|
|
257
619
|
);
|
|
620
|
+
}
|
|
621
|
+
}, [
|
|
622
|
+
enableHighAccuracyLocation,
|
|
623
|
+
currentLocationLabel,
|
|
624
|
+
nearbyPlacesAPI,
|
|
625
|
+
_disableRowLoaders,
|
|
626
|
+
onPress,
|
|
627
|
+
_requestNearby,
|
|
628
|
+
]);
|
|
629
|
+
|
|
630
|
+
// ==========================================================================
|
|
631
|
+
// EVENT HANDLERS
|
|
632
|
+
// ==========================================================================
|
|
633
|
+
|
|
634
|
+
const _enableRowLoader = (rowData) => {
|
|
635
|
+
const rows = buildRowsFromResults(resultsRef.current);
|
|
636
|
+
for (let i = 0; i < rows.length; i++) {
|
|
637
|
+
if (
|
|
638
|
+
rows[i].place_id === rowData.place_id ||
|
|
639
|
+
(rows[i].isCurrentLocation === true &&
|
|
640
|
+
rowData.isCurrentLocation === true)
|
|
641
|
+
) {
|
|
642
|
+
rows[i].isLoading = true;
|
|
643
|
+
setDataSource(rows);
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
258
647
|
};
|
|
259
648
|
|
|
649
|
+
const _disableRowLoaders = useCallback(() => {
|
|
650
|
+
for (let i = 0; i < resultsRef.current.length; i++) {
|
|
651
|
+
if (resultsRef.current[i].isLoading === true) {
|
|
652
|
+
resultsRef.current[i].isLoading = false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
setDataSource(buildRowsFromResults(resultsRef.current));
|
|
657
|
+
}, [buildRowsFromResults]);
|
|
658
|
+
|
|
260
659
|
const _onPress = (rowData) => {
|
|
261
|
-
if (rowData.isPredefinedPlace !== true &&
|
|
660
|
+
if (rowData.isPredefinedPlace !== true && fetchDetails === true) {
|
|
262
661
|
if (rowData.isLoading === true) {
|
|
263
662
|
// already requesting
|
|
264
663
|
return;
|
|
@@ -273,65 +672,78 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
273
672
|
|
|
274
673
|
// fetch details
|
|
275
674
|
const request = new XMLHttpRequest();
|
|
276
|
-
|
|
277
|
-
request.timeout =
|
|
278
|
-
request.ontimeout =
|
|
675
|
+
requestsRef.current.push(request);
|
|
676
|
+
request.timeout = timeout;
|
|
677
|
+
request.ontimeout = onTimeout;
|
|
279
678
|
request.onreadystatechange = () => {
|
|
280
679
|
if (request.readyState !== 4) return;
|
|
281
680
|
|
|
282
681
|
if (request.status === 200) {
|
|
283
682
|
const responseJSON = JSON.parse(request.responseText);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
683
|
+
if (
|
|
684
|
+
responseJSON.status === 'OK' ||
|
|
685
|
+
(isNewPlacesAPI && responseJSON.id)
|
|
686
|
+
) {
|
|
687
|
+
const details = isNewPlacesAPI ? responseJSON : responseJSON.result;
|
|
288
688
|
_disableRowLoaders();
|
|
289
689
|
_onBlur();
|
|
290
690
|
|
|
291
691
|
setStateText(_renderDescription(rowData));
|
|
292
692
|
|
|
293
693
|
delete rowData.isLoading;
|
|
294
|
-
|
|
295
|
-
// }
|
|
694
|
+
onPress(rowData, details);
|
|
296
695
|
} else {
|
|
297
696
|
_disableRowLoaders();
|
|
298
697
|
|
|
299
|
-
if (
|
|
698
|
+
if (autoFillOnNotFound) {
|
|
300
699
|
setStateText(_renderDescription(rowData));
|
|
301
700
|
delete rowData.isLoading;
|
|
302
701
|
}
|
|
303
702
|
|
|
304
|
-
if (!
|
|
703
|
+
if (!onNotFound) {
|
|
305
704
|
console.warn(
|
|
306
705
|
'google places autocomplete: ' + responseJSON.status,
|
|
307
706
|
);
|
|
308
707
|
} else {
|
|
309
|
-
|
|
708
|
+
onNotFound(responseJSON);
|
|
310
709
|
}
|
|
311
710
|
}
|
|
312
711
|
} else {
|
|
313
712
|
_disableRowLoaders();
|
|
314
713
|
|
|
315
|
-
if (!
|
|
714
|
+
if (!onFail) {
|
|
316
715
|
console.warn(
|
|
317
716
|
'google places autocomplete: request could not be completed or has been aborted',
|
|
318
717
|
);
|
|
319
718
|
} else {
|
|
320
|
-
|
|
719
|
+
onFail('request could not be completed or has been aborted');
|
|
321
720
|
}
|
|
322
721
|
}
|
|
323
722
|
};
|
|
324
723
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
724
|
+
if (isNewPlacesAPI) {
|
|
725
|
+
request.open(
|
|
726
|
+
'GET',
|
|
727
|
+
`${url}/v1/places/${rowData.place_id}?` +
|
|
728
|
+
Qs.stringify({
|
|
729
|
+
key: query.key,
|
|
730
|
+
sessionToken,
|
|
731
|
+
fields,
|
|
732
|
+
}),
|
|
733
|
+
);
|
|
734
|
+
setSessionToken(randomUUID());
|
|
735
|
+
} else {
|
|
736
|
+
request.open(
|
|
737
|
+
'GET',
|
|
738
|
+
`${url}/place/details/json?` +
|
|
739
|
+
Qs.stringify({
|
|
740
|
+
key: query.key,
|
|
741
|
+
placeid: rowData.place_id,
|
|
742
|
+
language: query.language,
|
|
743
|
+
...GooglePlacesDetailsQuery,
|
|
744
|
+
}),
|
|
745
|
+
);
|
|
746
|
+
}
|
|
335
747
|
|
|
336
748
|
request.withCredentials = requestShouldUseWithCredentials();
|
|
337
749
|
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
@@ -350,236 +762,13 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
350
762
|
|
|
351
763
|
_onBlur();
|
|
352
764
|
delete rowData.isLoading;
|
|
353
|
-
|
|
765
|
+
const predefinedPlace = _getPredefinedPlace(rowData);
|
|
354
766
|
|
|
355
767
|
// sending predefinedPlace as details for predefined places
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
const _enableRowLoader = (rowData) => {
|
|
361
|
-
let rows = buildRowsFromResults(_results);
|
|
362
|
-
for (let i = 0; i < rows.length; i++) {
|
|
363
|
-
if (
|
|
364
|
-
rows[i].place_id === rowData.place_id ||
|
|
365
|
-
(rows[i].isCurrentLocation === true &&
|
|
366
|
-
rowData.isCurrentLocation === true)
|
|
367
|
-
) {
|
|
368
|
-
rows[i].isLoading = true;
|
|
369
|
-
setDataSource(rows);
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
const _disableRowLoaders = () => {
|
|
376
|
-
// if (_isMounted === true) {
|
|
377
|
-
for (let i = 0; i < _results.length; i++) {
|
|
378
|
-
if (_results[i].isLoading === true) {
|
|
379
|
-
_results[i].isLoading = false;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
setDataSource(buildRowsFromResults(_results));
|
|
384
|
-
// }
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
const _getPredefinedPlace = (rowData) => {
|
|
388
|
-
if (rowData.isPredefinedPlace !== true) {
|
|
389
|
-
return rowData;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
for (let i = 0; i < props.predefinedPlaces.length; i++) {
|
|
393
|
-
if (props.predefinedPlaces[i].description === rowData.description) {
|
|
394
|
-
return props.predefinedPlaces[i];
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return rowData;
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
const _filterResultsByTypes = (unfilteredResults, types) => {
|
|
402
|
-
if (types.length === 0) return unfilteredResults;
|
|
403
|
-
|
|
404
|
-
const results = [];
|
|
405
|
-
for (let i = 0; i < unfilteredResults.length; i++) {
|
|
406
|
-
let found = false;
|
|
407
|
-
|
|
408
|
-
for (let j = 0; j < types.length; j++) {
|
|
409
|
-
if (unfilteredResults[i].types.indexOf(types[j]) !== -1) {
|
|
410
|
-
found = true;
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (found === true) {
|
|
416
|
-
results.push(unfilteredResults[i]);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
return results;
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
const _requestNearby = (latitude, longitude) => {
|
|
423
|
-
_abortRequests();
|
|
424
|
-
|
|
425
|
-
if (
|
|
426
|
-
latitude !== undefined &&
|
|
427
|
-
longitude !== undefined &&
|
|
428
|
-
latitude !== null &&
|
|
429
|
-
longitude !== null
|
|
430
|
-
) {
|
|
431
|
-
const request = new XMLHttpRequest();
|
|
432
|
-
_requests.push(request);
|
|
433
|
-
request.timeout = props.timeout;
|
|
434
|
-
request.ontimeout = props.onTimeout;
|
|
435
|
-
request.onreadystatechange = () => {
|
|
436
|
-
if (request.readyState !== 4) {
|
|
437
|
-
setListLoaderDisplayed(true);
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
setListLoaderDisplayed(false);
|
|
442
|
-
if (request.status === 200) {
|
|
443
|
-
const responseJSON = JSON.parse(request.responseText);
|
|
444
|
-
|
|
445
|
-
_disableRowLoaders();
|
|
446
|
-
|
|
447
|
-
if (typeof responseJSON.results !== 'undefined') {
|
|
448
|
-
// if (_isMounted === true) {
|
|
449
|
-
var results = [];
|
|
450
|
-
if (props.nearbyPlacesAPI === 'GoogleReverseGeocoding') {
|
|
451
|
-
results = _filterResultsByTypes(
|
|
452
|
-
responseJSON.results,
|
|
453
|
-
props.filterReverseGeocodingByTypes,
|
|
454
|
-
);
|
|
455
|
-
} else {
|
|
456
|
-
results = responseJSON.results;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
setDataSource(buildRowsFromResults(results));
|
|
460
|
-
// }
|
|
461
|
-
}
|
|
462
|
-
if (typeof responseJSON.error_message !== 'undefined') {
|
|
463
|
-
if (!props.onFail)
|
|
464
|
-
console.warn(
|
|
465
|
-
'google places autocomplete: ' + responseJSON.error_message,
|
|
466
|
-
);
|
|
467
|
-
else {
|
|
468
|
-
props.onFail(responseJSON.error_message);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
} else {
|
|
472
|
-
// console.warn("google places autocomplete: request could not be completed or has been aborted");
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
let requestUrl = '';
|
|
477
|
-
if (props.nearbyPlacesAPI === 'GoogleReverseGeocoding') {
|
|
478
|
-
// your key must be allowed to use Google Maps Geocoding API
|
|
479
|
-
requestUrl =
|
|
480
|
-
`${url}/geocode/json?` +
|
|
481
|
-
Qs.stringify({
|
|
482
|
-
latlng: latitude + ',' + longitude,
|
|
483
|
-
key: props.query.key,
|
|
484
|
-
...props.GoogleReverseGeocodingQuery,
|
|
485
|
-
});
|
|
486
|
-
} else {
|
|
487
|
-
requestUrl =
|
|
488
|
-
`${url}/place/nearbysearch/json?` +
|
|
489
|
-
Qs.stringify({
|
|
490
|
-
location: latitude + ',' + longitude,
|
|
491
|
-
key: props.query.key,
|
|
492
|
-
...props.GooglePlacesSearchQuery,
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
request.open('GET', requestUrl);
|
|
497
|
-
|
|
498
|
-
request.withCredentials = requestShouldUseWithCredentials();
|
|
499
|
-
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
500
|
-
|
|
501
|
-
request.send();
|
|
502
|
-
} else {
|
|
503
|
-
_results = [];
|
|
504
|
-
setDataSource(buildRowsFromResults([]));
|
|
505
|
-
}
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
const _request = (text) => {
|
|
509
|
-
_abortRequests();
|
|
510
|
-
if (!url) {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
if (supportedPlatform() && text && text.length >= props.minLength) {
|
|
514
|
-
const request = new XMLHttpRequest();
|
|
515
|
-
_requests.push(request);
|
|
516
|
-
request.timeout = props.timeout;
|
|
517
|
-
request.ontimeout = props.onTimeout;
|
|
518
|
-
request.onreadystatechange = () => {
|
|
519
|
-
if (request.readyState !== 4) {
|
|
520
|
-
setListLoaderDisplayed(true);
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
setListLoaderDisplayed(false);
|
|
525
|
-
if (request.status === 200) {
|
|
526
|
-
const responseJSON = JSON.parse(request.responseText);
|
|
527
|
-
if (typeof responseJSON.predictions !== 'undefined') {
|
|
528
|
-
// if (_isMounted === true) {
|
|
529
|
-
const results =
|
|
530
|
-
props.nearbyPlacesAPI === 'GoogleReverseGeocoding'
|
|
531
|
-
? _filterResultsByTypes(
|
|
532
|
-
responseJSON.predictions,
|
|
533
|
-
props.filterReverseGeocodingByTypes,
|
|
534
|
-
)
|
|
535
|
-
: responseJSON.predictions;
|
|
536
|
-
|
|
537
|
-
_results = results;
|
|
538
|
-
setDataSource(buildRowsFromResults(results, text));
|
|
539
|
-
// }
|
|
540
|
-
}
|
|
541
|
-
if (typeof responseJSON.error_message !== 'undefined') {
|
|
542
|
-
if (!props.onFail)
|
|
543
|
-
console.warn(
|
|
544
|
-
'google places autocomplete: ' + responseJSON.error_message,
|
|
545
|
-
);
|
|
546
|
-
else {
|
|
547
|
-
props.onFail(responseJSON.error_message);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
} else {
|
|
551
|
-
// console.warn("google places autocomplete: request could not be completed or has been aborted");
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
if (props.preProcess) {
|
|
556
|
-
setStateText(props.preProcess(text));
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
request.open(
|
|
560
|
-
'GET',
|
|
561
|
-
`${url}/place/autocomplete/json?input=` +
|
|
562
|
-
encodeURIComponent(text) +
|
|
563
|
-
'&' +
|
|
564
|
-
Qs.stringify(props.query),
|
|
565
|
-
);
|
|
566
|
-
|
|
567
|
-
request.withCredentials = requestShouldUseWithCredentials();
|
|
568
|
-
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
569
|
-
|
|
570
|
-
request.send();
|
|
571
|
-
} else {
|
|
572
|
-
_results = [];
|
|
573
|
-
setDataSource(buildRowsFromResults([]));
|
|
768
|
+
onPress(predefinedPlace, predefinedPlace);
|
|
574
769
|
}
|
|
575
770
|
};
|
|
576
771
|
|
|
577
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
578
|
-
const debounceData = useMemo(() => debounce(_request, props.debounce), [
|
|
579
|
-
props.query,
|
|
580
|
-
url,
|
|
581
|
-
]);
|
|
582
|
-
|
|
583
772
|
const _onChangeText = (text) => {
|
|
584
773
|
setStateText(text);
|
|
585
774
|
debounceData(text);
|
|
@@ -588,38 +777,46 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
588
777
|
const _handleChangeText = (text) => {
|
|
589
778
|
_onChangeText(text);
|
|
590
779
|
|
|
591
|
-
const onChangeText =
|
|
780
|
+
const onChangeText = textInputProps?.onChangeText;
|
|
592
781
|
|
|
593
782
|
if (onChangeText) {
|
|
594
783
|
onChangeText(text);
|
|
595
784
|
}
|
|
596
785
|
};
|
|
597
786
|
|
|
598
|
-
const
|
|
599
|
-
|
|
787
|
+
const isNewFocusInAutocompleteResultList = ({
|
|
788
|
+
relatedTarget,
|
|
789
|
+
currentTarget,
|
|
790
|
+
}) => {
|
|
791
|
+
if (!relatedTarget) return false;
|
|
792
|
+
|
|
793
|
+
let node = relatedTarget.parentNode;
|
|
794
|
+
|
|
795
|
+
while (node) {
|
|
796
|
+
if (node.id === 'result-list-id') return true;
|
|
797
|
+
node = node.parentNode;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
return false;
|
|
600
801
|
};
|
|
601
802
|
|
|
602
|
-
const
|
|
603
|
-
if (
|
|
604
|
-
|
|
803
|
+
const _onBlur = (e) => {
|
|
804
|
+
if (e && isNewFocusInAutocompleteResultList(e)) return;
|
|
805
|
+
|
|
806
|
+
if (!keepResultsAfterBlur) {
|
|
807
|
+
setListViewDisplayed(false);
|
|
605
808
|
}
|
|
809
|
+
inputRef?.current?.blur();
|
|
810
|
+
};
|
|
606
811
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
style={[
|
|
610
|
-
props.suppressDefaultStyles ? {} : defaultStyles.description,
|
|
611
|
-
props.styles.description,
|
|
612
|
-
rowData.isPredefinedPlace
|
|
613
|
-
? props.styles.predefinedPlacesDescription
|
|
614
|
-
: {},
|
|
615
|
-
]}
|
|
616
|
-
numberOfLines={props.numberOfLines}
|
|
617
|
-
>
|
|
618
|
-
{_renderDescription(rowData)}
|
|
619
|
-
</Text>
|
|
620
|
-
);
|
|
812
|
+
const _onFocus = () => {
|
|
813
|
+
setListViewDisplayed(true);
|
|
621
814
|
};
|
|
622
815
|
|
|
816
|
+
// ==========================================================================
|
|
817
|
+
// RENDER FUNCTIONS
|
|
818
|
+
// ==========================================================================
|
|
819
|
+
|
|
623
820
|
const _renderDescription = (rowData) => {
|
|
624
821
|
if (props.renderDescription) {
|
|
625
822
|
return props.renderDescription(rowData);
|
|
@@ -628,13 +825,17 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
628
825
|
return rowData.description || rowData.formatted_address || rowData.name;
|
|
629
826
|
};
|
|
630
827
|
|
|
828
|
+
const _getRowLoader = () => {
|
|
829
|
+
return <ActivityIndicator animating={true} size='small' />;
|
|
830
|
+
};
|
|
831
|
+
|
|
631
832
|
const _renderLoader = (rowData) => {
|
|
632
833
|
if (rowData.isLoading === true) {
|
|
633
834
|
return (
|
|
634
835
|
<View
|
|
635
836
|
style={[
|
|
636
|
-
|
|
637
|
-
|
|
837
|
+
suppressDefaultStyles ? {} : defaultStyles.loader,
|
|
838
|
+
styles?.loader,
|
|
638
839
|
]}
|
|
639
840
|
>
|
|
640
841
|
{_getRowLoader()}
|
|
@@ -645,26 +846,45 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
645
846
|
return null;
|
|
646
847
|
};
|
|
647
848
|
|
|
849
|
+
const _renderRowData = (rowData, index) => {
|
|
850
|
+
if (props.renderRow) {
|
|
851
|
+
return props.renderRow(rowData, index);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
return (
|
|
855
|
+
<Text
|
|
856
|
+
style={[
|
|
857
|
+
suppressDefaultStyles ? {} : defaultStyles.description,
|
|
858
|
+
styles?.description,
|
|
859
|
+
rowData.isPredefinedPlace ? styles?.predefinedPlacesDescription : {},
|
|
860
|
+
]}
|
|
861
|
+
numberOfLines={numberOfLines}
|
|
862
|
+
>
|
|
863
|
+
{_renderDescription(rowData)}
|
|
864
|
+
</Text>
|
|
865
|
+
);
|
|
866
|
+
};
|
|
867
|
+
|
|
648
868
|
const _renderRow = (rowData = {}, index) => {
|
|
649
869
|
return (
|
|
650
870
|
<ScrollView
|
|
651
871
|
contentContainerStyle={
|
|
652
|
-
|
|
872
|
+
isRowScrollable ? { minWidth: '100%' } : { width: '100%' }
|
|
653
873
|
}
|
|
654
|
-
scrollEnabled={
|
|
655
|
-
keyboardShouldPersistTaps={
|
|
874
|
+
scrollEnabled={isRowScrollable}
|
|
875
|
+
keyboardShouldPersistTaps={keyboardShouldPersistTaps}
|
|
656
876
|
horizontal={true}
|
|
657
877
|
showsHorizontalScrollIndicator={false}
|
|
658
878
|
showsVerticalScrollIndicator={false}
|
|
659
879
|
>
|
|
660
880
|
<Pressable
|
|
661
881
|
style={({ hovered, pressed }) => [
|
|
662
|
-
|
|
882
|
+
isRowScrollable ? { minWidth: '100%' } : { width: '100%' },
|
|
663
883
|
{
|
|
664
884
|
backgroundColor: pressed
|
|
665
|
-
?
|
|
885
|
+
? listUnderlayColor
|
|
666
886
|
: hovered
|
|
667
|
-
?
|
|
887
|
+
? listHoverColor
|
|
668
888
|
: undefined,
|
|
669
889
|
},
|
|
670
890
|
]}
|
|
@@ -673,9 +893,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
673
893
|
>
|
|
674
894
|
<View
|
|
675
895
|
style={[
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
rowData.isPredefinedPlace ?
|
|
896
|
+
suppressDefaultStyles ? {} : defaultStyles.row,
|
|
897
|
+
styles?.row,
|
|
898
|
+
rowData.isPredefinedPlace ? styles?.specialItemRow : {},
|
|
679
899
|
]}
|
|
680
900
|
>
|
|
681
901
|
{_renderLoader(rowData)}
|
|
@@ -695,40 +915,29 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
695
915
|
<View
|
|
696
916
|
key={`${sectionID}-${rowID}`}
|
|
697
917
|
style={[
|
|
698
|
-
|
|
699
|
-
|
|
918
|
+
suppressDefaultStyles ? {} : defaultStyles.separator,
|
|
919
|
+
styles?.separator,
|
|
700
920
|
]}
|
|
701
921
|
/>
|
|
702
922
|
);
|
|
703
923
|
};
|
|
704
924
|
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
if (!relatedTarget) return false;
|
|
925
|
+
const _shouldShowPoweredLogo = () => {
|
|
926
|
+
if (!enablePoweredByContainer || dataSource.length === 0) {
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
710
929
|
|
|
711
|
-
|
|
930
|
+
for (let i = 0; i < dataSource.length; i++) {
|
|
931
|
+
const row = dataSource[i];
|
|
712
932
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
933
|
+
if (!('isCurrentLocation' in row) && !('isPredefinedPlace' in row)) {
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
716
936
|
}
|
|
717
937
|
|
|
718
938
|
return false;
|
|
719
939
|
};
|
|
720
940
|
|
|
721
|
-
const _onBlur = (e) => {
|
|
722
|
-
if (e && isNewFocusInAutocompleteResultList(e)) return;
|
|
723
|
-
|
|
724
|
-
if (!props.keepResultsAfterBlur) {
|
|
725
|
-
setListViewDisplayed(false);
|
|
726
|
-
}
|
|
727
|
-
inputRef?.current?.blur();
|
|
728
|
-
};
|
|
729
|
-
|
|
730
|
-
const _onFocus = () => setListViewDisplayed(true);
|
|
731
|
-
|
|
732
941
|
const _renderPoweredLogo = () => {
|
|
733
942
|
if (!_shouldShowPoweredLogo()) {
|
|
734
943
|
return null;
|
|
@@ -737,15 +946,15 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
737
946
|
return (
|
|
738
947
|
<View
|
|
739
948
|
style={[
|
|
740
|
-
|
|
949
|
+
suppressDefaultStyles ? {} : defaultStyles.row,
|
|
741
950
|
defaultStyles.poweredContainer,
|
|
742
|
-
|
|
951
|
+
styles?.poweredContainer,
|
|
743
952
|
]}
|
|
744
953
|
>
|
|
745
954
|
<Image
|
|
746
955
|
style={[
|
|
747
|
-
|
|
748
|
-
|
|
956
|
+
suppressDefaultStyles ? {} : defaultStyles.powered,
|
|
957
|
+
styles?.powered,
|
|
749
958
|
]}
|
|
750
959
|
resizeMode='contain'
|
|
751
960
|
source={require('./images/powered_by_google_on_white.png')}
|
|
@@ -754,71 +963,73 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
754
963
|
);
|
|
755
964
|
};
|
|
756
965
|
|
|
757
|
-
const _shouldShowPoweredLogo = () => {
|
|
758
|
-
if (!props.enablePoweredByContainer || dataSource.length === 0) {
|
|
759
|
-
return false;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
for (let i = 0; i < dataSource.length; i++) {
|
|
763
|
-
let row = dataSource[i];
|
|
764
|
-
|
|
765
|
-
if (
|
|
766
|
-
!row.hasOwnProperty('isCurrentLocation') &&
|
|
767
|
-
!row.hasOwnProperty('isPredefinedPlace')
|
|
768
|
-
) {
|
|
769
|
-
return true;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
return false;
|
|
774
|
-
};
|
|
775
|
-
|
|
776
966
|
const _renderLeftButton = () => {
|
|
777
967
|
if (props.renderLeftButton) {
|
|
778
968
|
return props.renderLeftButton();
|
|
779
969
|
}
|
|
970
|
+
return null;
|
|
780
971
|
};
|
|
781
972
|
|
|
782
973
|
const _renderRightButton = () => {
|
|
783
974
|
if (props.renderRightButton) {
|
|
784
975
|
return props.renderRightButton();
|
|
785
976
|
}
|
|
977
|
+
return null;
|
|
786
978
|
};
|
|
787
979
|
|
|
788
980
|
const _getFlatList = () => {
|
|
789
|
-
const
|
|
981
|
+
const keyExtractor = (item, index) => {
|
|
982
|
+
// Use stable keys based on item data
|
|
983
|
+
if (item.place_id) {
|
|
984
|
+
return `place_${item.place_id}_${index}`;
|
|
985
|
+
}
|
|
986
|
+
if (item.isCurrentLocation) {
|
|
987
|
+
return 'current_location';
|
|
988
|
+
}
|
|
989
|
+
if (item.isPredefinedPlace && item.description) {
|
|
990
|
+
return `predefined_${item.description}_${index}`;
|
|
991
|
+
}
|
|
992
|
+
// Fallback to index-based key (should rarely happen)
|
|
993
|
+
return `item_${index}`;
|
|
994
|
+
};
|
|
790
995
|
|
|
791
|
-
if
|
|
996
|
+
// Show list if:
|
|
997
|
+
// 1. Platform is supported
|
|
998
|
+
// 2. There's data to show (dataSource has items)
|
|
999
|
+
// 3. listViewDisplayed is true OR we're in 'auto' mode (auto-shows when data exists)
|
|
1000
|
+
const isAutoMode =
|
|
1001
|
+
listViewDisplayedProp === 'auto' || listViewDisplayedProp === undefined;
|
|
1002
|
+
const shouldShowList =
|
|
792
1003
|
supportedPlatform() &&
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
) {
|
|
1004
|
+
dataSource.length > 0 &&
|
|
1005
|
+
(listViewDisplayed === true || isAutoMode);
|
|
1006
|
+
|
|
1007
|
+
if (shouldShowList) {
|
|
798
1008
|
return (
|
|
799
1009
|
<FlatList
|
|
800
1010
|
nativeID='result-list-id'
|
|
801
|
-
scrollEnabled={!
|
|
1011
|
+
scrollEnabled={!disableScroll}
|
|
1012
|
+
nestedScrollEnabled={true}
|
|
802
1013
|
style={[
|
|
803
|
-
|
|
804
|
-
|
|
1014
|
+
suppressDefaultStyles ? {} : defaultStyles.listView,
|
|
1015
|
+
styles?.listView,
|
|
805
1016
|
]}
|
|
806
1017
|
data={dataSource}
|
|
807
|
-
keyExtractor={
|
|
1018
|
+
keyExtractor={keyExtractor}
|
|
808
1019
|
extraData={[dataSource, props]}
|
|
809
1020
|
ItemSeparatorComponent={_renderSeparator}
|
|
810
1021
|
renderItem={({ item, index }) => _renderRow(item, index)}
|
|
811
1022
|
ListEmptyComponent={
|
|
812
1023
|
listLoaderDisplayed
|
|
813
1024
|
? props.listLoaderComponent
|
|
814
|
-
: stateText.length >
|
|
1025
|
+
: stateText.length > minLength && props.listEmptyComponent
|
|
815
1026
|
}
|
|
816
1027
|
ListHeaderComponent={
|
|
817
1028
|
props.renderHeaderComponent &&
|
|
818
1029
|
props.renderHeaderComponent(stateText)
|
|
819
1030
|
}
|
|
820
1031
|
ListFooterComponent={_renderPoweredLogo}
|
|
821
|
-
{...
|
|
1032
|
+
{...restProps}
|
|
822
1033
|
/>
|
|
823
1034
|
);
|
|
824
1035
|
}
|
|
@@ -826,52 +1037,141 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
826
1037
|
return null;
|
|
827
1038
|
};
|
|
828
1039
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
1040
|
+
// ==========================================================================
|
|
1041
|
+
// EFFECTS
|
|
1042
|
+
// ==========================================================================
|
|
1043
|
+
|
|
1044
|
+
// Update query ref when query changes
|
|
1045
|
+
useEffect(() => {
|
|
1046
|
+
queryRef.current = query;
|
|
1047
|
+
}, [query]);
|
|
1048
|
+
|
|
1049
|
+
// Initialize URL from requestUrl prop
|
|
1050
|
+
useEffect(() => {
|
|
1051
|
+
setUrl(getRequestUrl(props.requestUrl));
|
|
1052
|
+
}, [props.requestUrl]);
|
|
1053
|
+
|
|
1054
|
+
// Initialize dataSource on mount
|
|
1055
|
+
useEffect(() => {
|
|
1056
|
+
setDataSource(buildRowsFromResults([]));
|
|
1057
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1058
|
+
}, []);
|
|
1059
|
+
|
|
1060
|
+
// Keep requestRef updated
|
|
1061
|
+
requestRef.current = _request;
|
|
1062
|
+
|
|
1063
|
+
// Debounce setup
|
|
1064
|
+
const debounceData = useMemo(() => {
|
|
1065
|
+
return debounce((text) => requestRef.current(text), debounceMs);
|
|
1066
|
+
}, [debounceMs]);
|
|
1067
|
+
|
|
1068
|
+
useEffect(() => {
|
|
1069
|
+
return () => {
|
|
1070
|
+
// Cleanup debounced function on unmount
|
|
1071
|
+
if (debounceData.cancel) {
|
|
1072
|
+
debounceData.cancel();
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
}, [debounceData]);
|
|
1076
|
+
|
|
1077
|
+
// Reload search when query changes (using string comparison to avoid object reference issues)
|
|
1078
|
+
useEffect(() => {
|
|
1079
|
+
const queryChanged = prevQueryStringRef.current !== queryString;
|
|
1080
|
+
|
|
1081
|
+
if (queryChanged) {
|
|
1082
|
+
prevQueryStringRef.current = queryString;
|
|
1083
|
+
if (stateText && stateText.length >= minLength) {
|
|
1084
|
+
debounceData(stateText);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
return () => {
|
|
1089
|
+
_abortRequests();
|
|
1090
|
+
};
|
|
1091
|
+
}, [queryString, debounceData, stateText, minLength, _abortRequests]);
|
|
1092
|
+
|
|
1093
|
+
// Auto-show list when dataSource has items in 'auto' mode
|
|
1094
|
+
useEffect(() => {
|
|
1095
|
+
if (
|
|
1096
|
+
listViewDisplayedProp === 'auto' &&
|
|
1097
|
+
dataSource.length > 0 &&
|
|
1098
|
+
!listViewDisplayed
|
|
1099
|
+
) {
|
|
1100
|
+
setListViewDisplayed(true);
|
|
1101
|
+
}
|
|
1102
|
+
}, [dataSource.length, listViewDisplayedProp, listViewDisplayed]);
|
|
1103
|
+
|
|
1104
|
+
// ==========================================================================
|
|
1105
|
+
// IMPERATIVE HANDLE
|
|
1106
|
+
// ==========================================================================
|
|
1107
|
+
|
|
1108
|
+
useImperativeHandle(
|
|
1109
|
+
ref,
|
|
1110
|
+
() => ({
|
|
1111
|
+
setAddressText: (address) => {
|
|
1112
|
+
setStateText(address);
|
|
1113
|
+
},
|
|
1114
|
+
getAddressText: () => stateText,
|
|
1115
|
+
blur: () => inputRef.current?.blur(),
|
|
1116
|
+
focus: () => inputRef.current?.focus(),
|
|
1117
|
+
isFocused: () => inputRef.current?.isFocused(),
|
|
1118
|
+
clear: () => inputRef.current?.clear(),
|
|
1119
|
+
getCurrentLocation,
|
|
1120
|
+
}),
|
|
1121
|
+
[stateText, getCurrentLocation],
|
|
1122
|
+
);
|
|
1123
|
+
|
|
1124
|
+
// ==========================================================================
|
|
1125
|
+
// MAIN RENDER
|
|
1126
|
+
// ==========================================================================
|
|
1127
|
+
|
|
1128
|
+
const {
|
|
1129
|
+
onFocus: textInputOnFocus,
|
|
1130
|
+
onBlur: textInputOnBlur,
|
|
1131
|
+
onChangeText: textInputOnChangeText, // destructuring here stops this being set after onChangeText={_handleChangeText}
|
|
833
1132
|
clearButtonMode,
|
|
834
1133
|
InputComp,
|
|
835
1134
|
...userProps
|
|
836
|
-
} =
|
|
1135
|
+
} = textInputProps || {};
|
|
837
1136
|
const TextInputComp = InputComp || TextInput;
|
|
1137
|
+
|
|
838
1138
|
return (
|
|
839
1139
|
<View
|
|
840
1140
|
style={[
|
|
841
|
-
|
|
842
|
-
|
|
1141
|
+
suppressDefaultStyles ? {} : defaultStyles.container,
|
|
1142
|
+
styles?.container,
|
|
843
1143
|
]}
|
|
844
1144
|
pointerEvents='box-none'
|
|
845
1145
|
>
|
|
846
|
-
{!
|
|
1146
|
+
{!textInputHide && (
|
|
847
1147
|
<View
|
|
848
1148
|
style={[
|
|
849
|
-
|
|
850
|
-
|
|
1149
|
+
suppressDefaultStyles ? {} : defaultStyles.textInputContainer,
|
|
1150
|
+
styles?.textInputContainer,
|
|
851
1151
|
]}
|
|
852
1152
|
>
|
|
853
1153
|
{_renderLeftButton()}
|
|
854
1154
|
<TextInputComp
|
|
855
1155
|
ref={inputRef}
|
|
856
1156
|
style={[
|
|
857
|
-
|
|
858
|
-
|
|
1157
|
+
suppressDefaultStyles ? {} : defaultStyles.textInput,
|
|
1158
|
+
styles?.textInput,
|
|
859
1159
|
]}
|
|
860
1160
|
value={stateText}
|
|
861
|
-
placeholder={
|
|
1161
|
+
placeholder={placeholder}
|
|
862
1162
|
onFocus={
|
|
863
|
-
|
|
1163
|
+
textInputOnFocus
|
|
864
1164
|
? (e) => {
|
|
865
1165
|
_onFocus();
|
|
866
|
-
|
|
1166
|
+
textInputOnFocus(e);
|
|
867
1167
|
}
|
|
868
1168
|
: _onFocus
|
|
869
1169
|
}
|
|
870
1170
|
onBlur={
|
|
871
|
-
|
|
1171
|
+
textInputOnBlur
|
|
872
1172
|
? (e) => {
|
|
873
1173
|
_onBlur(e);
|
|
874
|
-
|
|
1174
|
+
textInputOnBlur(e);
|
|
875
1175
|
}
|
|
876
1176
|
: _onBlur
|
|
877
1177
|
}
|
|
@@ -889,105 +1189,6 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
889
1189
|
);
|
|
890
1190
|
});
|
|
891
1191
|
|
|
892
|
-
GooglePlacesAutocomplete.propTypes = {
|
|
893
|
-
autoFillOnNotFound: PropTypes.bool,
|
|
894
|
-
currentLocation: PropTypes.bool,
|
|
895
|
-
currentLocationLabel: PropTypes.string,
|
|
896
|
-
debounce: PropTypes.number,
|
|
897
|
-
disableScroll: PropTypes.bool,
|
|
898
|
-
enableHighAccuracyLocation: PropTypes.bool,
|
|
899
|
-
enablePoweredByContainer: PropTypes.bool,
|
|
900
|
-
fetchDetails: PropTypes.bool,
|
|
901
|
-
filterReverseGeocodingByTypes: PropTypes.array,
|
|
902
|
-
GooglePlacesDetailsQuery: PropTypes.object,
|
|
903
|
-
GooglePlacesSearchQuery: PropTypes.object,
|
|
904
|
-
GoogleReverseGeocodingQuery: PropTypes.object,
|
|
905
|
-
inbetweenCompo: PropTypes.object,
|
|
906
|
-
isRowScrollable: PropTypes.bool,
|
|
907
|
-
keyboardShouldPersistTaps: PropTypes.oneOf(['never', 'always', 'handled']),
|
|
908
|
-
listEmptyComponent: PropTypes.element,
|
|
909
|
-
listLoaderComponent: PropTypes.element,
|
|
910
|
-
listHoverColor: PropTypes.string,
|
|
911
|
-
listUnderlayColor: PropTypes.string,
|
|
912
|
-
// Must write it this way: https://stackoverflow.com/a/54290946/7180620
|
|
913
|
-
listViewDisplayed: PropTypes.oneOfType([
|
|
914
|
-
PropTypes.bool,
|
|
915
|
-
PropTypes.oneOf(['auto']),
|
|
916
|
-
]),
|
|
917
|
-
keepResultsAfterBlur: PropTypes.bool,
|
|
918
|
-
minLength: PropTypes.number,
|
|
919
|
-
nearbyPlacesAPI: PropTypes.string,
|
|
920
|
-
numberOfLines: PropTypes.number,
|
|
921
|
-
onFail: PropTypes.func,
|
|
922
|
-
onNotFound: PropTypes.func,
|
|
923
|
-
onPress: PropTypes.func,
|
|
924
|
-
onTimeout: PropTypes.func,
|
|
925
|
-
placeholder: PropTypes.string,
|
|
926
|
-
predefinedPlaces: PropTypes.array,
|
|
927
|
-
predefinedPlacesAlwaysVisible: PropTypes.bool,
|
|
928
|
-
preProcess: PropTypes.func,
|
|
929
|
-
query: PropTypes.object,
|
|
930
|
-
renderDescription: PropTypes.func,
|
|
931
|
-
renderHeaderComponent: PropTypes.func,
|
|
932
|
-
renderLeftButton: PropTypes.func,
|
|
933
|
-
renderRightButton: PropTypes.func,
|
|
934
|
-
renderRow: PropTypes.func,
|
|
935
|
-
requestUrl: PropTypes.shape({
|
|
936
|
-
url: PropTypes.string,
|
|
937
|
-
useOnPlatform: PropTypes.oneOf(['web', 'all']),
|
|
938
|
-
headers: PropTypes.objectOf(PropTypes.string),
|
|
939
|
-
}),
|
|
940
|
-
styles: PropTypes.object,
|
|
941
|
-
suppressDefaultStyles: PropTypes.bool,
|
|
942
|
-
textInputHide: PropTypes.bool,
|
|
943
|
-
textInputProps: PropTypes.object,
|
|
944
|
-
timeout: PropTypes.number,
|
|
945
|
-
};
|
|
946
|
-
|
|
947
|
-
GooglePlacesAutocomplete.defaultProps = {
|
|
948
|
-
autoFillOnNotFound: false,
|
|
949
|
-
currentLocation: false,
|
|
950
|
-
currentLocationLabel: 'Current location',
|
|
951
|
-
debounce: 0,
|
|
952
|
-
disableScroll: false,
|
|
953
|
-
enableHighAccuracyLocation: true,
|
|
954
|
-
enablePoweredByContainer: true,
|
|
955
|
-
fetchDetails: false,
|
|
956
|
-
filterReverseGeocodingByTypes: [],
|
|
957
|
-
GooglePlacesDetailsQuery: {},
|
|
958
|
-
GooglePlacesSearchQuery: {
|
|
959
|
-
rankby: 'distance',
|
|
960
|
-
type: 'restaurant',
|
|
961
|
-
},
|
|
962
|
-
GoogleReverseGeocodingQuery: {},
|
|
963
|
-
isRowScrollable: true,
|
|
964
|
-
keyboardShouldPersistTaps: 'always',
|
|
965
|
-
listHoverColor: '#ececec',
|
|
966
|
-
listUnderlayColor: '#c8c7cc',
|
|
967
|
-
listViewDisplayed: 'auto',
|
|
968
|
-
keepResultsAfterBlur: false,
|
|
969
|
-
minLength: 0,
|
|
970
|
-
nearbyPlacesAPI: 'GooglePlacesSearch',
|
|
971
|
-
numberOfLines: 1,
|
|
972
|
-
onFail: () => {},
|
|
973
|
-
onNotFound: () => {},
|
|
974
|
-
onPress: () => {},
|
|
975
|
-
onTimeout: () => console.warn('google places autocomplete: request timeout'),
|
|
976
|
-
placeholder: '',
|
|
977
|
-
predefinedPlaces: [],
|
|
978
|
-
predefinedPlacesAlwaysVisible: false,
|
|
979
|
-
query: {
|
|
980
|
-
key: 'missing api key',
|
|
981
|
-
language: 'en',
|
|
982
|
-
types: 'geocode',
|
|
983
|
-
},
|
|
984
|
-
styles: {},
|
|
985
|
-
suppressDefaultStyles: false,
|
|
986
|
-
textInputHide: false,
|
|
987
|
-
textInputProps: {},
|
|
988
|
-
timeout: 20000,
|
|
989
|
-
};
|
|
990
|
-
|
|
991
1192
|
GooglePlacesAutocomplete.displayName = 'GooglePlacesAutocomplete';
|
|
992
1193
|
|
|
993
1194
|
export default { GooglePlacesAutocomplete };
|