mirror of
https://github.com/maputnik/editor.git
synced 2026-01-18 03:10:01 +00:00
## Launch Checklist This PR adds back the error panel which was under the map for some reason. It also highlights problematic layers in the layers list (which already worked). It also highlights the field that has an error related to it. It fixes the error types throughout the code. Before: <img width="1141" height="665" alt="image" src="https://github.com/user-attachments/assets/c0593d6c-8f14-41b3-8a51-bc359446656d" /> After: <img width="1141" height="665" alt="image" src="https://github.com/user-attachments/assets/1ffeebb7-31ea-4ed5-97f4-fc5f907a6aea" /> - [x] Briefly describe the changes in this PR. - [x] Include before/after visuals or gifs if this PR includes visual changes. - [x] Write tests for all new functionality. - [x] Add an entry to `CHANGELOG.md` under the `## main` section. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
155 lines
5.4 KiB
TypeScript
155 lines
5.4 KiB
TypeScript
import React, { type ReactElement } from "react";
|
|
|
|
import InputColor, { type InputColorProps } from "./InputColor";
|
|
import InputNumber, { type InputNumberProps } from "./InputNumber";
|
|
import InputCheckbox, { type InputCheckboxProps } from "./InputCheckbox";
|
|
import InputString, { type InputStringProps } from "./InputString";
|
|
import InputArray, { type InputArrayProps } from "./InputArray";
|
|
import InputDynamicArray, { type InputDynamicArrayProps } from "./InputDynamicArray";
|
|
import InputFont, { type InputFontProps } from "./InputFont";
|
|
import InputAutocomplete, { type InputAutocompleteProps } from "./InputAutocomplete";
|
|
import InputEnum, { type InputEnumProps } from "./InputEnum";
|
|
import capitalize from "lodash.capitalize";
|
|
|
|
const iconProperties = ["background-pattern", "fill-pattern", "line-pattern", "fill-extrusion-pattern", "icon-image"];
|
|
|
|
export type FieldSpecType = "number" | "enum" | "resolvedImage" | "formatted" | "string" | "color" | "boolean" | "array" | "numberArray" | "padding" | "colorArray" | "variableAnchorOffsetCollection";
|
|
|
|
export type InputSpecProps = {
|
|
onChange?(fieldName: string | undefined, value: number | undefined | (string | number | undefined)[]): unknown
|
|
fieldName?: string
|
|
fieldSpec?: {
|
|
default?: unknown
|
|
type?: FieldSpecType
|
|
minimum?: number
|
|
maximum?: number
|
|
values?: unknown[]
|
|
length?: number
|
|
value?: string
|
|
}
|
|
value?: string | number | unknown[] | boolean
|
|
/** Override the style of the field */
|
|
style?: object
|
|
"aria-label"?: string
|
|
label?: string
|
|
action?: ReactElement
|
|
};
|
|
|
|
/** Display any field from the Maplibre GL style spec and
|
|
* choose the correct field component based on the @{fieldSpec}
|
|
* to display @{value}. */
|
|
export default class InputSpec extends React.Component<InputSpecProps> {
|
|
|
|
childNodes() {
|
|
const commonProps = {
|
|
fieldSpec: this.props.fieldSpec,
|
|
label: this.props.label,
|
|
action: this.props.action,
|
|
style: this.props.style,
|
|
value: this.props.value,
|
|
default: this.props.fieldSpec?.default,
|
|
name: this.props.fieldName,
|
|
"data-wd-key": "spec-field-input:" + this.props.fieldName,
|
|
onChange: (newValue: number | undefined | (string | number | undefined)[]) => this.props.onChange!(this.props.fieldName, newValue),
|
|
"aria-label": this.props["aria-label"],
|
|
};
|
|
switch(this.props.fieldSpec?.type) {
|
|
case "number": return (
|
|
<InputNumber
|
|
{...commonProps as InputNumberProps}
|
|
min={this.props.fieldSpec.minimum}
|
|
max={this.props.fieldSpec.maximum}
|
|
/>
|
|
);
|
|
case "enum": {
|
|
const options = Object.keys(this.props.fieldSpec.values || []).map(v => [v, capitalize(v)]);
|
|
|
|
return <InputEnum
|
|
{...commonProps as Omit<InputEnumProps, "options">}
|
|
options={options}
|
|
/>;
|
|
}
|
|
case "resolvedImage":
|
|
case "formatted":
|
|
case "string":
|
|
if (iconProperties.indexOf(this.props.fieldName!) >= 0) {
|
|
const options = this.props.fieldSpec.values || [];
|
|
return <InputAutocomplete
|
|
{...commonProps as Omit<InputAutocompleteProps, "options">}
|
|
options={options.map(f => [f, f])}
|
|
/>;
|
|
} else {
|
|
return <InputString
|
|
{...commonProps as InputStringProps}
|
|
/>;
|
|
}
|
|
case "color": return (
|
|
<InputColor
|
|
{...commonProps as InputColorProps}
|
|
/>
|
|
);
|
|
case "boolean": return (
|
|
<InputCheckbox
|
|
{...commonProps as InputCheckboxProps}
|
|
/>
|
|
);
|
|
case "array":
|
|
if(this.props.fieldName === "text-font") {
|
|
return <InputFont
|
|
{...commonProps as InputFontProps}
|
|
fonts={this.props.fieldSpec.values}
|
|
/>;
|
|
} else {
|
|
if (this.props.fieldSpec.length) {
|
|
return <InputArray
|
|
{...commonProps as InputArrayProps}
|
|
type={this.props.fieldSpec.value}
|
|
length={this.props.fieldSpec.length}
|
|
/>;
|
|
} else {
|
|
return <InputDynamicArray
|
|
{...commonProps as InputDynamicArrayProps}
|
|
fieldSpec={this.props.fieldSpec}
|
|
type={this.props.fieldSpec.value as InputDynamicArrayProps["type"]}
|
|
/>;
|
|
}
|
|
}
|
|
case "numberArray": return (
|
|
<InputDynamicArray
|
|
{...commonProps as InputDynamicArrayProps}
|
|
fieldSpec={this.props.fieldSpec}
|
|
type="number"
|
|
value={(Array.isArray(this.props.value) ? this.props.value : [this.props.value]) as (string | number | undefined)[]}
|
|
/>
|
|
);
|
|
case "colorArray": return (
|
|
<InputDynamicArray
|
|
{...commonProps as InputDynamicArrayProps}
|
|
fieldSpec={this.props.fieldSpec}
|
|
type="color"
|
|
value={(Array.isArray(this.props.value) ? this.props.value : [this.props.value]) as (string | number | undefined)[]}
|
|
/>
|
|
);
|
|
case "padding": return (
|
|
<InputArray
|
|
{...commonProps as InputArrayProps}
|
|
type="number"
|
|
value={(Array.isArray(this.props.value) ? this.props.value : [this.props.value]) as (string | number | undefined)[]}
|
|
length={4}
|
|
/>
|
|
);
|
|
default:
|
|
console.warn(`No proper field input for ${this.props.fieldName} type: ${this.props.fieldSpec?.type}`);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<div data-wd-key={"spec-field:"+this.props.fieldName}>
|
|
{this.childNodes()}
|
|
</div>
|
|
);
|
|
}
|
|
}
|