mirror of
https://github.com/maputnik/editor.git
synced 2026-01-08 06:20:00 +00:00
## Launch Checklist This adds support for `relief-color` property so that it will create an elevation expression when the button is pressed. It also adds support for `colorArray` and `numberArray` types so that the user would be able to add the relevant information. Before: <img width="403" height="324" alt="image" src="https://github.com/user-attachments/assets/250abd81-6176-4711-a1ee-d33d443932d7" /> <img width="403" height="324" alt="image" src="https://github.com/user-attachments/assets/6a1bb268-66db-42a1-97fc-33e5a40863b6" /> After: <img width="403" height="324" alt="image" src="https://github.com/user-attachments/assets/8ebaa1ea-4ef9-4aed-abcd-3c8b0057ea76" /> <img width="403" height="324" alt="image" src="https://github.com/user-attachments/assets/e0728c92-85f9-4b86-8635-8877cf257b2f" /> - [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>
165 lines
4.6 KiB
TypeScript
165 lines
4.6 KiB
TypeScript
import React from 'react'
|
|
import capitalize from 'lodash.capitalize'
|
|
import {MdDelete} from 'react-icons/md'
|
|
import { WithTranslation, withTranslation } from 'react-i18next';
|
|
|
|
import InputString from './InputString'
|
|
import InputNumber from './InputNumber'
|
|
import InputButton from './InputButton'
|
|
import FieldDocLabel from './FieldDocLabel'
|
|
import InputEnum from './InputEnum'
|
|
import InputUrl from './InputUrl'
|
|
import InputColor from './InputColor';
|
|
|
|
|
|
export type InputDynamicArrayProps = {
|
|
value?: (string | number | undefined)[]
|
|
type?: 'url' | 'number' | 'enum' | 'string' | 'color'
|
|
default?: (string | number | undefined)[]
|
|
onChange?(values: (string | number | undefined)[] | undefined): unknown
|
|
style?: object
|
|
fieldSpec?: {
|
|
values?: any
|
|
}
|
|
'aria-label'?: string
|
|
label: string
|
|
}
|
|
|
|
type InputDynamicArrayInternalProps = InputDynamicArrayProps & WithTranslation;
|
|
|
|
class InputDynamicArrayInternal extends React.Component<InputDynamicArrayInternalProps> {
|
|
changeValue(idx: number, newValue: string | number | undefined) {
|
|
const values = this.values.slice(0)
|
|
values[idx] = newValue
|
|
if (this.props.onChange) this.props.onChange(values)
|
|
}
|
|
|
|
get values() {
|
|
return this.props.value || this.props.default || []
|
|
}
|
|
|
|
addValue = () => {
|
|
const values = this.values.slice(0)
|
|
if (this.props.type === 'number') {
|
|
values.push(0)
|
|
}
|
|
else if (this.props.type === 'url') {
|
|
values.push("");
|
|
}
|
|
else if (this.props.type === 'enum') {
|
|
const {fieldSpec} = this.props;
|
|
const defaultValue = Object.keys(fieldSpec!.values)[0];
|
|
values.push(defaultValue);
|
|
} else if (this.props.type === 'color') {
|
|
values.push("#000000");
|
|
} else {
|
|
values.push("")
|
|
}
|
|
|
|
if (this.props.onChange) this.props.onChange(values)
|
|
}
|
|
|
|
deleteValue(valueIdx: number) {
|
|
const values = this.values.slice(0)
|
|
values.splice(valueIdx, 1)
|
|
|
|
if (this.props.onChange) this.props.onChange(values.length > 0 ? values : undefined);
|
|
}
|
|
|
|
render() {
|
|
const t = this.props.t;
|
|
const i18nProps = { t, i18n: this.props.i18n, tReady: this.props.tReady };
|
|
const inputs = this.values.map((v, i) => {
|
|
const deleteValueBtn= <DeleteValueInputButton
|
|
onClick={this.deleteValue.bind(this, i)}
|
|
{...i18nProps}
|
|
/>;
|
|
let input;
|
|
if(this.props.type === 'url') {
|
|
input = <InputUrl
|
|
value={v as string}
|
|
onChange={this.changeValue.bind(this, i)}
|
|
aria-label={this.props['aria-label'] || this.props.label}
|
|
/>
|
|
}
|
|
else if (this.props.type === 'number') {
|
|
input = <InputNumber
|
|
value={v as number}
|
|
onChange={this.changeValue.bind(this, i)}
|
|
aria-label={this.props['aria-label'] || this.props.label}
|
|
/>
|
|
}
|
|
else if (this.props.type === 'enum') {
|
|
const options = Object.keys(this.props.fieldSpec?.values).map(v => [v, capitalize(v)]);
|
|
input = <InputEnum
|
|
options={options}
|
|
value={v as string}
|
|
onChange={this.changeValue.bind(this, i)}
|
|
aria-label={this.props['aria-label'] || this.props.label}
|
|
/>
|
|
}
|
|
else if (this.props.type === 'color') {
|
|
input = <InputColor
|
|
value={v as string}
|
|
onChange={this.changeValue.bind(this, i)}
|
|
aria-label={this.props['aria-label'] || this.props.label}
|
|
/>
|
|
}
|
|
else {
|
|
input = <InputString
|
|
value={v as string}
|
|
onChange={this.changeValue.bind(this, i)}
|
|
aria-label={this.props['aria-label'] || this.props.label}
|
|
/>
|
|
}
|
|
|
|
return <div
|
|
style={this.props.style}
|
|
key={i}
|
|
className="maputnik-array-block"
|
|
>
|
|
<div className="maputnik-array-block-action">
|
|
{deleteValueBtn}
|
|
</div>
|
|
<div className="maputnik-array-block-content">
|
|
{input}
|
|
</div>
|
|
</div>
|
|
})
|
|
|
|
return (
|
|
<div className="maputnik-array">
|
|
{inputs}
|
|
<InputButton
|
|
className="maputnik-array-add-value"
|
|
onClick={this.addValue}
|
|
>
|
|
{t("Add value")}
|
|
</InputButton>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
const InputDynamicArray = withTranslation()(InputDynamicArrayInternal);
|
|
export default InputDynamicArray;
|
|
|
|
type DeleteValueInputButtonProps = {
|
|
onClick?(...args: unknown[]): unknown
|
|
} & WithTranslation;
|
|
|
|
class DeleteValueInputButton extends React.Component<DeleteValueInputButtonProps> {
|
|
render() {
|
|
const t = this.props.t;
|
|
return <InputButton
|
|
className="maputnik-delete-stop"
|
|
onClick={this.props.onClick}
|
|
title={t("Remove array item")}
|
|
>
|
|
<FieldDocLabel
|
|
label={<MdDelete />}
|
|
/>
|
|
</InputButton>
|
|
}
|
|
}
|