Refactor Field components with const arrow functions (#1261)

## Summary
- convert all remaining Field components to const arrow functions
- document the refactor in the CHANGELOG

## Testing
- `npm run lint`
- `npm run build`


------
https://chatgpt.com/codex/tasks/task_e_68684db1b6b88331837307a54e3f9dc1
This commit is contained in:
Bart Louwers
2025-07-05 14:47:03 +02:00
committed by GitHub
parent eb985f4d95
commit 2fef0467b6
24 changed files with 454 additions and 506 deletions

View File

@@ -111,296 +111,268 @@ type FieldFunctionProps = {
value?: any
};
type FieldFunctionState = {
dataType: string
isEditing: boolean
}
/** Supports displaying spec field for zoom function objects
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
*/
export default class FieldFunction extends React.Component<FieldFunctionProps, FieldFunctionState> {
constructor (props: FieldFunctionProps) {
super(props);
this.state = {
dataType: getDataType(props.value, props.fieldSpec),
isEditing: false,
}
}
const FieldFunction: React.FC<FieldFunctionProps> = (props) => {
const [dataType, setDataType] = React.useState(
getDataType(props.value, props.fieldSpec)
);
const [isEditing, setIsEditing] = React.useState(false);
static getDerivedStateFromProps(props: Readonly<FieldFunctionProps>, state: FieldFunctionState) {
// Because otherwise when editing values we end up accidentally changing field type.
if (state.isEditing) {
return {};
React.useEffect(() => {
if (!isEditing) {
setDataType(getDataType(props.value, props.fieldSpec));
}
else {
return {
isEditing: false,
dataType: getDataType(props.value, props.fieldSpec)
};
}
}
}, [props.value, props.fieldSpec, isEditing]);
getFieldFunctionType(fieldSpec: any) {
const getFieldFunctionType = (fieldSpec: any) => {
if (fieldSpec.expression.interpolated) {
return "exponential"
return 'exponential';
}
if (fieldSpec.type === "number") {
return "interval"
if (fieldSpec.type === 'number') {
return 'interval';
}
return "categorical"
}
return 'categorical';
};
addStop = () => {
const stops = this.props.value.stops.slice(0)
const lastStop = stops[stops.length - 1]
if (typeof lastStop[0] === "object") {
const addStop = () => {
const stops = props.value.stops.slice(0);
const lastStop = stops[stops.length - 1];
if (typeof lastStop[0] === 'object') {
stops.push([
{zoom: lastStop[0].zoom + 1, value: lastStop[0].value},
lastStop[1]
])
}
else {
stops.push([lastStop[0] + 1, lastStop[1]])
{ zoom: lastStop[0].zoom + 1, value: lastStop[0].value },
lastStop[1],
]);
} else {
stops.push([lastStop[0] + 1, lastStop[1]]);
}
const changedValue = {
...this.props.value,
...props.value,
stops: stops,
}
};
this.props.onChange(this.props.fieldName, changedValue)
}
props.onChange(props.fieldName, changedValue);
};
deleteExpression = () => {
const {fieldSpec, fieldName} = this.props;
this.props.onChange(fieldName, fieldSpec.default);
this.setState({
dataType: "value",
});
}
const deleteExpression = () => {
const { fieldSpec, fieldName } = props;
props.onChange(fieldName, fieldSpec.default);
setDataType('value');
};
deleteStop = (stopIdx: number) => {
const stops = this.props.value.stops.slice(0)
stops.splice(stopIdx, 1)
const deleteStop = (stopIdx: number) => {
const stops = props.value.stops.slice(0);
stops.splice(stopIdx, 1);
let changedValue = {
...this.props.value,
let changedValue: any = {
...props.value,
stops: stops,
};
if (stops.length === 1) {
changedValue = stops[0][1];
}
if(stops.length === 1) {
changedValue = stops[0][1]
}
props.onChange(props.fieldName, changedValue);
};
this.props.onChange(this.props.fieldName, changedValue)
}
const makeZoomFunction = () => {
const { value } = props;
makeZoomFunction = () => {
const {value} = this.props;
let zoomFunc;
if (typeof(value) === "object") {
let zoomFunc: any;
if (typeof value === 'object') {
if (value.stops) {
zoomFunc = {
base: value.base,
stops: value.stops.map((stop: Stop) => {
return [stop[0].zoom, stop[1] || findDefaultFromSpec(this.props.fieldSpec)];
})
}
}
else {
return [stop[0].zoom, stop[1] || findDefaultFromSpec(props.fieldSpec)];
}),
};
} else {
zoomFunc = {
base: value.base,
stops: [
[6, findDefaultFromSpec(this.props.fieldSpec)],
[10, findDefaultFromSpec(this.props.fieldSpec)]
]
}
[6, findDefaultFromSpec(props.fieldSpec)],
[10, findDefaultFromSpec(props.fieldSpec)],
],
};
}
}
else {
} else {
zoomFunc = {
stops: [
[6, value || findDefaultFromSpec(this.props.fieldSpec)],
[10, value || findDefaultFromSpec(this.props.fieldSpec)]
]
}
[6, value || findDefaultFromSpec(props.fieldSpec)],
[10, value || findDefaultFromSpec(props.fieldSpec)],
],
};
}
this.props.onChange(this.props.fieldName, zoomFunc)
}
props.onChange(props.fieldName, zoomFunc);
};
undoExpression = () => {
const {value, fieldName} = this.props;
const undoExpression = () => {
const { value, fieldName } = props;
if (isGetExpression(value)) {
this.props.onChange(fieldName, {
"type": "identity",
"property": value[1]
});
this.setState({
dataType: "value",
props.onChange(fieldName, {
type: 'identity',
property: value[1],
});
setDataType('value');
} else if (isLiteralExpression(value)) {
props.onChange(fieldName, value[1]);
setDataType('value');
}
else if (isLiteralExpression(value)) {
this.props.onChange(fieldName, value[1]);
this.setState({
dataType: "value",
});
}
}
};
canUndo = () => {
const {value, fieldSpec} = this.props;
const canUndo = () => {
const { value, fieldSpec } = props;
return (
isGetExpression(value) ||
isLiteralExpression(value) ||
isPrimative(value) ||
(Array.isArray(value) && fieldSpec.type === "array")
(Array.isArray(value) && fieldSpec.type === 'array')
);
}
};
makeExpression = () => {
const {value, fieldSpec} = this.props;
const makeExpression = () => {
const { value, fieldSpec } = props;
let expression;
if (typeof(value) === "object" && 'stops' in value) {
if (typeof value === 'object' && 'stops' in value) {
expression = styleFunction.convertFunction(value, fieldSpec);
} else if (isIdentityProperty(value)) {
expression = ['get', value.property];
} else {
expression = ['literal', value || props.fieldSpec.default];
}
else if (isIdentityProperty(value)) {
expression = ["get", value.property];
}
else {
expression = ["literal", value || this.props.fieldSpec.default];
}
this.props.onChange(this.props.fieldName, expression);
}
props.onChange(props.fieldName, expression);
};
makeDataFunction = () => {
const functionType = this.getFieldFunctionType(this.props.fieldSpec);
const makeDataFunction = () => {
const functionType = getFieldFunctionType(props.fieldSpec);
const stopValue = functionType === 'categorical' ? '' : 0;
const {value} = this.props;
const { value } = props;
let dataFunc;
if (typeof(value) === "object") {
if (typeof value === 'object') {
if (value.stops) {
dataFunc = {
property: "",
property: '',
type: functionType,
base: value.base,
stops: value.stops.map((stop: Stop) => {
return [{zoom: stop[0], value: stopValue}, stop[1] || findDefaultFromSpec(this.props.fieldSpec)];
})
}
}
else {
return [{ zoom: stop[0], value: stopValue }, stop[1] || findDefaultFromSpec(props.fieldSpec)];
}),
};
} else {
dataFunc = {
property: "",
property: '',
type: functionType,
base: value.base,
stops: [
[{zoom: 6, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)],
[{zoom: 10, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)]
]
}
[{ zoom: 6, value: stopValue }, findDefaultFromSpec(props.fieldSpec)],
[{ zoom: 10, value: stopValue }, findDefaultFromSpec(props.fieldSpec)],
],
};
}
}
else {
} else {
dataFunc = {
property: "",
property: '',
type: functionType,
base: value.base,
stops: [
[{zoom: 6, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)],
[{zoom: 10, value: stopValue}, this.props.value || findDefaultFromSpec(this.props.fieldSpec)]
]
}
[{ zoom: 6, value: stopValue }, props.value || findDefaultFromSpec(props.fieldSpec)],
[{ zoom: 10, value: stopValue }, props.value || findDefaultFromSpec(props.fieldSpec)],
],
};
}
this.props.onChange(this.props.fieldName, dataFunc)
props.onChange(props.fieldName, dataFunc);
};
const onMarkEditing = () => {
setIsEditing(true);
};
const onUnmarkEditing = () => {
setIsEditing(false);
};
const propClass =
props.fieldSpec.default === props.value ? 'maputnik-default-property' : 'maputnik-modified-property';
let specField;
if (dataType === 'expression') {
specField = (
<ExpressionProperty
errors={props.errors}
onChange={props.onChange.bind(null, props.fieldName)}
canUndo={canUndo}
onUndo={undoExpression}
onDelete={deleteExpression}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onFocus={onMarkEditing}
onBlur={onUnmarkEditing}
/>
);
} else if (dataType === 'zoom_function') {
specField = (
<ZoomProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onDeleteStop={deleteStop}
onAddStop={addStop}
onChangeToDataFunction={makeDataFunction}
onExpressionClick={makeExpression}
/>
);
} else if (dataType === 'data_function') {
specField = (
<DataProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onDeleteStop={deleteStop}
onAddStop={addStop}
onChangeToZoomFunction={makeZoomFunction}
onExpressionClick={makeExpression}
/>
);
} else {
specField = (
<SpecProperty
errors={props.errors}
onChange={props.onChange.bind(null)}
fieldType={props.fieldType}
fieldName={props.fieldName}
fieldSpec={props.fieldSpec}
value={props.value}
onZoomClick={makeZoomFunction}
onDataClick={makeDataFunction}
onExpressionClick={makeExpression}
/>
);
}
onMarkEditing = () => {
this.setState({isEditing: true});
}
onUnmarkEditing = () => {
this.setState({isEditing: false});
}
render() {
const {dataType} = this.state;
const propClass = this.props.fieldSpec.default === this.props.value ? "maputnik-default-property" : "maputnik-modified-property"
let specField;
if (dataType === "expression") {
specField = (
<ExpressionProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this, this.props.fieldName)}
canUndo={this.canUndo}
onUndo={this.undoExpression}
onDelete={this.deleteExpression}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onFocus={this.onMarkEditing}
onBlur={this.onUnmarkEditing}
/>
);
}
else if (dataType === "zoom_function") {
specField = (
<ZoomProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onDeleteStop={this.deleteStop}
onAddStop={this.addStop}
onChangeToDataFunction={this.makeDataFunction}
onExpressionClick={this.makeExpression}
/>
)
}
else if (dataType === "data_function") {
// TODO: Rename to FieldFunction **this file** shouldn't be called that
specField = (
<DataProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onDeleteStop={this.deleteStop}
onAddStop={this.addStop}
onChangeToZoomFunction={this.makeZoomFunction}
onExpressionClick={this.makeExpression}
/>
)
}
else {
specField = (
<SpecProperty
errors={this.props.errors}
onChange={this.props.onChange.bind(this)}
fieldType={this.props.fieldType}
fieldName={this.props.fieldName}
fieldSpec={this.props.fieldSpec}
value={this.props.value}
onZoomClick={this.makeZoomFunction}
onDataClick={this.makeDataFunction}
onExpressionClick={this.makeExpression}
/>
)
}
return <div className={propClass} data-wd-key={"spec-field-container:"+this.props.fieldName}>
return (
<div className={propClass} data-wd-key={'spec-field-container:' + props.fieldName}>
{specField}
</div>
}
}
);
};
export default FieldFunction;