diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9d16b64..68ffeeb 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,14 +7,14 @@ templates:
name: "Create artifacts directory"
command: mkdir /tmp/artifacts
- restore_cache:
- key: v1-dependencies-{{ checksum "package.json" }}
+ key: v1-dependencies-{{ arch }}-{{ checksum "package.json" }}
- run: npm install
- save_cache:
paths:
- node_modules
- key: v1-dependencies-{{ checksum "package.json" }}
+ key: v1-dependencies-{{ arch }}-{{ checksum "package.json" }}
- run: mkdir -p /tmp/artifacts/logs
- run: npm run build
@@ -30,14 +30,14 @@ templates:
name: "Create artifacts directory"
command: mkdir /tmp/artifacts
- restore_cache:
- key: v1-dependencies-{{ checksum "package.json" }}
+ key: v1-dependencies-{{ arch }}-{{ checksum "package.json" }}
- run: npm install
- save_cache:
paths:
- node_modules
- key: v1-dependencies-{{ checksum "package.json" }}
+ key: v1-dependencies-{{ arch }}-{{ checksum "package.json" }}
- run: mkdir -p /tmp/artifacts/logs
- run: npm run build
@@ -71,7 +71,7 @@ jobs:
dependencies:
override:
- brew install node@6
- working_directory: ~/repo-linux-node-v6
+ working_directory: ~/repo-osx-node-v6
steps: *build-steps
build-osx-node-v8:
macos:
@@ -79,7 +79,7 @@ jobs:
dependencies:
override:
- brew install node@8
- working_directory: ~/repo-linux-node-v8
+ working_directory: ~/repo-osx-node-v8
steps: *build-steps
build-osx-node-v10:
macos:
@@ -87,7 +87,7 @@ jobs:
dependencies:
override:
- brew install node@10
- working_directory: ~/repo-linux-node-v10
+ working_directory: ~/repo-osx-node-v10
steps: *build-steps
workflows:
diff --git a/package-lock.json b/package-lock.json
index 35c46c9..4667ddc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5523,6 +5523,11 @@
"readable-stream": "2.3.5"
}
},
+ "focus-group": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/focus-group/-/focus-group-0.3.1.tgz",
+ "integrity": "sha1-4PMu2GsNq91v/OvfiY7LMuR/7c4="
+ },
"focus-trap": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-2.4.4.tgz",
@@ -8365,6 +8370,11 @@
"resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz",
"integrity": "sha1-+CbJtOKoUR2E46yinbBeGk87cqk="
},
+ "lodash.clamp": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.clamp/-/lodash.clamp-4.0.3.tgz",
+ "integrity": "sha1-XCS+3u7vB1NWDcK0y0Zx+Qpt36o="
+ },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
@@ -11479,6 +11489,16 @@
"object-assign": "4.1.1"
}
},
+ "react-aria-menubutton": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/react-aria-menubutton/-/react-aria-menubutton-5.1.1.tgz",
+ "integrity": "sha512-ceBjPvuqwM2jnRFsfMlpfPdyqQ5cz4STNH7NlKpxStr2uETB/zQ2sHiIUMTuqSuOszU1kgUB2vm3aVn3xdjhcA==",
+ "requires": {
+ "focus-group": "0.3.1",
+ "prop-types": "15.6.1",
+ "teeny-tap": "0.2.0"
+ }
+ },
"react-aria-modal": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/react-aria-modal/-/react-aria-modal-2.12.1.tgz",
@@ -14298,6 +14318,11 @@
"xtend": "4.0.1"
}
},
+ "teeny-tap": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/teeny-tap/-/teeny-tap-0.2.0.tgz",
+ "integrity": "sha1-Fn5kUYLQasIi1iuyq2eUenClimg="
+ },
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
diff --git a/package.json b/package.json
index 0184727..575c9ab 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"github-api": "^3.0.0",
"jsonlint": "github:josdejong/jsonlint#85a19d7",
"lodash.capitalize": "^4.2.1",
+ "lodash.clamp": "^4.0.3",
"lodash.clonedeep": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.throttle": "^4.1.1",
@@ -42,6 +43,7 @@
"prop-types": "^15.6.0",
"react": "^16.3.2",
"react-addons-pure-render-mixin": "^15.6.2",
+ "react-aria-menubutton": "^5.1.1",
"react-aria-modal": "^2.12.1",
"react-autocomplete": "^1.7.2",
"react-codemirror2": "^4.2.1",
diff --git a/src/components/App.jsx b/src/components/App.jsx
index 780470b..5e2ee06 100644
--- a/src/components/App.jsx
+++ b/src/components/App.jsx
@@ -1,5 +1,8 @@
import React from 'react'
import Mousetrap from 'mousetrap'
+import cloneDeep from 'lodash.clonedeep'
+import clamp from 'lodash.clamp'
+import {arrayMove} from 'react-sortable-hoc';
import url from 'url'
import MapboxGlMap from './map/MapboxGlMap'
@@ -168,6 +171,24 @@ export default class App extends React.Component {
})
}
+ onMoveLayer(move) {
+ let { oldIndex, newIndex } = move;
+ let layers = this.state.mapStyle.layers;
+ oldIndex = clamp(oldIndex, 0, layers.length-1);
+ newIndex = clamp(newIndex, 0, layers.length-1);
+ if(oldIndex === newIndex) return;
+
+ if (oldIndex === this.state.selectedLayerIndex) {
+ this.setState({
+ selectedLayerIndex: newIndex
+ });
+ }
+
+ layers = layers.slice(0);
+ layers = arrayMove(layers, oldIndex, newIndex);
+ this.onLayersChange(layers);
+ }
+
onLayersChange(changedLayers) {
const changedStyle = {
...this.state.mapStyle,
@@ -176,6 +197,40 @@ export default class App extends React.Component {
this.onStyleChanged(changedStyle)
}
+ onLayerDestroy(layerId) {
+ let layers = this.state.mapStyle.layers;
+ const remainingLayers = layers.slice(0);
+ const idx = style.indexOfLayer(remainingLayers, layerId)
+ remainingLayers.splice(idx, 1);
+ this.onLayersChange(remainingLayers);
+ }
+
+ onLayerCopy(layerId) {
+ let layers = this.state.mapStyle.layers;
+ const changedLayers = layers.slice(0)
+ const idx = style.indexOfLayer(changedLayers, layerId)
+
+ const clonedLayer = cloneDeep(changedLayers[idx])
+ clonedLayer.id = clonedLayer.id + "-copy"
+ changedLayers.splice(idx, 0, clonedLayer)
+ this.onLayersChange(changedLayers)
+ }
+
+ onLayerVisibilityToggle(layerId) {
+ let layers = this.state.mapStyle.layers;
+ const changedLayers = layers.slice(0)
+ const idx = style.indexOfLayer(changedLayers, layerId)
+
+ const layer = { ...changedLayers[idx] }
+ const changedLayout = 'layout' in layer ? {...layer.layout} : {}
+ changedLayout.visibility = changedLayout.visibility === 'none' ? 'visible' : 'none'
+
+ layer.layout = changedLayout
+ changedLayers[idx] = layer
+ this.onLayersChange(changedLayers)
+ }
+
+
onLayerIdChange(oldId, newId) {
const changedLayers = this.state.mapStyle.layers.slice(0)
const idx = style.indexOfLayer(changedLayers, oldId)
@@ -311,6 +366,10 @@ export default class App extends React.Component {
/>
const layerList =