// Copyright (c) 2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import React, {useCallback, useMemo} from 'react'; import {FormattedMessage} from 'localization'; import { EXPORT_DATA_ID, EXPORT_MAP_ID, SHARE_MAP_ID, SIDEBAR_PANELS, OVERWRITE_MAP_ID, SAVE_MAP_ID, EXPORT_IMAGE_ID, ADD_DATA_ID, ADD_MAP_STYLE_ID } from 'constants/default-settings'; import SidebarFactory from './side-panel/side-bar'; import PanelHeaderFactory from './side-panel/panel-header'; import PanelToggleFactory from './side-panel/panel-toggle'; import LayerManagerFactory from './side-panel/layer-manager'; import FilterManagerFactory from './side-panel/filter-manager'; import InteractionManagerFactory from './side-panel/interaction-manager'; import MapManagerFactory from './side-panel/map-manager'; import CustomPanelsFactory from './side-panel/custom-panel'; import PanelTitleFactory from './side-panel/panel-title'; import styled from 'styled-components'; import get from 'lodash/get'; import {SidePanelProps} from './types'; export const StyledSidePanelContent = styled.div` ${props => props.theme.sidePanelScrollBar}; flex-grow: 1; padding: ${props => props.theme.sidePanelInnerPadding}px; overflow-y: scroll; overflow-x: hidden; .side-panel__content__inner { display: flex; height: 100%; flex-direction: column; } `; const StyledSidePanelSpacer = styled.div.attrs({className: 'side-panel__content__spacer'})` flex-grow: 1; `; SidePanelFactory.deps = [ SidebarFactory, PanelHeaderFactory, PanelToggleFactory, PanelTitleFactory, LayerManagerFactory, FilterManagerFactory, InteractionManagerFactory, MapManagerFactory, CustomPanelsFactory ]; /** * Vertical sidebar containing input components for the rendering layers */ export default function SidePanelFactory( Sidebar: ReturnType, PanelHeader: ReturnType, PanelToggle: ReturnType, PanelTitle: ReturnType, LayerManager: ReturnType, FilterManager: ReturnType, InteractionManager: ReturnType, MapManager: ReturnType, CustomPanels: ReturnType ) { // inject components const SIDEBAR_COMPONENTS = { layer: LayerManager, filter: FilterManager, interaction: InteractionManager, map: MapManager }; // We should defined sidebar panels here but keeping them for backward compatible const fullPanels = SIDEBAR_PANELS.map(component => ({ ...component, component: SIDEBAR_COMPONENTS[component.id] })); const getCustomPanelProps = get(CustomPanels, ['defaultProps', 'getProps']) || (() => ({})); const SidePanel = (props: SidePanelProps) => { const { appName, appWebsite, availableProviders, datasets, filters, layers, layerBlending, layerClasses, layerOrder, interactionConfig, panels, mapInfo, mapSaved, mapStateActions, mapStyle, mapStyleActions, onSaveMap, uiState, uiStateActions, visStateActions, version, width } = props; const {openDeleteModal, toggleModal, toggleSidePanel} = uiStateActions; const {activeSidePanel} = uiState; const {setMapInfo, showDatasetTable, updateTableColor} = visStateActions; const {hasShare, hasStorage} = availableProviders; const {title} = mapInfo; const isOpen = Boolean(activeSidePanel); const _onOpenOrClose = useCallback(() => toggleSidePanel(activeSidePanel ? '' : 'layer'), [ activeSidePanel, toggleSidePanel ]); const onClickExportImage = useCallback(() => toggleModal(EXPORT_IMAGE_ID), [toggleModal]); const onClickExportData = useCallback(() => toggleModal(EXPORT_DATA_ID), [toggleModal]); const onClickExportMap = useCallback(() => toggleModal(EXPORT_MAP_ID), [toggleModal]); const onClickSaveToStorage = useCallback( () => toggleModal(mapSaved ? OVERWRITE_MAP_ID : SAVE_MAP_ID), [mapSaved, toggleModal] ); const onClickSaveAsToStorage = useCallback(() => { setMapInfo({ title: `${title || 'Kepler.gl'} (Copy)` }); toggleModal(SAVE_MAP_ID); }, [title, setMapInfo, toggleModal]); const onClickShareMap = useCallback(() => toggleModal(SHARE_MAP_ID), [toggleModal]); const onShowDatasetTable = useCallback(dataId => showDatasetTable(dataId), [showDatasetTable]); const onUpdateTableColor = useCallback( (dataId, newColor) => updateTableColor(dataId, newColor), [updateTableColor] ); const onShowAddDataModal = useCallback(() => toggleModal(ADD_DATA_ID), [toggleModal]); const onShowAddMapStyleModal = useCallback(() => toggleModal(ADD_MAP_STYLE_ID), [toggleModal]); const onRemoveDataset = useCallback(dataId => openDeleteModal(dataId), [openDeleteModal]); const onSaveToStorage = useMemo(() => (hasStorage ? onClickSaveToStorage : null), [ hasStorage, onClickSaveToStorage ]); const onSaveAsToStorage = useMemo( () => (hasStorage && mapSaved ? onClickSaveAsToStorage : null), [hasStorage, mapSaved, onClickSaveAsToStorage] ); const currentPanel = useMemo(() => panels.find(({id}) => id === activeSidePanel), [ activeSidePanel, panels ]); const onShareMap = useMemo(() => (hasShare ? onClickShareMap : null), [ hasShare, onClickShareMap ]); const customPanelProps = useMemo(() => getCustomPanelProps(props), [props]); const PanelComponent = currentPanel?.component; return ( {/* the next two components should be moved into one */} {/* but i am keeping them because of backward compatibility */}
{currentPanel?.id !== 'layer' ? ( ) : null} {PanelComponent ? ( <> ) : null}
); }; SidePanel.defaultProps = { panels: fullPanels, sidebarComponents: SIDEBAR_COMPONENTS, uiState: {}, visStateActions: {}, mapStyleActions: {}, uiStateActions: {}, availableProviders: {}, mapInfo: {} }; return SidePanel; }