@maplibre/maplibre-react-native 10.0.0-alpha.5 → 10.0.0-alpha.7

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 (54) 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 +57 -48
  14. package/CONTRIBUTING.md +10 -9
  15. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/MarkerViewManager.java +5 -3
  16. package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNMapView.java +7 -7
  17. package/docs/Camera.md +3 -3
  18. package/docs/MapView.md +9 -33
  19. package/docs/UserLocation.md +10 -2
  20. package/docs/docs.json +17 -32
  21. package/docs/offlineManager.md +246 -0
  22. package/javascript/Maplibre.ts +5 -1
  23. package/javascript/components/BackgroundLayer.tsx +27 -20
  24. package/javascript/components/Callout.tsx +40 -40
  25. package/javascript/components/Camera.tsx +421 -478
  26. package/javascript/components/CircleLayer.tsx +29 -22
  27. package/javascript/components/FillExtrusionLayer.tsx +23 -23
  28. package/javascript/components/FillLayer.tsx +22 -19
  29. package/javascript/components/HeatmapLayer.tsx +21 -19
  30. package/javascript/components/ImageSource.tsx +25 -32
  31. package/javascript/components/Images.tsx +36 -35
  32. package/javascript/components/Light.tsx +20 -47
  33. package/javascript/components/LineLayer.tsx +23 -20
  34. package/javascript/components/MapView.tsx +604 -554
  35. package/javascript/components/MarkerView.tsx +23 -38
  36. package/javascript/components/NativeUserLocation.tsx +3 -5
  37. package/javascript/components/PointAnnotation.tsx +111 -87
  38. package/javascript/components/RasterLayer.tsx +21 -18
  39. package/javascript/components/RasterSource.tsx +39 -42
  40. package/javascript/components/ShapeSource.tsx +287 -239
  41. package/javascript/components/Style.tsx +1 -1
  42. package/javascript/components/SymbolLayer.tsx +34 -28
  43. package/javascript/components/UserLocation.tsx +164 -151
  44. package/javascript/components/VectorSource.tsx +128 -117
  45. package/javascript/components/annotations/Annotation.tsx +105 -79
  46. package/javascript/{components/AbstractLayer.tsx → hooks/useAbstractLayer.ts} +54 -37
  47. package/javascript/hooks/useAbstractSource.ts +34 -0
  48. package/javascript/hooks/useNativeBridge.ts +125 -0
  49. package/javascript/hooks/useNativeRef.ts +13 -0
  50. package/javascript/hooks/useOnce.ts +12 -0
  51. package/javascript/utils/Logger.ts +3 -3
  52. package/package.json +2 -1
  53. package/javascript/components/AbstractSource.tsx +0 -27
  54. package/javascript/components/NativeBridgeComponent.tsx +0 -117
@@ -3,7 +3,7 @@ import {makePoint} from '../utils/geoUtils';
3
3
 
4
4
  import PointAnnotation from './PointAnnotation';
5
5
 
6
- import React, {ReactElement} from 'react';
6
+ import React, {ReactElement, useMemo} from 'react';
7
7
  import {Platform, requireNativeComponent, ViewProps} from 'react-native';
8
8
 
9
9
  export const NATIVE_MODULE_NAME = 'RCTMLNMarkerView';
@@ -54,49 +54,34 @@ interface NativeProps extends ViewProps {
54
54
  * This is based on [MakerView plugin](https://docs.mapbox.com/android/plugins/overview/markerview/) on Android
55
55
  * and PointAnnotation on iOS.
56
56
  */
57
- class MarkerView extends React.PureComponent<MarkerViewProps> {
58
- static defaultProps = {
59
- anchor: {x: 0.5, y: 0.5},
60
- allowOverlap: false,
61
- isSelected: false,
62
- };
63
-
64
- static lastId = 0;
65
- __idForPointAnnotation?: string;
57
+ const MarkerView = (props: MarkerViewProps): ReactElement => {
58
+ const coordinate = props.coordinate
59
+ ? toJSONString(makePoint(props.coordinate))
60
+ : undefined;
66
61
 
67
- _idForPointAnnotation(): string {
68
- if (this.__idForPointAnnotation === undefined) {
69
- MarkerView.lastId = MarkerView.lastId + 1;
70
- this.__idForPointAnnotation = `MV-${MarkerView.lastId}`;
71
- }
72
- return this.__idForPointAnnotation;
73
- }
62
+ const idForPointAnnotation = useMemo(() => {
63
+ MarkerView.lastId = MarkerView.lastId + 1;
64
+ return `MV-${MarkerView.lastId}`;
65
+ }, []);
74
66
 
75
- _getCoordinate(): string | undefined {
76
- if (!this.props.coordinate) {
77
- return undefined;
78
- }
79
- return toJSONString(makePoint(this.props.coordinate));
67
+ if (Platform.OS === 'ios') {
68
+ return <PointAnnotation id={idForPointAnnotation} {...props} />;
80
69
  }
81
70
 
82
- render(): ReactElement {
83
- if (Platform.OS === 'ios') {
84
- return (
85
- <PointAnnotation id={this._idForPointAnnotation()} {...this.props} />
86
- );
87
- }
71
+ const propsToSend = {
72
+ ...props,
73
+ coordinate,
74
+ };
88
75
 
89
- const props = {
90
- ...this.props,
91
- anchor: this.props.anchor,
92
- coordinate: this._getCoordinate(),
93
- };
76
+ return <RCTMLNMarkerView {...propsToSend}>{props.children}</RCTMLNMarkerView>;
77
+ };
94
78
 
95
- return (
96
- <RCTMLNMarkerView {...props}>{this.props.children}</RCTMLNMarkerView>
97
- );
98
- }
99
- }
79
+ MarkerView.lastId = 0;
80
+ MarkerView.defaultProps = {
81
+ anchor: {x: 0.5, y: 0.5},
82
+ allowOverlap: false,
83
+ isSelected: false,
84
+ };
100
85
 
101
86
  const RCTMLNMarkerView =
102
87
  requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
@@ -22,11 +22,9 @@ interface NativeUserLocationProps {
22
22
  iosShowsUserHeadingIndicator?: boolean;
23
23
  }
24
24
 
25
- class NativeUserLocation extends React.Component<NativeUserLocationProps> {
26
- render(): ReactElement {
27
- return <RCTMLNNativeUserLocation {...this.props} />;
28
- }
29
- }
25
+ const NativeUserLocation = (props: NativeUserLocationProps): ReactElement => {
26
+ return <RCTMLNNativeUserLocation {...props} />;
27
+ };
30
28
 
31
29
  const RCTMLNNativeUserLocation = requireNativeComponent(NATIVE_MODULE_NAME);
32
30
 
@@ -1,14 +1,20 @@
1
- import {toJSONString, isFunction} from '../utils';
1
+ import useNativeBridge, {RNMLEvent} from '../hooks/useNativeBridge';
2
+ import {isFunction, toJSONString} from '../utils';
2
3
  import {makePoint} from '../utils/geoUtils';
3
4
 
4
- import NativeBridgeComponent, {RNMLEvent} from './NativeBridgeComponent';
5
-
6
- import React, {Component, ReactElement, SyntheticEvent} from 'react';
5
+ import React, {
6
+ Component,
7
+ SyntheticEvent,
8
+ forwardRef,
9
+ useImperativeHandle,
10
+ useRef,
11
+ ReactElement,
12
+ } from 'react';
7
13
  import {
8
- requireNativeComponent,
9
- StyleSheet,
10
14
  Platform,
15
+ StyleSheet,
11
16
  ViewProps,
17
+ requireNativeComponent,
12
18
  } from 'react-native';
13
19
 
14
20
  export const NATIVE_MODULE_NAME = 'RCTMLNPointAnnotation';
@@ -29,7 +35,7 @@ type FeaturePayload = GeoJSON.Feature<
29
35
  }
30
36
  >;
31
37
 
32
- interface PointAnnotationProps {
38
+ export interface PointAnnotationProps {
33
39
  /**
34
40
  * A string that uniquely identifies the annotation
35
41
  */
@@ -101,6 +107,14 @@ interface PointAnnotationProps {
101
107
  style?: ViewProps['style'];
102
108
  }
103
109
 
110
+ interface NativeProps extends Omit<PointAnnotationProps, 'coordinate'> {
111
+ coordinate?: string;
112
+ }
113
+
114
+ export interface PointAnnotationRef {
115
+ refresh(): void;
116
+ }
117
+
104
118
  /**
105
119
  * PointAnnotation represents a one-dimensional shape located at a single geographical coordinate.
106
120
  *
@@ -111,109 +125,119 @@ interface PointAnnotationProps {
111
125
  * If you need interctive views please use MarkerView,
112
126
  * as with PointAnnotation on Android child views are rendered onto a bitmap for better performance.
113
127
  */
114
- class PointAnnotation extends NativeBridgeComponent(
115
- React.PureComponent<PointAnnotationProps>,
116
- NATIVE_MODULE_NAME,
117
- ) {
118
- static defaultProps = {
119
- anchor: {x: 0.5, y: 0.5},
120
- draggable: false,
121
- };
122
-
123
- _nativeRef: Component<NativeProps> | null = null;
128
+ const PointAnnotation = forwardRef<PointAnnotationRef, PointAnnotationProps>(
129
+ (
130
+ {
131
+ anchor = {x: 0.5, y: 0.5},
132
+ draggable = false,
133
+ ...props
134
+ }: PointAnnotationProps,
135
+ ref,
136
+ ): ReactElement => {
137
+ useImperativeHandle(
138
+ ref,
139
+ (): PointAnnotationRef => ({
140
+ /**
141
+ * On android point annotation is rendered offscreen with a canvas into an image.
142
+ * To rerender the image from the current state of the view call refresh.
143
+ * Call this for example from Image#onLoad.
144
+ */
145
+ refresh,
146
+ }),
147
+ );
124
148
 
125
- constructor(props: PointAnnotationProps) {
126
- super(props);
127
- this._onSelected = this._onSelected.bind(this);
128
- this._onDeselected = this._onDeselected.bind(this);
129
- this._onDragStart = this._onDragStart.bind(this);
130
- this._onDrag = this._onDrag.bind(this);
131
- this._onDragEnd = this._onDragEnd.bind(this);
132
- }
149
+ const {_runNativeCommand, _runPendingNativeCommands} =
150
+ useNativeBridge(NATIVE_MODULE_NAME);
151
+ const _nativeRef = useRef<Component<NativeProps> | null>();
133
152
 
134
- _onSelected(e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>): void {
135
- if (isFunction(this.props.onSelected)) {
136
- this.props.onSelected(e.nativeEvent.payload);
153
+ function refresh(): void {
154
+ if (Platform.OS === 'android') {
155
+ _runNativeCommand('refresh', _nativeRef.current, []);
156
+ }
137
157
  }
138
- }
139
158
 
140
- _onDeselected(e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>): void {
141
- if (isFunction(this.props.onDeselected)) {
142
- this.props.onDeselected(e.nativeEvent.payload);
159
+ function _onSelected(
160
+ e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>,
161
+ ): void {
162
+ if (isFunction(props.onSelected)) {
163
+ props.onSelected(e.nativeEvent.payload);
164
+ }
143
165
  }
144
- }
145
166
 
146
- _onDragStart(e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>): void {
147
- if (isFunction(this.props.onDragStart)) {
148
- this.props.onDragStart(e.nativeEvent.payload);
167
+ function _onDeselected(
168
+ e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>,
169
+ ): void {
170
+ if (isFunction(props.onDeselected)) {
171
+ props.onDeselected(e.nativeEvent.payload);
172
+ }
149
173
  }
150
- }
151
174
 
152
- _onDrag(e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>): void {
153
- if (isFunction(this.props.onDrag)) {
154
- this.props.onDrag(e.nativeEvent.payload);
175
+ function _onDragStart(
176
+ e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>,
177
+ ): void {
178
+ if (isFunction(props.onDragStart)) {
179
+ props.onDragStart(e.nativeEvent.payload);
180
+ }
155
181
  }
156
- }
157
182
 
158
- _onDragEnd(e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>): void {
159
- if (isFunction(this.props.onDragEnd)) {
160
- this.props.onDragEnd(e.nativeEvent.payload);
183
+ function _onDrag(
184
+ e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>,
185
+ ): void {
186
+ if (isFunction(props.onDrag)) {
187
+ props.onDrag(e.nativeEvent.payload);
188
+ }
161
189
  }
162
- }
163
190
 
164
- _getCoordinate(): string | undefined {
165
- if (!this.props.coordinate) {
166
- return undefined;
191
+ function _onDragEnd(
192
+ e: SyntheticEvent<Element, RNMLEvent<FeaturePayload>>,
193
+ ): void {
194
+ if (isFunction(props.onDragEnd)) {
195
+ props.onDragEnd(e.nativeEvent.payload);
196
+ }
167
197
  }
168
- return toJSONString(makePoint(this.props.coordinate));
169
- }
170
198
 
171
- /**
172
- * On android point annotation is rendered offscreen with a canvas into an image.
173
- * To rerender the image from the current state of the view call refresh.
174
- * Call this for example from Image#onLoad.
175
- */
176
- refresh(): void {
177
- if (Platform.OS === 'android') {
178
- this._runNativeCommand('refresh', this._nativeRef, []);
199
+ function _getCoordinate(): string | undefined {
200
+ if (!props.coordinate) {
201
+ return undefined;
202
+ }
203
+ return toJSONString(makePoint(props.coordinate));
179
204
  }
180
- }
181
205
 
182
- _setNativeRef(nativeRef: Component<NativeProps> | null): void {
183
- this._nativeRef = nativeRef;
184
- super._runPendingNativeCommands(nativeRef);
185
- }
206
+ const _setNativeRef = (nativeRef: Component<NativeProps> | null): void => {
207
+ _nativeRef.current = nativeRef;
208
+ _runPendingNativeCommands(nativeRef);
209
+ };
186
210
 
187
- render(): ReactElement {
188
- const props = {
189
- ...this.props,
211
+ const nativeProps = {
212
+ ...props,
213
+ anchor,
214
+ draggable,
190
215
  ref: (nativeRef: Component<NativeProps> | null) =>
191
- this._setNativeRef(nativeRef),
192
- id: this.props.id,
193
- title: this.props.title,
194
- snippet: this.props.snippet,
195
- anchor: this.props.anchor,
196
- selected: this.props.selected,
197
- draggable: this.props.draggable,
198
- style: [this.props.style, styles.container],
199
- onMapboxPointAnnotationSelected: this._onSelected,
200
- onMapboxPointAnnotationDeselected: this._onDeselected,
201
- onMapboxPointAnnotationDragStart: this._onDragStart,
202
- onMapboxPointAnnotationDrag: this._onDrag,
203
- onMapboxPointAnnotationDragEnd: this._onDragEnd,
204
- coordinate: this._getCoordinate(),
216
+ _setNativeRef(nativeRef),
217
+ id: props.id,
218
+ title: props.title,
219
+ snippet: props.snippet,
220
+ selected: props.selected,
221
+ style: [props.style, styles.container],
222
+ onMapboxPointAnnotationSelected: _onSelected,
223
+ onMapboxPointAnnotationDeselected: _onDeselected,
224
+ onMapboxPointAnnotationDragStart: _onDragStart,
225
+ onMapboxPointAnnotationDrag: _onDrag,
226
+ onMapboxPointAnnotationDragEnd: _onDragEnd,
227
+ coordinate: _getCoordinate(),
205
228
  };
229
+
206
230
  return (
207
- <RCTMLNPointAnnotation {...props}>
208
- {this.props.children}
231
+ <RCTMLNPointAnnotation {...nativeProps}>
232
+ {props.children}
209
233
  </RCTMLNPointAnnotation>
210
234
  );
211
- }
212
- }
235
+ },
236
+ );
213
237
 
214
- interface NativeProps extends Omit<PointAnnotationProps, 'coordinate'> {
215
- coordinate?: string;
216
- }
238
+ // eslint complains about it
239
+ // not sure why only in this component
240
+ PointAnnotation.displayName = 'PointAnnotation';
217
241
 
218
242
  const RCTMLNPointAnnotation =
219
243
  requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
@@ -1,16 +1,18 @@
1
1
  import {RasterLayerStyleProps} from '../utils/MaplibreStyles';
2
2
  import BaseProps from '../types/BaseProps';
3
+ import useAbstractLayer, {
4
+ BaseLayerProps,
5
+ NativeBaseProps,
6
+ } from '../hooks/useAbstractLayer';
3
7
 
4
- import AbstractLayer, {BaseLayerProps, NativeBaseProps} from './AbstractLayer';
5
-
6
- import React, {ReactElement} from 'react';
8
+ import React from 'react';
7
9
  import {NativeModules, requireNativeComponent} from 'react-native';
8
10
 
9
11
  const MapLibreGL = NativeModules.MLNModule;
10
12
 
11
13
  export const NATIVE_MODULE_NAME = 'RCTMLNRasterLayer';
12
14
 
13
- interface RasterLayerProps extends BaseProps, BaseLayerProps {
15
+ export interface RasterLayerProps extends BaseProps, BaseLayerProps {
14
16
  /**
15
17
  * Customizable style attributes
16
18
  */
@@ -21,21 +23,22 @@ interface NativeProps
21
23
  extends Omit<RasterLayerProps, 'style'>,
22
24
  NativeBaseProps {}
23
25
 
24
- class RasterLayer extends AbstractLayer<RasterLayerProps, NativeProps> {
25
- static defaultProps = {
26
- sourceID: MapLibreGL.StyleSource.DefaultSourceID,
27
- };
28
-
29
- render(): ReactElement {
30
- const props = {
31
- ...this.baseProps,
32
- sourceLayerID: this.props.sourceLayerID,
33
- };
34
- return <RCTMLNRasterLayer ref={this.setNativeLayer} {...props} />;
35
- }
36
- }
37
-
38
26
  const RCTMLNRasterLayer =
39
27
  requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
40
28
 
29
+ const RasterLayer: React.FC<RasterLayerProps> = ({
30
+ sourceID = MapLibreGL.StyleSource.DefaultSourceID,
31
+ ...props
32
+ }: RasterLayerProps) => {
33
+ const {baseProps, setNativeLayer} = useAbstractLayer<
34
+ RasterLayerProps,
35
+ NativeProps
36
+ >({
37
+ ...props,
38
+ sourceID,
39
+ });
40
+
41
+ return <RCTMLNRasterLayer ref={setNativeLayer} {...baseProps} />;
42
+ };
43
+
41
44
  export default RasterLayer;
@@ -1,10 +1,10 @@
1
1
  import {cloneReactChildrenWithProps} from '../utils';
2
2
  import BaseProps from '../types/BaseProps';
3
-
4
- import AbstractSource from './AbstractSource';
3
+ import useAbstractSource from '../hooks/useAbstractSource';
4
+ import useOnce from '../hooks/useOnce';
5
5
 
6
6
  import {NativeModules, requireNativeComponent} from 'react-native';
7
- import React, {ReactElement} from 'react';
7
+ import React from 'react';
8
8
 
9
9
  const MapLibreGL = NativeModules.MLNModule;
10
10
 
@@ -60,58 +60,55 @@ interface RasterSourceProps extends BaseProps {
60
60
 
61
61
  type NativeProps = RasterSourceProps;
62
62
 
63
+ const RCTMLNRasterSource =
64
+ requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
65
+
63
66
  /**
64
67
  * RasterSource is a map content source that supplies raster image tiles to be shown on the map.
65
68
  * The location of and metadata about the tiles are defined either by an option dictionary
66
69
  * or by an external file that conforms to the TileJSON specification.
67
70
  */
68
- class RasterSource extends AbstractSource<RasterSourceProps, NativeProps> {
69
- static defaultProps = {
70
- id: MapLibreGL.StyleSource.DefaultSourceID,
71
- };
72
-
73
- constructor(props: RasterSourceProps) {
74
- super(props);
75
- if (isTileTemplateUrl(props.url)) {
71
+ const RasterSource: React.FC<RasterSourceProps> = ({
72
+ id = MapLibreGL.StyleSource.DefaultSourceID,
73
+ ...props
74
+ }: RasterSourceProps) => {
75
+ useOnce(() => {
76
+ if (props.url && props.tileUrlTemplates) {
76
77
  console.warn(
77
78
  `RasterSource 'url' property contains a Tile URL Template, but is intended for a StyleJSON URL. Please migrate your VectorSource to use: \`tileUrlTemplates=["${props.url}"]\` instead.`,
78
79
  );
79
80
  }
80
- }
81
+ });
81
82
 
82
- render(): ReactElement {
83
- let {url} = this.props;
84
- let {tileUrlTemplates} = this.props;
83
+ const {setNativeRef} = useAbstractSource<NativeProps>();
85
84
 
86
- // Swapping url for tileUrlTemplates to provide backward compatiblity
87
- // when RasterSource supported only tile url as url prop
88
- if (isTileTemplateUrl(url)) {
89
- tileUrlTemplates = [url];
90
- url = undefined;
91
- }
85
+ let {url, tileUrlTemplates} = props;
92
86
 
93
- const props = {
94
- ...this.props,
95
- id: this.props.id,
96
- url,
97
- tileUrlTemplates,
98
- minZoomLevel: this.props.minZoomLevel,
99
- maxZoomLevel: this.props.maxZoomLevel,
100
- tileSize: this.props.tileSize,
101
- tms: this.props.tms,
102
- attribution: this.props.attribution,
103
- };
104
- return (
105
- <RCTMLNRasterSource ref={this.setNativeRef} {...props}>
106
- {cloneReactChildrenWithProps(this.props.children, {
107
- sourceID: this.props.id,
108
- })}
109
- </RCTMLNRasterSource>
110
- );
87
+ // Swapping url for tileUrlTemplates to provide backward compatiblity
88
+ // when RasterSource supported only tile url as url prop
89
+ if (isTileTemplateUrl(url)) {
90
+ tileUrlTemplates = [url];
91
+ url = undefined;
111
92
  }
112
- }
93
+ const allProps = {
94
+ ...props,
95
+ id,
96
+ url,
97
+ tileUrlTemplates,
98
+ minZoomLevel: props.minZoomLevel,
99
+ maxZoomLevel: props.maxZoomLevel,
100
+ tileSize: props.tileSize,
101
+ tms: props.tms,
102
+ attribution: props.attribution,
103
+ };
113
104
 
114
- const RCTMLNRasterSource =
115
- requireNativeComponent<NativeProps>(NATIVE_MODULE_NAME);
105
+ return (
106
+ <RCTMLNRasterSource ref={setNativeRef} {...allProps}>
107
+ {cloneReactChildrenWithProps(props.children, {
108
+ sourceID: id,
109
+ })}
110
+ </RCTMLNRasterSource>
111
+ );
112
+ };
116
113
 
117
114
  export default RasterSource;