Skip to content

Commit

Permalink
[feat] Introduced dnd-context factory to better override dnd properti…
Browse files Browse the repository at this point in the history
…es (keplergl#2364)

Signed-off-by: Ihor Dykhta <[email protected]>
Co-authored-by: Giuseppe Macrì <[email protected]>
  • Loading branch information
igorDykhta and macrigiuseppe authored Oct 10, 2023
1 parent 673646a commit c798961
Show file tree
Hide file tree
Showing 18 changed files with 248 additions and 233 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package-lock.json

npm-debug.log
.history/
.yarn

.pnp.*
.yarn/*
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"test-browser-drive": "NODE_ENV=test node ./test/browser-drive.js debug",
"test-node-debug": "NODE_ENV=test node -r ./babel-register.js ./test/node.js",
"test-browser-debug": "NODE_ENV=test node -r ./babel-register.js ./test/setup-browser-env.js ./test/js-dom.js",
"test-jest": "jest --watch",
"test-jest": "jest",
"test-tape": "yarn test-node && yarn test-browser",
"test": "yarn test-jest && yarn test-tape",
"cover-tape": "nyc --reporter=json --report-dir=tape-coverage --reporter=html yarn test-tape",
Expand Down
8 changes: 4 additions & 4 deletions src/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
"dependencies": {
"@deck.gl/core": "^8.9.12",
"@deck.gl/react": "^8.9.12",
"@dnd-kit/core": "^6.0.5",
"@dnd-kit/modifiers": "^6.0.0",
"@dnd-kit/sortable": "^7.0.1",
"@dnd-kit/utilities": "^3.2.0",
"@dnd-kit/core": "^6.0.8",
"@dnd-kit/modifiers": "^6.0.1",
"@dnd-kit/sortable": "^7.0.2",
"@dnd-kit/utilities": "^3.2.1",
"@kepler.gl/actions": "3.0.0-alpha.0",
"@kepler.gl/cloud-providers": "3.0.0-alpha.0",
"@kepler.gl/constants": "3.0.0-alpha.0",
Expand Down
1 change: 1 addition & 0 deletions src/components/src/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const KeplerGlContext = createContext({
id: 'map'
});

// TODO: breakdown this file into multiple files
export const FeatureFlagsContext = createContext<object | null>({});

export type FeatureFlags = {[key: string]: string | boolean};
Expand Down
151 changes: 151 additions & 0 deletions src/components/src/dnd-context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React, {useCallback, useMemo, useState, PropsWithChildren} from 'react';
import styled from 'styled-components';
import {DndContext as DndKitContext, DragOverlay} from '@dnd-kit/core';
import {useDispatch} from 'react-redux';
import {
DND_EMPTY_MODIFIERS,
DND_MODIFIERS,
DROPPABLE_MAP_CONTAINER_TYPE,
SORTABLE_LAYER_TYPE,
SORTABLE_SIDE_PANEL_TYPE
} from '@kepler.gl/constants';
import {layerConfigChange, reorderLayer, toggleLayerForMap} from '@kepler.gl/actions';
import LayerPanelHeaderFactory from './side-panel/layer-panel/layer-panel-header';
import {withState} from './injector';
import {visStateLens} from '@kepler.gl/reducers';
import {reorderLayerOrder} from '@kepler.gl/reducers';
import {VisState} from '@kepler.gl/schemas';
import {Layer} from '@kepler.gl/layers';

export type DndContextProps = PropsWithChildren<{
visState: VisState;
}>;

export type DndContextComponent = React.FC<DndContextProps>;

export const DragItem = styled.div`
color: ${props => props.theme.textColorHl};
border-radius: ${props => props.theme.radioButtonRadius}px;
padding: 5px 10px;
display: inline;
`;

const nop = () => undefined;

DndContextFactory.deps = [LayerPanelHeaderFactory];

function DndContextFactory(
LayerPanelHeader: ReturnType<typeof LayerPanelHeaderFactory>
): React.FC<PropsWithChildren> {
const LayerPanelOverlay = ({layer, datasets}) => {
const color =
layer.config.dataId && datasets[layer.config.dataId]
? datasets[layer.config.dataId].color
: null;
return (
<LayerPanelHeader
isConfigActive={false}
layerId={layer.id}
isVisible={true}
isValid={true}
label={layer.config.label}
labelRCGColorValues={color}
onToggleVisibility={nop}
onResetIsValid={nop}
onUpdateLayerLabel={nop}
onToggleEnableConfig={nop}
onDuplicateLayer={nop}
onRemoveLayer={nop}
layerType={layer.type}
allowDuplicate={false}
isDragNDropEnabled={false}
/>
);
};

const DndContext = ({children, visState}: DndContextProps) => {
const {datasets, layerOrder, layers, splitMaps} = visState;

const [activeLayer, setActiveLayer]: [
Layer | undefined,
(l: Layer | undefined) => void
] = useState();

const dispatch = useDispatch();

const isSplit = useMemo(() => splitMaps?.length > 1, [splitMaps]);
const dndModifiers = useMemo(() => (isSplit ? DND_EMPTY_MODIFIERS : DND_MODIFIERS), [isSplit]);
const onDragStart = useCallback(
event => {
const {active} = event;
const newActiveLayer = layers.find(layer => layer.id === active.id);
if (newActiveLayer) {
setActiveLayer(newActiveLayer);

if (newActiveLayer?.config.isConfigActive) {
dispatch(layerConfigChange(newActiveLayer, {isConfigActive: false}));
}
}
},
[dispatch, layers]
);

const onDragEnd = useCallback(
event => {
const {active, over} = event;

const {id: activeLayerId} = active;
const overType = over.data.current?.type;

if (!overType) {
setActiveLayer(undefined);
return;
}

switch (overType) {
// moving layers into maps
case DROPPABLE_MAP_CONTAINER_TYPE:
const mapIndex = over.data.current?.index ?? 0;
dispatch(toggleLayerForMap(mapIndex, activeLayerId));
break;
// swaping layers
case SORTABLE_LAYER_TYPE:
const newLayerOrder = reorderLayerOrder(layerOrder, activeLayerId, over.id);
dispatch(reorderLayer(newLayerOrder));
break;
// moving layers within side panel
case SORTABLE_SIDE_PANEL_TYPE:
// move layer to the end of the list
dispatch(
reorderLayer(
reorderLayerOrder(layerOrder, activeLayerId, layerOrder[layerOrder.length - 1])
)
);
break;
default:
break;
}

setActiveLayer(undefined);
},
[dispatch, layerOrder]
);

return (
<DndKitContext onDragStart={onDragStart} onDragEnd={onDragEnd} modifiers={dndModifiers}>
{children}
{activeLayer ? (
<DragOverlay modifiers={dndModifiers} dropAnimation={null}>
<DragItem>
<LayerPanelOverlay layer={activeLayer} datasets={datasets} />
</DragItem>
</DragOverlay>
) : null}
</DndKitContext>
);
};

return withState([visStateLens], state => state)(DndContext) as React.FC<PropsWithChildren>;
}

export default DndContextFactory;
26 changes: 0 additions & 26 deletions src/components/src/dnd-layer-items.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ export {default as LayerGroupSelectorFactory} from './side-panel/map-style-panel
export {default as MapStyleSelectorFactory} from './side-panel/map-style-panel/map-style-selector';
export {default as LayerGroupColorPickerFactory} from './side-panel/map-style-panel/map-layer-group-color-picker';
export {default as CustomPanelsFactory} from './side-panel/custom-panel';
export {default as DndContextFactory} from './dnd-context';

// // map factories
export {default as MapPopoverFactory} from './map/map-popover';
export {default as MapPopoverContentFactory} from './map/map-popover-content';
Expand Down Expand Up @@ -294,6 +296,7 @@ export type {PanelMeta} from './side-panel/common/types';
export type {SideBarProps} from './side-panel/side-bar';
export type {FeatureActionPanelProps} from './editor/feature-action-panel';
export type {SingleColorPaletteProps} from './side-panel/layer-panel/single-color-palette';
export type {DndContextProps, DndContextComponent} from './dnd-context';

export {
Icons,
Expand Down
Loading

0 comments on commit c798961

Please sign in to comment.