mirror of
https://github.com/maputnik/editor.git
synced 2026-06-17 12:47:27 +00:00
More componenet migration
This commit is contained in:
@@ -10,6 +10,7 @@ import IconMissing from './IconMissing'
|
|||||||
type IconLayerProps = {
|
type IconLayerProps = {
|
||||||
type: string
|
type: string
|
||||||
style?: object
|
style?: object
|
||||||
|
className?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class IconLayer extends React.Component<IconLayerProps> {
|
export default class IconLayer extends React.Component<IconLayerProps> {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
|
|
||||||
@@ -8,20 +7,13 @@ import LayerListItem from './LayerListItem'
|
|||||||
import ModalAdd from './ModalAdd'
|
import ModalAdd from './ModalAdd'
|
||||||
|
|
||||||
import {SortableContainer} from 'react-sortable-hoc';
|
import {SortableContainer} from 'react-sortable-hoc';
|
||||||
|
import { LayerSpecification } from '@maplibre/maplibre-gl-style-spec';
|
||||||
|
|
||||||
const layerListPropTypes = {
|
function layerPrefix(name: string) {
|
||||||
layers: PropTypes.array.isRequired,
|
|
||||||
selectedLayerIndex: PropTypes.number.isRequired,
|
|
||||||
onLayersChange: PropTypes.func.isRequired,
|
|
||||||
onLayerSelect: PropTypes.func,
|
|
||||||
sources: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
function layerPrefix(name) {
|
|
||||||
return name.replace(' ', '-').replace('_', '-').split('-')[0]
|
return name.replace(' ', '-').replace('_', '-').split('-')[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
function findClosestCommonPrefix(layers, idx) {
|
function findClosestCommonPrefix(layers: LayerSpecification[], idx: number) {
|
||||||
const currentLayerPrefix = layerPrefix(layers[idx].id)
|
const currentLayerPrefix = layerPrefix(layers[idx].id)
|
||||||
let closestIdx = idx
|
let closestIdx = idx
|
||||||
for (let i = idx; i > 0; i--) {
|
for (let i = idx; i > 0; i--) {
|
||||||
@@ -37,14 +29,34 @@ function findClosestCommonPrefix(layers, idx) {
|
|||||||
|
|
||||||
let UID = 0;
|
let UID = 0;
|
||||||
|
|
||||||
|
type LayerListContainerProps = {
|
||||||
|
layers: LayerSpecification[]
|
||||||
|
selectedLayerIndex: number
|
||||||
|
onLayersChange(...args: unknown[]): unknown
|
||||||
|
onLayerSelect(...args: unknown[]): unknown
|
||||||
|
onLayerDestroy?(...args: unknown[]): unknown
|
||||||
|
onLayerCopy(...args: unknown[]): unknown
|
||||||
|
onLayerVisibilityToggle(...args: unknown[]): unknown
|
||||||
|
sources: object
|
||||||
|
errors: any[]
|
||||||
|
};
|
||||||
|
|
||||||
|
type LayerListContainerState = {
|
||||||
|
collapsedGroups: {[ket: string]: boolean}
|
||||||
|
areAllGroupsExpanded: boolean
|
||||||
|
keys: {[key: string]: number}
|
||||||
|
isOpen: {[key: string]: boolean}
|
||||||
|
};
|
||||||
|
|
||||||
// List of collapsible layer editors
|
// List of collapsible layer editors
|
||||||
class LayerListContainer extends React.Component {
|
class LayerListContainer extends React.Component<LayerListContainerProps, LayerListContainerState> {
|
||||||
static propTypes = {...layerListPropTypes}
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onLayerSelect: () => {},
|
onLayerSelect: () => {},
|
||||||
}
|
}
|
||||||
|
selectedItemRef: React.RefObject<any>;
|
||||||
|
scrollContainerRef: React.RefObject<HTMLElement>;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: LayerListContainerProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.selectedItemRef = React.createRef();
|
this.selectedItemRef = React.createRef();
|
||||||
this.scrollContainerRef = React.createRef();
|
this.scrollContainerRef = React.createRef();
|
||||||
@@ -60,7 +72,7 @@ class LayerListContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleModal(modalName) {
|
toggleModal(modalName: string) {
|
||||||
this.setState({
|
this.setState({
|
||||||
keys: {
|
keys: {
|
||||||
...this.state.keys,
|
...this.state.keys,
|
||||||
@@ -74,9 +86,9 @@ class LayerListContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleLayers = () => {
|
toggleLayers = () => {
|
||||||
let idx=0
|
let idx = 0
|
||||||
|
|
||||||
let newGroups=[]
|
let newGroups: {[key:string]: boolean} = {}
|
||||||
|
|
||||||
this.groupedLayers().forEach(layers => {
|
this.groupedLayers().forEach(layers => {
|
||||||
const groupPrefix = layerPrefix(layers[0].id)
|
const groupPrefix = layerPrefix(layers[0].id)
|
||||||
@@ -87,7 +99,7 @@ class LayerListContainer extends React.Component {
|
|||||||
newGroups[lookupKey] = this.state.areAllGroupsExpanded
|
newGroups[lookupKey] = this.state.areAllGroupsExpanded
|
||||||
}
|
}
|
||||||
|
|
||||||
layers.forEach((layer) => {
|
layers.forEach((_layer) => {
|
||||||
idx += 1
|
idx += 1
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@@ -98,7 +110,7 @@ class LayerListContainer extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
groupedLayers() {
|
groupedLayers(): (LayerSpecification & {key: string})[][] {
|
||||||
const groups = []
|
const groups = []
|
||||||
const layerIdCount = new Map();
|
const layerIdCount = new Map();
|
||||||
|
|
||||||
@@ -122,7 +134,7 @@ class LayerListContainer extends React.Component {
|
|||||||
return groups
|
return groups
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLayerGroup(groupPrefix, idx) {
|
toggleLayerGroup(groupPrefix: string, idx: number) {
|
||||||
const lookupKey = [groupPrefix, idx].join('-')
|
const lookupKey = [groupPrefix, idx].join('-')
|
||||||
const newGroups = { ...this.state.collapsedGroups }
|
const newGroups = { ...this.state.collapsedGroups }
|
||||||
if(lookupKey in this.state.collapsedGroups) {
|
if(lookupKey in this.state.collapsedGroups) {
|
||||||
@@ -135,12 +147,12 @@ class LayerListContainer extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsed(groupPrefix, idx) {
|
isCollapsed(groupPrefix: string, idx: number) {
|
||||||
const collapsed = this.state.collapsedGroups[[groupPrefix, idx].join('-')]
|
const collapsed = this.state.collapsedGroups[[groupPrefix, idx].join('-')]
|
||||||
return collapsed === undefined ? true : collapsed
|
return collapsed === undefined ? true : collapsed
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate (nextProps, nextState) {
|
shouldComponentUpdate (nextProps: LayerListContainerProps, nextState: LayerListContainerState) {
|
||||||
// Always update on state change
|
// Always update on state change
|
||||||
if (this.state !== nextState) {
|
if (this.state !== nextState) {
|
||||||
return true;
|
return true;
|
||||||
@@ -148,8 +160,8 @@ class LayerListContainer extends React.Component {
|
|||||||
|
|
||||||
// This component tree only requires id and visibility from the layers
|
// This component tree only requires id and visibility from the layers
|
||||||
// objects
|
// objects
|
||||||
function getRequiredProps (layer) {
|
function getRequiredProps(layer: LayerSpecification) {
|
||||||
const out = {
|
const out: {id: string, layout?: { visibility: any}} = {
|
||||||
id: layer.id,
|
id: layer.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -165,10 +177,10 @@ class LayerListContainer extends React.Component {
|
|||||||
this.props.layers.map(getRequiredProps),
|
this.props.layers.map(getRequiredProps),
|
||||||
);
|
);
|
||||||
|
|
||||||
function withoutLayers (props) {
|
function withoutLayers(props: LayerListContainerProps) {
|
||||||
const out = {
|
const out = {
|
||||||
...props
|
...props
|
||||||
};
|
} as LayerListContainerProps & { layers?: any };
|
||||||
delete out['layers'];
|
delete out['layers'];
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -184,7 +196,7 @@ class LayerListContainer extends React.Component {
|
|||||||
return propsChanged;
|
return propsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps: LayerListContainerProps) {
|
||||||
if (prevProps.selectedLayerIndex !== this.props.selectedLayerIndex) {
|
if (prevProps.selectedLayerIndex !== this.props.selectedLayerIndex) {
|
||||||
const selectedItemNode = this.selectedItemRef.current;
|
const selectedItemNode = this.selectedItemRef.current;
|
||||||
if (selectedItemNode && selectedItemNode.node) {
|
if (selectedItemNode && selectedItemNode.node) {
|
||||||
@@ -207,7 +219,7 @@ class LayerListContainer extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const listItems = []
|
const listItems: JSX.Element[] = []
|
||||||
let idx = 0
|
let idx = 0
|
||||||
const layersByGroup = this.groupedLayers();
|
const layersByGroup = this.groupedLayers();
|
||||||
layersByGroup.forEach(layers => {
|
layersByGroup.forEach(layers => {
|
||||||
@@ -235,7 +247,7 @@ class LayerListContainer extends React.Component {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const additionalProps = {};
|
const additionalProps: {ref?: React.RefObject<any>} = {};
|
||||||
if (idx === this.props.selectedLayerIndex) {
|
if (idx === this.props.selectedLayerIndex) {
|
||||||
additionalProps.ref = this.selectedItemRef;
|
additionalProps.ref = this.selectedItemRef;
|
||||||
}
|
}
|
||||||
@@ -255,7 +267,7 @@ class LayerListContainer extends React.Component {
|
|||||||
visibility={(layer.layout || {}).visibility}
|
visibility={(layer.layout || {}).visibility}
|
||||||
isSelected={idx === this.props.selectedLayerIndex}
|
isSelected={idx === this.props.selectedLayerIndex}
|
||||||
onLayerSelect={this.props.onLayerSelect}
|
onLayerSelect={this.props.onLayerSelect}
|
||||||
onLayerDestroy={this.props.onLayerDestroy.bind(this)}
|
onLayerDestroy={this.props.onLayerDestroy?.bind(this)}
|
||||||
onLayerCopy={this.props.onLayerCopy.bind(this)}
|
onLayerCopy={this.props.onLayerCopy.bind(this)}
|
||||||
onLayerVisibilityToggle={this.props.onLayerVisibilityToggle.bind(this)}
|
onLayerVisibilityToggle={this.props.onLayerVisibilityToggle.bind(this)}
|
||||||
{...additionalProps}
|
{...additionalProps}
|
||||||
@@ -316,11 +328,13 @@ class LayerListContainer extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerListContainerSortable = SortableContainer((props) => <LayerListContainer {...props} />)
|
const LayerListContainerSortable = SortableContainer((props: LayerListContainerProps) => <LayerListContainer {...props} />)
|
||||||
|
|
||||||
export default class LayerList extends React.Component {
|
type LayerListProps = LayerListContainerProps & {
|
||||||
static propTypes = {...layerListPropTypes}
|
onMoveLayer(...args: unknown[]): unknown
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class LayerList extends React.Component<LayerListProps> {
|
||||||
render() {
|
render() {
|
||||||
return <LayerListContainerSortable
|
return <LayerListContainerSortable
|
||||||
{...this.props}
|
{...this.props}
|
||||||
@@ -8,7 +8,12 @@ import IconLayer from './IconLayer'
|
|||||||
import {SortableElement, SortableHandle} from 'react-sortable-hoc'
|
import {SortableElement, SortableHandle} from 'react-sortable-hoc'
|
||||||
|
|
||||||
|
|
||||||
const DraggableLabel = SortableHandle((props) => {
|
type DraggableLabelProps = {
|
||||||
|
layerId: string
|
||||||
|
layerType: string
|
||||||
|
};
|
||||||
|
|
||||||
|
const DraggableLabel = SortableHandle((props: DraggableLabelProps) => {
|
||||||
return <div className="maputnik-layer-list-item-handle">
|
return <div className="maputnik-layer-list-item-handle">
|
||||||
<IconLayer
|
<IconLayer
|
||||||
className="layer-handle__icon"
|
className="layer-handle__icon"
|
||||||
@@ -20,15 +25,15 @@ const DraggableLabel = SortableHandle((props) => {
|
|||||||
</div>
|
</div>
|
||||||
});
|
});
|
||||||
|
|
||||||
class IconAction extends React.Component {
|
type IconActionProps = {
|
||||||
static propTypes = {
|
action: string
|
||||||
action: PropTypes.string.isRequired,
|
onClick(...args: unknown[]): unknown
|
||||||
onClick: PropTypes.func.isRequired,
|
wdKey?: string
|
||||||
wdKey: PropTypes.string,
|
classBlockName?: string
|
||||||
classBlockName: PropTypes.string,
|
classBlockModifier?: string
|
||||||
classBlockModifier: PropTypes.string,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
class IconAction extends React.Component<IconActionProps> {
|
||||||
renderIcon() {
|
renderIcon() {
|
||||||
switch(this.props.action) {
|
switch(this.props.action) {
|
||||||
case 'duplicate': return <MdContentCopy />
|
case 'duplicate': return <MdContentCopy />
|
||||||
@@ -51,7 +56,7 @@ class IconAction extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <button
|
return <button
|
||||||
tabIndex="-1"
|
tabIndex={-1}
|
||||||
title={this.props.action}
|
title={this.props.action}
|
||||||
className={`maputnik-layer-list-icon-action ${classAdditions}`}
|
className={`maputnik-layer-list-icon-action ${classAdditions}`}
|
||||||
data-wd-key={this.props.wdKey}
|
data-wd-key={this.props.wdKey}
|
||||||
@@ -63,21 +68,21 @@ class IconAction extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LayerListItem extends React.Component {
|
type LayerListItemProps = {
|
||||||
static propTypes = {
|
id?: string
|
||||||
layerIndex: PropTypes.number.isRequired,
|
layerIndex: number
|
||||||
layerId: PropTypes.string.isRequired,
|
layerId: string
|
||||||
layerType: PropTypes.string.isRequired,
|
layerType: string
|
||||||
isSelected: PropTypes.bool,
|
isSelected?: boolean
|
||||||
visibility: PropTypes.string,
|
visibility?: string
|
||||||
className: PropTypes.string,
|
className?: string
|
||||||
|
onLayerSelect(...args: unknown[]): unknown
|
||||||
onLayerSelect: PropTypes.func.isRequired,
|
onLayerCopy?(...args: unknown[]): unknown
|
||||||
onLayerCopy: PropTypes.func,
|
onLayerDestroy?(...args: unknown[]): unknown
|
||||||
onLayerDestroy: PropTypes.func,
|
onLayerVisibilityToggle?(...args: unknown[]): unknown
|
||||||
onLayerVisibilityToggle: PropTypes.func,
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
class LayerListItem extends React.Component<LayerListItemProps> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
visibility: 'visible',
|
visibility: 'visible',
|
||||||
@@ -102,12 +107,12 @@ class LayerListItem extends React.Component {
|
|||||||
return <li
|
return <li
|
||||||
id={this.props.id}
|
id={this.props.id}
|
||||||
key={this.props.layerId}
|
key={this.props.layerId}
|
||||||
onClick={e => this.props.onLayerSelect(this.props.layerIndex)}
|
onClick={_e => this.props.onLayerSelect(this.props.layerIndex)}
|
||||||
data-wd-key={"layer-list-item:"+this.props.layerId}
|
data-wd-key={"layer-list-item:"+this.props.layerId}
|
||||||
className={classnames({
|
className={classnames({
|
||||||
"maputnik-layer-list-item": true,
|
"maputnik-layer-list-item": true,
|
||||||
"maputnik-layer-list-item-selected": this.props.isSelected,
|
"maputnik-layer-list-item-selected": this.props.isSelected,
|
||||||
[this.props.className]: true,
|
[this.props.className!]: true,
|
||||||
})}>
|
})}>
|
||||||
<DraggableLabel {...this.props} />
|
<DraggableLabel {...this.props} />
|
||||||
<span style={{flexGrow: 1}} />
|
<span style={{flexGrow: 1}} />
|
||||||
@@ -115,25 +120,25 @@ class LayerListItem extends React.Component {
|
|||||||
wdKey={"layer-list-item:"+this.props.layerId+":delete"}
|
wdKey={"layer-list-item:"+this.props.layerId+":delete"}
|
||||||
action={'delete'}
|
action={'delete'}
|
||||||
classBlockName="delete"
|
classBlockName="delete"
|
||||||
onClick={e => this.props.onLayerDestroy(this.props.layerIndex)}
|
onClick={_e => this.props.onLayerDestroy!(this.props.layerIndex)}
|
||||||
/>
|
/>
|
||||||
<IconAction
|
<IconAction
|
||||||
wdKey={"layer-list-item:"+this.props.layerId+":copy"}
|
wdKey={"layer-list-item:"+this.props.layerId+":copy"}
|
||||||
action={'duplicate'}
|
action={'duplicate'}
|
||||||
classBlockName="duplicate"
|
classBlockName="duplicate"
|
||||||
onClick={e => this.props.onLayerCopy(this.props.layerIndex)}
|
onClick={_e => this.props.onLayerCopy!(this.props.layerIndex)}
|
||||||
/>
|
/>
|
||||||
<IconAction
|
<IconAction
|
||||||
wdKey={"layer-list-item:"+this.props.layerId+":toggle-visibility"}
|
wdKey={"layer-list-item:"+this.props.layerId+":toggle-visibility"}
|
||||||
action={visibilityAction}
|
action={visibilityAction}
|
||||||
classBlockName="visibility"
|
classBlockName="visibility"
|
||||||
classBlockModifier={visibilityAction}
|
classBlockModifier={visibilityAction}
|
||||||
onClick={e => this.props.onLayerVisibilityToggle(this.props.layerIndex)}
|
onClick={_e => this.props.onLayerVisibilityToggle!(this.props.layerIndex)}
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const LayerListItemSortable = SortableElement((props) => <LayerListItem {...props} />);
|
const LayerListItemSortable = SortableElement((props: LayerListItemProps) => <LayerListItem {...props} />);
|
||||||
|
|
||||||
export default LayerListItemSortable;
|
export default LayerListItemSortable;
|
||||||
Reference in New Issue
Block a user