@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.
- package/.eslintrc.js +3 -1
- package/.yarn/sdks/eslint/bin/eslint.js +8 -1
- package/.yarn/sdks/eslint/lib/api.js +8 -1
- package/.yarn/sdks/eslint/lib/unsupported-api.js +8 -1
- package/.yarn/sdks/prettier/bin/prettier.cjs +8 -1
- package/.yarn/sdks/prettier/index.cjs +8 -1
- package/.yarn/sdks/typescript/bin/tsc +8 -1
- package/.yarn/sdks/typescript/bin/tsserver +8 -1
- package/.yarn/sdks/typescript/lib/tsc.js +8 -1
- package/.yarn/sdks/typescript/lib/tsserver.js +20 -6
- package/.yarn/sdks/typescript/lib/tsserverlibrary.js +20 -6
- package/.yarn/sdks/typescript/lib/typescript.js +8 -1
- package/CHANGELOG.md +57 -48
- package/CONTRIBUTING.md +10 -9
- package/android/rctmln/src/main/java/com/maplibre/rctmln/components/annotation/MarkerViewManager.java +5 -3
- package/android/rctmln/src/main/java/com/maplibre/rctmln/components/mapview/RCTMLNMapView.java +7 -7
- package/docs/Camera.md +3 -3
- package/docs/MapView.md +9 -33
- package/docs/UserLocation.md +10 -2
- package/docs/docs.json +17 -32
- package/docs/offlineManager.md +246 -0
- package/javascript/Maplibre.ts +5 -1
- package/javascript/components/BackgroundLayer.tsx +27 -20
- package/javascript/components/Callout.tsx +40 -40
- package/javascript/components/Camera.tsx +421 -478
- package/javascript/components/CircleLayer.tsx +29 -22
- package/javascript/components/FillExtrusionLayer.tsx +23 -23
- package/javascript/components/FillLayer.tsx +22 -19
- package/javascript/components/HeatmapLayer.tsx +21 -19
- package/javascript/components/ImageSource.tsx +25 -32
- package/javascript/components/Images.tsx +36 -35
- package/javascript/components/Light.tsx +20 -47
- package/javascript/components/LineLayer.tsx +23 -20
- package/javascript/components/MapView.tsx +604 -554
- package/javascript/components/MarkerView.tsx +23 -38
- package/javascript/components/NativeUserLocation.tsx +3 -5
- package/javascript/components/PointAnnotation.tsx +111 -87
- package/javascript/components/RasterLayer.tsx +21 -18
- package/javascript/components/RasterSource.tsx +39 -42
- package/javascript/components/ShapeSource.tsx +287 -239
- package/javascript/components/Style.tsx +1 -1
- package/javascript/components/SymbolLayer.tsx +34 -28
- package/javascript/components/UserLocation.tsx +164 -151
- package/javascript/components/VectorSource.tsx +128 -117
- package/javascript/components/annotations/Annotation.tsx +105 -79
- package/javascript/{components/AbstractLayer.tsx → hooks/useAbstractLayer.ts} +54 -37
- package/javascript/hooks/useAbstractSource.ts +34 -0
- package/javascript/hooks/useNativeBridge.ts +125 -0
- package/javascript/hooks/useNativeRef.ts +13 -0
- package/javascript/hooks/useOnce.ts +12 -0
- package/javascript/utils/Logger.ts +3 -3
- package/package.json +2 -1
- package/javascript/components/AbstractSource.tsx +0 -27
- package/javascript/components/NativeBridgeComponent.tsx +0 -117
|
@@ -4,7 +4,12 @@ import AnimatedMapPoint from '../../utils/animated/AnimatedPoint';
|
|
|
4
4
|
import OnPressEvent from '../../types/OnPressEvent';
|
|
5
5
|
import {SymbolLayerStyleProps} from '../../utils/MaplibreStyles';
|
|
6
6
|
|
|
7
|
-
import React, {
|
|
7
|
+
import React, {
|
|
8
|
+
ReactElement,
|
|
9
|
+
useCallback,
|
|
10
|
+
useEffect,
|
|
11
|
+
useImperativeHandle,
|
|
12
|
+
} from 'react';
|
|
8
13
|
import {Animated as RNAnimated, Easing} from 'react-native';
|
|
9
14
|
|
|
10
15
|
interface AnnotationProps {
|
|
@@ -19,116 +24,137 @@ interface AnnotationProps {
|
|
|
19
24
|
icon?: string | number | object;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
type
|
|
23
|
-
shape: AnimatedMapPoint | GeoJSON.Point | null;
|
|
24
|
-
};
|
|
27
|
+
type Shape = AnimatedMapPoint | GeoJSON.Point;
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
animationEasingFunction: Easing.linear,
|
|
31
|
-
};
|
|
29
|
+
function getShapeFromProps(props: Partial<AnnotationProps> = {}): Shape {
|
|
30
|
+
const lng = props.coordinates?.[0] || 0;
|
|
31
|
+
const lat = props.coordinates?.[1] || 0;
|
|
32
|
+
const point: GeoJSON.Point = {type: 'Point', coordinates: [lng, lat]};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if (props.animated) {
|
|
35
|
+
return new AnimatedMapPoint(point);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return point;
|
|
39
|
+
}
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
function isShapeAnimated(shape: Shape): shape is AnimatedMapPoint {
|
|
42
|
+
return shape instanceof AnimatedMapPoint;
|
|
43
|
+
}
|
|
37
44
|
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
interface AnnotationRef {
|
|
46
|
+
onPress(event: OnPressEvent): void;
|
|
47
|
+
symbolStyle: SymbolLayerStyleProps | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const Annotation = React.forwardRef<AnnotationRef, AnnotationProps>(
|
|
51
|
+
(
|
|
52
|
+
{
|
|
53
|
+
animated = false,
|
|
54
|
+
animationDuration = 1000,
|
|
55
|
+
animationEasingFunction = Easing.linear,
|
|
56
|
+
...otherProps
|
|
57
|
+
}: AnnotationProps,
|
|
58
|
+
ref,
|
|
59
|
+
) => {
|
|
60
|
+
const props = {
|
|
61
|
+
...otherProps,
|
|
62
|
+
animated,
|
|
63
|
+
animationDuration,
|
|
64
|
+
animationEasingFunction,
|
|
40
65
|
};
|
|
41
66
|
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
useImperativeHandle(
|
|
68
|
+
ref,
|
|
69
|
+
(): AnnotationRef => ({
|
|
70
|
+
onPress,
|
|
71
|
+
symbolStyle,
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
44
74
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
75
|
+
const [shape, setShape] = React.useState<Shape | null>(
|
|
76
|
+
getShapeFromProps(props),
|
|
77
|
+
);
|
|
50
78
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
prevProps.coordinates?.[1] !== this.props.coordinates?.[1];
|
|
79
|
+
// this will run useEffect only when actual coordinates values change
|
|
80
|
+
const coordinateDeps = props.coordinates?.join(',');
|
|
54
81
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!Array.isArray(props.coordinates)) {
|
|
84
|
+
setShape(null);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
58
87
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
(this.state.shape as AnimatedMapPoint).stopAnimation();
|
|
62
|
-
|
|
63
|
-
(this.state.shape as AnimatedMapPoint)
|
|
64
|
-
.timing({
|
|
65
|
-
coordinates: this.props.coordinates,
|
|
66
|
-
easing: this.props.animationEasingFunction,
|
|
67
|
-
duration: this.props.animationDuration,
|
|
68
|
-
})
|
|
69
|
-
.start();
|
|
70
|
-
} else if (!this.state.shape || !this.props.animated) {
|
|
71
|
-
const shape = this._getShapeFromProps();
|
|
72
|
-
|
|
73
|
-
this.setState({
|
|
74
|
-
shape: this.props.animated ? new AnimatedMapPoint(shape) : shape,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
}
|
|
88
|
+
if (shape && isShapeAnimated(shape)) {
|
|
89
|
+
shape.stopAnimation();
|
|
78
90
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
shape
|
|
92
|
+
.timing({
|
|
93
|
+
coordinates: props.coordinates,
|
|
94
|
+
easing: animationEasingFunction,
|
|
95
|
+
duration: animationDuration,
|
|
96
|
+
})
|
|
97
|
+
.start();
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!shape || !isShapeAnimated(shape)) {
|
|
103
|
+
const newShape = getShapeFromProps(props);
|
|
104
|
+
setShape(newShape);
|
|
105
|
+
}
|
|
106
|
+
}, [coordinateDeps]);
|
|
107
|
+
|
|
108
|
+
const onPressProp = props.onPress;
|
|
90
109
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
const _onPress = useCallback(
|
|
111
|
+
(event: OnPressEvent) => {
|
|
112
|
+
if (onPressProp) {
|
|
113
|
+
onPressProp(event);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
[onPressProp],
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// This function is needed to correctly generate Annotation.md doc
|
|
120
|
+
function onPress(event: OnPressEvent): void {
|
|
121
|
+
_onPress(event);
|
|
94
122
|
}
|
|
95
|
-
return Object.assign({}, this.props.style, {
|
|
96
|
-
iconImage: this.props.icon,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
123
|
|
|
100
|
-
|
|
101
|
-
if (!this.props.coordinates) {
|
|
124
|
+
if (!props.coordinates) {
|
|
102
125
|
return null;
|
|
103
126
|
}
|
|
104
127
|
|
|
105
128
|
const children = [];
|
|
129
|
+
const symbolStyle: SymbolLayerStyleProps | undefined = props.icon
|
|
130
|
+
? {...props.style, iconImage: props.icon}
|
|
131
|
+
: undefined;
|
|
106
132
|
|
|
107
|
-
if (
|
|
133
|
+
if (symbolStyle) {
|
|
108
134
|
children.push(
|
|
109
|
-
<SymbolLayer id={`${
|
|
135
|
+
<SymbolLayer id={`${props.id}-symbol`} style={symbolStyle} />,
|
|
110
136
|
);
|
|
111
137
|
}
|
|
112
138
|
|
|
113
|
-
if (
|
|
114
|
-
if (Array.isArray(
|
|
115
|
-
children.push(...
|
|
139
|
+
if (props.children) {
|
|
140
|
+
if (Array.isArray(props.children)) {
|
|
141
|
+
children.push(...props.children);
|
|
116
142
|
} else {
|
|
117
|
-
children.push(
|
|
143
|
+
children.push(props.children);
|
|
118
144
|
}
|
|
119
145
|
}
|
|
120
146
|
|
|
121
147
|
return (
|
|
122
148
|
<Animated.ShapeSource
|
|
123
|
-
id={
|
|
124
|
-
onPress={
|
|
125
|
-
shape={
|
|
126
|
-
this.state.shape as RNAnimated.WithAnimatedObject<GeoJSON.Point>
|
|
127
|
-
}>
|
|
149
|
+
id={props.id}
|
|
150
|
+
onPress={_onPress}
|
|
151
|
+
shape={shape as RNAnimated.WithAnimatedObject<GeoJSON.Point>}>
|
|
128
152
|
{children}
|
|
129
153
|
</Animated.ShapeSource>
|
|
130
154
|
);
|
|
131
|
-
}
|
|
132
|
-
|
|
155
|
+
},
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
Annotation.displayName = 'Annotation';
|
|
133
159
|
|
|
134
160
|
export default Annotation;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
/* eslint react/prop-types:0 */
|
|
2
1
|
import {StyleValue, transformStyle} from '../utils/StyleValue';
|
|
3
2
|
import {getFilter} from '../utils/filterUtils';
|
|
4
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AllLayerStyleProps,
|
|
5
|
+
ExpressionField,
|
|
6
|
+
ExpressionName,
|
|
7
|
+
FilterExpression,
|
|
8
|
+
} from '../utils/MaplibreStyles';
|
|
5
9
|
import BaseProps from '../types/BaseProps';
|
|
6
10
|
|
|
7
|
-
import React from 'react';
|
|
11
|
+
import React, {useMemo, useRef} from 'react';
|
|
8
12
|
import {processColor, NativeMethods} from 'react-native';
|
|
9
13
|
|
|
10
14
|
export interface BaseLayerProps {
|
|
@@ -56,52 +60,65 @@ export interface NativeBaseProps {
|
|
|
56
60
|
reactStyle?: {[key: string]: StyleValue};
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
export default function useAbstractLayer<
|
|
60
64
|
Props extends BaseProps,
|
|
61
65
|
NativeProps extends NativeBaseProps,
|
|
62
|
-
>
|
|
63
|
-
|
|
66
|
+
>(
|
|
67
|
+
props: Props & BaseLayerProps,
|
|
68
|
+
): {
|
|
69
|
+
baseProps: Props & BaseLayerProps;
|
|
70
|
+
setNativeLayer: (
|
|
71
|
+
instance: (React.Component<NativeProps> & Readonly<NativeMethods>) | null,
|
|
72
|
+
) => void;
|
|
73
|
+
getStyleTypeFormatter: (styleType: string) => typeof processColor | undefined;
|
|
74
|
+
setNativeProps: (nativeProps: {[key: string]: unknown}) => void;
|
|
75
|
+
} {
|
|
76
|
+
const nativeLayer = useRef<
|
|
77
|
+
(React.Component<NativeProps> & Readonly<NativeMethods>) | null
|
|
78
|
+
>(null);
|
|
79
|
+
|
|
80
|
+
const baseProps = useMemo(() => {
|
|
64
81
|
return {
|
|
65
|
-
...
|
|
66
|
-
id:
|
|
67
|
-
sourceID:
|
|
68
|
-
reactStyle:
|
|
69
|
-
minZoomLevel:
|
|
70
|
-
maxZoomLevel:
|
|
71
|
-
aboveLayerID:
|
|
72
|
-
belowLayerID:
|
|
73
|
-
layerIndex:
|
|
74
|
-
filter: getFilter(
|
|
82
|
+
...props,
|
|
83
|
+
id: props.id,
|
|
84
|
+
sourceID: props.sourceID,
|
|
85
|
+
reactStyle: transformStyle(props.style),
|
|
86
|
+
minZoomLevel: props.minZoomLevel,
|
|
87
|
+
maxZoomLevel: props.maxZoomLevel,
|
|
88
|
+
aboveLayerID: props.aboveLayerID,
|
|
89
|
+
belowLayerID: props.belowLayerID,
|
|
90
|
+
layerIndex: props.layerIndex,
|
|
91
|
+
filter: getFilter(props.filter) as [ExpressionName, ...ExpressionField[]],
|
|
75
92
|
style: undefined,
|
|
76
93
|
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
nativeLayer: (React.Component<NativeProps> & Readonly<NativeMethods>) | null =
|
|
80
|
-
null;
|
|
94
|
+
}, [props]);
|
|
81
95
|
|
|
82
|
-
setNativeLayer = (
|
|
96
|
+
const setNativeLayer = (
|
|
83
97
|
instance: (React.Component<NativeProps> & Readonly<NativeMethods>) | null,
|
|
84
98
|
): void => {
|
|
85
|
-
|
|
99
|
+
nativeLayer.current = instance;
|
|
86
100
|
};
|
|
87
101
|
|
|
88
|
-
getStyleTypeFormatter
|
|
102
|
+
const getStyleTypeFormatter = (
|
|
103
|
+
styleType: string,
|
|
104
|
+
): typeof processColor | undefined => {
|
|
89
105
|
return styleType === 'color' ? processColor : undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
getStyle(): {[key: string]: StyleValue} | undefined {
|
|
93
|
-
return transformStyle(this.props.style);
|
|
94
|
-
}
|
|
106
|
+
};
|
|
95
107
|
|
|
96
|
-
setNativeProps(
|
|
97
|
-
if (
|
|
98
|
-
let propsToPass =
|
|
99
|
-
if (
|
|
100
|
-
propsToPass = {...
|
|
108
|
+
const setNativeProps = (nativeProps: {[key: string]: unknown}): void => {
|
|
109
|
+
if (nativeLayer.current) {
|
|
110
|
+
let propsToPass = nativeProps;
|
|
111
|
+
if (nativeProps.style) {
|
|
112
|
+
propsToPass = {...nativeProps, reactStyle: transformStyle(props.style)};
|
|
101
113
|
}
|
|
102
|
-
|
|
114
|
+
nativeLayer.current.setNativeProps(propsToPass);
|
|
103
115
|
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
116
|
+
};
|
|
106
117
|
|
|
107
|
-
|
|
118
|
+
return {
|
|
119
|
+
baseProps,
|
|
120
|
+
setNativeLayer,
|
|
121
|
+
getStyleTypeFormatter,
|
|
122
|
+
setNativeProps,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React, {useRef} from 'react';
|
|
2
|
+
import {NativeMethods} from 'react-native';
|
|
3
|
+
|
|
4
|
+
export default function useAbstractSource<NativePropsType extends object>(): {
|
|
5
|
+
_nativeRef:
|
|
6
|
+
| (React.Component<NativePropsType> & Readonly<NativeMethods>)
|
|
7
|
+
| undefined;
|
|
8
|
+
setNativeRef: (
|
|
9
|
+
instance: React.Component<NativePropsType> & Readonly<NativeMethods>,
|
|
10
|
+
) => void;
|
|
11
|
+
setNativeProps: (nativeProps: NativePropsType) => void;
|
|
12
|
+
} {
|
|
13
|
+
const _nativeRef = useRef<
|
|
14
|
+
(React.Component<NativePropsType> & Readonly<NativeMethods>) | undefined
|
|
15
|
+
>(undefined);
|
|
16
|
+
|
|
17
|
+
const setNativeRef = (
|
|
18
|
+
instance: React.Component<NativePropsType> & Readonly<NativeMethods>,
|
|
19
|
+
): void => {
|
|
20
|
+
_nativeRef.current = instance;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const setNativeProps = (newProps: NativePropsType): void => {
|
|
24
|
+
if (_nativeRef.current) {
|
|
25
|
+
_nativeRef.current.setNativeProps(newProps);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
_nativeRef: _nativeRef.current,
|
|
31
|
+
setNativeRef,
|
|
32
|
+
setNativeProps,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {runNativeCommand, isAndroid, NativeArg} from '../utils';
|
|
2
|
+
|
|
3
|
+
import React, {Component, SyntheticEvent, useRef} from 'react';
|
|
4
|
+
|
|
5
|
+
export type RNMLEvent<PayloadType = {[key: string]: string}> = {
|
|
6
|
+
payload: PayloadType;
|
|
7
|
+
type: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let callbackIncrement = 0;
|
|
11
|
+
|
|
12
|
+
type UseNativeBridge = {
|
|
13
|
+
_nativeModuleName: string;
|
|
14
|
+
_onAndroidCallback: (e: SyntheticEvent<Element, RNMLEvent>) => void;
|
|
15
|
+
_callbackMap: React.MutableRefObject<Map<string, any>>;
|
|
16
|
+
_preRefMapMethodQueue: React.MutableRefObject<any[]>;
|
|
17
|
+
_addAddAndroidCallback: <ReturnType>(
|
|
18
|
+
id: string,
|
|
19
|
+
resolve: (value: ReturnType) => void,
|
|
20
|
+
reject: (error: Error) => void,
|
|
21
|
+
) => void;
|
|
22
|
+
_removeAndroidCallback: (id: string) => void;
|
|
23
|
+
_runPendingNativeCommands: <RefType extends Component>(
|
|
24
|
+
nativeRef: RefType | null | undefined,
|
|
25
|
+
) => Promise<void>;
|
|
26
|
+
_runNativeCommand: <RefType extends Component, ReturnType = NativeArg>(
|
|
27
|
+
methodName: string,
|
|
28
|
+
nativeRef: RefType | undefined | null,
|
|
29
|
+
args?: NativeArg[],
|
|
30
|
+
) => Promise<ReturnType>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const useNativeBridge: (moduleName: string) => UseNativeBridge = (
|
|
34
|
+
_nativeModuleName: string,
|
|
35
|
+
) => {
|
|
36
|
+
const _callbackMap = useRef<Map<string, any>>(new Map());
|
|
37
|
+
const _preRefMapMethodQueue = useRef<any[]>([]);
|
|
38
|
+
|
|
39
|
+
const _addAddAndroidCallback = <ReturnType>(
|
|
40
|
+
id: string,
|
|
41
|
+
resolve: (value: ReturnType) => void,
|
|
42
|
+
reject: (error: Error) => void,
|
|
43
|
+
): void => {
|
|
44
|
+
_callbackMap.current.set(id, {resolve, reject});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const _removeAndroidCallback = (id: string): void => {
|
|
48
|
+
_callbackMap.current.delete(id);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const _onAndroidCallback = (e: SyntheticEvent<Element, RNMLEvent>): void => {
|
|
52
|
+
const callbackID = e.nativeEvent.type;
|
|
53
|
+
const callback = _callbackMap.current.get(callbackID);
|
|
54
|
+
|
|
55
|
+
if (!callback) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_callbackMap.current.delete(callbackID);
|
|
60
|
+
const {payload} = e.nativeEvent;
|
|
61
|
+
if (payload.error) {
|
|
62
|
+
callback.reject.call(null, new Error(payload.error));
|
|
63
|
+
} else {
|
|
64
|
+
callback.resolve.call(null, payload);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const _runPendingNativeCommands = async <RefType extends Component>(
|
|
69
|
+
nativeRef: RefType | null | undefined,
|
|
70
|
+
): Promise<void> => {
|
|
71
|
+
if (nativeRef) {
|
|
72
|
+
while (_preRefMapMethodQueue.current.length > 0) {
|
|
73
|
+
const item = _preRefMapMethodQueue.current.pop();
|
|
74
|
+
|
|
75
|
+
if (item && item.method && item.resolver) {
|
|
76
|
+
const res = await _runNativeCommand(
|
|
77
|
+
item.method.name,
|
|
78
|
+
nativeRef,
|
|
79
|
+
item.method.args,
|
|
80
|
+
);
|
|
81
|
+
item.resolver(res);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const _runNativeCommand = <RefType extends Component, ReturnType = NativeArg>(
|
|
88
|
+
methodName: string,
|
|
89
|
+
nativeRef: RefType | undefined | null,
|
|
90
|
+
args: NativeArg[] = [],
|
|
91
|
+
): Promise<ReturnType> => {
|
|
92
|
+
if (!nativeRef) {
|
|
93
|
+
return new Promise(resolve => {
|
|
94
|
+
_preRefMapMethodQueue.current.push({
|
|
95
|
+
method: {name: methodName, args},
|
|
96
|
+
resolver: resolve,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (isAndroid()) {
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
callbackIncrement += 1;
|
|
104
|
+
const callbackID = `${methodName}_${callbackIncrement}`;
|
|
105
|
+
_addAddAndroidCallback(callbackID, resolve, reject);
|
|
106
|
+
args.unshift(callbackID);
|
|
107
|
+
runNativeCommand(_nativeModuleName, methodName, nativeRef, args);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return runNativeCommand(_nativeModuleName, methodName, nativeRef, args);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
_nativeModuleName,
|
|
115
|
+
_onAndroidCallback,
|
|
116
|
+
_callbackMap,
|
|
117
|
+
_preRefMapMethodQueue,
|
|
118
|
+
_addAddAndroidCallback,
|
|
119
|
+
_removeAndroidCallback,
|
|
120
|
+
_runPendingNativeCommands,
|
|
121
|
+
_runNativeCommand,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export default useNativeBridge;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, {Component, useRef} from 'react';
|
|
2
|
+
import {NativeMethods} from 'react-native';
|
|
3
|
+
|
|
4
|
+
type NativeRef<NativeProps> = Component<NativeProps> & Readonly<NativeMethods>;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Separate module which allows to be mocked in tests.
|
|
8
|
+
*/
|
|
9
|
+
export function useNativeRef<NativeProps = object>(): React.RefObject<
|
|
10
|
+
NativeRef<NativeProps>
|
|
11
|
+
> {
|
|
12
|
+
return useRef<NativeRef<NativeProps>>(null);
|
|
13
|
+
}
|
|
@@ -120,11 +120,11 @@ class Logger {
|
|
|
120
120
|
const {message} = log;
|
|
121
121
|
const level = this.effectiveLevel(log);
|
|
122
122
|
if (level === 'error') {
|
|
123
|
-
console.error('
|
|
123
|
+
console.error('MapLibre error', message, log);
|
|
124
124
|
} else if (level === 'warning') {
|
|
125
|
-
console.warn('
|
|
125
|
+
console.warn('MapLibre warning', message, log);
|
|
126
126
|
} else {
|
|
127
|
-
console.log(`
|
|
127
|
+
console.log(`MapLibre [${level}]`, message, log);
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maplibre/maplibre-react-native",
|
|
3
3
|
"description": "A MapLibre GL Native plugin for creating maps in React Native",
|
|
4
|
-
"version": "10.0.0-alpha.
|
|
4
|
+
"version": "10.0.0-alpha.7",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"unittest:single": "jest --testNamePattern",
|
|
29
29
|
"lint": "eslint .",
|
|
30
30
|
"lint:fix": "eslint . --fix",
|
|
31
|
+
"lint:single": "eslint",
|
|
31
32
|
"prepack": "pinst --disable && yarn build:plugin",
|
|
32
33
|
"test:plugin": "jest plugin",
|
|
33
34
|
"build:plugin": "tsc --build plugin",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import BaseProps from '../types/BaseProps';
|
|
2
|
-
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import {NativeMethods} from 'react-native';
|
|
5
|
-
|
|
6
|
-
class AbstractSource<
|
|
7
|
-
PropsType extends BaseProps,
|
|
8
|
-
NativePropsType extends object,
|
|
9
|
-
> extends React.PureComponent<PropsType> {
|
|
10
|
-
_nativeRef?: React.Component<NativePropsType> & Readonly<NativeMethods>;
|
|
11
|
-
|
|
12
|
-
setNativeProps(props: NativePropsType): void {
|
|
13
|
-
if (this._nativeRef) {
|
|
14
|
-
this._nativeRef.setNativeProps(props);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
setNativeRef: (
|
|
19
|
-
instance: React.Component<NativePropsType> & Readonly<NativeMethods>,
|
|
20
|
-
) => void = (
|
|
21
|
-
instance: React.Component<NativePropsType> & Readonly<NativeMethods>,
|
|
22
|
-
) => {
|
|
23
|
-
this._nativeRef = instance;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default AbstractSource;
|