react-native-maplibre-lite 0.1.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 (99) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +203 -0
  3. package/lib/module/assets/MAP_ASSETS.js +7 -0
  4. package/lib/module/assets/MAP_ASSETS.js.map +1 -0
  5. package/lib/module/assets/dark_placeholder.jpg +0 -0
  6. package/lib/module/assets/light_placeholder.jpg +0 -0
  7. package/lib/module/components/MapPlaceholder.js +37 -0
  8. package/lib/module/components/MapPlaceholder.js.map +1 -0
  9. package/lib/module/components/MapSelectPoint.js +88 -0
  10. package/lib/module/components/MapSelectPoint.js.map +1 -0
  11. package/lib/module/components/MapView.js +244 -0
  12. package/lib/module/components/MapView.js.map +1 -0
  13. package/lib/module/components/Marker.js +27 -0
  14. package/lib/module/components/Marker.js.map +1 -0
  15. package/lib/module/components/Polygon.js +27 -0
  16. package/lib/module/components/Polygon.js.map +1 -0
  17. package/lib/module/components/Polyline.js +27 -0
  18. package/lib/module/components/Polyline.js.map +1 -0
  19. package/lib/module/components/types.js +2 -0
  20. package/lib/module/components/types.js.map +1 -0
  21. package/lib/module/components/webFunctions/addMarkerWeb.js +57 -0
  22. package/lib/module/components/webFunctions/addMarkerWeb.js.map +1 -0
  23. package/lib/module/components/webFunctions/addPolygonWeb.js +62 -0
  24. package/lib/module/components/webFunctions/addPolygonWeb.js.map +1 -0
  25. package/lib/module/components/webFunctions/addPolylineWeb.js +48 -0
  26. package/lib/module/components/webFunctions/addPolylineWeb.js.map +1 -0
  27. package/lib/module/components/webFunctions/fitBoundsWeb.js +11 -0
  28. package/lib/module/components/webFunctions/fitBoundsWeb.js.map +1 -0
  29. package/lib/module/components/webFunctions/initWeb.js +156 -0
  30. package/lib/module/components/webFunctions/initWeb.js.map +1 -0
  31. package/lib/module/components/webFunctions/removeMarkerWeb.js +12 -0
  32. package/lib/module/components/webFunctions/removeMarkerWeb.js.map +1 -0
  33. package/lib/module/components/webFunctions/removePolygonWeb.js +22 -0
  34. package/lib/module/components/webFunctions/removePolygonWeb.js.map +1 -0
  35. package/lib/module/components/webFunctions/removePolylineWeb.js +17 -0
  36. package/lib/module/components/webFunctions/removePolylineWeb.js.map +1 -0
  37. package/lib/module/index.js +9 -0
  38. package/lib/module/index.js.map +1 -0
  39. package/lib/module/package.json +1 -0
  40. package/lib/module/webContent.js +173 -0
  41. package/lib/module/webContent.js.map +1 -0
  42. package/lib/typescript/package.json +1 -0
  43. package/lib/typescript/src/assets/MAP_ASSETS.d.ts +5 -0
  44. package/lib/typescript/src/assets/MAP_ASSETS.d.ts.map +1 -0
  45. package/lib/typescript/src/components/MapPlaceholder.d.ts +5 -0
  46. package/lib/typescript/src/components/MapPlaceholder.d.ts.map +1 -0
  47. package/lib/typescript/src/components/MapSelectPoint.d.ts +12 -0
  48. package/lib/typescript/src/components/MapSelectPoint.d.ts.map +1 -0
  49. package/lib/typescript/src/components/MapView.d.ts +41 -0
  50. package/lib/typescript/src/components/MapView.d.ts.map +1 -0
  51. package/lib/typescript/src/components/Marker.d.ts +3 -0
  52. package/lib/typescript/src/components/Marker.d.ts.map +1 -0
  53. package/lib/typescript/src/components/Polygon.d.ts +3 -0
  54. package/lib/typescript/src/components/Polygon.d.ts.map +1 -0
  55. package/lib/typescript/src/components/Polyline.d.ts +3 -0
  56. package/lib/typescript/src/components/Polyline.d.ts.map +1 -0
  57. package/lib/typescript/src/components/types.d.ts +38 -0
  58. package/lib/typescript/src/components/types.d.ts.map +1 -0
  59. package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts +3 -0
  60. package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts.map +1 -0
  61. package/lib/typescript/src/components/webFunctions/addPolygonWeb.d.ts +3 -0
  62. package/lib/typescript/src/components/webFunctions/addPolygonWeb.d.ts.map +1 -0
  63. package/lib/typescript/src/components/webFunctions/addPolylineWeb.d.ts +3 -0
  64. package/lib/typescript/src/components/webFunctions/addPolylineWeb.d.ts.map +1 -0
  65. package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts +3 -0
  66. package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts.map +1 -0
  67. package/lib/typescript/src/components/webFunctions/initWeb.d.ts +3 -0
  68. package/lib/typescript/src/components/webFunctions/initWeb.d.ts.map +1 -0
  69. package/lib/typescript/src/components/webFunctions/removeMarkerWeb.d.ts +3 -0
  70. package/lib/typescript/src/components/webFunctions/removeMarkerWeb.d.ts.map +1 -0
  71. package/lib/typescript/src/components/webFunctions/removePolygonWeb.d.ts +3 -0
  72. package/lib/typescript/src/components/webFunctions/removePolygonWeb.d.ts.map +1 -0
  73. package/lib/typescript/src/components/webFunctions/removePolylineWeb.d.ts +3 -0
  74. package/lib/typescript/src/components/webFunctions/removePolylineWeb.d.ts.map +1 -0
  75. package/lib/typescript/src/index.d.ts +9 -0
  76. package/lib/typescript/src/index.d.ts.map +1 -0
  77. package/lib/typescript/src/webContent.d.ts +3 -0
  78. package/lib/typescript/src/webContent.d.ts.map +1 -0
  79. package/package.json +158 -0
  80. package/src/assets/MAP_ASSETS.ts +4 -0
  81. package/src/assets/dark_placeholder.jpg +0 -0
  82. package/src/assets/light_placeholder.jpg +0 -0
  83. package/src/components/MapPlaceholder.tsx +44 -0
  84. package/src/components/MapSelectPoint.tsx +131 -0
  85. package/src/components/MapView.tsx +333 -0
  86. package/src/components/Marker.tsx +31 -0
  87. package/src/components/Polygon.tsx +31 -0
  88. package/src/components/Polyline.tsx +31 -0
  89. package/src/components/types.ts +46 -0
  90. package/src/components/webFunctions/addMarkerWeb.ts +54 -0
  91. package/src/components/webFunctions/addPolygonWeb.ts +59 -0
  92. package/src/components/webFunctions/addPolylineWeb.ts +45 -0
  93. package/src/components/webFunctions/fitBoundsWeb.ts +8 -0
  94. package/src/components/webFunctions/initWeb.ts +153 -0
  95. package/src/components/webFunctions/removeMarkerWeb.ts +9 -0
  96. package/src/components/webFunctions/removePolygonWeb.ts +19 -0
  97. package/src/components/webFunctions/removePolylineWeb.ts +14 -0
  98. package/src/index.tsx +10 -0
  99. package/src/webContent.ts +182 -0
@@ -0,0 +1,44 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { Animated, Image } from 'react-native';
3
+
4
+ import { MAP_ASSETS } from '../assets/MAP_ASSETS';
5
+
6
+ const MapPlaceholder = (props: { theme: 'dark' | 'light' }) => {
7
+ const opacityAnim = useRef(new Animated.Value(0.5)).current;
8
+
9
+ useEffect(() => {
10
+ const animate = () => {
11
+ Animated.sequence([
12
+ Animated.timing(opacityAnim, {
13
+ toValue: 1,
14
+ duration: 1000,
15
+ useNativeDriver: true,
16
+ }),
17
+ Animated.timing(opacityAnim, {
18
+ toValue: 0.5,
19
+ duration: 1000,
20
+ useNativeDriver: true,
21
+ }),
22
+ ]).start(() => animate());
23
+ };
24
+
25
+ animate();
26
+ }, [opacityAnim]);
27
+
28
+ return (
29
+ <Animated.Image
30
+ source={props.theme === 'dark' ? MAP_ASSETS.DARK_MAP_PLACEHOLDER : MAP_ASSETS.LIGHT_MAP_PLACEHOLDER}
31
+ style={{
32
+ position: 'absolute',
33
+ top: 0,
34
+ left: 0,
35
+ width: '100%',
36
+ height: '100%',
37
+ zIndex: 1000,
38
+ opacity: opacityAnim,
39
+ }}
40
+ />
41
+ );
42
+ }
43
+
44
+ export default MapPlaceholder;
@@ -0,0 +1,131 @@
1
+ import React, {
2
+ forwardRef,
3
+ useImperativeHandle,
4
+ useRef,
5
+ } from 'react';
6
+
7
+ import {
8
+ Animated,
9
+ StyleSheet,
10
+ View,
11
+ } from 'react-native';
12
+
13
+ export type MapSelectPointType = {
14
+ up: () => void;
15
+ down: () => void;
16
+ };
17
+
18
+ const BORDER_WIDTH_UP = 6;
19
+ const BORDER_WIDTH_DOWN = 3;
20
+ const UP_POSITION = 10;
21
+ const DURATION = 200;
22
+
23
+ type MapSelectPointProps = {
24
+ color?: string;
25
+ backgroundColor?: string;
26
+
27
+ }
28
+
29
+ export const MapSelectPoint = forwardRef<MapSelectPointType, MapSelectPointProps>(
30
+ (_props, ref) => {
31
+ const position = useRef<'up' | 'down'>('down');
32
+
33
+ const borderWidth = useRef(new Animated.Value(BORDER_WIDTH_DOWN)).current;
34
+ const shadowHeight = useRef(new Animated.Value(0)).current;
35
+ const shadowMarginTop = useRef(new Animated.Value(0)).current;
36
+ const handleMarginTop = useRef(new Animated.Value(0)).current;
37
+
38
+ useImperativeHandle(ref, () => ({
39
+ up: () => moveMarker('up'),
40
+ down: () => moveMarker('down'),
41
+ }));
42
+
43
+ const animateTo = (
44
+ animatedValue: Animated.Value,
45
+ toValue: number
46
+ ) => {
47
+ return Animated.timing(animatedValue, {
48
+ toValue,
49
+ duration: DURATION,
50
+ useNativeDriver: false,
51
+ });
52
+ };
53
+
54
+ const moveMarker = (direction: 'up' | 'down') => {
55
+ if (position.current === direction) return;
56
+ position.current = direction;
57
+
58
+ if (direction === 'up') {
59
+ Animated.parallel([
60
+ animateTo(borderWidth, BORDER_WIDTH_UP),
61
+ animateTo(shadowHeight, 4),
62
+ animateTo(shadowMarginTop, UP_POSITION),
63
+ animateTo(handleMarginTop, -UP_POSITION),
64
+ ]).start();
65
+ } else {
66
+ Animated.parallel([
67
+ animateTo(borderWidth, BORDER_WIDTH_DOWN),
68
+ animateTo(shadowHeight, 0),
69
+ animateTo(shadowMarginTop, 0),
70
+ animateTo(handleMarginTop, 0),
71
+ ]).start();
72
+ }
73
+ };
74
+
75
+ return (
76
+ <View style={styles.container}>
77
+ <Animated.View style={{ marginTop: handleMarginTop }}>
78
+ <View style={styles.center}>
79
+ <Animated.View
80
+ style={[
81
+ styles.circle,
82
+ {
83
+ borderWidth: borderWidth,
84
+ borderColor: _props.color,
85
+ backgroundColor: _props.backgroundColor,
86
+ },
87
+ ]}
88
+ />
89
+ <View style={[styles.line, { backgroundColor: _props.color }]} />
90
+ </View>
91
+ </Animated.View>
92
+ <Animated.View
93
+ style={[
94
+ styles.shadow,
95
+ {
96
+ height: shadowHeight,
97
+ marginTop: shadowMarginTop,
98
+ backgroundColor: _props.color,
99
+ },
100
+ ]}
101
+ />
102
+ </View>
103
+ );
104
+ }
105
+ );
106
+
107
+ const styles = StyleSheet.create({
108
+ container: {
109
+ alignItems: 'center',
110
+ },
111
+ center: {
112
+ alignItems: 'center',
113
+ },
114
+ circle: {
115
+ borderRadius: 100,
116
+ width: 28,
117
+ height: 28,
118
+ },
119
+ line: {
120
+ width: 2,
121
+ height: 15,
122
+
123
+ },
124
+ shadow: {
125
+ opacity: 0.6,
126
+ width: 4,
127
+ borderRadius: 100,
128
+ },
129
+ });
130
+
131
+ export default MapSelectPoint;
@@ -0,0 +1,333 @@
1
+ import {
2
+ createContext,
3
+ forwardRef,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useImperativeHandle,
8
+ useRef,
9
+ useState,
10
+ } from 'react';
11
+
12
+ import {
13
+ type StyleProp,
14
+ Platform,
15
+ View,
16
+ type ViewStyle,
17
+ } from 'react-native';
18
+ import { WebView } from 'react-native-webview';
19
+
20
+ import { maplibreHtmlMap } from '../webContent';
21
+ import MapPlaceholder from './MapPlaceholder';
22
+ import MapSelectPoint, { type MapSelectPointType } from './MapSelectPoint';
23
+ import {
24
+ type EventParams,
25
+ type MarkerProps,
26
+ type PolygonProps,
27
+ type PolylineProps,
28
+ type SourcesProps,
29
+ } from './types';
30
+ import addMarkerWeb from './webFunctions/addMarkerWeb';
31
+ import addPolygonWeb from './webFunctions/addPolygonWeb';
32
+ import addPolylineWeb from './webFunctions/addPolylineWeb';
33
+ import fitBoundsWeb from './webFunctions/fitBoundsWeb';
34
+ import initWeb from './webFunctions/initWeb';
35
+ import removeMarkerWeb from './webFunctions/removeMarkerWeb';
36
+ import removePolygonWeb from './webFunctions/removePolygonWeb';
37
+ import removePolylineWeb from './webFunctions/removePolylineWeb';
38
+
39
+ interface MapViewProps {
40
+ children?: React.ReactNode;
41
+
42
+ theme: 'light' | 'dark';
43
+ center: [number, number];
44
+ zoom: number;
45
+
46
+ mapStyle: string;
47
+ style: StyleProp<ViewStyle>;
48
+ minZoom?: number;
49
+ maxZoom?: number;
50
+ zoomEnabled?: boolean;
51
+ scrollEnabled?: boolean;
52
+ onMoveStart?: (eventParams: EventParams) => void;
53
+ onMoveEnd?: (eventParams: EventParams) => void;
54
+ onZoomStart?: (eventParams: EventParams) => void;
55
+ onZoomEnd?: (eventParams: EventParams) => void;
56
+ onIdle?: (eventParams: EventParams) => void;
57
+ showSelectPoint?: boolean;
58
+ selectPointColor?: string;
59
+ selectPointBackgroundColor?: string;
60
+ performanceMode?: 'quality' | 'balanced' | 'performance';
61
+ pixelRatio?: number;
62
+ turboWhileMoving?: boolean;
63
+
64
+ sources: SourcesProps;
65
+ }
66
+
67
+ export type MapViewRef = {
68
+ fitBounds: () => void;
69
+ };
70
+
71
+ type MapViewRegistry = {
72
+ addMarker: (propsMarker: MarkerProps) => void;
73
+ removeMarker: (propsMarker: MarkerProps) => void;
74
+ addPolyline: (propsPolyline: PolylineProps) => void;
75
+ removePolyline: (propsPolyline: PolylineProps) => void;
76
+ addPolygon: (propsPolygon: PolygonProps) => void;
77
+ removePolygon: (propsPolygon: PolygonProps) => void;
78
+ };
79
+
80
+ const MapViewContext = createContext<MapViewRegistry | null>(null);
81
+
82
+ export const useMapViewContext = () => {
83
+ const ctx = useContext(MapViewContext);
84
+ if (!ctx) throw new Error('useMapViewContext must be used within <MapView>');
85
+ return ctx;
86
+ };
87
+
88
+ const webFunctionsString = [
89
+ initWeb,
90
+ addMarkerWeb,
91
+ removeMarkerWeb,
92
+ addPolylineWeb,
93
+ removePolylineWeb,
94
+ addPolygonWeb,
95
+ removePolygonWeb,
96
+ fitBoundsWeb,
97
+ ].join('\n');
98
+
99
+ const getBoundsFromCoords = (
100
+ coords: [number, number][]
101
+ ): [[number, number], [number, number]] => {
102
+ if (!coords.length) {
103
+ throw new Error('Empty coordinates array');
104
+ }
105
+
106
+ let minLng = coords[0]![0];
107
+ let maxLng = coords[0]![0];
108
+ let minLat = coords[0]![1];
109
+ let maxLat = coords[0]![1];
110
+
111
+ for (const [lng, lat] of coords) {
112
+ if (lng < minLng) minLng = lng;
113
+ if (lng > maxLng) maxLng = lng;
114
+ if (lat < minLat) minLat = lat;
115
+ if (lat > maxLat) maxLat = lat;
116
+ }
117
+
118
+ return [
119
+ [minLng, minLat],
120
+ [maxLng, maxLat],
121
+ ];
122
+ };
123
+
124
+ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
125
+ const webViewRef = useRef<any>(null);
126
+ const [inited, setInited] = useState(false);
127
+ const [html, setHtml] = useState('');
128
+
129
+ const coordsInMapRef = useRef<Record<string, [number, number][]>>({});
130
+ const markersClickHandlers = useRef<Record<string, () => void>>({});
131
+ const mapSelectPointRef = useRef<MapSelectPointType | null>(null);
132
+ const performanceMode = props.performanceMode ?? (Platform.OS === 'android' ? 'balanced' : 'quality');
133
+
134
+ const fallbackPixelRatio = performanceMode === 'performance'
135
+ ? 0.85
136
+ : (performanceMode === 'balanced' && Platform.OS === 'android' ? 1 : undefined);
137
+
138
+ const sendToWebView = useCallback((message: { function: string; params: any }) => {
139
+ webViewRef.current?.postMessage(JSON.stringify(message));
140
+ }, []);
141
+
142
+ const initMap = useCallback(() => {
143
+ sendToWebView({
144
+ function: 'init',
145
+ params: {
146
+ style: props.mapStyle,
147
+ zoomEnabled: props.zoomEnabled ?? false,
148
+ scrollEnabled: props.scrollEnabled ?? false,
149
+ theme: props.theme,
150
+ center: props.center,
151
+ zoom: props.zoom,
152
+ minZoom: props.minZoom,
153
+ maxZoom: props.maxZoom,
154
+ antialias: false,
155
+ crossSourceCollisions: performanceMode !== 'performance',
156
+ fadeDuration: performanceMode === 'performance' ? 0 : 120,
157
+ pixelRatio: props.pixelRatio ?? fallbackPixelRatio,
158
+ simplifyStyle: performanceMode !== 'quality',
159
+ aggressiveSimplifyStyle: performanceMode === 'performance',
160
+ maxPitch: performanceMode === 'performance' ? 0 : 45,
161
+ renderWorldCopies: performanceMode === 'quality',
162
+ turboWhileMoving: props.turboWhileMoving ?? (performanceMode === 'performance'),
163
+ },
164
+ });
165
+ }, [sendToWebView, props.zoomEnabled, props.scrollEnabled, props.theme, props.center, props.zoom, props.minZoom, props.maxZoom, props.mapStyle, performanceMode, props.pixelRatio, fallbackPixelRatio, props.turboWhileMoving]);
166
+
167
+ const addMarker = useCallback((propsMarker: MarkerProps) => {
168
+ if (propsMarker.latitude && propsMarker.longitude) {
169
+ coordsInMapRef.current[propsMarker.uniqueId] = [[propsMarker.longitude, propsMarker.latitude]];
170
+ }
171
+
172
+ if (propsMarker.onPress) {
173
+ markersClickHandlers.current[propsMarker.uniqueId] = propsMarker.onPress;
174
+ } else {
175
+ delete markersClickHandlers.current[propsMarker.uniqueId];
176
+ }
177
+
178
+ sendToWebView({ function: 'addMarker', params: propsMarker });
179
+ }, [sendToWebView]);
180
+
181
+ const removeMarker = useCallback((propsMarker: MarkerProps) => {
182
+ delete coordsInMapRef.current[propsMarker.uniqueId];
183
+ delete markersClickHandlers.current[propsMarker.uniqueId];
184
+ sendToWebView({ function: 'removeMarker', params: propsMarker });
185
+ }, [sendToWebView]);
186
+
187
+ const addPolyline = useCallback((propsPolyline: PolylineProps) => {
188
+ if (propsPolyline.coordinates) {
189
+ coordsInMapRef.current[propsPolyline.uniqueId] = propsPolyline.coordinates;
190
+ }
191
+ sendToWebView({ function: 'addPolyline', params: propsPolyline });
192
+ }, [sendToWebView]);
193
+
194
+ const removePolyline = useCallback((propsPolyline: PolylineProps) => {
195
+ delete coordsInMapRef.current[propsPolyline.uniqueId];
196
+ sendToWebView({ function: 'removePolyline', params: propsPolyline });
197
+ }, [sendToWebView]);
198
+
199
+ const addPolygon = useCallback((propsPolygon: PolygonProps) => {
200
+ if (propsPolygon.coordinates) {
201
+ coordsInMapRef.current[propsPolygon.uniqueId] = propsPolygon.coordinates;
202
+ }
203
+ sendToWebView({ function: 'addPolygon', params: propsPolygon });
204
+ }, [sendToWebView]);
205
+
206
+ const removePolygon = useCallback((propsPolygon: PolygonProps) => {
207
+ delete coordsInMapRef.current[propsPolygon.uniqueId];
208
+ sendToWebView({ function: 'removePolygon', params: propsPolygon });
209
+ }, [sendToWebView]);
210
+
211
+ const fitBounds = useCallback(() => {
212
+ const coords = Object.values(coordsInMapRef.current).flat();
213
+ if (coords.length === 0) return;
214
+
215
+ const bounds = getBoundsFromCoords(coords);
216
+ sendToWebView({ function: 'fitBounds', params: { bounds } });
217
+ }, [sendToWebView]);
218
+
219
+ useImperativeHandle(ref, () => ({
220
+ fitBounds,
221
+ }), [fitBounds]);
222
+
223
+ useEffect(() => {
224
+ if (html) return;
225
+ maplibreHtmlMap(webFunctionsString, props.sources).then(setHtml);
226
+ }, [html, props.sources]);
227
+
228
+ const onReceiveMessageFromWebView = useCallback((data: string) => {
229
+ try {
230
+ const msg = JSON.parse(data);
231
+
232
+ if (msg.type === 'event') {
233
+ switch (msg.event) {
234
+ case 'movestart':
235
+ mapSelectPointRef.current?.up();
236
+ props.onMoveStart?.(msg.params);
237
+ break;
238
+ case 'moveend':
239
+ props.onMoveEnd?.(msg.params);
240
+ mapSelectPointRef.current?.down();
241
+ break;
242
+ case 'zoomstart':
243
+ props.onZoomStart?.(msg.params);
244
+ break;
245
+ case 'zoomend':
246
+ props.onZoomEnd?.(msg.params);
247
+ break;
248
+ case 'idle':
249
+ props.onIdle?.(msg.params);
250
+ break;
251
+ }
252
+ return;
253
+ }
254
+
255
+ if (msg.type === 'inited') {
256
+ setInited(true);
257
+ return;
258
+ }
259
+
260
+ if (msg.type === 'scriptReady') {
261
+ initMap();
262
+ return;
263
+ }
264
+
265
+ if (msg.type === 'markerClick') {
266
+ const handler = markersClickHandlers.current[msg.uniqueId];
267
+ if (typeof handler === 'function') {
268
+ handler();
269
+ }
270
+ return;
271
+ }
272
+ } catch (e) {
273
+ if (__DEV__) {
274
+ console.warn('MapView: failed to parse WebView message', e);
275
+ }
276
+ }
277
+ }, [props.onMoveStart, props.onMoveEnd, props.onZoomStart, props.onZoomEnd, props.onIdle, initMap]);
278
+
279
+ return (
280
+ <View style={props.style}>
281
+ {!inited && (
282
+ <MapPlaceholder theme={props.theme} />
283
+ )}
284
+
285
+ <MapViewContext.Provider
286
+ value={{
287
+ addPolygon,
288
+ removePolygon,
289
+ addMarker,
290
+ removeMarker,
291
+ addPolyline,
292
+ removePolyline,
293
+ }}
294
+ >
295
+ <WebView
296
+ ref={webViewRef}
297
+ style={{ flex: 1, backgroundColor: 'transparent' }}
298
+ originWhitelist={['*']}
299
+ source={{ html }}
300
+ onMessage={event => {
301
+ onReceiveMessageFromWebView(event.nativeEvent.data);
302
+ }}
303
+ javaScriptEnabled
304
+ domStorageEnabled
305
+ scrollEnabled={false}
306
+ />
307
+
308
+ {inited && props.children}
309
+
310
+ {inited && props.showSelectPoint && (
311
+ <View
312
+ pointerEvents="none"
313
+ style={{
314
+ justifyContent: 'center',
315
+ alignItems: 'center',
316
+ position: 'absolute',
317
+ top: 0,
318
+ left: 0,
319
+ width: '100%',
320
+ height: '100%',
321
+ }}
322
+ >
323
+ <MapSelectPoint
324
+ ref={mapSelectPointRef}
325
+ color={props.selectPointColor ?? '#000'}
326
+ backgroundColor={props.selectPointBackgroundColor ?? '#fff'}
327
+ />
328
+ </View>
329
+ )}
330
+ </MapViewContext.Provider>
331
+ </View>
332
+ );
333
+ });
@@ -0,0 +1,31 @@
1
+ import {
2
+ useEffect,
3
+ useRef,
4
+ } from 'react';
5
+
6
+ import { useMapViewContext } from './MapView';
7
+ import { type MarkerProps } from './types';
8
+
9
+ export const Marker = (props: MarkerProps) => {
10
+ const { addMarker, removeMarker } = useMapViewContext();
11
+
12
+ const lastRenderProps = useRef<string>('');
13
+ const propsRef = useRef(props);
14
+ propsRef.current = props;
15
+
16
+ useEffect(() => {
17
+ const serialized = JSON.stringify(props);
18
+ if (lastRenderProps.current !== serialized) {
19
+ addMarker(props);
20
+ lastRenderProps.current = serialized;
21
+ }
22
+ }, [props, addMarker]);
23
+
24
+ useEffect(() => {
25
+ return () => {
26
+ removeMarker(propsRef.current);
27
+ };
28
+ }, [removeMarker]);
29
+
30
+ return null;
31
+ };
@@ -0,0 +1,31 @@
1
+ import {
2
+ useEffect,
3
+ useRef,
4
+ } from 'react';
5
+
6
+ import { useMapViewContext } from './MapView';
7
+ import { type PolygonProps } from './types';
8
+
9
+ export const Polygon = (props: PolygonProps) => {
10
+ const { addPolygon, removePolygon } = useMapViewContext();
11
+
12
+ const lastRenderProps = useRef<string>('');
13
+ const propsRef = useRef(props);
14
+ propsRef.current = props;
15
+
16
+ useEffect(() => {
17
+ const serialized = JSON.stringify(props);
18
+ if (lastRenderProps.current !== serialized) {
19
+ addPolygon(props);
20
+ lastRenderProps.current = serialized;
21
+ }
22
+ }, [props, addPolygon]);
23
+
24
+ useEffect(() => {
25
+ return () => {
26
+ removePolygon(propsRef.current);
27
+ };
28
+ }, [removePolygon]);
29
+
30
+ return null;
31
+ };
@@ -0,0 +1,31 @@
1
+ import {
2
+ useEffect,
3
+ useRef,
4
+ } from 'react';
5
+
6
+ import { useMapViewContext } from './MapView';
7
+ import type { PolylineProps } from './types';
8
+
9
+ export const Polyline = (props: PolylineProps) => {
10
+ const { addPolyline, removePolyline } = useMapViewContext();
11
+
12
+ const lastRenderProps = useRef<string>('');
13
+ const propsRef = useRef(props);
14
+ propsRef.current = props;
15
+
16
+ useEffect(() => {
17
+ const serialized = JSON.stringify(props);
18
+ if (lastRenderProps.current !== serialized) {
19
+ addPolyline(props);
20
+ lastRenderProps.current = serialized;
21
+ }
22
+ }, [props, addPolyline]);
23
+
24
+ useEffect(() => {
25
+ return () => {
26
+ removePolyline(propsRef.current);
27
+ };
28
+ }, [removePolyline]);
29
+
30
+ return null;
31
+ };
@@ -0,0 +1,46 @@
1
+
2
+ export type MarkerProps = {
3
+ uniqueId: string,
4
+ onPress?: () => void,
5
+ latitude: number,
6
+ longitude: number,
7
+ color?: string,
8
+
9
+ iconUrl?: string,
10
+ iconWidth?: number,
11
+ iconHeight?: number,
12
+
13
+ }
14
+
15
+ export type SourcesProps = {
16
+ maplibreJS: string;
17
+ maplibreCSS: string;
18
+ pmtilesJS: string;
19
+ }
20
+
21
+ export type PolygonProps = {
22
+ uniqueId: string,
23
+ coordinates: [number, number][],
24
+ fillColor?: string,
25
+ fillOpacity?: number,
26
+ strokeColor?: string,
27
+ strokeOpacity?: number,
28
+ strokeWidth?: number,
29
+
30
+ }
31
+
32
+ export type PolylineProps = {
33
+ uniqueId: string,
34
+ color?: string,
35
+ width?: number,
36
+ coordinates: [number, number][],
37
+
38
+ }
39
+
40
+ export type EventParams = {
41
+ center?: {
42
+ lng: number,
43
+ lat: number
44
+ },
45
+ zoom?: number
46
+ }
@@ -0,0 +1,54 @@
1
+ export default /*js*/`
2
+
3
+ if(functionName === 'addMarker') {
4
+
5
+
6
+ if(markers[params.uniqueId]){
7
+ markers[params.uniqueId].remove();
8
+ delete markers[params.uniqueId];
9
+ }
10
+
11
+
12
+ if(!params?.iconUrl){
13
+
14
+
15
+ markers[params.uniqueId] = new maplibregl.Marker({
16
+ color: params.color ?? undefined,
17
+ }).setLngLat([params.longitude, params.latitude])
18
+ .addTo(map);
19
+ markers[params.uniqueId].getElement().addEventListener('click', function() {
20
+ window.ReactNativeWebView.postMessage(JSON.stringify({
21
+ type: 'markerClick',
22
+ uniqueId: params.uniqueId
23
+ }));
24
+ });
25
+
26
+ return;
27
+
28
+ }else{
29
+
30
+
31
+ const el = document.createElement('div');
32
+ el.className = 'marker';
33
+ el.style.backgroundImage = 'url(' + params.iconUrl + ')';
34
+ el.style.width = params.iconWidth + 'px';
35
+ el.style.height = params.iconHeight + 'px';
36
+
37
+ el.addEventListener('click', () => {
38
+ window.ReactNativeWebView.postMessage(JSON.stringify({
39
+ type: 'markerClick',
40
+ uniqueId: params.uniqueId
41
+ }));
42
+ });
43
+
44
+
45
+ markers[params.uniqueId] = new maplibregl.Marker({element: el})
46
+ .setLngLat([params.longitude, params.latitude])
47
+ .addTo(map);
48
+
49
+ return;
50
+
51
+ }
52
+ }
53
+
54
+ `;