A few more components migrated

This commit is contained in:
HarelM
2023-12-22 14:41:38 +02:00
parent 1a7754c78d
commit a36f56fe93
7 changed files with 132 additions and 124 deletions
@@ -2,16 +2,16 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import ScrollContainer from './ScrollContainer' import ScrollContainer from './ScrollContainer'
class AppLayout extends React.Component { type AppLayoutProps = {
static propTypes = { toolbar: React.ReactElement
toolbar: PropTypes.element.isRequired, layerList: React.ReactElement
layerList: PropTypes.element.isRequired, layerEditor?: React.ReactElement
layerEditor: PropTypes.element, map: React.ReactElement
map: PropTypes.element.isRequired, bottom?: React.ReactElement
bottom: PropTypes.element, modals?: React.ReactNode
modals: PropTypes.node, };
}
class AppLayout extends React.Component<AppLayoutProps> {
static childContextTypes = { static childContextTypes = {
reactIconBase: PropTypes.object reactIconBase: PropTypes.object
} }
@@ -1,29 +1,28 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import {formatLayerId} from '../util/format'; import {formatLayerId} from '../util/format';
import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
export default class AppMessagePanel extends React.Component { type AppMessagePanelProps = {
static propTypes = { errors?: unknown[]
errors: PropTypes.array, infos?: unknown[]
infos: PropTypes.array, mapStyle?: StyleSpecification
mapStyle: PropTypes.object, onLayerSelect?(...args: unknown[]): unknown
onLayerSelect: PropTypes.func, currentLayer?: object
currentLayer: PropTypes.object, selectedLayerIndex?: number
selectedLayerIndex: PropTypes.number, };
}
export default class AppMessagePanel extends React.Component<AppMessagePanelProps> {
static defaultProps = { static defaultProps = {
onLayerSelect: () => {}, onLayerSelect: () => {},
} }
render() { render() {
const {selectedLayerIndex} = this.props; const {selectedLayerIndex} = this.props;
const errors = this.props.errors.map((error, idx) => { const errors = this.props.errors?.map((error: any, idx) => {
let content; let content;
if (error.parsed && error.parsed.type === "layer") { if (error.parsed && error.parsed.type === "layer") {
const {parsed} = error; const {parsed} = error;
const {mapStyle, currentLayer} = this.props; const layerId = this.props.mapStyle?.layers[parsed.data.index].id;
const layerId = mapStyle.layers[parsed.data.index].id;
content = ( content = (
<> <>
Layer <span>{formatLayerId(layerId)}</span>: {parsed.data.message} Layer <span>{formatLayerId(layerId)}</span>: {parsed.data.message}
@@ -32,7 +31,7 @@ export default class AppMessagePanel extends React.Component {
&nbsp;&mdash;&nbsp; &nbsp;&mdash;&nbsp;
<button <button
className="maputnik-message-panel__switch-button" className="maputnik-message-panel__switch-button"
onClick={() => this.props.onLayerSelect(parsed.data.index)} onClick={() => this.props.onLayerSelect!(parsed.data.index)}
> >
switch to layer switch to layer
</button> </button>
@@ -49,7 +48,7 @@ export default class AppMessagePanel extends React.Component {
</p> </p>
}) })
const infos = this.props.infos.map((m, i) => { const infos = this.props.infos?.map((m, i) => {
return <p key={"info-"+i}>{m}</p> return <p key={"info-"+i}>{m}</p>
}) })
@@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames' import classnames from 'classnames'
import {detect} from 'detect-browser'; import {detect} from 'detect-browser';
@@ -9,27 +8,28 @@ import pkgJson from '../../package.json'
// This is required because of <https://stackoverflow.com/a/49846426>, there isn't another way to detect support that I'm aware of. // This is required because of <https://stackoverflow.com/a/49846426>, there isn't another way to detect support that I'm aware of.
const browser = detect(); const browser = detect();
const colorAccessibilityFiltersEnabled = ['chrome', 'firefox'].indexOf(browser.name) > -1; const colorAccessibilityFiltersEnabled = ['chrome', 'firefox'].indexOf(browser!.name) > -1;
class IconText extends React.Component { type IconTextProps = {
static propTypes = { children?: React.ReactNode
children: PropTypes.node, };
}
class IconText extends React.Component<IconTextProps> {
render() { render() {
return <span className="maputnik-icon-text">{this.props.children}</span> return <span className="maputnik-icon-text">{this.props.children}</span>
} }
} }
class ToolbarLink extends React.Component { type ToolbarLinkProps = {
static propTypes = { className?: string
className: PropTypes.string, children?: React.ReactNode
children: PropTypes.node, href?: string
href: PropTypes.string, onToggleModal?(...args: unknown[]): unknown
onToggleModal: PropTypes.func, };
}
class ToolbarLink extends React.Component<ToolbarLinkProps> {
render() { render() {
return <a return <a
className={classnames('maputnik-toolbar-link', this.props.className)} className={classnames('maputnik-toolbar-link', this.props.className)}
@@ -42,14 +42,14 @@ class ToolbarLink extends React.Component {
} }
} }
class ToolbarLinkHighlighted extends React.Component { type ToolbarLinkHighlightedProps = {
static propTypes = { className?: string
className: PropTypes.string, children?: React.ReactNode
children: PropTypes.node, href?: string
href: PropTypes.string, onToggleModal?(...args: unknown[]): unknown
onToggleModal: PropTypes.func };
}
class ToolbarLinkHighlighted extends React.Component<ToolbarLinkHighlightedProps> {
render() { render() {
return <a return <a
className={classnames('maputnik-toolbar-link', "maputnik-toolbar-link--highlighted", this.props.className)} className={classnames('maputnik-toolbar-link', "maputnik-toolbar-link--highlighted", this.props.className)}
@@ -64,12 +64,12 @@ class ToolbarLinkHighlighted extends React.Component {
} }
} }
class ToolbarSelect extends React.Component { type ToolbarSelectProps = {
static propTypes = { children?: React.ReactNode
children: PropTypes.node, wdKey?: string
wdKey: PropTypes.string };
}
class ToolbarSelect extends React.Component<ToolbarSelectProps> {
render() { render() {
return <div return <div
className='maputnik-toolbar-select' className='maputnik-toolbar-select'
@@ -80,13 +80,13 @@ class ToolbarSelect extends React.Component {
} }
} }
class ToolbarAction extends React.Component { type ToolbarActionProps = {
static propTypes = { children?: React.ReactNode
children: PropTypes.node, onClick?(...args: unknown[]): unknown
onClick: PropTypes.func, wdKey?: string
wdKey: PropTypes.string };
}
class ToolbarAction extends React.Component<ToolbarActionProps> {
render() { render() {
return <button return <button
className='maputnik-toolbar-action' className='maputnik-toolbar-action'
@@ -98,22 +98,22 @@ class ToolbarAction extends React.Component {
} }
} }
export default class AppToolbar extends React.Component { type AppToolbarProps = {
static propTypes = { mapStyle: object
mapStyle: PropTypes.object.isRequired, inspectModeEnabled: boolean
inspectModeEnabled: PropTypes.bool.isRequired, onStyleChanged(...args: unknown[]): unknown
onStyleChanged: PropTypes.func.isRequired, // A new style has been uploaded
// A new style has been uploaded onStyleOpen(...args: unknown[]): unknown
onStyleOpen: PropTypes.func.isRequired, // A dict of source id's and the available source layers
// A dict of source id's and the available source layers sources: object
sources: PropTypes.object.isRequired, children?: React.ReactNode
children: PropTypes.node, onToggleModal(...args: unknown[]): unknown
onToggleModal: PropTypes.func, onSetMapState(...args: unknown[]): unknown
onSetMapState: PropTypes.func, mapState?: string
mapState: PropTypes.string, renderer?: string
renderer: PropTypes.string, };
}
export default class AppToolbar extends React.Component<AppToolbarProps> {
state = { state = {
isOpen: { isOpen: {
settings: false, settings: false,
@@ -124,16 +124,16 @@ export default class AppToolbar extends React.Component {
} }
} }
handleSelection(val) { handleSelection(val: string | undefined) {
this.props.onSetMapState(val); this.props.onSetMapState(val);
} }
onSkip = (target) => { onSkip = (target: string) => {
if (target === "map") { if (target === "map") {
document.querySelector(".maplibregl-canvas").focus(); (document.querySelector(".maplibregl-canvas") as HTMLCanvasElement).focus();
} }
else { else {
const el = document.querySelector("#skip-target-"+target); const el = document.querySelector("#skip-target-"+target) as HTMLButtonElement;
el.focus(); el.focus();
} }
} }
@@ -190,21 +190,21 @@ export default class AppToolbar extends React.Component {
<button <button
data-wd-key="root:skip:layer-list" data-wd-key="root:skip:layer-list"
className="maputnik-toolbar-skip" className="maputnik-toolbar-skip"
onClick={e => this.onSkip("layer-list")} onClick={_e => this.onSkip("layer-list")}
> >
Layers list Layers list
</button> </button>
<button <button
data-wd-key="root:skip:layer-editor" data-wd-key="root:skip:layer-editor"
className="maputnik-toolbar-skip" className="maputnik-toolbar-skip"
onClick={e => this.onSkip("layer-editor")} onClick={_e => this.onSkip("layer-editor")}
> >
Layer editor Layer editor
</button> </button>
<button <button
data-wd-key="root:skip:map-view" data-wd-key="root:skip:map-view"
className="maputnik-toolbar-skip" className="maputnik-toolbar-skip"
onClick={e => this.onSkip("map")} onClick={_e => this.onSkip("map")}
> >
Map view Map view
</button> </button>
@@ -246,7 +246,7 @@ export default class AppToolbar extends React.Component {
className="maputnik-select" className="maputnik-select"
data-wd-key="maputnik-select" data-wd-key="maputnik-select"
onChange={(e) => this.handleSelection(e.target.value)} onChange={(e) => this.handleSelection(e.target.value)}
value={currentView.id} value={currentView?.id}
> >
{views.filter(v => v.group === "general").map((item) => { {views.filter(v => v.group === "general").map((item) => {
return ( return (
@@ -1,18 +1,16 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types'
import IconLayer from './IconLayer' import IconLayer from './IconLayer'
import {latest} from '@maplibre/maplibre-gl-style-spec'
function groupFeaturesBySourceLayer(features) { function groupFeaturesBySourceLayer(features: any[]) {
const sources = {} const sources = {} as any
let returnedFeatures = {}; let returnedFeatures = {} as any;
features.forEach(feature => { features.forEach(feature => {
if(returnedFeatures.hasOwnProperty(feature.layer.id)) { if(returnedFeatures.hasOwnProperty(feature.layer.id)) {
returnedFeatures[feature.layer.id]++ returnedFeatures[feature.layer.id]++
const featureObject = sources[feature.layer['source-layer']].find(f => f.layer.id === feature.layer.id) const featureObject = sources[feature.layer['source-layer']].find((f: any) => f.layer.id === feature.layer.id)
featureObject.counter = returnedFeatures[feature.layer.id] featureObject.counter = returnedFeatures[feature.layer.id]
} else { } else {
@@ -26,14 +24,14 @@ function groupFeaturesBySourceLayer(features) {
return sources return sources
} }
class FeatureLayerPopup extends React.Component { type FeatureLayerPopupProps = {
static propTypes = { onLayerSelect(...args: unknown[]): unknown
onLayerSelect: PropTypes.func.isRequired, features: any[]
features: PropTypes.array, zoom?: number
zoom: PropTypes.number, };
}
_getFeatureColor(feature, zoom) { class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
_getFeatureColor(feature: any, _zoom?: number) {
// Guard because openlayers won't have this // Guard because openlayers won't have this
if (!feature.layer.paint) { if (!feature.layer.paint) {
return; return;
@@ -57,7 +55,6 @@ class FeatureLayerPopup extends React.Component {
} }
if(propName) { if(propName) {
const propertySpec = latest["paint_"+feature.layer.type][propName];
let color = feature.layer.paint[propName]; let color = feature.layer.paint[propName];
return String(color); return String(color);
} }
@@ -78,7 +75,7 @@ class FeatureLayerPopup extends React.Component {
const sources = groupFeaturesBySourceLayer(this.props.features) const sources = groupFeaturesBySourceLayer(this.props.features)
const items = Object.keys(sources).map(vectorLayerId => { const items = Object.keys(sources).map(vectorLayerId => {
const layers = sources[vectorLayerId].map((feature, idx) => { const layers = sources[vectorLayerId].map((feature: any, idx: number) => {
const featureColor = this._getFeatureColor(feature, this.props.zoom); const featureColor = this._getFeatureColor(feature, this.props.zoom);
return <div return <div
@@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import {throttle} from 'lodash'; import {throttle} from 'lodash';
import PropTypes from 'prop-types'
import MapMaplibreGlLayerPopup from './MapMaplibreGlLayerPopup'; import MapMaplibreGlLayerPopup from './MapMaplibreGlLayerPopup';
@@ -9,10 +8,10 @@ import {apply} from 'ol-mapbox-style';
import {Map, View, Overlay} from 'ol'; import {Map, View, Overlay} from 'ol';
import {toLonLat} from 'ol/proj'; import {toLonLat} from 'ol/proj';
import {toStringHDMS} from 'ol/coordinate'; import { StyleSpecification } from '@maplibre/maplibre-gl-style-spec';
function renderCoords (coords) { function renderCoords (coords: string[]) {
if (!coords || coords.length < 2) { if (!coords || coords.length < 2) {
return null; return null;
} }
@@ -23,36 +22,49 @@ function renderCoords (coords) {
} }
} }
export default class MapOpenLayers extends React.Component { type MapOpenLayersProps = {
static propTypes = { onDataChange?(...args: unknown[]): unknown
onDataChange: PropTypes.func, mapStyle: object
mapStyle: PropTypes.object.isRequired, accessToken?: string
accessToken: PropTypes.string, style?: object
style: PropTypes.object, onLayerSelect(...args: unknown[]): unknown
onLayerSelect: PropTypes.func.isRequired, debugToolbox: boolean
debugToolbox: PropTypes.bool.isRequired, replaceAccessTokens(...args: unknown[]): unknown
replaceAccessTokens: PropTypes.func.isRequired, onChange(...args: unknown[]): unknown
onChange: PropTypes.func.isRequired, };
}
type MapOpenLayersState = {
zoom: string
rotation: string
cursor: string[]
center: string[]
selectedFeatures?: any[]
};
export default class MapOpenLayers extends React.Component<MapOpenLayersProps, MapOpenLayersState> {
static defaultProps = { static defaultProps = {
onMapLoaded: () => {}, onMapLoaded: () => {},
onDataChange: () => {}, onDataChange: () => {},
onLayerSelect: () => {}, onLayerSelect: () => {},
} }
updateStyle: any;
map: any;
container: HTMLDivElement | null = null;
overlay: Overlay | undefined;
popupContainer: HTMLElement | null = null;
constructor(props) { constructor(props: MapOpenLayersProps) {
super(props); super(props);
this.state = { this.state = {
zoom: 0, zoom: "0",
rotation: 0, rotation: "0",
cursor: [], cursor: [] as string[],
center: [], center: [],
}; };
this.updateStyle = throttle(this._updateStyle.bind(this), 200); this.updateStyle = throttle(this._updateStyle.bind(this), 200);
} }
_updateStyle(newMapStyle) { _updateStyle(newMapStyle: StyleSpecification) {
if(!this.map) return; if(!this.map) return;
// See <https://github.com/openlayers/ol-mapbox-style/issues/215#issuecomment-493198815> // See <https://github.com/openlayers/ol-mapbox-style/issues/215#issuecomment-493198815>
@@ -60,7 +72,7 @@ export default class MapOpenLayers extends React.Component {
apply(this.map, newMapStyle); apply(this.map, newMapStyle);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps: MapOpenLayersProps) {
if (this.props.mapStyle !== prevProps.mapStyle) { if (this.props.mapStyle !== prevProps.mapStyle) {
this.updateStyle( this.updateStyle(
this.props.replaceAccessTokens(this.props.mapStyle) this.props.replaceAccessTokens(this.props.mapStyle)
@@ -70,7 +82,7 @@ export default class MapOpenLayers extends React.Component {
componentDidMount() { componentDidMount() {
this.overlay = new Overlay({ this.overlay = new Overlay({
element: this.popupContainer, element: this.popupContainer!,
autoPan: true, autoPan: true,
autoPanAnimation: { autoPanAnimation: {
duration: 250 duration: 250
@@ -78,7 +90,7 @@ export default class MapOpenLayers extends React.Component {
}); });
const map = new Map({ const map = new Map({
target: this.container, target: this.container!,
overlays: [this.overlay], overlays: [this.overlay],
view: new View({ view: new View({
zoom: 1, zoom: 1,
@@ -98,7 +110,7 @@ export default class MapOpenLayers extends React.Component {
const onMoveEnd = () => { const onMoveEnd = () => {
const zoom = map.getView().getZoom(); const zoom = map.getView().getZoom();
const center = toLonLat(map.getView().getCenter()); const center = toLonLat(map.getView().getCenter()!);
this.props.onChange({ this.props.onChange({
zoom, zoom,
@@ -112,15 +124,15 @@ export default class MapOpenLayers extends React.Component {
onMoveEnd(); onMoveEnd();
map.on('moveend', onMoveEnd); map.on('moveend', onMoveEnd);
map.on('postrender', (evt) => { map.on('postrender', (_e) => {
const center = toLonLat(map.getView().getCenter()); const center = toLonLat(map.getView().getCenter()!);
this.setState({ this.setState({
center: [ center: [
center[0].toFixed(2), center[0].toFixed(2),
center[1].toFixed(2), center[1].toFixed(2),
], ],
rotation: map.getView().getRotation().toFixed(2), rotation: map.getView().getRotation().toFixed(2),
zoom: map.getView().getZoom().toFixed(2) zoom: map.getView().getZoom()!.toFixed(2)
}); });
}); });
@@ -132,9 +144,9 @@ export default class MapOpenLayers extends React.Component {
); );
} }
closeOverlay = (e) => { closeOverlay = (e: any) => {
e.target.blur(); e.target.blur();
this.overlay.setPosition(undefined); this.overlay!.setPosition(undefined);
} }
render() { render() {
-3
View File
@@ -1,3 +0,0 @@
export function formatLayerId (id) {
return id === "" ? "[empty_string]" : `'${id}'`;
}
+3
View File
@@ -0,0 +1,3 @@
export function formatLayerId (id: string | undefined) {
return id === "" ? "[empty_string]" : `'${id}'`;
}