Skip to content

Commit

Permalink
redesign implementation of StickyMap
Browse files Browse the repository at this point in the history
  • Loading branch information
sheppard committed Jul 9, 2021
1 parent 40d35a3 commit 8519953
Show file tree
Hide file tree
Showing 15 changed files with 303 additions and 55 deletions.
27 changes: 27 additions & 0 deletions LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -1810,6 +1810,33 @@ In addition, the following third party dependencies are compiled into [**wq.js**
</details>

<details><summary><b><a href="https://paol-imi.github.io/react-reparenting">react-reparenting</a> 0.6.1</b></summary>

> MIT License
>
> Copyright (c) 2020 Paolo Longo
>
> 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.
>
</details>

<details><summary><b><a href="https:/reactjs/react-transition-group#readme">react-transition-group</a> 4.4.1</b> <i>(BSD-3-Clause)</i></summary>

> BSD 3-Clause License
Expand Down
8 changes: 8 additions & 0 deletions packages/map/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"homepage": "https://wq.io/@wq/map",
"dependencies": {
"@wq/react": "^1.3.0-beta.1",
"mustache": "^4.0.1"
"mustache": "^4.0.1",
"react-reparenting": "^0.6.1"
},
"devDependencies": {
"@wq/model": "^1.3.0-beta.1",
Expand Down
80 changes: 80 additions & 0 deletions packages/map/src/components/OffscreenMaps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect } from 'react';
import { useComponents, usePluginReducer } from '@wq/react';
import { createReparentableSpace } from 'react-reparenting';

const { Reparentable, sendReparentableChild } = createReparentableSpace();

export { Reparentable };

const OFFSCREEN_ID = 'offscreen-maps',
INVISIBLE_STYLE = {
position: 'absolute',
top: '-2000px',
width: '100vw',
height: 'calc(100vh - 120px)'
};

export function moveOffscreen(mapId) {
sendReparentableChild(mapId, OFFSCREEN_ID, mapId, 0);
}

export default function OffscreenMaps() {
const { AutoMap } = useComponents();
const [
{ mapId, stickyMaps, stickyMapId },
{ setStickyMapId }
] = usePluginReducer('map');

useEffect(() => {
if ((!mapId && !stickyMapId) || mapId === stickyMapId) {
return;
}

if (stickyMapId) {
moveOffscreen(stickyMapId);
}

if (
mapId &&
stickyMaps &&
stickyMaps[mapId] &&
stickyMaps[mapId].props
) {
sendReparentableChild(OFFSCREEN_ID, mapId, mapId, 0);
setStickyMapId(mapId);
} else {
setStickyMapId(null);
}
}, [mapId, stickyMapId, stickyMaps]);

return (
<div style={INVISIBLE_STYLE}>
<Reparentable id={OFFSCREEN_ID}>
{Object.entries(stickyMaps || {}).map(
([
mapId,
{
props: {
containerStyle,
invisibleStyle,
state
} = {}
}
]) =>
mapId !== stickyMapId &&
state && (
<AutoMap
key={mapId}
state={state}
containerStyle={{
...containerStyle,
...INVISIBLE_STYLE,
...invisibleStyle
}}
/>
)
)}
</Reparentable>
</div>
);
}
78 changes: 51 additions & 27 deletions packages/map/src/components/StickyMap.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,68 @@
import React, { useState, useEffect } from 'react';
import { useComponents } from '@wq/react';
import { useMapState } from '../hooks';
import React, { useEffect } from 'react';
import { useComponents, usePluginReducer } from '@wq/react';
import PropTypes from 'prop-types';
import { Reparentable, moveOffscreen } from './OffscreenMaps';

export default function StickyMap({
mapId,
containerStyle,
invisibleStyle,
children
}) {
const state = useMapState(),
{ AutoMap } = useComponents(),
[stickyState, setStickyState] = useState(null),
visible = state && mapId && state.mapId === mapId;
const [mapState, { setStickyProps }] = usePluginReducer('map'),
{ stickyMapId, stickyMaps } = mapState,
currentProps =
stickyMaps && stickyMaps[mapId] && stickyMaps[mapId].props,
{ AutoMap } = useComponents();

useEffect(() => {
if (visible) {
setStickyState(state);
if (mapState.mapId !== mapId) {
return;
}
}, [visible, state]);

if (!stickyState) {
return null;
}

if (!visible) {
containerStyle = {
...containerStyle,
position: 'absolute',
top: '-2000px',
width: '100vw',
height: 'calc(100vh - 120px)',
...invisibleStyle

const nextState = {};
Object.keys(mapState).forEach(key => {
if (key === 'stickyMapId' || key === 'stickyMaps') {
return;
}
nextState[key] = mapState[key];
});

if (
currentProps &&
currentProps.containerStyle === containerStyle &&
currentProps.invisibleStyle === invisibleStyle &&
Object.keys(nextState).every(
key => nextState[key] === currentProps.state[key]
)
) {
return;
}

setStickyProps({
containerStyle,
invisibleStyle,
state: nextState
});
}, [
mapId,
mapState,
currentProps,
containerStyle,
invisibleStyle,
children
]);

useEffect(() => {
return () => {
moveOffscreen(mapId);
};
}
}, [mapId]);

return (
<AutoMap containerStyle={containerStyle} state={stickyState}>
{children}
</AutoMap>
<Reparentable id={mapId}>
{mapId === stickyMapId && <AutoMap key={mapId} {...currentProps} />}
</Reparentable>
);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/map/src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AutoMap from './AutoMap';
import AutoBasemap from './AutoBasemap';
import AutoOverlay from './AutoOverlay';
import StickyMap from './StickyMap';
import OffscreenMaps from './OffscreenMaps';
import Map from './Map';
import Legend, { BasemapToggle, OverlayToggle } from './Legend';
import GeoTools from './GeoTools';
Expand All @@ -11,6 +12,7 @@ export {
AutoBasemap,
AutoOverlay,
StickyMap,
OffscreenMaps,
Map,
Legend,
BasemapToggle,
Expand Down
7 changes: 6 additions & 1 deletion packages/map/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import {
AutoBasemap,
AutoOverlay,
StickyMap,
OffscreenMaps,
GeoTools
} from './components/index';
import { Geo, EmbeddedGeo } from './inputs/index';
import { GeoHelp, GeoLocate, GeoCode, GeoCoords } from './geotools/index';
import { DefaultList, DefaultDetail } from './views/index';

export default map;

Expand All @@ -38,11 +40,14 @@ export {
AutoBasemap,
AutoOverlay,
StickyMap,
OffscreenMaps,
GeoTools,
Geo,
EmbeddedGeo,
GeoHelp,
GeoLocate,
GeoCode,
GeoCoords
GeoCoords,
DefaultList,
DefaultDetail
};
27 changes: 19 additions & 8 deletions packages/map/src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AutoBasemap,
AutoOverlay,
StickyMap,
OffscreenMaps,
Map,
Legend,
BasemapToggle,
Expand All @@ -11,8 +12,11 @@ import {
} from './components/index';
import { Geo, EmbeddedGeo } from './inputs/index';
import { GeoHelp, GeoLocate, GeoCode, GeoCoords } from './geotools/index';
import { DefaultList, DefaultDetail } from './views/index';
import reducer, {
MAP_READY,
MAP_SET_STICKY_PROPS,
MAP_SET_STICKY_ID,
MAP_SHOW_OVERLAY,
MAP_HIDE_OVERLAY,
MAP_SET_BASEMAP,
Expand All @@ -38,6 +42,18 @@ const map = {
payload: instance
};
},
setStickyProps(props) {
return {
type: MAP_SET_STICKY_PROPS,
payload: props
};
},
setStickyMapId(id) {
return {
type: MAP_SET_STICKY_ID,
payload: id
};
},
setBasemap(name) {
return {
type: MAP_SET_BASEMAP,
Expand Down Expand Up @@ -97,6 +113,7 @@ const map = {
AutoBasemap,
AutoOverlay,
StickyMap,
OffscreenMaps,
Map,
MapInteraction: () => null,
Legend,
Expand All @@ -110,6 +127,7 @@ const map = {
geotrace: Geo,
geoshape: Geo
},
views: { DefaultList, DefaultDetail },
config: {
maps: {}, // Auto-populated from app.config.pages where map == true
bounds: [
Expand Down Expand Up @@ -274,14 +292,7 @@ map.init = function (config) {
};

// Plugin API
map.runComponent = function ({ page, mode }) {
var mapconf = map.config.maps[page];
if (mapconf && mode !== 'edit' && !mapconf.mapId) {
return 'AutoMap';
} else {
return null;
}
};
map.runComponent = 'OffscreenMaps';

// FIXME: Drop this function in 2.0
map.run = function ($page, routeInfo) {
Expand Down
10 changes: 8 additions & 2 deletions packages/map/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { routeMapConf } from './hooks';

const RENDER = 'RENDER';
export const MAP_READY = 'MAP_READY',
MAP_SET_STICKY_PROPS = 'MAP_SET_STICKY_PROPS',
MAP_SET_STICKY_ID = 'MAP_SET_STICKY_ID',
MAP_SHOW_OVERLAY = 'MAP_SHOW_OVERLAY',
MAP_HIDE_OVERLAY = 'MAP_HIDE_OVERLAY',
MAP_SET_BASEMAP = 'MAP_SET_BASEMAP',
Expand Down Expand Up @@ -51,6 +53,10 @@ export default function reducer(state = {}, action, config) {
}
case MAP_READY:
return reduceMapState({ ...state, instance: action.payload });
case MAP_SET_STICKY_PROPS:
return reduceMapState(state, { props: action.payload });
case MAP_SET_STICKY_ID:
return { ...state, stickyMapId: action.payload };
case MAP_SHOW_OVERLAY:
return {
...state,
Expand Down Expand Up @@ -267,15 +273,15 @@ function checkEmpty(geojson) {
}
}

function reduceMapState(state) {
function reduceMapState(state, stickyState) {
const { mapId, instance, highlight } = state;
if (mapId) {
const stickyMaps = state.stickyMaps || {};
return {
...state,
stickyMaps: {
...stickyMaps,
[mapId]: { instance, highlight }
[mapId]: { instance, highlight, ...stickyState }
}
};
} else {
Expand Down
Loading

0 comments on commit 8519953

Please sign in to comment.