react-native-nitro-geolocation 0.3.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-geolocation",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "⚡🚀Blazing-fast geolocation for React Native powered by Nitro Modules",
5
5
  "main": "src/index",
6
6
  "source": "src/index",
@@ -0,0 +1,21 @@
1
+ import type { PermissionStatus } from "../NitroGeolocation.nitro";
2
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
3
+
4
+ /**
5
+ * Check current location permission status.
6
+ * Does NOT request permission, only checks current state.
7
+ *
8
+ * @returns Promise resolving to current permission status
9
+ * @example
10
+ * ```tsx
11
+ * import { checkPermission } from 'react-native-nitro-geolocation';
12
+ *
13
+ * const status = await checkPermission();
14
+ * if (status === 'granted') {
15
+ * // Get location
16
+ * }
17
+ * ```
18
+ */
19
+ export function checkPermission(): Promise<PermissionStatus> {
20
+ return NitroGeolocationHybridObject.checkPermission();
21
+ }
@@ -0,0 +1,43 @@
1
+ import type { LocationRequestOptions } from "../NitroGeolocation.nitro";
2
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
3
+ import { isDevtoolsEnabled } from "../devtools";
4
+ import { getDevtoolsCurrentPosition } from "../devtools/getCurrentPosition";
5
+ import type { GeolocationResponse } from "../types";
6
+
7
+ /**
8
+ * Get current location (one-time request).
9
+ *
10
+ * Strategy:
11
+ * 1. Check cached location (if maximumAge allows)
12
+ * 2. Request fresh location from GPS/Network
13
+ * 3. Timeout after specified duration
14
+ *
15
+ * @param options - Location request options
16
+ * @returns Promise resolving to current position
17
+ * @throws LocationError if permission denied, timeout, or unavailable
18
+ * @example
19
+ * ```tsx
20
+ * import { getCurrentPosition } from 'react-native-nitro-geolocation';
21
+ *
22
+ * try {
23
+ * const position = await getCurrentPosition({
24
+ * enableHighAccuracy: true,
25
+ * timeout: 15000
26
+ * });
27
+ * console.log(position.coords.latitude, position.coords.longitude);
28
+ * } catch (error) {
29
+ * console.error(error.message);
30
+ * }
31
+ * ```
32
+ */
33
+ export function getCurrentPosition(
34
+ options?: LocationRequestOptions
35
+ ): Promise<GeolocationResponse> {
36
+ if (isDevtoolsEnabled()) {
37
+ const devtoolsResult = getDevtoolsCurrentPosition();
38
+ if (devtoolsResult) {
39
+ return devtoolsResult;
40
+ }
41
+ }
42
+ return NitroGeolocationHybridObject.getCurrentPosition(options);
43
+ }
@@ -0,0 +1,7 @@
1
+ export { setConfiguration } from "./setConfiguration";
2
+ export { checkPermission } from "./checkPermission";
3
+ export { requestPermission } from "./requestPermission";
4
+ export { getCurrentPosition } from "./getCurrentPosition";
5
+ export { watchPosition } from "./watchPosition";
6
+ export { unwatch } from "./unwatch";
7
+ export { stopObserving } from "./stopObserving";
@@ -0,0 +1,21 @@
1
+ import type { PermissionStatus } from "../NitroGeolocation.nitro";
2
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
3
+
4
+ /**
5
+ * Request location permission from the user.
6
+ * Shows system permission dialog if not yet determined.
7
+ *
8
+ * @returns Promise resolving to new permission status
9
+ * @example
10
+ * ```tsx
11
+ * import { requestPermission } from 'react-native-nitro-geolocation';
12
+ *
13
+ * const status = await requestPermission();
14
+ * if (status === 'granted') {
15
+ * // Get location
16
+ * }
17
+ * ```
18
+ */
19
+ export function requestPermission(): Promise<PermissionStatus> {
20
+ return NitroGeolocationHybridObject.requestPermission();
21
+ }
@@ -0,0 +1,31 @@
1
+ import type { ModernGeolocationConfiguration as NitroModernGeolocationConfiguration } from "../NitroGeolocation.nitro";
2
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
3
+ import type { ModernGeolocationConfiguration } from "../types";
4
+
5
+ /**
6
+ * Set global geolocation configuration.
7
+ * Should be called once at app startup.
8
+ *
9
+ * @param config - Platform-specific configuration
10
+ * @example
11
+ * ```tsx
12
+ * import { setConfiguration } from 'react-native-nitro-geolocation';
13
+ *
14
+ * setConfiguration({
15
+ * authorizationLevel: 'whenInUse',
16
+ * enableBackgroundLocationUpdates: false,
17
+ * locationProvider: 'auto'
18
+ * });
19
+ * ```
20
+ */
21
+ export function setConfiguration(config: ModernGeolocationConfiguration): void {
22
+ const nativeConfig: NitroModernGeolocationConfiguration = {
23
+ ...config,
24
+ locationProvider:
25
+ config.locationProvider === "android"
26
+ ? "android_platform"
27
+ : config.locationProvider
28
+ };
29
+
30
+ NitroGeolocationHybridObject.setConfiguration(nativeConfig);
31
+ }
@@ -0,0 +1,22 @@
1
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
2
+
3
+ /**
4
+ * Stop ALL watch subscriptions immediately.
5
+ *
6
+ * Use cases:
7
+ * - Emergency cleanup
8
+ * - App termination
9
+ * - User logout
10
+ *
11
+ * Note: Individual subscriptions should use unwatch() instead.
12
+ * @example
13
+ * ```tsx
14
+ * import { stopObserving } from 'react-native-nitro-geolocation';
15
+ *
16
+ * // Stop all location tracking
17
+ * stopObserving();
18
+ * ```
19
+ */
20
+ export function stopObserving(): void {
21
+ NitroGeolocationHybridObject.stopObserving();
22
+ }
@@ -0,0 +1,22 @@
1
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
2
+ import { devtoolsUnwatch } from "../devtools/watchPosition";
3
+
4
+ /**
5
+ * Stop a specific watch subscription.
6
+ *
7
+ * @param token - Subscription token from watchPosition()
8
+ * @example
9
+ * ```tsx
10
+ * import { watchPosition, unwatch } from 'react-native-nitro-geolocation';
11
+ *
12
+ * const token = watchPosition((position) => console.log(position));
13
+ * // Later...
14
+ * unwatch(token);
15
+ * ```
16
+ */
17
+ export function unwatch(token: string): void {
18
+ if (devtoolsUnwatch(token)) {
19
+ return;
20
+ }
21
+ NitroGeolocationHybridObject.unwatch(token);
22
+ }
@@ -0,0 +1,43 @@
1
+ import type {
2
+ LocationError,
3
+ LocationRequestOptions
4
+ } from "../NitroGeolocation.nitro";
5
+ import { NitroGeolocationHybridObject } from "../NitroGeolocationModule";
6
+ import { isDevtoolsEnabled } from "../devtools";
7
+ import { devtoolsWatchPosition } from "../devtools/watchPosition";
8
+ import type { GeolocationResponse } from "../types";
9
+
10
+ /**
11
+ * Start watching for continuous location updates.
12
+ *
13
+ * IMPORTANT: This is a LOW-LEVEL API.
14
+ * For React components, use useWatchPosition() hook instead.
15
+ *
16
+ * @param success - Called on each successful location update
17
+ * @param error - Called when an error occurs
18
+ * @param options - Location request options
19
+ * @returns Subscription token (UUID string) for cleanup
20
+ * @example
21
+ * ```tsx
22
+ * import { watchPosition, unwatch } from 'react-native-nitro-geolocation';
23
+ *
24
+ * const token = watchPosition(
25
+ * (position) => console.log(position.coords),
26
+ * (error) => console.error(error.message),
27
+ * { enableHighAccuracy: true, distanceFilter: 10 }
28
+ * );
29
+ *
30
+ * // Later: cleanup
31
+ * unwatch(token);
32
+ * ```
33
+ */
34
+ export function watchPosition(
35
+ success: (position: GeolocationResponse) => void,
36
+ error?: (error: LocationError) => void,
37
+ options?: LocationRequestOptions
38
+ ): string {
39
+ if (isDevtoolsEnabled()) {
40
+ return devtoolsWatchPosition(success, error);
41
+ }
42
+ return NitroGeolocationHybridObject.watchPosition(success, error, options);
43
+ }
@@ -0,0 +1,15 @@
1
+ import type { GeolocationResponse } from "../types";
2
+ import { getDevtoolsState } from "./index";
3
+
4
+ export function getDevtoolsCurrentPosition(): Promise<GeolocationResponse> | null {
5
+ const devtools = getDevtoolsState();
6
+ if (devtools.position) {
7
+ return Promise.resolve(devtools.position);
8
+ }
9
+ // Devtools not connected - throw error
10
+ return Promise.reject(
11
+ new Error(
12
+ "Geolocation devtools not connected. Press 'j' in Metro to open devtools and enable the geolocation plugin."
13
+ )
14
+ );
15
+ }
@@ -0,0 +1,23 @@
1
+ import type { GeolocationResponse } from "../types";
2
+
3
+ declare global {
4
+ var __geolocationDevToolsEnabled: boolean | undefined;
5
+ var __geolocationDevtools: DevtoolsState | undefined;
6
+ }
7
+
8
+ interface DevtoolsState {
9
+ position: GeolocationResponse | null;
10
+ }
11
+
12
+ export function getDevtoolsState(): DevtoolsState {
13
+ if (!globalThis.__geolocationDevtools) {
14
+ globalThis.__geolocationDevtools = {
15
+ position: null
16
+ };
17
+ }
18
+ return globalThis.__geolocationDevtools;
19
+ }
20
+
21
+ export function isDevtoolsEnabled(): boolean {
22
+ return globalThis.__geolocationDevToolsEnabled === true;
23
+ }
@@ -0,0 +1,66 @@
1
+ import type { GeolocationError, GeolocationResponse } from "../types";
2
+ import { getDevtoolsState } from "./index";
3
+
4
+ export function devtoolsWatchPosition(
5
+ success: (position: GeolocationResponse) => void,
6
+ error?: (error: GeolocationError) => void
7
+ ): string {
8
+ const devtools = getDevtoolsState();
9
+
10
+ // Check if devtools has position at all
11
+ if (!devtools.position) {
12
+ // Call error callback immediately if provided
13
+ if (error) {
14
+ error({
15
+ code: 2, // POSITION_UNAVAILABLE
16
+ message:
17
+ "Geolocation devtools not connected. Press 'j' in Metro to open devtools and enable the geolocation plugin.",
18
+ PERMISSION_DENIED: 1,
19
+ POSITION_UNAVAILABLE: 2,
20
+ TIMEOUT: 3
21
+ });
22
+ }
23
+ // Return a dummy token that does nothing
24
+ return `devtools-error-${Date.now()}`;
25
+ }
26
+
27
+ let previousPosition = devtools.position;
28
+
29
+ // Send initial position immediately if available
30
+ success(devtools.position);
31
+
32
+ const interval = setInterval(() => {
33
+ if (devtools.position && devtools.position !== previousPosition) {
34
+ previousPosition = devtools.position;
35
+ success(devtools.position);
36
+ }
37
+ }, 100);
38
+
39
+ // Return a cleanup token
40
+ const token = `devtools-${Date.now()}`;
41
+ (globalThis as any).__devtoolsWatchers =
42
+ (globalThis as any).__devtoolsWatchers || {};
43
+ (globalThis as any).__devtoolsWatchers[token] = interval;
44
+
45
+ return token;
46
+ }
47
+
48
+ export function devtoolsUnwatch(token: string): boolean {
49
+ if (!token.startsWith("devtools-")) {
50
+ return false;
51
+ }
52
+
53
+ // Handle error tokens (no cleanup needed)
54
+ if (token.startsWith("devtools-error-")) {
55
+ return true;
56
+ }
57
+
58
+ const watchers = (globalThis as any).__devtoolsWatchers;
59
+ if (watchers?.[token]) {
60
+ clearInterval(watchers[token]);
61
+ delete watchers[token];
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Modern React hooks for geolocation.
3
- * These hooks provide a declarative, React-friendly API for location services.
2
+ * React hook for geolocation.
3
+ * Provides a declarative API for continuous location tracking.
4
4
  */
5
5
 
6
- export * from "./useCheckPermission";
7
- export * from "./useRequestPermission";
8
- export * from "./useGetCurrentPosition";
9
- export * from "./useWatchPosition";
6
+ export { useWatchPosition } from "./useWatchPosition";
7
+ export type { UseWatchPositionOptions } from "./useWatchPosition";
@@ -3,7 +3,7 @@ import type {
3
3
  LocationError,
4
4
  LocationRequestOptions
5
5
  } from "../NitroGeolocation.nitro";
6
- import { useGeolocationClient } from "../components/GeolocationProvider";
6
+ import { unwatch, watchPosition } from "../api";
7
7
  import type { GeolocationResponse } from "../types";
8
8
 
9
9
  /**
@@ -51,8 +51,6 @@ export interface UseWatchPositionOptions extends LocationRequestOptions {
51
51
  * ```
52
52
  */
53
53
  export function useWatchPosition(options?: UseWatchPositionOptions) {
54
- const client = useGeolocationClient();
55
-
56
54
  const [position, setPosition] = useState<GeolocationResponse | null>(null);
57
55
  const [isWatching, setIsWatching] = useState(false);
58
56
  const [error, setError] = useState<LocationError | null>(null);
@@ -78,7 +76,7 @@ export function useWatchPosition(options?: UseWatchPositionOptions) {
78
76
  if (!enabled) {
79
77
  // Not enabled, ensure cleanup
80
78
  if (tokenRef.current) {
81
- client.unwatch(tokenRef.current);
79
+ unwatch(tokenRef.current);
82
80
  tokenRef.current = null;
83
81
  }
84
82
  setIsWatching(false);
@@ -89,7 +87,7 @@ export function useWatchPosition(options?: UseWatchPositionOptions) {
89
87
  setIsWatching(true);
90
88
  setError(null);
91
89
 
92
- const token = client.watchPosition(
90
+ const token = watchPosition(
93
91
  (result: GeolocationResponse) => {
94
92
  // Success callback
95
93
  if (!isMountedRef.current) return;
@@ -109,10 +107,10 @@ export function useWatchPosition(options?: UseWatchPositionOptions) {
109
107
  // Cleanup function
110
108
  return () => {
111
109
  if (token) {
112
- client.unwatch(token);
110
+ unwatch(token);
113
111
  }
114
112
  };
115
- }, [enabled, client]); // Only re-subscribe when enabled/client changes
113
+ }, [enabled]); // Only re-subscribe when enabled changes
116
114
 
117
115
  // Track mount status
118
116
  useEffect(() => {
package/src/index.tsx CHANGED
@@ -1,61 +1,61 @@
1
1
  /**
2
2
  * Modern Geolocation API for React Native.
3
3
  *
4
- * This is the main entry point for the modern, React-friendly API.
4
+ * This is the main entry point for the modern, functional API.
5
5
  * For legacy compatibility, use: import Geolocation from 'react-native-nitro-geolocation/compat'
6
6
  *
7
7
  * @example
8
8
  * ```tsx
9
9
  * import {
10
- * GeolocationClient,
11
- * GeolocationClientProvider,
12
- * useRequestPermission,
13
- * useGetCurrentPosition,
10
+ * setConfiguration,
11
+ * getCurrentPosition,
12
+ * requestPermission,
14
13
  * useWatchPosition
15
14
  * } from 'react-native-nitro-geolocation';
16
15
  *
17
- * // Create GeolocationClient instance
18
- * const geolocationClient = new GeolocationClient({
16
+ * // Set configuration at app startup
17
+ * setConfiguration({
19
18
  * authorizationLevel: 'whenInUse',
20
19
  * enableBackgroundLocationUpdates: false,
21
20
  * locationProvider: 'auto'
22
21
  * });
23
22
  *
24
- * function App() {
25
- * return (
26
- * <GeolocationClientProvider client={geolocationClient}>
27
- * <YourApp />
28
- * </GeolocationClientProvider>
29
- * );
23
+ * // Request permission
24
+ * async function setup() {
25
+ * const status = await requestPermission();
26
+ * if (status === 'granted') {
27
+ * const position = await getCurrentPosition({ enableHighAccuracy: true });
28
+ * console.log('Position:', position);
29
+ * }
30
30
  * }
31
31
  *
32
- * function LocationButton() {
33
- * const { getCurrentPosition } = useGetCurrentPosition();
34
- * const [loading, setLoading] = useState(false);
32
+ * // Continuous tracking in React component
33
+ * function LiveTracking() {
34
+ * const { position, error, isWatching } = useWatchPosition({
35
+ * enabled: true,
36
+ * enableHighAccuracy: true,
37
+ * distanceFilter: 10
38
+ * });
35
39
  *
36
- * const handlePress = async () => {
37
- * setLoading(true);
38
- * try {
39
- * const pos = await getCurrentPosition({ enableHighAccuracy: true });
40
- * console.log('Position:', pos);
41
- * } catch (error) {
42
- * console.error('Error:', error);
43
- * } finally {
44
- * setLoading(false);
45
- * }
46
- * };
40
+ * if (!isWatching) return <Text>Not watching</Text>;
41
+ * if (error) return <Text>Error: {error.message}</Text>;
42
+ * if (!position) return <Text>Waiting...</Text>;
47
43
  *
48
- * return <Button onPress={handlePress} disabled={loading} />;
44
+ * return <Text>Lat: {position.coords.latitude}</Text>;
49
45
  * }
50
46
  * ```
51
47
  */
52
48
 
53
- // Core
54
- export { GeolocationClient } from "./GeolocationClient";
55
- export type { GeolocationClientConfig } from "./GeolocationClient";
56
-
57
- // Components
58
- export * from "./components";
49
+ // Core API functions
50
+ export {
51
+ setConfiguration,
52
+ checkPermission,
53
+ requestPermission,
54
+ getCurrentPosition,
55
+ watchPosition,
56
+ unwatch,
57
+ stopObserving
58
+ } from "./api";
59
59
 
60
60
  // Hooks
61
61
  export * from "./hooks";
@@ -1,116 +0,0 @@
1
- import type {
2
- LocationError,
3
- LocationRequestOptions,
4
- ModernGeolocationConfiguration as NitroModernGeolocationConfiguration,
5
- PermissionStatus
6
- } from "./NitroGeolocation.nitro";
7
- import { NitroGeolocationHybridObject } from "./NitroGeolocationModule";
8
- import type { ModernGeolocationConfiguration } from "./types";
9
- import type { GeolocationResponse } from "./types";
10
-
11
- export interface GeolocationClientConfig
12
- extends ModernGeolocationConfiguration {}
13
-
14
- /**
15
- * GeolocationClient provides direct access to geolocation methods.
16
- *
17
- * Usage:
18
- * ```tsx
19
- * // With provider
20
- * const client = new GeolocationClient({ locationProvider: 'auto' });
21
- * <GeolocationClientProvider client={client}>
22
- * <App />
23
- * </GeolocationClientProvider>
24
- *
25
- * // Without provider
26
- * const standaloneClient = new GeolocationClient();
27
- * await standaloneClient.getCurrentPosition();
28
- * ```
29
- */
30
- export class GeolocationClient {
31
- private config: GeolocationClientConfig;
32
-
33
- constructor(config: GeolocationClientConfig = {}) {
34
- this.config = config;
35
-
36
- // Set configuration on Nitro module
37
- if (Object.keys(config).length > 0) {
38
- const nativeConfig: NitroModernGeolocationConfiguration = {
39
- ...config,
40
- locationProvider:
41
- config.locationProvider === "android"
42
- ? "android_platform"
43
- : config.locationProvider
44
- };
45
-
46
- NitroGeolocationHybridObject.setConfiguration(nativeConfig);
47
- }
48
- }
49
-
50
- /**
51
- * Check current location permission status.
52
- * Does NOT request permission, only checks current state.
53
- */
54
- checkPermission = (): Promise<PermissionStatus> => {
55
- return NitroGeolocationHybridObject.checkPermission();
56
- };
57
-
58
- /**
59
- * Request location permission from the user.
60
- * Shows system permission dialog if not yet determined.
61
- */
62
- requestPermission = (): Promise<PermissionStatus> => {
63
- return NitroGeolocationHybridObject.requestPermission();
64
- };
65
-
66
- /**
67
- * Get current location (one-time request).
68
- *
69
- * @param options - Location request options
70
- * @returns Promise resolving to current position
71
- */
72
- getCurrentPosition = (
73
- options?: LocationRequestOptions
74
- ): Promise<GeolocationResponse> => {
75
- return NitroGeolocationHybridObject.getCurrentPosition(options);
76
- };
77
-
78
- /**
79
- * Start watching for continuous location updates.
80
- *
81
- * @param success - Called on each successful location update
82
- * @param error - Called when an error occurs
83
- * @param options - Location request options
84
- * @returns Subscription token (UUID string) for cleanup
85
- */
86
- watchPosition = (
87
- success: (position: GeolocationResponse) => void,
88
- error?: (error: LocationError) => void,
89
- options?: LocationRequestOptions
90
- ): string => {
91
- return NitroGeolocationHybridObject.watchPosition(success, error, options);
92
- };
93
-
94
- /**
95
- * Stop a specific watch subscription.
96
- *
97
- * @param token - Subscription token from watchPosition()
98
- */
99
- unwatch = (token: string): void => {
100
- NitroGeolocationHybridObject.unwatch(token);
101
- };
102
-
103
- /**
104
- * Stop ALL watch subscriptions immediately.
105
- */
106
- stopObserving = (): void => {
107
- NitroGeolocationHybridObject.stopObserving();
108
- };
109
-
110
- /**
111
- * Get the current client configuration.
112
- */
113
- getConfig = (): Readonly<GeolocationClientConfig> => {
114
- return { ...this.config };
115
- };
116
- }
@@ -1,91 +0,0 @@
1
- import React, { createContext, useContext } from "react";
2
- import type { GeolocationClient } from "../GeolocationClient";
3
-
4
- /**
5
- * Geolocation context value.
6
- */
7
- export interface GeolocationContextValue {
8
- client: GeolocationClient;
9
- }
10
-
11
- /**
12
- * Geolocation context.
13
- */
14
- const GeolocationContext = createContext<GeolocationContextValue | null>(null);
15
-
16
- /**
17
- * Hook to access GeolocationClient from context.
18
- * Throws error if used outside GeolocationClientProvider.
19
- */
20
- export function useGeolocationClient(): GeolocationClient {
21
- const context = useContext(GeolocationContext);
22
-
23
- if (!context) {
24
- throw new Error(
25
- "useGeolocationClient must be used within GeolocationClientProvider. " +
26
- "Wrap your component with <GeolocationClientProvider client={...}> at the root level."
27
- );
28
- }
29
-
30
- return context.client;
31
- }
32
-
33
- /**
34
- * Props for GeolocationProvider component.
35
- */
36
- export interface GeolocationProviderProps {
37
- /**
38
- * GeolocationClient instance (required).
39
- * Create with: new GeolocationClient({...config})
40
- */
41
- client: GeolocationClient;
42
-
43
- /**
44
- * Child components that can use geolocation hooks.
45
- */
46
- children: React.ReactNode;
47
- }
48
-
49
- /**
50
- * Provider component for GeolocationClient.
51
- *
52
- * This component should wrap your app at the root level.
53
- * It provides a GeolocationClient instance to all child components via context.
54
- *
55
- * @example
56
- * ```tsx
57
- * // Create client instance
58
- * const geolocationClient = new GeolocationClient({
59
- * authorizationLevel: 'whenInUse',
60
- * enableBackgroundLocationUpdates: false,
61
- * locationProvider: 'auto'
62
- * });
63
- *
64
- * function App() {
65
- * return (
66
- * <GeolocationClientProvider client={geolocationClient}>
67
- * <NavigationContainer>
68
- * <YourApp />
69
- * </NavigationContainer>
70
- * </GeolocationClientProvider>
71
- * );
72
- * }
73
- * ```
74
- */
75
- export function GeolocationProvider({
76
- client,
77
- children
78
- }: GeolocationProviderProps) {
79
- const value: GeolocationContextValue = {
80
- client
81
- };
82
-
83
- return (
84
- <GeolocationContext.Provider value={value}>
85
- {children}
86
- </GeolocationContext.Provider>
87
- );
88
- }
89
-
90
- // Modern alias (preferred)
91
- export const GeolocationClientProvider = GeolocationProvider;
@@ -1,13 +0,0 @@
1
- /**
2
- * React components for geolocation.
3
- */
4
-
5
- export {
6
- GeolocationProvider,
7
- GeolocationClientProvider,
8
- useGeolocationClient
9
- } from "./GeolocationProvider";
10
- export type {
11
- GeolocationProviderProps,
12
- GeolocationContextValue
13
- } from "./GeolocationProvider";
@@ -1,46 +0,0 @@
1
- import type { PermissionStatus } from "../NitroGeolocation.nitro";
2
- import { useGeolocationClient } from "../components/GeolocationProvider";
3
-
4
- /**
5
- * Hook that returns a function to check current location permission status.
6
- * Does NOT request permission, only checks current state.
7
- *
8
- * Must be used within GeolocationClientProvider.
9
- *
10
- * @returns Object containing checkPermission function
11
- *
12
- * @example
13
- * ```tsx
14
- * const geolocationClient = new GeolocationClient({...config});
15
- *
16
- * function App() {
17
- * return (
18
- * <GeolocationClientProvider client={geolocationClient}>
19
- * <MyComponent />
20
- * </GeolocationClientProvider>
21
- * );
22
- * }
23
- *
24
- * function MyComponent() {
25
- * const { checkPermission } = useCheckPermission();
26
- *
27
- * const handleCheck = async () => {
28
- * const status = await checkPermission();
29
- * if (status === 'granted') {
30
- * // Can use location
31
- * }
32
- * };
33
- *
34
- * return <Button onPress={handleCheck} />;
35
- * }
36
- * ```
37
- */
38
- export function useCheckPermission() {
39
- const client = useGeolocationClient();
40
-
41
- return {
42
- checkPermission: (): Promise<PermissionStatus> => {
43
- return client.checkPermission();
44
- }
45
- };
46
- }
@@ -1,140 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
2
- import type {
3
- LocationError,
4
- LocationRequestOptions
5
- } from "../NitroGeolocation.nitro";
6
- import { useGeolocationClient } from "../components/GeolocationProvider";
7
- import type { GeolocationResponse } from "../types";
8
-
9
- /**
10
- * Options for useGetCurrentPosition hook (Query style).
11
- */
12
- export interface UseGetCurrentPositionOptions extends LocationRequestOptions {
13
- /**
14
- * Whether to automatically fetch the current position.
15
- * When false, only manual refetch() will trigger the request.
16
- * @default true
17
- */
18
- enabled?: boolean;
19
- }
20
-
21
- /**
22
- * Hook for getting current location (one-time request) in Query style.
23
- * Provides loading, error states, and data similar to TanStack Query.
24
- *
25
- * @param options - Location request options and enabled flag
26
- * @returns Object containing position, loading/error states, and refetch function
27
- *
28
- * @example
29
- * ```tsx
30
- * // Auto-fetch on mount
31
- * function MyComponent() {
32
- * const {
33
- * position,
34
- * isLoading,
35
- * isError,
36
- * error,
37
- * refetch
38
- * } = useGetCurrentPosition({
39
- * enabled: true,
40
- * enableHighAccuracy: true,
41
- * });
42
- *
43
- * if (isLoading) return <Text>Loading...</Text>;
44
- * if (isError) return <Text>Error: {error?.message}</Text>;
45
- * if (!position) return null;
46
- *
47
- * return (
48
- * <View>
49
- * <Text>Lat: {position.coords.latitude}</Text>
50
- * <Text>Lng: {position.coords.longitude}</Text>
51
- * <Button title="Refresh" onPress={() => refetch()} />
52
- * </View>
53
- * );
54
- * }
55
- *
56
- * // Manual trigger only
57
- * function ManualComponent() {
58
- * const { position, isLoading, refetch } = useGetCurrentPosition({
59
- * enabled: false
60
- * });
61
- *
62
- * return (
63
- * <View>
64
- * <Button
65
- * title="Get Location"
66
- * onPress={() => refetch()}
67
- * disabled={isLoading}
68
- * />
69
- * {position && <Text>Lat: {position.coords.latitude}</Text>}
70
- * </View>
71
- * );
72
- * }
73
- * ```
74
- */
75
- export function useGetCurrentPosition(options?: UseGetCurrentPositionOptions) {
76
- const client = useGeolocationClient();
77
-
78
- const [position, setPosition] = useState<GeolocationResponse | null>(null);
79
- const [isLoading, setIsLoading] = useState(false);
80
- const [isError, setIsError] = useState(false);
81
- const [error, setError] = useState<LocationError | null>(null);
82
-
83
- const isMountedRef = useRef(true);
84
- const optionsRef = useRef(options);
85
-
86
- // Update options ref when they change
87
- useEffect(() => {
88
- optionsRef.current = options;
89
- }, [options]);
90
-
91
- const fetchPosition = useCallback(async () => {
92
- if (!isMountedRef.current) return;
93
-
94
- setIsLoading(true);
95
- setIsError(false);
96
- setError(null);
97
-
98
- try {
99
- const result = await client.getCurrentPosition(optionsRef.current);
100
- if (!isMountedRef.current) return;
101
-
102
- setPosition(result);
103
- setIsLoading(false);
104
- } catch (err) {
105
- if (!isMountedRef.current) return;
106
-
107
- setIsError(true);
108
- setError(err as LocationError);
109
- setIsLoading(false);
110
- }
111
- }, [client]);
112
-
113
- // Extract enabled flag for reactive dependency
114
- const enabled = options?.enabled ?? true;
115
-
116
- // Auto-fetch on mount if enabled
117
- useEffect(() => {
118
- if (enabled) {
119
- fetchPosition();
120
- }
121
- // Only run when enabled changes, not when fetchPosition changes
122
- // eslint-disable-next-line react-hooks/exhaustive-deps
123
- }, [enabled]);
124
-
125
- // Track mount status
126
- useEffect(() => {
127
- isMountedRef.current = true;
128
- return () => {
129
- isMountedRef.current = false;
130
- };
131
- }, []);
132
-
133
- return {
134
- position,
135
- isLoading,
136
- isError,
137
- error,
138
- refetch: fetchPosition
139
- };
140
- }
@@ -1,98 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from "react";
2
- import type {
3
- LocationError,
4
- PermissionStatus
5
- } from "../NitroGeolocation.nitro";
6
- import { useGeolocationClient } from "../components/GeolocationProvider";
7
-
8
- /**
9
- * Hook for requesting location permission in Mutation style.
10
- * Provides pending, error states, and status similar to TanStack Query mutations.
11
- *
12
- * @returns Object containing requestPermission function, status, and state flags
13
- *
14
- * @example
15
- * ```tsx
16
- * function MyComponent() {
17
- * const {
18
- * requestPermission,
19
- * status,
20
- * isPending,
21
- * isError,
22
- * error
23
- * } = useRequestPermission();
24
- *
25
- * const handleRequest = async () => {
26
- * const result = await requestPermission();
27
- * if (result === 'granted') {
28
- * console.log('Permission granted!');
29
- * }
30
- * };
31
- *
32
- * return (
33
- * <View>
34
- * <Button
35
- * onPress={handleRequest}
36
- * disabled={isPending}
37
- * >
38
- * {isPending ? 'Requesting...' : 'Request Permission'}
39
- * </Button>
40
- * {isError && <Text>Error: {error?.message}</Text>}
41
- * {status && <Text>Status: {status}</Text>}
42
- * </View>
43
- * );
44
- * }
45
- * ```
46
- */
47
- export function useRequestPermission() {
48
- const client = useGeolocationClient();
49
-
50
- const [status, setStatus] = useState<PermissionStatus | null>(null);
51
- const [isPending, setIsPending] = useState(false);
52
- const [isError, setIsError] = useState(false);
53
- const [error, setError] = useState<LocationError | null>(null);
54
-
55
- const isMountedRef = useRef(true);
56
-
57
- const requestPermission = useCallback(async (): Promise<PermissionStatus> => {
58
- if (!isMountedRef.current) {
59
- throw new Error("Component unmounted");
60
- }
61
-
62
- setIsPending(true);
63
- setIsError(false);
64
- setError(null);
65
-
66
- try {
67
- const result = await client.requestPermission();
68
- if (!isMountedRef.current) return result;
69
-
70
- setStatus(result);
71
- setIsPending(false);
72
- return result;
73
- } catch (err) {
74
- if (!isMountedRef.current) throw err;
75
-
76
- setIsError(true);
77
- setError(err as LocationError);
78
- setIsPending(false);
79
- throw err;
80
- }
81
- }, [client]);
82
-
83
- // Track mount status
84
- useEffect(() => {
85
- isMountedRef.current = true;
86
- return () => {
87
- isMountedRef.current = false;
88
- };
89
- }, []);
90
-
91
- return {
92
- requestPermission,
93
- status,
94
- isPending,
95
- isError,
96
- error
97
- };
98
- }