diff --git a/src/components/fields/FunctionSpecField.jsx b/src/components/fields/FunctionSpecField.jsx index d1e30d3c..fb12a45b 100644 --- a/src/components/fields/FunctionSpecField.jsx +++ b/src/components/fields/FunctionSpecField.jsx @@ -45,27 +45,30 @@ function isPrimative (value) { } function isArrayOfPrimatives (values) { - if (Array.isArray(value)) { + if (Array.isArray(values)) { return values.every(isPrimative); } return false; } -function checkIsExpression (value, fieldSpec={}) { +function getDataType (value, fieldSpec={}) { if (value === undefined) { - return false; + return "value"; } else if (isPrimative(value)) { - return false; + return "value"; } else if (fieldSpec.type === "array" && isArrayOfPrimatives(value)) { - return false; + return "value"; } - else if (isZoomField(value) || isDataField(value)) { - return false; + else if (isZoomField(value)) { + return "zoom_function"; + } + else if (isDataField(value)) { + return "data_function"; } else { - return true; + return "expression"; } } @@ -111,7 +114,21 @@ export default class FunctionSpecProperty extends React.Component { constructor (props) { super(); this.state = { - isExpression: checkIsExpression(props.value, props.fieldSpec), + dataType: getDataType(props.value, props.fieldSpec), + isEditing: false, + } + } + + static getDerivedStateFromProps(props, state) { + // Because otherwise when editing values we end up accidentally changing field type. + if (state.isEditing) { + return {}; + } + else { + return { + isEditing: false, + dataType: getDataType(props.value, props.fieldSpec) + }; } } @@ -150,7 +167,7 @@ export default class FunctionSpecProperty extends React.Component { const {fieldSpec, fieldName} = this.props; this.props.onChange(fieldName, fieldSpec.default); this.setState({ - isExpression: false, + dataType: "value", }); } @@ -184,25 +201,25 @@ export default class FunctionSpecProperty extends React.Component { const {value, fieldName} = this.props; if (isLiteralExpression(value)) { - this.props.onChange(fieldName, value[1]); - this.setState({ - isExpression: false - }); + this.props.onChange(fieldName, value[1]); + this.setState({ + dataType: "value", + }); } } canUndo = () => { - const {value} = this.props; - return isLiteralExpression(value); + const {value, fieldSpec} = this.props; + return ( + isLiteralExpression(value) || + isPrimative(value) || + (Array.isArray(value) && fieldSpec.type === "array") + ); } makeExpression = () => { const expression = ["literal", this.props.value || this.props.fieldSpec.default]; this.props.onChange(this.props.fieldName, expression); - - this.setState({ - isExpression: true, - }); } makeDataFunction = () => { @@ -219,11 +236,20 @@ export default class FunctionSpecProperty extends React.Component { this.props.onChange(this.props.fieldName, dataFunc) } + 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 (this.state.isExpression) { + if (dataType === "expression") { specField = ( ); } - else if (isZoomField(this.props.value)) { + else if (dataType === "zoom_function") { specField = ( ) } - else if (isDataField(this.props.value)) { + else if (dataType === "data_function") { specField = ( {}, + onBlur: () => {}, } constructor (props) { @@ -69,6 +71,8 @@ export default class ExpressionProperty extends React.Component { > { - return stringifyPretty(data, {indent: 2, maxLength: 50} ); - } + return stringifyPretty(data, {indent: 2, maxLength: 50}); + }, + onFocus: () => {}, + onBlur: () => {}, } constructor(props) { super(props) this.state = { isEditing: false, - prevValue: this.getValue(), + prevValue: this.props.getValue(this.props.layer), }; } - getValue () { - return this.props.getValue(this.props.layer); - } - componentDidMount () { this._doc = CodeMirror(this._el, { - value: this.getValue(), + value: this.props.getValue(this.props.layer), mode: { name: "javascript", json: true @@ -75,12 +73,14 @@ class JSONEditor extends React.Component { } onFocus = () => { + this.props.onFocus(); this.setState({ isEditing: true }); } onBlur = () => { + this.props.onBlur(); this.setState({ isEditing: false }); @@ -96,7 +96,7 @@ class JSONEditor extends React.Component { if (!this.state.isEditing && prevProps.layer !== this.props.layer) { this._cancelNextChange = true; this._doc.setValue( - this.getValue(), + this.props.getValue(this.props.layer), ) } } @@ -104,6 +104,9 @@ class JSONEditor extends React.Component { onChange = (e) => { if (this._cancelNextChange) { this._cancelNextChange = false; + this.setState({ + prevValue: this._doc.getValue(), + }) return; } const newCode = this._doc.getValue();