mirror of
https://github.com/maputnik/editor.git
synced 2026-08-30 17:07:26 +00:00
Add lint to CI and fix errors (#853)
Adds lint to CI and fixes errors. I'm not sure I'm fully proud of all the solutions there. But there's no lint issues and the lint is being checked as part of the CI. --------- Co-authored-by: Yuri Astrakhan <yuriastrakhan@gmail.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2020": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/jsx-runtime",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"dist"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"settings": {
|
||||
"react": { "version": "16.4" }
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
"react-refresh"],
|
||||
"rules": {
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ "allowConstantExport": true }
|
||||
],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{ "argsIgnorePattern": "^_" }
|
||||
],
|
||||
"no-unused-vars": "off",
|
||||
"react/prop-types": ["off"],
|
||||
// Disable no-undef. It's covered by @typescript-eslint
|
||||
"no-undef": "off",
|
||||
"indent": ["error", 2]
|
||||
},
|
||||
"globals": {
|
||||
"global": "readonly"
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react/jsx-runtime',
|
||||
'plugin:react-hooks/recommended',
|
||||
],
|
||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
settings: { react: { version: '18.2' } },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -42,6 +42,9 @@ jobs:
|
||||
${{ runner.os }}-node-
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- run: npm run lint
|
||||
- run: npm run lint-css
|
||||
|
||||
|
||||
|
||||
build-artifacts:
|
||||
|
||||
Generated
+244
-139
File diff suppressed because it is too large
Load Diff
+6
-3
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"lint": "eslint ./src --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0 && npm run lint-css",
|
||||
"lint": "eslint ./src --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0",
|
||||
"test": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"lint-css": "stylelint \"src/styles/*.scss\"",
|
||||
@@ -26,6 +26,8 @@
|
||||
"@maplibre/maplibre-gl-style-spec": "^17.0.1",
|
||||
"@mdi/js": "^6.6.96",
|
||||
"@mdi/react": "^1.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.16.0",
|
||||
"@typescript-eslint/parser": "^6.16.0",
|
||||
"array-move": "^4.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"classnames": "^2.3.1",
|
||||
@@ -103,6 +105,7 @@
|
||||
"@types/color": "^3.0.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/geojson": "^7946.0.13",
|
||||
"@types/json-to-ast": "^2.1.4",
|
||||
"@types/lodash.capitalize": "^4.2.9",
|
||||
"@types/lodash.clamp": "^4.0.9",
|
||||
@@ -124,10 +127,10 @@
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"cypress": "^13.6.1",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.4",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"express": "^4.17.3",
|
||||
"istanbul": "^0.4.5",
|
||||
"istanbul-lib-coverage": "^3.2.0",
|
||||
|
||||
+13
-13
@@ -334,7 +334,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
const metadata: {[key: string]: string} = this.state.mapStyle.metadata || {} as any
|
||||
const accessToken = metadata['maputnik:openmaptiles_access_token'] || tokens.openmaptiles
|
||||
|
||||
let glyphUrl = (typeof urlTemplate === 'string')? urlTemplate.replace('{key}', accessToken): urlTemplate;
|
||||
const glyphUrl = (typeof urlTemplate === 'string')? urlTemplate.replace('{key}', accessToken): urlTemplate;
|
||||
downloadGlyphsMetadata(glyphUrl, fonts => {
|
||||
this.setState({ spec: updateRootSpec(this.state.spec, 'glyphs', fonts)})
|
||||
})
|
||||
@@ -402,7 +402,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
// Special case: Duplicate layer id
|
||||
const dupMatch = error.message.match(/layers\[(\d+)\]: (duplicate layer id "?(.*)"?, previously used)/);
|
||||
if (dupMatch) {
|
||||
const [_matchStr, index, message] = dupMatch;
|
||||
const [, index, message] = dupMatch;
|
||||
return {
|
||||
message: error.message,
|
||||
parsed: {
|
||||
@@ -419,7 +419,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
// Special case: Invalid source
|
||||
const invalidSourceMatch = error.message.match(/layers\[(\d+)\]: (source "(?:.*)" not found)/);
|
||||
if (invalidSourceMatch) {
|
||||
const [_matchStr, index, message] = invalidSourceMatch;
|
||||
const [, index, message] = invalidSourceMatch;
|
||||
return {
|
||||
message: error.message,
|
||||
parsed: {
|
||||
@@ -435,7 +435,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
|
||||
const layerMatch = error.message.match(/layers\[(\d+)\]\.(?:(\S+)\.)?(\S+): (.*)/);
|
||||
if (layerMatch) {
|
||||
const [_matchStr, index, group, property, message] = layerMatch;
|
||||
const [, index, group, property, message] = layerMatch;
|
||||
const key = (group && property) ? [group, property].join(".") : property;
|
||||
return {
|
||||
message: error.message,
|
||||
@@ -466,7 +466,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
try {
|
||||
const objPath = message.split(":")[0];
|
||||
// Errors can be deply nested for example 'layers[0].filter[1][1][0]' we only care upto the property 'layers[0].filter'
|
||||
const unsetPath = objPath.match(/^\S+?\[\d+\]\.[^\[]+/)![0];
|
||||
const unsetPath = objPath.match(/^\S+?\[\d+\]\.[^[]+/)![0];
|
||||
unset(dirtyMapStyle, unsetPath);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -547,14 +547,14 @@ export default class App extends React.Component<any, AppState> {
|
||||
}
|
||||
|
||||
onLayerDestroy = (index: number) => {
|
||||
let layers = this.state.mapStyle.layers;
|
||||
const layers = this.state.mapStyle.layers;
|
||||
const remainingLayers = layers.slice(0);
|
||||
remainingLayers.splice(index, 1);
|
||||
this.onLayersChange(remainingLayers);
|
||||
}
|
||||
|
||||
onLayerCopy = (index: number) => {
|
||||
let layers = this.state.mapStyle.layers;
|
||||
const layers = this.state.mapStyle.layers;
|
||||
const changedLayers = layers.slice(0)
|
||||
|
||||
const clonedLayer = cloneDeep(changedLayers[index])
|
||||
@@ -564,7 +564,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
}
|
||||
|
||||
onLayerVisibilityToggle = (index: number) => {
|
||||
let layers = this.state.mapStyle.layers;
|
||||
const layers = this.state.mapStyle.layers;
|
||||
const changedLayers = layers.slice(0)
|
||||
|
||||
const layer = { ...changedLayers[index] }
|
||||
@@ -624,11 +624,11 @@ export default class App extends React.Component<any, AppState> {
|
||||
fetchSources() {
|
||||
const sourceList: {[key: string]: any} = {};
|
||||
|
||||
for(let [key, val] of Object.entries(this.state.mapStyle.sources)) {
|
||||
for(const [key, val] of Object.entries(this.state.mapStyle.sources)) {
|
||||
if(
|
||||
!this.state.sources.hasOwnProperty(key) &&
|
||||
!Object.prototype.hasOwnProperty.call(this.state.sources, key) &&
|
||||
val.type === "vector" &&
|
||||
val.hasOwnProperty("url")
|
||||
Object.prototype.hasOwnProperty.call(val, "url")
|
||||
) {
|
||||
sourceList[key] = {
|
||||
type: val.type,
|
||||
@@ -649,7 +649,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
|
||||
if(!json.hasOwnProperty("vector_layers")) {
|
||||
if(!Object.prototype.hasOwnProperty.call(json, "vector_layers")) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ export default class App extends React.Component<any, AppState> {
|
||||
[key]: this.state.sources[key],
|
||||
});
|
||||
|
||||
for(let layer of json.vector_layers) {
|
||||
for(const layer of json.vector_layers) {
|
||||
(sources[key] as any).layers.push(layer.id)
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ export default class Doc extends React.Component<DocProps> {
|
||||
<tr key={key}>
|
||||
<td>{key}</td>
|
||||
{Object.keys(headers).map((k) => {
|
||||
if (supportObj.hasOwnProperty(k)) {
|
||||
if (Object.prototype.hasOwnProperty.call(supportObj, k)) {
|
||||
return <td key={k}>{supportObj[k as keyof typeof headers]}</td>;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -40,7 +40,7 @@ function isIdentityProperty(value: any) {
|
||||
return (
|
||||
typeof(value) === 'object' &&
|
||||
value.type === "identity" &&
|
||||
value.hasOwnProperty("property")
|
||||
Object.prototype.hasOwnProperty.call(value, "property")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import FieldDocLabel from './FieldDocLabel'
|
||||
import Doc from './Doc'
|
||||
import generateUniqueId from '../libs/document-uid';
|
||||
|
||||
type FieldsetProps = {
|
||||
label?: string,
|
||||
@@ -12,14 +13,12 @@ type FieldsetState = {
|
||||
showDoc: boolean
|
||||
};
|
||||
|
||||
let IDX = 0;
|
||||
|
||||
export default class Fieldset extends React.Component<FieldsetProps, FieldsetState> {
|
||||
_labelId: string;
|
||||
|
||||
constructor (props: FieldsetProps) {
|
||||
super(props);
|
||||
this._labelId = `fieldset_label_${(IDX++)}`;
|
||||
this._labelId = generateUniqueId(`fieldset_label_`);
|
||||
this.state = {
|
||||
showDoc: false,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import ExpressionProperty from './_ExpressionProperty';
|
||||
|
||||
|
||||
function combiningFilter(props: FilterEditorProps): LegacyFilterSpecification | ExpressionSpecification {
|
||||
let filter = props.filter || ['all'];
|
||||
const filter = props.filter || ['all'];
|
||||
|
||||
if (!Array.isArray(filter)) {
|
||||
return filter;
|
||||
@@ -148,7 +148,7 @@ export default class FilterEditor extends React.Component<FilterEditorProps, Fil
|
||||
}
|
||||
|
||||
makeExpression = () => {
|
||||
let filter = combiningFilter(this.props);
|
||||
const filter = combiningFilter(this.props);
|
||||
this.props.onChange(migrateFilter(filter));
|
||||
this.setState({
|
||||
displaySimpleFilter: false,
|
||||
@@ -205,8 +205,8 @@ export default class FilterEditor extends React.Component<FilterEditorProps, Fil
|
||||
}
|
||||
else if (displaySimpleFilter) {
|
||||
const filter = combiningFilter(this.props);
|
||||
let combiningOp = filter[0];
|
||||
let filters = filter.slice(1) as (LegacyFilterSpecification | ExpressionSpecification)[];
|
||||
const combiningOp = filter[0];
|
||||
const filters = filter.slice(1) as (LegacyFilterSpecification | ExpressionSpecification)[];
|
||||
|
||||
const actions = (
|
||||
<div>
|
||||
@@ -282,7 +282,7 @@ export default class FilterEditor extends React.Component<FilterEditorProps, Fil
|
||||
);
|
||||
}
|
||||
else {
|
||||
let {filter} = this.props;
|
||||
const {filter} = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -110,7 +110,7 @@ export default class InputColor extends React.Component<InputColorProps> {
|
||||
/>
|
||||
</div>
|
||||
|
||||
var swatchStyle = {
|
||||
const swatchStyle = {
|
||||
backgroundColor: this.props.value
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { BaseSyntheticEvent } from 'react'
|
||||
|
||||
let IDX = 0;
|
||||
import generateUniqueId from '../libs/document-uid';
|
||||
|
||||
export type InputNumberProps = {
|
||||
value?: number
|
||||
@@ -32,7 +31,7 @@ export default class InputNumber extends React.Component<InputNumberProps, Input
|
||||
constructor(props: InputNumberProps) {
|
||||
super(props)
|
||||
this.state = {
|
||||
uuid: IDX++,
|
||||
uuid: +generateUniqueId(),
|
||||
editing: false,
|
||||
value: props.value,
|
||||
dirtyValue: props.value,
|
||||
@@ -140,7 +139,7 @@ export default class InputNumber extends React.Component<InputNumberProps, Input
|
||||
}
|
||||
else {
|
||||
value = value + (step - snap);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +154,8 @@ export default class InputNumber extends React.Component<InputNumberProps, Input
|
||||
|
||||
render() {
|
||||
if(
|
||||
this.props.hasOwnProperty("min") && this.props.hasOwnProperty("max") &&
|
||||
Object.prototype.hasOwnProperty.call(this.props, "min") &&
|
||||
Object.prototype.hasOwnProperty.call(this.props, "max") &&
|
||||
this.props.min !== undefined && this.props.max !== undefined &&
|
||||
this.props.allowRange
|
||||
) {
|
||||
|
||||
@@ -60,13 +60,14 @@ export default class SpecField extends React.Component<SpecFieldProps> {
|
||||
max={this.props.fieldSpec.maximum}
|
||||
/>
|
||||
)
|
||||
case 'enum':
|
||||
case 'enum': {
|
||||
const options = Object.keys(this.props.fieldSpec.values || []).map(v => [v, capitalize(v)])
|
||||
|
||||
return <InputEnum
|
||||
{...commonProps as Omit<InputEnumProps, "options">}
|
||||
options={options}
|
||||
/>
|
||||
}
|
||||
case 'resolvedImage':
|
||||
case 'formatted':
|
||||
case 'string':
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class InputString extends React.Component<InputStringProps, Input
|
||||
let tag;
|
||||
let classes;
|
||||
|
||||
if(!!this.props.multi) {
|
||||
if(this.props.multi) {
|
||||
tag = "textarea"
|
||||
classes = [
|
||||
"maputnik-string",
|
||||
@@ -60,14 +60,14 @@ export default class InputString extends React.Component<InputStringProps, Input
|
||||
]
|
||||
}
|
||||
|
||||
if(!!this.props.disabled) {
|
||||
if(this.props.disabled) {
|
||||
classes.push("maputnik-string--disabled");
|
||||
}
|
||||
|
||||
return React.createElement(tag, {
|
||||
"aria-label": this.props["aria-label"],
|
||||
"data-wd-key": this.props["data-wd-key"],
|
||||
spellCheck: this.props.hasOwnProperty("spellCheck") ? this.props.spellCheck : !(tag === "input"),
|
||||
spellCheck: Object.prototype.hasOwnProperty.call(this.props, "spellCheck") ? this.props.spellCheck : !(tag === "input"),
|
||||
disabled: this.props.disabled,
|
||||
className: classes.join(" "),
|
||||
style: this.props.style,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Wrapper, Button, Menu, MenuItem } from 'react-aria-menubutton'
|
||||
import {Accordion} from 'react-accessible-accordion';
|
||||
@@ -150,7 +150,7 @@ export default class LayerEditor extends React.Component<LayerEditorProps, Layer
|
||||
|
||||
let sourceLayerIds;
|
||||
const layer = this.props.layer as Exclude<LayerSpecification, BackgroundLayerSpecification>;
|
||||
if(this.props.sources.hasOwnProperty(layer.source)) {
|
||||
if(Object.prototype.hasOwnProperty.call(this.props.sources, layer.source)) {
|
||||
sourceLayerIds = (this.props.sources[layer.source] as any).layers;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import lodash from 'lodash';
|
||||
|
||||
@@ -8,26 +8,8 @@ import ModalAdd from './ModalAdd'
|
||||
|
||||
import {SortEndHandler, SortableContainer} from 'react-sortable-hoc';
|
||||
import type {LayerSpecification} from 'maplibre-gl';
|
||||
|
||||
function layerPrefix(name: string) {
|
||||
return name.replace(' ', '-').replace('_', '-').split('-')[0]
|
||||
}
|
||||
|
||||
function findClosestCommonPrefix(layers: LayerSpecification[], idx: number) {
|
||||
const currentLayerPrefix = layerPrefix(layers[idx].id)
|
||||
let closestIdx = idx
|
||||
for (let i = idx; i > 0; i--) {
|
||||
const previousLayerPrefix = layerPrefix(layers[i-1].id)
|
||||
if(previousLayerPrefix === currentLayerPrefix) {
|
||||
closestIdx = i - 1
|
||||
} else {
|
||||
return closestIdx
|
||||
}
|
||||
}
|
||||
return closestIdx
|
||||
}
|
||||
|
||||
let UID = 0;
|
||||
import generateUniqueId from '../libs/document-uid';
|
||||
import { findClosestCommonPrefix, layerPrefix } from '../libs/layer';
|
||||
|
||||
type LayerListContainerProps = {
|
||||
layers: LayerSpecification[]
|
||||
@@ -64,7 +46,7 @@ class LayerListContainer extends React.Component<LayerListContainerProps, LayerL
|
||||
collapsedGroups: {},
|
||||
areAllGroupsExpanded: false,
|
||||
keys: {
|
||||
add: UID++,
|
||||
add: +generateUniqueId(),
|
||||
},
|
||||
isOpen: {
|
||||
add: false,
|
||||
@@ -76,7 +58,7 @@ class LayerListContainer extends React.Component<LayerListContainerProps, LayerL
|
||||
this.setState({
|
||||
keys: {
|
||||
...this.state.keys,
|
||||
[modalName]: UID++,
|
||||
[modalName]: +generateUniqueId(),
|
||||
},
|
||||
isOpen: {
|
||||
...this.state.isOpen,
|
||||
@@ -88,7 +70,7 @@ class LayerListContainer extends React.Component<LayerListContainerProps, LayerL
|
||||
toggleLayers = () => {
|
||||
let idx = 0
|
||||
|
||||
let newGroups: {[key:string]: boolean} = {}
|
||||
const newGroups: {[key:string]: boolean} = {}
|
||||
|
||||
this.groupedLayers().forEach(layers => {
|
||||
const groupPrefix = layerPrefix(layers[0].id)
|
||||
@@ -328,6 +310,7 @@ class LayerListContainer extends React.Component<LayerListContainerProps, LayerL
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-refresh/only-export-components
|
||||
const LayerListContainerSortable = SortableContainer((props: LayerListContainerProps) => <LayerListContainer {...props} />)
|
||||
|
||||
type LayerListProps = LayerListContainerProps & {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react'
|
||||
import React, {type JSX} from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import MapLibreGl, {LayerSpecification, LngLat, Map, MapOptions, SourceSpecification, StyleSpecification} from 'maplibre-gl'
|
||||
// @ts-ignore
|
||||
|
||||
@@ -48,7 +48,7 @@ function renderFeature(feature: InspectFeature, idx: number) {
|
||||
}
|
||||
|
||||
function removeDuplicatedFeatures(features: InspectFeature[]) {
|
||||
let uniqueFeatures: InspectFeature[] = [];
|
||||
const uniqueFeatures: InspectFeature[] = [];
|
||||
|
||||
features.forEach(feature => {
|
||||
const featureIndex = uniqueFeatures.findIndex(feature2 => {
|
||||
|
||||
@@ -5,10 +5,10 @@ import type {InspectFeature} from './MapMaplibreGlFeaturePropertyPopup';
|
||||
function groupFeaturesBySourceLayer(features: InspectFeature[]) {
|
||||
const sources: {[key: string]: InspectFeature[]} = {}
|
||||
|
||||
let returnedFeatures: {[key: string]: number} = {}
|
||||
const returnedFeatures: {[key: string]: number} = {}
|
||||
|
||||
features.forEach(feature => {
|
||||
if(returnedFeatures.hasOwnProperty(feature.layer.id)) {
|
||||
if(Object.prototype.hasOwnProperty.call(returnedFeatures, feature.layer.id)) {
|
||||
returnedFeatures[feature.layer.id]++
|
||||
|
||||
const featureObject = sources[feature.layer['source-layer']].find((f: InspectFeature) => f.layer.id === feature.layer.id)
|
||||
@@ -42,21 +42,21 @@ class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
|
||||
const paintProps = feature.layer.paint;
|
||||
let propName;
|
||||
|
||||
if(paintProps.hasOwnProperty("text-color") && paintProps["text-color"]) {
|
||||
if(Object.prototype.hasOwnProperty.call(paintProps, "text-color") && paintProps["text-color"]) {
|
||||
propName = "text-color";
|
||||
}
|
||||
else if (paintProps.hasOwnProperty("fill-color") && paintProps["fill-color"]) {
|
||||
else if (Object.prototype.hasOwnProperty.call(paintProps, "fill-color") && paintProps["fill-color"]) {
|
||||
propName = "fill-color";
|
||||
}
|
||||
else if (paintProps.hasOwnProperty("line-color") && paintProps["line-color"]) {
|
||||
else if (Object.prototype.hasOwnProperty.call(paintProps, "line-color") && paintProps["line-color"]) {
|
||||
propName = "line-color";
|
||||
}
|
||||
else if (paintProps.hasOwnProperty("fill-extrusion-color") && paintProps["fill-extrusion-color"]) {
|
||||
else if (Object.prototype.hasOwnProperty.call(paintProps, "fill-extrusion-color") && paintProps["fill-extrusion-color"]) {
|
||||
propName = "fill-extrusion-color";
|
||||
}
|
||||
|
||||
if(propName) {
|
||||
let color = feature.layer.paint[propName];
|
||||
const color = feature.layer.paint[propName];
|
||||
return String(color);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -99,7 +99,7 @@ export default class MapOpenLayers extends React.Component<MapOpenLayersProps, M
|
||||
});
|
||||
|
||||
map.on('pointermove', (evt) => {
|
||||
var coords = toLonLat(evt.coordinate);
|
||||
const coords = toLonLat(evt.coordinate);
|
||||
this.setState({
|
||||
cursor: [
|
||||
coords[0].toFixed(2),
|
||||
|
||||
@@ -113,7 +113,7 @@ export default class ModalAdd extends React.Component<ModalAddProps, ModalAddSta
|
||||
]
|
||||
}
|
||||
|
||||
for(let [key, val] of Object.entries(this.props.sources) as any) {
|
||||
for(const [key, val] of Object.entries(this.props.sources) as any) {
|
||||
const valType = val.type as keyof typeof types;
|
||||
if(types[valType] && types[valType].indexOf(type) > -1) {
|
||||
sources.push(key);
|
||||
|
||||
@@ -135,7 +135,7 @@ export default class ModalOpen extends React.Component<ModalOpenProps, ModalOpen
|
||||
}
|
||||
|
||||
onUpload = (_: any, files: Result[]) => {
|
||||
const [_e, file] = files[0];
|
||||
const [, file] = files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
this.clearError();
|
||||
|
||||
@@ -23,7 +23,7 @@ function setStopRefs(props: DataPropertyProps, state: DataPropertyState) {
|
||||
|
||||
if(props.value && props.value.stops) {
|
||||
props.value.stops.forEach((_val, idx) => {
|
||||
if(!state.refs.hasOwnProperty(idx)) {
|
||||
if(!Object.prototype.hasOwnProperty.call(state.refs, idx)) {
|
||||
if(!newRefs) {
|
||||
newRefs = {...state};
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ function setStopRefs(props: ZoomPropertyProps, state: ZoomPropertyState) {
|
||||
|
||||
if(props.value && (props.value as ZoomWithStops).stops) {
|
||||
(props.value as ZoomWithStops).stops.forEach((_val, idx: number) => {
|
||||
if(!state.refs.hasOwnProperty(idx)) {
|
||||
if(Object.prototype.hasOwnProperty.call(!state.refs, idx)) {
|
||||
if(!newRefs) {
|
||||
newRefs = {...state};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { IconContext } from "react-icons";
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import './favicon.ico'
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ function get(namespace: keyof DebugStore, key: string) {
|
||||
if(!enabled()) {
|
||||
throw genErr();
|
||||
}
|
||||
if(debugStore.hasOwnProperty(namespace)) {
|
||||
if(Object.prototype.hasOwnProperty.call(debugStore, namespace)) {
|
||||
return debugStore[namespace][key];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,3 +70,21 @@ export function changeProperty(layer: LayerSpecification, group: keyof LayerSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function layerPrefix(name: string) {
|
||||
return name.replace(' ', '-').replace('_', '-').split('-')[0]
|
||||
}
|
||||
|
||||
export function findClosestCommonPrefix(layers: LayerSpecification[], idx: number) {
|
||||
const currentLayerPrefix = layerPrefix(layers[idx].id)
|
||||
let closestIdx = idx
|
||||
for (let i = idx; i > 0; i--) {
|
||||
const previousLayerPrefix = layerPrefix(layers[i-1].id)
|
||||
if(previousLayerPrefix === currentLayerPrefix) {
|
||||
closestIdx = i - 1
|
||||
} else {
|
||||
return closestIdx
|
||||
}
|
||||
}
|
||||
return closestIdx
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ export function downloadGlyphsMetadata(urlTemplate: string, cb: (...args: any[])
|
||||
|
||||
// Special handling because Tileserver GL serves the fontstacks metadata differently
|
||||
// https://github.com/klokantech/tileserver-gl/pull/104#issuecomment-274444087
|
||||
let urlObj = npmurl.parse(urlTemplate);
|
||||
const urlObj = npmurl.parse(urlTemplate);
|
||||
const normPathPart = '/%7Bfontstack%7D/%7Brange%7D.pbf';
|
||||
if(urlObj.pathname === normPathPart) {
|
||||
urlObj.pathname = '/fontstacks.json';
|
||||
} else {
|
||||
urlObj.pathname = urlObj.pathname!.replace(normPathPart, '.json');
|
||||
}
|
||||
let url = npmurl.format(urlObj);
|
||||
const url = npmurl.format(urlObj);
|
||||
|
||||
loadJSON(url, [], cb)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use 'sass:color';
|
||||
// MAP
|
||||
.maputnik-map__container {
|
||||
background: white;
|
||||
@@ -110,12 +111,12 @@
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($color-midgray, 12);
|
||||
background-color: color.adjust($color-midgray, $lightness: 12%);
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: darken($color-midgray, 5);
|
||||
background-color: color.adjust($color-midgray, $lightness: -5%);
|
||||
color: $color-midgray;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
.maputnik-filter-editor {
|
||||
@extend .clearfix;
|
||||
@extend .clearfix; /* stylelint-disable-line */
|
||||
color: $color-lowgray;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
}
|
||||
|
||||
.maputnik-delete-filter {
|
||||
@extend .maputnik-icon-button;
|
||||
@extend .maputnik-icon-button; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-filter-editor-block-action {
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
|
||||
.maputnik-radio-as-button {
|
||||
@extend .maputnik-button;
|
||||
@extend .maputnik-button; /* stylelint-disable-line */
|
||||
|
||||
border: solid 1px transparent;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use 'sass:color';
|
||||
//INPUT
|
||||
.maputnik-input {
|
||||
height: 24px;
|
||||
@@ -10,7 +11,7 @@
|
||||
padding-right: $margin-2;
|
||||
border: none;
|
||||
background-color: $color-gray;
|
||||
color: lighten($color-lowgray, 12);
|
||||
color: color.adjust($color-lowgray, $lightness: 12%);
|
||||
|
||||
&:invalid {
|
||||
border: solid 1px #B71C1C;
|
||||
@@ -19,7 +20,7 @@
|
||||
}
|
||||
|
||||
.maputnik-string {
|
||||
@extend .maputnik-input;
|
||||
@extend .maputnik-input; /* stylelint-disable-line */
|
||||
|
||||
&--multi {
|
||||
resize: vertical;
|
||||
@@ -43,12 +44,12 @@
|
||||
}
|
||||
|
||||
.maputnik-number {
|
||||
@extend .maputnik-input;
|
||||
@extend .maputnik-input; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
//COLOR PICKER
|
||||
.maputnik-color {
|
||||
@extend .maputnik-input;
|
||||
@extend .maputnik-input; /* stylelint-disable-line */
|
||||
|
||||
height: 26px;
|
||||
}
|
||||
@@ -95,7 +96,7 @@
|
||||
|
||||
// SELECT
|
||||
.maputnik-select {
|
||||
@extend .maputnik-input;
|
||||
@extend .maputnik-input; /* stylelint-disable-line */
|
||||
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
@@ -117,7 +118,7 @@
|
||||
}
|
||||
|
||||
.maputnik-button-selected {
|
||||
background-color: lighten($color-midgray, 12);
|
||||
background-color: color.adjust($color-midgray, $lightness: 12%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@
|
||||
outline: none;
|
||||
|
||||
&-wrapper {
|
||||
@extend .maputnik-input;
|
||||
@extend .maputnik-input; /* stylelint-disable-line */
|
||||
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
+14
-13
@@ -1,3 +1,4 @@
|
||||
@use 'sass:color';
|
||||
// LAYER LIST
|
||||
.maputnik-layer-list {
|
||||
height: 100%;
|
||||
@@ -48,7 +49,7 @@
|
||||
font-weight: 400;
|
||||
color: $color-lowgray;
|
||||
font-size: $font-size-6;
|
||||
border-bottom-color: lighten($color-black, 0.1);
|
||||
border-bottom-color: color.adjust($color-black, $lightness: 0.1%);
|
||||
user-select: none;
|
||||
list-style: none;
|
||||
z-index: 2000;
|
||||
@@ -87,7 +88,7 @@
|
||||
height: 15px;
|
||||
|
||||
svg {
|
||||
fill: darken($color-lowgray, 20);
|
||||
fill: color.adjust($color-lowgray, $lightness: -20%);
|
||||
|
||||
&:hover {
|
||||
fill: $color-white;
|
||||
@@ -101,13 +102,13 @@
|
||||
|
||||
.maputnik-layer-list-item:hover,
|
||||
.maputnik-layer-list-item-selected {
|
||||
background-color: lighten($color-black, 2);
|
||||
background-color: color.adjust($color-black, $lightness: 2%);
|
||||
|
||||
.maputnik-layer-list-icon-action {
|
||||
display: block;
|
||||
|
||||
svg {
|
||||
fill: darken($color-lowgray, 0.5);
|
||||
fill: color.adjust($color-lowgray, $lightness: -0.5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +152,7 @@
|
||||
border: solid 1px transparent;
|
||||
font-size: $font-size-6;
|
||||
color: $color-lowgray;
|
||||
background-color: lighten($color-black, 2);
|
||||
background-color: color.adjust($color-black, $lightness: 2%);
|
||||
user-select: none;
|
||||
padding: $margin-2;
|
||||
|
||||
@@ -185,7 +186,7 @@
|
||||
.maputnik-layer-editor-group {
|
||||
font-weight: bold;
|
||||
font-size: $font-size-5;
|
||||
background-color: lighten($color-black, 2);
|
||||
background-color: color.adjust($color-black, $lightness: 2%);
|
||||
color: $color-white;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
@@ -232,7 +233,7 @@
|
||||
// PROPERTY
|
||||
.maputnik-default-property {
|
||||
.maputnik-input-block-label {
|
||||
color: darken($color-lowgray, 20%);
|
||||
color: color.adjust($color-lowgray, $lightness: -20%);
|
||||
}
|
||||
|
||||
.maputnik-string,
|
||||
@@ -240,8 +241,8 @@
|
||||
.maputnik-color,
|
||||
.maputnik-select,
|
||||
.maputnik-checkbox-wrapper {
|
||||
background-color: darken($color-gray, 2%);
|
||||
color: darken($color-lowgray, 20%);
|
||||
background-color: color.adjust($color-gray, $lightness: -2%);
|
||||
color: color.adjust($color-lowgray, $lightness: -20%);
|
||||
}
|
||||
|
||||
.maputnik-make-zoom-function svg {
|
||||
@@ -249,17 +250,17 @@
|
||||
}
|
||||
|
||||
.maputnik-multibutton .maputnik-button {
|
||||
background-color: darken($color-midgray, 10%);
|
||||
color: darken($color-lowgray, 20%);
|
||||
background-color: color.adjust($color-midgray, $lightness: -10%);
|
||||
color: color.adjust($color-lowgray, $lightness: -20%);
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($color-midgray, 12);
|
||||
background-color: color.adjust($color-midgray, $lightness: 12%);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.maputnik-multibutton .maputnik-button-selected {
|
||||
background-color: darken($color-midgray, 2%);
|
||||
background-color: color.adjust($color-midgray, $lightness: -2%);
|
||||
color: $color-lowgray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,12 +72,12 @@
|
||||
}
|
||||
|
||||
.maputnik-modal-header-space {
|
||||
@extend .maputnik-space;
|
||||
@extend .maputnik-space; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
//OPEN MODAL
|
||||
.maputnik-upload-button {
|
||||
@extend .maputnik-big-button;
|
||||
@extend .maputnik-big-button; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-style-gallery-container {
|
||||
@@ -139,12 +139,12 @@
|
||||
}
|
||||
|
||||
.maputnik-add-layer {
|
||||
@extend .clearfix;
|
||||
@extend .clearfix; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
//ADD MODAL
|
||||
.maputnik-add-layer-button {
|
||||
@extend .maputnik-big-button;
|
||||
@extend .maputnik-big-button; /* stylelint-disable-line */
|
||||
|
||||
margin-right: $margin-3;
|
||||
float: right;
|
||||
@@ -221,7 +221,7 @@
|
||||
}
|
||||
|
||||
.maputnik-add-source {
|
||||
@extend .clearfix;
|
||||
@extend .clearfix; /* stylelint-disable-line */
|
||||
|
||||
.maputnik-input-block-label {
|
||||
width: 30%;
|
||||
@@ -233,7 +233,7 @@
|
||||
}
|
||||
|
||||
.maputnik-add-source-button {
|
||||
@extend .maputnik-big-button;
|
||||
@extend .maputnik-big-button; /* stylelint-disable-line */
|
||||
|
||||
display: inline-block;
|
||||
margin-top: 0;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use 'sass:color';
|
||||
// TOOLBAR
|
||||
.maputnik-toolbar {
|
||||
position: fixed;
|
||||
@@ -75,7 +76,7 @@
|
||||
}
|
||||
|
||||
&:hover .maputnik-toolbar-link-wrapper {
|
||||
background-color: lighten($color-midgray, 12);
|
||||
background-color: color.adjust($color-midgray, $lightness: 12%);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
@@ -93,13 +94,13 @@
|
||||
.maputnik-toolbar-action {
|
||||
background: inherit;
|
||||
border-width: 0;
|
||||
@extend .maputnik-toolbar-link;
|
||||
@extend .maputnik-toolbar-link; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-toolbar-select {
|
||||
background: inherit;
|
||||
border-width: 0;
|
||||
@extend .maputnik-toolbar-link;
|
||||
@extend .maputnik-toolbar-link; /* stylelint-disable-line */
|
||||
|
||||
select {
|
||||
margin-left: 6px;
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
vertical-align: middle;
|
||||
padding: 0 $margin-2 0 0;
|
||||
|
||||
@extend .maputnik-icon-button;
|
||||
@extend .maputnik-icon-button; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
// ZOOM PROPERTY
|
||||
.maputnik-zoom-spec-property {
|
||||
@extend .clearfix;
|
||||
@extend .clearfix; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-zoom-spec-property-label {
|
||||
@@ -49,7 +49,7 @@
|
||||
padding-top: 0;
|
||||
vertical-align: middle;
|
||||
|
||||
@extend .maputnik-icon-button;
|
||||
@extend .maputnik-icon-button; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-add-stop {
|
||||
@@ -65,7 +65,7 @@
|
||||
vertical-align: middle;
|
||||
padding: 0 $margin-2 0 0;
|
||||
|
||||
@extend .maputnik-icon-button;
|
||||
@extend .maputnik-icon-button; /* stylelint-disable-line */
|
||||
}
|
||||
|
||||
.maputnik-data-spec-property {
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.maputnik-data-spec-property {
|
||||
}
|
||||
|
||||
.maputnik-data-fieldset-inner {
|
||||
background: $color-black;
|
||||
border: solid 1px $color-midgray;
|
||||
|
||||
@@ -55,7 +55,9 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
|
||||
try {
|
||||
parser.parse(text);
|
||||
}
|
||||
catch (e) {}
|
||||
catch (e) {
|
||||
// ignore errors
|
||||
}
|
||||
|
||||
if (found.length > 0) {
|
||||
// JSON invalid so don't go any further
|
||||
@@ -154,7 +156,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
|
||||
found.push(err);
|
||||
}
|
||||
else if (key) {
|
||||
const path = key.replace(/^\[|\]$/g, "").split(/\.|[\[\]]+/).filter(Boolean)
|
||||
const path = key.replace(/^\[|\]$/g, "").split(/\.|[[\]]+/).filter(Boolean)
|
||||
const parsedError = getArrayPositionalFromAst(ast, path);
|
||||
if (!parsedError) {
|
||||
console.warn("Something went wrong parsing error:", error);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* If we don't have a default value just make one up
|
||||
*/
|
||||
export function findDefaultFromSpec(spec: { type: 'string' | 'color' | 'boolean' | 'array', default?: any }) {
|
||||
if (spec.hasOwnProperty('default')) {
|
||||
if (Object.prototype.hasOwnProperty.call(spec, 'default')) {
|
||||
return spec.default;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"types": ["geojson"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user