Skip to content

Commit

Permalink
Import style and event types from specific base libraries (visgl#2252)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress authored Aug 18, 2023
1 parent ec63f69 commit 9645b75
Show file tree
Hide file tree
Showing 17 changed files with 497 additions and 332 deletions.
33 changes: 17 additions & 16 deletions src/components/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,33 @@ import {MapContext} from './map';
import assert from '../utils/assert';
import {deepEqual} from '../utils/deep-equal';

import type {MapInstance, AnyLayer, CustomLayerInterface} from '../types';
import type {MapInstance, CustomLayerInterface, ILayer} from '../types';

// Omiting property from a union type, see
// https://github.com/microsoft/TypeScript/issues/39556#issuecomment-656925230
type OptionalId<T> = T extends {id: string} ? Omit<T, 'id'> & {id?: string} : T;
type OptionalSource<T> = T extends {source: string} ? Omit<T, 'source'> & {source?: string} : T;

export type LayerProps = OptionalSource<OptionalId<AnyLayer | CustomLayerInterface>> & {
export type LayerProps<LayerT> = OptionalSource<OptionalId<LayerT>> & {
/** If set, the layer will be inserted before the specified layer */
beforeId?: string;
};

/* eslint-disable complexity, max-statements */
function updateLayer(map: MapInstance, id: string, props: LayerProps, prevProps: LayerProps) {
function updateLayer<LayerT extends ILayer>(
map: MapInstance,
id: string,
props: LayerProps<LayerT>,
prevProps: LayerProps<LayerT>
) {
assert(props.id === prevProps.id, 'layer id changed');
assert(props.type === prevProps.type, 'layer type changed');

if (props.type === 'custom' || prevProps.type === 'custom') {
return;
}

const {
layout = {},
paint = {},
// @ts-expect-error filter is not defined on some layer types
filter,
minzoom,
maxzoom,
beforeId
} = props;
const {layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId} = props;

if (beforeId !== prevProps.beforeId) {
map.moveLayer(id, beforeId);
Expand Down Expand Up @@ -63,7 +60,7 @@ function updateLayer(map: MapInstance, id: string, props: LayerProps, prevProps:
}
}
}
// @ts-expect-error filter is not defined on some layer types

if (!deepEqual(filter, prevProps.filter)) {
map.setFilter(id, filter);
}
Expand All @@ -72,10 +69,14 @@ function updateLayer(map: MapInstance, id: string, props: LayerProps, prevProps:
}
}

function createLayer(map: MapInstance, id: string, props: LayerProps) {
function createLayer<LayerT extends ILayer>(
map: MapInstance,
id: string,
props: LayerProps<LayerT>
) {
// @ts-ignore
if (map.style && map.style._loaded && (!('source' in props) || map.getSource(props.source))) {
const options: LayerProps = {...props, id};
const options: LayerProps<LayerT> = {...props, id};
delete options.beforeId;

// @ts-ignore
Expand All @@ -87,7 +88,7 @@ function createLayer(map: MapInstance, id: string, props: LayerProps) {

let layerCounter = 0;

function Layer(props: LayerProps) {
function Layer<LayerT extends ILayer>(props: LayerProps<LayerT | CustomLayerInterface>) {
const map = useContext(MapContext).map.getMap();
const propsRef = useRef(props);
const [, setStyleLoaded] = useState(0);
Expand Down
24 changes: 17 additions & 7 deletions src/components/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import createRef, {MapRef} from '../mapbox/create-ref';
import type {CSSProperties} from 'react';
import useIsomorphicLayoutEffect from '../utils/use-isomorphic-layout-effect';
import setGlobals, {GlobalSettings} from '../utils/set-globals';
import type {MapLib, MapInstance} from '../types';
import type {MapLib, MapInstance, MapStyle, Callbacks} from '../types';

export type MapContextValue<MapT extends MapInstance = MapInstance> = {
mapLib: MapLib<MapT>;
Expand All @@ -22,8 +22,13 @@ type MapInitOptions<MapOptions> = Omit<
'style' | 'container' | 'bounds' | 'fitBoundsOptions' | 'center'
>;

export type MapProps<MapOptions, MapT extends MapInstance> = MapInitOptions<MapOptions> &
MapboxProps<MapT> &
export type MapProps<
MapOptions,
StyleT extends MapStyle,
CallbacksT extends Callbacks,
MapT extends MapInstance
> = MapInitOptions<MapOptions> &
MapboxProps<StyleT, CallbacksT> &
GlobalSettings & {
mapLib?: MapLib<MapT> | Promise<MapLib<MapT>>;
reuseMaps?: boolean;
Expand All @@ -34,21 +39,26 @@ export type MapProps<MapOptions, MapT extends MapInstance> = MapInitOptions<MapO
children?: any;
};

export default function Map<MapOptions, MapT extends MapInstance>(
props: MapProps<MapOptions, MapT>,
export default function Map<
MapOptions,
StyleT extends MapStyle,
CallbacksT extends Callbacks,
MapT extends MapInstance
>(
props: MapProps<MapOptions, StyleT, CallbacksT, MapT>,
ref: React.Ref<MapRef<MapT>>,
defaultLib: MapLib<MapT> | Promise<MapLib<MapT>>
) {
const mountedMapsContext = useContext(MountedMapsContext);
const [mapInstance, setMapInstance] = useState<Mapbox<MapT>>(null);
const [mapInstance, setMapInstance] = useState<Mapbox<StyleT, CallbacksT, MapT>>(null);
const containerRef = useRef();

const {current: contextValue} = useRef<MapContextValue<MapT>>({mapLib: null, map: null});

useEffect(() => {
const mapLib = props.mapLib;
let isMounted = true;
let mapbox: Mapbox<MapT>;
let mapbox: Mapbox<StyleT, CallbacksT, MapT>;

Promise.resolve(mapLib || defaultLib)
.then((module: MapLib<MapT> | {default: MapLib<MapT>}) => {
Expand Down
36 changes: 22 additions & 14 deletions src/components/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,26 @@ import {deepEqual} from '../utils/deep-equal';

import type {
MapInstance,
AnySource,
ISource,
CustomSource,
GeoJSONSource,
GeoJSONSourceImplementation,
ImageSource,
ImageSourceImplemtation,
VectorSource,
AnySourceImplementation
} from '../types';
import type {GeoJSONSource, ImageSource, VectorSource} from '../types/style-spec-maplibre';

export type SourceProps = (AnySource | CustomSource) & {
export type SourceProps<SourceT> = (SourceT | CustomSource) & {
id?: string;
children?: any;
};

let sourceCounter = 0;

function createSource(map: MapInstance, id: string, props: SourceProps) {
function createSource<SourceT extends ISource>(
map: MapInstance,
id: string,
props: SourceProps<SourceT>
) {
// @ts-ignore
if (map.style && map.style._loaded) {
const options = {...props};
Expand All @@ -38,7 +40,11 @@ function createSource(map: MapInstance, id: string, props: SourceProps) {
}

/* eslint-disable complexity */
function updateSource(source: AnySourceImplementation, props: SourceProps, prevProps: SourceProps) {
function updateSource<SourceT extends ISource>(
source: AnySourceImplementation,
props: SourceProps<SourceT>,
prevProps: SourceProps<SourceT>
) {
assert(props.id === prevProps.id, 'source id changed');
assert(props.type === prevProps.type, 'source type changed');

Expand All @@ -59,24 +65,26 @@ function updateSource(source: AnySourceImplementation, props: SourceProps, prevP
const type = props.type;

if (type === 'geojson') {
(source as GeoJSONSourceImplementation).setData((props as GeoJSONSource).data as any);
(source as GeoJSONSourceImplementation).setData(
(props as unknown as GeoJSONSource).data as any
);
} else if (type === 'image') {
(source as ImageSourceImplemtation).updateImage({
url: props.url,
coordinates: props.coordinates
url: (props as unknown as ImageSource).url,
coordinates: (props as unknown as ImageSource).coordinates
});
} else if ('setCoordinates' in source && changedKeyCount === 1 && changedKey === 'coordinates') {
source.setCoordinates((props as unknown as ImageSource).coordinates);
source.setCoordinates((props as ImageSource).coordinates);
} else if ('setUrl' in source) {
// Added in 1.12.0:
// vectorTileSource.setTiles
// vectorTileSource.setUrl
switch (changedKey) {
case 'url':
source.setUrl((props as unknown as VectorSource).url);
source.setUrl((props as VectorSource).url);
break;
case 'tiles':
source.setTiles((props as unknown as VectorSource).tiles);
source.setTiles((props as VectorSource).tiles);
break;
default:
}
Expand All @@ -87,7 +95,7 @@ function updateSource(source: AnySourceImplementation, props: SourceProps, prevP
}
/* eslint-enable complexity */

function Source(props: SourceProps) {
function Source<SourceT extends ISource>(props: SourceProps<SourceT>) {
const map = useContext(MapContext).map.getMap();
const propsRef = useRef(props);
const [, setStyleLoaded] = useState(0);
Expand Down
43 changes: 26 additions & 17 deletions src/exports-mapbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
NavigationControl as MapboxNavigationControl,
ScaleControl as MapboxScaleControl
} from 'mapbox-gl';
import {MapboxStyle, AnyLayer, AnySource} from './types/style-spec-mapbox';

import {default as _Map, MapProps as _MapProps} from './components/map';
import {default as _Marker, MarkerProps as _MarkerProps} from './components/marker';
Expand All @@ -36,20 +37,23 @@ import {
default as _ScaleControl,
ScaleControlProps as _ScaleControlProps
} from './components/scale-control';
import {default as _Layer, LayerProps as _LayerProps} from './components/layer';
import {default as _Source, SourceProps as _SourceProps} from './components/source';
import {useMap as _useMap} from './components/use-map';
import type {MapRef as _MapRef} from './mapbox/create-ref';
import type * as events from './types/events';
import type {MapCallbacks} from './types/events-mapbox';

export function useMap() {
return _useMap<MapboxMap>();
}

export type MapProps = _MapProps<MapboxOptions, MapboxMap>;
export type MapProps = _MapProps<MapboxOptions, MapboxStyle, MapCallbacks, MapboxMap>;
export type MapRef = _MapRef<MapboxMap>;
const mapLib = import('mapbox-gl');
export const Map = (() => {
return React.forwardRef(function Map(props: MapProps, ref: React.Ref<MapRef>) {
return _Map(props, ref, mapLib);
return _Map<MapboxOptions, MapboxStyle, MapCallbacks, MapboxMap>(props, ref, mapLib);
});
})();

Expand Down Expand Up @@ -96,30 +100,35 @@ export const ScaleControl = _ScaleControl as (
props: ScaleControlProps
) => React.ReactElement | null;

export {default as Source} from './components/source';
export {default as Layer} from './components/layer';
export type LayerProps = _LayerProps<AnyLayer>;
export const Layer = _Layer as (props: LayerProps) => React.ReactElement | null;

export type SourceProps = _SourceProps<AnySource>;
export const Source = _Source as (props: SourceProps) => React.ReactElement | null;

export {default as useControl} from './components/use-control';
export {MapProvider} from './components/use-map';

export default Map;

// Types
export * from './types/public';
export type {SourceProps} from './components/source';
export type {LayerProps} from './components/layer';
export * from './types/style-spec-mapbox';

// Events
export type MapEvent = events.MapEvent<MapboxMap>;
export type ErrorEvent = events.ErrorEvent<MapboxMap>;
export type MapStyleDataEvent = events.MapStyleDataEvent<MapboxMap>;
export type MapSourceDataEvent = events.MapSourceDataEvent<MapboxMap>;
export type MapMouseEvent = events.MapMouseEvent<MapboxMap>;
export type MapLayerMouseEvent = events.MapLayerMouseEvent<MapboxMap>;
export type MapTouchEvent = events.MapTouchEvent<MapboxMap>;
export type MapLayerTouchEvent = events.MapLayerTouchEvent<MapboxMap>;
export type MapWheelEvent = events.MapWheelEvent<MapboxMap>;
export type MapBoxZoomEvent = events.MapBoxZoomEvent<MapboxMap>;
export type ViewStateChangeEvent = events.ViewStateChangeEvent<MapboxMap>;
export type {
MapEvent,
MapMouseEvent,
MapLayerMouseEvent,
MapTouchEvent,
MapLayerTouchEvent,
MapStyleDataEvent,
MapSourceDataEvent,
MapWheelEvent,
MapBoxZoomEvent,
ErrorEvent,
ViewStateChangeEvent
} from './types/events-mapbox';
export type PopupEvent = events.PopupEvent<MapboxPopup>;
export type MarkerEvent = events.MarkerEvent<MapboxMarker>;
export type MarkerDragEvent = events.MarkerDragEvent<MapboxMarker>;
Expand Down
43 changes: 26 additions & 17 deletions src/exports-maplibre.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
NavigationControl as MaplibreNavigationControl,
ScaleControl as MaplibreScaleControl
} from 'maplibre-gl';
import {MapboxStyle, AnyLayer, AnySource} from './types/style-spec-maplibre';

import {default as _Map, MapProps as _MapProps} from './components/map';
import {default as _Marker, MarkerProps as _MarkerProps} from './components/marker';
Expand All @@ -36,20 +37,23 @@ import {
default as _ScaleControl,
ScaleControlProps as _ScaleControlProps
} from './components/scale-control';
import {default as _Layer, LayerProps as _LayerProps} from './components/layer';
import {default as _Source, SourceProps as _SourceProps} from './components/source';
import {useMap as _useMap} from './components/use-map';
import type {MapRef as _MapRef} from './mapbox/create-ref';
import type * as events from './types/events';
import type {MapCallbacks} from './types/events-maplibre';

export function useMap() {
return _useMap<MaplibreMap>();
}

export type MapProps = _MapProps<MapOptions, MaplibreMap>;
export type MapProps = _MapProps<MapOptions, MapboxStyle, MapCallbacks, MaplibreMap>;
export type MapRef = _MapRef<MaplibreMap>;
const mapLib = import('maplibre-gl');
export const Map = (() => {
return React.forwardRef(function Map(props: MapProps, ref: React.Ref<MapRef>) {
return _Map(props, ref, mapLib);
return _Map<MapOptions, MapboxStyle, MapCallbacks, MaplibreMap>(props, ref, mapLib);
});
})();

Expand Down Expand Up @@ -96,30 +100,35 @@ export const ScaleControl = _ScaleControl as (
props: ScaleControlProps
) => React.ReactElement | null;

export {default as Source} from './components/source';
export {default as Layer} from './components/layer';
export type LayerProps = _LayerProps<AnyLayer>;
export const Layer = _Layer as (props: LayerProps) => React.ReactElement | null;

export type SourceProps = _SourceProps<AnySource>;
export const Source = _Source as (props: SourceProps) => React.ReactElement | null;

export {default as useControl} from './components/use-control';
export {MapProvider} from './components/use-map';

export default Map;

// Types
export * from './types/public';
export type {SourceProps} from './components/source';
export type {LayerProps} from './components/layer';
export * from './types/style-spec-maplibre';

// Events
export type MapEvent = events.MapEvent<MaplibreMap>;
export type ErrorEvent = events.ErrorEvent<MaplibreMap>;
export type MapStyleDataEvent = events.MapStyleDataEvent<MaplibreMap>;
export type MapSourceDataEvent = events.MapSourceDataEvent<MaplibreMap>;
export type MapMouseEvent = events.MapMouseEvent<MaplibreMap>;
export type MapLayerMouseEvent = events.MapLayerMouseEvent<MaplibreMap>;
export type MapTouchEvent = events.MapTouchEvent<MaplibreMap>;
export type MapLayerTouchEvent = events.MapLayerTouchEvent<MaplibreMap>;
export type MapWheelEvent = events.MapWheelEvent<MaplibreMap>;
export type MapBoxZoomEvent = events.MapBoxZoomEvent<MaplibreMap>;
export type ViewStateChangeEvent = events.ViewStateChangeEvent<MaplibreMap>;
export type {
MapEvent,
MapMouseEvent,
MapLayerMouseEvent,
MapTouchEvent,
MapLayerTouchEvent,
MapStyleDataEvent,
MapSourceDataEvent,
MapWheelEvent,
MapBoxZoomEvent,
ErrorEvent,
ViewStateChangeEvent
} from './types/events-maplibre';
export type PopupEvent = events.PopupEvent<MaplibrePopup>;
export type MarkerEvent = events.MarkerEvent<MaplibreMarker>;
export type MarkerDragEvent = events.MarkerDragEvent<MaplibreMarker>;
Expand Down
Loading

0 comments on commit 9645b75

Please sign in to comment.