mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2025-01-29 21:04:38 +01:00
Merge pull request #563 from orangemug/feature/more-root-property-support
Added support for more root level properties
This commit is contained in:
commit
c45cf2f0c8
7 changed files with 236 additions and 21 deletions
|
@ -59,7 +59,7 @@ export default class PropertyGroup extends React.Component {
|
||||||
onChange={this.onPropertyChange}
|
onChange={this.onPropertyChange}
|
||||||
key={fieldName}
|
key={fieldName}
|
||||||
fieldName={fieldName}
|
fieldName={fieldName}
|
||||||
value={fieldValue === undefined ? fieldSpec.default : fieldValue}
|
value={fieldValue}
|
||||||
fieldSpec={fieldSpec}
|
fieldSpec={fieldSpec}
|
||||||
/>
|
/>
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,29 +12,89 @@ class ArrayInput extends React.Component {
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
changeValue(idx, newValue) {
|
static defaultProps = {
|
||||||
console.log(idx, newValue)
|
value: [],
|
||||||
const values = this.values.slice(0)
|
default: [],
|
||||||
values[idx] = newValue
|
|
||||||
this.props.onChange(values)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get values() {
|
constructor (props) {
|
||||||
return this.props.value || this.props.default || []
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
value: this.props.value.slice(0),
|
||||||
|
// This is so we can compare changes in getDerivedStateFromProps
|
||||||
|
initialPropsValue: this.props.value.slice(0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedStateFromProps(props, state) {
|
||||||
|
const value = [];
|
||||||
|
const initialPropsValue = state.initialPropsValue.slice(0);
|
||||||
|
|
||||||
|
Array(props.length).fill(null).map((_, i) => {
|
||||||
|
if (props.value[i] === state.initialPropsValue[i]) {
|
||||||
|
value[i] = state.value[i];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
value[i] = state.value[i];
|
||||||
|
initialPropsValue[i] = state.value[i];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
value,
|
||||||
|
initialPropsValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isComplete (value) {
|
||||||
|
return Array(this.props.length).fill(null).every((_, i) => {
|
||||||
|
const val = value[i]
|
||||||
|
return !(val === undefined || val === "");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeValue(idx, newValue) {
|
||||||
|
const value = this.state.value.slice(0);
|
||||||
|
value[idx] = newValue;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
}, () => {
|
||||||
|
if (this.isComplete(value)) {
|
||||||
|
this.props.onChange(value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Unset until complete
|
||||||
|
this.props.onChange(undefined);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const inputs = this.values.map((v, i) => {
|
const {value} = this.state;
|
||||||
|
|
||||||
|
const containsValues = (
|
||||||
|
value.length > 0 &&
|
||||||
|
!value.every(val => {
|
||||||
|
return (val === "" || val === undefined)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputs = Array(this.props.length).fill(null).map((_, i) => {
|
||||||
if(this.props.type === 'number') {
|
if(this.props.type === 'number') {
|
||||||
return <NumberInput
|
return <NumberInput
|
||||||
key={i}
|
key={i}
|
||||||
value={v}
|
default={containsValues ? undefined : this.props.default[i]}
|
||||||
|
value={value[i]}
|
||||||
|
required={containsValues ? true : false}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
/>
|
/>
|
||||||
} else {
|
} else {
|
||||||
return <StringInput
|
return <StringInput
|
||||||
key={i}
|
key={i}
|
||||||
value={v}
|
default={containsValues ? undefined : this.props.default[i]}
|
||||||
|
value={value[i]}
|
||||||
|
required={containsValues ? true : false}
|
||||||
onChange={this.changeValue.bind(this, i)}
|
onChange={this.changeValue.bind(this, i)}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,13 @@ class EnumInput extends React.Component {
|
||||||
if(options.length <= 3 && optionsLabelLength(options) <= 20) {
|
if(options.length <= 3 && optionsLabelLength(options) <= 20) {
|
||||||
return <MultiButtonInput
|
return <MultiButtonInput
|
||||||
options={options}
|
options={options}
|
||||||
value={value}
|
value={value || this.props.default}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
} else {
|
} else {
|
||||||
return <SelectInput
|
return <SelectInput
|
||||||
options={options}
|
options={options}
|
||||||
value={value}
|
value={value || this.props.default}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ class NumberInput extends React.Component {
|
||||||
min: PropTypes.number,
|
min: PropTypes.number,
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
|
required: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -65,7 +66,7 @@ class NumberInput extends React.Component {
|
||||||
this.setState({editing: false});
|
this.setState({editing: false});
|
||||||
// Reset explicitly to default value if value has been cleared
|
// Reset explicitly to default value if value has been cleared
|
||||||
if(this.state.value === "") {
|
if(this.state.value === "") {
|
||||||
return this.changeValue(this.props.default)
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If set value is invalid fall back to the last valid value from props or at last resort the default value
|
// If set value is invalid fall back to the last valid value from props or at last resort the default value
|
||||||
|
@ -73,7 +74,7 @@ class NumberInput extends React.Component {
|
||||||
if(this.isValid(this.props.value)) {
|
if(this.isValid(this.props.value)) {
|
||||||
this.changeValue(this.props.value)
|
this.changeValue(this.props.value)
|
||||||
} else {
|
} else {
|
||||||
this.changeValue(this.props.default)
|
this.changeValue(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,9 +84,10 @@ class NumberInput extends React.Component {
|
||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
className="maputnik-number"
|
className="maputnik-number"
|
||||||
placeholder={this.props.default}
|
placeholder={this.props.default}
|
||||||
value={this.state.value || ""}
|
value={this.state.value === undefined ? "" : this.state.value}
|
||||||
onChange={e => this.changeValue(e.target.value)}
|
onChange={e => this.changeValue(e.target.value)}
|
||||||
onBlur={this.resetValue}
|
onBlur={this.resetValue}
|
||||||
|
required={this.props.required}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ class StringInput extends React.Component {
|
||||||
default: PropTypes.string,
|
default: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
multi: PropTypes.bool,
|
multi: PropTypes.bool,
|
||||||
|
required: PropTypes.bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -50,7 +51,7 @@ class StringInput extends React.Component {
|
||||||
spellCheck: !(tag === "input"),
|
spellCheck: !(tag === "input"),
|
||||||
className: classes.join(" "),
|
className: classes.join(" "),
|
||||||
style: this.props.style,
|
style: this.props.style,
|
||||||
value: this.state.value,
|
value: this.state.value === undefined ? "" : this.state.value,
|
||||||
placeholder: this.props.default,
|
placeholder: this.props.default,
|
||||||
onChange: e => {
|
onChange: e => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -63,7 +64,8 @@ class StringInput extends React.Component {
|
||||||
this.setState({editing: false});
|
this.setState({editing: false});
|
||||||
this.props.onChange(this.state.value);
|
this.props.onChange(this.state.value);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
required: this.props.required,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,12 @@ import PropTypes from 'prop-types'
|
||||||
|
|
||||||
import {latest} from '@mapbox/mapbox-gl-style-spec'
|
import {latest} from '@mapbox/mapbox-gl-style-spec'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
|
import ArrayInput from '../inputs/ArrayInput'
|
||||||
|
import NumberInput from '../inputs/NumberInput'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
import SelectInput from '../inputs/SelectInput'
|
||||||
|
import EnumInput from '../inputs/EnumInput'
|
||||||
|
import ColorField from '../fields/ColorField'
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
|
||||||
class SettingsModal extends React.Component {
|
class SettingsModal extends React.Component {
|
||||||
|
@ -16,18 +20,64 @@ class SettingsModal extends React.Component {
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
onOpenToggle: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeTransitionProperty(property, value) {
|
||||||
|
const transition = {
|
||||||
|
...this.props.mapStyle.transition,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined) {
|
||||||
|
delete transition[property];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
transition[property] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onStyleChanged({
|
||||||
|
...this.props.mapStyle,
|
||||||
|
transition,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLightProperty(property, value) {
|
||||||
|
const light = {
|
||||||
|
...this.props.mapStyle.light,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined) {
|
||||||
|
delete light[property];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
light[property] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onStyleChanged({
|
||||||
|
...this.props.mapStyle,
|
||||||
|
light,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
changeStyleProperty(property, value) {
|
changeStyleProperty(property, value) {
|
||||||
const changedStyle = {
|
const changedStyle = {
|
||||||
...this.props.mapStyle,
|
...this.props.mapStyle,
|
||||||
[property]: value
|
};
|
||||||
|
|
||||||
|
if (value === undefined) {
|
||||||
|
delete changedStyle[property];
|
||||||
}
|
}
|
||||||
this.props.onStyleChanged(changedStyle)
|
else {
|
||||||
|
changedStyle[property] = value;
|
||||||
|
}
|
||||||
|
this.props.onStyleChanged(changedStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const metadata = this.props.mapStyle.metadata || {}
|
const metadata = this.props.mapStyle.metadata || {}
|
||||||
const {onChangeMetadataProperty} = this.props;
|
const {onChangeMetadataProperty, mapStyle} = this.props;
|
||||||
const inputProps = { }
|
const inputProps = { }
|
||||||
|
|
||||||
|
const light = this.props.mapStyle.light || {};
|
||||||
|
const transition = this.props.mapStyle.transition || {};
|
||||||
|
|
||||||
return <Modal
|
return <Modal
|
||||||
data-wd-key="modal-settings"
|
data-wd-key="modal-settings"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
|
@ -89,6 +139,100 @@ class SettingsModal extends React.Component {
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Center"} doc={latest.$root.center.doc}>
|
||||||
|
<ArrayInput
|
||||||
|
length={2}
|
||||||
|
type="number"
|
||||||
|
value={mapStyle.center}
|
||||||
|
default={latest.$root.center.default || [0, 0]}
|
||||||
|
onChange={this.changeStyleProperty.bind(this, "center")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Zoom"} doc={latest.$root.zoom.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={mapStyle.zoom}
|
||||||
|
default={latest.$root.zoom.default || 0}
|
||||||
|
onChange={this.changeStyleProperty.bind(this, "zoom")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Bearing"} doc={latest.$root.bearing.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={mapStyle.bearing}
|
||||||
|
default={latest.$root.bearing.default}
|
||||||
|
onChange={this.changeStyleProperty.bind(this, "bearing")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Pitch"} doc={latest.$root.pitch.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={mapStyle.pitch}
|
||||||
|
default={latest.$root.pitch.default}
|
||||||
|
onChange={this.changeStyleProperty.bind(this, "pitch")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Light anchor"} doc={latest.light.anchor.doc}>
|
||||||
|
<EnumInput
|
||||||
|
{...inputProps}
|
||||||
|
value={light.anchor}
|
||||||
|
options={Object.keys(latest.light.anchor.values)}
|
||||||
|
default={latest.light.anchor.default}
|
||||||
|
onChange={this.changeLightProperty.bind(this, "anchor")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Light color"} doc={latest.light.color.doc}>
|
||||||
|
<ColorField
|
||||||
|
{...inputProps}
|
||||||
|
value={light.color}
|
||||||
|
default={latest.light.color.default}
|
||||||
|
onChange={this.changeLightProperty.bind(this, "color")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Light intensity"} doc={latest.light.intensity.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={light.intensity}
|
||||||
|
default={latest.light.intensity.default}
|
||||||
|
onChange={this.changeLightProperty.bind(this, "intensity")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Light position"} doc={latest.light.position.doc}>
|
||||||
|
<ArrayInput
|
||||||
|
{...inputProps}
|
||||||
|
type="number"
|
||||||
|
length={latest.light.position.length}
|
||||||
|
value={light.position}
|
||||||
|
default={latest.light.position.default}
|
||||||
|
onChange={this.changeLightProperty.bind(this, "position")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Transition delay"} doc={latest.transition.delay.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={transition.delay}
|
||||||
|
default={latest.transition.delay.default}
|
||||||
|
onChange={this.changeTransitionProperty.bind(this, "delay")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
|
<InputBlock label={"Transition duration"} doc={latest.transition.duration.doc}>
|
||||||
|
<NumberInput
|
||||||
|
{...inputProps}
|
||||||
|
value={transition.duration}
|
||||||
|
default={latest.transition.duration.default}
|
||||||
|
onChange={this.changeTransitionProperty.bind(this, "duration")}
|
||||||
|
/>
|
||||||
|
</InputBlock>
|
||||||
|
|
||||||
<InputBlock label={"Style Renderer"} doc={"Choose the default Maputnik renderer for this style."}>
|
<InputBlock label={"Style Renderer"} doc={"Choose the default Maputnik renderer for this style."}>
|
||||||
<SelectInput {...inputProps}
|
<SelectInput {...inputProps}
|
||||||
data-wd-key="modal-settings.maputnik:renderer"
|
data-wd-key="modal-settings.maputnik:renderer"
|
||||||
|
@ -101,6 +245,8 @@ class SettingsModal extends React.Component {
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
border: none;
|
border: none;
|
||||||
background-color: $color-gray;
|
background-color: $color-gray;
|
||||||
color: lighten($color-lowgray, 12);
|
color: lighten($color-lowgray, 12);
|
||||||
|
|
||||||
|
&:invalid {
|
||||||
|
border: solid 1px #B71C1C;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.maputnik-string {
|
.maputnik-string {
|
||||||
|
|
Loading…
Reference in a new issue