react-native-google-places-autocomplete 2.5.5 → 2.5.7
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 +144 -52
- package/package.json +5 -3
|
@@ -286,11 +286,15 @@ interface GooglePlaceData {
|
|
|
286
286
|
interface Point {
|
|
287
287
|
lat: number;
|
|
288
288
|
lng: number;
|
|
289
|
+
latitude: number;
|
|
290
|
+
longitude: number;
|
|
289
291
|
}
|
|
290
292
|
|
|
291
293
|
interface AddressComponent {
|
|
292
294
|
long_name: string;
|
|
293
295
|
short_name: string;
|
|
296
|
+
longText: string;
|
|
297
|
+
shortText: string;
|
|
294
298
|
types: PlaceType[];
|
|
295
299
|
}
|
|
296
300
|
|
|
@@ -323,6 +327,11 @@ interface GooglePlaceDetail {
|
|
|
323
327
|
url: string;
|
|
324
328
|
utc_offset: number;
|
|
325
329
|
vicinity: string;
|
|
330
|
+
// New Places API parameters
|
|
331
|
+
addressComponents: AddressComponent[];
|
|
332
|
+
adrFormatAddress: string;
|
|
333
|
+
formattedAddress: string;
|
|
334
|
+
location: Point;
|
|
326
335
|
}
|
|
327
336
|
|
|
328
337
|
/** @see https://developers.google.com/places/web-service/autocomplete */
|
|
@@ -431,6 +440,8 @@ interface GooglePlacesAutocompleteProps {
|
|
|
431
440
|
/** text input props */
|
|
432
441
|
textInputProps?: TextInputProps | Object;
|
|
433
442
|
timeout?: number;
|
|
443
|
+
isNewPlacesAPI?: boolean;
|
|
444
|
+
fields?: string;
|
|
434
445
|
}
|
|
435
446
|
|
|
436
447
|
export type GooglePlacesAutocompleteRef = {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import debounce from 'lodash.debounce';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import Qs from 'qs';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
6
|
import React, {
|
|
6
7
|
forwardRef,
|
|
7
8
|
useMemo,
|
|
@@ -9,6 +10,7 @@ import React, {
|
|
|
9
10
|
useImperativeHandle,
|
|
10
11
|
useRef,
|
|
11
12
|
useState,
|
|
13
|
+
useCallback,
|
|
12
14
|
} from 'react';
|
|
13
15
|
import {
|
|
14
16
|
ActivityIndicator,
|
|
@@ -84,36 +86,46 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
84
86
|
}
|
|
85
87
|
};
|
|
86
88
|
|
|
87
|
-
const buildRowsFromResults = (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
89
|
+
const buildRowsFromResults = useCallback(
|
|
90
|
+
(results, text) => {
|
|
91
|
+
let res = [];
|
|
92
|
+
const shouldDisplayPredefinedPlaces = text
|
|
93
|
+
? results.length === 0 && text.length === 0
|
|
94
|
+
: results.length === 0;
|
|
95
|
+
if (
|
|
96
|
+
shouldDisplayPredefinedPlaces ||
|
|
97
|
+
props.predefinedPlacesAlwaysVisible === true
|
|
98
|
+
) {
|
|
99
|
+
res = [
|
|
100
|
+
...props.predefinedPlaces.filter(
|
|
101
|
+
(place) => place?.description.length,
|
|
102
|
+
),
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
if (props.currentLocation === true && hasNavigator()) {
|
|
106
|
+
res.unshift({
|
|
107
|
+
description: props.currentLocationLabel,
|
|
108
|
+
isCurrentLocation: true,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
105
111
|
}
|
|
106
|
-
}
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
res = res.map((place) => ({
|
|
114
|
+
...place,
|
|
115
|
+
isPredefinedPlace: true,
|
|
116
|
+
}));
|
|
112
117
|
|
|
113
|
-
|
|
114
|
-
|
|
118
|
+
return [...res, ...results];
|
|
119
|
+
},
|
|
120
|
+
[
|
|
121
|
+
props.currentLocation,
|
|
122
|
+
props.currentLocationLabel,
|
|
123
|
+
props.predefinedPlaces,
|
|
124
|
+
props.predefinedPlacesAlwaysVisible,
|
|
125
|
+
],
|
|
126
|
+
);
|
|
115
127
|
|
|
116
|
-
const getRequestUrl = (requestUrl) => {
|
|
128
|
+
const getRequestUrl = useCallback((requestUrl) => {
|
|
117
129
|
if (requestUrl) {
|
|
118
130
|
if (requestUrl.useOnPlatform === 'all') {
|
|
119
131
|
return requestUrl.url;
|
|
@@ -127,7 +139,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
127
139
|
} else {
|
|
128
140
|
return 'https://maps.googleapis.com/maps/api';
|
|
129
141
|
}
|
|
130
|
-
};
|
|
142
|
+
}, []);
|
|
131
143
|
|
|
132
144
|
const getRequestHeaders = (requestUrl) => {
|
|
133
145
|
return requestUrl?.headers || {};
|
|
@@ -144,10 +156,14 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
144
156
|
const [listViewDisplayed, setListViewDisplayed] = useState(
|
|
145
157
|
props.listViewDisplayed === 'auto' ? false : props.listViewDisplayed,
|
|
146
158
|
);
|
|
147
|
-
const [url] = useState(getRequestUrl(props.requestUrl));
|
|
159
|
+
const [url, setUrl] = useState(getRequestUrl(props.requestUrl));
|
|
148
160
|
const [listLoaderDisplayed, setListLoaderDisplayed] = useState(false);
|
|
149
161
|
|
|
150
162
|
const inputRef = useRef();
|
|
163
|
+
const [sessionToken, setSessionToken] = useState(uuidv4());
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
setUrl(getRequestUrl(props.requestUrl));
|
|
166
|
+
}, [getRequestUrl, props.requestUrl]);
|
|
151
167
|
|
|
152
168
|
useEffect(() => {
|
|
153
169
|
// This will load the search results after the query object ref gets changed
|
|
@@ -157,10 +173,11 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
157
173
|
};
|
|
158
174
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
159
175
|
}, [props.query]);
|
|
176
|
+
|
|
160
177
|
useEffect(() => {
|
|
161
178
|
// Update dataSource if props.predefinedPlaces changed
|
|
162
179
|
setDataSource(buildRowsFromResults([]));
|
|
163
|
-
}, [props.predefinedPlaces]);
|
|
180
|
+
}, [buildRowsFromResults, props.predefinedPlaces]);
|
|
164
181
|
|
|
165
182
|
useImperativeHandle(ref, () => ({
|
|
166
183
|
setAddressText: (address) => {
|
|
@@ -265,10 +282,14 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
265
282
|
|
|
266
283
|
if (request.status === 200) {
|
|
267
284
|
const responseJSON = JSON.parse(request.responseText);
|
|
268
|
-
|
|
269
|
-
|
|
285
|
+
if (
|
|
286
|
+
responseJSON.status === 'OK' ||
|
|
287
|
+
(props.isNewPlacesAPI && responseJSON.id)
|
|
288
|
+
) {
|
|
270
289
|
// if (_isMounted === true) {
|
|
271
|
-
const details =
|
|
290
|
+
const details = props.isNewPlacesAPI
|
|
291
|
+
? responseJSON
|
|
292
|
+
: responseJSON.result;
|
|
272
293
|
_disableRowLoaders();
|
|
273
294
|
_onBlur();
|
|
274
295
|
|
|
@@ -306,16 +327,29 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
306
327
|
}
|
|
307
328
|
};
|
|
308
329
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
330
|
+
if (props.isNewPlacesAPI) {
|
|
331
|
+
request.open(
|
|
332
|
+
'GET',
|
|
333
|
+
`${url}/v1/places/${rowData.place_id}?` +
|
|
334
|
+
Qs.stringify({
|
|
335
|
+
key: props.query.key,
|
|
336
|
+
sessionToken,
|
|
337
|
+
fields: props.fields,
|
|
338
|
+
}),
|
|
339
|
+
);
|
|
340
|
+
setSessionToken(uuidv4());
|
|
341
|
+
} else {
|
|
342
|
+
request.open(
|
|
343
|
+
'GET',
|
|
344
|
+
`${url}/place/details/json?` +
|
|
345
|
+
Qs.stringify({
|
|
346
|
+
key: props.query.key,
|
|
347
|
+
placeid: rowData.place_id,
|
|
348
|
+
language: props.query.language,
|
|
349
|
+
...props.GooglePlacesDetailsQuery,
|
|
350
|
+
}),
|
|
351
|
+
);
|
|
352
|
+
}
|
|
319
353
|
|
|
320
354
|
request.withCredentials = requestShouldUseWithCredentials();
|
|
321
355
|
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
@@ -403,6 +437,29 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
403
437
|
return results;
|
|
404
438
|
};
|
|
405
439
|
|
|
440
|
+
const _filterResultsByPlacePredictions = (unfilteredResults) => {
|
|
441
|
+
const results = [];
|
|
442
|
+
for (let i = 0; i < unfilteredResults.length; i++) {
|
|
443
|
+
if (unfilteredResults[i].placePrediction) {
|
|
444
|
+
results.push({
|
|
445
|
+
description: unfilteredResults[i].placePrediction.text?.text,
|
|
446
|
+
place_id: unfilteredResults[i].placePrediction.placeId,
|
|
447
|
+
reference: unfilteredResults[i].placePrediction.placeId,
|
|
448
|
+
structured_formatting: {
|
|
449
|
+
main_text:
|
|
450
|
+
unfilteredResults[i].placePrediction.structuredFormat?.mainText
|
|
451
|
+
?.text,
|
|
452
|
+
secondary_text:
|
|
453
|
+
unfilteredResults[i].placePrediction.structuredFormat
|
|
454
|
+
?.secondaryText?.text,
|
|
455
|
+
},
|
|
456
|
+
types: unfilteredResults[i].placePrediction.types ?? [],
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return results;
|
|
461
|
+
};
|
|
462
|
+
|
|
406
463
|
const _requestNearby = (latitude, longitude) => {
|
|
407
464
|
_abortRequests();
|
|
408
465
|
|
|
@@ -508,6 +565,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
508
565
|
setListLoaderDisplayed(false);
|
|
509
566
|
if (request.status === 200) {
|
|
510
567
|
const responseJSON = JSON.parse(request.responseText);
|
|
568
|
+
|
|
511
569
|
if (typeof responseJSON.predictions !== 'undefined') {
|
|
512
570
|
// if (_isMounted === true) {
|
|
513
571
|
const results =
|
|
@@ -522,6 +580,14 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
522
580
|
setDataSource(buildRowsFromResults(results, text));
|
|
523
581
|
// }
|
|
524
582
|
}
|
|
583
|
+
if (typeof responseJSON.suggestions !== 'undefined') {
|
|
584
|
+
const results = _filterResultsByPlacePredictions(
|
|
585
|
+
responseJSON.suggestions,
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
_results = results;
|
|
589
|
+
setDataSource(buildRowsFromResults(results, text));
|
|
590
|
+
}
|
|
525
591
|
if (typeof responseJSON.error_message !== 'undefined') {
|
|
526
592
|
if (!props.onFail)
|
|
527
593
|
console.warn(
|
|
@@ -540,18 +606,39 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
540
606
|
setStateText(props.preProcess(text));
|
|
541
607
|
}
|
|
542
608
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
609
|
+
if (props.isNewPlacesAPI) {
|
|
610
|
+
const keyQueryParam = props.query.key
|
|
611
|
+
? '?' +
|
|
612
|
+
Qs.stringify({
|
|
613
|
+
key: props.query.key,
|
|
614
|
+
})
|
|
615
|
+
: '';
|
|
616
|
+
request.open('POST', `${url}/v1/places:autocomplete${keyQueryParam}`);
|
|
617
|
+
} else {
|
|
618
|
+
request.open(
|
|
619
|
+
'GET',
|
|
620
|
+
`${url}/place/autocomplete/json?input=` +
|
|
621
|
+
encodeURIComponent(text) +
|
|
622
|
+
'&' +
|
|
623
|
+
Qs.stringify(props.query),
|
|
624
|
+
);
|
|
625
|
+
}
|
|
550
626
|
|
|
551
627
|
request.withCredentials = requestShouldUseWithCredentials();
|
|
552
628
|
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
|
|
553
629
|
|
|
554
|
-
|
|
630
|
+
if (props.isNewPlacesAPI) {
|
|
631
|
+
const { key, locationbias, types, ...rest } = props.query;
|
|
632
|
+
request.send(
|
|
633
|
+
JSON.stringify({
|
|
634
|
+
input: text,
|
|
635
|
+
sessionToken,
|
|
636
|
+
...rest,
|
|
637
|
+
}),
|
|
638
|
+
);
|
|
639
|
+
} else {
|
|
640
|
+
request.send();
|
|
641
|
+
}
|
|
555
642
|
} else {
|
|
556
643
|
_results = [];
|
|
557
644
|
setDataSource(buildRowsFromResults([]));
|
|
@@ -561,6 +648,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
|
|
|
561
648
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
562
649
|
const debounceData = useMemo(() => debounce(_request, props.debounce), [
|
|
563
650
|
props.query,
|
|
651
|
+
url,
|
|
564
652
|
]);
|
|
565
653
|
|
|
566
654
|
const _onChangeText = (text) => {
|
|
@@ -888,8 +976,8 @@ GooglePlacesAutocomplete.propTypes = {
|
|
|
888
976
|
inbetweenCompo: PropTypes.object,
|
|
889
977
|
isRowScrollable: PropTypes.bool,
|
|
890
978
|
keyboardShouldPersistTaps: PropTypes.oneOf(['never', 'always', 'handled']),
|
|
891
|
-
listEmptyComponent: PropTypes.
|
|
892
|
-
listLoaderComponent: PropTypes.
|
|
979
|
+
listEmptyComponent: PropTypes.element,
|
|
980
|
+
listLoaderComponent: PropTypes.element,
|
|
893
981
|
listHoverColor: PropTypes.string,
|
|
894
982
|
listUnderlayColor: PropTypes.string,
|
|
895
983
|
// Must write it this way: https://stackoverflow.com/a/54290946/7180620
|
|
@@ -925,6 +1013,8 @@ GooglePlacesAutocomplete.propTypes = {
|
|
|
925
1013
|
textInputHide: PropTypes.bool,
|
|
926
1014
|
textInputProps: PropTypes.object,
|
|
927
1015
|
timeout: PropTypes.number,
|
|
1016
|
+
isNewPlacesAPI: PropTypes.bool,
|
|
1017
|
+
fields: PropTypes.string,
|
|
928
1018
|
};
|
|
929
1019
|
|
|
930
1020
|
GooglePlacesAutocomplete.defaultProps = {
|
|
@@ -969,6 +1059,8 @@ GooglePlacesAutocomplete.defaultProps = {
|
|
|
969
1059
|
textInputHide: false,
|
|
970
1060
|
textInputProps: {},
|
|
971
1061
|
timeout: 20000,
|
|
1062
|
+
isNewPlacesAPI: false,
|
|
1063
|
+
fields: '*',
|
|
972
1064
|
};
|
|
973
1065
|
|
|
974
1066
|
GooglePlacesAutocomplete.displayName = 'GooglePlacesAutocomplete';
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-google-places-autocomplete",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.7",
|
|
4
4
|
"description": "Customizable Google Places autocomplete component for iOS and Android React-Native apps",
|
|
5
5
|
"main": "GooglePlacesAutocomplete.js",
|
|
6
6
|
"types": "GooglePlacesAutocomplete.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"lint": "eslint . && prettier --write .",
|
|
9
|
-
"release": "npx release-it"
|
|
9
|
+
"release": "npx release-it",
|
|
10
|
+
"prettier": "prettier --write ."
|
|
10
11
|
},
|
|
11
12
|
"author": "Farid from Safi",
|
|
12
13
|
"license": "MIT",
|
|
@@ -30,7 +31,8 @@
|
|
|
30
31
|
"dependencies": {
|
|
31
32
|
"lodash.debounce": "^4.0.8",
|
|
32
33
|
"prop-types": "^15.7.2",
|
|
33
|
-
"qs": "~6.9.1"
|
|
34
|
+
"qs": "~6.9.1",
|
|
35
|
+
"uuid": "^10.0.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@react-native-community/eslint-config": "2.0.0",
|