-
Notifications
You must be signed in to change notification settings - Fork 131
/
Copy pathindex.ts
103 lines (100 loc) · 3.52 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { createStaticStore } from "@solid-primitives/static-store";
import { access, MaybeAccessor } from "@solid-primitives/utils";
import type { Resource } from "solid-js";
import { createComputed, createResource, onCleanup } from "solid-js";
import { isServer } from "solid-js/web";
const geolocationDefaults: PositionOptions = {
enableHighAccuracy: false,
maximumAge: 0,
timeout: Number.POSITIVE_INFINITY,
};
/**
* Generates a basic primitive to perform unary geolocation querying and updating.
*
* @param options - @type PositionOptions
* @param options.enableHighAccuracy - Enable if the locator should be very accurate
* @param options.maximumAge - Maximum cached position age
* @param options.timeout - Amount of time before the error callback is evoked, if 0 then never
* @return Returns a `Resource` and refetch option resolving the location coordinates, refetch function and loading value.
*
* @example
* ```ts
* const [location, refetch, loading] = createGeolocation();
* ```
*/
export const createGeolocation = (
options?: MaybeAccessor<PositionOptions>,
): [location: Resource<GeolocationCoordinates | undefined>, refetch: VoidFunction] => {
if (isServer) {
return [
Object.assign(() => {}, { error: undefined, loading: true }) as Resource<undefined>,
() => {
/* noop */
},
];
}
const [location, { refetch }] = createResource(
() => Object.assign(geolocationDefaults, access(options)),
options =>
new Promise<GeolocationCoordinates>((resolve, reject) => {
if (!("geolocation" in navigator)) {
return reject("Geolocation is not supported.");
}
navigator.geolocation.getCurrentPosition(
res => resolve(res.coords),
error => reject(Object.assign(new Error(error.message), error)),
options,
);
}),
);
return [location, refetch];
};
/**
* Creates a primitive that allows for real-time geolocation watching.
*
* @param enabled - Specify if the location should be updated periodically (used to temporarily disable location watching)
* @param options - @type PositionOptions
* @param options.enableHighAccuracy - Enable if the locator should be very accurate
* @param options.maximumAge - Maximum cached position age
* @param options.timeout - Amount of time before the error callback is evoked, if 0 then never
* @return Returns a location signal
*
* @example
* ```ts
* const [location, error] = createGeolocationWatcher();
* ```
*/
export const createGeolocationWatcher = (
enabled: MaybeAccessor<boolean>,
options?: MaybeAccessor<PositionOptions>,
): {
location: GeolocationCoordinates | null;
error: GeolocationPositionError | null;
} => {
if (isServer) {
return { location: null, error: null };
}
const [store, setStore] = createStaticStore<{
location: null | GeolocationCoordinates;
error: null | GeolocationPositionError;
}>({
location: null,
error: null,
});
let registeredHandlerID: number | null;
const clearGeolocator = () =>
registeredHandlerID && navigator.geolocation.clearWatch(registeredHandlerID);
// Implement as an effect to allow switching locator on/off
createComputed(() => {
if (access(enabled)) {
return (registeredHandlerID = navigator.geolocation.watchPosition(
res => setStore({ location: res.coords, error: null }),
error => setStore({ location: null, error }),
Object.assign(geolocationDefaults, access(options)),
));
}
clearGeolocator();
});
onCleanup(clearGeolocator);
return store;
};