diff --git a/package.json b/package.json
index 145b75a..a119b9a 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"randomcolor": "^0.4.4",
"react": "^15.4.0",
"react-addons-pure-render-mixin": "^15.4.0",
+ "react-codemirror": "^0.3.0",
"react-collapse": "^2.3.3",
"react-color": "^2.10.0",
"react-dom": "^15.4.0",
diff --git a/src/codemirror-maputnik.css b/src/codemirror-maputnik.css
new file mode 100644
index 0000000..c5808a1
--- /dev/null
+++ b/src/codemirror-maputnik.css
@@ -0,0 +1,43 @@
+.cm-s-maputnik.CodeMirror {
+ height: 100%;
+ font-size: 10px;
+}
+
+.cm-s-maputnik.CodeMirror, .cm-s-maputnik .CodeMirror-gutters {
+ background: transparent;
+ color: #8e8e8e;
+ border: none;
+}
+.cm-s-maputnik .CodeMirror-cursor {
+ border-left: solid thin #8e8e8e !important;
+}
+
+.cm-s-maputnik.CodeMirror-focused div.CodeMirror-selected {
+ background: rgba(255, 255, 255, 0.10);
+}
+
+.cm-s-maputnik .CodeMirror-line::selection,
+.cm-s-maputnik .CodeMirror-line > span::selection,
+.cm-s-maputnik .CodeMirror-line > span > span::selection {
+ background: rgba(255, 255, 255, 0.10);
+}
+
+.cm-s-maputnik .CodeMirror-line::-moz-selection,
+.cm-s-maputnik .CodeMirror-line > span::-moz-selection,
+.cm-s-maputnik .CodeMirror-line > span > span::-moz-selection {
+ background: rgba(255, 255, 255, 0.10);
+}
+
+.cm-s-maputnik span.cm-string, .cm-s-maputnik span.cm-string-2 {
+ color: #8f9d6a;
+}
+.cm-s-maputnik span.cm-number { color: #91675f; }
+.cm-s-maputnik span.cm-property { color: #b8a077; }
+
+.cm-s-maputnik .CodeMirror-activeline-background {
+ background: rgba(255,255,255,0.1);
+}
+
+.cm-s-maputnik .CodeMirror-matchingbracket {
+ text-decoration: underline; color: white !important;
+}
diff --git a/src/components/layers/JSONEditor.jsx b/src/components/layers/JSONEditor.jsx
new file mode 100644
index 0000000..cc93b01
--- /dev/null
+++ b/src/components/layers/JSONEditor.jsx
@@ -0,0 +1,64 @@
+import React from 'react'
+
+import CodeMirror from 'react-codemirror'
+import InputBlock from '../inputs/InputBlock'
+import StringInput from '../inputs/StringInput'
+import SelectInput from '../inputs/SelectInput'
+
+import colors from '../../config/colors'
+import { margins } from '../../config/scales'
+
+import 'codemirror/mode/javascript/javascript'
+import 'codemirror/lib/codemirror.css'
+import '../../codemirror-maputnik.css'
+
+
+class JSONEditor extends React.Component {
+ static propTypes = {
+ layer: React.PropTypes.object.isRequired,
+ onChange: React.PropTypes.func,
+ }
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ code: JSON.stringify(props.layer, null, 2)
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState({
+ code: JSON.stringify(nextProps.layer, null, 2)
+ })
+ }
+
+ onCodeUpdate(newCode) {
+ try {
+ const parsedLayer = JSON.parse(newCode)
+ this.props.onChange(parsedLayer)
+ } catch(err) {
+ console.warn(err)
+ this.setState({
+ code: newCode
+ })
+ }
+ }
+
+ render() {
+ const codeMirrorOptions = {
+ mode: {name: "javascript", json: true},
+ tabSize: 2,
+ theme: 'maputnik',
+ viewportMargin: Infinity,
+ lineNumbers: false,
+ }
+
+ return
+ }
+}
+
+export default JSONEditor
diff --git a/src/components/layers/LayerEditor.jsx b/src/components/layers/LayerEditor.jsx
index 8af64cc..873e27e 100644
--- a/src/components/layers/LayerEditor.jsx
+++ b/src/components/layers/LayerEditor.jsx
@@ -1,5 +1,6 @@
import React from 'react'
+import JSONEditor from './JSONEditor'
import SourceEditor from './SourceEditor'
import FilterEditor from '../filter/FilterEditor'
import PropertyGroup from '../fields/PropertyGroup'
@@ -126,6 +127,10 @@ export default class LayerEditor extends React.Component {
groupFields={fields}
onChange={this.onPropertyChange.bind(this)}
/>
+ case 'jsoneditor': return
default: return null
}
}
diff --git a/src/config/layout.json b/src/config/layout.json
index 4e5f561..b947355 100644
--- a/src/config/layout.json
+++ b/src/config/layout.json
@@ -34,6 +34,10 @@
"line-dasharray",
"line-gap-width"
]
+ },
+ {
+ "title": "JSON",
+ "type": "jsoneditor"
}
]
},
@@ -55,6 +59,10 @@
"background-pattern",
"background-opacity"
]
+ },
+ {
+ "title": "JSON",
+ "type": "jsoneditor"
}
]
},
@@ -80,6 +88,10 @@
"fill-translate",
"fill-translate-anchor"
]
+ },
+ {
+ "title": "JSON",
+ "type": "jsoneditor"
}
]
},
@@ -150,6 +162,10 @@
"icon-keep-upright",
"icon-offset"
]
+ },
+ {
+ "title": "JSON",
+ "type": "jsoneditor"
}
]
}