Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chore] Refactored map control and decoupled action components #1552

Merged
merged 2 commits into from
Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/demo-app/src/factories/map-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function CustomMapControlFactory(...deps) {
const StyledMapControlOverlay = styled.div`
position: absolute;
top: ${props => props.top}px;
right: 0px;
right: 0;
z-index: 1;
`;

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -283,4 +283,4 @@
"volta": {
"node": "12.19.0"
}
}
}
16 changes: 10 additions & 6 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,15 @@ export {default as MapPopoverFactory} from './map/map-popover';
export {default as MapControlFactory} from './map/map-control';
export {default as LayerHoverInfoFactory} from './map/layer-hover-info';
export {default as CoordinateInfoFactory} from './map/coordinate-info';
export {
Toggle3dButtonFactory,
MapDrawPanelFactory,
SplitMapButtonFactory,
MapLegendPanelFactory
} from './map/map-control';
export {default as LayerSelectorPanelFactory} from './map/layer-selector-panel';
export {default as LocalePanelFactory} from './map/locale-panel';
export {default as MapControlPanelFactory} from './map/map-control-panel';
export {default as MapControlTooltipFactory} from './map/map-control-tooltip';
export {default as MapLegendFactory} from './map/map-legend';
export {default as MapDrawPanelFactory} from './map/map-draw-panel';
export {default as SplitMapButtonFactory} from './map/split-map-button';
export {default as MapLegendPanelFactory} from './map/map-legend-panel';
export {default as Toggle3dButtonFactory} from './map/toggle-3d-button';

// // modal factories
export {default as ModalDialogFactory} from './modals/modal-dialog';
Expand Down Expand Up @@ -187,6 +190,7 @@ export {default as MapLegend} from 'components/map/map-legend';

export * from './common/styled-components';
import * as Icons from './common/icons';

export {Icons};

// Individual Component from Dependency Tree
Expand Down
15 changes: 15 additions & 0 deletions src/components/map/layer-selector-panel.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import {Layer} from 'layers';
import {MapControls} from 'reducers/ui-state-updaters';

export type LayerSelectorPanelProps = {
onMapToggleLayer: (layerId: string) => void;
onToggleMapControl: (control: string) => void;
layers: ReadonlyArray<Layer>;
layersToRender: {[key: string]: boolean};
isSplit: boolean;
mapControls: MapControls;
readOnly: boolean;
};

export type LayerSelectorPanelComponent = React.FunctionComponent<LayerSelectorPanelProps>;
83 changes: 83 additions & 0 deletions src/components/map/layer-selector-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, {useCallback, useMemo} from 'react';
import {MapControlButton} from 'components/common/styled-components';
import {Layers} from '../common/icons';
import MapLayerSelector from '../common/map-layer-selector';
import MapControlTooltipFactory from './map-control-tooltip';
import MapControlPanelFactory from './map-control-panel';

LayerSelectorPanelFactory.deps = [MapControlTooltipFactory, MapControlPanelFactory];

function LayerSelectorPanelFactory(MapControlTooltip, MapControlPanel) {
/** @type {import('./layer-selector-panel').LayerSelectorPanelComponent} */
const LayerSelectorPanel = ({
onMapToggleLayer,
onToggleMapControl,
layers,
layersToRender,
isSplit,
mapControls,
readOnly
}) => {
const visibleLayers = mapControls?.visibleLayers || {};
const {active: isActive, show, disableClose} = visibleLayers;

const legendLayers = useMemo(
() =>
layers
.filter(({config}) => config.isVisible)
.map(({id, config}) => ({
id,
name: config.label,
// layer
isVisible: layersToRender[id]
})),
[layers, layersToRender]
);

const isVisible = useMemo(() => isSplit && show && readOnly !== true, [
isSplit,
show,
readOnly
]);

const onToggleMenuPanel = useCallback(
event => {
event.preventDefault();
onToggleMapControl('visibleLayers');
},
[onToggleMapControl]
);

return isVisible ? (
(!isActive ? (
<MapControlButton
key={1}
onClick={onToggleMenuPanel}
className="map-control-button toggle-layer"
data-tip
data-for="toggle-layer"
>
<Layers height="22px" />
<MapControlTooltip
id="toggle-layer"
message={isActive ? 'tooltip.hideLayerPanel' : 'tooltip.showLayerPanel'}
/>
</MapControlButton>
) : (
<MapControlPanel
header="header.visibleLayers"
onClick={onToggleMenuPanel}
disableClose={disableClose}
>
<MapLayerSelector layers={legendLayers} onMapToggleLayer={onMapToggleLayer} />
</MapControlPanel>
))
) : null;
};

LayerSelectorPanel.displayName = 'LayerSelectorPanel';

return React.memo(LayerSelectorPanel);
}

export default LayerSelectorPanelFactory;
12 changes: 12 additions & 0 deletions src/components/map/locale-panel.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import {MapControls} from '../../reducers';

export type LocalePanelProps = {
availableLocales: ReadnlyArray<string>;
onSetLocale: (locale: string) => void;
locale: string;
onToggleMenuPanel: () => void;
mapControls: MapControls;
};

export type LocalePanelComponent = React.FunctionComponent<LocalePanelProps>;
73 changes: 73 additions & 0 deletions src/components/map/locale-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, {useCallback} from 'react';
import ToolbarItem from 'components/common/toolbar-item';
import {MapControlButton} from 'components/common/styled-components';
import MapControlTooltipFactory from './map-control-tooltip';
import MapControlPanelFactory from './map-control-panel';
import MapControlToolbarFactory from './map-control-toolbar';

LocalePanelFactory.deps = [
MapControlTooltipFactory,
MapControlPanelFactory,
MapControlToolbarFactory
];

function LocalePanelFactory(MapControlTooltip, MapControlPanel, MapControlToolbar) {
/** @type {import('./locale-panel').LocalePanelComponent} */
const LocalePanel = React.memo(
({availableLocales, onToggleMenuPanel, onSetLocale, locale: currentLocal, mapControls}) => {
const {active: isActive, disableClose} = mapControls.mapLocale || {};

const onClickItem = useCallback(
locale => {
onSetLocale(locale);
},
[onSetLocale]
);

const onClickButton = useCallback(
e => {
e.preventDefault();
onToggleMenuPanel();
},
[onToggleMenuPanel]
);
const getLabel = useCallback(locale => `toolbar.${locale}`, []);

if (!mapControls.mapLocale) {
return null;
}
return (
<div style={{position: 'relative'}}>
{isActive ? (
<MapControlToolbar show={isActive}>
{availableLocales.map(locale => (
<ToolbarItem
key={locale}
onClick={() => onClickItem(locale)}
label={getLabel(locale)}
active={currentLocal === locale}
/>
))}
</MapControlToolbar>
) : null}
<MapControlButton
onClick={onClickButton}
active={isActive}
data-tip
data-for="locale"
disableClose={disableClose}
>
{currentLocal.toUpperCase()}
<MapControlTooltip id="locale" message="tooltip.selectLocale" />
</MapControlButton>
</div>
);
}
);

LocalePanel.displayName = 'LocalePanel';

return LocalePanel;
}

export default LocalePanelFactory;
11 changes: 11 additions & 0 deletions src/components/map/map-control-panel.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

export type MapControlPanelProps = {
header?: string;
scale?: number;
onClick: () => void;
isExport?: boolean;
logoComponent?: Element;
};

export type MapControlPanelComponent = React.FunctionComponent<MapControlPanelProps>;
78 changes: 78 additions & 0 deletions src/components/map/map-control-panel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';
import styled from 'styled-components';
import {FormattedMessage} from 'localization';
import {IconRoundSmall} from 'components/common/styled-components';
import {Close} from 'components/common/icons';

const StyledMapControlPanel = styled.div`
background-color: ${props => props.theme.mapPanelBackgroundColor};
flex-grow: 1;
z-index: 1;
p {
margin-bottom: 0;
}
`;

const StyledMapControlPanelContent = styled.div.attrs({
className: 'map-control__panel-content'
})`
${props => props.theme.dropdownScrollBar};
max-height: 500px;
min-height: 100px;
min-width: ${props => props.theme.mapControl.width}px;
overflow: auto;
`;

const StyledMapControlPanelHeader = styled.div.attrs({
className: 'map-control__panel-header'
})`
display: flex;
justify-content: space-between;
background-color: ${props => props.theme.mapPanelHeaderBackgroundColor};
height: 32px;
padding: 6px 12px;
font-size: 11px;
color: ${props => props.theme.titleTextColor};
position: relative;

button {
width: 18px;
height: 18px;
}
`;

function MapControlPanelFactory() {
/** @type {import('./map-control-panel').MapControlPanelComponent} */
const MapControlPanel = React.memo(
({children, header, onClick, scale = 1, isExport, logoComponent}) => (
<StyledMapControlPanel
style={{
transform: `scale(${scale})`,
marginBottom: '8px'
}}
>
<StyledMapControlPanelHeader>
{isExport && logoComponent ? (
logoComponent
) : header ? (
<span style={{verticalAlign: 'middle'}}>
<FormattedMessage id={header} />
</span>
) : null}
{isExport ? null : (
<IconRoundSmall className="close-map-control-item" onClick={onClick}>
<Close height="16px" />
</IconRoundSmall>
)}
</StyledMapControlPanelHeader>
<StyledMapControlPanelContent>{children}</StyledMapControlPanelContent>
</StyledMapControlPanel>
)
);

MapControlPanel.displayName = 'MapControlPanel';

return MapControlPanel;
}

export default MapControlPanelFactory;
13 changes: 13 additions & 0 deletions src/components/map/map-control-toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import styled from 'styled-components';
import VerticalToolbar from '../common/vertical-toolbar';

function MapControlToolbar() {
const StyledToolbar = styled(VerticalToolbar)`
position: absolute;
right: 32px;
`;

return StyledToolbar;
}

export default MapControlToolbar;
8 changes: 8 additions & 0 deletions src/components/map/map-control-tooltip.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

export type MapControlTooltipProps = {
id: string;
message: string;
};

export type MapControlTooltipComponent = React.FunctionComponent<MapControlTooltipProps>;
20 changes: 20 additions & 0 deletions src/components/map/map-control-tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import {Tooltip} from '..';
import {FormattedMessage} from 'localization';

function MapControlTooltipFactory() {
/** @type {import('./map-control-tooltip').MapControlTooltipComponent} */
const MapControlTooltip = React.memo(({id, message}) => (
<Tooltip id={id} place="left" effect="solid">
<span>
<FormattedMessage id={message} />
</span>
</Tooltip>
));

MapControlTooltip.displayName = 'MapControlTooltip';

return MapControlTooltip;
}

export default MapControlTooltipFactory;