Replace default export with named exports (#1998)

## Launch Checklist

See title,
Also removed some "_" from some file names.
This is a pure refactoring, no logic changes.


 - [x] Briefly describe the changes in this PR.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Harel M
2026-07-12 14:07:28 +03:00
committed by GitHub
parent 21e141542a
commit 9c1499b805
94 changed files with 319 additions and 402 deletions
+383
View File
@@ -0,0 +1,383 @@
import React from "react";
import {PiListPlusBold} from "react-icons/pi";
import {TbMathFunction} from "react-icons/tb";
import latest from "@maplibre/maplibre-gl-style-spec/dist/latest.json";
import { InputButton } from "./InputButton";
import { InputSpec } from "./InputSpec";
import { InputNumber } from "./InputNumber";
import { InputString } from "./InputString";
import { InputSelect } from "./InputSelect";
import { Block } from "./Block";
import { generateUniqueId as docUid } from "../libs/document-uid";
import { sortNumerically } from "../libs/sort-numerically";
import {findDefaultFromSpec} from "../libs/spec-helper";
import { type WithTranslation, withTranslation } from "react-i18next";
import { labelFromFieldName } from "../libs/label-from-field-name";
import { DeleteStopButton } from "./DeleteStopButton";
import { type MappedLayerErrors } from "../libs/definitions";
function setStopRefs(props: DataPropertyInternalProps, state: DataPropertyState) {
// This is initialised below only if required to improved performance.
let newRefs: {[key: number]: string} | undefined;
if(props.value && props.value.stops) {
props.value.stops.forEach((_val, idx) => {
if(!Object.prototype.hasOwnProperty.call(state.refs, idx)) {
if(!newRefs) {
newRefs = {...state};
}
newRefs[idx] = docUid("stop-");
}
});
}
return newRefs;
}
type DataPropertyInternalProps = {
onChange?(fieldName: string, value: any): unknown
onDeleteStop?(...args: unknown[]): unknown
onAddStop?(...args: unknown[]): unknown
onExpressionClick?(...args: unknown[]): unknown
onChangeToZoomFunction?(...args: unknown[]): unknown
fieldName: string
fieldType?: string
fieldSpec?: object
value?: DataPropertyValue
errors?: MappedLayerErrors
} & WithTranslation;
type DataPropertyState = {
refs: {[key: number]: string}
};
type DataPropertyValue = {
default?: any
property?: string
base?: number
type?: string
stops: Stop[]
};
export type Stop = [{
zoom: number
value: number
}, number];
class DataPropertyInternal extends React.Component<DataPropertyInternalProps, DataPropertyState> {
state = {
refs: {} as {[key: number]: string}
};
componentDidMount() {
const newRefs = setStopRefs(this.props, this.state);
if(newRefs) {
this.setState({
refs: newRefs
});
}
}
static getDerivedStateFromProps(props: Readonly<DataPropertyInternalProps>, state: DataPropertyState) {
const newRefs = setStopRefs(props, state);
if(newRefs) {
return {
refs: newRefs
};
}
return null;
}
getFieldFunctionType(fieldSpec: any) {
if (fieldSpec.expression.interpolated) {
return "exponential";
}
if (fieldSpec.type === "number") {
return "interval";
}
return "categorical";
}
getDataFunctionTypes(fieldSpec: any) {
if (fieldSpec.expression.interpolated) {
return ["interpolate", "categorical", "interval", "exponential", "identity"];
}
else {
return ["categorical", "interval", "identity"];
}
}
// Order the stops altering the refs to reflect their new position.
orderStopsByZoom(stops: Stop[]) {
const mappedWithRef = stops
.map((stop, idx) => {
return {
ref: this.state.refs[idx],
data: stop
};
})
// Sort by zoom
.sort((a, b) => sortNumerically(a.data[0].zoom, b.data[0].zoom));
// Fetch the new position of the stops
const newRefs = {} as {[key: number]: string};
mappedWithRef
.forEach((stop, idx) =>{
newRefs[idx] = stop.ref;
});
this.setState({
refs: newRefs
});
return mappedWithRef.map((item) => item.data);
}
onChange = (fieldName: string, value: any) => {
if (value.type === "identity") {
value = {
type: value.type,
property: value.property,
};
}
else {
const stopValue = value.type === "categorical" ? "" : 0;
value = {
property: "",
type: value.type,
// Default props if they don't already exist.
stops: [
[{zoom: 6, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec as any)],
[{zoom: 10, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec as any)]
],
...value,
};
}
this.props.onChange!(fieldName, value);
};
changeStop(changeIdx: number, stopData: { zoom: number | undefined, value: number }, value: number) {
const stops = this.props.value?.stops.slice(0) || [];
// const changedStop = stopData.zoom === undefined ? stopData.value : stopData
stops[changeIdx] = [
{
value: stopData.value,
zoom: (stopData.zoom === undefined) ? 0 : stopData.zoom,
},
value
];
const orderedStops = this.orderStopsByZoom(stops);
const changedValue = {
...this.props.value,
stops: orderedStops,
};
this.onChange(this.props.fieldName, changedValue);
}
changeBase(newValue: number | undefined) {
const changedValue = {
...this.props.value,
base: newValue
};
if (changedValue.base === undefined) {
delete changedValue["base"];
}
this.props.onChange!(this.props.fieldName, changedValue);
}
changeDataType(propVal: string) {
if (propVal === "interpolate" && this.props.onChangeToZoomFunction) {
this.props.onChangeToZoomFunction();
}
else {
this.onChange(this.props.fieldName, {
...this.props.value,
type: propVal,
});
}
}
changeDataProperty(propName: "property" | "default", propVal: any) {
if (propVal) {
this.props.value![propName] = propVal;
}
else {
delete this.props.value![propName];
}
this.onChange(this.props.fieldName, this.props.value);
}
render() {
const t = this.props.t;
if (typeof this.props.value?.type === "undefined") {
this.props.value!.type = this.getFieldFunctionType(this.props.fieldSpec);
}
let dataFields;
if (this.props.value?.stops) {
dataFields = this.props.value.stops.map((stop, idx) => {
const zoomLevel = typeof stop[0] === "object" ? stop[0].zoom : undefined;
const key = this.state.refs[idx];
const dataLevel = typeof stop[0] === "object" ? stop[0].value : stop[0];
const value = stop[1];
const deleteStopBtn = <DeleteStopButton onClick={this.props.onDeleteStop?.bind(this, idx)} />;
const dataProps = {
"aria-label": t("Input value"),
label: t("Data value"),
value: dataLevel as any,
onChange: (newData: string | number | undefined) => this.changeStop(idx, { zoom: zoomLevel, value: newData as number }, value)
};
let dataInput;
if(this.props.value?.type === "categorical") {
dataInput = <InputString {...dataProps} />;
}
else {
dataInput = <InputNumber {...dataProps} />;
}
let zoomInput = null;
if(zoomLevel !== undefined) {
zoomInput = <div>
<InputNumber
aria-label="Zoom"
value={zoomLevel}
onChange={newZoom => this.changeStop(idx, {zoom: newZoom, value: dataLevel}, value)}
min={0}
max={22}
/>
</div>;
}
return <tr key={key}>
<td>
{zoomInput}
</td>
<td>
{dataInput}
</td>
<td>
<InputSpec
aria-label={t("Output value")}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={value}
onChange={(_, newValue) => this.changeStop(idx, {zoom: zoomLevel, value: dataLevel}, newValue as number)}
/>
</td>
<td>
{deleteStopBtn}
</td>
</tr>;
});
}
return <div className="maputnik-data-spec-block">
<fieldset className="maputnik-data-spec-property">
<legend>{labelFromFieldName(this.props.fieldName)}</legend>
<div className="maputnik-data-fieldset-inner">
<Block
label={t("Function")}
key="function"
>
<div className="maputnik-data-spec-property-input">
<InputSelect
value={this.props.value!.type}
onChange={(propVal: string) => this.changeDataType(propVal)}
title={t("Select a type of data scale (default is 'categorical').")}
options={this.getDataFunctionTypes(this.props.fieldSpec)}
/>
</div>
</Block>
{this.props.value?.type !== "identity" &&
<Block
label={t("Base")}
key="base"
>
<div className="maputnik-data-spec-property-input">
<InputSpec
fieldName={"base"}
fieldSpec={latest.function.base as typeof latest.function.base & { type: "number" }}
value={this.props.value?.base}
onChange={(_, newValue) => this.changeBase(newValue as number)}
/>
</div>
</Block>
}
<Block
label={"Property"}
key="property"
>
<div className="maputnik-data-spec-property-input">
<InputString
value={this.props.value?.property}
title={t("Input a data property to base styles off of.")}
onChange={propVal => this.changeDataProperty("property", propVal)}
/>
</div>
</Block>
{dataFields &&
<Block
label={t("Default")}
key="default"
>
<InputSpec
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value?.default}
onChange={(_, propVal) => this.changeDataProperty("default", propVal)}
/>
</Block>
}
{dataFields &&
<div className="maputnik-function-stop">
<table className="maputnik-function-stop-table">
<caption>{t("Stops")}</caption>
<thead>
<tr>
<th>{t("Zoom")}</th>
<th>{t("Input value")}</th>
<th rowSpan={2}>{t("Output value")}</th>
</tr>
</thead>
<tbody>
{dataFields}
</tbody>
</table>
</div>
}
<div className="maputnik-toolbox">
{dataFields &&
<InputButton
className="maputnik-add-stop"
onClick={this.props.onAddStop?.bind(this)}
>
<PiListPlusBold style={{ verticalAlign: "text-bottom" }} />
{t("Add stop")}
</InputButton>
}
<InputButton
className="maputnik-add-stop"
onClick={this.props.onExpressionClick?.bind(this)}
>
<TbMathFunction style={{ verticalAlign: "text-bottom" }} />
{t("Convert to expression")}
</InputButton>
</div>
</div>
</fieldset>
</div>;
}
}
export const DataProperty = withTranslation()(DataPropertyInternal);