mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 12:43:11 +10:00
Merge pull request #869 from sharetribe/listingpage-static-map
Listingpage static map
This commit is contained in:
commit
8270dcbcb9
12 changed files with 404 additions and 56 deletions
|
|
@ -13,6 +13,8 @@ way to update this template, but currently, we follow a pattern:
|
|||
---
|
||||
|
||||
## Upcoming version
|
||||
* [change] Use Google's static map on ListingPage.
|
||||
[#869](https://github.com/sharetribe/flex-template-web/pull/869)
|
||||
* [change] Use sessionTokens and fields for Autocomplete calls to Google Maps.
|
||||
This is a reaction to pricing change of Google Maps APIs.
|
||||
[#867](https://github.com/sharetribe/flex-template-web/pull/867)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@mapbox/polyline": "^1.0.0",
|
||||
"array-includes": "^3.0.3",
|
||||
"array.prototype.find": "^2.0.4",
|
||||
"autosize": "^4.0.0",
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
69
src/components/Map/DynamicMap.js
Normal file
69
src/components/Map/DynamicMap.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import React from 'react';
|
||||
import { number, object, shape, string } from 'prop-types';
|
||||
import { withGoogleMap, GoogleMap, Marker, Circle } from 'react-google-maps';
|
||||
import config from '../../config';
|
||||
|
||||
/**
|
||||
* DynamicMap uses withGoogleMap HOC.
|
||||
* It handles some of the google map initialization states.
|
||||
*/
|
||||
const DynamicMap = withGoogleMap(props => {
|
||||
const { center, zoom, address, coordinatesConfig } = props;
|
||||
|
||||
const { markerURI, anchorX, anchorY, width, height } = coordinatesConfig.customMarker;
|
||||
const markerIcon = {
|
||||
url: markerURI,
|
||||
|
||||
// The origin for this image is (0, 0).
|
||||
origin: new window.google.maps.Point(0, 0),
|
||||
size: new window.google.maps.Size(width, height),
|
||||
anchor: new window.google.maps.Point(anchorX, anchorY),
|
||||
};
|
||||
|
||||
const marker = <Marker position={center} icon={markerIcon} title={address} />;
|
||||
|
||||
const circleProps = {
|
||||
options: coordinatesConfig.circleOptions,
|
||||
radius: coordinatesConfig.coordinateOffset,
|
||||
center,
|
||||
};
|
||||
|
||||
const circle = <Circle {...circleProps} />;
|
||||
|
||||
return (
|
||||
<GoogleMap
|
||||
defaultZoom={zoom}
|
||||
defaultCenter={center}
|
||||
center={center}
|
||||
options={{
|
||||
// Disable map type (ie. Satellite etc.)
|
||||
mapTypeControl: false,
|
||||
// Disable zooming by scrolling
|
||||
scrollwheel: false,
|
||||
// Fullscreen control toggle
|
||||
fullscreenControl: true,
|
||||
}}
|
||||
>
|
||||
{coordinatesConfig.fuzzy ? circle : marker}
|
||||
</GoogleMap>
|
||||
);
|
||||
});
|
||||
|
||||
DynamicMap.defaultProps = {
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
};
|
||||
|
||||
DynamicMap.propTypes = {
|
||||
address: string,
|
||||
center: shape({
|
||||
lat: number.isRequired,
|
||||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
};
|
||||
|
||||
export default DynamicMap;
|
||||
|
|
@ -1,59 +1,13 @@
|
|||
import React, { Component } from 'react';
|
||||
import { string, number, object } from 'prop-types';
|
||||
import { withGoogleMap, GoogleMap, Marker, Circle } from 'react-google-maps';
|
||||
import { bool, number, object, string } from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { propTypes } from '../../util/types';
|
||||
import config from '../../config';
|
||||
|
||||
import CustomMarker from './images/marker-32x32.png';
|
||||
import DynamicMap from './DynamicMap';
|
||||
import StaticMap from './StaticMap';
|
||||
import css from './Map.css';
|
||||
|
||||
/**
|
||||
* MapWithGoogleMap uses withGoogleMap HOC.
|
||||
* It handles some of the google map initialization states.
|
||||
*/
|
||||
const MapWithGoogleMap = withGoogleMap(props => {
|
||||
const { center, zoom, address, coordinatesConfig } = props;
|
||||
|
||||
const markerIcon = {
|
||||
url: CustomMarker,
|
||||
// This marker is 32 pixels wide by 32 pixels high.
|
||||
size: new window.google.maps.Size(32, 32),
|
||||
// The origin for this image is (0, 0).
|
||||
origin: new window.google.maps.Point(0, 0),
|
||||
// The anchor for the marker is in the bottom center.
|
||||
anchor: new window.google.maps.Point(16, 32),
|
||||
};
|
||||
|
||||
const marker = <Marker position={center} icon={markerIcon} title={address} />;
|
||||
|
||||
const circleProps = {
|
||||
options: coordinatesConfig.circleOptions,
|
||||
radius: coordinatesConfig.coordinateOffset,
|
||||
center,
|
||||
};
|
||||
|
||||
const circle = <Circle {...circleProps} />;
|
||||
|
||||
return (
|
||||
<GoogleMap
|
||||
defaultZoom={zoom}
|
||||
defaultCenter={center}
|
||||
center={center}
|
||||
options={{
|
||||
// Disable map type (ie. Satellite etc.)
|
||||
mapTypeControl: false,
|
||||
// Disable zooming by scrolling
|
||||
scrollwheel: false,
|
||||
// Fullscreen control toggle
|
||||
fullscreenControl: true,
|
||||
}}
|
||||
>
|
||||
{coordinatesConfig.fuzzy ? circle : marker}
|
||||
</GoogleMap>
|
||||
);
|
||||
});
|
||||
|
||||
export class Map extends Component {
|
||||
render() {
|
||||
const {
|
||||
|
|
@ -65,6 +19,7 @@ export class Map extends Component {
|
|||
obfuscatedCenter,
|
||||
zoom,
|
||||
coordinatesConfig,
|
||||
useStaticMap,
|
||||
} = this.props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const mapClasses = mapRootClassName || css.mapRoot;
|
||||
|
|
@ -83,8 +38,17 @@ export class Map extends Component {
|
|||
|
||||
const isMapsLibLoaded = typeof window !== 'undefined' && window.google && window.google.maps;
|
||||
|
||||
return isMapsLibLoaded ? (
|
||||
<MapWithGoogleMap
|
||||
return !isMapsLibLoaded ? (
|
||||
<div className={classes} />
|
||||
) : useStaticMap ? (
|
||||
<StaticMap
|
||||
center={centerLocationForGoogleMap}
|
||||
zoom={zoom}
|
||||
address={address}
|
||||
coordinatesConfig={coordinatesConfig}
|
||||
/>
|
||||
) : (
|
||||
<DynamicMap
|
||||
containerElement={<div className={classes} onClick={this.onMapClicked} />}
|
||||
mapElement={<div className={mapClasses} />}
|
||||
center={centerLocationForGoogleMap}
|
||||
|
|
@ -92,8 +56,6 @@ export class Map extends Component {
|
|||
address={address}
|
||||
coordinatesConfig={coordinatesConfig}
|
||||
/>
|
||||
) : (
|
||||
<div className={classes} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -105,6 +67,7 @@ Map.defaultProps = {
|
|||
address: '',
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
useStaticMap: false,
|
||||
};
|
||||
|
||||
Map.propTypes = {
|
||||
|
|
@ -116,6 +79,7 @@ Map.propTypes = {
|
|||
obfuscatedCenter: propTypes.latlng,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
useStaticMap: bool,
|
||||
};
|
||||
|
||||
export default Map;
|
||||
|
|
|
|||
177
src/components/Map/StaticMap.js
Normal file
177
src/components/Map/StaticMap.js
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import React, { Component } from 'react';
|
||||
import { number, object, shape, string } from 'prop-types';
|
||||
import pick from 'lodash/pick';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import polyline from '@mapbox/polyline';
|
||||
import { encodeLatLng, stringify } from '../../util/urlHelpers';
|
||||
import { lazyLoadWithDimensions } from '../../util/contextHelpers';
|
||||
import config from '../../config';
|
||||
|
||||
const DEFAULT_COLOR = 'FF0000';
|
||||
const DEFAULT_STROKE_OPACITY = 0.3;
|
||||
const DEFAULT_FILL_OPACITY = 0.2;
|
||||
|
||||
// Return polyline encoded list of points forming a circle
|
||||
// This algorithm is based on
|
||||
// https://stackoverflow.com/questions/7316963/drawing-a-circle-google-static-maps
|
||||
const getEncodedGMapCirclePoints = (lat, lng, rad, detail = 8) => {
|
||||
const R = 6371;
|
||||
const pi = Math.PI;
|
||||
|
||||
const _lat = lat * pi / 180;
|
||||
const _lng = lng * pi / 180;
|
||||
const d = rad / 1000 / R;
|
||||
|
||||
let points = [];
|
||||
for (let i = 0; i <= 360; i += detail) {
|
||||
const brng = i * pi / 180;
|
||||
|
||||
let pLat = Math.asin(
|
||||
Math.sin(_lat) * Math.cos(d) + Math.cos(_lat) * Math.sin(d) * Math.cos(brng)
|
||||
);
|
||||
const pLng =
|
||||
(_lng +
|
||||
Math.atan2(
|
||||
Math.sin(brng) * Math.sin(d) * Math.cos(_lat),
|
||||
Math.cos(d) - Math.sin(_lat) * Math.sin(pLat)
|
||||
)) *
|
||||
180 /
|
||||
pi;
|
||||
pLat = pLat * 180 / pi;
|
||||
|
||||
points.push([pLat.toFixed(6), pLng.toFixed(6)]);
|
||||
}
|
||||
|
||||
return polyline.encode(points);
|
||||
};
|
||||
|
||||
// Extract color from string. Given value should be either with '#' (e.g. #FFFFFF') or without it.
|
||||
const formatColorFromString = color => {
|
||||
if (typeof color === 'string' && /^#[0-9A-F]{6}$/i.test(color)) {
|
||||
return color.substring(1).toUpperCase();
|
||||
} else if (typeof color === 'string' && /^[0-9A-F]{6}$/i) {
|
||||
return color.toUpperCase();
|
||||
} else {
|
||||
return DEFAULT_COLOR;
|
||||
}
|
||||
};
|
||||
|
||||
// Convert opacity from floating point value (0.0 -> 1.0) to a hexadecimal format
|
||||
const convertOpacity = opacity => {
|
||||
if (typeof opacity === 'number' && !isNaN(opacity) && opacity >= 0 && opacity <= 1) {
|
||||
// 0.2 => 20
|
||||
return Math.floor(opacity * 255)
|
||||
.toString(16)
|
||||
.toUpperCase();
|
||||
}
|
||||
};
|
||||
|
||||
// Draw a circle polyline for fuzzy location.
|
||||
const drawFuzzyCircle = (coordinatesConfig, center) => {
|
||||
if (
|
||||
!(
|
||||
coordinatesConfig &&
|
||||
typeof coordinatesConfig === 'object' &&
|
||||
center &&
|
||||
typeof center === 'object'
|
||||
)
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { fillColor, fillOpacity, strokeColor, strokeWeight } = coordinatesConfig.circleOptions;
|
||||
const { lat, lng } = center;
|
||||
|
||||
const circleRadius = coordinatesConfig.coordinateOffset || 500;
|
||||
const circleStrokeWeight = strokeWeight || 1;
|
||||
const circleStrokeColor = formatColorFromString(strokeColor);
|
||||
const circleStrokeOpacity = convertOpacity(DEFAULT_STROKE_OPACITY);
|
||||
const circleFill = formatColorFromString(fillColor);
|
||||
const circleFillOpacity = convertOpacity(fillOpacity || DEFAULT_FILL_OPACITY);
|
||||
|
||||
//Encoded polyline string
|
||||
const encodedPolyline = getEncodedGMapCirclePoints(lat, lng, circleRadius, 8);
|
||||
|
||||
const polylineGraphicTokens = [
|
||||
`color:0x${circleStrokeColor}${circleStrokeOpacity}`,
|
||||
`fillcolor:0x${circleFill}${circleFillOpacity}`,
|
||||
`weight:${circleStrokeWeight}`,
|
||||
`enc:${encodedPolyline}`,
|
||||
];
|
||||
|
||||
return polylineGraphicTokens.join('|');
|
||||
};
|
||||
|
||||
// Get custom marker data for static map URI
|
||||
const customMarker = (options, lat, lng) => {
|
||||
const { anchorX, anchorY, markerURI } = options;
|
||||
return [`anchor:${anchorX},${anchorY}`, `icon:${markerURI}`, `${lat},${lng}`].join('|');
|
||||
};
|
||||
|
||||
class StaticMap extends Component {
|
||||
shouldComponentUpdate(nextProps, prevState) {
|
||||
// Do not draw the map unless center, zoom or dimensions change
|
||||
// We want to prevent unnecessary calls to Google Maps APIs due
|
||||
const currentData = pick(this.props, ['center', 'zoom', 'dimensions']);
|
||||
const nextData = pick(nextProps, ['center', 'zoom', 'dimensions']);
|
||||
return !isEqual(currentData, nextData);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { center, zoom, address, coordinatesConfig, dimensions } = this.props;
|
||||
const { lat, lng } = center || {};
|
||||
const { width, height } = dimensions;
|
||||
|
||||
// Extra graphics for the static map image
|
||||
// 1. if fuzzy coordinates are used, return circle path
|
||||
// 2. if customMarker is defined in config.js, use that
|
||||
// 3. else return default marker
|
||||
const targetMaybe = coordinatesConfig.fuzzy
|
||||
? { path: drawFuzzyCircle(coordinatesConfig, center) }
|
||||
: coordinatesConfig.customMarker
|
||||
? { markers: customMarker(coordinatesConfig.customMarker, lat, lng) }
|
||||
: { markers: `${lat},${lng}` };
|
||||
|
||||
const srcParams = stringify({
|
||||
center: encodeLatLng(center),
|
||||
zoom,
|
||||
size: `${width}x${height}`,
|
||||
maptype: 'roadmap',
|
||||
key: config.googleMapsAPIKey,
|
||||
...targetMaybe,
|
||||
});
|
||||
|
||||
return (
|
||||
<img src={`https://maps.googleapis.com/maps/api/staticmap?${srcParams}`} alt={address} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
StaticMap.defaultProps = {
|
||||
className: null,
|
||||
rootClassName: null,
|
||||
address: '',
|
||||
center: null,
|
||||
zoom: config.coordinates.fuzzy ? config.coordinates.fuzzyDefaultZoomLevel : 11,
|
||||
coordinatesConfig: config.coordinates,
|
||||
};
|
||||
|
||||
StaticMap.propTypes = {
|
||||
className: string,
|
||||
rootClassName: string,
|
||||
address: string,
|
||||
center: shape({
|
||||
lat: number.isRequired,
|
||||
lng: number.isRequired,
|
||||
}).isRequired,
|
||||
zoom: number,
|
||||
coordinatesConfig: object,
|
||||
|
||||
// from withDimensions
|
||||
dimensions: shape({
|
||||
width: number.isRequired,
|
||||
height: number.isRequired,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
export default lazyLoadWithDimensions(StaticMap, { maxWidth: '640px' });
|
||||
|
|
@ -252,6 +252,9 @@ const siteFacebookPage = 'https://www.facebook.com/Sharetribe/';
|
|||
// You should create one to track social sharing in Facebook
|
||||
const facebookAppId = null;
|
||||
|
||||
// Google Maps API key is needed for static map images.
|
||||
const googleMapsAPIKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;
|
||||
|
||||
const coordinates = {
|
||||
// If true, obfuscate the coordinates of the listings that are shown
|
||||
// on a map.
|
||||
|
|
@ -280,9 +283,26 @@ const coordinates = {
|
|||
fillColor: '#c0392b',
|
||||
fillOpacity: 0.2,
|
||||
strokeColor: '#c0392b',
|
||||
strokeWeight: 0.5,
|
||||
strokeOpacity: 0.5,
|
||||
strokeWeight: 1,
|
||||
clickable: false,
|
||||
},
|
||||
|
||||
// An option to use custom marker on static maps. Uncomment to enable it.
|
||||
// https://developers.google.com/maps/documentation/maps-static/dev-guide#Markers
|
||||
//
|
||||
// Note 1: fuzzy coordinate circle overwrites these custom marker settings)
|
||||
// Note 2: markerURI needs to be a public URI accessible by Google Maps API servers.
|
||||
// The easiest place is /public/static/icons/ folder, but then the marker image is not available
|
||||
// while developing through localhost.
|
||||
|
||||
// customMarker: {
|
||||
// markerURI: encodeURI(`${canonicalRootURL}/static/icons/map-marker-32x32.png`),
|
||||
// anchorX: 16,
|
||||
// anchorY: 32,
|
||||
// width: 32,
|
||||
// height: 32,
|
||||
// },
|
||||
};
|
||||
|
||||
// NOTE: only expose configuration that should be visible in the
|
||||
|
|
@ -318,6 +338,7 @@ const config = {
|
|||
facebookAppId,
|
||||
sentryDsn,
|
||||
usingSSL,
|
||||
googleMapsAPIKey,
|
||||
coordinates,
|
||||
custom,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -530,6 +530,9 @@
|
|||
/* Dimensions: Map takes all available space from viewport (excludes action button and section title) */
|
||||
height: calc(100vh - 193px);
|
||||
width: 100%;
|
||||
|
||||
/* Static map: max-width is 640px */
|
||||
max-width: 640px;
|
||||
background-color: #eee;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const SectionMapMaybe = props => {
|
|||
<FormattedMessage id="ListingPage.locationTitle" />
|
||||
</h2>
|
||||
<div className={css.map}>
|
||||
<Map {...mapProps} />
|
||||
<Map {...mapProps} useStaticMap />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,8 @@ exports[`SearchPageComponent matches snapshot 1`] = `
|
|||
"fillColor": "#c0392b",
|
||||
"fillOpacity": 0.2,
|
||||
"strokeColor": "#c0392b",
|
||||
"strokeWeight": 0.5,
|
||||
"strokeOpacity": 0.5,
|
||||
"strokeWeight": 1,
|
||||
},
|
||||
"coordinateOffset": 500,
|
||||
"fuzzy": false,
|
||||
|
|
|
|||
|
|
@ -68,3 +68,109 @@ export const withViewport = Component => {
|
|||
|
||||
return WithViewportComponent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A higher order component (HOC) that lazy loads the current element and provides
|
||||
* dimensions to the wrapped component as a `dimensions` prop that has
|
||||
* the shape `{ width: 600, height: 400}`.
|
||||
*
|
||||
* @param {React.Component} Component to be wrapped by this HOC
|
||||
* @param {Object} options pass in options like maxWidth and maxHeight.
|
||||
*
|
||||
* @return {Object} HOC component which knows its dimensions
|
||||
*/
|
||||
export const lazyLoadWithDimensions = (Component, options) => {
|
||||
// The resize event is flooded when the browser is resized. We'll
|
||||
// use a small timeout to throttle changing the viewport since it
|
||||
// will trigger rerendering.
|
||||
const THROTTLE_WAIT_MS = 200;
|
||||
// First render default wait after mounting (small wait for styled paint)
|
||||
const RENDER_WAIT_MS = 100;
|
||||
|
||||
class LazyLoadWithDimensionsComponent extends ReactComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.element = null;
|
||||
this.defaultRenderTimeout = null;
|
||||
|
||||
this.state = { width: 0, height: 0 };
|
||||
|
||||
this.handleWindowResize = this.handleWindowResize.bind(this);
|
||||
this.isElementInViewport = this.isElementInViewport.bind(this);
|
||||
this.setDimensions = throttle(this.setDimensions.bind(this), THROTTLE_WAIT_MS);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('scroll', this.handleWindowResize);
|
||||
window.addEventListener('resize', this.handleWindowResize);
|
||||
window.addEventListener('orientationchange', this.handleWindowResize);
|
||||
|
||||
this.defaultRenderTimeout = window.setTimeout(() => {
|
||||
if (this.isElementInViewport()) {
|
||||
this.handleWindowResize();
|
||||
}
|
||||
}, RENDER_WAIT_MS);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('scroll', this.handleWindowResize);
|
||||
window.removeEventListener('resize', this.handleWindowResize);
|
||||
window.removeEventListener('orientationchange', this.handleWindowResize);
|
||||
window.clearTimeout(this.defaultRenderTimeout);
|
||||
}
|
||||
|
||||
handleWindowResize() {
|
||||
this.setDimensions();
|
||||
}
|
||||
|
||||
setDimensions() {
|
||||
this.setState(prevState => {
|
||||
const { clientWidth, clientHeight } = this.element || { clientWidth: 0, clientHeight: 0 };
|
||||
return { width: clientWidth, height: clientHeight };
|
||||
});
|
||||
}
|
||||
|
||||
isElementInViewport() {
|
||||
if (this.element) {
|
||||
const rect = this.element.getBoundingClientRect();
|
||||
|
||||
return (
|
||||
rect.top >= 0 &&
|
||||
rect.left >= 0 &&
|
||||
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render() {
|
||||
const dimensions = this.state;
|
||||
const { width, height } = dimensions;
|
||||
const props = { ...this.props, dimensions };
|
||||
|
||||
// lazyLoadWithDimensions HOC needs to take all given space
|
||||
// unless max dimensions are provided through options.
|
||||
const { maxWidth, maxHeight } = options;
|
||||
const maxWidthMaybe = maxWidth ? { maxWidth } : {};
|
||||
const maxHeightMaybe = maxHeight ? { maxHeight } : {};
|
||||
const style = { width: '100%', height: '100%', ...maxWidthMaybe, ...maxHeightMaybe };
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={element => {
|
||||
this.element = element;
|
||||
}}
|
||||
style={style}
|
||||
>
|
||||
{width !== 0 && height !== 0 ? <Component {...props} /> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoadWithDimensionsComponent.displayName = `lazyLoadWithDimensions(${Component.displayName ||
|
||||
Component.name})`;
|
||||
|
||||
return LazyLoadWithDimensionsComponent;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@mapbox/polyline@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/polyline/-/polyline-1.0.0.tgz#b6f1c3cf61f8dddcf9ac6dce0b2e50e5f4e965bc"
|
||||
|
||||
"@types/node@*":
|
||||
version "9.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.0.tgz#d3480ee666df9784b1001a1872a2f6ccefb6c2d7"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue