@ttoss/google-maps 2.0.2 → 2.0.4
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/README.md +5 -3
- package/dist/esm/index.js +266 -0
- package/dist/index.d.ts +78 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
Install `@ttoss/google-maps` in your project:
|
|
8
8
|
|
|
9
9
|
```shell
|
|
10
|
-
$ pnpm
|
|
10
|
+
$ pnpm add @ttoss/google-maps
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
If you use TypeScript, add the following to a declaration file (generally `typings.d.ts`):
|
|
@@ -16,7 +16,9 @@ If you use TypeScript, add the following to a declaration file (generally `typin
|
|
|
16
16
|
/// <reference types="google.maps" />
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## How to Use
|
|
20
|
+
|
|
21
|
+
### Configuring `GoogleMapsProvider`
|
|
20
22
|
|
|
21
23
|
At the root of your application, configure `GoogleMapsProvider` with your Google Maps API key. This way, the whole application can access the `google` variable.
|
|
22
24
|
|
|
@@ -34,7 +36,7 @@ const App = ({ children }) => {
|
|
|
34
36
|
};
|
|
35
37
|
```
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
### Rendering the Map
|
|
38
40
|
|
|
39
41
|
At the component level, render Google Maps using `useMap` hook:
|
|
40
42
|
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
|
|
2
|
+
|
|
3
|
+
// src/GoogleMapsProvider.tsx
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { useScript } from "@ttoss/react-hooks";
|
|
6
|
+
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
var GoogleMapsContext = React.createContext({
|
|
8
|
+
status: "idle",
|
|
9
|
+
googleMaps: null
|
|
10
|
+
});
|
|
11
|
+
var GoogleMapsProvider = ({
|
|
12
|
+
children,
|
|
13
|
+
apiKey,
|
|
14
|
+
libraries,
|
|
15
|
+
language
|
|
16
|
+
}) => {
|
|
17
|
+
const src = (() => {
|
|
18
|
+
let srcTemp = `https://maps.googleapis.com/maps/api/js?key=${apiKey}`;
|
|
19
|
+
if (libraries) {
|
|
20
|
+
srcTemp = srcTemp + `&libraries=${libraries.join(",")}`;
|
|
21
|
+
}
|
|
22
|
+
if (language) {
|
|
23
|
+
srcTemp = srcTemp + `&language=${language}`;
|
|
24
|
+
}
|
|
25
|
+
return srcTemp;
|
|
26
|
+
})();
|
|
27
|
+
const {
|
|
28
|
+
status
|
|
29
|
+
} = useScript(src);
|
|
30
|
+
const googleMaps = React.useMemo(() => {
|
|
31
|
+
if (status === "ready" && window.google.maps) {
|
|
32
|
+
return window.google.maps;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}, [status]);
|
|
36
|
+
const value = React.useMemo(() => {
|
|
37
|
+
if (status === "ready" && googleMaps) {
|
|
38
|
+
return {
|
|
39
|
+
status,
|
|
40
|
+
googleMaps
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
status,
|
|
45
|
+
googleMaps: null
|
|
46
|
+
};
|
|
47
|
+
}, [googleMaps, status]);
|
|
48
|
+
return /* @__PURE__ */jsx(GoogleMapsContext.Provider, {
|
|
49
|
+
value,
|
|
50
|
+
children
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
var useGoogleMaps = () => {
|
|
54
|
+
return React.useContext(GoogleMapsContext);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/useGeocoder.ts
|
|
58
|
+
import * as React2 from "react";
|
|
59
|
+
var useGeocoder = () => {
|
|
60
|
+
const {
|
|
61
|
+
googleMaps
|
|
62
|
+
} = useGoogleMaps();
|
|
63
|
+
const [isGeocoderInitialized, setIsGeocoderInitialized] = React2.useState(false);
|
|
64
|
+
const geocoder = React2.useMemo(() => {
|
|
65
|
+
if (googleMaps) {
|
|
66
|
+
const googleMapsGeocoder = new googleMaps.Geocoder();
|
|
67
|
+
setIsGeocoderInitialized(true);
|
|
68
|
+
return googleMapsGeocoder;
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}, [googleMaps]);
|
|
72
|
+
return {
|
|
73
|
+
geocoder,
|
|
74
|
+
isGeocoderInitialized
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/useMap.ts
|
|
79
|
+
import * as React3 from "react";
|
|
80
|
+
import { useCallbackRef } from "use-callback-ref";
|
|
81
|
+
var useMap = (options = {}) => {
|
|
82
|
+
const [, forceUpdate] = React3.useState(0);
|
|
83
|
+
const ref = useCallbackRef(null, () => {
|
|
84
|
+
return forceUpdate(n => {
|
|
85
|
+
return n + 1;
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
const {
|
|
89
|
+
googleMaps
|
|
90
|
+
} = useGoogleMaps();
|
|
91
|
+
const map = React3.useMemo(() => {
|
|
92
|
+
if (googleMaps && ref.current) {
|
|
93
|
+
return new googleMaps.Map(ref.current, options);
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}, [googleMaps, ref.current]);
|
|
97
|
+
const optionsStringify = JSON.stringify(options);
|
|
98
|
+
React3.useEffect(() => {
|
|
99
|
+
if (map) {
|
|
100
|
+
const parsedOptions = JSON.parse(optionsStringify);
|
|
101
|
+
map.setOptions(parsedOptions);
|
|
102
|
+
}
|
|
103
|
+
}, [optionsStringify, map]);
|
|
104
|
+
return {
|
|
105
|
+
/**
|
|
106
|
+
* asss
|
|
107
|
+
*/
|
|
108
|
+
map,
|
|
109
|
+
/**
|
|
110
|
+
* hhhh
|
|
111
|
+
*/
|
|
112
|
+
ref
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/usePlacesAutocomplete/index.ts
|
|
117
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
118
|
+
|
|
119
|
+
// src/usePlacesAutocomplete/debounce.ts
|
|
120
|
+
var debounce = (fn, delay) => {
|
|
121
|
+
let timer;
|
|
122
|
+
function debounceFn(...args) {
|
|
123
|
+
if (timer !== null) {
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
timer = null;
|
|
126
|
+
}
|
|
127
|
+
timer = setTimeout(() => fn.apply(this, args), delay);
|
|
128
|
+
}
|
|
129
|
+
return debounceFn;
|
|
130
|
+
};
|
|
131
|
+
var debounce_default = debounce;
|
|
132
|
+
|
|
133
|
+
// src/usePlacesAutocomplete/useLatest.ts
|
|
134
|
+
import { useRef } from "react";
|
|
135
|
+
var useLatest_default = val => {
|
|
136
|
+
const ref = useRef(val);
|
|
137
|
+
ref.current = val;
|
|
138
|
+
return ref;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/usePlacesAutocomplete/index.ts
|
|
142
|
+
var usePlacesAutocomplete = ({
|
|
143
|
+
requestOptions,
|
|
144
|
+
debounce: debounce2 = 200,
|
|
145
|
+
cache = 24 * 60 * 60,
|
|
146
|
+
cacheKey,
|
|
147
|
+
callbackName,
|
|
148
|
+
defaultValue = "",
|
|
149
|
+
initOnMount = true
|
|
150
|
+
} = {}) => {
|
|
151
|
+
const [ready, setReady] = useState3(false);
|
|
152
|
+
const [value, setVal] = useState3(defaultValue);
|
|
153
|
+
const [suggestions, setSuggestions] = useState3({
|
|
154
|
+
loading: false,
|
|
155
|
+
status: "",
|
|
156
|
+
data: []
|
|
157
|
+
});
|
|
158
|
+
const asRef = useRef2(null);
|
|
159
|
+
const requestOptionsRef = useLatest_default(requestOptions);
|
|
160
|
+
const {
|
|
161
|
+
googleMaps
|
|
162
|
+
} = useGoogleMaps();
|
|
163
|
+
const googleMapsRef = useLatest_default(googleMaps);
|
|
164
|
+
const upaCacheKey = cacheKey ? `upa-${cacheKey}` : "upa";
|
|
165
|
+
const init = useCallback(() => {
|
|
166
|
+
if (asRef.current) return;
|
|
167
|
+
if (!googleMaps) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const {
|
|
171
|
+
current: gMaps
|
|
172
|
+
} = googleMapsRef;
|
|
173
|
+
const placesLib = gMaps?.places || googleMaps.places;
|
|
174
|
+
if (!placesLib) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
asRef.current = new placesLib.AutocompleteService();
|
|
178
|
+
setReady(true);
|
|
179
|
+
}, [googleMaps]);
|
|
180
|
+
const clearSuggestions = useCallback(() => {
|
|
181
|
+
setSuggestions({
|
|
182
|
+
loading: false,
|
|
183
|
+
status: "",
|
|
184
|
+
data: []
|
|
185
|
+
});
|
|
186
|
+
}, []);
|
|
187
|
+
const clearCache = useCallback(() => {
|
|
188
|
+
try {
|
|
189
|
+
sessionStorage.removeItem(upaCacheKey);
|
|
190
|
+
} catch (error) {}
|
|
191
|
+
}, []);
|
|
192
|
+
const fetchPredictions = useCallback(debounce_default(val => {
|
|
193
|
+
if (!val) {
|
|
194
|
+
clearSuggestions();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
setSuggestions(prevState => ({
|
|
198
|
+
...prevState,
|
|
199
|
+
loading: true
|
|
200
|
+
}));
|
|
201
|
+
let cachedData = {};
|
|
202
|
+
try {
|
|
203
|
+
cachedData = JSON.parse(sessionStorage.getItem(upaCacheKey) || "{}");
|
|
204
|
+
} catch (error) {}
|
|
205
|
+
if (cache) {
|
|
206
|
+
cachedData = Object.keys(cachedData).reduce((acc, key) => {
|
|
207
|
+
if (cachedData[key].maxAge - Date.now() >= 0) acc[key] = cachedData[key];
|
|
208
|
+
return acc;
|
|
209
|
+
}, {});
|
|
210
|
+
if (cachedData[val]) {
|
|
211
|
+
setSuggestions({
|
|
212
|
+
loading: false,
|
|
213
|
+
status: "OK",
|
|
214
|
+
data: cachedData[val].data
|
|
215
|
+
});
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
asRef?.current?.getPlacePredictions({
|
|
220
|
+
...requestOptionsRef.current,
|
|
221
|
+
input: val
|
|
222
|
+
}, (data, status) => {
|
|
223
|
+
setSuggestions({
|
|
224
|
+
loading: false,
|
|
225
|
+
status,
|
|
226
|
+
data: data || []
|
|
227
|
+
});
|
|
228
|
+
if (cache && status === "OK") {
|
|
229
|
+
cachedData[val] = {
|
|
230
|
+
data,
|
|
231
|
+
maxAge: Date.now() + cache * 1e3
|
|
232
|
+
};
|
|
233
|
+
try {
|
|
234
|
+
sessionStorage.setItem(upaCacheKey, JSON.stringify(cachedData));
|
|
235
|
+
} catch (error) {}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}, debounce2), [debounce2, clearSuggestions]);
|
|
239
|
+
const setValue = useCallback((val, shouldFetchData = true) => {
|
|
240
|
+
setVal(val);
|
|
241
|
+
if (asRef.current && shouldFetchData) fetchPredictions(val);
|
|
242
|
+
}, [fetchPredictions]);
|
|
243
|
+
useEffect2(() => {
|
|
244
|
+
if (!initOnMount) {
|
|
245
|
+
return () => null;
|
|
246
|
+
}
|
|
247
|
+
if (!googleMapsRef.current && !googleMaps && callbackName) {
|
|
248
|
+
window[callbackName] = init;
|
|
249
|
+
} else {
|
|
250
|
+
init();
|
|
251
|
+
}
|
|
252
|
+
return () => {
|
|
253
|
+
if (window[callbackName]) delete window[callbackName];
|
|
254
|
+
};
|
|
255
|
+
}, [callbackName, init]);
|
|
256
|
+
return {
|
|
257
|
+
ready,
|
|
258
|
+
value,
|
|
259
|
+
suggestions,
|
|
260
|
+
setValue,
|
|
261
|
+
clearSuggestions,
|
|
262
|
+
clearCache,
|
|
263
|
+
init
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
export { GoogleMapsProvider, useGeocoder, useGoogleMaps, useMap, usePlacesAutocomplete };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { ScriptStatus } from '@ttoss/react-hooks';
|
|
4
|
+
|
|
5
|
+
type Extends<T, U extends T> = U;
|
|
6
|
+
type GoogleMaps = typeof google.maps;
|
|
7
|
+
type LoadedMapsStatus = Extends<ScriptStatus, 'ready'>;
|
|
8
|
+
type NotLoadedMapStatus = Extends<ScriptStatus, 'idle' | 'error' | 'loading'>;
|
|
9
|
+
type Libraries = 'places' | 'visualization' | 'drawing' | 'geometry';
|
|
10
|
+
declare const GoogleMapsProvider: ({ children, apiKey, libraries, language, }: {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
apiKey: string;
|
|
13
|
+
libraries?: Libraries[];
|
|
14
|
+
/**
|
|
15
|
+
* https://developers.google.com/maps/faq#languagesupport
|
|
16
|
+
*/
|
|
17
|
+
language?: string;
|
|
18
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @returns param.googleMaps: GoogleMaps - returns the google maps object which
|
|
22
|
+
* provides access to the [Google Maps API](https://developers.google.com/maps/documentation/javascript/overview).
|
|
23
|
+
*/
|
|
24
|
+
declare const useGoogleMaps: () => {
|
|
25
|
+
status: LoadedMapsStatus;
|
|
26
|
+
googleMaps: GoogleMaps;
|
|
27
|
+
} | {
|
|
28
|
+
status: NotLoadedMapStatus;
|
|
29
|
+
googleMaps: null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
declare const useGeocoder: () => {
|
|
33
|
+
geocoder: google.maps.Geocoder | null;
|
|
34
|
+
isGeocoderInitialized: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
declare const useMap: (options?: google.maps.MapOptions) => {
|
|
38
|
+
/**
|
|
39
|
+
* asss
|
|
40
|
+
*/
|
|
41
|
+
map: google.maps.Map | null;
|
|
42
|
+
/**
|
|
43
|
+
* hhhh
|
|
44
|
+
*/
|
|
45
|
+
ref: React.MutableRefObject<HTMLDivElement | null>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
interface HookArgs {
|
|
49
|
+
requestOptions?: Omit<google.maps.places.AutocompletionRequest, 'input'>;
|
|
50
|
+
debounce?: number;
|
|
51
|
+
cache?: number | false;
|
|
52
|
+
cacheKey?: string;
|
|
53
|
+
callbackName?: string;
|
|
54
|
+
defaultValue?: string;
|
|
55
|
+
initOnMount?: boolean;
|
|
56
|
+
}
|
|
57
|
+
type Suggestion = google.maps.places.AutocompletePrediction;
|
|
58
|
+
type Status = `${google.maps.places.PlacesServiceStatus}` | '';
|
|
59
|
+
interface Suggestions {
|
|
60
|
+
readonly loading: boolean;
|
|
61
|
+
readonly status: Status;
|
|
62
|
+
data: Suggestion[];
|
|
63
|
+
}
|
|
64
|
+
interface SetValue {
|
|
65
|
+
(val: string, shouldFetchData?: boolean): void;
|
|
66
|
+
}
|
|
67
|
+
interface HookReturn {
|
|
68
|
+
ready: boolean;
|
|
69
|
+
value: string;
|
|
70
|
+
suggestions: Suggestions;
|
|
71
|
+
setValue: SetValue;
|
|
72
|
+
clearSuggestions: () => void;
|
|
73
|
+
clearCache: () => void;
|
|
74
|
+
init: () => void;
|
|
75
|
+
}
|
|
76
|
+
declare const usePlacesAutocomplete: ({ requestOptions, debounce, cache, cacheKey, callbackName, defaultValue, initOnMount, }?: HookArgs) => HookReturn;
|
|
77
|
+
|
|
78
|
+
export { GoogleMapsProvider, useGeocoder, useGoogleMaps, useMap, usePlacesAutocomplete };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/google-maps",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"author": "ttoss",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Pedro Arantes <pedro@arantespp.com> (https://arantespp.com/contact)",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"src"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@types/google.maps": "^3.
|
|
27
|
-
"use-callback-ref": "^1.3.
|
|
28
|
-
"@ttoss/react-hooks": "^2.0.
|
|
26
|
+
"@types/google.maps": "^3.58.1",
|
|
27
|
+
"use-callback-ref": "^1.3.2",
|
|
28
|
+
"@ttoss/react-hooks": "^2.0.3"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": ">=16.8.0",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"jest": "^29.7.0",
|
|
37
37
|
"react": "^18.3.1",
|
|
38
38
|
"tsup": "^8.3.0",
|
|
39
|
-
"@ttoss/
|
|
40
|
-
"@ttoss/
|
|
39
|
+
"@ttoss/test-utils": "^2.1.16",
|
|
40
|
+
"@ttoss/config": "^1.34.0"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"Google",
|