Skip to content

Commit

Permalink
Add Mapkit support in the editor (#29252)
Browse files Browse the repository at this point in the history
* Cherry-pick hook

* Cherry-pick

* WIP

* Markers & info window

* WIP useEffect dependency cleanup

* - MapRef for resizing
- Better zooming for multiple markers

* Some cleanup

* - Disable zoom control on map when we have more than 1 point

* Sane defaults when adding a map

* Remove TODO

* Add changelog

* Merge with location search

* Make check for mapRef more compact

* Rename createCalloutElement to createCalloutElementCallback

* Update style code styling

* Remove todo and add linebreak between import & function call

* Code style fix

* InfoWindow renaming

* Remove commented out console.log

* Mapkit doesn't have id's for places returned, so create one

* Fix resizing doing bad things
  • Loading branch information
TimBroddin authored Mar 7, 2023
1 parent a3f104f commit 8b79eab
Show file tree
Hide file tree
Showing 19 changed files with 592 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: enhancement

Editor support for Mapkit in the Map block
15 changes: 15 additions & 0 deletions projects/plugins/jetpack/extensions/blocks/map/component/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { forwardRef } from '@wordpress/element';
import { getMapProvider } from '../utils';
import MapboxComponent from './mapbox';
import MapkitComponent from './mapkit';

const MapComponent = forwardRef( ( props, ref ) => {
const mapProvider = getMapProvider();
if ( mapProvider === 'mapkit' && props.mapStyle !== 'terrain' ) {
const mapkitProps = { ...props, ref: null };
return <MapkitComponent { ...mapkitProps } ref={ ref } />;
}
return <MapboxComponent { ...props } ref={ ref } />;
} );

export default MapComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getMapProvider } from '../../utils';
import MapboxInfoWindow from './mapbox';
import MapkitInfoWindow from './mapkit';

const InfoWindow = props => {
const mapProvider = getMapProvider();
if ( mapProvider === 'mapkit' ) {
return <MapkitInfoWindow { ...props } />;
}
return <MapboxInfoWindow { ...props } />;
};

export default InfoWindow;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, createPortal } from '@wordpress/element';
import { createInfoWindowPopup } from '../mapbox-utils';
import { createInfoWindowPopup } from '../../mapbox-utils';

export class InfoWindow extends Component {
componentDidMount() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Button, Dashicon, TextareaControl, TextControl } from '@wordpress/components';
import { createPortal, Fragment, useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useMapkit } from '../../mapkit/hooks';

const InfoWindow = () => {
const { activeMarker, setActiveMarker, calloutReference, admin, points, setPoints } = useMapkit();
const [ pointsCopy, setPointsCopy ] = useState( points );
const [ isDirty, setIsDirty ] = useState( false );
const { title, caption } = pointsCopy.find( p => p.id === activeMarker?.id ) || {};

const updateActiveMarker = value => {
const newPoints = points.map( point => {
if ( point.id === activeMarker.id ) {
return { ...point, ...value };
}
return point;
} );
setPointsCopy( newPoints );
setIsDirty( true );
};

const deleteActiveMarker = () => {
const newPoints = points.filter( point => point.id !== activeMarker.id );
setPointsCopy( newPoints );
setIsDirty( true );
// force closing of window
setActiveMarker( null );
};

useEffect( () => {
if ( ! activeMarker && isDirty ) {
// commit the points when callout is closed, and content is dirty
setPoints( pointsCopy );
}
}, [ activeMarker, isDirty, pointsCopy, setPoints ] );

useEffect( () => {
setPointsCopy( points );
setIsDirty( false );
}, [ points ] );

if ( ! activeMarker || ! calloutReference ) {
return null;
}

return createPortal(
<Fragment>
{ admin && (
<Fragment>
<TextControl
label={ __( 'Marker Title', 'jetpack' ) }
value={ title }
onChange={ value => updateActiveMarker( { title: value } ) }
/>
<TextareaControl
className="wp-block-jetpack-map__marker-caption"
label={ __( 'Marker Caption', 'jetpack' ) }
value={ caption }
rows="2"
tag="textarea"
onChange={ value => updateActiveMarker( { caption: value } ) }
/>
<Button onClick={ deleteActiveMarker } className="wp-block-jetpack-map__delete-btn">
<Dashicon icon="trash" size="15" /> { __( 'Delete Marker', 'jetpack' ) }
</Button>
</Fragment>
) }

{ ! admin && (
<Fragment>
<h3>{ title }</h3>
<p>{ caption }</p>
</Fragment>
) }
</Fragment>,
calloutReference
);
};

InfoWindow.defaultProps = {};

export default InfoWindow;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component } from '@wordpress/element';
import { getLoadContext } from '../../../shared/block-editor-asset-loader';
import { setMarkerHTML } from '../mapbox-utils';
import { getLoadContext } from '../../../../shared/block-editor-asset-loader';
import { setMarkerHTML } from '../../mapbox-utils';

import './style.scss';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {
getLoadContext,
loadBlockEditorAssets,
waitForObject,
} from '../../shared/block-editor-asset-loader';
import editorAssets from './block-editor-assets.json';
import InfoWindow from './info-window/';
import MapMarker from './map-marker/';
import { mapboxMapFormatter } from './mapbox-map-formatter/';
import { fitMapToBounds, getMapBounds, googlePoint2Mapbox } from './mapbox-utils';
import { resizeMapContainer } from './utils';
} from '../../../shared/block-editor-asset-loader';
import editorAssets from '../block-editor-assets.json';
import { mapboxMapFormatter } from '../mapbox-map-formatter';
import { fitMapToBounds, getMapBounds, googlePoint2Mapbox } from '../mapbox-utils';
import { resizeMapContainer } from '../utils';
import InfoWindow from './info-window';
import MapMarker from './map-marker';

export class Map extends Component {
export class MapBoxComponent extends Component {
// Lifecycle
constructor() {
super( ...arguments );
Expand Down Expand Up @@ -212,7 +212,6 @@ export class Map extends Component {
const { map } = this.state;

map.setZoom( zoom );
map.updateZoom( zoom );
};
setBoundsByMarkers = () => {
const { admin, onSetMapCenter, onSetZoom, points, zoom } = this.props;
Expand Down Expand Up @@ -371,7 +370,7 @@ export class Map extends Component {
}
}

Map.defaultProps = {
MapBoxComponent.defaultProps = {
points: [],
mapStyle: 'default',
zoom: 13,
Expand All @@ -385,4 +384,4 @@ Map.defaultProps = {
mapCenter: {},
};

export default Map;
export default MapBoxComponent;
115 changes: 115 additions & 0 deletions projects/plugins/jetpack/extensions/blocks/map/component/mapkit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { Children, forwardRef, memo, useCallback, useRef } from '@wordpress/element';
import { get } from 'lodash';
import { MapkitProvider } from '../mapkit/context';
import {
useMapkit,
useMapkitSetup,
useMapkitInit,
useMapkitType,
useMapkitCenter,
useMapkitOnMapLoad,
useMapkitOnMapTap,
useMapkitZoom,
useMapkitPoints,
} from '../mapkit/hooks';
import { createCalloutElementCallback } from '../mapkit-utils';
import InfoWindow from './info-window';

const MapkitComponent = forwardRef( ( props, mapRef ) => {
const { admin, points, onSetPoints } = props;
const { loaded, mapkit, currentDoc, currentWindow } = useMapkitSetup( mapRef );
const { map } = useMapkitInit( mapkit, loaded, mapRef );
const addPoint = Children.map( props.children, child => {
const tagName = get( child, 'props.tagName' );
if ( 'AddPoint' === tagName ) {
return child;
}
} );

return (
<MapkitProvider
value={ {
mapkit,
map,
loaded,
currentDoc,
currentWindow,
admin,
points,
setPoints: onSetPoints,
} }
>
{ loaded && mapkit && map ? <MapkitHelpers { ...props } /> : null }
<div
style={ { height: props.mapHeight ? `${ props.mapHeight }px` : '400px' } }
className="wp-block-jetpack-map__gm-container"
ref={ mapRef }
/>
{ addPoint }
<InfoWindow />
</MapkitProvider>
);
} );

const MapkitHelpers = memo(
( {
mapCenter,
mapStyle,
zoom,
onSetMapCenter,
onSetZoom,
points,
markerColor,
onMarkerClick,
onMapLoaded,
} ) => {
const { map, mapkit, setActiveMarker, setCalloutReference, currentDoc } = useMapkit();

// Save these in a ref to prevent unwanted rerenders
const onMarkerClickRef = useRef( onMarkerClick );

const onSelect = useCallback(
marker => {
setActiveMarker( marker );
if ( onMarkerClickRef.current ) {
onMarkerClickRef.current( marker );
}
map.setCenterAnimated(
new mapkit.Coordinate( marker.coordinates.latitude, marker.coordinates.longitude )
);
},
[ map, mapkit, setActiveMarker, onMarkerClickRef ]
);

useMapkitCenter( mapCenter, onSetMapCenter );
useMapkitType( mapStyle );
useMapkitZoom( zoom, onSetZoom );
useMapkitPoints(
points,
markerColor,
createCalloutElementCallback( currentDoc, setCalloutReference ),
onSelect
);
useMapkitOnMapLoad( onMapLoaded );
useMapkitOnMapTap( () => {
setActiveMarker( null );
// TODO: recenter points
} );
return null;
}
);

MapkitComponent.defaultProps = {
points: [],
mapStyle: 'default',
zoom: 13,
onSetZoom: () => {},
onSetMapCenter: () => {},
onMapLoaded: () => {},
onMarkerClick: () => {},
onError: () => {},
markerColor: 'red',
mapCenter: {},
};

export default MapkitComponent;
19 changes: 14 additions & 5 deletions projects/plugins/jetpack/extensions/blocks/map/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export default ( {
setAttributes( { align: value } );

// Allow one cycle for alignment change to take effect
setTimeout( mapRef.current.sizeMap, 0 );
if ( mapRef.current?.sizeMap ) {
setTimeout( mapRef.current.sizeMap, 0 );
}
};

/**
Expand All @@ -52,7 +54,8 @@ export default ( {
height = null;
} else if ( null == mapHeight ) {
// There was previously no height defined, so set the default.
height = mapRef.current.mapRef.current.offsetHeight;
const ref = mapRef?.current?.mapRef ?? mapRef;
height = ref?.current.offsetHeight;
} else if ( height < minHeight ) {
// Set map height to minimum size
height = minHeight;
Expand All @@ -62,7 +65,9 @@ export default ( {
mapHeight: height,
} );

setTimeout( mapRef.current.sizeMap, 0 );
if ( mapRef.current.sizeMap ) {
setTimeout( mapRef.current.sizeMap, 0 );
}
};

if ( context === 'toolbar' ) {
Expand Down Expand Up @@ -111,7 +116,9 @@ export default ( {
// If this input isn't focussed, the onBlur handler won't be triggered
// to commit the map size, so we need to check for that.
if ( event.target !== document.activeElement ) {
setTimeout( mapRef.current.sizeMap, 0 );
if ( mapRef.current ) {
setTimeout( mapRef.current.sizeMap, 0 );
}
}
} }
onBlur={ onHeightChange }
Expand All @@ -133,7 +140,9 @@ export default ( {
value={ attributes.zoom }
onChange={ value => {
setAttributes( { zoom: value } );
setTimeout( mapRef.current.updateZoom, 0 );
if ( mapRef.current && mapRef.current.updateZoom ) {
setTimeout( mapRef.current.updateZoom, 0 );
}
} }
min={ 0 }
max={ 22 }
Expand Down
19 changes: 13 additions & 6 deletions projects/plugins/jetpack/extensions/blocks/map/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Component, createRef, Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { getActiveStyleName } from '../../shared/block-styles';
import AddPoint from './add-point';
import Map from './component.js';
import Map from './component';
import Controls from './controls';
import { getCoordinates } from './get-coordinates.js';
import previewPlaceholder from './map-preview.jpg';
Expand All @@ -39,6 +39,7 @@ const RESIZABLE_BOX_ENABLE_OPTION = {
bottomLeft: false,
topLeft: false,
};

class MapEdit extends Component {
constructor() {
super( ...arguments );
Expand Down Expand Up @@ -185,13 +186,19 @@ class MapEdit extends Component {

onResizeStop();

const height = parseInt( this.mapRef.current.mapRef.current.offsetHeight + delta.height, 10 );
const ref = this.mapRef?.current?.mapRef ?? this.mapRef;

setAttributes( {
mapHeight: height,
} );
if ( ref ) {
const height = parseInt( ref.current.offsetHeight + delta.height, 10 );

setAttributes( {
mapHeight: height,
} );

setTimeout( this.mapRef.current.sizeMap, 0 );
if ( ref.current.sizeMap ) {
setTimeout( ref.current.sizeMap, 0 );
}
}
};

render() {
Expand Down
Loading

0 comments on commit 8b79eab

Please sign in to comment.