react-native-maplibre-lite 0.1.9 → 0.2.1

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.
Files changed (78) hide show
  1. package/README.md +92 -6
  2. package/lib/module/components/MapView.js +167 -48
  3. package/lib/module/components/MapView.js.map +1 -1
  4. package/lib/module/components/NavigatorHud.js +152 -0
  5. package/lib/module/components/NavigatorHud.js.map +1 -0
  6. package/lib/module/components/NavigatorRecenterButton.js +48 -0
  7. package/lib/module/components/NavigatorRecenterButton.js.map +1 -0
  8. package/lib/module/components/NavigatorVoiceControl.js +173 -0
  9. package/lib/module/components/NavigatorVoiceControl.js.map +1 -0
  10. package/lib/module/components/navigatorChromeTheme.js +98 -0
  11. package/lib/module/components/navigatorChromeTheme.js.map +1 -0
  12. package/lib/module/components/navigatorManeuverIcon.js +210 -0
  13. package/lib/module/components/navigatorManeuverIcon.js.map +1 -0
  14. package/lib/module/components/navigatorVoiceCatalog.js +225 -0
  15. package/lib/module/components/navigatorVoiceCatalog.js.map +1 -0
  16. package/lib/module/components/navigatorVoiceKeys.js +14 -0
  17. package/lib/module/components/navigatorVoiceKeys.js.map +1 -0
  18. package/lib/module/components/navigatorVoicePlayer.js +100 -0
  19. package/lib/module/components/navigatorVoicePlayer.js.map +1 -0
  20. package/lib/module/components/navigatorVoiceStrings.js +31 -0
  21. package/lib/module/components/navigatorVoiceStrings.js.map +1 -0
  22. package/lib/module/components/types.js +47 -0
  23. package/lib/module/components/types.js.map +1 -1
  24. package/lib/module/components/useNavigatorVoice.js +78 -0
  25. package/lib/module/components/useNavigatorVoice.js.map +1 -0
  26. package/lib/module/components/utils.js +26 -0
  27. package/lib/module/components/utils.js.map +1 -1
  28. package/lib/module/components/webMapBuild.js +1 -1
  29. package/lib/module/components/webMapBuild.js.map +1 -1
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/typescript/src/components/MapView.d.ts +15 -2
  32. package/lib/typescript/src/components/MapView.d.ts.map +1 -1
  33. package/lib/typescript/src/components/NavigatorHud.d.ts +13 -0
  34. package/lib/typescript/src/components/NavigatorHud.d.ts.map +1 -0
  35. package/lib/typescript/src/components/NavigatorRecenterButton.d.ts +11 -0
  36. package/lib/typescript/src/components/NavigatorRecenterButton.d.ts.map +1 -0
  37. package/lib/typescript/src/components/NavigatorVoiceControl.d.ts +20 -0
  38. package/lib/typescript/src/components/NavigatorVoiceControl.d.ts.map +1 -0
  39. package/lib/typescript/src/components/navigatorChromeTheme.d.ts +19 -0
  40. package/lib/typescript/src/components/navigatorChromeTheme.d.ts.map +1 -0
  41. package/lib/typescript/src/components/navigatorManeuverIcon.d.ts +20 -0
  42. package/lib/typescript/src/components/navigatorManeuverIcon.d.ts.map +1 -0
  43. package/lib/typescript/src/components/navigatorVoiceCatalog.d.ts +50 -0
  44. package/lib/typescript/src/components/navigatorVoiceCatalog.d.ts.map +1 -0
  45. package/lib/typescript/src/components/navigatorVoiceKeys.d.ts +10 -0
  46. package/lib/typescript/src/components/navigatorVoiceKeys.d.ts.map +1 -0
  47. package/lib/typescript/src/components/navigatorVoicePlayer.d.ts +15 -0
  48. package/lib/typescript/src/components/navigatorVoicePlayer.d.ts.map +1 -0
  49. package/lib/typescript/src/components/navigatorVoiceStrings.d.ts +19 -0
  50. package/lib/typescript/src/components/navigatorVoiceStrings.d.ts.map +1 -0
  51. package/lib/typescript/src/components/types.d.ts +205 -12
  52. package/lib/typescript/src/components/types.d.ts.map +1 -1
  53. package/lib/typescript/src/components/useNavigatorVoice.d.ts +20 -0
  54. package/lib/typescript/src/components/useNavigatorVoice.d.ts.map +1 -0
  55. package/lib/typescript/src/components/utils.d.ts +9 -0
  56. package/lib/typescript/src/components/utils.d.ts.map +1 -1
  57. package/lib/typescript/src/components/webMapBuild.d.ts +1 -1
  58. package/lib/typescript/src/components/webMapBuild.d.ts.map +1 -1
  59. package/lib/typescript/src/index.d.ts +1 -1
  60. package/lib/typescript/src/index.d.ts.map +1 -1
  61. package/package.json +16 -7
  62. package/resources/README.md +62 -0
  63. package/resources/map.html +797 -0
  64. package/src/components/MapView.tsx +209 -58
  65. package/src/components/NavigatorHud.tsx +166 -0
  66. package/src/components/NavigatorRecenterButton.tsx +45 -0
  67. package/src/components/NavigatorVoiceControl.tsx +198 -0
  68. package/src/components/navigatorChromeTheme.ts +118 -0
  69. package/src/components/navigatorManeuverIcon.tsx +177 -0
  70. package/src/components/navigatorVoiceCatalog.ts +275 -0
  71. package/src/components/navigatorVoiceKeys.ts +132 -0
  72. package/src/components/navigatorVoicePlayer.tsx +126 -0
  73. package/src/components/navigatorVoiceStrings.ts +42 -0
  74. package/src/components/types.ts +198 -16
  75. package/src/components/useNavigatorVoice.ts +96 -0
  76. package/src/components/utils.ts +28 -0
  77. package/src/components/webMapBuild.ts +1 -1
  78. package/src/index.tsx +19 -0
@@ -1,21 +1,25 @@
1
-
2
- export type MarkerProps = {
3
- ignoreFitBounds?: boolean,
1
+ /** RN → Web: `addMarker` (`MapLiteController.MarkerParams`). */
2
+ export type MapLiteMarkerParams = {
4
3
  uniqueId: string,
5
- onPress?: () => void,
6
4
  latitude: number,
7
5
  longitude: number,
8
6
  color?: string,
9
-
10
7
  iconUrl?: string,
11
8
  iconWidth?: number,
12
9
  iconHeight?: number,
13
10
  html?: string,
11
+ }
14
12
 
13
+ /** RN → Web: `addPolyline` (`MapLiteController.PolylineParams`). */
14
+ export type MapLitePolylineParams = {
15
+ uniqueId: string,
16
+ coordinates: [number, number][],
17
+ color?: string,
18
+ width?: number,
15
19
  }
16
20
 
17
- export type PolygonProps = {
18
- ignoreFitBounds?: boolean,
21
+ /** RN Web: `addPolygon` (`MapLiteController.PolygonParams`). */
22
+ export type MapLitePolygonParams = {
19
23
  uniqueId: string,
20
24
  coordinates: [number, number][],
21
25
  fillColor?: string,
@@ -23,24 +27,33 @@ export type PolygonProps = {
23
27
  strokeColor?: string,
24
28
  strokeOpacity?: number,
25
29
  strokeWidth?: number,
30
+ }
26
31
 
32
+ /** RN → Web: `removeMarker` / `removePolyline` / `removePolygon`. */
33
+ export type MapLiteRemoveOverlayParams = {
34
+ uniqueId: string,
27
35
  }
28
36
 
29
- export type PolylineProps = {
37
+ export type MarkerProps = MapLiteMarkerParams & {
30
38
  ignoreFitBounds?: boolean,
31
- uniqueId: string,
32
- color?: string,
33
- width?: number,
34
- coordinates: [number, number][],
39
+ onPress?: () => void,
40
+ }
41
+
42
+ export type PolygonProps = MapLitePolygonParams & {
43
+ ignoreFitBounds?: boolean,
44
+ }
35
45
 
46
+ export type PolylineProps = MapLitePolylineParams & {
47
+ ignoreFitBounds?: boolean,
36
48
  }
37
49
 
50
+ /** Web → RN: `postToNative` payload (`webProject/src/map/types.ts`). */
38
51
  export type EventParams = {
39
52
  center?: {
40
53
  lng: number,
41
- lat: number
42
- },
43
- zoom?: number
54
+ lat: number,
55
+ } | null,
56
+ zoom?: number | null,
44
57
  }
45
58
 
46
59
  export type NavigatorLang = 'ru' | 'en'
@@ -113,7 +126,176 @@ export type NavigatorPositionSetParams = {
113
126
  distanceFromRouteMeters: number,
114
127
  }
115
128
 
129
+ /**
130
+ * Web → RN: `navigatorHud` event. View-model панели маршрута (HUD).
131
+ * Все строки уже локализованы/отформатированы в вебе — RN рисует «как есть».
132
+ */
133
+ export type NavigatorHudState = {
134
+ /** Показывать ли панель. */
135
+ visible: boolean,
136
+ /** Режим «кликни по карте, чтобы задать позицию» (dev): показать подсказку. */
137
+ pick?: boolean,
138
+ /** Состояние «Вы приехали». */
139
+ arrived?: boolean,
140
+ /** Код манёвра GraphHopper для иконки. */
141
+ sign?: number,
142
+ /** Крупная строка: дистанция / «Прибытие» / заголовок прибытия. */
143
+ distanceLabel?: string,
144
+ /** Текст манёвра / подзаголовок. */
145
+ maneuverText?: string,
146
+ /** Имя улицы после манёвра. */
147
+ streetName?: string,
148
+ /** Сводка маршрута («До конца: …»). */
149
+ summaryText?: string,
150
+ /** Доп. строка (подъём/спуск). */
151
+ extrasText?: string,
152
+ /** Ограничение скорости (км/ч) или null. */
153
+ speedLimitKmh?: number | null,
154
+ }
155
+
156
+ /** Действие озвучки в событии `navigatorVoice`. */
157
+ export type NavigatorVoiceAction = 'play' | 'prefetch' | 'stop'
158
+
159
+ /**
160
+ * Web → RN: `navigatorVoice` event. Веб шлёт абстрактные ключи фраз;
161
+ * нативная часть мапит их в URL клипов и воспроизводит.
162
+ */
163
+ export type NavigatorVoicePlayParams = {
164
+ action: NavigatorVoiceAction,
165
+ keys: string[],
166
+ }
167
+
116
168
  export type MapLiteWebError = {
117
169
  target: string,
118
170
  message: string,
119
- }
171
+ }
172
+
173
+ /** Parsed MapLibre style JSON — `InitParams.mapStyle` / `UpdateParams.mapStyle` в WebView. */
174
+ export type MapLiteStyleSpecification = Record<string, unknown>
175
+
176
+ /** RN → Web: `init` (`MapLiteController.InitParams`). */
177
+ export type MapLiteInitParams = {
178
+ mapStyle: MapLiteStyleSpecification,
179
+ center: [number, number],
180
+ zoom: number,
181
+ minZoom?: number,
182
+ maxZoom?: number,
183
+ zoomEnabled?: boolean,
184
+ scrollEnabled?: boolean,
185
+ antialias?: boolean,
186
+ crossSourceCollisions?: boolean,
187
+ fadeDuration?: number,
188
+ pixelRatio?: number,
189
+ simplifyStyle?: boolean,
190
+ aggressiveSimplifyStyle?: boolean,
191
+ maxPitch?: number,
192
+ renderWorldCopies?: boolean,
193
+ turboWhileMoving?: boolean,
194
+ debugMode?: boolean,
195
+ navigator?: boolean,
196
+ graphhopperUrl?: string,
197
+ navigatorLang?: NavigatorLang,
198
+ navigatorProfile?: NavigatorProfile | string,
199
+ navigatorChrome?: NavigatorChromeParams,
200
+ }
201
+
202
+ /** RN → Web: `update` (`MapLiteController.UpdateParams`). */
203
+ export type MapLiteUpdateParams = {
204
+ minZoom?: number,
205
+ maxZoom?: number,
206
+ zoomEnabled?: boolean,
207
+ scrollEnabled?: boolean,
208
+ mapStyle?: MapLiteStyleSpecification,
209
+ }
210
+
211
+ /** RN → Web: `fitBounds`. */
212
+ export type MapLiteFitBoundsParams = {
213
+ bounds: [[number, number], [number, number]],
214
+ padding?: number,
215
+ duration?: number,
216
+ }
217
+
218
+ /** RN → Web: `flyTo`. */
219
+ export type MapLiteFlyToParams = {
220
+ center: [number, number],
221
+ zoom: number,
222
+ duration?: number,
223
+ }
224
+
225
+ /** RN → Web: `setNavigatorPoint`. */
226
+ export type MapLiteSetNavigatorPointParams = {
227
+ latitude: number,
228
+ longitude: number,
229
+ }
230
+
231
+ /**
232
+ * RN → Web: `setNavigatorPosition`.
233
+ * `accuracy` (м) включает прод-режим off-route на стороне WebView.
234
+ */
235
+ export type MapLiteSetNavigatorPositionParams = {
236
+ latitude: number,
237
+ longitude: number,
238
+ accuracy?: number,
239
+ }
240
+
241
+ /** RN → Web: JSON в `WebView.postMessage` (`webProject/src/map/MapLiteController.receive`). */
242
+ export type NativeToWebCommand =
243
+ | { function: 'init', params: MapLiteInitParams }
244
+ | { function: 'update', params: MapLiteUpdateParams }
245
+ | { function: 'addMarker', params: MapLiteMarkerParams }
246
+ | { function: 'removeMarker', params: MapLiteRemoveOverlayParams }
247
+ | { function: 'addPolyline', params: MapLitePolylineParams }
248
+ | { function: 'removePolyline', params: MapLiteRemoveOverlayParams }
249
+ | { function: 'addPolygon', params: MapLitePolygonParams }
250
+ | { function: 'removePolygon', params: MapLiteRemoveOverlayParams }
251
+ | { function: 'fitBounds', params: MapLiteFitBoundsParams }
252
+ | { function: 'flyTo', params: MapLiteFlyToParams }
253
+ | { function: 'setNavigatorPoint', params: MapLiteSetNavigatorPointParams }
254
+ | { function: 'advanceNavigatorInstruction', params: Record<string, never> }
255
+ | { function: 'setNavigatorPosition', params: MapLiteSetNavigatorPositionParams }
256
+ | { function: 'pickNavigatorPosition', params: Record<string, never> }
257
+ | { function: 'recenterNavigatorCamera', params: Record<string, never> }
258
+
259
+ /** Web → RN: `postToNative` (`webProject/src/map/types.ts`). */
260
+ export type WebToNativeMessage =
261
+ | { type: 'scriptReady' }
262
+ | { type: 'inited' }
263
+ | { type: 'event', event: string, params: unknown }
264
+ | { type: 'markerClick', uniqueId: string }
265
+ | {
266
+ type: 'error',
267
+ data: MapLiteWebError,
268
+ }
269
+
270
+ /** Имена `event` в `{ type: 'event', event, params }` из WebView. */
271
+ export type MapLiteMapEventName =
272
+ | 'movestart'
273
+ | 'moveend'
274
+ | 'zoomstart'
275
+ | 'zoomend'
276
+ | 'idle'
277
+ | 'error'
278
+ | 'navigatorRouteSet'
279
+ | 'navigatorInstruction'
280
+ | 'navigatorPositionSet'
281
+ | 'navigatorHud'
282
+ | 'navigatorVoice'
283
+
284
+ export type MapLiteMapErrorEventParams = {
285
+ message: string,
286
+ }
287
+
288
+ /** `params` для `{ type: 'event', event, params }` по имени события. */
289
+ export type MapLiteMapEventParamsMap = {
290
+ movestart: EventParams,
291
+ moveend: EventParams,
292
+ zoomstart: EventParams,
293
+ zoomend: EventParams,
294
+ idle: EventParams,
295
+ error: MapLiteMapErrorEventParams,
296
+ navigatorRouteSet: NavigatorRouteSetParams,
297
+ navigatorInstruction: NavigatorInstructionParams,
298
+ navigatorPositionSet: NavigatorPositionSetParams,
299
+ navigatorHud: NavigatorHudState,
300
+ navigatorVoice: NavigatorVoicePlayParams,
301
+ }
@@ -0,0 +1,96 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+
3
+ import {
4
+ loadVoiceRuntime,
5
+ readVoiceVolumeLevel,
6
+ reloadVoiceForDir,
7
+ writeVoicePref,
8
+ writeVoiceVolumeLevel,
9
+ type VoiceCatalogEntry,
10
+ type VoiceManifest,
11
+ type VoiceRuntime,
12
+ type VoiceVolumeLevel,
13
+ } from './navigatorVoiceCatalog';
14
+
15
+ /**
16
+ * Нативное владение голосом навигатора: загрузка каталога/манифеста,
17
+ * выбор голоса/громкости и персист (AsyncStorage). Веб шлёт только ключи
18
+ * фраз; маппинг в аудио и воспроизведение — на стороне RN.
19
+ */
20
+ export type NavigatorVoiceController = {
21
+ runtime: VoiceRuntime | null;
22
+ catalog: VoiceCatalogEntry[];
23
+ selectedDir: string | null;
24
+ manifest: VoiceManifest | null;
25
+ clipBaseUrl: string | null;
26
+ voiceEnabled: boolean;
27
+ volumeLevel: VoiceVolumeLevel;
28
+ selectVoice: (dir: string) => Promise<void>;
29
+ selectVolume: (level: VoiceVolumeLevel) => void;
30
+ disableVoice: () => Promise<void>;
31
+ };
32
+
33
+ export function useNavigatorVoice(voiceUrl: string | undefined): NavigatorVoiceController {
34
+ const [runtime, setRuntime] = useState<VoiceRuntime | null>(null);
35
+ const [volumeLevel, setVolumeLevel] = useState<VoiceVolumeLevel>(5);
36
+
37
+ useEffect(() => {
38
+ let cancelled = false;
39
+ void readVoiceVolumeLevel().then((lvl) => {
40
+ if (!cancelled) setVolumeLevel(lvl);
41
+ });
42
+ if (!voiceUrl) {
43
+ setRuntime(null);
44
+ return () => {
45
+ cancelled = true;
46
+ };
47
+ }
48
+ void loadVoiceRuntime(voiceUrl)
49
+ .then((rt) => {
50
+ if (!cancelled) setRuntime(rt);
51
+ })
52
+ .catch((err) => {
53
+ console.warn('[maplite] navigator voice catalog failed', err);
54
+ if (!cancelled) setRuntime(null);
55
+ });
56
+ return () => {
57
+ cancelled = true;
58
+ };
59
+ }, [voiceUrl]);
60
+
61
+ const selectVoice = useCallback(
62
+ async (dir: string) => {
63
+ if (!runtime) return;
64
+ try {
65
+ const reloaded = await reloadVoiceForDir(runtime.catalogUrl, runtime.catalog, dir);
66
+ setRuntime((prev) => (prev ? { ...prev, ...reloaded } : prev));
67
+ } catch (err) {
68
+ console.warn('[maplite] failed to switch navigator voice', { dir, err });
69
+ }
70
+ },
71
+ [runtime]
72
+ );
73
+
74
+ const selectVolume = useCallback((level: VoiceVolumeLevel) => {
75
+ setVolumeLevel(level);
76
+ void writeVoiceVolumeLevel(level);
77
+ }, []);
78
+
79
+ const disableVoice = useCallback(async () => {
80
+ await writeVoicePref({ disabled: true });
81
+ setRuntime((prev) => (prev ? { ...prev, enabled: false, manifest: null } : prev));
82
+ }, []);
83
+
84
+ return {
85
+ runtime,
86
+ catalog: runtime?.catalog ?? [],
87
+ selectedDir: runtime?.selectedDir ?? null,
88
+ manifest: runtime?.manifest ?? null,
89
+ clipBaseUrl: runtime?.clipBaseUrl ?? null,
90
+ voiceEnabled: Boolean(runtime?.enabled && runtime.manifest),
91
+ volumeLevel,
92
+ selectVoice,
93
+ selectVolume,
94
+ disableVoice,
95
+ };
96
+ }
@@ -1,7 +1,35 @@
1
1
  import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { NativeModules, Platform } from 'react-native';
2
3
 
3
4
  const CACHE_VERSION = 'v1';
4
5
 
6
+ /** Android: `android/app/src/main/assets/map.html`. See `resources/README.md`. */
7
+ export const NATIVE_MAP_HTML_ANDROID_URI = 'file:///android_asset/map.html';
8
+
9
+ /** Имя файла в iOS bundle (Copy Bundle Resources). */
10
+ export const NATIVE_MAP_HTML_IOS_FILENAME = 'map.html';
11
+
12
+ /**
13
+ * URI для `map.html` из нативных ресурсов хост-приложения.
14
+ * Android — assets; iOS — main bundle (через путь к `.app` из `SourceCode.scriptURL`).
15
+ */
16
+ export const getNativeMapHtmlUri = (): string => {
17
+ if (Platform.OS === 'android') {
18
+ return NATIVE_MAP_HTML_ANDROID_URI;
19
+ }
20
+
21
+ if (Platform.OS === 'ios') {
22
+ const scriptURL: unknown = NativeModules.SourceCode?.scriptURL;
23
+ if (typeof scriptURL === 'string' && scriptURL.startsWith('file://')) {
24
+ const bundleDir = scriptURL.substring(0, scriptURL.lastIndexOf('/') + 1);
25
+ return `${bundleDir}${NATIVE_MAP_HTML_IOS_FILENAME}`;
26
+ }
27
+ return NATIVE_MAP_HTML_IOS_FILENAME;
28
+ }
29
+
30
+ return NATIVE_MAP_HTML_ANDROID_URI;
31
+ };
32
+
5
33
  export const loadResources = async (url: string) => {
6
34
  const cacheKey = `${url}@${CACHE_VERSION}`;
7
35