Update dependencies, fix tranlations, remove deprecated tools. (#1683)

It migrates to next gen translation extraction tool and updates other
libraries with their relevant changes.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Harel M
2026-03-03 14:14:39 +02:00
committed by GitHub
parent f5baa89276
commit cb9b7beb32
15 changed files with 3141 additions and 3496 deletions

View File

@@ -1,7 +1,7 @@
import React from "react";
import {formatLayerId} from "../libs/format";
import {type LayerSpecification, type StyleSpecification} from "maplibre-gl";
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
import { formatLayerId } from "../libs/format";
import { type LayerSpecification, type StyleSpecification } from "maplibre-gl";
import { type WithTranslation, withTranslation } from "react-i18next";
import { type MappedError } from "../libs/definitions";
type AppMessagePanelInternalProps = {
@@ -15,21 +15,19 @@ type AppMessagePanelInternalProps = {
class AppMessagePanelInternal extends React.Component<AppMessagePanelInternalProps> {
static defaultProps = {
onLayerSelect: () => {},
onLayerSelect: () => { },
};
render() {
const {t, selectedLayerIndex} = this.props;
const { t, selectedLayerIndex } = this.props;
const errors = this.props.errors?.map((error, idx) => {
let content;
if (error.parsed && error.parsed.type === "layer") {
const {parsed} = error;
const { parsed } = error;
const layerId = this.props.mapStyle?.layers[parsed.data.index].id;
content = (
<>
<Trans t={t}>
Layer <span>{formatLayerId(layerId)}</span>: {parsed.data.message}
</Trans>
{t("Layer")} <span>{formatLayerId(layerId)}</span>: {parsed.data.message}
{selectedLayerIndex !== parsed.data.index &&
<>
&nbsp;&mdash;&nbsp;
@@ -47,13 +45,13 @@ class AppMessagePanelInternal extends React.Component<AppMessagePanelInternalPro
else {
content = error.message;
}
return <p key={"error-"+idx} className="maputnik-message-panel-error">
return <p key={"error-" + idx} className="maputnik-message-panel-error">
{content}
</p>;
});
const infos = this.props.infos?.map((m, i) => {
return <p key={"info-"+i}>{m}</p>;
return <p key={"info-" + i}>{m}</p>;
});
return <div className="maputnik-message-panel">

View File

@@ -1,10 +1,10 @@
import React, {type JSX} from "react";
import React, { type JSX } from "react";
import { Wrapper, Button, Menu, MenuItem } from "react-aria-menubutton";
import {Accordion} from "react-accessible-accordion";
import {MdMoreVert} from "react-icons/md";
import { Accordion } from "react-accessible-accordion";
import { MdMoreVert } from "react-icons/md";
import { IconContext } from "react-icons";
import {type BackgroundLayerSpecification, type LayerSpecification, type SourceSpecification} from "maplibre-gl";
import {v8} from "@maplibre/maplibre-gl-style-spec";
import { type BackgroundLayerSpecification, type LayerSpecification, type SourceSpecification } from "maplibre-gl";
import { v8 } from "@maplibre/maplibre-gl-style-spec";
import FieldJson from "./FieldJson";
import FilterEditor from "./FilterEditor";
@@ -18,7 +18,7 @@ import FieldComment from "./FieldComment";
import FieldSource from "./FieldSource";
import FieldSourceLayer from "./FieldSourceLayer";
import { changeType, changeProperty } from "../libs/layer";
import {formatLayerId} from "../libs/format";
import { formatLayerId } from "../libs/format";
import { type WithTranslation, withTranslation } from "react-i18next";
import { type TFunction } from "i18next";
import { NON_SOURCE_LAYERS } from "../libs/non-source-layers";
@@ -93,7 +93,7 @@ function getLayoutForType(type: LayerSpecification["type"], t: TFunction): Maput
return groups;
}
function layoutGroups(layerType: LayerSpecification["type"], t: TFunction): {id: string, title: string, type: string, fields?: string[]}[] {
function layoutGroups(layerType: LayerSpecification["type"], t: TFunction): { id: string, title: string, type: string, fields?: string[] }[] {
const layerGroup = {
id: "layer",
title: t("Layer"),
@@ -116,8 +116,8 @@ function layoutGroups(layerType: LayerSpecification["type"], t: TFunction): {id:
type LayerEditorInternalProps = {
layer: LayerSpecification
sources: {[key: string]: SourceSpecification & {layers: string[]}}
vectorLayers: {[key: string]: any}
sources: { [key: string]: SourceSpecification & { layers: string[] } }
vectorLayers: { [key: string]: any }
spec: any
onLayerChanged(index: number, layer: LayerSpecification): void
onLayerIdChange(...args: unknown[]): unknown
@@ -132,21 +132,21 @@ type LayerEditorInternalProps = {
} & WithTranslation;
type LayerEditorState = {
editorGroups: {[keys:string]: boolean}
editorGroups: { [keys: string]: boolean }
};
/** Layer editor supporting multiple types of layers. */
class LayerEditorInternal extends React.Component<LayerEditorInternalProps, LayerEditorState> {
static defaultProps = {
onLayerChanged: () => {},
onLayerIdChange: () => {},
onLayerDestroyed: () => {},
onLayerChanged: () => { },
onLayerIdChange: () => { },
onLayerDestroyed: () => { },
};
constructor(props: LayerEditorInternalProps) {
super(props);
const editorGroups: {[keys:string]: boolean} = {};
const editorGroups: { [keys: string]: boolean } = {};
for (const group of layoutGroups(this.props.layer.type, props.t)) {
editorGroups[group.title] = true;
}
@@ -158,7 +158,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
const additionalGroups = { ...state.editorGroups };
for (const group of getLayoutForType(props.layer.type, props.t)) {
if(!(group.title in additionalGroups)) {
if (!(group.title in additionalGroups)) {
additionalGroups[group.title] = true;
}
}
@@ -188,10 +188,10 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
renderGroupType(type: string, fields?: string[]): JSX.Element {
let comment = "";
if(this.props.layer.metadata) {
if (this.props.layer.metadata) {
comment = (this.props.layer.metadata as any)["maputnik:comment"];
}
const {errors, layerIndex} = this.props;
const { errors, layerIndex } = this.props;
const errorData: MappedLayerErrors = {};
errors!.forEach(error => {
@@ -208,11 +208,11 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
let sourceLayerIds;
const layer = this.props.layer as Exclude<LayerSpecification, BackgroundLayerSpecification>;
if(Object.prototype.hasOwnProperty.call(this.props.sources, layer.source)) {
if (Object.prototype.hasOwnProperty.call(this.props.sources, layer.source)) {
sourceLayerIds = this.props.sources[layer.source].layers;
}
switch(type) {
switch (type) {
case "layer": return <div>
<FieldId
value={this.props.layer.id}
@@ -237,12 +237,12 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
/>
}
{!NON_SOURCE_LAYERS.includes(this.props.layer.type) &&
<FieldSourceLayer
error={errorData["source-layer"]}
sourceLayerIds={sourceLayerIds}
value={(this.props.layer as any)["source-layer"]}
onChange={v => this.changeProperty(null, "source-layer", v)}
/>
<FieldSourceLayer
error={errorData["source-layer"]}
sourceLayerIds={sourceLayerIds}
value={(this.props.layer as any)["source-layer"]}
onChange={v => this.changeProperty(null, "source-layer", v)}
/>
}
<FieldMinZoom
error={errorData.minzoom}
@@ -257,7 +257,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
<FieldComment
error={errorData.comment}
value={comment}
onChange={v => this.changeProperty("metadata", "maputnik:comment", v == "" ? undefined : v)}
onChange={v => this.changeProperty("metadata", "maputnik:comment", v == "" ? undefined : v)}
/>
</div>;
case "filter": return <div>
@@ -296,7 +296,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
moveLayer(offset: number) {
this.props.onMoveLayer({
oldIndex: this.props.layerIndex,
newIndex: this.props.layerIndex+offset
newIndex: this.props.layerIndex + offset
});
}
@@ -324,12 +324,14 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
const layout = this.props.layer.layout || {};
const items: {[key: string]: {
text: string,
handler: () => void,
disabled?: boolean,
wdKey?: string
}} = {
const items: {
[key: string]: {
text: string,
handler: () => void,
disabled?: boolean,
wdKey?: string
}
} = {
delete: {
text: t("Delete"),
handler: () => this.props.onLayerDestroy(this.props.layerIndex),
@@ -364,7 +366,7 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
items[id].handler();
}
return <IconContext.Provider value={{size: "14px", color: "#8e8e8e"}}>
return <IconContext.Provider value={{ size: "14px", color: "#8e8e8e" }}>
<section className="maputnik-layer-editor"
role="main"
aria-label={t("Layer editor")}
@@ -373,12 +375,12 @@ class LayerEditorInternal extends React.Component<LayerEditorInternalProps, Laye
<header data-wd-key="layer-editor.header">
<div className="layer-header">
<h2 className="layer-header__title">
{t("Layer: {{layerId}}", { layerId: formatLayerId(this.props.layer.id) })}
{t("Layer")}: {formatLayerId(this.props.layer.id)}
</h2>
<div className="layer-header__info">
<Wrapper
className='more-menu'
onSelection={handleSelection}
onSelection={(id, event) => handleSelection(id as string, event)}
closeOnSelection={false}
>
<Button

View File

@@ -1,11 +1,12 @@
import React from "react";
import classnames from "classnames";
import {MdContentCopy, MdVisibility, MdVisibilityOff, MdDelete} from "react-icons/md";
import { MdContentCopy, MdVisibility, MdVisibilityOff, MdDelete } from "react-icons/md";
import { IconContext } from "react-icons";
import {useSortable} from "@dnd-kit/sortable";
import {CSS} from "@dnd-kit/utilities";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import IconLayer from "./IconLayer";
import type { VisibilitySpecification } from "maplibre-gl";
type DraggableLabelProps = {
@@ -16,7 +17,7 @@ type DraggableLabelProps = {
};
const DraggableLabel: React.FC<DraggableLabelProps> = (props) => {
const {dragAttributes, dragListeners} = props;
const { dragAttributes, dragListeners } = props;
return <div className="maputnik-layer-list-item-handle" {...dragAttributes} {...dragListeners}>
<IconLayer
className="layer-handle__icon"
@@ -39,7 +40,7 @@ type IconActionProps = {
class IconAction extends React.Component<IconActionProps> {
renderIcon() {
switch(this.props.action) {
switch (this.props.action) {
case "duplicate": return <MdContentCopy />;
case "show": return <MdVisibility />;
case "hide": return <MdVisibilityOff />;
@@ -48,7 +49,7 @@ class IconAction extends React.Component<IconActionProps> {
}
render() {
const {classBlockName, classBlockModifier} = this.props;
const { classBlockName, classBlockModifier } = this.props;
let classAdditions = "";
if (classBlockName) {
@@ -78,7 +79,7 @@ type LayerListItemProps = {
layerId: string
layerType: string
isSelected?: boolean
visibility?: string
visibility?: VisibilitySpecification
className?: string
onLayerSelect(index: number): void;
onLayerCopy?(...args: unknown[]): unknown
@@ -90,9 +91,9 @@ const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props
const {
isSelected = false,
visibility = "visible",
onLayerCopy = () => {},
onLayerDestroy = () => {},
onLayerVisibilityToggle = () => {},
onLayerCopy = () => { },
onLayerDestroy = () => { },
onLayerVisibilityToggle = () => { },
} = props;
const {
@@ -102,7 +103,7 @@ const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props
transform,
transition,
isDragging,
} = useSortable({id: props.layerId});
} = useSortable({ id: props.layerId });
const style = {
transform: CSS.Transform.toString(transform),
@@ -115,7 +116,7 @@ const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props
// Cast ref to MutableRefObject since we know from the codebase that's what's always passed
const refObject = ref as React.MutableRefObject<HTMLLIElement | null> | null;
return <IconContext.Provider value={{size: "14px"}}>
return <IconContext.Provider value={{ size: "14px" }}>
<li
ref={(node) => {
setNodeRef(node);
@@ -138,21 +139,21 @@ const LayerListItem = React.forwardRef<HTMLLIElement, LayerListItemProps>((props
dragAttributes={attributes}
dragListeners={listeners}
/>
<span style={{flexGrow: 1}} />
<span style={{ flexGrow: 1 }} />
<IconAction
wdKey={"layer-list-item:" + props.layerId+":delete"}
wdKey={"layer-list-item:" + props.layerId + ":delete"}
action={"delete"}
classBlockName="delete"
onClick={_e => onLayerDestroy!(props.layerIndex)}
/>
<IconAction
wdKey={"layer-list-item:" + props.layerId+":copy"}
wdKey={"layer-list-item:" + props.layerId + ":copy"}
action={"duplicate"}
classBlockName="duplicate"
onClick={_e => onLayerCopy!(props.layerIndex)}
/>
<IconAction
wdKey={"layer-list-item:"+props.layerId+":toggle-visibility"}
wdKey={"layer-list-item:" + props.layerId + ":toggle-visibility"}
action={visibilityAction}
classBlockName="visibility"
classBlockModifier={visibilityAction}

View File

@@ -1,6 +1,6 @@
import React, { type FormEvent } from "react";
import {MdFileUpload} from "react-icons/md";
import {MdAddCircleOutline} from "react-icons/md";
import { MdFileUpload } from "react-icons/md";
import { MdAddCircleOutline } from "react-icons/md";
import { Trans, type WithTranslation, withTranslation } from "react-i18next";
import ModalLoading from "./ModalLoading";
@@ -72,9 +72,9 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
onCancelActiveRequest(e: Event) {
// Else the click propagates to the underlying modal
if(e) e.stopPropagation();
if (e) e.stopPropagation();
if(this.state.activeRequest) {
if (this.state.activeRequest) {
this.state.activeRequest.abort();
this.setState({
activeRequest: null,
@@ -92,11 +92,11 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
mode: "cors",
credentials: "same-origin"
})
.then(function(response) {
.then(function (response) {
return response.json();
})
.then((body) => {
if(canceled) {
if (canceled) {
return;
}
@@ -122,7 +122,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
this.setState({
activeRequest: {
abort: function() {
abort: function () {
canceled = true;
}
},
@@ -183,7 +183,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
try {
mapStyle = JSON.parse(e.target?.result as string);
}
catch(err) {
catch (err) {
this.setState({
error: (err as Error).toString()
});
@@ -223,7 +223,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
});
let errorElement;
if(this.state.error) {
if (this.state.error) {
errorElement = (
<div className="maputnik-modal-error">
{this.state.error}
@@ -249,7 +249,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
<InputButton
data-wd-key="modal:open.file.button"
className="maputnik-big-button"
onClick={this.onOpenFile}><MdFileUpload/> {t("Open Style")}
onClick={this.onOpenFile}><MdFileUpload /> {t("Open Style")}
</InputButton>
) : (
<label>
@@ -304,7 +304,7 @@ class ModalOpenInternal extends React.Component<ModalOpenInternalProps, ModalOpe
isOpen={!!this.state.activeRequest}
title={t("Loading style")}
onCancel={(e: Event) => this.onCancelActiveRequest(e)}
message={t("Loading: {{requestUrl}}", { requestUrl: this.state.activeRequestUrl })}
message={t("Loading") + ": " + this.state.activeRequestUrl}
/>
</div>
);