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

@smarthivelabs-devs/geocore-expo

v1.6.5

Published

Geocore Expo/React Native SDK — mapping and geocoding for mobile

Downloads

1,159

Readme

@smarthivelabs-devs/geocore-expo

Expo / React Native SDK for Geocore. All 14 geo-operations, weather, and the SmartHive Pricing Engine — with hooks that match the React package's API.

Installation

npx expo install @smarthivelabs-devs/geocore-expo @smarthivelabs-devs/geocore-core

Map rendering (optional)

Pick one — or both. Install the one your project already uses:

# Option A — react-native-maps (classic, widely used)
npx expo install react-native-maps

# Option B — expo-maps (newer Expo SDK)
npx expo install expo-maps

Neither is required if you only need the data hooks (geocoding, weather, pricing, etc.) without an interactive map.


Setup

import { Geocore } from '@smarthivelabs-devs/geocore-core';

// Backend mode (recommended — API key only)
const geocore = new Geocore({
  apiKey: 'your-geocore-api-key',
});

// Direct mode (provider keys in the app)
const geocore = new Geocore({
  apiKeys: {
    mapbox: { secretToken: 'sk.eyJ1...' },
    google: 'AIza...',
  },
});

Reverse Geocoding — useReverseGeocode

The simplest way to turn coordinates into a display address. Supports auto-fetching the device location or accepting explicit coordinates (e.g. from a map pin).

import { useReverseGeocode, getDisplayAddress } from '@smarthivelabs-devs/geocore-expo';

// Auto-fetch device location on mount
function MyLocationLabel() {
  const { address, components, loading } = useReverseGeocode({
    geocore,
    autoFetch: true,
  });

  if (loading) return <ActivityIndicator />;
  return <Text>{address}</Text>;
  // → "Adum, Kumasi, Ashanti Region, Ghana"
}

// Geocode a map pin
function MapPinAddress({ coords }) {
  const { address, components, loading, refresh } = useReverseGeocode({
    geocore,
    coords,   // re-runs whenever coords changes
  });

  return (
    <View>
      <Text>{address}</Text>
      <Text>{components.city}, {components.state}</Text>
    </View>
  );
}

Address Search — useAddressSearch

Debounced address search with autocomplete suggestions. Handles typing, shows results, and locks in coordinates once confirmed. Drop this into any address input field.

import { useAddressSearch } from '@smarthivelabs-devs/geocore-expo';
import * as Location from 'expo-location';

function AddressInput({ label, onConfirm }) {
  const [proximity, setProximity] = useState(null);

  useEffect(() => {
    Location.getCurrentPositionAsync().then(loc => {
      setProximity({ latitude: loc.coords.latitude, longitude: loc.coords.longitude });
    });
  }, []);

  const search = useAddressSearch({ geocore, proximity, limit: 5 });

  useEffect(() => {
    if (search.confirmed && search.coords) {
      onConfirm(search.value, search.coords, search.components);
    }
  }, [search.confirmed]);

  return (
    <View>
      <TextInput
        value={search.value}
        onChangeText={search.onChange}
        placeholder={`Enter ${label} address`}
      />
      {search.loading && <ActivityIndicator />}
      {search.suggestions.map(s => (
        <TouchableOpacity key={s.address} onPress={() => search.onSelect(s)}>
          <Text>{s.label}</Text>
          <Text style={{ color: 'gray' }}>{s.sublabel}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
}

// Confirm from a map picker instead of typing:
search.confirm('Adum, Kumasi', { latitude: 6.6885, longitude: -1.6244 });

Geocoding (low-level)

import { useGeocoding } from '@smarthivelabs-devs/geocore-expo';

function Screen() {
  const { geocodingResult, loading, geocode } = useGeocoding(geocore);

  return (
    <Button
      title="Find Eiffel Tower"
      onPress={() => geocode('Eiffel Tower, Paris')}
    />
  );
}

Places & Search

import { usePlaces, useNearbySearch, useAutocomplete } from '@smarthivelabs-devs/geocore-expo';

// Text search near a coordinate
const { result, loading, searchPlaces } = usePlaces(geocore);
await searchPlaces('pharmacy', { lat: 6.5244, lng: 3.3792 }, { radius: 1000 });
// result.data — [{ name, coordinates, address, rating }]

// Category-based nearby search
const { result, searchNearby } = useNearbySearch(geocore);
await searchNearby('hospital', { lat: 6.5244, lng: 3.3792 });

// Autocomplete as user types
const { predictions, loading, getSuggestions } = useAutocomplete(geocore);
await getSuggestions('Ikeja Ala');
// predictions — [{ mainText: 'Ikeja', secondaryText: 'Lagos, Nigeria', placeId }]

Directions & Routing

import { useDirections } from '@smarthivelabs-devs/geocore-expo';

const { result, getDirections } = useDirections(geocore);

await getDirections(
  { lat: 6.5244, lng: 3.3792 },
  { lat: 9.0765, lng: 7.3986 },
  { mode: 'driving' }
);
// result.data.distance, result.data.duration, result.data.steps

Spatial Analysis

import { useElevation, useTimezone, useIsochrone } from '@smarthivelabs-devs/geocore-expo';

const { result, getElevation } = useElevation(geocore);
const { result, getTimezone } = useTimezone(geocore);
const { result, getIsochrone } = useIsochrone(geocore);

await getTimezone(51.5074, -0.1278);
console.log(result?.data.timeZoneId); // 'Europe/London'

Utility Hooks

import { useTraffic, useDistanceMatrix, useSnapToRoad, useRouteOptimize, useStaticMap } from '@smarthivelabs-devs/geocore-expo';

// Traffic conditions at a location
const { result, getTraffic } = useTraffic(geocore);
await getTraffic(51.5074, -0.1278);
// result.data.condition: 'free' | 'slow' | 'heavy' | 'blocked'

// Origin → destination time/distance grid
const { result, getMatrix } = useDistanceMatrix(geocore);
await getMatrix(
  ['Lagos, Nigeria', 'Abuja, Nigeria'],
  ['Port Harcourt, Nigeria'],
  { mode: 'driving' }
);

// Snap recorded GPS points to the road network
const { result, snap } = useSnapToRoad(geocore);
await snap([
  { lat: 6.524, lng: 3.379 },
  { lat: 6.530, lng: 3.385 },
]);

// Optimise stop order for a multi-stop trip
const { result, optimise } = useRouteOptimize(geocore);
await optimise(['Lagos, Nigeria', 'Ibadan, Nigeria', 'Abeokuta, Nigeria']);

// Static map image URL
const { result, getMap } = useStaticMap(geocore);
await getMap(6.5244, 3.3792, { zoom: 14, width: 600, height: 400 });
// result.data.url — render in <Image source={{ uri: result.data.url }} />

Weather

import { useWeather } from '@smarthivelabs-devs/geocore-expo';
import * as Location from 'expo-location';

function WeatherScreen() {
  const { currentResult, forecastResult, loading, getWeather, getForecast } = useWeather(geocore);

  useEffect(() => {
    (async () => {
      const loc = await Location.getCurrentPositionAsync();
      const { latitude: lat, longitude: lng } = loc.coords;
      getWeather(lat, lng);
      getForecast(lat, lng, 7);
    })();
  }, []);

  return (
    <View>
      <Text>{currentResult?.data.temperature}°C</Text>
      <Text>{currentResult?.data.description}</Text>
      {forecastResult?.data.days.map(day => (
        <Text key={day.date}>
          {day.date}: {day.tempMin}–{day.tempMax}°C
        </Text>
      ))}
    </View>
  );
}

SmartHive Pricing Engine

Show localised prices based on the user's GPS location. If the user manually selects their country, call localizePriceByCountry to recalculate instantly — no re-detection needed.

import { usePricing } from '@smarthivelabs-devs/geocore-expo';
import * as Location from 'expo-location';

function PricingScreen() {
  const { result, loading, localizePrice, localizePriceByCountry } = usePricing(geocore);

  // Auto-detect on mount
  useEffect(() => {
    (async () => {
      const loc = await Location.getCurrentPositionAsync();
      localizePrice(100, 'GHS', loc.coords.latitude, loc.coords.longitude);
    })();
  }, []);

  return (
    <View>
      {loading && <ActivityIndicator />}
      {result && (
        <>
          <Text style={styles.price}>
            {result.data.symbol}{result.data.amount} {result.data.currency}/month
          </Text>
          <Text style={styles.country}>{result.data.countryName}</Text>
        </>
      )}

      {/* Country switcher */}
      <Picker onValueChange={(code) => localizePriceByCountry(100, 'GHS', code)}>
        <Picker.Item label="Nigeria" value="NG" />
        <Picker.Item label="Ghana" value="GH" />
        <Picker.Item label="United States" value="US" />
        <Picker.Item label="United Kingdom" value="GB" />
        <Picker.Item label="Kenya" value="KE" />
      </Picker>
    </View>
  );
}

FX lookup

const { rateResult, getRate } = usePricing(geocore);
await getRate('USD', 'NGN');
console.log(rateResult?.data.rate); // e.g. 1580

Interactive Map (render prop pattern)

Pass your preferred map library as a render prop. This avoids bundling native modules.

With react-native-maps

import { GeocodingMapScreen } from '@smarthivelabs-devs/geocore-expo';
import { ReactNativeMapsRenderer } from '@smarthivelabs-devs/geocore-expo/renderers';

<GeocodingMapScreen
  geocore={geocore}
  renderMap={(props) => <ReactNativeMapsRenderer {...props} />}
/>

With expo-maps

import { ExpoMapsRenderer } from '@smarthivelabs-devs/geocore-expo/renderers';

<GeocodingMapScreen
  geocore={geocore}
  renderMap={(props) => <ExpoMapsRenderer {...props} />}
/>

Bring your own map

<GeocodingMapScreen
  geocore={geocore}
  renderMap={({ region, markers, style }) => (
    <MyCustomMap region={region} pins={markers} style={style} />
  )}
/>

All Hooks

| Hook | Returns / Actions | Notes | |------|-------------------|-------| | useReverseGeocode | address, components, coords, loading, error, refresh | New in 1.6 — auto-fetches device location or accepts map pin coords | | useAddressSearch | value, suggestions, confirmed, coords, onChange, onSelect, confirm, clear | New in 1.6 — debounced search with autocomplete | | useGeocoding | geocode, reverse | Low-level geocode/reverse | | useDirections | getDirections | | | usePlaces | searchPlaces | | | useNearbySearch | searchNearby | | | useAutocomplete | getSuggestions | | | useElevation | getElevation | | | useIsochrone | getIsochrone | | | useTimezone | getTimezone | | | useTraffic | getTraffic | | | useDistanceMatrix | getMatrix | | | useSnapToRoad | snap | | | useRouteOptimize | optimise | | | useStaticMap | getMap | | | useWeather | getWeather, getForecast | | | usePricing | localizePrice, localizePriceByCountry, getRate, getRates | |

Every hook returns { loading, error, reset } alongside its data and action callbacks.


Changelog

1.6.0

  • New useReverseGeocode hook — reverse-geocode with auto device-location support. Returns normalized address string and structured components.
  • New useAddressSearch hook — debounced address input with autocomplete suggestions and coordinate confirmation.
  • Normalized address componentscomponents from all hooks now use consistent keys (city, state, area, street, etc.) regardless of which backend provider answered. See geocore-core changelog for details.
  • getDisplayAddress utility — re-exported from this package for convenience.

Error Handling

Every hook exposes error: Error | null. Errors are caught internally — they never crash your app. Use reset() to clear before a new action.

const { result, loading, error, geocode, reset } = useGeocoding(geocore);

const handleSearch = async () => {
  reset();
  await geocode('1 Infinite Loop, Cupertino');
};

return (
  <View>
    {loading && <ActivityIndicator />}
    {error && <Text style={{ color: 'red' }}>{error.message}</Text>}
    {result && <Text>{result.data.formattedAddress}</Text>}
    <Button title="Search" onPress={handleSearch} />
  </View>
);

Platform Notes

  • iOS — expo-maps uses Apple Maps by default
  • Android — expo-maps uses Google Maps (requires Google Maps SDK key)
  • react-native-maps — works on both platforms, uses Google Maps on Android and Apple Maps on iOS
  • Weather and Pricing hooks are platform-agnostic (pure HTTP)

License

MIT — SmartHive Labs