diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/ForkTemplateToGitConnectedApp.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/ForkTemplateToGitConnectedApp.js index 97abfc24d6..e6f7f4cd07 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/ForkTemplateToGitConnectedApp.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/ForkTemplateToGitConnectedApp.js @@ -50,9 +50,9 @@ describe("Fork a template to the current app", () => { cy.wait(6000); cy.get("body").then(($ele) => { if ($ele.find(widgetLocators.toastAction).length <= 0) { - if ($ele.find(template.templateViewForkButton).length> 0) { + if ($ele.find(template.templateViewForkButton).length > 0) { cy.get(template.templateViewForkButton).click(); - } + } } }); cy.get(widgetLocators.toastAction).should( diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_Existing_app_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_Existing_app_spec.js index 75c4f99649..e77ba78b92 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_Existing_app_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_Existing_app_spec.js @@ -23,8 +23,8 @@ describe("Fork a template to the current app from new page popover", () => { cy.wait(6000); cy.get("body").then(($ele) => { if ($ele.find(widgetLocators.toastAction).length <= 0) { - if ($ele.find(template.templateViewForkButton).length> 0) { - cy.get(template.templateViewForkButton).click(); + if ($ele.find(template.templateViewForkButton).length > 0) { + cy.get(template.templateViewForkButton).click(); } } }); diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_To_App_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_To_App_spec.js index 7828c8b99f..c2db087131 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_To_App_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/Templates/Fork_Template_To_App_spec.js @@ -37,9 +37,9 @@ describe("Fork a template to the current app", () => { cy.wait(6000); cy.get("body").then(($ele) => { if ($ele.find(widgetLocators.toastAction).length <= 0) { - if ($ele.find(template.templateViewForkButton).length> 0) { + if ($ele.find(template.templateViewForkButton).length > 0) { cy.get(template.templateViewForkButton).click(); - } + } } }); cy.get(widgetLocators.toastAction).should( diff --git a/app/client/package.json b/app/client/package.json index 66b7a84ff4..a58d084ba0 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -17,10 +17,13 @@ "@draft-js-plugins/mention": "^4.5.1", "@fusioncharts/powercharts": "^3.16.0", "@github/g-emoji-element": "^1.1.5", + "@googlemaps/markerclusterer": "^2.0.14", + "@googlemaps/react-wrapper": "^1.1.35", "@manaflair/redux-batch": "^1.0.0", "@sentry/react": "^6.2.4", "@sentry/tracing": "^6.2.4", "@tinymce/tinymce-react": "^3.13.0", + "@types/google.maps": "^3.51.0", "@types/react-page-visibility": "^6.4.1", "@uppy/core": "^1.16.0", "@uppy/dashboard": "^1.16.0", @@ -46,7 +49,7 @@ "cypress-log-to-output": "^1.1.2", "dayjs": "^1.10.6", "deep-diff": "^1.0.2", - "design-system": "npm:@appsmithorg/design-system@1.0.45", + "design-system": "npm:@appsmithorg/design-system@1.0.46", "downloadjs": "^1.4.7", "draft-js": "^0.11.7", "exceljs-lightweight": "^1.14.0", @@ -97,7 +100,7 @@ "rc-select": "^14.1.9", "rc-tree-select": "^5.4.0", "re-reselect": "^3.4.0", - "react": "^16.12.0", + "react": "^17.0.2", "react-beautiful-dnd": "^12.2.0", "react-custom-scrollbars": "^4.2.1", "react-device-detect": "^2.2.2", @@ -105,10 +108,9 @@ "react-dnd-html5-backend": "^9.3.4", "react-dnd-touch-backend": "^9.4.0", "react-documents": "^1.0.4", - "react-dom": "^16.7.0", + "react-dom": "^17.0.2", "react-full-screen": "^1.1.0", "react-fusioncharts": "^3.1.2", - "react-google-maps": "^9.4.5", "react-google-recaptcha": "^2.1.0", "react-helmet": "^5.2.1", "react-hook-form": "^7.28.0", @@ -212,10 +214,10 @@ "@types/node-forge": "^0.10.0", "@types/papaparse": "^5.3.5", "@types/prismjs": "^1.16.1", - "@types/react": "^16.8.2", + "@types/react": "^17.0.2", "@types/react-beautiful-dnd": "^11.0.4", "@types/react-custom-scrollbars": "^4.0.7", - "@types/react-dom": "^16.8.0", + "@types/react-dom": "^17.0.2", "@types/react-google-recaptcha": "^2.1.1", "@types/react-helmet": "^5.0.14", "@types/react-instantsearch-dom": "^6.3.0", diff --git a/app/client/src/components/propertyControls/LocationSearchControl.tsx b/app/client/src/components/propertyControls/LocationSearchControl.tsx index 088fe92961..e5831d9c29 100644 --- a/app/client/src/components/propertyControls/LocationSearchControl.tsx +++ b/app/client/src/components/propertyControls/LocationSearchControl.tsx @@ -1,18 +1,30 @@ -import React, { useState } from "react"; -import BaseControl, { ControlData, ControlProps } from "./BaseControl"; -import SearchBox from "react-google-maps/lib/components/places/SearchBox"; -import StandaloneSearchBox from "react-google-maps/lib/components/places/StandaloneSearchBox"; -import { getAppsmithConfigs } from "@appsmith/configs"; -import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript"; -import { StyledInputGroup } from "./StyledControls"; import log from "loglevel"; +import React, { useState } from "react"; +import styled from "styled-components"; +import { Wrapper, Status } from "@googlemaps/react-wrapper"; + +import { StyledInputGroup } from "./StyledControls"; +import { getAppsmithConfigs } from "@appsmith/configs"; import { isDynamicValue } from "utils/DynamicBindingUtils"; +import BaseControl, { ControlData, ControlProps } from "./BaseControl"; const { google } = getAppsmithConfigs(); -class LocationSearchControl extends BaseControl { - searchBox: any = null; +const MapStatusText = styled.span` + font-size: 14px; +`; +const renderMapStatus = (status: Status) => { + switch (status) { + case Status.LOADING: + return Loading...; + case Status.FAILURE: + return Error in the component; + case Status.SUCCESS: + return Component loaded....; + } +}; +class LocationSearchControl extends BaseControl { clearLocation = () => { this.updateProperty(this.props.propertyName, { lat: -34.397, @@ -21,10 +33,10 @@ class LocationSearchControl extends BaseControl { }); }; - onLocationSelection = () => { + onLocationSelection = (ref: any) => { try { // For some places, the length is zero - const places = this.searchBox.getPlaces(); + const places = ref.getPlaces(); const location = places[0].geometry.location; const title = places[0].formatted_address; const lat = location.lat(); @@ -32,26 +44,36 @@ class LocationSearchControl extends BaseControl { const value = { lat, long, title }; this.updateProperty(this.props.propertyName, value, true); } catch (e) { - if (this.searchBox && this.searchBox.getPlaces) - log.debug("Error selecting location:", this.searchBox.getPlaces()); + if (ref && ref.getPlaces) + log.debug("Error selecting location:", ref.getPlaces()); else { log.debug("Error selecting location - searchBox not found"); } } }; - onSearchBoxMounted = (ref: SearchBox) => { - this.searchBox = ref; + onSearchBoxMounted = (ref: any) => { + if (window) { + const searchBox = new window.google.maps.places.SearchBox(ref); + searchBox.addListener("places_changed", () => { + this.onLocationSelection(searchBox); + }); + } }; render() { return ( - + + + ); } @@ -65,43 +87,29 @@ class LocationSearchControl extends BaseControl { } interface MapScriptWrapperProps { - onSearchBoxMounted: (ref: SearchBox) => void; - onPlacesChanged: () => void; + onSearchBoxMounted: (ref: any) => void; clearLocation: () => void; propertyValue: any; } function MapScriptWrapper(props: MapScriptWrapperProps) { - const status = useScript( - `https://maps.googleapis.com/maps/api/js?key=${google.apiKey}&v=3.exp&libraries=geometry,drawing,places`, - AddScriptTo.HEAD, - ); const [title, setTitle] = useState(""); return (
- {status === ScriptStatus.READY && ( - { - props.onPlacesChanged(); - setTitle(""); - }} - ref={props.onSearchBoxMounted} - > - { - if (value === "") { - props.clearLocation(); - } - setTitle(value); - }} - placeholder="Enter location" - tabIndex={-1} - /> - - )} + { + if (value === "") { + props.clearLocation(); + } + setTitle(value); + }} + placeholder="Enter location" + ref={props.onSearchBoxMounted} + tabIndex={-1} + />
); } diff --git a/app/client/src/pages/Editor/PropertyPane/PropertyPaneSearchInput.tsx b/app/client/src/pages/Editor/PropertyPane/PropertyPaneSearchInput.tsx index 86a98c772c..f0e7e1955c 100644 --- a/app/client/src/pages/Editor/PropertyPane/PropertyPaneSearchInput.tsx +++ b/app/client/src/pages/Editor/PropertyPane/PropertyPaneSearchInput.tsx @@ -43,17 +43,19 @@ export function PropertyPaneSearchInput(props: PropertyPaneSearchInputProps) { useEffect(() => { // Checks if the property pane opened not because of focusing an input inside a widget - const isActiveFocusNotFromWidgetInput = !isCurrentFocusOnInput(); if ( shouldFocusSearch && - isActiveFocusNotFromWidgetInput && // while the panel transition happens, focus will be happening twice. Once on the main pane and then on the panel // The following check will make sure that the focus is only done once and prevents the UI jittering isPanel === shouldFocusPanelSearch ) { setTimeout( () => { - wrapperRef.current?.focus(); + //checking for active element + //inside timeout to have updated active element + if (!isCurrentFocusOnInput()) { + wrapperRef.current?.focus(); + } }, // Layered panels like Column Panel's transition takes 300ms. // To avoid UI jittering, we are delaying the focus by 300ms. diff --git a/app/client/src/utils/hooks/useClickToSelectWidget.tsx b/app/client/src/utils/hooks/useClickToSelectWidget.tsx index d6101c2126..01c2bbcb6d 100644 --- a/app/client/src/utils/hooks/useClickToSelectWidget.tsx +++ b/app/client/src/utils/hooks/useClickToSelectWidget.tsx @@ -1,15 +1,15 @@ -import { getIsPropertyPaneVisible } from "selectors/propertyPaneSelectors"; -import { useSelector } from "react-redux"; import { AppState } from "@appsmith/reducers"; -import { useWidgetSelection } from "./useWidgetSelection"; +import equal from "fast-deep-equal/es6"; import React, { ReactNode, useCallback } from "react"; -import { stopEventPropagation } from "utils/AppsmithUtils"; +import { useSelector } from "react-redux"; +import { getIsPropertyPaneVisible } from "selectors/propertyPaneSelectors"; import { getFocusedParentToOpen, isWidgetSelected, shouldWidgetIgnoreClicksSelector, } from "selectors/widgetSelectors"; -import equal from "fast-deep-equal/es6"; +import { stopEventPropagation } from "utils/AppsmithUtils"; +import { useWidgetSelection } from "./useWidgetSelection"; export function ClickContentToOpenPropPane({ children, @@ -49,7 +49,7 @@ export function ClickContentToOpenPropPane({ return (
diff --git a/app/client/src/widgets/MapWidget/component/Clusterer.tsx b/app/client/src/widgets/MapWidget/component/Clusterer.tsx new file mode 100644 index 0000000000..90988c3111 --- /dev/null +++ b/app/client/src/widgets/MapWidget/component/Clusterer.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useState } from "react"; +import { MarkerClusterer } from "@googlemaps/markerclusterer"; + +import Marker from "./Marker"; +import { MapComponentProps } from "."; + +type ClustererProps = { + map?: google.maps.Map; +} & Pick< + MapComponentProps, + | "selectMarker" + | "updateCenter" + | "updateMarker" + | "markers" + | "selectedMarker" + | "clickedMarkerCentered" +>; + +const Clusterer: React.FC = (props) => { + const { + clickedMarkerCentered, + map, + markers, + selectedMarker, + selectMarker, + updateCenter, + updateMarker, + } = props; + const [markerClusterer, setMarkerClusterer] = useState(); + + // add marker clusterer on map + useEffect(() => { + if (!map) return; + + setMarkerClusterer( + new MarkerClusterer({ + map, + }), + ); + + return () => { + if (markerClusterer) { + markerClusterer.clearMarkers(); + } + }; + }, [map]); + + if (!Array.isArray(markers)) return null; + + return ( + <> + {markers.map((marker, index) => ( + { + if (clickedMarkerCentered) { + updateCenter(marker.lat, marker.long); + } + + selectMarker(marker.lat, marker.long, marker.title); + }} + onDragEnd={(e) => { + updateMarker( + Number(e.latLng?.lat()), + Number(e.latLng?.lng()), + index, + ); + }} + position={{ + lat: marker.lat, + lng: marker.long, + }} + title={marker.title} + /> + ))} + + ); +}; + +export default Clusterer; diff --git a/app/client/src/widgets/MapWidget/component/Map.tsx b/app/client/src/widgets/MapWidget/component/Map.tsx new file mode 100644 index 0000000000..ce8e08cd74 --- /dev/null +++ b/app/client/src/widgets/MapWidget/component/Map.tsx @@ -0,0 +1,143 @@ +import styled from "styled-components"; +import React, { useCallback, useEffect, useRef, useState } from "react"; + +import Clusterer from "./Clusterer"; +import SearchBox from "./SearchBox"; +import { MapComponentProps } from "."; +import PickMyLocation from "./PickMyLocation"; + +const Wrapper = styled.div` + position: relative; +`; + +const StyledMap = styled.div>` + height: 100%; + width: 100%; + border-radius: ${(props) => props.borderRadius}; + box-shadow: ${(props) => props.boxShadow}; +`; + +type MapProps = { + children?: React.ReactNode; +} & Pick< + MapComponentProps, + | "updateCenter" + | "zoomLevel" + | "updateMarker" + | "selectMarker" + | "saveMarker" + | "markers" + | "center" + | "enableCreateMarker" + | "selectedMarker" + | "borderRadius" + | "boxShadow" + | "clickedMarkerCentered" + | "enableDrag" +>; + +const Map = (props: MapProps) => { + const { + borderRadius, + boxShadow, + center, + children, + enableCreateMarker, + enableDrag, + markers, + saveMarker, + selectMarker, + updateCenter, + updateMarker, + zoomLevel, + } = props; + const [map, setMap] = useState(); + const mapRef = useRef(null); + + // initialize the map instance + useEffect(() => { + if (!mapRef.current) return; + + setMap( + new window.google.maps.Map(mapRef.current, { + streetViewControl: false, + mapTypeControl: false, + fullscreenControl: false, + }), + ); + }, [mapRef]); + + // set center if center is changed + useEffect(() => { + if (map) { + map.setCenter({ lat: center.lat, lng: center.long }); + } + }, [center, map]); + + // set zoom if zoomLevel is changed + useEffect(() => { + if (map) { + map.setZoom(Math.floor(zoomLevel / 5)); + } + }, [zoomLevel, map]); + + /** + * on click map, add marker + * + * @param e + * @returns + */ + const onClickOnMap = useCallback( + (e: google.maps.MapMouseEvent) => { + if (!enableCreateMarker || !saveMarker) return; + + // only save marker when lag and long are available + if (e.latLng?.lat() && e.latLng?.lng()) { + saveMarker(Number(e.latLng.lat()), Number(e.latLng.lng())); + } + }, + [enableCreateMarker, saveMarker], + ); + + // NOTE: The event listeners require code to clear existing listeners + // when a handler passed as a prop has been updated. + React.useEffect(() => { + if (map) { + ["click", "idle"].forEach((eventName) => + google.maps.event.clearListeners(map, eventName), + ); + + map.addListener("click", onClickOnMap); + } + }, [map, onClickOnMap]); + + return ( + + + + {React.Children.map(children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child as React.ReactElement, { + map, + }); + } + })} + + ); +}; + +Map.PickMyLocation = PickMyLocation; +Map.SearchBox = SearchBox; + +export default Map; diff --git a/app/client/src/widgets/MapWidget/component/Marker.tsx b/app/client/src/widgets/MapWidget/component/Marker.tsx new file mode 100644 index 0000000000..6644ed56e3 --- /dev/null +++ b/app/client/src/widgets/MapWidget/component/Marker.tsx @@ -0,0 +1,56 @@ +import React, { useEffect, useState } from "react"; +import { MarkerClusterer } from "@googlemaps/markerclusterer"; + +type MarkerProps = google.maps.MarkerOptions & { + onClick?: () => void; + map?: google.maps.Map; + markerClusterer?: MarkerClusterer; + onDragEnd?: (e: google.maps.MapMouseEvent) => void; +}; + +const Marker: React.FC = (options) => { + const { markerClusterer, onClick, onDragEnd, position, ...rest } = options; + const [marker, setMarker] = useState(); + + useEffect(() => { + if (!marker) { + const marker = new google.maps.Marker({ position }); + + marker.addListener("click", () => { + if (onClick) onClick(); + }); + + marker.setOptions(rest); + + setMarker(marker); + } + + if (markerClusterer && marker) { + markerClusterer.addMarker(marker); + } + + // remove marker from map on unmount + return () => { + if (marker) { + marker.setMap(null); + } + + if (markerClusterer && marker) { + markerClusterer.removeMarker(marker); + } + }; + }, [marker, markerClusterer]); + + // add dragend event on marker + useEffect(() => { + if (!marker) return; + + marker.addListener("dragend", (e: google.maps.MapMouseEvent) => { + if (onDragEnd) onDragEnd(e); + }); + }, [marker, options.onDragEnd]); + + return null; +}; + +export default Marker; diff --git a/app/client/src/widgets/MapWidget/component/PickMyLocation.tsx b/app/client/src/widgets/MapWidget/component/PickMyLocation.tsx index fabd66a866..66dbdcf7a3 100644 --- a/app/client/src/widgets/MapWidget/component/PickMyLocation.tsx +++ b/app/client/src/widgets/MapWidget/component/PickMyLocation.tsx @@ -1,17 +1,11 @@ import React from "react"; -import { ControlIcons } from "icons/ControlIcons"; import styled from "styled-components"; -const StyledPickMyLocationSelectedIcon = styled( - ControlIcons.PICK_MY_LOCATION_SELECTED_CONTROL, -)` - position: relative; - cursor: pointer; - height: 28px; - width: 28px; -`; +import { ControlIcons } from "icons/ControlIcons"; -const PickMyLocationIconWrapper = styled.div` +const Icon = styled(ControlIcons.PICK_MY_LOCATION_SELECTED_CONTROL)<{ + allowZoom?: boolean; +}>` background: white; width: 40px; height: 40px; @@ -20,57 +14,55 @@ const PickMyLocationIconWrapper = styled.div` justify-content: center; align-items: center; box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px -1px; + right: 10px; + bottom: ${(props) => (props.allowZoom ? "110px" : "20px")}; + position: absolute; `; interface PickMyLocationProps { + title?: string; + isEnabled?: boolean; + allowZoom?: boolean; updateCenter: (lat: number, long: number) => void; } -interface PickMyLocationState { - clicked: boolean; - selected: boolean; -} -export default class PickMyLocation extends React.Component< - PickMyLocationProps, - PickMyLocationState -> { - constructor(props: PickMyLocationProps) { - super(props); - this.state = { - selected: false, - clicked: false, - }; - } - getUserLocation = () => { +const PickMyLocation: React.FC = (props) => { + const { allowZoom, isEnabled, title, updateCenter } = props; + const [clicked, setClicked] = React.useState(false); + const [selected, setSelected] = React.useState(false); + + /** + * get user location + * + * @returns + */ + const getUserLocation = () => { if ("geolocation" in navigator) { return navigator.geolocation.getCurrentPosition((data) => { const { coords: { latitude: lat, longitude: long }, } = data; - this.setState({ selected: true }); - this.props.updateCenter(lat, long); + setSelected(true); + updateCenter(lat, long); }); } }; - render() { - return ( - - { - if (!(this.state.clicked && this.state.selected)) { - this.setState({ clicked: true }); - this.getUserLocation(); - } - }} - /> - - ); - } -} + + if (!isEnabled) return null; + + return ( + { + if (!(clicked && selected)) { + setClicked(true); + getUserLocation(); + } + }} + title={title} + /> + ); +}; + +export default PickMyLocation; diff --git a/app/client/src/widgets/MapWidget/component/SearchBox.tsx b/app/client/src/widgets/MapWidget/component/SearchBox.tsx new file mode 100644 index 0000000000..b830b427da --- /dev/null +++ b/app/client/src/widgets/MapWidget/component/SearchBox.tsx @@ -0,0 +1,72 @@ +import styled from "styled-components"; +import React, { useRef, useEffect } from "react"; + +type Places = google.maps.places.PlaceResult[] | undefined; + +type SearchBoxProps = { + isEnabled: boolean; + map?: google.maps.Map; + placeholder?: string; + updateCenter: (lat: number, long: number) => void; +}; + +const StyledInput = styled.input` + position: absolute; + top: 0%; + box-sizing: border-box; + border: 1px solid transparent; + width: min(90%, 240px); + height: 32px; + padding: 0 12px; + border-radius: 3px; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); + font-size: 14px; + outline: none; + text-overflow: ellipses; + left: 0; + right: 0; + margin: 24px auto; +`; + +const SearchBox = (props: SearchBoxProps) => { + const { isEnabled, updateCenter } = props; + const searchBoxRef = useRef(null); + const searchBoxObjRef = useRef(); + + // initialize search box + useEffect(() => { + if (!searchBoxRef.current) return; + + searchBoxObjRef.current = new window.google.maps.places.SearchBox( + searchBoxRef.current, + ); + }, [searchBoxRef]); + + // add event listeners to search box + useEffect(() => { + if (!searchBoxObjRef.current) return; + + searchBoxObjRef.current?.addListener("places_changed", () => { + const places: Places = searchBoxObjRef.current?.getPlaces(); + const location = places ? places[0].geometry?.location : undefined; + + if (location) { + const lat = location.lat(); + const long = location.lng(); + updateCenter(lat, long); + } + }); + }, [updateCenter]); + + if (!isEnabled) return null; + + return ( + + ); +}; + +export default SearchBox; diff --git a/app/client/src/widgets/MapWidget/component/index.tsx b/app/client/src/widgets/MapWidget/component/index.tsx index d36a8bc84e..7f53c8ece0 100644 --- a/app/client/src/widgets/MapWidget/component/index.tsx +++ b/app/client/src/widgets/MapWidget/component/index.tsx @@ -1,13 +1,17 @@ -import React, { useEffect, useMemo } from "react"; -import { withGoogleMap, GoogleMap, Marker } from "react-google-maps"; -import SearchBox from "react-google-maps/lib/components/places/SearchBox"; -import { MarkerProps } from "../constants"; -import PickMyLocation from "./PickMyLocation"; +import React from "react"; import styled from "styled-components"; -import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript"; -import { Colors } from "constants/Colors"; +import { Wrapper, Status } from "@googlemaps/react-wrapper"; -interface MapComponentProps { +import Map from "./Map"; + +export interface MarkerProps { + lat: number; + long: number; + title?: string; + description?: string; + color?: string; +} +export interface MapComponentProps { apiKey: string; widgetId: string; isDisabled?: boolean; @@ -20,7 +24,7 @@ interface MapComponentProps { lat: number; long: number; }; - markers?: Array; + markers?: MarkerProps[]; selectedMarker?: { lat: number; long: number; @@ -28,211 +32,85 @@ interface MapComponentProps { }; enableCreateMarker: boolean; clickedMarkerCentered?: boolean; - updateCenter: (lat: number, long: number) => void; + updateCenter: (lat?: number, long?: number) => void; updateMarker: (lat: number, long: number, index: number) => void; - saveMarker: (lat: number, long: number) => void; - selectMarker: (lat: number, long: number, title: string) => void; + saveMarker: (lat?: number, long?: number) => void; + selectMarker: (lat?: number, long?: number, title?: string) => void; enableDrag: (e: any) => void; unselectMarker: () => void; borderRadius: string; boxShadow?: string; } -const MapContainerWrapper = styled.div` - width: 100%; - height: 100%; -`; - -const MapWrapper = styled.div<{ - borderRadius: string; - boxShadow?: string; -}>` - position: relative; - width: 100%; - height: 100%; - border-radius: ${({ borderRadius }) => borderRadius}; - border: ${({ boxShadow }) => - boxShadow === "none" ? `1px solid` : `0px solid`}; - border-color: ${Colors.GREY_3}; - overflow: hidden; - box-shadow: ${({ boxShadow }) => `${boxShadow}`} !important; - - ${({ borderRadius }) => - borderRadius >= "1.5rem" - ? `& div.gmnoprint:not([data-control-width]) { - margin-right: 10px !important;` - : ""} -`; - -const StyledInput = styled.input` - box-sizing: border-box; - border: 1px solid transparent; - width: 240px; - height: 32px; - margin-top: 27px; - padding: 0 12px; - border-radius: 3px; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); +const MapStatusText = styled.span` font-size: 14px; - outline: none; - text-overflow: ellipses; + position: absolute; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + color: var(--wds-color-text-light); `; -type PickMyLocationProps = { - allowZoom: boolean; + +const MapStatusLoading = styled.span` + font-size: 14px; + position: absolute; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + color: var(--wds-color-text-light); + background: var(--wds-color-bg-light); + text-align: center; +`; +/** + * This component will render the map based on the status of the google maps api. + * + * @param status + * @returns + */ +const renderMapStatus = (status: Status) => { + switch (status) { + case Status.LOADING: + return ; + case Status.FAILURE: + return Error while initializing the map; + case Status.SUCCESS: + return
; + } }; -const PickMyLocationWrapper = styled.div` - position: absolute; - bottom: ${(props) => (props.allowZoom ? 110 : 20)}px; - right: -90px; - width: 140px; -`; +const MapComponent = (props: MapComponentProps) => { + const { + allowZoom, + apiKey, + enablePickLocation, + enableSearch, + updateCenter, + ...rest + } = props; -const MyMapComponent = withGoogleMap((props: any) => { - const [mapCenter, setMapCenter] = React.useState< - | { - lat: number; - lng: number; - title?: string; - description?: string; - } - | undefined - >({ - ...props.center, - lng: props.center.long, - }); - const searchBox = React.createRef(); - const onPlacesChanged = () => { - const node: any = searchBox.current; - if (node) { - const places: any = node.getPlaces(); - if ( - places && - places.length && - places[0].geometry && - places[0].geometry.location - ) { - const location = places[0].geometry.location; - const lat = location.lat(); - const long = location.lng(); - setMapCenter({ lat, lng: long }); - props.updateCenter(lat, long, places[0].formatted_address); - props.unselectMarker(); - } - } - }; - useEffect(() => { - if (!props.selectedMarker) { - setMapCenter({ - ...props.center, - lng: props.center.long, - }); - } - }, [props.center, props.selectedMarker]); return ( - { - if (props.enableCreateMarker) { - props.saveMarker(e.latLng.lat(), e.latLng.lng()); - } - }} - options={{ - zoomControl: props.allowZoom, - fullscreenControl: false, - mapTypeControl: false, - scrollwheel: false, - rotateControl: false, - streetViewControl: false, - }} - zoom={props.zoom} + - {props.enableSearch && ( - - - - )} - {Array.isArray(props.markers) && - props.markers.map((marker: MarkerProps, index: number) => ( - { - if (props.clickedMarkerCentered) { - setMapCenter({ - ...marker, - lng: marker.long, - }); - } - - props.selectMarker(marker.lat, marker.long, marker.title); - }} - onDragEnd={(de) => { - props.updateMarker(de.latLng.lat(), de.latLng.lng(), index); - }} - position={{ lat: Number(marker.lat), lng: Number(marker.long) }} - title={marker.title} - /> - ))} - {props.enablePickLocation && ( - + - - - )} - - ); -}); - -function MapComponent(props: MapComponentProps) { - const zoom = Math.floor(props.zoomLevel / 5); - const status = useScript( - `https://maps.googleapis.com/maps/api/js?key=${props.apiKey}&v=3.exp&libraries=geometry,drawing,places`, - AddScriptTo.HEAD, - ); - const MapContainerWrapperMemoized = useMemo(() => , [ - props.borderRadius, - props.boxShadow, - ]); - - return ( - - {status === ScriptStatus.READY && ( - - )} - + + + ); -} +}; export default MapComponent; diff --git a/app/client/src/widgets/MapWidget/widget/index.tsx b/app/client/src/widgets/MapWidget/widget/index.tsx index 4a62b162bd..b9751dd6ca 100644 --- a/app/client/src/widgets/MapWidget/widget/index.tsx +++ b/app/client/src/widgets/MapWidget/widget/index.tsx @@ -304,7 +304,7 @@ class MapWidget extends BaseWidget { }; } - updateCenter = (lat: number, long: number, title?: string) => { + updateCenter = (lat?: number, long?: number, title?: string) => { this.props.updateWidgetMetaProperty("center", { lat, long, title }); }; @@ -321,7 +321,7 @@ class MapWidget extends BaseWidget { this.props.updateWidgetMetaProperty("markers", markers); }; - onCreateMarker = (lat: number, long: number) => { + onCreateMarker = (lat?: number, long?: number) => { this.disableDrag(true); const marker = { lat, long, title: "" }; @@ -344,7 +344,7 @@ class MapWidget extends BaseWidget { this.props.updateWidgetMetaProperty("selectedMarker", undefined); }; - onMarkerClick = (lat: number, long: number, title: string) => { + onMarkerClick = (lat?: number, long?: number, title?: string) => { this.disableDrag(true); const selectedMarker = { lat: lat, diff --git a/app/client/yarn.lock b/app/client/yarn.lock index 149137d6db..704039bf7e 100644 --- a/app/client/yarn.lock +++ b/app/client/yarn.lock @@ -1972,6 +1972,28 @@ version "1.1.5" resolved "https://registry.npmjs.org/@github/g-emoji-element/-/g-emoji-element-1.1.5.tgz" +"@googlemaps/js-api-loader@^1.13.2": + version "1.15.1" + resolved "https://registry.yarnpkg.com/@googlemaps/js-api-loader/-/js-api-loader-1.15.1.tgz#7d5f1d55a4ec5c99b1d8f0708f3a46b83a71384c" + integrity sha512-AsnEgNsB7S/VdrHGEQUaUM2e5tmjFGKBAfzR/AqO8O7TPq/jQGvoRw5liPBw4EMF38RDsHmKDV89q/X+qiUREQ== + dependencies: + fast-deep-equal "^3.1.3" + +"@googlemaps/markerclusterer@^2.0.14": + version "2.0.14" + resolved "https://registry.yarnpkg.com/@googlemaps/markerclusterer/-/markerclusterer-2.0.14.tgz#803dee96260feb26a3e75fb865125f8f3fbd5c29" + integrity sha512-/AKSz4kqMKOGc1ByPK4FWygOi0SHE2MjZdueelx4oShagcR5d9eIz77YMxcyxOUIc/dI0x5/Y0VoUTn+aWEUtQ== + dependencies: + fast-deep-equal "^3.1.3" + supercluster "^7.1.3" + +"@googlemaps/react-wrapper@^1.1.35": + version "1.1.35" + resolved "https://registry.yarnpkg.com/@googlemaps/react-wrapper/-/react-wrapper-1.1.35.tgz#fde9146b1ae02805dcad9c0fab56c4bc137b32ee" + integrity sha512-vK+BDQMHN0Oqr66cW3ZPWVK43BUmJJBu6P8T74tc6/fKpUJUlFEaZsupgIIRRRDW9ejB8uGagUmwOnA2gdcvbw== + dependencies: + "@googlemaps/js-api-loader" "^1.13.2" + "@humanwhocodes/config-array@^0.6.0": version "0.6.0" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz" @@ -3021,6 +3043,11 @@ version "1.1.2" resolved "https://registry.npmjs.org/@types/fined/-/fined-1.1.2.tgz" +"@types/google.maps@^3.51.0": + version "3.51.0" + resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.51.0.tgz#56198ebe9ecb9b83821a290ae2abe97b68e3d20b" + integrity sha512-44/oQYjc5D6kxBcI3Qk9rk3IIOMwnlEMWDV7pwPJ2YI89s5Q1OzDrFvR7QJ3LFrpVXEhig+gyagFg54+foinFg== + "@types/graceful-fs@^4.1.2": version "4.1.4" resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz" @@ -3272,12 +3299,12 @@ dependencies: "@types/react" "*" -"@types/react-dom@^16.8.0": - version "16.9.16" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.16.tgz#c591f2ed1c6f32e9759dfa6eb4abfd8041f29e39" - integrity sha512-Oqc0RY4fggGA3ltEgyPLc3IV9T73IGoWjkONbsyJ3ZBn+UPPCYpU2ec0i3cEbJuEdZtkqcCF2l1zf2pBdgUGSg== +"@types/react-dom@^17.0.2": + version "17.0.18" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.18.tgz#8f7af38f5d9b42f79162eea7492e5a1caff70dc2" + integrity sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw== dependencies: - "@types/react" "^16" + "@types/react" "^17" "@types/react-google-recaptcha@^2.1.1": version "2.1.1" @@ -3411,15 +3438,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^16", "@types/react@^16.8.2": - version "16.14.28" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.28.tgz#073258f3fe7bb80c748842c1f93aeaafe16dffad" - integrity sha512-83zBE6+XUVXsdL3iFzOyUewdauaU+KviKCHEGOgSW52coAuqW7tEKQM0E9+ZC0Zk6TELQ2/JgogPvp7FavzFwg== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - "@types/react@^16.0.40": version "16.14.8" resolved "https://registry.npmjs.org/@types/react/-/react-16.14.8.tgz" @@ -3437,6 +3455,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^17", "@types/react@^17.0.2": + version "17.0.52" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b" + integrity sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/redux-form@^8.1.9": version "8.3.0" resolved "https://registry.yarnpkg.com/@types/redux-form/-/redux-form-8.3.0.tgz#d253e0078a4940187b946459e0bb4d6a355018b1" @@ -4733,13 +4760,6 @@ babel-preset-react-app@^10.0.1: babel-plugin-macros "^3.1.0" babel-plugin-transform-react-remove-prop-types "^0.4.24" -babel-runtime@^6.11.6: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz" - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -5019,10 +5039,6 @@ camelize@^1.0.0: resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== -can-use-dom@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz" - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz" @@ -5126,10 +5142,6 @@ change-case@^4.1.2: snake-case "^3.0.4" tslib "^2.0.3" -change-emitter@^0.1.2: - version "0.1.6" - resolved "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz" - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" @@ -5583,11 +5595,7 @@ core-js-pure@^3.8.1: resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.5.tgz" integrity sha512-8xo9R00iYD7TcV7OrC98GwxiUEAabVWO3dix+uyWjnYrx9fyASLlIX+f/3p5dW5qByaP2bcZ8X/T47s55et/tA== -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz" - -core-js@^2.4.0, core-js@^2.6.5: +core-js@^2.6.5: version "2.6.11" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz" @@ -6259,10 +6267,10 @@ depd@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" -"design-system@npm:@appsmithorg/design-system@1.0.45": - version "1.0.45" - resolved "https://registry.yarnpkg.com/@appsmithorg/design-system/-/design-system-1.0.45.tgz#c3156581397beff0b4edc2bbc48ec2f17d51afd4" - integrity sha512-QrrtpQKhR719H6i9cp9OS0zr4lmjwheZcMrInOCllZ8BRr22eT7BFPpRgENzWQqq4deIWWFqD+qFDstImNhPUQ== +"design-system@npm:@appsmithorg/design-system@1.0.46": + version "1.0.46" + resolved "https://registry.yarnpkg.com/@appsmithorg/design-system/-/design-system-1.0.46.tgz#f2091ee536def9cce2f170aed036d62ae4752bb5" + integrity sha512-o1h72Sf0ZX/sUYibhxcPD4s8Z4e/AWRxPO5M45m3+g5sVZHMH25ydEEPBWODxFK2CeaNOU0NP+sBc063Q07NKA== dependencies: emoji-mart "3.0.1" @@ -7453,18 +7461,6 @@ fbjs-css-vars@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz" -fbjs@^0.8.1: - version "0.8.17" - resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - fbjs@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz" @@ -8125,10 +8121,6 @@ glur@^1.1.2: resolved "https://registry.npmjs.org/glur/-/glur-1.1.2.tgz" integrity sha1-8g6jbbEDv8KSNDkh8fkeg8NGdok= -google-maps-infobox@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/google-maps-infobox/-/google-maps-infobox-2.0.0.tgz" - graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz" @@ -8299,10 +8291,6 @@ history@^4.10.1, history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" -hoist-non-react-statics@^2.3.1: - version "2.5.5" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz" - hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" @@ -8699,7 +8687,7 @@ interweave@^12.7.2: dependencies: escape-html "^1.0.3" -invariant@^2.2.1, invariant@^2.2.4: +invariant@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" dependencies: @@ -9077,13 +9065,6 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isomorphic.js@^0.2.4: version "0.2.4" resolved "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.4.tgz" @@ -9850,6 +9831,11 @@ jszip@^3.1.3, jszip@^3.1.5, jszip@^3.7.1: readable-stream "~2.3.6" set-immediate-shim "~1.0.1" +kdbush@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0" + integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== + kind-of@^6.0.2: version "6.0.3" resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" @@ -10190,7 +10176,7 @@ lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" -lodash@4.x, lodash@^4, lodash@^4.16.2, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0, lodash@~4.17.21: +lodash@4.x, lodash@^4, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0, lodash@~4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -10340,14 +10326,6 @@ marked@^4.0.18: resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.18.tgz#cd0ac54b2e5610cfb90e8fd46ccaa8292c9ed569" integrity sha512-wbLDJ7Zh0sqA0Vdg6aqlbT+yPxqLblpAZh1mK2+AO2twQkPywvvqQNfEPVwSSRjZ7dZcdeVBIAgiO7MMp3Dszw== -marker-clusterer-plus@^2.1.4: - version "2.1.4" - resolved "https://registry.npmjs.org/marker-clusterer-plus/-/marker-clusterer-plus-2.1.4.tgz" - -markerwithlabel@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/markerwithlabel/-/markerwithlabel-2.0.2.tgz" - matchmediaquery@^0.3.0: version "0.3.1" resolved "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz" @@ -10744,7 +10722,7 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@2.6.7, node-fetch@^1.0.1, node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -12598,15 +12576,14 @@ react-documents@^1.0.4: resolved "https://registry.npmjs.org/react-documents/-/react-documents-1.0.4.tgz" integrity sha512-EpoY+MZEu3hPffIWA4FadUYu8daubNkr+LK2zuoPkCAVtyNY+z+/RuzzTriuhjcDydKXzgzp42kQTfAD2j3Mxw== -react-dom@^16.7.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.14.0.tgz#7ad838ec29a777fb3c75c3a190f661cf92ab8b89" - integrity sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" + scheduler "^0.20.2" react-error-boundary@^3.1.0: version "3.1.3" @@ -12641,22 +12618,6 @@ react-fusioncharts@^3.1.2: dependencies: uuid "^3.2.1" -react-google-maps@^9.4.5: - version "9.4.5" - resolved "https://registry.npmjs.org/react-google-maps/-/react-google-maps-9.4.5.tgz" - dependencies: - babel-runtime "^6.11.6" - can-use-dom "^0.1.0" - google-maps-infobox "^2.0.0" - invariant "^2.2.1" - lodash "^4.16.2" - marker-clusterer-plus "^2.1.4" - markerwithlabel "^2.0.1" - prop-types "^15.5.8" - recompose "^0.26.0" - scriptjs "^2.5.8" - warning "^3.0.0" - react-google-recaptcha@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz" @@ -13061,14 +13022,13 @@ react-zoom-pan-pinch@^1.6.1: version "1.6.1" resolved "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-1.6.1.tgz" -react@^16.12.0: - version "16.14.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.14.0.tgz#94d776ddd0aaa37da3eda8fc5b6b18a4c9a3114d" - integrity sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g== +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - prop-types "^15.6.2" read-pkg@^5.2.0: version "5.2.0" @@ -13124,15 +13084,6 @@ rechoir@^0.8.0: dependencies: resolve "^1.20.0" -recompose@^0.26.0: - version "0.26.0" - resolved "https://registry.npmjs.org/recompose/-/recompose-0.26.0.tgz" - dependencies: - change-emitter "^0.1.2" - fbjs "^0.8.1" - hoist-non-react-statics "^2.3.1" - symbol-observable "^1.0.4" - recursive-readdir@^2.2.2: version "2.2.2" resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz" @@ -13231,10 +13182,6 @@ regenerate@^1.4.2: resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz" - regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" @@ -13605,6 +13552,14 @@ scheduler@^0.19.1: loose-envify "^1.1.0" object-assign "^4.1.1" +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@2.7.0: version "2.7.0" resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz" @@ -13649,10 +13604,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -scriptjs@^2.5.8: - version "2.5.9" - resolved "https://registry.npmjs.org/scriptjs/-/scriptjs-2.5.9.tgz" - scroll-into-view-if-needed@^2.2.26: version "2.2.26" resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.26.tgz" @@ -14342,6 +14293,13 @@ stylehacks@^5.1.0: browserslist "^4.16.6" postcss-selector-parser "^6.0.4" +supercluster@^7.1.3: + version "7.1.5" + resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.1.5.tgz#65a6ce4a037a972767740614c19051b64b8be5a3" + integrity sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg== + dependencies: + kdbush "^3.0.0" + supports-color@8.1.1, supports-color@^8.0.0, supports-color@^8.1.1: version "8.1.1" resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" @@ -14412,7 +14370,7 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -symbol-observable@^1.0.4, symbol-observable@^1.2.0: +symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz" @@ -15192,12 +15150,6 @@ walker@^1.0.7: dependencies: makeerror "1.0.x" -warning@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz" - dependencies: - loose-envify "^1.0.0" - warning@^4.0.2, warning@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz" @@ -15403,10 +15355,6 @@ whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@>=0.10.0: - version "3.4.1" - resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz" - whatwg-fetch@^3.0.0, whatwg-fetch@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"