npm package: @gebeta/tiles-react-native
Description: A React Native SDK for integrating Gebeta Maps into your applications
Author: AfriGebeta
Latest version: 1.2.0

# GebetaMap React Native SDK

A React Native SDK for integrating Gebeta Maps into your applications.

## Features

- Interactive maps with Gebeta tiles
- Marker management
- Fence drawing
- Path visualization
- Clustering support
- Geocoding and reverse geocoding
- Directions and routing
- Navigation UI (route rendering + HUD)
- Custom styling options

## Installation

```bash
yarn add @gebeta/tiles-react-native
yarn add @maplibre/maplibre-react-native
```
> maplibre is a required dependency.
## Basic Usage

```tsx
import React, { useRef } from 'react';
import { View, Alert } from 'react-native';
import { GebetaMap, GebetaMapRef } from '@gebeta/tiles-react-native';

const App = () => {
  const mapRef = useRef<GebetaMapRef>(null);

  const handleMapClick = (lngLat: [number, number], event: any) => {
    Alert.alert(
      'Map Clicked',
      `Longitude: ${lngLat[0].toFixed(6)}\nLatitude: ${lngLat[1].toFixed(6)}`
    );
  };

  const handleMapLoaded = () => {
    // Add a marker after map loads
    if (mapRef.current) {
      mapRef.current.addImageMarker(
        [38.7463, 9.0223], // Addis Ababa coordinates
        'https://via.placeholder.com/32x32/007cbf/ffffff?text=M',
        [32, 32],
        (lngLat, marker, event) => {
          Alert.alert('Marker Clicked', 'You clicked on Addis Ababa!');
        }
      );
    }
  };

  return (
    <View style={{ flex: 1 }}>
      <GebetaMap
        ref={mapRef}
        apiKey="your-api-key-here"
        center={[38.7463, 9.0223]} // Addis Ababa
        zoom={12}
        onMapClick={handleMapClick}
        onMapLoaded={handleMapLoaded}
      />
    </View>
  );
};

export default App;
```

## Fly
```tsx
import React, { useRef } from 'react';
import { Alert, View, Button, StyleSheet } from 'react-native'; 
import GebetaMap, { GebetaMapRef } from '@gebeta/tiles-react-native';

const App = () => {
    const mapRef = useRef<GebetaMapRef>(null);

    const handleMapClick = (lngLat: [number, number]) => {
        Alert.alert(
            'Map Clicked',
            `Longitude: ${lngLat[0].toFixed(6)}\nLatitude: ${lngLat[1].toFixed(6)}`
        );
    };


    const handleFlyToBahirDar = () => {
        if (mapRef.current) {
            mapRef.current.flyTo({
                center: [37.3895, 11.5946],
                zoom: 14,
                pitch: 45,
                duration: 5000,
            });
        }
    };

    return (
        <View style={styles.container}>
            <GebetaMap
                ref={mapRef}
                apiKey="your-api-key-here"
                center={[38.7463, 9.0223]}
                zoom={12}
                onMapClick={handleMapClick}
                style={"https://tiles.gebeta.app/styles/standard/style.json"}
            />

            <View style={styles.buttonContainer}>
                <Button title="✈️ Fly to Bahir Dar" onPress={handleFlyToBahirDar} />
            </View>
        </View>
    );
};


const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    buttonContainer: {
        position: 'absolute',
        top: 60,
        left: 0,
        right: 0,
        alignItems: 'center',
    },
});

export default App;
```

## API Reference

### GebetaMap Props

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `apiKey` | `string` | Yes | Your Gebeta Maps API key |
| `center` | `[number, number]` | Yes | Initial map center coordinates [longitude, latitude] |
| `zoom` | `number` | Yes | Initial zoom level |
| `onMapClick` | `(lngLat: [number, number], event: any) => void` | No | Callback when map is clicked |
| `onMapLoaded` | `() => void` | No | Callback when map finishes loading |
| `blockInteractions` | `boolean` | No | Disable map interactions |
| `style` | `any` | No | Custom styles for the map container |
| `clusteringOptions` | `ClusteringOptions` | No | Options for marker clustering |

### GebetaMapRef Methods

#### Marker Management
- `addImageMarker(lngLat, imageUrl, size, onClick, zIndex, popupHtml)` - Add an image marker
- `addMarker(options)` - Add a basic marker
- `clearMarkers()` - Remove all markers
- `getMarkers()` - Get all current markers

#### Fence Management
- `startFence()` - Start drawing a fence
- `addFencePoint(lngLat, customImage, onClick)` - Add a point to the current fence
- `closeFence()` - Close the current fence
- `clearFence()` - Clear the current fence
- `clearAllFences()` - Clear all fences
- `getFences()` - Get all fences
- `getFencePoints()` - Get current fence points
- `isDrawingFence()` - Check if currently drawing a fence

#### Path Management
- `addPath(path, options)` - Add a path to the map
- `clearPaths()` - Clear all paths

### Fly Control
- `flyTo(options)` – Animate the map camera to a specified location with optional zoom, bearing, pitch, and duration.

#### Clustering
- `addClusteredMarker(marker)` - Add a marker for clustering
- `clearClusteredMarkers()` - Clear all clustered markers
- `updateClustering()` - Update clustering
- `setClusteringEnabled(enabled)` - Enable/disable clustering
- `setClusterImage(imageUrl)` - Set custom cluster image

#### Geocoding
- `geocode(name)` - Geocode an address
- `reverseGeocode(lat, lon)` - Reverse geocode coordinates

#### Directions
- `getDirections(origin, destination, options)` - Get directions between two points
- `convertDirectionsToNavigationRoute(response)` - Convert Gebeta directions response to `NavigationRoute`
- `displayRoute(routeData, options)` - Display a route on the map
- `clearRoute()` - Clear the current route
- `getCurrentRoute()` - Get the current route
- `getRouteSummary()` - Get route summary
- `updateRouteStyle(style)` - Update route styling

#### Navigation
- `startNavigation(route, options)` - Start navigation with a `NavigationRoute`
- `updateNavigationPosition([lng, lat])` - Update position (e.g., from GPS)
- `stopNavigation()` - Stop navigation
- `getNavigationState()` - Get current navigation state
- `isNavigating()` - Check if navigation is active

**Navigation route shape**
```ts
type NavigationRoute = {
  coordinates: [number, number][]; // [lng, lat]
  distance?: number;   // meters
  duration?: number;   // seconds
  instructions?: {
    type: 'turn' | 'straight' | 'arrive' | 'depart';
    direction?: 'left' | 'right' | 'slight-left' | 'slight-right' | 'sharp-left' | 'sharp-right';
    distance: number; // meters
    text: string;
    coordinate: [number, number];
  }[];
};
```

**Using Gebeta Directions response**
The Gebeta API returns:
```json
{
  "msg": "Ok",
  "timetaken": 5102.905,
  "totalDistance": 15308.715,
  "direction": [
    [lng, lat],
    ...
  ]
}
```
Convert and start navigation:
```ts
const res = await mapRef.current?.getDirections(origin, destination);
const route = mapRef.current?.convertDirectionsToNavigationRoute(res);
if (route) {
  mapRef.current?.startNavigation(route, {
    onNavigationUpdate: (state) => mapRef.current?.updateNavigationPosition(/* GPS coords */),
  });
}
```

**GPS tracking**
- The library does **not** bundle a GPS dependency; use your preferred location library (e.g. `@react-native-community/geolocation`) to call `updateNavigationPosition([lng, lat])`.
- On Android, request `ACCESS_FINE_LOCATION`. On iOS, set `NSLocationWhenInUseUsageDescription`.

## Example App

To test the package, navigate to the example and run:

```bash
cd example/GebetaMapsFence
yarn install
yarn android  # or yarn ios
```

## Development

To build the package:

```bash
yarn build
```

## License

MIT