Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(components/map/google): avoid loading google script when map is … #518

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions components/map/google/src/dynamic/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {useCallback} from 'react'

import PropTypes from 'prop-types'

import {GoogleMap, useLoadScript} from '@react-google-maps/api'

import AtomSkeleton from '@s-ui/react-atom-skeleton'

import {
CONTAINER_CLASSNAME,
DEFAULT_CENTER,
DEFAULT_LANGUAGE,
DEFAULT_ZOOM,
getDefaultMapSize,
handle
} from '../config.js'

function MapGoogleDynamic({
apiKey,
center = DEFAULT_CENTER,
language = DEFAULT_LANGUAGE,
zoom = DEFAULT_ZOOM,
height,
width,
isInteractive: isInteractiveProp,
loaderNode,
errorNode,
staticImageNode,
onError,
onLoad,
onUnmount,
...others
}) {
const {isLoaded, loadError} = useLoadScript({
googleMapsApiKey: apiKey,
language
})

const handleOnLoad = useCallback(
mapInstance => {
handle(onLoad)(mapInstance)
},
[onLoad]
)

if (loadError) {
return errorNode
}

const mapSize = getDefaultMapSize({height, width})

return (
<>
{isLoaded ? (
<div style={mapSize}>
<GoogleMap
apiKey={apiKey}
center={center}
height={height}
mapContainerClassName={CONTAINER_CLASSNAME}
onError={onError}
onLoad={handleOnLoad}
onUnmount={onUnmount}
width={width}
zoom={zoom}
{...others}
/>
</div>
) : (
loaderNode || <AtomSkeleton {...mapSize} />
)}
</>
)
}

MapGoogleDynamic.displayName = 'MapGoogleDynamic'
MapGoogleDynamic.propTypes = {
apiKey: PropTypes.string.isRequired,
center: PropTypes.shape({
lat: PropTypes.number.isRequired,
lng: PropTypes.number.isRequired
}),
children: PropTypes.node,
errorNode: PropTypes.node,
height: PropTypes.number,
width: PropTypes.number,
isInteractive: PropTypes.bool,
language: PropTypes.string,
loaderNode: PropTypes.node,
onError: PropTypes.func,
onLoad: PropTypes.func,
onUnmount: PropTypes.func,
staticImageNode: PropTypes.node,
zoom: PropTypes.number
}

export default MapGoogleDynamic
20 changes: 14 additions & 6 deletions components/map/google/src/image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,31 @@ import PropTypes from 'prop-types'
import {toQueryString} from '@s-ui/js/lib/string'
import Injector from '@s-ui/react-primitive-injector'

import {BASE_URL, DEFAULT_CENTER, DEFAULT_CHILDREN_ALT} from './config.js'
import {
BASE_URL,
DEFAULT_CENTER,
DEFAULT_CHILDREN_ALT,
DEFAULT_ZOOM
} from './config.js'

function MapGoogleImage({
alt = DEFAULT_CHILDREN_ALT,
apiKey,
center: {lat, lng} = DEFAULT_CENTER,
zoom = DEFAULT_ZOOM,
apiKey,
children = <img />,
height,
size,
width,
...others
}) {
if (!height || !width) {
if (height === undefined || width === undefined) {
throw new Error('Height and Width are mandatory in static map')
}

const params = toQueryString({
...others,
zoom,
key: apiKey,
center: `${lat},${lng}`,
size: size ?? `${width}x${height}`
Expand All @@ -38,11 +45,12 @@ MapGoogleImage.displayName = 'MapGoogleImage'
MapGoogleImage.propTypes = {
alt: PropTypes.string,
apiKey: PropTypes.string.isRequired,
center: PropTypes.shape({lat: PropTypes.number, lng: PropTypes.number}),
children: PropTypes.node,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
center: PropTypes.shape({lat: PropTypes.number, lng: PropTypes.number}),
size: PropTypes.string,
width: PropTypes.number.isRequired
zoom: PropTypes.number,
children: PropTypes.node
}

export default MapGoogleImage
120 changes: 37 additions & 83 deletions components/map/google/src/index.js
Original file line number Diff line number Diff line change
@@ -1,98 +1,51 @@
import {useCallback} from 'react'
import {forwardRef} from 'react'

import PropTypes from 'prop-types'

import {GoogleMap as DynamicMap, useLoadScript} from '@react-google-maps/api'

import AtomSkeleton from '@s-ui/react-atom-skeleton'
import useControlledState from '@s-ui/react-hooks/lib/useControlledState/index.js'

import MapGoogleCircle from './circle/index.js'
import StaticMap from './image/index.js'
import MapGoogleDynamic from './dynamic/index.js'
import MapGoogleImage from './image/index.js'
import MapGoogleMarker from './marker/index.js'
import MapGooglePolygon from './polygon/index.js'
import MapGooglePolyline from './polyline/index.js'
import MapGoogleRectangle from './rectangle/index.js'
import {
BASE_CLASS,
CONTAINER_CLASSNAME,
DEFAULT_CENTER,
DEFAULT_LANGUAGE,
DEFAULT_ZOOM,
getDefaultMapSize,
handle
} from './config.js'

function MapGoogle({
apiKey,
center = DEFAULT_CENTER,
children,
errorNode,
isInteractive: isInteractiveProp,
height,
width,
language = DEFAULT_LANGUAGE,
loaderNode,
staticImageNode,
zoom = DEFAULT_ZOOM,
onError,
onLoad,
onUnmount,
...others
}) {
const [isInteractive, setIsInteractive] =
useControlledState(isInteractiveProp)

const {isLoaded, loadError} = useLoadScript({
googleMapsApiKey: apiKey,
language
})
import {BASE_CLASS, CONTAINER_CLASSNAME, handle} from './config.js'

const handleOnLoad = useCallback(
mapInstance => {
handle(onLoad)(mapInstance)
const MapGoogle = forwardRef(
(
{
// eslint-disable-next-line react/prop-types
className,
isInteractive: isInteractiveProp,
staticImageNode,
children,
onClick,
...others
},
[onLoad]
)
forwardedRef
) => {
const [isInteractive, setIsInteractive] =
useControlledState(isInteractiveProp)

const handleClick = useCallback(() => {
setIsInteractive(true)
}, [setIsInteractive])

if (loadError) {
return errorNode ? <div className={BASE_CLASS}>{errorNode}</div> : null
}
const handleClick = event => {
handle(onClick)(event)

const MapElement = isInteractive ? DynamicMap : StaticMap
setIsInteractive(true)
}

const mapSize = getDefaultMapSize({height, width})
const Map = isInteractive ? MapGoogleDynamic : MapGoogleImage

return (
<div className={BASE_CLASS} onClick={handleClick}>
{isLoaded ? (
<div style={mapSize}>
<MapElement
apiKey={apiKey}
center={center}
height={height}
isInteractive={isInteractive}
mapContainerClassName={CONTAINER_CLASSNAME}
onError={onError}
onLoad={handleOnLoad}
onUnmount={onUnmount}
width={width}
zoom={zoom}
{...others}
>
{isInteractive ? children : staticImageNode}
</MapElement>
</div>
) : (
loaderNode || <AtomSkeleton {...mapSize} />
)}
</div>
)
}
return (
<div ref={forwardedRef} className={BASE_CLASS} onClick={handleClick}>
<Map mapContainerClassName={CONTAINER_CLASSNAME} {...others}>
{isInteractive ? children : staticImageNode}
</Map>
</div>
)
}
)

MapGoogle.displayName = 'MapGoogle'
MapGoogle.propTypes = {
Expand All @@ -101,18 +54,19 @@ MapGoogle.propTypes = {
lat: PropTypes.number.isRequired,
lng: PropTypes.number.isRequired
}),
staticImageNode: PropTypes.node,
zoom: PropTypes.number,
children: PropTypes.node,
errorNode: PropTypes.node,
height: PropTypes.number,
width: PropTypes.number,
isInteractive: PropTypes.bool,
language: PropTypes.string,
loaderNode: PropTypes.node,
onClick: PropTypes.func,
onError: PropTypes.func,
onLoad: PropTypes.func,
onUnmount: PropTypes.func,
staticImageNode: PropTypes.node,
zoom: PropTypes.number
onUnmount: PropTypes.func
}

export default MapGoogle
Expand All @@ -121,7 +75,7 @@ export {
MapGoogleCircle,
MapGoogleMarker,
MapGoogleRectangle,
StaticMap as MapGoogleImage,
MapGoogleImage,
MapGooglePolygon,
MapGooglePolyline
}
9 changes: 6 additions & 3 deletions components/map/google/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('MapGoogle', () => {

it('should render without crashing', () => {
// Given
const props = {}
const props = {...REQUIRED_MAPGOOGLEIMAGE_PROPS}

// When
const Component = <MapGoogle {...props} />
Expand All @@ -39,7 +39,7 @@ describe('MapGoogle', () => {

it('should not render null', () => {
// Given
const props = {}
const props = {...REQUIRED_MAPGOOGLEIMAGE_PROPS}

// When
const {container} = setup(props)
Expand All @@ -51,7 +51,10 @@ describe('MapGoogle', () => {

it('should not extend classNames', () => {
// Given
const props = {className: 'extended-classNames'}
const props = {
className: 'extended-classNames',
...REQUIRED_MAPGOOGLEIMAGE_PROPS
}
const findSentence = str => string => string.match(new RegExp(`S*${str}S*`))

// When
Expand Down