Fix more types, migrate two more files

This commit is contained in:
HarelM
2023-12-24 00:42:02 +02:00
parent 08f7a427f6
commit 90f50d98e7
28 changed files with 136 additions and 110 deletions

10
package-lock.json generated
View File

@@ -75,6 +75,7 @@
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52",
"@types/react-aria-menubutton": "^6.2.13",
"@types/react-aria-modal": "^4.0.9",
"@types/react-autocomplete": "^1.8.9",
"@types/react-collapse": "^5.0.4",
@@ -4889,6 +4890,15 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-aria-menubutton": {
"version": "6.2.13",
"resolved": "https://registry.npmjs.org/@types/react-aria-menubutton/-/react-aria-menubutton-6.2.13.tgz",
"integrity": "sha512-olSjeIzNzn0KrbShOmBwchHS++khDXBYFTO2U802o8LDHANLms7zUsJhdecfqFpwdFMHxFiMMlCn2nJNCEHWlQ==",
"dev": true,
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-aria-modal": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/@types/react-aria-modal/-/react-aria-modal-4.0.9.tgz",

View File

@@ -104,6 +104,7 @@
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.throttle": "^4.1.9",
"@types/react": "^16.14.52",
"@types/react-aria-menubutton": "^6.2.13",
"@types/react-aria-modal": "^4.0.9",
"@types/react-autocomplete": "^1.8.9",
"@types/react-collapse": "^5.0.4",

View File

@@ -12,7 +12,7 @@ type BlockProps = {
onChange?(...args: unknown[]): unknown
fieldSpec?: object
wideMode?: boolean
error?: unknown[]
error?: {message: string}
};
type BlockState = {

View File

@@ -5,7 +5,8 @@ import InputString from './InputString'
type FieldCommentProps = {
value?: string
onChange(...args: unknown[]): unknown
onChange(value: string | undefined): unknown
error: {message: string}
};
export default class FieldComment extends React.Component<FieldCommentProps> {
@@ -18,6 +19,7 @@ export default class FieldComment extends React.Component<FieldCommentProps> {
label={"Comments"}
fieldSpec={fieldSpec}
data-wd-key="layer-comment"
error={this.props.error}
>
<InputString
multi={true}

View File

@@ -107,7 +107,7 @@ type FieldFunctionProps = {
fieldName: string
fieldType: string
fieldSpec: any
errors?: unknown[]
errors?: {[key: string]: {message: string}}
value?: any
};

View File

@@ -7,8 +7,8 @@ import InputString from './InputString'
type FieldIdProps = {
value: string
wdKey: string
onChange(...args: unknown[]): unknown
error?: unknown[]
onChange(value: string | undefined): unknown
error?: {message: string}
};
export default class FieldId extends React.Component<FieldIdProps> {

View File

@@ -6,8 +6,8 @@ import InputNumber from './InputNumber'
type FieldMaxZoomProps = {
value?: number
onChange(...args: unknown[]): unknown
error?: unknown[]
onChange(value: number | undefined): unknown
error?: {message: string}
};
export default class FieldMaxZoom extends React.Component<FieldMaxZoomProps> {

View File

@@ -7,7 +7,7 @@ import InputNumber from './InputNumber'
type FieldMinZoomProps = {
value?: number
onChange(...args: unknown[]): unknown
error?: unknown[]
error?: {message: string}
};
export default class FieldMinZoom extends React.Component<FieldMinZoomProps> {

View File

@@ -7,9 +7,9 @@ import InputAutocomplete from './InputAutocomplete'
type FieldSourceProps = {
value?: string
wdKey?: string
onChange?(...args: unknown[]): unknown
onChange?(value: string| undefined): unknown
sourceIds?: unknown[]
error?: unknown[]
error?: {message: string}
};
export default class FieldSource extends React.Component<FieldSourceProps> {

View File

@@ -9,6 +9,7 @@ type FieldSourceLayerProps = {
onChange?(...args: unknown[]): unknown
sourceLayerIds?: unknown[]
isFixed?: boolean
error?: {message: string}
};
export default class FieldSourceLayer extends React.Component<FieldSourceLayerProps> {
@@ -19,8 +20,11 @@ export default class FieldSourceLayer extends React.Component<FieldSourceLayerPr
}
render() {
return <Block label={"Source Layer"} fieldSpec={latest.layer['source-layer']}
return <Block
label={"Source Layer"}
fieldSpec={latest.layer['source-layer']}
data-wd-key="layer-source-layer"
error={this.props.error}
>
<InputAutocomplete
keepMenuWithinWindowBounds={!!this.props.isFixed}

View File

@@ -8,8 +8,8 @@ import InputString from './InputString'
type FieldTypeProps = {
value: string
wdKey?: string
onChange(...args: unknown[]): unknown
error?: unknown[] | undefined
onChange(value: string): unknown
error?: {message: string}
disabled?: boolean
};

View File

@@ -1,10 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
import {combiningFilterOps} from '../libs/filterops'
import {mdiTableRowPlusAfter} from '@mdi/js';
import {isEqual} from 'lodash';
import {latest, migrate, convertFilter} from '@maplibre/maplibre-gl-style-spec'
import {latest, migrate, convertFilter, ExpressionSpecification, LegacyFilterSpecification, StyleSpecification} from '@maplibre/maplibre-gl-style-spec'
import InputSelect from './InputSelect'
import Block from './Block'
import SingleFilterEditor from './SingleFilterEditor'
@@ -15,7 +14,7 @@ import ExpressionProperty from './_ExpressionProperty';
import {mdiFunctionVariant} from '@mdi/js';
function combiningFilter (props) {
function combiningFilter(props: FilterEditorProps): LegacyFilterSpecification | ExpressionSpecification {
let filter = props.filter || ['all'];
if (!Array.isArray(filter)) {
@@ -30,14 +29,14 @@ function combiningFilter (props) {
filters = [filter.slice(0)];
}
return [combiningOp, ...filters];
return [combiningOp, ...filters] as LegacyFilterSpecification | ExpressionSpecification;
}
function migrateFilter (filter) {
return migrate(createStyleFromFilter(filter)).layers[0].filter;
function migrateFilter(filter: LegacyFilterSpecification | ExpressionSpecification) {
return (migrate(createStyleFromFilter(filter)).layers[0] as any).filter;
}
function createStyleFromFilter (filter) {
function createStyleFromFilter(filter: LegacyFilterSpecification | ExpressionSpecification): StyleSpecification & {id: string} {
return {
"id": "tmp",
"version": 8,
@@ -69,7 +68,7 @@ const FILTER_OPS = [
];
// If we convert a filter that is an expression to an expression it'll remain the same in value
function checkIfSimpleFilter (filter) {
function checkIfSimpleFilter (filter: LegacyFilterSpecification | ExpressionSpecification) {
if (filter.length === 1 && FILTER_OPS.includes(filter[0])) {
return true;
}
@@ -77,33 +76,38 @@ function checkIfSimpleFilter (filter) {
return !isEqual(expression, filter);
}
function hasCombiningFilter(filter) {
function hasCombiningFilter(filter: LegacyFilterSpecification | ExpressionSpecification) {
return combiningFilterOps.indexOf(filter[0]) >= 0
}
function hasNestedCombiningFilter(filter) {
function hasNestedCombiningFilter(filter: LegacyFilterSpecification | ExpressionSpecification) {
if(hasCombiningFilter(filter)) {
const combinedFilters = filter.slice(1)
return filter.slice(1).map(f => hasCombiningFilter(f)).filter(f => f == true).length > 0
return filter.slice(1).map(f => hasCombiningFilter(f as any)).filter(f => f == true).length > 0
}
return false
}
export default class FilterEditor extends React.Component {
static propTypes = {
/** Properties of the vector layer and the available fields */
properties: PropTypes.object,
filter: PropTypes.array,
errors: PropTypes.object,
onChange: PropTypes.func.isRequired,
}
type FilterEditorProps = {
/** Properties of the vector layer and the available fields */
properties?: {[key:string]: any}
filter?: any[]
errors?: {[key:string]: any}
onChange(value: LegacyFilterSpecification | ExpressionSpecification): unknown
};
type FilterEditorState = {
showDoc: boolean
displaySimpleFilter: boolean
valueIsSimpleFilter?: boolean
};
export default class FilterEditor extends React.Component<FilterEditorProps, FilterEditorState> {
static defaultProps = {
filter: ["all"],
}
constructor (props) {
super();
constructor (props: FilterEditorProps) {
super(props);
this.state = {
showDoc: false,
displaySimpleFilter: checkIfSimpleFilter(combiningFilter(props)),
@@ -111,25 +115,25 @@ export default class FilterEditor extends React.Component {
}
// Convert filter to combining filter
onFilterPartChanged(filterIdx, newPart) {
const newFilter = combiningFilter(this.props).slice(0)
onFilterPartChanged(filterIdx: number, newPart: any[]) {
const newFilter = combiningFilter(this.props).slice(0) as LegacyFilterSpecification | ExpressionSpecification
newFilter[filterIdx] = newPart
this.props.onChange(newFilter)
}
deleteFilterItem(filterIdx) {
const newFilter = combiningFilter(this.props).slice(0)
deleteFilterItem(filterIdx: number) {
const newFilter = combiningFilter(this.props).slice(0) as LegacyFilterSpecification | ExpressionSpecification
newFilter.splice(filterIdx + 1, 1)
this.props.onChange(newFilter)
}
addFilterItem = () => {
const newFilterItem = combiningFilter(this.props).slice(0)
newFilterItem.push(['==', 'name', ''])
const newFilterItem = combiningFilter(this.props).slice(0) as LegacyFilterSpecification | ExpressionSpecification
(newFilterItem as any[]).push(['==', 'name', ''])
this.props.onChange(newFilterItem)
}
onToggleDoc = (val) => {
onToggleDoc = (val: boolean) => {
this.setState({
showDoc: val
});
@@ -149,8 +153,7 @@ export default class FilterEditor extends React.Component {
})
}
static getDerivedStateFromProps (props, currentState) {
const {filter} = props;
static getDerivedStateFromProps(props: FilterEditorProps, currentState: FilterEditorState) {
const displaySimpleFilter = checkIfSimpleFilter(combiningFilter(props));
// Upgrade but never downgrade
@@ -178,7 +181,7 @@ export default class FilterEditor extends React.Component {
const fieldSpec={
doc: latest.layer.filter.doc + " Combine multiple filters together by using a compound filter."
};
const defaultFilter = ["all"];
const defaultFilter = ["all"] as LegacyFilterSpecification | ExpressionSpecification;
const isNestedCombiningFilter = displaySimpleFilter && hasNestedCombiningFilter(combiningFilter(this.props));
@@ -201,7 +204,7 @@ export default class FilterEditor extends React.Component {
else if (displaySimpleFilter) {
const filter = combiningFilter(this.props);
let combiningOp = filter[0];
let filters = filter.slice(1)
let filters = filter.slice(1) as (LegacyFilterSpecification | ExpressionSpecification)[];
const actions = (
<div>
@@ -218,7 +221,7 @@ export default class FilterEditor extends React.Component {
);
const editorBlocks = filters.map((f, idx) => {
const error = errors[`filter[${idx+1}]`];
const error = errors![`filter[${idx+1}]`];
return (
<div key={`block-${idx}`}>
@@ -247,7 +250,7 @@ export default class FilterEditor extends React.Component {
>
<InputSelect
value={combiningOp}
onChange={this.onFilterPartChanged.bind(this, 0)}
onChange={(v: [string, any]) => this.onFilterPartChanged(0, v)}
options={[["all", "every filter matches"], ["none", "no filter matches"], ["any", "any filter matches"]]}
/>
</Block>

View File

@@ -8,7 +8,7 @@ const MAX_HEIGHT = 140;
export type InputAutocompleteProps = {
value?: string
options: any[]
onChange(...args: unknown[]): unknown
onChange(value: string | undefined): unknown
keepMenuWithinWindowBounds?: boolean
'aria-label'?: string
};

View File

@@ -5,7 +5,7 @@ export type InputSelectProps = {
"data-wd-key"?: string
options: [string, any][] | string[]
style?: object
onChange(value: string): unknown
onChange(value: string | [string, any]): unknown
title?: string
'aria-label'?: string
};

View File

@@ -1,6 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Wrapper, Button, Menu, MenuItem } from 'react-aria-menubutton'
import {Accordion} from 'react-accessible-accordion';
import {MdMoreVert} from 'react-icons/md'
import FieldJson from './FieldJson'
import FilterEditor from './FilterEditor'
@@ -13,20 +15,18 @@ import FieldMaxZoom from './FieldMaxZoom'
import FieldComment from './FieldComment'
import FieldSource from './FieldSource'
import FieldSourceLayer from './FieldSourceLayer'
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 {formatLayerId} from '../util/format';
import { SourceSpecification } from '@maplibre/maplibre-gl-style-spec';
import { BackgroundLayerSpecification, LayerSpecification } from 'maplibre-gl';
function getLayoutForType (type) {
function getLayoutForType(type: LayerSpecification["type"]) {
return layout[type] ? layout[type] : layout.invalid;
}
function layoutGroups(layerType) {
function layoutGroups(layerType: LayerSpecification["type"]): {title: string, type: string, fields?: string[]}[] {
const layerGroup = {
title: 'Layer',
type: 'layer'
@@ -44,25 +44,29 @@ function layoutGroups(layerType) {
.concat([editorGroup])
}
/** Layer editor supporting multiple types of layers. */
export default class LayerEditor extends React.Component {
static propTypes = {
layer: PropTypes.object.isRequired,
sources: PropTypes.object,
vectorLayers: PropTypes.object,
spec: PropTypes.object.isRequired,
onLayerChanged: PropTypes.func,
onLayerIdChange: PropTypes.func,
onMoveLayer: PropTypes.func,
onLayerDestroy: PropTypes.func,
onLayerCopy: PropTypes.func,
onLayerVisibilityToggle: PropTypes.func,
isFirstLayer: PropTypes.bool,
isLastLayer: PropTypes.bool,
layerIndex: PropTypes.number,
errors: PropTypes.array,
}
type LayerEditorProps = {
layer: LayerSpecification
sources?: SourceSpecification
vectorLayers: {[key: string]: any}
spec: object
onLayerChanged(...args: unknown[]): unknown
onLayerIdChange(...args: unknown[]): unknown
onMoveLayer(...args: unknown[]): unknown
onLayerDestroy(...args: unknown[]): unknown
onLayerCopy(...args: unknown[]): unknown
onLayerVisibilityToggle(...args: unknown[]): unknown
isFirstLayer?: boolean
isLastLayer?: boolean
layerIndex: number
errors?: any[]
};
type LayerEditorState = {
editorGroups: {[keys:string]: boolean}
};
/** Layer editor supporting multiple types of layers. */
export default class LayerEditor extends React.Component<LayerEditorProps, LayerEditorState> {
static defaultProps = {
onLayerChanged: () => {},
onLayerIdChange: () => {},
@@ -73,11 +77,11 @@ export default class LayerEditor extends React.Component {
reactIconBase: PropTypes.object
}
constructor(props) {
constructor(props: LayerEditorProps) {
super(props)
//TODO: Clean this up and refactor into function
const editorGroups = {}
const editorGroups: {[keys:string]: boolean} = {}
layoutGroups(this.props.layer.type).forEach(group => {
editorGroups[group.title] = true
})
@@ -85,7 +89,7 @@ export default class LayerEditor extends React.Component {
this.state = { editorGroups }
}
static getDerivedStateFromProps(props, state) {
static getDerivedStateFromProps(props: LayerEditorProps, state: LayerEditorState) {
const additionalGroups = { ...state.editorGroups }
getLayoutForType(props.layer.type).groups.forEach(group => {
@@ -108,14 +112,14 @@ export default class LayerEditor extends React.Component {
}
}
changeProperty(group, property, newValue) {
changeProperty(group: keyof LayerSpecification | null, property: string, newValue: any) {
this.props.onLayerChanged(
this.props.layerIndex,
changeProperty(this.props.layer, group, property, newValue)
)
}
onGroupToggle(groupTitle, active) {
onGroupToggle(groupTitle: string, active: boolean) {
const changedActiveGroups = {
...this.state.editorGroups,
[groupTitle]: active,
@@ -125,15 +129,15 @@ export default class LayerEditor extends React.Component {
})
}
renderGroupType(type, fields) {
renderGroupType(type: string, fields?: string[]): JSX.Element {
let comment = ""
if(this.props.layer.metadata) {
comment = this.props.layer.metadata['maputnik:comment']
comment = (this.props.layer.metadata as any)['maputnik:comment']
}
const {errors, layerIndex} = this.props;
const errorData = {};
errors.forEach(error => {
const errorData: {[key in LayerSpecification as string]: {message: string}} = {};
errors!.forEach(error => {
if (
error.parsed &&
error.parsed.type === "layer" &&
@@ -146,8 +150,8 @@ export default class LayerEditor extends React.Component {
})
let sourceLayerIds;
if(this.props.sources.hasOwnProperty(this.props.layer.source)) {
sourceLayerIds = this.props.sources[this.props.layer.source].layers;
if(this.props.sources?.hasOwnProperty((this.props.layer as Exclude<LayerSpecification, BackgroundLayerSpecification>).source)) {
sourceLayerIds = (this.props.sources as any)[(this.props.layer as any).source].layers;
}
switch(type) {
@@ -169,7 +173,7 @@ export default class LayerEditor extends React.Component {
/>
{this.props.layer.type !== 'background' && <FieldSource
error={errorData.source}
sourceIds={Object.keys(this.props.sources)}
sourceIds={Object.keys(this.props.sources!)}
value={this.props.layer.source}
onChange={v => this.changeProperty(null, 'source', v)}
/>
@@ -178,7 +182,7 @@ export default class LayerEditor extends React.Component {
<FieldSourceLayer
error={errorData['source-layer']}
sourceLayerIds={sourceLayerIds}
value={this.props.layer['source-layer']}
value={(this.props.layer as any)['source-layer']}
onChange={v => this.changeProperty(null, 'source-layer', v)}
/>
}
@@ -202,8 +206,8 @@ export default class LayerEditor extends React.Component {
<div className="maputnik-filter-editor-wrapper">
<FilterEditor
errors={errorData}
filter={this.props.layer.filter}
properties={this.props.vectorLayers[this.props.layer['source-layer']]}
filter={(this.props.layer as any).filter}
properties={this.props.vectorLayers[(this.props.layer as any)['source-layer']]}
onChange={f => this.changeProperty(null, 'filter', f)}
/>
</div>
@@ -212,7 +216,7 @@ export default class LayerEditor extends React.Component {
return <PropertyGroup
errors={errorData}
layer={this.props.layer}
groupFields={fields}
groupFields={fields!}
spec={this.props.spec}
onChange={this.changeProperty.bind(this)}
/>
@@ -226,10 +230,11 @@ export default class LayerEditor extends React.Component {
);
}}
/>
default: return <></>
}
}
moveLayer(offset) {
moveLayer(offset: number) {
this.props.onMoveLayer({
oldIndex: this.props.layerIndex,
newIndex: this.props.layerIndex+offset
@@ -237,7 +242,7 @@ export default class LayerEditor extends React.Component {
}
render() {
const groupIds = [];
const groupIds: string[] = [];
const layerType = this.props.layer.type
const groups = layoutGroups(layerType).filter(group => {
return !(layerType === 'background' && group.type === 'source')
@@ -258,7 +263,7 @@ export default class LayerEditor extends React.Component {
const layout = this.props.layer.layout || {}
const items = {
const items: {[key: string]: {text: string, handler: () => void, disabled?: boolean}} = {
delete: {
text: "Delete",
handler: () => this.props.onLayerDestroy(this.props.layerIndex)
@@ -285,8 +290,8 @@ export default class LayerEditor extends React.Component {
}
}
function handleSelection(id, event) {
event.stopPropagation;
function handleSelection(id: string, event: React.SyntheticEvent) {
event.stopPropagation();
items[id].handler();
}
@@ -310,7 +315,7 @@ export default class LayerEditor extends React.Component {
</Button>
<Menu>
<ul className="more-menu__menu">
{Object.keys(items).map((id, idx) => {
{Object.keys(items).map((id) => {
const item = items[id];
return <li key={id}>
<MenuItem value={id} className='more-menu__menu__item'>

View File

@@ -18,7 +18,7 @@ type LayerEditorGroupProps = {
title: string
isActive: boolean
children: React.ReactElement
onActiveToggle(...args: unknown[]): unknown
onActiveToggle(active: boolean): unknown
};

View File

@@ -39,7 +39,7 @@ type PropertyGroupProps = {
groupFields: string[]
onChange(...args: unknown[]): unknown
spec: any
errors?: unknown[]
errors?: {[key: string]: {message: string}}
};
export default class PropertyGroup extends React.Component<PropertyGroupProps> {

View File

@@ -36,7 +36,7 @@ function parseFilter(v: string | boolean | number) {
type SingleFilterEditorProps = {
filter: any[]
onChange(...args: unknown[]): unknown
onChange(filter: any[]): unknown
properties?: {[key: string]: string}
};

View File

@@ -288,7 +288,7 @@ export default class DataProperty extends React.Component<DataPropertyProps, Dat
<div className="maputnik-data-spec-property-input">
<InputSelect
value={this.props.value!.type}
onChange={propVal => this.changeDataType(propVal)}
onChange={(propVal: string) => this.changeDataType(propVal)}
title={"Select a type of data scale (default is 'categorical')."}
options={this.getDataFunctionTypes(this.props.fieldSpec)}
/>

View File

@@ -14,7 +14,7 @@ type ExpressionPropertyProps = {
fieldType?: string
fieldSpec?: object
value?: any
errors?: {[key: string]: any}
errors?: {[key: string]: {message: string}}
onChange?(...args: unknown[]): unknown
onUndo?(...args: unknown[]): unknown
canUndo?(...args: unknown[]): unknown
@@ -109,7 +109,8 @@ export default class ExpressionProperty extends React.Component<ExpressionProper
}
return <Block
error={foundErrors}
// this feels like an incorrect type...? `foundErrors` is an array of objects, not a single object
error={foundErrors as any}
fieldSpec={this.props.fieldSpec}
label={labelFromFieldName(this.props.fieldName)}
action={deleteStopBtn}

View File

@@ -8,7 +8,7 @@ type BlockIdProps = {
value: string
wdKey: string
onChange(...args: unknown[]): unknown
error?: unknown[]
error?: {message: string}
};
export default class BlockId extends React.Component<BlockIdProps> {

View File

@@ -7,7 +7,7 @@ import FieldNumber from './FieldNumber'
type BlockMaxZoomProps = {
value?: number
onChange(...args: unknown[]): unknown
error?: unknown[]
error?: {message: string}
};
export default class BlockMaxZoom extends React.Component<BlockMaxZoomProps> {

View File

@@ -7,7 +7,7 @@ import FieldNumber from './FieldNumber'
type BlockMinZoomProps = {
value?: number
onChange(...args: unknown[]): unknown
error?: unknown[]
error?: {message: string}
};
export default class BlockMinZoom extends React.Component<BlockMinZoomProps> {

View File

@@ -9,7 +9,7 @@ type BlockSourceProps = {
wdKey?: string
onChange?(...args: unknown[]): unknown
sourceIds?: unknown[]
error?: unknown[]
error?: {message: string}
};
export default class BlockSource extends React.Component<BlockSourceProps> {

View File

@@ -9,7 +9,7 @@ type BlockTypeProps = {
value: string
wdKey?: string
onChange(...args: unknown[]): unknown
error?: unknown[]
error?: {message: string}
disabled?: boolean
};

View File

@@ -13,7 +13,7 @@ type SpecPropertyProps = SpecFieldProps & {
fieldType?: string
fieldSpec?: any
value?: any
errors?: unknown[]
errors?: {[key: string]: {message: string}}
onExpressionClick?(...args: unknown[]): unknown
};

View File

@@ -195,7 +195,7 @@ export default class ZoomProperty extends React.Component<ZoomPropertyProps, Zoo
<div className="maputnik-data-spec-property-input">
<InputSelect
value={"interpolate"}
onChange={propVal => this.changeDataType(propVal)}
onChange={(propVal: string) => this.changeDataType(propVal)}
title={"Select a type of data scale (default is 'categorical')."}
options={this.getDataFunctionTypes(this.props.fieldSpec!)}
/>

View File

@@ -27,7 +27,7 @@ export function changeType(layer: LayerSpecification, newType: string) {
/** A {@property} in either the paint our layout {@group} has changed
* to a {@newValue}.
*/
export function changeProperty(layer: LayerSpecification, group: keyof LayerSpecification, property: string, newValue: any) {
export function changeProperty(layer: LayerSpecification, group: keyof LayerSpecification | null, property: string, newValue: any) {
// Remove the property if undefined
if(newValue === undefined) {
if(group) {