@ingissa/navcore-react-native 1.0.8 → 1.0.10
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/LICENSE +3 -3
- package/README.md +135 -0
- package/dist/index.d.mts +131 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +233 -0
- package/dist/index.mjs +223 -0
- package/package.json +46 -54
- package/dist/core/src/NavCore.d.ts +0 -142
- package/dist/core/src/NavCore.d.ts.map +0 -1
- package/dist/core/src/NavCore.js +0 -390
- package/dist/core/src/bearing/BearingEngine.d.ts +0 -24
- package/dist/core/src/bearing/BearingEngine.d.ts.map +0 -1
- package/dist/core/src/bearing/BearingEngine.js +0 -50
- package/dist/core/src/constants.d.ts +0 -34
- package/dist/core/src/constants.d.ts.map +0 -1
- package/dist/core/src/constants.js +0 -41
- package/dist/core/src/corridor/DeviationDetector.d.ts +0 -33
- package/dist/core/src/corridor/DeviationDetector.d.ts.map +0 -1
- package/dist/core/src/corridor/DeviationDetector.js +0 -83
- package/dist/core/src/corridor/DynamicCorridor.d.ts +0 -13
- package/dist/core/src/corridor/DynamicCorridor.d.ts.map +0 -1
- package/dist/core/src/corridor/DynamicCorridor.js +0 -26
- package/dist/core/src/dead-reckoning/DeadReckoning.d.ts +0 -35
- package/dist/core/src/dead-reckoning/DeadReckoning.d.ts.map +0 -1
- package/dist/core/src/dead-reckoning/DeadReckoning.js +0 -49
- package/dist/core/src/directions/DirectionsProvider.d.ts +0 -70
- package/dist/core/src/directions/DirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/DirectionsProvider.js +0 -7
- package/dist/core/src/directions/OSRMDirectionsProvider.d.ts +0 -26
- package/dist/core/src/directions/OSRMDirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/OSRMDirectionsProvider.js +0 -90
- package/dist/core/src/directions/OpenRouteServiceProvider.d.ts +0 -30
- package/dist/core/src/directions/OpenRouteServiceProvider.d.ts.map +0 -1
- package/dist/core/src/directions/OpenRouteServiceProvider.js +0 -111
- package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts +0 -33
- package/dist/core/src/directions/ValhallaDirectionsProvider.d.ts.map +0 -1
- package/dist/core/src/directions/ValhallaDirectionsProvider.js +0 -155
- package/dist/core/src/eta/ETAEngine.d.ts +0 -61
- package/dist/core/src/eta/ETAEngine.d.ts.map +0 -1
- package/dist/core/src/eta/ETAEngine.js +0 -74
- package/dist/core/src/features.d.ts +0 -76
- package/dist/core/src/features.d.ts.map +0 -1
- package/dist/core/src/features.js +0 -76
- package/dist/core/src/geo/bearing.d.ts +0 -11
- package/dist/core/src/geo/bearing.d.ts.map +0 -1
- package/dist/core/src/geo/bearing.js +0 -25
- package/dist/core/src/geo/cumulative.d.ts +0 -9
- package/dist/core/src/geo/cumulative.d.ts.map +0 -1
- package/dist/core/src/geo/cumulative.js +0 -20
- package/dist/core/src/geo/haversine.d.ts +0 -13
- package/dist/core/src/geo/haversine.d.ts.map +0 -1
- package/dist/core/src/geo/haversine.js +0 -39
- package/dist/core/src/geo/projection.d.ts +0 -7
- package/dist/core/src/geo/projection.d.ts.map +0 -1
- package/dist/core/src/geo/projection.js +0 -17
- package/dist/core/src/geofencing/GeofencingEngine.d.ts +0 -93
- package/dist/core/src/geofencing/GeofencingEngine.d.ts.map +0 -1
- package/dist/core/src/geofencing/GeofencingEngine.js +0 -154
- package/dist/core/src/index.d.ts +0 -66
- package/dist/core/src/index.d.ts.map +0 -1
- package/dist/core/src/index.js +0 -62
- package/dist/core/src/kalman/KalmanFilter2D.d.ts +0 -46
- package/dist/core/src/kalman/KalmanFilter2D.d.ts.map +0 -1
- package/dist/core/src/kalman/KalmanFilter2D.js +0 -77
- package/dist/core/src/license/LicenseManager.d.ts +0 -40
- package/dist/core/src/license/LicenseManager.d.ts.map +0 -1
- package/dist/core/src/license/LicenseManager.js +0 -119
- package/dist/core/src/license/verifyP256Signature.d.ts +0 -2
- package/dist/core/src/license/verifyP256Signature.d.ts.map +0 -1
- package/dist/core/src/license/verifyP256Signature.js +0 -26
- package/dist/core/src/off-route/NavigationFSM.d.ts +0 -42
- package/dist/core/src/off-route/NavigationFSM.d.ts.map +0 -1
- package/dist/core/src/off-route/NavigationFSM.js +0 -56
- package/dist/core/src/off-route/OffRouteFSM.d.ts +0 -70
- package/dist/core/src/off-route/OffRouteFSM.d.ts.map +0 -1
- package/dist/core/src/off-route/OffRouteFSM.js +0 -151
- package/dist/core/src/predictor/RouteOffsetPredictor.d.ts +0 -24
- package/dist/core/src/predictor/RouteOffsetPredictor.d.ts.map +0 -1
- package/dist/core/src/predictor/RouteOffsetPredictor.js +0 -55
- package/dist/core/src/progress/InstructionEditor.d.ts +0 -77
- package/dist/core/src/progress/InstructionEditor.d.ts.map +0 -1
- package/dist/core/src/progress/InstructionEditor.js +0 -151
- package/dist/core/src/progress/InstructionResolver.d.ts +0 -25
- package/dist/core/src/progress/InstructionResolver.d.ts.map +0 -1
- package/dist/core/src/progress/InstructionResolver.js +0 -78
- package/dist/core/src/progress/ProgressTracker.d.ts +0 -12
- package/dist/core/src/progress/ProgressTracker.d.ts.map +0 -1
- package/dist/core/src/progress/ProgressTracker.js +0 -22
- package/dist/core/src/renderer/MapRendererAdapter.d.ts +0 -72
- package/dist/core/src/renderer/MapRendererAdapter.d.ts.map +0 -1
- package/dist/core/src/renderer/MapRendererAdapter.js +0 -19
- package/dist/core/src/route-builder/CustomRouteBuilder.d.ts +0 -83
- package/dist/core/src/route-builder/CustomRouteBuilder.d.ts.map +0 -1
- package/dist/core/src/route-builder/CustomRouteBuilder.js +0 -160
- package/dist/core/src/route-plan/RoutePlan.d.ts +0 -38
- package/dist/core/src/route-plan/RoutePlan.d.ts.map +0 -1
- package/dist/core/src/route-plan/RoutePlan.js +0 -102
- package/dist/core/src/session/NavigationSession.d.ts +0 -81
- package/dist/core/src/session/NavigationSession.d.ts.map +0 -1
- package/dist/core/src/session/NavigationSession.js +0 -115
- package/dist/core/src/snapper/ParallelRoadResolver.d.ts +0 -86
- package/dist/core/src/snapper/ParallelRoadResolver.d.ts.map +0 -1
- package/dist/core/src/snapper/ParallelRoadResolver.js +0 -83
- package/dist/core/src/snapper/RouteSnapper.d.ts +0 -38
- package/dist/core/src/snapper/RouteSnapper.d.ts.map +0 -1
- package/dist/core/src/snapper/RouteSnapper.js +0 -80
- package/dist/core/src/voice/VoiceTriggerEngine.d.ts +0 -80
- package/dist/core/src/voice/VoiceTriggerEngine.d.ts.map +0 -1
- package/dist/core/src/voice/VoiceTriggerEngine.js +0 -108
- package/dist/react-native/src/NavCoreProvider.d.ts +0 -33
- package/dist/react-native/src/NavCoreProvider.d.ts.map +0 -1
- package/dist/react-native/src/NavCoreProvider.js +0 -41
- package/dist/react-native/src/index.d.ts +0 -10
- package/dist/react-native/src/index.d.ts.map +0 -1
- package/dist/react-native/src/index.js +0 -8
- package/dist/react-native/src/useNavCore.d.ts +0 -60
- package/dist/react-native/src/useNavCore.d.ts.map +0 -1
- package/dist/react-native/src/useNavCore.js +0 -119
- package/dist/react-native/src/useNavSelectors.d.ts +0 -42
- package/dist/react-native/src/useNavSelectors.d.ts.map +0 -1
- package/dist/react-native/src/useNavSelectors.js +0 -103
- package/src/NavCoreProvider.tsx +0 -59
- package/src/index.ts +0 -18
- package/src/useNavCore.ts +0 -208
- package/src/useNavSelectors.ts +0 -143
package/LICENSE
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Copyright (c) 2026 Abdelnasser Aitabi. All rights reserved.
|
|
2
|
-
|
|
3
|
-
No license is granted except by separate written agreement.
|
|
1
|
+
Copyright (c) 2026 Abdelnasser Aitabi. All rights reserved.
|
|
2
|
+
|
|
3
|
+
No license is granted except by separate written agreement.
|
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# @ingissa/navcore-react-native
|
|
2
|
+
|
|
3
|
+
[Official Website](https://navcore-web.vercel.app/)
|
|
4
|
+
|
|
5
|
+
> React Native bindings and state selectors for the NavCore navigation engine.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@ingissa/navcore-react-native)
|
|
8
|
+

|
|
9
|
+
[](https://www.typescriptlang.org/)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
`@ingissa/navcore-react-native` provides lightweight, tearing-free React bindings for NavCore. Built on React 18's `useSyncExternalStore`, components subscribe to granular slices of navigation state and only re-render when their specific slice changes.
|
|
16
|
+
|
|
17
|
+
### Key Features
|
|
18
|
+
- **Zero native binary modules**: Pure JavaScript/TypeScript layer that works seamlessly with Expo Go, Expo Prebuild, and bare React Native.
|
|
19
|
+
- **Granular selector hooks**: Prevent full-screen re-renders on high-frequency (1–10 Hz) GPS ticks.
|
|
20
|
+
- **Shared engine context**: Easily share a single `NavCore` engine instance across maps, HUD banners, speedometers, and debug overlays using `NavCoreProvider`.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @ingissa/navcore-react-native @ingissa/navcore-core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Peer Dependencies
|
|
31
|
+
- `@ingissa/navcore-core`: `^1.0.9` (required)
|
|
32
|
+
- `react`: `>=18.0.0` (required)
|
|
33
|
+
- `react-native`: `>=0.72.0` (required)
|
|
34
|
+
- `react-native-maps`: `>=1.0.0` (optional, for applications using React Native Maps)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
### 1. Wrap your navigation screens in `NavCoreProvider`
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import React from 'react';
|
|
44
|
+
import { NavCoreProvider } from '@ingissa/navcore-react-native';
|
|
45
|
+
import { NavigationScreen } from './NavigationScreen';
|
|
46
|
+
|
|
47
|
+
export function App() {
|
|
48
|
+
return (
|
|
49
|
+
<NavCoreProvider options={{ isDev: true }}>
|
|
50
|
+
<NavigationScreen />
|
|
51
|
+
</NavCoreProvider>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Consume granular state in child components
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import React from 'react';
|
|
60
|
+
import { View, Text } from 'react-native';
|
|
61
|
+
import {
|
|
62
|
+
useNavInstruction,
|
|
63
|
+
useNavProgress,
|
|
64
|
+
useNavSpeed,
|
|
65
|
+
useNavIsOffRoute,
|
|
66
|
+
} from '@ingissa/navcore-react-native';
|
|
67
|
+
|
|
68
|
+
export function NavigationHud() {
|
|
69
|
+
const instruction = useNavInstruction();
|
|
70
|
+
const { distanceToDestination, distanceToNextInstruction } = useNavProgress();
|
|
71
|
+
const speed = useNavSpeed();
|
|
72
|
+
const isOffRoute = useNavIsOffRoute();
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<View style={{ padding: 16, backgroundColor: '#111', borderRadius: 8 }}>
|
|
76
|
+
{isOffRoute && <Text style={{ color: 'red' }}>⚠️ Off Route - Recalculating</Text>}
|
|
77
|
+
<Text style={{ color: 'white', fontSize: 18 }}>
|
|
78
|
+
{instruction?.text ?? 'Continue on route'}
|
|
79
|
+
</Text>
|
|
80
|
+
<Text style={{ color: '#aaa' }}>
|
|
81
|
+
In {distanceToNextInstruction != null ? `${Math.round(distanceToNextInstruction)}m` : '—'}
|
|
82
|
+
</Text>
|
|
83
|
+
<Text style={{ color: '#aaa' }}>
|
|
84
|
+
Destination: {distanceToDestination != null ? `${(distanceToDestination / 1000).toFixed(1)}km` : '—'}
|
|
85
|
+
</Text>
|
|
86
|
+
<Text style={{ color: '#4ade80' }}>
|
|
87
|
+
Speed: {Math.round(speed * 3.6)} km/h
|
|
88
|
+
</Text>
|
|
89
|
+
</View>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 3. Custom Selective Re-renders with `useNavSelector`
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { useNavSelector } from '@ingissa/navcore-react-native';
|
|
98
|
+
|
|
99
|
+
// Only re-renders when alertState ('NONE' | 'DEVIATING' | 'RECALCULATING' | 'REJOINING' | 'REJOINED') changes
|
|
100
|
+
export function AlertBadge() {
|
|
101
|
+
const alertState = useNavSelector((state) => state.alertState);
|
|
102
|
+
if (alertState === 'NONE') return null;
|
|
103
|
+
|
|
104
|
+
return <Text>Status: {alertState}</Text>;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Available Hooks
|
|
111
|
+
|
|
112
|
+
| Hook | Returns | Re-render Trigger |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `useNavCoreContext()` | `{ engine: NavCore }` | Context mount |
|
|
115
|
+
| `useNavSelector(selector, customEngine?, isEqual?)` | Selected slice `T` | When `isEqual(prev, next)` returns `false` |
|
|
116
|
+
| `useNavInstruction(customEngine?)` | `NavInstruction \| null` | When upcoming turn text or geometryIndex changes |
|
|
117
|
+
| `useNavAlert(customEngine?)` | `NavCoreState['alertState']` | On deviation or rejoin state transition |
|
|
118
|
+
| `useNavProgress(customEngine?)` | `NavProgressInfo` | On progress index, arrival, or distance change |
|
|
119
|
+
| `useNavIsOffRoute(customEngine?)` | `boolean` | When off-route flag changes |
|
|
120
|
+
| `useNavSpeed(customEngine?)` | `number` (m/s) | On speed update |
|
|
121
|
+
| `useNavCore(props)` | `UseNavCoreReturn` | Complete hook managing full engine lifecycle |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Documentation
|
|
126
|
+
|
|
127
|
+
- [React Native Integration Guide](../../docs/react-native.md)
|
|
128
|
+
- [API Reference](../../docs/api-reference/navcore-react-native.md)
|
|
129
|
+
- [Official Website](https://navcore-web.vercel.app/)
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Licensing
|
|
134
|
+
|
|
135
|
+
Proprietary software. Copyright (c) 2026 Abdelnasser Aitabi. All rights reserved. No license is granted except by separate written agreement.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Coordinate, NavInstruction, NavCoreOptions, NavCoreState, NavCore } from '@ingissa/navcore-core';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* useNavCore — React hook for the NavCore navigation engine.
|
|
7
|
+
*
|
|
8
|
+
* Manages engine lifecycle, GPS → engine → state pipeline,
|
|
9
|
+
* event wiring, and optimized re-render batching.
|
|
10
|
+
*
|
|
11
|
+
* Drop-in replacement for the existing Go4Exams useNavCore hook.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface UseNavCoreProps {
|
|
15
|
+
/** Current GPS coordinate [lng, lat] */
|
|
16
|
+
gpsCoord: Coordinate | null;
|
|
17
|
+
/** GPS bearing in degrees */
|
|
18
|
+
gpsBearing?: number | null;
|
|
19
|
+
/** GPS accuracy in metres */
|
|
20
|
+
gpsAccuracy?: number | null;
|
|
21
|
+
/** GPS timestamp (ms since epoch) */
|
|
22
|
+
gpsTimestamp?: number | null;
|
|
23
|
+
/** Current speed in m/s */
|
|
24
|
+
speed: number;
|
|
25
|
+
/** Route geometry [lng, lat][] */
|
|
26
|
+
routeGeometry: Coordinate[] | null;
|
|
27
|
+
/** Navigation instructions */
|
|
28
|
+
instructions?: NavInstruction[];
|
|
29
|
+
/** Whether navigation has been started by the user */
|
|
30
|
+
isNavigating: boolean;
|
|
31
|
+
/** Engine configuration */
|
|
32
|
+
options?: NavCoreOptions;
|
|
33
|
+
/** Resume navigation at a specific route index (after rejoin) */
|
|
34
|
+
resumeAtIndex?: number | null;
|
|
35
|
+
/** Ref for external camera output (map camera integration) */
|
|
36
|
+
outputRef?: {
|
|
37
|
+
current: {
|
|
38
|
+
coord: Coordinate;
|
|
39
|
+
bearing: number;
|
|
40
|
+
speed: number;
|
|
41
|
+
} | null;
|
|
42
|
+
};
|
|
43
|
+
/** Called when deviation is confirmed */
|
|
44
|
+
onDeviation?: (event: {
|
|
45
|
+
anchorIndex: number;
|
|
46
|
+
ghostCoord: Coordinate;
|
|
47
|
+
}) => void;
|
|
48
|
+
/** Called when rejoin completes */
|
|
49
|
+
onRejoin?: (event: {
|
|
50
|
+
resumeIndex: number;
|
|
51
|
+
}) => void;
|
|
52
|
+
/** Called when an instruction triggers */
|
|
53
|
+
onInstruction?: (instruction: NavInstruction) => void;
|
|
54
|
+
/** Called when arrival is detected */
|
|
55
|
+
onArrival?: () => void;
|
|
56
|
+
/** UI polling rate in Hz (default 30) */
|
|
57
|
+
pollRateHz?: number;
|
|
58
|
+
}
|
|
59
|
+
interface UseNavCoreReturn extends NavCoreState {
|
|
60
|
+
/** The raw NavCore engine instance (for advanced usage) */
|
|
61
|
+
engine: NavCore;
|
|
62
|
+
}
|
|
63
|
+
declare function useNavCore({ gpsCoord, gpsBearing, gpsAccuracy, gpsTimestamp, speed, routeGeometry, instructions, isNavigating, options, resumeAtIndex, outputRef, onDeviation, onRejoin, onInstruction, onArrival, pollRateHz, }: UseNavCoreProps): UseNavCoreReturn;
|
|
64
|
+
|
|
65
|
+
interface NavCoreContextValue {
|
|
66
|
+
engine: NavCore;
|
|
67
|
+
}
|
|
68
|
+
interface NavCoreProviderProps {
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
options?: NavCoreOptions;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Wraps children with a shared NavCore engine instance.
|
|
74
|
+
*
|
|
75
|
+
* ```tsx
|
|
76
|
+
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
77
|
+
* <MapScreen />
|
|
78
|
+
* <InstructionBanner />
|
|
79
|
+
* </NavCoreProvider>
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function NavCoreProvider({ children, options }: NavCoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
83
|
+
/**
|
|
84
|
+
* Access the shared NavCore engine from context.
|
|
85
|
+
* Must be used within a <NavCoreProvider>.
|
|
86
|
+
*/
|
|
87
|
+
declare function useNavCoreContext(): NavCoreContextValue;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Granular selector hooks for NavCore.
|
|
91
|
+
*
|
|
92
|
+
* Built with React 18 `useSyncExternalStore` for flicker-free, tearing-free
|
|
93
|
+
* state subscriptions. Components only re-render when the selected slice changes.
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Generic reactive selector subscribing to NavCore state updates.
|
|
98
|
+
* Only triggers re-renders when the selected value actually changes.
|
|
99
|
+
*/
|
|
100
|
+
declare function useNavSelector<T>(selector: (state: NavCoreState) => T, customEngine?: NavCore, isEqual?: (a: T, b: T) => boolean): T;
|
|
101
|
+
/**
|
|
102
|
+
* Hook to select the current upcoming turn-by-turn navigation instruction.
|
|
103
|
+
* Only re-renders when the instruction changes or triggers.
|
|
104
|
+
*/
|
|
105
|
+
declare function useNavInstruction(customEngine?: NavCore): NavInstruction | null;
|
|
106
|
+
/**
|
|
107
|
+
* Hook to select current alert/deviation state ('NONE' | 'DEVIATING' | 'RECALCULATING' | 'REJOINING' | 'REJOINED').
|
|
108
|
+
* Only re-renders on alert state transitions.
|
|
109
|
+
*/
|
|
110
|
+
declare function useNavAlert(customEngine?: NavCore): NavCoreState['alertState'];
|
|
111
|
+
interface NavProgressInfo {
|
|
112
|
+
distanceToDestination: number | null;
|
|
113
|
+
distanceToNextInstruction: number | null;
|
|
114
|
+
progressIndex: number;
|
|
115
|
+
routeIndex: number;
|
|
116
|
+
hasArrived: boolean;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Hook to select navigation progress and remaining distance metrics.
|
|
120
|
+
*/
|
|
121
|
+
declare function useNavProgress(customEngine?: NavCore): NavProgressInfo;
|
|
122
|
+
/**
|
|
123
|
+
* Hook to select whether the vehicle is currently off-route.
|
|
124
|
+
*/
|
|
125
|
+
declare function useNavIsOffRoute(customEngine?: NavCore): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Hook to select current speed in m/s.
|
|
128
|
+
*/
|
|
129
|
+
declare function useNavSpeed(customEngine?: NavCore): number;
|
|
130
|
+
|
|
131
|
+
export { NavCoreProvider, type NavProgressInfo, type UseNavCoreProps, type UseNavCoreReturn, useNavAlert, useNavCore, useNavCoreContext, useNavInstruction, useNavIsOffRoute, useNavProgress, useNavSelector, useNavSpeed };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Coordinate, NavInstruction, NavCoreOptions, NavCoreState, NavCore } from '@ingissa/navcore-core';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* useNavCore — React hook for the NavCore navigation engine.
|
|
7
|
+
*
|
|
8
|
+
* Manages engine lifecycle, GPS → engine → state pipeline,
|
|
9
|
+
* event wiring, and optimized re-render batching.
|
|
10
|
+
*
|
|
11
|
+
* Drop-in replacement for the existing Go4Exams useNavCore hook.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
interface UseNavCoreProps {
|
|
15
|
+
/** Current GPS coordinate [lng, lat] */
|
|
16
|
+
gpsCoord: Coordinate | null;
|
|
17
|
+
/** GPS bearing in degrees */
|
|
18
|
+
gpsBearing?: number | null;
|
|
19
|
+
/** GPS accuracy in metres */
|
|
20
|
+
gpsAccuracy?: number | null;
|
|
21
|
+
/** GPS timestamp (ms since epoch) */
|
|
22
|
+
gpsTimestamp?: number | null;
|
|
23
|
+
/** Current speed in m/s */
|
|
24
|
+
speed: number;
|
|
25
|
+
/** Route geometry [lng, lat][] */
|
|
26
|
+
routeGeometry: Coordinate[] | null;
|
|
27
|
+
/** Navigation instructions */
|
|
28
|
+
instructions?: NavInstruction[];
|
|
29
|
+
/** Whether navigation has been started by the user */
|
|
30
|
+
isNavigating: boolean;
|
|
31
|
+
/** Engine configuration */
|
|
32
|
+
options?: NavCoreOptions;
|
|
33
|
+
/** Resume navigation at a specific route index (after rejoin) */
|
|
34
|
+
resumeAtIndex?: number | null;
|
|
35
|
+
/** Ref for external camera output (map camera integration) */
|
|
36
|
+
outputRef?: {
|
|
37
|
+
current: {
|
|
38
|
+
coord: Coordinate;
|
|
39
|
+
bearing: number;
|
|
40
|
+
speed: number;
|
|
41
|
+
} | null;
|
|
42
|
+
};
|
|
43
|
+
/** Called when deviation is confirmed */
|
|
44
|
+
onDeviation?: (event: {
|
|
45
|
+
anchorIndex: number;
|
|
46
|
+
ghostCoord: Coordinate;
|
|
47
|
+
}) => void;
|
|
48
|
+
/** Called when rejoin completes */
|
|
49
|
+
onRejoin?: (event: {
|
|
50
|
+
resumeIndex: number;
|
|
51
|
+
}) => void;
|
|
52
|
+
/** Called when an instruction triggers */
|
|
53
|
+
onInstruction?: (instruction: NavInstruction) => void;
|
|
54
|
+
/** Called when arrival is detected */
|
|
55
|
+
onArrival?: () => void;
|
|
56
|
+
/** UI polling rate in Hz (default 30) */
|
|
57
|
+
pollRateHz?: number;
|
|
58
|
+
}
|
|
59
|
+
interface UseNavCoreReturn extends NavCoreState {
|
|
60
|
+
/** The raw NavCore engine instance (for advanced usage) */
|
|
61
|
+
engine: NavCore;
|
|
62
|
+
}
|
|
63
|
+
declare function useNavCore({ gpsCoord, gpsBearing, gpsAccuracy, gpsTimestamp, speed, routeGeometry, instructions, isNavigating, options, resumeAtIndex, outputRef, onDeviation, onRejoin, onInstruction, onArrival, pollRateHz, }: UseNavCoreProps): UseNavCoreReturn;
|
|
64
|
+
|
|
65
|
+
interface NavCoreContextValue {
|
|
66
|
+
engine: NavCore;
|
|
67
|
+
}
|
|
68
|
+
interface NavCoreProviderProps {
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
options?: NavCoreOptions;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Wraps children with a shared NavCore engine instance.
|
|
74
|
+
*
|
|
75
|
+
* ```tsx
|
|
76
|
+
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
77
|
+
* <MapScreen />
|
|
78
|
+
* <InstructionBanner />
|
|
79
|
+
* </NavCoreProvider>
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function NavCoreProvider({ children, options }: NavCoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
83
|
+
/**
|
|
84
|
+
* Access the shared NavCore engine from context.
|
|
85
|
+
* Must be used within a <NavCoreProvider>.
|
|
86
|
+
*/
|
|
87
|
+
declare function useNavCoreContext(): NavCoreContextValue;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Granular selector hooks for NavCore.
|
|
91
|
+
*
|
|
92
|
+
* Built with React 18 `useSyncExternalStore` for flicker-free, tearing-free
|
|
93
|
+
* state subscriptions. Components only re-render when the selected slice changes.
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Generic reactive selector subscribing to NavCore state updates.
|
|
98
|
+
* Only triggers re-renders when the selected value actually changes.
|
|
99
|
+
*/
|
|
100
|
+
declare function useNavSelector<T>(selector: (state: NavCoreState) => T, customEngine?: NavCore, isEqual?: (a: T, b: T) => boolean): T;
|
|
101
|
+
/**
|
|
102
|
+
* Hook to select the current upcoming turn-by-turn navigation instruction.
|
|
103
|
+
* Only re-renders when the instruction changes or triggers.
|
|
104
|
+
*/
|
|
105
|
+
declare function useNavInstruction(customEngine?: NavCore): NavInstruction | null;
|
|
106
|
+
/**
|
|
107
|
+
* Hook to select current alert/deviation state ('NONE' | 'DEVIATING' | 'RECALCULATING' | 'REJOINING' | 'REJOINED').
|
|
108
|
+
* Only re-renders on alert state transitions.
|
|
109
|
+
*/
|
|
110
|
+
declare function useNavAlert(customEngine?: NavCore): NavCoreState['alertState'];
|
|
111
|
+
interface NavProgressInfo {
|
|
112
|
+
distanceToDestination: number | null;
|
|
113
|
+
distanceToNextInstruction: number | null;
|
|
114
|
+
progressIndex: number;
|
|
115
|
+
routeIndex: number;
|
|
116
|
+
hasArrived: boolean;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Hook to select navigation progress and remaining distance metrics.
|
|
120
|
+
*/
|
|
121
|
+
declare function useNavProgress(customEngine?: NavCore): NavProgressInfo;
|
|
122
|
+
/**
|
|
123
|
+
* Hook to select whether the vehicle is currently off-route.
|
|
124
|
+
*/
|
|
125
|
+
declare function useNavIsOffRoute(customEngine?: NavCore): boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Hook to select current speed in m/s.
|
|
128
|
+
*/
|
|
129
|
+
declare function useNavSpeed(customEngine?: NavCore): number;
|
|
130
|
+
|
|
131
|
+
export { NavCoreProvider, type NavProgressInfo, type UseNavCoreProps, type UseNavCoreReturn, useNavAlert, useNavCore, useNavCoreContext, useNavInstruction, useNavIsOffRoute, useNavProgress, useNavSelector, useNavSpeed };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var navcoreCore = require('@ingissa/navcore-core');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
// src/useNavCore.ts
|
|
8
|
+
function useNavCore({
|
|
9
|
+
gpsCoord,
|
|
10
|
+
gpsBearing,
|
|
11
|
+
gpsAccuracy,
|
|
12
|
+
gpsTimestamp,
|
|
13
|
+
speed,
|
|
14
|
+
routeGeometry,
|
|
15
|
+
instructions,
|
|
16
|
+
isNavigating,
|
|
17
|
+
options,
|
|
18
|
+
resumeAtIndex,
|
|
19
|
+
outputRef,
|
|
20
|
+
onDeviation,
|
|
21
|
+
onRejoin,
|
|
22
|
+
onInstruction,
|
|
23
|
+
onArrival,
|
|
24
|
+
pollRateHz = 30
|
|
25
|
+
}) {
|
|
26
|
+
const navRef = react.useRef(null);
|
|
27
|
+
if (!navRef.current) {
|
|
28
|
+
navRef.current = new navcoreCore.NavCore(options);
|
|
29
|
+
}
|
|
30
|
+
const engine = navRef.current;
|
|
31
|
+
const [state, setState] = react.useState(() => engine.getState());
|
|
32
|
+
react.useEffect(() => {
|
|
33
|
+
if (!onDeviation) return;
|
|
34
|
+
const handler = (data) => onDeviation(data);
|
|
35
|
+
engine.on("deviation", handler);
|
|
36
|
+
return () => {
|
|
37
|
+
engine.off("deviation", handler);
|
|
38
|
+
};
|
|
39
|
+
}, [engine, onDeviation]);
|
|
40
|
+
react.useEffect(() => {
|
|
41
|
+
if (!onRejoin) return;
|
|
42
|
+
const handler = (data) => onRejoin(data);
|
|
43
|
+
engine.on("rejoined", handler);
|
|
44
|
+
return () => {
|
|
45
|
+
engine.off("rejoined", handler);
|
|
46
|
+
};
|
|
47
|
+
}, [engine, onRejoin]);
|
|
48
|
+
react.useEffect(() => {
|
|
49
|
+
if (!onInstruction) return;
|
|
50
|
+
const handler = (data) => onInstruction(data);
|
|
51
|
+
engine.on("instruction", handler);
|
|
52
|
+
return () => {
|
|
53
|
+
engine.off("instruction", handler);
|
|
54
|
+
};
|
|
55
|
+
}, [engine, onInstruction]);
|
|
56
|
+
react.useEffect(() => {
|
|
57
|
+
if (!onArrival) return;
|
|
58
|
+
const handler = () => onArrival();
|
|
59
|
+
engine.on("arrival", handler);
|
|
60
|
+
return () => {
|
|
61
|
+
engine.off("arrival", handler);
|
|
62
|
+
};
|
|
63
|
+
}, [engine, onArrival]);
|
|
64
|
+
react.useEffect(() => {
|
|
65
|
+
if (routeGeometry && routeGeometry.length >= 2) {
|
|
66
|
+
engine.setRoute(routeGeometry, instructions);
|
|
67
|
+
}
|
|
68
|
+
}, [engine, routeGeometry]);
|
|
69
|
+
react.useEffect(() => {
|
|
70
|
+
if (instructions && instructions.length > 0 && routeGeometry && routeGeometry.length >= 2) {
|
|
71
|
+
engine.setRoute(routeGeometry, instructions);
|
|
72
|
+
}
|
|
73
|
+
}, [engine, instructions]);
|
|
74
|
+
react.useEffect(() => {
|
|
75
|
+
if (!gpsCoord || !isNavigating) return;
|
|
76
|
+
const gpsUpdate = {
|
|
77
|
+
coord: gpsCoord,
|
|
78
|
+
accuracy: gpsAccuracy ?? null,
|
|
79
|
+
bearing: gpsBearing ?? null,
|
|
80
|
+
speed,
|
|
81
|
+
timestamp: gpsTimestamp ?? Date.now()
|
|
82
|
+
};
|
|
83
|
+
const nextState = engine.update(gpsUpdate);
|
|
84
|
+
if (outputRef) {
|
|
85
|
+
outputRef.current = {
|
|
86
|
+
coord: nextState.snappedCoord ?? gpsCoord,
|
|
87
|
+
bearing: nextState.bearing,
|
|
88
|
+
speed: nextState.currentSpeed
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}, [engine, gpsCoord, gpsAccuracy, gpsBearing, gpsTimestamp, speed, isNavigating, outputRef]);
|
|
92
|
+
react.useEffect(() => {
|
|
93
|
+
if (isNavigating) {
|
|
94
|
+
engine.startNavigation();
|
|
95
|
+
}
|
|
96
|
+
}, [engine, isNavigating]);
|
|
97
|
+
react.useEffect(() => {
|
|
98
|
+
if (!isNavigating) return;
|
|
99
|
+
const handleUpdate = (updatedState) => {
|
|
100
|
+
setState(updatedState);
|
|
101
|
+
};
|
|
102
|
+
engine.on("update", handleUpdate);
|
|
103
|
+
setState(engine.getState());
|
|
104
|
+
return () => {
|
|
105
|
+
engine.off("update", handleUpdate);
|
|
106
|
+
};
|
|
107
|
+
}, [engine, isNavigating]);
|
|
108
|
+
react.useEffect(() => {
|
|
109
|
+
return () => {
|
|
110
|
+
engine.destroy();
|
|
111
|
+
navRef.current = null;
|
|
112
|
+
};
|
|
113
|
+
}, [engine]);
|
|
114
|
+
return react.useMemo(() => ({
|
|
115
|
+
...state,
|
|
116
|
+
engine
|
|
117
|
+
}), [state, engine]);
|
|
118
|
+
}
|
|
119
|
+
var NavCoreContext = react.createContext(null);
|
|
120
|
+
function NavCoreProvider({ children, options }) {
|
|
121
|
+
const engineRef = react.useRef(null);
|
|
122
|
+
if (!engineRef.current) {
|
|
123
|
+
engineRef.current = new navcoreCore.NavCore(options);
|
|
124
|
+
}
|
|
125
|
+
const value = react.useMemo(() => ({
|
|
126
|
+
engine: engineRef.current
|
|
127
|
+
}), []);
|
|
128
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NavCoreContext.Provider, { value, children });
|
|
129
|
+
}
|
|
130
|
+
function useNavCoreContext() {
|
|
131
|
+
const ctx = react.useContext(NavCoreContext);
|
|
132
|
+
if (!ctx) {
|
|
133
|
+
throw new Error("useNavCoreContext must be used within a <NavCoreProvider>");
|
|
134
|
+
}
|
|
135
|
+
return ctx;
|
|
136
|
+
}
|
|
137
|
+
function useNavSelector(selector, customEngine, isEqual = Object.is) {
|
|
138
|
+
let contextEngine;
|
|
139
|
+
try {
|
|
140
|
+
contextEngine = useNavCoreContext().engine;
|
|
141
|
+
} catch {
|
|
142
|
+
contextEngine = void 0;
|
|
143
|
+
}
|
|
144
|
+
const engine = customEngine ?? contextEngine;
|
|
145
|
+
if (!engine) {
|
|
146
|
+
throw new Error("useNavSelector must be provided an engine or used within a NavCoreProvider");
|
|
147
|
+
}
|
|
148
|
+
const lastSelectedRef = react.useRef(void 0);
|
|
149
|
+
const lastStateRef = react.useRef(void 0);
|
|
150
|
+
const getSnapshot = react.useCallback(() => {
|
|
151
|
+
const currentState = engine.getState();
|
|
152
|
+
if (lastStateRef.current === currentState && lastSelectedRef.current !== void 0) {
|
|
153
|
+
return lastSelectedRef.current;
|
|
154
|
+
}
|
|
155
|
+
const nextSelected = selector(currentState);
|
|
156
|
+
if (lastSelectedRef.current !== void 0 && isEqual(lastSelectedRef.current, nextSelected)) {
|
|
157
|
+
return lastSelectedRef.current;
|
|
158
|
+
}
|
|
159
|
+
lastStateRef.current = currentState;
|
|
160
|
+
lastSelectedRef.current = nextSelected;
|
|
161
|
+
return nextSelected;
|
|
162
|
+
}, [engine, selector, isEqual]);
|
|
163
|
+
const subscribe = react.useCallback((onStoreChange) => {
|
|
164
|
+
engine.on("update", onStoreChange);
|
|
165
|
+
return () => {
|
|
166
|
+
engine.off("update", onStoreChange);
|
|
167
|
+
};
|
|
168
|
+
}, [engine]);
|
|
169
|
+
return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
170
|
+
}
|
|
171
|
+
function useNavInstruction(customEngine) {
|
|
172
|
+
return useNavSelector(
|
|
173
|
+
(state) => {
|
|
174
|
+
if (state.nextInstructionIndex === null) return null;
|
|
175
|
+
let engine = customEngine;
|
|
176
|
+
if (!engine) {
|
|
177
|
+
try {
|
|
178
|
+
engine = useNavCoreContext().engine;
|
|
179
|
+
} catch {
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!engine) return null;
|
|
183
|
+
const list = engine.getInstructions();
|
|
184
|
+
return list[state.nextInstructionIndex] ?? null;
|
|
185
|
+
},
|
|
186
|
+
customEngine,
|
|
187
|
+
(a, b) => a === b || a?.geometryIndex === b?.geometryIndex && a?.instruction === b?.instruction
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
function useNavAlert(customEngine) {
|
|
191
|
+
return useNavSelector(
|
|
192
|
+
(state) => state.alertState,
|
|
193
|
+
customEngine,
|
|
194
|
+
Object.is
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
function useNavProgress(customEngine) {
|
|
198
|
+
return useNavSelector(
|
|
199
|
+
(state) => ({
|
|
200
|
+
distanceToDestination: state.distanceToDestination,
|
|
201
|
+
distanceToNextInstruction: state.distanceToNextInstruction,
|
|
202
|
+
progressIndex: state.progressIndex,
|
|
203
|
+
routeIndex: state.routeIndex,
|
|
204
|
+
hasArrived: state.hasArrived
|
|
205
|
+
}),
|
|
206
|
+
customEngine,
|
|
207
|
+
(a, b) => a.distanceToDestination === b.distanceToDestination && a.distanceToNextInstruction === b.distanceToNextInstruction && a.progressIndex === b.progressIndex && a.routeIndex === b.routeIndex && a.hasArrived === b.hasArrived
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
function useNavIsOffRoute(customEngine) {
|
|
211
|
+
return useNavSelector(
|
|
212
|
+
(state) => state.isOffRoute,
|
|
213
|
+
customEngine,
|
|
214
|
+
Object.is
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
function useNavSpeed(customEngine) {
|
|
218
|
+
return useNavSelector(
|
|
219
|
+
(state) => state.currentSpeed,
|
|
220
|
+
customEngine,
|
|
221
|
+
Object.is
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
exports.NavCoreProvider = NavCoreProvider;
|
|
226
|
+
exports.useNavAlert = useNavAlert;
|
|
227
|
+
exports.useNavCore = useNavCore;
|
|
228
|
+
exports.useNavCoreContext = useNavCoreContext;
|
|
229
|
+
exports.useNavInstruction = useNavInstruction;
|
|
230
|
+
exports.useNavIsOffRoute = useNavIsOffRoute;
|
|
231
|
+
exports.useNavProgress = useNavProgress;
|
|
232
|
+
exports.useNavSelector = useNavSelector;
|
|
233
|
+
exports.useNavSpeed = useNavSpeed;
|