@ingissa/navcore-react-native 1.0.3 → 1.0.4
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/dist/{useNavCore.d.ts → index.d.mts} +34 -5
- package/dist/index.d.ts +84 -6
- package/dist/index.js +161 -7
- package/dist/index.mjs +157 -0
- package/package.json +5 -5
- package/dist/NavCoreProvider.d.ts +0 -33
- package/dist/NavCoreProvider.d.ts.map +0 -1
- package/dist/NavCoreProvider.js +0 -41
- package/dist/index.d.ts.map +0 -1
- package/dist/useNavCore.d.ts.map +0 -1
- package/dist/useNavCore.js +0 -145
|
@@ -1,3 +1,7 @@
|
|
|
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
|
+
|
|
1
5
|
/**
|
|
2
6
|
* useNavCore — React hook for the NavCore navigation engine.
|
|
3
7
|
*
|
|
@@ -6,8 +10,8 @@
|
|
|
6
10
|
*
|
|
7
11
|
* Drop-in replacement for the existing Go4Exams useNavCore hook.
|
|
8
12
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
interface UseNavCoreProps {
|
|
11
15
|
/** Current GPS coordinate [lng, lat] */
|
|
12
16
|
gpsCoord: Coordinate | null;
|
|
13
17
|
/** GPS bearing in degrees */
|
|
@@ -50,9 +54,34 @@ export interface UseNavCoreProps {
|
|
|
50
54
|
/** UI polling rate in Hz (default 30) */
|
|
51
55
|
pollRateHz?: number;
|
|
52
56
|
}
|
|
53
|
-
|
|
57
|
+
interface UseNavCoreReturn extends NavCoreState {
|
|
54
58
|
/** The raw NavCore engine instance (for advanced usage) */
|
|
55
59
|
engine: NavCore;
|
|
56
60
|
}
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
declare function useNavCore({ gpsCoord, gpsBearing, gpsAccuracy, gpsTimestamp, speed, routeGeometry, instructions, isNavigating, options, resumeAtIndex, outputRef, onDeviation, onRejoin, onInstruction, onArrival, pollRateHz, }: UseNavCoreProps): UseNavCoreReturn;
|
|
62
|
+
|
|
63
|
+
interface NavCoreContextValue {
|
|
64
|
+
engine: NavCore;
|
|
65
|
+
}
|
|
66
|
+
interface NavCoreProviderProps {
|
|
67
|
+
children: ReactNode;
|
|
68
|
+
options?: NavCoreOptions;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wraps children with a shared NavCore engine instance.
|
|
72
|
+
*
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
75
|
+
* <MapScreen />
|
|
76
|
+
* <InstructionBanner />
|
|
77
|
+
* </NavCoreProvider>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function NavCoreProvider({ children, options }: NavCoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
81
|
+
/**
|
|
82
|
+
* Access the shared NavCore engine from context.
|
|
83
|
+
* Must be used within a <NavCoreProvider>.
|
|
84
|
+
*/
|
|
85
|
+
declare function useNavCoreContext(): NavCoreContextValue;
|
|
86
|
+
|
|
87
|
+
export { NavCoreProvider, type UseNavCoreProps, type UseNavCoreReturn, useNavCore, useNavCoreContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,87 @@
|
|
|
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
|
+
|
|
1
5
|
/**
|
|
2
|
-
*
|
|
6
|
+
* useNavCore — React hook for the NavCore navigation engine.
|
|
3
7
|
*
|
|
4
|
-
*
|
|
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?: React.MutableRefObject<{
|
|
37
|
+
coord: Coordinate;
|
|
38
|
+
bearing: number;
|
|
39
|
+
speed: number;
|
|
40
|
+
} | null>;
|
|
41
|
+
/** Called when deviation is confirmed */
|
|
42
|
+
onDeviation?: (event: {
|
|
43
|
+
anchorIndex: number;
|
|
44
|
+
ghostCoord: Coordinate;
|
|
45
|
+
}) => void;
|
|
46
|
+
/** Called when rejoin completes */
|
|
47
|
+
onRejoin?: (event: {
|
|
48
|
+
resumeIndex: number;
|
|
49
|
+
}) => void;
|
|
50
|
+
/** Called when an instruction triggers */
|
|
51
|
+
onInstruction?: (instruction: NavInstruction) => void;
|
|
52
|
+
/** Called when arrival is detected */
|
|
53
|
+
onArrival?: () => void;
|
|
54
|
+
/** UI polling rate in Hz (default 30) */
|
|
55
|
+
pollRateHz?: number;
|
|
56
|
+
}
|
|
57
|
+
interface UseNavCoreReturn extends NavCoreState {
|
|
58
|
+
/** The raw NavCore engine instance (for advanced usage) */
|
|
59
|
+
engine: NavCore;
|
|
60
|
+
}
|
|
61
|
+
declare function useNavCore({ gpsCoord, gpsBearing, gpsAccuracy, gpsTimestamp, speed, routeGeometry, instructions, isNavigating, options, resumeAtIndex, outputRef, onDeviation, onRejoin, onInstruction, onArrival, pollRateHz, }: UseNavCoreProps): UseNavCoreReturn;
|
|
62
|
+
|
|
63
|
+
interface NavCoreContextValue {
|
|
64
|
+
engine: NavCore;
|
|
65
|
+
}
|
|
66
|
+
interface NavCoreProviderProps {
|
|
67
|
+
children: ReactNode;
|
|
68
|
+
options?: NavCoreOptions;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wraps children with a shared NavCore engine instance.
|
|
72
|
+
*
|
|
73
|
+
* ```tsx
|
|
74
|
+
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
75
|
+
* <MapScreen />
|
|
76
|
+
* <InstructionBanner />
|
|
77
|
+
* </NavCoreProvider>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function NavCoreProvider({ children, options }: NavCoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
81
|
+
/**
|
|
82
|
+
* Access the shared NavCore engine from context.
|
|
83
|
+
* Must be used within a <NavCoreProvider>.
|
|
5
84
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export { NavCoreProvider, useNavCoreContext }
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
|
85
|
+
declare function useNavCoreContext(): NavCoreContextValue;
|
|
86
|
+
|
|
87
|
+
export { NavCoreProvider, type UseNavCoreProps, type UseNavCoreReturn, useNavCore, useNavCoreContext };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,161 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
setState(engine.getState());
|
|
68
|
+
}
|
|
69
|
+
}, [engine, routeGeometry, instructions]);
|
|
70
|
+
react.useEffect(() => {
|
|
71
|
+
if (instructions && instructions.length > 0 && routeGeometry && routeGeometry.length >= 2) {
|
|
72
|
+
engine.setRoute(routeGeometry, instructions);
|
|
73
|
+
}
|
|
74
|
+
}, [engine, instructions]);
|
|
75
|
+
react.useEffect(() => {
|
|
76
|
+
if (!gpsCoord || !isNavigating) return;
|
|
77
|
+
const gpsUpdate = {
|
|
78
|
+
coord: gpsCoord,
|
|
79
|
+
accuracy: gpsAccuracy ?? null,
|
|
80
|
+
bearing: gpsBearing ?? null,
|
|
81
|
+
speed,
|
|
82
|
+
timestamp: gpsTimestamp ?? Date.now()
|
|
83
|
+
};
|
|
84
|
+
setState(engine.update(gpsUpdate));
|
|
85
|
+
}, [engine, gpsCoord, gpsAccuracy, gpsBearing, gpsTimestamp, speed, isNavigating]);
|
|
86
|
+
react.useEffect(() => {
|
|
87
|
+
if (isNavigating) {
|
|
88
|
+
engine.startNavigation();
|
|
89
|
+
setState(engine.getState());
|
|
90
|
+
}
|
|
91
|
+
}, [engine, isNavigating]);
|
|
92
|
+
react.useEffect(() => {
|
|
93
|
+
if (!isNavigating) return;
|
|
94
|
+
const lastRef = {
|
|
95
|
+
snapped: [0, 0],
|
|
96
|
+
bearing: 0,
|
|
97
|
+
raw: [0, 0]
|
|
98
|
+
};
|
|
99
|
+
const intervalMs = Math.round(1e3 / pollRateHz);
|
|
100
|
+
const poll = () => {
|
|
101
|
+
const live = engine.getState();
|
|
102
|
+
let changed = false;
|
|
103
|
+
if (Math.abs(live.bearing - lastRef.bearing) > 0.1) {
|
|
104
|
+
lastRef.bearing = live.bearing;
|
|
105
|
+
changed = true;
|
|
106
|
+
}
|
|
107
|
+
if (live.snappedCoord && (live.snappedCoord[0] !== lastRef.snapped[0] || live.snappedCoord[1] !== lastRef.snapped[1])) {
|
|
108
|
+
lastRef.snapped = [live.snappedCoord[0], live.snappedCoord[1]];
|
|
109
|
+
changed = true;
|
|
110
|
+
}
|
|
111
|
+
if (live.rawGpsCoord && (live.rawGpsCoord[0] !== lastRef.raw[0] || live.rawGpsCoord[1] !== lastRef.raw[1])) {
|
|
112
|
+
lastRef.raw = [live.rawGpsCoord[0], live.rawGpsCoord[1]];
|
|
113
|
+
changed = true;
|
|
114
|
+
}
|
|
115
|
+
if (changed) {
|
|
116
|
+
setState(live);
|
|
117
|
+
}
|
|
118
|
+
if (outputRef?.current !== void 0) {
|
|
119
|
+
outputRef.current = {
|
|
120
|
+
coord: live.snappedCoord ?? lastRef.snapped,
|
|
121
|
+
bearing: live.bearing,
|
|
122
|
+
speed: live.currentSpeed
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const id = setInterval(poll, intervalMs);
|
|
127
|
+
return () => clearInterval(id);
|
|
128
|
+
}, [engine, isNavigating, pollRateHz, outputRef]);
|
|
129
|
+
react.useEffect(() => {
|
|
130
|
+
return () => {
|
|
131
|
+
engine.destroy();
|
|
132
|
+
navRef.current = null;
|
|
133
|
+
};
|
|
134
|
+
}, [engine]);
|
|
135
|
+
return react.useMemo(() => ({
|
|
136
|
+
...state,
|
|
137
|
+
engine
|
|
138
|
+
}), [state, engine]);
|
|
139
|
+
}
|
|
140
|
+
var NavCoreContext = react.createContext(null);
|
|
141
|
+
function NavCoreProvider({ children, options }) {
|
|
142
|
+
const engineRef = react.useRef(null);
|
|
143
|
+
if (!engineRef.current) {
|
|
144
|
+
engineRef.current = new navcoreCore.NavCore(options);
|
|
145
|
+
}
|
|
146
|
+
const value = react.useMemo(() => ({
|
|
147
|
+
engine: engineRef.current
|
|
148
|
+
}), []);
|
|
149
|
+
return /* @__PURE__ */ jsxRuntime.jsx(NavCoreContext.Provider, { value, children });
|
|
150
|
+
}
|
|
151
|
+
function useNavCoreContext() {
|
|
152
|
+
const ctx = react.useContext(NavCoreContext);
|
|
153
|
+
if (!ctx) {
|
|
154
|
+
throw new Error("useNavCoreContext must be used within a <NavCoreProvider>");
|
|
155
|
+
}
|
|
156
|
+
return ctx;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
exports.NavCoreProvider = NavCoreProvider;
|
|
160
|
+
exports.useNavCore = useNavCore;
|
|
161
|
+
exports.useNavCoreContext = useNavCoreContext;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { createContext, useRef, useState, useEffect, useMemo, useContext } from 'react';
|
|
2
|
+
import { NavCore } from '@ingissa/navcore-core';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/useNavCore.ts
|
|
6
|
+
function useNavCore({
|
|
7
|
+
gpsCoord,
|
|
8
|
+
gpsBearing,
|
|
9
|
+
gpsAccuracy,
|
|
10
|
+
gpsTimestamp,
|
|
11
|
+
speed,
|
|
12
|
+
routeGeometry,
|
|
13
|
+
instructions,
|
|
14
|
+
isNavigating,
|
|
15
|
+
options,
|
|
16
|
+
resumeAtIndex,
|
|
17
|
+
outputRef,
|
|
18
|
+
onDeviation,
|
|
19
|
+
onRejoin,
|
|
20
|
+
onInstruction,
|
|
21
|
+
onArrival,
|
|
22
|
+
pollRateHz = 30
|
|
23
|
+
}) {
|
|
24
|
+
const navRef = useRef(null);
|
|
25
|
+
if (!navRef.current) {
|
|
26
|
+
navRef.current = new NavCore(options);
|
|
27
|
+
}
|
|
28
|
+
const engine = navRef.current;
|
|
29
|
+
const [state, setState] = useState(() => engine.getState());
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!onDeviation) return;
|
|
32
|
+
const handler = (data) => onDeviation(data);
|
|
33
|
+
engine.on("deviation", handler);
|
|
34
|
+
return () => {
|
|
35
|
+
engine.off("deviation", handler);
|
|
36
|
+
};
|
|
37
|
+
}, [engine, onDeviation]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!onRejoin) return;
|
|
40
|
+
const handler = (data) => onRejoin(data);
|
|
41
|
+
engine.on("rejoined", handler);
|
|
42
|
+
return () => {
|
|
43
|
+
engine.off("rejoined", handler);
|
|
44
|
+
};
|
|
45
|
+
}, [engine, onRejoin]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!onInstruction) return;
|
|
48
|
+
const handler = (data) => onInstruction(data);
|
|
49
|
+
engine.on("instruction", handler);
|
|
50
|
+
return () => {
|
|
51
|
+
engine.off("instruction", handler);
|
|
52
|
+
};
|
|
53
|
+
}, [engine, onInstruction]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!onArrival) return;
|
|
56
|
+
const handler = () => onArrival();
|
|
57
|
+
engine.on("arrival", handler);
|
|
58
|
+
return () => {
|
|
59
|
+
engine.off("arrival", handler);
|
|
60
|
+
};
|
|
61
|
+
}, [engine, onArrival]);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (routeGeometry && routeGeometry.length >= 2) {
|
|
64
|
+
engine.setRoute(routeGeometry, instructions);
|
|
65
|
+
setState(engine.getState());
|
|
66
|
+
}
|
|
67
|
+
}, [engine, routeGeometry, instructions]);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (instructions && instructions.length > 0 && routeGeometry && routeGeometry.length >= 2) {
|
|
70
|
+
engine.setRoute(routeGeometry, instructions);
|
|
71
|
+
}
|
|
72
|
+
}, [engine, instructions]);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (!gpsCoord || !isNavigating) return;
|
|
75
|
+
const gpsUpdate = {
|
|
76
|
+
coord: gpsCoord,
|
|
77
|
+
accuracy: gpsAccuracy ?? null,
|
|
78
|
+
bearing: gpsBearing ?? null,
|
|
79
|
+
speed,
|
|
80
|
+
timestamp: gpsTimestamp ?? Date.now()
|
|
81
|
+
};
|
|
82
|
+
setState(engine.update(gpsUpdate));
|
|
83
|
+
}, [engine, gpsCoord, gpsAccuracy, gpsBearing, gpsTimestamp, speed, isNavigating]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (isNavigating) {
|
|
86
|
+
engine.startNavigation();
|
|
87
|
+
setState(engine.getState());
|
|
88
|
+
}
|
|
89
|
+
}, [engine, isNavigating]);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!isNavigating) return;
|
|
92
|
+
const lastRef = {
|
|
93
|
+
snapped: [0, 0],
|
|
94
|
+
bearing: 0,
|
|
95
|
+
raw: [0, 0]
|
|
96
|
+
};
|
|
97
|
+
const intervalMs = Math.round(1e3 / pollRateHz);
|
|
98
|
+
const poll = () => {
|
|
99
|
+
const live = engine.getState();
|
|
100
|
+
let changed = false;
|
|
101
|
+
if (Math.abs(live.bearing - lastRef.bearing) > 0.1) {
|
|
102
|
+
lastRef.bearing = live.bearing;
|
|
103
|
+
changed = true;
|
|
104
|
+
}
|
|
105
|
+
if (live.snappedCoord && (live.snappedCoord[0] !== lastRef.snapped[0] || live.snappedCoord[1] !== lastRef.snapped[1])) {
|
|
106
|
+
lastRef.snapped = [live.snappedCoord[0], live.snappedCoord[1]];
|
|
107
|
+
changed = true;
|
|
108
|
+
}
|
|
109
|
+
if (live.rawGpsCoord && (live.rawGpsCoord[0] !== lastRef.raw[0] || live.rawGpsCoord[1] !== lastRef.raw[1])) {
|
|
110
|
+
lastRef.raw = [live.rawGpsCoord[0], live.rawGpsCoord[1]];
|
|
111
|
+
changed = true;
|
|
112
|
+
}
|
|
113
|
+
if (changed) {
|
|
114
|
+
setState(live);
|
|
115
|
+
}
|
|
116
|
+
if (outputRef?.current !== void 0) {
|
|
117
|
+
outputRef.current = {
|
|
118
|
+
coord: live.snappedCoord ?? lastRef.snapped,
|
|
119
|
+
bearing: live.bearing,
|
|
120
|
+
speed: live.currentSpeed
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const id = setInterval(poll, intervalMs);
|
|
125
|
+
return () => clearInterval(id);
|
|
126
|
+
}, [engine, isNavigating, pollRateHz, outputRef]);
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
return () => {
|
|
129
|
+
engine.destroy();
|
|
130
|
+
navRef.current = null;
|
|
131
|
+
};
|
|
132
|
+
}, [engine]);
|
|
133
|
+
return useMemo(() => ({
|
|
134
|
+
...state,
|
|
135
|
+
engine
|
|
136
|
+
}), [state, engine]);
|
|
137
|
+
}
|
|
138
|
+
var NavCoreContext = createContext(null);
|
|
139
|
+
function NavCoreProvider({ children, options }) {
|
|
140
|
+
const engineRef = useRef(null);
|
|
141
|
+
if (!engineRef.current) {
|
|
142
|
+
engineRef.current = new NavCore(options);
|
|
143
|
+
}
|
|
144
|
+
const value = useMemo(() => ({
|
|
145
|
+
engine: engineRef.current
|
|
146
|
+
}), []);
|
|
147
|
+
return /* @__PURE__ */ jsx(NavCoreContext.Provider, { value, children });
|
|
148
|
+
}
|
|
149
|
+
function useNavCoreContext() {
|
|
150
|
+
const ctx = useContext(NavCoreContext);
|
|
151
|
+
if (!ctx) {
|
|
152
|
+
throw new Error("useNavCoreContext must be used within a <NavCoreProvider>");
|
|
153
|
+
}
|
|
154
|
+
return ctx;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export { NavCoreProvider, useNavCore, useNavCoreContext };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingissa/navcore-react-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "React Native bindings for the NavCore navigation engine.",
|
|
5
5
|
"author": "Ingissa <8abnav@gmail.com>",
|
|
6
6
|
"license": "Commercial",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"types": "dist/index.d.ts",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
20
21
|
"import": "./dist/index.mjs",
|
|
21
|
-
"require": "./dist/index.js"
|
|
22
|
-
"types": "./dist/index.d.ts"
|
|
22
|
+
"require": "./dist/index.js"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
"files": ["dist"],
|
|
@@ -29,12 +29,12 @@
|
|
|
29
29
|
},
|
|
30
30
|
"engines": { "node": ">=18" },
|
|
31
31
|
"scripts": {
|
|
32
|
-
"build": "
|
|
32
|
+
"build": "tsup",
|
|
33
33
|
"lint": "tsc --noEmit",
|
|
34
34
|
"prepublishOnly": "npm run build"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@ingissa/navcore-core": "^1.0.
|
|
37
|
+
"@ingissa/navcore-core": "^1.0.4",
|
|
38
38
|
"react": ">=18.0.0",
|
|
39
39
|
"react-native": ">=0.72.0",
|
|
40
40
|
"react-native-maps": ">=1.0.0"
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NavCoreProvider — React Context for shared NavCore engine access.
|
|
3
|
-
*
|
|
4
|
-
* Use when multiple components need access to the same engine instance
|
|
5
|
-
* (e.g. map view, instruction banner, debug panel).
|
|
6
|
-
*/
|
|
7
|
-
import { type ReactNode } from 'react';
|
|
8
|
-
import { NavCore, type NavCoreOptions } from '@ingissa/navcore-core';
|
|
9
|
-
interface NavCoreContextValue {
|
|
10
|
-
engine: NavCore;
|
|
11
|
-
}
|
|
12
|
-
interface NavCoreProviderProps {
|
|
13
|
-
children: ReactNode;
|
|
14
|
-
options?: NavCoreOptions;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Wraps children with a shared NavCore engine instance.
|
|
18
|
-
*
|
|
19
|
-
* ```tsx
|
|
20
|
-
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
21
|
-
* <MapScreen />
|
|
22
|
-
* <InstructionBanner />
|
|
23
|
-
* </NavCoreProvider>
|
|
24
|
-
* ```
|
|
25
|
-
*/
|
|
26
|
-
export declare function NavCoreProvider({ children, options }: NavCoreProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
27
|
-
/**
|
|
28
|
-
* Access the shared NavCore engine from context.
|
|
29
|
-
* Must be used within a <NavCoreProvider>.
|
|
30
|
-
*/
|
|
31
|
-
export declare function useNavCoreContext(): NavCoreContextValue;
|
|
32
|
-
export {};
|
|
33
|
-
//# sourceMappingURL=NavCoreProvider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NavCoreProvider.d.ts","sourceRoot":"","sources":["../src/NavCoreProvider.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA8C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACnF,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAErE,UAAU,mBAAmB;IAC3B,MAAM,EAAE,OAAO,CAAC;CACjB;AAID,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,oBAAoB,2CAe1E;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CAMvD"}
|
package/dist/NavCoreProvider.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/**
|
|
3
|
-
* NavCoreProvider — React Context for shared NavCore engine access.
|
|
4
|
-
*
|
|
5
|
-
* Use when multiple components need access to the same engine instance
|
|
6
|
-
* (e.g. map view, instruction banner, debug panel).
|
|
7
|
-
*/
|
|
8
|
-
import { createContext, useContext, useRef, useMemo } from 'react';
|
|
9
|
-
import { NavCore } from '@ingissa/navcore-core';
|
|
10
|
-
const NavCoreContext = createContext(null);
|
|
11
|
-
/**
|
|
12
|
-
* Wraps children with a shared NavCore engine instance.
|
|
13
|
-
*
|
|
14
|
-
* ```tsx
|
|
15
|
-
* <NavCoreProvider options={{ licenseKey: '...' }}>
|
|
16
|
-
* <MapScreen />
|
|
17
|
-
* <InstructionBanner />
|
|
18
|
-
* </NavCoreProvider>
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
export function NavCoreProvider({ children, options }) {
|
|
22
|
-
const engineRef = useRef(null);
|
|
23
|
-
if (!engineRef.current) {
|
|
24
|
-
engineRef.current = new NavCore(options);
|
|
25
|
-
}
|
|
26
|
-
const value = useMemo(() => ({
|
|
27
|
-
engine: engineRef.current,
|
|
28
|
-
}), []);
|
|
29
|
-
return (_jsx(NavCoreContext.Provider, { value: value, children: children }));
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Access the shared NavCore engine from context.
|
|
33
|
-
* Must be used within a <NavCoreProvider>.
|
|
34
|
-
*/
|
|
35
|
-
export function useNavCoreContext() {
|
|
36
|
-
const ctx = useContext(NavCoreContext);
|
|
37
|
-
if (!ctx) {
|
|
38
|
-
throw new Error('useNavCoreContext must be used within a <NavCoreProvider>');
|
|
39
|
-
}
|
|
40
|
-
return ctx;
|
|
41
|
-
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/useNavCore.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useNavCore.d.ts","sourceRoot":"","sources":["../src/useNavCore.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAqB,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAIjJ,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAAC;IAC5B,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,aAAa,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;IACnC,8BAA8B;IAC9B,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,sDAAsD;IACtD,YAAY,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC;QACjC,KAAK,EAAE,UAAU,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC,CAAC;IACV,yCAAyC;IACzC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/E,mCAAmC;IACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACpD,0CAA0C;IAC1C,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,cAAc,KAAK,IAAI,CAAC;IACtD,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;CACjB;AAID,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,UAAU,EACV,WAAW,EACX,YAAY,EACZ,KAAK,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,OAAO,EACP,aAAa,EACb,SAAS,EACT,WAAW,EACX,QAAQ,EACR,aAAa,EACb,SAAS,EACT,UAAe,GAChB,EAAE,eAAe,GAAG,gBAAgB,CAwJpC"}
|
package/dist/useNavCore.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useNavCore — React hook for the NavCore navigation engine.
|
|
3
|
-
*
|
|
4
|
-
* Manages engine lifecycle, GPS → engine → state pipeline,
|
|
5
|
-
* event wiring, and optimized re-render batching.
|
|
6
|
-
*
|
|
7
|
-
* Drop-in replacement for the existing Go4Exams useNavCore hook.
|
|
8
|
-
*/
|
|
9
|
-
import { useState, useEffect, useRef, useMemo } from 'react';
|
|
10
|
-
import { NavCore } from '@ingissa/navcore-core';
|
|
11
|
-
// ── Hook ──────────────────────────────────────────────────────
|
|
12
|
-
export function useNavCore({ gpsCoord, gpsBearing, gpsAccuracy, gpsTimestamp, speed, routeGeometry, instructions, isNavigating, options, resumeAtIndex, outputRef, onDeviation, onRejoin, onInstruction, onArrival, pollRateHz = 30, }) {
|
|
13
|
-
// ── 1. Engine singleton ───────────────────────────────────────
|
|
14
|
-
const navRef = useRef(null);
|
|
15
|
-
if (!navRef.current) {
|
|
16
|
-
navRef.current = new NavCore(options);
|
|
17
|
-
}
|
|
18
|
-
const engine = navRef.current;
|
|
19
|
-
const [state, setState] = useState(() => engine.getState());
|
|
20
|
-
// ── 2. Event wiring ───────────────────────────────────────────
|
|
21
|
-
// 2a. Deviation
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (!onDeviation)
|
|
24
|
-
return;
|
|
25
|
-
const handler = (data) => onDeviation(data);
|
|
26
|
-
engine.on('deviation', handler);
|
|
27
|
-
return () => { engine.off('deviation', handler); };
|
|
28
|
-
}, [engine, onDeviation]);
|
|
29
|
-
// 2b. Rejoin
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (!onRejoin)
|
|
32
|
-
return;
|
|
33
|
-
const handler = (data) => onRejoin(data);
|
|
34
|
-
engine.on('rejoined', handler);
|
|
35
|
-
return () => { engine.off('rejoined', handler); };
|
|
36
|
-
}, [engine, onRejoin]);
|
|
37
|
-
// 2c. Instruction
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (!onInstruction)
|
|
40
|
-
return;
|
|
41
|
-
const handler = (data) => onInstruction(data);
|
|
42
|
-
engine.on('instruction', handler);
|
|
43
|
-
return () => { engine.off('instruction', handler); };
|
|
44
|
-
}, [engine, onInstruction]);
|
|
45
|
-
// 2d. Arrival
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (!onArrival)
|
|
48
|
-
return;
|
|
49
|
-
const handler = () => onArrival();
|
|
50
|
-
engine.on('arrival', handler);
|
|
51
|
-
return () => { engine.off('arrival', handler); };
|
|
52
|
-
}, [engine, onArrival]);
|
|
53
|
-
// ── 3. Route sync ────────────────────────────────────────────
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (routeGeometry && routeGeometry.length >= 2) {
|
|
56
|
-
engine.setRoute(routeGeometry, instructions);
|
|
57
|
-
}
|
|
58
|
-
}, [engine, routeGeometry]);
|
|
59
|
-
// ── 4. Instructions sync (can change independently of route) ──
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (instructions && instructions.length > 0 && routeGeometry && routeGeometry.length >= 2) {
|
|
62
|
-
engine.setRoute(routeGeometry, instructions);
|
|
63
|
-
}
|
|
64
|
-
}, [engine, instructions]);
|
|
65
|
-
// ── 5. GPS → engine pipeline ──────────────────────────────────
|
|
66
|
-
useEffect(() => {
|
|
67
|
-
if (!gpsCoord || !isNavigating)
|
|
68
|
-
return;
|
|
69
|
-
const gpsUpdate = {
|
|
70
|
-
coord: gpsCoord,
|
|
71
|
-
accuracy: gpsAccuracy ?? null,
|
|
72
|
-
bearing: gpsBearing ?? null,
|
|
73
|
-
speed,
|
|
74
|
-
timestamp: gpsTimestamp ?? Date.now(),
|
|
75
|
-
};
|
|
76
|
-
engine.update(gpsUpdate);
|
|
77
|
-
}, [engine, gpsCoord, gpsAccuracy, gpsBearing, gpsTimestamp, speed, isNavigating]);
|
|
78
|
-
// ── 6. Start navigation ───────────────────────────────────────
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
if (isNavigating) {
|
|
81
|
-
engine.startNavigation();
|
|
82
|
-
}
|
|
83
|
-
}, [engine, isNavigating]);
|
|
84
|
-
// ── 7. Optimized state polling ────────────────────────────────
|
|
85
|
-
// Polls at pollRateHz to batch state reads and minimize re-renders.
|
|
86
|
-
// Only triggers setState when positional properties actually change.
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
if (!isNavigating)
|
|
89
|
-
return;
|
|
90
|
-
const lastRef = {
|
|
91
|
-
snapped: [0, 0],
|
|
92
|
-
bearing: 0,
|
|
93
|
-
raw: [0, 0],
|
|
94
|
-
};
|
|
95
|
-
const intervalMs = Math.round(1000 / pollRateHz);
|
|
96
|
-
const poll = () => {
|
|
97
|
-
const live = engine.getState();
|
|
98
|
-
let changed = false;
|
|
99
|
-
// Bearing delta
|
|
100
|
-
if (Math.abs(live.bearing - lastRef.bearing) > 0.1) {
|
|
101
|
-
lastRef.bearing = live.bearing;
|
|
102
|
-
changed = true;
|
|
103
|
-
}
|
|
104
|
-
// Snapped coordinate delta
|
|
105
|
-
if (live.snappedCoord &&
|
|
106
|
-
(live.snappedCoord[0] !== lastRef.snapped[0] ||
|
|
107
|
-
live.snappedCoord[1] !== lastRef.snapped[1])) {
|
|
108
|
-
lastRef.snapped = [live.snappedCoord[0], live.snappedCoord[1]];
|
|
109
|
-
changed = true;
|
|
110
|
-
}
|
|
111
|
-
// Raw GPS delta
|
|
112
|
-
if (live.rawGpsCoord &&
|
|
113
|
-
(live.rawGpsCoord[0] !== lastRef.raw[0] ||
|
|
114
|
-
live.rawGpsCoord[1] !== lastRef.raw[1])) {
|
|
115
|
-
lastRef.raw = [live.rawGpsCoord[0], live.rawGpsCoord[1]];
|
|
116
|
-
changed = true;
|
|
117
|
-
}
|
|
118
|
-
if (changed) {
|
|
119
|
-
setState(live);
|
|
120
|
-
}
|
|
121
|
-
// Camera output ref
|
|
122
|
-
if (outputRef?.current !== undefined) {
|
|
123
|
-
outputRef.current = {
|
|
124
|
-
coord: live.snappedCoord ?? lastRef.snapped,
|
|
125
|
-
bearing: live.bearing,
|
|
126
|
-
speed: live.currentSpeed,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
const id = setInterval(poll, intervalMs);
|
|
131
|
-
return () => clearInterval(id);
|
|
132
|
-
}, [engine, isNavigating, pollRateHz, outputRef]);
|
|
133
|
-
// ── 8. Cleanup ────────────────────────────────────────────────
|
|
134
|
-
useEffect(() => {
|
|
135
|
-
return () => {
|
|
136
|
-
engine.destroy();
|
|
137
|
-
navRef.current = null;
|
|
138
|
-
};
|
|
139
|
-
}, [engine]);
|
|
140
|
-
// ── 9. Stable return ──────────────────────────────────────────
|
|
141
|
-
return useMemo(() => ({
|
|
142
|
-
...state,
|
|
143
|
-
engine,
|
|
144
|
-
}), [state, engine]);
|
|
145
|
-
}
|