@octanejs/react-map-gl 0.0.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.
- package/LICENSE +62 -0
- package/README.md +112 -0
- package/UPSTREAM.md +216 -0
- package/package.json +61 -0
- package/src/components/attribution-control.ts +27 -0
- package/src/components/fullscreen-control.ts +35 -0
- package/src/components/geolocate-control.ts +88 -0
- package/src/components/layer.ts +135 -0
- package/src/components/map.tsrx +173 -0
- package/src/components/marker.ts +217 -0
- package/src/components/navigation-control.ts +27 -0
- package/src/components/popup.ts +100 -0
- package/src/components/scale-control.ts +44 -0
- package/src/components/source.tsrx +146 -0
- package/src/components/use-control.ts +73 -0
- package/src/components/use-map.tsrx +64 -0
- package/src/index.ts +33 -0
- package/src/mapbox/create-ref.ts +114 -0
- package/src/mapbox/mapbox.ts +714 -0
- package/src/mapbox/proxy-transform.ts +155 -0
- package/src/types/common.ts +41 -0
- package/src/types/events.ts +130 -0
- package/src/types/internal.ts +20 -0
- package/src/types/lib.ts +70 -0
- package/src/types/octane.ts +27 -0
- package/src/types/style-spec.ts +51 -0
- package/src/utils/apply-react-style.ts +26 -0
- package/src/utils/assert.ts +10 -0
- package/src/utils/children.ts +26 -0
- package/src/utils/compare-class-names.ts +34 -0
- package/src/utils/deep-equal.ts +66 -0
- package/src/utils/set-globals.ts +62 -0
- package/src/utils/style-utils.ts +65 -0
- package/src/utils/transform.ts +115 -0
- package/src/utils/use-isomorphic-layout-effect.ts +7 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
import type {Transform} from '../types/internal';
|
|
7
|
+
import type {ViewState, LngLat} from '../types/common';
|
|
8
|
+
import {applyViewStateToTransform, isViewStateControlled} from '../utils/transform';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Mapbox map is stateful.
|
|
12
|
+
* During method calls/user interactions, map.transform is mutated and deviate from user-supplied props.
|
|
13
|
+
* In order to control the map reactively, we trap the transform mutations with a proxy,
|
|
14
|
+
* which reflects the view state resolved from both user-supplied props and the underlying state
|
|
15
|
+
*/
|
|
16
|
+
export type ProxyTransform = Transform & {
|
|
17
|
+
$internalUpdate: boolean;
|
|
18
|
+
$proposedTransform: Transform | null;
|
|
19
|
+
$reactViewState: Partial<ViewState>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// These are Transform class methods that:
|
|
23
|
+
// + do not mutate any view state properties
|
|
24
|
+
// + populate private members derived from view state properties
|
|
25
|
+
// They should always reflect the state of their owning instance and NOT trigger any proxied getter/setter
|
|
26
|
+
const unproxiedMethods = new Set([
|
|
27
|
+
'_calcMatrices',
|
|
28
|
+
'_calcFogMatrices',
|
|
29
|
+
'_updateCameraState',
|
|
30
|
+
'_updateSeaLevelZoom'
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export function createProxyTransform(tr: Transform): ProxyTransform {
|
|
34
|
+
let internalUpdate = false;
|
|
35
|
+
let reactViewState: Partial<ViewState> = {};
|
|
36
|
+
/**
|
|
37
|
+
* Reflects view state set by react props
|
|
38
|
+
* This is the transform seen by painter, style etc.
|
|
39
|
+
*/
|
|
40
|
+
const controlledTransform: Transform = tr;
|
|
41
|
+
/** Populated during camera move (handler/easeTo) if there is a discrepency between react props and proposed view state
|
|
42
|
+
* This is the transform seen by Mapbox's input handlers
|
|
43
|
+
*/
|
|
44
|
+
let proposedTransform: Transform | null = null;
|
|
45
|
+
|
|
46
|
+
const handlers: ProxyHandler<Transform> = {
|
|
47
|
+
get(target: Transform, prop: string) {
|
|
48
|
+
// Props added by us
|
|
49
|
+
if (prop === '$reactViewState') {
|
|
50
|
+
return reactViewState;
|
|
51
|
+
}
|
|
52
|
+
if (prop === '$proposedTransform') {
|
|
53
|
+
return proposedTransform;
|
|
54
|
+
}
|
|
55
|
+
if (prop === '$internalUpdate') {
|
|
56
|
+
return internalUpdate;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Ugly - this method is called from HandlerManager bypassing zoom setter
|
|
60
|
+
if (prop === '_setZoom') {
|
|
61
|
+
return (z: number) => {
|
|
62
|
+
if (internalUpdate) {
|
|
63
|
+
proposedTransform?.[prop](z);
|
|
64
|
+
}
|
|
65
|
+
if (!Number.isFinite(reactViewState.zoom)) {
|
|
66
|
+
controlledTransform[prop](z);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Ugly - this method is called from HandlerManager and mutates transform._camera
|
|
72
|
+
if (
|
|
73
|
+
internalUpdate &&
|
|
74
|
+
prop === '_translateCameraConstrained' &&
|
|
75
|
+
isViewStateControlled(reactViewState)
|
|
76
|
+
) {
|
|
77
|
+
proposedTransform = proposedTransform || controlledTransform.clone();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (unproxiedMethods.has(prop)) {
|
|
81
|
+
// When this function is executed, it updates both transforms respectively
|
|
82
|
+
return function (...parms: unknown[]) {
|
|
83
|
+
proposedTransform?.[prop](...parms);
|
|
84
|
+
controlledTransform[prop](...parms);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Expose the proposed transform to input handlers
|
|
89
|
+
if (internalUpdate && proposedTransform) {
|
|
90
|
+
return proposedTransform[prop];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Expose the controlled transform to renderer, markers, and event listeners
|
|
94
|
+
return controlledTransform[prop];
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
set(target: Transform, prop: string, value: unknown) {
|
|
98
|
+
// Props added by us
|
|
99
|
+
if (prop === '$reactViewState') {
|
|
100
|
+
reactViewState = value as Partial<ViewState>;
|
|
101
|
+
applyViewStateToTransform(controlledTransform, reactViewState);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (prop === '$proposedTransform') {
|
|
105
|
+
proposedTransform = value as Transform;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (prop === '$internalUpdate') {
|
|
109
|
+
internalUpdate = value as boolean;
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Controlled props
|
|
114
|
+
let controlledValue = value;
|
|
115
|
+
if (prop === 'center' || prop === '_center') {
|
|
116
|
+
if (Number.isFinite(reactViewState.longitude) || Number.isFinite(reactViewState.latitude)) {
|
|
117
|
+
// @ts-expect-error LngLat constructor is not typed
|
|
118
|
+
controlledValue = new value.constructor(
|
|
119
|
+
reactViewState.longitude ?? (value as LngLat).lng,
|
|
120
|
+
reactViewState.latitude ?? (value as LngLat).lat
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
} else if (prop === 'zoom' || prop === '_zoom' || prop === '_seaLevelZoom') {
|
|
124
|
+
if (Number.isFinite(reactViewState.zoom)) {
|
|
125
|
+
controlledValue = controlledTransform[prop];
|
|
126
|
+
}
|
|
127
|
+
} else if (prop === '_centerAltitude') {
|
|
128
|
+
if (Number.isFinite(reactViewState.elevation)) {
|
|
129
|
+
controlledValue = controlledTransform[prop];
|
|
130
|
+
}
|
|
131
|
+
} else if (prop === 'pitch' || prop === '_pitch') {
|
|
132
|
+
if (Number.isFinite(reactViewState.pitch)) {
|
|
133
|
+
controlledValue = controlledTransform[prop];
|
|
134
|
+
}
|
|
135
|
+
} else if (prop === 'bearing' || prop === 'rotation' || prop === 'angle') {
|
|
136
|
+
if (Number.isFinite(reactViewState.bearing)) {
|
|
137
|
+
controlledValue = controlledTransform[prop];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// During camera update, we save view states that are overriden by controlled values in proposedTransform
|
|
142
|
+
if (internalUpdate && controlledValue !== value) {
|
|
143
|
+
proposedTransform = proposedTransform || controlledTransform.clone();
|
|
144
|
+
}
|
|
145
|
+
if (internalUpdate && proposedTransform) {
|
|
146
|
+
proposedTransform[prop] = value;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// controlledTransform is not exposed to view state mutation
|
|
150
|
+
controlledTransform[prop] = controlledValue;
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
return new Proxy(tr, handlers) as ProxyTransform;
|
|
155
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
import type {PaddingOptions} from 'mapbox-gl';
|
|
7
|
+
|
|
8
|
+
export type {
|
|
9
|
+
Point,
|
|
10
|
+
PointLike,
|
|
11
|
+
LngLat,
|
|
12
|
+
LngLatLike,
|
|
13
|
+
LngLatBounds,
|
|
14
|
+
LngLatBoundsLike,
|
|
15
|
+
PaddingOptions,
|
|
16
|
+
GeoJSONFeature as MapGeoJSONFeature
|
|
17
|
+
} from 'mapbox-gl';
|
|
18
|
+
|
|
19
|
+
/* Public */
|
|
20
|
+
|
|
21
|
+
/** Describes the camera's state */
|
|
22
|
+
export type ViewState = {
|
|
23
|
+
/** Longitude at map center */
|
|
24
|
+
longitude: number;
|
|
25
|
+
/** Latitude at map center */
|
|
26
|
+
latitude: number;
|
|
27
|
+
/** Map zoom level */
|
|
28
|
+
zoom: number;
|
|
29
|
+
/** Map rotation bearing in degrees counter-clockwise from north */
|
|
30
|
+
bearing: number;
|
|
31
|
+
/** Map angle in degrees at which the camera is looking at the ground */
|
|
32
|
+
pitch: number;
|
|
33
|
+
/** Dimensions in pixels applied on each side of the viewport for shifting the vanishing point. */
|
|
34
|
+
padding: PaddingOptions;
|
|
35
|
+
/** Center elevation on terrain */
|
|
36
|
+
elevation?: number;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface ImmutableLike<T> {
|
|
40
|
+
toJS: () => T;
|
|
41
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
import type {ViewState, LngLat} from './common';
|
|
7
|
+
import {
|
|
8
|
+
Marker,
|
|
9
|
+
Popup,
|
|
10
|
+
GeolocateControl,
|
|
11
|
+
MapEvent,
|
|
12
|
+
MapEventOf,
|
|
13
|
+
ErrorEvent,
|
|
14
|
+
MapMouseEvent,
|
|
15
|
+
MapTouchEvent,
|
|
16
|
+
MapStyleDataEvent,
|
|
17
|
+
MapSourceDataEvent,
|
|
18
|
+
MapWheelEvent
|
|
19
|
+
} from 'mapbox-gl';
|
|
20
|
+
|
|
21
|
+
export type {
|
|
22
|
+
MapEvent,
|
|
23
|
+
ErrorEvent,
|
|
24
|
+
MapMouseEvent,
|
|
25
|
+
MapTouchEvent,
|
|
26
|
+
MapStyleDataEvent,
|
|
27
|
+
MapSourceDataEvent,
|
|
28
|
+
MapWheelEvent
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type MapBoxZoomEvent =
|
|
32
|
+
| MapEventOf<'boxzoomstart'>
|
|
33
|
+
| MapEventOf<'boxzoomend'>
|
|
34
|
+
| MapEventOf<'boxzoomcancel'>;
|
|
35
|
+
|
|
36
|
+
export type MapCallbacks = {
|
|
37
|
+
onMouseDown?: (e: MapMouseEvent) => void;
|
|
38
|
+
onMouseUp?: (e: MapMouseEvent) => void;
|
|
39
|
+
onMouseOver?: (e: MapMouseEvent) => void;
|
|
40
|
+
onMouseMove?: (e: MapMouseEvent) => void;
|
|
41
|
+
onClick?: (e: MapMouseEvent) => void;
|
|
42
|
+
onDblClick?: (e: MapMouseEvent) => void;
|
|
43
|
+
onMouseEnter?: (e: MapMouseEvent) => void;
|
|
44
|
+
onMouseLeave?: (e: MapMouseEvent) => void;
|
|
45
|
+
onMouseOut?: (e: MapMouseEvent) => void;
|
|
46
|
+
onContextMenu?: (e: MapMouseEvent) => void;
|
|
47
|
+
onTouchStart?: (e: MapTouchEvent) => void;
|
|
48
|
+
onTouchEnd?: (e: MapTouchEvent) => void;
|
|
49
|
+
onTouchMove?: (e: MapTouchEvent) => void;
|
|
50
|
+
onTouchCancel?: (e: MapTouchEvent) => void;
|
|
51
|
+
|
|
52
|
+
onMoveStart?: (e: ViewStateChangeEvent) => void;
|
|
53
|
+
onMove?: (e: ViewStateChangeEvent) => void;
|
|
54
|
+
onMoveEnd?: (e: ViewStateChangeEvent) => void;
|
|
55
|
+
onDragStart?: (e: ViewStateChangeEvent) => void;
|
|
56
|
+
onDrag?: (e: ViewStateChangeEvent) => void;
|
|
57
|
+
onDragEnd?: (e: ViewStateChangeEvent) => void;
|
|
58
|
+
onZoomStart?: (e: ViewStateChangeEvent) => void;
|
|
59
|
+
onZoom?: (e: ViewStateChangeEvent) => void;
|
|
60
|
+
onZoomEnd?: (e: ViewStateChangeEvent) => void;
|
|
61
|
+
onRotateStart?: (e: ViewStateChangeEvent) => void;
|
|
62
|
+
onRotate?: (e: ViewStateChangeEvent) => void;
|
|
63
|
+
onRotateEnd?: (e: ViewStateChangeEvent) => void;
|
|
64
|
+
onPitchStart?: (e: ViewStateChangeEvent) => void;
|
|
65
|
+
onPitch?: (e: ViewStateChangeEvent) => void;
|
|
66
|
+
onPitchEnd?: (e: ViewStateChangeEvent) => void;
|
|
67
|
+
|
|
68
|
+
onWheel?: (e: MapWheelEvent) => void;
|
|
69
|
+
onBoxZoomStart?: (e: MapBoxZoomEvent) => void;
|
|
70
|
+
onBoxZoomEnd?: (e: MapBoxZoomEvent) => void;
|
|
71
|
+
onBoxZoomCancel?: (e: MapBoxZoomEvent) => void;
|
|
72
|
+
|
|
73
|
+
onResize?: (e: MapEvent) => void;
|
|
74
|
+
onLoad?: (e: MapEvent) => void;
|
|
75
|
+
onRender?: (e: MapEvent) => void;
|
|
76
|
+
onIdle?: (e: MapEvent) => void;
|
|
77
|
+
onError?: (e: ErrorEvent) => void;
|
|
78
|
+
onRemove?: (e: MapEvent) => void;
|
|
79
|
+
onData?: (e: MapStyleDataEvent | MapSourceDataEvent) => void;
|
|
80
|
+
onStyleData?: (e: MapStyleDataEvent) => void;
|
|
81
|
+
onSourceData?: (e: MapSourceDataEvent) => void;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
interface IMapEvent<SourceT, OriginalEventT = undefined> {
|
|
85
|
+
type: string;
|
|
86
|
+
target: SourceT;
|
|
87
|
+
originalEvent: OriginalEventT;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface Callbacks {
|
|
91
|
+
[key: `on${string}`]: Function;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type ViewStateChangeEvent = MapEventOf<
|
|
95
|
+
| 'movestart'
|
|
96
|
+
| 'move'
|
|
97
|
+
| 'moveend'
|
|
98
|
+
| 'zoomstart'
|
|
99
|
+
| 'zoom'
|
|
100
|
+
| 'zoomend'
|
|
101
|
+
| 'rotatestart'
|
|
102
|
+
| 'rotate'
|
|
103
|
+
| 'rotateend'
|
|
104
|
+
| 'dragstart'
|
|
105
|
+
| 'drag'
|
|
106
|
+
| 'dragend'
|
|
107
|
+
| 'pitchstart'
|
|
108
|
+
| 'pitch'
|
|
109
|
+
| 'pitchend'
|
|
110
|
+
> & {
|
|
111
|
+
viewState: ViewState;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export type PopupEvent = {
|
|
115
|
+
type: 'open' | 'close';
|
|
116
|
+
target: Popup;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export type MarkerEvent<OriginalEventT = undefined> = IMapEvent<Marker, OriginalEventT>;
|
|
120
|
+
|
|
121
|
+
export type MarkerDragEvent = MarkerEvent & {
|
|
122
|
+
type: 'dragstart' | 'drag' | 'dragend';
|
|
123
|
+
lngLat: LngLat;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export type GeolocateEvent = IMapEvent<GeolocateControl>;
|
|
127
|
+
|
|
128
|
+
export type GeolocateResultEvent = GeolocateEvent & GeolocationPosition;
|
|
129
|
+
|
|
130
|
+
export type GeolocateErrorEvent = GeolocateEvent & GeolocationPositionError;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
// Internal types
|
|
7
|
+
import type {Map} from 'mapbox-gl';
|
|
8
|
+
|
|
9
|
+
export type Transform = Map['transform'];
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
GeoJSONSource as GeoJSONSourceImplementation,
|
|
13
|
+
ImageSource as ImageSourceImplementation,
|
|
14
|
+
CanvasSource as CanvasSourceImplementation,
|
|
15
|
+
VectorTileSource as VectorSourceImplementation,
|
|
16
|
+
RasterTileSource as RasterSourceImplementation,
|
|
17
|
+
RasterDemTileSource as RasterDemSourceImplementation,
|
|
18
|
+
VideoSource as VideoSourceImplementation,
|
|
19
|
+
Source as AnySourceImplementation
|
|
20
|
+
} from 'mapbox-gl';
|
package/src/types/lib.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
import type {
|
|
7
|
+
Map,
|
|
8
|
+
MapOptions,
|
|
9
|
+
Marker,
|
|
10
|
+
MarkerOptions,
|
|
11
|
+
Popup,
|
|
12
|
+
PopupOptions,
|
|
13
|
+
AttributionControl,
|
|
14
|
+
AttributionControlOptions,
|
|
15
|
+
FullscreenControl,
|
|
16
|
+
FullscreenControlOptions,
|
|
17
|
+
GeolocateControl,
|
|
18
|
+
GeolocateControlOptions,
|
|
19
|
+
NavigationControl,
|
|
20
|
+
NavigationControlOptions,
|
|
21
|
+
ScaleControl,
|
|
22
|
+
ScaleControlOptions
|
|
23
|
+
} from 'mapbox-gl';
|
|
24
|
+
|
|
25
|
+
export type {
|
|
26
|
+
ControlPosition,
|
|
27
|
+
IControl,
|
|
28
|
+
Map as MapInstance,
|
|
29
|
+
MapOptions,
|
|
30
|
+
Marker as MarkerInstance,
|
|
31
|
+
MarkerOptions,
|
|
32
|
+
Popup as PopupInstance,
|
|
33
|
+
PopupOptions,
|
|
34
|
+
AttributionControl as AttributionControlInstance,
|
|
35
|
+
AttributionControlOptions,
|
|
36
|
+
FullscreenControl as FullscreenControlInstance,
|
|
37
|
+
FullscreenControlOptions,
|
|
38
|
+
GeolocateControl as GeolocateControlInstance,
|
|
39
|
+
GeolocateControlOptions,
|
|
40
|
+
NavigationControl as NavigationControlInstance,
|
|
41
|
+
NavigationControlOptions,
|
|
42
|
+
ScaleControl as ScaleControlInstance,
|
|
43
|
+
ScaleControlOptions,
|
|
44
|
+
CustomLayerInterface
|
|
45
|
+
} from 'mapbox-gl';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* A user-facing type that represents the minimal intersection between Mapbox and Maplibre
|
|
49
|
+
* User provided `mapLib` is supposed to implement this interface
|
|
50
|
+
* Only losely typed for compatibility
|
|
51
|
+
*/
|
|
52
|
+
export interface MapLib {
|
|
53
|
+
supported?: (options: any) => boolean;
|
|
54
|
+
|
|
55
|
+
Map: {new (options: MapOptions): Map};
|
|
56
|
+
|
|
57
|
+
Marker: {new (options: MarkerOptions): Marker};
|
|
58
|
+
|
|
59
|
+
Popup: {new (options: PopupOptions): Popup};
|
|
60
|
+
|
|
61
|
+
AttributionControl: {new (options: AttributionControlOptions): AttributionControl};
|
|
62
|
+
|
|
63
|
+
FullscreenControl: {new (options: FullscreenControlOptions): FullscreenControl};
|
|
64
|
+
|
|
65
|
+
GeolocateControl: {new (options: GeolocateControlOptions): GeolocateControl};
|
|
66
|
+
|
|
67
|
+
NavigationControl: {new (options: NavigationControlOptions): NavigationControl};
|
|
68
|
+
|
|
69
|
+
ScaleControl: {new (options: ScaleControlOptions): ScaleControl};
|
|
70
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Octane replacements for the React types the upstream binding uses in its
|
|
3
|
+
* public props. Upstream reaches for `React.CSSProperties`, `React.ReactNode`
|
|
4
|
+
* and `React.Ref`; this module is where those three become Octane types so the
|
|
5
|
+
* ported components read like their upstream counterparts everywhere else.
|
|
6
|
+
*
|
|
7
|
+
* There is no upstream module at this path. It is a port-owned addition.
|
|
8
|
+
*/
|
|
9
|
+
import type { OctaneNode } from 'octane';
|
|
10
|
+
import type { Octane } from 'octane/jsx-runtime';
|
|
11
|
+
|
|
12
|
+
/** Structural equivalent of `React.CSSProperties`, taken from the host typing. */
|
|
13
|
+
export type CSSProperties = Exclude<
|
|
14
|
+
Octane.JSX.IntrinsicElements['div']['style'],
|
|
15
|
+
string | undefined
|
|
16
|
+
> & {
|
|
17
|
+
[customProperty: `--${string}`]: string | number | undefined;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Anything renderable in a child position — upstream's `React.ReactNode`. */
|
|
21
|
+
export type MapChildren = OctaneNode;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Octane has no `forwardRef`: a ref is an ordinary prop, so a component that
|
|
25
|
+
* exposes an imperative handle declares `ref?: Ref<T>` in its own props.
|
|
26
|
+
*/
|
|
27
|
+
export type Ref<T> = ((value: T | null) => void) | { current: T | null } | null;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
/*
|
|
7
|
+
* Mapbox Style Specification types
|
|
8
|
+
*/
|
|
9
|
+
export type CanvasSourceSpecification = {
|
|
10
|
+
type: 'canvas';
|
|
11
|
+
coordinates: [[number, number], [number, number], [number, number], [number, number]];
|
|
12
|
+
animate?: boolean;
|
|
13
|
+
canvas: string | HTMLCanvasElement;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
// Layers
|
|
18
|
+
LayerSpecification,
|
|
19
|
+
FillLayerSpecification,
|
|
20
|
+
LineLayerSpecification,
|
|
21
|
+
SymbolLayerSpecification,
|
|
22
|
+
CircleLayerSpecification,
|
|
23
|
+
HeatmapLayerSpecification,
|
|
24
|
+
FillExtrusionLayerSpecification,
|
|
25
|
+
RasterLayerSpecification,
|
|
26
|
+
RasterParticleLayerSpecification,
|
|
27
|
+
HillshadeLayerSpecification,
|
|
28
|
+
ModelLayerSpecification,
|
|
29
|
+
BackgroundLayerSpecification,
|
|
30
|
+
SkyLayerSpecification,
|
|
31
|
+
SlotLayerSpecification,
|
|
32
|
+
ClipLayerSpecification,
|
|
33
|
+
|
|
34
|
+
// Sources
|
|
35
|
+
SourceSpecification,
|
|
36
|
+
VectorSourceSpecification,
|
|
37
|
+
RasterSourceSpecification,
|
|
38
|
+
RasterDEMSourceSpecification,
|
|
39
|
+
RasterArraySourceSpecification,
|
|
40
|
+
GeoJSONSourceSpecification,
|
|
41
|
+
VideoSourceSpecification,
|
|
42
|
+
ImageSourceSpecification,
|
|
43
|
+
ModelSourceSpecification,
|
|
44
|
+
|
|
45
|
+
// Style
|
|
46
|
+
StyleSpecification,
|
|
47
|
+
LightSpecification,
|
|
48
|
+
FogSpecification,
|
|
49
|
+
TerrainSpecification,
|
|
50
|
+
ProjectionSpecification
|
|
51
|
+
} from 'mapbox-gl';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CSSProperties } from '../types/octane';
|
|
2
|
+
// This is a simplified version of
|
|
3
|
+
// https://github.com/facebook/react/blob/4131af3e4bf52f3a003537ec95a1655147c81270/src/renderers/dom/shared/CSSPropertyOperations.js#L62
|
|
4
|
+
const unitlessNumber = /box|flex|grid|column|lineHeight|fontWeight|opacity|order|tabSize|zIndex/;
|
|
5
|
+
|
|
6
|
+
// Ported from upstream src/utils/apply-react-style.ts. The only change is the
|
|
7
|
+
// style type: upstream annotates it `React.CSSProperties`. The name is kept
|
|
8
|
+
// because it is the upstream module name, not a claim about React.
|
|
9
|
+
export function applyReactStyle(
|
|
10
|
+
element: HTMLElement | undefined,
|
|
11
|
+
styles: CSSProperties | undefined,
|
|
12
|
+
): void {
|
|
13
|
+
if (!element || !styles) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const style = element.style;
|
|
17
|
+
|
|
18
|
+
for (const key in styles) {
|
|
19
|
+
const value = (styles as Record<string, unknown>)[key];
|
|
20
|
+
if (Number.isFinite(value) && !unitlessNumber.test(key)) {
|
|
21
|
+
(style as unknown as Record<string, unknown>)[key] = `${value}px`;
|
|
22
|
+
} else {
|
|
23
|
+
(style as unknown as Record<string, unknown>)[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
export default function assert(condition: any, message: string) {
|
|
7
|
+
if (!condition) {
|
|
8
|
+
throw new Error(message);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Children, isChildrenBlock } from 'octane';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Upstream `Marker` asks whether it was given any children with
|
|
5
|
+
*
|
|
6
|
+
* React.Children.forEach(props.children, el => { if (el) hasChildren = true })
|
|
7
|
+
*
|
|
8
|
+
* and uses the answer to choose between Mapbox's own default pin and a
|
|
9
|
+
* binding-created element it portals custom content into.
|
|
10
|
+
*
|
|
11
|
+
* Octane's compiler lowers a `.tsrx` parent's element children to a
|
|
12
|
+
* children-block render function rather than a descriptor array, so
|
|
13
|
+
* `Children.forEach` alone cannot see them. A `.tsx` parent still produces
|
|
14
|
+
* descriptors. Both dialects reach this binding, so both are handled here.
|
|
15
|
+
*
|
|
16
|
+
* There is no upstream module at this path. It is a port-owned addition.
|
|
17
|
+
*/
|
|
18
|
+
export function hasRenderableChildren(children: unknown): boolean {
|
|
19
|
+
if (children == null) return false;
|
|
20
|
+
if (isChildrenBlock(children)) return true;
|
|
21
|
+
let found = false;
|
|
22
|
+
Children.forEach(children, (child) => {
|
|
23
|
+
if (child) found = true;
|
|
24
|
+
});
|
|
25
|
+
return found;
|
|
26
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
/** Compare two classNames string and return the difference */
|
|
7
|
+
export function compareClassNames(
|
|
8
|
+
prevClassName: string | undefined,
|
|
9
|
+
nextClassName: string | undefined
|
|
10
|
+
): string[] | null {
|
|
11
|
+
if (prevClassName === nextClassName) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const prevClassList = getClassList(prevClassName);
|
|
16
|
+
const nextClassList = getClassList(nextClassName);
|
|
17
|
+
const diff: string[] = [];
|
|
18
|
+
|
|
19
|
+
for (const c of nextClassList) {
|
|
20
|
+
if (!prevClassList.has(c)) {
|
|
21
|
+
diff.push(c);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
for (const c of prevClassList) {
|
|
25
|
+
if (!nextClassList.has(c)) {
|
|
26
|
+
diff.push(c);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return diff.length === 0 ? null : diff;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getClassList(className: string | undefined) {
|
|
33
|
+
return new Set(className ? className.trim().split(/\s+/) : []);
|
|
34
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @ts-nocheck — byte-exact reuse of @vis.gl/react-mapbox 8.1.2. Upstream compiles
|
|
2
|
+
// without strictNullChecks or noImplicitAny; this repository is strict. The copy
|
|
3
|
+
// under upstream/ is typechecked with upstream's own configuration instead, so
|
|
4
|
+
// nothing here is unchecked, only checked at the settings its authors chose.
|
|
5
|
+
// Every line below this four-line banner is byte-identical to upstream.
|
|
6
|
+
import type {PointLike} from '../types/common';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compare two points
|
|
10
|
+
* @param a
|
|
11
|
+
* @param b
|
|
12
|
+
* @returns true if the points are equal
|
|
13
|
+
*/
|
|
14
|
+
export function arePointsEqual(a?: PointLike, b?: PointLike): boolean {
|
|
15
|
+
const ax = Array.isArray(a) ? a[0] : a ? a.x : 0;
|
|
16
|
+
const ay = Array.isArray(a) ? a[1] : a ? a.y : 0;
|
|
17
|
+
const bx = Array.isArray(b) ? b[0] : b ? b.x : 0;
|
|
18
|
+
const by = Array.isArray(b) ? b[1] : b ? b.y : 0;
|
|
19
|
+
return ax === bx && ay === by;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* eslint-disable complexity */
|
|
23
|
+
/**
|
|
24
|
+
* Compare any two objects
|
|
25
|
+
* @param a
|
|
26
|
+
* @param b
|
|
27
|
+
* @returns true if the objects are deep equal
|
|
28
|
+
*/
|
|
29
|
+
export function deepEqual(a: any, b: any): boolean {
|
|
30
|
+
if (a === b) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (!a || !b) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(a)) {
|
|
37
|
+
if (!Array.isArray(b) || a.length !== b.length) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
for (let i = 0; i < a.length; i++) {
|
|
41
|
+
if (!deepEqual(a[i], b[i])) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
} else if (Array.isArray(b)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (typeof a === 'object' && typeof b === 'object') {
|
|
50
|
+
const aKeys = Object.keys(a);
|
|
51
|
+
const bKeys = Object.keys(b);
|
|
52
|
+
if (aKeys.length !== bKeys.length) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
for (const key of aKeys) {
|
|
56
|
+
if (!b.hasOwnProperty(key)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (!deepEqual(a[key], b[key])) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|