npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@natify/geolocation-rn

v1.0.2

Published

Geolocation adapter for Natify Framework using `@react-native-community/geolocation`.

Readme

@natify/geolocation-rn

Geolocation adapter for Natify Framework using @react-native-community/geolocation.

Installation

pnpm add @natify/geolocation-rn @react-native-community/geolocation

iOS

Add permission in ios/YourApp/Info.plist:

<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to show nearby places</string>

<!-- Optional: For background location -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location to track your location in real time</string>

Then:

cd ios && pod install && cd ..

Android

Add permission in android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Usage

Provider Configuration

import { NatifyProvider } from "@natify/core";
import { RnGeolocationAdapter } from "@natify/geolocation-rn";
import { RnPermissionsAdapter } from "@natify/permissions-rn";

const config = {
  geolocation: new RnGeolocationAdapter(),
  permissions: new RnPermissionsAdapter(),
  // ... other adapters
};

function App() {
  return (
    <NatifyProvider config={config}>
      <MyApp />
    </NatifyProvider>
  );
}

Get Current Location

Basic Usage

import { useAdapter, GeolocationPort } from "@natify/core";

function MyComponent() {
  const geolocation = useAdapter<GeolocationPort>("geolocation");

  const getCurrentLocation = async () => {
    try {
      const currentLocation = await geolocation.getCurrentPosition();
      console.log("Latitude:", currentLocation.latitude);
      console.log("Longitude:", currentLocation.longitude);
      console.log("Accuracy:", currentLocation.accuracy, "meters");
    } catch (error) {
      console.error("Error getting location:", error);
    }
  };

  return <Button onPress={getCurrentLocation} title="Get Location" />;
}

With Accuracy Options

// High accuracy (GPS)
const location = await locationService.getCurrentPosition({
  enableHighAccuracy: true,
  timeout: 20000,
  maximumAge: 0, // Always get new location
});

// Low accuracy (faster, less battery)
const location = await locationService.getCurrentPosition({
  enableHighAccuracy: false,
  timeout: 10000,
  maximumAge: 60000, // Accept location up to 1 minute old
});

With Permission Check

import { useAdapter, GeolocationPort, PermissionPort, PermissionStatus } from "@natify/core";

function LocationButton() {
  const geolocation = useAdapter<GeolocationPort>("geolocation");
  const permissions = useAdapter<PermissionPort>("permissions");

  const requestLocation = async () => {
    // Check permission
    const status = await permissions.check("location");
    
    if (status !== PermissionStatus.GRANTED) {
      // Request permission
      const newStatus = await permissions.request("location");
      if (newStatus !== PermissionStatus.GRANTED) {
        alert("Location permission required");
        return;
      }
    }

    // Check if service is enabled
    const isEnabled = await geolocation.isLocationEnabled();
    if (!isEnabled) {
      alert("Please enable location services");
      return;
    }

    // Get location
    try {
      const currentLocation = await geolocation.getCurrentPosition();
      console.log("Location:", currentLocation);
    } catch (error) {
      console.error("Error:", error);
    }
  };

  return <Button onPress={requestLocation} title="Get Location" />;
}

Watch Location Changes

Simple Watch Position

function LocationTracker() {
  const geolocation = useAdapter<GeolocationPort>("geolocation");
  const [currentLocation, setCurrentLocation] = useState<Location | null>(null);

  useEffect(() => {
    const stopWatching = geolocation.watchPosition((newLocation) => {
      setCurrentLocation(newLocation);
      console.log("New location:", newLocation);
    });

    // Cleanup on unmount
    return stopWatching;
  }, []);

  return (
    <View>
      {currentLocation && (
        <Text>
          Lat: {currentLocation.latitude}, Lng: {currentLocation.longitude}
        </Text>
      )}
    </View>
  );
}

With Distance Filter

// Only update if device moves more than 10 meters
const stopWatching = geolocation.watchPosition(
  (newLocation) => {
    console.log("Location updated:", newLocation);
  },
  {
    enableHighAccuracy: true,
    distanceFilter: 10, // 10 meters
    interval: 5000, // Minimum 5 seconds between updates
  }
);

For Real-Time Navigation

function NavigationScreen() {
  const geolocation = useAdapter<GeolocationPort>("geolocation");
  const [route, setRoute] = useState<Location[]>([]);

  useEffect(() => {
    const stopWatching = geolocation.watchPosition(
      (newLocation) => {
        // Add to route
        setRoute((prev) => [...prev, newLocation]);
        
        // Update map
        updateMapMarker(newLocation);
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 5, // Update every 5 meters
        interval: 1000, // Maximum 1 update per second
      }
    );

    return stopWatching;
  }, []);

  return <MapView route={route} />;
}

Calculate Distance

Distance Between Two Points

const geolocation = useAdapter<GeolocationPort>("geolocation");

// Origin and destination coordinates
const origin: Coordinates = {
  latitude: 40.7128,
  longitude: -74.0060,
  accuracy: 10,
};

const destination: Coordinates = {
  latitude: 40.7589,
  longitude: -73.9851,
  accuracy: 10,
};

// Calculate distance in meters
const distance = geolocation.calculateDistance(origin, destination);
console.log(`Distance: ${distance.toFixed(2)} meters`);
console.log(`Distance: ${(distance / 1000).toFixed(2)} kilometers`);

Distance to Multiple Points

const findNearestPlace = async (places: Array<{ name: string; coordinates: Coordinates }>) => {
  const currentLocation = await geolocation.getCurrentPosition();
  
  const distances = places.map((place) => ({
    ...place,
    distance: geolocation.calculateDistance(currentLocation, place.coordinates),
  }));

  // Sort by distance
  distances.sort((a, b) => a.distance - b.distance);

  return distances[0]; // Nearest one
};

Calculate Bearing (Direction)

const geolocation = useAdapter<GeolocationPort>("geolocation");

const origin: Coordinates = {
  latitude: 40.7128,
  longitude: -74.0060,
  accuracy: 10,
};

const destination: Coordinates = {
  latitude: 40.7589,
  longitude: -73.9851,
  accuracy: 10,
};

// Calculate direction in degrees (0-360)
const bearing = geolocation.calculateBearing(origin, destination);
console.log(`Bearing: ${bearing.toFixed(2)}°`);

// Convert to cardinal direction
const directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"];
const direction = directions[Math.round(bearing / 45) % 8];
console.log(`Direction: ${direction}`);

Common Use Cases

Check If User Is Near a Place

const checkIfNearPlace = async (
  placeCoordinates: Coordinates,
  radiusMeters: number
): Promise<boolean> => {
  const currentLocation = await geolocation.getCurrentPosition();
  const distance = geolocation.calculateDistance(currentLocation, placeCoordinates);
  
  return distance <= radiusMeters;
};

Route Tracking

function RouteTracker() {
  const geolocation = useAdapter<GeolocationPort>("geolocation");
  const [route, setRoute] = useState<Location[]>([]);
  const [isTracking, setIsTracking] = useState(false);
  const stopWatchingRef = useRef<(() => void) | null>(null);

  const startTracking = () => {
    setIsTracking(true);
    setRoute([]);

    stopWatchingRef.current = geolocation.watchPosition(
      (newLocation) => {
        setRoute((prev) => [...prev, newLocation]);
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 5, // Record every 5 meters
        interval: 2000,
      }
    );
  };

  const stopTracking = () => {
    setIsTracking(false);
    stopWatchingRef.current?.();
    stopWatchingRef.current = null;
  };

  const calculateTotalDistance = () => {
    if (route.length < 2) return 0;

    let total = 0;
    for (let i = 1; i < route.length; i++) {
      total += geolocation.calculateDistance(route[i - 1], route[i]);
    }

    return total;
  };

  return (
    <View>
      <Button
        title={isTracking ? "Stop Tracking" : "Start Tracking"}
        onPress={isTracking ? stopTracking : startTracking}
      />
      {route.length > 0 && (
        <Text>Distance: {(calculateTotalDistance() / 1000).toFixed(2)} km</Text>
      )}
    </View>
  );
}

Geofencing (Zone Entry/Exit Detection)

function GeofenceMonitor({ center, radius }: { center: Coordinates; radius: number }) {
  const geolocation = useAdapter<GeolocationPort>("geolocation");
  const [isInside, setIsInside] = useState(false);

  useEffect(() => {
    const stopWatching = geolocation.watchPosition(
      (newLocation) => {
        const distance = geolocation.calculateDistance(newLocation, center);
        const inside = distance <= radius;

        if (inside !== isInside) {
          setIsInside(inside);
          if (inside) {
            console.log("Entered geofence!");
            onEnterGeofence();
          } else {
            console.log("Exited geofence!");
            onExitGeofence();
          }
        }
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 10, // Check every 10 meters
      }
    );

    return stopWatching;
  }, [center, radius]);

  return null;
}

Location UseCase

import { GeolocationPort } from "@natify/core";

export class GetNearbyPlacesUseCase {
  constructor(private readonly geolocation: GeolocationPort) {}

  async execute(radiusKm: number): Promise<Place[]> {
    // Get current location
    const currentLocation = await this.geolocation.getCurrentPosition({
      enableHighAccuracy: true,
    });

    // Get places from API
    const allPlaces = await this.fetchPlacesFromAPI();

    // Filter by distance
    const nearbyPlaces = allPlaces.filter((place) => {
      const distance = this.geolocation.calculateDistance(
        currentLocation,
        place.coordinates
      );
      return distance <= radiusKm * 1000; // Convert km to meters
    });

    // Sort by distance
    nearbyPlaces.sort((a, b) => {
      const distA = this.geolocation.calculateDistance(currentLocation, a.coordinates);
      const distB = this.geolocation.calculateDistance(currentLocation, b.coordinates);
      return distA - distB;
    });

    return nearbyPlaces;
  }
}

API

GeolocationPort

| Method | Description | |--------|-------------| | getCurrentPosition(options?) | Gets current location | | watchPosition(callback, options?) | Watches location changes | | isLocationEnabled() | Checks if service is enabled | | calculateDistance(from, to) | Calculates distance in meters | | calculateBearing(from, to) | Calculates direction in degrees |

LocationOptions

interface LocationOptions {
  enableHighAccuracy?: boolean; // default: true
  timeout?: number; // default: 15000 (15 seconds)
  maximumAge?: number; // default: 0 (always new)
}

WatchLocationOptions

interface WatchLocationOptions extends LocationOptions {
  distanceFilter?: number; // default: 0 (all updates)
  interval?: number; // default: 1000 (1 second)
}

Location

interface Location extends Coordinates {
  timestamp: number;
}

interface Coordinates {
  latitude: number;
  longitude: number;
  accuracy: number;
  altitude?: number;
  altitudeAccuracy?: number;
  verticalAccuracy?: number;
  heading?: number;
  speed?: number;
}

Notes

  • Permissions: Always check and request permissions before using location
  • Battery: Use enableHighAccuracy: false and distanceFilter to save battery
  • Accuracy: enableHighAccuracy: true uses GPS (more accurate but consumes more battery)
  • Timeout: Set a reasonable timeout to avoid infinite waits
  • Watch Position: Always clean up watchers in useEffect cleanup
  • iOS: Requires configuration in Info.plist
  • Android: Requires permissions in AndroidManifest.xml

Module Integration

import { createModule } from "@natify/core";
import { GetNearbyPlacesUseCase } from "./usecases/GetNearbyPlacesUseCase";

export const PlacesModule = createModule("places", "Places")
  .requires("geolocation", "permissions")
  .useCase("getNearbyPlaces", (adapters) => {
    return new GetNearbyPlacesUseCase(adapters.geolocation);
  })
  .build();