Tidy of components

- Moved all components into a single directory like nextjs
 - Made component names consistent with each other
 - Made component names consistent with their export class names
 - Added storybook for a few components with the aim to extend this further.
This commit is contained in:
orangemug
2020-06-01 16:09:32 +01:00
parent d07b40ccef
commit 624ccb5b00
88 changed files with 5167 additions and 513 deletions

View File

@@ -7,21 +7,21 @@ import {unset} from 'lodash'
import arrayMove from 'array-move'
import url from 'url'
import MapboxGlMap from './map/MapboxGlMap'
import OpenLayersMap from './map/OpenLayersMap'
import LayerList from './layers/LayerList'
import LayerEditor from './layers/LayerEditor'
import Toolbar from './Toolbar'
import MapMapboxGl from './MapMapboxGl'
import MapOpenLayers from './MapOpenLayers'
import LayerList from './LayerList'
import LayerEditor from './LayerEditor'
import AppToolbar from './AppToolbar'
import AppLayout from './AppLayout'
import MessagePanel from './MessagePanel'
import MessagePanel from './AppMessagePanel'
import SettingsModal from './modals/SettingsModal'
import ExportModal from './modals/ExportModal'
import SourcesModal from './modals/SourcesModal'
import OpenModal from './modals/OpenModal'
import ShortcutsModal from './modals/ShortcutsModal'
import SurveyModal from './modals/SurveyModal'
import DebugModal from './modals/DebugModal'
import ModalSettings from './ModalSettings'
import ModalExport from './ModalExport'
import ModalSources from './ModalSources'
import ModalOpen from './ModalOpen'
import ModalShortcuts from './ModalShortcuts'
import ModalSurvey from './ModalSurvey'
import ModalDebug from './ModalDebug'
import { downloadGlyphsMetadata, downloadSpriteMetadata } from '../libs/metadata'
import {latest, validate} from '@mapbox/mapbox-gl-style-spec'
@@ -36,7 +36,7 @@ import tokens from '../config/tokens.json'
import isEqual from 'lodash.isequal'
import Debug from '../libs/debug'
import queryUtil from '../libs/query-util'
import {formatLayerId} from './util/format';
import {formatLayerId} from '../util/format';
import MapboxGl from 'mapbox-gl'
@@ -668,14 +668,14 @@ export default class App extends React.Component {
// Check if OL code has been loaded?
if(renderer === 'ol') {
mapElement = <OpenLayersMap
mapElement = <MapOpenLayers
{...mapProps}
onChange={this.onMapChange}
debugToolbox={this.state.openlayersDebugOptions.debugToolbox}
onLayerSelect={this.onLayerSelect}
/>
} else {
mapElement = <MapboxGlMap {...mapProps}
mapElement = <MapMapboxGl {...mapProps}
onChange={this.onMapChange}
options={this.state.mapboxGlDebugOptions}
inspectModeEnabled={this.state.mapState === "inspect"}
@@ -741,7 +741,7 @@ export default class App extends React.Component {
const selectedLayer = layers.length > 0 ? layers[this.state.selectedLayerIndex] : null
const metadata = this.state.mapStyle.metadata || {}
const toolbar = <Toolbar
const toolbar = <AppToolbar
renderer={this._getRenderer()}
mapState={this.state.mapState}
mapStyle={this.state.mapStyle}
@@ -795,7 +795,7 @@ export default class App extends React.Component {
const modals = <div>
<DebugModal
<ModalDebug
renderer={this._getRenderer()}
mapboxGlDebugOptions={this.state.mapboxGlDebugOptions}
openlayersDebugOptions={this.state.openlayersDebugOptions}
@@ -805,12 +805,12 @@ export default class App extends React.Component {
onOpenToggle={this.toggleModal.bind(this, 'debug')}
mapView={this.state.mapView}
/>
<ShortcutsModal
<ModalShortcuts
ref={(el) => this.shortcutEl = el}
isOpen={this.state.isOpen.shortcuts}
onOpenToggle={this.toggleModal.bind(this, 'shortcuts')}
/>
<SettingsModal
<ModalSettings
mapStyle={this.state.mapStyle}
onStyleChanged={this.onStyleChanged}
onChangeMetadataProperty={this.onChangeMetadataProperty}
@@ -818,24 +818,24 @@ export default class App extends React.Component {
onOpenToggle={this.toggleModal.bind(this, 'settings')}
openlayersDebugOptions={this.state.openlayersDebugOptions}
/>
<ExportModal
<ModalExport
mapStyle={this.state.mapStyle}
onStyleChanged={this.onStyleChanged}
isOpen={this.state.isOpen.export}
onOpenToggle={this.toggleModal.bind(this, 'export')}
/>
<OpenModal
<ModalOpen
isOpen={this.state.isOpen.open}
onStyleOpen={this.openStyle}
onOpenToggle={this.toggleModal.bind(this, 'open')}
/>
<SourcesModal
<ModalSources
mapStyle={this.state.mapStyle}
onStyleChanged={this.onStyleChanged}
isOpen={this.state.isOpen.sources}
onOpenToggle={this.toggleModal.bind(this, 'sources')}
/>
<SurveyModal
<ModalSurvey
isOpen={this.state.isOpen.survey}
onOpenToggle={this.toggleModal.bind(this, 'survey')}
/>

View File

@@ -1,8 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
import {formatLayerId} from './util/format';
import {formatLayerId} from '../util/format';
class MessagePanel extends React.Component {
export default class AppMessagePanel extends React.Component {
static propTypes = {
errors: PropTypes.array,
infos: PropTypes.array,
@@ -60,5 +60,3 @@ class MessagePanel extends React.Component {
}
}
export default MessagePanel

View File

@@ -101,7 +101,7 @@ class ToolbarAction extends React.Component {
}
}
export default class Toolbar extends React.Component {
export default class AppToolbar extends React.Component {
static propTypes = {
mapStyle: PropTypes.object.isRequired,
inspectModeEnabled: PropTypes.bool.isRequired,

View File

@@ -1,12 +1,12 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import DocLabel from '../fields/DocLabel'
import SpecDoc from './SpecDoc'
import FieldDocLabel from './FieldDocLabel'
import Doc from './Doc'
/** Wrap a component with a label */
class InputBlock extends React.Component {
export default class Block extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
label: PropTypes.oneOfType([
@@ -53,7 +53,7 @@ class InputBlock extends React.Component {
>
{this.props.fieldSpec &&
<div className="maputnik-input-block-label">
<DocLabel
<FieldDocLabel
label={this.props.label}
onToggleDoc={this.onToggleDoc}
fieldSpec={this.props.fieldSpec}
@@ -85,11 +85,10 @@ class InputBlock extends React.Component {
className="maputnik-doc-inline"
style={{display: this.state.showDoc ? '' : 'none'}}
>
<SpecDoc fieldSpec={this.props.fieldSpec} />
<Doc fieldSpec={this.props.fieldSpec} />
</div>
}
</div>
}
}
export default InputBlock

View File

@@ -1,10 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import Block from './Block'
import FieldString from './FieldString'
class MetadataBlock extends React.Component {
export default class BlockComment extends React.Component {
static propTypes = {
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
@@ -15,19 +15,18 @@ class MetadataBlock extends React.Component {
doc: "Comments for the current layer. This is non-standard and not in the spec."
};
return <InputBlock
return <Block
label={"Comments"}
fieldSpec={fieldSpec}
data-wd-key="layer-comment"
>
<StringInput
<FieldString
multi={true}
value={this.props.value}
onChange={this.props.onChange}
default="Comment..."
/>
</InputBlock>
</Block>
}
}
export default MetadataBlock

View File

@@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import Block from './Block'
import FieldString from './FieldString'
class LayerIdBlock extends React.Component {
export default class BlockId extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
wdKey: PropTypes.string.isRequired,
@@ -14,16 +14,15 @@ class LayerIdBlock extends React.Component {
}
render() {
return <InputBlock label={"ID"} fieldSpec={latest.layer.id}
return <Block label={"ID"} fieldSpec={latest.layer.id}
data-wd-key={this.props.wdKey}
error={this.props.error}
>
<StringInput
<FieldString
value={this.props.value}
onChange={this.props.onChange}
/>
</InputBlock>
</Block>
}
}
export default LayerIdBlock

View File

@@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import NumberInput from '../inputs/NumberInput'
import Block from './Block'
import FieldNumber from './FieldNumber'
class MaxZoomBlock extends React.Component {
export default class BlockMaxZoom extends React.Component {
static propTypes = {
value: PropTypes.number,
onChange: PropTypes.func.isRequired,
@@ -13,11 +13,11 @@ class MaxZoomBlock extends React.Component {
}
render() {
return <InputBlock label={"Max Zoom"} fieldSpec={latest.layer.maxzoom}
return <Block label={"Max Zoom"} fieldSpec={latest.layer.maxzoom}
error={this.props.error}
data-wd-key="max-zoom"
>
<NumberInput
<FieldNumber
allowRange={true}
value={this.props.value}
onChange={this.props.onChange}
@@ -25,8 +25,7 @@ class MaxZoomBlock extends React.Component {
max={latest.layer.maxzoom.maximum}
default={latest.layer.maxzoom.maximum}
/>
</InputBlock>
</Block>
}
}
export default MaxZoomBlock

View File

@@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import NumberInput from '../inputs/NumberInput'
import Block from './Block'
import FieldNumber from './FieldNumber'
class MinZoomBlock extends React.Component {
export default class BlockMinZoom extends React.Component {
static propTypes = {
value: PropTypes.number,
onChange: PropTypes.func.isRequired,
@@ -13,11 +13,11 @@ class MinZoomBlock extends React.Component {
}
render() {
return <InputBlock label={"Min Zoom"} fieldSpec={latest.layer.minzoom}
return <Block label={"Min Zoom"} fieldSpec={latest.layer.minzoom}
error={this.props.error}
data-wd-key="min-zoom"
>
<NumberInput
<FieldNumber
allowRange={true}
value={this.props.value}
onChange={this.props.onChange}
@@ -25,8 +25,7 @@ class MinZoomBlock extends React.Component {
max={latest.layer.minzoom.maximum}
default={latest.layer.minzoom.minimum}
/>
</InputBlock>
</Block>
}
}
export default MinZoomBlock

View File

@@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import AutocompleteInput from '../inputs/AutocompleteInput'
import Block from './Block'
import FieldAutocomplete from './FieldAutocomplete'
class LayerSourceBlock extends React.Component {
export default class BlockSource extends React.Component {
static propTypes = {
value: PropTypes.string,
wdKey: PropTypes.string,
@@ -20,19 +20,18 @@ class LayerSourceBlock extends React.Component {
}
render() {
return <InputBlock
return <Block
label={"Source"}
fieldSpec={latest.layer.source}
error={this.props.error}
data-wd-key={this.props.wdKey}
>
<AutocompleteInput
<FieldAutocomplete
value={this.props.value}
onChange={this.props.onChange}
options={this.props.sourceIds.map(src => [src, src])}
/>
</InputBlock>
</Block>
}
}
export default LayerSourceBlock

View File

@@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import AutocompleteInput from '../inputs/AutocompleteInput'
import Block from './Block'
import FieldAutocomplete from './FieldAutocomplete'
class LayerSourceLayer extends React.Component {
export default class BlockSourceLayer extends React.Component {
static propTypes = {
value: PropTypes.string,
onChange: PropTypes.func,
@@ -20,17 +20,16 @@ class LayerSourceLayer extends React.Component {
}
render() {
return <InputBlock label={"Source Layer"} fieldSpec={latest.layer['source-layer']}
return <Block label={"Source Layer"} fieldSpec={latest.layer['source-layer']}
data-wd-key="layer-source-layer"
>
<AutocompleteInput
<FieldAutocomplete
keepMenuWithinWindowBounds={!!this.props.isFixed}
value={this.props.value}
onChange={this.props.onChange}
options={this.props.sourceLayerIds.map(l => [l, l])}
/>
</InputBlock>
</Block>
}
}
export default LayerSourceLayer

View File

@@ -2,11 +2,11 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import SelectInput from '../inputs/SelectInput'
import StringInput from '../inputs/StringInput'
import Block from './Block'
import FieldSelect from './FieldSelect'
import FieldString from './FieldString'
class LayerTypeBlock extends React.Component {
export default class BlockType extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
wdKey: PropTypes.string,
@@ -20,18 +20,18 @@ class LayerTypeBlock extends React.Component {
}
render() {
return <InputBlock label={"Type"} fieldSpec={latest.layer.type}
return <Block label={"Type"} fieldSpec={latest.layer.type}
data-wd-key={this.props.wdKey}
error={this.props.error}
>
{this.props.disabled &&
<StringInput
<FieldString
value={this.props.value}
disabled={true}
/>
}
{!this.props.disabled &&
<SelectInput
<FieldSelect
options={[
['background', 'Background'],
['fill', 'Fill'],
@@ -47,8 +47,7 @@ class LayerTypeBlock extends React.Component {
value={this.props.value}
/>
}
</InputBlock>
</Block>
}
}
export default LayerTypeBlock

View File

@@ -1,10 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import Collapse from 'react-collapse'
import Collapse as ReactCollapse from 'react-collapse'
import accessibility from '../../libs/accessibility'
export default class CollapseAlt extends React.Component {
export default class Collapse extends React.Component {
static propTypes = {
isActive: PropTypes.bool.isRequired,
children: PropTypes.element.isRequired
@@ -24,9 +24,9 @@ export default class CollapseAlt extends React.Component {
}
else {
return (
<Collapse isOpened={this.props.isActive}>
<ReactCollapse isOpened={this.props.isActive}>
{this.props.children}
</Collapse>
</ReactCollapse>
)
}
}

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
export default class SpecDoc extends React.Component {
export default class Doc extends React.Component {
static propTypes = {
fieldSpec: PropTypes.object.isRequired,
}

View File

@@ -1,9 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import StringInput from './StringInput'
import NumberInput from './NumberInput'
import FieldString from './FieldString'
import FieldNumber from './FieldNumber'
class ArrayInput extends React.Component {
export default class FieldArray extends React.Component {
static propTypes = {
value: PropTypes.array,
type: PropTypes.string,
@@ -82,7 +82,7 @@ class ArrayInput extends React.Component {
const inputs = Array(this.props.length).fill(null).map((_, i) => {
if(this.props.type === 'number') {
return <NumberInput
return <FieldNumber
key={i}
default={containsValues ? undefined : this.props.default[i]}
value={value[i]}
@@ -90,7 +90,7 @@ class ArrayInput extends React.Component {
onChange={this.changeValue.bind(this, i)}
/>
} else {
return <StringInput
return <FieldString
key={i}
default={containsValues ? undefined : this.props.default[i]}
value={value[i]}
@@ -106,4 +106,3 @@ class ArrayInput extends React.Component {
}
}
export default ArrayInput

View File

@@ -6,7 +6,7 @@ import Autocomplete from 'react-autocomplete'
const MAX_HEIGHT = 140;
class AutocompleteInput extends React.Component {
export default class FieldAutocomplete extends React.Component {
static propTypes = {
value: PropTypes.string,
options: PropTypes.array,
@@ -95,4 +95,3 @@ class AutocompleteInput extends React.Component {
}
}
export default AutocompleteInput

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
class CheckboxInput extends React.Component {
export default class FieldCheckbox extends React.Component {
static propTypes = {
value: PropTypes.bool,
style: PropTypes.object,
@@ -32,4 +32,3 @@ class CheckboxInput extends React.Component {
}
}
export default CheckboxInput

View File

@@ -10,7 +10,7 @@ function formatColor(color) {
}
/*** Number fields with support for min, max and units and documentation*/
class ColorField extends React.Component {
export default class FieldColor extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
name: PropTypes.string,
@@ -130,4 +130,3 @@ class ColorField extends React.Component {
}
}
export default ColorField

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import {MdInfoOutline, MdHighlightOff} from 'react-icons/md'
export default class DocLabel extends React.Component {
export default class FieldDocLabel extends React.Component {
static propTypes = {
label: PropTypes.oneOfType([
PropTypes.object,

View File

@@ -1,16 +1,16 @@
import React from 'react'
import PropTypes from 'prop-types'
import StringInput from './StringInput'
import NumberInput from './NumberInput'
import Button from '../Button'
import FieldString from './FieldString'
import FieldNumber from './FieldNumber'
import Button from './Button'
import {MdDelete} from 'react-icons/md'
import DocLabel from '../fields/DocLabel'
import EnumInput from '../inputs/SelectInput'
import FieldDocLabel from './FieldDocLabel'
import FieldEnum from './FieldEnum'
import capitalize from 'lodash.capitalize'
import UrlInput from '../inputs/UrlInput'
import FieldUrl from './FieldUrl'
class DynamicArrayInput extends React.Component {
export default class FieldDynamicArray extends React.Component {
static propTypes = {
value: PropTypes.array,
type: PropTypes.string,
@@ -62,13 +62,13 @@ class DynamicArrayInput extends React.Component {
const deleteValueBtn= <DeleteValueButton onClick={this.deleteValue.bind(this, i)} />
let input;
if(this.props.type === 'url') {
input = <UrlInput
input = <FieldUrl
value={v}
onChange={this.changeValue.bind(this, i)}
/>
}
else if (this.props.type === 'number') {
input = <NumberInput
input = <FieldNumber
value={v}
onChange={this.changeValue.bind(this, i)}
/>
@@ -76,14 +76,14 @@ class DynamicArrayInput extends React.Component {
else if (this.props.type === 'enum') {
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)]);
input = <EnumInput
input = <FieldEnum
options={options}
value={v}
onChange={this.changeValue.bind(this, i)}
/>
}
else {
input = <StringInput
input = <FieldString
value={v}
onChange={this.changeValue.bind(this, i)}
/>
@@ -126,7 +126,7 @@ class DeleteValueButton extends React.Component {
onClick={this.props.onClick}
title="Remove array item"
>
<DocLabel
<FieldDocLabel
label={<MdDelete />}
doc={"Remove array item."}
/>
@@ -134,4 +134,3 @@ class DeleteValueButton extends React.Component {
}
}
export default DynamicArrayInput

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import SelectInput from '../inputs/SelectInput'
import MultiButtonInput from '../inputs/MultiButtonInput'
import FieldSelect from './FieldSelect'
import FieldMultiInput from './FieldMultiInput'
function optionsLabelLength(options) {
@@ -13,7 +13,7 @@ function optionsLabelLength(options) {
}
class EnumInput extends React.Component {
export default class FieldEnum extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
@@ -28,14 +28,14 @@ class EnumInput extends React.Component {
const {options, value, onChange, name} = this.props;
if(options.length <= 3 && optionsLabelLength(options) <= 20) {
return <MultiButtonInput
return <FieldMultiInput
name={name}
options={options}
value={value || this.props.default}
onChange={onChange}
/>
} else {
return <SelectInput
return <FieldSelect
options={options}
value={value || this.props.default}
onChange={onChange}
@@ -43,5 +43,3 @@ class EnumInput extends React.Component {
}
}
}
export default EnumInput

View File

@@ -1,8 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
import AutocompleteInput from './AutocompleteInput'
import FieldAutocomplete from './FieldAutocomplete'
class FontInput extends React.Component {
export default class FieldFont extends React.Component {
static propTypes = {
value: PropTypes.array,
default: PropTypes.array,
@@ -39,7 +39,7 @@ class FontInput extends React.Component {
render() {
const inputs = this.values.map((value, i) => {
return <AutocompleteInput
return <FieldAutocomplete
key={i}
value={value}
options={this.props.fonts.map(f => [f, f])}
@@ -53,4 +53,3 @@ class FontInput extends React.Component {
}
}
export default FontInput

View File

@@ -106,7 +106,7 @@ function getDataType (value, fieldSpec={}) {
/** Supports displaying spec field for zoom function objects
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
*/
export default class FunctionSpecProperty extends React.Component {
export default class FieldFunction extends React.Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
fieldName: PropTypes.string.isRequired,

View File

@@ -2,8 +2,8 @@ import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames';
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import Block from './Block'
import FieldString from './FieldString'
import CodeMirror from 'codemirror';
import 'codemirror/mode/javascript/javascript'
@@ -16,7 +16,7 @@ import stringifyPretty from 'json-stringify-pretty-compact'
import '../util/codemirror-mgl';
class JSONEditor extends React.Component {
export default class FieldJsonEditor extends React.Component {
static propTypes = {
layer: PropTypes.any.isRequired,
maxHeight: PropTypes.number,
@@ -173,4 +173,3 @@ class JSONEditor extends React.Component {
}
}
export default JSONEditor

View File

@@ -1,9 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Button from '../Button'
import Button from './Button'
class MultiButtonInput extends React.Component {
export default class FieldMultiInput extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
@@ -39,4 +39,3 @@ class MultiButtonInput extends React.Component {
}
}
export default MultiButtonInput

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
let IDX = 0;
class NumberInput extends React.Component {
export default class FieldNumber extends React.Component {
static propTypes = {
value: PropTypes.number,
default: PropTypes.number,
@@ -230,4 +230,3 @@ class NumberInput extends React.Component {
}
}
export default NumberInput

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
class SelectInput extends React.Component {
export default class FieldSelect extends React.Component {
static propTypes = {
value: PropTypes.string.isRequired,
"data-wd-key": PropTypes.string,
@@ -31,4 +31,3 @@ class SelectInput extends React.Component {
}
}
export default SelectInput

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
class StringInput extends React.Component {
export default class FieldString extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
@@ -90,4 +90,3 @@ class StringInput extends React.Component {
}
}
export default StringInput

View File

@@ -1,9 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import AutocompleteInput from './AutocompleteInput'
import FieldAutocomplete from './FieldAutocomplete'
class IconInput extends React.Component {
export default class FieldSymbol extends React.Component {
static propTypes = {
value: PropTypes.string,
icons: PropTypes.array,
@@ -16,7 +16,7 @@ class IconInput extends React.Component {
}
render() {
return <AutocompleteInput
return <FieldAutocomplete
value={this.props.value}
options={this.props.icons.map(f => [f, f])}
onChange={this.props.onChange}
@@ -25,4 +25,3 @@ class IconInput extends React.Component {
}
}
export default IconInput

View File

@@ -1,7 +1,7 @@
import React, {Fragment} from 'react'
import PropTypes from 'prop-types'
import StringInput from './StringInput'
import SmallError from '../util/SmallError'
import FieldString from './FieldString'
import SmallError from './SmallError'
function validate (url) {
@@ -48,7 +48,7 @@ function validate (url) {
return error;
}
class UrlInput extends React.Component {
export default class FieldUrl extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
value: PropTypes.string,
@@ -88,7 +88,7 @@ class UrlInput extends React.Component {
render () {
return (
<div>
<StringInput
<FieldString
{...this.props}
onInput={this.onInput}
onChange={this.onChange}
@@ -99,4 +99,3 @@ class UrlInput extends React.Component {
}
}
export default UrlInput

View File

@@ -1,17 +1,16 @@
import React from 'react'
import PropTypes from 'prop-types'
import { combiningFilterOps } from '../../libs/filterops.js'
import { combiningFilterOps } from '../libs/filterops.js'
import {mdiTableRowPlusAfter} from '@mdi/js';
import {latest, validate, migrate} from '@mapbox/mapbox-gl-style-spec'
import DocLabel from '../fields/DocLabel'
import SelectInput from '../inputs/SelectInput'
import InputBlock from '../inputs/InputBlock'
import FieldSelect from './FieldSelect'
import Block from './Block'
import SingleFilterEditor from './SingleFilterEditor'
import FilterEditorBlock from './FilterEditorBlock'
import Button from '../Button'
import SpecDoc from '../inputs/SpecDoc'
import ExpressionProperty from '../fields/_ExpressionProperty';
import Button from './Button'
import Doc from './Doc'
import ExpressionProperty from './_ExpressionProperty';
import {mdiFunctionVariant} from '@mdi/js';
@@ -94,7 +93,7 @@ function hasNestedCombiningFilter(filter) {
return false
}
export default class CombiningFilterEditor extends React.Component {
export default class FilterEditor extends React.Component {
static propTypes = {
/** Properties of the vector layer and the available fields */
properties: PropTypes.object,
@@ -244,18 +243,18 @@ export default class CombiningFilterEditor extends React.Component {
return (
<>
<InputBlock
<Block
key="top"
fieldSpec={fieldSpec}
label={"Filter"}
action={actions}
>
<SelectInput
<FieldSelect
value={combiningOp}
onChange={this.onFilterPartChanged.bind(this, 0)}
options={[["all", "every filter matches"], ["none", "no filter matches"], ["any", "any filter matches"]]}
/>
</InputBlock>
</Block>
{editorBlocks}
<div
key="buttons"
@@ -276,7 +275,7 @@ export default class CombiningFilterEditor extends React.Component {
className="maputnik-doc-inline"
style={{display: this.state.showDoc ? '' : 'none'}}
>
<SpecDoc fieldSpec={fieldSpec} />
<Doc fieldSpec={fieldSpec} />
</div>
</>
);

View File

@@ -1,9 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import {MdDelete} from 'react-icons/md'
class FilterEditorBlock extends React.Component {
export default class FilterEditorBlock extends React.Component {
static propTypes = {
onDelete: PropTypes.func.isRequired,
children: PropTypes.element.isRequired,
@@ -27,4 +27,3 @@ class FilterEditorBlock extends React.Component {
}
}
export default FilterEditorBlock

View File

@@ -2,7 +2,7 @@ import React from 'react'
import IconBase from 'react-icon-base'
export default class BackgroundIcon extends React.Component {
export default class IconBackground extends React.Component {
render() {
return (
<IconBase viewBox="0 0 20 20" {...this.props}>

View File

@@ -2,7 +2,7 @@ import React from 'react'
import IconBase from 'react-icon-base'
export default class FillIcon extends React.Component {
export default class IconCircle extends React.Component {
render() {
return (
<IconBase viewBox="0 0 20 20" {...this.props}>

View File

@@ -2,7 +2,7 @@ import React from 'react'
import IconBase from 'react-icon-base'
export default class FillIcon extends React.Component {
export default class IconFill extends React.Component {
render() {
return (
<IconBase viewBox="0 0 20 20" {...this.props}>

View File

@@ -0,0 +1,33 @@
import React from 'react'
import PropTypes from 'prop-types'
import IconLine from './IconLine.jsx'
import IconFill from './IconFill.jsx'
import IconSymbol from './IconSymbol.jsx'
import IconBackground from './IconBackground.jsx'
import IconCircle from './IconCircle.jsx'
import IconMissing from './IconMissing.jsx'
export default class IconLayer extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
style: PropTypes.object,
}
render() {
const iconProps = { style: this.props.style }
switch(this.props.type) {
case 'fill-extrusion': return <IconBackground {...iconProps} />
case 'raster': return <IconFill {...iconProps} />
case 'hillshade': return <IconFill {...iconProps} />
case 'heatmap': return <IconFill {...iconProps} />
case 'fill': return <IconFill {...iconProps} />
case 'background': return <IconBackground {...iconProps} />
case 'line': return <IconLine {...iconProps} />
case 'symbol': return <IconSymbol {...iconProps} />
case 'circle': return <IconCircle {...iconProps} />
default: return <IconMissing {...iconProps} />
}
}
}

View File

@@ -2,7 +2,7 @@ import React from 'react'
import IconBase from 'react-icon-base'
export default class FillIcon extends React.Component {
export default class IconLine extends React.Component {
render() {
return (
<IconBase viewBox="0 0 20 20" {...this.props}>

View File

@@ -2,7 +2,7 @@ import React from 'react'
import {MdPriorityHigh} from 'react-icons/md'
export default class MissingIcon extends React.Component {
export default class IconMissing extends React.Component {
render() {
return (
<MdPriorityHigh {...this.props} />

View File

@@ -2,7 +2,7 @@ import React from 'react'
import IconBase from 'react-icon-base'
export default class SymbolIcon extends React.Component {
export default class IconSymbol extends React.Component {
render() {
return (
<IconBase viewBox="0 0 20 20" {...this.props}>

View File

@@ -2,23 +2,23 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Wrapper, Button, Menu, MenuItem } from 'react-aria-menubutton'
import JSONEditor from './JSONEditor'
import FilterEditor from '../filter/FilterEditor'
import PropertyGroup from '../fields/PropertyGroup'
import FieldJsonEditor from './FieldJsonEditor'
import FilterEditor from './FilterEditor'
import PropertyGroup from './PropertyGroup'
import LayerEditorGroup from './LayerEditorGroup'
import LayerTypeBlock from './LayerTypeBlock'
import LayerIdBlock from './LayerIdBlock'
import MinZoomBlock from './MinZoomBlock'
import MaxZoomBlock from './MaxZoomBlock'
import CommentBlock from './CommentBlock'
import LayerSourceBlock from './LayerSourceBlock'
import LayerSourceLayerBlock from './LayerSourceLayerBlock'
import BlockType from './BlockType'
import BlockId from './BlockId'
import BlockMinZoom from './BlockMinZoom'
import BlockMaxZoom from './BlockMaxZoom'
import BlockComment from './BlockComment'
import BlockSource from './BlockSource'
import BlockSourceLayer from './BlockSourceLayer'
import {Accordion} from 'react-accessible-accordion';
import {MdMoreVert} from 'react-icons/md'
import { changeType, changeProperty } from '../../libs/layer'
import layout from '../../config/layout.json'
import { changeType, changeProperty } from '../libs/layer'
import layout from '../config/layout.json'
import {formatLayerId} from '../util/format';
@@ -152,13 +152,13 @@ export default class LayerEditor extends React.Component {
switch(type) {
case 'layer': return <div>
<LayerIdBlock
<BlockId
value={this.props.layer.id}
wdKey="layer-editor.layer-id"
error={errorData.id}
onChange={newId => this.props.onLayerIdChange(this.props.layerIndex, this.props.layer.id, newId)}
/>
<LayerTypeBlock
<BlockType
disabled={true}
error={errorData.type}
value={this.props.layer.type}
@@ -167,7 +167,7 @@ export default class LayerEditor extends React.Component {
changeType(this.props.layer, newType)
)}
/>
{this.props.layer.type !== 'background' && <LayerSourceBlock
{this.props.layer.type !== 'background' && <BlockSource
error={errorData.source}
sourceIds={Object.keys(this.props.sources)}
value={this.props.layer.source}
@@ -175,24 +175,24 @@ export default class LayerEditor extends React.Component {
/>
}
{['background', 'raster', 'hillshade', 'heatmap'].indexOf(this.props.layer.type) < 0 &&
<LayerSourceLayerBlock
<BlockSourceLayer
error={errorData['source-layer']}
sourceLayerIds={sourceLayerIds}
value={this.props.layer['source-layer']}
onChange={v => this.changeProperty(null, 'source-layer', v)}
/>
}
<MinZoomBlock
<BlockMinZoom
error={errorData.minzoom}
value={this.props.layer.minzoom}
onChange={v => this.changeProperty(null, 'minzoom', v)}
/>
<MaxZoomBlock
<BlockMaxZoom
error={errorData.maxzoom}
value={this.props.layer.maxzoom}
onChange={v => this.changeProperty(null, 'maxzoom', v)}
/>
<CommentBlock
<BlockComment
error={errorData.comment}
value={comment}
onChange={v => this.changeProperty('metadata', 'maputnik:comment', v == "" ? undefined : v)}
@@ -215,7 +215,7 @@ export default class LayerEditor extends React.Component {
spec={this.props.spec}
onChange={this.changeProperty.bind(this)}
/>
case 'jsoneditor': return <JSONEditor
case 'jsoneditor': return <FieldJsonEditor
layer={this.props.layer}
onChange={(layer) => {
this.props.onLayerChanged(

View File

@@ -5,7 +5,7 @@ import lodash from 'lodash';
import LayerListGroup from './LayerListGroup'
import LayerListItem from './LayerListItem'
import AddModal from '../modals/AddModal'
import ModalAdd from './ModalAdd'
import {SortableContainer} from 'react-sortable-hoc';
@@ -270,7 +270,7 @@ class LayerListContainer extends React.Component {
aria-label="Layers list"
ref={this.scrollContainerRef}
>
<AddModal
<ModalAdd
key={this.state.keys.add}
layers={this.props.layers}
sources={this.props.sources}

View File

@@ -4,13 +4,13 @@ import classnames from 'classnames'
import {MdContentCopy, MdVisibility, MdVisibilityOff, MdDelete} from 'react-icons/md'
import LayerIcon from '../icons/LayerIcon'
import IconLayer from './IconLayer'
import {SortableElement, SortableHandle} from 'react-sortable-hoc'
const DraggableLabel = SortableHandle((props) => {
return <div className="maputnik-layer-list-item-handle">
<LayerIcon
<IconLayer
className="layer-handle__icon"
type={props.layerType}
/>

View File

@@ -3,16 +3,16 @@ import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import MapboxGl from 'mapbox-gl'
import MapboxInspect from 'mapbox-gl-inspect'
import FeatureLayerPopup from './FeatureLayerPopup'
import FeaturePropertyPopup from './FeaturePropertyPopup'
import tokens from '../../config/tokens.json'
import MapMapboxGlLayerPopup from './MapMapboxGlLayerPopup'
import MapMapboxGlFeaturePropertyPopup from './MapMapboxGlFeaturePropertyPopup'
import tokens from '../config/tokens.json'
import colors from 'mapbox-gl-inspect/lib/colors'
import Color from 'color'
import ZoomControl from '../../libs/zoomcontrol'
import { colorHighlightedLayer } from '../../libs/highlight'
import ZoomControl from '../libs/zoomcontrol'
import { colorHighlightedLayer } from '../libs/highlight'
import 'mapbox-gl/dist/mapbox-gl.css'
import '../../mapboxgl.css'
import '../../libs/mapbox-rtl'
import '../mapboxgl.css'
import '../libs/mapbox-rtl'
const IS_SUPPORTED = MapboxGl.supported();
@@ -52,7 +52,7 @@ function buildInspectStyle(originalMapStyle, coloredLayers, highlightedLayer) {
return inspectStyle
}
export default class MapboxGlMap extends React.Component {
export default class MapMapboxGl extends React.Component {
static propTypes = {
onDataChange: PropTypes.func,
onLayerSelect: PropTypes.func.isRequired,
@@ -175,9 +175,9 @@ export default class MapboxGlMap extends React.Component {
buildInspectStyle: (originalMapStyle, coloredLayers) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer),
renderPopup: features => {
if(this.props.inspectModeEnabled) {
return renderPopup(<FeaturePropertyPopup features={features} />, tmpNode);
return renderPopup(<MapMapboxGlFeaturePropertyPopup features={features} />, tmpNode);
} else {
return renderPopup(<FeatureLayerPopup features={features} onLayerSelect={this.onLayerSelectById} zoom={this.state.zoom} />, tmpNode);
return renderPopup(<MapMapboxGlLayerPopup features={features} onLayerSelect={this.onLayerSelectById} zoom={this.state.zoom} />, tmpNode);
}
}
})

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import Block from './Block'
import FieldString from './FieldString'
function displayValue(value) {
if (typeof value === 'undefined' || value === null) return value;
@@ -15,24 +15,24 @@ function displayValue(value) {
function renderProperties(feature) {
return Object.keys(feature.properties).map(propertyName => {
const property = feature.properties[propertyName]
return <InputBlock key={propertyName} label={propertyName}>
<StringInput value={displayValue(property)} style={{backgroundColor: 'transparent'}}/>
</InputBlock>
return <Block key={propertyName} label={propertyName}>
<FieldString value={displayValue(property)} style={{backgroundColor: 'transparent'}}/>
</Block>
})
}
function renderFeatureId(feature) {
return <InputBlock key={"feature-id"} label={"feature_id"}>
<StringInput value={displayValue(feature.id)} style={{backgroundColor: 'transparent'}} />
</InputBlock>
return <Block key={"feature-id"} label={"feature_id"}>
<FieldString value={displayValue(feature.id)} style={{backgroundColor: 'transparent'}} />
</Block>
}
function renderFeature(feature, idx) {
return <div key={`${feature.sourceLayer}-${idx}`}>
<div className="maputnik-popup-layer-id">{feature.layer['source']}: {feature.layer['source-layer']}{feature.inspectModeCounter && <span> × {feature.inspectModeCounter}</span>}</div>
<InputBlock key={"property-type"} label={"$type"}>
<StringInput value={feature.geometry.type} style={{backgroundColor: 'transparent'}} />
</InputBlock>
<Block key={"property-type"} label={"$type"}>
<FieldString value={feature.geometry.type} style={{backgroundColor: 'transparent'}} />
</Block>
{renderFeatureId(feature)}
{renderProperties(feature)}
</div>

View File

@@ -1,6 +1,6 @@
import React from 'react'
import PropTypes from 'prop-types'
import LayerIcon from '../icons/LayerIcon'
import IconLayer from './IconLayer'
import {latest, expression, function as styleFunction} from '@mapbox/mapbox-gl-style-spec'
function groupFeaturesBySourceLayer(features) {
@@ -96,7 +96,7 @@ class FeatureLayerPopup extends React.Component {
}}
>
{feature.layer.type &&
<LayerIcon type={feature.layer.type} style={{
<IconLayer type={feature.layer.type} style={{
width: 14,
height: 14,
paddingRight: 3

View File

@@ -1,9 +1,9 @@
import React from 'react'
import {throttle} from 'lodash';
import PropTypes from 'prop-types'
import { loadJSON } from '../../libs/urlopen'
import { loadJSON } from '../libs/urlopen'
import FeatureLayerPopup from './FeatureLayerPopup';
import MapMapboxGlLayerPopup from './MapMapboxGlLayerPopup';
import 'ol/ol.css'
import {apply} from 'ol-mapbox-style';
@@ -24,7 +24,7 @@ function renderCoords (coords) {
}
}
export default class OpenLayersMap extends React.Component {
export default class MapOpenLayers extends React.Component {
static propTypes = {
onDataChange: PropTypes.func,
mapStyle: PropTypes.object.isRequired,
@@ -152,7 +152,7 @@ export default class OpenLayersMap extends React.Component {
>
×
</button>
<FeatureLayerPopup
<MapMapboxGlLayerPopup
features={this.state.selectedFeatures || []}
onLayerSelect={this.props.onLayerSelect}
/>

View File

@@ -5,7 +5,7 @@ import AriaModal from 'react-aria-modal'
import classnames from 'classnames';
class Modal extends React.Component {
export default class Modal extends React.Component {
static propTypes = {
"data-wd-key": PropTypes.string,
isOpen: PropTypes.bool.isRequired,
@@ -73,4 +73,3 @@ class Modal extends React.Component {
}
}
export default Modal

View File

@@ -1,15 +1,15 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import Modal from './Modal'
import LayerTypeBlock from '../layers/LayerTypeBlock'
import LayerIdBlock from '../layers/LayerIdBlock'
import LayerSourceBlock from '../layers/LayerSourceBlock'
import LayerSourceLayerBlock from '../layers/LayerSourceLayerBlock'
import BlockType from './BlockType'
import BlockId from './BlockId'
import BlockSource from './BlockSource'
import BlockSourceLayer from './BlockSourceLayer'
class AddModal extends React.Component {
export default class ModalAdd extends React.Component {
static propTypes = {
layers: PropTypes.array.isRequired,
onLayersChange: PropTypes.func.isRequired,
@@ -129,20 +129,20 @@ class AddModal extends React.Component {
className="maputnik-add-modal"
>
<div className="maputnik-add-layer">
<LayerIdBlock
<BlockId
value={this.state.id}
wdKey="add-layer.layer-id"
onChange={v => {
this.setState({ id: v })
}}
/>
<LayerTypeBlock
<BlockType
value={this.state.type}
wdKey="add-layer.layer-type"
onChange={v => this.setState({ type: v })}
/>
{this.state.type !== 'background' &&
<LayerSourceBlock
<BlockSource
sourceIds={sources}
wdKey="add-layer.layer-source-block"
value={this.state.source}
@@ -150,7 +150,7 @@ class AddModal extends React.Component {
/>
}
{['background', 'raster', 'hillshade', 'heatmap'].indexOf(this.state.type) < 0 &&
<LayerSourceLayerBlock
<BlockSourceLayer
isFixed={true}
sourceLayerIds={layers}
value={this.state['source-layer']}
@@ -169,4 +169,3 @@ class AddModal extends React.Component {
}
}
export default AddModal

View File

@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Modal from './Modal'
class DebugModal extends React.Component {
export default class ModalDebug extends React.Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
renderer: PropTypes.string.isRequired,
@@ -70,4 +70,3 @@ class DebugModal extends React.Component {
}
}
export default DebugModal;

View File

@@ -4,18 +4,18 @@ import Slugify from 'slugify'
import { saveAs } from 'file-saver'
import {format} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import CheckboxInput from '../inputs/CheckboxInput'
import Button from '../Button'
import Block from './Block'
import FieldString from './FieldString'
import FieldCheckbox from './FieldCheckbox'
import Button from './Button'
import Modal from './Modal'
import {MdFileDownload} from 'react-icons/md'
import style from '../../libs/style'
import fieldSpecAdditional from '../../libs/field-spec-additional'
import style from '../libs/style'
import fieldSpecAdditional from '../libs/field-spec-additional'
class ExportModal extends React.Component {
export default class ModalExport extends React.Component {
static propTypes = {
mapStyle: PropTypes.object.isRequired,
onStyleChanged: PropTypes.func.isRequired,
@@ -75,33 +75,33 @@ class ExportModal extends React.Component {
</p>
<div>
<InputBlock
<Block
label={fieldSpecAdditional.maputnik.mapbox_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.mapbox_access_token}
>
<StringInput
<FieldString
value={(this.props.mapStyle.metadata || {})['maputnik:mapbox_access_token']}
onChange={this.changeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
/>
</InputBlock>
<InputBlock
</Block>
<Block
label={fieldSpecAdditional.maputnik.maptiler_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
>
<StringInput
<FieldString
value={(this.props.mapStyle.metadata || {})['maputnik:openmaptiles_access_token']}
onChange={this.changeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
/>
</InputBlock>
<InputBlock
</Block>
<Block
label={fieldSpecAdditional.maputnik.thunderforest_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
>
<StringInput
<FieldString
value={(this.props.mapStyle.metadata || {})['maputnik:thunderforest_access_token']}
onChange={this.changeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
/>
</InputBlock>
</Block>
</div>
<Button
@@ -117,4 +117,3 @@ class ExportModal extends React.Component {
}
}
export default ExportModal

View File

@@ -1,11 +1,11 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import Modal from './Modal'
class LoadingModal extends React.Component {
export default class ModalLoading extends React.Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
onCancel: PropTypes.func.isRequired,
@@ -42,4 +42,3 @@ class LoadingModal extends React.Component {
}
}
export default LoadingModal

View File

@@ -1,16 +1,16 @@
import React from 'react'
import PropTypes from 'prop-types'
import LoadingModal from './LoadingModal'
import ModalLoading from './ModalLoading'
import Modal from './Modal'
import Button from '../Button'
import Button from './Button'
import FileReaderInput from 'react-file-reader-input'
import UrlInput from '../inputs/UrlInput'
import FieldUrl from './FieldUrl'
import {MdFileUpload} from 'react-icons/md'
import {MdAddCircleOutline} from 'react-icons/md'
import style from '../../libs/style.js'
import publicStyles from '../../config/styles.json'
import style from '../libs/style.js'
import publicStyles from '../config/styles.json'
class PublicStyle extends React.Component {
static propTypes = {
@@ -43,7 +43,7 @@ class PublicStyle extends React.Component {
}
}
class OpenModal extends React.Component {
export default class ModalOpen extends React.Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
onOpenToggle: PropTypes.func.isRequired,
@@ -211,7 +211,7 @@ class OpenModal extends React.Component {
Load from a URL. Note that the URL must have <a href="https://enable-cors.org" target="_blank" rel="noopener noreferrer">CORS enabled</a>.
</p>
<form onSubmit={this.onSubmitUrl}>
<UrlInput
<FieldUrl
data-wd-key="modal:open.url.input"
type="text"
className="maputnik-input"
@@ -242,7 +242,7 @@ class OpenModal extends React.Component {
</section>
</Modal>
<LoadingModal
<ModalLoading
isOpen={!!this.state.activeRequest}
title={'Loading style'}
onCancel={(e) => this.onCancelActiveRequest(e)}
@@ -253,4 +253,3 @@ class OpenModal extends React.Component {
}
}
export default OpenModal

View File

@@ -2,18 +2,18 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import ArrayInput from '../inputs/ArrayInput'
import NumberInput from '../inputs/NumberInput'
import StringInput from '../inputs/StringInput'
import UrlInput from '../inputs/UrlInput'
import SelectInput from '../inputs/SelectInput'
import EnumInput from '../inputs/EnumInput'
import ColorField from '../fields/ColorField'
import Block from './Block'
import FieldArray from './FieldArray'
import FieldNumber from './FieldNumber'
import FieldString from './FieldString'
import FieldUrl from './FieldUrl'
import FieldSelect from './FieldSelect'
import FieldEnum from './FieldEnum'
import FieldColor from './FieldColor'
import Modal from './Modal'
import fieldSpecAdditional from '../../libs/field-spec-additional'
import fieldSpecAdditional from '../libs/field-spec-additional'
class SettingsModal extends React.Component {
export default class ModalSettings extends React.Component {
static propTypes = {
mapStyle: PropTypes.object.isRequired,
onStyleChanged: PropTypes.func.isRequired,
@@ -87,108 +87,108 @@ class SettingsModal extends React.Component {
title={'Style Settings'}
>
<div className="modal:settings">
<InputBlock label={"Name"} fieldSpec={latest.$root.name}>
<StringInput {...inputProps}
<Block label={"Name"} fieldSpec={latest.$root.name}>
<FieldString {...inputProps}
data-wd-key="modal:settings.name"
value={this.props.mapStyle.name}
onChange={this.changeStyleProperty.bind(this, "name")}
/>
</InputBlock>
<InputBlock label={"Owner"} fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}>
<StringInput {...inputProps}
</Block>
<Block label={"Owner"} fieldSpec={{doc: "Owner ID of the style. Used by Mapbox or future style APIs."}}>
<FieldString {...inputProps}
data-wd-key="modal:settings.owner"
value={this.props.mapStyle.owner}
onChange={this.changeStyleProperty.bind(this, "owner")}
/>
</InputBlock>
<InputBlock label={"Sprite URL"} fieldSpec={latest.$root.sprite}>
<UrlInput {...inputProps}
</Block>
<Block label={"Sprite URL"} fieldSpec={latest.$root.sprite}>
<FieldUrl {...inputProps}
data-wd-key="modal:settings.sprite"
value={this.props.mapStyle.sprite}
onChange={this.changeStyleProperty.bind(this, "sprite")}
/>
</InputBlock>
</Block>
<InputBlock label={"Glyphs URL"} fieldSpec={latest.$root.glyphs}>
<UrlInput {...inputProps}
<Block label={"Glyphs URL"} fieldSpec={latest.$root.glyphs}>
<FieldUrl {...inputProps}
data-wd-key="modal:settings.glyphs"
value={this.props.mapStyle.glyphs}
onChange={this.changeStyleProperty.bind(this, "glyphs")}
/>
</InputBlock>
</Block>
<InputBlock
<Block
label={fieldSpecAdditional.maputnik.mapbox_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.mapbox_access_token}
>
<StringInput {...inputProps}
<FieldString {...inputProps}
data-wd-key="modal:settings.maputnik:mapbox_access_token"
value={metadata['maputnik:mapbox_access_token']}
onChange={onChangeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
/>
</InputBlock>
</Block>
<InputBlock
<Block
label={fieldSpecAdditional.maputnik.maptiler_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.maptiler_access_token}
>
<StringInput {...inputProps}
<FieldString {...inputProps}
data-wd-key="modal:settings.maputnik:openmaptiles_access_token"
value={metadata['maputnik:openmaptiles_access_token']}
onChange={onChangeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
/>
</InputBlock>
</Block>
<InputBlock
<Block
label={fieldSpecAdditional.maputnik.thunderforest_access_token.label}
fieldSpec={fieldSpecAdditional.maputnik.thunderforest_access_token}
>
<StringInput {...inputProps}
<FieldString {...inputProps}
data-wd-key="modal:settings.maputnik:thunderforest_access_token"
value={metadata['maputnik:thunderforest_access_token']}
onChange={onChangeMetadataProperty.bind(this, "maputnik:thunderforest_access_token")}
/>
</InputBlock>
</Block>
<InputBlock label={"Center"} fieldSpec={latest.$root.center}>
<ArrayInput
<Block label={"Center"} fieldSpec={latest.$root.center}>
<FieldArray
length={2}
type="number"
value={mapStyle.center}
default={latest.$root.center.default || [0, 0]}
onChange={this.changeStyleProperty.bind(this, "center")}
/>
</InputBlock>
</Block>
<InputBlock label={"Zoom"} fieldSpec={latest.$root.zoom}>
<NumberInput
<Block label={"Zoom"} fieldSpec={latest.$root.zoom}>
<FieldNumber
{...inputProps}
value={mapStyle.zoom}
default={latest.$root.zoom.default || 0}
onChange={this.changeStyleProperty.bind(this, "zoom")}
/>
</InputBlock>
</Block>
<InputBlock label={"Bearing"} fieldSpec={latest.$root.bearing}>
<NumberInput
<Block label={"Bearing"} fieldSpec={latest.$root.bearing}>
<FieldNumber
{...inputProps}
value={mapStyle.bearing}
default={latest.$root.bearing.default}
onChange={this.changeStyleProperty.bind(this, "bearing")}
/>
</InputBlock>
</Block>
<InputBlock label={"Pitch"} fieldSpec={latest.$root.pitch}>
<NumberInput
<Block label={"Pitch"} fieldSpec={latest.$root.pitch}>
<FieldNumber
{...inputProps}
value={mapStyle.pitch}
default={latest.$root.pitch.default}
onChange={this.changeStyleProperty.bind(this, "pitch")}
/>
</InputBlock>
</Block>
<InputBlock label={"Light anchor"} fieldSpec={latest.light.anchor}>
<EnumInput
<Block label={"Light anchor"} fieldSpec={latest.light.anchor}>
<FieldEnum
{...inputProps}
name="light-anchor"
value={light.anchor}
@@ -196,28 +196,28 @@ class SettingsModal extends React.Component {
default={latest.light.anchor.default}
onChange={this.changeLightProperty.bind(this, "anchor")}
/>
</InputBlock>
</Block>
<InputBlock label={"Light color"} fieldSpec={latest.light.color}>
<ColorField
<Block label={"Light color"} fieldSpec={latest.light.color}>
<FieldColor
{...inputProps}
value={light.color}
default={latest.light.color.default}
onChange={this.changeLightProperty.bind(this, "color")}
/>
</InputBlock>
</Block>
<InputBlock label={"Light intensity"} fieldSpec={latest.light.intensity}>
<NumberInput
<Block label={"Light intensity"} fieldSpec={latest.light.intensity}>
<FieldNumber
{...inputProps}
value={light.intensity}
default={latest.light.intensity.default}
onChange={this.changeLightProperty.bind(this, "intensity")}
/>
</InputBlock>
</Block>
<InputBlock label={"Light position"} fieldSpec={latest.light.position}>
<ArrayInput
<Block label={"Light position"} fieldSpec={latest.light.position}>
<FieldArray
{...inputProps}
type="number"
length={latest.light.position.length}
@@ -225,31 +225,31 @@ class SettingsModal extends React.Component {
default={latest.light.position.default}
onChange={this.changeLightProperty.bind(this, "position")}
/>
</InputBlock>
</Block>
<InputBlock label={"Transition delay"} fieldSpec={latest.transition.delay}>
<NumberInput
<Block label={"Transition delay"} fieldSpec={latest.transition.delay}>
<FieldNumber
{...inputProps}
value={transition.delay}
default={latest.transition.delay.default}
onChange={this.changeTransitionProperty.bind(this, "delay")}
/>
</InputBlock>
</Block>
<InputBlock label={"Transition duration"} fieldSpec={latest.transition.duration}>
<NumberInput
<Block label={"Transition duration"} fieldSpec={latest.transition.duration}>
<FieldNumber
{...inputProps}
value={transition.duration}
default={latest.transition.duration.default}
onChange={this.changeTransitionProperty.bind(this, "duration")}
/>
</InputBlock>
</Block>
<InputBlock
<Block
label={fieldSpecAdditional.maputnik.style_renderer.label}
fieldSpec={fieldSpecAdditional.maputnik.style_renderer}
>
<SelectInput {...inputProps}
<FieldSelect {...inputProps}
data-wd-key="modal:settings.maputnik:renderer"
options={[
['mbgljs', 'MapboxGL JS'],
@@ -258,7 +258,7 @@ class SettingsModal extends React.Component {
value={metadata['maputnik:renderer'] || 'mbgljs'}
onChange={onChangeMetadataProperty.bind(this, 'maputnik:renderer')}
/>
</InputBlock>
</Block>
@@ -267,4 +267,3 @@ class SettingsModal extends React.Component {
}
}
export default SettingsModal

View File

@@ -4,7 +4,7 @@ import PropTypes from 'prop-types'
import Modal from './Modal'
class ShortcutsModal extends React.Component {
export default class ModalShortcuts extends React.Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
onOpenToggle: PropTypes.func.isRequired,
@@ -130,4 +130,3 @@ class ShortcutsModal extends React.Component {
}
}
export default ShortcutsModal

View File

@@ -2,15 +2,15 @@ import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import Modal from './Modal'
import Button from '../Button'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import SourceTypeEditor from '../sources/SourceTypeEditor'
import Button from './Button'
import Block from './Block'
import FieldString from './FieldString'
import FieldSelect from './FieldSelect'
import ModalSourcesTypeEditor from './ModalSourcesTypeEditor'
import style from '../../libs/style'
import { deleteSource, addSource, changeSource } from '../../libs/source'
import publicSources from '../../config/tilesets.json'
import style from '../libs/style'
import { deleteSource, addSource, changeSource } from '../libs/source'
import publicSources from '../config/tilesets.json'
import {MdAddCircleOutline, MdDelete} from 'react-icons/md'
@@ -69,7 +69,7 @@ function editorMode(source) {
return null
}
class ActiveSourceTypeEditor extends React.Component {
class ActiveModalSourcesTypeEditor extends React.Component {
static propTypes = {
sourceId: PropTypes.string.isRequired,
source: PropTypes.object.isRequired,
@@ -92,7 +92,7 @@ class ActiveSourceTypeEditor extends React.Component {
</Button>
</div>
<div className="maputnik-active-source-type-editor-content">
<SourceTypeEditor
<ModalSourcesTypeEditor
onChange={this.props.onChange}
mode={editorMode(this.props.source)}
source={this.props.source}
@@ -207,14 +207,14 @@ class AddSource extends React.Component {
};
return <div className="maputnik-add-source">
<InputBlock label={"Source ID"} fieldSpec={{doc: "Unique ID that identifies the source and is used in the layer to reference the source."}}>
<StringInput
<Block label={"Source ID"} fieldSpec={{doc: "Unique ID that identifies the source and is used in the layer to reference the source."}}>
<FieldString
value={this.state.sourceId}
onChange={v => this.setState({ sourceId: v})}
/>
</InputBlock>
<InputBlock label={"Source Type"} fieldSpec={sourceTypeFieldSpec}>
<SelectInput
</Block>
<Block label={"Source Type"} fieldSpec={sourceTypeFieldSpec}>
<FieldSelect
options={[
['geojson_json', 'GeoJSON (JSON)'],
['geojson_url', 'GeoJSON (URL)'],
@@ -230,8 +230,8 @@ class AddSource extends React.Component {
onChange={mode => this.setState({mode: mode, source: this.defaultSource(mode)})}
value={this.state.mode}
/>
</InputBlock>
<SourceTypeEditor
</Block>
<ModalSourcesTypeEditor
onChange={this.onChangeSource}
mode={this.state.mode}
source={this.state.source}
@@ -246,7 +246,7 @@ class AddSource extends React.Component {
}
}
class SourcesModal extends React.Component {
export default class ModalSources extends React.Component {
static propTypes = {
mapStyle: PropTypes.object.isRequired,
isOpen: PropTypes.bool.isRequired,
@@ -264,7 +264,7 @@ class SourcesModal extends React.Component {
const mapStyle = this.props.mapStyle
const activeSources = Object.keys(mapStyle.sources).map(sourceId => {
const source = mapStyle.sources[sourceId]
return <ActiveSourceTypeEditor
return <ActiveModalSourcesTypeEditor
key={sourceId}
sourceId={sourceId}
source={source}
@@ -317,4 +317,3 @@ class SourcesModal extends React.Component {
}
}
export default SourcesModal

View File

@@ -1,14 +1,14 @@
import React from 'react'
import PropTypes from 'prop-types'
import {latest} from '@mapbox/mapbox-gl-style-spec'
import InputBlock from '../inputs/InputBlock'
import StringInput from '../inputs/StringInput'
import UrlInput from '../inputs/UrlInput'
import NumberInput from '../inputs/NumberInput'
import SelectInput from '../inputs/SelectInput'
import DynamicArrayInput from '../inputs/DynamicArrayInput'
import ArrayInput from '../inputs/ArrayInput'
import JSONEditor from '../layers/JSONEditor'
import Block from './Block'
import FieldString from './FieldString'
import FieldUrl from './FieldUrl'
import FieldNumber from './FieldNumber'
import FieldSelect from './FieldSelect'
import FieldDynamicArray from './FieldDynamicArray'
import FieldArray from './FieldArray'
import FieldJsonEditor from './FieldJsonEditor'
class TileJSONSourceEditor extends React.Component {
@@ -20,15 +20,15 @@ class TileJSONSourceEditor extends React.Component {
render() {
return <div>
<InputBlock label={"TileJSON URL"} fieldSpec={latest.source_vector.url}>
<UrlInput
<Block label={"TileJSON URL"} fieldSpec={latest.source_vector.url}>
<FieldUrl
value={this.props.source.url}
onChange={url => this.props.onChange({
...this.props.source,
url: url
})}
/>
</InputBlock>
</Block>
{this.props.children}
</div>
}
@@ -50,36 +50,36 @@ class TileURLSourceEditor extends React.Component {
renderTileUrls() {
const tiles = this.props.source.tiles || [];
return <InputBlock label={"Tile URL"} fieldSpec={latest.source_vector.tiles}>
<DynamicArrayInput
return <Block label={"Tile URL"} fieldSpec={latest.source_vector.tiles}>
<FieldDynamicArray
type="url"
value={tiles}
onChange={this.changeTileUrls.bind(this)}
/>
</InputBlock>
</Block>
}
render() {
return <div>
{this.renderTileUrls()}
<InputBlock label={"Min Zoom"} fieldSpec={latest.source_vector.minzoom}>
<NumberInput
<Block label={"Min Zoom"} fieldSpec={latest.source_vector.minzoom}>
<FieldNumber
value={this.props.source.minzoom || 0}
onChange={minzoom => this.props.onChange({
...this.props.source,
minzoom: minzoom
})}
/>
</InputBlock>
<InputBlock label={"Max Zoom"} fieldSpec={latest.source_vector.maxzoom}>
<NumberInput
</Block>
<Block label={"Max Zoom"} fieldSpec={latest.source_vector.maxzoom}>
<FieldNumber
value={this.props.source.maxzoom || 22}
onChange={maxzoom => this.props.onChange({
...this.props.source,
maxzoom: maxzoom
})}
/>
</InputBlock>
</Block>
{this.props.children}
</div>
@@ -104,26 +104,26 @@ class ImageSourceEditor extends React.Component {
}
return <div>
<InputBlock label={"Image URL"} fieldSpec={latest.source_image.url}>
<UrlInput
<Block label={"Image URL"} fieldSpec={latest.source_image.url}>
<FieldUrl
value={this.props.source.url}
onChange={url => this.props.onChange({
...this.props.source,
url,
})}
/>
</InputBlock>
</Block>
{["top left", "top right", "bottom right", "bottom left"].map((label, idx) => {
return (
<InputBlock label={`Coord ${label}`} key={label}>
<ArrayInput
<Block label={`Coord ${label}`} key={label}>
<FieldArray
length={2}
type="number"
value={this.props.source.coordinates[idx]}
default={[0, 0]}
onChange={(val) => changeCoord(idx, val)}
/>
</InputBlock>
</Block>
);
})}
</div>
@@ -155,25 +155,25 @@ class VideoSourceEditor extends React.Component {
}
return <div>
<InputBlock label={"Video URL"} fieldSpec={latest.source_video.urls}>
<DynamicArrayInput
<Block label={"Video URL"} fieldSpec={latest.source_video.urls}>
<FieldDynamicArray
type="string"
value={this.props.source.urls}
default={""}
onChange={changeUrls}
/>
</InputBlock>
</Block>
{["top left", "top right", "bottom right", "bottom left"].map((label, idx) => {
return (
<InputBlock label={`Coord ${label}`} key={label}>
<ArrayInput
<Block label={`Coord ${label}`} key={label}>
<FieldArray
length={2}
type="number"
value={this.props.source.coordinates[idx]}
default={[0, 0]}
onChange={val => changeCoord(idx, val)}
/>
</InputBlock>
</Block>
);
})}
</div>
@@ -187,27 +187,27 @@ class GeoJSONSourceUrlEditor extends React.Component {
}
render() {
return <InputBlock label={"GeoJSON URL"} fieldSpec={latest.source_geojson.data}>
<UrlInput
return <Block label={"GeoJSON URL"} fieldSpec={latest.source_geojson.data}>
<FieldUrl
value={this.props.source.data}
onChange={data => this.props.onChange({
...this.props.source,
data: data
})}
/>
</InputBlock>
</Block>
}
}
class GeoJSONSourceJSONEditor extends React.Component {
class GeoJSONSourceFieldJsonEditor extends React.Component {
static propTypes = {
source: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
}
render() {
return <InputBlock label={"GeoJSON"} fieldSpec={latest.source_geojson.data}>
<JSONEditor
return <Block label={"GeoJSON"} fieldSpec={latest.source_geojson.data}>
<FieldJsonEditor
layer={this.props.source.data}
maxHeight={200}
mode={{
@@ -222,11 +222,11 @@ class GeoJSONSourceJSONEditor extends React.Component {
})
}}
/>
</InputBlock>
</Block>
}
}
class SourceTypeEditor extends React.Component {
export default class ModalSourcesTypeEditor extends React.Component {
static propTypes = {
mode: PropTypes.string.isRequired,
source: PropTypes.object.isRequired,
@@ -240,15 +240,15 @@ class SourceTypeEditor extends React.Component {
}
switch(this.props.mode) {
case 'geojson_url': return <GeoJSONSourceUrlEditor {...commonProps} />
case 'geojson_json': return <GeoJSONSourceJSONEditor {...commonProps} />
case 'geojson_json': return <GeoJSONSourceFieldJsonEditor {...commonProps} />
case 'tilejson_vector': return <TileJSONSourceEditor {...commonProps} />
case 'tilexyz_vector': return <TileURLSourceEditor {...commonProps} />
case 'tilejson_raster': return <TileJSONSourceEditor {...commonProps} />
case 'tilexyz_raster': return <TileURLSourceEditor {...commonProps} />
case 'tilejson_raster-dem': return <TileJSONSourceEditor {...commonProps} />
case 'tilexyz_raster-dem': return <TileURLSourceEditor {...commonProps}>
<InputBlock label={"Encoding"} fieldSpec={latest.source_raster_dem.encoding}>
<SelectInput
<Block label={"Encoding"} fieldSpec={latest.source_raster_dem.encoding}>
<FieldSelect
options={Object.keys(latest.source_raster_dem.encoding.values)}
onChange={encoding => this.props.onChange({
...this.props.source,
@@ -256,7 +256,7 @@ class SourceTypeEditor extends React.Component {
})}
value={this.props.source.encoding || latest.source_raster_dem.encoding.default}
/>
</InputBlock>
</Block>
</TileURLSourceEditor>
case 'image': return <ImageSourceEditor {...commonProps} />
case 'video': return <VideoSourceEditor {...commonProps} />
@@ -265,4 +265,3 @@ class SourceTypeEditor extends React.Component {
}
}
export default SourceTypeEditor

View File

@@ -1,12 +1,12 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import Modal from './Modal'
import logoImage from 'maputnik-design/logos/logo-color.svg'
class SurveyModal extends React.Component {
export default class ModalSurvey extends React.Component {
static propTypes = {
isOpen: PropTypes.bool.isRequired,
onOpenToggle: PropTypes.func.isRequired,
@@ -36,4 +36,3 @@ class SurveyModal extends React.Component {
}
}
export default SurveyModal

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import FunctionSpecField from './FunctionSpecField'
import FieldFunction from './FieldFunction'
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
/** Extract field spec by {@fieldName} from the {@layerType} in the
@@ -58,7 +58,7 @@ export default class PropertyGroup extends React.Component {
const fieldValue = fieldName in paint ? paint[fieldName] : layout[fieldName]
const fieldType = fieldName in paint ? 'paint' : 'layout';
return <FunctionSpecField
return <FieldFunction
errors={errors}
onChange={this.onPropertyChange}
key={fieldName}

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
class ScrollContainer extends React.Component {
export default class ScrollContainer extends React.Component {
static propTypes = {
children: PropTypes.node
}
@@ -13,4 +13,3 @@ class ScrollContainer extends React.Component {
}
}
export default ScrollContainer

View File

@@ -1,10 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import { otherFilterOps } from '../../libs/filterops.js'
import StringInput from '../inputs/StringInput'
import AutocompleteInput from '../inputs/AutocompleteInput'
import SelectInput from '../inputs/SelectInput'
import { otherFilterOps } from '../libs/filterops.js'
import FieldString from './FieldString'
import FieldAutocomplete from './FieldAutocomplete'
import FieldSelect from './FieldSelect'
function tryParseInt(v) {
if (v === '') return v
@@ -35,7 +35,7 @@ function parseFilter(v) {
return v;
}
class SingleFilterEditor extends React.Component {
export default class SingleFilterEditor extends React.Component {
static propTypes = {
filter: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
@@ -64,14 +64,14 @@ class SingleFilterEditor extends React.Component {
return <div className="maputnik-filter-editor-single">
<div className="maputnik-filter-editor-property">
<AutocompleteInput
<FieldAutocomplete
value={propertyName}
options={Object.keys(this.props.properties).map(propName => [propName, propName])}
onChange={newPropertyName => this.onFilterPartChanged(filterOp, newPropertyName, filterArgs)}
/>
</div>
<div className="maputnik-filter-editor-operator">
<SelectInput
<FieldSelect
value={filterOp}
onChange={newFilterOp => this.onFilterPartChanged(newFilterOp, propertyName, filterArgs)}
options={otherFilterOps}
@@ -79,7 +79,7 @@ class SingleFilterEditor extends React.Component {
</div>
{filterArgs.length > 0 &&
<div className="maputnik-filter-editor-args">
<StringInput
<FieldString
value={filterArgs.join(',')}
onChange={ v=> this.onFilterPartChanged(filterOp, propertyName, v.split(','))}
/>
@@ -90,4 +90,3 @@ class SingleFilterEditor extends React.Component {
}
export default SingleFilterEditor

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import './SmallError.scss';
class SmallError extends React.Component {
export default class SmallError extends React.Component {
static propTypes = {
children: PropTypes.node,
}
@@ -17,4 +17,3 @@ class SmallError extends React.Component {
}
}
export default SmallError

View File

@@ -1,4 +1,4 @@
@import '../../styles/vars';
@import '../styles/vars';
.SmallError {
color: #E57373;

View File

@@ -1,17 +1,17 @@
import React from 'react'
import PropTypes from 'prop-types'
import ColorField from './ColorField'
import NumberInput from '../inputs/NumberInput'
import CheckboxInput from '../inputs/CheckboxInput'
import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import MultiButtonInput from '../inputs/MultiButtonInput'
import ArrayInput from '../inputs/ArrayInput'
import DynamicArrayInput from '../inputs/DynamicArrayInput'
import FontInput from '../inputs/FontInput'
import IconInput from '../inputs/IconInput'
import EnumInput from '../inputs/EnumInput'
import FieldColor from './FieldColor'
import FieldNumber from './FieldNumber'
import FieldCheckbox from './FieldCheckbox'
import FieldString from './FieldString'
import FieldSelect from './FieldSelect'
import FieldMultiInput from './FieldMultiInput'
import FieldArray from './FieldArray'
import FieldDynamicArray from './FieldDynamicArray'
import FieldFont from './FieldFont'
import FieldSymbol from './FieldSymbol'
import FieldEnum from './FieldEnum'
import capitalize from 'lodash.capitalize'
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
@@ -62,7 +62,7 @@ export default class SpecField extends React.Component {
function childNodes() {
switch(this.props.fieldSpec.type) {
case 'number': return (
<NumberInput
<FieldNumber
{...commonProps}
min={this.props.fieldSpec.minimum}
max={this.props.fieldSpec.maximum}
@@ -71,7 +71,7 @@ export default class SpecField extends React.Component {
case 'enum':
const options = Object.keys(this.props.fieldSpec.values).map(v => [v, capitalize(v)])
return <EnumInput
return <FieldEnum
{...commonProps}
options={options}
/>
@@ -79,40 +79,40 @@ export default class SpecField extends React.Component {
case 'formatted':
case 'string':
if(iconProperties.indexOf(this.props.fieldName) >= 0) {
return <IconInput
return <FieldSymbol
{...commonProps}
icons={this.props.fieldSpec.values}
/>
} else {
return <StringInput
return <FieldString
{...commonProps}
/>
}
case 'color': return (
<ColorField
<FieldColor
{...commonProps}
/>
)
case 'boolean': return (
<CheckboxInput
<FieldCheckbox
{...commonProps}
/>
)
case 'array':
if(this.props.fieldName === 'text-font') {
return <FontInput
return <FieldFont
{...commonProps}
fonts={this.props.fieldSpec.values}
/>
} else {
if (this.props.fieldSpec.length) {
return <ArrayInput
return <FieldArray
{...commonProps}
type={this.props.fieldSpec.value}
length={this.props.fieldSpec.length}
/>
} else {
return <DynamicArrayInput
return <FieldDynamicArray
{...commonProps}
fieldSpec={this.props.fieldSpec}
type={this.props.fieldSpec.value}

View File

@@ -2,15 +2,15 @@ import React from 'react'
import PropTypes from 'prop-types'
import {mdiFunctionVariant, mdiTableRowPlusAfter} from '@mdi/js';
import Button from '../Button'
import Button from './Button'
import SpecField from './SpecField'
import NumberInput from '../inputs/NumberInput'
import StringInput from '../inputs/StringInput'
import SelectInput from '../inputs/SelectInput'
import DocLabel from './DocLabel'
import InputBlock from '../inputs/InputBlock'
import docUid from '../../libs/document-uid'
import sortNumerically from '../../libs/sort-numerically'
import FieldNumber from './FieldNumber'
import FieldString from './FieldString'
import FieldSelect from './FieldSelect'
import Doc from './Doc'
import Block from './Block'
import docUid from '../libs/document-uid'
import sortNumerically from '../libs/sort-numerically'
import {findDefaultFromSpec} from '../util/spec-helper';
import labelFromFieldName from './_labelFromFieldName'
@@ -195,16 +195,16 @@ export default class DataProperty extends React.Component {
let dataInput;
if(this.props.value.type === "categorical") {
dataInput = <StringInput {...dataProps} />
dataInput = <FieldString {...dataProps} />
}
else {
dataInput = <NumberInput {...dataProps} />
dataInput = <FieldNumber {...dataProps} />
}
let zoomInput = null;
if(zoomLevel !== undefined) {
zoomInput = <div className="maputnik-data-spec-property-stop-edit">
<NumberInput
<FieldNumber
value={zoomLevel}
onChange={newZoom => this.changeStop(idx, {zoom: newZoom, value: dataLevel}, value)}
min={0}
@@ -223,7 +223,7 @@ export default class DataProperty extends React.Component {
}).join("");
const error = message ? {message} : undefined;
return <InputBlock
return <Block
error={error}
key={key}
action={deleteStopBtn}
@@ -241,22 +241,22 @@ export default class DataProperty extends React.Component {
onChange={(_, newValue) => this.changeStop(idx, {zoom: zoomLevel, value: dataLevel}, newValue)}
/>
</div>
</InputBlock>
</Block>
})
}
return <div className="maputnik-data-spec-block">
<div className="maputnik-data-spec-property">
<InputBlock
<Block
fieldSpec={this.props.fieldSpec}
label={labelFromFieldName(this.props.fieldName)}
>
<div className="maputnik-data-spec-property-group">
<DocLabel
<Doc
label="Type"
/>
<div className="maputnik-data-spec-property-input">
<SelectInput
<FieldSelect
value={this.props.value.type}
onChange={propVal => this.changeDataProperty("type", propVal)}
title={"Select a type of data scale (default is 'categorical')."}
@@ -265,11 +265,11 @@ export default class DataProperty extends React.Component {
</div>
</div>
<div className="maputnik-data-spec-property-group">
<DocLabel
<Doc
label="Property"
/>
<div className="maputnik-data-spec-property-input">
<StringInput
<FieldString
value={this.props.value.property}
title={"Input a data property to base styles off of."}
onChange={propVal => this.changeDataProperty("property", propVal)}
@@ -278,7 +278,7 @@ export default class DataProperty extends React.Component {
</div>
{dataFields &&
<div className="maputnik-data-spec-property-group">
<DocLabel
<Doc
label="Default"
/>
<div className="maputnik-data-spec-property-input">
@@ -291,7 +291,7 @@ export default class DataProperty extends React.Component {
</div>
</div>
}
</InputBlock>
</Block>
</div>
{dataFields &&
<>

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import {MdDelete} from 'react-icons/md'

View File

@@ -1,14 +1,14 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputBlock from '../inputs/InputBlock'
import Button from '../Button'
import Block from './Block'
import Button from './Button'
import {MdDelete, MdUndo} from 'react-icons/md'
import StringInput from '../inputs/StringInput'
import FieldString from './FieldString'
import labelFromFieldName from './_labelFromFieldName'
import stringifyPretty from 'json-stringify-pretty-compact'
import JSONEditor from '../layers/JSONEditor'
import FieldJsonEditor from './FieldJsonEditor'
export default class ExpressionProperty extends React.Component {
@@ -107,14 +107,14 @@ export default class ExpressionProperty extends React.Component {
}
}
return <InputBlock
return <Block
error={foundErrors}
fieldSpec={this.props.fieldSpec}
label={labelFromFieldName(this.props.fieldName)}
action={deleteStopBtn}
wideMode={true}
>
<JSONEditor
<FieldJsonEditor
mode={{name: "mgl"}}
lint={{
context: "expression",
@@ -132,6 +132,6 @@ export default class ExpressionProperty extends React.Component {
getValue={getValue}
onChange={this.props.onChange}
/>
</InputBlock>
</Block>
}
}

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '../Button'
import Button from './Button'
import {MdFunctions, MdInsertChart} from 'react-icons/md'
import {mdiFunctionVariant} from '@mdi/js';

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import SpecField from './SpecField'
import FunctionButtons from './_FunctionButtons'
import InputBlock from '../inputs/InputBlock'
import Block from './Block'
import labelFromFieldName from './_labelFromFieldName'
@@ -37,13 +37,13 @@ export default class SpecProperty extends React.Component {
const error = errors[fieldType+"."+fieldName];
return <InputBlock
return <Block
error={error}
fieldSpec={this.props.fieldSpec}
label={labelFromFieldName(this.props.fieldName)}
action={functionBtn}
>
<SpecField {...this.props} />
</InputBlock>
</Block>
}
}

View File

@@ -2,16 +2,16 @@ import React from 'react'
import PropTypes from 'prop-types'
import {mdiFunctionVariant, mdiTableRowPlusAfter} from '@mdi/js';
import Button from '../Button'
import Button from './Button'
import SpecField from './SpecField'
import NumberInput from '../inputs/NumberInput'
import InputBlock from '../inputs/InputBlock'
import FieldNumber from './FieldNumber'
import Block from './Block'
import DeleteStopButton from './_DeleteStopButton'
import labelFromFieldName from './_labelFromFieldName'
import docUid from '../../libs/document-uid'
import sortNumerically from '../../libs/sort-numerically'
import docUid from '../libs/document-uid'
import sortNumerically from '../libs/sort-numerically'
/**
@@ -143,7 +143,7 @@ export default class ZoomProperty extends React.Component {
}).join("");
const error = message ? {message} : undefined;
return <InputBlock
return <Block
error={error}
key={key}
fieldSpec={this.props.fieldSpec}
@@ -152,7 +152,7 @@ export default class ZoomProperty extends React.Component {
>
<div>
<div className="maputnik-zoom-spec-property-stop-edit">
<NumberInput
<FieldNumber
value={zoomLevel}
onChange={changedStop => this.changeZoomStop(idx, changedStop, value)}
min={0}
@@ -168,7 +168,7 @@ export default class ZoomProperty extends React.Component {
/>
</div>
</div>
</InputBlock>
</Block>
});
return <div className="maputnik-zoom-spec-property">

View File

@@ -1,34 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import LineIcon from './LineIcon.jsx'
import FillIcon from './FillIcon.jsx'
import SymbolIcon from './SymbolIcon.jsx'
import BackgroundIcon from './BackgroundIcon.jsx'
import CircleIcon from './CircleIcon.jsx'
import MissingIcon from './MissingIcon.jsx'
class LayerIcon extends React.Component {
static propTypes = {
type: PropTypes.string.isRequired,
style: PropTypes.object,
}
render() {
const iconProps = { style: this.props.style }
switch(this.props.type) {
case 'fill-extrusion': return <BackgroundIcon {...iconProps} />
case 'raster': return <FillIcon {...iconProps} />
case 'hillshade': return <FillIcon {...iconProps} />
case 'heatmap': return <FillIcon {...iconProps} />
case 'fill': return <FillIcon {...iconProps} />
case 'background': return <BackgroundIcon {...iconProps} />
case 'line': return <LineIcon {...iconProps} />
case 'symbol': return <SymbolIcon {...iconProps} />
case 'circle': return <CircleIcon {...iconProps} />
default: return <MissingIcon {...iconProps} />
}
}
}
export default LayerIcon

View File

@@ -1,178 +0,0 @@
import jsonlint from 'jsonlint';
import CodeMirror from 'codemirror';
import jsonToAst from 'json-to-ast';
import {expression, validate, latest} from '@mapbox/mapbox-gl-style-spec';
CodeMirror.defineMode("mgl", function(config, parserConfig) {
// Just using the javascript mode with json enabled. Our logic is in the linter below.
return CodeMirror.modes.javascript(
{...config, json: true},
parserConfig
);
});
CodeMirror.registerHelper("lint", "json", function(text) {
const found = [];
// NOTE: This was modified from the original to remove the global, also the
// old jsonlint API was 'jsonlint.parseError' its now
// 'jsonlint.parser.parseError'
jsonlint.parser.parseError = function(str, hash) {
const loc = hash.loc;
found.push({
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
message: str
});
};
try {
jsonlint.parse(text);
}
catch(e) {
// Do nothing we catch the error above
}
return found;
});
CodeMirror.registerHelper("lint", "mgl", function(text, opts, doc) {
const found = [];
const {parser} = jsonlint;
const {context} = opts;
parser.parseError = function(str, hash) {
const loc = hash.loc;
found.push({
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
message: str
});
};
try {
parser.parse(text);
}
catch (e) {}
if (found.length > 0) {
// JSON invalid so don't go any further
return found;
}
const ast = jsonToAst(text);
const input = JSON.parse(text);
function getArrayPositionalFromAst (node, path) {
if (!node) {
return undefined;
}
else if (path.length < 1) {
return node;
}
else if (!node.children) {
return undefined;
}
else {
const key = path[0];
let newNode;
if (key.match(/^[0-9]+$/)) {
newNode = node.children[path[0]];
}
else {
newNode = node.children.find(childNode => {
return (
childNode.key &&
childNode.key.type === "Identifier" &&
childNode.key.value === key
);
});
if (newNode) {
newNode = newNode.value;
}
}
return getArrayPositionalFromAst(newNode, path.slice(1))
}
}
let out;
if (context === "layer") {
// Just an empty style so we can validate a layer.
const errors = validate({
"version": 8,
"name": "Empty Style",
"metadata": {},
"sources": {},
"sprite": "",
"glyphs": "https://example.com/glyphs/{fontstack}/{range}.pbf",
"layers": [
input
]
});
if (errors) {
out = {
result: "error",
value: errors
.filter(err => {
// Remove missing 'layer source' errors, because we don't include them
if (err.message.match(/^layers\[0\]: source ".*" not found$/)) {
return false;
}
else {
return true;
}
})
.map(err => {
// Remove the 'layers[0].' as we're validating the layer only here
const errMessageParts = err.message.replace(/^layers\[0\]./, "").split(":");
return {
key: errMessageParts[0],
message: errMessageParts[1],
};
})
}
}
}
else if (context === "expression") {
out = expression.createExpression(input, opts.spec);
}
else {
throw new Error(`Invalid context ${context}`);
}
if (out.result === "error") {
const errors = out.value;
errors.forEach(error => {
const {key, message} = error;
if (!key) {
const lastLineHandle = doc.getLineHandle(doc.lastLine());
const err = {
from: CodeMirror.Pos(doc.firstLine(), 0),
to: CodeMirror.Pos(doc.lastLine(), lastLineHandle.text.length),
message: message,
}
found.push(err);
}
else if (key) {
const path = key.replace(/^\[|\]$/g, "").split(/\.|[\[\]]+/).filter(Boolean)
const parsedError = getArrayPositionalFromAst(ast, path);
if (!parsedError) {
console.warn("Something went wrong parsing error:", error);
return;
}
const {loc} = parsedError;
const {start, end} = loc;
found.push({
from: CodeMirror.Pos(start.line - 1, start.column),
to: CodeMirror.Pos(end.line - 1, end.column),
message: message,
});
}
})
}
return found;
});

View File

@@ -1,3 +0,0 @@
export function formatLayerId (id) {
return id === "" ? "[empty_string]" : `'${id}'`;
}

View File

@@ -1,18 +0,0 @@
/**
* If we don't have a default value just make one up
*/
export function findDefaultFromSpec (spec) {
if (spec.hasOwnProperty('default')) {
return spec.default;
}
const defaults = {
'color': '#000000',
'string': '',
'boolean': false,
'number': 0,
'array': [],
}
return defaults[spec.type] || '';
}