diff --git a/components/map/google/src/dynamic/index.js b/components/map/google/src/dynamic/index.js new file mode 100644 index 000000000..845ef849d --- /dev/null +++ b/components/map/google/src/dynamic/index.js @@ -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 ? ( +
+ +
+ ) : ( + loaderNode || + )} + + ) +} + +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 diff --git a/components/map/google/src/image/index.js b/components/map/google/src/image/index.js index 677b3e4eb..62b50397d 100644 --- a/components/map/google/src/image/index.js +++ b/components/map/google/src/image/index.js @@ -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 = , 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}` @@ -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 diff --git a/components/map/google/src/index.js b/components/map/google/src/index.js index 380a52b37..0780d8b8c 100644 --- a/components/map/google/src/index.js +++ b/components/map/google/src/index.js @@ -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 ?
{errorNode}
: 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 ( -
- {isLoaded ? ( -
- - {isInteractive ? children : staticImageNode} - -
- ) : ( - loaderNode || - )} -
- ) -} + return ( +
+ + {isInteractive ? children : staticImageNode} + +
+ ) + } +) MapGoogle.displayName = 'MapGoogle' MapGoogle.propTypes = { @@ -101,6 +54,8 @@ 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, @@ -108,11 +63,10 @@ MapGoogle.propTypes = { 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 @@ -121,7 +75,7 @@ export { MapGoogleCircle, MapGoogleMarker, MapGoogleRectangle, - StaticMap as MapGoogleImage, + MapGoogleImage, MapGooglePolygon, MapGooglePolyline } diff --git a/components/map/google/test/index.test.js b/components/map/google/test/index.test.js index adf5ae983..624fb4ce8 100644 --- a/components/map/google/test/index.test.js +++ b/components/map/google/test/index.test.js @@ -26,7 +26,7 @@ describe('MapGoogle', () => { it('should render without crashing', () => { // Given - const props = {} + const props = {...REQUIRED_MAPGOOGLEIMAGE_PROPS} // When const Component = @@ -39,7 +39,7 @@ describe('MapGoogle', () => { it('should not render null', () => { // Given - const props = {} + const props = {...REQUIRED_MAPGOOGLEIMAGE_PROPS} // When const {container} = setup(props) @@ -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