@maplibre/maplibre-react-native 10.0.0-alpha.6 → 10.0.0-alpha.8

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 (113) hide show
  1. package/.eslintrc.js +3 -1
  2. package/.yarn/sdks/eslint/bin/eslint.js +8 -1
  3. package/.yarn/sdks/eslint/lib/api.js +8 -1
  4. package/.yarn/sdks/eslint/lib/unsupported-api.js +8 -1
  5. package/.yarn/sdks/prettier/bin/prettier.cjs +8 -1
  6. package/.yarn/sdks/prettier/index.cjs +8 -1
  7. package/.yarn/sdks/typescript/bin/tsc +8 -1
  8. package/.yarn/sdks/typescript/bin/tsserver +8 -1
  9. package/.yarn/sdks/typescript/lib/tsc.js +8 -1
  10. package/.yarn/sdks/typescript/lib/tsserver.js +20 -6
  11. package/.yarn/sdks/typescript/lib/tsserverlibrary.js +20 -6
  12. package/.yarn/sdks/typescript/lib/typescript.js +8 -1
  13. package/CHANGELOG.md +7 -0
  14. package/CONTRIBUTING.md +10 -9
  15. package/android/build.gradle +1 -1
  16. package/android/rctmln/build.gradle +5 -5
  17. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/MarkerView.java +2 -2
  18. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/MarkerViewManager.java +6 -6
  19. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/RCTMLNMarkerView.java +5 -5
  20. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/RCTMLNPointAnnotation.java +9 -8
  21. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/camera/CameraStop.java +14 -12
  22. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/camera/CameraUpdateItem.java +10 -10
  23. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/camera/CameraUpdateQueue.java +1 -1
  24. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/camera/RCTMLNCamera.java +26 -26
  25. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/camera/RCTMLNCameraManager.java +1 -1
  26. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/images/RCTMLNImages.java +12 -12
  27. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/location/LocationComponentManager.java +9 -9
  28. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/location/RCTMLNNativeUserLocation.java +7 -7
  29. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/location/RCTMLNNativeUserLocationManager.java +1 -1
  30. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/LayerSourceInfo.java +9 -9
  31. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNAndroidTextureMapView.java +2 -2
  32. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNAndroidTextureMapViewManager.java +2 -2
  33. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNMapView.java +43 -43
  34. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNMapViewManager.java +6 -6
  35. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/RCTMLNStyle.java +3 -3
  36. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/RCTMLNStyleFactory.java +14 -14
  37. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/RCTMLNStyleFunctionParser.java +2 -2
  38. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/RCTMLNStyleValue.java +2 -2
  39. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTLayer.java +8 -8
  40. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNBackgroundLayer.java +1 -1
  41. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNCircleLayer.java +2 -2
  42. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNFillExtrusionLayer.java +2 -2
  43. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNFillLayer.java +2 -2
  44. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNHeatmapLayer.java +2 -2
  45. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNLineLayer.java +2 -2
  46. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNRasterLayer.java +1 -1
  47. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/layers/RCTMLNSymbolLayer.java +2 -2
  48. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/light/RCTMLNLight.java +6 -6
  49. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNImageSource.java +3 -3
  50. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNImageSourceManager.java +1 -1
  51. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNRasterSource.java +3 -3
  52. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNShapeSource.java +9 -9
  53. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNShapeSourceManager.java +1 -1
  54. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNTileSource.java +2 -2
  55. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTMLNVectorSource.java +4 -4
  56. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/styles/sources/RCTSource.java +7 -7
  57. package/android/rctmln/src/main/java/com/maplibre/rctmln/events/FeatureClickEvent.java +2 -2
  58. package/android/rctmln/src/main/java/com/maplibre/rctmln/events/MapClickEvent.java +1 -1
  59. package/android/rctmln/src/main/java/com/maplibre/rctmln/events/PointAnnotationClickEvent.java +2 -2
  60. package/android/rctmln/src/main/java/com/maplibre/rctmln/events/PointAnnotationDragEvent.java +2 -2
  61. package/android/rctmln/src/main/java/com/maplibre/rctmln/location/LocationManager.java +6 -6
  62. package/android/rctmln/src/main/java/com/maplibre/rctmln/location/UserLocation.java +1 -1
  63. package/android/rctmln/src/main/java/com/maplibre/rctmln/location/UserTrackingMode.java +3 -3
  64. package/android/rctmln/src/main/java/com/maplibre/rctmln/modules/RCTMLNLocationModule.java +2 -2
  65. package/android/rctmln/src/main/java/com/maplibre/rctmln/modules/RCTMLNLogging.java +2 -2
  66. package/android/rctmln/src/main/java/com/maplibre/rctmln/modules/RCTMLNModule.java +8 -8
  67. package/android/rctmln/src/main/java/com/maplibre/rctmln/modules/RCTMLNOfflineModule.java +11 -11
  68. package/android/rctmln/src/main/java/com/maplibre/rctmln/modules/RCTMLNSnapshotModule.java +7 -7
  69. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/ClusterPropertyEntry.java +1 -1
  70. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/DownloadMapImageTask.java +5 -5
  71. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/ExpressionParser.java +2 -2
  72. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/GeoJSONUtils.java +13 -13
  73. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/GeoViewport.java +3 -3
  74. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/SimpleEventCallback.java +2 -2
  75. package/android/rctmln/src/main/java/com/maplibre/rctmln/utils/SphericalMercator.java +1 -1
  76. package/docs/Camera.md +3 -3
  77. package/docs/MapView.md +9 -33
  78. package/docs/UserLocation.md +10 -2
  79. package/docs/docs.json +16 -31
  80. package/javascript/Maplibre.ts +5 -1
  81. package/javascript/components/BackgroundLayer.tsx +27 -20
  82. package/javascript/components/Callout.tsx +40 -40
  83. package/javascript/components/Camera.tsx +421 -478
  84. package/javascript/components/CircleLayer.tsx +29 -22
  85. package/javascript/components/FillExtrusionLayer.tsx +23 -23
  86. package/javascript/components/FillLayer.tsx +22 -19
  87. package/javascript/components/HeatmapLayer.tsx +21 -19
  88. package/javascript/components/ImageSource.tsx +25 -32
  89. package/javascript/components/Images.tsx +36 -35
  90. package/javascript/components/Light.tsx +20 -47
  91. package/javascript/components/LineLayer.tsx +23 -20
  92. package/javascript/components/MapView.tsx +604 -554
  93. package/javascript/components/MarkerView.tsx +23 -38
  94. package/javascript/components/NativeUserLocation.tsx +3 -5
  95. package/javascript/components/PointAnnotation.tsx +111 -87
  96. package/javascript/components/RasterLayer.tsx +21 -18
  97. package/javascript/components/RasterSource.tsx +39 -42
  98. package/javascript/components/ShapeSource.tsx +287 -239
  99. package/javascript/components/Style.tsx +1 -1
  100. package/javascript/components/SymbolLayer.tsx +34 -28
  101. package/javascript/components/UserLocation.tsx +164 -151
  102. package/javascript/components/VectorSource.tsx +128 -117
  103. package/javascript/components/annotations/Annotation.tsx +105 -79
  104. package/javascript/{components/AbstractLayer.tsx → hooks/useAbstractLayer.ts} +54 -37
  105. package/javascript/hooks/useAbstractSource.ts +34 -0
  106. package/javascript/hooks/useNativeBridge.ts +125 -0
  107. package/javascript/hooks/useNativeRef.ts +13 -0
  108. package/javascript/hooks/useOnce.ts +12 -0
  109. package/javascript/utils/Logger.ts +3 -3
  110. package/package.json +2 -1
  111. package/scripts/templates/RCTMLNStyleFactory.java.ejs +14 -14
  112. package/javascript/components/AbstractSource.tsx +0 -27
  113. package/javascript/components/NativeBridgeComponent.tsx +0 -117
@@ -1,7 +1,9 @@
1
1
  import {type SymbolLayerStyleProps} from '../utils/MaplibreStyles';
2
2
  import BaseProps from '../types/BaseProps';
3
-
4
- import AbstractLayer, {BaseLayerProps, NativeBaseProps} from './AbstractLayer';
3
+ import useAbstractLayer, {
4
+ BaseLayerProps,
5
+ NativeBaseProps,
6
+ } from '../hooks/useAbstractLayer';
5
7
 
6
8
  import React, {ReactElement} from 'react';
7
9
  import {View, NativeModules, requireNativeComponent} from 'react-native';
@@ -10,7 +12,7 @@ const MapLibreGL = NativeModules.MLNModule;
10
12
 
11
13
  export const NATIVE_MODULE_NAME = 'RCTMLNSymbolLayer';
12
14
 
13
- interface SymbolLayerProps extends BaseProps, BaseLayerProps {
15
+ export interface SymbolLayerProps extends BaseProps, BaseLayerProps {
14
16
  /**
15
17
  * Customizable style attributes
16
18
  */
@@ -27,46 +29,50 @@ interface NativeProps extends Omit<SymbolLayerProps, 'style'>, NativeBaseProps {
27
29
  snapshot: boolean;
28
30
  }
29
31
 
32
+ const RCTMLNSymbolLayer =
33
+ requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
34
+
30
35
  /**
31
36
  * SymbolLayer is a style layer that renders icon and text labels at points or along lines on the map.
32
37
  */
33
- class SymbolLayer extends AbstractLayer<SymbolLayerProps, NativeBaseProps> {
34
- static defaultProps = {
35
- sourceID: MapLibreGL.StyleSource.DefaultSourceID,
36
- };
37
-
38
- _shouldSnapshot(): boolean {
38
+ const SymbolLayer: React.FC<SymbolLayerProps> = ({
39
+ sourceID = MapLibreGL.StyleSource.DefaultSourceID,
40
+ ...props
41
+ }: SymbolLayerProps) => {
42
+ const {baseProps, setNativeLayer} = useAbstractLayer<
43
+ SymbolLayerProps,
44
+ NativeBaseProps
45
+ >({
46
+ ...props,
47
+ sourceID,
48
+ });
49
+
50
+ const _shouldSnapshot = (): boolean => {
39
51
  let isSnapshot = false;
40
52
 
41
- if (React.Children.count(this.props.children) <= 0) {
53
+ if (React.Children.count(props.children) <= 0) {
42
54
  return isSnapshot;
43
55
  }
44
56
 
45
- React.Children.forEach(this.props.children, child => {
57
+ React.Children.forEach(props.children, child => {
46
58
  if (child?.type === View) {
47
59
  isSnapshot = true;
48
60
  }
49
61
  });
50
62
 
51
63
  return isSnapshot;
52
- }
53
-
54
- render(): ReactElement {
55
- const props = {
56
- ...this.baseProps,
57
- snapshot: this._shouldSnapshot(),
58
- sourceLayerID: this.props.sourceLayerID,
59
- };
64
+ };
60
65
 
61
- return (
62
- <RCTMLNSymbolLayer ref={this.setNativeLayer} {...props}>
63
- {this.props.children}
64
- </RCTMLNSymbolLayer>
65
- );
66
- }
67
- }
66
+ const updatedProps = {
67
+ ...baseProps,
68
+ snapshot: _shouldSnapshot(),
69
+ };
68
70
 
69
- const RCTMLNSymbolLayer =
70
- requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
71
+ return (
72
+ <RCTMLNSymbolLayer ref={setNativeLayer} {...updatedProps}>
73
+ {props.children}
74
+ </RCTMLNSymbolLayer>
75
+ );
76
+ };
71
77
 
72
78
  export default SymbolLayer;
@@ -6,7 +6,7 @@ import CircleLayer from './CircleLayer';
6
6
  import HeadingIndicator from './HeadingIndicator';
7
7
  import NativeUserLocation from './NativeUserLocation';
8
8
 
9
- import React, {ReactElement} from 'react';
9
+ import React, {ReactElement, useEffect, useImperativeHandle} from 'react';
10
10
 
11
11
  const mapboxBlue = 'rgba(51, 181, 229, 100)';
12
12
 
@@ -113,164 +113,177 @@ export enum UserLocationRenderMode {
113
113
  Normal = 'normal',
114
114
  }
115
115
 
116
- class UserLocation extends React.Component<
117
- UserLocationProps,
118
- UserLocationState
119
- > {
120
- static defaultProps = {
121
- animated: true,
122
- visible: true,
123
- showsUserHeadingIndicator: false,
124
- minDisplacement: 0,
125
- renderMode: 'normal',
126
- };
127
-
128
- constructor(props: UserLocationProps) {
129
- super(props);
130
-
131
- this.state = {
132
- shouldShowUserLocation: false,
133
- };
134
-
135
- this._onLocationUpdate = this._onLocationUpdate.bind(this);
136
- }
137
-
138
- // required as #setLocationManager attempts to setState
139
- // after component unmount
140
- _isMounted: boolean | null = null;
141
-
142
- renderMode: UserLocationRenderMode | undefined;
143
- locationManagerRunning = false;
144
-
145
- async componentDidMount(): Promise<void> {
146
- this._isMounted = true;
116
+ export interface UserLocationRef {
117
+ setLocationManager: (props: {running: boolean}) => Promise<void>;
118
+ needsLocationManagerRunning: () => boolean;
119
+ _onLocationUpdate: (location: Location | null) => void;
120
+ }
147
121
 
148
- await this.setLocationManager({
149
- running: this.needsLocationManagerRunning(),
150
- });
122
+ const UserLocation = React.memo(
123
+ React.forwardRef<UserLocationRef, UserLocationProps>(
124
+ (
125
+ {
126
+ animated = true,
127
+ visible = true,
128
+ showsUserHeadingIndicator = false,
129
+ minDisplacement = 0,
130
+ renderMode = 'normal',
131
+ androidRenderMode,
132
+ children,
133
+ onUpdate,
134
+ onPress,
135
+ }: UserLocationProps,
136
+ ref,
137
+ ) => {
138
+ const _isMounted = React.useRef<boolean | null>(null);
139
+ const locationManagerRunning = React.useRef<boolean>(false);
140
+
141
+ const [userLocationState, setUserLocationState] =
142
+ React.useState<UserLocationState>({
143
+ shouldShowUserLocation: false,
144
+ });
145
+
146
+ useImperativeHandle(
147
+ ref,
148
+ (): UserLocationRef => ({
149
+ /**
150
+ * Whether to start or stop listening to the locationManager
151
+ *
152
+ * Notice, that listening will start automatically when
153
+ * either `onUpdate` or `visible` are set
154
+ *
155
+ * @async
156
+ * @param {Object} running - Object with key `running` and `boolean` value
157
+ * @return {Promise<void>}
158
+ */
159
+ setLocationManager,
160
+ /**
161
+ *
162
+ * If locationManager should be running
163
+ *
164
+ * @return {boolean}
165
+ */
166
+ needsLocationManagerRunning,
167
+ _onLocationUpdate,
168
+ }),
169
+ );
170
+
171
+ useEffect(() => {
172
+ _isMounted.current = true;
173
+
174
+ setLocationManager({
175
+ running: needsLocationManagerRunning(),
176
+ }).then(() => {
177
+ if (renderMode === UserLocationRenderMode.Native) {
178
+ return;
179
+ }
180
+
181
+ locationManager.setMinDisplacement(minDisplacement ?? 0);
182
+ });
183
+
184
+ return (): void => {
185
+ _isMounted.current = false;
186
+ setLocationManager({running: false});
187
+ };
188
+ // eslint-disable-next-line react-hooks/exhaustive-deps
189
+ }, []);
190
+
191
+ useEffect(() => {
192
+ locationManager.setMinDisplacement(minDisplacement ?? 0);
193
+ }, [minDisplacement]);
194
+
195
+ useEffect(() => {
196
+ if (!_isMounted.current) {
197
+ return;
198
+ }
199
+
200
+ setLocationManager({
201
+ running: needsLocationManagerRunning(),
202
+ });
203
+ });
204
+
205
+ async function setLocationManager({
206
+ running,
207
+ }: {
208
+ running: boolean;
209
+ }): Promise<void> {
210
+ if (locationManagerRunning.current !== running) {
211
+ locationManagerRunning.current = running;
212
+
213
+ if (running) {
214
+ locationManager.addListener(_onLocationUpdate);
215
+ const location = await locationManager.getLastKnownLocation();
216
+ _onLocationUpdate(location);
217
+ } else {
218
+ locationManager.removeListener(_onLocationUpdate);
219
+ }
220
+ }
221
+ }
151
222
 
152
- if (this.renderMode === UserLocationRenderMode.Native) {
153
- return;
154
- }
223
+ function needsLocationManagerRunning(): boolean {
224
+ return !!(
225
+ !!onUpdate ||
226
+ (renderMode === UserLocationRenderMode.Normal && visible)
227
+ );
228
+ }
155
229
 
156
- locationManager.setMinDisplacement(this.props.minDisplacement ?? 0);
157
- }
230
+ function _onLocationUpdate(location: Location | null): void {
231
+ if (!_isMounted.current || !location) {
232
+ return;
233
+ }
234
+
235
+ let coordinates;
236
+ let heading;
237
+
238
+ if (location && location.coords) {
239
+ const {longitude, latitude} = location.coords;
240
+ heading = location.coords.heading;
241
+ coordinates = [longitude, latitude];
242
+ }
243
+
244
+ setUserLocationState({
245
+ ...userLocationState,
246
+ coordinates,
247
+ heading,
248
+ });
249
+
250
+ if (onUpdate) {
251
+ onUpdate(location);
252
+ }
253
+ }
158
254
 
159
- async componentDidUpdate(prevProps: UserLocationProps): Promise<void> {
160
- await this.setLocationManager({
161
- running: this.needsLocationManagerRunning(),
162
- });
255
+ if (!visible) {
256
+ return null;
257
+ }
163
258
 
164
- if (this.props.minDisplacement !== prevProps.minDisplacement) {
165
- locationManager.setMinDisplacement(this.props.minDisplacement ?? 0);
166
- }
167
- }
259
+ if (renderMode === UserLocationRenderMode.Native) {
260
+ const props = {
261
+ androidRenderMode,
262
+ iosShowsUserHeadingIndicator: showsUserHeadingIndicator,
263
+ };
168
264
 
169
- async componentWillUnmount(): Promise<void> {
170
- this._isMounted = false;
171
- await this.setLocationManager({running: false});
172
- }
265
+ return <NativeUserLocation {...props} />;
266
+ }
173
267
 
174
- /**
175
- * Whether to start or stop listening to the locationManager
176
- *
177
- * Notice, that listening will start automatically when
178
- * either `onUpdate` or `visible` are set
179
- *
180
- * @async
181
- * @param {Object} running - Object with key `running` and `boolean` value
182
- * @return {Promise<void>}
183
- */
184
- async setLocationManager({running}: {running: boolean}): Promise<void> {
185
- if (this.locationManagerRunning !== running) {
186
- this.locationManagerRunning = running;
187
- if (running) {
188
- locationManager.addListener(this._onLocationUpdate);
189
- const location = await locationManager.getLastKnownLocation();
190
- this._onLocationUpdate(location);
191
- } else {
192
- locationManager.removeListener(this._onLocationUpdate);
268
+ if (!userLocationState.coordinates) {
269
+ return null;
193
270
  }
194
- }
195
- }
196
271
 
197
- /**
198
- *
199
- * If locationManager should be running
200
- *
201
- * @return {boolean}
202
- */
203
- needsLocationManagerRunning(): boolean {
204
- return !!(
205
- !!this.props.onUpdate ||
206
- (this.props.renderMode === UserLocationRenderMode.Normal &&
207
- this.props.visible)
208
- );
209
- }
210
-
211
- _onLocationUpdate(location: Location | null): void {
212
- if (!this._isMounted || !location) {
213
- return;
214
- }
215
- let coordinates;
216
- let heading;
217
-
218
- if (location && location.coords) {
219
- const {longitude, latitude} = location.coords;
220
- heading = location.coords.heading;
221
- coordinates = [longitude, latitude];
222
- }
223
-
224
- this.setState({
225
- coordinates,
226
- heading,
227
- });
228
-
229
- if (this.props.onUpdate) {
230
- this.props.onUpdate(location);
231
- }
232
- }
233
-
234
- _renderNative(): ReactElement {
235
- const {androidRenderMode, showsUserHeadingIndicator} = this.props;
236
-
237
- const props = {
238
- androidRenderMode,
239
- iosShowsUserHeadingIndicator: showsUserHeadingIndicator,
240
- };
241
- return <NativeUserLocation {...props} />;
242
- }
243
-
244
- render(): ReactElement | null {
245
- const {heading, coordinates} = this.state;
246
- const {children, visible, showsUserHeadingIndicator, onPress, animated} =
247
- this.props;
248
-
249
- if (!visible) {
250
- return null;
251
- }
252
-
253
- if (this.props.renderMode === UserLocationRenderMode.Native) {
254
- return this._renderNative();
255
- }
256
-
257
- if (!coordinates) {
258
- return null;
259
- }
260
-
261
- return (
262
- <Annotation
263
- animated={animated}
264
- id="mapboxUserLocation"
265
- onPress={onPress}
266
- coordinates={coordinates}
267
- style={{
268
- iconRotate: heading,
269
- }}>
270
- {children || normalIcon(showsUserHeadingIndicator, heading)}
271
- </Annotation>
272
- );
273
- }
274
- }
272
+ return (
273
+ <Annotation
274
+ animated={animated}
275
+ id="mapboxUserLocation"
276
+ onPress={onPress}
277
+ coordinates={userLocationState.coordinates}
278
+ style={{
279
+ iconRotate: userLocationState.heading,
280
+ }}>
281
+ {children ||
282
+ normalIcon(showsUserHeadingIndicator, userLocationState.heading)}
283
+ </Annotation>
284
+ );
285
+ },
286
+ ),
287
+ );
275
288
 
276
289
  export default UserLocation;
@@ -4,13 +4,11 @@ import {getFilter} from '../utils/filterUtils';
4
4
  import {copyPropertiesAsDeprecated} from '../utils/deprecation';
5
5
  import BaseProps from '../types/BaseProps';
6
6
  import OnPressEvent from '../types/OnPressEvent';
7
+ import useAbstractSource from '../hooks/useAbstractSource';
8
+ import useNativeBridge from '../hooks/useNativeBridge';
7
9
 
8
- import AbstractSource from './AbstractSource';
9
- import NativeBridgeComponent from './NativeBridgeComponent';
10
-
11
- import React, {Component, ReactNode} from 'react';
10
+ import React, {memo, useImperativeHandle} from 'react';
12
11
  import {
13
- NativeMethods,
14
12
  NativeModules,
15
13
  NativeSyntheticEvent,
16
14
  requireNativeComponent,
@@ -85,123 +83,136 @@ interface VectorSourceProps extends BaseProps {
85
83
 
86
84
  type NativeProps = VectorSourceProps;
87
85
 
86
+ const RCTMLNVectorSource =
87
+ requireNativeComponent<VectorSourceProps>(NATIVE_MODULE_NAME);
88
+
88
89
  /**
89
90
  * VectorSource is a map content source that supplies tiled vector data in Mapbox Vector Tile format to be shown on the map.
90
91
  * The location of and metadata about the tiles are defined either by an option dictionary or by an external file that conforms to the TileJSON specification.
91
92
  */
92
- class VectorSource extends NativeBridgeComponent(
93
- AbstractSource<VectorSourceProps, NativeProps>,
94
- NATIVE_MODULE_NAME,
95
- ) {
96
- static defaultProps = {
97
- id: MapLibreGL.StyleSource.DefaultSourceID,
98
- };
99
-
100
- constructor(props: VectorSourceProps) {
101
- super(props);
102
- }
103
-
104
- _setNativeRef(
105
- nativeRef: (Component<NativeProps> & Readonly<NativeMethods>) | null,
106
- ): void {
107
- if (nativeRef) {
108
- this.setNativeRef(nativeRef);
109
- super._runPendingNativeCommands(nativeRef);
110
- }
111
- }
112
-
113
- /**
114
- * Returns all features that match the query parameters regardless of whether or not the feature is
115
- * currently rendered on the map. The domain of the query includes all currently-loaded vector tiles
116
- * and GeoJSON source tiles. This function does not check tiles outside of the visible viewport.
117
- *
118
- * @example
119
- * vectorSource.features(['id1', 'id2'])
120
- *
121
- * @param {Array=} layerIDs - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array.
122
- * @param {Array=} filter - an optional filter statement to filter the returned Features.
123
- * @return {GeoJSON.FeatureCollection}
124
- */
125
- async features(
126
- layerIDs = [],
127
- filter?: FilterExpression,
128
- ): Promise<GeoJSON.FeatureCollection> {
129
- if (!this._nativeRef) {
130
- return featureCollection([]);
131
- }
132
- const res: {data: string | GeoJSON.FeatureCollection} =
133
- await this._runNativeCommand('features', this._nativeRef, [
134
- [[layerIDs, getFilter(filter)]],
135
- ]);
136
-
137
- if (isAndroid()) {
138
- return JSON.parse(res?.data as string);
139
- }
140
-
141
- return res.data as GeoJSON.FeatureCollection;
142
- }
143
-
144
- onPress(event: NativeSyntheticEvent<{payload: OnPressEvent}>): void {
145
- const {onPress} = this.props;
146
-
147
- if (!onPress) {
148
- return;
149
- }
150
- const {
151
- nativeEvent: {
152
- payload: {features, coordinates, point},
153
- },
154
- } = event;
155
- let newEvent = {
156
- features,
157
- coordinates,
158
- point,
159
- };
160
- newEvent = copyPropertiesAsDeprecated(
161
- event,
162
- newEvent,
163
- (key: string) => {
164
- console.warn(
165
- `event.${key} is deprecated on VectorSource#onPress, please use event.features`,
166
- );
167
- },
93
+ const VectorSource = memo(
94
+ React.forwardRef(
95
+ (
168
96
  {
169
- nativeEvent: (origNativeEvent: OnPressEvent) => ({
170
- ...origNativeEvent,
171
- payload: features[0],
172
- }),
173
- },
174
- );
175
-
176
- onPress(newEvent);
177
- }
178
-
179
- render(): ReactNode {
180
- const props = {
181
- id: this.props.id,
182
- url: this.props.url,
183
- tileUrlTemplates: this.props.tileUrlTemplates,
184
- minZoomLevel: this.props.minZoomLevel,
185
- maxZoomLevel: this.props.maxZoomLevel,
186
- tms: this.props.tms,
187
- attribution: this.props.attribution,
188
- hitbox: this.props.hitbox,
189
- hasPressListener: isFunction(this.props.onPress),
190
- onMapboxVectorSourcePress: this.onPress.bind(this),
191
- onPress: undefined,
192
- onAndroidCallback: isAndroid() ? this._onAndroidCallback : undefined,
193
- };
194
- return (
195
- <RCTMLNVectorSource ref={this.setNativeRef} {...props}>
196
- {cloneReactChildrenWithProps(this.props.children, {
197
- sourceID: this.props.id,
198
- })}
199
- </RCTMLNVectorSource>
200
- );
201
- }
202
- }
97
+ id = MapLibreGL.StyleSource.DefaultSourceID,
98
+ ...props
99
+ }: VectorSourceProps,
100
+ ref,
101
+ ) => {
102
+ // * exposes the methods of the function component so we don't break projects that depend on calling this methods
103
+ useImperativeHandle(ref, () => ({
104
+ /**
105
+ * Returns all features that match the query parameters regardless of whether or not the feature is
106
+ * currently rendered on the map. The domain of the query includes all currently-loaded vector tiles
107
+ * and GeoJSON source tiles. This function does not check tiles outside of the visible viewport.
108
+ *
109
+ * @example
110
+ * vectorSource.features(['id1', 'id2'])
111
+ *
112
+ * @param {Array=} layerIDs - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array.
113
+ * @param {Array=} filter - an optional filter statement to filter the returned Features.
114
+ * @return {GeoJSON.FeatureCollection}
115
+ */
116
+ features,
117
+ onPress,
118
+ }));
119
+
120
+ const {
121
+ _runNativeCommand,
122
+ // _runPendingNativeCommands,
123
+ _onAndroidCallback,
124
+ } = useNativeBridge(NATIVE_MODULE_NAME);
125
+ const {setNativeRef, _nativeRef} = useAbstractSource<NativeProps>();
126
+
127
+ // const _setNativeRef = (
128
+ // nativeRef: (Component<NativeProps> & Readonly<NativeMethods>) | null,
129
+ // ): void => {
130
+ // if (nativeRef) {
131
+ // setNativeRef(nativeRef);
132
+ // _runPendingNativeCommands(nativeRef);
133
+ // }
134
+ // };
135
+
136
+ const features = async (
137
+ layerIDs = [],
138
+ filter?: FilterExpression,
139
+ ): Promise<GeoJSON.FeatureCollection> => {
140
+ if (!_nativeRef) {
141
+ return featureCollection([]);
142
+ }
143
+ const res: {data: string | GeoJSON.FeatureCollection} =
144
+ await _runNativeCommand('features', _nativeRef, [
145
+ [[layerIDs, getFilter(filter)]],
146
+ ]);
147
+
148
+ if (isAndroid()) {
149
+ return JSON.parse(res?.data as string);
150
+ }
151
+
152
+ return res.data as GeoJSON.FeatureCollection;
153
+ };
154
+
155
+ const onPress = (
156
+ event: NativeSyntheticEvent<{payload: OnPressEvent}>,
157
+ ): void => {
158
+ const {onPress} = props;
159
+
160
+ if (!onPress) {
161
+ return;
162
+ }
163
+ const {
164
+ nativeEvent: {
165
+ payload: {features, coordinates, point},
166
+ },
167
+ } = event;
168
+ let newEvent = {
169
+ features,
170
+ coordinates,
171
+ point,
172
+ };
173
+ newEvent = copyPropertiesAsDeprecated(
174
+ event,
175
+ newEvent,
176
+ (key: string) => {
177
+ console.warn(
178
+ `event.${key} is deprecated on VectorSource#onPress, please use event.features`,
179
+ );
180
+ },
181
+ {
182
+ nativeEvent: (origNativeEvent: OnPressEvent) => ({
183
+ ...origNativeEvent,
184
+ payload: features[0],
185
+ }),
186
+ },
187
+ );
203
188
 
204
- const RCTMLNVectorSource =
205
- requireNativeComponent<VectorSourceProps>(NATIVE_MODULE_NAME);
189
+ onPress(newEvent);
190
+ };
191
+
192
+ const allProps = {
193
+ id,
194
+ url: props.url,
195
+ tileUrlTemplates: props.tileUrlTemplates,
196
+ minZoomLevel: props.minZoomLevel,
197
+ maxZoomLevel: props.maxZoomLevel,
198
+ tms: props.tms,
199
+ attribution: props.attribution,
200
+ hitbox: props.hitbox,
201
+ hasPressListener: isFunction(props.onPress),
202
+ onMapboxVectorSourcePress: onPress,
203
+ onPress: undefined,
204
+ onAndroidCallback: isAndroid() ? _onAndroidCallback : undefined,
205
+ };
206
+
207
+ return (
208
+ <RCTMLNVectorSource ref={setNativeRef} {...allProps}>
209
+ {cloneReactChildrenWithProps(props.children, {
210
+ sourceID: id,
211
+ })}
212
+ </RCTMLNVectorSource>
213
+ );
214
+ },
215
+ ),
216
+ );
206
217
 
207
218
  export default VectorSource;